@snack-uikit/list 0.9.2-preview-c8f85f20.0 → 0.9.2-preview-0a44b2fc.0

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 (105) hide show
  1. package/README.md +51 -23
  2. package/dist/components/Items/AccordionItem/AccordionItem.d.ts +2 -2
  3. package/dist/components/Items/AccordionItem/AccordionItem.js +19 -16
  4. package/dist/components/Items/BaseItem/BaseItem.d.ts +5 -4
  5. package/dist/components/Items/BaseItem/BaseItem.js +22 -16
  6. package/dist/components/Items/BaseItem/styles.module.css +9 -122
  7. package/dist/components/Items/GroupItem/GroupItem.d.ts +2 -2
  8. package/dist/components/Items/GroupItem/GroupItem.js +3 -3
  9. package/dist/components/Items/NextListItem/NextListItem.d.ts +2 -2
  10. package/dist/components/Items/NextListItem/NextListItem.js +37 -36
  11. package/dist/components/Items/SearchItem/SearchItem.d.ts +3 -1
  12. package/dist/components/Items/SearchItem/SearchItem.js +7 -8
  13. package/dist/components/Items/hooks.d.ts +14 -9
  14. package/dist/components/Items/hooks.js +46 -30
  15. package/dist/components/Items/types.d.ts +41 -26
  16. package/dist/components/Items/utils.d.ts +7 -17
  17. package/dist/components/Items/utils.js +3 -31
  18. package/dist/components/Lists/Droplist/DropList.d.ts +2 -1
  19. package/dist/components/Lists/Droplist/DropList.js +85 -50
  20. package/dist/components/Lists/List/List.d.ts +7 -11
  21. package/dist/components/Lists/List/List.js +61 -53
  22. package/dist/components/Lists/ListPrivate/ListPrivate.d.ts +18 -20
  23. package/dist/components/Lists/ListPrivate/ListPrivate.js +10 -9
  24. package/dist/components/Lists/contexts/CollapseProvider.d.ts +13 -1
  25. package/dist/components/Lists/contexts/CollapseProvider.js +2 -0
  26. package/dist/components/Lists/contexts/FocusListProvider.d.ts +9 -0
  27. package/dist/components/Lists/contexts/FocusListProvider.js +5 -0
  28. package/dist/components/Lists/contexts/NewListProvider.d.ts +27 -0
  29. package/dist/components/Lists/contexts/{ListProvider.js → NewListProvider.js} +10 -5
  30. package/dist/components/Lists/contexts/SelectionProvider.d.ts +28 -15
  31. package/dist/components/Lists/contexts/SelectionProvider.js +14 -8
  32. package/dist/components/Lists/contexts/index.d.ts +2 -2
  33. package/dist/components/Lists/contexts/index.js +2 -2
  34. package/dist/components/Lists/hooks.d.ts +11 -11
  35. package/dist/components/Lists/hooks.js +80 -41
  36. package/dist/components/Lists/types.d.ts +19 -15
  37. package/dist/helperComponents/ItemContent/ItemContent.d.ts +15 -0
  38. package/dist/helperComponents/ItemContent/ItemContent.js +23 -0
  39. package/dist/helperComponents/ItemContent/index.d.ts +1 -0
  40. package/dist/helperComponents/ItemContent/index.js +1 -0
  41. package/dist/helperComponents/ItemContent/styles.module.css +117 -0
  42. package/dist/helperComponents/ListEmptyState/ListEmptyState.d.ts +2 -2
  43. package/dist/helperComponents/ListEmptyState/ListEmptyState.js +13 -4
  44. package/dist/helperComponents/index.d.ts +1 -0
  45. package/dist/helperComponents/index.js +1 -0
  46. package/dist/hooks.d.ts +1 -1
  47. package/dist/hooks.js +15 -10
  48. package/dist/index.d.ts +3 -2
  49. package/dist/index.js +3 -2
  50. package/dist/legacy/components/Items/hooks.d.ts +12 -0
  51. package/dist/legacy/components/Items/hooks.js +33 -0
  52. package/dist/legacy/components/index.d.ts +1 -0
  53. package/dist/legacy/components/index.js +1 -0
  54. package/dist/legacy/hooks.d.ts +5 -0
  55. package/dist/legacy/hooks.js +15 -0
  56. package/dist/legacy/index.d.ts +3 -0
  57. package/dist/legacy/index.js +3 -0
  58. package/dist/legacy/utils.d.ts +29 -0
  59. package/dist/legacy/utils.js +107 -0
  60. package/dist/types.d.ts +1 -1
  61. package/dist/utils.d.ts +27 -25
  62. package/dist/utils.js +74 -103
  63. package/package.json +12 -12
  64. package/src/components/Items/AccordionItem/AccordionItem.tsx +26 -19
  65. package/src/components/Items/BaseItem/BaseItem.tsx +48 -46
  66. package/src/components/Items/BaseItem/styles.module.scss +8 -70
  67. package/src/components/Items/GroupItem/GroupItem.tsx +6 -5
  68. package/src/components/Items/NextListItem/NextListItem.tsx +67 -78
  69. package/src/components/Items/SearchItem/SearchItem.tsx +8 -8
  70. package/src/components/Items/hooks.tsx +76 -54
  71. package/src/components/Items/types.ts +61 -31
  72. package/src/components/Items/utils.ts +9 -58
  73. package/src/components/Lists/Droplist/DropList.tsx +155 -102
  74. package/src/components/Lists/List/List.tsx +120 -105
  75. package/src/components/Lists/ListPrivate/ListPrivate.tsx +26 -27
  76. package/src/components/Lists/contexts/CollapseProvider.tsx +22 -0
  77. package/src/components/Lists/contexts/FocusListProvider.tsx +16 -0
  78. package/src/components/Lists/contexts/NewListProvider.tsx +49 -0
  79. package/src/components/Lists/contexts/SelectionProvider.tsx +63 -36
  80. package/src/components/Lists/contexts/index.ts +3 -2
  81. package/src/components/Lists/hooks.ts +139 -75
  82. package/src/components/Lists/types.ts +29 -27
  83. package/src/helperComponents/ItemContent/ItemContent.tsx +63 -0
  84. package/src/helperComponents/ItemContent/index.ts +1 -0
  85. package/src/helperComponents/ItemContent/styles.module.scss +78 -0
  86. package/src/helperComponents/ListEmptyState/ListEmptyState.tsx +21 -13
  87. package/src/helperComponents/index.ts +1 -0
  88. package/src/hooks.ts +21 -15
  89. package/src/index.ts +9 -2
  90. package/src/legacy/components/Items/hooks.tsx +53 -0
  91. package/src/legacy/components/index.ts +1 -0
  92. package/src/legacy/hooks.ts +27 -0
  93. package/src/legacy/index.ts +3 -0
  94. package/src/legacy/utils.ts +166 -0
  95. package/src/types.ts +1 -1
  96. package/src/utils.ts +153 -139
  97. package/dist/components/Items/NextListItem/hooks.d.ts +0 -19
  98. package/dist/components/Items/NextListItem/hooks.js +0 -80
  99. package/dist/components/Lists/contexts/ListProvider.d.ts +0 -17
  100. package/dist/components/Lists/contexts/ParentListProvider.d.ts +0 -18
  101. package/dist/components/Lists/contexts/ParentListProvider.js +0 -12
  102. package/src/components/Items/NextListItem/hooks.ts +0 -105
  103. package/src/components/Lists/contexts/CollapseProvider.ts +0 -9
  104. package/src/components/Lists/contexts/ListProvider.tsx +0 -28
  105. package/src/components/Lists/contexts/ParentListProvider.tsx +0 -35
@@ -1,20 +1,25 @@
1
1
  import { RefObject } from 'react';
2
- import { ItemProps } from './types';
3
- export declare function useRenderItems(items: ItemProps[]): import("react/jsx-runtime").JSX.Element[];
4
- type UseItemsWithIdsProps = {
2
+ import { AnyType, FlattenBaseItem, FlattenItem, ItemId } from './types';
3
+ type UseRenderItemsProps<Meta = AnyType> = {
4
+ items: ItemId[];
5
+ flattenedItems: Record<string, FlattenItem<Meta>>;
6
+ };
7
+ export declare function useRenderItems<Meta>(props: UseRenderItemsProps<Meta> | undefined): null[] | import("react/jsx-runtime").JSX.Element[];
8
+ type UseCreateBaseItemsProps = {
5
9
  search?: boolean;
6
10
  footerActiveElementsRefs?: RefObject<HTMLElement>[];
7
11
  };
8
- export declare function useItemsWithIds({ search, footerActiveElementsRefs }: UseItemsWithIdsProps): {
9
- search: ItemProps[];
10
- footerRefs: ItemProps[];
12
+ export declare function useCreateBaseItems<Meta>({ footerActiveElementsRefs }: UseCreateBaseItemsProps): {
13
+ searchItem: FlattenBaseItem<Meta>;
14
+ footerItems: FlattenBaseItem<Meta>[];
11
15
  };
12
16
  type UseGroupItemSelectionProps = {
13
- items: ItemProps[];
14
- id?: string | number;
17
+ allChildIds: ItemId[];
18
+ items: ItemId[];
19
+ id: ItemId;
15
20
  disabled?: boolean;
16
21
  };
17
- export declare function useGroupItemSelection({ id, items, disabled }: UseGroupItemSelectionProps): {
22
+ export declare function useGroupItemSelection({ id, disabled, allChildIds }: UseGroupItemSelectionProps): {
18
23
  checked: boolean | undefined;
19
24
  isIndeterminate: boolean;
20
25
  handleOnSelect: () => void;
@@ -1,41 +1,57 @@
1
1
  import { createElement as _createElement } from "react";
2
2
  import { createRef, useEffect, useMemo } from 'react';
3
- import { extractAllChildIds, extractChildIds } from '../../utils';
4
- import { useSelectionContext } from '../Lists/contexts';
3
+ import { useNewListContext, useSelectionContext } from '../Lists/contexts';
5
4
  import { AccordionItem } from './AccordionItem';
6
5
  import { BaseItem } from './BaseItem';
7
6
  import { GroupItem } from './GroupItem';
8
7
  import { NextListItem } from './NextListItem';
9
- import { addItemsIds, isAccordionItemProps, isGroupItemProps, isNextListItemProps } from './utils';
10
- export function useRenderItems(items) {
11
- return useMemo(() => items.map(item => {
12
- if (isGroupItemProps(item)) {
13
- return _createElement(GroupItem, Object.assign({}, item, { key: item.label }));
8
+ import { isAccordionItemProps, isBaseItemProps, isGroupItemProps, isNextListItemProps } from './utils';
9
+ export function useRenderItems(props) {
10
+ return useMemo(() => {
11
+ if (!props) {
12
+ return [null];
14
13
  }
15
- if (isAccordionItemProps(item)) {
16
- return _createElement(AccordionItem, Object.assign({}, item, { key: item.key }));
17
- }
18
- if (isNextListItemProps(item)) {
19
- return _createElement(NextListItem, Object.assign({}, item, { key: item.key }));
20
- }
21
- return _createElement(BaseItem, Object.assign({}, item, { key: item.key }));
22
- }), [items]);
14
+ const { items, flattenedItems } = props;
15
+ return items.map(id => {
16
+ const item = flattenedItems[id];
17
+ if (isGroupItemProps(item)) {
18
+ return _createElement(GroupItem, Object.assign({}, item, { key: item.label }));
19
+ }
20
+ if (isAccordionItemProps(item)) {
21
+ return _createElement(AccordionItem, Object.assign({}, item, { key: item.key }));
22
+ }
23
+ if (isNextListItemProps(item)) {
24
+ return _createElement(NextListItem, Object.assign({}, item, { key: item.key }));
25
+ }
26
+ return _createElement(BaseItem, Object.assign({}, item, { key: item.key }));
27
+ });
28
+ }, [props]);
23
29
  }
24
- export function useItemsWithIds({ search, footerActiveElementsRefs }) {
25
- return useMemo(() => ({
26
- search: addItemsIds(search ? [{ itemRef: createRef() }] : [], 'search'),
27
- footerRefs: addItemsIds(footerActiveElementsRefs
28
- ? footerActiveElementsRefs === null || footerActiveElementsRefs === void 0 ? void 0 : footerActiveElementsRefs.map(ref => ({ itemRef: ref }))
29
- : [], 'footer'),
30
- }), [footerActiveElementsRefs, search]);
30
+ export function useCreateBaseItems({ footerActiveElementsRefs }) {
31
+ return useMemo(() => {
32
+ var _a;
33
+ return ({
34
+ searchItem: {
35
+ itemRef: createRef(),
36
+ id: '~search',
37
+ parentId: '~main',
38
+ },
39
+ footerItems: (_a = footerActiveElementsRefs === null || footerActiveElementsRefs === void 0 ? void 0 : footerActiveElementsRefs.map((itemRef, idx) => ({
40
+ id: `~footer__${idx}`,
41
+ itemRef,
42
+ parentId: '~main',
43
+ }))) !== null && _a !== void 0 ? _a : [],
44
+ });
45
+ }, [footerActiveElementsRefs]);
31
46
  }
32
- export function useGroupItemSelection({ id, items, disabled }) {
47
+ export function useGroupItemSelection({ id, disabled, allChildIds }) {
33
48
  const { value, setValue, isSelectionMultiple } = useSelectionContext();
34
- const { childIds, allChildIds } = useMemo(() => ({ childIds: extractChildIds({ items }), allChildIds: extractAllChildIds({ items }) }), [items]);
49
+ const { flattenedItems } = useNewListContext();
50
+ const baseChildIds = useMemo(() => allChildIds.filter(itemId => isBaseItemProps(flattenedItems[itemId])), [allChildIds, flattenedItems]);
35
51
  const isIndeterminate = isSelectionMultiple
36
- ? allChildIds.some(childId => value === null || value === void 0 ? void 0 : value.includes(childId))
37
- : allChildIds.includes(value !== null && value !== void 0 ? value : '');
38
- const checked = isSelectionMultiple ? allChildIds.every(childId => value === null || value === void 0 ? void 0 : value.includes(childId)) : undefined;
52
+ ? baseChildIds.some(childId => value === null || value === void 0 ? void 0 : value.includes(childId))
53
+ : baseChildIds.includes(value !== null && value !== void 0 ? value : '');
54
+ const checked = isSelectionMultiple ? baseChildIds.every(childId => value === null || value === void 0 ? void 0 : value.includes(childId)) : undefined;
39
55
  useEffect(() => {
40
56
  if (isSelectionMultiple) {
41
57
  if (checked && !(value === null || value === void 0 ? void 0 : value.includes(id))) {
@@ -48,14 +64,14 @@ export function useGroupItemSelection({ id, items, disabled }) {
48
64
  }, [checked, disabled, id, isSelectionMultiple, setValue, value]);
49
65
  const handleOnSelect = () => {
50
66
  if (checked) {
51
- setValue === null || setValue === void 0 ? void 0 : setValue((value) => (value !== null && value !== void 0 ? value : []).filter(itemId => itemId !== id && !childIds.includes(itemId)));
67
+ setValue === null || setValue === void 0 ? void 0 : setValue((value) => (value !== null && value !== void 0 ? value : []).filter(itemId => itemId !== id && !baseChildIds.includes(itemId)));
52
68
  return;
53
69
  }
54
70
  if (isIndeterminate) {
55
- setValue === null || setValue === void 0 ? void 0 : setValue((value) => Array.from(new Set([...(value !== null && value !== void 0 ? value : []), ...childIds, id])));
71
+ setValue === null || setValue === void 0 ? void 0 : setValue((value) => Array.from(new Set([...(value !== null && value !== void 0 ? value : []), ...baseChildIds, id])));
56
72
  return;
57
73
  }
58
- setValue === null || setValue === void 0 ? void 0 : setValue((value) => (value !== null && value !== void 0 ? value : []).concat([...childIds, id !== null && id !== void 0 ? id : '']));
74
+ setValue === null || setValue === void 0 ? void 0 : setValue((value) => (value !== null && value !== void 0 ? value : []).concat([...baseChildIds, id !== null && id !== void 0 ? id : '']));
59
75
  };
60
76
  return { checked, isIndeterminate, handleOnSelect };
61
77
  }
@@ -1,23 +1,18 @@
1
1
  import { FocusEvent, KeyboardEvent, MouseEvent, ReactNode, RefObject } from 'react';
2
- import { TruncateStringProps } from '@snack-uikit/truncate-string';
3
2
  import { WithSupportProps } from '@snack-uikit/utils';
4
- import { SeparatorProps } from '../../helperComponents';
3
+ import { ItemContentProps, SeparatorProps } from '../../helperComponents';
5
4
  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
5
  export type BaseItemPrivateProps = {
17
6
  expandIcon?: ReactNode;
18
7
  open?: boolean;
19
8
  };
20
- export type BaseItemProps = WithSupportProps<{
9
+ export type AnyType = any;
10
+ export type ContentRenderProps<Meta = AnyType> = {
11
+ label: string | number;
12
+ meta?: Meta;
13
+ };
14
+ export type ItemId = string | number;
15
+ export type BaseItemProps<Meta = AnyType> = WithSupportProps<{
21
16
  /**
22
17
  * Слот до основного контента
23
18
  * @type ReactElement
@@ -28,8 +23,10 @@ export type BaseItemProps = WithSupportProps<{
28
23
  * @type ReactElement
29
24
  */
30
25
  afterContent?: ReactNode;
31
- /** Основной контент айтема */
32
- content: ItemContentProps;
26
+ /**
27
+ * Основной контент айтема
28
+ */
29
+ content?: ItemContentProps | ReactNode;
33
30
  /** Колбек обработки клика */
34
31
  onClick?(e: MouseEvent<HTMLElement>): void;
35
32
  /** Колбек обработки нажатия кнопки мыши */
@@ -41,7 +38,7 @@ export type BaseItemProps = WithSupportProps<{
41
38
  /** Колбек обработки блюра */
42
39
  onBlur?(e: FocusEvent<HTMLElement>): void;
43
40
  /** Уникальный идентификатор */
44
- id?: string | number;
41
+ id?: ItemId;
45
42
  /** Флаг неактивности элемента */
46
43
  disabled?: boolean;
47
44
  itemRef?: RefObject<HTMLElement>;
@@ -58,22 +55,40 @@ export type BaseItemProps = WithSupportProps<{
58
55
  switch?: boolean;
59
56
  key?: string | number;
60
57
  itemWrapRender?(item: ReactNode): ReactNode;
61
- }>;
62
- type BaseItemsWithoutNonGroupProps = Omit<BaseItemProps, 'switch' | 'inactive'>;
63
- export type ItemProps = BaseItemProps | AccordionItemProps | NextListItemProps | GroupItemProps;
64
- export type AccordionItemProps = BaseItemsWithoutNonGroupProps & {
65
- items: ItemProps[];
58
+ }> & {
59
+ /**
60
+ * Дополнительные поля для айтема, которые можно использовать для contentRender функции или поиска
61
+ */
62
+ meta?: Meta;
63
+ };
64
+ type BaseItemsWithoutNonGroupProps<Meta = AnyType> = Omit<BaseItemProps<Meta>, 'switch' | 'inactive'>;
65
+ export type ItemProps<Meta = AnyType> = BaseItemProps<Meta> | AccordionItemProps<Meta> | NextListItemProps<Meta> | GroupItemProps<Meta>;
66
+ export type AccordionItemProps<Meta = AnyType> = BaseItemsWithoutNonGroupProps<Meta> & {
67
+ items: ItemProps<Meta>[];
66
68
  type: 'collapse';
67
69
  };
68
- export type NextListItemProps = BaseItemsWithoutNonGroupProps & {
69
- items: ItemProps[];
70
+ export type NextListItemProps<Meta = AnyType> = BaseItemsWithoutNonGroupProps<Meta> & {
71
+ items: ItemProps<Meta>[];
70
72
  type: 'next-list';
71
73
  placement?: 'right-start' | 'left-start' | 'left' | 'right' | 'left-end' | 'right-end';
72
74
  search?: SearchState;
73
- onSublistOpenChanged?(open: boolean, id?: string | number): void;
74
75
  } & ScrollProps;
75
- export type GroupItemProps = Omit<SeparatorProps, 'size'> & {
76
- items: ItemProps[];
76
+ export type GroupItemProps<Meta = AnyType> = Omit<SeparatorProps, 'size'> & {
77
+ items: ItemProps<Meta>[];
77
78
  id?: string | number;
79
+ meta?: undefined;
80
+ };
81
+ type RequiredFields<T, K extends keyof T> = Required<Pick<T, K>> & Omit<T, K>;
82
+ export type Flatten<T, K extends keyof T> = RequiredFields<T, K>;
83
+ type CommonFlattenProps = {
84
+ items: ItemId[];
85
+ allChildIds: ItemId[];
86
+ };
87
+ export type FlattenBaseItem<Meta = AnyType> = Flatten<BaseItemProps<Meta>, 'id' | 'itemRef'>;
88
+ export type FlattenNextListItem<Meta = AnyType> = Flatten<Omit<NextListItemProps<Meta>, 'items'>, 'id' | 'itemRef'> & CommonFlattenProps;
89
+ export type FlattenGroupListItem<Meta = AnyType> = Flatten<Omit<GroupItemProps<Meta>, 'items'>, 'id'> & CommonFlattenProps;
90
+ export type FlattenAccordionItem<Meta = AnyType> = Flatten<Omit<AccordionItemProps<Meta>, 'items'>, 'id' | 'itemRef'> & CommonFlattenProps;
91
+ export type FlattenItem<Meta = AnyType> = (FlattenBaseItem<Meta> | FlattenNextListItem<Meta> | FlattenGroupListItem<Meta> | FlattenAccordionItem<Meta>) & {
92
+ parentId?: ItemId;
78
93
  };
79
94
  export {};
@@ -1,17 +1,7 @@
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[];
16
- };
17
- export declare function addItemsIds(itemsProp: ItemProps[], prefix?: string | number): ItemProps[];
1
+ import { ItemContentProps } from '../../helperComponents';
2
+ import { AccordionItemProps, AnyType, BaseItemProps, GroupItemProps, NextListItemProps } from './types';
3
+ export declare function isBaseItemProps<Meta, ReturnType = BaseItemProps<Meta>>(item: AnyType): item is ReturnType;
4
+ export declare function isAccordionItemProps<Meta, ReturnType = AccordionItemProps<Meta>>(item: AnyType): item is ReturnType;
5
+ export declare function isNextListItemProps<Meta, ReturnType = NextListItemProps<Meta>>(item: AnyType): item is ReturnType;
6
+ export declare function isGroupItemProps<Meta, ReturnType = GroupItemProps<Meta>>(item: AnyType): item is ReturnType;
7
+ export declare function isContentItemProps(item: AnyType): item is ItemContentProps;
@@ -1,43 +1,15 @@
1
- import { createRef } from 'react';
2
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
3
1
  export function isBaseItemProps(item) {
4
- return 'content' in item;
2
+ return !('items' in item);
5
3
  }
6
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
7
4
  export function isAccordionItemProps(item) {
8
5
  return 'items' in item && item['type'] === 'collapse';
9
6
  }
10
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
11
7
  export function isNextListItemProps(item) {
12
8
  return 'items' in item && item['type'] === 'next-list';
13
9
  }
14
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
15
10
  export function isGroupItemProps(item) {
16
11
  return 'items' in item && item['type'] === undefined;
17
12
  }
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
- };
29
- }
30
- export function addItemsIds(itemsProp, prefix) {
31
- return itemsProp.map((item, idx) => {
32
- var _a;
33
- 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) });
37
- }
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() });
40
- }
41
- return Object.assign(Object.assign({ key: autoId }, item), { id: itemId, itemRef: item.itemRef || createRef() });
42
- });
13
+ export function isContentItemProps(item) {
14
+ return typeof item === 'object' && item['option'] !== undefined;
43
15
  }
@@ -1,2 +1,3 @@
1
+ import { AnyType } from '../../Items';
1
2
  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;
3
+ export declare function Droplist<Meta = AnyType>({ 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<Meta>): 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';
13
14
  import { cloneElement, isValidElement, useCallback, useMemo, useRef } from 'react';
14
- import { useUncontrolledProp } from 'uncontrollable';
15
15
  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';
16
+ import { useValueControl } from '@snack-uikit/utils';
17
+ import { extractActiveItems, kindFlattenItems } from '../../../utils';
18
+ import { 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 flattenedItems = Object.assign(Object.assign(Object.assign({}, pinTop.flattenedItems), pinBottom.flattenedItems), items.flattenedItems);
43
+ [...footerItems, searchItem].forEach(item => {
44
+ flattenedItems[item.id] = item;
45
+ });
46
+ return { items, pinTop, pinBottom, flattenedItems };
47
+ }, [itemsProp, pinTopProp, pinBottomProp, searchItem, footerItems]), { flattenedItems } = _b, memorizedItems = __rest(_b, ["flattenedItems"]);
48
+ const { itemRefs, ids, expandedIds } = useMemo(() => {
49
+ const { pinTop, items, pinBottom } = memorizedItems;
50
+ let ids = [];
51
+ let expandedIds = [];
52
+ let itemRefs = [];
53
+ if (hasSearch) {
54
+ ids.push(searchItem.id);
55
+ itemRefs.push(searchItem.itemRef);
56
+ }
57
+ [pinTop, items, pinBottom].forEach(({ flattenedItems, items }) => {
58
+ const activeItems = extractActiveItems({ flattenedItems, items, openCollapseItems });
59
+ ids = ids.concat(activeItems.ids);
60
+ expandedIds = expandedIds.concat(activeItems.expandedIds);
61
+ itemRefs = itemRefs.concat(activeItems.itemRefs);
62
+ });
63
+ footerItems.forEach(footerItem => {
64
+ ids.push(footerItem.id);
65
+ itemRefs.push(footerItem.itemRef);
35
66
  });
36
- const items = searchItem.concat(res.items).concat(footerRefs);
37
67
  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,
68
+ ids,
69
+ itemRefs,
70
+ expandedIds,
42
71
  };
43
- }, [footerRefs, memorizedItems, openCollapsedItems, searchItem]);
44
- const slicedItems = useMemo(() => getSlicedItems({ items, hasSearch, pinTop, pinBottom, footerRefs }), [items, hasSearch, pinTop, pinBottom, footerRefs]);
72
+ }, [footerItems, hasSearch, memorizedItems, openCollapseItems, searchItem.id, searchItem.itemRef]);
45
73
  const triggerElemRef = useRef(null);
46
74
  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);
75
+ const { handleListKeyDownFactory, resetActiveItemId, activeItemId, forceUpdateActiveItemId } = useNewKeyboardNavigation({
76
+ mainRef: triggerElemRefProp !== null && triggerElemRefProp !== void 0 ? triggerElemRefProp : triggerElemRef,
77
+ itemRefs,
78
+ expandedIds,
79
+ flattenedItems,
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,16 @@ 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
+ // e.preventDefault();
98
+ setOpen(false);
99
+ }
65
100
  cb === null || cb === void 0 ? void 0 : cb(e);
66
- }, [setActiveFocusIndex, setOpen]);
101
+ }, [resetActiveItemId, setOpen]);
67
102
  const triggerElem = useMemo(() => {
68
103
  if (isValidElement(children)) {
69
104
  const props = typeof children.props === 'object' ? children.props : {};
@@ -77,24 +112,24 @@ export function Droplist(_a) {
77
112
  }
78
113
  return children;
79
114
  }, [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 })) }) })));
