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

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/CHANGELOG.md +25 -0
  2. package/README.md +35 -24
  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 +4 -11
  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 +75 -42
  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/HiddenTabButton/HiddenTabButton.js +1 -1
  55. package/dist/helperComponents/ItemContent/ItemContent.d.ts +15 -0
  56. package/dist/helperComponents/ItemContent/ItemContent.js +23 -0
  57. package/dist/helperComponents/ItemContent/index.d.ts +1 -0
  58. package/dist/helperComponents/ItemContent/index.js +1 -0
  59. package/dist/helperComponents/ItemContent/styles.module.css +117 -0
  60. package/dist/helperComponents/ListEmptyState/ListEmptyState.d.ts +2 -2
  61. package/dist/helperComponents/ListEmptyState/ListEmptyState.js +13 -4
  62. package/dist/helperComponents/Separator/Separator.d.ts +8 -2
  63. package/dist/helperComponents/Separator/Separator.js +22 -2
  64. package/dist/helperComponents/Separator/constants.d.ts +2 -0
  65. package/dist/helperComponents/Separator/constants.js +5 -0
  66. package/dist/helperComponents/Separator/styles.module.css +20 -1
  67. package/dist/helperComponents/index.d.ts +1 -0
  68. package/dist/helperComponents/index.js +1 -0
  69. package/dist/index.d.ts +2 -2
  70. package/dist/index.js +2 -2
  71. package/dist/types.d.ts +1 -1
  72. package/package.json +13 -18
  73. package/src/components/Items/AccordionItem/AccordionItem.tsx +24 -20
  74. package/src/components/Items/BaseItem/BaseItem.tsx +91 -82
  75. package/src/components/Items/BaseItem/styles.module.scss +19 -77
  76. package/src/components/Items/GroupItem/GroupItem.tsx +5 -5
  77. package/src/components/Items/GroupSelectItem/GroupSelectItem.tsx +44 -0
  78. package/src/components/Items/GroupSelectItem/index.ts +1 -0
  79. package/src/components/Items/NextListItem/NextListItem.tsx +88 -85
  80. package/src/components/Items/NextListItem/constants.ts +12 -0
  81. package/src/components/Items/PinGroupItem/PinGroupItem.tsx +14 -4
  82. package/src/components/Items/PinGroupItem/styles.module.scss +14 -14
  83. package/src/components/Items/SearchItem/SearchItem.tsx +5 -12
  84. package/src/components/Items/hooks.tsx +86 -66
  85. package/src/components/Items/index.ts +1 -5
  86. package/src/components/Items/styles.module.scss +36 -25
  87. package/src/components/Items/types.ts +91 -42
  88. package/src/components/Items/utils.ts +199 -52
  89. package/src/components/Lists/Droplist/DropList.tsx +155 -98
  90. package/src/components/Lists/List/List.tsx +129 -104
  91. package/src/components/Lists/ListPrivate/ListPrivate.tsx +19 -20
  92. package/src/components/Lists/ListPrivate/styles.module.scss +1 -0
  93. package/src/components/Lists/contexts/CollapseProvider.tsx +22 -0
  94. package/src/components/Lists/contexts/FocusListProvider.tsx +15 -0
  95. package/src/components/Lists/contexts/NewListProvider.tsx +54 -0
  96. package/src/components/Lists/contexts/SelectionProvider.tsx +56 -39
  97. package/src/components/Lists/contexts/index.ts +3 -2
  98. package/src/components/Lists/hooks.ts +125 -76
  99. package/src/components/Lists/index.ts +2 -2
  100. package/src/components/Lists/types.ts +20 -24
  101. package/src/components/index.ts +17 -2
  102. package/src/helperComponents/HiddenTabButton/HiddenTabButton.tsx +1 -0
  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/index.ts +4 -2
  112. package/src/types.ts +1 -1
  113. package/dist/components/Items/NextListItem/hooks.d.ts +0 -19
  114. package/dist/components/Items/NextListItem/hooks.js +0 -80
  115. package/dist/components/Lists/contexts/ListProvider.d.ts +0 -17
  116. package/dist/components/Lists/contexts/ParentListProvider.d.ts +0 -18
  117. package/dist/components/Lists/contexts/ParentListProvider.js +0 -12
  118. package/dist/hooks.d.ts +0 -5
  119. package/dist/hooks.js +0 -15
  120. package/dist/utils.d.ts +0 -30
  121. package/dist/utils.js +0 -115
  122. package/src/components/Items/NextListItem/hooks.ts +0 -105
  123. package/src/components/Lists/contexts/CollapseProvider.ts +0 -9
  124. package/src/components/Lists/contexts/ListProvider.tsx +0 -28
  125. package/src/components/Lists/contexts/ParentListProvider.tsx +0 -35
  126. package/src/hooks.ts +0 -27
  127. 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';
@@ -26,6 +26,7 @@ export const HiddenTabButton = forwardRef<HTMLButtonElement, HiddenTabButtonProp
26
26
 
27
27
  return (
28
28
  <button
29
+ type='button'
29
30
  aria-hidden
30
31
  ref={ref}
31
32
  onKeyDown={handleKeyDown}
@@ -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
- }