mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-06-08 14:11:56 -07:00
website: snapshot
This commit is contained in:
-2439
File diff suppressed because it is too large
Load Diff
@@ -1,22 +0,0 @@
|
||||
import { Computation, Queue } from "./core/index.js";
|
||||
import type { Effect } from "./core/index.js";
|
||||
export declare class CollectionQueue extends Queue {
|
||||
_collectionType: number;
|
||||
_nodes: Set<Effect>;
|
||||
_disabled: Computation<boolean>;
|
||||
constructor(type: number);
|
||||
run(type: number): void;
|
||||
notify(node: Effect, type: number, flags: number): any;
|
||||
merge(queue: CollectionQueue): void;
|
||||
}
|
||||
export declare enum BoundaryMode {
|
||||
VISIBLE = "visible",
|
||||
HIDDEN = "hidden"
|
||||
}
|
||||
export declare function createBoundary<T>(fn: () => T, condition: () => BoundaryMode): () => T | undefined;
|
||||
export declare function createSuspense(fn: () => any, fallback: () => any): () => any;
|
||||
export declare function createErrorBoundary<U>(fn: () => any, fallback: (error: unknown, reset: () => void) => U): () => any;
|
||||
export declare function flatten(children: any, options?: {
|
||||
skipNonRendered?: boolean;
|
||||
doNotUnwrap?: boolean;
|
||||
}): any;
|
||||
@@ -1,14 +0,0 @@
|
||||
/**
|
||||
* See https://dev.to/modderme123/super-charging-fine-grained-reactive-performance-47ph
|
||||
* State clean corresponds to a node where all the sources are fully up to date
|
||||
* State check corresponds to a node where some sources (including grandparents) may have changed
|
||||
* State dirty corresponds to a node where the direct parents of a node has changed
|
||||
*/
|
||||
export declare const STATE_CLEAN = 0;
|
||||
export declare const STATE_CHECK = 1;
|
||||
export declare const STATE_DIRTY = 2;
|
||||
export declare const STATE_DISPOSED = 3;
|
||||
export declare const EFFECT_PURE = 0;
|
||||
export declare const EFFECT_RENDER = 1;
|
||||
export declare const EFFECT_USER = 2;
|
||||
export declare const SUPPORTS_PROXY: boolean;
|
||||
@@ -1,162 +0,0 @@
|
||||
/**
|
||||
* Nodes for constructing a graph of reactive values and reactive computations.
|
||||
*
|
||||
* - The graph is acyclic.
|
||||
* - The user inputs new values into the graph by calling .write() on one more computation nodes.
|
||||
* - The user retrieves computed results from the graph by calling .read() on one or more computation nodes.
|
||||
* - The library is responsible for running any necessary computations so that .read() is up to date
|
||||
* with all prior .write() calls anywhere in the graph.
|
||||
* - We call the input nodes 'roots' and the output nodes 'leaves' of the graph here.
|
||||
* - Changes flow from roots to leaves. It would be effective but inefficient to immediately
|
||||
* propagate all changes from a root through the graph to descendant leaves. Instead, we defer
|
||||
* change most change propagation computation until a leaf is accessed. This allows us to
|
||||
* coalesce computations and skip altogether recalculating unused sections of the graph.
|
||||
* - Each computation node tracks its sources and its observers (observers are other
|
||||
* elements that have this node as a source). Source and observer links are updated automatically
|
||||
* as observer computations re-evaluate and call get() on their sources.
|
||||
* - Each node stores a cache state (clean/check/dirty) to support the change propagation algorithm:
|
||||
*
|
||||
* In general, execution proceeds in three passes:
|
||||
*
|
||||
* 1. write() propagates changes down the graph to the leaves
|
||||
* direct children are marked as dirty and their deeper descendants marked as check
|
||||
* (no computations are evaluated)
|
||||
* 2. read() requests that parent nodes updateIfNecessary(), which proceeds recursively up the tree
|
||||
* to decide whether the node is clean (parents unchanged) or dirty (parents changed)
|
||||
* 3. updateIfNecessary() evaluates the computation if the node is dirty (the computations are
|
||||
* executed in root to leaf order)
|
||||
*/
|
||||
import { type Flags } from "./flags.js";
|
||||
import { Owner } from "./owner.js";
|
||||
import { type Transition } from "./scheduler.js";
|
||||
export interface SignalOptions<T> {
|
||||
id?: string;
|
||||
name?: string;
|
||||
equals?: ((prev: T, next: T) => boolean) | false;
|
||||
pureWrite?: boolean;
|
||||
unobserved?: () => void;
|
||||
}
|
||||
export interface SourceType {
|
||||
_observers: ObserverType[] | null;
|
||||
_unobserved?: () => void;
|
||||
_updateIfNecessary: () => void;
|
||||
_stateFlags: Flags;
|
||||
_time: number;
|
||||
_transition?: Transition;
|
||||
_cloned?: Computation;
|
||||
}
|
||||
export interface ObserverType {
|
||||
_sources: SourceType[] | null;
|
||||
_notify: (state: number, skipQueue?: boolean) => void;
|
||||
_handlerMask: Flags;
|
||||
_notifyFlags: (mask: Flags, newFlags: Flags) => void;
|
||||
_time: number;
|
||||
_cloned?: Computation;
|
||||
}
|
||||
/**
|
||||
* Returns the current observer.
|
||||
*/
|
||||
export declare function getObserver(): Computation | null;
|
||||
export declare const UNCHANGED: unique symbol;
|
||||
export type UNCHANGED = typeof UNCHANGED;
|
||||
export declare class Computation<T = any> extends Owner implements SourceType, ObserverType {
|
||||
_sources: SourceType[] | null;
|
||||
_observers: ObserverType[] | null;
|
||||
_value: T | undefined;
|
||||
_error: unknown;
|
||||
_compute: null | ((p?: T) => T);
|
||||
_name: string | undefined;
|
||||
_equals: false | ((a: T, b: T) => boolean);
|
||||
_unobserved: (() => void) | undefined;
|
||||
_pureWrite: boolean;
|
||||
/** Whether the computation is an error or has ancestors that are unresolved */
|
||||
_stateFlags: number;
|
||||
/** Which flags raised by sources are handled, vs. being passed through. */
|
||||
_handlerMask: number;
|
||||
_time: number;
|
||||
_forceNotify: boolean;
|
||||
_transition?: Transition | undefined;
|
||||
_cloned?: Computation;
|
||||
constructor(initialValue: T | undefined, compute: null | ((p?: T) => T), options?: SignalOptions<T>);
|
||||
_read(): T;
|
||||
/**
|
||||
* Return the current value of this computation
|
||||
* Automatically re-executes the surrounding computation when the value changes
|
||||
*/
|
||||
read(): T;
|
||||
/**
|
||||
* Return the current value of this computation
|
||||
* Automatically re-executes the surrounding computation when the value changes
|
||||
*
|
||||
* If the computation has any unresolved ancestors, this function waits for the value to resolve
|
||||
* before continuing
|
||||
*/
|
||||
wait(): T;
|
||||
/** Update the computation with a new value. */
|
||||
write(value: T | ((currentValue: T) => T) | UNCHANGED, flags?: number, raw?: boolean): T;
|
||||
/**
|
||||
* Set the current node's state, and recursively mark all of this node's observers as STATE_CHECK
|
||||
*/
|
||||
_notify(state: number, skipQueue?: boolean): void;
|
||||
/**
|
||||
* Notify the computation that one of its sources has changed flags.
|
||||
*
|
||||
* @param mask A bitmask for which flag(s) were changed.
|
||||
* @param newFlags The source's new flags, masked to just the changed ones.
|
||||
*/
|
||||
_notifyFlags(mask: Flags, newFlags: Flags): void;
|
||||
_setError(error: unknown): void;
|
||||
/**
|
||||
* This is the core part of the reactivity system, which makes sure that the values are updated
|
||||
* before they are read. We've also adapted it to return the loading state of the computation,
|
||||
* so that we can propagate that to the computation's observers.
|
||||
*
|
||||
* This function will ensure that the value and states we read from the computation are up to date
|
||||
*/
|
||||
_updateIfNecessary(): void;
|
||||
/**
|
||||
* Remove ourselves from the owner graph and the computation graph
|
||||
*/
|
||||
_disposeNode(): void;
|
||||
}
|
||||
/**
|
||||
* Reruns a computation's _compute function, producing a new value and keeping track of dependencies.
|
||||
*
|
||||
* It handles the updating of sources and observers, disposal of previous executions,
|
||||
* and error handling if the _compute function throws. It also sets the node as loading
|
||||
* if it reads any parents that are currently loading.
|
||||
*/
|
||||
export declare function update<T>(node: Computation<T>): void;
|
||||
export declare function isEqual<T>(a: T, b: T): boolean;
|
||||
/**
|
||||
* Returns the current value stored inside the given compute function without triggering any
|
||||
* dependencies. Use `untrack` if you want to also disable owner tracking.
|
||||
*/
|
||||
export declare function untrack<T>(fn: () => T): T;
|
||||
/**
|
||||
* Returns true if the given functinon contains signals that have been updated since the last time
|
||||
* the parent computation was run.
|
||||
*/
|
||||
export declare function hasUpdated(fn: () => any): boolean;
|
||||
/**
|
||||
* Returns an accessor that is true if the given function contains async signals that are out of date.
|
||||
*/
|
||||
export declare function isPending(fn: () => any): boolean;
|
||||
export declare function isPending(fn: () => any, loadingValue: boolean): boolean;
|
||||
/**
|
||||
* Attempts to resolve value of expression synchronously returning the last resolved value for any async computation.
|
||||
*/
|
||||
export declare function latest<T>(fn: () => T): T;
|
||||
export declare function latest<T, U>(fn: () => T, fallback: U): T | U;
|
||||
/**
|
||||
* Runs the given function in the given observer.
|
||||
*
|
||||
* Warning: Usually there are simpler ways of modeling a problem that avoid using this function
|
||||
*/
|
||||
export declare function runWithObserver<T>(observer: Computation, run: () => T): T | undefined;
|
||||
/**
|
||||
* A convenient wrapper that calls `compute` with the `owner` and `observer` and is guaranteed
|
||||
* to reset the global context after the computation is finished even if an error is thrown.
|
||||
*/
|
||||
export declare function compute<T>(owner: Owner | null, fn: (val: T) => T, observer: Computation<T>): T;
|
||||
export declare function compute<T>(owner: Owner | null, fn: (val: undefined) => T, observer: null): T;
|
||||
@@ -1,39 +0,0 @@
|
||||
import { EFFECT_RENDER, EFFECT_USER } from "./constants.js";
|
||||
import { Computation, type SignalOptions } from "./core.js";
|
||||
import { type Flags } from "./flags.js";
|
||||
/**
|
||||
* Effects are the leaf nodes of our reactive graph. When their sources change, they are
|
||||
* automatically added to the queue of effects to re-execute, which will cause them to fetch their
|
||||
* sources and recompute
|
||||
*/
|
||||
export declare class Effect<T = any> extends Computation<T> {
|
||||
_effect: (val: T, prev: T | undefined) => void | (() => void);
|
||||
_onerror: ((err: unknown, cleanup: () => void) => void) | undefined;
|
||||
_cleanup: (() => void) | undefined;
|
||||
_modified: boolean;
|
||||
_prevValue: T | undefined;
|
||||
_type: typeof EFFECT_RENDER | typeof EFFECT_USER;
|
||||
constructor(initialValue: T, compute: (val?: T) => T, effect: (val: T, prev: T | undefined) => void | (() => void), error?: (err: unknown) => void | (() => void), options?: SignalOptions<T> & {
|
||||
render?: boolean;
|
||||
defer?: boolean;
|
||||
});
|
||||
write(value: T, flags?: number): T;
|
||||
_notify(state: number, skipQueue?: boolean): void;
|
||||
_notifyFlags(mask: Flags, newFlags: Flags): void;
|
||||
_setError(error: unknown): void;
|
||||
_disposeNode(): void;
|
||||
_run(type: number): void;
|
||||
}
|
||||
export declare class EagerComputation<T = any> extends Computation<T> {
|
||||
constructor(initialValue: T, compute: () => T, options?: SignalOptions<T> & {
|
||||
defer?: boolean;
|
||||
});
|
||||
_notify(state: number, skipQueue?: boolean): void;
|
||||
_run(): void;
|
||||
}
|
||||
export declare class FirewallComputation extends Computation {
|
||||
firewall: boolean;
|
||||
constructor(compute: () => void);
|
||||
_notify(state: number, skipQueue?: boolean): void;
|
||||
_run(): void;
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
export declare class NotReadyError extends Error {
|
||||
}
|
||||
export declare class NoOwnerError extends Error {
|
||||
constructor();
|
||||
}
|
||||
export declare class ContextNotFoundError extends Error {
|
||||
constructor();
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
export type Flags = number;
|
||||
export declare const ERROR_OFFSET = 0;
|
||||
export declare const ERROR_BIT: number;
|
||||
export declare const ERROR: unique symbol;
|
||||
export declare const LOADING_OFFSET = 1;
|
||||
export declare const LOADING_BIT: number;
|
||||
export declare const LOADING: unique symbol;
|
||||
export declare const UNINITIALIZED_OFFSET = 2;
|
||||
export declare const UNINITIALIZED_BIT: number;
|
||||
export declare const UNINITIALIZED: unique symbol;
|
||||
export declare const DEFAULT_FLAGS: number;
|
||||
@@ -1,7 +0,0 @@
|
||||
export { ContextNotFoundError, NoOwnerError, NotReadyError } from "./error.js";
|
||||
export { Owner, createContext, getContext, setContext, hasContext, getOwner, onCleanup, type Context, type ContextRecord, type Disposable } from "./owner.js";
|
||||
export { Computation, getObserver, isEqual, untrack, hasUpdated, isPending, latest, UNCHANGED, compute, runWithObserver, type SignalOptions } from "./core.js";
|
||||
export { Effect, EagerComputation } from "./effect.js";
|
||||
export { flush, Queue, incrementClock, transition, ActiveTransition, type IQueue } from "./scheduler.js";
|
||||
export * from "./constants.js";
|
||||
export * from "./flags.js";
|
||||
@@ -1,95 +0,0 @@
|
||||
/**
|
||||
* Owner tracking is used to enable nested tracking scopes with automatic cleanup.
|
||||
* We also use owners to also keep track of which error handling context we are in.
|
||||
*
|
||||
* If you write the following
|
||||
*
|
||||
* const a = createOwner(() => {
|
||||
* const b = createOwner(() => {});
|
||||
*
|
||||
* const c = createOwner(() => {
|
||||
* const d = createOwner(() => {});
|
||||
* });
|
||||
*
|
||||
* const e = createOwner(() => {});
|
||||
* });
|
||||
*
|
||||
* The owner tree will look like this:
|
||||
*
|
||||
* a
|
||||
* /|\
|
||||
* b-c-e
|
||||
* |
|
||||
* d
|
||||
*
|
||||
* Following the _nextSibling pointers of each owner will first give you its children, and then its siblings (in reverse).
|
||||
* a -> e -> c -> d -> b
|
||||
*
|
||||
* Note that the owner tree is largely orthogonal to the reactivity tree, and is much closer to the component tree.
|
||||
*/
|
||||
import { type IQueue } from "./scheduler.js";
|
||||
export type ContextRecord = Record<string | symbol, unknown>;
|
||||
export interface Disposable {
|
||||
(): void;
|
||||
}
|
||||
/**
|
||||
* Returns the currently executing parent owner.
|
||||
*/
|
||||
export declare function getOwner(): Owner | null;
|
||||
export declare function setOwner(owner: Owner | null): Owner | null;
|
||||
export declare class Owner {
|
||||
_parent: Owner | null;
|
||||
_nextSibling: Owner | null;
|
||||
_prevSibling: Owner | null;
|
||||
_state: number;
|
||||
_disposal: Disposable | Disposable[] | null;
|
||||
_context: ContextRecord;
|
||||
_queue: IQueue;
|
||||
_childCount: number;
|
||||
id: string | null;
|
||||
constructor(id?: string | null, skipAppend?: boolean);
|
||||
append(child: Owner): void;
|
||||
dispose(this: Owner, self?: boolean): void;
|
||||
_disposeNode(): void;
|
||||
emptyDisposal(): void;
|
||||
getNextChildId(): string;
|
||||
}
|
||||
export interface Context<T> {
|
||||
readonly id: symbol;
|
||||
readonly defaultValue: T | undefined;
|
||||
}
|
||||
/**
|
||||
* Context provides a form of dependency injection. It is used to save from needing to pass
|
||||
* data as props through intermediate components. This function creates a new context object
|
||||
* that can be used with `getContext` and `setContext`.
|
||||
*
|
||||
* A default value can be provided here which will be used when a specific value is not provided
|
||||
* via a `setContext` call.
|
||||
*/
|
||||
export declare function createContext<T>(defaultValue?: T, description?: string): Context<T>;
|
||||
/**
|
||||
* Attempts to get a context value for the given key.
|
||||
*
|
||||
* @throws `NoOwnerError` if there's no owner at the time of call.
|
||||
* @throws `ContextNotFoundError` if a context value has not been set yet.
|
||||
*/
|
||||
export declare function getContext<T>(context: Context<T>, owner?: Owner | null): T;
|
||||
/**
|
||||
* Attempts to set a context value on the parent scope with the given key.
|
||||
*
|
||||
* @throws `NoOwnerError` if there's no owner at the time of call.
|
||||
*/
|
||||
export declare function setContext<T>(context: Context<T>, value?: T, owner?: Owner | null): void;
|
||||
/**
|
||||
* Whether the given context is currently defined.
|
||||
*/
|
||||
export declare function hasContext(context: Context<any>, owner?: Owner | null): boolean;
|
||||
/**
|
||||
* Runs an effect once before the reactive scope is disposed
|
||||
* @param fn an effect that should run only once on cleanup
|
||||
*
|
||||
* @returns the same {@link fn} function that was passed in
|
||||
*
|
||||
* @description https://docs.solidjs.com/reference/lifecycle/on-cleanup
|
||||
*/
|
||||
export declare function onCleanup(fn: Disposable): Disposable;
|
||||
@@ -1,86 +0,0 @@
|
||||
import type { Computation, ObserverType, SourceType } from "./core.js";
|
||||
import type { Effect } from "./effect.js";
|
||||
export declare let clock: number;
|
||||
export declare function incrementClock(): void;
|
||||
export declare let ActiveTransition: Transition | null;
|
||||
export declare let Unobserved: SourceType[];
|
||||
export type QueueCallback = (type: number) => void;
|
||||
export interface IQueue {
|
||||
enqueue(type: number, fn: QueueCallback): void;
|
||||
run(type: number): boolean | void;
|
||||
flush(): void;
|
||||
addChild(child: IQueue): void;
|
||||
removeChild(child: IQueue): void;
|
||||
created: number;
|
||||
notify(...args: any[]): boolean;
|
||||
merge(queue: IQueue): void;
|
||||
_parent: IQueue | null;
|
||||
_cloned?: IQueue | undefined;
|
||||
}
|
||||
export declare class Queue implements IQueue {
|
||||
_parent: IQueue | null;
|
||||
_running: boolean;
|
||||
_queues: [QueueCallback[], QueueCallback[]];
|
||||
_children: IQueue[];
|
||||
created: number;
|
||||
enqueue(type: number, fn: QueueCallback): void;
|
||||
run(type: number): void;
|
||||
flush(): void;
|
||||
addChild(child: IQueue): any;
|
||||
removeChild(child: IQueue): any;
|
||||
notify(...args: any[]): boolean;
|
||||
merge(queue: Queue): void;
|
||||
}
|
||||
export declare const globalQueue: Queue;
|
||||
/**
|
||||
* By default, changes are batched on the microtask queue which is an async process. You can flush
|
||||
* the queue synchronously to get the latest updates by calling `flush()`.
|
||||
*/
|
||||
export declare function flush(): void;
|
||||
export declare function removeSourceObservers(node: ObserverType, index: number): void;
|
||||
export declare class Transition implements IQueue {
|
||||
_sources: Map<Computation, Computation>;
|
||||
_pendingNodes: Set<Effect>;
|
||||
_promises: Set<Promise<any>>;
|
||||
_optimistic: Set<(() => void) & {
|
||||
_transition?: Transition;
|
||||
}>;
|
||||
_done: Transition | boolean;
|
||||
_queues: [QueueCallback[], QueueCallback[]];
|
||||
_clonedQueues: Map<Queue, Queue>;
|
||||
_pureQueue: QueueCallback[];
|
||||
_children: IQueue[];
|
||||
_parent: IQueue | null;
|
||||
_running: boolean;
|
||||
_scheduled: boolean;
|
||||
_cloned: Queue;
|
||||
created: number;
|
||||
constructor();
|
||||
enqueue(type: number, fn: QueueCallback): void;
|
||||
run(type: number): void;
|
||||
flush(): void;
|
||||
addChild(child: IQueue): void;
|
||||
removeChild(child: IQueue): void;
|
||||
notify(node: Effect, type: number, flags: number): boolean;
|
||||
merge(queue: Transition): void;
|
||||
schedule(): void;
|
||||
runTransition(fn: () => any | Promise<any>, force?: boolean): void;
|
||||
addOptimistic(fn: (() => void) & {
|
||||
_transition?: Transition;
|
||||
}): void;
|
||||
}
|
||||
/**
|
||||
* Runs the given function in a transition scope, allowing for batch updates and optimizations.
|
||||
* This is useful for grouping multiple state updates together to avoid unnecessary re-renders.
|
||||
*
|
||||
* @param fn A function that receives a resume function to continue the transition.
|
||||
* The resume function can be called with another function to continue the transition.
|
||||
*
|
||||
* @description https://docs.solidjs.com/reference/advanced-reactivity/transition
|
||||
*/
|
||||
export declare function transition(fn: (resume: (fn: () => any | Promise<any>) => void) => any | Promise<any> | Iterable<any>): void;
|
||||
export declare function cloneGraph(node: Computation): Computation;
|
||||
export declare function getOGSource<T extends Computation>(input: T): T;
|
||||
export declare function getTransitionSource<T extends Computation>(input: T): T;
|
||||
export declare function getQueue(node: Computation): IQueue;
|
||||
export declare function initialDispose(node: any): void;
|
||||
@@ -1,6 +0,0 @@
|
||||
export { Computation, ContextNotFoundError, NoOwnerError, NotReadyError, Owner, Queue, createContext, flush, getContext, setContext, hasContext, getOwner, onCleanup, getObserver, isEqual, untrack, hasUpdated, isPending, latest, runWithObserver, transition, SUPPORTS_PROXY } from "./core/index.js";
|
||||
export type { SignalOptions, Context, ContextRecord, Disposable, IQueue } from "./core/index.js";
|
||||
export { mapArray, repeat, type Maybe } from "./map.js";
|
||||
export * from "./signals.js";
|
||||
export * from "./store/index.js";
|
||||
export { createSuspense, createErrorBoundary, createBoundary, flatten, type BoundaryMode } from "./boundaries.js";
|
||||
@@ -1,22 +0,0 @@
|
||||
import type { Accessor } from "./signals.js";
|
||||
export type Maybe<T> = T | void | null | undefined | false;
|
||||
/**
|
||||
* Reactively transforms an array with a callback function - underlying helper for the `<For>` control flow
|
||||
*
|
||||
* similar to `Array.prototype.map`, but gets the value and index as accessors, transforms only values that changed and returns an accessor and reactively tracks changes to the list.
|
||||
*
|
||||
* @description https://docs.solidjs.com/reference/reactive-utilities/map-array
|
||||
*/
|
||||
export declare function mapArray<Item, MappedItem>(list: Accessor<Maybe<readonly Item[]>>, map: (value: Accessor<Item>, index: Accessor<number>) => MappedItem, options?: {
|
||||
keyed?: boolean | ((item: Item) => any);
|
||||
fallback?: Accessor<any>;
|
||||
}): Accessor<MappedItem[]>;
|
||||
/**
|
||||
* Reactively repeats a callback function the count provided - underlying helper for the `<Repeat>` control flow
|
||||
*
|
||||
* @description https://docs.solidjs.com/reference/reactive-utilities/repeat
|
||||
*/
|
||||
export declare function repeat(count: Accessor<number>, map: (index: number) => any, options?: {
|
||||
from?: Accessor<number | undefined>;
|
||||
fallback?: Accessor<any>;
|
||||
}): Accessor<any[]>;
|
||||
@@ -1,180 +0,0 @@
|
||||
import type { SignalOptions } from "./core/index.js";
|
||||
import { Owner } from "./core/index.js";
|
||||
import { type Store, type StoreSetter } from "./store/index.js";
|
||||
export type Accessor<T> = () => T;
|
||||
export type Setter<in out T> = {
|
||||
<U extends T>(...args: undefined extends T ? [] : [value: Exclude<U, Function> | ((prev: T) => U)]): undefined extends T ? undefined : U;
|
||||
<U extends T>(value: (prev: T) => U): U;
|
||||
<U extends T>(value: Exclude<U, Function>): U;
|
||||
<U extends T>(value: Exclude<U, Function> | ((prev: T) => U)): U;
|
||||
};
|
||||
export type Signal<T> = [get: Accessor<T>, set: Setter<T>];
|
||||
export type ComputeFunction<Prev, Next extends Prev = Prev> = (v: Prev) => Next;
|
||||
export type EffectFunction<Prev, Next extends Prev = Prev> = (v: Next, p?: Prev) => (() => void) | void;
|
||||
export type EffectBundle<Prev, Next extends Prev = Prev> = {
|
||||
effect: EffectFunction<Prev, Next>;
|
||||
error: (err: unknown, cleanup: () => void) => void;
|
||||
};
|
||||
export interface EffectOptions {
|
||||
name?: string;
|
||||
defer?: boolean;
|
||||
}
|
||||
export interface MemoOptions<T> {
|
||||
name?: string;
|
||||
equals?: false | ((prev: T, next: T) => boolean);
|
||||
}
|
||||
export type NoInfer<T extends any> = [T][T extends any ? 0 : never];
|
||||
/**
|
||||
* Creates a simple reactive state with a getter and setter
|
||||
* ```typescript
|
||||
* const [state: Accessor<T>, setState: Setter<T>] = createSignal<T>(
|
||||
* value: T,
|
||||
* options?: { name?: string, equals?: false | ((prev: T, next: T) => boolean) }
|
||||
* )
|
||||
* ```
|
||||
* @param value initial value of the state; if empty, the state's type will automatically extended with undefined; otherwise you need to extend the type manually if you want setting to undefined not be an error
|
||||
* @param options optional object with a name for debugging purposes and equals, a comparator function for the previous and next value to allow fine-grained control over the reactivity
|
||||
*
|
||||
* @returns ```typescript
|
||||
* [state: Accessor<T>, setState: Setter<T>]
|
||||
* ```
|
||||
* * the Accessor is a function that returns the current value and registers each call to the reactive root
|
||||
* * the Setter is a function that allows directly setting or mutating the value:
|
||||
* ```typescript
|
||||
* const [count, setCount] = createSignal(0);
|
||||
* setCount(count => count + 1);
|
||||
* ```
|
||||
*
|
||||
* @description https://docs.solidjs.com/reference/basic-reactivity/create-signal
|
||||
*/
|
||||
export declare function createSignal<T>(): Signal<T | undefined>;
|
||||
export declare function createSignal<T>(value: Exclude<T, Function>, options?: SignalOptions<T>): Signal<T>;
|
||||
export declare function createSignal<T>(fn: ComputeFunction<T>, initialValue?: T, options?: SignalOptions<T>): Signal<T>;
|
||||
/**
|
||||
* Creates a readonly derived reactive memoized signal
|
||||
* ```typescript
|
||||
* export function createMemo<T>(
|
||||
* compute: (v: T) => T,
|
||||
* value?: T,
|
||||
* options?: { name?: string, equals?: false | ((prev: T, next: T) => boolean) }
|
||||
* ): () => T;
|
||||
* ```
|
||||
* @param compute a function that receives its previous or the initial value, if set, and returns a new value used to react on a computation
|
||||
* @param value an optional initial value for the computation; if set, fn will never receive undefined as first argument
|
||||
* @param options allows to set a name in dev mode for debugging purposes and use a custom comparison function in equals
|
||||
*
|
||||
* @description https://docs.solidjs.com/reference/basic-reactivity/create-memo
|
||||
*/
|
||||
export declare function createMemo<Next extends Prev, Prev = Next>(compute: ComputeFunction<undefined | NoInfer<Prev>, Next>): Accessor<Next>;
|
||||
export declare function createMemo<Next extends Prev, Init = Next, Prev = Next>(compute: ComputeFunction<Init | Prev, Next>, value: Init, options?: MemoOptions<Next>): Accessor<Next>;
|
||||
/**
|
||||
* Creates a readonly derived async reactive memoized signal
|
||||
* ```typescript
|
||||
* export function createAsync<T>(
|
||||
* compute: (v: T) => Promise<T> | T,
|
||||
* value?: T,
|
||||
* options?: { name?: string, equals?: false | ((prev: T, next: T) => boolean) }
|
||||
* ): () => T;
|
||||
* ```
|
||||
* @param compute a function that receives its previous or the initial value, if set, and returns a new value used to react on a computation
|
||||
* @param value an optional initial value for the computation; if set, fn will never receive undefined as first argument
|
||||
* @param options allows to set a name in dev mode for debugging purposes and use a custom comparison function in equals
|
||||
*
|
||||
* @description https://docs.solidjs.com/reference/basic-reactivity/create-async
|
||||
*/
|
||||
export declare function createAsync<T>(compute: (prev: T | undefined, refreshing: boolean) => Promise<T> | AsyncIterable<T> | T, value?: T, options?: MemoOptions<T>): Accessor<T> & {
|
||||
refresh: () => void;
|
||||
};
|
||||
/**
|
||||
* Creates a reactive effect that runs after the render phase
|
||||
* ```typescript
|
||||
* export function createEffect<T>(
|
||||
* compute: (prev: T) => T,
|
||||
* effect: (v: T, prev: T) => (() => void) | void,
|
||||
* value?: T,
|
||||
* options?: { name?: string }
|
||||
* ): void;
|
||||
* ```
|
||||
* @param compute a function that receives its previous or the initial value, if set, and returns a new value used to react on a computation
|
||||
* @param effect a function that receives the new value and is used to perform side effects, return a cleanup function to run on disposal
|
||||
* @param error an optional function that receives an error if thrown during the computation
|
||||
* @param value an optional initial value for the computation; if set, fn will never receive undefined as first argument
|
||||
* @param options allows to set a name in dev mode for debugging purposes
|
||||
*
|
||||
* @description https://docs.solidjs.com/reference/basic-reactivity/create-effect
|
||||
*/
|
||||
export declare function createEffect<Next>(compute: ComputeFunction<undefined | NoInfer<Next>, Next>, effect: EffectFunction<NoInfer<Next>, Next> | EffectBundle<NoInfer<Next>, Next>): void;
|
||||
export declare function createEffect<Next, Init = Next>(compute: ComputeFunction<Init | Next, Next>, effect: EffectFunction<Next, Next> | EffectBundle<Next, Next>, value: Init, options?: EffectOptions): void;
|
||||
/**
|
||||
* Creates a reactive computation that runs during the render phase as DOM elements are created and updated but not necessarily connected
|
||||
* ```typescript
|
||||
* export function createRenderEffect<T>(
|
||||
* compute: (prev: T) => T,
|
||||
* effect: (v: T, prev: T) => (() => void) | void,
|
||||
* value?: T,
|
||||
* options?: { name?: string }
|
||||
* ): void;
|
||||
* ```
|
||||
* @param compute a function that receives its previous or the initial value, if set, and returns a new value used to react on a computation
|
||||
* @param effect a function that receives the new value and is used to perform side effects
|
||||
* @param value an optional initial value for the computation; if set, fn will never receive undefined as first argument
|
||||
* @param options allows to set a name in dev mode for debugging purposes
|
||||
*
|
||||
* @description https://docs.solidjs.com/reference/secondary-primitives/create-render-effect
|
||||
*/
|
||||
export declare function createRenderEffect<Next>(compute: ComputeFunction<undefined | NoInfer<Next>, Next>, effect: EffectFunction<NoInfer<Next>, Next>): void;
|
||||
export declare function createRenderEffect<Next, Init = Next>(compute: ComputeFunction<Init | Next, Next>, effect: EffectFunction<Next, Next>, value: Init, options?: EffectOptions): void;
|
||||
/**
|
||||
* Creates a new non-tracked reactive context with manual disposal
|
||||
*
|
||||
* @param fn a function in which the reactive state is scoped
|
||||
* @returns the output of `fn`.
|
||||
*
|
||||
* @description https://docs.solidjs.com/reference/reactive-utilities/create-root
|
||||
*/
|
||||
export declare function createRoot<T>(init: ((dispose: () => void) => T) | (() => T), options?: {
|
||||
id: string;
|
||||
}): T;
|
||||
/**
|
||||
* Runs the given function in the given owner to move ownership of nested primitives and cleanups.
|
||||
* This method untracks the current scope.
|
||||
*
|
||||
* Warning: Usually there are simpler ways of modeling a problem that avoid using this function
|
||||
*/
|
||||
export declare function runWithOwner<T>(owner: Owner | null, run: () => T): T;
|
||||
/**
|
||||
* Returns a promise of the resolved value of a reactive expression
|
||||
* @param fn a reactive expression to resolve
|
||||
*/
|
||||
export declare function resolve<T>(fn: () => T): Promise<T>;
|
||||
/** Allows the user to mark a state change as non-urgent.
|
||||
*
|
||||
* @see {@link https://docs.solidjs.com/reference/advanced-reactivity/transition}
|
||||
*
|
||||
* @returns A tuple containing an accessor for the pending state and a function to start a transition.
|
||||
*/
|
||||
export declare function useTransition(): [
|
||||
get: Accessor<boolean>,
|
||||
start: (fn: (resume: (fn: () => any | Promise<any>) => void) => any | Promise<any> | Iterable<any>) => void
|
||||
];
|
||||
/**
|
||||
* Creates an optimistic store that can be used to optimistically update a value
|
||||
* and then revert it back to the previous value at end of transition.
|
||||
* ```typescript
|
||||
* export function createOptimistic<T>(
|
||||
* fn: (store: T) => void,
|
||||
* initial: T,
|
||||
* options?: { key?: string | ((item: NonNullable<any>) => any); all?: boolean }
|
||||
* ): [get: Store<T>, set: StoreSetter<T>];
|
||||
* ```
|
||||
* @param fn a function that receives the current store and can be used to mutate it directly inside a transition
|
||||
* @param initial The initial value of the signal.
|
||||
* @param options Optional signal options.
|
||||
*
|
||||
* @returns A tuple containing an accessor for the current value and a setter function to apply changes.
|
||||
*/
|
||||
export declare function createOptimistic<T extends object = {}>(initial: T | Store<T>): [get: Store<T>, set: StoreSetter<T>];
|
||||
export declare function createOptimistic<T extends object = {}>(fn: (store: T) => void, initial: T | Store<T>, options?: {
|
||||
key?: string | ((item: NonNullable<any>) => any);
|
||||
all?: boolean;
|
||||
}): [get: Store<T>, set: StoreSetter<T>];
|
||||
@@ -1,6 +0,0 @@
|
||||
export type { Store, StoreSetter, StoreNode, NotWrappable, SolidStore } from "./store.js";
|
||||
export type { Merge, Omit } from "./utils.js";
|
||||
export { isWrappable, createStore, deep, $TRACK, $PROXY, $TARGET } from "./store.js";
|
||||
export { createProjection } from "./projection.js";
|
||||
export { reconcile } from "./reconcile.js";
|
||||
export { snapshot, merge, omit } from "./utils.js";
|
||||
@@ -1,7 +0,0 @@
|
||||
import { type Store, type StoreOptions } from "./store.js";
|
||||
/**
|
||||
* Creates a mutable derived value
|
||||
*
|
||||
* @see {@link https://github.com/solidjs/x-reactivity#createprojection}
|
||||
*/
|
||||
export declare function createProjection<T extends Object>(fn: (draft: T) => void | T, initialValue?: T, options?: StoreOptions): Store<T>;
|
||||
@@ -1 +0,0 @@
|
||||
export declare function reconcile<T extends U, U>(value: T, key: string | ((item: NonNullable<any>) => any), all?: boolean): (state: U) => void;
|
||||
@@ -1,37 +0,0 @@
|
||||
import { Computation } from "../core/index.js";
|
||||
export type Store<T> = Readonly<T>;
|
||||
export type StoreSetter<T> = (fn: (state: T) => T | void) => void;
|
||||
export type StoreOptions = {
|
||||
key?: string | ((item: NonNullable<any>) => any);
|
||||
all?: boolean;
|
||||
};
|
||||
type DataNode = Computation<any>;
|
||||
type DataNodes = Record<PropertyKey, DataNode>;
|
||||
export declare const $TRACK: unique symbol, $DEEP: unique symbol, $TARGET: unique symbol, $PROXY: unique symbol, $DELETED: unique symbol;
|
||||
export declare const STORE_VALUE = "v", STORE_OVERRIDE = "o", STORE_NODE = "n", STORE_HAS = "h", STORE_WRAP = "w", STORE_LOOKUP = "l";
|
||||
export type StoreNode = {
|
||||
[$PROXY]: any;
|
||||
[STORE_VALUE]: Record<PropertyKey, any>;
|
||||
[STORE_OVERRIDE]?: Record<PropertyKey, any>;
|
||||
[STORE_NODE]?: DataNodes;
|
||||
[STORE_HAS]?: DataNodes;
|
||||
[STORE_WRAP]?: (value: any, target?: StoreNode) => any;
|
||||
[STORE_LOOKUP]?: WeakMap<any, any>;
|
||||
};
|
||||
export declare namespace SolidStore {
|
||||
interface Unwrappable {
|
||||
}
|
||||
}
|
||||
export type NotWrappable = string | number | bigint | symbol | boolean | Function | null | undefined | SolidStore.Unwrappable[keyof SolidStore.Unwrappable];
|
||||
export declare function createStoreProxy<T extends object>(value: T, traps?: ProxyHandler<StoreNode>, extend?: Record<PropertyKey, any>): any;
|
||||
export declare const storeLookup: WeakMap<object, any>;
|
||||
export declare function wrap<T extends Record<PropertyKey, any>>(value: T, target?: StoreNode): T;
|
||||
export declare function isWrappable<T>(obj: T | NotWrappable): obj is T;
|
||||
export declare function getKeys(source: Record<PropertyKey, any>, override: Record<PropertyKey, any> | undefined, enumerable?: boolean): PropertyKey[];
|
||||
export declare function getPropertyDescriptor(source: Record<PropertyKey, any>, override: Record<PropertyKey, any> | undefined, property: PropertyKey): PropertyDescriptor | undefined;
|
||||
export declare const storeTraps: ProxyHandler<StoreNode>;
|
||||
export declare function storeSetter<T extends object>(store: Store<T>, fn: (draft: T) => T | void): void;
|
||||
export declare function createStore<T extends object = {}>(store: T | Store<T>): [get: Store<T>, set: StoreSetter<T>];
|
||||
export declare function createStore<T extends object = {}>(fn: (store: T) => void, store: T | Store<T>, options?: StoreOptions): [get: Store<T>, set: StoreSetter<T>];
|
||||
export declare function deep<T extends object>(store: Store<T>): Store<T>;
|
||||
export {};
|
||||
@@ -1,36 +0,0 @@
|
||||
/**
|
||||
* Returns a non reactive copy of the store object.
|
||||
* It will attempt to preserver the original reference unless the value has been modified.
|
||||
* @param item store proxy object
|
||||
*/
|
||||
export declare function snapshot<T>(item: T): T;
|
||||
export declare function snapshot<T>(item: T, map?: Map<unknown, unknown>, lookup?: WeakMap<any, any>): T;
|
||||
type DistributeOverride<T, F> = T extends undefined ? F : T;
|
||||
type Override<T, U> = T extends any ? U extends any ? {
|
||||
[K in keyof T]: K extends keyof U ? DistributeOverride<U[K], T[K]> : T[K];
|
||||
} & {
|
||||
[K in keyof U]: K extends keyof T ? DistributeOverride<U[K], T[K]> : U[K];
|
||||
} : T & U : T & U;
|
||||
type OverrideSpread<T, U> = T extends any ? {
|
||||
[K in keyof ({
|
||||
[K in keyof T]: any;
|
||||
} & {
|
||||
[K in keyof U]?: any;
|
||||
} & {
|
||||
[K in U extends any ? keyof U : keyof U]?: any;
|
||||
})]: K extends keyof T ? Exclude<U extends any ? U[K & keyof U] : never, undefined> | T[K] : U extends any ? U[K & keyof U] : never;
|
||||
} : T & U;
|
||||
type Simplify<T> = T extends any ? {
|
||||
[K in keyof T]: T[K];
|
||||
} : T;
|
||||
type _Merge<T extends unknown[], Curr = {}> = T extends [
|
||||
infer Next | (() => infer Next),
|
||||
...infer Rest
|
||||
] ? _Merge<Rest, Override<Curr, Next>> : T extends [...infer Rest, infer Next | (() => infer Next)] ? Override<_Merge<Rest, Curr>, Next> : T extends [] ? Curr : T extends (infer I | (() => infer I))[] ? OverrideSpread<Curr, I> : Curr;
|
||||
export type Merge<T extends unknown[]> = Simplify<_Merge<T>>;
|
||||
export declare function merge<T extends unknown[]>(...sources: T): Merge<T>;
|
||||
export type Omit<T, K extends readonly (keyof T)[]> = {
|
||||
[P in keyof T as Exclude<P, K[number]>]: T[P];
|
||||
};
|
||||
export declare function omit<T extends Record<any, any>, K extends readonly (keyof T)[]>(props: T, ...keys: K): Omit<T, K>;
|
||||
export {};
|
||||
-2132
File diff suppressed because it is too large
Load Diff
@@ -1,25 +0,0 @@
|
||||
import { Queue, type Computed, type Effect } from "./core/index.js";
|
||||
import type { Signal } from "./core/index.js";
|
||||
export interface BoundaryComputed<T> extends Computed<T> {
|
||||
_propagationMask: number;
|
||||
}
|
||||
export declare class CollectionQueue extends Queue {
|
||||
_collectionType: number;
|
||||
_nodes: Set<Effect<any>>;
|
||||
_disabled: Signal<boolean>;
|
||||
_initialized: boolean;
|
||||
constructor(type: number);
|
||||
run(type: number): void;
|
||||
notify(node: Effect<any>, type: number, flags: number): boolean;
|
||||
}
|
||||
export declare const enum BoundaryMode {
|
||||
VISIBLE = "visible",
|
||||
HIDDEN = "hidden"
|
||||
}
|
||||
export declare function createBoundary<T>(fn: () => T, condition: () => BoundaryMode): () => T | undefined;
|
||||
export declare function createLoadBoundary(fn: () => any, fallback: () => any): () => unknown;
|
||||
export declare function createErrorBoundary<U>(fn: () => any, fallback: (error: unknown, reset: () => void) => U): () => unknown;
|
||||
export declare function flatten(children: any, options?: {
|
||||
skipNonRendered?: boolean;
|
||||
doNotUnwrap?: boolean;
|
||||
}): any;
|
||||
@@ -1,18 +0,0 @@
|
||||
export declare const REACTIVE_NONE = 0;
|
||||
export declare const REACTIVE_CHECK: number;
|
||||
export declare const REACTIVE_DIRTY: number;
|
||||
export declare const REACTIVE_RECOMPUTING_DEPS: number;
|
||||
export declare const REACTIVE_IN_HEAP: number;
|
||||
export declare const REACTIVE_IN_HEAP_HEIGHT: number;
|
||||
export declare const REACTIVE_ZOMBIE: number;
|
||||
export declare const REACTIVE_DISPOSED: number;
|
||||
export declare const STATUS_NONE = 0;
|
||||
export declare const STATUS_PENDING: number;
|
||||
export declare const STATUS_ERROR: number;
|
||||
export declare const STATUS_UNINITIALIZED: number;
|
||||
export declare const EFFECT_PURE = 0;
|
||||
export declare const EFFECT_RENDER = 1;
|
||||
export declare const EFFECT_USER = 2;
|
||||
export declare const NOT_PENDING: {};
|
||||
export declare const SUPPORTS_PROXY: boolean;
|
||||
export declare const defaultContext: {};
|
||||
@@ -1,28 +0,0 @@
|
||||
import { type Owner } from "./core.js";
|
||||
export interface Context<T> {
|
||||
readonly id: symbol;
|
||||
readonly defaultValue: T | undefined;
|
||||
}
|
||||
export type ContextRecord = Record<string | symbol, unknown>;
|
||||
/**
|
||||
* Context provides a form of dependency injection. It is used to save from needing to pass
|
||||
* data as props through intermediate components. This function creates a new context object
|
||||
* that can be used with `getContext` and `setContext`.
|
||||
*
|
||||
* A default value can be provided here which will be used when a specific value is not provided
|
||||
* via a `setContext` call.
|
||||
*/
|
||||
export declare function createContext<T>(defaultValue?: T, description?: string): Context<T>;
|
||||
/**
|
||||
* Attempts to get a context value for the given key.
|
||||
*
|
||||
* @throws `NoOwnerError` if there's no owner at the time of call.
|
||||
* @throws `ContextNotFoundError` if a context value has not been set yet.
|
||||
*/
|
||||
export declare function getContext<T>(context: Context<T>, owner?: Owner | null): T;
|
||||
/**
|
||||
* Attempts to set a context value on the parent scope with the given key.
|
||||
*
|
||||
* @throws `NoOwnerError` if there's no owner at the time of call.
|
||||
*/
|
||||
export declare function setContext<T>(context: Context<T>, value?: T, owner?: Owner | null): void;
|
||||
@@ -1,122 +0,0 @@
|
||||
import { NOT_PENDING } from "./constants.js";
|
||||
import { type IQueue, type Transition } from "./scheduler.js";
|
||||
export interface Disposable {
|
||||
(): void;
|
||||
}
|
||||
export interface Link {
|
||||
_dep: Signal<unknown> | Computed<unknown>;
|
||||
_sub: Computed<unknown>;
|
||||
_nextDep: Link | null;
|
||||
_prevSub: Link | null;
|
||||
_nextSub: Link | null;
|
||||
}
|
||||
export interface SignalOptions<T> {
|
||||
id?: string;
|
||||
name?: string;
|
||||
equals?: ((prev: T, next: T) => boolean) | false;
|
||||
pureWrite?: boolean;
|
||||
unobserved?: () => void;
|
||||
lazy?: boolean;
|
||||
}
|
||||
export interface RawSignal<T> {
|
||||
id?: string;
|
||||
_subs: Link | null;
|
||||
_subsTail: Link | null;
|
||||
_value: T;
|
||||
_error?: unknown;
|
||||
_statusFlags: number;
|
||||
_name?: string;
|
||||
_equals: false | ((a: T, b: T) => boolean);
|
||||
_pureWrite?: boolean;
|
||||
_unobserved?: () => void;
|
||||
_time: number;
|
||||
_transition: Transition | null;
|
||||
_pendingValue: T | typeof NOT_PENDING;
|
||||
_pendingCheck?: Signal<boolean> & {
|
||||
_set: (v: boolean) => void;
|
||||
};
|
||||
_pendingSignal?: Signal<T> & {
|
||||
_set: (v: T) => void;
|
||||
};
|
||||
_optimistic?: boolean;
|
||||
}
|
||||
export interface FirewallSignal<T> extends RawSignal<T> {
|
||||
_firewall: Computed<any>;
|
||||
_nextChild: FirewallSignal<unknown> | null;
|
||||
}
|
||||
export type Signal<T> = RawSignal<T> | FirewallSignal<T>;
|
||||
export interface Owner {
|
||||
id?: string;
|
||||
_disposal: Disposable | Disposable[] | null;
|
||||
_parent: Owner | null;
|
||||
_context: Record<symbol | string, unknown>;
|
||||
_childCount: number;
|
||||
_queue: IQueue;
|
||||
_firstChild: Owner | null;
|
||||
_nextSibling: Owner | null;
|
||||
_pendingDisposal: Disposable | Disposable[] | null;
|
||||
_pendingFirstChild: Owner | null;
|
||||
}
|
||||
export interface Computed<T> extends RawSignal<T>, Owner {
|
||||
_deps: Link | null;
|
||||
_depsTail: Link | null;
|
||||
_flags: number;
|
||||
_height: number;
|
||||
_nextHeap: Computed<any> | undefined;
|
||||
_prevHeap: Computed<any>;
|
||||
_fn: (prev?: T) => T;
|
||||
_inFlight: Promise<T> | AsyncIterable<T> | null;
|
||||
_child: FirewallSignal<any> | null;
|
||||
_notifyQueue?: (statusFlagsChanged: boolean, prevStatusFlags: number) => void;
|
||||
}
|
||||
export interface Root extends Owner {
|
||||
_root: true;
|
||||
_parentComputed: Computed<any> | null;
|
||||
dispose(self?: boolean): void;
|
||||
}
|
||||
export declare let context: Owner | null;
|
||||
export declare function recompute(el: Computed<any>, create?: boolean): void;
|
||||
export declare function handleAsync<T>(el: Computed<T>, result: T | Promise<T> | AsyncIterable<T>, setter?: (value: T) => void): T;
|
||||
export declare function dispose(node: Computed<unknown>): void;
|
||||
export declare function getNextChildId(owner: Owner): string;
|
||||
export declare function computed<T>(fn: (prev?: T) => T | Promise<T> | AsyncIterable<T>): Computed<T>;
|
||||
export declare function computed<T>(fn: (prev: T) => T | Promise<T> | AsyncIterable<T>, initialValue?: T, options?: SignalOptions<T>): Computed<T>;
|
||||
export declare function signal<T>(v: T, options?: SignalOptions<T>): Signal<T>;
|
||||
export declare function signal<T>(v: T, options?: SignalOptions<T>, firewall?: Computed<any>): FirewallSignal<T>;
|
||||
export declare function isEqual<T>(a: T, b: T): boolean;
|
||||
/**
|
||||
* Returns the current value stored inside the given compute function without triggering any
|
||||
* dependencies. Use `untrack` if you want to also disable owner tracking.
|
||||
*/
|
||||
export declare function untrack<T>(fn: () => T): T;
|
||||
export declare function read<T>(el: Signal<T> | Computed<T>): T;
|
||||
export declare function setSignal<T>(el: Signal<T> | Computed<T>, v: T | ((prev: T) => T)): T;
|
||||
export declare function getObserver(): Owner | null;
|
||||
export declare function getOwner(): Owner | null;
|
||||
export declare function onCleanup(fn: Disposable): Disposable;
|
||||
export declare function createOwner(options?: {
|
||||
id: string;
|
||||
}): Root;
|
||||
/**
|
||||
* Creates a new non-tracked reactive context with manual disposal
|
||||
*
|
||||
* @param fn a function in which the reactive state is scoped
|
||||
* @returns the output of `fn`.
|
||||
*
|
||||
* @description https://docs.solidjs.com/reference/reactive-utilities/create-root
|
||||
*/
|
||||
export declare function createRoot<T>(init: ((dispose: () => void) => T) | (() => T), options?: {
|
||||
id: string;
|
||||
}): T;
|
||||
/**
|
||||
* Runs the given function in the given owner to move ownership of nested primitives and cleanups.
|
||||
* This method untracks the current scope.
|
||||
*
|
||||
* Warning: Usually there are simpler ways of modeling a problem that avoid using this function
|
||||
*/
|
||||
export declare function runWithOwner<T>(owner: Owner | null, fn: () => T): T;
|
||||
export declare function staleValues<T>(fn: () => T, set?: boolean): T;
|
||||
export declare function pending<T>(fn: () => T): T;
|
||||
export declare function isPending(fn: () => any): boolean;
|
||||
export declare function refresh<T>(fn: () => T): T;
|
||||
export declare function isRefreshing(): boolean;
|
||||
@@ -1,18 +0,0 @@
|
||||
import { type Computed, type Owner, type SignalOptions } from "./core.js";
|
||||
export interface Effect<T> extends Computed<T>, Owner {
|
||||
_effectFn: (val: T, prev: T | undefined) => void | (() => void);
|
||||
_errorFn?: (err: unknown, cleanup: () => void) => void;
|
||||
_cleanup?: () => void;
|
||||
_modified: boolean;
|
||||
_prevValue: T | undefined;
|
||||
_type: number;
|
||||
}
|
||||
/**
|
||||
* Effects are the leaf nodes of our reactive graph. When their sources change, they are
|
||||
* automatically added to the queue of effects to re-execute, which will cause them to fetch their
|
||||
* sources and recompute
|
||||
*/
|
||||
export declare function effect<T>(compute: (prev: T | undefined) => T, effect: (val: T, prev: T | undefined) => void | (() => void), error?: (err: unknown, cleanup: () => void) => void | (() => void), initialValue?: T, options?: SignalOptions<any> & {
|
||||
render?: boolean;
|
||||
defer?: boolean;
|
||||
}): void;
|
||||
@@ -1,10 +0,0 @@
|
||||
export declare class NotReadyError extends Error {
|
||||
cause: any;
|
||||
constructor(cause: any);
|
||||
}
|
||||
export declare class NoOwnerError extends Error {
|
||||
constructor();
|
||||
}
|
||||
export declare class ContextNotFoundError extends Error {
|
||||
constructor();
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import type { Computed } from "./core.js";
|
||||
export interface Heap {
|
||||
_heap: (Computed<unknown> | undefined)[];
|
||||
_marked: boolean;
|
||||
_min: number;
|
||||
_max: number;
|
||||
}
|
||||
export declare function increaseHeapSize(n: number, heap: Heap): void;
|
||||
export declare function insertIntoHeap(n: Computed<any>, heap: Heap): void;
|
||||
export declare function insertIntoHeapHeight(n: Computed<unknown>, heap: Heap): void;
|
||||
export declare function deleteFromHeap(n: Computed<unknown>, heap: Heap): void;
|
||||
export declare function markHeap(heap: Heap): void;
|
||||
export declare function markNode(el: Computed<unknown>, newState?: number): void;
|
||||
export declare function runHeap(heap: Heap, recompute: (el: Computed<unknown>) => void): void;
|
||||
@@ -1,6 +0,0 @@
|
||||
export { ContextNotFoundError, NoOwnerError, NotReadyError } from "./error.js";
|
||||
export { createContext, getContext, setContext, type Context, type ContextRecord } from "./context.js";
|
||||
export { getObserver, isEqual, untrack, getOwner, runWithOwner, createOwner, createRoot, computed, dispose, signal, read, setSignal, onCleanup, getNextChildId, isPending, pending, refresh, isRefreshing, staleValues, handleAsync, type Owner, type Computed, type Root, type Signal, type SignalOptions } from "./core.js";
|
||||
export { effect, type Effect } from "./effect.js";
|
||||
export { flush, Queue, type IQueue, type QueueCallback } from "./scheduler.js";
|
||||
export * from "./constants.js";
|
||||
@@ -1,65 +0,0 @@
|
||||
import type { Computed, Signal } from "./core.js";
|
||||
import { type Heap } from "./heap.js";
|
||||
export declare let optimisticRun: boolean;
|
||||
export declare const dirtyQueue: Heap;
|
||||
export declare const zombieQueue: Heap;
|
||||
export declare let clock: number;
|
||||
export declare let activeTransition: Transition | null;
|
||||
export type QueueCallback = (type: number) => void;
|
||||
type QueueStub = {
|
||||
_queues: [QueueCallback[], QueueCallback[]];
|
||||
_children: QueueStub[];
|
||||
};
|
||||
export interface Transition {
|
||||
time: number;
|
||||
asyncNodes: Computed<any>[];
|
||||
pendingNodes: Signal<any>[];
|
||||
optimisticNodes: Signal<any>[];
|
||||
queueStash: QueueStub;
|
||||
done: boolean;
|
||||
}
|
||||
export declare function schedule(): void;
|
||||
export interface IQueue {
|
||||
enqueue(type: number, fn: QueueCallback): void;
|
||||
run(type: number): boolean | void;
|
||||
addChild(child: IQueue): void;
|
||||
removeChild(child: IQueue): void;
|
||||
created: number;
|
||||
notify(node: Computed<any>, mask: number, flags: number): boolean;
|
||||
stashQueues(stub: QueueStub): void;
|
||||
restoreQueues(stub: QueueStub): void;
|
||||
_parent: IQueue | null;
|
||||
}
|
||||
export declare class Queue implements IQueue {
|
||||
_parent: IQueue | null;
|
||||
_queues: [QueueCallback[], QueueCallback[]];
|
||||
_children: IQueue[];
|
||||
created: number;
|
||||
addChild(child: IQueue): void;
|
||||
removeChild(child: IQueue): void;
|
||||
notify(node: Computed<any>, mask: number, flags: number): boolean;
|
||||
run(type: number): void;
|
||||
enqueue(type: number, fn: QueueCallback): void;
|
||||
stashQueues(stub: QueueStub): void;
|
||||
restoreQueues(stub: QueueStub): void;
|
||||
}
|
||||
export declare class GlobalQueue extends Queue {
|
||||
_running: boolean;
|
||||
_pendingNodes: Signal<any>[];
|
||||
_optimisticNodes: Signal<any>[];
|
||||
static _update: (el: Computed<unknown>) => void;
|
||||
static _dispose: (el: Computed<unknown>, self: boolean, zombie: boolean) => void;
|
||||
flush(): void;
|
||||
notify(node: Computed<any>, mask: number, flags: number): boolean;
|
||||
initTransition(node: Computed<any>): void;
|
||||
}
|
||||
export declare function notifySubs(node: Signal<any> | Computed<any>): void;
|
||||
export declare function runOptimistic(activeTransition?: Transition | null): void;
|
||||
export declare const globalQueue: GlobalQueue;
|
||||
/**
|
||||
* By default, changes are batched on the microtask queue which is an async process. You can flush
|
||||
* the queue synchronously to get the latest updates by calling `flush()`.
|
||||
*/
|
||||
export declare function flush(): void;
|
||||
export declare function runInTransition(el: Computed<unknown>, recompute: (el: Computed<unknown>) => void): void;
|
||||
export {};
|
||||
@@ -1,6 +0,0 @@
|
||||
export { ContextNotFoundError, NoOwnerError, NotReadyError, createContext, createRoot, runWithOwner, flush, getNextChildId, getContext, setContext, getOwner, onCleanup, getObserver, isEqual, untrack, isPending, pending, isRefreshing, refresh, SUPPORTS_PROXY } from "./core/index.js";
|
||||
export type { Owner, SignalOptions, Context, ContextRecord, IQueue } from "./core/index.js";
|
||||
export * from "./signals.js";
|
||||
export { mapArray, repeat, type Maybe } from "./map.js";
|
||||
export * from "./store/index.js";
|
||||
export { createLoadBoundary, createErrorBoundary, createBoundary, flatten, type BoundaryMode } from "./boundaries.js";
|
||||
@@ -1,22 +0,0 @@
|
||||
import { type Accessor } from "./signals.js";
|
||||
export type Maybe<T> = T | void | null | undefined | false;
|
||||
/**
|
||||
* Reactively transforms an array with a callback function - underlying helper for the `<For>` control flow
|
||||
*
|
||||
* similar to `Array.prototype.map`, but gets the value and index as accessors, transforms only values that changed and returns an accessor and reactively tracks changes to the list.
|
||||
*
|
||||
* @description https://docs.solidjs.com/reference/reactive-utilities/map-array
|
||||
*/
|
||||
export declare function mapArray<Item, MappedItem>(list: Accessor<Maybe<readonly Item[]>>, map: (value: Accessor<Item>, index: Accessor<number>) => MappedItem, options?: {
|
||||
keyed?: boolean | ((item: Item) => any);
|
||||
fallback?: Accessor<any>;
|
||||
}): Accessor<MappedItem[]>;
|
||||
/**
|
||||
* Reactively repeats a callback function the count provided - underlying helper for the `<Repeat>` control flow
|
||||
*
|
||||
* @description https://docs.solidjs.com/reference/reactive-utilities/repeat
|
||||
*/
|
||||
export declare function repeat(count: Accessor<number>, map: (index: number) => any, options?: {
|
||||
from?: Accessor<number | undefined>;
|
||||
fallback?: Accessor<any>;
|
||||
}): Accessor<any[]>;
|
||||
@@ -1,143 +0,0 @@
|
||||
import type { SignalOptions } from "./core/index.js";
|
||||
export type Accessor<T> = () => T;
|
||||
export type Setter<in out T> = {
|
||||
<U extends T>(...args: undefined extends T ? [] : [value: Exclude<U, Function> | ((prev: T) => U)]): undefined extends T ? undefined : U;
|
||||
<U extends T>(value: (prev: T) => U): U;
|
||||
<U extends T>(value: Exclude<U, Function>): U;
|
||||
<U extends T>(value: Exclude<U, Function> | ((prev: T) => U)): U;
|
||||
};
|
||||
export type Signal<T> = [get: Accessor<T>, set: Setter<T>];
|
||||
export type ComputeFunction<Prev, Next extends Prev = Prev> = (v: Prev) => Promise<Next> | AsyncIterable<Next> | Next;
|
||||
export type EffectFunction<Prev, Next extends Prev = Prev> = (v: Next, p?: Prev) => (() => void) | void;
|
||||
export type EffectBundle<Prev, Next extends Prev = Prev> = {
|
||||
effect: EffectFunction<Prev, Next>;
|
||||
error: (err: unknown, cleanup: () => void) => void;
|
||||
};
|
||||
export interface EffectOptions {
|
||||
name?: string;
|
||||
defer?: boolean;
|
||||
}
|
||||
export interface MemoOptions<T> {
|
||||
name?: string;
|
||||
equals?: false | ((prev: T, next: T) => boolean);
|
||||
}
|
||||
export type NoInfer<T extends any> = [T][T extends any ? 0 : never];
|
||||
/**
|
||||
* Creates a simple reactive state with a getter and setter
|
||||
* ```typescript
|
||||
* const [state: Accessor<T>, setState: Setter<T>] = createSignal<T>(
|
||||
* value: T,
|
||||
* options?: { name?: string, equals?: false | ((prev: T, next: T) => boolean) }
|
||||
* )
|
||||
* ```
|
||||
* @param value initial value of the state; if empty, the state's type will automatically extended with undefined; otherwise you need to extend the type manually if you want setting to undefined not be an error
|
||||
* @param options optional object with a name for debugging purposes and equals, a comparator function for the previous and next value to allow fine-grained control over the reactivity
|
||||
*
|
||||
* @returns ```typescript
|
||||
* [state: Accessor<T>, setState: Setter<T>]
|
||||
* ```
|
||||
* * the Accessor is a function that returns the current value and registers each call to the reactive root
|
||||
* * the Setter is a function that allows directly setting or mutating the value:
|
||||
* ```typescript
|
||||
* const [count, setCount] = createSignal(0);
|
||||
* setCount(count => count + 1);
|
||||
* ```
|
||||
*
|
||||
* @description https://docs.solidjs.com/reference/basic-reactivity/create-signal
|
||||
*/
|
||||
export declare function createSignal<T>(): Signal<T | undefined>;
|
||||
export declare function createSignal<T>(value: Exclude<T, Function>, options?: SignalOptions<T>): Signal<T>;
|
||||
export declare function createSignal<T>(fn: ComputeFunction<T>, initialValue?: T, options?: SignalOptions<T>): Signal<T>;
|
||||
/**
|
||||
* Creates a readonly derived reactive memoized signal
|
||||
* ```typescript
|
||||
* export function createMemo<T>(
|
||||
* compute: (v: T) => T,
|
||||
* value?: T,
|
||||
* options?: { name?: string, equals?: false | ((prev: T, next: T) => boolean) }
|
||||
* ): () => T;
|
||||
* ```
|
||||
* @param compute a function that receives its previous or the initial value, if set, and returns a new value used to react on a computation
|
||||
* @param value an optional initial value for the computation; if set, fn will never receive undefined as first argument
|
||||
* @param options allows to set a name in dev mode for debugging purposes and use a custom comparison function in equals
|
||||
*
|
||||
* @description https://docs.solidjs.com/reference/basic-reactivity/create-memo
|
||||
*/
|
||||
export declare function createMemo<Next extends Prev, Prev = Next>(compute: ComputeFunction<undefined | NoInfer<Prev>, Next>): Accessor<Next>;
|
||||
export declare function createMemo<Next extends Prev, Init = Next, Prev = Next>(compute: ComputeFunction<Init | Prev, Next>, value: Init, options?: MemoOptions<Next>): Accessor<Next>;
|
||||
/**
|
||||
* Creates a reactive effect that runs after the render phase
|
||||
* ```typescript
|
||||
* export function createEffect<T>(
|
||||
* compute: (prev: T) => T,
|
||||
* effect: (v: T, prev: T) => (() => void) | void,
|
||||
* value?: T,
|
||||
* options?: { name?: string }
|
||||
* ): void;
|
||||
* ```
|
||||
* @param compute a function that receives its previous or the initial value, if set, and returns a new value used to react on a computation
|
||||
* @param effect a function that receives the new value and is used to perform side effects, return a cleanup function to run on disposal
|
||||
* @param error an optional function that receives an error if thrown during the computation
|
||||
* @param value an optional initial value for the computation; if set, fn will never receive undefined as first argument
|
||||
* @param options allows to set a name in dev mode for debugging purposes
|
||||
*
|
||||
* @description https://docs.solidjs.com/reference/basic-reactivity/create-effect
|
||||
*/
|
||||
export declare function createEffect<Next>(compute: ComputeFunction<undefined | NoInfer<Next>, Next>, effectFn: EffectFunction<NoInfer<Next>, Next> | EffectBundle<NoInfer<Next>, Next>): void;
|
||||
export declare function createEffect<Next, Init = Next>(compute: ComputeFunction<Init | Next, Next>, effect: EffectFunction<Next, Next> | EffectBundle<Next, Next>, value: Init, options?: EffectOptions): void;
|
||||
/**
|
||||
* Creates a reactive computation that runs during the render phase as DOM elements are created and updated but not necessarily connected
|
||||
* ```typescript
|
||||
* export function createRenderEffect<T>(
|
||||
* compute: (prev: T) => T,
|
||||
* effect: (v: T, prev: T) => (() => void) | void,
|
||||
* value?: T,
|
||||
* options?: { name?: string }
|
||||
* ): void;
|
||||
* ```
|
||||
* @param compute a function that receives its previous or the initial value, if set, and returns a new value used to react on a computation
|
||||
* @param effect a function that receives the new value and is used to perform side effects
|
||||
* @param value an optional initial value for the computation; if set, fn will never receive undefined as first argument
|
||||
* @param options allows to set a name in dev mode for debugging purposes
|
||||
*
|
||||
* @description https://docs.solidjs.com/reference/secondary-primitives/create-render-effect
|
||||
*/
|
||||
export declare function createRenderEffect<Next>(compute: ComputeFunction<undefined | NoInfer<Next>, Next>, effectFn: EffectFunction<NoInfer<Next>, Next>): void;
|
||||
export declare function createRenderEffect<Next, Init = Next>(compute: ComputeFunction<Init | Next, Next>, effectFn: EffectFunction<Next, Next>, value: Init, options?: EffectOptions): void;
|
||||
/**
|
||||
* Creates a tracked reactive effect that only tracks dependencies inside the effect itself
|
||||
* ```typescript
|
||||
* export function createTrackedEffect(
|
||||
* compute: () => (() => void) | void,
|
||||
* options?: { name?: string, defer?: boolean }
|
||||
* ): void;
|
||||
* ```
|
||||
* @param compute a function that contains reactive reads to track and returns an optional cleanup function to run on disposal or before next execution
|
||||
* @param options allows to set a name in dev mode for debugging purposes
|
||||
*
|
||||
* @description https://docs.solidjs.com/reference/secondary-primitives/create-tracked-effect
|
||||
*/
|
||||
export declare function createTrackedEffect(compute: () => void | (() => void), options?: EffectOptions): void;
|
||||
/**
|
||||
* Creates a reactive computation that runs after the render phase with flexible tracking
|
||||
* ```typescript
|
||||
* export function createReaction(
|
||||
* onInvalidate: () => void,
|
||||
* options?: { name?: string }
|
||||
* ): (fn: () => void) => void;
|
||||
* ```
|
||||
* @param invalidated a function that is called when tracked function is invalidated.
|
||||
* @param options allows to set a name in dev mode for debugging purposes
|
||||
*
|
||||
* @description https://docs.solidjs.com/reference/secondary-primitives/create-reaction
|
||||
*/
|
||||
export declare function createReaction(effectFn: EffectFunction<undefined> | EffectBundle<undefined>, options?: EffectOptions): (tracking: () => void) => void;
|
||||
/**
|
||||
* Returns a promise of the resolved value of a reactive expression
|
||||
* @param fn a reactive expression to resolve
|
||||
*/
|
||||
export declare function resolve<T>(fn: () => T): Promise<T>;
|
||||
export declare function createOptimistic<T>(): Signal<T | undefined>;
|
||||
export declare function createOptimistic<T>(value: Exclude<T, Function>, options?: SignalOptions<T>): Signal<T>;
|
||||
export declare function createOptimistic<T>(fn: ComputeFunction<T>, initialValue?: T, options?: SignalOptions<T>): Signal<T>;
|
||||
export declare function onSettled(callback: () => void | (() => void)): void;
|
||||
@@ -1,7 +0,0 @@
|
||||
export type { Store, StoreSetter, StoreNode, NotWrappable, SolidStore } from "./store.js";
|
||||
export type { Merge, Omit } from "./utils.js";
|
||||
export { isWrappable, createStore, deep, $TRACK, $PROXY, $TARGET } from "./store.js";
|
||||
export { createProjection } from "./projection.js";
|
||||
export { createOptimisticStore } from "./optimistic.js";
|
||||
export { reconcile } from "./reconcile.js";
|
||||
export { snapshot, merge, omit } from "./utils.js";
|
||||
@@ -1,22 +0,0 @@
|
||||
import { type Store, type StoreSetter } from "./store.js";
|
||||
/**
|
||||
* Creates an optimistic store that can be used to optimistically update a value
|
||||
* and then revert it back to the previous value at end of transition.
|
||||
* ```typescript
|
||||
* export function createOptimistic<T>(
|
||||
* fn: (store: T) => void,
|
||||
* initial: T,
|
||||
* options?: { key?: string | ((item: NonNullable<any>) => any); all?: boolean }
|
||||
* ): [get: Store<T>, set: StoreSetter<T>];
|
||||
* ```
|
||||
* @param fn a function that receives the current store and can be used to mutate it directly inside a transition
|
||||
* @param initial The initial value of the signal.
|
||||
* @param options Optional signal options.
|
||||
*
|
||||
* @returns A tuple containing an accessor for the current value and a setter function to apply changes.
|
||||
*/
|
||||
export declare function createOptimisticStore<T extends object = {}>(initial: T | Store<T>): [get: Store<T>, set: StoreSetter<T>];
|
||||
export declare function createOptimisticStore<T extends object = {}>(fn: (store: T) => T | void, initial: T | Store<T>, options?: {
|
||||
key?: string | ((item: NonNullable<any>) => any);
|
||||
all?: boolean;
|
||||
}): [get: Store<T>, set: StoreSetter<T>];
|
||||
@@ -1,11 +0,0 @@
|
||||
import { type Store, type StoreOptions } from "./store.js";
|
||||
export declare function createProjectionInternal<T extends object = {}>(fn: (draft: T) => void | T | Promise<void | T> | AsyncIterable<void | T>, initialValue?: T, options?: StoreOptions): {
|
||||
store: Readonly<T>;
|
||||
node: any;
|
||||
};
|
||||
/**
|
||||
* Creates a mutable derived value
|
||||
*
|
||||
* @see {@link https://github.com/solidjs/x-reactivity#createprojection}
|
||||
*/
|
||||
export declare function createProjection<T extends Object = {}>(fn: (draft: T) => void | T | Promise<void | T> | AsyncIterable<void | T>, initialValue?: T, options?: StoreOptions): Store<T>;
|
||||
@@ -1 +0,0 @@
|
||||
export declare function reconcile<T extends U, U>(value: T, key: string | ((item: NonNullable<any>) => any), all?: boolean): (state: U) => void;
|
||||
@@ -1,38 +0,0 @@
|
||||
import { type Computed, type Signal } from "../core/index.js";
|
||||
export type Store<T> = Readonly<T>;
|
||||
export type StoreSetter<T> = (fn: (state: T) => T | void) => void;
|
||||
export type StoreOptions = {
|
||||
key?: string | ((item: NonNullable<any>) => any);
|
||||
all?: boolean;
|
||||
};
|
||||
type DataNode = Signal<any>;
|
||||
type DataNodes = Record<PropertyKey, DataNode>;
|
||||
export declare const $TRACK: unique symbol, $DEEP: unique symbol, $TARGET: unique symbol, $PROXY: unique symbol, $DELETED: unique symbol;
|
||||
export declare const STORE_VALUE = "v", STORE_OVERRIDE = "o", STORE_NODE = "n", STORE_HAS = "h", STORE_WRAP = "w", STORE_LOOKUP = "l", STORE_FIREWALL = "f";
|
||||
export type StoreNode = {
|
||||
[$PROXY]: any;
|
||||
[STORE_VALUE]: Record<PropertyKey, any>;
|
||||
[STORE_OVERRIDE]?: Record<PropertyKey, any>;
|
||||
[STORE_NODE]?: DataNodes;
|
||||
[STORE_HAS]?: DataNodes;
|
||||
[STORE_WRAP]?: (value: any, target?: StoreNode) => any;
|
||||
[STORE_LOOKUP]?: WeakMap<any, any>;
|
||||
[STORE_FIREWALL]?: () => Computed<any>;
|
||||
};
|
||||
export declare namespace SolidStore {
|
||||
interface Unwrappable {
|
||||
}
|
||||
}
|
||||
export type NotWrappable = string | number | bigint | symbol | boolean | Function | null | undefined | SolidStore.Unwrappable[keyof SolidStore.Unwrappable];
|
||||
export declare function createStoreProxy<T extends object>(value: T, traps?: ProxyHandler<StoreNode>, extend?: Record<PropertyKey, any>): any;
|
||||
export declare const storeLookup: WeakMap<object, any>;
|
||||
export declare function wrap<T extends Record<PropertyKey, any>>(value: T, target?: StoreNode): T;
|
||||
export declare function isWrappable<T>(obj: T | NotWrappable): obj is T;
|
||||
export declare function getKeys(source: Record<PropertyKey, any>, override: Record<PropertyKey, any> | undefined, enumerable?: boolean): PropertyKey[];
|
||||
export declare function getPropertyDescriptor(source: Record<PropertyKey, any>, override: Record<PropertyKey, any> | undefined, property: PropertyKey): PropertyDescriptor | undefined;
|
||||
export declare const storeTraps: ProxyHandler<StoreNode>;
|
||||
export declare function storeSetter<T extends object>(store: Store<T>, fn: (draft: T) => T | void): void;
|
||||
export declare function createStore<T extends object = {}>(store: T | Store<T>): [get: Store<T>, set: StoreSetter<T>];
|
||||
export declare function createStore<T extends object = {}>(fn: (store: T) => void | T | Promise<void | T> | AsyncIterable<void | T>, store: T | Store<T>, options?: StoreOptions): [get: Store<T>, set: StoreSetter<T>];
|
||||
export declare function deep<T extends object>(store: Store<T>): Store<T>;
|
||||
export {};
|
||||
@@ -1,36 +0,0 @@
|
||||
/**
|
||||
* Returns a non reactive copy of the store object.
|
||||
* It will attempt to preserver the original reference unless the value has been modified.
|
||||
* @param item store proxy object
|
||||
*/
|
||||
export declare function snapshot<T>(item: T): T;
|
||||
export declare function snapshot<T>(item: T, map?: Map<unknown, unknown>, lookup?: WeakMap<any, any>): T;
|
||||
type DistributeOverride<T, F> = T extends undefined ? F : T;
|
||||
type Override<T, U> = T extends any ? U extends any ? {
|
||||
[K in keyof T]: K extends keyof U ? DistributeOverride<U[K], T[K]> : T[K];
|
||||
} & {
|
||||
[K in keyof U]: K extends keyof T ? DistributeOverride<U[K], T[K]> : U[K];
|
||||
} : T & U : T & U;
|
||||
type OverrideSpread<T, U> = T extends any ? {
|
||||
[K in keyof ({
|
||||
[K in keyof T]: any;
|
||||
} & {
|
||||
[K in keyof U]?: any;
|
||||
} & {
|
||||
[K in U extends any ? keyof U : keyof U]?: any;
|
||||
})]: K extends keyof T ? Exclude<U extends any ? U[K & keyof U] : never, undefined> | T[K] : U extends any ? U[K & keyof U] : never;
|
||||
} : T & U;
|
||||
type Simplify<T> = T extends any ? {
|
||||
[K in keyof T]: T[K];
|
||||
} : T;
|
||||
type _Merge<T extends unknown[], Curr = {}> = T extends [
|
||||
infer Next | (() => infer Next),
|
||||
...infer Rest
|
||||
] ? _Merge<Rest, Override<Curr, Next>> : T extends [...infer Rest, infer Next | (() => infer Next)] ? Override<_Merge<Rest, Curr>, Next> : T extends [] ? Curr : T extends (infer I | (() => infer I))[] ? OverrideSpread<Curr, I> : Curr;
|
||||
export type Merge<T extends unknown[]> = Simplify<_Merge<T>>;
|
||||
export declare function merge<T extends unknown[]>(...sources: T): Merge<T>;
|
||||
export type Omit<T, K extends readonly (keyof T)[]> = {
|
||||
[P in keyof T as Exclude<P, K[number]>]: T[P];
|
||||
};
|
||||
export declare function omit<T extends Record<any, any>, K extends readonly (keyof T)[]>(props: T, ...keys: K): Omit<T, K>;
|
||||
export {};
|
||||
@@ -405,7 +405,6 @@ main() {
|
||||
# Run the main function with all arguments
|
||||
# main "$@"
|
||||
|
||||
main "@solidjs/signals"
|
||||
main "@leeoniya/ufuzzy"
|
||||
main "lean-qr"
|
||||
main "lightweight-charts"
|
||||
|
||||
@@ -3,12 +3,10 @@
|
||||
*
|
||||
* @import { IChartApi, ISeriesApi as _ISeriesApi, SeriesDefinition, SingleValueData as _SingleValueData, CandlestickData as _CandlestickData, BaselineData as _BaselineData, HistogramData as _HistogramData, SeriesType as LCSeriesType, IPaneApi, LineSeriesPartialOptions as _LineSeriesPartialOptions, HistogramSeriesPartialOptions as _HistogramSeriesPartialOptions, BaselineSeriesPartialOptions as _BaselineSeriesPartialOptions, CandlestickSeriesPartialOptions as _CandlestickSeriesPartialOptions, WhitespaceData, DeepPartial, ChartOptions, Time, LineData as _LineData, createChart as CreateLCChart, LineStyle, createSeriesMarkers as CreateSeriesMarkers, SeriesMarker, ISeriesMarkersPluginApi } from './modules/lightweight-charts/5.1.0/dist/typings.js'
|
||||
*
|
||||
* @import { Signal, Signals, Accessor } from "./signals.js";
|
||||
*
|
||||
* @import * as Brk from "./modules/brk-client/index.js"
|
||||
* @import { BrkClient, Index, Metric, MetricData } from "./modules/brk-client/index.js"
|
||||
*
|
||||
* @import { Resources, MetricResource } from './resources.js'
|
||||
* @import { Options } from './options/full.js'
|
||||
*
|
||||
* @import { PersistedValue } from './utils/persisted.js'
|
||||
*
|
||||
|
||||
+195
-399
@@ -1,11 +1,13 @@
|
||||
import { webSockets } from "./utils/ws.js";
|
||||
import * as formatters from "./utils/format.js";
|
||||
import { onFirstIntersection, getElementById, isHidden } from "./utils/dom.js";
|
||||
import signals from "./signals.js";
|
||||
import { BrkClient } from "./modules/brk-client/index.js";
|
||||
import { initOptions } from "./options/full.js";
|
||||
import ufuzzy from "./modules/leeoniya-ufuzzy/1.0.19/dist/uFuzzy.mjs";
|
||||
import { init as initChart } from "./panes/chart.js";
|
||||
import {
|
||||
init as initChart,
|
||||
setOption as setChartOption,
|
||||
} from "./panes/chart.js";
|
||||
import { initSearch } from "./panes/search.js";
|
||||
import { next } from "./utils/timing.js";
|
||||
import { replaceHistory } from "./utils/url.js";
|
||||
import { removeStored, writeToStorage } from "./utils/storage.js";
|
||||
@@ -19,8 +21,6 @@ import {
|
||||
navElement,
|
||||
navLabelElement,
|
||||
searchElement,
|
||||
searchInput,
|
||||
searchResultsElement,
|
||||
style,
|
||||
} from "./utils/elements.js";
|
||||
|
||||
@@ -106,427 +106,223 @@ function initFrameSelectors() {
|
||||
}
|
||||
initFrameSelectors();
|
||||
|
||||
signals.createRoot(() => {
|
||||
const brk = new BrkClient("https://next.bitview.space");
|
||||
// const brk = new BrkClient("/");
|
||||
const owner = signals.getOwner();
|
||||
const brk = new BrkClient("https://next.bitview.space");
|
||||
// const brk = new BrkClient("/");
|
||||
|
||||
console.log(`VERSION = ${brk.VERSION}`);
|
||||
console.log(`VERSION = ${brk.VERSION}`);
|
||||
|
||||
webSockets.kraken1dCandle.onLatest((latest) => {
|
||||
console.log("close:", latest.close);
|
||||
window.document.title = `${latest.close.toLocaleString("en-us")} | ${window.location.host}`;
|
||||
});
|
||||
webSockets.kraken1dCandle.onLatest((latest) => {
|
||||
console.log("close:", latest.close);
|
||||
window.document.title = `${latest.close.toLocaleString("en-us")} | ${window.location.host}`;
|
||||
});
|
||||
|
||||
// function createLastHeightResource() {
|
||||
// const lastHeight = signals.createSignal(0);
|
||||
// function fetchLastHeight() {
|
||||
// utils.api.fetchLast(
|
||||
// (h) => {
|
||||
// lastHeight.set(h);
|
||||
// },
|
||||
// /** @satisfies {Height} */ (5),
|
||||
// "height",
|
||||
// );
|
||||
// }
|
||||
// fetchLastHeight();
|
||||
// setInterval(fetchLastHeight, 10_000);
|
||||
// return lastHeight;
|
||||
// }
|
||||
// const lastHeight = createLastHeightResource();
|
||||
const options = initOptions(brk);
|
||||
|
||||
const options = initOptions({
|
||||
signals,
|
||||
brk,
|
||||
});
|
||||
window.addEventListener("popstate", (_event) => {
|
||||
const path = window.document.location.pathname.split("/").filter((v) => v);
|
||||
let folder = options.tree;
|
||||
|
||||
window.addEventListener("popstate", (_event) => {
|
||||
const path = window.document.location.pathname.split("/").filter((v) => v);
|
||||
let folder = options.tree;
|
||||
|
||||
while (path.length) {
|
||||
const id = path.shift();
|
||||
const res = folder.find((v) => id === formatters.stringToId(v.name));
|
||||
if (!res) throw "Option not found";
|
||||
if (path.length >= 1) {
|
||||
if (!("tree" in res)) {
|
||||
throw "Unreachable";
|
||||
}
|
||||
folder = res.tree;
|
||||
} else {
|
||||
if ("tree" in res) {
|
||||
throw "Unreachable";
|
||||
}
|
||||
options.selected.set(res);
|
||||
while (path.length) {
|
||||
const id = path.shift();
|
||||
const res = folder.find((v) => id === formatters.stringToId(v.name));
|
||||
if (!res) throw "Option not found";
|
||||
if (path.length >= 1) {
|
||||
if (!("tree" in res)) {
|
||||
throw "Unreachable";
|
||||
}
|
||||
folder = res.tree;
|
||||
} else {
|
||||
if ("tree" in res) {
|
||||
throw "Unreachable";
|
||||
}
|
||||
options.selected.set(res);
|
||||
}
|
||||
});
|
||||
|
||||
function initSelected() {
|
||||
let firstRun = true;
|
||||
function initSelectedFrame() {
|
||||
if (!firstRun) throw Error("Unreachable");
|
||||
firstRun = false;
|
||||
|
||||
const owner = signals.getOwner();
|
||||
|
||||
const chartOption = signals.createSignal(
|
||||
/** @type {ChartOption | null} */ (null),
|
||||
);
|
||||
|
||||
let previousElement = /** @type {HTMLElement | undefined} */ (undefined);
|
||||
let firstTimeLoadingChart = true;
|
||||
|
||||
signals.createScopedEffect(options.selected, (option) => {
|
||||
/** @type {HTMLElement | undefined} */
|
||||
let element;
|
||||
|
||||
switch (option.kind) {
|
||||
case "chart": {
|
||||
element = chartElement;
|
||||
|
||||
chartOption.set(option);
|
||||
|
||||
if (firstTimeLoadingChart) {
|
||||
signals.runWithOwner(owner, () =>
|
||||
initChart({
|
||||
option: /** @type {Accessor<ChartOption>} */ (chartOption),
|
||||
brk,
|
||||
}),
|
||||
);
|
||||
}
|
||||
firstTimeLoadingChart = false;
|
||||
|
||||
break;
|
||||
}
|
||||
case "link": {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!element) throw "Element should be set";
|
||||
|
||||
if (element !== previousElement) {
|
||||
if (previousElement) previousElement.hidden = true;
|
||||
element.hidden = false;
|
||||
}
|
||||
|
||||
if (!previousElement) {
|
||||
replaceHistory({ pathname: option.path });
|
||||
}
|
||||
|
||||
previousElement = element;
|
||||
});
|
||||
}
|
||||
|
||||
function createMobileSwitchEffect() {
|
||||
let firstRun = true;
|
||||
signals.createEffect(options.selected, () => {
|
||||
if (!firstRun && !isHidden(asideLabelElement)) {
|
||||
asideLabelElement.click();
|
||||
}
|
||||
firstRun = false;
|
||||
});
|
||||
}
|
||||
createMobileSwitchEffect();
|
||||
|
||||
onFirstIntersection(asideElement, () =>
|
||||
signals.runWithOwner(owner, initSelectedFrame),
|
||||
);
|
||||
}
|
||||
initSelected();
|
||||
});
|
||||
|
||||
onFirstIntersection(navElement, async () => {
|
||||
options.parent.set(navElement);
|
||||
function initSelected() {
|
||||
let firstRun = true;
|
||||
function initSelectedFrame() {
|
||||
if (!firstRun) throw Error("Unreachable");
|
||||
firstRun = false;
|
||||
|
||||
const option = options.selected();
|
||||
if (!option) throw "Selected should be set by now";
|
||||
const path = [...option.path];
|
||||
let previousElement = /** @type {HTMLElement | undefined} */ (undefined);
|
||||
let firstTimeLoadingChart = true;
|
||||
|
||||
/** @type {HTMLUListElement | null} */
|
||||
let ul = /** @type {any} */ (null);
|
||||
async function getFirstChild() {
|
||||
try {
|
||||
ul = /** @type {HTMLUListElement} */ (navElement.firstElementChild);
|
||||
await next();
|
||||
if (!ul) {
|
||||
await getFirstChild();
|
||||
options.selected.onChange((option) => {
|
||||
/** @type {HTMLElement | undefined} */
|
||||
let element;
|
||||
|
||||
switch (option.kind) {
|
||||
case "chart": {
|
||||
element = chartElement;
|
||||
|
||||
if (firstTimeLoadingChart) {
|
||||
initChart(brk);
|
||||
}
|
||||
firstTimeLoadingChart = false;
|
||||
|
||||
setChartOption(option);
|
||||
|
||||
break;
|
||||
}
|
||||
} catch (_) {
|
||||
await next();
|
||||
await getFirstChild();
|
||||
}
|
||||
}
|
||||
await getFirstChild();
|
||||
if (!ul) throw Error("Unreachable");
|
||||
|
||||
while (path.length > 1) {
|
||||
const name = path.shift();
|
||||
if (!name) throw "Unreachable";
|
||||
/** @type {HTMLDetailsElement[]} */
|
||||
let detailsList = [];
|
||||
while (!detailsList.length) {
|
||||
detailsList = Array.from(ul.querySelectorAll(":scope > li > details"));
|
||||
if (!detailsList.length) {
|
||||
await next();
|
||||
}
|
||||
}
|
||||
const details = detailsList.find((s) => s.dataset.name == name);
|
||||
if (!details) return;
|
||||
details.open = true;
|
||||
ul = null;
|
||||
while (!ul) {
|
||||
const uls = /** @type {HTMLUListElement[]} */ (
|
||||
Array.from(details.querySelectorAll(":scope > ul"))
|
||||
);
|
||||
if (!uls.length) {
|
||||
await next();
|
||||
} else if (uls.length > 1) {
|
||||
throw "Shouldn't be possible";
|
||||
} else {
|
||||
ul = /** @type {HTMLUListElement} */ (uls.pop());
|
||||
}
|
||||
}
|
||||
}
|
||||
/** @type {HTMLAnchorElement[]} */
|
||||
let anchors = [];
|
||||
while (!anchors.length) {
|
||||
anchors = Array.from(ul.querySelectorAll(":scope > li > a"));
|
||||
if (!anchors.length) {
|
||||
await next();
|
||||
}
|
||||
}
|
||||
anchors
|
||||
.find((a) => a.getAttribute("href") == window.document.location.pathname)
|
||||
?.scrollIntoView({
|
||||
behavior: "instant",
|
||||
block: "center",
|
||||
});
|
||||
});
|
||||
|
||||
onFirstIntersection(searchElement, () => {
|
||||
console.log("search: init");
|
||||
|
||||
const haystack = options.list.map((option) => option.title);
|
||||
|
||||
const RESULTS_PER_PAGE = 100;
|
||||
|
||||
/**
|
||||
* @param {uFuzzy.SearchResult} searchResult
|
||||
* @param {number} pageIndex
|
||||
*/
|
||||
function computeResultPage(searchResult, pageIndex) {
|
||||
/** @type {{ option: Option, title: string }[]} */
|
||||
let list = [];
|
||||
|
||||
let [indexes, _info, order] = searchResult || [null, null, null];
|
||||
|
||||
const minIndex = pageIndex * RESULTS_PER_PAGE;
|
||||
|
||||
if (indexes?.length) {
|
||||
const maxIndex = Math.min(
|
||||
(order || indexes).length - 1,
|
||||
minIndex + RESULTS_PER_PAGE - 1,
|
||||
);
|
||||
|
||||
list = Array(maxIndex - minIndex + 1);
|
||||
|
||||
for (let i = minIndex; i <= maxIndex; i++) {
|
||||
let index = indexes[i];
|
||||
|
||||
const title = haystack[index];
|
||||
|
||||
list[i % 100] = {
|
||||
option: options.list[index],
|
||||
title,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/** @type {uFuzzy.Options} */
|
||||
const config = {
|
||||
intraIns: Infinity,
|
||||
intraChars: `[a-z\d' ]`,
|
||||
};
|
||||
|
||||
const fuzzyMultiInsert = /** @type {uFuzzy} */ (
|
||||
ufuzzy({
|
||||
intraIns: 1,
|
||||
})
|
||||
);
|
||||
const fuzzyMultiInsertFuzzier = /** @type {uFuzzy} */ (ufuzzy(config));
|
||||
const fuzzySingleError = /** @type {uFuzzy} */ (
|
||||
ufuzzy({
|
||||
intraMode: 1,
|
||||
...config,
|
||||
})
|
||||
);
|
||||
const fuzzySingleErrorFuzzier = /** @type {uFuzzy} */ (
|
||||
ufuzzy({
|
||||
intraMode: 1,
|
||||
...config,
|
||||
})
|
||||
);
|
||||
|
||||
/** @type {VoidFunction | undefined} */
|
||||
let dispose;
|
||||
|
||||
function inputEvent() {
|
||||
signals.createRoot((_dispose) => {
|
||||
const needle = /** @type {string} */ (searchInput.value);
|
||||
|
||||
dispose?.();
|
||||
|
||||
dispose = _dispose;
|
||||
|
||||
searchResultsElement.scrollTo({
|
||||
top: 0,
|
||||
});
|
||||
|
||||
if (!needle) {
|
||||
searchResultsElement.innerHTML = "";
|
||||
case "link": {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const outOfOrder = 5;
|
||||
const infoThresh = 5_000;
|
||||
if (!element) throw "Element should be set";
|
||||
|
||||
let result = fuzzyMultiInsert?.search(
|
||||
haystack,
|
||||
needle,
|
||||
undefined,
|
||||
infoThresh,
|
||||
);
|
||||
if (element !== previousElement) {
|
||||
if (previousElement) previousElement.hidden = true;
|
||||
element.hidden = false;
|
||||
}
|
||||
|
||||
if (!result?.[0]?.length || !result?.[1]) {
|
||||
result = fuzzyMultiInsert?.search(
|
||||
haystack,
|
||||
needle,
|
||||
outOfOrder,
|
||||
infoThresh,
|
||||
);
|
||||
}
|
||||
if (!previousElement) {
|
||||
replaceHistory({ pathname: option.path });
|
||||
}
|
||||
|
||||
if (!result?.[0]?.length || !result?.[1]) {
|
||||
result = fuzzySingleError?.search(
|
||||
haystack,
|
||||
needle,
|
||||
outOfOrder,
|
||||
infoThresh,
|
||||
);
|
||||
}
|
||||
previousElement = element;
|
||||
});
|
||||
}
|
||||
|
||||
if (!result?.[0]?.length || !result?.[1]) {
|
||||
result = fuzzySingleErrorFuzzier?.search(
|
||||
haystack,
|
||||
needle,
|
||||
outOfOrder,
|
||||
infoThresh,
|
||||
);
|
||||
}
|
||||
|
||||
if (!result?.[0]?.length || !result?.[1]) {
|
||||
result = fuzzyMultiInsertFuzzier?.search(
|
||||
haystack,
|
||||
needle,
|
||||
undefined,
|
||||
infoThresh,
|
||||
);
|
||||
}
|
||||
|
||||
if (!result?.[0]?.length || !result?.[1]) {
|
||||
result = fuzzyMultiInsertFuzzier?.search(
|
||||
haystack,
|
||||
needle,
|
||||
outOfOrder,
|
||||
infoThresh,
|
||||
);
|
||||
}
|
||||
|
||||
searchResultsElement.innerHTML = "";
|
||||
|
||||
const list = computeResultPage(result, 0);
|
||||
|
||||
list.forEach(({ option, title }) => {
|
||||
const li = window.document.createElement("li");
|
||||
searchResultsElement.appendChild(li);
|
||||
|
||||
const element = options.createOptionElement({
|
||||
option,
|
||||
name: title,
|
||||
});
|
||||
|
||||
if (element) {
|
||||
li.append(element);
|
||||
}
|
||||
});
|
||||
});
|
||||
let firstMobileSwitch = true;
|
||||
options.selected.onChange(() => {
|
||||
if (!firstMobileSwitch && !isHidden(asideLabelElement)) {
|
||||
asideLabelElement.click();
|
||||
}
|
||||
|
||||
if (searchInput.value) {
|
||||
inputEvent();
|
||||
}
|
||||
|
||||
searchInput.addEventListener("input", inputEvent);
|
||||
firstMobileSwitch = false;
|
||||
});
|
||||
|
||||
function initDesktopResizeBar() {
|
||||
const resizeBar = getElementById("resize-bar");
|
||||
let resize = false;
|
||||
let startingWidth = 0;
|
||||
let startingClientX = 0;
|
||||
onFirstIntersection(asideElement, initSelectedFrame);
|
||||
}
|
||||
initSelected();
|
||||
|
||||
const barWidthLocalStorageKey = "bar-width";
|
||||
onFirstIntersection(navElement, async () => {
|
||||
options.setParent(navElement);
|
||||
|
||||
/**
|
||||
* @param {number | null} width
|
||||
*/
|
||||
function setBarWidth(width) {
|
||||
// TODO: Check if should be a signal ??
|
||||
try {
|
||||
if (typeof width === "number") {
|
||||
mainElement.style.width = `${width}px`;
|
||||
writeToStorage(barWidthLocalStorageKey, String(width));
|
||||
} else {
|
||||
mainElement.style.width = style.getPropertyValue(
|
||||
"--default-main-width",
|
||||
);
|
||||
removeStored(barWidthLocalStorageKey);
|
||||
}
|
||||
} catch (_) {}
|
||||
const option = options.selected.value;
|
||||
if (!option) throw "Selected should be set by now";
|
||||
const path = [...option.path];
|
||||
|
||||
/** @type {HTMLUListElement | null} */
|
||||
let ul = /** @type {any} */ (null);
|
||||
async function getFirstChild() {
|
||||
try {
|
||||
ul = /** @type {HTMLUListElement} */ (navElement.firstElementChild);
|
||||
await next();
|
||||
if (!ul) {
|
||||
await getFirstChild();
|
||||
}
|
||||
} catch (_) {
|
||||
await next();
|
||||
await getFirstChild();
|
||||
}
|
||||
}
|
||||
await getFirstChild();
|
||||
if (!ul) throw Error("Unreachable");
|
||||
|
||||
/**
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
function mouseMoveEvent(event) {
|
||||
if (resize) {
|
||||
setBarWidth(startingWidth + (event.clientX - startingClientX));
|
||||
while (path.length > 1) {
|
||||
const name = path.shift();
|
||||
if (!name) throw "Unreachable";
|
||||
/** @type {HTMLDetailsElement[]} */
|
||||
let detailsList = [];
|
||||
while (!detailsList.length) {
|
||||
detailsList = Array.from(ul.querySelectorAll(":scope > li > details"));
|
||||
if (!detailsList.length) {
|
||||
await next();
|
||||
}
|
||||
}
|
||||
const details = detailsList.find((s) => s.dataset.name == name);
|
||||
if (!details) return;
|
||||
details.open = true;
|
||||
ul = null;
|
||||
while (!ul) {
|
||||
const uls = /** @type {HTMLUListElement[]} */ (
|
||||
Array.from(details.querySelectorAll(":scope > ul"))
|
||||
);
|
||||
if (!uls.length) {
|
||||
await next();
|
||||
} else if (uls.length > 1) {
|
||||
throw "Shouldn't be possible";
|
||||
} else {
|
||||
ul = /** @type {HTMLUListElement} */ (uls.pop());
|
||||
}
|
||||
}
|
||||
|
||||
resizeBar.addEventListener("mousedown", (event) => {
|
||||
startingClientX = event.clientX;
|
||||
startingWidth = mainElement.clientWidth;
|
||||
resize = true;
|
||||
window.document.documentElement.dataset.resize = "";
|
||||
window.addEventListener("mousemove", mouseMoveEvent);
|
||||
});
|
||||
|
||||
resizeBar.addEventListener("dblclick", () => {
|
||||
setBarWidth(null);
|
||||
});
|
||||
|
||||
const setResizeFalse = () => {
|
||||
resize = false;
|
||||
delete window.document.documentElement.dataset.resize;
|
||||
window.removeEventListener("mousemove", mouseMoveEvent);
|
||||
};
|
||||
window.addEventListener("mouseup", setResizeFalse);
|
||||
window.addEventListener("mouseleave", setResizeFalse);
|
||||
}
|
||||
initDesktopResizeBar();
|
||||
/** @type {HTMLAnchorElement[]} */
|
||||
let anchors = [];
|
||||
while (!anchors.length) {
|
||||
anchors = Array.from(ul.querySelectorAll(":scope > li > a"));
|
||||
if (!anchors.length) {
|
||||
await next();
|
||||
}
|
||||
}
|
||||
anchors
|
||||
.find((a) => a.getAttribute("href") == window.document.location.pathname)
|
||||
?.scrollIntoView({
|
||||
behavior: "instant",
|
||||
block: "center",
|
||||
});
|
||||
});
|
||||
|
||||
onFirstIntersection(searchElement, () => {
|
||||
initSearch(options);
|
||||
});
|
||||
|
||||
function initDesktopResizeBar() {
|
||||
const resizeBar = getElementById("resize-bar");
|
||||
let resize = false;
|
||||
let startingWidth = 0;
|
||||
let startingClientX = 0;
|
||||
|
||||
const barWidthLocalStorageKey = "bar-width";
|
||||
|
||||
/**
|
||||
* @param {number | null} width
|
||||
*/
|
||||
function setBarWidth(width) {
|
||||
// TODO: Check if should be a signal ??
|
||||
try {
|
||||
if (typeof width === "number") {
|
||||
mainElement.style.width = `${width}px`;
|
||||
writeToStorage(barWidthLocalStorageKey, String(width));
|
||||
} else {
|
||||
mainElement.style.width = style.getPropertyValue(
|
||||
"--default-main-width",
|
||||
);
|
||||
removeStored(barWidthLocalStorageKey);
|
||||
}
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
function mouseMoveEvent(event) {
|
||||
if (resize) {
|
||||
setBarWidth(startingWidth + (event.clientX - startingClientX));
|
||||
}
|
||||
}
|
||||
|
||||
resizeBar.addEventListener("mousedown", (event) => {
|
||||
startingClientX = event.clientX;
|
||||
startingWidth = mainElement.clientWidth;
|
||||
resize = true;
|
||||
window.document.documentElement.dataset.resize = "";
|
||||
window.addEventListener("mousemove", mouseMoveEvent);
|
||||
});
|
||||
|
||||
resizeBar.addEventListener("dblclick", () => {
|
||||
setBarWidth(null);
|
||||
});
|
||||
|
||||
const setResizeFalse = () => {
|
||||
resize = false;
|
||||
delete window.document.documentElement.dataset.resize;
|
||||
window.removeEventListener("mousemove", mouseMoveEvent);
|
||||
};
|
||||
window.addEventListener("mouseup", setResizeFalse);
|
||||
window.addEventListener("mouseleave", setResizeFalse);
|
||||
}
|
||||
initDesktopResizeBar();
|
||||
|
||||
@@ -7,11 +7,9 @@ import { collect, markUsed, logUnused } from "./unused.js";
|
||||
import { setQr } from "../panes/share.js";
|
||||
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {Signals} args.signals
|
||||
* @param {BrkClient} args.brk
|
||||
* @param {BrkClient} brk
|
||||
*/
|
||||
export function initOptions({ signals, brk }) {
|
||||
export function initOptions(brk) {
|
||||
collect(brk.metrics);
|
||||
|
||||
const LS_SELECTED_KEY = `selected_path`;
|
||||
@@ -25,9 +23,6 @@ export function initOptions({ signals, brk }) {
|
||||
).filter((v) => v);
|
||||
console.log(savedPath);
|
||||
|
||||
/** @type {Signal<Option>} */
|
||||
const selected = signals.createSignal(/** @type {any} */ (undefined));
|
||||
|
||||
const partialOptions = createPartialOptions({
|
||||
brk,
|
||||
});
|
||||
@@ -35,16 +30,49 @@ export function initOptions({ signals, brk }) {
|
||||
/** @type {Option[]} */
|
||||
const list = [];
|
||||
|
||||
const parent = signals.createSignal(/** @type {HTMLElement | null} */ (null));
|
||||
|
||||
/** @type {Map<string, HTMLLIElement>} */
|
||||
const liByPath = new Map();
|
||||
|
||||
/** @type {Set<(option: Option) => void>} */
|
||||
const selectedListeners = new Set();
|
||||
|
||||
/**
|
||||
* @param {Option | undefined} sel
|
||||
*/
|
||||
function updateHighlight(sel) {
|
||||
if (!sel) return;
|
||||
liByPath.forEach((li) => {
|
||||
delete li.dataset.highlight;
|
||||
});
|
||||
for (let i = 1; i <= sel.path.length; i++) {
|
||||
const pathKey = sel.path.slice(0, i).join("/");
|
||||
const li = liByPath.get(pathKey);
|
||||
if (li) li.dataset.highlight = "";
|
||||
}
|
||||
}
|
||||
|
||||
const selected = {
|
||||
/** @type {Option | undefined} */
|
||||
value: undefined,
|
||||
/** @param {Option} v */
|
||||
set(v) {
|
||||
this.value = v;
|
||||
updateHighlight(v);
|
||||
selectedListeners.forEach((cb) => cb(v));
|
||||
},
|
||||
/** @param {(option: Option) => void} cb */
|
||||
onChange(cb) {
|
||||
selectedListeners.add(cb);
|
||||
if (this.value) cb(this.value);
|
||||
return () => selectedListeners.delete(cb);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string[]} nodePath
|
||||
*/
|
||||
function isOnSelectedPath(nodePath) {
|
||||
const selectedPath = selected()?.path;
|
||||
const selectedPath = selected.value?.path;
|
||||
return (
|
||||
selectedPath &&
|
||||
nodePath.length <= selectedPath.length &&
|
||||
@@ -128,11 +156,6 @@ export function initOptions({ signals, brk }) {
|
||||
/** @type {Option | undefined} */
|
||||
let savedOption;
|
||||
|
||||
// ============================================
|
||||
// Phase 1: Process partial tree (non-reactive)
|
||||
// Transforms options, computes counts, populates list
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* @typedef {{ type: "group"; name: string; serName: string; path: string[]; count: number; children: ProcessedNode[] }} ProcessedGroup
|
||||
* @typedef {{ type: "option"; option: Option; path: string[] }} ProcessedOption
|
||||
@@ -267,11 +290,6 @@ export function initOptions({ signals, brk }) {
|
||||
const processedTree = processPartialTree(partialOptions);
|
||||
logUnused();
|
||||
|
||||
// ============================================
|
||||
// Phase 2: Build DOM lazily (imperative)
|
||||
// Uses native toggle events for lazy loading
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* @param {ProcessedNode[]} nodes
|
||||
* @param {HTMLElement} parentEl
|
||||
@@ -320,36 +338,19 @@ export function initOptions({ signals, brk }) {
|
||||
}
|
||||
}
|
||||
|
||||
// Single effect to kick off DOM building when parent is set
|
||||
signals.createEffect(
|
||||
() => parent(),
|
||||
(_parent) => {
|
||||
if (!_parent) return;
|
||||
buildTreeDOM(processedTree, _parent);
|
||||
},
|
||||
);
|
||||
/** @type {HTMLElement | null} */
|
||||
let parentEl = null;
|
||||
|
||||
// Single effect for highlighting on selection change
|
||||
signals.createEffect(
|
||||
() => selected(),
|
||||
(selected) => {
|
||||
if (!selected) return;
|
||||
/**
|
||||
* @param {HTMLElement} el
|
||||
*/
|
||||
function setParent(el) {
|
||||
if (parentEl) return;
|
||||
parentEl = el;
|
||||
buildTreeDOM(processedTree, el);
|
||||
}
|
||||
|
||||
// Clear all existing highlights
|
||||
liByPath.forEach((li) => {
|
||||
delete li.dataset.highlight;
|
||||
});
|
||||
|
||||
// Highlight selected option and parent groups
|
||||
for (let i = 1; i <= selected.path.length; i++) {
|
||||
const pathKey = selected.path.slice(0, i).join("/");
|
||||
const li = liByPath.get(pathKey);
|
||||
if (li) li.dataset.highlight = "";
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if (!selected()) {
|
||||
if (!selected.value) {
|
||||
const option =
|
||||
savedOption || list.find((option) => option.kind === "chart");
|
||||
if (option) {
|
||||
@@ -361,7 +362,7 @@ export function initOptions({ signals, brk }) {
|
||||
selected,
|
||||
list,
|
||||
tree: /** @type {OptionsTree} */ (partialOptions),
|
||||
parent,
|
||||
setParent,
|
||||
createOptionElement,
|
||||
selectOption,
|
||||
};
|
||||
|
||||
@@ -8,35 +8,30 @@
|
||||
* @property {Color} [color]
|
||||
* @property {[Color, Color]} [colors]
|
||||
* @property {BaselineSeriesPartialOptions} [options]
|
||||
* @property {Accessor<BaselineData[]>} [data]
|
||||
* @typedef {BaseSeriesBlueprint & BaselineSeriesBlueprintSpecific} BaselineSeriesBlueprint
|
||||
*
|
||||
* @typedef {Object} CandlestickSeriesBlueprintSpecific
|
||||
* @property {"Candlestick"} type
|
||||
* @property {[Color, Color]} [colors]
|
||||
* @property {CandlestickSeriesPartialOptions} [options]
|
||||
* @property {Accessor<CandlestickData[]>} [data]
|
||||
* @typedef {BaseSeriesBlueprint & CandlestickSeriesBlueprintSpecific} CandlestickSeriesBlueprint
|
||||
*
|
||||
* @typedef {Object} LineSeriesBlueprintSpecific
|
||||
* @property {"Line"} [type]
|
||||
* @property {Color} [color]
|
||||
* @property {LineSeriesPartialOptions} [options]
|
||||
* @property {Accessor<LineData[]>} [data]
|
||||
* @typedef {BaseSeriesBlueprint & LineSeriesBlueprintSpecific} LineSeriesBlueprint
|
||||
*
|
||||
* @typedef {Object} HistogramSeriesBlueprintSpecific
|
||||
* @property {"Histogram"} type
|
||||
* @property {Color | [Color, Color]} [color] - Single color or [positive, negative] colors (defaults to green/red)
|
||||
* @property {HistogramSeriesPartialOptions} [options]
|
||||
* @property {Accessor<HistogramData[]>} [data]
|
||||
* @typedef {BaseSeriesBlueprint & HistogramSeriesBlueprintSpecific} HistogramSeriesBlueprint
|
||||
*
|
||||
* @typedef {Object} DotsSeriesBlueprintSpecific
|
||||
* @property {"Dots"} type
|
||||
* @property {Color} [color]
|
||||
* @property {LineSeriesPartialOptions} [options]
|
||||
* @property {Accessor<LineData[]>} [data]
|
||||
* @typedef {BaseSeriesBlueprint & DotsSeriesBlueprintSpecific} DotsSeriesBlueprint
|
||||
*
|
||||
* @typedef {BaselineSeriesBlueprint | CandlestickSeriesBlueprint | LineSeriesBlueprint | HistogramSeriesBlueprint | DotsSeriesBlueprint} AnySeriesBlueprint
|
||||
|
||||
@@ -1,99 +1,99 @@
|
||||
import { randomFromArray } from "../utils/array.js";
|
||||
import { explorerElement } from "../utils/elements.js";
|
||||
// import { randomFromArray } from "../utils/array.js";
|
||||
// import { explorerElement } from "../utils/elements.js";
|
||||
|
||||
export function init() {
|
||||
const chain = window.document.createElement("div");
|
||||
chain.id = "chain";
|
||||
explorerElement.append(chain);
|
||||
// export function init() {
|
||||
// const chain = window.document.createElement("div");
|
||||
// chain.id = "chain";
|
||||
// explorerElement.append(chain);
|
||||
|
||||
// vecsResources.getOrCreate(/** @satisfies {Height}*/ (5), "height");
|
||||
//
|
||||
const miners = [
|
||||
{ name: "Foundry USA", color: "orange" },
|
||||
{ name: "Via BTC", color: "teal" },
|
||||
{ name: "Ant Pool", color: "emerald" },
|
||||
{ name: "F2Pool", color: "indigo" },
|
||||
{ name: "Spider Pool", color: "yellow" },
|
||||
{ name: "Mara Pool", color: "amber" },
|
||||
{ name: "SEC Pool", color: "violet" },
|
||||
{ name: "Luxor", color: "orange" },
|
||||
{ name: "Brains Pool", color: "cyan" },
|
||||
];
|
||||
// // vecsResources.getOrCreate(/** @satisfies {Height}*/ (5), "height");
|
||||
// //
|
||||
// const miners = [
|
||||
// { name: "Foundry USA", color: "orange" },
|
||||
// { name: "Via BTC", color: "teal" },
|
||||
// { name: "Ant Pool", color: "emerald" },
|
||||
// { name: "F2Pool", color: "indigo" },
|
||||
// { name: "Spider Pool", color: "yellow" },
|
||||
// { name: "Mara Pool", color: "amber" },
|
||||
// { name: "SEC Pool", color: "violet" },
|
||||
// { name: "Luxor", color: "orange" },
|
||||
// { name: "Brains Pool", color: "cyan" },
|
||||
// ];
|
||||
|
||||
for (let i = 0; i <= 10; i++) {
|
||||
const { name, color: _color } = randomFromArray(miners);
|
||||
const { cubeElement, leftFaceElement, rightFaceElement, topFaceElement } =
|
||||
createCube();
|
||||
// for (let i = 0; i <= 10; i++) {
|
||||
// const { name, color: _color } = randomFromArray(miners);
|
||||
// const { cubeElement, leftFaceElement, rightFaceElement, topFaceElement } =
|
||||
// createCube();
|
||||
|
||||
// cubeElement.style.setProperty("--color", `var(--${color})`);
|
||||
// // cubeElement.style.setProperty("--color", `var(--${color})`);
|
||||
|
||||
const heightElement = window.document.createElement("p");
|
||||
const height = (1_000_002 - i).toString();
|
||||
const prefixLength = 7 - height.length;
|
||||
const spanPrefix = window.document.createElement("span");
|
||||
spanPrefix.style.opacity = "0.5";
|
||||
spanPrefix.style.userSelect = "none";
|
||||
heightElement.append(spanPrefix);
|
||||
spanPrefix.innerHTML = "#" + "0".repeat(prefixLength);
|
||||
const spanHeight = window.document.createElement("span");
|
||||
heightElement.append(spanHeight);
|
||||
spanHeight.innerHTML = height;
|
||||
rightFaceElement.append(heightElement);
|
||||
// const heightElement = window.document.createElement("p");
|
||||
// const height = (1_000_002 - i).toString();
|
||||
// const prefixLength = 7 - height.length;
|
||||
// const spanPrefix = window.document.createElement("span");
|
||||
// spanPrefix.style.opacity = "0.5";
|
||||
// spanPrefix.style.userSelect = "none";
|
||||
// heightElement.append(spanPrefix);
|
||||
// spanPrefix.innerHTML = "#" + "0".repeat(prefixLength);
|
||||
// const spanHeight = window.document.createElement("span");
|
||||
// heightElement.append(spanHeight);
|
||||
// spanHeight.innerHTML = height;
|
||||
// rightFaceElement.append(heightElement);
|
||||
|
||||
const feesElement = window.document.createElement("div");
|
||||
feesElement.classList.add("fees");
|
||||
leftFaceElement.append(feesElement);
|
||||
const averageFeeElement = window.document.createElement("p");
|
||||
feesElement.append(averageFeeElement);
|
||||
averageFeeElement.innerHTML = `~1.41`;
|
||||
const feeRangeElement = window.document.createElement("p");
|
||||
feesElement.append(feeRangeElement);
|
||||
const minFeeElement = window.document.createElement("span");
|
||||
minFeeElement.innerHTML = `0.11`;
|
||||
feeRangeElement.append(minFeeElement);
|
||||
const dashElement = window.document.createElement("span");
|
||||
dashElement.style.opacity = "0.5";
|
||||
dashElement.innerHTML = `-`;
|
||||
feeRangeElement.append(dashElement);
|
||||
const maxFeeElement = window.document.createElement("span");
|
||||
maxFeeElement.innerHTML = `12.1`;
|
||||
feeRangeElement.append(maxFeeElement);
|
||||
const feeUnitElement = window.document.createElement("p");
|
||||
feesElement.append(feeUnitElement);
|
||||
feeUnitElement.style.opacity = "0.5";
|
||||
feeUnitElement.innerHTML = `sat/vB`;
|
||||
// const feesElement = window.document.createElement("div");
|
||||
// feesElement.classList.add("fees");
|
||||
// leftFaceElement.append(feesElement);
|
||||
// const averageFeeElement = window.document.createElement("p");
|
||||
// feesElement.append(averageFeeElement);
|
||||
// averageFeeElement.innerHTML = `~1.41`;
|
||||
// const feeRangeElement = window.document.createElement("p");
|
||||
// feesElement.append(feeRangeElement);
|
||||
// const minFeeElement = window.document.createElement("span");
|
||||
// minFeeElement.innerHTML = `0.11`;
|
||||
// feeRangeElement.append(minFeeElement);
|
||||
// const dashElement = window.document.createElement("span");
|
||||
// dashElement.style.opacity = "0.5";
|
||||
// dashElement.innerHTML = `-`;
|
||||
// feeRangeElement.append(dashElement);
|
||||
// const maxFeeElement = window.document.createElement("span");
|
||||
// maxFeeElement.innerHTML = `12.1`;
|
||||
// feeRangeElement.append(maxFeeElement);
|
||||
// const feeUnitElement = window.document.createElement("p");
|
||||
// feesElement.append(feeUnitElement);
|
||||
// feeUnitElement.style.opacity = "0.5";
|
||||
// feeUnitElement.innerHTML = `sat/vB`;
|
||||
|
||||
const spanMiner = window.document.createElement("span");
|
||||
spanMiner.innerHTML = name;
|
||||
topFaceElement.append(spanMiner);
|
||||
// const spanMiner = window.document.createElement("span");
|
||||
// spanMiner.innerHTML = name;
|
||||
// topFaceElement.append(spanMiner);
|
||||
|
||||
chain.prepend(cubeElement);
|
||||
}
|
||||
}
|
||||
// chain.prepend(cubeElement);
|
||||
// }
|
||||
// }
|
||||
|
||||
function createCube() {
|
||||
const cubeElement = window.document.createElement("div");
|
||||
cubeElement.classList.add("cube");
|
||||
// function createCube() {
|
||||
// const cubeElement = window.document.createElement("div");
|
||||
// cubeElement.classList.add("cube");
|
||||
|
||||
const rightFaceElement = window.document.createElement("div");
|
||||
rightFaceElement.classList.add("face");
|
||||
rightFaceElement.classList.add("right");
|
||||
cubeElement.append(rightFaceElement);
|
||||
// const rightFaceElement = window.document.createElement("div");
|
||||
// rightFaceElement.classList.add("face");
|
||||
// rightFaceElement.classList.add("right");
|
||||
// cubeElement.append(rightFaceElement);
|
||||
|
||||
const leftFaceElement = window.document.createElement("div");
|
||||
leftFaceElement.classList.add("face");
|
||||
leftFaceElement.classList.add("left");
|
||||
cubeElement.append(leftFaceElement);
|
||||
// const leftFaceElement = window.document.createElement("div");
|
||||
// leftFaceElement.classList.add("face");
|
||||
// leftFaceElement.classList.add("left");
|
||||
// cubeElement.append(leftFaceElement);
|
||||
|
||||
const topFaceElement = window.document.createElement("div");
|
||||
topFaceElement.classList.add("face");
|
||||
topFaceElement.classList.add("top");
|
||||
cubeElement.append(topFaceElement);
|
||||
// const topFaceElement = window.document.createElement("div");
|
||||
// topFaceElement.classList.add("face");
|
||||
// topFaceElement.classList.add("top");
|
||||
// cubeElement.append(topFaceElement);
|
||||
|
||||
return {
|
||||
cubeElement,
|
||||
leftFaceElement,
|
||||
rightFaceElement,
|
||||
topFaceElement,
|
||||
};
|
||||
}
|
||||
// return {
|
||||
// cubeElement,
|
||||
// leftFaceElement,
|
||||
// rightFaceElement,
|
||||
// topFaceElement,
|
||||
// };
|
||||
// }
|
||||
|
||||
+1103
-1103
File diff suppressed because it is too large
Load Diff
+421
-421
@@ -1,433 +1,433 @@
|
||||
// @ts-nocheck
|
||||
// // @ts-nocheck
|
||||
|
||||
import { randomFromArray } from "../utils/array.js";
|
||||
import { createButtonElement, createHeader, createSelect } from "../utils/dom.js";
|
||||
import { tableElement } from "../utils/elements.js";
|
||||
import { serdeMetrics, serdeString } from "../utils/serde.js";
|
||||
import { resetParams } from "../utils/url.js";
|
||||
// import { randomFromArray } from "../utils/array.js";
|
||||
// import { createButtonElement, createHeader, createSelect } from "../utils/dom.js";
|
||||
// import { tableElement } from "../utils/elements.js";
|
||||
// import { serdeMetrics, serdeString } from "../utils/serde.js";
|
||||
// import { resetParams } from "../utils/url.js";
|
||||
|
||||
export function init() {
|
||||
tableElement.innerHTML = "wip, will hopefuly be back soon, sorry !";
|
||||
// export function init() {
|
||||
// tableElement.innerHTML = "wip, will hopefuly be back soon, sorry !";
|
||||
|
||||
// const parent = tableElement;
|
||||
// const { headerElement } = createHeader("Table");
|
||||
// parent.append(headerElement);
|
||||
// // const parent = tableElement;
|
||||
// // const { headerElement } = createHeader("Table");
|
||||
// // parent.append(headerElement);
|
||||
|
||||
// const div = window.document.createElement("div");
|
||||
// parent.append(div);
|
||||
// // const div = window.document.createElement("div");
|
||||
// // parent.append(div);
|
||||
|
||||
// const table = createTable({
|
||||
// signals,
|
||||
// brk,
|
||||
// resources,
|
||||
// option,
|
||||
// });
|
||||
// div.append(table.element);
|
||||
// // const table = createTable({
|
||||
// // signals,
|
||||
// // brk,
|
||||
// // resources,
|
||||
// // option,
|
||||
// // });
|
||||
// // div.append(table.element);
|
||||
|
||||
// const span = window.document.createElement("span");
|
||||
// span.innerHTML = "Add column";
|
||||
// div.append(
|
||||
// createButtonElement({
|
||||
// onClick: () => {
|
||||
// table.addRandomCol?.();
|
||||
// },
|
||||
// inside: span,
|
||||
// title: "Click or tap to add a column to the table",
|
||||
// }),
|
||||
// );
|
||||
}
|
||||
// // const span = window.document.createElement("span");
|
||||
// // span.innerHTML = "Add column";
|
||||
// // div.append(
|
||||
// // createButtonElement({
|
||||
// // onClick: () => {
|
||||
// // table.addRandomCol?.();
|
||||
// // },
|
||||
// // inside: span,
|
||||
// // title: "Click or tap to add a column to the table",
|
||||
// // }),
|
||||
// // );
|
||||
// }
|
||||
|
||||
// // /**
|
||||
// // * @param {Object} args
|
||||
// // * @param {Option} args.option
|
||||
// // * @param {Signals} args.signals
|
||||
// // * @param {BrkClient} args.brk
|
||||
// // * @param {Resources} args.resources
|
||||
// // */
|
||||
// // function createTable({ brk, signals, option, resources }) {
|
||||
// // const indexToMetrics = createIndexToMetrics(metricToIndexes);
|
||||
|
||||
// // const serializedIndexes = createSerializedIndexes();
|
||||
// // /** @type {SerializedIndex} */
|
||||
// // const defaultSerializedIndex = "height";
|
||||
// // const serializedIndex = /** @type {Signal<SerializedIndex>} */ (
|
||||
// // signals.createSignal(
|
||||
// // /** @type {SerializedIndex} */ (defaultSerializedIndex),
|
||||
// // {
|
||||
// // save: {
|
||||
// // ...serdeString,
|
||||
// // keyPrefix: "table",
|
||||
// // key: "index",
|
||||
// // },
|
||||
// // },
|
||||
// // )
|
||||
// // );
|
||||
// // const index = signals.createMemo(() =>
|
||||
// // serializedIndexToIndex(serializedIndex()),
|
||||
// // );
|
||||
|
||||
// // const table = window.document.createElement("table");
|
||||
// // const obj = {
|
||||
// // element: table,
|
||||
// // /** @type {VoidFunction | undefined} */
|
||||
// // addRandomCol: undefined,
|
||||
// // };
|
||||
|
||||
// // signals.createEffect(index, (index, prevIndex) => {
|
||||
// // if (prevIndex !== undefined) {
|
||||
// // resetParams(option);
|
||||
// // }
|
||||
|
||||
// // const possibleMetrics = indexToMetrics[index];
|
||||
|
||||
// // const columns = signals.createSignal(/** @type {Metric[]} */ ([]), {
|
||||
// // equals: false,
|
||||
// // save: {
|
||||
// // ...serdeMetrics,
|
||||
// // keyPrefix: `table-${serializedIndex()}`,
|
||||
// // key: `columns`,
|
||||
// // },
|
||||
// // });
|
||||
// // columns.set((l) => l.filter((id) => possibleMetrics.includes(id)));
|
||||
|
||||
// // signals.createEffect(columns, (columns) => {
|
||||
// // console.log(columns);
|
||||
// // });
|
||||
|
||||
// // table.innerHTML = "";
|
||||
// // const thead = window.document.createElement("thead");
|
||||
// // table.append(thead);
|
||||
// // const trHead = window.document.createElement("tr");
|
||||
// // thead.append(trHead);
|
||||
// // const tbody = window.document.createElement("tbody");
|
||||
// // table.append(tbody);
|
||||
|
||||
// // const rowElements = signals.createSignal(
|
||||
// // /** @type {HTMLTableRowElement[]} */ ([]),
|
||||
// // );
|
||||
|
||||
// // /**
|
||||
// // * @param {Object} args
|
||||
// // * @param {HTMLSelectElement} args.select
|
||||
// // * @param {Unit} [args.unit]
|
||||
// // * @param {(event: MouseEvent) => void} [args.onLeft]
|
||||
// // * @param {(event: MouseEvent) => void} [args.onRight]
|
||||
// // * @param {(event: MouseEvent) => void} [args.onRemove]
|
||||
// // */
|
||||
// // function addThCol({ select, onLeft, onRight, onRemove, unit: _unit }) {
|
||||
// // const th = window.document.createElement("th");
|
||||
// // th.scope = "col";
|
||||
// // trHead.append(th);
|
||||
// // const div = window.document.createElement("div");
|
||||
// // div.append(select);
|
||||
// // // const top = window.document.createElement("div");
|
||||
// // // div.append(top);
|
||||
// // // top.append(select);
|
||||
// // // top.append(
|
||||
// // // createAnchorElement({
|
||||
// // // href: "",
|
||||
// // // blank: true,
|
||||
// // // }),
|
||||
// // // );
|
||||
// // const bottom = window.document.createElement("div");
|
||||
// // const unit = window.document.createElement("span");
|
||||
// // if (_unit) {
|
||||
// // unit.innerHTML = _unit;
|
||||
// // }
|
||||
// // const moveLeft = createButtonElement({
|
||||
// // inside: "←",
|
||||
// // title: "Move column to the left",
|
||||
// // onClick: onLeft || (() => {}),
|
||||
// // });
|
||||
// // const moveRight = createButtonElement({
|
||||
// // inside: "→",
|
||||
// // title: "Move column to the right",
|
||||
// // onClick: onRight || (() => {}),
|
||||
// // });
|
||||
// // const remove = createButtonElement({
|
||||
// // inside: "×",
|
||||
// // title: "Remove column",
|
||||
// // onClick: onRemove || (() => {}),
|
||||
// // });
|
||||
// // bottom.append(unit);
|
||||
// // bottom.append(moveLeft);
|
||||
// // bottom.append(moveRight);
|
||||
// // bottom.append(remove);
|
||||
// // div.append(bottom);
|
||||
// // th.append(div);
|
||||
// // return {
|
||||
// // element: th,
|
||||
// // /**
|
||||
// // * @param {Unit} _unit
|
||||
// // */
|
||||
// // setUnit(_unit) {
|
||||
// // unit.innerHTML = _unit;
|
||||
// // },
|
||||
// // };
|
||||
// // }
|
||||
|
||||
// // addThCol({
|
||||
// // ...createSelect({
|
||||
// // list: serializedIndexes,
|
||||
// // signal: serializedIndex,
|
||||
// // }),
|
||||
// // unit: "index",
|
||||
// // });
|
||||
|
||||
// // let from = 0;
|
||||
// // let to = 0;
|
||||
|
||||
// // resources
|
||||
// // .getOrCreate(index, serializedIndex())
|
||||
// // .fetch()
|
||||
// // .then((vec) => {
|
||||
// // if (!vec) return;
|
||||
// // from = /** @type {number} */ (vec[0]);
|
||||
// // to = /** @type {number} */ (vec.at(-1)) + 1;
|
||||
// // const trs = /** @type {HTMLTableRowElement[]} */ ([]);
|
||||
// // for (let i = vec.length - 1; i >= 0; i--) {
|
||||
// // const value = vec[i];
|
||||
// // const tr = window.document.createElement("tr");
|
||||
// // trs.push(tr);
|
||||
// // tbody.append(tr);
|
||||
// // const th = window.document.createElement("th");
|
||||
// // th.innerHTML = serializeValue({
|
||||
// // value,
|
||||
// // unit: "index",
|
||||
// // });
|
||||
// // th.scope = "row";
|
||||
// // tr.append(th);
|
||||
// // }
|
||||
// // rowElements.set(() => trs);
|
||||
// // });
|
||||
|
||||
// // const owner = signals.getOwner();
|
||||
|
||||
// // /**
|
||||
// // * @param {Metric} metric
|
||||
// // * @param {number} [_colIndex]
|
||||
// // */
|
||||
// // function addCol(metric, _colIndex = columns().length) {
|
||||
// // signals.runWithOwner(owner, () => {
|
||||
// // /** @type {VoidFunction | undefined} */
|
||||
// // let dispose;
|
||||
// // signals.createRoot((_dispose) => {
|
||||
// // dispose = _dispose;
|
||||
|
||||
// // const metricOption = signals.createSignal({
|
||||
// // name: metric,
|
||||
// // value: metric,
|
||||
// // });
|
||||
// // const { select } = createSelect({
|
||||
// // list: possibleMetrics.map((metric) => ({
|
||||
// // name: metric,
|
||||
// // value: metric,
|
||||
// // })),
|
||||
// // signal: metricOption,
|
||||
// // });
|
||||
|
||||
// // signals.createEffect(metricOption, (metricOption) => {
|
||||
// // select.style.width = `${21 + 7.25 * metricOption.name.length}px`;
|
||||
// // });
|
||||
|
||||
// // if (_colIndex === columns().length) {
|
||||
// // columns.set((l) => {
|
||||
// // l.push(metric);
|
||||
// // return l;
|
||||
// // });
|
||||
// // }
|
||||
|
||||
// // const colIndex = signals.createSignal(_colIndex);
|
||||
|
||||
// // /**
|
||||
// // * @param {boolean} right
|
||||
// // * @returns {(event: MouseEvent) => void}
|
||||
// // */
|
||||
// // function createMoveColumnFunction(right) {
|
||||
// // return () => {
|
||||
// // const oldColIndex = colIndex();
|
||||
// // const newColIndex = oldColIndex + (right ? 1 : -1);
|
||||
|
||||
// // const currentTh = /** @type {HTMLTableCellElement} */ (
|
||||
// // trHead.childNodes[oldColIndex + 1]
|
||||
// // );
|
||||
// // const oterTh = /** @type {HTMLTableCellElement} */ (
|
||||
// // trHead.childNodes[newColIndex + 1]
|
||||
// // );
|
||||
|
||||
// // if (right) {
|
||||
// // oterTh.after(currentTh);
|
||||
// // } else {
|
||||
// // oterTh.before(currentTh);
|
||||
// // }
|
||||
|
||||
// // columns.set((l) => {
|
||||
// // [l[oldColIndex], l[newColIndex]] = [
|
||||
// // l[newColIndex],
|
||||
// // l[oldColIndex],
|
||||
// // ];
|
||||
// // return l;
|
||||
// // });
|
||||
|
||||
// // const rows = rowElements();
|
||||
// // for (let i = 0; i < rows.length; i++) {
|
||||
// // const element = rows[i].childNodes[oldColIndex + 1];
|
||||
// // const sibling = rows[i].childNodes[newColIndex + 1];
|
||||
// // const temp = element.textContent;
|
||||
// // element.textContent = sibling.textContent;
|
||||
// // sibling.textContent = temp;
|
||||
// // }
|
||||
// // };
|
||||
// // }
|
||||
|
||||
// // const th = addThCol({
|
||||
// // select,
|
||||
// // unit: serdeUnit.deserialize(metric),
|
||||
// // onLeft: createMoveColumnFunction(false),
|
||||
// // onRight: createMoveColumnFunction(true),
|
||||
// // onRemove: () => {
|
||||
// // const ci = colIndex();
|
||||
// // trHead.childNodes[ci + 1].remove();
|
||||
// // columns.set((l) => {
|
||||
// // l.splice(ci, 1);
|
||||
// // return l;
|
||||
// // });
|
||||
// // const rows = rowElements();
|
||||
// // for (let i = 0; i < rows.length; i++) {
|
||||
// // rows[i].childNodes[ci + 1].remove();
|
||||
// // }
|
||||
// // dispose?.();
|
||||
// // },
|
||||
// // });
|
||||
|
||||
// // signals.createEffect(columns, () => {
|
||||
// // colIndex.set(Array.from(trHead.children).indexOf(th.element) - 1);
|
||||
// // });
|
||||
|
||||
// // console.log(colIndex());
|
||||
|
||||
// // signals.createEffect(rowElements, (rowElements) => {
|
||||
// // if (!rowElements.length) return;
|
||||
// // for (let i = 0; i < rowElements.length; i++) {
|
||||
// // const td = window.document.createElement("td");
|
||||
// // rowElements[i].append(td);
|
||||
// // }
|
||||
|
||||
// // signals.createEffect(
|
||||
// // () => metricOption().name,
|
||||
// // (metric, prevMetric) => {
|
||||
// // const unit = serdeUnit.deserialize(metric);
|
||||
// // th.setUnit(unit);
|
||||
|
||||
// // const vec = resources.getOrCreate(index, metric);
|
||||
|
||||
// // vec.fetch({ from, to });
|
||||
|
||||
// // const fetchedKey = resources.genFetchedKey({ from, to });
|
||||
|
||||
// // columns.set((l) => {
|
||||
// // const i = l.indexOf(prevMetric ?? metric);
|
||||
// // if (i === -1) {
|
||||
// // l.push(metric);
|
||||
// // } else {
|
||||
// // l[i] = metric;
|
||||
// // }
|
||||
// // return l;
|
||||
// // });
|
||||
|
||||
// // signals.createEffect(
|
||||
// // () => vec.fetched().get(fetchedKey)?.vec(),
|
||||
// // (vec) => {
|
||||
// // if (!vec?.length) return;
|
||||
|
||||
// // const thIndex = colIndex() + 1;
|
||||
|
||||
// // for (let i = 0; i < rowElements.length; i++) {
|
||||
// // const iRev = vec.length - 1 - i;
|
||||
// // const value = vec[iRev];
|
||||
// // // @ts-ignore
|
||||
// // rowElements[i].childNodes[thIndex].innerHTML =
|
||||
// // serializeValue({
|
||||
// // value,
|
||||
// // unit,
|
||||
// // });
|
||||
// // }
|
||||
// // },
|
||||
// // );
|
||||
|
||||
// // return () => metric;
|
||||
// // },
|
||||
// // );
|
||||
// // });
|
||||
// // });
|
||||
|
||||
// // signals.onCleanup(() => {
|
||||
// // dispose?.();
|
||||
// // });
|
||||
// // });
|
||||
// // }
|
||||
|
||||
// // columns().forEach((metric, colIndex) => addCol(metric, colIndex));
|
||||
|
||||
// // obj.addRandomCol = function () {
|
||||
// // addCol(randomFromArray(possibleMetrics));
|
||||
// // };
|
||||
|
||||
// // return () => index;
|
||||
// // });
|
||||
|
||||
// // return obj;
|
||||
// // }
|
||||
|
||||
// /**
|
||||
// * @param {MetricToIndexes} metricToIndexes
|
||||
// */
|
||||
// function createIndexToMetrics(metricToIndexes) {
|
||||
// // const indexToMetrics = Object.entries(metricToIndexes).reduce(
|
||||
// // (arr, [_id, indexes]) => {
|
||||
// // const id = /** @type {Metric} */ (_id);
|
||||
// // indexes.forEach((i) => {
|
||||
// // arr[i] ??= [];
|
||||
// // arr[i].push(id);
|
||||
// // });
|
||||
// // return arr;
|
||||
// // },
|
||||
// // /** @type {Metric[][]} */ (Array.from({ length: 24 })),
|
||||
// // );
|
||||
// // indexToMetrics.forEach((arr) => {
|
||||
// // arr.sort();
|
||||
// // });
|
||||
// // return indexToMetrics;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * @param {Object} args
|
||||
// * @param {Option} args.option
|
||||
// * @param {Signals} args.signals
|
||||
// * @param {BrkClient} args.brk
|
||||
// * @param {Resources} args.resources
|
||||
// * @param {number | string | Object | Array<any>} args.value
|
||||
// * @param {Unit} args.unit
|
||||
// */
|
||||
// function createTable({ brk, signals, option, resources }) {
|
||||
// const indexToMetrics = createIndexToMetrics(metricToIndexes);
|
||||
|
||||
// const serializedIndexes = createSerializedIndexes();
|
||||
// /** @type {SerializedIndex} */
|
||||
// const defaultSerializedIndex = "height";
|
||||
// const serializedIndex = /** @type {Signal<SerializedIndex>} */ (
|
||||
// signals.createSignal(
|
||||
// /** @type {SerializedIndex} */ (defaultSerializedIndex),
|
||||
// {
|
||||
// save: {
|
||||
// ...serdeString,
|
||||
// keyPrefix: "table",
|
||||
// key: "index",
|
||||
// },
|
||||
// },
|
||||
// )
|
||||
// );
|
||||
// const index = signals.createMemo(() =>
|
||||
// serializedIndexToIndex(serializedIndex()),
|
||||
// );
|
||||
|
||||
// const table = window.document.createElement("table");
|
||||
// const obj = {
|
||||
// element: table,
|
||||
// /** @type {VoidFunction | undefined} */
|
||||
// addRandomCol: undefined,
|
||||
// };
|
||||
|
||||
// signals.createEffect(index, (index, prevIndex) => {
|
||||
// if (prevIndex !== undefined) {
|
||||
// resetParams(option);
|
||||
// function serializeValue({ value, unit }) {
|
||||
// const t = typeof value;
|
||||
// if (value === null) {
|
||||
// return "null";
|
||||
// } else if (typeof value === "string") {
|
||||
// return value;
|
||||
// } else if (t !== "number") {
|
||||
// return JSON.stringify(value).replaceAll('"', "").slice(1, -1);
|
||||
// } else if (value !== 18446744073709552000) {
|
||||
// if (unit === "usd" || unit === "difficulty" || unit === "sat/vb") {
|
||||
// return value.toLocaleString("en-us", {
|
||||
// minimumFractionDigits: 2,
|
||||
// maximumFractionDigits: 2,
|
||||
// });
|
||||
// } else if (unit === "btc") {
|
||||
// return value.toLocaleString("en-us", {
|
||||
// minimumFractionDigits: 8,
|
||||
// maximumFractionDigits: 8,
|
||||
// });
|
||||
// } else {
|
||||
// return value.toLocaleString("en-us");
|
||||
// }
|
||||
|
||||
// const possibleMetrics = indexToMetrics[index];
|
||||
|
||||
// const columns = signals.createSignal(/** @type {Metric[]} */ ([]), {
|
||||
// equals: false,
|
||||
// save: {
|
||||
// ...serdeMetrics,
|
||||
// keyPrefix: `table-${serializedIndex()}`,
|
||||
// key: `columns`,
|
||||
// },
|
||||
// });
|
||||
// columns.set((l) => l.filter((id) => possibleMetrics.includes(id)));
|
||||
|
||||
// signals.createEffect(columns, (columns) => {
|
||||
// console.log(columns);
|
||||
// });
|
||||
|
||||
// table.innerHTML = "";
|
||||
// const thead = window.document.createElement("thead");
|
||||
// table.append(thead);
|
||||
// const trHead = window.document.createElement("tr");
|
||||
// thead.append(trHead);
|
||||
// const tbody = window.document.createElement("tbody");
|
||||
// table.append(tbody);
|
||||
|
||||
// const rowElements = signals.createSignal(
|
||||
// /** @type {HTMLTableRowElement[]} */ ([]),
|
||||
// );
|
||||
|
||||
// /**
|
||||
// * @param {Object} args
|
||||
// * @param {HTMLSelectElement} args.select
|
||||
// * @param {Unit} [args.unit]
|
||||
// * @param {(event: MouseEvent) => void} [args.onLeft]
|
||||
// * @param {(event: MouseEvent) => void} [args.onRight]
|
||||
// * @param {(event: MouseEvent) => void} [args.onRemove]
|
||||
// */
|
||||
// function addThCol({ select, onLeft, onRight, onRemove, unit: _unit }) {
|
||||
// const th = window.document.createElement("th");
|
||||
// th.scope = "col";
|
||||
// trHead.append(th);
|
||||
// const div = window.document.createElement("div");
|
||||
// div.append(select);
|
||||
// // const top = window.document.createElement("div");
|
||||
// // div.append(top);
|
||||
// // top.append(select);
|
||||
// // top.append(
|
||||
// // createAnchorElement({
|
||||
// // href: "",
|
||||
// // blank: true,
|
||||
// // }),
|
||||
// // );
|
||||
// const bottom = window.document.createElement("div");
|
||||
// const unit = window.document.createElement("span");
|
||||
// if (_unit) {
|
||||
// unit.innerHTML = _unit;
|
||||
// }
|
||||
// const moveLeft = createButtonElement({
|
||||
// inside: "←",
|
||||
// title: "Move column to the left",
|
||||
// onClick: onLeft || (() => {}),
|
||||
// });
|
||||
// const moveRight = createButtonElement({
|
||||
// inside: "→",
|
||||
// title: "Move column to the right",
|
||||
// onClick: onRight || (() => {}),
|
||||
// });
|
||||
// const remove = createButtonElement({
|
||||
// inside: "×",
|
||||
// title: "Remove column",
|
||||
// onClick: onRemove || (() => {}),
|
||||
// });
|
||||
// bottom.append(unit);
|
||||
// bottom.append(moveLeft);
|
||||
// bottom.append(moveRight);
|
||||
// bottom.append(remove);
|
||||
// div.append(bottom);
|
||||
// th.append(div);
|
||||
// return {
|
||||
// element: th,
|
||||
// /**
|
||||
// * @param {Unit} _unit
|
||||
// */
|
||||
// setUnit(_unit) {
|
||||
// unit.innerHTML = _unit;
|
||||
// },
|
||||
// };
|
||||
// }
|
||||
|
||||
// addThCol({
|
||||
// ...createSelect({
|
||||
// list: serializedIndexes,
|
||||
// signal: serializedIndex,
|
||||
// }),
|
||||
// unit: "index",
|
||||
// });
|
||||
|
||||
// let from = 0;
|
||||
// let to = 0;
|
||||
|
||||
// resources
|
||||
// .getOrCreate(index, serializedIndex())
|
||||
// .fetch()
|
||||
// .then((vec) => {
|
||||
// if (!vec) return;
|
||||
// from = /** @type {number} */ (vec[0]);
|
||||
// to = /** @type {number} */ (vec.at(-1)) + 1;
|
||||
// const trs = /** @type {HTMLTableRowElement[]} */ ([]);
|
||||
// for (let i = vec.length - 1; i >= 0; i--) {
|
||||
// const value = vec[i];
|
||||
// const tr = window.document.createElement("tr");
|
||||
// trs.push(tr);
|
||||
// tbody.append(tr);
|
||||
// const th = window.document.createElement("th");
|
||||
// th.innerHTML = serializeValue({
|
||||
// value,
|
||||
// unit: "index",
|
||||
// });
|
||||
// th.scope = "row";
|
||||
// tr.append(th);
|
||||
// }
|
||||
// rowElements.set(() => trs);
|
||||
// });
|
||||
|
||||
// const owner = signals.getOwner();
|
||||
|
||||
// /**
|
||||
// * @param {Metric} metric
|
||||
// * @param {number} [_colIndex]
|
||||
// */
|
||||
// function addCol(metric, _colIndex = columns().length) {
|
||||
// signals.runWithOwner(owner, () => {
|
||||
// /** @type {VoidFunction | undefined} */
|
||||
// let dispose;
|
||||
// signals.createRoot((_dispose) => {
|
||||
// dispose = _dispose;
|
||||
|
||||
// const metricOption = signals.createSignal({
|
||||
// name: metric,
|
||||
// value: metric,
|
||||
// });
|
||||
// const { select } = createSelect({
|
||||
// list: possibleMetrics.map((metric) => ({
|
||||
// name: metric,
|
||||
// value: metric,
|
||||
// })),
|
||||
// signal: metricOption,
|
||||
// });
|
||||
|
||||
// signals.createEffect(metricOption, (metricOption) => {
|
||||
// select.style.width = `${21 + 7.25 * metricOption.name.length}px`;
|
||||
// });
|
||||
|
||||
// if (_colIndex === columns().length) {
|
||||
// columns.set((l) => {
|
||||
// l.push(metric);
|
||||
// return l;
|
||||
// });
|
||||
// }
|
||||
|
||||
// const colIndex = signals.createSignal(_colIndex);
|
||||
|
||||
// /**
|
||||
// * @param {boolean} right
|
||||
// * @returns {(event: MouseEvent) => void}
|
||||
// */
|
||||
// function createMoveColumnFunction(right) {
|
||||
// return () => {
|
||||
// const oldColIndex = colIndex();
|
||||
// const newColIndex = oldColIndex + (right ? 1 : -1);
|
||||
|
||||
// const currentTh = /** @type {HTMLTableCellElement} */ (
|
||||
// trHead.childNodes[oldColIndex + 1]
|
||||
// );
|
||||
// const oterTh = /** @type {HTMLTableCellElement} */ (
|
||||
// trHead.childNodes[newColIndex + 1]
|
||||
// );
|
||||
|
||||
// if (right) {
|
||||
// oterTh.after(currentTh);
|
||||
// } else {
|
||||
// oterTh.before(currentTh);
|
||||
// }
|
||||
|
||||
// columns.set((l) => {
|
||||
// [l[oldColIndex], l[newColIndex]] = [
|
||||
// l[newColIndex],
|
||||
// l[oldColIndex],
|
||||
// ];
|
||||
// return l;
|
||||
// });
|
||||
|
||||
// const rows = rowElements();
|
||||
// for (let i = 0; i < rows.length; i++) {
|
||||
// const element = rows[i].childNodes[oldColIndex + 1];
|
||||
// const sibling = rows[i].childNodes[newColIndex + 1];
|
||||
// const temp = element.textContent;
|
||||
// element.textContent = sibling.textContent;
|
||||
// sibling.textContent = temp;
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
|
||||
// const th = addThCol({
|
||||
// select,
|
||||
// unit: serdeUnit.deserialize(metric),
|
||||
// onLeft: createMoveColumnFunction(false),
|
||||
// onRight: createMoveColumnFunction(true),
|
||||
// onRemove: () => {
|
||||
// const ci = colIndex();
|
||||
// trHead.childNodes[ci + 1].remove();
|
||||
// columns.set((l) => {
|
||||
// l.splice(ci, 1);
|
||||
// return l;
|
||||
// });
|
||||
// const rows = rowElements();
|
||||
// for (let i = 0; i < rows.length; i++) {
|
||||
// rows[i].childNodes[ci + 1].remove();
|
||||
// }
|
||||
// dispose?.();
|
||||
// },
|
||||
// });
|
||||
|
||||
// signals.createEffect(columns, () => {
|
||||
// colIndex.set(Array.from(trHead.children).indexOf(th.element) - 1);
|
||||
// });
|
||||
|
||||
// console.log(colIndex());
|
||||
|
||||
// signals.createEffect(rowElements, (rowElements) => {
|
||||
// if (!rowElements.length) return;
|
||||
// for (let i = 0; i < rowElements.length; i++) {
|
||||
// const td = window.document.createElement("td");
|
||||
// rowElements[i].append(td);
|
||||
// }
|
||||
|
||||
// signals.createEffect(
|
||||
// () => metricOption().name,
|
||||
// (metric, prevMetric) => {
|
||||
// const unit = serdeUnit.deserialize(metric);
|
||||
// th.setUnit(unit);
|
||||
|
||||
// const vec = resources.getOrCreate(index, metric);
|
||||
|
||||
// vec.fetch({ from, to });
|
||||
|
||||
// const fetchedKey = resources.genFetchedKey({ from, to });
|
||||
|
||||
// columns.set((l) => {
|
||||
// const i = l.indexOf(prevMetric ?? metric);
|
||||
// if (i === -1) {
|
||||
// l.push(metric);
|
||||
// } else {
|
||||
// l[i] = metric;
|
||||
// }
|
||||
// return l;
|
||||
// });
|
||||
|
||||
// signals.createEffect(
|
||||
// () => vec.fetched().get(fetchedKey)?.vec(),
|
||||
// (vec) => {
|
||||
// if (!vec?.length) return;
|
||||
|
||||
// const thIndex = colIndex() + 1;
|
||||
|
||||
// for (let i = 0; i < rowElements.length; i++) {
|
||||
// const iRev = vec.length - 1 - i;
|
||||
// const value = vec[iRev];
|
||||
// // @ts-ignore
|
||||
// rowElements[i].childNodes[thIndex].innerHTML =
|
||||
// serializeValue({
|
||||
// value,
|
||||
// unit,
|
||||
// });
|
||||
// }
|
||||
// },
|
||||
// );
|
||||
|
||||
// return () => metric;
|
||||
// },
|
||||
// );
|
||||
// });
|
||||
// });
|
||||
|
||||
// signals.onCleanup(() => {
|
||||
// dispose?.();
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
|
||||
// columns().forEach((metric, colIndex) => addCol(metric, colIndex));
|
||||
|
||||
// obj.addRandomCol = function () {
|
||||
// addCol(randomFromArray(possibleMetrics));
|
||||
// };
|
||||
|
||||
// return () => index;
|
||||
// });
|
||||
|
||||
// return obj;
|
||||
// } else {
|
||||
// return "";
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* @param {MetricToIndexes} metricToIndexes
|
||||
*/
|
||||
function createIndexToMetrics(metricToIndexes) {
|
||||
// const indexToMetrics = Object.entries(metricToIndexes).reduce(
|
||||
// (arr, [_id, indexes]) => {
|
||||
// const id = /** @type {Metric} */ (_id);
|
||||
// indexes.forEach((i) => {
|
||||
// arr[i] ??= [];
|
||||
// arr[i].push(id);
|
||||
// });
|
||||
// return arr;
|
||||
// },
|
||||
// /** @type {Metric[][]} */ (Array.from({ length: 24 })),
|
||||
// );
|
||||
// indexToMetrics.forEach((arr) => {
|
||||
// arr.sort();
|
||||
// });
|
||||
// return indexToMetrics;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {number | string | Object | Array<any>} args.value
|
||||
* @param {Unit} args.unit
|
||||
*/
|
||||
function serializeValue({ value, unit }) {
|
||||
const t = typeof value;
|
||||
if (value === null) {
|
||||
return "null";
|
||||
} else if (typeof value === "string") {
|
||||
return value;
|
||||
} else if (t !== "number") {
|
||||
return JSON.stringify(value).replaceAll('"', "").slice(1, -1);
|
||||
} else if (value !== 18446744073709552000) {
|
||||
if (unit === "usd" || unit === "difficulty" || unit === "sat/vb") {
|
||||
return value.toLocaleString("en-us", {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
});
|
||||
} else if (unit === "btc") {
|
||||
return value.toLocaleString("en-us", {
|
||||
minimumFractionDigits: 8,
|
||||
maximumFractionDigits: 8,
|
||||
});
|
||||
} else {
|
||||
return value.toLocaleString("en-us");
|
||||
}
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,28 @@
|
||||
import {
|
||||
createShadow,
|
||||
createChoiceField,
|
||||
createHeader,
|
||||
} from "../utils/dom.js";
|
||||
import { createShadow, createChoiceField, createHeader } from "../utils/dom.js";
|
||||
import { chartElement } from "../utils/elements.js";
|
||||
import { serdeChartableIndex } from "../utils/serde.js";
|
||||
import { Unit } from "../utils/units.js";
|
||||
import signals from "../signals.js";
|
||||
import { createChart } from "../chart/index.js";
|
||||
import { colors } from "../chart/colors.js";
|
||||
import { webSockets } from "../utils/ws.js";
|
||||
|
||||
const ONE_BTC_IN_SATS = 100_000_000;
|
||||
|
||||
/** @type {((opt: ChartOption) => void) | null} */
|
||||
let _setOption = null;
|
||||
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {Accessor<ChartOption>} args.option
|
||||
* @param {BrkClient} args.brk
|
||||
* @param {ChartOption} opt
|
||||
*/
|
||||
export function init({ option, brk }) {
|
||||
export function setOption(opt) {
|
||||
if (!_setOption) throw new Error("Chart not initialized");
|
||||
_setOption(opt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {BrkClient} brk
|
||||
*/
|
||||
export function init(brk) {
|
||||
chartElement.append(createShadow("left"));
|
||||
chartElement.append(createShadow("right"));
|
||||
|
||||
@@ -31,8 +35,8 @@ export function init({ option, brk }) {
|
||||
brk,
|
||||
});
|
||||
|
||||
// Create index selector using chart's index state
|
||||
const fieldset = createIndexSelector(option, chart);
|
||||
// Create index selector
|
||||
const { fieldset, setChoices } = createIndexSelector(chart);
|
||||
chartElement.append(fieldset);
|
||||
|
||||
/**
|
||||
@@ -91,61 +95,62 @@ export function init({ option, brk }) {
|
||||
priceSeries.update({ ...last, close });
|
||||
}
|
||||
|
||||
// When option changes, update heading and rebuild blueprints
|
||||
signals.createEffect(option, (opt) => {
|
||||
// Set up the setOption function
|
||||
_setOption = (opt) => {
|
||||
headingElement.innerHTML = opt.title;
|
||||
|
||||
// Update index choices based on option
|
||||
setChoices(computeChoices(opt));
|
||||
|
||||
blueprints = chart.setBlueprints({
|
||||
top: buildTopBlueprints(opt.top),
|
||||
bottom: opt.bottom,
|
||||
onDataLoaded: updatePriceWithLatest,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Live price update listener
|
||||
webSockets.kraken1dCandle.onLatest(updatePriceWithLatest);
|
||||
}
|
||||
|
||||
const ALL_CHOICES = /** @satisfies {ChartableIndexName[]} */ ([
|
||||
"timestamp",
|
||||
"date",
|
||||
"week",
|
||||
"month",
|
||||
"quarter",
|
||||
"semester",
|
||||
"year",
|
||||
"decade",
|
||||
]);
|
||||
|
||||
/**
|
||||
* @param {ChartOption} opt
|
||||
* @returns {ChartableIndexName[]}
|
||||
*/
|
||||
function computeChoices(opt) {
|
||||
if (!opt.top.size && !opt.bottom.size) {
|
||||
return [...ALL_CHOICES];
|
||||
}
|
||||
const rawIndexes = new Set(
|
||||
[Array.from(opt.top.values()), Array.from(opt.bottom.values())]
|
||||
.flat(2)
|
||||
.filter((blueprint) => {
|
||||
const path = Object.values(blueprint.metric.by)[0]?.path ?? "";
|
||||
return !path.includes("constant_");
|
||||
})
|
||||
.flatMap((blueprint) => blueprint.metric.indexes()),
|
||||
);
|
||||
|
||||
return ALL_CHOICES.filter((choice) =>
|
||||
rawIndexes.has(serdeChartableIndex.deserialize(choice)),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Accessor<ChartOption>} option
|
||||
* @param {Chart} chart
|
||||
*/
|
||||
function createIndexSelector(option, chart) {
|
||||
const choices_ = /** @satisfies {ChartableIndexName[]} */ ([
|
||||
"timestamp",
|
||||
"date",
|
||||
"week",
|
||||
"month",
|
||||
"quarter",
|
||||
"semester",
|
||||
"year",
|
||||
"decade",
|
||||
]);
|
||||
|
||||
/** @type {Accessor<typeof choices_>} */
|
||||
const choices = signals.createMemo(() => {
|
||||
const o = option();
|
||||
|
||||
if (!o.top.size && !o.bottom.size) {
|
||||
return [...choices_];
|
||||
}
|
||||
const rawIndexes = new Set(
|
||||
[Array.from(o.top.values()), Array.from(o.bottom.values())]
|
||||
.flat(2)
|
||||
.filter((blueprint) => {
|
||||
const path = Object.values(blueprint.metric.by)[0]?.path ?? "";
|
||||
return !path.includes("constant_");
|
||||
})
|
||||
.flatMap((blueprint) => blueprint.metric.indexes()),
|
||||
);
|
||||
|
||||
return /** @type {any} */ (
|
||||
choices_.filter((choice) =>
|
||||
rawIndexes.has(serdeChartableIndex.deserialize(choice)),
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
function createIndexSelector(chart) {
|
||||
const fieldset = window.document.createElement("fieldset");
|
||||
fieldset.id = "interval";
|
||||
fieldset.dataset.size = "sm";
|
||||
@@ -155,7 +160,11 @@ function createIndexSelector(option, chart) {
|
||||
|
||||
/** @type {HTMLElement | null} */
|
||||
let field = null;
|
||||
signals.createEffect(choices, (newChoices) => {
|
||||
|
||||
/**
|
||||
* @param {ChartableIndexName[]} newChoices
|
||||
*/
|
||||
function setChoices(newChoices) {
|
||||
if (field) field.remove();
|
||||
|
||||
// Use preferred index if available, otherwise fall back to first choice
|
||||
@@ -177,7 +186,7 @@ function createIndexSelector(option, chart) {
|
||||
id: "index",
|
||||
});
|
||||
fieldset.append(field);
|
||||
});
|
||||
}
|
||||
|
||||
return fieldset;
|
||||
return { fieldset, setChoices };
|
||||
}
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
import {
|
||||
searchInput,
|
||||
searchLabelElement,
|
||||
searchResultsElement,
|
||||
} from "../utils/elements.js";
|
||||
import ufuzzy from "../modules/leeoniya-ufuzzy/1.0.19/dist/uFuzzy.mjs";
|
||||
|
||||
/**
|
||||
* @param {Options} options
|
||||
*/
|
||||
export function initSearch(options) {
|
||||
console.log("search: init");
|
||||
|
||||
const haystack = options.list.map((option) => option.title);
|
||||
|
||||
const RESULTS_PER_PAGE = 100;
|
||||
|
||||
/**
|
||||
* @param {uFuzzy.SearchResult} searchResult
|
||||
* @param {number} pageIndex
|
||||
*/
|
||||
function computeResultPage(searchResult, pageIndex) {
|
||||
/** @type {{ option: Option, title: string }[]} */
|
||||
let list = [];
|
||||
|
||||
let [indexes, _info, order] = searchResult || [null, null, null];
|
||||
|
||||
const minIndex = pageIndex * RESULTS_PER_PAGE;
|
||||
|
||||
if (indexes?.length) {
|
||||
const maxIndex = Math.min(
|
||||
(order || indexes).length - 1,
|
||||
minIndex + RESULTS_PER_PAGE - 1,
|
||||
);
|
||||
|
||||
list = Array(maxIndex - minIndex + 1);
|
||||
|
||||
for (let i = minIndex; i <= maxIndex; i++) {
|
||||
let index = indexes[i];
|
||||
|
||||
const title = haystack[index];
|
||||
|
||||
list[i % 100] = {
|
||||
option: options.list[index],
|
||||
title,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/** @type {uFuzzy.Options} */
|
||||
const config = {
|
||||
intraIns: Infinity,
|
||||
intraChars: `[a-z\d' ]`,
|
||||
};
|
||||
|
||||
const fuzzyMultiInsert = /** @type {uFuzzy} */ (
|
||||
ufuzzy({
|
||||
intraIns: 1,
|
||||
})
|
||||
);
|
||||
const fuzzyMultiInsertFuzzier = /** @type {uFuzzy} */ (ufuzzy(config));
|
||||
const fuzzySingleError = /** @type {uFuzzy} */ (
|
||||
ufuzzy({
|
||||
intraMode: 1,
|
||||
...config,
|
||||
})
|
||||
);
|
||||
const fuzzySingleErrorFuzzier = /** @type {uFuzzy} */ (
|
||||
ufuzzy({
|
||||
intraMode: 1,
|
||||
...config,
|
||||
})
|
||||
);
|
||||
|
||||
function inputEvent() {
|
||||
const needle = /** @type {string} */ (searchInput.value);
|
||||
|
||||
searchResultsElement.scrollTo({
|
||||
top: 0,
|
||||
});
|
||||
|
||||
if (!needle) {
|
||||
searchResultsElement.innerHTML = "";
|
||||
return;
|
||||
}
|
||||
|
||||
const outOfOrder = 5;
|
||||
const infoThresh = 5_000;
|
||||
|
||||
let result = fuzzyMultiInsert?.search(
|
||||
haystack,
|
||||
needle,
|
||||
undefined,
|
||||
infoThresh,
|
||||
);
|
||||
|
||||
if (!result?.[0]?.length || !result?.[1]) {
|
||||
result = fuzzyMultiInsert?.search(
|
||||
haystack,
|
||||
needle,
|
||||
outOfOrder,
|
||||
infoThresh,
|
||||
);
|
||||
}
|
||||
|
||||
if (!result?.[0]?.length || !result?.[1]) {
|
||||
result = fuzzySingleError?.search(
|
||||
haystack,
|
||||
needle,
|
||||
outOfOrder,
|
||||
infoThresh,
|
||||
);
|
||||
}
|
||||
|
||||
if (!result?.[0]?.length || !result?.[1]) {
|
||||
result = fuzzySingleErrorFuzzier?.search(
|
||||
haystack,
|
||||
needle,
|
||||
outOfOrder,
|
||||
infoThresh,
|
||||
);
|
||||
}
|
||||
|
||||
if (!result?.[0]?.length || !result?.[1]) {
|
||||
result = fuzzyMultiInsertFuzzier?.search(
|
||||
haystack,
|
||||
needle,
|
||||
undefined,
|
||||
infoThresh,
|
||||
);
|
||||
}
|
||||
|
||||
if (!result?.[0]?.length || !result?.[1]) {
|
||||
result = fuzzyMultiInsertFuzzier?.search(
|
||||
haystack,
|
||||
needle,
|
||||
outOfOrder,
|
||||
infoThresh,
|
||||
);
|
||||
}
|
||||
|
||||
searchResultsElement.innerHTML = "";
|
||||
|
||||
const list = computeResultPage(result, 0);
|
||||
|
||||
list.forEach(({ option, title }) => {
|
||||
const li = window.document.createElement("li");
|
||||
searchResultsElement.appendChild(li);
|
||||
|
||||
const element = options.createOptionElement({
|
||||
option,
|
||||
name: title,
|
||||
});
|
||||
|
||||
if (element) {
|
||||
li.append(element);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (searchInput.value) {
|
||||
inputEvent();
|
||||
}
|
||||
|
||||
searchInput.addEventListener("input", inputEvent);
|
||||
}
|
||||
|
||||
document.addEventListener("keydown", (e) => {
|
||||
const el = document.activeElement;
|
||||
const isTextInput =
|
||||
el?.tagName === "INPUT" &&
|
||||
/** @type {HTMLInputElement} */ (el).type === "text";
|
||||
if (e.key === "/" && !isTextInput) {
|
||||
e.preventDefault();
|
||||
searchLabelElement.click();
|
||||
searchInput.focus();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Object} Resource
|
||||
* @property {Signal<T | null>} data
|
||||
* @property {Signal<boolean>} loading
|
||||
* @property {Signal<Error | null>} error
|
||||
* @property {(...args: any[]) => Promise<T | null>} fetch
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Object} RangeState
|
||||
* @property {Signal<MetricData<T> | null>} response
|
||||
* @property {Signal<boolean>} loading
|
||||
*/
|
||||
/** @typedef {RangeState<unknown>} AnyRangeState */
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Object} MetricResource
|
||||
* @property {string} path
|
||||
* @property {(from?: number, to?: number) => RangeState<T>} range
|
||||
* @property {(from?: number, to?: number) => Promise<MetricData<T> | null>} fetch
|
||||
*/
|
||||
/** @typedef {MetricResource<unknown>} AnyMetricResource */
|
||||
|
||||
/**
|
||||
* @typedef {{ createResource: typeof createResource, useMetricEndpoint: typeof useMetricEndpoint }} Resources
|
||||
*/
|
||||
|
||||
import signals from "./signals.js";
|
||||
|
||||
/**
|
||||
* Create a generic reactive resource wrapper for any async fetcher
|
||||
* @template T
|
||||
* @template {any[]} Args
|
||||
* @param {(...args: Args) => Promise<T>} fetcher
|
||||
* @returns {Resource<T>}
|
||||
*/
|
||||
function createResource(fetcher) {
|
||||
const owner = signals.getOwner();
|
||||
return signals.runWithOwner(owner, () => {
|
||||
const data = signals.createSignal(/** @type {T | null} */ (null));
|
||||
const loading = signals.createSignal(false);
|
||||
const error = signals.createSignal(/** @type {Error | null} */ (null));
|
||||
|
||||
return {
|
||||
data,
|
||||
loading,
|
||||
error,
|
||||
/**
|
||||
* @param {Args} args
|
||||
*/
|
||||
async fetch(...args) {
|
||||
loading.set(true);
|
||||
error.set(null);
|
||||
try {
|
||||
const result = await fetcher(...args);
|
||||
data.set(() => result);
|
||||
return result;
|
||||
} catch (e) {
|
||||
error.set(e instanceof Error ? e : new Error(String(e)));
|
||||
return null;
|
||||
} finally {
|
||||
loading.set(false);
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a reactive resource wrapper for a MetricEndpoint with multi-range support
|
||||
* @template T
|
||||
* @param {MetricEndpoint<T>} endpoint
|
||||
* @returns {MetricResource<T>}
|
||||
*/
|
||||
function useMetricEndpoint(endpoint) {
|
||||
const owner = signals.getOwner();
|
||||
return signals.runWithOwner(owner, () => {
|
||||
/** @type {Map<string, RangeState<T>>} */
|
||||
const ranges = new Map();
|
||||
|
||||
/**
|
||||
* Get or create range state
|
||||
* @param {number} [from=-10000]
|
||||
* @param {number} [to]
|
||||
* @returns {RangeState<T>}
|
||||
*/
|
||||
function range(from = -10000, to) {
|
||||
const key = `${from}-${to ?? ""}`;
|
||||
const existing = ranges.get(key);
|
||||
if (existing) return existing;
|
||||
|
||||
/** @type {RangeState<T>} */
|
||||
const state = {
|
||||
response: signals.createSignal(
|
||||
/** @type {MetricData<T> | null} */ (null),
|
||||
),
|
||||
loading: signals.createSignal(false),
|
||||
};
|
||||
ranges.set(key, state);
|
||||
return state;
|
||||
}
|
||||
|
||||
return {
|
||||
path: endpoint.path,
|
||||
range,
|
||||
/**
|
||||
* Fetch data for a range
|
||||
* @param {number} [start=-10000]
|
||||
* @param {number} [end]
|
||||
*/
|
||||
async fetch(start = -10000, end) {
|
||||
const r = range(start, end);
|
||||
r.loading.set(true);
|
||||
try {
|
||||
const result = await endpoint.slice(start, end).fetch(r.response.set);
|
||||
return result;
|
||||
} finally {
|
||||
r.loading.set(false);
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export const resources = { createResource, useMetricEndpoint };
|
||||
@@ -1,134 +0,0 @@
|
||||
/**
|
||||
* @import { SignalOptions } from "./modules/solidjs-signals/0.6.3/dist/types/core/core.js"
|
||||
* @import { getOwner as GetOwner, onCleanup as OnCleanup } from "./modules/solidjs-signals/0.6.3/dist/types/core/owner.js"
|
||||
* @import { createSignal as CreateSignal, createEffect as CreateEffect, createMemo as CreateMemo, createRoot as CreateRoot, runWithOwner as RunWithOwner, Setter } from "./modules/solidjs-signals/0.6.3/dist/types/signals.js";
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {() => T} Accessor
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Accessor<T> & { set: Setter<T>; reset: VoidFunction }} Signal
|
||||
*/
|
||||
|
||||
import {
|
||||
createSignal,
|
||||
createEffect,
|
||||
getOwner,
|
||||
createMemo,
|
||||
createRoot,
|
||||
runWithOwner,
|
||||
onCleanup,
|
||||
} from "./modules/solidjs-signals/0.6.3/dist/prod.js";
|
||||
import { createPersistedValue } from "./utils/persisted.js";
|
||||
|
||||
// let effectCount = 0;
|
||||
|
||||
const signals = {
|
||||
createSolidSignal: /** @type {typeof CreateSignal} */ (createSignal),
|
||||
createEffect: /** @type {typeof CreateEffect} */ (createEffect),
|
||||
createScopedEffect: /** @type {typeof CreateEffect} */ (
|
||||
// @ts-ignore
|
||||
(compute, effect) => {
|
||||
let dispose = /** @type {VoidFunction | null} */ (null);
|
||||
|
||||
if (getOwner() === null) {
|
||||
throw Error("No owner");
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
if (dispose) {
|
||||
dispose();
|
||||
dispose = null;
|
||||
// console.log("effectCount = ", --effectCount);
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
createEffect(compute, (v, oldV) => {
|
||||
// console.log("effectCount = ", ++effectCount);
|
||||
cleanup();
|
||||
signals.createRoot((_dispose) => {
|
||||
dispose = _dispose;
|
||||
return effect(v, oldV);
|
||||
});
|
||||
signals.onCleanup(cleanup);
|
||||
});
|
||||
signals.onCleanup(cleanup);
|
||||
}
|
||||
),
|
||||
createMemo: /** @type {typeof CreateMemo} */ (createMemo),
|
||||
createRoot: /** @type {typeof CreateRoot} */ (createRoot),
|
||||
getOwner: /** @type {typeof GetOwner} */ (getOwner),
|
||||
runWithOwner: /** @type {typeof RunWithOwner} */ (runWithOwner),
|
||||
onCleanup: /** @type {typeof OnCleanup} */ (onCleanup),
|
||||
/**
|
||||
* @template T
|
||||
* @param {T} initialValue
|
||||
* @param {SignalOptions<T>} [options]
|
||||
* @returns {Signal<T>}
|
||||
*/
|
||||
createSignal(initialValue, options) {
|
||||
const [get, set] = this.createSolidSignal(
|
||||
/** @type {any} */ (initialValue),
|
||||
options,
|
||||
);
|
||||
|
||||
// @ts-ignore
|
||||
get.set = set;
|
||||
|
||||
// @ts-ignore
|
||||
get.reset = () => set(initialValue);
|
||||
|
||||
// @ts-ignore
|
||||
return get;
|
||||
},
|
||||
/**
|
||||
* @template T
|
||||
* @param {Object} args
|
||||
* @param {T} args.defaultValue
|
||||
* @param {string} args.storageKey
|
||||
* @param {string} [args.urlKey]
|
||||
* @param {(v: T) => string} args.serialize
|
||||
* @param {(s: string) => T} args.deserialize
|
||||
* @param {boolean} [args.saveDefaultValue]
|
||||
* @returns {Signal<T>}
|
||||
*/
|
||||
createPersistedSignal({
|
||||
defaultValue,
|
||||
storageKey,
|
||||
urlKey,
|
||||
serialize,
|
||||
deserialize,
|
||||
saveDefaultValue = false,
|
||||
}) {
|
||||
const persisted = createPersistedValue({
|
||||
defaultValue,
|
||||
storageKey,
|
||||
urlKey,
|
||||
serialize,
|
||||
deserialize,
|
||||
saveDefaultValue,
|
||||
});
|
||||
|
||||
const signal = this.createSignal(persisted.value);
|
||||
|
||||
// Sync signal changes to persisted storage
|
||||
let firstRun = true;
|
||||
this.createEffect(signal, (value) => {
|
||||
if (firstRun) {
|
||||
firstRun = false;
|
||||
} else {
|
||||
persisted.set(value);
|
||||
}
|
||||
});
|
||||
|
||||
return signal;
|
||||
},
|
||||
};
|
||||
/** @typedef {typeof signals} Signals */
|
||||
|
||||
export default signals;
|
||||
Reference in New Issue
Block a user