@snack-uikit/list 0.10.0 → 0.10.1-preview-69abc1d3.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 (127) hide show
  1. package/README.md +56 -24
  2. package/dist/components/Items/AccordionItem/AccordionItem.d.ts +4 -2
  3. package/dist/components/Items/AccordionItem/AccordionItem.js +18 -16
  4. package/dist/components/Items/BaseItem/BaseItem.d.ts +8 -4
  5. package/dist/components/Items/BaseItem/BaseItem.js +20 -14
  6. package/dist/components/Items/BaseItem/styles.module.css +9 -122
  7. package/dist/components/Items/GroupItem/GroupItem.d.ts +5 -1
  8. package/dist/components/Items/GroupItem/GroupItem.js +1 -3
  9. package/dist/components/Items/GroupSelectItem/GroupSelectItem.d.ts +4 -0
  10. package/dist/components/Items/GroupSelectItem/GroupSelectItem.js +18 -0
  11. package/dist/components/Items/GroupSelectItem/index.d.ts +1 -0
  12. package/dist/components/Items/GroupSelectItem/index.js +1 -0
  13. package/dist/components/Items/NextListItem/NextListItem.d.ts +6 -2
  14. package/dist/components/Items/NextListItem/NextListItem.js +53 -45
  15. package/dist/components/Items/NextListItem/constants.d.ts +2 -0
  16. package/dist/components/Items/NextListItem/constants.js +10 -0
  17. package/dist/components/Items/SearchItem/SearchItem.d.ts +3 -1
  18. package/dist/components/Items/SearchItem/SearchItem.js +5 -8
  19. package/dist/components/Items/hooks.d.ts +11 -10
  20. package/dist/components/Items/hooks.js +64 -46
  21. package/dist/components/Items/index.d.ts +1 -5
  22. package/dist/components/Items/index.js +1 -5
  23. package/dist/components/Items/types.d.ts +68 -34
  24. package/dist/components/Items/utils.d.ts +33 -16
  25. package/dist/components/Items/utils.js +132 -37
  26. package/dist/components/Lists/Droplist/DropList.d.ts +1 -1
  27. package/dist/components/Lists/Droplist/DropList.js +73 -50
  28. package/dist/components/Lists/List/List.d.ts +5 -9
  29. package/dist/components/Lists/List/List.js +56 -54
  30. package/dist/components/Lists/ListPrivate/ListPrivate.d.ts +6 -20
  31. package/dist/components/Lists/ListPrivate/ListPrivate.js +9 -8
  32. package/dist/components/Lists/ListPrivate/styles.module.css +1 -0
  33. package/dist/components/Lists/contexts/CollapseProvider.d.ts +13 -1
  34. package/dist/components/Lists/contexts/CollapseProvider.js +2 -0
  35. package/dist/components/Lists/contexts/FocusListProvider.d.ts +9 -0
  36. package/dist/components/Lists/contexts/FocusListProvider.js +5 -0
  37. package/dist/components/Lists/contexts/NewListProvider.d.ts +32 -0
  38. package/dist/components/Lists/contexts/{ListProvider.js → NewListProvider.js} +10 -5
  39. package/dist/components/Lists/contexts/SelectionProvider.d.ts +25 -15
  40. package/dist/components/Lists/contexts/SelectionProvider.js +17 -13
  41. package/dist/components/Lists/contexts/index.d.ts +2 -2
  42. package/dist/components/Lists/contexts/index.js +2 -2
  43. package/dist/components/Lists/hooks.d.ts +10 -12
  44. package/dist/components/Lists/hooks.js +73 -40
  45. package/dist/components/Lists/types.d.ts +12 -14
  46. package/dist/components/index.d.ts +2 -2
  47. package/dist/components/index.js +1 -1
  48. package/dist/helperComponents/ItemContent/ItemContent.d.ts +15 -0
  49. package/dist/helperComponents/ItemContent/ItemContent.js +23 -0
  50. package/dist/helperComponents/ItemContent/index.d.ts +1 -0
  51. package/dist/helperComponents/ItemContent/index.js +1 -0
  52. package/dist/helperComponents/ItemContent/styles.module.css +117 -0
  53. package/dist/helperComponents/ListEmptyState/ListEmptyState.d.ts +2 -2
  54. package/dist/helperComponents/ListEmptyState/ListEmptyState.js +13 -4
  55. package/dist/helperComponents/Separator/Separator.d.ts +8 -2
  56. package/dist/helperComponents/Separator/Separator.js +22 -2
  57. package/dist/helperComponents/Separator/constants.d.ts +2 -0
  58. package/dist/helperComponents/Separator/constants.js +5 -0
  59. package/dist/helperComponents/Separator/styles.module.css +20 -1
  60. package/dist/helperComponents/index.d.ts +1 -0
  61. package/dist/helperComponents/index.js +1 -0
  62. package/dist/hooks.d.ts +1 -1
  63. package/dist/hooks.js +15 -10
  64. package/dist/index.d.ts +3 -2
  65. package/dist/index.js +3 -2
  66. package/dist/legacy/components/Items/hooks.d.ts +12 -0
  67. package/dist/legacy/components/Items/hooks.js +33 -0
  68. package/dist/legacy/components/index.d.ts +1 -0
  69. package/dist/legacy/components/index.js +1 -0
  70. package/dist/legacy/hooks.d.ts +5 -0
  71. package/dist/legacy/hooks.js +15 -0
  72. package/dist/legacy/index.d.ts +3 -0
  73. package/dist/legacy/index.js +3 -0
  74. package/dist/{utils.d.ts → legacy/utils.d.ts} +2 -3
  75. package/dist/{utils.js → legacy/utils.js} +4 -12
  76. package/dist/types.d.ts +1 -1
  77. package/package.json +14 -14
  78. package/src/components/Items/AccordionItem/AccordionItem.tsx +24 -20
  79. package/src/components/Items/BaseItem/BaseItem.tsx +48 -43
  80. package/src/components/Items/BaseItem/styles.module.scss +8 -70
  81. package/src/components/Items/GroupItem/GroupItem.tsx +5 -5
  82. package/src/components/Items/GroupSelectItem/GroupSelectItem.tsx +44 -0
  83. package/src/components/Items/GroupSelectItem/index.ts +1 -0
  84. package/src/components/Items/NextListItem/NextListItem.tsx +86 -85
  85. package/src/components/Items/NextListItem/constants.ts +12 -0
  86. package/src/components/Items/SearchItem/SearchItem.tsx +6 -8
  87. package/src/components/Items/hooks.tsx +86 -66
  88. package/src/components/Items/index.ts +1 -5
  89. package/src/components/Items/types.ts +91 -42
  90. package/src/components/Items/utils.ts +193 -52
  91. package/src/components/Lists/Droplist/DropList.tsx +151 -98
  92. package/src/components/Lists/List/List.tsx +124 -104
  93. package/src/components/Lists/ListPrivate/ListPrivate.tsx +19 -20
  94. package/src/components/Lists/ListPrivate/styles.module.scss +1 -0
  95. package/src/components/Lists/contexts/CollapseProvider.tsx +22 -0
  96. package/src/components/Lists/contexts/FocusListProvider.tsx +16 -0
  97. package/src/components/Lists/contexts/NewListProvider.tsx +54 -0
  98. package/src/components/Lists/contexts/SelectionProvider.tsx +56 -39
  99. package/src/components/Lists/contexts/index.ts +3 -2
  100. package/src/components/Lists/hooks.ts +124 -75
  101. package/src/components/Lists/types.ts +20 -24
  102. package/src/components/index.ts +16 -2
  103. package/src/helperComponents/ItemContent/ItemContent.tsx +63 -0
  104. package/src/helperComponents/ItemContent/index.ts +1 -0
  105. package/src/helperComponents/ItemContent/styles.module.scss +78 -0
  106. package/src/helperComponents/ListEmptyState/ListEmptyState.tsx +26 -12
  107. package/src/helperComponents/Separator/Separator.tsx +49 -3
  108. package/src/helperComponents/Separator/constants.ts +7 -0
  109. package/src/helperComponents/Separator/styles.module.scss +41 -1
  110. package/src/helperComponents/index.ts +1 -0
  111. package/src/hooks.ts +21 -15
  112. package/src/index.ts +5 -2
  113. package/src/legacy/components/Items/hooks.tsx +53 -0
  114. package/src/legacy/components/index.ts +1 -0
  115. package/src/legacy/hooks.ts +27 -0
  116. package/src/legacy/index.ts +3 -0
  117. package/src/{utils.ts → legacy/utils.ts} +4 -13
  118. package/src/types.ts +1 -1
  119. package/dist/components/Items/NextListItem/hooks.d.ts +0 -19
  120. package/dist/components/Items/NextListItem/hooks.js +0 -80
  121. package/dist/components/Lists/contexts/ListProvider.d.ts +0 -17
  122. package/dist/components/Lists/contexts/ParentListProvider.d.ts +0 -18
  123. package/dist/components/Lists/contexts/ParentListProvider.js +0 -12
  124. package/src/components/Items/NextListItem/hooks.ts +0 -105
  125. package/src/components/Lists/contexts/CollapseProvider.ts +0 -9
  126. package/src/components/Lists/contexts/ListProvider.tsx +0 -28
  127. package/src/components/Lists/contexts/ParentListProvider.tsx +0 -35
