From 77f83fd4e1b177b07c6be5f256c1a4727652b5db Mon Sep 17 00:00:00 2001 From: lawliet Date: Wed, 21 Sep 2022 22:05:11 +0800 Subject: [PATCH 1/4] fix: Tooltip arrow postion --- .../Floating/FloatingArrow/FloatingArrow.tsx | 15 +++++++++---- .../get-arrow-position-styles.ts | 22 +++++++++++-------- .../src/Popover/Popover.context.ts | 3 +++ src/mantine-core/src/Popover/Popover.tsx | 7 +++++- .../PopoverDropdown/PopoverDropdown.tsx | 3 +++ src/mantine-core/src/Popover/use-popover.ts | 4 ++++ src/mantine-core/src/Tooltip/Tooltip.tsx | 7 +++++- src/mantine-core/src/Tooltip/use-tooltip.ts | 20 +++++++++++++++-- 8 files changed, 64 insertions(+), 17 deletions(-) diff --git a/src/mantine-core/src/Floating/FloatingArrow/FloatingArrow.tsx b/src/mantine-core/src/Floating/FloatingArrow/FloatingArrow.tsx index fba138f9002..b20573db408 100644 --- a/src/mantine-core/src/Floating/FloatingArrow/FloatingArrow.tsx +++ b/src/mantine-core/src/Floating/FloatingArrow/FloatingArrow.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { forwardRef } from 'react'; import { useMantineTheme } from '@mantine/styles'; import { getArrowPositionStyles } from './get-arrow-position-styles'; import { FloatingPosition } from '../types'; @@ -8,17 +8,21 @@ interface FloatingArrowProps extends React.ComponentPropsWithoutRef<'div'> { position: FloatingPosition; arrowSize: number; arrowOffset: number; + arrowX: number; + arrowY: number; visible: boolean; } -export function FloatingArrow({ +export const FloatingArrow = forwardRef(({ withBorder, position, arrowSize, arrowOffset, visible, + arrowX, + arrowY, ...others -}: FloatingArrowProps) { +}, ref) => { const theme = useMantineTheme(); if (!visible) { @@ -28,15 +32,18 @@ export function FloatingArrow({ return (
); -} +}); FloatingArrow.displayName = '@mantine/core/FloatingArrow'; diff --git a/src/mantine-core/src/Floating/FloatingArrow/get-arrow-position-styles.ts b/src/mantine-core/src/Floating/FloatingArrow/get-arrow-position-styles.ts index c1720108465..2b67517cb73 100644 --- a/src/mantine-core/src/Floating/FloatingArrow/get-arrow-position-styles.ts +++ b/src/mantine-core/src/Floating/FloatingArrow/get-arrow-position-styles.ts @@ -2,11 +2,11 @@ import type { FloatingPosition, FloatingSide, FloatingPlacement } from '../types function horizontalSide( placement: FloatingPlacement | 'center', - arrowSize: number, - arrowOffset: number + arrowY: number, + arrowOffset: number, ) { if (placement === 'center') { - return { top: `calc(50% - ${arrowSize / 2}px)` }; + return { top: arrowY }; } if (placement === 'end') { @@ -22,12 +22,12 @@ function horizontalSide( function verticalSide( placement: FloatingPlacement | 'center', - arrowSize: number, + arrowX: number, arrowOffset: number, dir: 'rtl' | 'ltr' ) { if (placement === 'center') { - return { left: `calc(50% - ${arrowSize / 2}px)` }; + return { [dir === 'ltr' ? 'left' : 'right']: arrowX }; } if (placement === 'end') { @@ -46,12 +46,16 @@ export function getArrowPositionStyles({ withBorder, arrowSize, arrowOffset, + arrowX, + arrowY, dir, }: { position: FloatingPosition; withBorder: boolean; arrowSize: number; arrowOffset: number; + arrowX: number; + arrowY: number; dir: 'rtl' | 'ltr'; }) { const [side, placement = 'center'] = position.split('-') as [FloatingSide, FloatingPlacement]; @@ -67,7 +71,7 @@ export function getArrowPositionStyles({ if (side === 'left') { return { ...baseStyles, - ...horizontalSide(placement, arrowSize, arrowOffset), + ...horizontalSide(placement, arrowY, arrowOffset), right: arrowPosition, borderLeft: 0, borderBottom: 0, @@ -77,7 +81,7 @@ export function getArrowPositionStyles({ if (side === 'right') { return { ...baseStyles, - ...horizontalSide(placement, arrowSize, arrowOffset), + ...horizontalSide(placement, arrowY, arrowOffset), left: arrowPosition, borderRight: 0, borderTop: 0, @@ -87,7 +91,7 @@ export function getArrowPositionStyles({ if (side === 'top') { return { ...baseStyles, - ...verticalSide(placement, arrowSize, arrowOffset, dir), + ...verticalSide(placement, arrowX, arrowOffset, dir), bottom: arrowPosition, borderTop: 0, [dir === 'ltr' ? 'borderLeft' : 'borderRight']: 0, @@ -97,7 +101,7 @@ export function getArrowPositionStyles({ if (side === 'bottom') { return { ...baseStyles, - ...verticalSide(placement, arrowSize, arrowOffset, dir), + ...verticalSide(placement, arrowX, arrowOffset, dir), top: arrowPosition, borderBottom: 0, [dir === 'ltr' ? 'borderRight' : 'borderLeft']: 0, diff --git a/src/mantine-core/src/Popover/Popover.context.ts b/src/mantine-core/src/Popover/Popover.context.ts index 543b9808247..ec633afbd7f 100644 --- a/src/mantine-core/src/Popover/Popover.context.ts +++ b/src/mantine-core/src/Popover/Popover.context.ts @@ -9,6 +9,9 @@ import { PopoverWidth } from './Popover.types'; interface PopoverContext { x: number; y: number; + arrowX: number; + arrowY: number; + arrowRef: React.RefObject; opened: boolean; transition: MantineTransition; transitionDuration: number; diff --git a/src/mantine-core/src/Popover/Popover.tsx b/src/mantine-core/src/Popover/Popover.tsx index 2dc414ec8ec..32ee62fcc47 100644 --- a/src/mantine-core/src/Popover/Popover.tsx +++ b/src/mantine-core/src/Popover/Popover.tsx @@ -1,6 +1,6 @@ /* eslint-disable react/no-unused-prop-types */ -import React from 'react'; +import React, { useRef } from 'react'; import { useId, useClickOutside } from '@mantine/hooks'; import { useMantineTheme, @@ -138,6 +138,7 @@ const defaultProps: Partial = { }; export function Popover(props: PopoverProps) { + const arrowRef = useRef(null); const { children, position, @@ -181,6 +182,7 @@ export function Popover(props: PopoverProps) { width, position: getFloatingPosition(theme.dir, position), offset: offset + (withArrow ? arrowSize / 2 : 0), + arrowRef, onPositionChange, positionDependencies, opened, @@ -209,7 +211,10 @@ export function Popover(props: PopoverProps) { floating: popover.floating.floating, x: popover.floating.x, y: popover.floating.y, + arrowX: popover.floating?.middlewareData?.arrow?.x, + arrowY: popover.floating?.middlewareData?.arrow?.y, opened: popover.opened, + arrowRef, transition, transitionDuration, exitTransitionDuration, diff --git a/src/mantine-core/src/Popover/PopoverDropdown/PopoverDropdown.tsx b/src/mantine-core/src/Popover/PopoverDropdown/PopoverDropdown.tsx index 3f78134205c..6465310de83 100644 --- a/src/mantine-core/src/Popover/PopoverDropdown/PopoverDropdown.tsx +++ b/src/mantine-core/src/Popover/PopoverDropdown/PopoverDropdown.tsx @@ -73,6 +73,9 @@ export function PopoverDropdown({ style, className, children, ...others }: Popov {children} ; } function getPopoverMiddlewares(options: UsePopoverOptions) { @@ -35,6 +37,8 @@ function getPopoverMiddlewares(options: UsePopoverOptions) { middlewares.push(flip()); } + middlewares.push(arrow({ element: options.arrowRef })); + return middlewares; } diff --git a/src/mantine-core/src/Tooltip/Tooltip.tsx b/src/mantine-core/src/Tooltip/Tooltip.tsx index 153eb358050..ee3116efdf2 100644 --- a/src/mantine-core/src/Tooltip/Tooltip.tsx +++ b/src/mantine-core/src/Tooltip/Tooltip.tsx @@ -1,4 +1,4 @@ -import React, { cloneElement, forwardRef } from 'react'; +import React, { cloneElement, forwardRef, useRef } from 'react'; import { isElement, ForwardRefWithStaticComponents } from '@mantine/utils'; import { useMergedRef } from '@mantine/hooks'; import { getDefaultZIndex, useComponentDefaultProps } from '@mantine/styles'; @@ -67,6 +67,7 @@ const defaultProps: Partial = { }; const _Tooltip = forwardRef((props, ref) => { + const arrowRef = useRef(null); const { children, position, @@ -114,6 +115,7 @@ const _Tooltip = forwardRef((props, ref) => { onPositionChange, opened, events, + arrowRef, offset: offset + (withArrow ? arrowSize / 2 : 0), positionDependencies: [...positionDependencies, children], }); @@ -150,6 +152,9 @@ const _Tooltip = forwardRef((props, ref) => { {label} ; events: { hover: boolean; focus: boolean; touch: boolean }; positionDependencies: any[]; } @@ -47,11 +49,23 @@ export function useTooltip(settings: UseTooltip) { [setCurrentId, uid] ); - const { x, y, reference, floating, context, refs, update, placement } = useFloating({ + const { + x, + y, + reference, + floating, + context, + refs, + update, + placement, + middlewareData: { arrow: { x: arrowX, y: arrowY } = {} }, + } = useFloating({ placement: settings.position, open: opened, onOpenChange: onChange, - middleware: [offset(settings.offset), shift({ padding: 8 }), flip()], + middleware: [offset(settings.offset), shift({ padding: 8 }), flip(), arrow({ + element: settings.arrowRef, + })], }); const { getReferenceProps, getFloatingProps } = useInteractions([ @@ -82,6 +96,8 @@ export function useTooltip(settings: UseTooltip) { return { x, y, + arrowX, + arrowY, reference, floating, getFloatingProps, From 33b0f29f4ca9b0c1ea329aded6396b552052dd12 Mon Sep 17 00:00:00 2001 From: lawliet Date: Wed, 21 Sep 2022 22:44:59 +0800 Subject: [PATCH 2/4] fix: prettier code style --- .../Floating/FloatingArrow/FloatingArrow.tsx | 53 ++++++++----------- .../get-arrow-position-styles.ts | 2 +- src/mantine-core/src/Tooltip/use-tooltip.ts | 11 ++-- 3 files changed, 32 insertions(+), 34 deletions(-) diff --git a/src/mantine-core/src/Floating/FloatingArrow/FloatingArrow.tsx b/src/mantine-core/src/Floating/FloatingArrow/FloatingArrow.tsx index b20573db408..320cf49166d 100644 --- a/src/mantine-core/src/Floating/FloatingArrow/FloatingArrow.tsx +++ b/src/mantine-core/src/Floating/FloatingArrow/FloatingArrow.tsx @@ -13,37 +13,30 @@ interface FloatingArrowProps extends React.ComponentPropsWithoutRef<'div'> { visible: boolean; } -export const FloatingArrow = forwardRef(({ - withBorder, - position, - arrowSize, - arrowOffset, - visible, - arrowX, - arrowY, - ...others -}, ref) => { - const theme = useMantineTheme(); +export const FloatingArrow = forwardRef( + ({ withBorder, position, arrowSize, arrowOffset, visible, arrowX, arrowY, ...others }, ref) => { + const theme = useMantineTheme(); - if (!visible) { - return null; - } + if (!visible) { + return null; + } - return ( -
- ); -}); + return ( +
+ ); + } +); FloatingArrow.displayName = '@mantine/core/FloatingArrow'; diff --git a/src/mantine-core/src/Floating/FloatingArrow/get-arrow-position-styles.ts b/src/mantine-core/src/Floating/FloatingArrow/get-arrow-position-styles.ts index 2b67517cb73..765c878d5df 100644 --- a/src/mantine-core/src/Floating/FloatingArrow/get-arrow-position-styles.ts +++ b/src/mantine-core/src/Floating/FloatingArrow/get-arrow-position-styles.ts @@ -3,7 +3,7 @@ import type { FloatingPosition, FloatingSide, FloatingPlacement } from '../types function horizontalSide( placement: FloatingPlacement | 'center', arrowY: number, - arrowOffset: number, + arrowOffset: number ) { if (placement === 'center') { return { top: arrowY }; diff --git a/src/mantine-core/src/Tooltip/use-tooltip.ts b/src/mantine-core/src/Tooltip/use-tooltip.ts index ba2367ec2f6..b4539985f2c 100644 --- a/src/mantine-core/src/Tooltip/use-tooltip.ts +++ b/src/mantine-core/src/Tooltip/use-tooltip.ts @@ -63,9 +63,14 @@ export function useTooltip(settings: UseTooltip) { placement: settings.position, open: opened, onOpenChange: onChange, - middleware: [offset(settings.offset), shift({ padding: 8 }), flip(), arrow({ - element: settings.arrowRef, - })], + middleware: [ + offset(settings.offset), + shift({ padding: 8 }), + flip(), + arrow({ + element: settings.arrowRef, + }), + ], }); const { getReferenceProps, getFloatingProps } = useInteractions([ From fe30af721ba806f7607c5e18593eb590707e62bb Mon Sep 17 00:00:00 2001 From: lawliet Date: Thu, 22 Sep 2022 12:15:46 +0800 Subject: [PATCH 3/4] feat: add arrow postion story in Tooltip & Popover / update floating-ui to the latest --- package.json | 2 +- src/mantine-core/package.json | 2 +- .../src/Popover/Popover.story.tsx | 14 +++++++ .../src/Tooltip/Tooltip.story.tsx | 9 +++++ .../demos/core/Popover/Popover.demo.arrow.tsx | 38 ++++++++++++++++++ .../src/demos/core/Popover/index.ts | 1 + .../demos/core/Tooltip/Tooltip.demo.arrow.tsx | 23 ++++++++++- yarn.lock | 40 +++++++++---------- 8 files changed, 105 insertions(+), 24 deletions(-) create mode 100644 src/mantine-demos/src/demos/core/Popover/Popover.demo.arrow.tsx diff --git a/package.json b/package.json index ff2cbac265d..d0d4906cb89 100644 --- a/package.json +++ b/package.json @@ -126,7 +126,7 @@ "@emotion/react": "11.9.3", "@emotion/server": "11.4.0", "@emotion/styled": "^11.10.0", - "@floating-ui/react-dom-interactions": "0.6.6", + "@floating-ui/react-dom-interactions": "^0.10.1", "@radix-ui/react-scroll-area": "1.0.0", "@tabler/icons": "^1.68.0", "clsx": "1.1.1", diff --git a/src/mantine-core/package.json b/src/mantine-core/package.json index 259ed2b56ca..0777b770cac 100644 --- a/src/mantine-core/package.json +++ b/src/mantine-core/package.json @@ -36,7 +36,7 @@ "@mantine/styles": "5.4.0", "@radix-ui/react-scroll-area": "1.0.0", "react-textarea-autosize": "8.3.4", - "@floating-ui/react-dom-interactions": "0.6.6" + "@floating-ui/react-dom-interactions": "^0.10.1" }, "devDependencies": {} } diff --git a/src/mantine-core/src/Popover/Popover.story.tsx b/src/mantine-core/src/Popover/Popover.story.tsx index 3a96e74a824..0acd5932758 100644 --- a/src/mantine-core/src/Popover/Popover.story.tsx +++ b/src/mantine-core/src/Popover/Popover.story.tsx @@ -20,6 +20,20 @@ export function Uncontrolled() { ); } +export function WithArrow() { + return ( +
+ + + + + + Dropdown with arrow + +
+ ); +} + export function Usage() { const [opened, setState] = useState(false); diff --git a/src/mantine-core/src/Tooltip/Tooltip.story.tsx b/src/mantine-core/src/Tooltip/Tooltip.story.tsx index b17414082db..b33fd1b1795 100644 --- a/src/mantine-core/src/Tooltip/Tooltip.story.tsx +++ b/src/mantine-core/src/Tooltip/Tooltip.story.tsx @@ -92,3 +92,12 @@ export const WithinGroup = () => ( ); + +export const WithinArrow = () => ( + + + +); diff --git a/src/mantine-demos/src/demos/core/Popover/Popover.demo.arrow.tsx b/src/mantine-demos/src/demos/core/Popover/Popover.demo.arrow.tsx new file mode 100644 index 00000000000..9ee39ba97fd --- /dev/null +++ b/src/mantine-demos/src/demos/core/Popover/Popover.demo.arrow.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import { Popover, Text, Button } from '@mantine/core'; + +const code = ` +import { Popover, Text, Button } from '@mantine/core'; + +function Demo() { + return ( + + + + + + This is to test popover arrow, the arrow will be the center postion. + + + ); +} +`; + +function Demo() { + return ( + + + + + + This is to test popover arrow, the arrow will be the center postion. + + + ); +} + +export const arrow: MantineDemo = { + type: 'demo', + code, + component: Demo, +}; diff --git a/src/mantine-demos/src/demos/core/Popover/index.ts b/src/mantine-demos/src/demos/core/Popover/index.ts index 21bf76154c3..30af08e1cb8 100644 --- a/src/mantine-demos/src/demos/core/Popover/index.ts +++ b/src/mantine-demos/src/demos/core/Popover/index.ts @@ -2,3 +2,4 @@ export { usage } from './Popover.demo.usage'; export { form } from './Popover.demo.form'; export { hover } from './Popover.demo.hover'; export { sameWidth } from './Popover.demo.sameWidth'; +export { arrow } from './Popover.demo.arrow'; diff --git a/src/mantine-demos/src/demos/core/Tooltip/Tooltip.demo.arrow.tsx b/src/mantine-demos/src/demos/core/Tooltip/Tooltip.demo.arrow.tsx index 14f6529d883..646b2448100 100644 --- a/src/mantine-demos/src/demos/core/Tooltip/Tooltip.demo.arrow.tsx +++ b/src/mantine-demos/src/demos/core/Tooltip/Tooltip.demo.arrow.tsx @@ -7,6 +7,14 @@ import { Tooltip, Button } from '@mantine/core'; function Demo() { return ( <> + + + + + + + + @@ -22,7 +30,20 @@ function Demo() { export function Demo() { return ( - + + + + + + + diff --git a/yarn.lock b/yarn.lock index 67bcb13eba6..04b7d5f53cd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1866,34 +1866,32 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@floating-ui/core@^0.7.3": - version "0.7.3" - resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-0.7.3.tgz#d274116678ffae87f6b60e90f88cc4083eefab86" - integrity sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg== +"@floating-ui/core@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.0.1.tgz#00e64d74e911602c8533957af0cce5af6b2e93c8" + integrity sha512-bO37brCPfteXQfFY0DyNDGB3+IMe4j150KFQcgJ5aBP295p9nBGeHEs/p0czrRbtlHq4Px/yoPXO/+dOCcF4uA== -"@floating-ui/dom@^0.5.3": - version "0.5.4" - resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-0.5.4.tgz#4eae73f78bcd4bd553ae2ade30e6f1f9c73fe3f1" - integrity sha512-419BMceRLq0RrmTSDxn8hf9R3VCJv2K9PUfugh5JyEFmdjzDo+e8U5EdR8nzKq8Yj1htzLm3b6eQEEam3/rrtg== +"@floating-ui/dom@^1.0.0": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.0.2.tgz#c5184c52c6f50abd11052d71204f4be2d9245237" + integrity sha512-5X9WSvZ8/fjy3gDu8yx9HAA4KG1lazUN2P4/VnaXLxTO9Dz53HI1oYoh1OlhqFNlHgGDiwFX5WhFCc2ljbW3yA== dependencies: - "@floating-ui/core" "^0.7.3" + "@floating-ui/core" "^1.0.1" -"@floating-ui/react-dom-interactions@0.6.6": - version "0.6.6" - resolved "https://registry.yarnpkg.com/@floating-ui/react-dom-interactions/-/react-dom-interactions-0.6.6.tgz#8542e8c4bcbee2cd0d512de676c6a493e0a2d168" - integrity sha512-qnao6UPjSZNHnXrF+u4/n92qVroQkx0Umlhy3Avk1oIebm/5ee6yvDm4xbHob0OjY7ya8WmUnV3rQlPwX3Atwg== +"@floating-ui/react-dom-interactions@^0.10.1": + version "0.10.1" + resolved "https://registry.yarnpkg.com/@floating-ui/react-dom-interactions/-/react-dom-interactions-0.10.1.tgz#45fc7c3d9a2ae58f0ef39078660e97594f484af8" + integrity sha512-mb9Sn/cnPjVlEucSZTSt4Iu7NAvqnXTvmzeE5EtfdRhVQO6L94dqqT+DPTmJmbiw4XqzoyGP+Q6J+I5iK2p6bw== dependencies: - "@floating-ui/react-dom" "^0.7.2" + "@floating-ui/react-dom" "^1.0.0" aria-hidden "^1.1.3" - use-isomorphic-layout-effect "^1.1.1" -"@floating-ui/react-dom@^0.7.2": - version "0.7.2" - resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-0.7.2.tgz#0bf4ceccb777a140fc535c87eb5d6241c8e89864" - integrity sha512-1T0sJcpHgX/u4I1OzIEhlcrvkUN8ln39nz7fMoE/2HDHrPiMFoOGR7++GYyfUmIQHkkrTinaeQsO3XWubjSvGg== +"@floating-ui/react-dom@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-1.0.0.tgz#e0975966694433f1f0abffeee5d8e6bb69b7d16e" + integrity sha512-uiOalFKPG937UCLm42RxjESTWUVpbbatvlphQAU6bsv+ence6IoVG8JOUZcy8eW81NkU+Idiwvx10WFLmR4MIg== dependencies: - "@floating-ui/dom" "^0.5.3" - use-isomorphic-layout-effect "^1.1.1" + "@floating-ui/dom" "^1.0.0" "@humanwhocodes/config-array@^0.9.2": version "0.9.5" From 2b835096b1f8a8dff2ae0d053fc8a2dbbc49aed6 Mon Sep 17 00:00:00 2001 From: lawliet Date: Thu, 22 Sep 2022 12:22:14 +0800 Subject: [PATCH 4/4] fix: typo --- src/mantine-core/src/Tooltip/Tooltip.story.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mantine-core/src/Tooltip/Tooltip.story.tsx b/src/mantine-core/src/Tooltip/Tooltip.story.tsx index b33fd1b1795..503f56f296b 100644 --- a/src/mantine-core/src/Tooltip/Tooltip.story.tsx +++ b/src/mantine-core/src/Tooltip/Tooltip.story.tsx @@ -93,7 +93,7 @@ export const WithinGroup = () => ( ); -export const WithinArrow = () => ( +export const WithArrow = () => (