@qoretechnologies/reqore 0.29.9 → 0.30.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 (73) hide show
  1. package/__tests__/collection.test.tsx +1 -1
  2. package/__tests__/{control_group.text.tsx → control_group.test.tsx} +4 -2
  3. package/__tests__/panel.test.tsx +22 -24
  4. package/__tests__/tabs.test.tsx +32 -0
  5. package/dist/components/Button/index.d.ts.map +1 -1
  6. package/dist/components/Button/index.js +5 -2
  7. package/dist/components/Button/index.js.map +1 -1
  8. package/dist/components/Collection/index.d.ts.map +1 -1
  9. package/dist/components/Collection/index.js +14 -37
  10. package/dist/components/Collection/index.js.map +1 -1
  11. package/dist/components/Columns/column.d.ts.map +1 -1
  12. package/dist/components/Columns/column.js +1 -1
  13. package/dist/components/Columns/column.js.map +1 -1
  14. package/dist/components/ControlGroup/index.d.ts +5 -4
  15. package/dist/components/ControlGroup/index.d.ts.map +1 -1
  16. package/dist/components/ControlGroup/index.js +117 -24
  17. package/dist/components/ControlGroup/index.js.map +1 -1
  18. package/dist/components/Drawer/index.d.ts.map +1 -1
  19. package/dist/components/Drawer/index.js +6 -4
  20. package/dist/components/Drawer/index.js.map +1 -1
  21. package/dist/components/Effect/index.d.ts.map +1 -1
  22. package/dist/components/Effect/index.js +1 -1
  23. package/dist/components/Effect/index.js.map +1 -1
  24. package/dist/components/Input/index.js +2 -2
  25. package/dist/components/Input/index.js.map +1 -1
  26. package/dist/components/InternalPopover/index.d.ts.map +1 -1
  27. package/dist/components/InternalPopover/index.js +5 -3
  28. package/dist/components/InternalPopover/index.js.map +1 -1
  29. package/dist/components/MultiSelect/index.d.ts +1 -1
  30. package/dist/components/MultiSelect/index.d.ts.map +1 -1
  31. package/dist/components/MultiSelect/index.js +10 -10
  32. package/dist/components/MultiSelect/index.js.map +1 -1
  33. package/dist/components/Panel/index.d.ts +4 -1
  34. package/dist/components/Panel/index.d.ts.map +1 -1
  35. package/dist/components/Panel/index.js +39 -16
  36. package/dist/components/Panel/index.js.map +1 -1
  37. package/dist/components/Spacer/index.d.ts +2 -0
  38. package/dist/components/Spacer/index.d.ts.map +1 -1
  39. package/dist/components/Spacer/index.js +29 -7
  40. package/dist/components/Spacer/index.js.map +1 -1
  41. package/dist/components/Tabs/index.d.ts.map +1 -1
  42. package/dist/components/Tabs/index.js +2 -1
  43. package/dist/components/Tabs/index.js.map +1 -1
  44. package/dist/components/Tag/index.d.ts +2 -2
  45. package/dist/components/Tag/index.d.ts.map +1 -1
  46. package/dist/components/Tag/index.js +7 -1
  47. package/dist/components/Tag/index.js.map +1 -1
  48. package/dist/components/Tree/index.js +1 -1
  49. package/dist/components/Tree/index.js.map +1 -1
  50. package/dist/constants/animations.js +1 -1
  51. package/dist/containers/PopoverProvider.js +3 -3
  52. package/dist/containers/PopoverProvider.js.map +1 -1
  53. package/package.json +1 -1
  54. package/src/components/Button/index.tsx +2 -1
  55. package/src/components/Collection/index.tsx +14 -37
  56. package/src/components/Columns/column.tsx +1 -0
  57. package/src/components/ControlGroup/index.tsx +386 -232
  58. package/src/components/Drawer/index.tsx +6 -4
  59. package/src/components/Effect/index.tsx +1 -0
  60. package/src/components/Input/index.tsx +1 -1
  61. package/src/components/InternalPopover/index.tsx +127 -123
  62. package/src/components/MultiSelect/index.tsx +180 -188
  63. package/src/components/Panel/index.tsx +127 -42
  64. package/src/components/Spacer/index.tsx +63 -14
  65. package/src/components/Tabs/index.tsx +3 -2
  66. package/src/components/Tag/index.tsx +5 -1
  67. package/src/components/Tree/index.tsx +1 -1
  68. package/src/constants/animations.ts +1 -1
  69. package/src/containers/PopoverProvider.tsx +3 -3
  70. package/src/stories/ControlGroup/ControlGroup.stories.tsx +55 -5
  71. package/src/stories/Panel/Panel.stories.tsx +60 -17
  72. package/src/stories/Popover/Popover.stories.tsx +5 -5
  73. package/tests.json +1 -1
