1
+ import React from "react"
1
2
import { useEnvironment } from "@chakra-ui/react-env"
2
3
import { useTheme } from "@chakra-ui/system"
3
- import React from "react"
4
- import createMediaQueries from "./create-media-query"
5
-
6
- interface Listener {
7
- mediaQuery : MediaQueryList
8
- handleChange : ( ) => void
9
- }
10
-
11
- export interface Breakpoint {
12
- breakpoint : string
13
- maxWidth ?: string
14
- minWidth : string
15
- }
16
4
17
5
/**
18
6
* React hook used to get the current responsive media breakpoint.
@@ -24,89 +12,73 @@ export interface Breakpoint {
24
12
* to get the default breakpoint value from the user-agent
25
13
*/
26
14
export function useBreakpoint ( defaultBreakpoint ?: string ) {
27
- const { breakpoints } = useTheme ( )
15
+ const { __breakpoints } = useTheme ( )
28
16
const env = useEnvironment ( )
29
17
30
- const mediaQueries = React . useMemo (
31
- ( ) => createMediaQueries ( { base : "0px" , ...breakpoints } ) ,
32
- [ breakpoints ] ,
18
+ const queries = React . useMemo (
19
+ ( ) =>
20
+ __breakpoints ?. details . map ( ( { minMaxQuery, breakpoint } ) => ( {
21
+ breakpoint,
22
+ query : minMaxQuery . replace ( "@media screen and " , "" ) ,
23
+ } ) ) ?? [ ] ,
24
+ [ __breakpoints ] ,
33
25
)
34
26
35
27
const [ currentBreakpoint , setCurrentBreakpoint ] = React . useState ( ( ) => {
36
28
if ( env . window . matchMedia ) {
37
- let maxBreakpoint
38
- mediaQueries . forEach ( ( { query, ...breakpoint } ) => {
39
- const mediaQuery = env . window . matchMedia ( query )
40
- if ( mediaQuery . matches ) {
41
- maxBreakpoint = breakpoint
42
- }
43
- } )
44
- if ( maxBreakpoint ) {
45
- return maxBreakpoint
46
- }
29
+ // set correct breakpoint on first render
30
+ const matchingBreakpointDetail = queries . find (
31
+ ( { query } ) => env . window . matchMedia ( query ) . matches ,
32
+ )
33
+ return matchingBreakpointDetail ?. breakpoint
47
34
}
48
35
49
- if ( ! defaultBreakpoint ) {
50
- return undefined
51
- }
52
-
53
- const mediaQuery = mediaQueries . find (
54
- ( { breakpoint } ) => breakpoint === defaultBreakpoint ,
55
- )
56
-
57
- if ( mediaQuery ) {
58
- const { query, ...breakpoint } = mediaQuery
59
- return breakpoint
36
+ if ( defaultBreakpoint ) {
37
+ // use fallback if available
38
+ const fallbackBreakpointDetail = queries . find (
39
+ ( { breakpoint } ) => breakpoint === defaultBreakpoint ,
40
+ )
41
+ return fallbackBreakpointDetail ?. breakpoint
60
42
}
61
43
62
44
return undefined
63
45
} )
64
46
65
- const current = currentBreakpoint ?. breakpoint
47
+ React . useEffect ( ( ) => {
48
+ const allUnregisterFns = queries . map ( ( { breakpoint, query } ) => {
49
+ const mediaQueryList = env . window . matchMedia ( query )
66
50
67
- const update = React . useCallback (
68
- ( query : MediaQueryList , breakpoint : Breakpoint ) => {
69
- if ( query . matches && current !== breakpoint . breakpoint ) {
51
+ if ( mediaQueryList . matches ) {
70
52
setCurrentBreakpoint ( breakpoint )
71
53
}
72
- } ,
73
- [ current ] ,
74
- )
75
-
76
- React . useEffect ( ( ) => {
77
- const listeners = new Set < Listener > ( )
78
-
79
- mediaQueries . forEach ( ( { query, ...breakpoint } ) => {
80
- const mediaQuery = env . window . matchMedia ( query )
81
54
82
- // trigger an initial update to determine media query
83
- update ( mediaQuery , breakpoint )
84
-
85
- const handleChange = ( ) => {
86
- update ( mediaQuery , breakpoint )
55
+ const handleChange = ( ev : MediaQueryListEvent ) => {
56
+ if ( ev . matches ) {
57
+ setCurrentBreakpoint ( breakpoint )
58
+ }
87
59
}
88
60
89
- // add media query- listener
90
- mediaQuery . addListener ( handleChange )
91
-
92
- // push the media query list handleChange
93
- // so we can use it to remove Listener
94
- listeners . add ( { mediaQuery , handleChange } )
61
+ // add media query listener
62
+ if ( typeof mediaQueryList . addEventListener === "function" ) {
63
+ mediaQueryList . addEventListener ( "change" , handleChange )
64
+ } else {
65
+ mediaQueryList . addListener ( handleChange )
66
+ }
95
67
68
+ // return unregister fn
96
69
return ( ) => {
97
- // clean up 1
98
- mediaQuery . removeListener ( handleChange )
70
+ if ( typeof mediaQueryList . removeEventListener === "function" ) {
71
+ mediaQueryList . removeEventListener ( "change" , handleChange )
72
+ } else {
73
+ mediaQueryList . removeListener ( handleChange )
74
+ }
99
75
}
100
76
} )
101
77
102
78
return ( ) => {
103
- // clean up 2: for safety
104
- listeners . forEach ( ( { mediaQuery, handleChange } ) => {
105
- mediaQuery . removeListener ( handleChange )
106
- } )
107
- listeners . clear ( )
79
+ allUnregisterFns . forEach ( ( unregister ) => unregister ( ) )
108
80
}
109
- } , [ mediaQueries , breakpoints , update , env . window ] )
81
+ } , [ queries , __breakpoints , env . window ] )
110
82
111
- return current
83
+ return currentBreakpoint
112
84
}
0 commit comments