dynamicCSS.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
  2. import canUseDom from "./canUseDom";
  3. import contains from "./contains";
  4. var APPEND_ORDER = 'data-rc-order';
  5. var APPEND_PRIORITY = 'data-rc-priority';
  6. var MARK_KEY = "rc-util-key";
  7. var containerCache = new Map();
  8. function getMark() {
  9. var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
  10. mark = _ref.mark;
  11. if (mark) {
  12. return mark.startsWith('data-') ? mark : "data-".concat(mark);
  13. }
  14. return MARK_KEY;
  15. }
  16. function getContainer(option) {
  17. if (option.attachTo) {
  18. return option.attachTo;
  19. }
  20. var head = document.querySelector('head');
  21. return head || document.body;
  22. }
  23. function getOrder(prepend) {
  24. if (prepend === 'queue') {
  25. return 'prependQueue';
  26. }
  27. return prepend ? 'prepend' : 'append';
  28. }
  29. /**
  30. * Find style which inject by rc-util
  31. */
  32. function findStyles(container) {
  33. return Array.from((containerCache.get(container) || container).children).filter(function (node) {
  34. return node.tagName === 'STYLE';
  35. });
  36. }
  37. export function injectCSS(css) {
  38. var option = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  39. if (!canUseDom()) {
  40. return null;
  41. }
  42. var csp = option.csp,
  43. prepend = option.prepend,
  44. _option$priority = option.priority,
  45. priority = _option$priority === void 0 ? 0 : _option$priority;
  46. var mergedOrder = getOrder(prepend);
  47. var isPrependQueue = mergedOrder === 'prependQueue';
  48. var styleNode = document.createElement('style');
  49. styleNode.setAttribute(APPEND_ORDER, mergedOrder);
  50. if (isPrependQueue && priority) {
  51. styleNode.setAttribute(APPEND_PRIORITY, "".concat(priority));
  52. }
  53. if (csp !== null && csp !== void 0 && csp.nonce) {
  54. styleNode.nonce = csp === null || csp === void 0 ? void 0 : csp.nonce;
  55. }
  56. styleNode.innerHTML = css;
  57. var container = getContainer(option);
  58. var firstChild = container.firstChild;
  59. if (prepend) {
  60. // If is queue `prepend`, it will prepend first style and then append rest style
  61. if (isPrependQueue) {
  62. var existStyle = (option.styles || findStyles(container)).filter(function (node) {
  63. // Ignore style which not injected by rc-util with prepend
  64. if (!['prepend', 'prependQueue'].includes(node.getAttribute(APPEND_ORDER))) {
  65. return false;
  66. }
  67. // Ignore style which priority less then new style
  68. var nodePriority = Number(node.getAttribute(APPEND_PRIORITY) || 0);
  69. return priority >= nodePriority;
  70. });
  71. if (existStyle.length) {
  72. container.insertBefore(styleNode, existStyle[existStyle.length - 1].nextSibling);
  73. return styleNode;
  74. }
  75. }
  76. // Use `insertBefore` as `prepend`
  77. container.insertBefore(styleNode, firstChild);
  78. } else {
  79. container.appendChild(styleNode);
  80. }
  81. return styleNode;
  82. }
  83. function findExistNode(key) {
  84. var option = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  85. var container = getContainer(option);
  86. return (option.styles || findStyles(container)).find(function (node) {
  87. return node.getAttribute(getMark(option)) === key;
  88. });
  89. }
  90. export function removeCSS(key) {
  91. var option = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  92. var existNode = findExistNode(key, option);
  93. if (existNode) {
  94. var container = getContainer(option);
  95. container.removeChild(existNode);
  96. }
  97. }
  98. /**
  99. * qiankun will inject `appendChild` to insert into other
  100. */
  101. function syncRealContainer(container, option) {
  102. var cachedRealContainer = containerCache.get(container);
  103. // Find real container when not cached or cached container removed
  104. if (!cachedRealContainer || !contains(document, cachedRealContainer)) {
  105. var placeholderStyle = injectCSS('', option);
  106. var parentNode = placeholderStyle.parentNode;
  107. containerCache.set(container, parentNode);
  108. container.removeChild(placeholderStyle);
  109. }
  110. }
  111. /**
  112. * manually clear container cache to avoid global cache in unit testes
  113. */
  114. export function clearContainerCache() {
  115. containerCache.clear();
  116. }
  117. export function updateCSS(css, key) {
  118. var originOption = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
  119. var container = getContainer(originOption);
  120. var styles = findStyles(container);
  121. var option = _objectSpread(_objectSpread({}, originOption), {}, {
  122. styles: styles
  123. });
  124. // Sync real parent
  125. syncRealContainer(container, option);
  126. var existNode = findExistNode(key, option);
  127. if (existNode) {
  128. var _option$csp, _option$csp2;
  129. if ((_option$csp = option.csp) !== null && _option$csp !== void 0 && _option$csp.nonce && existNode.nonce !== ((_option$csp2 = option.csp) === null || _option$csp2 === void 0 ? void 0 : _option$csp2.nonce)) {
  130. var _option$csp3;
  131. existNode.nonce = (_option$csp3 = option.csp) === null || _option$csp3 === void 0 ? void 0 : _option$csp3.nonce;
  132. }
  133. if (existNode.innerHTML !== css) {
  134. existNode.innerHTML = css;
  135. }
  136. return existNode;
  137. }
  138. var newNode = injectCSS(css, option);
  139. newNode.setAttribute(getMark(option), key);
  140. return newNode;
  141. }