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

Commit 605f4d1

Browse files
CaerusKaruThomasBurleson
authored andcommitted
feat(tokens): add configuration for breakpoints and flex styles
* add token to add individual breakpoints that can be merged with the defaults seamlessly * add token that optionally adds flex stylings to parents without inline flex styles (set to false by default) * add token to optionally disable adding vendor prefixes to inline styles BREAKING CHANGE: * `fxFlex` no longer adds `display: flex; flex-direction: row` by default
1 parent bc1954c commit 605f4d1

30 files changed

+517
-359
lines changed

docs/documentation/BreakPoints.md

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,21 @@ export class CoreModule {
2323
}
2424
```
2525

26-
This provider is used to return a list to *all* known BreakPoint(s)... and, in turn, this list is used internally to
26+
This provider is used to return a list to *all* known BreakPoint(s) and, in turn, this list is used internally to
2727
register mediaQueries and announce mediaQuery activations.
2828

2929

3030
### Custom BreakPoints
3131

32-
Using the **BREAKPOINTS** InjectionToken, developers can add custom breakpoints or easily override existing breakpoints.
32+
Using the **BREAKPOINT** (note: singular) `InjectionToken`, developers can add custom breakpoints or easily override
33+
existing breakpoints.
3334

3435
For example to add mediaQueries that activate when printing:
3536

3637
##### `custom-breakpoints.ts`
3738

3839
```typescript
39-
import {BREAKPOINTS, DEFAULT_BREAKPOINTS} from '@angular/flex-layout';
40+
import {BREAKPOINT} from '@angular/flex-layout';
4041

