@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 +37 -9
- package/dist/src/components/List/ListContext.js +32 -15
- package/dist/src/components/List/index.js +3 -1
- package/dist/src/components/MenuV2/Group.js +25 -0
- package/dist/src/components/MenuV2/Item.js +28 -6
- package/dist/src/components/MenuV2/index.js +22 -7
- package/dist/src/components/Popover/index.js +1 -1
- package/dist/src/components/Popup/index.js +20 -6
- package/dist/src/components/Toaster/index.js +0 -1
- package/dist/src/components/Tooltip/index.js +2 -0
- package/package.json +5 -5
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
83
|
-
...
|
|
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
|
-
|
|
89
|
-
...
|
|
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:
|
|
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(
|
|
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(
|
|
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
|
-
})("
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
},
|
|
162
|
-
}, [animationDuration, disableAnimation,
|
|
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
|
-
|
|
195
|
+
if (debounceDelay > 0) {
|
|
196
|
+
debounceTimer.current = setTimeout(() => {
|
|
197
|
+
setVisibleInDom(true);
|
|
198
|
+
}, debounceDelay);
|
|
199
|
+
} else {
|
|
200
|
+
setVisibleInDom(true);
|
|
201
|
+
}
|
|
190
202
|
}
|
|
191
|
-
}, [closePopup,
|
|
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',
|
|
@@ -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.
|
|
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.
|
|
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.
|
|
46
|
+
"@types/react": "18.2.78",
|
|
47
47
|
"@types/react-datepicker": "4.19.6",
|
|
48
|
-
"@types/react-dom": "18.2.
|
|
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.
|
|
68
|
+
"@ultraviolet/icons": "2.12.4"
|
|
69
69
|
},
|
|
70
70
|
"scripts": {
|
|
71
71
|
"build": "rollup -c ../../rollup.config.mjs",
|