From f4b38c74f24e6aef8a3eef1348dfbe2c62c8f863 Mon Sep 17 00:00:00 2001 From: Thomas Burleson Date: Tue, 14 Feb 2017 11:01:08 -0600 Subject: [PATCH] fix(fxFlex): fxFlex=auto with overlapping breakpoints activated Layout changes from gt-sm will not restore default layout with auto fixes #135. --- package.json | 2 +- .../DemosResponsiveLayouts.ts | 3 +- .../app/github-issues/DemosGithubIssues.ts | 27 +++--- .../app/github-issues/issue.135.demo.ts | 53 ++++++++++++ src/lib/flexbox/api/flex.spec.ts | 83 +++++++++++++++++-- src/lib/flexbox/api/flex.ts | 2 +- src/lib/utils/testing/custom-matchers.ts | 3 +- 7 files changed, 149 insertions(+), 24 deletions(-) create mode 100644 src/demo-app/app/github-issues/issue.135.demo.ts diff --git a/package.json b/package.json index b1ba07b44..675b049df 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "@types/glob": "^5.0.29", "@types/gulp": "^3.8.29", "@types/hammerjs": "~2.0.33", - "@types/jasmine": "^2.2.34", + "@types/jasmine": "2.5.38", "@types/merge2": "0.0.28", "@types/minimist": "^1.1.28", "@types/node": "^6.0.45", diff --git a/src/demo-app/app/docs-layout-responsive/DemosResponsiveLayouts.ts b/src/demo-app/app/docs-layout-responsive/DemosResponsiveLayouts.ts index dd056d6b6..bf7043caa 100644 --- a/src/demo-app/app/docs-layout-responsive/DemosResponsiveLayouts.ts +++ b/src/demo-app/app/docs-layout-responsive/DemosResponsiveLayouts.ts @@ -35,8 +35,7 @@ import {DemoResponsiveStyle} from "./responsiveStyle.demo"; DemoResponsiveFlexDirectives, DemoResponsiveFlexOrder, DemoResponsiveShowHide, - DemoResponsiveStyle - + DemoResponsiveStyle, ], imports : [ CommonModule, diff --git a/src/demo-app/app/github-issues/DemosGithubIssues.ts b/src/demo-app/app/github-issues/DemosGithubIssues.ts index a6b635e4d..5db11f220 100644 --- a/src/demo-app/app/github-issues/DemosGithubIssues.ts +++ b/src/demo-app/app/github-issues/DemosGithubIssues.ts @@ -3,29 +3,32 @@ import {Component} from '@angular/core'; @Component({ selector: 'demos-github-issues', template: ` - - - - ` + + + + + ` }) export class DemosGithubIssues { } -import {NgModule} from '@angular/core'; -import {CommonModule} from "@angular/common"; -import {MaterialModule} from "@angular/material"; -import {FlexLayoutModule} from "../../../lib"; // `gulp build:components` to deploy to node_modules manually +import {NgModule} from '@angular/core'; +import {CommonModule} from "@angular/common"; +import {MaterialModule} from "@angular/material"; +import {FlexLayoutModule} from "../../../lib"; // `gulp build:components` to deploy to node_modules manually -import {DemoIssue5345} from "./issue.5345.demo"; -import {DemoIssue9897} from "./issue.9897.demo"; -import {DemoIssue181} from './issue.181.demo'; +import {DemoIssue5345} from "./issue.5345.demo"; +import {DemoIssue9897} from "./issue.9897.demo"; +import {DemoIssue181} from './issue.181.demo'; +import {DemoIssue135} from "./issue.135.demo"; @NgModule({ declarations: [ DemosGithubIssues, // used by the Router with the root app component DemoIssue5345, DemoIssue9897, - DemoIssue181 + DemoIssue181, + DemoIssue135 ], imports: [ CommonModule, diff --git a/src/demo-app/app/github-issues/issue.135.demo.ts b/src/demo-app/app/github-issues/issue.135.demo.ts new file mode 100644 index 000000000..4259ea753 --- /dev/null +++ b/src/demo-app/app/github-issues/issue.135.demo.ts @@ -0,0 +1,53 @@ +import {Component, OnInit, OnDestroy} from '@angular/core'; +import {Subscription} from "rxjs/Subscription"; +import 'rxjs/add/operator/filter'; + +import {MediaChange} from "../../../lib/media-query/media-change"; +import { ObservableMedia } from "../../../lib/media-query/observable-media-service"; + +@Component({ + selector: 'demo-issue-135', + styleUrls : [ + '../demo-app/material2.css' + ], + template: ` + + Issue #135 + Layout with fxFlex="auto" not restoring max-height values properly: + +
+
+
<div fxFlex="auto" fxFlex.gt-sm="70" >
+
<div fxFlex="auto" fxFlex.gt-sm="14.6">
+
<div fxFlex="auto" fxFlex.gt-sm="15.4">
+
+
+
+ +
Active mediaQuery: {{ activeMediaQuery }}
+
+
+ ` +}) +export class DemoIssue135 implements OnInit, OnDestroy { + public activeMediaQuery = ""; + private _watcher : Subscription; + + constructor(private _media$:ObservableMedia) { } + + ngOnInit() { + this._watcher = this.watchMQChanges(); + } + + ngOnDestroy() { + this._watcher.unsubscribe(); + } + + + watchMQChanges() { + return this._media$.subscribe((change:MediaChange) => { + let value = change ? `'${change.mqAlias}' = (${change.mediaQuery})` : ""; + this.activeMediaQuery = value; + }); + } +} diff --git a/src/lib/flexbox/api/flex.spec.ts b/src/lib/flexbox/api/flex.spec.ts index 2a22f6c75..2b2c33b9e 100644 --- a/src/lib/flexbox/api/flex.spec.ts +++ b/src/lib/flexbox/api/flex.spec.ts @@ -16,11 +16,13 @@ import {MatchMedia} from '../../media-query/match-media'; import {FlexLayoutModule} from '../_module'; import {__platform_browser_private__} from '@angular/platform-browser'; -import {customMatchers, expect } from '../../utils/testing/custom-matchers'; +import {customMatchers, expect} from '../../utils/testing/custom-matchers'; import { makeExpectDOMFrom, makeExpectDOMForQuery, - makeCreateTestComponent + makeCreateTestComponent, + expectNativeEl, + queryFor } from '../../utils/testing/helpers'; const getDOM = __platform_browser_private__.getDOM; @@ -31,6 +33,10 @@ describe('flex directive', () => { let expectDOMFrom = makeExpectDOMFrom(() => TestFlexComponent); let expectDomForQuery = makeExpectDOMForQuery(() => TestFlexComponent); let componentWithTemplate = makeCreateTestComponent(() => TestFlexComponent); + let activateMediaQuery = (alias, allowOverlaps?: boolean) => { + let matchMedia: MockMatchMedia = fixture.debugElement.injector.get(MatchMedia); + matchMedia.activate(alias, allowOverlaps); + }; beforeEach(() => { jasmine.addMatchers(customMatchers); @@ -60,10 +66,10 @@ describe('flex directive', () => { let dom = fRef.debugElement.children[0].nativeElement; let isBox = getDOM().hasStyle(dom, 'box-sizing', 'border-box'); - let hasFlex = getDOM().hasStyle(dom, 'flex', '1 1 1e-09px') || // IE - getDOM().hasStyle(dom, 'flex', '1 1 1e-9px') || // Chrome - getDOM().hasStyle(dom, 'flex', '1 1 0.000000001px') || // Safari - getDOM().hasStyle(dom, 'flex', '1 1 0px'); + let hasFlex = getDOM().hasStyle(dom, 'flex', '1 1 1e-09px') || // IE + getDOM().hasStyle(dom, 'flex', '1 1 1e-9px') || // Chrome + getDOM().hasStyle(dom, 'flex', '1 1 0.000000001px') || // Safari + getDOM().hasStyle(dom, 'flex', '1 1 0px'); expect(isBox).toBeTruthy(); expect(hasFlex).toBeTruthy(); @@ -104,7 +110,7 @@ describe('flex directive', () => { }); it('should work with calc values', () => { // @see http://caniuse.com/#feat=calc for IE issues with calc() - if ( !isIE ) { + if (!isIE) { expectDOMFrom(`
`).toHaveCssStyle({ 'box-sizing': 'border-box', 'flex': '1 1 calc(30vw - 10px)' @@ -246,7 +252,70 @@ describe('flex directive', () => { }); }); + describe('with responsive features', () => { + it('should initialize the component with the largest matching breakpoint', () => { + fixture = componentWithTemplate(` +
+
+ `); + + activateMediaQuery('xl'); + expectNativeEl(fixture).toHaveCssStyle({ + 'flex': '1 1 50%' + }); + + activateMediaQuery('sm'); + expectNativeEl(fixture).toHaveCssStyle({ + 'flex': '1 1 33%' + }); + }); + + it('should fallback the default layout properly', () => { + fixture = componentWithTemplate(` +
+
+
+
+
+ `); + + activateMediaQuery('sm', true); + fixture.detectChanges(); + + let nodes = queryFor(fixture, "[fxFlex]"); + expect(nodes.length).toEqual(3); + expect(nodes[0].nativeElement).toHaveCssStyle({'flex': '1 1 auto'}); + expect(nodes[1].nativeElement).toHaveCssStyle({'flex': '1 1 auto'}); + expect(nodes[2].nativeElement).toHaveCssStyle({'flex': '1 1 auto'}); + + activateMediaQuery('xl', true); + fixture.detectChanges(); + + nodes = queryFor(fixture, "[fxFlex]"); + expect(nodes[0].nativeElement).toHaveCssStyle({'flex': '1 1 100%', 'max-height': '50%'}); + expect(nodes[1].nativeElement).toHaveCssStyle({'flex': '1 1 100%', 'max-height': '24.4%'}); + expect(nodes[2].nativeElement).toHaveCssStyle({'flex': '1 1 100%', 'max-height': '25.6%'}); + + activateMediaQuery('sm', true); + fixture.detectChanges(); + + nodes = queryFor(fixture, "[fxFlex]"); + expect(nodes.length).toEqual(3); + expect(nodes[0].nativeElement).toHaveCssStyle({'flex': '1 1 auto'}); + expect(nodes[1].nativeElement).toHaveCssStyle({'flex': '1 1 auto'}); + expect(nodes[2].nativeElement).toHaveCssStyle({'flex': '1 1 auto'}); + + expect(nodes[0].nativeElement).not.toHaveCssStyle({'max-height': '50%'}); + expect(nodes[1].nativeElement).not.toHaveCssStyle({'max-height': '24.4%'}); + expect(nodes[2].nativeElement).not.toHaveCssStyle({'max-height': '25.6%'}); + expect(nodes[0].nativeElement).not.toHaveCssStyle({'max-height': '*'}); + expect(nodes[1].nativeElement).not.toHaveCssStyle({'max-height': '*'}); + expect(nodes[2].nativeElement).not.toHaveCssStyle({'max-height': '*'}); + }); + }); }); diff --git a/src/lib/flexbox/api/flex.ts b/src/lib/flexbox/api/flex.ts index 5fb49b118..c2f3374be 100644 --- a/src/lib/flexbox/api/flex.ts +++ b/src/lib/flexbox/api/flex.ts @@ -307,7 +307,7 @@ export class FlexDirective extends BaseFxDirective implements OnInit, OnChanges, let max = (direction === 'row') ? 'max-width' : 'max-height'; let min = (direction === 'row') ? 'min-width' : 'min-height'; - let usingCalc = String(basis).indexOf('calc') > -1; + let usingCalc = (String(basis).indexOf('calc') > -1) || (basis == 'auto'); let isPx = String(basis).indexOf('px') > -1 || usingCalc; diff --git a/src/lib/utils/testing/custom-matchers.ts b/src/lib/utils/testing/custom-matchers.ts index 494635b28..734da8e34 100644 --- a/src/lib/utils/testing/custom-matchers.ts +++ b/src/lib/utils/testing/custom-matchers.ts @@ -148,7 +148,8 @@ export const customMatchers: jasmine.CustomMatcherFactories = { * (Safari, IE, etc) will use prefixed style instead of defaults. */ function hasPrefixedStyles(actual, key, value) { - let hasStyle = getDOM().hasStyle(actual, key, value.trim()); + value = value !== "*" ? value.trim() : undefined; + let hasStyle = getDOM().hasStyle(actual, key, value); if (!hasStyle) { let prefixedStyles = applyCssPrefixes({[key]: value}); Object.keys(prefixedStyles).forEach(prop => {