@hh.ru/magritte-ui-modal 11.0.41 → 11.0.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/actionBarDefaults.d.ts +2 -2
  2. package/actionBarDefaults.js +3 -17
  3. package/actionBarDefaults.js.map +1 -1
  4. package/index.css +121 -121
  5. package/index.d.ts +5 -5
  6. package/index.js +1 -1
  7. package/index.mock.js +5 -5
  8. package/index.mock.js.map +1 -1
  9. package/internal/ModalBody.js +42 -24
  10. package/internal/ModalBody.js.map +1 -1
  11. package/internal/ModalContent.js +2 -2
  12. package/internal/ModalContent.js.map +1 -1
  13. package/internal/ModalInner.d.ts +1 -1
  14. package/internal/ModalInner.js +46 -26
  15. package/internal/ModalInner.js.map +1 -1
  16. package/internal/ModalSlotsContext.js +34 -52
  17. package/internal/ModalSlotsContext.js.map +1 -1
  18. package/internal/ModalStickyHeader.js +27 -23
  19. package/internal/ModalStickyHeader.js.map +1 -1
  20. package/internal/constants.js +33 -42
  21. package/internal/constants.js.map +1 -1
  22. package/internal/isTreeSelectorChild.js +0 -5
  23. package/internal/isTreeSelectorChild.js.map +1 -1
  24. package/internal/useModalOrder.js +69 -76
  25. package/internal/useModalOrder.js.map +1 -1
  26. package/internal/useModalTransition.js +71 -72
  27. package/internal/useModalTransition.js.map +1 -1
  28. package/internal/usePageHeaderScrollAnimation.js +42 -42
  29. package/internal/usePageHeaderScrollAnimation.js.map +1 -1
  30. package/modal-DKfr_WcM.js +5 -0
  31. package/modal-DKfr_WcM.js.map +1 -0
  32. package/package.json +30 -29
  33. package/public/Modal.d.ts +2 -2
  34. package/public/Modal.js +119 -51
  35. package/public/Modal.js.map +1 -1
  36. package/public/ModalMedia.js +26 -15
  37. package/public/ModalMedia.js.map +1 -1
  38. package/public/ModalWithImage.d.ts +2 -2
  39. package/public/ModalWithImage.js +11 -3
  40. package/public/ModalWithImage.js.map +1 -1
  41. package/withImageDefaults.d.ts +3 -3
  42. package/withImageDefaults.js +5 -18
  43. package/withImageDefaults.js.map +1 -1
  44. package/modal-Df_WVial.js +0 -5
  45. package/modal-Df_WVial.js.map +0 -1
@@ -1,52 +1,43 @@
1
1
  import './../index.css';
2
2
  import coreTokens from '@hh.ru/magritte-design-tokens/core-tokens';
3
- import { s as styles } from '../modal-Df_WVial.js';
3
+ import { s as styles } from '../modal-DKfr_WcM.js';
4
4
 
5
- /** Отступ сверху под page-header (px) — дефолт для `position=left|right` без оверлея. */
6
5
  const DEFAULT_PAGE_HEADER_PADDING = 72;
7
- const noop = () => undefined;
8
- /** Длительности анимации появления/исчезновения модала (мс) — из дизайн-токенов (см. modal.less). */
9
- const ENTER_ANIMATION_DURATION = coreTokens['magritte-semantic-animation-ease-in-out-300'].duration;
10
- const EXIT_ANIMATION_DURATION = coreTokens['magritte-semantic-animation-ease-in-out-200'].duration;
11
- /**
12
- * Таймаут `CSSTransition` для анимации модала (мс).
13
- * При `prefers-reduced-motion` анимация мгновенная (0) — согласовано с media-query в modal.less.
14
- */
6
+ const noop = () => void 0;
7
+ const ENTER_ANIMATION_DURATION = coreTokens["magritte-semantic-animation-ease-in-out-300"].duration;
8
+ const EXIT_ANIMATION_DURATION = coreTokens["magritte-semantic-animation-ease-in-out-200"].duration;
15
9
  const getAnimationTimeout = () => {
16
- const prefersReducedMotion = typeof window !== 'undefined' &&
17
- typeof window.matchMedia === 'function' &&
18
- window.matchMedia('(prefers-reduced-motion: reduce)').matches;
19
- if (prefersReducedMotion) {
20
- return { enter: 0, exit: 0 };
21
- }
22
- return { enter: ENTER_ANIMATION_DURATION, exit: EXIT_ANIMATION_DURATION };
10
+ const prefersReducedMotion = typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
11
+ if (prefersReducedMotion) {
12
+ return { enter: 0, exit: 0 };
13
+ }
14
+ return { enter: ENTER_ANIMATION_DURATION, exit: EXIT_ANIMATION_DURATION };
23
15
  };
24
- /** Классы фаз `CSSTransition` по позиции модала. */
25
16
  const CSS_CLASSES = {
26
- center: {
27
- appear: styles.animationEnterCenter,
28
- appearActive: styles.animationEnterCenterActive,
29
- enter: styles.animationEnterCenter,
30
- enterActive: styles.animationEnterCenterActive,
31
- exit: styles.animationExitCenter,
32
- exitActive: styles.animationExitCenterActive,
33
- },
34
- left: {
35
- appear: styles.animationEnterLeft,
36
- appearActive: styles.animationEnterLeftActive,
37
- enter: styles.animationEnterLeft,
38
- enterActive: styles.animationEnterLeftActive,
39
- exit: styles.animationExitLeft,
40
- exitActive: styles.animationExitLeftActive,
41
- },
42
- right: {
43
- appear: styles.animationEnterRight,
44
- appearActive: styles.animationEnterRightActive,
45
- enter: styles.animationEnterRight,
46
- enterActive: styles.animationEnterRightActive,
47
- exit: styles.animationExitRight,
48
- exitActive: styles.animationExitRightActive,
49
- },
17
+ center: {
18
+ appear: styles.animationEnterCenter,
19
+ appearActive: styles.animationEnterCenterActive,
20
+ enter: styles.animationEnterCenter,
21
+ enterActive: styles.animationEnterCenterActive,
22
+ exit: styles.animationExitCenter,
23
+ exitActive: styles.animationExitCenterActive
24
+ },
25
+ left: {
26
+ appear: styles.animationEnterLeft,
27
+ appearActive: styles.animationEnterLeftActive,
28
+ enter: styles.animationEnterLeft,
29
+ enterActive: styles.animationEnterLeftActive,
30
+ exit: styles.animationExitLeft,
31
+ exitActive: styles.animationExitLeftActive
32
+ },
33
+ right: {
34
+ appear: styles.animationEnterRight,
35
+ appearActive: styles.animationEnterRightActive,
36
+ enter: styles.animationEnterRight,
37
+ enterActive: styles.animationEnterRightActive,
38
+ exit: styles.animationExitRight,
39
+ exitActive: styles.animationExitRightActive
40
+ }
50
41
  };
