@jetbrains/ring-ui 7.0.60 → 7.0.61
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/button/button.d.ts +1 -1
- package/components/button/button.js +1 -1
- package/components/global/configuration.d.ts +11 -0
- package/components/global/configuration.js +21 -0
- package/components/global/controls-height.d.ts +4 -7
- package/components/global/controls-height.js +8 -12
- package/components/input/input.d.ts +3 -2
- package/components/input/input.js +1 -1
- package/components/popup/popup.css +74 -0
- package/components/popup/popup.d.ts +2 -0
- package/components/popup/popup.js +52 -21
- package/components/popup/position-css.d.ts +14 -0
- package/components/popup/position-css.js +75 -0
- package/components/popup/position.d.ts +1 -0
- package/components/popup/position.js +12 -5
- package/components/select/select.d.ts +3 -2
- package/components/select/select.js +1 -1
- package/components/tags-input/tags-input.d.ts +3 -2
- package/components/tags-input/tags-input.js +1 -1
- package/package.json +21 -23
|
@@ -51,7 +51,7 @@ export declare class Button extends PureComponent<ButtonProps> {
|
|
|
51
51
|
* @deprecated Use icons with appropriate intrinsic sizes instead
|
|
52
52
|
*/
|
|
53
53
|
static IconSize: typeof Size;
|
|
54
|
-
static contextType: React.Context<ControlsHeight>;
|
|
54
|
+
static contextType: React.Context<ControlsHeight | (() => ControlsHeight)>;
|
|
55
55
|
context: React.ContextType<typeof ControlsHeightContext>;
|
|
56
56
|
buttonRef: React.RefObject<HTMLButtonElement | null>;
|
|
57
57
|
render(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -40,7 +40,7 @@ export class Button extends PureComponent {
|
|
|
40
40
|
const classes = getButtonClasses({
|
|
41
41
|
...this.props,
|
|
42
42
|
inline: isInline,
|
|
43
|
-
height: height ?? this.context,
|
|
43
|
+
height: height ?? (typeof this.context === 'function' ? this.context() : this.context),
|
|
44
44
|
});
|
|
45
45
|
const content = (_jsxs(_Fragment, { children: [icon && (_jsx(Icon, { className: classNames(styles.icon, iconClassName), glyph: icon, size: iconSize, suppressSizeWarning: iconSuppressSizeWarning })), children, iconRight && _jsx(Icon, { className: classNames(styles.iconRight, iconRightClassName), glyph: iconRight }), dropdown && _jsx(Icon, { glyph: isInline ? chevron12pxDown : chevronDown, className: styles.dropdownIcon })] }));
|
|
46
46
|
const isDisabled = disabled || loader || undefined;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare enum ControlsHeight {
|
|
2
|
+
S = "S",
|
|
3
|
+
M = "M",
|
|
4
|
+
L = "L"
|
|
5
|
+
}
|
|
6
|
+
export interface RingUIConfiguration {
|
|
7
|
+
controlsHeight?: ControlsHeight;
|
|
8
|
+
popupsCssPositioning?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function configure(config: RingUIConfiguration): void;
|
|
11
|
+
export declare function getConfiguration(): Required<RingUIConfiguration>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export var ControlsHeight;
|
|
2
|
+
(function (ControlsHeight) {
|
|
3
|
+
ControlsHeight["S"] = "S";
|
|
4
|
+
ControlsHeight["M"] = "M";
|
|
5
|
+
ControlsHeight["L"] = "L";
|
|
6
|
+
})(ControlsHeight || (ControlsHeight = {}));
|
|
7
|
+
const globalConfiguration = {
|
|
8
|
+
controlsHeight: ControlsHeight.M,
|
|
9
|
+
popupsCssPositioning: true,
|
|
10
|
+
};
|
|
11
|
+
export function configure(config) {
|
|
12
|
+
if (config.controlsHeight !== undefined) {
|
|
13
|
+
globalConfiguration.controlsHeight = config.controlsHeight;
|
|
14
|
+
}
|
|
15
|
+
if (config.popupsCssPositioning !== undefined) {
|
|
16
|
+
globalConfiguration.popupsCssPositioning = config.popupsCssPositioning;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export function getConfiguration() {
|
|
20
|
+
return { ...globalConfiguration };
|
|
21
|
+
}
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
L = "L"
|
|
5
|
-
}
|
|
6
|
-
export declare const ControlsHeightContext: import("react").Context<ControlsHeight>;
|
|
7
|
-
export declare function configureGlobalControlsHeight(value: ControlsHeight): void;
|
|
1
|
+
import { ControlsHeight } from './configuration';
|
|
2
|
+
export { ControlsHeight } from './configuration';
|
|
3
|
+
export declare const configureGlobalControlsHeight: (value: ControlsHeight) => void;
|
|
8
4
|
export declare function getGlobalControlsHeight(): ControlsHeight;
|
|
5
|
+
export declare const ControlsHeightContext: import("react").Context<ControlsHeight | (() => ControlsHeight)>;
|
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
import { createContext } from 'react';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
ControlsHeight["M"] = "M";
|
|
6
|
-
ControlsHeight["L"] = "L";
|
|
7
|
-
})(ControlsHeight || (ControlsHeight = {}));
|
|
8
|
-
export const ControlsHeightContext = createContext(ControlsHeight.M);
|
|
9
|
-
let globalControlsHeight = ControlsHeight.M;
|
|
2
|
+
import deprecate from 'util-deprecate';
|
|
3
|
+
import { configure, ControlsHeight, getConfiguration } from './configuration';
|
|
4
|
+
export { ControlsHeight } from './configuration';
|
|
10
5
|
// This can be used if React Context is not applicable, for example for alertService or Auth dialog
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
}
|
|
6
|
+
export const configureGlobalControlsHeight = deprecate((value) => {
|
|
7
|
+
configure({ controlsHeight: value });
|
|
8
|
+
}, 'Ring UI: configureGlobalControlsHeight() is deprecated, use configure() instead');
|
|
14
9
|
export function getGlobalControlsHeight() {
|
|
15
|
-
return
|
|
10
|
+
return getConfiguration().controlsHeight ?? ControlsHeight.M;
|
|
16
11
|
}
|
|
12
|
+
export const ControlsHeightContext = createContext(getGlobalControlsHeight);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PureComponent, Ref, ComponentType, InputHTMLAttributes, TextareaHTMLAttributes, ReactNode } from 'react';
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import { ControlsHeight } from '../global/controls-height';
|
|
3
|
+
import { ControlsHeight, ControlsHeightContext } from '../global/controls-height';
|
|
4
4
|
import { LabelType } from '../control-label/control-label';
|
|
5
5
|
declare function noop(): void;
|
|
6
6
|
/**
|
|
@@ -58,7 +58,8 @@ export declare class Input extends PureComponent<InputProps> {
|
|
|
58
58
|
componentDidMount(): void;
|
|
59
59
|
componentDidUpdate(): void;
|
|
60
60
|
componentWillUnmount(): void;
|
|
61
|
-
static contextType: React.Context<ControlsHeight>;
|
|
61
|
+
static contextType: React.Context<ControlsHeight | (() => ControlsHeight)>;
|
|
62
|
+
context: React.ContextType<typeof ControlsHeightContext>;
|
|
62
63
|
frame?: number;
|
|
63
64
|
input?: HTMLInputElement | HTMLTextAreaElement | null;
|
|
64
65
|
id: string;
|
|
@@ -97,7 +97,7 @@ export class Input extends PureComponent {
|
|
|
97
97
|
// Modifiers
|
|
98
98
|
size, multiline, borderless,
|
|
99
99
|
// Props
|
|
100
|
-
label, labelType, error, help, className, inputClassName, children, value, onClear, disabled, inputRef, onChange, enableShortcuts, id, placeholder, icon, translations, height = this.context, beforeInput, afterInput, autogrow, ...restProps } = this.props;
|
|
100
|
+
label, labelType, error, help, className, inputClassName, children, value, onClear, disabled, inputRef, onChange, enableShortcuts, id, placeholder, icon, translations, height = typeof this.context === 'function' ? this.context() : this.context, beforeInput, afterInput, autogrow, ...restProps } = this.props;
|
|
101
101
|
const { empty } = this.state;
|
|
102
102
|
const clearable = !!onClear;
|
|
103
103
|
const classes = classNames(className, styles.outerContainer, [styles[`size${size}`]], [styles[`height${height}`]], {
|
|
@@ -19,6 +19,80 @@
|
|
|
19
19
|
box-shadow: var(--ring-popup-shadow);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
:root {
|
|
23
|
+
--ring-popup-offset: 8px;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.cssAnchoredPopup {
|
|
27
|
+
--ring-popup-offset: 0;
|
|
28
|
+
|
|
29
|
+
top: unset;
|
|
30
|
+
left: unset;
|
|
31
|
+
|
|
32
|
+
margin: 0
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@position-try --bottom-right {
|
|
36
|
+
position-area: block-end span-inline-end;
|
|
37
|
+
margin-block-start: var(--ring-popup-offset);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
@position-try --bottom-left {
|
|
41
|
+
position-area: block-end span-inline-start;
|
|
42
|
+
margin-block-start: var(--ring-popup-offset);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@position-try --bottom-center {
|
|
46
|
+
position-area: block-end center;
|
|
47
|
+
margin-block-start: var(--ring-popup-offset);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@position-try --top-center {
|
|
51
|
+
position-area: block-start center;
|
|
52
|
+
margin-block-end: var(--ring-popup-offset);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@position-try --top-right {
|
|
56
|
+
position-area: block-start span-inline-end;
|
|
57
|
+
margin-block-end: var(--ring-popup-offset);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
@position-try --top-left {
|
|
61
|
+
position-area: block-start span-inline-start;
|
|
62
|
+
margin-block-end: var(--ring-popup-offset);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@position-try --right-center {
|
|
66
|
+
position-area: center inline-end;
|
|
67
|
+
margin-inline-start: var(--ring-popup-offset);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@position-try --right-top {
|
|
71
|
+
position-area: span-block-start inline-end;
|
|
72
|
+
margin-inline-start: var(--ring-popup-offset);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@position-try --right-bottom {
|
|
76
|
+
position-area: span-block-end inline-end;
|
|
77
|
+
margin-inline-start: var(--ring-popup-offset);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@position-try --left-center {
|
|
81
|
+
position-area: center inline-start;
|
|
82
|
+
margin-inline-end: var(--ring-popup-offset);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@position-try --left-top {
|
|
86
|
+
position-area: span-block-start inline-start;
|
|
87
|
+
margin-inline-end: var(--ring-popup-offset);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@position-try --left-bottom {
|
|
91
|
+
position-area: span-block-end inline-start;
|
|
92
|
+
margin-inline-end: var(--ring-popup-offset);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
22
96
|
.largeBorderRadius {
|
|
23
97
|
border-radius: var(--ring-border-radius-large);
|
|
24
98
|
}
|
|
@@ -32,6 +32,7 @@ export interface BasePopupProps {
|
|
|
32
32
|
withTail?: boolean;
|
|
33
33
|
tailOffset?: number;
|
|
34
34
|
largeBorderRadius?: boolean;
|
|
35
|
+
cssPositioning?: boolean;
|
|
35
36
|
anchorElement?: HTMLElement | null | undefined;
|
|
36
37
|
target?: string | Element | null | undefined;
|
|
37
38
|
className?: string | null | undefined;
|
|
@@ -117,6 +118,7 @@ export default class Popup<P extends BasePopupProps = PopupProps> extends PureCo
|
|
|
117
118
|
direction: Directions | null;
|
|
118
119
|
};
|
|
119
120
|
private _updateDirection;
|
|
121
|
+
private shouldUseCssPositioning;
|
|
120
122
|
private _updatePosition;
|
|
121
123
|
private _redraw;
|
|
122
124
|
private _getAnchor;
|
|
@@ -11,10 +11,12 @@ import { Listeners, getStyles } from '../global/dom';
|
|
|
11
11
|
import Shortcuts from '../shortcuts/shortcuts';
|
|
12
12
|
import dataTests from '../global/data-tests';
|
|
13
13
|
import TabTrap from '../tab-trap/tab-trap';
|
|
14
|
+
import { getConfiguration } from '../global/configuration';
|
|
14
15
|
import position from './position';
|
|
15
16
|
import styles from './popup.css';
|
|
16
17
|
import { DEFAULT_DIRECTIONS, Dimension, Directions, Display, MaxHeight, MinWidth } from './popup.consts';
|
|
17
18
|
import { PopupTargetContext, PopupTarget } from './popup.target';
|
|
19
|
+
import { setCSSAnchorPositioning, supportsCSSAnchorPositioning } from './position-css';
|
|
18
20
|
export { PopupTargetContext, PopupTarget };
|
|
19
21
|
const isPossibleClientSideNavigation = (event) => {
|
|
20
22
|
const target = event.target;
|
|
@@ -158,23 +160,47 @@ export default class Popup extends PureComponent {
|
|
|
158
160
|
}
|
|
159
161
|
}
|
|
160
162
|
};
|
|
163
|
+
shouldUseCssPositioning() {
|
|
164
|
+
if (!supportsCSSAnchorPositioning()) {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
return this.props.cssPositioning !== undefined
|
|
168
|
+
? this.props.cssPositioning
|
|
169
|
+
: getConfiguration().popupsCssPositioning;
|
|
170
|
+
}
|
|
161
171
|
_updatePosition = () => {
|
|
162
172
|
const popup = this.popup;
|
|
173
|
+
const anchor = this._getAnchor();
|
|
163
174
|
if (popup) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
+
if (this.shouldUseCssPositioning() && anchor) {
|
|
176
|
+
// Use CSS Anchor positioning
|
|
177
|
+
setCSSAnchorPositioning({
|
|
178
|
+
popup,
|
|
179
|
+
anchor,
|
|
180
|
+
uid: this.uid,
|
|
181
|
+
minWidth: this.props.minWidth,
|
|
182
|
+
top: this.props.top,
|
|
183
|
+
left: this.props.left,
|
|
184
|
+
directions: this.props.directions,
|
|
185
|
+
offset: this.props.offset,
|
|
175
186
|
});
|
|
176
|
-
|
|
177
|
-
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
popup.style.position = 'absolute';
|
|
190
|
+
if (this.isVisible()) {
|
|
191
|
+
const { styles: style, direction } = this.position();
|
|
192
|
+
Object.entries(style).forEach(([key, value]) => {
|
|
193
|
+
const propKey = key;
|
|
194
|
+
if (typeof value === 'number') {
|
|
195
|
+
popup.style[propKey] = `${value}px`;
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
popup.style[propKey] = value.toString();
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
if (direction != null) {
|
|
202
|
+
this._updateDirection(direction);
|
|
203
|
+
}
|
|
178
204
|
}
|
|
179
205
|
}
|
|
180
206
|
this.setState(this.calculateDisplay);
|
|
@@ -199,16 +225,20 @@ export default class Popup extends PureComponent {
|
|
|
199
225
|
clearTimeout(this._prevTimeout);
|
|
200
226
|
this._prevTimeout = window.setTimeout(() => {
|
|
201
227
|
this._listenersEnabled = true;
|
|
202
|
-
|
|
203
|
-
if
|
|
204
|
-
|
|
228
|
+
// CSS positioning doesn't need resize/scroll listeners as it's handled by CSS
|
|
229
|
+
// But we need them if CSS positioning isn't supported
|
|
230
|
+
if (!this.shouldUseCssPositioning()) {
|
|
231
|
+
this.listeners.add(window, 'resize', this._redraw);
|
|
232
|
+
if (this.props.autoPositioningOnScroll) {
|
|
233
|
+
this.listeners.add(window, 'scroll', this._redraw);
|
|
234
|
+
}
|
|
235
|
+
let el = this._getAnchor();
|
|
236
|
+
while (el) {
|
|
237
|
+
this.listeners.add(el, 'scroll', this._redraw);
|
|
238
|
+
el = el.parentElement;
|
|
239
|
+
}
|
|
205
240
|
}
|
|
206
241
|
this.listeners.add(document, 'pointerdown', this._onDocumentClick, true);
|
|
207
|
-
let el = this._getAnchor();
|
|
208
|
-
while (el) {
|
|
209
|
-
this.listeners.add(el, 'scroll', this._redraw);
|
|
210
|
-
el = el.parentElement;
|
|
211
|
-
}
|
|
212
242
|
}, 0);
|
|
213
243
|
return;
|
|
214
244
|
}
|
|
@@ -259,6 +289,7 @@ export default class Popup extends PureComponent {
|
|
|
259
289
|
const { className, style, hidden, attached, keepMounted, client, onMouseDown, onMouseUp, onMouseOver, onMouseOut, onContextMenu, 'data-test': dataTest, largeBorderRadius, } = this.props;
|
|
260
290
|
const showing = this.state.display === Display.SHOWING;
|
|
261
291
|
const classes = classNames(className, styles.popup, {
|
|
292
|
+
[styles.cssAnchoredPopup]: this.shouldUseCssPositioning(),
|
|
262
293
|
[styles.attached]: attached,
|
|
263
294
|
[styles.hidden]: hidden,
|
|
264
295
|
[styles.showing]: showing,
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Directions } from './popup.consts';
|
|
2
|
+
export declare const supportsCSSAnchorPositioning: () => boolean;
|
|
3
|
+
interface SetCSSAnchorPositioningParams {
|
|
4
|
+
popup: HTMLElement;
|
|
5
|
+
anchor: HTMLElement;
|
|
6
|
+
uid: string;
|
|
7
|
+
minWidth?: number | 'target' | null;
|
|
8
|
+
top?: number;
|
|
9
|
+
left?: number;
|
|
10
|
+
directions: readonly Directions[];
|
|
11
|
+
offset?: number;
|
|
12
|
+
}
|
|
13
|
+
export declare const setCSSAnchorPositioning: ({ popup, anchor, uid, minWidth, top, left, directions, offset, }: SetCSSAnchorPositioningParams) => void;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { getRect } from '../global/dom';
|
|
2
|
+
import { calculateMinWidth } from './position';
|
|
3
|
+
import { Directions } from './popup.consts';
|
|
4
|
+
export const supportsCSSAnchorPositioning = () => {
|
|
5
|
+
return CSS?.supports?.('anchor-name', 'none');
|
|
6
|
+
};
|
|
7
|
+
const getPositionArea = (direction) => {
|
|
8
|
+
switch (direction) {
|
|
9
|
+
case Directions.BOTTOM_RIGHT:
|
|
10
|
+
return ['block-end span-inline-end', '--bottom-right'];
|
|
11
|
+
case Directions.BOTTOM_LEFT:
|
|
12
|
+
return ['block-end span-inline-start', '--bottom-left'];
|
|
13
|
+
case Directions.BOTTOM_CENTER:
|
|
14
|
+
return ['block-end center', '--bottom-center'];
|
|
15
|
+
case Directions.TOP_CENTER:
|
|
16
|
+
return ['block-start center', '--top-center'];
|
|
17
|
+
case Directions.TOP_RIGHT:
|
|
18
|
+
return ['block-start span-inline-end', '--top-right'];
|
|
19
|
+
case Directions.TOP_LEFT:
|
|
20
|
+
return ['block-start span-inline-start', '--top-left'];
|
|
21
|
+
case Directions.RIGHT_CENTER:
|
|
22
|
+
return ['center inline-end', '--right-center'];
|
|
23
|
+
case Directions.RIGHT_TOP:
|
|
24
|
+
return ['span-block-start inline-end', '--right-top'];
|
|
25
|
+
case Directions.RIGHT_BOTTOM:
|
|
26
|
+
return ['span-block-end inline-end', '--right-bottom'];
|
|
27
|
+
case Directions.LEFT_CENTER:
|
|
28
|
+
return ['center inline-start', '--left-center'];
|
|
29
|
+
case Directions.LEFT_TOP:
|
|
30
|
+
return ['span-block-start inline-start', '--left-top'];
|
|
31
|
+
case Directions.LEFT_BOTTOM:
|
|
32
|
+
return ['span-block-end inline-start', '--left-bottom'];
|
|
33
|
+
default:
|
|
34
|
+
return ['block-end span-inline-end', '--bottom-right'];
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const getPositionFallbacks = (directions) => {
|
|
38
|
+
return directions
|
|
39
|
+
.slice(1)
|
|
40
|
+
.map(direction => getPositionArea(direction)[1])
|
|
41
|
+
.join(', ');
|
|
42
|
+
};
|
|
43
|
+
export const setCSSAnchorPositioning = ({ popup, anchor, uid, minWidth, top, left, directions, offset, }) => {
|
|
44
|
+
const anchorName = anchor.style.getPropertyValue('anchor-name') || `--anchor-${uid}`;
|
|
45
|
+
if (!anchor.style.getPropertyValue('anchor-name')) {
|
|
46
|
+
anchor.style.setProperty('anchor-name', anchorName);
|
|
47
|
+
}
|
|
48
|
+
popup.style.setProperty('position-anchor', anchorName);
|
|
49
|
+
const calculatedMinWidth = calculateMinWidth(getRect(anchor).width, minWidth);
|
|
50
|
+
if (calculatedMinWidth !== null) {
|
|
51
|
+
popup.style.minWidth = `${calculatedMinWidth}px`;
|
|
52
|
+
}
|
|
53
|
+
if (top) {
|
|
54
|
+
popup.style.transform = `translateY(${top}px)`;
|
|
55
|
+
}
|
|
56
|
+
if (left) {
|
|
57
|
+
popup.style.left = `${left}px`;
|
|
58
|
+
}
|
|
59
|
+
const [initialPositionStyle, initialPositionName] = getPositionArea(directions[0]);
|
|
60
|
+
popup.style.setProperty('position-area', initialPositionStyle);
|
|
61
|
+
if (offset) {
|
|
62
|
+
popup.style.setProperty('--ring-popup-offset', `${offset}px`);
|
|
63
|
+
if (initialPositionName.startsWith('--bottom') || initialPositionName.startsWith('--top')) {
|
|
64
|
+
popup.style.margin = `${offset}px 0`;
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
popup.style.margin = `0 ${offset}px`;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// Add fallbacks for better positioning if there are multiple directions
|
|
71
|
+
const fallbacks = getPositionFallbacks(directions);
|
|
72
|
+
if (fallbacks) {
|
|
73
|
+
popup.style.setProperty('position-try-fallbacks', fallbacks);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
@@ -24,6 +24,7 @@ export interface PositionAttrs {
|
|
|
24
24
|
}
|
|
25
25
|
export declare const positionPropKeys: readonly ["directions", "autoPositioning", "autoCorrectTopOverflow", "sidePadding", "top", "left", "offset", "maxHeight", "minWidth"];
|
|
26
26
|
export declare function maxHeightForDirection(direction: Directions, anchorNode: Element, containerNode?: Element | null): number | null;
|
|
27
|
+
export declare function calculateMinWidth(anchorWidth: number, minWidth: PositionAttrs['minWidth']): number | null;
|
|
27
28
|
export default function position(attrs: PositionAttrs): {
|
|
28
29
|
styles: PositionStyles;
|
|
29
30
|
direction: Directions | null;
|
|
@@ -126,6 +126,15 @@ export function maxHeightForDirection(direction, anchorNode, containerNode) {
|
|
|
126
126
|
return null;
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
|
+
export function calculateMinWidth(anchorWidth, minWidth) {
|
|
130
|
+
if (minWidth === MinWidth.TARGET || minWidth === 'target') {
|
|
131
|
+
return anchorWidth;
|
|
132
|
+
}
|
|
133
|
+
else if (minWidth) {
|
|
134
|
+
return anchorWidth < minWidth ? minWidth : anchorWidth;
|
|
135
|
+
}
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
129
138
|
export default function position(attrs) {
|
|
130
139
|
const { popup, anchor, container, directions, autoPositioning, sidePadding, top, left, offset, maxHeight, minWidth, autoCorrectTopOverflow = true, } = attrs;
|
|
131
140
|
let styles = {
|
|
@@ -185,11 +194,9 @@ export default function position(attrs) {
|
|
|
185
194
|
scroll,
|
|
186
195
|
});
|
|
187
196
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
else if (minWidth) {
|
|
192
|
-
styles.minWidth = anchorRect.width < minWidth ? minWidth : anchorRect.width;
|
|
197
|
+
const newMinWidth = calculateMinWidth(anchorRect.width, minWidth);
|
|
198
|
+
if (newMinWidth !== null) {
|
|
199
|
+
styles.minWidth = newMinWidth;
|
|
193
200
|
}
|
|
194
201
|
return { styles, direction: chosenDirection };
|
|
195
202
|
}
|
|
@@ -5,7 +5,7 @@ import { Size } from '../input/input';
|
|
|
5
5
|
import { LabelType } from '../control-label/control-label';
|
|
6
6
|
import { ListDataItem } from '../list/consts';
|
|
7
7
|
import { Directions } from '../popup/popup.consts';
|
|
8
|
-
import { ControlsHeight } from '../global/controls-height';
|
|
8
|
+
import { ControlsHeight, ControlsHeightContext } from '../global/controls-height';
|
|
9
9
|
import SelectPopup, { Filter, FilterFn, Multiple, Tags } from './select__popup';
|
|
10
10
|
/**
|
|
11
11
|
* @name Select
|
|
@@ -206,7 +206,8 @@ export default class Select<T = unknown> extends Component<SelectProps<T>, Selec
|
|
|
206
206
|
static getDerivedStateFromProps<T = unknown>(nextProps: SelectProps<T>, prevState: SelectState<T>): Partial<SelectState<T>>;
|
|
207
207
|
state: SelectState<T>;
|
|
208
208
|
componentDidUpdate(prevProps: SelectProps<T>, prevState: SelectState<T>): void;
|
|
209
|
-
static contextType: React.Context<ControlsHeight>;
|
|
209
|
+
static contextType: React.Context<ControlsHeight | (() => ControlsHeight)>;
|
|
210
|
+
context: React.ContextType<typeof ControlsHeightContext>;
|
|
210
211
|
static Type: typeof Type;
|
|
211
212
|
static Size: typeof Size;
|
|
212
213
|
id: string;
|
|
@@ -737,7 +737,7 @@ export default class Select extends Component {
|
|
|
737
737
|
const { selected } = this.state;
|
|
738
738
|
const { disabled, clear, hideArrow } = this.props;
|
|
739
739
|
const icons = [];
|
|
740
|
-
const height = this.props.height || this.context;
|
|
740
|
+
const height = this.props.height || (typeof this.context === 'function' ? this.context() : this.context);
|
|
741
741
|
if (!Array.isArray(selected) && selected?.icon) {
|
|
742
742
|
icons.push(_jsx("button", { title: "Toggle options popup", type: "button", className: styles.selectedIcon, disabled: this.props.disabled, onClick: this._clickHandler, style: { backgroundImage: `url(${selected.icon})` } }, "selected"));
|
|
743
743
|
}
|
|
@@ -4,7 +4,7 @@ import Select, { SelectItem } from '../select/select';
|
|
|
4
4
|
import { TagType } from '../tags-list/tags-list';
|
|
5
5
|
import Caret from '../caret/caret';
|
|
6
6
|
import { Size } from '../input/input';
|
|
7
|
-
import { ControlsHeight } from '../global/controls-height';
|
|
7
|
+
import { ControlsHeight, ControlsHeightContext } from '../global/controls-height';
|
|
8
8
|
import { Filter } from '../select/select__popup';
|
|
9
9
|
import { TagAttrs } from '../tag/tag';
|
|
10
10
|
import { LabelType } from '../control-label/control-label';
|
|
@@ -82,7 +82,8 @@ export default class TagsInput extends PureComponent<TagsInputProps, TagsInputSt
|
|
|
82
82
|
componentDidMount(): void;
|
|
83
83
|
static ngModelStateField: string;
|
|
84
84
|
ngModelStateField: string;
|
|
85
|
-
static contextType: React.Context<ControlsHeight>;
|
|
85
|
+
static contextType: React.Context<ControlsHeight | (() => ControlsHeight)>;
|
|
86
|
+
context: React.ContextType<typeof ControlsHeightContext>;
|
|
86
87
|
id: string;
|
|
87
88
|
node?: HTMLElement | null;
|
|
88
89
|
nodeRef: (node: HTMLElement | null) => void;
|
|
@@ -221,7 +221,7 @@ export default class TagsInput extends PureComponent {
|
|
|
221
221
|
};
|
|
222
222
|
render() {
|
|
223
223
|
const { focused, tags, activeIndex } = this.state;
|
|
224
|
-
const { disabled, canNotBeEmpty, allowAddNewTags, filter, size, labelType, height = this.context, label, } = this.props;
|
|
224
|
+
const { disabled, canNotBeEmpty, allowAddNewTags, filter, size, labelType, height = typeof this.context === 'function' ? this.context() : this.context, label, } = this.props;
|
|
225
225
|
const classes = classNames(styles.tagsInput, [inputStyles[`size${size}`]], [inputStyles[`height${height}`]], {
|
|
226
226
|
[styles.tagsInputDisabled]: disabled,
|
|
227
227
|
[styles.tagsInputFocused]: focused,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jetbrains/ring-ui",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.61",
|
|
4
4
|
"description": "JetBrains UI library",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "JetBrains"
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"prepare": "webpack -c .storybook/custom-header/webpack.config.js",
|
|
70
70
|
"prepublishOnly": "pinst --disable",
|
|
71
71
|
"prerelease-built-ci": "node scripts/prepare-built-package.js",
|
|
72
|
-
"prerelease-ci": "git pull
|
|
72
|
+
"prerelease-ci": "git pull",
|
|
73
73
|
"pretest-ci": "npm run lint-ci",
|
|
74
74
|
"release-built-ci": "npm publish --access=public $NPM_PUBLISH_PARAMS",
|
|
75
75
|
"release-ci": "npm version $NPM_VERSION_PARAMS && npm publish --access=public $NPM_PUBLISH_PARAMS",
|
|
@@ -96,52 +96,50 @@
|
|
|
96
96
|
"readmeFilename": "README.md",
|
|
97
97
|
"devDependencies": {
|
|
98
98
|
"@babel/cli": "^7.28.3",
|
|
99
|
-
"@babel/eslint-parser": "^7.28.
|
|
99
|
+
"@babel/eslint-parser": "^7.28.4",
|
|
100
100
|
"@csstools/css-parser-algorithms": "^3.0.4",
|
|
101
101
|
"@csstools/stylelint-no-at-nest-rule": "^4.0.0",
|
|
102
102
|
"@eslint/compat": "^1.3.2",
|
|
103
103
|
"@eslint/eslintrc": "^3.2.0",
|
|
104
|
-
"@eslint/js": "^9.
|
|
105
|
-
"@figma/code-connect": "^1.3.
|
|
104
|
+
"@eslint/js": "^9.35.0",
|
|
105
|
+
"@figma/code-connect": "^1.3.5",
|
|
106
106
|
"@jetbrains/eslint-config": "^6.0.5",
|
|
107
107
|
"@jetbrains/logos": "3.0.0-canary.734b213.0",
|
|
108
108
|
"@jetbrains/rollup-css-plugin": "./packages/rollup-css-plugin",
|
|
109
109
|
"@jetbrains/stylelint-config": "^4.0.2",
|
|
110
|
-
"@primer/octicons": "^19.
|
|
110
|
+
"@primer/octicons": "^19.17.0",
|
|
111
111
|
"@rollup/plugin-babel": "^6.0.4",
|
|
112
112
|
"@rollup/plugin-json": "^6.1.0",
|
|
113
113
|
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
114
114
|
"@rollup/plugin-replace": "^6.0.2",
|
|
115
|
-
"@storybook/addon-a11y": "9.1.
|
|
116
|
-
"@storybook/addon-docs": "^9.1.
|
|
117
|
-
"@storybook/addon-themes": "^9.1.
|
|
115
|
+
"@storybook/addon-a11y": "9.1.5",
|
|
116
|
+
"@storybook/addon-docs": "^9.1.5",
|
|
117
|
+
"@storybook/addon-themes": "^9.1.5",
|
|
118
118
|
"@storybook/csf": "^0.1.13",
|
|
119
|
-
"@storybook/react-webpack5": "9.1.
|
|
119
|
+
"@storybook/react-webpack5": "9.1.5",
|
|
120
120
|
"@storybook/test-runner": "^0.23.0",
|
|
121
121
|
"@testing-library/dom": "^10.4.1",
|
|
122
122
|
"@testing-library/react": "^16.3.0",
|
|
123
123
|
"@testing-library/user-event": "^14.6.1",
|
|
124
|
-
"@types/chai": "^5.2.2",
|
|
125
124
|
"@types/chai-as-promised": "^8.0.2",
|
|
126
125
|
"@types/chai-dom": "1.11.3",
|
|
127
126
|
"@types/eslint__js": "^9.14.0",
|
|
128
127
|
"@types/markdown-it": "^14.1.2",
|
|
129
128
|
"@types/react": "^19.1.12",
|
|
130
|
-
"@types/react-dom": "^19.1.
|
|
129
|
+
"@types/react-dom": "^19.1.9",
|
|
131
130
|
"@types/webpack-env": "^1.18.8",
|
|
132
131
|
"@vitejs/plugin-react": "^5.0.2",
|
|
133
|
-
"@vitest/eslint-plugin": "^1.3.
|
|
132
|
+
"@vitest/eslint-plugin": "^1.3.9",
|
|
134
133
|
"acorn": "^8.15.0",
|
|
135
134
|
"babel-plugin-require-context-hook": "^1.0.0",
|
|
136
|
-
"caniuse-lite": "^1.0.
|
|
137
|
-
"chai": "^5.3.1",
|
|
135
|
+
"caniuse-lite": "^1.0.30001741",
|
|
138
136
|
"chai-as-promised": "^8.0.2",
|
|
139
137
|
"chai-dom": "^1.12.1",
|
|
140
138
|
"cheerio": "^1.1.2",
|
|
141
139
|
"core-js": "^3.45.1",
|
|
142
140
|
"cpy-cli": "^6.0.0",
|
|
143
141
|
"dotenv-cli": "^10.0.0",
|
|
144
|
-
"eslint": "^9.
|
|
142
|
+
"eslint": "^9.35.0",
|
|
145
143
|
"eslint-config-prettier": "^10.1.8",
|
|
146
144
|
"eslint-formatter-jslint-xml": "^8.40.0",
|
|
147
145
|
"eslint-import-resolver-exports": "^1.0.0-beta.5",
|
|
@@ -151,7 +149,7 @@
|
|
|
151
149
|
"eslint-plugin-prettier": "^5.5.4",
|
|
152
150
|
"eslint-plugin-react": "^7.37.5",
|
|
153
151
|
"eslint-plugin-react-hooks": "^5.2.0",
|
|
154
|
-
"eslint-plugin-storybook": "^9.1.
|
|
152
|
+
"eslint-plugin-storybook": "^9.1.5",
|
|
155
153
|
"events": "^3.3.0",
|
|
156
154
|
"glob": "^11.0.3",
|
|
157
155
|
"globals": "^16.3.0",
|
|
@@ -159,8 +157,8 @@
|
|
|
159
157
|
"http-server": "^14.1.1",
|
|
160
158
|
"husky": "^9.1.7",
|
|
161
159
|
"identity-obj-proxy": "^3.0.0",
|
|
162
|
-
"jest": "~30.1.
|
|
163
|
-
"jest-environment-jsdom": "^30.1.
|
|
160
|
+
"jest": "~30.1.3",
|
|
161
|
+
"jest-environment-jsdom": "^30.1.2",
|
|
164
162
|
"jest-teamcity": "^1.12.0",
|
|
165
163
|
"lint-staged": "^16.1.6",
|
|
166
164
|
"markdown-it": "^14.1.0",
|
|
@@ -175,13 +173,13 @@
|
|
|
175
173
|
"rollup": "^4.50.0",
|
|
176
174
|
"rollup-plugin-clear": "^2.0.7",
|
|
177
175
|
"storage-mock": "^2.1.0",
|
|
178
|
-
"storybook": "9.1.
|
|
176
|
+
"storybook": "9.1.5",
|
|
179
177
|
"stylelint": "^16.23.1",
|
|
180
178
|
"svg-inline-loader": "^0.8.2",
|
|
181
179
|
"teamcity-service-messages": "^0.1.14",
|
|
182
180
|
"terser-webpack-plugin": "^5.3.14",
|
|
183
181
|
"typescript": "~5.9.2",
|
|
184
|
-
"typescript-eslint": "^8.
|
|
182
|
+
"typescript-eslint": "^8.42.0",
|
|
185
183
|
"vitest": "^3.2.4",
|
|
186
184
|
"vitest-teamcity-reporter": "^0.3.1",
|
|
187
185
|
"wallaby-webpack": "^3.9.16",
|
|
@@ -209,7 +207,7 @@
|
|
|
209
207
|
}
|
|
210
208
|
},
|
|
211
209
|
"dependencies": {
|
|
212
|
-
"@babel/core": "^7.28.
|
|
210
|
+
"@babel/core": "^7.28.4",
|
|
213
211
|
"@babel/preset-typescript": "^7.27.1",
|
|
214
212
|
"@jetbrains/babel-preset-jetbrains": "^2.4.0",
|
|
215
213
|
"@jetbrains/icons": "^5.12.0",
|
|
@@ -220,7 +218,7 @@
|
|
|
220
218
|
"@types/util-deprecate": "^1.0.4",
|
|
221
219
|
"babel-loader": "10.0.0",
|
|
222
220
|
"babel-plugin-transform-define": "^2.1.4",
|
|
223
|
-
"browserslist": "^4.25.
|
|
221
|
+
"browserslist": "^4.25.4",
|
|
224
222
|
"change-case": "^4.1.1",
|
|
225
223
|
"classnames": "^2.5.1",
|
|
226
224
|
"combokeys": "^3.0.1",
|