@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
@@ -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,21 @@
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
+ ItemId,
11
+ } from './Items';
12
+
13
+ export {
14
+ isAccordionItemProps,
15
+ isBaseItemProps,
16
+ isGroupItemProps,
17
+ isNextListItemProps,
18
+ isGroupSelectItem,
19
+ } from './Items';
5
20
 
6
21
  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/index.ts CHANGED
@@ -1,4 +1,6 @@
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';
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 {};
@@ -1,80 +0,0 @@
1
- import { useCallback, useEffect, useState } from 'react';
2
- import { useParentListContext } from '../../Lists/contexts';
3
- export function useKeyboardNavigation({ ids, expandedIds, itemRefs, id }) {
4
- const { triggerRef, parentResetNestedIndex, parentIds, parentItemRefs, parentOpenNestedIndex } = useParentListContext();
5
- const [activeFocusIndex, setActiveFocusIndex] = useState(-1);
6
- const [openNestedIndex, setOpenNestedIndex] = useState(-1);
7
- const [open, setOpen] = useState(false);
8
- const handleListKeyDown = (e) => {
9
- var _a, _b;
10
- switch (e.key) {
11
- case 'ArrowDown': {
12
- setActiveFocusIndex(activeIndex => Math.min(activeIndex + 1, ids.length - 1));
13
- e.stopPropagation();
14
- e.preventDefault();
15
- return;
16
- }
17
- case 'ArrowUp': {
18
- setActiveFocusIndex(activeIndex => Math.max(activeIndex - 1, 0));
19
- e.preventDefault();
20
- e.stopPropagation();
21
- return;
22
- }
23
- case 'ArrowRight': {
24
- e.stopPropagation();
25
- e.preventDefault();
26
- if (expandedIds.includes(ids[activeFocusIndex])) {
27
- setOpenNestedIndex(activeFocusIndex);
28
- }
29
- return;
30
- }
31
- case 'ArrowLeft': {
32
- (_a = parentItemRefs === null || parentItemRefs === void 0 ? void 0 : parentItemRefs[parentOpenNestedIndex].current) === null || _a === void 0 ? void 0 : _a.focus();
33
- parentResetNestedIndex === null || parentResetNestedIndex === void 0 ? void 0 : parentResetNestedIndex();
34
- setActiveFocusIndex(-1);
35
- setOpenNestedIndex(-1);
36
- setOpen(false);
37
- e.stopPropagation();
38
- e.preventDefault();
39
- return;
40
- }
41
- case 'Tab': {
42
- (_b = triggerRef === null || triggerRef === void 0 ? void 0 : triggerRef.current) === null || _b === void 0 ? void 0 : _b.focus();
43
- parentResetNestedIndex === null || parentResetNestedIndex === void 0 ? void 0 : parentResetNestedIndex();
44
- setActiveFocusIndex(-1);
45
- setOpen(false);
46
- e.preventDefault();
47
- return;
48
- }
49
- default: {
50
- break;
51
- }
52
- }
53
- };
54
- useEffect(() => {
55
- var _a, _b;
56
- (_b = (_a = itemRefs === null || itemRefs === void 0 ? void 0 : itemRefs[activeFocusIndex]) === null || _a === void 0 ? void 0 : _a.current) === null || _b === void 0 ? void 0 : _b.focus();
57
- }, [activeFocusIndex, itemRefs]);
58
- useEffect(() => {
59
- if (parentIds[parentOpenNestedIndex] === id && openNestedIndex === -1) {
60
- setOpen(true);
61
- setActiveFocusIndex(activeIndex => (activeIndex === -1 ? 0 : activeIndex));
62
- }
63
- }, [id, openNestedIndex, parentIds, parentOpenNestedIndex]);
64
- const resetNestedIndex = () => {
65
- setActiveFocusIndex(openNestedIndex);
66
- setOpenNestedIndex(-1);
67
- };
68
- const resetActiveFocusIndex = useCallback(() => setActiveFocusIndex(-1), []);
69
- return {
70
- activeFocusIndex,
71
- setActiveFocusIndex,
72
- openNestedIndex,
73
- setOpenNestedIndex,
74
- resetNestedIndex,
75
- resetActiveFocusIndex,
76
- handleListKeyDown,
77
- open,
78
- setOpen,
79
- };
80
- }
@@ -1,17 +0,0 @@
1
- import { ReactNode } from 'react';
2
- export type ListContextType = {
3
- /** Размер списка */
4
- size?: 's' | 'm' | 'l';
5
- /** Отображать ли маркер у выбранного жлемента списка */
6
- marker?: boolean;
7
- };
8
- export type ListContextPrivateType = {
9
- parent?: 'list' | 'droplist';
10
- };
11
- type Child = {
12
- children: ReactNode;
13
- };
14
- export declare const ListContext: import("react").Context<ListContextType & ListContextPrivateType>;
15
- export declare const useListContext: () => ListContextType & ListContextPrivateType;
16
- export declare function ListContextProvider({ children, ...props }: ListContextType & Child & ListContextPrivateType): import("react/jsx-runtime").JSX.Element;
17
- export {};
@@ -1,18 +0,0 @@
1
- import { RefObject } from 'react';
2
- export type ParentListContextType = {
3
- parentActiveFocusIndex: number;
4
- parentSetActiveFocusIndex?(idx: number): void;
5
- parentResetActiveFocusIndex?(): void;
6
- parentIds: Array<string | number>;
7
- parentExpandedIds: Array<string | number>;
8
- parentItemRefs: Array<RefObject<HTMLElement>>;
9
- parentOpenNestedIndex: number;
10
- parentResetNestedIndex?(): void;
11
- openCollapsedItems?: Array<string | number>;
12
- toggleOpenCollapsedItems?(id: string | number): void;
13
- triggerRef?: RefObject<HTMLElement>;
14
- parentRef?: RefObject<HTMLElement>;
15
- };
16
- export declare const ParentListContext: import("react").Context<ParentListContextType>;
17
- export declare const useParentListContext: () => ParentListContextType;
18
- export declare function ParentListProvider(): null;
@@ -1,12 +0,0 @@
1
- import { createContext, useContext } from 'react';
2
- export const ParentListContext = createContext({
3
- parentActiveFocusIndex: -1,
4
- parentOpenNestedIndex: -1,
5
- parentIds: [],
6
- parentExpandedIds: [],
7
- parentItemRefs: [],
8
- });
9
- export const useParentListContext = () => useContext(ParentListContext);
10
- export function ParentListProvider() {
11
- return null;
12
- }
package/dist/hooks.d.ts DELETED
@@ -1,5 +0,0 @@
1
- import { ItemProps } from './components/Items';
2
- /**
3
- * Нечеткий поиск среди айтемов по полям 'content.option', 'content.caption', 'content.description', 'label'
4
- */
5
- export declare function useFuzzySearch(items: ItemProps[], minSearchInputLength?: number): (search: string) => ItemProps[];
package/dist/hooks.js DELETED
@@ -1,15 +0,0 @@
1
- import FuzzySearch from 'fuzzy-search';
2
- import { useCallback } from 'react';
3
- import { flattenItems } from './utils';
4
- const DEFAULT_MIN_SEARCH_INPUT_LENGTH = 2;
5
- /**
6
- * Нечеткий поиск среди айтемов по полям 'content.option', 'content.caption', 'content.description', 'label'
7
- */
8
- export function useFuzzySearch(items, minSearchInputLength) {
9
- return useCallback((search) => {
10
- const searcher = new FuzzySearch(flattenItems(items), ['content.option', 'content.caption', 'content.description', 'label'], {});
11
- return search.length > (minSearchInputLength !== null && minSearchInputLength !== void 0 ? minSearchInputLength : DEFAULT_MIN_SEARCH_INPUT_LENGTH)
12
- ? searcher.search(search)
13
- : items;
14
- }, [items, minSearchInputLength]);
15
- }
package/dist/utils.d.ts DELETED
@@ -1,30 +0,0 @@
1
- import { RefObject } from 'react';
2
- import { AccordionItemProps, BaseItemProps, ItemProps, NextListItemProps } from './components/Items';
3
- type WithCollapsedItemsProps = {
4
- items: ItemProps[];
5
- openCollapsedItems: Array<number | string>;
6
- };
7
- export declare function withCollapsedItems({ items, openCollapsedItems }: WithCollapsedItemsProps): {
8
- items: ItemProps[];
9
- itemRefs: RefObject<HTMLElement>[];
10
- ids: (string | number)[];
11
- expandedIds: (string | number)[];
12
- };
13
- export declare function extractItemRefs(items: ItemProps[]): RefObject<HTMLElement>[];
14
- /**
15
- * Функция возвращает массив id дочерних items
16
- * @function extractItemIds
17
- */
18
- export declare function extractItemIds(items: ItemProps[]): Array<string | number>;
19
- export declare function extractChildIds({ items }: {
20
- items: ItemProps[];
21
- }): Array<string | number>;
22
- export declare function extractAllChildIds({ items }: {
23
- items: ItemProps[];
24
- }): Array<string | number>;
25
- /**
26
- *  Функция разворачивает массив айтемов в плоский список
27
- * @function flattenItems
28
- */
29
- export declare function flattenItems(items: ItemProps[]): (BaseItemProps | AccordionItemProps | NextListItemProps)[];
30
- export {};