New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@vue-composable/web

Package Overview
Dependencies
Maintainers
1
Versions
25
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@vue-composable/web - npm Package Compare versions

Comparing version 1.0.0-dev.7 to 1.0.0-dev.8

549

dist/web.cjs.js

@@ -23,4 +23,3 @@ 'use strict';

};
const eventOptions = typeof options === "number" ? undefined : options;
const ms = typeof options === "number" ? options : wait;
const [eventOptions, ms] = core.isNumber(options) ? [undefined, options] : [options, wait];
if (ms) {

@@ -45,4 +44,3 @@ handler = core.useDebounce(handler, wait);

};
const eventOptions = typeof options === "number" ? undefined : options;
const ms = typeof options === "number" ? options : wait;
const [eventOptions, ms] = core.isNumber(options) ? [undefined, options] : [options, wait];
if (ms) {

@@ -52,3 +50,3 @@ handler = core.useDebounce(handler, wait);

// resize seems only to be fired against the window
const remove = useEvent(window, "resize", handler, eventOptions || { passive: true });
const remove = core.isClient ? useEvent(window, "resize", handler, eventOptions || { passive: true }) : core.NO_OP;
return {

@@ -69,4 +67,3 @@ height,

};
const eventOptions = typeof options === "number" ? undefined : options;
const ms = typeof options === "number" ? options : wait;
const [eventOptions, ms] = core.isNumber(options) ? [undefined, options] : [options, wait];
if (ms) {

@@ -117,3 +114,4 @@ handler = core.useDebounce(handler, wait);

function useWebSocket(url, protocols) {
const ws = new WebSocket(url, protocols);
const supported = core.isClient && 'WebSocket' in window;
let ws = null;
const messageEvent = compositionApi.ref(null);

@@ -127,33 +125,39 @@ const errorEvent = compositionApi.ref();

let lastMessage = ( Date.now()) || undefined;
ws.addEventListener("message", x => {
messageEvent.value = x;
data.value = x.data;
// if the messages are to quick, we need to warn
/* istanbul ignore else */
{
if (Date.now() - lastMessage < 2) {
console.warn('[useWebSocket] message rate is too high, if you are using "data" or "messageEvent"' +
" you might not get updated of all the messages." +
' Use "ws..addEventListener("message", handler)" instead');
let send = core.NO_OP;
let close = core.NO_OP;
if (supported) {
ws = new WebSocket(url, protocols);
ws.addEventListener("message", x => {
messageEvent.value = x;
data.value = x.data;
// if the messages are to quick, we need to warn
/* istanbul ignore else */
{
if (Date.now() - lastMessage < 2) {
console.warn('[useWebSocket] message rate is too high, if you are using "data" or "messageEvent"' +
" you might not get updated of all the messages." +
' Use "ws..addEventListener("message", handler)" instead');
}
lastMessage = Date.now();
}
lastMessage = Date.now();
}
});
ws.addEventListener("error", error => {
errorEvent.value = error;
errored.value = true;
});
ws.addEventListener("close", () => {
isOpen.value = false;
isClosed.value = true;
});
ws.addEventListener("open", () => {
isOpen.value = true;
isClosed.value = false;
});
const send = (data) => ws.send(data);
const close = (code, reason) => {
ws.close(code, reason);
};
});
ws.addEventListener("error", error => {
errorEvent.value = error;
errored.value = true;
});
ws.addEventListener("close", () => {
isOpen.value = false;
isClosed.value = true;
});
ws.addEventListener("open", () => {
isOpen.value = true;
isClosed.value = false;
});
send = (data) => ws.send(data);
close = (code, reason) => {
ws.close(code, reason);
};
}
return {
supported,
ws,

@@ -172,2 +176,3 @@ send,

function useIntersectionObserver(refEl, refOptions) {
const supported = core.isClient && 'IntersectionObserver' in window;
const wrappedElement = refEl ? core.wrap(refEl) : undefined;

@@ -188,25 +193,27 @@ const element = wrappedElement && (core.isElement(wrappedElement.value) || !wrappedElement.value)

let observer = compositionApi.ref();
compositionApi.watch(options, options => {
if (observer.value) {
observer.value.disconnect();
}
const opts = (options &&
options && {
root: core.unwrap(options.root),
rootMargin: core.unwrap(options.rootMargin),
threshold: core.unwrap(options.threshold)
}) ||
undefined;
observer.value = new IntersectionObserver(handling, opts);
const targets = elements.value.map(x => x.target);
targets.forEach(observer.value.observe);
}, { deep: true });
const observe = (element) => {
if (supported) {
compositionApi.watch(options, options => {
if (observer.value) {
observer.value.disconnect();
}
const opts = (options &&
options && {
root: core.unwrap(options.root),
rootMargin: core.unwrap(options.rootMargin),
threshold: core.unwrap(options.threshold)
}) ||
undefined;
observer.value = new IntersectionObserver(handling, opts);
const targets = elements.value.map(x => x.target);
targets.forEach(observer.value.observe);
}, { deep: true });
}
const observe = supported ? (element) => {
const e = core.unwrap(element);
observer.value.observe(e);
};
const unobserve = (element) => {
} : core.NO_OP;
const unobserve = supported ? (element) => {
const e = core.unwrap(element);
observer.value.unobserve(e);
};
} : core.NO_OP;
const disconnect = () => observer.value.disconnect();

@@ -238,2 +245,3 @@ // if the element is passed we should add hooks

return {
supported,
elements,

@@ -248,6 +256,7 @@ observe,

function useNetworkInformation() {
const connection = navigator.connection ||
navigator.mozConnection ||
navigator.webkitConnection;
const supported = compositionApi.computed(() => !!connection);
const connection = core.isClient ?
navigator.connection ||
navigator.mozConnection ||
navigator.webkitConnection : false;
const supported = !!connection;
const downlink = compositionApi.ref(0);

@@ -294,3 +303,3 @@ const downlinkMax = compositionApi.ref(0);

function useOnline() {
const supported = "onLine" in navigator;
const supported = core.isClient && "onLine" in navigator;
// not sure how to test this :/

@@ -319,12 +328,17 @@ if (!supported) {

if (!hidden) {
hidden = compositionApi.ref(document.hidden);
hidden = compositionApi.ref(core.isClient && document.hidden);
}
if (!visibility) {
visibility = compositionApi.ref(document.visibilityState);
document.addEventListener("visibilitychange", () => {
visibility.value = document.visibilityState;
hidden.value = document.hidden;
}, { passive: true }
// true
);
if (core.isClient) {
visibility = compositionApi.ref(document.visibilityState);
document.addEventListener("visibilitychange", () => {
visibility.value = document.visibilityState;
hidden.value = document.hidden;
}, { passive: true }
// true
);
}
else {
visibility = compositionApi.ref(false);
}
}

@@ -341,11 +355,16 @@ return {

if (!language) {
language = compositionApi.ref(navigator.language);
language = core.isClient ? compositionApi.ref(navigator.language) : compositionApi.ref('');
}
if (!languages) {
languages = compositionApi.ref(navigator.languages);
const change = () => {
language.value = navigator.language;
languages.value = navigator.languages;
};
window.addEventListener('languagechange', change, { passive: true });
if (core.isClient) {
languages = compositionApi.ref(navigator.languages);
const change = () => {
language.value = navigator.language;
languages.value = navigator.languages;
};
window.addEventListener('languagechange', change, { passive: true });
}
else {
languages = compositionApi.ref([]);
}
}

@@ -358,15 +377,140 @@ return {

function useMatchMedia(query) {
const mediaQueryList = compositionApi.ref(matchMedia(query));
const matches = compositionApi.ref(mediaQueryList.value.matches);
const process = (e) => {
matches.value = e.matches;
function useBroadcastChannel(name, onBeforeClose) {
const supported = core.isClient && 'BroadcastChannel' in self;
const data = compositionApi.ref(null);
const messageEvent = compositionApi.ref(null);
const errorEvent = compositionApi.ref(null);
const errored = compositionApi.ref(false);
const isClosed = compositionApi.ref(false);
let send = core.NO_OP;
let close = core.NO_OP;
let addListener = core.NO_OP;
/* istanbul ignore else */
if (supported) {
const bc = new BroadcastChannel(name);
bc.addEventListener('messageerror', (e) => {
errorEvent.value = e;
errored.value = true;
}, core.PASSIVE_EV);
bc.addEventListener('message', (ev) => {
messageEvent.value = ev;
data.value = ev.data;
}, core.PASSIVE_EV);
send = (d) => bc.postMessage(d);
close = () => {
bc.close();
isClosed.value = true;
};
addListener = (cb, o) => {
bc.addEventListener('message', cb, o);
compositionApi.onUnmounted(() => bc.removeEventListener('message', cb));
};
compositionApi.onUnmounted(() => {
onBeforeClose && onBeforeClose();
close();
});
}
else {
{
console.warn('[BroadcastChannel] is not supported');
}
}
return {
supported,
data,
messageEvent,
errorEvent,
errored,
isClosed,
send,
close,
addListener,
};
mediaQueryList.value.addEventListener("change", process, { passive: true });
const remove = () => mediaQueryList.value.removeEventListener("change", process);
compositionApi.onUnmounted(remove);
}
function useGeolocation(options) {
const supported = core.isClient && !!navigator.geolocation;
// used to check if the execution is lazy
const lazy = compositionApi.ref(options ? options.immediate === false : undefined);
const error = compositionApi.ref(null);
const timestamp = compositionApi.ref(null);
const coords = compositionApi.ref(null);
const highAccuracy = compositionApi.ref(options && options.enableHighAccuracy || null);
// allow manual control on when the geolocation is requested
let refresh = core.NO_OP;
if (supported) {
const setPosition = (pos) => {
timestamp.value = pos.timestamp;
coords.value = pos.coords;
error.value = null;
};
const setError = (err) => {
timestamp.value = Date.now();
coords.value = null;
error.value = err;
};
const clearWatch = () => lazy.value !== true && watchId && navigator.geolocation.clearWatch(watchId);
let _currentPositionRefresh = () => navigator.geolocation.getCurrentPosition(setPosition, setError, options);
if (lazy.value) {
refresh = () => {
if (lazy.value) {
lazy.value = false;
}
else {
_currentPositionRefresh();
}
};
}
else {
// NOTE probably useless??
refresh = _currentPositionRefresh;
}
let watchId = 0;
compositionApi.onMounted(() => compositionApi.watch([highAccuracy, lazy], (a) => {
clearWatch();
const enableHighAccuracy = core.isBoolean(a[0]) ? a[0] : options ? options.enableHighAccuracy : undefined;
watchId = navigator.geolocation.watchPosition(setPosition, setError, options ? { ...options, enableHighAccuracy } : { enableHighAccuracy });
}, {
lazy: lazy.value
}));
compositionApi.onUnmounted(clearWatch);
}
return {
supported,
refresh,
error,
timestamp,
coords,
highAccuracy
};
}
function useMatchMedia(query) {
const supported = core.isClient ? 'matchMedia' in window : false;
let mediaQueryList = undefined;
let matches = undefined;
let remove = core.NO_OP;
if (supported) {
mediaQueryList = compositionApi.ref(matchMedia(query));
matches = compositionApi.ref(mediaQueryList.value.matches);
const process = (e) => {
matches.value = e.matches;
};
mediaQueryList.value.addEventListener("change", process, { passive: true });
const remove = () => mediaQueryList.value.removeEventListener("change", process);
compositionApi.onUnmounted(remove);
}
else {
/* istanbul ignore else */
{
console.warn('[matchMedia] not supported');
}
mediaQueryList = compositionApi.ref({});
matches = compositionApi.ref(false);
}
return {
supported,
mediaQueryList,
remove,
matches
matches,
remove
};

@@ -399,3 +543,3 @@ }

sorted = sorted.sort((a, b) => b - a);
const resize = () => {
const resize = core.isClient ? () => {
const width = window.innerWidth;

@@ -412,5 +556,5 @@ let c = undefined;

current.value = c;
};
} : core.NO_OP;
const processResize = core.useDebounce(resize, 10);
const remove = () => window.removeEventListener("resize", processResize);
const remove = core.isClient ? () => window.removeEventListener("resize", processResize) : core.NO_OP;
compositionApi.onMounted(() => {

@@ -433,2 +577,168 @@ resize();

function useSharedRef(name, defaultValue) {
const { addListener, send, close, supported } = useBroadcastChannel(name, () => disconnect());
const id = Date.now();
const master = compositionApi.ref(false);
const mind = compositionApi.ref(0 /* HIVE */);
const editable = compositionApi.computed(() => mind.value === 1 /* MASTER */ ? master.value : true);
// who's listening to this broadcast
const targets = compositionApi.ref([]);
const data = compositionApi.ref(defaultValue);
// if the state was updated by an event it sets to true
let updateState = false;
let masterId = undefined;
send({ type: 0 /* INIT */ });
const ping = () => send({ type: 5 /* PING */, id });
const disconnect = () => {
if (targets.value.length === 0)
return;
if (master.value) {
send({
type: 3 /* SET_MIND */,
mind: 1 /* MASTER */,
id: Math.min(...targets.value)
});
}
send({
type: 4 /* LEAVE */,
id
});
};
const setMind = (t) => {
switch (t) {
case 1 /* MASTER */: {
master.value = true;
break;
}
case 0 /* HIVE */: {
master.value = false;
break;
}
}
mind.value = t;
send({
type: 3 /* SET_MIND */,
id: id,
mind: mind.value,
});
};
addListener((e) => {
switch (e.data.type) {
case 0 /* INIT */: {
send({
type: 2 /* UPDATE */,
value: data.value,
mind: mind.value
});
break;
}
case 4 /* LEAVE */: {
const index = targets.value.indexOf(e.data.id);
if (index >= 0) {
targets.value.splice(index, 1);
}
// if master disconnects
if (masterId === e.data.id && targets.value.length > 0) {
send({
type: 3 /* SET_MIND */,
mind: 1 /* MASTER */,
id: Math.min(id, ...targets.value)
});
}
break;
}
case 2 /* UPDATE */: {
updateState = true;
data.value = e.data.value;
mind.value = e.data.mind;
break;
}
case 3 /* SET_MIND */: {
mind.value = e.data.mind;
masterId = e.data.mind === 1 /* MASTER */ && e.data.id || undefined;
master.value = masterId === id;
if (master.value) {
targets.value = [];
ping();
}
break;
}
case 5 /* PING */: {
targets.value = [e.data.id];
send({
type: 6 /* PONG */,
id
});
break;
}
case 6 /* PONG */: {
targets.value.push(e.data.id);
break;
}
}
}, core.PASSIVE_EV);
ping();
compositionApi.watch(data, (v, o) => {
if (updateState) {
updateState = false;
return;
}
// mind is set to MASTER and we are not master, we shouldn't update!
if (mind.value === 1 /* MASTER */ && master.value === false) {
updateState = true;
data.value = o;
return;
}
send({
type: 2 /* UPDATE */,
mind: mind.value,
value: core.isObject(v) ? { ...v } : v
});
updateState = false;
}, { deep: true, lazy: true });
if (core.isClient) {
window.addEventListener('unload', disconnect, core.PASSIVE_EV);
}
compositionApi.onUnmounted(() => {
disconnect();
close();
});
return {
supported,
id,
data,
master,
mind,
editable,
targets,
ping,
setMind,
addListener
};
}
let shared = undefined;
function refShared(defaultValue, id) {
const vm = compositionApi.getCurrentInstance();
const name = id ? id : vm.$vnode.tag;
/* istanbul ignore else */
{
if (!shared) {
shared = new Set();
}
if (shared.has(name)) {
console.warn('[refShared] You can only have one refShared per component, if you need more please assign pass an id refShared(defaultValue, id)');
}
shared.add(name);
}
const { data, supported } = useSharedRef(name, defaultValue);
/* istanbul ignore next */
{
if (!supported) {
console.warn('[refShared] is dependent of BroadcastChannel');
}
}
return data;
}
const STORAGE_TEST_KEY = '__storage_test__' ;
/* istanbul ignore next */

@@ -447,3 +757,3 @@ function isQuotaExceededError(e, storage) {

// acknowledge QuotaExceededError only if there's something already stored
(storage && storage.length !== 0);
(storage && storage.length !== 0 || false);
}

@@ -453,3 +763,6 @@ // based on https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API

try {
const x = '__storage_test__';
if (!storage) {
return false;
}
const x = STORAGE_TEST_KEY;
storage.setItem(x, x);

@@ -473,3 +786,3 @@ storage.removeItem(x);

function useWebStorage(type, serializer = JSON, ms = 10) {
const storage = window[type];
const storage = core.isClient ? window[type] : undefined;
const supported = storageAvailable(storage);

@@ -479,31 +792,33 @@ const remove = () => storageMap.delete(type);

storageMap = new Map();
window.addEventListener('storage', (e) => {
if (e.newValue === e.oldValue) {
return;
}
let webStore = storageMap.get('localStorage');
if (e.storageArea === window.localStorage) {
webStore = storageMap.get('localStorage');
}
else {
webStore = storageMap.get('sessionStorage');
}
if (webStore && Object.keys(webStore.$syncKeys).length > 0) {
if (e.key === null) {
webStore.clear();
if (core.isClient) {
window.addEventListener('storage', (e) => {
if (e.newValue === e.oldValue) {
return;
}
else if (webStore.$syncKeys[e.key]) {
if (e.newValue === null) {
webStore.removeItem(e.key);
let webStore = storageMap.get('localStorage');
if (e.storageArea === window.localStorage) {
webStore = storageMap.get('localStorage');
}
else {
webStore = storageMap.get('sessionStorage');
}
if (webStore && Object.keys(webStore.$syncKeys).length > 0) {
if (e.key === null) {
webStore.clear();
}
else {
webStore.updateItem(e.key, e.newValue);
else if (webStore.$syncKeys[e.key]) {
if (e.newValue === null) {
webStore.removeItem(e.key);
}
else {
webStore.updateItem(e.key, e.newValue);
}
}
}
}
});
});
}
}
let store = storageMap.get(type);
let quotaError;
if (supported) {
if (supported && storage) {
if (!store) {

@@ -622,2 +937,3 @@ quotaError = compositionApi.ref(false);

}
storage = compositionApi.ref(defaultValue);
}

@@ -656,2 +972,3 @@ return {

}
storage = compositionApi.ref(defaultValue);
}

@@ -677,6 +994,9 @@ return {

exports.refShared = refShared;
exports.storageAvailable = storageAvailable;
exports.useBreakpoint = useBreakpoint;
exports.useBroadcastChannel = useBroadcastChannel;
exports.useEvent = useEvent;
exports.useFetch = useFetch;
exports.useGeolocation = useGeolocation;
exports.useIntersectionObserver = useIntersectionObserver;

@@ -693,4 +1013,5 @@ exports.useLanguage = useLanguage;

exports.useSessionStorage = useSessionStorage;
exports.useSharedRef = useSharedRef;
exports.useStorage = useStorage;
exports.useWebSocket = useWebSocket;
exports.useWebStorage = useWebStorage;

@@ -23,4 +23,3 @@ 'use strict';

};
const eventOptions = typeof options === "number" ? undefined : options;
const ms = typeof options === "number" ? options : wait;
const [eventOptions, ms] = core.isNumber(options) ? [undefined, options] : [options, wait];
if (ms) {

@@ -45,4 +44,3 @@ handler = core.useDebounce(handler, wait);

};
const eventOptions = typeof options === "number" ? undefined : options;
const ms = typeof options === "number" ? options : wait;
const [eventOptions, ms] = core.isNumber(options) ? [undefined, options] : [options, wait];
if (ms) {

@@ -52,3 +50,3 @@ handler = core.useDebounce(handler, wait);

// resize seems only to be fired against the window
const remove = useEvent(window, "resize", handler, eventOptions || { passive: true });
const remove = core.isClient ? useEvent(window, "resize", handler, eventOptions || { passive: true }) : core.NO_OP;
return {

@@ -69,4 +67,3 @@ height,

};
const eventOptions = typeof options === "number" ? undefined : options;
const ms = typeof options === "number" ? options : wait;
const [eventOptions, ms] = core.isNumber(options) ? [undefined, options] : [options, wait];
if (ms) {

@@ -117,3 +114,4 @@ handler = core.useDebounce(handler, wait);

function useWebSocket(url, protocols) {
const ws = new WebSocket(url, protocols);
const supported = core.isClient && 'WebSocket' in window;
let ws = null;
const messageEvent = compositionApi.ref(null);

@@ -125,23 +123,29 @@ const errorEvent = compositionApi.ref();

const errored = compositionApi.ref(false);
ws.addEventListener("message", x => {
messageEvent.value = x;
data.value = x.data;
});
ws.addEventListener("error", error => {
errorEvent.value = error;
errored.value = true;
});
ws.addEventListener("close", () => {
isOpen.value = false;
isClosed.value = true;
});
ws.addEventListener("open", () => {
isOpen.value = true;
isClosed.value = false;
});
const send = (data) => ws.send(data);
const close = (code, reason) => {
ws.close(code, reason);
};
let send = core.NO_OP;
let close = core.NO_OP;
if (supported) {
ws = new WebSocket(url, protocols);
ws.addEventListener("message", x => {
messageEvent.value = x;
data.value = x.data;
});
ws.addEventListener("error", error => {
errorEvent.value = error;
errored.value = true;
});
ws.addEventListener("close", () => {
isOpen.value = false;
isClosed.value = true;
});
ws.addEventListener("open", () => {
isOpen.value = true;
isClosed.value = false;
});
send = (data) => ws.send(data);
close = (code, reason) => {
ws.close(code, reason);
};
}
return {
supported,
ws,

@@ -160,2 +164,3 @@ send,

function useIntersectionObserver(refEl, refOptions) {
const supported = core.isClient && 'IntersectionObserver' in window;
const wrappedElement = refEl ? core.wrap(refEl) : undefined;

@@ -176,25 +181,27 @@ const element = wrappedElement && (core.isElement(wrappedElement.value) || !wrappedElement.value)

let observer = compositionApi.ref();
compositionApi.watch(options, options => {
if (observer.value) {
observer.value.disconnect();
}
const opts = (options &&
options && {
root: core.unwrap(options.root),
rootMargin: core.unwrap(options.rootMargin),
threshold: core.unwrap(options.threshold)
}) ||
undefined;
observer.value = new IntersectionObserver(handling, opts);
const targets = elements.value.map(x => x.target);
targets.forEach(observer.value.observe);
}, { deep: true });
const observe = (element) => {
if (supported) {
compositionApi.watch(options, options => {
if (observer.value) {
observer.value.disconnect();
}
const opts = (options &&
options && {
root: core.unwrap(options.root),
rootMargin: core.unwrap(options.rootMargin),
threshold: core.unwrap(options.threshold)
}) ||
undefined;
observer.value = new IntersectionObserver(handling, opts);
const targets = elements.value.map(x => x.target);
targets.forEach(observer.value.observe);
}, { deep: true });
}
const observe = supported ? (element) => {
const e = core.unwrap(element);
observer.value.observe(e);
};
const unobserve = (element) => {
} : core.NO_OP;
const unobserve = supported ? (element) => {
const e = core.unwrap(element);
observer.value.unobserve(e);
};
} : core.NO_OP;
const disconnect = () => observer.value.disconnect();

@@ -226,2 +233,3 @@ // if the element is passed we should add hooks

return {
supported,
elements,

@@ -236,6 +244,7 @@ observe,

function useNetworkInformation() {
const connection = navigator.connection ||
navigator.mozConnection ||
navigator.webkitConnection;
const supported = compositionApi.computed(() => !!connection);
const connection = core.isClient ?
navigator.connection ||
navigator.mozConnection ||
navigator.webkitConnection : false;
const supported = !!connection;
const downlink = compositionApi.ref(0);

@@ -276,3 +285,3 @@ const downlinkMax = compositionApi.ref(0);

function useOnline() {
const supported = "onLine" in navigator;
const supported = core.isClient && "onLine" in navigator;
// not sure how to test this :/

@@ -301,12 +310,17 @@ if (!supported) {

if (!hidden) {
hidden = compositionApi.ref(document.hidden);
hidden = compositionApi.ref(core.isClient && document.hidden);
}
if (!visibility) {
visibility = compositionApi.ref(document.visibilityState);
document.addEventListener("visibilitychange", () => {
visibility.value = document.visibilityState;
hidden.value = document.hidden;
}, { passive: true }
// true
);
if (core.isClient) {
visibility = compositionApi.ref(document.visibilityState);
document.addEventListener("visibilitychange", () => {
visibility.value = document.visibilityState;
hidden.value = document.hidden;
}, { passive: true }
// true
);
}
else {
visibility = compositionApi.ref(false);
}
}

@@ -323,11 +337,16 @@ return {

if (!language) {
language = compositionApi.ref(navigator.language);
language = core.isClient ? compositionApi.ref(navigator.language) : compositionApi.ref('');
}
if (!languages) {
languages = compositionApi.ref(navigator.languages);
const change = () => {
language.value = navigator.language;
languages.value = navigator.languages;
};
window.addEventListener('languagechange', change, { passive: true });
if (core.isClient) {
languages = compositionApi.ref(navigator.languages);
const change = () => {
language.value = navigator.language;
languages.value = navigator.languages;
};
window.addEventListener('languagechange', change, { passive: true });
}
else {
languages = compositionApi.ref([]);
}
}

@@ -340,15 +359,131 @@ return {

function useMatchMedia(query) {
const mediaQueryList = compositionApi.ref(matchMedia(query));
const matches = compositionApi.ref(mediaQueryList.value.matches);
const process = (e) => {
matches.value = e.matches;
function useBroadcastChannel(name, onBeforeClose) {
const supported = core.isClient && 'BroadcastChannel' in self;
const data = compositionApi.ref(null);
const messageEvent = compositionApi.ref(null);
const errorEvent = compositionApi.ref(null);
const errored = compositionApi.ref(false);
const isClosed = compositionApi.ref(false);
let send = core.NO_OP;
let close = core.NO_OP;
let addListener = core.NO_OP;
/* istanbul ignore else */
if (supported) {
const bc = new BroadcastChannel(name);
bc.addEventListener('messageerror', (e) => {
errorEvent.value = e;
errored.value = true;
}, core.PASSIVE_EV);
bc.addEventListener('message', (ev) => {
messageEvent.value = ev;
data.value = ev.data;
}, core.PASSIVE_EV);
send = (d) => bc.postMessage(d);
close = () => {
bc.close();
isClosed.value = true;
};
addListener = (cb, o) => {
bc.addEventListener('message', cb, o);
compositionApi.onUnmounted(() => bc.removeEventListener('message', cb));
};
compositionApi.onUnmounted(() => {
onBeforeClose && onBeforeClose();
close();
});
}
return {
supported,
data,
messageEvent,
errorEvent,
errored,
isClosed,
send,
close,
addListener,
};
mediaQueryList.value.addEventListener("change", process, { passive: true });
const remove = () => mediaQueryList.value.removeEventListener("change", process);
compositionApi.onUnmounted(remove);
}
function useGeolocation(options) {
const supported = core.isClient && !!navigator.geolocation;
// used to check if the execution is lazy
const lazy = compositionApi.ref(options ? options.immediate === false : undefined);
const error = compositionApi.ref(null);
const timestamp = compositionApi.ref(null);
const coords = compositionApi.ref(null);
const highAccuracy = compositionApi.ref(options && options.enableHighAccuracy || null);
// allow manual control on when the geolocation is requested
let refresh = core.NO_OP;
if (supported) {
const setPosition = (pos) => {
timestamp.value = pos.timestamp;
coords.value = pos.coords;
error.value = null;
};
const setError = (err) => {
timestamp.value = Date.now();
coords.value = null;
error.value = err;
};
const clearWatch = () => lazy.value !== true && watchId && navigator.geolocation.clearWatch(watchId);
let _currentPositionRefresh = () => navigator.geolocation.getCurrentPosition(setPosition, setError, options);
if (lazy.value) {
refresh = () => {
if (lazy.value) {
lazy.value = false;
}
else {
_currentPositionRefresh();
}
};
}
else {
// NOTE probably useless??
refresh = _currentPositionRefresh;
}
let watchId = 0;
compositionApi.onMounted(() => compositionApi.watch([highAccuracy, lazy], (a) => {
clearWatch();
const enableHighAccuracy = core.isBoolean(a[0]) ? a[0] : options ? options.enableHighAccuracy : undefined;
watchId = navigator.geolocation.watchPosition(setPosition, setError, options ? { ...options, enableHighAccuracy } : { enableHighAccuracy });
}, {
lazy: lazy.value
}));
compositionApi.onUnmounted(clearWatch);
}
return {
supported,
refresh,
error,
timestamp,
coords,
highAccuracy
};
}
function useMatchMedia(query) {
const supported = core.isClient ? 'matchMedia' in window : false;
let mediaQueryList = undefined;
let matches = undefined;
let remove = core.NO_OP;
if (supported) {
mediaQueryList = compositionApi.ref(matchMedia(query));
matches = compositionApi.ref(mediaQueryList.value.matches);
const process = (e) => {
matches.value = e.matches;
};
mediaQueryList.value.addEventListener("change", process, { passive: true });
const remove = () => mediaQueryList.value.removeEventListener("change", process);
compositionApi.onUnmounted(remove);
}
else {
mediaQueryList = compositionApi.ref({});
matches = compositionApi.ref(false);
}
return {
supported,
mediaQueryList,
remove,
matches
matches,
remove
};

@@ -381,3 +516,3 @@ }

sorted = sorted.sort((a, b) => b - a);
const resize = () => {
const resize = core.isClient ? () => {
const width = window.innerWidth;

@@ -394,5 +529,5 @@ let c = undefined;

current.value = c;
};
} : core.NO_OP;
const processResize = core.useDebounce(resize, 10);
const remove = () => window.removeEventListener("resize", processResize);
const remove = core.isClient ? () => window.removeEventListener("resize", processResize) : core.NO_OP;
compositionApi.onMounted(() => {

@@ -415,2 +550,151 @@ resize();

function useSharedRef(name, defaultValue) {
const { addListener, send, close, supported } = useBroadcastChannel(name, () => disconnect());
const id = Date.now();
const master = compositionApi.ref(false);
const mind = compositionApi.ref(0 /* HIVE */);
const editable = compositionApi.computed(() => mind.value === 1 /* MASTER */ ? master.value : true);
// who's listening to this broadcast
const targets = compositionApi.ref([]);
const data = compositionApi.ref(defaultValue);
// if the state was updated by an event it sets to true
let updateState = false;
let masterId = undefined;
send({ type: 0 /* INIT */ });
const ping = () => send({ type: 5 /* PING */, id });
const disconnect = () => {
if (targets.value.length === 0)
return;
if (master.value) {
send({
type: 3 /* SET_MIND */,
mind: 1 /* MASTER */,
id: Math.min(...targets.value)
});
}
send({
type: 4 /* LEAVE */,
id
});
};
const setMind = (t) => {
switch (t) {
case 1 /* MASTER */: {
master.value = true;
break;
}
case 0 /* HIVE */: {
master.value = false;
break;
}
}
mind.value = t;
send({
type: 3 /* SET_MIND */,
id: id,
mind: mind.value,
});
};
addListener((e) => {
switch (e.data.type) {
case 0 /* INIT */: {
send({
type: 2 /* UPDATE */,
value: data.value,
mind: mind.value
});
break;
}
case 4 /* LEAVE */: {
const index = targets.value.indexOf(e.data.id);
if (index >= 0) {
targets.value.splice(index, 1);
}
// if master disconnects
if (masterId === e.data.id && targets.value.length > 0) {
send({
type: 3 /* SET_MIND */,
mind: 1 /* MASTER */,
id: Math.min(id, ...targets.value)
});
}
break;
}
case 2 /* UPDATE */: {
updateState = true;
data.value = e.data.value;
mind.value = e.data.mind;
break;
}
case 3 /* SET_MIND */: {
mind.value = e.data.mind;
masterId = e.data.mind === 1 /* MASTER */ && e.data.id || undefined;
master.value = masterId === id;
if (master.value) {
targets.value = [];
ping();
}
break;
}
case 5 /* PING */: {
targets.value = [e.data.id];
send({
type: 6 /* PONG */,
id
});
break;
}
case 6 /* PONG */: {
targets.value.push(e.data.id);
break;
}
}
}, core.PASSIVE_EV);
ping();
compositionApi.watch(data, (v, o) => {
if (updateState) {
updateState = false;
return;
}
// mind is set to MASTER and we are not master, we shouldn't update!
if (mind.value === 1 /* MASTER */ && master.value === false) {
updateState = true;
data.value = o;
return;
}
send({
type: 2 /* UPDATE */,
mind: mind.value,
value: core.isObject(v) ? { ...v } : v
});
updateState = false;
}, { deep: true, lazy: true });
if (core.isClient) {
window.addEventListener('unload', disconnect, core.PASSIVE_EV);
}
compositionApi.onUnmounted(() => {
disconnect();
close();
});
return {
supported,
id,
data,
master,
mind,
editable,
targets,
ping,
setMind,
addListener
};
}
function refShared(defaultValue, id) {
const vm = compositionApi.getCurrentInstance();
const name = id ? id : vm.$vnode.tag;
const { data, supported } = useSharedRef(name, defaultValue);
return data;
}
const STORAGE_TEST_KEY = ":$";
/* istanbul ignore next */

@@ -429,3 +713,3 @@ function isQuotaExceededError(e, storage) {

// acknowledge QuotaExceededError only if there's something already stored
(storage && storage.length !== 0);
(storage && storage.length !== 0 || false);
}

@@ -435,3 +719,6 @@ // based on https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API

try {
const x = '__storage_test__';
if (!storage) {
return false;
}
const x = STORAGE_TEST_KEY;
storage.setItem(x, x);

@@ -455,3 +742,3 @@ storage.removeItem(x);

function useWebStorage(type, serializer = JSON, ms = 10) {
const storage = window[type];
const storage = core.isClient ? window[type] : undefined;
const supported = storageAvailable(storage);

@@ -461,31 +748,33 @@ const remove = () => storageMap.delete(type);

storageMap = new Map();
window.addEventListener('storage', (e) => {
if (e.newValue === e.oldValue) {
return;
}
let webStore = storageMap.get('localStorage');
if (e.storageArea === window.localStorage) {
webStore = storageMap.get('localStorage');
}
else {
webStore = storageMap.get('sessionStorage');
}
if (webStore && Object.keys(webStore.$syncKeys).length > 0) {
if (e.key === null) {
webStore.clear();
if (core.isClient) {
window.addEventListener('storage', (e) => {
if (e.newValue === e.oldValue) {
return;
}
else if (webStore.$syncKeys[e.key]) {
if (e.newValue === null) {
webStore.removeItem(e.key);
let webStore = storageMap.get('localStorage');
if (e.storageArea === window.localStorage) {
webStore = storageMap.get('localStorage');
}
else {
webStore = storageMap.get('sessionStorage');
}
if (webStore && Object.keys(webStore.$syncKeys).length > 0) {
if (e.key === null) {
webStore.clear();
}
else {
webStore.updateItem(e.key, e.newValue);
else if (webStore.$syncKeys[e.key]) {
if (e.newValue === null) {
webStore.removeItem(e.key);
}
else {
webStore.updateItem(e.key, e.newValue);
}
}
}
}
});
});
}
}
let store = storageMap.get(type);
let quotaError;
if (supported) {
if (supported && storage) {
if (!store) {

@@ -599,2 +888,5 @@ quotaError = compositionApi.ref(false);

}
else {
storage = compositionApi.ref(defaultValue);
}
return {

@@ -623,2 +915,5 @@ supported,

}
else {
storage = compositionApi.ref(defaultValue);
}
return {

@@ -643,6 +938,9 @@ supported,

exports.refShared = refShared;
exports.storageAvailable = storageAvailable;
exports.useBreakpoint = useBreakpoint;
exports.useBroadcastChannel = useBroadcastChannel;
exports.useEvent = useEvent;
exports.useFetch = useFetch;
exports.useGeolocation = useGeolocation;
exports.useIntersectionObserver = useIntersectionObserver;

@@ -659,4 +957,5 @@ exports.useLanguage = useLanguage;

exports.useSessionStorage = useSessionStorage;
exports.useSharedRef = useSharedRef;
exports.useStorage = useStorage;
exports.useWebSocket = useWebSocket;
exports.useWebStorage = useWebStorage;

@@ -5,2 +5,14 @@ import { Ref } from '@vue/composition-api';

export declare interface BroadcastMessageEvent<T> extends MessageEvent {
readonly data: T;
}
export declare interface GeolocationOptions {
/**
* @description Executes request location immediately
* @default true
*/
immediate?: boolean;
}
export declare interface IntersectionObserverOptions {

@@ -13,2 +25,3 @@ root?: RefTyped<Element> | null;

export declare interface IntersectionObserverResult {
supported: boolean;
elements: Ref<IntersectionObserverEntry[]>;

@@ -67,3 +80,3 @@ observe: (el: RefTyped<Element>) => void;

declare interface NetworkInformationReturn {
readonly supported: Ref<boolean>;
readonly supported: boolean;
/**

@@ -99,2 +112,53 @@ * @description Returns the effective bandwidth estimate in megabits per second, rounded to the nearest multiple of 25 kilobits per seconds

export declare function refShared<T = any>(defaultValue?: RefTyped<T>, id?: string): Ref<RefTyped<T>>;
export declare type RefSharedMessage<T = any> = RefSharedMessageInit | RefSharedMessageSync<T> | RefSharedMessageLeave | RefSharedMessageUpdate<T> | RefSharedMessageSetMind | RefSharedMessagePing | RefSharedMessagePong;
export declare type RefSharedMessageInit = {
type: RefSharedMessageType.INIT;
};
export declare type RefSharedMessageLeave = {
type: RefSharedMessageType.LEAVE;
id: number;
};
export declare type RefSharedMessagePing = {
type: RefSharedMessageType.PING;
id: number;
};
export declare type RefSharedMessagePong = {
type: RefSharedMessageType.PONG;
id: number;
};
export declare type RefSharedMessageSetMind = {
type: RefSharedMessageType.SET_MIND;
mind: SharedRefMind;
id: number;
};
export declare type RefSharedMessageSync<T> = {
type: RefSharedMessageType.SYNC;
value: T;
mind: SharedRefMind;
};
export declare const enum RefSharedMessageType {
INIT = 0,
SYNC = 1,
UPDATE = 2,
SET_MIND = 3,
LEAVE = 4,
PING = 5,
PONG = 6
}
export declare type RefSharedMessageUpdate<T> = {
type: RefSharedMessageType.UPDATE;
value: T;
mind: SharedRefMind;
};
export declare type RemoveEventFunction = () => void;

@@ -114,4 +178,9 @@

export declare function storageAvailable(storage: Storage): boolean;
export declare const enum SharedRefMind {
HIVE = 0,
MASTER = 1
}
export declare function storageAvailable(storage?: Storage): boolean;
export declare interface StorageSerializer<T = any> {

@@ -127,2 +196,14 @@ stringify(item: T): string;

export declare function useBroadcastChannel<T = any>(name: string, onBeforeClose?: Function): {
supported: boolean;
data: import("@vue/composition-api").Ref<T | null>;
messageEvent: import("@vue/composition-api").Ref<MessageEvent | null>;
errorEvent: import("@vue/composition-api").Ref<MessageEvent | null>;
errored: import("@vue/composition-api").Ref<boolean>;
isClosed: import("@vue/composition-api").Ref<boolean>;
send: (data: T) => void;
close: Function;
addListener: (cb: (ev: BroadcastMessageEvent<T>) => void, options?: boolean | AddEventListenerOptions | undefined) => void;
};
export declare function useEvent<T extends {

@@ -167,2 +248,11 @@ addEventListener: (name: string, listener: EventListenerOrEventListenerObject) => any;

export declare function useGeolocation(options?: PositionOptions & GeolocationOptions): {
supported: boolean;
refresh: () => void;
error: import("@vue/composition-api").Ref<PositionError | null>;
timestamp: import("@vue/composition-api").Ref<number | null>;
coords: import("@vue/composition-api").Ref<Coordinates | null>;
highAccuracy: import("@vue/composition-api").Ref<boolean>;
};
export declare function useIntersectionObserver(el: RefElement, options?: RefTyped<IntersectionObserverOptions>): IntersectionObserverResult;

@@ -182,5 +272,6 @@

export declare function useMatchMedia(query: string): {
mediaQueryList: import("@vue/composition-api").Ref<MediaQueryList>;
supported: boolean;
mediaQueryList: Ref<MediaQueryList>;
matches: Ref<boolean>;
remove: () => void;
matches: import("@vue/composition-api").Ref<boolean>;
};

@@ -228,2 +319,15 @@

export declare function useSharedRef<T = any>(name: string, defaultValue?: T): {
supported: boolean;
id: number;
data: Ref<T>;
master: Ref<boolean>;
mind: Ref<SharedRefMind>;
editable: Readonly<Ref<boolean>>;
targets: Ref<number[]>;
ping: () => void;
setMind: (t: SharedRefMind) => void;
addListener: (cb: (ev: import("../web").BroadcastMessageEvent<RefSharedMessage<T>>) => void, options?: boolean | AddEventListenerOptions | undefined) => void;
};
export declare function useStorage(key: string, defaultValue?: RefTyped<string>): LocalStorageReturn<string>;

@@ -234,3 +338,4 @@

export declare function useWebSocket(url: string, protocols?: string | string[]): {
ws: WebSocket;
supported: boolean;
ws: WebSocket | null;
send: (data: string | ArrayBuffer | SharedArrayBuffer | Blob | ArrayBufferView) => void;

@@ -237,0 +342,0 @@ close: (code?: number | undefined, reason?: string | undefined) => void;

@@ -1,3 +0,3 @@

import { onMounted, onUnmounted, ref, computed, watch } from '@vue/composition-api';
import { wrap, useDebounce, usePromise, isElement, unwrap, NO_OP, isNumber, debounce, isString, FALSE_OP } from '@vue-composable/core';
import { onMounted, onUnmounted, ref, computed, watch, getCurrentInstance } from '@vue/composition-api';
import { wrap, isNumber, useDebounce, isClient, NO_OP, usePromise, isElement, unwrap, PASSIVE_EV, isBoolean, isObject, debounce, isString, FALSE_OP } from '@vue-composable/core';

@@ -19,4 +19,3 @@ function useEvent(el, name, listener, options) {

};
const eventOptions = typeof options === "number" ? undefined : options;
const ms = typeof options === "number" ? options : wait;
const [eventOptions, ms] = isNumber(options) ? [undefined, options] : [options, wait];
if (ms) {

@@ -41,4 +40,3 @@ handler = useDebounce(handler, wait);

};
const eventOptions = typeof options === "number" ? undefined : options;
const ms = typeof options === "number" ? options : wait;
const [eventOptions, ms] = isNumber(options) ? [undefined, options] : [options, wait];
if (ms) {

@@ -48,3 +46,3 @@ handler = useDebounce(handler, wait);

// resize seems only to be fired against the window
const remove = useEvent(window, "resize", handler, eventOptions || { passive: true });
const remove = isClient ? useEvent(window, "resize", handler, eventOptions || { passive: true }) : NO_OP;
return {

@@ -65,4 +63,3 @@ height,

};
const eventOptions = typeof options === "number" ? undefined : options;
const ms = typeof options === "number" ? options : wait;
const [eventOptions, ms] = isNumber(options) ? [undefined, options] : [options, wait];
if (ms) {

@@ -113,3 +110,4 @@ handler = useDebounce(handler, wait);

function useWebSocket(url, protocols) {
const ws = new WebSocket(url, protocols);
const supported = isClient && 'WebSocket' in window;
let ws = null;
const messageEvent = ref(null);

@@ -122,34 +120,40 @@ const errorEvent = ref();

/* istanbul ignore next */
let lastMessage = ((true !== 'production') && Date.now()) || undefined;
ws.addEventListener("message", x => {
messageEvent.value = x;
data.value = x.data;
// if the messages are to quick, we need to warn
/* istanbul ignore else */
if ((true !== 'production')) {
if (Date.now() - lastMessage < 2) {
console.warn('[useWebSocket] message rate is too high, if you are using "data" or "messageEvent"' +
" you might not get updated of all the messages." +
' Use "ws..addEventListener("message", handler)" instead');
let lastMessage = ((process.env.NODE_ENV !== 'production') && Date.now()) || undefined;
let send = NO_OP;
let close = NO_OP;
if (supported) {
ws = new WebSocket(url, protocols);
ws.addEventListener("message", x => {
messageEvent.value = x;
data.value = x.data;
// if the messages are to quick, we need to warn
/* istanbul ignore else */
if ((process.env.NODE_ENV !== 'production')) {
if (Date.now() - lastMessage < 2) {
console.warn('[useWebSocket] message rate is too high, if you are using "data" or "messageEvent"' +
" you might not get updated of all the messages." +
' Use "ws..addEventListener("message", handler)" instead');
}
lastMessage = Date.now();
}
lastMessage = Date.now();
}
});
ws.addEventListener("error", error => {
errorEvent.value = error;
errored.value = true;
});
ws.addEventListener("close", () => {
isOpen.value = false;
isClosed.value = true;
});
ws.addEventListener("open", () => {
isOpen.value = true;
isClosed.value = false;
});
const send = (data) => ws.send(data);
const close = (code, reason) => {
ws.close(code, reason);
};
});
ws.addEventListener("error", error => {
errorEvent.value = error;
errored.value = true;
});
ws.addEventListener("close", () => {
isOpen.value = false;
isClosed.value = true;
});
ws.addEventListener("open", () => {
isOpen.value = true;
isClosed.value = false;
});
send = (data) => ws.send(data);
close = (code, reason) => {
ws.close(code, reason);
};
}
return {
supported,
ws,

@@ -168,2 +172,3 @@ send,

function useIntersectionObserver(refEl, refOptions) {
const supported = isClient && 'IntersectionObserver' in window;
const wrappedElement = refEl ? wrap(refEl) : undefined;

@@ -184,25 +189,27 @@ const element = wrappedElement && (isElement(wrappedElement.value) || !wrappedElement.value)

let observer = ref();
watch(options, options => {
if (observer.value) {
observer.value.disconnect();
}
const opts = (options &&
options && {
root: unwrap(options.root),
rootMargin: unwrap(options.rootMargin),
threshold: unwrap(options.threshold)
}) ||
undefined;
observer.value = new IntersectionObserver(handling, opts);
const targets = elements.value.map(x => x.target);
targets.forEach(observer.value.observe);
}, { deep: true });
const observe = (element) => {
if (supported) {
watch(options, options => {
if (observer.value) {
observer.value.disconnect();
}
const opts = (options &&
options && {
root: unwrap(options.root),
rootMargin: unwrap(options.rootMargin),
threshold: unwrap(options.threshold)
}) ||
undefined;
observer.value = new IntersectionObserver(handling, opts);
const targets = elements.value.map(x => x.target);
targets.forEach(observer.value.observe);
}, { deep: true });
}
const observe = supported ? (element) => {
const e = unwrap(element);
observer.value.observe(e);
};
const unobserve = (element) => {
} : NO_OP;
const unobserve = supported ? (element) => {
const e = unwrap(element);
observer.value.unobserve(e);
};
} : NO_OP;
const disconnect = () => observer.value.disconnect();

@@ -228,3 +235,3 @@ // if the element is passed we should add hooks

// if (elements.value.length === 0) {
// (true !== 'production') && console.warn('[IntersectionObserver] no elements provided, did you mount the component?')
// (process.env.NODE_ENV !== 'production') && console.warn('[IntersectionObserver] no elements provided, did you mount the component?')
// return;

@@ -235,2 +242,3 @@ // }

return {
supported,
elements,

@@ -245,6 +253,7 @@ observe,

function useNetworkInformation() {
const connection = navigator.connection ||
navigator.mozConnection ||
navigator.webkitConnection;
const supported = computed(() => !!connection);
const connection = isClient ?
navigator.connection ||
navigator.mozConnection ||
navigator.webkitConnection : false;
const supported = !!connection;
const downlink = ref(0);

@@ -273,3 +282,3 @@ const downlinkMax = ref(0);

/* istanbul ignore else */
if ((true !== 'production')) {
if ((process.env.NODE_ENV !== 'production')) {
console.warn("[navigator.connection] not found, networkInformation not available.");

@@ -292,3 +301,3 @@ }

function useOnline() {
const supported = "onLine" in navigator;
const supported = isClient && "onLine" in navigator;
// not sure how to test this :/

@@ -317,12 +326,17 @@ if (!supported) {

if (!hidden) {
hidden = ref(document.hidden);
hidden = ref(isClient && document.hidden);
}
if (!visibility) {
visibility = ref(document.visibilityState);
document.addEventListener("visibilitychange", () => {
visibility.value = document.visibilityState;
hidden.value = document.hidden;
}, { passive: true }
// true
);
if (isClient) {
visibility = ref(document.visibilityState);
document.addEventListener("visibilitychange", () => {
visibility.value = document.visibilityState;
hidden.value = document.hidden;
}, { passive: true }
// true
);
}
else {
visibility = ref(false);
}
}

@@ -339,11 +353,16 @@ return {

if (!language) {
language = ref(navigator.language);
language = isClient ? ref(navigator.language) : ref('');
}
if (!languages) {
languages = ref(navigator.languages);
const change = () => {
language.value = navigator.language;
languages.value = navigator.languages;
};
window.addEventListener('languagechange', change, { passive: true });
if (isClient) {
languages = ref(navigator.languages);
const change = () => {
language.value = navigator.language;
languages.value = navigator.languages;
};
window.addEventListener('languagechange', change, { passive: true });
}
else {
languages = ref([]);
}
}

@@ -356,15 +375,140 @@ return {

function useMatchMedia(query) {
const mediaQueryList = ref(matchMedia(query));
const matches = ref(mediaQueryList.value.matches);
const process = (e) => {
matches.value = e.matches;
function useBroadcastChannel(name, onBeforeClose) {
const supported = isClient && 'BroadcastChannel' in self;
const data = ref(null);
const messageEvent = ref(null);
const errorEvent = ref(null);
const errored = ref(false);
const isClosed = ref(false);
let send = NO_OP;
let close = NO_OP;
let addListener = NO_OP;
/* istanbul ignore else */
if (supported) {
const bc = new BroadcastChannel(name);
bc.addEventListener('messageerror', (e) => {
errorEvent.value = e;
errored.value = true;
}, PASSIVE_EV);
bc.addEventListener('message', (ev) => {
messageEvent.value = ev;
data.value = ev.data;
}, PASSIVE_EV);
send = (d) => bc.postMessage(d);
close = () => {
bc.close();
isClosed.value = true;
};
addListener = (cb, o) => {
bc.addEventListener('message', cb, o);
onUnmounted(() => bc.removeEventListener('message', cb));
};
onUnmounted(() => {
onBeforeClose && onBeforeClose();
close();
});
}
else {
if ((process.env.NODE_ENV !== 'production')) {
console.warn('[BroadcastChannel] is not supported');
}
}
return {
supported,
data,
messageEvent,
errorEvent,
errored,
isClosed,
send,
close,
addListener,
};
mediaQueryList.value.addEventListener("change", process, { passive: true });
const remove = () => mediaQueryList.value.removeEventListener("change", process);
onUnmounted(remove);
}
function useGeolocation(options) {
const supported = isClient && !!navigator.geolocation;
// used to check if the execution is lazy
const lazy = ref(options ? options.immediate === false : undefined);
const error = ref(null);
const timestamp = ref(null);
const coords = ref(null);
const highAccuracy = ref(options && options.enableHighAccuracy || null);
// allow manual control on when the geolocation is requested
let refresh = NO_OP;
if (supported) {
const setPosition = (pos) => {
timestamp.value = pos.timestamp;
coords.value = pos.coords;
error.value = null;
};
const setError = (err) => {
timestamp.value = Date.now();
coords.value = null;
error.value = err;
};
const clearWatch = () => lazy.value !== true && watchId && navigator.geolocation.clearWatch(watchId);
let _currentPositionRefresh = () => navigator.geolocation.getCurrentPosition(setPosition, setError, options);
if (lazy.value) {
refresh = () => {
if (lazy.value) {
lazy.value = false;
}
else {
_currentPositionRefresh();
}
};
}
else {
// NOTE probably useless??
refresh = _currentPositionRefresh;
}
let watchId = 0;
onMounted(() => watch([highAccuracy, lazy], (a) => {
clearWatch();
const enableHighAccuracy = isBoolean(a[0]) ? a[0] : options ? options.enableHighAccuracy : undefined;
watchId = navigator.geolocation.watchPosition(setPosition, setError, options ? { ...options, enableHighAccuracy } : { enableHighAccuracy });
}, {
lazy: lazy.value
}));
onUnmounted(clearWatch);
}
return {
supported,
refresh,
error,
timestamp,
coords,
highAccuracy
};
}
function useMatchMedia(query) {
const supported = isClient ? 'matchMedia' in window : false;
let mediaQueryList = undefined;
let matches = undefined;
let remove = NO_OP;
if (supported) {
mediaQueryList = ref(matchMedia(query));
matches = ref(mediaQueryList.value.matches);
const process = (e) => {
matches.value = e.matches;
};
mediaQueryList.value.addEventListener("change", process, { passive: true });
const remove = () => mediaQueryList.value.removeEventListener("change", process);
onUnmounted(remove);
}
else {
/* istanbul ignore else */
if ((process.env.NODE_ENV !== 'production')) {
console.warn('[matchMedia] not supported');
}
mediaQueryList = ref({});
matches = ref(false);
}
return {
supported,
mediaQueryList,
remove,
matches
matches,
remove
};

@@ -397,3 +541,3 @@ }

sorted = sorted.sort((a, b) => b - a);
const resize = () => {
const resize = isClient ? () => {
const width = window.innerWidth;

@@ -410,5 +554,5 @@ let c = undefined;

current.value = c;
};
} : NO_OP;
const processResize = useDebounce(resize, 10);
const remove = () => window.removeEventListener("resize", processResize);
const remove = isClient ? () => window.removeEventListener("resize", processResize) : NO_OP;
onMounted(() => {

@@ -431,2 +575,168 @@ resize();

function useSharedRef(name, defaultValue) {
const { addListener, send, close, supported } = useBroadcastChannel(name, () => disconnect());
const id = Date.now();
const master = ref(false);
const mind = ref(0 /* HIVE */);
const editable = computed(() => mind.value === 1 /* MASTER */ ? master.value : true);
// who's listening to this broadcast
const targets = ref([]);
const data = ref(defaultValue);
// if the state was updated by an event it sets to true
let updateState = false;
let masterId = undefined;
send({ type: 0 /* INIT */ });
const ping = () => send({ type: 5 /* PING */, id });
const disconnect = () => {
if (targets.value.length === 0)
return;
if (master.value) {
send({
type: 3 /* SET_MIND */,
mind: 1 /* MASTER */,
id: Math.min(...targets.value)
});
}
send({
type: 4 /* LEAVE */,
id
});
};
const setMind = (t) => {
switch (t) {
case 1 /* MASTER */: {
master.value = true;
break;
}
case 0 /* HIVE */: {
master.value = false;
break;
}
}
mind.value = t;
send({
type: 3 /* SET_MIND */,
id: id,
mind: mind.value,
});
};
addListener((e) => {
switch (e.data.type) {
case 0 /* INIT */: {
send({
type: 2 /* UPDATE */,
value: data.value,
mind: mind.value
});
break;
}
case 4 /* LEAVE */: {
const index = targets.value.indexOf(e.data.id);
if (index >= 0) {
targets.value.splice(index, 1);
}
// if master disconnects
if (masterId === e.data.id && targets.value.length > 0) {
send({
type: 3 /* SET_MIND */,
mind: 1 /* MASTER */,
id: Math.min(id, ...targets.value)
});
}
break;
}
case 2 /* UPDATE */: {
updateState = true;
data.value = e.data.value;
mind.value = e.data.mind;
break;
}
case 3 /* SET_MIND */: {
mind.value = e.data.mind;
masterId = e.data.mind === 1 /* MASTER */ && e.data.id || undefined;
master.value = masterId === id;
if (master.value) {
targets.value = [];
ping();
}
break;
}
case 5 /* PING */: {
targets.value = [e.data.id];
send({
type: 6 /* PONG */,
id
});
break;
}
case 6 /* PONG */: {
targets.value.push(e.data.id);
break;
}
}
}, PASSIVE_EV);
ping();
watch(data, (v, o) => {
if (updateState) {
updateState = false;
return;
}
// mind is set to MASTER and we are not master, we shouldn't update!
if (mind.value === 1 /* MASTER */ && master.value === false) {
updateState = true;
data.value = o;
return;
}
send({
type: 2 /* UPDATE */,
mind: mind.value,
value: isObject(v) ? { ...v } : v
});
updateState = false;
}, { deep: true, lazy: true });
if (isClient) {
window.addEventListener('unload', disconnect, PASSIVE_EV);
}
onUnmounted(() => {
disconnect();
close();
});
return {
supported,
id,
data,
master,
mind,
editable,
targets,
ping,
setMind,
addListener
};
}
let shared = undefined;
function refShared(defaultValue, id) {
const vm = getCurrentInstance();
const name = id ? id : vm.$vnode.tag;
/* istanbul ignore else */
if ((process.env.NODE_ENV !== 'production')) {
if (!shared) {
shared = new Set();
}
if (shared.has(name)) {
console.warn('[refShared] You can only have one refShared per component, if you need more please assign pass an id refShared(defaultValue, id)');
}
shared.add(name);
}
const { data, supported } = useSharedRef(name, defaultValue);
/* istanbul ignore next */
if ((process.env.NODE_ENV !== 'production')) {
if (!supported) {
console.warn('[refShared] is dependent of BroadcastChannel');
}
}
return data;
}
const STORAGE_TEST_KEY = (process.env.NODE_ENV !== 'production') ? '__storage_test__' : ":$";
/* istanbul ignore next */

@@ -445,3 +755,3 @@ function isQuotaExceededError(e, storage) {

// acknowledge QuotaExceededError only if there's something already stored
(storage && storage.length !== 0);
(storage && storage.length !== 0 || false);
}

@@ -451,3 +761,6 @@ // based on https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API

try {
const x = '__storage_test__';
if (!storage) {
return false;
}
const x = STORAGE_TEST_KEY;
storage.setItem(x, x);

@@ -471,3 +784,3 @@ storage.removeItem(x);

function useWebStorage(type, serializer = JSON, ms = 10) {
const storage = window[type];
const storage = isClient ? window[type] : undefined;
const supported = storageAvailable(storage);

@@ -477,31 +790,33 @@ const remove = () => storageMap.delete(type);

storageMap = new Map();
window.addEventListener('storage', (e) => {
if (e.newValue === e.oldValue) {
return;
}
let webStore = storageMap.get('localStorage');
if (e.storageArea === window.localStorage) {
webStore = storageMap.get('localStorage');
}
else {
webStore = storageMap.get('sessionStorage');
}
if (webStore && Object.keys(webStore.$syncKeys).length > 0) {
if (e.key === null) {
webStore.clear();
if (isClient) {
window.addEventListener('storage', (e) => {
if (e.newValue === e.oldValue) {
return;
}
else if (webStore.$syncKeys[e.key]) {
if (e.newValue === null) {
webStore.removeItem(e.key);
let webStore = storageMap.get('localStorage');
if (e.storageArea === window.localStorage) {
webStore = storageMap.get('localStorage');
}
else {
webStore = storageMap.get('sessionStorage');
}
if (webStore && Object.keys(webStore.$syncKeys).length > 0) {
if (e.key === null) {
webStore.clear();
}
else {
webStore.updateItem(e.key, e.newValue);
else if (webStore.$syncKeys[e.key]) {
if (e.newValue === null) {
webStore.removeItem(e.key);
}
else {
webStore.updateItem(e.key, e.newValue);
}
}
}
}
});
});
}
}
let store = storageMap.get(type);
let quotaError;
if (supported) {
if (supported && storage) {
if (!store) {

@@ -617,5 +932,6 @@ quotaError = ref(false);

/* istanbul ignore else */
if ((true !== 'production')) {
if ((process.env.NODE_ENV !== 'production')) {
console.warn('[localStorage] is not available');
}
storage = ref(defaultValue);
}

@@ -639,3 +955,3 @@ return {

/* istanbul ignore else */
if ((true !== 'production')) {
if ((process.env.NODE_ENV !== 'production')) {
setSync = () => console.warn('sync is not supported, please `useLocalStorage` instead');

@@ -652,5 +968,6 @@ }

/* istanbul ignore else */
if ((true !== 'production')) {
if ((process.env.NODE_ENV !== 'production')) {
console.warn('[sessionStorage] is not available');
}
storage = ref(defaultValue);
}

@@ -676,2 +993,2 @@ return {

export { storageAvailable, useBreakpoint, useEvent, useFetch, useIntersectionObserver, useLanguage, useLocalStorage, useMatchMedia, useNetworkInformation, useOnMouseMove, useOnResize, useOnScroll, useOnline, usePageVisibility, useSessionStorage, useStorage, useWebSocket, useWebStorage };
export { refShared, storageAvailable, useBreakpoint, useBroadcastChannel, useEvent, useFetch, useGeolocation, useIntersectionObserver, useLanguage, useLocalStorage, useMatchMedia, useNetworkInformation, useOnMouseMove, useOnResize, useOnScroll, useOnline, usePageVisibility, useSessionStorage, useSharedRef, useStorage, useWebSocket, useWebStorage };
{
"name": "@vue-composable/web",
"version": "1.0.0-dev.7",
"version": "1.0.0-dev.8",
"description": "@vue-composable/web",

@@ -37,7 +37,11 @@ "main": "index.js",

"homepage": "https://github.com/pikax/vue-composable/tree/dev/packages/core#readme",
"peerDependencies": {
"@vue/composition-api": "^0.3.4"
},
"dependencies": {
"@vue-composable/core": "1.0.0-dev.7",
"@vue/composition-api": "^0.3.4",
"@vue-composable/core": "1.0.0-dev.8"
},
"devDependencies": {
"vue": "^2.6.10"
}
}

@@ -36,2 +36,3 @@ # @vue-composable/web

- [breakpoint](https://pikax.me/vue-composable/composable/misc/breakpoint) - reactive `breakpoints` based on `window.innerWidth`
- [sharedRef](https://pikax.me/vue-composable/composable/misc/sharedRef) - cross-tab reactive `ref`

@@ -54,2 +55,4 @@ ### Storage

- [Language](https://pikax.me/vue-composable/composable/web/language) - reactive `NavigatorLanguage`
- [BroadcastChannel](https://pikax.me/vue-composable/composable/web/broadcastChannel) - reactive `BroadcastChannel API`
- [Geolocation API](https://pikax.me/vue-composable/composable/web/geolocation)

@@ -56,0 +59,0 @@ ## Contributing

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc