From 818ce914cd3fe233f72071afebdc4b71a17d22a3 Mon Sep 17 00:00:00 2001 From: Andrew Scott Date: Fri, 2 Feb 2018 16:44:49 -0800 Subject: [PATCH] fix: apply correct RTL margins Copy bidi module from angular material cdk so there's not a new dependency. --- src/demo-app/app/docs-layout/_module.ts | 5 +- .../layoutRowWithDirection.demo.ts | 42 ++++++ src/lib/api/flexbox/flex-offset.spec.ts | 44 ++++++- src/lib/api/flexbox/flex-offset.ts | 15 ++- src/lib/api/flexbox/layout-gap.spec.ts | 23 +++- src/lib/api/flexbox/layout-gap.ts | 12 +- src/lib/bidi/bidi-module.ts | 23 ++++ src/lib/bidi/bidi.md | 39 ++++++ src/lib/bidi/dir.ts | 63 +++++++++ src/lib/bidi/directionality.spec.ts | 121 ++++++++++++++++++ src/lib/bidi/directionality.ts | 55 ++++++++ src/lib/bidi/index.ts | 9 ++ src/lib/bidi/public-api.ts | 11 ++ src/lib/module.ts | 4 +- 14 files changed, 458 insertions(+), 8 deletions(-) create mode 100644 src/demo-app/app/docs-layout/layoutRowWithDirection.demo.ts create mode 100644 src/lib/bidi/bidi-module.ts create mode 100644 src/lib/bidi/bidi.md create mode 100644 src/lib/bidi/dir.ts create mode 100644 src/lib/bidi/directionality.spec.ts create mode 100644 src/lib/bidi/directionality.ts create mode 100644 src/lib/bidi/index.ts create mode 100644 src/lib/bidi/public-api.ts diff --git a/src/demo-app/app/docs-layout/_module.ts b/src/demo-app/app/docs-layout/_module.ts index 8edcc0df6..bb917e920 100644 --- a/src/demo-app/app/docs-layout/_module.ts +++ b/src/demo-app/app/docs-layout/_module.ts @@ -10,6 +10,7 @@ import {Component} from '@angular/core'; + ` }) export class DemosLayoutAPI { @@ -26,6 +27,7 @@ import {DemoFlexRowFillWrap} from './flexRowFillWrap.demo'; import {DemoFlexAttributeValues} from './flexOtherValues.demo'; import {DemoFlexOffsetValues} from './flexOffetValues.demo'; import {DemoFlexAlignSelf} from './FlexAlignSelf.demo'; +import {DemoLayoutRowDirection} from './layoutRowWithDirection.demo'; @NgModule({ declarations: [ @@ -37,7 +39,8 @@ import {DemoFlexAlignSelf} from './FlexAlignSelf.demo'; DemoFlexRowFillWrap, DemoFlexAttributeValues, DemoFlexOffsetValues, - DemoFlexAlignSelf + DemoFlexAlignSelf, + DemoLayoutRowDirection, ], imports: [ SharedModule, diff --git a/src/demo-app/app/docs-layout/layoutRowWithDirection.demo.ts b/src/demo-app/app/docs-layout/layoutRowWithDirection.demo.ts new file mode 100644 index 000000000..3f1a29022 --- /dev/null +++ b/src/demo-app/app/docs-layout/layoutRowWithDirection.demo.ts @@ -0,0 +1,42 @@ +import {Component} from '@angular/core'; + +@Component({ + moduleId: module.id, + selector: 'demo-layout-row-direction', + template: ` + + Direction support for RTL + + Simple row using layout gap and flex offset to demonstrate changes + in layout direction between rtl and ltr. + + +
+ +
+
+
+
item 1
+
item 2
+
item 3
+
+
+
+ +
+ <div dir="{{ direction }}" fxLayoutGap="20px"> +
+
+
+ ` +}) +export class DemoLayoutRowDirection { + direction = 'ltr'; + + toggleDirection() { + this.direction = this.direction === 'ltr' ? 'rtl' : 'ltr'; + } +} diff --git a/src/lib/api/flexbox/flex-offset.spec.ts b/src/lib/api/flexbox/flex-offset.spec.ts index 68b3f62cc..2ab8640c0 100644 --- a/src/lib/api/flexbox/flex-offset.spec.ts +++ b/src/lib/api/flexbox/flex-offset.spec.ts @@ -9,6 +9,7 @@ import {Component} from '@angular/core'; import {CommonModule} from '@angular/common'; import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {DIR_DOCUMENT} from '../../bidi/directionality'; import {DEFAULT_BREAKPOINTS_PROVIDER} from '../../media-query/breakpoints/break-points-provider'; import {BreakPointRegistry} from '../../media-query/breakpoints/break-point-registry'; import {MockMatchMedia} from '../../media-query/mock/mock-match-media'; @@ -27,12 +28,14 @@ import { describe('flex directive', () => { let fixture: ComponentFixture; let expectDOMFrom = makeExpectDOMFrom(() => TestFlexComponent); + let fakeDocument: {body: {dir?: string}, documentElement: {dir?: string}}; let componentWithTemplate = (template: string) => { fixture = makeCreateTestComponent(() => TestFlexComponent)(template); }; beforeEach(() => { jasmine.addMatchers(customMatchers); + fakeDocument = {body: {}, documentElement: {}}; // Configure testbed to prepare services TestBed.configureTestingModule({ @@ -40,7 +43,8 @@ describe('flex directive', () => { declarations: [TestFlexComponent], providers: [ BreakPointRegistry, DEFAULT_BREAKPOINTS_PROVIDER, - {provide: MatchMedia, useClass: MockMatchMedia} + {provide: MatchMedia, useClass: MockMatchMedia}, + {provide: DIR_DOCUMENT, useValue: fakeDocument} ] }); }); @@ -134,6 +138,44 @@ describe('flex directive', () => { }); }); + it('should set margin-right for rtl layouts on document body', () => { + fakeDocument.body.dir = 'rtl'; + componentWithTemplate(` +
+
+
+ `); + fixture.detectChanges(); + + let element = queryFor(fixture, '[fxFlex]')[0].nativeElement; + expect(element).toHaveStyle({'margin-right': '17px'}); + }); + + it('should set margin-right for rtl layouts on documentElement', () => { + fakeDocument.documentElement.dir = 'rtl'; + componentWithTemplate(` +
+
+
+ `); + fixture.detectChanges(); + + let element = queryFor(fixture, '[fxFlex]')[0].nativeElement; + expect(element).toHaveStyle({'margin-right': '17px'}); + }); + + it('should set margin-left for ltr layouts', () => { + componentWithTemplate(` +
+
+
+ `); + fixture.detectChanges(); + + let element = queryFor(fixture, '[fxFlex]')[0].nativeElement; + expect(element).toHaveStyle({'margin-left': '17px'}); + }); + }); }); diff --git a/src/lib/api/flexbox/flex-offset.ts b/src/lib/api/flexbox/flex-offset.ts index a97f8992e..0e00ed800 100644 --- a/src/lib/api/flexbox/flex-offset.ts +++ b/src/lib/api/flexbox/flex-offset.ts @@ -23,6 +23,7 @@ import { import {Subscription} from 'rxjs/Subscription'; import {BaseFxDirective} from '../core/base'; +import {Directionality} from '../../bidi/directionality'; import {MediaChange} from '../../media-query/media-change'; import {MediaMonitor} from '../../media-query/media-monitor'; import {LayoutDirective} from './layout'; @@ -39,6 +40,7 @@ import {isFlowHorizontal} from '../../utils/layout-validator'; [fxFlexOffset.gt-xs], [fxFlexOffset.gt-sm], [fxFlexOffset.gt-md], [fxFlexOffset.gt-lg] `}) export class FlexOffsetDirective extends BaseFxDirective implements OnInit, OnChanges, OnDestroy { + private _directionWatcher: Subscription; /* tslint:disable */ @Input('fxFlexOffset') set offset(val) { this._cacheInput('offset', val); } @@ -63,8 +65,11 @@ export class FlexOffsetDirective extends BaseFxDirective implements OnInit, OnCh elRef: ElementRef, renderer: Renderer2, @Optional() @SkipSelf() protected _container: LayoutDirective, - @Inject(PLATFORM_ID) platformId: Object) { + @Inject(PLATFORM_ID) platformId: Object, + private _directionality: Directionality) { super(monitor, elRef, renderer, platformId); + this._directionWatcher = + this._directionality.change.subscribe(this._updateWithValue.bind(this)); this.watchParentFlow(); @@ -91,6 +96,9 @@ export class FlexOffsetDirective extends BaseFxDirective implements OnInit, OnCh if (this._layoutWatcher) { this._layoutWatcher.unsubscribe(); } + if (this._directionWatcher) { + this._directionWatcher.unsubscribe(); + } } /** @@ -162,8 +170,11 @@ export class FlexOffsetDirective extends BaseFxDirective implements OnInit, OnCh offset = offset + '%'; } + const horizontalLayoutKey = + this._directionality.value === 'rtl' ? 'margin-right' : 'margin-left'; // The flex-direction of this element's flex container. Defaults to 'row'. let layout = this._getFlowDirection(this.parentElement, true); - return isFlowHorizontal(layout) ? {'margin-left': `${offset}`} : {'margin-top': `${offset}`}; + return isFlowHorizontal(layout) ? {[horizontalLayoutKey]: `${offset}`} : + {'margin-top': `${offset}`}; } } diff --git a/src/lib/api/flexbox/layout-gap.spec.ts b/src/lib/api/flexbox/layout-gap.spec.ts index 9f2f6f729..233874d9c 100644 --- a/src/lib/api/flexbox/layout-gap.spec.ts +++ b/src/lib/api/flexbox/layout-gap.spec.ts @@ -9,6 +9,7 @@ import {Component, OnInit} from '@angular/core'; import {CommonModule} from '@angular/common'; import {TestBed, ComponentFixture, async} from '@angular/core/testing'; +import {DIR_DOCUMENT} from '../../bidi/directionality'; import {DEFAULT_BREAKPOINTS_PROVIDER} from '../../media-query/breakpoints/break-points-provider'; import {BreakPointRegistry} from '../../media-query/breakpoints/break-point-registry'; import {MockMatchMedia} from '../../media-query/mock/mock-match-media'; @@ -26,9 +27,11 @@ describe('layout-gap directive', () => { let fixture: ComponentFixture; let createTestComponent = makeCreateTestComponent(() => TestLayoutGapComponent); let expectDomForQuery = makeExpectDOMForQuery(() => TestLayoutGapComponent); + let fakeDocument: {body: {dir?: string}, documentElement: {dir?: string}}; beforeEach(() => { jasmine.addMatchers(customMatchers); + fakeDocument = {body: {}, documentElement: {}}; // Configure testbed to prepare services TestBed.configureTestingModule({ @@ -36,7 +39,8 @@ describe('layout-gap directive', () => { declarations: [TestLayoutGapComponent], providers: [ BreakPointRegistry, DEFAULT_BREAKPOINTS_PROVIDER, - {provide: MatchMedia, useClass: MockMatchMedia} + {provide: MatchMedia, useClass: MockMatchMedia}, + {provide: DIR_DOCUMENT, useValue: fakeDocument} ] }); }); @@ -287,6 +291,23 @@ describe('layout-gap directive', () => { }); + describe('rtl support', () => { + it('uses margin-left when document body has rtl dir', () => { + fakeDocument.body.dir = 'rtl'; + verifyCorrectMargin('row', 'margin-left'); + }); + + it('uses margin-left when documentElement has rtl dir', () => { + fakeDocument.documentElement.dir = 'rtl'; + verifyCorrectMargin('row', 'margin-left'); + }); + + it('still uses margin-bottom in column layout when body has rtl dir', () => { + fakeDocument.body.dir = 'rtl'; + verifyCorrectMargin('column', 'margin-bottom'); + }); + }); + }); diff --git a/src/lib/api/flexbox/layout-gap.ts b/src/lib/api/flexbox/layout-gap.ts index 7626ebe58..dc85f8a46 100644 --- a/src/lib/api/flexbox/layout-gap.ts +++ b/src/lib/api/flexbox/layout-gap.ts @@ -24,6 +24,7 @@ import {Subscription} from 'rxjs/Subscription'; import {BaseFxDirective} from '../core/base'; import {LayoutDirective} from './layout'; +import {Directionality} from '../../bidi/directionality'; import {MediaChange} from '../../media-query/media-change'; import {MediaMonitor} from '../../media-query/media-monitor'; import {LAYOUT_VALUES} from '../../utils/layout-validator'; @@ -45,6 +46,7 @@ export class LayoutGapDirective extends BaseFxDirective implements AfterContentI protected _layout = 'row'; // default flex-direction protected _layoutWatcher: Subscription; protected _observer: MutationObserver; + private _directionWatcher: Subscription; /* tslint:disable */ @Input('fxLayoutGap') set gap(val) { this._cacheInput('gap', val); } @@ -70,12 +72,15 @@ export class LayoutGapDirective extends BaseFxDirective implements AfterContentI renderer: Renderer2, @Optional() @Self() container: LayoutDirective, private _zone: NgZone, - @Inject(PLATFORM_ID) platformId: Object) { + @Inject(PLATFORM_ID) platformId: Object, + private _directionality: Directionality) { super(monitor, elRef, renderer, platformId); if (container) { // Subscribe to layout direction changes this._layoutWatcher = container.layout$.subscribe(this._onLayoutChange.bind(this)); } + this._directionWatcher = + this._directionality.change.subscribe(this._updateWithValue.bind(this)); } // ********************************************* @@ -108,6 +113,9 @@ export class LayoutGapDirective extends BaseFxDirective implements AfterContentI if (this._observer) { this._observer.disconnect(); } + if (this._directionWatcher) { + this._directionWatcher.unsubscribe(); + } } // ********************************************* @@ -196,7 +204,7 @@ export class LayoutGapDirective extends BaseFxDirective implements AfterContentI case 'row' : case 'row-reverse': default : - key = 'margin-right'; + key = this._directionality.value === 'rtl' ? 'margin-left' : 'margin-right'; break; } margins[key] = value; diff --git a/src/lib/bidi/bidi-module.ts b/src/lib/bidi/bidi-module.ts new file mode 100644 index 000000000..84c482f10 --- /dev/null +++ b/src/lib/bidi/bidi-module.ts @@ -0,0 +1,23 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {NgModule} from '@angular/core'; +import {DOCUMENT} from '@angular/common'; +import {Dir} from './dir'; +import {DIR_DOCUMENT, Directionality} from './directionality'; + + +@NgModule({ + exports: [Dir], + declarations: [Dir], + providers: [ + {provide: DIR_DOCUMENT, useExisting: DOCUMENT}, + Directionality, + ] +}) +export class BidiModule { } diff --git a/src/lib/bidi/bidi.md b/src/lib/bidi/bidi.md new file mode 100644 index 000000000..0ae5f4ed4 --- /dev/null +++ b/src/lib/bidi/bidi.md @@ -0,0 +1,39 @@ +The `bidi` package provides a common system for components to get and respond to change in the +application's LTR/RTL layout direction. This directory was copied straight from +https://github.com/angular/material2/blob/master/src/cdk/bidi/ + +### Directionality + +When including the CDK's `BidiModule`, components can inject `Directionality` to get the current +text direction (RTL or LTR); + +#### Example +```ts +@Component({ ... }) +export class MyWidget implements OnDestroy { + + /** Whether the widget is in RTL mode or not. */ + private isRtl: boolean; + + /** Subscription to the Directionality change EventEmitter. */ + private _dirChangeSubscription = Subscription.EMPTY; + + constructor(dir: Directionality) { + this.isRtl = dir.value === 'rtl'; + + _dirChangeSubscription = dir.change.subscribe(() => { + this.flipDirection(); + }); + } + + ngOnDestroy() { + this._dirChangeSubscription.unsubscribe(); + } +} +``` + +### The `Dir` directive +The `BidiModule` also includes a directive that matches any elements with a `dir` attribute. This +directive has the same API as Directionality and provides itself _as_ `Directionality`. By doing +this, any component that injects `Directionality` will get the closest ancestor layout direction +context. \ No newline at end of file diff --git a/src/lib/bidi/dir.ts b/src/lib/bidi/dir.ts new file mode 100644 index 000000000..56a3f0194 --- /dev/null +++ b/src/lib/bidi/dir.ts @@ -0,0 +1,63 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +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'; + + /** Whether the `value` has been set to its initial value. */ + private _isInitialized: boolean = false; + + /** Event emitted when the direction changes. */ + @Output('dirChange') change = new EventEmitter(); + + /** @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; } + + /** Initialize once default value has been set. */ + ngAfterContentInit() { + this._isInitialized = true; + } + + ngOnDestroy() { + this.change.complete(); + } + } diff --git a/src/lib/bidi/directionality.spec.ts b/src/lib/bidi/directionality.spec.ts new file mode 100644 index 000000000..ad14f0117 --- /dev/null +++ b/src/lib/bidi/directionality.spec.ts @@ -0,0 +1,121 @@ +import {async, fakeAsync, TestBed} from '@angular/core/testing'; +import {Component} from '@angular/core'; +import {By} from '@angular/platform-browser'; +import {BidiModule, Directionality, Direction, DIR_DOCUMENT} from './index'; + +describe('Directionality', () => { + let fakeDocument: FakeDocument; + + 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'; + + let fixture = TestBed.createComponent(InjectsDirectionality); + let 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'; + + let fixture = TestBed.createComponent(InjectsDirectionality); + let 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', () => { + let fixture = TestBed.createComponent(InjectsDirectionality); + let testComponent = fixture.debugElement.componentInstance; + + expect(testComponent.dir.value).toBe('ltr'); + }); + }); + + describe('Dir directive', () => { + it('should provide itself as Directionality', () => { + let 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(() => { + let 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: ` +
+ +
+ ` +}) +class ElementWithDir { + direction = 'rtl'; + changeCount = 0; +} + +/** Test component with Dir directive. */ +@Component({ + selector: 'injects-directionality', + template: `
` +}) +class InjectsDirectionality { + constructor(public dir: Directionality) { } +} + +interface FakeDocument { + documentElement: {dir?: string}; + body: {dir?: string}; +} diff --git a/src/lib/bidi/directionality.ts b/src/lib/bidi/directionality.ts new file mode 100644 index 000000000..323ec17b9 --- /dev/null +++ b/src/lib/bidi/directionality.ts @@ -0,0 +1,55 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import { + EventEmitter, + Injectable, + Optional, + Inject, + InjectionToken, + } from '@angular/core'; + + + export type Direction = 'ltr' | 'rtl'; + + /** + * 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. + */ + export const DIR_DOCUMENT = new InjectionToken('cdk-dir-doc'); + + /** + * The directionality (LTR / RTL) context for the application (or a subtree of it). + * Exposes the current direction and a stream of direction changes. + */ + @Injectable() + export class Directionality { + /** The current 'ltr' or 'rtl' value. */ + readonly value: Direction = 'ltr'; + + /** Stream that emits whenever the 'ltr' / 'rtl' state changes. */ + readonly change = new EventEmitter(); + + 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; + } + } + } diff --git a/src/lib/bidi/index.ts b/src/lib/bidi/index.ts new file mode 100644 index 000000000..676ca90f1 --- /dev/null +++ b/src/lib/bidi/index.ts @@ -0,0 +1,9 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +export * from './public-api'; diff --git a/src/lib/bidi/public-api.ts b/src/lib/bidi/public-api.ts new file mode 100644 index 000000000..3e20fe799 --- /dev/null +++ b/src/lib/bidi/public-api.ts @@ -0,0 +1,11 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +export {Directionality, DIR_DOCUMENT, Direction} from './directionality'; +export {Dir} from './dir'; +export * from './bidi-module'; diff --git a/src/lib/module.ts b/src/lib/module.ts index c0a0f87e1..17e2f82f2 100644 --- a/src/lib/module.ts +++ b/src/lib/module.ts @@ -32,6 +32,8 @@ import {ClassDirective} from './api/ext/class'; import {StyleDirective} from './api/ext/style'; import {ImgSrcDirective} from './api/ext/img-src'; +import {BidiModule} from './bidi/bidi-module'; + /** * Since the equivalent results are easily achieved with a css class attached to each * layout child, these have been deprecated and removed from the API. @@ -59,7 +61,7 @@ const ALL_DIRECTIVES = [ * */ @NgModule({ - imports: [MediaQueriesModule], + imports: [MediaQueriesModule, BidiModule], exports: [MediaQueriesModule, ...ALL_DIRECTIVES], declarations: [...ALL_DIRECTIVES], providers: [