@@ -5,19 +5,12 @@ import { WithSupportProps } from '@snack-uikit/utils';
5
5
 
6
6
  import { EmptyStateProps } from '../../helperComponents';
7
7
  import { ScrollProps, SearchState } from '../../types';
8
- import { ItemProps } from '../Items';
9
- import { ListContextPrivateType, ListContextType, SelectionState } from './contexts';
10
-
11
- type CollapseState = {
12
- value?: (string | number)[];
13
- onChange?(value: (string | number)[]): void;
14
- defaultValue?: (string | number)[];
15
- };
8
+ import { FlattenBaseItem, Item, ItemId } from '../Items';
9
+ import { CollapseState, PublicListContextType, SelectionState } from './contexts';
16
10
 
17
11
  export type EmptyState = {
18
12
  dataFiltered?: boolean;
19
13
  dataError?: boolean;
20
-
21
14
  /** Экран при отстутствии данных */
22
15
  noDataState?: EmptyStateProps;
23
16
  /** Экран при отстутствии результатов поиска или фильтров */
@@ -29,11 +22,11 @@ export type EmptyState = {
29
22
  export type ListProps = WithSupportProps<
30
23
  {
31
24
  /** Основные элементы списка */
32
- items: ItemProps[];
25
+ items: Item[];
33
26
  /** Элементы списка, закрепленные сверху */
34
- pinTop?: ItemProps[];
27
+ pinTop?: Item[];
35
28
  /** Элементы списка, закрепленные снизу */
36
- pinBottom?: ItemProps[];
29
+ pinBottom?: Item[];
37
30
  /**
38
31
  * Кастомизируемый элемент в конце списка
39
32
  * @type ReactNode;
@@ -55,7 +48,7 @@ export type ListProps = WithSupportProps<
55
48
  /** Флаг, отвещающий за состояние загрузки списка */
56
49
  loading?: boolean;
57
50
  } & SelectionState &
58
- ListContextType &
51
+ PublicListContextType &
59
52
  ScrollProps &
60
53
  EmptyState
61
54
  >;
@@ -70,16 +63,19 @@ export type DroplistProps = {
70
63
  * Рендер функция принимает аргументы `onKeyDown` - хендлер ввода, для поддержки управления с клавиатуры
71
64
  */
72
65
  children: ReactNode | ((params: { onKeyDown?: (e: KeyboardEvent<HTMLElement>) => void }) => ReactNode);
73
- } & Pick<DropdownProps, 'trigger' | 'placement' | 'widthStrategy' | 'open' | 'onOpenChange'> &
66
+ } & Pick<DropdownProps, 'trigger' | 'placement' | 'widthStrategy' | 'open' | 'onOpenChange' | 'triggerClassName'> &
74
67
  Omit<ListProps, 'tabIndex' | 'onKeyDown'>;
75
68
 
76
- export type ListPrivateProps = ListProps &
77
- ListContextPrivateType & {
78
- nested?: boolean;
79
- active?: boolean;
80
- tabIndex?: number;
81
- onFocus?(e: FocusEvent<HTMLElement>): void;
82
- onBlur?(e: FocusEvent<HTMLElement>): void;
83
- onKeyDown?(e: KeyboardEvent<HTMLElement>): void;
84
- limitedScrollHeight?: boolean;
85
- };
69
+ export type ListPrivateProps = Omit<ListProps, 'pinTop' | 'pinBottom' | 'items'> & {
70
+ nested?: boolean;
71
+ active?: boolean;
72
+ tabIndex?: number;
73
+ onFocus?(e: FocusEvent<HTMLElement>): void;
74
+ onBlur?(e: FocusEvent<HTMLElement>): void;
75
+ onKeyDown?(e: KeyboardEvent<HTMLElement>): void;
76
+ limitedScrollHeight?: boolean;
77
+ searchItem?: FlattenBaseItem;
78
+ pinTop?: ItemId[];
79
+ items: ItemId[];
80
+ pinBottom?: ItemId[];
81
+ };
@@ -1,6 +1,20 @@
1
1
  export * from './Lists';
2
2
 
3
- export type { AccordionItemProps, NextListItemProps, BaseItemProps, GroupItemProps, ItemProps } from './Items';
4
- export { isAccordionItemProps, isBaseItemProps, isGroupItemProps, isNextListItemProps } from './Items';
3
+ export type {
4
+ AccordionItemProps,
5
+ NextListItemProps,
6
+ BaseItemProps,
7
+ GroupItemProps,
8
+ ItemProps,
9
+ GroupSelectItemProps,
10
+ } from './Items';
11
+
12
+ export {
13
+ isAccordionItemProps,
14
+ isBaseItemProps,
15
+ isGroupItemProps,
16
+ isNextListItemProps,
17
+ isGroupSelectItem,
18
+ } from './Items';
5
19
 
6
20
  export { useGroupItemSelection } from './Items/hooks';
@@ -0,0 +1,63 @@
1
+ import cn from 'classnames';
2
+
3
+ import { TruncateString, TruncateStringProps } from '@snack-uikit/truncate-string';
4
+ import { extractSupportProps, WithSupportProps } from '@snack-uikit/utils';
5
+
6
+ import { useNewListContext } from '../../components/Lists/contexts';
7
+ import styles from './styles.module.scss';
8
+
9
+ export type ItemContentProps = WithSupportProps<{
10
+ option: string | number;
11
+ caption?: string;
12
+ description?: string;
13
+ truncate?: {
14
+ option?: number;
15
+ description?: number;
16
+ variant?: TruncateStringProps['variant'];
17
+ };
18
+ disabled?: boolean;
19
+ className?: string;
20
+ }>;
21
+
22
+ export function ItemContent({
23
+ truncate,
24
+ caption,
25
+ description,
26
+ option,
27
+ className,
28
+ disabled,
29
+ ...rest
30
+ }: ItemContentProps) {
31
+ const { size = 's' } = useNewListContext();
32
+
33
+ return (
34
+ <div
35
+ className={cn(styles.content, className)}
36
+ {...extractSupportProps(rest)}
37
+ data-size={size ?? 's'}
38
+ data-disabled={disabled || undefined}
39
+ >
40
+ <div className={styles.headline}>
41
+ <span className={styles.label}>
42
+ <TruncateString
43
+ variant={truncate?.variant}
44
+ text={String(option)}
45
+ maxLines={truncate?.option ?? 1}
46
+ data-test-id='list__base-item-option'
47
+ />
48
+ </span>
49
+ {caption && <span className={styles.caption}>{caption}</span>}
50
+ </div>
51
+
52
+ {description && (
53
+ <div className={styles.description}>
54
+ <TruncateString
55
+ text={description}
56
+ maxLines={truncate?.description ?? 2}
57
+ data-test-id='list__base-item-description'
58
+ />
59
+ </div>
60
+ )}
61
+ </div>
62
+ );
63
+ }
@@ -0,0 +1 @@
1
+ export * from './ItemContent';
@@ -0,0 +1,78 @@
1
+ @import '@snack-uikit/figma-tokens/build/scss/components/styles-tokens-dropList';
2
+ @import '@snack-uikit/figma-tokens/build/scss/components/styles-tokens-element';
3
+
4
+ $sizes: 's', 'm', 'l';
5
+ $typography: (
6
+ 's': (
7
+ 'label': $sans-body-s,
8
+ 'caption': $sans-body-s,
9
+ 'description': $sans-body-s,
10
+ 'separator': $light-label-m,
11
+ ),
12
+ 'm': (
13
+ 'label': $sans-body-m,
14
+ 'caption': $sans-body-s,
15
+ 'description': $sans-body-s,
16
+ 'separator': $light-label-l,
17
+ ),
18
+ 'l': (
19
+ 'label': $sans-body-l,
20
+ 'caption': $sans-body-m,
21
+ 'description': $sans-body-m,
22
+ 'separator': $light-label-l,
23
+ ),
24
+ );
25
+
26
+ .headline {
27
+ display: flex;
28
+ align-items: center;
29
+ }
30
+
31
+ .label {
32
+ overflow: hidden;
33
+ flex: 1;
34
+ color: $sys-neutral-text-main;
35
+ }
36
+
37
+ .caption {
38
+ overflow: hidden;
39
+ color: $sys-neutral-text-light;
40
+ text-overflow: ellipsis;
41
+ white-space: nowrap;
42
+ }
43
+
44
+ .description {
45
+ color: $sys-neutral-text-support;
46
+ }
47
+
48
+ .content {
49
+ overflow: hidden;
50
+ flex-grow: 1;
51
+ flex-shrink: 1;
52
+ box-sizing: border-box;
53
+
54
+ @each $size in $sizes {
55
+ &[data-size='#{$size}'] {
56
+ .headline {
57
+ @include composite-var($drop-list, 'item', $size, 'headline');
58
+ }
59
+ .label {
60
+ @include composite-var($typography, $size, 'label');
61
+ }
62
+ .caption {
63
+ @include composite-var($typography, $size, 'caption');
64
+ }
65
+ .description {
66
+ @include composite-var($typography, $size, 'description');
67
+ }
68
+ }
69
+ }
70
+
71
+ &[data-disabled] {
72
+ .label,
73
+ .description,
74
+ .caption {
75
+ color: $sys-neutral-text-disabled;
76
+ }
77
+ }
78
+ }
@@ -13,23 +13,37 @@ export type ListEmptyState = {
13
13
  loading?: boolean;
14
14
  dataError?: boolean;
15
15
  dataFiltered?: boolean;
16
- itemsLength: number;
16
+ hasNoItems: boolean;
17
17
  };
18
18
 
19
- export function ListEmptyState({ dataError, dataFiltered, itemsLength, emptyStates, loading }: ListEmptyState) {
20
- if (itemsLength || loading) {
19
+ export function ListEmptyState({ dataError, dataFiltered, hasNoItems, emptyStates, loading }: ListEmptyState) {
20
+ if (loading) {
21
21
  return null;
22
22
  }
23
23
 
24
- return (
25
- <div className={styles.listEmptyStateWrapper}>
26
- {dataError && <InfoBlock {...emptyStates.errorDataState} size='s' align='vertical' />}
27
- {!dataError && dataFiltered && (
24
+ if (dataError) {
25
+ return (
26
+ <div className={styles.listEmptyStateWrapper}>
27
+ <InfoBlock {...emptyStates.errorDataState} size='s' align='vertical' />
28
+ </div>
29
+ );
30
+ }
31
+
32
+ if (dataFiltered && hasNoItems) {
33
+ return (
34
+ <div className={styles.listEmptyStateWrapper}>
28
35
  <InfoBlock {...emptyStates.noResultsState} size='s' align='vertical' data-test-id='list__no-results' />
29
- )}
30
- {!dataError && !dataFiltered && (
36
+ </div>
37
+ );
38
+ }
39
+
40
+ if (!dataFiltered && hasNoItems) {
41
+ return (
42
+ <div className={styles.listEmptyStateWrapper}>
31
43
  <InfoBlock {...emptyStates.noDataState} size='s' align='vertical' data-test-id='list__no-data' />
32
- )}
33
- </div>
34
- );
44
+ </div>
45
+ );
46
+ }
47
+
48
+ return null;
35
49
  }
@@ -1,6 +1,12 @@
1
+ import { ForwardedRef, MouseEvent, RefObject, useMemo } from 'react';
2
+
3
+ import { ButtonFunction } from '@snack-uikit/button';
1
4
  import { Divider } from '@snack-uikit/divider';
5
+ import { useLocale } from '@snack-uikit/locale';
2
6
  import { TruncateString, TruncateStringProps } from '@snack-uikit/truncate-string';
3
7
 
8
+ import { useNewListContext } from '../../components/Lists/contexts';
9
+ import { SELECT_BUTTON_SIZE_MAP } from './constants';
4
10
  import styles from './styles.module.scss';
5
11
 
6
12
  export type SeparatorProps = {
@@ -10,10 +16,46 @@ export type SeparatorProps = {
10
16
  };
11
17
  mode?: 'primary' | 'secondary';
12
18
  divider?: boolean;
13
- size?: 's' | 'm' | 'l';
19
+ selectButton?: {
20
+ onClick?(e: MouseEvent<HTMLElement>): void;
21
+ indeterminate?: boolean;
22
+ checked?: boolean;
23
+ itemRef?: ForwardedRef<HTMLElement>;
24
+ };
14
25
  };
15
26
 
16
- export function Separator({ label, truncate, divider, mode = 'secondary', size = 's' }: SeparatorProps) {
27
+ export function Separator({ label, truncate, divider, mode = 'secondary', selectButton }: SeparatorProps) {
28
+ const { size = 's' } = useNewListContext();
29
+
30
+ const { t } = useLocale('List');
31
+
32
+ const selectButtonJSX = useMemo(() => {
33
+ if (!selectButton) {
34
+ return null;
35
+ }
36
+
37
+ const { onClick, checked, itemRef } = selectButton;
38
+
39
+ return (
40
+ <span className={styles.selectButton} data-size={size} data-weight={(divider && mode) || undefined}>
41
+ <ButtonFunction
42
+ size={SELECT_BUTTON_SIZE_MAP[size]}
43
+ tabIndex={0}
44
+ onClick={e => {
45
+ onClick?.(e);
46
+ e.preventDefault();
47
+ e.stopPropagation();
48
+ }}
49
+ onFocus={e => {
50
+ e.stopPropagation();
51
+ }}
52
+ ref={itemRef as RefObject<HTMLButtonElement>}
53
+ label={checked ? t('groupSelectButton.reset') : t('groupSelectButton.select')}
54
+ />
55
+ </span>
56
+ );
57
+ }, [divider, mode, selectButton, size, t]);
58
+
17
59
  if (label) {
18
60
  return (
19
61
  <div className={styles.separatorWithLabel} data-size={size}>
@@ -21,7 +63,11 @@ export function Separator({ label, truncate, divider, mode = 'secondary', size =
21
63
  <TruncateString variant={truncate?.variant} text={label} maxLines={1} />
22
64
  </span>
23
65
 
24
- {divider && <Divider weight={mode === 'primary' ? 'regular' : 'light'} className={styles.divider} />}
66
+ <div style={{ flex: 1 }}>
67
+ {selectButtonJSX}
68
+
69
+ {divider && <Divider weight={mode === 'primary' ? 'regular' : 'light'} className={styles.divider} />}
70
+ </div>
25
71
  </div>
26
72
  );
27
73
  }
@@ -0,0 +1,7 @@
1
+ import { ButtonFunctionProps } from '@snack-uikit/button';
2
+
3
+ export const SELECT_BUTTON_SIZE_MAP: Record<string, ButtonFunctionProps['size']> = {
4
+ s: 'xs',
5
+ m: 's',
6
+ l: 'm',
7
+ } as const;
@@ -1,3 +1,4 @@
1
+ @import '@snack-uikit/figma-tokens/build/scss/components/styles-tokens-button-buttonFunction';
1
2
  @import '@snack-uikit/figma-tokens/build/scss/components/styles-tokens-dropList';
2
3
  @import '@snack-uikit/figma-tokens/build/scss/components/styles-tokens-element';
3
4
 
@@ -15,8 +16,15 @@ $typography-secondary: (
15
16
  'l': $light-title-m,
16
17
  );
17
18
 
19
+ $button-size: (
20
+ 's': 'xs',
21
+ 'm': 's',
22
+ 'l': 'm',
23
+ );
24
+
25
+ $containerSize: 1px;
26
+
18
27
  .separatorWithLabel {
19
- overflow: hidden;
20
28
  display: flex;
21
29
  gap: $dimension-1m;
22
30
  align-items: flex-end;
@@ -72,3 +80,35 @@ hr.divider {
72
80
  width: auto;
73
81
  min-width: 0;
74
82
  }
83
+
84
+ .selectButton {
85
+ display: flex;
86
+ justify-content: flex-end;
87
+
88
+ &[data-weight='primary'] {
89
+ --divider-height: #{$containerSize};
90
+ }
91
+
92
+ &[data-weight='secondary'] {
93
+ --divider-height: #{calc($containerSize / 2)};
94
+ }
95
+
96
+ @each $size in $sizes {
97
+ &[data-size='#{$size}'] {
98
+ transform: translateY(
99
+ calc(
100
+ (
101
+ simple-var(
102
+ $button-function,
103
+ 'container',
104
+ simple-var($button-size, $size),
105
+ 'label-only',
106
+ 'height'
107
+ ) - simple-var($theme-variables, 'sans', 'label', $size, 'line-height')
108
+ ) /
109
+ 2 - var(--divider-height, 0)
110
+ )
111
+ );
112
+ }
113
+ }
114
+ }
@@ -2,3 +2,4 @@ export * from './CollapseBlockPrivate';
2
2
  export * from './Separator';
3
3
  export * from './HiddenTabButton';
4
4
  export * from './ListEmptyState';
5
+ export * from './ItemContent';
package/src/hooks.ts CHANGED
@@ -1,27 +1,33 @@
1
- import FuzzySearch from 'fuzzy-search';
1
+ // import FuzzySearch from 'fuzzy-search';
2
2
  import { useCallback } from 'react';
3
3
 
4
4
  import { ItemProps } from './components/Items';
5
- import { flattenItems } from './utils';
5
+ // import { flattenItems } from './utils';
6
6
 
7
- const DEFAULT_MIN_SEARCH_INPUT_LENGTH = 2;
7
+ // const DEFAULT_MIN_SEARCH_INPUT_LENGTH = 2;
8
8
 
9
9
  /**
10
10
  * Нечеткий поиск среди айтемов по полям 'content.option', 'content.caption', 'content.description', 'label'
11
11
  */
12
- export function useFuzzySearch(items: ItemProps[], minSearchInputLength?: number) {
12
+ export function useFuzzySearch(
13
+ items: ItemProps[],
14
+ // minSearchInputLength?: number
15
+ ) {
13
16
  return useCallback(
14
- (search: string) => {
15
- const searcher = new FuzzySearch(
16
- flattenItems(items),
17
- ['content.option', 'content.caption', 'content.description', 'label'],
18
- {},
19
- );
17
+ () =>
18
+ // (search: string) =>
19
+ // const searcher = new FuzzySearch(
20
+ // // flattenItems(items),
21
+ // ['content.option', 'content.caption', 'content.description', 'label'],
22
+ // {},
23
+ // );
20
24
 
21
- return search.length > (minSearchInputLength ?? DEFAULT_MIN_SEARCH_INPUT_LENGTH)
22
- ? searcher.search(search)
23
- : items;
24
- },
25
- [items, minSearchInputLength],
25
+ // return search.length > (minSearchInputLength ?? DEFAULT_MIN_SEARCH_INPUT_LENGTH)
26
+ // ? searcher.search(search)
27
+ // : items;
28
+
29
+ items,
30
+
31
+ [items],
26
32
  );
27
33
  }
package/src/index.ts CHANGED
@@ -1,4 +1,7 @@
1
1
  export * from './components';
2
- export { useFuzzySearch } from './hooks';
2
+
3
3
  export type { SearchState } from './types';
4
- export { extractChildIds, flattenItems } from './utils';
4
+ export { kindFlattenItems } from './components/Items';
5
+
6
+ export * from './helperComponents/ItemContent';
7
+ export * from './legacy';
@@ -0,0 +1,53 @@
1
+ import { useEffect, useMemo } from 'react';
2
+
3
+ import { ItemProps } from '../../../components';
4
+ import { useSelectionContext } from '../../../components/Lists/contexts';
5
+ import { extractAllChildIds, extractChildIds } from '../../utils';
6
+
7
+ type UseGroupItemSelectionProps = {
8
+ items: ItemProps[];
9
+ id?: string | number;
10
+ disabled?: boolean;
11
+ };
12
+
13
+ export function useLegacyGroupItemSelection({ id = '', items, disabled }: UseGroupItemSelectionProps) {
14
+ const { value, setValue, isSelectionMultiple } = useSelectionContext();
15
+ const { childIds, allChildIds } = useMemo(
16
+ () => ({ childIds: extractChildIds({ items }), allChildIds: extractAllChildIds({ items }) }),
17
+ [items],
18
+ );
19
+
20
+ const isIndeterminate = isSelectionMultiple
21
+ ? allChildIds.some(childId => value?.includes(childId))
22
+ : allChildIds.includes(value ?? '');
23
+ const checked = isSelectionMultiple ? allChildIds.every(childId => value?.includes(childId)) : undefined;
24
+
25
+ useEffect(() => {
26
+ if (isSelectionMultiple) {
27
+ if (checked && !value?.includes(id)) {
28
+ setValue?.((value: Array<number | string>) => (value ?? []).concat([id ?? '']));
29
+ }
30
+ if (!checked && value?.includes(id)) {
31
+ setValue?.((value: Array<number | string>) => (value ?? []).filter(itemId => itemId !== id));
32
+ }
33
+ }
34
+ }, [checked, disabled, id, isSelectionMultiple, setValue, value]);
35
+
36
+ const handleOnSelect = () => {
37
+ if (checked) {
38
+ setValue?.((value: Array<string | number>) =>
39
+ (value ?? []).filter(itemId => itemId !== id && !childIds.includes(itemId)),
40
+ );
41
+ return;
42
+ }
43
+
44
+ if (isIndeterminate) {
45
+ setValue?.((value: Array<string | number>) => Array.from(new Set([...(value ?? []), ...childIds, id])));
46
+ return;
47
+ }
48
+
49
+ setValue?.((value: Array<string | number>) => (value ?? []).concat([...childIds, id ?? '']));
50
+ };
51
+
52
+ return { checked, isIndeterminate, handleOnSelect };
53
+ }
@@ -0,0 +1 @@
1
+ export { useLegacyGroupItemSelection } from './Items/hooks';
@@ -0,0 +1,27 @@
1
+ import FuzzySearch from 'fuzzy-search';
2
+ import { useCallback } from 'react';
3
+
4
+ import { ItemProps } from '../components';
5
+ import { flattenItems } from './utils';
6
+
7
+ const DEFAULT_MIN_SEARCH_INPUT_LENGTH = 2;
8
+
9
+ /**
10
+ * Нечеткий поиск среди айтемов по полям 'content.option', 'content.caption', 'content.description', 'label'
11
+ */
12
+ export function useFuzzySearch(items: ItemProps[], minSearchInputLength?: number) {
13
+ return useCallback(
14
+ (search: string) => {
15
+ const searcher = new FuzzySearch(
16
+ flattenItems(items),
17
+ ['content.option', 'content.caption', 'content.description', 'label'],
18
+ {},
19
+ );
20
+
21
+ return search.length > (minSearchInputLength ?? DEFAULT_MIN_SEARCH_INPUT_LENGTH)
22
+ ? searcher.search(search)
23
+ : items;
24
+ },
25
+ [items, minSearchInputLength],
26
+ );
27
+ }
@@ -0,0 +1,3 @@
1
+ export * from './components';
2
+ export { useFuzzySearch } from './hooks';
3
+ export { extractChildIds, flattenItems } from './utils';
@@ -9,7 +9,7 @@ import {
9
9
  isNextListItemProps,
10
10
  ItemProps,
11
11
  NextListItemProps,
12
- } from './components/Items';
12
+ } from '../components/Items';
13
13
 
14
14
  type WithCollapsedItemsProps = {
15
15
  items: ItemProps[];
@@ -71,15 +71,6 @@ export function withCollapsedItems({ items, openCollapsedItems }: WithCollapsedI
71
71
  return { items, itemRefs, ids, expandedIds };
72
72
  }
73
73
 
74
- export function extractItemRefs(items: ItemProps[]): RefObject<HTMLElement>[] {
75
- return items.reduce((prev: RefObject<HTMLElement>[], item: ItemProps) => {
76
- if (isGroupItemProps(item)) {
77
- return prev.concat(extractItemRefs(item.items));
78
- }
79
- return item.itemRef ? prev.concat([item.itemRef]) : prev;
80
- }, [] as RefObject<HTMLElement>[]);
81
- }
82
-
83
74
  /**
84
75
  * Функция возвращает массив id дочерних items
85
76
  * @function extractItemIds
@@ -153,11 +144,11 @@ export function extractAllChildIds({ items }: { items: ItemProps[] }): Array<str
153
144
  */
154
145
 
155
146
  export function flattenItems(items: ItemProps[]): (BaseItemProps | AccordionItemProps | NextListItemProps)[] {
156
- const flattenedItems: (BaseItemProps | AccordionItemProps | NextListItemProps)[] = [];
147
+ const flattenItems: (BaseItemProps | AccordionItemProps | NextListItemProps)[] = [];
157
148
 
158
149
  function flatten(item: ItemProps) {
159
150
  if (!isGroupItemProps(item)) {
160
- flattenedItems.push(item);
151
+ flattenItems.push(item);
161
152
  }
162
153
 
163
154
  if ('items' in item) {
@@ -171,5 +162,5 @@ export function flattenItems(items: ItemProps[]): (BaseItemProps | AccordionItem
171
162
  flatten(item);
172
163
  }
173
164
 
174
- return flattenedItems;
165
+ return flattenItems;
175
166
  }
package/src/types.ts CHANGED
@@ -2,9 +2,9 @@ import { RefObject } from 'react';
2
2
 
3
3
  export type SearchState = {
4
4
  placeholder?: string;
5
+ loading?: boolean;
5
6
  value?: string;
6
7
  onChange(value: string): void;
7
- loading?: boolean;
8
8
  };
9
9
 
10
10
  export type ScrollProps = {
@@ -1,19 +0,0 @@
1
- import { KeyboardEvent, RefObject } from 'react';
2
- type UseKeyboardNavigationProps = {
3
- ids: Array<number | string>;
4
- expandedIds: Array<number | string>;
5
- itemRefs?: RefObject<HTMLElement>[];
6
- id?: string | number;
7
- };
8
- export declare function useKeyboardNavigation({ ids, expandedIds, itemRefs, id }: UseKeyboardNavigationProps): {
9
- activeFocusIndex: number;
10
- setActiveFocusIndex: import("react").Dispatch<import("react").SetStateAction<number>>;
11
- openNestedIndex: number;
12
- setOpenNestedIndex: import("react").Dispatch<import("react").SetStateAction<number>>;
13
- resetNestedIndex: () => void;
14
- resetActiveFocusIndex: () => void;
15
- handleListKeyDown: (e: KeyboardEvent<HTMLElement>) => void;
16
- open: boolean;
17
- setOpen: import("react").Dispatch<import("react").SetStateAction<boolean>>;
18
- };
19
- export {};