@ultraviolet/ui 1.51.0 → 1.51.1
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 +61 -31
- package/dist/src/components/MenuV2/index.js +3 -1
- package/dist/src/components/Popover/index.js +3 -1
- package/dist/src/components/Popup/helpers.js +4 -4
- package/dist/src/components/Popup/index.js +24 -4
- package/dist/src/components/SelectInputV2/SearchBarDropdown.js +2 -8
- package/package.json +8 -8
package/dist/index.d.ts
CHANGED
|
@@ -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: {
|
|
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;
|
|
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**.
|
|
@@ -2034,7 +2034,7 @@ declare const arrowPlacementStyles: {
|
|
|
2034
2034
|
readonly 'top-start': (theme: Theme) => _emotion_react.SerializedStyles;
|
|
2035
2035
|
};
|
|
2036
2036
|
type ArrowPlacement = keyof typeof arrowPlacementStyles;
|
|
2037
|
-
type MenuProps
|
|
2037
|
+
type MenuProps = {
|
|
2038
2038
|
ariaLabel?: string;
|
|
2039
2039
|
id?: string;
|
|
2040
2040
|
placement?: ArrowPlacement;
|
|
@@ -2052,7 +2052,7 @@ type MenuProps$1 = {
|
|
|
2052
2052
|
* When a user activates a choice in a menu, the menu usually closes unless the choice opened a submenu.
|
|
2053
2053
|
* @deprecated use MenuV2 component instead
|
|
2054
2054
|
*/
|
|
2055
|
-
declare const Menu: react.ForwardRefExoticComponent<MenuProps
|
|
2055
|
+
declare const Menu: react.ForwardRefExoticComponent<MenuProps & react.RefAttributes<HTMLButtonElement>> & {
|
|
2056
2056
|
Item: react.ForwardRefExoticComponent<{
|
|
2057
2057
|
href?: string | undefined;
|
|
2058
2058
|
disabled?: boolean | undefined;
|
|
@@ -2358,7 +2358,8 @@ declare const Popover: react.ForwardRefExoticComponent<{
|
|
|
2358
2358
|
maxHeight?: string | number | undefined;
|
|
2359
2359
|
disableAnimation?: boolean | undefined;
|
|
2360
2360
|
portalTarget?: HTMLElement | undefined;
|
|
2361
|
-
|
|
2361
|
+
dynamicDomRendering?: boolean | undefined;
|
|
2362
|
+
} & react.RefAttributes<HTMLDivElement>, "placement" | "dynamicDomRendering"> & react.RefAttributes<HTMLDivElement>>;
|
|
2362
2363
|
|
|
2363
2364
|
type PopupProps = {
|
|
2364
2365
|
/**
|
|
@@ -2418,6 +2419,12 @@ type PopupProps = {
|
|
|
2418
2419
|
* behavior by setting a portalTarget prop.
|
|
2419
2420
|
*/
|
|
2420
2421
|
portalTarget?: HTMLElement;
|
|
2422
|
+
/**
|
|
2423
|
+
* If you set this to true, the popup will be rendered in the DOM only when it is visible.
|
|
2424
|
+
* When set to false, the popup will always be rendered in the DOM. By default this value is set to `true`, if for some
|
|
2425
|
+
* reason you need to disable it, you can set it to `false`.
|
|
2426
|
+
*/
|
|
2427
|
+
dynamicDomRendering?: boolean;
|
|
2421
2428
|
};
|
|
2422
2429
|
/**
|
|
2423
2430
|
* @experimental This component is experimental and may be subject to breaking changes in the future.
|
|
@@ -3364,11 +3371,6 @@ declare const RadioGroup: {
|
|
|
3364
3371
|
Radio: ({ onFocus, onBlur, disabled, error, name, value, label, helper, className, autoFocus, onKeyDown, "data-testid": dataTestId, }: RadioGroupRadioProps) => _emotion_react_jsx_runtime.JSX.Element;
|
|
3365
3372
|
};
|
|
3366
3373
|
|
|
3367
|
-
declare const SIZES: {
|
|
3368
|
-
small: string;
|
|
3369
|
-
medium: string;
|
|
3370
|
-
large: string;
|
|
3371
|
-
};
|
|
3372
3374
|
type DisclosureProps = {
|
|
3373
3375
|
visible: boolean;
|
|
3374
3376
|
};
|
|
@@ -3378,40 +3380,68 @@ type DisclosureElement = ((disclosure: DisclosureProps) => ReactElement<ButtonHT
|
|
|
3378
3380
|
type ChildMenuProps = {
|
|
3379
3381
|
toggle: () => void;
|
|
3380
3382
|
};
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3383
|
+
/**
|
|
3384
|
+
* A menu is a widget that offers a list of choices to the user, such as a set of actions or functions.
|
|
3385
|
+
* A menu is usually opened, or made visible, by activating a menu button, choosing an item in a menu that opens a
|
|
3386
|
+
* sub menu, or by invoking a command, such as `Shift + F10` on Windows, that opens a context specific menu.
|
|
3387
|
+
* When a user activates a choice in a menu, the menu usually closes unless the choice opened a submenu.
|
|
3388
|
+
*/
|
|
3389
|
+
declare const MenuV2: react.ForwardRefExoticComponent<{
|
|
3390
|
+
id?: string | undefined;
|
|
3391
|
+
ariaLabel?: string | undefined;
|
|
3385
3392
|
children?: ReactNode | (({ toggle }: ChildMenuProps) => ReactNode);
|
|
3386
|
-
className?: string;
|
|
3393
|
+
className?: string | undefined;
|
|
3387
3394
|
disclosure: DisclosureElement;
|
|
3388
|
-
hasArrow?: boolean;
|
|
3389
|
-
visible?: boolean;
|
|
3390
|
-
'data-testid'?: string;
|
|
3391
|
-
maxHeight?: string;
|
|
3395
|
+
hasArrow?: boolean | undefined;
|
|
3396
|
+
visible?: boolean | undefined;
|
|
3397
|
+
'data-testid'?: string | undefined;
|
|
3398
|
+
maxHeight?: string | undefined;
|
|
3392
3399
|
/**
|
|
3393
3400
|
* @deprecated: use `size` instead
|
|
3394
3401
|
*/
|
|
3395
|
-
maxWidth?: string;
|
|
3402
|
+
maxWidth?: string | undefined;
|
|
3396
3403
|
/**
|
|
3397
3404
|
* By default, the portal target is children container or document.body if children is a function. You can override this
|
|
3398
3405
|
* behavior by setting a portalTarget prop.
|
|
3399
3406
|
*/
|
|
3400
|
-
portalTarget?: HTMLElement;
|
|
3401
|
-
size?:
|
|
3407
|
+
portalTarget?: HTMLElement | undefined;
|
|
3408
|
+
size?: "large" | "small" | "medium" | undefined;
|
|
3402
3409
|
/**
|
|
3403
3410
|
* The behavior of the menu when it is opened. If set to `click`, the menu will open when the user clicks on the disclosure.
|
|
3404
3411
|
* If set to `hover`, the menu will open when the user hovers over the disclosure.
|
|
3405
3412
|
*/
|
|
3406
|
-
triggerMethod?:
|
|
3407
|
-
}
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3413
|
+
triggerMethod?: "click" | "hover" | undefined;
|
|
3414
|
+
} & Pick<{
|
|
3415
|
+
id?: string | undefined;
|
|
3416
|
+
children: ReactNode | ((renderProps: {
|
|
3417
|
+
className?: string | undefined;
|
|
3418
|
+
onBlur: () => void;
|
|
3419
|
+
onFocus: () => void;
|
|
3420
|
+
onPointerEnter: () => void;
|
|
3421
|
+
onPointerLeave: () => void;
|
|
3422
|
+
ref: react.RefObject<HTMLDivElement>;
|
|
3423
|
+
}) => ReactNode);
|
|
3424
|
+
maxWidth?: string | number | undefined;
|
|
3425
|
+
placement?: PopupPlacement | undefined;
|
|
3426
|
+
text?: ReactNode;
|
|
3427
|
+
className?: string | undefined;
|
|
3428
|
+
containerFullWidth?: boolean | undefined;
|
|
3429
|
+
visible?: boolean | undefined;
|
|
3430
|
+
innerRef?: Ref<HTMLDivElement | null> | undefined;
|
|
3431
|
+
role?: string | undefined;
|
|
3432
|
+
'data-testid'?: string | undefined;
|
|
3433
|
+
hasArrow?: boolean | undefined;
|
|
3434
|
+
onClose?: (() => void) | undefined;
|
|
3435
|
+
tabIndex?: number | undefined;
|
|
3436
|
+
onKeyDown?: react.KeyboardEventHandler | undefined;
|
|
3437
|
+
'aria-haspopup'?: boolean | "menu" | "dialog" | "grid" | "listbox" | "tree" | "false" | "true" | undefined;
|
|
3438
|
+
hideOnClickOutside?: boolean | undefined;
|
|
3439
|
+
debounceDelay?: number | undefined;
|
|
3440
|
+
maxHeight?: string | number | undefined;
|
|
3441
|
+
disableAnimation?: boolean | undefined;
|
|
3442
|
+
portalTarget?: HTMLElement | undefined;
|
|
3443
|
+
dynamicDomRendering?: boolean | undefined;
|
|
3444
|
+
} & react.RefAttributes<HTMLDivElement>, "placement" | "dynamicDomRendering"> & react.RefAttributes<HTMLButtonElement>> & {
|
|
3415
3445
|
Item: react.ForwardRefExoticComponent<{
|
|
3416
3446
|
href?: string | undefined;
|
|
3417
3447
|
disabled?: boolean | undefined;
|
|
@@ -48,7 +48,8 @@ const FwdMenu = /*#__PURE__*/forwardRef(({
|
|
|
48
48
|
maxWidth,
|
|
49
49
|
portalTarget,
|
|
50
50
|
size = 'small',
|
|
51
|
-
triggerMethod = 'click'
|
|
51
|
+
triggerMethod = 'click',
|
|
52
|
+
dynamicDomRendering
|
|
52
53
|
}, ref) => {
|
|
53
54
|
const [isVisible, setIsVisible] = useState(visible);
|
|
54
55
|
const popupRef = useRef(null);
|
|
@@ -98,6 +99,7 @@ const FwdMenu = /*#__PURE__*/forwardRef(({
|
|
|
98
99
|
}) : children
|
|
99
100
|
}),
|
|
100
101
|
portalTarget: portalTarget,
|
|
102
|
+
dynamicDomRendering: dynamicDomRendering,
|
|
101
103
|
children: finalDisclosure
|
|
102
104
|
});
|
|
103
105
|
});
|
|
@@ -101,7 +101,8 @@ const Popover = /*#__PURE__*/forwardRef(({
|
|
|
101
101
|
maxWidth,
|
|
102
102
|
maxHeight,
|
|
103
103
|
'data-testid': dataTestId,
|
|
104
|
-
portalTarget
|
|
104
|
+
portalTarget,
|
|
105
|
+
dynamicDomRendering
|
|
105
106
|
}, ref) => {
|
|
106
107
|
const innerRef = useRef(null);
|
|
107
108
|
const [localVisible, setLocalVisible] = useState(visible);
|
|
@@ -137,6 +138,7 @@ const Popover = /*#__PURE__*/forwardRef(({
|
|
|
137
138
|
maxWidth: maxWidth,
|
|
138
139
|
maxHeight: maxHeight,
|
|
139
140
|
portalTarget: portalTarget,
|
|
141
|
+
dynamicDomRendering: dynamicDomRendering,
|
|
140
142
|
children: children
|
|
141
143
|
});
|
|
142
144
|
});
|
|
@@ -2,13 +2,13 @@ const ARROW_WIDTH = 8; // in px
|
|
|
2
2
|
const SPACE = 4; // in px
|
|
3
3
|
const TOTAL_USED_SPACE = 0; // in px
|
|
4
4
|
const DEFAULT_POSITIONS = {
|
|
5
|
-
arrowLeft:
|
|
6
|
-
arrowTop:
|
|
5
|
+
arrowLeft: 0,
|
|
6
|
+
arrowTop: 0,
|
|
7
7
|
arrowTransform: 'translate(-50%, -50)',
|
|
8
8
|
placement: 'top',
|
|
9
9
|
rotate: 135,
|
|
10
|
-
popupInitialPosition: 'translate3d(
|
|
11
|
-
popupPosition: 'translate3d(
|
|
10
|
+
popupInitialPosition: 'translate3d(0px, 0px, 0)',
|
|
11
|
+
popupPosition: 'translate3d(0px, 0px, 0)'
|
|
12
12
|
};
|
|
13
13
|
/**
|
|
14
14
|
* This function will find the best placement in a window for popup based on children position and popup size
|
|
@@ -28,7 +28,7 @@ const StyledPopup = /*#__PURE__*/_styled('div', {
|
|
|
28
28
|
maxHeight
|
|
29
29
|
}) => typeof maxHeight === 'number' ? `${maxHeight}px` : maxHeight, ";overflow:", ({
|
|
30
30
|
maxHeight
|
|
31
|
-
}) => maxHeight ? 'auto' : undefined, ";overflow-wrap:break-word;font-size:0.8rem;inset:0 auto auto 0;top:0;left:0;z-index:1;transform:", ({
|
|
31
|
+
}) => maxHeight ? 'auto' : undefined, ";overflow-wrap:break-word;font-size:0.8rem;inset:0 auto auto 0;top:0;left:0;opacity:0;z-index:1;transform:", ({
|
|
32
32
|
positions
|
|
33
33
|
}) => positions.popupPosition, ";animation:", ({
|
|
34
34
|
positions,
|
|
@@ -45,7 +45,7 @@ const StyledPopup = /*#__PURE__*/_styled('div', {
|
|
|
45
45
|
positions
|
|
46
46
|
}) => positions.rotate, "deg);margin-left:-", ARROW_WIDTH, "px;border-width:", ARROW_WIDTH, "px;border-style:solid;border-color:", ({
|
|
47
47
|
theme
|
|
48
|
-
}) => theme.colors.neutral.backgroundStronger, " transparent transparent transparent;pointer-events:none;}}");
|
|
48
|
+
}) => theme.colors.neutral.backgroundStronger, " transparent transparent transparent;pointer-events:none;}}&[data-visible-in-dom='false']{display:none;}");
|
|
49
49
|
const StyledChildrenContainer = /*#__PURE__*/_styled("div", {
|
|
50
50
|
target: "e4h1g860"
|
|
51
51
|
})(process.env.NODE_ENV === "production" ? {
|
|
@@ -80,7 +80,8 @@ const Popup = /*#__PURE__*/forwardRef(({
|
|
|
80
80
|
hideOnClickOutside = false,
|
|
81
81
|
debounceDelay = DEFAULT_DEBOUNCE_DURATION,
|
|
82
82
|
disableAnimation = false,
|
|
83
|
-
portalTarget
|
|
83
|
+
portalTarget,
|
|
84
|
+
dynamicDomRendering = true
|
|
84
85
|
}, ref) => {
|
|
85
86
|
const childrenRef = useRef(null);
|
|
86
87
|
useImperativeHandle(innerRef, () => childrenRef.current);
|
|
@@ -226,6 +227,15 @@ const Popup = /*#__PURE__*/forwardRef(({
|
|
|
226
227
|
};
|
|
227
228
|
}, [generatePopupPositions, onWindowChangeDetected, visibleInDom, maxWidth, popupPortalTarget]);
|
|
228
229
|
|
|
230
|
+
// This will be triggered when positions are computed and popup is visible in the dom.
|
|
231
|
+
useEffect(() => {
|
|
232
|
+
if (visibleInDom && innerPopupRef.current) {
|
|
233
|
+
innerPopupRef.current.style.opacity = '1';
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
237
|
+
[positions]);
|
|
238
|
+
|
|
229
239
|
/**
|
|
230
240
|
* If popup has `visible` prop it means the popup is manually controlled through this prop.
|
|
231
241
|
* In this cas we don't want to display popup on hover, but only when `visible` is true.
|
|
@@ -324,6 +334,15 @@ const Popup = /*#__PURE__*/forwardRef(({
|
|
|
324
334
|
children: children
|
|
325
335
|
});
|
|
326
336
|
}, [ariaHasPopup, children, containerFullWidth, generatedId, isControlled, onKeyDown, onPointerEvent, tabIndex]);
|
|
337
|
+
const shouldRender = useMemo(() => {
|
|
338
|
+
if (!dynamicDomRendering) {
|
|
339
|
+
return true;
|
|
340
|
+
}
|
|
341
|
+
if (dynamicDomRendering && visibleInDom) {
|
|
342
|
+
return true;
|
|
343
|
+
}
|
|
344
|
+
return false;
|
|
345
|
+
}, [dynamicDomRendering, visibleInDom]);
|
|
327
346
|
if (!text) {
|
|
328
347
|
if (typeof children === 'function') return null;
|
|
329
348
|
return jsx(Fragment, {
|
|
@@ -338,7 +357,7 @@ const Popup = /*#__PURE__*/forwardRef(({
|
|
|
338
357
|
event.nativeEvent.stopImmediatePropagation();
|
|
339
358
|
};
|
|
340
359
|
return jsxs(Fragment, {
|
|
341
|
-
children: [renderChildren(),
|
|
360
|
+
children: [renderChildren(), shouldRender ? /*#__PURE__*/createPortal(jsx(StyledPopup, {
|
|
342
361
|
ref: innerPopupRef,
|
|
343
362
|
positions: positions,
|
|
344
363
|
maxWidth: maxWidth,
|
|
@@ -355,6 +374,7 @@ const Popup = /*#__PURE__*/forwardRef(({
|
|
|
355
374
|
animationDuration: animationDuration,
|
|
356
375
|
onKeyDown: role === 'dialog' ? handleFocusTrap : undefined,
|
|
357
376
|
isDialog: role === 'dialog',
|
|
377
|
+
"data-visible-in-dom": !dynamicDomRendering ? visibleInDom : undefined,
|
|
358
378
|
children: text
|
|
359
379
|
}), popupPortalTarget) : null]
|
|
360
380
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import _styled from '@emotion/styled/base';
|
|
2
2
|
import { Icon } from '@ultraviolet/icons';
|
|
3
|
-
import { useRef
|
|
3
|
+
import { useRef } from 'react';
|
|
4
4
|
import { TextInputV2 } from '../TextInputV2/index.js';
|
|
5
5
|
import { useSelectInput } from './SelectInputProvider.js';
|
|
6
6
|
import { jsx } from '@emotion/react/jsx-runtime';
|
|
@@ -99,13 +99,6 @@ const SearchBarDropdown = ({
|
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
101
|
};
|
|
102
|
-
useEffect(() => {
|
|
103
|
-
// TODO: Remove me and use autoFocus when popup is fixed
|
|
104
|
-
// Explanation : Actually the component render at -999px -999px then it will be placed according to child position and it broke the autoFocus (scroll -999px to top)
|
|
105
|
-
setTimeout(() => {
|
|
106
|
-
searchInputRef.current?.focus();
|
|
107
|
-
}, 50);
|
|
108
|
-
}, []);
|
|
109
102
|
return jsx(StyledInput, {
|
|
110
103
|
value: searchInput,
|
|
111
104
|
onChange: event => handleChange(event),
|
|
@@ -120,6 +113,7 @@ const SearchBarDropdown = ({
|
|
|
120
113
|
}),
|
|
121
114
|
onKeyDown: event => handleKeyDown(event.key, searchInput),
|
|
122
115
|
size: "medium",
|
|
116
|
+
autoFocus: true,
|
|
123
117
|
"aria-label": "search-bar",
|
|
124
118
|
ref: searchInputRef
|
|
125
119
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ultraviolet/ui",
|
|
3
|
-
"version": "1.51.
|
|
3
|
+
"version": "1.51.1",
|
|
4
4
|
"description": "Ultraviolet UI",
|
|
5
5
|
"homepage": "https://github.com/scaleway/ultraviolet#readme",
|
|
6
6
|
"repository": {
|
|
@@ -35,19 +35,19 @@
|
|
|
35
35
|
"peerDependencies": {
|
|
36
36
|
"@emotion/react": "11.11.4",
|
|
37
37
|
"@emotion/styled": "11.11.5",
|
|
38
|
-
"react": "18.
|
|
39
|
-
"react-dom": "18.
|
|
38
|
+
"react": "18.3.1",
|
|
39
|
+
"react-dom": "18.3.1"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@babel/core": "7.24.
|
|
42
|
+
"@babel/core": "7.24.5",
|
|
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.
|
|
46
|
+
"@types/react": "18.3.1",
|
|
47
47
|
"@types/react-datepicker": "4.19.6",
|
|
48
|
-
"@types/react-dom": "18.
|
|
49
|
-
"react": "18.
|
|
50
|
-
"react-dom": "18.
|
|
48
|
+
"@types/react-dom": "18.3.0",
|
|
49
|
+
"react": "18.3.1",
|
|
50
|
+
"react-dom": "18.3.1"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
53
|
"@emotion/serialize": "1.1.4",
|