Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: follow-up for rtl date/time format #7685

Merged
merged 3 commits into from
Jan 31, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/@react-aria/datepicker/src/useDateSegment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -388,9 +388,14 @@ export function useDateSegment(segment: DateSegment, state: DateFieldState, ref:
let dateSegments = ['day', 'month', 'year'];
let segmentStyle : CSSProperties = {caretColor: 'transparent'};
if (direction === 'rtl') {
// While the bidirectional algorithm seems to work properly on inline elements with actual values, it returns different results for placeholder strings.
// To ensure placeholder render in correct format, we apply the CSS equivalent of LRE (left-to-right embedding). See https://www.unicode.org/reports/tr9/#Explicit_Directional_Embeddings.
// However, we apply this to both placeholders and date segments with an actual value because the date segments will shift around when deleting otherwise.
if (dateSegments.includes(segment.type)) {
segmentStyle = {caretColor: 'transparent', direction: 'ltr', unicodeBidi: 'embed'};
} else if (segment.type === 'timeZoneName') {
// This is needed so that the time zone renders on the left side of the time segments (hour:minute).
// Otherwise, it will render on the right side which is incorrect.
segmentStyle = {caretColor: 'transparent', unicodeBidi: 'embed'};
}
}
Expand Down
9 changes: 8 additions & 1 deletion packages/@react-stately/datepicker/src/useDateFieldState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,11 @@ function processSegments(dateValue, validSegments, dateFormatter, resolvedOption
isEditable
} as DateSegment;

// There is an issue in RTL languages where time fields render (minute:hour) instead of (hour:minute).
// To force an LTR direction on the time field since, we wrap the time segments in LRI (left-to-right) isolate unicode. See https://www.w3.org/International/questions/qa-bidi-unicode-controls.
// These unicode characters will be added to the array of processed segments as literals and will mark the start and end of the embedded direction change.
if (segment.type === 'hour') {
// This marks the start of the embedded direction change.
processedSegments.push({
type: 'literal',
text: '\u2066',
Expand All @@ -440,6 +444,7 @@ function processSegments(dateValue, validSegments, dateFormatter, resolvedOption
isEditable: false
});
processedSegments.push(dateSegment);
// This marks the end of the embedded direction change in the case that the granularity it set to "hour".
if (segment.type === granularity) {
processedSegments.push({
type: 'literal',
Expand All @@ -450,8 +455,9 @@ function processSegments(dateValue, validSegments, dateFormatter, resolvedOption
isEditable: false
});
}
} else if (timeValue.includes(granularity) && segment.type === granularity) {
} else if (timeValue.includes(segment.type) && segment.type === granularity) {
processedSegments.push(dateSegment);
// This marks the end of the embedded direction change.
processedSegments.push({
type: 'literal',
text: '\u2069',
Expand All @@ -461,6 +467,7 @@ function processSegments(dateValue, validSegments, dateFormatter, resolvedOption
isEditable: false
});
} else {
// We only want to "wrap" the unicode around segments that are hour, minute, or second. If they aren't, just process as normal.
processedSegments.push(dateSegment);
}
}
Expand Down
4 changes: 4 additions & 0 deletions packages/react-aria-components/docs/DateField.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,10 @@ If the date field does not have a visible label, an `aria-label` or `aria-labell

Note that most of this anatomy is shared with [TimeField](TimeField.html), so you can reuse many components between them if you have both.

### Internationalization
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rob suggested that it would be a good idea to leave some kind of information regarding the CSS changes needed to ensure the date/time format properly in RTL locales. I decided to add it like this but let me know if you have other opinions where it should go or contents that it should include.


To ensure the proper date and time format in RTL locales, `DateInput` must have `display` set to either `inline`, `inline-block`, or `block`.

### Concepts

`DateField` makes use of the following concepts:
Expand Down
4 changes: 4 additions & 0 deletions packages/react-aria-components/docs/DatePicker.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,10 @@ If the date picker does not have a visible label, an `aria-label` or `aria-label

Note that most of this anatomy is shared with [DateRangePicker](DateRangePicker.html), so you can reuse many components between them if you have both.

### Internationalization

To ensure the proper date and time format in RTL locales, `DateInput` must have `display` set to either `inline`, `inline-block`, or `block`.

### Concepts

`DatePicker` makes use of the following concepts:
Expand Down
4 changes: 4 additions & 0 deletions packages/react-aria-components/docs/DateRangePicker.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,10 @@ If the date range picker does not have a visible label, an `aria-label` or `aria

Note that most of this anatomy is shared with [DatePicker](DatePicker.html), so you can reuse many components between them if you have both.

### Internationalization

To ensure the proper date and time format in RTL locales, `DateInput` must have `display` set to either `inline`, `inline-block`, or `block`.

### Concepts

`DateRangePicker` makes use of the following concepts:
Expand Down