4142
const PRINT_BREAKPOINTS = [{
4243
alias: 'xs.print',
@@ -46,8 +47,9 @@ const PRINT_BREAKPOINTS = [{
4647
}];
4748

4849
export const CustomBreakPointsProvider = {
49-
provide: BREAKPOINTS,
50-
useValue: [...DEFAULT_BREAKPOINTS, ...PRINT_BREAKPOINTS]
50+
provide: BREAKPOINT,
51+
useValue: PRINT_BREAKPOINTS,
52+
multi: true
5153
};
5254
```
5355

@@ -56,7 +58,7 @@ export const CustomBreakPointsProvider = {
5658
```typescript
5759
import {CommonModule, NgModule} from '@angular/core';
5860
import {FlexLayoutModule} from '@angular/flex-layout';
59-
import {CustomBreakPointsProvider} from 'custom-breakpoints.ts';
61+
import {CustomBreakPointsProvider} from './custom-breakpoints.ts';
6062

6163
@NgModule({
6264
imports : [
@@ -71,7 +73,43 @@ export class MyAppModule {
7173
}
7274
```
7375

74-
With the above changes, when printing on mobile-sized viewports the **`xs.print`** mediaQuery will activate.
76+
With the above changes, when printing on mobile-sized viewports the **`xs.print`** mediaQuery will activate. Please note
77+
that the provider is a **multi-provider**, meaning it can be provided multiple times and in a variety of
78+
presentations. The type signature of `BREAKPOINT` is the following:
79+
80+
`BREAKPOINT = InjectionToken<BreakPoint|BreakPoint[]>`
81+
82+
Thus, you can use the token to segment which breakpoints you provide and in which order. For instance,
83+
you can provide all print breakpoints in an array called `PRINT_BREAKPOINTS` and then all mobile breakpoints
84+
in another array called `MOBILE_BREAKPOINTS`. You can also simply provide one additional breakpoint if that's
85+
all you need.
86+
87+
### Disabling the default breakpoints
88+
89+
To disable the default breakpoints, you simply provide the new **DISABLE_DEFAULT_BREAKPOINTS** token as follows:
90+
91+
```typescript
92+
import {DISABLE_DEFAULT_BREAKPOINTS} from '@angular/flex-layout';
93+
94+
{provide: DISABLE_DEFAULT_BREAKPOINTS, useValue: true}
95+
```
96+
97+
The default value for this breakpoint is false
98+
99+
### Adding the orientation breakpoints
100+
101+
The orientation breakpoints are a set of breakpoints that detect when a device is in portrait or landscape mode. Flex
102+
Layout has a set of these that conform to the Material Design spec built-in to the library. They can be found in the
103+
`ORIENTATION_BREAKPOINTS` `InjectionToken`. To have these added to the default breakpoints, you can provide the token
104+
`ADD_ORIENTATION_BREAKPOINTS` to your app as follows:
105+
106+
```typescript
107+
import {ADD_ORIENTATION_BREAKPOINTS} from '@angular/flex-layout';
108+
109+
{provide: ADD_ORIENTATION_BREAKPOINTS, useValue: true}
110+
```
111+
112+
The default value for this breakpoint is false
75113

76114
### Custom Breakpoints and Directives
77115

src/lib/core/breakpoints/break-point-registry.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {BREAKPOINTS} from './break-points-token';
1313

1414
/**
1515
* Registry of 1..n MediaQuery breakpoint ranges
16-
* This is published as a provider and may be overriden from custom, application-specific ranges
16+
* This is published as a provider and may be overridden from custom, application-specific ranges
1717
*
1818
*/
1919
@Injectable()
@@ -25,7 +25,7 @@ export class BreakPointRegistry {
2525
/**
2626
* Accessor to raw list
2727
*/
28-
get items(): BreakPoint[ ] {
28+
get items(): BreakPoint[] {
2929
return [...this._registry];
3030
}
3131

src/lib/core/breakpoints/break-points-provider.ts

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,26 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.io/license
77
*/
8-
import {InjectionToken} from '@angular/core';
8+
import {InjectionToken, Optional, SkipSelf} from '@angular/core';
99

1010
import {BreakPoint} from './break-point';
1111
import {BREAKPOINTS} from './break-points-token';
1212
import {DEFAULT_BREAKPOINTS} from './data/break-points';
1313
import {ORIENTATION_BREAKPOINTS} from './data/orientation-break-points';
14-
1514
import {extendObject} from '../../utils/object-extend';
1615
import {mergeByAlias, validateSuffixes} from './breakpoint-tools';
16+
import {
17+
ADD_ORIENTATION_BREAKPOINTS,
18+
BREAKPOINT,
19+
DISABLE_DEFAULT_BREAKPOINTS,
20+
} from '../tokens/breakpoint-token';
1721

1822

1923
/**
2024
* Options to identify which breakpoint types to include as part of
2125
* a BreakPoint provider
26+
* @deprecated
27+
* @deletion-target v6.0.0-beta.15
2228
*/
2329
export interface BreakPointProviderOptions {
2430
/**
@@ -35,11 +41,13 @@ export interface BreakPointProviderOptions {
3541

3642
/**
3743
* Add new custom items to the default list or override existing default with custom overrides
44+
* @deprecated
45+
* @deletion-target v6.0.0-beta.15
3846
*/
3947
export function buildMergedBreakPoints(_custom?: BreakPoint[],
4048
options?: BreakPointProviderOptions) {
4149
options = extendObject({}, {
42-
defaults: true, // exclude pre-configured, internal default breakpoints
50+
defaults: true, // exclude pre-configured, internal default breakpoints
4351
orientation: false // exclude pre-configured, internal orientations breakpoints
4452
}, options || {});
4553

@@ -55,6 +63,8 @@ export function buildMergedBreakPoints(_custom?: BreakPoint[],
5563

5664
/**
5765
* Ensure that only a single global BreakPoint list is instantiated...
66+
* @deprecated
67+
* @deletion-target v6.0.0-beta.15
5868
*/
5969
export function DEFAULT_BREAKPOINTS_PROVIDER_FACTORY() {
6070
return validateSuffixes(DEFAULT_BREAKPOINTS);
@@ -67,18 +77,53 @@ export function DEFAULT_BREAKPOINTS_PROVIDER_FACTORY() {
6777
* custom breakpoints matching existing breakpoints will override the properties
6878
* of the existing (and not be added as an extra breakpoint entry).
6979
* [xs, gt-xs, sm, gt-sm, md, gt-md, lg, gt-lg, xl]
80+
* @deprecated
81+
* @deletion-target v6.0.0-beta.15
7082
*/
71-
export const DEFAULT_BREAKPOINTS_PROVIDER = { // tslint:disable-line:variable-name
83+
export const DEFAULT_BREAKPOINTS_PROVIDER = {
7284
provide: BREAKPOINTS,
7385
useFactory: DEFAULT_BREAKPOINTS_PROVIDER_FACTORY
7486
};
87+
88+
/**
89+
* Factory that combines the configured breakpoints into one array and then merges
90+
* them using a utility function
91+
*/
92+
export function BREAKPOINTS_PROVIDER_FACTORY(parentBreakpoints: BreakPoint[],
93+
breakpoints: (BreakPoint|BreakPoint[])[],
94+
disableDefaults: boolean,
95+
addOrientation: boolean) {
96+
const bpFlattenArray = [].concat.apply([], (breakpoints || [])
97+
.map(v => Array.isArray(v) ? v : [v]));
98+
const builtIns = DEFAULT_BREAKPOINTS.concat(addOrientation ? ORIENTATION_BREAKPOINTS : []);
99+
return parentBreakpoints || disableDefaults ?
100+
mergeByAlias(bpFlattenArray) : mergeByAlias(builtIns, bpFlattenArray);
101+
}
102+
103+
/**
104+
* Provider that combines the provided extra breakpoints with the default and
105+
* orientation breakpoints based on configuration
106+
*/
107+
export const BREAKPOINTS_PROVIDER = {
108+
provide: BREAKPOINTS,
109+
useFactory: BREAKPOINTS_PROVIDER_FACTORY,
110+
deps: [
111+
[new Optional(), new SkipSelf(), BREAKPOINTS],
112+
[new Optional(), BREAKPOINT],
113+
[new Optional(), DISABLE_DEFAULT_BREAKPOINTS],
114+
[new Optional(), ADD_ORIENTATION_BREAKPOINTS],
115+
]
116+
};
117+
75118
/**
76119
* Use with FlexLayoutModule.CUSTOM_BREAKPOINTS_PROVIDER_FACTORY!
120+
* @deprecated
121+
* @deletion-target v6.0.0-beta.15
77122
*/
78-
export function CUSTOM_BREAKPOINTS_PROVIDER_FACTORY(_custom?: BreakPoint[],
123+
export function CUSTOM_BREAKPOINTS_PROVIDER_FACTORY(custom?: BreakPoint[],
79124
options?: BreakPointProviderOptions) {
80125
return {
81126
provide: <InjectionToken<BreakPoint[]>>BREAKPOINTS,
82-
useFactory: buildMergedBreakPoints(_custom, options)
127+
useFactory: buildMergedBreakPoints(custom, options)
83128
};
84129
}

src/lib/core/breakpoints/breakpoint-tools.spec.ts

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,11 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.io/license
77
*/
8-
import {TestBed, inject} from '@angular/core/testing';
8+
import {TestBed, inject, fakeAsync} from '@angular/core/testing';
99

1010
import {BreakPoint} from './break-point';
1111
import {BREAKPOINTS} from './break-points-token';
12-
import {
13-
DEFAULT_BREAKPOINTS_PROVIDER,
14-
buildMergedBreakPoints
15-
} from './break-points-provider';
12+
import {BREAKPOINTS_PROVIDER, BREAKPOINTS_PROVIDER_FACTORY} from './break-points-provider';
1613
import {validateSuffixes, mergeByAlias} from './breakpoint-tools';
1714

1815
describe('breakpoint-tools', () => {
@@ -22,7 +19,7 @@ describe('breakpoint-tools', () => {
2219
}, null);
2320

2421
beforeEach(() => {
25-
all = buildMergedBreakPoints([], {orientations: true})();
22+
all = BREAKPOINTS_PROVIDER_FACTORY([], [], false, true);
2623
});
2724

2825
describe('validation', () => {
@@ -47,18 +44,20 @@ describe('breakpoint-tools', () => {
4744
expect(validated[4].suffix).toEqual('HandsetPortrait');
4845
});
4946
it('should auto-validate the DEFAULT_BREAKPOINTS', () => {
50-
let xsBp: BreakPoint = findByAlias('xs')!;
51-
let gtLgBp: BreakPoint = findByAlias('gt-lg')!;
52-
let xlBp: BreakPoint = findByAlias('xl')!;
47+
fakeAsync(() => {
48+
let xsBp: BreakPoint = findByAlias('xs')!;
49+
let gtLgBp: BreakPoint = findByAlias('gt-lg')!;
50+
let xlBp: BreakPoint = findByAlias('xl')!;
5351

54-
expect(xsBp.alias).toEqual('xs');
55-
expect(xsBp.suffix).toEqual('Xs');
52+
expect(xsBp.alias).toEqual('xs');
53+
expect(xsBp.suffix).toEqual('Xs');
5654

57-
expect(gtLgBp.alias).toEqual('gt-lg');
58-
expect(gtLgBp.suffix).toEqual('GtLg');
55+
expect(gtLgBp.alias).toEqual('gt-lg');
56+
expect(gtLgBp.suffix).toEqual('GtLg');
5957

60-
expect(xlBp.alias).toEqual('xl');
61-
expect(xlBp.suffix).toEqual('Xl');
58+
expect(xlBp.alias).toEqual('xl');
59+
expect(xlBp.suffix).toEqual('Xl');
60+
});
6261
});
6362
});
6463

@@ -76,7 +75,7 @@ describe('breakpoint-tools', () => {
7675
});
7776
it('should add custom breakpoints with unique aliases', () => {
7877
let defaults = [{alias: 'xs', mediaQuery: 'screen and (max-width: 599px)'}],
79-
custom = [{alias: 'sm', mediaQuery: 'screen'}, {alias: 'md', mediaQuery: 'screen'}];
78+
custom = [{alias: 'sm', mediaQuery: 'screen'}, {alias: 'md', mediaQuery: 'screen'}];
8079

8180
all = mergeByAlias(defaults, custom);
8281

@@ -97,12 +96,12 @@ describe('breakpoint-tools', () => {
9796
});
9897
});
9998

100-
describe('with DEFAULT_BREAKPOINTS_PROVIDER', () => {
99+
describe('with BREAKPOINTS_PROVIDER', () => {
101100
beforeEach(() => {
102101
// Configure testbed to prepare services
103102
TestBed.configureTestingModule({
104103
providers: [
105-
DEFAULT_BREAKPOINTS_PROVIDER // Supports developer overrides of list of known breakpoints
104+
BREAKPOINTS_PROVIDER // Supports developer overrides of list of known breakpoints
106105
]
107106
});
108107
});

src/lib/core/breakpoints/breakpoint-tools.ts

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ function camelCase(name: string): string {
3434
*/
3535
export function validateSuffixes(list: BreakPoint[]): BreakPoint[] {
3636
list.forEach((bp: BreakPoint) => {
37-
if (!bp.suffix || bp.suffix === '') {
38-
bp.suffix = camelCase(bp.alias); // create Suffix value based on alias
39-
bp.overlapping = bp.overlapping || false; // ensure default value
37+
if (!bp.suffix) {
38+
bp.suffix = camelCase(bp.alias); // create Suffix value based on alias
39+
bp.overlapping = !!bp.overlapping; // ensure default value
4040
}
4141
});
4242
return list;
@@ -48,21 +48,19 @@ export function validateSuffixes(list: BreakPoint[]): BreakPoint[] {
4848
* - Items are merged with the custom override if the alias exists in the default list
4949
*/
5050
export function mergeByAlias(defaults: BreakPoint[], custom: BreakPoint[] = []): BreakPoint[] {
51-
const merged = defaults.map((bp) => extendObject({}, bp));
52-
const findByAlias = (alias) => merged.reduce((result, bp) => {
53-
return result || (( bp.alias === alias) ? bp : null);
54-
}, null);
55-
51+
const dict: {[key: string]: BreakPoint} = {};
52+
defaults.forEach(bp => {
53+
dict[bp.alias] = bp;
54+
});
5655
// Merge custom breakpoints
5756
custom.forEach((bp: BreakPoint) => {
58-
let target = findByAlias(bp.alias);
59-
if (target) {
60-
extendObject(target, bp);
57+
if (dict[bp.alias]) {
58+
extendObject(dict[bp.alias], bp);
6159
} else {
62-
merged.push(bp);
60+
dict[bp.alias] = bp;
6361
}
6462
});
6563

66-
return validateSuffixes(merged);
64+
return validateSuffixes(Object.keys(dict).map(k => dict[k]));
6765
}
6866

0 commit comments

Comments
 (0)