-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathensure-is-media.js
119 lines (104 loc) · 2.84 KB
/
ensure-is-media.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import { promises as fs } from 'fs'
import ensureFile from './ensure-file.js'
import path from 'path'
let makeUseIsMedia = (
media,
isReactNative
) => `// This file is automatically generated by Views and will be overwritten
// when the morpher runs. If you want to contribute to how it's generated, eg,
// improving the algorithms inside, etc, see this:
// https://github.com/viewstools/morph/blob/master/ensure-is-media.js
// based on https://github.com/streamich/use-media
${isReactNative ? "import '@react-native-extra/match-media'" : ''}
import { useState, useEffect } from 'react'
let MOCK_MEDIA_QUERY_LIST = {
media: '',
matches: false,
addListener: () => {},
removeListener: () => {},
}
function matchMedia(query) {
if (typeof window === 'undefined') return MOCK_MEDIA_QUERY_LIST
return window.matchMedia(query)
}
function useMedia (query, defaultState = Boolean(matchMedia(query).matches)) {
let [state, setState] = useState(defaultState)
useEffect(() => {
let cancel = true
let mediaQueryList = matchMedia(query)
let onChange = () => {
if (!cancel) return
setState(Boolean(mediaQueryList.matches))
}
${
isReactNative
? "mediaQueryList.addEventListener('change', onChange)"
: 'mediaQueryList.addListener(onChange)'
}
setState(Boolean(mediaQueryList.matches))
return () => {
cancel = false
${
isReactNative
? "mediaQueryList.removeEventListener('change', onChange)"
: 'mediaQueryList.removeListener(onChange)'
}
}
}, [query])
return state
}
export default function useIsMedia() {
return {${media
.map(({ name, minWidth, maxWidth }) => {
let ret = [`"${name}": useMedia("(min-width: ${minWidth}px)`]
if (maxWidth) {
ret.push(` and (max-width: ${maxWidth}px)`)
}
ret.push('")')
return ret.join('')
})
.join(',')}
}
}
`
async function getMediaConfig(src) {
let media = {
mobile: {
width: 414,
},
tablet: {
width: 1024,
},
laptop: {
width: 1280,
},
}
try {
media = JSON.parse(
await fs.readFile(
path.resolve(path.join(src, '..', 'app.viewstools')),
'utf8'
)
).media
delete media.base
} catch (error) {}
return Object.entries(media)
.sort((a, b) => a[1].width - b[1].width)
.map(([name, item], index, list) => ({
name,
minWidth: index === 0 ? 0 : list[index - 1][1].width + 1,
maxWidth:
index === 0
? item.width
: index === list.length - 1
? null
: item.width,
}))
}
export default async function ensureIsMedia({ pass, src, as }) {
if (pass > 0) return false
return ensureFile({
file: path.join(src, 'Views', 'hooks', 'useIsMedia.js'),
content: makeUseIsMedia(await getMediaConfig(src), as === 'react-native'),
})
}