@epoch32/visage 1.0.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/client.d.ts +5 -0
- package/dist/api/file-router.d.ts +29 -0
- package/dist/api/handler.d.ts +15 -0
- package/dist/api/index.d.ts +12 -0
- package/dist/{src/api → api}/index.js +87 -2
- package/dist/api/middleware.d.ts +11 -0
- package/dist/api/pragma.d.ts +21 -0
- package/dist/api/procedure.d.ts +66 -0
- package/dist/api/types.d.ts +181 -0
- package/dist/charts/Area.d.ts +18 -0
- package/dist/charts/Axis.d.ts +21 -0
- package/dist/charts/Bar.d.ts +10 -0
- package/dist/charts/CartesianGrid.d.ts +10 -0
- package/dist/charts/Chart.d.ts +16 -0
- package/dist/charts/Cursor.d.ts +8 -0
- package/dist/charts/Legend.d.ts +9 -0
- package/dist/charts/Line.d.ts +18 -0
- package/dist/charts/Pie.d.ts +12 -0
- package/dist/charts/Tooltip.d.ts +12 -0
- package/dist/charts/context.d.ts +20 -0
- package/dist/charts/index.d.ts +14 -0
- package/dist/{src/charts → charts}/index.js +87 -2
- package/dist/charts/path.d.ts +27 -0
- package/dist/charts/scale.d.ts +23 -0
- package/dist/charts/types.d.ts +43 -0
- package/dist/devtools/DomTab.d.ts +6 -0
- package/dist/devtools/GraphInspector.d.ts +11 -0
- package/dist/devtools/GraphTab.d.ts +10 -0
- package/dist/devtools/QueryTab.d.ts +10 -0
- package/dist/devtools/RpcTab.d.ts +10 -0
- package/dist/devtools/SignalsTab.d.ts +10 -0
- package/dist/devtools/component.d.ts +2 -0
- package/dist/devtools/highlighter.d.ts +2 -0
- package/dist/devtools/hub.d.ts +41 -0
- package/dist/devtools/index.d.ts +9 -0
- package/dist/{src/devtools → devtools}/index.js +87 -2
- package/dist/devtools/styles.d.ts +1 -0
- package/dist/devtools/types.d.ts +44 -0
- package/dist/dom/async.d.ts +41 -0
- package/dist/dom/control-flow.d.ts +53 -0
- package/dist/dom/index.d.ts +3 -0
- package/dist/{src/dom → dom}/index.js +87 -2
- package/dist/dom/lazy.d.ts +30 -0
- package/dist/dom/render.d.ts +23 -0
- package/dist/dom/resource.d.ts +34 -0
- package/dist/form/form.d.ts +41 -0
- package/dist/form/index.d.ts +2 -0
- package/dist/{src/form → form}/index.js +87 -2
- package/dist/form/schema.d.ts +96 -0
- package/dist/index.d.ts +15 -0
- package/dist/{src/index.js → index.js} +87 -2
- package/dist/jsx-dev-runtime/index.d.ts +1 -0
- package/dist/jsx-runtime/index.d.ts +8 -0
- package/dist/{src/jsx-runtime → jsx-runtime}/index.js +87 -2
- package/dist/jsx-runtime/jsx.d.ts +278 -0
- package/dist/query/create-mutation.d.ts +3 -0
- package/dist/query/create-query.d.ts +4 -0
- package/dist/query/focus-manager.d.ts +14 -0
- package/dist/query/index.d.ts +9 -0
- package/dist/{src/query → query}/index.js +87 -2
- package/dist/query/mutation-cache.d.ts +24 -0
- package/dist/query/online-manager.d.ts +14 -0
- package/dist/query/query-cache.d.ts +69 -0
- package/dist/query/query-client.d.ts +46 -0
- package/dist/query/types.d.ts +131 -0
- package/dist/query/utils.d.ts +16 -0
- package/dist/router/index.d.ts +1 -0
- package/dist/{src/router → router}/index.js +87 -2
- package/dist/router/router.d.ts +91 -0
- package/dist/rpc/client.d.ts +2 -0
- package/dist/rpc/error.d.ts +16 -0
- package/dist/rpc/index.d.ts +7 -0
- package/dist/{src/rpc → rpc}/index.js +87 -2
- package/dist/rpc/procedure.d.ts +8 -0
- package/dist/rpc/router.d.ts +19 -0
- package/dist/rpc/server.d.ts +3 -0
- package/dist/rpc/types.d.ts +200 -0
- package/dist/server/hydrate.d.ts +5 -0
- package/dist/server/index.d.ts +3 -0
- package/dist/{src/server → server}/index.js +87 -2
- package/dist/server/render-to-stream.d.ts +9 -0
- package/dist/server/render-to-string.d.ts +6 -0
- package/dist/signals/computed.d.ts +61 -0
- package/dist/signals/context.d.ts +44 -0
- package/dist/signals/effect.d.ts +56 -0
- package/dist/signals/index.d.ts +8 -0
- package/dist/{src/signals → signals}/index.js +87 -2
- package/dist/signals/scope.d.ts +61 -0
- package/dist/signals/signal.d.ts +40 -0
- package/dist/signals/store.d.ts +45 -0
- package/dist/signals/system.d.ts +56 -0
- package/dist/signals/types.d.ts +58 -0
- package/dist/style/component.d.ts +49 -0
- package/dist/style/create-style.d.ts +63 -0
- package/dist/style/cx.d.ts +18 -0
- package/dist/style/hash.d.ts +8 -0
- package/dist/style/index.d.ts +8 -0
- package/dist/{src/style → style}/index.js +87 -2
- package/dist/style/layout.d.ts +129 -0
- package/dist/style/manager.d.ts +31 -0
- package/dist/style/parser.d.ts +12 -0
- package/dist/style/scale.d.ts +82 -0
- package/dist/template/index.d.ts +1 -0
- package/dist/{src/template → template}/index.js +87 -2
- package/dist/template/template.d.ts +8 -0
- package/dist/ui/accordion.d.ts +81 -0
- package/dist/ui/command-dialog.d.ts +10 -0
- package/dist/ui/command.d.ts +103 -0
- package/dist/ui/data-table.d.ts +38 -0
- package/dist/ui/dialog.d.ts +102 -0
- package/dist/ui/dropdown-menu.d.ts +92 -0
- package/dist/ui/icon.d.ts +18 -0
- package/dist/ui/index.d.ts +14 -0
- package/dist/{src/ui → ui}/index.js +87 -2
- package/dist/ui/layout.d.ts +1 -0
- package/dist/ui/popover.d.ts +68 -0
- package/dist/ui/switch.d.ts +31 -0
- package/dist/ui/tabs.d.ts +71 -0
- package/dist/ui/toast.d.ts +91 -0
- package/dist/ui/tooltip.d.ts +64 -0
- package/dist/ui/utils.d.ts +21 -0
- package/dist/virtual/index.d.ts +2 -0
- package/dist/{src/virtual → virtual}/index.js +87 -2
- package/dist/virtual/virtual-list.d.ts +21 -0
- package/dist/virtual/virtualizer.d.ts +31 -0
- package/dist/vite/hmr.d.ts +7 -0
- package/dist/vite/index.d.ts +3 -0
- package/dist/{src/vite → vite}/index.js +4 -0
- package/dist/vite/lucide.d.ts +27 -0
- package/dist/vite/plugin.d.ts +3 -0
- package/dist/vite/rpc-middleware.d.ts +5 -0
- package/dist/vite/types.d.ts +59 -0
- package/package.json +40 -40
- package/src/signals/index.ts +1 -0
- package/src/signals/signal.ts +110 -2
- package/src/signals/types.ts +9 -0
- package/src/vite/plugin.ts +4 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import type { InferSchemaType, SchemaLike, ValidationIssue } from "../form/schema";
|
|
2
|
+
import type { CreateQueryOptions, MutationOptions, MutationResult, QueryResult } from "../query/types";
|
|
3
|
+
export type RPCErrorCode = "BAD_REQUEST" | "UNAUTHORIZED" | "FORBIDDEN" | "NOT_FOUND" | "METHOD_NOT_ALLOWED" | "TIMEOUT" | "CONFLICT" | "UNPROCESSABLE_CONTENT" | "INTERNAL_SERVER_ERROR";
|
|
4
|
+
export type ProcedureType = "query" | "mutation" | "subscription";
|
|
5
|
+
export type MiddlewareFn<TContext = any, TNewContext = TContext> = (opts: {
|
|
6
|
+
ctx: TContext;
|
|
7
|
+
req: Request;
|
|
8
|
+
signal: AbortSignal;
|
|
9
|
+
next: (opts?: {
|
|
10
|
+
ctx?: TNewContext;
|
|
11
|
+
}) => Promise<any>;
|
|
12
|
+
}) => Promise<any>;
|
|
13
|
+
export interface ProcedureOptionsWithInput<TSchema extends SchemaLike<any>, TOutput = any, TContext = any> {
|
|
14
|
+
input: TSchema;
|
|
15
|
+
output?: SchemaLike<TOutput>;
|
|
16
|
+
resolve: (opts: {
|
|
17
|
+
input: InferSchemaType<TSchema>;
|
|
18
|
+
ctx: TContext;
|
|
19
|
+
req: Request;
|
|
20
|
+
signal: AbortSignal;
|
|
21
|
+
}) => Promise<TOutput> | TOutput | AsyncIterable<TOutput>;
|
|
22
|
+
}
|
|
23
|
+
export interface ProcedureOptionsWithoutInput<TOutput = any, TContext = any> {
|
|
24
|
+
input?: undefined;
|
|
25
|
+
output?: SchemaLike<TOutput>;
|
|
26
|
+
resolve: (opts: {
|
|
27
|
+
input: void;
|
|
28
|
+
ctx: TContext;
|
|
29
|
+
req: Request;
|
|
30
|
+
signal: AbortSignal;
|
|
31
|
+
}) => Promise<TOutput> | TOutput | AsyncIterable<TOutput>;
|
|
32
|
+
}
|
|
33
|
+
export type ProcedureOptions<TInput = any, TOutput = any, TContext = any> = {
|
|
34
|
+
input?: SchemaLike<TInput>;
|
|
35
|
+
output?: SchemaLike<TOutput>;
|
|
36
|
+
resolve: (opts: {
|
|
37
|
+
input: TInput;
|
|
38
|
+
ctx: TContext;
|
|
39
|
+
req: Request;
|
|
40
|
+
signal: AbortSignal;
|
|
41
|
+
}) => Promise<TOutput> | TOutput | AsyncIterable<TOutput>;
|
|
42
|
+
};
|
|
43
|
+
export interface Procedure<TType extends ProcedureType = ProcedureType, TInput = any, TOutput = any, TContext = any> {
|
|
44
|
+
type: TType;
|
|
45
|
+
inputSchema?: SchemaLike<TInput>;
|
|
46
|
+
outputSchema?: SchemaLike<TOutput>;
|
|
47
|
+
middlewares: MiddlewareFn<any, any>[];
|
|
48
|
+
resolve: (opts: {
|
|
49
|
+
input: TInput;
|
|
50
|
+
ctx: TContext;
|
|
51
|
+
req: Request;
|
|
52
|
+
signal: AbortSignal;
|
|
53
|
+
}) => Promise<TOutput> | TOutput | AsyncIterable<TOutput>;
|
|
54
|
+
}
|
|
55
|
+
export type ProcedureRecord = Record<string, Procedure<any, any, any, any> | Router<any, any>>;
|
|
56
|
+
export interface Router<TRecord extends ProcedureRecord = ProcedureRecord, TContext = any> {
|
|
57
|
+
_def: {
|
|
58
|
+
record: TRecord;
|
|
59
|
+
middlewares: MiddlewareFn<any, any>[];
|
|
60
|
+
};
|
|
61
|
+
query<TName extends string, TSchema extends SchemaLike<any>, TOutput = any>(name: TName, options: ProcedureOptionsWithInput<TSchema, TOutput, TContext>): Router<TRecord & {
|
|
62
|
+
[K in TName]: Procedure<"query", InferSchemaType<TSchema>, TOutput, TContext>;
|
|
63
|
+
}, TContext>;
|
|
64
|
+
query<TName extends string, TOutput = any>(name: TName, options: ProcedureOptionsWithoutInput<TOutput, TContext>): Router<TRecord & {
|
|
65
|
+
[K in TName]: Procedure<"query", void, TOutput, TContext>;
|
|
66
|
+
}, TContext>;
|
|
67
|
+
mutation<TName extends string, TSchema extends SchemaLike<any>, TOutput = any>(name: TName, options: ProcedureOptionsWithInput<TSchema, TOutput, TContext>): Router<TRecord & {
|
|
68
|
+
[K in TName]: Procedure<"mutation", InferSchemaType<TSchema>, TOutput, TContext>;
|
|
69
|
+
}, TContext>;
|
|
70
|
+
mutation<TName extends string, TOutput = any>(name: TName, options: ProcedureOptionsWithoutInput<TOutput, TContext>): Router<TRecord & {
|
|
71
|
+
[K in TName]: Procedure<"mutation", void, TOutput, TContext>;
|
|
72
|
+
}, TContext>;
|
|
73
|
+
subscription<TName extends string, TSchema extends SchemaLike<any>, TOutput = any>(name: TName, options: ProcedureOptionsWithInput<TSchema, TOutput, TContext>): Router<TRecord & {
|
|
74
|
+
[K in TName]: Procedure<"subscription", InferSchemaType<TSchema>, TOutput, TContext>;
|
|
75
|
+
}, TContext>;
|
|
76
|
+
subscription<TName extends string, TOutput = any>(name: TName, options: ProcedureOptionsWithoutInput<TOutput, TContext>): Router<TRecord & {
|
|
77
|
+
[K in TName]: Procedure<"subscription", void, TOutput, TContext>;
|
|
78
|
+
}, TContext>;
|
|
79
|
+
use<TNewContext = TContext>(middleware: MiddlewareFn<TContext, TNewContext>): Router<TRecord, TNewContext>;
|
|
80
|
+
merge<TPrefix extends string, TSubRecord extends ProcedureRecord>(prefix: TPrefix, router: Router<TSubRecord, TContext>): Router<TRecord & {
|
|
81
|
+
[K in TPrefix]: Router<TSubRecord, TContext>;
|
|
82
|
+
}, TContext>;
|
|
83
|
+
}
|
|
84
|
+
export interface CORSOptions {
|
|
85
|
+
origin?: string | string[] | ((origin: string) => boolean | string);
|
|
86
|
+
methods?: string[];
|
|
87
|
+
allowedHeaders?: string[];
|
|
88
|
+
exposedHeaders?: string[];
|
|
89
|
+
credentials?: boolean;
|
|
90
|
+
maxAge?: number;
|
|
91
|
+
}
|
|
92
|
+
export type DynamicHeadersFn = (req: Request, ctx: any) => Promise<Record<string, string>> | Record<string, string>;
|
|
93
|
+
export type HeadersConfig = Record<string, string> | DynamicHeadersFn;
|
|
94
|
+
export interface RouteRule {
|
|
95
|
+
/**
|
|
96
|
+
* Response headers to attach to all matching requests.
|
|
97
|
+
*/
|
|
98
|
+
headers?: HeadersConfig;
|
|
99
|
+
/**
|
|
100
|
+
* Required request headers. If any are missing, automatically rejects with HTTP 401 Unauthorized.
|
|
101
|
+
*/
|
|
102
|
+
requireHeaders?: string[];
|
|
103
|
+
/**
|
|
104
|
+
* Required query parameters. If missing on GET requests, rejects with HTTP 400 Bad Request.
|
|
105
|
+
*/
|
|
106
|
+
requireParams?: string[];
|
|
107
|
+
/**
|
|
108
|
+
* Custom guard function for matching requests. Return false or throw RPCError to reject.
|
|
109
|
+
*/
|
|
110
|
+
guard?: (opts: {
|
|
111
|
+
req: Request;
|
|
112
|
+
ctx: any;
|
|
113
|
+
path: string;
|
|
114
|
+
}) => Promise<boolean | void> | boolean | void;
|
|
115
|
+
}
|
|
116
|
+
export interface FetchHandlerOptions<TRouter extends Router<any, any> = Router<any, any>, TContext = any> {
|
|
117
|
+
router: TRouter;
|
|
118
|
+
endpoint?: string;
|
|
119
|
+
createContext?: (opts: {
|
|
120
|
+
req: Request;
|
|
121
|
+
extra: any[];
|
|
122
|
+
}) => Promise<TContext> | TContext;
|
|
123
|
+
onError?: (opts: {
|
|
124
|
+
error: any;
|
|
125
|
+
path?: string;
|
|
126
|
+
req: Request;
|
|
127
|
+
}) => void;
|
|
128
|
+
cors?: boolean | CORSOptions;
|
|
129
|
+
securityHeaders?: boolean | Record<string, string>;
|
|
130
|
+
/**
|
|
131
|
+
* Declarative pattern rules matching URL paths or procedure names (e.g. "*", "/api/*", "admin.*").
|
|
132
|
+
* Supports wildcard matching with '*'.
|
|
133
|
+
*/
|
|
134
|
+
rules?: Record<string, RouteRule> | Array<{
|
|
135
|
+
match: string;
|
|
136
|
+
} & RouteRule>;
|
|
137
|
+
}
|
|
138
|
+
export type ClientHeadersRule = Record<string, string> | (() => Promise<Record<string, string>> | Record<string, string>);
|
|
139
|
+
export interface ClientOptions {
|
|
140
|
+
baseUrl: string;
|
|
141
|
+
fetch?: typeof fetch;
|
|
142
|
+
headers?: Record<string, string> | Record<string, ClientHeadersRule> | (() => Promise<Record<string, string>> | Record<string, string>);
|
|
143
|
+
}
|
|
144
|
+
export interface SubscriptionCallbacks<TData = any> {
|
|
145
|
+
onData: (data: TData) => void;
|
|
146
|
+
onError?: (error: any) => void;
|
|
147
|
+
onComplete?: () => void;
|
|
148
|
+
}
|
|
149
|
+
export interface SubscriptionHandle {
|
|
150
|
+
unsubscribe: () => void;
|
|
151
|
+
}
|
|
152
|
+
export type InferProcedureInput<P> = P extends Procedure<any, infer TInput, any, any> ? TInput : void;
|
|
153
|
+
export type InferProcedureOutput<P> = P extends Procedure<any, any, infer TOutput, any> ? TOutput : unknown;
|
|
154
|
+
export type ClientQueryMethod<P> = InferProcedureInput<P> extends void | undefined ? (input?: void, options?: {
|
|
155
|
+
signal?: AbortSignal;
|
|
156
|
+
headers?: Record<string, string>;
|
|
157
|
+
}) => Promise<InferProcedureOutput<P>> : (input: InferProcedureInput<P>, options?: {
|
|
158
|
+
signal?: AbortSignal;
|
|
159
|
+
headers?: Record<string, string>;
|
|
160
|
+
}) => Promise<InferProcedureOutput<P>>;
|
|
161
|
+
export type ClientMutationMethod<P> = InferProcedureInput<P> extends void | undefined ? (input?: void, options?: {
|
|
162
|
+
signal?: AbortSignal;
|
|
163
|
+
headers?: Record<string, string>;
|
|
164
|
+
}) => Promise<InferProcedureOutput<P>> : (input: InferProcedureInput<P>, options?: {
|
|
165
|
+
signal?: AbortSignal;
|
|
166
|
+
headers?: Record<string, string>;
|
|
167
|
+
}) => Promise<InferProcedureOutput<P>>;
|
|
168
|
+
export type ClientSubscriptionMethod<P> = InferProcedureInput<P> extends void | undefined ? (input: void | undefined, callbacks: SubscriptionCallbacks<InferProcedureOutput<P>>) => SubscriptionHandle : (input: InferProcedureInput<P>, callbacks: SubscriptionCallbacks<InferProcedureOutput<P>>) => SubscriptionHandle;
|
|
169
|
+
export type ClientProcedure<P> = P extends Procedure<"query", infer TInput, infer TOutput, any> ? {
|
|
170
|
+
query: ClientQueryMethod<P>;
|
|
171
|
+
createQuery: (input?: TInput | (() => TInput), extra?: Partial<CreateQueryOptions<TOutput, any, TOutput, any>>) => QueryResult<TOutput, any>;
|
|
172
|
+
useQuery: (input?: TInput | (() => TInput), extra?: Partial<CreateQueryOptions<TOutput, any, TOutput, any>>) => QueryResult<TOutput, any>;
|
|
173
|
+
queryKey: (input?: TInput) => unknown[];
|
|
174
|
+
queryOptions: (input?: TInput, extra?: Partial<CreateQueryOptions<TOutput, any, TOutput, any>>) => CreateQueryOptions<TOutput, any, TOutput, any>;
|
|
175
|
+
} : P extends Procedure<"mutation", infer TInput, infer TOutput, any> ? {
|
|
176
|
+
mutate: ClientMutationMethod<P>;
|
|
177
|
+
createMutation: (extra?: Partial<MutationOptions<TOutput, any, TInput, any>>) => MutationResult<TOutput, any, TInput, any>;
|
|
178
|
+
useMutation: (extra?: Partial<MutationOptions<TOutput, any, TInput, any>>) => MutationResult<TOutput, any, TInput, any>;
|
|
179
|
+
mutationKey: () => unknown[];
|
|
180
|
+
mutationOptions: (extra?: Partial<MutationOptions<TOutput, any, TInput, any>>) => MutationOptions<TOutput, any, TInput, any>;
|
|
181
|
+
} : P extends Procedure<"subscription", any, any, any> ? {
|
|
182
|
+
subscribe: ClientSubscriptionMethod<P>;
|
|
183
|
+
} : never;
|
|
184
|
+
export type ClientRouter<R> = R extends Router<infer TRecord, any> ? {
|
|
185
|
+
[K in keyof TRecord]: TRecord[K] extends Procedure<any, any, any, any> ? ClientProcedure<TRecord[K]> : TRecord[K] extends Router<any, any> ? ClientRouter<TRecord[K]> : never;
|
|
186
|
+
} : never;
|
|
187
|
+
export interface RPCResponseSuccess<T = any> {
|
|
188
|
+
result: {
|
|
189
|
+
data: T;
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
export interface RPCResponseError {
|
|
193
|
+
error: {
|
|
194
|
+
code: RPCErrorCode;
|
|
195
|
+
message: string;
|
|
196
|
+
issues?: ValidationIssue[];
|
|
197
|
+
data?: any;
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
export type RPCResponse<T = any> = RPCResponseSuccess<T> | RPCResponseError;
|
|
@@ -431,10 +431,12 @@ class Signal {
|
|
|
431
431
|
_value;
|
|
432
432
|
_subscribers = new Set;
|
|
433
433
|
_equals;
|
|
434
|
+
_onSet;
|
|
434
435
|
version = 0;
|
|
435
|
-
constructor(initialValue, equals) {
|
|
436
|
+
constructor(initialValue, equals, onSet) {
|
|
436
437
|
this._value = initialValue;
|
|
437
438
|
this._equals = equals ?? Object.is;
|
|
439
|
+
this._onSet = onSet;
|
|
438
440
|
}
|
|
439
441
|
get() {
|
|
440
442
|
if (currentSubscriber !== null && currentSubscriber.state !== 3 /* DISPOSED */) {
|
|
@@ -459,6 +461,9 @@ class Signal {
|
|
|
459
461
|
}
|
|
460
462
|
this._value = newValue;
|
|
461
463
|
this.version++;
|
|
464
|
+
if (this._onSet) {
|
|
465
|
+
this._onSet(newValue);
|
|
466
|
+
}
|
|
462
467
|
batch(() => {
|
|
463
468
|
this.notify();
|
|
464
469
|
});
|
|
@@ -484,11 +489,91 @@ class Signal {
|
|
|
484
489
|
}
|
|
485
490
|
}
|
|
486
491
|
}
|
|
492
|
+
function resolveStorage(storageOption) {
|
|
493
|
+
if (storageOption && typeof storageOption === "object") {
|
|
494
|
+
return storageOption;
|
|
495
|
+
}
|
|
496
|
+
if (storageOption === "session") {
|
|
497
|
+
try {
|
|
498
|
+
if (typeof sessionStorage !== "undefined")
|
|
499
|
+
return sessionStorage;
|
|
500
|
+
} catch {}
|
|
501
|
+
try {
|
|
502
|
+
if (typeof window !== "undefined" && window.sessionStorage) {
|
|
503
|
+
return window.sessionStorage;
|
|
504
|
+
}
|
|
505
|
+
} catch {}
|
|
506
|
+
try {
|
|
507
|
+
if (typeof globalThis !== "undefined" && globalThis.sessionStorage) {
|
|
508
|
+
return globalThis.sessionStorage;
|
|
509
|
+
}
|
|
510
|
+
} catch {}
|
|
511
|
+
return null;
|
|
512
|
+
}
|
|
513
|
+
try {
|
|
514
|
+
if (typeof localStorage !== "undefined")
|
|
515
|
+
return localStorage;
|
|
516
|
+
} catch {}
|
|
517
|
+
try {
|
|
518
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
519
|
+
return window.localStorage;
|
|
520
|
+
}
|
|
521
|
+
} catch {}
|
|
522
|
+
try {
|
|
523
|
+
if (typeof globalThis !== "undefined" && globalThis.localStorage) {
|
|
524
|
+
return globalThis.localStorage;
|
|
525
|
+
}
|
|
526
|
+
} catch {}
|
|
527
|
+
return null;
|
|
528
|
+
}
|
|
487
529
|
function signal(initialValue, optionsOrEquals) {
|
|
488
530
|
const equals = typeof optionsOrEquals === "function" ? optionsOrEquals : optionsOrEquals?.equals;
|
|
489
531
|
const isInternal = typeof optionsOrEquals === "object" ? optionsOrEquals?.internal : false;
|
|
490
532
|
const customName = typeof optionsOrEquals === "object" ? optionsOrEquals?.name : undefined;
|
|
491
|
-
const
|
|
533
|
+
const persistOption = typeof optionsOrEquals === "object" ? optionsOrEquals?.persist : undefined;
|
|
534
|
+
const persistConfig = persistOption ? typeof persistOption === "string" ? { key: persistOption } : persistOption : undefined;
|
|
535
|
+
let effectiveInitial = initialValue;
|
|
536
|
+
const storage = persistConfig ? resolveStorage(persistConfig.storage) : null;
|
|
537
|
+
const serialize = persistConfig?.serialize ?? JSON.stringify;
|
|
538
|
+
const deserialize = persistConfig?.deserialize ?? JSON.parse;
|
|
539
|
+
if (persistConfig && storage) {
|
|
540
|
+
try {
|
|
541
|
+
const stored = storage.getItem(persistConfig.key);
|
|
542
|
+
if (stored !== null) {
|
|
543
|
+
effectiveInitial = deserialize(stored);
|
|
544
|
+
}
|
|
545
|
+
} catch {}
|
|
546
|
+
}
|
|
547
|
+
let isSyncing = false;
|
|
548
|
+
const onSet = persistConfig && storage ? (val) => {
|
|
549
|
+
if (isSyncing)
|
|
550
|
+
return;
|
|
551
|
+
try {
|
|
552
|
+
storage.setItem(persistConfig.key, serialize(val));
|
|
553
|
+
} catch {}
|
|
554
|
+
} : undefined;
|
|
555
|
+
const s = new Signal(effectiveInitial, equals, onSet);
|
|
556
|
+
if (persistConfig && storage && (persistConfig.syncTabs ?? true) && typeof window !== "undefined" && typeof window.addEventListener === "function") {
|
|
557
|
+
const onStorage = (e) => {
|
|
558
|
+
if (e.key === persistConfig.key) {
|
|
559
|
+
try {
|
|
560
|
+
const nextVal = e.newValue !== null ? deserialize(e.newValue) : initialValue;
|
|
561
|
+
isSyncing = true;
|
|
562
|
+
try {
|
|
563
|
+
s.set(nextVal);
|
|
564
|
+
} finally {
|
|
565
|
+
isSyncing = false;
|
|
566
|
+
}
|
|
567
|
+
} catch {}
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
window.addEventListener("storage", onStorage);
|
|
571
|
+
if (currentScope) {
|
|
572
|
+
currentScope.addCleanup(() => {
|
|
573
|
+
window.removeEventListener("storage", onStorage);
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
}
|
|
492
577
|
const accessor = (...args) => {
|
|
493
578
|
if (args.length === 0) {
|
|
494
579
|
return s.get();
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Child } from "../dom/render";
|
|
2
|
+
export interface StreamOptions {
|
|
3
|
+
onChunk?: (chunk: string) => void;
|
|
4
|
+
onError?: (error: any) => void;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Stream HTML chunks progressively using standard Web Streams (ReadableStream)
|
|
8
|
+
*/
|
|
9
|
+
export declare function renderToStream(fn: () => Child, options?: StreamOptions): ReadableStream<Uint8Array>;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Visage Lazy, Glitch-Free Computed State Engine
|
|
3
|
+
*/
|
|
4
|
+
import type { Scope } from "./scope";
|
|
5
|
+
import { COMPUTED_BRAND, type ComputedOptions, type IDependency, type ISubscriber, type ReadonlySignal, SubscriberState } from "./types";
|
|
6
|
+
export type { ComputedOptions };
|
|
7
|
+
/**
|
|
8
|
+
* Computed / Derived reactive state (Lazy, Glitch-Free, Memoized)
|
|
9
|
+
*/
|
|
10
|
+
export declare class Computed<T> implements ISubscriber, IDependency {
|
|
11
|
+
[COMPUTED_BRAND]: true;
|
|
12
|
+
private _fn;
|
|
13
|
+
private _value;
|
|
14
|
+
private _subscribers;
|
|
15
|
+
sources: Set<IDependency>;
|
|
16
|
+
sourceVersions: Map<IDependency, number>;
|
|
17
|
+
state: SubscriberState;
|
|
18
|
+
scope: Scope | null;
|
|
19
|
+
version: number;
|
|
20
|
+
constructor(fn: () => T);
|
|
21
|
+
get(): T;
|
|
22
|
+
get value(): T;
|
|
23
|
+
removeSubscriber(sub: ISubscriber): void;
|
|
24
|
+
markDirty(targetState?: SubscriberState): void;
|
|
25
|
+
updateIfNecessary(): boolean;
|
|
26
|
+
private recompute;
|
|
27
|
+
private cleanupSources;
|
|
28
|
+
dispose(): void;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Factory for creating lazy, memoized, glitch-free computed signals.
|
|
32
|
+
*
|
|
33
|
+
* Computed values are only recalculated when one of their recorded reactive
|
|
34
|
+
* dependencies changes and the value is actually accessed.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```tsx
|
|
38
|
+
* const count = signal(2);
|
|
39
|
+
* const double = computed(() => count() * 2);
|
|
40
|
+
*
|
|
41
|
+
* console.log(double()); // 4
|
|
42
|
+
*
|
|
43
|
+
* // In JSX, passes directly or as a function
|
|
44
|
+
* <div>Doubled value: {double}</div>
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* @param fn - The pure reactive computation function
|
|
48
|
+
* @param options - Optional debug metadata and internal flags
|
|
49
|
+
* @returns A readonly reactive signal function accessor
|
|
50
|
+
*/
|
|
51
|
+
export declare function computed<T>(fn: () => T, options?: ComputedOptions): ReadonlySignal<T>;
|
|
52
|
+
/**
|
|
53
|
+
* Solid-compatible alias for `computed()`.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```tsx
|
|
57
|
+
* const count = signal(5);
|
|
58
|
+
* const squared = createMemo(() => count() ** 2);
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export declare const createMemo: typeof computed;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type Child } from "../dom/render";
|
|
2
|
+
export interface Context<T> {
|
|
3
|
+
id: symbol;
|
|
4
|
+
defaultValue: T;
|
|
5
|
+
Provider: (props: {
|
|
6
|
+
value: T;
|
|
7
|
+
children: Child;
|
|
8
|
+
}) => any;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Create a reactive Context for dependency injection across the component tree.
|
|
12
|
+
*
|
|
13
|
+
* Context allows passing state and utilities down the component tree without
|
|
14
|
+
* manually drilling props through every intermediate component.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```tsx
|
|
18
|
+
* const ThemeContext = createContext<"light" | "dark">("light");
|
|
19
|
+
*
|
|
20
|
+
* // Provide value in parent
|
|
21
|
+
* function App() {
|
|
22
|
+
* return (
|
|
23
|
+
* <ThemeContext.Provider value="dark">
|
|
24
|
+
* <Header />
|
|
25
|
+
* </ThemeContext.Provider>
|
|
26
|
+
* );
|
|
27
|
+
* }
|
|
28
|
+
*
|
|
29
|
+
* // Consume value in descendant
|
|
30
|
+
* function Header() {
|
|
31
|
+
* const theme = useContext(ThemeContext);
|
|
32
|
+
* return <div>Current theme: {theme}</div>;
|
|
33
|
+
* }
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare function createContext<T>(defaultValue: T): Context<T>;
|
|
37
|
+
export declare function createContext<T>(): Context<T | undefined>;
|
|
38
|
+
/**
|
|
39
|
+
* Consume a Context value from the nearest ancestor Provider, falling back to defaultValue.
|
|
40
|
+
*
|
|
41
|
+
* @param context - The Context object returned from `createContext`
|
|
42
|
+
* @returns The current context value
|
|
43
|
+
*/
|
|
44
|
+
export declare function useContext<T>(context: Context<T>): T;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Scope } from "./scope";
|
|
2
|
+
import { type CleanupFn, type IDependency, type ISubscriber, SubscriberState } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* Side-effect runner with automatic dependency tracking and disposal
|
|
5
|
+
*/
|
|
6
|
+
export declare class Effect implements ISubscriber {
|
|
7
|
+
private _fn;
|
|
8
|
+
sources: Set<IDependency>;
|
|
9
|
+
sourceVersions: Map<IDependency, number>;
|
|
10
|
+
cleanups: CleanupFn[];
|
|
11
|
+
state: SubscriberState;
|
|
12
|
+
scope: Scope | null;
|
|
13
|
+
constructor(fn: () => void | CleanupFn);
|
|
14
|
+
addCleanup(fn: CleanupFn): void;
|
|
15
|
+
private runCleanups;
|
|
16
|
+
markDirty(targetState?: SubscriberState): void;
|
|
17
|
+
run(): void;
|
|
18
|
+
private cleanupSources;
|
|
19
|
+
dispose(): void;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Execute side-effects reactively when dependencies change.
|
|
23
|
+
*
|
|
24
|
+
* Runs immediately upon creation and tracks any signals read within `fn`.
|
|
25
|
+
* When dependencies change, re-execution is scheduled automatically.
|
|
26
|
+
*
|
|
27
|
+
* An optional cleanup function can be returned from `fn`, which runs
|
|
28
|
+
* before the next re-execution and when the enclosing scope is disposed.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```tsx
|
|
32
|
+
* const count = signal(0);
|
|
33
|
+
*
|
|
34
|
+
* effect(() => {
|
|
35
|
+
* console.log("Count changed to:", count());
|
|
36
|
+
*
|
|
37
|
+
* const timer = setInterval(() => console.log("tick"), 1000);
|
|
38
|
+
* return () => clearInterval(timer);
|
|
39
|
+
* });
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* @param fn - The side-effect function, optionally returning a cleanup function
|
|
43
|
+
* @returns A manual disposal cleanup function
|
|
44
|
+
*/
|
|
45
|
+
export declare function effect(fn: () => void | CleanupFn): CleanupFn;
|
|
46
|
+
/**
|
|
47
|
+
* Solid / React-compatible alias for `effect()`.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```tsx
|
|
51
|
+
* createEffect(() => {
|
|
52
|
+
* document.title = `Total: ${count()}`;
|
|
53
|
+
* });
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export declare const createEffect: typeof effect;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { Computed, type ComputedOptions, computed, createMemo } from "./computed";
|
|
2
|
+
export { type Context, createContext, useContext } from "./context";
|
|
3
|
+
export { createEffect, Effect, effect } from "./effect";
|
|
4
|
+
export { createRoot, getActiveScope, onCleanup, runInScope, Scope } from "./scope";
|
|
5
|
+
export { createSignal, Signal, type SignalOptions, signal } from "./signal";
|
|
6
|
+
export { createStore, mutateStore, type Store, unwrapStore } from "./store";
|
|
7
|
+
export { batch, untrack } from "./system";
|
|
8
|
+
export { type CleanupFn, COMPUTED_BRAND, type Dependency, isSignal, type PersistOptions, type ReadonlySignal, SIGNAL_BRAND, type Subscriber, SubscriberState, type WritableSignal } from "./types";
|
|
@@ -848,10 +848,12 @@ class Signal {
|
|
|
848
848
|
_value;
|
|
849
849
|
_subscribers = new Set;
|
|
850
850
|
_equals;
|
|
851
|
+
_onSet;
|
|
851
852
|
version = 0;
|
|
852
|
-
constructor(initialValue, equals) {
|
|
853
|
+
constructor(initialValue, equals, onSet) {
|
|
853
854
|
this._value = initialValue;
|
|
854
855
|
this._equals = equals ?? Object.is;
|
|
856
|
+
this._onSet = onSet;
|
|
855
857
|
}
|
|
856
858
|
get() {
|
|
857
859
|
if (currentSubscriber !== null && currentSubscriber.state !== 3 /* DISPOSED */) {
|
|
@@ -876,6 +878,9 @@ class Signal {
|
|
|
876
878
|
}
|
|
877
879
|
this._value = newValue;
|
|
878
880
|
this.version++;
|
|
881
|
+
if (this._onSet) {
|
|
882
|
+
this._onSet(newValue);
|
|
883
|
+
}
|
|
879
884
|
batch(() => {
|
|
880
885
|
this.notify();
|
|
881
886
|
});
|
|
@@ -901,11 +906,91 @@ class Signal {
|
|
|
901
906
|
}
|
|
902
907
|
}
|
|
903
908
|
}
|
|
909
|
+
function resolveStorage(storageOption) {
|
|
910
|
+
if (storageOption && typeof storageOption === "object") {
|
|
911
|
+
return storageOption;
|
|
912
|
+
}
|
|
913
|
+
if (storageOption === "session") {
|
|
914
|
+
try {
|
|
915
|
+
if (typeof sessionStorage !== "undefined")
|
|
916
|
+
return sessionStorage;
|
|
917
|
+
} catch {}
|
|
918
|
+
try {
|
|
919
|
+
if (typeof window !== "undefined" && window.sessionStorage) {
|
|
920
|
+
return window.sessionStorage;
|
|
921
|
+
}
|
|
922
|
+
} catch {}
|
|
923
|
+
try {
|
|
924
|
+
if (typeof globalThis !== "undefined" && globalThis.sessionStorage) {
|
|
925
|
+
return globalThis.sessionStorage;
|
|
926
|
+
}
|
|
927
|
+
} catch {}
|
|
928
|
+
return null;
|
|
929
|
+
}
|
|
930
|
+
try {
|
|
931
|
+
if (typeof localStorage !== "undefined")
|
|
932
|
+
return localStorage;
|
|
933
|
+
} catch {}
|
|
934
|
+
try {
|
|
935
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
936
|
+
return window.localStorage;
|
|
937
|
+
}
|
|
938
|
+
} catch {}
|
|
939
|
+
try {
|
|
940
|
+
if (typeof globalThis !== "undefined" && globalThis.localStorage) {
|
|
941
|
+
return globalThis.localStorage;
|
|
942
|
+
}
|
|
943
|
+
} catch {}
|
|
944
|
+
return null;
|
|
945
|
+
}
|
|
904
946
|
function signal(initialValue, optionsOrEquals) {
|
|
905
947
|
const equals = typeof optionsOrEquals === "function" ? optionsOrEquals : optionsOrEquals?.equals;
|
|
906
948
|
const isInternal = typeof optionsOrEquals === "object" ? optionsOrEquals?.internal : false;
|
|
907
949
|
const customName = typeof optionsOrEquals === "object" ? optionsOrEquals?.name : undefined;
|
|
908
|
-
const
|
|
950
|
+
const persistOption = typeof optionsOrEquals === "object" ? optionsOrEquals?.persist : undefined;
|
|
951
|
+
const persistConfig = persistOption ? typeof persistOption === "string" ? { key: persistOption } : persistOption : undefined;
|
|
952
|
+
let effectiveInitial = initialValue;
|
|
953
|
+
const storage = persistConfig ? resolveStorage(persistConfig.storage) : null;
|
|
954
|
+
const serialize = persistConfig?.serialize ?? JSON.stringify;
|
|
955
|
+
const deserialize = persistConfig?.deserialize ?? JSON.parse;
|
|
956
|
+
if (persistConfig && storage) {
|
|
957
|
+
try {
|
|
958
|
+
const stored = storage.getItem(persistConfig.key);
|
|
959
|
+
if (stored !== null) {
|
|
960
|
+
effectiveInitial = deserialize(stored);
|
|
961
|
+
}
|
|
962
|
+
} catch {}
|
|
963
|
+
}
|
|
964
|
+
let isSyncing = false;
|
|
965
|
+
const onSet = persistConfig && storage ? (val) => {
|
|
966
|
+
if (isSyncing)
|
|
967
|
+
return;
|
|
968
|
+
try {
|
|
969
|
+
storage.setItem(persistConfig.key, serialize(val));
|
|
970
|
+
} catch {}
|
|
971
|
+
} : undefined;
|
|
972
|
+
const s = new Signal(effectiveInitial, equals, onSet);
|
|
973
|
+
if (persistConfig && storage && (persistConfig.syncTabs ?? true) && typeof window !== "undefined" && typeof window.addEventListener === "function") {
|
|
974
|
+
const onStorage = (e) => {
|
|
975
|
+
if (e.key === persistConfig.key) {
|
|
976
|
+
try {
|
|
977
|
+
const nextVal = e.newValue !== null ? deserialize(e.newValue) : initialValue;
|
|
978
|
+
isSyncing = true;
|
|
979
|
+
try {
|
|
980
|
+
s.set(nextVal);
|
|
981
|
+
} finally {
|
|
982
|
+
isSyncing = false;
|
|
983
|
+
}
|
|
984
|
+
} catch {}
|
|
985
|
+
}
|
|
986
|
+
};
|
|
987
|
+
window.addEventListener("storage", onStorage);
|
|
988
|
+
if (currentScope) {
|
|
989
|
+
currentScope.addCleanup(() => {
|
|
990
|
+
window.removeEventListener("storage", onStorage);
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
}
|
|
909
994
|
const accessor = (...args) => {
|
|
910
995
|
if (args.length === 0) {
|
|
911
996
|
return s.get();
|