@qoretechnologies/reqore 0.31.1 → 0.32.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 (65) hide show
  1. package/__tests__/collection.test.tsx +5 -1
  2. package/__tests__/input.test.tsx +417 -24
  3. package/__tests__/multiselect.test.tsx +8 -10
  4. package/__tests__/textarea.test.tsx +405 -24
  5. package/dist/components/Button/index.d.ts.map +1 -1
  6. package/dist/components/Button/index.js +1 -1
  7. package/dist/components/Button/index.js.map +1 -1
  8. package/dist/components/Collection/index.d.ts +5 -2
  9. package/dist/components/Collection/index.d.ts.map +1 -1
  10. package/dist/components/Collection/index.js +10 -5
  11. package/dist/components/Collection/index.js.map +1 -1
  12. package/dist/components/Collection/item.d.ts.map +1 -1
  13. package/dist/components/Collection/item.js +1 -1
  14. package/dist/components/Collection/item.js.map +1 -1
  15. package/dist/components/ControlGroup/index.d.ts.map +1 -1
  16. package/dist/components/ControlGroup/index.js +17 -56
  17. package/dist/components/ControlGroup/index.js.map +1 -1
  18. package/dist/components/Icon/index.d.ts +2 -0
  19. package/dist/components/Icon/index.d.ts.map +1 -1
  20. package/dist/components/Icon/index.js +10 -5
  21. package/dist/components/Icon/index.js.map +1 -1
  22. package/dist/components/Input/index.d.ts +4 -0
  23. package/dist/components/Input/index.d.ts.map +1 -1
  24. package/dist/components/Input/index.js +18 -6
  25. package/dist/components/Input/index.js.map +1 -1
  26. package/dist/components/InputClearButton/index.d.ts +1 -0
  27. package/dist/components/InputClearButton/index.d.ts.map +1 -1
  28. package/dist/components/InputClearButton/index.js +18 -8
  29. package/dist/components/InputClearButton/index.js.map +1 -1
  30. package/dist/components/Panel/index.d.ts +4 -2
  31. package/dist/components/Panel/index.d.ts.map +1 -1
  32. package/dist/components/Panel/index.js +18 -14
  33. package/dist/components/Panel/index.js.map +1 -1
  34. package/dist/components/Textarea/index.d.ts +2 -0
  35. package/dist/components/Textarea/index.d.ts.map +1 -1
  36. package/dist/components/Textarea/index.js +4 -2
  37. package/dist/components/Textarea/index.js.map +1 -1
  38. package/dist/hooks/useAutoFocus.d.ts +11 -0
  39. package/dist/hooks/useAutoFocus.d.ts.map +1 -0
  40. package/dist/hooks/useAutoFocus.js +80 -0
  41. package/dist/hooks/useAutoFocus.js.map +1 -0
  42. package/dist/styles.d.ts.map +1 -1
  43. package/dist/styles.js +1 -1
  44. package/dist/styles.js.map +1 -1
  45. package/dist/types/global.d.ts +11 -0
  46. package/dist/types/global.d.ts.map +1 -1
  47. package/package.json +3 -1
  48. package/src/components/Button/index.tsx +1 -0
  49. package/src/components/Collection/index.tsx +34 -7
  50. package/src/components/Collection/item.tsx +1 -0
  51. package/src/components/ControlGroup/index.tsx +25 -86
  52. package/src/components/Icon/index.tsx +18 -4
  53. package/src/components/Input/index.tsx +38 -3
  54. package/src/components/InputClearButton/index.tsx +41 -17
  55. package/src/components/Panel/index.tsx +34 -26
  56. package/src/components/Textarea/index.tsx +15 -8
  57. package/src/hooks/useAutoFocus.ts +104 -0
  58. package/src/mock/collectionData.tsx +1 -0
  59. package/src/stories/Collection/Collection.stories.tsx +84 -10
  60. package/src/stories/Input/Input.stories.tsx +29 -6
  61. package/src/stories/Panel/Panel.stories.tsx +20 -2
  62. package/src/stories/TextArea/TextArea.stories.tsx +1 -0
  63. package/src/styles.ts +0 -1
  64. package/src/types/global.ts +12 -0
  65. package/tests.json +1 -1
@@ -21,6 +21,7 @@ import {
21
21
  } from '../../helpers/colors';
22
22
  import { getOneHigherSize, isActionShown } from '../../helpers/utils';
23
23
  import { useCombinedRefs } from '../../hooks/useCombinedRefs';
24
+ import { useReqore } from '../../hooks/useReqore';
24
25
  import { useReqoreTheme } from '../../hooks/useTheme';
25
26
  import { useTooltip } from '../../hooks/useTooltip';
26
27
  import { ACTIVE_ICON_SCALE, INACTIVE_ICON_SCALE } from '../../styles';
@@ -29,6 +30,7 @@ import {
29
30
  IWithReqoreCustomTheme,
30
31
  IWithReqoreFlat,
31
32
  IWithReqoreFluid,
33
+ IWithReqoreIconImage,
32
34
  IWithReqoreSize,
33
35
  IWithReqoreTooltip,
34
36
  } from '../../types/global';
@@ -40,8 +42,7 @@ import ReqoreDropdown from '../Dropdown';
40
42
  import { IReqoreDropdownItem } from '../Dropdown/list';
41
43
  import { IReqoreEffect, StyledEffect, TReqoreEffectColor } from '../Effect';
42
44
  import { ReqoreHeading } from '../Header';
43
- import ReqoreIcon, { StyledIconWrapper } from '../Icon';
44
- import { ReqoreHorizontalSpacer, ReqoreSpacer } from '../Spacer';
45
+ import ReqoreIcon, { IReqoreIconProps, StyledIconWrapper } from '../Icon';
45
46
 
46
47
  export interface IReqorePanelAction extends IReqoreButtonProps, IWithReqoreTooltip, IReqoreIntent {
47
48
  label?: string | number;
@@ -72,10 +73,12 @@ export interface IReqorePanelProps
72
73
  IReqoreIntent,
73
74
  IWithReqoreTooltip,
74
75
  IWithReqoreFluid,
76
+ IWithReqoreIconImage,
75
77
  React.HTMLAttributes<HTMLDivElement> {
76
78
  as?: any;
77
79
  children?: any;
78
80
  icon?: IReqoreIconName;
81
+ iconProps?: IReqoreIconProps;
79
82
  label?: string | ReactElement<any>;
80
83
  badge?: TReqoreBadge | TReqoreBadge[];
81
84
  collapsible?: boolean;
@@ -184,6 +187,7 @@ export const StyledPanel = styled(StyledEffect)<IStyledPanel>`
184
187
 
185
188
  export const StyledPanelTitle = styled.div<IStyledPanel>`
186
189
  display: flex;
190
+ flex-flow: ${({ isMobile }) => (isMobile ? 'column' : 'row')};
187
191
  background-color: ${({ theme, opacity = 1 }: IStyledPanel) =>
188
192
  rgba(changeLightness(getMainBackgroundColor(theme), 0.03), opacity)};
189
193
  justify-content: space-between;
@@ -198,6 +202,7 @@ export const StyledPanelTitle = styled.div<IStyledPanel>`
198
202
  transition: background-color 0.2s ease-out;
199
203
  overflow: hidden;
200
204
  flex: 0 0 auto;
205
+ gap: ${GAP_FROM_SIZE.normal}px;
201
206
 
202
207
  > div > ${StyledIconWrapper} {
203
208
  transform: scale(${INACTIVE_ICON_SCALE});
@@ -252,7 +257,6 @@ export const StyledPanelTitleHeader = styled.div`
252
257
  display: flex;
253
258
  justify-content: flex-start;
254
259
  align-items: center;
255
- padding-right: 5px;
256
260
  flex: 1 1 auto;
257
261
  width: 100%;
258
262
  overflow: hidden;
@@ -272,6 +276,7 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
272
276
  isCollapsed,
273
277
  customTheme,
274
278
  icon,
279
+ iconImage,
275
280
  intent,
276
281
  className,
277
282
  flat,
@@ -287,6 +292,7 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
287
292
  tooltip,
288
293
  badge,
289
294
  iconColor,
295
+ iconProps = {},
290
296
  fluid,
291
297
  responsiveActions = true,
292
298
  size: panelSize = 'normal',
@@ -302,6 +308,7 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
302
308
  ? { main: Object.values(contentEffect.gradient.colors)[0] as TReqoreEffectColor }
303
309
  : undefined)
304
310
  );
311
+ const { isMobile } = useReqore();
305
312
  const { targetRef } = useCombinedRefs(ref);
306
313
 
307
314
  useTooltip(targetRef.current, tooltip);
@@ -414,8 +421,8 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
414
421
  stack
415
422
  customTheme={rest.customTheme || theme}
416
423
  size={rest.size}
417
- fixed
418
- fluid={rest.fluid}
424
+ fixed={rest.fixed ? true : false}
425
+ fluid={rest.fluid ? true : false}
419
426
  key={index}
420
427
  >
421
428
  {group.map((action, index) => renderActions(action, index, true))}
@@ -426,9 +433,9 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
426
433
  if (size(actions)) {
427
434
  return (
428
435
  <ReqoreDropdown<IReqoreButtonProps>
436
+ fixed
429
437
  {...rest}
430
438
  key={index}
431
- fixed
432
439
  label={label}
433
440
  items={actions}
434
441
  intent={intent}
@@ -445,7 +452,8 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
445
452
  <CustomElement
446
453
  fixed
447
454
  {...props}
448
- key={index}
455
+ key={props.key || index}
456
+ reactKey={props.key || index}
449
457
  customTheme={props.customTheme || theme}
450
458
  onClick={(e: React.MouseEvent<any>) => {
451
459
  e.stopPropagation();
@@ -457,9 +465,9 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
457
465
 
458
466
  return (
459
467
  <ReqoreButton
468
+ fixed
460
469
  {...rest}
461
470
  id={id}
462
- fixed
463
471
  key={index}
464
472
  className={className}
465
473
  customTheme={rest.customTheme || theme}
@@ -532,19 +540,22 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
532
540
  size={contentSize || panelSize}
533
541
  opacity={opacity ?? (minimal ? 0 : 1)}
534
542
  noHorizontalPadding={noHorizontalPadding}
543
+ isMobile={isMobile}
535
544
  >
536
545
  {hasTitleHeader && (
537
546
  <StyledPanelTitleHeader>
538
- {icon && (
547
+ {icon || iconImage ? (
539
548
  <ReqoreIcon
540
549
  size={`${
541
550
  ICON_FROM_HEADER_SIZE[headerSize || HEADER_SIZE_TO_NUMBER[panelSize]]
542
551
  }px`}
543
552
  icon={icon}
553
+ image={iconImage}
544
554
  margin='right'
545
555
  color={iconColor}
556
+ {...iconProps}
546
557
  />
547
- )}
558
+ ) : null}
548
559
  {typeof label === 'string' ? (
549
560
  <ReqoreHeading
550
561
  size={headerSize || panelSize}
@@ -566,7 +577,6 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
566
577
  size={getOneHigherSize(panelSize)}
567
578
  content={badge}
568
579
  />
569
- <ReqoreSpacer width={PADDING_FROM_SIZE.normal} />
570
580
  </>
571
581
  ) : null}
572
582
  </StyledPanelTitleHeader>
@@ -574,7 +584,7 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
574
584
  {hasResponsiveActions(actions) && (
575
585
  <ReqoreControlGroup
576
586
  responsive={responsiveActions}
577
- fluid={responsiveActions}
587
+ fluid={responsiveActions || isMobile}
578
588
  horizontalAlign='flex-end'
579
589
  customTheme={theme}
580
590
  size={panelSize}
@@ -584,8 +594,12 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
584
594
  )}
585
595
  {collapsible || onClose || hasNonResponsiveActions(actions) ? (
586
596
  <>
587
- <ReqoreHorizontalSpacer width={GAP_FROM_SIZE.normal} />
588
- <ReqoreControlGroup fixed horizontalAlign='flex-end' size={panelSize}>
597
+ <ReqoreControlGroup
598
+ fixed={!isMobile}
599
+ fluid={isMobile}
600
+ horizontalAlign='flex-end'
601
+ size={panelSize}
602
+ >
589
603
  {actions.map(renderNonResponsiveActions)}
590
604
  {collapsible && (
591
605
  <ReqoreButton
@@ -637,12 +651,9 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
637
651
  noHorizontalPadding={noHorizontalPadding}
638
652
  >
639
653
  {hasNonResponsiveActions(leftBottomActions) ? (
640
- <>
641
- <ReqoreControlGroup size={panelSize}>
642
- {leftBottomActions.map(renderNonResponsiveActions)}
643
- </ReqoreControlGroup>
644
- <ReqoreHorizontalSpacer width={GAP_FROM_SIZE.normal} />
645
- </>
654
+ <ReqoreControlGroup size={panelSize}>
655
+ {leftBottomActions.map(renderNonResponsiveActions)}
656
+ </ReqoreControlGroup>
646
657
  ) : null}
647
658
  {hasResponsiveActions(leftBottomActions) && (
648
659
  <ReqoreControlGroup
@@ -666,12 +677,9 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
666
677
  </ReqoreControlGroup>
667
678
  )}
668
679
  {hasNonResponsiveActions(rightBottomActions) ? (
669
- <>
670
- <ReqoreHorizontalSpacer width={GAP_FROM_SIZE.normal} />
671
- <ReqoreControlGroup horizontalAlign='flex-end' size={panelSize}>
672
- {rightBottomActions.map(renderNonResponsiveActions)}
673
- </ReqoreControlGroup>
674
- </>
680
+ <ReqoreControlGroup horizontalAlign='flex-end' size={panelSize}>
681
+ {rightBottomActions.map(renderNonResponsiveActions)}
682
+ </ReqoreControlGroup>
675
683
  ) : null}
676
684
  </StyledPanelBottomActions>
677
685
  ) : null}
@@ -4,6 +4,7 @@ import styled, { css } from 'styled-components';
4
4
  import { RADIUS_FROM_SIZE, SIZE_TO_PX, TEXT_FROM_SIZE, TSizes } from '../../constants/sizes';
5
5
  import { IReqoreTheme } from '../../constants/theme';
6
6
  import { changeLightness, getReadableColor } from '../../helpers/colors';
7
+ import { IReqoreAutoFocusRules, useAutoFocus } from '../../hooks/useAutoFocus';
7
8
  import { useCombinedRefs } from '../../hooks/useCombinedRefs';
8
9
  import useAutosizeTextArea from '../../hooks/useTextareaAutoSize';
9
10
  import { useReqoreTheme } from '../../hooks/useTheme';
@@ -44,6 +45,7 @@ export interface IReqoreTextareaProps
44
45
  fixed?: boolean;
45
46
  onClearClick?: () => any;
46
47
  wrapperStyle?: React.CSSProperties;
48
+ focusRules?: IReqoreAutoFocusRules;
47
49
  }
48
50
 
49
51
  export interface IReqoreTextareaStyle extends IReqoreTextareaProps {
@@ -138,6 +140,7 @@ const ReqoreInput = forwardRef<HTMLTextAreaElement, IReqoreTextareaProps>(
138
140
  value,
139
141
  onChange,
140
142
  fixed,
143
+ focusRules,
141
144
  ...rest
142
145
  }: IReqoreTextareaProps,
143
146
  ref
@@ -152,6 +155,11 @@ const ReqoreInput = forwardRef<HTMLTextAreaElement, IReqoreTextareaProps>(
152
155
 
153
156
  useTooltip(targetRef?.current, tooltip);
154
157
  useAutosizeTextArea(targetRef?.current, _value, scaleWithContent);
158
+ useAutoFocus(
159
+ targetRef.current,
160
+ rest.readOnly || rest.disabled ? undefined : focusRules,
161
+ onChange
162
+ );
155
163
 
156
164
  return (
157
165
  <StyledTextareaWrapper
@@ -182,15 +190,14 @@ const ReqoreInput = forwardRef<HTMLTextAreaElement, IReqoreTextareaProps>(
182
190
  rounded={rounded}
183
191
  rows={1}
184
192
  value={_value}
193
+ readonly={rest?.readOnly}
194
+ />
195
+ <ReqoreInputClearButton
196
+ enabled={!rest?.readOnly && !rest?.disabled && !!(onClearClick && onChange)}
197
+ show={_value && _value !== ''}
198
+ onClick={onClearClick}
199
+ size={size}
185
200
  />
186
- {!rest.readOnly && (
187
- <ReqoreInputClearButton
188
- enabled={!rest?.disabled && !!(onClearClick && onChange)}
189
- show={_value && _value !== ''}
190
- onClick={onClearClick}
191
- size={size}
192
- />
193
- )}
194
201
  </StyledTextareaWrapper>
195
202
  );
196
203
  }
@@ -0,0 +1,104 @@
1
+ import { useCallback, useEffect, useRef } from 'react';
2
+ import { useUnmount, useUpdateEffect } from 'react-use';
3
+
4
+ export type TReqoreAutoFocusType = 'auto' | 'keypress';
5
+
6
+ export interface IReqoreAutoFocusRules {
7
+ type: TReqoreAutoFocusType;
8
+ viewportOnly?: boolean;
9
+ viewport?: HTMLElement;
10
+ viewportMargin?: string;
11
+ shortcut?: 'letters' | 'numbers' | string | ('letters' | 'numbers' | string)[];
12
+ clearOnFocus?: boolean;
13
+ }
14
+
15
+ export const useAutoFocus = (
16
+ element: HTMLInputElement | HTMLTextAreaElement,
17
+ rules?: IReqoreAutoFocusRules,
18
+ onChange?: (e: unknown) => void
19
+ ) => {
20
+ const isInViewport = useRef<boolean>(false);
21
+ const observer = useRef<IntersectionObserver>(null);
22
+
23
+ const focus = useCallback(() => {
24
+ if (!rules.viewportOnly || isInViewport.current) {
25
+ if (rules.clearOnFocus) {
26
+ onChange?.({ target: { value: '' } } as any);
27
+ }
28
+
29
+ element.setSelectionRange(-1, -1);
30
+ element.focus();
31
+ }
32
+ }, [element, rules, isInViewport.current]);
33
+
34
+ const handleKeyDown = (e: KeyboardEvent) => {
35
+ // Check if this event came from another html input
36
+ if (
37
+ e.target &&
38
+ ((e.target as HTMLElement).tagName === 'INPUT' ||
39
+ (e.target as HTMLElement).tagName === 'TEXTAREA')
40
+ ) {
41
+ return;
42
+ }
43
+
44
+ const shortcut = Array.isArray(rules?.shortcut) ? rules?.shortcut : [rules?.shortcut];
45
+
46
+ if (shortcut.includes('letters') && e.key.length === 1 && e.key.match(/[a-z]/i)) {
47
+ focus();
48
+ }
49
+
50
+ if (shortcut.includes('numbers') && e.key.length === 1 && e.key.match(/[0-9]/i)) {
51
+ focus();
52
+ }
53
+
54
+ if (shortcut.includes(e.key)) {
55
+ focus();
56
+ }
57
+ };
58
+
59
+ useUpdateEffect(() => {
60
+ if (element && rules) {
61
+ if (rules.viewportOnly) {
62
+ observer.current = new IntersectionObserver(
63
+ (entries: IntersectionObserverEntry[]) => {
64
+ entries.forEach((entry) => {
65
+ if (entry.isIntersecting) {
66
+ isInViewport.current = true;
67
+ } else {
68
+ isInViewport.current = false;
69
+ }
70
+ // If the focus type is auto, we focus the element now if its in the viewport
71
+ // and set the observer to null so it doesn't run again
72
+ if (rules.type === 'auto' && isInViewport.current) {
73
+ element.focus();
74
+ observer.current?.disconnect();
75
+ observer.current = null;
76
+ }
77
+ });
78
+ },
79
+ {
80
+ root: rules?.viewport,
81
+ rootMargin: rules?.viewportMargin,
82
+ threshold: 0.8,
83
+ }
84
+ );
85
+
86
+ observer.current.observe(element);
87
+ } else if (rules.type === 'auto') {
88
+ focus();
89
+ }
90
+ }
91
+ }, [element]);
92
+
93
+ useUnmount(() => {
94
+ observer.current?.disconnect();
95
+ });
96
+
97
+ useEffect(() => {
98
+ if (element && rules && rules.type === 'keypress') {
99
+ window.addEventListener('keydown', handleKeyDown);
100
+ }
101
+
102
+ return () => window.removeEventListener('keydown', handleKeyDown);
103
+ }, [element, rules]);
104
+ };
@@ -94,6 +94,7 @@ export default [
94
94
  label: 'Item with custom content when expanded',
95
95
  tooltip: 'Expandable item with custom content',
96
96
  selected: true,
97
+ badge: '2km',
97
98
  content:
98
99
  'Hello I am a test item content and I am very long so I will wrap to the next line and I will be very long. Hello I am a test item content and I am very long so I will wrap to the next line and I will be very long. Hello I am a test item content and I am very long so I will wrap to the next line and I will be very long. Hello I am a test item content and I am very long so I will wrap to the next line and I will be very long. Hello I am a test item content and I am very long so I will wrap to the next line and I will be very long. Hello I am a test item content and I am very long so I will wrap to the next line and I will be very long',
99
100
  expandable: true,
@@ -1,8 +1,10 @@
1
1
  import { Meta, Story } from '@storybook/react';
2
+ import { ReqoreButton, ReqoreControlGroup } from '../..';
2
3
  import { IReqoreCollectionProps, ReqoreCollection } from '../../components/Collection';
3
4
  import { IReqoreColumnsProps } from '../../components/Columns';
4
5
  import items from '../../mock/collectionData';
5
- import { IntentArg, SizeArg, argManager } from '../utils/args';
6
+ import data from '../../mock/data.json';
7
+ import { argManager, IntentArg, SizeArg } from '../utils/args';
6
8
 
7
9
  export interface IColumnsStoryArgs extends IReqoreColumnsProps {
8
10
  multipleColumns?: boolean;
@@ -57,7 +59,7 @@ export default {
57
59
  description: 'If true, the collection will fill the parent',
58
60
  }),
59
61
  ...createArg('label', {
60
- defaultValue: 'Collection of items',
62
+ defaultValue: undefined,
61
63
  type: 'string',
62
64
  name: 'Label',
63
65
  description: 'Label of the collection',
@@ -69,20 +71,17 @@ export default {
69
71
  } as Meta<IReqoreCollectionProps>;
70
72
 
71
73
  const Template: Story<IReqoreCollectionProps> = (args) => {
72
- return (
73
- <ReqoreCollection
74
- {...args}
75
- badge={10}
76
- selectedIcon='CheckLine'
77
- actions={[{ label: 'Custom action', icon: 'Home7Line' }, { actions: [{ value: 'Test' }] }]}
78
- />
79
- );
74
+ return <ReqoreCollection {...args} selectedIcon='CheckLine' />;
80
75
  };
81
76
 
82
77
  export const Basic = Template.bind({});
83
78
  Basic.args = {
84
79
  label: 'Config Items',
85
80
  items,
81
+ actions: [
82
+ { label: 'Custom action', icon: 'Home7Line', fixed: true },
83
+ { actions: [{ value: 'Test' }] },
84
+ ],
86
85
  };
87
86
 
88
87
  export const WithHeight = Template.bind({});
@@ -90,6 +89,10 @@ WithHeight.args = {
90
89
  label: 'Collection of items',
91
90
  height: '600px',
92
91
  items,
92
+ actions: [
93
+ { label: 'Custom action', icon: 'Home7Line', fixed: true },
94
+ { actions: [{ value: 'Test' }] },
95
+ ],
93
96
  };
94
97
 
95
98
  export const Stacked = Template.bind({});
@@ -97,6 +100,10 @@ Stacked.args = {
97
100
  label: 'Collection of items',
98
101
  stacked: true,
99
102
  items,
103
+ actions: [
104
+ { label: 'Custom action', icon: 'Home7Line', fixed: true },
105
+ { actions: [{ value: 'Test' }] },
106
+ ],
100
107
  };
101
108
 
102
109
  export const Fill = Template.bind({});
@@ -104,6 +111,10 @@ Fill.args = {
104
111
  label: 'Collection of items',
105
112
  fill: true,
106
113
  items,
114
+ actions: [
115
+ { label: 'Custom action', icon: 'Home7Line', fixed: true },
116
+ { actions: [{ value: 'Test' }] },
117
+ ],
107
118
  };
108
119
 
109
120
  export const SelectedFirst = Template.bind({});
@@ -127,3 +138,66 @@ CustomPropsAndTexts.args = {
127
138
  sortButtonTooltip: (sort) => `Seradit ${sort === 'asc' ? 'vzestupne' : 'sestupne'}`,
128
139
  displayButtonTooltip: (display) => `Zobrazit ${display === 'list' ? 'v liste' : 'v mriezke'}`,
129
140
  };
141
+
142
+ export const ChildrenBeforeAndAfter = Template.bind({});
143
+ ChildrenBeforeAndAfter.args = {
144
+ label: 'Collection of items',
145
+ items,
146
+ childrenBefore: (
147
+ <ReqoreControlGroup horizontalAlign='center' fluid>
148
+ <ReqoreButton fluid> I could be a filter of some kind</ReqoreButton>
149
+ </ReqoreControlGroup>
150
+ ),
151
+ childrenAfter: (
152
+ <ReqoreControlGroup horizontalAlign='center' fluid>
153
+ <ReqoreControlGroup fluid={false} fixed>
154
+ <ReqoreButton fixed textAlign='center'>
155
+ 1
156
+ </ReqoreButton>
157
+ <ReqoreButton fixed textAlign='center'>
158
+ 2
159
+ </ReqoreButton>
160
+ <ReqoreButton fixed textAlign='center'>
161
+ 3
162
+ </ReqoreButton>
163
+ <ReqoreButton fixed textAlign='center'>
164
+ 4
165
+ </ReqoreButton>
166
+ </ReqoreControlGroup>
167
+ </ReqoreControlGroup>
168
+ ),
169
+ };
170
+
171
+ export const FilteringSearchingPaging = Template.bind({});
172
+ FilteringSearchingPaging.args = {
173
+ inputProps: {
174
+ focusRules: {
175
+ type: 'keypress',
176
+ shortcut: 'letters',
177
+ clearOnFocus: true,
178
+ },
179
+ },
180
+ inputPlaceholder(items) {
181
+ return `Start typing to search in ${items.length} items`;
182
+ },
183
+ size: 'big',
184
+ padded: false,
185
+ fill: true,
186
+ items: data.slice(0, 100).map((datum) => ({
187
+ label: `${datum.firstName} ${datum.lastName}`,
188
+ badge: datum.id,
189
+ size: 'small',
190
+ expandable: true,
191
+ content: datum.address,
192
+ tags: [
193
+ {
194
+ labelKey: 'Age',
195
+ label: datum.age,
196
+ },
197
+ {
198
+ labelKey: 'Occupation',
199
+ label: datum.occupation,
200
+ },
201
+ ],
202
+ })),
203
+ } as IReqoreCollectionProps;
@@ -29,7 +29,13 @@ const Template: Story<IReqoreInputProps> = (args: IReqoreInputProps) => {
29
29
  <>
30
30
  <ReqoreControlGroup wrap>
31
31
  <ReqoreInput {...args} placeholder='Reqore Input' onChange={handleValueChange} />
32
- <ReqoreInput {...args} placeholder='Minimal Input' minimal onChange={handleValueChange} />
32
+ <ReqoreInput
33
+ {...args}
34
+ placeholder='Minimal Input'
35
+ minimal
36
+ onChange={handleValueChange}
37
+ rightIcon='ClipboardLine'
38
+ />
33
39
  <ReqoreInput
34
40
  {...args}
35
41
  placeholder='Flat Input'
@@ -44,11 +50,22 @@ const Template: Story<IReqoreInputProps> = (args: IReqoreInputProps) => {
44
50
  onClearClick={handleValueClear}
45
51
  onChange={handleValueChange}
46
52
  />
53
+ <ReqoreInput
54
+ {...args}
55
+ iconColor='pending:lighten:2'
56
+ placeholder='Clearable Input w/ icon'
57
+ onClearClick={handleValueClear}
58
+ onChange={handleValueChange}
59
+ rightIcon='EraserFill'
60
+ rightIconColor='#8727b7'
61
+ />
47
62
  <ReqoreInput {...args} placeholder='Disabled Input' disabled onChange={handleValueChange} />
48
63
  <ReqoreInput
49
64
  {...args}
50
65
  placeholder='Read Only Input'
51
66
  readOnly
67
+ rightIcon='Bus2Fill'
68
+ rightIconColor='info'
52
69
  onChange={handleValueChange}
53
70
  />
54
71
  </ReqoreControlGroup>
@@ -73,6 +90,8 @@ const Template: Story<IReqoreInputProps> = (args: IReqoreInputProps) => {
73
90
  flat
74
91
  tooltip="I'm a tooltip"
75
92
  onChange={handleValueChange}
93
+ rightIcon='DragMoveLine'
94
+ rightIconColor='#eb0e8c'
76
95
  value={value}
77
96
  />
78
97
  <ReqoreInput
@@ -84,18 +103,21 @@ const Template: Story<IReqoreInputProps> = (args: IReqoreInputProps) => {
84
103
  />
85
104
  <ReqoreInput
86
105
  {...args}
87
- placeholder='Disabled Input'
88
- disabled
89
- onChange={handleValueChange}
106
+ placeholder='Clearable Input w/ icon'
107
+ onClearClick={handleValueClear}
90
108
  value={value}
109
+ rightIcon='FilePptFill'
110
+ rightIconColor='#508a90'
111
+ onChange={handleValueChange}
91
112
  />
92
113
  <ReqoreInput
93
114
  {...args}
94
- placeholder='Read Only Input'
95
- readOnly
115
+ placeholder='Disabled Input'
116
+ disabled
96
117
  onChange={handleValueChange}
97
118
  value={value}
98
119
  />
120
+ <ReqoreInput {...args} placeholder='Read Only Input' readOnly value={value} />
99
121
  </ReqoreControlGroup>
100
122
  <br />
101
123
  <ReqoreControlGroup fluid>
@@ -104,6 +126,7 @@ const Template: Story<IReqoreInputProps> = (args: IReqoreInputProps) => {
104
126
  placeholder='Fluid Input'
105
127
  onChange={handleValueChange}
106
128
  value={value}
129
+ focusRules={{ type: 'keypress', shortcut: 'k' }}
107
130
  />
108
131
  </ReqoreControlGroup>
109
132
  </>
@@ -3,7 +3,7 @@ import { noop } from 'lodash';
3
3
  import ReqoreInput, { IReqoreInputProps } from '../../components/Input';
4
4
  import { IReqorePanelAction, IReqorePanelProps, ReqorePanel } from '../../components/Panel';
5
5
  import { ReqoreVerticalSpacer } from '../../components/Spacer';
6
- import { FlatArg, IconArg, IntentArg, SizeArg, argManager } from '../utils/args';
6
+ import { argManager, FlatArg, IconArg, IntentArg, SizeArg } from '../utils/args';
7
7
 
8
8
  const { createArg } = argManager<IReqorePanelProps>();
9
9
 
@@ -168,6 +168,7 @@ const Template: Story<IReqorePanelProps> = (args: IReqorePanelProps) => {
168
168
  {
169
169
  icon: 'FullscreenExitLine',
170
170
  customTheme: { main: '#a40a62' },
171
+ fixed: true,
171
172
  },
172
173
  ],
173
174
  },
@@ -199,7 +200,7 @@ const Template: Story<IReqorePanelProps> = (args: IReqorePanelProps) => {
199
200
  position: 'left',
200
201
  intent: 'success',
201
202
  group: [
202
- { label: 'Test 1', icon: '24HoursFill' },
203
+ { label: 'Test 1', icon: '24HoursFill', fixed: true },
203
204
  { label: 'Test 2', icon: '24HoursFill' },
204
205
  ],
205
206
  },
@@ -346,6 +347,23 @@ Size.args = {
346
347
  size: 'small',
347
348
  };
348
349
 
350
+ export const NoActions: Story<IReqorePanelProps> = Template.bind({});
351
+ NoActions.args = {
352
+ collapsible: false,
353
+ actions: [],
354
+ label:
355
+ 'This is a really long title that should stretch all the way to the right of the panel, all the way to the end and not end in the middle',
356
+ };
357
+
358
+ export const ImageAsIcon: Story<IReqorePanelProps> = Template.bind({});
359
+ ImageAsIcon.args = {
360
+ iconImage:
361
+ 'https://avatars.githubusercontent.com/u/44835090?s=400&u=371120ce0755102d2e432f11ad9aa0378c871b45&v=4',
362
+ iconProps: {
363
+ size: '30px',
364
+ },
365
+ };
366
+
349
367
  export const ContentSize: Story<IReqorePanelProps> = Template.bind({});
350
368
  ContentSize.args = {
351
369
  contentSize: 'big',
@@ -137,6 +137,7 @@ const Template: Story<IReqoreTextareaProps> = (args) => {
137
137
  onClearClick={handleValueClear}
138
138
  value={value}
139
139
  fluid
140
+ focusRules={{ type: 'keypress', shortcut: 'letters', clearOnFocus: true }}
140
141
  />
141
142
  </ReqoreControlGroup>
142
143
  </>
package/src/styles.ts CHANGED
@@ -51,6 +51,5 @@ export const DisabledElement = css`
51
51
  `;
52
52
 
53
53
  export const ReadOnlyElement = css`
54
- pointer-events: none;
55
54
  cursor: not-allowed;
56
55
  `;