ranui 0.1.10-alpha.9 → 0.2.0-alpha.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 (326) hide show
  1. package/README.md +397 -0
  2. package/README.zh-CN.md +216 -37
  3. package/dist/assets/image/failImage.d.ts +2 -0
  4. package/dist/bin/generate-component-api.d.ts +1 -0
  5. package/dist/bin/generate-style-docs.d.ts +1 -0
  6. package/dist/build/config.bundle.d.ts +2 -0
  7. package/dist/build/config.d.ts +3 -0
  8. package/dist/build/config.es.d.ts +2 -0
  9. package/dist/build/config.umd.d.ts +1 -0
  10. package/dist/builder.d.ts +11 -0
  11. package/dist/builder.js +39 -0
  12. package/dist/button-DukaD6uL.js +117 -0
  13. package/dist/button.js +3 -5
  14. package/dist/card-DQUJoDUQ.js +60 -0
  15. package/dist/card.js +5 -0
  16. package/dist/checkbox-iHZQb-yQ.js +94 -0
  17. package/dist/checkbox.js +3 -5
  18. package/dist/colorpicker-Ch67dWa_.js +302 -0
  19. package/dist/colorpicker.js +3 -9
  20. package/dist/components/button/index.d.ts +44 -0
  21. package/dist/components/card/index.d.ts +21 -0
  22. package/dist/components/checkbox/index.d.ts +35 -0
  23. package/dist/components/colorpicker/index.d.ts +88 -0
  24. package/dist/components/dropdown/index.d.ts +32 -0
  25. package/dist/components/form/index.d.ts +15 -0
  26. package/dist/components/icon/index.d.ts +58 -0
  27. package/dist/components/image/index.d.ts +25 -0
  28. package/dist/components/input/index.d.ts +229 -0
  29. package/dist/components/link/index.d.ts +21 -0
  30. package/dist/components/loading/index.d.ts +76 -0
  31. package/dist/components/math/index.d.ts +16 -0
  32. package/dist/components/message/container.d.ts +8 -0
  33. package/dist/components/message/index.d.ts +32 -0
  34. package/dist/components/modal/index.d.ts +100 -0
  35. package/dist/components/player/core/constants.d.ts +5 -0
  36. package/dist/components/player/core/controller.d.ts +33 -0
  37. package/dist/components/player/core/events.d.ts +10 -0
  38. package/dist/components/player/core/fullscreen.d.ts +5 -0
  39. package/dist/components/player/core/levels.d.ts +20 -0
  40. package/dist/components/player/core/media.d.ts +50 -0
  41. package/dist/components/player/core/playback.d.ts +14 -0
  42. package/dist/components/player/core/progress.d.ts +2 -0
  43. package/dist/components/player/core/state.d.ts +27 -0
  44. package/dist/components/player/core/view.d.ts +39 -0
  45. package/dist/components/player/index.d.ts +277 -0
  46. package/dist/components/popover/content/index.d.ts +12 -0
  47. package/dist/components/popover/index.d.ts +95 -0
  48. package/dist/components/progress/index.d.ts +40 -0
  49. package/dist/components/radar/index.d.ts +52 -0
  50. package/dist/components/route/index.d.ts +26 -0
  51. package/dist/components/router/index.d.ts +24 -0
  52. package/dist/components/scratch/index.d.ts +19 -0
  53. package/dist/components/section/index.d.ts +23 -0
  54. package/dist/components/select/dropdown-item/index.d.ts +21 -0
  55. package/dist/components/select/index.d.ts +135 -0
  56. package/dist/components/select/option/index.d.ts +19 -0
  57. package/dist/components/skeleton/index.d.ts +13 -0
  58. package/dist/components/tab/index.d.ts +58 -0
  59. package/dist/components/tabpane/index.d.ts +33 -0
  60. package/dist/demo/i18n.d.ts +4 -0
  61. package/dist/demo/index.d.ts +3 -0
  62. package/dist/demo/register-icons.d.ts +1 -0
  63. package/dist/dropdown-C5362qTy.js +82 -0
  64. package/dist/dropdown.js +6 -0
  65. package/dist/events-C59wGdni.js +30 -0
  66. package/dist/factory-BdsO0dEW.js +165 -0
  67. package/dist/form-05Lxxl3D.js +44 -0
  68. package/dist/form.js +5 -0
  69. package/dist/icon-DmoEnao5.js +165 -0
  70. package/dist/icon.js +4 -4
  71. package/dist/{index-KS2nvVcO.js → image-6GayFDqX.js} +58 -71
  72. package/dist/image.js +3 -2
  73. package/dist/index.cjs +35 -0
  74. package/dist/index.d.ts +277 -114
  75. package/dist/index.iife.js +306 -0
  76. package/dist/index.js +78 -38
  77. package/dist/input-DoraIb3x.js +198 -0
  78. package/dist/input.js +2 -3
  79. package/dist/katex-es-Bpesphgp.js +23682 -0
  80. package/dist/katex-es-Cnq5Pk8K.cjs +261 -0
  81. package/dist/link-BW-gvrpN.js +77 -0
  82. package/dist/link.js +6 -0
  83. package/dist/loading-Mko22ncl.js +206 -0
  84. package/dist/loading.js +4 -6
  85. package/dist/math-B5PpSnFR.js +52 -0
  86. package/dist/math.js +2 -4
  87. package/dist/message-CQENvkoi.js +137 -0
  88. package/dist/message.js +3 -4
  89. package/dist/mocks-CMGoftIc.js +179 -0
  90. package/dist/modal-DruDj3AB.js +350 -0
  91. package/dist/modal.js +3 -2
  92. package/dist/player-CvfmwWUa.js +13536 -0
  93. package/dist/player.js +3 -6
  94. package/dist/playwright.config.d.ts +2 -0
  95. package/dist/plugins/load-svg.d.ts +9 -0
  96. package/dist/popover-BCvHwLZb.js +213 -0
  97. package/dist/popover.js +3 -5
  98. package/dist/progress-BWkNf2J5.js +123 -0
  99. package/dist/progress.js +3 -5
  100. package/dist/radar-CWsawt2g.js +181 -0
  101. package/dist/radar.js +3 -4
  102. package/dist/ranui.css +1 -0
  103. package/dist/route-BY_E6-2C.js +88 -0
  104. package/dist/route.js +6 -0
  105. package/dist/router-BDcv4F-2.js +79 -0
  106. package/dist/router.js +6 -0
  107. package/dist/scratch-Dbd9G6Q6.js +60 -0
  108. package/dist/scratch.js +4 -0
  109. package/dist/section-CNTvgdQ-.js +63 -0
  110. package/dist/section.js +5 -0
  111. package/dist/select-BmhCUTLb.js +433 -0
  112. package/dist/select.js +3 -8
  113. package/dist/signal-XHfNsQNW.js +57 -0
  114. package/dist/skeleton-DPv9nFhL.js +32 -0
  115. package/dist/skeleton.js +3 -2
  116. package/dist/ssg.js +21 -0
  117. package/dist/ssr-DSGwPtEd.js +34 -0
  118. package/dist/ssr-stream.d.ts +1 -0
  119. package/dist/ssr-stream.js +87 -0
  120. package/dist/ssr.d.ts +1 -0
  121. package/dist/ssr.js +7 -0
  122. package/dist/style.d.ts +1 -0
  123. package/dist/style.js +0 -0
  124. package/dist/tab-C9swK-hm.js +185 -0
  125. package/dist/tab.js +3 -4
  126. package/dist/tabpane-B_M-Jokw.js +87 -0
  127. package/dist/tabpane.js +3 -2
  128. package/dist/test/e2e/button.spec.d.ts +1 -0
  129. package/dist/test/e2e/checkbox.spec.d.ts +1 -0
  130. package/dist/test/e2e/helpers.d.ts +13 -0
  131. package/dist/test/e2e/icon.spec.d.ts +1 -0
  132. package/dist/test/e2e/image.spec.d.ts +1 -0
  133. package/dist/test/e2e/input.spec.d.ts +1 -0
  134. package/dist/test/e2e/loading.spec.d.ts +1 -0
  135. package/dist/test/e2e/message.spec.d.ts +1 -0
  136. package/dist/test/e2e/modal.spec.d.ts +1 -0
  137. package/dist/test/e2e/popover.spec.d.ts +1 -0
  138. package/dist/test/e2e/progress.spec.d.ts +1 -0
  139. package/dist/test/e2e/radar.spec.d.ts +1 -0
  140. package/dist/test/e2e/select.spec.d.ts +1 -0
  141. package/dist/test/e2e/skeleton.spec.d.ts +1 -0
  142. package/dist/test/e2e/tab.spec.d.ts +1 -0
  143. package/dist/test/e2e/visual/colorpicker.spec.d.ts +1 -0
  144. package/dist/test/e2e/visual/components.spec.d.ts +1 -0
  145. package/dist/test/e2e/visual/player.spec.d.ts +1 -0
  146. package/dist/test/integration/composition.test.d.ts +23 -0
  147. package/dist/test/setup.d.ts +0 -0
  148. package/dist/test/ssr/builder.core.ssr.test.d.ts +1 -0
  149. package/dist/test/ssr/builder.factory.ssr.test.d.ts +1 -0
  150. package/dist/test/ssr/builder.mocks.test.d.ts +1 -0
  151. package/dist/test/ssr/components/button.test.d.ts +1 -0
  152. package/dist/test/ssr/css-vars.test.d.ts +1 -0
  153. package/dist/test/ssr/registry.test.d.ts +1 -0
  154. package/dist/test/ssr/router.ssg.test.d.ts +2 -0
  155. package/dist/test/ssr/snapshots/button.test.d.ts +1 -0
  156. package/dist/test/ssr/stream.test.d.ts +2 -0
  157. package/dist/test/ssr/theme.tokens.ssr.test.d.ts +1 -0
  158. package/dist/test/unit/builder.core.browser.test.d.ts +1 -0
  159. package/dist/test/unit/builder.escape.test.d.ts +1 -0
  160. package/dist/test/unit/builder.selectors.test.d.ts +1 -0
  161. package/dist/test/unit/button.contract.test.d.ts +1 -0
  162. package/dist/test/unit/card.contract.test.d.ts +1 -0
  163. package/dist/test/unit/checkbox.contract.test.d.ts +1 -0
  164. package/dist/test/unit/colorpicker.color.utils.test.d.ts +1 -0
  165. package/dist/test/unit/colorpicker.contract.test.d.ts +1 -0
  166. package/dist/test/unit/colorpicker.methods.test.d.ts +1 -0
  167. package/dist/test/unit/component.helpers.test.d.ts +1 -0
  168. package/dist/test/unit/dropdown-item.contract.test.d.ts +1 -0
  169. package/dist/test/unit/dropdown.contract.test.d.ts +1 -0
  170. package/dist/test/unit/form.contract.test.d.ts +1 -0
  171. package/dist/test/unit/helpers/component.d.ts +3 -0
  172. package/dist/test/unit/helpers/dom.d.ts +2 -0
  173. package/dist/test/unit/icon.contract.test.d.ts +1 -0
  174. package/dist/test/unit/image.contract.test.d.ts +1 -0
  175. package/dist/test/unit/input.contract.test.d.ts +1 -0
  176. package/dist/test/unit/link.contract.test.d.ts +1 -0
  177. package/dist/test/unit/loading.contract.test.d.ts +1 -0
  178. package/dist/test/unit/math.contract.test.d.ts +1 -0
  179. package/dist/test/unit/message.component.test.d.ts +1 -0
  180. package/dist/test/unit/message.container.test.d.ts +1 -0
  181. package/dist/test/unit/modal.contract.test.d.ts +1 -0
  182. package/dist/test/unit/option.contract.test.d.ts +1 -0
  183. package/dist/test/unit/package-exports.source.test.d.ts +1 -0
  184. package/dist/test/unit/player-controls.test.d.ts +1 -0
  185. package/dist/test/unit/player-core.test.d.ts +1 -0
  186. package/dist/test/unit/player-event-handlers.test.d.ts +1 -0
  187. package/dist/test/unit/player-events.test.d.ts +1 -0
  188. package/dist/test/unit/player-fullscreen.test.d.ts +1 -0
  189. package/dist/test/unit/player-interactions.test.d.ts +1 -0
  190. package/dist/test/unit/player-levels.test.d.ts +1 -0
  191. package/dist/test/unit/player-media.test.d.ts +1 -0
  192. package/dist/test/unit/player-playback.test.d.ts +1 -0
  193. package/dist/test/unit/player.contract.test.d.ts +1 -0
  194. package/dist/test/unit/popover-accessibility.test.d.ts +1 -0
  195. package/dist/test/unit/popover.contract.test.d.ts +2 -0
  196. package/dist/test/unit/progress.contract.test.d.ts +1 -0
  197. package/dist/test/unit/radar.contract.test.d.ts +1 -0
  198. package/dist/test/unit/route.contract.test.d.ts +1 -0
  199. package/dist/test/unit/router.contract.test.d.ts +2 -0
  200. package/dist/test/unit/scratch.contract.test.d.ts +1 -0
  201. package/dist/test/unit/select-accessibility.test.d.ts +1 -0
  202. package/dist/test/unit/select-option.contract.test.d.ts +1 -0
  203. package/dist/test/unit/select.contract.test.d.ts +1 -0
  204. package/dist/test/unit/skeleton.contract.test.d.ts +1 -0
  205. package/dist/test/unit/ssr.test.d.ts +1 -0
  206. package/dist/test/unit/tab.contract.test.d.ts +2 -0
  207. package/dist/test/unit/theme.semantic-tokens.test.d.ts +1 -0
  208. package/dist/test/unit/theme.skin-tokens.test.d.ts +1 -0
  209. package/dist/test/unit/utils.dom.test.d.ts +1 -0
  210. package/dist/test/unit/utils.error.test.d.ts +1 -0
  211. package/dist/test/unit/utils.i18n.test.d.ts +1 -0
  212. package/dist/test/unit/utils.image.test.d.ts +1 -0
  213. package/dist/test/unit/utils.math.test.d.ts +1 -0
  214. package/dist/test/unit/utils.router.test.d.ts +1 -0
  215. package/dist/test/unit/utils.signal.test.d.ts +1 -0
  216. package/dist/test/unit/utils.ssr-stream.test.d.ts +1 -0
  217. package/dist/test/unit/utils.style.test.d.ts +1 -0
  218. package/dist/test/unit/utils.theme.test.d.ts +1 -0
  219. package/dist/test/unit/utils.tween.test.d.ts +1 -0
  220. package/dist/tsconfig.json +8 -8
  221. package/dist/typings.d.ts +163 -114
  222. package/dist/utils/builder/core.d.ts +70 -0
  223. package/dist/utils/builder/env.d.ts +1 -0
  224. package/dist/utils/builder/escape.d.ts +2 -0
  225. package/dist/utils/builder/events.d.ts +55 -0
  226. package/dist/utils/builder/factory.d.ts +18 -0
  227. package/dist/utils/builder/index.d.ts +9 -0
  228. package/dist/utils/builder/mocks.d.ts +62 -0
  229. package/dist/utils/builder/selectors.d.ts +4 -0
  230. package/dist/utils/builder/signal.d.ts +87 -0
  231. package/dist/utils/color.d.ts +52 -0
  232. package/dist/utils/component.d.ts +16 -0
  233. package/dist/utils/dom.d.ts +39 -0
  234. package/dist/utils/error.d.ts +6 -0
  235. package/dist/utils/i18n/index.d.ts +53 -0
  236. package/dist/utils/i18n.js +88 -0
  237. package/dist/utils/image.d.ts +39 -0
  238. package/dist/utils/index.d.ts +8 -0
  239. package/dist/utils/math.d.ts +26 -0
  240. package/dist/utils/router/index.d.ts +128 -0
  241. package/dist/utils/router.js +197 -0
  242. package/dist/utils/ssg.d.ts +49 -0
  243. package/dist/utils/ssr-registry.d.ts +8 -0
  244. package/dist/utils/ssr-stream.d.ts +23 -0
  245. package/dist/utils/ssr.d.ts +17 -0
  246. package/dist/utils/style.d.ts +12 -0
  247. package/dist/utils/theme.d.ts +9 -0
  248. package/dist/utils/tween.d.ts +21 -0
  249. package/dist/utils/video.d.ts +40 -0
  250. package/dist/utils-D4pPF77E.js +689 -0
  251. package/dist/vite.config.d.ts +6 -0
  252. package/dist/vitest.config.d.ts +2 -0
  253. package/dist/vitest.config.ssr.d.ts +2 -0
  254. package/docs/COMPONENTS.md +326 -0
  255. package/docs/DESIGN.md +182 -0
  256. package/docs/style-tokens-public.md +880 -0
  257. package/package.json +136 -77
  258. package/typings.d.ts +163 -114
  259. package/dist/_commonjs-dynamic-modules-DLbDWi6a.js +0 -12
  260. package/dist/add-user-BN1JlY7e.js +0 -4
  261. package/dist/arrow-down-B_hCY3Wt.js +0 -662
  262. package/dist/book-nTEFXU2x.js +0 -4
  263. package/dist/check-circle-fill-B_pd8ZSs.js +0 -4
  264. package/dist/check-circle-szyAJiap.js +0 -4
  265. package/dist/close-CFnkhudp.js +0 -4
  266. package/dist/close-circle-CwmuN2C6.js +0 -4
  267. package/dist/close-circle-fill-jSqPPw9i.js +0 -4
  268. package/dist/colz-DJZvo_8B.js +0 -232
  269. package/dist/docx-CHkPTdGU.js +0 -3665
  270. package/dist/drop-4j4abxje.js +0 -36
  271. package/dist/eye-D_mEt17f.js +0 -4
  272. package/dist/eye-close-BVr3NJtg.js +0 -4
  273. package/dist/home-BUQ4USMk.js +0 -4
  274. package/dist/iconShadowless.js +0 -6
  275. package/dist/index-15M0olqa.js +0 -204
  276. package/dist/index-1v568_nq.js +0 -140
  277. package/dist/index-B897keW5.js +0 -279
  278. package/dist/index-BZR0HaP2.js +0 -40
  279. package/dist/index-B_GuEcTd.js +0 -9575
  280. package/dist/index-Bc2Bcl8D.js +0 -63701
  281. package/dist/index-C4Sv0T51.js +0 -495
  282. package/dist/index-C6RcMHoH.js +0 -187
  283. package/dist/index-C9z10IgG.js +0 -103
  284. package/dist/index-CFjEuvBW.js +0 -308
  285. package/dist/index-CGEx9VOA.js +0 -17106
  286. package/dist/index-CGYfjKUV.js +0 -72
  287. package/dist/index-CQTJoWhb.js +0 -19
  288. package/dist/index-CiWwvEMM.js +0 -511
  289. package/dist/index-CkM9ENTf.js +0 -496
  290. package/dist/index-CtVOgBDk.js +0 -659
  291. package/dist/index-D4qUro5V.js +0 -279
  292. package/dist/index-D4y9c1Dj.js +0 -310
  293. package/dist/index-DAxs7Dd2.js +0 -119
  294. package/dist/index-DC5EA657.js +0 -91
  295. package/dist/index-DJZmDHz-.js +0 -146
  296. package/dist/index-D_CA5VDZ.js +0 -158
  297. package/dist/index-WfFw4LJT.js +0 -490
  298. package/dist/index-mhFL9MJp.js +0 -320
  299. package/dist/info-circle-COnL5bTJ.js +0 -4
  300. package/dist/info-circle-fill-CFeVMdci.js +0 -4
  301. package/dist/inputShadowless.js +0 -6
  302. package/dist/jszip.min-Dhs3nUkD.js +0 -2346
  303. package/dist/katex-es-B5r5vt3m.js +0 -14628
  304. package/dist/loading-Dcc5RApI.js +0 -4
  305. package/dist/loading-scene-BMc2wqKm.js +0 -4
  306. package/dist/lock-Cr7BnmWN.js +0 -4
  307. package/dist/message-D36_Zo2l.js +0 -4
  308. package/dist/pdf-Cx0VWKFo.js +0 -118
  309. package/dist/power-off-lQRbiBak.js +0 -4
  310. package/dist/preview-CJbz9GjO.js +0 -4
  311. package/dist/preview.js +0 -7
  312. package/dist/selectShadowless.js +0 -564
  313. package/dist/setting-DemlgzVC.js +0 -4
  314. package/dist/shadowless.js +0 -8
  315. package/dist/sprite-CH2zLtZy.js +0 -141
  316. package/dist/style.css +0 -1
  317. package/dist/team-tl4NJXPC.js +0 -4
  318. package/dist/umd/index.umd.cjs +0 -60
  319. package/dist/umd/shadowless/shadowless.umd.cjs +0 -1
  320. package/dist/umd/shadowless/style.css +0 -1
  321. package/dist/umd/style.css +0 -1
  322. package/dist/unlock-CeU74z9n.js +0 -4
  323. package/dist/user-B-eVXwuk.js +0 -4
  324. package/dist/warning-circle-DDUgEDIv.js +0 -4
  325. package/dist/warning-circle-fill-lODUKz0i.js +0 -4
  326. package/readme.md +0 -195
