UNPKG

5.29 kBJavaScriptView Raw
1/*
2Copyright (c) 2014, Yahoo! Inc. All rights reserved.
3Copyrights licensed under the New BSD License.
4See the accompanying LICENSE file for terms.
5*/
6// https://github.com/ericf/css-mediaquery
7import { Trace } from '../trace';
8import { Length } from '../ui/styling/style-properties';
9// -----------------------------------------------------------------------------
10const RE_MEDIA_QUERY = /^(?:(only|not)?\s*([_a-z][_a-z0-9-]*)|(\([^\)]+\)))(?:\s*and\s*(.*))?$/i, RE_MQ_EXPRESSION = /^\(\s*([_a-z-][_a-z0-9-]*)\s*(?:\:\s*([^\)]+))?\s*\)$/, RE_MQ_FEATURE = /^(?:(min|max)-)?(.+)/, RE_LENGTH_UNIT = /(em|rem|px|cm|mm|in|pt|pc)?\s*$/, RE_RESOLUTION_UNIT = /(dpi|dpcm|dppx)?\s*$/;
11export var MediaQueryType;
12(function (MediaQueryType) {
13 MediaQueryType["all"] = "all";
14 MediaQueryType["print"] = "print";
15 MediaQueryType["screen"] = "screen";
16})(MediaQueryType || (MediaQueryType = {}));
17export function matchQuery(mediaQuery, values) {
18 const expressions = parseQuery(mediaQuery);
19 return expressions.some((query) => {
20 const { type, inverse, features } = query;
21 // Either the parsed or specified `type` is "all", or the types must be
22 // equal for a match.
23 const typeMatch = query.type === 'all' || values.type === query.type;
24 // Quit early when `type` doesn't match, but take "not" into account
25 if ((typeMatch && inverse) || !(typeMatch || inverse)) {
26 return false;
27 }
28 const expressionsMatch = features.every((feature) => {
29 const value = values[feature.property];
30 // Missing or falsy values don't match
31 if (!value && value !== 0) {
32 return false;
33 }
34 switch (feature.property) {
35 case 'orientation':
36 case 'prefers-color-scheme':
37 if (typeof value !== 'string') {
38 return false;
39 }
40 return value.toLowerCase() === feature.value.toLowerCase();
41 default: {
42 // Numeric properties
43 let numVal;
44 if (typeof value !== 'number') {
45 Trace.write(`Unknown CSS media query feature property: '${feature.property}' on '${query}'`, Trace.categories.MediaQuery, Trace.messageType.warn);
46 return false;
47 }
48 switch (feature.property) {
49 case 'width':
50 case 'height':
51 case 'device-width':
52 case 'device-height': {
53 numVal = Length.toDevicePixels(Length.parse(feature.value), 0);
54 break;
55 }
56 default:
57 Trace.write(`Unknown CSS media query feature property: '${feature.property}' on '${query}'`, Trace.categories.MediaQuery, Trace.messageType.warn);
58 break;
59 }
60 switch (feature.modifier) {
61 case 'min':
62 return value >= numVal;
63 case 'max':
64 return value <= numVal;
65 default:
66 return value === numVal;
67 }
68 break;
69 }
70 }
71 });
72 return (expressionsMatch && !inverse) || (!expressionsMatch && inverse);
73 });
74}
75export function parseQuery(mediaQuery) {
76 const mediaQueryStrings = mediaQuery.split(',');
77 return mediaQueryStrings.map((query) => {
78 query = query.trim();
79 const captures = query.match(RE_MEDIA_QUERY);
80 // Media query must be valid
81 if (!captures) {
82 throw new SyntaxError(`Invalid CSS media query: '${query}'`);
83 }
84 const modifier = captures[1];
85 const type = captures[2];
86 const featureString = ((captures[3] || '') + (captures[4] || '')).trim();
87 const expression = {
88 inverse: !!modifier && modifier.toLowerCase() === 'not',
89 type: MediaQueryType[type ? type.toLowerCase() : 'all'] ?? 'all',
90 features: [],
91 };
92 // Check for media query features
93 if (!featureString) {
94 return expression;
95 }
96 // Split features string into a list
97 const features = featureString.match(/\([^\)]+\)/g);
98 // Media query must be valid
99 if (!features) {
100 throw new SyntaxError(`Invalid CSS media query features: '${featureString}' on '${query}'`);
101 }
102 for (const feature of features) {
103 const captures = feature.match(RE_MQ_EXPRESSION);
104 // Media query must be valid
105 if (!captures) {
106 throw new SyntaxError(`Invalid CSS media query feature: '${feature}' on '${query}'`);
107 }
108 const featureData = captures[1].toLowerCase().match(RE_MQ_FEATURE);
109 expression.features.push({
110 modifier: featureData[1],
111 property: featureData[2],
112 value: captures[2],
113 });
114 }
115 return expression;
116 });
117}
118//# sourceMappingURL=index.js.map
\No newline at end of file