diff --git a/dist/index.js b/dist/index.js index dfad756..fb3ac3d 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1100,7 +1100,7 @@ var require_react_development = __commonJS({ var dispatcher = resolveDispatcher(); return dispatcher.useRef(initialValue); } - function useEffect4(create, deps) { + function useEffect5(create, deps) { var dispatcher = resolveDispatcher(); return dispatcher.useEffect(create, deps); } @@ -1882,7 +1882,7 @@ var require_react_development = __commonJS({ exports.useContext = useContext2; exports.useDebugValue = useDebugValue2; exports.useDeferredValue = useDeferredValue; - exports.useEffect = useEffect4; + exports.useEffect = useEffect5; exports.useId = useId; exports.useImperativeHandle = useImperativeHandle; exports.useInsertionEffect = useInsertionEffect; @@ -2437,7 +2437,7 @@ var require_react_dom_development = __commonJS({ var HostPortal = 4; var HostComponent = 5; var HostText = 6; - var Fragment = 7; + var Fragment2 = 7; var Mode = 8; var ContextConsumer = 9; var ContextProvider = 10; @@ -3593,7 +3593,7 @@ var require_react_dom_development = __commonJS({ return "DehydratedFragment"; case ForwardRef: return getWrappedName$1(type, type.render, "ForwardRef"); - case Fragment: + case Fragment2: return "Fragment"; case HostComponent: return type; @@ -13264,7 +13264,7 @@ var require_react_dom_development = __commonJS({ } } function updateFragment2(returnFiber, current2, fragment, lanes, key) { - if (current2 === null || current2.tag !== Fragment) { + if (current2 === null || current2.tag !== Fragment2) { var created = createFiberFromFragment(fragment, returnFiber.mode, lanes, key); created.return = returnFiber; return created; @@ -13667,7 +13667,7 @@ var require_react_dom_development = __commonJS({ if (child.key === key) { var elementType = element.type; if (elementType === REACT_FRAGMENT_TYPE) { - if (child.tag === Fragment) { + if (child.tag === Fragment2) { deleteRemainingChildren(returnFiber, child.sibling); var existing = useFiber(child, element.props.children); existing.return = returnFiber; @@ -17842,7 +17842,7 @@ var require_react_dom_development = __commonJS({ var _resolvedProps2 = workInProgress2.elementType === type ? _unresolvedProps2 : resolveDefaultProps(type, _unresolvedProps2); return updateForwardRef(current2, workInProgress2, type, _resolvedProps2, renderLanes2); } - case Fragment: + case Fragment2: return updateFragment(current2, workInProgress2, renderLanes2); case Mode: return updateMode(current2, workInProgress2, renderLanes2); @@ -18115,7 +18115,7 @@ var require_react_dom_development = __commonJS({ case SimpleMemoComponent: case FunctionComponent: case ForwardRef: - case Fragment: + case Fragment2: case Mode: case Profiler: case ContextConsumer: @@ -22374,7 +22374,7 @@ var require_react_dom_development = __commonJS({ return fiber; } function createFiberFromFragment(elements, mode, lanes, key) { - var fiber = createFiber(Fragment, elements, key, mode); + var fiber = createFiber(Fragment2, elements, key, mode); fiber.lanes = lanes; return fiber; } @@ -24416,6 +24416,693 @@ function Header() { } var Header_default = Header; +// src/Picker.tsx +var import_react2 = __toESM(require_react(), 1); + +// node_modules/jotai/esm/vanilla.mjs +var keyCount = 0; +function atom(read, write) { + const key = `atom${++keyCount}`; + const config = { + toString: () => key + }; + if (typeof read === "function") { + config.read = read; + } else { + config.init = read; + config.read = (get) => get(config); + config.write = (get, set2, arg) => set2( + config, + typeof arg === "function" ? arg(get(config)) : arg + ); + } + if (write) { + config.write = write; + } + return config; +} +var hasInitialValue = (atom2) => "init" in atom2; +var isActuallyWritableAtom = (atom2) => !!atom2.write; +var cancelPromiseMap = /* @__PURE__ */ new WeakMap(); +var registerCancelPromise = (promise, cancel) => { + cancelPromiseMap.set(promise, cancel); + promise.catch(() => { + }).finally(() => cancelPromiseMap.delete(promise)); +}; +var cancelPromise = (promise, next) => { + const cancel = cancelPromiseMap.get(promise); + if (cancel) { + cancelPromiseMap.delete(promise); + cancel(next); + } +}; +var resolvePromise = (promise, value) => { + promise.status = "fulfilled"; + promise.value = value; +}; +var rejectPromise = (promise, e) => { + promise.status = "rejected"; + promise.reason = e; +}; +var isPromiseLike = (x) => typeof (x == null ? void 0 : x.then) === "function"; +var isEqualAtomValue = (a, b) => "v" in a && "v" in b && Object.is(a.v, b.v); +var isEqualAtomError = (a, b) => "e" in a && "e" in b && Object.is(a.e, b.e); +var hasPromiseAtomValue = (a) => "v" in a && a.v instanceof Promise; +var isEqualPromiseAtomValue = (a, b) => "v" in a && "v" in b && a.v.orig && a.v.orig === b.v.orig; +var returnAtomValue = (atomState) => { + if ("e" in atomState) { + throw atomState.e; + } + return atomState.v; +}; +var createStore = () => { + const atomStateMap = /* @__PURE__ */ new WeakMap(); + const mountedMap = /* @__PURE__ */ new WeakMap(); + const pendingMap = /* @__PURE__ */ new Map(); + let storeListenersRev1; + let storeListenersRev2; + let mountedAtoms; + if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { + storeListenersRev1 = /* @__PURE__ */ new Set(); + storeListenersRev2 = /* @__PURE__ */ new Set(); + mountedAtoms = /* @__PURE__ */ new Set(); + } + const getAtomState = (atom2) => atomStateMap.get(atom2); + const setAtomState = (atom2, atomState) => { + if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { + Object.freeze(atomState); + } + const prevAtomState = atomStateMap.get(atom2); + atomStateMap.set(atom2, atomState); + if (!pendingMap.has(atom2)) { + pendingMap.set(atom2, prevAtomState); + } + if (prevAtomState && hasPromiseAtomValue(prevAtomState)) { + const next = "v" in atomState ? atomState.v instanceof Promise ? atomState.v : Promise.resolve(atomState.v) : Promise.reject(atomState.e); + cancelPromise(prevAtomState.v, next); + } + }; + const updateDependencies = (atom2, nextAtomState, nextDependencies) => { + const dependencies = /* @__PURE__ */ new Map(); + let changed = false; + nextDependencies.forEach((aState, a) => { + if (!aState && a === atom2) { + aState = nextAtomState; + } + if (aState) { + dependencies.set(a, aState); + if (nextAtomState.d.get(a) !== aState) { + changed = true; + } + } else if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { + console.warn("[Bug] atom state not found"); + } + }); + if (changed || nextAtomState.d.size !== dependencies.size) { + nextAtomState.d = dependencies; + } + }; + const setAtomValue = (atom2, value, nextDependencies) => { + const prevAtomState = getAtomState(atom2); + const nextAtomState = { + d: (prevAtomState == null ? void 0 : prevAtomState.d) || /* @__PURE__ */ new Map(), + v: value + }; + if (nextDependencies) { + updateDependencies(atom2, nextAtomState, nextDependencies); + } + if (prevAtomState && isEqualAtomValue(prevAtomState, nextAtomState) && prevAtomState.d === nextAtomState.d) { + return prevAtomState; + } + if (prevAtomState && hasPromiseAtomValue(prevAtomState) && hasPromiseAtomValue(nextAtomState) && isEqualPromiseAtomValue(prevAtomState, nextAtomState)) { + if (prevAtomState.d === nextAtomState.d) { + return prevAtomState; + } else { + nextAtomState.v = prevAtomState.v; + } + } + setAtomState(atom2, nextAtomState); + return nextAtomState; + }; + const setAtomValueOrPromise = (atom2, valueOrPromise, nextDependencies, abortPromise) => { + if (isPromiseLike(valueOrPromise)) { + let continuePromise; + const promise = new Promise((resolve2, reject) => { + let settled = false; + valueOrPromise.then( + (v) => { + if (!settled) { + settled = true; + const prevAtomState = getAtomState(atom2); + const nextAtomState = setAtomValue( + atom2, + promise, + nextDependencies + ); + resolvePromise(promise, v); + resolve2(v); + if ((prevAtomState == null ? void 0 : prevAtomState.d) !== nextAtomState.d) { + mountDependencies(atom2, nextAtomState, prevAtomState == null ? void 0 : prevAtomState.d); + } + } + }, + (e) => { + if (!settled) { + settled = true; + const prevAtomState = getAtomState(atom2); + const nextAtomState = setAtomValue( + atom2, + promise, + nextDependencies + ); + rejectPromise(promise, e); + reject(e); + if ((prevAtomState == null ? void 0 : prevAtomState.d) !== nextAtomState.d) { + mountDependencies(atom2, nextAtomState, prevAtomState == null ? void 0 : prevAtomState.d); + } + } + } + ); + continuePromise = (next) => { + if (!settled) { + settled = true; + next.then( + (v) => resolvePromise(promise, v), + (e) => rejectPromise(promise, e) + ); + resolve2(next); + } + }; + }); + promise.orig = valueOrPromise; + promise.status = "pending"; + registerCancelPromise(promise, (next) => { + if (next) { + continuePromise(next); + } + abortPromise == null ? void 0 : abortPromise(); + }); + return setAtomValue(atom2, promise, nextDependencies); + } + return setAtomValue(atom2, valueOrPromise, nextDependencies); + }; + const setAtomError = (atom2, error, nextDependencies) => { + const prevAtomState = getAtomState(atom2); + const nextAtomState = { + d: (prevAtomState == null ? void 0 : prevAtomState.d) || /* @__PURE__ */ new Map(), + e: error + }; + if (nextDependencies) { + updateDependencies(atom2, nextAtomState, nextDependencies); + } + if (prevAtomState && isEqualAtomError(prevAtomState, nextAtomState) && prevAtomState.d === nextAtomState.d) { + return prevAtomState; + } + setAtomState(atom2, nextAtomState); + return nextAtomState; + }; + const readAtomState = (atom2) => { + const atomState = getAtomState(atom2); + if (atomState) { + atomState.d.forEach((_, a) => { + if (a !== atom2 && !mountedMap.has(a)) { + readAtomState(a); + } + }); + if (Array.from(atomState.d).every( + ([a, s]) => a === atom2 || getAtomState(a) === s + )) { + return atomState; + } + } + const nextDependencies = /* @__PURE__ */ new Map(); + let isSync = true; + const getter = (a) => { + if (a === atom2) { + const aState2 = getAtomState(a); + if (aState2) { + nextDependencies.set(a, aState2); + return returnAtomValue(aState2); + } + if (hasInitialValue(a)) { + nextDependencies.set(a, void 0); + return a.init; + } + throw new Error("no atom init"); + } + const aState = readAtomState(a); + nextDependencies.set(a, aState); + return returnAtomValue(aState); + }; + let controller; + let setSelf; + const options = { + get signal() { + if (!controller) { + controller = new AbortController(); + } + return controller.signal; + }, + get setSelf() { + if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && !isActuallyWritableAtom(atom2)) { + console.warn("setSelf function cannot be used with read-only atom"); + } + if (!setSelf && isActuallyWritableAtom(atom2)) { + setSelf = (...args) => { + if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && isSync) { + console.warn("setSelf function cannot be called in sync"); + } + if (!isSync) { + return writeAtom(atom2, ...args); + } + }; + } + return setSelf; + } + }; + try { + const valueOrPromise = atom2.read(getter, options); + return setAtomValueOrPromise( + atom2, + valueOrPromise, + nextDependencies, + () => controller == null ? void 0 : controller.abort() + ); + } catch (error) { + return setAtomError(atom2, error, nextDependencies); + } finally { + isSync = false; + } + }; + const readAtom = (atom2) => returnAtomValue(readAtomState(atom2)); + const addAtom = (atom2) => { + let mounted = mountedMap.get(atom2); + if (!mounted) { + mounted = mountAtom(atom2); + } + return mounted; + }; + const canUnmountAtom = (atom2, mounted) => !mounted.l.size && (!mounted.t.size || mounted.t.size === 1 && mounted.t.has(atom2)); + const delAtom = (atom2) => { + const mounted = mountedMap.get(atom2); + if (mounted && canUnmountAtom(atom2, mounted)) { + unmountAtom(atom2); + } + }; + const recomputeDependents = (atom2) => { + const dependencyMap = /* @__PURE__ */ new Map(); + const dirtyMap = /* @__PURE__ */ new WeakMap(); + const loop1 = (a) => { + const mounted = mountedMap.get(a); + mounted == null ? void 0 : mounted.t.forEach((dependent) => { + if (dependent !== a) { + dependencyMap.set( + dependent, + (dependencyMap.get(dependent) || /* @__PURE__ */ new Set()).add(a) + ); + dirtyMap.set(dependent, (dirtyMap.get(dependent) || 0) + 1); + loop1(dependent); + } + }); + }; + loop1(atom2); + const loop2 = (a) => { + const mounted = mountedMap.get(a); + mounted == null ? void 0 : mounted.t.forEach((dependent) => { + var _a; + if (dependent !== a) { + let dirtyCount = dirtyMap.get(dependent); + if (dirtyCount) { + dirtyMap.set(dependent, --dirtyCount); + } + if (!dirtyCount) { + let isChanged = !!((_a = dependencyMap.get(dependent)) == null ? void 0 : _a.size); + if (isChanged) { + const prevAtomState = getAtomState(dependent); + const nextAtomState = readAtomState(dependent); + isChanged = !prevAtomState || !isEqualAtomValue(prevAtomState, nextAtomState); + } + if (!isChanged) { + dependencyMap.forEach((s) => s.delete(dependent)); + } + } + loop2(dependent); + } + }); + }; + loop2(atom2); + }; + const writeAtomState = (atom2, ...args) => { + let isSync = true; + const getter = (a) => returnAtomValue(readAtomState(a)); + const setter = (a, ...args2) => { + let r; + if (a === atom2) { + if (!hasInitialValue(a)) { + throw new Error("atom not writable"); + } + const prevAtomState = getAtomState(a); + const nextAtomState = setAtomValueOrPromise(a, args2[0]); + if (!prevAtomState || !isEqualAtomValue(prevAtomState, nextAtomState)) { + recomputeDependents(a); + } + } else { + r = writeAtomState(a, ...args2); + } + if (!isSync) { + const flushed = flushPending(); + if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { + storeListenersRev2.forEach( + (l) => l({ type: "async-write", flushed }) + ); + } + } + return r; + }; + const result = atom2.write(getter, setter, ...args); + isSync = false; + return result; + }; + const writeAtom = (atom2, ...args) => { + const result = writeAtomState(atom2, ...args); + const flushed = flushPending(); + if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { + storeListenersRev2.forEach( + (l) => l({ type: "write", flushed }) + ); + } + return result; + }; + const mountAtom = (atom2, initialDependent) => { + const mounted = { + t: new Set(initialDependent && [initialDependent]), + l: /* @__PURE__ */ new Set() + }; + mountedMap.set(atom2, mounted); + if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { + mountedAtoms.add(atom2); + } + readAtomState(atom2).d.forEach((_, a) => { + const aMounted = mountedMap.get(a); + if (aMounted) { + aMounted.t.add(atom2); + } else { + if (a !== atom2) { + mountAtom(a, atom2); + } + } + }); + readAtomState(atom2); + if (isActuallyWritableAtom(atom2) && atom2.onMount) { + const onUnmount = atom2.onMount((...args) => writeAtom(atom2, ...args)); + if (onUnmount) { + mounted.u = onUnmount; + } + } + return mounted; + }; + const unmountAtom = (atom2) => { + var _a; + const onUnmount = (_a = mountedMap.get(atom2)) == null ? void 0 : _a.u; + if (onUnmount) { + onUnmount(); + } + mountedMap.delete(atom2); + if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { + mountedAtoms.delete(atom2); + } + const atomState = getAtomState(atom2); + if (atomState) { + if (hasPromiseAtomValue(atomState)) { + cancelPromise(atomState.v); + } + atomState.d.forEach((_, a) => { + if (a !== atom2) { + const mounted = mountedMap.get(a); + if (mounted) { + mounted.t.delete(atom2); + if (canUnmountAtom(a, mounted)) { + unmountAtom(a); + } + } + } + }); + } else if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { + console.warn("[Bug] could not find atom state to unmount", atom2); + } + }; + const mountDependencies = (atom2, atomState, prevDependencies) => { + const depSet = new Set(atomState.d.keys()); + prevDependencies == null ? void 0 : prevDependencies.forEach((_, a) => { + if (depSet.has(a)) { + depSet.delete(a); + return; + } + const mounted = mountedMap.get(a); + if (mounted) { + mounted.t.delete(atom2); + if (canUnmountAtom(a, mounted)) { + unmountAtom(a); + } + } + }); + depSet.forEach((a) => { + const mounted = mountedMap.get(a); + if (mounted) { + mounted.t.add(atom2); + } else if (mountedMap.has(atom2)) { + mountAtom(a, atom2); + } + }); + }; + const flushPending = () => { + let flushed; + if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { + flushed = /* @__PURE__ */ new Set(); + } + while (pendingMap.size) { + const pending = Array.from(pendingMap); + pendingMap.clear(); + pending.forEach(([atom2, prevAtomState]) => { + const atomState = getAtomState(atom2); + if (atomState) { + if (atomState.d !== (prevAtomState == null ? void 0 : prevAtomState.d)) { + mountDependencies(atom2, atomState, prevAtomState == null ? void 0 : prevAtomState.d); + } + const mounted = mountedMap.get(atom2); + if (mounted && !// TODO This seems pretty hacky. Hope to fix it. + // Maybe we could `mountDependencies` in `setAtomState`? + (prevAtomState && !hasPromiseAtomValue(prevAtomState) && (isEqualAtomValue(prevAtomState, atomState) || isEqualAtomError(prevAtomState, atomState)))) { + mounted.l.forEach((listener) => listener()); + if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { + flushed.add(atom2); + } + } + } else if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { + console.warn("[Bug] no atom state to flush"); + } + }); + } + if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { + storeListenersRev1.forEach((l) => l("state")); + return flushed; + } + }; + const subscribeAtom = (atom2, listener) => { + const mounted = addAtom(atom2); + const flushed = flushPending(); + const listeners = mounted.l; + listeners.add(listener); + if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { + storeListenersRev1.forEach((l) => l("sub")); + storeListenersRev2.forEach( + (l) => l({ type: "sub", flushed }) + ); + } + return () => { + listeners.delete(listener); + delAtom(atom2); + if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { + storeListenersRev1.forEach((l) => l("unsub")); + storeListenersRev2.forEach((l) => l({ type: "unsub" })); + } + }; + }; + if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { + return { + get: readAtom, + set: writeAtom, + sub: subscribeAtom, + // store dev methods (these are tentative and subject to change without notice) + dev_subscribe_store: (l, rev) => { + if (rev !== 2) { + console.warn( + "The current StoreListener revision is 2. The older ones are deprecated." + ); + storeListenersRev1.add(l); + return () => { + storeListenersRev1.delete(l); + }; + } + storeListenersRev2.add(l); + return () => { + storeListenersRev2.delete(l); + }; + }, + dev_get_mounted_atoms: () => mountedAtoms.values(), + dev_get_atom_state: (a) => atomStateMap.get(a), + dev_get_mounted: (a) => mountedMap.get(a), + dev_restore_atoms: (values) => { + for (const [atom2, valueOrPromise] of values) { + if (hasInitialValue(atom2)) { + setAtomValueOrPromise(atom2, valueOrPromise); + recomputeDependents(atom2); + } + } + const flushed = flushPending(); + storeListenersRev2.forEach( + (l) => l({ type: "restore", flushed }) + ); + } + }; + } + return { + get: readAtom, + set: writeAtom, + sub: subscribeAtom + }; +}; +var defaultStore; +var getDefaultStore = () => { + if (!defaultStore) { + defaultStore = createStore(); + } + return defaultStore; +}; + +// node_modules/jotai/esm/react.mjs +var import_react = __toESM(require_react(), 1); +var StoreContext = (0, import_react.createContext)(void 0); +var useStore = (options) => { + const store = (0, import_react.useContext)(StoreContext); + return (options == null ? void 0 : options.store) || store || getDefaultStore(); +}; +var isPromiseLike2 = (x) => typeof (x == null ? void 0 : x.then) === "function"; +var use = import_react.default.use || ((promise) => { + if (promise.status === "pending") { + throw promise; + } else if (promise.status === "fulfilled") { + return promise.value; + } else if (promise.status === "rejected") { + throw promise.reason; + } else { + promise.status = "pending"; + promise.then( + (v) => { + promise.status = "fulfilled"; + promise.value = v; + }, + (e) => { + promise.status = "rejected"; + promise.reason = e; + } + ); + throw promise; + } +}); +function useAtomValue(atom2, options) { + const store = useStore(options); + const [[valueFromReducer, storeFromReducer, atomFromReducer], rerender] = (0, import_react.useReducer)( + (prev) => { + const nextValue = store.get(atom2); + if (Object.is(prev[0], nextValue) && prev[1] === store && prev[2] === atom2) { + return prev; + } + return [nextValue, store, atom2]; + }, + void 0, + () => [store.get(atom2), store, atom2] + ); + let value = valueFromReducer; + if (storeFromReducer !== store || atomFromReducer !== atom2) { + rerender(); + value = store.get(atom2); + } + const delay = options == null ? void 0 : options.delay; + (0, import_react.useEffect)(() => { + const unsub = store.sub(atom2, () => { + if (typeof delay === "number") { + setTimeout(rerender, delay); + return; + } + rerender(); + }); + rerender(); + return unsub; + }, [store, atom2, delay]); + (0, import_react.useDebugValue)(value); + return isPromiseLike2(value) ? use(value) : value; +} +function useSetAtom(atom2, options) { + const store = useStore(options); + const setAtom = (0, import_react.useCallback)( + (...args) => { + if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && !("write" in atom2)) { + throw new Error("not writable atom"); + } + return store.set(atom2, ...args); + }, + [store, atom2] + ); + return setAtom; +} +function useAtom(atom2, options) { + return [ + useAtomValue(atom2, options), + // We do wrong type assertion here, which results in throwing an error. + useSetAtom(atom2, options) + ]; +} + +// src/Picker.tsx +var import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1); +function Picker({ + $url, + $options = (0, import_react2.useMemo)(() => atom([]), []), + $isLoading = (0, import_react2.useMemo)(() => atom(true), []), + $isEnabled = (0, import_react2.useMemo)(() => atom(true), []), + $selectedOption = (0, import_react2.useMemo)(() => atom(""), []) +}) { + const url = useAtomValue($url); + const options = useAtomValue($options); + const isLoading = useAtomValue($isLoading); + const [selectedOption, setSelectedOption] = useAtom($selectedOption); + const isEnabled = useAtomValue($isEnabled); + const optionsFetched = useSetAtom((0, import_react2.useMemo)(() => atom(null, (get, set2, options2) => { + set2($options, options2); + set2($isLoading, false); + }), [$options, $isLoading])); + (0, import_react2.useEffect)(() => { + if (isEnabled) { + fetch(url).then((x) => x.json()).catch((err) => ["AAPL", "MSFT", "GOOG"]).then(optionsFetched); + } + }, [url, isEnabled]); + return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "Loading..." }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("select", { value: selectedOption, onChange: (e) => { + setSelectedOption(e.target.value); + }, children: [ + /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "" }, ""), + options.map( + (date) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: date, children: date }, date) + ) + ] }) }); +} + +// src/App.module.css +var App_module_default = { + "app": "App-module__app_gPMrEW__001", + "picker": "App-module__picker_gPMrEW__001" +}; + // node_modules/@kurkle/color/dist/color.esm.js function round(v) { return v + 0.5 | 0; @@ -26313,7 +27000,7 @@ function _addGrace(minmax, grace, beginAtZero) { max: keepZero(max, change) }; } -function createContext(parentContext, context) { +function createContext2(parentContext, context) { return Object.assign(Object.create(parentContext), context); } function _createResolver(scopes, prefixes = [ @@ -27272,7 +27959,7 @@ function doSplitByStyles(line, segments, points, segmentOptions) { let style; for (i = start + 1; i <= segment.end; i++) { const pt = points[i % count]; - style = readStyle(segmentOptions.setContext(createContext(chartContext, { + style = readStyle(segmentOptions.setContext(createContext2(chartContext, { type: "segment", p0: prev, p1: pt, @@ -27829,7 +28516,7 @@ function getFirstScaleId(chart, axis) { return Object.keys(scales).filter((key) => scales[key].axis === axis).shift(); } function createDatasetContext(parent, index) { - return createContext(parent, { + return createContext2(parent, { active: false, dataset: void 0, datasetIndex: index, @@ -27839,7 +28526,7 @@ function createDatasetContext(parent, index) { }); } function createDataContext(parent, index, element) { - return createContext(parent, { + return createContext2(parent, { active: false, dataIndex: index, parsed: void 0, @@ -29665,13 +30352,13 @@ function getTitleHeight(options, fallback) { return lines * font.lineHeight + padding.height; } function createScaleContext(parent, scale) { - return createContext(parent, { + return createContext2(parent, { scale, type: "scale" }); } function createTickContext(parent, index, tick) { - return createContext(parent, { + return createContext2(parent, { tick, index, type: "tick" @@ -32129,7 +32816,7 @@ var Chart = class { return meta; } getContext() { - return this.$context || (this.$context = createContext(null, { + return this.$context || (this.$context = createContext2(null, { chart: this, type: "chart" })); @@ -33557,7 +34244,7 @@ function getBeforeAfterBodyLines(callback2) { return pushOrConcat([], splitNewlines(callback2)); } function createTooltipContext(parent, tooltip, tooltipItems) { - return createContext(parent, { + return createContext2(parent, { tooltip, tooltipItems, type: "tooltip" @@ -35089,7 +35776,7 @@ function drawRadiusLine(scale, gridLineOpts, radius, labelCount, borderOpts) { ctx.restore(); } function createPointLabelContext(parent, index, label) { - return createContext(parent, { + return createContext2(parent, { label, index, type: "pointLabel" @@ -35853,7 +36540,7 @@ __publicField(TimeSeriesScale, "id", "timeseries"); __publicField(TimeSeriesScale, "defaults", TimeScale.defaults); // node_modules/react-chartjs-2/dist/index.js -var import_react = __toESM(require_react(), 1); +var import_react3 = __toESM(require_react(), 1); var defaultDatasetIdKey = "label"; function reforwardRef(ref, value) { if (typeof ref === "function") { @@ -35898,8 +36585,8 @@ function cloneData(data) { } function ChartComponent(props, ref) { const { height = 150, width = 300, redraw = false, datasetIdKey, type, data, options, plugins = [], fallbackContent, updateMode, ...canvasProps } = props; - const canvasRef = (0, import_react.useRef)(null); - const chartRef = (0, import_react.useRef)(); + const canvasRef = (0, import_react3.useRef)(null); + const chartRef = (0, import_react3.useRef)(); const renderChart = () => { if (!canvasRef.current) return; @@ -35920,7 +36607,7 @@ function ChartComponent(props, ref) { chartRef.current = null; } }; - (0, import_react.useEffect)(() => { + (0, import_react3.useEffect)(() => { if (!redraw && chartRef.current && options) { setOptions(chartRef.current, options); } @@ -35928,7 +36615,7 @@ function ChartComponent(props, ref) { redraw, options ]); - (0, import_react.useEffect)(() => { + (0, import_react3.useEffect)(() => { if (!redraw && chartRef.current) { setLabels(chartRef.current.config.data, data.labels); } @@ -35936,7 +36623,7 @@ function ChartComponent(props, ref) { redraw, data.labels ]); - (0, import_react.useEffect)(() => { + (0, import_react3.useEffect)(() => { if (!redraw && chartRef.current && data.datasets) { setDatasets(chartRef.current.config.data, data.datasets, datasetIdKey); } @@ -35944,7 +36631,7 @@ function ChartComponent(props, ref) { redraw, data.datasets ]); - (0, import_react.useEffect)(() => { + (0, import_react3.useEffect)(() => { if (!chartRef.current) return; if (redraw) { @@ -35960,7 +36647,7 @@ function ChartComponent(props, ref) { data.datasets, updateMode ]); - (0, import_react.useEffect)(() => { + (0, import_react3.useEffect)(() => { if (!chartRef.current) return; destroyChart(); @@ -35968,742 +36655,176 @@ function ChartComponent(props, ref) { }, [ type ]); - (0, import_react.useEffect)(() => { + (0, import_react3.useEffect)(() => { renderChart(); return () => destroyChart(); }, []); - return /* @__PURE__ */ import_react.default.createElement("canvas", Object.assign({ + return /* @__PURE__ */ import_react3.default.createElement("canvas", Object.assign({ ref: canvasRef, role: "img", height, width }, canvasProps), fallbackContent); } -var Chart2 = /* @__PURE__ */ (0, import_react.forwardRef)(ChartComponent); +var Chart2 = /* @__PURE__ */ (0, import_react3.forwardRef)(ChartComponent); function createTypedChart(type, registerables) { Chart.register(registerables); - return /* @__PURE__ */ (0, import_react.forwardRef)((props, ref) => /* @__PURE__ */ import_react.default.createElement(Chart2, Object.assign({}, props, { + return /* @__PURE__ */ (0, import_react3.forwardRef)((props, ref) => /* @__PURE__ */ import_react3.default.createElement(Chart2, Object.assign({}, props, { ref, type }))); } var Line = /* @__PURE__ */ createTypedChart("line", LineController); -// src/HistoricalImpliedVolatilityChart.tsx -var import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1); -Chart.register(LineElement, plugin_tooltip, plugin_legend, CategoryScale, LinearScale, PointElement); -function HistoricalImpliedVolatilityChart() { - return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)( - Line, - { - datasetIdKey: "id", - data: { - labels: ["Jun", "Jul", "Aug"], - datasets: [ - { - //@ts-ignore - id: 1, - label: "", - data: [5, 6, 7] - }, - { - //@ts-ignore - id: 2, - label: "", - data: [3, 2, 1] +// node_modules/jotai/esm/vanilla/utils.mjs +var RESET = Symbol(); +var isPromiseLike3 = (x) => typeof (x == null ? void 0 : x.then) === "function"; +function createJSONStorage(getStringStorage) { + let lastStr; + let lastValue; + const storage = { + getItem: (key, initialValue) => { + var _a, _b; + const parse2 = (str2) => { + str2 = str2 || ""; + if (lastStr !== str2) { + try { + lastValue = JSON.parse(str2); + } catch { + return initialValue; } - ] + lastStr = str2; + } + return lastValue; + }; + const str = (_b = (_a = getStringStorage()) == null ? void 0 : _a.getItem(key)) != null ? _b : null; + if (isPromiseLike3(str)) { + return str.then(parse2); } - } - ) }); -} - -// src/Picker.tsx -var import_react3 = __toESM(require_react(), 1); - -// node_modules/jotai/esm/vanilla.mjs -var keyCount = 0; -function atom(read, write) { - const key = `atom${++keyCount}`; - const config = { - toString: () => key - }; - if (typeof read === "function") { - config.read = read; - } else { - config.init = read; - config.read = (get) => get(config); - config.write = (get, set2, arg) => set2( - config, - typeof arg === "function" ? arg(get(config)) : arg - ); - } - if (write) { - config.write = write; - } - return config; -} -var hasInitialValue = (atom2) => "init" in atom2; -var isActuallyWritableAtom = (atom2) => !!atom2.write; -var cancelPromiseMap = /* @__PURE__ */ new WeakMap(); -var registerCancelPromise = (promise, cancel) => { - cancelPromiseMap.set(promise, cancel); - promise.catch(() => { - }).finally(() => cancelPromiseMap.delete(promise)); -}; -var cancelPromise = (promise, next) => { - const cancel = cancelPromiseMap.get(promise); - if (cancel) { - cancelPromiseMap.delete(promise); - cancel(next); - } -}; -var resolvePromise = (promise, value) => { - promise.status = "fulfilled"; - promise.value = value; -}; -var rejectPromise = (promise, e) => { - promise.status = "rejected"; - promise.reason = e; -}; -var isPromiseLike = (x) => typeof (x == null ? void 0 : x.then) === "function"; -var isEqualAtomValue = (a, b) => "v" in a && "v" in b && Object.is(a.v, b.v); -var isEqualAtomError = (a, b) => "e" in a && "e" in b && Object.is(a.e, b.e); -var hasPromiseAtomValue = (a) => "v" in a && a.v instanceof Promise; -var isEqualPromiseAtomValue = (a, b) => "v" in a && "v" in b && a.v.orig && a.v.orig === b.v.orig; -var returnAtomValue = (atomState) => { - if ("e" in atomState) { - throw atomState.e; - } - return atomState.v; -}; -var createStore = () => { - const atomStateMap = /* @__PURE__ */ new WeakMap(); - const mountedMap = /* @__PURE__ */ new WeakMap(); - const pendingMap = /* @__PURE__ */ new Map(); - let storeListenersRev1; - let storeListenersRev2; - let mountedAtoms; - if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { - storeListenersRev1 = /* @__PURE__ */ new Set(); - storeListenersRev2 = /* @__PURE__ */ new Set(); - mountedAtoms = /* @__PURE__ */ new Set(); - } - const getAtomState = (atom2) => atomStateMap.get(atom2); - const setAtomState = (atom2, atomState) => { - if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { - Object.freeze(atomState); - } - const prevAtomState = atomStateMap.get(atom2); - atomStateMap.set(atom2, atomState); - if (!pendingMap.has(atom2)) { - pendingMap.set(atom2, prevAtomState); - } - if (prevAtomState && hasPromiseAtomValue(prevAtomState)) { - const next = "v" in atomState ? atomState.v instanceof Promise ? atomState.v : Promise.resolve(atomState.v) : Promise.reject(atomState.e); - cancelPromise(prevAtomState.v, next); + return parse2(str); + }, + setItem: (key, newValue) => { + var _a; + return (_a = getStringStorage()) == null ? void 0 : _a.setItem(key, JSON.stringify(newValue)); + }, + removeItem: (key) => { + var _a; + return (_a = getStringStorage()) == null ? void 0 : _a.removeItem(key); } }; - const updateDependencies = (atom2, nextAtomState, nextDependencies) => { - const dependencies = /* @__PURE__ */ new Map(); - let changed = false; - nextDependencies.forEach((aState, a) => { - if (!aState && a === atom2) { - aState = nextAtomState; - } - if (aState) { - dependencies.set(a, aState); - if (nextAtomState.d.get(a) !== aState) { - changed = true; - } - } else if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { - console.warn("[Bug] atom state not found"); - } - }); - if (changed || nextAtomState.d.size !== dependencies.size) { - nextAtomState.d = dependencies; - } - }; - const setAtomValue = (atom2, value, nextDependencies) => { - const prevAtomState = getAtomState(atom2); - const nextAtomState = { - d: (prevAtomState == null ? void 0 : prevAtomState.d) || /* @__PURE__ */ new Map(), - v: value - }; - if (nextDependencies) { - updateDependencies(atom2, nextAtomState, nextDependencies); - } - if (prevAtomState && isEqualAtomValue(prevAtomState, nextAtomState) && prevAtomState.d === nextAtomState.d) { - return prevAtomState; - } - if (prevAtomState && hasPromiseAtomValue(prevAtomState) && hasPromiseAtomValue(nextAtomState) && isEqualPromiseAtomValue(prevAtomState, nextAtomState)) { - if (prevAtomState.d === nextAtomState.d) { - return prevAtomState; - } else { - nextAtomState.v = prevAtomState.v; - } - } - setAtomState(atom2, nextAtomState); - return nextAtomState; - }; - const setAtomValueOrPromise = (atom2, valueOrPromise, nextDependencies, abortPromise) => { - if (isPromiseLike(valueOrPromise)) { - let continuePromise; - const promise = new Promise((resolve2, reject) => { - let settled = false; - valueOrPromise.then( - (v) => { - if (!settled) { - settled = true; - const prevAtomState = getAtomState(atom2); - const nextAtomState = setAtomValue( - atom2, - promise, - nextDependencies - ); - resolvePromise(promise, v); - resolve2(v); - if ((prevAtomState == null ? void 0 : prevAtomState.d) !== nextAtomState.d) { - mountDependencies(atom2, nextAtomState, prevAtomState == null ? void 0 : prevAtomState.d); - } - } - }, - (e) => { - if (!settled) { - settled = true; - const prevAtomState = getAtomState(atom2); - const nextAtomState = setAtomValue( - atom2, - promise, - nextDependencies - ); - rejectPromise(promise, e); - reject(e); - if ((prevAtomState == null ? void 0 : prevAtomState.d) !== nextAtomState.d) { - mountDependencies(atom2, nextAtomState, prevAtomState == null ? void 0 : prevAtomState.d); - } - } - } - ); - continuePromise = (next) => { - if (!settled) { - settled = true; - next.then( - (v) => resolvePromise(promise, v), - (e) => rejectPromise(promise, e) - ); - resolve2(next); - } - }; - }); - promise.orig = valueOrPromise; - promise.status = "pending"; - registerCancelPromise(promise, (next) => { - if (next) { - continuePromise(next); - } - abortPromise == null ? void 0 : abortPromise(); - }); - return setAtomValue(atom2, promise, nextDependencies); - } - return setAtomValue(atom2, valueOrPromise, nextDependencies); - }; - const setAtomError = (atom2, error, nextDependencies) => { - const prevAtomState = getAtomState(atom2); - const nextAtomState = { - d: (prevAtomState == null ? void 0 : prevAtomState.d) || /* @__PURE__ */ new Map(), - e: error - }; - if (nextDependencies) { - updateDependencies(atom2, nextAtomState, nextDependencies); - } - if (prevAtomState && isEqualAtomError(prevAtomState, nextAtomState) && prevAtomState.d === nextAtomState.d) { - return prevAtomState; - } - setAtomState(atom2, nextAtomState); - return nextAtomState; - }; - const readAtomState = (atom2) => { - const atomState = getAtomState(atom2); - if (atomState) { - atomState.d.forEach((_, a) => { - if (a !== atom2 && !mountedMap.has(a)) { - readAtomState(a); - } - }); - if (Array.from(atomState.d).every( - ([a, s]) => a === atom2 || getAtomState(a) === s - )) { - return atomState; - } - } - const nextDependencies = /* @__PURE__ */ new Map(); - let isSync = true; - const getter = (a) => { - if (a === atom2) { - const aState2 = getAtomState(a); - if (aState2) { - nextDependencies.set(a, aState2); - return returnAtomValue(aState2); - } - if (hasInitialValue(a)) { - nextDependencies.set(a, void 0); - return a.init; - } - throw new Error("no atom init"); - } - const aState = readAtomState(a); - nextDependencies.set(a, aState); - return returnAtomValue(aState); - }; - let controller; - let setSelf; - const options = { - get signal() { - if (!controller) { - controller = new AbortController(); - } - return controller.signal; - }, - get setSelf() { - if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && !isActuallyWritableAtom(atom2)) { - console.warn("setSelf function cannot be used with read-only atom"); - } - if (!setSelf && isActuallyWritableAtom(atom2)) { - setSelf = (...args) => { - if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && isSync) { - console.warn("setSelf function cannot be called in sync"); - } - if (!isSync) { - return writeAtom(atom2, ...args); - } - }; - } - return setSelf; - } - }; - try { - const valueOrPromise = atom2.read(getter, options); - return setAtomValueOrPromise( - atom2, - valueOrPromise, - nextDependencies, - () => controller == null ? void 0 : controller.abort() - ); - } catch (error) { - return setAtomError(atom2, error, nextDependencies); - } finally { - isSync = false; - } - }; - const readAtom = (atom2) => returnAtomValue(readAtomState(atom2)); - const addAtom = (atom2) => { - let mounted = mountedMap.get(atom2); - if (!mounted) { - mounted = mountAtom(atom2); - } - return mounted; - }; - const canUnmountAtom = (atom2, mounted) => !mounted.l.size && (!mounted.t.size || mounted.t.size === 1 && mounted.t.has(atom2)); - const delAtom = (atom2) => { - const mounted = mountedMap.get(atom2); - if (mounted && canUnmountAtom(atom2, mounted)) { - unmountAtom(atom2); - } - }; - const recomputeDependents = (atom2) => { - const dependencyMap = /* @__PURE__ */ new Map(); - const dirtyMap = /* @__PURE__ */ new WeakMap(); - const loop1 = (a) => { - const mounted = mountedMap.get(a); - mounted == null ? void 0 : mounted.t.forEach((dependent) => { - if (dependent !== a) { - dependencyMap.set( - dependent, - (dependencyMap.get(dependent) || /* @__PURE__ */ new Set()).add(a) - ); - dirtyMap.set(dependent, (dirtyMap.get(dependent) || 0) + 1); - loop1(dependent); - } - }); - }; - loop1(atom2); - const loop2 = (a) => { - const mounted = mountedMap.get(a); - mounted == null ? void 0 : mounted.t.forEach((dependent) => { - var _a; - if (dependent !== a) { - let dirtyCount = dirtyMap.get(dependent); - if (dirtyCount) { - dirtyMap.set(dependent, --dirtyCount); - } - if (!dirtyCount) { - let isChanged = !!((_a = dependencyMap.get(dependent)) == null ? void 0 : _a.size); - if (isChanged) { - const prevAtomState = getAtomState(dependent); - const nextAtomState = readAtomState(dependent); - isChanged = !prevAtomState || !isEqualAtomValue(prevAtomState, nextAtomState); - } - if (!isChanged) { - dependencyMap.forEach((s) => s.delete(dependent)); - } - } - loop2(dependent); - } - }); - }; - loop2(atom2); - }; - const writeAtomState = (atom2, ...args) => { - let isSync = true; - const getter = (a) => returnAtomValue(readAtomState(a)); - const setter = (a, ...args2) => { - let r; - if (a === atom2) { - if (!hasInitialValue(a)) { - throw new Error("atom not writable"); - } - const prevAtomState = getAtomState(a); - const nextAtomState = setAtomValueOrPromise(a, args2[0]); - if (!prevAtomState || !isEqualAtomValue(prevAtomState, nextAtomState)) { - recomputeDependents(a); - } - } else { - r = writeAtomState(a, ...args2); - } - if (!isSync) { - const flushed = flushPending(); - if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { - storeListenersRev2.forEach( - (l) => l({ type: "async-write", flushed }) - ); - } - } - return r; - }; - const result = atom2.write(getter, setter, ...args); - isSync = false; - return result; - }; - const writeAtom = (atom2, ...args) => { - const result = writeAtomState(atom2, ...args); - const flushed = flushPending(); - if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { - storeListenersRev2.forEach( - (l) => l({ type: "write", flushed }) - ); - } - return result; - }; - const mountAtom = (atom2, initialDependent) => { - const mounted = { - t: new Set(initialDependent && [initialDependent]), - l: /* @__PURE__ */ new Set() - }; - mountedMap.set(atom2, mounted); - if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { - mountedAtoms.add(atom2); - } - readAtomState(atom2).d.forEach((_, a) => { - const aMounted = mountedMap.get(a); - if (aMounted) { - aMounted.t.add(atom2); - } else { - if (a !== atom2) { - mountAtom(a, atom2); - } - } - }); - readAtomState(atom2); - if (isActuallyWritableAtom(atom2) && atom2.onMount) { - const onUnmount = atom2.onMount((...args) => writeAtom(atom2, ...args)); - if (onUnmount) { - mounted.u = onUnmount; - } - } - return mounted; - }; - const unmountAtom = (atom2) => { - var _a; - const onUnmount = (_a = mountedMap.get(atom2)) == null ? void 0 : _a.u; - if (onUnmount) { - onUnmount(); - } - mountedMap.delete(atom2); - if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { - mountedAtoms.delete(atom2); - } - const atomState = getAtomState(atom2); - if (atomState) { - if (hasPromiseAtomValue(atomState)) { - cancelPromise(atomState.v); - } - atomState.d.forEach((_, a) => { - if (a !== atom2) { - const mounted = mountedMap.get(a); - if (mounted) { - mounted.t.delete(atom2); - if (canUnmountAtom(a, mounted)) { - unmountAtom(a); - } - } - } - }); - } else if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { - console.warn("[Bug] could not find atom state to unmount", atom2); - } - }; - const mountDependencies = (atom2, atomState, prevDependencies) => { - const depSet = new Set(atomState.d.keys()); - prevDependencies == null ? void 0 : prevDependencies.forEach((_, a) => { - if (depSet.has(a)) { - depSet.delete(a); - return; - } - const mounted = mountedMap.get(a); - if (mounted) { - mounted.t.delete(atom2); - if (canUnmountAtom(a, mounted)) { - unmountAtom(a); - } - } - }); - depSet.forEach((a) => { - const mounted = mountedMap.get(a); - if (mounted) { - mounted.t.add(atom2); - } else if (mountedMap.has(atom2)) { - mountAtom(a, atom2); - } - }); - }; - const flushPending = () => { - let flushed; - if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { - flushed = /* @__PURE__ */ new Set(); - } - while (pendingMap.size) { - const pending = Array.from(pendingMap); - pendingMap.clear(); - pending.forEach(([atom2, prevAtomState]) => { - const atomState = getAtomState(atom2); - if (atomState) { - if (atomState.d !== (prevAtomState == null ? void 0 : prevAtomState.d)) { - mountDependencies(atom2, atomState, prevAtomState == null ? void 0 : prevAtomState.d); - } - const mounted = mountedMap.get(atom2); - if (mounted && !// TODO This seems pretty hacky. Hope to fix it. - // Maybe we could `mountDependencies` in `setAtomState`? - (prevAtomState && !hasPromiseAtomValue(prevAtomState) && (isEqualAtomValue(prevAtomState, atomState) || isEqualAtomError(prevAtomState, atomState)))) { - mounted.l.forEach((listener) => listener()); - if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { - flushed.add(atom2); - } - } - } else if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { - console.warn("[Bug] no atom state to flush"); - } - }); - } - if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { - storeListenersRev1.forEach((l) => l("state")); - return flushed; - } - }; - const subscribeAtom = (atom2, listener) => { - const mounted = addAtom(atom2); - const flushed = flushPending(); - const listeners = mounted.l; - listeners.add(listener); - if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { - storeListenersRev1.forEach((l) => l("sub")); - storeListenersRev2.forEach( - (l) => l({ type: "sub", flushed }) - ); - } - return () => { - listeners.delete(listener); - delAtom(atom2); - if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { - storeListenersRev1.forEach((l) => l("unsub")); - storeListenersRev2.forEach((l) => l({ type: "unsub" })); - } - }; - }; - if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { - return { - get: readAtom, - set: writeAtom, - sub: subscribeAtom, - // store dev methods (these are tentative and subject to change without notice) - dev_subscribe_store: (l, rev) => { - if (rev !== 2) { - console.warn( - "The current StoreListener revision is 2. The older ones are deprecated." - ); - storeListenersRev1.add(l); - return () => { - storeListenersRev1.delete(l); - }; - } - storeListenersRev2.add(l); + if (typeof window !== "undefined" && typeof window.addEventListener === "function") { + storage.subscribe = (key, callback2, initialValue) => { + if (!(getStringStorage() instanceof window.Storage)) { return () => { - storeListenersRev2.delete(l); }; - }, - dev_get_mounted_atoms: () => mountedAtoms.values(), - dev_get_atom_state: (a) => atomStateMap.get(a), - dev_get_mounted: (a) => mountedMap.get(a), - dev_restore_atoms: (values) => { - for (const [atom2, valueOrPromise] of values) { - if (hasInitialValue(atom2)) { - setAtomValueOrPromise(atom2, valueOrPromise); - recomputeDependents(atom2); - } - } - const flushed = flushPending(); - storeListenersRev2.forEach( - (l) => l({ type: "restore", flushed }) - ); } + const storageEventCallback = (e) => { + if (e.storageArea === getStringStorage() && e.key === key) { + let newValue; + try { + newValue = JSON.parse(e.newValue || ""); + } catch { + newValue = initialValue; + } + callback2(newValue); + } + }; + window.addEventListener("storage", storageEventCallback); + return () => { + window.removeEventListener("storage", storageEventCallback); + }; }; } - return { - get: readAtom, - set: writeAtom, - sub: subscribeAtom - }; -}; -var defaultStore; -var getDefaultStore = () => { - if (!defaultStore) { - defaultStore = createStore(); - } - return defaultStore; -}; - -// node_modules/jotai/esm/react.mjs -var import_react2 = __toESM(require_react(), 1); -var StoreContext = (0, import_react2.createContext)(void 0); -var useStore = (options) => { - const store = (0, import_react2.useContext)(StoreContext); - return (options == null ? void 0 : options.store) || store || getDefaultStore(); -}; -var isPromiseLike2 = (x) => typeof (x == null ? void 0 : x.then) === "function"; -var use = import_react2.default.use || ((promise) => { - if (promise.status === "pending") { - throw promise; - } else if (promise.status === "fulfilled") { - return promise.value; - } else if (promise.status === "rejected") { - throw promise.reason; - } else { - promise.status = "pending"; - promise.then( - (v) => { - promise.status = "fulfilled"; - promise.value = v; + return storage; +} +var defaultStorage = createJSONStorage( + () => typeof window !== "undefined" ? window.localStorage : void 0 +); +var cache1$1 = /* @__PURE__ */ new WeakMap(); +var memo1 = (create, dep1) => (cache1$1.has(dep1) ? cache1$1 : cache1$1.set(dep1, create())).get(dep1); +var LOADING = { state: "loading" }; +function loadable(anAtom) { + return memo1(() => { + const loadableCache = /* @__PURE__ */ new WeakMap(); + const refreshAtom = atom(0); + if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { + refreshAtom.debugPrivate = true; + } + const derivedAtom = atom( + (get, { setSelf }) => { + get(refreshAtom); + const promise = get(anAtom); + if (!(promise instanceof Promise)) { + return { state: "hasData", data: promise }; + } + const cached = loadableCache.get(promise); + if (cached) { + return cached; + } + loadableCache.set(promise, LOADING); + promise.then( + (data) => { + loadableCache.set(promise, { state: "hasData", data }); + }, + (error) => { + loadableCache.set(promise, { state: "hasError", error }); + } + ).finally(setSelf); + return LOADING; }, - (e) => { - promise.status = "rejected"; - promise.reason = e; + (_get, set2) => { + set2(refreshAtom, (c) => c + 1); } ); - throw promise; - } -}); -function useAtomValue(atom2, options) { - const store = useStore(options); - const [[valueFromReducer, storeFromReducer, atomFromReducer], rerender] = (0, import_react2.useReducer)( - (prev) => { - const nextValue = store.get(atom2); - if (Object.is(prev[0], nextValue) && prev[1] === store && prev[2] === atom2) { - return prev; - } - return [nextValue, store, atom2]; - }, - void 0, - () => [store.get(atom2), store, atom2] - ); - let value = valueFromReducer; - if (storeFromReducer !== store || atomFromReducer !== atom2) { - rerender(); - value = store.get(atom2); - } - const delay = options == null ? void 0 : options.delay; - (0, import_react2.useEffect)(() => { - const unsub = store.sub(atom2, () => { - if (typeof delay === "number") { - setTimeout(rerender, delay); - return; - } - rerender(); - }); - rerender(); - return unsub; - }, [store, atom2, delay]); - (0, import_react2.useDebugValue)(value); - return isPromiseLike2(value) ? use(value) : value; -} -function useSetAtom(atom2, options) { - const store = useStore(options); - const setAtom = (0, import_react2.useCallback)( - (...args) => { - if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && !("write" in atom2)) { - throw new Error("not writable atom"); - } - return store.set(atom2, ...args); - }, - [store, atom2] - ); - return setAtom; -} -function useAtom(atom2, options) { - return [ - useAtomValue(atom2, options), - // We do wrong type assertion here, which results in throwing an error. - useSetAtom(atom2, options) - ]; -} - -// src/Picker.tsx -var import_jsx_runtime3 = __toESM(require_jsx_runtime(), 1); -function Picker({ - $url, - $options = (0, import_react3.useMemo)(() => atom([]), []), - $isLoading = (0, import_react3.useMemo)(() => atom(true), []), - $isEnabled = (0, import_react3.useMemo)(() => atom(true), []), - $selectedOption = (0, import_react3.useMemo)(() => atom(""), []) -}) { - const url = useAtomValue($url); - const options = useAtomValue($options); - const isLoading = useAtomValue($isLoading); - const [selectedOption, setSelectedOption] = useAtom($selectedOption); - const isEnabled = useAtomValue($isEnabled); - const optionsFetched = useSetAtom((0, import_react3.useMemo)(() => atom(null, (get, set2, options2) => { - set2($options, options2); - set2($isLoading, false); - }), [$options, $isLoading])); - (0, import_react3.useEffect)(() => { - if (isEnabled) { - fetch(url).then((x) => x.json()).catch((err) => ["AAPL", "MSFT", "GOOG"]).then(optionsFetched); + if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") { + derivedAtom.debugPrivate = true; } - }, [url, isEnabled]); - return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "Loading..." }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("select", { value: selectedOption, onChange: (e) => { - setSelectedOption(e.target.value); - }, children: [ - /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "" }, ""), - options.map( - (date) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: date, children: date }, date) - ) - ] }) }); + return atom((get) => get(derivedAtom)); + }, anAtom); } -// src/App.module.css -var App_module_default = { - "app": "App-module__app_gPMrEW__001", - "picker": "App-module__picker_gPMrEW__001" -}; +// src/CalendarPricesChart.tsx +var import_react4 = __toESM(require_react(), 1); +var import_jsx_runtime3 = __toESM(require_jsx_runtime(), 1); +Chart.register(LineElement, plugin_tooltip, plugin_legend, CategoryScale, LinearScale, PointElement); +var $prices = loadable(atom(async (get) => { + const selectedUnderlying = get($selectedUnderlying); + const selectedStrike = get($selectedStrike); + const selectedFrontExpiration = get($selectedFrontExpiration); + const selectedBackExpiration = get($selectedBackExpiration); + if (selectedUnderlying !== "" && selectedStrike !== "" && selectedFrontExpiration !== "" && selectedBackExpiration !== "") { + return await fetch(`${baseUrl}/option_quotes/${selectedUnderlying}/${selectedStrike}/${selectedFrontExpiration}/${selectedBackExpiration}`).then((x) => x.json()).catch(() => []); + } else { + return []; + } +})); +function CalendarPricesChart() { + const prices = useAtomValue($prices); + (0, import_react4.useEffect)(() => { + console.log(prices); + }, [prices]); + if (prices.state === "hasData") { + return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)( + Line, + { + datasetIdKey: "id", + data: { + labels: prices.data.map((x) => x.quote_date.substring(0, 10)), + datasets: [ + { + //@ts-ignore + id: 1, + label: "", + data: prices.data.map((x) => x.price) + } + ] + } + } + ) }); + } else { + return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, {}); + } +} // src/App.tsx var import_jsx_runtime4 = __toESM(require_jsx_runtime(), 1); @@ -36722,19 +36843,7 @@ var $selectedFrontExpiration = atom(""); var $backMonthExpirationPickerUrl = atom((get) => `${baseUrl}/option_quotes/${get($selectedUnderlying)}/${get($selectedQuoteDate)}/expirations`); var $isBackMonthExpirationPickerEnabled = atom((get) => get($selectedQuoteDate) !== "" && get($selectedUnderlying) !== ""); var $selectedBackExpiration = atom(""); -var $prices = atom((get) => { - const selectedUnderlying = get($selectedUnderlying); - const selectedStrike = get($selectedStrike); - const selectedFrontExpiration = get($selectedFrontExpiration); - const selectedBackExpiration = get($selectedBackExpiration); - if (selectedUnderlying !== "" && selectedStrike !== "" && selectedFrontExpiration !== "" && selectedBackExpiration !== "") { - return fetch(`${baseUrl}/option_quotes/${selectedUnderlying}/${selectedStrike}/${selectedFrontExpiration}/${selectedBackExpiration}`).then((x) => x.json()).catch(() => []); - } else { - return Promise.resolve([]); - } -}); function App() { - const prices = useAtomValue($prices); return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: App_module_default.app, children: [ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Header_default, {}), /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: App_module_default.picker, children: [ @@ -36757,7 +36866,7 @@ function App() { /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("label", { children: "Back Expiration" }), /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Picker, { $url: $backMonthExpirationPickerUrl, $isEnabled: $isBackMonthExpirationPickerEnabled, $selectedOption: $selectedBackExpiration }) ] }), - /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(HistoricalImpliedVolatilityChart, {}) + /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CalendarPricesChart, {}) ] }); } var App_default = App; diff --git a/src/App.tsx b/src/App.tsx index 8a8e750..a6f7325 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -2,48 +2,38 @@ import Header from './Header'; import { HistoricalImpliedVolatilityChart } from "./HistoricalImpliedVolatilityChart"; import { Picker } from './Picker'; import { atom as $, useAtomValue } from 'jotai'; +import { loadable } from 'jotai/utils'; //import './index.css'; //@ts-ignore import k from './App.module.css'; +import { useEffect } from 'react'; +import { CalendarPricesChart } from './CalendarPricesChart'; -const baseUrl = 'http://127.0.0.1:8234'; +export const baseUrl = 'http://127.0.0.1:8234'; /* The following are wrapped in atoms to prevent re-creating them if App() re-runs. */ -const $underlyingsUrl = $(`${baseUrl}/option_quotes/underlyings`); -const $selectedUnderlying = $(''); +export const $underlyingsUrl = $(`${baseUrl}/option_quotes/underlyings`); +export const $selectedUnderlying = $(''); -const $quoteDatePickerUrl = $((get) => `${baseUrl}/option_quotes/${get($selectedUnderlying)}/quote_dates`); -const $isQuoteDatePickerEnabled = $((get) => get($selectedUnderlying)!==''); -const $selectedQuoteDate = $(''); +export const $quoteDatePickerUrl = $((get) => `${baseUrl}/option_quotes/${get($selectedUnderlying)}/quote_dates`); +export const $isQuoteDatePickerEnabled = $((get) => get($selectedUnderlying)!==''); +export const $selectedQuoteDate = $(''); -const $strikePickerUrl = $((get) => `${baseUrl}/option_quotes/${get($selectedUnderlying)}/${get($selectedQuoteDate)}/strikes`); -const $isStrikePickerEnabled = $((get) => get($selectedQuoteDate)!=='' && get($selectedUnderlying)!==''); -const $selectedStrike = $(''); +export const $strikePickerUrl = $((get) => `${baseUrl}/option_quotes/${get($selectedUnderlying)}/${get($selectedQuoteDate)}/strikes`); +export const $isStrikePickerEnabled = $((get) => get($selectedQuoteDate)!=='' && get($selectedUnderlying)!==''); +export const $selectedStrike = $(''); -const $frontMonthExpirationPickerUrl = $((get) => `${baseUrl}/option_quotes/${get($selectedUnderlying)}/${get($selectedQuoteDate)}/expirations`); -const $isFrontMonthExpirationPickerEnabled = $((get) => get($selectedQuoteDate)!=='' && get($selectedUnderlying)!==''); -const $selectedFrontExpiration = $(''); +export const $frontMonthExpirationPickerUrl = $((get) => `${baseUrl}/option_quotes/${get($selectedUnderlying)}/${get($selectedQuoteDate)}/expirations`); +export const $isFrontMonthExpirationPickerEnabled = $((get) => get($selectedQuoteDate)!=='' && get($selectedUnderlying)!==''); +export const $selectedFrontExpiration = $(''); + +export const $backMonthExpirationPickerUrl = $((get) => `${baseUrl}/option_quotes/${get($selectedUnderlying)}/${get($selectedQuoteDate)}/expirations`); +export const $isBackMonthExpirationPickerEnabled = $((get) => get($selectedQuoteDate)!=='' && get($selectedUnderlying)!==''); +export const $selectedBackExpiration = $(''); -const $backMonthExpirationPickerUrl = $((get) => `${baseUrl}/option_quotes/${get($selectedUnderlying)}/${get($selectedQuoteDate)}/expirations`); -const $isBackMonthExpirationPickerEnabled = $((get) => get($selectedQuoteDate)!=='' && get($selectedUnderlying)!==''); -const $selectedBackExpiration = $(''); -const $prices = $((get)=>{ - const selectedUnderlying = get($selectedUnderlying); - const selectedStrike = get($selectedStrike); - const selectedFrontExpiration = get($selectedFrontExpiration); - const selectedBackExpiration = get($selectedBackExpiration); - if(selectedUnderlying!=='' && selectedStrike!=='' && selectedFrontExpiration!=='' && selectedBackExpiration!==''){ - return fetch(`${baseUrl}/option_quotes/${selectedUnderlying}/${selectedStrike}/${selectedFrontExpiration}/${selectedBackExpiration}`).then(x=>x.json()).catch(()=>[]); - } - else{ - return Promise.resolve([]); - } -}); function App() { - const prices = useAtomValue($prices); - return (