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

<Meta title='@dxtmisha/vi/functional/Classes/ListDataRef - Quản Lý Danh Sách Dữ Liệu'/>

# Lớp ListDataRef

Một lớp phản ứng (reactive) để quản lý danh sách dữ liệu với bất kỳ độ phức tạp nào. Hỗ trợ lọc, lựa chọn (selection), tiêu điểm (focus) và cấu trúc lồng nhau (nhóm và menu). Lớp này chuyển đổi dữ liệu đầu vào thành định dạng chuẩn hóa và cung cấp một bộ phương thức phong phú để điều hướng, tìm kiếm và quản lý trạng thái của các phần tử.

## Các tính năng chính

- **Tính phản ứng (Reactivity)** — tự động cập nhật các thuộc tính tính toán (computed properties) khi dữ liệu nguồn (Vue ref) hoặc tham số điều khiển thay đổi.
- **Chuẩn hóa** — chuyển đổi bất kỳ định dạng đầu vào nào (mảng chuỗi, đối tượng) thành một giao diện `ListDataItem` thống nhất.
- **Lồng nhau sâu** — hỗ trợ cấu trúc dạng cây với việc quản lý danh sách con tự động thông qua `getSubList`.
- **Điều hướng thông minh** — các phương thức tích hợp sẵn để di chuyển trong danh sách, có tính đến việc lọc và loại phần tử.
- **Chế độ Lite** — tối ưu hóa việc hiển thị cho danh sách lớn bằng cách sử dụng `liteData`.
- **Quản lý lựa chọn** — kiểm soát số lượng phần tử được chọn (tối thiểu/tối đa) và trạng thái của chúng.

## Khởi tạo

Tạo một thực thực thể `ListDataRef` mới để quản lý dữ liệu danh sách. Lớp này cung cấp khả năng chuẩn hóa dữ liệu đầu vào, quản lý tiêu điểm, lựa chọn và tìm kiếm. Hỗ trợ cập nhật phản ứng khi danh sách nguồn hoặc các tham số điều khiển thay đổi.

**Tham số:**

- `list: RefOrNormal<ListListInput | undefined>` — danh sách dữ liệu phản ứng hoặc thông thường.
- `focus?: RefType<ListSelectedItem | undefined>` — mã định danh phần tử đang được lấy tiêu điểm (Vue ref).
- `highlight?: RefType<string | undefined>` — văn bản tìm kiếm để làm nổi bật (Vue ref).
- `highlightLengthStart?: RefType<number | undefined>` — số ký tự tối thiểu để bắt đầu tìm kiếm (Vue ref).
- `filterMode?: RefType<boolean | undefined>` — chế độ lọc (Vue ref).
- `selected?: RefType<ListSelectedList | undefined>` — danh sách các mã định danh đã chọn (Vue ref).
- `keyValue?: RefType<string | undefined>` — tên trường cho giá trị (mặc định là `'value'`).
- `keyLabel?: RefType<string | undefined>` — tên trường cho nhãn (mặc định là `'label'`).
- `lite?: RefType<number | undefined>` — ngưỡng số lượng phần tử để kích hoạt chế độ Lite (Vue ref).
- `min: RefOrNormal<number | string | undefined> = 0` — số lượng lựa chọn tối thiểu được phép.
- `max: RefOrNormal<number | string | undefined> = 9_999_999` — số lượng lựa chọn tối đa được phép.
- `parent?: string` — mã định danh cha (được sử dụng cho danh sách con).

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

