@qoretechnologies/reqore 0.31.2 → 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 (56) 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 +3 -2
  9. package/dist/components/Collection/index.d.ts.map +1 -1
  10. package/dist/components/Collection/index.js +6 -3
  11. package/dist/components/Collection/index.js.map +1 -1
  12. package/dist/components/ControlGroup/index.d.ts.map +1 -1
  13. package/dist/components/ControlGroup/index.js +17 -56
  14. package/dist/components/ControlGroup/index.js.map +1 -1
  15. package/dist/components/Icon/index.d.ts +2 -0
  16. package/dist/components/Icon/index.d.ts.map +1 -1
  17. package/dist/components/Icon/index.js +10 -5
  18. package/dist/components/Icon/index.js.map +1 -1
  19. package/dist/components/Input/index.d.ts +4 -0
  20. package/dist/components/Input/index.d.ts.map +1 -1
  21. package/dist/components/Input/index.js +18 -6
  22. package/dist/components/Input/index.js.map +1 -1
  23. package/dist/components/InputClearButton/index.d.ts +1 -0
  24. package/dist/components/InputClearButton/index.d.ts.map +1 -1
  25. package/dist/components/InputClearButton/index.js +18 -8
  26. package/dist/components/InputClearButton/index.js.map +1 -1
  27. package/dist/components/Panel/index.d.ts.map +1 -1
  28. package/dist/components/Panel/index.js +11 -6
  29. package/dist/components/Panel/index.js.map +1 -1
  30. package/dist/components/Textarea/index.d.ts +2 -0
  31. package/dist/components/Textarea/index.d.ts.map +1 -1
  32. package/dist/components/Textarea/index.js +4 -2
  33. package/dist/components/Textarea/index.js.map +1 -1
  34. package/dist/hooks/useAutoFocus.d.ts +11 -0
  35. package/dist/hooks/useAutoFocus.d.ts.map +1 -0
  36. package/dist/hooks/useAutoFocus.js +80 -0
  37. package/dist/hooks/useAutoFocus.js.map +1 -0
  38. package/dist/styles.d.ts.map +1 -1
  39. package/dist/styles.js +1 -1
  40. package/dist/styles.js.map +1 -1
  41. package/package.json +3 -1
  42. package/src/components/Button/index.tsx +1 -0
  43. package/src/components/Collection/index.tsx +12 -2
  44. package/src/components/ControlGroup/index.tsx +25 -86
  45. package/src/components/Icon/index.tsx +18 -4
  46. package/src/components/Input/index.tsx +38 -3
  47. package/src/components/InputClearButton/index.tsx +41 -17
  48. package/src/components/Panel/index.tsx +18 -8
  49. package/src/components/Textarea/index.tsx +15 -8
  50. package/src/hooks/useAutoFocus.ts +104 -0
  51. package/src/stories/Collection/Collection.stories.tsx +54 -10
  52. package/src/stories/Input/Input.stories.tsx +29 -6
  53. package/src/stories/Panel/Panel.stories.tsx +3 -2
  54. package/src/stories/TextArea/TextArea.stories.tsx +1 -0
  55. package/src/styles.ts +0 -1
  56. package/tests.json +1 -1
@@ -1,12 +1,5 @@
1
1
  import { debounce } from 'lodash';
2
- import React, {
3
- memo,
4
- useCallback,
5
- useEffect,
6
- useMemo,
7
- useRef,
8
- useState,
9
- } from 'react';
2
+ import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
10
3
  import { useMount, useUnmount } from 'react-use';
11
4
  import styled, { css } from 'styled-components';
12
5
  import { ReqoreButton, ReqoreDrawer } from '../..';
