@lyonph/preact-hooks
Version:
Collection of useful Preact Hooks
652 lines (612 loc) • 18.7 kB
JavaScript
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
// src/useAsyncMemo.ts
import { useEffect as useEffect2 } from "preact/hooks";
// src/useConditionalCallback.tsx
import { useRef as useRef2 } from "preact/hooks";
// src/useDependencyChanged.tsx
import { useDebugValue, useRef } from "preact/hooks";
function defaultCompare(a, b) {
return !Object.is(a, b);
}
function useDependencyChanged(dependency, shouldUpdate = defaultCompare) {
const prevDeps = useRef(dependency);
const result = shouldUpdate(prevDeps.current, dependency);
if (result) {
prevDeps.current = dependency;
}
useDebugValue(result);
return result;
}
// src/useConditionalCallback.tsx
function useConditionalCallback(supplier, dependency, shouldUpdate = defaultCompare) {
const value = useRef2(supplier);
const dependencyChanged = useDependencyChanged(dependency, shouldUpdate);
if (dependencyChanged) {
value.current = supplier;
}
return value.current;
}
// src/useFreshState.tsx
import { useDebugValue as useDebugValue4 } from "preact/hooks";
// src/useConstant.ts
import { useDebugValue as useDebugValue3 } from "preact/hooks";
// src/useLazyRef.ts
import { useDebugValue as useDebugValue2, useRef as useRef3 } from "preact/hooks";
function useLazyRef(supplier) {
const ref = useRef3();
if (!ref.current) {
ref.current = {
current: supplier()
};
}
useDebugValue2(ref.current);
return ref.current;
}
// src/useConstant.ts
function useConstant(supplier) {
const { current } = useLazyRef(supplier);
useDebugValue3(current);
return current;
}
// src/useConstantCallback.ts
function useConstantCallback(cb) {
return useConstant(() => cb);
}
// src/useForceUpdate.ts
import { useReducer } from "preact/hooks";
function useForceUpdate() {
return useReducer(() => [], [])[1];
}
// src/useFreshLazyRef.tsx
function useFreshLazyRef(supplier, dependency, shouldUpdate = defaultCompare) {
const value = useLazyRef(supplier);
const dependencyChanged = useDependencyChanged(dependency, shouldUpdate);
if (dependencyChanged) {
value.current = supplier();
}
return value;
}
// src/useMountedState.ts
import { useRef as useRef4 } from "preact/hooks";
// src/useIsomorphicEffect.ts
import { useEffect, useLayoutEffect } from "preact/hooks";
// src/utils/is-client.ts
var IS_CLIENT = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined";
var is_client_default = IS_CLIENT;
// src/useIsomorphicEffect.ts
var useIsomorphicEffect = is_client_default ? useLayoutEffect : useEffect;
var useIsomorphicEffect_default = useIsomorphicEffect;
// src/useMountedState.ts
function useMountedState() {
const alive = useRef4(false);
useIsomorphicEffect_default(() => {
alive.current = true;
return () => {
alive.current = false;
};
}, []);
return useConstantCallback(() => alive.current);
}
// src/useFreshState.tsx
function isRefreshStateInitialAction(initial) {
return typeof initial === "function";
}
function isRefreshStateAction(state) {
return typeof state === "function";
}
function useFreshState(initialState, dependencies, shouldUpdate = defaultCompare) {
const stateRef = useFreshLazyRef(
() => isRefreshStateInitialAction(initialState) ? initialState() : initialState,
dependencies,
shouldUpdate
);
const forceUpdate = useForceUpdate();
const isMounted = useMountedState();
const setState = useConstantCallback(
(action) => {
if (isMounted()) {
const { current } = stateRef;
const newState = isRefreshStateAction(action) ? action(current) : action;
if (!Object.is(current, newState)) {
stateRef.current = newState;
forceUpdate();
}
}
}
);
useDebugValue4(stateRef.current);
return [stateRef.current, setState];
}
// src/useAsyncMemo.ts
function useAsyncMemo(supplier, dependency, shouldUpdate = defaultCompare) {
const [state, setState] = useFreshState(
() => ({
status: "pending"
}),
dependency,
shouldUpdate
);
const request = useConditionalCallback(supplier, dependency, shouldUpdate);
useEffect2(() => {
let mounted = true;
request().then((value) => {
if (mounted) {
setState({
status: "success",
value
});
}
}, (value) => {
if (mounted) {
setState({
status: "failure",
value
});
}
});
return () => {
mounted = false;
};
}, [request, setState]);
return state;
}
// src/useConditionalEffect.tsx
import { useEffect as useEffect3 } from "preact/hooks";
// src/useDependencyVersion.tsx
import { useDebugValue as useDebugValue5, useRef as useRef5 } from "preact/hooks";
function useDependencyVersion(dependency, shouldUpdate = defaultCompare) {
const dependencyChanged = useDependencyChanged(dependency, shouldUpdate);
const version = useRef5(0);
if (dependencyChanged) {
version.current += 1;
}
useDebugValue5(version.current);
return version.current;
}
// src/useConditionalEffect.tsx
function useConditionalEffect(supplier, dependency, shouldUpdate = defaultCompare) {
const version = useDependencyVersion(dependency, shouldUpdate);
useEffect3(supplier, [version]);
}
// src/useConditionalLayoutEffect.tsx
import { useLayoutEffect as useLayoutEffect2 } from "preact/hooks";
function useConditionalLayoutEffect(supplier, dependency, shouldUpdate = defaultCompare) {
const version = useDependencyVersion(dependency, shouldUpdate);
useLayoutEffect2(supplier, [version]);
}
// src/useConditionalMemo.tsx
import { useDebugValue as useDebugValue6 } from "preact/hooks";
function useConditionalMemo(supplier, dependency, shouldUpdate = defaultCompare) {
const value = useFreshLazyRef(
supplier,
dependency,
shouldUpdate
).current;
useDebugValue6(value);
return value;
}
// src/useFullscreenElement.tsx
import { useDebugValue as useDebugValue8 } from "preact/hooks";
// src/useSubscription.ts
import { useDebugValue as useDebugValue7, useEffect as useEffect4, useState } from "preact/hooks";
function useSubscription({
read,
subscribe,
shouldUpdate = defaultCompare
}) {
const [state, setState] = useState(() => ({
read,
subscribe,
shouldUpdate,
value: read()
}));
let currentValue = state.value;
if (state.read !== read || state.subscribe !== subscribe || state.shouldUpdate !== shouldUpdate) {
currentValue = read();
setState({
read,
subscribe,
shouldUpdate,
value: currentValue
});
}
useDebugValue7(currentValue);
useEffect4(() => {
let mounted = true;
const readCurrent = () => {
if (mounted) {
const nextValue = read();
setState((prev) => {
if (prev.read !== read || prev.subscribe !== subscribe || prev.shouldUpdate !== shouldUpdate) {
return prev;
}
if (!shouldUpdate(prev.value, nextValue)) {
return prev;
}
return __spreadProps(__spreadValues({}, prev), { value: nextValue });
});
}
};
const unsubscribe = subscribe(readCurrent);
readCurrent();
return () => {
mounted = false;
if (unsubscribe) {
unsubscribe();
}
};
}, [read, subscribe, shouldUpdate]);
return currentValue;
}
// src/useFullscreenElement.tsx
var SUBSCRIPTION = {
read: () => {
if (is_client_default && document.fullscreenElement) {
return document.fullscreenElement;
}
return void 0;
},
subscribe: (callback) => {
if (is_client_default) {
document.addEventListener("fullscreenchange", callback);
return () => {
document.removeEventListener("fullscreenchange", callback);
};
}
return void 0;
}
};
function useFullscreenElement() {
const value = useSubscription(SUBSCRIPTION);
useDebugValue8(value);
return value;
}
// src/useMediaQuery.tsx
import { useDebugValue as useDebugValue9 } from "preact/hooks";
var MEDIA = /* @__PURE__ */ new Map();
function getMediaMatcher(query) {
const media = MEDIA.get(query);
if (media) {
return media;
}
const newMedia = window.matchMedia(query);
MEDIA.set(query, newMedia);
return newMedia;
}
function useMediaQuery(query) {
const media = useConditionalMemo(() => {
if (is_client_default) {
return getMediaMatcher(query);
}
return void 0;
}, query);
const subscription = useConditionalMemo(() => ({
read: () => !!(media == null ? void 0 : media.matches),
subscribe: (callback) => {
if (media) {
media.addEventListener("change", callback);
return () => {
media.removeEventListener("change", callback);
};
}
return void 0;
}
}), media);
const value = useSubscription(subscription);
useDebugValue9(value);
return value;
}
// src/useOnlineStatus.ts
import { useDebugValue as useDebugValue10 } from "preact/hooks";
var SUBSCRIPTION2 = {
read: () => {
if (is_client_default) {
return navigator.onLine;
}
return true;
},
subscribe: (callback) => {
if (is_client_default) {
window.addEventListener("online", callback, false);
window.addEventListener("offline", callback, false);
return () => {
window.removeEventListener("online", callback, false);
window.removeEventListener("offline", callback, false);
};
}
return void 0;
}
};
function useOnlineStatus() {
const value = useSubscription(SUBSCRIPTION2);
useDebugValue10(value);
return value;
}
// src/usePageVisibility.ts
import { useDebugValue as useDebugValue11 } from "preact/hooks";
var SUBSCRIPTION3 = {
read: () => {
if (is_client_default) {
return document.visibilityState === "visible";
}
return true;
},
subscribe: (callback) => {
if (is_client_default) {
document.addEventListener("visibilitychange", callback, false);
return () => {
document.removeEventListener("visibilitychange", callback, false);
};
}
return void 0;
}
};
function usePageVisibility() {
const value = useSubscription(SUBSCRIPTION3);
useDebugValue11(value);
return value;
}
// src/usePartialState.tsx
import { useState as useState2 } from "preact/hooks";
function isActionFunc(action) {
return typeof action === "function";
}
function usePartialState(initialState) {
const [state, setState] = useState2(initialState);
const setPartialState = useConstantCallback((action) => {
setState((current) => {
const newValue = isActionFunc(action) ? action(current) : action;
return __spreadValues(__spreadValues({}, current), newValue);
});
});
return [state, setPartialState];
}
// src/usePrefersDarkTheme.tsx
function usePrefersDarkTheme() {
return useMediaQuery("(prefers-color-scheme: dark)");
}
// src/usePrefersLightTheme.tsx
function usePrefersLightTheme() {
return useMediaQuery("(prefers-color-scheme: light)");
}
// src/usePrefersReducedMotion.tsx
function usePrefersReducedMotion() {
return useMediaQuery("(prefers-reduced-motion)");
}
// src/useReadyState.tsx
import { useDebugValue as useDebugValue12 } from "preact/hooks";
var SUBSCRIPTION4 = {
read: () => {
if (is_client_default) {
return document.readyState;
}
return void 0;
},
subscribe: (callback) => {
if (is_client_default) {
document.addEventListener("readystatechange", callback, false);
return () => {
document.removeEventListener("readystatechange", callback, false);
};
}
return void 0;
}
};
function useReadyState() {
const value = useSubscription(SUBSCRIPTION4);
useDebugValue12(value);
return value;
}
// src/useReactiveObject.tsx
import { useDebugValue as useDebugValue13 } from "preact/hooks";
function useReactiveObject(supplier) {
const object = useConstant(supplier);
const forceUpdate = useForceUpdate();
const proxyObject = useConstant(() => new Proxy(object, {
get(target, property, handler) {
return Reflect.get(target, property, handler);
},
set(target, property, value, receiver) {
if (!Object.is(Reflect.get(target, property, receiver), value)) {
Reflect.set(target, property, value, receiver);
forceUpdate();
}
return true;
}
}));
useDebugValue13(proxyObject);
return proxyObject;
}
// src/useReactiveRef.ts
import { useDebugValue as useDebugValue14 } from "preact/hooks";
function useReactiveRef(supplier) {
const forceUpdate = useForceUpdate();
const ref = useLazyRef(supplier);
const proxyObject = useConstant(() => ({
get current() {
return ref.current;
},
set current(value) {
if (!Object.is(value, ref.current)) {
ref.current = value;
forceUpdate();
}
}
}));
useDebugValue14(proxyObject);
return proxyObject;
}
// src/useRenderCount.ts
import { useDebugValue as useDebugValue15, useRef as useRef6 } from "preact/hooks";
function useRenderCount() {
const ref = useRef6(0);
ref.current += 1;
useDebugValue15(ref.current);
return ref.current;
}
// src/useWindowScroll.tsx
import { useDebugValue as useDebugValue16 } from "preact/hooks";
var SUBSCRIPTION5 = {
read: () => {
if (is_client_default) {
return {
x: window.pageXOffset,
y: window.pageYOffset
};
}
return void 0;
},
subscribe: (callback) => {
if (is_client_default) {
window.addEventListener("scroll", callback, {
capture: false,
passive: true
});
return () => {
window.removeEventListener("scroll", callback);
};
}
return void 0;
}
};
function useWindowScroll() {
const value = useSubscription(SUBSCRIPTION5);
useDebugValue16(value);
return value;
}
// src/useWindowSize.ts
import { useDebugValue as useDebugValue17 } from "preact/hooks";
var SUBSCRIPTION6 = {
read: () => {
if (is_client_default) {
return {
width: window.innerWidth,
height: window.innerHeight
};
}
return void 0;
},
subscribe: (callback) => {
if (is_client_default) {
window.addEventListener("resize", callback, false);
return () => {
window.removeEventListener("resize", callback, false);
};
}
return void 0;
}
};
function useWindowSize() {
const value = useSubscription(SUBSCRIPTION6);
useDebugValue17(value);
return value;
}
export {
defaultCompare,
useAsyncMemo,
useConditionalCallback as useCallbackCondition,
useConditionalCallback,
useConditionalEffect,
useConditionalLayoutEffect,
useConditionalMemo,
useConstant,
useConstantCallback,
useDependencyChanged,
useDependencyVersion,
useConditionalEffect as useEffectCondition,
useForceUpdate,
useFreshLazyRef,
useFreshState,
useFullscreenElement,
useIsomorphicEffect_default as useIsomorphicEffect,
useLazyRef,
useMediaQuery,
useConditionalMemo as useMemoCondition,
useMountedState,
useOnlineStatus,
usePageVisibility,
usePartialState,
usePrefersDarkTheme,
usePrefersLightTheme,
usePrefersReducedMotion,
useReactiveObject,
useReactiveRef,
useReadyState,
useRenderCount,
useSubscription,
useWindowScroll,
useWindowSize
};
/**
* @license
* MIT License
*
* Copyright (c) 2021 Lyon Software Technologies, Inc.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
* @author Lyon Software Technologies, Inc.
* @copyright Lyon Software Technologies, Inc. 2021
*/
/**
* @license
* MIT License
*
* Copyright (c) 2021 Lyon Software Technologies, Inc.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the 'Software'), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
* @author Lyon Software Technologies, Inc.
* @copyright Lyon Software Technologies, Inc. 2021
*/
//# sourceMappingURL=index.mjs.map