weifuwu 0.55.1 → 0.55.2
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/README.md +29 -0
- package/dist/client/app.d.ts +7 -7
- package/dist/client/i18n.d.ts +5 -1
- package/dist/client/index.d.ts +6 -3
- package/dist/client/middleware/api.d.ts +5 -1
- package/dist/client/middleware/auth.d.ts +5 -1
- package/dist/client/middleware/ws.d.ts +11 -1
- package/dist/client/router.d.ts +14 -1
- package/dist/client/type-flow.test.d.ts +7 -0
- package/dist/client/types.d.ts +6 -1
- package/dist/client/vnode.d.ts +5 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -991,6 +991,35 @@ const Badge: Component = () =>
|
|
|
991
991
|
(props) => h('span', { class: `badge-${props.variant}` }, props.children)
|
|
992
992
|
```
|
|
993
993
|
|
|
994
|
+
### 类型流(props 泛型 + ctx 注入)
|
|
995
|
+
|
|
996
|
+
```tsx
|
|
997
|
+
import type { Component } from 'weifuwu/client'
|
|
998
|
+
import type { ApiInjected, RouteInjected } from 'weifuwu/client'
|
|
999
|
+
|
|
1000
|
+
// ① props 泛型:JSX 使用时自动类型检查(传错类型编译期报错)
|
|
1001
|
+
interface DeckCardProps { title: string; pages: number }
|
|
1002
|
+
const DeckCard: Component<DeckCardProps> = (_init, ctx) =>
|
|
1003
|
+
(props) => <div>{props.title} / {props.pages} 页</div>
|
|
1004
|
+
// <DeckCard title="x" pages={8} /> ✓
|
|
1005
|
+
// <DeckCard title="x" pages="8" /> ✗ 编译期报错
|
|
1006
|
+
|
|
1007
|
+
// ② ctx 注入声明:use(api()).use(router()) 后组件声明依赖,ctx 直接访问
|
|
1008
|
+
const Home: Component<{}, ApiInjected & RouteInjected> = (_init, ctx) => {
|
|
1009
|
+
ctx.api.get('/users') // ✓ 有类型
|
|
1010
|
+
ctx.app.navigate('/x') // ✓ 有类型
|
|
1011
|
+
return () => <h1>Home</h1>
|
|
1012
|
+
}
|
|
1013
|
+
// 未声明的注入字段编译期报错——注入从"文档约定"变成"类型保证"
|
|
1014
|
+
|
|
1015
|
+
createApp()
|
|
1016
|
+
.use(api()) // 注入 ctx.api
|
|
1017
|
+
.use(router({ routes })) // 注入 ctx.route / ctx.app
|
|
1018
|
+
.mount('#root', Home) // mount 时类型累积完整
|
|
1019
|
+
```
|
|
1020
|
+
|
|
1021
|
+
> 各中间件的注入接口:`api()` → `ApiInjected`、`auth()` → `AuthInjected`、`ws()` → `WsInjected`、`i18n()` → `I18nInjected`、`router()` → `RouteInjected`(均可从 `weifuwu/client` 导入)。
|
|
1022
|
+
|
|
994
1023
|
| 规则 | 说明 |
|
|
995
1024
|
|------|------|
|
|
996
1025
|
| 组件签名 | `(initProps: P, ctx: WfuiContext) => (props: P) => VNode \| null` |
|
package/dist/client/app.d.ts
CHANGED
|
@@ -14,11 +14,11 @@
|
|
|
14
14
|
* 并设置 childCtx.ui._selfId = 组件 ID
|
|
15
15
|
* render() 无参时从 this._selfId 取当前组件 ID
|
|
16
16
|
*/
|
|
17
|
-
import type {
|
|
17
|
+
import type { AppMiddleware } from './types.ts';
|
|
18
18
|
import type { Component } from './vnode.ts';
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
use(mw: AppMiddleware):
|
|
22
|
-
mount(rootSelector: string,
|
|
23
|
-
|
|
24
|
-
}
|
|
19
|
+
/** 应用句柄:use() 链式累积中间件注入的 ctx 类型,mount() 时组件拿到完整注入 */
|
|
20
|
+
export interface App<C extends object = {}> {
|
|
21
|
+
use<I extends object, O extends object>(mw: AppMiddleware<I, O>): App<C & O>;
|
|
22
|
+
mount(rootSelector: string, root: Component<any, C>): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
export declare function createApp<C extends object = {}>(): App<C>;
|
package/dist/client/i18n.d.ts
CHANGED
|
@@ -24,4 +24,8 @@ export interface I18nState {
|
|
|
24
24
|
setLocale: (lang: string) => void;
|
|
25
25
|
components: Record<string, Record<string, string>>;
|
|
26
26
|
}
|
|
27
|
-
|
|
27
|
+
/** i18n 中间件注入到 ctx 的字段 */
|
|
28
|
+
export interface I18nInjected {
|
|
29
|
+
i18n: I18nState;
|
|
30
|
+
}
|
|
31
|
+
export declare function i18n(opts?: I18nOptions): AppMiddleware<{}, I18nInjected>;
|
package/dist/client/index.d.ts
CHANGED
|
@@ -18,19 +18,22 @@
|
|
|
18
18
|
export { h, jsx, jsxs, jsxDEV, Fragment, Portal, createPortal } from './vnode.ts';
|
|
19
19
|
export type { VNode, VNodeType, Component } from './vnode.ts';
|
|
20
20
|
export { createApp } from './app.ts';
|
|
21
|
+
export type { App } from './app.ts';
|
|
21
22
|
export { router, RouteView } from './router.ts';
|
|
23
|
+
export type { RouteInjected } from './router.ts';
|
|
22
24
|
export { ws } from './middleware/ws.ts';
|
|
25
|
+
export type { WsClient, WsInjected } from './middleware/ws.ts';
|
|
23
26
|
export { api } from './middleware/api.ts';
|
|
24
27
|
export { auth } from './middleware/auth.ts';
|
|
25
|
-
export type { ApiClient, ApiOptions, ApiRequestOptions } from './middleware/api.ts';
|
|
28
|
+
export type { ApiClient, ApiOptions, ApiRequestOptions, ApiInjected } from './middleware/api.ts';
|
|
26
29
|
export { ApiError } from './middleware/api.ts';
|
|
27
|
-
export type { AuthClient, AuthOptions } from './middleware/auth.ts';
|
|
30
|
+
export type { AuthClient, AuthOptions, AuthInjected } from './middleware/auth.ts';
|
|
28
31
|
export { extendCtx } from './types.ts';
|
|
29
32
|
export type { WfuiContext, AppMiddleware, RouteDef } from './types.ts';
|
|
30
33
|
export { ErrorBoundary } from './error-boundary.ts';
|
|
31
34
|
export type { ErrorBoundaryProps } from './error-boundary.ts';
|
|
32
35
|
export { i18n } from './i18n.ts';
|
|
33
|
-
export type { I18nOptions, I18nState } from './i18n.ts';
|
|
36
|
+
export type { I18nOptions, I18nState, I18nInjected } from './i18n.ts';
|
|
34
37
|
export { lockScroll, unlockScroll } from './scroll-lock.ts';
|
|
35
38
|
export { trapFocus } from './focus-trap.ts';
|
|
36
39
|
export { computeFixedPos } from './popup.ts';
|
|
@@ -61,7 +61,11 @@ export interface ApiRequestOptions {
|
|
|
61
61
|
* await ctx.api.delete('/users/1')
|
|
62
62
|
* ```
|
|
63
63
|
*/
|
|
64
|
-
|
|
64
|
+
/** api 中间件注入到 ctx 的字段 */
|
|
65
|
+
export interface ApiInjected {
|
|
66
|
+
api: ApiClient;
|
|
67
|
+
}
|
|
68
|
+
export declare function api(options?: ApiOptions): AppMiddleware<{}, ApiInjected>;
|
|
65
69
|
/**
|
|
66
70
|
* API 错误 — 包含 HTTP 状态码和响应文本。
|
|
67
71
|
*
|
|
@@ -21,4 +21,8 @@ export interface AuthClient {
|
|
|
21
21
|
setUser: (user: any) => void;
|
|
22
22
|
refresh: () => Promise<boolean>;
|
|
23
23
|
}
|
|
24
|
-
|
|
24
|
+
/** auth 中间件注入到 ctx 的字段 */
|
|
25
|
+
export interface AuthInjected {
|
|
26
|
+
auth: AuthClient;
|
|
27
|
+
}
|
|
28
|
+
export declare function auth(options?: AuthOptions): AppMiddleware<{}, AuthInjected>;
|
|
@@ -12,4 +12,14 @@ export interface WsOptions {
|
|
|
12
12
|
pingInterval?: number;
|
|
13
13
|
pingTimeout?: number;
|
|
14
14
|
}
|
|
15
|
-
|
|
15
|
+
/** ws 中间件注入到 ctx 的字段 */
|
|
16
|
+
/** ws 中间件注入的客户端形状(与 WfuiContext.ws 一致) */
|
|
17
|
+
export interface WsClient {
|
|
18
|
+
send: (msg: unknown) => void;
|
|
19
|
+
onMessage: (fn: (data: unknown) => void) => () => void;
|
|
20
|
+
isConnected: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface WsInjected {
|
|
23
|
+
ws: WsClient;
|
|
24
|
+
}
|
|
25
|
+
export declare function ws(options?: WsOptions): AppMiddleware<{}, WsInjected>;
|
package/dist/client/router.d.ts
CHANGED
|
@@ -9,5 +9,18 @@ export interface RouterOptions {
|
|
|
9
9
|
routes: RouteDef[];
|
|
10
10
|
notFound?: (props: any, ctx: WfuiContext) => any;
|
|
11
11
|
}
|
|
12
|
-
|
|
12
|
+
/** router 中间件注入到 ctx 的字段 */
|
|
13
|
+
export interface RouteInjected {
|
|
14
|
+
route: {
|
|
15
|
+
path: string;
|
|
16
|
+
params: Record<string, string>;
|
|
17
|
+
query: Record<string, string>;
|
|
18
|
+
title?: string;
|
|
19
|
+
};
|
|
20
|
+
/** 编程式导航 */
|
|
21
|
+
app: {
|
|
22
|
+
navigate: (path: string) => void;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export declare function router(opts: RouterOptions): AppMiddleware<{}, RouteInjected>;
|
|
13
26
|
export declare function RouteView(_props: {}, ctx: WfuiContext): () => any;
|
package/dist/client/types.d.ts
CHANGED
|
@@ -81,7 +81,12 @@ export interface WfuiContext {
|
|
|
81
81
|
};
|
|
82
82
|
}
|
|
83
83
|
/** 中间件签名 */
|
|
84
|
-
|
|
84
|
+
/**
|
|
85
|
+
* 前端中间件:输入 ctx 需要 I,输出 ctx 注入 O(链式累积,createApp().use() 类型自动合并)
|
|
86
|
+
* api() → AppMiddleware<{}, ApiInjected> 注入 ctx.api
|
|
87
|
+
* router()→ AppMiddleware<{}, RouteInjected> 注入 ctx.route / ctx.app
|
|
88
|
+
*/
|
|
89
|
+
export type AppMiddleware<I extends object = {}, O extends object = I> = (ctx: WfuiContext & I) => (WfuiContext & O) | Promise<WfuiContext & O>;
|
|
85
90
|
/** 路由定义 */
|
|
86
91
|
export interface RouteDef {
|
|
87
92
|
path: string;
|
package/dist/client/vnode.d.ts
CHANGED
|
@@ -30,7 +30,11 @@ export interface VNode {
|
|
|
30
30
|
/** 组件 mount/render 时的 ctx 版本号(供三态 skip 判定) */
|
|
31
31
|
_ctxVersion?: number;
|
|
32
32
|
}
|
|
33
|
-
|
|
33
|
+
/**
|
|
34
|
+
* 两阶段组件:外层 = mount(一次),内层 = render(每次 dirty/props 变化)。
|
|
35
|
+
* P = props 类型(JSX 自动推断),C = 组件依赖的 ctx 注入(如 ApiInjected & RouteInjected)
|
|
36
|
+
*/
|
|
37
|
+
export type Component<P = {}, C extends object = {}> = (initProps: P, ctx: WfuiContext & C) => ((props: P) => VNode | null) | null;
|
|
34
38
|
export declare const Fragment: unique symbol;
|
|
35
39
|
/** Portal — 将子 VNode 渲染到 document.body 下的独立容器 */
|
|
36
40
|
export declare const Portal: unique symbol;
|