@@ -63,16 +56,13 @@ export interface IReqoreControlGroupStyle extends IReqoreControlGroupProps {
63
56
 
64
57
  export const StyledReqoreControlGroup = styled.div<IReqoreControlGroupStyle>`
65
58
  display: flex;
66
- flex: ${({ fluid, fixed }) =>
67
- fixed ? '0 0 auto' : fluid ? undefined : '0 0 auto'};
59
+ flex: ${({ fluid, fixed }) => (fixed ? '0 0 auto' : fluid ? undefined : '0 0 auto')};
68
60
  width: ${({ fluid, fixed }) => (fluid && !fixed ? '100%' : undefined)};
69
- justify-content: ${({ fluid, vertical }) =>
70
- vertical && fluid ? 'stretch' : undefined};
61
+ justify-content: ${({ fluid, vertical }) => (vertical && fluid ? 'stretch' : undefined)};
71
62
  align-items: ${({ vertical, fluid, horizontalAlign }) =>
72
63
  vertical ? (fluid ? 'stretch' : horizontalAlign) : undefined};
73
64
  flex-flow: ${({ vertical }) => (vertical ? 'column' : 'row')};
74
- gap: ${({ gapSize, stack }) =>
75
- !stack ? `${GAP_FROM_SIZE[gapSize]}px` : undefined};
65
+ gap: ${({ gapSize, stack }) => (!stack ? `${GAP_FROM_SIZE[gapSize]}px` : undefined)};
76
66
  flex-wrap: ${({ wrap }) => (wrap ? 'wrap' : 'nowrap')};
77
67
 
78
68
  // If the group has the fill prop,
@@ -95,23 +85,16 @@ export const StyledReqoreControlGroup = styled.div<IReqoreControlGroupStyle>`
95
85
 
96
86
  > * {
97
87
  margin-top: ${({ fill, verticalAlign }) =>
98
- !fill && (verticalAlign === 'flex-end' || verticalAlign === 'center')
99
- ? 'auto'
100
- : undefined};
88
+ !fill && (verticalAlign === 'flex-end' || verticalAlign === 'center') ? 'auto' : undefined};
101
89
  margin-bottom: ${({ fill, verticalAlign }) =>
102
- !fill && (verticalAlign === 'flex-start' || verticalAlign === 'center')
103
- ? 'auto'
104
- : undefined};
105
- margin-right: ${({ horizontalAlign }) =>
106
- horizontalAlign === 'center' ? 'auto' : undefined};
90
+ !fill && (verticalAlign === 'flex-start' || verticalAlign === 'center') ? 'auto' : undefined};
91
+ margin-right: ${({ horizontalAlign }) => (horizontalAlign === 'center' ? 'auto' : undefined)};
107
92
 
108
93
  ${({ vertical }) =>
109
94
  vertical &&
110
95
  css`
111
96
  margin-left: ${({ horizontalAlign }) =>
112
- horizontalAlign === 'flex-end' || horizontalAlign === 'center'
113
- ? 'auto'
114
- : undefined};
97
+ horizontalAlign === 'flex-end' || horizontalAlign === 'center' ? 'auto' : undefined};
115
98
  `}
116
99
  }
117
100
 
@@ -120,9 +103,7 @@ export const StyledReqoreControlGroup = styled.div<IReqoreControlGroupStyle>`
120
103
  css`
121
104
  > *:first-child {
122
105
  margin-left: ${({ horizontalAlign }) =>
123
- horizontalAlign === 'flex-end' || horizontalAlign === 'center'
124
- ? 'auto'
125
- : undefined};
106
+ horizontalAlign === 'flex-end' || horizontalAlign === 'center' ? 'auto' : undefined};
126
107
  }
