@qoretechnologies/reqore 0.30.6 → 0.30.8

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 (215) hide show
  1. package/CODE_OF_CONDUCT.md +104 -104
  2. package/CONTRIBUTING.MD +78 -78
  3. package/LICENSE +1 -1
  4. package/README.md +1 -1
  5. package/SECURITY.md +5 -5
  6. package/__tests__/collection.test.tsx +1 -1
  7. package/__tests__/{control_group.text.tsx → control_group.test.tsx} +4 -2
  8. package/__tests__/modal.test.tsx +74 -2
  9. package/__tests__/panel.test.tsx +96 -24
  10. package/__tests__/popover.test.tsx +24 -2
  11. package/__tests__/tabs.test.tsx +75 -0
  12. package/dist/components/Button/index.d.ts +6 -1
  13. package/dist/components/Button/index.d.ts.map +1 -1
  14. package/dist/components/Button/index.js +30 -20
  15. package/dist/components/Button/index.js.map +1 -1
  16. package/dist/components/Checkbox/index.d.ts.map +1 -1
  17. package/dist/components/Checkbox/index.js +6 -3
  18. package/dist/components/Checkbox/index.js.map +1 -1
  19. package/dist/components/Collection/index.d.ts +7 -2
  20. package/dist/components/Collection/index.d.ts.map +1 -1
  21. package/dist/components/Collection/index.js +57 -53
  22. package/dist/components/Collection/index.js.map +1 -1
  23. package/dist/components/Collection/item.d.ts +5 -5
  24. package/dist/components/Collection/item.d.ts.map +1 -1
  25. package/dist/components/Collection/item.js +15 -4
  26. package/dist/components/Collection/item.js.map +1 -1
  27. package/dist/components/Columns/column.d.ts.map +1 -1
  28. package/dist/components/Columns/column.js +1 -1
  29. package/dist/components/Columns/column.js.map +1 -1
  30. package/dist/components/ControlGroup/index.d.ts +21 -4
  31. package/dist/components/ControlGroup/index.d.ts.map +1 -1
  32. package/dist/components/ControlGroup/index.js +250 -55
  33. package/dist/components/ControlGroup/index.js.map +1 -1
  34. package/dist/components/Drawer/index.d.ts +2 -2
  35. package/dist/components/Drawer/index.d.ts.map +1 -1
  36. package/dist/components/Drawer/index.js +27 -16
  37. package/dist/components/Drawer/index.js.map +1 -1
  38. package/dist/components/Dropdown/index.d.ts +1 -0
  39. package/dist/components/Dropdown/index.d.ts.map +1 -1
  40. package/dist/components/Dropdown/index.js +2 -2
  41. package/dist/components/Dropdown/index.js.map +1 -1
  42. package/dist/components/Effect/index.d.ts +1 -1
  43. package/dist/components/Effect/index.d.ts.map +1 -1
  44. package/dist/components/Effect/index.js +7 -6
  45. package/dist/components/Effect/index.js.map +1 -1
  46. package/dist/components/Icon/index.d.ts +5 -6
  47. package/dist/components/Icon/index.d.ts.map +1 -1
  48. package/dist/components/Icon/index.js +14 -7
  49. package/dist/components/Icon/index.js.map +1 -1
  50. package/dist/components/Input/index.d.ts +2 -0
  51. package/dist/components/Input/index.d.ts.map +1 -1
  52. package/dist/components/Input/index.js +10 -4
  53. package/dist/components/Input/index.js.map +1 -1
  54. package/dist/components/InternalPopover/index.d.ts.map +1 -1
  55. package/dist/components/InternalPopover/index.js +12 -10
  56. package/dist/components/InternalPopover/index.js.map +1 -1
  57. package/dist/components/Menu/index.d.ts.map +1 -1
  58. package/dist/components/Menu/index.js +1 -1
  59. package/dist/components/Menu/index.js.map +1 -1
  60. package/dist/components/Message/index.d.ts +2 -0
  61. package/dist/components/Message/index.d.ts.map +1 -1
  62. package/dist/components/Message/index.js +2 -2
  63. package/dist/components/Message/index.js.map +1 -1
  64. package/dist/components/MultiSelect/index.d.ts +1 -1
  65. package/dist/components/MultiSelect/index.d.ts.map +1 -1
  66. package/dist/components/MultiSelect/index.js +10 -10
  67. package/dist/components/MultiSelect/index.js.map +1 -1
  68. package/dist/components/Panel/index.d.ts +13 -6
  69. package/dist/components/Panel/index.d.ts.map +1 -1
  70. package/dist/components/Panel/index.js +78 -44
  71. package/dist/components/Panel/index.js.map +1 -1
  72. package/dist/components/Popover/index.d.ts +1 -2
  73. package/dist/components/Popover/index.d.ts.map +1 -1
  74. package/dist/components/Popover/index.js +2 -2
  75. package/dist/components/Popover/index.js.map +1 -1
  76. package/dist/components/Spacer/index.d.ts +2 -0
  77. package/dist/components/Spacer/index.d.ts.map +1 -1
  78. package/dist/components/Spacer/index.js +29 -7
  79. package/dist/components/Spacer/index.js.map +1 -1
  80. package/dist/components/Table/header.js +2 -2
  81. package/dist/components/Table/header.js.map +1 -1
  82. package/dist/components/Table/headerCell.js +2 -2
  83. package/dist/components/Table/headerCell.js.map +1 -1
  84. package/dist/components/Table/helpers.d.ts +3 -2
  85. package/dist/components/Table/helpers.d.ts.map +1 -1
  86. package/dist/components/Table/helpers.js +6 -3
  87. package/dist/components/Table/helpers.js.map +1 -1
  88. package/dist/components/Table/index.d.ts +1 -0
  89. package/dist/components/Table/index.d.ts.map +1 -1
  90. package/dist/components/Table/index.js.map +1 -1
  91. package/dist/components/Table/row.d.ts +0 -5
  92. package/dist/components/Table/row.d.ts.map +1 -1
  93. package/dist/components/Table/row.js +3 -7
  94. package/dist/components/Table/row.js.map +1 -1
  95. package/dist/components/Tabs/content.d.ts +3 -1
  96. package/dist/components/Tabs/content.d.ts.map +1 -1
  97. package/dist/components/Tabs/content.js +8 -3
  98. package/dist/components/Tabs/content.js.map +1 -1
  99. package/dist/components/Tabs/index.d.ts +4 -1
  100. package/dist/components/Tabs/index.d.ts.map +1 -1
  101. package/dist/components/Tabs/index.js +12 -4
  102. package/dist/components/Tabs/index.js.map +1 -1
  103. package/dist/components/Tabs/item.d.ts +1 -0
  104. package/dist/components/Tabs/item.d.ts.map +1 -1
  105. package/dist/components/Tabs/item.js +7 -7
  106. package/dist/components/Tabs/item.js.map +1 -1
  107. package/dist/components/Tabs/list.d.ts +1 -1
  108. package/dist/components/Tabs/list.d.ts.map +1 -1
  109. package/dist/components/Tabs/list.js +7 -6
  110. package/dist/components/Tabs/list.js.map +1 -1
  111. package/dist/components/Tag/group.d.ts +2 -2
  112. package/dist/components/Tag/group.d.ts.map +1 -1
  113. package/dist/components/Tag/group.js +7 -8
  114. package/dist/components/Tag/group.js.map +1 -1
  115. package/dist/components/Tag/index.d.ts +6 -2
  116. package/dist/components/Tag/index.d.ts.map +1 -1
  117. package/dist/components/Tag/index.js +24 -12
  118. package/dist/components/Tag/index.js.map +1 -1
  119. package/dist/components/Tree/index.js +1 -1
  120. package/dist/components/Tree/index.js.map +1 -1
  121. package/dist/constants/animations.js +1 -1
  122. package/dist/constants/sizes.js +10 -10
  123. package/dist/constants/sizes.js.map +1 -1
  124. package/dist/containers/PopoverProvider.d.ts.map +1 -1
  125. package/dist/containers/PopoverProvider.js +10 -8
  126. package/dist/containers/PopoverProvider.js.map +1 -1
  127. package/dist/containers/ReqoreProvider.d.ts.map +1 -1
  128. package/dist/containers/ReqoreProvider.js +4 -2
  129. package/dist/containers/ReqoreProvider.js.map +1 -1
  130. package/dist/containers/UIProvider.d.ts +7 -0
  131. package/dist/containers/UIProvider.d.ts.map +1 -1
  132. package/dist/containers/UIProvider.js.map +1 -1
  133. package/dist/context/ReqoreContext.d.ts +2 -0
  134. package/dist/context/ReqoreContext.d.ts.map +1 -1
  135. package/dist/context/ReqoreContext.js.map +1 -1
  136. package/dist/helpers/colors.d.ts +1 -1
  137. package/dist/helpers/colors.d.ts.map +1 -1
  138. package/dist/helpers/colors.js +6 -2
  139. package/dist/helpers/colors.js.map +1 -1
  140. package/dist/helpers/utils.d.ts +3 -0
  141. package/dist/helpers/utils.d.ts.map +1 -1
  142. package/dist/helpers/utils.js +16 -1
  143. package/dist/helpers/utils.js.map +1 -1
  144. package/dist/hooks/useLatestZIndex.js +2 -2
  145. package/dist/hooks/useLatestZIndex.js.map +1 -1
  146. package/dist/hooks/usePopover.d.ts +1 -0
  147. package/dist/hooks/usePopover.d.ts.map +1 -1
  148. package/dist/hooks/usePopover.js +8 -6
  149. package/dist/hooks/usePopover.js.map +1 -1
  150. package/dist/styles.d.ts +1 -0
  151. package/dist/styles.d.ts.map +1 -1
  152. package/dist/styles.js +6 -5
  153. package/dist/styles.js.map +1 -1
  154. package/dist/types/global.d.ts +26 -0
  155. package/dist/types/global.d.ts.map +1 -1
  156. package/package.json +1 -1
  157. package/src/components/Button/index.tsx +79 -34
  158. package/src/components/Checkbox/index.tsx +3 -2
  159. package/src/components/Collection/index.tsx +93 -60
  160. package/src/components/Collection/item.tsx +29 -9
  161. package/src/components/Columns/column.tsx +1 -0
  162. package/src/components/ControlGroup/index.tsx +449 -104
  163. package/src/components/Drawer/index.tsx +28 -27
  164. package/src/components/Dropdown/index.tsx +3 -1
  165. package/src/components/Effect/index.tsx +22 -14
  166. package/src/components/Icon/index.tsx +81 -62
  167. package/src/components/Input/index.tsx +8 -3
  168. package/src/components/InternalPopover/index.tsx +131 -126
  169. package/src/components/Menu/index.tsx +7 -1
  170. package/src/components/Message/index.tsx +9 -1
  171. package/src/components/MultiSelect/index.tsx +180 -188
  172. package/src/components/Panel/index.tsx +227 -100
  173. package/src/components/Popover/index.tsx +1 -3
  174. package/src/components/Spacer/index.tsx +63 -14
  175. package/src/components/Table/header.tsx +2 -2
  176. package/src/components/Table/headerCell.tsx +2 -2
  177. package/src/components/Table/helpers.ts +12 -6
  178. package/src/components/Table/index.tsx +1 -0
  179. package/src/components/Table/row.tsx +2 -7
  180. package/src/components/Tabs/content.tsx +11 -3
  181. package/src/components/Tabs/index.tsx +14 -3
  182. package/src/components/Tabs/item.tsx +28 -5
  183. package/src/components/Tabs/list.tsx +7 -3
  184. package/src/components/Tag/group.tsx +6 -12
  185. package/src/components/Tag/index.tsx +69 -35
  186. package/src/components/Tree/index.tsx +1 -1
  187. package/src/constants/animations.ts +1 -1
  188. package/src/constants/sizes.ts +10 -10
  189. package/src/containers/PopoverProvider.tsx +11 -8
  190. package/src/containers/ReqoreProvider.tsx +40 -35
  191. package/src/containers/UIProvider.tsx +7 -0
  192. package/src/context/ReqoreContext.tsx +2 -0
  193. package/src/helpers/colors.ts +8 -2
  194. package/src/helpers/utils.ts +18 -0
  195. package/src/hooks/useLatestZIndex.ts +2 -2
  196. package/src/hooks/usePopover.tsx +9 -6
  197. package/src/mock/collectionData.tsx +33 -2
  198. package/src/stories/Button/Button.stories.tsx +72 -7
  199. package/src/stories/Checkbox/Checkbox.stories.tsx +6 -3
  200. package/src/stories/Collection/Collection.stories.tsx +18 -2
  201. package/src/stories/ControlGroup/ControlGroup.stories.tsx +282 -33
  202. package/src/stories/Drawer/Drawer.stories.tsx +70 -3
  203. package/src/stories/Dropdown/Dropdown.stories.tsx +13 -3
  204. package/src/stories/Icon/Icon.stories.tsx +1 -0
  205. package/src/stories/Input/Input.stories.tsx +5 -3
  206. package/src/stories/Menu/Menu.stories.tsx +2 -0
  207. package/src/stories/Message/Message.stories.tsx +7 -0
  208. package/src/stories/Panel/Panel.stories.tsx +147 -13
  209. package/src/stories/Popover/Popover.stories.tsx +88 -82
  210. package/src/stories/Tabs/Tabs.stories.tsx +33 -15
  211. package/src/stories/Tag/Tag.stories.tsx +23 -3
  212. package/src/stories/TextArea/TextArea.stories.tsx +3 -3
  213. package/src/styles.ts +6 -0
  214. package/src/types/global.ts +28 -0
  215. package/tests.json +1 -1
