@alfalab/core-components-popover 6.1.0 → 6.2.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.
package/src/Component.tsx CHANGED
@@ -19,6 +19,7 @@ import maxSize from 'popper-max-size-modifier';
19
19
 
20
20
  import { Portal } from '@alfalab/core-components-portal';
21
21
  import { Stack, stackingOrder } from '@alfalab/core-components-stack';
22
+ import { useLayoutEffect_SAFE_FOR_SSR } from '@alfalab/hooks';
22
23
 
23
24
  import styles from './index.module.css';
24
25
 
@@ -54,7 +55,7 @@ export type PopoverProps = {
54
55
 
55
56
  /**
56
57
  * Запрещает поповеру менять свою позицию.
57
- * Например, если места снизу недостаточно,то он все равно будет показан снизу
58
+ * Например, если места снизу недостаточно, то он все равно будет показан снизу
58
59
  */
59
60
  preventFlip?: boolean;
60
61
 
@@ -118,7 +119,7 @@ export type PopoverProps = {
118
119
  /**
119
120
  * Хранит функцию, с помощью которой можно обновить положение компонента
120
121
  */
121
- update?: MutableRefObject<() => void>;
122
+ update?: MutableRefObject<(() => void) | undefined>;
122
123
 
123
124
  /**
124
125
  * Дополнительный класс
@@ -175,11 +176,36 @@ const availableHieghtModifier = {
175
176
  },
176
177
  };
177
178
 
178
- /**
179
- * Минимальный размер anchorElement,
180
- * при котором возможно смещение стрелочки относительно центра
181
- */
182
- const MIN_ARROW_SHIFT_SIZE = 75;
179
+ const DEFAULT_OFFSET = [0, 0];
180
+
181
+ // Минимальное расстояние стрелки до края поповера
182
+ const MIN_DISTANCE_TO_EDGE = 24;
183
+
184
+ function getArrowPadding({
185
+ placement,
186
+ }: {
187
+ popper: { height: number; width: number };
188
+ reference: { height: number; width: number };
189
+ placement: Position;
190
+ }) {
191
+ if (placement === 'right-end' || placement === 'left-end') {
192
+ return { top: MIN_DISTANCE_TO_EDGE, right: 0, bottom: 0, left: 0 };
193
+ }
194
+
195
+ if (placement === 'top-start' || placement === 'bottom-start') {
196
+ return { top: 0, right: MIN_DISTANCE_TO_EDGE, bottom: 0, left: 0 };
197
+ }
198
+
199
+ if (placement === 'right-start' || placement === 'left-start') {
200
+ return { top: 0, right: 0, bottom: MIN_DISTANCE_TO_EDGE, left: 0 };
201
+ }
202
+
203
+ if (placement === 'top-end' || placement === 'bottom-end') {
204
+ return { top: 0, right: 0, bottom: 0, left: MIN_DISTANCE_TO_EDGE };
205
+ }
206
+
207
+ return 0;
208
+ }
183
209
 
184
210
  export const Popover = forwardRef<HTMLDivElement, PopoverProps>(
185
211
  (
@@ -189,7 +215,7 @@ export const Popover = forwardRef<HTMLDivElement, PopoverProps>(
189
215
  transition = DEFAULT_TRANSITION,
190
216
  anchorElement,
191
217
  useAnchorWidth,
192
- offset = [0, 0],
218
+ offset = DEFAULT_OFFSET,
193
219
  withArrow = false,
194
220
  withTransition = true,
195
221
  position = 'left',
@@ -211,7 +237,6 @@ export const Popover = forwardRef<HTMLDivElement, PopoverProps>(
211
237
  const [referenceElement, setReferenceElement] = useState<RefElement>(anchorElement);
212
238
  const [popperElement, setPopperElement] = useState<RefElement>(null);
213
239
  const [arrowElement, setArrowElement] = useState<RefElement>(null);
214
- const [arrowShift, setArrowShift] = useState(false);
215
240
 
216
241
  const updatePopperRef = useRef<() => void>();
217
242
 
@@ -222,7 +247,13 @@ export const Popover = forwardRef<HTMLDivElement, PopoverProps>(
222
247
  const modifiers: PopperModifier[] = [{ name: 'offset', options: { offset } }];
223
248
 
224
249
  if (withArrow) {
225
- modifiers.push({ name: 'arrow', options: { element: arrowElement } });
250
+ modifiers.push({
251
+ name: 'arrow',
252
+ options: {
253
+ element: arrowElement,
254
+ padding: getArrowPadding,
255
+ },
256
+ });
226
257
  }
227
258
 
228
259
  if (preventFlip) {
@@ -266,7 +297,7 @@ export const Popover = forwardRef<HTMLDivElement, PopoverProps>(
266
297
  updatePopperRef.current = updatePopper;
267
298
  }
268
299
 
269
- useEffect(() => {
300
+ useLayoutEffect_SAFE_FOR_SSR(() => {
270
301
  setReferenceElement(anchorElement);
271
302
  }, [anchorElement]);
272
303
 
@@ -277,7 +308,7 @@ export const Popover = forwardRef<HTMLDivElement, PopoverProps>(
277
308
  }, [updatePopper, arrowElement, children]);
278
309
 
279
310
  useEffect(() => {
280
- if (update && !update.current && updatePopper) {
311
+ if (update && updatePopper) {
281
312
  // eslint-disable-next-line no-param-reassign
282
313
  update.current = updatePopper;
283
314
  }
@@ -301,25 +332,6 @@ export const Popover = forwardRef<HTMLDivElement, PopoverProps>(
301
332
  return () => ({});
302
333
  }, [anchorElement, useAnchorWidth]);
303
334
 
304
- /**
305
- * По дизайну, если у тултипа позиционирование -start/-end, то стрелочка немного сдвигается вбок.
306
- * Но если anchorElement слишком маленький, то стрелочка сдвигаться не должна.
307
- */
308
- useEffect(() => {
309
- const shiftedPosition = position.includes('-start') || position.includes('-end');
310
-
311
- if (shiftedPosition && referenceElement) {
312
- const { width, height } = referenceElement.getBoundingClientRect();
313
-
314
- const size =
315
- position.includes('left') || position.includes('right') ? height : width;
316
-
317
- if (size >= MIN_ARROW_SHIFT_SIZE) {
318
- setArrowShift(true);
319
- }
320
- }
321
- }, [referenceElement, position]);
322
-
323
335
  const renderContent = (computedZIndex: number) => (
324
336
  <div
325
337
  ref={mergeRefs([ref, popperRef, setPopperElement])}
@@ -330,9 +342,7 @@ export const Popover = forwardRef<HTMLDivElement, PopoverProps>(
330
342
  ...(popperStyles.popper?.transform ? null : { visibility: 'hidden' }),
331
343
  }}
332
344
  data-test-id={dataTestId}
333
- className={cn(styles.component, className, {
334
- [styles.arrowShift]: arrowShift,
335
- })}
345
+ className={cn(styles.component, className)}
336
346
  {...attributes.popper}
337
347
  >
338
348
  <div className={cn(styles.inner, popperClassName)} ref={innerRef}>
@@ -11,7 +11,7 @@
11
11
 
12
12
  .inner {
13
13
  position: relative;
14
- background-color: var(--color-light-bg-primary);
14
+ background-color: var(--color-light-modal-bg-primary);
15
15
  box-shadow: var(--shadow-m);
16
16
  border: 1px solid var(--popover-border-color);
17
17
  box-sizing: border-box;
@@ -34,7 +34,7 @@
34
34
  position: absolute;
35
35
  width: 12px;
36
36
  height: 12px;
37
- background-color: var(--color-light-bg-primary);
37
+ background-color: var(--color-light-modal-bg-primary);
38
38
  border: 1px solid var(--popover-border-color);
39
39
  box-sizing: border-box;
40
40
  transform: rotate(45deg);
@@ -52,14 +52,6 @@
52
52
  }
53
53
  }
54
54
 
55
- .component[data-popper-placement='left-start'].arrowShift .arrow:after {
56
- top: -7px;
57
- }
58
-
59
- .component[data-popper-placement='left-end'].arrowShift .arrow:after {
60
- top: -5px;
61
- }
62
-
63
55
  .component[data-popper-placement='right'] .arrow,
64
56
  .component[data-popper-placement='right-start'] .arrow,
65
57
  .component[data-popper-placement='right-end'] .arrow {
@@ -72,14 +64,6 @@
72
64
  }
73
65
  }
74
66
 
75
- .component[data-popper-placement='right-start'].arrowShift .arrow:after {
76
- top: -7px;
77
- }
78
-
79
- .component[data-popper-placement='right-end'].arrowShift .arrow:after {
80
- top: -5px;
81
- }
82
-
83
67
  .component[data-popper-placement='top'] .arrow,
84
68
  .component[data-popper-placement='top-start'] .arrow,
85
69
  .component[data-popper-placement='top-end'] .arrow {
@@ -92,14 +76,6 @@
92
76
  }
93
77
  }
94
78
 
95
- .component[data-popper-placement='top-start'].arrowShift .arrow:after {
96
- left: -17px;
97
- }
98
-
99
- .component[data-popper-placement='top-end'].arrowShift .arrow:after {
100
- left: 5px;
101
- }
102
-
103
79
  .component[data-popper-placement='bottom'] .arrow,
104
80
  .component[data-popper-placement='bottom-start'] .arrow,
105
81
  .component[data-popper-placement='bottom-end'] .arrow {
@@ -112,14 +88,6 @@
112
88
  }
113
89
  }
114
90
 
115
- .component[data-popper-placement='bottom-start'].arrowShift .arrow:after {
116
- left: -17px;
117
- }
118
-
119
- .component[data-popper-placement='bottom-end'].arrowShift .arrow:after {
120
- left: 5px;
121
- }
122
-
123
91
  .enter .inner {
124
92
  opacity: 0;
125
93
  transform: scale(0.98);