@qoretechnologies/reqore 0.31.2 → 0.32.2

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 (183) hide show
  1. package/.github/workflows/tests.yml +3 -1
  2. package/__tests__/breadcrumbs.test.tsx +46 -28
  3. package/__tests__/button.test.tsx +18 -0
  4. package/__tests__/checkbox.test.tsx +19 -1
  5. package/__tests__/collection.test.tsx +14 -1
  6. package/__tests__/icon.test.tsx +19 -1
  7. package/__tests__/input.test.tsx +435 -24
  8. package/__tests__/messages.test.tsx +16 -0
  9. package/__tests__/modal.test.tsx +4 -4
  10. package/__tests__/multiselect.test.tsx +8 -10
  11. package/__tests__/notifications.test.tsx +6 -6
  12. package/__tests__/panel.test.tsx +19 -1
  13. package/__tests__/textarea.test.tsx +423 -24
  14. package/__tests__/tree.test.tsx +3 -1
  15. package/dist/components/Breadcrumbs/item.d.ts.map +1 -1
  16. package/dist/components/Breadcrumbs/item.js +6 -2
  17. package/dist/components/Breadcrumbs/item.js.map +1 -1
  18. package/dist/components/Button/index.d.ts.map +1 -1
  19. package/dist/components/Button/index.js +18 -4
  20. package/dist/components/Button/index.js.map +1 -1
  21. package/dist/components/Checkbox/index.d.ts.map +1 -1
  22. package/dist/components/Checkbox/index.js +8 -4
  23. package/dist/components/Checkbox/index.js.map +1 -1
  24. package/dist/components/Collection/index.d.ts +4 -2
  25. package/dist/components/Collection/index.d.ts.map +1 -1
  26. package/dist/components/Collection/index.js +19 -13
  27. package/dist/components/Collection/index.js.map +1 -1
  28. package/dist/components/Collection/item.js +2 -2
  29. package/dist/components/Collection/item.js.map +1 -1
  30. package/dist/components/Comment/index.d.ts +0 -1
  31. package/dist/components/Comment/index.d.ts.map +1 -1
  32. package/dist/components/ControlGroup/index.d.ts.map +1 -1
  33. package/dist/components/ControlGroup/index.js +18 -57
  34. package/dist/components/ControlGroup/index.js.map +1 -1
  35. package/dist/components/Drawer/index.d.ts +1 -1
  36. package/dist/components/Drawer/index.d.ts.map +1 -1
  37. package/dist/components/Drawer/index.js +1 -1
  38. package/dist/components/Drawer/index.js.map +1 -1
  39. package/dist/components/Dropdown/item.d.ts +0 -1
  40. package/dist/components/Dropdown/item.d.ts.map +1 -1
  41. package/dist/components/Icon/index.d.ts +2 -0
  42. package/dist/components/Icon/index.d.ts.map +1 -1
  43. package/dist/components/Icon/index.js +17 -8
  44. package/dist/components/Icon/index.js.map +1 -1
  45. package/dist/components/Input/index.d.ts +4 -0
  46. package/dist/components/Input/index.d.ts.map +1 -1
  47. package/dist/components/Input/index.js +19 -7
  48. package/dist/components/Input/index.js.map +1 -1
  49. package/dist/components/InputClearButton/index.d.ts +1 -1
  50. package/dist/components/InputClearButton/index.d.ts.map +1 -1
  51. package/dist/components/InputClearButton/index.js +18 -8
  52. package/dist/components/InputClearButton/index.js.map +1 -1
  53. package/dist/components/InternalPopover/index.d.ts.map +1 -1
  54. package/dist/components/InternalPopover/index.js +2 -1
  55. package/dist/components/InternalPopover/index.js.map +1 -1
  56. package/dist/components/Menu/item.d.ts +1 -1
  57. package/dist/components/Menu/item.d.ts.map +1 -1
  58. package/dist/components/Menu/item.js +3 -6
  59. package/dist/components/Menu/item.js.map +1 -1
  60. package/dist/components/Message/index.d.ts.map +1 -1
  61. package/dist/components/Message/index.js +6 -2
  62. package/dist/components/Message/index.js.map +1 -1
  63. package/dist/components/Modal/index.d.ts +0 -1
  64. package/dist/components/Modal/index.d.ts.map +1 -1
  65. package/dist/components/Panel/index.d.ts +1 -0
  66. package/dist/components/Panel/index.d.ts.map +1 -1
  67. package/dist/components/Panel/index.js +18 -9
  68. package/dist/components/Panel/index.js.map +1 -1
  69. package/dist/components/Panel/panel.screenshot.d.ts +0 -1
  70. package/dist/components/Panel/panel.screenshot.d.ts.map +1 -1
  71. package/dist/components/Sidebar/item.d.ts +0 -1
  72. package/dist/components/Sidebar/item.d.ts.map +1 -1
  73. package/dist/components/Sidebar/item.js +1 -3
  74. package/dist/components/Sidebar/item.js.map +1 -1
  75. package/dist/components/Spinner/index.d.ts +0 -1
  76. package/dist/components/Spinner/index.d.ts.map +1 -1
  77. package/dist/components/Table/header.d.ts +0 -1
  78. package/dist/components/Table/header.d.ts.map +1 -1
  79. package/dist/components/Tag/index.d.ts.map +1 -1
  80. package/dist/components/Tag/index.js +7 -4
  81. package/dist/components/Tag/index.js.map +1 -1
  82. package/dist/components/Textarea/index.d.ts +2 -0
  83. package/dist/components/Textarea/index.d.ts.map +1 -1
  84. package/dist/components/Textarea/index.js +9 -6
  85. package/dist/components/Textarea/index.js.map +1 -1
  86. package/dist/components/Tree/index.d.ts +0 -1
  87. package/dist/components/Tree/index.d.ts.map +1 -1
  88. package/dist/components/Tree/index.js +2 -4
  89. package/dist/components/Tree/index.js.map +1 -1
  90. package/dist/containers/PopoverProvider.d.ts.map +1 -1
  91. package/dist/containers/PopoverProvider.js +2 -2
  92. package/dist/containers/PopoverProvider.js.map +1 -1
  93. package/dist/containers/ReqoreProvider.d.ts.map +1 -1
  94. package/dist/containers/ReqoreProvider.js +4 -0
  95. package/dist/containers/ReqoreProvider.js.map +1 -1
  96. package/dist/containers/ThemeProvider.d.ts +1 -2
  97. package/dist/containers/ThemeProvider.d.ts.map +1 -1
  98. package/dist/containers/ThemeProvider.js +3 -3
  99. package/dist/containers/ThemeProvider.js.map +1 -1
  100. package/dist/context/PopoverContext.d.ts +1 -2
  101. package/dist/context/PopoverContext.d.ts.map +1 -1
  102. package/dist/context/PopoverContext.js +2 -2
  103. package/dist/context/PopoverContext.js.map +1 -1
  104. package/dist/context/ReqoreContext.d.ts +3 -2
  105. package/dist/context/ReqoreContext.d.ts.map +1 -1
  106. package/dist/context/ReqoreContext.js +5 -3
  107. package/dist/context/ReqoreContext.js.map +1 -1
  108. package/dist/context/ThemeContext.d.ts +1 -2
  109. package/dist/context/ThemeContext.d.ts.map +1 -1
  110. package/dist/context/ThemeContext.js +2 -2
  111. package/dist/context/ThemeContext.js.map +1 -1
  112. package/dist/hooks/useAutoFocus.d.ts +11 -0
  113. package/dist/hooks/useAutoFocus.d.ts.map +1 -0
  114. package/dist/hooks/useAutoFocus.js +80 -0
  115. package/dist/hooks/useAutoFocus.js.map +1 -0
  116. package/dist/hooks/useLatestZIndex.d.ts.map +1 -1
  117. package/dist/hooks/useLatestZIndex.js +3 -2
  118. package/dist/hooks/useLatestZIndex.js.map +1 -1
  119. package/dist/hooks/usePopover.d.ts +0 -1
  120. package/dist/hooks/usePopover.d.ts.map +1 -1
  121. package/dist/hooks/usePopover.js +4 -3
  122. package/dist/hooks/usePopover.js.map +1 -1
  123. package/dist/hooks/useReqore.js +2 -2
  124. package/dist/hooks/useReqore.js.map +1 -1
  125. package/dist/hooks/useReqoreContext.d.ts +3 -0
  126. package/dist/hooks/useReqoreContext.d.ts.map +1 -0
  127. package/dist/hooks/useReqoreContext.js +19 -0
  128. package/dist/hooks/useReqoreContext.js.map +1 -0
  129. package/dist/hooks/useReqoreEffect.js +2 -5
  130. package/dist/hooks/useReqoreEffect.js.map +1 -1
  131. package/dist/hooks/useTheme.d.ts.map +1 -1
  132. package/dist/hooks/useTheme.js +20 -20
  133. package/dist/hooks/useTheme.js.map +1 -1
  134. package/dist/index.d.ts +1 -0
  135. package/dist/index.d.ts.map +1 -1
  136. package/dist/index.js +3 -1
  137. package/dist/index.js.map +1 -1
  138. package/dist/styles.d.ts.map +1 -1
  139. package/dist/styles.js +1 -1
  140. package/dist/styles.js.map +1 -1
  141. package/package.json +20 -16
  142. package/src/components/Breadcrumbs/item.tsx +7 -3
  143. package/src/components/Button/index.tsx +26 -7
  144. package/src/components/Checkbox/index.tsx +9 -5
  145. package/src/components/Collection/index.tsx +33 -11
  146. package/src/components/Collection/item.tsx +3 -3
  147. package/src/components/ControlGroup/index.tsx +26 -87
  148. package/src/components/Drawer/index.tsx +4 -4
  149. package/src/components/Icon/index.tsx +27 -9
  150. package/src/components/Input/index.tsx +35 -4
  151. package/src/components/InputClearButton/index.tsx +41 -17
  152. package/src/components/InternalPopover/index.tsx +2 -1
  153. package/src/components/Menu/item.tsx +6 -9
  154. package/src/components/Message/index.tsx +6 -2
  155. package/src/components/Panel/index.tsx +26 -9
  156. package/src/components/Sidebar/item.tsx +2 -4
  157. package/src/components/Tag/index.tsx +9 -6
  158. package/src/components/Textarea/index.tsx +16 -11
  159. package/src/components/Tree/index.tsx +5 -8
  160. package/src/containers/PopoverProvider.tsx +2 -2
  161. package/src/containers/ReqoreProvider.tsx +5 -1
  162. package/src/containers/ThemeProvider.tsx +3 -13
  163. package/src/context/PopoverContext.tsx +1 -1
  164. package/src/context/ReqoreContext.tsx +4 -1
  165. package/src/context/ThemeContext.tsx +1 -1
  166. package/src/hooks/useAutoFocus.ts +104 -0
  167. package/src/hooks/useLatestZIndex.ts +5 -3
  168. package/src/hooks/usePopover.tsx +4 -3
  169. package/src/hooks/useReqore.ts +1 -1
  170. package/src/hooks/useReqoreContext.ts +16 -0
  171. package/src/hooks/useReqoreEffect.ts +3 -3
  172. package/src/hooks/useTheme.ts +21 -17
  173. package/src/index.tsx +1 -0
  174. package/src/stories/Button/Button.stories.tsx +7 -0
  175. package/src/stories/Collection/Collection.stories.tsx +56 -9
  176. package/src/stories/Drawer/Drawer.stories.tsx +4 -3
  177. package/src/stories/Input/Input.stories.tsx +29 -6
  178. package/src/stories/Modal/Modal.stories.tsx +3 -4
  179. package/src/stories/Notifications/Interactive.stories.tsx +3 -4
  180. package/src/stories/Panel/Panel.stories.tsx +4 -2
  181. package/src/stories/TextArea/TextArea.stories.tsx +1 -0
  182. package/src/styles.ts +0 -1
  183. package/tests.json +1 -1