package/README.md ADDED
@@ -0,0 +1,397 @@
1
+ # ranui
2
+
3
+ An experimental UI component library based on Web Components. Components use Shadow DOM encapsulation, CSS Token theming, and SSR / Declarative Shadow DOM support.
4
+
5
+ ---
6
+
7
+ <a href="https://github.com/chaxus/ran"><img src="https://img.shields.io/github/actions/workflow/status/chaxus/ran/ci.yml" alt="Build Status"></a>
8
+ <a href="https://github.com/chaxus/ran"><img src="https://img.shields.io/npm/v/ranui.svg" alt="npm-v"></a>
9
+ <a href="https://github.com/chaxus/ran"><img src="https://img.shields.io/npm/dt/ranui.svg" alt="npm-d"></a>
10
+ <a href="https://github.com/chaxus/ran"><img src="https://img.badgesize.io/https:/unpkg.com/ranui/dist/umd/shadowless/shadowless.umd.cjs?label=brotli&compression=brotli" alt="brotli"></a>
11
+ <a href="https://github.com/chaxus/ran"><img src="https://img.shields.io/badge/module%20formats-umd%2C%20esm-green.svg" alt="module formats: umd, esm"></a>
12
+
13
+ [中文](./README.zh-CN.md) | **English**
14
+
15
+ ## Important Notice
16
+
17
+ This is an **experimental UI library** in early development. It is usable, but primarily intended for learning and experimentation.
18
+
19
+ Key points:
20
+
21
+ - **Early development**: features are still being developed and refined.
22
+ - **Experimental**: APIs may change frequently.
23
+ - **Learning-oriented**: mainly intended for learning Web Components and UI development.
24
+
25
+ ## Features
26
+
27
+ 1. **Cross-framework compatibility:** works with React, Vue, Preact, SolidJS, Svelte, and any JavaScript project that follows W3C standards.
28
+ 2. **Native experience:** use custom elements such as `<r-button>` and `<r-modal>` like native HTML elements.
29
+ 3. **Modular design:** supports both full imports and per-component imports for better maintainability and bundle control.
30
+ 4. **Shadow DOM encapsulation:** component internals are isolated by default, while CSS Tokens, `::part()`, and the `sheet` attribute provide controlled styling hooks.
31
+ 5. **TypeScript support:** built with TypeScript and type definitions.
32
+ 6. **SSR friendly:** supports server rendering through `defineSSR`, `renderToString`, and Declarative Shadow DOM.
33
+ 7. **Accessible:** ARIA roles/states, full keyboard navigation, form-associated inputs (`<r-checkbox>`/`<r-input>`/`<r-select>` participate in native `FormData`), live-region toasts, and `prefers-reduced-motion` support.
34
+
35
+ ## Installation
36
+
37
+ Using npm:
38
+
39
+ ```console
40
+ npm install ranui --save
41
+ ```
42
+
43
+ ## Documentation and Examples
44
+
45
+ [See components and use examples](https://chaxus.github.io/ran/src/ranui/)
46
+
47
+ ### Components & API reference
48
+
49
+ Every element's attributes, properties, **events (with `detail` shapes)**, slots, and `::part()` names are generated from source — no need to grep the exports:
50
+
51
+ - Per-element API: [docs/COMPONENTS.md](./docs/COMPONENTS.md)
52
+ - Design standard (color/spacing/typography/motion/a11y): [docs/DESIGN.md](./docs/DESIGN.md)
53
+
54
+ Regenerate after changing a component's API with:
55
+
56
+ ```bash
57
+ pnpm doc:api
58
+ ```
59
+
60
+ ### AI / Claude Code skill
61
+
62
+ A ready-to-use skill lets AI assistants (Claude Code) read and use ranui without
63
+ spelunking the source. It's published from the `ran` plugin marketplace:
64
+
65
+ ```bash
66
+ /plugin marketplace add chaxus/ran
67
+ /plugin install ranui@ran
68
+ ```
69
+
70
+ Once installed, Claude uses it automatically when you work with ranui (or invoke it
71
+ explicitly as `/ranui:ranui`). The skill covers the import map, element inventory, the
72
+ builder/reactivity API, accessibility, and usage examples, and points to the API
73
+ reference shipped in the package ([docs/COMPONENTS.md](./docs/COMPONENTS.md)).
74
+
75
+ ### Styling Documentation
76
+
77
+ The styling system is unified around CSS Tokens and `::part()`.
78
+
79
+ - Style override guide: [docs/style-override.md](./docs/style-override.md)
80
+ - Complete Token/Part list, generated automatically: [docs/style-tokens-parts.md](./docs/style-tokens-parts.md)
81
+ - Public styling API for consumers, generated automatically: [docs/style-tokens-public.md](./docs/style-tokens-public.md)
82
+ - Public token filter config: [docs/style-token-filter.json](./docs/style-token-filter.json)
83
+
84
+ Refresh the styling docs with:
85
+
86
+ ```bash
87
+ pnpm doc:style
88
+ ```
89
+
90
+ ### Theming
91
+
92
+ ranui ships a single token system based on the [Geist design system](https://vercel.com/design), with `light`, `dark`, and `system` modes — there are no theme packs. Switch the mode or override any token at runtime (SSR-safe):
93
+
94
+ ```ts
95
+ import { initTheme, setTheme, setThemeToken, setThemeTokens } from 'ranui';
96
+ import 'ranui/style';
97
+
98
+ initTheme(); // restore the persisted choice on load
99
+ setTheme('system'); // 'light' | 'dark' | 'system'
100
+ setThemeToken('--ran-color-primary', '#6c47ff');
101
+ setThemeTokens({ '--ran-radius-md': '10px' });
102
+ ```
103
+
104
+ Dark mode redefines only the base color scale; semantic tokens (`--ran-color-*`) reference it and flip automatically. See [docs/THEME_STYLE_SYSTEM_DESIGN.md](./docs/THEME_STYLE_SYSTEM_DESIGN.md) and [docs/DESIGN.md](./docs/DESIGN.md).
105
+
106
+ ## Imports
107
+
108
+ Use per-component imports to reduce bundle size:
109
+
110
+ ```js
111
+ import 'ranui/button';
112
+ ```
113
+
114
+ If styles are missing, import the stylesheet manually:
115
+
116
+ ```js
117
+ import 'ranui/style';
118
+ ```
119
+
120
+ If type resolution fails, import one of the type entry points manually:
121
+
122
+ ```ts
123
+ import 'ranui/typings';
124
+ // or
125
+ import 'ranui/dist/index.d.ts';
126
+ // or
127
+ import 'ranui/type';
128
+ // or
129
+ import 'ranui/dist/typings';
130
+ ```
131
+
132
+ Only one working type entry is needed.
133
+
134
+ Full import is also supported:
135
+
136
+ ```ts
137
+ import 'ranui';
138
+ ```
139
+
140
+ ES module:
141
+
142
+ ```js
143
+ import 'ranui';
144
+ ```
145
+
146
+ or:
147
+
148
+ ```js
149
+ import 'ranui/button';
150
+ ```
151
+
152
+ UMD, IIFE, CJS:
153
+
154
+ ```html
155
+ <script src="./ranui/dist/umd/index.umd.cjs"></script>
156
+ ```
157
+
158
+ ## Usage
159
+
160
+ RanUI components are Web Components, so they can be used without framework-specific wrappers.
161
+
162
+ In most cases, use them like native HTML elements.
163
+
164
+ Examples:
165
+
166
+ - html
167
+ - js
168
+ - jsx
169
+ - vue
170
+ - tsx
171
+
172
+ ### html
173
+
174
+ ```html
175
+ <script src="./ranui/dist/umd/index.umd.cjs"></script>
176
+
177
+ <body>
178
+ <r-button>Button</r-button>
179
+ </body>
180
+ ```
181
+
182
+ ### js
183
+
184
+ ```js
185
+ import 'ranui';
186
+
187
+ const Button = document.createElement('r-button');
188
+ Button.textContent = 'this is button text';
189
+ document.body.appendChild(Button);
190
+ ```
191
+
192
+ ### jsx
193
+
194
+ ```jsx
195
+ import 'ranui';
196
+
197
+ const App = () => {
198
+ return (
199
+ <>
200
+ <r-button>Button</r-button>
201
+ </>
202
+ );
203
+ };
204
+ ```
205
+
206
+ ### vue
207
+
208
+ ```vue
209
+ <template>
210
+ <r-button></r-button>
211
+ </template>
212
+ <script>
213
+ import 'ranui';
214
+ </script>
215
+ ```
216
+
217
+ ### tsx
218
+
219
+ ```tsx
220
+ import 'ranui/button';
221
+
222
+ const Button = () => {
223
+ return (
224
+ <div>
225
+ <r-button type="primary">button</r-button>
226
+ </div>
227
+ );
228
+ };
229
+ ```
230
+
231
+ ### Message Position and Container
232
+
233
+ `window.message` supports custom top offset, z-index, and mount container:
234
+
235
+ ```ts
236
+ import 'ranui/message';
237
+
238
+ const customRoot = document.getElementById('custom-message-root');
239
+
240
+ window.message?.success({
241
+ content: 'Saved',
242
+ duration: 2000,
243
+ top: 24,
244
+ zIndex: 3000,
245
+ getContainer: () => customRoot,
246
+ });
247
+ ```
248
+
249
+ `top` supports `number | string`; `24` becomes `24px`, while `'2rem'` keeps its unit.
250
+
251
+ `zIndex` supports `number | string`.
252
+
253
+ `getContainer` must return an `HTMLElement`; when omitted, messages mount to `document.body`.
254
+
255
+ ### Reactive Primitives
256
+
257
+ `signal`, `createEffect`, `computed`, and `batch` ship alongside the DOM builder for building reactive page sections without a framework. The design mirrors SwiftUI's `@Observable` with two correctness improvements from Solid.js: effects automatically clean up stale subscriptions before each re-run, and `batch()` coalesces multiple signal writes into a single effect flush — the same guarantee SwiftUI gives for free.
258
+
259
+ ```ts
260
+ import { signal, createEffect, computed, batch, EventManager, Div, ButtonBuilder } from 'ranui/builder';
261
+
262
+ function initCounter(container: HTMLElement) {
263
+ const [count, setCount] = signal(0);
264
+ const [step, setStep] = signal(1);
265
+ const doubled = computed(() => count() * 2);
266
+ const scope = new EventManager();
267
+
268
+ const label = Div().build();
269
+ const view = Div()
270
+ .children(
271
+ label,
272
+ ButtonBuilder()
273
+ .text('+')
274
+ .listen(scope, 'click', () => setCount((n) => n + step())),
275
+ ButtonBuilder()
276
+ .text('reset')
277
+ .listen(
278
+ scope,
279
+ 'click',
280
+ () =>
281
+ batch(() => {
282
+ setCount(0);
283
+ setStep(1);
284
+ }), // two writes → one effect flush
285
+ ),
286
+ )
287
+ .build();
288
+
289
+ const dispose = createEffect(() => {
290
+ label.textContent = `${count()} (×2 = ${doubled()})`;
291
+ });
292
+
293
+ container.appendChild(view);
294
+ return () => {
295
+ dispose();
296
+ scope.abort();
297
+ }; // teardown
298
+ }
299
+ ```
300
+
301
+ See [Utility Documentation](./utils/README.md) for the full API.
302
+
303
+ ### Routing
304
+
305
+ RanUI includes client-side routing via declarative components and a JavaScript API.
306
+
307
+ **Declarative components:**
308
+
309
+ ```html
310
+ <r-router>
311
+ <nav>
312
+ <r-link href="/">Home</r-link>
313
+ <r-link href="/about">About</r-link>
314
+ </nav>
315
+
316
+ <r-route path="/" exact><h2>Home</h2></r-route>
317
+ <r-route path="/about"><h2>About</h2></r-route>
318
+ <r-route path="/users/:id"><h2>User detail</h2></r-route>
319
+ </r-router>
320
+ ```
321
+
322
+ **JavaScript API with navigation guard:**
323
+
324
+ ```ts
325
+ import { createRouter } from 'ranui';
326
+
327
+ const router = createRouter({
328
+ mode: 'history',
329
+ routes: [
330
+ { path: '/', exact: true, meta: { title: 'Home' } },
331
+ { path: '/users/:id', meta: { requiresAuth: true } },
332
+ ],
333
+ viewTransition: 'spa', // 'spa' | 'mpa' | 'both'
334
+ });
335
+
336
+ router.beforeEach((to, from, next) => {
337
+ if (to.meta?.requiresAuth && !isLoggedIn()) next('/login');
338
+ else next();
339
+ });
340
+
341
+ router.push('/users/42');
342
+ ```
343
+
344
+ For pure MPA sites (no JS router needed), use `enableMpaViewTransitions()` to inject `@view-transition { navigation: auto }`. Shared-element morph animations are supported via the standard `view-transition-name` CSS property.
345
+
346
+ ```ts
347
+ import { enableMpaViewTransitions } from 'ranui';
348
+ enableMpaViewTransitions();
349
+ ```
350
+
351
+ See the [Router documentation](https://chaxus.github.io/ran/src/ranui/router/) for the full API including guards, `onPageSwap`/`onPageReveal`, and per-element transition names.
352
+
353
+ ### SSR & Builder
354
+
355
+ For SSR or declarative UI construction, RanUI internally uses `builder`, the SSR registry, and Declarative Shadow DOM. Components reuse existing Shadow Roots through `ensureShadowRoot` and keep initialization idempotent through `ensureShadowElement`.
356
+
357
+ Source-level SSR rendering example:
358
+
359
+ ```ts
360
+ import { Button } from '@/components/button';
361
+ import { renderToString } from '@/utils/ssr';
362
+
363
+ const button = new Button();
364
+ button.setAttribute('effect', 'true');
365
+
366
+ // Outputs an HTML string containing Declarative Shadow DOM.
367
+ const html = renderToString(button);
368
+ ```
369
+
370
+ See [Utility Documentation](./utils/README.md) for details.
371
+
372
+ ## Component Development Conventions
373
+
374
+ When adding or maintaining components, follow the package conventions:
375
+
376
+ - Extend `RanElement`; do not directly extend the browser `HTMLElement`.
377
+ - Use `ensureShadowRoot` to create or reuse Shadow Roots; do not call `attachShadow` directly.
378
+ - Use `ensureShadowElement` to build Shadow DOM subtrees idempotently.
379
+ - Include `sheet` in `observedAttributes` and sync component-level style overrides through `syncSheetAttribute`.
380
+ - Guard `attributeChangedCallback` with `if (old === next) return;`.
381
+ - Register components with `defineSSR('r-name', Component)`, not direct `customElements.define`.
382
+ - Add both type exports and side-effect imports in `index.ts`; also add standalone entries in `vite.config.ts` and `package.json`.
383
+ - Use `EventManager` from `@/utils/builder` for lifecycle-bound listeners in `connectedCallback`; call `manager.abort()` in `disconnectedCallback` instead of tracking individual `removeEventListener` calls.
384
+
385
+ ## Contributing
386
+
387
+ Contributions from learners and developers are welcome. This is an experimental project, so please expect active iteration.
388
+
389
+ ## Contributors
390
+
391
+ <a href="https://github.com/chaxus/ran/graphs/contributors">
392
+ <img src="https://contrib.rocks/image?repo=chaxus/ran" />
393
+ </a>
394
+
395
+ ## Meta
396
+
397
+ [LICENSE (MIT)](/LICENSE)
package/README.zh-CN.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # ranui
2
2
 
3
- 基于 `Web Components` 组件方案
3
+ 基于 `Web Components` 的实验性组件库。组件使用 Shadow DOM 封装、CSS Token 主题体系,并提供 SSR / Declarative Shadow DOM 支持。
4
4
 
5
5
  ---
6
6
 
@@ -12,14 +12,25 @@
12
12
 
13
13
  **中文** | [English](./README.md)
14
14
 
15
+ ## ⚠️ 重要说明
16
+
17
+ 这是一个**实验性 UI 库**,处于早期开发阶段。虽然功能可用,但主要用于学习和实验。
18
+
19
+ **关键要点:**
20
+
21
+ - 🚧 **早期开发**: 功能仍在开发和完善中
22
+ - 🧪 **实验性**: API 可能会频繁变化
23
+ - 📚 **学习导向**: 主要用于学习 Web Components 和 UI 开发
24
+
15
25
  ## 特点
16
26
 
17
27
  1. **跨框架兼容:** 与 React, Vue, Preact, SolidJS, Svelte 等兼容。可以和遵循 W3C 标准的任何 JavaScript 项目集成。
18
- 2. **原生体验:** 易于入门,像使用本地 div 标签,简化项目大小和减少学习成本。
28
+ 2. **原生体验:** 易于入门,像使用原生 HTML 标签一样使用 `<r-button>`、`<r-modal>` 等自定义元素。
19
29
  3. **模块化设计:** 可选导入和全量导入,以增强可维护性和可伸缩性。
20
- 4. **交互式丰富文档:** 提供详细的交互式文档,并附有有效的示例子。
30
+ 4. **Shadow DOM 封装:** 组件内部样式默认隔离,并通过 CSS Token、`::part()` 和 `sheet` 属性开放可控的样式覆盖能力。
21
31
  5. **支持类型校验:** 基于 TypeScript 构建,具有类型支持,确保代码的健壮性和可维护性。
22
- 6. **持久和稳定:** 与框架 (React/vue) 无关,避免破坏性的更新,并确保持续的项目运行。
32
+ 6. **SSR 友好:** 通过 `defineSSR`、`renderToString` 和 Declarative Shadow DOM 支持服务端渲染场景。
33
+ 7. **无障碍:** ARIA 角色/状态、完整键盘导航、表单参与控件(`<r-checkbox>`/`<r-input>`/`<r-select>` 可被原生 `FormData` 收集)、live-region 提示,并尊重 `prefers-reduced-motion`。
23
34
 
24
35
  ## 安装
25
36
 
@@ -33,6 +44,37 @@ npm install ranui --save
33
44
 
34
45
  [See components and use examples](https://chaxus.github.io/ran/cn/src/ranui/)
35
46
 
47
+ ### 样式定制文档
48
+
49
+ 当前样式系统已统一为 CSS Token 与 `::part()` 规范。
50
+
51
+ - 样式覆盖规范:[docs/style-override.md](./docs/style-override.md)
52
+ - 完整 Token/Part 清单(自动生成): [docs/style-tokens-parts.md](./docs/style-tokens-parts.md)
53
+ - 面向使用方的公开样式 API(自动生成): [docs/style-tokens-public.md](./docs/style-tokens-public.md)
54
+ - 公开 Token 过滤配置:[docs/style-token-filter.json](./docs/style-token-filter.json)
55
+
56
+ 可通过以下命令刷新样式文档:
57
+
58
+ ```bash
59
+ pnpm doc:style
60
+ ```
61
+
62
+ ### 主题与主题包
63
+
64
+ RanUI 支持亮色、暗色与系统主题,并提供多个 CSS-only 主题包。
65
+
66
+ ```ts
67
+ import { initTheme, setTheme, setThemePack, setThemeToken } from 'ranui';
68
+ import 'ranui/theme-packs/pixel-retro';
69
+
70
+ initTheme();
71
+ setTheme('system');
72
+ setThemePack('pixel-retro');
73
+ setThemeToken('--ran-color-primary', '#2563eb');
74
+ ```
75
+
76
+ 可用主题包包括 `windows-98`、`windows-xp`、`system-6`、`wired`、`paper`、`pixel-retro`、`neo-brutalism`。使用 `setThemePack('default')` 可恢复默认主题包。
77
+
36
78
  ## 引入方式
37
79
 
38
80
  支持按需导入,以显著减少包体积大小
@@ -50,15 +92,17 @@ import 'ranui/style';
50
92
  如果遇到类型问题,可以选择手动导入类型文件
51
93
 
52
94
  ```ts
53
- import 'ranui/types';
54
- ```
55
-
56
- 或者
57
-
58
- ```ts
95
+ import 'ranui/typings';
96
+ // 或者
97
+ import 'ranui/dist/index.d.ts';
98
+ // 或者
99
+ import 'ranui/type';
100
+ // 或者
59
101
  import 'ranui/dist/typings';
60
102
  ```
61
103
 
104
+ 并不是都要,选一个能生效的就行
105
+
62
106
  也支持全量导入
63
107
 
64
108
  ```ts
@@ -113,7 +157,7 @@ import 'ranui/button';
113
157
  import 'ranui';
114
158
 
115
159
  const Button = document.createElement('r-button');
116
- Button.appendChild('this is button text');
160
+ Button.textContent = 'this is button text';
117
161
  document.body.appendChild(Button);
118
162
  ```
119
163
 
@@ -145,40 +189,175 @@ import 'ranui';
145
189
  ### tsx
146
190
 
147
191
  ```tsx
148
- // react 18
149
- import type { SyntheticEvent } from 'react';
150
- import React, { useRef } from 'react';
151
- import 'ranui';
192
+ import 'ranui/button';
152
193
 
153
- const FilePreview = () => {
154
- const ref = useRef<HTMLDivElement | null>(null);
155
- const uploadFile = (e: SyntheticEvent<HTMLDivElement>) => {
156
- if (ref.current) {
157
- const uploadFile = document.createElement('input');
158
- uploadFile.setAttribute('type', 'file');
159
- uploadFile.click();
160
- uploadFile.onchange = (e) => {
161
- const { files = [] } = uploadFile;
162
- if (files && files?.length > 0 && ref.current) {
163
- ref.current.setAttribute('src', '');
164
- const file = files[0];
165
- const url = URL.createObjectURL(file);
166
- ref.current.setAttribute('src', url);
167
- }
168
- };
169
- }
170
- };
194
+ const Button = () => {
171
195
  return (
172
196
  <div>
173
- <r-preview ref={ref}></r-preview>
174
- <r-button type="primary" onClick={uploadFile}>
175
- choose file to preview
176
- </r-button>
197
+ <r-button type="primary">button</r-button>
177
198
  </div>
178
199
  );
179
200
  };
180
201
  ```
181
202
 
203
+ ### Message 位置与容器配置
204
+
205
+ `window.message` 现已支持自定义顶部偏移、层级和挂载容器:
206
+
207
+ ```ts
208
+ import 'ranui/message';
209
+
210
+ const customRoot = document.getElementById('custom-message-root');
211
+
212
+ window.message?.success({
213
+ content: '保存成功',
214
+ duration: 2000,
215
+ top: 24,
216
+ zIndex: 3000,
217
+ getContainer: () => customRoot,
218
+ });
219
+ ```
220
+
221
+ `top` 支持 `number | string`(`24` 会转成 `24px`,`'2rem'` 会保留原单位)。
222
+
223
+ `zIndex` 支持 `number | string`。
224
+
225
+ `getContainer` 需要返回 `HTMLElement`;未传时默认挂载到 `document.body`。
226
+
227
+ ### 响应式原语
228
+
229
+ `signal`、`createEffect`、`computed`、`batch` 与 DOM builder 一起提供,用于在无框架依赖的情况下构建响应式页面区块。设计参考 SwiftUI 的 `@Observable`,并借鉴 Solid.js 补充了两个正确性改进:effect 重新执行前自动清理过期订阅;`batch()` 将多次 signal 写入合并为一次 effect flush,与 SwiftUI 自动合并变更的行为对齐。
230
+
231
+ ```ts
232
+ import { signal, createEffect, computed, batch, EventManager, Div, ButtonBuilder } from 'ranui/builder';
233
+
234
+ function initCounter(container: HTMLElement) {
235
+ const [count, setCount] = signal(0);
236
+ const [step, setStep] = signal(1);
237
+ const doubled = computed(() => count() * 2);
238
+ const scope = new EventManager();
239
+
240
+ const label = Div().build();
241
+ const view = Div()
242
+ .children(
243
+ label,
244
+ ButtonBuilder()
245
+ .text('+')
246
+ .listen(scope, 'click', () => setCount((n) => n + step())),
247
+ ButtonBuilder()
248
+ .text('重置')
249
+ .listen(
250
+ scope,
251
+ 'click',
252
+ () =>
253
+ batch(() => {
254
+ setCount(0);
255
+ setStep(1);
256
+ }), // 两次写入 → 一次 flush
257
+ ),
258
+ )
259
+ .build();
260
+
261
+ const dispose = createEffect(() => {
262
+ label.textContent = `${count()} (×2 = ${doubled()})`;
263
+ });
264
+
265
+ container.appendChild(view);
266
+ return () => {
267
+ dispose();
268
+ scope.abort();
269
+ }; // 区块销毁时清理
270
+ }
271
+ ```
272
+
273
+ 详细 API 请参考 [工具文档](./utils/README.zh-CN.md)。
274
+
275
+ ### 路由
276
+
277
+ RanUI 内置客户端路由,提供声明式组件和 JavaScript API 两种方式。
278
+
279
+ **声明式组件:**
280
+
281
+ ```html
282
+ <r-router>
283
+ <nav>
284
+ <r-link href="/">首页</r-link>
285
+ <r-link href="/about">关于</r-link>
286
+ </nav>
287
+
288
+ <r-route path="/" exact><h2>首页</h2></r-route>
289
+ <r-route path="/about"><h2>关于</h2></r-route>
290
+ <r-route path="/users/:id"><h2>用户详情</h2></r-route>
291
+ </r-router>
292
+ ```
293
+
294
+ **JavaScript API,含导航守卫:**
295
+
296
+ ```ts
297
+ import { createRouter } from 'ranui';
298
+
299
+ const router = createRouter({
300
+ mode: 'history',
301
+ routes: [
302
+ { path: '/', exact: true, meta: { title: '首页' } },
303
+ { path: '/users/:id', meta: { requiresAuth: true } },
304
+ ],
305
+ viewTransition: 'spa', // 'spa' | 'mpa' | 'both'
306
+ });
307
+
308
+ router.beforeEach((to, from, next) => {
309
+ if (to.meta?.requiresAuth && !isLoggedIn()) next('/login');
310
+ else next();
311
+ });
312
+
313
+ router.push('/users/42');
314
+ ```
315
+
316
+ 纯 MPA 站点(无需 JS router)可使用 `enableMpaViewTransitions()` 注入 `@view-transition { navigation: auto }`。共享元素过渡动画通过标准 `view-transition-name` CSS 属性实现。
317
+
318
+ ```ts
319
+ import { enableMpaViewTransitions } from 'ranui';
320
+ enableMpaViewTransitions();
321
+ ```
322
+
323
+ 完整 API(守卫、`onPageSwap`/`onPageReveal`、元素级动画命名)请参考 [路由文档](https://chaxus.github.io/ran/cn/src/ranui/router/)。
324
+
325
+ ### SSR & Builder (推荐)
326
+
327
+ 对于需要服务端渲染 (SSR) 或更声明式构建 UI 的场景,RanUI 内部使用 `builder`、SSR registry 与 Declarative Shadow DOM。组件会通过 `ensureShadowRoot` 复用已有 Shadow Root,并通过 `ensureShadowElement` 保持初始化幂等。
328
+
329
+ 源码内的 SSR 渲染示例:
330
+
331
+ ```ts
332
+ import { Button } from '@/components/button';
333
+ import { renderToString } from '@/utils/ssr';
334
+
335
+ const button = new Button();
336
+ button.setAttribute('effect', 'true');
337
+
338
+ // 输出包含 Declarative Shadow DOM 的 HTML 字符串
339
+ const html = renderToString(button);
340
+ ```
341
+
342
+ 更多细节请查看 [Utility Documentation](./utils/README.md)。
343
+
344
+ ## 组件开发约定
345
+
346
+ 新增或维护组件时请遵循当前包内约定:
347
+
348
+ - 组件继承 `RanElement`,不要直接继承浏览器环境下的 `HTMLElement`。
349
+ - 使用 `ensureShadowRoot` 创建或复用 Shadow Root,不要直接调用 `attachShadow`。
350
+ - 使用 `ensureShadowElement` 构建 Shadow DOM 子树,保证重复构造时幂等。
351
+ - `observedAttributes` 包含 `sheet`,并通过 `syncSheetAttribute` 同步组件级样式覆盖。
352
+ - `attributeChangedCallback` 首行使用 `if (old === next) return;` 避免重复同步。
353
+ - 使用 `defineSSR('r-name', Component)` 注册组件,而不是直接调用 `customElements.define`。
354
+ - 在 `index.ts` 中同时添加类型导出和副作用导入;在 `vite.config.ts`、`package.json` 中补齐独立入口与导出。
355
+ - 在 `connectedCallback` 中使用 `@/utils/builder` 导出的 `EventManager` 管理生命周期事件;在 `disconnectedCallback` 中调用 `manager.abort()` 一次清理所有监听器,不要逐个调用 `removeEventListener`。
356
+
357
+ ## 贡献
358
+
359
+ 我们欢迎学习者和开发者的贡献!这是一个实验性项目,请对开发过程保持耐心。
360
+
182
361
  ## 贡献者
183
362
 
184
363
  <a href="https://github.com/chaxus/ran/graphs/contributors">