@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.
- package/__tests__/collection.test.tsx +5 -1
- package/__tests__/input.test.tsx +417 -24
- package/__tests__/multiselect.test.tsx +8 -10
- package/__tests__/textarea.test.tsx +405 -24
- package/dist/components/Button/index.d.ts.map +1 -1
- package/dist/components/Button/index.js +1 -1
- package/dist/components/Button/index.js.map +1 -1
- package/dist/components/Collection/index.d.ts +5 -2
- package/dist/components/Collection/index.d.ts.map +1 -1
- package/dist/components/Collection/index.js +10 -5
- package/dist/components/Collection/index.js.map +1 -1
- package/dist/components/Collection/item.d.ts.map +1 -1
- package/dist/components/Collection/item.js +1 -1
- package/dist/components/Collection/item.js.map +1 -1
- package/dist/components/ControlGroup/index.d.ts.map +1 -1
- package/dist/components/ControlGroup/index.js +17 -56
- package/dist/components/ControlGroup/index.js.map +1 -1
- package/dist/components/Icon/index.d.ts +2 -0
- package/dist/components/Icon/index.d.ts.map +1 -1
- package/dist/components/Icon/index.js +10 -5
- package/dist/components/Icon/index.js.map +1 -1
- package/dist/components/Input/index.d.ts +4 -0
- package/dist/components/Input/index.d.ts.map +1 -1
- package/dist/components/Input/index.js +18 -6
- package/dist/components/Input/index.js.map +1 -1
- package/dist/components/InputClearButton/index.d.ts +1 -0
- package/dist/components/InputClearButton/index.d.ts.map +1 -1
- package/dist/components/InputClearButton/index.js +18 -8
- package/dist/components/InputClearButton/index.js.map +1 -1
- package/dist/components/Panel/index.d.ts +4 -2
- package/dist/components/Panel/index.d.ts.map +1 -1
- package/dist/components/Panel/index.js +18 -14
- package/dist/components/Panel/index.js.map +1 -1
- package/dist/components/Textarea/index.d.ts +2 -0
- package/dist/components/Textarea/index.d.ts.map +1 -1
- package/dist/components/Textarea/index.js +4 -2
- package/dist/components/Textarea/index.js.map +1 -1
- package/dist/hooks/useAutoFocus.d.ts +11 -0
- package/dist/hooks/useAutoFocus.d.ts.map +1 -0
- package/dist/hooks/useAutoFocus.js +80 -0
- package/dist/hooks/useAutoFocus.js.map +1 -0
- package/dist/styles.d.ts.map +1 -1
- package/dist/styles.js +1 -1
- package/dist/styles.js.map +1 -1
- package/dist/types/global.d.ts +11 -0
- package/dist/types/global.d.ts.map +1 -1
- package/package.json +3 -1
- package/src/components/Button/index.tsx +1 -0
- package/src/components/Collection/index.tsx +34 -7
- package/src/components/Collection/item.tsx +1 -0
- package/src/components/ControlGroup/index.tsx +25 -86
- package/src/components/Icon/index.tsx +18 -4
- package/src/components/Input/index.tsx +38 -3
- package/src/components/InputClearButton/index.tsx +41 -17
- package/src/components/Panel/index.tsx +34 -26
- package/src/components/Textarea/index.tsx +15 -8
- package/src/hooks/useAutoFocus.ts +104 -0
- package/src/mock/collectionData.tsx +1 -0
- package/src/stories/Collection/Collection.stories.tsx +84 -10
- package/src/stories/Input/Input.stories.tsx +29 -6
- package/src/stories/Panel/Panel.stories.tsx +20 -2
- package/src/stories/TextArea/TextArea.stories.tsx +1 -0
- package/src/styles.ts +0 -1
- package/src/types/global.ts +12 -0
- 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
|
-
<
|
|
588
|
-
|
|
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
|
-
|
|
642
|
-
|
|
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
|
-
|
|
671
|
-
|
|
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
|
|
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:
|
|
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
|
|
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='
|
|
88
|
-
|
|
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='
|
|
95
|
-
|
|
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
|
|
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',
|