happy-dom 9.18.3 → 9.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of happy-dom might be problematic. Click here for more details.

Files changed (131) hide show
  1. package/README.md +15 -1
  2. package/lib/css/CSSParser.d.ts.map +1 -1
  3. package/lib/css/CSSParser.js +16 -6
  4. package/lib/css/CSSParser.js.map +1 -1
  5. package/lib/css/declaration/AbstractCSSStyleDeclaration.d.ts +2 -2
  6. package/lib/css/declaration/AbstractCSSStyleDeclaration.d.ts.map +1 -1
  7. package/lib/css/declaration/AbstractCSSStyleDeclaration.js +2 -2
  8. package/lib/css/declaration/AbstractCSSStyleDeclaration.js.map +1 -1
  9. package/lib/css/declaration/css-parser/CSSStyleDeclarationCSSParser.d.ts.map +1 -0
  10. package/lib/css/declaration/css-parser/CSSStyleDeclarationCSSParser.js.map +1 -0
  11. package/lib/css/declaration/{utilities → element-style}/CSSStyleDeclarationElementStyle.d.ts +14 -3
  12. package/lib/css/declaration/element-style/CSSStyleDeclarationElementStyle.d.ts.map +1 -0
  13. package/lib/css/declaration/{utilities → element-style}/CSSStyleDeclarationElementStyle.js +102 -84
  14. package/lib/css/declaration/element-style/CSSStyleDeclarationElementStyle.js.map +1 -0
  15. package/lib/css/declaration/element-style/config/CSSStyleDeclarationElementDefaultCSS.d.ts.map +1 -0
  16. package/lib/css/declaration/{utilities → element-style/config}/CSSStyleDeclarationElementDefaultCSS.js +1 -1
  17. package/lib/css/declaration/element-style/config/CSSStyleDeclarationElementDefaultCSS.js.map +1 -0
  18. package/lib/css/declaration/element-style/config/CSSStyleDeclarationElementInheritedProperties.d.ts.map +1 -0
  19. package/lib/css/declaration/element-style/config/CSSStyleDeclarationElementInheritedProperties.js.map +1 -0
  20. package/lib/css/declaration/element-style/config/CSSStyleDeclarationElementMeasurementProperties.d.ts +3 -0
  21. package/lib/css/declaration/element-style/config/CSSStyleDeclarationElementMeasurementProperties.d.ts.map +1 -0
  22. package/lib/css/declaration/element-style/config/CSSStyleDeclarationElementMeasurementProperties.js +44 -0
  23. package/lib/css/declaration/element-style/config/CSSStyleDeclarationElementMeasurementProperties.js.map +1 -0
  24. package/lib/css/declaration/measurement-converter/CSSMeasurementConverter.d.ts +32 -0
  25. package/lib/css/declaration/measurement-converter/CSSMeasurementConverter.d.ts.map +1 -0
  26. package/lib/css/declaration/measurement-converter/CSSMeasurementConverter.js +70 -0
  27. package/lib/css/declaration/measurement-converter/CSSMeasurementConverter.js.map +1 -0
  28. package/lib/css/declaration/{utilities → property-manager}/CSSStyleDeclarationPropertyGetParser.d.ts +9 -0
  29. package/lib/css/declaration/property-manager/CSSStyleDeclarationPropertyGetParser.d.ts.map +1 -0
  30. package/lib/css/declaration/{utilities → property-manager}/CSSStyleDeclarationPropertyGetParser.js +38 -0
  31. package/lib/css/declaration/property-manager/CSSStyleDeclarationPropertyGetParser.js.map +1 -0
  32. package/lib/css/declaration/{utilities → property-manager}/CSSStyleDeclarationPropertyManager.d.ts +1 -1
  33. package/lib/css/declaration/property-manager/CSSStyleDeclarationPropertyManager.d.ts.map +1 -0
  34. package/lib/css/declaration/{utilities → property-manager}/CSSStyleDeclarationPropertyManager.js +32 -1
  35. package/lib/css/declaration/property-manager/CSSStyleDeclarationPropertyManager.js.map +1 -0
  36. package/lib/css/declaration/{utilities → property-manager}/CSSStyleDeclarationPropertySetParser.d.ts +90 -0
  37. package/lib/css/declaration/property-manager/CSSStyleDeclarationPropertySetParser.d.ts.map +1 -0
  38. package/lib/css/declaration/{utilities → property-manager}/CSSStyleDeclarationPropertySetParser.js +171 -25
  39. package/lib/css/declaration/property-manager/CSSStyleDeclarationPropertySetParser.js.map +1 -0
  40. package/lib/css/declaration/property-manager/CSSStyleDeclarationValueParser.d.ts.map +1 -0
  41. package/lib/css/declaration/{utilities → property-manager}/CSSStyleDeclarationValueParser.js +1 -1
  42. package/lib/css/declaration/property-manager/CSSStyleDeclarationValueParser.js.map +1 -0
  43. package/lib/css/declaration/property-manager/ICSSStyleDeclarationPropertyValue.d.ts +5 -0
  44. package/lib/css/declaration/property-manager/ICSSStyleDeclarationPropertyValue.d.ts.map +1 -0
  45. package/lib/css/declaration/property-manager/ICSSStyleDeclarationPropertyValue.js.map +1 -0
  46. package/lib/match-media/IMediaQueryRange.d.ts +12 -0
  47. package/lib/match-media/IMediaQueryRange.d.ts.map +1 -0
  48. package/lib/match-media/IMediaQueryRange.js +3 -0
  49. package/lib/match-media/IMediaQueryRange.js.map +1 -0
  50. package/lib/match-media/IMediaQueryRule.d.ts +5 -0
  51. package/lib/match-media/IMediaQueryRule.d.ts.map +1 -0
  52. package/lib/match-media/IMediaQueryRule.js +3 -0
  53. package/lib/match-media/IMediaQueryRule.js.map +1 -0
  54. package/lib/match-media/MediaQueryItem.d.ts +77 -0
  55. package/lib/match-media/MediaQueryItem.d.ts.map +1 -0
  56. package/lib/match-media/MediaQueryItem.js +283 -0
  57. package/lib/match-media/MediaQueryItem.js.map +1 -0
  58. package/lib/match-media/MediaQueryList.d.ts +18 -4
  59. package/lib/match-media/MediaQueryList.d.ts.map +1 -1
  60. package/lib/match-media/MediaQueryList.js +37 -21
  61. package/lib/match-media/MediaQueryList.js.map +1 -1
  62. package/lib/match-media/MediaQueryParser.d.ts +22 -0
  63. package/lib/match-media/MediaQueryParser.d.ts.map +1 -0
  64. package/lib/match-media/MediaQueryParser.js +112 -0
  65. package/lib/match-media/MediaQueryParser.js.map +1 -0
  66. package/lib/match-media/MediaQueryTypeEnum.d.ts +7 -0
  67. package/lib/match-media/MediaQueryTypeEnum.d.ts.map +1 -0
  68. package/lib/match-media/MediaQueryTypeEnum.js +10 -0
  69. package/lib/match-media/MediaQueryTypeEnum.js.map +1 -0
  70. package/lib/nodes/element/Element.d.ts +2 -0
  71. package/lib/nodes/element/Element.d.ts.map +1 -1
  72. package/lib/nodes/element/Element.js +1 -0
  73. package/lib/nodes/element/Element.js.map +1 -1
  74. package/lib/window/IHappyDOMOptions.d.ts +4 -0
  75. package/lib/window/IHappyDOMOptions.d.ts.map +1 -1
  76. package/lib/window/IHappyDOMSettings.d.ts +4 -0
  77. package/lib/window/IHappyDOMSettings.d.ts.map +1 -1
  78. package/lib/window/Window.d.ts +4 -0
  79. package/lib/window/Window.d.ts.map +1 -1
  80. package/lib/window/Window.js +16 -4
  81. package/lib/window/Window.js.map +1 -1
  82. package/package.json +1 -1
  83. package/src/css/CSSParser.ts +21 -6
  84. package/src/css/declaration/AbstractCSSStyleDeclaration.ts +2 -2
  85. package/src/css/declaration/{utilities → element-style}/CSSStyleDeclarationElementStyle.ts +117 -94
  86. package/src/css/declaration/{utilities → element-style/config}/CSSStyleDeclarationElementDefaultCSS.ts +1 -1
  87. package/src/css/declaration/element-style/config/CSSStyleDeclarationElementMeasurementProperties.ts +41 -0
  88. package/src/css/declaration/measurement-converter/CSSMeasurementConverter.ts +81 -0
  89. package/src/css/declaration/{utilities → property-manager}/CSSStyleDeclarationPropertyGetParser.ts +51 -0
  90. package/src/css/declaration/{utilities → property-manager}/CSSStyleDeclarationPropertyManager.ts +34 -2
  91. package/src/css/declaration/{utilities → property-manager}/CSSStyleDeclarationPropertySetParser.ts +235 -20
  92. package/src/css/declaration/{utilities → property-manager}/CSSStyleDeclarationValueParser.ts +2 -1
  93. package/src/css/declaration/{utilities → property-manager}/ICSSStyleDeclarationPropertyValue.ts +2 -2
  94. package/src/match-media/IMediaQueryRange.ts +5 -0
  95. package/src/match-media/IMediaQueryRule.ts +4 -0
  96. package/src/match-media/MediaQueryItem.ts +336 -0
  97. package/src/match-media/MediaQueryList.ts +43 -20
  98. package/src/match-media/MediaQueryParser.ts +113 -0
  99. package/src/match-media/MediaQueryTypeEnum.ts +7 -0
  100. package/src/nodes/element/Element.ts +2 -0
  101. package/src/window/IHappyDOMOptions.ts +4 -0
  102. package/src/window/IHappyDOMSettings.ts +4 -0
  103. package/src/window/Window.ts +16 -4
  104. package/lib/css/declaration/utilities/CSSStyleDeclarationCSSParser.d.ts.map +0 -1
  105. package/lib/css/declaration/utilities/CSSStyleDeclarationCSSParser.js.map +0 -1
  106. package/lib/css/declaration/utilities/CSSStyleDeclarationElementDefaultCSS.d.ts.map +0 -1
  107. package/lib/css/declaration/utilities/CSSStyleDeclarationElementDefaultCSS.js.map +0 -1
  108. package/lib/css/declaration/utilities/CSSStyleDeclarationElementInheritedProperties.d.ts.map +0 -1
  109. package/lib/css/declaration/utilities/CSSStyleDeclarationElementInheritedProperties.js.map +0 -1
  110. package/lib/css/declaration/utilities/CSSStyleDeclarationElementStyle.d.ts.map +0 -1
  111. package/lib/css/declaration/utilities/CSSStyleDeclarationElementStyle.js.map +0 -1
  112. package/lib/css/declaration/utilities/CSSStyleDeclarationPropertyGetParser.d.ts.map +0 -1
  113. package/lib/css/declaration/utilities/CSSStyleDeclarationPropertyGetParser.js.map +0 -1
  114. package/lib/css/declaration/utilities/CSSStyleDeclarationPropertyManager.d.ts.map +0 -1
  115. package/lib/css/declaration/utilities/CSSStyleDeclarationPropertyManager.js.map +0 -1
  116. package/lib/css/declaration/utilities/CSSStyleDeclarationPropertySetParser.d.ts.map +0 -1
  117. package/lib/css/declaration/utilities/CSSStyleDeclarationPropertySetParser.js.map +0 -1
  118. package/lib/css/declaration/utilities/CSSStyleDeclarationValueParser.d.ts.map +0 -1
  119. package/lib/css/declaration/utilities/CSSStyleDeclarationValueParser.js.map +0 -1
  120. package/lib/css/declaration/utilities/ICSSStyleDeclarationPropertyValue.d.ts +0 -5
  121. package/lib/css/declaration/utilities/ICSSStyleDeclarationPropertyValue.d.ts.map +0 -1
  122. package/lib/css/declaration/utilities/ICSSStyleDeclarationPropertyValue.js.map +0 -1
  123. /package/lib/css/declaration/{utilities → css-parser}/CSSStyleDeclarationCSSParser.d.ts +0 -0
  124. /package/lib/css/declaration/{utilities → css-parser}/CSSStyleDeclarationCSSParser.js +0 -0
  125. /package/lib/css/declaration/{utilities → element-style/config}/CSSStyleDeclarationElementDefaultCSS.d.ts +0 -0
  126. /package/lib/css/declaration/{utilities → element-style/config}/CSSStyleDeclarationElementInheritedProperties.d.ts +0 -0
  127. /package/lib/css/declaration/{utilities → element-style/config}/CSSStyleDeclarationElementInheritedProperties.js +0 -0
  128. /package/lib/css/declaration/{utilities → property-manager}/CSSStyleDeclarationValueParser.d.ts +0 -0
  129. /package/lib/css/declaration/{utilities → property-manager}/ICSSStyleDeclarationPropertyValue.js +0 -0
  130. /package/src/css/declaration/{utilities → css-parser}/CSSStyleDeclarationCSSParser.ts +0 -0
  131. /package/src/css/declaration/{utilities → element-style/config}/CSSStyleDeclarationElementInheritedProperties.ts +0 -0
