Skip to content

Commit cbe0e65

Browse files
committed
add hideArrow to Overlay #4311
1 parent 2d2d62b commit cbe0e65

9 files changed

Lines changed: 132 additions & 17 deletions

File tree

.changeset/shaggy-otters-cough.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@salt-ds/core": minor
3+
---
4+
5+
Add hideArrow prop to Overlay.

packages/core/src/overlay/Overlay.tsx

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,22 @@ export interface OverlayProps extends ComponentPropsWithoutRef<"div"> {
2222
* Callback function triggered when open state changes.
2323
*/
2424
onOpenChange?: (open: boolean) => void;
25-
/*
25+
/**
2626
* Set the placement of the Overlay component relative to the trigger element. Defaults to `top`.
2727
*/
2828
placement?: "top" | "bottom" | "left" | "right";
29+
/**
30+
* When `true`, the arrow indicator is hidden
31+
*/
32+
hideArrow?: boolean;
2933
}
3034

3135
export const Overlay = ({
3236
children,
3337
open,
3438
onOpenChange,
3539
placement: placementProp = "top",
40+
hideArrow = false,
3641
}: OverlayProps) => {
3742
const arrowRef = useRef<SVGSVGElement | null>(null);
3843

@@ -48,17 +53,31 @@ export const Overlay = ({
4853
onOpenChange?.(newOpen);
4954
};
5055

56+
const middleware = hideArrow
57+
? [
58+
offset(1),
59+
flip(),
60+
{
61+
name: "alignStart",
62+
fn({ rects }: { rects: { reference: { x: number } } }) {
63+
return { x: rects.reference.x };
64+
},
65+
},
66+
shift({ limiter: limitShift() }),
67+
]
68+
: [
69+
offset(11),
70+
flip(),
71+
shift({ limiter: limitShift() }),
72+
arrow({ element: arrowRef }),
73+
];
74+
5175
const { x, y, strategy, context, elements, floating, reference } =
5276
useFloatingUI({
5377
open: openState,
5478
onOpenChange: handleOpenChange,
5579
placement: placementProp,
56-
middleware: [
57-
offset(11),
58-
flip(),
59-
shift({ limiter: limitShift() }),
60-
arrow({ element: arrowRef }),
61-
],
80+
middleware,
6281
});
6382

6483
const { getReferenceProps, getFloatingProps } = useInteractions([
@@ -88,7 +107,7 @@ export const Overlay = ({
88107
openState,
89108
floatingStyles,
90109
context,
91-
arrowProps,
110+
arrowProps: hideArrow ? undefined : arrowProps,
92111
floating,
93112
reference,
94113
getFloatingProps,

packages/core/src/overlay/OverlayContext.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ type FloatingStyleProps = {
1919
export interface OverlayContextValue {
2020
openState: boolean;
2121
floatingStyles: FloatingStyleProps;
22-
arrowProps: FloatingArrowProps;
22+
arrowProps: FloatingArrowProps | undefined;
2323
context: FloatingContext;
2424
reference?: (node: ReferenceType | null) => void;
2525
floating?: (node: HTMLElement | null) => void;

packages/core/src/overlay/OverlayPanel.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,16 @@ export const OverlayPanel = forwardRef<HTMLDivElement, OverlayPanelProps>(
6868
aria-labelledby={ariaLabelledby}
6969
>
7070
<div {...rest}> {children} </div>
71-
<FloatingArrow
72-
{...arrowProps}
73-
strokeWidth={1}
74-
fill="var(--overlay-background)"
75-
stroke="var(--overlay-borderColor)"
76-
height={6}
77-
width={12}
78-
/>
71+
{arrowProps && (
72+
<FloatingArrow
73+
{...arrowProps}
74+
strokeWidth={1}
75+
fill="var(--overlay-background)"
76+
stroke="var(--overlay-borderColor)"
77+
height={6}
78+
width={12}
79+
/>
80+
)}
7981
</FloatingComponent>
8082
);
8183
},

packages/core/stories/overlay/overlay.qa.stories.tsx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,34 @@ DeprecatedCloseButton.parameters = {
127127
disableSnapshot: false,
128128
},
129129
};
130+
131+
export const HideArrow: StoryFn<QAContainerProps> = (props) => {
132+
return (
133+
<QAContainer
134+
height={800}
135+
cols={5}
136+
itemPadding={50}
137+
itemWidthAuto
138+
width={1200}
139+
{...props}
140+
>
141+
<Overlay open placement="bottom" hideArrow>
142+
<OverlayTrigger>
143+
<Button>Show Overlay</Button>
144+
</OverlayTrigger>
145+
<OverlayPanel>
146+
<OverlayPanelContent>
147+
<h3 className="content-heading">Title</h3>
148+
<div>Content of Overlay</div>
149+
</OverlayPanelContent>
150+
</OverlayPanel>
151+
</Overlay>
152+
</QAContainer>
153+
);
154+
};
155+
156+
HideArrow.parameters = {
157+
chromatic: {
158+
disableSnapshot: false,
159+
},
160+
};

packages/core/stories/overlay/overlay.stories.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,27 @@ Right.args = {
6060
placement: "right",
6161
};
6262

63+
export const HideArrow: StoryFn<OverlayProps> = ({ ...args }) => {
64+
const id = useId();
65+
66+
return (
67+
<Overlay placement="bottom" hideArrow {...args}>
68+
<OverlayTrigger>
69+
<Button>Show Overlay</Button>
70+
</OverlayTrigger>
71+
72+
<OverlayPanel aria-labelledby={id}>
73+
<OverlayPanelContent>
74+
<h3 id={id} className="content-heading">
75+
Title
76+
</h3>
77+
<div>Content of Overlay</div>
78+
</OverlayPanelContent>
79+
</OverlayPanel>
80+
</Overlay>
81+
);
82+
};
83+
6384
const HeaderTemplate: StoryFn = ({ onOpenChange, ...props }: OverlayProps) => {
6485
const [open, setOpen] = useState(false);
6586

site/docs/components/overlay/examples.mdx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,9 @@ With actions, users can decide if interacting with content in the overlay should
4545
**Note:** `OverlayPanelCloseButton` is deprecated. Use the prop `actions` within `OverlayHeader` instead.
4646

4747
<LivePreview componentName="overlay" exampleName="CloseButton" />
48+
49+
## Hide arrow
50+
51+
Use the `hideArrow` prop to display the overlay without the arrow.
52+
53+
<LivePreview componentName="overlay" exampleName="HideArrow" />
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import {
2+
Button,
3+
Overlay,
4+
OverlayPanel,
5+
OverlayPanelContent,
6+
OverlayTrigger,
7+
useId,
8+
} from "@salt-ds/core";
9+
import type { ReactElement } from "react";
10+
11+
import styles from "./index.module.css";
12+
13+
export const HideArrow = (): ReactElement => {
14+
const id = useId();
15+
return (
16+
<Overlay placement="bottom" hideArrow>
17+
<OverlayTrigger>
18+
<Button>Show Overlay</Button>
19+
</OverlayTrigger>
20+
<OverlayPanel aria-labelledby={id}>
21+
<OverlayPanelContent>
22+
<h3 className={styles.contentHeading} id={id}>
23+
Title
24+
</h3>
25+
<div>Content of Overlay</div>
26+
</OverlayPanelContent>
27+
</OverlayPanel>
28+
</Overlay>
29+
);
30+
};

site/src/examples/overlay/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export * from "./CloseButton";
22
export * from "./Default";
3+
export * from "./HideArrow";
34
export * from "./LongContent";
45
export * from "./Placement";
56
export * from "./WithActions";

0 commit comments

Comments
 (0)