@qoretechnologies/reqore 0.32.3 → 0.33.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 (92) hide show
  1. package/__tests__/collection.test.tsx +123 -5
  2. package/__tests__/hooks/useLatestZIndex.test.tsx +10 -0
  3. package/__tests__/hooks/useReqorePaging.test.tsx +251 -0
  4. package/__tests__/hooks/useTheme.test.tsx +31 -0
  5. package/__tests__/pagination.test.tsx +301 -0
  6. package/__tests__/popover.test.tsx +20 -6
  7. package/__tests__/setup.js +8 -0
  8. package/__tests__/tree.test.tsx +0 -1
  9. package/dist/components/Button/index.d.ts +1 -0
  10. package/dist/components/Button/index.d.ts.map +1 -1
  11. package/dist/components/Button/index.js +11 -7
  12. package/dist/components/Button/index.js.map +1 -1
  13. package/dist/components/Collection/index.d.ts +9 -3
  14. package/dist/components/Collection/index.d.ts.map +1 -1
  15. package/dist/components/Collection/index.js +34 -8
  16. package/dist/components/Collection/index.js.map +1 -1
  17. package/dist/components/Dropdown/index.d.ts +5 -2
  18. package/dist/components/Dropdown/index.d.ts.map +1 -1
  19. package/dist/components/Dropdown/index.js +2 -2
  20. package/dist/components/Dropdown/index.js.map +1 -1
  21. package/dist/components/Dropdown/list.d.ts +4 -1
  22. package/dist/components/Dropdown/list.d.ts.map +1 -1
  23. package/dist/components/Dropdown/list.js +3 -3
  24. package/dist/components/Dropdown/list.js.map +1 -1
  25. package/dist/components/Menu/item.d.ts +1 -0
  26. package/dist/components/Menu/item.d.ts.map +1 -1
  27. package/dist/components/Menu/item.js +14 -2
  28. package/dist/components/Menu/item.js.map +1 -1
  29. package/dist/components/MultiSelect/index.d.ts +1 -1
  30. package/dist/components/MultiSelect/index.d.ts.map +1 -1
  31. package/dist/components/Paging/index.d.ts +30 -0
  32. package/dist/components/Paging/index.d.ts.map +1 -0
  33. package/dist/components/Paging/index.js +106 -0
  34. package/dist/components/Paging/index.js.map +1 -0
  35. package/dist/components/Tag/index.d.ts +3 -2
  36. package/dist/components/Tag/index.d.ts.map +1 -1
  37. package/dist/components/Tag/index.js +10 -7
  38. package/dist/components/Tag/index.js.map +1 -1
  39. package/dist/constants/colors.d.ts +2 -9
  40. package/dist/constants/colors.d.ts.map +1 -1
  41. package/dist/constants/colors.js +3 -1
  42. package/dist/constants/colors.js.map +1 -1
  43. package/dist/constants/paging.d.ts +10 -0
  44. package/dist/constants/paging.d.ts.map +1 -0
  45. package/dist/constants/paging.js +41 -0
  46. package/dist/constants/paging.js.map +1 -0
  47. package/dist/constants/theme.d.ts.map +1 -1
  48. package/dist/constants/theme.js +8 -7
  49. package/dist/constants/theme.js.map +1 -1
  50. package/dist/containers/ReqoreProvider.d.ts.map +1 -1
  51. package/dist/containers/ReqoreProvider.js +2 -2
  52. package/dist/containers/ReqoreProvider.js.map +1 -1
  53. package/dist/containers/UIProvider.d.ts.map +1 -1
  54. package/dist/containers/UIProvider.js +9 -3
  55. package/dist/containers/UIProvider.js.map +1 -1
  56. package/dist/hooks/useCombinedRefs.d.ts +2 -2
  57. package/dist/hooks/useCombinedRefs.d.ts.map +1 -1
  58. package/dist/hooks/useCombinedRefs.js.map +1 -1
  59. package/dist/hooks/usePaging.d.ts +27 -0
  60. package/dist/hooks/usePaging.d.ts.map +1 -0
  61. package/dist/hooks/usePaging.js +83 -0
  62. package/dist/hooks/usePaging.js.map +1 -0
  63. package/dist/index.d.ts +2 -0
  64. package/dist/index.d.ts.map +1 -1
  65. package/dist/index.js +6 -2
  66. package/dist/index.js.map +1 -1
  67. package/package.json +6 -4
  68. package/src/components/Button/index.tsx +18 -10
  69. package/src/components/Collection/index.tsx +96 -44
  70. package/src/components/ControlGroup/index.tsx +1 -1
  71. package/src/components/Dropdown/index.tsx +8 -2
  72. package/src/components/Dropdown/list.tsx +7 -1
  73. package/src/components/Menu/item.tsx +16 -2
  74. package/src/components/MultiSelect/index.tsx +1 -1
  75. package/src/components/Paging/index.tsx +232 -0
  76. package/src/components/Tag/index.tsx +9 -7
  77. package/src/constants/colors.ts +5 -1
  78. package/src/constants/paging.ts +48 -0
  79. package/src/constants/theme.ts +8 -7
  80. package/src/containers/ReqoreProvider.tsx +3 -3
  81. package/src/containers/UIProvider.tsx +17 -4
  82. package/src/hooks/useCombinedRefs.ts +2 -2
  83. package/src/hooks/usePaging.ts +110 -0
  84. package/src/index.tsx +2 -0
  85. package/src/mock/collectionData.tsx +19 -0
  86. package/src/mock/tableData.ts +1 -0
  87. package/src/stories/Button/Button.stories.tsx +25 -8
  88. package/src/stories/Collection/Collection.stories.tsx +32 -42
  89. package/src/stories/Dropdown/Dropdown.stories.tsx +24 -1
  90. package/src/stories/Paging/Paging.stories.tsx +184 -0
  91. package/src/stories/Tag/Tag.stories.tsx +50 -0
  92. package/tests.json +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qoretechnologies/reqore",
