gradient.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. "use strict";
  2. function _defaults(obj, defaults) { var keys = Object.getOwnPropertyNames(defaults); for (var i = 0; i < keys.length; i++) { var key = keys[i]; var value = Object.getOwnPropertyDescriptor(defaults, key); if (value && value.configurable && obj[key] === undefined) { Object.defineProperty(obj, key, value); } } return obj; }
  3. function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _defaults(subClass, superClass); }
  4. function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
  5. function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
  6. var OldValue = require('../old-value');
  7. var Value = require('../value');
  8. var utils = require('../utils');
  9. var parser = require('postcss-value-parser');
  10. var range = require('normalize-range');
  11. var IS_DIRECTION = /top|left|right|bottom/gi;
  12. var Gradient =
  13. /*#__PURE__*/
  14. function (_Value) {
  15. _inheritsLoose(Gradient, _Value);
  16. function Gradient() {
  17. var _this;
  18. for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
  19. args[_key] = arguments[_key];
  20. }
  21. _this = _Value.call.apply(_Value, [this].concat(args)) || this;
  22. _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "directions", {
  23. top: 'bottom',
  24. left: 'right',
  25. bottom: 'top',
  26. right: 'left' // Direction to replace
  27. });
  28. _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "oldDirections", {
  29. 'top': 'left bottom, left top',
  30. 'left': 'right top, left top',
  31. 'bottom': 'left top, left bottom',
  32. 'right': 'left top, right top',
  33. 'top right': 'left bottom, right top',
  34. 'top left': 'right bottom, left top',
  35. 'right top': 'left bottom, right top',
  36. 'right bottom': 'left top, right bottom',
  37. 'bottom right': 'left top, right bottom',
  38. 'bottom left': 'right top, left bottom',
  39. 'left top': 'right bottom, left top',
  40. 'left bottom': 'right top, left bottom'
  41. /**
  42. * Change degrees for webkit prefix
  43. */
  44. });
  45. return _this;
  46. }
  47. var _proto = Gradient.prototype;
  48. _proto.replace = function replace(string, prefix) {
  49. var ast = parser(string);
  50. for (var _iterator = ast.nodes, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
  51. var _ref;
  52. if (_isArray) {
  53. if (_i >= _iterator.length) break;
  54. _ref = _iterator[_i++];
  55. } else {
  56. _i = _iterator.next();
  57. if (_i.done) break;
  58. _ref = _i.value;
  59. }
  60. var node = _ref;
  61. if (node.type === 'function' && node.value === this.name) {
  62. node.nodes = this.newDirection(node.nodes);
  63. node.nodes = this.normalize(node.nodes);
  64. if (prefix === '-webkit- old') {
  65. var changes = this.oldWebkit(node);
  66. if (!changes) {
  67. return false;
  68. }
  69. } else {
  70. node.nodes = this.convertDirection(node.nodes);
  71. node.value = prefix + node.value;
  72. }
  73. }
  74. }
  75. return ast.toString();
  76. }
  77. /**
  78. * Replace first token
  79. */
  80. ;
  81. _proto.replaceFirst = function replaceFirst(params) {
  82. for (var _len2 = arguments.length, words = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
  83. words[_key2 - 1] = arguments[_key2];
  84. }
  85. var prefix = words.map(function (i) {
  86. if (i === ' ') {
  87. return {
  88. type: 'space',
  89. value: i
  90. };
  91. }
  92. return {
  93. type: 'word',
  94. value: i
  95. };
  96. });
  97. return prefix.concat(params.slice(1));
  98. }
  99. /**
  100. * Convert angle unit to deg
  101. */
  102. ;
  103. _proto.normalizeUnit = function normalizeUnit(str, full) {
  104. var num = parseFloat(str);
  105. var deg = num / full * 360;
  106. return deg + "deg";
  107. }
  108. /**
  109. * Normalize angle
  110. */
  111. ;
  112. _proto.normalize = function normalize(nodes) {
  113. if (!nodes[0]) return nodes;
  114. if (/-?\d+(.\d+)?grad/.test(nodes[0].value)) {
  115. nodes[0].value = this.normalizeUnit(nodes[0].value, 400);
  116. } else if (/-?\d+(.\d+)?rad/.test(nodes[0].value)) {
  117. nodes[0].value = this.normalizeUnit(nodes[0].value, 2 * Math.PI);
  118. } else if (/-?\d+(.\d+)?turn/.test(nodes[0].value)) {
  119. nodes[0].value = this.normalizeUnit(nodes[0].value, 1);
  120. } else if (nodes[0].value.indexOf('deg') !== -1) {
  121. var num = parseFloat(nodes[0].value);
  122. num = range.wrap(0, 360, num);
  123. nodes[0].value = num + "deg";
  124. }
  125. if (nodes[0].value === '0deg') {
  126. nodes = this.replaceFirst(nodes, 'to', ' ', 'top');
  127. } else if (nodes[0].value === '90deg') {
  128. nodes = this.replaceFirst(nodes, 'to', ' ', 'right');
  129. } else if (nodes[0].value === '180deg') {
  130. nodes = this.replaceFirst(nodes, 'to', ' ', 'bottom');
  131. } else if (nodes[0].value === '270deg') {
  132. nodes = this.replaceFirst(nodes, 'to', ' ', 'left');
  133. }
  134. return nodes;
  135. }
  136. /**
  137. * Replace old direction to new
  138. */
  139. ;
  140. _proto.newDirection = function newDirection(params) {
  141. if (params[0].value === 'to') {
  142. return params;
  143. }
  144. IS_DIRECTION.lastIndex = 0; // reset search index of global regexp
  145. if (!IS_DIRECTION.test(params[0].value)) {
  146. return params;
  147. }
  148. params.unshift({
  149. type: 'word',
  150. value: 'to'
  151. }, {
  152. type: 'space',
  153. value: ' '
  154. });
  155. for (var i = 2; i < params.length; i++) {
  156. if (params[i].type === 'div') {
  157. break;
  158. }
  159. if (params[i].type === 'word') {
  160. params[i].value = this.revertDirection(params[i].value);
  161. }
  162. }
  163. return params;
  164. }
  165. /**
  166. * Look for at word
  167. */
  168. ;
  169. _proto.isRadial = function isRadial(params) {
  170. var state = 'before';
  171. for (var _iterator2 = params, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) {
  172. var _ref2;
  173. if (_isArray2) {
  174. if (_i2 >= _iterator2.length) break;
  175. _ref2 = _iterator2[_i2++];
  176. } else {
  177. _i2 = _iterator2.next();
  178. if (_i2.done) break;
  179. _ref2 = _i2.value;
  180. }
  181. var param = _ref2;
  182. if (state === 'before' && param.type === 'space') {
  183. state = 'at';
  184. } else if (state === 'at' && param.value === 'at') {
  185. state = 'after';
  186. } else if (state === 'after' && param.type === 'space') {
  187. return true;
  188. } else if (param.type === 'div') {
  189. break;
  190. } else {
  191. state = 'before';
  192. }
  193. }
  194. return false;
  195. }
  196. /**
  197. * Change new direction to old
  198. */
  199. ;
  200. _proto.convertDirection = function convertDirection(params) {
  201. if (params.length > 0) {
  202. if (params[0].value === 'to') {
  203. this.fixDirection(params);
  204. } else if (params[0].value.indexOf('deg') !== -1) {
  205. this.fixAngle(params);
  206. } else if (this.isRadial(params)) {
  207. this.fixRadial(params);
  208. }
  209. }
  210. return params;
  211. }
  212. /**
  213. * Replace `to top left` to `bottom right`
  214. */
  215. ;
  216. _proto.fixDirection = function fixDirection(params) {
  217. params.splice(0, 2);
  218. for (var _iterator3 = params, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) {
  219. var _ref3;
  220. if (_isArray3) {
  221. if (_i3 >= _iterator3.length) break;
  222. _ref3 = _iterator3[_i3++];
  223. } else {
  224. _i3 = _iterator3.next();
  225. if (_i3.done) break;
  226. _ref3 = _i3.value;
  227. }
  228. var param = _ref3;
  229. if (param.type === 'div') {
  230. break;
  231. }
  232. if (param.type === 'word') {
  233. param.value = this.revertDirection(param.value);
  234. }
  235. }
  236. }
  237. /**
  238. * Add 90 degrees
  239. */
  240. ;
  241. _proto.fixAngle = function fixAngle(params) {
  242. var first = params[0].value;
  243. first = parseFloat(first);
  244. first = Math.abs(450 - first) % 360;
  245. first = this.roundFloat(first, 3);
  246. params[0].value = first + "deg";
  247. }
  248. /**
  249. * Fix radial direction syntax
  250. */
  251. ;
  252. _proto.fixRadial = function fixRadial(params) {
  253. var first = [];
  254. var second = [];
  255. var a, b, c, i, next;
  256. for (i = 0; i < params.length - 2; i++) {
  257. a = params[i];
  258. b = params[i + 1];
  259. c = params[i + 2];
  260. if (a.type === 'space' && b.value === 'at' && c.type === 'space') {
  261. next = i + 3;
  262. break;
  263. } else {
  264. first.push(a);
  265. }
  266. }
  267. var div;
  268. for (i = next; i < params.length; i++) {
  269. if (params[i].type === 'div') {
  270. div = params[i];
  271. break;
  272. } else {
  273. second.push(params[i]);
  274. }
  275. }
  276. params.splice.apply(params, [0, i].concat(second, [div], first));
  277. };
  278. _proto.revertDirection = function revertDirection(word) {
  279. return this.directions[word.toLowerCase()] || word;
  280. }
  281. /**
  282. * Round float and save digits under dot
  283. */
  284. ;
  285. _proto.roundFloat = function roundFloat(float, digits) {
  286. return parseFloat(float.toFixed(digits));
  287. }
  288. /**
  289. * Convert to old webkit syntax
  290. */
  291. ;
  292. _proto.oldWebkit = function oldWebkit(node) {
  293. var nodes = node.nodes;
  294. var string = parser.stringify(node.nodes);
  295. if (this.name !== 'linear-gradient') {
  296. return false;
  297. }
  298. if (nodes[0] && nodes[0].value.indexOf('deg') !== -1) {
  299. return false;
  300. }
  301. if (string.indexOf('px') !== -1 || string.indexOf('-corner') !== -1 || string.indexOf('-side') !== -1) {
  302. return false;
  303. }
  304. var params = [[]];
  305. for (var _iterator4 = nodes, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) {
  306. var _ref4;
  307. if (_isArray4) {
  308. if (_i4 >= _iterator4.length) break;
  309. _ref4 = _iterator4[_i4++];
  310. } else {
  311. _i4 = _iterator4.next();
  312. if (_i4.done) break;
  313. _ref4 = _i4.value;
  314. }
  315. var i = _ref4;
  316. params[params.length - 1].push(i);
  317. if (i.type === 'div' && i.value === ',') {
  318. params.push([]);
  319. }
  320. }
  321. this.oldDirection(params);
  322. this.colorStops(params);
  323. node.nodes = [];
  324. for (var _i5 = 0; _i5 < params.length; _i5++) {
  325. var param = params[_i5];
  326. node.nodes = node.nodes.concat(param);
  327. }
  328. node.nodes.unshift({
  329. type: 'word',
  330. value: 'linear'
  331. }, this.cloneDiv(node.nodes));
  332. node.value = '-webkit-gradient';
  333. return true;
  334. }
  335. /**
  336. * Change direction syntax to old webkit
  337. */
  338. ;
  339. _proto.oldDirection = function oldDirection(params) {
  340. var div = this.cloneDiv(params[0]);
  341. if (params[0][0].value !== 'to') {
  342. return params.unshift([{
  343. type: 'word',
  344. value: this.oldDirections.bottom
  345. }, div]);
  346. } else {
  347. var words = [];
  348. for (var _iterator5 = params[0].slice(2), _isArray5 = Array.isArray(_iterator5), _i6 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) {
  349. var _ref5;
  350. if (_isArray5) {
  351. if (_i6 >= _iterator5.length) break;
  352. _ref5 = _iterator5[_i6++];
  353. } else {
  354. _i6 = _iterator5.next();
  355. if (_i6.done) break;
  356. _ref5 = _i6.value;
  357. }
  358. var node = _ref5;
  359. if (node.type === 'word') {
  360. words.push(node.value.toLowerCase());
  361. }
  362. }
  363. words = words.join(' ');
  364. var old = this.oldDirections[words] || words;
  365. params[0] = [{
  366. type: 'word',
  367. value: old
  368. }, div];
  369. return params[0];
  370. }
  371. }
  372. /**
  373. * Get div token from exists parameters
  374. */
  375. ;
  376. _proto.cloneDiv = function cloneDiv(params) {
  377. for (var _iterator6 = params, _isArray6 = Array.isArray(_iterator6), _i7 = 0, _iterator6 = _isArray6 ? _iterator6 : _iterator6[Symbol.iterator]();;) {
  378. var _ref6;
  379. if (_isArray6) {
  380. if (_i7 >= _iterator6.length) break;
  381. _ref6 = _iterator6[_i7++];
  382. } else {
  383. _i7 = _iterator6.next();
  384. if (_i7.done) break;
  385. _ref6 = _i7.value;
  386. }
  387. var i = _ref6;
  388. if (i.type === 'div' && i.value === ',') {
  389. return i;
  390. }
  391. }
  392. return {
  393. type: 'div',
  394. value: ',',
  395. after: ' '
  396. };
  397. }
  398. /**
  399. * Change colors syntax to old webkit
  400. */
  401. ;
  402. _proto.colorStops = function colorStops(params) {
  403. var result = [];
  404. for (var i = 0; i < params.length; i++) {
  405. var pos = void 0;
  406. var param = params[i];
  407. var item = void 0;
  408. if (i === 0) {
  409. continue;
  410. }
  411. var color = parser.stringify(param[0]);
  412. if (param[1] && param[1].type === 'word') {
  413. pos = param[1].value;
  414. } else if (param[2] && param[2].type === 'word') {
  415. pos = param[2].value;
  416. }
  417. var stop = void 0;
  418. if (i === 1 && (!pos || pos === '0%')) {
  419. stop = "from(" + color + ")";
  420. } else if (i === params.length - 1 && (!pos || pos === '100%')) {
  421. stop = "to(" + color + ")";
  422. } else if (pos) {
  423. stop = "color-stop(" + pos + ", " + color + ")";
  424. } else {
  425. stop = "color-stop(" + color + ")";
  426. }
  427. var div = param[param.length - 1];
  428. params[i] = [{
  429. type: 'word',
  430. value: stop
  431. }];
  432. if (div.type === 'div' && div.value === ',') {
  433. item = params[i].push(div);
  434. }
  435. result.push(item);
  436. }
  437. return result;
  438. }
  439. /**
  440. * Remove old WebKit gradient too
  441. */
  442. ;
  443. _proto.old = function old(prefix) {
  444. if (prefix === '-webkit-') {
  445. var type = this.name === 'linear-gradient' ? 'linear' : 'radial';
  446. var string = '-gradient';
  447. var regexp = utils.regexp("-webkit-(" + type + "-gradient|gradient\\(\\s*" + type + ")", false);
  448. return new OldValue(this.name, prefix + this.name, string, regexp);
  449. } else {
  450. return _Value.prototype.old.call(this, prefix);
  451. }
  452. }
  453. /**
  454. * Do not add non-webkit prefixes for list-style and object
  455. */
  456. ;
  457. _proto.add = function add(decl, prefix) {
  458. var p = decl.prop;
  459. if (p.indexOf('mask') !== -1) {
  460. if (prefix === '-webkit-' || prefix === '-webkit- old') {
  461. return _Value.prototype.add.call(this, decl, prefix);
  462. }
  463. } else if (p === 'list-style' || p === 'list-style-image' || p === 'content') {
  464. if (prefix === '-webkit-' || prefix === '-webkit- old') {
  465. return _Value.prototype.add.call(this, decl, prefix);
  466. }
  467. } else {
  468. return _Value.prototype.add.call(this, decl, prefix);
  469. }
  470. return undefined;
  471. };
  472. return Gradient;
  473. }(Value);
  474. _defineProperty(Gradient, "names", ['linear-gradient', 'repeating-linear-gradient', 'radial-gradient', 'repeating-radial-gradient']);
  475. module.exports = Gradient;