Skip to content

Commit

Permalink
feat(cdk/bidi): support auto direction value
Browse files Browse the repository at this point in the history
Adds support for the `auto` value of the `dir` attribute. The value gets resolved to `ltr` or `rtl` based on browser's locale.

Fixes angular#10186.
  • Loading branch information
crisbeto committed Nov 5, 2021
1 parent e7a3f68 commit af532df
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 13 deletions.
14 changes: 8 additions & 6 deletions src/cdk/bidi/dir.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import {Directive, Output, Input, EventEmitter, AfterContentInit, OnDestroy} from '@angular/core';

import {Direction, Directionality} from './directionality';
import {Direction, Directionality, _resolveDirectionality} from './directionality';

/**
* Directive to listen for changes of direction of part of the DOM.
Expand Down Expand Up @@ -40,14 +40,16 @@ export class Dir implements Directionality, AfterContentInit, OnDestroy {
get dir(): Direction {
return this._dir;
}
set dir(value: Direction) {
const old = this._dir;
const normalizedValue = value ? value.toLowerCase() : value;
set dir(value: Direction | 'auto') {
const previousValue = this._dir;

// Note: `_resolveDirectionality` resolves the language based on the browser's language,
// whereas the browser does it based on the content of the element. Since doing so based
// on the content can be expensive, for now we're doing the simpler matching.
this._dir = _resolveDirectionality(value);
this._rawDir = value;
this._dir = normalizedValue === 'ltr' || normalizedValue === 'rtl' ? normalizedValue : 'ltr';

if (old !== this._dir && this._isInitialized) {
if (previousValue !== this._dir && this._isInitialized) {
this.change.emit(this._dir);
}
}
Expand Down
22 changes: 16 additions & 6 deletions src/cdk/bidi/directionality.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,21 @@ import {DIR_DOCUMENT} from './dir-document-token';

export type Direction = 'ltr' | 'rtl';

/** Regex that matches locales with an RTL script. Taken from `goog.i18n.bidi.isRtlLanguage`. */
const RTL_LOCALE_PATTERN =
/^(ar|ckb|dv|he|iw|fa|nqo|ps|sd|ug|ur|yi|.*[-_](Adlm|Arab|Hebr|Nkoo|Rohg|Thaa))(?!.*[-_](Latn|Cyrl)($|-|_))($|-|_)/i;

/** Resolves a string value to a specific direction. */
export function _resolveDirectionality(rawValue: string): Direction {
const value = rawValue.toLowerCase();

if (value === 'auto' && typeof navigator !== 'undefined' && navigator && navigator.language) {
return RTL_LOCALE_PATTERN.test(navigator.language) ? 'rtl' : 'ltr';
}

return value === 'rtl' ? 'rtl' : 'ltr';
}

/**
* The directionality (LTR / RTL) context for the application (or a subtree of it).
* Exposes the current direction and a stream of direction changes.
Expand All @@ -25,14 +40,9 @@ export class Directionality implements OnDestroy {

constructor(@Optional() @Inject(DIR_DOCUMENT) _document?: any) {
if (_document) {
// TODO: handle 'auto' value -
// We still need to account for dir="auto".
// It looks like HTMLElemenet.dir is also "auto" when that's set to the attribute,
// but getComputedStyle return either "ltr" or "rtl". avoiding getComputedStyle for now
const bodyDir = _document.body ? _document.body.dir : null;
const htmlDir = _document.documentElement ? _document.documentElement.dir : null;
const value = bodyDir || htmlDir;
this.value = value === 'ltr' || value === 'rtl' ? value : 'ltr';
this.value = _resolveDirectionality(bodyDir || htmlDir || 'ltr');
}
}

Expand Down
2 changes: 1 addition & 1 deletion tools/public_api_guard/cdk/bidi.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export class BidiModule {
export class Dir implements Directionality, AfterContentInit, OnDestroy {
readonly change: EventEmitter<Direction>;
get dir(): Direction;
set dir(value: Direction);
set dir(value: Direction | 'auto');
ngAfterContentInit(): void;
// (undocumented)
ngOnDestroy(): void;
Expand Down

0 comments on commit af532df

Please sign in to comment.