component-classes.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. Object.defineProperty(exports, "__esModule", {
  4. value: true
  5. });
  6. exports.ClassList = void 0;
  7. exports.default = _default;
  8. var _indexOf = _interopRequireDefault(require("lodash/indexOf"));
  9. /**
  10. * source by `component-classes`
  11. * https://github.com/component/classes.git
  12. */
  13. /**
  14. * Whitespace regexp.
  15. */
  16. const re = /\s+/;
  17. class ClassList {
  18. constructor(el) {
  19. if (!el || !el.nodeType) {
  20. throw new Error('A DOM element reference is required');
  21. }
  22. this.el = el;
  23. this.list = el.classList;
  24. }
  25. array() {
  26. const className = this.el.getAttribute('class') || '';
  27. const str = className.replace(/^\s+|\s+$/g, '');
  28. const arr = str.split(re);
  29. if ('' === arr[0]) arr.shift();
  30. return arr;
  31. }
  32. /**
  33. * Add class `name` if not already present.
  34. *
  35. * @param {String} name
  36. * @return {ClassList}
  37. * @api public
  38. */
  39. add(name) {
  40. // classList
  41. if (this.list) {
  42. this.list.add(name);
  43. return this;
  44. }
  45. // fallback
  46. const arr = this.array();
  47. const i = (0, _indexOf.default)(arr, name);
  48. if (!~i) arr.push(name);
  49. this.el.className = arr.join(' ');
  50. return this;
  51. }
  52. /**
  53. * Remove class `name` when present, or
  54. * pass a regular expression to remove
  55. * any which match.
  56. *
  57. * @param {String|RegExp} name
  58. * @return {ClassList}
  59. * @api public
  60. */
  61. remove(name) {
  62. if ('[object RegExp]' === toString.call(name)) {
  63. return this._removeMatching(name);
  64. }
  65. // classList
  66. if (this.list) {
  67. this.list.remove(name);
  68. return this;
  69. }
  70. // fallback
  71. const arr = this.array();
  72. const i = (0, _indexOf.default)(arr, name);
  73. if (~i) arr.splice(i, 1);
  74. this.el.className = arr.join(' ');
  75. return this;
  76. }
  77. /**
  78. * Remove all classes matching `re`.
  79. *
  80. * @param {RegExp} re
  81. * @return {ClassList}
  82. * @api private
  83. */
  84. _removeMatching(re) {
  85. const arr = this.array();
  86. for (let i = 0; i < arr.length; i++) {
  87. if (re.test(arr[i])) {
  88. this.remove(arr[i]);
  89. }
  90. }
  91. return this;
  92. }
  93. /**
  94. * Toggle class `name`, can force state via `force`.
  95. *
  96. * For browsers that support classList, but do not support `force` yet,
  97. * the mistake will be detected and corrected.
  98. *
  99. * @param {String} name
  100. * @param {Boolean} force
  101. * @return {ClassList}
  102. * @api public
  103. */
  104. toggle(name, force) {
  105. // classList
  106. if (this.list) {
  107. if ('undefined' !== typeof force) {
  108. if (force !== this.list.toggle(name, force)) {
  109. this.list.toggle(name); // toggle again to correct
  110. }
  111. } else {
  112. this.list.toggle(name);
  113. }
  114. return this;
  115. }
  116. // fallback
  117. if ('undefined' !== typeof force) {
  118. if (!force) {
  119. this.remove(name);
  120. } else {
  121. this.add(name);
  122. }
  123. } else {
  124. if (this.has(name)) {
  125. this.remove(name);
  126. } else {
  127. this.add(name);
  128. }
  129. }
  130. return this;
  131. }
  132. /**
  133. * Check if class `name` is present.
  134. *
  135. * @param {String} name
  136. * @api public
  137. */
  138. has(name) {
  139. return this.list ? this.list.contains(name) : !!~(0, _indexOf.default)(this.array(), name);
  140. }
  141. /**
  142. * Check if class `name` is present.
  143. *
  144. * @param {String} name
  145. * @api public
  146. */
  147. contains(name) {
  148. return this.has(name);
  149. }
  150. }
  151. /**
  152. * Wrap `el` in a `ClassList`.
  153. *
  154. * @param {Element} el
  155. * @return {ClassList}
  156. * @api public
  157. */
  158. exports.ClassList = ClassList;
  159. function _default(el) {
  160. return new ClassList(el);
  161. }