51
42
 
52
43
  export { CSS_CLASSES, DEFAULT_PAGE_HEADER_PADDING, getAnimationTimeout, noop };
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sources":["src/internal/constants.ts"],"sourcesContent":["import coreTokens from '@hh.ru/magritte-design-tokens/core-tokens';\n\nimport styles from './modal.less';\n\n/** Отступ сверху под page-header (px) — дефолт для `position=left|right` без оверлея. */\nexport const DEFAULT_PAGE_HEADER_PADDING = 72;\n\nexport const noop = (): undefined => undefined;\n\n/** Длительности анимации появления/исчезновения модала (мс) — из дизайн-токенов (см. modal.less). */\nconst ENTER_ANIMATION_DURATION = coreTokens['magritte-semantic-animation-ease-in-out-300'].duration;\nconst EXIT_ANIMATION_DURATION = coreTokens['magritte-semantic-animation-ease-in-out-200'].duration;\n\n/**\n * Таймаут `CSSTransition` для анимации модала (мс).\n * При `prefers-reduced-motion` анимация мгновенная (0) — согласовано с media-query в modal.less.\n */\nexport const getAnimationTimeout = (): { enter: number; exit: number } => {\n const prefersReducedMotion =\n typeof window !== 'undefined' &&\n typeof window.matchMedia === 'function' &&\n window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n\n if (prefersReducedMotion) {\n return { enter: 0, exit: 0 };\n }\n\n return { enter: ENTER_ANIMATION_DURATION, exit: EXIT_ANIMATION_DURATION };\n};\n\n/** Классы фаз `CSSTransition` по позиции модала. */\nexport const CSS_CLASSES = {\n center: {\n appear: styles.animationEnterCenter,\n appearActive: styles.animationEnterCenterActive,\n enter: styles.animationEnterCenter,\n enterActive: styles.animationEnterCenterActive,\n exit: styles.animationExitCenter,\n exitActive: styles.animationExitCenterActive,\n },\n left: {\n appear: styles.animationEnterLeft,\n appearActive: styles.animationEnterLeftActive,\n enter: styles.animationEnterLeft,\n enterActive: styles.animationEnterLeftActive,\n exit: styles.animationExitLeft,\n exitActive: styles.animationExitLeftActive,\n },\n right: {\n appear: styles.animationEnterRight,\n appearActive: styles.animationEnterRightActive,\n enter: styles.animationEnterRight,\n enterActive: styles.animationEnterRightActive,\n exit: styles.animationExitRight,\n exitActive: styles.animationExitRightActive,\n },\n};\n"],"names":[],"mappings":";;;AAIA;AACO,MAAM,2BAA2B,GAAG,GAAG;MAEjC,IAAI,GAAG,MAAiB,UAAU;AAE/C;AACA,MAAM,wBAAwB,GAAG,UAAU,CAAC,6CAA6C,CAAC,CAAC,QAAQ,CAAC;AACpG,MAAM,uBAAuB,GAAG,UAAU,CAAC,6CAA6C,CAAC,CAAC,QAAQ,CAAC;AAEnG;;;AAGG;AACI,MAAM,mBAAmB,GAAG,MAAsC;AACrE,IAAA,MAAM,oBAAoB,GACtB,OAAO,MAAM,KAAK,WAAW;AAC7B,QAAA,OAAO,MAAM,CAAC,UAAU,KAAK,UAAU;AACvC,QAAA,MAAM,CAAC,UAAU,CAAC,kCAAkC,CAAC,CAAC,OAAO,CAAC;IAElE,IAAI,oBAAoB,EAAE;QACtB,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;KAChC;IAED,OAAO,EAAE,KAAK,EAAE,wBAAwB,EAAE,IAAI,EAAE,uBAAuB,EAAE,CAAC;AAC9E,EAAE;AAEF;AACa,MAAA,WAAW,GAAG;AACvB,IAAA,MAAM,EAAE;QACJ,MAAM,EAAE,MAAM,CAAC,oBAAoB;QACnC,YAAY,EAAE,MAAM,CAAC,0BAA0B;QAC/C,KAAK,EAAE,MAAM,CAAC,oBAAoB;QAClC,WAAW,EAAE,MAAM,CAAC,0BAA0B;QAC9C,IAAI,EAAE,MAAM,CAAC,mBAAmB;QAChC,UAAU,EAAE,MAAM,CAAC,yBAAyB;AAC/C,KAAA;AACD,IAAA,IAAI,EAAE;QACF,MAAM,EAAE,MAAM,CAAC,kBAAkB;QACjC,YAAY,EAAE,MAAM,CAAC,wBAAwB;QAC7C,KAAK,EAAE,MAAM,CAAC,kBAAkB;QAChC,WAAW,EAAE,MAAM,CAAC,wBAAwB;QAC5C,IAAI,EAAE,MAAM,CAAC,iBAAiB;QAC9B,UAAU,EAAE,MAAM,CAAC,uBAAuB;AAC7C,KAAA;AACD,IAAA,KAAK,EAAE;QACH,MAAM,EAAE,MAAM,CAAC,mBAAmB;QAClC,YAAY,EAAE,MAAM,CAAC,yBAAyB;QAC9C,KAAK,EAAE,MAAM,CAAC,mBAAmB;QACjC,WAAW,EAAE,MAAM,CAAC,yBAAyB;QAC7C,IAAI,EAAE,MAAM,CAAC,kBAAkB;QAC/B,UAAU,EAAE,MAAM,CAAC,wBAAwB;AAC9C,KAAA;;;;;"}
1
+ {"version":3,"file":"constants.js","sources":["src/internal/constants.ts"],"sourcesContent":["import coreTokens from '@hh.ru/magritte-design-tokens/core-tokens';\n\nimport styles from './modal.less';\n\n/** Отступ сверху под page-header (px) — дефолт для `position=left|right` без оверлея. */\nexport const DEFAULT_PAGE_HEADER_PADDING = 72;\n\nexport const noop = (): undefined => undefined;\n\n/** Длительности анимации появления/исчезновения модала (мс) — из дизайн-токенов (см. modal.less). */\nconst ENTER_ANIMATION_DURATION = coreTokens['magritte-semantic-animation-ease-in-out-300'].duration;\nconst EXIT_ANIMATION_DURATION = coreTokens['magritte-semantic-animation-ease-in-out-200'].duration;\n\n/**\n * Таймаут `CSSTransition` для анимации модала (мс).\n * При `prefers-reduced-motion` анимация мгновенная (0) — согласовано с media-query в modal.less.\n */\nexport const getAnimationTimeout = (): { enter: number; exit: number } => {\n const prefersReducedMotion =\n typeof window !== 'undefined' &&\n typeof window.matchMedia === 'function' &&\n window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n\n if (prefersReducedMotion) {\n return { enter: 0, exit: 0 };\n }\n\n return { enter: ENTER_ANIMATION_DURATION, exit: EXIT_ANIMATION_DURATION };\n};\n\n/** Классы фаз `CSSTransition` по позиции модала. */\nexport const CSS_CLASSES = {\n center: {\n appear: styles.animationEnterCenter,\n appearActive: styles.animationEnterCenterActive,\n enter: styles.animationEnterCenter,\n enterActive: styles.animationEnterCenterActive,\n exit: styles.animationExitCenter,\n exitActive: styles.animationExitCenterActive,\n },\n left: {\n appear: styles.animationEnterLeft,\n appearActive: styles.animationEnterLeftActive,\n enter: styles.animationEnterLeft,\n enterActive: styles.animationEnterLeftActive,\n exit: styles.animationExitLeft,\n exitActive: styles.animationExitLeftActive,\n },\n right: {\n appear: styles.animationEnterRight,\n appearActive: styles.animationEnterRightActive,\n enter: styles.animationEnterRight,\n enterActive: styles.animationEnterRightActive,\n exit: styles.animationExitRight,\n exitActive: styles.animationExitRightActive,\n },\n};\n"],"names":[],"mappings":";;;AAKO,MAAM,2BAA8B,GAAA,GAAA;AAEpC,MAAM,OAAO,MAAiB,KAAA,EAAA;AAGrC,MAAM,wBAAA,GAA2B,UAAW,CAAA,6CAA6C,CAAE,CAAA,QAAA,CAAA;AAC3F,MAAM,uBAAA,GAA0B,UAAW,CAAA,6CAA6C,CAAE,CAAA,QAAA,CAAA;AAMnF,MAAM,sBAAsB,MAAuC;AACtE,EAAM,MAAA,oBAAA,GACF,OAAO,MAAA,KAAW,WAClB,IAAA,OAAO,MAAO,CAAA,UAAA,KAAe,UAC7B,IAAA,MAAA,CAAO,UAAW,CAAA,kCAAkC,CAAE,CAAA,OAAA,CAAA;AAE1D,EAAA,IAAI,oBAAsB,EAAA;AACtB,IAAA,OAAO,EAAE,KAAA,EAAO,CAAG,EAAA,IAAA,EAAM,CAAE,EAAA,CAAA;AAAA,GAC/B;AAEA,EAAA,OAAO,EAAE,KAAA,EAAO,wBAA0B,EAAA,IAAA,EAAM,uBAAwB,EAAA,CAAA;AAC5E,EAAA;AAGO,MAAM,WAAc,GAAA;AAAA,EACvB,MAAQ,EAAA;AAAA,IACJ,QAAQ,MAAO,CAAA,oBAAA;AAAA,IACf,cAAc,MAAO,CAAA,0BAAA;AAAA,IACrB,OAAO,MAAO,CAAA,oBAAA;AAAA,IACd,aAAa,MAAO,CAAA,0BAAA;AAAA,IACpB,MAAM,MAAO,CAAA,mBAAA;AAAA,IACb,YAAY,MAAO,CAAA,yBAAA;AAAA,GACvB;AAAA,EACA,IAAM,EAAA;AAAA,IACF,QAAQ,MAAO,CAAA,kBAAA;AAAA,IACf,cAAc,MAAO,CAAA,wBAAA;AAAA,IACrB,OAAO,MAAO,CAAA,kBAAA;AAAA,IACd,aAAa,MAAO,CAAA,wBAAA;AAAA,IACpB,MAAM,MAAO,CAAA,iBAAA;AAAA,IACb,YAAY,MAAO,CAAA,uBAAA;AAAA,GACvB;AAAA,EACA,KAAO,EAAA;AAAA,IACH,QAAQ,MAAO,CAAA,mBAAA;AAAA,IACf,cAAc,MAAO,CAAA,yBAAA;AAAA,IACrB,OAAO,MAAO,CAAA,mBAAA;AAAA,IACd,aAAa,MAAO,CAAA,yBAAA;AAAA,IACpB,MAAM,MAAO,CAAA,kBAAA;AAAA,IACb,YAAY,MAAO,CAAA,wBAAA;AAAA,GACvB;AACJ;;;;"}
@@ -2,11 +2,6 @@ import './../index.css';
2
2
  import { Children } from 'react';
