Browse Source

HTML5 quality selection

Sam Potts 1 year ago
parent
commit
3395e8df90

+ 1
- 0
.stylelintrc.json View File

@@ -9,6 +9,7 @@
9 9
                 "ignore": ["attribute", "class"]
10 10
             }
11 11
         ],
12
+        "string-no-newline": null,
12 13
         "indentation": 4,
13 14
         "string-quotes": "single",
14 15
         "max-nesting-depth": 2,

+ 189
- 53
demo/dist/demo.js View File

@@ -85,6 +85,15 @@ function serializer(replacer, cycleReplacer) {
85 85
 });
86 86
 var stringify_2 = stringify_1.getSerialize;
87 87
 
88
+
89
+var stringify = Object.freeze({
90
+	default: stringify_1,
91
+	__moduleExports: stringify_1,
92
+	getSerialize: stringify_2
93
+});
94
+
95
+var stringify$1 = ( stringify && stringify_1 ) || stringify;
96
+
88 97
 var _window =
89 98
   typeof window !== 'undefined'
90 99
     ? window
@@ -592,7 +601,7 @@ function serializeException(ex, depth, maxSize) {
592 601
 
593 602
   var serialized = serializeObject(ex, depth);
594 603
 
595
-  if (jsonSize(stringify_1(serialized)) > maxSize) {
604
+  if (jsonSize(stringify$1(serialized)) > maxSize) {
596 605
     return serializeException(ex, depth - 1);
597 606
   }
598 607
 
@@ -630,7 +639,7 @@ function sanitize(input, sanitizeKeys) {
630 639
   var safeInput;
631 640
 
632 641
   try {
633
-    safeInput = JSON.parse(stringify_1(input));
642
+    safeInput = JSON.parse(stringify$1(input));
634 643
   } catch (o_O) {
635 644
     return input;
636 645
   }
@@ -693,6 +702,78 @@ var utils = {
693 702
   serializeKeysForMessage: serializeKeysForMessage,
694 703
   sanitize: sanitize
695 704
 };
705
+var utils_1 = utils.isObject;
706
+var utils_2 = utils.isError;
707
+var utils_3 = utils.isErrorEvent;
708
+var utils_4 = utils.isUndefined;
709
+var utils_5 = utils.isFunction;
710
+var utils_6 = utils.isPlainObject;
711
+var utils_7 = utils.isString;
712
+var utils_8 = utils.isArray;
713
+var utils_9 = utils.isEmptyObject;
714
+var utils_10 = utils.supportsErrorEvent;
715
+var utils_11 = utils.supportsFetch;
716
+var utils_12 = utils.supportsReferrerPolicy;
717
+var utils_13 = utils.supportsPromiseRejectionEvent;
718
+var utils_14 = utils.wrappedCallback;
719
+var utils_15 = utils.each;
720
+var utils_16 = utils.objectMerge;
721
+var utils_17 = utils.truncate;
722
+var utils_18 = utils.objectFrozen;
723
+var utils_19 = utils.hasKey;
724
+var utils_20 = utils.joinRegExp;
725
+var utils_21 = utils.urlencode;
726
+var utils_22 = utils.uuid4;
727
+var utils_23 = utils.htmlTreeAsString;
728
+var utils_24 = utils.htmlElementAsString;
729
+var utils_25 = utils.isSameException;
730
+var utils_26 = utils.isSameStacktrace;
731
+var utils_27 = utils.parseUrl;
732
+var utils_28 = utils.fill;
733
+var utils_29 = utils.safeJoin;
734
+var utils_30 = utils.serializeException;
735
+var utils_31 = utils.serializeKeysForMessage;
736
+var utils_32 = utils.sanitize;
737
+
738
+
739
+var utils$1 = Object.freeze({
740
+	default: utils,
741
+	__moduleExports: utils,
742
+	isObject: utils_1,
743
+	isError: utils_2,
744
+	isErrorEvent: utils_3,
745
+	isUndefined: utils_4,
746
+	isFunction: utils_5,
747
+	isPlainObject: utils_6,
748
+	isString: utils_7,
749
+	isArray: utils_8,
750
+	isEmptyObject: utils_9,
751
+	supportsErrorEvent: utils_10,
752
+	supportsFetch: utils_11,
753
+	supportsReferrerPolicy: utils_12,
754
+	supportsPromiseRejectionEvent: utils_13,
755
+	wrappedCallback: utils_14,
756
+	each: utils_15,
757
+	objectMerge: utils_16,
758
+	truncate: utils_17,
759
+	objectFrozen: utils_18,
760
+	hasKey: utils_19,
761
+	joinRegExp: utils_20,
762
+	urlencode: utils_21,
763
+	uuid4: utils_22,
764
+	htmlTreeAsString: utils_23,
765
+	htmlElementAsString: utils_24,
766
+	isSameException: utils_25,
767
+	isSameStacktrace: utils_26,
768
+	parseUrl: utils_27,
769
+	fill: utils_28,
770
+	safeJoin: utils_29,
771
+	serializeException: utils_30,
772
+	serializeKeysForMessage: utils_31,
773
+	sanitize: utils_32
774
+});
775
+
776
+var utils$2 = ( utils$1 && utils ) || utils$1;
696 777
 
697 778
 /*
698 779
  TraceKit - Cross brower stack traces
@@ -842,9 +923,9 @@ TraceKit.report = (function reportModuleWrapper() {
842 923
   function traceKitWindowOnError(msg, url, lineNo, colNo, ex) {
843 924
     var stack = null;
844 925
     // If 'ex' is ErrorEvent, get real Error from inside
845
-    var exception = utils.isErrorEvent(ex) ? ex.error : ex;
926
+    var exception = utils$2.isErrorEvent(ex) ? ex.error : ex;
846 927
     // If 'msg' is ErrorEvent, get real message from inside
847
-    var message = utils.isErrorEvent(msg) ? msg.message : msg;
928
+    var message = utils$2.isErrorEvent(msg) ? msg.message : msg;
848 929
 
849 930
     if (lastExceptionStack) {
850 931
       TraceKit.computeStackTrace.augmentStackTraceWithInitialElement(
@@ -854,7 +935,7 @@ TraceKit.report = (function reportModuleWrapper() {
854 935
         message
855 936
       );
856 937
       processLastException();
857
-    } else if (exception && utils.isError(exception)) {
938
+    } else if (exception && utils$2.isError(exception)) {
858 939
       // non-string `exception` arg; attempt to extract stack trace
859 940
 
860 941
       // New chrome and blink send along a real error object
@@ -1321,6 +1402,12 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
1321 1402
 
1322 1403
 var tracekit = TraceKit;
1323 1404
 
1405
+
1406
+var tracekit$1 = Object.freeze({
1407
+	default: tracekit,
1408
+	__moduleExports: tracekit
1409
+});
1410
+
1324 1411
 /*
1325 1412
  * JavaScript MD5
1326 1413
  * https://github.com/blueimp/JavaScript-MD5
@@ -1588,6 +1675,12 @@ function md5(string, key, raw) {
1588 1675
 
1589 1676
 var md5_1 = md5;
1590 1677
 
1678
+
1679
+var md5$1 = Object.freeze({
1680
+	default: md5_1,
1681
+	__moduleExports: md5_1
1682
+});
1683
+
1591 1684
 function RavenConfigError(message) {
1592 1685
   this.name = 'RavenConfigError';
1593 1686
   this.message = message;
@@ -1597,6 +1690,12 @@ RavenConfigError.prototype.constructor = RavenConfigError;
1597 1690
 
1598 1691
 var configError = RavenConfigError;
1599 1692
 
1693
+
1694
+var configError$1 = Object.freeze({
1695
+	default: configError,
1696
+	__moduleExports: configError
1697
+});
1698
+
1600 1699
 var wrapMethod = function(console, level, callback) {
1601 1700
   var originalConsoleLevel = console[level];
1602 1701
   var originalConsole = console;
@@ -1610,14 +1709,14 @@ var wrapMethod = function(console, level, callback) {
1610 1709
   console[level] = function() {
1611 1710
     var args = [].slice.call(arguments);
1612 1711
 
1613
-    var msg = utils.safeJoin(args, ' ');
1712
+    var msg = utils$2.safeJoin(args, ' ');
1614 1713
     var data = {level: sentryLevel, logger: 'console', extra: {arguments: args}};
1615 1714
 
1616 1715
     if (level === 'assert') {
1617 1716
       if (args[0] === false) {
1618 1717
         // Default browsers message
1619 1718
         msg =
1620
-          'Assertion failed: ' + (utils.safeJoin(args.slice(1), ' ') || 'console.assert');
1719
+          'Assertion failed: ' + (utils$2.safeJoin(args.slice(1), ' ') || 'console.assert');
1621 1720
         data.extra.arguments = args.slice(1);
1622 1721
         callback && callback(msg, data);
1623 1722
       }
@@ -1637,6 +1736,22 @@ var wrapMethod = function(console, level, callback) {
1637 1736
 var console$1 = {
1638 1737
   wrapMethod: wrapMethod
1639 1738
 };
1739
+var console_1 = console$1.wrapMethod;
1740
+
1741
+
1742
+var console$2 = Object.freeze({
1743
+	default: console$1,
1744
+	__moduleExports: console$1,
1745
+	wrapMethod: console_1
1746
+});
1747
+
1748
+var TraceKit$1 = ( tracekit$1 && tracekit ) || tracekit$1;
1749
+
1750
+var md5$2 = ( md5$1 && md5_1 ) || md5$1;
1751
+
1752
+var RavenConfigError$1 = ( configError$1 && configError ) || configError$1;
1753
+
1754
+var require$$0 = ( console$2 && console$1 ) || console$2;
1640 1755
 
1641 1756
 /*global XDomainRequest:false */
1642 1757
 
@@ -1646,35 +1761,35 @@ var console$1 = {
1646 1761
 
1647 1762
 
1648 1763
 
1649
-var isError$1 = utils.isError;
1650
-var isObject$1 = utils.isObject;
1651
-var isPlainObject$1 = utils.isPlainObject;
1652
-var isErrorEvent$1 = utils.isErrorEvent;
1653
-var isUndefined$1 = utils.isUndefined;
1654
-var isFunction$1 = utils.isFunction;
1655
-var isString$1 = utils.isString;
1656
-var isArray$1 = utils.isArray;
1657
-var isEmptyObject$1 = utils.isEmptyObject;
1658
-var each$1 = utils.each;
1659
-var objectMerge$1 = utils.objectMerge;
1660
-var truncate$1 = utils.truncate;
1661
-var objectFrozen$1 = utils.objectFrozen;
1662
-var hasKey$1 = utils.hasKey;
1663
-var joinRegExp$1 = utils.joinRegExp;
1664
-var urlencode$1 = utils.urlencode;
1665
-var uuid4$1 = utils.uuid4;
1666
-var htmlTreeAsString$1 = utils.htmlTreeAsString;
1667
-var isSameException$1 = utils.isSameException;
1668
-var isSameStacktrace$1 = utils.isSameStacktrace;
1669
-var parseUrl$1 = utils.parseUrl;
1670
-var fill$1 = utils.fill;
1671
-var supportsFetch$1 = utils.supportsFetch;
1672
-var supportsReferrerPolicy$1 = utils.supportsReferrerPolicy;
1673
-var serializeKeysForMessage$1 = utils.serializeKeysForMessage;
1674
-var serializeException$1 = utils.serializeException;
1675
-var sanitize$1 = utils.sanitize;
1764
+var isError$1 = utils$2.isError;
1765
+var isObject$1 = utils$2.isObject;
1766
+var isPlainObject$1 = utils$2.isPlainObject;
1767
+var isErrorEvent$1 = utils$2.isErrorEvent;
1768
+var isUndefined$1 = utils$2.isUndefined;
1769
+var isFunction$1 = utils$2.isFunction;
1770
+var isString$1 = utils$2.isString;
1771
+var isArray$1 = utils$2.isArray;
1772
+var isEmptyObject$1 = utils$2.isEmptyObject;
1773
+var each$1 = utils$2.each;
1774
+var objectMerge$1 = utils$2.objectMerge;
1775
+var truncate$1 = utils$2.truncate;
1776
+var objectFrozen$1 = utils$2.objectFrozen;
1777
+var hasKey$1 = utils$2.hasKey;
1778
+var joinRegExp$1 = utils$2.joinRegExp;
1779
+var urlencode$1 = utils$2.urlencode;
1780
+var uuid4$1 = utils$2.uuid4;
1781
+var htmlTreeAsString$1 = utils$2.htmlTreeAsString;
1782
+var isSameException$1 = utils$2.isSameException;
1783
+var isSameStacktrace$1 = utils$2.isSameStacktrace;
1784
+var parseUrl$1 = utils$2.parseUrl;
1785
+var fill$1 = utils$2.fill;
1786
+var supportsFetch$1 = utils$2.supportsFetch;
1787
+var supportsReferrerPolicy$1 = utils$2.supportsReferrerPolicy;
1788
+var serializeKeysForMessage$1 = utils$2.serializeKeysForMessage;
1789
+var serializeException$1 = utils$2.serializeException;
1790
+var sanitize$1 = utils$2.sanitize;
1676 1791
 
1677
-var wrapConsoleMethod = console$1.wrapMethod;
1792
+var wrapConsoleMethod = require$$0.wrapMethod;
1678 1793
 
1679 1794
 var dsnKeys = 'source protocol user pass host port path'.split(' '),
1680 1795
   dsnPattern = /^(?:(\w+):)?\/\/(?:(\w+)(:\w+)?@)?([\w\.-]+)(?::(\d+))?(\/.*)/;
@@ -1781,7 +1896,7 @@ Raven.prototype = {
1781 1896
 
1782 1897
   debug: false,
1783 1898
 
1784
-  TraceKit: tracekit, // alias to TraceKit
1899
+  TraceKit: TraceKit$1, // alias to TraceKit
1785 1900
 
1786 1901
   /*
1787 1902
      * Configure Raven with a DSN and extra options
@@ -1862,7 +1977,7 @@ Raven.prototype = {
1862 1977
     }
1863 1978
     globalOptions.instrument = instrument;
1864 1979
 
1865
-    tracekit.collectWindowErrors = !!globalOptions.collectWindowErrors;
1980
+    TraceKit$1.collectWindowErrors = !!globalOptions.collectWindowErrors;
1866 1981
 
1867 1982
     // return for chaining
1868 1983
     return self;
@@ -1879,7 +1994,7 @@ Raven.prototype = {
1879 1994
   install: function() {
1880 1995
     var self = this;
1881 1996
     if (self.isSetup() && !self._isRavenInstalled) {
1882
-      tracekit.report.subscribe(function() {
1997
+      TraceKit$1.report.subscribe(function() {
1883 1998
         self._handleOnErrorStackInfo.apply(self, arguments);
1884 1999
       });
1885 2000
 
@@ -2043,7 +2158,7 @@ Raven.prototype = {
2043 2158
    * @return {Raven}
2044 2159
    */
2045 2160
   uninstall: function() {
2046
-    tracekit.report.uninstall();
2161
+    TraceKit$1.report.uninstall();
2047 2162
 
2048 2163
     this._detachPromiseRejectionHandler();
2049 2164
     this._unpatchFunctionToString();
@@ -2138,7 +2253,7 @@ Raven.prototype = {
2138 2253
     // raises an exception different from the one we asked to
2139 2254
     // report on.
2140 2255
     try {
2141
-      var stack = tracekit.computeStackTrace(ex);
2256
+      var stack = TraceKit$1.computeStackTrace(ex);
2142 2257
       this._handleStackInfo(stack, options);
2143 2258
     } catch (ex1) {
2144 2259
       if (ex !== ex1) {
@@ -2154,7 +2269,7 @@ Raven.prototype = {
2154 2269
     var options = objectMerge$1(currentOptions, {
2155 2270
       message:
2156 2271
         'Non-Error exception captured with keys: ' + serializeKeysForMessage$1(exKeys),
2157
-      fingerprint: [md5_1(exKeys)],
2272
+      fingerprint: [md5$2(exKeys)],
2158 2273
       extra: currentOptions.extra || {}
2159 2274
     });
2160 2275
     options.extra.__serialized__ = serializeException$1(ex);
@@ -2203,7 +2318,7 @@ Raven.prototype = {
2203 2318
 
2204 2319
     // null exception name so `Error` isn't prefixed to msg
2205 2320
     ex.name = null;
2206
-    var stack = tracekit.computeStackTrace(ex);
2321
+    var stack = TraceKit$1.computeStackTrace(ex);
2207 2322
 
2208 2323
     // stack[0] is `throw new Error(msg)` call itself, we are interested in the frame that was just before that, stack[1]
2209 2324
     var initialCall = isArray$1(stack.stack) && stack.stack[1];
@@ -2350,7 +2465,7 @@ Raven.prototype = {
2350 2465
      */
2351 2466
   getContext: function() {
2352 2467
     // lol javascript
2353
-    return JSON.parse(stringify_1(this._globalContext));
2468
+    return JSON.parse(stringify$1(this._globalContext));
2354 2469
   },
2355 2470
 
2356 2471
   /*
@@ -2486,12 +2601,12 @@ Raven.prototype = {
2486 2601
 
2487 2602
     var lastEventId = options.eventId || this.lastEventId();
2488 2603
     if (!lastEventId) {
2489
-      throw new configError('Missing eventId');
2604
+      throw new RavenConfigError$1('Missing eventId');
2490 2605
     }
2491 2606
 
2492 2607
     var dsn = options.dsn || this._dsn;
2493 2608
     if (!dsn) {
2494
-      throw new configError('Missing DSN');
2609
+      throw new RavenConfigError$1('Missing DSN');
2495 2610
     }
2496 2611
 
2497 2612
     var encode = encodeURIComponent;
@@ -3133,11 +3248,11 @@ Raven.prototype = {
3133 3248
     try {
3134 3249
       while (i--) dsn[dsnKeys[i]] = m[i] || '';
3135 3250
     } catch (e) {
3136
-      throw new configError('Invalid DSN: ' + str);
3251
+      throw new RavenConfigError$1('Invalid DSN: ' + str);
3137 3252
     }
3138 3253
 
3139 3254
     if (dsn.pass && !this._globalOptions.allowSecretKey) {
3140
-      throw new configError(
3255
+      throw new RavenConfigError$1(
3141 3256
         'Do not specify your secret key in the DSN. See: http://bit.ly/raven-secret-key'
3142 3257
       );
3143 3258
     }
@@ -3658,7 +3773,7 @@ Raven.prototype = {
3658 3773
     }
3659 3774
 
3660 3775
     if (supportsFetch$1()) {
3661
-      evaluatedFetchParameters.body = stringify_1(opts.data);
3776
+      evaluatedFetchParameters.body = stringify$1(opts.data);
3662 3777
 
3663 3778
       var defaultFetchOptions = objectMerge$1({}, this._fetchDefaults);
3664 3779
       var fetchOptions = objectMerge$1(defaultFetchOptions, evaluatedFetchParameters);
@@ -3733,7 +3848,7 @@ Raven.prototype = {
3733 3848
       });
3734 3849
     }
3735 3850
 
3736
-    request.send(stringify_1(opts.data));
3851
+    request.send(stringify$1(opts.data));
3737 3852
   },
3738 3853
 
3739 3854
   _evaluateHash: function(hash) {
@@ -3775,6 +3890,14 @@ Raven.prototype.setReleaseContext = Raven.prototype.setRelease;
3775 3890
 
3776 3891
 var raven = Raven;
3777 3892
 
3893
+
3894
+var raven$1 = Object.freeze({
3895
+	default: raven,
3896
+	__moduleExports: raven
3897
+});
3898
+
3899
+var RavenConstructor = ( raven$1 && raven ) || raven$1;
3900
+
3778 3901
 /**
3779 3902
  * Enforces a single instance of the Raven client, and the
3780 3903
  * main entry point for Raven. If you are a consumer of the
@@ -3790,7 +3913,7 @@ var _window$3 =
3790 3913
     : typeof commonjsGlobal !== 'undefined' ? commonjsGlobal : typeof self !== 'undefined' ? self : {};
3791 3914
 var _Raven = _window$3.Raven;
3792 3915
 
3793
-var Raven$1 = new raven();
3916
+var Raven$1 = new RavenConstructor();
3794 3917
 
3795 3918
 /*
3796 3919
  * Allow multiple versions of Raven to be installed.
@@ -3841,7 +3964,7 @@ var singleton = Raven$1;
3841 3964
  *
3842 3965
  * It should "just work".
3843 3966
  */
3844
-var Client = raven;
3967
+var Client = RavenConstructor;
3845 3968
 singleton.Client = Client;
3846 3969
 
3847 3970
 // ==========================================================================
@@ -3960,8 +4083,21 @@ singleton.Client = Client;
3960 4083
                             type: 'video',
3961 4084
                             title: 'View From A Blue Moon',
3962 4085
                             sources: [{
3963
-                                src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.mp4',
3964
-                                type: 'video/mp4'
4086
+                                src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-576p.mp4',
4087
+                                type: 'video/mp4',
4088
+                                size: 576
4089
+                            }, {
4090
+                                src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-720p.mp4',
4091
+                                type: 'video/mp4',
4092
+                                size: 720
4093
+                            }, {
4094
+                                src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-1080p.mp4',
4095
+                                type: 'video/mp4',
4096
+                                size: 1080
4097
+                            }, {
4098
+                                src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-1440p.mp4',
4099
+                                type: 'video/mp4',
4100
+                                size: 1440
3965 4101
                             }],
3966 4102
                             poster: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.jpg',
3967 4103
                             tracks: [{

+ 1
- 1
demo/dist/demo.js.map
File diff suppressed because it is too large
View File


+ 1
- 1
demo/dist/demo.min.js
File diff suppressed because it is too large
View File


+ 1
- 1
demo/dist/demo.min.js.map
File diff suppressed because it is too large
View File


+ 7
- 5
demo/index.html View File

@@ -93,16 +93,18 @@
93 93
         <main>
94 94
             <video controls crossorigin playsinline poster="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.jpg" id="player">
95 95
                 <!-- Video files -->
96
-                <source src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.mp4" type="video/mp4">
97
-                <source src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.webm" type="video/webm">
96
+                <source src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-576p.mp4" type="video/mp4" size="576">
97
+                <source src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-720p.mp4" type="video/mp4" size="720">
98
+                <source src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-1080p.mp4" type="video/mp4" size="1080">
99
+                <source src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-1440p.mp4" type="video/mp4" size="1440">
98 100
 
99
-                <!-- Text track file -->
101
+                <!-- Caption files -->
100 102
                 <track kind="captions" label="English" srclang="en" src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.en.vtt"
101 103
                     default>
102 104
                 <track kind="captions" label="Français" srclang="fr" src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.fr.vtt">
103 105
 
104 106
                 <!-- Fallback for browsers that don't support the <video> element -->
105
-                <a href="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.mp4" download>Download</a>
107
+                <a href="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-576p.mp4" download>Download</a>
106 108
             </video>
107 109
 
108 110
             <ul>
@@ -169,7 +171,7 @@
169 171
     </aside>
170 172
 
171 173
     <!-- Polyfills -->
172
-    <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=es6,Array.prototype.includes,CustomEvent,Object.entries"
174
+    <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=es6,Array.prototype.includes,CustomEvent,Object.entries,Object.values"
173 175
         crossorigin="anonymous"></script>
174 176
 
175 177
     <!-- Plyr core script -->

+ 22
- 4
demo/src/js/demo.js View File

@@ -119,10 +119,28 @@ import Raven from 'raven-js';
119 119
                         player.source = {
120 120
                             type: 'video',
121 121
                             title: 'View From A Blue Moon',
122
-                            sources: [{
123
-                                src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.mp4',
124
-                                type: 'video/mp4',
125
-                            }],
122
+                            sources: [
123
+                                {
124
+                                    src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-576p.mp4',
125
+                                    type: 'video/mp4',
126
+                                    size: 576,
127
+                                },
128
+                                {
129
+                                    src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-720p.mp4',
130
+                                    type: 'video/mp4',
131
+                                    size: 720,
132
+                                },
133
+                                {
134
+                                    src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-1080p.mp4',
135
+                                    type: 'video/mp4',
136
+                                    size: 1080,
137
+                                },
138
+                                {
139
+                                    src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-1440p.mp4',
140
+                                    type: 'video/mp4',
141
+                                    size: 1440,
142
+                                },
143
+                            ],
126 144
                             poster: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.jpg',
127 145
                             tracks: [
128 146
                                 {

+ 305
- 96
dist/plyr.js View File

@@ -77,15 +77,15 @@ var defaults = {
77 77
     // Sprite (for icons)
78 78
     loadSprite: true,
79 79
     iconPrefix: 'plyr',
80
-    iconUrl: 'https://cdn.plyr.io/3.0.10/plyr.svg',
80
+    iconUrl: 'https://cdn.plyr.io/3.0.11/plyr.svg',
81 81
 
82 82
     // Blank video (used to prevent errors on source change)
83 83
     blankVideo: 'https://cdn.plyr.io/static/blank.mp4',
84 84
 
85 85
     // Quality default
86 86
     quality: {
87
-        default: 'default',
88
-        options: ['hd2160', 'hd1440', 'hd1080', 'hd720', 'large', 'medium', 'small', 'tiny', 'default']
87
+        default: 720,
88
+        options: [4320, 2880, 2160, 1440, 1080, 720, 576, 480, 360, 240, 'default']
89 89
     },
90 90
 
91 91
     // Set loops
@@ -1339,15 +1339,19 @@ var utils = {
1339 1339
 
1340 1340
 
1341 1341
     // Trigger event
1342
-    dispatchEvent: function dispatchEvent(element, type, bubbles, detail) {
1342
+    dispatchEvent: function dispatchEvent(element) {
1343
+        var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
1344
+        var bubbles = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
1345
+        var detail = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
1346
+
1343 1347
         // Bail if no element
1344
-        if (!utils.is.element(element) || !utils.is.string(type)) {
1348
+        if (!utils.is.element(element) || utils.is.empty(type)) {
1345 1349
             return;
1346 1350
         }
1347 1351
 
1348 1352
         // Create and dispatch the event
1349 1353
         var event = new CustomEvent(type, {
1350
-            bubbles: utils.is.boolean(bubbles) ? bubbles : false,
1354
+            bubbles: bubbles,
1351 1355
             detail: Object.assign({}, detail, {
1352 1356
                 plyr: utils.is.plyr(this) ? this : null
1353 1357
             })
@@ -1526,6 +1530,18 @@ var utils = {
1526 1530
     },
1527 1531
 
1528 1532
 
1533
+    // Remove duplicates in an array
1534
+    dedupe: function dedupe(array) {
1535
+        if (!utils.is.array(array)) {
1536
+            return array;
1537
+        }
1538
+
1539
+        return array.filter(function (item, index) {
1540
+            return array.indexOf(item) === index;
1541
+        });
1542
+    },
1543
+
1544
+
1529 1545
     // Get the provider for a given URL
1530 1546
     getProviderByUrl: function getProviderByUrl(url) {
1531 1547
         // YouTube
@@ -2427,8 +2443,8 @@ var ui = {
2427 2443
         // Reset loop state
2428 2444
         this.loop = null;
2429 2445
 
2430
-        // Reset quality options
2431
-        this.options.quality = [];
2446
+        // Reset quality setting
2447
+        this.quality = null;
2432 2448
 
2433 2449
         // Reset volume display
2434 2450
         ui.updateVolume.call(this);
@@ -2700,6 +2716,159 @@ var ui = {
2700 2716
 
2701 2717
 // ==========================================================================
2702 2718
 
2719
+var html5 = {
2720
+    getSources: function getSources() {
2721
+        if (!this.isHTML5) {
2722
+            return null;
2723
+        }
2724
+
2725
+        return this.media.querySelectorAll('source');
2726
+    },
2727
+
2728
+
2729
+    // Get quality levels
2730
+    getQualityOptions: function getQualityOptions() {
2731
+        if (!this.isHTML5) {
2732
+            return null;
2733
+        }
2734
+
2735
+        // Get sources
2736
+        var sources = html5.getSources.call(this);
2737
+
2738
+        if (utils.is.empty(sources)) {
2739
+            return null;
2740
+        }
2741
+
2742
+        // Get <source> with size attribute
2743
+        var sizes = Array.from(sources).filter(function (source) {
2744
+            return !utils.is.empty(source.getAttribute('size'));
2745
+        });
2746
+
2747
+        // If none, bail
2748
+        if (utils.is.empty(sizes)) {
2749
+            return null;
2750
+        }
2751
+
2752
+        // Reduce to unique list
2753
+        return utils.dedupe(sizes.map(function (source) {
2754
+            return Number(source.getAttribute('size'));
2755
+        }));
2756
+    },
2757
+    extend: function extend() {
2758
+        if (!this.isHTML5) {
2759
+            return;
2760
+        }
2761
+
2762
+        var player = this;
2763
+
2764
+        // Quality
2765
+        Object.defineProperty(player.media, 'quality', {
2766
+            get: function get() {
2767
+                // Get sources
2768
+                var sources = html5.getSources.call(player);
2769
+
2770
+                if (utils.is.empty(sources)) {
2771
+                    return null;
2772
+                }
2773
+
2774
+                var matches = Array.from(sources).filter(function (source) {
2775
+                    return source.getAttribute('src') === player.source;
2776
+                });
2777
+
2778
+                if (utils.is.empty(matches)) {
2779
+                    return null;
2780
+                }
2781
+
2782
+                return Number(matches[0].getAttribute('size'));
2783
+            },
2784
+            set: function set(input) {
2785
+                // Get sources
2786
+                var sources = html5.getSources.call(player);
2787
+
2788
+                if (utils.is.empty(sources)) {
2789
+                    return;
2790
+                }
2791
+
2792
+                // Get matches for requested size
2793
+                var matches = Array.from(sources).filter(function (source) {
2794
+                    return Number(source.getAttribute('size')) === input;
2795
+                });
2796
+
2797
+                // No matches for requested size
2798
+                if (utils.is.empty(matches)) {
2799
+                    return;
2800
+                }
2801
+
2802
+                // Get supported sources
2803
+                var supported = matches.filter(function (source) {
2804
+                    return support.mime.call(player, source.getAttribute('type'));
2805
+                });
2806
+
2807
+                // No supported sources
2808
+                if (utils.is.empty(supported)) {
2809
+                    return;
2810
+                }
2811
+
2812
+                // Trigger change event
2813
+                utils.dispatchEvent.call(player, player.media, 'qualityrequested', false, {
2814
+                    quality: input
2815
+                });
2816
+
2817
+                // Get current state
2818
+                var currentTime = player.currentTime,
2819
+                    playing = player.playing;
2820
+
2821
+                // Set new source
2822
+
2823
+                player.media.src = supported[0].getAttribute('src');
2824
+
2825
+                // Load new source
2826
+                player.media.load();
2827
+
2828
+                // Resume playing
2829
+                if (playing) {
2830
+                    player.play();
2831
+                }
2832
+
2833
+                // Restore time
2834
+                player.currentTime = currentTime;
2835
+
2836
+                // Trigger change event
2837
+                utils.dispatchEvent.call(player, player.media, 'qualitychange', false, {
2838
+                    quality: input
2839
+                });
2840
+            }
2841
+        });
2842
+    },
2843
+
2844
+
2845
+    // Cancel current network requests
2846
+    // See https://github.com/sampotts/plyr/issues/174
2847
+    cancelRequests: function cancelRequests() {
2848
+        if (!this.isHTML5) {
2849
+            return;
2850
+        }
2851
+
2852
+        // Remove child sources
2853
+        utils.removeElement(html5.getSources());
2854
+
2855
+        // Set blank video src attribute
2856
+        // This is to prevent a MEDIA_ERR_SRC_NOT_SUPPORTED error
2857
+        // Info: http://stackoverflow.com/questions/32231579/how-to-properly-dispose-of-an-html5-video-and-close-socket-or-connection
2858
+        this.media.setAttribute('src', this.config.blankVideo);
2859
+
2860
+        // Load the new empty source
2861
+        // This will cancel existing requests
2862
+        // See https://github.com/sampotts/plyr/issues/174
2863
+        this.media.load();
2864
+
2865
+        // Debugging
2866
+        this.debug.log('Cancelled network requests');
2867
+    }
2868
+};
2869
+
2870
+// ==========================================================================
2871
+
2703 2872
 // Sniff out the browser
2704 2873
 var browser$1 = utils.getBrowser();
2705 2874
 
@@ -3100,8 +3269,8 @@ var controls = {
3100 3269
     },
3101 3270
 
3102 3271
 
3103
-    // Set the YouTube quality menu
3104
-    // TODO: Support for HTML5
3272
+    // Set the quality menu
3273
+    // TODO: Vimeo support
3105 3274
     setQualityMenu: function setQualityMenu(options) {
3106 3275
         var _this2 = this;
3107 3276
 
@@ -3118,12 +3287,10 @@ var controls = {
3118 3287
             this.options.quality = options.filter(function (quality) {
3119 3288
                 return _this2.config.quality.options.includes(quality);
3120 3289
             });
3121
-        } else {
3122
-            this.options.quality = this.config.quality.options;
3123 3290
         }
3124 3291
 
3125 3292
         // Toggle the pane and tab
3126
-        var toggle = !utils.is.empty(this.options.quality) && this.isYouTube;
3293
+        var toggle = !utils.is.empty(this.options.quality) && this.options.quality.length > 1;
3127 3294
         controls.toggleTab.call(this, type, toggle);
3128 3295
 
3129 3296
         // If we're hiding, nothing more to do
@@ -3139,22 +3306,26 @@ var controls = {
3139 3306
             var label = '';
3140 3307
 
3141 3308
             switch (quality) {
3142
-                case 'hd2160':
3309
+                case 2160:
3143 3310
                     label = '4K';
3144 3311
                     break;
3145 3312
 
3146
-                case 'hd1440':
3313
+                case 1440:
3147 3314
                     label = 'WQHD';
3148 3315
                     break;
3149 3316
 
3150
-                case 'hd1080':
3317
+                case 1080:
3151 3318
                     label = 'HD';
3152 3319
                     break;
3153 3320
 
3154
-                case 'hd720':
3321
+                case 720:
3155 3322
                     label = 'HD';
3156 3323
                     break;
3157 3324
 
3325
+                case 576:
3326
+                    label = 'SD';
3327
+                    break;
3328
+
3158 3329
                 default:
3159 3330
                     break;
3160 3331
             }
@@ -3166,8 +3337,13 @@ var controls = {
3166 3337
             return controls.createBadge.call(_this2, label);
3167 3338
         };
3168 3339
 
3169
-        this.options.quality.forEach(function (quality) {
3170
-            return controls.createMenuItem.call(_this2, quality, list, type, controls.getLabel.call(_this2, 'quality', quality), getBadge(quality));
3340
+        // Sort options by the config and then render options
3341
+        this.options.quality.sort(function (a, b) {
3342
+            var sorting = _this2.config.quality.options;
3343
+            return sorting.indexOf(a) > sorting.indexOf(b) ? 1 : -1;
3344
+        }).forEach(function (quality) {
3345
+            var label = controls.getLabel.call(_this2, 'quality', quality);
3346
+            controls.createMenuItem.call(_this2, quality, list, type, label, getBadge(quality));
3171 3347
         });
3172 3348
 
3173 3349
         controls.updateSetting.call(this, type, list);
@@ -3182,28 +3358,10 @@ var controls = {
3182 3358
                 return value === 1 ? 'Normal' : value + '&times;';
3183 3359
 
3184 3360
             case 'quality':
3185
-                switch (value) {
3186
-                    case 'hd2160':
3187
-                        return '2160P';
3188
-                    case 'hd1440':
3189
-                        return '1440P';
3190
-                    case 'hd1080':
3191
-                        return '1080P';
3192
-                    case 'hd720':
3193
-                        return '720P';
3194
-                    case 'large':
3195
-                        return '480P';
3196
-                    case 'medium':
3197
-                        return '360P';
3198
-                    case 'small':
3199
-                        return '240P';
3200
-                    case 'tiny':
3201
-                        return 'Tiny';
3202
-                    case 'default':
3203
-                        return 'Auto';
3204
-                    default:
3205
-                        return value;
3361
+                if (utils.is.number(value)) {
3362
+                    return value + 'p';
3206 3363
                 }
3364
+                return utils.toTitleCase(value);
3207 3365
 
3208 3366
             case 'captions':
3209 3367
                 return controls.getLanguage.call(this);
@@ -3215,7 +3373,7 @@ var controls = {
3215 3373
 
3216 3374
 
3217 3375
     // Update the selected setting
3218
-    updateSetting: function updateSetting(setting, container) {
3376
+    updateSetting: function updateSetting(setting, container, input) {
3219 3377
         var pane = this.elements.settings.panes[setting];
3220 3378
         var value = null;
3221 3379
         var list = container;
@@ -3226,7 +3384,7 @@ var controls = {
3226 3384
                 break;
3227 3385
 
3228 3386
             default:
3229
-                value = this[setting];
3387
+                value = !utils.is.empty(input) ? input : this[setting];
3230 3388
 
3231 3389
                 // Get default
3232 3390
                 if (utils.is.empty(value)) {
@@ -3234,7 +3392,7 @@ var controls = {
3234 3392
                 }
3235 3393
 
3236 3394
                 // Unsupported value
3237
-                if (!this.options[setting].includes(value)) {
3395
+                if (!utils.is.empty(this.options[setting]) && !this.options[setting].includes(value)) {
3238 3396
                     this.debug.warn('Unsupported value of \'' + value + '\' for ' + setting);
3239 3397
                     return;
3240 3398
                 }
@@ -3428,10 +3586,13 @@ var controls = {
3428 3586
 
3429 3587
     // Check if we need to hide/show the settings menu
3430 3588
     checkMenu: function checkMenu() {
3431
-        var speedHidden = this.elements.settings.tabs.speed.getAttribute('hidden') !== null;
3432
-        var languageHidden = this.elements.settings.tabs.captions.getAttribute('hidden') !== null;
3589
+        var tabs = this.elements.settings.tabs;
3433 3590
 
3434
-        utils.toggleHidden(this.elements.settings.menu, speedHidden && languageHidden);
3591
+        var visible = !utils.is.empty(tabs) && Object.values(tabs).some(function (tab) {
3592
+            return !tab.hidden;
3593
+        });
3594
+
3595
+        utils.toggleHidden(this.elements.settings.menu, !visible);
3435 3596
     },
3436 3597
 
3437 3598
 
@@ -3827,6 +3988,10 @@ var controls = {
3827 3988
 
3828 3989
         controls.setSpeedMenu.call(this);
3829 3990
 
3991
+        if (this.isHTML5) {
3992
+            controls.setQualityMenu.call(this, html5.getQualityOptions.call(this));
3993
+        }
3994
+
3830 3995
         return container;
3831 3996
     },
3832 3997
 
@@ -4285,13 +4450,16 @@ var Listeners = function () {
4285 4450
                 _this3.player.storage.set({ speed: _this3.player.speed });
4286 4451
             });
4287 4452
 
4453
+            // Quality request
4454
+            utils.on(this.player.media, 'qualityrequested', function (event) {
4455
+                // Save to storage
4456
+                _this3.player.storage.set({ quality: event.detail.quality });
4457
+            });
4458
+
4288 4459
             // Quality change
4289
-            utils.on(this.player.media, 'qualitychange', function () {
4460
+            utils.on(this.player.media, 'qualitychange', function (event) {
4290 4461
                 // Update UI
4291
-                controls.updateSetting.call(_this3.player, 'quality');
4292
-
4293
-                // Save to storage
4294
-                _this3.player.storage.set({ quality: _this3.player.quality });
4462
+                controls.updateSetting.call(_this3.player, 'quality', null, event.detail.quality);
4295 4463
             });
4296 4464
 
4297 4465
             // Caption language change
@@ -5280,6 +5448,66 @@ var Ads = function () {
5280 5448
 
5281 5449
 // ==========================================================================
5282 5450
 
5451
+// Standardise YouTube quality unit
5452
+function mapQualityUnit(input) {
5453
+    switch (input) {
5454
+        case 'hd2160':
5455
+            return 2160;
5456
+
5457
+        case 2160:
5458
+            return 'hd2160';
5459
+
5460
+        case 'hd1440':
5461
+            return 1440;
5462
+
5463
+        case 1440:
5464
+            return 'hd1440';
5465
+
5466
+        case 'hd1080':
5467
+            return 1080;
5468
+
5469
+        case 1080:
5470
+            return 'hd1080';
5471
+
5472
+        case 'hd720':
5473
+            return 720;
5474
+
5475
+        case 720:
5476
+            return 'hd720';
5477
+
5478
+        case 'large':
5479
+            return 480;
5480
+
5481
+        case 480:
5482
+            return 'large';
5483
+
5484
+        case 'medium':
5485
+            return 360;
5486
+
5487
+        case 360:
5488
+            return 'medium';
5489
+
5490
+        case 'small':
5491
+            return 240;
5492
+
5493
+        case 240:
5494
+            return 'small';
5495
+
5496
+        default:
5497
+            return 'default';
5498
+    }
5499
+}
5500
+
5501
+function mapQualityUnits(levels) {
5502
+    if (utils.is.empty(levels)) {
5503
+        return levels;
5504
+    }
5505
+
5506
+    return utils.dedupe(levels.map(function (level) {
5507
+        return mapQualityUnit(level);
5508
+    }));
5509
+}
5510
+
5283 5511
 var youtube = {
5284 5512
     setup: function setup() {
5285 5513
         var _this = this;
@@ -5444,14 +5672,10 @@ var youtube = {
5444 5672
 
5445 5673
                     utils.dispatchEvent.call(player, player.media, 'error');
5446 5674
                 },
5447
-                onPlaybackQualityChange: function onPlaybackQualityChange(event) {
5448
-                    // Get the instance
5449
-                    var instance = event.target;
5450
-
5451
-                    // Get current quality
5452
-                    player.media.quality = instance.getPlaybackQuality();
5453
-
5454
-                    utils.dispatchEvent.call(player, player.media, 'qualitychange');
5675
+                onPlaybackQualityChange: function onPlaybackQualityChange() {
5676
+                    utils.dispatchEvent.call(player, player.media, 'qualitychange', false, {
5677
+                        quality: player.media.quality
5678
+                    });
5455 5679
                 },
5456 5680
                 onPlaybackRateChange: function onPlaybackRateChange(event) {
5457 5681
                     // Get the instance
@@ -5516,15 +5740,18 @@ var youtube = {
5516 5740
                     // Quality
5517 5741
                     Object.defineProperty(player.media, 'quality', {
5518 5742
                         get: function get() {
5519
-                            return instance.getPlaybackQuality();
5743
+                            return mapQualityUnit(instance.getPlaybackQuality());
5520 5744
                         },
5521 5745
                         set: function set(input) {
5746
+                            var quality = input;
5747
+
5748
+                            // Set via API
5749
+                            instance.setPlaybackQuality(mapQualityUnit(quality));
5750
+
5522 5751
                             // Trigger request event
5523 5752
                             utils.dispatchEvent.call(player, player.media, 'qualityrequested', false, {
5524
-                                quality: input
5753
+                                quality: quality
5525 5754
                             });
5526
-
5527
-                            instance.setPlaybackQuality(input);
5528 5755
                         }
5529 5756
                     });
5530 5757
 
@@ -5681,7 +5908,7 @@ var youtube = {
5681 5908
                             }
5682 5909
 
5683 5910
                             // Get quality
5684
-                            controls.setQualityMenu.call(player, instance.getAvailableQualityLevels());
5911
+                            controls.setQualityMenu.call(player, mapQualityUnits(instance.getAvailableQualityLevels()));
5685 5912
 
5686 5913
                             break;
5687 5914
 
@@ -6103,32 +6330,9 @@ var media = {
6103 6330
             }
6104 6331
         } else if (this.isHTML5) {
6105 6332
             ui.setTitle.call(this);
6106
-        }
6107
-    },
6108
-
6109 6333
 
6110
-    // Cancel current network requests
6111
-    // See https://github.com/sampotts/plyr/issues/174
6112
-    cancelRequests: function cancelRequests() {
6113
-        if (!this.isHTML5) {
6114
-            return;
6334
+            html5.extend.call(this);
6115 6335
         }
6116
-
6117
-        // Remove child sources
6118
-        utils.removeElement(this.media.querySelectorAll('source'));
6119
-
6120
-        // Set blank video src attribute
6121
-        // This is to prevent a MEDIA_ERR_SRC_NOT_SUPPORTED error
6122
-        // Info: http://stackoverflow.com/questions/32231579/how-to-properly-dispose-of-an-html5-video-and-close-socket-or-connection
6123
-        this.media.setAttribute('src', this.config.blankVideo);
6124
-
6125
-        // Load the new empty source
6126
-        // This will cancel existing requests
6127
-        // See https://github.com/sampotts/plyr/issues/174
6128
-        this.media.load();
6129
-
6130
-        // Debugging
6131
-        this.debug.log('Cancelled network requests');
6132 6336
     }
6133 6337
 };
6134 6338
 
@@ -6162,11 +6366,12 @@ var source = {
6162 6366
         }
6163 6367
 
6164 6368
         // Cancel current network requests
6165
-        media.cancelRequests.call(this);
6369
+        html5.cancelRequests.call(this);
6166 6370
 
6167 6371
         // Destroy instance and re-setup
6168 6372
         this.destroy.call(this, function () {
6169
-            // TODO: Reset menus here
6373
+            // Reset quality options
6374
+            _this2.options.quality = [];
6170 6375
 
6171 6376
             // Remove elements
6172 6377
             utils.removeElement(_this2.media);
@@ -7325,8 +7530,8 @@ var Plyr = function () {
7325 7530
 
7326 7531
         /**
7327 7532
          * Set playback quality
7328
-         * Currently YouTube only
7329
-         * @param {string} input - Quality level
7533
+         * Currently HTML5 & YouTube only
7534
+         * @param {number} input - Quality level
7330 7535
          */
7331 7536
 
7332 7537
     }, {
@@ -7334,18 +7539,22 @@ var Plyr = function () {
7334 7539
         set: function set$$1(input) {
7335 7540
             var quality = null;
7336 7541
 
7337
-            if (utils.is.string(input)) {
7338
-                quality = input;
7542
+            if (!utils.is.empty(input)) {
7543
+                quality = Number(input);
7339 7544
             }
7340 7545
 
7341
-            if (!utils.is.string(quality)) {
7546
+            if (!utils.is.number(quality) || quality === 0) {
7342 7547
                 quality = this.storage.get('quality');
7343 7548
             }
7344 7549
 
7345
-            if (!utils.is.string(quality)) {
7550
+            if (!utils.is.number(quality)) {
7346 7551
                 quality = this.config.quality.selected;
7347 7552
             }
7348 7553
 
7554
+            if (!utils.is.number(quality)) {
7555
+                quality = this.config.quality.default;
7556
+            }
7557
+
7349 7558
             if (!this.options.quality.includes(quality)) {
7350 7559
                 this.debug.warn('Unsupported quality option (' + quality + ')');
7351 7560
                 return;

+ 1
- 1
dist/plyr.js.map
File diff suppressed because it is too large
View File


+ 1
- 1
dist/plyr.min.js
File diff suppressed because it is too large
View File


+ 1
- 1
dist/plyr.min.js.map
File diff suppressed because it is too large
View File


+ 1962
- 853
dist/plyr.polyfilled.js
File diff suppressed because it is too large
View File


+ 1
- 1
dist/plyr.polyfilled.js.map
File diff suppressed because it is too large
View File


+ 1
- 1
dist/plyr.polyfilled.min.js
File diff suppressed because it is too large
View File


+ 1
- 1
dist/plyr.polyfilled.min.js.map
File diff suppressed because it is too large
View File


+ 3
- 3
package.json View File

@@ -16,7 +16,7 @@
16 16
         "eslint": "^4.19.1",
17 17
         "eslint-config-airbnb-base": "^12.1.0",
18 18
         "eslint-config-prettier": "^2.9.0",
19
-        "eslint-plugin-import": "^2.9.0",
19
+        "eslint-plugin-import": "^2.10.0",
20 20
         "git-branch": "^2.0.1",
21 21
         "gulp": "^3.9.1",
22 22
         "gulp-autoprefixer": "^5.0.0",
@@ -41,12 +41,12 @@
41 41
         "rollup-plugin-commonjs": "^9.1.0",
42 42
         "rollup-plugin-node-resolve": "^3.3.0",
43 43
         "run-sequence": "^2.2.1",
44
-        "stylelint": "^9.1.3",
44
+        "stylelint": "^9.2.0",
45 45
         "stylelint-config-prettier": "^3.0.4",
46 46
         "stylelint-config-recommended": "^2.1.0",
47 47
         "stylelint-config-sass-guidelines": "^5.0.0",
48 48
         "stylelint-order": "^0.8.1",
49
-        "stylelint-scss": "^2.5.0",
49
+        "stylelint-scss": "^3.0.0",
50 50
         "stylelint-selector-bem-pattern": "^2.0.0"
51 51
     },
52 52
     "keywords": ["HTML5 Video", "HTML5 Audio", "Media Player", "DASH", "Shaka", "WordPress", "HLS"],

+ 33
- 39
src/js/controls.js View File

@@ -7,6 +7,7 @@ import utils from './utils';
7 7
 import ui from './ui';
8 8
 import i18n from './i18n';
9 9
 import captions from './captions';
10
+import html5 from './html5';
10 11
 
11 12
 // Sniff out the browser
12 13
 const browser = utils.getBrowser();
@@ -435,8 +436,8 @@ const controls = {
435 436
         utils.toggleHidden(pane, !toggle);
436 437
     },
437 438
 
438
-    // Set the YouTube quality menu
439
-    // TODO: Support for HTML5
439
+    // Set the quality menu
440
+    // TODO: Vimeo support
440 441
     setQualityMenu(options) {
441 442
         // Menu required
442 443
         if (!utils.is.element(this.elements.settings.panes.quality)) {
@@ -449,12 +450,10 @@ const controls = {
449 450
         // Set options if passed and filter based on config
450 451
         if (utils.is.array(options)) {
451 452
             this.options.quality = options.filter(quality => this.config.quality.options.includes(quality));
452
-        } else {
453
-            this.options.quality = this.config.quality.options;
454 453
         }
455 454
 
456 455
         // Toggle the pane and tab
457
-        const toggle = !utils.is.empty(this.options.quality) && this.isYouTube;
456
+        const toggle = !utils.is.empty(this.options.quality) && this.options.quality.length > 1;
458 457
         controls.toggleTab.call(this, type, toggle);
459 458
 
460 459
         // If we're hiding, nothing more to do
@@ -470,22 +469,26 @@ const controls = {
470 469
             let label = '';
471 470
 
472 471
             switch (quality) {
473
-                case 'hd2160':
472
+                case 2160:
474 473
                     label = '4K';
475 474
                     break;
476 475
 
477
-                case 'hd1440':
476
+                case 1440:
478 477
                     label = 'WQHD';
479 478
                     break;
480 479
 
481
-                case 'hd1080':
480
+                case 1080:
482 481
                     label = 'HD';
483 482
                     break;
484 483
 
485
-                case 'hd720':
484
+                case 720:
486 485
                     label = 'HD';
487 486
                     break;
488 487
 
488
+                case 576:
489
+                    label = 'SD';
490
+                    break;
491
+
489 492
                 default:
490 493
                     break;
491 494
             }
@@ -497,9 +500,14 @@ const controls = {
497 500
             return controls.createBadge.call(this, label);
498 501
         };
499 502
 
500
-        this.options.quality.forEach(quality =>
501
-            controls.createMenuItem.call(this, quality, list, type, controls.getLabel.call(this, 'quality', quality), getBadge(quality)),
502
-        );
503
+        // Sort options by the config and then render options
504
+        this.options.quality.sort((a, b) => {
505
+            const sorting = this.config.quality.options;
506
+            return sorting.indexOf(a) > sorting.indexOf(b) ? 1 : -1;
507
+        }).forEach(quality => {
508
+            const label = controls.getLabel.call(this, 'quality', quality);
509
+            controls.createMenuItem.call(this, quality, list, type, label, getBadge(quality));
510
+        });
503 511
 
504 512
         controls.updateSetting.call(this, type, list);
505 513
     },
@@ -512,28 +520,10 @@ const controls = {
512 520
                 return value === 1 ? 'Normal' : `${value}&times;`;
513 521
 
514 522
             case 'quality':
515
-                switch (value) {
516
-                    case 'hd2160':
517
-                        return '2160P';
518
-                    case 'hd1440':
519
-                        return '1440P';
520
-                    case 'hd1080':
521
-                        return '1080P';
522
-                    case 'hd720':
523
-                        return '720P';
524
-                    case 'large':
525
-                        return '480P';
526
-                    case 'medium':
527
-                        return '360P';
528
-                    case 'small':
529
-                        return '240P';
530
-                    case 'tiny':
531
-                        return 'Tiny';
532
-                    case 'default':
533
-                        return 'Auto';
534
-                    default:
535
-                        return value;
523
+                if (utils.is.number(value)) {
524
+                    return `${value}p`;
536 525
                 }
526
+                return utils.toTitleCase(value);
537 527
 
538 528
             case 'captions':
539 529
                 return controls.getLanguage.call(this);
@@ -544,7 +534,7 @@ const controls = {
544 534
     },
545 535
 
546 536
     // Update the selected setting
547
-    updateSetting(setting, container) {
537
+    updateSetting(setting, container, input) {
548 538
         const pane = this.elements.settings.panes[setting];
549 539
         let value = null;
550 540
         let list = container;
@@ -555,7 +545,7 @@ const controls = {
555 545
                 break;
556 546
 
557 547
             default:
558
-                value = this[setting];
548
+                value = !utils.is.empty(input) ? input : this[setting];
559 549
 
560 550
                 // Get default
561 551
                 if (utils.is.empty(value)) {
@@ -563,7 +553,7 @@ const controls = {
563 553
                 }
564 554
 
565 555
                 // Unsupported value
566
-                if (!this.options[setting].includes(value)) {
556
+                if (!utils.is.empty(this.options[setting]) && !this.options[setting].includes(value)) {
567 557
                     this.debug.warn(`Unsupported value of '${value}' for ${setting}`);
568 558
                     return;
569 559
                 }
@@ -767,10 +757,10 @@ const controls = {
767 757
 
768 758
     // Check if we need to hide/show the settings menu
769 759
     checkMenu() {
770
-        const speedHidden = this.elements.settings.tabs.speed.getAttribute('hidden') !== null;
771
-        const languageHidden = this.elements.settings.tabs.captions.getAttribute('hidden') !== null;
760
+        const { tabs } = this.elements.settings;
761
+        const visible = !utils.is.empty(tabs) && Object.values(tabs).some(tab => !tab.hidden);
772 762
 
773
-        utils.toggleHidden(this.elements.settings.menu, speedHidden && languageHidden);
763
+        utils.toggleHidden(this.elements.settings.menu, !visible);
774 764
     },
775 765
 
776 766
     // Show/hide menu
@@ -1179,6 +1169,10 @@ const controls = {
1179 1169
 
1180 1170
         controls.setSpeedMenu.call(this);
1181 1171
 
1172
+        if (this.isHTML5) {
1173
+            controls.setQualityMenu.call(this, html5.getQualityOptions.call(this));
1174
+        }
1175
+
1182 1176
         return container;
1183 1177
     },
1184 1178
 

+ 12
- 10
src/js/defaults.js View File

@@ -63,17 +63,19 @@ const defaults = {
63 63
 
64 64
     // Quality default
65 65
     quality: {
66
-        default: 'default',
66
+        default: 720,
67 67
         options: [
68
-            'hd2160',
69
-            'hd1440',
70
-            'hd1080',
71
-            'hd720',
72
-            'large',
73
-            'medium',
74
-            'small',
75
-            'tiny',
76
-            'default',
68
+            4320,
69
+            2880,
70
+            2160,
71
+            1440,
72
+            1080,
73
+            720,
74
+            576,
75
+            480,
76
+            360,
77
+            240,
78
+            'default', // YouTube's "auto"
77 79
         ],
78 80
     },
79 81
 

+ 146
- 0
src/js/html5.js View File

@@ -0,0 +1,146 @@
1
+// ==========================================================================
2
+// Plyr HTML5 helpers
3
+// ==========================================================================
4
+
5
+import support from './support';
6
+import utils from './utils';
7
+
8
+const html5 = {
9
+    getSources() {
10
+        if (!this.isHTML5) {
11
+            return null;
12
+        }
13
+
14
+        return this.media.querySelectorAll('source');
15
+    },
16
+
17
+    // Get quality levels
18
+    getQualityOptions() {
19
+        if (!this.isHTML5) {
20
+            return null;
21
+        }
22
+
23
+        // Get sources
24
+        const sources = html5.getSources.call(this);
25
+
26
+        if (utils.is.empty(sources)) {
27
+            return null;
28
+        }
29
+
30
+        // Get <source> with size attribute
31
+        const sizes = Array.from(sources).filter(source => !utils.is.empty(source.getAttribute('size')));
32
+
33
+        // If none, bail
34
+        if (utils.is.empty(sizes)) {
35
+            return null;
36
+        }
37
+
38
+        // Reduce to unique list
39
+        return utils.dedupe(sizes.map(source => Number(source.getAttribute('size'))));
40
+    },
41
+
42
+    extend() {
43
+        if (!this.isHTML5) {
44
+            return;
45
+        }
46
+
47
+        const player = this;
48
+
49
+        // Quality
50
+        Object.defineProperty(player.media, 'quality', {
51
+            get() {
52
+                // Get sources
53
+                const sources = html5.getSources.call(player);
54
+
55
+                if (utils.is.empty(sources)) {
56
+                    return null;
57
+                }
58
+
59
+                const matches = Array.from(sources).filter(source => source.getAttribute('src') === player.source);
60
+
61
+                if (utils.is.empty(matches)) {
62
+                    return null;
63
+                }
64
+
65
+                return Number(matches[0].getAttribute('size'));
66
+            },
67
+            set(input) {
68
+                // Get sources
69
+                const sources = html5.getSources.call(player);
70
+
71
+                if (utils.is.empty(sources)) {
72
+                    return;
73
+                }
74
+
75
+                // Get matches for requested size
76
+                const matches = Array.from(sources).filter(source => Number(source.getAttribute('size')) === input);
77
+
78
+                // No matches for requested size
79
+                if (utils.is.empty(matches)) {
80
+                    return;
81
+                }
82
+
83
+                // Get supported sources
84
+                const supported = matches.filter(source => support.mime.call(player, source.getAttribute('type')));
85
+
86
+                // No supported sources
87
+                if (utils.is.empty(supported)) {
88
+                    return;
89
+                }
90
+
91
+                // Trigger change event
92
+                utils.dispatchEvent.call(player, player.media, 'qualityrequested', false, {
93
+                    quality: input,
94
+                });
95
+
96
+                // Get current state
97
+                const { currentTime, playing } = player;
98
+
99
+                // Set new source
100
+                player.media.src = supported[0].getAttribute('src');
101
+
102
+                // Load new source
103
+                player.media.load();
104
+
105
+                // Resume playing
106
+                if (playing) {
107
+                    player.play();
108
+                }
109
+
110
+                // Restore time
111
+                player.currentTime = currentTime;
112
+
113
+                // Trigger change event
114
+                utils.dispatchEvent.call(player, player.media, 'qualitychange', false, {
115
+                    quality: input,
116
+                });
117
+            },
118
+        });
119
+    },
120
+
121
+    // Cancel current network requests
122
+    // See https://github.com/sampotts/plyr/issues/174
123
+    cancelRequests() {
124
+        if (!this.isHTML5) {
125
+            return;
126
+        }
127
+
128
+        // Remove child sources
129
+        utils.removeElement(html5.getSources());
130
+
131
+        // Set blank video src attribute
132
+        // This is to prevent a MEDIA_ERR_SRC_NOT_SUPPORTED error
133
+        // Info: http://stackoverflow.com/questions/32231579/how-to-properly-dispose-of-an-html5-video-and-close-socket-or-connection
134
+        this.media.setAttribute('src', this.config.blankVideo);
135
+
136
+        // Load the new empty source
137
+        // This will cancel existing requests
138
+        // See https://github.com/sampotts/plyr/issues/174
139
+        this.media.load();
140
+
141
+        // Debugging
142
+        this.debug.log('Cancelled network requests');
143
+    },
144
+};
145
+
146
+export default html5;

+ 8
- 5
src/js/listeners.js View File

@@ -355,13 +355,16 @@ class Listeners {
355 355
             this.player.storage.set({ speed: this.player.speed });
356 356
         });
357 357
 
358
+        // Quality request
359
+        utils.on(this.player.media, 'qualityrequested', event => {
360
+            // Save to storage
361
+            this.player.storage.set({ quality: event.detail.quality });
362
+        });
363
+
358 364
         // Quality change
359
-        utils.on(this.player.media, 'qualitychange', () => {
365
+        utils.on(this.player.media, 'qualitychange', event => {
360 366
             // Update UI
361
-            controls.updateSetting.call(this.player, 'quality');
362
-
363
-            // Save to storage
364
-            this.player.storage.set({ quality: this.player.quality });
367
+            controls.updateSetting.call(this.player, 'quality', null, event.detail.quality);
365 368
         });
366 369
 
367 370
         // Caption language change

+ 2
- 23
src/js/media.js View File

@@ -6,6 +6,7 @@ import support from './support';
6 6
 import utils from './utils';
7 7
 import youtube from './plugins/youtube';
8 8
 import vimeo from './plugins/vimeo';
9
+import html5 from './html5';
9 10
 import ui from './ui';
10 11
 
11 12
 // Sniff out the browser
@@ -75,31 +76,9 @@ const media = {
75 76
             }
76 77
         } else if (this.isHTML5) {
77 78
             ui.setTitle.call(this);
78
-        }
79
-    },
80 79
 
81
-    // Cancel current network requests
82
-    // See https://github.com/sampotts/plyr/issues/174
83
-    cancelRequests() {
84
-        if (!this.isHTML5) {
85
-            return;
80
+            html5.extend.call(this);
86 81
         }
87
-
88
-        // Remove child sources
89
-        utils.removeElement(this.media.querySelectorAll('source'));
90
-
91
-        // Set blank video src attribute
92
-        // This is to prevent a MEDIA_ERR_SRC_NOT_SUPPORTED error
93
-        // Info: http://stackoverflow.com/questions/32231579/how-to-properly-dispose-of-an-html5-video-and-close-socket-or-connection
94
-        this.media.setAttribute('src', this.config.blankVideo);
95
-
96
-        // Load the new empty source
97
-        // This will cancel existing requests
98
-        // See https://github.com/sampotts/plyr/issues/174
99
-        this.media.load();
100
-
101
-        // Debugging
102
-        this.debug.log('Cancelled network requests');
103 82
     },
104 83
 };
105 84
 

+ 70
- 13
src/js/plugins/youtube.js View File

@@ -6,6 +6,64 @@ import utils from './../utils';
6 6
 import controls from './../controls';
7 7
 import ui from './../ui';
8 8
 
9
+// Standardise YouTube quality unit
10
+function mapQualityUnit(input) {
11
+    switch (input) {
12
+        case 'hd2160':
13
+            return 2160;
14
+
15
+        case 2160:
16
+            return 'hd2160';
17
+
18
+        case 'hd1440':
19
+            return 1440;
20
+
21
+        case 1440:
22
+            return 'hd1440';
23
+
24
+        case 'hd1080':
25
+            return 1080;
26
+
27
+        case 1080:
28
+            return 'hd1080';
29
+
30
+        case 'hd720':
31
+            return 720;
32
+
33
+        case 720:
34
+            return 'hd720';
35
+
36
+        case 'large':
37
+            return 480;
38
+
39
+        case 480:
40
+            return 'large';
41
+
42
+        case 'medium':
43
+            return 360;
44
+
45
+        case 360:
46
+            return 'medium';
47
+
48
+        case 'small':
49
+            return 240;
50
+
51
+        case 240:
52
+            return 'small';
53
+
54
+        default:
55
+            return 'default';
56
+    }
57
+}
58
+
59
+function mapQualityUnits(levels) {
60
+    if (utils.is.empty(levels)) {
61
+        return levels;
62
+    }
63
+
64
+    return utils.dedupe(levels.map(level => mapQualityUnit(level)));
65
+}
66
+
9 67
 const youtube = {
10 68
     setup() {
11 69
         // Add embed class for responsive
@@ -168,14 +226,10 @@ const youtube = {
168 226
 
169 227
                     utils.dispatchEvent.call(player, player.media, 'error');
170 228
                 },
171
-                onPlaybackQualityChange(event) {
172
-                    // Get the instance
173
-                    const instance = event.target;
174
-
175
-                    // Get current quality
176
-                    player.media.quality = instance.getPlaybackQuality();
177
-
178
-                    utils.dispatchEvent.call(player, player.media, 'qualitychange');
229
+                onPlaybackQualityChange() {
230
+                    utils.dispatchEvent.call(player, player.media, 'qualitychange', false, {
231
+                        quality: player.media.quality,
232
+                    });
179 233
                 },
180 234
                 onPlaybackRateChange(event) {
181 235
                     // Get the instance
@@ -240,15 +294,18 @@ const youtube = {
240 294
                     // Quality
241 295
                     Object.defineProperty(player.media, 'quality', {
242 296
                         get() {
243
-                            return instance.getPlaybackQuality();
297
+                            return mapQualityUnit(instance.getPlaybackQuality());
244 298
                         },
245 299
                         set(input) {
300
+                            const quality = input;
301
+
302
+                            // Set via API
303
+                            instance.setPlaybackQuality(mapQualityUnit(quality));
304
+
246 305
                             // Trigger request event
247 306
                             utils.dispatchEvent.call(player, player.media, 'qualityrequested', false, {
248
-                                quality: input,
307
+                                quality,
249 308
                             });
250
-
251
-                            instance.setPlaybackQuality(input);
252 309
                         },
253 310
                     });
254 311
 
@@ -401,7 +458,7 @@ const youtube = {
401 458
                             }
402 459
 
403 460
                             // Get quality
404
-                            controls.setQualityMenu.call(player, instance.getAvailableQualityLevels());
461
+                            controls.setQualityMenu.call(player, mapQualityUnits(instance.getAvailableQualityLevels()));
405 462
 
406 463
                             break;
407 464
 

+ 10
- 6
src/js/plyr.js View File

@@ -670,24 +670,28 @@ class Plyr {
670 670
 
671 671
     /**
672 672
      * Set playback quality
673
-     * Currently YouTube only
674
-     * @param {string} input - Quality level
673
+     * Currently HTML5 & YouTube only
674
+     * @param {number} input - Quality level
675 675
      */
676 676
     set quality(input) {
677 677
         let quality = null;
678 678
 
679
-        if (utils.is.string(input)) {
680
-            quality = input;
679
+        if (!utils.is.empty(input)) {
680
+            quality = Number(input);
681 681
         }
682 682
 
683
-        if (!utils.is.string(quality)) {
683
+        if (!utils.is.number(quality) || quality === 0) {
684 684
             quality = this.storage.get('quality');
685 685
         }
686 686
 
687
-        if (!utils.is.string(quality)) {
687
+        if (!utils.is.number(quality)) {
688 688
             quality = this.config.quality.selected;
689 689
         }
690 690
 
691
+        if (!utils.is.number(quality)) {
692
+            quality = this.config.quality.default;
693
+        }
694
+
691 695
         if (!this.options.quality.includes(quality)) {
692 696
             this.debug.warn(`Unsupported quality option (${quality})`);
693 697
             return;

+ 4
- 2
src/js/source.js View File

@@ -4,6 +4,7 @@
4 4
 
5 5
 import { providers } from './types';
6 6
 import utils from './utils';
7
+import html5 from './html5';
7 8
 import media from './media';
8 9
 import ui from './ui';
9 10
 import support from './support';
@@ -31,13 +32,14 @@ const source = {
31 32
         }
32 33
 
33 34
         // Cancel current network requests
34
-        media.cancelRequests.call(this);
35
+        html5.cancelRequests.call(this);
35 36
 
36 37
         // Destroy instance and re-setup
37 38
         this.destroy.call(
38 39
             this,
39 40
             () => {
40
-                // TODO: Reset menus here
41
+                // Reset quality options
42
+                this.options.quality = [];
41 43
 
42 44
                 // Remove elements
43 45
                 utils.removeElement(this.media);

+ 2
- 2
src/js/ui.js View File

@@ -71,8 +71,8 @@ const ui = {
71 71
         // Reset loop state
72 72
         this.loop = null;
73 73
 
74
-        // Reset quality options
75
-        this.options.quality = [];
74
+        // Reset quality setting
75
+        this.quality = null;
76 76
 
77 77
         // Reset volume display
78 78
         ui.updateVolume.call(this);

+ 12
- 3
src/js/utils.js View File

@@ -586,15 +586,15 @@ const utils = {
586 586
     },
587 587
 
588 588
     // Trigger event
589
-    dispatchEvent(element, type, bubbles, detail) {
589
+    dispatchEvent(element, type = '', bubbles = false, detail = {}) {
590 590
         // Bail if no element
591
-        if (!utils.is.element(element) || !utils.is.string(type)) {
591
+        if (!utils.is.element(element) || utils.is.empty(type)) {
592 592
             return;
593 593
         }
594 594
 
595 595
         // Create and dispatch the event
596 596
         const event = new CustomEvent(type, {
597
-            bubbles: utils.is.boolean(bubbles) ? bubbles : false,
597
+            bubbles,
598 598
             detail: Object.assign({}, detail, {
599 599
                 plyr: utils.is.plyr(this) ? this : null,
600 600
             }),
@@ -737,6 +737,15 @@ const utils = {
737 737
         return utils.extend(target, ...sources);
738 738
     },
739 739
 
740
+    // Remove duplicates in an array
741
+    dedupe(array) {
742
+        if (!utils.is.array(array)) {
743
+            return array;
744
+        }
745
+
746
+        return array.filter((item, index) => array.indexOf(item) === index);
747
+    },
748
+
740 749
     // Get the provider for a given URL
741 750
     getProviderByUrl(url) {
742 751
         // YouTube

+ 207
- 16
yarn.lock View File

@@ -8,6 +8,26 @@
8 8
   dependencies:
9 9
     "@babel/highlight" "7.0.0-beta.42"
10 10
 
11
+"@babel/core@^7.0.0-beta.42":
12
+  version "7.0.0-beta.42"
13
+  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.0.0-beta.42.tgz#b3a838fddbd19663369a0b4892189fd8d3f82001"
14
+  dependencies:
15
+    "@babel/code-frame" "7.0.0-beta.42"
16
+    "@babel/generator" "7.0.0-beta.42"
17
+    "@babel/helpers" "7.0.0-beta.42"
18
+    "@babel/template" "7.0.0-beta.42"
19
+    "@babel/traverse" "7.0.0-beta.42"
20
+    "@babel/types" "7.0.0-beta.42"
21
+    babylon "7.0.0-beta.42"
22
+    convert-source-map "^1.1.0"
23
+    debug "^3.1.0"
24
+    json5 "^0.5.0"
25
+    lodash "^4.2.0"
26
+    micromatch "^2.3.11"
27
+    resolve "^1.3.2"
28
+    semver "^5.4.1"
29
+    source-map "^0.5.0"
30
+
11 31
 "@babel/generator@7.0.0-beta.42":
12 32
   version "7.0.0-beta.42"
13 33
   resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.42.tgz#777bb50f39c94a7e57f73202d833141f8159af33"
@@ -38,6 +58,14 @@
38 58
   dependencies:
39 59
     "@babel/types" "7.0.0-beta.42"
40 60
 
61
+"@babel/helpers@7.0.0-beta.42":
62
+  version "7.0.0-beta.42"
63
+  resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.0.0-beta.42.tgz#151c1c4e9da1b6ce83d54c1be5fb8c9c57aa5044"
64
+  dependencies:
65
+    "@babel/template" "7.0.0-beta.42"
66
+    "@babel/traverse" "7.0.0-beta.42"
67
+    "@babel/types" "7.0.0-beta.42"
68
+
41 69
 "@babel/highlight@7.0.0-beta.42":
42 70
   version "7.0.0-beta.42"
43 71
   resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.42.tgz#a502a1c0d6f99b2b0e81d468a1b0c0e81e3f3623"
@@ -55,7 +83,7 @@
55 83
     babylon "7.0.0-beta.42"
56 84
     lodash "^4.2.0"
57 85
 
58
-"@babel/traverse@^7.0.0-beta.40":
86
+"@babel/traverse@7.0.0-beta.42", "@babel/traverse@^7.0.0-beta.40", "@babel/traverse@^7.0.0-beta.42":
59 87
   version "7.0.0-beta.42"
60 88
   resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.42.tgz#f4bf4d1e33d41baf45205e2d0463591d57326285"
61 89
   dependencies:
@@ -95,6 +123,13 @@
95 123
     normalize-path "^2.0.1"
96 124
     through2 "^2.0.3"
97 125
 
126
+"@mrmlnc/readdir-enhanced@^2.2.1":
127
+  version "2.2.1"
128
+  resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"
129
+  dependencies:
130
+    call-me-maybe "^1.0.1"
131
+    glob-to-regexp "^0.3.0"
132
+
98 133
 abbrev@1:
99 134
   version "1.1.1"
100 135
   resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
@@ -853,7 +888,7 @@ babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0:
853 888
     lodash "^4.17.4"
854 889
     to-fast-properties "^1.0.3"
855 890
 
856
-babylon@7.0.0-beta.42, babylon@^7.0.0-beta.40:
891
+babylon@7.0.0-beta.42, babylon@^7.0.0-beta.40, babylon@^7.0.0-beta.42:
857 892
   version "7.0.0-beta.42"
858 893
   resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.42.tgz#67cfabcd4f3ec82999d29031ccdea89d0ba99657"
859 894
 
@@ -1003,6 +1038,10 @@ cache-base@^1.0.1:
1003 1038
     union-value "^1.0.0"
1004 1039
     unset-value "^1.0.0"
1005 1040
 
1041
+call-me-maybe@^1.0.1:
1042
+  version "1.0.1"
1043
+  resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b"
1044
+
1006 1045
 caller-path@^0.1.0:
1007 1046
   version "0.1.0"
1008 1047
   resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f"
@@ -1323,7 +1362,7 @@ contains-path@^0.1.0:
1323 1362
   version "0.1.0"
1324 1363
   resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a"
1325 1364
 
1326
-convert-source-map@1.X, convert-source-map@^1.5.0:
1365
+convert-source-map@1.X, convert-source-map@^1.1.0, convert-source-map@^1.5.0:
1327 1366
   version "1.5.1"
1328 1367
   resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5"
1329 1368
 
@@ -1738,23 +1777,23 @@ eslint-import-resolver-node@^0.3.1:
1738 1777
     debug "^2.6.9"
1739 1778
     resolve "^1.5.0"
1740 1779
 
1741
-eslint-module-utils@^2.1.1:
1742
-  version "2.1.1"
1743
-  resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.1.1.tgz#abaec824177613b8a95b299639e1b6facf473449"
1780
+eslint-module-utils@^2.2.0:
1781
+  version "2.2.0"
1782
+  resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz#b270362cd88b1a48ad308976ce7fa54e98411746"
1744 1783
   dependencies:
1745 1784
     debug "^2.6.8"
1746 1785
     pkg-dir "^1.0.0"
1747 1786
 
1748
-eslint-plugin-import@^2.9.0:
1749
-  version "2.9.0"
1750
-  resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.9.0.tgz#26002efbfca5989b7288ac047508bd24f217b169"
1787
+eslint-plugin-import@^2.10.0:
1788
+  version "2.10.0"
1789
+  resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.10.0.tgz#fa09083d5a75288df9c6c7d09fe12255985655e7"
1751 1790
   dependencies:
1752 1791
     builtin-modules "^1.1.1"
1753 1792
     contains-path "^0.1.0"
1754 1793
     debug "^2.6.8"
1755 1794
     doctrine "1.5.0"
1756 1795
     eslint-import-resolver-node "^0.3.1"
1757
-    eslint-module-utils "^2.1.1"
1796
+    eslint-module-utils "^2.2.0"
1758 1797
     has "^1.0.1"
1759 1798
     lodash "^4.17.4"
1760 1799
     minimatch "^3.0.3"
@@ -2045,6 +2084,16 @@ fast-deep-equal@^1.0.0:
2045 2084
   version "1.1.0"
2046 2085
   resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614"
2047 2086
 
2087
+fast-glob@^2.0.2:
2088
+  version "2.2.0"
2089
+  resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.0.tgz#e9d032a69b86bef46fc03d935408f02fb211d9fc"
2090
+  dependencies:
2091
+    "@mrmlnc/readdir-enhanced" "^2.2.1"
2092
+    glob-parent "^3.1.0"
2093
+    is-glob "^4.0.0"
2094
+    merge2 "^1.2.1"
2095
+    micromatch "^3.1.8"
2096
+
2048 2097
 fast-json-stable-stringify@^2.0.0:
2049 2098
   version "2.0.0"
2050 2099
   resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
@@ -2256,6 +2305,10 @@ get-stdin@^5.0.1:
2256 2305
   version "5.0.1"
2257 2306
   resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398"
2258 2307
 
2308
+get-stdin@^6.0.0:
2309
+  version "6.0.0"
2310
+  resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b"
2311
+
2259 2312
 get-stream@^3.0.0:
2260 2313
   version "3.0.0"
2261 2314
   resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
@@ -2289,6 +2342,13 @@ glob-parent@^2.0.0:
2289 2342
   dependencies:
2290 2343
     is-glob "^2.0.0"
2291 2344
 
2345
+glob-parent@^3.1.0:
2346
+  version "3.1.0"
2347
+  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
2348
+  dependencies:
2349
+    is-glob "^3.1.0"
2350
+    path-dirname "^1.0.0"
2351
+
2292 2352
 glob-stream@^3.1.5:
2293 2353
   version "3.1.18"
2294 2354
   resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-3.1.18.tgz#9170a5f12b790306fdfe598f313f8f7954fd143b"
@@ -2300,6 +2360,10 @@ glob-stream@^3.1.5:
2300 2360
     through2 "^0.6.1"
2301 2361
     unique-stream "^1.0.0"
2302 2362
 
2363
+glob-to-regexp@^0.3.0:
2364
+  version "0.3.0"
2365
+  resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
2366
+
2303 2367
 glob-watcher@^0.0.6:
2304 2368
   version "0.0.6"
2305 2369
   resolved "https://registry.yarnpkg.com/glob-watcher/-/glob-watcher-0.0.6.tgz#b95b4a8df74b39c83298b0c05c978b4d9a3b710b"
@@ -2414,6 +2478,18 @@ globby@^7.0.0:
2414 2478
     pify "^3.0.0"
2415 2479
     slash "^1.0.0"
2416 2480
 
2481
+globby@^8.0.0:
2482
+  version "8.0.1"
2483
+  resolved "https://registry.yarnpkg.com/globby/-/globby-8.0.1.tgz#b5ad48b8aa80b35b814fc1281ecc851f1d2b5b50"
2484
+  dependencies:
2485
+    array-union "^1.0.1"
2486
+    dir-glob "^2.0.0"
2487
+    fast-glob "^2.0.2"
2488
+    glob "^7.1.2"
2489
+    ignore "^3.3.5"
2490
+    pify "^3.0.0"
2491
+    slash "^1.0.0"
2492
+
2417 2493
 globjoin@^0.1.4:
2418 2494
   version "0.1.4"
2419 2495
   resolved "https://registry.yarnpkg.com/globjoin/-/globjoin-0.1.4.tgz#2f4494ac8919e3767c5cbb691e9f463324285d43"
@@ -2853,6 +2929,10 @@ import-lazy@^2.1.0:
2853 2929
   version "2.1.0"
2854 2930
   resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43"
2855 2931
 
2932
+import-lazy@^3.1.0:
2933
+  version "3.1.0"
2934
+  resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-3.1.0.tgz#891279202c8a2280fdbd6674dbd8da1a1dfc67cc"
2935
+
2856 2936
 import-local@^0.1.1:
2857 2937
   version "0.1.1"
2858 2938
   resolved "https://registry.yarnpkg.com/import-local/-/import-local-0.1.1.tgz#b1179572aacdc11c6a91009fb430dbcab5f668a8"
@@ -3042,7 +3122,7 @@ is-extglob@^1.0.0:
3042 3122
   version "1.0.0"
3043 3123
   resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
3044 3124
 
3045
-is-extglob@^2.1.0:
3125
+is-extglob@^2.1.0, is-extglob@^2.1.1:
3046 3126
   version "2.1.1"
3047 3127
   resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
3048 3128
 
@@ -3074,6 +3154,12 @@ is-glob@^3.1.0:
3074 3154
   dependencies:
3075 3155
     is-extglob "^2.1.0"
3076 3156
 
3157
+is-glob@^4.0.0:
3158
+  version "4.0.0"
3159
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0"
3160
+  dependencies:
3161
+    is-extglob "^2.1.1"
3162
+
3077 3163
 is-hexadecimal@^1.0.0:
3078 3164
   version "1.0.1"
3079 3165
   resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.1.tgz#6e084bbc92061fbb0971ec58b6ce6d404e24da69"
@@ -3326,7 +3412,7 @@ json-stringify-safe@~5.0.1:
3326 3412
   version "5.0.1"
3327 3413
   resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
3328 3414
 
3329
-json5@^0.5.1:
3415
+json5@^0.5.0, json5@^0.5.1:
3330 3416
   version "0.5.1"
3331 3417
   resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
3332 3418
 
@@ -3864,6 +3950,10 @@ meow@^4.0.0:
3864 3950
     redent "^2.0.0"
3865 3951
     trim-newlines "^2.0.0"
3866 3952
 
3953
+merge2@^1.2.1:
3954
+  version "1.2.1"
3955
+  resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.1.tgz#271d2516ff52d4af7f7b710b8bf3e16e183fef66"
3956
+
3867 3957
 micromatch@^2.3.11:
3868 3958
   version "2.3.11"
3869 3959
   resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
@@ -3900,6 +3990,24 @@ micromatch@^3.0.4:
3900 3990
     snapdragon "^0.8.1"
3901 3991
     to-regex "^3.0.1"
3902 3992
 
3993
+micromatch@^3.1.8:
3994
+  version "3.1.10"
3995
+  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
3996
+  dependencies:
3997
+    arr-diff "^4.0.0"
3998
+    array-unique "^0.3.2"
3999
+    braces "^2.3.1"
4000
+    define-property "^2.0.2"
4001
+    extend-shallow "^3.0.2"
4002
+    extglob "^2.0.4"
4003
+    fragment-cache "^0.2.1"
4004
+    kind-of "^6.0.2"
4005
+    nanomatch "^1.2.9"
4006
+    object.pick "^1.3.0"
4007
+    regex-not "^1.0.0"
4008
+    snapdragon "^0.8.1"
4009
+    to-regex "^3.0.2"
4010
+
3903 4011
 mime-db@~1.33.0:
3904 4012
   version "1.33.0"
3905 4013
   resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db"
@@ -4348,6 +4456,10 @@ pascalcase@^0.1.1:
4348 4456
   version "0.1.1"
4349 4457
   resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
4350 4458
 
4459
+path-dirname@^1.0.0:
4460
+  version "1.0.2"
4461
+  resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
4462
+
4351 4463
 path-exists@^2.0.0:
4352 4464
   version "2.1.0"
4353 4465
   resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
@@ -4502,12 +4614,29 @@ postcss-html@^0.15.0:
4502 4614
     remark "^9.0.0"
4503 4615
     unist-util-find-all-after "^1.0.1"
4504 4616
 
4617
+postcss-html@^0.18.0:
4618
+  version "0.18.0"
4619
+  resolved "https://registry.yarnpkg.com/postcss-html/-/postcss-html-0.18.0.tgz#992a84117cc56f9f28915fbadba576489641e652"
4620
+  dependencies:
4621
+    "@babel/core" "^7.0.0-beta.42"
4622
+    "@babel/traverse" "^7.0.0-beta.42"
4623
+    babylon "^7.0.0-beta.42"
4624
+    htmlparser2 "^3.9.2"
4625
+    remark "^9.0.0"
4626
+    unist-util-find-all-after "^1.0.1"
4627
+
4505 4628
 postcss-less@^1.1.0:
4506 4629
   version "1.1.3"
4507 4630
   resolved "https://registry.yarnpkg.com/postcss-less/-/postcss-less-1.1.3.tgz#6930525271bfe38d5793d33ac09c1a546b87bb51"
4508 4631
   dependencies:
4509 4632
     postcss "^5.2.16"
4510 4633
 
4634
+postcss-less@^1.1.5:
4635
+  version "1.1.5"
4636
+  resolved "https://registry.yarnpkg.com/postcss-less/-/postcss-less-1.1.5.tgz#a6f0ce180cf3797eeee1d4adc0e9e6d6db665609"
4637
+  dependencies:
4638
+    postcss "^5.2.16"
4639
+
4511 4640
 postcss-media-query-parser@^0.2.3:
4512 4641
   version "0.2.3"
4513 4642
   resolved "https://registry.yarnpkg.com/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz#27b39c6f4d94f81b1a73b8f76351c609e5cef244"
@@ -5119,6 +5248,12 @@ resolve@^1.1.6, resolve@^1.1.7, resolve@^1.5.0:
5119 5248
   dependencies:
5120 5249
     path-parse "^1.0.5"
5121 5250
 
5251
+resolve@^1.3.2:
5252
+  version "1.6.0"
5253
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.6.0.tgz#0fbd21278b27b4004481c395349e7aba60a9ff5c"
5254
+  dependencies:
5255
+    path-parse "^1.0.5"
5256
+
5122 5257
 restore-cursor@^2.0.0:
5123 5258
   version "2.0.0"
5124 5259
   resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
@@ -5237,7 +5372,7 @@ semver-diff@^2.0.0:
5237 5372
   dependencies:
5238 5373
     semver "^5.0.3"
5239 5374
 
5240
-"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0:
5375
+"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1:
5241 5376
   version "5.5.0"
5242 5377
   resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
5243 5378
 
@@ -5620,7 +5755,7 @@ stylelint-order@^0.8.0, stylelint-order@^0.8.1:
5620 5755
     postcss "^6.0.14"
5621 5756
     postcss-sorting "^3.1.0"
5622 5757
 
5623
-stylelint-scss@^2.0.0, stylelint-scss@^2.5.0:
5758
+stylelint-scss@^2.0.0:
5624 5759
   version "2.5.0"
5625 5760
   resolved "https://registry.yarnpkg.com/stylelint-scss/-/stylelint-scss-2.5.0.tgz#ac4c83474c53b19cc1f9e93d332786cf89c8d217"
5626 5761
   dependencies:
@@ -5630,6 +5765,16 @@ stylelint-scss@^2.0.0, stylelint-scss@^2.5.0:
5630 5765
     postcss-selector-parser "^3.1.1"
5631 5766
     postcss-value-parser "^3.3.0"
5632 5767
 
5768
+stylelint-scss@^3.0.0:
5769
+  version "3.0.0"
5770
+  resolved "https://registry.yarnpkg.com/stylelint-scss/-/stylelint-scss-3.0.0.tgz#15beb887117ccef20668a3f4728eb5be5fbda045"
5771
+  dependencies:
5772
+    lodash "^4.17.4"
5773
+    postcss-media-query-parser "^0.2.3"
5774
+    postcss-resolve-nested-selector "^0.1.1"
5775
+    postcss-selector-parser "^3.1.1"
5776
+    postcss-value-parser "^3.3.0"
5777
+
5633 5778
 stylelint-selector-bem-pattern@^2.0.0:
5634 5779
   version "2.0.0"
5635 5780
   resolved "https://registry.yarnpkg.com/stylelint-selector-bem-pattern/-/stylelint-selector-bem-pattern-2.0.0.tgz#9a6130c9c90963b30e925c917079d6c8fed73f45"
@@ -5639,7 +5784,7 @@ stylelint-selector-bem-pattern@^2.0.0:
5639 5784
     postcss-bem-linter "^3.0.0"
5640 5785
     stylelint ">=3.0.2"
5641 5786
 
5642
-stylelint@>=3.0.2, stylelint@^9.1.1, stylelint@^9.1.3:
5787
+stylelint@>=3.0.2, stylelint@^9.1.1:
5643 5788
   version "9.1.3"
5644 5789
   resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-9.1.3.tgz#8260f2a221b98e4afafd9b2b8a785d2e38cbb8a4"
5645 5790
   dependencies:
@@ -5728,6 +5873,52 @@ stylelint@^8.1.1:
5728 5873
     svg-tags "^1.0.0"
5729 5874
     table "^4.0.1"
5730 5875
 
5876
+stylelint@^9.2.0:
5877
+  version "9.2.0"
5878
+  resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-9.2.0.tgz#f77a82518106074c1a795e962fd780da2c8af43b"
5879
+  dependencies:
5880
+    autoprefixer "^8.0.0"
5881
+    balanced-match "^1.0.0"
5882
+    chalk "^2.0.1"
5883
+    cosmiconfig "^4.0.0"
5884
+    debug "^3.0.0"
5885
+    execall "^1.0.0"
5886
+    file-entry-cache "^2.0.0"
5887
+    get-stdin "^6.0.0"
5888
+    globby "^8.0.0"
5889
+    globjoin "^0.1.4"
5890
+    html-tags "^2.0.0"
5891
+    ignore "^3.3.3"
5892
+    import-lazy "^3.1.0"
5893
+    imurmurhash "^0.1.4"
5894
+    known-css-properties "^0.6.0"
5895
+    lodash "^4.17.4"
5896
+    log-symbols "^2.0.0"
5897
+    mathml-tag-names "^2.0.1"
5898
+    meow "^4.0.0"
5899
+    micromatch "^2.3.11"
5900
+    normalize-selector "^0.2.0"
5901
+    pify "^3.0.0"
5902
+    postcss "^6.0.16"
5903
+    postcss-html "^0.18.0"
5904
+    postcss-less "^1.1.5"
5905
+    postcss-media-query-parser "^0.2.3"
5906
+    postcss-reporter "^5.0.0"
5907
+    postcss-resolve-nested-selector "^0.1.1"
5908
+    postcss-safe-parser "^3.0.1"
5909
+    postcss-sass "^0.3.0"
5910
+    postcss-scss "^1.0.2"
5911
+    postcss-selector-parser "^3.1.0"
5912
+    postcss-value-parser "^3.3.0"
5913
+    resolve-from "^4.0.0"
5914
+    signal-exit "^3.0.2"
5915
+    specificity "^0.3.1"
5916
+    string-width "^2.1.0"
5917
+    style-search "^0.1.0"
5918
+    sugarss "^1.0.0"
5919
+    svg-tags "^1.0.0"
5920
+    table "^4.0.1"
5921
+
5731 5922
 sugarss@^1.0.0:
5732 5923
   version "1.0.1"
5733 5924
   resolved "https://registry.yarnpkg.com/sugarss/-/sugarss-1.0.1.tgz#be826d9003e0f247735f92365dc3fd7f1bae9e44"
@@ -5909,7 +6100,7 @@ to-regex-range@^2.1.0:
5909 6100
     is-number "^3.0.0"
5910 6101
     repeat-string "^1.6.1"
5911 6102
 
5912
-to-regex@^3.0.1:
6103
+to-regex@^3.0.1, to-regex@^3.0.2:
5913 6104
   version "3.0.2"
5914 6105
   resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
5915 6106
   dependencies: