solid-use
Version:
A collection of SolidJS utilities
85 lines (72 loc) • 1.65 kB
text/typescript
import type { Component } from 'solid-js';
import { onCleanup } from 'solid-js';
let PROVIDER: ProviderTree | undefined;
interface ProviderData<T> {
value: T;
}
interface ProviderTree {
parent?: ProviderTree;
data: Record<string, ProviderData<any> | undefined>;
}
export function capturedProvider<T extends any[], R>(
callback: (...args: T) => R,
): (...args: T) => R {
const current = PROVIDER;
return (...args) => {
const parent = PROVIDER;
PROVIDER = current;
try {
return callback(...args);
} finally {
PROVIDER = parent;
}
};
}
export function providerScope<T>(callback: () => T): T {
const parent = PROVIDER;
PROVIDER = {
parent,
data: {},
};
try {
return callback();
} finally {
PROVIDER = parent;
}
}
export interface Provider<T> {
id: number;
defaultValue: T;
}
let ID = 0;
export function createProvider<T>(defaultValue: T): Provider<T> {
return {
id: ID++,
defaultValue,
};
}
export function provide<T>(context: Provider<T>, value: T): void {
const parent = PROVIDER;
if (parent) {
parent.data[context.id] = { value };
onCleanup(() => {
parent.data[context.id] = undefined;
});
}
}
export function inject<T>(context: Provider<T>): T {
let current = PROVIDER;
while (current) {
const currentData = current.data[context.id];
if (currentData) {
return currentData.value;
}
current = current.parent;
}
return context.defaultValue;
}
export function withProvider<T extends Record<string, any>>(
Comp: Component<T>,
): Component<T> {
return props => providerScope(() => Comp(props));
}