weifuwu 0.71.0 → 0.72.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/README.md +58 -47
- package/dist/components/Accordion/Accordion.d.ts +1 -1
- package/dist/components/Affix/Affix.d.ts +1 -1
- package/dist/components/AiChat/AiChat.d.ts +2 -2
- package/dist/components/Alert/Alert.d.ts +1 -1
- package/dist/components/AlertGroup/AlertGroup.d.ts +1 -1
- package/dist/components/Anchor/Anchor.d.ts +1 -1
- package/dist/components/ApprovalCard/ApprovalCard.d.ts +1 -1
- package/dist/components/AspectRatio/AspectRatio.d.ts +1 -1
- package/dist/components/AutoComplete/AutoComplete.d.ts +1 -1
- package/dist/components/Avatar/Avatar.d.ts +1 -1
- package/dist/components/AvatarGroup/AvatarGroup.d.ts +1 -1
- package/dist/components/BackTop/BackTop.d.ts +1 -1
- package/dist/components/Badge/Badge.d.ts +1 -1
- package/dist/components/Breadcrumb/Breadcrumb.d.ts +1 -1
- package/dist/components/Button/Button.d.ts +1 -1
- package/dist/components/Calendar/Calendar.d.ts +1 -1
- package/dist/components/Card/Card.d.ts +1 -1
- package/dist/components/Carousel/Carousel.d.ts +1 -1
- package/dist/components/Cascader/Cascader.d.ts +1 -1
- package/dist/components/Chart/Chart.d.ts +1 -1
- package/dist/components/Checkbox/Checkbox.d.ts +1 -1
- package/dist/components/CheckboxGroup/CheckboxGroup.d.ts +1 -1
- package/dist/components/CodeBlock/CodeBlock.d.ts +1 -1
- package/dist/components/Collapse/Collapse.d.ts +1 -1
- package/dist/components/ColorPicker/ColorPicker.d.ts +1 -1
- package/dist/components/Command/Command.d.ts +1 -1
- package/dist/components/Confirm/Confirm.d.ts +2 -2
- package/dist/components/ContextMenu/ContextMenu.d.ts +1 -1
- package/dist/components/CopyButton/CopyButton.d.ts +1 -1
- package/dist/components/DatePicker/DatePicker.d.ts +1 -1
- package/dist/components/Descriptions/Descriptions.d.ts +1 -1
- package/dist/components/DiffView/DiffView.d.ts +1 -1
- package/dist/components/Divider/Divider.d.ts +1 -1
- package/dist/components/Drawer/Drawer.d.ts +1 -1
- package/dist/components/Dropdown/Dropdown.d.ts +1 -1
- package/dist/components/Editor/Editor.d.ts +1 -1
- package/dist/components/Editor/tools/toolbar.d.ts +1 -1
- package/dist/components/EmptyState/EmptyState.d.ts +1 -1
- package/dist/components/Field/Field.d.ts +1 -1
- package/dist/components/FileUpload/FileUpload.d.ts +1 -1
- package/dist/components/FloatButton/FloatButton.d.ts +1 -1
- package/dist/components/Form/Form.d.ts +1 -1
- package/dist/components/Grid/Grid.d.ts +1 -1
- package/dist/components/Highlight/Highlight.d.ts +1 -1
- package/dist/components/HoverCard/HoverCard.d.ts +2 -2
- package/dist/components/Icon/Icon.d.ts +1 -1
- package/dist/components/Img/Img.d.ts +1 -1
- package/dist/components/InView/InView.d.ts +1 -1
- package/dist/components/InfiniteScroll/InfiniteScroll.d.ts +1 -1
- package/dist/components/Input/Input.d.ts +1 -1
- package/dist/components/InputNumber/InputNumber.d.ts +1 -1
- package/dist/components/JSONViewer/JSONViewer.d.ts +1 -1
- package/dist/components/Kanban/Kanban.d.ts +1 -1
- package/dist/components/Label/Label.d.ts +1 -1
- package/dist/components/Layout/Layout.d.ts +1 -1
- package/dist/components/Link/Link.d.ts +1 -1
- package/dist/components/List/List.d.ts +1 -1
- package/dist/components/Loading/Loading.d.ts +1 -1
- package/dist/components/LogViewer/LogViewer.d.ts +1 -1
- package/dist/components/Markdown/Markdown.d.ts +1 -1
- package/dist/components/Mentions/Mentions.d.ts +1 -1
- package/dist/components/Menu/Menu.d.ts +1 -1
- package/dist/components/Menubar/Menubar.d.ts +1 -1
- package/dist/components/MessageBubble/MessageBubble.d.ts +1 -1
- package/dist/components/Modal/Modal.d.ts +1 -1
- package/dist/components/NavMenu/NavMenu.d.ts +1 -1
- package/dist/components/Notification/Notification.d.ts +2 -2
- package/dist/components/PageHeader/PageHeader.d.ts +1 -1
- package/dist/components/Pagination/Pagination.d.ts +1 -1
- package/dist/components/PasswordInput/PasswordInput.d.ts +1 -1
- package/dist/components/PinInput/PinInput.d.ts +1 -1
- package/dist/components/Pipeline/Pipeline.d.ts +1 -1
- package/dist/components/Popconfirm/Popconfirm.d.ts +2 -2
- package/dist/components/Popover/Popover.d.ts +2 -2
- package/dist/components/ProgressBar/ProgressBar.d.ts +1 -1
- package/dist/components/QRCode/QRCode.d.ts +1 -1
- package/dist/components/RadioGroup/RadioGroup.d.ts +1 -1
- package/dist/components/Rate/Rate.d.ts +1 -1
- package/dist/components/Resizable/Resizable.d.ts +1 -1
- package/dist/components/Result/Result.d.ts +1 -1
- package/dist/components/Scrollbar/Scrollbar.d.ts +1 -1
- package/dist/components/SearchInput/SearchInput.d.ts +1 -1
- package/dist/components/SegmentedControl/SegmentedControl.d.ts +1 -1
- package/dist/components/Select/Select.d.ts +1 -1
- package/dist/components/Skeleton/Skeleton.d.ts +1 -1
- package/dist/components/Slider/Slider.d.ts +1 -1
- package/dist/components/Space/Space.d.ts +1 -1
- package/dist/components/Sparkline/Sparkline.d.ts +1 -1
- package/dist/components/StatCard/StatCard.d.ts +1 -1
- package/dist/components/Steps/Steps.d.ts +1 -1
- package/dist/components/Switch/Switch.d.ts +1 -1
- package/dist/components/Table/Table.d.ts +1 -1
- package/dist/components/Tabs/Tabs.d.ts +1 -1
- package/dist/components/Tag/Tag.d.ts +1 -1
- package/dist/components/TagsInput/TagsInput.d.ts +1 -1
- package/dist/components/Textarea/Textarea.d.ts +1 -1
- package/dist/components/ThemeSwitch/ThemeSwitch.d.ts +1 -1
- package/dist/components/Timeline/Timeline.d.ts +1 -1
- package/dist/components/Toast/Toast.d.ts +2 -2
- package/dist/components/ToggleGroup/ToggleGroup.d.ts +1 -1
- package/dist/components/ToolCallCard/ToolCallCard.d.ts +1 -1
- package/dist/components/Tooltip/Tooltip.d.ts +2 -2
- package/dist/components/Tour/Tour.d.ts +1 -1
- package/dist/components/Transfer/Transfer.d.ts +1 -1
- package/dist/components/Tree/Tree.d.ts +1 -1
- package/dist/components/TreeSelect/TreeSelect.d.ts +1 -1
- package/dist/components/Typography/Typography.d.ts +1 -1
- package/dist/components/VirtualList/VirtualList.d.ts +1 -1
- package/dist/components/VirtualTable/VirtualTable.d.ts +1 -1
- package/dist/components/Watermark/Watermark.d.ts +1 -1
- package/dist/components/index.js +12 -12
- package/dist/dev/index.js +1 -1
- package/dist/index.js +4 -4
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/ssr-page.d.ts +1 -1
- package/dist/ui/ssr.d.ts +1 -1
- package/dist/ui-dom/Confirm.d.ts +44 -0
- package/dist/ui-dom/Notification.d.ts +70 -0
- package/dist/ui-dom/Toast.d.ts +43 -0
- package/dist/ui-dom/index.d.ts +33 -0
- package/dist/ui-dom/index.js +18 -0
- package/dist/ui-dom/jsx-runtime.d.ts +4 -0
- package/dist/ui-dom/jsx-runtime.js +1 -0
- package/dist/ui-dom/popup-tracker.d.ts +36 -0
- package/dist/ui-dom/registry.d.ts +39 -0
- package/dist/{client → ui-dom}/render.d.ts +2 -1
- package/dist/ui-dom/router.d.ts +66 -0
- package/dist/ui-dom/serve.d.ts +28 -0
- package/dist/ui-dom/ssr.d.ts +56 -0
- package/dist/{client → ui-dom}/types.d.ts +22 -0
- package/dist/{client → ui-dom}/ui.d.ts +2 -0
- package/dist/{client → ui-dom}/vnode.d.ts +13 -12
- package/docs/custom-components.md +2 -0
- package/docs/frontend-middleware.md +3 -1
- package/docs/frontend-ui-dom.md +110 -0
- package/docs/frontend.md +3 -1
- package/docs/realtime.md +2 -0
- package/docs/saas.md +2 -0
- package/package.json +7 -7
- package/dist/client/app.d.ts +0 -26
- package/dist/client/error-boundary.d.ts +0 -23
- package/dist/client/index.d.ts +0 -54
- package/dist/client/index.js +0 -6
- package/dist/client/registry.d.ts +0 -49
- package/dist/client/router.d.ts +0 -27
- package/dist/client/type-flow.test.d.ts +0 -7
- /package/dist/{client → ui-dom}/ai.d.ts +0 -0
- /package/dist/{client → ui-dom}/browser.d.ts +0 -0
- /package/dist/{client → ui-dom}/diff.d.ts +0 -0
- /package/dist/{client → ui-dom}/focus-trap.d.ts +0 -0
- /package/dist/{client → ui-dom}/hydration.d.ts +0 -0
- /package/dist/{client → ui-dom}/i18n.d.ts +0 -0
- /package/dist/{client → ui-dom}/locale/en_US.d.ts +0 -0
- /package/dist/{client → ui-dom}/locale/zh_CN.d.ts +0 -0
- /package/dist/{client → ui-dom}/middleware/api.d.ts +0 -0
- /package/dist/{client → ui-dom}/middleware/auth.d.ts +0 -0
- /package/dist/{client → ui-dom}/middleware/ws.d.ts +0 -0
- /package/dist/{client → ui-dom}/motion.d.ts +0 -0
- /package/dist/{client → ui-dom}/popup.d.ts +0 -0
- /package/dist/{client → ui-dom}/reactive.d.ts +0 -0
- /package/dist/{client → ui-dom}/route-match.d.ts +0 -0
- /package/dist/{client → ui-dom}/scroll-lock.d.ts +0 -0
- /package/dist/{client → ui-dom}/use-chat.d.ts +0 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 服务端 SSR 字符串遍历器 — async 工厂组件(形态 C)的 HTML 序列化
|
|
3
|
+
*
|
|
4
|
+
* 支持:
|
|
5
|
+
* - 同步组件(mount → render → VNode → HTML)
|
|
6
|
+
* - async 工厂组件(await 工厂 → 数据进 HTML;服务端不缓存定义,数据 per-request)
|
|
7
|
+
* - Fragment / Portal(内联子节点)
|
|
8
|
+
* - innerHTML prop(原样输出)、class/style 对象序列化
|
|
9
|
+
* - 事件处理器 / ref 剥离、文本自动转义(XSS)
|
|
10
|
+
* - 服务端 ctx shim($ no-op dirty、ctx.data 预取、selfId 隔离)
|
|
11
|
+
*
|
|
12
|
+
* 产物为 HtmlSafe 标记的安全 HTML 片段,可直接内联进 ctx.ui.html 模板。
|
|
13
|
+
*/
|
|
14
|
+
import type { Component, AsyncComponent } from './vnode.ts';
|
|
15
|
+
export interface SsrOptions {
|
|
16
|
+
/** 服务端数据存储:ctx.data 预取结果写入此处,调用方序列化进 __DATA__ */
|
|
17
|
+
data?: Map<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* SSR 渲染组件 → HTML 片段(HtmlSafe 标记,可直接内联进 ctx.ui.html 模板,不二次转义)。
|
|
21
|
+
*
|
|
22
|
+
* ```ts
|
|
23
|
+
* const data = new Map()
|
|
24
|
+
* const html = await ctx.ui.ssr(BlogPage, { slug }, { data })
|
|
25
|
+
* return ctx.ui.html`
|
|
26
|
+
* <div id="root">${html}</div>
|
|
27
|
+
* ${ctx.ui.ssrData(data)}
|
|
28
|
+
* `
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare function ssrToString(Comp: Component | AsyncComponent, props: Record<string, any>, serverCtx: any, opts?: SsrOptions): Promise<string>;
|
|
32
|
+
/** 序列化数据存储 → window.__DATA__ 脚本(防 XSS:转义 <) */
|
|
33
|
+
export declare function serializeData(data: Map<string, unknown>): string;
|
|
34
|
+
import type { UIRouter } from './router.ts';
|
|
35
|
+
export interface SsrPageResult {
|
|
36
|
+
html: string;
|
|
37
|
+
/** __DATA__ 脚本(hydration 种子) */
|
|
38
|
+
dataScript: string;
|
|
39
|
+
/** 完整 HTML(含 dataScript) */
|
|
40
|
+
page: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* SSR 渲染路由页面 → 完整 HTML(Node 无 DOM)。
|
|
44
|
+
* 执行 router 匹配 → 中间件链 → handler(async 组件)→ vnode → renderSsr。
|
|
45
|
+
*
|
|
46
|
+
* ```ts
|
|
47
|
+
* const { page } = await ssrPage(router, { url: '/users/42' })
|
|
48
|
+
* // 客户端 uiServe(router, { root, hydrate: true }) 收养
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export declare function ssrPage(router: UIRouter, opts: {
|
|
52
|
+
url: string;
|
|
53
|
+
title?: string;
|
|
54
|
+
lang?: string;
|
|
55
|
+
rootId?: string;
|
|
56
|
+
}): Promise<SsrPageResult>;
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import type { UseChatHandle, UseChatOptions } from './use-chat.ts';
|
|
5
5
|
import type { VNode } from './vnode.ts';
|
|
6
|
+
export type { VNode } from './vnode.ts';
|
|
6
7
|
import type { Placement } from './popup.ts';
|
|
7
8
|
/** 弹层位置跟踪配置 — 供 ctx.ui.usePopupPosition 使用 */
|
|
8
9
|
export interface PopupPositionOptions {
|
|
@@ -587,3 +588,24 @@ declare global {
|
|
|
587
588
|
var __DATA__: Record<string, unknown> | undefined;
|
|
588
589
|
}
|
|
589
590
|
export {};
|
|
591
|
+
/** ui-dom ctx:client WfuiContext + 顶层 params/query/data(定稿——对齐后端 ctx.params/ctx.query) */
|
|
592
|
+
export type UIContext<C extends object = {}> = WfuiContext & C & {
|
|
593
|
+
params: Record<string, string>;
|
|
594
|
+
query: Record<string, string>;
|
|
595
|
+
data: NonNullable<WfuiContext['data']>;
|
|
596
|
+
[key: string]: any;
|
|
597
|
+
};
|
|
598
|
+
/** req = window.location(浏览器原生 Location,不包装) */
|
|
599
|
+
export type UIRequest = Location;
|
|
600
|
+
/** res = VNode(数据结构);uiServe = VDOM(落地) */
|
|
601
|
+
export type UIResponse = VNode | null;
|
|
602
|
+
/** handler = 异步组件:async (location, ctx) => vnode($ 有效) */
|
|
603
|
+
export type UIHandler<C extends object = {}> = (location: Location, ctx: UIContext<C>) => Promise<UIResponse> | UIResponse;
|
|
604
|
+
/** middleware = 两阶段 async:(location, ctx, children) => async (location, ctx) => vnode */
|
|
605
|
+
export type UIMiddleware<I extends object = {}, O extends object = {}> = (location: Location, ctx: UIContext<I>, children: UIHandler<any>) => Promise<UIHandler<O>> | UIHandler<O>;
|
|
606
|
+
/** 路由定义(UIRouter.get 内部存储) */
|
|
607
|
+
export interface UIRouteDef {
|
|
608
|
+
path: string;
|
|
609
|
+
handler: UIHandler;
|
|
610
|
+
title?: string;
|
|
611
|
+
}
|
|
@@ -72,5 +72,7 @@ export interface UiDeps {
|
|
|
72
72
|
/** mount 阶段标记置位/恢复(mountComponent 包裹) */
|
|
73
73
|
setMounting: (v: boolean) => void;
|
|
74
74
|
endMounting: () => void;
|
|
75
|
+
/** 注册表实例(serve 注入局部;缺省 ctx.__registry) */
|
|
76
|
+
registry?: import('./registry.ts').Registry;
|
|
75
77
|
}
|
|
76
78
|
export declare function createUi(deps: UiDeps): WfuiContext['ui'] & UiInternal;
|
|
@@ -77,18 +77,6 @@ export declare const Fragment: unique symbol;
|
|
|
77
77
|
/** Portal — 将子 VNode 渲染到 document.body 下的独立容器 */
|
|
78
78
|
export declare const Portal: unique symbol;
|
|
79
79
|
/** JSX 类型声明 — 使 TypeScript 理解自定义 JSX 运行时 */
|
|
80
|
-
declare global {
|
|
81
|
-
namespace JSX {
|
|
82
|
-
type Element = VNode | null;
|
|
83
|
-
type ElementType = string | Component<any, any>;
|
|
84
|
-
interface IntrinsicAttributes {
|
|
85
|
-
key?: string | number;
|
|
86
|
-
}
|
|
87
|
-
interface IntrinsicElements {
|
|
88
|
-
[tag: string]: any;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
80
|
export declare function jsx(type: VNodeType, props: Record<string, any> | null, key?: string | null): VNode;
|
|
93
81
|
export declare const jsxs: typeof jsx;
|
|
94
82
|
export declare function jsxDEV(type: VNodeType, props: Record<string, any> | null, key?: string | null): VNode;
|
|
@@ -100,3 +88,16 @@ export declare function isFragment(vnode: VNode): boolean;
|
|
|
100
88
|
export declare function isPortal(vnode: VNode): boolean;
|
|
101
89
|
/** Portal VNode — 子节点渲染到 document.body#__wf_portal 中 */
|
|
102
90
|
export declare function createPortal(children: VNodeChild, portalKey?: string): VNode;
|
|
91
|
+
/** JSX 类型声明 — ui-dom 是 jsxImportSource(client 壳不再声明) */
|
|
92
|
+
declare global {
|
|
93
|
+
namespace JSX {
|
|
94
|
+
type Element = import('./vnode.ts').VNode | null;
|
|
95
|
+
type ElementType = string | ((props: any, ctx: any) => any) | typeof Fragment | typeof Portal;
|
|
96
|
+
interface IntrinsicElements {
|
|
97
|
+
[tag: string]: any;
|
|
98
|
+
}
|
|
99
|
+
interface IntrinsicAttributes {
|
|
100
|
+
key?: string | number;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# ui-dom — 前端路由(UIRouter + uiServe,试验性)
|
|
2
|
+
|
|
3
|
+
> **试验性**:`src/ui-dom/` 是定稿架构(`design/ui-architecture.md`)的落地——
|
|
4
|
+
> **UIRouter(纯路由)+ uiServe(渲染运行时)**,复用 `weifuwu/components`
|
|
5
|
+
> (VNode 契约共享,组件零修改)。渲染算法复制自 client(局部 registry 隔离,
|
|
6
|
+
> 不与 createApp 交叉)。当前未随 npm 包发布,源码直用。
|
|
7
|
+
>
|
|
8
|
+
> 概念对齐:**req = window.location**,**res = VNode**(数据结构),
|
|
9
|
+
> **uiServe = VDOM**(落地机制),**params/query 在 ctx**(对齐后端 `ctx.params`)。
|
|
10
|
+
|
|
11
|
+
## 快速开始
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import { UIRouter, uiServe, h } from './src/ui-dom/index.ts'
|
|
15
|
+
import { toast } from './src/ui-dom/Toast.ts'
|
|
16
|
+
import { Button } from './src/components/index.ts'
|
|
17
|
+
|
|
18
|
+
const app = new UIRouter()
|
|
19
|
+
|
|
20
|
+
app.use(toast()) // ctx 注入链(对齐后端 app.use——注入 ctx.toast)
|
|
21
|
+
|
|
22
|
+
// handler = 异步组件:async (location, ctx) => VNode($ 有效)
|
|
23
|
+
app.get('/', async (location, ctx) => {
|
|
24
|
+
const info = await ctx.data.get('/api/info', async () => ({ title: '首页' }))
|
|
25
|
+
const $ = ctx.ui.$()
|
|
26
|
+
$.clicks = $.clicks ?? 0
|
|
27
|
+
return h('div', {},
|
|
28
|
+
h('h2', {}, info.title),
|
|
29
|
+
h(Button, { onClick: () => $.clicks++ }, `点击 ${$.clicks} 次`),
|
|
30
|
+
h(Button, { variant: 'secondary', onClick: () => ctx.toast?.('提示', 'success') }, '弹 toast'),
|
|
31
|
+
)
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
app.get('/users/:id', (location, ctx) => h('div', {}, `用户 ${ctx.params.id}`))
|
|
35
|
+
app.notFound(() => h('div', {}, '404'))
|
|
36
|
+
|
|
37
|
+
uiServe(app, { root: '#root' }) // 装配点:路由已注册 → serve 监听 URL → 渲染
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## 核心概念
|
|
41
|
+
|
|
42
|
+
### req / res / 落地分离
|
|
43
|
+
|
|
44
|
+
| 概念 | 含义 |
|
|
45
|
+
|------|------|
|
|
46
|
+
| req | `window.location`(浏览器原生,不包装) |
|
|
47
|
+
| res | `VNode`(handler 返回的数据结构) |
|
|
48
|
+
| uiServe | VDOM 落地(renderValue/patchValue diff·patch DOM) |
|
|
49
|
+
| ssrPage | 服务端落地(renderSsr → HTML + `__DATA__`) |
|
|
50
|
+
|
|
51
|
+
handler 只产 VNode,落地由 serve 决定——SSR 与 SPA 是两种落地,同一 router 定义共享。
|
|
52
|
+
|
|
53
|
+
### UIRouter 三态 use(对齐后端 app.use)
|
|
54
|
+
|
|
55
|
+
| 形态 | 签名 | 用途 |
|
|
56
|
+
|------|------|------|
|
|
57
|
+
| ctx 注入 | `use(mw: AppMiddleware)` | `(ctx) => ctx`——注入 ctx.toast/confirm 等(类型累积 `UIRouter<C & O>`) |
|
|
58
|
+
| 渲染中间件 | `use(mw: UIMiddleware)` | `(location, ctx, children) => (location, ctx) => vnode`——layout/SSR 包装 children |
|
|
59
|
+
| 子路由 | `use(prefix, sub)` | 独立路由树(sub 的中间件/notFound/嵌套均生效) |
|
|
60
|
+
|
|
61
|
+
运行时按 `arg.length` 区分(1 参 = ctx 注入;3 参 = 渲染)。
|
|
62
|
+
|
|
63
|
+
### components 复用(零修改)
|
|
64
|
+
|
|
65
|
+
VNode 契约与 client 共享(Fragment/Portal symbol 同一份)——components 产的 VNode
|
|
66
|
+
直接被 ui-dom 渲染器识别。渲染算法(render/diff/createUi 19 原语)复制到 ui-dom,
|
|
67
|
+
**registry/popup-tracker/dirty 集合局部实例**(不与 createApp 交叉)。
|
|
68
|
+
|
|
69
|
+
命令式工厂(toast/confirm/notification)复制到 ui-dom(`src/ui-dom/Toast.ts` 等):
|
|
70
|
+
components 版 import client 的 mountVNode(模块级 registry)会注册错——ui-dom 版用局部。
|
|
71
|
+
|
|
72
|
+
### $ 响应式(两层)
|
|
73
|
+
|
|
74
|
+
| 层级 | 触发 | 重渲染范围 |
|
|
75
|
+
|------|------|-----------|
|
|
76
|
+
| 路由实例级 `$`(handler 的 `ctx.ui.$()`) | 赋值 | 重渲染 handler(data 缓存命中) |
|
|
77
|
+
| 组件级 `$`(子组件 `ctx.ui.$()`) | 赋值 | **仅该组件**(父 handler 不重跑) |
|
|
78
|
+
|
|
79
|
+
## SSR + hydration(端到端)
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
// 服务端(Node 无 DOM):ssrPage → 完整 HTML + __DATA__
|
|
83
|
+
import { ssrPage } from './src/ui-dom/ssr.ts'
|
|
84
|
+
import { app } from './router.ts' // 路由定义两端共享
|
|
85
|
+
|
|
86
|
+
const { page } = await ssrPage(app, { url: '/users/42' })
|
|
87
|
+
|
|
88
|
+
// 客户端:uiServe hydrate(收养服务端 HTML + __DATA__ 种子命中不重取数)
|
|
89
|
+
uiServe(app, { root: '#root', hydrate: true })
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
- SSR 时 `ctx.data.get` 写入 dataStore → `__DATA__` 脚本;hydrate 从种子同步命中
|
|
93
|
+
- renderSsr:组件两阶段 + asyncComponent await(数据 per-request)/ Portal 内联 / 事件剥离
|
|
94
|
+
- SSR 确定性:ui 19 原语 shim 全 no-op(不启动监听/会话);渲染期非确定性由开发者规避
|
|
95
|
+
|
|
96
|
+
## ctx 注入
|
|
97
|
+
|
|
98
|
+
| 字段 | 说明 |
|
|
99
|
+
|------|------|
|
|
100
|
+
| `ctx.params` / `ctx.query` | 路由参数 / URL query(顶层,对齐后端) |
|
|
101
|
+
| `ctx.data.get/set/has` | 数据管道(缓存 + in-flight 合并 + `__DATA__` 种子) |
|
|
102
|
+
| `ctx.ui.*` | 19 原语(`$`/`dirty`/`render`/`usePopup`/`useChat`/`useInView`…) |
|
|
103
|
+
| `ctx.browser.*` | 环境抽象(复制自 client) |
|
|
104
|
+
| `ctx.toast` / `ctx.confirm` / `ctx.notification` | 命令式注入(`app.use(toast())` 等) |
|
|
105
|
+
|
|
106
|
+
## demo
|
|
107
|
+
|
|
108
|
+
`apps/ui-router-demo`:UIRouter + uiServe + components(Button/Input/Tag/Dropdown)
|
|
109
|
+
+ toast 注入 + 嵌套路由 + SSR/hydrate 端到端。
|
|
110
|
+
启动:`node apps/ui-router-demo/server.ts` → http://localhost:3100
|
package/docs/frontend.md
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
# 前端 API 核心(weifuwu/
|
|
1
|
+
# 前端 API 核心(weifuwu/ui-dom)
|
|
2
|
+
|
|
3
|
+
> ⚠️ **`weifuwu/client` 已删除**——本页为历史文档。前端运行时唯一入口是 **`weifuwu/ui-dom`**(UIRouter 纯路由 + uiServe 渲染运行时 + SSR/hydration),权威参考见 **[docs/frontend-ui-dom.md](frontend-ui-dom.md)**。本页的 createApp/router/RouteView 用法已失效,对应新 API 为 `uiServe` / `UIRouter`。
|
|
2
4
|
|
|
3
5
|
> 以下为完整 API 参考,按需查阅。新手建议先阅读 README 的「核心概念」和「快速开始」。
|
|
4
6
|
|
package/docs/realtime.md
CHANGED
|
@@ -69,6 +69,8 @@ app.get('/page', (req, ctx) => ctx.ui.html`
|
|
|
69
69
|
|
|
70
70
|
```ts
|
|
71
71
|
app.get('/app.js', (req, ctx) => ctx.ui.js('./src/main.tsx')) // 相对路径
|
|
72
|
+
|
|
73
|
+
> ⚠️ **weifuwu/client 已删除**——前端运行时唯一入口为 `weifuwu/ui-dom`,见 [frontend-ui-dom.md](frontend-ui-dom.md)。
|
|
72
74
|
app.get('/app.js', (req, ctx) => ctx.ui.js('weifuwu/client')) // 或包名
|
|
73
75
|
```
|
|
74
76
|
|
package/docs/saas.md
CHANGED
|
@@ -75,6 +75,8 @@ app.get('/me', (req, ctx) => ok(ctx.user)) // 已注入
|
|
|
75
75
|
app.post('/secure', (req, ctx) => { ctx.auth.requireAuth(); ... })
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
+
|
|
79
|
+
> ⚠️ **weifuwu/client 已删除**——前端运行时唯一入口为 `weifuwu/ui-dom`,见 [frontend-ui-dom.md](frontend-ui-dom.md)。
|
|
78
80
|
- **安全基线**:scrypt 密码哈希(per-user salt + timing-safe,异步不阻塞);access token = HMAC-SHA256 JWT(与 `weifuwu/client` 的 `auth()` 天然配对);refresh token = 不透明随机串,DB 只存哈希,logout/轮换即撤销
|
|
79
81
|
- **防枚举**:登录失败统一 401(不泄露邮箱是否存在)
|
|
80
82
|
- **`ctx.auth` 方法面**:`register` / `login` / `logout` / `requireAuth` / `setPassword(userId, newPwd)` / `createToken(type, payload, { ttlSeconds })`(邮箱验证/密码重置自接)
|
package/package.json
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "weifuwu",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.72.0",
|
|
5
5
|
"description": "AI SaaS framework — (req, ctx) => Response",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
9
9
|
"default": "./dist/index.js"
|
|
10
10
|
},
|
|
11
|
-
"./
|
|
12
|
-
"types": "./dist/
|
|
13
|
-
"default": "./dist/
|
|
11
|
+
"./ui-dom": {
|
|
12
|
+
"types": "./dist/ui-dom/index.d.ts",
|
|
13
|
+
"default": "./dist/ui-dom/index.js"
|
|
14
14
|
},
|
|
15
|
-
"./
|
|
16
|
-
"types": "./dist/
|
|
17
|
-
"default": "./dist/
|
|
15
|
+
"./ui-dom/jsx-runtime": {
|
|
16
|
+
"types": "./dist/ui-dom/index.d.ts",
|
|
17
|
+
"default": "./dist/ui-dom/jsx-runtime.js"
|
|
18
18
|
},
|
|
19
19
|
"./layout": "./dist/layout/weifuwu-layout.css",
|
|
20
20
|
"./layout/style.css": "./dist/layout/weifuwu-layout.css",
|
package/dist/client/app.d.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* weifuwu/client 应用 — createApp + ctx.ui.render
|
|
3
|
-
*
|
|
4
|
-
* createApp() → app.use(mw) → app.mount('#root', RootComponent)
|
|
5
|
-
*
|
|
6
|
-
* ctx.ui 在 mount 时注入:
|
|
7
|
-
* ctx.ui.render() 同步刷新当前组件
|
|
8
|
-
* ctx.ui.render(['#id']) 同步刷新指定组件
|
|
9
|
-
* ctx.ui.dirty() 异步刷新当前组件(微任务批处理)
|
|
10
|
-
* ctx.ui.$() 响应式状态容器($.x = val 自动 dirty)
|
|
11
|
-
*
|
|
12
|
-
* render / dirty / $ 通过 prototype chain 实现组件级 scope:
|
|
13
|
-
* 每个组件 mount 时创建 childCtx.ui = Object.create(ctx.ui)
|
|
14
|
-
* 并设置 childCtx.ui._selfId = 组件 ID
|
|
15
|
-
* render() 无参时从 this._selfId 取当前组件 ID
|
|
16
|
-
*/
|
|
17
|
-
import type { AppMiddleware } from './types.ts';
|
|
18
|
-
import type { Component } from './vnode.ts';
|
|
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>, options?: {
|
|
23
|
-
hydrate?: boolean;
|
|
24
|
-
}): Promise<void>;
|
|
25
|
-
}
|
|
26
|
-
export declare function createApp<C extends object = {}>(): App<C>;
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ErrorBoundary — 错误边界组件
|
|
3
|
-
*
|
|
4
|
-
* 捕获子组件渲染时的错误,展示 fallback 替代崩溃白屏。
|
|
5
|
-
*
|
|
6
|
-
* ```tsx
|
|
7
|
-
* <ErrorBoundary fallback={<p>出错了</p>}>
|
|
8
|
-
* <UserProfile />
|
|
9
|
-
* </ErrorBoundary>
|
|
10
|
-
* ```
|
|
11
|
-
*
|
|
12
|
-
* 基于 ctx.ui._errorHandler 机制:在渲染子组件前注入错误处理器,
|
|
13
|
-
* 子组件 render 抛错时设置 error → 重新渲染 fallback。
|
|
14
|
-
*/
|
|
15
|
-
import type { WfuiContext } from './types.ts';
|
|
16
|
-
import type { VNode } from './vnode.ts';
|
|
17
|
-
export interface ErrorBoundaryProps {
|
|
18
|
-
fallback?: VNode | ((props: {
|
|
19
|
-
error: unknown;
|
|
20
|
-
}) => VNode) | null;
|
|
21
|
-
children?: any;
|
|
22
|
-
}
|
|
23
|
-
export declare function ErrorBoundary(props: ErrorBoundaryProps, ctx: WfuiContext): (props2: ErrorBoundaryProps) => VNode | null;
|
package/dist/client/index.d.ts
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* weifuwu/client — VDOM 前端框架
|
|
3
|
-
*
|
|
4
|
-
* 概念:
|
|
5
|
-
* 组件 = (props, ctx) => VNode
|
|
6
|
-
* 状态 = JS 变量
|
|
7
|
-
* 更新 = ctx.ui.render()
|
|
8
|
-
* 挂载/卸载 = ref 回调
|
|
9
|
-
*
|
|
10
|
-
* 导出:
|
|
11
|
-
* h / jsx / jsxs / jsxDEV / Fragment → JSX 工厂
|
|
12
|
-
* createApp → 应用引导
|
|
13
|
-
* router / RouteView → 路由
|
|
14
|
-
* api / auth / ws → 中间件
|
|
15
|
-
* extendCtx → ctx 扩展
|
|
16
|
-
* WfuiContext / AppMiddleware / RouteDef → 类型
|
|
17
|
-
*/
|
|
18
|
-
export { h, jsx, jsxs, jsxDEV, Fragment, Portal, createPortal } from './vnode.ts';
|
|
19
|
-
export type { VNode, VNodeType, Component, AsyncComponent } from './vnode.ts';
|
|
20
|
-
export { asyncComponent, isAsyncComponent } from './vnode.ts';
|
|
21
|
-
export { createApp } from './app.ts';
|
|
22
|
-
export type { App } from './app.ts';
|
|
23
|
-
export { router, RouteView } from './router.ts';
|
|
24
|
-
export type { RouteInjected } from './router.ts';
|
|
25
|
-
export { ws } from './middleware/ws.ts';
|
|
26
|
-
export type { WsClient, WsInjected } from './middleware/ws.ts';
|
|
27
|
-
export { api } from './middleware/api.ts';
|
|
28
|
-
export { auth } from './middleware/auth.ts';
|
|
29
|
-
export type { ApiClient, ApiOptions, ApiRequestOptions, ApiInjected } from './middleware/api.ts';
|
|
30
|
-
export { ApiError } from './middleware/api.ts';
|
|
31
|
-
export type { AuthClient, AuthOptions, AuthInjected } from './middleware/auth.ts';
|
|
32
|
-
export { extendCtx } from './types.ts';
|
|
33
|
-
export type { WfuiContext, AppMiddleware, RouteDef } from './types.ts';
|
|
34
|
-
export { aiStream } from './ai.ts';
|
|
35
|
-
export type { AiStreamCallbacks, AiStreamOptions, AiStreamHandle } from './ai.ts';
|
|
36
|
-
export { toChatMessages } from './use-chat.ts';
|
|
37
|
-
export type { UiMessage, UiToolCall, UseChatOptions, UseChatState, UseChatHandle, ChatApi } from './use-chat.ts';
|
|
38
|
-
export type { WfStreamEvent, WfMessageStart, WfToken, WfUsage, WfDone, WfError, WfErrorCode, WfToolCall, WfToolResult, WfToolProgress, WfStep, WfApprovalRequest, WfApprovalResponse, WfApprovalDecision, ChatMessage, ChatParams, MessageRole, ToolCall, ToolDefinition, } from '../ai/types.ts';
|
|
39
|
-
export { ErrorBoundary } from './error-boundary.ts';
|
|
40
|
-
export type { ErrorBoundaryProps } from './error-boundary.ts';
|
|
41
|
-
export { i18n } from './i18n.ts';
|
|
42
|
-
export type { I18nOptions, I18nState, I18nInjected } from './i18n.ts';
|
|
43
|
-
export { createReactiveState } from './reactive.ts';
|
|
44
|
-
export type { ReactiveState } from './types.ts';
|
|
45
|
-
export { lockScroll, unlockScroll } from './scroll-lock.ts';
|
|
46
|
-
export { trapFocus } from './focus-trap.ts';
|
|
47
|
-
export { mountVNode, callRefCleanup, clearAsyncComponentCache } from './render.ts';
|
|
48
|
-
export { hydrateVNode } from './hydration.ts';
|
|
49
|
-
export { patchValue } from './diff.ts';
|
|
50
|
-
export { animateOut } from './motion.ts';
|
|
51
|
-
export { computeFixedPos, computeFixedPosRect } from './popup.ts';
|
|
52
|
-
export type { FixedPos, Placement } from './popup.ts';
|
|
53
|
-
export { zhCN } from './locale/zh_CN.ts';
|
|
54
|
-
export { enUS } from './locale/en_US.ts';
|
package/dist/client/index.js
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
var $e="__wfAsyncComponent";function Tn(e){let n=e;return n[$e]=!0,n}function J(e){return typeof e=="function"&&e?.[$e]===!0}var $=Symbol("Fragment"),B=Symbol("Portal");function Ne(e,n,t){return{type:e,props:Ke(n),key:t??void 0}}var En=Ne;function Pn(e,n,t){return Ne(e,n,t)}function Nn(e,n,...t){let o=Ke(n??{});return t.length>0&&(o.children=t.length===1?t[0]:t),{type:e,props:o,key:n?.key??void 0}}function Ke(e){if(!e)return{};let n={};for(let t of Object.keys(e))t!=="key"&&(n[t]=e[t]);return n}function _e(e,n){return{type:B,props:{children:e,portalKey:n},key:n??void 0,_placement:"remote"}}var _n=0,H=new Map,Q=[];function F(e){return Q.push(e),()=>{let n=Q.indexOf(e);n>=0&&Q.splice(n,1)}}var de=new WeakMap;function Z(){de=new WeakMap}function Ae(e,n){let t=de.get(e);if(t)return t;let o={promise:null};return o.promise=Promise.resolve().then(()=>e(n)).then(i=>{if(typeof i!="function")throw new Error(`asyncComponent factory <${e.name||"anonymous"}> must return a Component (initProps, ctx) => (props) => VNode.`);return o.resolved=i,i}),de.set(e,o),o}async function ze(e,n){return Ae(e,n).promise}function Ge(e){return de.get(e)?.resolved}function ke(e,n,t,o){try{e(n)}catch(i){console.error(`[weifuwu] ref ${t} error in <${o??"anonymous"}>`,i)}}function An(e){let n=e._child;if(n!=null)if(Array.isArray(n))for(let t of n)t&&typeof t=="object"&&W(t);else typeof n=="object"&&W(n)}function W(e){if(e==null||typeof e!="object")return;let n=e;if(n._id){if(n._customId&&H.delete(n._customId),H.delete(n._id),Q.length>0){let t=[...Q];for(let o of t)o(n._id);if(n._customId)for(let o of t)o(n._customId)}n._id=void 0,n._customId=void 0,n._render=void 0,n._parentNode=void 0,n._refNode=void 0}if(n._child!=null){if(Array.isArray(n._child))for(let t of n._child)t&&typeof t=="object"&&W(t);else W(n._child);n._child=void 0}if(n.props?.children&&typeof n.type=="string"){let t=Array.isArray(n.props.children)?n.props.children:[n.props.children];for(let o of t)o&&typeof o=="object"&&W(o)}typeof n.props?.ref=="function"&&ke(n.props.ref,null,"cleanup"),n._remoteEl&&(An(n),n._remoteEl.remove(),n._remoteEl=void 0)}function ee(){return`_wf_${_n++}`}var Ye=new WeakMap;function kn(e){let n=Ye.get(e)??{count:0,warned:!1};n.count++,n.count>=3&&!n.warned&&(n.warned=!0,console.warn("[weifuwu] ref \u51FD\u6570\u6BCF\u6B21\u6E32\u67D3\u90FD\u53D8\u5316\uFF08\u5185\u8054 ref\uFF09\u2014\u2014ref \u56DE\u8C03\u5728\u6BCF\u6B21\u6E32\u67D3\u540E\u91CD\u65B0\u6267\u884C\uFF08\u6027\u80FD\u635F\u8017\uFF09\u3002\u628A ref \u5B9A\u4E49\u5230 mount \u4F5C\u7528\u57DF\uFF08\u7A33\u5B9A\u5F15\u7528\uFF09\uFF1Aconst listRef = (el) => {...}; return h('div', { ref: listRef })")),Ye.set(e,n)}function z(e,n,t,o,i){if(t==null){if(o==null)return null;let a=D(o,i);return a==null?null:(n&&n.parentNode?n.parentNode.insertBefore(a,n):e.appendChild(a),a)}if(o==null)return n?(W(t),n.remove()):W(t),null;let l=Je(t),s=Je(o);if(l!==s){W(t);let a=D(o,i);return a==null?null:(n?.parentNode&&n.parentNode.replaceChild(a,n),a)}if(s==="text")return n&&n.textContent!==String(o)&&(n.textContent=String(o)),n;let c=o,d=t;if(typeof c.type=="function"){let a=c.type;d._render&&d.type===c.type&&(c._render=d._render,c._id=d._id,c._id&&H.set(c._id,c)),c._parentNode=e,c._refNode=n;let g=Object.create(i);g.ui=Object.create(i.ui);let m=g.ui;if(m._selfId=c._id,m._selfVNode=c,c._ctxVersion=d._ctxVersion??m._ctxVersion??0,d._render&&d.type===c.type&&Mn(d.props,c.props)&&!m._dirtySet?.has(d._id)&&c._ctxVersion===m._ctxVersion)return c._child=d._child,n;m._dirtySet?.delete(d._id);let b;try{typeof c._render=="function"?b=c._render(c.props):b=Me(a,c.props,c,g)}catch(w){let r=i.ui?._errorHandler;r?(r(w),b=null):(console.error(`[weifuwu] Component render error in <${a?.name||"anonymous"}> (id: ${d._id??"?"}, phase: update)`,w),b=null)}let C=d._child;c._child=b;let h=z(e,n,C,b,g);return h||(c._refNode=null),h}if(c.type===$){let a=d._childNodes,g=Ze(e,d,c,i,a);return c._childNodes=g,n}if(typeof c.type=="string"){if(n&&n.nodeType===1){let a=d.props?.ref,g=c.props?.ref;a!==g&&(typeof g=="function"&&g(n),typeof a=="function"&&typeof g=="function"&&kn(n)),Re(n,d.props,c.props),Ze(n,d,c,i)}else if(n){W(t);let a=D(o,i);return a==null?null:(n.parentNode?.replaceChild(a,n),a)}return n}if(c.type===B)return oe(d,c,i),null;if(Array.isArray(o)){let a=Array.isArray(t)?t:[];ce(a,o);let g=Array.from(e.childNodes),m=n?g.indexOf(n):-1,b=m>=0?ne(g.slice(m),a):ne(g,a);return fe(e,a,o,i,b,n),n}return n}var Xe=new Map;function Sn(e){let n=Xe.get(e);return n||(n=`fn:${e.name||"anon"}`,Xe.set(e,n)),n}function Je(e){if(e==null||typeof e=="boolean")return"null";if(typeof e=="string"||typeof e=="number")return"text";if(Array.isArray(e))return"array";let n=e;return typeof n.type=="function"?Sn(n.type):n.type===$?"fragment":n.type===B?"portal":typeof n.type=="string"?"tag:"+n.type:"unknown"}function Re(e,n,t){let o=n?Object.keys(n).filter(s=>s!=="children"&&s!=="key"&&s!=="innerHTML"):[],i=t?Object.keys(t).filter(s=>s!=="children"&&s!=="key"&&s!=="innerHTML"):[],l=new Set(i);for(let s of o){if(!n)break;if(!l.has(s)){if(s==="ref")continue;s.startsWith("on")&&typeof n[s]=="function"?e.removeEventListener(s.slice(2).toLowerCase(),n[s]):s==="value"&&(e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement||e instanceof HTMLSelectElement)?e.value="":e.removeAttribute(s==="className"?"class":s)}}for(let s of i){if(s==="ref")continue;let c=n?.[s],d=t?.[s];if(s==="innerHTML")d!==c&&(e.innerHTML=String(d??""));else if(d!==c)if(s==="class"||s==="className")e instanceof SVGElement?e.setAttribute("class",Qe(d)):e.className=Qe(d);else if(s==="style"&&typeof d=="object"&&d!==null){let a=e.style,g=d;for(let m of Object.keys(g)){let b=g[m];b==null?m.startsWith("--")?a.removeProperty(m):a[m]="":m.startsWith("--")?a.setProperty(m,String(b)):a[m]=typeof b=="number"?b+"px":String(b)}}else if(s.startsWith("on")&&typeof d=="function"){let a=s.slice(2).toLowerCase();typeof c=="function"&&e.removeEventListener(a,c),e.addEventListener(a,d)}else s==="draggable"?e.setAttribute("draggable",d?"true":"false"):s==="value"&&(e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement||e instanceof HTMLSelectElement)?e.value=String(d??""):d===!0?e.setAttribute(s,""):d!=null&&d!==!1?e.setAttribute(s,String(d)):s==="value"&&(e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement||e instanceof HTMLSelectElement)?e.value="":e.removeAttribute(s)}}function Qe(e){return typeof e=="string"?e:Array.isArray(e)?e.filter(Boolean).join(" "):e&&typeof e=="object"?Object.entries(e).filter(([,n])=>n).map(([n])=>n).join(" "):""}function Se(e){if(!(e==null||typeof e!="object"))return Array.isArray(e)?void 0:e.key}function ce(e,n){if(!n.some(o=>o&&typeof o=="object"&&!Array.isArray(o)&&o.key!==void 0)){for(let o=0;o<n.length;o++){let i=n[o];i&&typeof i=="object"&&!Array.isArray(i)&&(i.key=String(o))}for(let o=0;o<e.length;o++){let i=e[o];i&&typeof i=="object"&&!Array.isArray(i)&&(i.key=String(o))}}}function ne(e,n){let t=[],o=0;for(let i of n){if(i==null||typeof i=="boolean"){t.push(null);continue}let l=i;if(l.type===B){t.push(null);continue}if(l.type===$){let s=l._childNodes;Array.isArray(s)&&s.length>0?(t.push(s.slice()),o+=s.length):(t.push(e[o]?[e[o]]:null),o+=1)}else if(typeof l.type=="function")if(l._render){let s=l._childNodes??l._refNode;s==null?t.push(null):Array.isArray(s)?(t.push(s.slice()),o+=s.length):(t.push([s]),o+=1)}else t.push(e[o]?[e[o]]:null),o+=1;else typeof process<"u"&&process.env.DBG&&console.error("[map] idx=",o,"type=",l.type,"sourceLen=",e.length,"hit=",!!e[o]),t.push(e[o]?[e[o]]:null),o+=1}return t}function Ze(e,n,t,o,i){let l=te(n.props?.children),s=te(t.props?.children);ce(l,s);let c=i??Array.from(e.childNodes),d=ne(c,l),a=fe(e,l,s,o,d,i?.[0]??null),g=[];for(let m of a)m&&m.length>0&&g.push(...m);return g}function te(e){if(e==null)return[];if(!Array.isArray(e))return[e];let n=[];for(let t of e)Array.isArray(t)?n.push(...t):n.push(t);return n}function en(e){return e==null?[]:e instanceof DocumentFragment?Array.from(e.childNodes):[e]}function fe(e,n,t,o,i=[],l=null){if(!t.some(h=>h&&typeof h=="object"&&!Array.isArray(h)&&h.key!==void 0&&h._placement!=="remote")){let h=Math.max(n.length,t.length);for(let w=0;w<h;w++){let r=w<n.length?n[w]:null,u=w<t.length?t[w]:null;if(u==null){if(r!=null){W(r);for(let f of i[w]??[])f.remove()}}else if(r==null){let f=D(u,o);if(f!=null){let p=null;for(let y=w+1;y<i.length;y++){let v=i[y]?.[0];if(v&&v.parentNode===e){p=v;break}}p?e.insertBefore(f,p):e.appendChild(f)}}else{let f=i[w]?.[0]??null;z(e,f,r,u,o)}}return[]}for(let h=0;h<n.length;h++){let w=n[h];if(!(w==null||typeof w=="boolean")&&Se(w)===void 0)for(let r of i[h]??[])r.remove()}let c=new Map,d=0;for(let h=0;h<n.length;h++){let w=Se(n[h]);w!==void 0&&c.set(w,{vnode:n[h],nodes:i[h]??[],index:d++})}let a=t.map(h=>Se(h)),g=new Set(a);for(let h of[...c.keys()])if(!g.has(h)){let w=c.get(h);W(w.vnode);for(let r of w.nodes)r?.remove();c.delete(h)}let m=new Array(t.length).fill(null),b=-1,C=l&&l.parentNode===e?l:e.firstChild;for(let h=0;h<t.length;h++){let w=a[h],r=t[h],u=w!==void 0?c.get(w):void 0,f=r&&typeof r=="object"&&r._placement==="remote";if(u)if(u.nodes.length>0){if(u.index<b)for(let y of u.nodes)e.insertBefore(y,C);b=Math.max(b,u.index),z(e,u.nodes[0],u.vnode,r,o),m[h]=r._childNodes??u.nodes.filter(y=>y.parentNode===e),C=m[h][m[h].length-1]?.nextSibling??null}else if(f)oe(u.vnode,r,o),m[h]=[];else{let p=z(e,null,u.vnode,r,o);m[h]=en(p);for(let v of m[h])e.insertBefore(v,C);C=m[h][m[h].length-1]?.nextSibling??null}else if(f)Y(r,o),m[h]=[];else{let p=D(r,o);m[h]=en(p);for(let v of m[h])e.insertBefore(v,C);C=m[h][m[h].length-1]?.nextSibling??null}}return m}function Rn(e,n){if(e===n)return!0;if(Array.isArray(e)&&Array.isArray(n)){if(e.length!==n.length)return!1;for(let t=0;t<e.length;t++)if(e[t]!==n[t])return!1;return!0}return e===n}function Mn(e,n){if(e===n)return!0;if(!e||!n)return!1;let t=new Set([...Object.keys(e),...Object.keys(n)]);for(let o of t)if(o!=="key"){if(o==="children"){if(!Rn(e[o],n[o]))return!1}else if(e[o]!==n[o])return!1}return!0}var Le="http://www.w3.org/2000/svg",Ve=new Set(["svg","path","circle","line","rect","text","g","polyline","polygon","ellipse","defs","use","clipPath","mask","linearGradient","radialGradient","stop","tspan"]);function tn(e,n){return D(e,n)}function D(e,n){if(e==null||typeof e=="boolean")return null;if(typeof e=="string"||typeof e=="number")return document.createTextNode(String(e));if(Array.isArray(e))return On(e,n);let t=e;if(t.type===B)return Y(t,n),null;if(t.type===$){let s=document.createDocumentFragment(),c=t.props?.children==null?[]:Array.isArray(t.props.children)?t.props.children:[t.props.children];for(let d of c){let a=D(d,n);a!=null&&s.appendChild(a)}return t._childNodes=Array.from(s.childNodes),s}if(typeof t.type=="function")return Vn(t.type,t.props,t,n);let o=t.type,i=Ve.has(o)?document.createElementNS(Le,o):document.createElement(o);t.el=i;let l;for(let[s,c]of Object.entries(t.props??{}))s==="children"||s==="key"||s==="value"||s==="innerHTML"||nn(i,s,c);if("value"in(t.props??{})&&i instanceof HTMLSelectElement?l=t.props.value:"value"in(t.props??{})&&nn(i,"value",t.props.value),"innerHTML"in(t.props??{}))i.innerHTML=String(t.props.innerHTML??"");else{let s=Oe(t.props?.children);for(let c of s){let d=D(c,n);if(d!=null&&(i.appendChild(d),c&&typeof c=="object"&&typeof c.type=="function")){let a=c;a._parentNode||(a._parentNode=i,a._refNode=d)}}}return l!==void 0&&(i.value=String(l)),typeof t.props?.ref=="function"&&ke(t.props.ref,i,"mount",o),i}function Ln(e){let n=e.ui;n&&typeof n.render=="function"&&n.render(["_wf_root"])}function Me(e,n,t,o){let i;if(J(e)){if(i=Ge(e),!i)return Ae(e,o).promise.then(()=>Ln(o),()=>{}),null}else i=e;o.ui?.setMounting?.(!0);let l;try{l=i(n,o)}finally{o.ui?.endMounting?.()}if(typeof l!="function")throw new Error(`Component ${e.name||"anonymous"} must return a render function. Use (init_props, ctx) => (props) => VNode pattern.`);return t._render=l,l(n)}function Vn(e,n,t,o){t._id||(t._id=ee(),H.set(t._id,t));let i=Object.create(o);i.ui=Object.create(o.ui);let l=i.ui;l._selfId=t._id,l._selfVNode=t,t._ctxVersion=l._ctxVersion??0;let s;try{s=Me(e,n,t,i)}catch(d){let a=o.ui?._errorHandler;a?(a(d),s=null):(console.error(`[weifuwu] Component render error in <${e.name||"anonymous"}> (id: ${t._id??"?"}, phase: mount)`,d),s=null)}if(s==null){if(t._child=null,i.ui?._errorHandler){let a=document.createComment("wf-empty");return t._refNode=a,a}return null}t._child=s;let c=D(s,i);return t._refNode||(t._refNode=c),c}function On(e,n){let t=document.createDocumentFragment();for(let o of e){let i=D(o,n);i!=null&&t.appendChild(i)}return t}function Wn(){let e=document.getElementById("__wf_portal");return e||(e=document.createElement("div"),e.id="__wf_portal",e.style.cssText="position:fixed;inset:0;pointer-events:none;z-index:9999",document.body.appendChild(e)),e}function Y(e,n){let t=Wn(),o=document.createElement("div");o.style.pointerEvents="auto",t.appendChild(o),e._remoteEl=o;let i=te(e.props?.children);e._child=i;for(let l of i){let s=D(l,n);s!=null&&o.appendChild(s)}}function oe(e,n,t){let o=e?._remoteEl;if(n._remoteEl=o,!o){Y(n,t);return}let i=te(n.props?.children),l=e._child||[];n._child=i,ce(l,i);let s=ne(Array.from(o.childNodes),l);fe(o,l,i,t,s,s[0]?.[0]??null)}function Oe(e){if(e==null)return[];if(!Array.isArray(e))return[e];let n=[];for(let t of e)Array.isArray(t)?n.push(...t):n.push(t);return n}function nn(e,n,t){if(n!=="ref")if(n==="class"||n==="className")e instanceof SVGElement?e.setAttribute("class",String(t??"")):e.className=String(t??"");else if(n==="style"&&typeof t=="object"&&t!==null){let o=e.style;for(let i of Object.keys(t)){let l=t[i];l!=null&&(i.startsWith("--")?o.setProperty(i,String(l)):o[i]=typeof l=="number"?l+"px":String(l))}}else n.startsWith("on")&&typeof t=="function"?e.addEventListener(n.slice(2).toLowerCase(),t):n==="draggable"?e.setAttribute("draggable",t?"true":"false"):n==="value"&&(e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement||e instanceof HTMLSelectElement)?e.value=String(t??""):t===!0?e.setAttribute(n,""):t!=null&&t!==!1&&e.setAttribute(n,String(t))}function In(e,n,t){e.innerHTML="";let o=D(n,t);o instanceof Node&&e.appendChild(o)}function We(e){e.node=e.node?e.node.nextSibling:null}function Hn(e,n){e.node&&e.node.parentNode?e.node.parentNode.insertBefore(n,e.node):e.parent.appendChild(n)}function Un(e,n){e.node&&e.node.parentNode?(e.node.parentNode.replaceChild(n,e.node),We(e)):e.parent.appendChild(n)}async function re(e,n,t){if(e==null||typeof e=="boolean")return null;if(typeof e=="string"||typeof e=="number"){let c=String(e);if(t.node&&t.node.nodeType===3)return t.node.textContent!==c&&(t.node.textContent=c),We(t),t.node;let d=document.createTextNode(c);return Hn(t,d),d}if(Array.isArray(e)){let c=null;for(let d of e){let a=await re(d,n,t);a!=null&&!c&&(c=a)}return c}let o=e;if(o.type===B||o.type===$){let c=o.props?.children,d=c==null?[]:Array.isArray(c)?c:[c],a=null;for(let g of d){let m=await re(g,n,t);m!=null&&!a&&(a=m)}return a}if(typeof o.type=="function")return Dn(o,n,t);let i=o.type,l=o.props??{},s;if(t.node&&t.node.nodeType===1&&t.node.tagName.toLowerCase()===i.toLowerCase()?(s=t.node,We(t)):(s=Ve.has(i)?document.createElementNS(Le,i):document.createElement(i),Un(t,s)),o.el=s,Re(s,null,l),!("innerHTML"in l)){let c={parent:s,node:s.firstChild},d=Oe(l.children);for(let a of d){let g=await re(a,n,c);if(g!=null&&g.parentNode!==s&&s.appendChild(g),a&&typeof a=="object"&&typeof a.type=="function"){let m=a;m._parentNode||(m._parentNode=s,m._refNode=g)}}for(;c.node;){let a=c.node;c.node=a.nextSibling,a.parentNode?.removeChild(a)}}return"value"in l&&s instanceof HTMLSelectElement&&(s.value=String(l.value??"")),typeof l.ref=="function"&&l.ref(s),s}async function Dn(e,n,t){e._id||(e._id=ee(),H.set(e._id,e));let o=Object.create(n);o.ui=Object.create(n.ui);let i=o.ui;i._selfId=e._id,i._selfVNode=e,e._ctxVersion=i._ctxVersion??0;let l=e.type,s;try{let d;J(l)?d=await ze(l,o):d=l;let a=d(e.props??{},o);if(typeof a!="function")throw new Error(`Component ${l.name||"anonymous"} must return a render function. Use (init_props, ctx) => (props) => VNode pattern.`);e._render=a,s=a(e.props??{})}catch(d){let a=n.ui?._errorHandler;a?(a(d),s=null):(console.error(`[weifuwu] Component hydration error in <${l.name||"anonymous"}> (id: ${e._id??"?"})`,d),s=null)}if(s==null)return e._child=null,null;e._child=s;let c=await re(s,o,t);return e._refNode||(e._refNode=c),c}async function Ie(e,n,t){let o={parent:e,node:e.firstChild};for(await re(n,t,o);o.node;){let i=o.node;o.node=i.nextSibling,i.parentNode?.removeChild(i)}}var ie=0,on="",rn="",sn="",ln="",pe=0;function an(){return typeof window<"u"&&typeof document<"u"}function He(){if(ie++,ie>1||!an())return;pe=window.scrollY;let e=document.body;on=e.style.overflow,rn=e.style.position,sn=e.style.top,ln=e.style.width,e.style.overflow="hidden",(/iPhone|iPad|iPod/.test(navigator.platform)||/Mac/.test(navigator.platform)&&"ontouchend"in document)&&(e.style.position="fixed",e.style.top=`-${pe}px`,e.style.width="100%")}function Ue(){if(ie===0||(ie--,ie>0)||!an())return;let e=document.body;e.style.overflow=on,e.style.position=rn,e.style.top=sn,e.style.width=ln,pe>0&&window.scrollTo(0,pe)}var jn='a[href], button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';function me(e){let n=e.querySelectorAll(jn);if(n.length===0)return()=>{};let t=n[0],o=n[n.length-1],i=s=>{s.key==="Tab"&&(s.shiftKey&&document.activeElement===t?(s.preventDefault(),o.focus()):!s.shiftKey&&document.activeElement===o&&(s.preventDefault(),t.focus()))},l=document.activeElement;return queueMicrotask(()=>{t.focus()}),e.addEventListener("keydown",i),()=>{e.removeEventListener("keydown",i),l?.focus()}}function ge(e){let n=new WeakMap,t=new Set,o=l=>{if(l===null||typeof l!="object")return l;if(l instanceof Set||l instanceof Map){if(n.has(l))return n.get(l);let c=l instanceof Set?new Set(["add","delete","clear"]):new Set(["set","delete","clear"]),d=new Proxy(l,{get(a,g){let m=Reflect.get(a,g);return typeof m=="function"?c.has(String(g))?(...b)=>{let C=m.apply(a,b);e();for(let h of t)h();return C}:m.bind(a):m},set(a,g,m){Reflect.set(a,g,m),e();for(let b of t)b();return!0}});return n.set(l,d),d}if(l instanceof Date||l instanceof RegExp)return l;if(n.has(l))return n.get(l);let s=new Proxy(l,{set(c,d,a){if(Reflect.get(c,d)===a)return!0;Reflect.set(c,d,a),e();for(let m of t)m();return!0},get(c,d){let a=Reflect.get(c,d);return typeof a=="object"&&a!==null?o(a):a},deleteProperty(c,d){if(Reflect.has(c,d)){Reflect.deleteProperty(c,d),e();for(let a of t)a()}return!0}});return n.set(l,s),s},i=o({});return Object.defineProperty(i,"__watch",{value:l=>(t.add(l),()=>{t.delete(l)}),writable:!1,enumerable:!1}),i}function De(e,n,t){let o=new AbortController,i=t?.signal;i&&(i.aborted?o.abort():i.addEventListener("abort",()=>o.abort(),{once:!0}));let l=t?.traceId??Kn(),s=t?.record!==!1,c=[],d=(async()=>{let a;try{a=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json","X-Trace-Id":l,Accept:"text/event-stream",...t?.headers},body:JSON.stringify(n),signal:o.signal})}catch(g){if(o.signal.aborted)return;t?.onError?.({code:"provider_error",message:g instanceof Error?g.message:String(g)});return}if(!a.ok){t?.onError?.({code:$n(a.status),message:`HTTP ${a.status} ${a.statusText}`});return}try{for await(let{name:g,data:m}of Fn(a.body)){if(o.signal.aborted)return;Bn(c,{name:g,data:m},s),qn(g,m,t??{})}}catch(g){if(o.signal.aborted)return;t?.onError?.({code:"provider_error",message:g instanceof Error?g.message:String(g)})}})();return{abort:()=>o.abort(),done:d,traceId:l,events:c}}function qn(e,n,t){switch(e){case"wf:token":return t.onToken?.(n.text);case"wf:tool_call":return t.onToolCall?.(n);case"wf:tool_result":return t.onToolResult?.(n);case"wf:tool_progress":return t.onToolProgress?.(n);case"wf:step":return t.onStep?.(n);case"wf:approval_request":return t.onApproval?.(n);case"wf:usage":return t.onUsage?.(n);case"wf:done":return t.onDone?.(n);case"wf:error":return t.onError?.(n);default:return t.onEvent?.(e,n)}}async function*Fn(e){let n=e.getReader(),t=new TextDecoder,o="";try{for(;;){let{done:i,value:l}=await n.read();if(i)break;o+=t.decode(l,{stream:!0});let s=o.split(`
|
|
2
|
-
|
|
3
|
-
`);o=s.pop()??"";for(let c of s){let d="message",a="";for(let g of c.split(`
|
|
4
|
-
`))g.startsWith("event: ")?d=g.slice(7):g.startsWith("data: ")&&(a+=g.slice(6));if(a)try{yield{name:d,data:JSON.parse(a)}}catch{}}}}finally{n.releaseLock()}}function Bn(e,n,t){t&&(e.length>=1e3&&e.shift(),e.push(n))}function $n(e){return e===401||e===403?"auth_failed":e===429?"rate_limited":e>=500?"provider_error":"invalid_request"}function Kn(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`trace-${Date.now()}-${Math.random().toString(36).slice(2,10)}`}function un(e){return e.map(n=>({role:n.role,content:n.content}))}function je(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`msg-${Date.now()}-${Math.random().toString(36).slice(2,10)}`}function dn(e,n,t){t.initialMessages?e.messages=structuredClone(t.initialMessages):e.messages===void 0&&(e.messages=[]),e.input===void 0&&(e.input=""),e.streaming===void 0&&(e.streaming=!1),e.error===void 0&&(e.error=null),e.usage===void 0&&(e.usage=null),e.step===void 0&&(e.step=null);let o=null;function i(){if(!e.streaming)return;let C=e.messages[e.messages.length-1];return C&&C.role==="assistant"&&C.status==="streaming"?C:void 0}function l(C,h,w){let r=i();switch(C){case"wf:token":r&&(r.content+=h.text);break;case"wf:tool_call":{r&&(r.toolCalls||(r.toolCalls=[]),r.toolCalls.push({call:h,status:"running"}));break}case"wf:tool_progress":{let u=h,f=r?.toolCalls?.find(p=>p.call.id===u.toolCallId);f&&(f.progress=u);break}case"wf:tool_result":{let u=h,f=r?.toolCalls?.find(p=>p.call.id===u.id);f&&(f.result=u,f.status=u.ok?"ok":"error");break}case"wf:approval_request":r&&(r.approval=h);break;case"wf:usage":r&&(r.usage=h);break;case"wf:step":e.step=h;break;case"wf:done":r&&(r.status="done",r.approval=void 0),e.streaming=!1,e.step=null;break;case"wf:error":r&&(r.status="error",r.error=h,r.approval=void 0),e.error=h,e.streaming=!1,e.step=null;break;default:w?.(C,h);break}}function s(){let C=t.body?t.body(e.messages):{messages:un(e.messages)};o=n(t.url,C,{onToken:w=>l("wf:token",{text:w}),onToolCall:w=>l("wf:tool_call",w),onToolProgress:w=>l("wf:tool_progress",w),onToolResult:w=>l("wf:tool_result",w),onApproval:w=>l("wf:approval_request",w),onUsage:w=>l("wf:usage",w),onStep:w=>l("wf:step",w),onDone:w=>l("wf:done",w),onError:w=>l("wf:error",w),onEvent:(w,r)=>l(w,r,t.onEvent)},{signal:t.signal,headers:t.headers}),e.streaming=!0;let h=i();h&&o?.traceId&&(h.id=o.traceId)}function c(){if(e.streaming)return;let C=String(e.input??"").trim();C&&(e.input="",e.error=null,e.usage=null,e.step=null,e.messages.push({id:je(),role:"user",content:C,status:"done"},{id:je(),role:"assistant",content:"",status:"streaming",toolCalls:[]}),s())}function d(){o?.abort(),e.streaming=!1,e.step=null;let C=e.messages[e.messages.length-1];C&&C.role==="assistant"&&C.status==="streaming"&&(!C.content&&(!C.toolCalls||C.toolCalls.length===0)?e.messages.pop():C.status="done")}function a(){if(e.streaming)return;let C=-1;for(let h=e.messages.length-1;h>=0;h--)if(e.messages[h].role==="user"){C=h;break}C!==-1&&(e.messages.splice(C+1),e.error=null,e.usage=null,e.step=null,e.messages.push({id:je(),role:"assistant",content:"",status:"streaming",toolCalls:[]}),s())}function g(){o?.abort(),e.messages=[],e.input="",e.streaming=!1,e.error=null,e.usage=null,e.step=null}async function m(C,h){let w=e.messages[e.messages.length-1],r=w?.role==="assistant"?w.approval:void 0;if(r&&(w.approval=void 0,!!t.approveUrl))try{await fetch(t.approveUrl,{method:"POST",headers:{"Content-Type":"application/json",...t.headers},body:JSON.stringify({id:r.id,decision:C,note:h}),signal:t.signal})}catch(u){if(t.signal?.aborted)return;e.error={code:"provider_error",message:u instanceof Error?u.message:String(u)}}}function b(){o?.abort(),o=null}return{send:c,stop:d,retry:a,clear:g,approve:m,dispose:b}}function ye(e,n="bottom",t=6,o=!0){switch(n){case"bottom":return{top:e.bottom+t,left:o?e.left+e.width/2:e.left};case"top":return{top:e.top-t,left:o?e.left+e.width/2:e.left};case"left":return{top:o?e.top+e.height/2:e.top,left:e.left-t};case"right":return{top:o?e.top+e.height/2:e.top,left:e.right+t}}}function zn(e,n="bottom",t=6,o=!0){return ye(e.getBoundingClientRect(),n,t,o)}function he(e,n,t=8){if(!n)return e;let o=n.getBoundingClientRect();if(o.width===0&&o.height===0)return e;let i=Number.parseFloat(n.style.top)||o.top,l=Number.parseFloat(n.style.left)||o.left,s=e.top-i,c=e.left-l,d={top:o.top+s,bottom:o.bottom+s,left:o.left+c,right:o.right+c},a=window.innerWidth,g=window.innerHeight,m=e.top,b=e.left;return d.bottom>g-t&&(m=Math.max(t,m-(d.bottom-(g-t)))),d.top<t&&(m=Math.max(t,m+(t-d.top))),d.right>a-t&&(b=Math.max(t,b-(d.right-(a-t)))),d.left<t&&(b=Math.max(t,b+(t-d.left))),{top:m,left:b,width:e.width}}var ve=new Set,se=new Map,we=new Map,le=new Map;function cn(e){let{ctx:n,renderByIds:t,getSelfId:o,dirtyBatch:i,dirtySet:l,mediaRegistry:s,popupTrackers:c,scrollTrackers:d,schedulePopupRecompute:a,ensurePopupListeners:g,isRendering:m,isMounting:b,setMounting:C,endMounting:h}=e;return{_selfId:"_wf_root",_ctxVersion:0,_dirtySet:l,setMounting:C,endMounting:h,bumpCtxVersion:function(){this._ctxVersion++},render:function(r){if(m()){if(b())return;this._pendingRender||(this._pendingRender=!0,queueMicrotask(()=>{this._pendingRender=!1,this.render(r)}));return}if(!r||r.length===0){let u=o(this);if(u)r=[u];else return}t(r)},dirty:function(r){if(!b()){if(m()){this._pendingDirty||(this._pendingDirty=!0,queueMicrotask(()=>{this._pendingDirty=!1,this.dirty(r)}));return}if(!r||r.length===0){let u=o(this);if(u)r=[u];else return}for(let u of r)u&&(i.add(u),l.add(u));this._dirtyScheduled||(this._dirtyScheduled=!0,queueMicrotask(()=>{this._dirtyScheduled=!1;let u=[...i];i.clear(),u.length>0&&t(u)}))}},$:function(){let r=this;if(!Object.prototype.hasOwnProperty.call(r,"_$cache")){let u=ge(()=>{let f=r._selfVNode?._id??o(r);f&&n.ui.dirty([f])});r._$cache=u}return r._$cache},useChat:function(r){let u=this.$(),f=dn(u,De,r);Object.assign(u,{send:f.send,stop:f.stop,retry:f.retry,clear:f.clear,approve:f.approve,dispose:f.dispose});let p=o(this);if(p){let y=F(v=>{v===p&&(f.dispose(),y())})}return u},useMedia:function(r,u){let p=`media:${o(this)}:${r}`;if(!s.has(p)){let y=window.matchMedia(r);u(y.matches);let v=T=>u(T.matches);y.addEventListener("change",v),s.set(p,{mql:y,handler:v})}},useBreakpoint:function(r,u){let f=typeof r=="function"?{mobile:"(max-width: 639px)",tablet:"(min-width: 640px) and (max-width: 1023px)",desktop:"(min-width: 1024px)"}:r,p=typeof r=="function"?r:u,v=`bp:${o(this)}`;function T(){for(let[x,S]of Object.entries(f))if(window.matchMedia(S).matches)return x;return Object.keys(f)[0]??""}if(!s.has(v)){p(T());let x=[];for(let S of Object.values(f)){let O=window.matchMedia(S),P=()=>p(T());O.addEventListener("change",P),x.push({mql:O,handler:P})}s.set(v,{mqls:x})}},usePopupPosition:function(r){let u=o(this),f={top:0,left:0,refresh:()=>{}};if(!u)return f;let p={pos:f,getEl:r.el,isOpen:r.isOpen,compute:r.compute,panel:r.panel,margin:r.margin??8};return c.set(u,p),g(),f.refresh=()=>{let y=p.getEl();if(!y)return;let v=y.getBoundingClientRect();if(v.width===0&&v.height===0)return;let T=p.compute(v);Object.assign(f,he(T,p.panel?.(),p.margin))},f},useHoverCapable:function(){return typeof window<"u"&&!!window.matchMedia?.("(hover: hover)").matches},useStableRef:function(r,u){return p=>{p?r(p):u?.()}},useVisualViewport:function(){let r=o(this),u={height:window.innerHeight,offsetTop:0,keyboardOpen:!1},f=()=>{n.ui&&n.ui.dirty(r?[r]:void 0)},p=()=>{let v=window.visualViewport;u.height=v?.height??window.innerHeight,u.offsetTop=v?.offsetTop??0,u.keyboardOpen=u.height<window.innerHeight*.9,f()},y=window.visualViewport;if(y?.addEventListener?(y.addEventListener("resize",p),y.addEventListener("scroll",p)):window.addEventListener("resize",p),r){let v=F(T=>{T===r&&(y?.removeEventListener?(y.removeEventListener("resize",p),y.removeEventListener("scroll",p)):window.removeEventListener("resize",p),v())})}return u},usePopup:function(r){let u=o(this),f=this.useHoverCapable(),p=()=>typeof r.trigger=="function"?r.trigger():r.trigger,y=r.open!==void 0,v=()=>!!r.disabled?.(),T=()=>y?typeof r.open=="function"?!!r.open():!!r.open:r.isOpen(),x=E=>{v()||(y?r.onOpenChange?.(E):r.setOpen(E))},S=()=>{let E=r.placement;return typeof E=="function"?E():E??"bottom"},O=null,P=!1,N=n.ui.usePopupPosition({el:r.el,isOpen:()=>T(),compute:E=>{if(r.position){let L=r.position();return{top:L.y,left:L.x}}return ye(E,S(),r.gap??6,r.center!==!1)},panel:()=>O,margin:r.margin??8}),_=E=>{if(r.closeOnOutside===!1||!T())return;let L=E.target;if(!(L instanceof Node))return;let q=r.el();q&&q.contains(L)||O&&O.contains(L)||x(!1)},k=E=>{r.closeOnEscape!==!1&&(E.key!=="Escape"||!T()||x(!1))};if(document.addEventListener("mousedown",_),document.addEventListener("keydown",k),u){let E=F(L=>{L===u&&(document.removeEventListener("mousedown",_),document.removeEventListener("keydown",k),E())})}let A={},R=E=>typeof E=="function"?E():E??0,j=()=>R(r.openDelay),M=()=>R(r.closeDelay),V,I,ae=()=>{clearTimeout(V),clearTimeout(I),V=void 0,I=void 0},ue=E=>{if(v())return;let L=E.currentTarget,q=E.relatedTarget;L.contains(q)||(clearTimeout(I),I=void 0,V=setTimeout(()=>{V=void 0,x(!0)},j()))},hn=E=>{if(v())return;let L=E.currentTarget,q=E.relatedTarget;L.contains(q)||(clearTimeout(V),V=void 0,I=setTimeout(()=>{I=void 0,x(!1)},M()))},vn=()=>{v()||(clearTimeout(I),I=void 0,V=setTimeout(()=>{V=void 0,x(!0)},j()))},wn=()=>{v()||(clearTimeout(V),V=void 0,I=setTimeout(()=>{I=void 0,x(!1)},M()))},X=()=>p()==="hover";if(A.onMouseOver=E=>{X()&&ue(E)},A.onMouseOut=E=>{X()&&hn(E)},A.onClick=()=>{X()?f||x(!T()):p()==="click"&&x(!0)},A.onFocus=()=>{X()&&vn()},A.onBlur=()=>{X()&&wn()},p()==="longpress"){let E,L=0,q=0,K=()=>{clearTimeout(E),E=void 0};A.onPointerDown=U=>{v()||(L=U.clientX??0,q=U.clientY??0,K(),E=setTimeout(()=>{E=void 0,r.onTrigger?.({clientX:L,clientY:q}),x(!0)},r.longPressDuration??500))},A.onPointerUp=K,A.onPointerLeave=K,A.onPointerMove=U=>{let Ee=Math.abs((U.clientX??0)-L),Pe=Math.abs((U.clientY??0)-q);(Ee>10||Pe>10)&&K()},A.onContextMenu=U=>{U.preventDefault(),r.onTrigger?.({clientX:U.clientX??0,clientY:U.clientY??0}),x(!0)}}if(A.onKeyDown=E=>{E.key==="Escape"&&r.closeOnEscape!==!1&&x(!1)},u){let E=F(L=>{L===u&&(ae(),E())})}let Cn=E=>{if(E){O=E;let L=()=>N.refresh();E.addEventListener("animationend",L,{once:!0})}else O=null},xe=null,Te=null,bn=E=>{Cn(E),Te&&Te(E)};return{get open(){return T()},setOpen:x,wrapProps:A,portal:(E,L="popover")=>{if(v())return null;if(!T())return P=!1,xe=null,null;let K=r.el();(!P||K!==xe)&&(K?N.refresh():queueMicrotask(()=>{T()&&N.refresh()}),P=!0,xe=K);let U=E.props??{};Te=U.ref??null;let Ee=["wf-popup",U.class].filter(Boolean).join(" "),Pe={...U.style??{},position:"fixed",top:`${N.top}px`,left:`${N.left}px`,maxWidth:r.width!==void 0?`min(${r.width}px, calc(100vw - 32px))`:"calc(100vw - 32px)"},xn={...E,props:{...U,class:Ee,style:Pe,ref:bn}};return _e(xn,L)},refresh:()=>N.refresh()}},useLongPress:function(r){let{onLongPress:u,duration:f=500}=r,p,y=0,v=0,T=null,x=()=>{clearTimeout(p),p=void 0};return{onPointerDown:S=>{y=S.clientX??0,v=S.clientY??0,T=S,x(),p=setTimeout(()=>{p=void 0,T&&u(T)},f)},onPointerUp:x,onPointerLeave:x,onPointerMove:S=>{let O=Math.abs((S.clientX??0)-y),P=Math.abs((S.clientY??0)-v);(O>10||P>10)&&x()},onContextMenu:S=>{S.preventDefault(),u(S)}}},useInView:function(r){let u=o(this),f={isIn:!1,ready:!1,observe:x,refresh:S,disconnect:O},p=null,y=null,v=()=>{n.ui&&n.ui.dirty(u?[u]:void 0)};function T(){if(y?.disconnect(),y=null,!p)return;let P=typeof r.rootMargin=="function"?r.rootMargin():r.rootMargin,N=typeof r.threshold=="function"?r.threshold():r.threshold;y=new IntersectionObserver(_=>{let k=_[_.length-1];if(!k)return;let A=k.isIntersecting,R=A!==f.isIn,j=!f.ready;f.isIn=A,f.ready=!0,r.onChange?.(k,A),(R||j)&&v()},{root:r.root?r.root():null,rootMargin:P??"0px",threshold:N??0}),y.observe(p)}function x(P){p=P,P?T():(y?.disconnect(),y=null,f.isIn=!1)}function S(){T()}function O(){y?.disconnect(),y=null}return f},useScrollPosition:function(r){let u=o(this),f={y:0,refresh(){let y=p.getScroller();f.y=y instanceof Window?document.scrollingElement?.scrollTop??y.scrollY??0:y.scrollTop??0}},p={handle:f,getScroller:r.getScroller??(()=>window)};return u?(d.set(u,p),g(),f.refresh(),f):(f.refresh(),f)},useAsync:function(r){let u=o(this),f=ge(()=>{n.ui&&n.ui.dirty(u?[u]:void 0)});f.loading=!0;let p=0,y=()=>{let v=++p;f.loading=!0,f.error=null,Promise.resolve().then(()=>r()).then(T=>{p===v&&(f.data=T,f.loading=!1)}).catch(T=>{p===v&&(f.error=T,f.loading=!1)})};return y(),f.reload=y,f},useControlled:function(r){let u=o(this),f=r.value!==void 0;if(f&&!r.onChange&&r.name&&(ve.has(r.name)||(ve.add(r.name),console.warn(`[weifuwu/${r.name}] \u53D7\u63A7\u6A21\u5F0F\uFF08value \u5DF2\u4F20\uFF09\u4F46\u672A\u63D0\u4F9B onChange\uFF0C\u4EA4\u4E92\u65E0\u6CD5\u751F\u6548\u3002
|
|
5
|
-
\u975E\u53D7\u63A7\uFF1A\u53BB\u6389 value\uFF1B\u53D7\u63A7\uFF1A\u4F20\u5165 onChange={(v) => setValue(v)}`))),!f&&u&&!se.has(u)){se.set(u,r.value);let y=F(v=>{v===u&&(se.delete(u),y())})}let p=y=>{if(f){r.onChange?.(y);return}u&&se.set(u,y),n.ui&&(u?n.ui.dirty([u]):n.ui.render())};return{value:f?r.value:u?se.get(u):r.value,setValue:p,controlled:f}},useControlledInput:function(r){let u=o(this),f=this.useControlled({value:r.value,onChange:r.onChange,name:r.name});if(u&&!we.has(u)){we.set(u,{keyword:"",selectedLabel:""});let v=F(T=>{T===u&&(we.delete(u),v())})}let p=u?we.get(u):{keyword:"",selectedLabel:""},y=()=>{u?n.ui?.dirty([u]):n.ui?.render()};return{...f,get keyword(){return p.keyword},setKeyword(v){p.keyword=v,y()},get selectedLabel(){return p.selectedLabel},setSelectedLabel(v){p.selectedLabel=v,y()}}},useOpen:function(r){let u=o(this);if(u&&!le.has(u)){le.set(u,!1);let T=F(x=>{x===u&&(le.delete(u),T())})}let f=r.open!==void 0;f&&!r.onOpenChange&&r.name&&!ve.has(r.name)&&(ve.add(r.name),console.warn(`[weifuwu/${r.name}] \u53D7\u63A7\u6A21\u5F0F\uFF08open \u5DF2\u4F20\uFF09\u4F46\u672A\u63D0\u4F9B onOpenChange\uFF0C\u4EA4\u4E92\u65E0\u6CD5\u751F\u6548\u3002
|
|
6
|
-
\u975E\u53D7\u63A7\uFF1A\u53BB\u6389 open\uFF1B\u53D7\u63A7\uFF1A\u4F20\u5165 onOpenChange={(o) => setOpen(o)}`));let p=()=>f?!!r.open:u?le.get(u)??!1:!1,y=()=>{u?n.ui?.dirty([u]):n.ui?.render()},v=T=>{if(f){r.onOpenChange?.(T);return}u&&le.set(u,T),y()};return{get open(){return p()},setOpen:v,triggerProps:{onClick:()=>v(!0),onFocus:()=>{r.openOnFocus&&v(!0)}}}},usePresence:function(r){let u=o(this),f="closed",p,y=()=>{f="closed",n.ui&&(u?n.ui.dirty([u]):n.ui.render())};return{get phase(){return f},ref:T=>{T?p||(p=()=>{f==="exit"&&y()},T.addEventListener("animationend",p)):p=void 0},sync:T=>(T?f="open":f==="open"&&(f="exit"),f)}},useDialog:function(r){let u=o(this),f,p=null,y=this.usePresence(r);return{get phase(){return y.phase},rootRef:x=>{x?(He(),p&&(f=me(p)),y.ref(x)):(Ue(),f?.(),y.ref(null))},panelRef:x=>{p=x,x&&!f&&(f=me(x))},sync:x=>y.sync(x)}},useGlobalKey:function(r){let u=o(this);if(typeof window>"u")return()=>{};if(window.addEventListener("keydown",r),u){let f=F(p=>{p===u&&(window.removeEventListener("keydown",r),f())})}return()=>window.removeEventListener("keydown",r)},useDrag:function(r){let u=0,f=0,p=!1,y=x=>{p&&r.onMove(x,{x:x.clientX-u,y:x.clientY-f})},v=x=>{p&&(p=!1,window.removeEventListener("pointermove",y),window.removeEventListener("pointerup",v),r.onEnd?.(x))};return{onPointerDown:x=>{p||(x.preventDefault(),p=!0,u=x.clientX,f=x.clientY,window.addEventListener("pointermove",y),window.addEventListener("pointerup",v),r.onStart?.(x))}}},useDragDrop:function(r){let u={};r.onDrop&&(u.onDrop=p=>{p.preventDefault(),r.onDrop(p)}),r.onDragOver&&(u.onDragOver=p=>{p.preventDefault(),r.onDragOver(p)}),r.onDragLeave&&(u.onDragLeave=p=>r.onDragLeave(p));let f={draggable:!0};if(r.onDragStart){let p=r.onDragStart;f.onDragStart=y=>{typeof document<"u"&&document.body.classList.add("wf-dragging"),p(y)}}if(r.onDragEnd){let p=r.onDragEnd;f.onDragEnd=y=>{typeof document<"u"&&document.body.classList.remove("wf-dragging"),p(y)}}return{dropProps:u,dragProps:f}},useReducedMotion:function(){return typeof window<"u"&&!!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches},useAnimationEnd:function(r,u){let f=null,p=()=>{r(),u?.once&&f&&f.removeEventListener("animationend",p)};return v=>{v?(f=v,v.addEventListener("animationend",p)):f&&(f.removeEventListener("animationend",p),f=null)}},useTween:function(r,u){let f=o(this),p=this.useReducedMotion(),y=u?.duration??400,v=u?.ease==="linear"?N=>N:N=>1-Math.pow(1-N,3),T,x=r,S={value:p?r:0,reset:()=>{}},O=()=>{n.ui&&(f?n.ui.dirty([f]):n.ui.render())},P=N=>{if(x=N,p){S.value=N,O();return}if(N===S.value)return;T&&cancelAnimationFrame(T);let _=S.value,k=performance.now(),A=R=>{let j=Math.min(1,(R-k)/y);S.value=Math.round(_+(N-_)*v(j)),j<1?(T=requestAnimationFrame(A),O()):(T=void 0,O())};T=requestAnimationFrame(A)};return S.reset=N=>{N===x&&T||P(N)},queueMicrotask(()=>P(r)),S},selfId:function(r){if(typeof r!="string"||!r)throw new Error(`[weifuwu] selfId requires a non-empty string, got ${typeof r}`);if(H.has(r))throw new Error(`[weifuwu] Duplicate component ID: "${r}". Each component must have a unique custom ID.`);let u=this._selfVNode;u&&(u._customId=r,H.set(r,u))}}}function fn(){return{activeElement:()=>typeof document<"u"?document.activeElement:null,byId:e=>typeof document<"u"?document.getElementById(e):null,query:e=>typeof document<"u"?document.querySelector(e):null,createElement:e=>typeof document<"u"?document.createElement(e):null,bodyAppend:e=>{typeof document<"u"&&document.body.appendChild(e)},bodyRemove:e=>{typeof document<"u"&&e.parentNode&&document.body.removeChild(e)},copyText:async e=>{let n=typeof window<"u"?window:null;if(n?.navigator?.clipboard?.writeText)try{return await n.navigator.clipboard.writeText(e),!0}catch{}try{if(typeof document>"u")return!1;let t=document.createElement("textarea");t.value=e,t.style.position="fixed",t.style.opacity="0",document.body.appendChild(t),t.select();let o=document.execCommand("copy");return document.body.removeChild(t),o}catch{return!1}},execCommand:(e,n)=>typeof document<"u"?document.execCommand(e,!1,n):!1,queryCommandState:e=>typeof document<"u"?document.queryCommandState(e):!1,queryCommandValue:e=>typeof document<"u"?document.queryCommandValue(e):"",selectionText:()=>typeof window<"u"?window.getSelection?.()?.toString()??null:null,getSelection:()=>typeof window<"u"?window.getSelection():null,viewportHeight:()=>typeof window<"u"?window.innerHeight:0,scrollTop:()=>{let e=typeof document<"u"?document:null,n=typeof window<"u"?window:null;return e?.scrollingElement?.scrollTop??n?.scrollY??0},hash:()=>typeof window<"u"?window.location?.hash??"":"",setHash:e=>{typeof window<"u"&&(window.location.hash=e)},timeout:(e,n)=>typeof window<"u"?window.setTimeout(e,n):0,rootElement:()=>typeof document<"u"?document.documentElement:null,storageGet:e=>{try{return typeof window<"u"?window.localStorage?.getItem(e)??null:null}catch{return null}},storageSet:(e,n)=>{try{typeof window<"u"&&window.localStorage?.setItem(e,n)}catch{}}}}function Gn(){let e=[],n={},t=null,o=null,i=null,l=!1,s=null,c=!1,d=[];function a(P){d.push(c),c=P}function g(){c=d.pop()??!1}let m=new Set,b=!1,C=new Map;function h(P){let N=C.get(P);N&&(N.mql&&N.handler&&N.mql.removeEventListener("change",N.handler),N.mqls?.forEach(({mql:_,handler:k})=>_.removeEventListener("change",k)),C.delete(P))}let w=new Map,r=!1,u=0;function f(){r||(r=!0,window.addEventListener("scroll",v,{capture:!0,passive:!0}),window.addEventListener("resize",v))}function p(){r&&(window.removeEventListener("scroll",v,{capture:!0}),window.removeEventListener("resize",v),r=!1)}let y=new Map;function v(){u||(u=requestAnimationFrame(()=>{u=0;let P=[];for(let[N,_]of w){if(!_.isOpen())continue;let k=_.getEl();if(!k)continue;let A=k.getBoundingClientRect();if(A.width===0&&A.height===0)continue;let R=_.compute(A);Object.assign(_.pos,he(R,_.panel?.(),_.margin)),P.push(N)}for(let[N,_]of y){let k=_.getScroller(),A=k instanceof Window?document.scrollingElement?.scrollTop??k.scrollY??0:k.scrollTop??0;A!==_.handle.y&&(_.handle.y=A,P.push(N))}P.length>0&&n.ui.render(P)}))}function T(P){if(!l){l=!0;for(let N of P){let _=H.get(N);if(!_||!_._render)continue;n.ui._dirtySet?.delete(N);let k=_._child,A=_._render(_.props);if(_._child=A,k&&k._placement==="remote"||A&&A._placement==="remote"){k&&A?oe(k,A,n):A?Y(A,n):k&&W(k);continue}if(!_._parentNode&&_._refNode){let R=_._refNode.parentNode;R&&(_._parentNode=R)}if(_._parentNode){let R=z(_._parentNode,_._refNode??null,k,A,n);R&&R!==_._refNode?_._refNode=R:R||(_._refNode=null)}}l=!1,x()}}function x(){let P=n.ui;P&&m.size>0&&!P._dirtyScheduled&&(P._dirtyScheduled=!0,queueMicrotask(()=>{P._dirtyScheduled=!1;let N=[...m];m.clear(),N.length>0&&T(N)}))}function S(P){return P?._selfId??n.ui?._selfId}let O={get ctx(){return n},use(P){return e.push(P),O},async mount(P,N,_){o=N;for(let M of e)n=await M(n);let k=typeof P=="string"?document.querySelector(P):P;if(!k)throw new Error(`mount target not found: ${P}`);t=k;let A=!!_?.hydrate;A||(t.innerHTML="");let R=new Map,j=globalThis.__DATA__??window.__DATA__;if(j&&typeof j=="object")for(let[M,V]of Object.entries(j))R.set(M,{value:V});if(n.data={async get(M,V){let I=R.get(M);if(I&&"value"in I)return I.value;if(I?.promise)return I.promise;if(!V)return;let ae=Promise.resolve().then(()=>V()).then(ue=>(R.set(M,{value:ue}),ue));return R.set(M,{promise:ae}),ae},set(M,V){R.set(M,{value:V})},has(M){return R.has(M)}},s=F(M=>{for(let V of[...C.keys()])(V.startsWith(`media:${M}:`)||V===`bp:${M}`)&&h(V);w.delete(M),y.delete(M)}),n.browser=fn(),n.ui=cn({ctx:n,renderByIds:T,getSelfId:S,dirtyBatch:m,dirtySet:new Set,mediaRegistry:C,popupTrackers:w,scrollTrackers:y,schedulePopupRecompute:v,ensurePopupListeners:f,destroyPopupListeners:p,isRendering:()=>l,isMounting:()=>c,setMounting:a,endMounting:g}),l=!0,i=Yn(N,n),i._id="_wf_root",i._parentNode=t,i._refNode=A?t.firstChild:null,H.set("_wf_root",i),A)await Ie(t,i,n);else{let M=tn(i,n);M instanceof Node&&t.appendChild(M)}i._refNode=t.firstChild,l=!1,x()},destroy(){u&&(cancelAnimationFrame(u),u=0),p(),i&&W(i),s&&(s(),s=null),w.clear(),y.clear();for(let P of[...C.keys()])h(P);H.clear(),t&&(t.innerHTML=""),t=null,i=null,n={}}};return O}function Yn(e,n){return{type:e,props:{},key:void 0}}function Xn(e,n){if(!n||n==="/")return e||"/";let t=e.endsWith("/")?e.slice(0,-1):e,o=n.startsWith("/")?n:"/"+n;return t+o}function Jn(e){let n=[],t=e.replace(/:(\w+)/g,(o,i)=>(n.push(i),"([^/]+)")).replace(/\*/g,".*");return{re:new RegExp(`^${t}$`),keys:n}}function qe(e,n="",t=[]){let o=[];for(let i of e){let l=Xn(n,i.path),{re:s,keys:c}=Jn(l),d=[...t,i];o.push({re:s,keys:c,def:i,chain:d}),i.children&&o.push(...qe(i.children,l,d))}return o}function pn(e,n){let t=null;for(let o of n)e.match(o.re)&&(!t||o.chain.length>t.chain.length)&&(t=o);return t}function mn(e,n){let t={},o=e.match(n.re);if(o)for(let i=0;i<n.keys.length;i++)t[n.keys[i]]=Qn(o[i+1]);return t}function Qn(e){try{return decodeURIComponent(e)}catch{return e}}function Zn(e){let n=qe(e.routes),t=e.mode||"history";function o(){return t==="hash"?window.location.hash.replace(/^#/,"")||"/":window.location.pathname}function i(l){let s=pn(l,n);if(s){let c=s.chain[s.chain.length-1];return{path:s.def.path,params:mn(l,s),query:Object.fromEntries(new URLSearchParams(window.location.search)),chain:s.chain,title:c?.title??""}}return{path:l,params:{},query:Object.fromEntries(new URLSearchParams(window.location.search)),chain:e.notFound?[{component:e.notFound,title:"Not Found"}]:[],title:""}}return l=>{let s=a=>{a.ui?.bumpCtxVersion?.()},c=a=>{Z(),t==="hash"?(window.location.hash="#"+a,l.route=i(a)):(window.history.pushState({},"",a),l.route=i(a)),l.route?.title&&(document.title=l.route.title),s(l),l.ui?.render()};l.route=i(o()),l.route.title&&(document.title=l.route.title),l.app={navigate:c};let d=()=>{Z(),l.route=i(o()),l.route?.title&&(document.title=l.route.title),s(l),l.ui?.render()};return window.addEventListener("popstate",d),t==="hash"&&window.addEventListener("hashchange",d),l}}function et(e,n){let t=n.route?._rvDepth??0;return()=>{let o=n.route;if(!o?.chain?.length||t>=o.chain.length)return null;let i=o.chain[t],l=i.layout??i.component;return l?(i.layout&&(o._rvDepth=t+1),{type:l,props:{},key:void 0}):null}}function G(e,n){return Object.assign(Object.create(e),n)}function nt(e={}){let n=e.url??"/ws",t=e.reconnectInterval??3e3,o=e.maxReconnect??10,i=e.pingInterval??3e4,l=e.pingTimeout??1e4;return s=>{let c=new Set,d=null,a=0,g=null,m=null,b=null,C=!1,h={isConnected:!1,onMessage:p=>(c.add(p),()=>{c.delete(p)}),send:p=>{d?.readyState===WebSocket.OPEN&&d.send(JSON.stringify(p))},_connect:w,close:()=>{C=!0,f(),d?.close(),d=null,h.isConnected=!1}};async function w(){if(!C)try{d=new WebSocket(n),d.onopen=()=>{h.isConnected=!0,a=0,r()},d.onmessage=p=>{try{let y=JSON.parse(p.data);for(let v of c)v(y)}catch{}u()},d.onclose=()=>{h.isConnected=!1,f(),!C&&a<o&&(a++,g=setTimeout(w,t*Math.min(a,5)))},d.onerror=()=>{d?.close()}}catch{C||(g=setTimeout(w,t))}}function r(){i<=0||(m=setInterval(()=>{d?.readyState===WebSocket.OPEN&&d.send(JSON.stringify({type:"ping"})),b=setTimeout(()=>{d?.close()},l)},i))}function u(){clearTimeout(b)}function f(){clearInterval(m),clearTimeout(b),clearTimeout(g)}return w(),G(s,{ws:h})}}function tt(e){let n={baseURL:e?.baseURL??"",headers:{"Content-Type":"application/json",...e?.headers}},t=e?.onRequest,o=e?.onResponse,i=e?.timeout??0;async function l(s,c,d,a){let g=n.baseURL+c,m={method:s,headers:{...n.headers,...a?.headers}},b=e?.token?.();b&&!m.headers.Authorization&&(m.headers.Authorization=`Bearer ${b}`);let C=i>0,h=!!a?.signal,w=null,r=null;(C||h)&&(w=new AbortController,m.signal=w.signal,C&&(r=setTimeout(()=>w.abort(new Error("Request timed out")),i)),h&&a.signal.addEventListener("abort",()=>w.abort())),d!==void 0&&s!=="GET"&&s!=="HEAD"&&(m.body=JSON.stringify(d));let u={url:g,init:m};t&&(u=t(u));try{let f=await fetch(u.url,u.init);if(o)return o(f);if(!f.ok){let v=await f.text().catch(()=>"");throw new Ce(f.status,v||f.statusText)}let p=f.headers.get("content-length");if(f.status===204||p==="0")return;let y=(f.headers.get("content-type")||"").toLowerCase();return y.includes("application/json")||y.includes("json")?f.json():f.text()}finally{r&&clearTimeout(r)}}return s=>G(s,{api:{get:(d,a)=>l("GET",d,void 0,a),post:(d,a,g)=>l("POST",d,a,g),put:(d,a,g)=>l("PUT",d,a,g),patch:(d,a,g)=>l("PATCH",d,a,g),delete:(d,a)=>l("DELETE",d,void 0,a)}})}var Ce=class extends Error{status;body;constructor(n,t){super(`API Error ${n}: ${t}`),this.name="ApiError",this.status=n,this.body=t}};function ot(e){try{let n=e.split(".");if(n.length!==3)return null;let t=n[1].replace(/-/g,"+").replace(/_/g,"/");return JSON.parse(atob(t))}catch{return null}}function rt(e){let n=ot(e);return n?.exp?n.exp*1e3-3e4<Date.now():!0}function it(e){let n=e?.storage??localStorage,t=e?.tokenKey??"weifuwu_token",o=e?.userKey??"weifuwu_user",i=e?.refreshTokenKey??"weifuwu_refresh",l=e?.refreshEndpoint??"/api/auth/refresh";return s=>{let c=n.getItem(t),d=n.getItem(o),a={token:c,user:d?JSON.parse(d):null,get isLoggedIn(){return this.token!==null},login(g,m,b){a.token=g,a.user=m,n.setItem(t,g),n.setItem(o,JSON.stringify(m)),b&&n.setItem(i,b)},logout(){a.token=null,a.user=null,n.removeItem(t),n.removeItem(o),n.removeItem(i)},setUser(g){a.user=g,n.setItem(o,JSON.stringify(g))},async refresh(){let g=n.getItem(i);if(!g)return!1;try{let m=await fetch(l,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:g})});if(!m.ok)return a.logout(),!1;let b=await m.json();return a.token=b.token,n.setItem(t,b.token),b.refreshToken&&n.setItem(i,b.refreshToken),!0}catch{return!1}}};return c&&rt(c)&&a.refresh().catch(()=>{}),G(s,{auth:a})}}function st(e,n){let t=n.ui.$();return t.error=null,o=>{if(t.error){let s=o.fallback;return typeof s=="function"?s({error:t.error}):s??null}let i=n.ui;i._errorHandler=s=>{t.error=s};let l=o.children;try{return l??null}catch(s){t.error=s;let c=o.fallback;return typeof c=="function"?c({error:s}):c??null}}}var Fe={components:{Button:{loading:"\u52A0\u8F7D\u4E2D..."},FileUpload:{placeholder:"\u70B9\u51FB\u6216\u62D6\u62FD\u4E0A\u4F20\u6587\u4EF6",supportedFormats:"\u652F\u6301\u683C\u5F0F: ",maxSize:"\u6700\u5927 ",remove:"\u5220\u9664"},Pagination:{ariaLabel:"\u5206\u9875"},ProgressBar:{ariaLabel:"\u8FDB\u5EA6"},Switch:{ariaLabel:"\u5207\u6362"},Breadcrumb:{ariaLabel:"\u9762\u5305\u5C51"},Modal:{ariaLabel:"\u5F39\u7A97",closeAria:"\u5173\u95ED"},Confirm:{confirmText:"\u786E\u5B9A",cancelText:"\u53D6\u6D88"},Drawer:{ariaLabel:"\u4FA7\u8FB9\u9762\u677F",closeAria:"\u5173\u95ED"},DatePicker:{w0:"\u65E5",w1:"\u4E00",w2:"\u4E8C",w3:"\u4E09",w4:"\u56DB",w5:"\u4E94",w6:"\u516D",hour:"\u65F6",minute:"\u5206",time:"\u65F6\u95F4",confirm:"\u786E\u5B9A",cancel:"\u53D6\u6D88",placeholder:"\u9009\u62E9\u65E5\u671F"}}};var Be={components:{Button:{loading:"Loading..."},FileUpload:{placeholder:"Click or drag to upload",supportedFormats:"Supported formats: ",maxSize:"Max size: ",remove:"Remove"},Pagination:{ariaLabel:"Pagination"},ProgressBar:{ariaLabel:"Progress"},Switch:{ariaLabel:"Toggle"},Breadcrumb:{ariaLabel:"Breadcrumb"},Modal:{ariaLabel:"Dialog",closeAria:"Close"},Confirm:{confirmText:"OK",cancelText:"Cancel"},Drawer:{ariaLabel:"Panel",closeAria:"Close"},DatePicker:{w0:"Su",w1:"Mo",w2:"Tu",w3:"We",w4:"Th",w5:"Fr",w6:"Sa",hour:"Hour",minute:"Min",time:"Time",confirm:"OK",cancel:"Cancel",placeholder:"Pick a date"}}};var be={"zh-CN":Fe,"en-US":Be};function gn(e){if(be[e])return e;let n=e.split("-")[0];return Object.keys(be).find(o=>o.startsWith(n))??"zh-CN"}function lt(e={}){let{locale:n="zh-CN",messages:t={},components:o={}}=e,i=gn(n),l=be[i],s=yn(l,t,o),c={locale:i,t:(d,a)=>s.messages?.[d]??a??d,setLocale:()=>{},components:s.components};return d=>{let a=d;return a.i18n=c,c.setLocale=g=>{let m=gn(g),b=be[m];b&&(s=yn(b,t,o),c.locale=m,c.components=s.components,a.ui?.bumpCtxVersion?.(),a.ui?.render())},d}}function yn(e,n,t){return{messages:{...e?.messages,...n},components:at(e?.components??{},t)}}function at(e,n){let t={...e};for(let o of Object.keys(n))typeof n[o]=="object"&&n[o]!==null&&typeof t[o]=="object"?t[o]={...t[o],...n[o]}:t[o]=n[o];return t}function ut(e,n,t=400){let o=!1,i=()=>{o||(o=!0,e.removeEventListener("animationend",i),clearTimeout(l),n())};e.addEventListener("animationend",i);let l=setTimeout(i,t)}export{Ce as ApiError,st as ErrorBoundary,$ as Fragment,B as Portal,et as RouteView,De as aiStream,ut as animateOut,tt as api,Tn as asyncComponent,it as auth,W as callRefCleanup,Z as clearAsyncComponentCache,zn as computeFixedPos,ye as computeFixedPosRect,Gn as createApp,_e as createPortal,ge as createReactiveState,Be as enUS,G as extendCtx,Nn as h,Ie as hydrateVNode,lt as i18n,J as isAsyncComponent,Ne as jsx,Pn as jsxDEV,En as jsxs,He as lockScroll,In as mountVNode,z as patchValue,Zn as router,un as toChatMessages,me as trapFocus,Ue as unlockScroll,nt as ws,Fe as zhCN};
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* weifuwu/client 注册表 — 组件实例 ID 注册 + async 工厂缓存 + ref 清理
|
|
3
|
-
*
|
|
4
|
-
* 从 render.ts 拆出(P2 结构拆分):本文件无内部依赖(仅 vnode/types),
|
|
5
|
-
* render/diff/hydration/app 各模块共享同一实例状态。
|
|
6
|
-
* ⚠️ 模块状态共享约束:本文件必须保持单实例(dist 消费端由 build.mjs 外部化保证)。
|
|
7
|
-
*/
|
|
8
|
-
import type { VNode, Component, AsyncComponent } from './vnode.ts';
|
|
9
|
-
import type { WfuiContext } from './types.ts';
|
|
10
|
-
export declare const idRegistry: Map<string, VNode>;
|
|
11
|
-
type UnmountHook = (id: string) => void;
|
|
12
|
-
/**
|
|
13
|
-
* 注册组件卸载钩子(组件从 idRegistry 注销时触发,含 _customId)。
|
|
14
|
-
*
|
|
15
|
-
* 返回退订函数——组件级钩子(use* 原语)应在触发后自退订,
|
|
16
|
-
* 避免 _unmountHooks 数组随 mount 累积导致长期 SPA 内存增长 + unmount O(n) 退化。
|
|
17
|
-
* app 生命周期级钩子(app.mount 注册的 media/popup/scroll 清理)不退订(随 app 消亡)。
|
|
18
|
-
*/
|
|
19
|
-
export declare function onComponentUnmount(hook: UnmountHook): () => void;
|
|
20
|
-
/** test-only:返回当前注册的卸载钩子数(回归护栏——验证组件级钩子自退订不累积) */
|
|
21
|
-
export declare function __testHookCount(): number;
|
|
22
|
-
interface FactoryEntry {
|
|
23
|
-
promise: Promise<Component<any, any>>;
|
|
24
|
-
resolved?: Component<any, any>;
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* 清空 async 工厂缓存。
|
|
28
|
-
* 页面上下文切换时调用(路由导航/登录登出)——工厂内 ctx.data.get 的 key 依赖 ctx(如 route.params),
|
|
29
|
-
* 上下文变化后旧缓存定义的数据已失效,需要让工厂以新 ctx 重新执行。
|
|
30
|
-
*/
|
|
31
|
-
export declare function clearAsyncComponentCache(): void;
|
|
32
|
-
/** 启动 async 工厂(幂等,缓存):返回 entry,promise resolve 后 resolved 可用 */
|
|
33
|
-
export declare function startAsyncFactory(Comp: AsyncComponent, ctx: WfuiContext): FactoryEntry;
|
|
34
|
-
/** async 模式:await 工厂定义(初次渲染/服务端遍历/未来 hydration) */
|
|
35
|
-
export declare function resolveAsyncFactory(Comp: AsyncComponent, ctx: WfuiContext): Promise<Component>;
|
|
36
|
-
/** sync 模式:工厂已解析 → 定义;未解析 → undefined(占位 + 完成后整树重渲染) */
|
|
37
|
-
export declare function resolveAsyncFactorySync(Comp: AsyncComponent): Component | undefined;
|
|
38
|
-
/**
|
|
39
|
-
* 包裹 ref 回调调用——用户 ref 逻辑抛错时不中断渲染/卸载管线。
|
|
40
|
-
*
|
|
41
|
-
* ref 在渲染期外执行(mount 后/卸载时),语义上属用户逻辑 bug,不接 _errorHandler
|
|
42
|
-
* (ErrorBoundary 只覆盖渲染期错误)。console.error 暴露问题即可。
|
|
43
|
-
*/
|
|
44
|
-
export declare function safeCallRef(ref: Function, arg: any, phase: 'mount' | 'cleanup', name?: string): void;
|
|
45
|
-
/** 通知 ref 清理 + Portal 子容器清理 */
|
|
46
|
-
export declare function callRefCleanup(input: any): void;
|
|
47
|
-
/** 供 hydration/mount 路径生成新组件 ID(保持与 idRegistry 同源递增) */
|
|
48
|
-
export declare function nextComponentId(): string;
|
|
49
|
-
export {};
|