Skip to content

Commit

Permalink
perf(flex): generate style only when the key is different
Browse files Browse the repository at this point in the history
  • Loading branch information
alyleui committed Jun 25, 2018
1 parent 2672bab commit a6fc154
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 93 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
"karma-jasmine": "~1.1.1",
"karma-jasmine-html-reporter": "^0.2.2",
"karma-mocha-reporter": "^2.2.5",
"ng-packagr": "^3.0.1",
"ng-packagr": "^4.0.0-rc.2",
"protractor": "~5.3.0",
"size-limit": "^0.17.0",
"ts-node": "~5.0.1",
Expand All @@ -105,4 +105,4 @@
"limit": "150 KB"
}
]
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<div class="container" [fxDirection]="direction" [fxWrap]="wrap" [fxAlign]="[align, crossAlign, multiAlign]" color="rgba(0,0,0,.2)">
<div class="container" [fxDirection]="direction" [fxWrap]="wrap" [fxAlign]="[align, crossAlign, multiAlign].join(' ')" color="rgba(0,0,0,.2)">
<div class="item" bg="warn" color="auto" *ngFor="let item of items">
<div>{{ item }}</div>
</div>
</div>

<div [fxAlign]="['center']">[fxAlign]="{{ [align, crossAlign, multiAlign] | json }}"</div>
<div fxAlign="center">[fxAlign]="{{ [align, crossAlign, multiAlign].join(' ') }}"</div>
<div fxDisplay="inline">
<ly-radio-group [(ngModel)]="align" fxDirection="column">
<h3>Main Align</h3>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<strong color="warn">{{ item.key }}: </strong>{{ item.mediaQuery }}
</p>
</div>
code <div fx="['align:center:lg', 'align:between:xs']"></div>
<!-- ···deprecated··· -->
<!-- <p>Handset : {{ responsive.observe('Handset') | async | json }}</p>
<p>Tablet : {{ responsive.observe('Tablet') | async | json }}</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { trigger, state, style, transition, animate } from '@angular/animations'
})
export class ResponsiveDemo01Component implements OnDestroy {
private _subscription: Subscription;
private queries: {key: string, mediaQuery: string}[] = [];
queries: {key: string, mediaQuery: string}[] = [];
constructor(
@Inject(LY_MEDIA_QUERIES) mediaQueries: { [key: string]: string; },
public responsive: Responsive
Expand Down
26 changes: 15 additions & 11 deletions src/lib/flex/flex.directive.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ describe('LyFlex', () => {
const computedStyleEl1 = getComputedStyle(element1);
const computedStyleEl2 = getComputedStyle(element2);
expect(element1.className.split(' ').length).toEqual(2);
expect(testComponent.items.first.fxAlign).toEqual([ 'center', 'center' ]);
expect(computedStyleEl1.justifyContent).toEqual('center');
expect(testComponent.items.first.fxAlign).toEqual('between center');
expect(computedStyleEl1.justifyContent).toEqual('space-between');
expect(computedStyleEl1.display).toEqual('flex');
expect(computedStyleEl1.alignItems).toEqual('center');
expect(computedStyleEl1.alignContent).toEqual('center');
Expand All @@ -55,7 +55,13 @@ describe('LyFlex', () => {
fixture.detectChanges();

const testComponent = fixture.componentInstance;
expect(testComponent.fx.fxAlign).toEqual(`start stretch stretch`);
const element = fixture.debugElement.query(By.css('div')).nativeElement;
const computedStyleEl = getComputedStyle(element);
expect(testComponent.fx.fxAlign).toEqual(`start stretch`);
expect(computedStyleEl.justifyContent).toEqual('flex-start');
expect(computedStyleEl.display).toEqual('flex');
expect(computedStyleEl.alignItems).toEqual('stretch');
expect(computedStyleEl.alignContent).toEqual('stretch');
});

it('should set default `row wrap` on `fxFlow`', () => {
Expand All @@ -67,11 +73,10 @@ describe('LyFlex', () => {
const computedStyle = getComputedStyle(element);
expect(computedStyle.flexFlow).toEqual('row wrap');
expect(testComponent.fx.fxFlow).toEqual('row wrap');
testComponent.fx.fxFlow = 'row wrap';
testComponent.fx.fxFlow = 'row nowrap';
expect(testComponent.fx.fxFlow).toEqual('row nowrap');
testComponent.fx.fxFlow = ['row', 'nowrap'];
expect(testComponent.fx.fxFlow).toEqual(['row', 'nowrap']);
testComponent.fx.fxFlow = 'row nowrap';
expect(testComponent.fx.fxFlow).toEqual('row nowrap');

});

Expand All @@ -82,10 +87,10 @@ describe('LyFlex', () => {
const testComponent = fixture.componentInstance;
const element = fixture.debugElement.query(By.css('div')).nativeElement;
const computedStyle = getComputedStyle(element);
expect(computedStyle.display).toEqual('inline-flex');
expect(testComponent.fx.fxDisplay).toEqual('inline');
testComponent.fx.fxDisplay = 'inline';
expect(testComponent.fx.fxDisplay).toEqual('inline');
expect(computedStyle.display).toEqual('inline-flex');
// testComponent.fx.fxDisplay = 'inline';
// expect(testComponent.fx.fxDisplay).toEqual('inline');
});

it('should set default `row` on `fxDirection`', () => {
Expand All @@ -112,12 +117,11 @@ describe('LyFlex', () => {
const computedStyle = getComputedStyle(element);
expect(computedStyle.flexWrap).toEqual('wrap');
expect(testComponent.fx.fxWrap).toEqual('wrap');
testComponent.fx.fxWrap = 'wrap';
});
});

@Component({template: `
<div a [fxAlign]="['center', 'center']"></div>
<div a fxAlign="between center"></div>
<div b fxAlign="center center"></div>
`})
class FlexAlign {
Expand Down
149 changes: 92 additions & 57 deletions src/lib/flex/flex.directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,16 @@ enum __align {

export type FxDirection = 'row' | 'rowReverse' | 'column' | 'columnReverse' | null;
export type FxWrap = 'nowrap' | 'wrap' | 'wrap-reverse' | null;
export type FxFlow = [FxDirection, FxWrap] | string;
/** [FxDirection, FxWrap] */
export type FxFlow = string;
export type FxJustifyContent = 'start' | 'end' | 'center' | 'between' | 'around' | 'evenly' | null;
export type FxAlignItems = 'start' | 'end' | 'center' | 'baseline' | 'stretch' | null;
export type FxAlignContent = 'start' | 'end' | 'center' | 'between' | 'around' | 'stretch' | null;
export type FxAlignItemsAndContent = 'start' | 'center' | 'end' | 'stretch' | null;
/**
* TODO: remove array type, FxAlign = string;
* [FxJustifyContent] | [FxJustifyContent, FxAlignItemsAndContent] | [FxJustifyContent, FxAlignItems, FxAlignContent]
*/
export type FxAlign = [FxJustifyContent] | [FxJustifyContent, FxAlignItemsAndContent] | [FxJustifyContent, FxAlignItems, FxAlignContent] | string;
export type FxAlign = string;

@Directive({
// tslint:disable-next-line:directive-selector
Expand All @@ -42,25 +43,28 @@ export type FxAlign = [FxJustifyContent] | [FxJustifyContent, FxAlignItemsAndCon
export class LyFlex implements OnChanges {
private _fxDisplay: 'flex' | 'inline';
private fxDisplayClass: string;
private _fxFlow: FxFlow; // <FxDirection> + <FxWrap>

/** <FxDirection> + <FxWrap> */
private _fxFlow: FxFlow;
private fxFlowClass: string;

private _fxAlign: FxAlign;
private fxAlignClass: string;

private _fxDirection: FxDirection;
private fxDirectionClass: string;

private _fxWrap: FxWrap;
private fxWrapClass: string;
private _currentClassname: string;

@Input()
set fx(val: string) {
// code
set fx(val: string[]) {
// code <div fx="['align:center:lg', 'align:between:xs']"></div>
}
@Input()
set fxDisplay(val: 'flex' | 'inline') {
if (this._fxDisplay !== val) {
this._fxDisplay = val || 'flex';
const newClass = this._createDisplayClass(this._fxDisplay);
if (this.fxDisplay !== val) {
const newClass = this._createDisplayClass(val);
this.coreTheme.updateClassName(this.elementRef.nativeElement, this.renderer, newClass, this.fxDisplayClass);
this.fxDisplayClass = newClass;
}
Expand All @@ -71,17 +75,8 @@ export class LyFlex implements OnChanges {

@Input()
set fxFlow(val: FxFlow) {
if (this._fxFlow !== val) {
const newVal = val || 'row wrap';
const key = typeof val === 'string' ? newVal as string : `${val[0]} ${val[1]}`;
this._fxFlow = val || key;

/** create Style */
const newClass = this.coreTheme.setUpStyle(key,
() => (
`flex-flow:${key}`
)
);
if (this.fxFlow !== val) {
const newClass = this._createFlowClass(val);
/** Add class */
this.coreTheme.updateClassName(this.elementRef.nativeElement, this.renderer, newClass, this.fxFlowClass);
this.fxFlowClass = newClass;
Expand All @@ -93,23 +88,10 @@ export class LyFlex implements OnChanges {

@Input()
set fxAlign(val: FxAlign) {
if (this._fxAlign !== val) {
const arrayVal = typeof val === 'string' ? val.split(' ') : val;

const justifyContent = arrayVal[0] || 'start';
const alignItems = arrayVal[1] || 'stretch';
const alignContent = arrayVal[2];

const key = !!val && typeof val === 'string' ? val : `${justifyContent} ${alignItems} ${alignContent || alignItems}`;
this._fxAlign = val || key;
if (this.fxAlign !== val) {
/** create Style */
const newClass = this.coreTheme.setUpStyle(key, {
'': () => (
`justify-content:${__align[justifyContent]};` +
`align-items:${__align[alignItems]};` +
`align-content:${__align[alignContent || alignItems]};`
)
});
const newClass = this._createAlignClass(val);

/** Add class */
this.coreTheme.updateClassName(this.elementRef.nativeElement, this.renderer, newClass, this.fxAlignClass);
this.fxAlignClass = newClass;
Expand All @@ -125,11 +107,7 @@ export class LyFlex implements OnChanges {
const newKey = val || 'row';
this._fxDirection = newKey;
/** create Style */
const newClass = this.coreTheme.setUpStyle(newKey, {
'': () => (
`flex-direction:${__align[newKey]};`
)
});
const newClass = this._createDirectionClass(val);
this.coreTheme.updateClassName(this.elementRef.nativeElement, this.renderer, newClass, this.fxDirectionClass);
this.fxDirectionClass = newClass;
}
Expand All @@ -140,15 +118,9 @@ export class LyFlex implements OnChanges {

@Input()
set fxWrap(val: FxWrap) {
if (this._fxWrap !== val) {
const newKey = val || 'wrap';
this._fxWrap = newKey;
if (this.fxWrap !== val) {
/** create Style */
const newClass = this.coreTheme.setUpStyle(val, {
'': () => (
`flex-wrap:${__align[newKey]};`
)
});
const newClass = this._createWrapClass(val);
this.coreTheme.updateClassName(this.elementRef.nativeElement, this.renderer, newClass, this.fxWrapClass);
this.fxWrapClass = newClass;
}
Expand All @@ -164,19 +136,82 @@ export class LyFlex implements OnChanges {
) { }

ngOnChanges(changes: SimpleChanges) {
if (!this.fxDisplayClass) {
if (!this._fxDisplay && !this.fxDisplayClass) {
/** Set default display */
this.fxDisplay = null;
}
}

private _createDisplayClass(val: 'flex' | 'inline' = 'flex') {
return this.coreTheme.setUpStyle(
`k-fx-display-${val}`,
() => {
return val === 'inline' ? `display:inline-flex;` : `display:flex;`;
}
private _createDisplayClass(val: 'flex' | 'inline') {
this._checkVal(val);

this._fxDisplay = val || 'flex';
return this.coreTheme.setUpStyle(`k-fx-display:${this.fxDisplay}`,
() => (
val === 'inline' ? `display:inline-flex;` : `display:flex;`
)
);
}

private _createFlowClass(val: string) {
this._checkVal(val);

this._fxFlow = val || 'row wrap';

/** create Style */
return this.coreTheme.setUpStyle(`k-fx-flow:${this.fxFlow}`,
() => `flex-flow:${this.fxFlow}`
);
}

private _createAlignClass(val: string) {
this._checkVal(val);

this._fxAlign = val || 'start stretch';
/** create Style */
return this.coreTheme.setUpStyle(`k-fx-align:${this.fxAlign}`,
() => {
const arrayVal = this.fxAlign.split(' ');

const justifyContent = arrayVal[0] || 'start';
const alignItems = arrayVal[1] || 'stretch';
const alignContent = arrayVal[2];
return (
`justify-content:${__align[justifyContent]};` +
`align-items:${__align[alignItems]};` +
`align-content:${__align[alignContent || alignItems]};`
);
}
);
}

private _createDirectionClass(val: FxDirection) {

this._fxDirection = val || 'row';
/** create Style */
return this.coreTheme.setUpStyle(`k-fx-direction:${this.fxDirection}`, {
'': () => (
`flex-direction:${__align[this.fxDirection]};`
)
});
}

private _createWrapClass(val: FxWrap) {
this._fxWrap = val || 'wrap';
/** create Style */
return this.coreTheme.setUpStyle(`k-fx-wrap:${this.fxWrap}`, {
'': () => (
`flex-wrap:${__align[this.fxWrap]};`
)
});
}

/** Check if value is string else emit error */
private _checkVal(val: any) {
if (isDevMode() && Array.isArray(val)) {
console.warn(val, this.elementRef, `\n🠋🠋🠋🠋🠋🠋🠋🠋🠋🠋🠋🠋🠋🠋🠋🠋🠋🠋🠋🠋`);
throw new Error(`value: '${val}' is not a string in`);
}
}

}
4 changes: 3 additions & 1 deletion src/lib/responsive/tokens.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { InjectionToken } from '@angular/core';

export const LY_MEDIA_QUERIES = new InjectionToken<any>('ly·media·queries');
export const LY_MEDIA_QUERIES = new InjectionToken<LyMediaQueries>('ly·media·queries');

export interface LyMediaQueries { [key: string]: string; }
Loading

0 comments on commit a6fc154

Please sign in to comment.