@jetbrains/ring-ui 7.0.79 → 7.0.81
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/components/avatar/fallback-avatar.js +2 -2
- package/components/collapse/collapse-content.js +8 -10
- package/components/collapse/collapse-control.js +2 -7
- package/components/collapse/collapse.js +4 -4
- package/components/date-picker/months.js +7 -10
- package/components/dropdown/dropdown.css +4 -0
- package/components/dropdown/dropdown.js +6 -4
- package/components/dropdown-menu/dropdown-menu.js +9 -8
- package/components/editable-heading/editable-heading.js +29 -31
- package/components/global/theme.d.ts +1 -0
- package/components/global/theme.js +11 -17
- package/components/global/use-event-callback.js +1 -0
- package/components/popup/popup.js +29 -50
- package/components/slider/slider.js +48 -50
- package/components/tabs/collapsible-more.js +29 -32
- package/components/tabs/collapsible-tabs.js +20 -24
- package/components/upload/upload.js +13 -10
- package/package.json +32 -32
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useState } from 'react';
|
|
2
2
|
import getUID from '../global/get-uid';
|
|
3
3
|
import { Size } from './avatar-size';
|
|
4
4
|
const colorPairs = [
|
|
@@ -184,7 +184,7 @@ export default function FallbackAvatar({ username, size, round }) {
|
|
|
184
184
|
const sizes = round ? SizesRound[size] : SizesSquare[size];
|
|
185
185
|
const underscore = sizes.underscore;
|
|
186
186
|
const radius = round ? '50%' : sizes.radius;
|
|
187
|
-
const gradientId =
|
|
187
|
+
const [gradientId] = useState(() => getUID('gradient-'));
|
|
188
188
|
return (<svg viewBox={`0 0 ${size} ${size}`} xmlns='http://www.w3.org/2000/svg'>
|
|
189
189
|
<defs>
|
|
190
190
|
<linearGradient id={gradientId} x1='1' y1='1' x2='0' y2='0'>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState, useEffect, useRef, useContext
|
|
1
|
+
import React, { useState, useEffect, useRef, useContext } from 'react';
|
|
2
2
|
import classNames from 'classnames';
|
|
3
3
|
import dataTests from '../global/data-tests';
|
|
4
4
|
import { getRect } from '../global/dom';
|
|
@@ -45,15 +45,13 @@ export const CollapseContent = ({ children, minHeight = DEFAULT_HEIGHT, 'data-te
|
|
|
45
45
|
observer.observe(contentRef.current);
|
|
46
46
|
}
|
|
47
47
|
}, []);
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}, [duration, contentHeight, height, collapsed, minHeight]);
|
|
56
|
-
const fadeShouldBeVisible = useMemo(() => Boolean(minHeight && collapsed), [minHeight, collapsed]);
|
|
48
|
+
const calculatedDuration = duration + contentHeight * DURATION_FACTOR;
|
|
49
|
+
const style = {
|
|
50
|
+
'--duration': `${calculatedDuration}ms`,
|
|
51
|
+
height,
|
|
52
|
+
opacity: collapsed && !minHeight ? HIDDEN : VISIBLE,
|
|
53
|
+
};
|
|
54
|
+
const fadeShouldBeVisible = Boolean(minHeight && collapsed);
|
|
57
55
|
const shouldRenderContent = disableAnimation ? !collapsed : !shouldHideContent;
|
|
58
56
|
return (<div ref={containerRef} id={`collapse-content-${id}`} data-test={dataTests(COLLAPSE_CONTENT_CONTAINER_TEST_ID)} className={classNames(styles.container, { [styles.transition]: !disableAnimation })} style={style}>
|
|
59
57
|
<div ref={contentRef} data-test={dataTests(COLLAPSE_CONTENT_TEST_ID, dataTest)}>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useContext, cloneElement } from 'react';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import dataTests from '../global/data-tests';
|
|
4
4
|
import { CollapseContext } from './collapse-context';
|
|
@@ -9,12 +9,7 @@ import { COLLAPSE_CONTROL_TEST_ID } from './consts';
|
|
|
9
9
|
export const CollapseControl = ({ children, 'data-test': dataTest }) => {
|
|
10
10
|
const { setCollapsed, collapsed, id } = useContext(CollapseContext);
|
|
11
11
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
12
|
-
const child =
|
|
13
|
-
if (typeof children === 'function') {
|
|
14
|
-
return children(collapsed);
|
|
15
|
-
}
|
|
16
|
-
return children;
|
|
17
|
-
}, [children, collapsed]);
|
|
12
|
+
const child = typeof children === 'function' ? children(collapsed) : children;
|
|
18
13
|
return (<p data-test={dataTests(COLLAPSE_CONTROL_TEST_ID, dataTest)}>
|
|
19
14
|
{/* eslint-disable-next-line */}
|
|
20
15
|
{cloneElement(child, {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useId, useState } from 'react';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import { CollapseContext } from './collapse-context';
|
|
4
4
|
import { BASE_ANIMATION_DURATION } from './consts';
|
|
@@ -8,11 +8,11 @@ import { BASE_ANIMATION_DURATION } from './consts';
|
|
|
8
8
|
export const Collapse = ({ children, duration = BASE_ANIMATION_DURATION, disableAnimation = false, className = '', onChange = () => { }, defaultCollapsed = true, collapsed = null, }) => {
|
|
9
9
|
const [innerCollapsed, setInnerCollapsed] = useState(defaultCollapsed);
|
|
10
10
|
const id = useId();
|
|
11
|
-
const finalCollapsedValue =
|
|
12
|
-
const setCollapsed =
|
|
11
|
+
const finalCollapsedValue = collapsed ?? innerCollapsed;
|
|
12
|
+
const setCollapsed = () => {
|
|
13
13
|
setInnerCollapsed(!finalCollapsedValue);
|
|
14
14
|
onChange(!finalCollapsedValue);
|
|
15
|
-
}
|
|
15
|
+
};
|
|
16
16
|
return (<div className={className}>
|
|
17
17
|
<CollapseContext.Provider value={{
|
|
18
18
|
collapsed: finalCollapsedValue,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect,
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
2
|
import { addMonths } from 'date-fns/addMonths';
|
|
3
3
|
import { getDay } from 'date-fns/getDay';
|
|
4
4
|
import { getDaysInMonth } from 'date-fns/getDaysInMonth';
|
|
@@ -37,15 +37,12 @@ export default function Months(props) {
|
|
|
37
37
|
const { scrollDate } = props;
|
|
38
38
|
const monthDate = scrollDate instanceof Date ? scrollDate : new Date(scrollDate);
|
|
39
39
|
const monthStart = startOfMonth(monthDate);
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
return result;
|
|
48
|
-
}, [monthStart]);
|
|
40
|
+
let month = subMonths(monthStart, MONTHSBACK);
|
|
41
|
+
const months = [month];
|
|
42
|
+
for (let i = 0; i < MONTHSBACK * DOUBLE; i++) {
|
|
43
|
+
month = addMonths(month, 1);
|
|
44
|
+
months.push(month);
|
|
45
|
+
}
|
|
49
46
|
const currentSpeed = scrollSpeed(scrollDate);
|
|
50
47
|
const pxToDate = linearFunction(0, Number(scrollDate), currentSpeed);
|
|
51
48
|
const offset = pxToDate.x(Number(monthStart)); // is a negative number
|
|
@@ -125,10 +125,12 @@ export default class Dropdown extends Component {
|
|
|
125
125
|
onContextMenu: hoverMode ? this.handlePopupInteraction : undefined,
|
|
126
126
|
dontCloseOnAnchorClick: true,
|
|
127
127
|
};
|
|
128
|
-
return (<div data-test={dataTests('ring-dropdown', dataTest)} {...restProps}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
128
|
+
return (<div data-test={dataTests('ring-dropdown', dataTest)} {...restProps} onMouseEnter={hoverMode ? this.onMouseEnter : undefined} onMouseLeave={hoverMode ? this.onMouseLeave : undefined} className={classes}>
|
|
129
|
+
{clickMode ? (<div data-test='ring-dropdown-anchor-click-interceptor' className={styles.clickInterceptor} onClick={this.onClick}
|
|
130
|
+
// anchorElement should be a `button` or an `a`
|
|
131
|
+
role='presentation'>
|
|
132
|
+
{anchorElement}
|
|
133
|
+
</div>) : (anchorElement)}
|
|
132
134
|
{typeof children === 'function'
|
|
133
135
|
? children(childProps)
|
|
134
136
|
: cloneElement(children, childProps)}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { forwardRef,
|
|
1
|
+
import { forwardRef, cloneElement, useState, } from 'react';
|
|
2
2
|
import List, { ActiveItemContext } from '../list/list';
|
|
3
3
|
import Dropdown from '../dropdown/dropdown';
|
|
4
4
|
import PopupMenu from '../popup-menu/popup-menu';
|
|
@@ -7,13 +7,13 @@ import Anchor from '../dropdown/anchor';
|
|
|
7
7
|
import { isArray } from '../global/typescript-utils';
|
|
8
8
|
const defaultAriaLabel = 'Dropdown menu';
|
|
9
9
|
function DropdownAnchorWrapper({ anchor, pinned, active, activeListItemId, listId, ...restProps }) {
|
|
10
|
-
const anchorAriaProps =
|
|
10
|
+
const anchorAriaProps = {
|
|
11
11
|
...(listId ? { 'aria-haspopup': true } : {}),
|
|
12
12
|
...(activeListItemId ? { 'aria-activedescendant': activeListItemId, 'aria-owns': listId } : {}),
|
|
13
13
|
...(active ? { 'aria-expanded': true } : {}),
|
|
14
|
-
}
|
|
15
|
-
const anchorProps =
|
|
16
|
-
const anchorComponentProps =
|
|
14
|
+
};
|
|
15
|
+
const anchorProps = { active, pinned, ...restProps, ...anchorAriaProps };
|
|
16
|
+
const anchorComponentProps = { ...anchorProps, pinned: `${anchorProps.pinned}` };
|
|
17
17
|
if (typeof anchor === 'string') {
|
|
18
18
|
return <Anchor {...anchorComponentProps}>{anchor}</Anchor>;
|
|
19
19
|
}
|
|
@@ -32,8 +32,9 @@ function renderDropdownMenuChildren({ children, popupMenuProps }) {
|
|
|
32
32
|
return (popupProps) => children({ ...popupProps, ...popupMenuProps });
|
|
33
33
|
}
|
|
34
34
|
const DropdownMenu = forwardRef(function DropdownMenu({ id, anchor, ariaLabel, data, onSelect, menuProps, children, ...restDropdownProps }, forwardedRef) {
|
|
35
|
-
const
|
|
36
|
-
const
|
|
35
|
+
const [uid] = useState(() => getUID('dropdown-menu-list'));
|
|
36
|
+
const listId = id || uid;
|
|
37
|
+
const popupMenuProps = {
|
|
37
38
|
ref: forwardedRef,
|
|
38
39
|
id: listId,
|
|
39
40
|
ariaLabel: ariaLabel || defaultAriaLabel,
|
|
@@ -42,7 +43,7 @@ const DropdownMenu = forwardRef(function DropdownMenu({ id, anchor, ariaLabel, d
|
|
|
42
43
|
data,
|
|
43
44
|
onSelect,
|
|
44
45
|
...menuProps,
|
|
45
|
-
}
|
|
46
|
+
};
|
|
46
47
|
return (<ActiveItemContext.Provider>
|
|
47
48
|
<Dropdown anchor={({ pinned, active, ...restAnchorProps }) => (<ActiveItemContext.ValueContext.Consumer>
|
|
48
49
|
{activeItemId => (<DropdownAnchorWrapper anchor={anchor} pinned={pinned} active={active} activeListItemId={activeItemId} listId={listId} {...restAnchorProps}/>)}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import classNames from 'classnames';
|
|
4
4
|
import Heading, { Levels } from '../heading/heading';
|
|
@@ -6,6 +6,7 @@ import Button from '../button/button';
|
|
|
6
6
|
import { Size } from '../input/input';
|
|
7
7
|
import getUID from '../global/get-uid';
|
|
8
8
|
import Shortcuts from '../shortcuts/shortcuts';
|
|
9
|
+
import useEventCallback from '../global/use-event-callback';
|
|
9
10
|
import inputStyles from '../input/input.css';
|
|
10
11
|
import styles from './editable-heading.css';
|
|
11
12
|
export { Levels };
|
|
@@ -28,16 +29,13 @@ export const EditableHeading = (props) => {
|
|
|
28
29
|
const isSaveDisabled = !isSavingPossible || !children || children.trim() === '' || hasError || isSaving;
|
|
29
30
|
const isCancelDisabled = isSaving;
|
|
30
31
|
const isShortcutsDisabled = !isInFocus || isSaving;
|
|
31
|
-
const shortcutsMap =
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
return map;
|
|
40
|
-
}, [isSaveDisabled, isCancelDisabled, onSave, onCancel]);
|
|
32
|
+
const shortcutsMap = {};
|
|
33
|
+
if (!isSaveDisabled) {
|
|
34
|
+
shortcutsMap.enter = onSave;
|
|
35
|
+
}
|
|
36
|
+
if (isCancelDisabled) {
|
|
37
|
+
shortcutsMap.esc = onCancel;
|
|
38
|
+
}
|
|
41
39
|
const classes = classNames(styles.editableHeading, className, {
|
|
42
40
|
[styles.fullSize]: isEditing && size === Size.FULL,
|
|
43
41
|
[styles.isEditing]: isEditing,
|
|
@@ -48,61 +46,61 @@ export const EditableHeading = (props) => {
|
|
|
48
46
|
});
|
|
49
47
|
const headingClasses = classNames(styles.heading, headingClassName, styles[`size${size}`]);
|
|
50
48
|
const inputClasses = classNames('ring-js-shortcuts', styles.input, styles.textarea, { [styles.textareaNotOverflow]: !isOverflow }, inputStyles[`size${size}`], styles[`level${level}`], inputClassName);
|
|
51
|
-
const stretch =
|
|
49
|
+
const stretch = (el) => {
|
|
52
50
|
if (!el || !el.style) {
|
|
53
51
|
return;
|
|
54
52
|
}
|
|
55
53
|
el.style.height = '0';
|
|
56
54
|
const { paddingTop, paddingBottom } = window.getComputedStyle(el);
|
|
57
55
|
el.style.height = `${el.scrollHeight - parseFloat(paddingTop) - parseFloat(paddingBottom)}px`;
|
|
58
|
-
}
|
|
59
|
-
const checkValue =
|
|
56
|
+
};
|
|
57
|
+
const checkValue = (el) => {
|
|
60
58
|
if (multiline && el && el.scrollHeight >= el.clientHeight) {
|
|
61
59
|
stretch(el);
|
|
62
60
|
}
|
|
63
|
-
}
|
|
64
|
-
const checkOverflow =
|
|
61
|
+
};
|
|
62
|
+
const checkOverflow = (el) => {
|
|
65
63
|
const scrollHeight = el.scrollHeight || 0;
|
|
66
64
|
const clientHeight = el.clientHeight || 0;
|
|
67
65
|
const scrollTop = el.scrollTop || 0;
|
|
68
66
|
setIsScrolledToBottom(scrollHeight - clientHeight <= scrollTop);
|
|
69
67
|
setIsOverflow(scrollHeight > clientHeight);
|
|
70
|
-
}
|
|
71
|
-
const onHeadingMouseDown =
|
|
68
|
+
};
|
|
69
|
+
const onHeadingMouseDown = () => {
|
|
72
70
|
setIsMouseDown(true);
|
|
73
|
-
}
|
|
74
|
-
const onMouseMove =
|
|
71
|
+
};
|
|
72
|
+
const onMouseMove = useEventCallback(() => {
|
|
75
73
|
if (!isMouseDown) {
|
|
76
74
|
return;
|
|
77
75
|
}
|
|
78
76
|
setIsInSelectionMode(true);
|
|
79
|
-
}
|
|
80
|
-
const onMouseUp =
|
|
77
|
+
});
|
|
78
|
+
const onMouseUp = useEventCallback(() => {
|
|
81
79
|
if (isMouseDown && !isInSelectionMode && !disabled) {
|
|
82
80
|
onEdit();
|
|
83
81
|
}
|
|
84
82
|
setIsMouseDown(false);
|
|
85
83
|
setIsInSelectionMode(false);
|
|
86
|
-
}
|
|
87
|
-
const onInputFocus =
|
|
84
|
+
});
|
|
85
|
+
const onInputFocus = (e) => {
|
|
88
86
|
setIsInFocus(true);
|
|
89
87
|
checkValue(e.target);
|
|
90
88
|
checkOverflow(e.target);
|
|
91
89
|
onFocus?.(e);
|
|
92
|
-
}
|
|
93
|
-
const onInputChange =
|
|
90
|
+
};
|
|
91
|
+
const onInputChange = (e) => {
|
|
94
92
|
checkValue(e.target);
|
|
95
93
|
checkOverflow(e.target);
|
|
96
94
|
onChange?.(e);
|
|
97
|
-
}
|
|
98
|
-
const onInputScroll =
|
|
95
|
+
};
|
|
96
|
+
const onInputScroll = (e) => {
|
|
99
97
|
checkOverflow(e.target);
|
|
100
98
|
onScroll?.(e);
|
|
101
|
-
}
|
|
102
|
-
const onInputBlur =
|
|
99
|
+
};
|
|
100
|
+
const onInputBlur = (e) => {
|
|
103
101
|
setIsInFocus(false);
|
|
104
102
|
onBlur?.(e);
|
|
105
|
-
}
|
|
103
|
+
};
|
|
106
104
|
useEffect(() => {
|
|
107
105
|
window.addEventListener('mousemove', onMouseMove);
|
|
108
106
|
window.addEventListener('mouseup', onMouseUp);
|
|
@@ -6,6 +6,7 @@ declare enum Theme {
|
|
|
6
6
|
}
|
|
7
7
|
export declare const ThemeContext: import("react").Context<{
|
|
8
8
|
theme: Theme.LIGHT | Theme.DARK;
|
|
9
|
+
passToPopups?: boolean;
|
|
9
10
|
}>;
|
|
10
11
|
export declare const GLOBAL_DARK_CLASS_NAME = "ring-ui-theme-dark";
|
|
11
12
|
export declare function useTheme(): Theme.LIGHT | Theme.DARK;
|
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useState, useEffect, forwardRef, createContext, } from 'react';
|
|
2
2
|
import classNames from 'classnames';
|
|
3
|
-
import { createPortal } from 'react-dom';
|
|
4
|
-
import { PopupTarget, PopupTargetContext } from '../popup/popup.target';
|
|
5
|
-
import { getPopupContainer } from '../popup/popup';
|
|
6
|
-
import getUID from './get-uid';
|
|
7
3
|
import defaultStyles from './variables.css';
|
|
8
4
|
import styles from './variables_dark.css';
|
|
9
5
|
var Theme;
|
|
@@ -12,7 +8,9 @@ var Theme;
|
|
|
12
8
|
Theme["LIGHT"] = "light";
|
|
13
9
|
Theme["DARK"] = "dark";
|
|
14
10
|
})(Theme || (Theme = {}));
|
|
15
|
-
export const ThemeContext = createContext({
|
|
11
|
+
export const ThemeContext = createContext({
|
|
12
|
+
theme: Theme.LIGHT,
|
|
13
|
+
});
|
|
16
14
|
export const GLOBAL_DARK_CLASS_NAME = 'ring-ui-theme-dark';
|
|
17
15
|
const darkMatcher = window.matchMedia('(prefers-color-scheme: dark)');
|
|
18
16
|
export function useTheme() {
|
|
@@ -52,27 +50,23 @@ export function applyTheme(theme, container) {
|
|
|
52
50
|
const DefaultWrapper = forwardRef(function Wrapper(props, ref) {
|
|
53
51
|
return <div {...props} ref={ref}/>;
|
|
54
52
|
});
|
|
55
|
-
|
|
53
|
+
function ThemeProviderInner({ theme = Theme.AUTO, className, passToPopups, children, WrapperComponent = DefaultWrapper, target, wrapperRef, ...restProps }) {
|
|
56
54
|
const systemTheme = useTheme();
|
|
57
55
|
const resolvedTheme = theme === Theme.AUTO ? systemTheme : theme;
|
|
58
|
-
const
|
|
59
|
-
const themeValue = useMemo(() => ({ theme: resolvedTheme }), [resolvedTheme]);
|
|
56
|
+
const themeValue = { theme: resolvedTheme, passToPopups };
|
|
60
57
|
useEffect(() => {
|
|
61
58
|
if (target) {
|
|
62
59
|
applyTheme(resolvedTheme, target);
|
|
63
60
|
}
|
|
64
61
|
}, [resolvedTheme, target]);
|
|
65
62
|
const themeClasses = useThemeClasses(theme);
|
|
66
|
-
const parentTarget = useContext(PopupTargetContext);
|
|
67
63
|
return (<ThemeContext.Provider value={themeValue}>
|
|
68
|
-
<WrapperComponent ref={
|
|
69
|
-
{
|
|
70
|
-
{popupTarget => (<>
|
|
71
|
-
{children}
|
|
72
|
-
{createPortal(<div className={themeClasses}>{popupTarget}</div>, (parentTarget && getPopupContainer(parentTarget)) || document.body)}
|
|
73
|
-
</>)}
|
|
74
|
-
</PopupTarget>) : (children)}
|
|
64
|
+
<WrapperComponent ref={wrapperRef} className={target ? undefined : classNames(className, themeClasses)} {...restProps}>
|
|
65
|
+
{children}
|
|
75
66
|
</WrapperComponent>
|
|
76
67
|
</ThemeContext.Provider>);
|
|
68
|
+
}
|
|
69
|
+
export const ThemeProvider = forwardRef(function ThemeProvider(props, ref) {
|
|
70
|
+
return <ThemeProviderInner {...props} wrapperRef={ref}/>;
|
|
77
71
|
});
|
|
78
72
|
export default Theme;
|
|
@@ -17,30 +17,9 @@ import position from './position';
|
|
|
17
17
|
import { DEFAULT_DIRECTIONS, Dimension, Directions, Display, MaxHeight, MinWidth } from './popup.consts';
|
|
18
18
|
import { PopupTargetContext, PopupTarget } from './popup.target';
|
|
19
19
|
import { setCSSAnchorPositioning, supportsCSSAnchorPositioning } from './position-css';
|
|
20
|
+
import { ThemeContext, WithThemeClasses } from '../global/theme';
|
|
20
21
|
import styles from './popup.css';
|
|
21
22
|
export { PopupTargetContext, PopupTarget };
|
|
22
|
-
const isPossibleClientSideNavigation = (event) => {
|
|
23
|
-
const target = event.target;
|
|
24
|
-
const link = target.closest('a');
|
|
25
|
-
// Taken from https://github.com/nanostores/router/blob/80a333db4cf0789fda21a02715ebabca15192642/index.js#L58-L69
|
|
26
|
-
return (link &&
|
|
27
|
-
event.button === 0 && // Left mouse button
|
|
28
|
-
link.target !== '_blank' && // Not for new tab
|
|
29
|
-
link.origin === location.origin && // Not external link
|
|
30
|
-
link.rel !== 'external' && // Not external link
|
|
31
|
-
link.target !== '_self' && // Now manually disabled
|
|
32
|
-
!link.download && // Not download link
|
|
33
|
-
!event.altKey && // Not download link by user
|
|
34
|
-
!event.metaKey && // Not open in new tab by user
|
|
35
|
-
!event.ctrlKey && // Not open in new tab by user
|
|
36
|
-
!event.shiftKey && // Not open in new window by user
|
|
37
|
-
!event.defaultPrevented);
|
|
38
|
-
};
|
|
39
|
-
const stop = (event) => {
|
|
40
|
-
if (!isPossibleClientSideNavigation(event)) {
|
|
41
|
-
event.stopPropagation();
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
23
|
export const getPopupContainer = (target) => typeof target === 'string' ? document.querySelector(`[data-portaltarget=${target}]`) : target;
|
|
45
24
|
/**
|
|
46
25
|
* @constructor
|
|
@@ -301,35 +280,35 @@ export default class Popup extends PureComponent {
|
|
|
301
280
|
render() {
|
|
302
281
|
const { className, style, hidden, attached, keepMounted, client, onMouseDown, onMouseUp, onMouseOver, onMouseOut, onContextMenu, 'data-test': dataTest, largeBorderRadius, } = this.props;
|
|
303
282
|
const showing = this.state.display === Display.SHOWING;
|
|
304
|
-
const classes = classNames(className, styles.popup, {
|
|
305
|
-
[styles.cssAnchoredPopup]: this.shouldUseCssPositioning(),
|
|
306
|
-
[styles.attached]: attached,
|
|
307
|
-
[styles.hidden]: hidden,
|
|
308
|
-
[styles.showing]: showing,
|
|
309
|
-
[styles.largeBorderRadius]: largeBorderRadius,
|
|
310
|
-
});
|
|
311
283
|
const direction = (this.state.direction || '').toLowerCase().replace(/[_]/g, '-');
|
|
312
|
-
return (<
|
|
313
|
-
{
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
284
|
+
return (<ThemeContext.Consumer>
|
|
285
|
+
{theme => (<WithThemeClasses theme={theme.theme}>
|
|
286
|
+
{themeClasses => (<PopupTargetContext.Consumer>
|
|
287
|
+
{value => {
|
|
288
|
+
this.ringPopupTarget = value;
|
|
289
|
+
const classes = classNames(className, theme.passToPopups ? themeClasses : null, styles.popup, {
|
|
290
|
+
[styles.cssAnchoredPopup]: this.shouldUseCssPositioning(),
|
|
291
|
+
[styles.attached]: attached,
|
|
292
|
+
[styles.hidden]: hidden,
|
|
293
|
+
[styles.showing]: showing,
|
|
294
|
+
[styles.largeBorderRadius]: largeBorderRadius,
|
|
295
|
+
});
|
|
296
|
+
return (<span ref={this.portalRef}>
|
|
297
|
+
{this.shouldUseShortcuts() && <Shortcuts map={this.shortcutsMap} scope={this.shortcutsScope}/>}
|
|
321
298
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
299
|
+
{client !== false &&
|
|
300
|
+
(keepMounted || !hidden) &&
|
|
301
|
+
createPortal(<PopupTarget id={this.uid} ref={this.containerRef} onMouseOver={onMouseOver} onFocus={onMouseOver} onMouseOut={onMouseOut} onBlur={onMouseOut} onContextMenu={onContextMenu}>
|
|
302
|
+
<div data-test={dataTests('ring-popup', dataTest)} data-test-shown={!hidden && !showing} data-test-direction={direction} ref={this.popupRef} className={classes} style={style} onMouseDown={onMouseDown} onMouseUp={onMouseUp}
|
|
303
|
+
// mouse handlers are used to track clicking on inner elements
|
|
304
|
+
role='presentation'>
|
|
305
|
+
{this.getInternalContent()}
|
|
306
|
+
</div>
|
|
307
|
+
</PopupTarget>, this.getContainer() || document.body)}
|
|
308
|
+
</span>);
|
|
309
|
+
}}
|
|
310
|
+
</PopupTargetContext.Consumer>)}
|
|
311
|
+
</WithThemeClasses>)}
|
|
312
|
+
</ThemeContext.Consumer>);
|
|
334
313
|
}
|
|
335
314
|
}
|
|
@@ -1,22 +1,23 @@
|
|
|
1
|
-
import { Fragment,
|
|
1
|
+
import { Fragment, useEffect, useRef, useState } from 'react';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import classNames from 'classnames';
|
|
4
4
|
import { isArray } from '../global/typescript-utils';
|
|
5
5
|
import Shortcuts from '../shortcuts/shortcuts';
|
|
6
6
|
import getUID from '../global/get-uid';
|
|
7
7
|
import { adjustValues, calculateMarks, calculateValue, HUNDRED, toPercent, toRange, validateValue } from './slider.utils';
|
|
8
|
+
import useEventCallback from '../global/use-event-callback';
|
|
8
9
|
import styles from './slider.css';
|
|
9
10
|
export const Slider = ({ defaultValue, value, min = 0, max = HUNDRED, step = 1, disabled, marks, showTicks, showTag, className, renderTag, onChange, }) => {
|
|
10
11
|
const ref = useRef(null);
|
|
11
12
|
const previouslyDragged = useRef(false);
|
|
12
13
|
const [values, setValues] = useState(defaultValue ?? min);
|
|
13
|
-
const validValues =
|
|
14
|
+
const validValues = toRange(value ?? values, min, max);
|
|
14
15
|
const validStep = step < 0 ? 0 : step;
|
|
15
16
|
const isRange = isArray(defaultValue ?? value);
|
|
16
17
|
const [isDragging, setIsDragging] = useState(false);
|
|
17
18
|
const [draggedIndex, setDraggedIndex] = useState(-1);
|
|
18
19
|
const [shortcutsScope] = useState(getUID('ring-slider-'));
|
|
19
|
-
const markValues =
|
|
20
|
+
const markValues = (() => {
|
|
20
21
|
if (isArray(marks)) {
|
|
21
22
|
return marks.map(mark => ({ ...mark, value: validateValue(mark.value, min, max) }));
|
|
22
23
|
}
|
|
@@ -24,54 +25,51 @@ export const Slider = ({ defaultValue, value, min = 0, max = HUNDRED, step = 1,
|
|
|
24
25
|
return calculateMarks(min, max, validStep);
|
|
25
26
|
}
|
|
26
27
|
return [];
|
|
27
|
-
}
|
|
28
|
-
const tickMarks =
|
|
28
|
+
})();
|
|
29
|
+
const tickMarks = (() => {
|
|
29
30
|
if (showTicks) {
|
|
30
31
|
return markValues.length ? markValues : calculateMarks(min, max, validStep);
|
|
31
32
|
}
|
|
32
33
|
return [];
|
|
33
|
-
}
|
|
34
|
-
const trackStart =
|
|
35
|
-
const trackLength =
|
|
36
|
-
const handleValueChange =
|
|
34
|
+
})();
|
|
35
|
+
const trackStart = toPercent(isRange ? Math.min(...validValues) : min, min, max);
|
|
36
|
+
const trackLength = toPercent(Math.max(...validValues), min, max) - trackStart;
|
|
37
|
+
const handleValueChange = (nextValues) => {
|
|
37
38
|
setValues(nextValues);
|
|
38
39
|
onChange?.(isRange ? nextValues : nextValues[0]);
|
|
39
|
-
}
|
|
40
|
-
const
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
thumb?.focus();
|
|
49
|
-
}
|
|
50
|
-
handleValueChange(nextValues);
|
|
51
|
-
};
|
|
52
|
-
const getIndex = (target) => Number(target?.getAttribute('data-index'));
|
|
53
|
-
const map = {};
|
|
54
|
-
if (!disabled) {
|
|
55
|
-
map.left = map.down = ({ target }) => {
|
|
56
|
-
const index = getIndex(target);
|
|
57
|
-
setValueAndSwap(Math.max(min, validValues[index] - validStep), index);
|
|
58
|
-
};
|
|
59
|
-
map.right = map.up = ({ target }) => {
|
|
60
|
-
const index = getIndex(target);
|
|
61
|
-
setValueAndSwap(Math.min(max, validValues[index] + validStep), index);
|
|
62
|
-
};
|
|
63
|
-
map.home = ({ target }) => {
|
|
64
|
-
const index = getIndex(target);
|
|
65
|
-
setValueAndSwap(min, index);
|
|
66
|
-
};
|
|
67
|
-
map.end = ({ target }) => {
|
|
68
|
-
const index = getIndex(target);
|
|
69
|
-
setValueAndSwap(max, index);
|
|
70
|
-
};
|
|
40
|
+
};
|
|
41
|
+
const setValueAndSwap = (nextValue, index) => {
|
|
42
|
+
const nextValues = [...validValues];
|
|
43
|
+
nextValues[index] = nextValue;
|
|
44
|
+
if (nextValues[0] > nextValues[1]) {
|
|
45
|
+
const previousValue = nextValues[index];
|
|
46
|
+
nextValues.reverse();
|
|
47
|
+
const thumb = ref.current?.querySelector(`[role="slider"][data-index="${nextValues.indexOf(previousValue)}"]`);
|
|
48
|
+
thumb?.focus();
|
|
71
49
|
}
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
const
|
|
50
|
+
handleValueChange(nextValues);
|
|
51
|
+
};
|
|
52
|
+
const getIndex = (target) => Number(target?.getAttribute('data-index'));
|
|
53
|
+
const shortcutsMap = {};
|
|
54
|
+
if (!disabled) {
|
|
55
|
+
shortcutsMap.left = shortcutsMap.down = ({ target }) => {
|
|
56
|
+
const index = getIndex(target);
|
|
57
|
+
setValueAndSwap(Math.max(min, validValues[index] - validStep), index);
|
|
58
|
+
};
|
|
59
|
+
shortcutsMap.right = shortcutsMap.up = ({ target }) => {
|
|
60
|
+
const index = getIndex(target);
|
|
61
|
+
setValueAndSwap(Math.min(max, validValues[index] + validStep), index);
|
|
62
|
+
};
|
|
63
|
+
shortcutsMap.home = ({ target }) => {
|
|
64
|
+
const index = getIndex(target);
|
|
65
|
+
setValueAndSwap(min, index);
|
|
66
|
+
};
|
|
67
|
+
shortcutsMap.end = ({ target }) => {
|
|
68
|
+
const index = getIndex(target);
|
|
69
|
+
setValueAndSwap(max, index);
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
const handleMouseDown = (e) => {
|
|
75
73
|
e.stopPropagation();
|
|
76
74
|
if (disabled) {
|
|
77
75
|
return;
|
|
@@ -87,8 +85,8 @@ export const Slider = ({ defaultValue, value, min = 0, max = HUNDRED, step = 1,
|
|
|
87
85
|
}
|
|
88
86
|
setIsDragging(true);
|
|
89
87
|
previouslyDragged.current = false;
|
|
90
|
-
}
|
|
91
|
-
const handleMouseUp =
|
|
88
|
+
};
|
|
89
|
+
const handleMouseUp = useEventCallback(({ pageX }) => {
|
|
92
90
|
const nextValues = adjustValues(validValues, ref, draggedIndex, pageX, max, min, validStep);
|
|
93
91
|
if (nextValues[0] > nextValues[1]) {
|
|
94
92
|
nextValues.reverse();
|
|
@@ -97,15 +95,15 @@ export const Slider = ({ defaultValue, value, min = 0, max = HUNDRED, step = 1,
|
|
|
97
95
|
setDraggedIndex(-1);
|
|
98
96
|
setIsDragging(false);
|
|
99
97
|
previouslyDragged.current = true;
|
|
100
|
-
}
|
|
101
|
-
const handleMouseMove =
|
|
98
|
+
});
|
|
99
|
+
const handleMouseMove = useEventCallback(({ pageX }) => {
|
|
102
100
|
const nextValues = adjustValues(validValues, ref, draggedIndex, pageX, max, min, validStep);
|
|
103
101
|
if (nextValues[0] > nextValues[1]) {
|
|
104
102
|
nextValues.reverse();
|
|
105
103
|
setDraggedIndex(prevState => (prevState === 0 ? 1 : 0));
|
|
106
104
|
}
|
|
107
105
|
handleValueChange(nextValues);
|
|
108
|
-
}
|
|
106
|
+
});
|
|
109
107
|
useEffect(() => {
|
|
110
108
|
if (disabled) {
|
|
111
109
|
return undefined;
|
|
@@ -122,7 +120,7 @@ export const Slider = ({ defaultValue, value, min = 0, max = HUNDRED, step = 1,
|
|
|
122
120
|
window.removeEventListener('mousemove', handleMouseMove);
|
|
123
121
|
window.removeEventListener('mouseup', handleMouseUp);
|
|
124
122
|
};
|
|
125
|
-
}, [isDragging, handleMouseMove, handleMouseUp
|
|
123
|
+
}, [isDragging, disabled, handleMouseMove, handleMouseUp]);
|
|
126
124
|
return (<div ref={ref} role='presentation' // contains interactive elements
|
|
127
125
|
className={classNames(styles.slider, className, {
|
|
128
126
|
[styles.disabled]: disabled,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { memo
|
|
1
|
+
import { memo } from 'react';
|
|
2
2
|
import classNames from 'classnames';
|
|
3
3
|
import { Directions } from '../popup/popup.consts';
|
|
4
4
|
import PopupMenu, { ListProps } from '../popup-menu/popup-menu';
|
|
@@ -15,7 +15,7 @@ export const AnchorLink = ({ hasActiveChildren, moreClassName, moreActiveClassNa
|
|
|
15
15
|
};
|
|
16
16
|
const morePopupDirections = [Directions.BOTTOM_CENTER, Directions.BOTTOM_LEFT, Directions.BOTTOM_RIGHT];
|
|
17
17
|
export const MoreButton = memo(({ items, selected, onSelect, moreClassName, moreActiveClassName, morePopupClassName, morePopupItemClassName, morePopupBeforeEnd, }) => {
|
|
18
|
-
const onSelectHandler =
|
|
18
|
+
const onSelectHandler = onSelect
|
|
19
19
|
? (listItem) => {
|
|
20
20
|
if (listItem.disabled === true || listItem.custom === true) {
|
|
21
21
|
return;
|
|
@@ -23,37 +23,34 @@ export const MoreButton = memo(({ items, selected, onSelect, moreClassName, more
|
|
|
23
23
|
const cb = onSelect(String(listItem.key));
|
|
24
24
|
cb();
|
|
25
25
|
}
|
|
26
|
-
: undefined
|
|
27
|
-
const hasActiveChild =
|
|
28
|
-
const data =
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
26
|
+
: undefined;
|
|
27
|
+
const hasActiveChild = items.some(item => item.props.alwaysHidden && item.props.id === selected);
|
|
28
|
+
const data = getTabTitles({
|
|
29
|
+
items,
|
|
30
|
+
selected,
|
|
31
|
+
collapsed: true,
|
|
32
|
+
}).map(tab => {
|
|
33
|
+
const disabled = tab.props.disabled === true;
|
|
34
|
+
const custom = tab.props.child.type === CustomItem;
|
|
35
|
+
return {
|
|
36
|
+
template: tab,
|
|
37
|
+
key: tab.key,
|
|
38
|
+
rgItemType: ListProps.Type.CUSTOM,
|
|
39
|
+
className: morePopupItemClassName,
|
|
40
|
+
disabled,
|
|
41
|
+
custom,
|
|
42
|
+
};
|
|
43
|
+
});
|
|
44
|
+
if (morePopupBeforeEnd) {
|
|
45
|
+
data.push({
|
|
46
|
+
template: morePopupBeforeEnd,
|
|
47
|
+
key: 'before-end-content',
|
|
48
|
+
className: styles.morePopupBeforeEnd,
|
|
49
|
+
rgItemType: ListProps.Type.CUSTOM,
|
|
44
50
|
});
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
key: 'before-end-content',
|
|
49
|
-
className: styles.morePopupBeforeEnd,
|
|
50
|
-
rgItemType: ListProps.Type.CUSTOM,
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
return popupItems;
|
|
54
|
-
}, [items, morePopupBeforeEnd, morePopupItemClassName, selected]);
|
|
55
|
-
const popupAnchor = useMemo(() => (<AnchorLink moreClassName={moreClassName} moreActiveClassName={moreActiveClassName} hasActiveChildren={hasActiveChild}/>), [hasActiveChild, moreActiveClassName, moreClassName]);
|
|
56
|
-
const popup = useMemo(() => (<PopupMenu directions={morePopupDirections} className={morePopupClassName} onSelect={onSelectHandler} data={data}/>), [data, morePopupClassName, onSelectHandler]);
|
|
51
|
+
}
|
|
52
|
+
const popupAnchor = (<AnchorLink moreClassName={moreClassName} moreActiveClassName={moreActiveClassName} hasActiveChildren={hasActiveChild}/>);
|
|
53
|
+
const popup = (<PopupMenu directions={morePopupDirections} className={morePopupClassName} onSelect={onSelectHandler} data={data}/>);
|
|
57
54
|
if (items.length === 0) {
|
|
58
55
|
return null;
|
|
59
56
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useState, useRef,
|
|
1
|
+
import { useState, useRef, useCallback, useEffect, memo } from 'react';
|
|
2
2
|
import classNames from 'classnames';
|
|
3
3
|
import fastdom from 'fastdom';
|
|
4
4
|
import { FakeMoreButton, MoreButton } from './collapsible-more';
|
|
@@ -15,24 +15,22 @@ export const CollapsibleTabs = ({ children, selected, onSelect, onLastVisibleInd
|
|
|
15
15
|
hidden: [],
|
|
16
16
|
});
|
|
17
17
|
const measureRef = useRef(null);
|
|
18
|
-
const selectedIndex =
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}, [initialVisibleItems, children, preparedElements.ready, preparedElements.visible, onSelect, selected]);
|
|
35
|
-
const hiddenElements = useMemo(() => {
|
|
18
|
+
const selectedIndex = children.filter(tab => tab.props.alwaysHidden !== true).findIndex(tab => tab.props.id === selected) ?? null;
|
|
19
|
+
let items;
|
|
20
|
+
if (preparedElements.ready) {
|
|
21
|
+
items = preparedElements.visible;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
items = initialVisibleItems
|
|
25
|
+
? children.filter(item => item.props.alwaysHidden !== true).slice(0, initialVisibleItems)
|
|
26
|
+
: [];
|
|
27
|
+
}
|
|
28
|
+
const visibleElements = getTabTitles({
|
|
29
|
+
items,
|
|
30
|
+
selected,
|
|
31
|
+
onSelect,
|
|
32
|
+
});
|
|
33
|
+
const hiddenElements = (() => {
|
|
36
34
|
if (preparedElements.ready) {
|
|
37
35
|
return preparedElements.hidden;
|
|
38
36
|
}
|
|
@@ -40,7 +38,7 @@ export const CollapsibleTabs = ({ children, selected, onSelect, onLastVisibleInd
|
|
|
40
38
|
return children.filter(item => !visibleElements.some(visibleItem => visibleItem.props.child === item));
|
|
41
39
|
}
|
|
42
40
|
return [];
|
|
43
|
-
}
|
|
41
|
+
})();
|
|
44
42
|
const adjustTabs = useCallback((entry) => {
|
|
45
43
|
const containerWidth = entry.contentRect.width;
|
|
46
44
|
const { tabs: tabsSizes, more = 0 } = elements.sizes;
|
|
@@ -119,10 +117,8 @@ export const CollapsibleTabs = ({ children, selected, onSelect, onLastVisibleInd
|
|
|
119
117
|
};
|
|
120
118
|
}, [children, elements.lastVisibleIndex, preparedElements, selected, selectedIndex]);
|
|
121
119
|
// Get list of all possibly visible elements to render in a measure container
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
return getTabTitles({ items, tabIndex: -1 });
|
|
125
|
-
}, [children]);
|
|
120
|
+
const childItems = children.filter(tab => tab.props.alwaysHidden !== true);
|
|
121
|
+
const childrenToMeasure = getTabTitles({ items: childItems, tabIndex: -1 });
|
|
126
122
|
// Initial measure for tabs and more button sizes
|
|
127
123
|
useEffect(() => {
|
|
128
124
|
if (measureRef.current === null) {
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { forwardRef,
|
|
1
|
+
import { forwardRef, useImperativeHandle, useRef, useState, } from 'react';
|
|
2
2
|
import classNames from 'classnames';
|
|
3
3
|
import attachmentIcon from '@jetbrains/icons/attachment';
|
|
4
4
|
import Icon from '../icon';
|
|
5
5
|
import styles from './upload.css';
|
|
6
6
|
const defaultRenderIcon = () => <Icon className={styles.attachmentIcon} glyph={attachmentIcon}/>;
|
|
7
|
-
|
|
7
|
+
function UploadInner({ children, className, onFilesSelected, onFilesRejected, validate = () => true, variant = 'empty', multiple, renderIcon = defaultRenderIcon, accept, disabled, forwardedRef, }) {
|
|
8
8
|
const fileInputRef = useRef(null);
|
|
9
9
|
const [dragOver, setDragOver] = useState(false);
|
|
10
|
-
useImperativeHandle(
|
|
11
|
-
const handleSelectedFiles =
|
|
10
|
+
useImperativeHandle(forwardedRef, () => ({ openFilePicker: () => fileInputRef.current?.click() }), []);
|
|
11
|
+
const handleSelectedFiles = (files) => {
|
|
12
12
|
if (!files.length) {
|
|
13
13
|
return;
|
|
14
14
|
}
|
|
@@ -18,16 +18,16 @@ export const Upload = forwardRef(function Upload({ children, className, onFilesS
|
|
|
18
18
|
return;
|
|
19
19
|
}
|
|
20
20
|
onFilesSelected(files);
|
|
21
|
-
}
|
|
22
|
-
const onDragEnter =
|
|
23
|
-
const onDragOver =
|
|
24
|
-
const onDragLeave =
|
|
25
|
-
const onInputChange =
|
|
21
|
+
};
|
|
22
|
+
const onDragEnter = () => setDragOver(true);
|
|
23
|
+
const onDragOver = e => e.preventDefault();
|
|
24
|
+
const onDragLeave = () => setDragOver(false);
|
|
25
|
+
const onInputChange = () => {
|
|
26
26
|
setDragOver(false);
|
|
27
27
|
if (fileInputRef.current?.files) {
|
|
28
28
|
handleSelectedFiles(Array.from(fileInputRef.current.files));
|
|
29
29
|
}
|
|
30
|
-
}
|
|
30
|
+
};
|
|
31
31
|
return (<div className={classNames(className, styles.upload, {
|
|
32
32
|
[styles.disabled]: disabled,
|
|
33
33
|
[styles.dragOver]: dragOver,
|
|
@@ -38,5 +38,8 @@ export const Upload = forwardRef(function Upload({ children, className, onFilesS
|
|
|
38
38
|
{renderIcon()}
|
|
39
39
|
{children}
|
|
40
40
|
</div>);
|
|
41
|
+
}
|
|
42
|
+
export const Upload = forwardRef(function Upload(props, ref) {
|
|
43
|
+
return <UploadInner {...props} forwardedRef={ref}/>;
|
|
41
44
|
});
|
|
42
45
|
export default Upload;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jetbrains/ring-ui",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.81",
|
|
4
4
|
"description": "JetBrains UI library",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "JetBrains"
|
|
@@ -93,43 +93,43 @@
|
|
|
93
93
|
"@babel/eslint-parser": "^7.28.5",
|
|
94
94
|
"@csstools/css-parser-algorithms": "^3.0.4",
|
|
95
95
|
"@csstools/stylelint-no-at-nest-rule": "^4.0.0",
|
|
96
|
-
"@eslint/compat": "^
|
|
97
|
-
"@eslint/eslintrc": "^3.
|
|
96
|
+
"@eslint/compat": "^2.0.0",
|
|
97
|
+
"@eslint/eslintrc": "^3.3.3",
|
|
98
98
|
"@eslint/js": "^9.39.1",
|
|
99
|
-
"@figma/code-connect": "^1.3.
|
|
99
|
+
"@figma/code-connect": "^1.3.11",
|
|
100
100
|
"@jetbrains/eslint-config": "^6.0.5",
|
|
101
101
|
"@jetbrains/logos": "3.0.0-canary.734b213.0",
|
|
102
102
|
"@jetbrains/rollup-css-plugin": "./packages/rollup-css-plugin",
|
|
103
103
|
"@jetbrains/stylelint-config": "^4.0.2",
|
|
104
|
-
"@primer/octicons": "^19.
|
|
104
|
+
"@primer/octicons": "^19.21.0",
|
|
105
105
|
"@rollup/plugin-babel": "^6.1.0",
|
|
106
106
|
"@rollup/plugin-json": "^6.1.0",
|
|
107
107
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
108
108
|
"@rollup/plugin-replace": "^6.0.3",
|
|
109
|
-
"@storybook/addon-a11y": "10.
|
|
110
|
-
"@storybook/addon-docs": "^10.
|
|
111
|
-
"@storybook/addon-themes": "^10.
|
|
109
|
+
"@storybook/addon-a11y": "10.1.2",
|
|
110
|
+
"@storybook/addon-docs": "^10.1.2",
|
|
111
|
+
"@storybook/addon-themes": "^10.1.2",
|
|
112
112
|
"@storybook/csf": "^0.1.13",
|
|
113
|
-
"@storybook/react-webpack5": "10.
|
|
114
|
-
"@storybook/test-runner": "^0.24.
|
|
113
|
+
"@storybook/react-webpack5": "10.1.2",
|
|
114
|
+
"@storybook/test-runner": "^0.24.2",
|
|
115
115
|
"@testing-library/dom": "^10.4.1",
|
|
116
116
|
"@testing-library/react": "^16.3.0",
|
|
117
117
|
"@testing-library/user-event": "^14.6.1",
|
|
118
118
|
"@types/chai-as-promised": "^8.0.2",
|
|
119
119
|
"@types/chai-dom": "1.11.3",
|
|
120
120
|
"@types/markdown-it": "^14.1.2",
|
|
121
|
-
"@types/react": "^19.2.
|
|
122
|
-
"@types/react-dom": "^19.2.
|
|
121
|
+
"@types/react": "^19.2.7",
|
|
122
|
+
"@types/react-dom": "^19.2.3",
|
|
123
123
|
"@types/webpack-env": "^1.18.8",
|
|
124
|
-
"@vitejs/plugin-react": "^5.
|
|
125
|
-
"@vitest/eslint-plugin": "^1.
|
|
124
|
+
"@vitejs/plugin-react": "^5.1.1",
|
|
125
|
+
"@vitest/eslint-plugin": "^1.5.1",
|
|
126
126
|
"acorn": "^8.15.0",
|
|
127
127
|
"babel-plugin-require-context-hook": "^1.0.0",
|
|
128
|
-
"caniuse-lite": "^1.0.
|
|
128
|
+
"caniuse-lite": "^1.0.30001757",
|
|
129
129
|
"chai-as-promised": "^8.0.2",
|
|
130
130
|
"chai-dom": "^1.12.1",
|
|
131
131
|
"cheerio": "^1.1.2",
|
|
132
|
-
"core-js": "^3.
|
|
132
|
+
"core-js": "^3.47.0",
|
|
133
133
|
"cpy-cli": "^6.0.0",
|
|
134
134
|
"dotenv-cli": "^11.0.0",
|
|
135
135
|
"eslint": "^9.39.1",
|
|
@@ -142,42 +142,42 @@
|
|
|
142
142
|
"eslint-plugin-prettier": "^5.5.4",
|
|
143
143
|
"eslint-plugin-react": "^7.37.5",
|
|
144
144
|
"eslint-plugin-react-hooks": "^7.0.1",
|
|
145
|
-
"eslint-plugin-storybook": "^10.
|
|
145
|
+
"eslint-plugin-storybook": "^10.1.2",
|
|
146
146
|
"eslint-plugin-unicorn": "^62.0.0",
|
|
147
147
|
"events": "^3.3.0",
|
|
148
|
-
"glob": "^
|
|
148
|
+
"glob": "^13.0.0",
|
|
149
149
|
"globals": "^16.5.0",
|
|
150
|
-
"html-webpack-plugin": "^5.6.
|
|
150
|
+
"html-webpack-plugin": "^5.6.5",
|
|
151
151
|
"http-server": "^14.1.1",
|
|
152
152
|
"husky": "^9.1.7",
|
|
153
153
|
"identity-obj-proxy": "^3.0.0",
|
|
154
154
|
"jest": "~30.2.0",
|
|
155
155
|
"jest-environment-jsdom": "^30.2.0",
|
|
156
156
|
"jest-teamcity": "^1.12.0",
|
|
157
|
-
"lint-staged": "^16.2.
|
|
157
|
+
"lint-staged": "^16.2.7",
|
|
158
158
|
"markdown-it": "^14.1.0",
|
|
159
159
|
"merge-options": "^3.0.4",
|
|
160
160
|
"pinst": "^3.0.0",
|
|
161
|
-
"prettier": "^3.
|
|
161
|
+
"prettier": "^3.7.3",
|
|
162
162
|
"raw-loader": "^4.0.2",
|
|
163
163
|
"react": "^19.2.0",
|
|
164
164
|
"react-dom": "^19.2.0",
|
|
165
165
|
"regenerator-runtime": "^0.14.1",
|
|
166
|
-
"rimraf": "^6.1.
|
|
167
|
-
"rollup": "^4.53.
|
|
166
|
+
"rimraf": "^6.1.2",
|
|
167
|
+
"rollup": "^4.53.3",
|
|
168
168
|
"rollup-plugin-clear": "^2.0.7",
|
|
169
169
|
"storage-mock": "^2.1.0",
|
|
170
|
-
"storybook": "10.
|
|
171
|
-
"stylelint": "^16.
|
|
170
|
+
"storybook": "10.1.2",
|
|
171
|
+
"stylelint": "^16.26.1",
|
|
172
172
|
"stylelint-config-sass-guidelines": "^12.1.0",
|
|
173
173
|
"svg-inline-loader": "^0.8.2",
|
|
174
174
|
"teamcity-service-messages": "^0.1.14",
|
|
175
175
|
"terser-webpack-plugin": "^5.3.14",
|
|
176
176
|
"typescript": "~5.9.3",
|
|
177
|
-
"typescript-eslint": "^8.
|
|
178
|
-
"vitest": "^
|
|
179
|
-
"vitest-teamcity-reporter": "^0.
|
|
180
|
-
"webpack": "^5.
|
|
177
|
+
"typescript-eslint": "^8.48.0",
|
|
178
|
+
"vitest": "^4.0.14",
|
|
179
|
+
"vitest-teamcity-reporter": "^0.4.1",
|
|
180
|
+
"webpack": "^5.103.0",
|
|
181
181
|
"webpack-cli": "^6.0.1"
|
|
182
182
|
},
|
|
183
183
|
"peerDependencies": {
|
|
@@ -212,12 +212,12 @@
|
|
|
212
212
|
"babel-loader": "10.0.0",
|
|
213
213
|
"babel-plugin-react-compiler": "^1.0.0",
|
|
214
214
|
"babel-plugin-transform-define": "^2.1.4",
|
|
215
|
-
"browserslist": "^4.
|
|
215
|
+
"browserslist": "^4.28.0",
|
|
216
216
|
"change-case": "^4.1.1",
|
|
217
217
|
"classnames": "^2.5.1",
|
|
218
218
|
"combokeys": "^3.0.1",
|
|
219
219
|
"css-loader": "^7.1.2",
|
|
220
|
-
"csstype": "^3.1
|
|
220
|
+
"csstype": "^3.2.1",
|
|
221
221
|
"date-fns": "^4.1.0",
|
|
222
222
|
"dequal": "^2.0.3",
|
|
223
223
|
"element-resize-detector": "^1.2.4",
|
|
@@ -240,7 +240,7 @@
|
|
|
240
240
|
"react-waypoint": "^10.3.0",
|
|
241
241
|
"scrollbar-width": "^3.1.1",
|
|
242
242
|
"simply-uuid": "^1.0.1",
|
|
243
|
-
"sniffr": "^1.
|
|
243
|
+
"sniffr": "^1.4.0",
|
|
244
244
|
"style-inject": "^0.3.0",
|
|
245
245
|
"style-loader": "~4.0.0",
|
|
246
246
|
"url-loader": "^4.1.1",
|