@alfalab/core-components-popover 5.3.0 → 5.6.1

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.
@@ -1,8 +1,10 @@
1
- import React, { forwardRef, useState, useCallback, useEffect } from 'react';
1
+ import React, { forwardRef, useState, useRef, useCallback, useEffect } from 'react';
2
2
  import cn from 'classnames';
3
3
  import { CSSTransition } from 'react-transition-group';
4
4
  import { usePopper } from 'react-popper';
5
+ import maxSize from 'popper-max-size-modifier';
5
6
  import mergeRefs from 'react-merge-refs';
7
+ import { ResizeObserver } from 'resize-observer';
6
8
  import { stackingOrder, Stack } from '@alfalab/core-components-stack/dist/esm';
7
9
  import { Portal } from '@alfalab/core-components-portal/dist/esm';
8
10
 
@@ -33,7 +35,7 @@ var __assign = function () {
33
35
  return __assign.apply(this, arguments);
34
36
  };
35
37
 
36
- var styles = {"component":"popover__component_4qqzo","inner":"popover__inner_4qqzo","arrow":"popover__arrow_4qqzo","enter":"popover__enter_4qqzo","enterActive":"popover__enterActive_4qqzo","exit":"popover__exit_4qqzo","exitActive":"popover__exitActive_4qqzo"};
38
+ var styles = {"component":"popover__component_dvtgo","inner":"popover__inner_dvtgo","scrollableContent":"popover__scrollableContent_dvtgo","arrow":"popover__arrow_dvtgo","arrowShift":"popover__arrowShift_dvtgo","enter":"popover__enter_dvtgo","enterActive":"popover__enterActive_dvtgo","exit":"popover__exit_dvtgo","exitActive":"popover__exitActive_dvtgo"};
37
39
  require('./index.css')
38
40
 
