weifuwu 0.87.0 → 0.89.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 (392) hide show
  1. package/README.md +111 -135
  2. package/dist/client/components/ActionSheet/ActionSheet.d.ts +1 -1
  3. package/dist/client/components/AiChat/AiChat.d.ts +3 -4
  4. package/dist/client/components/ChatInput/ChatInput.d.ts +5 -0
  5. package/dist/client/components/CitationCard/CitationCard.d.ts +1 -1
  6. package/dist/client/components/Command/Command.d.ts +1 -1
  7. package/dist/client/components/ContextMenu/ContextMenu.d.ts +1 -1
  8. package/dist/client/components/DatePicker/DatePicker.d.ts +1 -1
  9. package/dist/client/components/Dropdown/Dropdown.d.ts +1 -1
  10. package/dist/client/components/Editor/model/html.d.ts +10 -0
  11. package/dist/client/components/ImageCropper/ImageCropper.d.ts +6 -2
  12. package/dist/client/components/Menu/Menu.d.ts +1 -1
  13. package/dist/client/components/NavMenu/NavMenu.d.ts +1 -1
  14. package/dist/client/components/Popconfirm/Popconfirm.d.ts +1 -1
  15. package/dist/client/components/SlideCanvas/SlideCanvas.d.ts +1 -1
  16. package/dist/client/components/Tour/Tour.d.ts +1 -1
  17. package/dist/client/components/TreeSelect/TreeSelect.d.ts +1 -1
  18. package/dist/client/components/index.js +41 -41
  19. package/dist/client/components/style.css +298 -644
  20. package/dist/client/layout/weifuwu-layout.css +286 -640
  21. package/dist/client/vdom/browser/Browser.d.ts +2 -0
  22. package/dist/client/vdom/commands.d.ts +4 -1
  23. package/dist/client/vdom/context/UIContext.d.ts +8 -0
  24. package/dist/client/vdom/core/diff/attrs.d.ts +10 -2
  25. package/dist/client/vdom/core/field/attributes.d.ts +12 -0
  26. package/dist/client/vdom/core/field/events.d.ts +8 -0
  27. package/dist/client/vdom/core/field/input-sync.d.ts +14 -0
  28. package/dist/client/vdom/core/field/key.d.ts +3 -0
  29. package/dist/client/vdom/core/field/props.d.ts +13 -1
  30. package/dist/client/vdom/core/field/ref.d.ts +6 -0
  31. package/dist/client/vdom/core/field/style.d.ts +7 -1
  32. package/dist/client/vdom/core/node/component.d.ts +3 -4
  33. package/dist/client/vdom/core/node/native.d.ts +6 -1
  34. package/dist/client/vdom/core/patch/index.d.ts +24 -1
  35. package/dist/client/vdom/core/patch/processors.d.ts +8 -1
  36. package/dist/client/vdom/core/protocol.d.ts +45 -0
  37. package/dist/client/vdom/core/router.d.ts +7 -0
  38. package/dist/client/vdom/core/ssr/absorb.d.ts +31 -4
  39. package/dist/client/vdom/core/transform/index.d.ts +6 -6
  40. package/dist/client/vdom/core/v2/cycle.d.ts +54 -0
  41. package/dist/client/vdom/core/v2/diff.d.ts +80 -0
  42. package/dist/client/vdom/core/v2/integrate.d.ts +24 -0
  43. package/dist/client/vdom/core/v2/render.d.ts +28 -0
  44. package/dist/client/vdom/core/v2/schedule.d.ts +33 -0
  45. package/dist/client/vdom/core/v2/serve.d.ts +4 -0
  46. package/dist/client/vdom/core/v2/spy.d.ts +21 -0
  47. package/dist/client/vdom/core/v2/ssr.d.ts +14 -0
  48. package/dist/client/vdom/core/vnode.d.ts +9 -6
  49. package/dist/client/vdom/dev/error-counter.d.ts +27 -0
  50. package/dist/client/vdom/dev/render-health.d.ts +60 -0
  51. package/dist/client/vdom/hooks/chat.d.ts +32 -5
  52. package/dist/client/vdom/hooks/drag-media.d.ts +3 -1
  53. package/dist/client/vdom/hooks/env.d.ts +32 -0
  54. package/dist/client/vdom/hooks/popup-manager.d.ts +21 -0
  55. package/dist/client/vdom/hooks/popup.d.ts +4 -1
  56. package/dist/client/vdom/hooks/stable.d.ts +4 -0
  57. package/dist/client/vdom/hooks/use-observable.d.ts +13 -0
  58. package/dist/client/vdom/index.d.ts +14 -6
  59. package/dist/client/vdom/index.js +4 -7
  60. package/dist/client/vdom/jsx-runtime.js +1 -1
  61. package/dist/client/vdom/middlewares/api.d.ts +8 -0
  62. package/dist/client/vdom/middlewares/auth-i18n.d.ts +7 -0
  63. package/dist/client/vdom/middlewares/ws.d.ts +41 -1
  64. package/dist/client/vdom/observable/index.d.ts +13 -0
  65. package/dist/client/vdom/observable/observable.d.ts +26 -0
  66. package/dist/client/vdom/observable/operators.d.ts +76 -0
  67. package/dist/client/vdom/observable/sources.d.ts +54 -0
  68. package/dist/client/vdom/observable/types.d.ts +45 -0
  69. package/dist/client/vdom/store.d.ts +17 -2
  70. package/dist/client/vdom/testing.js +2 -2
  71. package/dist/server/ai/agent.d.ts +18 -0
  72. package/dist/server/ai/client.d.ts +14 -2
  73. package/dist/server/ai/contracts.d.ts +2 -2
  74. package/dist/server/ai/sse.d.ts +6 -0
  75. package/dist/server/core/collect.d.ts +31 -0
  76. package/dist/server/core/error-counter.d.ts +11 -0
  77. package/dist/server/core/hub.d.ts +2 -0
  78. package/dist/server/core/router.d.ts +12 -9
  79. package/dist/server/db/contracts.d.ts +24 -0
  80. package/dist/server/db/memory-redis.d.ts +3 -4
  81. package/dist/server/db/memory-sql.d.ts +20 -4
  82. package/dist/server/db/postgres-server.d.ts +2 -0
  83. package/dist/server/db/query.d.ts +21 -0
  84. package/dist/server/db/redis-server.d.ts +4 -2
  85. package/dist/server/db/sql-parser.d.ts +2 -1
  86. package/dist/server/email/index.d.ts +2 -0
  87. package/dist/server/index.d.ts +4 -1
  88. package/dist/server/index.js +3927 -1982
  89. package/dist/server/messager/index.d.ts +21 -2
  90. package/dist/server/middleware/compress.d.ts +25 -0
  91. package/dist/server/ui/index.d.ts +8 -1
  92. package/dist/server/user/index.d.ts +4 -0
  93. package/dist/shared/router/chain.d.ts +9 -0
  94. package/dist/shared/router/context.d.ts +35 -0
  95. package/dist/shared/router/ctx-fields.d.ts +20 -0
  96. package/dist/shared/router/pipeline.d.ts +70 -0
  97. package/dist/shared/router/trie.d.ts +11 -3
  98. package/dist/shared/router/types.d.ts +23 -0
  99. package/docs/style-guide.md +44 -41
  100. package/package.json +13 -10
  101. package/content/apps/admin.md +0 -55
  102. package/content/apps/agent-platform.md +0 -35
  103. package/content/apps/auth.md +0 -49
  104. package/content/apps/multi.md +0 -44
  105. package/content/apps/todo.md +0 -51
  106. package/content/backend/ai.md +0 -28
  107. package/content/backend/auth.md +0 -20
  108. package/content/backend/email.md +0 -23
  109. package/content/backend/graphql.md +0 -23
  110. package/content/backend/http.md +0 -23
  111. package/content/backend/limit.md +0 -23
  112. package/content/backend/middleware.md +0 -17
  113. package/content/backend/queue.md +0 -23
  114. package/content/backend/redis.md +0 -26
  115. package/content/backend/router.md +0 -23
  116. package/content/backend/schedule.md +0 -23
  117. package/content/backend/sql.md +0 -27
  118. package/content/backend/sse.md +0 -26
  119. package/content/backend/ws.md +0 -26
  120. package/content/capabilities/app-node.md +0 -21
  121. package/content/capabilities/data.md +0 -21
  122. package/content/capabilities/events.md +0 -21
  123. package/content/capabilities/hooks.md +0 -22
  124. package/content/capabilities/i18n.md +0 -21
  125. package/content/capabilities/popup.md +0 -21
  126. package/content/capabilities/render-only.md +0 -23
  127. package/content/capabilities/router.md +0 -22
  128. package/content/capabilities/self-id.md +0 -21
  129. package/content/capabilities/store.md +0 -21
  130. package/content/capabilities/theme.md +0 -21
  131. package/content/capabilities/two-phase.md +0 -21
  132. package/content/components/accordion.md +0 -50
  133. package/content/components/actionsheet.md +0 -46
  134. package/content/components/affix.md +0 -51
  135. package/content/components/aichat.md +0 -57
  136. package/content/components/alert.md +0 -52
  137. package/content/components/alertgroup.md +0 -45
  138. package/content/components/anchor.md +0 -52
  139. package/content/components/app.md +0 -37
  140. package/content/components/approvalcard.md +0 -56
  141. package/content/components/appshell.md +0 -50
  142. package/content/components/aspectratio.md +0 -47
  143. package/content/components/authpage.md +0 -61
  144. package/content/components/autocomplete-v2.md +0 -40
  145. package/content/components/autocomplete.md +0 -56
  146. package/content/components/avatar.md +0 -51
  147. package/content/components/avatargroup.md +0 -47
  148. package/content/components/backtop.md +0 -53
  149. package/content/components/badge.md +0 -55
  150. package/content/components/breadcrumb.md +0 -49
  151. package/content/components/button.md +0 -63
  152. package/content/components/calendar-v2.md +0 -40
  153. package/content/components/calendar.md +0 -50
  154. package/content/components/card.md +0 -58
  155. package/content/components/carousel.md +0 -52
  156. package/content/components/cascader-v2.md +0 -39
  157. package/content/components/cascader.md +0 -54
  158. package/content/components/chart.md +0 -53
  159. package/content/components/chatinput.md +0 -63
  160. package/content/components/checkbox.md +0 -51
  161. package/content/components/checkboxgroup.md +0 -52
  162. package/content/components/citationcard.md +0 -48
  163. package/content/components/codeblock.md +0 -48
  164. package/content/components/codeeditor.md +0 -47
  165. package/content/components/collapse.md +0 -49
  166. package/content/components/colorpicker.md +0 -50
  167. package/content/components/command.md +0 -50
  168. package/content/components/confirm.md +0 -57
  169. package/content/components/contextmenu.md +0 -48
  170. package/content/components/copybutton.md +0 -51
  171. package/content/components/datepicker.md +0 -52
  172. package/content/components/descriptions-v2.md +0 -39
  173. package/content/components/descriptions.md +0 -52
  174. package/content/components/diffview-v2.md +0 -39
  175. package/content/components/diffview.md +0 -50
  176. package/content/components/divider.md +0 -48
  177. package/content/components/drawer.md +0 -55
  178. package/content/components/dropdown.md +0 -53
  179. package/content/components/editor.md +0 -49
  180. package/content/components/emptystate.md +0 -51
  181. package/content/components/exportcsv.md +0 -38
  182. package/content/components/field.md +0 -54
  183. package/content/components/filepreview-office.md +0 -37
  184. package/content/components/filepreview.md +0 -49
  185. package/content/components/filetree.md +0 -56
  186. package/content/components/fileupload-v2.md +0 -39
  187. package/content/components/fileupload.md +0 -57
  188. package/content/components/floatbutton.md +0 -52
  189. package/content/components/form-v2.md +0 -41
  190. package/content/components/form.md +0 -60
  191. package/content/components/grid.md +0 -51
  192. package/content/components/highlight-v2.md +0 -39
  193. package/content/components/highlight.md +0 -46
  194. package/content/components/hovercard.md +0 -51
  195. package/content/components/icon.md +0 -50
  196. package/content/components/imagecropper.md +0 -45
  197. package/content/components/img.md +0 -56
  198. package/content/components/infinitescroll-v2.md +0 -40
  199. package/content/components/infinitescroll.md +0 -54
  200. package/content/components/input.md +0 -65
  201. package/content/components/inputnumber.md +0 -58
  202. package/content/components/inview.md +0 -56
  203. package/content/components/jsonschemaform.md +0 -53
  204. package/content/components/jsonviewer-v2.md +0 -39
  205. package/content/components/jsonviewer.md +0 -49
  206. package/content/components/kanban.md +0 -46
  207. package/content/components/label.md +0 -48
  208. package/content/components/layout.md +0 -54
  209. package/content/components/layoutcontent.md +0 -43
  210. package/content/components/layoutheader.md +0 -43
  211. package/content/components/layoutsider.md +0 -43
  212. package/content/components/link.md +0 -52
  213. package/content/components/list.md +0 -44
  214. package/content/components/loading.md +0 -45
  215. package/content/components/logviewer-v2.md +0 -39
  216. package/content/components/logviewer.md +0 -53
  217. package/content/components/markdown.md +0 -51
  218. package/content/components/markdowneditor.md +0 -47
  219. package/content/components/math.md +0 -42
  220. package/content/components/mentions-v2.md +0 -39
  221. package/content/components/mentions.md +0 -52
  222. package/content/components/menu.md +0 -56
  223. package/content/components/menubar.md +0 -44
  224. package/content/components/messagebubble.md +0 -50
  225. package/content/components/modal.md +0 -59
  226. package/content/components/navmenu.md +0 -47
  227. package/content/components/notification.md +0 -51
  228. package/content/components/pageheader.md +0 -53
  229. package/content/components/pagination.md +0 -49
  230. package/content/components/paragraph.md +0 -45
  231. package/content/components/passwordinput.md +0 -57
  232. package/content/components/pininput-v2.md +0 -39
  233. package/content/components/pininput.md +0 -50
  234. package/content/components/pipeline.md +0 -49
  235. package/content/components/popconfirm.md +0 -58
  236. package/content/components/popover.md +0 -61
  237. package/content/components/progressbar.md +0 -50
  238. package/content/components/prompttemplate.md +0 -49
  239. package/content/components/qrcode.md +0 -50
  240. package/content/components/radiogroup.md +0 -53
  241. package/content/components/rate.md +0 -53
  242. package/content/components/reasoningblock.md +0 -47
  243. package/content/components/relationgraph.md +0 -52
  244. package/content/components/resizable.md +0 -53
  245. package/content/components/result.md +0 -49
  246. package/content/components/scrollbar.md +0 -49
  247. package/content/components/searchinput.md +0 -51
  248. package/content/components/segmentedcontrol.md +0 -59
  249. package/content/components/select-searchable.md +0 -47
  250. package/content/components/select.md +0 -66
  251. package/content/components/sessionlist.md +0 -52
  252. package/content/components/sheetgrid.md +0 -44
  253. package/content/components/skeleton.md +0 -55
  254. package/content/components/slidecanvas.md +0 -44
  255. package/content/components/slider.md +0 -62
  256. package/content/components/sortablelist.md +0 -39
  257. package/content/components/space.md +0 -52
  258. package/content/components/sparkline.md +0 -52
  259. package/content/components/statcard-countdown.md +0 -39
  260. package/content/components/statcard.md +0 -56
  261. package/content/components/steps.md +0 -48
  262. package/content/components/switch.md +0 -50
  263. package/content/components/tabbar.md +0 -45
  264. package/content/components/table-v2.md +0 -40
  265. package/content/components/table.md +0 -66
  266. package/content/components/tabs.md +0 -56
  267. package/content/components/tag.md +0 -51
  268. package/content/components/tagsinput-v2.md +0 -39
  269. package/content/components/tagsinput.md +0 -54
  270. package/content/components/text.md +0 -45
  271. package/content/components/textarea.md +0 -57
  272. package/content/components/themeswitch.md +0 -69
  273. package/content/components/timeline.md +0 -50
  274. package/content/components/title.md +0 -45
  275. package/content/components/toast.md +0 -52
  276. package/content/components/toggle-togglegroup.md +0 -52
  277. package/content/components/togglegroup.md +0 -47
  278. package/content/components/toolcallcard.md +0 -51
  279. package/content/components/tooltip.md +0 -50
  280. package/content/components/tour.md +0 -50
  281. package/content/components/transfer.md +0 -52
  282. package/content/components/tree-v2.md +0 -39
  283. package/content/components/tree.md +0 -59
  284. package/content/components/treeselect.md +0 -54
  285. package/content/components/typography.md +0 -51
  286. package/content/components/videoplayer.md +0 -52
  287. package/content/components/virtuallist.md +0 -52
  288. package/content/components/virtualtable-v2.md +0 -39
  289. package/content/components/virtualtable.md +0 -55
  290. package/content/components/watermark.md +0 -53
  291. package/content/components/wave.md +0 -43
  292. package/content/guides/ai-chat-family.md +0 -24
  293. package/content/guides/choose.md +0 -67
  294. package/content/guides/component-model.md +0 -32
  295. package/content/guides/component-standards.md +0 -123
  296. package/content/guides/components-guide.md +0 -813
  297. package/content/guides/custom-component.md +0 -321
  298. package/content/guides/data-guide.md +0 -281
  299. package/content/guides/file-preview-family.md +0 -18
  300. package/content/guides/frontend.md +0 -968
  301. package/content/guides/layout-choice.md +0 -64
  302. package/content/guides/layout-guide.md +0 -241
  303. package/content/guides/middleware.md +0 -459
  304. package/content/guides/mobile-guide.md +0 -105
  305. package/content/guides/page-building.md +0 -98
  306. package/content/guides/production.md +0 -37
  307. package/content/guides/quality.md +0 -60
  308. package/content/guides/realtime-guide.md +0 -296
  309. package/content/guides/render-only.md +0 -44
  310. package/content/guides/saas-guide.md +0 -253
  311. package/content/guides/server-guide.md +0 -359
  312. package/content/guides/start.md +0 -41
  313. package/content/guides/styling.md +0 -154
  314. package/content/guides/ui-dom-guide.md +0 -157
  315. package/content/index.json +0 -4344
  316. package/content/index.md +0 -181
  317. package/content/layout/align.md +0 -20
  318. package/content/layout/anchor.md +0 -19
  319. package/content/layout/app-shell.md +0 -23
  320. package/content/layout/border.md +0 -20
  321. package/content/layout/center.md +0 -19
  322. package/content/layout/cluster.md +0 -19
  323. package/content/layout/container.md +0 -19
  324. package/content/layout/fill.md +0 -19
  325. package/content/layout/grid.md +0 -19
  326. package/content/layout/hidden.md +0 -22
  327. package/content/layout/layer.md +0 -19
  328. package/content/layout/position.md +0 -22
  329. package/content/layout/row.md +0 -23
  330. package/content/layout/safe-area.md +0 -20
  331. package/content/layout/scroll.md +0 -21
  332. package/content/layout/spacing.md +0 -22
  333. package/content/layout/split.md +0 -19
  334. package/content/layout/stack.md +0 -19
  335. package/content/layout/surface.md +0 -23
  336. package/content/layout/text.md +0 -22
  337. package/content/patterns/app-shell.md +0 -34
  338. package/content/patterns/dashboard.md +0 -36
  339. package/content/patterns/data-screen.md +0 -30
  340. package/content/patterns/detail-page.md +0 -31
  341. package/content/patterns/docs.md +0 -34
  342. package/content/patterns/focus-task.md +0 -34
  343. package/content/patterns/landing.md +0 -35
  344. package/content/patterns/list-page.md +0 -32
  345. package/content/patterns/mobile.md +0 -31
  346. package/content/patterns/settings-page.md +0 -33
  347. package/content/patterns/workspace.md +0 -32
  348. package/dist/cli/content-sync.test.d.ts +0 -1
  349. package/dist/cli/docs-cli.test.d.ts +0 -1
  350. package/dist/cli/docs.d.ts +0 -2
  351. package/dist/cli/docs.mjs +0 -10961
  352. package/dist/client/vdom/core/build.d.ts +0 -36
  353. package/dist/client/vdom/core/diff/children.d.ts +0 -29
  354. package/dist/client/vdom/core/diff/index.d.ts +0 -22
  355. package/dist/client/vdom/core/diff/output.d.ts +0 -30
  356. package/dist/client/vdom/core/diff/same.d.ts +0 -22
  357. package/dist/client/vdom/core/serve.d.ts +0 -75
  358. package/dist/client/vdom/core/ssr/index.d.ts +0 -25
  359. package/examples/apps/admin/README.md +0 -23
  360. package/examples/apps/admin/api.ts +0 -27
  361. package/examples/apps/admin/app.tsx +0 -144
  362. package/examples/apps/admin/main.tsx +0 -8
  363. package/examples/apps/admin/server.ts +0 -37
  364. package/examples/apps/auth/README.md +0 -23
  365. package/examples/apps/auth/api.ts +0 -49
  366. package/examples/apps/auth/app.tsx +0 -137
  367. package/examples/apps/auth/main.tsx +0 -8
  368. package/examples/apps/auth/server.ts +0 -37
  369. package/examples/apps/multi/README.md +0 -23
  370. package/examples/apps/multi/app.tsx +0 -83
  371. package/examples/apps/multi/main.tsx +0 -8
  372. package/examples/apps/multi/server.ts +0 -33
  373. package/examples/apps/todo/README.md +0 -23
  374. package/examples/apps/todo/api.ts +0 -26
  375. package/examples/apps/todo/app.tsx +0 -128
  376. package/examples/apps/todo/main.tsx +0 -9
  377. package/examples/apps/todo/server.ts +0 -39
  378. package/examples/hello-world/README.md +0 -9
  379. package/examples/hello-world/client.ts +0 -14
  380. package/examples/hello-world/routes.tsx +0 -26
  381. package/examples/hello-world/server.ts +0 -46
  382. package/examples/patterns/AppShell.tsx +0 -224
  383. package/examples/patterns/Dashboard.tsx +0 -153
  384. package/examples/patterns/DataScreen.tsx +0 -104
  385. package/examples/patterns/DetailPage.tsx +0 -79
  386. package/examples/patterns/Docs.tsx +0 -105
  387. package/examples/patterns/FocusTask.tsx +0 -67
  388. package/examples/patterns/Landing.tsx +0 -90
  389. package/examples/patterns/ListPage.tsx +0 -77
  390. package/examples/patterns/Mobile.tsx +0 -154
  391. package/examples/patterns/SettingsPage.tsx +0 -98
  392. package/examples/patterns/SplitWorkspace.tsx +0 -113
