@qoretechnologies/reqore 0.28.6 → 0.29.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (167) hide show
  1. package/.vscode/settings.json +2 -1
  2. package/__tests__/checkbox.test.tsx +7 -12
  3. package/__tests__/multiselect.test.tsx +407 -0
  4. package/__tests__/popover.test.tsx +35 -8
  5. package/dist/components/Button/index.js +1 -1
  6. package/dist/components/Button/index.js.map +1 -1
  7. package/dist/components/Checkbox/index.d.ts +7 -2
  8. package/dist/components/Checkbox/index.d.ts.map +1 -1
  9. package/dist/components/Checkbox/index.js +60 -26
  10. package/dist/components/Checkbox/index.js.map +1 -1
  11. package/dist/components/Collection/item.js +2 -2
  12. package/dist/components/Collection/item.js.map +1 -1
  13. package/dist/components/ControlGroup/index.d.ts +3 -4
  14. package/dist/components/ControlGroup/index.d.ts.map +1 -1
  15. package/dist/components/ControlGroup/index.js +7 -9
  16. package/dist/components/ControlGroup/index.js.map +1 -1
  17. package/dist/components/Dropdown/index.d.ts +2 -1
  18. package/dist/components/Dropdown/index.d.ts.map +1 -1
  19. package/dist/components/Dropdown/index.js +3 -3
  20. package/dist/components/Dropdown/index.js.map +1 -1
  21. package/dist/components/Dropdown/list.d.ts +6 -3
  22. package/dist/components/Dropdown/list.d.ts.map +1 -1
  23. package/dist/components/Dropdown/list.js +19 -1
  24. package/dist/components/Dropdown/list.js.map +1 -1
  25. package/dist/components/Effect/index.d.ts +15 -2
  26. package/dist/components/Effect/index.d.ts.map +1 -1
  27. package/dist/components/Effect/index.js +60 -23
  28. package/dist/components/Effect/index.js.map +1 -1
  29. package/dist/components/Icon/index.d.ts +2 -9
  30. package/dist/components/Icon/index.d.ts.map +1 -1
  31. package/dist/components/Icon/index.js +4 -28
  32. package/dist/components/Icon/index.js.map +1 -1
  33. package/dist/components/Input/index.js +3 -3
  34. package/dist/components/Input/index.js.map +1 -1
  35. package/dist/components/InputClearButton/index.d.ts.map +1 -1
  36. package/dist/components/InputClearButton/index.js +1 -1
  37. package/dist/components/InputClearButton/index.js.map +1 -1
  38. package/dist/components/InternalPopover/index.d.ts.map +1 -1
  39. package/dist/components/InternalPopover/index.js +19 -5
  40. package/dist/components/InternalPopover/index.js.map +1 -1
  41. package/dist/components/Menu/divider.d.ts +3 -2
  42. package/dist/components/Menu/divider.d.ts.map +1 -1
  43. package/dist/components/Menu/divider.js +2 -2
  44. package/dist/components/Menu/divider.js.map +1 -1
  45. package/dist/components/Menu/index.js +4 -3
  46. package/dist/components/Menu/index.js.map +1 -1
  47. package/dist/components/MultiSelect/index.d.ts +34 -0
  48. package/dist/components/MultiSelect/index.d.ts.map +1 -0
  49. package/dist/components/MultiSelect/index.js +178 -0
  50. package/dist/components/MultiSelect/index.js.map +1 -0
  51. package/dist/components/Panel/index.d.ts.map +1 -1
  52. package/dist/components/Panel/index.js +1 -1
  53. package/dist/components/Panel/index.js.map +1 -1
  54. package/dist/components/Popover/index.d.ts +1 -1
  55. package/dist/components/Popover/index.d.ts.map +1 -1
  56. package/dist/components/Popover/index.js +5 -2
  57. package/dist/components/Popover/index.js.map +1 -1
  58. package/dist/components/RadioGroup/index.d.ts +3 -1
  59. package/dist/components/RadioGroup/index.d.ts.map +1 -1
  60. package/dist/components/RadioGroup/index.js +2 -2
  61. package/dist/components/RadioGroup/index.js.map +1 -1
  62. package/dist/components/Table/row.js +2 -2
  63. package/dist/components/Table/row.js.map +1 -1
  64. package/dist/components/Tabs/item.js +1 -1
  65. package/dist/components/Tabs/item.js.map +1 -1
  66. package/dist/components/Tabs/list.d.ts.map +1 -1
  67. package/dist/components/Tabs/list.js +5 -4
  68. package/dist/components/Tabs/list.js.map +1 -1
  69. package/dist/components/Tag/group.d.ts +3 -3
  70. package/dist/components/Tag/group.d.ts.map +1 -1
  71. package/dist/components/Tag/group.js +6 -3
  72. package/dist/components/Tag/group.js.map +1 -1
  73. package/dist/components/Tag/index.d.ts +1 -1
  74. package/dist/components/Tag/index.d.ts.map +1 -1
  75. package/dist/components/Tag/index.js +21 -18
  76. package/dist/components/Tag/index.js.map +1 -1
  77. package/dist/components/Textarea/index.js +3 -3
  78. package/dist/components/Textarea/index.js.map +1 -1
  79. package/dist/components/Tree/index.js +1 -1
  80. package/dist/components/Tree/index.js.map +1 -1
  81. package/dist/containers/PopoverProvider.d.ts.map +1 -1
  82. package/dist/containers/PopoverProvider.js +28 -3
  83. package/dist/containers/PopoverProvider.js.map +1 -1
  84. package/dist/containers/ReqoreProvider.d.ts.map +1 -1
  85. package/dist/containers/ReqoreProvider.js +6 -5
  86. package/dist/containers/ReqoreProvider.js.map +1 -1
  87. package/dist/containers/UIProvider.d.ts +1 -0
  88. package/dist/containers/UIProvider.d.ts.map +1 -1
  89. package/dist/containers/UIProvider.js.map +1 -1
  90. package/dist/context/PopoverContext.d.ts +1 -0
  91. package/dist/context/PopoverContext.d.ts.map +1 -1
  92. package/dist/context/PopoverContext.js.map +1 -1
  93. package/dist/context/ReqoreContext.d.ts +1 -0
  94. package/dist/context/ReqoreContext.d.ts.map +1 -1
  95. package/dist/context/ReqoreContext.js +2 -1
  96. package/dist/context/ReqoreContext.js.map +1 -1
  97. package/dist/helpers/colors.d.ts +3 -0
  98. package/dist/helpers/colors.d.ts.map +1 -1
  99. package/dist/helpers/colors.js +27 -3
  100. package/dist/helpers/colors.js.map +1 -1
  101. package/dist/hooks/usePopover.d.ts +8 -1
  102. package/dist/hooks/usePopover.d.ts.map +1 -1
  103. package/dist/hooks/usePopover.js +12 -7
  104. package/dist/hooks/usePopover.js.map +1 -1
  105. package/dist/hooks/useReqore.d.ts +3 -0
  106. package/dist/hooks/useReqore.d.ts.map +1 -0
  107. package/dist/hooks/useReqore.js +17 -0
  108. package/dist/hooks/useReqore.js.map +1 -0
  109. package/dist/hooks/useTheme.d.ts +1 -1
  110. package/dist/hooks/useTheme.d.ts.map +1 -1
  111. package/dist/hooks/useTheme.js +3 -0
  112. package/dist/hooks/useTheme.js.map +1 -1
  113. package/dist/index.d.ts +3 -0
  114. package/dist/index.d.ts.map +1 -1
  115. package/dist/index.js +8 -2
  116. package/dist/index.js.map +1 -1
  117. package/package.json +1 -1
  118. package/src/components/Button/index.tsx +1 -1
  119. package/src/components/Checkbox/index.tsx +189 -34
  120. package/src/components/Collection/item.tsx +2 -2
  121. package/src/components/ControlGroup/index.tsx +46 -35
  122. package/src/components/Dropdown/index.tsx +5 -0
  123. package/src/components/Dropdown/list.tsx +29 -15
  124. package/src/components/Effect/index.tsx +123 -55
  125. package/src/components/Icon/index.tsx +4 -52
  126. package/src/components/Input/index.tsx +3 -3
  127. package/src/components/InputClearButton/index.tsx +1 -0
  128. package/src/components/InternalPopover/index.tsx +6 -3
  129. package/src/components/Menu/divider.tsx +15 -4
  130. package/src/components/Menu/index.tsx +3 -3
  131. package/src/components/MultiSelect/index.tsx +292 -0
  132. package/src/components/Panel/index.tsx +6 -4
  133. package/src/components/Popover/index.tsx +8 -3
  134. package/src/components/RadioGroup/index.tsx +6 -0
  135. package/src/components/Table/row.tsx +2 -2
  136. package/src/components/Tabs/item.tsx +1 -1
  137. package/src/components/Tabs/list.tsx +11 -11
  138. package/src/components/Tag/group.tsx +10 -2
  139. package/src/components/Tag/index.tsx +26 -20
  140. package/src/components/Textarea/index.tsx +3 -3
  141. package/src/components/Tree/index.tsx +3 -3
  142. package/src/containers/PopoverProvider.tsx +35 -3
  143. package/src/containers/ReqoreProvider.tsx +6 -4
  144. package/src/containers/UIProvider.tsx +1 -0
  145. package/src/context/PopoverContext.tsx +1 -0
  146. package/src/context/ReqoreContext.tsx +2 -0
  147. package/src/helpers/colors.ts +52 -4
  148. package/src/hooks/usePopover.tsx +24 -10
  149. package/src/hooks/useReqore.ts +12 -0
  150. package/src/hooks/useTheme.ts +6 -1
  151. package/src/index.tsx +3 -0
  152. package/src/mock/collectionData.tsx +6 -6
  153. package/src/mock/multiSelect.ts +69 -0
  154. package/src/stories/Button/Button.stories.tsx +20 -8
  155. package/src/stories/Checkbox/Checkbox.stories.tsx +42 -7
  156. package/src/stories/ControlGroup/ControlGroup.stories.tsx +7 -2
  157. package/src/stories/Dropdown/Dropdown.stories.tsx +6 -1
  158. package/src/stories/Icon/Icon.stories.tsx +42 -12
  159. package/src/stories/Input/Input.stories.tsx +25 -0
  160. package/src/stories/Menu/Menu.stories.tsx +3 -1
  161. package/src/stories/MultiSelect/MultiSelect.stories.tsx +106 -0
  162. package/src/stories/Popover/Popover.stories.tsx +19 -2
  163. package/src/stories/RadioGroup/RadioGroup.stories.tsx +51 -1
  164. package/src/stories/Tabs/Tabs.stories.tsx +23 -3
  165. package/src/stories/Tag/Tag.stories.tsx +10 -3
  166. package/src/stories/utils/args.ts +1 -1
  167. package/tests.json +1 -1