3
- "version": "0.32.3",
3
+ "version": "0.33.0",
4
4
  "description": "ReQore is a highly theme-able and modular UI library for React",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -53,7 +53,7 @@
53
53
  "@storybook/react": "^6.5.13",
54
54
  "@storybook/testing-library": "^0.0.13",
55
55
  "@testing-library/jest-dom": "^5.16.5",
56
- "@testing-library/react": "^11.2.2",
56
+ "@testing-library/react": "^13.4.0",
57
57
  "@types/jest": "^26.0.19",
58
58
  "@types/lodash": "^4.14.166",
59
59
  "@types/node": "^14.14.14",
@@ -62,7 +62,8 @@
62
62
  "babel-jest": "^26.6.3",
63
63
  "babel-loader": "^8.2.2",
64
64
  "chromatic": "^6.3.3",
65
- "jest": "^26.6.3",
65
+ "jest": "^29.4.3",
66
+ "jest-environment-jsdom": "^29.4.3",
66
67
  "jest-github-actions-reporter": "^1.0.2",
67
68
  "npm-cli-login": "^0.1.1",
68
69
  "playwright": "^1.16.3",
@@ -73,7 +74,7 @@
73
74
  "react-test-renderer": "^18.2.0",
74
75
  "storybook-addon-outline": "^1.4.2",
75
76
  "storybook-dark-mode": "^1.1.2",
76
- "ts-jest": "^26.4.4",
77
+ "ts-jest": "^29.0.5",
77
78
  "ts-node": "^9.1.1",
78
79
  "typescript": "^4.7.3",
79
80
  "viteshot": "^0.3.1"
@@ -94,6 +95,7 @@
94
95
  "react-popper": "^2.3.0",
95
96
  "react-scrollbar": "^0.5.6",
96
97
  "react-use": "^17.4.0",
98
+ "react-use-pagination-hook": "^1.1.2",
97
99
  "react-window": "^1.8.6",
98
100
  "scheduler": "^0.23.0",
99
101
  "shortid": "^2.2.16",
@@ -69,6 +69,7 @@ export interface IReqoreButtonProps
69
69
  description?: string | number;
70
70
  maxWidth?: string;
71
71
  textAlign?: 'left' | 'center' | 'right';
72
+ iconsAlign?: 'center' | 'sides';
72
73
  iconColor?: TReqoreEffectColor;
