Skip to content

Commit

Permalink
fix(FloatingArrow): avoid requiring leading space for manually specif…
Browse files Browse the repository at this point in the history
…ied `transform` style property
  • Loading branch information
baylorpaul authored Sep 10, 2024
1 parent 0918ddd commit 42876ac
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 13 deletions.
5 changes: 5 additions & 0 deletions .changeset/rude-pugs-peel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@floating-ui/react": patch
---

fix(FloatingArrow): avoid requiring leading space for manually specified `transform` style property
4 changes: 3 additions & 1 deletion packages/react/src/components/FloatingArrow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ export interface FloatingArrowProps extends React.ComponentPropsWithRef<'svg'> {
tipRadius?: number;
/**
* Forces a static offset over dynamic positioning under a certain condition.
* If the shift() middleware causes the popover to shift, this value will be
* ignored.
*/
staticOffset?: string | number | null;
/**
Expand Down Expand Up @@ -154,7 +156,7 @@ export const FloatingArrow = React.forwardRef(function FloatingArrow(
isVerticalSide || isCustomShape
? '100%'
: `calc(100% - ${computedStrokeWidth / 2}px)`,
transform: `${rotation}${transform ?? ''}`,
transform: [rotation, transform].filter(t => !!t).join(' '),
...restStyle,
}}
>
Expand Down
70 changes: 60 additions & 10 deletions packages/react/test/visual/components/Arrow.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import type {Placement} from '@floating-ui/react';
import type { Middleware, Placement} from '@floating-ui/react';
import {hide} from '@floating-ui/react';
import {autoPlacement, shift} from '@floating-ui/react';
import {
arrow,
autoUpdate,
Expand All @@ -14,29 +16,33 @@ const ROUND_D =
'M0 20C0 20 2.06906 19.9829 5.91817 15.4092C7.49986 13.5236 8.97939 12.3809 10.0002 12.3809C11.0202 12.3809 12.481 13.6451 14.0814 15.5472C17.952 20.1437 20 20 20 20H0Z';

function Demo({
placement,
placement: placementProp,
arrowProps,
floatingStyle,
floatingProps,
middleware,
children,
}: {
placement: Placement;
arrowProps: Partial<React.SVGAttributes<SVGSVGElement> & FloatingArrowProps>;
placement?: Placement;
arrowProps?: Partial<React.SVGAttributes<SVGSVGElement> & FloatingArrowProps>;
floatingStyle?: React.CSSProperties;
floatingProps?: React.HTMLAttributes<HTMLDivElement>;
middleware?: Array<Middleware>;
children?: React.ReactNode;
}) {
const [isOpen, setIsOpen] = useState(true);

const arrowRef = useRef<SVGSVGElement>(null);

const {floatingStyles, refs, context} = useFloating({
placement,
const {floatingStyles, placement: finalPlacement, middlewareData, refs, context} = useFloating({
placement: placementProp,
open: isOpen,
onOpenChange: setIsOpen,
whileElementsMounted: autoUpdate,
middleware: [offset(8), arrow({element: arrowRef})],
middleware: [offset(8), ...(middleware ?? []), arrow({element: arrowRef})],
});

const edgeAlignment = placement.split('-')[1];
const edgeAlignment = placementProp?.split('-')[1];

return (
<div>
Expand All @@ -48,19 +54,22 @@ function Demo({
color: 'white',
}}
>
{placement}
{finalPlacement}
</span>
{isOpen && (
<div
ref={refs.setFloating}
className="bg-black text-white p-2 bg-clip-padding"
{...floatingProps}
style={{
visibility: middlewareData.hide?.referenceHidden
? 'hidden'
: 'visible',
...floatingStyles,
...floatingStyle,
}}
>
Tooltip
{children ?? 'Tooltip'}
<FloatingArrow
context={context}
ref={arrowRef}
Expand Down Expand Up @@ -184,6 +193,47 @@ export const Main = () => {
/>
))}
</div>
<h2 className="text-xl font-bold mb-6 mt-10">
Arrow with shift()
</h2>
<div className="grid grid-cols-1 place-items-center border border-slate-400 rounded lg:w-[40rem] h-[130rem] mb-4">
{allPlacements.map((placement) => (
<Demo
key={placement}
arrowProps={{
fill: 'rgba(255,0,0)',
staticOffset: undefined,
}}
floatingStyle={{
zIndex: 1500,
}}
placement={placement}
middleware={[
shift(),
// Use hide() so the examples are not shifted onto the screen while we're not looking at this section
hide()
]}
>
{'0123456789 '.repeat(40)}
</Demo>
))}
</div>
<h2 className="text-xl font-bold mb-6 mt-10">
Arrow with autoPlacement()
</h2>
<div className="grid grid-cols-3 place-items-center border border-slate-400 rounded lg:w-[40rem] h-[20rem] mb-4">
{allPlacements.map((placement) => (
<Demo
key={placement}
arrowProps={{
fill: 'rgba(255,0,0)',
}}
middleware={[
autoPlacement({allowedPlacements: [placement]})
]}
/>
))}
</div>
</>
);
};
3 changes: 2 additions & 1 deletion website/pages/docs/FloatingArrow.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,8 @@ default: `undefined{:js}` (use dynamic position)
A static offset override of the arrow from the floating element
edge. Often desirable if the floating element is smaller than the
reference element along the relevant axis and has an edge
alignment (`'start'{:js}`/`'end'{:js}`).
alignment (`'start'{:js}`/`'end'{:js}`). This is ignored if the
shift() middleware caused the floating element to shift.

```js
<FloatingArrow
Expand Down
2 changes: 1 addition & 1 deletion website/pages/docs/arrow.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ To help you understand how this middleware works, here is a
## Order
`arrow(){:js}` should generally be placed toward the end of your
middleware array, after `shift(){:js}` (if used).
middleware array, after `shift(){:js}` or `autoPlacement(){:js}` (if used).
## Placement
Expand Down

0 comments on commit 42876ac

Please sign in to comment.