@@ -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 { useReqoreProperty } from '../../hooks/useReqoreContext';
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';
@@ -101,6 +102,7 @@ export interface IReqorePanelProps
101
102
  transparent?: boolean;
102
103
  iconColor?: TReqoreEffectColor;
103
104
  responsiveActions?: boolean;
105
+ responsiveTitle?: boolean;
104
106
  }
105
107
 
106
108
  export interface IStyledPanel extends IReqorePanelProps {
@@ -186,6 +188,7 @@ export const StyledPanel = styled(StyledEffect)<IStyledPanel>`
186
188
 
187
189
  export const StyledPanelTitle = styled.div<IStyledPanel>`
188
190
  display: flex;
191
+ flex-flow: ${({ responsive, isMobile }) => (responsive ? (isMobile ? 'column' : 'row') : 'row')};
189
192
  background-color: ${({ theme, opacity = 1 }: IStyledPanel) =>
190
193
  rgba(changeLightness(getMainBackgroundColor(theme), 0.03), opacity)};
191
194
  justify-content: space-between;
@@ -293,6 +296,7 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
293
296
  iconProps = {},
294
297
  fluid,
295
298
  responsiveActions = true,
299
+ responsiveTitle = true,
296
300
  size: panelSize = 'normal',
297
301
  ...rest
298
302
  }: IReqorePanelProps,
