Commit 6cc198bf authored by Sangjune Bae's avatar Sangjune Bae
Browse files

first commit

parent 81c6da4b
import useCustomEffect from './useCustomEffect';
import isEqual from "lodash-es/isEqual";
import useImmediateUpdateEffect from './useImmediateUpdateEffect';
import useEventCallback from './useEventCallback';
function isDepsEqual(_ref, _ref2) {
var nextElement = _ref[0],
nextConfig = _ref[1];
var prevElement = _ref2[0],
prevConfig = _ref2[1];
return nextElement === prevElement && isEqual(nextConfig, prevConfig);
}
/**
* Observe mutations on a DOM node or tree of DOM nodes.
* Depends on the `MutationObserver` api.
*
* ```ts
* const [element, attachRef] = useCallbackRef(null);
*
* useMutationObserver(element, { subtree: true }, (records) => {
*
* });
*
* return (
* <div ref={attachRef} />
* )
* ```
*
* @param element The DOM element to observe
* @param config The observer configuration
* @param callback A callback fired when a mutation occurs
*/
function useMutationObserver(element, config, callback) {
var fn = useEventCallback(callback);
useCustomEffect(function () {
if (!element) return; // The behavior around reusing mutation observers is confusing
// observing again _should_ disable the last listener but doesn't
// seem to always be the case, maybe just in JSDOM? In any case the cost
// to redeclaring it is gonna be fairly low anyway, so make it simple
var observer = new MutationObserver(fn);
observer.observe(element, config);
return function () {
observer.disconnect();
};
}, [element, config], {
isEqual: isDepsEqual,
// Intentionally done in render, otherwise observer will miss any
// changes made to the DOM during this update
effectHook: useImmediateUpdateEffect
});
}
export default useMutationObserver;
\ No newline at end of file
/**
* Store the last of some value. Tracked via a `Ref` only updating it
* after the component renders.
*
* Helpful if you need to compare a prop value to it's previous value during render.
*
* ```ts
* function Component(props) {
* const lastProps = usePrevious(props)
*
* if (lastProps.foo !== props.foo)
* resetValueFromProps(props.foo)
* }
* ```
*
* @param value the value to track
*/
export default function usePrevious<T>(value: T): T | null;
import { useEffect, useRef } from 'react';
/**
* Store the last of some value. Tracked via a `Ref` only updating it
* after the component renders.
*
* Helpful if you need to compare a prop value to it's previous value during render.
*
* ```ts
* function Component(props) {
* const lastProps = usePrevious(props)
*
* if (lastProps.foo !== props.foo)
* resetValueFromProps(props.foo)
* }
* ```
*
* @param value the value to track
*/
export default function usePrevious(value) {
var ref = useRef(null);
useEffect(function () {
ref.current = value;
});
return ref.current;
}
\ No newline at end of file
declare function useRafInterval(fn: () => void, ms: number): void;
export default useRafInterval;
import { useEffect } from 'react';
import useCommittedRef from './useCommittedRef';
function useRafInterval(fn, ms, paused) {
if (paused === void 0) {
paused = false;
}
var handle;
var start = new Date().getTime();
var fnRef = useCommittedRef(fn); // this ref is necessary b/c useEffect will sometimes miss a paused toggle
// orphaning a setTimeout chain in the aether, so relying on it's refresh logic is not reliable.
var pausedRef = useCommittedRef(paused);
function loop() {
var current = new Date().getTime();
var delta = current - start;
if (pausedRef.current) return;
if (delta >= ms && fnRef.current) {
fnRef.current();
start = new Date().getTime();
}
cancelAnimationFrame(handle);
handle = requestAnimationFrame(loop);
}
useEffect(function () {
handle = requestAnimationFrame(loop);
return function () {
return cancelAnimationFrame(handle);
};
}, []);
}
export default useRafInterval;
\ No newline at end of file
/// <reference types="react" />
/**
* Exactly the same as `useRef` except that the initial value is set via a
* factroy function. Useful when the default is relatively costly to construct.
*
* ```ts
* const ref = useRefWithInitialValueFactory<ExpensiveValue>(() => constructExpensiveValue())
*
* ```
*
* @param initialValueFactory A factory function returning the ref's default value
* @category refs
*/
export default function useRefWithInitialValueFactory<T>(initialValueFactory: () => T): import("react").MutableRefObject<T>;
import { useRef } from 'react';
var dft = Symbol('default value sigil');
/**
* Exactly the same as `useRef` except that the initial value is set via a
* factroy function. Useful when the default is relatively costly to construct.
*
* ```ts
* const ref = useRefWithInitialValueFactory<ExpensiveValue>(() => constructExpensiveValue())
*
* ```
*
* @param initialValueFactory A factory function returning the ref's default value
* @category refs
*/
export default function useRefWithInitialValueFactory(initialValueFactory) {
var ref = useRef(dft);
if (ref.current === dft) {
ref.current = initialValueFactory();
}
return ref;
}
\ No newline at end of file
export interface Rect {
width: number;
height: number;
x?: number;
y?: number;
}
/**
* Efficiently observe size changes on an element. Depends on the `ResizeObserver` api,
* and polyfills are needed in older browsers.
*
* ```ts
* const [ref, attachRef] = useCallbackRef(null);
*
* const rect = useResizeObserver(ref);
*
* return (
* <div ref={attachRef}>
* {JSON.stringify(rect)}
* </div>
* )
* ```
*
* @param element The DOM element to observe
*/
export default function useResizeObserver<TElement extends Element>(element: TElement | null | undefined): Rect | null;
import { useState } from 'react';
import useEffect from './useIsomorphicEffect';
var targetMap = new WeakMap();
var resizeObserver;
function getResizeObserver() {
// eslint-disable-next-line no-return-assign
return resizeObserver = resizeObserver || new window.ResizeObserver(function (entries) {
entries.forEach(function (entry) {
var handler = targetMap.get(entry.target);
if (handler) handler(entry.contentRect);
});
});
}
/**
* Efficiently observe size changes on an element. Depends on the `ResizeObserver` api,
* and polyfills are needed in older browsers.
*
* ```ts
* const [ref, attachRef] = useCallbackRef(null);
*
* const rect = useResizeObserver(ref);
*
* return (
* <div ref={attachRef}>
* {JSON.stringify(rect)}
* </div>
* )
* ```
*
* @param element The DOM element to observe
*/
export default function useResizeObserver(element) {
var _useState = useState(null),
rect = _useState[0],
setRect = _useState[1];
useEffect(function () {
if (!element) return;
getResizeObserver().observe(element);
setRect(element.getBoundingClientRect());
targetMap.set(element, function (rect) {
setRect(rect);
});
return function () {
targetMap.delete(element);
};
}, [element]);
return rect;
}
\ No newline at end of file
import { Dispatch, SetStateAction } from 'react';
import { AsyncSetState } from './useStateAsync';
declare type StateSetter<TState> = Dispatch<SetStateAction<TState>>;
/**
* `useSafeState` takes the return value of a `useState` hook and wraps the
* setter to prevent updates onces the component has unmounted. Can used
* with `useMergeState` and `useStateAsync` as well
*
* @param state The return value of a useStateHook
*
* ```ts
* const [show, setShow] = useSafeState(useState(true));
* ```
*/
declare function useSafeState<TState>(state: [TState, AsyncSetState<TState>]): [TState, (stateUpdate: React.SetStateAction<TState>) => Promise<void>];
declare function useSafeState<TState>(state: [TState, StateSetter<TState>]): [TState, StateSetter<TState>];
export default useSafeState;
import { useCallback } from 'react';
import useMounted from './useMounted';
function useSafeState(state) {
var isMounted = useMounted();
return [state[0], useCallback(function (nextState) {
if (!isMounted()) return;
return state[1](nextState);
}, [isMounted, state[1]])];
}
export default useSafeState;
\ No newline at end of file
export declare class ObservableSet<V> extends Set<V> {
private readonly listener;
constructor(listener: (map: ObservableSet<V>) => void, init?: Iterable<V>);
add(value: V): this;
delete(value: V): boolean;
clear(): void;
}
/**
* Create and return a [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) that triggers rerenders when it's updated.
*
* ```ts
* const ids = useSet<number>([1,2,3,4]);
*
* return (
* <>
* {Array.from(ids, id => (
* <div>
* id: {id}. <button onClick={() => ids.delete(id)}>X</button>
* </div>
* )}
* </>
* )
* ```
*
* @param init initial Set values
*/
declare function useSet<V>(init?: Iterable<V>): ObservableSet<V>;
export default useSet;
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
function _wrapNativeSuper(Class) { var _cache = typeof Map === "function" ? new Map() : undefined; _wrapNativeSuper = function _wrapNativeSuper(Class) { if (Class === null || !_isNativeFunction(Class)) return Class; if (typeof Class !== "function") { throw new TypeError("Super expression must either be null or a function"); } if (typeof _cache !== "undefined") { if (_cache.has(Class)) return _cache.get(Class); _cache.set(Class, Wrapper); } function Wrapper() { return _construct(Class, arguments, _getPrototypeOf(this).constructor); } Wrapper.prototype = Object.create(Class.prototype, { constructor: { value: Wrapper, enumerable: false, writable: true, configurable: true } }); return _setPrototypeOf(Wrapper, Class); }; return _wrapNativeSuper(Class); }
function isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
function _construct(Parent, args, Class) { if (isNativeReflectConstruct()) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Function.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); }
function _isNativeFunction(fn) { return Function.toString.call(fn).indexOf("[native code]") !== -1; }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
import useForceUpdate from './useForceUpdate';
import useStableMemo from './useStableMemo';
export var ObservableSet =
/*#__PURE__*/
function (_Set) {
_inheritsLoose(ObservableSet, _Set);
function ObservableSet(listener, init) {
var _this;
_this = _Set.call(this, init) || this;
_this.listener = listener;
return _this;
}
var _proto = ObservableSet.prototype;
_proto.add = function add(value) {
_Set.prototype.add.call(this, value); // When initializing the Set, the base Set calls this.add() before the
// listener is assigned so it will be undefined
if (this.listener) this.listener(this);
return this;
};
_proto.delete = function _delete(value) {
var result = _Set.prototype.delete.call(this, value);
this.listener(this);
return result;
};
_proto.clear = function clear() {
_Set.prototype.clear.call(this);
this.listener(this);
};
return ObservableSet;
}(
/*#__PURE__*/
_wrapNativeSuper(Set));
/**
* Create and return a [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) that triggers rerenders when it's updated.
*
* ```ts
* const ids = useSet<number>([1,2,3,4]);
*
* return (
* <>
* {Array.from(ids, id => (
* <div>
* id: {id}. <button onClick={() => ids.delete(id)}>X</button>
* </div>
* )}
* </>
* )
* ```
*
* @param init initial Set values
*/
function useSet(init) {
var forceUpdate = useForceUpdate();
return useStableMemo(function () {
return new ObservableSet(forceUpdate, init);
}, []);
}
export default useSet;
\ No newline at end of file
import { DependencyList } from 'react';
/**
* Identical to `useMemo` _except_ that it provides a semantic guarantee that
* values will not be invalidated unless the dependencies change. This is unlike
* the built in `useMemo` which may discard memoized values for performance reasons.
*
* @param factory A function that returns a value to be memoized
* @param deps A dependency array
*/
export default function useStableMemo<T>(factory: () => T, deps?: DependencyList): T;
import { useRef } from 'react';
function isEqual(a, b) {
if (a.length !== b.length) return false;
for (var i = 0; i < a.length; i++) {
if (a[i] !== b[i]) {
return false;
}
}
return true;
}
/**
* Identical to `useMemo` _except_ that it provides a semantic guarantee that
* values will not be invalidated unless the dependencies change. This is unlike
* the built in `useMemo` which may discard memoized values for performance reasons.
*
* @param factory A function that returns a value to be memoized
* @param deps A dependency array
*/
export default function useStableMemo(factory, deps) {
var isValid = true;
var valueRef = useRef(); // initial hook call
if (!valueRef.current) {
valueRef.current = {
deps: deps,
result: factory()
}; // subsequent calls
} else {
isValid = !!(deps && valueRef.current.deps && isEqual(deps, valueRef.current.deps));
}
var cache = isValid ? valueRef.current : {
deps: deps,
result: factory()
}; // must update immediately so any sync renders here don't cause an infinite loop
valueRef.current = cache;
return cache.result;
}
\ No newline at end of file
import React from 'react';
export declare type AsyncSetState<TState> = (stateUpdate: React.SetStateAction<TState>) => Promise<TState>;
/**
* A hook that mirrors `useState` in function and API, expect that setState
* calls return a promise that resolves after the state has been set (in an effect).
*
* This is _similar_ to the second callback in classy setState calls, but fires later.
*
* ```ts
* const [counter, setState] = useStateAsync(1);
*
* const handleIncrement = async () => {
* await setState(2);
* doWorkRequiringCurrentState()
* }
* ```
*
* @param initialState initialize with some state value same as `useState`
*/
export default function useStateAsync<TState>(initialState: TState | (() => TState)): [TState, AsyncSetState<TState>];
import { useCallback, useEffect, useRef, useState } from 'react';
/**
* A hook that mirrors `useState` in function and API, expect that setState
* calls return a promise that resolves after the state has been set (in an effect).
*
* This is _similar_ to the second callback in classy setState calls, but fires later.
*
* ```ts
* const [counter, setState] = useStateAsync(1);
*
* const handleIncrement = async () => {
* await setState(2);
* doWorkRequiringCurrentState()
* }
* ```
*
* @param initialState initialize with some state value same as `useState`
*/
export default function useStateAsync(initialState) {
var _useState = useState(initialState),
state = _useState[0],
setState = _useState[1];
var resolvers = useRef([]);
useEffect(function () {
resolvers.current.forEach(function (resolve) {
return resolve(state);
});
resolvers.current.length = 0;
}, [state]);
var setStateAsync = useCallback(function (update) {
return new Promise(function (resolve, reject) {
setState(function (prevState) {
try {
var nextState; // ugly instanceof for typescript
if (update instanceof Function) {
nextState = update(prevState);
} else {
nextState = update;
} // If state does not change, we must resolve the promise because
// react won't re-render and effect will not resolve. If there are already
// resolvers queued, then it should be safe to assume an update will happen
if (!resolvers.current.length && Object.is(nextState, prevState)) {
resolve(nextState);
} else {
resolvers.current.push(resolve);
}
return nextState;
} catch (e) {
reject(e);
throw e;
}
});
});
}, [setState]);
return [state, setStateAsync];
}
\ No newline at end of file
import { SyntheticEvent } from 'react';
export declare type ThrottledHandler<TEvent> = ((event: TEvent) => void) & {
clear(): void;
};
/**
* Creates a event handler function throttled by `requestAnimationFrame` that
* returns the **most recent** event. Useful for noisy events that update react state.
*
* ```tsx
* function Component() {
* const [position, setPosition] = useState();
* const handleMove = useThrottledEventHandler<React.PointerEvent>(
* (event) => {
* setPosition({
* top: event.clientX,
* left: event.clientY,
* })
* }
* )
*
* return (
* <div onPointerMove={handleMove}>
* <div style={position} />
* </div>
* );
* }
* ```
*
* @param handler An event handler function
* @typeParam TEvent The event object passed to the handler function
* @returns The event handler with a `clear` method attached for clearing any in-flight handler calls
*
*/
export default function useThrottledEventHandler<TEvent = SyntheticEvent>(handler: (event: TEvent) => void): ThrottledHandler<TEvent>;
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
import { useRef } from 'react';
import useMounted from './useMounted';
import useEventCallback from './useEventCallback';
var isSyntheticEvent = function isSyntheticEvent(event) {
return typeof event.persist === 'function';
};
/**
* Creates a event handler function throttled by `requestAnimationFrame` that
* returns the **most recent** event. Useful for noisy events that update react state.
*
* ```tsx
* function Component() {
* const [position, setPosition] = useState();
* const handleMove = useThrottledEventHandler<React.PointerEvent>(
* (event) => {
* setPosition({
* top: event.clientX,
* left: event.clientY,
* })
* }
* )
*
* return (
* <div onPointerMove={handleMove}>
* <div style={position} />
* </div>
* );
* }
* ```
*
* @param handler An event handler function
* @typeParam TEvent The event object passed to the handler function
* @returns The event handler with a `clear` method attached for clearing any in-flight handler calls
*
*/
export default function useThrottledEventHandler(handler) {
var isMounted = useMounted();
var eventHandler = useEventCallback(handler);
var nextEventInfoRef = useRef({
event: null,
handle: null
});
var clear = function clear() {
cancelAnimationFrame(nextEventInfoRef.current.handle);
nextEventInfoRef.current.handle = null;
};
var handlePointerMoveAnimation = function handlePointerMoveAnimation() {
var next = nextEventInfoRef.current;
if (next.handle && next.event) {
if (isMounted()) {
next.handle = null;
eventHandler(next.event);
}
}
next.event = null;
};
var throttledHandler = function throttledHandler(event) {
if (!isMounted()) return;
if (isSyntheticEvent(event)) {
event.persist();
} // Special handling for a React.Konva event which reuses the
// event object as it bubbles, setting target
else if ('evt' in event) {
event = _extends({}, event);
}
nextEventInfoRef.current.event = event;
if (!nextEventInfoRef.current.handle) {
nextEventInfoRef.current.handle = requestAnimationFrame(handlePointerMoveAnimation);
}
};
throttledHandler.clear = clear;
return throttledHandler;
}
\ No newline at end of file
/**
* Returns a controller object for setting a timeout that is properly cleaned up
* once the component unmounts. New timeouts cancel and replace existing ones.
*/
export default function useTimeout(): {
set: (fn: () => void, delayMs?: number) => void;
clear: () => void;
};
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment