@snack-uikit/list 0.11.1-preview-5d3667ec.0 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +22 -61
  3. package/dist/components/Items/AccordionItem/AccordionItem.d.ts +4 -2
  4. package/dist/components/Items/AccordionItem/AccordionItem.js +18 -16
  5. package/dist/components/Items/BaseItem/BaseItem.d.ts +8 -4
  6. package/dist/components/Items/BaseItem/BaseItem.js +20 -14
  7. package/dist/components/Items/BaseItem/styles.module.css +20 -119
  8. package/dist/components/Items/GroupItem/GroupItem.d.ts +5 -1
  9. package/dist/components/Items/GroupItem/GroupItem.js +1 -3
  10. package/dist/components/Items/GroupSelectItem/GroupSelectItem.d.ts +4 -0
  11. package/dist/components/Items/GroupSelectItem/GroupSelectItem.js +18 -0
  12. package/dist/components/Items/GroupSelectItem/index.d.ts +1 -0
  13. package/dist/components/Items/GroupSelectItem/index.js +1 -0
  14. package/dist/components/Items/NextListItem/NextListItem.d.ts +6 -2
  15. package/dist/components/Items/NextListItem/NextListItem.js +55 -45
  16. package/dist/components/Items/NextListItem/constants.d.ts +2 -0
  17. package/dist/components/Items/NextListItem/constants.js +10 -0
  18. package/dist/components/Items/PinGroupItem/PinGroupItem.js +7 -3
  19. package/dist/components/Items/PinGroupItem/styles.module.css +26 -14
  20. package/dist/components/Items/SearchItem/SearchItem.d.ts +3 -1
  21. package/dist/components/Items/SearchItem/SearchItem.js +5 -8
  22. package/dist/components/Items/hooks.d.ts +11 -10
  23. package/dist/components/Items/hooks.js +64 -46
  24. package/dist/components/Items/index.d.ts +1 -5
  25. package/dist/components/Items/index.js +1 -5
  26. package/dist/components/Items/styles.module.css +33 -26
  27. package/dist/components/Items/types.d.ts +68 -34
  28. package/dist/components/Items/utils.d.ts +34 -16
  29. package/dist/components/Items/utils.js +135 -37
  30. package/dist/components/Lists/Droplist/DropList.d.ts +1 -1
  31. package/dist/components/Lists/Droplist/DropList.js +78 -50
  32. package/dist/components/Lists/List/List.d.ts +5 -9
  33. package/dist/components/Lists/List/List.js +61 -54
  34. package/dist/components/Lists/ListPrivate/ListPrivate.d.ts +6 -20
  35. package/dist/components/Lists/ListPrivate/ListPrivate.js +9 -8
  36. package/dist/components/Lists/ListPrivate/styles.module.css +1 -0
  37. package/dist/components/Lists/contexts/CollapseProvider.d.ts +13 -1
  38. package/dist/components/Lists/contexts/CollapseProvider.js +2 -0
  39. package/dist/components/Lists/contexts/FocusListProvider.d.ts +9 -0
  40. package/dist/components/Lists/contexts/FocusListProvider.js +5 -0
  41. package/dist/components/Lists/contexts/NewListProvider.d.ts +32 -0
  42. package/dist/components/Lists/contexts/{ListProvider.js → NewListProvider.js} +10 -5
  43. package/dist/components/Lists/contexts/SelectionProvider.d.ts +25 -15
  44. package/dist/components/Lists/contexts/SelectionProvider.js +17 -13
  45. package/dist/components/Lists/contexts/index.d.ts +3 -2
  46. package/dist/components/Lists/contexts/index.js +3 -2
  47. package/dist/components/Lists/hooks.d.ts +10 -12
  48. package/dist/components/Lists/hooks.js +73 -40
  49. package/dist/components/Lists/index.d.ts +2 -1
  50. package/dist/components/Lists/index.js +1 -0
  51. package/dist/components/Lists/types.d.ts +12 -14
  52. package/dist/components/index.d.ts +2 -2
  53. package/dist/components/index.js +1 -1
  54. package/dist/helperComponents/ItemContent/ItemContent.d.ts +15 -0
  55. package/dist/helperComponents/ItemContent/ItemContent.js +23 -0
  56. package/dist/helperComponents/ItemContent/index.d.ts +1 -0
  57. package/dist/helperComponents/ItemContent/index.js +1 -0
  58. package/dist/helperComponents/ItemContent/styles.module.css +117 -0
  59. package/dist/helperComponents/ListEmptyState/ListEmptyState.d.ts +2 -2
  60. package/dist/helperComponents/ListEmptyState/ListEmptyState.js +13 -4
  61. package/dist/helperComponents/Separator/Separator.d.ts +8 -2
  62. package/dist/helperComponents/Separator/Separator.js +22 -2
  63. package/dist/helperComponents/Separator/constants.d.ts +2 -0
  64. package/dist/helperComponents/Separator/constants.js +5 -0
  65. package/dist/helperComponents/Separator/styles.module.css +20 -1
  66. package/dist/helperComponents/index.d.ts +1 -0
  67. package/dist/helperComponents/index.js +1 -0
  68. package/dist/index.d.ts +2 -2
  69. package/dist/index.js +2 -2
  70. package/dist/types.d.ts +1 -1
  71. package/package.json +13 -18
  72. package/src/components/Items/AccordionItem/AccordionItem.tsx +24 -20
  73. package/src/components/Items/BaseItem/BaseItem.tsx +91 -82
  74. package/src/components/Items/BaseItem/styles.module.scss +19 -77
  75. package/src/components/Items/GroupItem/GroupItem.tsx +5 -5
  76. package/src/components/Items/GroupSelectItem/GroupSelectItem.tsx +44 -0
  77. package/src/components/Items/GroupSelectItem/index.ts +1 -0
  78. package/src/components/Items/NextListItem/NextListItem.tsx +88 -85
  79. package/src/components/Items/NextListItem/constants.ts +12 -0
  80. package/src/components/Items/PinGroupItem/PinGroupItem.tsx +14 -4
  81. package/src/components/Items/PinGroupItem/styles.module.scss +14 -14
  82. package/src/components/Items/SearchItem/SearchItem.tsx +6 -8
  83. package/src/components/Items/hooks.tsx +86 -66
  84. package/src/components/Items/index.ts +1 -5
  85. package/src/components/Items/styles.module.scss +36 -25
  86. package/src/components/Items/types.ts +91 -42
  87. package/src/components/Items/utils.ts +199 -52
  88. package/src/components/Lists/Droplist/DropList.tsx +155 -98
  89. package/src/components/Lists/List/List.tsx +129 -104
  90. package/src/components/Lists/ListPrivate/ListPrivate.tsx +19 -20
  91. package/src/components/Lists/ListPrivate/styles.module.scss +1 -0
  92. package/src/components/Lists/contexts/CollapseProvider.tsx +22 -0
  93. package/src/components/Lists/contexts/FocusListProvider.tsx +15 -0
  94. package/src/components/Lists/contexts/NewListProvider.tsx +54 -0
  95. package/src/components/Lists/contexts/SelectionProvider.tsx +56 -39
  96. package/src/components/Lists/contexts/index.ts +3 -2
  97. package/src/components/Lists/hooks.ts +124 -75
  98. package/src/components/Lists/index.ts +2 -2
  99. package/src/components/Lists/types.ts +20 -24
  100. package/src/components/index.ts +17 -2
  101. package/src/helperComponents/ItemContent/ItemContent.tsx +63 -0
  102. package/src/helperComponents/ItemContent/index.ts +1 -0
  103. package/src/helperComponents/ItemContent/styles.module.scss +78 -0
  104. package/src/helperComponents/ListEmptyState/ListEmptyState.tsx +26 -12
  105. package/src/helperComponents/Separator/Separator.tsx +49 -3
  106. package/src/helperComponents/Separator/constants.ts +7 -0
  107. package/src/helperComponents/Separator/styles.module.scss +41 -1
  108. package/src/helperComponents/index.ts +1 -0
  109. package/src/index.ts +4 -2
  110. package/src/types.ts +1 -1
  111. package/dist/components/Items/NextListItem/hooks.d.ts +0 -19
  112. package/dist/components/Items/NextListItem/hooks.js +0 -80
  113. package/dist/components/Lists/contexts/ListProvider.d.ts +0 -17
  114. package/dist/components/Lists/contexts/ParentListProvider.d.ts +0 -18
  115. package/dist/components/Lists/contexts/ParentListProvider.js +0 -12
  116. package/dist/hooks.d.ts +0 -5
  117. package/dist/hooks.js +0 -15
  118. package/dist/utils.d.ts +0 -30
  119. package/dist/utils.js +0 -115
  120. package/src/components/Items/NextListItem/hooks.ts +0 -105
  121. package/src/components/Lists/contexts/CollapseProvider.ts +0 -9
  122. package/src/components/Lists/contexts/ListProvider.tsx +0 -28
  123. package/src/components/Lists/contexts/ParentListProvider.tsx +0 -35
  124. package/src/hooks.ts +0 -27
  125. package/src/utils.ts +0 -175