3
3
  import { isValidTreeSelectorWrapper } from '@hh.ru/magritte-ui-tree-selector';
4
4
 
5
- /**
6
- * `true`, если среди детей модала есть `TreeSelector`-обёртка. Единая точка детекции: её используют и
7
- * `Modal` (форсит `height='full-screen'`), и `ModalContent` (рендерит особый контейнер) — проверка детей
8
- * должна совпадать в обоих местах, иначе детекция разъедется.
9
- */
10
5
  const isTreeSelectorChild = (children) => Children.toArray(children).some(isValidTreeSelectorWrapper);
11
6
 
12
7
  export { isTreeSelectorChild };
@@ -1 +1 @@
1
- {"version":3,"file":"isTreeSelectorChild.js","sources":["src/internal/isTreeSelectorChild.ts"],"sourcesContent":["import { Children, type ReactNode } from 'react';\n\nimport { isValidTreeSelectorWrapper } from '@hh.ru/magritte-ui-tree-selector';\n\n/**\n * `true`, если среди детей модала есть `TreeSelector`-обёртка. Единая точка детекции: её используют и\n * `Modal` (форсит `height='full-screen'`), и `ModalContent` (рендерит особый контейнер) — проверка детей\n * должна совпадать в обоих местах, иначе детекция разъедется.\n */\nexport const isTreeSelectorChild = (children: ReactNode): boolean =>\n Children.toArray(children).some(isValidTreeSelectorWrapper);\n"],"names":[],"mappings":";;;AAIA;;;;AAIG;MACU,mBAAmB,GAAG,CAAC,QAAmB,KACnD,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,0BAA0B;;;;"}
1
+ {"version":3,"file":"isTreeSelectorChild.js","sources":["src/internal/isTreeSelectorChild.ts"],"sourcesContent":["import { Children, type ReactNode } from 'react';\n\nimport { isValidTreeSelectorWrapper } from '@hh.ru/magritte-ui-tree-selector';\n\n/**\n * `true`, если среди детей модала есть `TreeSelector`-обёртка. Единая точка детекции: её используют и\n * `Modal` (форсит `height='full-screen'`), и `ModalContent` (рендерит особый контейнер) — проверка детей\n * должна совпадать в обоих местах, иначе детекция разъедется.\n */\nexport const isTreeSelectorChild = (children: ReactNode): boolean =>\n Children.toArray(children).some(isValidTreeSelectorWrapper);\n"],"names":[],"mappings":";;;AASa,MAAA,mBAAA,GAAsB,CAAC,QAChC,KAAA,QAAA,CAAS,QAAQ,QAAQ,CAAA,CAAE,KAAK,0BAA0B;;;;"}
@@ -2,90 +2,83 @@ import './../index.css';
2
2
  import { useState, useLayoutEffect, useEffect } from 'react';
