import {Meta} from '@storybook/addon-docs/blocks'

<Meta title='@dxtmisha/ru/functional/Classes/ListDataRef - Управление Списками Данных'/>

# Класс ListDataRef

Реактивный класс для управления списками данных любой сложности. Поддерживает фильтрацию, выделение (selection), фокус и вложенные структуры (группы и меню). Класс преобразует входные данные в стандартизированный формат и предоставляет обширный набор методов для навигации, поиска и управления состоянием элементов.

## Ключевые особенности

- **Реактивность** — автоматическое обновление вычисляемых свойств при изменении исходных данных (Vue ref) или параметров управления.
- **Стандартизация** — приведение любых входных форматов (массив строк, объектов) к единому интерфейсу `ListDataItem`.
- **Глубокая вложенность** — поддержка древовидных структур с автоматическим управлением подписками через `getSubList`.
- **Умная навигация** — встроенные методы для перемещения по списку с учетом фильтрации и типа элементов.
- **Облегченный режим** — оптимизация отрисовки больших списков через `liteData`.
- **Управление выбором** — контроль за количеством выбранных элементов (min/max) и их состоянием.

## Инициализация

Создает новый экземпляр `ListDataRef` для управления данными списка. Класс обеспечивает стандартизацию входных данных, управление фокусом, выделением и поиском. Поддерживает реактивное обновление при изменении исходного списка или параметров управления.

**Параметры:**

- `list: RefOrNormal<ListListInput | undefined>` — реактивный или обычный список данных.
- `focus?: RefType<ListSelectedItem | undefined>` — идентификатор элемента в фокусе (Vue ref).
- `highlight?: RefType<string | undefined>` — текст для поиска и выделения (Vue ref).
- `highlightLengthStart?: RefType<number | undefined>` — минимальное количество символов для начала поиска (Vue ref).
- `filterMode?: RefType<boolean | undefined>` — режим фильтрации (Vue ref).
- `selected?: RefType<ListSelectedList | undefined>` — список выбранных идентификаторов (Vue ref).
- `keyValue?: RefType<string | undefined>` — название поля для значения (по умолчанию `'value'`).
- `keyLabel?: RefType<string | undefined>` — название поля для метки (по умолчанию `'label'`).
- `lite?: RefType<number | undefined>` — порог количества элементов для включения режима Lite (Vue ref).
- `min: RefOrNormal<number | string | undefined> = 0` — минимально допустимое количество выделений.
- `max: RefOrNormal<number | string | undefined> = 9_999_999` — максимально допустимое количество выделений.
- `parent?: string` — идентификатор родительского элемента (используется для подсписков).

```typescript
import { ListDataRef } from '@dxtmisha/functional'
import { ref } from 'vue'

const list = ref([
  { label: 'Пункт 1', value: 'item-1' },
  { label: 'Группа 1', type: 'group', value: [
    { label: 'Подпункт 1.1', value: 'sub-1.1' }
  ]}
])

const focus = ref(undefined)
const selected = ref(['item-1'])

const listData = new ListDataRef(
  list, 
  focus, 
  undefined, // highlight
  undefined, // highlightLengthStart
  undefined, // filterMode
  selected
)
```

## Свойства

### Данные

- `data: Computed<ListList>` — Основной стандартизированный список данных текущего уровня.
- `liteData: Computed<ListList>` — Упрощенная версия списка для быстрой отрисовки (активируется, если длина `data` превышает порог `lite`).
- `fullData: Computed<ListDataFull>` — Расширенный список данных, где для каждого элемента рассчитаны флаги `focus`, `selected`, `disabled` и активный `highlight`.
- `map: Computed<ListList>` — Плоский список абсолютно всех элементов дерева (включая группы и меню), развернутый в один массив.
- `mapItems: Computed<ListList>` — Плоский список только конечных выбираемых элементов (тип `item`). Используется для основной навигации.
- `items: Computed<ListList>` — Плоский список элементов, которые могут иметь интерактивное состояние (типы `item`, `group`, `menu`).

### Выбор и Состояние

- `isSelected: Computed<boolean>` — Возвращает `true`, если в дереве `mapItems` выбран хотя бы один элемент.
- `isSelectedMin: Computed<boolean>` — Возвращает `true`, если количество выбранных элементов в текущей группе достигло или превысило `min`.
- `isSelectedMax: Computed<boolean>` — Возвращает `true`, если количество выбранных элементов в текущей группе достигло порога `max`.
- `selectedList: Computed<ListList>` — Список всех объектов `ListDataItem`, выбранных во всем дереве (на основе `mapItems`).
- `selectedListInGroup: Computed<ListList>` — Список объектов, выбранных только на текущем уровне вложенности (`data`).
- `selectedNames: Computed<ListNames>` — Массив строк с метками (`label`) всех выбранных элементов дерева.
- `selectedValues: Computed<any[]>` — Массив значений (`value`) всех выбранных элементов дерева.

### Поиск

- `highlightFirstItem: Computed<number>` — Индекс первого элемента в `map`, текст которого совпадает с `highlight` (с учетом `highlightLengthStart`). Возвращает `-1`, если совпадений нет.

## Методы

### Статус и Проверки

- `isLite(): boolean` — Возвращает `true`, если включен режим оптимизации (длина списка > `lite`).
- `isFocus(): boolean` — Проверяет, совпадает ли значение `focus` с каким-либо элементом в текущем `map`.
- `isHighlight(): boolean` — Возвращает `true`, если поиск нашел хотя бы одно совпадение.
- `isHighlightActive(): boolean` — Проверяет, активен ли процесс поиска (длина строки достаточна и есть результаты).
- `getLength(): number` — Общее количество элементов на текущем уровне (`data`).
- `getLengthByMap(): number` — Общее количество всех элементов в дереве (`map`).
- `getLengthByItems(): number` — Количество конечных элементов во всем дереве (`mapItems`).

### Получение значений

- `getFocus(): ListSelectedItem | undefined` — Текущее значение идентификатора в фокусе.
- `getHighlight(): string | undefined` — Текущая строка поиска.
- `getHighlightLengthStart(): number` — Минимальная длина строки для срабатывания поиска (по умолчанию `2`).
- `getSelected(): ListSelectedList | undefined` — текущий список выбранных идентификаторов.

### Навигация и Поиск

- `getSelectedByStep(step): ListSelectedItem | undefined` — поиск соседа относительно выделения.
- `getSelectedNext(): ListSelectedItem | undefined` — следующий элемент от выделения.
- `getSelectedPrev(): ListSelectedItem | undefined` — предыдущий элемент от выделения.
- `getItemByStep(item, step): ListDataItem | undefined` — поиск соседа относительно элемента.
- `getItemNext(item): ListDataItem | undefined` — следующий от элемента.
- `getItemPrev(item): ListDataItem | undefined` — предыдущий от элемента.
- `getIndexByStep(index, step): ListDataItem | undefined` — поиск соседа относительно индекса.
- `getIndexNext(index): ListDataItem | undefined` — следующий от индекса.
- `getIndexPrev(index): ListDataItem | undefined` — предыдущий от индекса.
- `getItemByIndex(index): { key, item } | undefined` — поиск элемента по индексу.
- `getItemByKey(key): ListDataItem | undefined` — возвращает элемент по ключу в map.
- `getFirstItemByParent(parent): ListDataItem | undefined` — первый интерактивный элемент родителя.
- `getLastItemByParent(parent): ListDataItem | undefined` — последний интерактивный элемент родителя.
- `getSubList(item): ListDataRef` — создает/возвращает инстанс подсписка.

## Типы данных

Класс использует стандартизированные структуры для предсказуемой работы с любыми форматами данных.

### `ListType`

Определяет роль элемента:
- `item` — основной интерактивный элемент для выбора и фокуса.
- `group` / `menu` — контейнеры для вложенных списков (`value`).
- `subtitle` — текстовый заголовок внутри списка.
- `html` — элемент для вставки произвольного HTML.
- `line` / `space` — визуальные разделители.

### `ListDataItem`

Объект, в который преобразуются все входные данные:
- `index: string` — уникальный идентификатор (генерируется автоматически).
- `type: ListType` — тип элемента (по умолчанию `item`).
- `label?: string | number` — текст в интерфейсе.
- `value?: any` — значение элемента.
- `parent?: string` — идентификатор родителя.

### `ListDataFullItem`

Расширенная версия `ListDataItem` для `fullData`:
- `focus: boolean` — `true`, если в фокусе.
- `selected: boolean` — `true`, если выбран.
- `disabled: boolean` — `true`, если выбор заблокирован (лимит `max`).
- `highlight?: string` — строка поиска, если есть совпадение.

### `ListListInput`

Форматы данных для конструктора:
- `string[]` — массив строк (метки).
- `Record<string, string>` — объект `value: label`.
- `ListDataBasic[]` — массив объектов с полями `label`, `value`, `type` и др.

## Управление выбором (Selection)

Класс поддерживает одиночный и множественный выбор с ограничениями.

### Ключевые параметры

- `selected` — Vue `ref` с массивом идентификаторов.
- `min` / `max` — лимиты выбора на текущем уровне.

### Глобальный vs Групповой выбор

- **selectedList** — все выбранные `item` во всем дереве.
- **selectedListInGroup** — выбранные элементы только в текущей группе (`data`). На основе этого списка работают `min` и `max`.

### Автоматическое состояние disabled

При достижении `max` (`isSelectedMax`), остальные невыбранные элементы в `fullData` получают `disabled: true`.

## Управление фокусом

Реализовано через внешнюю переменную `ref`, общую для всего дерева.

### Особенности

- **Общее состояние** — подсписки используют тот же `ref` фокуса.
- **Реактивность** — `fullData` рассчитывает `focus: true` по совпадению `index`.
- **Ручное управление** — класс не меняет фокус сам. Навигация лишь возвращает объект.

```javascript
const next = listData.getItemNext(currentItem)
if (next) {
    focus.value = next.index
}
```

## Поиск и Подсветка (Highlight)

### Параметры

- `highlight` — строка запроса.
- `highlightLengthStart` — порог активации (по умолчанию `2`).

### Механика

1. **Regex** — автоматическое создание регулярного выражения.
2. **Поля** — поиск по `label`, `index` и `search`.
3. **fullData** — передача `highlight` в элементы для подсветки в UI.
4. **Результат** — `highlightFirstItem` возвращает индекс первого совпадения в `map`.

### Состояния

- `isHighlight()` — есть совпадения.
- `isHighlightActive()` — длина строки достигла порога.

## Режим фильтрации (filterMode)

Флаг для UI о необходимости скрыть не подходящие под поиск элементы. Значение наследуется подсписками.

## Облегченный режим (Lite Mode)

Оптимизация производительности для больших списков. Если количество элементов в `data` > `lite`, активируется `liteData` с упрощенной структурой.

## Примеры

### Рендеринг дерева

```vue
<template>
  <ul>
    <li v-for="item in listData.data.value" :key="item.index">
      {{ item.label }}
      <ul v-if="item.type === 'group'">
        <li v-for="sub in listData.getSubList(item).data.value" :key="sub.index">
           {{ sub.label }}
        </li>
      </ul>
    </li>
  </ul>
</template>

<script setup>
const listData = new ListDataRef(props.list)
</script>
```

## Работа с навигацией

### Плоская циклическая навигация

Методы `getItemNext/Prev` и `getIndexNext/Prev` работают через `mapItems` (только `item`). Навигация сквозная по всему дереву и циклическая.

### Навигация по выделению

`getSelectedNext/Prev` ищут соседа относительно первого выбранного элемента.

### Контекстная навигация

`getFirstItemByParent` и `getLastItemByParent` ищут границы текущей группы.
