@qoretechnologies/reqore 0.34.3 → 0.34.4

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 (61) hide show
  1. package/__tests__/button.test.tsx +30 -1
  2. package/__tests__/drawer.test.tsx +1 -1
  3. package/__tests__/heading.test.tsx +58 -0
  4. package/__tests__/hooks/useReqorePaging.test.tsx +16 -0
  5. package/__tests__/pagination.test.tsx +104 -3
  6. package/__tests__/panel.test.tsx +23 -2
  7. package/dist/components/Button/index.d.ts +3 -1
  8. package/dist/components/Button/index.d.ts.map +1 -1
  9. package/dist/components/Button/index.js +9 -7
  10. package/dist/components/Button/index.js.map +1 -1
  11. package/dist/components/Collection/index.d.ts.map +1 -1
  12. package/dist/components/Collection/index.js +1 -1
  13. package/dist/components/Collection/index.js.map +1 -1
  14. package/dist/components/ControlGroup/index.js +2 -2
  15. package/dist/components/ControlGroup/index.js.map +1 -1
  16. package/dist/components/Drawer/index.d.ts.map +1 -1
  17. package/dist/components/Drawer/index.js +3 -10
  18. package/dist/components/Drawer/index.js.map +1 -1
  19. package/dist/components/Header/index.d.ts +3 -3
  20. package/dist/components/Header/index.d.ts.map +1 -1
  21. package/dist/components/Header/index.js +5 -2
  22. package/dist/components/Header/index.js.map +1 -1
  23. package/dist/components/Paging/index.d.ts +2 -1
  24. package/dist/components/Paging/index.d.ts.map +1 -1
  25. package/dist/components/Paging/index.js +31 -1
  26. package/dist/components/Paging/index.js.map +1 -1
  27. package/dist/components/Panel/NonResponsiveActions.d.ts +18 -0
  28. package/dist/components/Panel/NonResponsiveActions.d.ts.map +1 -0
  29. package/dist/components/Panel/NonResponsiveActions.js +47 -0
  30. package/dist/components/Panel/NonResponsiveActions.js.map +1 -0
  31. package/dist/components/Panel/index.d.ts +5 -1
  32. package/dist/components/Panel/index.d.ts.map +1 -1
  33. package/dist/components/Panel/index.js +32 -19
  34. package/dist/components/Panel/index.js.map +1 -1
  35. package/dist/components/Tag/group.js +4 -1
  36. package/dist/components/Tag/group.js.map +1 -1
  37. package/dist/containers/Paging.d.ts +2 -1
  38. package/dist/containers/Paging.d.ts.map +1 -1
  39. package/dist/containers/Paging.js.map +1 -1
  40. package/dist/hooks/usePaging.d.ts +5 -0
  41. package/dist/hooks/usePaging.d.ts.map +1 -1
  42. package/dist/hooks/usePaging.js +7 -1
  43. package/dist/hooks/usePaging.js.map +1 -1
  44. package/package.json +1 -1
  45. package/src/components/Button/index.tsx +19 -14
  46. package/src/components/Collection/index.tsx +1 -0
  47. package/src/components/ControlGroup/index.tsx +1 -1
  48. package/src/components/Drawer/index.tsx +4 -10
  49. package/src/components/Header/index.tsx +9 -3
  50. package/src/components/Paging/index.tsx +37 -1
  51. package/src/components/Panel/NonResponsiveActions.tsx +79 -0
  52. package/src/components/Panel/index.tsx +128 -75
  53. package/src/components/Tag/group.tsx +1 -1
  54. package/src/containers/Paging.tsx +7 -3
  55. package/src/hooks/usePaging.ts +14 -0
  56. package/src/stories/Drawer/Drawer.stories.tsx +6 -1
  57. package/src/stories/Dropdown/Dropdown.stories.tsx +1 -0
  58. package/src/stories/Header/Header.stories.tsx +6 -8
  59. package/src/stories/Paging/Paging.stories.tsx +17 -1
  60. package/src/stories/Panel/Panel.stories.tsx +13 -3
  61. package/tests.json +1 -1
@@ -1,14 +1,16 @@
1
- import { memo, useMemo } from 'react';
1
+ import { memo, useMemo, useState } from 'react';
2
2
  import styled from 'styled-components';
3
3
  import { HEADER_SIZE_TO_NUMBER, TSizes } from '../../constants/sizes';
