Advertisement
Guest User

Untitled

a guest
May 20th, 2019
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.14 KB | None | 0 0
  1. // @flow
  2. /* eslint-env browser */
  3.  
  4. import {useRef, useEffect} from 'react';
  5.  
  6. function getDiff(a, b, properties) {
  7. const diff = {};
  8.  
  9. if (properties.length === 0) {
  10. for (const property in b) {
  11. if (b.hasOwnProperty(property) && b[property] !== a[property]) {
  12. diff[property] = {
  13. prev: a[property],
  14. curr: b[property],
  15. };
  16. }
  17. }
  18. return diff;
  19. }
  20.  
  21. return properties.reduce((result, property) => {
  22. if (b[property] !== a[property]) {
  23. result[property] = {
  24. prev: a[property],
  25. curr: b[property],
  26. };
  27. }
  28. return result;
  29. }, diff);
  30. }
  31.  
  32. function getCopy(obj, properties) {
  33. const result = {};
  34.  
  35. if (properties.length === 0) {
  36. for (const property in obj) {
  37. if (obj.hasOwnProperty(property)) {
  38. result[property] = obj[property];
  39. }
  40. }
  41. return result;
  42. }
  43.  
  44. return properties.reduce((acc, property) => {
  45. if (process.env.NODE_ENV === 'development') {
  46. if (!obj.hasOwnProperty(property)) {
  47. console.trace(); // eslint-disable-line no-console
  48. console.error(
  49. `useComputedStyleObserver: computed style does not have own property: ${property}`
  50. );
  51. return acc;
  52. }
  53. }
  54.  
  55. acc[property] = obj[property];
  56. return acc;
  57. }, result);
  58. }
  59.  
  60. type DiffType = {[string]: {curr: string, prev: string}};
  61.  
  62. /**
  63. * Observes the computed style for a single DOM node, and fires an onChange handler
  64. * if a diff exists.
  65. */
  66. export const useComputedStyleObserver = (
  67. /**
  68. * List of properties to diff against. The less there is the more performant. If
  69. * list is empty, all computed style properties will be checked
  70. */
  71. properties: Array<string>,
  72. /**
  73. * Callback that is invoked when a diff occurs
  74. */
  75. onStyleChange: (diff: DiffType) => void
  76. ) => {
  77. /**
  78. * Stores a single reference to the node's computed style that can
  79. * be observed for changes.
  80. */
  81. const computedStylesRef = useRef();
  82.  
  83. /**
  84. * Stores a subset of the computed styles based on the list of properties
  85. */
  86. const stylesRef = useRef();
  87.  
  88. const started = useRef(false);
  89.  
  90. const animationFrameIDRef = useRef(null);
  91.  
  92. useEffect(() => {
  93. function checkDiff() {
  94. const styles = stylesRef.current;
  95. const computedStyles = computedStylesRef.current;
  96. if (!styles || !computedStyles) {
  97. return;
  98. }
  99. started.current = true;
  100.  
  101. const newStyles = getCopy(computedStyles, properties);
  102. const diff = getDiff(styles, newStyles, properties);
  103.  
  104. if (Object.keys(diff).length) {
  105. stylesRef.current = newStyles;
  106. onStyleChange(diff);
  107. }
  108. animationFrameIDRef.current = requestAnimationFrame(checkDiff);
  109. }
  110.  
  111. if (!started.current) {
  112. checkDiff();
  113. }
  114. });
  115.  
  116. useEffect(() => {
  117. return () => {
  118. if (animationFrameIDRef.current) {
  119. cancelAnimationFrame(animationFrameIDRef.current);
  120. }
  121. };
  122. }, []);
  123.  
  124. return {
  125. observe: (node: Element) => {
  126. const win = node.ownerDocument.defaultView;
  127. const computedStyles = win.getComputedStyle(node);
  128. computedStylesRef.current = computedStyles;
  129. stylesRef.current = getCopy(computedStyles, properties);
  130. },
  131. };
  132. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement