@gravity-ui/date-components 2.10.3 → 2.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/RangeDateSelection/RangeDateSelection.css +28 -0
- package/dist/cjs/components/RangeDateSelection/RangeDateSelection.d.ts +24 -0
- package/dist/cjs/components/RangeDateSelection/RangeDateSelection.js +49 -0
- package/dist/cjs/components/RangeDateSelection/components/NowLine/NowLine.css +4 -0
- package/dist/cjs/components/RangeDateSelection/components/NowLine/NowLine.d.ts +2 -0
- package/dist/cjs/components/RangeDateSelection/components/NowLine/NowLine.js +42 -0
- package/dist/cjs/components/RangeDateSelection/components/Ruler/Ruler.d.ts +32 -0
- package/dist/cjs/components/RangeDateSelection/components/Ruler/Ruler.js +61 -0
- package/dist/cjs/components/RangeDateSelection/components/RulerViewport/RulerViewport.css +25 -0
- package/dist/cjs/components/RangeDateSelection/components/RulerViewport/RulerViewport.d.ts +13 -0
- package/dist/cjs/components/RangeDateSelection/components/RulerViewport/RulerViewport.js +35 -0
- package/dist/cjs/components/RangeDateSelection/components/SelectionControl/SelectionControl.css +78 -0
- package/dist/cjs/components/RangeDateSelection/components/SelectionControl/SelectionControl.d.ts +8 -0
- package/dist/cjs/components/RangeDateSelection/components/SelectionControl/SelectionControl.js +135 -0
- package/dist/cjs/components/RangeDateSelection/components/Ticks/MiddleTicks.d.ts +3 -0
- package/dist/cjs/components/RangeDateSelection/components/Ticks/MiddleTicks.js +10 -0
- package/dist/cjs/components/RangeDateSelection/components/Ticks/SlitTicks.d.ts +5 -0
- package/dist/cjs/components/RangeDateSelection/components/Ticks/SlitTicks.js +10 -0
- package/dist/cjs/components/RangeDateSelection/components/Ticks/Ticks.css +16 -0
- package/dist/cjs/components/RangeDateSelection/components/Ticks/Ticks.d.ts +18 -0
- package/dist/cjs/components/RangeDateSelection/components/Ticks/Ticks.js +52 -0
- package/dist/cjs/components/RangeDateSelection/components/Ticks/UnavialableTicks.d.ts +15 -0
- package/dist/cjs/components/RangeDateSelection/components/Ticks/UnavialableTicks.js +50 -0
- package/dist/cjs/components/RangeDateSelection/components/Ticks/utils.d.ts +24 -0
- package/dist/cjs/components/RangeDateSelection/components/Ticks/utils.js +166 -0
- package/dist/cjs/components/RangeDateSelection/hooks/useRangeDateSelectionState.d.ts +60 -0
- package/dist/cjs/components/RangeDateSelection/hooks/useRangeDateSelectionState.js +150 -0
- package/dist/cjs/components/RangeDateSelection/i18n/en.json +7 -0
- package/dist/cjs/components/RangeDateSelection/i18n/index.d.ts +1 -0
- package/dist/cjs/components/RangeDateSelection/i18n/index.js +11 -0
- package/dist/cjs/components/RangeDateSelection/i18n/ru.json +7 -0
- package/dist/cjs/components/RangeDateSelection/index.d.ts +3 -0
- package/dist/cjs/components/RangeDateSelection/index.js +18 -0
- package/dist/cjs/components/RangeDateSelection/utils/date.d.ts +2 -0
- package/dist/cjs/components/RangeDateSelection/utils/date.js +10 -0
- package/dist/cjs/components/RangeDateSelection/utils/span.d.ts +23 -0
- package/dist/cjs/components/RangeDateSelection/utils/span.js +27 -0
- package/dist/cjs/components/RelativeRangeDatePicker/components/Presets/i18n/index.d.ts +1 -1
- package/dist/cjs/components/index.d.ts +1 -0
- package/dist/cjs/components/index.js +1 -0
- package/dist/cjs/components/mixins.css +0 -0
- package/dist/cjs/components/utils/constants.d.ts +7 -0
- package/dist/cjs/components/utils/constants.js +10 -0
- package/dist/cjs/components/utils/filterDOMProps.d.ts +17 -0
- package/dist/cjs/components/utils/filterDOMProps.js +27 -0
- package/dist/cjs/hooks/useEventHandler.d.ts +1 -0
- package/dist/cjs/hooks/useEventHandler.js +24 -0
- package/dist/cjs/hooks/useMove.d.ts +31 -0
- package/dist/cjs/hooks/useMove.js +173 -0
- package/dist/cjs/hooks/useResizeObserver.d.ts +8 -0
- package/dist/cjs/hooks/useResizeObserver.js +32 -0
- package/dist/esm/components/RangeDateSelection/RangeDateSelection.css +28 -0
- package/dist/esm/components/RangeDateSelection/RangeDateSelection.d.ts +24 -0
- package/dist/esm/components/RangeDateSelection/RangeDateSelection.js +43 -0
- package/dist/esm/components/RangeDateSelection/components/NowLine/NowLine.css +4 -0
- package/dist/esm/components/RangeDateSelection/components/NowLine/NowLine.d.ts +2 -0
- package/dist/esm/components/RangeDateSelection/components/NowLine/NowLine.js +36 -0
- package/dist/esm/components/RangeDateSelection/components/Ruler/Ruler.d.ts +32 -0
- package/dist/esm/components/RangeDateSelection/components/Ruler/Ruler.js +53 -0
- package/dist/esm/components/RangeDateSelection/components/RulerViewport/RulerViewport.css +25 -0
- package/dist/esm/components/RangeDateSelection/components/RulerViewport/RulerViewport.d.ts +13 -0
- package/dist/esm/components/RangeDateSelection/components/RulerViewport/RulerViewport.js +29 -0
- package/dist/esm/components/RangeDateSelection/components/SelectionControl/SelectionControl.css +78 -0
- package/dist/esm/components/RangeDateSelection/components/SelectionControl/SelectionControl.d.ts +8 -0
- package/dist/esm/components/RangeDateSelection/components/SelectionControl/SelectionControl.js +132 -0
- package/dist/esm/components/RangeDateSelection/components/Ticks/MiddleTicks.d.ts +3 -0
- package/dist/esm/components/RangeDateSelection/components/Ticks/MiddleTicks.js +7 -0
- package/dist/esm/components/RangeDateSelection/components/Ticks/SlitTicks.d.ts +5 -0
- package/dist/esm/components/RangeDateSelection/components/Ticks/SlitTicks.js +7 -0
- package/dist/esm/components/RangeDateSelection/components/Ticks/Ticks.css +16 -0
- package/dist/esm/components/RangeDateSelection/components/Ticks/Ticks.d.ts +18 -0
- package/dist/esm/components/RangeDateSelection/components/Ticks/Ticks.js +44 -0
- package/dist/esm/components/RangeDateSelection/components/Ticks/UnavialableTicks.d.ts +15 -0
- package/dist/esm/components/RangeDateSelection/components/Ticks/UnavialableTicks.js +42 -0
- package/dist/esm/components/RangeDateSelection/components/Ticks/utils.d.ts +24 -0
- package/dist/esm/components/RangeDateSelection/components/Ticks/utils.js +158 -0
- package/dist/esm/components/RangeDateSelection/hooks/useRangeDateSelectionState.d.ts +60 -0
- package/dist/esm/components/RangeDateSelection/hooks/useRangeDateSelectionState.js +144 -0
- package/dist/esm/components/RangeDateSelection/i18n/en.json +7 -0
- package/dist/esm/components/RangeDateSelection/i18n/index.d.ts +1 -0
- package/dist/esm/components/RangeDateSelection/i18n/index.js +5 -0
- package/dist/esm/components/RangeDateSelection/i18n/ru.json +7 -0
- package/dist/esm/components/RangeDateSelection/index.d.ts +3 -0
- package/dist/esm/components/RangeDateSelection/index.js +2 -0
- package/dist/esm/components/RangeDateSelection/utils/date.d.ts +2 -0
- package/dist/esm/components/RangeDateSelection/utils/date.js +7 -0
- package/dist/esm/components/RangeDateSelection/utils/span.d.ts +23 -0
- package/dist/esm/components/RangeDateSelection/utils/span.js +23 -0
- package/dist/esm/components/RelativeRangeDatePicker/components/Presets/i18n/index.d.ts +1 -1
- package/dist/esm/components/index.d.ts +1 -0
- package/dist/esm/components/index.js +1 -0
- package/dist/esm/components/mixins.css +0 -0
- package/dist/esm/components/utils/constants.d.ts +7 -0
- package/dist/esm/components/utils/constants.js +7 -0
- package/dist/esm/components/utils/filterDOMProps.d.ts +17 -0
- package/dist/esm/components/utils/filterDOMProps.js +24 -0
- package/dist/esm/hooks/useEventHandler.d.ts +1 -0
- package/dist/esm/hooks/useEventHandler.js +18 -0
- package/dist/esm/hooks/useMove.d.ts +31 -0
- package/dist/esm/hooks/useMove.js +167 -0
- package/dist/esm/hooks/useResizeObserver.d.ts +8 -0
- package/dist/esm/hooks/useResizeObserver.js +26 -0
- package/package.json +1 -1
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { DateTime } from '@gravity-ui/date-utils';
|
|
2
|
+
import type { RangeValue, ValueBase } from '../../types';
|
|
3
|
+
export interface RangeDateSelectionState {
|
|
4
|
+
viewportInterval: RangeValue<DateTime>;
|
|
5
|
+
value: RangeValue<DateTime>;
|
|
6
|
+
setValue: (value: RangeValue<DateTime>) => void;
|
|
7
|
+
timeZone: string;
|
|
8
|
+
setDraggingValue: (value: RangeValue<DateTime> | null) => void;
|
|
9
|
+
canResize: boolean;
|
|
10
|
+
startDragging: () => void;
|
|
11
|
+
move: (delta: number, options?: {
|
|
12
|
+
visualMinDuration?: number;
|
|
13
|
+
}) => void;
|
|
14
|
+
scale: (scale: number, options?: {
|
|
15
|
+
visualMinDuration?: number;
|
|
16
|
+
fixedPoint?: number;
|
|
17
|
+
}) => void;
|
|
18
|
+
moveStart: (delta: number, options?: {
|
|
19
|
+
visualMinDuration?: number;
|
|
20
|
+
}) => void;
|
|
21
|
+
moveEnd: (delta: number, options?: {
|
|
22
|
+
visualMinDuration?: number;
|
|
23
|
+
}) => void;
|
|
24
|
+
endDragging: () => void;
|
|
25
|
+
align: number;
|
|
26
|
+
isDragging: boolean;
|
|
27
|
+
}
|
|
28
|
+
export interface RangeDateSelectionOptions extends ValueBase<RangeValue<DateTime>> {
|
|
29
|
+
/** The minimum allowed date that a user may select. */
|
|
30
|
+
minValue?: DateTime;
|
|
31
|
+
/** The maximum allowed date that a user may select. */
|
|
32
|
+
maxValue?: DateTime;
|
|
33
|
+
/** Minimum duration of the selection in milliseconds. Defaults to 1 second. */
|
|
34
|
+
minDuration?: number;
|
|
35
|
+
/** Maximum duration of the selection in milliseconds. Defaults to 15 years. */
|
|
36
|
+
maxDuration?: number;
|
|
37
|
+
/** Alignment of the selection in milliseconds. Defaults to 1 second. */
|
|
38
|
+
align?: number;
|
|
39
|
+
/** A placeholder date that controls the default values of each segment when the user first interacts with them. Defaults to today's date at midnight. */
|
|
40
|
+
placeholderValue?: DateTime;
|
|
41
|
+
/**
|
|
42
|
+
* Which timezone use to show values. Example: 'default', 'system', 'Europe/Amsterdam'.
|
|
43
|
+
* @default The timezone of the `value` or `defaultValue` or `placeholderValue`, 'default' otherwise.
|
|
44
|
+
*/
|
|
45
|
+
timeZone?: string;
|
|
46
|
+
/**
|
|
47
|
+
* The number of selection intervals that fit into the underlying ruler.
|
|
48
|
+
*
|
|
49
|
+
* @default 4
|
|
50
|
+
*/
|
|
51
|
+
numberOfIntervals?: number;
|
|
52
|
+
/**
|
|
53
|
+
* Place of the selection on the underlying ruler.
|
|
54
|
+
* Value must be between 0 and 1, where 0 is the start of the ruler and 1 is the end.
|
|
55
|
+
*
|
|
56
|
+
* @default 0.5 - center of the ruler
|
|
57
|
+
*/
|
|
58
|
+
placeOnRuler?: number;
|
|
59
|
+
}
|
|
60
|
+
export declare function useRangeDateSelectionState(props: RangeDateSelectionOptions): RangeDateSelectionState;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useControlledState } from '@gravity-ui/uikit';
|
|
3
|
+
import { SECOND, YEAR } from '../../utils/constants';
|
|
4
|
+
import { constrainValue, createPlaceholderValue } from '../../utils/dates';
|
|
5
|
+
import { useDefaultTimeZone } from '../../utils/useDefaultTimeZone';
|
|
6
|
+
import { alignDateTime } from '../utils/date';
|
|
7
|
+
function getViewportIntervalFromDates(start, end, numberOfIntervals = 4, placeInViewport = 0.5) {
|
|
8
|
+
const diff = end.diff(start);
|
|
9
|
+
return {
|
|
10
|
+
start: start.subtract(diff * (numberOfIntervals - 1) * placeInViewport),
|
|
11
|
+
end: end.add(diff * (numberOfIntervals - 1) * (1 - placeInViewport)),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export function useRangeDateSelectionState(props) {
|
|
15
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
16
|
+
const inputTimeZone = useDefaultTimeZone(((_a = props.value) === null || _a === void 0 ? void 0 : _a.start) || ((_b = props.defaultValue) === null || _b === void 0 ? void 0 : _b.start) || props.placeholderValue);
|
|
17
|
+
const timeZone = props.timeZone || inputTimeZone;
|
|
18
|
+
const placeholderValue = createPlaceholderValue({
|
|
19
|
+
placeholderValue: props.placeholderValue,
|
|
20
|
+
timeZone,
|
|
21
|
+
});
|
|
22
|
+
const [isDragging, setIsDragging] = React.useState(false);
|
|
23
|
+
const [currentValue, setCurrentValue] = React.useState(null);
|
|
24
|
+
const [value, setValue] = useControlledState(props.value, (_c = props.defaultValue) !== null && _c !== void 0 ? _c : {
|
|
25
|
+
start: placeholderValue.startOf('day').timeZone(inputTimeZone),
|
|
26
|
+
end: placeholderValue.endOf('day').timeZone(inputTimeZone),
|
|
27
|
+
}, props.onUpdate);
|
|
28
|
+
const setInterval = (newValue) => {
|
|
29
|
+
setCurrentValue(null);
|
|
30
|
+
setValue({
|
|
31
|
+
start: alignDateTime(newValue.start, props.align).timeZone(inputTimeZone),
|
|
32
|
+
end: alignDateTime(newValue.end, props.align).timeZone(inputTimeZone),
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
const displayValue = {
|
|
36
|
+
start: value.start.timeZone(timeZone),
|
|
37
|
+
end: value.end.timeZone(timeZone),
|
|
38
|
+
};
|
|
39
|
+
const interval = isDragging ? displayValue : currentValue !== null && currentValue !== void 0 ? currentValue : displayValue;
|
|
40
|
+
const viewportInterval = getViewportIntervalFromDates(interval.start, interval.end, props.numberOfIntervals, props.placeOnRuler);
|
|
41
|
+
const minValue = ((_d = props.minValue) === null || _d === void 0 ? void 0 : _d.isAfter(viewportInterval.start))
|
|
42
|
+
? props.minValue
|
|
43
|
+
: viewportInterval.start;
|
|
44
|
+
const maxValue = ((_e = props.maxValue) === null || _e === void 0 ? void 0 : _e.isBefore(viewportInterval.end))
|
|
45
|
+
? props.maxValue
|
|
46
|
+
: viewportInterval.end;
|
|
47
|
+
const align = (_f = props.align) !== null && _f !== void 0 ? _f : SECOND;
|
|
48
|
+
const minDuration = Math.max((_g = props.minDuration) !== null && _g !== void 0 ? _g : SECOND, align);
|
|
49
|
+
const maxDuration = Math.max(Math.min((_h = props.maxDuration) !== null && _h !== void 0 ? _h : 15 * YEAR, maxValue.diff(minValue)), minDuration);
|
|
50
|
+
const canResize = minDuration < maxDuration;
|
|
51
|
+
const draggingState = React.useRef(null);
|
|
52
|
+
const setDraggingValue = (v) => {
|
|
53
|
+
draggingState.current = v;
|
|
54
|
+
setCurrentValue(v);
|
|
55
|
+
};
|
|
56
|
+
const startDragging = () => {
|
|
57
|
+
setIsDragging(true);
|
|
58
|
+
setDraggingValue(displayValue);
|
|
59
|
+
};
|
|
60
|
+
const endDragging = () => {
|
|
61
|
+
setIsDragging(false);
|
|
62
|
+
if (draggingState.current) {
|
|
63
|
+
setInterval(draggingState.current);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
const moveInterval = (delta) => {
|
|
67
|
+
if (!draggingState.current) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const { start, end } = draggingState.current;
|
|
71
|
+
let newStart = start.add(delta, 'millisecond');
|
|
72
|
+
let newEnd = end.add(delta, 'millisecond');
|
|
73
|
+
const diff = newEnd.diff(newStart);
|
|
74
|
+
if (newStart.valueOf() < minValue.valueOf()) {
|
|
75
|
+
newStart = minValue;
|
|
76
|
+
newEnd = constrainValue(newStart.add(diff, 'millisecond'), newStart, maxValue);
|
|
77
|
+
}
|
|
78
|
+
else if (newEnd.valueOf() > maxValue.valueOf()) {
|
|
79
|
+
newEnd = maxValue;
|
|
80
|
+
newStart = constrainValue(newEnd.subtract(diff, 'millisecond'), minValue, newEnd);
|
|
81
|
+
}
|
|
82
|
+
setDraggingValue({ start: newStart, end: newEnd });
|
|
83
|
+
};
|
|
84
|
+
const moveStart = (delta, { visualMinDuration = minDuration } = {}) => {
|
|
85
|
+
if (!draggingState.current) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const { start, end } = draggingState.current;
|
|
89
|
+
let newStart = start.add(delta, 'millisecond');
|
|
90
|
+
const deltaMin = Math.max(visualMinDuration, minDuration);
|
|
91
|
+
const deltaMax = Math.min(maxDuration, end.diff(minValue));
|
|
92
|
+
newStart = constrainValue(newStart, end.subtract(deltaMax, 'millisecond'), end.subtract(deltaMin, 'millisecond'));
|
|
93
|
+
setDraggingValue({ start: newStart, end });
|
|
94
|
+
};
|
|
95
|
+
const moveEnd = (delta, { visualMinDuration = minDuration } = {}) => {
|
|
96
|
+
if (!draggingState.current) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const { start, end } = draggingState.current;
|
|
100
|
+
let newEnd = end.add(delta, 'millisecond');
|
|
101
|
+
const deltaMin = Math.max(visualMinDuration, minDuration);
|
|
102
|
+
const deltaMax = Math.min(maxDuration, maxValue.diff(start));
|
|
103
|
+
newEnd = constrainValue(end.add(delta, 'millisecond'), start.add(deltaMin, 'millisecond'), start.add(deltaMax, 'millisecond'));
|
|
104
|
+
setDraggingValue({ start, end: newEnd });
|
|
105
|
+
};
|
|
106
|
+
const zoomInterval = (scale, { visualMinDuration = minDuration, fixedPoint = 0.5, } = {}) => {
|
|
107
|
+
if (!draggingState.current) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const { start, end } = draggingState.current;
|
|
111
|
+
const len = end.diff(start);
|
|
112
|
+
let newDiff = len * scale;
|
|
113
|
+
newDiff = align * Math.round(newDiff / align);
|
|
114
|
+
newDiff = Math.min(Math.max(newDiff, Math.max(visualMinDuration, minDuration)), maxDuration);
|
|
115
|
+
let newStart = start.subtract(fixedPoint * (newDiff - len));
|
|
116
|
+
let newEnd = newStart.add(newDiff, 'millisecond');
|
|
117
|
+
const diff = newEnd.diff(newStart);
|
|
118
|
+
if (newStart.valueOf() < minValue.valueOf()) {
|
|
119
|
+
newStart = minValue;
|
|
120
|
+
newEnd = constrainValue(newStart.add(diff, 'millisecond'), newStart, maxValue);
|
|
121
|
+
}
|
|
122
|
+
else if (newEnd.valueOf() > maxValue.valueOf()) {
|
|
123
|
+
newEnd = maxValue;
|
|
124
|
+
newStart = constrainValue(newEnd.subtract(diff, 'millisecond'), minValue, newEnd);
|
|
125
|
+
}
|
|
126
|
+
setDraggingValue({ start: newStart, end: newEnd });
|
|
127
|
+
};
|
|
128
|
+
return {
|
|
129
|
+
viewportInterval,
|
|
130
|
+
value: currentValue !== null && currentValue !== void 0 ? currentValue : displayValue,
|
|
131
|
+
setValue: setInterval,
|
|
132
|
+
setDraggingValue,
|
|
133
|
+
canResize,
|
|
134
|
+
startDragging,
|
|
135
|
+
move: moveInterval,
|
|
136
|
+
scale: zoomInterval,
|
|
137
|
+
moveStart,
|
|
138
|
+
moveEnd,
|
|
139
|
+
endDragging,
|
|
140
|
+
timeZone,
|
|
141
|
+
align,
|
|
142
|
+
isDragging,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const i18n: (key: "Range" | "Start of range" | "End of range" | "Increase range" | "Decrease range", params?: import("@gravity-ui/i18n").Params | undefined) => string;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { dateTimeUtc } from '@gravity-ui/date-utils';
|
|
2
|
+
import { SECOND } from '../../utils/constants';
|
|
3
|
+
export function alignDateTime(date, align = SECOND) {
|
|
4
|
+
return dateTimeUtc({
|
|
5
|
+
input: Math.round(date.utc(true).valueOf() / align) * align,
|
|
6
|
+
}).timeZone(date.timeZone(), true);
|
|
7
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface Span {
|
|
2
|
+
start: number;
|
|
3
|
+
end: number;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Implements linear interpolation (lerp).
|
|
7
|
+
*
|
|
8
|
+
* Calculates such a linear mapping `R -> R` that `from.start` will be mapped
|
|
9
|
+
* into `to.start`, and `from.end` will be mapped to `to.end`. Then applies
|
|
10
|
+
* this mapping to `value`.
|
|
11
|
+
* @param from Interpolation domain
|
|
12
|
+
* @param to Interpolation target
|
|
13
|
+
* @param value Value from domain
|
|
14
|
+
* @returns Value from target
|
|
15
|
+
*/
|
|
16
|
+
export declare function lerp(from: Span, to: Span, value: number): number;
|
|
17
|
+
/**
|
|
18
|
+
* Calculates a lerp scale coefficient
|
|
19
|
+
* @param from Interpolation domain
|
|
20
|
+
* @param to Interpolation target
|
|
21
|
+
* @returns Scale coefficient
|
|
22
|
+
*/
|
|
23
|
+
export declare function getLerpCoeff(from: Span, to: Span): number;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Implements linear interpolation (lerp).
|
|
3
|
+
*
|
|
4
|
+
* Calculates such a linear mapping `R -> R` that `from.start` will be mapped
|
|
5
|
+
* into `to.start`, and `from.end` will be mapped to `to.end`. Then applies
|
|
6
|
+
* this mapping to `value`.
|
|
7
|
+
* @param from Interpolation domain
|
|
8
|
+
* @param to Interpolation target
|
|
9
|
+
* @param value Value from domain
|
|
10
|
+
* @returns Value from target
|
|
11
|
+
*/
|
|
12
|
+
export function lerp(from, to, value) {
|
|
13
|
+
return to.start + ((value - from.start) * (to.end - to.start)) / (from.end - from.start);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Calculates a lerp scale coefficient
|
|
17
|
+
* @param from Interpolation domain
|
|
18
|
+
* @param to Interpolation target
|
|
19
|
+
* @returns Scale coefficient
|
|
20
|
+
*/
|
|
21
|
+
export function getLerpCoeff(from, to) {
|
|
22
|
+
return (to.end - to.start) / (from.end - from.start);
|
|
23
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const i18n: (key: "Last 5 minutes" | "Last 15 minutes" | "Last 30 minutes" | "Last hour" | "Last 3 hours" | "Last 6 hours" | "Last 12 hours" | "Last day" | "Last 3 days" | "Last week" | "Last month" | "Last 3 months" | "Last 6 months" | "Last year" | "Last 3 years" | "Today" | "Yesterday" | "Day before yesterday" | "This week" | "This month" | "This year" | "From start of day" | "From start of week" | "From start of month" | "From start of year" | "Previous month" | "Last second" | "Last minute" | "Main" | "Other" | "
|
|
1
|
+
export declare const i18n: (key: "Range" | "Last 5 minutes" | "Last 15 minutes" | "Last 30 minutes" | "Last hour" | "Last 3 hours" | "Last 6 hours" | "Last 12 hours" | "Last day" | "Last 3 days" | "Last week" | "Last month" | "Last 3 months" | "Last 6 months" | "Last year" | "Last 3 years" | "Today" | "Yesterday" | "Day before yesterday" | "This week" | "This month" | "This year" | "From start of day" | "From start of week" | "From start of month" | "From start of year" | "Previous month" | "Last second" | "Last minute" | "Main" | "Other" | "From" | "To" | "Last {count} second" | "Last {count} minute" | "Last {count} hour" | "Last {count} day" | "Last {count} week" | "Last {count} month" | "Last {count} year", params?: import("@gravity-ui/i18n").Params | undefined) => string;
|
|
@@ -3,6 +3,7 @@ export * from './RangeCalendar';
|
|
|
3
3
|
export * from './DateField';
|
|
4
4
|
export * from './DatePicker';
|
|
5
5
|
export * from './RangeDatePicker';
|
|
6
|
+
export * from './RangeDateSelection';
|
|
6
7
|
export * from './RelativeDateField';
|
|
7
8
|
export * from './RelativeDatePicker';
|
|
8
9
|
export * from './RangeDateField';
|
|
@@ -3,6 +3,7 @@ export * from './RangeCalendar';
|
|
|
3
3
|
export * from './DateField';
|
|
4
4
|
export * from './DatePicker';
|
|
5
5
|
export * from './RangeDatePicker';
|
|
6
|
+
export * from './RangeDateSelection';
|
|
6
7
|
export * from './RelativeDateField';
|
|
7
8
|
export * from './RelativeDatePicker';
|
|
8
9
|
export * from './RangeDateField';
|
|
File without changes
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AccessibilityProps } from '../types';
|
|
2
|
+
interface Options {
|
|
3
|
+
/**
|
|
4
|
+
* If labelling associated aria properties should be included in the filter.
|
|
5
|
+
*/
|
|
6
|
+
labelable?: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* A Set of other property names that should be included in the filter.
|
|
9
|
+
*/
|
|
10
|
+
propNames?: Set<string>;
|
|
11
|
+
}
|
|
12
|
+
export declare function filterDOMProps(props: {
|
|
13
|
+
id?: string;
|
|
14
|
+
} & AccessibilityProps, options?: Options): {
|
|
15
|
+
id?: string;
|
|
16
|
+
} & AccessibilityProps;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const DOMPropNames = new Set(['id']);
|
|
2
|
+
const labelablePropNames = new Set([
|
|
3
|
+
'aria-label',
|
|
4
|
+
'aria-labelledby',
|
|
5
|
+
'aria-describedby',
|
|
6
|
+
'aria-details',
|
|
7
|
+
]);
|
|
8
|
+
const propRe = /^(data-.*)$/;
|
|
9
|
+
/* FIXME: use the same function from @gravity-ui/uikit */
|
|
10
|
+
export function filterDOMProps(props, options = {}) {
|
|
11
|
+
const { labelable, propNames } = options;
|
|
12
|
+
const filteredProps = {};
|
|
13
|
+
for (const prop in props) {
|
|
14
|
+
if (Object.prototype.hasOwnProperty.call(props, prop) &&
|
|
15
|
+
(DOMPropNames.has(prop) ||
|
|
16
|
+
(labelable && labelablePropNames.has(prop)) ||
|
|
17
|
+
(propNames === null || propNames === void 0 ? void 0 : propNames.has(prop)) ||
|
|
18
|
+
propRe.test(prop))) {
|
|
19
|
+
// @ts-expect-error
|
|
20
|
+
filteredProps[prop] = props[prop];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return filteredProps;
|
|
24
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function useEventHandler<T extends Function>(handler?: T): T;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
/*
|
|
3
|
+
* TODO: move to @gravity-ui/uikit
|
|
4
|
+
* The hook returns a stable function (an empty list of dependencies),
|
|
5
|
+
* but this function always calls the actual function associated with the last render.
|
|
6
|
+
* The returned function should be used as an event handler or inside a useEffect.
|
|
7
|
+
*/
|
|
8
|
+
export function useEventHandler(handler) {
|
|
9
|
+
const ref = React.useRef(handler);
|
|
10
|
+
React.useLayoutEffect(() => {
|
|
11
|
+
ref.current = handler;
|
|
12
|
+
}, [handler]);
|
|
13
|
+
// @ts-expect-error
|
|
14
|
+
return React.useCallback((...args) => {
|
|
15
|
+
var _a;
|
|
16
|
+
return (_a = ref.current) === null || _a === void 0 ? void 0 : _a.call(ref, ...args);
|
|
17
|
+
}, []);
|
|
18
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export type PointerType = 'mouse' | 'pen' | 'touch' | 'keyboard';
|
|
3
|
+
interface EventBase {
|
|
4
|
+
shiftKey: boolean;
|
|
5
|
+
ctrlKey: boolean;
|
|
6
|
+
metaKey: boolean;
|
|
7
|
+
altKey: boolean;
|
|
8
|
+
}
|
|
9
|
+
interface BaseMoveEvent extends EventBase {
|
|
10
|
+
pointerType: PointerType;
|
|
11
|
+
}
|
|
12
|
+
export interface MoveStartEvent extends BaseMoveEvent {
|
|
13
|
+
type: 'movestart';
|
|
14
|
+
}
|
|
15
|
+
export interface MoveMoveEvent extends BaseMoveEvent {
|
|
16
|
+
type: 'move';
|
|
17
|
+
deltaX: number;
|
|
18
|
+
deltaY: number;
|
|
19
|
+
}
|
|
20
|
+
export interface MoveEndEvent extends BaseMoveEvent {
|
|
21
|
+
type: 'moveend';
|
|
22
|
+
}
|
|
23
|
+
export interface MoveEvents {
|
|
24
|
+
onMoveStart?: (e: MoveStartEvent) => void;
|
|
25
|
+
onMove?: (e: MoveMoveEvent) => void;
|
|
26
|
+
onMoveEnd?: (e: MoveEndEvent) => void;
|
|
27
|
+
}
|
|
28
|
+
export declare function useMove(props: MoveEvents): {
|
|
29
|
+
moveProps: React.DOMAttributes<HTMLElement>;
|
|
30
|
+
};
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useEventHandler } from './useEventHandler';
|
|
3
|
+
export function useMove(props) {
|
|
4
|
+
const { onMoveStart, onMove, onMoveEnd } = props;
|
|
5
|
+
const state = React.useRef({
|
|
6
|
+
isMoving: false,
|
|
7
|
+
lastPosition: null,
|
|
8
|
+
id: null,
|
|
9
|
+
});
|
|
10
|
+
const move = useEventHandler((originalEvent, deltaX, deltaY, pointerType) => {
|
|
11
|
+
if (deltaX === 0 && deltaY === 0) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
if (!state.current.isMoving) {
|
|
15
|
+
state.current.isMoving = true;
|
|
16
|
+
onMoveStart === null || onMoveStart === void 0 ? void 0 : onMoveStart({
|
|
17
|
+
type: 'movestart',
|
|
18
|
+
pointerType,
|
|
19
|
+
shiftKey: originalEvent.shiftKey,
|
|
20
|
+
ctrlKey: originalEvent.ctrlKey,
|
|
21
|
+
metaKey: originalEvent.metaKey,
|
|
22
|
+
altKey: originalEvent.altKey,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
onMove === null || onMove === void 0 ? void 0 : onMove({
|
|
26
|
+
type: 'move',
|
|
27
|
+
pointerType,
|
|
28
|
+
deltaX,
|
|
29
|
+
deltaY,
|
|
30
|
+
shiftKey: originalEvent.shiftKey,
|
|
31
|
+
ctrlKey: originalEvent.ctrlKey,
|
|
32
|
+
metaKey: originalEvent.metaKey,
|
|
33
|
+
altKey: originalEvent.altKey,
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
const end = useEventHandler((originalEvent, pointerType) => {
|
|
37
|
+
if (state.current.isMoving) {
|
|
38
|
+
state.current.isMoving = false;
|
|
39
|
+
onMoveEnd === null || onMoveEnd === void 0 ? void 0 : onMoveEnd({
|
|
40
|
+
type: 'moveend',
|
|
41
|
+
pointerType,
|
|
42
|
+
shiftKey: originalEvent.shiftKey,
|
|
43
|
+
ctrlKey: originalEvent.ctrlKey,
|
|
44
|
+
metaKey: originalEvent.metaKey,
|
|
45
|
+
altKey: originalEvent.altKey,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
return React.useMemo(() => {
|
|
50
|
+
const moveProps = {};
|
|
51
|
+
if (typeof PointerEvent === 'undefined') {
|
|
52
|
+
moveProps.onMouseDown = (e) => {
|
|
53
|
+
if (e.button === 0) {
|
|
54
|
+
state.current.isMoving = false;
|
|
55
|
+
e.preventDefault();
|
|
56
|
+
state.current.lastPosition = { pageX: e.pageX, pageY: e.pageY };
|
|
57
|
+
const handleMouseMove = (ev) => {
|
|
58
|
+
var _a, _b;
|
|
59
|
+
if (ev.buttons === 0) {
|
|
60
|
+
move(ev, ev.pageX - (((_a = state.current.lastPosition) === null || _a === void 0 ? void 0 : _a.pageX) || 0), ev.pageY - (((_b = state.current.lastPosition) === null || _b === void 0 ? void 0 : _b.pageY) || 0), 'mouse');
|
|
61
|
+
state.current.lastPosition = { pageX: ev.pageX, pageY: ev.pageY };
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
const handleMouseUp = (ev) => {
|
|
65
|
+
if (ev.button === 0) {
|
|
66
|
+
end(ev, 'mouse');
|
|
67
|
+
window.removeEventListener('mousemove', handleMouseMove);
|
|
68
|
+
window.removeEventListener('mouseup', handleMouseUp);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
window.addEventListener('mousemove', handleMouseMove);
|
|
72
|
+
window.addEventListener('mouseup', handleMouseUp);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
moveProps.onTouchStart = (e) => {
|
|
76
|
+
if (e.touches.length === 0 || state.current.id !== null) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const { pageX, pageY, identifier } = e.touches[0];
|
|
80
|
+
state.current.id = identifier;
|
|
81
|
+
state.current.lastPosition = { pageX, pageY };
|
|
82
|
+
e.preventDefault();
|
|
83
|
+
const handleTouchMove = (ev) => {
|
|
84
|
+
var _a, _b;
|
|
85
|
+
const touch = [...ev.changedTouches].findIndex((el) => el.identifier === state.current.id);
|
|
86
|
+
if (touch !== -1) {
|
|
87
|
+
const { pageX, pageY } = e.changedTouches[touch];
|
|
88
|
+
move(ev, pageX - (((_a = state.current.lastPosition) === null || _a === void 0 ? void 0 : _a.pageX) || 0), pageY - (((_b = state.current.lastPosition) === null || _b === void 0 ? void 0 : _b.pageY) || 0), 'touch');
|
|
89
|
+
state.current.lastPosition = { pageX, pageY };
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
const handleTouchEnd = (ev) => {
|
|
93
|
+
const touch = [...ev.changedTouches].findIndex((el) => el.identifier === state.current.id);
|
|
94
|
+
if (touch !== -1) {
|
|
95
|
+
end(ev, 'touch');
|
|
96
|
+
state.current.id = null;
|
|
97
|
+
window.removeEventListener('touchmove', handleTouchMove);
|
|
98
|
+
window.removeEventListener('touchend', handleTouchEnd);
|
|
99
|
+
window.removeEventListener('touchcancel', handleTouchEnd);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
window.addEventListener('touchmove', handleTouchMove);
|
|
103
|
+
window.addEventListener('touchend', handleTouchEnd);
|
|
104
|
+
window.addEventListener('touchcancel', handleTouchEnd);
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
moveProps.onPointerDown = (e) => {
|
|
109
|
+
if (e.button === 0 && state.current.id === null) {
|
|
110
|
+
e.preventDefault();
|
|
111
|
+
state.current.isMoving = false;
|
|
112
|
+
state.current.id = e.pointerId;
|
|
113
|
+
state.current.lastPosition = { pageX: e.pageX, pageY: e.pageY };
|
|
114
|
+
const handlePointerMove = (ev) => {
|
|
115
|
+
var _a, _b;
|
|
116
|
+
if (ev.pointerId === state.current.id) {
|
|
117
|
+
move(ev, ev.pageX - (((_a = state.current.lastPosition) === null || _a === void 0 ? void 0 : _a.pageX) || 0), ev.pageY - (((_b = state.current.lastPosition) === null || _b === void 0 ? void 0 : _b.pageY) || 0), (ev.pointerType || 'mouse'));
|
|
118
|
+
state.current.lastPosition = { pageX: ev.pageX, pageY: ev.pageY };
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
const handlePointerUp = (ev) => {
|
|
122
|
+
if (ev.pointerId === state.current.id) {
|
|
123
|
+
end(ev, (ev.pointerType || 'mouse'));
|
|
124
|
+
state.current.id = null;
|
|
125
|
+
window.removeEventListener('pointermove', handlePointerMove);
|
|
126
|
+
window.removeEventListener('pointerup', handlePointerUp);
|
|
127
|
+
window.removeEventListener('pointercancel', handlePointerUp);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
window.addEventListener('pointermove', handlePointerMove);
|
|
131
|
+
window.addEventListener('pointerup', handlePointerUp);
|
|
132
|
+
window.addEventListener('pointercancel', handlePointerUp);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
const handleKeyboardMove = (e, deltaX, deltaY) => {
|
|
137
|
+
state.current.isMoving = false;
|
|
138
|
+
move(e, deltaX, deltaY, 'keyboard');
|
|
139
|
+
end(e, 'keyboard');
|
|
140
|
+
};
|
|
141
|
+
moveProps.onKeyDown = (e) => {
|
|
142
|
+
switch (e.key) {
|
|
143
|
+
case 'ArrowLeft': {
|
|
144
|
+
e.preventDefault();
|
|
145
|
+
handleKeyboardMove(e, -1, 0);
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
case 'ArrowRight': {
|
|
149
|
+
e.preventDefault();
|
|
150
|
+
handleKeyboardMove(e, 1, 0);
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
case 'ArrowUp': {
|
|
154
|
+
e.preventDefault();
|
|
155
|
+
handleKeyboardMove(e, 0, -1);
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
case 'ArrowDown': {
|
|
159
|
+
e.preventDefault();
|
|
160
|
+
handleKeyboardMove(e, 0, 1);
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
return { moveProps };
|
|
166
|
+
}, [end, move]);
|
|
167
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface UseResizeObserverProps<T> {
|
|
3
|
+
ref: React.RefObject<T | null | undefined> | undefined;
|
|
4
|
+
onResize: () => void;
|
|
5
|
+
box?: ResizeObserverBoxOptions;
|
|
6
|
+
}
|
|
7
|
+
export declare function useResizeObserver<T extends Element>({ ref, onResize, box, }: UseResizeObserverProps<T>): void;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
/* FIXME: use the same hook from @gravity-ui/uikit */
|
|
3
|
+
export function useResizeObserver({ ref, onResize, box, }) {
|
|
4
|
+
React.useEffect(() => {
|
|
5
|
+
const element = ref === null || ref === void 0 ? void 0 : ref.current;
|
|
6
|
+
if (!element) {
|
|
7
|
+
return undefined;
|
|
8
|
+
}
|
|
9
|
+
if (typeof window.ResizeObserver === 'undefined') {
|
|
10
|
+
window.addEventListener('resize', onResize, false);
|
|
11
|
+
return () => {
|
|
12
|
+
window.removeEventListener('resize', onResize, false);
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
const observer = new ResizeObserver((entries) => {
|
|
16
|
+
if (!entries.length) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
onResize();
|
|
20
|
+
});
|
|
21
|
+
observer.observe(element, { box });
|
|
22
|
+
return () => {
|
|
23
|
+
observer.disconnect();
|
|
24
|
+
};
|
|
25
|
+
}, [ref, onResize, box]);
|
|
26
|
+
}
|