Skip to content

Commit

Permalink
fix(media-query): fix an issue with useBreakpointValue (#4038)
Browse files Browse the repository at this point in the history
If one had used useBreakpointValue within an IFrame,
the root window element was used to determine the breakpoint.
Now the window from the current context is used.

Closes #3693
  • Loading branch information
cschroeter committed May 20, 2021
1 parent 256842c commit 7606076
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 7 deletions.
5 changes: 5 additions & 0 deletions .changeset/new-seas-attack.md
@@ -0,0 +1,5 @@
---
"@chakra-ui/media-query": patch
---

fix(media-query): fix an issue with useBreakpointValue
1 change: 1 addition & 0 deletions packages/media-query/package.json
Expand Up @@ -52,6 +52,7 @@
"lint:types": "tsc --noEmit"
},
"dependencies": {
"@chakra-ui/react-env": "1.0.4",
"@chakra-ui/utils": "1.8.0"
},
"devDependencies": {
Expand Down
6 changes: 4 additions & 2 deletions packages/media-query/src/use-breakpoint.ts
@@ -1,3 +1,4 @@
import { useEnvironment } from "@chakra-ui/react-env"
import { useTheme } from "@chakra-ui/system"
import React from "react"
import createMediaQueries from "./create-media-query"
Expand All @@ -24,6 +25,7 @@ export interface Breakpoint {
*/
export function useBreakpoint(defaultBreakpoint?: string) {
const { breakpoints } = useTheme()
const env = useEnvironment()

const mediaQueries = React.useMemo(
() => createMediaQueries({ base: "0px", ...breakpoints }),
Expand Down Expand Up @@ -62,7 +64,7 @@ export function useBreakpoint(defaultBreakpoint?: string) {
const listeners = new Set<Listener>()

mediaQueries.forEach(({ query, ...breakpoint }) => {
const mediaQuery = window.matchMedia(query)
const mediaQuery = env.window.matchMedia(query)

// trigger an initial update to determine media query
update(mediaQuery, breakpoint)
Expand Down Expand Up @@ -91,7 +93,7 @@ export function useBreakpoint(defaultBreakpoint?: string) {
})
listeners.clear()
}
}, [mediaQueries, breakpoints, update])
}, [mediaQueries, breakpoints, update, env.window])

return current
}
10 changes: 6 additions & 4 deletions packages/media-query/src/use-media-query.ts
@@ -1,5 +1,6 @@
import * as React from "react"
import { useEnvironment } from "@chakra-ui/react-env"
import { isBrowser } from "@chakra-ui/utils"
import * as React from "react"

const useSafeLayoutEffect = isBrowser ? React.useLayoutEffect : React.useEffect

Expand All @@ -9,19 +10,20 @@ const useSafeLayoutEffect = isBrowser ? React.useLayoutEffect : React.useEffect
* @param query the media query to match
*/
export function useMediaQuery(query: string | string[]): boolean[] {
const env = useEnvironment()
const queries = Array.isArray(query) ? query : [query]
const isSupported = isBrowser && "matchMedia" in window
const isSupported = isBrowser && "matchMedia" in env.window

const [matches, setMatches] = React.useState(
queries.map((query) =>
isSupported ? !!window.matchMedia(query).matches : false,
isSupported ? !!env.window.matchMedia(query).matches : false,
),
)

useSafeLayoutEffect(() => {
if (!isSupported) return undefined

const mediaQueryList = queries.map((query) => window.matchMedia(query))
const mediaQueryList = queries.map((query) => env.window.matchMedia(query))

const listenerList = mediaQueryList.map((mediaQuery, index) => {
const listener = () =>
Expand Down
28 changes: 27 additions & 1 deletion packages/media-query/stories/media-query.stories.tsx
@@ -1,5 +1,7 @@
import * as React from "react"
import { EnvironmentProvider } from "@chakra-ui/react-env"
import { chakra } from "@chakra-ui/system"
import * as React from "react"
import Frame from "react-frame-component"
import { Hide, Show, useBreakpoint, useBreakpointValue } from "../src"

export default {
Expand Down Expand Up @@ -49,3 +51,27 @@ export const BreakpointValueHook = () => {
</chakra.div>
)
}

export const BreakpointHookWithIFrame = () => {
return (
<>
<BreakpointValue />
<Frame style={{ background: "yellow", maxWidth: "600px", width: "100%" }}>
<EnvironmentProvider>
<BreakpointValue />
</EnvironmentProvider>
</Frame>
</>
)
}

const BreakpointValue = () => {
const breakpoint = useBreakpointValue({
base: "base",
sm: "sm",
md: "md",
lg: "lg",
xl: "xl",
})
return <p>Breakpoint: {breakpoint}</p>
}

1 comment on commit 7606076

@vercel
Copy link

@vercel vercel bot commented on 7606076 May 20, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.