weifuwu 0.60.0 → 0.61.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.
Files changed (38) hide show
  1. package/README.md +23 -7
  2. package/dist/ai/agent.d.ts +29 -1
  3. package/dist/ai/client.d.ts +15 -0
  4. package/dist/ai/index.d.ts +2 -1
  5. package/dist/client/diff.d.ts +15 -0
  6. package/dist/client/hydration.d.ts +13 -0
  7. package/dist/client/index.d.ts +4 -0
  8. package/dist/client/index.js +3 -2214
  9. package/dist/client/middleware/api.d.ts +2 -0
  10. package/dist/client/motion.d.ts +8 -0
  11. package/dist/client/registry.d.ts +34 -0
  12. package/dist/client/render.d.ts +13 -14
  13. package/dist/client/types.d.ts +28 -0
  14. package/dist/client/ui.d.ts +56 -0
  15. package/dist/components/Badge/Badge.d.ts +1 -1
  16. package/dist/components/Button/Button.d.ts +3 -0
  17. package/dist/components/Card/Card.d.ts +2 -0
  18. package/dist/components/Confirm/Confirm.d.ts +8 -1
  19. package/dist/components/Dropdown/Dropdown.d.ts +2 -0
  20. package/dist/components/Icon/Icon.d.ts +19 -0
  21. package/dist/components/Input/Input.d.ts +5 -0
  22. package/dist/components/Modal/Modal.d.ts +2 -0
  23. package/dist/components/PageHeader/PageHeader.d.ts +2 -0
  24. package/dist/components/StatCard/StatCard.d.ts +2 -0
  25. package/dist/components/Table/Table.d.ts +4 -0
  26. package/dist/components/Toast/Toast.d.ts +13 -1
  27. package/dist/components/index.d.ts +2 -0
  28. package/dist/components/index.js +1 -3381
  29. package/dist/components/style.css +282 -134
  30. package/dist/core/router.d.ts +10 -10
  31. package/dist/core/serve.d.ts +1 -1
  32. package/dist/index.d.ts +3 -1
  33. package/dist/index.js +523 -11
  34. package/dist/layout/weifuwu-layout.css +106 -17
  35. package/dist/messager/index.d.ts +107 -0
  36. package/dist/types.d.ts +2 -2
  37. package/dist/user/index.d.ts +3 -2
  38. package/package.json +1 -1
@@ -23,6 +23,8 @@ export interface ApiOptions {
23
23
  baseURL?: string;
24
24
  /** 默认请求头 */
25
25
  headers?: Record<string, string>;
26
+ /** 动态鉴权 token:非空时自动加 `Authorization: Bearer <token>`(请求头未显式指定时) */
27
+ token?: () => string | null;
26
28
  /** 请求拦截器 */
27
29
  onRequest?: (req: {
28
30
  url: string;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * weifuwu/client — 动效工具
3
+ *
4
+ * animateOut:挂 --exit 类播退场动画,animationend 后回调。
5
+ * - reduced-motion 下动画时长被 _base.css 降为 0.01ms,animationend 立即触发,等效瞬时关闭
6
+ * - 兜底 timeout:类未命中动画(防御)或 animationend 丢失时不挂死
7
+ */
8
+ export declare function animateOut(el: HTMLElement, onDone: () => void, fallbackMs?: number): void;
@@ -0,0 +1,34 @@
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
+ /** 注册组件卸载钩子(组件从 idRegistry 注销时触发,含 _customId) */
13
+ export declare function onComponentUnmount(hook: UnmountHook): void;
14
+ interface FactoryEntry {
15
+ promise: Promise<Component<any, any>>;
16
+ resolved?: Component<any, any>;
17
+ }
18
+ /**
19
+ * 清空 async 工厂缓存。
20
+ * 页面上下文切换时调用(路由导航/登录登出)——工厂内 ctx.data.get 的 key 依赖 ctx(如 route.params),
21
+ * 上下文变化后旧缓存定义的数据已失效,需要让工厂以新 ctx 重新执行。
22
+ */
23
+ export declare function clearAsyncComponentCache(): void;
24
+ /** 启动 async 工厂(幂等,缓存):返回 entry,promise resolve 后 resolved 可用 */
25
+ export declare function startAsyncFactory(Comp: AsyncComponent, ctx: WfuiContext): FactoryEntry;
26
+ /** async 模式:await 工厂定义(初次渲染/服务端遍历/未来 hydration) */
27
+ export declare function resolveAsyncFactory(Comp: AsyncComponent, ctx: WfuiContext): Promise<Component>;
28
+ /** sync 模式:工厂已解析 → 定义;未解析 → undefined(占位 + 完成后整树重渲染) */
29
+ export declare function resolveAsyncFactorySync(Comp: AsyncComponent): Component | undefined;
30
+ /** 通知 ref 清理 + Portal 子容器清理 */
31
+ export declare function callRefCleanup(input: any): void;
32
+ /** 供 hydration/mount 路径生成新组件 ID(保持与 idRegistry 同源递增) */
33
+ export declare function nextComponentId(): string;
34
+ export {};
@@ -10,26 +10,25 @@
10
10
  *
11
11
  * 状态管理:组件使用闭包变量 + ctx.ui.render() 手动触发重渲染。
12
12
  */
13
- import type { VNode } from './vnode.ts';
13
+ import type { VNode, Component, AsyncComponent } from './vnode.ts';
14
14
  import type { WfuiContext } from './types.ts';
15
- export declare const idRegistry: Map<string, VNode>;
15
+ export declare const SVG_NS = "http://www.w3.org/2000/svg";
16
+ export declare const SVG_TAGS: Set<string>;
16
17
  export declare function render(input: any, ctx: WfuiContext): Node | null;
18
+ export declare function renderValue(v: any, ctx: WfuiContext): Node | null;
17
19
  /**
18
- * 清空 async 工厂缓存。
19
- * 页面上下文切换时调用(路由导航/登录登出)——工厂内 ctx.data.get 的 key 依赖 ctx(如 route.params),
20
- * 上下文变化后旧缓存定义的数据已失效,需要让工厂以新 ctx 重新执行。
20
+ * 同步 mount 组件(async 工厂占位策略):
21
+ * - 同步组件 → def(props, ctx) → render fn → 输出 VNode
22
+ * - async 工厂已解析 → 同同步组件
23
+ * - async 工厂未解析 → 占位(返回 null)+ 启动工厂 + 完成后整树重渲染
21
24
  */
22
- export declare function clearAsyncComponentCache(): void;
25
+ export declare function mountComponent(Comp: Component | AsyncComponent, props: any, vnode: VNode, ctx: WfuiContext): VNode | null;
23
26
  /** 首次渲染 Portal:创建远程容器、渲染子节点(不返回占位节点) */
24
27
  export declare function renderPortal(vnode: VNode, ctx: WfuiContext): void;
25
28
  /** 更新 Portal:复用远程容器,patch 子节点(不操作父 DOM) */
26
29
  export declare function patchPortal(oldV: VNode | null, newV: VNode, ctx: WfuiContext): void;
27
- export declare function patchValue(parent: Node, oldNode: Node | null, oldInput: any, newInput: any, ctx: WfuiContext): Node | null;
28
- /** 通知 ref 清理 + Portal 子容器清理 */
29
- export declare function callRefCleanup(input: any): void;
30
+ /** 展平嵌套数组 */
31
+ export declare function flattenChildren(children: any): any[];
30
32
  export declare function mountVNode(container: Element, vnode: VNode, ctx: WfuiContext): void;
31
- /**
32
- * Hydration 挂载入口:收养 container 内现有服务端 HTML。
33
- * 渲染完收尾:删除服务端有、客户端没有的残留 DOM。
34
- */
35
- export declare function hydrateVNode(container: Element, vnode: VNode, ctx: WfuiContext): Promise<void>;
33
+ export { callRefCleanup, idRegistry, clearAsyncComponentCache, nextComponentId } from './registry.ts';
34
+ export { patchValue } from './diff.ts';
@@ -15,6 +15,13 @@ export interface PopupPositionOptions {
15
15
  width?: number;
16
16
  };
17
17
  }
18
+ /** 异步取数工具返回值 — ctx.ui.useAsync()(data/loading/error 响应式,reload 重跑) */
19
+ export interface UseAsyncHandle<T = any> {
20
+ data?: T;
21
+ loading: boolean;
22
+ error?: unknown;
23
+ reload: () => void;
24
+ }
18
25
  /** 弹层位置跟踪器 — usePopupPosition 的返回值 */
19
26
  export interface PopupPosition {
20
27
  top: number;
@@ -44,8 +51,22 @@ export interface WfuiContext {
44
51
  * ```
45
52
  */
46
53
  useChat: (options: UseChatOptions) => UseChatHandle;
54
+ /** 响应式媒体查询:注册监听,值变化时自动 dirty(立即回调一次当前值) */
55
+ useMedia: (query: string, callback: (matches: boolean) => void) => void;
56
+ /** 响应式断点:mobile/tablet/desktop 或自定义断点,值变化时自动 dirty */
57
+ useBreakpoint: (bpsOrCallback: Record<string, string> | ((vp: string) => void), callback?: (vp: string) => void) => void;
47
58
  /** 弹层位置跟踪:滚动/resize 时自动重算 fixed 坐标 */
48
59
  usePopupPosition: (options: PopupPositionOptions) => PopupPosition;
60
+ /**
61
+ * 异步取数工具(mount 阶段调用):loading/error 自动管理 + 数据就绪自动渲染。
62
+ *
63
+ * ```tsx
64
+ * const list = ctx.ui.useAsync(() => ctx.api.get<User[]>('/users'))
65
+ * return () => list.loading ? h(Loading) : list.data?.map(...)
66
+ * ```
67
+ * data/loading/error 响应式;reload() 重跑;组件卸载后旧 Promise resolve 不再触发渲染。
68
+ */
69
+ useAsync: <T = any>(fetcher: () => Promise<T>) => UseAsyncHandle<T>;
49
70
  /** 注册组件实例的自定义语义 ID,同名冲突抛错 */
50
71
  selfId: (name: string) => void;
51
72
  /** 当前组件实例 ID(仅供内部使用,通过 ctx 扩展注入) */
@@ -107,6 +128,13 @@ export interface WfuiContext {
107
128
  logout: () => void;
108
129
  [key: string]: any;
109
130
  };
131
+ /** 命令式确认(由 components 的 confirm() 中间件注入):ctx.confirm(msg) → Promise<boolean> */
132
+ confirm?: (message: string, options?: Record<string, any>) => Promise<boolean>;
133
+ /** 命令式轻提示(由 components 的 toast() 中间件注入):ctx.toast(msg, type?, duration?, action?) */
134
+ toast?: (message: string, type?: string, duration?: number, action?: {
135
+ label: string;
136
+ onClick: () => void;
137
+ }) => void;
110
138
  }
111
139
  /** 中间件签名 */
112
140
  /**
@@ -0,0 +1,56 @@
1
+ /**
2
+ * weifuwu/client ctx.ui 工厂 — createApp 注入的 UI 能力
3
+ *
4
+ * 从 app.ts 拆出(P2 结构拆分)。createUi(deps) 返回完整 ui 对象:
5
+ * render / dirty / $ / useChat / useMedia / useBreakpoint / usePopupPosition / selfId
6
+ *
7
+ * 内部状态(_selfId/_selfVNode/_dirtySet/_ctxVersion)集中建模为 UiInternal,
8
+ * 消除 app.ts 中散落的 `as any`——跨模块状态误用由编译器拦截。
9
+ */
10
+ import type { WfuiContext, PopupPosition } from './types.ts';
11
+ import type { VNode } from './vnode.ts';
12
+ /** 内部 UI 状态(ctx.ui 扩展字段)——跨模块共享,编译器可检查 */
13
+ export interface UiInternal {
14
+ _selfId?: string;
15
+ _selfVNode?: VNode;
16
+ _dirtySet: Set<string>;
17
+ _ctxVersion: number;
18
+ bumpCtxVersion(): void;
19
+ /** 异步批处理调度标记(dirty 微任务防重入) */
20
+ _dirtyScheduled?: boolean;
21
+ /** ctx.ui.$() 的 WeakMap 缓存(每组件一个 $ 容器) */
22
+ _$cache?: Record<string, any>;
23
+ }
24
+ /** createUi 依赖(由 createApp 注入 app 级闭包状态) */
25
+ export interface UiDeps {
26
+ ctx: WfuiContext;
27
+ renderByIds: (ids: string[]) => void;
28
+ getSelfId: (ui: any) => string | undefined;
29
+ dirtyBatch: Set<string>;
30
+ dirtySet: Set<string>;
31
+ mediaRegistry: Map<string, {
32
+ mql?: MediaQueryList;
33
+ handler?: (e: MediaQueryListEvent) => void;
34
+ mqls?: Array<{
35
+ mql: MediaQueryList;
36
+ handler: () => void;
37
+ }>;
38
+ }>;
39
+ popupTrackers: Map<string, {
40
+ pos: PopupPosition;
41
+ getEl: () => HTMLElement | null;
42
+ isOpen: () => boolean;
43
+ compute: (rect: DOMRect) => {
44
+ top: number;
45
+ left: number;
46
+ width?: number;
47
+ };
48
+ }>;
49
+ schedulePopupRecompute: () => void;
50
+ /** 惰性挂载全局 scroll/resize 监听(幂等) */
51
+ ensurePopupListeners: () => void;
52
+ destroyPopupListeners: () => void;
53
+ /** 渲染保护期(dirty 被忽略) */
54
+ isRendering: () => boolean;
55
+ }
56
+ export declare function createUi(deps: UiDeps): WfuiContext['ui'] & UiInternal;
@@ -1,5 +1,5 @@
1
1
  import type { Component } from '../../client/vnode.ts';
2
- export type BadgeVariant = 'default' | 'primary' | 'success' | 'warning' | 'danger' | 'info';
2
+ export type BadgeVariant = 'default' | 'primary' | 'success' | 'warning' | 'danger' | 'info' | 'error';
3
3
  export interface BadgeProps {
4
4
  variant?: BadgeVariant;
5
5
  dot?: boolean;
@@ -6,6 +6,9 @@ export interface ButtonProps {
6
6
  loading?: boolean;
7
7
  disabled?: boolean;
8
8
  type?: 'button' | 'submit';
9
+ title?: string;
10
+ /** 透传原生 class(覆盖默认 wf-btn 组合) */
11
+ class?: string;
9
12
  onClick?: (e: MouseEvent) => void;
10
13
  children?: any;
11
14
  }
@@ -1,6 +1,8 @@
1
1
  import type { Component } from '../../client/vnode.ts';
2
2
  export interface CardProps {
3
3
  variant?: 'default' | 'outlined';
4
+ /** 便捷:outlined = variant 'outlined' */
5
+ outlined?: boolean;
4
6
  padding?: 'sm' | 'md' | 'lg';
5
7
  clickable?: boolean;
6
8
  /** hover 抬升(阴影 + 上移),适合可点击/可悬停的卡片 */
@@ -16,6 +16,8 @@ export interface ConfirmProps {
16
16
  variant?: 'primary' | 'danger';
17
17
  /** 对话框宽度,如 '500px'、'80%',默认 Modal 的 400px */
18
18
  width?: string;
19
+ /** 遮罩点击是否取消(默认 false:危险操作防误触;显式传 true 可恢复) */
20
+ maskClosable?: boolean;
19
21
  onConfirm?: () => void;
20
22
  onCancel?: () => void;
21
23
  }
@@ -26,6 +28,11 @@ export interface ConfirmOptions {
26
28
  cancelText?: string;
27
29
  variant?: 'primary' | 'danger';
28
30
  width?: string;
31
+ maskClosable?: boolean;
32
+ }
33
+ /** 命令式 ctx.confirm 的注入类型(AppMiddleware<{}, ConfirmInjected>) */
34
+ export interface ConfirmInjected {
35
+ confirm: (message: string, options?: ConfirmOptions) => Promise<boolean>;
29
36
  }
30
37
  /**
31
38
  * 命令式中间件:注入 ctx.confirm()
@@ -33,5 +40,5 @@ export interface ConfirmOptions {
33
40
  * 每次调用挂载 Confirm 组件到独立容器(mountVNode),
34
41
  * resolve 后 callRefCleanup 清理(含 Modal 的 portal DOM)+ 移除容器。
35
42
  */
36
- export declare function confirm(): AppMiddleware;
43
+ export declare function confirm(): AppMiddleware<{}, ConfirmInjected>;
37
44
  export declare const Confirm: Component<ConfirmProps>;
@@ -13,5 +13,7 @@ export interface DropdownProps {
13
13
  trigger: any;
14
14
  items?: DropdownItem[];
15
15
  open?: boolean;
16
+ /** 关闭回调(面板内 Escape) */
17
+ onOpenChange?: (open: boolean) => void;
16
18
  }
17
19
  export declare const Dropdown: Component<DropdownProps>;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * weifuwu/components — Icon 内联 SVG 图标
3
+ *
4
+ * 24px stroke 风格(feather-like),currentColor 着色随文字/上下文,
5
+ * 零外部依赖(FS-05)。组件内部图标统一走这里,替换文本字形/emoji。
6
+ *
7
+ * 用法:
8
+ * h(Icon, { name: 'close' })
9
+ * h(Icon, { name: 'check', size: 16 })
10
+ */
11
+ import type { Component } from '../../client/vnode.ts';
12
+ export type IconName = 'chevron-down' | 'chevron-up' | 'chevron-left' | 'chevron-right' | 'arrow-left' | 'arrow-up' | 'arrow-down' | 'sort' | 'sort-asc' | 'sort-desc' | 'check' | 'close' | 'alert' | 'info' | 'warning' | 'pause' | 'settings' | 'search' | 'send' | 'stop' | 'retry' | 'upload' | 'trash' | 'edit' | 'plus';
13
+ export interface IconProps {
14
+ name: IconName;
15
+ /** 尺寸,默认 1em(随字号缩放) */
16
+ size?: number | string;
17
+ className?: string;
18
+ }
19
+ export declare const Icon: Component<IconProps>;
@@ -13,5 +13,10 @@ export interface InputProps {
13
13
  variant?: 'default' | 'borderless';
14
14
  onInput?: (e: Event) => void;
15
15
  onChange?: (e: Event) => void;
16
+ /** 原生 input 属性透传(type=number 时 min/max/step 等) */
17
+ min?: string | number;
18
+ max?: string | number;
19
+ step?: string | number;
20
+ [key: string]: any;
16
21
  }
17
22
  export declare const Input: Component<InputProps>;
@@ -12,5 +12,7 @@ export interface ModalProps {
12
12
  width?: string;
13
13
  /** 是否显示关闭按钮,默认 true */
14
14
  closable?: boolean;
15
+ /** 点击遮罩是否关闭,默认 true(危险确认应设 false) */
16
+ maskClosable?: boolean;
15
17
  }
16
18
  export declare const Modal: Component<ModalProps>;
@@ -2,6 +2,8 @@ import type { Component } from '../../client/vnode.ts';
2
2
  export interface PageHeaderProps {
3
3
  title: string;
4
4
  sub?: string;
5
+ /** 顶级页面大标题(display 档 30px),默认 21px */
6
+ display?: boolean;
5
7
  children?: any;
6
8
  }
7
9
  export declare const PageHeader: Component<PageHeaderProps>;
@@ -7,5 +7,7 @@ export interface StatCardProps {
7
7
  icon?: string;
8
8
  /** 点击跳转/交互(悬停抬升 + role=button) */
9
9
  onClick?: () => void;
10
+ /** 数字从 0 递增动画(reduced-motion 下直接终值),仅数值类型生效 */
11
+ animate?: boolean;
10
12
  }
11
13
  export declare const StatCard: Component<StatCardProps>;
@@ -24,5 +24,9 @@ export interface TableProps {
24
24
  emptyText?: string;
25
25
  /** 表格最小宽度(窄屏横向滚动,如 '720px') */
26
26
  minWidth?: string;
27
+ /** 加载中:保留表头,渲染骨架行 */
28
+ loading?: boolean;
29
+ /** 骨架行数,默认 3 */
30
+ loadingRows?: number;
27
31
  }
28
32
  export declare const Table: Component<TableProps>;
@@ -8,6 +8,11 @@ export interface ToastItem {
8
8
  message: string;
9
9
  /** 此条目的自动消失时间(ms),覆盖 Toast 的默认 duration */
10
10
  duration?: number;
11
+ /** 操作按钮(如"撤销"):点击不自动关闭,由回调自行移除 */
12
+ action?: {
13
+ label: string;
14
+ onClick: () => void;
15
+ };
11
16
  }
12
17
  export interface ToastProps {
13
18
  toasts?: ToastItem[];
@@ -28,4 +33,11 @@ export interface ToastOptions {
28
33
  max?: number;
29
34
  }
30
35
  export declare const Toast: Component<ToastProps>;
31
- export declare function toast(opts?: ToastOptions): AppMiddleware;
36
+ /** 命令式 ctx.toast 的注入类型(AppMiddleware<{}, ToastInjected>) */
37
+ export interface ToastInjected {
38
+ toast: (message: string, type?: ToastType, duration?: number, action?: {
39
+ label: string;
40
+ onClick: () => void;
41
+ }) => void;
42
+ }
43
+ export declare function toast(opts?: ToastOptions): AppMiddleware<{}, ToastInjected>;
@@ -5,6 +5,8 @@
5
5
  * import { Button, Input } from 'weifuwu/components'
6
6
  * import 'weifuwu/components/style.css'
7
7
  */
8
+ export { Icon } from './Icon/Icon.ts';
9
+ export type { IconProps, IconName } from './Icon/Icon.ts';
8
10
  export { Button } from './Button/Button.ts';
9
11
  export type { ButtonProps } from './Button/Button.ts';
10
12
  export { Input } from './Input/Input.ts';