39
41
  var DEFAULT_TRANSITION = {
@@ -45,11 +47,32 @@ var CSS_TRANSITION_CLASS_NAMES = {
45
47
  exit: styles.exit,
46
48
  exitActive: styles.exitActive,
47
49
  };
50
+ var availableHieghtModifier = {
51
+ name: 'availableHeight',
52
+ enabled: true,
53
+ phase: 'beforeWrite',
54
+ requires: ['maxSize'],
55
+ fn: function (_a) {
56
+ var _b = _a.state, modifiersData = _b.modifiersData, popper = _b.elements.popper;
57
+ var height = modifiersData.maxSize.height;
58
+ var content = popper.querySelector("." + styles.scrollableContent);
59
+ if (content && !content.style.maxHeight) {
60
+ content.style.maxHeight = height + "px";
61
+ }
62
+ },
63
+ };
64
+ /**
65
+ * Минимальный размер anchorElement,
66
+ * при котором возможно смещение стрелочки относительно центра
67
+ */
68
+ var MIN_ARROW_SHIFT_SIZE = 75;
48
69
  var Popover = forwardRef(function (_a, ref) {
49
- var children = _a.children, getPortalContainer = _a.getPortalContainer, _b = _a.transition, transition = _b === void 0 ? DEFAULT_TRANSITION : _b, anchorElement = _a.anchorElement, _c = _a.offset, offset = _c === void 0 ? [0, 0] : _c, _d = _a.withArrow, withArrow = _d === void 0 ? false : _d, _e = _a.withTransition, withTransition = _e === void 0 ? true : _e, _f = _a.position, position = _f === void 0 ? 'left' : _f, preventFlip = _a.preventFlip, popperClassName = _a.popperClassName, arrowClassName = _a.arrowClassName, className = _a.className, open = _a.open, dataTestId = _a.dataTestId, update = _a.update, _g = _a.transitionDuration, transitionDuration = _g === void 0 ? transition.timeout + "ms" : _g, _h = _a.zIndex, zIndex = _h === void 0 ? stackingOrder.POPOVER : _h, fallbackPlacements = _a.fallbackPlacements, _j = _a.preventOverflow, preventOverflow = _j === void 0 ? true : _j;
50
- var _k = useState(anchorElement), referenceElement = _k[0], setReferenceElement = _k[1];
51
- var _l = useState(null), popperElement = _l[0], setPopperElement = _l[1];
52
- var _m = useState(null), arrowElement = _m[0], setArrowElement = _m[1];
70
+ var children = _a.children, getPortalContainer = _a.getPortalContainer, _b = _a.transition, transition = _b === void 0 ? DEFAULT_TRANSITION : _b, anchorElement = _a.anchorElement, useAnchorWidth = _a.useAnchorWidth, _c = _a.offset, offset = _c === void 0 ? [0, 0] : _c, _d = _a.withArrow, withArrow = _d === void 0 ? false : _d, _e = _a.withTransition, withTransition = _e === void 0 ? true : _e, _f = _a.position, position = _f === void 0 ? 'left' : _f, preventFlip = _a.preventFlip, popperClassName = _a.popperClassName, arrowClassName = _a.arrowClassName, className = _a.className, open = _a.open, dataTestId = _a.dataTestId, update = _a.update, _g = _a.transitionDuration, transitionDuration = _g === void 0 ? transition.timeout + "ms" : _g, _h = _a.zIndex, zIndex = _h === void 0 ? stackingOrder.POPOVER : _h, fallbackPlacements = _a.fallbackPlacements, _j = _a.preventOverflow, preventOverflow = _j === void 0 ? true : _j, _k = _a.availableHeight, availableHeight = _k === void 0 ? false : _k;
71
+ var _l = useState(anchorElement), referenceElement = _l[0], setReferenceElement = _l[1];
72
+ var _m = useState(null), popperElement = _m[0], setPopperElement = _m[1];
73
+ var _o = useState(null), arrowElement = _o[0], setArrowElement = _o[1];
74
+ var _p = useState(false), arrowShift = _p[0], setArrowShift = _p[1];
75
+ var updatePopperRef = useRef();
53
76
  var getModifiers = useCallback(function () {
54
77
  var modifiers = [{ name: 'offset', options: { offset: offset } }];
55
78
  if (withArrow) {
@@ -64,12 +87,32 @@ var Popover = forwardRef(function (_a, ref) {
64
87
  if (preventOverflow) {
65
88
  modifiers.push({ name: 'preventOverflow', options: { mainAxis: false } });
66
89
  }
90
+ if (availableHeight) {
91
+ modifiers.push(__assign(__assign({}, maxSize), { options: {} }));
92
+ modifiers.push(__assign(__assign({}, availableHieghtModifier), { options: {} }));
93
+ }
67
94
  return modifiers;
68
- }, [offset, withArrow, preventFlip, fallbackPlacements, preventOverflow, arrowElement]);
69
- var _o = usePopper(referenceElement, popperElement, {
95
+ }, [
96
+ offset,
97
+ withArrow,
98
+ preventFlip,
99
+ fallbackPlacements,
100
+ preventOverflow,
101
+ availableHeight,
102
+ arrowElement,
103
+ ]);
104
+ var _q = usePopper(referenceElement, popperElement, {
70
105
  placement: position,
71
106
  modifiers: getModifiers(),
72
- }), popperStyles = _o.styles, attributes = _o.attributes, updatePopper = _o.update;
107
+ }), popperStyles = _q.styles, attributes = _q.attributes, updatePopper = _q.update;
108
+ if (updatePopper) {
109
+ updatePopperRef.current = updatePopper;
110
+ }
111
+ var updatePopoverWidth = useCallback(function () {
112
+ if (useAnchorWidth && updatePopperRef.current) {
113
+ updatePopperRef.current();
114
+ }
115
+ }, [useAnchorWidth]);
73
116
  useEffect(function () {
74
117
  setReferenceElement(anchorElement);
75
118
  }, [anchorElement]);
@@ -84,12 +127,39 @@ var Popover = forwardRef(function (_a, ref) {
84
127
  update.current = updatePopper;
85
128
  }
86
129
  });
130
+ useEffect(function () {
131
+ if (useAnchorWidth) {
132
+ var observer_1 = new ResizeObserver(updatePopoverWidth);
133
+ if (anchorElement) {
134
+ observer_1.observe(anchorElement);
135
+ }
136
+ return function () {
137
+ observer_1.disconnect();
138
+ };
139
+ }
140
+ return function () { return ({}); };
141
+ }, [anchorElement, updatePopoverWidth, useAnchorWidth]);
142
+ /**
143
+ * По дизайну, если у тултипа позиционирование -start/-end, то стрелочка немного сдвигается вбок.
144
+ * Но если anchorElement слишком маленький, то стрелочка сдвигаться не должна.
145
+ */
146
+ useEffect(function () {
147
+ var shiftedPosition = position.includes('-start') || position.includes('-end');
148
+ if (shiftedPosition && referenceElement) {
149
+ var _a = referenceElement.getBoundingClientRect(), width = _a.width, height = _a.height;
150
+ var size = position.includes('left') || position.includes('right') ? height : width;
151
+ if (size >= MIN_ARROW_SHIFT_SIZE) {
152
+ setArrowShift(true);
153
+ }
154
+ }
155
+ }, [referenceElement, position]);
87
156
  var renderContent = function (computedZIndex, style) {
88
- return (React.createElement("div", __assign({ ref: mergeRefs([ref, setPopperElement]),
89
- // ref={setPopperElement}
90
- style: __assign({ zIndex: computedZIndex }, popperStyles.popper), "data-test-id": dataTestId, className: cn(styles.component, className) }, attributes.popper),
157
+ var _a, _b;
158
+ return (React.createElement("div", __assign({ ref: mergeRefs([ref, setPopperElement]), style: __assign({ zIndex: computedZIndex, width: useAnchorWidth ? referenceElement === null || referenceElement === void 0 ? void 0 : referenceElement.offsetWidth : undefined }, popperStyles.popper), "data-test-id": dataTestId, className: cn(styles.component, className, (_a = {},
159
+ _a[styles.arrowShift] = arrowShift,
160
+ _a)) }, attributes.popper),
91
161
  React.createElement("div", { className: cn(styles.inner, popperClassName), style: style },
92
- children,
162
+ React.createElement("div", { className: cn((_b = {}, _b[styles.scrollableContent] = availableHeight, _b)) }, children),
93
163
  withArrow && (React.createElement("div", { ref: setArrowElement, style: popperStyles.arrow, className: cn(styles.arrow, arrowClassName) })))));
94
164
  };
95
165
  return (React.createElement(Stack, { value: zIndex }, function (computedZIndex) { return (React.createElement(Portal, { getPortalContainer: getPortalContainer }, withTransition ? (React.createElement(CSSTransition, __assign({ unmountOnExit: true, classNames: CSS_TRANSITION_CLASS_NAMES }, transition, { in: open }), renderContent(computedZIndex, { transitionDuration: transitionDuration }))) : (open && renderContent(computedZIndex)))); }));
@@ -1,13 +1,10 @@
1
- /* hash: 4qqzo */
1
+ /* hash: 5ddm6 */
2
2
  :root {
3
3
  --color-light-bg-primary: #fff;
4
4
  --color-light-text-primary: #0b1f35;
5
-
6
- /* TODO: цвета добавлены руками. Обновить токены */
7
- --color-light-text-secondary-inverted-transparent: rgba(255, 255, 255, 0.7);
8
5
  }
9
6
  :root {
10
- --shadow-l: 0 0 24px rgba(11, 31, 53, 0.12), 0 12px 24px rgba(11, 31, 53, 0.24);
7
+ --shadow-m: 0 0 16px rgba(11, 31, 53, 0.08), 0 8px 16px rgba(11, 31, 53, 0.16);
11
8
 
12
9
  /* Hard */
13
10
 
@@ -18,83 +15,116 @@
18
15
  :root {
19
16
  --popover-border-color: transparent;
20
17
  }
21
- .popover__component_4qqzo {
18
+ .popover__component_dvtgo {
22
19
  background-color: transparent;
23
20
  color: var(--color-light-text-primary);
24
21
  }
25
- .popover__inner_4qqzo {
22
+ .popover__inner_dvtgo {
26
23
  position: relative;
27
24
  background-color: var(--color-light-bg-primary);
28
- box-shadow: var(--shadow-l);
25
+ box-shadow: var(--shadow-m);
29
26
  border: 1px solid var(--popover-border-color);
30
27
  transition-property: opacity, transform;
31
28
  transition-timing-function: ease-in-out;
32
29
  box-sizing: border-box;
33
30
  will-change: transform;
34
31
  }
35
- .popover__arrow_4qqzo:after {
32
+ .popover__scrollableContent_dvtgo {
33
+ position: relative;
34
+ z-index: 2;
35
+ overflow-y: auto;
36
+ }
37
+ .popover__arrow_dvtgo {
38
+ z-index: 1;
39
+ }
40
+ .popover__arrow_dvtgo:after {
36
41
  content: '';
37
42
  display: block;
38
43
  position: absolute;
39
- width: 10px;
40
- height: 10px;
44
+ width: 12px;
45
+ height: 12px;
41
46
  background-color: var(--color-light-bg-primary);
42
47
  border: 1px solid var(--popover-border-color);
48
+ box-sizing: border-box;
43
49
  transform: rotate(45deg);
44
50
  }
45
- .popover__component_4qqzo[data-popper-placement='left'] .popover__arrow_4qqzo,
46
- .popover__component_4qqzo[data-popper-placement='left-start'] .popover__arrow_4qqzo,
47
- .popover__component_4qqzo[data-popper-placement='left-end'] .popover__arrow_4qqzo {
51
+ .popover__component_dvtgo[data-popper-placement='left'] .popover__arrow_dvtgo,
52
+ .popover__component_dvtgo[data-popper-placement='left-start'] .popover__arrow_dvtgo,
53
+ .popover__component_dvtgo[data-popper-placement='left-end'] .popover__arrow_dvtgo {
48
54
  right: 5px
49
55
  }
50
- .popover__component_4qqzo[data-popper-placement='left'] .popover__arrow_4qqzo:after, .popover__component_4qqzo[data-popper-placement='left-start'] .popover__arrow_4qqzo:after, .popover__component_4qqzo[data-popper-placement='left-end'] .popover__arrow_4qqzo:after {
51
- top: -4px;
56
+ .popover__component_dvtgo[data-popper-placement='left'] .popover__arrow_dvtgo:after, .popover__component_dvtgo[data-popper-placement='left-start'] .popover__arrow_dvtgo:after, .popover__component_dvtgo[data-popper-placement='left-end'] .popover__arrow_dvtgo:after {
57
+ top: -6px;
52
58
  border-bottom: none;
53
59
  border-left: none;
54
60
  }
55
- .popover__component_4qqzo[data-popper-placement='right'] .popover__arrow_4qqzo,
56
- .popover__component_4qqzo[data-popper-placement='right-start'] .popover__arrow_4qqzo,
57
- .popover__component_4qqzo[data-popper-placement='right-end'] .popover__arrow_4qqzo {
58
- left: -6px
61
+ .popover__component_dvtgo[data-popper-placement='left-start'].popover__arrowShift_dvtgo .popover__arrow_dvtgo:after {
62
+ top: -7px;
63
+ }
64
+ .popover__component_dvtgo[data-popper-placement='left-end'].popover__arrowShift_dvtgo .popover__arrow_dvtgo:after {
65
+ top: -5px;
66
+ }
67
+ .popover__component_dvtgo[data-popper-placement='right'] .popover__arrow_dvtgo,
68
+ .popover__component_dvtgo[data-popper-placement='right-start'] .popover__arrow_dvtgo,
69
+ .popover__component_dvtgo[data-popper-placement='right-end'] .popover__arrow_dvtgo {
70
+ left: -7px
59
71
  }
60
- .popover__component_4qqzo[data-popper-placement='right'] .popover__arrow_4qqzo:after, .popover__component_4qqzo[data-popper-placement='right-start'] .popover__arrow_4qqzo:after, .popover__component_4qqzo[data-popper-placement='right-end'] .popover__arrow_4qqzo:after {
61
- top: -4px;
72
+ .popover__component_dvtgo[data-popper-placement='right'] .popover__arrow_dvtgo:after, .popover__component_dvtgo[data-popper-placement='right-start'] .popover__arrow_dvtgo:after, .popover__component_dvtgo[data-popper-placement='right-end'] .popover__arrow_dvtgo:after {
73
+ top: -6px;
62
74
  border-top: none;
63
75
  border-right: none;
64
76
  }
65
- .popover__component_4qqzo[data-popper-placement='top'] .popover__arrow_4qqzo,
66
- .popover__component_4qqzo[data-popper-placement='top-start'] .popover__arrow_4qqzo,
67
- .popover__component_4qqzo[data-popper-placement='top-end'] .popover__arrow_4qqzo {
77
+ .popover__component_dvtgo[data-popper-placement='right-start'].popover__arrowShift_dvtgo .popover__arrow_dvtgo:after {
78
+ top: -7px;
79
+ }
80
+ .popover__component_dvtgo[data-popper-placement='right-end'].popover__arrowShift_dvtgo .popover__arrow_dvtgo:after {
81
+ top: -5px;
82
+ }
83
+ .popover__component_dvtgo[data-popper-placement='top'] .popover__arrow_dvtgo,
84
+ .popover__component_dvtgo[data-popper-placement='top-start'] .popover__arrow_dvtgo,
85
+ .popover__component_dvtgo[data-popper-placement='top-end'] .popover__arrow_dvtgo {
68
86
  bottom: 5px
69
87
  }
70
- .popover__component_4qqzo[data-popper-placement='top'] .popover__arrow_4qqzo:after, .popover__component_4qqzo[data-popper-placement='top-start'] .popover__arrow_4qqzo:after, .popover__component_4qqzo[data-popper-placement='top-end'] .popover__arrow_4qqzo:after {
71
- left: -4px;
88
+ .popover__component_dvtgo[data-popper-placement='top'] .popover__arrow_dvtgo:after, .popover__component_dvtgo[data-popper-placement='top-start'] .popover__arrow_dvtgo:after, .popover__component_dvtgo[data-popper-placement='top-end'] .popover__arrow_dvtgo:after {
89
+ left: -6px;
72
90
  border-top: none;
73
91
  border-left: none;
74
92
  }
75
- .popover__component_4qqzo[data-popper-placement='bottom'] .popover__arrow_4qqzo,
76
- .popover__component_4qqzo[data-popper-placement='bottom-start'] .popover__arrow_4qqzo,
77
- .popover__component_4qqzo[data-popper-placement='bottom-end'] .popover__arrow_4qqzo {
78
- top: -6px
93
+ .popover__component_dvtgo[data-popper-placement='top-start'].popover__arrowShift_dvtgo .popover__arrow_dvtgo:after {
94
+ left: -17px;
95
+ }
96
+ .popover__component_dvtgo[data-popper-placement='top-end'].popover__arrowShift_dvtgo .popover__arrow_dvtgo:after {
97
+ left: 5px;
79
98
  }
80
- .popover__component_4qqzo[data-popper-placement='bottom'] .popover__arrow_4qqzo:after, .popover__component_4qqzo[data-popper-placement='bottom-start'] .popover__arrow_4qqzo:after, .popover__component_4qqzo[data-popper-placement='bottom-end'] .popover__arrow_4qqzo:after {
81
- left: -4px;
99
+ .popover__component_dvtgo[data-popper-placement='bottom'] .popover__arrow_dvtgo,
100
+ .popover__component_dvtgo[data-popper-placement='bottom-start'] .popover__arrow_dvtgo,
101
+ .popover__component_dvtgo[data-popper-placement='bottom-end'] .popover__arrow_dvtgo {
102
+ top: -7px
103
+ }
104
+ .popover__component_dvtgo[data-popper-placement='bottom'] .popover__arrow_dvtgo:after, .popover__component_dvtgo[data-popper-placement='bottom-start'] .popover__arrow_dvtgo:after, .popover__component_dvtgo[data-popper-placement='bottom-end'] .popover__arrow_dvtgo:after {
105
+ left: -6px;
82
106
  border-bottom: none;
83
107
  border-right: none;
84
108
  }
85
- .popover__enter_4qqzo .popover__inner_4qqzo {
109
+ .popover__component_dvtgo[data-popper-placement='bottom-start'].popover__arrowShift_dvtgo .popover__arrow_dvtgo:after {
110
+ left: -17px;
111
+ }
112
+ .popover__component_dvtgo[data-popper-placement='bottom-end'].popover__arrowShift_dvtgo .popover__arrow_dvtgo:after {
113
+ left: 5px;
114
+ }
115
+ .popover__enter_dvtgo .popover__inner_dvtgo {
86
116
  opacity: 0;
87
117
  transform: scale(0.98);
88
118
  }
89
- .popover__enterActive_4qqzo .popover__inner_4qqzo {
119
+ .popover__enterActive_dvtgo .popover__inner_dvtgo {
90
120
  opacity: 1;
91
121
  transform: scale(1);
92
122
  }
93
- .popover__exit_4qqzo .popover__inner_4qqzo {
123
+ .popover__exit_dvtgo .popover__inner_dvtgo {
94
124
  opacity: 1;
95
125
  transform: scale(1);
96
126
  }
97
- .popover__exitActive_4qqzo .popover__inner_4qqzo {
127
+ .popover__exitActive_dvtgo .popover__inner_dvtgo {
98
128
  opacity: 0;
99
129
  transform: scale(0.98);
100
130
  }
package/dist/esm/index.js CHANGED
@@ -3,6 +3,8 @@ import 'react';
3
3
  import 'classnames';
4
4
  import 'react-transition-group';
5
5
  import 'react-popper';
6
+ import 'popper-max-size-modifier';
6
7
  import 'react-merge-refs';
8
+ import 'resize-observer';
7
9
  import '@alfalab/core-components-stack/dist/esm';
8
10
  import '@alfalab/core-components-portal/dist/esm';
package/dist/index.css CHANGED
@@ -1,13 +1,10 @@
1
- /* hash: 4qqzo */
1
+ /* hash: 5ddm6 */
2
2
  :root {
3
3
  --color-light-bg-primary: #fff;
4
4
  --color-light-text-primary: #0b1f35;
5
-
6
- /* TODO: цвета добавлены руками. Обновить токены */
7
- --color-light-text-secondary-inverted-transparent: rgba(255, 255, 255, 0.7);
8
5
  }
9
6
  :root {
10
- --shadow-l: 0 0 24px rgba(11, 31, 53, 0.12), 0 12px 24px rgba(11, 31, 53, 0.24);
7
+ --shadow-m: 0 0 16px rgba(11, 31, 53, 0.08), 0 8px 16px rgba(11, 31, 53, 0.16);
11
8
 
12
9
  /* Hard */
13
10
 
@@ -18,83 +15,116 @@
18
15
  :root {
19
16
  --popover-border-color: transparent;
20
17
  }
21
- .popover__component_4qqzo {
18
+ .popover__component_dvtgo {
22
19
  background-color: transparent;
23
20
  color: var(--color-light-text-primary);
24
21
  }
25
- .popover__inner_4qqzo {
22
+ .popover__inner_dvtgo {
26
23
  position: relative;
27
24
  background-color: var(--color-light-bg-primary);
28
- box-shadow: var(--shadow-l);
25
+ box-shadow: var(--shadow-m);
29
26
  border: 1px solid var(--popover-border-color);
30
27
  transition-property: opacity, transform;
31
28
  transition-timing-function: ease-in-out;
32
29
  box-sizing: border-box;
33
30
  will-change: transform;
34
31
  }
35
- .popover__arrow_4qqzo:after {
32
+ .popover__scrollableContent_dvtgo {
33
+ position: relative;
34
+ z-index: 2;
35
+ overflow-y: auto;
36
+ }
37
+ .popover__arrow_dvtgo {
38
+ z-index: 1;
39
+ }
40
+ .popover__arrow_dvtgo:after {
36
41
  content: '';
37
42
  display: block;
38
43
  position: absolute;
39
- width: 10px;
40
- height: 10px;
44
+ width: 12px;
45
+ height: 12px;
41
46
  background-color: var(--color-light-bg-primary);
42
47
  border: 1px solid var(--popover-border-color);
48
+ box-sizing: border-box;
43
49
  transform: rotate(45deg);
44
50
  }
45
- .popover__component_4qqzo[data-popper-placement='left'] .popover__arrow_4qqzo,
46
- .popover__component_4qqzo[data-popper-placement='left-start'] .popover__arrow_4qqzo,
47
- .popover__component_4qqzo[data-popper-placement='left-end'] .popover__arrow_4qqzo {
51
+ .popover__component_dvtgo[data-popper-placement='left'] .popover__arrow_dvtgo,
52
+ .popover__component_dvtgo[data-popper-placement='left-start'] .popover__arrow_dvtgo,
53
+ .popover__component_dvtgo[data-popper-placement='left-end'] .popover__arrow_dvtgo {
48
54
  right: 5px
49
55
  }
50
- .popover__component_4qqzo[data-popper-placement='left'] .popover__arrow_4qqzo:after, .popover__component_4qqzo[data-popper-placement='left-start'] .popover__arrow_4qqzo:after, .popover__component_4qqzo[data-popper-placement='left-end'] .popover__arrow_4qqzo:after {
51
- top: -4px;
56
+ .popover__component_dvtgo[data-popper-placement='left'] .popover__arrow_dvtgo:after, .popover__component_dvtgo[data-popper-placement='left-start'] .popover__arrow_dvtgo:after, .popover__component_dvtgo[data-popper-placement='left-end'] .popover__arrow_dvtgo:after {
57
+ top: -6px;
52
58
  border-bottom: none;
53
59
  border-left: none;
54
60
  }
55
- .popover__component_4qqzo[data-popper-placement='right'] .popover__arrow_4qqzo,
56
- .popover__component_4qqzo[data-popper-placement='right-start'] .popover__arrow_4qqzo,
57
- .popover__component_4qqzo[data-popper-placement='right-end'] .popover__arrow_4qqzo {
58
- left: -6px
61
+ .popover__component_dvtgo[data-popper-placement='left-start'].popover__arrowShift_dvtgo .popover__arrow_dvtgo:after {
62
+ top: -7px;
63
+ }
64
+ .popover__component_dvtgo[data-popper-placement='left-end'].popover__arrowShift_dvtgo .popover__arrow_dvtgo:after {
65
+ top: -5px;
66
+ }
67
+ .popover__component_dvtgo[data-popper-placement='right'] .popover__arrow_dvtgo,
68
+ .popover__component_dvtgo[data-popper-placement='right-start'] .popover__arrow_dvtgo,
69
+ .popover__component_dvtgo[data-popper-placement='right-end'] .popover__arrow_dvtgo {
70
+ left: -7px
59
71
  }
60
- .popover__component_4qqzo[data-popper-placement='right'] .popover__arrow_4qqzo:after, .popover__component_4qqzo[data-popper-placement='right-start'] .popover__arrow_4qqzo:after, .popover__component_4qqzo[data-popper-placement='right-end'] .popover__arrow_4qqzo:after {
61
- top: -4px;
72
+ .popover__component_dvtgo[data-popper-placement='right'] .popover__arrow_dvtgo:after, .popover__component_dvtgo[data-popper-placement='right-start'] .popover__arrow_dvtgo:after, .popover__component_dvtgo[data-popper-placement='right-end'] .popover__arrow_dvtgo:after {
73
+ top: -6px;
62
74
  border-top: none;
63
75
  border-right: none;
64
76
  }
65
- .popover__component_4qqzo[data-popper-placement='top'] .popover__arrow_4qqzo,
66
- .popover__component_4qqzo[data-popper-placement='top-start'] .popover__arrow_4qqzo,
67
- .popover__component_4qqzo[data-popper-placement='top-end'] .popover__arrow_4qqzo {
77
+ .popover__component_dvtgo[data-popper-placement='right-start'].popover__arrowShift_dvtgo .popover__arrow_dvtgo:after {
78
+ top: -7px;
79
+ }
80
+ .popover__component_dvtgo[data-popper-placement='right-end'].popover__arrowShift_dvtgo .popover__arrow_dvtgo:after {
81
+ top: -5px;
82
+ }
83
+ .popover__component_dvtgo[data-popper-placement='top'] .popover__arrow_dvtgo,
84
+ .popover__component_dvtgo[data-popper-placement='top-start'] .popover__arrow_dvtgo,
85
+ .popover__component_dvtgo[data-popper-placement='top-end'] .popover__arrow_dvtgo {
68
86
  bottom: 5px
69
87
  }
70
- .popover__component_4qqzo[data-popper-placement='top'] .popover__arrow_4qqzo:after, .popover__component_4qqzo[data-popper-placement='top-start'] .popover__arrow_4qqzo:after, .popover__component_4qqzo[data-popper-placement='top-end'] .popover__arrow_4qqzo:after {
71
- left: -4px;
88
+ .popover__component_dvtgo[data-popper-placement='top'] .popover__arrow_dvtgo:after, .popover__component_dvtgo[data-popper-placement='top-start'] .popover__arrow_dvtgo:after, .popover__component_dvtgo[data-popper-placement='top-end'] .popover__arrow_dvtgo:after {
89
+ left: -6px;
72
90
  border-top: none;
73
91
  border-left: none;
74
92
  }
75
- .popover__component_4qqzo[data-popper-placement='bottom'] .popover__arrow_4qqzo,
76
- .popover__component_4qqzo[data-popper-placement='bottom-start'] .popover__arrow_4qqzo,
77
- .popover__component_4qqzo[data-popper-placement='bottom-end'] .popover__arrow_4qqzo {
78
- top: -6px
93
+ .popover__component_dvtgo[data-popper-placement='top-start'].popover__arrowShift_dvtgo .popover__arrow_dvtgo:after {
94
+ left: -17px;
95
+ }
96
+ .popover__component_dvtgo[data-popper-placement='top-end'].popover__arrowShift_dvtgo .popover__arrow_dvtgo:after {
97
+ left: 5px;
79
98
  }
80
- .popover__component_4qqzo[data-popper-placement='bottom'] .popover__arrow_4qqzo:after, .popover__component_4qqzo[data-popper-placement='bottom-start'] .popover__arrow_4qqzo:after, .popover__component_4qqzo[data-popper-placement='bottom-end'] .popover__arrow_4qqzo:after {
81
- left: -4px;
99
+ .popover__component_dvtgo[data-popper-placement='bottom'] .popover__arrow_dvtgo,
100
+ .popover__component_dvtgo[data-popper-placement='bottom-start'] .popover__arrow_dvtgo,
101
+ .popover__component_dvtgo[data-popper-placement='bottom-end'] .popover__arrow_dvtgo {
102
+ top: -7px
103
+ }
104
+ .popover__component_dvtgo[data-popper-placement='bottom'] .popover__arrow_dvtgo:after, .popover__component_dvtgo[data-popper-placement='bottom-start'] .popover__arrow_dvtgo:after, .popover__component_dvtgo[data-popper-placement='bottom-end'] .popover__arrow_dvtgo:after {
105
+ left: -6px;
82
106
  border-bottom: none;
83
107
  border-right: none;
84
108
  }
85
- .popover__enter_4qqzo .popover__inner_4qqzo {
109
+ .popover__component_dvtgo[data-popper-placement='bottom-start'].popover__arrowShift_dvtgo .popover__arrow_dvtgo:after {
110
+ left: -17px;
111
+ }
112
+ .popover__component_dvtgo[data-popper-placement='bottom-end'].popover__arrowShift_dvtgo .popover__arrow_dvtgo:after {
113
+ left: 5px;
114
+ }
115
+ .popover__enter_dvtgo .popover__inner_dvtgo {
86
116
  opacity: 0;
87
117
  transform: scale(0.98);
88
118
  }
89
- .popover__enterActive_4qqzo .popover__inner_4qqzo {
119
+ .popover__enterActive_dvtgo .popover__inner_dvtgo {
90
120
  opacity: 1;
91
121
  transform: scale(1);
92
122
  }
93
- .popover__exit_4qqzo .popover__inner_4qqzo {
123
+ .popover__exit_dvtgo .popover__inner_dvtgo {
94
124
  opacity: 1;
95
125
  transform: scale(1);
96
126
  }
97
- .popover__exitActive_4qqzo .popover__inner_4qqzo {
127
+ .popover__exitActive_dvtgo .popover__inner_dvtgo {
98
128
  opacity: 0;
99
129
  transform: scale(0.98);
100
130
  }
package/dist/index.js CHANGED
@@ -7,7 +7,9 @@ require('react');
7
7
  require('classnames');
8
8
  require('react-transition-group');
9
9
  require('react-popper');
10
+ require('popper-max-size-modifier');
10
11
  require('react-merge-refs');
12
+ require('resize-observer');
11
13
  require('@alfalab/core-components-stack');
12
14
  require('@alfalab/core-components-portal');
13
15
 
@@ -15,6 +15,10 @@ type PopoverProps = {
15
15
  * Элемент, относительного которого появляется поповер
16
16
  */
17
17
  anchorElement: RefElement;
18
+ /**
19
+ * Использовать ширину родительского элемента
20
+ */
21
+ useAnchorWidth?: boolean;
18
22
  /**
19
23
  * Позиционирование поповера
20
24
  */
@@ -28,6 +32,10 @@ type PopoverProps = {
28
32
  * Запрещает поповеру менять свою позицию, если он не влезает в видимую область.
29
33
  */
30
34
  preventOverflow?: boolean;
35
+ /**
36
+ * Позволяет поповеру подствраивать свою высоту под границы экрана, если из-за величины контента он выходит за рамки видимой области экрана
37
+ */
38
+ availableHeight?: boolean;
31
39
  /**
32
40
  * Если `true`, будет отрисована стрелочка
33
41
  */
@@ -1,12 +1,14 @@
1
- import React, { forwardRef, useState, useCallback, useEffect } from 'react';
1
+ import React, { forwardRef, useState, useRef, useCallback, useEffect } from 'react';
2
2
  import cn from 'classnames';
3
3
  import { CSSTransition } from 'react-transition-group';
4
4
  import { usePopper } from 'react-popper';
5
+ import maxSize from 'popper-max-size-modifier';
5
6
  import mergeRefs from 'react-merge-refs';
7
+ import { ResizeObserver } from 'resize-observer';
6
8
  import { stackingOrder, Stack } from '@alfalab/core-components-stack/dist/modern';
7
9
  import { Portal } from '@alfalab/core-components-portal/dist/modern';
8
10
 
9
- var styles = {"component":"popover__component_4qqzo","inner":"popover__inner_4qqzo","arrow":"popover__arrow_4qqzo","enter":"popover__enter_4qqzo","enterActive":"popover__enterActive_4qqzo","exit":"popover__exit_4qqzo","exitActive":"popover__exitActive_4qqzo"};
11
+ var styles = {"component":"popover__component_dvtgo","inner":"popover__inner_dvtgo","scrollableContent":"popover__scrollableContent_dvtgo","arrow":"popover__arrow_dvtgo","arrowShift":"popover__arrowShift_dvtgo","enter":"popover__enter_dvtgo","enterActive":"popover__enterActive_dvtgo","exit":"popover__exit_dvtgo","exitActive":"popover__exitActive_dvtgo"};
10
12
  require('./index.css')
11
13
 
12
14
  const DEFAULT_TRANSITION = {
@@ -18,10 +20,30 @@ const CSS_TRANSITION_CLASS_NAMES = {
18
20
  exit: styles.exit,
19
21
  exitActive: styles.exitActive,
20
22
  };
21
- const Popover = forwardRef(({ children, getPortalContainer, transition = DEFAULT_TRANSITION, anchorElement, offset = [0, 0], withArrow = false, withTransition = true, position = 'left', preventFlip, popperClassName, arrowClassName, className, open, dataTestId, update, transitionDuration = `${transition.timeout}ms`, zIndex = stackingOrder.POPOVER, fallbackPlacements, preventOverflow = true, }, ref) => {
23
+ const availableHieghtModifier = {
24
+ name: 'availableHeight',
25
+ enabled: true,
26
+ phase: 'beforeWrite',
27
+ requires: ['maxSize'],
28
+ fn({ state: { modifiersData, elements: { popper }, }, }) {
29
+ const { height } = modifiersData.maxSize;
30
+ const content = popper.querySelector(`.${styles.scrollableContent}`);
31
+ if (content && !content.style.maxHeight) {
32
+ content.style.maxHeight = `${height}px`;
33
+ }
34
+ },
35
+ };
36
+ /**
37
+ * Минимальный размер anchorElement,
38
+ * при котором возможно смещение стрелочки относительно центра
39
+ */
40
+ const MIN_ARROW_SHIFT_SIZE = 75;
41
+ const Popover = forwardRef(({ children, getPortalContainer, transition = DEFAULT_TRANSITION, anchorElement, useAnchorWidth, offset = [0, 0], withArrow = false, withTransition = true, position = 'left', preventFlip, popperClassName, arrowClassName, className, open, dataTestId, update, transitionDuration = `${transition.timeout}ms`, zIndex = stackingOrder.POPOVER, fallbackPlacements, preventOverflow = true, availableHeight = false, }, ref) => {
22
42
  const [referenceElement, setReferenceElement] = useState(anchorElement);
23
43
  const [popperElement, setPopperElement] = useState(null);
24
44
  const [arrowElement, setArrowElement] = useState(null);
45
+ const [arrowShift, setArrowShift] = useState(false);
46
+ const updatePopperRef = useRef();
25
47
  const getModifiers = useCallback(() => {
26
48
  const modifiers = [{ name: 'offset', options: { offset } }];
27
49
  if (withArrow) {
@@ -36,12 +58,32 @@ const Popover = forwardRef(({ children, getPortalContainer, transition = DEFAULT
36
58
  if (preventOverflow) {
37
59
  modifiers.push({ name: 'preventOverflow', options: { mainAxis: false } });
38
60
  }
61
+ if (availableHeight) {
62
+ modifiers.push({ ...maxSize, options: {} });
63
+ modifiers.push({ ...availableHieghtModifier, options: {} });
64
+ }
39
65
  return modifiers;
40
- }, [offset, withArrow, preventFlip, fallbackPlacements, preventOverflow, arrowElement]);
66
+ }, [
67
+ offset,
68
+ withArrow,
69
+ preventFlip,
70
+ fallbackPlacements,
71
+ preventOverflow,
72
+ availableHeight,
73
+ arrowElement,
74
+ ]);
41
75
  const { styles: popperStyles, attributes, update: updatePopper } = usePopper(referenceElement, popperElement, {
42
76
  placement: position,
43
77
  modifiers: getModifiers(),
44
78
  });
79
+ if (updatePopper) {
80
+ updatePopperRef.current = updatePopper;
81
+ }
82
+ const updatePopoverWidth = useCallback(() => {
83
+ if (useAnchorWidth && updatePopperRef.current) {
84
+ updatePopperRef.current();
85
+ }
86
+ }, [useAnchorWidth]);
45
87
  useEffect(() => {
46
88
  setReferenceElement(anchorElement);
47
89
  }, [anchorElement]);
@@ -56,15 +98,42 @@ const Popover = forwardRef(({ children, getPortalContainer, transition = DEFAULT
56
98
  update.current = updatePopper;
57
99
  }
58
100
  });
101
+ useEffect(() => {
102
+ if (useAnchorWidth) {
103
+ const observer = new ResizeObserver(updatePopoverWidth);
104
+ if (anchorElement) {
105
+ observer.observe(anchorElement);
106
+ }
107
+ return () => {
108
+ observer.disconnect();
109
+ };
110
+ }
111
+ return () => ({});
112
+ }, [anchorElement, updatePopoverWidth, useAnchorWidth]);
113
+ /**
114
+ * По дизайну, если у тултипа позиционирование -start/-end, то стрелочка немного сдвигается вбок.
115
+ * Но если anchorElement слишком маленький, то стрелочка сдвигаться не должна.
116
+ */
117
+ useEffect(() => {
118
+ const shiftedPosition = position.includes('-start') || position.includes('-end');
119
+ if (shiftedPosition && referenceElement) {
120
+ const { width, height } = referenceElement.getBoundingClientRect();
121
+ const size = position.includes('left') || position.includes('right') ? height : width;
122
+ if (size >= MIN_ARROW_SHIFT_SIZE) {
123
+ setArrowShift(true);
124
+ }
125
+ }
126
+ }, [referenceElement, position]);
59
127
  const renderContent = (computedZIndex, style) => {
60
- return (React.createElement("div", Object.assign({ ref: mergeRefs([ref, setPopperElement]),
61
- // ref={setPopperElement}
62
- style: {
128
+ return (React.createElement("div", Object.assign({ ref: mergeRefs([ref, setPopperElement]), style: {
63
129
  zIndex: computedZIndex,
130
+ width: useAnchorWidth ? referenceElement?.offsetWidth : undefined,
64
131
  ...popperStyles.popper,
65
- }, "data-test-id": dataTestId, className: cn(styles.component, className) }, attributes.popper),
132
+ }, "data-test-id": dataTestId, className: cn(styles.component, className, {
133
+ [styles.arrowShift]: arrowShift,
134
+ }) }, attributes.popper),
66
135
  React.createElement("div", { className: cn(styles.inner, popperClassName), style: style },
67
- children,
136
+ React.createElement("div", { className: cn({ [styles.scrollableContent]: availableHeight }) }, children),
68
137
  withArrow && (React.createElement("div", { ref: setArrowElement, style: popperStyles.arrow, className: cn(styles.arrow, arrowClassName) })))));
69
138
  };
70
139
  return (React.createElement(Stack, { value: zIndex }, computedZIndex => (React.createElement(Portal, { getPortalContainer: getPortalContainer }, withTransition ? (React.createElement(CSSTransition, Object.assign({ unmountOnExit: true, classNames: CSS_TRANSITION_CLASS_NAMES }, transition, { in: open }), renderContent(computedZIndex, { transitionDuration }))) : (open && renderContent(computedZIndex))))));