@qoretechnologies/reqore 0.29.8 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) 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__/popover.test.tsx +24 -2
  5. package/__tests__/tabs.test.tsx +32 -0
  6. package/dist/components/Button/index.js +6 -6
  7. package/dist/components/Button/index.js.map +1 -1
  8. package/dist/components/Collection/index.d.ts +3 -2
  9. package/dist/components/Collection/index.d.ts.map +1 -1
  10. package/dist/components/Collection/index.js +19 -44
  11. package/dist/components/Collection/index.js.map +1 -1
  12. package/dist/components/Collection/item.d.ts +2 -3
  13. package/dist/components/Collection/item.d.ts.map +1 -1
  14. package/dist/components/Collection/item.js +8 -4
  15. package/dist/components/Collection/item.js.map +1 -1
  16. package/dist/components/Columns/column.d.ts.map +1 -1
  17. package/dist/components/Columns/column.js +1 -1
  18. package/dist/components/Columns/column.js.map +1 -1
  19. package/dist/components/ControlGroup/index.d.ts +7 -4
  20. package/dist/components/ControlGroup/index.d.ts.map +1 -1
  21. package/dist/components/ControlGroup/index.js +118 -22
  22. package/dist/components/ControlGroup/index.js.map +1 -1
  23. package/dist/components/Drawer/index.d.ts.map +1 -1
  24. package/dist/components/Drawer/index.js +6 -4
  25. package/dist/components/Drawer/index.js.map +1 -1
  26. package/dist/components/Effect/index.d.ts.map +1 -1
  27. package/dist/components/Effect/index.js +1 -1
  28. package/dist/components/Effect/index.js.map +1 -1
  29. package/dist/components/Icon/index.d.ts +3 -5
  30. package/dist/components/Icon/index.d.ts.map +1 -1
  31. package/dist/components/Icon/index.js +10 -6
  32. package/dist/components/Icon/index.js.map +1 -1
  33. package/dist/components/Input/index.js +2 -2
  34. package/dist/components/Input/index.js.map +1 -1
  35. package/dist/components/InternalPopover/index.d.ts.map +1 -1
  36. package/dist/components/InternalPopover/index.js +5 -3
  37. package/dist/components/InternalPopover/index.js.map +1 -1
  38. package/dist/components/MultiSelect/index.d.ts +1 -1
  39. package/dist/components/MultiSelect/index.d.ts.map +1 -1
  40. package/dist/components/MultiSelect/index.js +10 -10
  41. package/dist/components/MultiSelect/index.js.map +1 -1
  42. package/dist/components/Panel/index.d.ts +6 -3
  43. package/dist/components/Panel/index.d.ts.map +1 -1
  44. package/dist/components/Panel/index.js +64 -32
  45. package/dist/components/Panel/index.js.map +1 -1
  46. package/dist/components/Spacer/index.d.ts +2 -0
  47. package/dist/components/Spacer/index.d.ts.map +1 -1
  48. package/dist/components/Spacer/index.js +29 -7
  49. package/dist/components/Spacer/index.js.map +1 -1
  50. package/dist/components/Tabs/content.d.ts +3 -1
  51. package/dist/components/Tabs/content.d.ts.map +1 -1
  52. package/dist/components/Tabs/content.js +8 -3
  53. package/dist/components/Tabs/content.js.map +1 -1
  54. package/dist/components/Tabs/index.d.ts +4 -1
  55. package/dist/components/Tabs/index.d.ts.map +1 -1
  56. package/dist/components/Tabs/index.js +12 -4
  57. package/dist/components/Tabs/index.js.map +1 -1
  58. package/dist/components/Tabs/item.d.ts +1 -0
  59. package/dist/components/Tabs/item.d.ts.map +1 -1
  60. package/dist/components/Tabs/item.js +7 -7
  61. package/dist/components/Tabs/item.js.map +1 -1
  62. package/dist/components/Tabs/list.d.ts +1 -1
  63. package/dist/components/Tabs/list.d.ts.map +1 -1
  64. package/dist/components/Tabs/list.js +3 -2
  65. package/dist/components/Tabs/list.js.map +1 -1
  66. package/dist/components/Tag/index.d.ts +3 -2
  67. package/dist/components/Tag/index.d.ts.map +1 -1
  68. package/dist/components/Tag/index.js +10 -2
  69. package/dist/components/Tag/index.js.map +1 -1
  70. package/dist/components/Tree/index.js +1 -1
  71. package/dist/components/Tree/index.js.map +1 -1
  72. package/dist/constants/animations.js +1 -1
  73. package/dist/constants/sizes.js +7 -7
  74. package/dist/containers/PopoverProvider.js +3 -3
  75. package/dist/containers/PopoverProvider.js.map +1 -1
  76. package/dist/containers/ReqoreProvider.d.ts.map +1 -1
  77. package/dist/containers/ReqoreProvider.js +1 -0
  78. package/dist/containers/ReqoreProvider.js.map +1 -1
  79. package/dist/containers/UIProvider.d.ts +7 -0
  80. package/dist/containers/UIProvider.d.ts.map +1 -1
  81. package/dist/containers/UIProvider.js.map +1 -1
  82. package/dist/context/ReqoreContext.d.ts +1 -0
  83. package/dist/context/ReqoreContext.d.ts.map +1 -1
  84. package/dist/context/ReqoreContext.js.map +1 -1
  85. package/dist/hooks/usePopover.d.ts.map +1 -1
  86. package/dist/hooks/usePopover.js +4 -2
  87. package/dist/hooks/usePopover.js.map +1 -1
  88. package/dist/types/global.d.ts +13 -0
  89. package/dist/types/global.d.ts.map +1 -1
  90. package/package.json +1 -1
  91. package/src/components/Button/index.tsx +2 -2
  92. package/src/components/Collection/index.tsx +29 -39
  93. package/src/components/Collection/item.tsx +14 -6
  94. package/src/components/Columns/column.tsx +1 -0
  95. package/src/components/ControlGroup/index.tsx +390 -227
  96. package/src/components/Drawer/index.tsx +6 -4
  97. package/src/components/Effect/index.tsx +1 -0
  98. package/src/components/Icon/index.tsx +78 -62
  99. package/src/components/Input/index.tsx +1 -1
  100. package/src/components/InternalPopover/index.tsx +127 -123
  101. package/src/components/MultiSelect/index.tsx +180 -188
  102. package/src/components/Panel/index.tsx +171 -77
  103. package/src/components/Spacer/index.tsx +63 -14
  104. package/src/components/Tabs/content.tsx +11 -3
  105. package/src/components/Tabs/index.tsx +14 -3
  106. package/src/components/Tabs/item.tsx +24 -1
  107. package/src/components/Tabs/list.tsx +3 -0
  108. package/src/components/Tag/index.tsx +30 -23
  109. package/src/components/Tree/index.tsx +1 -1
  110. package/src/constants/animations.ts +1 -1
  111. package/src/constants/sizes.ts +7 -7
  112. package/src/containers/PopoverProvider.tsx +3 -3
  113. package/src/containers/ReqoreProvider.tsx +1 -0
  114. package/src/containers/UIProvider.tsx +7 -0
  115. package/src/context/ReqoreContext.tsx +1 -0
  116. package/src/hooks/usePopover.tsx +4 -2
  117. package/src/mock/collectionData.tsx +21 -1
  118. package/src/stories/ControlGroup/ControlGroup.stories.tsx +68 -6
  119. package/src/stories/Icon/Icon.stories.tsx +1 -0
  120. package/src/stories/Input/Input.stories.tsx +2 -1
  121. package/src/stories/Panel/Panel.stories.tsx +83 -2
  122. package/src/stories/Popover/Popover.stories.tsx +5 -5
  123. package/src/stories/Tabs/Tabs.stories.tsx +30 -14
  124. package/src/stories/Tag/Tag.stories.tsx +12 -2
  125. package/src/types/global.ts +14 -0
  126. package/tests.json +1 -1
@@ -1,10 +1,15 @@
1
- import React, { forwardRef, memo, useCallback, useMemo } from 'react';
2
- import styled from 'styled-components';
1
+ import { debounce } from 'lodash';
2
+ import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
+ import { useMount, useUnmount } from 'react-use';
4
+ import styled, { css } from 'styled-components';
5
+ import { ReqoreButton, ReqoreModal } from '../..';
3
6
  import { GAP_FROM_SIZE, RADIUS_FROM_SIZE, TSizes } from '../../constants/sizes';
4
7
  import { IReqoreTheme } from '../../constants/theme';
5
8
  import {
6
9
  IReqoreIntent,
10
+ IWithReqoreCustomTheme,
7
11
  IWithReqoreFlat,
12
+ IWithReqoreFluid,
8
13
  IWithReqoreMinimal,
9
14
  IWithReqoreSize,
10
15
  } from '../../types/global';
@@ -14,16 +19,21 @@ export interface IReqoreControlGroupProps
14
19
  IWithReqoreFlat,
15
20
  IWithReqoreSize,
16
21
  IWithReqoreMinimal,
17
- IReqoreIntent {
22
+ IReqoreIntent,
23
+ IWithReqoreFluid,
24
+ IWithReqoreCustomTheme {
18
25
  stack?: boolean;
19
26
  children: any;
20
- fluid?: boolean;
27
+ fixed?: boolean;
21
28
  rounded?: boolean;
29
+ responsive?: boolean;
22
30
  gapSize?: TSizes;
23
31
  /*
24
32
  * Whether the contents of the control group should be stacked vertically
25
33
  */
26
34
  vertical?: boolean;
35
+ verticalAlign?: 'flex-start' | 'center' | 'flex-end';
36
+ horizontalAlign?: 'flex-start' | 'center' | 'flex-end';
27
37
  wrap?: boolean;
28
38
  isInsideStackGroup?: boolean;
29
39
  isInsideVerticalGroup?: boolean;
@@ -46,162 +56,211 @@ export interface IReqoreControlGroupStyle extends IReqoreControlGroupProps {
46
56
  export const StyledReqoreControlGroup = styled.div<IReqoreControlGroupStyle>`
47
57
  display: flex;
48
58
  flex: 0 auto;
49
- width: ${({ fluid }) => (fluid ? '100%' : undefined)};
50
- align-items: ${({ fluid }) => (fluid ? 'stretch' : 'flex-start')};
59
+ width: ${({ fluid, fixed }) => (fluid && !fixed ? '100%' : undefined)};
60
+ justify-content: ${({ fluid, vertical }) => (vertical && fluid ? 'stretch' : undefined)};
61
+ align-items: ${({ vertical, fluid, horizontalAlign }) =>
62
+ vertical ? (fluid ? 'stretch' : horizontalAlign) : undefined};
51
63
  flex-flow: ${({ vertical }) => (vertical ? 'column' : 'row')};
52
64
  gap: ${({ gapSize, stack }) => (!stack ? `${GAP_FROM_SIZE[gapSize]}px` : undefined)};
53
65
  flex-wrap: ${({ wrap }) => (wrap ? 'wrap' : 'nowrap')};
54
66
 
67
+ > * {
68
+ margin-top: ${({ verticalAlign }) =>
69
+ verticalAlign === 'flex-end' || verticalAlign === 'center' ? 'auto' : undefined};
70
+ margin-bottom: ${({ verticalAlign }) =>
71
+ verticalAlign === 'flex-start' || verticalAlign === 'center' ? 'auto' : undefined};
72
+ margin-right: ${({ horizontalAlign }) => (horizontalAlign === 'center' ? 'auto' : undefined)};
73
+
74
+ ${({ vertical }) =>
75
+ vertical &&
76
+ css`
77
+ margin-left: ${({ horizontalAlign }) =>
78
+ horizontalAlign === 'flex-end' || horizontalAlign === 'center' ? 'auto' : undefined};
79
+ `}
80
+ }
81
+
82
+ ${({ vertical }) =>
83
+ !vertical &&
84
+ css`
85
+ > *:first-child {
86
+ margin-left: ${({ horizontalAlign }) =>
87
+ horizontalAlign === 'flex-end' || horizontalAlign === 'center' ? 'auto' : undefined};
88
+ }
89
+ `}
90
+
55
91
  > * {
56
92
  border-radius: ${({ stack }) => (!stack ? undefined : 0)};
57
93
  }
58
94
  `;
59
95
 
60
96
  const ReqoreControlGroup = memo(
61
- forwardRef<HTMLDivElement, IReqoreControlGroupProps>(
62
- (
63
- {
64
- children,
65
- className,
66
- minimal,
67
- size = 'normal',
68
- gapSize = 'normal',
69
- fluid,
70
- flat,
71
- rounded = true,
72
- wrap,
73
- stack,
74
- isInsideStackGroup,
75
- isInsideVerticalGroup,
76
- isFirstInLastGroup,
77
- isLastInFirstGroup,
78
- isLastInLastGroup,
79
- intent,
80
- isFirst,
81
- isLast,
82
- vertical,
83
- childrenCount,
84
- childId,
85
- isChild,
86
- isFirstGroup,
87
- isLastGroup,
88
- ...rest
89
- }: IReqoreControlGroupProps,
90
- ref
91
- ) => {
92
- const isStack = stack || isInsideStackGroup;
93
- const isVertical = vertical || isInsideVerticalGroup;
94
- const realChildCount = useMemo((): number => {
95
- let count = 0;
96
-
97
- const countChildren = (children: React.ReactNode) =>
98
- React.Children.forEach(children, (child: any) => {
99
- if (child && React.isValidElement(child)) {
100
- if (child.type === React.Fragment) {
101
- // just compare to `React.Fragment`
102
- countChildren((child.props as any).children);
103
- } else {
104
- count++;
105
- }
97
+ ({
98
+ children,
99
+ className,
100
+ minimal,
101
+ size = 'normal',
102
+ gapSize = 'normal',
103
+ fluid,
104
+ flat,
105
+ fixed,
106
+ rounded = true,
107
+ wrap,
108
+ stack,
109
+ isInsideStackGroup,
110
+ isInsideVerticalGroup,
111
+ isFirstInLastGroup,
112
+ isLastInFirstGroup,
113
+ isLastInLastGroup,
114
+ intent,
115
+ customTheme,
116
+ isFirst,
117
+ isLast,
118
+ vertical,
119
+ childrenCount,
120
+ childId,
121
+ isChild,
122
+ isFirstGroup,
123
+ isLastGroup,
124
+ verticalAlign = 'center',
125
+ horizontalAlign = 'flex-start',
126
+ responsive,
127
+ ...rest
128
+ }: IReqoreControlGroupProps) => {
129
+ const isStack = stack || isInsideStackGroup;
130
+ const isVertical = vertical || isInsideVerticalGroup;
131
+
132
+ const [overflowingChildren, setOverflowingChildren] = useState<number | undefined>(0);
133
+ const [lastReSize, setLastReSize] = useState<number>(0);
134
+ const [isResizing, setIsResizing] = useState<boolean>(false);
135
+ const [isOverflownDialogOpen, setIsOverflownDialogOpen] = useState<boolean>(false);
136
+ const observer = useRef<ResizeObserver | null>(null);
137
+ const ref = useRef<HTMLDivElement>(null);
138
+ const resizeTimerObserver = useRef<ResizeObserver | null>(null);
139
+ const resizingTimer = useRef<any>(null);
140
+
141
+ const realChildCount = useMemo((): number => {
142
+ let count = 0;
143
+
144
+ const countChildren = (children: React.ReactNode) =>
145
+ React.Children.forEach(children, (child: any) => {
146
+ if (child && React.isValidElement(child)) {
147
+ if (child.type === React.Fragment) {
148
+ // just compare to `React.Fragment`
149
+ countChildren((child.props as any).children);
150
+ } else {
151
+ count++;
106
152
  }
107
- });
108
-
109
- countChildren(children);
110
-
111
- return count < 0 ? 0 : count;
112
- }, [children]);
113
-
114
- const getIsFirst = (index: number): boolean => {
115
- return !isInsideStackGroup || childrenCount === 1
116
- ? index === 0
117
- : (isFirst || isFirst !== false) && index === 0;
118
- };
119
- const getIsLast = (index: number): boolean => {
120
- return !isInsideStackGroup
121
- ? index === realChildCount - 1
122
- : (isLast || isLast !== false) && index === realChildCount - 1;
123
- };
124
- const getIsLastInFirstGroup = (index: number): boolean => {
125
- return !isInsideStackGroup
126
- ? index === 0
127
- : isFirstGroup && (isLast || isLast !== false) && index === realChildCount - 1;
128
- };
129
- const getIsFirstInLastGroup = (index: number): boolean => {
130
- return !isInsideStackGroup
131
- ? index === realChildCount - 1
132
- : isLastGroup && (isFirst || isFirst !== false) && childId === 1 && index === 0;
133
- };
134
- const getIsLastInLastGroup = (index: number): boolean => {
135
- return !isInsideStackGroup
136
- ? index === realChildCount - 1
137
- : isLastGroup && (isLast || isLast !== false) && index === realChildCount - 1;
138
- };
139
-
140
- const getBorderTopLeftRadius = (index: number): number | undefined => {
141
- const _isFirstGroup =
142
- !isInsideStackGroup || childrenCount === 1 ? true : isChild ? isFirstGroup : index === 0;
143
-
144
- // If this is the first item
145
- if (_isFirstGroup && getIsFirst(index)) {
146
- return RADIUS_FROM_SIZE[size];
147
- }
148
-
149
- return undefined;
150
- };
151
-
152
- const getBorderTopRightRadius = (index: number): number | undefined => {
153
- // If this group is not vertical we need to style the very last item
154
- if (!isVertical || !isStack) {
155
- const _isLastGroup =
156
- !isInsideStackGroup || childrenCount === 1
157
- ? true
158
- : isChild
159
- ? isLastGroup
160
- : index === realChildCount - 1;
161
-
162
- if (_isLastGroup && getIsLast(index)) {
163
- return RADIUS_FROM_SIZE[size];
164
153
  }
154
+ });
165
155
 
166
- return undefined;
167
- }
168
-
169
- // This border only needs to apply when this group is vertical
170
- // AND this item is the last item of the first group
171
- if (getIsLastInFirstGroup(index)) {
172
- return RADIUS_FROM_SIZE[size];
173
- }
156
+ countChildren(children);
174
157
 
175
- return undefined;
176
- };
177
-
178
- const getBorderBottomLeftRadius = (index: number): number | undefined => {
179
- // If this group is not vertical we need to style the very first item
180
- if (!isVertical || !isStack) {
181
- const _isFirstGroup =
182
- !isInsideStackGroup || childrenCount === 1
183
- ? true
184
- : isChild
185
- ? isFirstGroup
186
- : index === 0;
187
-
188
- if (_isFirstGroup && getIsFirst(index)) {
189
- return RADIUS_FROM_SIZE[size];
190
- }
158
+ return count < 0 ? 0 : count;
159
+ }, [children]);
191
160
 
192
- return undefined;
193
- }
161
+ const checkIfOverflowing = useCallback(() => {
162
+ return (
163
+ ref.current.clientWidth > 40 &&
164
+ !vertical &&
165
+ responsive &&
166
+ ref.current &&
167
+ ref.current.scrollWidth > ref.current.clientWidth
168
+ );
169
+ }, [vertical, responsive, ref, children]);
170
+
171
+ useMount(() => {
172
+ if (!vertical && responsive) {
173
+ if ('ResizeObserver' in window) {
174
+ observer.current = new ResizeObserver(
175
+ debounce(() => {
176
+ if (ref && ref.current) {
177
+ setOverflowingChildren(0);
178
+ setLastReSize(ref.current.clientWidth);
179
+ }
180
+ }, 200)
181
+ );
182
+
183
+ resizeTimerObserver.current = new ResizeObserver(() => {
184
+ if (ref && ref.current) {
185
+ setIsResizing(true);
186
+ clearTimeout(resizingTimer.current);
187
+ resizingTimer.current = setTimeout(() => {
188
+ setIsResizing(false);
189
+ }, 500);
190
+ }
191
+ });
194
192
 
195
- // This border only needs to apply when this group is vertical
196
- // AND this item is the first item of the last group
197
- if (getIsFirstInLastGroup(index)) {
198
- return RADIUS_FROM_SIZE[size];
193
+ observer.current.observe(ref.current);
194
+ resizeTimerObserver.current.observe(ref.current);
199
195
  }
200
-
201
- return undefined;
202
- };
203
-
204
- const getBorderBottomRightRadius = (index: number): number | undefined => {
196
+ }
197
+ });
198
+
199
+ useUnmount(() => {
200
+ if (observer.current) {
201
+ observer.current.disconnect();
202
+ }
203
+
204
+ if (resizeTimerObserver.current) {
205
+ resizeTimerObserver.current.disconnect();
206
+ }
207
+
208
+ clearTimeout(resizingTimer.current);
209
+ });
210
+
211
+ useEffect(() => {
212
+ // Is the control group still overflowing?
213
+ if ((overflowingChildren || overflowingChildren === 0) && checkIfOverflowing()) {
214
+ setOverflowingChildren(overflowingChildren + 1);
215
+ }
216
+
217
+ // Hide the dialog if the group was resized and the dialog was open
218
+ if (overflowingChildren === 0) {
219
+ setIsOverflownDialogOpen(false);
220
+ }
221
+ }, [overflowingChildren, lastReSize]);
222
+
223
+ const getIsFirst = (index: number): boolean => {
224
+ return !isInsideStackGroup || childrenCount === 1
225
+ ? index === 0
226
+ : (isFirst || isFirst !== false) && index === 0;
227
+ };
228
+ const getIsLast = (index: number): boolean => {
229
+ return !isInsideStackGroup
230
+ ? index === realChildCount - 1
231
+ : (isLast || isLast !== false) && index === realChildCount - 1;
232
+ };
233
+ const getIsLastInFirstGroup = (index: number): boolean => {
234
+ return !isInsideStackGroup
235
+ ? index === 0
236
+ : isFirstGroup && (isLast || isLast !== false) && index === realChildCount - 1;
237
+ };
238
+ const getIsFirstInLastGroup = (index: number): boolean => {
239
+ return !isInsideStackGroup
240
+ ? index === realChildCount - 1
241
+ : isLastGroup && (isFirst || isFirst !== false) && childId === 1 && index === 0;
242
+ };
243
+ const getIsLastInLastGroup = (index: number): boolean => {
244
+ return !isInsideStackGroup
245
+ ? index === realChildCount - 1
246
+ : isLastGroup && (isLast || isLast !== false) && index === realChildCount - 1;
247
+ };
248
+
249
+ const getBorderTopLeftRadius = (index: number): number | undefined => {
250
+ const _isFirstGroup =
251
+ !isInsideStackGroup || childrenCount === 1 ? true : isChild ? isFirstGroup : index === 0;
252
+
253
+ // If this is the first item
254
+ if (_isFirstGroup && getIsFirst(index)) {
255
+ return RADIUS_FROM_SIZE[size];
256
+ }
257
+
258
+ return undefined;
259
+ };
260
+
261
+ const getBorderTopRightRadius = (index: number): number | undefined => {
262
+ // If this group is not vertical we need to style the very last item
263
+ if (!isVertical || !isStack) {
205
264
  const _isLastGroup =
206
265
  !isInsideStackGroup || childrenCount === 1
207
266
  ? true
@@ -209,117 +268,221 @@ const ReqoreControlGroup = memo(
209
268
  ? isLastGroup
210
269
  : index === realChildCount - 1;
211
270
 
212
- // If this is the last item
213
271
  if (_isLastGroup && getIsLast(index)) {
214
272
  return RADIUS_FROM_SIZE[size];
215
273
  }
216
274
 
217
275
  return undefined;
218
- };
276
+ }
219
277
 
220
- let index = 0;
278
+ // This border only needs to apply when this group is vertical
279
+ // AND this item is the last item of the first group
280
+ if (getIsLastInFirstGroup(index)) {
281
+ return RADIUS_FROM_SIZE[size];
282
+ }
221
283
 
222
- const cloneThroughFragments = useCallback(
223
- (children: React.ReactNode): React.ReactNode => {
224
- return React.Children.map(children, (child) => {
225
- if (child && React.isValidElement(child)) {
226
- if (child.type === React.Fragment) {
227
- // just compare to `React.Fragment`
228
- return cloneThroughFragments(child.props.children);
229
- }
284
+ return undefined;
285
+ };
230
286
 
231
- let newProps = {
232
- ...child.props,
233
- key: index,
234
- minimal:
235
- child.props?.minimal || child.props?.minimal === false
236
- ? child.props.minimal
237
- : minimal,
238
- size: child.props?.size || size,
239
- flat: child.props?.flat || child.props?.flat === false ? child.props.flat : flat,
240
- fluid:
241
- child.props?.fluid || child.props?.fluid === false ? child.props.fluid : fluid,
242
- stack:
243
- child.props?.stack || child.props?.stack === false ? child.props.stack : isStack,
244
- intent: child.props?.intent || intent,
245
- };
287
+ const getBorderBottomLeftRadius = (index: number): number | undefined => {
288
+ // If this group is not vertical we need to style the very first item
289
+ if (!isVertical || !isStack) {
290
+ const _isFirstGroup =
291
+ !isInsideStackGroup || childrenCount === 1 ? true : isChild ? isFirstGroup : index === 0;
246
292
 
247
- if (isStack) {
248
- newProps = {
249
- ...newProps,
250
- style: {
251
- borderTopLeftRadius: getBorderTopLeftRadius(index),
252
- borderBottomLeftRadius: getBorderBottomLeftRadius(index),
253
- borderTopRightRadius: getBorderTopRightRadius(index),
254
- borderBottomRightRadius: getBorderBottomRightRadius(index),
255
- ...(child.props?.style || {}),
256
- },
257
- rounded: !isStack,
258
- isInsideStackGroup: isStack,
259
- isInsideVerticalGroup: isVertical,
260
- isFirst: isChild ? getIsFirst(index) : undefined,
261
- isLast: isChild ? getIsLast(index) : undefined,
262
- isLastInFirstGroup: getIsLastInFirstGroup(index),
263
- isLastInLastGroup: getIsLastInLastGroup(index),
264
- isFirstInLastGroup: getIsFirstInLastGroup(index),
265
- childrenCount: realChildCount,
266
- childId: index + 1,
267
- isChild: true,
268
- isFirstGroup: isChild ? isFirstGroup : index === 0,
269
- isLastGroup: isChild ? isLastGroup : index === realChildCount - 1,
270
- };
271
- }
293
+ if (_isFirstGroup && getIsFirst(index)) {
294
+ return RADIUS_FROM_SIZE[size];
295
+ }
272
296
 
273
- /*
274
- * Because of the way React.Children.map works, we have to
275
- * manually decrement the index for every child that is `null`
276
- * because react maps through null children and returns them in `Count`
277
- * We filter these children out in the `realChildCount` variable,
278
- * but the index is still incremented
279
- * */
280
- index = index + 1;
297
+ return undefined;
298
+ }
299
+
300
+ // This border only needs to apply when this group is vertical
301
+ // AND this item is the first item of the last group
302
+ if (getIsFirstInLastGroup(index)) {
303
+ return RADIUS_FROM_SIZE[size];
304
+ }
305
+
306
+ return undefined;
307
+ };
308
+
309
+ const getBorderBottomRightRadius = (index: number): number | undefined => {
310
+ const _isLastGroup =
311
+ !isInsideStackGroup || childrenCount === 1
312
+ ? true
313
+ : isChild
314
+ ? isLastGroup
315
+ : index === realChildCount - 1;
316
+
317
+ // If this is the last item
318
+ if (_isLastGroup && getIsLast(index)) {
319
+ return RADIUS_FROM_SIZE[size];
320
+ }
321
+
322
+ return undefined;
323
+ };
324
+
325
+ let index = 0;
326
+
327
+ const cloneThroughFragments = useCallback(
328
+ (children: React.ReactNode): React.ReactNode => {
329
+ return React.Children.map(children, (child) => {
330
+ if (child && React.isValidElement(child)) {
331
+ if (child.type === React.Fragment) {
332
+ // just compare to `React.Fragment`
333
+ return cloneThroughFragments(child.props.children);
334
+ }
281
335
 
282
- return React.cloneElement(child, newProps);
336
+ let newProps = {
337
+ ...child.props,
338
+ key: index,
339
+ minimal:
340
+ child.props?.minimal || child.props?.minimal === false
341
+ ? child.props.minimal
342
+ : minimal,
343
+ size: child.props?.size || size,
344
+ flat: child.props?.flat || child.props?.flat === false ? child.props.flat : flat,
345
+ fluid: child.props?.fluid || child.props?.fluid === false ? child.props.fluid : fluid,
346
+ fixed: child.props?.fixed || child.props?.fixed === false ? child.props.fixed : fixed,
347
+ stack:
348
+ child.props?.stack || child.props?.stack === false ? child.props.stack : isStack,
349
+ intent: child.props?.intent || intent,
350
+ customTheme: child.props?.customTheme || customTheme,
351
+ };
352
+
353
+ if (isStack) {
354
+ newProps = {
355
+ ...newProps,
356
+ style: {
357
+ borderTopLeftRadius: getBorderTopLeftRadius(index),
358
+ borderBottomLeftRadius: getBorderBottomLeftRadius(index),
359
+ borderTopRightRadius: getBorderTopRightRadius(index),
360
+ borderBottomRightRadius: getBorderBottomRightRadius(index),
361
+ ...(child.props?.style || {}),
362
+ },
363
+ isChild: true,
364
+ rounded: !isStack,
365
+ isInsideStackGroup: isStack,
366
+ isInsideVerticalGroup: isVertical,
367
+ isFirst: isChild ? getIsFirst(index) : undefined,
368
+ isLast: isChild ? getIsLast(index) : undefined,
369
+ isLastInFirstGroup: getIsLastInFirstGroup(index),
370
+ isLastInLastGroup: getIsLastInLastGroup(index),
371
+ isFirstInLastGroup: getIsFirstInLastGroup(index),
372
+ childrenCount: realChildCount,
373
+ childId: index + 1,
374
+
375
+ isFirstGroup: isChild ? isFirstGroup : index === 0,
376
+ isLastGroup: isChild ? isLastGroup : index === realChildCount - 1,
377
+ };
283
378
  }
284
379
 
285
- return child;
286
- });
287
- },
288
- [
289
- children,
290
- isStack,
291
- isVertical,
292
- isChild,
293
- isLastGroup,
294
- isFirstGroup,
295
- realChildCount,
296
- index,
297
- fluid,
298
- flat,
299
- minimal,
300
- size,
301
- intent,
302
- ]
303
- );
380
+ /*
381
+ * Because of the way React.Children.map works, we have to
382
+ * manually decrement the index for every child that is `null`
383
+ * because react maps through null children and returns them in `Count`
384
+ * We filter these children out in the `realChildCount` variable,
385
+ * but the index is still incremented
386
+ * */
387
+ index = index + 1;
304
388
 
305
- return (
389
+ return React.cloneElement(child, newProps);
390
+ }
391
+
392
+ return child;
393
+ });
394
+ },
395
+ [
396
+ children,
397
+ isStack,
398
+ isVertical,
399
+ isChild,
400
+ isLastGroup,
401
+ isFirstGroup,
402
+ realChildCount,
403
+ index,
404
+ fluid,
405
+ flat,
406
+ minimal,
407
+ size,
408
+ intent,
409
+ ]
410
+ );
411
+
412
+ // Get the overflown children
413
+ const overflownChildren = useMemo(
414
+ () =>
415
+ overflowingChildren ? React.Children.toArray(children).slice(0, overflowingChildren) : [],
416
+ [children, overflowingChildren]
417
+ );
418
+
419
+ // Remove the overflowing children count from the start of the children array
420
+ const _children = useMemo(
421
+ () =>
422
+ overflowingChildren && responsive
423
+ ? [
424
+ children.slice(overflowingChildren),
425
+ <ReqoreButton
426
+ icon='MenuLine'
427
+ customTheme={customTheme}
428
+ tooltip={{
429
+ content: `Show ${React.Children.count(overflownChildren)} hidden items`,
430
+ closeOnAnyClick: true,
431
+ }}
432
+ fixed
433
+ onClick={(e: React.MouseEvent<HTMLButtonElement>) => {
434
+ e.stopPropagation();
435
+ setIsOverflownDialogOpen(true);
436
+ }}
437
+ flat
438
+ />,
439
+ ]
440
+ : children,
441
+ [children, overflowingChildren, responsive, overflownChildren]
442
+ );
443
+
444
+ return (
445
+ <>
446
+ {isOverflownDialogOpen ? (
447
+ <ReqoreModal
448
+ isOpen
449
+ onClose={() => setIsOverflownDialogOpen(false)}
450
+ flat
451
+ minimal
452
+ hasBackdrop={false}
453
+ intent='info'
454
+ label='Hidden items'
455
+ >
456
+ <ReqoreControlGroup fluid wrap>
457
+ {overflownChildren}
458
+ </ReqoreControlGroup>
459
+ </ReqoreModal>
460
+ ) : null}
306
461
  <StyledReqoreControlGroup
307
462
  {...rest}
308
463
  vertical={vertical}
464
+ style={{
465
+ overflowX: responsive ? 'auto' : undefined,
466
+ visibility: isResizing ? 'hidden' : undefined,
467
+ ...rest.style,
468
+ }}
309
469
  size={size}
310
470
  gapSize={gapSize}
311
471
  ref={ref}
312
472
  rounded={rounded}
313
473
  fluid={fluid}
474
+ fixed={fixed}
314
475
  wrap={wrap}
315
476
  stack={isStack}
477
+ verticalAlign={verticalAlign}
478
+ horizontalAlign={horizontalAlign}
316
479
  className={`${className || ''} reqore-control-group`}
317
480
  >
318
- {cloneThroughFragments(children)}
481
+ {cloneThroughFragments(_children)}
319
482
  </StyledReqoreControlGroup>
320
- );
321
- }
322
- )
483
+ </>
484
+ );
485
+ }
323
486
  );
324
487
 
325
488
  export default ReqoreControlGroup;