responsiveObserver.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
  3. Object.defineProperty(exports, "__esModule", {
  4. value: true
  5. });
  6. exports.responsiveArray = exports.matchScreen = exports.default = void 0;
  7. var _react = _interopRequireDefault(require("react"));
  8. var _internal = require("../theme/internal");
  9. var _mediaQueryUtil = require("./mediaQueryUtil");
  10. const responsiveArray = exports.responsiveArray = ['xxl', 'xl', 'lg', 'md', 'sm', 'xs'];
  11. const getResponsiveMap = token => ({
  12. xs: `(max-width: ${token.screenXSMax}px)`,
  13. sm: `(min-width: ${token.screenSM}px)`,
  14. md: `(min-width: ${token.screenMD}px)`,
  15. lg: `(min-width: ${token.screenLG}px)`,
  16. xl: `(min-width: ${token.screenXL}px)`,
  17. xxl: `(min-width: ${token.screenXXL}px)`
  18. });
  19. /**
  20. * Ensures that the breakpoints token are valid, in good order
  21. * For each breakpoint : screenMin <= screen <= screenMax and screenMax <= nextScreenMin
  22. */
  23. const validateBreakpoints = token => {
  24. const indexableToken = token;
  25. const revBreakpoints = [].concat(responsiveArray).reverse();
  26. revBreakpoints.forEach((breakpoint, i) => {
  27. const breakpointUpper = breakpoint.toUpperCase();
  28. const screenMin = `screen${breakpointUpper}Min`;
  29. const screen = `screen${breakpointUpper}`;
  30. if (!(indexableToken[screenMin] <= indexableToken[screen])) {
  31. throw new Error(`${screenMin}<=${screen} fails : !(${indexableToken[screenMin]}<=${indexableToken[screen]})`);
  32. }
  33. if (i < revBreakpoints.length - 1) {
  34. const screenMax = `screen${breakpointUpper}Max`;
  35. if (!(indexableToken[screen] <= indexableToken[screenMax])) {
  36. throw new Error(`${screen}<=${screenMax} fails : !(${indexableToken[screen]}<=${indexableToken[screenMax]})`);
  37. }
  38. const nextBreakpointUpperMin = revBreakpoints[i + 1].toUpperCase();
  39. const nextScreenMin = `screen${nextBreakpointUpperMin}Min`;
  40. if (!(indexableToken[screenMax] <= indexableToken[nextScreenMin])) {
  41. throw new Error(`${screenMax}<=${nextScreenMin} fails : !(${indexableToken[screenMax]}<=${indexableToken[nextScreenMin]})`);
  42. }
  43. }
  44. });
  45. return token;
  46. };
  47. const matchScreen = (screens, screenSizes) => {
  48. if (!screenSizes) {
  49. return;
  50. }
  51. for (const breakpoint of responsiveArray) {
  52. if (screens[breakpoint] && (screenSizes === null || screenSizes === void 0 ? void 0 : screenSizes[breakpoint]) !== undefined) {
  53. return screenSizes[breakpoint];
  54. }
  55. }
  56. };
  57. exports.matchScreen = matchScreen;
  58. const useResponsiveObserver = () => {
  59. const [, token] = (0, _internal.useToken)();
  60. const responsiveMap = getResponsiveMap(validateBreakpoints(token));
  61. // To avoid repeat create instance, we add `useMemo` here.
  62. return _react.default.useMemo(() => {
  63. const subscribers = new Map();
  64. let subUid = -1;
  65. let screens = {};
  66. return {
  67. responsiveMap,
  68. matchHandlers: {},
  69. dispatch(pointMap) {
  70. screens = pointMap;
  71. subscribers.forEach(func => func(screens));
  72. return subscribers.size >= 1;
  73. },
  74. subscribe(func) {
  75. if (!subscribers.size) {
  76. this.register();
  77. }
  78. subUid += 1;
  79. subscribers.set(subUid, func);
  80. func(screens);
  81. return subUid;
  82. },
  83. unsubscribe(paramToken) {
  84. subscribers.delete(paramToken);
  85. if (!subscribers.size) {
  86. this.unregister();
  87. }
  88. },
  89. register() {
  90. Object.entries(responsiveMap).forEach(([screen, mediaQuery]) => {
  91. const listener = ({
  92. matches
  93. }) => {
  94. this.dispatch(Object.assign(Object.assign({}, screens), {
  95. [screen]: matches
  96. }));
  97. };
  98. const mql = window.matchMedia(mediaQuery);
  99. (0, _mediaQueryUtil.addMediaQueryListener)(mql, listener);
  100. this.matchHandlers[mediaQuery] = {
  101. mql,
  102. listener
  103. };
  104. listener(mql);
  105. });
  106. },
  107. unregister() {
  108. Object.values(responsiveMap).forEach(mediaQuery => {
  109. const handler = this.matchHandlers[mediaQuery];
  110. (0, _mediaQueryUtil.removeMediaQueryListener)(handler === null || handler === void 0 ? void 0 : handler.mql, handler === null || handler === void 0 ? void 0 : handler.listener);
  111. });
  112. subscribers.clear();
  113. }
  114. };
  115. }, [token]);
  116. };
  117. var _default = exports.default = useResponsiveObserver;