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

<Meta title='@dxtmisha/functional/ru/Classes/Ref/ListDataRef'/>

# Класс ListDataRef

Vue-ориентированный класс для управления списками данных с реактивными computed свойствами. Обеспечивает фокус, выделение, выбор элементов, работу с подсписками и поддержку облегченного режима для больших списков.

## Основные возможности

- **Vue Reactivity** — использует computed свойства и ref/watch для реактивности
- **Облегченный режим** — автоматическое переключение на упрощенный список для больших данных
- **Поддержка подсписков** — иерархические списки с группами и меню
- **Поиск с выделением** — настраиваемое выделение найденного текста
- **Фокус и выбор** — управление состоянием фокуса и выбранных элементов
- **Гибкие ключи** — настраиваемые ключи для value и label
- **Карта элементов** — плоское представление иерархических данных
- **Фильтрация по типам** — отдельные списки для items, groups, menu

## Конструктор

### `constructor`

Создаёт экземпляр ListDataRef с реактивными параметрами.

**Параметры:**
- `list: RefOrNormal<ListListInput | undefined>` — данные списка (ref или обычное значение)
- `focus?: RefType<ListSelectedItem | undefined>` — элемент в фокусе
- `highlight?: RefType<string | undefined>` — текст для выделения
- `highlightLengthStart?: RefType<number | undefined>` — минимальная длина для начала выделения
- `selected?: RefType<ListSelectedList | undefined>` — выбранные элементы
- `keyValue?: RefType<string | undefined>` — ключ для получения значения
- `keyLabel?: RefType<string | undefined>` — ключ для получения метки
- `lite?: RefType<number | undefined>` — порог для облегченного режима
- `parent?: string` — идентификатор родителя

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

// С ref данными
const listRef = ref(['Apple', 'Banana', 'Cherry'])
const focusRef = ref('Apple')
const selectedRef = ref(['Apple'])

const listData = new ListDataRef(
  listRef,
  focusRef,
  undefined, // highlight
  undefined, // highlightLengthStart
  selectedRef
)

// С обычными данными
const staticList = new ListDataRef([
  { label: 'Главная', value: 'home', type: 'item' },
  { label: 'Продукты', value: 'products', type: 'group' }
])
```

## Реактивные computed свойства

### `data`

Основной список элементов с обработанными данными.

**Возвращает:** `ComputedRef<ListList>` — обработанный список

```javascript
const items = listData.data.value
// Каждый элемент содержит: parent, index, type, label, value
```

### `liteData`

Упрощенный список для быстрой загрузки больших данных.

**Возвращает:** `ComputedRef<ListList>` — упрощенный или полный список

```javascript
// Автоматически переключается на lite режим при превышении порога
const displayItems = listData.liteData.value
```

### `fullData`

Список с полными данными состояния (фокус, выделение, выбор).

**Возвращает:** `ComputedRef<ListDataFull>` — список с состоянием

```javascript
const fullItems = listData.fullData.value
// Каждый элемент дополнительно содержит: focus, highlight, selected
```

### `map`

Плоское представление иерархического списка.

**Возвращает:** `ComputedRef<ListList>` — плоский список всех элементов

```javascript
const flatList = listData.map.value
// Включает элементы из подгрупп
```

### `mapItems`

Только элементы типа 'item' из плоского списка.

**Возвращает:** `ComputedRef<ListList>`

```javascript
const onlyItems = listData.mapItems.value
```

### `items`

Элементы для выбора (item, group, menu).

**Возвращает:** `ComputedRef<ListList>`

```javascript
const selectableItems = listData.items.value
```

### `highlightFirstItem`

Индекс первого элемента, соответствующего условиям поиска.

**Возвращает:** `ComputedRef<number>` — индекс найденного элемента или -1

```javascript
const searchIndex = listData.highlightFirstItem.value
if (searchIndex !== -1) {
  console.log('Найден элемент на позиции:', searchIndex)
}
```

### `isSelected`

Проверяет наличие выбранных элементов в списке.

**Возвращает:** `ComputedRef<boolean>` — true если есть выбранные элементы

```javascript
const hasSelected = listData.isSelected.value
```

### `selectedList`

Список выбранных элементов с полными данными.

**Возвращает:** `ComputedRef<ListList>`

```javascript
const selected = listData.selectedList.value
```

### `selectedNames`

Имена (labels) выбранных элементов.

**Возвращает:** `ComputedRef<ListNames>`

```javascript
const names = listData.selectedNames.value // ['Яблоко', 'Банан']
```

### `selectedValues`

Значения выбранных элементов.

**Возвращает:** `ComputedRef<any[]>`

```javascript
const values = listData.selectedValues.value // ['apple', 'banana']
```

## Методы проверки состояния

### `isLite`

Проверяет необходимость облегченного режима.

**Возвращает:** `boolean`

```javascript
if (listData.isLite()) {
  // используется упрощенный список
}
```

### `isFocus`

Проверяет наличие элемента в фокусе.

**Возвращает:** `boolean`

```javascript
const hasFocus = listData.isFocus()
```

### `isHighlight`

Проверяет наличие выделенного элемента при поиске.

**Возвращает:** `boolean`

```javascript
const hasHighlight = listData.isHighlight()
```

## Методы получения данных

### `getLength`

Возвращает количество основных записей.

**Возвращает:** `number`

```javascript
const count = listData.getLength()
```

### `getLengthByMap`

Возвращает количество всех доступных записей (включая подгруппы).

**Возвращает:** `number`

```javascript
const totalCount = listData.getLengthByMap()
```

### `getLengthByItems`

Возвращает количество элементов доступных для выбора.

**Возвращает:** `number`

```javascript
const selectableCount = listData.getLengthByItems()
```

### `getFocus`

Возвращает значение элемента в фокусе.

**Возвращает:** `ListSelectedItem | undefined`

```javascript
const focusedValue = listData.getFocus()
```

### `getHighlight`

Возвращает текст для выделения при поиске.

**Возвращает:** `string | undefined`

```javascript
const searchText = listData.getHighlight()
```

### `getHighlightLengthStart`

Возвращает минимальную длину для начала выделения.

**Возвращает:** `number`

```javascript
const minLength = listData.getHighlightLengthStart() // по умолчанию 2
```

### `getSelected`

Возвращает выбранные значения.

**Возвращает:** `ListSelectedList | undefined`

```javascript
const selectedValues = listData.getSelected()
```

### `getItemByKey`

Возвращает элемент по ключу.

**Параметры:**
- `key: number` — ключ элемента

**Возвращает:** `ListDataItem | undefined`

```javascript
const item = listData.getItemByKey(0)
console.log(item?.label)
```

### `getFirstItemByParent`

Возвращает первый элемент с указанным родителем.

**Параметры:**
- `parent: string` — идентификатор родителя

**Возвращает:** `ListDataItem | undefined`

```javascript
const firstChild = listData.getFirstItemByParent('group1')
```

### `getLastItemByParent`

Возвращает последний элемент с указанным родителем.

**Параметры:**
- `parent: string` — идентификатор родителя

**Возвращает:** `ListDataItem | undefined`

```javascript
const lastChild = listData.getLastItemByParent('group1')
```

### `getItemByIndex`

Возвращает элемент по индексу.

**Параметры:**
- `index?: string` — индекс элемента

**Возвращает:** `{ key: number, item: ListDataItem } | undefined`

```javascript
const result = listData.getItemByIndex('apple')
if (result) {
  console.log(result.key, result.item)
}
```

### `getSubList`

Возвращает подсписок для группового элемента.

**Параметры:**
- `item: ListDataItem` — элемент группы

**Возвращает:** `ListData` — экземпляр подсписка

```javascript
const groupItem = listData.data.value.find(item => item.type === 'group')
if (groupItem) {
  const subList = listData.getSubList(groupItem)
  const subItems = subList.data.value
}
```

## Практические примеры

### Vue компонент с реактивными данными

```javascript
// Composable для списка
export function useListData(initialData) {
  const list = ref(initialData)
  const focus = ref(null)
  const selected = ref([])
  const highlight = ref('')

  const listData = new ListDataRef(
    list,
    focus,
    highlight,
    ref(2), // минимум 2 символа для поиска
    selected
  )

  return {
    list,
    focus,
    selected,
    highlight,
    data: listData.fullData,
    selectedItems: listData.selectedList
  }
}
```

### Компонент выпадающего списка

```html
<template>
  <div class="dropdown">
    <div class="dropdown-items">
      <div
        v-for="item in displayData"
        :key="item.index"
        :class="{
          'focused': item.focus,
          'selected': item.selected,
          'highlighted': item.highlight
        }"
        @click="toggleSelection(item)"
      >
        {{ item.label }}
      </div>
    </div>
  </div>
</template>

<script setup>
import { ListDataRef } from '@dxtmisha/functional'

const props = defineProps(['items'])
const focus = ref(null)
const selected = ref([])

const listData = new ListDataRef(
  computed(() => props.items),
  focus,
  undefined,
  undefined,
  selected
)

const displayData = listData.fullData

function toggleSelection(item) {
  const currentSelected = selected.value || []
  const index = currentSelected.indexOf(item.value)

  if (index === -1) {
    selected.value = [...currentSelected, item.value]
  } else {
    selected.value = currentSelected.filter(v => v !== item.value)
  }
}
</script>
```

### Иерархический список с группами

```javascript
// Данные с группами
const hierarchicalData = [
  {
    label: 'Фрукты',
    type: 'group',
    value: [
      { label: 'Яблоко', value: 'apple' },
      { label: 'Банан', value: 'banana' }
    ]
  },
  {
    label: 'Овощи',
    type: 'group',
    value: [
      { label: 'Морковь', value: 'carrot' },
      { label: 'Картофель', value: 'potato' }
    ]
  }
]

const listData = new ListDataRef(hierarchicalData)

// Получение всех элементов (включая из групп)
const allItems = listData.map.value

// Работа с подгруппами
const fruitGroup = listData.data.value[0]
const fruitSubList = listData.getSubList(fruitGroup)
const fruits = fruitSubList.data.value
```

Класс ListDataRef предоставляет мощную реактивную систему управления списками для Vue приложений с поддержкой иерархии, состояния и оптимизации производительности.
