From 979104cce30c6c93c157a45150166dd4c39b8f02 Mon Sep 17 00:00:00 2001 From: hextion <100ishundred@gmail.com> Date: Thu, 19 Sep 2024 22:27:14 +0300 Subject: [PATCH] fix(popover): migrated to floating-ui --- package.json | 1 + .../src/__snapshots__/Component.test.tsx.snap | 6 - packages/popover/package.json | 2 +- packages/popover/src/Component.tsx | 170 +++++------------- .../src/__snapshots__/Component.test.tsx.snap | 8 +- .../popover/src/docs/Component.stories.mdx | 5 +- packages/popover/src/index.module.css | 2 + .../src/__snapshots__/component.test.tsx.snap | 8 +- .../src/__snapshots__/Component.test.tsx.snap | 12 +- yarn.lock | 27 +++ 10 files changed, 89 insertions(+), 152 deletions(-) diff --git a/package.json b/package.json index f772ed4092..417da39007 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "@alfalab/utils": "^1.15.2", "@dnd-kit/core": "^6.0.7", "@dnd-kit/sortable": "^7.0.2", + "@floating-ui/react-dom": "^2.1.2", "@juggle/resize-observer": "^3.3.1", "@maskito/core": "^1.7.0", "@maskito/react": "^1.7.0", diff --git a/packages/custom-picker-button/src/__snapshots__/Component.test.tsx.snap b/packages/custom-picker-button/src/__snapshots__/Component.test.tsx.snap index f72dbce519..69a9fa7923 100644 --- a/packages/custom-picker-button/src/__snapshots__/Component.test.tsx.snap +++ b/packages/custom-picker-button/src/__snapshots__/Component.test.tsx.snap @@ -218,9 +218,7 @@ exports[`Snapshots tests should display opened correctly 2`] = ` >
void) | undefined>; @@ -157,39 +155,12 @@ const CSS_TRANSITION_CLASS_NAMES = { exitActive: styles.exitActive, }; -const availableHieghtModifier = { - name: 'availableHeight', - enabled: true, - phase: 'beforeWrite', - requires: ['maxSize'], - fn({ - state: { - modifiersData, - elements: { popper }, - }, - }: ModifierArguments) { - const { height } = modifiersData.maxSize; - - const content = popper.querySelector(`.${styles.scrollableContent}`) as HTMLElement; - - if (content && !content.style.maxHeight) { - content.style.maxHeight = `${height}px`; - } - }, -}; - -const DEFAULT_OFFSET = [0, 0]; +const DEFAULT_OFFSET: [number, number] = [0, 0]; // Минимальное расстояние стрелки до края поповера const MIN_DISTANCE_TO_EDGE = 24; -function getArrowPadding({ - placement, -}: { - popper: { height: number; width: number }; - reference: { height: number; width: number }; - placement: Position; -}) { +function getArrowPadding(placement: Position) { if (placement === 'right-end' || placement === 'left-end') { return { top: MIN_DISTANCE_TO_EDGE, right: 0, bottom: 0, left: 0 }; } @@ -216,7 +187,7 @@ export const Popover = forwardRef( getPortalContainer, transition = DEFAULT_TRANSITION, anchorElement: referenceElement, - useAnchorWidth, + useAnchorWidth = false, offset = DEFAULT_OFFSET, withArrow = false, withTransition = true, @@ -235,103 +206,53 @@ export const Popover = forwardRef( }, ref, ) => { - const [popperElement, setPopperElement] = useState(null); - const [arrowElement, setArrowElement] = useState(null); - const resizeObserverRef = useRef(null); - - const updatePopperRef = useRef<(() => void) | null>(null); - + const [arrowElement, setArrowElement] = useState(null); const popperRef = useRef(null); - const popperModifiers = useMemo(() => { - const modifiers: PopperModifier[] = [{ name: 'offset', options: { offset } }]; + const floatingMiddlewares = useMemo(() => { + const [crossAxis, mainAxis] = offset; + const middlewares = [offsetMiddleware({ mainAxis, crossAxis })]; if (withArrow) { - modifiers.push({ - name: 'arrow', - options: { - element: arrowElement, - padding: getArrowPadding, - }, - }); + middlewares.push( + arrow( + (state) => ({ + element: arrowElement, + padding: getArrowPadding(state.placement), + }), + [arrowElement], + ), + ); } - if (preventFlip) { - modifiers.push({ name: 'flip', options: { fallbackPlacements: [] } }); + if (preventFlip || fallbackPlacements || preventOverflow) { + middlewares.push( + flip({ flipAlignment: preventFlip, fallbackPlacements, mainAxis: false }), + ); } - if (fallbackPlacements) { - modifiers.push({ name: 'flip', options: { fallbackPlacements } }); - } - - if (preventOverflow) { - modifiers.push({ name: 'preventOverflow', options: { mainAxis: false } }); - } + return middlewares; + }, [offset, withArrow, preventFlip, fallbackPlacements, preventOverflow, arrowElement]); - if (availableHeight) { - modifiers.push({ ...maxSize, options: {} }); - modifiers.push({ ...availableHieghtModifier, options: {} }); - } - - return modifiers; - }, [ - offset, - withArrow, - preventFlip, - fallbackPlacements, - preventOverflow, - availableHeight, - arrowElement, - ]); - - const { - styles: popperStyles, - attributes, - update: updatePopper, - } = usePopper(referenceElement, popperElement, { + const { floatingStyles, refs, middlewareData, placement } = useFloating({ placement: position, - modifiers: popperModifiers, + elements: { reference: referenceElement }, + whileElementsMounted: autoUpdate, + middleware: floatingMiddlewares, }); - if (!(updatePopperRef.current === updatePopper)) { - updatePopperRef.current = updatePopper; - } - - if (isClient() && fnUtils.isNil(resizeObserverRef.current)) { - const ResizeObserver = window.ResizeObserver || ResizeObserverPolyfill; - const updatePopperCallback = () => { - updatePopperRef.current?.(); - }; - - resizeObserverRef.current = new ResizeObserver(updatePopperCallback); - } - - useEffect(() => { - if (fnUtils.isNil(popperElement)) return fnUtils.noop; - resizeObserverRef.current?.observe(popperElement); - - return () => resizeObserverRef.current?.unobserve(popperElement); - }, [popperElement]); - - useEffect(() => { - if (!useAnchorWidth || fnUtils.isNil(referenceElement)) return fnUtils.noop; - resizeObserverRef.current?.observe(referenceElement); - - return () => resizeObserverRef.current?.unobserve(referenceElement); - }, [referenceElement, useAnchorWidth]); - const renderContent = (computedZIndex: number) => (
(
{children}
- {withArrow && (
)} diff --git a/packages/popover/src/__snapshots__/Component.test.tsx.snap b/packages/popover/src/__snapshots__/Component.test.tsx.snap index 41c0b13d4c..5c09a87eaf 100644 --- a/packages/popover/src/__snapshots__/Component.test.tsx.snap +++ b/packages/popover/src/__snapshots__/Component.test.tsx.snap @@ -10,10 +10,8 @@ Object { >
0; + const buttonLabel = text('buttonLabel', 'Popover'); return (
) : ( )}
diff --git a/packages/popover/src/index.module.css b/packages/popover/src/index.module.css index eb2b9ae671..0a6c1ac1b2 100644 --- a/packages/popover/src/index.module.css +++ b/packages/popover/src/index.module.css @@ -26,6 +26,8 @@ .arrow { z-index: 1; + position: absolute; + bottom: 100%; } .arrow:after { diff --git a/packages/toast/src/__snapshots__/component.test.tsx.snap b/packages/toast/src/__snapshots__/component.test.tsx.snap index fed0f19033..079d53f3d5 100644 --- a/packages/toast/src/__snapshots__/component.test.tsx.snap +++ b/packages/toast/src/__snapshots__/component.test.tsx.snap @@ -55,10 +55,8 @@ exports[`Toast Snapshots tests should math snapshot when prop \`anchorElement\` >
@@ -197,10 +195,8 @@ Object { >
diff --git a/yarn.lock b/yarn.lock index 7aedd03ed6..12456a5e31 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2201,6 +2201,21 @@ dependencies: "@floating-ui/utils" "^0.1.1" +"@floating-ui/core@^1.6.0": + version "1.6.5" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.5.tgz#102335cac0d22035b04d70ca5ff092d2d1a26f2b" + integrity sha512-8GrTWmoFhm5BsMZOTHeGD2/0FLKLQQHvO/ZmQga4tKempYRLz8aqJGqXVuQgisnMObq2YZ2SgkwctN1LOOxcqA== + dependencies: + "@floating-ui/utils" "^0.2.5" + +"@floating-ui/dom@^1.0.0": + version "1.6.8" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.8.tgz#45e20532b6d8a061b356a4fb336022cf2609754d" + integrity sha512-kx62rP19VZ767Q653wsP1XZCGIirkE09E0QUGNYTM/ttbbQHqcGPdSfWFxUyyNLc/W6aoJRBajOSXhP6GXjC0Q== + dependencies: + "@floating-ui/core" "^1.6.0" + "@floating-ui/utils" "^0.2.5" + "@floating-ui/dom@^1.0.1", "@floating-ui/dom@^1.3.0": version "1.5.1" resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.5.1.tgz#88b70defd002fe851f17b4a25efb2d3c04d7a8d7" @@ -2216,11 +2231,23 @@ dependencies: "@floating-ui/dom" "^1.3.0" +"@floating-ui/react-dom@^2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.1.2.tgz#a1349bbf6a0e5cb5ded55d023766f20a4d439a31" + integrity sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A== + dependencies: + "@floating-ui/dom" "^1.0.0" + "@floating-ui/utils@^0.1.1": version "0.1.1" resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.1.1.tgz#1a5b1959a528e374e8037c4396c3e825d6cf4a83" integrity sha512-m0G6wlnhm/AX0H12IOWtK8gASEMffnX08RtKkCgTdHb9JpHKGloI7icFfLg9ZmQeavcvR0PKmzxClyuFPSjKWw== +"@floating-ui/utils@^0.2.5": + version "0.2.5" + resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.5.tgz#105c37d9d9620ce69b7f692a20c821bf1ad2cbf9" + integrity sha512-sTcG+QZ6fdEUObICavU+aB3Mp8HY4n14wYHdxK4fXjPmv3PXZZeY5RaguJmGyeH/CJQhX3fqKUtS4qc1LoHwhQ== + "@gar/promisify@^1.1.3": version "1.1.3" resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6"