Skip to content

Commit

Permalink
fix(fxFlex): improve support for 'auto' and flex-basis variations (#212)
Browse files Browse the repository at this point in the history
  • Loading branch information
ThomasBurleson authored and tinayuangao committed Mar 10, 2017
1 parent 2340a19 commit c28dfc7
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 93 deletions.
106 changes: 33 additions & 73 deletions src/lib/flexbox/api/flex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,9 @@ export type FlexBasisAlias = 'grow' | 'initial' | 'auto' | 'none' | 'nogrow' | '
* @see https://css-tricks.com/snippets/css/a-guide-to-flexbox/
*/
@Directive({selector: `
[fxFlex],
[fxFlex.xs],
[fxFlex.gt-xs],
[fxFlex.sm],
[fxFlex.gt-sm],
[fxFlex.md],
[fxFlex.gt-md],
[fxFlex.lg],
[fxFlex.gt-lg],
[fxFlex.xl]
[fxFlex],
[fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl],
[fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]
`
})
export class FlexDirective extends BaseFxDirective implements OnInit, OnChanges, OnDestroy {
Expand All @@ -63,55 +56,23 @@ export class FlexDirective extends BaseFxDirective implements OnInit, OnChanges,
*/
protected _layoutWatcher: Subscription;

@Input('fxFlex') set flex(val) {
this._cacheInput("flex", val);
}

@Input('fxShrink') set shrink(val) {
this._cacheInput("shrink", val);
}

@Input('fxGrow') set grow(val) {
this._cacheInput("grow", val);
}

@Input('fxFlex.xs') set flexXs(val) {
this._cacheInput('flexXs', val);
}

@Input('fxFlex.gt-xs') set flexGtXs(val) {
this._cacheInput('flexGtXs', val);
};

@Input('fxFlex.sm') set flexSm(val) {
this._cacheInput('flexSm', val);
};

@Input('fxFlex.gt-sm') set flexGtSm(val) {
this._cacheInput('flexGtSm', val);
};
/* tslint:disable */
@Input('fxShrink') set shrink(val) { this._cacheInput("shrink", val); };
@Input('fxGrow') set grow(val) { this._cacheInput("grow", val); };

@Input('fxFlex.md') set flexMd(val) {
this._cacheInput('flexMd', val);
};

@Input('fxFlex.gt-md') set flexGtMd(val) {
this._cacheInput('flexGtMd', val);
};

@Input('fxFlex.lg') set flexLg(val) {
this._cacheInput('flexLg', val);
};

@Input('fxFlex.gt-lg') set flexGtLg(val) {
this._cacheInput('flexGtLg', val);
};

@Input('fxFlex.xl') set flexXl(val) {
this._cacheInput('flexXl', val);
};
@Input('fxFlex') set flex(val) { this._cacheInput("flex", val); };
@Input('fxFlex.xs') set flexXs(val) { this._cacheInput('flexXs', val); };
@Input('fxFlex.sm') set flexSm(val) { this._cacheInput('flexSm', val); };
@Input('fxFlex.md') set flexMd(val) { this._cacheInput('flexMd', val); };
@Input('fxFlex.lg') set flexLg(val) { this._cacheInput('flexLg', val); };
@Input('fxFlex.xl') set flexXl(val) { this._cacheInput('flexXl', val); };

@Input('fxFlex.gt-xs') set flexGtXs(val) { this._cacheInput('flexGtXs', val); };
@Input('fxFlex.gt-sm') set flexGtSm(val) { this._cacheInput('flexGtSm', val); };
@Input('fxFlex.gt-md') set flexGtMd(val) { this._cacheInput('flexGtMd', val); };
@Input('fxFlex.gt-lg') set flexGtLg(val) { this._cacheInput('flexGtLg', val); };

/* tslint:enable */
// Explicitly @SkipSelf on LayoutDirective and LayoutWrapDirective because we want the
// parent flex container for this flex item.
constructor(monitor: MediaMonitor,
Expand Down Expand Up @@ -215,13 +176,14 @@ export class FlexDirective extends BaseFxDirective implements OnInit, OnChanges,
// ≥2 (integer n): Stretch. Will be n times the size of other elements
// with 'flex-grow: 1' on the same row.

// Use `null` to clear existing styles.
let clearStyles = {
let hasCalc = String(basis).indexOf('calc') > -1;
let clearStyles = { // Use `null` to clear existing styles.
'max-width': null,
'max-height': null,
'min-width': null,
'min-height': null
};

switch (basis || '') {
case '':
css = extendObject(clearStyles, {'flex': '1 1 0.000000001px'});
Expand All @@ -247,7 +209,6 @@ export class FlexDirective extends BaseFxDirective implements OnInit, OnChanges,
css = extendObject(clearStyles, {'flex': '0 0 auto'});
break;
default:
let hasCalc = String(basis).indexOf('calc') > -1;
let isPercent = String(basis).indexOf('%') > -1 && !hasCalc;

isValue = hasCalc ||
Expand All @@ -267,27 +228,26 @@ export class FlexDirective extends BaseFxDirective implements OnInit, OnChanges,

// Set max-width = basis if using layout-wrap
// tslint:disable-next-line:max-line-length
// @see https://github.com/philipwalton/flexbugs#11-min-and-max-size-declarations-are-ignored-when-wrappifl-flex-items
// @see http://bit.ly/2m5pZVI

css = extendObject(clearStyles, { // fix issue #5345
'flex': `${grow} ${shrink} ${(isValue || this._wrap) ? basis : '100%'}`,
});
break;
}

let max = (direction === 'row') ? 'max-width' : 'max-height';
let min = (direction === 'row') ? 'min-width' : 'min-height';

let usingCalc = (String(basis).indexOf('calc') > -1) || (basis == 'auto');
let isPx = String(basis).indexOf('px') > -1 || usingCalc;


// make box inflexible when shrink and grow are both zero
// should not set a min when the grow is zero
// should not set a max when the shrink is zero
let isFixed = !grow && !shrink;
css[min] = (basis == '0%') ? 0 : isFixed || (isPx && grow) ? basis : null;
css[max] = (basis == '0%') ? 0 : isFixed || (!usingCalc && shrink) ? basis : null;
if (basis !== 'auto') {
let max = (direction === 'row') ? 'max-width' : 'max-height';
let min = (direction === 'row') ? 'min-width' : 'min-height';
let isPx = String(basis).indexOf('px') > -1 || hasCalc;

// make box inflexible when shrink and grow are both zero
// * do not set a min when the grow is zero
// * do not set a max when the shrink is zero
let isFixed = !grow && !shrink;
css[min] = (basis == '0%') ? 0 : isFixed || (isPx && grow) ? basis : null;
css[max] = (basis == '0%') ? 0 : isFixed || (!hasCalc && shrink) ? basis : null;
}

return extendObject(css, {'box-sizing': 'border-box'});
}
Expand Down
5 changes: 5 additions & 0 deletions src/lib/utils/basis-validator.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ describe('validateBasis', () => {
expect( result ).toEqual('3 3 calc(15em + 20px)');
});

it('should validate calc() expression with multiple operators', () => {
let result = validateBasis('calc(100% / 7 * 2)').join(" ");
expect( result ).toEqual('1 1 calc(100% / 7 * 2)');
});

it('should validate with complex value that includes a bad calc() expression', () => {
let result = validateBasis('3 3 calc(15em +20px)').join(" ");
expect( result ).toEqual('3 3 calc(15em + 20px)');
Expand Down
30 changes: 10 additions & 20 deletions src/lib/utils/basis-validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,6 @@
* The flex API permits 3 or 1 parts of the value:
* - `flex-grow flex-shrink flex-basis`, or
* - `flex-basis`
* Flex-Basis values can be complicated short-hand versions such as:
* - "3 3 calc(15em + 20px)"
* - "calc(15em + 20px)"
* - "calc(15em+20px)"
* - "37px"
* = "43%"
*/
export function validateBasis(basis: string, grow = "1", shrink = "1"): string[] {
let parts = [grow, shrink, basis];
Expand All @@ -25,28 +19,24 @@ export function validateBasis(basis: string, grow = "1", shrink = "1"): string[]
} else {
let matches = basis.split(" ");
parts = (matches.length === 3) ? matches : [
grow, shrink, basis
];
grow, shrink, basis
];
}

return parts;
}


/**
* Calc expressions require whitespace before & after the operator
* Calc expressions require whitespace before & after any expression operators
* This is a simple, crude whitespace padding solution.
* - "3 3 calc(15em + 20px)"
* - calc(100% / 7 * 2)
* - "calc(15em + 20px)"
* - "calc(15em+20px)"
* - "37px"
* = "43%"
*/
function _validateCalcValue(calc: string): string {
let operators = ["+", "-", "*", "/"];
let findOperator = () => operators.reduce((index, operator) => {
return index || (calc.indexOf(operator) + 1);
}, 0);

if (findOperator() > 0) {
calc = calc.replace(/[\s]/g, "");
let offset = findOperator() - 1;
calc = calc.substr(0, offset) + " " + calc.charAt(offset) + " " + calc.substr(offset + 1);
}
return calc;
return calc.replace(/[\s]/g, "").replace(/[\/\*\+\-]/g, " $& ");
}

0 comments on commit c28dfc7

Please sign in to comment.