@geneui/components 3.0.0-next-6501ddf-03042025 → 3.0.0-next-b9c382c-15042025

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.
package/Popover.js CHANGED
@@ -1,13 +1,318 @@
1
- export { P as Popover, a as PopoverBody, b as PopoverFooter, c as PopoverFooterActions } from './index-fd485ab0.js';
2
- import 'react';
3
- import './floating-ui.react-0485e4db.js';
1
+ import React__default, { forwardRef, useState, useContext, useRef, useImperativeHandle, useEffect, useLayoutEffect } from 'react';
2
+ import { u as useFloating, p as platform, o as offset, f as flip, a as arrow, s as shift, b as autoUpdate, c as useDismiss, d as useClick, e as useRole, g as useInteractions, F as FloatingPortal } from './floating-ui.react-0485e4db.js';
3
+ import { S as SvgInfoOutlined } from './InfoOutlined-fc7d9afa.js';
4
+ import { S as SvgX } from './X-20da3b4a.js';
5
+ import Button from './Button.js';
6
+ import { a as GeneUIDesignSystemContext } from './index-7fa24b9c.js';
7
+ import { s as styleInject } from './style-inject.es-746bb8ed.js';
8
+ import { c as classNames } from './index-ce02421b.js';
9
+ import Scrollbar from './Scrollbar.js';
4
10
  import 'react-dom';
5
- import './InfoOutlined-fc7d9afa.js';
6
11
  import './ActivityRecent-b88e2ba8.js';
7
- import './X-20da3b4a.js';
8
- import './style-inject.es-746bb8ed.js';
9
- import './index-7fa24b9c.js';
10
- import './useDebounceCallback-999deae7.js';
11
- import './Button.js';
12
- import './index-ce02421b.js';
13
12
  import './Loader.js';
13
+ import './useDebounceCallback-999deae7.js';
14
+ import 'prop-types';
15
+
16
+ var css_248z = ".popover{background-color:var(--guit-sem-color-background-neutral-1-nudge);border-top-left-radius:var(--guit-ref-radius-2xsmall);border-top-right-radius:var(--guit-ref-radius-2xsmall);filter:drop-shadow(var(--guit-sem-shadow-floating-2-position-x-1) var(--guit-sem-shadow-floating-2-position-y-1) var(--guit-sem-shadow-floating-2-blur-1) var(--guit-sem-color-floating-2-rgba-1)) drop-shadow(var(--guit-sem-shadow-floating-2-position-x-2) var(--guit-sem-shadow-floating-2-position-y-2) var(--guit-sem-shadow-floating-2-blur-2) var(--guit-sem-color-floating-2-rgba-2))}.popover:not(.popover_size_mobile){border-bottom-left-radius:var(--guit-ref-radius-2xsmall);border-bottom-right-radius:var(--guit-ref-radius-2xsmall)}.popover:not(.popover_size_mobile) .popover__arrow{position:absolute}.popover:not(.popover_size_mobile) .popover__arrowPath{fill:var(--guit-sem-color-background-neutral-1-nudge)}.popover_position_top .popover__arrow{transform:rotate(180deg)}.popover_position_bottom .popover__arrow{transform:rotate(0deg)}.popover_position_left .popover__arrow{transform:rotate(90deg)}.popover_position_right .popover__arrow{transform:rotate(-90deg)}.popover_size_xLarge{max-width:82rem;min-width:64rem}.popover_size_xLarge .popover__body{max-height:82rem;min-height:32rem}.popover_size_large{max-width:64rem;min-width:52rem}.popover_size_large .popover__body{max-height:64rem;min-height:26rem}.popover_size_medium{max-width:52rem;min-width:28rem}.popover_size_medium .popover__body{max-height:52rem;min-height:14rem}.popover_size_small{max-width:28rem;min-width:16rem}.popover_size_small .popover__body{max-height:52rem;min-height:4rem}.popover_size_large .popover__footer,.popover_size_xLarge .popover__footer{height:6.4rem}.popover_size_fitContent{width:-moz-fit-content;width:fit-content}.popover_size_reference{min-width:auto;width:var(--parent-width)}.popover__container{display:grid;grid-template-rows:auto 1fr auto}.popover__header{border-bottom:var(--guit-ref-border-width-thin) var(--guit-ref-border-style-solid) var(--guit-sem-color-border-neutral-2);height:4.8rem;justify-content:space-between;padding-inline:var(--guit-ref-spacing-large)}.popover__header,.popover__title{align-items:center;column-gap:var(--guit-ref-spacing-xsmall);display:flex;overflow:hidden}.popover__title{color:var(--guit-sem-color-foreground-neutral-2);flex:1}.popover__title_icon{flex:0 0 auto}.popover__title_text{font-family:var(--guit-sem-font-label-medium-default-semibold-font-family),sans-serif;font-size:var(--guit-sem-font-label-medium-default-semibold-font-size);font-weight:var(--guit-sem-font-label-medium-default-semibold-font-weight);line-height:var(--guit-sem-font-label-medium-default-semibold-line-height)}.popover__close{flex:0 0 auto}.popover__body{min-width:0}.popover__body_withPadding{padding-block:var(--guit-ref-spacing-large);padding-inline:var(--guit-ref-spacing-large)}.popover__content{height:100%;width:100%}.popover__footer{border-top:var(--guit-ref-border-width-thin) var(--guit-ref-border-style-solid) var(--guit-sem-color-border-neutral-2);justify-content:space-between;overflow:hidden;padding-block:var(--guit-ref-spacing-large);padding-inline:var(--guit-ref-spacing-large)}.popover__footer,.popover__footer_buttons{align-items:center;column-gap:var(--guit-ref-spacing-xsmall);display:flex}.popover__footer_buttons{margin-inline-start:auto}";
17
+ styleInject(css_248z);
18
+
19
+ const getPositionRect = (currentPopoverRect, position) => {
20
+ const { width, height, top, right, bottom, left } = currentPopoverRect;
21
+ switch (position) {
22
+ case "top":
23
+ return {
24
+ top: top - width,
25
+ left,
26
+ bottom: top,
27
+ right: left + width
28
+ };
29
+ case "right":
30
+ return {
31
+ top,
32
+ left: right,
33
+ bottom: top + height,
34
+ right: right + width
35
+ };
36
+ case "bottom":
37
+ return {
38
+ top: bottom,
39
+ left,
40
+ bottom: bottom + height,
41
+ right: left + width
42
+ };
43
+ case "left":
44
+ return {
45
+ top,
46
+ left: left - width,
47
+ bottom: top + height,
48
+ right: left
49
+ };
50
+ case "top-start":
51
+ return {
52
+ top: top - height,
53
+ left: left - width / 2,
54
+ bottom: top,
55
+ right: left + width / 2
56
+ };
57
+ case "right-start":
58
+ return {
59
+ top: top - height / 2,
60
+ left: right,
61
+ bottom: top + height / 2,
62
+ right: right + width
63
+ };
64
+ case "bottom-start":
65
+ return {
66
+ top: bottom,
67
+ left: left - width / 2,
68
+ bottom: bottom + height,
69
+ right: left + width / 2
70
+ };
71
+ case "left-start":
72
+ return {
73
+ top: top - height / 2,
74
+ left: left - width,
75
+ bottom: top + height / 2,
76
+ right: left
77
+ };
78
+ case "top-end":
79
+ return {
80
+ top: top - height,
81
+ left: right - width,
82
+ bottom: top,
83
+ right
84
+ };
85
+ case "right-end":
86
+ return {
87
+ top: bottom - height,
88
+ left: right,
89
+ bottom,
90
+ right: right + width
91
+ };
92
+ case "bottom-end":
93
+ return {
94
+ top: bottom,
95
+ left: right - width,
96
+ bottom: bottom + height,
97
+ right
98
+ };
99
+ case "left-end":
100
+ return {
101
+ top: top + height / 2,
102
+ left: left - width,
103
+ bottom: bottom - height / 2,
104
+ right: left
105
+ };
106
+ default:
107
+ return currentPopoverRect;
108
+ }
109
+ };
110
+ const calculateOverlap = (rect1, rect2) => {
111
+ if (rect1.right <= rect2.left ||
112
+ rect1.left >= rect2.right ||
113
+ rect1.bottom <= rect2.top ||
114
+ rect1.top >= rect2.bottom) {
115
+ return 0;
116
+ }
117
+ const overlapWidth = Math.min(rect1.right, rect2.right) - Math.max(rect1.left, rect2.left);
118
+ const overlapHeight = Math.min(rect1.bottom, rect2.bottom) - Math.max(rect1.top, rect2.top);
119
+ return overlapWidth * overlapHeight;
120
+ };
121
+
122
+ const positions = [
123
+ "top",
124
+ "bottom",
125
+ "right",
126
+ "left",
127
+ "top-start",
128
+ "right-start",
129
+ "bottom-start",
130
+ "left-start",
131
+ "top-end",
132
+ "right-end",
133
+ "bottom-end",
134
+ "left-end"
135
+ ];
136
+ const correctPosition = {
137
+ "bottom-center": "bottom",
138
+ "bottom-left": "bottom-start",
139
+ "bottom-right": "bottom-end",
140
+ "left-bottom": "left-end",
141
+ "left-center": "left",
142
+ "left-top": "left-start",
143
+ "right-bottom": "right-end",
144
+ "right-center": "right",
145
+ "right-top": "right-start",
146
+ "top-center": "top",
147
+ "top-left": "top-start",
148
+ "top-right": "top-end",
149
+ auto: "auto"
150
+ };
151
+ const arrowPositions = {
152
+ "top-start": "left",
153
+ "top-end": "right",
154
+ "bottom-end": "right",
155
+ "bottom-start": "left"
156
+ };
157
+ const staticSides = {
158
+ top: "bottom",
159
+ right: "left",
160
+ bottom: "top",
161
+ left: "right"
162
+ };
163
+ /**
164
+ Popover displays additional content or information in an overlay floating box.
165
+ It appears on top of the main content when triggered by a user action,
166
+ such as a click or hover. Unlike tooltips, popovers can contain more
167
+ complex and interactive content, including text, images, and form elements.
168
+ */
169
+ const Popover = forwardRef(({ size = "medium", fitReference, position = "bottom-center", margin = 10, defaultOpen = false, setProps, title, withArrow = true, children, disableReposition = false, onClose, open }, popoverRef) => {
170
+ const [popoverOpened, setPopoverOpened] = useState(defaultOpen);
171
+ const { geneUIProviderRef, breakpoint } = useContext(GeneUIDesignSystemContext);
172
+ const [currentPosition, setCurrentPosition] = useState(correctPosition[position]);
173
+ const arrowRef = useRef(null);
174
+ const isMobile = breakpoint === null || breakpoint === void 0 ? void 0 : breakpoint.isMobileBreakpoint;
175
+ const wosPosed = useRef(new Map());
176
+ const { refs, floatingStyles, context, middlewareData, placement } = useFloating({
177
+ open: popoverOpened,
178
+ onOpenChange: setPopoverOpened,
179
+ placement: currentPosition,
180
+ platform: Object.assign(Object.assign({}, platform), { isRTL: () => false }),
181
+ middleware: [
182
+ offset(margin),
183
+ flip({
184
+ mainAxis: position !== "auto" && !disableReposition,
185
+ fallbackAxisSideDirection: "none",
186
+ fallbackPlacements: position === "auto" ? [] : positions
187
+ }),
188
+ arrow({ element: arrowRef }),
189
+ shift({
190
+ mainAxis: false,
191
+ crossAxis: false,
192
+ limiter: {
193
+ fn: ({ x, y }) => ({
194
+ x: Math.max(0, x),
195
+ y: Math.max(0, y)
196
+ })
197
+ }
198
+ })
199
+ ],
200
+ whileElementsMounted: autoUpdate
201
+ });
202
+ useImperativeHandle(popoverRef, () => {
203
+ return {
204
+ referenceElement: refs.reference,
205
+ floatingElement: refs.floating
206
+ };
207
+ }, []);
208
+ useEffect(() => {
209
+ if (!popoverOpened && onClose) {
210
+ onClose();
211
+ }
212
+ }, [popoverOpened]);
213
+ useDismiss(context, {
214
+ outsidePressEvent: "click"
215
+ });
216
+ const click = useClick(context, {
217
+ event: "click"
218
+ });
219
+ const role = useRole(context);
220
+ const { getReferenceProps, getFloatingProps } = useInteractions([click, role]);
221
+ useEffect(() => {
222
+ const internalControl = open === undefined ? getReferenceProps() : {};
223
+ setProps(Object.assign({ ref: refs.setReference }, internalControl));
224
+ }, [setProps, getReferenceProps, open, refs.setReference]);
225
+ const [currentDirection] = placement.split("-");
226
+ const offsetFromEdge = 8;
227
+ const middlewareArrowData = middlewareData.arrow;
228
+ const staticSide = staticSides[currentDirection];
229
+ const arrowPosition = arrowPositions[placement];
230
+ const getCorrectPosition = arrowPosition
231
+ ? { [arrowPosition]: offsetFromEdge }
232
+ : { insetInlineStart: middlewareArrowData === null || middlewareArrowData === void 0 ? void 0 : middlewareArrowData.x };
233
+ const isPopoverOpened = open || popoverOpened;
234
+ useLayoutEffect(() => {
235
+ if (position === "auto") {
236
+ setCurrentPosition(size === "small" ? "auto" : "bottom");
237
+ return;
238
+ }
239
+ setCurrentPosition(correctPosition[position]);
240
+ return () => {
241
+ wosPosed.current.clear();
242
+ };
243
+ }, [position, size]);
244
+ /* eslint consistent-return: off */
245
+ useEffect(() => {
246
+ if (!refs.floating.current || position !== "auto")
247
+ return;
248
+ const currentPopoverRect = refs.floating.current.getBoundingClientRect();
249
+ const otherPopovers = document.querySelectorAll(".popover");
250
+ let bestPosition = correctPosition[position];
251
+ let leastOverlap = Infinity;
252
+ let hasOverlap = false;
253
+ const preventPosition = correctPosition[currentPosition];
254
+ const updatePopoverPosition = () => {
255
+ positions.forEach((possiblePositions) => {
256
+ const rect = getPositionRect(currentPopoverRect, possiblePositions);
257
+ let overlap = 0;
258
+ otherPopovers.forEach((otherPopover) => {
259
+ if (otherPopover === refs.floating.current)
260
+ return;
261
+ const otherRect = otherPopover.getBoundingClientRect();
262
+ overlap += calculateOverlap(rect, otherRect);
263
+ });
264
+ if (overlap < leastOverlap) {
265
+ leastOverlap = overlap;
266
+ bestPosition = possiblePositions;
267
+ }
268
+ });
269
+ hasOverlap = leastOverlap > 0;
270
+ if (preventPosition !== bestPosition && !hasOverlap && !wosPosed.current.has(bestPosition)) {
271
+ wosPosed.current.set(bestPosition, true);
272
+ setCurrentPosition(bestPosition);
273
+ }
274
+ };
275
+ const checkInterval = setInterval(() => {
276
+ updatePopoverPosition();
277
+ if (!hasOverlap) {
278
+ clearInterval(checkInterval);
279
+ }
280
+ });
281
+ return () => {
282
+ clearInterval(checkInterval);
283
+ leastOverlap = Infinity;
284
+ };
285
+ }, [popoverOpened, refs.floating.current, placement, position, currentPosition]);
286
+ const arrowOffsetFromEdge = 5;
287
+ const parentElement = refs.reference.current;
288
+ return (React__default.createElement(React__default.Fragment, null, isPopoverOpened &&
289
+ (isMobile ? (React__default.createElement("span", null, "Spreadsheet component")) : (React__default.createElement(FloatingPortal, { root: geneUIProviderRef.current },
290
+ React__default.createElement("div", Object.assign({ style: fitReference && parentElement
291
+ ? Object.assign(Object.assign({}, floatingStyles), { "--parent-width": `${parentElement === null || parentElement === void 0 ? void 0 : parentElement.offsetWidth}px` }) : floatingStyles, className: `popover ${fitReference && "popover_size_reference"} popover_size_${size} popover_position_${currentDirection}`, ref: refs.setFloating }, getFloatingProps()),
292
+ React__default.createElement("div", { ref: arrowRef, className: "popover__arrow", style: Object.assign(Object.assign({}, getCorrectPosition), { top: middlewareArrowData === null || middlewareArrowData === void 0 ? void 0 : middlewareArrowData.y, [staticSide]: arrowRef.current
293
+ ? `${-arrowRef.current.offsetWidth + arrowOffsetFromEdge}px`
294
+ : 0 }) },
295
+ React__default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "8", viewBox: "0 0 20 8", fill: "none" }, withArrow && (React__default.createElement("path", { d: "M8.75061 0.999513C9.48105 0.415163 10.519 0.415162 11.2494 0.999512L20 8H0L8.75061 0.999513Z", className: "popover__arrowPath" })))),
296
+ React__default.createElement("div", { className: "popover__container" },
297
+ title && (React__default.createElement("div", { className: "popover__header" },
298
+ React__default.createElement("p", { className: "popover__title" },
299
+ React__default.createElement(SvgInfoOutlined, { className: "popover__title_icon", size: 20 }),
300
+ React__default.createElement("span", { className: "popover__title_text ellipsis-text" }, title)),
301
+ React__default.createElement(Button, { Icon: SvgX, size: "small", appearance: "secondary", displayType: "text", className: "popover__close", onClick: () => setPopoverOpened(false) }))),
302
+ children)))))));
303
+ });
304
+
305
+ const PopoverBody = ({ children, withPadding = true, className, withScrollbar = true }) => {
306
+ return (React__default.createElement("div", { className: classNames("popover__body", { popover__body_withPadding: withPadding }, className) },
307
+ React__default.createElement("div", { className: "popover__content" }, withScrollbar ? React__default.createElement(Scrollbar, null, children) : children)));
308
+ };
309
+
310
+ const PopoverFooter = ({ children }) => {
311
+ return React__default.createElement("div", { className: "popover__footer" }, children);
312
+ };
313
+
314
+ const PopoverFooterActions = ({ children }) => {
315
+ return React__default.createElement("div", { className: "popover__footer_buttons" }, children);
316
+ };
317
+
318
+ export { Popover, PopoverBody, PopoverFooter, PopoverFooterActions };
package/Scrollbar.js CHANGED
@@ -3392,7 +3392,7 @@ function (_super) {
3392
3392
  return Scrollbar;
3393
3393
  }(React$1.Component);
3394
3394
 
3395
- var css_248z = ".scrollbar{min-height:0;min-width:0}.scrollbar_width_full{width:100%}.scrollbar_width_auto{width:auto}.scrollbar_height_full{height:100%}.scrollbar_height_auto{height:auto}.scrollbar__wrapper{height:100%;position:relative!important;width:100%}.scrollbar__scroller{height:100%;inset:auto!important;margin:0!important;position:relative!important}.scrollbar__scroller::-webkit-scrollbar,.scrollbar__scroller::-webkit-scrollbar-thumb,.scrollbar__scroller::-webkit-scrollbar-track{height:0;width:0}.scrollbar__content{padding:0!important}.scrollbar__content:focus-visible{outline:none}.scrollbar__track{border-radius:var(--guit-ref-radius-3xsmall);bottom:var(--guit-ref-spacing-3xsmall)!important;inset-inline-end:var(--guit-ref-spacing-4xsmall);overflow:hidden;position:absolute;z-index:100}.scrollbar__track_direction_y{height:100%;top:0;width:.6rem}.scrollbar__track_direction_x{bottom:0;height:.6rem;width:100%}.scrollbar__thumb{background:var(--guit-sem-color-background-transparent-2);border-radius:var(--guit-ref-radius-3xsmall);overflow:hidden;position:absolute}.scrollbar__thumb_direction_y{height:100%;inset-inline-end:0;top:0;width:.6rem}.scrollbar__thumb_direction_x{bottom:0;height:.6rem;inset-inline-start:0;width:100%}.scrollbar__thumb_direction_hide{height:0;width:0}";
3395
+ var css_248z = ".scrollbar{min-height:0;min-width:0}.scrollbar_width_full,.scrollbar_width_full .scrollbar__content{width:100%}.scrollbar_width_auto{width:auto}.scrollbar_height_full,.scrollbar_height_full .scrollbar__content{height:100%}.scrollbar_height_auto{height:auto}.scrollbar__wrapper{height:100%;position:relative!important;width:100%}.scrollbar__scroller{height:100%;inset:auto!important;margin:0!important;position:relative!important}.scrollbar__scroller::-webkit-scrollbar,.scrollbar__scroller::-webkit-scrollbar-thumb,.scrollbar__scroller::-webkit-scrollbar-track{height:0;width:0}.scrollbar__content{padding:0!important}.scrollbar__content:focus-visible{outline:none}.scrollbar__track{border-radius:var(--guit-ref-radius-3xsmall);bottom:var(--guit-ref-spacing-3xsmall)!important;inset-inline-end:var(--guit-ref-spacing-4xsmall);overflow:hidden;position:absolute;z-index:100}.scrollbar__track_direction_y{height:100%;top:0;width:.6rem}.scrollbar__track_direction_x{bottom:0;height:.6rem;width:100%}.scrollbar__thumb{background:var(--guit-sem-color-background-transparent-2);border-radius:var(--guit-ref-radius-3xsmall);overflow:hidden;position:absolute}.scrollbar__thumb_direction_y{height:100%;inset-inline-end:0;top:0;width:.6rem}.scrollbar__thumb_direction_x{bottom:0;height:.6rem;inset-inline-start:0;width:100%}.scrollbar__thumb_direction_hide{height:0;width:0}";
3396
3396
  styleInject(css_248z);
3397
3397
 
3398
3398
  /**
@@ -16,30 +16,31 @@ export interface IPopoverProps {
16
16
  defaultOpen?: boolean;
17
17
  /**
18
18
  * Define width and height of the popover.<br>
19
- * Possible values: <code> xLarge | large | medium | small | mobile </code>
19
+ * Possible values: `xLarge | large | medium | small | fitContent`
20
20
  */
21
- size?: "xLarge" | "large" | "medium" | "small" | "mobile";
21
+ size?: "small" | "medium" | "large" | "xLarge" | "fitContent";
22
+ /**
23
+ * When set to true, the `width` of the `popover` will match the `width` of the reference (trigger, anchor) element.
24
+ * The `height` of the popover will still be determined by the `size` prop.
25
+ */
26
+ fitReference?: boolean;
22
27
  /**
23
28
  * Title displayed in the popover header.
24
29
  */
25
30
  title?: string;
26
31
  /**
27
- * Position of the popover, relative to the target.<br><br>
28
- * Possible values: <code> bottom-center | bottom-left | bottom-right | left-bottom | left-center | left-top | <br><br> right-bottom | right-center | right-top | top-center | top-left | top-right | auto </code>
32
+ * Position of the popover, relative to the reference (trigger, anchor) element.<br><br>
33
+ * Possible values: `bottom-center | bottom-left | bottom-right | left-bottom | left-center` <br> `left-top | right-bottom | right-center | right-top | top-center | top-left | top-right | auto`
29
34
  */
30
35
  position?: keyof typeof correctPosition;
31
36
  /**
32
- * Margin between the popover and its target element.
37
+ * Margin between the popover and its reference (trigger, anchor) element.
33
38
  */
34
39
  margin?: number;
35
40
  /**
36
41
  * Function to update popover props dynamically.
37
42
  */
38
43
  setProps: Dispatch<SetStateAction<Record<string, unknown>>>;
39
- /**
40
- * Additional content displayed in the popover footer.
41
- */
42
- footerContent?: ReactNode;
43
44
  /**
44
45
  * The content displayed inside the popover.
45
46
  */
@@ -49,22 +50,37 @@ export interface IPopoverProps {
49
50
  */
50
51
  withArrow?: boolean;
51
52
  /**
52
- * If this property is enabled, rather than the popover content repositioning on a boundary collision,
53
- * the popover content container will move beyond the window's bounds.
54
- * You are, however, supplied with nudgedLeft and nudgedTop values, so you may choose to handle content overflow as you wish.
53
+ * If `true`, disables automatic repositioning of the popover when it would otherwise
54
+ * overflow or collide with a window boundary. By default, the popover will attempt
55
+ * to reposition itself (e.g., flip to another side) to remain visible.
56
+ *
57
+ * When `disableReposition` is enabled, the popover will instead remain in its
58
+ * original placement, even if that causes it to overflow the viewport.
59
+ * This can be useful when you want to handle overflow behavior manually or
60
+ * maintain consistent placement.
61
+ *
62
+ * Note: Even with repositioning disabled, the component still provides
63
+ * `nudgedLeft` and `nudgedTop` values, which can be used to handle content overflow.
55
64
  */
56
65
  disableReposition?: boolean;
57
66
  /**
58
- * A callback function that is called when the popover needs to be closed.
67
+ * A callback function that is called when the popover is closed.
59
68
  */
60
69
  onClose?: () => void;
61
70
  /**
62
- * Use `open` prop to control open state. By default, open is controls by component.
71
+ * Controls the open state of the popover externally.
72
+ *
73
+ * If `open` is provided, the component becomes a controlled component,
74
+ * and its visibility will be dictated by the parent.
75
+ * If `open` is not provided, the component manages its own open/close
76
+ * state internally via user interaction (e.g., clicks).
77
+ *
78
+ * This allows the component to be used both in controlled and uncontrolled modes.
63
79
  */
64
80
  open?: boolean;
65
81
  }
66
82
  /**
67
- Popover displays additional content or information in an overlay box.
83
+ Popover displays additional content or information in an overlay floating box.
68
84
  It appears on top of the main content when triggered by a user action,
69
85
  such as a click or hover. Unlike tooltips, popovers can contain more
70
86
  complex and interactive content, including text, images, and form elements.
@@ -9,6 +9,10 @@ interface IPopoverBodyProps extends PropsWithChildren {
9
9
  * By default the PopoverBody has <code>--guit-ref-spacing-large</code> padding.
10
10
  */
11
11
  withPadding?: boolean;
12
+ /**
13
+ * By default, the withScrollbar is <code>true</code>. Set withScrollbar <code>false</code> to return only children.
14
+ */
15
+ withScrollbar?: boolean;
12
16
  }
13
17
  declare const PopoverBody: FC<IPopoverBodyProps>;
14
18
  export default PopoverBody;
package/index.js CHANGED
@@ -10,7 +10,7 @@ export { default as Logo } from './Logo.js';
10
10
  export { default as Rate } from './Rate.js';
11
11
  export { default as Radio } from './Radio.js';
12
12
  export { default as Text } from './Text.js';
13
- export { P as Popover, a as PopoverBody, b as PopoverFooter, c as PopoverFooterActions, u as useScrollLock } from './index-fd485ab0.js';
13
+ export { Popover, PopoverBody, PopoverFooter, PopoverFooterActions } from './Popover.js';
14
14
  export { default as Badge } from './Badge.js';
15
15
  export { default as Scrollbar } from './Scrollbar.js';
16
16
  export { Col, Grid, Row } from './Grid.js';
@@ -37,6 +37,30 @@ import 'react-dom';
37
37
  import './X-20da3b4a.js';
38
38
  import 'prop-types';
39
39
 
40
+ const SCROLL_LOCK_CLASS = "scroll-lock";
41
+ const useScrollLock = (target) => {
42
+ const resolvedElement = target instanceof HTMLElement ? target : target.current;
43
+ const lockedRef = useRef(false);
44
+ const lock = useCallback(() => {
45
+ if (resolvedElement && !lockedRef.current) {
46
+ resolvedElement.classList.add(SCROLL_LOCK_CLASS);
47
+ lockedRef.current = true;
48
+ }
49
+ }, [resolvedElement]);
50
+ const unlock = useCallback(() => {
51
+ if (resolvedElement && lockedRef.current) {
52
+ resolvedElement.classList.remove(SCROLL_LOCK_CLASS);
53
+ lockedRef.current = false;
54
+ }
55
+ }, [resolvedElement]);
56
+ useEffect(() => {
57
+ return () => {
58
+ unlock();
59
+ };
60
+ }, [unlock]);
61
+ return { lock, unlock };
62
+ };
63
+
40
64
  const useClickOutside = (callback, relativeElements) => {
41
65
  const ref = useRef(null);
42
66
  const handleClickOutside = useCallback((e) => {
@@ -110,4 +134,4 @@ const useDeviceInfo = () => {
110
134
  }, []);
111
135
  };
112
136
 
113
- export { useClickOutside, useDeviceInfo };
137
+ export { useClickOutside, useDeviceInfo, useScrollLock };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@geneui/components",
3
3
  "description": "The Gene UI components library designed for BI tools",
4
- "version": "3.0.0-next-6501ddf-03042025",
4
+ "version": "3.0.0-next-b9c382c-15042025",
5
5
  "author": "SoftConstruct",
6
6
  "homepage": "https://github.com/softconstruct/gene-ui-components#readme",
7
7
  "repository": {
package/index-fd485ab0.js DELETED
@@ -1,355 +0,0 @@
1
- import React__default, { useRef, useCallback, useEffect, forwardRef, useState, useContext, useImperativeHandle, useLayoutEffect } from 'react';
2
- import { u as useFloating, p as platform, o as offset, f as flip, a as arrow, s as shift, b as autoUpdate, c as useDismiss, d as useClick, e as useRole, g as useInteractions, F as FloatingPortal } from './floating-ui.react-0485e4db.js';
3
- import { S as SvgInfoOutlined } from './InfoOutlined-fc7d9afa.js';
4
- import { S as SvgX } from './X-20da3b4a.js';
5
- import { s as styleInject } from './style-inject.es-746bb8ed.js';
6
- import { a as GeneUIDesignSystemContext } from './index-7fa24b9c.js';
7
- import Button from './Button.js';
8
- import { c as classNames } from './index-ce02421b.js';
9
-
10
- var css_248z = ".popover{background-color:var(--guit-sem-color-background-neutral-1-nudge);border-top-left-radius:var(--guit-ref-radius-2xsmall);border-top-right-radius:var(--guit-ref-radius-2xsmall);filter:drop-shadow(var(--guit-sem-shadow-floating-2-position-x-1) var(--guit-sem-shadow-floating-2-position-y-1) var(--guit-sem-shadow-floating-2-blur-1) var(--guit-sem-color-floating-2-rgba-1)) drop-shadow(var(--guit-sem-shadow-floating-2-position-x-2) var(--guit-sem-shadow-floating-2-position-y-2) var(--guit-sem-shadow-floating-2-blur-2) var(--guit-sem-color-floating-2-rgba-2))}.popover:not(.popover_size_mobile){border-bottom-left-radius:var(--guit-ref-radius-2xsmall);border-bottom-right-radius:var(--guit-ref-radius-2xsmall)}.popover:not(.popover_size_mobile) .popover__arrow{position:absolute}.popover:not(.popover_size_mobile) .popover__arrowPath{fill:var(--guit-sem-color-background-neutral-1-nudge)}.popover_position_top .popover__arrow{transform:rotate(180deg)}.popover_position_bottom .popover__arrow{transform:rotate(0deg)}.popover_position_left .popover__arrow{transform:rotate(90deg)}.popover_position_right .popover__arrow{transform:rotate(-90deg)}.popover_size_xLarge{width:72rem}.popover_size_xLarge .popover__body{height:15.4rem}.popover_size_xLarge .popover__footer{height:6.4rem}.popover_size_large{width:48rem}.popover_size_medium{width:36rem}.popover_size_large .popover__body,.popover_size_medium .popover__body{height:17.2rem}.popover_size_large .popover__footer,.popover_size_medium .popover__footer{height:5.6rem}.popover_size_small{width:24rem}.popover_size_small .popover__body{height:8.8rem}.popover_size_small .popover__footer{height:5.6rem}.popover_size_mobile{min-width:32rem;width:100%}.popover_size_mobile .popover__body{height:17.2rem}.popover_size_mobile .popover__footer{height:6.4rem}.popover__header{border-bottom:var(--guit-ref-border-width-thin) var(--guit-ref-border-style-solid) var(--guit-sem-color-border-neutral-2);height:4.8rem;justify-content:space-between;padding-inline:var(--guit-ref-spacing-large)}.popover__header,.popover__title{align-items:center;column-gap:var(--guit-ref-spacing-xsmall);display:flex}.popover__title{color:var(--guit-sem-color-foreground-neutral-2);flex:1;overflow:hidden}.popover__title_icon{flex:0 0 auto}.popover__title_text{font-family:var(--guit-sem-font-label-medium-default-semibold-font-family);font-size:var(--guit-sem-font-label-medium-default-semibold-font-size);font-weight:var(--guit-sem-font-label-medium-default-semibold-font-weight);line-height:var(--guit-sem-font-label-medium-default-semibold-line-height)}.popover__close{flex:0 0 auto}.popover__body_withPadding{padding-block:var(--guit-ref-spacing-large);padding-inline:var(--guit-ref-spacing-large)}.popover__content{height:100%;width:100%}.popover__footer{border-top:var(--guit-ref-border-width-thin) var(--guit-ref-border-style-solid) var(--guit-sem-color-border-neutral-2);justify-content:space-between;padding-block:var(--guit-ref-spacing-large);padding-inline:var(--guit-ref-spacing-large)}.popover__footer,.popover__footer_buttons{align-items:center;column-gap:var(--guit-ref-spacing-xsmall);display:flex}.popover__footer_buttons{margin-inline-start:auto}";
11
- styleInject(css_248z);
12
-
13
- const SCROLL_LOCK_CLASS = "scroll-lock";
14
- const useScrollLock = (target) => {
15
- const resolvedElement = target instanceof HTMLElement ? target : target.current;
16
- const lockedRef = useRef(false);
17
- const lock = useCallback(() => {
18
- if (resolvedElement && !lockedRef.current) {
19
- resolvedElement.classList.add(SCROLL_LOCK_CLASS);
20
- lockedRef.current = true;
21
- }
22
- }, [resolvedElement]);
23
- const unlock = useCallback(() => {
24
- if (resolvedElement && lockedRef.current) {
25
- resolvedElement.classList.remove(SCROLL_LOCK_CLASS);
26
- lockedRef.current = false;
27
- }
28
- }, [resolvedElement]);
29
- useEffect(() => {
30
- return () => {
31
- unlock();
32
- };
33
- }, [unlock]);
34
- return { lock, unlock };
35
- };
36
-
37
- const getPositionRect = (currentPopoverRect, position) => {
38
- const { width, height, top, right, bottom, left } = currentPopoverRect;
39
- switch (position) {
40
- case "top":
41
- return {
42
- top: top - width,
43
- left,
44
- bottom: top,
45
- right: left + width
46
- };
47
- case "right":
48
- return {
49
- top,
50
- left: right,
51
- bottom: top + height,
52
- right: right + width
53
- };
54
- case "bottom":
55
- return {
56
- top: bottom,
57
- left,
58
- bottom: bottom + height,
59
- right: left + width
60
- };
61
- case "left":
62
- return {
63
- top,
64
- left: left - width,
65
- bottom: top + height,
66
- right: left
67
- };
68
- case "top-start":
69
- return {
70
- top: top - height,
71
- left: left - width / 2,
72
- bottom: top,
73
- right: left + width / 2
74
- };
75
- case "right-start":
76
- return {
77
- top: top - height / 2,
78
- left: right,
79
- bottom: top + height / 2,
80
- right: right + width
81
- };
82
- case "bottom-start":
83
- return {
84
- top: bottom,
85
- left: left - width / 2,
86
- bottom: bottom + height,
87
- right: left + width / 2
88
- };
89
- case "left-start":
90
- return {
91
- top: top - height / 2,
92
- left: left - width,
93
- bottom: top + height / 2,
94
- right: left
95
- };
96
- case "top-end":
97
- return {
98
- top: top - height,
99
- left: right - width,
100
- bottom: top,
101
- right
102
- };
103
- case "right-end":
104
- return {
105
- top: bottom - height,
106
- left: right,
107
- bottom,
108
- right: right + width
109
- };
110
- case "bottom-end":
111
- return {
112
- top: bottom,
113
- left: right - width,
114
- bottom: bottom + height,
115
- right
116
- };
117
- case "left-end":
118
- return {
119
- top: top + height / 2,
120
- left: left - width,
121
- bottom: bottom - height / 2,
122
- right: left
123
- };
124
- default:
125
- return currentPopoverRect;
126
- }
127
- };
128
- const calculateOverlap = (rect1, rect2) => {
129
- if (rect1.right <= rect2.left ||
130
- rect1.left >= rect2.right ||
131
- rect1.bottom <= rect2.top ||
132
- rect1.top >= rect2.bottom) {
133
- return 0;
134
- }
135
- const overlapWidth = Math.min(rect1.right, rect2.right) - Math.max(rect1.left, rect2.left);
136
- const overlapHeight = Math.min(rect1.bottom, rect2.bottom) - Math.max(rect1.top, rect2.top);
137
- return overlapWidth * overlapHeight;
138
- };
139
-
140
- const positions = [
141
- "top",
142
- "bottom",
143
- "right",
144
- "left",
145
- "top-start",
146
- "right-start",
147
- "bottom-start",
148
- "left-start",
149
- "top-end",
150
- "right-end",
151
- "bottom-end",
152
- "left-end"
153
- ];
154
- const correctPosition = {
155
- "bottom-center": "bottom",
156
- "bottom-left": "bottom-start",
157
- "bottom-right": "bottom-end",
158
- "left-bottom": "left-end",
159
- "left-center": "left",
160
- "left-top": "left-start",
161
- "right-bottom": "right-end",
162
- "right-center": "right",
163
- "right-top": "right-start",
164
- "top-center": "top",
165
- "top-left": "top-start",
166
- "top-right": "top-end",
167
- auto: "auto"
168
- };
169
- const arrowPositions = {
170
- "top-start": "left",
171
- "top-end": "right",
172
- "bottom-end": "right",
173
- "bottom-start": "left"
174
- };
175
- const staticSides = {
176
- top: "bottom",
177
- right: "left",
178
- bottom: "top",
179
- left: "right"
180
- };
181
- /**
182
- Popover displays additional content or information in an overlay box.
183
- It appears on top of the main content when triggered by a user action,
184
- such as a click or hover. Unlike tooltips, popovers can contain more
185
- complex and interactive content, including text, images, and form elements.
186
- */
187
- const Popover = forwardRef(({ size = "medium", position = "bottom-center", margin = 10, defaultOpen = false, setProps, title, withArrow = true, children, disableReposition = false, onClose, open }, popoverRef) => {
188
- const { lock: lockBodyScroll, unlock: unlockBodyScroll } = useScrollLock(document.body);
189
- const [popoverOpened, setPopoverOpened] = useState(defaultOpen);
190
- const { geneUIProviderRef } = useContext(GeneUIDesignSystemContext);
191
- const [currentPosition, setCurrentPosition] = useState(correctPosition[position]);
192
- const arrowRef = useRef(null);
193
- const wosPosed = useRef(new Map());
194
- const { refs, floatingStyles, context, middlewareData, placement } = useFloating({
195
- open: popoverOpened,
196
- onOpenChange: setPopoverOpened,
197
- placement: currentPosition,
198
- platform: Object.assign(Object.assign({}, platform), { isRTL: () => false }),
199
- middleware: [
200
- offset(margin),
201
- flip({
202
- mainAxis: position !== "auto" && !disableReposition,
203
- fallbackAxisSideDirection: "none",
204
- fallbackPlacements: position === "auto" ? [] : positions
205
- }),
206
- arrow({ element: arrowRef }),
207
- shift({
208
- mainAxis: false,
209
- crossAxis: false,
210
- limiter: {
211
- fn: ({ x, y }) => ({
212
- x: Math.max(0, x),
213
- y: Math.max(0, y)
214
- })
215
- }
216
- })
217
- ],
218
- whileElementsMounted: autoUpdate
219
- });
220
- useImperativeHandle(popoverRef, () => {
221
- return {
222
- referenceElement: refs.reference,
223
- floatingElement: refs.floating
224
- };
225
- }, []);
226
- useEffect(() => {
227
- if (!popoverOpened && onClose) {
228
- onClose();
229
- }
230
- }, [popoverOpened]);
231
- useDismiss(context, {
232
- outsidePressEvent: "click"
233
- });
234
- const click = useClick(context, {
235
- event: "click"
236
- });
237
- const role = useRole(context);
238
- const { getReferenceProps, getFloatingProps } = useInteractions([click, role]);
239
- useEffect(() => {
240
- const internalControl = open === undefined ? getReferenceProps() : {};
241
- setProps(Object.assign({ ref: refs.setReference }, internalControl));
242
- }, [setProps, getReferenceProps, open, refs.setReference]);
243
- const [currentDirection] = placement.split("-");
244
- const offsetFromEdge = 8;
245
- const middlewareArrowData = middlewareData.arrow;
246
- const staticSide = staticSides[currentDirection];
247
- const arrowPosition = arrowPositions[placement];
248
- const getCorrectPosition = arrowPosition
249
- ? { [arrowPosition]: offsetFromEdge }
250
- : { insetInlineStart: middlewareArrowData === null || middlewareArrowData === void 0 ? void 0 : middlewareArrowData.x };
251
- const styles = size === "mobile"
252
- ? {
253
- position: "fixed",
254
- bottom: "0"
255
- }
256
- : floatingStyles;
257
- const isShowPopover = open || popoverOpened;
258
- useEffect(() => {
259
- if (size === "mobile" && isShowPopover) {
260
- lockBodyScroll();
261
- }
262
- else {
263
- unlockBodyScroll();
264
- }
265
- }, [size, isShowPopover]);
266
- useEffect(() => {
267
- return () => {
268
- unlockBodyScroll();
269
- };
270
- }, []);
271
- useLayoutEffect(() => {
272
- if (position === "auto") {
273
- setCurrentPosition(size === "small" ? "auto" : "bottom");
274
- return;
275
- }
276
- setCurrentPosition(correctPosition[position]);
277
- return () => {
278
- wosPosed.current.clear();
279
- };
280
- }, [position, size]);
281
- /* eslint consistent-return: off */
282
- useEffect(() => {
283
- if (!refs.floating.current || position !== "auto")
284
- return;
285
- const currentPopoverRect = refs.floating.current.getBoundingClientRect();
286
- const otherPopovers = document.querySelectorAll(".popover");
287
- let bestPosition = correctPosition[position];
288
- let leastOverlap = Infinity;
289
- let hasOverlap = false;
290
- const preventPosition = correctPosition[currentPosition];
291
- const updatePopoverPosition = () => {
292
- positions.forEach((possiblePositions) => {
293
- const rect = getPositionRect(currentPopoverRect, possiblePositions);
294
- let overlap = 0;
295
- otherPopovers.forEach((otherPopover) => {
296
- if (otherPopover === refs.floating.current)
297
- return;
298
- const otherRect = otherPopover.getBoundingClientRect();
299
- overlap += calculateOverlap(rect, otherRect);
300
- });
301
- if (overlap < leastOverlap) {
302
- leastOverlap = overlap;
303
- bestPosition = possiblePositions;
304
- }
305
- });
306
- hasOverlap = leastOverlap > 0;
307
- if (preventPosition !== bestPosition && !hasOverlap && !wosPosed.current.has(bestPosition)) {
308
- wosPosed.current.set(bestPosition, true);
309
- setCurrentPosition(bestPosition);
310
- }
311
- };
312
- const checkInterval = setInterval(() => {
313
- updatePopoverPosition();
314
- if (!hasOverlap) {
315
- clearInterval(checkInterval);
316
- }
317
- });
318
- return () => {
319
- clearInterval(checkInterval);
320
- leastOverlap = Infinity;
321
- };
322
- }, [popoverOpened, refs.floating.current, placement, position, currentPosition]);
323
- const arrowOffsetFromEdge = 5;
324
- return (React__default.createElement(React__default.Fragment, null, isShowPopover && (React__default.createElement(FloatingPortal, { root: geneUIProviderRef.current },
325
- React__default.createElement("div", Object.assign({ style: styles, className: `popover popover_size_${size} popover_position_${currentDirection}`, ref: refs.setFloating }, getFloatingProps()),
326
- size !== "mobile" && (React__default.createElement("div", { ref: arrowRef, className: "popover__arrow", style: Object.assign(Object.assign({}, getCorrectPosition), { top: middlewareArrowData === null || middlewareArrowData === void 0 ? void 0 : middlewareArrowData.y, [staticSide]: arrowRef.current
327
- ? `${-arrowRef.current.offsetWidth + arrowOffsetFromEdge}px`
328
- : 0 }) },
329
- React__default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "8", viewBox: "0 0 20 8", fill: "none" }, withArrow && (React__default.createElement("path", { d: "M8.75061 0.999513C9.48105 0.415163 10.519 0.415162 11.2494 0.999512L20 8H0L8.75061 0.999513Z", className: "popover__arrowPath" }))))),
330
- React__default.createElement("div", { className: "popover__container" },
331
- title && (React__default.createElement("div", { className: "popover__header" },
332
- React__default.createElement("p", { className: "popover__title" },
333
- React__default.createElement(SvgInfoOutlined, { className: "popover__title_icon", size: 20 }),
334
- React__default.createElement("span", { className: "popover__title_text ellipsis-text" }, title)),
335
- React__default.createElement(Button, { Icon: SvgX, size: "small", appearance: "secondary", displayType: "text", className: "popover__close", onClick: () => setPopoverOpened(false) }))),
336
- children))))));
337
- });
338
-
339
- const PopoverBody = ({ children, withPadding = true, className }) => {
340
- return (React__default.createElement("div", { className: classNames("popover__body", { popover__body_withPadding: withPadding }, className) },
341
- React__default.createElement("div", { className: "popover__content" },
342
- children,
343
- " ")));
344
- };
345
-
346
- const PopoverFooter = ({ children }) => {
347
- return React__default.createElement("div", { className: "popover__footer" }, children);
348
- };
349
-
350
- const PopoverFooterActions = ({ children }) => {
351
- return (React__default.createElement("div", { className: "popover__footer_buttons" },
352
- React__default.createElement("div", { className: "popover__footer_buttons" }, children)));
353
- };
354
-
355
- export { Popover as P, PopoverBody as a, PopoverFooter as b, PopoverFooterActions as c, useScrollLock as u };