@@ -1,23 +1,53 @@
1
- import React, { forwardRef } from 'react';
1
+ import { debounce } from 'lodash';
2
+ import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
+ import { useMount, useUnmount } from 'react-use';
2
4
  import styled, { css } from 'styled-components';
5
+ import { ReqoreButton, ReqoreDrawer } from '../..';
3
6
  import { GAP_FROM_SIZE, RADIUS_FROM_SIZE, TSizes } from '../../constants/sizes';
4
7
  import { IReqoreTheme } from '../../constants/theme';
5
- import { IWithReqoreFlat, IWithReqoreMinimal, IWithReqoreSize } from '../../types/global';
8
+ import {
9
+ IReqoreIntent,
10
+ IWithReqoreCustomTheme,
11
+ IWithReqoreFlat,
12
+ IWithReqoreFluid,
13
+ IWithReqoreMinimal,
14
+ IWithReqoreSize,
15
+ } from '../../types/global';
6
16
 
7
17
  export interface IReqoreControlGroupProps
8
18
  extends React.HTMLAttributes<HTMLDivElement>,
9
19
  IWithReqoreFlat,
10
20
  IWithReqoreSize,
11
- IWithReqoreMinimal {
21
+ IWithReqoreMinimal,
22
+ IReqoreIntent,
23
+ IWithReqoreFluid,
24
+ IWithReqoreCustomTheme {
12
25
  stack?: boolean;
13
26
  children: any;
14
- fluid?: boolean;
27
+ fixed?: boolean;
15
28
  rounded?: boolean;
29
+ responsive?: boolean;
16
30
  gapSize?: TSizes;
17
31
  /*
18
32
  * Whether the contents of the control group should be stacked vertically
19
33
  */
20
34
  vertical?: boolean;
35
+ verticalAlign?: 'flex-start' | 'center' | 'flex-end';
36
+ horizontalAlign?: 'flex-start' | 'center' | 'flex-end';
37
+ wrap?: boolean;
38
+ isInsideStackGroup?: boolean;
39
+ isInsideVerticalGroup?: boolean;
40
+ isFirst?: boolean;
41
+ isLast?: boolean;
42
+ isLastInFirstGroup?: boolean;
43
+ isLastInLastGroup?: boolean;
44
+ isFirstInLastGroup?: boolean;
45
+ childrenCount?: number;
46
+ childId?: number;
47
+ isChild?: boolean;
48
+ isFirstGroup?: boolean;
49
+ isLastGroup?: boolean;
50
+ fill?: boolean;
21
51
  }
22
52
 
23
53
  export interface IReqoreControlGroupStyle extends IReqoreControlGroupProps {
@@ -26,122 +56,437 @@ export interface IReqoreControlGroupStyle extends IReqoreControlGroupProps {
26
56
 
27
57
  export const StyledReqoreControlGroup = styled.div<IReqoreControlGroupStyle>`
28
58
  display: flex;
29
- flex: 0 auto;
30
- width: ${({ fluid }) => (fluid ? '100%' : undefined)};
31
- align-items: ${({ fluid }) => (fluid ? 'stretch' : 'flex-start')};
59
+ flex: ${({ fluid, fixed }) => (fixed ? '0 0 auto' : fluid ? '1 auto' : '0 0 auto')};
60
+ width: ${({ fluid, fixed }) => (fluid && !fixed ? '100%' : undefined)};
61
+ justify-content: ${({ fluid, vertical }) => (vertical && fluid ? 'stretch' : undefined)};
62
+ align-items: ${({ vertical, fluid, horizontalAlign }) =>
63
+ vertical ? (fluid ? 'stretch' : horizontalAlign) : undefined};
32
64
  flex-flow: ${({ vertical }) => (vertical ? 'column' : 'row')};
65
+ gap: ${({ gapSize, stack }) => (!stack ? `${GAP_FROM_SIZE[gapSize]}px` : undefined)};
66
+ flex-wrap: ${({ wrap }) => (wrap ? 'wrap' : 'nowrap')};
33
67
 
34
- > .reqore-control-wrapper .reqore-control {
35
- border-radius: ${({ stack }) => (!stack ? undefined : 0)};
68
+ // If the group has the fill prop,
69
+ // we need to make sure that the children are vertically stretched
70
+ // kind of like 'fluid' but vertically
71
+ // ! Only works when the group is horizontal & wrap is false
72
+ ${({ fill, vertical }) => {
73
+ if (fill && !vertical) {
74
+ return css`
75
+ > * {
76
+ max-height: 100%;
77
+ height: unset !important;
78
+ align-self: stretch;
79
+ }
80
+ `;
81
+ }
82
+
83
+ return undefined;
84
+ }}
85
+
86
+ > * {
87
+ margin-top: ${({ fill, verticalAlign }) =>
88
+ !fill && (verticalAlign === 'flex-end' || verticalAlign === 'center') ? 'auto' : undefined};
89
+ margin-bottom: ${({ fill, verticalAlign }) =>
90
+ !fill && (verticalAlign === 'flex-start' || verticalAlign === 'center') ? 'auto' : undefined};
91
+ margin-right: ${({ horizontalAlign }) => (horizontalAlign === 'center' ? 'auto' : undefined)};
92
+
93
+ ${({ vertical }) =>
94
+ vertical &&
95
+ css`
96
+ margin-left: ${({ horizontalAlign }) =>
97
+ horizontalAlign === 'flex-end' || horizontalAlign === 'center' ? 'auto' : undefined};
98
+ `}
36
99
  }
37
100
 
38
101
  ${({ vertical }) =>
39
- vertical
40
- ? css`
41
- > .reqore-control,
42
- > .reqore-control-wrapper,
43
- > .reqore-tag,
44
- > * {
45
- &:not(:last-child) {
46
- margin-bottom: ${({ stack, gapSize }) =>
47
- !stack ? `${GAP_FROM_SIZE[gapSize]}px` : undefined};
48
- border-bottom: ${({ stack }) => (!stack ? undefined : 0)};
49
- }
102
+ !vertical &&
103
+ css`
104
+ > *:first-child {
105
+ margin-left: ${({ horizontalAlign }) =>
106
+ horizontalAlign === 'flex-end' || horizontalAlign === 'center' ? 'auto' : undefined};
107
+ }
108
+ `}
50
109
 
51
- border-radius: ${({ stack }) => (!stack ? undefined : 0)};
52
-
53
- ${({ rounded, size, stack }) =>
54
- rounded && stack
55
- ? css`
56
- &:first-child {
57
- border-top-left-radius: ${RADIUS_FROM_SIZE[size]}px;
58
- border-top-right-radius: ${RADIUS_FROM_SIZE[size]}px;
59
- }
60
-
61
- &:last-child {
62
- border-bottom-left-radius: ${RADIUS_FROM_SIZE[size]}px;
63
- border-bottom-right-radius: ${RADIUS_FROM_SIZE[size]}px;
64
- }
65
- `
66
- : undefined}
67
- }
110
+ > * {
111
+ border-radius: ${({ stack }) => (!stack ? undefined : 0)};
112
+ }
113
+ `;
68
114
 
69
- > .reqore-control-wrapper:not(:last-child) .reqore-control {
70
- margin-bottom: ${({ stack, gapSize }) =>
71
- !stack ? `${GAP_FROM_SIZE[gapSize]}px` : undefined};
72
- border-bottom: ${({ stack }) => (!stack ? undefined : 0)};
73
- }
74
- `
75
- : css`
76
- > .reqore-control,
77
- > .reqore-control-wrapper,
78
- > .reqore-tag,
79
- > * {
80
- &:not(:last-child) {
81
- margin-right: ${({ stack, gapSize }) =>
82
- !stack ? `${GAP_FROM_SIZE[gapSize]}px` : undefined};
83
- border-right: ${({ stack }) => (!stack ? undefined : 0)};
84
- }
115
+ const ReqoreControlGroup = memo(
116
+ ({
117
+ children,
118
+ className,
119
+ minimal,
120
+ size = 'normal',
121
+ gapSize = 'normal',
122
+ fluid,
123
+ flat,
124
+ fixed,
125
+ fill,
126
+ rounded = true,
127
+ wrap,
128
+ stack,
129
+ isInsideStackGroup,
130
+ isInsideVerticalGroup,
131
+ isFirstInLastGroup,
132
+ isLastInFirstGroup,
133
+ isLastInLastGroup,
134
+ intent,
135
+ customTheme,
136
+ isFirst,
137
+ isLast,
138
+ vertical,
139
+ childrenCount,
140
+ childId,
141
+ isChild,
142
+ isFirstGroup,
143
+ isLastGroup,
144
+ verticalAlign = 'center',
145
+ horizontalAlign = 'flex-start',
146
+ responsive,
147
+ ...rest
148
+ }: IReqoreControlGroupProps) => {
149
+ const isStack = stack || isInsideStackGroup;
150
+ const isVertical = vertical || isInsideVerticalGroup;
85
151
 
86
- border-radius: ${({ stack }) => (!stack ? undefined : 0)};
87
-
88
- ${({ rounded, size, stack }) =>
89
- rounded && stack
90
- ? css`
91
- &:first-child {
92
- border-top-left-radius: ${RADIUS_FROM_SIZE[size]}px;
93
- border-bottom-left-radius: ${RADIUS_FROM_SIZE[size]}px;
94
- }
95
-
96
- &:last-child {
97
- border-top-right-radius: ${RADIUS_FROM_SIZE[size]}px;
98
- border-bottom-right-radius: ${RADIUS_FROM_SIZE[size]}px;
99
- }
100
- `
101
- : undefined}
152
+ const [overflowingChildren, setOverflowingChildren] = useState<number | undefined>(0);
153
+ const [lastReSize, setLastReSize] = useState<number>(0);
154
+ const [isOverflownDialogOpen, setIsOverflownDialogOpen] = useState<boolean>(false);
155
+ const observer = useRef<ResizeObserver | null>(null);
156
+ const ref = useRef<HTMLDivElement>(null);
157
+
158
+ const realChildCount = useMemo((): number => {
159
+ let count = 0;
160
+
161
+ const countChildren = (children: React.ReactNode) =>
162
+ React.Children.forEach(children, (child: any) => {
163
+ if (child && React.isValidElement(child)) {
164
+ if (child.type === React.Fragment) {
165
+ // just compare to `React.Fragment`
166
+ countChildren((child.props as any).children);
167
+ } else {
168
+ count++;
169
+ }
102
170
  }
103
- `}
104
- `;
171
+ });
172
+
173
+ countChildren(children);
174
+
175
+ return count < 0 ? 0 : count;
176
+ }, [children]);
177
+
178
+ const checkIfOverflowing = useCallback(() => {
179
+ return (
180
+ ref.current &&
181
+ ref.current.clientWidth > 40 &&
182
+ !vertical &&
183
+ responsive &&
184
+ ref.current.scrollWidth > ref.current.clientWidth
185
+ );
186
+ }, [vertical, responsive, ref, children]);
187
+
188
+ useMount(() => {
189
+ if (!vertical && responsive) {
190
+ if ('ResizeObserver' in window) {
191
+ observer.current = new ResizeObserver(
192
+ debounce(() => {
193
+ if (ref && ref.current) {
194
+ setOverflowingChildren(0);
195
+ setLastReSize(ref.current.clientWidth);
196
+ }
197
+ }, 200)
198
+ );
199
+
200
+ observer.current.observe(ref.current);
201
+ }
202
+ }
203
+ });
204
+
205
+ useUnmount(() => {
206
+ if (observer.current) {
207
+ observer.current.disconnect();
208
+ }
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
+ };
105
260
 
106
- const ReqoreControlGroup = forwardRef<HTMLDivElement, IReqoreControlGroupProps>(
107
- (
108
- {
109
- children,
110
- className,
111
- minimal,
112
- size = 'normal',
113
- gapSize = 'normal',
114
- fluid,
115
- flat,
116
- rounded = true,
117
- ...rest
118
- }: IReqoreControlGroupProps,
119
- ref
120
- ) => (
121
- <StyledReqoreControlGroup
122
- {...rest}
123
- size={size}
124
- gapSize={gapSize}
125
- ref={ref}
126
- rounded={rounded}
127
- fluid={fluid}
128
- className={`${className || ''} reqore-control-group`}
129
- >
130
- {React.Children.map(children, (child) =>
131
- child
132
- ? React.cloneElement(child, {
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) {
264
+ const _isLastGroup =
265
+ !isInsideStackGroup || childrenCount === 1
266
+ ? true
267
+ : isChild
268
+ ? isLastGroup
269
+ : index === realChildCount - 1;
270
+
271
+ if (_isLastGroup && getIsLast(index)) {
272
+ return RADIUS_FROM_SIZE[size];
273
+ }
274
+
275
+ return undefined;
276
+ }
277
+
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
+ }
283
+
284
+ return undefined;
285
+ };
286
+
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;
292
+
293
+ if (_isFirstGroup && getIsFirst(index)) {
294
+ return RADIUS_FROM_SIZE[size];
295
+ }
296
+
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
+ }
335
+
336
+ let newProps = {
337
+ ...child.props,
338
+ key: index,
133
339
  minimal:
134
340
  child.props?.minimal || child.props?.minimal === false
135
341
  ? child.props.minimal
136
342
  : minimal,
137
343
  size: child.props?.size || size,
138
344
  flat: child.props?.flat || child.props?.flat === false ? child.props.flat : flat,
139
- fluid,
140
- })
141
- : null
142
- )}
143
- </StyledReqoreControlGroup>
144
- )
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
+ fill,
348
+ stack:
349
+ child.props?.stack || child.props?.stack === false ? child.props.stack : isStack,
350
+ intent: child.props?.intent || intent,
351
+ customTheme: child.props?.customTheme || customTheme,
352
+ };
353
+
354
+ if (isStack) {
355
+ newProps = {
356
+ ...newProps,
357
+ style: {
358
+ borderTopLeftRadius: getBorderTopLeftRadius(index),
359
+ borderBottomLeftRadius: getBorderBottomLeftRadius(index),
360
+ borderTopRightRadius: getBorderTopRightRadius(index),
361
+ borderBottomRightRadius: getBorderBottomRightRadius(index),
362
+ ...(child.props?.style || {}),
363
+ },
364
+ isChild: true,
365
+ rounded: !isStack,
366
+ isInsideStackGroup: isStack,
367
+ isInsideVerticalGroup: isVertical,
368
+ isFirst: isChild ? getIsFirst(index) : undefined,
369
+ isLast: isChild ? getIsLast(index) : undefined,
370
+ isLastInFirstGroup: getIsLastInFirstGroup(index),
371
+ isLastInLastGroup: getIsLastInLastGroup(index),
372
+ isFirstInLastGroup: getIsFirstInLastGroup(index),
373
+ childrenCount: realChildCount,
374
+ childId: index + 1,
375
+
376
+ isFirstGroup: isChild ? isFirstGroup : index === 0,
377
+ isLastGroup: isChild ? isLastGroup : index === realChildCount - 1,
378
+ };
379
+ }
380
+
381
+ /*
382
+ * Because of the way React.Children.map works, we have to
383
+ * manually decrement the index for every child that is `null`
384
+ * because react maps through null children and returns them in `Count`
385
+ * We filter these children out in the `realChildCount` variable,
386
+ * but the index is still incremented
387
+ * */
388
+ index = index + 1;
389
+
390
+ return React.cloneElement(child, newProps);
391
+ }
392
+
393
+ return child;
394
+ });
395
+ },
396
+ [
397
+ children,
398
+ isStack,
399
+ isVertical,
400
+ isChild,
401
+ isLastGroup,
402
+ isFirstGroup,
403
+ realChildCount,
404
+ index,
405
+ fluid,
406
+ flat,
407
+ minimal,
408
+ size,
409
+ intent,
410
+ ]
411
+ );
412
+
413
+ // Get the overflown children
414
+ const overflownChildren = useMemo(
415
+ () =>
416
+ overflowingChildren ? React.Children.toArray(children).slice(0, overflowingChildren) : [],
417
+ [children, overflowingChildren]
418
+ );
419
+
420
+ // Remove the overflowing children count from the start of the children array
421
+ const _children = useMemo(
422
+ () =>
423
+ overflowingChildren && responsive
424
+ ? [
425
+ children.slice(overflowingChildren),
426
+ <ReqoreButton
427
+ icon='MenuLine'
428
+ customTheme={customTheme}
429
+ tooltip={{
430
+ content: `Show ${React.Children.count(overflownChildren)} hidden items`,
431
+ }}
432
+ fixed
433
+ active={isOverflownDialogOpen}
434
+ onClick={(e: React.MouseEvent<HTMLButtonElement>) => {
435
+ e.stopPropagation();
436
+ setIsOverflownDialogOpen(!isOverflownDialogOpen);
437
+ }}
438
+ flat
439
+ />,
440
+ ]
441
+ : children,
442
+ [children, overflowingChildren, responsive, overflownChildren]
443
+ );
444
+
445
+ return (
446
+ <>
447
+ {isOverflownDialogOpen ? (
448
+ <ReqoreDrawer
449
+ isOpen
450
+ onClose={() => setIsOverflownDialogOpen(false)}
451
+ flat
452
+ floating
453
+ minimal
454
+ position='bottom'
455
+ hasBackdrop={false}
456
+ label='Hidden items'
457
+ minSize='100px'
458
+ size='auto'
459
+ >
460
+ <ReqoreControlGroup fluid wrap>
461
+ {overflownChildren}
462
+ </ReqoreControlGroup>
463
+ </ReqoreDrawer>
464
+ ) : null}
465
+ <StyledReqoreControlGroup
466
+ {...rest}
467
+ vertical={vertical}
468
+ style={{
469
+ overflowX: responsive ? 'auto' : undefined,
470
+ ...rest.style,
471
+ }}
472
+ size={size}
473
+ gapSize={gapSize}
474
+ ref={ref}
475
+ rounded={rounded}
476
+ fluid={fluid}
477
+ fixed={fixed}
478
+ fill={fill}
479
+ wrap={wrap}
480
+ stack={isStack}
481
+ verticalAlign={verticalAlign}
482
+ horizontalAlign={horizontalAlign}
483
+ className={`${className || ''} reqore-control-group`}
484
+ >
485
+ {cloneThroughFragments(_children)}
486
+ </StyledReqoreControlGroup>
487
+ </>
488
+ );
489
+ }
145
490
  );
146
491
 
147
492
  export default ReqoreControlGroup;