vue-viewports 3.1.2 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +123 -50
- package/dist/composable.d.ts +16 -0
- package/dist/core.d.ts +33 -0
- package/dist/index.d.ts +4 -0
- package/dist/plugin.d.ts +31 -0
- package/dist/types.d.ts +16 -0
- package/dist/vue-viewports.cjs +1 -0
- package/dist/vue-viewports.js +54 -1
- package/package.json +60 -20
- package/.babelrc +0 -16
- package/.eslintrc.js +0 -3
- package/.travis.yml +0 -24
- package/src/index.js +0 -50
- package/src/matchMedia.js +0 -22
- package/src/store.js +0 -34
- package/webpack.config.js +0 -27
package/README.md
CHANGED
|
@@ -1,73 +1,146 @@
|
|
|
1
1
|
# vue-viewports
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Named, reactive, `matchMedia`-based viewport breakpoints for Vue 3 — a tiny plugin **and** composable.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/vue-viewports)
|
|
6
|
+
[](https://github.com/scaccogatto/vue-viewports/actions/workflows/ci.yml)
|
|
7
|
+
[](https://bundlephobia.com/package/vue-viewports)
|
|
8
|
+
[](./LICENSE)
|
|
6
9
|
|
|
7
|
-
|
|
8
|
-
- Exposes a fully updated viewport name
|
|
10
|
+
Define your breakpoints once, get the **current viewport** reactively in every component. No resize listeners, no debouncing — it is backed by the browser's [`matchMedia`](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia) and updates only when a breakpoint is actually crossed.
|
|
9
11
|
|
|
10
|
-
|
|
12
|
+
- **Reactive everywhere** — the current viewport is a shared `ref`; templates, `computed`, and `watch` all update automatically.
|
|
13
|
+
- **Two APIs** — a Vue plugin (`$currentViewport` on every component) and a `useViewport()` composable.
|
|
14
|
+
- **Typed** — ships first-class TypeScript types and a single bundled `.d.ts`.
|
|
15
|
+
- **Tiny & zero-dependency** — < 1 kB gzipped, `vue` is the only (peer) dependency.
|
|
16
|
+
- **ESM + CJS** — works with Vite and bundlers.
|
|
11
17
|
|
|
12
|
-
|
|
18
|
+
## Installation
|
|
13
19
|
|
|
14
20
|
```shell
|
|
15
|
-
npm install vue-viewports
|
|
21
|
+
npm install vue-viewports
|
|
16
22
|
```
|
|
17
23
|
|
|
18
|
-
|
|
24
|
+
Requires **Vue 3.3+**.
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
### Composable (`<script setup>`)
|
|
19
29
|
|
|
20
|
-
```
|
|
30
|
+
```vue
|
|
31
|
+
<script setup lang="ts">
|
|
32
|
+
import { useViewport } from 'vue-viewports'
|
|
33
|
+
|
|
34
|
+
const viewport = useViewport()
|
|
35
|
+
// viewport.value is { rule, label } | undefined
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<template>
|
|
39
|
+
<p>Current viewport: {{ viewport?.label ?? 'unknown' }}</p>
|
|
40
|
+
<DesktopNav v-if="viewport?.label === 'desktop'" />
|
|
41
|
+
<MobileNav v-else />
|
|
42
|
+
</template>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
`useViewport()` returns a `readonly` ref. It lazily initializes the [default breakpoints](#default-breakpoints) on first use, so it works without the plugin. The value is `undefined` while no breakpoint matches (e.g. a width below the smallest `rule`).
|
|
46
|
+
|
|
47
|
+
### Plugin
|
|
48
|
+
|
|
49
|
+
Install the plugin to expose `$currentViewport` on every component and to register your own breakpoints app-wide.
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
import { createApp } from 'vue'
|
|
21
53
|
import VueViewports from 'vue-viewports'
|
|
54
|
+
import App from './App.vue'
|
|
55
|
+
|
|
56
|
+
createApp(App)
|
|
57
|
+
.use(VueViewports) // default breakpoints
|
|
58
|
+
.mount('#app')
|
|
59
|
+
```
|
|
22
60
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
rule: '
|
|
30
|
-
label: '
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
rule: '2560px',
|
|
42
|
-
label: 'qhd-desktop'
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
rule: '3840px',
|
|
46
|
-
label: 'uhd-desktop'
|
|
47
|
-
}
|
|
48
|
-
]
|
|
49
|
-
|
|
50
|
-
Vue.use(VueViewports, options)
|
|
61
|
+
With custom breakpoints:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
createApp(App)
|
|
65
|
+
.use(VueViewports, [
|
|
66
|
+
{ rule: '600px', label: 'small' },
|
|
67
|
+
{ rule: '900px', label: 'medium' },
|
|
68
|
+
{ rule: '1200px', label: 'large' },
|
|
69
|
+
])
|
|
70
|
+
.mount('#app')
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Then, in any component:
|
|
74
|
+
|
|
75
|
+
```vue
|
|
76
|
+
<template>
|
|
77
|
+
<header :class="$currentViewport?.label">…</header>
|
|
78
|
+
</template>
|
|
51
79
|
```
|
|
52
80
|
|
|
53
|
-
|
|
81
|
+
The plugin is **authoritative**: installing it (re)configures the shared state, overriding any defaults a composable may have lazily set up.
|
|
54
82
|
|
|
55
|
-
|
|
83
|
+
### Custom breakpoints with the composable
|
|
56
84
|
|
|
57
|
-
|
|
85
|
+
You can also configure breakpoints without the plugin by calling `setupViewports` once (e.g. in your entry file):
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
import { setupViewports } from 'vue-viewports'
|
|
89
|
+
|
|
90
|
+
setupViewports([{ rule: '600px', label: 'small' }, { rule: '1200px', label: 'large' }])
|
|
91
|
+
```
|
|
58
92
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
93
|
+
## API
|
|
94
|
+
|
|
95
|
+
| Export | Description |
|
|
96
|
+
| --- | --- |
|
|
97
|
+
| `default` / `VueViewports` | Vue 3 plugin. `app.use(VueViewports, viewports?)`. |
|
|
98
|
+
| `useViewport()` | Composable returning `Readonly<Ref<ViewportMatch \| undefined>>`. |
|
|
99
|
+
| `setupViewports(viewports?)` | Imperatively (re)configure breakpoints; returns a teardown function. Idempotent. |
|
|
100
|
+
| `defaultViewports` | The built-in breakpoints. |
|
|
101
|
+
| `toMediaQuery(rule)` | `'768px'` → `'(min-width: 768px)'`. |
|
|
102
|
+
| `computeMatch(viewports)` | Pure-ish helper: the largest currently matching viewport. |
|
|
103
|
+
| `viewportInjectionKey` | `InjectionKey` for the readonly ref provided by the plugin. |
|
|
104
|
+
| `$currentViewport` | Component property added by the plugin: `ViewportMatch \| undefined`. |
|
|
105
|
+
|
|
106
|
+
### Types
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
interface ViewportConfig {
|
|
110
|
+
readonly rule: string // CSS length used as `min-width`, e.g. '768px'
|
|
111
|
+
readonly label: string // your name for the viewport, e.g. 'tablet'
|
|
66
112
|
}
|
|
113
|
+
type ViewportMatch = ViewportConfig
|
|
114
|
+
type ViewportConfigList = readonly ViewportConfig[]
|
|
67
115
|
```
|
|
68
116
|
|
|
69
|
-
|
|
117
|
+
`rule` is the width at which the viewport **starts** (inclusive); the matching viewport is the largest one whose `min-width` is satisfied.
|
|
118
|
+
|
|
119
|
+
### Default breakpoints
|
|
120
|
+
|
|
121
|
+
| label | starts at (`min-width`) |
|
|
122
|
+
| --- | --- |
|
|
123
|
+
| `mobile` | `320px` |
|
|
124
|
+
| `tablet` | `768px` |
|
|
125
|
+
| `desktop` | `1024px` |
|
|
126
|
+
| `hd-desktop` | `1920px` |
|
|
127
|
+
| `qhd-desktop` | `2560px` |
|
|
128
|
+
| `uhd-desktop` | `3840px` |
|
|
129
|
+
|
|
130
|
+
## Migrating from v3 (Vue 2)
|
|
131
|
+
|
|
132
|
+
`v4` is a full Vue 3 + TypeScript rewrite. The old `v3.x` line (Vue 2) remains installable for legacy projects: `npm install vue-viewports@3`.
|
|
133
|
+
|
|
134
|
+
| v3.x (Vue 2) | v4 (Vue 3) |
|
|
135
|
+
| --- | --- |
|
|
136
|
+
| `Vue.use(VueViewports, options)` | `createApp(App).use(VueViewports, options)` |
|
|
137
|
+
| `this.$currentViewport` | `this.$currentViewport` (unchanged) or `useViewport()` |
|
|
138
|
+
| Object getters `{ rule, label }` | Plain reactive `{ rule, label }` object |
|
|
139
|
+
| Not reactive ([#6](https://github.com/scaccogatto/vue-viewports/issues/6)) | Fully reactive (`ref`-backed) |
|
|
140
|
+
| Bundled a `matchMedia` polyfill | Uses the native `matchMedia` API |
|
|
141
|
+
|
|
142
|
+
The `options` shape (`[{ rule, label }]`) is unchanged, so most apps only need to swap `Vue.use` for `createApp(...).use`.
|
|
70
143
|
|
|
71
|
-
|
|
144
|
+
## License
|
|
72
145
|
|
|
73
|
-
|
|
146
|
+
[MIT](./LICENSE) © Marco Boffo
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { DeepReadonly, Ref } from 'vue';
|
|
2
|
+
import { ViewportMatch } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Reactive access to the current viewport from any component.
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* const viewport = useViewport()
|
|
8
|
+
* watchEffect(() => console.log(viewport.value?.label))
|
|
9
|
+
* ```
|
|
10
|
+
*
|
|
11
|
+
* If the {@link VueViewports} plugin has been installed, this returns the state
|
|
12
|
+
* configured there. Otherwise it lazily initializes the default breakpoints on
|
|
13
|
+
* first call (no-op during SSR). The value is `undefined` until the first match
|
|
14
|
+
* is computed and whenever no viewport matches.
|
|
15
|
+
*/
|
|
16
|
+
export declare const useViewport: () => DeepReadonly<Ref<ViewportMatch | undefined>>;
|
package/dist/core.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { DeepReadonly, Ref } from 'vue';
|
|
2
|
+
import { ViewportConfig, ViewportConfigList, ViewportMatch } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Sensible default breakpoints, ordered from smallest to largest.
|
|
5
|
+
* Override them by passing your own list to the plugin or composable.
|
|
6
|
+
*/
|
|
7
|
+
export declare const defaultViewports: ViewportConfigList;
|
|
8
|
+
/** `'768px'` -> `'(min-width: 768px)'`. */
|
|
9
|
+
export declare const toMediaQuery: (rule: string) => string;
|
|
10
|
+
/**
|
|
11
|
+
* The largest viewport whose `min-width` currently matches, or `undefined`
|
|
12
|
+
* when none match. Pure with respect to its input: reads only `matchMedia`.
|
|
13
|
+
*/
|
|
14
|
+
export declare const computeMatch: (viewports: ViewportConfigList) => ViewportMatch | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* Register `matchMedia` listeners for every viewport and keep
|
|
17
|
+
* {@link currentViewport} in sync. Idempotent: tears down any previous setup
|
|
18
|
+
* first. Returns a teardown function that removes the listeners.
|
|
19
|
+
*/
|
|
20
|
+
export declare const setupViewports: (viewports?: ViewportConfigList) => (() => void);
|
|
21
|
+
/**
|
|
22
|
+
* Lazily set up the default viewports on first read from a composable, but
|
|
23
|
+
* only if a plugin (which is authoritative) has not already done so and the
|
|
24
|
+
* environment exposes `matchMedia` (skipped during SSR).
|
|
25
|
+
*/
|
|
26
|
+
export declare const ensureViewports: () => void;
|
|
27
|
+
/** Readonly handle to the shared reactive state, for composables. */
|
|
28
|
+
export declare const viewportRef: () => DeepReadonly<Ref<ViewportMatch | undefined>>;
|
|
29
|
+
/** Current value without subscribing reactively — used by the plugin getter. */
|
|
30
|
+
export declare const currentViewportValue: () => ViewportMatch | undefined;
|
|
31
|
+
/** Reset all state. Intended for tests. */
|
|
32
|
+
export declare const resetViewports: () => void;
|
|
33
|
+
export type { ViewportConfig, ViewportConfigList, ViewportMatch };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { VueViewports, VueViewports as default, viewportInjectionKey } from './plugin';
|
|
2
|
+
export { useViewport } from './composable';
|
|
3
|
+
export { defaultViewports, setupViewports, toMediaQuery, computeMatch } from './core';
|
|
4
|
+
export type { ViewportConfig, ViewportConfigList, ViewportMatch } from './types';
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { InjectionKey, Plugin } from 'vue';
|
|
2
|
+
import { viewportRef } from './core';
|
|
3
|
+
import { ViewportConfigList, ViewportMatch } from './types';
|
|
4
|
+
/** Inject key for the readonly current-viewport ref. */
|
|
5
|
+
export declare const viewportInjectionKey: InjectionKey<ReturnType<typeof viewportRef>>;
|
|
6
|
+
/**
|
|
7
|
+
* Vue 3 plugin. Sets up `matchMedia` listeners for the given viewports and
|
|
8
|
+
* exposes the current one as:
|
|
9
|
+
*
|
|
10
|
+
* - `this.$currentViewport` on every component (Options & global), and
|
|
11
|
+
* - an injectable readonly ref via {@link viewportInjectionKey}.
|
|
12
|
+
*
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { createApp } from 'vue'
|
|
15
|
+
* import VueViewports from 'vue-viewports'
|
|
16
|
+
*
|
|
17
|
+
* createApp(App).use(VueViewports).mount('#app')
|
|
18
|
+
* // or with custom breakpoints:
|
|
19
|
+
* createApp(App).use(VueViewports, [{ rule: '600px', label: 'small' }])
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* The plugin is authoritative: installing it always (re)configures the shared
|
|
23
|
+
* state, overriding any lazy defaults a composable may have set up.
|
|
24
|
+
*/
|
|
25
|
+
export declare const VueViewports: Plugin<[ViewportConfigList?]>;
|
|
26
|
+
declare module 'vue' {
|
|
27
|
+
interface ComponentCustomProperties {
|
|
28
|
+
/** The current viewport, or `undefined` when none matches. */
|
|
29
|
+
readonly $currentViewport: ViewportMatch | undefined;
|
|
30
|
+
}
|
|
31
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A single viewport definition.
|
|
3
|
+
*
|
|
4
|
+
* `rule` is the CSS length at which the viewport starts (used as `min-width`),
|
|
5
|
+
* e.g. `'768px'`. `label` is the human-readable name, e.g. `'tablet'`.
|
|
6
|
+
*/
|
|
7
|
+
export interface ViewportConfig {
|
|
8
|
+
readonly rule: string;
|
|
9
|
+
readonly label: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The currently matching viewport, or `undefined` when no viewport matches
|
|
13
|
+
* (e.g. a width smaller than the smallest configured `rule`).
|
|
14
|
+
*/
|
|
15
|
+
export type ViewportMatch = ViewportConfig;
|
|
16
|
+
export type ViewportConfigList = readonly ViewportConfig[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});let e=require("vue");var t=[{rule:`320px`,label:`mobile`},{rule:`768px`,label:`tablet`},{rule:`1024px`,label:`desktop`},{rule:`1920px`,label:`hd-desktop`},{rule:`2560px`,label:`qhd-desktop`},{rule:`3840px`,label:`uhd-desktop`}],n=(0,e.ref)(void 0),r,i=!1,a=e=>`(min-width: ${e})`,o=e=>Number.parseFloat(e),s=e=>{let t=[...e].sort((e,t)=>o(e.rule)-o(t.rule)).filter(e=>window.matchMedia(a(e.rule)).matches).at(-1);return t?{rule:t.rule,label:t.label}:void 0},c=(e=t)=>{r?.();let o=e.map(e=>window.matchMedia(a(e.rule))),c=()=>{n.value=s(e)};o.forEach(e=>e.addEventListener(`change`,c)),c(),i=!0;let l=()=>{o.forEach(e=>e.removeEventListener(`change`,c)),r===l&&(r=void 0)};return r=l,l},l=()=>{i||typeof window>`u`||typeof window.matchMedia!=`function`||c(t)},u=()=>(0,e.readonly)(n),d=()=>n.value,f=Symbol(`vue-viewports`),p={install(e,n=t){c(n),Object.defineProperty(e.config.globalProperties,"$currentViewport",{configurable:!0,enumerable:!0,get:()=>d()}),e.provide(f,u())}},m=()=>(l(),u());exports.VueViewports=p,exports.default=p,exports.computeMatch=s,exports.defaultViewports=t,exports.setupViewports=c,exports.toMediaQuery=a,exports.useViewport=m,exports.viewportInjectionKey=f;
|
package/dist/vue-viewports.js
CHANGED
|
@@ -1 +1,54 @@
|
|
|
1
|
-
|
|
1
|
+
import { readonly as e, ref as t } from "vue";
|
|
2
|
+
//#region src/core.ts
|
|
3
|
+
var n = [
|
|
4
|
+
{
|
|
5
|
+
rule: "320px",
|
|
6
|
+
label: "mobile"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
rule: "768px",
|
|
10
|
+
label: "tablet"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
rule: "1024px",
|
|
14
|
+
label: "desktop"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
rule: "1920px",
|
|
18
|
+
label: "hd-desktop"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
rule: "2560px",
|
|
22
|
+
label: "qhd-desktop"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
rule: "3840px",
|
|
26
|
+
label: "uhd-desktop"
|
|
27
|
+
}
|
|
28
|
+
], r = t(void 0), i, a = !1, o = (e) => `(min-width: ${e})`, s = (e) => Number.parseFloat(e), c = (e) => {
|
|
29
|
+
let t = [...e].sort((e, t) => s(e.rule) - s(t.rule)).filter((e) => window.matchMedia(o(e.rule)).matches).at(-1);
|
|
30
|
+
return t ? {
|
|
31
|
+
rule: t.rule,
|
|
32
|
+
label: t.label
|
|
33
|
+
} : void 0;
|
|
34
|
+
}, l = (e = n) => {
|
|
35
|
+
i?.();
|
|
36
|
+
let t = e.map((e) => window.matchMedia(o(e.rule))), s = () => {
|
|
37
|
+
r.value = c(e);
|
|
38
|
+
};
|
|
39
|
+
t.forEach((e) => e.addEventListener("change", s)), s(), a = !0;
|
|
40
|
+
let l = () => {
|
|
41
|
+
t.forEach((e) => e.removeEventListener("change", s)), i === l && (i = void 0);
|
|
42
|
+
};
|
|
43
|
+
return i = l, l;
|
|
44
|
+
}, u = () => {
|
|
45
|
+
a || typeof window > "u" || typeof window.matchMedia != "function" || l(n);
|
|
46
|
+
}, d = () => e(r), f = () => r.value, p = Symbol("vue-viewports"), m = { install(e, t = n) {
|
|
47
|
+
l(t), Object.defineProperty(e.config.globalProperties, "$currentViewport", {
|
|
48
|
+
configurable: !0,
|
|
49
|
+
enumerable: !0,
|
|
50
|
+
get: () => f()
|
|
51
|
+
}), e.provide(p, d());
|
|
52
|
+
} }, h = () => (u(), d());
|
|
53
|
+
//#endregion
|
|
54
|
+
export { m as VueViewports, m as default, c as computeMatch, n as defaultViewports, l as setupViewports, o as toMediaQuery, h as useViewport, p as viewportInjectionKey };
|
package/package.json
CHANGED
|
@@ -1,35 +1,75 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vue-viewports",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
|
+
"description": "Named, reactive, matchMedia-based viewport breakpoints for Vue 3 — a tiny plugin and composable.",
|
|
5
|
+
"type": "module",
|
|
5
6
|
"author": {
|
|
6
7
|
"name": "Marco Boffo",
|
|
7
8
|
"email": "marcoboffo.waves@gmail.com"
|
|
8
9
|
},
|
|
10
|
+
"license": "MIT",
|
|
9
11
|
"repository": {
|
|
10
12
|
"type": "git",
|
|
11
|
-
"url": "https://github.com/scaccogatto/vue-viewports.git"
|
|
13
|
+
"url": "git+https://github.com/scaccogatto/vue-viewports.git"
|
|
12
14
|
},
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
+
"homepage": "https://github.com/scaccogatto/vue-viewports#readme",
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/scaccogatto/vue-viewports/issues"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"vue",
|
|
21
|
+
"vue3",
|
|
22
|
+
"viewport",
|
|
23
|
+
"viewports",
|
|
24
|
+
"responsive",
|
|
25
|
+
"breakpoints",
|
|
26
|
+
"media-query",
|
|
27
|
+
"matchmedia",
|
|
28
|
+
"composable",
|
|
29
|
+
"plugin"
|
|
30
|
+
],
|
|
31
|
+
"sideEffects": false,
|
|
32
|
+
"main": "./dist/vue-viewports.cjs",
|
|
33
|
+
"module": "./dist/vue-viewports.js",
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"exports": {
|
|
36
|
+
".": {
|
|
37
|
+
"types": "./dist/index.d.ts",
|
|
38
|
+
"import": "./dist/vue-viewports.js",
|
|
39
|
+
"require": "./dist/vue-viewports.cjs"
|
|
40
|
+
},
|
|
41
|
+
"./package.json": "./package.json"
|
|
42
|
+
},
|
|
43
|
+
"files": [
|
|
44
|
+
"dist"
|
|
45
|
+
],
|
|
15
46
|
"scripts": {
|
|
16
|
-
"
|
|
17
|
-
"
|
|
47
|
+
"dev": "vite",
|
|
48
|
+
"build": "vite build",
|
|
49
|
+
"typecheck": "tsc --noEmit",
|
|
50
|
+
"test": "vitest run",
|
|
51
|
+
"test:watch": "vitest",
|
|
52
|
+
"coverage": "vitest run --coverage",
|
|
53
|
+
"lint": "eslint .",
|
|
54
|
+
"prepublishOnly": "npm run build"
|
|
18
55
|
},
|
|
19
|
-
"
|
|
20
|
-
"vue": "^
|
|
56
|
+
"peerDependencies": {
|
|
57
|
+
"vue": "^3.3.0"
|
|
21
58
|
},
|
|
22
59
|
"devDependencies": {
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"eslint
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
60
|
+
"@eslint/js": "^10.0.1",
|
|
61
|
+
"@vitest/coverage-v8": "^4.1.9",
|
|
62
|
+
"@vue/test-utils": "^2.4.11",
|
|
63
|
+
"eslint": "^10.6.0",
|
|
64
|
+
"jsdom": "^29.1.1",
|
|
65
|
+
"typescript": "^6.0.3",
|
|
66
|
+
"typescript-eslint": "^8.62.0",
|
|
67
|
+
"vite": "^8.1.0",
|
|
68
|
+
"vite-plugin-dts": "^5.0.3",
|
|
69
|
+
"vitest": "^4.1.9",
|
|
70
|
+
"vue": "^3.5.39"
|
|
71
|
+
},
|
|
72
|
+
"engines": {
|
|
73
|
+
"node": ">=20"
|
|
34
74
|
}
|
|
35
75
|
}
|
package/.babelrc
DELETED
package/.eslintrc.js
DELETED
package/.travis.yml
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
language: node_js
|
|
2
|
-
|
|
3
|
-
node_js:
|
|
4
|
-
- lts/carbon
|
|
5
|
-
|
|
6
|
-
install:
|
|
7
|
-
- npm install
|
|
8
|
-
|
|
9
|
-
script:
|
|
10
|
-
- npm run start
|
|
11
|
-
|
|
12
|
-
cache:
|
|
13
|
-
directories:
|
|
14
|
-
- node_modules
|
|
15
|
-
|
|
16
|
-
deploy:
|
|
17
|
-
provider: npm
|
|
18
|
-
email: marcoboffo.waves@gmail.com
|
|
19
|
-
skip_cleanup: true
|
|
20
|
-
api_key:
|
|
21
|
-
secure: O232hq84yuYDU7vXTXc8Mu9UFdEL7rpA/9b+E8WDd4O7m/BWbeHdG1VTLK4FHq2jP27jekVGB1WpmrM+wiSg5TpYm0l0540iqadv6x1VBGeEkTdY44M3I93UbmDa6rM7w9vxdU3jm2LweS59PnXWeKAMDQ3FKlDKnIL/Rw1eKGlAVdRDFGY2lMpMmQQNvLXXMCchcceLDLAElcIRPi3CGpjYttpTlFbTayaRkObwHuZphCOB/9e3t/0ZtCM5W9iWBe6F+2+WoOLgL+qMVv7b1r458CWR3wS7FyLzT/jg9sl06Uqhcau6W29HfH2RnCYuS4uuNIITtDRKn6xOGLJr3XmJbhsqTDGVk6ybvnI20ltkOXZNDaMFYrWaEN+ibl/2c4itGUTsUg/EAMV7s37+W3rcB0Q3BPFXw3zFDT0AyVEpXpo6hvcti+leodZ2JA6CUco/KHPov31lfr6zh7B+TyFNQrFJeAVKTLng5TLJlkPQOe3fVFrZZmqKaD+s73EI/kGvgwclcoWqu2pVoEE/S7x6lwKFsT4nmw8Q0AGuJ2YTOTNw2Ky0S1siBeEFAlThST9HqaGL9qwDHOiO/4E1croGpuJjT6Xf472H43orCP+s9RFg506I9+Qy0cq2qI+ouBk7EIqpxdTAt/Rm55RnDVMjyj7moIbM2QzEgrWeR+8=
|
|
22
|
-
on:
|
|
23
|
-
tags: true
|
|
24
|
-
repo: scaccogatto/vue-viewports
|
package/src/index.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { store, defaultOptions } from './store'
|
|
2
|
-
import { toMatchMedia, updateMatchStatus } from './matchMedia'
|
|
3
|
-
|
|
4
|
-
const VueViewports = {
|
|
5
|
-
install (Vue, options = defaultOptions) {
|
|
6
|
-
// save sizes
|
|
7
|
-
store.sizes = options
|
|
8
|
-
|
|
9
|
-
// create matchMediaObjects https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia
|
|
10
|
-
const matchMedia = store.sizes.map(toMatchMedia)
|
|
11
|
-
|
|
12
|
-
// save it
|
|
13
|
-
store.matchMedia = matchMedia
|
|
14
|
-
|
|
15
|
-
// add listeners
|
|
16
|
-
store.matchMedia.forEach(matchMediaObj => matchMediaObj.addListener(updateMatchStatus))
|
|
17
|
-
|
|
18
|
-
// first trigger
|
|
19
|
-
store.matchMedia.forEach(updateMatchStatus)
|
|
20
|
-
|
|
21
|
-
// global call
|
|
22
|
-
window.Object.defineProperty(Vue.prototype, '$currentViewport', {
|
|
23
|
-
get: () => VueViewports._getPublicObject()
|
|
24
|
-
})
|
|
25
|
-
},
|
|
26
|
-
get currentViewport () {
|
|
27
|
-
return store.currentMatch
|
|
28
|
-
},
|
|
29
|
-
_getPublicObject () {
|
|
30
|
-
const { currentViewport } = VueViewports
|
|
31
|
-
if (typeof currentViewport !== 'undefined') {
|
|
32
|
-
const { rule, label } = VueViewports.currentViewport
|
|
33
|
-
return {
|
|
34
|
-
get rule () {
|
|
35
|
-
return rule
|
|
36
|
-
},
|
|
37
|
-
get label () {
|
|
38
|
-
return label
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export default VueViewports
|
|
46
|
-
|
|
47
|
-
// in-browser load
|
|
48
|
-
if (typeof window !== 'undefined' && window.Vue) {
|
|
49
|
-
window.Vue.use(VueViewports)
|
|
50
|
-
}
|
package/src/matchMedia.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import 'core-js/fn/array/find'
|
|
2
|
-
import 'core-js/fn/string/includes'
|
|
3
|
-
import { store } from './store'
|
|
4
|
-
|
|
5
|
-
const toMatchMedia = size => window.matchMedia(toMediaQuery(size.rule))
|
|
6
|
-
|
|
7
|
-
const toMediaQuery = rule => `(min-width: ${rule})`
|
|
8
|
-
|
|
9
|
-
const updateMatchStatus = ({ media, matches }) => {
|
|
10
|
-
// find the store rule, matching the event
|
|
11
|
-
const rule = store.sizes.find(size => media.includes(size.rule)).rule
|
|
12
|
-
|
|
13
|
-
if (matches) {
|
|
14
|
-
// if it matches, just set the rule
|
|
15
|
-
store.currentMatch = store.sizes.find(size => size.rule === rule)
|
|
16
|
-
} else {
|
|
17
|
-
// if it does not,find the greater matching rule and apply
|
|
18
|
-
store.currentMatch = store.sizes.slice(0).reverse().find(size => window.matchMedia(toMediaQuery(size.rule)).matches)
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export { toMatchMedia, toMediaQuery, updateMatchStatus }
|
package/src/store.js
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
const defaultOptions = [
|
|
2
|
-
{
|
|
3
|
-
rule: '320px',
|
|
4
|
-
label: 'mobile'
|
|
5
|
-
},
|
|
6
|
-
{
|
|
7
|
-
rule: '768px',
|
|
8
|
-
label: 'tablet'
|
|
9
|
-
},
|
|
10
|
-
{
|
|
11
|
-
rule: '1024px',
|
|
12
|
-
label: 'desktop'
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
rule: '1920px',
|
|
16
|
-
label: 'hd-desktop'
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
rule: '2560px',
|
|
20
|
-
label: 'qhd-desktop'
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
rule: '3840px',
|
|
24
|
-
label: 'uhd-desktop'
|
|
25
|
-
}
|
|
26
|
-
]
|
|
27
|
-
|
|
28
|
-
const store = {
|
|
29
|
-
sizes: undefined,
|
|
30
|
-
matchMedia: [],
|
|
31
|
-
currentMatch: undefined
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export { defaultOptions, store }
|
package/webpack.config.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
const webpack = require('webpack')
|
|
2
|
-
const path = require('path')
|
|
3
|
-
|
|
4
|
-
const config = {
|
|
5
|
-
entry: path.resolve(__dirname, 'src', 'index.js'),
|
|
6
|
-
output: {
|
|
7
|
-
path: path.resolve(__dirname, 'dist'),
|
|
8
|
-
filename: 'vue-viewports.js',
|
|
9
|
-
library: 'VueViewports',
|
|
10
|
-
libraryTarget: 'umd'
|
|
11
|
-
},
|
|
12
|
-
module: {
|
|
13
|
-
rules: [
|
|
14
|
-
{
|
|
15
|
-
test: /\.js$/,
|
|
16
|
-
include: path.resolve(__dirname, 'src'),
|
|
17
|
-
exclude: /node_modules/,
|
|
18
|
-
use: 'babel-loader'
|
|
19
|
-
}
|
|
20
|
-
]
|
|
21
|
-
},
|
|
22
|
-
plugins: [
|
|
23
|
-
new webpack.optimize.UglifyJsPlugin()
|
|
24
|
-
]
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
module.exports = config
|