Skip to content
This repository was archived by the owner on Jan 6, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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, " $& ");
}