@@ -1,23 +1,12 @@
1
1
  import { FocusEvent, KeyboardEvent, MouseEvent, ReactNode, RefObject } from 'react';
2
2
  import { TruncateStringProps } from '@snack-uikit/truncate-string';
3
3
  import { WithSupportProps } from '@snack-uikit/utils';
4
- import { SeparatorProps } from '../../helperComponents';
5
- import { ScrollProps, SearchState } from '../../types';
6
- export type ItemContentProps = {
7
- option: string;
8
- caption?: string;
9
- description?: string;
10
- truncate?: {
11
- option?: number;
12
- description?: number;
13
- variant?: TruncateStringProps['variant'];
14
- };
15
- };
16
- export type BaseItemPrivateProps = {
17
- expandIcon?: ReactNode;
18
- open?: boolean;
19
- };
20
- export type BaseItemProps = WithSupportProps<{
4
+ import { ItemContentProps } from '../../helperComponents';
5
+ import { ScrollProps } from '../../types';
6
+ export type AnyType = any;
7
+ export type ItemId = string | number;
8
+ type ItemContent = ItemContentProps;
9
+ export type BaseItem = WithSupportProps<{
21
10
  /**
22
11
  * Слот до основного контента
23
12
  * @type ReactElement
@@ -28,8 +17,10 @@ export type BaseItemProps = WithSupportProps<{
28
17
  * @type ReactElement
29
18
  */
30
19
  afterContent?: ReactNode;
31
- /** Основной контент айтема */
32
- content: ItemContentProps;
20
+ /**
21
+ * Основной контент айтема
22
+ */
23
+ content?: ItemContent | ReactNode;
33
24
  /** Колбек обработки клика */
34
25
  onClick?(e: MouseEvent<HTMLElement>): void;
35
26
  /** Колбек обработки нажатия кнопки мыши */
@@ -41,7 +32,7 @@ export type BaseItemProps = WithSupportProps<{
41
32
  /** Колбек обработки блюра */
42
33
  onBlur?(e: FocusEvent<HTMLElement>): void;
43
34
  /** Уникальный идентификатор */
44
- id?: string | number;
35
+ id?: ItemId;
45
36
  /** Флаг неактивности элемента */
46
37
  disabled?: boolean;
47
38
  itemRef?: RefObject<HTMLElement>;
@@ -56,25 +47,68 @@ export type BaseItemProps = WithSupportProps<{
56
47
  * Флаг отображения состояния выбранного элемента через switch
57
48
  */
58
49
  switch?: boolean;
59
- key?: string | number;
60
50
  itemWrapRender?(item: ReactNode): ReactNode;
61
51
  }>;
62
- type BaseItemsWithoutNonGroupProps = Omit<BaseItemProps, 'switch' | 'inactive'>;
63
- export type ItemProps = BaseItemProps | AccordionItemProps | NextListItemProps | GroupItemProps;
64
- export type AccordionItemProps = BaseItemsWithoutNonGroupProps & {
65
- items: ItemProps[];
52
+ type BaseItemWithoutNonGroup = Omit<BaseItem, 'switch' | 'inactive'>;
53
+ export type Item = BaseItem | AccordionItem | NextListItem | GroupItem | GroupSelectItem;
54
+ export type AccordionItem = BaseItemWithoutNonGroup & {
55
+ items: Item[];
66
56
  type: 'collapse';
67
57
  };
68
- export type NextListItemProps = BaseItemsWithoutNonGroupProps & {
69
- items: ItemProps[];
58
+ export type NextListItem = BaseItemWithoutNonGroup & ScrollProps & {
59
+ items: Item[];
70
60
  type: 'next-list';
71
- placement?: 'right-start' | 'left-start' | 'left' | 'right' | 'left-end' | 'right-end';
72
- search?: SearchState;
73
- onSublistOpenChanged?(open: boolean, id?: string | number): void;
61
+ onSublistOpenChanged?(open: boolean, id?: ItemId): void;
74
62
  loading?: boolean;
75
- } & ScrollProps;
76
- export type GroupItemProps = Omit<SeparatorProps, 'size'> & {
77
- items: ItemProps[];
78
- id?: string | number;
63
+ dataError?: boolean;
64
+ dataFiltered?: boolean;
65
+ placement?: 'right-start' | 'left-start' | 'left' | 'right' | 'left-end' | 'right-end';
66
+ };
67
+ type CommonGroupItem = {
68
+ label?: string;
69
+ truncate?: {
70
+ variant?: TruncateStringProps['variant'];
71
+ };
72
+ mode?: 'primary' | 'secondary';
73
+ divider?: boolean;
74
+ };
75
+ export type GroupItem = CommonGroupItem & {
76
+ items: Item[];
77
+ type: 'group';
78
+ };
79
+ export type GroupSelectItem = CommonGroupItem & {
80
+ items: Item[];
81
+ type: 'group-select';
82
+ id?: ItemId;
83
+ itemRef?: RefObject<HTMLElement>;
84
+ };
85
+ type RequiredFields<T, K extends keyof T> = Required<Pick<T, K>> & Omit<T, K>;
86
+ export type Flatten<T, K extends keyof T> = RequiredFields<T, K>;
87
+ export type CommonFlattenProps = {
88
+ items: ItemId[];
89
+ allChildIds: ItemId[];
90
+ };
91
+ export type FlattenBaseItem = Flatten<BaseItem, 'id'>;
92
+ export type FlattenNextListItem = Flatten<Omit<NextListItem, 'items'>, 'id'>;
93
+ export type FlattenGroupListItem = Omit<GroupItem, 'items'> & {
94
+ id: ItemId;
79
95
  };
96
+ export type FlattenGroupSelectListItem = Flatten<Omit<GroupSelectItem, 'items'>, 'id'>;
97
+ export type FlattenAccordionItem = Flatten<Omit<AccordionItem, 'items'>, 'id'>;
98
+ export type FlattenItem = FlattenBaseItem | ((FlattenNextListItem | FlattenGroupListItem | FlattenAccordionItem | FlattenGroupSelectListItem) & CommonFlattenProps);
99
+ export type FocusFlattenItem = {
100
+ key: ItemId;
101
+ id: ItemId;
102
+ originalId: ItemId;
103
+ parentId?: ItemId;
104
+ itemRef?: RefObject<HTMLElement>;
105
+ type?: 'next-list' | 'collapse' | 'group' | 'group-select';
106
+ disabled?: boolean;
107
+ } & CommonFlattenProps;
108
+ export type ItemProps = Item;
109
+ export type BaseItemProps = BaseItem;
110
+ export type GroupItemProps = GroupItem;
111
+ export type NextListItemProps = NextListItem;
112
+ export type AccordionItemProps = AccordionItem;
113
+ export type GroupSelectItemProps = GroupSelectItem;
80
114
  export {};
@@ -1,17 +1,35 @@
1
- import { AccordionItemProps, BaseItemProps, GroupItemProps, ItemProps, NextListItemProps } from './types';
2
- export declare function isBaseItemProps(item: any): item is BaseItemProps;
3
- export declare function isAccordionItemProps(item: any): item is AccordionItemProps;
4
- export declare function isNextListItemProps(item: any): item is NextListItemProps;
5
- export declare function isGroupItemProps(item: any): item is GroupItemProps;
6
- export declare function getSlicedItems({ items, hasSearch, pinTop, pinBottom, footerRefs, }: {
7
- items: ItemProps[];
8
- hasSearch: boolean;
9
- footerRefs: ItemProps[];
10
- pinTop?: ItemProps[];
11
- pinBottom?: ItemProps[];
12
- }): {
13
- pinTop: ItemProps[];
14
- items: ItemProps[];
15
- pinBottom: ItemProps[];
1
+ import { ItemContentProps } from '../../helperComponents';
2
+ import { AccordionItem, AnyType, BaseItem, FlattenItem, FocusFlattenItem, GroupItem, GroupSelectItem, Item, ItemId, NextListItem } from './types';
3
+ export declare function isBaseItem<ReturnType = BaseItem>(item: AnyType): item is ReturnType;
4
+ export declare function isAccordionItem<ReturnType = AccordionItem>(item: AnyType): item is ReturnType;
5
+ export declare function isNextListItem<ReturnType = NextListItem>(item: AnyType): item is ReturnType;
6
+ export declare function isGroupItem<ReturnType = GroupItem>(item: AnyType): item is ReturnType;
7
+ export declare function isGroupSelectItem<ReturnType = GroupSelectItem>(item: AnyType): item is ReturnType;
8
+ export declare function isContentItem(item: AnyType): item is ItemContentProps;
9
+ export declare const isBaseItemProps: typeof isBaseItem;
10
+ export declare const isAccordionItemProps: typeof isAccordionItem;
11
+ export declare const isNextListItemProps: typeof isNextListItem;
12
+ export declare const isGroupItemProps: typeof isGroupItem;
13
+ type KindFlattenItemsProps = {
14
+ items: Item[];
15
+ prefix?: ItemId;
16
+ parentId?: ItemId;
16
17
  };
17
- export declare function addItemsIds(itemsProp: ItemProps[], prefix?: string | number): ItemProps[];
18
+ export declare function kindFlattenItems({ items, prefix, parentId }: KindFlattenItemsProps): {
19
+ focusCloseChildIds: ItemId[];
20
+ allChildIds: ItemId[];
21
+ flattenItems: Record<string, FlattenItem>;
22
+ focusFlattenItems: Record<string, FocusFlattenItem>;
23
+ };
24
+ type ExtractActiveItemsProps = {
25
+ focusFlattenItems: Record<string, FocusFlattenItem>;
26
+ focusCloseChildIds: ItemId[];
27
+ openCollapseItems: ItemId[];
28
+ isSelectionMultiple?: boolean;
29
+ };
30
+ type ExtractActiveItemsReturnType = {
31
+ ids: ItemId[];
32
+ expandedIds: ItemId[];
33
+ };
34
+ export declare function extractActiveItems({ focusFlattenItems, focusCloseChildIds, openCollapseItems, isSelectionMultiple, }: ExtractActiveItemsProps): ExtractActiveItemsReturnType;
35
+ export {};
@@ -1,43 +1,141 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
1
12
  import { createRef } from 'react';
2
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
3
- export function isBaseItemProps(item) {
4
- return 'content' in item;
5
- }
6
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
7
- export function isAccordionItemProps(item) {
8
- return 'items' in item && item['type'] === 'collapse';
9
- }
10
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
11
- export function isNextListItemProps(item) {
12
- return 'items' in item && item['type'] === 'next-list';
13
- }
14
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
15
- export function isGroupItemProps(item) {
16
- return 'items' in item && item['type'] === undefined;
17
- }
18
- export function getSlicedItems({ items, hasSearch, pinTop, pinBottom, footerRefs, }) {
19
- var _a, _b, _c;
20
- const searchShift = hasSearch ? 1 : 0;
21
- const pinTopNumber = (_a = pinTop === null || pinTop === void 0 ? void 0 : pinTop.length) !== null && _a !== void 0 ? _a : 0;
22
- const pinBottomNumber = (_b = pinBottom === null || pinBottom === void 0 ? void 0 : pinBottom.length) !== null && _b !== void 0 ? _b : 0;
23
- const footerElementsNumber = (_c = footerRefs === null || footerRefs === void 0 ? void 0 : footerRefs.length) !== null && _c !== void 0 ? _c : 0;
24
- return {
25
- pinTop: items.slice(searchShift, pinTopNumber + searchShift),
26
- items: items.slice(pinTopNumber + searchShift, items.length - pinBottomNumber - footerElementsNumber),
27
- pinBottom: items.slice(items.length - pinBottomNumber - footerElementsNumber, items.length - footerElementsNumber),
28
- };
13
+ export function isBaseItem(item) {
14
+ return item && !('items' in item);
15
+ }
16
+ export function isAccordionItem(item) {
17
+ return item && 'items' in item && item['type'] === 'collapse';
18
+ }
19
+ export function isNextListItem(item) {
20
+ return item && 'items' in item && item['type'] === 'next-list';
21
+ }
22
+ export function isGroupItem(item) {
23
+ return item && 'items' in item && item['type'] === 'group';
24
+ }
25
+ export function isGroupSelectItem(item) {
26
+ return item && 'items' in item && item['type'] === 'group-select';
29
27
  }
30
- export function addItemsIds(itemsProp, prefix) {
31
- return itemsProp.map((item, idx) => {
32
- var _a;
28
+ export function isContentItem(item) {
29
+ return typeof item === 'object' && item['option'] !== undefined;
30
+ }
31
+ export const isBaseItemProps = isBaseItem;
32
+ export const isAccordionItemProps = isAccordionItem;
33
+ export const isNextListItemProps = isNextListItem;
34
+ export const isGroupItemProps = isGroupItem;
35
+ export function kindFlattenItems({ items, prefix, parentId }) {
36
+ const flattenItems = {};
37
+ const focusFlattenItems = {};
38
+ function flatten({ item, idx, prefix, parentId = '~main' }) {
39
+ var _a, _b;
33
40
  const autoId = prefix !== undefined ? [prefix, idx].join('-') : String(idx);
34
- const itemId = (_a = item.id) !== null && _a !== void 0 ? _a : autoId;
35
- if (isGroupItemProps(item)) {
36
- return Object.assign(Object.assign({ key: autoId }, item), { id: itemId, items: addItemsIds(item.items, itemId) });
41
+ const itemId = (_a = (!isGroupItem(item) ? item.id : undefined)) !== null && _a !== void 0 ? _a : autoId;
42
+ if (isBaseItem(item)) {
43
+ flattenItems[itemId] = Object.assign(Object.assign({}, item), { items: [], allChildIds: [], id: itemId });
44
+ focusFlattenItems[autoId] = {
45
+ key: autoId,
46
+ originalId: itemId,
47
+ id: autoId,
48
+ disabled: item.disabled,
49
+ parentId,
50
+ items: [],
51
+ allChildIds: [],
52
+ itemRef: item.itemRef || createRef(),
53
+ };
54
+ return { id: itemId, children: [itemId], autoId, focusChildren: [autoId] };
37
55
  }
38
- if (isAccordionItemProps(item) || isNextListItemProps(item)) {
39
- return Object.assign(Object.assign({ key: autoId }, item), { id: itemId, items: addItemsIds(item.items, itemId), itemRef: item.itemRef || createRef() });
56
+ let allChildIds = [];
57
+ let allFocusChildIds = [];
58
+ const closeChildIds = [];
59
+ const autoChildIds = [];
60
+ const { items } = item, rest = __rest(item, ["items"]);
61
+ const childActiveParent = isGroupItem(item) ? parentId !== null && parentId !== void 0 ? parentId : '~main' : autoId;
62
+ for (let idx = 0; idx < items.length; idx++) {
63
+ const { id, children, autoId, focusChildren } = flatten({
64
+ item: items[idx],
65
+ idx,
66
+ prefix: itemId,
67
+ parentId: childActiveParent,
68
+ });
69
+ autoChildIds.push(autoId);
70
+ closeChildIds.push(id);
71
+ allChildIds = allChildIds.concat(children);
72
+ allFocusChildIds = allFocusChildIds.concat(focusChildren);
40
73
  }
41
- return Object.assign(Object.assign({ key: autoId }, item), { id: itemId, itemRef: item.itemRef || createRef() });
42
- });
74
+ const children = [...new Set(allChildIds.concat(closeChildIds))];
75
+ const focusChildren = [...new Set(allFocusChildIds.concat(autoChildIds))];
76
+ flattenItems[itemId] = Object.assign(Object.assign({}, rest), { id: itemId, items: [], allChildIds: children });
77
+ focusFlattenItems[autoId] = {
78
+ key: autoId,
79
+ originalId: itemId,
80
+ id: autoId,
81
+ parentId,
82
+ items: autoChildIds,
83
+ allChildIds: focusChildren,
84
+ disabled: (item.type === 'collapse' || item.type === 'next-list') && item.disabled,
85
+ type: item.type,
86
+ itemRef: (_b = (!isGroupItem(item) ? item.itemRef : undefined)) !== null && _b !== void 0 ? _b : createRef(),
87
+ };
88
+ return { id: itemId, children, autoId, focusChildren };
89
+ }
90
+ const closeChildIds = [];
91
+ const autoChildIds = [];
92
+ let allChildIds = [];
93
+ for (let idx = 0; idx < items.length; idx++) {
94
+ const { id, children, autoId } = flatten({ item: items[idx], idx, prefix, parentId });
95
+ autoChildIds.push(autoId);
96
+ closeChildIds.push(id);
97
+ allChildIds.push(id);
98
+ allChildIds = allChildIds.concat(children);
99
+ }
100
+ const children = [...new Set(allChildIds)];
101
+ return {
102
+ focusCloseChildIds: autoChildIds,
103
+ allChildIds: children,
104
+ flattenItems,
105
+ focusFlattenItems,
106
+ };
107
+ }
108
+ export function extractActiveItems({ focusFlattenItems, focusCloseChildIds, openCollapseItems, isSelectionMultiple, }) {
109
+ const ids = [];
110
+ const expandedIds = [];
111
+ function internalFn(focusCloseChildIds) {
112
+ focusCloseChildIds.forEach(id => {
113
+ const child = focusFlattenItems[id];
114
+ if (child.type === 'group') {
115
+ internalFn(child.items);
116
+ return;
117
+ }
118
+ if (!child.disabled) {
119
+ if (child.type === 'group-select') {
120
+ if (isSelectionMultiple) {
121
+ ids.push(child.id);
122
+ }
123
+ internalFn(child.items);
124
+ return;
125
+ }
126
+ ids.push(child.id);
127
+ if (child.type) {
128
+ expandedIds.push(id);
129
+ if (openCollapseItems.includes(child.originalId)) {
130
+ internalFn(child.items);
131
+ }
132
+ }
133
+ }
134
+ });
135
+ }
136
+ internalFn(focusCloseChildIds);
137
+ return {
138
+ ids,
139
+ expandedIds,
140
+ };
43
141
  }
@@ -1,2 +1,2 @@
1
1
  import { DroplistProps } from '../types';
2
- export declare function Droplist({ items: itemsProp, search, pinBottom, pinTop, footerActiveElementsRefs, children, trigger, placement, widthStrategy, triggerElemRef: triggerElemRefProp, open: openProp, onOpenChange, collapse, ...props }: DroplistProps): import("react/jsx-runtime").JSX.Element;
2
+ export declare function Droplist({ items: itemsProp, search, pinBottom: pinBottomProp, pinTop: pinTopProp, footerActiveElementsRefs, children, trigger, placement, widthStrategy, triggerElemRef: triggerElemRefProp, open: openProp, onOpenChange, collapse, triggerClassName, selection, contentRender, size, marker, className, ...props }: DroplistProps): import("react/jsx-runtime").JSX.Element;
@@ -10,46 +10,77 @@ var __rest = (this && this.__rest) || function (s, e) {
10
10
  return t;
11
11
  };
12
12
  import { jsx as _jsx } from "react/jsx-runtime";
13
+ import cn from 'classnames';
14
+ import mergeRefs from 'merge-refs';
13
15
  import { cloneElement, isValidElement, useCallback, useMemo, useRef } from 'react';
14
- import { useUncontrolledProp } from 'uncontrollable';
15
16
  import { Dropdown } from '@snack-uikit/dropdown';
16
- import { extractItemIds, extractItemRefs, withCollapsedItems } from '../../../utils';
17
- import { addItemsIds, getSlicedItems, useItemsWithIds } from '../../Items';
18
- import { extractSelectionProps, ParentListContext, SelectionProvider } from '../contexts';
19
- import { useKeyboardNavigation } from '../hooks';
17
+ import { useValueControl } from '@snack-uikit/utils';
18
+ import { extractActiveItems, kindFlattenItems, useCreateBaseItems } from '../../Items';
19
+ import { CollapseContext, FocusListContext, NewListContextProvider, SelectionProvider } from '../contexts';
20
+ import { useNewKeyboardNavigation } from '../hooks';
20
21
  import { ListPrivate } from '../ListPrivate';
22
+ import styles from '../styles.module.css';
23
+ const DEFAULT_FALLBACK_PLACEMENTS = ['top', 'right', 'bottom', 'left'];
21
24
  export function Droplist(_a) {
22
- var _b;
23
- var { items: itemsProp, search, pinBottom, pinTop, footerActiveElementsRefs, children, trigger, placement, widthStrategy, triggerElemRef: triggerElemRefProp, open: openProp, onOpenChange, collapse = {} } = _a, props = __rest(_a, ["items", "search", "pinBottom", "pinTop", "footerActiveElementsRefs", "children", "trigger", "placement", "widthStrategy", "triggerElemRef", "open", "onOpenChange", "collapse"]);
25
+ var { items: itemsProp, search, pinBottom: pinBottomProp = [], pinTop: pinTopProp = [], footerActiveElementsRefs, children, trigger, placement, widthStrategy, triggerElemRef: triggerElemRefProp, open: openProp, onOpenChange, collapse = {}, triggerClassName, selection, contentRender, size = 's', marker = true, className } = _a, props = __rest(_a, ["items", "search", "pinBottom", "pinTop", "footerActiveElementsRefs", "children", "trigger", "placement", "widthStrategy", "triggerElemRef", "open", "onOpenChange", "collapse", "triggerClassName", "selection", "contentRender", "size", "marker", "className"]);
24
26
  const hasSearch = useMemo(() => Boolean(search), [search]);
25
- const memorizedItems = useMemo(() => addItemsIds((pinTop !== null && pinTop !== void 0 ? pinTop : []).concat(itemsProp).concat(pinBottom !== null && pinBottom !== void 0 ? pinBottom : [])), [itemsProp, pinBottom, pinTop]);
26
- const [openCollapsedItems, setOpenCollapsedItems] = useUncontrolledProp(collapse.value, (_b = collapse.defaultValue) !== null && _b !== void 0 ? _b : [], collapse.onChange);
27
- const { search: searchItem, footerRefs } = useItemsWithIds({
28
- search: hasSearch,
29
- footerActiveElementsRefs,
27
+ const [openCollapseItems = [], setOpenCollapsedItems] = useValueControl(collapse);
28
+ const toggleOpenCollapseItem = useCallback((id) => setOpenCollapsedItems((items) => (items === null || items === void 0 ? void 0 : items.includes(id)) ? items.filter(item => item !== id) : (items !== null && items !== void 0 ? items : []).concat([id])), [setOpenCollapsedItems]);
29
+ const [open = false, setOpen] = useValueControl({
30
+ value: openProp,
31
+ defaultValue: false,
32
+ onChange: onOpenChange,
30
33
  });
31
- const { items, itemRefs, ids, expandedIds } = useMemo(() => {
32
- const res = withCollapsedItems({
33
- items: memorizedItems,
34
- openCollapsedItems,
34
+ const { searchItem, footerItems } = useCreateBaseItems({ footerActiveElementsRefs });
35
+ /**
36
+ * Объект с пропсами всех вложенных айтемов; ключ id
37
+ */
38
+ const _b = useMemo(() => {
39
+ const pinTop = kindFlattenItems({ items: pinTopProp, prefix: '~pinTop', parentId: '~main' });
40
+ const items = kindFlattenItems({ items: itemsProp, prefix: '~main', parentId: '~main' });
41
+ const pinBottom = kindFlattenItems({ items: pinBottomProp, prefix: '~pinBottom', parentId: '~main' });
42
+ const flattenItems = Object.assign(Object.assign(Object.assign({}, pinTop.flattenItems), pinBottom.flattenItems), items.flattenItems);
43
+ const focusFlattenItems = Object.assign(Object.assign(Object.assign({}, pinTop.focusFlattenItems), pinBottom.focusFlattenItems), items.focusFlattenItems);
44
+ [...footerItems, searchItem].forEach(item => {
45
+ flattenItems[item.id] = item;
46
+ focusFlattenItems[item.id] = Object.assign(Object.assign({}, item), { originalId: item.id, items: [], key: item.id, allChildIds: [] });
47
+ });
48
+ return { items, pinTop, pinBottom, flattenItems, focusFlattenItems };
49
+ }, [itemsProp, pinTopProp, pinBottomProp, searchItem, footerItems]), { flattenItems, focusFlattenItems } = _b, memorizedItems = __rest(_b, ["flattenItems", "focusFlattenItems"]);
50
+ const { ids, expandedIds } = useMemo(() => {
51
+ const { pinTop, items, pinBottom } = memorizedItems;
52
+ let ids = [];
53
+ let expandedIds = [];
54
+ if (hasSearch) {
55
+ ids.push(searchItem.id);
56
+ }
57
+ [pinTop, items, pinBottom].forEach(({ focusFlattenItems, focusCloseChildIds }) => {
58
+ const activeItems = extractActiveItems({
59
+ focusFlattenItems,
60
+ focusCloseChildIds,
61
+ openCollapseItems,
62
+ isSelectionMultiple: (selection === null || selection === void 0 ? void 0 : selection.mode) === 'multiple',
63
+ });
64
+ ids = ids.concat(activeItems.ids);
65
+ expandedIds = expandedIds.concat(activeItems.expandedIds);
66
+ });
67
+ footerItems.forEach(footerItem => {
68
+ ids.push(footerItem.id);
35
69
  });
36
- const items = searchItem.concat(res.items).concat(footerRefs);
37
70
  return {
38
- items,
39
- ids: extractItemIds(searchItem).concat(res.ids).concat(extractItemIds(footerRefs)),
40
- itemRefs: extractItemRefs(searchItem).concat(res.itemRefs).concat(extractItemRefs(footerRefs)),
41
- expandedIds: res.expandedIds,
71
+ ids,
72
+ expandedIds,
42
73
  };
43
- }, [footerRefs, memorizedItems, openCollapsedItems, searchItem]);
44
- const slicedItems = useMemo(() => getSlicedItems({ items, hasSearch, pinTop, pinBottom, footerRefs }), [items, hasSearch, pinTop, pinBottom, footerRefs]);
74
+ }, [footerItems, hasSearch, memorizedItems, openCollapseItems, searchItem.id, selection === null || selection === void 0 ? void 0 : selection.mode]);
45
75
  const triggerElemRef = useRef(null);
46
76
  const listRef = useRef(null);
47
- const { activeFocusIndex, setActiveFocusIndex, openNestedIndex, handleListKeyDown, resetNestedIndex, resetActiveFocusIndex, } = useKeyboardNavigation({ ids, expandedIds, parentRef: triggerElemRefProp !== null && triggerElemRefProp !== void 0 ? triggerElemRefProp : triggerElemRef, itemRefs });
48
- const [open, setOpen] = useUncontrolledProp(openProp, false, onOpenChange);
77
+ const { handleListKeyDownFactory, resetActiveItemId, activeItemId, forceUpdateActiveItemId } = useNewKeyboardNavigation({
78
+ mainRef: triggerElemRef,
79
+ focusFlattenItems,
80
+ });
81
+ const handleListKeyDown = useCallback((e) => handleListKeyDownFactory(ids, expandedIds)(e), [handleListKeyDownFactory, ids, expandedIds]);
49
82
  const handleOpenChange = (open) => {
50
- resetNestedIndex();
51
- resetActiveFocusIndex();
52
- setOpenCollapsedItems([]);
83
+ resetActiveItemId();
53
84
  setOpen(open);
54
85
  };
55
86
  const onKeyDown = useCallback((e, cb) => {
@@ -58,12 +89,15 @@ export function Droplist(_a) {
58
89
  setOpen(true);
59
90
  setTimeout(() => {
60
91
  var _a;
92
+ resetActiveItemId();
61
93
  (_a = listRef.current) === null || _a === void 0 ? void 0 : _a.focus();
62
- setActiveFocusIndex(0);
63
94
  }, 0);
64
95
  }
96
+ if (e.key === 'ArrowUp') {
97
+ setOpen(false);
98
+ }
65
99
  cb === null || cb === void 0 ? void 0 : cb(e);
66
- }, [setActiveFocusIndex, setOpen]);
100
+ }, [resetActiveItemId, setOpen]);
67
101
  const triggerElem = useMemo(() => {
68
102
  if (isValidElement(children)) {
69
103
  const props = typeof children.props === 'object' ? children.props : {};
@@ -77,24 +111,18 @@ export function Droplist(_a) {
77
111
  }
78
112
  return children;
79
113
  }, [onKeyDown, children]);
80
- return (
81
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
82
- // @ts-ignore
83
- _jsx(SelectionProvider, Object.assign({}, extractSelectionProps(props), { children: _jsx(ParentListContext.Provider, { value: {
84
- parentIds: ids,
85
- parentActiveFocusIndex: activeFocusIndex,
86
- parentExpandedIds: expandedIds,
87
- parentItemRefs: itemRefs,
88
- parentOpenNestedIndex: openNestedIndex,
89
- triggerRef: triggerElemRefProp !== null && triggerElemRefProp !== void 0 ? triggerElemRefProp : triggerElemRef,
90
- parentRef: listRef,
91
- parentResetNestedIndex: resetNestedIndex,
92
- parentResetActiveFocusIndex: resetActiveFocusIndex,
93
- openCollapsedItems,
94
- toggleOpenCollapsedItems: id => setOpenCollapsedItems((items = []) => items.includes(id) ? items.filter(item => item !== id) : items === null || items === void 0 ? void 0 : items.concat([id])),
95
- }, children: _jsx(Dropdown, Object.assign({ content: _jsx(ListPrivate, Object.assign({}, slicedItems, props, { onKeyDown: handleListKeyDown, tabIndex: 0, ref: listRef, search: search, limitedScrollHeight: true, parent: 'droplist' })), trigger: trigger, placement: placement, widthStrategy: widthStrategy }, (triggerElemRefProp
96
- ? {}
97
- : {
98
- triggerRef: triggerElemRef,
99
- }), { open: open, onOpenChange: handleOpenChange, children: triggerElem })) }) })));
114
+ return (_jsx(NewListContextProvider, { flattenItems: flattenItems, focusFlattenItems: focusFlattenItems, contentRender: contentRender, size: size, marker: marker, children: _jsx(SelectionProvider, Object.assign({}, selection, { children: _jsx(CollapseContext.Provider, { value: {
115
+ openCollapseItems,
116
+ toggleOpenCollapseItem,
117
+ }, children: _jsx(FocusListContext.Provider, { value: {
118
+ activeItemId,
119
+ handleListKeyDownFactory,
120
+ forceUpdateActiveItemId,
121
+ }, children: _jsx(Dropdown, { content: _jsx("div", { className: cn(styles.wrapper, className), children: _jsx(ListPrivate, Object.assign({}, props, { items: memorizedItems.items.focusCloseChildIds, pinTop: memorizedItems.pinTop.focusCloseChildIds, pinBottom: memorizedItems.pinBottom.focusCloseChildIds, onKeyDown: handleListKeyDown, searchItem: searchItem, tabIndex: 0, ref: listRef, search: search, onFocus: e => {
122
+ e.stopPropagation();
123
+ forceUpdateActiveItemId === null || forceUpdateActiveItemId === void 0 ? void 0 : forceUpdateActiveItemId(ids[0]);
124
+ }, limitedScrollHeight: true })) }), triggerClassName: triggerClassName, fallbackPlacements: DEFAULT_FALLBACK_PLACEMENTS, trigger: trigger, placement: placement, widthStrategy: widthStrategy,
125
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
126
+ // @ts-expect-error
127
+ triggerRef: triggerElemRefProp ? mergeRefs(triggerElemRef, triggerElemRefProp) : triggerElemRef, open: open, onOpenChange: handleOpenChange, children: triggerElem }) }) }) })) }));
100
128
  }
@@ -2,19 +2,15 @@ import { KeyboardEvent } from 'react';
2
2
  export declare const List: import("react").ForwardRefExoticComponent<{
3
3
  'data-test-id'?: string | undefined;
4
4
  } & import("react").AriaAttributes & {
5
- items: import("../../Items").ItemProps[];
6
- pinTop?: import("../../Items").ItemProps[] | undefined;
7
- pinBottom?: import("../../Items").ItemProps[] | undefined;
5
+ items: import("../../Items").Item[];
6
+ pinTop?: import("../../Items").Item[] | undefined;
7
+ pinBottom?: import("../../Items").Item[] | undefined;
8
8
  footer?: import("react").ReactNode;
9
9
  footerActiveElementsRefs?: import("react").RefObject<HTMLElement>[] | undefined;
10
10
  search?: import("../../..").SearchState | undefined;
11
11
  tabIndex?: number | undefined;
12
- collapse?: {
13
- value?: (string | number)[] | undefined;
14
- onChange?(value: (string | number)[]): void;
15
- defaultValue?: (string | number)[] | undefined;
16
- } | undefined;
12
+ collapse?: import("../contexts").CollapseState | undefined;
17
13
  className?: string | undefined;
18
14
  onKeyDown?(e: KeyboardEvent<HTMLElement>): void;
19
15
  loading?: boolean | undefined;
20
- } & import("../contexts").SelectionState & import("../contexts").ListContextType & import("../../../types").ScrollProps & import("../types").EmptyState & import("react").RefAttributes<HTMLElement>>;
16
+ } & import("../contexts").SelectionState & import("../contexts").PublicListContextType & import("../../../types").ScrollProps & import("../types").EmptyState & import("react").RefAttributes<HTMLElement>>;