@ultraviolet/ui 1.45.6 → 1.47.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 CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as react from 'react';
2
- import react__default, { ReactNode, ComponentProps, ButtonHTMLAttributes, AriaRole, MouseEventHandler, JSX, MouseEvent, InputHTMLAttributes, FocusEvent, HTMLAttributeAnchorTarget, AnchorHTMLAttributes, ReactElement, Ref, RefObject, KeyboardEventHandler, HTMLAttributes, CSSProperties, ChangeEventHandler, FocusEventHandler, ForwardRefExoticComponent, ForwardedRef, ElementType, DOMAttributes, TextareaHTMLAttributes } from 'react';
2
+ import react__default, { ReactNode, ComponentProps, ButtonHTMLAttributes, AriaRole, MouseEventHandler, JSX, MouseEvent, InputHTMLAttributes, FocusEvent, HTMLAttributeAnchorTarget, AnchorHTMLAttributes, Dispatch, SetStateAction, ReactElement, Ref, RefObject, KeyboardEventHandler, HTMLAttributes, CSSProperties, ChangeEventHandler, FocusEventHandler, ForwardRefExoticComponent, ForwardedRef, ElementType, DOMAttributes, 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';
@@ -1334,7 +1334,7 @@ type AvatarProps = {
1334
1334
  declare const Avatar: ({ image, size, text, textBgColor, textColor, textSize, lock, className, "data-testid": dataTestId, }: AvatarProps) => _emotion_react_jsx_runtime.JSX.Element;
1335
1335
 
1336
1336
  type IconName$1 = ComponentProps<typeof Icon>['name'];
1337
- declare const SIZES: {
1337
+ declare const SIZES$1: {
1338
1338
  large: number;
1339
1339
  medium: number;
1340
1340
  small: number;
@@ -1345,7 +1345,7 @@ declare const PROMINENCES$3: {
1345
1345
  };
1346
1346
  type BadgeProps = {
1347
1347
  sentiment?: Color;
1348
- size?: keyof typeof SIZES;
1348
+ size?: keyof typeof SIZES$1;
1349
1349
  prominence?: keyof typeof PROMINENCES$3;
1350
1350
  /**
1351
1351
  * Defines icon to display on left side of badge. **Only available on medium and large sizes**.
@@ -1803,6 +1803,10 @@ type ListProps = {
1803
1803
  * Auto collapse is collapsing expandable row when another is expanding
1804
1804
  * */
1805
1805
  autoCollapse?: boolean;
1806
+ /**
1807
+ * Action when selection changes (get the list of selected rows)
1808
+ */
1809
+ onSelectedChange?: Dispatch<SetStateAction<string[]>>;
1806
1810
  };
1807
1811
  /**
1808
1812
  * List is a component that displays a list of items based on the columns you provide and the data you pass.
@@ -2257,7 +2261,7 @@ declare const Popover: react.ForwardRefExoticComponent<{
2257
2261
  onKeyDown?: react.KeyboardEventHandler | undefined;
2258
2262
  'aria-haspopup'?: boolean | "menu" | "dialog" | "grid" | "listbox" | "tree" | "false" | "true" | undefined;
2259
2263
  hideOnClickOutside?: boolean | undefined;
2260
- needDebounce?: boolean | undefined;
2264
+ debounceDelay?: number | undefined;
2261
2265
  maxHeight?: string | number | undefined;
2262
2266
  disableAnimation?: boolean | undefined;
2263
2267
  portalTarget?: HTMLElement | undefined;
@@ -2303,7 +2307,11 @@ type PopupProps = {
2303
2307
  onKeyDown?: KeyboardEventHandler;
2304
2308
  'aria-haspopup'?: HTMLAttributes<HTMLDivElement>['aria-haspopup'];
2305
2309
  hideOnClickOutside?: boolean;
2306
- needDebounce?: boolean;
2310
+ /**
2311
+ * If you set debounceTime to false, the popup will not debounce the hover event and will be displayed instantly.
2312
+ * If set to 0 it will disable debounce.
2313
+ */
2314
+ debounceDelay?: number;
2307
2315
  /**
2308
2316
  * If you set a max height keep in mind that the animation is disabled, or it will not work properly on some browsers.
2309
2317
  */
@@ -2323,7 +2331,7 @@ type PopupProps = {
2323
2331
  */
2324
2332
  declare const Popup: react.ForwardRefExoticComponent<PopupProps & react.RefAttributes<HTMLDivElement>>;
2325
2333
 
2326
- declare const progressBarSentiments: readonly ["primary", "success", "warning", "info"];
2334
+ declare const progressBarSentiments: readonly ["primary", "success", "warning", "info", "danger"];
2327
2335
  type ProgressBarProps = {
2328
2336
  sentiment?: (typeof progressBarSentiments)[number];
2329
2337
  value?: number;
@@ -2790,7 +2798,8 @@ declare const Tabs: {
2790
2798
  children: ReactNode;
2791
2799
  onClick?: react.MouseEventHandler<HTMLElement> | undefined;
2792
2800
  borderless?: boolean | undefined;
2793
- sentiment?: ("neutral" | "danger") | undefined;
2801
+ sentiment?: ("primary" | "neutral" | "danger") | undefined;
2802
+ active?: boolean | undefined;
2794
2803
  'data-testid'?: string | undefined;
2795
2804
  } & react.RefAttributes<HTMLElement> & {
2796
2805
  theme?: _emotion_react.Theme | undefined;
@@ -3197,7 +3206,7 @@ declare const ToggleGroup: {
3197
3206
  Toggle: ({ disabled, name, value, label, helper, className, "data-testid": dataTestId, }: ToggleGroupToggleProps) => _emotion_react_jsx_runtime.JSX.Element;
3198
3207
  };
3199
3208
 
3200
- type TooltipProps = Pick<ComponentProps<typeof Popup>, 'id' | 'children' | 'maxWidth' | 'placement' | 'text' | 'className' | 'visible' | 'innerRef' | 'role' | 'data-testid' | 'containerFullWidth' | 'portalTarget' | 'tabIndex'>;
3209
+ type TooltipProps = Pick<ComponentProps<typeof Popup>, 'id' | 'children' | 'maxWidth' | 'placement' | 'text' | 'className' | 'visible' | 'innerRef' | 'role' | 'data-testid' | 'containerFullWidth' | 'portalTarget' | 'tabIndex' | 'debounceDelay'>;
3201
3210
  /**
3202
3211
  * Tooltip component is used to display additional information on hover or focus.
3203
3212
  * It is used to explain the purpose of the element it is attached to.
@@ -3261,6 +3270,11 @@ declare const RadioGroup: {
3261
3270
  Radio: ({ onFocus, onBlur, disabled, error, name, value, label, helper, className, autoFocus, onKeyDown, "data-testid": dataTestId, }: RadioGroupRadioProps) => _emotion_react_jsx_runtime.JSX.Element;
3262
3271
  };
3263
3272
 
3273
+ declare const SIZES: {
3274
+ small: string;
3275
+ medium: string;
3276
+ large: string;
3277
+ };
3264
3278
  type DisclosureProps = {
3265
3279
  visible: boolean;
3266
3280
  };
@@ -3281,12 +3295,21 @@ type MenuProps = {
3281
3295
  visible?: boolean;
3282
3296
  'data-testid'?: string;
3283
3297
  maxHeight?: string;
3298
+ /**
3299
+ * @deprecated: use `size` instead
3300
+ */
3284
3301
  maxWidth?: string;
3285
3302
  /**
3286
3303
  * By default, the portal target is children container or document.body if children is a function. You can override this
3287
3304
  * behavior by setting a portalTarget prop.
3288
3305
  */
3289
3306
  portalTarget?: HTMLElement;
3307
+ size?: keyof typeof SIZES;
3308
+ /**
3309
+ * The behavior of the menu when it is opened. If set to `click`, the menu will open when the user clicks on the disclosure.
3310
+ * If set to `hover`, the menu will open when the user hovers over the disclosure.
3311
+ */
3312
+ triggerMethod?: 'click' | 'hover';
3290
3313
  };
3291
3314
  /**
3292
3315
  * A menu is a widget that offers a list of choices to the user, such as a set of actions or functions.
@@ -3303,9 +3326,14 @@ declare const MenuV2: react.ForwardRefExoticComponent<MenuProps & react.RefAttri
3303
3326
  children: ReactNode;
3304
3327
  onClick?: react.MouseEventHandler<HTMLElement> | undefined;
3305
3328
  borderless?: boolean | undefined;
3306
- sentiment?: ("neutral" | "danger") | undefined;
3329
+ sentiment?: ("primary" | "neutral" | "danger") | undefined;
3330
+ active?: boolean | undefined;
3307
3331
  'data-testid'?: string | undefined;
3308
3332
  } & react.RefAttributes<HTMLElement>>;
3333
+ Group: ({ label, children }: {
3334
+ label: string;
3335
+ children: ReactNode;
3336
+ }) => _emotion_react_jsx_runtime.JSX.Element;
3309
3337
  };
3310
3338
 
3311
3339
  type GlobalAlertProps = {
@@ -6,7 +6,8 @@ const ListProvider = ({
6
6
  children,
7
7
  autoCollapse,
8
8
  selectable,
9
- expandButton
9
+ expandButton,
10
+ onSelectedChange
10
11
  }) => {
11
12
  const [expandedRowIds, setExpandedRowIds] = useState({});
12
13
  const [selectedRowIds, setSelectedRowIds] = useState({});
@@ -67,29 +68,45 @@ const ListProvider = ({
67
68
  return 'indeterminate';
68
69
  }, [selectedRowIds]);
69
70
  const selectAll = useCallback(() => {
70
- setSelectedRowIds(current => Object.keys(current).reduce((acc, rowId) => ({
71
+ const newSelectedRowIds = Object.keys(selectedRowIds).reduce((acc, rowId) => ({
71
72
  ...acc,
72
73
  [rowId]: true
73
- }), {}));
74
- }, []);
74
+ }), {});
75
+ setSelectedRowIds(newSelectedRowIds);
76
+ if (onSelectedChange) {
77
+ onSelectedChange(Object.keys(newSelectedRowIds).filter(row => newSelectedRowIds[row]));
78
+ }
79
+ }, [onSelectedChange, selectedRowIds]);
75
80
  const unselectAll = useCallback(() => {
76
- setSelectedRowIds(current => Object.keys(current).reduce((acc, rowId) => ({
81
+ const newSelectedRowIds = Object.keys(selectedRowIds).reduce((acc, rowId) => ({
77
82
  ...acc,
78
83
  [rowId]: false
79
- }), {}));
80
- }, []);
84
+ }), {});
85
+ setSelectedRowIds(newSelectedRowIds);
86
+ if (onSelectedChange) {
87
+ onSelectedChange(Object.keys(newSelectedRowIds).filter(row => newSelectedRowIds[row]));
88
+ }
89
+ }, [onSelectedChange, selectedRowIds]);
81
90
  const selectRow = useCallback(rowId => {
82
- setSelectedRowIds(current => ({
83
- ...current,
91
+ const newSelectedRowIds = {
92
+ ...selectedRowIds,
84
93
  [rowId]: true
85
- }));
86
- }, []);
94
+ };
95
+ setSelectedRowIds(newSelectedRowIds);
96
+ if (onSelectedChange) {
97
+ onSelectedChange(Object.keys(newSelectedRowIds).filter(row => newSelectedRowIds[row]));
98
+ }
99
+ }, [onSelectedChange, selectedRowIds]);
87
100
  const unselectRow = useCallback(rowId => {
88
- setSelectedRowIds(current => ({
89
- ...current,
101
+ const newSelectedRowIds = {
102
+ ...selectedRowIds,
90
103
  [rowId]: false
91
- }));
92
- }, []);
104
+ };
105
+ setSelectedRowIds(newSelectedRowIds);
106
+ if (onSelectedChange) {
107
+ onSelectedChange(Object.keys(newSelectedRowIds).filter(row => newSelectedRowIds[row]));
108
+ }
109
+ }, [onSelectedChange, selectedRowIds]);
93
110
  const value = useMemo(() => ({
94
111
  registerExpandableRow,
95
112
  expandedRowIds,
@@ -25,7 +25,8 @@ const BaseList = /*#__PURE__*/forwardRef(({
25
25
  columns,
26
26
  children,
27
27
  loading,
28
- autoCollapse = false
28
+ autoCollapse = false,
29
+ onSelectedChange
29
30
  }, ref) => {
30
31
  const computeTemplate = `${selectable ? `${SELECTABLE_CHECKBOX_SIZE}px ` : ''}${expandable ? `${EXPANDABLE_COLUMN_SIZE}px ` : ''}${columns.map(({
31
32
  width
@@ -34,6 +35,7 @@ const BaseList = /*#__PURE__*/forwardRef(({
34
35
  selectable: selectable,
35
36
  expandButton: expandable,
36
37
  autoCollapse: autoCollapse,
38
+ onSelectedChange: onSelectedChange,
37
39
  children: jsxs(StyledList, {
38
40
  ref: ref,
39
41
  role: "grid",
@@ -0,0 +1,25 @@
1
+ import _styled from '@emotion/styled/base';
2
+ import { Text } from '../Text/index.js';
3
+ import { jsxs, Fragment, jsx } from '@emotion/react/jsx-runtime';
4
+
5
+ const Container = /*#__PURE__*/_styled("span", {
6
+ target: "e7u2rl20"
7
+ })("padding:", ({
8
+ theme
9
+ }) => `${theme.space['0.5']} ${theme.space['1.5']}`, ";text-align:left;");
10
+ const Group = ({
11
+ label,
12
+ children
13
+ }) => jsxs(Fragment, {
14
+ children: [jsx(Container, {
15
+ children: jsx(Text, {
16
+ variant: "captionStrong",
17
+ as: "span",
18
+ prominence: "weak",
19
+ sentiment: "neutral",
20
+ children: label
21
+ })
22
+ }), children]
23
+ });
24
+
25
+ export { Group };
@@ -3,22 +3,28 @@ import { forwardRef } from 'react';
3
3
  import { Tooltip } from '../Tooltip/index.js';
4
4
  import { jsx } from '@emotion/react/jsx-runtime';
5
5
 
6
+ const ANIMATION_DURATION = 200; // in ms
7
+
6
8
  const itemCoreStyle = ({
7
9
  theme,
8
- borderless,
9
10
  sentiment,
10
11
  disabled
11
12
  }) => `
12
- display: inline-block;
13
+ display: flex;
14
+ justify-content: start;
15
+ align-items: center;
16
+ min-height: 32px;
17
+ max-height: 44px;
13
18
  font-size: ${theme.typography.bodySmall.fontSize};
14
19
  line-height: ${theme.typography.bodySmall.lineHeight};
15
20
  font-weight: inherit;
16
21
  padding: ${`${theme.space['0.5']} ${theme.space['1']}`};
17
22
  border: none;
18
- ${borderless ? '' : `border-bottom: 1px solid ${theme.colors.neutral.border};`}
19
23
  cursor: pointer;
20
24
  min-width: 110px;
21
25
  width: 100%;
26
+ border-radius: ${theme.radii.default};
27
+ transition: background-color ${ANIMATION_DURATION}ms, color ${ANIMATION_DURATION}ms;
22
28
 
23
29
  color: ${theme.colors[sentiment][disabled ? 'textDisabled' : 'text']};
24
30
  svg {
@@ -29,13 +35,24 @@ const itemCoreStyle = ({
29
35
  cursor: not-allowed;
30
36
  ` : `
31
37
  &:hover,
32
- &:focus {
38
+ &:focus, &[data-active='true'] {
39
+ background-color: ${theme.colors[sentiment].backgroundHover};
33
40
  color: ${theme.colors[sentiment].textHover};
34
41
  svg {
35
42
  fill: ${theme.colors[sentiment].textHover};
36
43
  }
37
44
  }`}
38
45
  `;
46
+ const Container = /*#__PURE__*/_styled('div', {
47
+ shouldForwardProp: prop => !['borderless'].includes(prop),
48
+ target: "ei26g5y2"
49
+ })(({
50
+ theme,
51
+ borderless
52
+ }) => borderless ? '' : `border-bottom: 1px solid ${theme.colors.neutral.border};`, " padding:", ({
53
+ theme,
54
+ borderless
55
+ }) => `${borderless ? theme.space['0.25'] : theme.space['0.5']} ${theme.space['0.5']}`, ";&:last-child{border:none;}");
39
56
  const StyledItem = /*#__PURE__*/_styled('button', {
40
57
  shouldForwardProp: prop => !['borderless', 'sentiment'].includes(prop),
41
58
  target: "ei26g5y1"
@@ -72,14 +89,17 @@ const Item = /*#__PURE__*/forwardRef(({
72
89
  href,
73
90
  children,
74
91
  tooltip,
92
+ active,
75
93
  className,
76
94
  'data-testid': dataTestId
77
95
  }, ref) => {
78
96
  if (href && !disabled) {
79
- return jsx("div", {
97
+ return jsx(Container, {
98
+ borderless: borderless,
80
99
  children: jsx(Tooltip, {
81
100
  text: tooltip,
82
101
  children: jsx(StyledLinkItem, {
102
+ "data-active": active,
83
103
  borderless: true,
84
104
  href: href,
85
105
  ref: ref,
@@ -94,7 +114,8 @@ const Item = /*#__PURE__*/forwardRef(({
94
114
  })
95
115
  });
96
116
  }
97
- return jsx("div", {
117
+ return jsx(Container, {
118
+ borderless: borderless,
98
119
  children: jsx(Tooltip, {
99
120
  text: tooltip,
100
121
  children: jsx(StyledItem, {
@@ -107,6 +128,7 @@ const Item = /*#__PURE__*/forwardRef(({
107
128
  sentiment: sentiment,
108
129
  className: className,
109
130
  "data-testid": dataTestId,
131
+ "data-active": active,
110
132
  children: children
111
133
  })
112
134
  })
@@ -2,10 +2,17 @@ import _styled from '@emotion/styled/base';
2
2
  import { forwardRef, useState, useRef, useId, isValidElement, useImperativeHandle, cloneElement } from 'react';
3
3
  import { Popup } from '../Popup/index.js';
4
4
  import { Stack } from '../Stack/index.js';
5
+ import { Group } from './Group.js';
5
6
  import Item from './Item.js';
6
7
  import { jsx } from '@emotion/react/jsx-runtime';
7
8
 
9
+ const SIZES = {
10
+ small: '180px',
11
+ medium: '280px',
12
+ large: '380px'
13
+ };
8
14
  const StyledPopup = /*#__PURE__*/_styled(Popup, {
15
+ shouldForwardProp: prop => !['size'].includes(prop),
9
16
  target: "e1jn11gg1"
10
17
  })("background-color:", ({
11
18
  theme
@@ -13,10 +20,14 @@ const StyledPopup = /*#__PURE__*/_styled(Popup, {
13
20
  theme
14
21
  }) => theme.shadows.menu, ";padding:0;&[data-has-arrow='true']{&::after{border-color:", ({
15
22
  theme
16
- }) => theme.colors.neutral.background, " transparent transparent transparent;}}");
23
+ }) => theme.colors.neutral.background, " transparent transparent transparent;}}width:", ({
24
+ size
25
+ }) => SIZES[size], ";max-width:none;padding:", ({
26
+ theme
27
+ }) => `${theme.space['0.25']} 0`, ";");
17
28
  const MenuList = /*#__PURE__*/_styled(Stack, {
18
29
  target: "e1jn11gg0"
19
- })("&:after,&:before{border:solid transparent;border-width:9px;content:' ';height:0;width:0;position:absolute;pointer-events:none;}&:after{border-color:transparent;}&:before{border-color:transparent;}background-color:", ({
30
+ })("max-height:480px;overflow-y:auto;overflow-x:hidden;&:after,&:before{border:solid transparent;border-width:9px;content:' ';height:0;width:0;position:absolute;pointer-events:none;}&:after{border-color:transparent;}&:before{border-color:transparent;}background-color:", ({
20
31
  theme
21
32
  }) => theme.colors.neutral.backgroundWeakElevated, ";color:", ({
22
33
  theme
@@ -28,14 +39,16 @@ const FwdMenu = /*#__PURE__*/forwardRef(({
28
39
  ariaLabel = 'Menu',
29
40
  children,
30
41
  disclosure,
31
- hasArrow = true,
42
+ hasArrow = false,
32
43
  placement = 'bottom',
33
44
  visible = false,
34
45
  className,
35
46
  'data-testid': dataTestId,
36
47
  maxHeight,
37
48
  maxWidth,
38
- portalTarget
49
+ portalTarget,
50
+ size = 'small',
51
+ triggerMethod = 'click'
39
52
  }, ref) => {
40
53
  const [isVisible, setIsVisible] = useState(visible);
41
54
  const popupRef = useRef(null);
@@ -60,11 +73,11 @@ const FwdMenu = /*#__PURE__*/forwardRef(({
60
73
  ref: disclosureRef
61
74
  });
62
75
  return jsx(StyledPopup, {
63
- needDebounce: false,
76
+ debounceDelay: triggerMethod === 'hover' ? 350 : 0,
64
77
  hideOnClickOutside: true,
65
78
  "aria-label": ariaLabel,
66
79
  className: className,
67
- visible: isVisible,
80
+ visible: triggerMethod === 'click' ? isVisible : undefined,
68
81
  placement: placement,
69
82
  hasArrow: hasArrow,
70
83
  "data-has-arrow": hasArrow,
@@ -75,6 +88,7 @@ const FwdMenu = /*#__PURE__*/forwardRef(({
75
88
  tabIndex: -1,
76
89
  maxHeight: maxHeight,
77
90
  maxWidth: maxWidth,
91
+ size: size,
78
92
  text: jsx(MenuList, {
79
93
  "data-testid": dataTestId,
80
94
  className: className,
@@ -95,7 +109,8 @@ const FwdMenu = /*#__PURE__*/forwardRef(({
95
109
  * When a user activates a choice in a menu, the menu usually closes unless the choice opened a submenu.
96
110
  */
97
111
  const MenuV2 = /*#__PURE__*/Object.assign(FwdMenu, {
98
- Item
112
+ Item,
113
+ Group
99
114
  });
100
115
 
101
116
  export { MenuV2 };
@@ -116,7 +116,7 @@ const Popover = /*#__PURE__*/forwardRef(({
116
116
  }, [onClose]);
117
117
  return jsx(StyledPopup, {
118
118
  hideOnClickOutside: true,
119
- needDebounce: false,
119
+ debounceDelay: 0,
120
120
  visible: localVisible,
121
121
  placement: placement,
122
122
  text: jsx(ContentWrapper, {
@@ -78,7 +78,7 @@ const Popup = /*#__PURE__*/forwardRef(({
78
78
  onKeyDown,
79
79
  'aria-haspopup': ariaHasPopup,
80
80
  hideOnClickOutside = false,
81
- needDebounce = true,
81
+ debounceDelay = DEFAULT_DEBOUNCE_DURATION,
82
82
  disableAnimation = false,
83
83
  portalTarget
84
84
  }, ref) => {
@@ -88,8 +88,8 @@ const Popup = /*#__PURE__*/forwardRef(({
88
88
  useImperativeHandle(ref, () => innerPopupRef.current);
89
89
  const timer = useRef();
90
90
  const popupPortalTarget = useMemo(() => {
91
+ if (portalTarget) return portalTarget;
91
92
  if (role === 'dialog') {
92
- if (portalTarget) return portalTarget;
93
93
  if (childrenRef.current) return childrenRef.current;
94
94
  if (typeof window !== 'undefined') return document.body;
95
95
  return null;
@@ -158,14 +158,20 @@ const Popup = /*#__PURE__*/forwardRef(({
158
158
  unmountPopupFromDom();
159
159
  onClose?.();
160
160
  }, animationDuration);
161
- }, needDebounce && !disableAnimation ? DEFAULT_DEBOUNCE_DURATION : 0);
162
- }, [animationDuration, disableAnimation, needDebounce, onClose, unmountPopupFromDom]);
161
+ }, debounceDelay && !disableAnimation ? debounceDelay : 0);
162
+ }, [animationDuration, disableAnimation, debounceDelay, onClose, unmountPopupFromDom]);
163
163
 
164
164
  /**
165
165
  * When mouse hover or stop hovering children this function display or hide popup. A timeout is set to allow animation
166
166
  * end, then remove popup from dom.
167
167
  */
168
168
  const onPointerEvent = useCallback(isVisible => () => {
169
+ // If there is a debounceDelay and the popup is not visible, we clear the debounce timer
170
+ if (!visible && debounceDelay > 0 && debounceTimer.current) {
171
+ clearTimeout(debounceTimer.current);
172
+ debounceTimer.current = undefined;
173
+ }
174
+
169
175
  // This condition is for when we want to unmount the popup
170
176
  // There is debounce in order to avoid popup to flicker when we move the mouse from children to popup
171
177
  // Timer is used to follow the animation duration
@@ -186,9 +192,15 @@ const Popup = /*#__PURE__*/forwardRef(({
186
192
  clearTimeout(debounceTimer.current);
187
193
  debounceTimer.current = undefined;
188
194
  }
189
- setVisibleInDom(true);
195
+ if (debounceDelay > 0) {
196
+ debounceTimer.current = setTimeout(() => {
197
+ setVisibleInDom(true);
198
+ }, debounceDelay);
199
+ } else {
200
+ setVisibleInDom(true);
201
+ }
190
202
  }
191
- }, [closePopup, innerPopupRef]);
203
+ }, [closePopup, debounceDelay, visible]);
192
204
 
193
205
  /**
194
206
  * Once popup is visible in the dom we can compute positions, then set it visible on screen and add event to
@@ -338,6 +350,8 @@ const Popup = /*#__PURE__*/forwardRef(({
338
350
  "data-testid": dataTestId,
339
351
  "data-has-arrow": hasArrow,
340
352
  onClick: stopClickPropagation,
353
+ onPointerEnter: !isControlled ? onPointerEvent(true) : noop,
354
+ onPointerLeave: !isControlled ? onPointerEvent(false) : noop,
341
355
  animationDuration: animationDuration,
342
356
  onKeyDown: role === 'dialog' ? handleFocusTrap : undefined,
343
357
  isDialog: role === 'dialog',
@@ -58,7 +58,6 @@ const toast = {
58
58
  /**
59
59
  * @deprecated "Deprecated, please use another variant instead"
60
60
  */
61
- // eslint-disable-next-line deprecation/deprecation
62
61
  info: (children, options, containerId) => toast$1.info(jsx(Content, {
63
62
  children: children
64
63
  }), {
@@ -32,6 +32,7 @@ const Tooltip = /*#__PURE__*/forwardRef(({
32
32
  role = 'tooltip',
33
33
  'data-testid': dataTestId,
34
34
  portalTarget,
35
+ debounceDelay,
35
36
  tabIndex
36
37
  }, tooltipRef) => jsx(StyledPopup, {
37
38
  id: id,
@@ -47,6 +48,7 @@ const Tooltip = /*#__PURE__*/forwardRef(({
47
48
  innerRef: innerRef,
48
49
  portalTarget: portalTarget,
49
50
  tabIndex: tabIndex,
51
+ debounceDelay: debounceDelay,
50
52
  children: children
51
53
  }));
52
54
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ultraviolet/ui",
3
- "version": "1.45.6",
3
+ "version": "1.47.0",
4
4
  "description": "Ultraviolet UI",
5
5
  "homepage": "https://github.com/scaleway/ultraviolet#readme",
6
6
  "repository": {
@@ -39,13 +39,13 @@
39
39
  "react-dom": "18.2.0"
40
40
  },
41
41
  "devDependencies": {
42
- "@babel/core": "7.24.3",
42
+ "@babel/core": "7.24.4",
43
43
  "@emotion/babel-plugin": "11.11.0",
44
44
  "@emotion/react": "11.11.4",
45
45
  "@emotion/styled": "11.11.5",
46
- "@types/react": "18.2.74",
46
+ "@types/react": "18.2.78",
47
47
  "@types/react-datepicker": "4.19.6",
48
- "@types/react-dom": "18.2.24",
48
+ "@types/react-dom": "18.2.25",
49
49
  "react": "18.2.0",
50
50
  "react-dom": "18.2.0"
51
51
  },
@@ -65,7 +65,7 @@
65
65
  "react-use-clipboard": "1.0.9",
66
66
  "reakit": "1.3.11",
67
67
  "@ultraviolet/themes": "1.10.0",
68
- "@ultraviolet/icons": "2.12.2"
68
+ "@ultraviolet/icons": "2.12.4"
69
69
  },
70
70
  "scripts": {
71
71
  "build": "rollup -c ../../rollup.config.mjs",