@qoretechnologies/reqore 0.37.9 → 0.38.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 (92) hide show
  1. package/__tests__/dropdown.test.tsx +10 -8
  2. package/__tests__/table.test.tsx +0 -1
  3. package/dist/components/Breadcrumbs/index.d.ts.map +1 -1
  4. package/dist/components/Breadcrumbs/index.js +6 -4
  5. package/dist/components/Breadcrumbs/index.js.map +1 -1
  6. package/dist/components/Button/index.d.ts.map +1 -1
  7. package/dist/components/Button/index.js +5 -5
  8. package/dist/components/Button/index.js.map +1 -1
  9. package/dist/components/ControlGroup/index.d.ts.map +1 -1
  10. package/dist/components/ControlGroup/index.js +1 -1
  11. package/dist/components/ControlGroup/index.js.map +1 -1
  12. package/dist/components/Drawer/index.d.ts +1 -1
  13. package/dist/components/Drawer/index.d.ts.map +1 -1
  14. package/dist/components/Dropdown/index.d.ts +2 -2
  15. package/dist/components/Dropdown/index.d.ts.map +1 -1
  16. package/dist/components/Dropdown/index.js +5 -5
  17. package/dist/components/Dropdown/index.js.map +1 -1
  18. package/dist/components/Dropdown/item.d.ts +6 -5
  19. package/dist/components/Dropdown/item.d.ts.map +1 -1
  20. package/dist/components/Dropdown/item.js +14 -6
  21. package/dist/components/Dropdown/item.js.map +1 -1
  22. package/dist/components/Dropdown/list.d.ts +4 -2
  23. package/dist/components/Dropdown/list.d.ts.map +1 -1
  24. package/dist/components/Dropdown/list.js +33 -7
  25. package/dist/components/Dropdown/list.js.map +1 -1
  26. package/dist/components/Effect/index.d.ts +1 -0
  27. package/dist/components/Effect/index.d.ts.map +1 -1
  28. package/dist/components/Effect/index.js +39 -24
  29. package/dist/components/Effect/index.js.map +1 -1
  30. package/dist/components/InternalPopover/index.d.ts.map +1 -1
  31. package/dist/components/InternalPopover/index.js +21 -1
  32. package/dist/components/InternalPopover/index.js.map +1 -1
  33. package/dist/components/Menu/index.js +4 -4
  34. package/dist/components/Menu/index.js.map +1 -1
  35. package/dist/components/Menu/item.d.ts +1 -1
  36. package/dist/components/Menu/item.d.ts.map +1 -1
  37. package/dist/components/Menu/item.js +6 -6
  38. package/dist/components/Menu/item.js.map +1 -1
  39. package/dist/components/Message/index.d.ts.map +1 -1
  40. package/dist/components/Message/index.js +3 -4
  41. package/dist/components/Message/index.js.map +1 -1
  42. package/dist/components/MultiSelect/index.js +2 -2
  43. package/dist/components/MultiSelect/index.js.map +1 -1
  44. package/dist/components/Notifications/notification.d.ts +1 -0
  45. package/dist/components/Notifications/notification.d.ts.map +1 -1
  46. package/dist/components/Notifications/notification.js +10 -21
  47. package/dist/components/Notifications/notification.js.map +1 -1
  48. package/dist/components/Panel/LabelEditor.d.ts +12 -0
  49. package/dist/components/Panel/LabelEditor.d.ts.map +1 -0
  50. package/dist/components/Panel/LabelEditor.js +61 -0
  51. package/dist/components/Panel/LabelEditor.js.map +1 -0
  52. package/dist/components/Panel/index.d.ts +11 -1
  53. package/dist/components/Panel/index.d.ts.map +1 -1
  54. package/dist/components/Panel/index.js +65 -22
  55. package/dist/components/Panel/index.js.map +1 -1
  56. package/dist/components/Tabs/content.d.ts +4 -2
  57. package/dist/components/Tabs/content.d.ts.map +1 -1
  58. package/dist/components/Tabs/content.js +22 -5
  59. package/dist/components/Tabs/content.js.map +1 -1
  60. package/dist/components/Textarea/index.d.ts +4 -0
  61. package/dist/components/Textarea/index.d.ts.map +1 -1
  62. package/dist/components/Textarea/index.js +20 -5
  63. package/dist/components/Textarea/index.js.map +1 -1
  64. package/package.json +1 -1
  65. package/src/components/Breadcrumbs/index.tsx +19 -5
  66. package/src/components/Button/index.tsx +12 -11
  67. package/src/components/ControlGroup/index.tsx +1 -0
  68. package/src/components/Drawer/index.tsx +1 -1
  69. package/src/components/Dropdown/index.tsx +16 -14
  70. package/src/components/Dropdown/item.tsx +26 -10
  71. package/src/components/Dropdown/list.tsx +80 -30
  72. package/src/components/Effect/index.tsx +46 -15
  73. package/src/components/InternalPopover/index.tsx +24 -1
  74. package/src/components/Menu/index.tsx +2 -2
  75. package/src/components/Menu/item.tsx +93 -85
  76. package/src/components/Message/index.tsx +39 -35
  77. package/src/components/MultiSelect/index.tsx +2 -2
  78. package/src/components/Notifications/notification.tsx +34 -30
  79. package/src/components/Panel/LabelEditor.tsx +67 -0
  80. package/src/components/Panel/index.tsx +99 -25
  81. package/src/components/Tabs/content.tsx +44 -7
  82. package/src/components/Textarea/index.tsx +77 -27
  83. package/src/mock/breadcrumbs.ts +12 -1
  84. package/src/stories/Dropdown/Dropdown.stories.tsx +58 -0
  85. package/src/stories/Dropdown/DropdownTests.stories.tsx +78 -0
  86. package/src/stories/Message/Message.stories.tsx +13 -5
  87. package/src/stories/MultiSelect/MultiSelect.stories.tsx +2 -2
  88. package/src/stories/Panel/Panel.stories.tsx +123 -0
  89. package/src/stories/Popover/Popover.stories.tsx +41 -0
  90. package/src/stories/TextArea/TextArea.stories.tsx +49 -0
  91. package/src/stories/TextArea/TextAreaTests.stories.tsx +103 -0
  92. package/tests.json +1 -1