const list = ref([
  { label: 'Mục 1', value: 'item-1' },
  { label: 'Nhóm 1', type: 'group', value: [
    { label: 'Mục con 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
)
```

## Thuộc tính

### Dữ liệu

- `data: Computed<ListList>` — danh sách dữ liệu chuẩn hóa cốt lõi cho cấp độ hiện tại.
- `liteData: Computed<ListList>` — phiên bản danh sách đơn giản hóa để hiển thị nhanh (chế độ Lite).
- `fullData: Computed<ListDataFull>` — danh sách dữ liệu mở rộng với các cờ `focus`, `selected`, `disabled` và `highlight`.
- `map: Computed<ListList>` — danh sách phẳng của tất cả các phần tử trong cây (bao gồm cả vùng chứa).
- `mapItems: Computed<ListList>` — danh sách phẳng chỉ chứa các phần tử được chọn cuối cùng (`item`).
- `items: Computed<ListList>` — danh sách phẳng các phần tử tương tác (`item`, `group`, `menu`).

### Lựa chọn và Trạng thái

- `isSelected: Computed<boolean>` — trả về `true` nếu có ít nhất một mục được chọn trong toàn bộ cây.
- `isSelectedMin: Computed<boolean>` — `true` nếu số lượng mục được chọn đạt mức tối thiểu `min`.
- `isSelectedMax: Computed<boolean>` — `true` nếu số lượng mục được chọn đạt ngưỡng `max`.
- `selectedList: Computed<ListList>` — danh sách tất cả các đối tượng được chọn trên toàn bộ cây.
- `selectedListInGroup: Computed<ListList>` — danh sách các đối tượng được chọn ở cấp độ hiện tại.
- `selectedNames: Computed<ListNames>` — mảng các nhãn (`label`) cho tất cả các mục được chọn.
- `selectedValues: Computed<any[]>` — mảng các giá trị (`value`) cho tất cả các mục được chọn.

### Tìm kiếm

- `highlightFirstItem: Computed<number>` — chỉ số của phần tử đầu tiên khớp với tìm kiếm trong `map`.

## Phương thức

### Trạng thái và Kiểm tra

- `isLite(): boolean` — trả về `true` nếu chế độ tối ưu hóa đang hoạt động.
- `isFocus(): boolean` — kiểm tra xem có tiêu điểm trong `map` hiện tại hay không.
- `isHighlight(): boolean` — trả về `true` nếu tìm kiếm thấy kết quả khớp.
- `isHighlightActive(): boolean` — kiểm tra xem quá trình tìm kiếm có đang hoạt động hay không.
- `getLength(): number` — tổng số phần tử ở cấp độ hiện tại.
- `getLengthByMap(): number` — tổng số phần tử trong toàn bộ cây.
- `getLengthByItems(): number` — số lượng phần tử cuối cùng trong toàn bộ cây.

### Lấy giá trị

- `getFocus(): ListSelectedItem | undefined` — mã định danh đang được lấy tiêu điểm hiện tại.
- `getHighlight(): string | undefined` — chuỗi tìm kiếm hiện tại.
- `getHighlightLengthStart(): number` — độ dài chuỗi tối thiểu để kích hoạt tìm kiếm (mặc định là `2`).
- `getSelected(): ListSelectedList | undefined` — danh sách các mã định danh đã chọn hiện tại.

### Điều hướng và Tìm kiếm

- `getSelectedByStep(step): ListSelectedItem | undefined` — tìm phần tử lân cận so với lựa chọn.
- `getSelectedNext(): ListSelectedItem | undefined` — tiếp theo từ lựa chọn.
- `getSelectedPrev(): ListSelectedItem | undefined` — trước đó từ lựa chọn.
- `getItemByStep(item, step): ListDataItem | undefined` — tìm phần tử lân cận so với phần tử.
- `getItemNext(item): ListDataItem | undefined` — tiếp theo từ phần tử.
- `getItemPrev(item): ListDataItem | undefined` — trước đó từ phần tử.
- `getIndexByStep(index, step): ListDataItem | undefined` — tìm phần tử lân cận so với chỉ số.
- `getIndexNext(index): ListDataItem | undefined` — tiếp theo từ chỉ số.
- `getIndexPrev(index): ListDataItem | undefined` — trước đó từ chỉ số.
- `getItemByIndex(index): { key, item } | undefined` — tìm phần tử theo chỉ số.
- `getItemByKey(key): ListDataItem | undefined` — trả về phần tử theo khóa trong map.
- `getFirstItemByParent(parent): ListDataItem | undefined` — phần tử tương tác đầu tiên của cha.
- `getLastItemByParent(parent): ListDataItem | undefined` — phần tử tương tác cuối cùng của cha.
- `getSubList(item): ListDataRef` — tạo/trả về thực thể danh sách con.

## Các kiểu dữ liệu

Lớp sử dụng các cấu trúc chuẩn hóa để đảm bảo hành vi có thể dự đoán được với bất kỳ định dạng dữ liệu đầu vào nào.

### `ListType`

Xác định vai trò chức năng của một mục trong danh sách:
- `item` — phần tử tương tác chính có sẵn để lựa chọn và lấy tiêu điểm.
- `group` / `menu` — các vùng chứa các danh sách lồng nhau (`value`).
- `subtitle` — một tiêu đề văn bản trong danh sách.
- `html` — phần tử để chèn mã HTML tùy ý.
- `line` / `space` — các vạch ngăn cách và khoảng cách trực quan.

### `ListDataItem`

Đối tượng mà tất cả dữ liệu đầu vào được chuyển đổi sau khi chuẩn hóa:
- `index: string` — mã định danh duy nhất (tự động tạo nếu không được cung cấp).
- `type: ListType` — loại mục (mặc định là `item`).
- `label?: string | number` — văn bản hiển thị trong giao diện.
- `value?: any` — một giá trị tùy ý được liên kết với mục.
- `parent?: string` — mã định danh của mục cha.

### `ListDataFullItem`

Phiên bản mở rộng của `ListDataItem` cho `fullData`:
- `focus: boolean` — `true` nếu mục đang được lấy tiêu điểm.
- `selected: boolean` — `true` nếu mục được chọn.
- `disabled: boolean` — `true` nếu mục bị vô hiệu hóa (ví dụ: khi đạt đến giới hạn `max`).
- `highlight?: string` — chuỗi tìm kiếm hiện tại nếu nó khớp với văn bản của mục.

### `ListListInput`

Các định dạng dữ liệu được hỗ trợ cho hàm khởi tạo:
- `string[]` — mảng chuỗi đơn giản (nhãn).
- `Record<string, string>` — đối tượng `value: label`.
- `ListDataBasic[]` — mảng các đối tượng với các trường như `label`, `value`, `type`, v.v.


## Quản lý lựa chọn (Selection)

Lớp cung cấp các công cụ mạnh mẽ để kiểm soát trạng thái lựa chọn trong danh sách, hỗ trợ lựa chọn đơn và nhiều lựa chọn với các ràng buộc.

### Các tham số lựa chọn cốt lõi

- `selected` — biến phản ứng (Vue `ref`) lưu trữ một mảng các mã định danh.
- `min` / `max` — các ràng buộc về số lượng mục được chọn trên cấp độ hiện tại.

### Lựa chọn Toàn cầu vs Cấp độ Nhóm

- **selectedList** — trả về tất cả các mục đã chọn loại `item` từ toàn bộ cây.
- **selectedListInGroup** — trả về các mục đã chọn chỉ từ cấp độ hiện tại (`data`). Các ràng buộc `min` và `max` làm việc dựa trên danh sách này.

### Trạng thái disabled tự động

Khi đạt đến giới hạn `max` (`isSelectedMax`), lớp sẽ tự động đánh dấu các mục chưa được chọn còn lại trong `fullData` là `disabled: true`.

## Quản lý tiêu điểm (Focus)

Trạng thái tiêu điểm được triển khai thông qua một biến phản ứng bên ngoài (Vue `ref`).

### Các tính năng chính

- **Trạng thái dùng chung** — các danh sách con sử dụng cùng một `ref` tiêu điểm.
- **Tính phản ứng** — `fullData` tự động tính toán `focus: true` bằng cách so sánh `index` với biến tiêu điểm.
- **Điều khiển thủ công** — lớp không tự thay đổi trạng thái tiêu điểm. Các phương thức điều hướng chỉ trả về đối tượng đích.

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

## Tìm kiếm và Làm nổi bật (Highlight)

### Các tham số cốt lõi

- `highlight` — chuỗi phản ứng chứa truy vấn tìm kiếm.
- `highlightLengthStart` — ngưỡng kích hoạt (mặc định là `2`). 

### Cách thức hoạt động

1. **Regex** — tự động tạo biểu thức chính quy khi chuỗi tìm kiếm thay đổi.
2. **Các trường** — tìm kiếm trên `label`, `index` và trường `search`.
3. **fullData** — mỗi mục nhận giá trị `highlight` để hiển thị trong UI.
4. **Kết quả khớp đầu tiên** — `highlightFirstItem` trả về chỉ số của mục đầu tiên tìm thấy trong mảng `map`.

### Kiểm tra trạng thái

- `isHighlight()` — có ít nhất một mục khớp.
- `isHighlightActive()` — chuỗi tìm kiếm đã đạt đến độ dài yêu cầu.

## Chế độ lọc (filterMode)

Tham số `filterMode` là một cờ trạng thái hướng dẫn UI có nên ẩn các mục không khớp hay không. Cờ này được kế thừa bởi các danh sách con.

## Chế độ Lite (Lite Mode)

Tối ưu hóa hiệu suất cho danh sách lớn. Nếu số lượng phần tử > `lite`, thuộc tính `liteData` với cấu trúc đơn giản sẽ được kích hoạt.

## Ví dụ sử dụng

### Hiển thị cây nhóm

```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>
```

## Làm việc với điều hướng

### Điều hướng phẳng vòng lặp

Các phương thức `getItemNext/Prev` và `getIndexNext/Prev` hoạt động thông qua `mapItems` (chỉ các phần tử loại `item`). Điều hướng xuyên suốt cây dữ liệu và có tính vòng lặp.

### Điều hướng dựa trên lựa chọn

`getSelectedNext/Prev` tìm phần tử lân cận so với phần tử được chọn đầu tiên.

### Điều hướng theo ngữ cảnh (Parent)

`getFirstItemByParent` và `getLastItemByParent` tìm ranh giới của cấp độ lồng nhau hiện tại bằng mã định danh cha.