115
+ // const handleOnFocus = e => {
116
+ // // resetActiveItemId();
117
+ // };
118
+ return (_jsx(NewListContextProvider, { flattenedItems: flattenedItems, contentRender: contentRender, size: size, marker: marker, children: _jsx(SelectionProvider, Object.assign({}, selection, { children: _jsx(CollapseContext.Provider, { value: {
119
+ openCollapseItems,
120
+ toggleOpenCollapseItem,
121
+ }, children: _jsx(FocusListContext.Provider, { value: {
122
+ activeItemId,
123
+ handleListKeyDownFactory,
124
+ forceUpdateActiveItemId,
125
+ }, children: _jsx(Dropdown, Object.assign({ content: _jsx("div", { className: cn(styles.wrapper, className), children: _jsx(ListPrivate, Object.assign({}, props, memorizedItems, { onKeyDown: handleListKeyDown, tabIndex: 0, ref: listRef, search: search,
126
+ // onFocus={handleOnFocus}
127
+ onFocus: e => {
128
+ e.stopPropagation();
129
+ forceUpdateActiveItemId === null || forceUpdateActiveItemId === void 0 ? void 0 : forceUpdateActiveItemId(ids[0]);
130
+ }, limitedScrollHeight: true })) }), triggerClassName: triggerClassName, fallbackPlacements: DEFAULT_FALLBACK_PLACEMENTS, trigger: trigger, placement: placement, widthStrategy: widthStrategy }, (triggerElemRefProp
131
+ ? {}
132
+ : {
133
+ triggerRef: triggerElemRef,
134
+ }), { open: open, onOpenChange: handleOpenChange, children: triggerElem })) }) }) })) }));
100
135
  }
@@ -1,20 +1,16 @@
1
- import { KeyboardEvent } from 'react';
1
+ import { KeyboardEvent, RefObject } 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").ItemProps<unknown>[];
6
+ pinTop?: import("../../Items").ItemProps<unknown>[] | undefined;
7
+ pinBottom?: import("../../Items").ItemProps<unknown>[] | undefined;
8
8
  footer?: import("react").ReactNode;
9
- footerActiveElementsRefs?: import("react").RefObject<HTMLElement>[] | undefined;
9
+ footerActiveElementsRefs?: 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<unknown> & import("../../../types").ScrollProps & import("../types").EmptyState & import("react").RefAttributes<HTMLElement>>;