@@ -306,9 +310,11 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
306
310
  ? { main: Object.values(contentEffect.gradient.colors)[0] as TReqoreEffectColor }
307
311
  : undefined)
308
312
  );
313
+ const isMobile = useReqoreProperty('isMobile');
309
314
  const { targetRef } = useCombinedRefs(ref);
315
+ const [itemRef, setItemRef] = useState<HTMLDivElement>(undefined);
310
316
 
311
- useTooltip(targetRef.current, tooltip);
317
+ useTooltip(itemRef, tooltip);
312
318
 
313
319
  useUpdateEffect(() => {
314
320
  setIsCollapsed(!!isCollapsed);
@@ -418,7 +424,7 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
418
424
  stack
419
425
  customTheme={rest.customTheme || theme}
420
426
  size={rest.size}
421
- fixed
427
+ fixed={rest.fixed}
422
428
  fluid={rest.fluid}
423
429
  key={index}
424
430
  >
@@ -430,9 +436,9 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
430
436
  if (size(actions)) {
431
437
  return (
432
438
  <ReqoreDropdown<IReqoreButtonProps>
439
+ fixed
433
440
  {...rest}
434
441
  key={index}
435
- fixed
436
442
  label={label}
437
443
  items={actions}
438
444
  intent={intent}
@@ -449,7 +455,8 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
449
455
  <CustomElement
450
456
  fixed
451
457
  {...props}
452
- key={index}
458
+ key={props.key || index}
459
+ reactKey={props.key || index}
453
460
  customTheme={props.customTheme || theme}
454
461
  onClick={(e: React.MouseEvent<any>) => {
455
462
  e.stopPropagation();
@@ -461,9 +468,9 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
461
468
 
462
469
  return (
463
470
  <ReqoreButton
471
+ fixed
464
472
  {...rest}
465
473
  id={id}
466
- fixed
467
474
  key={index}
468
475
  className={className}
469
476
  customTheme={rest.customTheme || theme}
@@ -513,7 +520,10 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
513
520
  <StyledPanel
514
521
  {...rest}
515
522
  as={rest.as || 'div'}
516
- ref={targetRef}
523
+ ref={(ref) => {
524
+ targetRef.current = ref;
525
+ setItemRef(ref);
526
+ }}
517
527
  isCollapsed={_isCollapsed}
518
528
  rounded={rounded}
519
529
  flat={flat}
@@ -536,6 +546,8 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
536
546
  size={contentSize || panelSize}
537
547
  opacity={opacity ?? (minimal ? 0 : 1)}
538
548
  noHorizontalPadding={noHorizontalPadding}
549
+ responsive={responsiveTitle}
550
+ isMobile={isMobile}
539
551
  >
540
552
  {hasTitleHeader && (
541
553
  <StyledPanelTitleHeader>
@@ -579,7 +591,7 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
579
591
  {hasResponsiveActions(actions) && (
580
592
  <ReqoreControlGroup
581
593
  responsive={responsiveActions}
582
- fluid={responsiveActions}
594
+ fluid={responsiveActions || isMobile}
583
595
  horizontalAlign='flex-end'
584
596
  customTheme={theme}
585
597
  size={panelSize}
@@ -589,7 +601,12 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
589
601
  )}
590
602
  {collapsible || onClose || hasNonResponsiveActions(actions) ? (
591
603
  <>
592
- <ReqoreControlGroup fixed horizontalAlign='flex-end' size={panelSize}>
604
+ <ReqoreControlGroup
605
+ fixed={!isMobile}
606
+ fluid={isMobile}
607
+ horizontalAlign='flex-end'
608
+ size={panelSize}
609
+ >
593
610
  {actions.map(renderNonResponsiveActions)}
594
611
  {collapsible && (
595
612
  <ReqoreButton
@@ -1,11 +1,9 @@
1
1
  import classnames from 'classnames';
2
2
  import map from 'lodash/map';
3
- import { useContext } from 'react';
4
3
  import { useMount } from 'react-use';
5
4
  import { IQorusSidebarItem } from '.';
6
- import { ReqorePopover } from '../..';
5
+ import { ReqorePopover, useReqoreTheme } from '../..';
7
6
  import { IReqoreTheme } from '../../constants/theme';
8
- import ThemeContext from '../../context/ThemeContext';
9
7
  import { getMainColor, getReadableColor } from '../../helpers/colors';
10
8
  import { isActiveMulti } from '../../helpers/sidebar';
11
9
  import ReqoreIcon from '../Icon';
@@ -202,7 +200,7 @@ const SidebarItemWrapper = ({
202
200
  useNativeTitle,
203
201
  onClick,
204
202
  }: SidebarItemProps) => {
205
- const theme: IReqoreTheme = useContext(ThemeContext);
203
+ const theme: IReqoreTheme = useReqoreTheme();
206
204
 
207
205
  useMount(() => {
208
206
  if (
@@ -1,8 +1,8 @@
1
1
  import _size from 'lodash/size';
2
2
  import { rgba } from 'polished';
3
- import React, { forwardRef, useContext } from 'react';
3
+ import React, { forwardRef, useState } from 'react';
4
4
  import styled, { css } from 'styled-components';
5
- import { ReqorePopover } from '../..';
5
+ import { ReqorePopover, useReqoreTheme } from '../..';
6
6
  import {
7
7
  BADGE_SIZE_TO_PX,
8
8
  PADDING_FROM_SIZE,
@@ -12,7 +12,6 @@ import {
12
12
  TSizes,
13
13
  } from '../../constants/sizes';
14
14
  import { IReqoreTheme, TReqoreIntent } from '../../constants/theme';
15
- import ThemeContext from '../../context/ThemeContext';
16
15
  import {
17
16
  changeLightness,
18
17
  getColorFromMaybeString,
@@ -264,9 +263,10 @@ const ReqoreTag = forwardRef<HTMLSpanElement, IReqoreTagProps>(
264
263
  ref
265
264
  ) => {
266
265
  const { targetRef } = useCombinedRefs(ref);
267
- const theme: IReqoreTheme = useContext<IReqoreTheme>(ThemeContext);
266
+ const theme: IReqoreTheme = useReqoreTheme();
267
+ const [itemRef, setItemRef] = useState<HTMLDivElement>(undefined);
268
268
 
269
- useTooltip(targetRef.current, tooltip);
269
+ useTooltip(itemRef, tooltip);
270
270
 
271
271
  // If color or intent was specified, set the color
272
272
  const getCustomColor = (itemIntent?: TReqoreIntent): TReqoreHexColor => {
@@ -292,7 +292,10 @@ const ReqoreTag = forwardRef<HTMLSpanElement, IReqoreTagProps>(
292
292
  color={getCustomColor(intent)}
293
293
  className={`${className || ''} reqore-tag`}
294
294
  size={size}
295
- ref={targetRef}
295
+ ref={(ref) => {
296
+ targetRef.current = ref;
297
+ setItemRef(ref);
298
+ }}
296
299
  asBadge={asBadge}
297
300
  minimal={minimal}
298
301
  removable={!!onRemoveClick}
@@ -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,11 +140,13 @@ 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
144
147
  ) => {
145
148
  const { targetRef }: any = useCombinedRefs(ref);
149
+ const [inputRef, setInputRef] = useState<HTMLTextAreaElement>(null);
146
150
  const theme = useReqoreTheme('main', customTheme, intent);
147
151
  const [_value, setValue] = useState(value || '');
148
152
 
@@ -150,8 +154,9 @@ const ReqoreInput = forwardRef<HTMLTextAreaElement, IReqoreTextareaProps>(
150
154
  setValue(value || '');
151
155
  }, [value]);
152
156
 
153
- useTooltip(targetRef?.current, tooltip);
154
- useAutosizeTextArea(targetRef?.current, _value, scaleWithContent);
157
+ useTooltip(inputRef, tooltip);
158
+ useAutosizeTextArea(inputRef, _value, scaleWithContent);
159
+ useAutoFocus(inputRef, rest.readOnly || rest.disabled ? undefined : focusRules, onChange);
155
160
 
156
161
  return (
157
162
  <StyledTextareaWrapper
@@ -163,6 +168,7 @@ const ReqoreInput = forwardRef<HTMLTextAreaElement, IReqoreTextareaProps>(
163
168
  _size={size}
164
169
  theme={theme}
165
170
  style={wrapperStyle}
171
+ ref={targetRef}
166
172
  >
167
173
  <StyledTextarea
168
174
  {...rest}
@@ -177,20 +183,19 @@ const ReqoreInput = forwardRef<HTMLTextAreaElement, IReqoreTextareaProps>(
177
183
  as='textarea'
178
184
  className={`${className || ''} reqore-control reqore-textarea`}
179
185
  _size={size}
180
- ref={targetRef}
186
+ ref={(ref) => setInputRef(ref)}
181
187
  theme={theme}
182
188
  rounded={rounded}
183
189
  rows={1}
184
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}
185
198
  />
186
- {!rest.readOnly && (
187
- <ReqoreInputClearButton
188
- enabled={!rest?.disabled && !!(onClearClick && onChange)}
189
- show={_value && _value !== ''}
190
- onClick={onClearClick}
191
- size={size}
192
- />
193
- )}
194
199
  </StyledTextareaWrapper>
195
200
  );
196
201
  }
@@ -1,10 +1,9 @@
1
1
  import { cloneDeep, size as lodashSize } from 'lodash';
2
- import { useContext, useState } from 'react';
2
+ import { useState } from 'react';
3
3
  import styled from 'styled-components';
4
- import { ReqoreMessage, ReqorePanel, ReqoreTextarea } from '../..';
4
+ import { ReqoreMessage, ReqorePanel, ReqoreTextarea, useReqoreProperty } from '../..';
5
5
  import { IReqoreTheme } from '../../constants/theme';
6
- import ReqoreContext from '../../context/ReqoreContext';
7
- import { getLineCount, getTypeFromValue } from '../../helpers/utils';
6
+ import { getTypeFromValue } from '../../helpers/utils';
8
7
  import { IWithReqoreSize } from '../../types/global';
9
8
  import ReqoreButton from '../Button';
10
9
  import ReqoreControlGroup from '../ControlGroup';
@@ -45,7 +44,7 @@ export const ReqoreTree = ({
45
44
  const [items, setItems] = useState({});
46
45
  const [allExpanded, setAllExpanded] = useState(expanded || !showControls);
47
46
  const [_showTypes, setShowTypes] = useState(showTypes);
48
- const { addNotification } = useContext(ReqoreContext);
47
+ const addNotification = useReqoreProperty('addNotification');
49
48
 
50
49
  const handleCopyClick = () => {
51
50
  setMode('copy');
@@ -173,7 +172,6 @@ export const ReqoreTree = ({
173
172
  }
174
173
 
175
174
  const textData: string = renderText(data);
176
- const lineCount: number = getLineCount(textData);
177
175
 
178
176
  return (
179
177
  <ReqorePanel
@@ -224,12 +222,11 @@ export const ReqoreTree = ({
224
222
  <ReqoreTextarea
225
223
  className='reqore-tree-textarea'
226
224
  id='tree-content'
227
- defaultValue={textData}
225
+ value={textData}
228
226
  scaleWithContent
229
227
  size={size}
230
228
  fluid
231
229
  readOnly
232
- rows={lineCount > 20 ? 20 : lineCount}
233
230
  />
234
231
  )}
235
232
  </ReqorePanel>
@@ -1,9 +1,9 @@
1
1
  import { size } from 'lodash';
2
2
  import React, { MutableRefObject, useCallback, useEffect, useState } from 'react';
3
+ import { useReqoreProperty } from '..';
3
4
  import Popover from '../components/InternalPopover';
4
5
  import PopoverContext from '../context/PopoverContext';
5
6
  import { IPopoverOptions } from '../hooks/usePopover';
6
- import { useReqore } from '../hooks/useReqore';
7
7
 
8
8
  export interface IReqorePopoverProviderProps {
9
9
  children: any;
@@ -17,7 +17,7 @@ export interface IPopoverData extends IPopoverOptions {
17
17
 
18
18
  const PopoverProvider: React.FC<IReqorePopoverProviderProps> = ({ children, uiScale }) => {
19
19
  const [popovers, setPopovers] = useState<IPopoverData[]>([]);
20
- const { closePopoversOnEscPress } = useReqore();
20
+ const closePopoversOnEscPress = useReqoreProperty('closePopoversOnEscPress');
21
21
 
22
22
  const handleClick = useCallback(
23
23
  (event: MouseEvent) => {
@@ -2,14 +2,16 @@ import { size } from 'lodash';
2
2
  import React, { useRef, useState } from 'react';
3
3
  import { useMedia } from 'react-use';
4
4
  import shortid from 'shortid';
5
+ import { useContext } from 'use-context-selector';
5
6
  import { ReqoreModal, ReqoreTextEffect } from '..';
6
7
  import ReqoreNotificationsWrapper from '../components/Notifications';
7
8
  import ReqoreNotification, {
8
9
  IReqoreNotificationType,
9
10
  } from '../components/Notifications/notification';
10
11
  import { TSizes } from '../constants/sizes';
11
- import { TReqoreIntent } from '../constants/theme';
12
+ import { IReqoreTheme, TReqoreIntent } from '../constants/theme';
12
13
  import ReqoreContext from '../context/ReqoreContext';
14
+ import ThemeContext from '../context/ThemeContext';
13
15
  import { IReqoreIconName } from '../types/icons';
14
16
  import { IReqoreOptions } from './UIProvider';
15
17
 
@@ -50,6 +52,7 @@ export interface IReqoreConfirmationModal {
50
52
  const ReqoreProvider: React.FC<IReqoreNotifications> = ({ children, options = {} }) => {
51
53
  const [notifications, setNotifications] = useState<IReqoreNotificationData[] | null>([]);
52
54
  const [confirmationModal, setConfirmationModal] = useState<IReqoreConfirmationModal>({});
55
+ const theme: IReqoreTheme = useContext<IReqoreTheme>(ThemeContext);
53
56
  const latestZIndex = useRef<number>(9000);
54
57
 
55
58
  const isMobile = process.env.NODE_ENV === 'test' ? false : useMedia('(max-width: 480px)');
@@ -114,6 +117,7 @@ const ReqoreProvider: React.FC<IReqoreNotifications> = ({ children, options = {}
114
117
  <ReqoreContext.Provider
115
118
  value={{
116
119
  notifications,
120
+ theme,
117
121
  addNotification,
118
122
  removeNotification,
119
123
  confirmAction,
@@ -1,22 +1,12 @@
1
- import { useContext } from 'react';
2
1
  import { ThemeProvider } from 'styled-components';
2
+ import { useContext } from 'use-context-selector';
3
3
  import { IReqoreTheme } from '../constants/theme';
4
4
  import ThemeContext from '../context/ThemeContext';
5
5
 
6
- const ReqoreThemeProvider = ({
7
- children,
8
- theme,
9
- }: {
10
- children: any;
11
- theme?: IReqoreTheme;
12
- }) => {
6
+ const ReqoreThemeProvider = ({ children, theme }: { children: any; theme?: IReqoreTheme }) => {
13
7
  const _theme: IReqoreTheme = useContext(ThemeContext);
14
8
 
15
- return (
16
- <ThemeProvider theme={theme || _theme}>
17
- <>{children}</>
18
- </ThemeProvider>
19
- );
9
+ return <ThemeProvider theme={theme || _theme}>{children}</ThemeProvider>;
20
10
  };
21
11
 
22
12
  export default ReqoreThemeProvider;
@@ -1,4 +1,4 @@
1
- import { createContext } from 'react';
1
+ import { createContext } from 'use-context-selector';
2
2
  import { IPopoverData } from '../containers/PopoverProvider';
3
3
 
4
4
  export default createContext<{
@@ -1,4 +1,5 @@
1
- import { createContext } from 'react';
1
+ import { createContext } from 'use-context-selector';
2
+ import { DEFAULT_THEME, IReqoreTheme } from '../constants/theme';
2
3
  import { IReqoreConfirmationModal, IReqoreNotificationData } from '../containers/ReqoreProvider';
3
4
  import { IReqoreOptions } from '../containers/UIProvider';
4
5
 
@@ -15,6 +16,7 @@ export interface IReqoreContext {
15
16
  readonly tooltips?: IReqoreOptions['tooltips'];
16
17
  readonly closePopoversOnEscPress?: boolean;
17
18
  readonly latestZIndex?: number;
19
+ theme: IReqoreTheme;
18
20
  }
19
21
 
20
22
  export default createContext<IReqoreContext>({
@@ -27,4 +29,5 @@ export default createContext<IReqoreContext>({
27
29
  dialogs: true,
28
30
  },
29
31
  closePopoversOnEscPress: true,
32
+ theme: DEFAULT_THEME,
30
33
  });
@@ -1,4 +1,4 @@
1
- import { createContext } from 'react';
1
+ import { createContext } from 'use-context-selector';
2
2
  import { DEFAULT_THEME, IReqoreTheme } from '../constants/theme';
3
3
 
4
4
  export default createContext<IReqoreTheme>(DEFAULT_THEME);
@@ -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
+ };
@@ -1,8 +1,10 @@
1
- import { useContext, useMemo } from 'react';
2
- import { ReqoreContext } from '..';
1
+ import { useMemo } from 'react';
2
+ import { useReqoreProperty } from './useReqoreContext';
3
3
 
4
4
  const useLatestZIndex = (): number => {
5
- const { getAndIncreaseZIndex, latestZIndex } = useContext(ReqoreContext);
5
+ const getAndIncreaseZIndex = useReqoreProperty('getAndIncreaseZIndex');
6
+ const latestZIndex = useReqoreProperty('latestZIndex');
7
+
6
8
  const zIndex = useMemo(() => getAndIncreaseZIndex(), [latestZIndex]);
7
9
 
8
10
  return zIndex;
@@ -1,7 +1,9 @@
1
1
  import { Placement } from '@popperjs/core';
2
- import { MutableRefObject, useContext, useEffect, useMemo, useRef } from 'react';
2
+ import { MutableRefObject, useEffect, useMemo, useRef } from 'react';
3
3
  import { useUnmount, useUpdateEffect } from 'react-use';
4
4
  import shortid from 'shortid';
5
+ import { useContext } from 'use-context-selector';
6
+ import { useReqoreProperty } from '..';
5
7
  import { IPopoverData } from '../containers/PopoverProvider';
6
8
  import PopoverContext from '../context/PopoverContext';
7
9
  import {
@@ -11,7 +13,6 @@ import {
11
13
  IWithReqoreMinimal,
12
14
  } from '../types/global';
13
15
  import { IReqoreIconName } from '../types/icons';
14
- import { useReqore } from './useReqore';
15
16
 
16
17
  const startEvents = {
17
18
  hover: 'mouseenter',
@@ -78,7 +79,7 @@ const usePopover = ({
78
79
  }: IPopoverOptions): IPopoverControls => {
79
80
  const { addPopover, removePopover, updatePopover, popovers, isPopoverOpen } =
80
81
  useContext(PopoverContext);
81
- const { tooltips } = useReqore();
82
+ const tooltips = useReqoreProperty('tooltips');
82
83
  const { current }: MutableRefObject<string> = useRef(shortid.generate());
83
84
  let { current: timeout }: MutableRefObject<any> = useRef(0);
84
85
 
@@ -1,4 +1,4 @@
1
- import { useContext } from 'react';
1
+ import { useContext } from 'use-context-selector';
2
2
  import ReqoreContext, { IReqoreContext } from '../context/ReqoreContext';
3
3
 
4
4
  export const useReqore = (): IReqoreContext => {
@@ -0,0 +1,16 @@
1
+ import { useContextSelector } from 'use-context-selector';
2
+ import ReqoreContext, { IReqoreContext } from '../context/ReqoreContext';
3
+
4
+ export const useReqoreProperty = <T extends keyof IReqoreContext>(
5
+ property: T
6
+ ): IReqoreContext[T] => {
7
+ const contextProperty = useContextSelector(ReqoreContext, (value) => {
8
+ if (!(property in value)) {
9
+ throw new Error(`Reqore context property ${property} not found`);
10
+ }
11
+
12
+ return value[property];
13
+ });
14
+
15
+ return contextProperty;
16
+ };
@@ -1,18 +1,18 @@
1
- import { useContext, useMemo } from 'react';
1
+ import { useMemo } from 'react';
2
2
  import {
3
3
  IReqoreEffect,
4
4
  TReqoreEffectGradientAnimationTrigger,
5
5
  TReqoreHexColor,
6
6
  } from '../components/Effect';
7
7
  import { IReqoreTheme } from '../constants/theme';
8
- import ThemeContext from '../context/ThemeContext';
8
+ import { useReqoreTheme } from './useTheme';
9
9
 
10
10
  export const useReqoreEffect = (
11
11
  component: 'buttons',
12
12
  theme: IReqoreTheme,
13
13
  effect?: IReqoreEffect
14
14
  ): IReqoreEffect => {
15
- let _theme: IReqoreTheme = useContext<IReqoreTheme>(ThemeContext);
15
+ let _theme: IReqoreTheme = useReqoreTheme();
16
16
 
17
17
  // Return the effect if the component is not defined in the theme
18
18
  if (!theme[component]) {