127
108
  `}
128
109
 
@@ -168,12 +149,9 @@ const ReqoreControlGroup = memo(
168
149
  const isStack = stack || isInsideStackGroup;
169
150
  const isVertical = vertical || isInsideVerticalGroup;
170
151
 
171
- const [overflowingChildren, setOverflowingChildren] = useState<
172
- number | undefined
173
- >(0);
152
+ const [overflowingChildren, setOverflowingChildren] = useState<number | undefined>(0);
174
153
  const [lastReSize, setLastReSize] = useState<number>(0);
175
- const [isOverflownDialogOpen, setIsOverflownDialogOpen] =
176
- useState<boolean>(false);
154
+ const [isOverflownDialogOpen, setIsOverflownDialogOpen] = useState<boolean>(false);
177
155
  const observer = useRef<ResizeObserver | null>(null);
178
156
  const ref = useRef<HTMLDivElement>(null);
179
157
 
@@ -232,10 +210,7 @@ const ReqoreControlGroup = memo(
232
210
 
233
211
  useEffect(() => {
234
212
  // Is the control group still overflowing?
235
- if (
236
- (overflowingChildren || overflowingChildren === 0) &&
237
- checkIfOverflowing()
238
- ) {
213
+ if ((overflowingChildren || overflowingChildren === 0) && checkIfOverflowing()) {
239
214
  setOverflowingChildren(overflowingChildren + 1);
240
215
  }
241
216
 
@@ -258,33 +233,22 @@ const ReqoreControlGroup = memo(
258
233
  const getIsLastInFirstGroup = (index: number): boolean => {
259
234
  return !isInsideStackGroup
260
235
  ? index === 0
261
- : isFirstGroup &&
262
- (isLast || isLast !== false) &&
263
- index === realChildCount - 1;
236
+ : isFirstGroup && (isLast || isLast !== false) && index === realChildCount - 1;
264
237
  };
265
238
  const getIsFirstInLastGroup = (index: number): boolean => {
266
239
  return !isInsideStackGroup
267
240
  ? index === realChildCount - 1
268
- : isLastGroup &&
269
- (isFirst || isFirst !== false) &&
270
- childId === 1 &&
271
- index === 0;
241
+ : isLastGroup && (isFirst || isFirst !== false) && childId === 1 && index === 0;
272
242
  };
273
243
  const getIsLastInLastGroup = (index: number): boolean => {
274
244
  return !isInsideStackGroup
275
245
  ? index === realChildCount - 1
276
- : isLastGroup &&
277
- (isLast || isLast !== false) &&
278
- index === realChildCount - 1;
246
+ : isLastGroup && (isLast || isLast !== false) && index === realChildCount - 1;
279
247
  };
280
248
 
281
249
  const getBorderTopLeftRadius = (index: number): number | undefined => {
282
250
  const _isFirstGroup =
283
- !isInsideStackGroup || childrenCount === 1
284
- ? true
285
- : isChild
286
- ? isFirstGroup
287
- : index === 0;
251
+ !isInsideStackGroup || childrenCount === 1 ? true : isChild ? isFirstGroup : index === 0;
288
252
 
289
253
  // If this is the first item
290
254
  if (_isFirstGroup && getIsFirst(index)) {
@@ -324,11 +288,7 @@ const ReqoreControlGroup = memo(
324
288
  // If this group is not vertical we need to style the very first item
325
289
  if (!isVertical || !isStack) {
326
290
  const _isFirstGroup =
327
- !isInsideStackGroup || childrenCount === 1
328
- ? true
329
- : isChild
330
- ? isFirstGroup
331
- : index === 0;
291
+ !isInsideStackGroup || childrenCount === 1 ? true : isChild ? isFirstGroup : index === 0;
332
292
 
333
293
  if (_isFirstGroup && getIsFirst(index)) {
334
294
  return RADIUS_FROM_SIZE[size];
@@ -369,7 +329,6 @@ const ReqoreControlGroup = memo(
369
329
  return React.Children.map(children, (child) => {
370
330
  if (child && React.isValidElement(child)) {
371
331
  if (child.type === React.Fragment) {
372
- // just compare to `React.Fragment`
373
332
  return cloneThroughFragments(child.props.children);
374
333
  }
375
334
 
@@ -381,26 +340,12 @@ const ReqoreControlGroup = memo(
381
340
  ? child.props.minimal
382
341
  : minimal,
383
342
  size: child.props?.size || size,
384
- flat:
385
- child.props?.flat || child.props?.flat === false
386
- ? child.props.flat
387
- : flat,
388
- fluid:
389
- child.props?.fluid || child.props?.fluid === false
390
- ? child.props.fluid
391
- : fluid,
392
- fixed:
393
- child.props?.fixed || child.props?.fixed === false
394
- ? child.props.fixed
395
- : fixed,
396
- fill:
397
- child.props?.fill || child.props?.fill === false
398
- ? child.props.fill
399
- : fill,
343
+ flat: child.props?.flat || child.props?.flat === false ? child.props.flat : flat,
344
+ fluid: child.props?.fluid || child.props?.fluid === false ? child.props.fluid : fluid,
345
+ fixed: child.props?.fixed || child.props?.fixed === false ? child.props.fixed : fixed,
346
+ fill: child.props?.fill || child.props?.fill === false ? child.props.fill : fill,
400
347
  stack:
401
- child.props?.stack || child.props?.stack === false
402
- ? child.props.stack
403
- : isStack,
348
+ child.props?.stack || child.props?.stack === false ? child.props.stack : isStack,
404
349
  intent: child.props?.intent || intent,
405
350
  customTheme: child.props?.customTheme || customTheme,
406
351
  };
@@ -428,9 +373,7 @@ const ReqoreControlGroup = memo(
428
373
  childId: index + 1,
429
374
 
430
375
  isFirstGroup: isChild ? isFirstGroup : index === 0,
431
- isLastGroup: isChild
432
- ? isLastGroup
433
- : index === realChildCount - 1,
376
+ isLastGroup: isChild ? isLastGroup : index === realChildCount - 1,
434
377
  };
435
378
  }
436
379
 
@@ -469,9 +412,7 @@ const ReqoreControlGroup = memo(
469
412
  // Get the overflown children
470
413
  const overflownChildren = useMemo(
471
414
  () =>
472
- overflowingChildren
473
- ? React.Children.toArray(children).slice(0, overflowingChildren)
474
- : [],
415
+ overflowingChildren ? React.Children.toArray(children).slice(0, overflowingChildren) : [],
475
416
  [children, overflowingChildren]
476
417
  );
477
418
 
@@ -485,9 +426,7 @@ const ReqoreControlGroup = memo(
485
426
  icon='MenuLine'
486
427
  customTheme={customTheme}
487
428
  tooltip={{
488
- content: `Show ${React.Children.count(
489
- overflownChildren
490
- )} hidden items`,
429
+ content: `Show ${React.Children.count(overflownChildren)} hidden items`,
491
430
  }}
492
431
  fixed
493
432
  active={isOverflownDialogOpen}
@@ -21,6 +21,8 @@ export interface IReqoreIconProps
21
21
  icon?: IReqoreIconName;
22
22
  color?: TReqoreEffectColor;
23
23
  size?: TSizes | string;
24
+ wrapperSize?: TSizes | string;
25
+ wrapperElement?: any;
24
26
  iconProps?: IconBaseProps;
25
27
  margin?: 'right' | 'left' | 'both';
26
28
  image?: string;
@@ -38,8 +40,10 @@ const SpinKeyframes = keyframes`
38
40
  `;
39
41
 
40
42
  export const StyledIconWrapper = styled(StyledEffect)<{ margin: 'right' | 'left' | 'both' }>`
