@epoch32/visage 0.0.0-stage → 1.0.0
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/LICENSE +373 -0
- package/README.md +110 -2
- package/dist/src/api/index.js +4002 -0
- package/dist/src/charts/index.js +2717 -0
- package/dist/src/devtools/index.js +4677 -0
- package/dist/src/dom/index.js +1550 -0
- package/dist/src/form/index.js +1415 -0
- package/dist/src/index.js +11826 -0
- package/dist/src/jsx-runtime/index.js +1630 -0
- package/dist/src/query/index.js +2422 -0
- package/dist/src/router/index.js +1856 -0
- package/dist/src/rpc/index.js +3484 -0
- package/dist/src/server/index.js +1173 -0
- package/dist/src/signals/index.js +1077 -0
- package/dist/src/style/index.js +2340 -0
- package/dist/src/template/index.js +1149 -0
- package/dist/src/ui/index.js +4155 -0
- package/dist/src/virtual/index.js +1955 -0
- package/dist/src/vite/index.js +984 -0
- package/package.json +140 -4
- package/src/api/client.ts +371 -0
- package/src/api/file-router.ts +183 -0
- package/src/api/handler.ts +326 -0
- package/src/api/index.ts +71 -0
- package/src/api/middleware.ts +54 -0
- package/src/api/pragma.ts +155 -0
- package/src/api/procedure.ts +172 -0
- package/src/api/types.ts +249 -0
- package/src/charts/Area.tsx +111 -0
- package/src/charts/Axis.tsx +126 -0
- package/src/charts/Bar.tsx +86 -0
- package/src/charts/CartesianGrid.tsx +72 -0
- package/src/charts/Chart.tsx +269 -0
- package/src/charts/Cursor.tsx +42 -0
- package/src/charts/Legend.tsx +56 -0
- package/src/charts/Line.tsx +106 -0
- package/src/charts/Pie.tsx +88 -0
- package/src/charts/Tooltip.tsx +127 -0
- package/src/charts/context.ts +30 -0
- package/src/charts/index.ts +14 -0
- package/src/charts/path.ts +155 -0
- package/src/charts/scale.ts +133 -0
- package/src/charts/types.ts +50 -0
- package/src/devtools/DomTab.tsx +134 -0
- package/src/devtools/GraphInspector.tsx +196 -0
- package/src/devtools/GraphTab.tsx +315 -0
- package/src/devtools/QueryTab.tsx +200 -0
- package/src/devtools/RpcTab.tsx +190 -0
- package/src/devtools/SignalsTab.tsx +129 -0
- package/src/devtools/component.tsx +243 -0
- package/src/devtools/highlighter.ts +134 -0
- package/src/devtools/hub.ts +175 -0
- package/src/devtools/index.ts +20 -0
- package/src/devtools/styles.ts +313 -0
- package/src/devtools/types.ts +45 -0
- package/src/dom/async.ts +232 -0
- package/src/dom/control-flow.ts +353 -0
- package/src/dom/index.ts +32 -0
- package/src/dom/lazy.ts +82 -0
- package/src/dom/render.ts +286 -0
- package/src/dom/resource.ts +120 -0
- package/src/form/form.ts +218 -0
- package/src/form/index.ts +17 -0
- package/src/form/schema.ts +299 -0
- package/src/index.ts +413 -0
- package/src/jsx-dev-runtime/index.ts +1 -0
- package/src/jsx-runtime/index.ts +112 -0
- package/src/jsx-runtime/jsx.d.ts +278 -0
- package/src/query/create-mutation.ts +64 -0
- package/src/query/create-query.ts +426 -0
- package/src/query/focus-manager.ts +68 -0
- package/src/query/index.ts +63 -0
- package/src/query/mutation-cache.ts +138 -0
- package/src/query/online-manager.ts +67 -0
- package/src/query/query-cache.ts +369 -0
- package/src/query/query-client.ts +248 -0
- package/src/query/types.ts +221 -0
- package/src/query/utils.ts +132 -0
- package/src/router/index.ts +19 -0
- package/src/router/router.tsx +352 -0
- package/src/rpc/client.ts +317 -0
- package/src/rpc/error.ts +70 -0
- package/src/rpc/index.ts +52 -0
- package/src/rpc/procedure.ts +88 -0
- package/src/rpc/router.ts +105 -0
- package/src/rpc/server.ts +511 -0
- package/src/rpc/types.ts +328 -0
- package/src/server/hydrate.ts +21 -0
- package/src/server/index.ts +10 -0
- package/src/server/render-to-stream.ts +31 -0
- package/src/server/render-to-string.ts +125 -0
- package/src/signals/computed.ts +217 -0
- package/src/signals/context.ts +89 -0
- package/src/signals/effect.ts +161 -0
- package/src/signals/index.ts +57 -0
- package/src/signals/scope.ts +132 -0
- package/src/signals/signal.ts +203 -0
- package/src/signals/store.ts +163 -0
- package/src/signals/system.ts +124 -0
- package/src/signals/types.ts +64 -0
- package/src/style/component.tsx +122 -0
- package/src/style/create-style.ts +229 -0
- package/src/style/cx.ts +75 -0
- package/src/style/hash.ts +19 -0
- package/src/style/index.ts +8 -0
- package/src/style/layout.tsx +406 -0
- package/src/style/manager.ts +87 -0
- package/src/style/parser.ts +257 -0
- package/src/style/scale.ts +237 -0
- package/src/template/index.ts +4 -0
- package/src/template/template.ts +126 -0
- package/src/ui/accordion.tsx +286 -0
- package/src/ui/command-dialog.tsx +49 -0
- package/src/ui/command.tsx +400 -0
- package/src/ui/data-table.tsx +322 -0
- package/src/ui/dialog.tsx +362 -0
- package/src/ui/dropdown-menu.tsx +381 -0
- package/src/ui/icon.tsx +69 -0
- package/src/ui/index.ts +138 -0
- package/src/ui/layout.tsx +13 -0
- package/src/ui/popover.tsx +249 -0
- package/src/ui/switch.tsx +114 -0
- package/src/ui/tabs.tsx +297 -0
- package/src/ui/toast.tsx +280 -0
- package/src/ui/tooltip.tsx +262 -0
- package/src/ui/utils.ts +110 -0
- package/src/virtual/index.ts +12 -0
- package/src/virtual/virtual-list.tsx +185 -0
- package/src/virtual/virtualizer.ts +274 -0
- package/src/vite/hmr.ts +38 -0
- package/src/vite/index.ts +3 -0
- package/src/vite/lucide.ts +124 -0
- package/src/vite/plugin.ts +102 -0
- package/src/vite/rpc-middleware.ts +82 -0
- package/src/vite/types.ts +65 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import type { InferSchemaType, SchemaLike, StandardSchemaV1 } from "../form/schema";
|
|
2
|
+
import type {
|
|
3
|
+
ApiProcedure,
|
|
4
|
+
MiddlewareDefinition,
|
|
5
|
+
MiddlewareFn,
|
|
6
|
+
MiddlewarePragma,
|
|
7
|
+
ProcedureOptions
|
|
8
|
+
} from "./types";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Define a type-safe Query procedure
|
|
12
|
+
*/
|
|
13
|
+
export function query<
|
|
14
|
+
TSchema extends SchemaLike<any> | StandardSchemaV1<any>,
|
|
15
|
+
TOutput = any,
|
|
16
|
+
TCtx = any
|
|
17
|
+
>(options: {
|
|
18
|
+
input: TSchema;
|
|
19
|
+
output?: SchemaLike<TOutput> | StandardSchemaV1<TOutput>;
|
|
20
|
+
resolve: (args: {
|
|
21
|
+
input: InferSchemaType<TSchema>;
|
|
22
|
+
ctx: TCtx;
|
|
23
|
+
req: Request;
|
|
24
|
+
params: Record<string, string>;
|
|
25
|
+
}) => Promise<TOutput> | TOutput | AsyncGenerator<any, void, unknown>;
|
|
26
|
+
}): ApiProcedure<InferSchemaType<TSchema>, TOutput, TCtx>;
|
|
27
|
+
export function query<TInput = void, TOutput = any, TCtx = any>(
|
|
28
|
+
options: ProcedureOptions<TInput, TOutput, TCtx>
|
|
29
|
+
): ApiProcedure<TInput, TOutput, TCtx>;
|
|
30
|
+
export function query(options: any): ApiProcedure<any, any, any> {
|
|
31
|
+
return {
|
|
32
|
+
type: "query",
|
|
33
|
+
options
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Define a type-safe Mutation procedure
|
|
39
|
+
*/
|
|
40
|
+
export function mutation<
|
|
41
|
+
TSchema extends SchemaLike<any> | StandardSchemaV1<any>,
|
|
42
|
+
TOutput = any,
|
|
43
|
+
TCtx = any
|
|
44
|
+
>(options: {
|
|
45
|
+
input: TSchema;
|
|
46
|
+
output?: SchemaLike<TOutput> | StandardSchemaV1<TOutput>;
|
|
47
|
+
resolve: (args: {
|
|
48
|
+
input: InferSchemaType<TSchema>;
|
|
49
|
+
ctx: TCtx;
|
|
50
|
+
req: Request;
|
|
51
|
+
params: Record<string, string>;
|
|
52
|
+
}) => Promise<TOutput> | TOutput | AsyncGenerator<any, void, unknown>;
|
|
53
|
+
}): ApiProcedure<InferSchemaType<TSchema>, TOutput, TCtx>;
|
|
54
|
+
export function mutation<TInput = void, TOutput = any, TCtx = any>(
|
|
55
|
+
options: ProcedureOptions<TInput, TOutput, TCtx>
|
|
56
|
+
): ApiProcedure<TInput, TOutput, TCtx>;
|
|
57
|
+
export function mutation(options: any): ApiProcedure<any, any, any> {
|
|
58
|
+
return {
|
|
59
|
+
type: "mutation",
|
|
60
|
+
options
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Define a real-time SSE / Stream Subscription procedure
|
|
66
|
+
*/
|
|
67
|
+
export function subscription<TOutput = any, TCtx = any>(
|
|
68
|
+
options: Omit<ProcedureOptions<void, TOutput, TCtx>, "input">
|
|
69
|
+
): ApiProcedure<void, TOutput, TCtx> {
|
|
70
|
+
return {
|
|
71
|
+
type: "subscription",
|
|
72
|
+
options: {
|
|
73
|
+
...options,
|
|
74
|
+
resolve: options.resolve as any
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Helper to define a middleware function with optional pragma metadata
|
|
81
|
+
*/
|
|
82
|
+
export function defineMiddleware<TCtxIn = any, TCtxOut = any>(
|
|
83
|
+
fn: MiddlewareFn<TCtxIn, TCtxOut>,
|
|
84
|
+
pragma: MiddlewarePragma = { cascade: true, match: ["*"] }
|
|
85
|
+
): MiddlewareDefinition {
|
|
86
|
+
return {
|
|
87
|
+
fn,
|
|
88
|
+
pragma
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Composable Procedure Builder (Fluent Style)
|
|
94
|
+
*/
|
|
95
|
+
export class ProcedureBuilder<TCtx = any, TInput = any> {
|
|
96
|
+
private _middlewares: MiddlewareFn[] = [];
|
|
97
|
+
private _inputSchema?: SchemaLike<TInput> | StandardSchemaV1<TInput>;
|
|
98
|
+
|
|
99
|
+
constructor(middlewares: MiddlewareFn[] = [], inputSchema?: SchemaLike<TInput>) {
|
|
100
|
+
this._middlewares = middlewares;
|
|
101
|
+
this._inputSchema = inputSchema;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
use<TNextCtx = Record<string, unknown>>(
|
|
105
|
+
middleware: MiddlewareFn<TCtx, TNextCtx>
|
|
106
|
+
): ProcedureBuilder<TCtx & TNextCtx, TInput> {
|
|
107
|
+
return new ProcedureBuilder<TCtx & TNextCtx, TInput>(
|
|
108
|
+
[...this._middlewares, middleware],
|
|
109
|
+
this._inputSchema as any
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
input<TNewInput>(
|
|
114
|
+
schema: SchemaLike<TNewInput> | StandardSchemaV1<TNewInput>
|
|
115
|
+
): ProcedureBuilder<TCtx, TNewInput> {
|
|
116
|
+
return new ProcedureBuilder<TCtx, TNewInput>(this._middlewares, schema as any);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
query<TOutput>(
|
|
120
|
+
resolve: (args: {
|
|
121
|
+
input: TInput;
|
|
122
|
+
ctx: TCtx;
|
|
123
|
+
req: Request;
|
|
124
|
+
params: Record<string, string>;
|
|
125
|
+
}) => Promise<TOutput> | TOutput
|
|
126
|
+
): ApiProcedure<TInput, TOutput, TCtx> {
|
|
127
|
+
return {
|
|
128
|
+
type: "query",
|
|
129
|
+
options: {
|
|
130
|
+
input: this._inputSchema,
|
|
131
|
+
resolve
|
|
132
|
+
},
|
|
133
|
+
middlewares: this._middlewares
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
mutation<TOutput>(
|
|
138
|
+
resolve: (args: {
|
|
139
|
+
input: TInput;
|
|
140
|
+
ctx: TCtx;
|
|
141
|
+
req: Request;
|
|
142
|
+
params: Record<string, string>;
|
|
143
|
+
}) => Promise<TOutput> | TOutput
|
|
144
|
+
): ApiProcedure<TInput, TOutput, TCtx> {
|
|
145
|
+
return {
|
|
146
|
+
type: "mutation",
|
|
147
|
+
options: {
|
|
148
|
+
input: this._inputSchema,
|
|
149
|
+
resolve
|
|
150
|
+
},
|
|
151
|
+
middlewares: this._middlewares
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
subscription<TOutput>(
|
|
156
|
+
resolve: (args: {
|
|
157
|
+
ctx: TCtx;
|
|
158
|
+
req: Request;
|
|
159
|
+
params: Record<string, string>;
|
|
160
|
+
}) => AsyncGenerator<TOutput, void, unknown>
|
|
161
|
+
): ApiProcedure<void, TOutput, TCtx> {
|
|
162
|
+
return {
|
|
163
|
+
type: "subscription",
|
|
164
|
+
options: {
|
|
165
|
+
resolve: resolve as any
|
|
166
|
+
},
|
|
167
|
+
middlewares: this._middlewares
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export const procedure = new ProcedureBuilder<Record<string, unknown>>();
|
package/src/api/types.ts
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Visage API & File-Based RPC Routing System Types
|
|
3
|
+
*/
|
|
4
|
+
import type { SchemaLike, StandardSchemaV1 } from "../form/schema";
|
|
5
|
+
import type { RPCErrorCode } from "../rpc/types";
|
|
6
|
+
|
|
7
|
+
export type { RPCErrorCode };
|
|
8
|
+
|
|
9
|
+
export type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS" | "HEAD";
|
|
10
|
+
|
|
11
|
+
export interface MiddlewarePragma {
|
|
12
|
+
/**
|
|
13
|
+
* Whether this middleware cascades to child subdirectories.
|
|
14
|
+
* Default: true
|
|
15
|
+
*/
|
|
16
|
+
cascade?: boolean;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Route name / path globs to include.
|
|
20
|
+
* Default: ["*"]
|
|
21
|
+
*/
|
|
22
|
+
match?: string[];
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Route name / path globs to exclude.
|
|
26
|
+
* Default: []
|
|
27
|
+
*/
|
|
28
|
+
exclude?: string[];
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Execution priority within the same directory (higher runs earlier).
|
|
32
|
+
* Default: 0
|
|
33
|
+
*/
|
|
34
|
+
priority?: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export type NextFn<TCtxIn = any, TCtxOut = any> = (
|
|
38
|
+
enriched?: Partial<TCtxOut>
|
|
39
|
+
) => Promise<Response | (TCtxIn & TCtxOut)>;
|
|
40
|
+
|
|
41
|
+
export interface MiddlewareContext<TCtx = any> {
|
|
42
|
+
req: Request;
|
|
43
|
+
ctx: TCtx;
|
|
44
|
+
url: URL;
|
|
45
|
+
params: Record<string, string>;
|
|
46
|
+
next: NextFn<TCtx, any>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export type MiddlewareFn<TCtxIn = any, _TCtxOut = any> = (
|
|
50
|
+
args: MiddlewareContext<TCtxIn>
|
|
51
|
+
) => Promise<Response | void | any>;
|
|
52
|
+
|
|
53
|
+
export interface MiddlewareDefinition {
|
|
54
|
+
fn: MiddlewareFn;
|
|
55
|
+
pragma: MiddlewarePragma;
|
|
56
|
+
filePath?: string;
|
|
57
|
+
directory?: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export type ProcedureType = "query" | "mutation" | "subscription";
|
|
61
|
+
|
|
62
|
+
export interface ProcedureOptions<TInput = any, TOutput = any, TCtx = any> {
|
|
63
|
+
input?: SchemaLike<TInput> | StandardSchemaV1<TInput>;
|
|
64
|
+
output?: SchemaLike<TOutput> | StandardSchemaV1<TOutput>;
|
|
65
|
+
resolve: (args: {
|
|
66
|
+
input: TInput;
|
|
67
|
+
ctx: TCtx;
|
|
68
|
+
req: Request;
|
|
69
|
+
params: Record<string, string>;
|
|
70
|
+
}) => Promise<TOutput> | TOutput | AsyncGenerator<any, void, unknown>;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface ApiProcedure<TInput = any, TOutput = any, TCtx = any> {
|
|
74
|
+
type: ProcedureType;
|
|
75
|
+
options: ProcedureOptions<TInput, TOutput, TCtx>;
|
|
76
|
+
middlewares?: MiddlewareFn[];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface RouteMatch {
|
|
80
|
+
pattern: RegExp;
|
|
81
|
+
paramNames: string[];
|
|
82
|
+
routePath: string;
|
|
83
|
+
filePath: string;
|
|
84
|
+
directory: string;
|
|
85
|
+
procedures: Record<string, ApiProcedure>;
|
|
86
|
+
middlewares: MiddlewareDefinition[];
|
|
87
|
+
handler?: (req: Request, ctx: any) => Promise<Response> | Response;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface FileRouteModule {
|
|
91
|
+
default?: ApiProcedure | ((req: Request, ctx?: any) => Promise<Response> | Response);
|
|
92
|
+
middleware?: MiddlewareFn;
|
|
93
|
+
get?: ApiProcedure;
|
|
94
|
+
post?: ApiProcedure;
|
|
95
|
+
put?: ApiProcedure;
|
|
96
|
+
del?: ApiProcedure;
|
|
97
|
+
patch?: ApiProcedure;
|
|
98
|
+
[key: string]: any;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface ApiRouterConfig {
|
|
102
|
+
prefix?: string;
|
|
103
|
+
cors?: {
|
|
104
|
+
origin?: string | string[] | ((origin: string) => boolean);
|
|
105
|
+
methods?: string[];
|
|
106
|
+
allowedHeaders?: string[];
|
|
107
|
+
credentials?: boolean;
|
|
108
|
+
maxAge?: number;
|
|
109
|
+
};
|
|
110
|
+
onError?: (err: Error, req: Request) => Response | Promise<Response>;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export type ApiClientHeadersRule =
|
|
114
|
+
| Record<string, string>
|
|
115
|
+
| (() => Promise<Record<string, string>> | Record<string, string>);
|
|
116
|
+
|
|
117
|
+
export interface ApiClientOptions {
|
|
118
|
+
baseUrl: string;
|
|
119
|
+
fetch?: typeof fetch;
|
|
120
|
+
headers?:
|
|
121
|
+
| Record<string, string>
|
|
122
|
+
| Record<string, ApiClientHeadersRule>
|
|
123
|
+
| (() => Promise<Record<string, string>> | Record<string, string>);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export interface ApiCallOptions {
|
|
127
|
+
signal?: AbortSignal;
|
|
128
|
+
headers?: Record<string, string>;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export interface ApiSubscriptionCallbacks<TData = any> {
|
|
132
|
+
onData: (data: TData) => void;
|
|
133
|
+
onError?: (error: any) => void;
|
|
134
|
+
onComplete?: () => void;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export interface ApiSubscriptionHandle {
|
|
138
|
+
unsubscribe: () => void;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export type InferApiInput<P> =
|
|
142
|
+
P extends ApiProcedure<infer TInput, any, any>
|
|
143
|
+
? TInput
|
|
144
|
+
: P extends (...args: any[]) => any
|
|
145
|
+
? any
|
|
146
|
+
: void;
|
|
147
|
+
|
|
148
|
+
export type InferApiOutput<P> =
|
|
149
|
+
P extends ApiProcedure<any, infer TOutput, any>
|
|
150
|
+
? TOutput
|
|
151
|
+
: P extends (...args: any[]) => Promise<infer TOutput>
|
|
152
|
+
? TOutput
|
|
153
|
+
: unknown;
|
|
154
|
+
|
|
155
|
+
export type ApiMethodCaller<P> =
|
|
156
|
+
InferApiInput<P> extends void | undefined
|
|
157
|
+
? (input?: void, options?: ApiCallOptions) => Promise<InferApiOutput<P>>
|
|
158
|
+
: (input: InferApiInput<P>, options?: ApiCallOptions) => Promise<InferApiOutput<P>>;
|
|
159
|
+
|
|
160
|
+
export type ApiSubscriptionCaller<P> =
|
|
161
|
+
InferApiInput<P> extends void | undefined
|
|
162
|
+
? (
|
|
163
|
+
input: void | undefined,
|
|
164
|
+
callbacks: ApiSubscriptionCallbacks<InferApiOutput<P>>
|
|
165
|
+
) => ApiSubscriptionHandle
|
|
166
|
+
: (
|
|
167
|
+
input: InferApiInput<P>,
|
|
168
|
+
callbacks: ApiSubscriptionCallbacks<InferApiOutput<P>>
|
|
169
|
+
) => ApiSubscriptionHandle;
|
|
170
|
+
|
|
171
|
+
export type ApiEndpointMethods<T> = {
|
|
172
|
+
get: T extends { GET: infer P }
|
|
173
|
+
? ApiMethodCaller<P>
|
|
174
|
+
: T extends { get: infer P }
|
|
175
|
+
? ApiMethodCaller<P>
|
|
176
|
+
: T extends { default: infer P }
|
|
177
|
+
? ApiMethodCaller<P>
|
|
178
|
+
: (input?: any, options?: ApiCallOptions) => Promise<any>;
|
|
179
|
+
post: T extends { POST: infer P }
|
|
180
|
+
? ApiMethodCaller<P>
|
|
181
|
+
: T extends { post: infer P }
|
|
182
|
+
? ApiMethodCaller<P>
|
|
183
|
+
: (input?: any, options?: ApiCallOptions) => Promise<any>;
|
|
184
|
+
put: T extends { PUT: infer P }
|
|
185
|
+
? ApiMethodCaller<P>
|
|
186
|
+
: T extends { put: infer P }
|
|
187
|
+
? ApiMethodCaller<P>
|
|
188
|
+
: (input?: any, options?: ApiCallOptions) => Promise<any>;
|
|
189
|
+
patch: T extends { PATCH: infer P }
|
|
190
|
+
? ApiMethodCaller<P>
|
|
191
|
+
: T extends { patch: infer P }
|
|
192
|
+
? ApiMethodCaller<P>
|
|
193
|
+
: (input?: any, options?: ApiCallOptions) => Promise<any>;
|
|
194
|
+
del: T extends { DELETE: infer P }
|
|
195
|
+
? ApiMethodCaller<P>
|
|
196
|
+
: T extends { del: infer P }
|
|
197
|
+
? ApiMethodCaller<P>
|
|
198
|
+
: (input?: any, options?: ApiCallOptions) => Promise<any>;
|
|
199
|
+
delete: T extends { DELETE: infer P }
|
|
200
|
+
? ApiMethodCaller<P>
|
|
201
|
+
: T extends { del: infer P }
|
|
202
|
+
? ApiMethodCaller<P>
|
|
203
|
+
: (input?: any, options?: ApiCallOptions) => Promise<any>;
|
|
204
|
+
subscribe: T extends { GET: infer P }
|
|
205
|
+
? ApiSubscriptionCaller<P>
|
|
206
|
+
: T extends { subscription: infer P }
|
|
207
|
+
? ApiSubscriptionCaller<P>
|
|
208
|
+
: (input: any, callbacks: ApiSubscriptionCallbacks) => ApiSubscriptionHandle;
|
|
209
|
+
|
|
210
|
+
queryKey: (input?: any) => unknown[];
|
|
211
|
+
queryOptions: (input?: any, extra?: any) => any;
|
|
212
|
+
createQuery: (input?: any, extra?: any) => any;
|
|
213
|
+
useQuery: (input?: any, extra?: any) => any;
|
|
214
|
+
|
|
215
|
+
mutationKey: () => unknown[];
|
|
216
|
+
mutationOptions: (extra?: any) => any;
|
|
217
|
+
createMutation: (extra?: any) => any;
|
|
218
|
+
useMutation: (extra?: any) => any;
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
export type DynamicApiClient = {
|
|
222
|
+
get: (input?: any, options?: ApiCallOptions) => Promise<any>;
|
|
223
|
+
post: (input?: any, options?: ApiCallOptions) => Promise<any>;
|
|
224
|
+
put: (input?: any, options?: ApiCallOptions) => Promise<any>;
|
|
225
|
+
patch: (input?: any, options?: ApiCallOptions) => Promise<any>;
|
|
226
|
+
del: (input?: any, options?: ApiCallOptions) => Promise<any>;
|
|
227
|
+
delete: (input?: any, options?: ApiCallOptions) => Promise<any>;
|
|
228
|
+
subscribe: (input: any, callbacks: ApiSubscriptionCallbacks) => ApiSubscriptionHandle;
|
|
229
|
+
queryKey: (input?: any) => unknown[];
|
|
230
|
+
queryOptions: (input?: any, extra?: any) => any;
|
|
231
|
+
createQuery: (input?: any, extra?: any) => any;
|
|
232
|
+
useQuery: (input?: any, extra?: any) => any;
|
|
233
|
+
mutationKey: () => unknown[];
|
|
234
|
+
mutationOptions: (extra?: any) => any;
|
|
235
|
+
createMutation: (extra?: any) => any;
|
|
236
|
+
useMutation: (extra?: any) => any;
|
|
237
|
+
(param: string | number): DynamicApiClient;
|
|
238
|
+
} & Record<string, any>;
|
|
239
|
+
|
|
240
|
+
export type ApiClient<TRoutes = any> = 0 extends 1 & TRoutes
|
|
241
|
+
? DynamicApiClient
|
|
242
|
+
: [TRoutes] extends [Record<string, any>]
|
|
243
|
+
? {
|
|
244
|
+
[K in keyof TRoutes]-?: ((param: string | number) => ApiClient<TRoutes[K]>) &
|
|
245
|
+
ApiEndpointMethods<TRoutes[K]> &
|
|
246
|
+
ApiClient<TRoutes[K]>;
|
|
247
|
+
} & ((param: string | number) => any) &
|
|
248
|
+
ApiEndpointMethods<any>
|
|
249
|
+
: DynamicApiClient;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { Child } from "../dom";
|
|
2
|
+
import { onCleanup } from "../signals";
|
|
3
|
+
import { useChartContext } from "./context";
|
|
4
|
+
import { pathArea, pathLine } from "./path";
|
|
5
|
+
import type { CurveType, Point } from "./types";
|
|
6
|
+
|
|
7
|
+
export interface AreaProps {
|
|
8
|
+
dataKey: string;
|
|
9
|
+
stroke?: string;
|
|
10
|
+
strokeWidth?: number | string;
|
|
11
|
+
fill?: string;
|
|
12
|
+
fillOpacity?: number | string;
|
|
13
|
+
curve?: CurveType;
|
|
14
|
+
dot?: boolean | { r?: number; fill?: string; stroke?: string };
|
|
15
|
+
name?: string;
|
|
16
|
+
opacity?: number | string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function Area(props: AreaProps): Child {
|
|
20
|
+
return () => {
|
|
21
|
+
const ctx = useChartContext();
|
|
22
|
+
|
|
23
|
+
const stroke = props.stroke ?? "#a855f7";
|
|
24
|
+
const strokeWidth = props.strokeWidth ?? 2;
|
|
25
|
+
const fill = props.fill ?? "rgba(168, 85, 247, 0.15)";
|
|
26
|
+
const fillOpacity = props.fillOpacity ?? 1;
|
|
27
|
+
const curve = props.curve ?? "smooth";
|
|
28
|
+
|
|
29
|
+
const id = `area-${props.dataKey}-${Math.random().toString(36).slice(2, 7)}`;
|
|
30
|
+
|
|
31
|
+
ctx.registerSeries({
|
|
32
|
+
id,
|
|
33
|
+
dataKey: props.dataKey,
|
|
34
|
+
type: "area",
|
|
35
|
+
color: stroke,
|
|
36
|
+
name: props.name ?? props.dataKey
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
onCleanup(() => {
|
|
40
|
+
ctx.unregisterSeries(id);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<g class={`visage-area-${props.dataKey}`} opacity={props.opacity ?? 1}>
|
|
45
|
+
{() => {
|
|
46
|
+
const dataArr = ctx.data();
|
|
47
|
+
if (dataArr.length === 0) return null;
|
|
48
|
+
|
|
49
|
+
const xScale = ctx.xScale();
|
|
50
|
+
const yScale = ctx.yScale();
|
|
51
|
+
const baselineY = ctx.innerHeight();
|
|
52
|
+
|
|
53
|
+
const points: Point[] = [];
|
|
54
|
+
for (let i = 0; i < dataArr.length; i++) {
|
|
55
|
+
const item = dataArr[i];
|
|
56
|
+
const val = item[props.dataKey];
|
|
57
|
+
if (typeof val !== "number" || Number.isNaN(val)) continue;
|
|
58
|
+
|
|
59
|
+
let x = 0;
|
|
60
|
+
if (xScale.type === "band") {
|
|
61
|
+
x = xScale(i) + xScale.bandwidth() / 2;
|
|
62
|
+
} else {
|
|
63
|
+
x = xScale(i);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const y = yScale(val);
|
|
67
|
+
points.push({ x, y });
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const areaD = pathArea(points, baselineY, { curve });
|
|
71
|
+
const lineD = pathLine(points, { curve });
|
|
72
|
+
|
|
73
|
+
const dots: Child[] = [];
|
|
74
|
+
if (props.dot && points.length > 0) {
|
|
75
|
+
const dotCfg = typeof props.dot === "object" ? props.dot : {};
|
|
76
|
+
const r = dotCfg.r ?? 3.5;
|
|
77
|
+
const dotFill = dotCfg.fill ?? "#ffffff";
|
|
78
|
+
const dotStroke = dotCfg.stroke ?? stroke;
|
|
79
|
+
|
|
80
|
+
for (let i = 0; i < points.length; i++) {
|
|
81
|
+
const p = points[i]!;
|
|
82
|
+
dots.push(
|
|
83
|
+
<circle
|
|
84
|
+
cx={p.x}
|
|
85
|
+
cy={p.y}
|
|
86
|
+
r={r}
|
|
87
|
+
fill={dotFill}
|
|
88
|
+
stroke={dotStroke}
|
|
89
|
+
stroke-width={2}
|
|
90
|
+
/>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return [
|
|
96
|
+
<path d={areaD} fill={fill} fill-opacity={fillOpacity} />,
|
|
97
|
+
<path
|
|
98
|
+
d={lineD}
|
|
99
|
+
fill="none"
|
|
100
|
+
stroke={stroke}
|
|
101
|
+
stroke-width={strokeWidth}
|
|
102
|
+
stroke-linejoin="round"
|
|
103
|
+
stroke-linecap="round"
|
|
104
|
+
/>,
|
|
105
|
+
...dots
|
|
106
|
+
];
|
|
107
|
+
}}
|
|
108
|
+
</g>
|
|
109
|
+
);
|
|
110
|
+
};
|
|
111
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import type { Child } from "../dom";
|
|
2
|
+
import { onCleanup } from "../signals";
|
|
3
|
+
import { useChartContext } from "./context";
|
|
4
|
+
|
|
5
|
+
export interface XAxisProps {
|
|
6
|
+
dataKey?: string;
|
|
7
|
+
tickFormat?: (val: any, index: number) => string;
|
|
8
|
+
tickCount?: number;
|
|
9
|
+
stroke?: string;
|
|
10
|
+
fontSize?: number | string;
|
|
11
|
+
fontFamily?: string;
|
|
12
|
+
hideLine?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function XAxis(props: XAxisProps): Child {
|
|
16
|
+
return () => {
|
|
17
|
+
const ctx = useChartContext();
|
|
18
|
+
|
|
19
|
+
if (props.dataKey) {
|
|
20
|
+
ctx.setXDataKey(props.dataKey);
|
|
21
|
+
onCleanup(() => {
|
|
22
|
+
if (ctx.xDataKey() === props.dataKey) {
|
|
23
|
+
ctx.setXDataKey("");
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const stroke = props.stroke ?? "#94a3b8";
|
|
29
|
+
const fontSize = props.fontSize ?? 11;
|
|
30
|
+
const hideLine = props.hideLine ?? false;
|
|
31
|
+
|
|
32
|
+
const w = ctx.innerWidth();
|
|
33
|
+
const h = ctx.innerHeight();
|
|
34
|
+
const xScale = ctx.xScale();
|
|
35
|
+
const dataArr = ctx.data();
|
|
36
|
+
|
|
37
|
+
const elements: Child[] = [];
|
|
38
|
+
|
|
39
|
+
if (!hideLine) {
|
|
40
|
+
elements.push(<line x1={0} y1={h} x2={w} y2={h} stroke={stroke} stroke-width={1} />);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (xScale.type === "band") {
|
|
44
|
+
const ticks = xScale.ticks();
|
|
45
|
+
const bw = xScale.bandwidth();
|
|
46
|
+
for (let i = 0; i < ticks.length; i++) {
|
|
47
|
+
const val = ticks[i];
|
|
48
|
+
const x = xScale(i) + bw / 2;
|
|
49
|
+
const text = props.tickFormat ? props.tickFormat(val, i) : String(val);
|
|
50
|
+
elements.push(
|
|
51
|
+
<text x={x} y={h + 16} text-anchor="middle" font-size={fontSize} fill={stroke}>
|
|
52
|
+
{text}
|
|
53
|
+
</text>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
} else {
|
|
57
|
+
const count = props.tickCount ?? 5;
|
|
58
|
+
const ticks = xScale.ticks(count);
|
|
59
|
+
for (let i = 0; i < ticks.length; i++) {
|
|
60
|
+
const tickIdx = ticks[i]!;
|
|
61
|
+
const x = xScale(tickIdx);
|
|
62
|
+
const idx = Math.max(0, Math.min(dataArr.length - 1, Math.round(tickIdx)));
|
|
63
|
+
const rawItem = dataArr[idx];
|
|
64
|
+
const rawVal = props.dataKey && rawItem ? rawItem[props.dataKey] : idx;
|
|
65
|
+
const text = props.tickFormat ? props.tickFormat(rawVal, i) : String(rawVal ?? idx);
|
|
66
|
+
|
|
67
|
+
elements.push(
|
|
68
|
+
<text x={x} y={h + 16} text-anchor="middle" font-size={fontSize} fill={stroke}>
|
|
69
|
+
{text}
|
|
70
|
+
</text>
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return <g class="visage-x-axis">{elements}</g>;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface YAxisProps {
|
|
80
|
+
dataKey?: string;
|
|
81
|
+
tickFormat?: (val: any, index: number) => string;
|
|
82
|
+
unit?: string;
|
|
83
|
+
tickCount?: number;
|
|
84
|
+
stroke?: string;
|
|
85
|
+
fontSize?: number | string;
|
|
86
|
+
hideLine?: boolean;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function YAxis(props: YAxisProps): Child {
|
|
90
|
+
return () => {
|
|
91
|
+
const ctx = useChartContext();
|
|
92
|
+
|
|
93
|
+
const stroke = props.stroke ?? "#94a3b8";
|
|
94
|
+
const fontSize = props.fontSize ?? 11;
|
|
95
|
+
const hideLine = props.hideLine ?? true;
|
|
96
|
+
const unit = props.unit ?? "";
|
|
97
|
+
|
|
98
|
+
const h = ctx.innerHeight();
|
|
99
|
+
const yScale = ctx.yScale();
|
|
100
|
+
const ticks = yScale.ticks(props.tickCount ?? 5);
|
|
101
|
+
|
|
102
|
+
const elements: Child[] = [];
|
|
103
|
+
|
|
104
|
+
if (!hideLine) {
|
|
105
|
+
elements.push(<line x1={0} y1={0} x2={0} y2={h} stroke={stroke} stroke-width={1} />);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
for (let i = 0; i < ticks.length; i++) {
|
|
109
|
+
const val = ticks[i]!;
|
|
110
|
+
const y = yScale(val);
|
|
111
|
+
const formatted = props.tickFormat
|
|
112
|
+
? props.tickFormat(val, i)
|
|
113
|
+
: unit
|
|
114
|
+
? `${val}${unit}`
|
|
115
|
+
: String(val);
|
|
116
|
+
|
|
117
|
+
elements.push(
|
|
118
|
+
<text x={-8} y={y + 4} text-anchor="end" font-size={fontSize} fill={stroke}>
|
|
119
|
+
{formatted}
|
|
120
|
+
</text>
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return <g class="visage-y-axis">{elements}</g>;
|
|
125
|
+
};
|
|
126
|
+
}
|