├── hooks_works_internally.md
├── simulate_life_cycle.md
├── fiber.md
├── Readme.md
├── scopes.md
└── react.js
/hooks_works_internally.md:
--------------------------------------------------------------------------------
1 | # Steps
2 |
3 | On render phase
4 |
5 | - Before render start,
6 | - set a global variable pointing to the current dispatcher (for simplicity consider global variable to points to component instance).
7 | - create a list to store hooks state (if not present already) on the component instance.
8 | - create/reset a current pointer to point to specific hook in the list.
9 | - On render call for every hook
10 | - if there is item in the hook list for the current pointer return that.
11 | - else create a hooks state object, based on type of hook and add the state object to the list.
12 | - if it is effect hook add the effect on effect list on that fiber along with the previous cleanup callback. _11594_
13 | - increment the current pointer for the next hook.
14 | - return the value from the hook (based on the type of hook).
15 |
16 | On commit phase
17 |
18 | - Before commit call all the cleanup effect callback.
19 | - After commit call the effect callback.
20 |
--------------------------------------------------------------------------------
/simulate_life_cycle.md:
--------------------------------------------------------------------------------
1 | ### constructor
2 |
3 | ```js
4 | function MyApp() => {
5 | const [state, setState] = useState(() => {
6 | // do one time heavy computation here, which will be done on first render
7 | })
8 |
9 | const someValue = useMemo(() => {
10 | // do things you want to do one time which will be done on first render
11 | }, [])
12 | }
13 | ```
14 |
15 | ### getDerivedStateFromProps
16 |
17 | ```js
18 | function MyApp(props) {
19 | const [factor, setFactor] = useState(1);
20 |
21 | useMemo(() => {
22 | setFactor(props.value);
23 | }, [props.value]);
24 | }
25 | ```
26 |
27 | ### componentDidMount
28 |
29 | ```js
30 | function MyApp(props) {
31 | const [factor, setFactor] = useState(1);
32 |
33 | useEffect(() => {
34 | // do something similar to mount
35 | }, []);
36 | }
37 | ```
38 |
39 | ### componentWillUnMount
40 |
41 | ```js
42 | function MyApp(props) {
43 | const [factor, setFactor] = useState(1);
44 |
45 | useEffect(() => {
46 | return () => {
47 | // do something similar to mount
48 | };
49 | }, []);
50 | }
51 | ```
52 |
--------------------------------------------------------------------------------
/fiber.md:
--------------------------------------------------------------------------------
1 | You write in JSX.
2 |
3 | ```jsx
4 |
8 | ```
9 |
10 | JSX is transformed to create element syntax
11 |
12 | ```js
13 | React.createElement(
14 | "div",
15 | { className: "my-app" },
16 | React.createElement("h1", {}, "My App"),
17 | React.createElement(App, {})
18 | );
19 | ```
20 |
21 | Create element returns react elements
22 |
23 | ```js
24 | {
25 | type: 'div',
26 | props: {
27 | className: 'my-app',
28 | children: [{
29 | type: 'h1',
30 | props: {
31 | children: 'My App'
32 | }
33 | }, {
34 | type: App,
35 | props: {}
36 | }]
37 | }
38 | }
39 | ```
40 |
41 | A fiber node is created for each of the React Element
42 |
43 | ```js
44 | // div fiber
45 | {
46 | type: 'div',
47 | stateNode: HTMLElement,
48 | child: H1Fiber
49 | }
50 |
51 | // h1 fiber
52 | {
53 | type: 'h1',
54 | stateNode: HTMLElement
,
55 | parent: DivFiber,
56 | child: TextFiber,
57 | sibling: AppFiber
58 | }
59 |
60 | // App fiber
61 | {
62 | type: App,
63 | stateNode: AppInstance, // new App
64 | parent: DivFiber,
65 | }
66 | ```
67 |
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | ## Agenda
2 |
3 | - What are hooks in React?
4 | - Rules of hooks.
5 | - What are the different React hooks and their usage?
6 | - JSX -> VDOM -> Fiber.
7 | - Different phases of rendering.
8 | - How hooks work internally.
9 | - Different parts of React which allow hooks to work.
10 | - Internal implementation of core hooks.
11 | - Why does the dependency array in hooks matter and how does it work?
12 | - Effect of scope in hooks.
13 | - Simulating life cycle methods with hooks.
14 |
15 | ### Resources:
16 |
17 | Rules of Hooks
18 | [https://reactjs.org/docs/hooks-rules.html](https://reactjs.org/docs/hooks-rules.html)
19 |
20 | Scopes and hooks (Making SetInternval declarative with React Hooks)
21 | [https://overreacted.io/making-setinterval-declarative-with-react-hooks/](https://overreacted.io/making-setinterval-declarative-with-react-hooks/)
22 |
23 | A Cartoon Intro to Fiber
24 | [https://www.youtube.com/watch?v=ZCuYPiUIONs](https://www.youtube.com/watch?v=ZCuYPiUIONs)
25 |
26 | Internals meetup recording on Fiber Architecture
27 | [https://www.youtube.com/watch?v=xZMwnZjvZa0](https://www.youtube.com/watch?v=xZMwnZjvZa0)
28 |
29 | React hooks is nothing but an array:
30 | [https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e](https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e)
31 |
32 | Implementation of hooks
33 | [https://www.youtube.com/watch?v=KJP1E-Y-xyo&t=904s](https://www.youtube.com/watch?v=KJP1E-Y-xyo&t=904s)
34 |
35 | Hooks performance Issue
36 | [https://github.com/ryardley/hooks-perf-issues](https://github.com/ryardley/hooks-perf-issues)
37 |
38 | React Specific resources
39 | [https://reactresources.com](https://reactresources.com)
40 |
--------------------------------------------------------------------------------
/scopes.md:
--------------------------------------------------------------------------------
1 | ### Basic scope example
2 |
3 | ```js
4 | function ageTeller(name) {
5 | return function (age) {
6 | return `The age of ${name} is ${age}.`;
7 | };
8 | }
9 |
10 | const sudhanshu = ageTeller("Sudhanshu");
11 |
12 | sudhanshu(29); // The age of Sudhanshu is 29.
13 |
14 | sudhanshu(30); // The age of Sudhanshu is 30.
15 | ```
16 |
17 | ### React functional component
18 |
19 | #### Scope example
20 |
21 | ```js
22 | function MyComponent(props) {
23 | const [value, setValue] = useState("initial");
24 |
25 | useEffect(() => {
26 | document.title = value;
27 | });
28 |
29 | return Something
;
30 | }
31 | ```
32 |
33 | #### Callback example
34 |
35 | ```js ❌
36 | function MyComponent(props) {
37 | const [value, setValue] = useState("initial");
38 |
39 | const onClick = useCallback(() => {
40 | setValue(value + "--");
41 | }, []);
42 |
43 | return ;
44 | }
45 | ```
46 |
47 | ```js ✅
48 | function MyComponent(props) {
49 | const [value, setValue] = useState("initial");
50 |
51 | const onClick = useCallback(() => {
52 | setValue(value + "--");
53 | }, [value]);
54 |
55 | return ;
56 | }
57 | ```
58 |
59 | ```js ✅
60 | function MyComponent(props) {
61 | const [value, setValue] = useState("initial");
62 |
63 | const onClick = useCallback(() => {
64 | setValue((value) => {
65 | return value + "--";
66 | });
67 | }, []);
68 |
69 | return ;
70 | }
71 | ```
72 |
73 | #### Fetch example
74 |
75 | ```js ❌
76 | function MyComponent(props) {
77 | const [factor, setFactor] = useState(1);
78 | const [chartData, setChartData] = useState();
79 |
80 | useEffect(() => {
81 | fetch('chart data').then((list) => {
82 | const factoredList = list.map((list) => list * factor);
83 | setChartData(factoredList);
84 | })
85 | }, []);
86 |
87 |
88 | return (
89 | <>
90 | setFactor(Number(e.target.value))} />
91 |
92 | <>
93 | )
94 | }
95 | ```
96 |
97 | ```js ✅
98 | function MyComponent(props) {
99 | const [factor, setFactor] = useState(1);
100 | const [apiData, setApiData] = useState();
101 |
102 | useEffect(() => {
103 | fetch('chart data').then((list) => {
104 | setChartData(list);
105 | })
106 | }, []);
107 |
108 |
109 | const chartData = apiData.map((item) => item * factor);
110 |
111 | //OR
112 |
113 | const chartData = useMemo(() => {
114 | return apiData.map((item) => item * factor)
115 | }, [apiData, factor])
116 |
117 | return (
118 | <>
119 | setFactor(Number(e.target.value))} />
120 |
121 | <>
122 | )
123 | }
124 | ```
125 |
126 | #### setInterval example
127 |
128 | ```js ❌
129 | import React, { useState, useEffect, useRef } from "react";
130 |
131 | function Counter() {
132 | const [count, setCount] = useState(0);
133 | const [delay, setDelay] = useState(1000);
134 |
135 | useEffect(() => {
136 | setInterval(() => {
137 | setCount(count + 1);
138 | }, delay);
139 | });
140 |
141 | return (
142 | <>
143 | setDelay(e.target.value)}
147 | />
148 | {count} ;
149 | >
150 | );
151 | }
152 | ```
153 |
154 | Correct approach
155 | [https://overreacted.io/making-setinterval-declarative-with-react-hooks/](https://overreacted.io/making-setinterval-declarative-with-react-hooks/)
156 |
--------------------------------------------------------------------------------
/react.js:
--------------------------------------------------------------------------------
1 | /** @license React vundefined
2 | * react.production.min.js
3 | *
4 | * Copyright (c) Facebook, Inc. and its affiliates.
5 | *
6 | * This source code is licensed under the MIT license found in the
7 | * LICENSE file in the root directory of this source tree.
8 | */
9 | (function (global, factory) {
10 | typeof exports === "object" && typeof module !== "undefined"
11 | ? factory(exports)
12 | : typeof define === "function" && define.amd
13 | ? define(["exports"], factory)
14 | : ((global = global || self), factory((global.React = {})));
15 | })(this, function (exports) {
16 | "use strict";
17 |
18 | // TODO: this is special because it gets imported during build.
19 | var ReactVersion = "16.13.1";
20 |
21 | // The Symbol used to tag the ReactElement-like types. If there is no native Symbol
22 | // nor polyfill, then a plain number is used for performance.
23 | let REACT_ELEMENT_TYPE = 0xeac7;
24 | let REACT_PORTAL_TYPE = 0xeaca;
25 | exports.Fragment = 0xeacb;
26 | exports.StrictMode = 0xeacc;
27 | exports.Profiler = 0xead2;
28 | let REACT_PROVIDER_TYPE = 0xeacd;
29 | let REACT_CONTEXT_TYPE = 0xeace;
30 | let REACT_FORWARD_REF_TYPE = 0xead0;
31 | exports.Suspense = 0xead1;
32 | exports.SuspenseList = 0xead8;
33 | let REACT_MEMO_TYPE = 0xead3;
34 | let REACT_LAZY_TYPE = 0xead4;
35 | let REACT_BLOCK_TYPE = 0xead9;
36 |
37 | if (typeof Symbol === "function" && Symbol.for) {
38 | const symbolFor = Symbol.for;
39 | REACT_ELEMENT_TYPE = symbolFor("react.element");
40 | REACT_PORTAL_TYPE = symbolFor("react.portal");
41 | exports.Fragment = symbolFor("react.fragment");
42 | exports.StrictMode = symbolFor("react.strict_mode");
43 | exports.Profiler = symbolFor("react.profiler");
44 | REACT_PROVIDER_TYPE = symbolFor("react.provider");
45 | REACT_CONTEXT_TYPE = symbolFor("react.context");
46 | REACT_FORWARD_REF_TYPE = symbolFor("react.forward_ref");
47 | exports.Suspense = symbolFor("react.suspense");
48 | exports.SuspenseList = symbolFor("react.suspense_list");
49 | REACT_MEMO_TYPE = symbolFor("react.memo");
50 | REACT_LAZY_TYPE = symbolFor("react.lazy");
51 | REACT_BLOCK_TYPE = symbolFor("react.block");
52 | }
53 |
54 | const MAYBE_ITERATOR_SYMBOL = typeof Symbol === "function" && Symbol.iterator;
55 | const FAUX_ITERATOR_SYMBOL = "@@iterator";
56 | function getIteratorFn(maybeIterable) {
57 | if (maybeIterable === null || typeof maybeIterable !== "object") {
58 | return null;
59 | }
60 |
61 | const maybeIterator =
62 | (MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL]) ||
63 | maybeIterable[FAUX_ITERATOR_SYMBOL];
64 |
65 | if (typeof maybeIterator === "function") {
66 | return maybeIterator;
67 | }
68 |
69 | return null;
70 | }
71 |
72 | const hasOwnProperty = Object.prototype.hasOwnProperty;
73 |
74 | const _assign = function (to, from) {
75 | for (const key in from) {
76 | if (hasOwnProperty.call(from, key)) {
77 | to[key] = from[key];
78 | }
79 | }
80 | };
81 |
82 | var _assign$1 =
83 | Object.assign ||
84 | function (target, sources) {
85 | if (target == null) {
86 | throw new TypeError("Object.assign target cannot be null or undefined");
87 | }
88 |
89 | const to = Object(target);
90 |
91 | for (let nextIndex = 1; nextIndex < arguments.length; nextIndex++) {
92 | const nextSource = arguments[nextIndex];
93 |
94 | if (nextSource != null) {
95 | _assign(to, Object(nextSource));
96 | }
97 | }
98 |
99 | return to;
100 | };
101 |
102 | // Do not require this module directly! Use normal `invariant` calls with
103 | // template literal strings. The messages will be replaced with error codes
104 | // during build.
105 | function formatProdErrorMessage(code) {
106 | let url = "https://reactjs.org/docs/error-decoder.html?invariant=" + code;
107 |
108 | for (let i = 1; i < arguments.length; i++) {
109 | url += "&args[]=" + encodeURIComponent(arguments[i]);
110 | }
111 |
112 | return (
113 | "Minified React error #" +
114 | code +
115 | "; visit " +
116 | url +
117 | " for the full message or " +
118 | "use the non-minified dev environment for full errors and additional " +
119 | "helpful warnings."
120 | );
121 | }
122 |
123 | /**
124 | * This is the abstract API for an update queue.
125 | */
126 |
127 | const ReactNoopUpdateQueue = {
128 | /**
129 | * Checks whether or not this composite component is mounted.
130 | * @param {ReactClass} publicInstance The instance we want to test.
131 | * @return {boolean} True if mounted, false otherwise.
132 | * @protected
133 | * @final
134 | */
135 | isMounted: function (publicInstance) {
136 | return false;
137 | },
138 |
139 | /**
140 | * Forces an update. This should only be invoked when it is known with
141 | * certainty that we are **not** in a DOM transaction.
142 | *
143 | * You may want to call this when you know that some deeper aspect of the
144 | * component's state has changed but `setState` was not called.
145 | *
146 | * This will not invoke `shouldComponentUpdate`, but it will invoke
147 | * `componentWillUpdate` and `componentDidUpdate`.
148 | *
149 | * @param {ReactClass} publicInstance The instance that should rerender.
150 | * @param {?function} callback Called after component is updated.
151 | * @param {?string} callerName name of the calling function in the public API.
152 | * @internal
153 | */
154 | enqueueForceUpdate: function (publicInstance, callback, callerName) {},
155 |
156 | /**
157 | * Replaces all of the state. Always use this or `setState` to mutate state.
158 | * You should treat `this.state` as immutable.
159 | *
160 | * There is no guarantee that `this.state` will be immediately updated, so
161 | * accessing `this.state` after calling this method may return the old value.
162 | *
163 | * @param {ReactClass} publicInstance The instance that should rerender.
164 | * @param {object} completeState Next state.
165 | * @param {?function} callback Called after component is updated.
166 | * @param {?string} callerName name of the calling function in the public API.
167 | * @internal
168 | */
169 | enqueueReplaceState: function (
170 | publicInstance,
171 | completeState,
172 | callback,
173 | callerName
174 | ) {},
175 |
176 | /**
177 | * Sets a subset of the state. This only exists because _pendingState is
178 | * internal. This provides a merging strategy that is not available to deep
179 | * properties which is confusing. TODO: Expose pendingState or don't use it
180 | * during the merge.
181 | *
182 | * @param {ReactClass} publicInstance The instance that should rerender.
183 | * @param {object} partialState Next partial state to be merged with state.
184 | * @param {?function} callback Called after component is updated.
185 | * @param {?string} Name of the calling function in the public API.
186 | * @internal
187 | */
188 | enqueueSetState: function (
189 | publicInstance,
190 | partialState,
191 | callback,
192 | callerName
193 | ) {},
194 | };
195 |
196 | const emptyObject = {};
197 | /**
198 | * Base class helpers for the updating state of a component.
199 | */
200 |
201 | function Component(props, context, updater) {
202 | this.props = props;
203 | this.context = context; // If a component has string refs, we will assign a different object later.
204 |
205 | this.refs = emptyObject; // We initialize the default updater but the real one gets injected by the
206 | // renderer.
207 |
208 | this.updater = updater || ReactNoopUpdateQueue;
209 | }
210 |
211 | Component.prototype.isReactComponent = {};
212 | /**
213 | * Sets a subset of the state. Always use this to mutate
214 | * state. You should treat `this.state` as immutable.
215 | *
216 | * There is no guarantee that `this.state` will be immediately updated, so
217 | * accessing `this.state` after calling this method may return the old value.
218 | *
219 | * There is no guarantee that calls to `setState` will run synchronously,
220 | * as they may eventually be batched together. You can provide an optional
221 | * callback that will be executed when the call to setState is actually
222 | * completed.
223 | *
224 | * When a function is provided to setState, it will be called at some point in
225 | * the future (not synchronously). It will be called with the up to date
226 | * component arguments (state, props, context). These values can be different
227 | * from this.* because your function may be called after receiveProps but before
228 | * shouldComponentUpdate, and this new state, props, and context will not yet be
229 | * assigned to this.
230 | *
231 | * @param {object|function} partialState Next partial state or function to
232 | * produce next partial state to be merged with current state.
233 | * @param {?function} callback Called after state is updated.
234 | * @final
235 | * @protected
236 | */
237 |
238 | Component.prototype.setState = function (partialState, callback) {
239 | if (
240 | !(
241 | typeof partialState === "object" ||
242 | typeof partialState === "function" ||
243 | partialState == null
244 | )
245 | ) {
246 | {
247 | throw Error(formatProdErrorMessage(85));
248 | }
249 | }
250 |
251 | this.updater.enqueueSetState(this, partialState, callback, "setState");
252 | };
253 | /**
254 | * Forces an update. This should only be invoked when it is known with
255 | * certainty that we are **not** in a DOM transaction.
256 | *
257 | * You may want to call this when you know that some deeper aspect of the
258 | * component's state has changed but `setState` was not called.
259 | *
260 | * This will not invoke `shouldComponentUpdate`, but it will invoke
261 | * `componentWillUpdate` and `componentDidUpdate`.
262 | *
263 | * @param {?function} callback Called after update is complete.
264 | * @final
265 | * @protected
266 | */
267 |
268 | Component.prototype.forceUpdate = function (callback) {
269 | this.updater.enqueueForceUpdate(this, callback, "forceUpdate");
270 | };
271 |
272 | function ComponentDummy() {}
273 |
274 | ComponentDummy.prototype = Component.prototype;
275 | /**
276 | * Convenience component with default shallow equality check for sCU.
277 | */
278 |
279 | function PureComponent(props, context, updater) {
280 | this.props = props;
281 | this.context = context; // If a component has string refs, we will assign a different object later.
282 |
283 | this.refs = emptyObject;
284 | this.updater = updater || ReactNoopUpdateQueue;
285 | }
286 |
287 | const pureComponentPrototype = (PureComponent.prototype = new ComponentDummy());
288 | pureComponentPrototype.constructor = PureComponent; // Avoid an extra prototype jump for these methods.
289 |
290 | _assign$1(pureComponentPrototype, Component.prototype);
291 |
292 | pureComponentPrototype.isPureReactComponent = true;
293 |
294 | // an immutable object with a single mutable value
295 | function createRef() {
296 | const refObject = {
297 | current: null,
298 | };
299 |
300 | return refObject;
301 | }
302 |
303 | /**
304 | * Keeps track of the current owner.
305 | *
306 | * The current owner is the component who should own any components that are
307 | * currently being constructed.
308 | */
309 | const ReactCurrentOwner = {
310 | /**
311 | * @internal
312 | * @type {ReactComponent}
313 | */
314 | current: null,
315 | };
316 |
317 | const hasOwnProperty$1 = Object.prototype.hasOwnProperty;
318 | const RESERVED_PROPS = {
319 | key: true,
320 | ref: true,
321 | __self: true,
322 | __source: true,
323 | };
324 |
325 | function hasValidRef(config) {
326 | return config.ref !== undefined;
327 | }
328 |
329 | function hasValidKey(config) {
330 | return config.key !== undefined;
331 | }
332 | /**
333 | * Factory method to create a new React element. This no longer adheres to
334 | * the class pattern, so do not use new to call it. Also, instanceof check
335 | * will not work. Instead test $$typeof field against Symbol.for('react.element') to check
336 | * if something is a React Element.
337 | *
338 | * @param {*} type
339 | * @param {*} props
340 | * @param {*} key
341 | * @param {string|object} ref
342 | * @param {*} owner
343 | * @param {*} self A *temporary* helper to detect places where `this` is
344 | * different from the `owner` when React.createElement is called, so that we
345 | * can warn. We want to get rid of owner and replace string `ref`s with arrow
346 | * functions, and as long as `this` and owner are the same, there will be no
347 | * change in behavior.
348 | * @param {*} source An annotation object (added by a transpiler or otherwise)
349 | * indicating filename, line number, and/or other information.
350 | * @internal
351 | */
352 |
353 | const ReactElement = function (type, key, ref, self, source, owner, props) {
354 | const element = {
355 | // This tag allows us to uniquely identify this as a React Element
356 | $$typeof: REACT_ELEMENT_TYPE,
357 | // Built-in properties that belong on the element
358 | type: type,
359 | key: key,
360 | ref: ref,
361 | props: props,
362 | // Record the component responsible for creating this element.
363 | _owner: owner,
364 | };
365 |
366 | return element;
367 | };
368 | /**
369 | * Create and return a new ReactElement of the given type.
370 | * See https://reactjs.org/docs/react-api.html#createelement
371 | */
372 |
373 | function createElement(type, config, children) {
374 | let propName; // Reserved names are extracted
375 |
376 | const props = {};
377 | let key = null;
378 | let ref = null;
379 | let self = null;
380 | let source = null;
381 |
382 | if (config != null) {
383 | if (hasValidRef(config)) {
384 | ref = config.ref;
385 | }
386 |
387 | if (hasValidKey(config)) {
388 | key = "" + config.key;
389 | }
390 |
391 | self = config.__self === undefined ? null : config.__self;
392 | source = config.__source === undefined ? null : config.__source; // Remaining properties are added to a new props object
393 |
394 | for (propName in config) {
395 | if (
396 | hasOwnProperty$1.call(config, propName) &&
397 | !RESERVED_PROPS.hasOwnProperty(propName)
398 | ) {
399 | props[propName] = config[propName];
400 | }
401 | }
402 | } // Children can be more than one argument, and those are transferred onto
403 | // the newly allocated props object.
404 |
405 | const childrenLength = arguments.length - 2;
406 |
407 | if (childrenLength === 1) {
408 | props.children = children;
409 | } else if (childrenLength > 1) {
410 | const childArray = Array(childrenLength);
411 |
412 | for (let i = 0; i < childrenLength; i++) {
413 | childArray[i] = arguments[i + 2];
414 | }
415 |
416 | props.children = childArray;
417 | } // Resolve default props
418 |
419 | if (type && type.defaultProps) {
420 | const defaultProps = type.defaultProps;
421 |
422 | for (propName in defaultProps) {
423 | if (props[propName] === undefined) {
424 | props[propName] = defaultProps[propName];
425 | }
426 | }
427 | }
428 |
429 | return ReactElement(
430 | type,
431 | key,
432 | ref,
433 | self,
434 | source,
435 | ReactCurrentOwner.current,
436 | props
437 | );
438 | }
439 | /**
440 | * Return a function that produces ReactElements of a given type.
441 | * See https://reactjs.org/docs/react-api.html#createfactory
442 | */
443 |
444 | function createFactory(type) {
445 | const factory = createElement.bind(null, type); // Expose the type on the factory and the prototype so that it can be
446 | // easily accessed on elements. E.g. ` .type === Foo`.
447 | // This should not be named `constructor` since this may not be the function
448 | // that created the element, and it may not even be a constructor.
449 | // Legacy hook: remove it
450 |
451 | factory.type = type;
452 | return factory;
453 | }
454 | function cloneAndReplaceKey(oldElement, newKey) {
455 | const newElement = ReactElement(
456 | oldElement.type,
457 | newKey,
458 | oldElement.ref,
459 | oldElement._self,
460 | oldElement._source,
461 | oldElement._owner,
462 | oldElement.props
463 | );
464 | return newElement;
465 | }
466 | /**
467 | * Clone and return a new ReactElement using element as the starting point.
468 | * See https://reactjs.org/docs/react-api.html#cloneelement
469 | */
470 |
471 | function cloneElement(element, config, children) {
472 | if (!!(element === null || element === undefined)) {
473 | {
474 | throw Error(formatProdErrorMessage(267, element));
475 | }
476 | }
477 |
478 | let propName; // Original props are copied
479 |
480 | const props = _assign$1({}, element.props); // Reserved names are extracted
481 |
482 | let key = element.key;
483 | let ref = element.ref; // Self is preserved since the owner is preserved.
484 |
485 | const self = element._self; // Source is preserved since cloneElement is unlikely to be targeted by a
486 | // transpiler, and the original source is probably a better indicator of the
487 | // true owner.
488 |
489 | const source = element._source; // Owner will be preserved, unless ref is overridden
490 |
491 | let owner = element._owner;
492 |
493 | if (config != null) {
494 | if (hasValidRef(config)) {
495 | // Silently steal the ref from the parent.
496 | ref = config.ref;
497 | owner = ReactCurrentOwner.current;
498 | }
499 |
500 | if (hasValidKey(config)) {
501 | key = "" + config.key;
502 | } // Remaining properties override existing props
503 |
504 | let defaultProps;
505 |
506 | if (element.type && element.type.defaultProps) {
507 | defaultProps = element.type.defaultProps;
508 | }
509 |
510 | for (propName in config) {
511 | if (
512 | hasOwnProperty$1.call(config, propName) &&
513 | !RESERVED_PROPS.hasOwnProperty(propName)
514 | ) {
515 | if (config[propName] === undefined && defaultProps !== undefined) {
516 | // Resolve default props
517 | props[propName] = defaultProps[propName];
518 | } else {
519 | props[propName] = config[propName];
520 | }
521 | }
522 | }
523 | } // Children can be more than one argument, and those are transferred onto
524 | // the newly allocated props object.
525 |
526 | const childrenLength = arguments.length - 2;
527 |
528 | if (childrenLength === 1) {
529 | props.children = children;
530 | } else if (childrenLength > 1) {
531 | const childArray = Array(childrenLength);
532 |
533 | for (let i = 0; i < childrenLength; i++) {
534 | childArray[i] = arguments[i + 2];
535 | }
536 |
537 | props.children = childArray;
538 | }
539 |
540 | return ReactElement(element.type, key, ref, self, source, owner, props);
541 | }
542 | /**
543 | * Verifies the object is a ReactElement.
544 | * See https://reactjs.org/docs/react-api.html#isvalidelement
545 | * @param {?object} object
546 | * @return {boolean} True if `object` is a ReactElement.
547 | * @final
548 | */
549 |
550 | function isValidElement(object) {
551 | return (
552 | typeof object === "object" &&
553 | object !== null &&
554 | object.$$typeof === REACT_ELEMENT_TYPE
555 | );
556 | }
557 |
558 | const SEPARATOR = ".";
559 | const SUBSEPARATOR = ":";
560 | /**
561 | * Escape and wrap key so it is safe to use as a reactid
562 | *
563 | * @param {string} key to be escaped.
564 | * @return {string} the escaped key.
565 | */
566 |
567 | function escape(key) {
568 | const escapeRegex = /[=:]/g;
569 | const escaperLookup = {
570 | "=": "=0",
571 | ":": "=2",
572 | };
573 | const escapedString = key.replace(escapeRegex, function (match) {
574 | return escaperLookup[match];
575 | });
576 | return "$" + escapedString;
577 | }
578 | const userProvidedKeyEscapeRegex = /\/+/g;
579 |
580 | function escapeUserProvidedKey(text) {
581 | return text.replace(userProvidedKeyEscapeRegex, "$&/");
582 | }
583 | /**
584 | * Generate a key string that identifies a element within a set.
585 | *
586 | * @param {*} element A element that could contain a manual key.
587 | * @param {number} index Index that is used if a manual key is not provided.
588 | * @return {string}
589 | */
590 |
591 | function getElementKey(element, index) {
592 | // Do some typechecking here since we call this blindly. We want to ensure
593 | // that we don't block potential future ES APIs.
594 | if (
595 | typeof element === "object" &&
596 | element !== null &&
597 | element.key != null
598 | ) {
599 | // Explicit key
600 | return escape("" + element.key);
601 | } // Implicit key determined by the index in the set
602 |
603 | return index.toString(36);
604 | }
605 |
606 | function mapIntoArray(children, array, escapedPrefix, nameSoFar, callback) {
607 | const type = typeof children;
608 |
609 | if (type === "undefined" || type === "boolean") {
610 | // All of the above are perceived as null.
611 | children = null;
612 | }
613 |
614 | let invokeCallback = false;
615 |
616 | if (children === null) {
617 | invokeCallback = true;
618 | } else {
619 | switch (type) {
620 | case "string":
621 | case "number":
622 | invokeCallback = true;
623 | break;
624 |
625 | case "object":
626 | switch (children.$$typeof) {
627 | case REACT_ELEMENT_TYPE:
628 | case REACT_PORTAL_TYPE:
629 | invokeCallback = true;
630 | }
631 | }
632 | }
633 |
634 | if (invokeCallback) {
635 | const child = children;
636 | let mappedChild = callback(child); // If it's the only child, treat the name as if it was wrapped in an array
637 | // so that it's consistent if the number of children grows:
638 |
639 | const childKey =
640 | nameSoFar === "" ? SEPARATOR + getElementKey(child, 0) : nameSoFar;
641 |
642 | if (Array.isArray(mappedChild)) {
643 | let escapedChildKey = "";
644 |
645 | if (childKey != null) {
646 | escapedChildKey = escapeUserProvidedKey(childKey) + "/";
647 | }
648 |
649 | mapIntoArray(mappedChild, array, escapedChildKey, "", (c) => c);
650 | } else if (mappedChild != null) {
651 | if (isValidElement(mappedChild)) {
652 | mappedChild = cloneAndReplaceKey(
653 | mappedChild, // Keep both the (mapped) and old keys if they differ, just as
654 | // traverseAllChildren used to do for objects as children
655 | escapedPrefix + // $FlowFixMe Flow incorrectly thinks React.Portal doesn't have a key
656 | (mappedChild.key && (!child || child.key !== mappedChild.key) // $FlowFixMe Flow incorrectly thinks existing element's key can be a number
657 | ? escapeUserProvidedKey("" + mappedChild.key) + "/"
658 | : "") +
659 | childKey
660 | );
661 | }
662 |
663 | array.push(mappedChild);
664 | }
665 |
666 | return 1;
667 | }
668 |
669 | let child;
670 | let nextName;
671 | let subtreeCount = 0; // Count of children found in the current subtree.
672 |
673 | const nextNamePrefix =
674 | nameSoFar === "" ? SEPARATOR : nameSoFar + SUBSEPARATOR;
675 |
676 | if (Array.isArray(children)) {
677 | for (let i = 0; i < children.length; i++) {
678 | child = children[i];
679 | nextName = nextNamePrefix + getElementKey(child, i);
680 | subtreeCount += mapIntoArray(
681 | child,
682 | array,
683 | escapedPrefix,
684 | nextName,
685 | callback
686 | );
687 | }
688 | } else {
689 | const iteratorFn = getIteratorFn(children);
690 |
691 | if (typeof iteratorFn === "function") {
692 | const iterableChildren = children;
693 |
694 | const iterator = iteratorFn.call(iterableChildren);
695 | let step;
696 | let ii = 0;
697 |
698 | while (!(step = iterator.next()).done) {
699 | child = step.value;
700 | nextName = nextNamePrefix + getElementKey(child, ii++);
701 | subtreeCount += mapIntoArray(
702 | child,
703 | array,
704 | escapedPrefix,
705 | nextName,
706 | callback
707 | );
708 | }
709 | } else if (type === "object") {
710 | let addendum = "";
711 |
712 | const childrenString = "" + children;
713 |
714 | {
715 | {
716 | throw Error(
717 | formatProdErrorMessage(
718 | 31,
719 | childrenString === "[object Object]"
720 | ? "object with keys {" +
721 | Object.keys(children).join(", ") +
722 | "}"
723 | : childrenString,
724 | addendum
725 | )
726 | );
727 | }
728 | }
729 | }
730 | }
731 |
732 | return subtreeCount;
733 | }
734 |
735 | /**
736 | * Maps children that are typically specified as `props.children`.
737 | *
738 | * See https://reactjs.org/docs/react-api.html#reactchildrenmap
739 | *
740 | * The provided mapFunction(child, key, index) will be called for each
741 | * leaf child.
742 | *
743 | * @param {?*} children Children tree container.
744 | * @param {function(*, int)} func The map function.
745 | * @param {*} context Context for mapFunction.
746 | * @return {object} Object containing the ordered map of results.
747 | */
748 | function mapChildren(children, func, context) {
749 | if (children == null) {
750 | return children;
751 | }
752 |
753 | const result = [];
754 | let count = 0;
755 | mapIntoArray(children, result, "", "", function (child) {
756 | return func.call(context, child, count++);
757 | });
758 | return result;
759 | }
760 | /**
761 | * Count the number of children that are typically specified as
762 | * `props.children`.
763 | *
764 | * See https://reactjs.org/docs/react-api.html#reactchildrencount
765 | *
766 | * @param {?*} children Children tree container.
767 | * @return {number} The number of children.
768 | */
769 |
770 | function countChildren(children) {
771 | let n = 0;
772 | mapChildren(children, () => {
773 | n++; // Don't return anything
774 | });
775 | return n;
776 | }
777 |
778 | /**
779 | * Iterates through children that are typically specified as `props.children`.
780 | *
781 | * See https://reactjs.org/docs/react-api.html#reactchildrenforeach
782 | *
783 | * The provided forEachFunc(child, index) will be called for each
784 | * leaf child.
785 | *
786 | * @param {?*} children Children tree container.
787 | * @param {function(*, int)} forEachFunc
788 | * @param {*} forEachContext Context for forEachContext.
789 | */
790 | function forEachChildren(children, forEachFunc, forEachContext) {
791 | mapChildren(
792 | children,
793 | function () {
794 | forEachFunc.apply(this, arguments); // Don't return anything.
795 | },
796 | forEachContext
797 | );
798 | }
799 | /**
800 | * Flatten a children object (typically specified as `props.children`) and
801 | * return an array with appropriately re-keyed children.
802 | *
803 | * See https://reactjs.org/docs/react-api.html#reactchildrentoarray
804 | */
805 |
806 | function toArray(children) {
807 | return mapChildren(children, (child) => child) || [];
808 | }
809 | /**
810 | * Returns the first child in a collection of children and verifies that there
811 | * is only one child in the collection.
812 | *
813 | * See https://reactjs.org/docs/react-api.html#reactchildrenonly
814 | *
815 | * The current implementation of this function assumes that a single child gets
816 | * passed without a wrapper, but the purpose of this helper function is to
817 | * abstract away the particular structure of children.
818 | *
819 | * @param {?object} children Child collection structure.
820 | * @return {ReactElement} The first and only `ReactElement` contained in the
821 | * structure.
822 | */
823 |
824 | function onlyChild(children) {
825 | if (!isValidElement(children)) {
826 | {
827 | throw Error(formatProdErrorMessage(143));
828 | }
829 | }
830 |
831 | return children;
832 | }
833 |
834 | function createContext(defaultValue, calculateChangedBits) {
835 | if (calculateChangedBits === undefined) {
836 | calculateChangedBits = null;
837 | }
838 |
839 | const context = {
840 | $$typeof: REACT_CONTEXT_TYPE,
841 | _calculateChangedBits: calculateChangedBits,
842 | // As a workaround to support multiple concurrent renderers, we categorize
843 | // some renderers as primary and others as secondary. We only expect
844 | // there to be two concurrent renderers at most: React Native (primary) and
845 | // Fabric (secondary); React DOM (primary) and React ART (secondary).
846 | // Secondary renderers store their context values on separate fields.
847 | _currentValue: defaultValue,
848 | _currentValue2: defaultValue,
849 | // Used to track how many concurrent renderers this context currently
850 | // supports within in a single renderer. Such as parallel server rendering.
851 | _threadCount: 0,
852 | // These are circular
853 | Provider: null,
854 | Consumer: null,
855 | };
856 | context.Provider = {
857 | $$typeof: REACT_PROVIDER_TYPE,
858 | _context: context,
859 | };
860 |
861 | {
862 | context.Consumer = context;
863 | }
864 |
865 | return context;
866 | }
867 |
868 | const Uninitialized = -1;
869 | const Pending = 0;
870 | const Resolved = 1;
871 | const Rejected = 2;
872 |
873 | function lazyInitializer(payload) {
874 | if (payload._status === Uninitialized) {
875 | const ctor = payload._result;
876 | const thenable = ctor(); // Transition to the next state.
877 |
878 | const pending = payload;
879 | pending._status = Pending;
880 | pending._result = thenable;
881 | thenable.then(
882 | (moduleObject) => {
883 | if (payload._status === Pending) {
884 | const defaultExport = moduleObject.default;
885 |
886 | const resolved = payload;
887 | resolved._status = Resolved;
888 | resolved._result = defaultExport;
889 | }
890 | },
891 | (error) => {
892 | if (payload._status === Pending) {
893 | // Transition to the next state.
894 | const rejected = payload;
895 | rejected._status = Rejected;
896 | rejected._result = error;
897 | }
898 | }
899 | );
900 | }
901 |
902 | if (payload._status === Resolved) {
903 | return payload._result;
904 | } else {
905 | throw payload._result;
906 | }
907 | }
908 |
909 | function lazy(ctor) {
910 | const payload = {
911 | // We use these fields to store the result.
912 | _status: -1,
913 | _result: ctor,
914 | };
915 | const lazyType = {
916 | $$typeof: REACT_LAZY_TYPE,
917 | _payload: payload,
918 | _init: lazyInitializer,
919 | };
920 |
921 | return lazyType;
922 | }
923 |
924 | function forwardRef(render) {
925 | const elementType = {
926 | $$typeof: REACT_FORWARD_REF_TYPE,
927 | render,
928 | };
929 |
930 | return elementType;
931 | }
932 |
933 | function memo(type, compare) {
934 | const elementType = {
935 | $$typeof: REACT_MEMO_TYPE,
936 | type,
937 | compare: compare === undefined ? null : compare,
938 | };
939 |
940 | return elementType;
941 | }
942 |
943 | function lazyInitializer$1(payload) {
944 | return {
945 | $$typeof: REACT_BLOCK_TYPE,
946 | _data: payload.load.apply(null, payload.args),
947 | _render: payload.render,
948 | };
949 | }
950 |
951 | function block(render, load) {
952 | if (load === undefined) {
953 | return function () {
954 | const blockComponent = {
955 | $$typeof: REACT_BLOCK_TYPE,
956 | _data: undefined,
957 | // $FlowFixMe: Data must be void in this scenario.
958 | _render: render,
959 | }; // $FlowFixMe: Upstream BlockComponent to Flow as a valid Node.
960 |
961 | return blockComponent;
962 | };
963 | } // Trick to let Flow refine this.
964 |
965 | const loadFn = load;
966 | return function () {
967 | const args = arguments;
968 | const payload = {
969 | load: loadFn,
970 | args: args,
971 | render: render,
972 | };
973 | const lazyType = {
974 | $$typeof: REACT_LAZY_TYPE,
975 | _payload: payload,
976 | _init: lazyInitializer$1,
977 | }; // $FlowFixMe: Upstream BlockComponent to Flow as a valid Node.
978 |
979 | return lazyType;
980 | };
981 | }
982 |
983 | /**
984 | * Keeps track of the current dispatcher.
985 | */
986 | const ReactCurrentDispatcher = {
987 | /**
988 | * @internal
989 | * @type {ReactComponent}
990 | */
991 | current: null,
992 | };
993 |
994 | function resolveDispatcher() {
995 | const dispatcher = ReactCurrentDispatcher.current;
996 |
997 | if (!(dispatcher !== null)) {
998 | {
999 | throw Error(formatProdErrorMessage(321));
1000 | }
1001 | }
1002 |
1003 | return dispatcher;
1004 | }
1005 |
1006 | function useContext(Context, unstable_observedBits) {
1007 | const dispatcher = resolveDispatcher();
1008 |
1009 | return dispatcher.useContext(Context, unstable_observedBits);
1010 | }
1011 | function useState(initialState) {
1012 | const dispatcher = resolveDispatcher();
1013 | return dispatcher.useState(initialState);
1014 | }
1015 | function useReducer(reducer, initialArg, init) {
1016 | const dispatcher = resolveDispatcher();
1017 | return dispatcher.useReducer(reducer, initialArg, init);
1018 | }
1019 | function useRef(initialValue) {
1020 | const dispatcher = resolveDispatcher();
1021 | return dispatcher.useRef(initialValue);
1022 | }
1023 | function useEffect(create, deps) {
1024 | const dispatcher = resolveDispatcher();
1025 | return dispatcher.useEffect(create, deps);
1026 | }
1027 | function useLayoutEffect(create, deps) {
1028 | const dispatcher = resolveDispatcher();
1029 | return dispatcher.useLayoutEffect(create, deps);
1030 | }
1031 | function useCallback(callback, deps) {
1032 | const dispatcher = resolveDispatcher();
1033 | return dispatcher.useCallback(callback, deps);
1034 | }
1035 | function useMemo(create, deps) {
1036 | const dispatcher = resolveDispatcher();
1037 | return dispatcher.useMemo(create, deps);
1038 | }
1039 | function useImperativeHandle(ref, create, deps) {
1040 | const dispatcher = resolveDispatcher();
1041 | return dispatcher.useImperativeHandle(ref, create, deps);
1042 | }
1043 | function useDebugValue(value, formatterFn) {}
1044 | function useTransition(config) {
1045 | const dispatcher = resolveDispatcher();
1046 | return dispatcher.useTransition(config);
1047 | }
1048 | function useDeferredValue(value, config) {
1049 | const dispatcher = resolveDispatcher();
1050 | return dispatcher.useDeferredValue(value, config);
1051 | }
1052 | function useOpaqueIdentifier() {
1053 | const dispatcher = resolveDispatcher();
1054 | return dispatcher.useOpaqueIdentifier();
1055 | }
1056 | function useMutableSource(source, getSnapshot, subscribe) {
1057 | const dispatcher = resolveDispatcher();
1058 | return dispatcher.useMutableSource(source, getSnapshot, subscribe);
1059 | }
1060 |
1061 | /**
1062 | * Keeps track of the current batch's configuration such as how long an update
1063 | * should suspend for if it needs to.
1064 | */
1065 | const ReactCurrentBatchConfig = {
1066 | suspense: null,
1067 | };
1068 |
1069 | function withSuspenseConfig(scope, config) {
1070 | const previousConfig = ReactCurrentBatchConfig.suspense;
1071 | ReactCurrentBatchConfig.suspense = config === undefined ? null : config;
1072 |
1073 | try {
1074 | scope();
1075 | } finally {
1076 | ReactCurrentBatchConfig.suspense = previousConfig;
1077 | }
1078 | }
1079 |
1080 | function createMutableSource(source, getVersion) {
1081 | const mutableSource = {
1082 | _getVersion: getVersion,
1083 | _source: source,
1084 | _workInProgressVersionPrimary: null,
1085 | _workInProgressVersionSecondary: null,
1086 | };
1087 |
1088 | return mutableSource;
1089 | }
1090 |
1091 | const enableSchedulerDebugging = false;
1092 | const enableProfiling = false;
1093 |
1094 | let requestHostCallback;
1095 | let requestHostTimeout;
1096 | let cancelHostTimeout;
1097 | let shouldYieldToHost;
1098 | let requestPaint;
1099 | let getCurrentTime;
1100 | let forceFrameRate;
1101 |
1102 | if (
1103 | // If Scheduler runs in a non-DOM environment, it falls back to a naive
1104 | // implementation using setTimeout.
1105 | typeof window === "undefined" || // Check if MessageChannel is supported, too.
1106 | typeof MessageChannel !== "function"
1107 | ) {
1108 | // If this accidentally gets imported in a non-browser environment, e.g. JavaScriptCore,
1109 | // fallback to a naive implementation.
1110 | let _callback = null;
1111 | let _timeoutID = null;
1112 |
1113 | const _flushCallback = function () {
1114 | if (_callback !== null) {
1115 | try {
1116 | const currentTime = getCurrentTime();
1117 | const hasRemainingTime = true;
1118 |
1119 | _callback(hasRemainingTime, currentTime);
1120 |
1121 | _callback = null;
1122 | } catch (e) {
1123 | setTimeout(_flushCallback, 0);
1124 | throw e;
1125 | }
1126 | }
1127 | };
1128 |
1129 | const initialTime = Date.now();
1130 |
1131 | getCurrentTime = function () {
1132 | return Date.now() - initialTime;
1133 | };
1134 |
1135 | requestHostCallback = function (cb) {
1136 | if (_callback !== null) {
1137 | // Protect against re-entrancy.
1138 | setTimeout(requestHostCallback, 0, cb);
1139 | } else {
1140 | _callback = cb;
1141 | setTimeout(_flushCallback, 0);
1142 | }
1143 | };
1144 |
1145 | requestHostTimeout = function (cb, ms) {
1146 | _timeoutID = setTimeout(cb, ms);
1147 | };
1148 |
1149 | cancelHostTimeout = function () {
1150 | clearTimeout(_timeoutID);
1151 | };
1152 |
1153 | shouldYieldToHost = function () {
1154 | return false;
1155 | };
1156 |
1157 | requestPaint = forceFrameRate = function () {};
1158 | } else {
1159 | // Capture local references to native APIs, in case a polyfill overrides them.
1160 | const performance = window.performance;
1161 | const Date = window.Date;
1162 | const setTimeout = window.setTimeout;
1163 | const clearTimeout = window.clearTimeout;
1164 |
1165 | if (typeof console !== "undefined") {
1166 | // TODO: Scheduler no longer requires these methods to be polyfilled. But
1167 | // maybe we want to continue warning if they don't exist, to preserve the
1168 | // option to rely on it in the future?
1169 | const requestAnimationFrame = window.requestAnimationFrame;
1170 | const cancelAnimationFrame = window.cancelAnimationFrame; // TODO: Remove fb.me link
1171 |
1172 | if (typeof requestAnimationFrame !== "function") {
1173 | // Using console['error'] to evade Babel and ESLint
1174 | console["error"](
1175 | "This browser doesn't support requestAnimationFrame. " +
1176 | "Make sure that you load a " +
1177 | "polyfill in older browsers. https://fb.me/react-polyfills"
1178 | );
1179 | }
1180 |
1181 | if (typeof cancelAnimationFrame !== "function") {
1182 | // Using console['error'] to evade Babel and ESLint
1183 | console["error"](
1184 | "This browser doesn't support cancelAnimationFrame. " +
1185 | "Make sure that you load a " +
1186 | "polyfill in older browsers. https://fb.me/react-polyfills"
1187 | );
1188 | }
1189 | }
1190 |
1191 | if (
1192 | typeof performance === "object" &&
1193 | typeof performance.now === "function"
1194 | ) {
1195 | getCurrentTime = () => performance.now();
1196 | } else {
1197 | const initialTime = Date.now();
1198 |
1199 | getCurrentTime = () => Date.now() - initialTime;
1200 | }
1201 |
1202 | let isMessageLoopRunning = false;
1203 | let scheduledHostCallback = null;
1204 | let taskTimeoutID = -1; // Scheduler periodically yields in case there is other work on the main
1205 | // thread, like user events. By default, it yields multiple times per frame.
1206 | // It does not attempt to align with frame boundaries, since most tasks don't
1207 | // need to be frame aligned; for those that do, use requestAnimationFrame.
1208 |
1209 | let yieldInterval = 5;
1210 | let deadline = 0; // TODO: Make this configurable
1211 |
1212 | {
1213 | // `isInputPending` is not available. Since we have no way of knowing if
1214 | // there's pending input, always yield at the end of the frame.
1215 | shouldYieldToHost = function () {
1216 | return getCurrentTime() >= deadline;
1217 | }; // Since we yield every frame regardless, `requestPaint` has no effect.
1218 |
1219 | requestPaint = function () {};
1220 | }
1221 |
1222 | forceFrameRate = function (fps) {
1223 | if (fps < 0 || fps > 125) {
1224 | // Using console['error'] to evade Babel and ESLint
1225 | console["error"](
1226 | "forceFrameRate takes a positive int between 0 and 125, " +
1227 | "forcing framerates higher than 125 fps is not unsupported"
1228 | );
1229 | return;
1230 | }
1231 |
1232 | if (fps > 0) {
1233 | yieldInterval = Math.floor(1000 / fps);
1234 | } else {
1235 | // reset the framerate
1236 | yieldInterval = 5;
1237 | }
1238 | };
1239 |
1240 | const performWorkUntilDeadline = () => {
1241 | if (scheduledHostCallback !== null) {
1242 | const currentTime = getCurrentTime(); // Yield after `yieldInterval` ms, regardless of where we are in the vsync
1243 | // cycle. This means there's always time remaining at the beginning of
1244 | // the message event.
1245 |
1246 | deadline = currentTime + yieldInterval;
1247 | const hasTimeRemaining = true;
1248 |
1249 | try {
1250 | const hasMoreWork = scheduledHostCallback(
1251 | hasTimeRemaining,
1252 | currentTime
1253 | );
1254 |
1255 | if (!hasMoreWork) {
1256 | isMessageLoopRunning = false;
1257 | scheduledHostCallback = null;
1258 | } else {
1259 | // If there's more work, schedule the next message event at the end
1260 | // of the preceding one.
1261 | port.postMessage(null);
1262 | }
1263 | } catch (error) {
1264 | // If a scheduler task throws, exit the current browser task so the
1265 | // error can be observed.
1266 | port.postMessage(null);
1267 | throw error;
1268 | }
1269 | } else {
1270 | isMessageLoopRunning = false;
1271 | } // Yielding to the browser will give it a chance to paint, so we can
1272 | };
1273 |
1274 | const channel = new MessageChannel();
1275 | const port = channel.port2;
1276 | channel.port1.onmessage = performWorkUntilDeadline;
1277 |
1278 | requestHostCallback = function (callback) {
1279 | scheduledHostCallback = callback;
1280 |
1281 | if (!isMessageLoopRunning) {
1282 | isMessageLoopRunning = true;
1283 | port.postMessage(null);
1284 | }
1285 | };
1286 |
1287 | requestHostTimeout = function (callback, ms) {
1288 | taskTimeoutID = setTimeout(() => {
1289 | callback(getCurrentTime());
1290 | }, ms);
1291 | };
1292 |
1293 | cancelHostTimeout = function () {
1294 | clearTimeout(taskTimeoutID);
1295 | taskTimeoutID = -1;
1296 | };
1297 | }
1298 |
1299 | function push(heap, node) {
1300 | const index = heap.length;
1301 | heap.push(node);
1302 | siftUp(heap, node, index);
1303 | }
1304 | function peek(heap) {
1305 | const first = heap[0];
1306 | return first === undefined ? null : first;
1307 | }
1308 | function pop(heap) {
1309 | const first = heap[0];
1310 |
1311 | if (first !== undefined) {
1312 | const last = heap.pop();
1313 |
1314 | if (last !== first) {
1315 | heap[0] = last;
1316 | siftDown(heap, last, 0);
1317 | }
1318 |
1319 | return first;
1320 | } else {
1321 | return null;
1322 | }
1323 | }
1324 |
1325 | function siftUp(heap, node, i) {
1326 | let index = i;
1327 |
1328 | while (true) {
1329 | const parentIndex = (index - 1) >>> 1;
1330 | const parent = heap[parentIndex];
1331 |
1332 | if (parent !== undefined && compare(parent, node) > 0) {
1333 | // The parent is larger. Swap positions.
1334 | heap[parentIndex] = node;
1335 | heap[index] = parent;
1336 | index = parentIndex;
1337 | } else {
1338 | // The parent is smaller. Exit.
1339 | return;
1340 | }
1341 | }
1342 | }
1343 |
1344 | function siftDown(heap, node, i) {
1345 | let index = i;
1346 | const length = heap.length;
1347 |
1348 | while (index < length) {
1349 | const leftIndex = (index + 1) * 2 - 1;
1350 | const left = heap[leftIndex];
1351 | const rightIndex = leftIndex + 1;
1352 | const right = heap[rightIndex]; // If the left or right node is smaller, swap with the smaller of those.
1353 |
1354 | if (left !== undefined && compare(left, node) < 0) {
1355 | if (right !== undefined && compare(right, left) < 0) {
1356 | heap[index] = right;
1357 | heap[rightIndex] = node;
1358 | index = rightIndex;
1359 | } else {
1360 | heap[index] = left;
1361 | heap[leftIndex] = node;
1362 | index = leftIndex;
1363 | }
1364 | } else if (right !== undefined && compare(right, node) < 0) {
1365 | heap[index] = right;
1366 | heap[rightIndex] = node;
1367 | index = rightIndex;
1368 | } else {
1369 | // Neither child is smaller. Exit.
1370 | return;
1371 | }
1372 | }
1373 | }
1374 |
1375 | function compare(a, b) {
1376 | // Compare sort index first, then task id.
1377 | const diff = a.sortIndex - b.sortIndex;
1378 | return diff !== 0 ? diff : a.id - b.id;
1379 | }
1380 |
1381 | // TODO: Use symbols?
1382 | const ImmediatePriority = 1;
1383 | const UserBlockingPriority = 2;
1384 | const NormalPriority = 3;
1385 | const LowPriority = 4;
1386 | const IdlePriority = 5;
1387 |
1388 | function markTaskErrored(task, ms) {}
1389 |
1390 | /* eslint-disable no-var */
1391 | // Math.pow(2, 30) - 1
1392 | // 0b111111111111111111111111111111
1393 |
1394 | var maxSigned31BitInt = 1073741823; // Times out immediately
1395 |
1396 | var IMMEDIATE_PRIORITY_TIMEOUT = -1; // Eventually times out
1397 |
1398 | var USER_BLOCKING_PRIORITY = 250;
1399 | var NORMAL_PRIORITY_TIMEOUT = 5000;
1400 | var LOW_PRIORITY_TIMEOUT = 10000; // Never times out
1401 |
1402 | var IDLE_PRIORITY = maxSigned31BitInt; // Tasks are stored on a min heap
1403 |
1404 | var taskQueue = [];
1405 | var timerQueue = []; // Incrementing id counter. Used to maintain insertion order.
1406 |
1407 | var taskIdCounter = 1; // Pausing the scheduler is useful for debugging.
1408 | var currentTask = null;
1409 | var currentPriorityLevel = NormalPriority; // This is set while performing work, to prevent re-entrancy.
1410 |
1411 | var isPerformingWork = false;
1412 | var isHostCallbackScheduled = false;
1413 | var isHostTimeoutScheduled = false;
1414 |
1415 | function advanceTimers(currentTime) {
1416 | // Check for tasks that are no longer delayed and add them to the queue.
1417 | let timer = peek(timerQueue);
1418 |
1419 | while (timer !== null) {
1420 | if (timer.callback === null) {
1421 | // Timer was cancelled.
1422 | pop(timerQueue);
1423 | } else if (timer.startTime <= currentTime) {
1424 | // Timer fired. Transfer to the task queue.
1425 | pop(timerQueue);
1426 | timer.sortIndex = timer.expirationTime;
1427 | push(taskQueue, timer);
1428 | } else {
1429 | // Remaining timers are pending.
1430 | return;
1431 | }
1432 |
1433 | timer = peek(timerQueue);
1434 | }
1435 | }
1436 |
1437 | function handleTimeout(currentTime) {
1438 | isHostTimeoutScheduled = false;
1439 | advanceTimers(currentTime);
1440 |
1441 | if (!isHostCallbackScheduled) {
1442 | if (peek(taskQueue) !== null) {
1443 | isHostCallbackScheduled = true;
1444 | requestHostCallback(flushWork);
1445 | } else {
1446 | const firstTimer = peek(timerQueue);
1447 |
1448 | if (firstTimer !== null) {
1449 | requestHostTimeout(handleTimeout, firstTimer.startTime - currentTime);
1450 | }
1451 | }
1452 | }
1453 | }
1454 |
1455 | function flushWork(hasTimeRemaining, initialTime) {
1456 | isHostCallbackScheduled = false;
1457 |
1458 | if (isHostTimeoutScheduled) {
1459 | // We scheduled a timeout but it's no longer needed. Cancel it.
1460 | isHostTimeoutScheduled = false;
1461 | cancelHostTimeout();
1462 | }
1463 |
1464 | isPerformingWork = true;
1465 | const previousPriorityLevel = currentPriorityLevel;
1466 |
1467 | try {
1468 | if (enableProfiling) {
1469 | try {
1470 | return workLoop(hasTimeRemaining, initialTime);
1471 | } catch (error) {
1472 | if (currentTask !== null) {
1473 | const currentTime = getCurrentTime();
1474 | markTaskErrored(currentTask, currentTime);
1475 | currentTask.isQueued = false;
1476 | }
1477 |
1478 | throw error;
1479 | }
1480 | } else {
1481 | // No catch in prod codepath.
1482 | return workLoop(hasTimeRemaining, initialTime);
1483 | }
1484 | } finally {
1485 | currentTask = null;
1486 | currentPriorityLevel = previousPriorityLevel;
1487 | isPerformingWork = false;
1488 | }
1489 | }
1490 |
1491 | function workLoop(hasTimeRemaining, initialTime) {
1492 | let currentTime = initialTime;
1493 | advanceTimers(currentTime);
1494 | currentTask = peek(taskQueue);
1495 |
1496 | while (currentTask !== null && !enableSchedulerDebugging) {
1497 | if (
1498 | currentTask.expirationTime > currentTime &&
1499 | (!hasTimeRemaining || shouldYieldToHost())
1500 | ) {
1501 | // This currentTask hasn't expired, and we've reached the deadline.
1502 | break;
1503 | }
1504 |
1505 | const callback = currentTask.callback;
1506 |
1507 | if (callback !== null) {
1508 | currentTask.callback = null;
1509 | currentPriorityLevel = currentTask.priorityLevel;
1510 | const didUserCallbackTimeout =
1511 | currentTask.expirationTime <= currentTime;
1512 | const continuationCallback = callback(didUserCallbackTimeout);
1513 | currentTime = getCurrentTime();
1514 |
1515 | if (typeof continuationCallback === "function") {
1516 | currentTask.callback = continuationCallback;
1517 | } else {
1518 | if (currentTask === peek(taskQueue)) {
1519 | pop(taskQueue);
1520 | }
1521 | }
1522 |
1523 | advanceTimers(currentTime);
1524 | } else {
1525 | pop(taskQueue);
1526 | }
1527 |
1528 | currentTask = peek(taskQueue);
1529 | } // Return whether there's additional work
1530 |
1531 | if (currentTask !== null) {
1532 | return true;
1533 | } else {
1534 | const firstTimer = peek(timerQueue);
1535 |
1536 | if (firstTimer !== null) {
1537 | requestHostTimeout(handleTimeout, firstTimer.startTime - currentTime);
1538 | }
1539 |
1540 | return false;
1541 | }
1542 | }
1543 |
1544 | function unstable_runWithPriority(priorityLevel, eventHandler) {
1545 | switch (priorityLevel) {
1546 | case ImmediatePriority:
1547 | case UserBlockingPriority:
1548 | case NormalPriority:
1549 | case LowPriority:
1550 | case IdlePriority:
1551 | break;
1552 |
1553 | default:
1554 | priorityLevel = NormalPriority;
1555 | }
1556 |
1557 | var previousPriorityLevel = currentPriorityLevel;
1558 | currentPriorityLevel = priorityLevel;
1559 |
1560 | try {
1561 | return eventHandler();
1562 | } finally {
1563 | currentPriorityLevel = previousPriorityLevel;
1564 | }
1565 | }
1566 |
1567 | function unstable_next(eventHandler) {
1568 | var priorityLevel;
1569 |
1570 | switch (currentPriorityLevel) {
1571 | case ImmediatePriority:
1572 | case UserBlockingPriority:
1573 | case NormalPriority:
1574 | // Shift down to normal priority
1575 | priorityLevel = NormalPriority;
1576 | break;
1577 |
1578 | default:
1579 | // Anything lower than normal priority should remain at the current level.
1580 | priorityLevel = currentPriorityLevel;
1581 | break;
1582 | }
1583 |
1584 | var previousPriorityLevel = currentPriorityLevel;
1585 | currentPriorityLevel = priorityLevel;
1586 |
1587 | try {
1588 | return eventHandler();
1589 | } finally {
1590 | currentPriorityLevel = previousPriorityLevel;
1591 | }
1592 | }
1593 |
1594 | function unstable_wrapCallback(callback) {
1595 | var parentPriorityLevel = currentPriorityLevel;
1596 | return function () {
1597 | // This is a fork of runWithPriority, inlined for performance.
1598 | var previousPriorityLevel = currentPriorityLevel;
1599 | currentPriorityLevel = parentPriorityLevel;
1600 |
1601 | try {
1602 | return callback.apply(this, arguments);
1603 | } finally {
1604 | currentPriorityLevel = previousPriorityLevel;
1605 | }
1606 | };
1607 | }
1608 |
1609 | function timeoutForPriorityLevel(priorityLevel) {
1610 | switch (priorityLevel) {
1611 | case ImmediatePriority:
1612 | return IMMEDIATE_PRIORITY_TIMEOUT;
1613 |
1614 | case UserBlockingPriority:
1615 | return USER_BLOCKING_PRIORITY;
1616 |
1617 | case IdlePriority:
1618 | return IDLE_PRIORITY;
1619 |
1620 | case LowPriority:
1621 | return LOW_PRIORITY_TIMEOUT;
1622 |
1623 | case NormalPriority:
1624 | default:
1625 | return NORMAL_PRIORITY_TIMEOUT;
1626 | }
1627 | }
1628 |
1629 | function unstable_scheduleCallback(priorityLevel, callback, options) {
1630 | var currentTime = getCurrentTime();
1631 | var startTime;
1632 | var timeout;
1633 |
1634 | if (typeof options === "object" && options !== null) {
1635 | var delay = options.delay;
1636 |
1637 | if (typeof delay === "number" && delay > 0) {
1638 | startTime = currentTime + delay;
1639 | } else {
1640 | startTime = currentTime;
1641 | }
1642 |
1643 | timeout =
1644 | typeof options.timeout === "number"
1645 | ? options.timeout
1646 | : timeoutForPriorityLevel(priorityLevel);
1647 | } else {
1648 | timeout = timeoutForPriorityLevel(priorityLevel);
1649 | startTime = currentTime;
1650 | }
1651 |
1652 | var expirationTime = startTime + timeout;
1653 | var newTask = {
1654 | id: taskIdCounter++,
1655 | callback,
1656 | priorityLevel,
1657 | startTime,
1658 | expirationTime,
1659 | sortIndex: -1,
1660 | };
1661 |
1662 | if (startTime > currentTime) {
1663 | // This is a delayed task.
1664 | newTask.sortIndex = startTime;
1665 | push(timerQueue, newTask);
1666 |
1667 | if (peek(taskQueue) === null && newTask === peek(timerQueue)) {
1668 | // All tasks are delayed, and this is the task with the earliest delay.
1669 | if (isHostTimeoutScheduled) {
1670 | // Cancel an existing timeout.
1671 | cancelHostTimeout();
1672 | } else {
1673 | isHostTimeoutScheduled = true;
1674 | } // Schedule a timeout.
1675 |
1676 | requestHostTimeout(handleTimeout, startTime - currentTime);
1677 | }
1678 | } else {
1679 | newTask.sortIndex = expirationTime;
1680 | push(taskQueue, newTask);
1681 | // wait until the next time we yield.
1682 |
1683 | if (!isHostCallbackScheduled && !isPerformingWork) {
1684 | isHostCallbackScheduled = true;
1685 | requestHostCallback(flushWork);
1686 | }
1687 | }
1688 |
1689 | return newTask;
1690 | }
1691 |
1692 | function unstable_pauseExecution() {}
1693 |
1694 | function unstable_continueExecution() {
1695 | if (!isHostCallbackScheduled && !isPerformingWork) {
1696 | isHostCallbackScheduled = true;
1697 | requestHostCallback(flushWork);
1698 | }
1699 | }
1700 |
1701 | function unstable_getFirstCallbackNode() {
1702 | return peek(taskQueue);
1703 | }
1704 |
1705 | function unstable_cancelCallback(task) {
1706 | // remove from the queue because you can't remove arbitrary nodes from an
1707 | // array based heap, only the first one.)
1708 |
1709 | task.callback = null;
1710 | }
1711 |
1712 | function unstable_getCurrentPriorityLevel() {
1713 | return currentPriorityLevel;
1714 | }
1715 |
1716 | function unstable_shouldYield() {
1717 | const currentTime = getCurrentTime();
1718 | advanceTimers(currentTime);
1719 | const firstTask = peek(taskQueue);
1720 | return (
1721 | (firstTask !== currentTask &&
1722 | currentTask !== null &&
1723 | firstTask !== null &&
1724 | firstTask.callback !== null &&
1725 | firstTask.startTime <= currentTime &&
1726 | firstTask.expirationTime < currentTask.expirationTime) ||
1727 | shouldYieldToHost()
1728 | );
1729 | }
1730 |
1731 | const unstable_requestPaint = requestPaint;
1732 | const unstable_Profiling = null;
1733 |
1734 | var Scheduler = {
1735 | __proto__: null,
1736 | unstable_ImmediatePriority: ImmediatePriority,
1737 | unstable_UserBlockingPriority: UserBlockingPriority,
1738 | unstable_NormalPriority: NormalPriority,
1739 | unstable_IdlePriority: IdlePriority,
1740 | unstable_LowPriority: LowPriority,
1741 | unstable_runWithPriority: unstable_runWithPriority,
1742 | unstable_next: unstable_next,
1743 | unstable_scheduleCallback: unstable_scheduleCallback,
1744 | unstable_cancelCallback: unstable_cancelCallback,
1745 | unstable_wrapCallback: unstable_wrapCallback,
1746 | unstable_getCurrentPriorityLevel: unstable_getCurrentPriorityLevel,
1747 | unstable_shouldYield: unstable_shouldYield,
1748 | unstable_requestPaint: unstable_requestPaint,
1749 | unstable_continueExecution: unstable_continueExecution,
1750 | unstable_pauseExecution: unstable_pauseExecution,
1751 | unstable_getFirstCallbackNode: unstable_getFirstCallbackNode,
1752 | get unstable_now() {
1753 | return getCurrentTime;
1754 | },
1755 | get unstable_forceFrameRate() {
1756 | return forceFrameRate;
1757 | },
1758 | unstable_Profiling: unstable_Profiling,
1759 | };
1760 |
1761 | let threadIDCounter = 0; // Set of currently traced interactions.
1762 | // Interactions "stack"–
1763 | // Meaning that newly traced interactions are appended to the previously active set.
1764 | // When an interaction goes out of scope, the previous set (if any) is restored.
1765 |
1766 | let interactionsRef = null; // Listener(s) to notify when interactions begin and end.
1767 |
1768 | let subscriberRef = null;
1769 | function unstable_clear(callback) {
1770 | {
1771 | return callback();
1772 | }
1773 | }
1774 | function unstable_getCurrent() {
1775 | {
1776 | return null;
1777 | }
1778 | }
1779 | function unstable_getThreadID() {
1780 | return ++threadIDCounter;
1781 | }
1782 | function unstable_trace(name, timestamp, callback) {
1783 | {
1784 | return callback();
1785 | }
1786 | }
1787 | function unstable_wrap(callback) {
1788 | {
1789 | return callback;
1790 | }
1791 | }
1792 |
1793 | function unstable_subscribe(subscriber) {}
1794 | function unstable_unsubscribe(subscriber) {}
1795 |
1796 | var SchedulerTracing = {
1797 | __proto__: null,
1798 | __interactionsRef: interactionsRef,
1799 | __subscriberRef: subscriberRef,
1800 | unstable_clear: unstable_clear,
1801 | unstable_getCurrent: unstable_getCurrent,
1802 | unstable_getThreadID: unstable_getThreadID,
1803 | unstable_trace: unstable_trace,
1804 | unstable_wrap: unstable_wrap,
1805 | unstable_subscribe: unstable_subscribe,
1806 | unstable_unsubscribe: unstable_unsubscribe,
1807 | };
1808 |
1809 | /**
1810 | * Used by act() to track whether you're inside an act() scope.
1811 | */
1812 | const IsSomeRendererActing = {
1813 | current: false,
1814 | };
1815 |
1816 | const ReactSharedInternals = {
1817 | ReactCurrentDispatcher,
1818 | ReactCurrentOwner,
1819 | IsSomeRendererActing,
1820 | ReactCurrentBatchConfig,
1821 | // Used by renderers to avoid bundling object-assign twice in UMD bundles:
1822 | assign: _assign$1,
1823 | };
1824 | // This avoids introducing a dependency on a new UMD global in a minor update,
1825 | // Since that would be a breaking change (e.g. for all existing CodeSandboxes).
1826 | // This re-export is only required for UMD bundles;
1827 | // CJS bundles use the shared NPM package.
1828 |
1829 | _assign$1(ReactSharedInternals, {
1830 | Scheduler,
1831 | SchedulerTracing,
1832 | });
1833 |
1834 | const createElement$1 = createElement;
1835 | const cloneElement$1 = cloneElement;
1836 | const createFactory$1 = createFactory;
1837 | const Children = {
1838 | map: mapChildren,
1839 | forEach: forEachChildren,
1840 | count: countChildren,
1841 | toArray,
1842 | only: onlyChild,
1843 | };
1844 |
1845 | exports.Children = Children;
1846 | exports.Component = Component;
1847 | exports.PureComponent = PureComponent;
1848 | exports.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = ReactSharedInternals;
1849 | exports.block = block;
1850 | exports.cloneElement = cloneElement$1;
1851 | exports.createContext = createContext;
1852 | exports.createElement = createElement$1;
1853 | exports.createFactory = createFactory$1;
1854 | exports.createMutableSource = createMutableSource;
1855 | exports.createRef = createRef;
1856 | exports.forwardRef = forwardRef;
1857 | exports.isValidElement = isValidElement;
1858 | exports.lazy = lazy;
1859 | exports.memo = memo;
1860 | exports.unstable_useOpaqueIdentifier = useOpaqueIdentifier;
1861 | exports.unstable_withSuspenseConfig = withSuspenseConfig;
1862 | exports.useCallback = useCallback;
1863 | exports.useContext = useContext;
1864 | exports.useDebugValue = useDebugValue;
1865 | exports.useDeferredValue = useDeferredValue;
1866 | exports.useEffect = useEffect;
1867 | exports.useImperativeHandle = useImperativeHandle;
1868 | exports.useLayoutEffect = useLayoutEffect;
1869 | exports.useMemo = useMemo;
1870 | exports.useMutableSource = useMutableSource;
1871 | exports.useReducer = useReducer;
1872 | exports.useRef = useRef;
1873 | exports.useState = useState;
1874 | exports.useTransition = useTransition;
1875 | exports.version = ReactVersion;
1876 | });
1877 |
--------------------------------------------------------------------------------