-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
611413d
commit 89b6d23
Showing
16 changed files
with
315 additions
and
34 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { NgModule } from '@angular/core'; | ||
|
||
import { Dir } from './dir'; | ||
|
||
|
||
@NgModule({ | ||
exports: [Dir], | ||
declarations: [Dir] | ||
}) | ||
export class BidiModule { | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { DOCUMENT } from '@angular/common'; | ||
import { inject, InjectionToken } from '@angular/core'; | ||
|
||
|
||
/** | ||
* Injection token used to inject the document into Directionality. | ||
* This is used so that the value can be faked in tests. | ||
* | ||
* We can't use the real document in tests because changing the real `dir` causes geometry-based | ||
* tests in Safari to fail. | ||
* | ||
* We also can't re-provide the DOCUMENT token from platform-brower because the unit tests | ||
* themselves use things like `querySelector` in test code. | ||
* | ||
* This token is defined in a separate file from Directionality as a workaround for | ||
* https://github.com/angular/angular/issues/22559 | ||
* | ||
* @docs-private | ||
*/ | ||
export const DIR_DOCUMENT = new InjectionToken<Document>('cdk-dir-doc', { | ||
providedIn: 'root', | ||
factory: DIR_DOCUMENT_FACTORY | ||
}); | ||
|
||
/** @docs-private */ | ||
export function DIR_DOCUMENT_FACTORY(): Document { | ||
return inject(DOCUMENT); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import { | ||
Directive, | ||
Output, | ||
Input, | ||
EventEmitter, | ||
AfterContentInit, | ||
OnDestroy | ||
} from '@angular/core'; | ||
|
||
import { Direction, Directionality } from './directionality'; | ||
|
||
|
||
/** | ||
* Directive to listen for changes of direction of part of the DOM. | ||
* | ||
* Provides itself as Directionality such that descendant directives only need to ever inject | ||
* Directionality to get the closest direction. | ||
*/ | ||
@Directive({ | ||
selector: '[dir]', | ||
providers: [{provide: Directionality, useExisting: Dir}], | ||
host: {'[dir]': 'dir'}, | ||
exportAs: 'dir' | ||
}) | ||
export class Dir implements Directionality, AfterContentInit, OnDestroy { | ||
_dir: Direction = 'ltr'; | ||
|
||
/** Event emitted when the direction changes. */ | ||
@Output('dirChange') change = new EventEmitter<Direction>(); | ||
|
||
/** @docs-private */ | ||
@Input() | ||
get dir(): Direction { | ||
return this._dir; | ||
} | ||
|
||
set dir(v: Direction) { | ||
const old = this._dir; | ||
this._dir = v; | ||
|
||
if (old !== this._dir && this._isInitialized) { | ||
this.change.emit(this._dir); | ||
} | ||
} | ||
|
||
/** Current layout direction of the element. */ | ||
get value(): Direction { | ||
return this.dir; | ||
} | ||
|
||
/** Whether the `value` has been set to its initial value. */ | ||
private _isInitialized: boolean = false; | ||
|
||
/** Initialize once default value has been set. */ | ||
ngAfterContentInit() { | ||
this._isInitialized = true; | ||
} | ||
|
||
ngOnDestroy() { | ||
this.change.complete(); | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
import {Component} from '@angular/core'; | ||
import {async, fakeAsync, TestBed} from '@angular/core/testing'; | ||
import {By} from '@angular/platform-browser'; | ||
|
||
import {BidiModule, Directionality, Direction, DIR_DOCUMENT} from './index'; | ||
|
||
|
||
describe('Directionality', () => { | ||
let fakeDocument: IFakeDocument; | ||
|
||
beforeEach(async(() => { | ||
fakeDocument = {body: {}, documentElement: {}}; | ||
|
||
TestBed.configureTestingModule({ | ||
imports: [BidiModule], | ||
declarations: [ElementWithDir, InjectsDirectionality], | ||
providers: [{provide: DIR_DOCUMENT, useFactory: () => fakeDocument}], | ||
}).compileComponents(); | ||
})); | ||
|
||
describe('Service', () => { | ||
it('should read dir from the html element if not specified on the body', () => { | ||
fakeDocument.documentElement.dir = 'rtl'; | ||
|
||
const fixture = TestBed.createComponent(InjectsDirectionality); | ||
const testComponent = fixture.debugElement.componentInstance; | ||
|
||
expect(testComponent.dir.value).toBe('rtl'); | ||
}); | ||
|
||
it('should read dir from the body even it is also specified on the html element', () => { | ||
fakeDocument.documentElement.dir = 'ltr'; | ||
fakeDocument.body.dir = 'rtl'; | ||
|
||
const fixture = TestBed.createComponent(InjectsDirectionality); | ||
const testComponent = fixture.debugElement.componentInstance; | ||
|
||
expect(testComponent.dir.value).toBe('rtl'); | ||
}); | ||
|
||
it('should default to ltr if nothing is specified on either body or the html element', () => { | ||
const fixture = TestBed.createComponent(InjectsDirectionality); | ||
const testComponent = fixture.debugElement.componentInstance; | ||
|
||
expect(testComponent.dir.value).toBe('ltr'); | ||
}); | ||
|
||
it('should complete the `change` stream on destroy', () => { | ||
const fixture = TestBed.createComponent(InjectsDirectionality); | ||
const spy = jasmine.createSpy('complete spy'); | ||
const subscription = | ||
fixture.componentInstance.dir.change.subscribe(undefined, undefined, spy); | ||
|
||
fixture.componentInstance.dir.ngOnDestroy(); | ||
expect(spy).toHaveBeenCalled(); | ||
|
||
subscription.unsubscribe(); | ||
}); | ||
|
||
}); | ||
|
||
describe('Dir directive', () => { | ||
it('should provide itself as Directionality', () => { | ||
const fixture = TestBed.createComponent(ElementWithDir); | ||
const injectedDirectionality = | ||
fixture.debugElement.query(By.directive(InjectsDirectionality)).componentInstance.dir; | ||
|
||
fixture.detectChanges(); | ||
|
||
expect(injectedDirectionality.value).toBe('rtl'); | ||
}); | ||
|
||
it('should emit a change event when the value changes', fakeAsync(() => { | ||
const fixture = TestBed.createComponent(ElementWithDir); | ||
const injectedDirectionality = | ||
fixture.debugElement.query(By.directive(InjectsDirectionality)).componentInstance.dir; | ||
|
||
fixture.detectChanges(); | ||
|
||
let direction = injectedDirectionality.value; | ||
injectedDirectionality.change.subscribe((dir: Direction) => { | ||
direction = dir; | ||
}); | ||
|
||
expect(direction).toBe('rtl'); | ||
expect(injectedDirectionality.value).toBe('rtl'); | ||
expect(fixture.componentInstance.changeCount).toBe(0); | ||
|
||
fixture.componentInstance.direction = 'ltr'; | ||
|
||
fixture.detectChanges(); | ||
|
||
expect(direction).toBe('ltr'); | ||
expect(injectedDirectionality.value).toBe('ltr'); | ||
expect(fixture.componentInstance.changeCount).toBe(1); | ||
})); | ||
|
||
it('should complete the change stream on destroy', fakeAsync(() => { | ||
const fixture = TestBed.createComponent(ElementWithDir); | ||
const dir = | ||
fixture.debugElement.query(By.directive(InjectsDirectionality)).componentInstance.dir; | ||
const spy = jasmine.createSpy('complete spy'); | ||
const subscription = dir.change.subscribe(undefined, undefined, spy); | ||
|
||
fixture.destroy(); | ||
expect(spy).toHaveBeenCalled(); | ||
subscription.unsubscribe(); | ||
})); | ||
|
||
}); | ||
}); | ||
|
||
|
||
@Component({ | ||
template: ` | ||
<div [dir]="direction" (dirChange)="changeCount = changeCount + 1"> | ||
<injects-directionality></injects-directionality> | ||
</div> | ||
` | ||
}) | ||
class ElementWithDir { | ||
direction = 'rtl'; | ||
changeCount = 0; | ||
} | ||
|
||
/** Test component with Dir directive. */ | ||
@Component({ | ||
selector: 'injects-directionality', | ||
template: ` | ||
<div></div>` | ||
}) | ||
class InjectsDirectionality { | ||
constructor(public dir: Directionality) { | ||
} | ||
} | ||
|
||
interface IFakeDocument { | ||
documentElement: { dir?: string }; | ||
body: { dir?: string }; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { EventEmitter, Inject, Injectable, Optional, OnDestroy } from '@angular/core'; | ||
|
||
import {DIR_DOCUMENT} from './dir-document-token'; | ||
|
||
|
||
export type Direction = 'ltr' | 'rtl'; | ||
|
||
|
||
/** | ||
* The directionality (LTR / RTL) context for the application (or a subtree of it). | ||
* Exposes the current direction and a stream of direction changes. | ||
*/ | ||
@Injectable({providedIn: 'root'}) | ||
export class Directionality implements OnDestroy { | ||
/** The current 'ltr' or 'rtl' value. */ | ||
readonly value: Direction = 'ltr'; | ||
|
||
/** Stream that emits whenever the 'ltr' / 'rtl' state changes. */ | ||
readonly change = new EventEmitter<Direction>(); | ||
|
||
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; | ||
this.value = (bodyDir || htmlDir || 'ltr') as Direction; | ||
} | ||
} | ||
|
||
ngOnDestroy() { | ||
this.change.complete(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
|
||
export * from './public-api'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
|
||
export { Directionality, Direction } from './directionality'; | ||
export { DIR_DOCUMENT } from './dir-document-token'; | ||
export { Dir } from './dir'; | ||
|
||
export * from './bidi-module'; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
{ | ||
"extends": "../tsconfig.build", | ||
"files": [ | ||
"public-api.ts" | ||
], | ||
"angularCompilerOptions": { | ||
"strictMetadataEmit": true, | ||
"flatModuleOutFile": "index.js", | ||
"flatModuleId": "@ptsecurity/cdk/bidi", | ||
"skipTemplateCodegen": true, | ||
"fullTemplateTypeCheck": true | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +0,0 @@ | ||
Please see the official documentation at https://material.angular.io/components/component/divider | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.