@@ -7,11 +7,12 @@ import { IWithReqoreEffect, IWithReqoreSize } from '../../types/global';
7
7
  import { IReqoreEffect, StyledTextEffect } from '../Effect';
8
8
 
9
9
  export interface IReqoreMenuDividerProps
10
- extends React.HTMLAttributes<HTMLDivElement>,
10
+ extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'>,
11
11
  IWithReqoreEffect,
12
12
  IWithReqoreSize {
13
- label?: string;
13
+ label?: string | number;
14
14
  margin?: 'left' | 'right' | 'both';
15
+ align?: 'left' | 'center' | 'right';
15
16
  }
16
17
 
17
18
  export const StyledMenuDivider = styled(StyledTextEffect)`
@@ -38,7 +39,17 @@ export const StyledMenuDivider = styled(StyledTextEffect)`
38
39
  `;
39
40
 
40
41
  const ReqoreMenuDivider = forwardRef<HTMLDivElement, IReqoreMenuDividerProps>(
41
- ({ label, className, effect, size = 'normal', ...rest }: IReqoreMenuDividerProps, ref: any) => (
42
+ (
43
+ {
44
+ label,
45
+ className,
46
+ effect,
47
+ size = 'normal',
48
+ align = 'center',
49
+ ...rest
50
+ }: IReqoreMenuDividerProps,
51
+ ref: any
52
+ ) => (
42
53
  <StyledMenuDivider
43
54
  as='div'
44
55
  {...rest}
@@ -49,7 +60,7 @@ const ReqoreMenuDivider = forwardRef<HTMLDivElement, IReqoreMenuDividerProps>(
49
60
  {
50
61
  uppercase: true,
51
62
  spaced: 2,
52
- textAlign: 'center',
63
+ textAlign: align,
53
64
  textSize: getOneLessSize(size),
54
65
  weight: 'bold',
55
66
  ...effect,
@@ -81,10 +81,10 @@ const ReqoreMenu = forwardRef<HTMLDivElement, IReqoreMenuProps>(
81
81
  React.cloneElement(child, {
82
82
  _insidePopover,
83
83
  _popoverId,
84
- customTheme: child?.props.customTheme || theme,
84
+ customTheme: child.props?.customTheme || theme,
85
85
  wrap: wrapText,
86
- flat: 'flat' in child?.props ? child.props.flat : flat,
87
- minimal: 'minimal' in child?.props ? child.props.minimal : minimal,
86
+ flat: 'flat' in (child.props || {}) ? child.props.flat : flat,
87
+ minimal: 'minimal' in (child.props || {}) ? child.props.minimal : minimal,
88
88
  })
89
89
  : null;
90
90
  })}
@@ -0,0 +1,292 @@
1
+ import { omit, size } from 'lodash';
2
+ import { forwardRef, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
+ import { useUpdateEffect } from 'react-use';
4
+ import { ReqoreDropdown, ReqoreInput } from '../..';
5
+ import { TSizes } from '../../constants/sizes';
6
+ import { IPopoverControls } from '../../hooks/usePopover';
7
+ import ReqoreControlGroup, { IReqoreControlGroupProps } from '../ControlGroup';
8
+ import { IReqoreDropdownProps } from '../Dropdown';
9
+ import { IReqoreDropdownItem } from '../Dropdown/list';
10
+ import { IReqoreEffect } from '../Effect';
11
+ import { IReqoreInputProps } from '../Input';
12
+ import ReqoreTag, { IReqoreTagProps } from '../Tag';
13
+ import ReqoreTagGroup from '../Tag/group';
14
+
15
+ export type TReqoreMultiSelectItem = Omit<IReqoreDropdownItem, 'color'> &
16
+ Pick<IReqoreTagProps, 'asBadge' | 'rightIcon' | 'actions'> & { isNew?: boolean };
17
+
18
+ export interface IReqoreMultiSelectProps
19
+ extends Omit<IReqoreControlGroupProps, 'children' | 'vertical' | 'stack'> {
20
+ value?: string[];
21
+ onValueChange?: (value: string[]) => void;
22
+ items?: TReqoreMultiSelectItem[];
23
+ onItemClick?: (item: IReqoreDropdownItem) => void;
24
+ onItemClickIcon?: IReqoreTagProps['rightIcon'];
25
+ canRemoveItems?: boolean;
26
+ canCreateItems?: boolean;
27
+ selectedItemEffect?: IReqoreEffect;
28
+ selectedItemSize?: TSizes;
29
+ selectorProps?: Omit<IReqoreInputProps, 'value' | 'onValueChange'> & IReqoreDropdownProps;
30
+ openOnMount?: IReqoreDropdownProps['openOnMount'];
31
+ enterKeySelects?: boolean;
32
+ }
33
+
34
+ export interface IReqoreMultiSelectItemProps
35
+ extends Pick<IReqoreMultiSelectProps, 'selectedItemEffect' | 'selectedItemSize'> {
36
+ item: TReqoreMultiSelectItem;
37
+ onClick?: () => void;
38
+ onRemoveClick?: () => void;
39
+ onItemClickIcon?: IReqoreTagProps['rightIcon'];
40
+ }
41
+
42
+ export const ReqoreMultiSelectItem = memo(
43
+ ({
44
+ item,
45
+ onRemoveClick,
46
+ onClick,
47
+ selectedItemEffect,
48
+ selectedItemSize,
49
+ onItemClickIcon,
50
+ }: IReqoreMultiSelectItemProps) => {
51
+ if (!item) {
52
+ return null;
53
+ }
54
+
55
+ return (
56
+ <ReqoreTag
57
+ {...item}
58
+ label={item.label || item.value}
59
+ onRemoveClick={onRemoveClick}
60
+ intent={item.intent}
61
+ effect={!item.intent ? item.effect || selectedItemEffect : undefined}
62
+ size={selectedItemSize}
63
+ onClick={onClick}
64
+ rightIcon={item.rightIcon || item.disabled ? undefined : onItemClickIcon}
65
+ />
66
+ );
67
+ }
68
+ );
69
+
70
+ export const ReqoreMultiSelect = forwardRef<HTMLDivElement, IReqoreMultiSelectProps>(
71
+ (
72
+ {
73
+ value,
74
+ onValueChange,
75
+ onItemClick,
76
+ canRemoveItems,
77
+ canCreateItems,
78
+ items = [],
79
+ selectedItemEffect,
80
+ selectedItemSize,
81
+ selectorProps,
82
+ openOnMount,
83
+ enterKeySelects,
84
+ onItemClickIcon,
85
+ ...rest
86
+ }: IReqoreMultiSelectProps,
87
+ ref
88
+ ) => {
89
+ const [_value, setValue] = useState<string[]>(value || []);
90
+ const [createdItems, setCreatedItems] = useState<TReqoreMultiSelectItem[]>([]);
91
+ const [query, setQuery] = useState<string>('');
92
+ const popoverData = useRef<IPopoverControls>(undefined);
93
+ const [focused, setFocused] = useState<boolean>(false);
94
+
95
+ useUpdateEffect(() => {
96
+ onValueChange?.(_value);
97
+ }, [_value]);
98
+
99
+ useEffect(() => {
100
+ setValue(value || []);
101
+ }, [value]);
102
+
103
+ useEffect(() => {
104
+ if (query && !popoverData.current?.isOpen()) {
105
+ popoverData.current?.open();
106
+ }
107
+ }, [query]);
108
+
109
+ useEffect(() => {
110
+ if (enterKeySelects) {
111
+ document.addEventListener('keydown', handleKeyDown);
112
+ }
113
+
114
+ return () => {
115
+ document.removeEventListener('keydown', handleKeyDown);
116
+ };
117
+ });
118
+
119
+ const addRemoveItem = useCallback(
120
+ (item: TReqoreMultiSelectItem): void => {
121
+ if (_value.includes(item.value)) {
122
+ setValue(_value.filter((v) => v !== item.value));
123
+ } else {
124
+ setValue([..._value, item.value]);
125
+ }
126
+ },
127
+ [_value, value]
128
+ );
129
+
130
+ const handleItemSelect = useCallback(
131
+ (item: Partial<TReqoreMultiSelectItem>) => {
132
+ addRemoveItem(item);
133
+
134
+ if (item.isNew) {
135
+ setCreatedItems([
136
+ ...createdItems,
137
+ {
138
+ value: item.value,
139
+ },
140
+ ]);
141
+ }
142
+
143
+ setQuery('');
144
+ },
145
+ [createdItems, _value]
146
+ );
147
+
148
+ /*
149
+ This code creates a list of all items that are available
150
+ for selection in the dropdown. It will include the items
151
+ that are passed in as props, as well as any items that the
152
+ user has created.
153
+ */
154
+ const allItems: TReqoreMultiSelectItem[] = useMemo(() => {
155
+ const customItems: TReqoreMultiSelectItem[] = size(createdItems)
156
+ ? [{ divider: true, label: 'Custom Items' }, ...createdItems]
157
+ : [];
158
+
159
+ let filteredItems: TReqoreMultiSelectItem[] = [...items, ...customItems].filter((item) =>
160
+ query
161
+ ? item.divider
162
+ ? false
163
+ : (item.label || item.value)?.toString().toLowerCase().indexOf(query.toLowerCase()) !==
164
+ -1
165
+ : true
166
+ );
167
+
168
+ // Mark selected items as selected
169
+ filteredItems = filteredItems.map((item: TReqoreMultiSelectItem) => ({
170
+ ...omit(item, ['actions', 'asBadge', 'rightIcon']),
171
+ selected: _value.includes(item.value),
172
+ }));
173
+
174
+ if (query && !size(filteredItems)) {
175
+ filteredItems = [
176
+ { label: 'No existing items found', readOnly: true, minimal: true, icon: 'ForbidLine' },
177
+ ];
178
+ }
179
+
180
+ // If there is a query and there are filtered items
181
+ // and there is no item that exactly matches the query, add it to the list
182
+ if (
183
+ query &&
184
+ !filteredItems.some((item: TReqoreMultiSelectItem) => item.value === query) &&
185
+ canCreateItems
186
+ ) {
187
+ filteredItems = [
188
+ {
189
+ label: `Create new "${query}"`,
190
+ value: query,
191
+ isNew: true,
192
+ icon: 'AddCircleLine',
193
+ minimal: true,
194
+ flat: false,
195
+ effect: {
196
+ gradient: {
197
+ colors: {
198
+ 0: 'success',
199
+ 100: 'success:darken:1',
200
+ },
201
+ },
202
+ },
203
+ },
204
+ { divider: true, label: 'Items matching your query' },
205
+ ...filteredItems,
206
+ ];
207
+ }
208
+
209
+ return filteredItems;
210
+ }, [items, createdItems, query, _value]);
211
+
212
+ const handleKeyDown = useCallback(
213
+ (e: KeyboardEvent) => {
214
+ if (e.key === 'Enter' && focused) {
215
+ const item = [...items, ...createdItems].find((item) => item.value === query);
216
+
217
+ if (item) {
218
+ handleItemSelect(item);
219
+ } else if (canCreateItems && query) {
220
+ handleItemSelect({
221
+ value: query,
222
+ isNew: true,
223
+ });
224
+ }
225
+ }
226
+ },
227
+ [items, createdItems, query, canCreateItems, focused]
228
+ );
229
+
230
+ const getItemByValue = useCallback(
231
+ (value: string): TReqoreMultiSelectItem => {
232
+ return [...items, ...createdItems].find((item) => item.value === value);
233
+ },
234
+ [items, createdItems, _value]
235
+ );
236
+
237
+ return (
238
+ <ReqoreControlGroup vertical fluid {...rest} ref={ref}>
239
+ <ReqoreTagGroup minimal={rest.minimal} size={rest.size}>
240
+ {size(_value) ? (
241
+ _value.map((v) => (
242
+ <ReqoreMultiSelectItem
243
+ key={v}
244
+ item={getItemByValue(v)}
245
+ onItemClickIcon={onItemClickIcon}
246
+ onRemoveClick={canRemoveItems ? () => addRemoveItem(getItemByValue(v)) : undefined}
247
+ onClick={
248
+ onItemClick
249
+ ? () => {
250
+ onItemClick(getItemByValue(v));
251
+ }
252
+ : undefined
253
+ }
254
+ selectedItemEffect={selectedItemEffect}
255
+ selectedItemSize={selectedItemSize}
256
+ />
257
+ ))
258
+ ) : (
259
+ <ReqoreTag color='transparent' icon='ForbidLine' label='No items selected' />
260
+ )}
261
+ </ReqoreTagGroup>
262
+ <ReqoreControlGroup minimal={rest.minimal} flat={rest.flat} size={rest.size}>
263
+ <ReqoreDropdown<IReqoreInputProps>
264
+ {...selectorProps}
265
+ multiSelect
266
+ handler='focus'
267
+ onFocus={() => setFocused(true)}
268
+ onBlur={() => setFocused(false)}
269
+ passPopoverData={(data) => (popoverData.current = data)}
270
+ component={ReqoreInput}
271
+ onClearClick={() => setQuery('')}
272
+ value={query}
273
+ isDefaultOpen={openOnMount}
274
+ onItemSelect={handleItemSelect}
275
+ placeholder={
276
+ canCreateItems ? 'Type to search or create an item...' : 'Type to search...'
277
+ }
278
+ onChange={(e: any) => setQuery(e.target.value)}
279
+ items={
280
+ size(allItems)
281
+ ? allItems
282
+ : canCreateItems
283
+ ? [{ label: 'No items exist', readOnly: true, minimal: true, icon: 'ForbidLine' }]
284
+ : []
285
+ }
286
+ useTargetWidth
287
+ />
288
+ </ReqoreControlGroup>
289
+ </ReqoreControlGroup>
290
+ );
291
+ }
292
+ );
@@ -8,14 +8,14 @@ import {
8
8
  PADDING_FROM_SIZE,
9
9
  RADIUS_FROM_SIZE,
10
10
  TEXT_FROM_SIZE,
11
- TSizes
11
+ TSizes,
12
12
  } from '../../constants/sizes';
13
13
  import { IReqoreTheme } from '../../constants/theme';
14
14
  import {
15
15
  changeDarkness,
16
16
  changeLightness,
17
17
  getMainBackgroundColor,
18
- getReadableColor
18
+ getReadableColor,
19
19
  } from '../../helpers/colors';
20
20
  import { useCombinedRefs } from '../../hooks/useCombinedRefs';
21
21
  import { useReqoreTheme } from '../../hooks/useTheme';
@@ -26,7 +26,7 @@ import {
26
26
  IWithReqoreCustomTheme,
27
27
  IWithReqoreFlat,
28
28
  IWithReqoreSize,
29
- IWithReqoreTooltip
29
+ IWithReqoreTooltip,
30
30
  } from '../../types/global';
31
31
  import { IReqoreIconName } from '../../types/icons';
32
32
  import ReqoreButton, { ButtonBadge, IReqoreButtonProps, TReqoreBadge } from '../Button';
@@ -323,7 +323,9 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
323
323
  (actionOrActions: IReqorePanelAction | IReqorePanelAction[], index: number) => {
324
324
  if (Array.isArray(actionOrActions)) {
325
325
  return (
326
- <ReqoreControlGroup stack>{actionOrActions.map(renderActions)}</ReqoreControlGroup>
326
+ <ReqoreControlGroup key={index} stack>
327
+ {actionOrActions.map(renderActions)}
328
+ </ReqoreControlGroup>
327
329
  );
328
330
  }
329
331
 
@@ -1,6 +1,6 @@
1
- import React, { memo, useState } from 'react';
1
+ import React, { memo, useEffect, useState } from 'react';
2
2
  import styled from 'styled-components';
3
- import usePopover, { IPopoverOptions } from '../../hooks/usePopover';
3
+ import usePopover, { IPopoverControls, IPopoverOptions } from '../../hooks/usePopover';
4
4
  import { IReqoreComponent } from '../../types/global';
5
5
 
6
6
  export interface IReqorePopoverProps extends IReqoreComponent, IPopoverOptions {
@@ -26,13 +26,18 @@ const Popover = memo(
26
26
  noWrapper,
27
27
  wrapperTag = 'span',
28
28
  wrapperStyle = {},
29
+ passPopoverData,
29
30
  _insidePopover,
30
31
  _popoverId,
31
32
  ...rest
32
33
  }: IReqorePopoverProps) => {
33
34
  const [ref, setRef] = useState(undefined);
34
35
 
35
- usePopover({ targetElement: ref, ...rest });
36
+ const popoverData: IPopoverControls = usePopover({ targetElement: ref, ...rest });
37
+
38
+ useEffect(() => {
39
+ passPopoverData?.(popoverData);
40
+ }, [popoverData]);
36
41
 
37
42
  if (isReqoreComponent || noWrapper) {
38
43
  return (
@@ -19,6 +19,8 @@ export interface IReqoreRadioGroupProps
19
19
  size?: TSizes;
20
20
  disabled?: boolean;
21
21
  asSwitch?: boolean;
22
+ onText?: string;
23
+ offText?: string;
22
24
  }
23
25
 
24
26
  const ReqoreRadioGroup = ({
@@ -29,6 +31,8 @@ const ReqoreRadioGroup = ({
29
31
  disabled,
30
32
  asSwitch,
31
33
  vertical = true,
34
+ onText,
35
+ offText,
32
36
  ...rest
33
37
  }: IReqoreRadioGroupProps) => (
34
38
  <ReqoreControlGroup {...rest} vertical={vertical}>
@@ -44,6 +48,8 @@ const ReqoreRadioGroup = ({
44
48
  ) : (
45
49
  <ReqoreCheckbox
46
50
  asSwitch={asSwitch}
51
+ onText={onText}
52
+ offText={offText}
47
53
  {...itemRest}
48
54
  key={value}
49
55
  checked={value === selected}
@@ -277,10 +277,10 @@ const ReqoreTableRow = ({
277
277
  onClick: (e: React.MouseEvent<HTMLDivElement>) => {
278
278
  if (onCellClick) {
279
279
  e.stopPropagation();
280
- onCellClick?.(data[index]);
280
+ onCellClick(data[index]);
281
281
  } else if (onRowClick) {
282
282
  e.stopPropagation();
283
- onRowClick?.(data[index]);
283
+ onRowClick(data[index]);
284
284
  } else if (selectable && data[index]._selectId) {
285
285
  // Otherwise select the row if selectable
286
286
  onSelectClick(data[index]._selectId);
@@ -35,7 +35,7 @@ export const StyledTabListItem = styled.div<IReqoreTabListItemStyle>`
35
35
  position: relative;
36
36
  align-items: center;
37
37
  width: ${vertical ? `100%` : undefined};
38
- padding: ${vertical ? `${TABS_PADDING_TO_PX[size!]}px` : `${TABS_PADDING_TO_PX[size!]}px`};
38
+ padding: ${`${TABS_PADDING_TO_PX[size!]}px`};
39
39
  padding-bottom: ${!vertical && 0};
40
40
  padding-right: ${vertical && 0};
41
41
 
@@ -13,9 +13,14 @@ import {
13
13
  } from '../../constants/sizes';
14
14
  import { IReqoreBreadcrumbsTheme, IReqoreCustomTheme, IReqoreTheme } from '../../constants/theme';
15
15
  import ReqoreThemeProvider from '../../containers/ThemeProvider';
16
- import { changeLightness } from '../../helpers/colors';
16
+ import {
17
+ changeLightness,
18
+ getColorFromMaybeString,
19
+ getNthGradientColor,
20
+ } from '../../helpers/colors';
17
21
  import { calculateStringSizeInPixels } from '../../helpers/utils';
18
22
  import { useReqoreTheme } from '../../hooks/useTheme';
23
+ import { TReqoreHexColor } from '../Effect';
19
24
  import ReqoreMenu from '../Menu';
20
25
  import ReqoreMenuItem, { IReqoreMenuItemProps } from '../Menu/item';
21
26
  import { StyledPopover } from '../Popover';
@@ -159,23 +164,18 @@ const ReqoreTabsList = ({
159
164
  intent,
160
165
  ...rest
161
166
  }: IReqoreTabsListProps) => {
162
- const [ref, { width, height }] = useMeasure();
167
+ const [ref, { width }] = useMeasure();
163
168
  const theme = useReqoreTheme('main', customTheme, intent);
164
169
  const activeTabData = tabs.find((tab) => tab.id === activeTab);
165
- const currentTabColor =
170
+ const currentTabColor: TReqoreHexColor =
166
171
  activeTabIntent || activeTabData?.intent
167
172
  ? theme.intents[activeTabIntent || activeTabData.intent]
168
- : activeTabData?.customTheme?.main || theme.main;
173
+ : getNthGradientColor(theme, activeTabData?.effect?.gradient?.colors) ||
174
+ getColorFromMaybeString(theme, activeTabData?.customTheme?.main || theme.main);
169
175
 
170
176
  const transformedItems = vertical
171
177
  ? tabs
172
- : getTransformedItems(
173
- tabs,
174
- vertical ? height : _testWidth || width,
175
- vertical ? 'height' : 'width',
176
- activeTab,
177
- size
178
- );
178
+ : getTransformedItems(tabs, _testWidth || width, 'width', activeTab, size);
179
179
 
180
180
  return (
181
181
  <ReqoreThemeProvider theme={theme}>
@@ -2,10 +2,13 @@ import React from 'react';
2
2
  import styled from 'styled-components';
3
3
  import { StyledTag } from '.';
4
4
  import { GAP_FROM_SIZE, TSizes } from '../../constants/sizes';
5
+ import { IWithReqoreMinimal, IWithReqoreSize } from '../../types/global';
5
6
 
6
- export interface IReqoreTagGroup extends React.HTMLAttributes<HTMLDivElement> {
7
+ export interface IReqoreTagGroup
8
+ extends React.HTMLAttributes<HTMLDivElement>,
9
+ IWithReqoreSize,
10
+ IWithReqoreMinimal {
7
11
  children: any;
8
- size?: TSizes;
9
12
  gapSize?: TSizes;
10
13
  columns?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10;
11
14
  hasBottomMargin?: boolean;
@@ -27,6 +30,7 @@ const ReqoreTagGroup = ({
27
30
  children,
28
31
  size,
29
32
  gapSize = 'normal',
33
+ minimal,
30
34
  className,
31
35
  columns,
32
36
  hasBottomMargin = true,
@@ -43,6 +47,10 @@ const ReqoreTagGroup = ({
43
47
  ? React.cloneElement(child, {
44
48
  size: child.props?.size || size,
45
49
  width: columns ? `calc(${100 / columns}% - 5px)` : child.props.width,
50
+ minimal:
51
+ child.props?.minimal || child.props?.minimal === false
52
+ ? child.props.minimal
53
+ : minimal,
46
54
  })
47
55
  : null
48
56
  )}
@@ -53,7 +53,7 @@ export interface IReqoreTagProps
53
53
  color?: TReqoreEffectColor;
54
54
  actions?: IReqoreTagAction[];
55
55
  width?: string;
56
- badge?: boolean;
56
+ asBadge?: boolean;
57
57
  intent?: TReqoreIntent;
58
58
  wrap?: boolean;
59
59
  }
@@ -77,17 +77,18 @@ export const StyledTag = styled(StyledEffect)<IReqoreTagStyle>`
77
77
  font-size: ${({ size }) => TEXT_FROM_SIZE[size]}px;
78
78
 
79
79
  min-width: ${({ size }) => SIZE_TO_PX[size]}px;
80
- border-radius: ${({ badge, size }) => (badge ? 18 : RADIUS_FROM_SIZE[size])}px;
80
+ border-radius: ${({ asBadge, size }) => (asBadge ? 18 : RADIUS_FROM_SIZE[size])}px;
81
81
  width: ${({ width }) => width || undefined};
82
82
  transition: all 0.2s ease-out;
83
83
 
84
84
  ${({ wrap, hasWidth }) =>
85
85
  wrap || hasWidth
86
86
  ? css`
87
- min-height: ${({ size, badge }) => (badge ? BADGE_SIZE_TO_PX[size] : SIZE_TO_PX[size])}px;
87
+ min-height: ${({ size, asBadge }) =>
88
+ asBadge ? BADGE_SIZE_TO_PX[size] : SIZE_TO_PX[size]}px;
88
89
  `
89
90
  : css`
90
- height: ${({ size, badge }) => (badge ? BADGE_SIZE_TO_PX[size] : SIZE_TO_PX[size])}px;
91
+ height: ${({ size, asBadge }) => (asBadge ? BADGE_SIZE_TO_PX[size] : SIZE_TO_PX[size])}px;
91
92
  `}
92
93
 
93
94
  ${({ theme, color, labelKey, minimal }: IReqoreTagStyle) =>
@@ -220,7 +221,7 @@ const ReqoreTag = forwardRef<HTMLSpanElement, IReqoreTagProps>(
220
221
  size = 'normal',
221
222
  onRemoveClick,
222
223
  actions,
223
- badge,
224
+ asBadge,
224
225
  intent,
225
226
  color,
226
227
  minimal,
@@ -236,10 +237,15 @@ const ReqoreTag = forwardRef<HTMLSpanElement, IReqoreTagProps>(
236
237
  useTooltip(targetRef.current, tooltip);
237
238
 
238
239
  // If color or intent was specified, set the color
239
- let customColor: TReqoreHexColor = intent
240
- ? theme.intents[intent]
241
- : getColorFromMaybeString(theme, color);
242
- customColor = minimal ? `${customColor || '#000000'}40` : customColor;
240
+ const getCustomColor = (itemIntent?: TReqoreIntent): TReqoreHexColor => {
241
+ let customColor: TReqoreHexColor = itemIntent
242
+ ? theme.intents[itemIntent]
243
+ : getColorFromMaybeString(theme, color);
244
+
245
+ customColor = minimal ? `${customColor || '#000000'}40` : customColor;
246
+
247
+ return customColor;
248
+ };
243
249
 
244
250
  return (
245
251
  <StyledTag
@@ -250,11 +256,11 @@ const ReqoreTag = forwardRef<HTMLSpanElement, IReqoreTagProps>(
250
256
  }}
251
257
  width={width}
252
258
  labelKey={labelKey}
253
- color={customColor}
259
+ color={getCustomColor(intent)}
254
260
  className={`${className || ''} reqore-tag`}
255
261
  size={size}
256
262
  ref={targetRef}
257
- badge={badge}
263
+ asBadge={asBadge}
258
264
  minimal={minimal}
259
265
  removable={!!onRemoveClick}
260
266
  interactive={!!onClick && !rest.disabled}
@@ -265,7 +271,7 @@ const ReqoreTag = forwardRef<HTMLSpanElement, IReqoreTagProps>(
265
271
  <StyledTagKeyWrapper
266
272
  size={size}
267
273
  className='reqore-tag-key-content'
268
- onClick={onClick}
274
+ onClick={rest.disabled ? undefined : onClick}
269
275
  wrap={wrap}
270
276
  hasWidth={!!width}
271
277
  hasKey={!!labelKey}
@@ -282,13 +288,13 @@ const ReqoreTag = forwardRef<HTMLSpanElement, IReqoreTagProps>(
282
288
  <StyledTagContentWrapper
283
289
  size={size}
284
290
  className='reqore-tag-content'
285
- onClick={onClick}
291
+ onClick={rest.disabled ? undefined : onClick}
286
292
  wrap={wrap}
287
293
  hasWidth={!!width}
288
294
  hasKey={!!labelKey}
289
295
  >
290
296
  {label || label === 0 ? (
291
- <StyledTagContent size={size} onClick={onClick} wrap={wrap} hasWidth={!!width}>
297
+ <StyledTagContent size={size} wrap={wrap} hasWidth={!!width}>
292
298
  {label}
293
299
  </StyledTagContent>
294
300
  ) : null}
@@ -302,13 +308,13 @@ const ReqoreTag = forwardRef<HTMLSpanElement, IReqoreTagProps>(
302
308
  </StyledTagContentWrapper>
303
309
  ) : null}
304
310
  {_size(actions)
305
- ? actions.map((action) => (
306
- <>
311
+ ? actions.map((action, index) => (
312
+ <React.Fragment key={index}>
307
313
  <ReqorePopover
308
314
  component={StyledButtonWrapper}
309
315
  componentProps={{
310
316
  size,
311
- color: customColor,
317
+ color: getCustomColor(action.intent),
312
318
  className: 'reqore-tag-action',
313
319
  onClick: action.onClick,
314
320
  effect: rest.effect,
@@ -316,13 +322,13 @@ const ReqoreTag = forwardRef<HTMLSpanElement, IReqoreTagProps>(
316
322
  {...(action.tooltip
317
323
  ? typeof action.tooltip === 'string'
318
324
  ? { tooltip: action.tooltip }
319
- : action.tooltip || {}
325
+ : action.tooltip
320
326
  : {})}
321
327
  noWrapper
322
328
  >
323
329
  <ReqoreIcon icon={action.icon} size={size} />
324
330
  </ReqorePopover>
325
- </>
331
+ </React.Fragment>
326
332
  ))
327
333
  : null}
328
334
  {onRemoveClick && !rest.disabled ? (
@@ -330,7 +336,7 @@ const ReqoreTag = forwardRef<HTMLSpanElement, IReqoreTagProps>(
330
336
  component={StyledButtonWrapper}
331
337
  componentProps={{
332
338
  size,
333
- color: customColor,
339
+ color: getCustomColor(intent),
334
340
  className: 'reqore-tag-remove',
335
341
  onClick: onRemoveClick,
336
342
  effect: rest.effect,