Skip to content

Commit dee851e

Browse files
committed
feat(hooks): add useMedia hook
1 parent 6d55928 commit dee851e

File tree

5 files changed

+85
-1
lines changed

5 files changed

+85
-1
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
"markdown-it-link-attributes": "^2.1.0",
9595
"markdown-it-loader": "^0.7.0",
9696
"markdown-it-prism": "^2.0.2",
97+
"match-media-mock": "^0.1.1",
9798
"prettier": "^1.18.2",
9899
"prismjs": "^1.17.1",
99100
"rimraf": "^3.0.0",

src/__tests__/useMedia.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { onMounted, onUnmounted } from 'vue-function-api';
2+
import { useMedia } from '..';
3+
import renderHook from '../util/renderHook';
4+
5+
const matchMediaMock = require('match-media-mock').create();
6+
7+
matchMediaMock.setConfig({ type: 'screen', width: 1280, height: 800 });
8+
window.matchMedia = matchMediaMock;
9+
10+
describe('useMedia', () => {
11+
it('should be defined', () => {
12+
expect(useMedia).toBeDefined();
13+
});
14+
15+
it('should update matches', () => {
16+
const { vm } = renderHook<unknown>(() => {
17+
const pc = useMedia('(min-width: 768px)');
18+
const sp = useMedia('(max-width: 768px)');
19+
expect(pc.value).toBe(false);
20+
expect(sp.value).toBe(false);
21+
22+
onMounted(() => {
23+
expect(pc.value).toBe(true);
24+
expect(sp.value).toBe(false);
25+
26+
matchMediaMock.setConfig({ type: 'screen', width: 375, height: 667 });
27+
28+
expect(pc.value).toBe(false);
29+
expect(sp.value).toBe(true);
30+
});
31+
32+
onUnmounted(() => {
33+
matchMediaMock.setConfig({ type: 'screen', width: 1280, height: 800 });
34+
35+
expect(pc.value).toBe(false);
36+
expect(sp.value).toBe(true);
37+
});
38+
});
39+
40+
vm.$destroy();
41+
});
42+
});

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export { default as useRouter } from './useRouter';
1515
export { default as useRef } from './useRef';
1616
export { default as useMountedState } from './useMountedState';
1717
export { default as useTimeout } from './useTimeout';
18+
export { default as useMedia } from './useMedia';
1819

1920
export default function install(Vue: VueConstructor) {
2021
Vue.mixin({ beforeCreate: setRuntimeVM });

src/useMedia.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { value, onMounted, onUnmounted } from 'vue-function-api';
2+
3+
export default function useMedia(query, defaultState = false) {
4+
let mql;
5+
const matches = value(defaultState);
6+
const updateMatches = () => {
7+
if (mql) matches.value = mql.matches;
8+
};
9+
10+
onMounted(() => {
11+
mql = window.matchMedia(query);
12+
mql.addListener(updateMatches);
13+
matches.value = mql.matches;
14+
});
15+
16+
onUnmounted(() => {
17+
mql.removeListener(updateMatches);
18+
});
19+
20+
return matches;
21+
}

yarn.lock

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4115,6 +4115,11 @@ css-loader@^2.1.1:
41154115
postcss-value-parser "^3.3.0"
41164116
schema-utils "^1.0.0"
41174117

4118+
css-mediaquery@^0.1.2:
4119+
version "0.1.2"
4120+
resolved "https://registry.yarnpkg.com/css-mediaquery/-/css-mediaquery-0.1.2.tgz#6a2c37344928618631c54bd33cedd301da18bea0"
4121+
integrity sha1-aiw3NEkoYYYxxUvTPO3TAdoYvqA=
4122+
41184123
css-select@^1.1.0:
41194124
version "1.2.0"
41204125
resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858"
@@ -5190,6 +5195,11 @@ execa@^2.0.3:
51905195
signal-exit "^3.0.2"
51915196
strip-final-newline "^2.0.0"
51925197

5198+
exenv@^1.2.0:
5199+
version "1.2.2"
5200+
resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d"
5201+
integrity sha1-KueOhdmJQVhnCwPUe+wfA72Ru50=
5202+
51935203
exit@^0.1.2:
51945204
version "0.1.2"
51955205
resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c"
@@ -8011,7 +8021,7 @@ lodash@4.17.14:
80118021
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.14.tgz#9ce487ae66c96254fe20b599f21b6816028078ba"
80128022
integrity sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==
80138023

8014-
lodash@^4.0.1, lodash@^4.11.2, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.2.1:
8024+
lodash@^4.0.1, lodash@^4.11.2, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.1:
80158025
version "4.17.15"
80168026
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
80178027
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
@@ -8254,6 +8264,15 @@ marked@^0.7.0:
82548264
resolved "https://registry.yarnpkg.com/marked/-/marked-0.7.0.tgz#b64201f051d271b1edc10a04d1ae9b74bb8e5c0e"
82558265
integrity sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg==
82568266

8267+
match-media-mock@^0.1.1:
8268+
version "0.1.1"
8269+
resolved "https://registry.yarnpkg.com/match-media-mock/-/match-media-mock-0.1.1.tgz#25485e5b26942e56142ce147a8e1d59c406d85f8"
8270+
integrity sha512-YPCJ9HLrTkGQ5YV88TQraXnu/ZrEa2XCfefWY0cL84fq2gNhtmEVUA6tlO70eqCDJmRai7LQY3p8so9HPJ/oIQ==
8271+
dependencies:
8272+
css-mediaquery "^0.1.2"
8273+
exenv "^1.2.0"
8274+
lodash "^4.17.5"
8275+
82578276
material-colors@^1.2.1:
82588277
version "1.2.6"
82598278
resolved "https://registry.yarnpkg.com/material-colors/-/material-colors-1.2.6.tgz#6d1958871126992ceecc72f4bcc4d8f010865f46"

0 commit comments

Comments
 (0)