Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | 1x 1x 3x 3x 3x 3x 3x 3x 3x 3x 3x 1x | 'use client';
import React from 'react';
import type {DateTime} from '@gravity-ui/date-utils';
import {Minus, Plus} from '@gravity-ui/icons';
import {Button, Icon} from '@gravity-ui/uikit';
import {block} from '../../utils/cn';
import type {AccessibilityProps, DomProps, StyleProps} from '../types';
import {filterDOMProps} from '../utils/filterDOMProps';
import {DateTimeRuler} from './components/Ruler/Ruler';
import type {ViewportDimensions, ViewportInterval} from './components/Ruler/Ruler';
import {SelectionControl} from './components/SelectionControl/SelectionControl';
import {useRangeDateSelectionState} from './hooks/useRangeDateSelectionState';
import type {RangeDateSelectionOptions} from './hooks/useRangeDateSelectionState';
import {i18n} from './i18n';
import './RangeDateSelection.scss';
const b = block('range-date-selection');
export interface RangeDateSelectionProps
extends RangeDateSelectionOptions, DomProps, StyleProps, AccessibilityProps {
/** Formats time ticks */
formatTime?: (time: DateTime) => string;
/** Displays now line */
displayNow?: boolean;
/** Enables dragging ruler */
draggableRuler?: boolean;
/** Displays buttons to scale selection */
hasScaleButtons?: boolean;
/** Position of scale buttons */
scaleButtonsPosition?: 'start' | 'end';
/** Renders additional svg content in the ruler */
renderAdditionalRulerContent?: (props: {
interval: ViewportInterval;
dimensions: ViewportDimensions;
}) => React.ReactNode;
}
export function RangeDateSelection(props: RangeDateSelectionProps) {
const state = useRangeDateSelectionState(props);
const [isDraggingRuler, setDraggingRuler] = React.useState(false);
const handleRulerMoveStart = () => {
state.setDraggingValue(state.value);
setDraggingRuler(true);
};
const handleRulerMove = (d: number) => {
const intervalWidth = state.viewportInterval.end.diff(state.viewportInterval.start);
const delta = -Math.floor((d * intervalWidth) / 100);
state.move(delta);
};
const handleRulerMoveEnd = () => {
setDraggingRuler(false);
state.endDragging();
};
let id = React.useId();
id = props.id ?? id;
const {t} = i18n.useTranslation();
return (
<div
{...filterDOMProps(props, {labelable: true})}
id={id}
className={b(null, props.className)}
style={props.style}
dir="ltr" // TODO: RTL support
>
<DateTimeRuler
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}
>
<SelectionControl className={b('selection')} state={state} aria-labelledby={id} />
</DateTimeRuler>
{props.hasScaleButtons ? (
<div className={b('buttons', {position: props.scaleButtonsPosition ?? 'start'})}>
<Button
view="flat-secondary"
size="xs"
onClick={() => {
state.startDragging();
state.scale(0.5);
state.endDragging();
}}
aria-label={t('Decrease range')}
>
<Icon data={Minus} />
</Button>
<Button
view="flat-secondary"
size="xs"
onClick={() => {
state.startDragging();
state.scale(1.5);
state.endDragging();
}}
aria-label={t('Increase range')}
>
<Icon data={Plus} />
</Button>
</div>
) : null}
</div>
);
}
|