4
4
  import { IReqoreTheme, TReqoreIntent } from '../../constants/theme';
5
5
  import { isStringSize } from '../../helpers/utils';
6
6
  import { useReqoreTheme } from '../../hooks/useTheme';
7
- import { IWithReqoreEffect } from '../../types/global';
7
+ import { useTooltip } from '../../hooks/useTooltip';
8
+ import { IWithReqoreEffect, IWithReqoreTooltip } from '../../types/global';
8
9
  import { StyledTextEffect } from '../Effect';
9
10
 
10
11
  export interface IReqoreHeadingProps
11
12
  extends IWithReqoreEffect,
13
+ IWithReqoreTooltip,
12
14
  React.HTMLAttributes<HTMLHeadingElement> {
13
15
  intent?: TReqoreIntent;
14
16
  size?: 1 | 2 | 3 | 4 | 5 | 6 | TSizes;
@@ -45,18 +47,22 @@ export const StyledHeader = styled(StyledTextEffect)`
45
47
  `;
46
48
 
47
49
  export const ReqoreHeading = memo(
48
- ({ size, children, customTheme, intent, className, ...rest }: IReqoreHeadingProps) => {
50
+ ({ size, children, customTheme, intent, className, tooltip, ...rest }: IReqoreHeadingProps) => {
51
+ const [ref, setRef] = useState<HTMLHeadingElement>(undefined);
49
52
  const theme = useReqoreTheme('main', customTheme, intent);
50
53
  const _size: number = isStringSize(size) ? HEADER_SIZE_TO_NUMBER[size] : size;
51
54
  const HTMLheaderElement = useMemo(() => {
52
55
  return `h${_size}` as 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
53
56
  }, [_size]);
54
57
 
58
+ useTooltip(ref, tooltip);
59
+
55
60
  return (
56
61
  <StyledHeader
57
62
  as={HTMLheaderElement}
58
63
  theme={theme}
59
64
  intent={intent}
65
+ ref={setRef}
60
66
  {...rest}
61
67
  _size={_size}
62
68
  className={`${className || ''} reqore-heading`}
@@ -1,4 +1,5 @@
1
- import { memo, useRef, useState } from 'react';
1
+ import { debounce } from 'lodash';
2
+ import { memo, useEffect, useRef, useState } from 'react';
2
3
  import { useUnmount, useUpdateEffect } from 'react-use';
3
4
  import styled from 'styled-components';
4
5
  import { ReqoreDropdown } from '../..';
@@ -27,6 +28,7 @@ export interface IReqorePaginationComponentProps
27
28
  showLabels?: boolean;
28
29
  scrollOnLoadMore?: boolean;
29
30
  autoLoadMore?: boolean;
31
+ changePageOnScroll?: 'vertical' | 'horizontal';
30
32
  scrollContainer?: HTMLElement;
31
33
  scrollToTopOnPageChange?: boolean;
32
34
  }
@@ -79,6 +81,7 @@ function Pagination<T>({
79
81
  renderControls,
80
82
  scrollContainer,
81
83
  scrollToTopOnPageChange = true,
84
+ changePageOnScroll,
82
85
  ...rest
83
86
  }: IReqorePaginationProps<T>) {
84
87
  const [loadMoreRef, setLoadMoreRef] = useState<HTMLButtonElement>(undefined);
@@ -119,6 +122,39 @@ function Pagination<T>({
119
122
  }
120
123
  }, [currentPage, scrollContainer, scrollToTopOnPageChange, infinite]);
121
124
 
125
+ // Switch pages when user scrolls and holds the Shift key
126
+ useEffect(() => {
127
+ const handleScroll = debounce((e: WheelEvent) => {
128
+ const deltaKey = changePageOnScroll === 'vertical' ? 'deltaY' : 'deltaX';
129
+ // Only change pages when user holds the shift key
130
+ // aka horizontal scroll
131
+ if (
132
+ changePageOnScroll === 'vertical' ||
133
+ (changePageOnScroll === 'horizontal' && e.shiftKey)
134
+ ) {
135
+ // Do not horizontal scroll
136
+ e.preventDefault();
137
+ // If the user scrolls to the right, go to the next page
138
+ if (e[deltaKey] > 20) {
139
+ next();
140
+ // If the user scrolls to the left, go to the previous page
141
+ } else if (e[deltaKey] < -20) {
142
+ back();
143
+ }
144
+ }
145
+ }, 30);
146
+
147
+ if (scrollContainer && changePageOnScroll) {
148
+ scrollContainer.addEventListener('wheel', handleScroll);
149
+ }
150
+
151
+ return () => {
152
+ if (scrollContainer) {
153
+ scrollContainer.removeEventListener('wheel', handleScroll);
154
+ }
155
+ };
156
+ }, [currentPage, scrollContainer, changePageOnScroll]);
157
+
122
158
  useUpdateEffect(() => {
123
159
  if (loadMoreRef && autoLoadMore) {
124
160
  observer.current = new IntersectionObserver(
@@ -0,0 +1,79 @@
1
+ import { size } from 'lodash';
2
+ import { memo } from 'react';
3
+ import { IReqorePanelProps } from '.';
4
+ import { ReqoreButton } from '../..';
5
+ import { IWithReqoreCustomTheme } from '../../types/global';
6
+ import ReqoreControlGroup, { IReqoreControlGroupProps } from '../ControlGroup';
7
+
8
+ export interface IReqorePanelNonResponsiveActionsProps
9
+ extends IWithReqoreCustomTheme,
10
+ Omit<IReqoreControlGroupProps, 'children'> {
11
+ onCollapseClick?: () => void;
12
+ onCloseClick?: () => void;
13
+ hasResponsiveActions?: boolean;
14
+ isCollapsed?: boolean;
15
+ showControlButtons?: boolean;
16
+ show?: boolean;
17
+ children?: IReqoreControlGroupProps['children'] | undefined;
18
+ closeButtonProps?: IReqorePanelProps['closeButtonProps'];
19
+ collapseButtonProps?: IReqorePanelProps['collapseButtonProps'];
20
+ isSmall: boolean;
21
+ }
22
+
23
+ export const ReqorePanelNonResponsiveActions = memo(
24
+ ({
25
+ onCollapseClick,
26
+ onCloseClick,
27
+ hasResponsiveActions,
28
+ isCollapsed,
29
+ customTheme,
30
+ children,
31
+ showControlButtons,
32
+ show,
33
+ collapseButtonProps,
34
+ closeButtonProps,
35
+ isSmall,
36
+ ...rest
37
+ }: IReqorePanelNonResponsiveActionsProps) => {
38
+ if (!show || (!size(children) && !showControlButtons)) {
39
+ return null;
40
+ }
41
+
42
+ return (
43
+ <ReqoreControlGroup
44
+ fixed={isSmall ? false : hasResponsiveActions}
45
+ fluid={isSmall ? true : !hasResponsiveActions}
46
+ horizontalAlign='flex-end'
47
+ {...rest}
48
+ >
49
+ {children}
50
+ {!!onCollapseClick && showControlButtons ? (
51
+ <ReqoreButton
52
+ customTheme={customTheme}
53
+ icon={isCollapsed ? 'ArrowDownSLine' : 'ArrowUpSLine'}
54
+ onClick={(e) => {
55
+ e.stopPropagation();
56
+ onCollapseClick();
57
+ }}
58
+ tooltip={isCollapsed ? 'Expand' : 'Collapse'}
59
+ fixed
60
+ {...collapseButtonProps}
61
+ />
62
+ ) : null}
63
+ {!!onCloseClick && showControlButtons ? (
64
+ <ReqoreButton
65
+ fixed
66
+ customTheme={customTheme}
67
+ icon='CloseLine'
68
+ onClick={(e: React.MouseEvent<HTMLButtonElement>) => {
69
+ e.stopPropagation();
70
+ onCloseClick();
71
+ }}
72
+ tooltip='Close'
73
+ {...closeButtonProps}
74
+ />
75
+ ) : null}
76
+ </ReqoreControlGroup>
77
+ );
78
+ }
79
+ );
@@ -1,7 +1,7 @@
1
1
  import { size } from 'lodash';
2
2
  import { darken, rgba } from 'polished';
3
- import { ReactElement, forwardRef, useCallback, useMemo, useState } from 'react';
4
- import { useUpdateEffect } from 'react-use';
3
+ import { forwardRef, ReactElement, useCallback, useMemo, useState } from 'react';
4
+ import { useMeasure, useUpdateEffect } from 'react-use';
5
5
  import styled, { css } from 'styled-components';
6
6
  import {
7
7
  GAP_FROM_SIZE,
@@ -41,8 +41,9 @@ import ReqoreControlGroup from '../ControlGroup';
41
41
  import ReqoreDropdown from '../Dropdown';
42
42
  import { IReqoreDropdownItem } from '../Dropdown/list';
43
43
  import { IReqoreEffect, StyledEffect, TReqoreEffectColor } from '../Effect';
44
- import { ReqoreHeading } from '../Header';
44
+ import { ReqoreHeading, StyledHeader } from '../Header';
45
45
  import ReqoreIcon, { IReqoreIconProps, StyledIconWrapper } from '../Icon';
46
+ import { ReqorePanelNonResponsiveActions } from './NonResponsiveActions';
46
47
 
47
48
  export interface IReqorePanelAction extends IReqoreButtonProps, IWithReqoreTooltip, IReqoreIntent {
48
49
  label?: string | number;
@@ -83,7 +84,11 @@ export interface IReqorePanelProps
83
84
  badge?: TReqoreBadge | TReqoreBadge[];
84
85
  collapsible?: boolean;
85
86
  isCollapsed?: boolean;
87
+ collapseButtonProps?: IReqoreButtonProps;
88
+
86
89
  onClose?: () => void;
90
+ closeButtonProps?: IReqoreButtonProps;
91
+
87
92
  rounded?: boolean;
88
93
  actions?: TReqorePanelActions;
89
94
  bottomActions?: TReqorePanelBottomActions;
@@ -104,6 +109,8 @@ export interface IReqorePanelProps
104
109
  responsiveActions?: boolean;
105
110
  responsiveTitle?: boolean;
106
111
  getContentRef?: (ref: HTMLDivElement) => any;
112
+
113
+ headerProps?: React.HTMLAttributes<unknown>;
107
114
  }
108
115
 
109
116
  export interface IStyledPanel extends IReqorePanelProps {
@@ -111,6 +118,40 @@ export interface IStyledPanel extends IReqorePanelProps {
111
118
  noHorizontalPadding?: boolean;
112
119
  }
113
120
 
121
+ export const StyledPanelTitleHeader = styled.div`
122
+ display: flex;
123
+ justify-content: flex-start;
124
+ align-items: center;
125
+ flex: 1 1 auto;
126
+ width: 100%;
127
+ overflow: hidden;
128
+ `;
129
+
130
+ export const StyledPanelTitleHeaderContent = styled.div`
131
+ display: flex;
132
+ justify-content: flex-start;
133
+ align-items: center;
134
+ flex: 0 1 auto;
135
+ overflow: hidden;
136
+ min-width: ${({ iconSize, hasLabel, hasIcon }) => {
137
+ let width = 0;
138
+
139
+ if (hasIcon) {
140
+ width += iconSize;
141
+ }
142
+
143
+ if (hasLabel) {
144
+ width += 50;
145
+ }
146
+
147
+ return width;
148
+ }}px;
149
+
150
+ ${StyledHeader} {
151
+ min-width: 50px;
152
+ }
153
+ `;
154
+
114
155
  export const StyledPanel = styled(StyledEffect)<IStyledPanel>`
115
156
  background-color: ${({ theme, opacity = 1 }: IStyledPanel) =>
116
157
  rgba(changeDarkness(getMainBackgroundColor(theme), 0.03), opacity)};
@@ -139,7 +180,7 @@ export const StyledPanel = styled(StyledEffect)<IStyledPanel>`
139
180
  cursor: pointer;
140
181
 
141
182
  &:hover {
142
- ${StyledPanelTitle} > div > ${StyledIconWrapper} {
183
+ ${StyledPanelTitle} ${StyledPanelTitleHeaderContent} > ${StyledIconWrapper} {
143
184
  transform: scale(${ACTIVE_ICON_SCALE});
144
185
  }
145
186
 
@@ -206,7 +247,7 @@ export const StyledPanelTitle = styled.div<IStyledPanel>`
206
247
  flex: 0 0 auto;
207
248
  gap: ${GAP_FROM_SIZE.normal}px;
208
249
 
209
- > div > ${StyledIconWrapper} {
250
+ ${StyledPanelTitleHeaderContent} > ${StyledIconWrapper} {
210
251
  transform: scale(${INACTIVE_ICON_SCALE});
211
252
  }
212
253
 
@@ -215,7 +256,7 @@ export const StyledPanelTitle = styled.div<IStyledPanel>`
215
256
  css`
216
257
  cursor: pointer;
217
258
  &:hover {
218
- > div > ${StyledIconWrapper} {
259
+ ${StyledPanelTitleHeaderContent} > ${StyledIconWrapper} {
219
260
  transform: scale(${ACTIVE_ICON_SCALE});
220
261
  }
221
262
 
@@ -255,23 +296,15 @@ export const StyledPanelContent = styled.div<IStyledPanel>`
255
296
  font-size: ${({ size }) => TEXT_FROM_SIZE[size]}px;
256
297
  `;
257
298
 
258
- export const StyledPanelTitleHeader = styled.div`
259
- display: flex;
260
- justify-content: flex-start;
261
- align-items: center;
262
- flex: 1 1 auto;
263
- width: 100%;
264
- overflow: hidden;
265
- min-width: 100px;
266
- `;
267
-
268
299
  export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
269
300
  (
270
301
  {
271
302
  children,
272
303
  label,
304
+ collapseButtonProps = {},
273
305
  collapsible,
274
306
  onClose,
307
+ closeButtonProps = {},
275
308
  rounded = true,
276
309
  actions = [],
277
310
  bottomActions = [],
@@ -300,6 +333,7 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
300
333
  responsiveTitle = true,
301
334
  size: panelSize = 'normal',
302
335
  getContentRef,
336
+ headerProps = {},
303
337
  ...rest
304
338
  }: IReqorePanelProps,
305
339
  ref
@@ -315,6 +349,7 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
315
349
  const isMobile = useReqoreProperty('isMobile');
316
350
  const { targetRef } = useCombinedRefs(ref);
317
351
  const [itemRef, setItemRef] = useState<HTMLDivElement>(undefined);
352
+ const [measureRef, { width }] = useMeasure();
318
353
 
319
354
  useTooltip(itemRef, tooltip);
320
355
 
@@ -340,6 +375,8 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
340
375
  [label, icon, badge]
341
376
  );
342
377
 
378
+ const isSmall = useMemo(() => width < 480 && process.env.NODE_ENV !== 'test', [width]);
379
+
343
380
  // If collapsible is true, toggle the isCollapsed state
344
381
  // If the isCollapsed state is true, the component is expanded
345
382
  // If the isCollapsed state is false, the component is collapsed
@@ -557,51 +594,80 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
557
594
  opacity={opacity ?? (minimal ? 0 : 1)}
558
595
  noHorizontalPadding={noHorizontalPadding}
559
596
  responsive={responsiveTitle}
560
- isMobile={isMobile}
597
+ isMobile={isMobile || isSmall}
598
+ ref={measureRef}
561
599
  >
562
600
  {hasTitleHeader && (
563
601
  <StyledPanelTitleHeader>
564
- {icon || iconImage ? (
565
- <ReqoreIcon
566
- size={`${
567
- ICON_FROM_HEADER_SIZE[headerSize || HEADER_SIZE_TO_NUMBER[panelSize]]
568
- }px`}
569
- icon={icon}
570
- image={iconImage}
571
- margin='right'
572
- color={iconColor}
573
- {...iconProps}
574
- />
575
- ) : null}
576
- {typeof label === 'string' ? (
577
- <ReqoreHeading
578
- size={headerSize || panelSize}
579
- customTheme={theme}
580
- effect={{
581
- noWrap: true,
582
- ...headerEffect,
583
- }}
602
+ {icon || iconImage || label ? (
603
+ <StyledPanelTitleHeaderContent
604
+ size={panelSize}
605
+ {...headerProps}
606
+ hasLabel={!!label}
607
+ hasIcon={!!icon || !!iconImage}
608
+ iconSize={ICON_FROM_HEADER_SIZE[headerSize || HEADER_SIZE_TO_NUMBER[panelSize]]}
584
609
  >
585
- {label}
586
- </ReqoreHeading>
587
- ) : (
588
- label
589
- )}
610
+ {icon || iconImage ? (
611
+ <ReqoreIcon
612
+ size={`${
613
+ ICON_FROM_HEADER_SIZE[headerSize || HEADER_SIZE_TO_NUMBER[panelSize]]
614
+ }px`}
615
+ icon={icon}
616
+ image={iconImage}
617
+ margin='right'
618
+ color={iconColor}
619
+ tooltip={{
620
+ content: label,
621
+ }}
622
+ {...iconProps}
623
+ />
624
+ ) : null}
625
+ {typeof label === 'string' ? (
626
+ <ReqoreHeading
627
+ size={headerSize || panelSize}
628
+ customTheme={theme}
629
+ effect={{
630
+ noWrap: true,
631
+ ...headerEffect,
632
+ }}
633
+ tooltip={label}
634
+ >
635
+ {label}
636
+ </ReqoreHeading>
637
+ ) : (
638
+ label
639
+ )}
640
+ </StyledPanelTitleHeaderContent>
641
+ ) : null}
590
642
  {badge || badge === 0 ? (
591
- <>
592
- <ButtonBadge
593
- color={changeLightness(theme.main, 0.18)}
594
- size={getOneHigherSize(panelSize)}
595
- content={badge}
596
- />
597
- </>
643
+ <ButtonBadge
644
+ color={changeLightness(theme.main, 0.18)}
645
+ size={getOneHigherSize(panelSize)}
646
+ content={badge}
647
+ wrapGroup={isSmall}
648
+ />
598
649
  ) : null}
650
+ <ReqorePanelNonResponsiveActions
651
+ show={isSmall}
652
+ isSmall={isSmall}
653
+ showControlButtons
654
+ size={panelSize}
655
+ hasResponsiveActions={hasResponsiveActions(actions)}
656
+ customTheme={theme}
657
+ isCollapsed={_isCollapsed}
658
+ onCollapseClick={collapsible ? handleCollapseClick : undefined}
659
+ onCloseClick={onClose}
660
+ closeButtonProps={closeButtonProps}
661
+ collapseButtonProps={collapseButtonProps}
662
+ fluid={false}
663
+ style={{ marginLeft: 'auto' }}
664
+ />
599
665
  </StyledPanelTitleHeader>
600
666
  )}
601
667
  {hasResponsiveActions(actions) && (
602
668
  <ReqoreControlGroup
603
669
  responsive={responsiveActions}
604
- fluid={responsiveActions || isMobile}
670
+ fluid={responsiveActions || isSmall}
605
671
  horizontalAlign='flex-end'
606
672
  customTheme={theme}
607
673
  size={panelSize}
@@ -611,34 +677,21 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
611
677
  )}
612
678
  {collapsible || onClose || hasNonResponsiveActions(actions) ? (
613
679
  <>
614
- <ReqoreControlGroup
615
- fixed={isMobile ? false : hasResponsiveActions(actions)}
616
- fluid={isMobile ? true : !hasResponsiveActions(actions)}
617
- horizontalAlign='flex-end'
680
+ <ReqorePanelNonResponsiveActions
681
+ show
682
+ isSmall={isSmall}
683
+ showControlButtons={!isSmall}
618
684
  size={panelSize}
685
+ hasResponsiveActions={hasResponsiveActions(actions)}
686
+ customTheme={theme}
687
+ isCollapsed={_isCollapsed}
688
+ onCollapseClick={collapsible ? handleCollapseClick : undefined}
689
+ onCloseClick={onClose}
690
+ closeButtonProps={closeButtonProps}
691
+ collapseButtonProps={collapseButtonProps}
619
692
  >
620
693
  {actions.map(renderNonResponsiveActions())}
621
- {collapsible && (
622
- <ReqoreButton
623
- customTheme={theme}
624
- icon={_isCollapsed ? 'ArrowDownSLine' : 'ArrowUpSLine'}
625
- onClick={handleCollapseClick}
626
- tooltip={_isCollapsed ? 'Expand' : 'Collapse'}
627
- fixed
628
- />
629
- )}
630
- {onClose && (
631
- <ReqoreButton
632
- fixed
633
- customTheme={theme}
634
- icon='CloseLine'
635
- onClick={(e: React.MouseEvent<HTMLButtonElement>) => {
636
- e.stopPropagation();
637
- onClose?.();
638
- }}
639
- />
640
- )}
641
- </ReqoreControlGroup>
694
+ </ReqorePanelNonResponsiveActions>
642
695
  </>
643
696
  ) : null}
644
697
  </StyledPanelTitle>
@@ -14,7 +14,7 @@ export interface IReqoreTagGroup
14
14
  }
15
15
 
16
16
  const StyledTagGroup = styled.div`
17
- flex-shrink: 0;
17
+ flex-shrink: ${({ wrap }: IReqoreTagGroup) => (wrap ? 1 : 0)};
18
18
  display: flex;
19
19
  flex-wrap: ${({ wrap }: IReqoreTagGroup) => (wrap ? 'wrap' : 'nowrap')};
20
20
  gap: ${({ gapSize }: IReqoreTagGroup) => GAP_FROM_SIZE[gapSize]}px;
@@ -1,10 +1,14 @@
1
1
  import { memo, useMemo } from 'react';
2
- import { IReqorePaginationProps, ReqorePagination } from '../components/Paging';
2
+ import {
3
+ IReqorePaginationComponentProps,
4
+ IReqorePaginationProps,
5
+ ReqorePagination,
6
+ } from '../components/Paging';
3
7
  import { ReqoreVerticalSpacer } from '../components/Spacer';
4
8
  import {
9
+ getPaginationOptionsFromType,
5
10
  TReqorePaginationType,
6
11
  TReqorePaginationTypeResult,
7
- getPaginationOptionsFromType,
8
12
  } from '../constants/paging';
9
13
  import { PADDING_FROM_SIZE, TSizes } from '../constants/sizes';
10
14
  import { IReqorePagingResult, useReqorePaging } from '../hooks/usePaging';
@@ -12,7 +16,7 @@ import { IReqorePagingResult, useReqorePaging } from '../hooks/usePaging';
12
16
  export interface IReqorePagingContainerProps<T> {
13
17
  type?: TReqorePaginationType<T>;
14
18
  items: T[];
15
- scrollContainer?: HTMLElement;
19
+ scrollContainer?: IReqorePaginationComponentProps['scrollContainer'];
16
20
  children: (
17
21
  items: T[],
18
22
  Controls: JSX.Element,
@@ -3,6 +3,11 @@ import { useEffect, useMemo } from 'react';
3
3
  import { useUpdateEffect } from 'react-use';
4
4
  import usePagination, { usePaginationReturn } from 'react-use-pagination-hook';
5
5
 
6
+ export interface IReqorePageChangeData {
7
+ isFirst?: boolean;
8
+ isLast?: boolean;
9
+ }
10
+
6
11
  export interface IReqorePagingOptions<T> {
7
12
  items: T[];
8
13
  startPage?: number;
@@ -10,6 +15,7 @@ export interface IReqorePagingOptions<T> {
10
15
  itemsPerPage?: number;
11
16
  infinite?: boolean;
12
17
  enabled?: boolean;
18
+ onPageChange?: (page: number, info: IReqorePageChangeData) => void;
13
19
  }
14
20
 
15
21
  export interface IReqorePagingResult<T>
@@ -46,6 +52,7 @@ export const useReqorePaging = <T>(
46
52
  pagesToShow,
47
53
  startPage,
48
54
  enabled = true,
55
+ onPageChange,
49
56
  }: IReqorePagingOptions<T> = merge({}, defaultPagingOptions, options);
50
57
  const allPageCount = useMemo(() => Math.ceil(size(items) / itemsPerPage), [items, itemsPerPage]);
51
58
  const { pagelist, currentPage, setPage, setTotalPage, goNext, goBefore } = usePagination({
@@ -57,6 +64,13 @@ export const useReqorePaging = <T>(
57
64
  setPage(startPage || 1);
58
65
  }, [startPage]);
59
66
 
67
+ useUpdateEffect(() => {
68
+ onPageChange?.(currentPage, {
69
+ isFirst: currentPage === 1,
70
+ isLast: currentPage === allPageCount,
71
+ });
72
+ }, [currentPage]);
73
+
60
74
  useUpdateEffect(() => {
61
75
  setPage(1);
62
76
  setTotalPage(Math.ceil(size(items) / itemsPerPage));
@@ -10,12 +10,17 @@ import {
10
10
  ReqoreTabsContent,
11
11
  useReqoreProperty,
12
12
  } from '../../index';
13
- import { FlatArg, IntentArg, argManager } from '../utils/args';
13
+ import { argManager, FlatArg, IntentArg } from '../utils/args';
14
14
 
15
15
  const { createArg } = argManager<IReqoreDrawerProps>();
16
16
 
17
17
  export default {
18
18
  title: 'Components/Drawer',
19
+ parameters: {
20
+ chromatic: {
21
+ viewports: [450, 600, 1440],
22
+ },
23
+ },
19
24
  argTypes: {
20
25
  ...FlatArg,
21
26
  ...createArg('floating', {
@@ -229,6 +229,7 @@ export const WithPaging: Story<IReqoreDropdownProps> = Template.bind({});
229
229
  WithPaging.args = {
230
230
  paging: {
231
231
  itemsPerPage: 50,
232
+ changePageOnScroll: 'horizontal',
232
233
  },
233
234
  label: 'Dropdown with paging',
234
235
  };
@@ -1,6 +1,6 @@
1
1
  import { Meta, Story } from '@storybook/react/types-6-0';
2
2
  import { IReqoreHeadingProps } from '../../components/Header';
3
- import { ReqoreHeading, ReqoreVerticalSpacer } from '../../index';
3
+ import { ReqoreControlGroup, ReqoreHeading } from '../../index';
4
4
  import { IntentArg } from '../utils/args';
5
5
 
6
6
  export default {
@@ -12,31 +12,29 @@ export default {
12
12
 
13
13
  const Template: Story<IReqoreHeadingProps> = (args) => {
14
14
  return (
15
- <>
15
+ <ReqoreControlGroup gapSize='big' vertical>
16
16
  <ReqoreHeading size={1} {...args}>
17
17
  This is a heading
18
18
  </ReqoreHeading>
19
- <ReqoreVerticalSpacer height={10} />
20
19
  <ReqoreHeading size={2} {...args}>
21
20
  This is a heading
22
21
  </ReqoreHeading>
23
- <ReqoreVerticalSpacer height={10} />
24
22
  <ReqoreHeading size={3} {...args}>
25
23
  This is a heading
26
24
  </ReqoreHeading>
27
- <ReqoreVerticalSpacer height={10} />
28
25
  <ReqoreHeading size={4} {...args}>
29
26
  This is a heading
30
27
  </ReqoreHeading>
31
- <ReqoreVerticalSpacer height={10} />
32
28
  <ReqoreHeading size={5} {...args}>
33
29
  This is a heading
34
30
  </ReqoreHeading>
35
- <ReqoreVerticalSpacer height={10} />
36
31
  <ReqoreHeading size={6} {...args}>
37
32
  This is a heading
38
33
  </ReqoreHeading>
39
- </>
34
+ <ReqoreHeading size={1} {...args} tooltip={{ content: 'Nice tooltip', openOnMount: true }}>
35
+ This is a heading with tooltip
36
+ </ReqoreHeading>
37
+ </ReqoreControlGroup>
40
38
  );
41
39
  };
42
40
 
@@ -27,7 +27,9 @@ const Template: Story<IReqorePaginationProps<any> & { pagingOptions?: IReqorePag
27
27
  <ReqorePagination<any>
28
28
  {...paging}
29
29
  {...args}
30
- scrollContainer={args.scrollToTopOnPageChange ? scrollContainer : undefined}
30
+ scrollContainer={
31
+ args.scrollToTopOnPageChange || !!args.changePageOnScroll ? scrollContainer : undefined
32
+ }
31
33
  />
32
34
  </ReqoreControlGroup>
33
35
  );
@@ -142,6 +144,20 @@ WithLabels.args = {
142
144
  } as IReqorePagingOptions<any>,
143
145
  };
144
146
 
147
+ export const NextPageOnVerticalScroll: Story<
148
+ IReqorePaginationProps<any> & { pagingOptions?: IReqorePagingOptions<any> }
149
+ > = Template.bind({});
150
+ NextPageOnVerticalScroll.args = {
151
+ changePageOnScroll: 'vertical',
152
+ };
153
+
154
+ export const NextPageOnHorizontalScroll: Story<
155
+ IReqorePaginationProps<any> & { pagingOptions?: IReqorePagingOptions<any> }
156
+ > = Template.bind({});
157
+ NextPageOnHorizontalScroll.args = {
158
+ changePageOnScroll: 'horizontal',
159
+ };
160
+
145
161
  export const ScrollToTop: Story<
146
162
  IReqorePaginationProps<any> & { pagingOptions?: IReqorePagingOptions<any> }
147
163
  > = Template.bind({});