@@ -1,5 +1,5 @@
1
1
  import { omit, size } from 'lodash';
2
- import { forwardRef, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
+ import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
3
  import { ReqoreDropdown, ReqoreInput } from '../..';
4
4
  import { TSizes } from '../../constants/sizes';
5
5
  import { IPopoverControls } from '../../hooks/usePopover';
@@ -74,217 +74,209 @@ export const ReqoreMultiSelectItem = memo(
74
74
  }
75
75
  );
76
76
 
77
- export const ReqoreMultiSelect = forwardRef<HTMLDivElement, IReqoreMultiSelectProps>(
78
- (
79
- {
80
- value = [],
81
- onValueChange,
82
- onItemClick,
83
- canRemoveItems,
84
- canCreateItems,
85
- items = [],
86
- selectedItemEffect,
87
- selectedItemSize,
88
- selectorProps,
89
- openOnMount,
90
- enterKeySelects,
91
- onItemClickIcon,
92
- ...rest
93
- }: IReqoreMultiSelectProps,
94
- ref
95
- ) => {
96
- const [createdItems, setCreatedItems] = useState<TReqoreMultiSelectItem[]>([]);
97
- const [query, setQuery] = useState<string>('');
98
- const popoverData = useRef<IPopoverControls>(undefined);
99
- const [focused, setFocused] = useState<boolean>(false);
77
+ export const ReqoreMultiSelect = ({
78
+ value = [],
79
+ onValueChange,
80
+ onItemClick,
81
+ canRemoveItems,
82
+ canCreateItems,
83
+ items = [],
84
+ selectedItemEffect,
85
+ selectedItemSize,
86
+ selectorProps,
87
+ openOnMount,
88
+ enterKeySelects,
89
+ onItemClickIcon,
90
+ ...rest
91
+ }: IReqoreMultiSelectProps) => {
92
+ const [createdItems, setCreatedItems] = useState<TReqoreMultiSelectItem[]>([]);
93
+ const [query, setQuery] = useState<string>('');
94
+ const popoverData = useRef<IPopoverControls>(undefined);
95
+ const [focused, setFocused] = useState<boolean>(false);
100
96
 
101
- useEffect(() => {
102
- if (query && !popoverData.current?.isOpen()) {
103
- popoverData.current?.open();
104
- }
105
- }, [query]);
97
+ useEffect(() => {
98
+ if (query && !popoverData.current?.isOpen()) {
99
+ popoverData.current?.open();
100
+ }
101
+ }, [query]);
106
102
 
107
- useEffect(() => {
108
- if (enterKeySelects) {
109
- document.addEventListener('keydown', handleKeyDown);
110
- }
103
+ useEffect(() => {
104
+ if (enterKeySelects) {
105
+ document.addEventListener('keydown', handleKeyDown);
106
+ }
111
107
 
112
- return () => {
113
- document.removeEventListener('keydown', handleKeyDown);
114
- };
115
- });
108
+ return () => {
109
+ document.removeEventListener('keydown', handleKeyDown);
110
+ };
111
+ });
116
112
 
117
- const addRemoveItem = useCallback(
118
- (item: TReqoreMultiSelectItem): void => {
119
- if (value.includes(item.value)) {
120
- onValueChange(value.filter((v) => v !== item.value));
121
- } else {
122
- onValueChange([...value, item.value]);
123
- }
124
- },
125
- [value]
126
- );
113
+ const addRemoveItem = useCallback(
114
+ (item: TReqoreMultiSelectItem): void => {
115
+ if (value.includes(item.value)) {
116
+ onValueChange(value.filter((v) => v !== item.value));
117
+ } else {
118
+ onValueChange([...value, item.value]);
119
+ }
120
+ },
121
+ [value]
122
+ );
127
123
 
128
- const handleItemSelect = useCallback(
129
- (item: Partial<TReqoreMultiSelectItem>) => {
130
- addRemoveItem(item);
124
+ const handleItemSelect = useCallback(
125
+ (item: Partial<TReqoreMultiSelectItem>) => {
126
+ addRemoveItem(item);
131
127
 
132
- if (item.isNew) {
133
- setCreatedItems([
134
- ...createdItems,
135
- {
136
- value: item.value,
137
- },
138
- ]);
139
- }
128
+ if (item.isNew) {
129
+ setCreatedItems([
130
+ ...createdItems,
131
+ {
132
+ value: item.value,
133
+ },
134
+ ]);
135
+ }
140
136
 
141
- setQuery('');
142
- },
143
- [createdItems, value]
144
- );
137
+ setQuery('');
138
+ },
139
+ [createdItems, value]
140
+ );
145
141
 
146
- /*
142
+ /*
147
143
  This code creates a list of all items that are available
148
144
  for selection in the dropdown. It will include the items
149
145
  that are passed in as props, as well as any items that the
150
146
  user has created.
151
147
  */
152
- const allItems: TReqoreMultiSelectItem[] = useMemo(() => {
153
- const customItems: TReqoreMultiSelectItem[] = size(createdItems)
154
- ? [{ divider: true, label: 'Custom Items' }, ...createdItems]
155
- : [];
148
+ const allItems: TReqoreMultiSelectItem[] = useMemo(() => {
149
+ const customItems: TReqoreMultiSelectItem[] = size(createdItems)
150
+ ? [{ divider: true, label: 'Custom Items' }, ...createdItems]
151
+ : [];
156
152
 
157
- let filteredItems: TReqoreMultiSelectItem[] = [...items, ...customItems].filter((item) =>
158
- query
159
- ? item.divider
160
- ? false
161
- : (item.label || item.value)?.toString().toLowerCase().indexOf(query.toLowerCase()) !==
162
- -1
163
- : true
164
- );
153
+ let filteredItems: TReqoreMultiSelectItem[] = [...items, ...customItems].filter((item) =>
154
+ query
155
+ ? item.divider
156
+ ? false
157
+ : (item.label || item.value)?.toString().toLowerCase().indexOf(query.toLowerCase()) !== -1
158
+ : true
159
+ );
165
160
 
166
- // Mark selected items as selected
167
- filteredItems = filteredItems.map((item: TReqoreMultiSelectItem) => ({
168
- ...omit(item, ['actions', 'asBadge', 'rightIcon']),
169
- selected: value.includes(item.value),
170
- }));
161
+ // Mark selected items as selected
162
+ filteredItems = filteredItems.map((item: TReqoreMultiSelectItem) => ({
163
+ ...omit(item, ['actions', 'asBadge', 'rightIcon']),
164
+ selected: value.includes(item.value),
165
+ }));
171
166
 
172
- if (query && !size(filteredItems)) {
173
- filteredItems = [
174
- { label: 'No existing items found', readOnly: true, minimal: true, icon: 'ForbidLine' },
175
- ];
176
- }
167
+ if (query && !size(filteredItems)) {
168
+ filteredItems = [
169
+ { label: 'No existing items found', readOnly: true, minimal: true, icon: 'ForbidLine' },
170
+ ];
171
+ }
177
172
 
178
- // If there is a query and there are filtered items
179
- // and there is no item that exactly matches the query, add it to the list
180
- if (
181
- query &&
182
- !filteredItems.some((item: TReqoreMultiSelectItem) => item.value === query) &&
183
- canCreateItems
184
- ) {
185
- filteredItems = [
186
- {
187
- label: `Create new "${query}"`,
188
- value: query,
189
- isNew: true,
190
- icon: 'AddCircleLine',
191
- minimal: true,
192
- flat: false,
193
- effect: {
194
- gradient: {
195
- colors: {
196
- 0: 'success',
197
- 100: 'success:darken:1',
198
- },
173
+ // If there is a query and there are filtered items
174
+ // and there is no item that exactly matches the query, add it to the list
175
+ if (
176
+ query &&
177
+ !filteredItems.some((item: TReqoreMultiSelectItem) => item.value === query) &&
178
+ canCreateItems
179
+ ) {
180
+ filteredItems = [
181
+ {
182
+ label: `Create new "${query}"`,
183
+ value: query,
184
+ isNew: true,
185
+ icon: 'AddCircleLine',
186
+ minimal: true,
187
+ flat: false,
188
+ effect: {
189
+ gradient: {
190
+ colors: {
191
+ 0: 'success',
192
+ 100: 'success:darken:1',
199
193
  },
200
194
  },
201
195
  },
202
- { divider: true, label: 'Items matching your query' },
203
- ...filteredItems,
204
- ];
205
- }
196
+ },
197
+ { divider: true, label: 'Items matching your query' },
198
+ ...filteredItems,
199
+ ];
200
+ }
206
201
 
207
- return filteredItems;
208
- }, [items, createdItems, query, value]);
202
+ return filteredItems;
203
+ }, [items, createdItems, query, value]);
209
204
 
210
- const handleKeyDown = useCallback(
211
- (e: KeyboardEvent) => {
212
- if (e.key === 'Enter' && focused) {
213
- const item = [...items, ...createdItems].find((item) => item.value === query);
205
+ const handleKeyDown = useCallback(
206
+ (e: KeyboardEvent) => {
207
+ if (e.key === 'Enter' && focused) {
208
+ const item = [...items, ...createdItems].find((item) => item.value === query);
214
209
 
215
- if (item) {
216
- handleItemSelect(item);
217
- } else if (canCreateItems && query) {
218
- handleItemSelect({
219
- value: query,
220
- isNew: true,
221
- });
222
- }
210
+ if (item) {
211
+ handleItemSelect(item);
212
+ } else if (canCreateItems && query) {
213
+ handleItemSelect({
214
+ value: query,
215
+ isNew: true,
216
+ });
223
217
  }
224
- },
225
- [items, createdItems, query, canCreateItems, focused]
226
- );
218
+ }
219
+ },
220
+ [items, createdItems, query, canCreateItems, focused]
221
+ );
227
222
 
228
- const getItemByValue = useCallback(
229
- (value: string): TReqoreMultiSelectItem => {
230
- return [...items, ...createdItems].find((item) => item.value === value);
231
- },
232
- [items, createdItems, value]
233
- );
223
+ const getItemByValue = useCallback(
224
+ (value: string): TReqoreMultiSelectItem => {
225
+ return [...items, ...createdItems].find((item) => item.value === value);
226
+ },
227
+ [items, createdItems, value]
228
+ );
234
229
 
235
- return (
236
- <ReqoreControlGroup vertical fluid {...rest} ref={ref}>
237
- <ReqoreTagGroup minimal={rest.minimal} size={rest.size}>
238
- {size(value) ? (
239
- value.map((v) => (
240
- <ReqoreMultiSelectItem
241
- key={v}
242
- item={getItemByValue(v)}
243
- onItemClickIcon={onItemClickIcon}
244
- onRemoveClick={canRemoveItems ? () => addRemoveItem(getItemByValue(v)) : undefined}
245
- onClick={
246
- onItemClick
247
- ? () => {
248
- onItemClick(getItemByValue(v));
249
- }
250
- : undefined
251
- }
252
- selectedItemEffect={selectedItemEffect}
253
- selectedItemSize={selectedItemSize}
254
- />
255
- ))
256
- ) : (
257
- <ReqoreTag color='transparent' icon='ForbidLine' label='No items selected' />
258
- )}
259
- </ReqoreTagGroup>
260
- <ReqoreControlGroup minimal={rest.minimal} flat={rest.flat} size={rest.size}>
261
- <ReqoreDropdown<IReqoreInputProps>
262
- {...selectorProps}
263
- multiSelect
264
- handler='focus'
265
- onFocus={() => setFocused(true)}
266
- onBlur={() => setFocused(false)}
267
- passPopoverData={(data) => (popoverData.current = data)}
268
- component={ReqoreInput}
269
- onClearClick={() => setQuery('')}
270
- value={query}
271
- isDefaultOpen={openOnMount}
272
- onItemSelect={handleItemSelect}
273
- placeholder={
274
- canCreateItems ? 'Type to search or create an item...' : 'Type to search...'
275
- }
276
- onChange={(e: any) => setQuery(e.target.value)}
277
- items={
278
- size(allItems)
279
- ? allItems
280
- : canCreateItems
281
- ? [{ label: 'No items exist', readOnly: true, minimal: true, icon: 'ForbidLine' }]
282
- : []
283
- }
284
- useTargetWidth
285
- />
286
- </ReqoreControlGroup>
230
+ return (
231
+ <ReqoreControlGroup vertical fluid {...rest}>
232
+ <ReqoreTagGroup minimal={rest.minimal} size={rest.size}>
233
+ {size(value) ? (
234
+ value.map((v) => (
235
+ <ReqoreMultiSelectItem
236
+ key={v}
237
+ item={getItemByValue(v)}
238
+ onItemClickIcon={onItemClickIcon}
239
+ onRemoveClick={canRemoveItems ? () => addRemoveItem(getItemByValue(v)) : undefined}
240
+ onClick={
241
+ onItemClick
242
+ ? () => {
243
+ onItemClick(getItemByValue(v));
244
+ }
245
+ : undefined
246
+ }
247
+ selectedItemEffect={selectedItemEffect}
248
+ selectedItemSize={selectedItemSize}
249
+ />
250
+ ))
251
+ ) : (
252
+ <ReqoreTag color='transparent' icon='ForbidLine' label='No items selected' />
253
+ )}
254
+ </ReqoreTagGroup>
255
+ <ReqoreControlGroup minimal={rest.minimal} flat={rest.flat} size={rest.size}>
256
+ <ReqoreDropdown<IReqoreInputProps>
257
+ {...selectorProps}
258
+ multiSelect
259
+ handler='focus'
260
+ onFocus={() => setFocused(true)}
261
+ onBlur={() => setFocused(false)}
262
+ passPopoverData={(data) => (popoverData.current = data)}
263
+ component={ReqoreInput}
264
+ onClearClick={() => setQuery('')}
265
+ value={query}
266
+ isDefaultOpen={openOnMount}
267
+ onItemSelect={handleItemSelect}
268
+ placeholder={canCreateItems ? 'Type to search or create an item...' : 'Type to search...'}
269
+ onChange={(e: any) => setQuery(e.target.value)}
270
+ items={
271
+ size(allItems)
272
+ ? allItems
273
+ : canCreateItems
274
+ ? [{ label: 'No items exist', readOnly: true, minimal: true, icon: 'ForbidLine' }]
275
+ : []
276
+ }
277
+ useTargetWidth
278
+ />
287
279
  </ReqoreControlGroup>
288
- );
289
- }
290
- );
280
+ </ReqoreControlGroup>
281
+ );
282
+ };
@@ -1,9 +1,10 @@
1
1
  import { size } from 'lodash';
2
2
  import { darken, rgba } from 'polished';
3
- import { forwardRef, ReactElement, useCallback, useMemo, useState } from 'react';
3
+ import { ReactElement, forwardRef, useCallback, useMemo, useState } from 'react';
4
4
  import { useUpdateEffect } from 'react-use';
5
5
  import styled, { css } from 'styled-components';
6
6
  import {
7
+ GAP_FROM_SIZE,
7
8
  ICON_FROM_HEADER_SIZE,
8
9
  PADDING_FROM_SIZE,
9
10
  RADIUS_FROM_SIZE,
@@ -38,7 +39,7 @@ import { IReqoreDropdownItem } from '../Dropdown/list';
38
39
  import { IReqoreEffect, StyledEffect, TReqoreEffectColor } from '../Effect';
39
40
  import { ReqoreHeading } from '../Header';
40
41
  import ReqoreIcon, { StyledIconWrapper } from '../Icon';
41
- import { ReqoreSpacer } from '../Spacer';
42
+ import { ReqoreHorizontalSpacer, ReqoreSpacer } from '../Spacer';
42
43
 
43
44
  export interface IReqorePanelAction extends IReqoreButtonProps, IWithReqoreTooltip, IReqoreIntent {
44
45
  label?: string | number;
@@ -46,9 +47,11 @@ export interface IReqorePanelAction extends IReqoreButtonProps, IWithReqoreToolt
46
47
  actions?: Omit<IReqoreDropdownItem[], 'value'>;
47
48
  // Custom react element
48
49
  as?: React.ElementType;
49
- props?: any;
50
+ props?: { [key: string | number]: any } | undefined;
50
51
  // Hide the action if the condition is false
51
52
  show?: boolean;
53
+ // Hide the action if the group is too small
54
+ responsive?: boolean;
52
55
  }
53
56
 
54
57
  export interface IReqorePanelBottomAction extends IReqorePanelAction {
@@ -116,6 +119,7 @@ export const StyledPanel = styled(StyledEffect)<IStyledPanel>`
116
119
  backdrop-filter: ${({ blur, opacity }) => (blur && opacity < 1 ? `blur(${blur}px)` : undefined)};
117
120
  transition: 0.2s ease-in-out;
118
121
  width: ${({ fluid }) => (fluid ? '100%' : undefined)};
122
+ max-width: 100%;
119
123
  flex: ${({ fluid }) => (fluid ? '1 auto' : '0 0 auto')};
120
124
 
121
125
  ${({ interactive, theme, opacity = 1, flat, intent }) =>
@@ -240,10 +244,13 @@ export const StyledPanelContent = styled.div<IStyledPanel>`
240
244
 
241
245
  export const StyledPanelTitleHeader = styled.div`
242
246
  display: flex;
243
- justify-content: center;
247
+ justify-content: flex-start;
244
248
  align-items: center;
245
- overflow: hidden;
246
249
  padding-right: 5px;
250
+ flex: 1 1 auto;
251
+ width: 100%;
252
+ overflow: hidden;
253
+ min-width: 100px;
247
254
  `;
248
255
 
249
256
  export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
@@ -328,17 +335,56 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
328
335
  [leftBottomActions, rightBottomActions]
329
336
  );
330
337
 
331
- const renderActions = useCallback(
338
+ const renderResponsiveActions = useCallback(
332
339
  (actionOrActions: IReqorePanelAction | IReqorePanelAction[], index: number) => {
333
- if (Array.isArray(actionOrActions)) {
334
- return (
335
- <ReqoreControlGroup key={index} stack>
336
- {actionOrActions.map(renderActions)}
337
- </ReqoreControlGroup>
338
- );
339
- }
340
+ return renderActions(actionOrActions, index, true);
341
+ },
342
+ [actions]
343
+ );
344
+
345
+ const hasNonResponsiveActions = useCallback(
346
+ (data: (IReqorePanelAction[] | IReqorePanelAction)[]) =>
347
+ data.some((action) => !Array.isArray(action) && action.responsive === false),
348
+ [actions, bottomActions]
349
+ );
340
350
 
341
- if (actionOrActions.show === false) {
351
+ const hasResponsiveActions = useCallback(
352
+ (data: (IReqorePanelAction[] | IReqorePanelAction)[]) =>
353
+ data.some((action) => Array.isArray(action) || action.responsive !== false),
354
+ [actions, bottomActions]
355
+ );
356
+
357
+ const renderNonResponsiveActions = useCallback(
358
+ (actionOrActions: IReqorePanelAction | IReqorePanelAction[], index: number) => {
359
+ return renderActions(actionOrActions, index, false);
360
+ },
361
+ [actions]
362
+ );
363
+
364
+ const renderActions = useCallback(
365
+ (
366
+ actionOrActions: IReqorePanelAction | IReqorePanelAction[],
367
+ index: number,
368
+ includeResponsive
369
+ ) => {
370
+ const action: IReqorePanelAction = Array.isArray(actionOrActions)
371
+ ? {
372
+ show: true,
373
+ responsive: true,
374
+ as: ReqoreControlGroup,
375
+ props: {
376
+ stack: true,
377
+ fluid: true,
378
+ children: actionOrActions.map(renderActions),
379
+ },
380
+ }
381
+ : actionOrActions;
382
+
383
+ if (
384
+ action.show === false ||
385
+ (includeResponsive && action.responsive === false) ||
386
+ (!includeResponsive && (action.responsive === true || !('responsive' in action)))
387
+ ) {
342
388
  return null;
343
389
  }
344
390
 
@@ -349,20 +395,21 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
349
395
  intent,
350
396
  className,
351
397
  as: CustomElement,
352
- props,
398
+ props = {},
353
399
  ...rest
354
- }: IReqorePanelAction = actionOrActions;
400
+ }: IReqorePanelAction = action;
355
401
 
356
402
  if (size(actions)) {
357
403
  return (
358
404
  <ReqoreDropdown<IReqoreButtonProps>
359
405
  {...rest}
360
406
  key={index}
407
+ fixed
361
408
  label={label}
362
409
  items={actions}
363
410
  intent={intent}
364
411
  className={className}
365
- customTheme={theme}
412
+ customTheme={rest.customTheme || theme}
366
413
  onClick={(e: React.MouseEvent<HTMLButtonElement>) => e.stopPropagation()}
367
414
  id={id}
368
415
  />
@@ -372,9 +419,10 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
372
419
  if (CustomElement) {
373
420
  return (
374
421
  <CustomElement
422
+ fixed
375
423
  {...props}
376
424
  key={index}
377
- customTheme={theme}
425
+ customTheme={props.customTheme || theme}
378
426
  onClick={(e: React.MouseEvent<any>) => {
379
427
  e.stopPropagation();
380
428
  props?.onClick?.(e);
@@ -387,9 +435,10 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
387
435
  <ReqoreButton
388
436
  {...rest}
389
437
  id={id}
438
+ fixed
390
439
  key={index}
391
440
  className={className}
392
- customTheme={theme}
441
+ customTheme={rest.customTheme || theme}
393
442
  intent={intent}
394
443
  onClick={
395
444
  rest.onClick
@@ -494,27 +543,39 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
494
543
  </>
495
544
  ) : null}
496
545
  </StyledPanelTitleHeader>
497
- <ReqoreControlGroup>
498
- {actions.map(renderActions)}
499
- {collapsible && (
500
- <ReqoreButton
501
- customTheme={theme}
502
- icon={_isCollapsed ? 'ArrowDownSLine' : 'ArrowUpSLine'}
503
- onClick={handleCollapseClick}
504
- tooltip={_isCollapsed ? 'Expand' : 'Collapse'}
505
- />
506
- )}
507
- {onClose && (
508
- <ReqoreButton
509
- customTheme={theme}
510
- icon='CloseLine'
511
- onClick={(e: React.MouseEvent<HTMLButtonElement>) => {
512
- e.stopPropagation();
513
- onClose?.();
514
- }}
515
- />
516
- )}
517
- </ReqoreControlGroup>
546
+ {hasResponsiveActions(actions) && (
547
+ <ReqoreControlGroup responsive fluid horizontalAlign='flex-end' customTheme={theme}>
548
+ {actions.map(renderResponsiveActions)}
549
+ </ReqoreControlGroup>
550
+ )}
551
+ {collapsible || onClose || hasNonResponsiveActions(actions) ? (
552
+ <>
553
+ <ReqoreHorizontalSpacer width={GAP_FROM_SIZE.normal} />
554
+ <ReqoreControlGroup fixed horizontalAlign='flex-end'>
555
+ {actions.map(renderNonResponsiveActions)}
556
+ {collapsible && (
557
+ <ReqoreButton
558
+ customTheme={theme}
559
+ icon={_isCollapsed ? 'ArrowDownSLine' : 'ArrowUpSLine'}
560
+ onClick={handleCollapseClick}
561
+ tooltip={_isCollapsed ? 'Expand' : 'Collapse'}
562
+ fixed
563
+ />
564
+ )}
565
+ {onClose && (
566
+ <ReqoreButton
567
+ fixed
568
+ customTheme={theme}
569
+ icon='CloseLine'
570
+ onClick={(e: React.MouseEvent<HTMLButtonElement>) => {
571
+ e.stopPropagation();
572
+ onClose?.();
573
+ }}
574
+ />
575
+ )}
576
+ </ReqoreControlGroup>
577
+ </>
578
+ ) : null}
518
579
  </StyledPanelTitle>
519
580
  )}
520
581
  {!_isCollapsed || (_isCollapsed && !unMountContentOnCollapse) ? (
@@ -540,8 +601,32 @@ export const ReqorePanel = forwardRef<HTMLDivElement, IReqorePanelProps>(
540
601
  opacity={opacity ?? (minimal ? 0 : 1)}
541
602
  noHorizontalPadding={noHorizontalPadding}
542
603
  >
543
- <ReqoreControlGroup>{leftBottomActions.map(renderActions)}</ReqoreControlGroup>
544
- <ReqoreControlGroup>{rightBottomActions.map(renderActions)}</ReqoreControlGroup>
604
+ {hasNonResponsiveActions(leftBottomActions) ? (
605
+ <>
606
+ <ReqoreControlGroup>
607
+ {leftBottomActions.map(renderNonResponsiveActions)}
608
+ </ReqoreControlGroup>
609
+ <ReqoreHorizontalSpacer width={GAP_FROM_SIZE.normal} />
610
+ </>
611
+ ) : null}
612
+ {hasResponsiveActions(leftBottomActions) && (
613
+ <ReqoreControlGroup fluid responsive customTheme={theme}>
614
+ {leftBottomActions.map(renderResponsiveActions)}
615
+ </ReqoreControlGroup>
616
+ )}
617
+ {hasResponsiveActions(rightBottomActions) && (
618
+ <ReqoreControlGroup fluid horizontalAlign='flex-end' responsive customTheme={theme}>
619
+ {rightBottomActions.map(renderResponsiveActions)}
620
+ </ReqoreControlGroup>
621
+ )}
622
+ {hasNonResponsiveActions(rightBottomActions) ? (
623
+ <>
624
+ <ReqoreHorizontalSpacer width={GAP_FROM_SIZE.normal} />
625
+ <ReqoreControlGroup horizontalAlign='flex-end'>
626
+ {rightBottomActions.map(renderNonResponsiveActions)}
627
+ </ReqoreControlGroup>
628
+ </>
629
+ ) : null}
545
630
  </StyledPanelBottomActions>
546
631
  ) : null}
547
632
  </StyledPanel>