@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
|
@@ -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';
|
|
@@ -19,6 +19,7 @@ __exportStar(require("./RangeCalendar"), exports);
|
|
|
19
19
|
__exportStar(require("./DateField"), exports);
|
|
20
20
|
__exportStar(require("./DatePicker"), exports);
|
|
21
21
|
__exportStar(require("./RangeDatePicker"), exports);
|
|
22
|
+
__exportStar(require("./RangeDateSelection"), exports);
|
|
22
23
|
__exportStar(require("./RelativeDateField"), exports);
|
|
23
24
|
__exportStar(require("./RelativeDatePicker"), exports);
|
|
24
25
|
__exportStar(require("./RangeDateField"), exports);
|
|
File without changes
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.YEAR = exports.MONTH = exports.WEEK = exports.DAY = exports.HOUR = exports.MINUTE = exports.SECOND = void 0;
|
|
4
|
+
exports.SECOND = 1000;
|
|
5
|
+
exports.MINUTE = 60 * exports.SECOND;
|
|
6
|
+
exports.HOUR = 60 * exports.MINUTE;
|
|
7
|
+
exports.DAY = 24 * exports.HOUR;
|
|
8
|
+
exports.WEEK = 7 * exports.DAY;
|
|
9
|
+
exports.MONTH = 30 * exports.DAY;
|
|
10
|
+
exports.YEAR = 365 * exports.DAY;
|
|
@@ -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,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.filterDOMProps = filterDOMProps;
|
|
4
|
+
const DOMPropNames = new Set(['id']);
|
|
5
|
+
const labelablePropNames = new Set([
|
|
6
|
+
'aria-label',
|
|
7
|
+
'aria-labelledby',
|
|
8
|
+
'aria-describedby',
|
|
9
|
+
'aria-details',
|
|
10
|
+
]);
|
|
11
|
+
const propRe = /^(data-.*)$/;
|
|
12
|
+
/* FIXME: use the same function from @gravity-ui/uikit */
|
|
13
|
+
function filterDOMProps(props, options = {}) {
|
|
14
|
+
const { labelable, propNames } = options;
|
|
15
|
+
const filteredProps = {};
|
|
16
|
+
for (const prop in props) {
|
|
17
|
+
if (Object.prototype.hasOwnProperty.call(props, prop) &&
|
|
18
|
+
(DOMPropNames.has(prop) ||
|
|
19
|
+
(labelable && labelablePropNames.has(prop)) ||
|
|
20
|
+
(propNames === null || propNames === void 0 ? void 0 : propNames.has(prop)) ||
|
|
21
|
+
propRe.test(prop))) {
|
|
22
|
+
// @ts-expect-error
|
|
23
|
+
filteredProps[prop] = props[prop];
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return filteredProps;
|
|
27
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function useEventHandler<T extends Function>(handler?: T): T;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.useEventHandler = useEventHandler;
|
|
7
|
+
const react_1 = __importDefault(require("react"));
|
|
8
|
+
/*
|
|
9
|
+
* TODO: move to @gravity-ui/uikit
|
|
10
|
+
* The hook returns a stable function (an empty list of dependencies),
|
|
11
|
+
* but this function always calls the actual function associated with the last render.
|
|
12
|
+
* The returned function should be used as an event handler or inside a useEffect.
|
|
13
|
+
*/
|
|
14
|
+
function useEventHandler(handler) {
|
|
15
|
+
const ref = react_1.default.useRef(handler);
|
|
16
|
+
react_1.default.useLayoutEffect(() => {
|
|
17
|
+
ref.current = handler;
|
|
18
|
+
}, [handler]);
|
|
19
|
+
// @ts-expect-error
|
|
20
|
+
return react_1.default.useCallback((...args) => {
|
|
21
|
+
var _a;
|
|
22
|
+
return (_a = ref.current) === null || _a === void 0 ? void 0 : _a.call(ref, ...args);
|
|
23
|
+
}, []);
|
|
24
|
+
}
|
|
@@ -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,173 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.useMove = useMove;
|
|
7
|
+
const react_1 = __importDefault(require("react"));
|
|
8
|
+
const useEventHandler_1 = require("./useEventHandler");
|
|
9
|
+
function useMove(props) {
|
|
10
|
+
const { onMoveStart, onMove, onMoveEnd } = props;
|
|
11
|
+
const state = react_1.default.useRef({
|
|
12
|
+
isMoving: false,
|
|
13
|
+
lastPosition: null,
|
|
14
|
+
id: null,
|
|
15
|
+
});
|
|
16
|
+
const move = (0, useEventHandler_1.useEventHandler)((originalEvent, deltaX, deltaY, pointerType) => {
|
|
17
|
+
if (deltaX === 0 && deltaY === 0) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
if (!state.current.isMoving) {
|
|
21
|
+
state.current.isMoving = true;
|
|
22
|
+
onMoveStart === null || onMoveStart === void 0 ? void 0 : onMoveStart({
|
|
23
|
+
type: 'movestart',
|
|
24
|
+
pointerType,
|
|
25
|
+
shiftKey: originalEvent.shiftKey,
|
|
26
|
+
ctrlKey: originalEvent.ctrlKey,
|
|
27
|
+
metaKey: originalEvent.metaKey,
|
|
28
|
+
altKey: originalEvent.altKey,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
onMove === null || onMove === void 0 ? void 0 : onMove({
|
|
32
|
+
type: 'move',
|
|
33
|
+
pointerType,
|
|
34
|
+
deltaX,
|
|
35
|
+
deltaY,
|
|
36
|
+
shiftKey: originalEvent.shiftKey,
|
|
37
|
+
ctrlKey: originalEvent.ctrlKey,
|
|
38
|
+
metaKey: originalEvent.metaKey,
|
|
39
|
+
altKey: originalEvent.altKey,
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
const end = (0, useEventHandler_1.useEventHandler)((originalEvent, pointerType) => {
|
|
43
|
+
if (state.current.isMoving) {
|
|
44
|
+
state.current.isMoving = false;
|
|
45
|
+
onMoveEnd === null || onMoveEnd === void 0 ? void 0 : onMoveEnd({
|
|
46
|
+
type: 'moveend',
|
|
47
|
+
pointerType,
|
|
48
|
+
shiftKey: originalEvent.shiftKey,
|
|
49
|
+
ctrlKey: originalEvent.ctrlKey,
|
|
50
|
+
metaKey: originalEvent.metaKey,
|
|
51
|
+
altKey: originalEvent.altKey,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
return react_1.default.useMemo(() => {
|
|
56
|
+
const moveProps = {};
|
|
57
|
+
if (typeof PointerEvent === 'undefined') {
|
|
58
|
+
moveProps.onMouseDown = (e) => {
|
|
59
|
+
if (e.button === 0) {
|
|
60
|
+
state.current.isMoving = false;
|
|
61
|
+
e.preventDefault();
|
|
62
|
+
state.current.lastPosition = { pageX: e.pageX, pageY: e.pageY };
|
|
63
|
+
const handleMouseMove = (ev) => {
|
|
64
|
+
var _a, _b;
|
|
65
|
+
if (ev.buttons === 0) {
|
|
66
|
+
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');
|
|
67
|
+
state.current.lastPosition = { pageX: ev.pageX, pageY: ev.pageY };
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
const handleMouseUp = (ev) => {
|
|
71
|
+
if (ev.button === 0) {
|
|
72
|
+
end(ev, 'mouse');
|
|
73
|
+
window.removeEventListener('mousemove', handleMouseMove);
|
|
74
|
+
window.removeEventListener('mouseup', handleMouseUp);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
window.addEventListener('mousemove', handleMouseMove);
|
|
78
|
+
window.addEventListener('mouseup', handleMouseUp);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
moveProps.onTouchStart = (e) => {
|
|
82
|
+
if (e.touches.length === 0 || state.current.id !== null) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const { pageX, pageY, identifier } = e.touches[0];
|
|
86
|
+
state.current.id = identifier;
|
|
87
|
+
state.current.lastPosition = { pageX, pageY };
|
|
88
|
+
e.preventDefault();
|
|
89
|
+
const handleTouchMove = (ev) => {
|
|
90
|
+
var _a, _b;
|
|
91
|
+
const touch = [...ev.changedTouches].findIndex((el) => el.identifier === state.current.id);
|
|
92
|
+
if (touch !== -1) {
|
|
93
|
+
const { pageX, pageY } = e.changedTouches[touch];
|
|
94
|
+
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');
|
|
95
|
+
state.current.lastPosition = { pageX, pageY };
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
const handleTouchEnd = (ev) => {
|
|
99
|
+
const touch = [...ev.changedTouches].findIndex((el) => el.identifier === state.current.id);
|
|
100
|
+
if (touch !== -1) {
|
|
101
|
+
end(ev, 'touch');
|
|
102
|
+
state.current.id = null;
|
|
103
|
+
window.removeEventListener('touchmove', handleTouchMove);
|
|
104
|
+
window.removeEventListener('touchend', handleTouchEnd);
|
|
105
|
+
window.removeEventListener('touchcancel', handleTouchEnd);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
window.addEventListener('touchmove', handleTouchMove);
|
|
109
|
+
window.addEventListener('touchend', handleTouchEnd);
|
|
110
|
+
window.addEventListener('touchcancel', handleTouchEnd);
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
moveProps.onPointerDown = (e) => {
|
|
115
|
+
if (e.button === 0 && state.current.id === null) {
|
|
116
|
+
e.preventDefault();
|
|
117
|
+
state.current.isMoving = false;
|
|
118
|
+
state.current.id = e.pointerId;
|
|
119
|
+
state.current.lastPosition = { pageX: e.pageX, pageY: e.pageY };
|
|
120
|
+
const handlePointerMove = (ev) => {
|
|
121
|
+
var _a, _b;
|
|
122
|
+
if (ev.pointerId === state.current.id) {
|
|
123
|
+
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'));
|
|
124
|
+
state.current.lastPosition = { pageX: ev.pageX, pageY: ev.pageY };
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
const handlePointerUp = (ev) => {
|
|
128
|
+
if (ev.pointerId === state.current.id) {
|
|
129
|
+
end(ev, (ev.pointerType || 'mouse'));
|
|
130
|
+
state.current.id = null;
|
|
131
|
+
window.removeEventListener('pointermove', handlePointerMove);
|
|
132
|
+
window.removeEventListener('pointerup', handlePointerUp);
|
|
133
|
+
window.removeEventListener('pointercancel', handlePointerUp);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
window.addEventListener('pointermove', handlePointerMove);
|
|
137
|
+
window.addEventListener('pointerup', handlePointerUp);
|
|
138
|
+
window.addEventListener('pointercancel', handlePointerUp);
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
const handleKeyboardMove = (e, deltaX, deltaY) => {
|
|
143
|
+
state.current.isMoving = false;
|
|
144
|
+
move(e, deltaX, deltaY, 'keyboard');
|
|
145
|
+
end(e, 'keyboard');
|
|
146
|
+
};
|
|
147
|
+
moveProps.onKeyDown = (e) => {
|
|
148
|
+
switch (e.key) {
|
|
149
|
+
case 'ArrowLeft': {
|
|
150
|
+
e.preventDefault();
|
|
151
|
+
handleKeyboardMove(e, -1, 0);
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
case 'ArrowRight': {
|
|
155
|
+
e.preventDefault();
|
|
156
|
+
handleKeyboardMove(e, 1, 0);
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
case 'ArrowUp': {
|
|
160
|
+
e.preventDefault();
|
|
161
|
+
handleKeyboardMove(e, 0, -1);
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
case 'ArrowDown': {
|
|
165
|
+
e.preventDefault();
|
|
166
|
+
handleKeyboardMove(e, 0, 1);
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
return { moveProps };
|
|
172
|
+
}, [end, move]);
|
|
173
|
+
}
|
|
@@ -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,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.useResizeObserver = useResizeObserver;
|
|
7
|
+
const react_1 = __importDefault(require("react"));
|
|
8
|
+
/* FIXME: use the same hook from @gravity-ui/uikit */
|
|
9
|
+
function useResizeObserver({ ref, onResize, box, }) {
|
|
10
|
+
react_1.default.useEffect(() => {
|
|
11
|
+
const element = ref === null || ref === void 0 ? void 0 : ref.current;
|
|
12
|
+
if (!element) {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
if (typeof window.ResizeObserver === 'undefined') {
|
|
16
|
+
window.addEventListener('resize', onResize, false);
|
|
17
|
+
return () => {
|
|
18
|
+
window.removeEventListener('resize', onResize, false);
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const observer = new ResizeObserver((entries) => {
|
|
22
|
+
if (!entries.length) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
onResize();
|
|
26
|
+
});
|
|
27
|
+
observer.observe(element, { box });
|
|
28
|
+
return () => {
|
|
29
|
+
observer.disconnect();
|
|
30
|
+
};
|
|
31
|
+
}, [ref, onResize, box]);
|
|
32
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
.g-date-range-date-selection {
|
|
2
|
+
display: grid;
|
|
3
|
+
align-items: center;
|
|
4
|
+
grid-template-areas: "buttons-start ruler buttons-end";
|
|
5
|
+
grid-template-columns: auto 1fr auto;
|
|
6
|
+
border-block: 1px solid var(--g-color-line-generic);
|
|
7
|
+
}
|
|
8
|
+
.g-date-range-date-selection__ruler {
|
|
9
|
+
grid-area: ruler;
|
|
10
|
+
}
|
|
11
|
+
.g-date-range-date-selection__ruler_dragging .g-date-range-date-selection__selection {
|
|
12
|
+
pointer-events: none;
|
|
13
|
+
}
|
|
14
|
+
.g-date-range-date-selection__buttons {
|
|
15
|
+
display: flex;
|
|
16
|
+
align-items: center;
|
|
17
|
+
height: 22px;
|
|
18
|
+
}
|
|
19
|
+
.g-date-range-date-selection__buttons_position_start {
|
|
20
|
+
grid-area: buttons-start;
|
|
21
|
+
padding-inline-end: var(--g-spacing-half);
|
|
22
|
+
border-inline-end: 1px solid var(--g-color-line-generic);
|
|
23
|
+
}
|
|
24
|
+
.g-date-range-date-selection__buttons_position_end {
|
|
25
|
+
grid-area: buttons-end;
|
|
26
|
+
padding-inline-start: var(--g-spacing-half);
|
|
27
|
+
border-inline-start: 1px solid var(--g-color-line-generic);
|
|
28
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { DateTime } from '@gravity-ui/date-utils';
|
|
3
|
+
import type { AccessibilityProps, DomProps, StyleProps } from '../types';
|
|
4
|
+
import type { ViewportDimensions, ViewportInterval } from './components/Ruler/Ruler';
|
|
5
|
+
import type { RangeDateSelectionOptions } from './hooks/useRangeDateSelectionState';
|
|
6
|
+
import './RangeDateSelection.css';
|
|
7
|
+
export interface RangeDateSelectionProps extends RangeDateSelectionOptions, DomProps, StyleProps, AccessibilityProps {
|
|
8
|
+
/** Formats time ticks */
|
|
9
|
+
formatTime?: (time: DateTime) => string;
|
|
10
|
+
/** Displays now line */
|
|
11
|
+
displayNow?: boolean;
|
|
12
|
+
/** Enables dragging ruler */
|
|
13
|
+
draggableRuler?: boolean;
|
|
14
|
+
/** Displays buttons to scale selection */
|
|
15
|
+
hasScaleButtons?: boolean;
|
|
16
|
+
/** Position of scale buttons */
|
|
17
|
+
scaleButtonsPosition?: 'start' | 'end';
|
|
18
|
+
/** Renders additional svg content in the ruler */
|
|
19
|
+
renderAdditionalRulerContent?: (props: {
|
|
20
|
+
interval: ViewportInterval;
|
|
21
|
+
dimensions: ViewportDimensions;
|
|
22
|
+
}) => React.ReactNode;
|
|
23
|
+
}
|
|
24
|
+
export declare function RangeDateSelection(props: RangeDateSelectionProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { Minus, Plus } from '@gravity-ui/icons';
|
|
5
|
+
import { Button, Icon } from '@gravity-ui/uikit';
|
|
6
|
+
import { block } from '../../utils/cn';
|
|
7
|
+
import { filterDOMProps } from '../utils/filterDOMProps';
|
|
8
|
+
import { DateTimeRuler } from './components/Ruler/Ruler';
|
|
9
|
+
import { SelectionControl } from './components/SelectionControl/SelectionControl';
|
|
10
|
+
import { useRangeDateSelectionState } from './hooks/useRangeDateSelectionState';
|
|
11
|
+
import { i18n } from './i18n';
|
|
12
|
+
import './RangeDateSelection.css';
|
|
13
|
+
const b = block('range-date-selection');
|
|
14
|
+
export function RangeDateSelection(props) {
|
|
15
|
+
var _a, _b;
|
|
16
|
+
const state = useRangeDateSelectionState(props);
|
|
17
|
+
const [isDraggingRuler, setDraggingRuler] = React.useState(false);
|
|
18
|
+
const handleRulerMoveStart = () => {
|
|
19
|
+
state.setDraggingValue(state.value);
|
|
20
|
+
setDraggingRuler(true);
|
|
21
|
+
};
|
|
22
|
+
const handleRulerMove = (d) => {
|
|
23
|
+
const intervalWidth = state.viewportInterval.end.diff(state.viewportInterval.start);
|
|
24
|
+
const delta = -Math.floor((d * intervalWidth) / 100);
|
|
25
|
+
state.move(delta);
|
|
26
|
+
};
|
|
27
|
+
const handleRulerMoveEnd = () => {
|
|
28
|
+
setDraggingRuler(false);
|
|
29
|
+
state.endDragging();
|
|
30
|
+
};
|
|
31
|
+
let id = React.useId();
|
|
32
|
+
id = (_a = props.id) !== null && _a !== void 0 ? _a : id;
|
|
33
|
+
return (_jsxs("div", Object.assign({}, filterDOMProps(props, { labelable: true }), { id: id, className: b(null, props.className), style: props.style, dir: "ltr" // TODO: RTL support
|
|
34
|
+
, children: [_jsx(DateTimeRuler, Object.assign({ className: b('ruler', { dragging: isDraggingRuler }) }, state.viewportInterval, { onMoveStart: handleRulerMoveStart, onMove: props.draggableRuler ? handleRulerMove : undefined, onMoveEnd: handleRulerMoveEnd, dragDisabled: state.isDragging, displayNow: props.displayNow, minValue: props.minValue, maxValue: props.maxValue, formatTime: props.formatTime, timeZone: state.timeZone, renderAdditionalRulerContent: props.renderAdditionalRulerContent, children: _jsx(SelectionControl, { className: b('selection'), state: state, "aria-labelledby": id }) })), props.hasScaleButtons ? (_jsxs("div", { className: b('buttons', { position: (_b = props.scaleButtonsPosition) !== null && _b !== void 0 ? _b : 'start' }), children: [_jsx(Button, { view: "flat-secondary", size: "xs", onClick: () => {
|
|
35
|
+
state.startDragging();
|
|
36
|
+
state.scale(0.5);
|
|
37
|
+
state.endDragging();
|
|
38
|
+
}, extraProps: { 'aria-label': i18n('Decrease range') }, children: _jsx(Icon, { data: Minus }) }), _jsx(Button, { view: "flat-secondary", size: "xs", onClick: () => {
|
|
39
|
+
state.startDragging();
|
|
40
|
+
state.scale(1.5);
|
|
41
|
+
state.endDragging();
|
|
42
|
+
}, extraProps: { 'aria-label': i18n('Increase range') }, children: _jsx(Icon, { data: Plus }) })] })) : null] })));
|
|
43
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { block } from '../../../../utils/cn';
|
|
4
|
+
import { SECOND } from '../../../utils/constants';
|
|
5
|
+
import { useViewportDimensions, useViewportInterval } from '../Ruler/Ruler';
|
|
6
|
+
const MIN_UPDATE_DISTANCE = 4; // in px
|
|
7
|
+
import './NowLine.css';
|
|
8
|
+
const b = block('timeline-now-line');
|
|
9
|
+
export function NowLine() {
|
|
10
|
+
const viewport = useViewportDimensions();
|
|
11
|
+
const { start: startDate, end: endDate } = useViewportInterval();
|
|
12
|
+
const [, rerender] = React.useState({});
|
|
13
|
+
const nowTime = Date.now();
|
|
14
|
+
const needUpdateNow = endDate.valueOf() > nowTime;
|
|
15
|
+
const interval = Math.max(SECOND, (MIN_UPDATE_DISTANCE * endDate.diff(startDate)) / viewport.width, startDate.valueOf() - nowTime);
|
|
16
|
+
React.useEffect(() => {
|
|
17
|
+
let timer = null;
|
|
18
|
+
if (needUpdateNow) {
|
|
19
|
+
timer = window.setInterval(() => {
|
|
20
|
+
rerender({});
|
|
21
|
+
}, interval);
|
|
22
|
+
}
|
|
23
|
+
return () => {
|
|
24
|
+
if (timer) {
|
|
25
|
+
window.clearInterval(timer);
|
|
26
|
+
timer = null;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}, [needUpdateNow, interval]);
|
|
30
|
+
if (nowTime < startDate.valueOf() || endDate.valueOf() < nowTime) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
const nowX = ((nowTime - startDate.valueOf()) / (endDate.valueOf() - startDate.valueOf())) *
|
|
34
|
+
viewport.width;
|
|
35
|
+
return _jsx("path", { d: `M${nowX},0l0,${viewport.height}`, className: b() });
|
|
36
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { DateTime } from '@gravity-ui/date-utils';
|
|
3
|
+
import type { MoveEndEvent, MoveMoveEvent, MoveStartEvent } from '../../../../hooks/useMove';
|
|
4
|
+
import type { RangeValue } from '../../../types';
|
|
5
|
+
interface RulerProps {
|
|
6
|
+
className?: string;
|
|
7
|
+
children?: React.ReactNode;
|
|
8
|
+
start: DateTime;
|
|
9
|
+
end: DateTime;
|
|
10
|
+
minValue?: DateTime;
|
|
11
|
+
maxValue?: DateTime;
|
|
12
|
+
onMoveStart?: (event: MoveStartEvent) => void;
|
|
13
|
+
onMove?: (delta: number, event: MoveMoveEvent) => void;
|
|
14
|
+
onMoveEnd?: (event: MoveEndEvent) => void;
|
|
15
|
+
displayNow?: boolean;
|
|
16
|
+
formatTime?: (time: DateTime) => string;
|
|
17
|
+
timeZone?: string;
|
|
18
|
+
dragDisabled?: boolean;
|
|
19
|
+
renderAdditionalRulerContent?: (props: {
|
|
20
|
+
interval: ViewportInterval;
|
|
21
|
+
dimensions: ViewportDimensions;
|
|
22
|
+
}) => React.ReactNode;
|
|
23
|
+
}
|
|
24
|
+
export interface ViewportDimensions {
|
|
25
|
+
width: number;
|
|
26
|
+
height: number;
|
|
27
|
+
}
|
|
28
|
+
export type ViewportInterval = RangeValue<DateTime>;
|
|
29
|
+
export declare function DateTimeRuler({ className, children, start, end, minValue, maxValue, onMove, onMoveStart, onMoveEnd, displayNow, formatTime, timeZone, dragDisabled, renderAdditionalRulerContent, }: RulerProps): import("react/jsx-runtime").JSX.Element;
|
|
30
|
+
export declare function useViewportDimensions(): ViewportDimensions;
|
|
31
|
+
export declare function useViewportInterval(): ViewportInterval;
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import ReactDOM from 'react-dom';
|
|
4
|
+
import { useResizeObserver } from '../../../../hooks/useResizeObserver';
|
|
5
|
+
import { block } from '../../../../utils/cn';
|
|
6
|
+
import { NowLine } from '../NowLine/NowLine';
|
|
7
|
+
import { RulerViewport } from '../RulerViewport/RulerViewport';
|
|
8
|
+
import { MiddleTicks } from '../Ticks/MiddleTicks';
|
|
9
|
+
import { SlitTicks } from '../Ticks/SlitTicks';
|
|
10
|
+
import { UnavailableTicks } from '../Ticks/UnavialableTicks';
|
|
11
|
+
import { makeUnavailableTicksGeometry } from '../Ticks/utils';
|
|
12
|
+
const b = block('ruler');
|
|
13
|
+
const viewportDimensionsContext = React.createContext(null);
|
|
14
|
+
const viewportIntervalContext = React.createContext(null);
|
|
15
|
+
export function DateTimeRuler({ className, children, start, end, minValue, maxValue, onMove, onMoveStart, onMoveEnd, displayNow, formatTime, timeZone, dragDisabled, renderAdditionalRulerContent, }) {
|
|
16
|
+
const [container, setContainer] = React.useState(null);
|
|
17
|
+
const viewportInterval = React.useMemo(() => ({ start, end }), [start, end]);
|
|
18
|
+
const [viewportDimensions, setViewportDimensions] = React.useState({
|
|
19
|
+
width: 0,
|
|
20
|
+
height: 0,
|
|
21
|
+
});
|
|
22
|
+
const onResize = React.useCallback(() => {
|
|
23
|
+
if (!container) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const { width, height } = container.getBoundingClientRect();
|
|
27
|
+
setViewportDimensions({ width, height });
|
|
28
|
+
}, [container]);
|
|
29
|
+
const containerRef = React.useMemo(() => ({ current: container }), [container]);
|
|
30
|
+
useResizeObserver({ ref: containerRef, onResize });
|
|
31
|
+
const hasConstrains = Boolean(minValue || maxValue);
|
|
32
|
+
return (_jsx("div", { className: b(null, className), children: _jsx(viewportIntervalContext.Provider, { value: viewportInterval, children: _jsxs(viewportDimensionsContext.Provider, { value: viewportDimensions, children: [_jsxs(RulerViewport, { ref: setContainer, onMove: onMove, onMoveStart: onMoveStart, onMoveEnd: onMoveEnd, dragDisabled: dragDisabled, children: [_jsx(MiddleTicks, { timeZone: timeZone }), _jsx(SlitTicks, { formatTime: formatTime, timeZone: timeZone }), hasConstrains ? (_jsx(UnavailableTicks, { theme: "dim", minValue: minValue, maxValue: maxValue, geometry: makeUnavailableTicksGeometry({
|
|
33
|
+
tickHeight: 10,
|
|
34
|
+
viewportHeight: viewportDimensions.height,
|
|
35
|
+
}), tickWidth: viewportDimensions.height + 10 })) : null, displayNow ? _jsx(NowLine, {}) : null, renderAdditionalRulerContent === null || renderAdditionalRulerContent === void 0 ? void 0 : renderAdditionalRulerContent({
|
|
36
|
+
interval: viewportInterval,
|
|
37
|
+
dimensions: viewportDimensions,
|
|
38
|
+
})] }), container ? ReactDOM.createPortal(children, container) : null] }) }) }));
|
|
39
|
+
}
|
|
40
|
+
export function useViewportDimensions() {
|
|
41
|
+
const viewport = React.useContext(viewportDimensionsContext);
|
|
42
|
+
if (!viewport) {
|
|
43
|
+
throw new Error('useViewportDimensions must be used within a RulerViewport');
|
|
44
|
+
}
|
|
45
|
+
return viewport;
|
|
46
|
+
}
|
|
47
|
+
export function useViewportInterval() {
|
|
48
|
+
const viewport = React.useContext(viewportIntervalContext);
|
|
49
|
+
if (!viewport) {
|
|
50
|
+
throw new Error('useViewportInterval must be used within a RulerViewport');
|
|
51
|
+
}
|
|
52
|
+
return viewport;
|
|
53
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
.g-date-ruler-viewport {
|
|
2
|
+
--_--g-date-ruler-viewport-background: var(
|
|
3
|
+
--g-date-ruler-viewport-background,
|
|
4
|
+
var(--g-color-base-background)
|
|
5
|
+
);
|
|
6
|
+
--g-date-thin-timeline-height: 22px;
|
|
7
|
+
--g-date-thin-timeline-now-color: var(--g-color-line-danger);
|
|
8
|
+
position: relative;
|
|
9
|
+
box-sizing: border-box;
|
|
10
|
+
height: var(--g-date-thin-timeline-height);
|
|
11
|
+
}
|
|
12
|
+
.g-date-ruler-viewport__dragger {
|
|
13
|
+
position: absolute;
|
|
14
|
+
inset: 0;
|
|
15
|
+
cursor: grab;
|
|
16
|
+
}
|
|
17
|
+
.g-date-ruler-viewport__dragger:focus-visible {
|
|
18
|
+
outline: 2px solid var(--g-color-line-focus);
|
|
19
|
+
}
|
|
20
|
+
.g-date-ruler-viewport__dragger_disabled {
|
|
21
|
+
pointer-events: none;
|
|
22
|
+
}
|
|
23
|
+
.g-date-ruler-viewport__svg {
|
|
24
|
+
pointer-events: none;
|
|
25
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { MoveEndEvent, MoveMoveEvent, MoveStartEvent } from '../../../../hooks/useMove';
|
|
3
|
+
import './RulerViewport.css';
|
|
4
|
+
interface RulerViewportProps {
|
|
5
|
+
className?: string;
|
|
6
|
+
children?: React.ReactNode;
|
|
7
|
+
onMoveStart?: (event: MoveStartEvent) => void;
|
|
8
|
+
onMove?: (delta: number, event: MoveMoveEvent) => void;
|
|
9
|
+
onMoveEnd?: (event: MoveEndEvent) => void;
|
|
10
|
+
dragDisabled?: boolean;
|
|
11
|
+
}
|
|
12
|
+
declare const _RulerViewport: React.ForwardRefExoticComponent<RulerViewportProps & React.RefAttributes<HTMLDivElement>>;
|
|
13
|
+
export { _RulerViewport as RulerViewport };
|