@@ -174,6 +174,66 @@ export default class CSSStyleDeclarationPropertySetParser {
174
174
  return null;
175
175
  }
176
176
 
177
+ /**
178
+ * Returns letter spacing.
179
+ *
180
+ * @param value Value.
181
+ * @param important Important.
182
+ * @returns Property values
183
+ */
184
+ public static getLetterSpacing(
185
+ value: string,
186
+ important: boolean
187
+ ): {
188
+ [key: string]: ICSSStyleDeclarationPropertyValue;
189
+ } {
190
+ const parsedValue =
191
+ CSSStyleDeclarationValueParser.getVariable(value) ||
192
+ CSSStyleDeclarationValueParser.getGlobal(value) ||
193
+ CSSStyleDeclarationValueParser.getContentMeasurement(value);
194
+ return parsedValue ? { 'letter-spacing': { value: parsedValue, important } } : null;
195
+ }
196
+
197
+ /**
198
+ * Returns word spacing.
199
+ *
200
+ * @param value Value.
201
+ * @param important Important.
202
+ * @returns Property values
203
+ */
204
+ public static getWordSpacing(
205
+ value: string,
206
+ important: boolean
207
+ ): {
208
+ [key: string]: ICSSStyleDeclarationPropertyValue;
209
+ } {
210
+ const parsedValue =
211
+ CSSStyleDeclarationValueParser.getVariable(value) ||
212
+ CSSStyleDeclarationValueParser.getGlobal(value) ||
213
+ CSSStyleDeclarationValueParser.getContentMeasurement(value);
214
+ return parsedValue ? { 'word-spacing': { value: parsedValue, important } } : null;
215
+ }
216
+
217
+ /**
218
+ * Returns text indent.
219
+ *
220
+ * @param value Value.
221
+ * @param important Important.
222
+ * @returns Property values
223
+ */
224
+ public static getTextIndent(
225
+ value: string,
226
+ important: boolean
227
+ ): {
228
+ [key: string]: ICSSStyleDeclarationPropertyValue;
229
+ } {
230
+ const parsedValue =
231
+ CSSStyleDeclarationValueParser.getVariable(value) ||
232
+ CSSStyleDeclarationValueParser.getGlobal(value) ||
233
+ CSSStyleDeclarationValueParser.getContentMeasurement(value);
234
+ return parsedValue ? { 'text-indent': { value: parsedValue, important } } : null;
235
+ }
236
+
177
237
  /**
178
238
  * Returns width.
179
239
  *
@@ -187,16 +247,33 @@ export default class CSSStyleDeclarationPropertySetParser {
187
247
  ): {
188
248
  [key: string]: ICSSStyleDeclarationPropertyValue;
189
249
  } {
190
- const variable = CSSStyleDeclarationValueParser.getVariable(value);
191
- if (variable) {
192
- return { width: { value: variable, important } };
193
- }
194
250
  const parsedValue =
251
+ CSSStyleDeclarationValueParser.getVariable(value) ||
195
252
  CSSStyleDeclarationValueParser.getGlobal(value) ||
196
253
  CSSStyleDeclarationValueParser.getContentMeasurement(value);
197
254
  return parsedValue ? { width: { value: parsedValue, important } } : null;
198
255
  }
199
256
 
257
+ /**
258
+ * Returns height.
259
+ *
260
+ * @param value Value.
261
+ * @param important Important.
262
+ * @returns Property values
263
+ */
264
+ public static getHeight(
265
+ value: string,
266
+ important: boolean
267
+ ): {
268
+ [key: string]: ICSSStyleDeclarationPropertyValue;
269
+ } {
270
+ const parsedValue =
271
+ CSSStyleDeclarationValueParser.getVariable(value) ||
272
+ CSSStyleDeclarationValueParser.getGlobal(value) ||
273
+ CSSStyleDeclarationValueParser.getContentMeasurement(value);
274
+ return parsedValue ? { height: { value: parsedValue, important } } : null;
275
+ }
276
+
200
277
  /**
201
278
  * Returns top.
202
279
  *
@@ -210,11 +287,8 @@ export default class CSSStyleDeclarationPropertySetParser {
210
287
  ): {
211
288
  [key: string]: ICSSStyleDeclarationPropertyValue;
212
289
  } {
213
- const variable = CSSStyleDeclarationValueParser.getVariable(value);
214
- if (variable) {
215
- return { top: { value: variable, important } };
216
- }
217
290
  const parsedValue =
291
+ CSSStyleDeclarationValueParser.getVariable(value) ||
218
292
  CSSStyleDeclarationValueParser.getGlobal(value) ||
219
293
  CSSStyleDeclarationValueParser.getContentMeasurement(value);
220
294
  return parsedValue ? { top: { value: parsedValue, important } } : null;
@@ -233,11 +307,8 @@ export default class CSSStyleDeclarationPropertySetParser {
233
307
  ): {
234
308
  [key: string]: ICSSStyleDeclarationPropertyValue;
235
309
  } {
236
- const variable = CSSStyleDeclarationValueParser.getVariable(value);
237
- if (variable) {
238
- return { right: { value: variable, important } };
239
- }
240
310
  const parsedValue =
311
+ CSSStyleDeclarationValueParser.getVariable(value) ||
241
312
  CSSStyleDeclarationValueParser.getGlobal(value) ||
242
313
  CSSStyleDeclarationValueParser.getContentMeasurement(value);
243
314
  return parsedValue ? { right: { value: parsedValue, important } } : null;
@@ -256,11 +327,8 @@ export default class CSSStyleDeclarationPropertySetParser {
256
327
  ): {
257
328
  [key: string]: ICSSStyleDeclarationPropertyValue;
258
329
  } {
259
- const variable = CSSStyleDeclarationValueParser.getVariable(value);
260
- if (variable) {
261
- return { bottom: { value: variable, important } };
262
- }
263
330
  const parsedValue =
331
+ CSSStyleDeclarationValueParser.getVariable(value) ||
264
332
  CSSStyleDeclarationValueParser.getGlobal(value) ||
265
333
  CSSStyleDeclarationValueParser.getContentMeasurement(value);
266
334
  return parsedValue ? { bottom: { value: parsedValue, important } } : null;
@@ -279,11 +347,8 @@ export default class CSSStyleDeclarationPropertySetParser {
279
347
  ): {
280
348
  [key: string]: ICSSStyleDeclarationPropertyValue;
281
349
  } {
282
- const variable = CSSStyleDeclarationValueParser.getVariable(value);
283
- if (variable) {
284
- return { left: { value: variable, important } };
285
- }
286
350
  const parsedValue =
351
+ CSSStyleDeclarationValueParser.getVariable(value) ||
287
352
  CSSStyleDeclarationValueParser.getGlobal(value) ||
288
353
  CSSStyleDeclarationValueParser.getContentMeasurement(value);
289
354
  return parsedValue ? { left: { value: parsedValue, important } } : null;
@@ -398,6 +463,156 @@ export default class CSSStyleDeclarationPropertySetParser {
398
463
  return float ? { 'css-float': float['float'] } : null;
399
464
  }
400
465
 
466
+ /**
467
+ * Returns outline.
468
+ *
469
+ * @param value Value.
470
+ * @param important Important.
471
+ * @returns Property values.
472
+ */
473
+ public static getOutline(
474
+ value: string,
475
+ important: boolean
476
+ ): { [key: string]: ICSSStyleDeclarationPropertyValue } {
477
+ const variable = CSSStyleDeclarationValueParser.getVariable(value);
478
+ if (variable) {
479
+ return { outline: { value: variable, important } };
480
+ }
481
+
482
+ const globalValue = CSSStyleDeclarationValueParser.getGlobal(value);
483
+
484
+ if (globalValue) {
485
+ return {
486
+ ...this.getOutlineColor(globalValue, important),
487
+ ...this.getOutlineStyle(globalValue, important),
488
+ ...this.getOutlineWidth(globalValue, important)
489
+ };
490
+ }
491
+
492
+ const properties = {
493
+ ...this.getOutlineColor('initial', important),
494
+ ...this.getOutlineStyle('initial', important),
495
+ ...this.getOutlineWidth('initial', important)
496
+ };
497
+
498
+ const parts = value.split(/ +/);
499
+
500
+ for (const part of parts) {
501
+ const width = this.getOutlineWidth(part, important);
502
+ const style = this.getOutlineStyle(part, important);
503
+ const color = this.getOutlineColor(part, important);
504
+
505
+ if (width === null && style === null && color === null) {
506
+ return null;
507
+ }
508
+
509
+ Object.assign(properties, width, style, color);
510
+ }
511
+
512
+ return properties;
513
+ }
514
+
515
+ /**
516
+ * Returns outline color.
517
+ *
518
+ * @param value Value.
519
+ * @param important Important.
520
+ * @returns Property values
521
+ */
522
+ public static getOutlineColor(
523
+ value: string,
524
+ important: boolean
525
+ ): {
526
+ [key: string]: ICSSStyleDeclarationPropertyValue;
527
+ } {
528
+ const color =
529
+ CSSStyleDeclarationValueParser.getVariable(value) ||
530
+ CSSStyleDeclarationValueParser.getGlobal(value) ||
531
+ CSSStyleDeclarationValueParser.getColor(value);
532
+ return color
533
+ ? {
534
+ 'outline-color': { value: color, important }
535
+ }
536
+ : null;
537
+ }
538
+
539
+ /**
540
+ * Returns outline offset.
541
+ *
542
+ * @param value Value.
543
+ * @param important Important.
544
+ * @returns Property values
545
+ */
546
+ public static getOutlineOffset(
547
+ value: string,
548
+ important: boolean
549
+ ): {
550
+ [key: string]: ICSSStyleDeclarationPropertyValue;
551
+ } {
552
+ const parsedValue =
553
+ CSSStyleDeclarationValueParser.getVariable(value) ||
554
+ CSSStyleDeclarationValueParser.getLength(value);
555
+ return parsedValue ? { 'outline-offset': { value: parsedValue, important } } : null;
556
+ }
557
+
558
+ /**
559
+ * Returns outline style.
560
+ *
561
+ * @param value Value.
562
+ * @param important Important.
563
+ * @returns Property values
564
+ */
565
+ public static getOutlineStyle(
566
+ value: string,
567
+ important: boolean
568
+ ): {
569
+ [key: string]: ICSSStyleDeclarationPropertyValue;
570
+ } {
571
+ const variable = CSSStyleDeclarationValueParser.getVariable(value);
572
+ if (variable) {
573
+ return { 'outline-style': { value: variable, important } };
574
+ }
575
+
576
+ const lowerValue = value.toLowerCase();
577
+ if (CSSStyleDeclarationValueParser.getGlobal(lowerValue) || BORDER_STYLE.includes(lowerValue)) {
578
+ return {
579
+ 'outline-style': { value: lowerValue, important }
580
+ };
581
+ }
582
+ return null;
583
+ }
584
+
585
+ /**
586
+ * Returns outline width.
587
+ *
588
+ * @param value Value.
589
+ * @param important Important.
590
+ * @returns Property values
591
+ */
592
+ public static getOutlineWidth(
593
+ value: string,
594
+ important: boolean
595
+ ): {
596
+ [key: string]: ICSSStyleDeclarationPropertyValue;
597
+ } {
598
+ const variable = CSSStyleDeclarationValueParser.getVariable(value);
599
+ if (variable) {
600
+ return { 'outline-width': { value: variable, important } };
601
+ }
602
+
603
+ const lowerValue = value.toLowerCase();
604
+ const parsedValue =
605
+ BORDER_WIDTH.includes(lowerValue) || CSSStyleDeclarationValueParser.getGlobal(lowerValue)
606
+ ? lowerValue
607
+ : CSSStyleDeclarationValueParser.getLength(value);
608
+ if (parsedValue) {
609
+ return {
610
+ 'outline-width': { value: parsedValue, important }
611
+ };
612
+ }
613
+ return null;
614
+ }
615
+
401
616
  /**
402
617
  * Returns border.
403
618
  *
@@ -1,7 +1,8 @@
1
1
  const COLOR_REGEXP =
2
2
  /^#([0-9a-fA-F]{3,4}){1,2}$|^rgb\(([^)]*)\)$|^rgba\(([^)]*)\)$|^hsla?\(\s*(-?\d+|-?\d*.\d+)\s*,\s*(-?\d+|-?\d*.\d+)%\s*,\s*(-?\d+|-?\d*.\d+)%\s*(,\s*(-?\d+|-?\d*.\d+)\s*)?\)/;
3
3
 
4
- const LENGTH_REGEXP = /^(0|[-+]?[0-9]*\.?[0-9]+(in|cm|em|mm|pt|pc|px|ex|rem|vh|vw|ch))$/;
4
+ const LENGTH_REGEXP =
5
+ /^(0|[-+]?[0-9]*\.?[0-9]+(in|cm|em|mm|pt|pc|px|ex|rem|vh|vw|ch|vw|vh|vmin|vmax|Q))$/;
5
6
  const PERCENTAGE_REGEXP = /^[-+]?[0-9]*\.?[0-9]+%$/;
6
7
  const DEGREE_REGEXP = /^[0-9]+deg$/;
7
8
  const URL_REGEXP = /^url\(\s*([^)]*)\s*\)$/;
@@ -1,4 +1,4 @@
1
1
  export default interface ICSSStyleDeclarationPropertyValue {
2
- readonly value: string;
3
- readonly important: boolean;
2
+ value: string;
3
+ important: boolean;
4
4
  }
@@ -0,0 +1,5 @@
1
+ export default interface IMediaQueryRange {
2
+ before: { value: string; operator: string };
3
+ type: string;
4
+ after: { value: string; operator: string };
5
+ }
@@ -0,0 +1,4 @@
1
+ export default interface IMediaQueryRule {
2
+ name: string;
3
+ value: string | null;
4
+ }
@@ -0,0 +1,336 @@
1
+ import CSSMeasurementConverter from '../css/declaration/measurement-converter/CSSMeasurementConverter';
2
+ import IWindow from '../window/IWindow';
3
+ import IMediaQueryRange from './IMediaQueryRange';
4
+ import IMediaQueryRule from './IMediaQueryRule';
5
+ import MediaQueryTypeEnum from './MediaQueryTypeEnum';
6
+
7
+ /**
8
+ * Media query this.
9
+ */
10
+ export default class MediaQueryItem {
11
+ public mediaTypes: MediaQueryTypeEnum[];
12
+ public not: boolean;
13
+ public rules: IMediaQueryRule[];
14
+ public ranges: IMediaQueryRange[];
15
+ private rootFontSize: string | number | null = null;
16
+ private ownerWindow: IWindow;
17
+
18
+ /**
19
+ * Constructor.
20
+ *
21
+ * @param options Options.
22
+ * @param options.ownerWindow Owner window.
23
+ * @param [options.rootFontSize] Root font size.
24
+ * @param [options.mediaTypes] Media types.
25
+ * @param [options.not] Not.
26
+ * @param [options.rules] Rules.
27
+ * @param [options.ranges] Ranges.
28
+ */
29
+ constructor(options: {
30
+ ownerWindow: IWindow;
31
+ rootFontSize?: string | number | null;
32
+ mediaTypes?: MediaQueryTypeEnum[];
33
+ not?: boolean;
34
+ rules?: IMediaQueryRule[];
35
+ ranges?: IMediaQueryRange[];
36
+ }) {
37
+ this.ownerWindow = options.ownerWindow;
38
+ this.rootFontSize = options.rootFontSize || null;
39
+ this.mediaTypes = options.mediaTypes || [];
40
+ this.not = options.not || false;
41
+ this.rules = options.rules || [];
42
+ this.ranges = options.ranges || [];
43
+ }
44
+
45
+ /**
46
+ * Returns media string.
47
+ */
48
+ public toString(): string {
49
+ return `${this.not ? 'not ' : ''}${this.mediaTypes.join(', ')}${
50
+ (this.not || this.mediaTypes.length > 0) && !!this.ranges.length ? ' and ' : ''
51
+ }${this.ranges
52
+ .map(
53
+ (range) =>
54
+ `(${range.before ? `${range.before.value} ${range.before.operator} ` : ''}${range.type}${
55
+ range.after ? ` ${range.after.operator} ${range.after.value}` : ''
56
+ })`
57
+ )
58
+ .join(' and ')}${
59
+ (this.not || this.mediaTypes.length > 0) && !!this.rules.length ? ' and ' : ''
60
+ }${this.rules
61
+ .map((rule) => (rule.value ? `(${rule.name}: ${rule.value})` : `(${rule.name})`))
62
+ .join(' and ')}`;
63
+ }
64
+
65
+ /**
66
+ * Returns "true" if the item matches.
67
+ */
68
+ public matches(): boolean {
69
+ return this.not ? !this.matchesAll() : this.matchesAll();
70
+ }
71
+
72
+ /**
73
+ * Returns "true" if all matches.
74
+ *
75
+ * @returns "true" if all matches.
76
+ */
77
+ private matchesAll(): boolean {
78
+ if (!!this.mediaTypes.length) {
79
+ let isMediaTypeMatch = false;
80
+ for (const mediaType of this.mediaTypes) {
81
+ if (this.matchesMediaType(mediaType)) {
82
+ isMediaTypeMatch = true;
83
+ break;
84
+ }
85
+ }
86
+
87
+ if (!isMediaTypeMatch) {
88
+ return false;
89
+ }
90
+ }
91
+
92
+ for (const rule of this.rules) {
93
+ if (!this.matchesRule(rule)) {
94
+ return false;
95
+ }
96
+ }
97
+
98
+ for (const range of this.ranges) {
99
+ if (!this.matchesRange(range)) {
100
+ return false;
101
+ }
102
+ }
103
+
104
+ return true;
105
+ }
106
+
107
+ /**
108
+ * Returns "true" if the mediaType matches.
109
+ *
110
+ * @param mediaType Media type.
111
+ * @returns "true" if the mediaType matches.
112
+ */
113
+ private matchesMediaType(mediaType: MediaQueryTypeEnum): boolean {
114
+ if (mediaType === MediaQueryTypeEnum.all) {
115
+ return true;
116
+ }
117
+ return mediaType === this.ownerWindow.happyDOM.settings.device.mediaType;
118
+ }
119
+
120
+ /**
121
+ * Returns "true" if the range matches.
122
+ *
123
+ * @param range Range.
124
+ * @returns "true" if the range matches.
125
+ */
126
+ private matchesRange(range: IMediaQueryRange): boolean {
127
+ const windowSize =
128
+ range.type === 'width' ? this.ownerWindow.innerWidth : this.ownerWindow.innerHeight;
129
+
130
+ if (range.before) {
131
+ const beforeValue = this.toPixels(range.before.value);
132
+
133
+ if (beforeValue === null) {
134
+ return false;
135
+ }
136
+
137
+ switch (range.before.operator) {
138
+ case '<':
139
+ if (beforeValue >= windowSize) {
140
+ return false;
141
+ }
142
+ break;
143
+ case '<=':
144
+ if (beforeValue > windowSize) {
145
+ return false;
146
+ }
147
+ break;
148
+ case '>':
149
+ if (beforeValue <= windowSize) {
150
+ return false;
151
+ }
152
+ break;
153
+ case '>=':
154
+ if (beforeValue < windowSize) {
155
+ return false;
156
+ }
157
+ break;
158
+ }
159
+ }
160
+
161
+ if (range.after) {
162
+ const afterValue = this.toPixels(range.after.value);
163
+
164
+ if (afterValue === null) {
165
+ return false;
166
+ }
167
+
168
+ switch (range.after.operator) {
169
+ case '<':
170
+ if (windowSize >= afterValue) {
171
+ return false;
172
+ }
173
+ break;
174
+ case '<=':
175
+ if (windowSize > afterValue) {
176
+ return false;
177
+ }
178
+ break;
179
+ case '>':
180
+ if (windowSize <= afterValue) {
181
+ return false;
182
+ }
183
+ break;
184
+ case '>=':
185
+ if (windowSize < afterValue) {
186
+ return false;
187
+ }
188
+ break;
189
+ }
190
+ }
191
+
192
+ return true;
193
+ }
194
+
195
+ /**
196
+ * Returns "true" if the rule matches.
197
+ *
198
+ * @param rule Rule.
199
+ * @returns "true" if the rule matches.
200
+ */
201
+ private matchesRule(rule: IMediaQueryRule): boolean {
202
+ if (!rule.value) {
203
+ switch (rule.name) {
204
+ case 'min-width':
205
+ case 'max-width':
206
+ case 'min-height':
207
+ case 'max-height':
208
+ case 'width':
209
+ case 'height':
210
+ case 'orientation':
211
+ case 'prefers-color-scheme':
212
+ case 'hover':
213
+ case 'any-hover':
214
+ case 'any-pointer':
215
+ case 'pointer':
216
+ case 'display-mode':
217
+ case 'min-aspect-ratio':
218
+ case 'max-aspect-ratio':
219
+ case 'aspect-ratio':
220
+ return true;
221
+ }
222
+ return false;
223
+ }
224
+
225
+ switch (rule.name) {
226
+ case 'min-width':
227
+ const minWidth = this.toPixels(rule.value);
228
+ return minWidth !== null && this.ownerWindow.innerWidth >= minWidth;
229
+ case 'max-width':
230
+ const maxWidth = this.toPixels(rule.value);
231
+ return maxWidth !== null && this.ownerWindow.innerWidth <= maxWidth;
232
+ case 'min-height':
233
+ const minHeight = this.toPixels(rule.value);
234
+ return minHeight !== null && this.ownerWindow.innerHeight >= minHeight;
235
+ case 'max-height':
236
+ const maxHeight = this.toPixels(rule.value);
237
+ return maxHeight !== null && this.ownerWindow.innerHeight <= maxHeight;
238
+ case 'width':
239
+ const width = this.toPixels(rule.value);
240
+ return width !== null && this.ownerWindow.innerWidth === width;
241
+ case 'height':
242
+ const height = this.toPixels(rule.value);
243
+ return height !== null && this.ownerWindow.innerHeight === height;
244
+ case 'orientation':
245
+ return rule.value === 'landscape'
246
+ ? this.ownerWindow.innerWidth > this.ownerWindow.innerHeight
247
+ : this.ownerWindow.innerWidth < this.ownerWindow.innerHeight;
248
+ case 'prefers-color-scheme':
249
+ return rule.value === this.ownerWindow.happyDOM.settings.device.prefersColorScheme;
250
+ case 'any-hover':
251
+ case 'hover':
252
+ if (rule.value === 'none') {
253
+ return this.ownerWindow.navigator.maxTouchPoints > 0;
254
+ }
255
+ if (rule.value === 'hover') {
256
+ return this.ownerWindow.navigator.maxTouchPoints === 0;
257
+ }
258
+ return false;
259
+ case 'any-pointer':
260
+ case 'pointer':
261
+ if (rule.value === 'none') {
262
+ return false;
263
+ }
264
+
265
+ if (rule.value === 'coarse') {
266
+ return this.ownerWindow.navigator.maxTouchPoints > 0;
267
+ }
268
+
269
+ if (rule.value === 'fine') {
270
+ return this.ownerWindow.navigator.maxTouchPoints === 0;
271
+ }
272
+
273
+ return false;
274
+ case 'display-mode':
275
+ return rule.value === 'browser';
276
+ case 'min-aspect-ratio':
277
+ case 'max-aspect-ratio':
278
+ case 'aspect-ratio':
279
+ const aspectRatio = rule.value.split('/');
280
+ const aspectRatioWidth = parseInt(aspectRatio[0], 10);
281
+ const aspectRatioHeight = parseInt(aspectRatio[1], 10);
282
+
283
+ if (isNaN(aspectRatioWidth) || isNaN(aspectRatioHeight)) {
284
+ return false;
285
+ }
286
+
287
+ switch (rule.name) {
288
+ case 'min-aspect-ratio':
289
+ return (
290
+ aspectRatioWidth / aspectRatioHeight <=
291
+ this.ownerWindow.innerWidth / this.ownerWindow.innerHeight
292
+ );
293
+ case 'max-aspect-ratio':
294
+ return (
295
+ aspectRatioWidth / aspectRatioHeight >=
296
+ this.ownerWindow.innerWidth / this.ownerWindow.innerHeight
297
+ );
298
+ case 'aspect-ratio':
299
+ return (
300
+ aspectRatioWidth / aspectRatioHeight ===
301
+ this.ownerWindow.innerWidth / this.ownerWindow.innerHeight
302
+ );
303
+ }
304
+ }
305
+
306
+ return false;
307
+ }
308
+
309
+ /**
310
+ * Convert to pixels.
311
+ *
312
+ * @param value Value.
313
+ * @returns Value in pixels.
314
+ */
315
+ private toPixels(value: string): number | null {
316
+ if (value.endsWith('em')) {
317
+ this.rootFontSize =
318
+ this.rootFontSize ||
319
+ parseFloat(
320
+ this.ownerWindow.getComputedStyle(this.ownerWindow.document.documentElement).fontSize
321
+ );
322
+ return CSSMeasurementConverter.toPixels({
323
+ ownerWindow: this.ownerWindow,
324
+ value,
325
+ rootFontSize: this.rootFontSize,
326
+ parentFontSize: this.rootFontSize
327
+ });
328
+ }
329
+ return CSSMeasurementConverter.toPixels({
330
+ ownerWindow: this.ownerWindow,
331
+ value,
332
+ rootFontSize: 16,
333
+ parentFontSize: 16
334
+ });
335
+ }
336
+ }