@@ -1,459 +0,0 @@
1
- # 中间件与 ctx 注入链
2
-
3
- > 从 docs/frontend-middleware.md 迁移(content/ 文档库——随 npm 包发布,与框架版本同步)。
4
- > 本页为叙述性指南——组件/能力逐项参考见 content/ 各域目录。
5
-
6
- # 前端中间件与工具(weifuwu/ui-dom)
7
-
8
- > ⚠️ **`weifuwu/client` 已并入 `weifuwu/ui-dom`**——中间件(api/auth/ws/i18n)位于 `weifuwu/ui-dom`,前端运行时唯一入口为 `weifuwu/ui-dom`(vdom3 事件流引擎:createRouter + createRoot),见 [ui-dom 指南](ui-dom-guide.md)。
9
-
10
- ## createRouter — 前端路由(vdom3)
11
-
12
- ```tsx
13
- import { createRouter, h } from 'weifuwu/ui-dom'
14
-
15
- let ctx: any = {}
16
- ctx = v3Toast()(ctx) // 中间件面展开(ctx 注入——对齐后端 app.use)
17
- ctx = v3Notification()(ctx) // 注入 ctx.notification
18
-
19
- const handle = createRouter(
20
- [
21
- { path: '/', render: () => h(Home, {}) },
22
- { path: '/users', render: () => h(UserList, {}) },
23
- { path: '/users/:id', render: (params) => h(UserDetail, { id: params.id }) },
24
- { path: '*', render: () => h(NotFound, {}) },
25
- ],
26
- document.querySelector('#root')!,
27
- { ctx },
28
- )
29
- ```
30
-
31
- ### 嵌套布局(RouteDef.layout——跨路由工厂不重跑)
32
-
33
- ```tsx
34
- const DashboardLayout = async (page: any) => {
35
- let open = true
36
- return h('div', { class: 'wf-row' },
37
- h('aside', {}, '导航菜单'),
38
- h('main', {}, page), // 子路由内容(layout 包装——工厂复用——状态保持)
39
- )
40
- }
41
- // { path: '/users', layout: DashboardLayout, render: () => h(UserList, {}) }
42
- ```
43
-
44
- ### 编程式导航
45
-
46
- ```tsx
47
- // 在任意组件/页面中(ctx.app——createRouter 注入)
48
- ctx.app?.navigate('/users/123?tab=profile')
49
- ```
50
-
51
- | ctx 注入 | 类型 | 说明 |
52
- |----------|------|------|
53
- | `ctx.params` / `ctx.query` | `Record<string, string>` | 路由参数 / URL query(顶层注入) |
54
- | `ctx.route.path` | `string` | 当前路由路径 |
55
- | `ctx.route.params` | `Record<string, string>` | URL 参数 |
56
- | `ctx.route.query` | `Record<string, string>` | 查询参数 |
57
- | `ctx.app.navigate(path)` | `(string) => void` | 编程式导航 |
58
-
59
- | RouteDef | 签名 | 说明 |
60
- |---------|------|------|
61
- | `path` | `string` | 路径(`:id` 参数 / `*` 通配) |
62
- | `render(params)` | `(params) => VNode` | 页面(params 注入——`ctx.route.params` 同源) |
63
- | `layout(page)` | `(VNode) => VNode` | 嵌套布局(跨路由工厂不重跑——状态保持) |
64
-
65
- | UIHandler | 类型 | 说明 |
66
- |-----------|------|------|
67
- | 签名 | `(location, ctx) => Promise<VNode> \| VNode` | 页面 = 异步组件(`ctx.data.get` 三场景;async 组件无需包装) |
68
- | 返回值 | `VNode \| null` | 数据结构(落地由 createRouter 事件流渲染决定) |
69
-
70
- ---
71
-
72
- ## api — HTTP 客户端中间件
73
-
74
- ```tsx
75
- import { createRouter, h, api } from 'weifuwu/ui-dom'
76
-
77
- let ctx: any = {}
78
- const root = document.querySelector('#root')!
79
- ctx = api({ baseURL: '/api' })(ctx)
80
- createRouter([], root, { ctx })
81
-
82
- // 在组件中使用
83
- async function loadUsers(ctx: WfuiContext) {
84
- const users = await ctx.api?.get<User[]>('/users')
85
- const user = await ctx.api?.get<User>('/users/1')
86
- const created = await ctx.api?.post<User>('/users', { name: 'Alice' })
87
- await ctx.api?.put('/users/1', { name: 'Bob' })
88
- await ctx.api?.patch('/users/1', { name: 'Bob' })
89
- await ctx.api?.delete('/users/1')
90
- }
91
- ```
92
-
93
- | 选项 | 类型 | 默认值 | 说明 |
94
- |------|------|--------|------|
95
- | `baseURL` | `string` | `''` | API 基础路径 |
96
- | `headers` | `Record<string, string>` | `{ 'Content-Type': 'application/json' }` | 默认请求头 |
97
- | `onRequest` | `(req) => { url, init }` | — | 请求拦截器 |
98
- | `onResponse` | `(res) => Promise<T>` | — | 响应拦截器 |
99
- | `timeout` | `number` | `0`(无超时) | 请求超时(ms)|
100
-
101
- | ctx.api 方法 | 签名 | 说明 |
102
- |-------------|------|------|
103
- | `api.get(url, opts?)` | `<T>(string, ApiRequestOptions?) => Promise<T>` | GET |
104
- | `api.post(url, body?, opts?)` | `<T>(string, unknown?, ApiRequestOptions?) => Promise<T>` | POST |
105
- | `api.put(url, body?, opts?)` | `<T>(string, unknown?, ApiRequestOptions?) => Promise<T>` | PUT |
106
- | `api.patch(url, body?, opts?)` | `<T>(string, unknown?, ApiRequestOptions?) => Promise<T>` | PATCH |
107
- | `api.delete(url, opts?)` | `<T>(string, ApiRequestOptions?) => Promise<T>` | DELETE |
108
-
109
- ```ts
110
- // 错误处理
111
- try {
112
- await ctx.api!.get('/users')
113
- } catch (e) {
114
- if (e instanceof ApiError) {
115
- console.log(e.status, e.body) // e.g. 404, 'Not Found'
116
- }
117
- }
118
- ```
119
-
120
- `ApiError`:`{ status: number, body: string }`,继承 `Error`。
121
-
122
- | ApiRequestOptions | 类型 | 说明 |
123
- |-------------------|------|------|
124
- | `headers` | `Record<string, string>` | 本次请求自定义请求头 |
125
- | `signal` | `AbortSignal` | 取消请求 |
126
-
127
- ---
128
-
129
- ## auth — 认证中间件
130
-
131
- ```tsx
132
- import { createRouter, h, auth } from 'weifuwu/ui-dom'
133
-
134
- let ctx: any = {}
135
- const root = document.querySelector('#root')!
136
- ctx = auth()(ctx)
137
- createRouter([], root, { ctx })
138
-
139
- // 在组件中
140
- async function Profile(_props: {}, ctx: WfuiContext) {
141
- return async (props) => {
142
- if (!ctx.auth?.isLoggedIn) return <p>请登录</p>
143
- return <p>欢迎, {ctx.auth?.user?.name}</p>
144
- }
145
- }
146
-
147
- // 登录
148
- ctx.auth?.login(token, { id: 1, name: 'Alice' }, refreshToken)
149
-
150
- // 登出
151
- ctx.auth?.logout()
152
-
153
- // 更新用户信息
154
- ctx.auth?.setUser({ id: 1, name: 'Bob' })
155
-
156
- // 刷新 token
157
- await ctx.auth?.refresh() // → boolean
158
- ```
159
-
160
- | 选项 | 类型 | 默认值 | 说明 |
161
- |------|------|--------|------|
162
- | `storage` | `Storage` | `localStorage` | 存储方式 |
163
- | `tokenKey` | `string` | `'weifuwu_token'` | Token 存储 key |
164
- | `userKey` | `string` | `'weifuwu_user'` | 用户信息存储 key |
165
- | `refreshTokenKey` | `string` | `'weifuwu_refresh'` | Refresh token 存储 key |
166
- | `refreshEndpoint` | `string` | `'/api/auth/refresh'` | 刷新端点 |
167
-
168
- | ctx.auth | 类型 | 说明 |
169
- |----------|------|------|
170
- | `.token` | `string \| null` | JWT token |
171
- | `.user` | `any` | 用户对象 |
172
- | `.isLoggedIn` | `boolean` | 是否已登录(基于 token 存在) |
173
- | `.login(token, user, refreshToken?)` | `void` | 登录 |
174
- | `.logout()` | `void` | 登出(清除存储) |
175
- | `.setUser(user)` | `void` | 更新用户信息 |
176
- | `.refresh()` | `Promise<boolean>` | 刷新 token(自动检测过期) |
177
-
178
- 启动时自动检测 token 是否过期(JWT `exp` 提前 30 秒),过期则自动调用 `refresh()`。
179
-
180
- ---
181
-
182
- ## ws — WebSocket 客户端中间件
183
-
184
- ```tsx
185
- import { createRouter, h, ws } from 'weifuwu/ui-dom'
186
-
187
- let ctx: any = {}
188
- const root = document.querySelector('#root')!
189
- ctx = ws({ url: '/ws' })(ctx)
190
- createRouter([], root, { ctx })
191
-
192
- // 发送消息
193
- ctx.ws?.send({ type: 'chat', body: 'hello' })
194
-
195
- // 接收消息 — 返回 unsubscribe 函数
196
- const unsubscribe = ctx.ws?.onMessage((msg) => {
197
- console.log('收到:', msg)
198
- })
199
-
200
- // 清理
201
- unsubscribe?.()
202
- ```
203
-
204
- | 选项 | 类型 | 默认值 | 说明 |
205
- |------|------|--------|------|
206
- | `url` | `string` | `'/ws'` | WebSocket 连接地址 |
207
- | `reconnectInterval` | `number` | `3000` | 重连间隔(ms) |
208
- | `maxReconnect` | `number` | `10` | 最大重连次数 |
209
- | `pingInterval` | `number` | `30000` | 心跳发送间隔 |
210
- | `pingTimeout` | `number` | `10000` | 心跳超时断开 |
211
-
212
- | ctx.ws | 类型 | 说明 |
213
- |--------|------|------|
214
- | `.send(msg)` | `(unknown) => void` | 发送 JSON 消息 |
215
- | `.onMessage(fn)` | `(fn) => () => void` | 订阅消息,返回 unsubscribe |
216
- | `.isConnected` | `boolean` | 连接状态 |
217
- | `.close()` | `() => void` | 断开连接 |
218
-
219
- 自动重连(指数退避)、心跳保活、JSON 序列化/反序列化。
220
-
221
- ---
222
-
223
- ## i18n — 国际化中间件
224
-
225
- ```tsx
226
- import { createRouter, h, i18n } from 'weifuwu/ui-dom'
227
-
228
- let ctx: any = {}
229
- const root = document.querySelector('#root')!
230
- app.use(i18n({
231
- locale: 'zh-CN',
232
- messages: {
233
- 'title': '仪表盘',
234
- 'welcome': '欢迎光临',
235
- },
236
- }))
237
- .mount('#root', App)
238
-
239
- // 组件中使用
240
- <h1>{ctx.i18n?.t('title')}</h1>
241
- <p>{ctx.i18n?.t('welcome')}</p>
242
-
243
- // 运行时切换语言
244
- ctx.i18n?.setLocale('en-US')
245
- // → 自动触发根组件重渲染(所有组件使用新语言文案)
246
- ```
247
-
248
- | I18nOptions | 类型 | 默认值 | 说明 |
249
- |-------------|------|--------|------|
250
- | `locale` | `string` | `'zh-CN'` | 初始语言 |
251
- | `messages` | `Record<string, string>` | `{}` | 翻译键值对 |
252
- | `components` | `Record<string, Record<string, string>>` | `{}` | 组件文案覆盖 |
253
-
254
- | ctx.i18n | 类型 | 说明 |
255
- |----------|------|------|
256
- | `.t(key, fallback?)` | `(string, string?) => string` | 翻译 |
257
- | `.locale` | `string` | 当前语言 |
258
- | `.setLocale(lang)` | `(string) => void` | 切换语言(触发重渲染) |
259
- | `.components` | `Record<string, Record<string, string>>` | 组件文案映射 |
260
-
261
- 内置语言包:
262
-
263
- ```ts
264
- import { zhCN, enUS } from 'weifuwu/ui-dom'
265
- ```
266
-
267
- - `zh-CN`:默认中文
268
- - `en-US`:英文
269
-
270
- 组件文案(Button 的 `加载中...`、FileUpload 的 `点击或拖拽上传文件` 等)随语言自动切换。组件内部通过 `ctx.i18n?.components?.ComponentName.field` 读取。
271
-
272
- 组件支持 `props.locale` 局部覆盖语言。
273
-
274
- ---
275
-
276
- ## ErrorBoundary — 错误边界
277
-
278
- ```tsx
279
- import { ErrorBoundary } from 'weifuwu/ui-dom'
280
-
281
- <ErrorBoundary fallback={<p>出错了,请刷新页面</p>}>
282
- <UserProfile />
283
- </ErrorBoundary>
284
-
285
- // fallback 也可以是一个接收 error 的函数
286
- <ErrorBoundary fallback={({ error }) => (
287
- <div>
288
- <p>出错了: {String(error)}</p>
289
- <button onClick={() => location.reload()}>重试</button>
290
- </div>
291
- )}>
292
- <UserProfile />
293
- </ErrorBoundary>
294
- ```
295
-
296
- | ErrorBoundaryProps | 类型 | 默认值 | 说明 |
297
- |--------------------|------|--------|------|
298
- | `fallback` | `VNode \| ((props: { error }) => VNode) \| null` | `null` | 错误时渲染的内容 |
299
- | `children` | `any` | — | 子组件 |
300
-
301
- 捕获子组件 render 时的错误 → 渲染 fallback。清除 `error` 即可重试。
302
-
303
- ---
304
-
305
- ## confirm — 确认对话框
306
-
307
- 两种用法,共享同一视觉与行为(基于 Modal 封装):
308
-
309
- **① 命令式 `ctx.confirm()`(推荐,操作前询问)**
310
-
311
- ```tsx
312
- import { createRouter, h } from 'weifuwu/ui-dom'
313
- import { confirm } from 'weifuwu/components'
314
-
315
- let ctx: any = {}
316
- const root = document.querySelector('#root')!
317
- ctx = confirm()(ctx)
318
- createRouter([], root, { ctx })
319
-
320
- // 任意代码中(组件事件、async 逻辑)
321
- async function handleDelete(ctx: WfuiContext) {
322
- const ok = await ctx.confirm?.('确定删除这条记录?', {
323
- title: '确认删除',
324
- confirmText: '删除',
325
- cancelText: '取消',
326
- variant: 'danger', // 'primary' | 'danger'
327
- })
328
- if (ok) {
329
- // 执行删除...
330
- }
331
- }
332
- ```
333
-
334
- **② 声明式 `<Confirm>`(需要受控状态时)**
335
-
336
- ```tsx
337
- import { Confirm } from 'weifuwu/components'
338
-
339
- <Confirm
340
- open={confirming}
341
- title="确认删除"
342
- message="确定删除这条记录?"
343
- confirmText="删除"
344
- variant="danger"
345
- onConfirm={() => doDelete()}
346
- onCancel={() => setConfirming(false)}
347
- />
348
- ```
349
-
350
- | ConfirmOptions | 类型 | 默认值 | 说明 |
351
- |----------------|------|--------|------|
352
- | `title` | `string` | `'确认操作'` | 对话框标题 |
353
- | `confirmText` | `string` | `'确定'` | 确认按钮文字 |
354
- | `cancelText` | `string` | `'取消'` | 取消按钮文字 |
355
- | `variant` | `'primary' \| 'danger'` | `'primary'` | 按钮样式变体 |
356
- | `width` | `string` | Modal 默认 | 对话框宽度 |
357
-
358
- - `ctx.confirm()` 返回 `Promise<boolean>`,ESC / 点击遮罩 / 取消 → resolve(false)
359
- - 组件化渲染(Modal + portal),自动锁定滚动 + 焦点陷阱,i18n 文案可配置
360
- - 多次调用各自独立渲染(叠放语义),互不干扰
361
-
362
- ---
363
-
364
- ## toast — 命令式消息提示
365
-
366
- `ctx.toast()` 是 `<Toast>` 组件的全局命令式封装:任意代码中一行调用,自动消失、自动清理,无需宿主状态。
367
-
368
- ```tsx
369
- import { createRouter, h } from 'weifuwu/ui-dom'
370
- import { toast } from 'weifuwu/components'
371
-
372
- let ctx: any = {}
373
- const root = document.querySelector('#root')!
374
- ctx = toast({ position: 'top-right', duration: 3000, max: 3 })(ctx)
375
- createRouter([], root, { ctx })
376
-
377
- // 任意代码中(组件事件、api 拦截器、WS 回调、定时器)
378
- ctx.toast?.('保存成功', 'success')
379
- ctx.toast?.('请求失败', 'error')
380
- ctx.toast?.('普通消息') // 默认 type = 'info'
381
- ```
382
-
383
- | ToastOptions | 类型 | 默认值 | 说明 |
384
- |-------------|------|--------|------|
385
- | `position` | `ToastPosition` | `'top-right'` | 容器位置 |
386
- | `duration` | `number` | `3000` | 默认自动消失时间(ms),0 = 不消失 |
387
- | `max` | `number` | `3` | 最大显示条数,超出移除最早 |
388
-
389
- 单条可覆盖自动消失时间:`ctx.toast('慢一点消失', 'info', 5000)`。
390
-
391
- 与声明式 `<Toast toasts={...}/>` 共存:声明式用于局部列表(合并消息、自定义布局),命令式用于全局一次性反馈。
392
-
393
- ---
394
-
395
- ## notification — 命令式通知
396
-
397
- `ctx.notification()` 是 `<Notification>` 组件的全局命令式封装:队列式通知(title + description + icon + 操作),自动消失、手动关闭、四角定位。
398
-
399
- ```tsx
400
- import { v3Notification } from 'weifuwu/ui-dom'
401
-
402
- let ctx: any = {}
403
- ctx = v3Notification({ position: 'top-right', duration: 4500, max: 5 })(ctx)
404
-
405
- // 任意代码中(组件事件、api 拦截器、WS 回调、定时器)
406
- ctx.notification?.success({ title: '部署成功', description: 'v0.63.0 已上线' })
407
- ctx.notification?.warning({ title: '磁盘空间不足', description: '已使用 92%' })
408
- ctx.notification?.('普通通知')
409
- ctx.notification?.open({ type: 'error', title: '请求失败', duration: 8000, action: { label: '重试', onClick: retry } })
410
- ```
411
-
412
- | NotificationOptions | 类型 | 默认值 | 说明 |
413
- |-------------|------|--------|------|
414
- | `position` | `NotificationPosition` | `'top-right'` | 容器位置(top-right/top-left/bottom-right/bottom-left) |
415
- | `duration` | `number` | `4500` | 默认自动消失时间(ms),0 = 不消失 |
416
- | `max` | `number` | `5` | 最大显示条数,超出移除最早 |
417
-
418
- 单条可覆盖自动消失时间:`ctx.notification({ title: 'x', duration: 8000 })`。
419
-
420
- ---
421
-
422
- ## ScrollLock / FocusTrap
423
-
424
- ```tsx
425
- import { lockScroll, unlockScroll } from 'weifuwu/ui-dom'
426
- import { trapFocus } from 'weifuwu/ui-dom'
427
-
428
- // 锁定/解锁滚动(支持嵌套计数)
429
- lockScroll()
430
- unlockScroll()
431
-
432
- // 焦点陷阱 — 返回 cleanup 函数
433
- const cleanup = trapFocus(containerElement)
434
- cleanup() // 恢复之前的焦点
435
- ```
436
-
437
- | API | 说明 |
438
- |-----|------|
439
- | `lockScroll()` | 锁定 body 滚动(iOS 兼容) |
440
- | `unlockScroll()` | 解锁滚动,恢复滚动位置 |
441
- | `trapFocus(el)` | Tab/Shift+Tab 在容器内循环,返回 cleanup |
442
-
443
- ---
444
-
445
- ## extendCtx — 上下文扩展
446
-
447
- ```tsx
448
- import { extendCtx } from 'weifuwu/ui-dom'
449
-
450
- // 在 AppMiddleware 中创建新 ctx,原 ctx getter 通过原型链继承
451
- function myMw(ctx: WfuiContext): WfuiContext {
452
- return extendCtx(ctx, { myField: 'value' })
453
- }
454
- ```
455
-
456
- `extendCtx` 使用 `Object.create(ctx)` 保持原型链,再用 `Object.assign` 添加新字段。保证 getter 不被快照化。
457
-
458
- ---
459
-
@@ -1,105 +0,0 @@
1
- # 移动端开发指南
2
-
3
- > 从 docs/mobile.md 迁移(content/ 文档库——随 npm 包发布,与框架版本同步)。
4
- > 本页为叙述性指南——组件/能力逐项参考见 content/ 各域目录。
5
-
6
- # 移动端开发指南(weifuwu)
7
-
8
- > 移动端友好由框架构造保证:**用对原语 + 守 audit 规则**,不靠每个组件"记得"。
9
- > 落地依据:移动端支持计划(P0-P3 全落地——openPopup 全系 + safe-area + 44px 命中区 + docs/mobile 指南)。
10
-
11
- ## 一、断点体系(布局原语)
12
-
13
- 移动优先,640/768/1024 三个断点(与 `useBreakpoint` 的 mobile/tablet/desktop 对齐):
14
-
15
- | 断点 | 类前缀 | 语义 |
16
- |------|--------|------|
17
- | ≥640px | `@sm` | 小屏以上 |
18
- | ≥768px | `@md` | 平板以上 |
19
- | ≥1024px | `@lg` | 桌面 |
20
-
21
- ```html
22
- <div class="wf-stack wf-stack@md">…</div> <!-- 移动纵向堆叠,md 起横向 -->
23
- <div class="wf-hidden@sm">…</div> <!-- 移动端隐藏 -->
24
- ```
25
-
26
- - 组件级移动适配用 `@media (max-width: 639px)`(bottom-sheet/全宽抽屉)或 `(max-width: 767px)`(双栏堆叠)
27
- - 触屏判定用 `@media (pointer: coarse)`(44px 命中区),**不要**用 width 猜触屏
28
-
29
- ## 二、命中区纪律(44px,Apple HIG / WCAG 2.5.8)
30
-
31
- - **button/input/select 由全局 coarse 规则自动覆盖**(`_base.css`)
32
- - **非 button 交互元素**(div/label/span 带 onClick)必须进 coarse 44px 清单——style-audit 规则强制,新组件漏了测试红
33
- - **小组件**(圆点/星/勾选框)视觉尺寸不变,用 `::after` 扩展命中区(参考 Carousel dot):
34
-
35
- ```css
36
- @media (pointer: coarse) {
37
- .wf-carousel-dot {
38
- position: relative;
39
- }
40
- .wf-carousel-dot::after {
41
- content: '';
42
- position: absolute;
43
- inset: -14px;
44
- }
45
- }
46
- ```
47
-
48
- - 小按钮(显式 `min-height` 覆盖了全局)需在组件 CSS 补 coarse 44px(参考 Pagination/Transfer/Calendar nav)
49
-
50
- ## 三、弹层(openPopup 命令式弹窗)
51
-
52
- **弹层组件必须用 `ctx.ui.openPopup`**——移动端友好由构造保证:
53
-
54
- ```tsx
55
- let handle: PopupHandle | null = null
56
- if (open && !handle)
57
- handle = ctx.ui.openPopup({
58
- anchor: () => anchorEl, // **anchor 必传**(触发区是锚点——否则被当外部点击关闭)
59
- content: () => h('div', { class: 'wf-popover' }, props.content),
60
- onClose: () => { handle = null; open = false; ctx.ui.render() },
61
- })
62
- else if (!open && handle) { handle.close(); handle = null }
63
- else if (handle) handle.update(h('div', { class: 'wf-popover' }, props.content))
64
- ```
65
-
66
- ## 四、手势原语
67
-
68
- | 原语 | 用法 | 场景 |
69
- |------|------|------|
70
- | `ctx.ui.useLongPress({ onLongPress, duration })` | spread 到目标 | ContextMenu 触屏长按(已内置双通道) |
71
- | `ctx.ui.useVisualViewport()` | 返回 `{ height, offsetTop, keyboardOpen }` 响应式 | fixed 底部栏被键盘遮挡(AiChat `raiseOnKeyboard`) |
72
- | `ctx.ui.useBreakpoint()` / `useMedia()` | 断点回调 | JS 侧响应式 |
73
- | `ctx.ui.useHoverCapable()` | boolean | 自定义 hover/tap 双模式 |
74
-
75
- ## 五、safe-area(刘海屏/Home 条)
76
-
77
- ```html
78
- <div class="wf-safe-bottom">…</div> <!-- padding-bottom: env(safe-area-inset-bottom) -->
79
- <div class="wf-safe-top">…</div>
80
- ```
81
-
82
- 底部抽屉/Modal bottom-sheet 已内置(P2)。
83
-
84
- ## 六、防横向溢出(375px 验收基线)
85
-
86
- - 弹层宽度:openPopup 自动视口夹紧(`calc(100vw - 32px)`);手动浮层加 `.wf-popup` 基类
87
- - 宽内容(表格/双栏):容器 `overflow-x: auto`(Table/Resizable 已内置)
88
- - 网格:`minmax(min(100%, 420px), 1fr)`(防 minmax 固定值撑破窄屏)
89
- - 验收:375×667 视口 `document.documentElement.scrollWidth <= innerWidth`
90
-
91
- ## 七、验证清单
92
-
93
- 1. 375px 视口无横向溢出
94
- 2. 交互元素 tap 可达(44px 命中区)
95
- 3. hover 组件 tap 可开、点外部可关、Escape 可关
96
- 4. ContextMenu 长按触发
97
- 5. 键盘弹起不遮挡输入(fixed 底部栏)
98
- 6. 桌面视口行为不变(hover 仍 hover)
99
- 7. style-audit 18 规则全绿 + `npm test` ≤15s
100
-
101
- ## 八、已知裁剪/例外(诚实声明)
102
-
103
- - Rate 星 / Tree 勾选 / Slider 手柄:视觉小标记,命中区依赖行级容器(不做元素级 44px,避免破坏视觉)
104
- - ⌘K 类快捷键在移动端无键盘语义(Command 需显式触发按钮)
105
- - `raiseOnKeyboard` 默认 false:内联 chat 靠原生聚焦滚动;全屏 chat 布局才抬升
@@ -1,98 +0,0 @@
1
- # 页面组装方法论(从零搭一个页面)
2
-
3
- > 解决"我会组件、会原语,但打开编辑器不知道第一行写什么"。
4
- > 与 [布局选型](layout-choice.md) 配合:选型决定"用什么",本页决定"怎么搭"。
5
- > 前提:先查 patterns(`content/patterns/*.md`)——有现成蓝本直接复制,
6
- > 本方法论用于"没有蓝本时从零搭"。
7
-
8
- ## 1. 页面解剖学(页面 = 五层)
9
-
10
- ```
11
- 骨架层 页面的大形状:wf-app-shell(壳)/ wf-container(定宽)/ wf-stack(纵列)
12
- 分区层 区域划分:header / content / footer / sider(用 row/stack 组合)
13
- 内容层 组件就位:Table/Form/Card…(组件文档查 API)
14
- 间距层 呼吸感:wf-gap-* / wf-p-*(间距工具)
15
- 响应式层 多设备:wf-hidden@lg / 断点变体(布局降级)
16
- ```
17
-
18
- ## 2. 组装 5 步套路(固定流程,不是自由发挥)
19
-
20
- ```
21
- ① 定骨架:这个页面是"壳内页面"(有侧栏/顶栏 → app-shell 已存在)还是
22
- "独立页面"(→ wf-container + wf-stack)?
23
- ② 划分区:从上到下/从左到右画出区域(header 标题区 / 主体区 / 底部操作区)
24
- ③ 填内容:每个区域放什么组件(标题 → PageHeader;列表 → Table;表单 → Form)
25
- ④ 调间距:区域间 wf-gap-lg、卡片内 wf-gap-sm、标题下 wf-mb-*
26
- ⑤ 响应式:窄屏时哪些隐藏(wf-hidden@lg)、哪些堆叠(grid 列数自适应)
27
- ```
28
-
29
- ## 3. 完整示例:从零搭"订单详情页"(逐步)
30
-
31
- ### 第 1 步:定骨架(独立页面——container + stack)
32
-
33
- ```tsx
34
- return (
35
- <div class="wf-container wf-stack" style="--wf-max:960px;--wf-gap:16px;padding:24px 16px">
36
- {/* 分区占位 */}
37
- </div>
38
- )
39
- ```
40
-
41
- ### 第 2 步:划分区 + 第 3 步:填内容
42
-
43
- ```tsx
44
- // ① 标题区:PageHeader(标题 + 状态 Tag + 操作按钮)
45
- <PageHeader title={`订单 ${id}`} sub="客户:张伟">
46
- <Button variant="primary">导出</Button>
47
- </PageHeader>
48
-
49
- // ② 主体区:Descriptions(详情字段栅格)
50
- <Descriptions items={[{ label: '订单号', value: id }, { label: '金额', value: '¥3,200' }]} bordered />
51
-
52
- // ③ 历史区:Timeline(执行流)
53
- <Timeline items={[{ key: '1', title: '已支付', time: '08-12 09:15' }]} />
54
- ```
55
-
56
- ### 第 4 步:调间距(gap 阶梯)
57
-
58
- ```tsx
59
- // 区域间 gap-lg(16px)已有(骨架 --wf-gap:16px)
60
- // 卡片内紧凑 gap-sm、标题下留白 wf-mb-sm
61
- <Card>
62
- <div class="wf-text-bold wf-mb-sm">补充信息</div>
63
- <div class="wf-stack wf-gap-xs">…</div>
64
- </Card>
65
- ```
66
-
67
- ### 第 5 步:响应式降级
68
-
69
- ```tsx
70
- // 双栏 → 窄屏单栏(grid auto-fit)
71
- <div class="wf-grid" style="--wf-cols:repeat(auto-fit,minmax(min(100%,300px),1fr))">
72
- <Card>补充信息</Card><Card>执行历史</Card>
73
- </div>
74
- ```
75
-
76
- **完整成品**:`examples/patterns/DetailPage.tsx`(本示例的落地版——5 步的每一步都可在源码中对应)。
77
-
78
- ## 4. 常见页面的搭法速查
79
-
80
- | 页面类型 | 骨架 | 分区 | 核心组件 |
81
- |---------|------|------|---------|
82
- | 列表页 | container+stack | 标题区/表格区/分页区 | PageHeader + SearchInput + Table + Pagination |
83
- | 详情页 | container+stack | 标题区/详情区/历史区 | PageHeader + Descriptions + Timeline |
84
- | 设置页 | container+stack | 标题区/分区 Tabs | PageHeader + Tabs + Form + Switch |
85
- | 表单页 | container+stack | 标题区/表单区/操作区 | PageHeader + Form + Field + Button |
86
- | 仪表盘 | container+stack | KPI 行/图表区/表格区 | StatCard + Chart + Table |
87
-
88
- (每种都有对应 patterns 蓝本——`content/patterns/*.md`)
89
-
90
- ## 5. 纪律(搭页面时的红线)
91
-
92
- ```
93
- □ 布局结构只用 wf-* 原语(不手写 CSS/内联 style 自定义)
94
- □ 内容元素用组件(不裸 div/span 手搓结构)
95
- □ 间距走 wf-gap-*/wf-p-*(不用魔数 px)
96
- □ 图标用 Icon 组件(禁 emoji 装饰)
97
- □ 先查 patterns——重复造轮子是最常见的浪费
98
- ```