73
74
  leftIconColor?: TReqoreEffectColor;
74
75
  rightIconColor?: TReqoreEffectColor;
@@ -393,6 +394,7 @@ const ReqoreButton = memo(
393
394
  leftIconColor,
394
395
  rightIconColor,
395
396
  iconColor,
397
+ iconsAlign,
396
398
  ...rest
397
399
  }: IReqoreButtonProps,
398
400
  ref
@@ -455,17 +457,18 @@ const ReqoreButton = memo(
455
457
  size={size}
456
458
  color={leftIconColor || iconColor}
457
459
  style={
458
- textAlign !== 'left'
460
+ textAlign !== 'left' || iconsAlign === 'center'
459
461
  ? {
460
- marginRight: 'auto',
461
- marginLeft: textAlign === 'center' ? 'auto' : undefined,
462
+ marginRight: iconsAlign !== 'center' || !children ? 'auto' : undefined,
463
+ marginLeft:
464
+ iconsAlign === 'center' || (textAlign === 'center' && !children)
465
+ ? 'auto'
466
+ : undefined,
462
467
  }
463
468
  : undefined
464
469
  }
465
470
  />
466
- {children || badge || rightIcon ? (
467
- <ReqoreSpacer width={PADDING_FROM_SIZE[size]} />
468
- ) : null}
471
+ {children || rightIcon ? <ReqoreSpacer width={PADDING_FROM_SIZE[size]} /> : null}
469
472
  </>
470
473
  ) : children ? (
471
474
  <ReqoreHorizontalSpacer
@@ -476,7 +479,9 @@ const ReqoreButton = memo(
476
479
  {children && (
477
480
  <StyledAnimatedTextWrapper
478
481
  textAlign={textAlign}
479
- style={textAlign === 'center' ? { margin: 'auto' } : undefined}
482
+ style={
483
+ textAlign === 'center' && iconsAlign !== 'center' ? { margin: 'auto' } : undefined
484
+ }
480
485
  >
481
486
  <StyledActiveContent wrap={wrap} effect={labelEffect}>
482
487
  {children}
@@ -509,10 +514,13 @@ const ReqoreButton = memo(
509
514
  icon={rightIcon}
510
515
  size={size}
511
516
  style={
512
- textAlign !== 'right'
517
+ textAlign !== 'right' || iconsAlign === 'center'
513
518
  ? {
514
- marginLeft: 'auto',
515
- marginRight: textAlign === 'center' ? 'auto' : undefined,
519
+ marginLeft: iconsAlign !== 'center' || !children ? 'auto' : undefined,
520
+ marginRight:
521
+ iconsAlign === 'center' || (textAlign === 'center' && !children)
522
+ ? 'auto'
523
+ : undefined,
516
524
  }
517
525
  : undefined
518
526
  }
@@ -1,17 +1,26 @@
1
1
  import { size } from 'lodash';
2
- import { useMemo, useState } from 'react';
2
+ import { useCallback, useMemo, useState } from 'react';
3
3
  import { useDebounce, useUpdateEffect } from 'react-use';
4
4
  import styled, { css } from 'styled-components';
5
+ import { getPaginationOptionsFromType, TReqorePaginationType } from '../../constants/paging';
5
6
  import { PADDING_FROM_SIZE } from '../../constants/sizes';
7
+ import { IReqorePagingOptions, useReqorePaging } from '../../hooks/usePaging';
6
8
  import { IReqoreIconName } from '../../types/icons';
7
9
  import { IReqoreColumnsProps, StyledColumns } from '../Columns';
8
10
  import ReqoreInput, { IReqoreInputProps } from '../Input';
9
11
  import ReqoreMessage from '../Message';
12
+ import { IReqorePaginationComponentProps, ReqorePagination } from '../Paging';
10
13
  import { IReqorePanelAction, IReqorePanelProps, ReqorePanel, TReqorePanelActions } from '../Panel';
11
14
  import { ReqoreVerticalSpacer } from '../Spacer';
12
15
  import { sortTableData } from '../Table/helpers';
13
16
  import { IReqoreCollectionItemProps, ReqoreCollectionItem } from './item';
14
17
 
18
+ export interface IReqoreCollectionPagingOptions
19
+ extends Omit<IReqorePagingOptions<IReqoreCollectionItemProps>, 'items'>,
20
+ IReqorePaginationComponentProps {
21
+ pageControlsPosition?: 'top' | 'bottom' | 'both';
22
+ }
23
+
15
24
  export interface IReqoreCollectionProps
16
25
  extends Pick<
17
26
  IReqorePanelProps,
@@ -48,8 +57,10 @@ export interface IReqoreCollectionProps
48
57
  selectedIcon?: IReqoreIconName;
49
58
  searchDelay?: number;
50
59
 
51
- childrenBefore?: React.ReactNode;
52
- childrenAfter?: React.ReactNode;
60
+ contentRenderer?: (
61
+ children: React.ReactNode,
62
+ items: IReqoreCollectionItemProps[]
63
+ ) => React.ReactNode;
53
64
 
54
65
  onQueryChange?: (query: string) => void;
55
66
 
@@ -57,6 +68,8 @@ export interface IReqoreCollectionProps
57
68
  sortButtonTooltip?: (sort?: 'asc' | 'desc') => string;
58
69
  displayButtonTooltip?: (display?: 'list' | 'grid') => string;
59
70
  inputPlaceholder?: (items?: IReqoreCollectionItemProps[]) => string;
71
+
72
+ paging?: TReqorePaginationType;
60
73
  }
61
74
 
62
75
  export const StyledCollectionWrapper = styled(StyledColumns)`
@@ -92,13 +105,13 @@ export const ReqoreCollection = ({
92
105
  minimal,
93
106
  transparent = true,
94
107
  onQueryChange,
95
- childrenBefore,
96
- childrenAfter,
108
+ contentRenderer = (children) => children,
97
109
  searchDelay = 300,
98
110
  emptyMessage = 'No data in this collection, try changing your search query or filters',
99
111
  sortButtonTooltip = (sort) => (sort === 'desc' ? 'Sort ascending' : 'Sort descending'),
100
112
  displayButtonTooltip = (display) => (display === 'grid' ? 'Show as list' : 'Show as grid'),
101
113
  inputPlaceholder = (items) => `Search in ${size(items)} items`,
114
+ paging,
102
115
  ...rest
103
116
  }: IReqoreCollectionProps) => {
104
117
  const [_showAs, setShowAs] = useState<'list' | 'grid'>(showAs);
@@ -152,7 +165,7 @@ export const ReqoreCollection = ({
152
165
  });
153
166
  }, [items, sort]);
154
167
 
155
- const finalItems: IReqoreCollectionItemProps[] = useMemo(() => {
168
+ const filteredItems: IReqoreCollectionItemProps[] = useMemo(() => {
156
169
  if (!filterable || query === '') {
157
170
  return sortedItems;
158
171
  }
@@ -170,6 +183,18 @@ export const ReqoreCollection = ({
170
183
  });
171
184
  }, [items, query, sortedItems]);
172
185
 
186
+ const {
187
+ pagingOptions = {},
188
+ componentOptions = {},
189
+ pageControlsPosition,
190
+ } = useMemo(() => getPaginationOptionsFromType(paging), [paging]);
191
+
192
+ const { items: finalItems, ...pagingData } = useReqorePaging({
193
+ items: filteredItems,
194
+ ...pagingOptions,
195
+ enabled: !!paging,
196
+ });
197
+
173
198
  const handlePreQueryChange = (event: React.ChangeEvent<HTMLInputElement>) => {
174
199
  setPreQuery(event.target.value);
175
200
  };
@@ -210,8 +235,11 @@ export const ReqoreCollection = ({
210
235
  props: {
211
236
  key: 'search',
212
237
  fixed: false,
213
- placeholder: inputPlaceholder(finalItems),
214
- onClearClick: () => setQuery(''),
238
+ placeholder: inputPlaceholder(items),
239
+ onClearClick: () => {
240
+ setQuery('');
241
+ setPreQuery('');
242
+ },
215
243
  onChange: handlePreQueryChange,
216
244
  value: preQuery,
217
245
  icon: 'Search2Line',
@@ -225,6 +253,65 @@ export const ReqoreCollection = ({
225
253
  return [...actions, toolbarGroup];
226
254
  }, [filterable, preQuery, query, rest.actions, _showAs, sort, sortable, finalItems]);
227
255
 
256
+ const renderContent = useCallback(() => {
257
+ return contentRenderer(
258
+ <>
259
+ {!!paging && (pageControlsPosition === 'top' || pageControlsPosition === 'both') ? (
260
+ <>
261
+ <ReqorePagination size={rest.size} {...pagingData} {...componentOptions} />
262
+ <ReqoreVerticalSpacer height={PADDING_FROM_SIZE[rest.size || 'normal']} />
263
+ </>
264
+ ) : null}
265
+ {!size(finalItems) ? (
266
+ <ReqoreMessage flat icon='Search2Line'>
267
+ {emptyMessage}
268
+ </ReqoreMessage>
269
+ ) : (
270
+ <StyledCollectionWrapper
271
+ columns={_showAs === 'grid' ? 'auto-fit' : 1}
272
+ columnsGap={stacked ? '0px' : columnsGap}
273
+ rounded={rounded}
274
+ stacked={stacked}
275
+ {...rest}
276
+ >
277
+ {finalItems?.map((item, index) => (
278
+ <ReqoreCollectionItem
279
+ size={rest.size}
280
+ {...item}
281
+ icon={item.icon || (item.selected ? selectedIcon : undefined)}
282
+ key={index}
283
+ rounded={!stacked}
284
+ maxContentHeight={maxItemHeight}
285
+ />
286
+ ))}
287
+ </StyledCollectionWrapper>
288
+ )}
289
+ {!!paging &&
290
+ (!pageControlsPosition ||
291
+ pageControlsPosition === 'bottom' ||
292
+ pageControlsPosition === 'both') ? (
293
+ <>
294
+ <ReqoreVerticalSpacer height={PADDING_FROM_SIZE[rest.size || 'normal']} />
295
+ <ReqorePagination size={rest.size} {...pagingData} {...componentOptions} />
296
+ </>
297
+ ) : null}
298
+ </>,
299
+ finalItems
300
+ );
301
+ }, [
302
+ contentRenderer,
303
+ finalItems,
304
+ _showAs,
305
+ columnsGap,
306
+ emptyMessage,
307
+ maxItemHeight,
308
+ rest,
309
+ rounded,
310
+ selectedIcon,
311
+ size,
312
+ stacked,
313
+ ]);
314
+
228
315
  return (
229
316
  <ReqorePanel
230
317
  {...rest}
@@ -239,42 +326,7 @@ export const ReqoreCollection = ({
239
326
  actions={finalActions}
240
327
  className={`reqore-collection ${rest.className || ''}`}
241
328
  >
242
- {childrenBefore ? (
243
- <>
244
- {childrenBefore}
245
- <ReqoreVerticalSpacer height={PADDING_FROM_SIZE[rest.size || 'normal']} />
246
- </>
247
- ) : null}
248
- {!size(finalItems) ? (
249
- <ReqoreMessage flat icon='Search2Line'>
250
- {emptyMessage}
251
- </ReqoreMessage>
252
- ) : (
253
- <StyledCollectionWrapper
254
- columns={_showAs === 'grid' ? 'auto-fit' : 1}
255
- columnsGap={stacked ? '0px' : columnsGap}
256
- rounded={rounded}
257
- stacked={stacked}
258
- {...rest}
259
- >
260
- {finalItems?.map((item, index) => (
261
- <ReqoreCollectionItem
262
- size={rest.size}
263
- {...item}
264
- icon={item.icon || (item.selected ? selectedIcon : undefined)}
265
- key={index}
266
- rounded={!stacked}
267
- maxContentHeight={maxItemHeight}
268
- />
269
- ))}
270
- </StyledCollectionWrapper>
271
- )}
272
- {childrenAfter ? (
273
- <>
274
- <ReqoreVerticalSpacer height={PADDING_FROM_SIZE[rest.size || 'normal']} />
275
- {childrenAfter}
276
- </>
277
- ) : null}
329
+ {renderContent()}
278
330
  </ReqorePanel>
279
331
  );
280
332
  };
@@ -11,7 +11,7 @@ import {
11
11
  IWithReqoreFlat,
12
12
  IWithReqoreFluid,
13
13
  IWithReqoreMinimal,
14
- IWithReqoreSize,
14
+ IWithReqoreSize
15
15
  } from '../../types/global';
16
16
  import { StyledHeader } from '../Header';
17
17
  import { StyledParagraph } from '../Paragraph';
@@ -4,9 +4,10 @@ import { ReqorePopover } from '../..';
4
4
  import { IPopoverOptions } from '../../hooks/usePopover';
5
5
  import { IReqoreIconName } from '../../types/icons';
6
6
  import ReqoreButton, { IReqoreButtonProps } from '../Button';
7
+ import { IReqoreInputProps } from '../Input';
7
8
  import ReqoreDropdownList, { IReqoreDropdownItem, TDropdownItemOnClick } from './list';
8
9
 
9
- export interface IReqoreDropdownProps extends Partial<IPopoverOptions> {
10
+ export interface IReqoreDropdownProps extends Partial<Omit<IPopoverOptions, 'openOnMount'>> {
10
11
  items?: IReqoreDropdownItem[];
11
12
  multiSelect?: boolean;
12
13
  buttonStyle?: React.CSSProperties;
@@ -23,6 +24,8 @@ export interface IReqoreDropdownProps extends Partial<IPopoverOptions> {
23
24
  isDefaultOpen?: boolean;
24
25
  onItemSelect?: TDropdownItemOnClick;
25
26
  style?: React.CSSProperties;
27
+ inputProps?: IReqoreInputProps;
28
+ scrollToSelected?: boolean;
26
29
  }
27
30
 
28
31
  function ReqoreDropdown<T extends unknown = IReqoreButtonProps>({
@@ -50,13 +53,14 @@ function ReqoreDropdown<T extends unknown = IReqoreButtonProps>({
50
53
  maxWidth,
51
54
  noArrow = true,
52
55
  transparent,
53
- openOnMount,
54
56
  show,
55
57
  targetElement,
56
58
  useTargetWidth,
57
59
  listWidth,
58
60
  listHeight,
59
61
  passPopoverData,
62
+ inputProps,
63
+ scrollToSelected,
60
64
  ...rest
61
65
  }: IReqoreDropdownProps & T) {
62
66
  const componentProps = useMemo(
@@ -82,6 +86,8 @@ function ReqoreDropdown<T extends unknown = IReqoreButtonProps>({
82
86
  items={items}
83
87
  filterable={filterable}
84
88
  onItemSelect={onItemSelect}
89
+ inputProps={inputProps}
90
+ scrollToSelected={scrollToSelected}
85
91
  />
86
92
  ) : undefined;
87
93
  }, [items]);
@@ -1,6 +1,6 @@
1
1
  import React, { memo, useEffect, useMemo, useState } from 'react';
2
2
  import { IReqoreComponent } from '../../types/global';
3
- import ReqoreInput from '../Input';
3
+ import ReqoreInput, { IReqoreInputProps } from '../Input';
4
4
  import ReqoreMenu from '../Menu';
5
5
  import ReqoreMenuDivider from '../Menu/divider';
6
6
  import ReqoreMenuItem, { IReqoreMenuItemProps } from '../Menu/item';
@@ -25,6 +25,8 @@ export interface IReqoreDropdownListProps extends IReqoreComponent {
25
25
  height?: string;
26
26
  filterable?: boolean;
27
27
  onItemSelect?: TDropdownItemOnClick;
28
+ inputProps?: IReqoreInputProps;
29
+ scrollToSelected?: boolean;
28
30
  }
29
31
 
30
32
  const ReqoreDropdownList = memo(
@@ -37,6 +39,8 @@ const ReqoreDropdownList = memo(
37
39
  width,
38
40
  height,
39
41
  onItemSelect,
42
+ inputProps,
43
+ scrollToSelected,
40
44
  }: IReqoreDropdownListProps) => {
41
45
  const [_items, setItems] = useState<TReqoreDropdownItems>(items);
42
46
  const [query, setQuery] = useState<string>('');
@@ -94,6 +98,7 @@ const ReqoreDropdownList = memo(
94
98
  onChange={handleQueryChange}
95
99
  placeholder='Filter'
96
100
  onClearClick={() => setQuery('')}
101
+ {...inputProps}
97
102
  />
98
103
  </>
99
104
  )}
@@ -108,6 +113,7 @@ const ReqoreDropdownList = memo(
108
113
  label={item.label || item.value}
109
114
  onClick={() => handleItemClick({ ...item, onClick })}
110
115
  rightIcon={item.selected ? 'CheckLine' : undefined}
116
+ scrollIntoView={scrollToSelected && item.selected && !multiSelect}
111
117
  />
112
118
  )
113
119
  )}
@@ -1,8 +1,9 @@
1
- import React, { forwardRef } from 'react';
1
+ import React, { forwardRef, useEffect, useState } from 'react';
2
2
  import { useContext } from 'use-context-selector';
3
3
  import { ReqoreButton, ReqoreControlGroup } from '../..';
4
4
  import { IReqoreTheme, TReqoreIntent } from '../../constants/theme';
5
5
  import PopoverContext from '../../context/PopoverContext';
6
+ import { useCombinedRefs } from '../../hooks/useCombinedRefs';
6
7
  import { IReqoreComponent } from '../../types/global';
7
8
  import { IReqoreButtonProps } from '../Button';
8
9
 
@@ -17,6 +18,7 @@ export interface IReqoreMenuItemProps
17
18
  itemId?: string;
18
19
  onRightIconClick?: (itemId?: string, event?: React.MouseEvent<HTMLElement>) => void;
19
20
  onClick?: (itemId?: string, event?: React.MouseEvent<HTMLElement>) => void;
21
+ scrollIntoView?: boolean;
20
22
  }
21
23
 
22
24
  export interface IReqoreMenuItemStyle {
@@ -50,11 +52,14 @@ const ReqoreMenuItem = forwardRef<HTMLButtonElement, IReqoreMenuItemProps>(
50
52
  tooltip,
51
53
  intent,
52
54
  flat = true,
55
+ scrollIntoView,
53
56
  ...rest
54
57
  }: IReqoreMenuItemProps,
55
58
  ref
56
59
  ) => {
57
60
  const { removePopover } = useContext(PopoverContext);
61
+ const { targetRef } = useCombinedRefs<HTMLButtonElement>(ref);
62
+ const [itemRef, setItemRef] = useState<HTMLButtonElement>(undefined);
58
63
 
59
64
  const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
60
65
  event.persist();
@@ -79,6 +84,12 @@ const ReqoreMenuItem = forwardRef<HTMLButtonElement, IReqoreMenuItemProps>(
79
84
  }
80
85
  };
81
86
 
87
+ useEffect(() => {
88
+ if (scrollIntoView && itemRef) {
89
+ itemRef.scrollIntoView?.({ behavior: 'smooth', block: 'center', inline: 'center' });
90
+ }
91
+ }, [itemRef, scrollIntoView]);
92
+
82
93
  return (
83
94
  <ReqoreControlGroup stack={!!onRightIconClick} fluid>
84
95
  <ReqoreButton
@@ -90,7 +101,10 @@ const ReqoreMenuItem = forwardRef<HTMLButtonElement, IReqoreMenuItemProps>(
90
101
  fluid
91
102
  onClick={handleClick}
92
103
  active={selected}
93
- ref={ref}
104
+ ref={(ref) => {
105
+ targetRef.current = ref;
106
+ setItemRef(ref);
107
+ }}
94
108
  disabled={disabled}
95
109
  intent={intent}
96
110
  icon={icon}
@@ -28,7 +28,7 @@ export interface IReqoreMultiSelectProps
28
28
  selectedItemEffect?: IReqoreEffect;
29
29
  selectedItemSize?: TSizes;
30
30
  selectorProps?: Omit<IReqoreInputProps, 'value' | 'onValueChange'> & IReqoreDropdownProps;
31
- openOnMount?: IReqoreDropdownProps['openOnMount'];
31
+ openOnMount?: IReqoreDropdownProps['isDefaultOpen'];
32
32
  enterKeySelects?: boolean;
33
33
  }
34
34