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

Commit 4fc9739

Browse files
committed
feat(core): add centralized media marshal service
1 parent 1205588 commit 4fc9739

File tree

23 files changed

+907
-762
lines changed

23 files changed

+907
-762
lines changed

src/lib/core/add-alias.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {extendObject} from '../utils/object-extend';
1313
* For the specified MediaChange, make sure it contains the breakpoint alias
1414
* and suffix (if available).
1515
*/
16-
export function mergeAlias(dest: MediaChange, source: BreakPoint | null) {
16+
export function mergeAlias(dest: MediaChange, source: BreakPoint | null): MediaChange {
1717
return extendObject(dest, source ? {
1818
mqAlias: source.alias,
1919
suffix: source.suffix

src/lib/core/base/base-adapter.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import {StyleUtils} from '../style-utils/style-utils';
1717
/**
1818
* Adapter to the BaseDirective abstract class so it can be used via composition.
1919
* @see BaseDirective
20+
* @deprecated
21+
* @deletion-target v7.0.0-beta.21
2022
*/
2123
export class BaseDirectiveAdapter extends BaseDirective {
2224

src/lib/core/base/base.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@ import {MediaMonitor} from '../media-monitor/media-monitor';
2323
import {MediaQuerySubscriber} from '../media-change';
2424
import {StyleBuilder} from '../style-builder/style-builder';
2525

26-
/** Abstract base class for the Layout API styling directives. */
26+
/**
27+
* Abstract base class for the Layout API styling directives.
28+
* @deprecated
29+
* @deletion-target v7.0.0-beta.21
30+
*/
2731
export abstract class BaseDirective implements OnDestroy, OnChanges {
2832

2933
/**

src/lib/core/base/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@
88

99
export * from './base';
1010
export * from './base-adapter';
11+
export * from './new-base';

src/lib/core/base/new-base.ts

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
import {ElementRef} from '@angular/core';
9+
10+
import {StyleDefinition, StyleUtils} from '../style-utils/style-utils';
11+
import {StyleBuilder} from '../style-builder/style-builder';
12+
import {MediaMarshaller} from '../media-marshaller/media-marshaller';
13+
import {buildLayoutCSS} from '../../utils/layout-validator';
14+
15+
export abstract class NewBaseDirective {
16+
17+
protected DIRECTIVE_KEY = '';
18+
19+
/** Access to host element's parent DOM node */
20+
protected get parentElement(): any {
21+
return this.elementRef.nativeElement.parentNode;
22+
}
23+
24+
protected get nativeElement(): HTMLElement {
25+
return this.elementRef.nativeElement;
26+
}
27+
28+
/** Cache map for style computation */
29+
protected styleCache: Map<string, StyleDefinition> = new Map();
30+
31+
protected constructor(protected elementRef: ElementRef,
32+
protected styleBuilder: StyleBuilder,
33+
protected styler: StyleUtils,
34+
protected marshal: MediaMarshaller) {
35+
}
36+
37+
/** Add styles to the element using predefined style builder */
38+
protected addStyles(input: string, parent?: Object) {
39+
const builder = this.styleBuilder;
40+
const useCache = builder.shouldCache;
41+
42+
let genStyles: StyleDefinition | undefined = this.styleCache.get(input);
43+
44+
if (!genStyles || !useCache) {
45+
genStyles = builder.buildStyles(input, parent);
46+
if (useCache) {
47+
this.styleCache.set(input, genStyles);
48+
}
49+
}
50+
51+
this.applyStyleToElement(genStyles);
52+
builder.sideEffect(input, genStyles, parent);
53+
}
54+
55+
/**
56+
* Determine the DOM element's Flexbox flow (flex-direction).
57+
*
58+
* Check inline style first then check computed (stylesheet) style.
59+
* And optionally add the flow value to element's inline style.
60+
*/
61+
protected getFlexFlowDirection(target: HTMLElement, addIfMissing = false): string {
62+
if (target) {
63+
let [value, hasInlineValue] = this.styler.getFlowDirection(target);
64+
65+
if (!hasInlineValue && addIfMissing) {
66+
const style = buildLayoutCSS(value);
67+
const elements = [target];
68+
this.styler.applyStyleToElements(style, elements);
69+
}
70+
71+
return value.trim();
72+
}
73+
74+
return 'row';
75+
}
76+
77+
/** Applies styles given via string pair or object map to the directive element */
78+
protected applyStyleToElement(style: StyleDefinition,
79+
value?: string | number,
80+
element: HTMLElement = this.nativeElement) {
81+
this.styler.applyStyleToElement(element, style, value);
82+
}
83+
84+
protected setValue(val: any, bp: string): void {
85+
this.marshal.setValue(this.nativeElement, bp, this.DIRECTIVE_KEY, val);
86+
}
87+
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,6 @@ export interface BreakPoint {
1010
alias: string;
1111
suffix?: string;
1212
overlapping?: boolean;
13+
priority?: number;
14+
includes?: string[];
1315
}

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

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,63 +14,76 @@ export const RESPONSIVE_ALIASES = [
1414
export const DEFAULT_BREAKPOINTS: BreakPoint[] = [
1515
{
1616
alias: 'xs',
17-
mediaQuery: '(min-width: 0px) and (max-width: 599px)'
17+
mediaQuery: '(min-width: 0px) and (max-width: 599px)',
18+
priority: 100,
1819
},
1920
{
2021
alias: 'gt-xs',
2122
overlapping: true,
22-
mediaQuery: '(min-width: 600px)'
23+
mediaQuery: '(min-width: 600px)',
24+
priority: 7,
2325
},
2426
{
2527
alias: 'lt-sm',
2628
overlapping: true,
27-
mediaQuery: '(max-width: 599px)'
29+
mediaQuery: '(max-width: 599px)',
30+
priority: 10,
2831
},
2932
{
3033
alias: 'sm',
31-
mediaQuery: '(min-width: 600px) and (max-width: 959px)'
34+
mediaQuery: '(min-width: 600px) and (max-width: 959px)',
35+
priority: 100,
3236
},
3337
{
3438
alias: 'gt-sm',
3539
overlapping: true,
36-
mediaQuery: '(min-width: 960px)'
40+
mediaQuery: '(min-width: 960px)',
41+
priority: 8,
3742
},
3843
{
3944
alias: 'lt-md',
4045
overlapping: true,
41-
mediaQuery: '(max-width: 959px)'
46+
mediaQuery: '(max-width: 959px)',
47+
priority: 9,
4248
},
4349
{
4450
alias: 'md',
45-
mediaQuery: '(min-width: 960px) and (max-width: 1279px)'
51+
mediaQuery: '(min-width: 960px) and (max-width: 1279px)',
52+
priority: 100,
4653
},
4754
{
4855
alias: 'gt-md',
4956
overlapping: true,
50-
mediaQuery: '(min-width: 1280px)'
57+
mediaQuery: '(min-width: 1280px)',
58+
priority: 9,
5159
},
5260
{
5361
alias: 'lt-lg',
5462
overlapping: true,
55-
mediaQuery: '(max-width: 1279px)'
63+
mediaQuery: '(max-width: 1279px)',
64+
priority: 8,
5665
},
5766
{
5867
alias: 'lg',
59-
mediaQuery: '(min-width: 1280px) and (max-width: 1919px)'
68+
mediaQuery: '(min-width: 1280px) and (max-width: 1919px)',
69+
priority: 100,
6070
},
6171
{
6272
alias: 'gt-lg',
6373
overlapping: true,
64-
mediaQuery: '(min-width: 1920px)'
74+
mediaQuery: '(min-width: 1920px)',
75+
priority: 10,
6576
},
6677
{
6778
alias: 'lt-xl',
6879
overlapping: true,
69-
mediaQuery: '(max-width: 1919px)'
80+
mediaQuery: '(max-width: 1919px)',
81+
priority: 7,
7082
},
7183
{
7284
alias: 'xl',
73-
mediaQuery: '(min-width: 1920px) and (max-width: 5000px)'
85+
mediaQuery: '(min-width: 1920px) and (max-width: 5000px)',
86+
priority: 100,
7487
}
7588
];
7689

src/lib/core/match-media/mock/mock-match-media.ts

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -79,57 +79,60 @@ export class MockMatchMedia extends MatchMedia {
7979
// Simulate activation of overlapping lt-<XXX> ranges
8080
switch (alias) {
8181
case 'lg' :
82-
this._activateByAlias('lt-xl');
82+
this._activateByAlias('lt-xl', true);
8383
break;
8484
case 'md' :
85-
this._activateByAlias('lt-xl, lt-lg');
85+
this._activateByAlias('lt-xl, lt-lg', true);
8686
break;
8787
case 'sm' :
88-
this._activateByAlias('lt-xl, lt-lg, lt-md');
88+
this._activateByAlias('lt-xl, lt-lg, lt-md', true);
8989
break;
9090
case 'xs' :
91-
this._activateByAlias('lt-xl, lt-lg, lt-md, lt-sm');
91+
this._activateByAlias('lt-xl, lt-lg, lt-md, lt-sm', true);
9292
break;
9393
}
9494

9595
// Simulate activate of overlapping gt-<xxxx> mediaQuery ranges
9696
switch (alias) {
9797
case 'xl' :
98-
this._activateByAlias('gt-lg, gt-md, gt-sm, gt-xs');
98+
this._activateByAlias('gt-lg, gt-md, gt-sm, gt-xs', true);
9999
break;
100100
case 'lg' :
101-
this._activateByAlias('gt-md, gt-sm, gt-xs');
101+
this._activateByAlias('gt-md, gt-sm, gt-xs', true);
102102
break;
103103
case 'md' :
104-
this._activateByAlias('gt-sm, gt-xs');
104+
this._activateByAlias('gt-sm, gt-xs', true);
105105
break;
106106
case 'sm' :
107-
this._activateByAlias('gt-xs');
107+
this._activateByAlias('gt-xs', true);
108108
break;
109109
}
110110
}
111111
// Activate last since the responsiveActivation is watching *this* mediaQuery
112-
return this._activateByQuery(mediaQuery);
112+
return this._activateByQuery(mediaQuery, true);
113113
}
114114

115115
/**
116116
*
117117
*/
118-
private _activateByAlias(aliases: string) {
118+
private _activateByAlias(aliases: string, useOverlaps = false) {
119119
const activate = (alias: string) => {
120120
const bp = this._breakpoints.findByAlias(alias);
121-
this._activateByQuery(bp ? bp.mediaQuery : alias);
121+
this._activateByQuery(bp ? bp.mediaQuery : alias, useOverlaps);
122122
};
123123
aliases.split(',').forEach(alias => activate(alias.trim()));
124124
}
125125

126126
/**
127127
*
128128
*/
129-
private _activateByQuery(mediaQuery: string) {
130-
const mql = this._registry.get(mediaQuery)!;
129+
private _activateByQuery(mediaQuery: string, useOverlaps = false) {
130+
if (useOverlaps) {
131+
this._registerMediaQuery(mediaQuery);
132+
}
133+
const mql = this._registry.get(mediaQuery);
131134
const alreadyAdded = this._actives
132-
.reduce((found, it) => (found || (mql && (it.media === mql.media))), false);
135+
.reduce((found, it) => (found || (mql ? (it.media === mql.media) : false)), false);
133136

134137
if (mql && !alreadyAdded) {
135138
this._actives.push(mql.activate());

0 commit comments

Comments
 (0)