3
3
  import { useDomStoredUniqueId, getValueFromDom, storeValueInDom } from '@hh.ru/magritte-common-dom-storage';
4
4
 
5
- const STORAGE_NAME = '_MAGRITTE_MODAL_COUNTER_';
5
+ const STORAGE_NAME = "_MAGRITTE_MODAL_COUNTER_";
6
6
  const getState = () => {
7
- const state = getValueFromDom(STORAGE_NAME);
8
- if (state === undefined) {
9
- return {
10
- prevVisiblility: {},
11
- positions: {},
12
- subscribers: {},
13
- count: 0,
14
- };
15
- }
16
- return state;
7
+ const state = getValueFromDom(STORAGE_NAME);
8
+ if (state === void 0) {
9
+ return {
10
+ prevVisiblility: {},
11
+ positions: {},
12
+ subscribers: {},
13
+ count: 0
14
+ };
15
+ }
16
+ return state;
17
17
  };
18
18
  const storeState = (state) => {
19
- storeValueInDom(STORAGE_NAME, state);
19
+ storeValueInDom(STORAGE_NAME, state);
20
20
  };
21
21
  const counterFactory = () => {
22
- return {
23
- updateVisiblility: (id, visible) => {
24
- // eslint-disable-next-line prefer-const
25
- const state = getState();
26
- const prevVisible = !!state.prevVisiblility[id];
27
- if (visible === prevVisible) {
28
- return;
29
- }
30
- state.prevVisiblility[id] = visible;
31
- if (visible) {
32
- state.count += 1;
33
- state.positions[id] = state.count;
34
- }
35
- else {
36
- state.count -= 1;
37
- const currentPosition = state.positions[id];
38
- state.positions[id] = 0;
39
- Object.entries(state.positions).forEach(([key, value]) => {
40
- state.positions[key] = value > currentPosition ? value - 1 : value;
41
- });
42
- }
43
- storeState(state);
44
- },
45
- subscribe: (id, callback) => {
46
- const state = getState();
47
- state.subscribers[id] = callback;
48
- storeState(state);
49
- },
50
- unsubscribe: (id) => {
51
- const state = getState();
52
- delete state.subscribers[id];
53
- storeState(state);
54
- },
55
- notifyAll: () => {
56
- const { subscribers, count, positions } = getState();
57
- Object.entries(subscribers).forEach(([id, callback]) => callback({ position: positions[id], count }));
58
- },
59
- };
22
+ return {
23
+ updateVisiblility: (id, visible) => {
24
+ const state = getState();
25
+ const prevVisible = !!state.prevVisiblility[id];
26
+ if (visible === prevVisible) {
27
+ return;
28
+ }
29
+ state.prevVisiblility[id] = visible;
30
+ if (visible) {
31
+ state.count += 1;
32
+ state.positions[id] = state.count;
33
+ } else {
34
+ state.count -= 1;
35
+ const currentPosition = state.positions[id];
36
+ state.positions[id] = 0;
37
+ Object.entries(state.positions).forEach(([key, value]) => {
38
+ state.positions[key] = value > currentPosition ? value - 1 : value;
39
+ });
40
+ }
41
+ storeState(state);
42
+ },
43
+ subscribe: (id, callback) => {
44
+ const state = getState();
45
+ state.subscribers[id] = callback;
46
+ storeState(state);
47
+ },
48
+ unsubscribe: (id) => {
49
+ const state = getState();
50
+ delete state.subscribers[id];
51
+ storeState(state);
52
+ },
53
+ notifyAll: () => {
54
+ const { subscribers, count, positions } = getState();
55
+ Object.entries(subscribers).forEach(([id, callback]) => callback({ position: positions[id], count }));
56
+ }
57
+ };
60
58
  };
61
59
  const counter = counterFactory();