@@ -1,6 +1,7 @@
1
1
  import classNames from 'classnames';
2
- import { isArray, size } from 'lodash';
2
+ import { isArray, omit, size } from 'lodash';
3
3
  import { darken, rgba } from 'polished';
4
+ import { Resizable, ResizableProps } from 're-resizable';
4
5
  import { ReactElement, forwardRef, useCallback, useMemo, useState } from 'react';
5
6
  import { useMeasure, useUpdateEffect } from 'react-use';
6
7
  import styled, { css } from 'styled-components';
@@ -44,8 +45,9 @@ import ReqoreControlGroup from '../ControlGroup';
44
45
  import ReqoreDropdown from '../Dropdown';
45
46
  import { IReqoreDropdownItem } from '../Dropdown/list';
46
47
  import { IReqoreEffect, StyledEffect, TReqoreEffectColor } from '../Effect';
47
- import { ReqoreHeading, StyledHeader } from '../Header';
48
+ import { StyledHeader } from '../Header';
48
49
  import ReqoreIcon, { IReqoreIconProps, StyledIconWrapper } from '../Icon';
50
+ import { LabelEditor } from './LabelEditor';
49
51
  import { ReqorePanelNonResponsiveActions } from './NonResponsiveActions';
50
52
 
51
53
  export interface IReqorePanelSubAction extends Omit<IReqoreDropdownItem, 'value'> {}
@@ -92,6 +94,9 @@ export interface IReqorePanelProps
92
94
  collapseButtonProps?: IReqoreButtonProps;
93
95
  disabled?: boolean;
94
96
 
97
+ onLabelEdit?: (label: string | number) => void;
98
+ resizable?: ResizableProps;
99
+
95
100
  breadcrumbs?: IReqoreBreadcrumbsProps;
96
101
 
97
102
  onClose?: () => void;
@@ -164,7 +169,17 @@ export const StyledPanelTitleHeaderContent = styled.div`
164
169
  }
165
170
  `;
166
171
 
167
- export const StyledPanel = styled(StyledEffect)<IStyledPanel>`
172
+ export type TPanelStyle = React.FC<
173
+ Omit<IReqorePanelProps, 'onResize' | 'size'> &
174
+ ResizableProps & {
175
+ ref?: any;
176
+ theme: IReqoreTheme;
177
+ effect: IReqoreEffect;
178
+ interactive?: boolean;
179
+ }
180
+ >;
181
+
182
+ export const StyledPanel: TPanelStyle = styled(StyledEffect)<IStyledPanel>`
168
183
  background-color: ${({ theme, opacity = 1 }: IStyledPanel) =>
169
184
  rgba(changeDarkness(getMainBackgroundColor(theme), 0.03), opacity)};
170
185
  border-radius: ${({ rounded }) => (rounded ? RADIUS_FROM_SIZE.normal : 0)}px;
@@ -181,7 +196,6 @@ export const StyledPanel = styled(StyledEffect)<IStyledPanel>`
181
196
  flex-flow: column;
182
197
  position: relative;
183
198
  backdrop-filter: ${({ blur, opacity }) => (blur && opacity < 1 ? `blur(${blur}px)` : undefined)};
184
- transition: 0.2s ease-in-out;
185
199
  width: ${({ fluid }) => (fluid ? '100%' : undefined)};
186
200
  max-width: 100%;
187
201
  flex: ${({ fluid }) => (fluid ? '1 auto' : '0 0 auto')};
@@ -255,10 +269,14 @@ export const StyledPanelTitle = styled.div<IStyledPanel>`
255
269
  rgba(changeLightness(getMainBackgroundColor(theme), 0.03), opacity)};
256
270
  justify-content: space-between;
257
271
  // 2 is border that has to be added to the size + the button size + padding
258
- min-height: ${({ size }) => 2 + (SIZE_TO_PX[size] + PADDING_FROM_SIZE[size] * 2)}px;
272
+ min-height: ${({ size, transparent, flat, minimal }) =>
273
+ 2 +
274
+ (SIZE_TO_PX[size] + ((transparent && flat) || minimal ? 0 : PADDING_FROM_SIZE[size]) * 2)}px;
259
275
  align-items: center;
260
- padding: ${({ noHorizontalPadding, size }: IStyledPanel) =>
261
- `${PADDING_FROM_SIZE[size]}px ${noHorizontalPadding ? 0 : `${PADDING_FROM_SIZE[size]}px`}`};
276
+ padding: ${({ noHorizontalPadding, size, transparent, flat, intent }: IStyledPanel) =>
277
+ `${transparent && flat && !intent ? 0 : PADDING_FROM_SIZE[size]}px ${
278
+ noHorizontalPadding ? 0 : `${PADDING_FROM_SIZE[size]}px`
279
+ }`};
262
280
  border-bottom: ${({ theme, isCollapsed, flat, opacity = 1 }) =>
263
281
  !isCollapsed && !flat
264
282
  ? `1px solid ${rgba(changeLightness(getMainBackgroundColor(theme), 0.2), opacity)}`
@@ -287,9 +305,18 @@ export const StyledPanelTitle = styled.div<IStyledPanel>`
287
305
  `}
288
306
  `;
289
307
 
308
+ export const StyledPanelTopBar = styled(StyledPanelTitle)`
309
+ padding-bottom: ${({ minimal, padded, size, transparent }: IStyledPanel) =>
310
+ !padded ? `${PADDING_FROM_SIZE[size]}px` : minimal || transparent ? 0 : undefined};
311
+ padding-top: ${({ minimal, size }: IStyledPanel) =>
312
+ minimal ? `${PADDING_FROM_SIZE[size]}px` : undefined};
313
+ `;
314
+
290
315
  export const StyledPanelBottomActions = styled(StyledPanelTitle)`
291
- padding: ${({ noHorizontalPadding, size }: IStyledPanel) =>
292
- `${PADDING_FROM_SIZE[size]}px ${noHorizontalPadding ? 0 : `${PADDING_FROM_SIZE[size]}px`}`};
316
+ padding-top: ${({ minimal, padded, size, transparent }: IStyledPanel) =>
317
+ !padded ? `${PADDING_FROM_SIZE[size]}px` : minimal || transparent ? 0 : undefined};
318
+ padding-bottom: ${({ minimal, size }: IStyledPanel) =>
319
+ minimal ? `${PADDING_FROM_SIZE[size]}px` : undefined};
293
320
  border-bottom: 0;
294
321
  border-top: ${({ theme, flat, opacity = 1 }) =>
295
322
  !flat
@@ -299,18 +326,26 @@ export const StyledPanelBottomActions = styled(StyledPanelTitle)`
299
326
 
300
327
  export const StyledPanelContent = styled.div<IStyledPanel>`
301
328
  display: ${({ isCollapsed }) => (isCollapsed ? 'none !important' : undefined)};
302
- padding: ${({ padded, size, noHorizontalPadding }) =>
329
+ padding: ${({ padded, size, noHorizontalPadding, minimal }) =>
303
330
  !padded
304
331
  ? undefined
305
332
  : noHorizontalPadding
306
333
  ? `${PADDING_FROM_SIZE[size]}px 0`
307
- : `${PADDING_FROM_SIZE[size]}px`};
334
+ : `${PADDING_FROM_SIZE[size] / (minimal ? 2 : 1)}px ${PADDING_FROM_SIZE[size]}px`};
308
335
  // The padding is not needed when the panel is minimal and has title, since
309
336
  // the title already has padding and is transparent
310
337
  padding-top: ${({ minimal, hasLabel, padded, size }) =>
311
- minimal && hasLabel && padded ? `${PADDING_FROM_SIZE[size] / 2}px` : undefined};
312
- padding-bottom: ${({ minimal, padded, size }) =>
313
- minimal && padded ? `${PADDING_FROM_SIZE[size]}px` : undefined};
338
+ minimal && hasLabel && padded
339
+ ? `${PADDING_FROM_SIZE[size] / 2}px`
340
+ : padded
341
+ ? `${PADDING_FROM_SIZE[size]}px`
342
+ : undefined};
343
+ padding-bottom: ${({ minimal, padded, size, hasBottomActions }) =>
344
+ minimal && hasBottomActions && padded
345
+ ? `${PADDING_FROM_SIZE[size] / 2}px`
346
+ : padded
347
+ ? `${PADDING_FROM_SIZE[size]}px`
348
+ : undefined};
314
349
  flex: 1;
315
350
  overflow: auto;
316
351
  overflow-wrap: anywhere;
@@ -359,6 +394,8 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
359
394
  breadcrumbs,
360
395
  showActionsWhenCollapsed = true,
361
396
  showHeaderTooltip,
397
+ resizable,
398
+ onLabelEdit,
362
399
  ...rest
363
400
  }: IReqorePanelProps,
364
401
  ref
@@ -382,6 +419,27 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
382
419
  setIsCollapsed(!!isCollapsed);
383
420
  }, [isCollapsed]);
384
421
 
422
+ const _resizable: ResizableProps = useMemo(() => {
423
+ const disabledProps: ResizableProps = {
424
+ enable: {
425
+ top: false,
426
+ right: false,
427
+ bottom: false,
428
+ left: false,
429
+ topRight: false,
430
+ bottomRight: false,
431
+ bottomLeft: false,
432
+ topLeft: false,
433
+ },
434
+ };
435
+
436
+ if (isCollapsed || disabled) {
437
+ return disabledProps;
438
+ }
439
+
440
+ return resizable || disabledProps;
441
+ }, [resizable, isCollapsed, disabled]);
442
+
385
443
  // Return true if the card has a title bar, otherwise return false.
386
444
  const hasTitleBar: boolean = useMemo(
387
445
  () =>
@@ -626,11 +684,18 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
626
684
 
627
685
  return (
628
686
  <StyledPanel
629
- {...rest}
630
- as={rest.as || 'div'}
687
+ {...omit(rest, ['onResize'])}
688
+ {..._resizable}
689
+ as={rest.as || !!resizable ? Resizable : 'div'}
631
690
  ref={(ref) => {
632
- targetRef.current = ref;
633
- setItemRef(ref);
691
+ let _ref = ref;
692
+
693
+ if (ref?.resizable) {
694
+ _ref = ref.resizable;
695
+ }
696
+
697
+ targetRef.current = _ref;
698
+ setItemRef(_ref);
634
699
  }}
635
700
  isCollapsed={_isCollapsed}
636
701
  rounded={rounded}
@@ -645,19 +710,23 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
645
710
  disabled={disabled}
646
711
  >
647
712
  {hasTitleBar && (
648
- <StyledPanelTitle
713
+ <StyledPanelTopBar
649
714
  flat={flat}
650
715
  isCollapsed={_isCollapsed}
651
716
  collapsible={collapsible}
652
717
  className='reqore-panel-title'
653
718
  onClick={handleCollapseClick}
654
719
  theme={theme}
720
+ minimal={minimal}
655
721
  size={contentSize || panelSize}
656
722
  opacity={opacity ?? (minimal ? 0 : 1)}
657
723
  noHorizontalPadding={noHorizontalPadding}
658
724
  responsive={responsiveTitle}
659
725
  isMobile={isMobile || isSmall}
660
726
  ref={measureRef}
727
+ padded={padded}
728
+ transparent={rest.transparent || opacity === 0}
729
+ intent={intent}
661
730
  >
662
731
  {hasTitleHeader && (
663
732
  <StyledPanelTitleHeader>
@@ -693,17 +762,17 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
693
762
  />
694
763
  ) : null}
695
764
  {typeof label === 'string' ? (
696
- <ReqoreHeading
765
+ <LabelEditor
697
766
  size={headerSize || panelSize}
698
767
  customTheme={theme}
699
768
  effect={{
700
769
  noWrap: true,
701
770
  ...headerEffect,
702
771
  }}
772
+ label={label}
773
+ onSubmit={onLabelEdit}
703
774
  tooltip={showHeaderTooltip ? label : undefined}
704
- >
705
- {label}
706
- </ReqoreHeading>
775
+ />
707
776
  ) : (
708
777
  label
709
778
  )}
@@ -761,13 +830,14 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
761
830
  >
762
831
  {actions.map(renderNonResponsiveActions())}
763
832
  </ReqorePanelNonResponsiveActions>
764
- </StyledPanelTitle>
833
+ </StyledPanelTopBar>
765
834
  )}
766
835
  {!_isCollapsed || (_isCollapsed && !unMountContentOnCollapse) ? (
767
836
  <StyledPanelContent
768
837
  as={'div'}
769
838
  className='reqore-panel-content'
770
- hasLabel={!!label}
839
+ hasLabel={!!hasTitleBar}
840
+ hasBottomActions={hasBottomActions}
771
841
  isCollapsed={_isCollapsed}
772
842
  style={contentStyle}
773
843
  padded={padded}
@@ -784,6 +854,10 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
784
854
  flat={flat}
785
855
  className='reqore-panel-bottom-actions'
786
856
  theme={theme}
857
+ padded={padded}
858
+ intent={intent}
859
+ minimal={minimal}
860
+ transparent={rest.transparent || opacity === 0}
787
861
  opacity={opacity ?? (minimal ? 0 : 1)}
788
862
  size={contentSize || panelSize}
789
863
  noHorizontalPadding={noHorizontalPadding}
@@ -1,12 +1,24 @@
1
1
  import React from 'react';
2
2
  import styled from 'styled-components';
3
+ import { PADDING_FROM_SIZE, TSizes } from '../../constants/sizes';
3
4
 
4
- export type TReqoreTabsContentPadding = 'horizontal' | 'vertical' | 'none' | 'both' | true | false;
5
+ export type TReqoreTabsContentPadding =
6
+ | 'horizontal'
7
+ | 'vertical'
8
+ | 'none'
9
+ | 'both'
10
+ | 'top'
11
+ | 'bottom'
12
+ | 'left'
13
+ | 'right'
14
+ | true
15
+ | false;
5
16
 
6
17
  export interface IReqoreTabsContent extends React.HTMLAttributes<HTMLDivElement> {
7
18
  children?: any;
8
19
  tabId: string | number;
9
20
  padded?: TReqoreTabsContentPadding;
21
+ size?: TSizes;
10
22
  }
11
23
 
12
24
  const StyledTabsContent = styled.div`
@@ -14,16 +26,41 @@ const StyledTabsContent = styled.div`
14
26
  flex-flow: column;
15
27
  overflow: hidden;
16
28
  flex: 1;
17
- padding: ${({ padded }: IReqoreTabsContent) =>
29
+ padding: ${({ padded, size }: IReqoreTabsContent) =>
18
30
  padded === 'none' || padded === false
19
31
  ? undefined
20
- : `${padded === 'both' || padded === true || padded === 'vertical' ? 10 : 0}px ${
21
- padded === 'both' || padded === true || padded === 'horizontal' ? 10 : 0
22
- }px}`};
32
+ : `${
33
+ padded === 'both' || padded === true || padded === 'vertical'
34
+ ? `${PADDING_FROM_SIZE[size]}px`
35
+ : 0
36
+ } ${
37
+ padded === 'both' || padded === true || padded === 'horizontal'
38
+ ? `${PADDING_FROM_SIZE[size]}px`
39
+ : 0
40
+ }`};
41
+ padding-top: ${({ padded, size }: IReqoreTabsContent) =>
42
+ padded === 'top' ? `${PADDING_FROM_SIZE[size]}px` : undefined};
43
+ padding-bottom: ${({ padded, size }: IReqoreTabsContent) =>
44
+ padded === 'bottom' ? `${PADDING_FROM_SIZE[size]}px` : undefined};
45
+ padding-left: ${({ padded, size }: IReqoreTabsContent) =>
46
+ padded === 'left' ? `${PADDING_FROM_SIZE[size]}px` : undefined};
47
+ padding-right: ${({ padded, size }: IReqoreTabsContent) =>
48
+ padded === 'right' ? `${PADDING_FROM_SIZE[size]}px` : undefined};
23
49
  `;
24
50
 
25
- const ReqoreTabsContent = ({ children, className, padded = true, ...rest }: IReqoreTabsContent) => (
26
- <StyledTabsContent {...rest} padded={padded} className={`${className || ''} reqore-tabs-content`}>
51
+ const ReqoreTabsContent = ({
52
+ children,
53
+ className,
54
+ padded = true,
55
+ size = 'normal',
56
+ ...rest
57
+ }: IReqoreTabsContent) => (
58
+ <StyledTabsContent
59
+ {...rest}
60
+ size={size}
61
+ padded={padded}
62
+ className={`${className || ''} reqore-tabs-content`}
63
+ >
27
64
  {children}
28
65
  </StyledTabsContent>
29
66
  );
@@ -1,6 +1,7 @@
1
1
  import { rgba } from 'polished';
2
- import React, { forwardRef, useEffect, useState } from 'react';
2
+ import React, { forwardRef, useCallback, useEffect, useState } from 'react';
3
3
  import styled, { css } from 'styled-components';
4
+ import { ReqoreDropdown } from '../..';
4
5
  import { RADIUS_FROM_SIZE, SIZE_TO_PX, TEXT_FROM_SIZE, TSizes } from '../../constants/sizes';
5
6
  import { IReqoreTheme } from '../../constants/theme';
6
7
  import { changeLightness, getReadableColor } from '../../helpers/colors';
@@ -18,10 +19,13 @@ import {
18
19
  IWithReqoreEffect,
19
20
  IWithReqoreTooltip,
20
21
  } from '../../types/global';
22
+ import { IReqoreDropdownProps } from '../Dropdown';
21
23
  import { StyledEffect } from '../Effect';
22
24
  import { IReqoreInputStyle } from '../Input';
23
25
  import ReqoreInputClearButton from '../InputClearButton';
24
26
 
27
+ export interface IReqoreFormTemplates extends IReqoreDropdownProps {}
28
+
25
29
  export interface IReqoreTextareaProps
26
30
  extends React.HTMLAttributes<HTMLTextAreaElement>,
27
31
  IReqoreReadOnly,
@@ -46,6 +50,7 @@ export interface IReqoreTextareaProps
46
50
  onClearClick?: () => any;
47
51
  wrapperStyle?: React.CSSProperties;
48
52
  focusRules?: IReqoreAutoFocusRules;
53
+ templates?: IReqoreFormTemplates;
49
54
  }
50
55
 
51
56
  export interface IReqoreTextareaStyle extends IReqoreTextareaProps {
@@ -141,6 +146,7 @@ const ReqoreInput = forwardRef<HTMLTextAreaElement, IReqoreTextareaProps>(
141
146
  onChange,
142
147
  fixed,
143
148
  focusRules,
149
+ templates,
144
150
  ...rest
145
151
  }: IReqoreTextareaProps,
146
152
  ref
@@ -158,6 +164,75 @@ const ReqoreInput = forwardRef<HTMLTextAreaElement, IReqoreTextareaProps>(
158
164
  useAutosizeTextArea(inputRef, _value, scaleWithContent);
159
165
  useAutoFocus(inputRef, rest.readOnly || rest.disabled ? undefined : focusRules, onChange);
160
166
 
167
+ const handleItemSelect = useCallback(
168
+ (item) => {
169
+ if (!inputRef || !item || !item.value) {
170
+ return;
171
+ }
172
+ // Add the value of the selected item to the current value at the cursor position
173
+ const value = `${_value.slice(0, inputRef.selectionStart)}${item.value}${_value.slice(
174
+ inputRef.selectionEnd
175
+ )}`;
176
+
177
+ setValue(value);
178
+ },
179
+ [inputRef, _value]
180
+ );
181
+
182
+ const renderChildren = () => {
183
+ return (
184
+ <>
185
+ <StyledTextarea
186
+ {...rest}
187
+ effect={{
188
+ interactive: !rest?.disabled && !rest.readOnly,
189
+ ...rest?.effect,
190
+ }}
191
+ onChange={(e) => {
192
+ setValue(e.target.value);
193
+ onChange?.(e);
194
+ }}
195
+ as='textarea'
196
+ className={`${className || ''} reqore-control reqore-textarea`}
197
+ _size={size}
198
+ ref={(ref) => setInputRef(ref)}
199
+ theme={theme}
200
+ rounded={rounded}
201
+ rows={1}
202
+ value={_value}
203
+ readonly={rest?.readOnly}
204
+ />
205
+ <ReqoreInputClearButton
206
+ enabled={!rest?.readOnly && !rest?.disabled && !!(onClearClick && onChange)}
207
+ show={_value && _value !== ''}
208
+ onClick={onClearClick}
209
+ size={size}
210
+ />
211
+ </>
212
+ );
213
+ };
214
+
215
+ if (templates) {
216
+ return (
217
+ <ReqoreDropdown<Omit<IReqoreTextareaStyle & { ref: any }, 'content'>>
218
+ component={StyledTextareaWrapper}
219
+ className={`${className || ''} reqore-control-wrapper`}
220
+ width={width}
221
+ height={height}
222
+ fluid={fluid}
223
+ fixed={fixed}
224
+ _size={size}
225
+ theme={theme}
226
+ style={wrapperStyle}
227
+ ref={targetRef}
228
+ onItemSelect={handleItemSelect}
229
+ {...templates}
230
+ >
231
+ {renderChildren()}
232
+ </ReqoreDropdown>
233
+ );
234
+ }
235
+
161
236
  return (
162
237
  <StyledTextareaWrapper
163
238
  className={`${className || ''} reqore-control-wrapper`}
@@ -170,32 +245,7 @@ const ReqoreInput = forwardRef<HTMLTextAreaElement, IReqoreTextareaProps>(
170
245
  style={wrapperStyle}
171
246
  ref={targetRef}
172
247
  >
173
- <StyledTextarea
174
- {...rest}
175
- effect={{
176
- interactive: !rest?.disabled && !rest.readOnly,
177
- ...rest?.effect,
178
- }}
179
- onChange={(e) => {
180
- setValue(e.target.value);
181
- onChange?.(e);
182
- }}
183
- as='textarea'
184
- className={`${className || ''} reqore-control reqore-textarea`}
185
- _size={size}
186
- ref={(ref) => setInputRef(ref)}
187
- theme={theme}
188
- rounded={rounded}
189
- rows={1}
190
- value={_value}
191
- readonly={rest?.readOnly}
192
- />
193
- <ReqoreInputClearButton
194
- enabled={!rest?.readOnly && !rest?.disabled && !!(onClearClick && onChange)}
195
- show={_value && _value !== ''}
196
- onClick={onClearClick}
197
- size={size}
198
- />
248
+ {renderChildren()}
199
249
  </StyledTextareaWrapper>
200
250
  );
201
251
  }
@@ -17,9 +17,20 @@ export default [
17
17
  props: {
18
18
  href: 'https://google.com',
19
19
  },
20
- icon: Icons.Workflows,
20
+ leftIconProps: {
21
+ image:
22
+ 'https://avatars.githubusercontent.com/u/44835090?s=400&u=371120ce0755102d2e432f11ad9aa0378c871b45&v=4',
23
+ },
21
24
  flat: false,
22
25
  intent: 'info',
26
+ effect: {
27
+ glow: {
28
+ color: 'info',
29
+ size: 1,
30
+ blur: 10,
31
+ when: 'hover',
32
+ },
33
+ },
23
34
  },
24
35
  {
25
36
  icon: Icons.Services,
@@ -1,6 +1,8 @@
1
1
  import { StoryFn, StoryObj } from '@storybook/react';
2
+ import { fireEvent, within } from '@storybook/testing-library';
2
3
  import ReqoreButton, { IReqoreButtonProps } from '../../components/Button';
3
4
  import { IReqoreDropdownProps } from '../../components/Dropdown';
5
+ import { sleep } from '../../helpers/utils';
4
6
  import { ReqoreControlGroup, ReqoreDropdown, ReqoreInput } from '../../index';
5
7
  import { StoryMeta } from '../utils';
6
8
  import { argManager } from '../utils/args';
@@ -315,3 +317,59 @@ export const WithCustomPaging: Story = {
315
317
 
316
318
  play: () => {},
317
319
  };
320
+
321
+ export const WithChildItems: Story = {
322
+ render: (args) => <ReqoreDropdown {...args} />,
323
+ args: {
324
+ label: 'Dropdown with child items',
325
+ items: [
326
+ {
327
+ label: 'Test',
328
+ description: 'I have children',
329
+ rightIcon: 'MenuLine',
330
+ rightIconColor: 'info:lighten:2',
331
+ items: [
332
+ {
333
+ label: 'Test child 1',
334
+ },
335
+ {
336
+ label: 'Test child 2',
337
+ },
338
+ {
339
+ label: 'Test child 3',
340
+ description: 'I have children too',
341
+ items: [
342
+ {
343
+ label: 'Test deep child 1',
344
+ },
345
+ {
346
+ label: 'Test deep child 2',
347
+ },
348
+ {
349
+ label: 'Test deep child 3',
350
+ },
351
+ ],
352
+ },
353
+ {
354
+ label: 'Test child 4',
355
+ },
356
+ ],
357
+ },
358
+ {
359
+ label: 'Normal item',
360
+ description: 'I have no children',
361
+ },
362
+ ],
363
+ },
364
+ play: async ({ canvasElement }) => {
365
+ const canvas = within(canvasElement);
366
+
367
+ await sleep(200);
368
+
369
+ await fireEvent.click(canvas.getAllByText('Dropdown with child items')[0]);
370
+
371
+ await sleep(200);
372
+
373
+ await fireEvent.click(canvas.getAllByText('Test')[0]);
374
+ },
375
+ };
@@ -0,0 +1,78 @@
1
+ import { expect } from '@storybook/jest';
2
+ import { StoryObj } from '@storybook/react';
3
+ import { fireEvent, waitFor, within } from '@storybook/testing-library';
4
+ import ReqoreButton, { IReqoreButtonProps } from '../../components/Button';
5
+ import { IReqoreDropdownProps } from '../../components/Dropdown';
6
+ import { ReqoreDropdown } from '../../index';
7
+ import { StoryMeta } from '../utils';
8
+ import { argManager } from '../utils/args';
9
+ import { WithChildItems } from './Dropdown.stories';
10
+
11
+ const { createArg, disableArg } = argManager<IReqoreDropdownProps>();
12
+
13
+ const meta = {
14
+ title: 'Form/Dropdown/Tests',
15
+ component: ReqoreDropdown,
16
+ parameters: {
17
+ chromatic: {
18
+ delay: 1500,
19
+ },
20
+ },
21
+ argTypes: {
22
+ ...disableArg('multiSelect'),
23
+ ...createArg('component', {
24
+ defaultValue: ReqoreButton,
25
+ table: {
26
+ disable: true,
27
+ },
28
+ }),
29
+ ...createArg('filterable', {
30
+ defaultValue: true,
31
+ name: 'Filterable',
32
+ type: 'boolean',
33
+ }),
34
+ ...createArg('items', {
35
+ table: {
36
+ disable: true,
37
+ },
38
+ }),
39
+ },
40
+ args: {
41
+ component: ReqoreButton,
42
+ filterable: true,
43
+ },
44
+ } as StoryMeta<typeof ReqoreDropdown<IReqoreButtonProps>>;
45
+
46
+ export default meta;
47
+
48
+ type Story = StoryObj<typeof meta>;
49
+
50
+ export const ItemsCanBeTraversed: Story = {
51
+ ...WithChildItems,
52
+ play: async ({ canvasElement, ...rest }) => {
53
+ const canvas = within(canvasElement);
54
+
55
+ await WithChildItems.play({ canvasElement, ...rest });
56
+
57
+ await waitFor(() => expect(canvas.getAllByText('Test child 3')[0]).toBeTruthy(), {
58
+ timeout: 5000,
59
+ });
60
+
61
+ await fireEvent.click(canvas.getAllByText('Test child 3')[0]);
62
+
63
+ await expect(canvas.getAllByText('Test deep child 3')[0]).toBeTruthy();
64
+ },
65
+ };
66
+
67
+ export const BackButtonsWork: Story = {
68
+ ...ItemsCanBeTraversed,
69
+ play: async ({ canvasElement, ...rest }) => {
70
+ const canvas = within(canvasElement);
71
+
72
+ await ItemsCanBeTraversed.play({ canvasElement, ...rest });
73
+
74
+ await fireEvent.click(document.querySelector('.reqore-dropdown-back-button'));
75
+
76
+ await expect(canvas.getAllByText('Test child 3')[0]).toBeTruthy();
77
+ },
78
+ };
@@ -39,11 +39,8 @@ const Template: StoryFn<IReqoreMessageProps> = (args: IReqoreMessageProps) => {
39
39
  return (
40
40
  <>
41
41
  <ReqoreMessage {...args} onClick={noop}>
42
- In to am attended desirous raptures declared diverted confined at. Collected instantly
43
- remaining up certainly to necessary as. Over walk dull into son boy door went new. At or
44
- happiness commanded daughters as. Is handsome an declared at received in extended vicinity
45
- subjects. Into miss on he over been late pain an. Only week bore boy what fat case left use.
46
- Match round scale now sex style far times. Your me past an much.
42
+ {args.children ||
43
+ 'In to am attended desirous raptures declared diverted confined at. Collected instantly remaining up certainly to necessary as. Over walk dull into son boy door went new. At or happiness commanded daughters as. Is handsome an declared at received in extended vicinity subjects. Into miss on he over been late pain an. Only week bore boy what fat case left use. Match round scale now sex style far times. Your me past an much.'}
47
44
  </ReqoreMessage>
48
45
  </>
49
46
  );
@@ -53,6 +50,16 @@ export const Basic: Story = {
53
50
  render: Template,
54
51
  };
55
52
 
53
+ export const NoTitle: Story = {
54
+ render: Template,
55
+ args: {
56
+ icon: 'InformationFill',
57
+ flat: true,
58
+ title: undefined,
59
+ children: 'This is a test',
60
+ },
61
+ };
62
+
56
63
  export const Flat: Story = {
57
64
  render: Template,
58
65
 
@@ -68,6 +75,7 @@ export const Minimal: Story = {
68
75
  args: {
69
76
  minimal: true,
70
77
  intent: 'danger',
78
+ size: 'small',
71
79
  },
72
80
  };
73
81