These files should not be added

This commit is contained in:
Gabe Kangas
2020-10-19 22:22:33 -07:00
parent 226242f07b
commit 205ef8926e
6368 changed files with 0 additions and 603959 deletions

View File

@@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2015-present Jason Miller
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.

View File

@@ -1,26 +0,0 @@
{
"name": "preact-hooks",
"amdName": "preactHooks",
"version": "0.1.0",
"private": true,
"description": "Hook addon for Preact",
"main": "dist/hooks.js",
"module": "dist/hooks.module.js",
"umd:main": "dist/hooks.umd.js",
"source": "src/index.js",
"license": "MIT",
"types": "src/index.d.ts",
"scripts": {
"build": "microbundle build --raw",
"dev": "microbundle watch --raw --format cjs",
"test": "npm-run-all build --parallel test:karma",
"test:karma": "karma start test/karma.conf.js --single-run",
"test:karma:watch": "karma start test/karma.conf.js --no-single-run"
},
"peerDependencies": {
"preact": "^10.0.0"
},
"mangle": {
"regex": "^_"
}
}

View File

@@ -1,133 +0,0 @@
import { PreactContext, Ref as PreactRef } from '../..';
type Inputs = ReadonlyArray<unknown>;
export type StateUpdater<S> = (value: S | ((prevState: S) => S)) => void;
/**
* Returns a stateful value, and a function to update it.
* @param initialState The initial value (or a function that returns the initial value)
*/
export function useState<S>(initialState: S | (() => S)): [S, StateUpdater<S>];
export type Reducer<S, A> = (prevState: S, action: A) => S;
/**
* An alternative to `useState`.
*
* `useReducer` is usually preferable to `useState` when you have complex state logic that involves
* multiple sub-values. It also lets you optimize performance for components that trigger deep
* updates because you can pass `dispatch` down instead of callbacks.
* @param reducer Given the current state and an action, returns the new state
* @param initialState The initial value to store as state
*/
export function useReducer<S, A>(
reducer: Reducer<S, A>,
initialState: S
): [S, (action: A) => void];
/**
* An alternative to `useState`.
*
* `useReducer` is usually preferable to `useState` when you have complex state logic that involves
* multiple sub-values. It also lets you optimize performance for components that trigger deep
* updates because you can pass `dispatch` down instead of callbacks.
* @param reducer Given the current state and an action, returns the new state
* @param initialArg The initial argument to pass to the `init` function
* @param init A function that, given the `initialArg`, returns the initial value to store as state
*/
export function useReducer<S, A, I>(
reducer: Reducer<S, A>,
initialArg: I,
init: (arg: I) => S
): [S, (action: A) => void];
type PropRef<T> = { current?: T };
type Ref<T> = { current: T };
/**
* `useRef` returns a mutable ref object whose `.current` property is initialized to the passed argument
* (`initialValue`). The returned object will persist for the full lifetime of the component.
*
* Note that `useRef()` is useful for more than the `ref` attribute. Its handy for keeping any mutable
* value around similar to how youd use instance fields in classes.
*/
export function useRef<T>(initialValue?: T | null): Ref<T>;
/**
* `useRef` without an initial value is the special case handling `ref` props.
* If you want a non prop-based, mutable ref, you can explicitly give it an initial value of undefined/null/etc.
* You should explicitly set the type parameter for the expected ref value to either a DOM Element like `HTMLInputElement` or a `Component`
*/
export function useRef<T = unknown>(): PropRef<T>;
type EffectCallback = () => void | (() => void);
/**
* Accepts a function that contains imperative, possibly effectful code.
* The effects run after browser paint, without blocking it.
*
* @param effect Imperative function that can return a cleanup function
* @param inputs If present, effect will only activate if the values in the list change (using ===).
*/
export function useEffect(effect: EffectCallback, inputs?: Inputs): void;
type CreateHandle = () => object;
/**
* @param ref The ref that will be mutated
* @param create The function that will be executed to get the value that will be attached to
* ref.current
* @param inputs If present, effect will only activate if the values in the list change (using ===).
*/
export function useImperativeHandle<T, R extends T>(
ref: PreactRef<T>,
create: () => R,
inputs?: Inputs
): void;
/**
* Accepts a function that contains imperative, possibly effectful code.
* Use this to read layout from the DOM and synchronously re-render.
* Updates scheduled inside `useLayoutEffect` will be flushed synchronously, after all DOM mutations but before the browser has a chance to paint.
* Prefer the standard `useEffect` hook when possible to avoid blocking visual updates.
*
* @param effect Imperative function that can return a cleanup function
* @param inputs If present, effect will only activate if the values in the list change (using ===).
*/
export function useLayoutEffect(effect: EffectCallback, inputs?: Inputs): void;
/**
* Returns a memoized version of the callback that only changes if one of the `inputs`
* has changed (using ===).
*/
export function useCallback<T extends Function>(callback: T, inputs: Inputs): T;
/**
* Pass a factory function and an array of inputs.
* useMemo will only recompute the memoized value when one of the inputs has changed.
* This optimization helps to avoid expensive calculations on every render.
* If no array is provided, a new value will be computed whenever a new function instance is passed as the first argument.
*/
// for `inputs`, allow undefined, but don't make it optional as that is very likely a mistake
export function useMemo<T>(factory: () => T, inputs: Inputs | undefined): T;
/**
* Returns the current context value, as given by the nearest context provider for the given context.
* When the provider updates, this Hook will trigger a rerender with the latest context value.
*
* @param context The context you want to use
*/
export function useContext<T>(context: PreactContext<T>): T;
/**
* Customize the displayed value in the devtools panel.
*
* @param value Custom hook name or object that is passed to formatter
* @param formatter Formatter to modify value before sending it to the devtools
*/
export function useDebugValue<T>(
value: T,
formatter?: (value: T) => any
): void;
export function useErrorBoundary(
callback?: (error: any) => Promise<void> | void
): [any, () => void];

View File

@@ -1,360 +0,0 @@
import { options } from 'preact';
/** @type {number} */
let currentIndex;
/** @type {import('./internal').Component} */
let currentComponent;
/** @type {number} */
let currentHook = 0;
/** @type {Array<import('./internal').Component>} */
let afterPaintEffects = [];
let oldBeforeRender = options._render;
let oldAfterDiff = options.diffed;
let oldCommit = options._commit;
let oldBeforeUnmount = options.unmount;
const RAF_TIMEOUT = 100;
let prevRaf;
options._render = vnode => {
if (oldBeforeRender) oldBeforeRender(vnode);
currentComponent = vnode._component;
currentIndex = 0;
const hooks = currentComponent.__hooks;
if (hooks) {
hooks._pendingEffects.forEach(invokeCleanup);
hooks._pendingEffects.forEach(invokeEffect);
hooks._pendingEffects = [];
}
};
options.diffed = vnode => {
if (oldAfterDiff) oldAfterDiff(vnode);
const c = vnode._component;
if (c && c.__hooks && c.__hooks._pendingEffects.length) {
afterPaint(afterPaintEffects.push(c));
}
};
options._commit = (vnode, commitQueue) => {
commitQueue.some(component => {
try {
component._renderCallbacks.forEach(invokeCleanup);
component._renderCallbacks = component._renderCallbacks.filter(cb =>
cb._value ? invokeEffect(cb) : true
);
} catch (e) {
commitQueue.some(c => {
if (c._renderCallbacks) c._renderCallbacks = [];
});
commitQueue = [];
options._catchError(e, component._vnode);
}
});
if (oldCommit) oldCommit(vnode, commitQueue);
};
options.unmount = vnode => {
if (oldBeforeUnmount) oldBeforeUnmount(vnode);
const c = vnode._component;
if (c && c.__hooks) {
try {
c.__hooks._list.forEach(invokeCleanup);
} catch (e) {
options._catchError(e, c._vnode);
}
}
};
/**
* Get a hook's state from the currentComponent
* @param {number} index The index of the hook to get
* @param {number} type The index of the hook to get
* @returns {import('./internal').HookState}
*/
function getHookState(index, type) {
if (options._hook) {
options._hook(currentComponent, index, currentHook || type);
}
currentHook = 0;
// Largely inspired by:
// * https://github.com/michael-klein/funcy.js/blob/f6be73468e6ec46b0ff5aa3cc4c9baf72a29025a/src/hooks/core_hooks.mjs
// * https://github.com/michael-klein/funcy.js/blob/650beaa58c43c33a74820a3c98b3c7079cf2e333/src/renderer.mjs
// Other implementations to look at:
// * https://codesandbox.io/s/mnox05qp8
const hooks =
currentComponent.__hooks ||
(currentComponent.__hooks = {
_list: [],
_pendingEffects: []
});
if (index >= hooks._list.length) {
hooks._list.push({});
}
return hooks._list[index];
}
/**
* @param {import('./index').StateUpdater<any>} initialState
*/
export function useState(initialState) {
currentHook = 1;
return useReducer(invokeOrReturn, initialState);
}
/**
* @param {import('./index').Reducer<any, any>} reducer
* @param {import('./index').StateUpdater<any>} initialState
* @param {(initialState: any) => void} [init]
* @returns {[ any, (state: any) => void ]}
*/
export function useReducer(reducer, initialState, init) {
/** @type {import('./internal').ReducerHookState} */
const hookState = getHookState(currentIndex++, 2);
hookState._reducer = reducer;
if (!hookState._component) {
hookState._value = [
!init ? invokeOrReturn(undefined, initialState) : init(initialState),
action => {
const nextValue = hookState._reducer(hookState._value[0], action);
if (hookState._value[0] !== nextValue) {
hookState._value = [nextValue, hookState._value[1]];
hookState._component.setState({});
}
}
];
hookState._component = currentComponent;
}
return hookState._value;
}
/**
* @param {import('./internal').Effect} callback
* @param {any[]} args
*/
export function useEffect(callback, args) {
/** @type {import('./internal').EffectHookState} */
const state = getHookState(currentIndex++, 3);
if (!options._skipEffects && argsChanged(state._args, args)) {
state._value = callback;
state._args = args;
currentComponent.__hooks._pendingEffects.push(state);
}
}
/**
* @param {import('./internal').Effect} callback
* @param {any[]} args
*/
export function useLayoutEffect(callback, args) {
/** @type {import('./internal').EffectHookState} */
const state = getHookState(currentIndex++, 4);
if (!options._skipEffects && argsChanged(state._args, args)) {
state._value = callback;
state._args = args;
currentComponent._renderCallbacks.push(state);
}
}
export function useRef(initialValue) {
currentHook = 5;
return useMemo(() => ({ current: initialValue }), []);
}
/**
* @param {object} ref
* @param {() => object} createHandle
* @param {any[]} args
*/
export function useImperativeHandle(ref, createHandle, args) {
currentHook = 6;
useLayoutEffect(
() => {
if (typeof ref == 'function') ref(createHandle());
else if (ref) ref.current = createHandle();
},
args == null ? args : args.concat(ref)
);
}
/**
* @param {() => any} factory
* @param {any[]} args
*/
export function useMemo(factory, args) {
/** @type {import('./internal').MemoHookState} */
const state = getHookState(currentIndex++, 7);
if (argsChanged(state._args, args)) {
state._value = factory();
state._args = args;
state._factory = factory;
}
return state._value;
}
/**
* @param {() => void} callback
* @param {any[]} args
*/
export function useCallback(callback, args) {
currentHook = 8;
return useMemo(() => callback, args);
}
/**
* @param {import('./internal').PreactContext} context
*/
export function useContext(context) {
const provider = currentComponent.context[context._id];
// We could skip this call here, but than we'd not call
// `options._hook`. We need to do that in order to make
// the devtools aware of this hook.
const state = getHookState(currentIndex++, 9);
// The devtools needs access to the context object to
// be able to pull of the default value when no provider
// is present in the tree.
state._context = context;
if (!provider) return context._defaultValue;
// This is probably not safe to convert to "!"
if (state._value == null) {
state._value = true;
provider.sub(currentComponent);
}
return provider.props.value;
}
/**
* Display a custom label for a custom hook for the devtools panel
* @type {<T>(value: T, cb?: (value: T) => string | number) => void}
*/
export function useDebugValue(value, formatter) {
if (options.useDebugValue) {
options.useDebugValue(formatter ? formatter(value) : value);
}
}
export function useErrorBoundary(cb) {
const state = getHookState(currentIndex++, 10);
const errState = useState();
state._value = cb;
if (!currentComponent.componentDidCatch) {
currentComponent.componentDidCatch = err => {
if (state._value) state._value(err);
errState[1](err);
};
}
return [
errState[0],
() => {
errState[1](undefined);
}
];
}
/**
* After paint effects consumer.
*/
function flushAfterPaintEffects() {
afterPaintEffects.some(component => {
if (component._parentDom) {
try {
component.__hooks._pendingEffects.forEach(invokeCleanup);
component.__hooks._pendingEffects.forEach(invokeEffect);
component.__hooks._pendingEffects = [];
} catch (e) {
component.__hooks._pendingEffects = [];
options._catchError(e, component._vnode);
return true;
}
}
});
afterPaintEffects = [];
}
let HAS_RAF = typeof requestAnimationFrame == 'function';
/**
* Schedule a callback to be invoked after the browser has a chance to paint a new frame.
* Do this by combining requestAnimationFrame (rAF) + setTimeout to invoke a callback after
* the next browser frame.
*
* Also, schedule a timeout in parallel to the the rAF to ensure the callback is invoked
* even if RAF doesn't fire (for example if the browser tab is not visible)
*
* @param {() => void} callback
*/
function afterNextFrame(callback) {
const done = () => {
clearTimeout(timeout);
if (HAS_RAF) cancelAnimationFrame(raf);
setTimeout(callback);
};
const timeout = setTimeout(done, RAF_TIMEOUT);
let raf;
if (HAS_RAF) {
raf = requestAnimationFrame(done);
}
}
// Note: if someone used options.debounceRendering = requestAnimationFrame,
// then effects will ALWAYS run on the NEXT frame instead of the current one, incurring a ~16ms delay.
// Perhaps this is not such a big deal.
/**
* Schedule afterPaintEffects flush after the browser paints
* @param {number} newQueueLength
*/
function afterPaint(newQueueLength) {
if (newQueueLength === 1 || prevRaf !== options.requestAnimationFrame) {
prevRaf = options.requestAnimationFrame;
(prevRaf || afterNextFrame)(flushAfterPaintEffects);
}
}
/**
* @param {import('./internal').EffectHookState} hook
*/
function invokeCleanup(hook) {
if (typeof hook._cleanup == 'function') hook._cleanup();
}
/**
* Invoke a Hook's effect
* @param {import('./internal').EffectHookState} hook
*/
function invokeEffect(hook) {
hook._cleanup = hook._value();
}
/**
* @param {any[]} oldArgs
* @param {any[]} newArgs
*/
function argsChanged(oldArgs, newArgs) {
return (
!oldArgs ||
oldArgs.length !== newArgs.length ||
newArgs.some((arg, index) => arg !== oldArgs[index])
);
}
function invokeOrReturn(arg, f) {
return typeof f == 'function' ? f(arg) : f;
}

View File

@@ -1,57 +0,0 @@
import { Component as PreactComponent } from '../../src/internal';
import { Reducer } from '.';
export { PreactContext } from '../../src/internal';
/**
* The type of arguments passed to a Hook function. While this type is not
* strictly necessary, they are given a type name to make it easier to read
* the following types and trace the flow of data.
*/
export type HookArgs = any;
/**
* The return type of a Hook function. While this type is not
* strictly necessary, they are given a type name to make it easier to read
* the following types and trace the flow of data.
*/
export type HookReturnValue = any;
/** The public function a user invokes to use a Hook */
export type Hook = (...args: HookArgs[]) => HookReturnValue;
// Hook tracking
export interface ComponentHooks {
/** The list of hooks a component uses */
_list: HookState[];
/** List of Effects to be invoked after the next frame is rendered */
_pendingEffects: EffectHookState[];
}
export interface Component extends PreactComponent<any, any> {
__hooks?: ComponentHooks;
}
export type HookState = EffectHookState | MemoHookState | ReducerHookState;
export type Effect = () => void | Cleanup;
export type Cleanup = () => void;
export interface EffectHookState {
_value?: Effect;
_args?: any[];
_cleanup?: Cleanup;
}
export interface MemoHookState {
_value?: any;
_args?: any[];
_factory?: () => any;
}
export interface ReducerHookState {
_value?: any;
_component?: Component;
_reducer?: Reducer<any, any>;
}