@ultraviolet/ui 1.25.0 → 1.26.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.
- package/dist/index.d.ts +39 -21
- package/dist/src/components/MenuV2/index.js +6 -23
- package/dist/src/components/Modal/Dialog.js +3 -3
- package/dist/src/components/Popover/index.js +5 -20
- package/dist/src/components/Popup/animations.js +24 -0
- package/dist/src/components/Popup/helpers.js +72 -44
- package/dist/src/components/Popup/index.js +109 -85
- package/dist/src/components/Snippet/index.js +5 -4
- package/dist/src/components/Tabs/Tab.js +54 -21
- package/dist/src/components/Tabs/TabMenu.js +2 -0
- package/dist/src/components/Tabs/index.js +21 -6
- package/dist/src/components/Tooltip/index.js +3 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import react__default, { ReactNode, ComponentProps, ButtonHTMLAttributes, AriaRole, MouseEventHandler, JSX, MouseEvent, InputHTMLAttributes, HTMLAttributeAnchorTarget, AnchorHTMLAttributes, ReactElement, Ref,
|
|
2
|
+
import react__default, { ReactNode, ComponentProps, ButtonHTMLAttributes, AriaRole, MouseEventHandler, JSX, MouseEvent, InputHTMLAttributes, HTMLAttributeAnchorTarget, AnchorHTMLAttributes, ReactElement, Ref, RefObject, KeyboardEventHandler, HTMLAttributes, CSSProperties, ChangeEventHandler, FocusEventHandler, ForwardRefExoticComponent, ForwardedRef, ElementType, TextareaHTMLAttributes } from 'react';
|
|
3
3
|
import * as _emotion_react_jsx_runtime from '@emotion/react/jsx-runtime';
|
|
4
4
|
import * as _emotion_styled from '@emotion/styled';
|
|
5
5
|
import * as _emotion_react from '@emotion/react';
|
|
@@ -1232,7 +1232,7 @@ type BarStackProps = {
|
|
|
1232
1232
|
/**
|
|
1233
1233
|
* BarStack is a graphic component that is used to show data in one dimension.
|
|
1234
1234
|
*/
|
|
1235
|
-
declare const BarStack: ({ data, total, className, "data-testid": dataTestId, }: BarStackProps) => JSX.Element;
|
|
1235
|
+
declare const BarStack: ({ data, total, className, "data-testid": dataTestId, }: BarStackProps) => _emotion_react_jsx_runtime.JSX.Element;
|
|
1236
1236
|
|
|
1237
1237
|
type ItemProps$1 = {
|
|
1238
1238
|
children: ReactNode;
|
|
@@ -1329,8 +1329,8 @@ type CarouselProps = {
|
|
|
1329
1329
|
* Carousel component allows you to scroll horizontally through a list of items.
|
|
1330
1330
|
*/
|
|
1331
1331
|
declare const Carousel: {
|
|
1332
|
-
({ children, className, "data-testid": dataTestId, }: CarouselProps): JSX.Element;
|
|
1333
|
-
Item: ({ children, width, }: CarouselItemProps) => JSX.Element;
|
|
1332
|
+
({ children, className, "data-testid": dataTestId, }: CarouselProps): _emotion_react_jsx_runtime.JSX.Element;
|
|
1333
|
+
Item: ({ children, width, }: CarouselItemProps) => _emotion_react_jsx_runtime.JSX.Element;
|
|
1334
1334
|
};
|
|
1335
1335
|
|
|
1336
1336
|
type CheckboxProps = {
|
|
@@ -1695,7 +1695,7 @@ type PasswordStrengthMeterProps$1 = {
|
|
|
1695
1695
|
/**
|
|
1696
1696
|
* Show strength of a password based on different criteria.
|
|
1697
1697
|
*/
|
|
1698
|
-
declare const Meter: ({ strength, title, value, className, "data-testid": dataTestId, id, }: PasswordStrengthMeterProps$1) => JSX.Element;
|
|
1698
|
+
declare const Meter: ({ strength, title, value, className, "data-testid": dataTestId, id, }: PasswordStrengthMeterProps$1) => _emotion_react_jsx_runtime.JSX.Element;
|
|
1699
1699
|
|
|
1700
1700
|
type ModalSize = 'large' | 'medium' | 'small' | 'xsmall' | 'xxsmall';
|
|
1701
1701
|
type ModalPlacement = 'bottom' | 'bottom-left' | 'bottom-right' | 'center' | 'top' | 'top-left' | 'top-right' | 'right' | 'left';
|
|
@@ -1856,7 +1856,7 @@ type PaginationProps = {
|
|
|
1856
1856
|
* Pagination is a component to navigate between pages, it is composed of 2 buttons to go to the previous and next page,
|
|
1857
1857
|
* and a list of buttons to go to a specific page.
|
|
1858
1858
|
*/
|
|
1859
|
-
declare const Pagination: ({ disabled, page, pageCount, onChange, pageTabCount, className, "data-testid": dataTestId, }: PaginationProps) => JSX.Element;
|
|
1859
|
+
declare const Pagination: ({ disabled, page, pageCount, onChange, pageTabCount, className, "data-testid": dataTestId, }: PaginationProps) => _emotion_react_jsx_runtime.JSX.Element;
|
|
1860
1860
|
|
|
1861
1861
|
type Rule = {
|
|
1862
1862
|
name: string;
|
|
@@ -1915,7 +1915,7 @@ type PasswordStrengthMeterProps = {
|
|
|
1915
1915
|
* PasswordStrengthMeter is a component that displays a password strength meter.
|
|
1916
1916
|
* @deprecated use Meter component instead
|
|
1917
1917
|
*/
|
|
1918
|
-
declare const PasswordStrengthMeter: ({ password, onChange, strength, title, estimate, forbiddenInputs, className, "data-testid": dataTestId, }: PasswordStrengthMeterProps) => JSX.Element;
|
|
1918
|
+
declare const PasswordStrengthMeter: ({ password, onChange, strength, title, estimate, forbiddenInputs, className, "data-testid": dataTestId, }: PasswordStrengthMeterProps) => _emotion_react_jsx_runtime.JSX.Element;
|
|
1919
1919
|
|
|
1920
1920
|
type Data = {
|
|
1921
1921
|
name?: string | null;
|
|
@@ -1961,6 +1961,11 @@ declare const Popover: react.ForwardRefExoticComponent<{
|
|
|
1961
1961
|
'data-testid'?: string | undefined;
|
|
1962
1962
|
maxWidth?: string | undefined;
|
|
1963
1963
|
maxHeight?: string | undefined;
|
|
1964
|
+
/**
|
|
1965
|
+
* By default, the portal target is children container or document.body if children is a function. You can override this
|
|
1966
|
+
* behavior by setting a portalTarget prop.
|
|
1967
|
+
*/
|
|
1968
|
+
portalTarget?: HTMLElement | undefined;
|
|
1964
1969
|
} & Pick<{
|
|
1965
1970
|
id?: string | undefined;
|
|
1966
1971
|
children: ReactNode | ((renderProps: {
|
|
@@ -1983,17 +1988,18 @@ declare const Popover: react.ForwardRefExoticComponent<{
|
|
|
1983
1988
|
hasArrow?: boolean | undefined;
|
|
1984
1989
|
onClose?: (() => void) | undefined;
|
|
1985
1990
|
tabIndex?: number | undefined;
|
|
1986
|
-
onKeyDown?: KeyboardEventHandler | undefined;
|
|
1991
|
+
onKeyDown?: react.KeyboardEventHandler | undefined;
|
|
1987
1992
|
'aria-haspopup'?: boolean | "menu" | "dialog" | "grid" | "listbox" | "tree" | "false" | "true" | undefined;
|
|
1988
1993
|
hideOnClickOutside?: boolean | undefined;
|
|
1989
1994
|
needDebounce?: boolean | undefined;
|
|
1990
1995
|
maxHeight?: string | number | undefined;
|
|
1991
1996
|
disableAnimation?: boolean | undefined;
|
|
1997
|
+
portalTarget?: HTMLElement | undefined;
|
|
1992
1998
|
} & react.RefAttributes<HTMLDivElement>, "placement"> & react.RefAttributes<HTMLDivElement>>;
|
|
1993
1999
|
|
|
1994
2000
|
type PopupProps = {
|
|
1995
2001
|
/**
|
|
1996
|
-
* Id is automatically generated if not set. It is used for associating
|
|
2002
|
+
* Id is automatically generated if not set. It is used for associating popup wrapper with popup portal.
|
|
1997
2003
|
*/
|
|
1998
2004
|
id?: string;
|
|
1999
2005
|
children: ReactNode | ((renderProps: {
|
|
@@ -2006,20 +2012,20 @@ type PopupProps = {
|
|
|
2006
2012
|
}) => ReactNode);
|
|
2007
2013
|
maxWidth?: number | string;
|
|
2008
2014
|
/**
|
|
2009
|
-
* `auto` placement will change the position of the
|
|
2015
|
+
* `auto` placement will change the position of the popup if it doesn't fit in the viewport.
|
|
2010
2016
|
*/
|
|
2011
2017
|
placement?: PopupPlacement;
|
|
2012
2018
|
/**
|
|
2013
|
-
* Content of the
|
|
2019
|
+
* Content of the popup, preferably text inside.
|
|
2014
2020
|
*/
|
|
2015
2021
|
text?: ReactNode;
|
|
2016
2022
|
className?: string;
|
|
2017
2023
|
/**
|
|
2018
|
-
* It will add `width: 100%` to the
|
|
2024
|
+
* It will add `width: 100%` to the popup container.
|
|
2019
2025
|
*/
|
|
2020
2026
|
containerFullWidth?: boolean;
|
|
2021
2027
|
/**
|
|
2022
|
-
* It will force display
|
|
2028
|
+
* It will force display popup. This can be useful if you need to always display the popup without hover needed.
|
|
2023
2029
|
*/
|
|
2024
2030
|
visible?: boolean;
|
|
2025
2031
|
innerRef?: Ref<HTMLDivElement | null>;
|
|
@@ -2040,6 +2046,11 @@ type PopupProps = {
|
|
|
2040
2046
|
* Will remove the animation on the popup if set to false.
|
|
2041
2047
|
*/
|
|
2042
2048
|
disableAnimation?: boolean;
|
|
2049
|
+
/**
|
|
2050
|
+
* By default, the portal target is children container or document.body if children is a function. You can override this
|
|
2051
|
+
* behavior by setting a portalTarget prop.
|
|
2052
|
+
*/
|
|
2053
|
+
portalTarget?: HTMLElement;
|
|
2043
2054
|
};
|
|
2044
2055
|
/**
|
|
2045
2056
|
* @experimental This component is experimental and may be subject to breaking changes in the future.
|
|
@@ -2200,7 +2211,7 @@ type SeparatorProps = {
|
|
|
2200
2211
|
/**
|
|
2201
2212
|
* Separator component used to separate content with a horizontal or vertical line.
|
|
2202
2213
|
*/
|
|
2203
|
-
declare const Separator: ({ direction, thickness, color, icon, className, "data-testid": dataTestId, }: SeparatorProps) => JSX.Element;
|
|
2214
|
+
declare const Separator: ({ direction, thickness, color, icon, className, "data-testid": dataTestId, }: SeparatorProps) => _emotion_react_jsx_runtime.JSX.Element;
|
|
2204
2215
|
|
|
2205
2216
|
declare const variants$1: {
|
|
2206
2217
|
readonly block: ({ length }: {
|
|
@@ -2258,12 +2269,13 @@ type SnippetProps = {
|
|
|
2258
2269
|
showText?: string;
|
|
2259
2270
|
hideText?: string;
|
|
2260
2271
|
'data-testid'?: string;
|
|
2272
|
+
initiallyExpanded?: boolean;
|
|
2261
2273
|
} & Pick<ComponentProps<typeof CopyButton>, 'copyText' | 'copiedText'>;
|
|
2262
2274
|
/**
|
|
2263
2275
|
* Snippet component is used to display code snippets with the ability to copy the code.
|
|
2264
2276
|
* It also has the ability to show/hide the code snippet if it has more than 4 lines.
|
|
2265
2277
|
*/
|
|
2266
|
-
declare const Snippet: ({ children, copyText, copiedText, showText, hideText, prefix, className, "data-testid": dataTestId, }: SnippetProps) => _emotion_react_jsx_runtime.JSX.Element;
|
|
2278
|
+
declare const Snippet: ({ children, copyText, copiedText, showText, hideText, prefix, className, "data-testid": dataTestId, initiallyExpanded, }: SnippetProps) => _emotion_react_jsx_runtime.JSX.Element;
|
|
2267
2279
|
|
|
2268
2280
|
type StackProps = {
|
|
2269
2281
|
gap?: keyof UltravioletUITheme['space'] | number;
|
|
@@ -2314,7 +2326,7 @@ type StatusProps = {
|
|
|
2314
2326
|
/**
|
|
2315
2327
|
* Status component used to display a colored circle with a tooltip for additional information.
|
|
2316
2328
|
*/
|
|
2317
|
-
declare const Status: ({ animated, className, tooltip, sentiment, "data-testid": dataTestId, }: StatusProps) => JSX.Element;
|
|
2329
|
+
declare const Status: ({ animated, className, tooltip, sentiment, "data-testid": dataTestId, }: StatusProps) => _emotion_react_jsx_runtime.JSX.Element;
|
|
2318
2330
|
|
|
2319
2331
|
type Sizes = 'small' | 'medium';
|
|
2320
2332
|
type ContentProps = {
|
|
@@ -2485,10 +2497,11 @@ declare const Tabs: {
|
|
|
2485
2497
|
className?: string | undefined;
|
|
2486
2498
|
counter?: string | number | undefined;
|
|
2487
2499
|
disabled?: boolean | undefined;
|
|
2488
|
-
value?: string | number | undefined;
|
|
2489
2500
|
onClick?: react.MouseEventHandler<HTMLElement> | undefined;
|
|
2490
2501
|
onKeyDown?: react.KeyboardEventHandler<HTMLElement> | undefined;
|
|
2502
|
+
subtitle?: string | undefined;
|
|
2491
2503
|
tooltip?: string | undefined;
|
|
2504
|
+
value?: string | number | undefined;
|
|
2492
2505
|
} & Omit<any, "tooltip" | "children" | "role" | "className" | "as" | "disabled" | "value" | "badge" | "counter">, "ref"> & react.RefAttributes<HTMLElement>>;
|
|
2493
2506
|
Menu: react.ForwardRefExoticComponent<{
|
|
2494
2507
|
children: ReactNode;
|
|
@@ -2569,7 +2582,7 @@ type TagInputProps = {
|
|
|
2569
2582
|
* TagInput is a component that allows users to input tags.
|
|
2570
2583
|
* @experimental This component is experimental and may be subject to breaking changes in the future.
|
|
2571
2584
|
*/
|
|
2572
|
-
declare const TagInput: ({ disabled, id, manualInput, name, onChange, onChangeError, placeholder, tags, variant, className, "data-testid": dataTestId, }: TagInputProps) => JSX.Element;
|
|
2585
|
+
declare const TagInput: ({ disabled, id, manualInput, name, onChange, onChangeError, placeholder, tags, variant, className, "data-testid": dataTestId, }: TagInputProps) => _emotion_react_jsx_runtime.JSX.Element;
|
|
2573
2586
|
|
|
2574
2587
|
type TagListProps = {
|
|
2575
2588
|
/**
|
|
@@ -2598,7 +2611,7 @@ type TagListProps = {
|
|
|
2598
2611
|
/**
|
|
2599
2612
|
* This component is used to display a list of tags with a threshold and a popover when there are too many tags.
|
|
2600
2613
|
*/
|
|
2601
|
-
declare const TagList: ({ maxLength, tags, threshold, multiline, popoverTitle, copiable, copyText, copiedText, className, "data-testid": dataTestId, }: TagListProps) => JSX.Element | null;
|
|
2614
|
+
declare const TagList: ({ maxLength, tags, threshold, multiline, popoverTitle, copiable, copyText, copiedText, className, "data-testid": dataTestId, }: TagListProps) => _emotion_react_jsx_runtime.JSX.Element | null;
|
|
2602
2615
|
|
|
2603
2616
|
declare const PROMINENCES: {
|
|
2604
2617
|
default: string;
|
|
@@ -2800,7 +2813,7 @@ declare const ToggleGroup: {
|
|
|
2800
2813
|
Toggle: ({ disabled, name, value, label, helper, className, "data-testid": dataTestId, }: ToggleGroupToggleProps) => _emotion_react_jsx_runtime.JSX.Element;
|
|
2801
2814
|
};
|
|
2802
2815
|
|
|
2803
|
-
type TooltipProps = Pick<ComponentProps<typeof Popup>, 'id' | 'children' | 'maxWidth' | 'placement' | 'text' | 'className' | 'visible' | 'innerRef' | 'role' | 'data-testid' | 'containerFullWidth'>;
|
|
2816
|
+
type TooltipProps = Pick<ComponentProps<typeof Popup>, 'id' | 'children' | 'maxWidth' | 'placement' | 'text' | 'className' | 'visible' | 'innerRef' | 'role' | 'data-testid' | 'containerFullWidth' | 'portalTarget'>;
|
|
2804
2817
|
/**
|
|
2805
2818
|
* Tooltip component is used to display additional information on hover or focus.
|
|
2806
2819
|
* It is used to explain the purpose of the element it is attached to.
|
|
@@ -2838,7 +2851,7 @@ type VerificationCodeProps = {
|
|
|
2838
2851
|
/**
|
|
2839
2852
|
* Verification code allows you to enter a code in multiple fields (4 by default).
|
|
2840
2853
|
*/
|
|
2841
|
-
declare const VerificationCode: ({ disabled, className, error, fields, initialValue, inputId, inputStyle, onChange, onComplete, placeholder, required, type, "data-testid": dataTestId, "aria-label": ariaLabel, }: VerificationCodeProps) => JSX.Element;
|
|
2854
|
+
declare const VerificationCode: ({ disabled, className, error, fields, initialValue, inputId, inputStyle, onChange, onComplete, placeholder, required, type, "data-testid": dataTestId, "aria-label": ariaLabel, }: VerificationCodeProps) => _emotion_react_jsx_runtime.JSX.Element;
|
|
2842
2855
|
|
|
2843
2856
|
type RadioGroupRadioProps = Omit<ComponentProps<typeof Radio>, 'onChange' | 'checked' | 'required'>;
|
|
2844
2857
|
type RadioGroupProps = {
|
|
@@ -2879,6 +2892,11 @@ type MenuProps = {
|
|
|
2879
2892
|
'data-testid'?: string;
|
|
2880
2893
|
maxHeight?: string;
|
|
2881
2894
|
maxWidth?: string;
|
|
2895
|
+
/**
|
|
2896
|
+
* By default, the portal target is children container or document.body if children is a function. You can override this
|
|
2897
|
+
* behavior by setting a portalTarget prop.
|
|
2898
|
+
*/
|
|
2899
|
+
portalTarget?: HTMLElement;
|
|
2882
2900
|
};
|
|
2883
2901
|
/**
|
|
2884
2902
|
* A menu is a widget that offers a list of choices to the user, such as a set of actions or functions.
|
|
@@ -53,7 +53,8 @@ const FwdMenu = /*#__PURE__*/forwardRef((_ref7, ref) => {
|
|
|
53
53
|
className,
|
|
54
54
|
'data-testid': dataTestId,
|
|
55
55
|
maxHeight,
|
|
56
|
-
maxWidth
|
|
56
|
+
maxWidth,
|
|
57
|
+
portalTarget
|
|
57
58
|
} = _ref7;
|
|
58
59
|
const [isVisible, setIsVisible] = useState(visible);
|
|
59
60
|
const popupRef = useRef(null);
|
|
@@ -67,27 +68,8 @@ const FwdMenu = /*#__PURE__*/forwardRef((_ref7, ref) => {
|
|
|
67
68
|
});
|
|
68
69
|
const innerRef = useRef(target);
|
|
69
70
|
useImperativeHandle(ref, () => innerRef.current);
|
|
70
|
-
const toggleVisible = () => {
|
|
71
|
-
setIsVisible(!isVisible);
|
|
72
|
-
|
|
73
|
-
// Focus the first item when the menu is opened
|
|
74
|
-
if (!isVisible) {
|
|
75
|
-
setTimeout(() => {
|
|
76
|
-
// We have to wait for the popup to be inserted in the DOM
|
|
77
|
-
if (popupRef.current?.firstChild?.firstChild instanceof HTMLElement) {
|
|
78
|
-
popupRef.current.firstChild.firstChild.focus();
|
|
79
|
-
}
|
|
80
|
-
}, 1);
|
|
81
|
-
}
|
|
82
|
-
};
|
|
83
|
-
const onClose = () => {
|
|
84
|
-
setIsVisible(false);
|
|
85
|
-
|
|
86
|
-
// Focus the disclosure when the menu is closed
|
|
87
|
-
disclosureRef.current?.focus();
|
|
88
|
-
};
|
|
89
71
|
const finalDisclosure = /*#__PURE__*/cloneElement(target, {
|
|
90
|
-
onClick:
|
|
72
|
+
onClick: () => setIsVisible(!isVisible),
|
|
91
73
|
'aria-haspopup': 'dialog',
|
|
92
74
|
'aria-expanded': isVisible,
|
|
93
75
|
// @ts-expect-error not sure how to fix this
|
|
@@ -105,7 +87,7 @@ const FwdMenu = /*#__PURE__*/forwardRef((_ref7, ref) => {
|
|
|
105
87
|
role: "dialog",
|
|
106
88
|
id: finalId,
|
|
107
89
|
ref: popupRef,
|
|
108
|
-
onClose:
|
|
90
|
+
onClose: () => setIsVisible(false),
|
|
109
91
|
tabIndex: -1,
|
|
110
92
|
maxHeight: maxHeight,
|
|
111
93
|
maxWidth: maxWidth,
|
|
@@ -114,9 +96,10 @@ const FwdMenu = /*#__PURE__*/forwardRef((_ref7, ref) => {
|
|
|
114
96
|
className: className,
|
|
115
97
|
role: "menu",
|
|
116
98
|
children: typeof children === 'function' ? children({
|
|
117
|
-
toggle:
|
|
99
|
+
toggle: () => setIsVisible(!isVisible)
|
|
118
100
|
}) : children
|
|
119
101
|
}),
|
|
102
|
+
portalTarget: portalTarget,
|
|
120
103
|
children: finalDisclosure
|
|
121
104
|
});
|
|
122
105
|
});
|
|
@@ -11,7 +11,7 @@ const StyledBackdrop = /*#__PURE__*/_styled("div", {
|
|
|
11
11
|
theme
|
|
12
12
|
} = _ref;
|
|
13
13
|
return theme.colors.overlay;
|
|
14
|
-
}, ";&[data-open='true']{padding:", _ref2 => {
|
|
14
|
+
}, ";z-index:1;&[data-open='true']{padding:", _ref2 => {
|
|
15
15
|
let {
|
|
16
16
|
theme
|
|
17
17
|
} = _ref2;
|
|
@@ -175,7 +175,7 @@ const Dialog = _ref9 => {
|
|
|
175
175
|
event.preventDefault();
|
|
176
176
|
event.stopPropagation();
|
|
177
177
|
};
|
|
178
|
-
return /*#__PURE__*/createPortal(jsx(StyledBackdrop, {
|
|
178
|
+
return open ? /*#__PURE__*/createPortal(jsx(StyledBackdrop, {
|
|
179
179
|
"data-open": open,
|
|
180
180
|
onClick: handleClose,
|
|
181
181
|
className: backdropClassName,
|
|
@@ -201,7 +201,7 @@ const Dialog = _ref9 => {
|
|
|
201
201
|
tabIndex: 0,
|
|
202
202
|
children: open ? children : null
|
|
203
203
|
})
|
|
204
|
-
}), containerRef.current);
|
|
204
|
+
}), containerRef.current) : null;
|
|
205
205
|
};
|
|
206
206
|
|
|
207
207
|
export { Dialog };
|
|
@@ -72,10 +72,6 @@ const ContentWrapper = _ref6 => {
|
|
|
72
72
|
children,
|
|
73
73
|
sentiment
|
|
74
74
|
} = _ref6;
|
|
75
|
-
const buttonRef = useRef(null);
|
|
76
|
-
useEffect(() => {
|
|
77
|
-
buttonRef.current?.focus();
|
|
78
|
-
}, []);
|
|
79
75
|
return jsxs(StyledStack, {
|
|
80
76
|
gap: 1,
|
|
81
77
|
children: [jsxs(Stack, {
|
|
@@ -93,8 +89,7 @@ const ContentWrapper = _ref6 => {
|
|
|
93
89
|
onClick: onClose,
|
|
94
90
|
size: "small",
|
|
95
91
|
icon: "close",
|
|
96
|
-
"aria-label": "close"
|
|
97
|
-
ref: buttonRef
|
|
92
|
+
"aria-label": "close"
|
|
98
93
|
})]
|
|
99
94
|
}), typeof children === 'string' ? jsx(Text, {
|
|
100
95
|
variant: "bodySmall",
|
|
@@ -122,7 +117,8 @@ const Popover = /*#__PURE__*/forwardRef((_ref7, ref) => {
|
|
|
122
117
|
className,
|
|
123
118
|
maxWidth,
|
|
124
119
|
maxHeight,
|
|
125
|
-
'data-testid': dataTestId
|
|
120
|
+
'data-testid': dataTestId,
|
|
121
|
+
portalTarget
|
|
126
122
|
} = _ref7;
|
|
127
123
|
const innerRef = useRef(null);
|
|
128
124
|
const [localVisible, setLocalVisible] = useState(visible);
|
|
@@ -131,21 +127,9 @@ const Popover = /*#__PURE__*/forwardRef((_ref7, ref) => {
|
|
|
131
127
|
useEffect(() => {
|
|
132
128
|
setLocalVisible(visible);
|
|
133
129
|
}, [visible]);
|
|
134
|
-
|
|
135
|
-
// When space key is pressed we show the popover
|
|
136
|
-
const onKeyDownSpace = useCallback(event => {
|
|
137
|
-
if (event.code === 'Space') {
|
|
138
|
-
event.preventDefault();
|
|
139
|
-
event.stopPropagation();
|
|
140
|
-
setLocalVisible(true);
|
|
141
|
-
}
|
|
142
|
-
}, []);
|
|
143
|
-
|
|
144
|
-
// When we close we hide the popover and focus the disclosure element
|
|
145
130
|
const localOnClose = useCallback(() => {
|
|
146
131
|
setLocalVisible(false);
|
|
147
132
|
onClose?.();
|
|
148
|
-
innerRef.current?.focus();
|
|
149
133
|
}, [onClose]);
|
|
150
134
|
return jsx(StyledPopup, {
|
|
151
135
|
hideOnClickOutside: true,
|
|
@@ -164,11 +148,12 @@ const Popover = /*#__PURE__*/forwardRef((_ref7, ref) => {
|
|
|
164
148
|
size: size,
|
|
165
149
|
role: "dialog",
|
|
166
150
|
ref: ref,
|
|
151
|
+
tabIndex: -1,
|
|
167
152
|
innerRef: innerRef,
|
|
168
153
|
onClose: localOnClose,
|
|
169
|
-
onKeyDown: onKeyDownSpace,
|
|
170
154
|
maxWidth: maxWidth,
|
|
171
155
|
maxHeight: maxHeight,
|
|
156
|
+
portalTarget: portalTarget,
|
|
172
157
|
children: children
|
|
173
158
|
});
|
|
174
159
|
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { keyframes } from '@emotion/react';
|
|
2
|
+
|
|
3
|
+
const animation = positions => keyframes`
|
|
4
|
+
0% {
|
|
5
|
+
opacity: 0;
|
|
6
|
+
transform: ${positions.popupInitialPosition};
|
|
7
|
+
}
|
|
8
|
+
100% {
|
|
9
|
+
opacity: 1;
|
|
10
|
+
transform: ${positions.popupPosition};
|
|
11
|
+
}
|
|
12
|
+
`;
|
|
13
|
+
const exitAnimation = positions => keyframes`
|
|
14
|
+
0% {
|
|
15
|
+
opacity: 1;
|
|
16
|
+
transform: ${positions.popupPosition};
|
|
17
|
+
}
|
|
18
|
+
100% {
|
|
19
|
+
opacity: 0;
|
|
20
|
+
transform: ${positions.popupInitialPosition};
|
|
21
|
+
}
|
|
22
|
+
`;
|
|
23
|
+
|
|
24
|
+
export { animation, exitAnimation };
|
|
@@ -1,57 +1,75 @@
|
|
|
1
1
|
const ARROW_WIDTH = 8; // in px
|
|
2
2
|
const SPACE = 4; // in px
|
|
3
|
-
const TOTAL_USED_SPACE =
|
|
3
|
+
const TOTAL_USED_SPACE = 0; // in px
|
|
4
4
|
const DEFAULT_POSITIONS = {
|
|
5
5
|
arrowLeft: -999,
|
|
6
6
|
arrowTop: -999,
|
|
7
7
|
arrowTransform: 'translate(-50%, -50)',
|
|
8
8
|
placement: 'top',
|
|
9
9
|
rotate: 135,
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
popupInitialPosition: 'translate3d(-999px, -999px, 0)',
|
|
11
|
+
popupPosition: 'translate3d(-999px, -999px, 0)'
|
|
12
12
|
};
|
|
13
13
|
/**
|
|
14
|
-
* This function will find the best placement in a window for
|
|
14
|
+
* This function will find the best placement in a window for popup based on children position and popup size
|
|
15
15
|
*/
|
|
16
16
|
const computePlacement = _ref => {
|
|
17
17
|
let {
|
|
18
18
|
childrenStructuredRef,
|
|
19
|
-
|
|
19
|
+
popupStructuredRef,
|
|
20
|
+
offsetParentRect,
|
|
21
|
+
popupPortalTarget
|
|
20
22
|
} = _ref;
|
|
21
23
|
const {
|
|
22
|
-
top:
|
|
23
|
-
left:
|
|
24
|
+
top: childrenTop,
|
|
25
|
+
left: childrenLeft,
|
|
24
26
|
right: childrenRight
|
|
25
27
|
} = childrenStructuredRef;
|
|
26
28
|
const {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
top: parentTop,
|
|
30
|
+
left: parentLeft,
|
|
31
|
+
right: parentRight
|
|
32
|
+
} = offsetParentRect;
|
|
33
|
+
const overloadedChildrenLeft = popupPortalTarget === document.body ? childrenLeft : childrenLeft - parentLeft;
|
|
34
|
+
const overloadedChildrenTop = popupPortalTarget === document.body ? childrenTop : childrenTop - parentTop;
|
|
35
|
+
const overloadedChildrenRight = popupPortalTarget === document.body ? childrenRight : childrenRight - parentRight;
|
|
36
|
+
const {
|
|
37
|
+
width: popupWidth,
|
|
38
|
+
height: popupHeight
|
|
39
|
+
} = popupStructuredRef;
|
|
40
|
+
if (overloadedChildrenTop - popupHeight - TOTAL_USED_SPACE < 0) {
|
|
31
41
|
return 'bottom';
|
|
32
42
|
}
|
|
33
|
-
if (
|
|
43
|
+
if (overloadedChildrenLeft - popupWidth - TOTAL_USED_SPACE < 0) {
|
|
34
44
|
return 'right';
|
|
35
45
|
}
|
|
36
|
-
if (
|
|
46
|
+
if (overloadedChildrenRight + popupWidth + TOTAL_USED_SPACE > window.innerWidth) {
|
|
37
47
|
return 'left';
|
|
38
48
|
}
|
|
39
49
|
return 'top';
|
|
40
50
|
};
|
|
41
51
|
/**
|
|
42
|
-
* This function will compute the positions of
|
|
52
|
+
* This function will compute the positions of popup and arrow based on children position and popup size
|
|
43
53
|
*/
|
|
44
54
|
const computePositions = _ref2 => {
|
|
45
55
|
let {
|
|
46
56
|
placement,
|
|
47
57
|
childrenRef,
|
|
48
|
-
|
|
58
|
+
popupRef,
|
|
59
|
+
popupPortalTarget
|
|
49
60
|
} = _ref2;
|
|
50
61
|
const childrenStructuredRef = childrenRef.current.getBoundingClientRect();
|
|
51
|
-
const
|
|
62
|
+
const offsetParentRect = childrenRef?.current?.offsetParent?.getBoundingClientRect() ?? {
|
|
63
|
+
top: 0,
|
|
64
|
+
left: 0,
|
|
65
|
+
right: 0
|
|
66
|
+
};
|
|
67
|
+
const popupStructuredRef = popupRef.current.getBoundingClientRect();
|
|
52
68
|
const placementBasedOnWindowSize = placement === 'auto' ? computePlacement({
|
|
53
69
|
childrenStructuredRef,
|
|
54
|
-
|
|
70
|
+
popupStructuredRef,
|
|
71
|
+
offsetParentRect: offsetParentRect,
|
|
72
|
+
popupPortalTarget
|
|
55
73
|
}) : placement;
|
|
56
74
|
const {
|
|
57
75
|
top: childrenTop,
|
|
@@ -61,68 +79,78 @@ const computePositions = _ref2 => {
|
|
|
61
79
|
height: childrenHeight
|
|
62
80
|
} = childrenStructuredRef;
|
|
63
81
|
const {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
82
|
+
top: parentTop,
|
|
83
|
+
left: parentLeft,
|
|
84
|
+
right: parentRight
|
|
85
|
+
} = offsetParentRect;
|
|
86
|
+
const {
|
|
87
|
+
width: popupWidth,
|
|
88
|
+
height: popupHeight
|
|
89
|
+
} = popupStructuredRef;
|
|
90
|
+
|
|
91
|
+
// It will get how much scroll is done on the page to compute the position of the popup
|
|
92
|
+
const scrollTopValue = popupPortalTarget === document.body ? document.documentElement.scrollTop : 0;
|
|
67
93
|
|
|
68
|
-
//
|
|
69
|
-
const
|
|
94
|
+
// We need to compute the position of the popup based on the parent element in the case the popup is not in the body
|
|
95
|
+
const overloadedChildrenLeft = popupPortalTarget === document.body ? childrenLeft : childrenLeft - parentLeft;
|
|
96
|
+
const overloadedChildrenTop = popupPortalTarget === document.body ? childrenTop : childrenTop - parentTop;
|
|
97
|
+
const overloadedChildrenRight = popupPortalTarget === document.body ? childrenRight : childrenRight + childrenWidth + ARROW_WIDTH + SPACE - parentRight / 2;
|
|
70
98
|
switch (placementBasedOnWindowSize) {
|
|
71
99
|
case 'bottom':
|
|
72
100
|
{
|
|
73
|
-
const positionX =
|
|
74
|
-
const positionY =
|
|
101
|
+
const positionX = overloadedChildrenLeft + childrenWidth / 2 - popupWidth / 2;
|
|
102
|
+
const positionY = overloadedChildrenTop + scrollTopValue + childrenHeight + ARROW_WIDTH + SPACE;
|
|
75
103
|
return {
|
|
76
|
-
arrowLeft:
|
|
104
|
+
arrowLeft: popupWidth / 2,
|
|
77
105
|
arrowTop: -ARROW_WIDTH - 5,
|
|
78
106
|
arrowTransform: '',
|
|
79
107
|
placement: 'bottom',
|
|
80
108
|
rotate: 180,
|
|
81
|
-
|
|
82
|
-
|
|
109
|
+
popupInitialPosition: `translate3d(${positionX}px, ${positionY - TOTAL_USED_SPACE}px, 0)`,
|
|
110
|
+
popupPosition: `translate3d(${positionX}px, ${positionY}px, 0)`
|
|
83
111
|
};
|
|
84
112
|
}
|
|
85
113
|
case 'left':
|
|
86
114
|
{
|
|
87
|
-
const positionX =
|
|
88
|
-
const positionY =
|
|
115
|
+
const positionX = overloadedChildrenLeft - popupWidth - ARROW_WIDTH - SPACE * 2;
|
|
116
|
+
const positionY = overloadedChildrenTop + scrollTopValue - popupHeight / 2 + childrenHeight / 2;
|
|
89
117
|
return {
|
|
90
|
-
arrowLeft:
|
|
91
|
-
arrowTop:
|
|
118
|
+
arrowLeft: popupWidth + ARROW_WIDTH + 5,
|
|
119
|
+
arrowTop: popupHeight / 2,
|
|
92
120
|
arrowTransform: 'translate(-50%, -50%)',
|
|
93
121
|
placement: 'left',
|
|
94
122
|
rotate: -90,
|
|
95
|
-
|
|
96
|
-
|
|
123
|
+
popupInitialPosition: `translate3d(${positionX + TOTAL_USED_SPACE}px, ${positionY}px, 0)`,
|
|
124
|
+
popupPosition: `translate3d(${positionX}px, ${positionY}px, 0)`
|
|
97
125
|
};
|
|
98
126
|
}
|
|
99
127
|
case 'right':
|
|
100
128
|
{
|
|
101
|
-
const positionX =
|
|
102
|
-
const positionY =
|
|
129
|
+
const positionX = overloadedChildrenRight + ARROW_WIDTH + SPACE * 2;
|
|
130
|
+
const positionY = overloadedChildrenTop + scrollTopValue - popupHeight / 2 + childrenHeight / 2;
|
|
103
131
|
return {
|
|
104
132
|
arrowLeft: -ARROW_WIDTH - 5,
|
|
105
|
-
arrowTop:
|
|
133
|
+
arrowTop: popupHeight / 2,
|
|
106
134
|
arrowTransform: 'translate(50%, -50%)',
|
|
107
135
|
placement: 'right',
|
|
108
136
|
rotate: 90,
|
|
109
|
-
|
|
110
|
-
|
|
137
|
+
popupInitialPosition: `translate3d(${positionX - TOTAL_USED_SPACE}px, ${positionY}px, 0)`,
|
|
138
|
+
popupPosition: `translate3d(${positionX}px, ${positionY}px, 0)`
|
|
111
139
|
};
|
|
112
140
|
}
|
|
113
141
|
default:
|
|
114
142
|
{
|
|
115
143
|
// top placement is default value
|
|
116
|
-
const positionX =
|
|
117
|
-
const positionY =
|
|
144
|
+
const positionX = overloadedChildrenLeft + childrenWidth / 2 - popupWidth / 2;
|
|
145
|
+
const positionY = overloadedChildrenTop + scrollTopValue - popupHeight - ARROW_WIDTH - SPACE;
|
|
118
146
|
return {
|
|
119
|
-
arrowLeft:
|
|
120
|
-
arrowTop:
|
|
147
|
+
arrowLeft: popupWidth / 2,
|
|
148
|
+
arrowTop: popupHeight - 1,
|
|
121
149
|
arrowTransform: '',
|
|
122
150
|
placement: 'top',
|
|
123
151
|
rotate: 0,
|
|
124
|
-
|
|
125
|
-
|
|
152
|
+
popupInitialPosition: `translate3d(${positionX}px, ${positionY + TOTAL_USED_SPACE}px, 0)`,
|
|
153
|
+
popupPosition: `translate3d(${positionX}px, ${positionY}px, 0)`
|
|
126
154
|
};
|
|
127
155
|
}
|
|
128
156
|
}
|
|
@@ -1,36 +1,18 @@
|
|
|
1
1
|
import _styled from '@emotion/styled/base';
|
|
2
|
-
import { css
|
|
3
|
-
import { forwardRef, useRef, useImperativeHandle, useState, useId, useCallback, useEffect } from 'react';
|
|
2
|
+
import { css } from '@emotion/react';
|
|
3
|
+
import { forwardRef, useRef, useImperativeHandle, useMemo, useState, useId, useCallback, useEffect } from 'react';
|
|
4
4
|
import { createPortal } from 'react-dom';
|
|
5
|
+
import { animation, exitAnimation } from './animations.js';
|
|
5
6
|
import { DEFAULT_POSITIONS, computePositions, ARROW_WIDTH } from './helpers.js';
|
|
6
7
|
import { jsx, Fragment, jsxs } from '@emotion/react/jsx-runtime';
|
|
7
8
|
|
|
8
9
|
function _EMOTION_STRINGIFIED_CSS_ERROR__() { return "You have tried to stringify object returned from `css` function. It isn't supposed to be used directly (e.g. as value of the `className` prop), but rather handed to emotion so it can handle it (e.g. as value of `css` prop)."; }
|
|
9
10
|
const DEFAULT_ANIMATION_DURATION = 230; // in ms
|
|
10
|
-
const DEFAULT_DEBOUNCE_DURATION = 200;
|
|
11
|
+
const DEFAULT_DEBOUNCE_DURATION = 200; // in ms
|
|
12
|
+
|
|
11
13
|
function noop() {}
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
opacity: 0;
|
|
15
|
-
transform: ${positions.tooltipInitialPosition};
|
|
16
|
-
}
|
|
17
|
-
100% {
|
|
18
|
-
opacity: 1;
|
|
19
|
-
transform: ${positions.tooltipPosition};
|
|
20
|
-
}
|
|
21
|
-
`;
|
|
22
|
-
const exitAnimation = positions => keyframes`
|
|
23
|
-
0% {
|
|
24
|
-
opacity: 1;
|
|
25
|
-
transform: ${positions.tooltipPosition};
|
|
26
|
-
}
|
|
27
|
-
100% {
|
|
28
|
-
opacity: 0;
|
|
29
|
-
transform: ${positions.tooltipInitialPosition};
|
|
30
|
-
}
|
|
31
|
-
`;
|
|
32
|
-
const StyledTooltip = /*#__PURE__*/_styled('div', {
|
|
33
|
-
shouldForwardProp: prop => !['maxWidth', 'positions', 'reverseAnimation', 'maxHeight', 'animationDuration'].includes(prop),
|
|
14
|
+
const StyledPopup = /*#__PURE__*/_styled('div', {
|
|
15
|
+
shouldForwardProp: prop => !['maxWidth', 'positions', 'reverseAnimation', 'maxHeight', 'animationDuration', 'isDialog'].includes(prop),
|
|
34
16
|
target: "e4h1g861"
|
|
35
17
|
})("background:", _ref => {
|
|
36
18
|
let {
|
|
@@ -67,11 +49,11 @@ const StyledTooltip = /*#__PURE__*/_styled('div', {
|
|
|
67
49
|
maxHeight
|
|
68
50
|
} = _ref7;
|
|
69
51
|
return maxHeight ? 'auto' : undefined;
|
|
70
|
-
}, ";overflow-wrap:break-word;font-size:0.8rem;inset:0 auto auto 0;top:0;left:0;transform:", _ref8 => {
|
|
52
|
+
}, ";overflow-wrap:break-word;font-size:0.8rem;inset:0 auto auto 0;top:0;left:0;z-index:1;transform:", _ref8 => {
|
|
71
53
|
let {
|
|
72
54
|
positions
|
|
73
55
|
} = _ref8;
|
|
74
|
-
return positions.
|
|
56
|
+
return positions.popupPosition;
|
|
75
57
|
}, ";animation:", _ref9 => {
|
|
76
58
|
let {
|
|
77
59
|
positions,
|
|
@@ -131,7 +113,7 @@ const Popup = /*#__PURE__*/forwardRef((_ref15, ref) => {
|
|
|
131
113
|
maxHeight,
|
|
132
114
|
visible,
|
|
133
115
|
innerRef,
|
|
134
|
-
role = '
|
|
116
|
+
role = 'popup',
|
|
135
117
|
'data-testid': dataTestId,
|
|
136
118
|
hasArrow = true,
|
|
137
119
|
onClose,
|
|
@@ -140,18 +122,34 @@ const Popup = /*#__PURE__*/forwardRef((_ref15, ref) => {
|
|
|
140
122
|
'aria-haspopup': ariaHasPopup,
|
|
141
123
|
hideOnClickOutside = false,
|
|
142
124
|
needDebounce = true,
|
|
143
|
-
disableAnimation = false
|
|
125
|
+
disableAnimation = false,
|
|
126
|
+
portalTarget
|
|
144
127
|
} = _ref15;
|
|
145
128
|
const childrenRef = useRef(null);
|
|
146
129
|
useImperativeHandle(innerRef, () => childrenRef.current);
|
|
147
|
-
const
|
|
148
|
-
useImperativeHandle(ref, () =>
|
|
130
|
+
const innerPopupRef = useRef(null);
|
|
131
|
+
useImperativeHandle(ref, () => innerPopupRef.current);
|
|
149
132
|
const timer = useRef();
|
|
133
|
+
const popupPortalTarget = useMemo(() => {
|
|
134
|
+
if (role === 'dialog') {
|
|
135
|
+
if (portalTarget) return portalTarget;
|
|
136
|
+
if (childrenRef.current) return childrenRef.current;
|
|
137
|
+
if (typeof window !== 'undefined') return document.body;
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// We check if window exists for SSR
|
|
142
|
+
if (typeof window !== 'undefined') {
|
|
143
|
+
return document.body;
|
|
144
|
+
}
|
|
145
|
+
return null;
|
|
146
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
147
|
+
}, [portalTarget, role, childrenRef.current]);
|
|
150
148
|
|
|
151
149
|
// There are some issue when mixing animation and maxHeight on some browsers, so we disable animation if maxHeight is set.
|
|
152
150
|
const animationDuration = disableAnimation || maxHeight ? 0 : DEFAULT_ANIMATION_DURATION;
|
|
153
151
|
|
|
154
|
-
// Debounce timer will be used to prevent the
|
|
152
|
+
// Debounce timer will be used to prevent the popup from flickering when the user moves the mouse out and in the children element.
|
|
155
153
|
const debounceTimer = useRef();
|
|
156
154
|
const [visibleInDom, setVisibleInDom] = useState(false);
|
|
157
155
|
const [reverseAnimation, setReverseAnimation] = useState(false);
|
|
@@ -161,70 +159,71 @@ const Popup = /*#__PURE__*/forwardRef((_ref15, ref) => {
|
|
|
161
159
|
const uniqueId = useId();
|
|
162
160
|
const generatedId = id ?? uniqueId;
|
|
163
161
|
const isControlled = visible !== undefined;
|
|
164
|
-
const
|
|
165
|
-
if (childrenRef.current &&
|
|
162
|
+
const generatePopupPositions = useCallback(() => {
|
|
163
|
+
if (childrenRef.current && innerPopupRef.current) {
|
|
166
164
|
setPositions(computePositions({
|
|
167
165
|
childrenRef,
|
|
168
166
|
placement,
|
|
169
|
-
|
|
167
|
+
popupRef: innerPopupRef,
|
|
168
|
+
popupPortalTarget: popupPortalTarget
|
|
170
169
|
}));
|
|
171
170
|
}
|
|
172
|
-
}, [
|
|
171
|
+
}, [placement, popupPortalTarget]);
|
|
173
172
|
|
|
174
173
|
/**
|
|
175
|
-
* This function is called when we need to recompute positions of
|
|
174
|
+
* This function is called when we need to recompute positions of popup due to window scroll or resize.
|
|
176
175
|
*/
|
|
177
176
|
const onWindowChangeDetected = useCallback(() => {
|
|
178
177
|
// We remove animation on scroll or the animation will restart on every scroll
|
|
179
|
-
if (
|
|
180
|
-
|
|
178
|
+
if (innerPopupRef.current) {
|
|
179
|
+
innerPopupRef.current.style.animation = 'none';
|
|
181
180
|
}
|
|
182
|
-
|
|
183
|
-
}, [
|
|
181
|
+
generatePopupPositions();
|
|
182
|
+
}, [generatePopupPositions, innerPopupRef]);
|
|
184
183
|
|
|
185
184
|
/**
|
|
186
|
-
* This function is called when we need to remove
|
|
185
|
+
* This function is called when we need to remove popup portal from DOM and remove event listener to it.
|
|
187
186
|
*/
|
|
188
|
-
const
|
|
187
|
+
const unmountPopupFromDom = useCallback(() => {
|
|
189
188
|
setVisibleInDom(false);
|
|
190
189
|
setReverseAnimation(false);
|
|
191
190
|
window.removeEventListener('scroll', onWindowChangeDetected, true);
|
|
192
191
|
}, [onWindowChangeDetected]);
|
|
193
192
|
|
|
194
193
|
/**
|
|
195
|
-
* This function is called when we need to hide
|
|
196
|
-
*
|
|
194
|
+
* This function is called when we need to hide popup. A timeout is set to allow animation end, then remove
|
|
195
|
+
* popup from dom.
|
|
197
196
|
*/
|
|
198
|
-
const
|
|
197
|
+
const closePopup = useCallback(() => {
|
|
199
198
|
debounceTimer.current = setTimeout(() => {
|
|
200
199
|
setReverseAnimation(true);
|
|
201
200
|
timer.current = setTimeout(() => {
|
|
202
|
-
|
|
201
|
+
unmountPopupFromDom();
|
|
203
202
|
onClose?.();
|
|
204
203
|
}, animationDuration);
|
|
205
204
|
}, needDebounce && !disableAnimation ? DEFAULT_DEBOUNCE_DURATION : 0);
|
|
206
|
-
}, [animationDuration, disableAnimation, needDebounce, onClose,
|
|
205
|
+
}, [animationDuration, disableAnimation, needDebounce, onClose, unmountPopupFromDom]);
|
|
207
206
|
|
|
208
207
|
/**
|
|
209
|
-
* When mouse hover or stop hovering children this function display or hide
|
|
210
|
-
* end, then remove
|
|
208
|
+
* When mouse hover or stop hovering children this function display or hide popup. A timeout is set to allow animation
|
|
209
|
+
* end, then remove popup from dom.
|
|
211
210
|
*/
|
|
212
211
|
const onPointerEvent = useCallback(isVisible => () => {
|
|
213
|
-
// This condition is for when we want to unmount the
|
|
214
|
-
// There is debounce in order to avoid
|
|
212
|
+
// This condition is for when we want to unmount the popup
|
|
213
|
+
// There is debounce in order to avoid popup to flicker when we move the mouse from children to popup
|
|
215
214
|
// Timer is used to follow the animation duration
|
|
216
|
-
if (!isVisible &&
|
|
217
|
-
|
|
215
|
+
if (!isVisible && innerPopupRef.current && !debounceTimer.current) {
|
|
216
|
+
closePopup();
|
|
218
217
|
} else if (isVisible) {
|
|
219
|
-
// This condition is for when we want to mount the
|
|
220
|
-
// If the timer exists it means the
|
|
221
|
-
// so we clear the timer and the
|
|
218
|
+
// This condition is for when we want to mount the popup
|
|
219
|
+
// If the timer exists it means the popup was about to umount, but we hovered the children again,
|
|
220
|
+
// so we clear the timer and the popup will not be unmounted
|
|
222
221
|
if (timer.current) {
|
|
223
222
|
setReverseAnimation(false);
|
|
224
223
|
clearTimeout(timer.current);
|
|
225
224
|
timer.current = undefined;
|
|
226
225
|
}
|
|
227
|
-
// And here is when we currently are in a debounce timer, it means
|
|
226
|
+
// And here is when we currently are in a debounce timer, it means popup was hovered during
|
|
228
227
|
// that period, and so we can clear debounce timer
|
|
229
228
|
if (debounceTimer.current) {
|
|
230
229
|
clearTimeout(debounceTimer.current);
|
|
@@ -232,20 +231,21 @@ const Popup = /*#__PURE__*/forwardRef((_ref15, ref) => {
|
|
|
232
231
|
}
|
|
233
232
|
setVisibleInDom(true);
|
|
234
233
|
}
|
|
235
|
-
}, [
|
|
234
|
+
}, [closePopup, innerPopupRef]);
|
|
236
235
|
|
|
237
236
|
/**
|
|
238
|
-
* Once
|
|
237
|
+
* Once popup is visible in the dom we can compute positions, then set it visible on screen and add event to
|
|
239
238
|
* recompute positions on scroll or screen resize.
|
|
240
239
|
*/
|
|
241
240
|
useEffect(() => {
|
|
242
241
|
if (visibleInDom) {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
242
|
+
generatePopupPositions();
|
|
243
|
+
if (popupPortalTarget === document.body) {
|
|
244
|
+
// We want to detect scroll and resize in order to recompute positions of popup
|
|
245
|
+
// Adding true as third parameter to event listener will detect nested scrolls.
|
|
246
|
+
window.addEventListener('scroll', onWindowChangeDetected, true);
|
|
247
|
+
window.addEventListener('resize', onWindowChangeDetected, true);
|
|
248
|
+
}
|
|
249
249
|
}
|
|
250
250
|
return () => {
|
|
251
251
|
window.removeEventListener('scroll', onWindowChangeDetected, true);
|
|
@@ -255,22 +255,17 @@ const Popup = /*#__PURE__*/forwardRef((_ref15, ref) => {
|
|
|
255
255
|
timer.current = undefined;
|
|
256
256
|
}
|
|
257
257
|
};
|
|
258
|
-
}, [
|
|
258
|
+
}, [generatePopupPositions, onWindowChangeDetected, visibleInDom, maxWidth, popupPortalTarget]);
|
|
259
259
|
|
|
260
260
|
/**
|
|
261
|
-
* If
|
|
262
|
-
* In this cas we don't want to display
|
|
261
|
+
* If popup has `visible` prop it means the popup is manually controlled through this prop.
|
|
262
|
+
* In this cas we don't want to display popup on hover, but only when `visible` is true.
|
|
263
263
|
*/
|
|
264
264
|
useEffect(() => {
|
|
265
265
|
if (isControlled) {
|
|
266
266
|
onPointerEvent(visible)();
|
|
267
267
|
}
|
|
268
268
|
}, [isControlled, onPointerEvent, visible]);
|
|
269
|
-
const onLocalKeyDown = useCallback(event => {
|
|
270
|
-
if (event.code === 'Escape') {
|
|
271
|
-
unmountTooltip();
|
|
272
|
-
}
|
|
273
|
-
}, [unmountTooltip]);
|
|
274
269
|
|
|
275
270
|
// Handle hide on esc press and hide on click outside
|
|
276
271
|
useEffect(() => {
|
|
@@ -278,17 +273,17 @@ const Popup = /*#__PURE__*/forwardRef((_ref15, ref) => {
|
|
|
278
273
|
if (event.key === 'Escape') {
|
|
279
274
|
event.preventDefault();
|
|
280
275
|
event.stopPropagation();
|
|
281
|
-
|
|
276
|
+
closePopup();
|
|
282
277
|
}
|
|
283
278
|
};
|
|
284
279
|
const handleClickOutside = event => {
|
|
285
|
-
const
|
|
280
|
+
const popupCurrent = innerPopupRef.current;
|
|
286
281
|
const childrenCurrent = childrenRef.current;
|
|
287
|
-
if (
|
|
288
|
-
if (event.target && event.target !==
|
|
282
|
+
if (popupCurrent && hideOnClickOutside && !event.defaultPrevented) {
|
|
283
|
+
if (event.target && event.target !== popupCurrent && event.target !== childrenCurrent && !childrenCurrent?.contains(event.target) && !popupCurrent.contains(event.target)) {
|
|
289
284
|
event.preventDefault();
|
|
290
285
|
event.stopPropagation();
|
|
291
|
-
|
|
286
|
+
closePopup();
|
|
292
287
|
}
|
|
293
288
|
}
|
|
294
289
|
};
|
|
@@ -300,7 +295,35 @@ const Popup = /*#__PURE__*/forwardRef((_ref15, ref) => {
|
|
|
300
295
|
document.body.removeEventListener('keyup', handleEscPress);
|
|
301
296
|
document.body.removeEventListener('click', handleClickOutside);
|
|
302
297
|
};
|
|
303
|
-
}, [
|
|
298
|
+
}, [closePopup, visibleInDom, innerPopupRef, childrenRef, hideOnClickOutside]);
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* This event will occur only for dialog and will trap focus inside the dialog.
|
|
302
|
+
*/
|
|
303
|
+
const handleFocusTrap = useCallback(event => {
|
|
304
|
+
const isTabPressed = event.key === 'Tab';
|
|
305
|
+
if (!isTabPressed) {
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
event.stopPropagation();
|
|
309
|
+
const focusableEls = innerPopupRef.current?.querySelectorAll('a[href]:not([disabled]), button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled])') ?? [];
|
|
310
|
+
|
|
311
|
+
// Handle case when no interactive element are within the modal (including close icon)
|
|
312
|
+
if (focusableEls.length === 0) {
|
|
313
|
+
event.preventDefault();
|
|
314
|
+
}
|
|
315
|
+
const firstFocusableEl = focusableEls[0];
|
|
316
|
+
const lastFocusableEl = focusableEls[focusableEls.length - 1];
|
|
317
|
+
if (event.shiftKey) {
|
|
318
|
+
if (document.activeElement === firstFocusableEl || document.activeElement === innerPopupRef.current) {
|
|
319
|
+
lastFocusableEl.focus();
|
|
320
|
+
event.preventDefault();
|
|
321
|
+
}
|
|
322
|
+
} else if (document.activeElement === lastFocusableEl || document.activeElement === innerPopupRef.current) {
|
|
323
|
+
firstFocusableEl.focus();
|
|
324
|
+
event.preventDefault();
|
|
325
|
+
}
|
|
326
|
+
}, []);
|
|
304
327
|
|
|
305
328
|
/**
|
|
306
329
|
* Will render children conditionally if children is a function or not.
|
|
@@ -326,13 +349,12 @@ const Popup = /*#__PURE__*/forwardRef((_ref15, ref) => {
|
|
|
326
349
|
tabIndex: tabIndex,
|
|
327
350
|
onKeyDown: event => {
|
|
328
351
|
onKeyDown?.(event);
|
|
329
|
-
onLocalKeyDown(event);
|
|
330
352
|
},
|
|
331
353
|
"data-container-full-width": containerFullWidth,
|
|
332
354
|
"aria-haspopup": ariaHasPopup,
|
|
333
355
|
children: children
|
|
334
356
|
});
|
|
335
|
-
}, [ariaHasPopup, children, containerFullWidth, generatedId, isControlled, onKeyDown,
|
|
357
|
+
}, [ariaHasPopup, children, containerFullWidth, generatedId, isControlled, onKeyDown, onPointerEvent, tabIndex]);
|
|
336
358
|
if (!text) {
|
|
337
359
|
if (typeof children === 'function') return null;
|
|
338
360
|
return jsx(Fragment, {
|
|
@@ -347,8 +369,8 @@ const Popup = /*#__PURE__*/forwardRef((_ref15, ref) => {
|
|
|
347
369
|
event.nativeEvent.stopImmediatePropagation();
|
|
348
370
|
};
|
|
349
371
|
return jsxs(Fragment, {
|
|
350
|
-
children: [renderChildren(), visibleInDom ? /*#__PURE__*/createPortal(jsx(
|
|
351
|
-
ref:
|
|
372
|
+
children: [renderChildren(), visibleInDom ? /*#__PURE__*/createPortal(jsx(StyledPopup, {
|
|
373
|
+
ref: innerPopupRef,
|
|
352
374
|
positions: positions,
|
|
353
375
|
maxWidth: maxWidth,
|
|
354
376
|
maxHeight: maxHeight,
|
|
@@ -360,8 +382,10 @@ const Popup = /*#__PURE__*/forwardRef((_ref15, ref) => {
|
|
|
360
382
|
"data-has-arrow": hasArrow,
|
|
361
383
|
onClick: stopClickPropagation,
|
|
362
384
|
animationDuration: animationDuration,
|
|
385
|
+
onKeyDown: role === 'dialog' ? handleFocusTrap : undefined,
|
|
386
|
+
isDialog: role === 'dialog',
|
|
363
387
|
children: text
|
|
364
|
-
}),
|
|
388
|
+
}), popupPortalTarget) : null]
|
|
365
389
|
});
|
|
366
390
|
});
|
|
367
391
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import _styled from '@emotion/styled/base';
|
|
2
2
|
import { Icon } from '@ultraviolet/icons';
|
|
3
|
-
import {
|
|
3
|
+
import { useReducer, Children } from 'react';
|
|
4
4
|
import { CopyButton } from '../CopyButton/index.js';
|
|
5
5
|
import { Expandable } from '../Expandable/index.js';
|
|
6
6
|
import { Stack } from '../Stack/index.js';
|
|
@@ -196,9 +196,10 @@ const Snippet = _ref19 => {
|
|
|
196
196
|
hideText = 'Hide',
|
|
197
197
|
prefix,
|
|
198
198
|
className,
|
|
199
|
-
'data-testid': dataTestId
|
|
199
|
+
'data-testid': dataTestId,
|
|
200
|
+
initiallyExpanded
|
|
200
201
|
} = _ref19;
|
|
201
|
-
const [showMore, setShowMore] =
|
|
202
|
+
const [showMore, setShowMore] = useReducer(value => !value, initiallyExpanded ?? false);
|
|
202
203
|
const lines = children.split(LINES_BREAK_REGEX).filter(Boolean);
|
|
203
204
|
const numberOfLines = lines.length;
|
|
204
205
|
const multiline = numberOfLines > 1;
|
|
@@ -235,7 +236,7 @@ const Snippet = _ref19 => {
|
|
|
235
236
|
showMore: showMore,
|
|
236
237
|
children: jsx(StyledButton, {
|
|
237
238
|
type: "button",
|
|
238
|
-
onClick:
|
|
239
|
+
onClick: setShowMore,
|
|
239
240
|
"aria-expanded": showMore,
|
|
240
241
|
children: jsxs(AlignCenterText, {
|
|
241
242
|
as: "span",
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import _styled from '@emotion/styled/base';
|
|
2
2
|
import { forwardRef, useMemo } from 'react';
|
|
3
3
|
import { Badge } from '../Badge/index.js';
|
|
4
|
+
import { Stack } from '../Stack/index.js';
|
|
5
|
+
import { Text } from '../Text/index.js';
|
|
4
6
|
import { Tooltip } from '../Tooltip/index.js';
|
|
5
7
|
import { useTabsContext } from './TabsContext.js';
|
|
6
8
|
import { jsx, jsxs } from '@emotion/react/jsx-runtime';
|
|
7
9
|
|
|
8
10
|
const StyledBadge = /*#__PURE__*/_styled(Badge, {
|
|
9
|
-
target: "
|
|
11
|
+
target: "e1hzf7cr4"
|
|
10
12
|
})("padding:0 ", _ref => {
|
|
11
13
|
let {
|
|
12
14
|
theme
|
|
@@ -18,6 +20,9 @@ const StyledBadge = /*#__PURE__*/_styled(Badge, {
|
|
|
18
20
|
} = _ref2;
|
|
19
21
|
return theme.space['1'];
|
|
20
22
|
}, ";");
|
|
23
|
+
const StyledText = /*#__PURE__*/_styled(Text, {
|
|
24
|
+
target: "e1hzf7cr3"
|
|
25
|
+
})();
|
|
21
26
|
const StyledTooltip = /*#__PURE__*/_styled(Tooltip, {
|
|
22
27
|
target: "e1hzf7cr2"
|
|
23
28
|
})();
|
|
@@ -36,7 +41,7 @@ const StyledTabButton = /*#__PURE__*/_styled('button', {
|
|
|
36
41
|
theme
|
|
37
42
|
} = _ref4;
|
|
38
43
|
return `${theme.space['1']} ${theme.space['2']}`;
|
|
39
|
-
}, ";cursor:pointer;justify-content:center;align-items:
|
|
44
|
+
}, ";cursor:pointer;justify-content:center;align-items:baseline;white-space:nowrap;color:", _ref5 => {
|
|
40
45
|
let {
|
|
41
46
|
theme
|
|
42
47
|
} = _ref5;
|
|
@@ -81,33 +86,43 @@ const StyledTabButton = /*#__PURE__*/_styled('button', {
|
|
|
81
86
|
theme
|
|
82
87
|
} = _ref13;
|
|
83
88
|
return theme.colors.primary.border;
|
|
84
|
-
}, ";
|
|
89
|
+
}, ";", StyledText, "{color:", _ref14 => {
|
|
85
90
|
let {
|
|
86
91
|
theme
|
|
87
92
|
} = _ref14;
|
|
88
93
|
return theme.colors.primary.text;
|
|
89
|
-
}, ";
|
|
94
|
+
}, ";}}&[aria-disabled='false']:not(:disabled){&:hover,&:focus,&:active{outline:none;color:", _ref15 => {
|
|
90
95
|
let {
|
|
91
96
|
theme
|
|
92
97
|
} = _ref15;
|
|
93
|
-
return theme.colors.primary.
|
|
94
|
-
}, "
|
|
98
|
+
return theme.colors.primary.text;
|
|
99
|
+
}, ";border-bottom-color:", _ref16 => {
|
|
95
100
|
let {
|
|
96
101
|
theme
|
|
97
102
|
} = _ref16;
|
|
98
|
-
return theme.colors.primary.
|
|
99
|
-
}, "
|
|
103
|
+
return theme.colors.primary.border;
|
|
104
|
+
}, ";&[data-is-selected='false']{", StyledBadge, "{background-color:", _ref17 => {
|
|
100
105
|
let {
|
|
101
106
|
theme
|
|
102
107
|
} = _ref17;
|
|
103
108
|
return theme.colors.primary.background;
|
|
104
|
-
}, ";color:", _ref18 => {
|
|
109
|
+
}, ";border-color:", _ref18 => {
|
|
105
110
|
let {
|
|
106
111
|
theme
|
|
107
112
|
} = _ref18;
|
|
113
|
+
return theme.colors.primary.background;
|
|
114
|
+
}, ";color:", _ref19 => {
|
|
115
|
+
let {
|
|
116
|
+
theme
|
|
117
|
+
} = _ref19;
|
|
118
|
+
return theme.colors.primary.text;
|
|
119
|
+
}, ";}", StyledText, "{color:", _ref20 => {
|
|
120
|
+
let {
|
|
121
|
+
theme
|
|
122
|
+
} = _ref20;
|
|
108
123
|
return theme.colors.primary.text;
|
|
109
124
|
}, ";}}}}&[aria-disabled='true'],&:disabled{cursor:not-allowed;filter:grayscale(1) opacity(50%);}");
|
|
110
|
-
const Tab = /*#__PURE__*/forwardRef((
|
|
125
|
+
const Tab = /*#__PURE__*/forwardRef((_ref21, ref) => {
|
|
111
126
|
let {
|
|
112
127
|
as,
|
|
113
128
|
badge,
|
|
@@ -115,12 +130,13 @@ const Tab = /*#__PURE__*/forwardRef((_ref19, ref) => {
|
|
|
115
130
|
className,
|
|
116
131
|
counter,
|
|
117
132
|
disabled = false,
|
|
118
|
-
value,
|
|
119
133
|
onClick,
|
|
120
134
|
onKeyDown,
|
|
135
|
+
subtitle,
|
|
121
136
|
tooltip,
|
|
137
|
+
value,
|
|
122
138
|
...props
|
|
123
|
-
} =
|
|
139
|
+
} = _ref21;
|
|
124
140
|
const {
|
|
125
141
|
selected,
|
|
126
142
|
onChange
|
|
@@ -129,7 +145,7 @@ const Tab = /*#__PURE__*/forwardRef((_ref19, ref) => {
|
|
|
129
145
|
const isSelected = useMemo(() => value !== undefined && selected === value, [value, selected]);
|
|
130
146
|
return jsx(StyledTooltip, {
|
|
131
147
|
text: tooltip,
|
|
132
|
-
children:
|
|
148
|
+
children: jsx(StyledTabButton, {
|
|
133
149
|
role: "tab",
|
|
134
150
|
ref: ref,
|
|
135
151
|
className: className,
|
|
@@ -151,14 +167,31 @@ const Tab = /*#__PURE__*/forwardRef((_ref19, ref) => {
|
|
|
151
167
|
},
|
|
152
168
|
"data-is-selected": isSelected,
|
|
153
169
|
...props,
|
|
154
|
-
children:
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
170
|
+
children: jsxs(Stack, {
|
|
171
|
+
direction: "column",
|
|
172
|
+
gap: 0.5,
|
|
173
|
+
children: [jsxs(Stack, {
|
|
174
|
+
direction: "row",
|
|
175
|
+
alignItems: "center",
|
|
176
|
+
children: [children, typeof counter === 'number' || typeof counter === 'string' ? jsx(StyledBadge, {
|
|
177
|
+
sentiment: isSelected ? 'primary' : 'neutral',
|
|
178
|
+
prominence: isSelected ? 'strong' : 'default',
|
|
179
|
+
size: "medium",
|
|
180
|
+
children: counter
|
|
181
|
+
}) : null, badge ? jsx(BadgeContainer, {
|
|
182
|
+
children: badge
|
|
183
|
+
}) : null]
|
|
184
|
+
}), subtitle ? jsx(Stack, {
|
|
185
|
+
direction: "row",
|
|
186
|
+
children: jsx(StyledText, {
|
|
187
|
+
as: "span",
|
|
188
|
+
variant: "bodySmall",
|
|
189
|
+
sentiment: "neutral",
|
|
190
|
+
prominence: "weak",
|
|
191
|
+
children: subtitle
|
|
192
|
+
})
|
|
193
|
+
}) : null]
|
|
194
|
+
})
|
|
162
195
|
})
|
|
163
196
|
});
|
|
164
197
|
});
|
|
@@ -23,6 +23,7 @@ const TabMenu = /*#__PURE__*/forwardRef((_ref2, ref) => {
|
|
|
23
23
|
visible,
|
|
24
24
|
id,
|
|
25
25
|
disabled,
|
|
26
|
+
className,
|
|
26
27
|
...props
|
|
27
28
|
} = _ref2;
|
|
28
29
|
return jsx(Menu, {
|
|
@@ -34,6 +35,7 @@ const TabMenu = /*#__PURE__*/forwardRef((_ref2, ref) => {
|
|
|
34
35
|
"aria-disabled": disabled ?? 'false',
|
|
35
36
|
disabled: disabled,
|
|
36
37
|
"aria-haspopup": "menu",
|
|
38
|
+
className: className,
|
|
37
39
|
...props,
|
|
38
40
|
children: [disclosure, jsx(ArrowIcon, {
|
|
39
41
|
name: "arrow-down"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import _styled from '@emotion/styled/base';
|
|
2
|
-
import { useRef, useState, useMemo, useEffect } from 'react';
|
|
2
|
+
import { useRef, useState, useMemo, useEffect, Children, isValidElement, cloneElement } from 'react';
|
|
3
3
|
import { Tab, StyledTabButton } from './Tab.js';
|
|
4
4
|
import { TabMenu } from './TabMenu.js';
|
|
5
5
|
import { TabMenuItem } from './TabMenuItem.js';
|
|
@@ -23,7 +23,9 @@ const MenuContainer = /*#__PURE__*/_styled("div", {
|
|
|
23
23
|
theme
|
|
24
24
|
} = _ref3;
|
|
25
25
|
return `${theme.space['1']} ${theme.space['2']}`;
|
|
26
|
-
}, ";border-bottom-width:
|
|
26
|
+
}, ";border-bottom-width:1.5px;width:100%;cursor:pointer;min-width:110px;background-color:transparent;&[aria-disabled='true'],&:disabled{cursor:not-allowed;filter:grayscale(1) opacity(50%);}}");
|
|
27
|
+
|
|
28
|
+
// Migration to MenuV2 will not work as expected here.
|
|
27
29
|
const StyledTabMenu = /*#__PURE__*/_styled(TabMenu, {
|
|
28
30
|
target: "ewug27g1"
|
|
29
31
|
})("position:sticky;right:0;top:0;bottom:0;background:", _ref4 => {
|
|
@@ -61,7 +63,7 @@ const Tabs = _ref7 => {
|
|
|
61
63
|
...props
|
|
62
64
|
} = _ref7;
|
|
63
65
|
const tabsRef = useRef({});
|
|
64
|
-
const moreStaticRef = useRef(
|
|
66
|
+
const moreStaticRef = useRef(null);
|
|
65
67
|
const [displayMore, setDisplayMore] = useState(false);
|
|
66
68
|
const value = useMemo(() => ({
|
|
67
69
|
onChange,
|
|
@@ -82,12 +84,14 @@ const Tabs = _ref7 => {
|
|
|
82
84
|
}
|
|
83
85
|
}, [selected]);
|
|
84
86
|
|
|
85
|
-
// Change the moreButton style automatically based on the scroll
|
|
87
|
+
// Change the moreButton style automatically based on the scroll to show that a scroll effect is possible.
|
|
86
88
|
useEffect(() => {
|
|
87
89
|
const element = tabsRef.current;
|
|
88
90
|
const moreElement = moreStaticRef.current;
|
|
89
91
|
const handler = () => {
|
|
90
|
-
moreElement
|
|
92
|
+
if (moreElement?.style) {
|
|
93
|
+
moreElement.style.boxShadow = element.scrollLeft + SHADOW_THRESHOLD > element.scrollWidth - element.clientWidth ? 'none' : '';
|
|
94
|
+
}
|
|
91
95
|
};
|
|
92
96
|
if (displayMore) {
|
|
93
97
|
element.addEventListener('scroll', handler);
|
|
@@ -96,6 +100,17 @@ const Tabs = _ref7 => {
|
|
|
96
100
|
if (displayMore) element.removeEventListener('scroll', handler);
|
|
97
101
|
};
|
|
98
102
|
}, [displayMore]);
|
|
103
|
+
|
|
104
|
+
// mapping of tab children to avoid using subtitle props
|
|
105
|
+
const menuItemChildren = Children.map(children, child => {
|
|
106
|
+
if ( /*#__PURE__*/isValidElement(child)) {
|
|
107
|
+
return /*#__PURE__*/cloneElement(child, {
|
|
108
|
+
...child.props,
|
|
109
|
+
subtitle: null
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return null;
|
|
113
|
+
});
|
|
99
114
|
return jsx(TabsContext.Provider, {
|
|
100
115
|
value: value,
|
|
101
116
|
children: jsxs(TabsContainer, {
|
|
@@ -108,7 +123,7 @@ const Tabs = _ref7 => {
|
|
|
108
123
|
ref: moreStaticRef,
|
|
109
124
|
disclosure: moreDisclosure,
|
|
110
125
|
children: jsx(MenuContainer, {
|
|
111
|
-
children:
|
|
126
|
+
children: menuItemChildren
|
|
112
127
|
})
|
|
113
128
|
}) : null]
|
|
114
129
|
})
|
|
@@ -31,7 +31,8 @@ const Tooltip = /*#__PURE__*/forwardRef((_ref, tooltipRef) => {
|
|
|
31
31
|
visible,
|
|
32
32
|
innerRef,
|
|
33
33
|
role = 'tooltip',
|
|
34
|
-
'data-testid': dataTestId
|
|
34
|
+
'data-testid': dataTestId,
|
|
35
|
+
portalTarget
|
|
35
36
|
} = _ref;
|
|
36
37
|
return jsx(StyledPopup, {
|
|
37
38
|
id: id,
|
|
@@ -45,6 +46,7 @@ const Tooltip = /*#__PURE__*/forwardRef((_ref, tooltipRef) => {
|
|
|
45
46
|
placement: placement,
|
|
46
47
|
text: text,
|
|
47
48
|
innerRef: innerRef,
|
|
49
|
+
portalTarget: portalTarget,
|
|
48
50
|
children: children
|
|
49
51
|
});
|
|
50
52
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ultraviolet/ui",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.26.0",
|
|
4
4
|
"description": "Ultraviolet UI",
|
|
5
5
|
"homepage": "https://github.com/scaleway/ultraviolet#readme",
|
|
6
6
|
"repository": {
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"react-dom": "18.2.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@babel/core": "7.23.
|
|
42
|
+
"@babel/core": "7.23.3",
|
|
43
43
|
"@emotion/babel-plugin": "11.11.0",
|
|
44
44
|
"@emotion/react": "11.11.1",
|
|
45
45
|
"@emotion/styled": "11.11.0",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"react-use-clipboard": "1.0.9",
|
|
68
68
|
"reakit": "1.3.11",
|
|
69
69
|
"@ultraviolet/themes": "1.5.0",
|
|
70
|
-
"@ultraviolet/icons": "2.5.
|
|
70
|
+
"@ultraviolet/icons": "2.5.5"
|
|
71
71
|
},
|
|
72
72
|
"scripts": {
|
|
73
73
|
"build": "rollup -c ../../rollup.config.mjs"
|