Skip to content

Commit 0d7bd16

Browse files
authored
feat(DateField): support rtl (#28)
1 parent 5a9c51f commit 0d7bd16

File tree

4 files changed

+35
-4
lines changed

4 files changed

+35
-4
lines changed

.storybook/preview.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ configure({
1818
});
1919

2020
const WithContextProvider: Decorator = (Story, context) => {
21+
const direction = context.globals.direction;
22+
React.useEffect(() => {
23+
if (direction === 'ltr') {
24+
document.body.removeAttribute('dir');
25+
} else {
26+
document.body.setAttribute('dir', direction);
27+
}
28+
}, [direction]);
2129
return (
2230
<React.StrictMode>
2331
<ThemeProvider theme={context.globals.theme}>
@@ -61,6 +69,7 @@ const preview: Preview = {
6169
{value: 'light-hc', right: '☼', title: 'High Contrast Light (beta)'},
6270
{value: 'dark-hc', right: '☾', title: 'High Contrast Dark (beta)'},
6371
],
72+
dynamicTitle: true,
6473
},
6574
},
6675
lang: {
@@ -72,6 +81,19 @@ const preview: Preview = {
7281
{value: 'en', right: '🇬🇧', title: 'En'},
7382
{value: 'ru', right: '🇷🇺', title: 'Ru'},
7483
],
84+
dynamicTitle: true,
85+
},
86+
},
87+
direction: {
88+
defaultValue: 'ltr',
89+
toolbar: {
90+
title: 'Direction',
91+
icon: 'menu',
92+
items: [
93+
{value: 'ltr', title: 'Left to Right', icon: 'arrowrightalt'},
94+
{value: 'rtl', title: 'Right to Left', icon: 'arrowleftalt'},
95+
],
96+
dynamicTitle: true,
7597
},
7698
},
7799
platform: {
@@ -82,6 +104,7 @@ const preview: Preview = {
82104
{value: 'desktop', title: 'Desktop', icon: 'browser'},
83105
{value: 'mobile', title: 'Mobile', icon: 'mobile'},
84106
],
107+
dynamicTitle: true,
85108
},
86109
},
87110
},

src/components/DateField/hooks/useDateFieldProps.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import React from 'react';
33
import type {TextInputProps} from '@gravity-ui/uikit';
44

55
import type {DateFieldProps} from '../DateField';
6-
import {CtrlCmd} from '../utils';
6+
import {CtrlCmd, cleanString} from '../utils';
77

88
import type {DateFieldState} from './useDateFieldState';
99

@@ -190,7 +190,7 @@ export function useDateFieldProps(
190190
return;
191191
}
192192

193-
const pastedValue = e.clipboardData.getData('text');
193+
const pastedValue = cleanString(e.clipboardData.getData('text'));
194194
if (
195195
state.selectedSectionIndexes &&
196196
state.selectedSectionIndexes.startIndex ===

src/components/DateField/hooks/useDateFieldState.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,8 @@ export function useDateFieldState(props: DateFieldStateOptions): DateFieldState
246246
isEmpty: Object.keys(validSegments).length === 0,
247247
displayValue,
248248
setValue,
249-
text: sectionsState.editableSections.map((s) => s.textValue).join(''),
249+
// use ltr direction context to get predictable navigation inside input
250+
text: '\u2066' + sectionsState.editableSections.map((s) => s.textValue).join('') + '\u2069',
250251
readOnly: props.readOnly,
251252
disabled: props.disabled,
252253
sections: sectionsState.editableSections,
@@ -625,7 +626,7 @@ function getEditableSections(
625626
value: DateTime,
626627
validSegments: typeof EDITABLE_SEGMENTS,
627628
) {
628-
let position = 0;
629+
let position = 1;
629630
const newSections: DateFieldSection[] = [];
630631
let previousEditableSection = -1;
631632
for (let i = 0; i < sections.length; i++) {
@@ -643,6 +644,9 @@ function getEditableSections(
643644
}
644645
}
645646

647+
// use bidirectional context to allow the browser autodetect text direction
648+
renderedValue = '\u2068' + renderedValue + '\u2069';
649+
646650
const sectionLength = renderedValue.length;
647651

648652
const newSection = {

src/components/DateField/utils.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,3 +516,7 @@ function getSectionOptions(
516516

517517
return undefined;
518518
}
519+
520+
export function cleanString(dirtyString: string) {
521+
return dirtyString.replace(/[\u2066\u2067\u2068\u2069]/g, '');
522+
}

0 commit comments

Comments
 (0)