41
- display: inline-block;
43
+ display: inline-flex;
42
44
  flex: 0 0 auto;
45
+ justify-content: center;
46
+ align-items: center;
43
47
  vertical-align: text-bottom;
44
48
  transition: all 0.2s ease-out;
45
49
  overflow: hidden;
@@ -78,6 +82,8 @@ const ReqoreIcon = memo(
78
82
  {
79
83
  icon,
80
84
  size = 'normal',
85
+ wrapperSize,
86
+ wrapperElement,
81
87
  className,
82
88
  color,
83
89
  margin,
@@ -97,6 +103,11 @@ const ReqoreIcon = memo(
97
103
  ? theme.intents[intent]
98
104
  : getColorFromMaybeString(theme, color);
99
105
  const finalSize: string = isStringSize(size) ? ICON_FROM_SIZE[size] : size;
106
+ const finalWrapperSize: string = wrapperSize
107
+ ? isStringSize(wrapperSize)
108
+ ? ICON_FROM_SIZE[wrapperSize]
109
+ : wrapperSize
110
+ : finalSize;
100
111
 
101
112
  useTooltip(targetRef.current, tooltip);
102
113
 
@@ -104,11 +115,12 @@ const ReqoreIcon = memo(
104
115
  return (
105
116
  <StyledIconWrapper
106
117
  {...rest}
118
+ as={wrapperElement}
107
119
  ref={targetRef}
108
120
  size={size}
109
121
  margin={margin}
110
122
  className={`${className || ''} reqore-icon`}
111
- style={{ ...style, width: finalSize, height: finalSize }}
123
+ style={{ width: finalWrapperSize, height: finalWrapperSize, ...style }}
112
124
  >
113
125
  <img src={image} alt='' />
114
126
  </StyledIconWrapper>
@@ -119,11 +131,12 @@ const ReqoreIcon = memo(
119
131
  return (
120
132
  <StyledIconWrapper
121
133
  {...rest}
134
+ as={wrapperElement}
122
135
  ref={targetRef}
123
136
  size={size}
124
137
  margin={margin}
125
138
  className={`${className || ''} reqore-icon`}
126
- style={{ ...style, width: finalSize, height: finalSize }}
139
+ style={{ width: finalWrapperSize, height: finalWrapperSize, ...style }}
127
140
  />
128
141
  );
129
142
  }
@@ -131,10 +144,11 @@ const ReqoreIcon = memo(
131
144
  return (
132
145
  <StyledIconWrapper
133
146
  {...rest}
147
+ as={wrapperElement}
134
148
  ref={targetRef}
135
149
  margin={margin}
136
150
  size={size}
137
- style={{ ...style, width: finalSize, height: finalSize }}
151
+ style={{ width: finalWrapperSize, height: finalWrapperSize, ...style }}
138
152
  className={`${className || ''} reqore-icon`}
139
153
  >
140
154
  <IconContext.Provider
@@ -1,5 +1,5 @@
1
1
  import { rgba } from 'polished';
2
- import React, { forwardRef } from 'react';
2
+ import React, { forwardRef, useRef } from 'react';
3
3
  import styled, { css } from 'styled-components';
4
4
  import {
5
5
  PADDING_FROM_SIZE,
@@ -10,6 +10,7 @@ import {
10
10
  } from '../../constants/sizes';
11
11
  import { IReqoreTheme } from '../../constants/theme';
12
12
  import { changeLightness, getReadableColor } from '../../helpers/colors';
13
+ import { IReqoreAutoFocusRules, useAutoFocus } from '../../hooks/useAutoFocus';
13
14
  import { useCombinedRefs } from '../../hooks/useCombinedRefs';
14
15
  import { useReqoreTheme } from '../../hooks/useTheme';
15
16
  import { useTooltip } from '../../hooks/useTooltip';
@@ -44,11 +45,14 @@ export interface IReqoreInputProps
44
45
  onClearClick?: () => void;
45
46
  maxLength?: number;
46
47
  icon?: IReqoreIconName;
48
+ rightIcon?: IReqoreIconName;
47
49
  flat?: boolean;
48
50
  rounded?: boolean;
49
51
  type?: 'text' | 'password' | 'email' | 'number' | 'tel' | 'url';
50
52
  wrapperStyle?: React.CSSProperties;
51
53
  iconColor?: TReqoreEffectColor;
54
+ rightIconColor?: TReqoreEffectColor;
55
+ focusRules?: IReqoreAutoFocusRules;
52
56
  }
53
57
 
54
58
  export interface IReqoreInputStyle extends IReqoreInputProps {
@@ -76,6 +80,8 @@ const StyledIconWrapper = styled.div<IReqoreInputStyle>`
76
80
  position: absolute;
77
81
  height: ${({ _size }) => SIZE_TO_PX[_size]}px;
78
82
  width: ${({ _size }) => SIZE_TO_PX[_size]}px;
83
+ right: ${({ position }) => (position === 'right' ? 0 : undefined)};
84
+ top: 0;
79
85
  display: flex;
80
86
  justify-content: center;
81
87
  align-items: center;
@@ -87,7 +93,18 @@ export const StyledInput = styled(StyledEffect)<IReqoreInputStyle>`
87
93
  flex: 1;
88
94
  margin: 0;
89
95
  padding: ${({ _size }) => PADDING_FROM_SIZE[_size] / 2}px 7px;
90
- padding-right: ${({ clearable, _size }) => (clearable ? SIZE_TO_PX[_size] : 7)}px;
96
+ padding-right: ${({ clearable, hasRightIcon, _size }) => {
97
+ let padding = 7;
98
+
99
+ if (clearable || hasRightIcon) {
100
+ padding = 0;
101
+ padding += clearable ? SIZE_TO_PX[_size] : 0;
102
+ padding += hasRightIcon ? SIZE_TO_PX[_size] : 0;
103
+ }
104
+
105
+ return padding;
106
+ }}px;
107
+
91
108
  padding-left: ${({ hasIcon, _size }) => (hasIcon ? SIZE_TO_PX[_size] : 7)}px;
92
109
  font-size: ${({ _size }) => TEXT_FROM_SIZE[_size]}px;
93
110
  transition: all 0.2s ease-out;
@@ -154,7 +171,9 @@ const ReqoreInput = forwardRef<HTMLDivElement, IReqoreInputProps>(
154
171
  className,
155
172
  onClearClick,
156
173
  icon,
174
+ rightIcon,
157
175
  iconColor,
176
+ rightIconColor,
158
177
  flat,
159
178
  rounded = true,
160
179
  minimal,
@@ -163,14 +182,21 @@ const ReqoreInput = forwardRef<HTMLDivElement, IReqoreInputProps>(
163
182
  customTheme,
164
183
  intent,
165
184
  wrapperStyle,
185
+ focusRules,
166
186
  ...rest
167
187
  }: IReqoreInputProps,
168
188
  ref
169
189
  ) => {
170
190
  const { targetRef } = useCombinedRefs(ref);
191
+ const inputRef = useRef<HTMLInputElement>(null);
171
192
  const theme = useReqoreTheme('main', customTheme, intent);
172
193
 
173
194
  useTooltip(targetRef.current, tooltip);
195
+ useAutoFocus(
196
+ inputRef.current,
197
+ readOnly || rest.disabled ? undefined : focusRules,
198
+ rest.onChange
199
+ );
174
200
 
175
201
  return (
176
202
  <StyledInputWrapper
@@ -199,23 +225,32 @@ const ReqoreInput = forwardRef<HTMLDivElement, IReqoreInputProps>(
199
225
  interactive: !rest?.disabled && !readOnly,
200
226
  ...rest?.effect,
201
227
  }}
228
+ onChange={!readOnly && !rest?.disabled ? rest?.onChange : undefined}
202
229
  as='input'
230
+ ref={inputRef}
203
231
  theme={theme}
204
232
  _size={size}
205
233
  minimal={minimal}
206
234
  flat={flat}
207
235
  rounded={rounded}
208
236
  hasIcon={!!icon}
209
- clearable={!rest?.disabled && !!(onClearClick && rest?.onChange)}
237
+ hasRightIcon={!!rightIcon}
238
+ clearable={!rest?.disabled && !readOnly && !!(onClearClick && rest?.onChange)}
210
239
  className={`${className || ''} reqore-control reqore-input`}
211
240
  readOnly={readOnly}
212
241
  />
213
242
  <ReqoreInputClearButton
214
243
  enabled={!readOnly && !rest?.disabled && !!(onClearClick && rest?.onChange)}
215
244
  onClick={onClearClick}
245
+ hasRightIcon={!!rightIcon}
216
246
  size={size}
217
247
  show={rest?.value && rest.value !== '' ? true : false}
218
248
  />
249
+ {rightIcon && (
250
+ <StyledIconWrapper _size={size} position='right'>
251
+ <ReqoreIcon size={size} icon={rightIcon} color={rightIconColor} />
252
+ </StyledIconWrapper>
253
+ )}
219
254
  </StyledInputWrapper>
220
255
  );
221
256
  }
@@ -1,16 +1,28 @@
1
+ import { animated, useTransition } from '@react-spring/web';
1
2
  import styled from 'styled-components';
2
- import ReqoreButton, { IReqoreButtonProps } from '../Button';
3
+ import { SPRING_CONFIG } from '../../constants/animations';
4
+ import { SIZE_TO_PX } from '../../constants/sizes';
5
+ import { IReqoreButtonProps } from '../Button';
6
+ import ReqoreIcon from '../Icon';
3
7
 
4
8
  export interface IReqoreInputClearButtonProps extends IReqoreButtonProps {
5
9
  show: boolean;
6
10
  enabled: boolean;
11
+ hasRightIcon?: boolean;
7
12
  }
8
13
 
9
- export const StyledInputClearButton = styled(ReqoreButton)<{ show?: boolean }>`
14
+ export const StyledInputClearButton = styled(ReqoreIcon)<{ show?: boolean }>`
10
15
  position: absolute;
11
- right: ${({ show }) => (show ? 0 : -40)}px;
16
+ right: ${({ size, hasRightIcon }) => (hasRightIcon ? SIZE_TO_PX[size] : 0)}px;
12
17
  top: 0;
13
- opacity: ${({ show }) => (show ? 0.2 : 0)};
18
+ justify-content: center;
19
+ align-items: center;
20
+ transition: all 0.1s ease-out;
21
+ cursor: pointer;
22
+
23
+ &:hover {
24
+ opacity: 1 !important;
25
+ }
14
26
  `;
15
27
 
16
28
  const ReqoreInputClearButton = ({
@@ -18,18 +30,30 @@ const ReqoreInputClearButton = ({
18
30
  enabled,
19
31
  size = 'normal',
20
32
  ...rest
21
- }: IReqoreInputClearButtonProps) =>
22
- enabled ? (
23
- <StyledInputClearButton
24
- {...rest}
25
- className='reqore-clear-input-button'
26
- icon='CloseLine'
27
- minimal
28
- flat
29
- tabIndex={show ? 1 : -1}
30
- size={size}
31
- show={show}
32
- />
33
- ) : null;
33
+ }: IReqoreInputClearButtonProps) => {
34
+ const transitions = useTransition(show && enabled, {
35
+ from: { opacity: 0, filter: 'blur(10px)' },
36
+ enter: { opacity: 0.5, filter: 'blur(0px)' },
37
+ leave: { opacity: 0, filter: 'blur(10px)' },
38
+ config: SPRING_CONFIG,
39
+ });
40
+
41
+ return transitions((styles, item) =>
42
+ item ? (
43
+ <StyledInputClearButton
44
+ {...rest}
45
+ className='reqore-clear-input-button'
46
+ icon='CloseLine'
47
+ wrapperElement={animated.span}
48
+ size={size}
49
+ wrapperSize={SIZE_TO_PX[size]}
50
+ show={show}
51
+ style={{
52
+ opacity: styles.opacity,
53
+ }}
54
+ />
55
+ ) : null
56
+ );
57
+ };
34
58
 
35
59
  export default ReqoreInputClearButton;
@@ -1,6 +1,6 @@
1
1
  import { size } from 'lodash';
2
2
  import { darken, rgba } from 'polished';
3
- import { ReactElement, forwardRef, useCallback, useMemo, useState } from 'react';
3
+ import { forwardRef, ReactElement, useCallback, useMemo, useState } from 'react';
4
4
  import { useUpdateEffect } from 'react-use';
5
5
  import styled, { css } from 'styled-components';
6
6
  import {
@@ -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';
@@ -186,6 +187,7 @@ export const StyledPanel = styled(StyledEffect)<IStyledPanel>`
186
187
 
187
188
  export const StyledPanelTitle = styled.div<IStyledPanel>`
188
189
  display: flex;
190
+ flex-flow: ${({ isMobile }) => (isMobile ? 'column' : 'row')};
189
191
  background-color: ${({ theme, opacity = 1 }: IStyledPanel) =>
190
192
  rgba(changeLightness(getMainBackgroundColor(theme), 0.03), opacity)};
191
193
  justify-content: space-between;
@@ -306,6 +308,7 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
306
308
  ? { main: Object.values(contentEffect.gradient.colors)[0] as TReqoreEffectColor }
307
309
  : undefined)
308
310
  );
311
+ const { isMobile } = useReqore();
309
312
  const { targetRef } = useCombinedRefs(ref);
310
313
 
311
314
  useTooltip(targetRef.current, tooltip);
@@ -418,8 +421,8 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
418
421
  stack
419
422
  customTheme={rest.customTheme || theme}
420
423
  size={rest.size}
421
- fixed
422
- fluid={rest.fluid}
424
+ fixed={rest.fixed ? true : false}
425
+ fluid={rest.fluid ? true : false}
423
426
  key={index}
424
427
  >
425
428
  {group.map((action, index) => renderActions(action, index, true))}
@@ -430,9 +433,9 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
430
433
  if (size(actions)) {
431
434
  return (
432
435
  <ReqoreDropdown<IReqoreButtonProps>
436
+ fixed
433
437
  {...rest}
434
438
  key={index}
435
- fixed
436
439
  label={label}
437
440
  items={actions}
438
441
  intent={intent}
@@ -449,7 +452,8 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
449
452
  <CustomElement
450
453
  fixed
451
454
  {...props}
452
- key={index}
455
+ key={props.key || index}
456
+ reactKey={props.key || index}
453
457
  customTheme={props.customTheme || theme}
454
458
  onClick={(e: React.MouseEvent<any>) => {
455
459
  e.stopPropagation();
@@ -461,9 +465,9 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
461
465
 
462
466
  return (
463
467
  <ReqoreButton
468
+ fixed
464
469
  {...rest}
465
470
  id={id}
466
- fixed
467
471
  key={index}
468
472
  className={className}
469
473
  customTheme={rest.customTheme || theme}
@@ -536,6 +540,7 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
536
540
  size={contentSize || panelSize}
537
541
  opacity={opacity ?? (minimal ? 0 : 1)}
538
542
  noHorizontalPadding={noHorizontalPadding}
543
+ isMobile={isMobile}
539
544
  >
540
545
  {hasTitleHeader && (
541
546
  <StyledPanelTitleHeader>
@@ -579,7 +584,7 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
579
584
  {hasResponsiveActions(actions) && (
580
585
  <ReqoreControlGroup
581
586
  responsive={responsiveActions}
582
- fluid={responsiveActions}
587
+ fluid={responsiveActions || isMobile}
583
588
  horizontalAlign='flex-end'
584
589
  customTheme={theme}
585
590
  size={panelSize}
@@ -589,7 +594,12 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
589
594
  )}
590
595
  {collapsible || onClose || hasNonResponsiveActions(actions) ? (
591
596
  <>
592
- <ReqoreControlGroup fixed horizontalAlign='flex-end' size={panelSize}>
597
+ <ReqoreControlGroup
598
+ fixed={!isMobile}
599
+ fluid={isMobile}
600
+ horizontalAlign='flex-end'
601
+ size={panelSize}
602
+ >
593
603
  {actions.map(renderNonResponsiveActions)}
594
604
  {collapsible && (
595
605
  <ReqoreButton
@@ -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
  }