<!--
  Copyright 2023 Comcast Cable Communications Management, LLC

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

  SPDX-License-Identifier: Apache-2.0
-->

import { Canvas, Story } from '@storybook/addon-docs';
import { DocsLink } from '../../docs/utils';

# FocusManager

In Lightning, setting focus on elements and managing it manually is required. `FocusManager` is a component that simplifies focus for elements within a list.

## Source

https://github.com/rdkcentral/Lightning-UI-Components/tree/develop/packages/%40lightningjs/ui-components/src/components/FocusManager/FocusManager.js

## Usage

Within a parent component `_template()` function, define a child of type `FocusManager` and in `_getFocused()` return that child component

```js
import { FocusManager } from '@lightningjs/ui-components';

class RowExample extends lng.Component {
  static _template() {
    return {
      Row: {
        type: FocusManager,
        direction: 'row',
        items: [
          // components to be managed
        ]
      }
    };
  }

  _getFocused() {
    return this.tag('Row');
  }
}
```

<Canvas>
  <Story id="components-focusmanager--column-with-rows" />
</Canvas>

Set the `direction` property to `row` for left/right or `column` for up/down key handling.

```js
{
  type: FocusManager,
  direction: 'column',
  children: [/* ... */]
}
```

To enable cycling focus between the first and last items, set the `wrapSelected` property to true.

```js
{
  type: FocusManager,
  wrapSelected: true,
  children: [/* ... */]
}
```

## Extending FocusManager

You can create a component that extends `FocusManager` to add custom focus behavior. Just create a `render()` method that responds to changes in focus.

```js
import lng from '@lightningjs/core';
import { FocusManager } from '@lightningjs/ui-components';

class FancyFocus extends FocusManager {
  render() {
    // customize selected item appearance
    this.selected.patch({
      texture: lng.Tools.getRoundRect(
        150,
        40,
        4,
        3,
        0xffff00ff,
        true,
        0xff00ffff
      )
    });
  }
}
```

## API

### Properties

| name          | type                                                    | default   | description                                                                                                                                                                                                                                                                                                                                            |
| ------------- | ------------------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| direction     | 'column'\|'row'                                         | undefined | The navigation direction for focus ('left/right' or 'up/down')                                                                                                                                                                                                                                                                                         |
| selectedIndex | number                                                  | undefined | The index of the currently selected item.                                                                                                                                                                                                                                                                                                              |
| items         | <DocsLink id="lng.Component">lng.Component[]</DocsLink> | undefined | Child element or elements of the FocusManager.                                                                                                                                                                                                                                                                                                         |
| wrapSelected  | boolean                                                 | false     | When wrapSelected is set to true, the focus will loop back to the beginning of the list after reaching the last item, and vice versa. This enables continuous navigation through the list without dead ends. If wrapSelected is set to false (the default value), the focus will stop at the first or last item, depending on the navigation direction |

### Methods

#### appendItems(items: <DocsLink id="lng.Component">lng.Component[]</DocsLink>): void

This method appends the provided rows to the end of the FocusManager's children

#### appendItemsAt(items: <DocsLink id="lng.Component">lng.Component[]</DocsLink>, idx: number): void

This method is similar to appendItems, but it allows appending items at a specific index in the list of child items.

##### Arguments

| name  | type                                                    | required | default   | description                   |
| ----- | ------------------------------------------------------- | -------- | --------- | ----------------------------- |
| items | <DocsLink id="lng.Component">lng.Component[]</DocsLink> | false    | []        | The list of items to append   |
| idx   | number                                                  | true     | undefined | The index to insert the items |

#### prependItems(items: <DocsLink id="lng.Component">lng.Component[]</DocsLink>): void

This method prepends items to the beginning of the FocusManager's children.

| name  | type                                                    | required | default | description                 |
| ----- | ------------------------------------------------------- | -------- | ------- | --------------------------- |
| items | <DocsLink id="lng.Component">lng.Component[]</DocsLink> | false    | []      | The list of items to append |

#### removeItemAt(index: number): void

Removes an item at a specific index from the FocusManager's children.

#### getTransitionXTargetValue(): string

Returns the transition value for the x coordinate of the FocusManager's items.

#### getTransitionYTargetValue(): string

Returns the transition value for the y coordinate of the FocusManager's items.

#### \_render(): void

A no-op function that is called when `selectedIndex` is set. Can be overridden by classes that extend `FocusManager` for custom render behavior.

#### selectPrevious(): void

Selects the previous item in the FocusManager's children. If wrapSelected is true, it selects the last item if the focus is currently on the first item.

#### selectNext(): void

Selects the next item in the FocusManager's children. If wrapSelected is true, it selects the first item if the focus is currently on the last item.
