-
Notifications
You must be signed in to change notification settings - Fork 0
/
useSection.ts
83 lines (75 loc) · 3.04 KB
/
useSection.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import { useCallback, useEffect } from 'react';
import { spatnavInstance, Config, SECTION_ROOT_CLASS_NAME } from '../../core';
export type CustomizeConfig = (config: Partial<Config>) => void;
export type UseSectionResultTuple<S extends string> = [
{ className: typeof SECTION_ROOT_CLASS_NAME; id: S | '' },
CustomizeConfig,
];
/**
* Создаёт секцию и набор инструментов для работы с ней.
* Если изменить имя секции, передаваемое в хук, то будет создана новая секция с новым конфигом, а старая будет удалена.
*
* @param sectionId имя секции, если передано существующее — хук вернёт tuple с данными существующей секции
*
* @returns Объект с props для корневого элемента секции и функция для кастомизации параметров секции.
* Колбек `customizeConfig` мемоизирован с помощью `useCallback` и зависит `sectionId`.
*
* @example
* ```typescript
* const Page1 = ({ condition }) => {
* const [section1Props, customizeSection1] = useSection('section1');
* const [section2Props, customizeSection2] = useSection(condition ? 'section2' : '');
*
* useEffect(() => {
* customizeSection1({
* enterTo: 'default-element',
* straightOnly: true
* })
* }, [customizeSection1]);
*
* useEffect(() => {
* customizeSection2({
* enterTo: 'default-element'
* })
* }, [customizeSection2]);
*
* const onSelect = useCallback((event: KeyboardEvent) => {
* // ваша обработка
* }, []);
*
* return (
* <>
* <div {...section1Props}> // или <div id={section1Props.id} className={section1Props.className}>
* <FocusableButton onKeyDown={onSelect} />
* <FocusableButton onKeyDown={onSelect} />
* </div>
* {condition && <div {...section2Props}> // или <div id={section2Props.id} className={section2Props.className}>
* <FocusableButton onKeyDown={onSelect} />
* <FocusableButton onKeyDown={onSelect} />
* </div>}
* </>
* );
* };
* ```
*/
export function useSection<S extends string>(sectionId: S): UseSectionResultTuple<S> {
useEffect(() => {
if (sectionId === '') {
return;
}
spatnavInstance.add(sectionId);
return () => {
spatnavInstance.remove(sectionId);
};
}, [sectionId]);
const customizeConfig = useCallback(
(sectionConfig: Partial<Config>) => {
if (sectionId === '') {
return;
}
spatnavInstance.set(sectionId, sectionConfig);
},
[sectionId],
);
return [{ className: SECTION_ROOT_CLASS_NAME, id: sectionId }, customizeConfig];
}