Skip to content
This repository was archived by the owner on Jan 6, 2025. It is now read-only.

Commit f57a63d

Browse files
joanllenastinayuangao
authored andcommitted
feat(api): add responsive support for ngClass and ngStyle (#170)
* update(flexbox): refactor fxStyle and fxClass code * refactor code to `base-adapter.ts` * update(flexbox): refactor fxStyle and fxClass code * refactor code to `base-adapter.ts` * feat(api): add responsive support for ngClass and ngStyle
1 parent e6bc451 commit f57a63d

File tree

12 files changed

+839
-5
lines changed

12 files changed

+839
-5
lines changed

src/demo-app/app/demo-app/demo-app.css

+32
Original file line numberDiff line numberDiff line change
@@ -192,3 +192,35 @@ md-toolbar .md-toolbar-layout md-toolbar-row {
192192
.demo-content .small-demo:first-child {
193193
margin-top: 40px;
194194
}
195+
196+
md-card-content pre {
197+
font-size: 12px;
198+
white-space: pre-wrap;
199+
}
200+
201+
.fxClass-all {
202+
font-style: italic;
203+
}
204+
205+
.fxClass-xs {
206+
font-size: 10px;
207+
color: blue!important;
208+
}
209+
.fxClass-sm {
210+
font-size: 20px;
211+
color: lightblue!important;
212+
}
213+
.fxClass-md {
214+
font-size: 30px;
215+
color: orange!important;
216+
}
217+
.fxClass-md2 {
218+
font-weight: bold;
219+
}
220+
.fxClass-lg {
221+
font-size: 40px;
222+
color: lightgreen!important;
223+
}
224+
.fxClass-lg2 {
225+
text-shadow: #5c5c5c;
226+
}

src/demo-app/app/docs-layout-responsive/DemosResponsiveLayouts.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { Component } from '@angular/core';
88
<demo-responsive-flex-directive class="small-demo"> </demo-responsive-flex-directive>
99
<demo-responsive-flex-order class="small-demo"> </demo-responsive-flex-order>
1010
<demo-responsive-show-hide class="small-demo"> </demo-responsive-show-hide>
11+
<demo-responsive-style class="small-demo"> </demo-responsive-style>
1112
`
1213
})
1314
export class DemosResponsiveLayout { }
@@ -23,7 +24,7 @@ import {DemoResponsiveLayoutDirection } from "./responsiveLayoutDirections.demo
2324
import {DemoResponsiveShowHide} from "./responsiveShowHide.demo";
2425
import {DemoResponsiveFlexDirectives} from "./responsiveFlexDirective.demo";
2526
import {DemoResponsiveFlexOrder} from "./responsiveFlexOrder.demo";
26-
27+
import {DemoResponsiveStyle} from "./responsiveStyle.demo";
2728

2829
@NgModule({
2930
declarations : [
@@ -33,7 +34,8 @@ import {DemoResponsiveFlexOrder} from "./responsiveFlexOrder.demo";
3334
DemoResponsiveLayoutDirection,
3435
DemoResponsiveFlexDirectives,
3536
DemoResponsiveFlexOrder,
36-
DemoResponsiveShowHide
37+
DemoResponsiveShowHide,
38+
DemoResponsiveStyle
3739

3840
],
3941
imports : [
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import { Component, OnInit, Inject, OnDestroy } from '@angular/core';
2+
import { Subscription } from "rxjs/Subscription";
3+
import 'rxjs/add/operator/filter';
4+
5+
import { MediaChange } from "../../../lib/media-query/media-change";
6+
import { ObservableMedia } from "../../../lib/media-query/observable-media-service";
7+
8+
@Component({
9+
selector: 'demo-responsive-style',
10+
styleUrls: [
11+
'../demo-app/material2.css'
12+
],
13+
template: `
14+
15+
<md-card class="card-demo" >
16+
<md-card-title>Responsive Style</md-card-title>
17+
<md-card-subtitle>
18+
Use the fxClass and fxStyle APIs to responsively apply styles to elements:
19+
</md-card-subtitle>
20+
21+
<md-card-content>
22+
<div class="containerX">
23+
<div fxLayout="row" fxFlex class="coloredContainerX box">
24+
<div
25+
fxFlex
26+
class="fxClass-all"
27+
class.xs="fxClass-xs"
28+
[class.sm]="{'fxClass-sm': hasStyle}"
29+
[class.md]="{'fxClass-md': hasStyle, 'fxClass-md2': hasStyle}"
30+
[class.lg]="['fxClass-lg', 'fxClass-lg2']">
31+
{{ activeMediaQueryAlias }}
32+
<md-checkbox
33+
[(ngModel)]="hasStyle"
34+
fxShow="false"
35+
[fxShow.sm]="true"
36+
[fxShow.md]="true">
37+
Activate styles
38+
</md-checkbox>
39+
</div>
40+
</div>
41+
</div>
42+
</md-card-content>
43+
<md-card-content>
44+
<pre>
45+
&lt;div
46+
fxFlex
47+
class="fxClass-all"
48+
class.xs="fxClass-xs"
49+
[class.sm]="&#123;'fxClass-sm': hasStyle&#125;"
50+
[class.md]="&#123;'fxClass-md': hasStyle, 'fxClass-md2': hasStyle&#125;"
51+
[class.lg]="['fxClass-lg', 'fxClass-lg2']"&gt;
52+
&lt;/div&gt;
53+
</pre>
54+
</md-card-content>
55+
56+
<md-card-content>
57+
<div class="containerX">
58+
<div fxLayout="row" fxFlex class="coloredContainerX box">
59+
<div
60+
fxFlex
61+
style="font-style: italic"
62+
[style.xs]="{'font-size.px': 10, color: 'blue'}"
63+
[style.sm]="{'font-size.px': 20, color: 'lightblue'}"
64+
[style.md]="{'font-size.px': 30, color: 'orange'}"
65+
[style.lg]="styleLgExp">
66+
{{ activeMediaQueryAlias }}
67+
</div>
68+
</div>
69+
</div>
70+
</md-card-content>
71+
<md-card-content>
72+
<pre>
73+
&lt;div
74+
style="font-style: italic"
75+
[style.xs]="&#123;'font-size.px': 10, color: 'blue'&#125;"
76+
[style.sm]="&#123;'font-size.px': 20, color: 'lightblue'&#125;"
77+
[style.md]="&#123;'font-size.px': 30, color: 'orange'&#125;"
78+
[style.lg]="styleLgExp"&gt;
79+
&lt;/div&gt;
80+
</pre>
81+
</md-card-content>
82+
83+
84+
<md-card-footer style="width:95%">
85+
<div class="hint" >Active mediaQuery: <span style="padding-left: 20px; color: rgba(0, 0, 0, 0.54)">{{ activeMediaQuery }}</span></div>
86+
</md-card-footer>
87+
</md-card>
88+
`
89+
})
90+
export class DemoResponsiveStyle implements OnDestroy {
91+
private _watcher: Subscription;
92+
public activeMediaQuery = "";
93+
public activeMediaQueryAlias = "";
94+
public hasStyle: boolean = false;
95+
public styleLgExp = {
96+
'font-size': '40px',
97+
color: 'lightgreen'
98+
};
99+
100+
constructor( private _media$:ObservableMedia ) {
101+
this._watcher = this._media$.subscribe((change: MediaChange) => {
102+
this.activeMediaQuery = change ? `'${change.mqAlias}' = ${change.mediaQuery} )` : "";
103+
this.activeMediaQueryAlias = change.mqAlias;
104+
});
105+
}
106+
107+
ngOnDestroy() {
108+
this._watcher.unsubscribe();
109+
}
110+
}

src/lib/flexbox/_module.ts

+4
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import {FlexOrderDirective} from './api/flex-order';
2323
import {LayoutAlignDirective} from './api/layout-align';
2424
import {LayoutWrapDirective} from './api/layout-wrap';
2525
import {LayoutGapDirective} from './api/layout-gap';
26+
import {ClassDirective} from './api/class';
27+
import {StyleDirective} from './api/style';
2628

2729
/**
2830
* Since the equivalent results are easily achieved with a css class attached to each
@@ -44,6 +46,8 @@ const ALL_DIRECTIVES = [
4446
FlexAlignDirective,
4547
ShowDirective,
4648
HideDirective,
49+
ClassDirective,
50+
StyleDirective,
4751
];
4852

4953
/**
+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
import {ElementRef} from '@angular/core';
9+
import {BaseFxDirectiveAdapter} from './base-adapter';
10+
import {expect} from '../../utils/testing/custom-matchers';
11+
12+
export class MockElementRef extends ElementRef {
13+
constructor() {
14+
const nEl = document.createElement('DIV');
15+
super(nEl);
16+
this.nativeElement = nEl;
17+
}
18+
}
19+
20+
describe('BaseFxDirectiveAdapter class', () => {
21+
let component;
22+
beforeEach(() => {
23+
component = new BaseFxDirectiveAdapter(null, new MockElementRef(), null);
24+
});
25+
describe('cacheInput', () => {
26+
it('should call _cacheInputArray when source is an array', () => {
27+
spyOn(component, '_cacheInputArray');
28+
component.cacheInput('key', []);
29+
expect(component._cacheInputArray).toHaveBeenCalled();
30+
});
31+
it('should call _cacheInputObject when source is an object', () => {
32+
spyOn(component, '_cacheInputObject');
33+
component.cacheInput('key', {});
34+
expect(component._cacheInputObject).toHaveBeenCalled();
35+
});
36+
it('should call _cacheInputString when source is a string', () => {
37+
spyOn(component, '_cacheInputString');
38+
component.cacheInput('key', '');
39+
expect(component._cacheInputString).toHaveBeenCalled();
40+
});
41+
it('should throw when source is not an object, array or string', () => {
42+
expect(component.cacheInput.bind(null, true)).toThrow();
43+
});
44+
});
45+
46+
});
47+
48+
49+

src/lib/flexbox/api/base-adapter.ts

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/**
2+
* Adapted BaseFxDirective abtract class version so it can be used via composition.
3+
*
4+
* @see BaseFxDirective
5+
*/
6+
import {BaseFxDirective} from './base';
7+
import {ResponsiveActivation} from './../responsive/responsive-activation';
8+
import {MediaQuerySubscriber} from '../../media-query/media-change';
9+
10+
export class BaseFxDirectiveAdapter extends BaseFxDirective {
11+
get inputMap() {
12+
return this._inputMap;
13+
}
14+
15+
/**
16+
* Save the property value.
17+
*/
18+
cacheInput(key?: string, source?: any) {
19+
if (Array.isArray(source)) {
20+
this._cacheInputArray(key, source);
21+
} else if (typeof source === 'object') {
22+
this._cacheInputObject(key, source);
23+
} else if (typeof source === 'string') {
24+
this._cacheInputString(key, source);
25+
} else {
26+
throw new Error('Invalid class value provided');
27+
}
28+
}
29+
30+
_cacheInputRaw(key?: string, source?: any) {
31+
this._inputMap[key] = source;
32+
}
33+
34+
/**
35+
* Save the property value for Array values.
36+
*/
37+
_cacheInputArray(key?: string, source?: boolean[]) {
38+
this._inputMap[key] = source.join(' ');
39+
}
40+
41+
/**
42+
* Save the property value for key/value pair values.
43+
*/
44+
_cacheInputObject(key?: string, source?: {[key: string]: boolean}) {
45+
let classes = [];
46+
for (let prop in source) {
47+
if (!!source[prop]) {
48+
classes.push(prop);
49+
}
50+
}
51+
this._inputMap[key] = classes.join(' ');
52+
}
53+
54+
/**
55+
* Save the property value for string values.
56+
*/
57+
_cacheInputString(key?: string, source?: string) {
58+
this._inputMap[key] = source;
59+
}
60+
61+
/**
62+
* @see BaseFxDirective._listenForMediaQueryChanges
63+
*/
64+
listenForMediaQueryChanges(key: string,
65+
defaultValue: any,
66+
onMediaQueryChange: MediaQuerySubscriber): ResponsiveActivation {
67+
return this._listenForMediaQueryChanges(key, defaultValue, onMediaQueryChange);
68+
}
69+
70+
/**
71+
* @see BaseFxDirective._queryInput
72+
*/
73+
queryInput(key) {
74+
return this._queryInput(key);
75+
}
76+
77+
/**
78+
* @see BaseFxDirective._mqActivation
79+
*/
80+
get mqActivation(): ResponsiveActivation {
81+
return this._mqActivation;
82+
}
83+
}

0 commit comments

Comments
 (0)