@jetbrains/ring-ui 6.0.7 → 6.0.9
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/global/variables.css +2 -2
- package/components/global/variables_dark.css +2 -2
- package/components/select/select.js +1 -1
- package/components/slider/slider.css +178 -0
- package/components/slider/slider.d.ts +21 -0
- package/components/slider/slider.js +176 -0
- package/components/slider/slider.utils.d.ts +10 -0
- package/components/slider/slider.utils.js +53 -0
- package/package.json +34 -33
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
--ring-line-color: rgb(var(--ring-line-components)); /* #dfe5eb */
|
|
10
10
|
--ring-borders-components: 197, 209, 219;
|
|
11
11
|
--ring-borders-color: rgb(var(--ring-borders-components)); /* #c5d1db */
|
|
12
|
-
--ring-icon-components:
|
|
13
|
-
--ring-icon-color: rgb(var(--ring-icon-components)); /* #
|
|
12
|
+
--ring-icon-components: 132, 150, 173;
|
|
13
|
+
--ring-icon-color: rgb(var(--ring-icon-components)); /* #8496ad */
|
|
14
14
|
--ring-icon-secondary-components: 153, 153, 153;
|
|
15
15
|
--ring-icon-secondary-color: rgb(var(--ring-icon-secondary-components)); /* #999 */
|
|
16
16
|
--ring-border-disabled-components: 232, 232, 232;
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
--ring-line-color: rgb(var(--ring-line-components)); /* #393B40 */
|
|
8
8
|
--ring-borders-components: 90, 93, 99;
|
|
9
9
|
--ring-borders-color: rgb(var(--ring-borders-components)); /* #5A5D63 */
|
|
10
|
-
--ring-icon-components:
|
|
11
|
-
--ring-icon-color: rgb(var(--ring-icon-components)); /* #
|
|
10
|
+
--ring-icon-components: 128, 146, 157;
|
|
11
|
+
--ring-icon-color: rgb(var(--ring-icon-components)); /* #80929d */
|
|
12
12
|
--ring-icon-secondary-components: 121, 126, 139;
|
|
13
13
|
--ring-icon-secondary-color: rgb(var(--ring-icon-secondary-components)); /* #797E8B */
|
|
14
14
|
--ring-border-disabled-components: 73, 73, 73;
|
|
@@ -813,7 +813,7 @@ export default class Select extends Component {
|
|
|
813
813
|
case Type.INPUT: return (<>
|
|
814
814
|
<div ref={this.nodeRef} className={classNames(classes, styles.inputMode)} data-test={dataTests('ring-select', dataTest)}>
|
|
815
815
|
{shortcutsEnabled && (<Shortcuts map={this.getShortcutsMap()} scope={this.shortcutsScope}/>)}
|
|
816
|
-
<Input {...ariaProps} height={this.props.height} autoComplete="off" id={this.props.id} onClick={this._clickHandler} inputRef={composeRefs(this.filterRef, this.props.filterRef)} disabled={this.props.disabled} value={this.state.filterValue} borderless={this.props.type === Type.INPUT_WITHOUT_CONTROLS} style={style} size={Size.FULL} onChange={this._filterChangeHandler} onFocus={this._focusHandler} onBlur={this._blurHandler}
|
|
816
|
+
<Input {...ariaProps} loading={this.props.loading} height={this.props.height} autoComplete="off" id={this.props.id} onClick={this._clickHandler} inputRef={composeRefs(this.filterRef, this.props.filterRef)} disabled={this.props.disabled} value={this.state.filterValue} borderless={this.props.type === Type.INPUT_WITHOUT_CONTROLS} style={style} size={Size.FULL} onChange={this._filterChangeHandler} onFocus={this._focusHandler} onBlur={this._blurHandler}
|
|
817
817
|
// Input with error style without description
|
|
818
818
|
error={this.props.error != null ? '' : null} label={this.props.type === Type.INPUT ? this._getLabel() : null} placeholder={this.props.inputPlaceholder} onKeyDown={this.props.onKeyDown} data-test="ring-select__focus" enableShortcuts={shortcutsEnabled
|
|
819
819
|
? Object.keys({
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
@value dark from "../global/variables_dark.css";
|
|
2
|
+
|
|
3
|
+
.slider {
|
|
4
|
+
--ring-slider-thumb-color: var(--ring-content-background-color);
|
|
5
|
+
--ring-slider-thumb-border: var(--ring-main-color);
|
|
6
|
+
--ring-slider-thumb-disabled-color: var(--ring-content-background-color);
|
|
7
|
+
--ring-slider-tag-disabled-text-color: var(--ring-white-text-color);
|
|
8
|
+
|
|
9
|
+
position: relative;
|
|
10
|
+
|
|
11
|
+
height: calc(var(--ring-unit) / 2);
|
|
12
|
+
padding: var(--ring-unit) 0;
|
|
13
|
+
|
|
14
|
+
cursor: pointer;
|
|
15
|
+
|
|
16
|
+
&.disabled {
|
|
17
|
+
cursor: default;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
&.marked {
|
|
21
|
+
margin-top: calc(var(--ring-unit) * 3);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.dark, :global(.ring-ui-theme-dark) {
|
|
26
|
+
.slider {
|
|
27
|
+
--ring-slider-thumb-color: var(--ring-main-color);
|
|
28
|
+
--ring-slider-thumb-border: var(--ring-white-text-color);
|
|
29
|
+
--ring-slider-thumb-disabled-color: var(--ring-disabled-background-color);
|
|
30
|
+
--ring-slider-thumb-disabled-border: var(--ring-border-disabled-color);
|
|
31
|
+
--ring-slider-tag-disabled-text-color: var(--ring-secondary-color);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.rail {
|
|
36
|
+
height: inherit;
|
|
37
|
+
|
|
38
|
+
border-radius: calc(var(--ring-unit) / 2);
|
|
39
|
+
|
|
40
|
+
background-color: var(--ring-selected-background-color);
|
|
41
|
+
|
|
42
|
+
&.rounded {
|
|
43
|
+
border-radius: calc(var(--ring-unit) / 2);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
&.disabled {
|
|
47
|
+
background-color: var(--ring-disabled-background-color);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.track {
|
|
52
|
+
position: absolute;
|
|
53
|
+
left: 0;
|
|
54
|
+
|
|
55
|
+
height: inherit;
|
|
56
|
+
margin-top:calc(var(--ring-unit) / -2);
|
|
57
|
+
|
|
58
|
+
border-radius: calc(var(--ring-unit) / 2);
|
|
59
|
+
|
|
60
|
+
background-color: var(--ring-main-color);
|
|
61
|
+
|
|
62
|
+
&.rounded {
|
|
63
|
+
border-radius: calc(var(--ring-unit) / 2);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
&.disabled {
|
|
67
|
+
background-color: var(--ring-disabled-selected-background-color);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.thumb {
|
|
72
|
+
composes: resetButton from "../global/global.css";
|
|
73
|
+
|
|
74
|
+
position: absolute;
|
|
75
|
+
z-index: 1;
|
|
76
|
+
|
|
77
|
+
width: calc(var(--ring-unit) * 1.5);
|
|
78
|
+
height: calc(var(--ring-unit) * 1.5);
|
|
79
|
+
margin-top: calc(var(--ring-unit) * -1);
|
|
80
|
+
|
|
81
|
+
cursor: pointer;
|
|
82
|
+
transform: translateX(-50%);
|
|
83
|
+
|
|
84
|
+
border-radius: var(--ring-unit);
|
|
85
|
+
background-color: var(--ring-slider-thumb-color);
|
|
86
|
+
box-shadow: 0 1px 2px 0 var(--ring-popup-secondary-shadow-color), 0 2px 8px 0 var(--ring-popup-shadow-components);
|
|
87
|
+
|
|
88
|
+
&.disabled {
|
|
89
|
+
cursor: default;
|
|
90
|
+
|
|
91
|
+
border: 1px solid var(--ring-slider-thumb-disabled-border);
|
|
92
|
+
background-color: var(--ring-slider-thumb-disabled-color);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
&.dragged {
|
|
96
|
+
cursor: grabbing;
|
|
97
|
+
|
|
98
|
+
border: 1px solid var(--ring-slider-thumb-border);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.tick {
|
|
103
|
+
position: absolute;
|
|
104
|
+
|
|
105
|
+
width: calc(var(--ring-unit) / 2);
|
|
106
|
+
height: calc(var(--ring-unit) / 2);
|
|
107
|
+
margin-top: calc(var(--ring-unit) / -2);
|
|
108
|
+
margin-left: calc(var(--ring-unit) / -4);
|
|
109
|
+
|
|
110
|
+
border-radius: calc(var(--ring-unit) / 2);
|
|
111
|
+
background-color: var(--ring-border-hover-color);
|
|
112
|
+
|
|
113
|
+
&.active {
|
|
114
|
+
background-color: var(--ring-main-hover-color);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
&.disabled {
|
|
118
|
+
background-color: var(--ring-border-selected-disabled-color);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.markValue {
|
|
123
|
+
position: absolute;
|
|
124
|
+
|
|
125
|
+
margin-top: calc(var(--ring-unit) * -4);
|
|
126
|
+
margin-left: calc(var(--ring-unit) / -4);
|
|
127
|
+
|
|
128
|
+
transform: translateX(calc(-50% + 2px));
|
|
129
|
+
|
|
130
|
+
color: var(--ring-text-color);
|
|
131
|
+
|
|
132
|
+
font-size: var(--ring-font-size-smaller);
|
|
133
|
+
line-height: var(--ring-line-height-lowest);
|
|
134
|
+
|
|
135
|
+
&.disabled {
|
|
136
|
+
color: var(--ring-disabled-color);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.tag {
|
|
141
|
+
position: absolute;
|
|
142
|
+
z-index: 2;
|
|
143
|
+
|
|
144
|
+
margin-top: calc(var(--ring-unit) * -4 - 2px);
|
|
145
|
+
padding: calc(var(--ring-unit) / 4) calc(var(--ring-unit) * 0.75);
|
|
146
|
+
|
|
147
|
+
transform: translateX(-50%);
|
|
148
|
+
|
|
149
|
+
color: var(--ring-white-text-color);
|
|
150
|
+
border-radius: calc(var(--ring-unit) / 2);
|
|
151
|
+
|
|
152
|
+
background-color: var(--ring-main-color);
|
|
153
|
+
|
|
154
|
+
font-size: var(--ring-font-size-smaller);
|
|
155
|
+
line-height: var(--ring-line-height-lowest);
|
|
156
|
+
|
|
157
|
+
&::after {
|
|
158
|
+
position: absolute;
|
|
159
|
+
top: 100%;
|
|
160
|
+
left: calc(50% - 3px);
|
|
161
|
+
|
|
162
|
+
content: ' ';
|
|
163
|
+
|
|
164
|
+
border-top: 3px solid var(--ring-main-color);
|
|
165
|
+
|
|
166
|
+
border-right: 3px solid transparent;
|
|
167
|
+
border-left: 3px solid transparent;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
&.disabled {
|
|
171
|
+
color: var(--ring-slider-tag-disabled-text-color);
|
|
172
|
+
background-color: var(--ring-border-selected-disabled-color);
|
|
173
|
+
|
|
174
|
+
&::after {
|
|
175
|
+
border-top: 3px solid var(--ring-border-selected-disabled-color);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React, { ReactNode } from 'react';
|
|
2
|
+
type Mark = {
|
|
3
|
+
value: number;
|
|
4
|
+
label?: ReactNode;
|
|
5
|
+
};
|
|
6
|
+
type Props = {
|
|
7
|
+
defaultValue?: number | number[];
|
|
8
|
+
value?: number | number[];
|
|
9
|
+
min?: number;
|
|
10
|
+
max?: number;
|
|
11
|
+
step?: number;
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
marks?: Mark[] | boolean;
|
|
14
|
+
showTicks?: boolean;
|
|
15
|
+
showTag?: boolean;
|
|
16
|
+
className?: string;
|
|
17
|
+
renderTag?: (value: number) => ReactNode;
|
|
18
|
+
onChange?: (value: number | number[]) => void;
|
|
19
|
+
};
|
|
20
|
+
export declare const Slider: React.FC<Props>;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import React, { Fragment, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
import { isArray } from '../global/typescript-utils';
|
|
4
|
+
import Shortcuts from '../shortcuts/shortcuts';
|
|
5
|
+
import getUID from '../global/get-uid';
|
|
6
|
+
import styles from './slider.css';
|
|
7
|
+
import { adjustValues, calculateMarks, calculateValue, HUNDRED, toPercent, toRange, validateValue } from './slider.utils';
|
|
8
|
+
export const Slider = ({ defaultValue, value, min = 0, max = HUNDRED, step = 1, disabled, marks, showTicks, showTag, className, renderTag, onChange }) => {
|
|
9
|
+
const ref = useRef(null);
|
|
10
|
+
const previouslyDragged = useRef(false);
|
|
11
|
+
const [values, setValues] = useState(defaultValue ?? min);
|
|
12
|
+
const validValues = useMemo(() => toRange(value ?? values, min, max), [max, min, value, values]);
|
|
13
|
+
const validStep = step < 0 ? 0 : step;
|
|
14
|
+
const isRange = isArray(defaultValue ?? value);
|
|
15
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
16
|
+
const [draggedIndex, setDraggedIndex] = useState(-1);
|
|
17
|
+
const [shortcutsScope] = useState(getUID('ring-slider-'));
|
|
18
|
+
const markValues = useMemo(() => {
|
|
19
|
+
if (isArray(marks)) {
|
|
20
|
+
return marks.map(mark => ({ ...mark, value: validateValue(mark.value, min, max) }));
|
|
21
|
+
}
|
|
22
|
+
else if (marks) {
|
|
23
|
+
return calculateMarks(min, max, validStep);
|
|
24
|
+
}
|
|
25
|
+
return [];
|
|
26
|
+
}, [marks, max, min, validStep]);
|
|
27
|
+
const tickMarks = useMemo(() => {
|
|
28
|
+
if (showTicks) {
|
|
29
|
+
return markValues.length ? markValues : calculateMarks(min, max, validStep);
|
|
30
|
+
}
|
|
31
|
+
return [];
|
|
32
|
+
}, [max, min, markValues, showTicks, validStep]);
|
|
33
|
+
const trackStart = useMemo(() => toPercent(isRange ? Math.min(...validValues) : min, min, max), [isRange, max, min, validValues]);
|
|
34
|
+
const trackLength = useMemo(() => toPercent(Math.max(...validValues), min, max) - trackStart, [max, min, trackStart, validValues]);
|
|
35
|
+
const handleValueChange = useCallback((nextValues) => {
|
|
36
|
+
setValues(nextValues);
|
|
37
|
+
onChange?.(isRange ? nextValues : nextValues[0]);
|
|
38
|
+
}, [isRange, onChange]);
|
|
39
|
+
const shortcutsMap = useMemo(() => {
|
|
40
|
+
const setValueAndSwap = (nextValue, index) => {
|
|
41
|
+
const nextValues = [...validValues];
|
|
42
|
+
nextValues[index] = nextValue;
|
|
43
|
+
if (nextValues[0] > nextValues[1]) {
|
|
44
|
+
const previousValue = nextValues[index];
|
|
45
|
+
nextValues.reverse();
|
|
46
|
+
const thumb = ref.current?.querySelector(`[role="slider"][data-index="${nextValues.indexOf(previousValue)}"]`);
|
|
47
|
+
thumb?.focus();
|
|
48
|
+
}
|
|
49
|
+
handleValueChange(nextValues);
|
|
50
|
+
};
|
|
51
|
+
const getIndex = (target) => Number(target?.getAttribute('data-index'));
|
|
52
|
+
const map = {};
|
|
53
|
+
if (!disabled) {
|
|
54
|
+
map.left = map.down = ({ target }) => {
|
|
55
|
+
const index = getIndex(target);
|
|
56
|
+
setValueAndSwap(Math.max(min, validValues[index] - validStep), index);
|
|
57
|
+
};
|
|
58
|
+
map.right = map.up = ({ target }) => {
|
|
59
|
+
const index = getIndex(target);
|
|
60
|
+
setValueAndSwap(Math.min(max, validValues[index] + validStep), index);
|
|
61
|
+
};
|
|
62
|
+
map.home = ({ target }) => {
|
|
63
|
+
const index = getIndex(target);
|
|
64
|
+
setValueAndSwap(min, index);
|
|
65
|
+
};
|
|
66
|
+
map.end = ({ target }) => {
|
|
67
|
+
const index = getIndex(target);
|
|
68
|
+
setValueAndSwap(max, index);
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return map;
|
|
72
|
+
}, [disabled, handleValueChange, max, min, validStep, validValues]);
|
|
73
|
+
const handleMouseDown = useCallback((e) => {
|
|
74
|
+
e.stopPropagation();
|
|
75
|
+
if (disabled) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const index = e.currentTarget.getAttribute('data-index');
|
|
79
|
+
const nextValue = calculateValue(ref, e.pageX, min, max, validStep);
|
|
80
|
+
if (nextValue !== null && !isNaN(nextValue) && !index) {
|
|
81
|
+
const rangeIndex = Number(Math.abs(validValues[0] - nextValue) > Math.abs(validValues[1] - nextValue));
|
|
82
|
+
setDraggedIndex(isRange ? rangeIndex : 0);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
setDraggedIndex(Number(index));
|
|
86
|
+
}
|
|
87
|
+
setIsDragging(true);
|
|
88
|
+
previouslyDragged.current = false;
|
|
89
|
+
}, [disabled, isRange, max, min, validStep, validValues]);
|
|
90
|
+
const handleMouseUp = useCallback(({ pageX }) => {
|
|
91
|
+
const nextValues = adjustValues(validValues, ref, draggedIndex, pageX, max, min, validStep);
|
|
92
|
+
if (nextValues[0] > nextValues[1]) {
|
|
93
|
+
nextValues.reverse();
|
|
94
|
+
}
|
|
95
|
+
handleValueChange(nextValues);
|
|
96
|
+
setDraggedIndex(-1);
|
|
97
|
+
setIsDragging(false);
|
|
98
|
+
previouslyDragged.current = true;
|
|
99
|
+
}, [validValues, draggedIndex, handleValueChange, max, min, validStep]);
|
|
100
|
+
const handleMouseMove = useCallback(({ pageX }) => {
|
|
101
|
+
const nextValues = adjustValues(validValues, ref, draggedIndex, pageX, max, min, validStep);
|
|
102
|
+
if (nextValues[0] > nextValues[1]) {
|
|
103
|
+
nextValues.reverse();
|
|
104
|
+
setDraggedIndex(prevState => (prevState === 0 ? 1 : 0));
|
|
105
|
+
}
|
|
106
|
+
handleValueChange(nextValues);
|
|
107
|
+
}, [validValues, draggedIndex, max, min, validStep, handleValueChange]);
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
if (disabled) {
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
if (isDragging && !previouslyDragged.current) {
|
|
113
|
+
window.addEventListener('mousemove', handleMouseMove);
|
|
114
|
+
window.addEventListener('mouseup', handleMouseUp);
|
|
115
|
+
}
|
|
116
|
+
else if (!isDragging && previouslyDragged.current) {
|
|
117
|
+
window.removeEventListener('mousemove', handleMouseMove);
|
|
118
|
+
window.removeEventListener('mouseup', handleMouseUp);
|
|
119
|
+
}
|
|
120
|
+
return () => {
|
|
121
|
+
window.removeEventListener('mousemove', handleMouseMove);
|
|
122
|
+
window.removeEventListener('mouseup', handleMouseUp);
|
|
123
|
+
};
|
|
124
|
+
}, [isDragging, handleMouseMove, handleMouseUp, disabled]);
|
|
125
|
+
return (<div ref={ref} role="button" className={classNames(styles.slider, className, {
|
|
126
|
+
[styles.disabled]: disabled,
|
|
127
|
+
[styles.marked]: !!marks || showTag
|
|
128
|
+
})} tabIndex={-1} onMouseDown={handleMouseDown}>
|
|
129
|
+
<Shortcuts map={shortcutsMap} scope={shortcutsScope}/>
|
|
130
|
+
<div className={classNames(styles.rail, {
|
|
131
|
+
[styles.rounded]: !showTicks,
|
|
132
|
+
[styles.disabled]: disabled
|
|
133
|
+
})}/>
|
|
134
|
+
<div style={{
|
|
135
|
+
left: `${trackStart}%`,
|
|
136
|
+
width: `${trackLength}%`
|
|
137
|
+
}} className={classNames(styles.track, {
|
|
138
|
+
[styles.rounded]: !showTicks,
|
|
139
|
+
[styles.disabled]: disabled
|
|
140
|
+
})}/>
|
|
141
|
+
{validValues.map((numValue, index) => {
|
|
142
|
+
const percent = toPercent(numValue, min, max);
|
|
143
|
+
return (
|
|
144
|
+
// eslint-disable-next-line react/no-array-index-key
|
|
145
|
+
<Fragment key={index}>
|
|
146
|
+
<button type="button" role="slider" aria-valuemin={min} aria-valuemax={max} aria-valuenow={numValue} data-index={index} style={{ left: `${percent}%` }} className={classNames(styles.thumb, {
|
|
147
|
+
[styles.disabled]: disabled,
|
|
148
|
+
[styles.dragged]: isDragging && draggedIndex === index
|
|
149
|
+
})} disabled={disabled} onMouseDown={handleMouseDown}/>
|
|
150
|
+
{showTag && (<div style={{ left: `${percent}%` }} className={classNames(styles.tag, { [styles.disabled]: disabled })} role="tooltip">
|
|
151
|
+
{renderTag ? renderTag(numValue) : numValue}
|
|
152
|
+
</div>)}
|
|
153
|
+
</Fragment>);
|
|
154
|
+
})}
|
|
155
|
+
{markValues.map(({ value: markValue, label }, index) => {
|
|
156
|
+
const percent = toPercent(markValue, min, max);
|
|
157
|
+
return (<div
|
|
158
|
+
// eslint-disable-next-line react/no-array-index-key
|
|
159
|
+
key={index} style={{ left: `${percent}%` }} className={classNames(styles.markValue, { [styles.disabled]: disabled })}>
|
|
160
|
+
{label ?? markValue}
|
|
161
|
+
</div>);
|
|
162
|
+
})}
|
|
163
|
+
{tickMarks.map(({ value: tickValue }, index) => {
|
|
164
|
+
const percent = toPercent(tickValue, min, max);
|
|
165
|
+
const isActive = isRange
|
|
166
|
+
? tickValue >= validValues[0] && tickValue <= validValues[validValues.length - 1]
|
|
167
|
+
: tickValue <= validValues[0];
|
|
168
|
+
return (<div
|
|
169
|
+
// eslint-disable-next-line react/no-array-index-key
|
|
170
|
+
key={index} className={classNames(styles.tick, {
|
|
171
|
+
[styles.active]: isActive,
|
|
172
|
+
[styles.disabled]: disabled
|
|
173
|
+
})} style={{ left: `${percent}%` }}/>);
|
|
174
|
+
})}
|
|
175
|
+
</div>);
|
|
176
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
export declare const HUNDRED = 100;
|
|
3
|
+
export declare function toPercent(value: number, min: number, max: number): number;
|
|
4
|
+
export declare function calculateValue(ref: RefObject<HTMLDivElement>, x: number, min: number, max: number, step: number): number | null;
|
|
5
|
+
export declare function validateValue(value: number, min: number, max: number): number;
|
|
6
|
+
export declare function toRange(value: number | number[], min: number, max: number): number[];
|
|
7
|
+
export declare function adjustValues(values: number[], ref: RefObject<HTMLDivElement>, index: number, x: number, max: number, min: number, step: number): number[];
|
|
8
|
+
export declare function calculateMarks(min: number, max: number, step: number): {
|
|
9
|
+
value: number;
|
|
10
|
+
}[];
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { isArray } from '../global/typescript-utils';
|
|
2
|
+
export const HUNDRED = 100;
|
|
3
|
+
export function toPercent(value, min, max) {
|
|
4
|
+
return ((value - min) * HUNDRED) / (max - min);
|
|
5
|
+
}
|
|
6
|
+
function toValue(percent, min, max) {
|
|
7
|
+
return (max - min) * percent + min;
|
|
8
|
+
}
|
|
9
|
+
function roundToStep(value, step, min) {
|
|
10
|
+
return Math.round((value - min) / step) * step + min;
|
|
11
|
+
}
|
|
12
|
+
export function calculateValue(ref, x, min, max, step) {
|
|
13
|
+
if (!ref.current) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
const { width, left } = ref.current.getBoundingClientRect();
|
|
17
|
+
const value = toValue((x - left) / width, min, max);
|
|
18
|
+
const precision = step.toString().split('.')?.[1]?.length;
|
|
19
|
+
return Number(roundToStep(value, step, min).toFixed(precision));
|
|
20
|
+
}
|
|
21
|
+
export function validateValue(value, min, max) {
|
|
22
|
+
if (value <= min) {
|
|
23
|
+
return min;
|
|
24
|
+
}
|
|
25
|
+
if (value >= max) {
|
|
26
|
+
return max;
|
|
27
|
+
}
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
export function toRange(value, min, max) {
|
|
31
|
+
if (isArray(value)) {
|
|
32
|
+
const nextValues = value.slice(0, 2).map(val => validateValue(val, min, max));
|
|
33
|
+
if (nextValues[0] > nextValues[1]) {
|
|
34
|
+
nextValues.reverse();
|
|
35
|
+
}
|
|
36
|
+
return nextValues;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
return [validateValue(value, min, max)];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export function adjustValues(values, ref, index, x, max, min, step) {
|
|
43
|
+
const nextValue = calculateValue(ref, x, min, max, step);
|
|
44
|
+
const nextValues = [...values];
|
|
45
|
+
if (nextValue !== null && !isNaN(nextValue)) {
|
|
46
|
+
nextValues[index] = validateValue(nextValue, min, max);
|
|
47
|
+
}
|
|
48
|
+
return nextValues;
|
|
49
|
+
}
|
|
50
|
+
export function calculateMarks(min, max, step) {
|
|
51
|
+
const numMarks = Math.floor((max - min) / step) + 1;
|
|
52
|
+
return Array.from({ length: numMarks }, (_, index) => ({ value: validateValue(min + step * index, min, max) }));
|
|
53
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jetbrains/ring-ui",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.9",
|
|
4
4
|
"description": "JetBrains UI library",
|
|
5
5
|
"author": "JetBrains",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -78,8 +78,8 @@
|
|
|
78
78
|
"devDependencies": {
|
|
79
79
|
"@babel/cli": "^7.23.9",
|
|
80
80
|
"@babel/eslint-parser": "^7.23.10",
|
|
81
|
+
"@csstools/css-parser-algorithms": "^2.6.0",
|
|
81
82
|
"@csstools/stylelint-no-at-nest-rule": "^2.0.0",
|
|
82
|
-
"@csstools/css-parser-algorithms": "^2.5.0",
|
|
83
83
|
"@jetbrains/eslint-config": "^5.4.1",
|
|
84
84
|
"@jetbrains/stylelint-config": "^4.0.2",
|
|
85
85
|
"@primer/octicons": "^19.8.0",
|
|
@@ -87,36 +87,37 @@
|
|
|
87
87
|
"@rollup/plugin-json": "^6.1.0",
|
|
88
88
|
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
89
89
|
"@rollup/plugin-replace": "^5.0.5",
|
|
90
|
-
"@storybook/addon-a11y": "7.6.
|
|
91
|
-
"@storybook/addon-docs": "7.6.
|
|
92
|
-
"@storybook/addon-essentials": "7.6.
|
|
93
|
-
"@storybook/addon-storyshots": "7.6.
|
|
94
|
-
"@storybook/addon-storyshots-puppeteer": "7.6.
|
|
95
|
-
"@storybook/addon-storysource": "7.6.
|
|
96
|
-
"@storybook/addons": "7.6.
|
|
97
|
-
"@storybook/
|
|
98
|
-
"@storybook/
|
|
99
|
-
"@storybook/react
|
|
100
|
-
"@storybook/
|
|
101
|
-
"@storybook/
|
|
90
|
+
"@storybook/addon-a11y": "7.6.17",
|
|
91
|
+
"@storybook/addon-docs": "7.6.17",
|
|
92
|
+
"@storybook/addon-essentials": "7.6.17",
|
|
93
|
+
"@storybook/addon-storyshots": "7.6.17",
|
|
94
|
+
"@storybook/addon-storyshots-puppeteer": "7.6.17",
|
|
95
|
+
"@storybook/addon-storysource": "7.6.17",
|
|
96
|
+
"@storybook/addons": "7.6.17",
|
|
97
|
+
"@storybook/components": "7.6.17",
|
|
98
|
+
"@storybook/preview-api": "7.6.17",
|
|
99
|
+
"@storybook/react": "7.6.17",
|
|
100
|
+
"@storybook/react-webpack5": "7.6.17",
|
|
101
|
+
"@storybook/source-loader": "7.6.17",
|
|
102
|
+
"@storybook/theming": "7.6.17",
|
|
102
103
|
"@testing-library/react": "^14.2.1",
|
|
103
104
|
"@testing-library/user-event": "^14.5.2",
|
|
104
|
-
"@types/chai": "^4.3.
|
|
105
|
+
"@types/chai": "^4.3.12",
|
|
105
106
|
"@types/chai-as-promised": "^7.1.8",
|
|
106
107
|
"@types/chai-dom": "0.0.10",
|
|
107
108
|
"@types/chai-enzyme": "^0.6.13",
|
|
108
109
|
"@types/enzyme": "^3.10.18",
|
|
109
110
|
"@types/markdown-it": "^13.0.7",
|
|
110
|
-
"@types/react": "^18.2.
|
|
111
|
+
"@types/react": "^18.2.60",
|
|
111
112
|
"@types/react-dom": "^18.2.19",
|
|
112
113
|
"@types/sinon": "^17.0.3",
|
|
113
114
|
"@types/sinon-chai": "^3.2.12",
|
|
114
|
-
"@typescript-eslint/eslint-plugin": "^7.0
|
|
115
|
-
"@typescript-eslint/parser": "^7.0
|
|
115
|
+
"@typescript-eslint/eslint-plugin": "^7.1.0",
|
|
116
|
+
"@typescript-eslint/parser": "^7.1.0",
|
|
116
117
|
"@wojtekmaj/enzyme-adapter-react-17": "^0.8.0",
|
|
117
118
|
"acorn": "^8.11.3",
|
|
118
119
|
"babel-plugin-require-context-hook": "^1.0.0",
|
|
119
|
-
"caniuse-lite": "^1.0.
|
|
120
|
+
"caniuse-lite": "^1.0.30001591",
|
|
120
121
|
"chai": "^5.1.0",
|
|
121
122
|
"chai-as-promised": "^7.1.1",
|
|
122
123
|
"chai-dom": "^1.10.0",
|
|
@@ -125,13 +126,13 @@
|
|
|
125
126
|
"core-js": "^3.36.0",
|
|
126
127
|
"cpy-cli": "^3.1.1",
|
|
127
128
|
"enzyme": "^3.11.0",
|
|
128
|
-
"eslint": "^8.
|
|
129
|
+
"eslint": "^8.57.0",
|
|
129
130
|
"eslint-import-resolver-webpack": "^0.13.8",
|
|
130
131
|
"eslint-plugin-bdd": "^2.1.1",
|
|
131
132
|
"eslint-plugin-import": "^2.29.1",
|
|
132
133
|
"eslint-plugin-jsx-a11y": "^6.8.0",
|
|
133
134
|
"eslint-plugin-react": "^7.33.2",
|
|
134
|
-
"eslint-plugin-storybook": "^0.
|
|
135
|
+
"eslint-plugin-storybook": "^0.8.0",
|
|
135
136
|
"events": "^3.3.0",
|
|
136
137
|
"glob": "^10.3.10",
|
|
137
138
|
"html-webpack-plugin": "^5.6.0",
|
|
@@ -141,7 +142,7 @@
|
|
|
141
142
|
"jest": "~29.7.0",
|
|
142
143
|
"jest-environment-jsdom": "^29.7.0",
|
|
143
144
|
"jest-teamcity": "^1.10.0",
|
|
144
|
-
"karma": "^6.4.
|
|
145
|
+
"karma": "^6.4.3",
|
|
145
146
|
"karma-chrome-launcher": "3.2.0",
|
|
146
147
|
"karma-mocha": "^2.0.1",
|
|
147
148
|
"karma-sourcemap-loader": "^0.4.0",
|
|
@@ -150,23 +151,23 @@
|
|
|
150
151
|
"lint-staged": "^15.2.2",
|
|
151
152
|
"markdown-it": "^14.0.0",
|
|
152
153
|
"merge-options": "^3.0.4",
|
|
153
|
-
"mocha": "^10.
|
|
154
|
+
"mocha": "^10.3.0",
|
|
154
155
|
"pinst": "^3.0.0",
|
|
155
156
|
"prettier": "^3.2.5",
|
|
156
|
-
"puppeteer": "^22.
|
|
157
|
+
"puppeteer": "^22.3.0",
|
|
157
158
|
"raw-loader": "^4.0.2",
|
|
158
159
|
"react": "^18.2.0",
|
|
159
160
|
"react-dom": "^18.2.0",
|
|
160
161
|
"react-test-renderer": "^18.2.0",
|
|
161
162
|
"regenerator-runtime": "^0.14.1",
|
|
162
163
|
"rimraf": "^5.0.5",
|
|
163
|
-
"rollup": "^4.
|
|
164
|
+
"rollup": "^4.12.0",
|
|
164
165
|
"rollup-plugin-clear": "^2.0.7",
|
|
165
166
|
"rollup-plugin-styles": "^4.0.0",
|
|
166
167
|
"sinon": "^17.0.1",
|
|
167
168
|
"sinon-chai": "^3.7.0",
|
|
168
169
|
"storage-mock": "^2.1.0",
|
|
169
|
-
"storybook": "7.6.
|
|
170
|
+
"storybook": "7.6.17",
|
|
170
171
|
"storybook-addon-themes": "^6.1.0",
|
|
171
172
|
"stylelint": "^16.2.1",
|
|
172
173
|
"svg-inline-loader": "^0.8.2",
|
|
@@ -174,7 +175,7 @@
|
|
|
174
175
|
"terser-webpack-plugin": "^5.3.10",
|
|
175
176
|
"typescript": "~5.3.3",
|
|
176
177
|
"wallaby-webpack": "^3.9.16",
|
|
177
|
-
"webpack": "^5.90.
|
|
178
|
+
"webpack": "^5.90.3",
|
|
178
179
|
"webpack-cli": "^5.1.4",
|
|
179
180
|
"xmlappend": "^1.0.4"
|
|
180
181
|
},
|
|
@@ -198,10 +199,10 @@
|
|
|
198
199
|
}
|
|
199
200
|
},
|
|
200
201
|
"dependencies": {
|
|
201
|
-
"@babel/core": "^7.
|
|
202
|
+
"@babel/core": "^7.24.0",
|
|
202
203
|
"@babel/preset-typescript": "^7.23.3",
|
|
203
204
|
"@jetbrains/babel-preset-jetbrains": "^2.3.2",
|
|
204
|
-
"@jetbrains/icons": "^4.0.
|
|
205
|
+
"@jetbrains/icons": "^4.0.1",
|
|
205
206
|
"@jetbrains/logos": "^2.2.25",
|
|
206
207
|
"@jetbrains/postcss-require-hover": "^0.1.2",
|
|
207
208
|
"@types/combokeys": "^2.4.9",
|
|
@@ -224,7 +225,7 @@
|
|
|
224
225
|
"element-resize-detector": "^1.2.4",
|
|
225
226
|
"es6-error": "^4.1.1",
|
|
226
227
|
"eslint-plugin-react-hooks": "^4.6.0",
|
|
227
|
-
"fastdom": "^1.0.
|
|
228
|
+
"fastdom": "^1.0.12",
|
|
228
229
|
"file-loader": "^6.2.0",
|
|
229
230
|
"focus-trap": "^7.5.4",
|
|
230
231
|
"highlight.js": "^10.7.2",
|
|
@@ -234,11 +235,11 @@
|
|
|
234
235
|
"postcss-calc": "^9.0.1",
|
|
235
236
|
"postcss-flexbugs-fixes": "^5.0.2",
|
|
236
237
|
"postcss-font-family-system-ui": "^5.0.0",
|
|
237
|
-
"postcss-loader": "^8.1.
|
|
238
|
+
"postcss-loader": "^8.1.1",
|
|
238
239
|
"postcss-modules-values-replace": "^4.1.0",
|
|
239
|
-
"postcss-preset-env": "^9.
|
|
240
|
+
"postcss-preset-env": "^9.4.0",
|
|
240
241
|
"prop-types": "^15.8.1",
|
|
241
|
-
"react-movable": "^3.0
|
|
242
|
+
"react-movable": "^3.2.0",
|
|
242
243
|
"react-virtualized": "^9.22.5",
|
|
243
244
|
"react-waypoint": "^10.3.0",
|
|
244
245
|
"scrollbar-width": "^3.1.1",
|