<!--
  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, focus must be explicitly set on an element and managed manually. `FocusManager` is a utility component that simplifies focus for elements in a list.

## Source

https://github.com/rdkcentral/Lightning-UI-Components/blob/develop/packages/@lightningjs/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="navigation-focusmanager--rows" />
</Canvas>

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

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

<Canvas>
  <Story id="navigation-focusmanager--columns" />
</Canvas>

Enable the `wrapSelected` property to allow cycling focus between the first and last items.

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

<Canvas>
  <Story id="navigation-focusmanager--wrap-selected" />
</Canvas>

## Extending FocusManager

You can create a component that extends the capabilities of `FocusManager` and responds to changes in focus. Just create a `render()` instance method.

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

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

<Canvas>
  <Story id="navigation-focusmanager--extended-component" />
</Canvas>

## API

### Properties

| name          | type                                                    | readonly | description                                                                                                                  |
| ------------- | ------------------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------- |
| direction     | 'column'\|'row'                                         | false    | determines whether focus handling responds to left/right or up/down key                                                      |
| selected      | <DocsLink id="lng.Component" />                         | true     | current item in focus                                                                                                        |
| selectedIndex | number                                                  | false    | index of current item in focus                                                                                               |
| loading       | boolean                                                 | true     | False if an item is in focus, true otherwise                                                                                 |
| items         | <DocsLink id="lng.Component">lng.Component[]</DocsLink> | false    | alias for `children`                                                                                                         |
| wrapSelected  | boolean                                                 | false    | enables wrapping behavior, so `selectNext` selects the first item if the current item is the last on the list and vice versa |

### Methods

#### appendItems

Appends items to child list and updates focus

##### Arguments

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

#### render

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

#### selectPrevious

Selects previous item. If this.wrapSelected=true, will select the last element in the list if focus is currently on the first item.

#### selectNext

Selects next item. If this.wrapSelected=true, will select the first element in the list if focus is currently on the last item.
