Skip to content

Commit 4e1ed2a

Browse files
authored
feat: allow locking/unlocking scroll when using hint overlays (#415)
* feat: allow locking/unlocking scroll when using hint overlays * fix check on scroll * make lock scroll more efficient
1 parent 5d9deef commit 4e1ed2a

File tree

6 files changed

+58
-7
lines changed

6 files changed

+58
-7
lines changed

apps/smithy/src/stories/Tour/Tour.stories.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export const Default = {
2020
variables: {
2121
firstName: "Euronymous Bosch",
2222
},
23+
lockScroll: true,
2324
},
2425
decorators: [
2526
(_: StoryFn, options: StoryContext) => {

packages/react/src/components/Hint/index.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export interface HintProps extends BoxProps {
2020
autoScroll?: ScrollIntoViewOptions | boolean
2121
children?: React.ReactNode
2222
defaultOpen?: boolean
23+
lockScroll?: boolean
2324
modal?: boolean
2425
onMount?: () => void
2526
onOpenChange?: (open: boolean) => void
@@ -37,6 +38,7 @@ export function Hint({
3738
children,
3839
css = {},
3940
defaultOpen = true,
41+
lockScroll = true,
4042
modal = false,
4143
onMount,
4244
onOpenChange = () => {},
@@ -120,8 +122,8 @@ export function Hint({
120122

121123
return (
122124
<>
123-
{spotlight && canonicalOpen && <Spotlight anchor={anchor} />}
124-
{modal && !spotlight && canonicalOpen && <Overlay lockScroll />}
125+
{spotlight && canonicalOpen && <Spotlight anchor={anchor} lockScroll={lockScroll} />}
126+
{modal && !spotlight && canonicalOpen && <Overlay lockScroll={lockScroll} />}
125127

126128
<Box
127129
css={{

packages/react/src/components/Overlay/index.tsx

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@ import { keyframes } from '@emotion/react'
44
import { Box, type BoxProps } from '@/components/Box'
55

66
import { RemoveScroll } from 'react-remove-scroll'
7+
import { useEffect, useState } from 'react'
78

8-
export interface OverlayProps extends BoxProps {}
9+
export interface OverlayProps extends BoxProps {
10+
lockScroll?: boolean
11+
}
912

1013
function OverlayWithRef(
11-
{ children, part, opacity = 0.5, ...props }: OverlayProps,
14+
{ children, lockScroll = true, part, opacity = 0.5, ...props }: OverlayProps,
1215
ref: React.ForwardedRef<HTMLDivElement>
1316
) {
1417
const fadeIn = keyframes`
@@ -20,8 +23,31 @@ function OverlayWithRef(
2023
}
2124
`
2225

26+
const [hasScrolled, setHasScrolled] = useState(false)
27+
28+
useEffect(() => {
29+
if (!lockScroll) {
30+
const handleScroll = () => {
31+
if (!hasScrolled) {
32+
setHasScrolled(true)
33+
window.removeEventListener('scroll', handleScroll)
34+
}
35+
}
36+
37+
window.addEventListener('scroll', handleScroll)
38+
39+
return () => {
40+
window.removeEventListener('scroll', handleScroll)
41+
}
42+
}
43+
}, [lockScroll, hasScrolled])
44+
45+
if (!lockScroll && hasScrolled) {
46+
return <>{children}</>
47+
}
48+
2349
return (
24-
<RemoveScroll forwardProps ref={ref}>
50+
<RemoveScroll forwardProps ref={ref} enabled={lockScroll}>
2551
<Box
2652
animation={`${fadeIn} 300ms ease-out`}
2753
backgroundColor="black"

packages/react/src/components/Spotlight/index.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,16 @@ function getComputedRadius(element: ReferenceElement) {
5555

5656
export interface SpotlightProps extends OverlayProps {
5757
anchor: string
58+
lockScroll?: boolean
5859
}
5960

60-
export function Spotlight({ anchor, part, style = {}, ...props }: SpotlightProps) {
61+
export function Spotlight({
62+
anchor,
63+
lockScroll = true,
64+
part,
65+
style = {},
66+
...props
67+
}: SpotlightProps) {
6168
const [clipPathCoords, setClipPathCoords] = useState<ClipPathCoords>({
6269
maxX: 0,
6370
maxY: 0,
@@ -109,6 +116,7 @@ export function Spotlight({ anchor, part, style = {}, ...props }: SpotlightProps
109116

110117
return (
111118
<Overlay
119+
lockScroll={lockScroll}
112120
part={['spotlight', part]}
113121
ref={refs.setFloating}
114122
style={{

packages/react/src/components/Tour/Tour.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ export interface TourProps extends FlowPropsWithoutChildren, Omit<HintProps, 'an
2727
* Whether the tooltip should be open by default.
2828
*/
2929
defaultOpen?: boolean
30+
/**
31+
* Whether to lock the scroll of the container when the Spotlight is enabled.
32+
* Defaults to `true`.
33+
*/
34+
lockScroll?: boolean
3035
/**
3136
* Whether to render a modal overlay behind the tooltip.
3237
*/
@@ -82,6 +87,7 @@ export function Tour({ as, flowId, ...props }: TourProps) {
8287
autoScroll = false,
8388
container = 'body',
8489
defaultOpen,
90+
lockScroll = true,
8591
modal,
8692
onOpenChange,
8793
open,
@@ -127,7 +133,12 @@ export function Tour({ as, flowId, ...props }: TourProps) {
127133
zIndex={zIndex}
128134
{...containerProps}
129135
>
130-
<TourStep defaultOpen={defaultOpen ?? true} key={step.id} {...sequentialStepProps} />
136+
<TourStep
137+
defaultOpen={defaultOpen ?? true}
138+
key={step.id}
139+
lockScroll={lockScroll}
140+
{...sequentialStepProps}
141+
/>
131142
</TourWrapper>
132143
)
133144
}
@@ -198,6 +209,7 @@ export function Tour({ as, flowId, ...props }: TourProps) {
198209
}}
199210
defaultOpen={(defaultOpen || shouldShowSpotlight) ?? false}
200211
key={`${currentStep.id}-${shouldShowSpotlight}`}
212+
lockScroll={lockScroll}
201213
step={currentStep}
202214
{...nonSequentialStepProps}
203215
/>

packages/react/src/components/Tour/TourStep.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export function TourStep({
3434
dismissible,
3535
flow,
3636
handleDismiss,
37+
lockScroll,
3738
modal,
3839
onPrimary,
3940
onSecondary,
@@ -63,6 +64,7 @@ export function TourStep({
6364
autoScroll={autoScroll}
6465
data-step-id={step.id}
6566
defaultOpen={defaultOpen}
67+
lockScroll={lockScroll}
6668
modal={modal}
6769
part={part}
6870
side={side}

0 commit comments

Comments
 (0)