{"version":3,"file":"hooks.modern.js","sources":["../src/index.js","../../src/constants.js"],"sourcesContent":["import { options } from 'preact';\nimport { MODE_UNMOUNTING } from '../../src/constants';\n\n/** @type {number} */\nlet currentIndex;\n\n/** @type {import('./internal').Component} */\nlet currentComponent;\n/**\n * Keep track of the previous component so that we can set\n * `currentComponent` to `null` and throw when a hook is invoked\n * outside of render\n * @type {import('./internal').Component}\n */\nlet previousComponent;\n\n/** @type {number} */\nlet currentHook = 0;\n\n/** @type {Array} */\nlet afterPaintEffects = [];\n\nlet oldBeforeDiff = options._diff;\nlet oldBeforeRender = options._render;\nlet oldAfterDiff = options.diffed;\nlet oldCommit = options._commit;\nlet oldBeforeUnmount = options.unmount;\n\nconst RAF_TIMEOUT = 100;\nlet prevRaf;\n\noptions._diff = (internal, vnode) => {\n\tcurrentComponent = null;\n\tif (oldBeforeDiff) oldBeforeDiff(internal, vnode);\n};\n\noptions._render = internal => {\n\tif (oldBeforeRender) oldBeforeRender(internal);\n\n\tcurrentComponent = internal._component;\n\tcurrentIndex = 0;\n\n\tconst hooks = currentComponent.__hooks;\n\tif (hooks) {\n\t\thooks._pendingEffects.forEach(invokeCleanup);\n\t\thooks._pendingEffects.forEach(invokeEffect);\n\t\thooks._pendingEffects = [];\n\t}\n};\n\noptions.diffed = internal => {\n\tif (oldAfterDiff) oldAfterDiff(internal);\n\n\tconst c = internal._component;\n\tif (c && c.__hooks && c.__hooks._pendingEffects.length) {\n\t\tafterPaint(afterPaintEffects.push(c));\n\t}\n\tcurrentComponent = previousComponent;\n};\n\noptions._commit = (internal, commitQueue) => {\n\tcommitQueue.some(internal => {\n\t\ttry {\n\t\t\tinternal._commitCallbacks.forEach(invokeCleanup);\n\t\t\tinternal._commitCallbacks = internal._commitCallbacks.filter(cb =>\n\t\t\t\tcb._value ? invokeEffect(cb) : true\n\t\t\t);\n\t\t} catch (e) {\n\t\t\tcommitQueue.some(i => {\n\t\t\t\tif (i._commitCallbacks) i._commitCallbacks = [];\n\t\t\t});\n\t\t\tcommitQueue = [];\n\t\t\toptions._catchError(e, internal);\n\t\t}\n\t});\n\n\tif (oldCommit) oldCommit(internal, commitQueue);\n};\n\noptions.unmount = internal => {\n\tif (oldBeforeUnmount) oldBeforeUnmount(internal);\n\n\tconst c = internal._component;\n\tif (c && c.__hooks) {\n\t\ttry {\n\t\t\tc.__hooks._list.forEach(invokeCleanup);\n\t\t} catch (e) {\n\t\t\toptions._catchError(e, c._internal);\n\t\t}\n\t}\n};\n\n/**\n * Get a hook's state from the currentComponent\n * @param {number} index The index of the hook to get\n * @param {number} type The index of the hook to get\n * @returns {any}\n */\nfunction getHookState(index, type) {\n\tif (options._hook) {\n\t\toptions._hook(currentComponent, index, currentHook || type);\n\t}\n\tcurrentHook = 0;\n\n\t// Largely inspired by:\n\t// * https://github.com/michael-klein/funcy.js/blob/f6be73468e6ec46b0ff5aa3cc4c9baf72a29025a/src/hooks/core_hooks.mjs\n\t// * https://github.com/michael-klein/funcy.js/blob/650beaa58c43c33a74820a3c98b3c7079cf2e333/src/renderer.mjs\n\t// Other implementations to look at:\n\t// * https://codesandbox.io/s/mnox05qp8\n\tconst hooks =\n\t\tcurrentComponent.__hooks ||\n\t\t(currentComponent.__hooks = {\n\t\t\t_list: [],\n\t\t\t_pendingEffects: []\n\t\t});\n\n\tif (index >= hooks._list.length) {\n\t\thooks._list.push({});\n\t}\n\treturn hooks._list[index];\n}\n\n/**\n * @param {import('./index').StateUpdater} [initialState]\n */\nexport function useState(initialState) {\n\tcurrentHook = 1;\n\treturn useReducer(invokeOrReturn, initialState);\n}\n\n/**\n * @param {import('./index').Reducer} reducer\n * @param {import('./index').StateUpdater} initialState\n * @param {(initialState: any) => void} [init]\n * @returns {[ any, (state: any) => void ]}\n */\nexport function useReducer(reducer, initialState, init) {\n\t/** @type {import('./internal').ReducerHookState} */\n\tconst hookState = getHookState(currentIndex++, 2);\n\thookState._reducer = reducer;\n\tif (!hookState._component) {\n\t\thookState._value = [\n\t\t\t!init ? invokeOrReturn(undefined, initialState) : init(initialState),\n\n\t\t\taction => {\n\t\t\t\tconst nextValue = hookState._reducer(hookState._value[0], action);\n\t\t\t\tif (hookState._value[0] !== nextValue) {\n\t\t\t\t\thookState._value = [nextValue, hookState._value[1]];\n\t\t\t\t\thookState._component.setState({});\n\t\t\t\t}\n\t\t\t}\n\t\t];\n\n\t\thookState._component = currentComponent;\n\t}\n\n\treturn hookState._value;\n}\n\n/**\n * @param {import('./internal').Effect} callback\n * @param {any[]} args\n */\nexport function useEffect(callback, args) {\n\t/** @type {import('./internal').EffectHookState} */\n\tconst state = getHookState(currentIndex++, 3);\n\tif (!options._skipEffects && argsChanged(state._args, args)) {\n\t\tstate._value = callback;\n\t\tstate._args = args;\n\n\t\tcurrentComponent.__hooks._pendingEffects.push(state);\n\t}\n}\n\n/**\n * @param {import('./internal').Effect} callback\n * @param {any[]} args\n */\nexport function useLayoutEffect(callback, args) {\n\t/** @type {import('./internal').EffectHookState} */\n\tconst state = getHookState(currentIndex++, 4);\n\tif (!options._skipEffects && argsChanged(state._args, args)) {\n\t\tstate._value = callback;\n\t\tstate._args = args;\n\n\t\tif (currentComponent._internal._commitCallbacks == null) {\n\t\t\tcurrentComponent._internal._commitCallbacks = [];\n\t\t}\n\t\tcurrentComponent._internal._commitCallbacks.push(state);\n\t}\n}\n\nexport function useRef(initialValue) {\n\tcurrentHook = 5;\n\treturn useMemo(() => ({ current: initialValue }), []);\n}\n\n/**\n * @param {object} ref\n * @param {() => object} createHandle\n * @param {any[]} args\n */\nexport function useImperativeHandle(ref, createHandle, args) {\n\tcurrentHook = 6;\n\tuseLayoutEffect(\n\t\t() => {\n\t\t\tif (typeof ref == 'function') ref(createHandle());\n\t\t\telse if (ref) ref.current = createHandle();\n\t\t},\n\t\targs == null ? args : args.concat(ref)\n\t);\n}\n\n/**\n * @param {() => any} factory\n * @param {any[]} args\n */\nexport function useMemo(factory, args) {\n\t/** @type {import('./internal').MemoHookState} */\n\tconst state = getHookState(currentIndex++, 7);\n\tif (argsChanged(state._args, args)) {\n\t\tstate._value = factory();\n\t\tstate._args = args;\n\t\tstate._factory = factory;\n\t}\n\n\treturn state._value;\n}\n\n/**\n * @param {() => void} callback\n * @param {any[]} args\n */\nexport function useCallback(callback, args) {\n\tcurrentHook = 8;\n\treturn useMemo(() => callback, args);\n}\n\n/**\n * @param {import('./internal').PreactContext} context\n */\nexport function useContext(context) {\n\tconst provider = currentComponent.context[context._id];\n\t// We could skip this call here, but than we'd not call\n\t// `options._hook`. We need to do that in order to make\n\t// the devtools aware of this hook.\n\t/** @type {import('./internal').ContextHookState} */\n\tconst state = getHookState(currentIndex++, 9);\n\t// The devtools needs access to the context object to\n\t// be able to pull of the default value when no provider\n\t// is present in the tree.\n\tstate._context = context;\n\tif (!provider) return context._defaultValue;\n\t// This is probably not safe to convert to \"!\"\n\tif (state._value == null) {\n\t\tstate._value = true;\n\t\tprovider.sub(currentComponent);\n\t}\n\treturn provider.props.value;\n}\n\n/**\n * Display a custom label for a custom hook for the devtools panel\n * @type {(value: T, cb?: (value: T) => string | number) => void}\n */\nexport function useDebugValue(value, formatter) {\n\tif (options.useDebugValue) {\n\t\toptions.useDebugValue(formatter ? formatter(value) : value);\n\t}\n}\n\n/**\n * @param {(error: any) => void} cb\n */\nexport function useErrorBoundary(cb) {\n\t/** @type {import('./internal').ErrorBoundaryHookState} */\n\tconst state = getHookState(currentIndex++, 10);\n\tconst errState = useState();\n\tstate._value = cb;\n\tif (!currentComponent.componentDidCatch) {\n\t\tcurrentComponent.componentDidCatch = err => {\n\t\t\tif (state._value) state._value(err);\n\t\t\terrState[1](err);\n\t\t};\n\t}\n\treturn [\n\t\terrState[0],\n\t\t() => {\n\t\t\terrState[1](undefined);\n\t\t}\n\t];\n}\n\n/**\n * After paint effects consumer.\n */\nfunction flushAfterPaintEffects() {\n\tafterPaintEffects.forEach(component => {\n\t\tif (~component._internal._flags & MODE_UNMOUNTING) {\n\t\t\ttry {\n\t\t\t\tcomponent.__hooks._pendingEffects.forEach(invokeCleanup);\n\t\t\t\tcomponent.__hooks._pendingEffects.forEach(invokeEffect);\n\t\t\t\tcomponent.__hooks._pendingEffects = [];\n\t\t\t} catch (e) {\n\t\t\t\tcomponent.__hooks._pendingEffects = [];\n\t\t\t\toptions._catchError(e, component._internal);\n\t\t\t}\n\t\t}\n\t});\n\tafterPaintEffects = [];\n}\n\nlet HAS_RAF = typeof requestAnimationFrame == 'function';\n\n/**\n * Schedule a callback to be invoked after the browser has a chance to paint a new frame.\n * Do this by combining requestAnimationFrame (rAF) + setTimeout to invoke a callback after\n * the next browser frame.\n *\n * Also, schedule a timeout in parallel to the the rAF to ensure the callback is invoked\n * even if RAF doesn't fire (for example if the browser tab is not visible)\n *\n * @param {() => void} callback\n */\nfunction afterNextFrame(callback) {\n\tconst done = () => {\n\t\tclearTimeout(timeout);\n\t\tif (HAS_RAF) cancelAnimationFrame(raf);\n\t\tsetTimeout(callback);\n\t};\n\tconst timeout = setTimeout(done, RAF_TIMEOUT);\n\n\tlet raf;\n\tif (HAS_RAF) {\n\t\traf = requestAnimationFrame(done);\n\t}\n}\n\n// Note: if someone used options.debounceRendering = requestAnimationFrame,\n// then effects will ALWAYS run on the NEXT frame instead of the current one, incurring a ~16ms delay.\n// Perhaps this is not such a big deal.\n/**\n * Schedule afterPaintEffects flush after the browser paints\n * @param {number} newQueueLength\n */\nfunction afterPaint(newQueueLength) {\n\tif (newQueueLength === 1 || prevRaf !== options.requestAnimationFrame) {\n\t\tprevRaf = options.requestAnimationFrame;\n\t\t(prevRaf || afterNextFrame)(flushAfterPaintEffects);\n\t}\n}\n\n/**\n * @param {import('./internal').EffectHookState} hook\n */\nfunction invokeCleanup(hook) {\n\t// A hook cleanup can introduce a call to render which creates a new root, this will call options.vnode\n\t// and move the currentComponent away.\n\tconst comp = currentComponent;\n\tif (typeof hook._cleanup == 'function') hook._cleanup();\n\tcurrentComponent = comp;\n}\n\n/**\n * Invoke a Hook's effect\n * @param {import('./internal').EffectHookState} hook\n */\nfunction invokeEffect(hook) {\n\t// A hook call can introduce a call to render which creates a new root, this will call options.vnode\n\t// and move the currentComponent away.\n\tconst comp = currentComponent;\n\thook._cleanup = hook._value();\n\tcurrentComponent = comp;\n}\n\n/**\n * @param {any[]} oldArgs\n * @param {any[]} newArgs\n */\nfunction argsChanged(oldArgs, newArgs) {\n\treturn (\n\t\t!oldArgs ||\n\t\toldArgs.length !== newArgs.length ||\n\t\tnewArgs.some((arg, index) => arg !== oldArgs[index])\n\t);\n}\n\nfunction invokeOrReturn(arg, f) {\n\treturn typeof f == 'function' ? f(arg) : f;\n}\n","// Internal._flags bitfield constants\nexport const TYPE_TEXT = 1 << 0;\nexport const TYPE_ELEMENT = 1 << 1;\nexport const TYPE_CLASS = 1 << 2;\nexport const TYPE_FUNCTION = 1 << 3;\n/** Signals this internal has a _parentDom prop that should change the parent\n * DOM node of it's children */\nexport const TYPE_ROOT = 1 << 4;\n\n/** Any type of internal representing DOM */\nexport const TYPE_DOM = TYPE_TEXT | TYPE_ELEMENT;\n/** Any type of component */\nexport const TYPE_COMPONENT = TYPE_CLASS | TYPE_FUNCTION | TYPE_ROOT;\n\n// Modes of rendering\n/** Normal hydration that attaches to a DOM tree but does not diff it. */\nexport const MODE_HYDRATE = 1 << 5;\n/** Top level render unspecified behaviour (old replaceNode parameter to render) */\nexport const MODE_MUTATIVE_HYDRATE = 1 << 6;\n/** Signifies this VNode suspended on the previous render */\nexport const MODE_SUSPENDED = 1 << 7;\n/** Signifies this VNode errored on the previous render */\nexport const MODE_ERRORED = 1 << 8;\n/** Signifies an error has been thrown and this component will be attempting to\n * handle & rerender the error on next render. In other words, on the next\n * render of this component, unset this mode and set the MODE_RERENDERING_ERROR.\n * This flag is distinct from MODE_RERENDERING_ERROR so that a component can\n * catch multiple errors thrown by its children in one render pass (see test\n * \"should handle double child throws\").\n */\nexport const MODE_PENDING_ERROR = 1 << 9;\n/** Signifies this Internal is attempting to \"handle\" an error and is\n * rerendering. This mode tracks that a component's last rerender was trying to\n * handle an error. As such, if another error is thrown while a component has\n * this flag set, it should not handle the newly thrown error since it failed to\n * successfully rerender the original error. This prevents error handling\n * infinite render loops */\nexport const MODE_RERENDERING_ERROR = 1 << 10;\n/** Signals this internal has been unmounted */\nexport const MODE_UNMOUNTING = 1 << 11;\n/** This Internal is rendered in an SVG tree */\nexport const MODE_SVG = 1 << 12;\n\n/** Signifies that bailout checks will be bypassed */\nexport const FORCE_UPDATE = 1 << 13;\n/** Signifies that a node needs to be updated */\nexport const DIRTY_BIT = 1 << 14;\n\n/** Reset all mode flags */\nexport const RESET_MODE = ~(\n\tMODE_HYDRATE |\n\tMODE_MUTATIVE_HYDRATE |\n\tMODE_SUSPENDED |\n\tMODE_ERRORED |\n\tMODE_RERENDERING_ERROR |\n\tFORCE_UPDATE\n);\n\n/** Modes a child internal inherits from their parent */\nexport const INHERITED_MODES = MODE_HYDRATE | MODE_MUTATIVE_HYDRATE | MODE_SVG;\n\nexport const EMPTY_ARR = [];\n\nexport const IS_NON_DIMENSIONAL = /acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;\n"],"names":["currentIndex","currentComponent","prevRaf","currentHook","afterPaintEffects","oldBeforeDiff","options","oldBeforeRender","oldAfterDiff","diffed","oldCommit","oldBeforeUnmount","unmount","getHookState","index","type","hooks","__","__h","length","push","useState","initialState","useReducer","invokeOrReturn","reducer","init","hookState","_reducer","undefined","action","nextValue","setState","useEffect","callback","args","state","argsChanged","useLayoutEffect","useRef","initialValue","useMemo","current","useImperativeHandle","ref","createHandle","concat","factory","useCallback","useContext","context","provider","sub","props","value","useDebugValue","formatter","useErrorBoundary","cb","errState","componentDidCatch","err","flushAfterPaintEffects","forEach","component","invokeCleanup","invokeEffect","e","internal","vnode","c","requestAnimationFrame","afterNextFrame","previousComponent","commitQueue","some","filter","i","HAS_RAF","done","clearTimeout","timeout","cancelAnimationFrame","raf","setTimeout","hook","comp","oldArgs","newArgs","arg","f"],"mappings":"iCAIA,IAAIA,EAGAC,EAsBAC,EAZAC,EAAc,EAGdC,EAAoB,GAEpBC,EAAgBC,MAChBC,EAAkBD,MAClBE,EAAeF,EAAQG,OACvBC,EAAYJ,MACZK,EAAmBL,EAAQM,QAwE/B,SAASC,EAAaC,EAAOC,GACxBT,OACHA,MAAcL,EAAkBa,EAAOX,GAAeY,GAEvDZ,EAAc,EAOd,MAAMa,EACLf,QACCA,MAA2B,CAC3BgB,GAAO,GACPC,IAAiB,KAMnB,OAHIJ,GAASE,KAAYG,QACxBH,KAAYI,KAAK,IAEXJ,KAAYF,YAMJO,EAASC,GAExB,OADAnB,EAAc,EACPoB,EAAWC,EAAgBF,YASnBC,EAAWE,EAASH,EAAcI,GAEjD,MAAMC,EAAYd,EAAab,IAAgB,GAkB/C,OAjBA2B,EAAUC,EAAWH,EAChBE,QACJA,KAAmB,CACjBD,EAAiDA,EAAKJ,GAA/CE,OAAeK,EAAWP,GAElCQ,IACC,MAAMC,EAAYJ,EAAUC,EAASD,KAAiB,GAAIG,GACtDH,KAAiB,KAAOI,IAC3BJ,KAAmB,CAACI,EAAWJ,KAAiB,IAChDA,MAAqBK,SAAS,OAKjCL,MAAuB1B,GAGjB0B,cAOQM,EAAUC,EAAUC,GAEnC,MAAMC,EAAQvB,EAAab,IAAgB,IACtCM,OAAwB+B,EAAYD,MAAaD,KACrDC,KAAeF,EACfE,MAAcD,EAEdlC,UAAyCmB,KAAKgB,aAQhCE,EAAgBJ,EAAUC,GAEzC,MAAMC,EAAQvB,EAAab,IAAgB,IACtCM,OAAwB+B,EAAYD,MAAaD,KACrDC,KAAeF,EACfE,MAAcD,EAEqC,MAA/ClC,YACHA,UAA8C,IAE/CA,UAA4CmB,KAAKgB,aAInCG,EAAOC,GAEtB,OADArC,EAAc,EACPsC,EAAQ,MAASC,QAASF,IAAiB,aAQnCG,EAAoBC,EAAKC,EAAcV,GACtDhC,EAAc,EACdmC,EACC,KACmB,mBAAPM,EAAmBA,EAAIC,KACzBD,IAAKA,EAAIF,QAAUG,MAErB,MAARV,EAAeA,EAAOA,EAAKW,OAAOF,aAQpBH,EAAQM,EAASZ,GAEhC,MAAMC,EAAQvB,EAAab,IAAgB,GAO3C,OANIqC,EAAYD,MAAaD,KAC5BC,KAAeW,IACfX,MAAcD,EACdC,MAAiBW,GAGXX,cAOQY,EAAYd,EAAUC,GAErC,OADAhC,EAAc,EACPsC,EAAQ,IAAMP,EAAUC,YAMhBc,EAAWC,GAC1B,MAAMC,EAAWlD,EAAiBiD,QAAQA,OAKpCd,EAAQvB,EAAab,IAAgB,GAK3C,OADAoC,MAAiBc,EACZC,GAEe,MAAhBf,OACHA,MAAe,EACfe,EAASC,IAAInD,IAEPkD,EAASE,MAAMC,OANAJ,cAaPK,EAAcD,EAAOE,GAChClD,EAAQiD,eACXjD,EAAQiD,cAAcC,EAAYA,EAAUF,GAASA,YAOvCG,EAAiBC,GAEhC,MAAMtB,EAAQvB,EAAab,IAAgB,IACrC2D,EAAWtC,IAQjB,OAPAe,KAAesB,EACVzD,EAAiB2D,oBACrB3D,EAAiB2D,kBAAoBC,IAChCzB,MAAcA,KAAayB,GAC/BF,EAAS,GAAGE,KAGP,CACNF,EAAS,GACT,KACCA,EAAS,QAAG9B,KAQf,SAASiC,IACR1D,EAAkB2D,QAAQC,IACzB,GCnQ6B,MDmQxBA,UACJ,IACCA,UAAkCD,QAAQE,GAC1CD,UAAkCD,QAAQG,GAC1CF,UAAoC,GACnC,MAAOG,GACRH,UAAoC,GACpC1D,MAAoB6D,EAAGH,UAI1B5D,EAAoB,GAtRrBE,MAAgB,CAAC8D,EAAUC,KAC1BpE,EAAmB,KACfI,GAAeA,EAAc+D,EAAUC,IAG5C/D,MAAkB8D,IACb7D,GAAiBA,EAAgB6D,GAErCnE,EAAmBmE,MACnBpE,EAAe,EAEf,MAAMgB,EAAQf,MACVe,IACHA,MAAsB+C,QAAQE,GAC9BjD,MAAsB+C,QAAQG,GAC9BlD,MAAwB,KAI1BV,EAAQG,OAAS2D,IACZ5D,GAAcA,EAAa4D,GAE/B,MAAME,EAAIF,MACNE,GAAKA,OAAaA,UAA0BnD,SAoSzB,IAnSXf,EAAkBgB,KAAKkD,IAmSPpE,IAAYI,EAAQiE,wBAC/CrE,EAAUI,EAAQiE,uBACjBrE,GAAWsE,GAAgBV,KAnS7B7D,OA3CGwE,GA8CJnE,MAAkB,CAAC8D,EAAUM,KAC5BA,EAAYC,KAAKP,IAChB,IACCA,MAA0BL,QAAQE,GAClCG,MAA4BA,MAA0BQ,OAAOlB,IAC5DA,MAAYQ,EAAaR,IAEzB,MAAOS,GACRO,EAAYC,KAAKE,IACZA,QAAoBA,MAAqB,MAE9CH,EAAc,GACdpE,MAAoB6D,EAAGC,MAIrB1D,GAAWA,EAAU0D,EAAUM,IAGpCpE,EAAQM,QAAUwD,IACbzD,GAAkBA,EAAiByD,GAEvC,MAAME,EAAIF,MACV,GAAIE,GAAKA,MACR,IACCA,SAAgBP,QAAQE,GACvB,MAAOE,GACR7D,MAAoB6D,EAAGG,SAiO1B,IAAIQ,EAA0C,mBAAzBP,sBAYrB,SAASC,EAAetC,GACvB,MAAM6C,EAAO,KACZC,aAAaC,GACTH,GAASI,qBAAqBC,GAClCC,WAAWlD,IAEN+C,EAAUG,WAAWL,EA9SR,KAgTnB,IAAII,EACAL,IACHK,EAAMZ,sBAAsBQ,IAqB9B,SAASd,EAAcoB,GAGtB,MAAMC,EAAOrF,EACe,mBAAjBoF,OAA6BA,QACxCpF,EAAmBqF,EAOpB,SAASpB,EAAamB,GAGrB,MAAMC,EAAOrF,EACboF,MAAgBA,OAChBpF,EAAmBqF,EAOpB,SAASjD,EAAYkD,EAASC,GAC7B,OACED,GACDA,EAAQpE,SAAWqE,EAAQrE,QAC3BqE,EAAQb,KAAK,CAACc,EAAK3E,IAAU2E,IAAQF,EAAQzE,IAI/C,SAASU,EAAeiE,EAAKC,GAC5B,MAAmB,mBAALA,EAAkBA,EAAED,GAAOC"}