62
60
  const useModalOrder = (visible, modalRef) => {
63
- const [position, setPosition] = useState({ position: 0, count: 0 });
64
- const id = useDomStoredUniqueId();
65
- useLayoutEffect(() => {
66
- counter.updateVisiblility(id, visible);
67
- counter.notifyAll();
68
- // eslint-disable-next-line react-hooks/exhaustive-deps
69
- }, [visible]);
70
- useEffect(() => {
71
- counter.subscribe(id, setPosition);
72
- counter.updateVisiblility(id, visible);
73
- return () => {
74
- counter.unsubscribe(id);
75
- counter.updateVisiblility(id, false);
76
- counter.notifyAll();
77
- };
78
- // eslint-disable-next-line react-hooks/exhaustive-deps
79
- }, [id]);
80
- useLayoutEffect(() => {
81
- // Если это самый "верхний" модал передаем туда фокус
82
- if (position.position === position.count &&
83
- position.count > 0 &&
84
- !modalRef.current?.contains(document.activeElement)) {
85
- modalRef.current?.focus();
86
- }
87
- }, [position, modalRef]);
88
- return [position.position, position.count];
61
+ const [position, setPosition] = useState({ position: 0, count: 0 });
62
+ const id = useDomStoredUniqueId();
63
+ useLayoutEffect(() => {
64
+ counter.updateVisiblility(id, visible);
65
+ counter.notifyAll();
66
+ }, [visible]);
67
+ useEffect(() => {
68
+ counter.subscribe(id, setPosition);
69
+ counter.updateVisiblility(id, visible);
70
+ return () => {
71
+ counter.unsubscribe(id);
72
+ counter.updateVisiblility(id, false);
73
+ counter.notifyAll();
74
+ };
75
+ }, [id]);
76
+ useLayoutEffect(() => {
77
+ if (position.position === position.count && position.count > 0 && !modalRef.current?.contains(document.activeElement)) {
78
+ modalRef.current?.focus();
79
+ }
80
+ }, [position, modalRef]);
81
+ return [position.position, position.count];
89
82
  };
90
83
 
91
84
  export { useModalOrder };
@@ -1 +1 @@
1
- {"version":3,"file":"useModalOrder.js","sources":["src/internal/useModalOrder.ts"],"sourcesContent":["import { RefObject, useEffect, useLayoutEffect, useState } from 'react';\n\nimport { storeValueInDom, getValueFromDom, useDomStoredUniqueId } from '@hh.ru/magritte-common-dom-storage';\n\ntype NotifyCallbackArg = { position: number; count: number };\n\ntype Subscribers = Record<string, (position: NotifyCallbackArg) => void>;\ntype VisibilityMap = Record<string, boolean>;\ntype PositionMap = Record<string, number>;\n\ntype ModalCounterState = {\n prevVisiblility: VisibilityMap;\n positions: PositionMap;\n subscribers: Subscribers;\n count: number;\n};\n\nconst STORAGE_NAME = '_MAGRITTE_MODAL_COUNTER_';\n\nconst getState = (): ModalCounterState => {\n const state = getValueFromDom<ModalCounterState>(STORAGE_NAME);\n if (state === undefined) {\n return {\n prevVisiblility: {},\n positions: {},\n subscribers: {},\n count: 0,\n };\n }\n return state;\n};\n\nconst storeState = (state: ModalCounterState): void => {\n storeValueInDom(STORAGE_NAME, state);\n};\n\nconst counterFactory = () => {\n return {\n updateVisiblility: (id: string, visible: boolean) => {\n // eslint-disable-next-line prefer-const\n const state = getState();\n const prevVisible = !!state.prevVisiblility[id];\n if (visible === prevVisible) {\n return;\n }\n state.prevVisiblility[id] = visible;\n if (visible) {\n state.count += 1;\n state.positions[id] = state.count;\n } else {\n state.count -= 1;\n const currentPosition = state.positions[id];\n state.positions[id] = 0;\n Object.entries(state.positions).forEach(([key, value]) => {\n state.positions[key] = value > currentPosition ? value - 1 : value;\n });\n }\n storeState(state);\n },\n subscribe: (id: string, callback: (position: NotifyCallbackArg) => void) => {\n const state = getState();\n state.subscribers[id] = callback;\n storeState(state);\n },\n unsubscribe: (id: string) => {\n const state = getState();\n delete state.subscribers[id];\n storeState(state);\n },\n notifyAll: () => {\n const { subscribers, count, positions } = getState();\n Object.entries(subscribers).forEach(([id, callback]) => callback({ position: positions[id], count }));\n },\n };\n};\n\nconst counter = counterFactory();\n\nexport const useModalOrder = (visible: boolean, modalRef: RefObject<HTMLDivElement>): [number, number] => {\n const [position, setPosition] = useState<{ position: number; count: number }>({ position: 0, count: 0 });\n const id = useDomStoredUniqueId();\n\n useLayoutEffect(() => {\n counter.updateVisiblility(id, visible);\n counter.notifyAll();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [visible]);\n\n useEffect(() => {\n counter.subscribe(id, setPosition);\n counter.updateVisiblility(id, visible);\n return () => {\n counter.unsubscribe(id);\n counter.updateVisiblility(id, false);\n counter.notifyAll();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [id]);\n\n useLayoutEffect(() => {\n // Если это самый \"верхний\" модал передаем туда фокус\n if (\n position.position === position.count &&\n position.count > 0 &&\n !modalRef.current?.contains(document.activeElement)\n ) {\n modalRef.current?.focus();\n }\n }, [position, modalRef]);\n\n return [position.position, position.count];\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useModalOrder.js","sources":["src/internal/useModalOrder.ts"],"sourcesContent":["import { RefObject, useEffect, useLayoutEffect, useState } from 'react';\n\nimport { storeValueInDom, getValueFromDom, useDomStoredUniqueId } from '@hh.ru/magritte-common-dom-storage';\n\ntype NotifyCallbackArg = { position: number; count: number };\n\ntype Subscribers = Record<string, (position: NotifyCallbackArg) => void>;\ntype VisibilityMap = Record<string, boolean>;\ntype PositionMap = Record<string, number>;\n\ntype ModalCounterState = {\n prevVisiblility: VisibilityMap;\n positions: PositionMap;\n subscribers: Subscribers;\n count: number;\n};\n\nconst STORAGE_NAME = '_MAGRITTE_MODAL_COUNTER_';\n\nconst getState = (): ModalCounterState => {\n const state = getValueFromDom<ModalCounterState>(STORAGE_NAME);\n if (state === undefined) {\n return {\n prevVisiblility: {},\n positions: {},\n subscribers: {},\n count: 0,\n };\n }\n return state;\n};\n\nconst storeState = (state: ModalCounterState): void => {\n storeValueInDom(STORAGE_NAME, state);\n};\n\nconst counterFactory = () => {\n return {\n updateVisiblility: (id: string, visible: boolean) => {\n // eslint-disable-next-line prefer-const\n const state = getState();\n const prevVisible = !!state.prevVisiblility[id];\n if (visible === prevVisible) {\n return;\n }\n state.prevVisiblility[id] = visible;\n if (visible) {\n state.count += 1;\n state.positions[id] = state.count;\n } else {\n state.count -= 1;\n const currentPosition = state.positions[id];\n state.positions[id] = 0;\n Object.entries(state.positions).forEach(([key, value]) => {\n state.positions[key] = value > currentPosition ? value - 1 : value;\n });\n }\n storeState(state);\n },\n subscribe: (id: string, callback: (position: NotifyCallbackArg) => void) => {\n const state = getState();\n state.subscribers[id] = callback;\n storeState(state);\n },\n unsubscribe: (id: string) => {\n const state = getState();\n delete state.subscribers[id];\n storeState(state);\n },\n notifyAll: () => {\n const { subscribers, count, positions } = getState();\n Object.entries(subscribers).forEach(([id, callback]) => callback({ position: positions[id], count }));\n },\n };\n};\n\nconst counter = counterFactory();\n\nexport const useModalOrder = (visible: boolean, modalRef: RefObject<HTMLDivElement>): [number, number] => {\n const [position, setPosition] = useState<{ position: number; count: number }>({ position: 0, count: 0 });\n const id = useDomStoredUniqueId();\n\n useLayoutEffect(() => {\n counter.updateVisiblility(id, visible);\n counter.notifyAll();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [visible]);\n\n useEffect(() => {\n counter.subscribe(id, setPosition);\n counter.updateVisiblility(id, visible);\n return () => {\n counter.unsubscribe(id);\n counter.updateVisiblility(id, false);\n counter.notifyAll();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [id]);\n\n useLayoutEffect(() => {\n // Если это самый \"верхний\" модал передаем туда фокус\n if (\n position.position === position.count &&\n position.count > 0 &&\n !modalRef.current?.contains(document.activeElement)\n ) {\n modalRef.current?.focus();\n }\n }, [position, modalRef]);\n\n return [position.position, position.count];\n};\n"],"names":[],"mappings":"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"}
@@ -6,79 +6,78 @@ import { useModalOrder } from './useModalOrder.js';
6
6
  import '@hh.ru/magritte-common-dom-storage';
7
7
 
8
8
  const INVISIBLE_FOR_BREAKPOINTS = [Breakpoint.XS, Breakpoint.S];
9
- /**
10
- * Жизненный цикл модала вокруг `CSSTransition`: блокировка скролла страницы на время показа, возврат
11
- * фокуса на активатор после закрытия, колбэки `onAppear/onBeforeExit/onAfterExit`, регистрация в стеке
12
- * модалов (`useModalOrder`) и обработка смены брейкпоинта (на XS/S модал скрывается). Возвращает
13
- * хендлеры для `CSSTransition` и флаг «скрыт на текущем брейкпоинте».
14
- */
15
- const useModalTransition = ({ visible, isServerEnv, showOverlay, returnFocusOnClose, onAppear, onBeforeExit, onAfterExit, modalRef, animationTimeoutExit, }) => {
16
- const enableScrollRef = useRef();
17
- const onAfterExitRef = useRef(onAfterExit);
18
- const onBeforeExitRef = useRef(onBeforeExit);
19
- onAfterExitRef.current = onAfterExit;
20
- onBeforeExitRef.current = onBeforeExit;
21
- const animationTimeoutExitRef = useRef(animationTimeoutExit);
22
- animationTimeoutExitRef.current = animationTimeoutExit;
23
- const activatorRef = useRef(null);
24
- const onEntering = useCallback(() => {
25
- if (returnFocusOnClose && document.activeElement instanceof HTMLElement) {
26
- activatorRef.current = document.activeElement;
27
- }
28
- if (!enableScrollRef.current && showOverlay) {
29
- enableScrollRef.current = disableScroll();
30
- }
31
- if (modalRef.current && !modalRef.current.contains(document.activeElement)) {
32
- modalRef.current.focus();
33
- }
34
- }, [returnFocusOnClose, showOverlay, modalRef]);
35
- const onEntered = useCallback(() => {
36
- onAppear?.();
37
- }, [onAppear]);
38
- const onExit = useCallback(() => {
39
- onBeforeExitRef.current?.();
40
- }, []);
41
- const onExited = useCallback(() => {
42
- // оставляем обработку скрола еще и тут
43
- // чтобы обработать историю со сменой breakpoint
44
- enableScrollRef.current?.();
45
- enableScrollRef.current = undefined;
46
- onAfterExitRef.current?.();
47
- if (activatorRef.current !== null && document.contains(activatorRef.current)) {
48
- activatorRef.current?.focus();
49
- activatorRef.current = null;
50
- }
51
- }, []);
52
- useModalOrder(!!visible && !isServerEnv, modalRef);
53
- const { breakpoint } = useBreakpoint();
54
- useEffect(() => {
55
- if (!visible) {
56
- return;
57
- }
58
- const currentBreakpointVisible = !INVISIBLE_FOR_BREAKPOINTS.includes(breakpoint);
59
- if (!currentBreakpointVisible) {
60
- onExit();
61
- onExited();
62
- return;
63
- }
64
- onEntering();
65
- // visible не должно быть в зависимостях, т.к. этот эффект обрабатывает только изменение брейкпоинта
66
- // visible обрабатывается CSSTransition
67
- // eslint-disable-next-line react-hooks/exhaustive-deps
68
- }, [breakpoint, onEntering, onExited, onExit]);
69
- useEffect(() => {
70
- return () => {
71
- enableScrollRef.current?.(animationTimeoutExitRef.current);
72
- enableScrollRef.current = undefined;
73
- };
74
- }, [visible, showOverlay]);
75
- return {
76
- onEntering,
77
- onEntered,
78
- onExit,
79
- onExited,
80
- isHiddenForBreakpoint: INVISIBLE_FOR_BREAKPOINTS.includes(breakpoint),
9
+ const useModalTransition = ({
10
+ visible,
11
+ isServerEnv,
12
+ showOverlay,
13
+ returnFocusOnClose,
14
+ onAppear,
15
+ onBeforeExit,
16
+ onAfterExit,
17
+ modalRef,
18
+ animationTimeoutExit
19
+ }) => {
20
+ const enableScrollRef = useRef();
21
+ const onAfterExitRef = useRef(onAfterExit);
22
+ const onBeforeExitRef = useRef(onBeforeExit);
23
+ onAfterExitRef.current = onAfterExit;
24
+ onBeforeExitRef.current = onBeforeExit;
25
+ const animationTimeoutExitRef = useRef(animationTimeoutExit);
26
+ animationTimeoutExitRef.current = animationTimeoutExit;
27
+ const activatorRef = useRef(null);
28
+ const onEntering = useCallback(() => {
29
+ if (returnFocusOnClose && document.activeElement instanceof HTMLElement) {
30
+ activatorRef.current = document.activeElement;
31
+ }
32
+ if (!enableScrollRef.current && showOverlay) {
33
+ enableScrollRef.current = disableScroll();
34
+ }
35
+ if (modalRef.current && !modalRef.current.contains(document.activeElement)) {
36
+ modalRef.current.focus();
37
+ }
38
+ }, [returnFocusOnClose, showOverlay, modalRef]);
39
+ const onEntered = useCallback(() => {
40
+ onAppear?.();
41
+ }, [onAppear]);
42
+ const onExit = useCallback(() => {
43
+ onBeforeExitRef.current?.();
44
+ }, []);
45
+ const onExited = useCallback(() => {
46
+ enableScrollRef.current?.();
47
+ enableScrollRef.current = void 0;
48
+ onAfterExitRef.current?.();
49
+ if (activatorRef.current !== null && document.contains(activatorRef.current)) {
50
+ activatorRef.current?.focus();
51
+ activatorRef.current = null;
52
+ }
53
+ }, []);
54
+ useModalOrder(!!visible && !isServerEnv, modalRef);
55
+ const { breakpoint } = useBreakpoint();
56
+ useEffect(() => {
57
+ if (!visible) {
58
+ return;
59
+ }
60
+ const currentBreakpointVisible = !INVISIBLE_FOR_BREAKPOINTS.includes(breakpoint);
61
+ if (!currentBreakpointVisible) {
62
+ onExit();
63
+ onExited();
64
+ return;
65
+ }
66
+ onEntering();
67
+ }, [breakpoint, onEntering, onExited, onExit]);
68
+ useEffect(() => {
69
+ return () => {
70
+ enableScrollRef.current?.(animationTimeoutExitRef.current);
71
+ enableScrollRef.current = void 0;
81
72
  };
73
+ }, [visible, showOverlay]);
74
+ return {
75
+ onEntering,
76
+ onEntered,
77
+ onExit,
78
+ onExited,
79
+ isHiddenForBreakpoint: INVISIBLE_FOR_BREAKPOINTS.includes(breakpoint)
80
+ };
82
81
  };
83
82
 
84
83
  export { useModalTransition };
@@ -1 +1 @@
1
- {"version":3,"file":"useModalTransition.js","sources":["src/internal/useModalTransition.ts"],"sourcesContent":["import { type RefObject, useCallback, useEffect, useRef } from 'react';\n\nimport { disableScroll, type TimeoutCallback } from '@hh.ru/magritte-common-modal-helper';\nimport { Breakpoint, useBreakpoint } from '@hh.ru/magritte-ui-breakpoint';\nimport { useModalOrder } from '@hh.ru/magritte-ui-modal/internal/useModalOrder';\n\nconst INVISIBLE_FOR_BREAKPOINTS = [Breakpoint.XS, Breakpoint.S];\n\ninterface UseModalTransitionParams {\n visible: boolean | undefined;\n isServerEnv: boolean;\n showOverlay: boolean;\n returnFocusOnClose: boolean | undefined;\n onAppear?: VoidFunction;\n onBeforeExit?: VoidFunction;\n onAfterExit?: VoidFunction;\n modalRef: RefObject<HTMLDivElement>;\n /** Длительность анимации закрытия (мс) — с ней разблокируется скролл при размонтировании. */\n animationTimeoutExit: number;\n}\n\ninterface UseModalTransitionResult {\n onEntering: VoidFunction;\n onEntered: VoidFunction;\n onExit: VoidFunction;\n onExited: VoidFunction;\n /** Текущий брейкпоинт входит в число тех, на которых модал не рендерится (XS/S). */\n isHiddenForBreakpoint: boolean;\n}\n\n/**\n * Жизненный цикл модала вокруг `CSSTransition`: блокировка скролла страницы на время показа, возврат\n * фокуса на активатор после закрытия, колбэки `onAppear/onBeforeExit/onAfterExit`, регистрация в стеке\n * модалов (`useModalOrder`) и обработка смены брейкпоинта (на XS/S модал скрывается). Возвращает\n * хендлеры для `CSSTransition` и флаг «скрыт на текущем брейкпоинте».\n */\nexport const useModalTransition = ({\n visible,\n isServerEnv,\n showOverlay,\n returnFocusOnClose,\n onAppear,\n onBeforeExit,\n onAfterExit,\n modalRef,\n animationTimeoutExit,\n}: UseModalTransitionParams): UseModalTransitionResult => {\n const enableScrollRef = useRef<TimeoutCallback>();\n const onAfterExitRef = useRef(onAfterExit);\n const onBeforeExitRef = useRef(onBeforeExit);\n onAfterExitRef.current = onAfterExit;\n onBeforeExitRef.current = onBeforeExit;\n const animationTimeoutExitRef = useRef(animationTimeoutExit);\n animationTimeoutExitRef.current = animationTimeoutExit;\n\n const activatorRef = useRef<HTMLElement | null>(null);\n\n const onEntering = useCallback(() => {\n if (returnFocusOnClose && document.activeElement instanceof HTMLElement) {\n activatorRef.current = document.activeElement;\n }\n if (!enableScrollRef.current && showOverlay) {\n enableScrollRef.current = disableScroll();\n }\n if (modalRef.current && !modalRef.current.contains(document.activeElement)) {\n modalRef.current.focus();\n }\n }, [returnFocusOnClose, showOverlay, modalRef]);\n\n const onEntered = useCallback(() => {\n onAppear?.();\n }, [onAppear]);\n\n const onExit = useCallback(() => {\n onBeforeExitRef.current?.();\n }, []);\n\n const onExited = useCallback(() => {\n // оставляем обработку скрола еще и тут\n // чтобы обработать историю со сменой breakpoint\n enableScrollRef.current?.();\n enableScrollRef.current = undefined;\n\n onAfterExitRef.current?.();\n\n if (activatorRef.current !== null && document.contains(activatorRef.current)) {\n activatorRef.current?.focus();\n activatorRef.current = null;\n }\n }, []);\n\n useModalOrder(!!visible && !isServerEnv, modalRef);\n\n const { breakpoint } = useBreakpoint();\n useEffect(() => {\n if (!visible) {\n return;\n }\n\n const currentBreakpointVisible = !INVISIBLE_FOR_BREAKPOINTS.includes(breakpoint);\n if (!currentBreakpointVisible) {\n onExit();\n onExited();\n return;\n }\n\n onEntering();\n // visible не должно быть в зависимостях, т.к. этот эффект обрабатывает только изменение брейкпоинта\n // visible обрабатывается CSSTransition\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [breakpoint, onEntering, onExited, onExit]);\n\n useEffect(() => {\n return () => {\n enableScrollRef.current?.(animationTimeoutExitRef.current);\n enableScrollRef.current = undefined;\n };\n }, [visible, showOverlay]);\n\n return {\n onEntering,\n onEntered,\n onExit,\n onExited,\n isHiddenForBreakpoint: INVISIBLE_FOR_BREAKPOINTS.includes(breakpoint),\n };\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useModalTransition.js","sources":["src/internal/useModalTransition.ts"],"sourcesContent":["import { type RefObject, useCallback, useEffect, useRef } from 'react';\n\nimport { disableScroll, type TimeoutCallback } from '@hh.ru/magritte-common-modal-helper';\nimport { Breakpoint, useBreakpoint } from '@hh.ru/magritte-ui-breakpoint';\nimport { useModalOrder } from '@hh.ru/magritte-ui-modal/internal/useModalOrder';\n\nconst INVISIBLE_FOR_BREAKPOINTS = [Breakpoint.XS, Breakpoint.S];\n\ninterface UseModalTransitionParams {\n visible: boolean | undefined;\n isServerEnv: boolean;\n showOverlay: boolean;\n returnFocusOnClose: boolean | undefined;\n onAppear?: VoidFunction;\n onBeforeExit?: VoidFunction;\n onAfterExit?: VoidFunction;\n modalRef: RefObject<HTMLDivElement>;\n /** Длительность анимации закрытия (мс) — с ней разблокируется скролл при размонтировании. */\n animationTimeoutExit: number;\n}\n\ninterface UseModalTransitionResult {\n onEntering: VoidFunction;\n onEntered: VoidFunction;\n onExit: VoidFunction;\n onExited: VoidFunction;\n /** Текущий брейкпоинт входит в число тех, на которых модал не рендерится (XS/S). */\n isHiddenForBreakpoint: boolean;\n}\n\n/**\n * Жизненный цикл модала вокруг `CSSTransition`: блокировка скролла страницы на время показа, возврат\n * фокуса на активатор после закрытия, колбэки `onAppear/onBeforeExit/onAfterExit`, регистрация в стеке\n * модалов (`useModalOrder`) и обработка смены брейкпоинта (на XS/S модал скрывается). Возвращает\n * хендлеры для `CSSTransition` и флаг «скрыт на текущем брейкпоинте».\n */\nexport const useModalTransition = ({\n visible,\n isServerEnv,\n showOverlay,\n returnFocusOnClose,\n onAppear,\n onBeforeExit,\n onAfterExit,\n modalRef,\n animationTimeoutExit,\n}: UseModalTransitionParams): UseModalTransitionResult => {\n const enableScrollRef = useRef<TimeoutCallback>();\n const onAfterExitRef = useRef(onAfterExit);\n const onBeforeExitRef = useRef(onBeforeExit);\n onAfterExitRef.current = onAfterExit;\n onBeforeExitRef.current = onBeforeExit;\n const animationTimeoutExitRef = useRef(animationTimeoutExit);\n animationTimeoutExitRef.current = animationTimeoutExit;\n\n const activatorRef = useRef<HTMLElement | null>(null);\n\n const onEntering = useCallback(() => {\n if (returnFocusOnClose && document.activeElement instanceof HTMLElement) {\n activatorRef.current = document.activeElement;\n }\n if (!enableScrollRef.current && showOverlay) {\n enableScrollRef.current = disableScroll();\n }\n if (modalRef.current && !modalRef.current.contains(document.activeElement)) {\n modalRef.current.focus();\n }\n }, [returnFocusOnClose, showOverlay, modalRef]);\n\n const onEntered = useCallback(() => {\n onAppear?.();\n }, [onAppear]);\n\n const onExit = useCallback(() => {\n onBeforeExitRef.current?.();\n }, []);\n\n const onExited = useCallback(() => {\n // оставляем обработку скрола еще и тут\n // чтобы обработать историю со сменой breakpoint\n enableScrollRef.current?.();\n enableScrollRef.current = undefined;\n\n onAfterExitRef.current?.();\n\n if (activatorRef.current !== null && document.contains(activatorRef.current)) {\n activatorRef.current?.focus();\n activatorRef.current = null;\n }\n }, []);\n\n useModalOrder(!!visible && !isServerEnv, modalRef);\n\n const { breakpoint } = useBreakpoint();\n useEffect(() => {\n if (!visible) {\n return;\n }\n\n const currentBreakpointVisible = !INVISIBLE_FOR_BREAKPOINTS.includes(breakpoint);\n if (!currentBreakpointVisible) {\n onExit();\n onExited();\n return;\n }\n\n onEntering();\n // visible не должно быть в зависимостях, т.к. этот эффект обрабатывает только изменение брейкпоинта\n // visible обрабатывается CSSTransition\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [breakpoint, onEntering, onExited, onExit]);\n\n useEffect(() => {\n return () => {\n enableScrollRef.current?.(animationTimeoutExitRef.current);\n enableScrollRef.current = undefined;\n };\n }, [visible, showOverlay]);\n\n return {\n onEntering,\n onEntered,\n onExit,\n onExited,\n isHiddenForBreakpoint: INVISIBLE_FOR_BREAKPOINTS.includes(breakpoint),\n };\n};\n"],"names":[],"mappings":"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"}