@linloir/limr 0.0.0-stage → 0.1.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 (421) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +197 -2
  3. package/benchmarks/results/browser.json +237 -0
  4. package/benchmarks/results/node.json +75 -0
  5. package/benchmarks/results/selection.json +172 -0
  6. package/dist/THIRD_PARTY_LICENSES.txt +117 -0
  7. package/dist/base.css +451 -0
  8. package/dist/chunk-65V5OZ4G.js +3070 -0
  9. package/dist/chunk-65V5OZ4G.js.map +1 -0
  10. package/dist/chunk-6N6TFHEN.js +83 -0
  11. package/dist/chunk-6N6TFHEN.js.map +1 -0
  12. package/dist/chunk-7JF5HHVF.js +465 -0
  13. package/dist/chunk-7JF5HHVF.js.map +1 -0
  14. package/dist/chunk-ETHLPBKQ.js +1193 -0
  15. package/dist/chunk-ETHLPBKQ.js.map +1 -0
  16. package/dist/chunk-V2OG4Y3F.js +1 -0
  17. package/dist/chunk-V2OG4Y3F.js.map +1 -0
  18. package/dist/core/index.d.ts +54 -0
  19. package/dist/core/index.js +37 -0
  20. package/dist/core/index.js.map +1 -0
  21. package/dist/engine-43u8B4yt.d.ts +172 -0
  22. package/dist/extensions/index.d.ts +130 -0
  23. package/dist/extensions/index.js +50 -0
  24. package/dist/extensions/index.js.map +1 -0
  25. package/dist/fonts/KaTeX_AMS-Regular.ttf +0 -0
  26. package/dist/fonts/KaTeX_AMS-Regular.woff +0 -0
  27. package/dist/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  28. package/dist/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
  29. package/dist/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
  30. package/dist/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  31. package/dist/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
  32. package/dist/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
  33. package/dist/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  34. package/dist/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
  35. package/dist/fonts/KaTeX_Fraktur-Bold.woff +0 -0
  36. package/dist/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  37. package/dist/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
  38. package/dist/fonts/KaTeX_Fraktur-Regular.woff +0 -0
  39. package/dist/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  40. package/dist/fonts/KaTeX_Main-Bold.ttf +0 -0
  41. package/dist/fonts/KaTeX_Main-Bold.woff +0 -0
  42. package/dist/fonts/KaTeX_Main-Bold.woff2 +0 -0
  43. package/dist/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
  44. package/dist/fonts/KaTeX_Main-BoldItalic.woff +0 -0
  45. package/dist/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  46. package/dist/fonts/KaTeX_Main-Italic.ttf +0 -0
  47. package/dist/fonts/KaTeX_Main-Italic.woff +0 -0
  48. package/dist/fonts/KaTeX_Main-Italic.woff2 +0 -0
  49. package/dist/fonts/KaTeX_Main-Regular.ttf +0 -0
  50. package/dist/fonts/KaTeX_Main-Regular.woff +0 -0
  51. package/dist/fonts/KaTeX_Main-Regular.woff2 +0 -0
  52. package/dist/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
  53. package/dist/fonts/KaTeX_Math-BoldItalic.woff +0 -0
  54. package/dist/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  55. package/dist/fonts/KaTeX_Math-Italic.ttf +0 -0
  56. package/dist/fonts/KaTeX_Math-Italic.woff +0 -0
  57. package/dist/fonts/KaTeX_Math-Italic.woff2 +0 -0
  58. package/dist/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
  59. package/dist/fonts/KaTeX_SansSerif-Bold.woff +0 -0
  60. package/dist/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  61. package/dist/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
  62. package/dist/fonts/KaTeX_SansSerif-Italic.woff +0 -0
  63. package/dist/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  64. package/dist/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
  65. package/dist/fonts/KaTeX_SansSerif-Regular.woff +0 -0
  66. package/dist/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  67. package/dist/fonts/KaTeX_Script-Regular.ttf +0 -0
  68. package/dist/fonts/KaTeX_Script-Regular.woff +0 -0
  69. package/dist/fonts/KaTeX_Script-Regular.woff2 +0 -0
  70. package/dist/fonts/KaTeX_Size1-Regular.ttf +0 -0
  71. package/dist/fonts/KaTeX_Size1-Regular.woff +0 -0
  72. package/dist/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  73. package/dist/fonts/KaTeX_Size2-Regular.ttf +0 -0
  74. package/dist/fonts/KaTeX_Size2-Regular.woff +0 -0
  75. package/dist/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  76. package/dist/fonts/KaTeX_Size3-Regular.ttf +0 -0
  77. package/dist/fonts/KaTeX_Size3-Regular.woff +0 -0
  78. package/dist/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  79. package/dist/fonts/KaTeX_Size4-Regular.ttf +0 -0
  80. package/dist/fonts/KaTeX_Size4-Regular.woff +0 -0
  81. package/dist/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  82. package/dist/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
  83. package/dist/fonts/KaTeX_Typewriter-Regular.woff +0 -0
  84. package/dist/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  85. package/dist/fonts/LICENSE.txt +93 -0
  86. package/dist/fonts/manifest.json +2204 -0
  87. package/dist/fonts/maple-7.9-bold-005-5530d8c1d6.woff2 +0 -0
  88. package/dist/fonts/maple-7.9-bold-00f-1179d800a7.woff2 +0 -0
  89. package/dist/fonts/maple-7.9-bold-010-9974a942b1.woff2 +0 -0
  90. package/dist/fonts/maple-7.9-bold-011-9b9230baf2.woff2 +0 -0
  91. package/dist/fonts/maple-7.9-bold-012-c2545292b1.woff2 +0 -0
  92. package/dist/fonts/maple-7.9-bold-013-877b19fe05.woff2 +0 -0
  93. package/dist/fonts/maple-7.9-bold-014-6acf4a4e92.woff2 +0 -0
  94. package/dist/fonts/maple-7.9-bold-015-c889146da3.woff2 +0 -0
  95. package/dist/fonts/maple-7.9-bold-018-419ad5f31f.woff2 +0 -0
  96. package/dist/fonts/maple-7.9-bold-027-dd414483da.woff2 +0 -0
  97. package/dist/fonts/maple-7.9-bold-028-263744fbc7.woff2 +0 -0
  98. package/dist/fonts/maple-7.9-bold-029-ae3a163d8b.woff2 +0 -0
  99. package/dist/fonts/maple-7.9-bold-02a-515f0a82c2.woff2 +0 -0
  100. package/dist/fonts/maple-7.9-bold-02b-0823c5133d.woff2 +0 -0
  101. package/dist/fonts/maple-7.9-bold-02c-296fd5db38.woff2 +0 -0
  102. package/dist/fonts/maple-7.9-bold-02d-0bb4734363.woff2 +0 -0
  103. package/dist/fonts/maple-7.9-bold-02e-25415fed50.woff2 +0 -0
  104. package/dist/fonts/maple-7.9-bold-02f-19ed79a84e.woff2 +0 -0
  105. package/dist/fonts/maple-7.9-bold-030-21962a0327.woff2 +0 -0
  106. package/dist/fonts/maple-7.9-bold-031-d216fc0d68.woff2 +0 -0
  107. package/dist/fonts/maple-7.9-bold-032-d90ba34901.woff2 +0 -0
  108. package/dist/fonts/maple-7.9-bold-033-55ea37ea00.woff2 +0 -0
  109. package/dist/fonts/maple-7.9-bold-034-bc8649f808.woff2 +0 -0
  110. package/dist/fonts/maple-7.9-bold-035-03604fe40b.woff2 +0 -0
  111. package/dist/fonts/maple-7.9-bold-036-44fc7f77b2.woff2 +0 -0
  112. package/dist/fonts/maple-7.9-bold-037-8a1440f155.woff2 +0 -0
  113. package/dist/fonts/maple-7.9-bold-038-c65a618d5c.woff2 +0 -0
  114. package/dist/fonts/maple-7.9-bold-039-be05db966d.woff2 +0 -0
  115. package/dist/fonts/maple-7.9-bold-03a-ca3a10002d.woff2 +0 -0
  116. package/dist/fonts/maple-7.9-bold-03b-067b32e10b.woff2 +0 -0
  117. package/dist/fonts/maple-7.9-bold-03c-4da4f84530.woff2 +0 -0
  118. package/dist/fonts/maple-7.9-bold-03d-f0fe6a68c8.woff2 +0 -0
  119. package/dist/fonts/maple-7.9-bold-03e-0e97f89433.woff2 +0 -0
  120. package/dist/fonts/maple-7.9-bold-03f-3289a5e3bc.woff2 +0 -0
  121. package/dist/fonts/maple-7.9-bold-040-232dcd0d7b.woff2 +0 -0
  122. package/dist/fonts/maple-7.9-bold-041-e25e9a9c41.woff2 +0 -0
  123. package/dist/fonts/maple-7.9-bold-042-d64a2b1824.woff2 +0 -0
  124. package/dist/fonts/maple-7.9-bold-043-2d01cf5e52.woff2 +0 -0
  125. package/dist/fonts/maple-7.9-bold-044-0ab808b5f1.woff2 +0 -0
  126. package/dist/fonts/maple-7.9-bold-045-e41dc814b4.woff2 +0 -0
  127. package/dist/fonts/maple-7.9-bold-046-d5fe26344d.woff2 +0 -0
  128. package/dist/fonts/maple-7.9-bold-047-f322ded671.woff2 +0 -0
  129. package/dist/fonts/maple-7.9-bold-048-0cdcf7257f.woff2 +0 -0
  130. package/dist/fonts/maple-7.9-bold-049-aa280ca08a.woff2 +0 -0
  131. package/dist/fonts/maple-7.9-bold-04a-f51ad4d92c.woff2 +0 -0
  132. package/dist/fonts/maple-7.9-bold-04b-4e8c6fa3ee.woff2 +0 -0
  133. package/dist/fonts/maple-7.9-bold-04c-9bfdf4d743.woff2 +0 -0
  134. package/dist/fonts/maple-7.9-bold-04d-83ac1f5bb3.woff2 +0 -0
  135. package/dist/fonts/maple-7.9-bold-04e-bcec89804a.woff2 +0 -0
  136. package/dist/fonts/maple-7.9-bold-04f-d31e83b6ce.woff2 +0 -0
  137. package/dist/fonts/maple-7.9-bold-070-8a3b0fdf98.woff2 +0 -0
  138. package/dist/fonts/maple-7.9-bold-071-5bee0a62c4.woff2 +0 -0
  139. package/dist/fonts/maple-7.9-bold-072-97d891eee4.woff2 +0 -0
  140. package/dist/fonts/maple-7.9-bold-073-4d4c36aca0.woff2 +0 -0
  141. package/dist/fonts/maple-7.9-bold-074-6d3cc01e90.woff2 +0 -0
  142. package/dist/fonts/maple-7.9-bold-075-eab42ad657.woff2 +0 -0
  143. package/dist/fonts/maple-7.9-bold-076-2b1f5c4a42.woff2 +0 -0
  144. package/dist/fonts/maple-7.9-bold-077-1db0d50873.woff2 +0 -0
  145. package/dist/fonts/maple-7.9-bold-078-bc6994a28f.woff2 +0 -0
  146. package/dist/fonts/maple-7.9-bold-079-ad6c1757ce.woff2 +0 -0
  147. package/dist/fonts/maple-7.9-bold-07a-d08ed2b87d.woff2 +0 -0
  148. package/dist/fonts/maple-7.9-bold-07f-2f4af46cc6.woff2 +0 -0
  149. package/dist/fonts/maple-7.9-bold-0fc-42ed90884c.woff2 +0 -0
  150. package/dist/fonts/maple-7.9-bold-780-261fac1b24.woff2 +0 -0
  151. package/dist/fonts/maple-7.9-bold-781-377319a91b.woff2 +0 -0
  152. package/dist/fonts/maple-7.9-bold-782-3106f0be62.woff2 +0 -0
  153. package/dist/fonts/maple-7.9-bold-783-74fbfa8648.woff2 +0 -0
  154. package/dist/fonts/maple-7.9-bold-784-8570270664.woff2 +0 -0
  155. package/dist/fonts/maple-7.9-bold-785-cee8de1ded.woff2 +0 -0
  156. package/dist/fonts/maple-7.9-bold-786-5ab5ff7149.woff2 +0 -0
  157. package/dist/fonts/maple-7.9-bold-787-844b4c4373.woff2 +0 -0
  158. package/dist/fonts/maple-7.9-bold-788-01731198ab.woff2 +0 -0
  159. package/dist/fonts/maple-7.9-bold-789-f4c75fa806.woff2 +0 -0
  160. package/dist/fonts/maple-7.9-bold-78a-4370321ec6.woff2 +0 -0
  161. package/dist/fonts/maple-7.9-bold-78b-5cd412b56f.woff2 +0 -0
  162. package/dist/fonts/maple-7.9-bold-78c-f88e331085.woff2 +0 -0
  163. package/dist/fonts/maple-7.9-bold-78d-1b9b77f6e8.woff2 +0 -0
  164. package/dist/fonts/maple-7.9-bold-latin-3b4b2831f3.woff2 +0 -0
  165. package/dist/fonts/maple-7.9-bolditalic-005-d59fef8639.woff2 +0 -0
  166. package/dist/fonts/maple-7.9-bolditalic-00f-1bbda7af69.woff2 +0 -0
  167. package/dist/fonts/maple-7.9-bolditalic-010-5cdd4b46a7.woff2 +0 -0
  168. package/dist/fonts/maple-7.9-bolditalic-011-0d1f1ae687.woff2 +0 -0
  169. package/dist/fonts/maple-7.9-bolditalic-012-4ceb000b2e.woff2 +0 -0
  170. package/dist/fonts/maple-7.9-bolditalic-013-ad0a4f4313.woff2 +0 -0
  171. package/dist/fonts/maple-7.9-bolditalic-014-94d54b71b3.woff2 +0 -0
  172. package/dist/fonts/maple-7.9-bolditalic-015-7aede280da.woff2 +0 -0
  173. package/dist/fonts/maple-7.9-bolditalic-018-f21221b1c2.woff2 +0 -0
  174. package/dist/fonts/maple-7.9-bolditalic-027-d23d0e80a4.woff2 +0 -0
  175. package/dist/fonts/maple-7.9-bolditalic-028-23bd6f24df.woff2 +0 -0
  176. package/dist/fonts/maple-7.9-bolditalic-029-c481c0ad50.woff2 +0 -0
  177. package/dist/fonts/maple-7.9-bolditalic-02a-1c134be68e.woff2 +0 -0
  178. package/dist/fonts/maple-7.9-bolditalic-02b-3feb29ecfd.woff2 +0 -0
  179. package/dist/fonts/maple-7.9-bolditalic-02c-de8cc5a063.woff2 +0 -0
  180. package/dist/fonts/maple-7.9-bolditalic-02d-ea25c21fad.woff2 +0 -0
  181. package/dist/fonts/maple-7.9-bolditalic-02e-e68d6bd335.woff2 +0 -0
  182. package/dist/fonts/maple-7.9-bolditalic-02f-c88d1e92dc.woff2 +0 -0
  183. package/dist/fonts/maple-7.9-bolditalic-030-f26fefe87e.woff2 +0 -0
  184. package/dist/fonts/maple-7.9-bolditalic-031-f2aa1b8e22.woff2 +0 -0
  185. package/dist/fonts/maple-7.9-bolditalic-032-c4fafc4aa6.woff2 +0 -0
  186. package/dist/fonts/maple-7.9-bolditalic-033-288a1639ca.woff2 +0 -0
  187. package/dist/fonts/maple-7.9-bolditalic-034-7c982125bc.woff2 +0 -0
  188. package/dist/fonts/maple-7.9-bolditalic-035-fd1575dea2.woff2 +0 -0
  189. package/dist/fonts/maple-7.9-bolditalic-036-f6bf406353.woff2 +0 -0
  190. package/dist/fonts/maple-7.9-bolditalic-037-8ac1466916.woff2 +0 -0
  191. package/dist/fonts/maple-7.9-bolditalic-038-e9f7fed6a6.woff2 +0 -0
  192. package/dist/fonts/maple-7.9-bolditalic-039-6f90d42310.woff2 +0 -0
  193. package/dist/fonts/maple-7.9-bolditalic-03a-30c9409a7e.woff2 +0 -0
  194. package/dist/fonts/maple-7.9-bolditalic-03b-4f1741e9e9.woff2 +0 -0
  195. package/dist/fonts/maple-7.9-bolditalic-03c-6551c74e78.woff2 +0 -0
  196. package/dist/fonts/maple-7.9-bolditalic-03d-c8e2b07106.woff2 +0 -0
  197. package/dist/fonts/maple-7.9-bolditalic-03e-c3e98613d4.woff2 +0 -0
  198. package/dist/fonts/maple-7.9-bolditalic-03f-f1c580bad4.woff2 +0 -0
  199. package/dist/fonts/maple-7.9-bolditalic-040-32e8260076.woff2 +0 -0
  200. package/dist/fonts/maple-7.9-bolditalic-041-39805a0ed7.woff2 +0 -0
  201. package/dist/fonts/maple-7.9-bolditalic-042-13b4d84cd3.woff2 +0 -0
  202. package/dist/fonts/maple-7.9-bolditalic-043-d85780d0bd.woff2 +0 -0
  203. package/dist/fonts/maple-7.9-bolditalic-044-1b5eb624d7.woff2 +0 -0
  204. package/dist/fonts/maple-7.9-bolditalic-045-ad0b4f8762.woff2 +0 -0
  205. package/dist/fonts/maple-7.9-bolditalic-046-9966021b3a.woff2 +0 -0
  206. package/dist/fonts/maple-7.9-bolditalic-047-100d4f6f4e.woff2 +0 -0
  207. package/dist/fonts/maple-7.9-bolditalic-048-a0a1e8b29c.woff2 +0 -0
  208. package/dist/fonts/maple-7.9-bolditalic-049-0806f9b3cc.woff2 +0 -0
  209. package/dist/fonts/maple-7.9-bolditalic-04a-28fdef78b3.woff2 +0 -0
  210. package/dist/fonts/maple-7.9-bolditalic-04b-6e93ef0086.woff2 +0 -0
  211. package/dist/fonts/maple-7.9-bolditalic-04c-50b8da6282.woff2 +0 -0
  212. package/dist/fonts/maple-7.9-bolditalic-04d-f93277723d.woff2 +0 -0
  213. package/dist/fonts/maple-7.9-bolditalic-04e-72e2644690.woff2 +0 -0
  214. package/dist/fonts/maple-7.9-bolditalic-04f-4f234f1802.woff2 +0 -0
  215. package/dist/fonts/maple-7.9-bolditalic-070-a3658a8a23.woff2 +0 -0
  216. package/dist/fonts/maple-7.9-bolditalic-071-4987e49732.woff2 +0 -0
  217. package/dist/fonts/maple-7.9-bolditalic-072-e587fa72cd.woff2 +0 -0
  218. package/dist/fonts/maple-7.9-bolditalic-073-2aca01fdf6.woff2 +0 -0
  219. package/dist/fonts/maple-7.9-bolditalic-074-ae89f99a60.woff2 +0 -0
  220. package/dist/fonts/maple-7.9-bolditalic-075-5a77191665.woff2 +0 -0
  221. package/dist/fonts/maple-7.9-bolditalic-076-4c54a87277.woff2 +0 -0
  222. package/dist/fonts/maple-7.9-bolditalic-077-e47dce25ee.woff2 +0 -0
  223. package/dist/fonts/maple-7.9-bolditalic-078-b0b720dab6.woff2 +0 -0
  224. package/dist/fonts/maple-7.9-bolditalic-079-316ee96f6a.woff2 +0 -0
  225. package/dist/fonts/maple-7.9-bolditalic-07a-b10ccb8107.woff2 +0 -0
  226. package/dist/fonts/maple-7.9-bolditalic-07d-5667cb3be1.woff2 +0 -0
  227. package/dist/fonts/maple-7.9-bolditalic-07f-2ac6735ff8.woff2 +0 -0
  228. package/dist/fonts/maple-7.9-bolditalic-0fc-52171ca01e.woff2 +0 -0
  229. package/dist/fonts/maple-7.9-bolditalic-780-3c090c5f89.woff2 +0 -0
  230. package/dist/fonts/maple-7.9-bolditalic-781-ca4077b4fa.woff2 +0 -0
  231. package/dist/fonts/maple-7.9-bolditalic-782-42c3d52206.woff2 +0 -0
  232. package/dist/fonts/maple-7.9-bolditalic-783-d72840dd37.woff2 +0 -0
  233. package/dist/fonts/maple-7.9-bolditalic-784-b9ca097e50.woff2 +0 -0
  234. package/dist/fonts/maple-7.9-bolditalic-785-b81dec6af9.woff2 +0 -0
  235. package/dist/fonts/maple-7.9-bolditalic-786-76c266f6f5.woff2 +0 -0
  236. package/dist/fonts/maple-7.9-bolditalic-787-403bd73766.woff2 +0 -0
  237. package/dist/fonts/maple-7.9-bolditalic-788-71a4b8c2c5.woff2 +0 -0
  238. package/dist/fonts/maple-7.9-bolditalic-789-94527f3fa4.woff2 +0 -0
  239. package/dist/fonts/maple-7.9-bolditalic-78a-81918568b8.woff2 +0 -0
  240. package/dist/fonts/maple-7.9-bolditalic-78b-d0302b4bfe.woff2 +0 -0
  241. package/dist/fonts/maple-7.9-bolditalic-78c-e864792049.woff2 +0 -0
  242. package/dist/fonts/maple-7.9-bolditalic-78d-105ff69bf4.woff2 +0 -0
  243. package/dist/fonts/maple-7.9-bolditalic-latin-96412d165b.woff2 +0 -0
  244. package/dist/fonts/maple-7.9-italic-005-23b09473f8.woff2 +0 -0
  245. package/dist/fonts/maple-7.9-italic-00f-e9bf4dd93c.woff2 +0 -0
  246. package/dist/fonts/maple-7.9-italic-010-22933d6d77.woff2 +0 -0
  247. package/dist/fonts/maple-7.9-italic-011-71b0157ddc.woff2 +0 -0
  248. package/dist/fonts/maple-7.9-italic-012-b751ab3752.woff2 +0 -0
  249. package/dist/fonts/maple-7.9-italic-013-530b1d3f8b.woff2 +0 -0
  250. package/dist/fonts/maple-7.9-italic-014-0e842f6749.woff2 +0 -0
  251. package/dist/fonts/maple-7.9-italic-015-642211b03a.woff2 +0 -0
  252. package/dist/fonts/maple-7.9-italic-018-0c5b0001c6.woff2 +0 -0
  253. package/dist/fonts/maple-7.9-italic-027-9a09afbbb1.woff2 +0 -0
  254. package/dist/fonts/maple-7.9-italic-028-93fea67326.woff2 +0 -0
  255. package/dist/fonts/maple-7.9-italic-029-7d7627d4cc.woff2 +0 -0
  256. package/dist/fonts/maple-7.9-italic-02a-88e76d051b.woff2 +0 -0
  257. package/dist/fonts/maple-7.9-italic-02b-7d9219748b.woff2 +0 -0
  258. package/dist/fonts/maple-7.9-italic-02c-049df19d84.woff2 +0 -0
  259. package/dist/fonts/maple-7.9-italic-02d-663fc73c6e.woff2 +0 -0
  260. package/dist/fonts/maple-7.9-italic-02e-a98ed33998.woff2 +0 -0
  261. package/dist/fonts/maple-7.9-italic-02f-8ef9d93d09.woff2 +0 -0
  262. package/dist/fonts/maple-7.9-italic-030-74885d994d.woff2 +0 -0
  263. package/dist/fonts/maple-7.9-italic-031-4cf66c5d65.woff2 +0 -0
  264. package/dist/fonts/maple-7.9-italic-032-a608b7aed4.woff2 +0 -0
  265. package/dist/fonts/maple-7.9-italic-033-2978f66e55.woff2 +0 -0
  266. package/dist/fonts/maple-7.9-italic-034-38f7a0bf87.woff2 +0 -0
  267. package/dist/fonts/maple-7.9-italic-035-5cc45cd3b7.woff2 +0 -0
  268. package/dist/fonts/maple-7.9-italic-036-ca92d327e5.woff2 +0 -0
  269. package/dist/fonts/maple-7.9-italic-037-f887681c7d.woff2 +0 -0
  270. package/dist/fonts/maple-7.9-italic-038-06150b88f8.woff2 +0 -0
  271. package/dist/fonts/maple-7.9-italic-039-761da333b7.woff2 +0 -0
  272. package/dist/fonts/maple-7.9-italic-03a-1408ddaf2c.woff2 +0 -0
  273. package/dist/fonts/maple-7.9-italic-03b-1542b3b67c.woff2 +0 -0
  274. package/dist/fonts/maple-7.9-italic-03c-479f2f5011.woff2 +0 -0
  275. package/dist/fonts/maple-7.9-italic-03d-0f10590b11.woff2 +0 -0
  276. package/dist/fonts/maple-7.9-italic-03e-8b93e0ee0e.woff2 +0 -0
  277. package/dist/fonts/maple-7.9-italic-03f-2bd8815e3e.woff2 +0 -0
  278. package/dist/fonts/maple-7.9-italic-040-b85023679a.woff2 +0 -0
  279. package/dist/fonts/maple-7.9-italic-041-eb881b7b92.woff2 +0 -0
  280. package/dist/fonts/maple-7.9-italic-042-01490a139e.woff2 +0 -0
  281. package/dist/fonts/maple-7.9-italic-043-ffb21b6c4c.woff2 +0 -0
  282. package/dist/fonts/maple-7.9-italic-044-05cd1a1b14.woff2 +0 -0
  283. package/dist/fonts/maple-7.9-italic-045-1270935363.woff2 +0 -0
  284. package/dist/fonts/maple-7.9-italic-046-857077eab1.woff2 +0 -0
  285. package/dist/fonts/maple-7.9-italic-047-ca57774cc3.woff2 +0 -0
  286. package/dist/fonts/maple-7.9-italic-048-20969d6307.woff2 +0 -0
  287. package/dist/fonts/maple-7.9-italic-049-4066aa1a18.woff2 +0 -0
  288. package/dist/fonts/maple-7.9-italic-04a-1ed360d580.woff2 +0 -0
  289. package/dist/fonts/maple-7.9-italic-04b-2eba62d76b.woff2 +0 -0
  290. package/dist/fonts/maple-7.9-italic-04c-2f4effc460.woff2 +0 -0
  291. package/dist/fonts/maple-7.9-italic-04d-d858c0a9c1.woff2 +0 -0
  292. package/dist/fonts/maple-7.9-italic-04e-a19eb0289f.woff2 +0 -0
  293. package/dist/fonts/maple-7.9-italic-04f-8addde15f2.woff2 +0 -0
  294. package/dist/fonts/maple-7.9-italic-070-f0bd641f1c.woff2 +0 -0
  295. package/dist/fonts/maple-7.9-italic-071-e6ac564431.woff2 +0 -0
  296. package/dist/fonts/maple-7.9-italic-072-e6fea65bca.woff2 +0 -0
  297. package/dist/fonts/maple-7.9-italic-073-71621c00dc.woff2 +0 -0
  298. package/dist/fonts/maple-7.9-italic-074-4bd488962a.woff2 +0 -0
  299. package/dist/fonts/maple-7.9-italic-075-2838d95bd6.woff2 +0 -0
  300. package/dist/fonts/maple-7.9-italic-076-94e02ecc03.woff2 +0 -0
  301. package/dist/fonts/maple-7.9-italic-077-32c536ab6b.woff2 +0 -0
  302. package/dist/fonts/maple-7.9-italic-078-18256447bd.woff2 +0 -0
  303. package/dist/fonts/maple-7.9-italic-079-7a735e61cf.woff2 +0 -0
  304. package/dist/fonts/maple-7.9-italic-07a-2b57a6a905.woff2 +0 -0
  305. package/dist/fonts/maple-7.9-italic-07d-8ba1bbfb50.woff2 +0 -0
  306. package/dist/fonts/maple-7.9-italic-07f-0240d80c69.woff2 +0 -0
  307. package/dist/fonts/maple-7.9-italic-0fc-e5b20a692e.woff2 +0 -0
  308. package/dist/fonts/maple-7.9-italic-780-093cc90a9b.woff2 +0 -0
  309. package/dist/fonts/maple-7.9-italic-781-f6ec357f6d.woff2 +0 -0
  310. package/dist/fonts/maple-7.9-italic-782-5ca2ef4ddd.woff2 +0 -0
  311. package/dist/fonts/maple-7.9-italic-783-7450baabee.woff2 +0 -0
  312. package/dist/fonts/maple-7.9-italic-784-14a93cc4bd.woff2 +0 -0
  313. package/dist/fonts/maple-7.9-italic-785-d62fb8b4d7.woff2 +0 -0
  314. package/dist/fonts/maple-7.9-italic-786-1d2959dc83.woff2 +0 -0
  315. package/dist/fonts/maple-7.9-italic-787-70ae947136.woff2 +0 -0
  316. package/dist/fonts/maple-7.9-italic-788-cf1f156ebf.woff2 +0 -0
  317. package/dist/fonts/maple-7.9-italic-789-f0b79f9680.woff2 +0 -0
  318. package/dist/fonts/maple-7.9-italic-78a-5a53fd7870.woff2 +0 -0
  319. package/dist/fonts/maple-7.9-italic-78b-40be093bfd.woff2 +0 -0
  320. package/dist/fonts/maple-7.9-italic-78c-3b11646f8e.woff2 +0 -0
  321. package/dist/fonts/maple-7.9-italic-78d-b13ed8c48b.woff2 +0 -0
  322. package/dist/fonts/maple-7.9-italic-latin-befeb2b610.woff2 +0 -0
  323. package/dist/fonts/maple-7.9-regular-005-90bff107ac.woff2 +0 -0
  324. package/dist/fonts/maple-7.9-regular-00f-001e503e53.woff2 +0 -0
  325. package/dist/fonts/maple-7.9-regular-010-374da1ebb4.woff2 +0 -0
  326. package/dist/fonts/maple-7.9-regular-011-8f91fcc9e7.woff2 +0 -0
  327. package/dist/fonts/maple-7.9-regular-012-e4ec3016ef.woff2 +0 -0
  328. package/dist/fonts/maple-7.9-regular-013-e779e13a12.woff2 +0 -0
  329. package/dist/fonts/maple-7.9-regular-014-6b833ad501.woff2 +0 -0
  330. package/dist/fonts/maple-7.9-regular-015-4e058c4c42.woff2 +0 -0
  331. package/dist/fonts/maple-7.9-regular-018-6f776bc19b.woff2 +0 -0
  332. package/dist/fonts/maple-7.9-regular-027-92c0be3439.woff2 +0 -0
  333. package/dist/fonts/maple-7.9-regular-028-154c8c3039.woff2 +0 -0
  334. package/dist/fonts/maple-7.9-regular-029-9d88470aca.woff2 +0 -0
  335. package/dist/fonts/maple-7.9-regular-02a-7a94cb26f2.woff2 +0 -0
  336. package/dist/fonts/maple-7.9-regular-02b-1725b841c2.woff2 +0 -0
  337. package/dist/fonts/maple-7.9-regular-02c-e080c435d6.woff2 +0 -0
  338. package/dist/fonts/maple-7.9-regular-02d-a6461c4708.woff2 +0 -0
  339. package/dist/fonts/maple-7.9-regular-02e-2e55d9b957.woff2 +0 -0
  340. package/dist/fonts/maple-7.9-regular-02f-858a76fa1f.woff2 +0 -0
  341. package/dist/fonts/maple-7.9-regular-030-bbbe80f8ad.woff2 +0 -0
  342. package/dist/fonts/maple-7.9-regular-031-cafc1258ad.woff2 +0 -0
  343. package/dist/fonts/maple-7.9-regular-032-0ca83ecceb.woff2 +0 -0
  344. package/dist/fonts/maple-7.9-regular-033-6cb995f2e7.woff2 +0 -0
  345. package/dist/fonts/maple-7.9-regular-034-5877222be6.woff2 +0 -0
  346. package/dist/fonts/maple-7.9-regular-035-988d8f2d26.woff2 +0 -0
  347. package/dist/fonts/maple-7.9-regular-036-e91853e3ca.woff2 +0 -0
  348. package/dist/fonts/maple-7.9-regular-037-3eed60f359.woff2 +0 -0
  349. package/dist/fonts/maple-7.9-regular-038-5681f42a4a.woff2 +0 -0
  350. package/dist/fonts/maple-7.9-regular-039-07036fe444.woff2 +0 -0
  351. package/dist/fonts/maple-7.9-regular-03a-5495eead93.woff2 +0 -0
  352. package/dist/fonts/maple-7.9-regular-03b-d07b1d6c1e.woff2 +0 -0
  353. package/dist/fonts/maple-7.9-regular-03c-6291400ee0.woff2 +0 -0
  354. package/dist/fonts/maple-7.9-regular-03d-3787a51772.woff2 +0 -0
  355. package/dist/fonts/maple-7.9-regular-03e-ce4d945844.woff2 +0 -0
  356. package/dist/fonts/maple-7.9-regular-03f-95e98b329c.woff2 +0 -0
  357. package/dist/fonts/maple-7.9-regular-040-693b769fe8.woff2 +0 -0
  358. package/dist/fonts/maple-7.9-regular-041-7b436d2c09.woff2 +0 -0
  359. package/dist/fonts/maple-7.9-regular-042-9ad884cd73.woff2 +0 -0
  360. package/dist/fonts/maple-7.9-regular-043-372231e8e2.woff2 +0 -0
  361. package/dist/fonts/maple-7.9-regular-044-9922b540b1.woff2 +0 -0
  362. package/dist/fonts/maple-7.9-regular-045-8a88a91c22.woff2 +0 -0
  363. package/dist/fonts/maple-7.9-regular-046-82859ede10.woff2 +0 -0
  364. package/dist/fonts/maple-7.9-regular-047-6532babd62.woff2 +0 -0
  365. package/dist/fonts/maple-7.9-regular-048-abfdc5d7ce.woff2 +0 -0
  366. package/dist/fonts/maple-7.9-regular-049-adb7fa9ed3.woff2 +0 -0
  367. package/dist/fonts/maple-7.9-regular-04a-f3f794b1cb.woff2 +0 -0
  368. package/dist/fonts/maple-7.9-regular-04b-715211b8dd.woff2 +0 -0
  369. package/dist/fonts/maple-7.9-regular-04c-c6f978d10d.woff2 +0 -0
  370. package/dist/fonts/maple-7.9-regular-04d-61019a1c8f.woff2 +0 -0
  371. package/dist/fonts/maple-7.9-regular-04e-806d6efe85.woff2 +0 -0
  372. package/dist/fonts/maple-7.9-regular-04f-99d19aa8db.woff2 +0 -0
  373. package/dist/fonts/maple-7.9-regular-070-e94ba9445d.woff2 +0 -0
  374. package/dist/fonts/maple-7.9-regular-071-057314b533.woff2 +0 -0
  375. package/dist/fonts/maple-7.9-regular-072-a7699beb84.woff2 +0 -0
  376. package/dist/fonts/maple-7.9-regular-073-ebe1bd9ef4.woff2 +0 -0
  377. package/dist/fonts/maple-7.9-regular-074-722db38100.woff2 +0 -0
  378. package/dist/fonts/maple-7.9-regular-075-150ff7187b.woff2 +0 -0
  379. package/dist/fonts/maple-7.9-regular-076-c14595e715.woff2 +0 -0
  380. package/dist/fonts/maple-7.9-regular-077-6c88302a32.woff2 +0 -0
  381. package/dist/fonts/maple-7.9-regular-078-549b294c78.woff2 +0 -0
  382. package/dist/fonts/maple-7.9-regular-079-5131c42759.woff2 +0 -0
  383. package/dist/fonts/maple-7.9-regular-07a-c0dad221b5.woff2 +0 -0
  384. package/dist/fonts/maple-7.9-regular-07f-5cf5ebe065.woff2 +0 -0
  385. package/dist/fonts/maple-7.9-regular-0fc-b644c0c6d9.woff2 +0 -0
  386. package/dist/fonts/maple-7.9-regular-780-c6000d472a.woff2 +0 -0
  387. package/dist/fonts/maple-7.9-regular-781-86409ab7f7.woff2 +0 -0
  388. package/dist/fonts/maple-7.9-regular-782-9cd950637c.woff2 +0 -0
  389. package/dist/fonts/maple-7.9-regular-783-105c4d02df.woff2 +0 -0
  390. package/dist/fonts/maple-7.9-regular-784-00c042af97.woff2 +0 -0
  391. package/dist/fonts/maple-7.9-regular-785-022568d0b8.woff2 +0 -0
  392. package/dist/fonts/maple-7.9-regular-786-90b6f3aef5.woff2 +0 -0
  393. package/dist/fonts/maple-7.9-regular-787-e2888596c9.woff2 +0 -0
  394. package/dist/fonts/maple-7.9-regular-788-3416e1fda3.woff2 +0 -0
  395. package/dist/fonts/maple-7.9-regular-789-9ffc917b0b.woff2 +0 -0
  396. package/dist/fonts/maple-7.9-regular-78a-4a921d07f6.woff2 +0 -0
  397. package/dist/fonts/maple-7.9-regular-78b-9d71c5327b.woff2 +0 -0
  398. package/dist/fonts/maple-7.9-regular-78c-9ec048314b.woff2 +0 -0
  399. package/dist/fonts/maple-7.9-regular-78d-46a2ebd113.woff2 +0 -0
  400. package/dist/fonts/maple-7.9-regular-latin-59c752ba1d.woff2 +0 -0
  401. package/dist/fonts/maple.css +315 -0
  402. package/dist/index.d.ts +9 -0
  403. package/dist/index.js +132 -0
  404. package/dist/index.js.map +1 -0
  405. package/dist/math-renderer-L6DOH4RX.js +21 -0
  406. package/dist/math-renderer-L6DOH4RX.js.map +1 -0
  407. package/dist/math.css +1 -0
  408. package/dist/react/index.d.ts +112 -0
  409. package/dist/react/index.js +57 -0
  410. package/dist/react/index.js.map +1 -0
  411. package/dist/styles.css +451 -0
  412. package/dist/translations-BliabrPd.d.ts +310 -0
  413. package/docs/api.md +161 -0
  414. package/docs/extensions.md +309 -0
  415. package/docs/implementation.md +79 -0
  416. package/docs/performance.md +84 -0
  417. package/docs/styles.md +103 -0
  418. package/docs/visual-upgrade.md +148 -0
  419. package/examples/assistant.tsx +52 -0
  420. package/examples/notes.tsx +73 -0
  421. package/package.json +110 -3
@@ -0,0 +1,309 @@
1
+ # 扩展指南
2
+
3
+ 语法、节点渲染、角注和选区操作遵循同一套公开接口。`standard()` 只是默认模块列表,没有第二套内部专用模块接口。
4
+
5
+ ## 独立语法模块
6
+
7
+ `defineBlock({name, component, tags?, directives?, selection?})` 同时注册标签和指令适配器:
8
+
9
+ ```tsx
10
+ const warning = defineBlock({
11
+ name: 'warning',
12
+ component: ({ children, pending }) => <aside aria-busy={pending}>{children}</aside>,
13
+ });
14
+ ```
15
+
16
+ ```markdown
17
+ <warning>
18
+
19
+ **Markdown** 内容。
20
+
21
+ </warning>
22
+
23
+ :::warning
24
+ 也可以用指令语法。
25
+ :::
26
+ ```
27
+
28
+ 组件接收 `node`(含 attributes/children/原文 position)、`children`、`source`、`pending` 和 `renderChildren(nodes)`。后者直接渲染已解析子树,不需要重新解析字符串。按需渲染答案/提示时可保留对应节点,以原始坐标交还给 `renderChildren`。字面量节点(如 code/inlineCode)使用 `renderValue(tokens?)` 保留源码映射和装饰;token 只需提供正文 `content`、相对 node.value 的 UTF-16 `offset` 和可选 `style`。
29
+
30
+ 属性中的可见文字使用 `renderAttribute('title')`:内置 JSX/指令适配器保留属性值的原文位置(不含引号),因此标题同样支持部分选择、高亮和角注,实体解码后仍能回到原始坐标。直接输出 `node.attributes.title` 则只会得到普通文字。自定义解析器可提供 `node.attributeNodes[name]`(带 `value` / `position` 的文本节点)接入同一链路。
31
+
32
+ 需要行内标签、全新 token 或 AST 改写时用 `defineExtension()`:
33
+
34
+ ```tsx
35
+ const badge = defineExtension({
36
+ name: 'badge', tags: ['badge'], display: 'inline', scope: 'local',
37
+ components: { badge: ({ children }) => <span className="badge">{children}</span> },
38
+ });
39
+ ```
40
+
41
+ `micromark` 接收 micromark syntax extensions 数组,`mdast` 接收 mdast from-markdown extensions 数组。`transform(root, {source, streaming, documentId})` 可以把自定义 AST 节点变换为新的节点类型,再通过 `components[nodeType]` 渲染。保留原始 position,不修改原始 source。没有 position 的生成内容无法提供精确选区映射。
42
+
43
+ `transform` 默认为全文语义。声明 `scope: 'local'` 的承诺是:已有完整顶层区块的输出不依赖其后的区块,不依赖正在变化的全文上下文;输入末尾重新解析就能保持语义正确。编号、跨段关系等插件应保留默认全文模式。内置 Markdown 引用/脚注定义有单独的全文失效机制。未闭合标签会使用原文回退,完成后重试,结束后总会完整解析。
44
+
45
+ 扩展 name、tag、directive 冲突会抛错。用 `replaceExtension(existing, replacement)` 按 name 替换;组件覆盖可直接放 `components`,角注覆盖可直接放 `annotationTypes`。不做隐式的 parser 覆盖。
46
+
47
+ ## 默认模块
48
+
49
+ | 工厂 / name | 能力和配置 |
50
+ | --- | --- |
51
+ | `gfm()` / `gfm` | 表格、任务列表、删除线、自动链接、标准脚注 |
52
+ | `math({macros?, strict?})` / `math` | `$...$`、`$$...$$`,KaTeX,不信任执行性命令 |
53
+ | `codeHighlight({languages?, lightTheme?, darkTheme?, eager?, maxLength?})` / `code-highlight` | Shiki;默认靠近视口加载,超过 100,000 字符保留纯代码 |
54
+ | `definition({component?})` / `definition` | `<definition>`,title 属性或 `<title>`,可选 `<content>` |
55
+ | `question({component?})` / `question` | 问题正文、提示、答案、选择题 |
56
+ | `extras({component?})` / `extras` | `<extras><extra title="..." url="..." desc="..." /></extras>` |
57
+ | `video({component?, resolveUrl?, loading?})` / `video` | `<video>` / `<md-video>`,自动识别 native / youtube / bilibili |
58
+ | `figures(options?)` / `figures` | `<figures>` 响应式图组、`<figure>` 单图、图注与图片复制 |
59
+ | `citation(annotationTypeOverrides?)` / `citation` | `<ref>` / `<citation>`,citation 角注类型 |
60
+ | `translations({defaultMode?})` / `translations` | `<translations>`、`<origin>`、`<translation>`;原文、译文、对照与段末切换角标 |
61
+
62
+ 问题的子标签为 `question-content`、`question-hint`、`question-answer`、`question-sel-grp` 和 `question-sel`。选择组用 `answer="[0,2]"` 配置从 0 开始的正确选项编号,`multi="true"` 开启多选。它们是内容组件,不包含提问/聊天角注或服务连接。
63
+
64
+ 视频使用 `url` 或 `src`,默认从 URL 识别平台,也可显式指定 `provider="youtube"`、`"bilibili"`、`"native"`。支持 YouTube watch/短链接/embed/shorts/live 地址及起始时间、Bilibili BV/av 地址及分 P。播放器靠近视口 200px 时才挂载真实 iframe/原生 video,不自动播放;可用 `video({ loading: 'click' })` 或单个标签的 `loading="click"` 改成点击后加载,`"eager"` 则立即加载。视频居中、默认最大宽 560px,16:9;右上角复用公式复制按钮,复制原始 Markdown。
65
+
66
+ YouTube 使用标准 `youtube.com/embed` 地址,iframe 的 `referrerPolicy="strict-origin-when-cross-origin"` 保留来源站点。播放器的来源要求见 [YouTube 官方文档](https://developers.google.com/youtube/iframe_api_reference#Events)(缺少来源身份可能报 153)。远程平台仍决定视频能否嵌入;本地回归使用请求拦截验证 URL、加载时机和 iframe 参数,不代替真实播放验收。未知标签不执行 HTML;自定义组件对自己的远程请求和 URL 处理负责。
67
+
68
+ ## 图片与论文图组
69
+
70
+ ```markdown
71
+ <figures columns="2" rows="2" min-width="220" min-height="120" max-width="560" max-height="480">
72
+
73
+ <figure src="/paper/a.png" alt="实验 A" caption="(a) 实验 A" />
74
+
75
+ <figure>
76
+
77
+ ![实验 B](/paper/b.png)
78
+
79
+ <figcaption>**(b)** 实验 B,支持 Markdown 图注。</figcaption>
80
+
81
+ </figure>
82
+
83
+ <figcaption>图 1 · 两个实验的比较。</figcaption>
84
+
85
+ </figures>
86
+ ```
87
+
88
+ `figure` 可以独立使用,支持 `src` / `url` 属性,或内部的 Markdown 图片、图片引用及 `<img src="..." alt="..." />`。每个 `figure` 放一张图,多图使用 `figures`;图注可用 `caption` 属性、`<figcaption>` 或 `<caption>`。`id` 可以作为普通 Markdown 页内链接的目标。属性文字保留源文坐标;富文本图注仍可选择、高亮和加角注。也支持 `:::figures`、`:::figure`、`:::figcaption` 指令,单图可写作 `::figure{src="/image.png" caption="图注"}`。
89
+
90
+ 图片在各网格行中垂直居中,图注居中对齐。选择按“图片、该图图注、下一张图片、该图图注、总图注”的阅读顺序进行;属性顺序不同也不会把未选中的图注混进选区。图片高亮描绘实际图片的边框(或所选的下划线样式),图注仍按文字高亮。图片角标叠在图片右下角,保留按钮主题底色;图注角标跟随文字。复制按钮位于外框内部。
91
+
92
+ | 属性 | 默认值 | 行为 |
93
+ | --- | --- | --- |
94
+ | `min-width` / `min-height` | `220` / `120` | 图片可读尺寸下限,用于决定是否增加列;窄于下限时优先适应容器 |
95
+ | `max-width` / `max-height` | `560` / `480` | 图片尺寸上限,保持比例、不裁切;`none` 或 `false` 取消对应上限 |
96
+ | `columns`(或 `cols`) | 自动 | 指定列数,上限 24 |
97
+ | `rows` | 自动 | 单独指定时按图数推导列数;同时指定行列时预留行,超出内容继续排入新行 |
98
+ | `responsive` | `true` | 显式列数无法满足可读尺寸时逐步减列;`false` 保留列数,允许小图 |
99
+ | `gap` | `16` | 图组间距,像素 |
100
+
101
+ 尺寸接受非负数字或 `px`,模块工厂对应驼峰参数,例如 `figures({ maxHeight: 360, maxWidth: false })`。`figures` 的尺寸限制由内部 `figure` 继承,单图属性可覆盖。最小高度也保留媒体区域的留白;长宽比使上下限无法同时满足时,最大尺寸及容器宽度优先,图片不会变形。
102
+
103
+ 自动布局从一列开始,结合图片加载后的真实比例:当前列达到可用最大宽度后,还有空间容纳另一张达到最小宽、高的图,才增加一列。最大高度同样会限制可用宽度。明确关闭全部尺寸上限时,自动布局保持一列;需要多列可设置 `columns` / `rows`。这里的上限约束图片,不裁切较长的图注。
104
+
105
+ 单图按钮复制 **图片 URL**,沿用 infilearn 的行为;相对 URL 保留原来的相对形式。图组按钮复制完整的 **Markdown 源码**。复制不读取图片二进制,也不要求图片服务器允许跨域读取;浏览器拒绝剪贴板写入时会显示失败提示。
106
+
107
+ ## 分段译文与全局参数
108
+
109
+ ```markdown
110
+ <translations default="origin">
111
+
112
+ <origin>
113
+
114
+ Original **Markdown**. It can include lists, images and citations.
115
+
116
+ </origin>
117
+
118
+ <translation>
119
+
120
+ 翻译后的 **Markdown**,同样可以包含列表、图片和引用。
121
+
122
+ </translation>
123
+
124
+ </translations>
125
+ ```
126
+
127
+ `default` 接受 `origin`、`translation`、`both`,默认 `origin`。对照时先显示译文,再显示原文。角标位于最后一段显示内容的末尾,用圆角线条的原文页、译文页、并排页图标表示状态,悬浮提示及无障碍名称说明当前状态和下一步操作,依次切换“原 → 译 → 对照 → 原”。内容高度和透明度共同过渡,支持中途反向切换与减少动态效果偏好;隐藏内容保持挂载并设置 `inert`,其角注不会生成同步侧栏卡片。流式生成期间只有一侧内容时,先显示已到达的内容。
128
+
129
+ 这是 `translations()` 模块通过公共 `InlineMarker` 和 `renderChildren(nodes, { trailing })` 注入的操作,不生成 `Annotation`,不打开浮层或侧栏。`InlineMarker` 也可用于插件自己的纯操作角标;最后一个节点是段落时 `trailing` 放在段内,其余块类型放在块后。
130
+
131
+ ```tsx
132
+ const [mode, setMode] = useState<TranslationMode | undefined>();
133
+
134
+ <Reader
135
+ source={source}
136
+ parameters={{ translationMode: mode, onTranslationModeChange: setMode }}
137
+ />
138
+ ```
139
+
140
+ `translationMode` 覆盖各块的 `default` 和本地选择;设回 `undefined` 后恢复各块原来的本地选择。传入 `onTranslationModeChange` 时,角标会请求修改全局模式;只有全局值而没有回调时,角标只显示当前模式,不允许局部绕过外部控制。不同阅读器的参数相互隔离。
141
+
142
+ 插件参数是通用能力,不需要修改 LiMR 内核:
143
+
144
+ ```tsx
145
+ import { useRendererParameter, type RendererExtension } from '@linloir/limr';
146
+
147
+ declare module '@linloir/limr' {
148
+ interface RendererParameters { glossaryDetail?: 'short' | 'full' }
149
+ }
150
+
151
+ const glossary: RendererExtension = {
152
+ name: 'glossary', tags: ['glossary'],
153
+ parameters: { glossaryDetail: 'short' },
154
+ components: {
155
+ glossary: ({ children }) => {
156
+ const detail = useRendererParameter('glossaryDetail');
157
+ return <aside data-detail={detail}>{children}</aside>;
158
+ },
159
+ },
160
+ };
161
+
162
+ <Markdown source={source} plugins={[glossary]} parameters={{ glossaryDetail: 'full' }} />
163
+ ```
164
+
165
+ 模块在 `RendererExtension.parameters` 注册默认值;宿主通过 `Reader`、`Markdown` 或 `DocumentProvider` 的 `parameters` 覆盖。后注册模块可以覆盖同名默认值。hook 仅订阅所请求的值,参数变化不会重新解析 Markdown,卡片中的 `AnnotationMarkdown` 也继承宿主参数。
166
+
167
+ ## 角注类型
168
+
169
+ ```tsx
170
+ const glossary = defineAnnotation<{ title: string; body: string }>({
171
+ type: 'glossary', label: '术语', icon: '◎', color: '#548b74',
172
+ Content: ({ data, presentation }) => <div>
173
+ <strong>{data?.title}</strong>
174
+ <AnnotationMarkdown source={data?.body ?? ''} />
175
+ </div>,
176
+ });
177
+ ```
178
+
179
+ 注册类型与放置角注是独立操作。类型定义 icon、可选 Marker 组件、内容组件和可选的数据加载器;数据通过 annotations、文档命令或自定义语法 transform 生成。
180
+
181
+ `icon` / `Marker` 只负责图形;按钮、点击、悬浮、可访问标签和大小由 LiMR 管理。推荐带方形 `viewBox`、`currentColor` 的 SVG,图形在 viewBox 中居中,不需要写外层按钮、sup 或尺寸。图标槽会限制超大 SVG/图片、嵌套组件的尺寸与溢出,统一普通和插件角标的尺寸,并重置装饰性 HTML 包裹层的字体基线。复杂自定义图形仍应在自己的 viewBox 内留出边界;槽位不能修复 SVG 内部画偏或留白不对称。可通过 `--limr-mark-size` 修改整套角标尺寸。
182
+
183
+ `Content` 接收 `annotation`、`data`、`presentation`(preview/expanded/sidebar)、`expanded`、`editing`、`loading`、`error`、`retry`。可以按展示模式显示摘要或完整 UI;`editing` 来自 `editAnnotation(id)` 或 `addAnnotation(annotation, { edit: true })`。`load(annotation, {signal})` 只在需要展示内容时调用,必须遵守 signal;同一注释在侧栏和浮层之间共享请求和结果。更换不可变 annotation 对象会换资源标识;显式 `invalidateAnnotation(id)` 或 `retry()` 可重新加载。缓存按阅读器隔离,结果采用有限 LRU;不会把一个应用用户的数据共享给另一阅读器。
184
+
185
+ `color` 同时作为角标、默认侧栏标题/装饰条/淡色背景及公共浮层标题的主题色,未激活的装饰条也保留主题色。`sidebar.color`、`borderColor`、`titleColor`、`textColor`、`excerptColor`、`previewColor` 可分别覆盖侧栏主题色、未激活装饰条、标题、正文、关联文本和标题下的预览;不指定正文颜色时沿用阅读器正文色,支持 CSS 颜色和变量。`Content` 和 `Preview` 可以给局部元素单独设置颜色,不会被骨架强制覆盖。多条注释共用一张卡片时,首条注释决定卡片主题,各条目的内部富文本仍由模块控制。
186
+
187
+ 默认侧栏卡片顶部始终显示灰色的关联文本区(`.limr-sidebar-reference`),单行省略,完整文本放在 `title` 中。选区角注展示关联范围的可读文本,去掉 Markdown 标记并解码实体;嵌入式 `<ref>` 展示所在段落。它由 LiMR 根据 occurrence 生成,展开后仍保留,模块无需在 Content 内重复渲染。页面级 `renderCard` 接管时可自行选择是否提供关联区域。
188
+
189
+ 收起时,标题下面的摘要由模块的 `sidebar.Preview` 组件渲染。它接收 `AnnotationSidebarPreviewProps<T>`:`annotation`、`data`(本地 `annotation.data`)、`occurrence`、同组的 `annotations` 和上方的 `referenceText`。同组首条注释的模块负责整组预览,可以自行合并摘要或显示数量。默认最多两行,`sidebar.previewLines` 可设置正整数行数;展开后预览收起,改为显示完整 `Content`。设 `Preview: false` 或组件返回 `null` 可关闭预览,不留下空白间距。未配置预览的模块保持只显示标题。
190
+
191
+ 预览不会触发 `load`,也不需要挂载完整内容。远程模块应随本地注释携带摘要字段;摘要更新后预览跟随 `updateAnnotation()` 更新。建议使用简短文字或轻量富文本,不要在 Preview 里启动完整会话或远程加载。返回链接、按钮时,它们保留自身交互,其余预览区域点击展开卡片。
192
+
193
+ ```tsx
194
+ defineAnnotation<{ question: string; answer: string }>({
195
+ type: 'assistant', label: '询问助手', color: '#8b5cf6',
196
+ Content: ({ data }) => <AnnotationMarkdown source={data?.answer ?? ''} />,
197
+ sidebar: {
198
+ Preview: ({ data }) => data?.question ? <span title={data.question}>{data.question}</span> : null,
199
+ previewLines: 2,
200
+ textColor: 'var(--limr-text, #1a1a1a)',
201
+ previewColor: 'var(--limr-secondary, #7b756e)',
202
+ },
203
+ });
204
+ ```
205
+
206
+ Citation 的默认预览依次使用 `summary`、`description`、安全 URL、标题;摘要和描述去掉 Markdown 标记并解码实体,同组引用按顺序拼接。`summary` 可通过注释 data 或 `<citation summary="简短摘要" ... />` 提供;有 description 时,展开显示完整 description。`citation({ sidebar: { Preview: MyPreview, previewLines: 3 } })` 可替换展示,`Preview: false` 可关闭。只覆盖颜色或行数会保留默认预览。
207
+
208
+ **模块内容边距约定:** 默认卡片由灰色关联区和 `.limr-sidebar-card-body` 两块组成,中间保留 `1px` 分隔(`--limr-sidebar-reference-gap`)。两区共享 `--limr-sidebar-padding-inline`,默认 `10px`,关联文本、标题、预览和展开正文的文字起点必须对齐;不要在模块根节点再加水平 padding、margin 或 text-indent。修改横向留白应调整共享变量,不要分别改两区。逻辑方向属性保证 RTL 使用同一约定。
209
+
210
+ 骨架负责标题到预览/正文的间隔;通用内容区底部比顶部多 2px,补足文字基线带来的视觉差异。模块只负责内部段落间距,不要再给 `Content` 或 `Preview` 根节点添加卡片 padding 或用于补偿底部的空段落。骨架清除内容根节点首尾 margin;自定义包裹层中的段落边距由模块处理,Markdown 内容推荐使用 `AnnotationMarkdown`,它会清除末段 margin,包含 source-binding 包裹层和绘制层的情况。不同字体的视觉留白仍需按实际字形检查。
211
+
212
+ Citation 保留专用间距:多条目的底部补偿及条目间隔不受通用骨架的 2px 调整影响;单条目展开时底部比多条目少 2px。请分别验证带描述/不带描述、单条/多条、普通文本/Markdown、加载中/流式回答和浅色/深色,不要通过统一增减所有卡片的底部 padding 修正某一种内容。
213
+
214
+ 模块通过 `overlay.Card` 接管悬浮和展开卡片的全部内部 UI,包括标题、正文、操作和底栏。`AnnotationOverlayCardProps<T>` 提供 `annotation`、`occurrence`、`presentation`、`expanded`、`pinned`、`canExpand`、`expand()`、`collapse()`、`close()`,以及已经接入各条目 `Content` 和缓存的 `children`。LiMR 只保留浮层定位、挂载、动画和焦点管理。自定义正文可用 `data-limr-card-body` 标记淡入区域。
215
+
216
+ 可以选用公共布局组件,标题仍由模块决定:
217
+
218
+ ```tsx
219
+ import { AnnotationCard, type AnnotationOverlayCardProps } from '@linloir/limr';
220
+
221
+ function ConversationCard(props: AnnotationOverlayCardProps) {
222
+ return <AnnotationCard {...props} title="询问助手" />;
223
+ }
224
+ ```
225
+
226
+ 不需要默认布局时直接返回自己的 header、正文和操作按钮即可。`Card` 使用同一个组件处理两种 presentation,避免切换时丢失输入状态。兼容旧的仅 `Content` 定义时,默认布局以类型 `label` 作为标题。
227
+
228
+ 浮层是否允许展开、展开的布局由角注模块声明,默认不展开。点击没有展开能力的角标会固定预览,触屏也可滚动阅读、点击关闭;Citation 默认采用此行为。
229
+
230
+ ```tsx
231
+ defineAnnotation({
232
+ type: 'conversation', label: '对话', Content: Conversation,
233
+ overlay: { Card: ConversationCard, expand: { placement: 'center', width: 680, height: '80dvh' } },
234
+ sidebar: { collapseOnContentClick: false },
235
+ });
236
+
237
+ defineAnnotation({
238
+ type: 'detail', label: '详细说明', Content: Detail,
239
+ overlay: { expand: { placement: 'anchor' } },
240
+ sidebar: { collapseOnContentClick: true },
241
+ });
242
+ ```
243
+
244
+ `overlay.expand` 可以是 `false`、`AnnotationExpansion`,也可以是 `(annotation) => false | AnnotationExpansion`,按数据选择。`placement: 'anchor'` 保持预览靠近角标的一侧边缘,在原地按内容增高;`'center'` 在整个页面的 visual viewport 居中,不受正文列宽或内部滚动容器限制。可设 `width`、`height`、`maxHeight`(数字为 px,字符串为 CSS 长度);省略 height 时按内容高度,省略 width 时 anchor 保持预览宽度、center 使用 640px。`overlay.previewWidth` 可单独设置预览宽度。尺寸始终受可视区域限制,包括移动键盘。
245
+
246
+ 展开从脚注预览的位置和尺寸放大,关闭缩回该位置和尺寸并淡出;触摸和工具栏直接打开时会先隐式测量实际预览。外壳独立变形,文字和控件保持正常比例。展开、收起复用同一组件与请求,模块可根据 `presentation` 改变内容;关闭动画可被重新打开打断,完成后才卸载。
247
+
248
+ `sidebar.collapseOnContentClick` 默认 false,Citation 也保持 false。Citation 条目悬浮时显示下划线,有 URL 时点击标题或说明可以跳转;标题栏负责展开/收起。自定义模块启用该选项后,展开卡片的普通文字/空白区域可点击收起,链接、按钮、输入框、选中文本和 `[data-limr-card-interactive]` 区域保留自身交互。模块仍可用 `useLiMR().activateAnnotation(null)` 自行关闭。多个角注共用一个角标时,首个角注决定浮层 Card 和布局,`children` 保留所有条目各自的 Content;侧栏仅在所有角注类型均启用后才允许点击内容收起;页面级 `renderCard` 可完全替换侧栏卡片行为。
249
+
250
+ 自定义语法可以生成 `annotationDefinition` 节点,其 `annotation` 字段为完整数据;生成 `annotationReference` 节点,其 `annotationIds` 为引用的 ID 数组,position 对应角标位置。也可以完全不添加语法,直接给用户选中的范围添加外部 annotation。
251
+
252
+ ## 工具栏插件与展开面板
253
+
254
+ 工具栏默认包含高亮和复制。插件将 `SelectionAction` 放入 `actions` 即可追加入口;`icon` 是必填字段,推荐 `currentColor`、圆润线端和方形 viewBox。LiMR 将 SVG、图片或嵌套图形限制到统一的图标槽中;内部图形的留白和视觉重量仍需由插件作者控制。内置的 `ToolIcon` 提供同一设计语言的常用图形。
255
+
256
+ ```tsx
257
+ import { ToolIcon, defineExtension, type ToolbarActionContext } from '@linloir/limr';
258
+
259
+ function Settings({ context }: { context: ToolbarActionContext }) {
260
+ return <button disabled={context.busy} onClick={() => void context.run(current => {
261
+ current.addAnnotation({
262
+ id: crypto.randomUUID(), type: 'my-note',
263
+ range: current.selection.syntax.ranges[0], data: { text: current.selection.text },
264
+ });
265
+ current.clearSelection();
266
+ })}>保存选中文本</button>;
267
+ }
268
+
269
+ const noteTool = defineExtension({
270
+ name: 'note-tool',
271
+ actions: [{
272
+ id: 'note-tool:add', label: '记一笔', icon: <ToolIcon name="note" />,
273
+ run: context => context.expand(),
274
+ renderExpanded: context => <Settings context={context} />,
275
+ }],
276
+ // 另行注册 my-note 的 annotationTypes,定义卡片内容。
277
+ });
278
+ ```
279
+
280
+ `renderExpanded` 自动接入悬浮展开、键盘入口、尺寸约束与选区保留;触屏点击动作本身展开。可选 `onHover(context)` 接入自定义悬浮行为。`context.annotations` 是当前片段绑定的所有 annotation,`context.highlight` 是其中的高亮 annotation;`label(context)` / `icon(context)` 可以随状态改变。展开内容的操作使用 `context.run(operation)` 统一处理忙碌与异常。完整自绘 `render` 槽位的控件与可访问性由模块自行管理。
281
+
282
+ 面板的最大可用高度由 LiMR 决定,通过 `--limr-toolbar-panel-height` 暴露;默认上限 260px,样式包可设置 `--limr-toolbar-panel-max-height`。插件使用自然高度和响应式宽度,骨架在实际溢出时提供不占内容宽度的细滚动条,无需插件重复处理滚动。第三方皮肤可覆盖工具栏的颜色、圆角、字体与面板宽高,详见[样式指南](styles.md)。
283
+
284
+ [notes.tsx](../examples/notes.tsx) 将旁注、笔记、提问和脚注拆成四个直接操作,使用 `addAnnotation(..., { edit: true })` 创建带原文 quote 的锚点、共享高亮并进入编辑。宽屏在侧栏编辑,窄屏直接打开卡片;草稿存入 annotation data,跨布局切换仍然保留。编辑框透明无边框、随内容增高,支持 Markdown 换行及 Ctrl/Cmd+Enter 提交。修改、删除、取消和提交采用右对齐的图标文字按钮,复用 `.limr-underline`。Playground 的模块样式在 `playground/playground.css` 的 `.demo-note-*` 中,移植时可替换为应用自己的样式。插件的卡片内容与业务状态由插件负责,骨架只管理定位、激活、编辑状态和滚动。
285
+
286
+ ## 助手插件的协作方式
287
+
288
+ [assistant.tsx](../examples/assistant.tsx) 是完整、经过浏览器验证的例子:
289
+
290
+ 1. 插件在 `actions` 注册选区菜单入口。
291
+ 2. 动作从选区创建一个具有原始范围和 quote 的自定义 annotation。
292
+ 3. 用 `activateAnnotation(id)` 打开卡片,清空菜单选区。
293
+ 4. 应用 adapter 产生 `AsyncIterable<string>`;每个片段调用 `updateAnnotation()`。
294
+ 5. 自定义 Content 使用 `AnnotationMarkdown streaming` 渲染回答。
295
+ 6. Reader 卸载时中止请求,动作不再更新已卸载的文档。
296
+
297
+ 示例支持 `prompt(selection)` 生成首个问题,保存到 `data.question` 并传给 `adapter.answer({ selection, question, signal })`。`sidebar.Preview` 显示这个问题,流式回答只更新答案,不覆盖问题;中文页面可配置 `prompt: selection => \`请解释「${selection.text}」。\``。接入已有对话时,应用也可提供自己的 Preview 展示首条用户消息。
298
+
299
+ 示例只从 `@linloir/limr` 的公共入口导入,可以复制到应用中使用。真实 Codex 集成可以实现同一个 adapter,也可以自行实现更复杂的组件、对话状态、输入框和动作。LiMR 不把助手的传输、认证、问题/答案 schema 写入内核。
300
+
301
+ 插件任务的取消信号来自动作的生命周期上下文。若业务还需要“停止生成”、重试、切换会话等控制,可由插件自己的 AbortController 与 context.signal 联动。角标保留哪个历史回答、是否保存、如何鉴权,也由应用决定。
302
+
303
+ ## 作为独立包分发
304
+
305
+ 插件导出一个返回 `RendererExtension` 的工厂,消费者通过 `plugins={[yourPlugin(options)]}` 添加即可。`plugins` 会追加到 `extensions`(未指定时为 `standard()`),无须消费者重复列出默认模块。以 `@linloir/limr` 和 `react` 为 peerDependencies,导出 ESM 和类型声明;不要把另一份 React 或 LiMR 打包进插件。
306
+
307
+ [`examples/packages/reading-tools`](../examples/packages/reading-tools) 演示一个同时提供语法、角注内容和选区动作的独立包,[`paper-theme`](../examples/packages/paper-theme) 是独立 CSS 包。`pnpm test:package` 会先打包,再在仓库外安装这些包与 LiMR,验证 React 18/19 的类型、SSR、浏览器交互和 portal 样式。示例包名未发布到 npm;发布自己的包时替换 name、version,并移除 private。
308
+
309
+ 仅样式包无需 React 或解析器依赖。使用 `appearance` 属性选择作用域,使多个阅读器和浮层使用正确主题;详见[样式指南](styles.md)。
@@ -0,0 +1,79 @@
1
+ # LiMR implementation and acceptance
2
+
3
+ The agreed scope is a standalone React Markdown package preserving the original
4
+ renderer's reading style and capabilities while making syntax,
5
+ annotation types, selection actions, layout and resource loading extensible.
6
+ Long-document reading and streaming output are equal first-release requirements.
7
+ All original special syntax modules belong to LiMR's default extensions, with
8
+ individual imports, replacement and opt-out. There is no platform-specific preset.
9
+ Default annotations are reference citations only; highlighting is a core capability.
10
+ Question/note/chat annotations belong to application plugins. Question content
11
+ blocks remain a default syntax extension. Plugins can contribute menu actions,
12
+ annotation types and streaming content updates through document commands.
13
+
14
+ ## Required deliverables
15
+
16
+ - DOM-free document engine, original UTF-16 offsets, immutable document snapshots,
17
+ stable blocks, incremental append with reference dependency invalidation.
18
+ - CommonMark/GFM, math, highlighting, images, figures, videos, questions,
19
+ definitions, extra reading, citations; each special capability is an extension.
20
+ - Public parser and component extension APIs; replace/disable built-ins; no
21
+ execution of Markdown-supplied JavaScript or unregistered HTML.
22
+ - Markdown, DocumentProvider, Reader, TableOfContents, AnnotationSidebar,
23
+ AnnotationOverlay, SelectionToolbar; standalone and composed use.
24
+ - Generic annotation types, occurrence anchors, custom icons/content, recursive
25
+ Markdown with isolated document scopes and shared configuration/resources.
26
+ - Raw, syntax-complete and block selections; extensible atomic selection behavior;
27
+ versioned selection snapshots and programmable highlights.
28
+ - Scroll-root convention, sidebar collision handling and custom positioning;
29
+ wrapping/fixed-title/hidden-scrollbar TOC with active-item following.
30
+ - Pointer previews, touch/click expansion, content-column sizing, viewport and
31
+ keyboard accommodation, focus/keyboard behavior and configurable portals.
32
+ - Bounded caches, deduplicated/cancellable optional data loaders, no implicit CDN
33
+ font/style requests; local math assets and optional self-hosted font guidance.
34
+ - Classic light/dark theme, SSR/multiple documents, streaming incomplete syntax,
35
+ final equivalence and opt-in follow-output without fighting user scrolling.
36
+ - Package exports/types/assets; examples and API/extension documentation.
37
+ - Core/SSR tests, real-browser interaction/layout tests, pack/consumer smoke,
38
+ visual review and reproducible static/streaming performance measurements.
39
+
40
+ ## Decisions
41
+
42
+ Use mdast/micromark for standards-compatible parsing. Share the parsed document
43
+ across all views. Roll back the final top-level block on append; maintain a
44
+ definition environment for suffix parsing; invalidate previous nodes when
45
+ document-wide definitions change. Unknown whole-document transforms fall back
46
+ to a full parse. Never claim arbitrary plugins are incrementally safe.
47
+
48
+ The public core has no React or DOM runtime dependency. React renderers own
49
+ their DOM, including marks. Layout reads, selection and document changes use
50
+ separate subscription channels. Source offsets always refer to the original
51
+ input, including legacy tag syntax.
52
+
53
+ Do not claim performance parity until the measurements cover equivalent
54
+ features. Virtualization is optional future work unless a verified implementation
55
+ preserves selection/search/printing; the default reading mode retains document
56
+ semantics.
57
+
58
+ ## Verification completed
59
+
60
+ - `pnpm check`: strict TypeScript checking, 32 core/resource/runtime/SSR tests,
61
+ ESM declaration build and copied local math assets.
62
+ - `pnpm test:browser`: 11 Chromium tests covering desktop rendering, three
63
+ selection variants, highlights, TOC follow/clamping, shared internal scroll
64
+ roots, sidebar alignment, pointer and touch cards, reduced visual viewport,
65
+ plugin streaming/cancellation, multiple documents, SSR hydration, resource
66
+ handoff/cache invalidation and decoded native-text source mapping.
67
+ - `pnpm test:package`: install the actual tarball in isolated React 18.3 and
68
+ React 19 consumers; check public TypeScript declarations, SSR, extension
69
+ imports and every math font URL. Verify the core entry with a loader that
70
+ rejects React imports. The resulting archive is copied to `artifacts/`.
71
+ - Production Node and isolated-browser benchmarks are reproducible; complete
72
+ measurements and limitations are in `docs/performance.md`.
73
+ - Desktop, content-block and mobile plugin screenshots are in `docs/screenshots/`.
74
+ The playground explicitly supplies its own local demo font; package CSS does
75
+ not fetch a body/code font.
76
+
77
+ The assistant example uses a local simulated adapter. Real service connections
78
+ and authentication belong to the consuming application. No remote publication,
79
+ real mobile-device acceptance or arbitrary-plugin performance claim is included.
@@ -0,0 +1,84 @@
1
+ # 性能测量
2
+
3
+ 日期:2026-10-12。环境为 Intel Core i7-13700、WSL2/Linux、Node 20.19.5、Chromium 156.0.8078.4。React 19 production build;对照为 react-markdown 10.1.0 + remark-gfm 4.0.1。
4
+
5
+ 以下是本机固定夹具的实测值。浏览器静态渲染与基线接近;流式追加减少了明显的重复工作。几个百分点的静态差异不应解读为所有设备和内容上的胜负;本轮 Node 长文 SSR 波动较大,也没有显示出性能优势。
6
+
7
+ ## 浏览器
8
+
9
+ 双方都渲染同一份 GFM:标题、强调、链接、行内代码、列表和表格,使用相同排版样式。LiMR 开启正常交互和原文映射能力。这里只比较正文,不把目录、侧栏等基线不具备的 UI 算进去。
10
+
11
+ 每组运行三次、取中位数;每次用独立页面,先预热并等待字体,交替运行两个渲染器,避免上一组 DOM/内存影响下一组。计时范围是同步 React 提交和一次强制布局;不计网络下载、异步重资源加载、帧间空闲时间及后续观察器工作。
12
+
13
+ | 场景 | LiMR | react-markdown |
14
+ | --- | ---: | ---: |
15
+ | 87,381 字符,200 节,首次挂载 | 126.1 ms | 134.0 ms |
16
+ | 877,782 字符,2,000 节,首次挂载 | 1,345.4 ms | 1,437.6 ms |
17
+ | 34,860 字符,256 字符/次,138 次提交,累计同步时间 | 306.1 ms | 1,864.1 ms |
18
+ | 同一流式场景,单次提交 P95 | 2.9 ms | 23.7 ms |
19
+
20
+ 本次流式累计同步时间约为基线的 **1/6.1**。末次提交执行最终完整解析,也包含在统计内。三轮 LiMR 流式单次最大值为 31.1–31.8 ms,不能将 P95 解读为每一帧都小于 16 ms。
21
+
22
+ 长文夹具最终 DOM 元素数:LiMR 40,002,基线 36,001。差异主要来自表格滚动容器、代码文本映射及一个选区绘制层;普通段落、标题和文本不再依赖额外包裹层。未使用虚拟化,浏览器仍能搜索、选择和打印整个文档。
23
+
24
+ 原始样本:[browser.json](../benchmarks/results/browser.json)。
25
+
26
+ ## 持续拖选
27
+
28
+ 真实鼠标持续按下并移动 90 次,结束前统计更新和绘制,不能用松手后的单次更新通过检查。每组使用三个独立页面,等待字体和代码着色后开始;下表展示按手势总时长排序的中间样本。绘制延迟是 `selectionchange` 到覆盖层 DOM 变更的间隔,帧间隔由 rAF 采样,均不等同于硬件输入到屏幕呈现的延迟。
29
+
30
+ | 场景 | 原生选区变化 | 拖动中的更新 / 绘制 | 绘制延迟 P95 | 帧间隔 P95 | 长任务 |
31
+ | --- | ---: | ---: | ---: | ---: | ---: |
32
+ | LiMR:877,782 字符,8,000 区块 | 91 | 75 / 75 | 25.2 ms | 16.8 ms | 0 |
33
+ | react-markdown:同一篇长文 | 91 | 无自定义覆盖层 | 不适用 | 16.7 ms | 0 |
34
+ | LiMR:1,000 行 Shiki 着色代码 | 51 | 47 / 47 | 19.3 ms | 16.8 ms | 0 |
35
+
36
+ 三轮长文的绘制延迟 P95 为 25.2–28.5 ms,代码为 18.9–19.4 ms。一次绘制只保留视口内片段;这两个手势结束前分别有 11、12 个绘制矩形。浏览器回归还会全选全文并滚动到中间,要求可见绘制跟随滚动且矩形数少于 250。
37
+
38
+ 同一自动化长文手势在 LiMR 中耗时 3.23 秒,基线为 1.52 秒;基线没有原文映射和自定义覆盖层,不能用接近的 rAF 间隔宣称两者输入处理成本相同。保留全部样本以便继续比较,见 [selection.json](../benchmarks/results/selection.json)。
39
+
40
+ 回归预算:更新及绘制次数均超过原生变化的 60%,绘制延迟与帧间隔 P95 小于 40 ms,拖动期间没有超过 100 ms 的任务。测试使用单 worker,避免并发浏览器争抢资源扭曲结果。该预算是当前夹具的回归门槛,不是任意设备的性能保证。
41
+
42
+ ## Node / SSR
43
+
44
+ core 对照为同版本 mdast-util-from-markdown + GFM。core 除解析外还生成标题、脚注、角注、区块和原文元信息。SSR 对照使用等价 GFM 功能;没有把未加载的代码高亮或公式冷启动算成渲染优势。
45
+
46
+ | 场景 | LiMR | 对照 |
47
+ | --- | ---: | ---: |
48
+ | 87,381 字符,核心处理 | 109.32 ms | 101.78 ms |
49
+ | 877,782 字符,核心处理 | 2,702.76 ms | 2,864.73 ms |
50
+ | 87,381 字符,SSR | 123.85 ms | 135.80 ms |
51
+ | 877,782 字符,SSR | 5,508.29 ms | 2,720.70 ms |
52
+ | 34,860 字符,137 次核心追加及收尾,累计 | 164.04 ms | 2,673.74 ms |
53
+
54
+ 核心追加对照每次重新解析整个前缀。不同组分别预热,GC 和 JIT 会影响数值,因此不能把“核心处理”和“SSR”两行相减当作精确的 React 渲染成本。本轮长文 SSR 的 LiMR 样本范围为 2.64–9.10 秒,对照为 2.70–5.03 秒;中位数明显较慢,波动原因未归因,不据此承诺长文 SSR 与基线相当。原始区间:[node.json](../benchmarks/results/node.json)。
55
+
56
+ ## 实现要点和边界
57
+
58
+ - 追加时回退到末尾尚未稳定的顶层区块。先前的 Markdown 定义作为解析环境;新定义影响前文时完整校正;生成结束时完整解析。
59
+ - 源文本从不预处理改写,坐标是原始 UTF-16 偏移。普通文本在真正选择时才建立 DOM 文本节点到源码的映射;装饰和自定义布局按需采用显式绑定。
60
+ - 区块和未变化的目录保持引用稳定;交互、布局与文档分开更新。滚动不会触发重新解析。
61
+ - 选区跟踪按 rAF 合并事件,取消会被持续拖动反复重置的 debounce。语法扩展仅检查边界祖先;绘制按可见区块二分定位、缓存文本映射与字体测量,复用矩形元素。绘制层自身也限制为视口高度,减少超长页面上的布局和命中测试工作。
62
+ - 代码接近视口时加载所需语言/主题;流式代码暂停后高亮。公式和视频分别按需加载或点击加载。
63
+ - 角注的缓存按阅读器隔离。浏览器测试覆盖了预览切换展开时复用同一请求、再次打开命中缓存、数据变更后重新请求;默认渲染没有第三方 CDN 请求。
64
+
65
+ 尾部若是非常长的单个代码块、列表或未闭合标签,重新解析该区块的成本仍会增长。全文 transform、修改中间内容、引用定义变化和收尾都会触发完整解析。这不是任意语法、任意编辑模式下的常数时间增量解析器。
66
+
67
+ 这里的性能数据没有覆盖大型公式集、Shiki 冷启动、密集外部注释、第三方插件、完整 Reader 布局或真实移动设备。相关功能另有交互验证,但不能从这些 GFM 数据推导出它们的性能承诺。
68
+
69
+ ## 复现
70
+
71
+ 在仓库中运行,测量时不要并行运行构建或其他基准:
72
+
73
+ ```sh
74
+ NODE_ENV=production pnpm bench
75
+ pnpm exec vite build
76
+ pnpm exec vite preview --host 127.0.0.1 --port 4174
77
+ # 另一个终端:
78
+ pnpm bench:browser
79
+ pnpm bench:selection
80
+ # 浏览器交互与持续拖选回归:
81
+ pnpm test:browser
82
+ ```
83
+
84
+ 脚本及夹具位于 `benchmarks/`、`playground/benchmark.tsx` 和 `playground/selection-benchmark.tsx`;结果写入 `benchmarks/results/`。
package/docs/styles.md ADDED
@@ -0,0 +1,103 @@
1
+ # 样式与交互外观
2
+
3
+ `@linloir/limr/styles.css` 提供默认 classic 样式和代码字体。所有默认规则位于 `@layer limr`;应用或样式包的普通 CSS 可以直接覆盖,无须提高选择器优先级。`appearance="paper"` 会传播到正文、目录、侧栏、选区工具栏和 portal 浮层,适合同页存在多个阅读器的场景。
4
+
5
+ ```tsx
6
+ import '@linloir/limr/styles.css';
7
+ import '@your-scope/limr-theme-paper';
8
+ <Reader source={markdown} appearance="paper" theme="dark" />
9
+ ```
10
+
11
+ 主题包可只包含 CSS,并将 `exports["."]` 指向该文件、`sideEffects` 设为 `["**/*.css"]`。用 `[data-limr-appearance='paper']` 包裹 token 和规则,不依赖 `.limr-reader` 作为 portal 的祖先。自定义组件使用稳定的 `.limr-*` 类,状态由 `data-active`、`data-expanded`、`data-open`、`data-status` 等属性表示。
12
+
13
+ | CSS 变量 | 用途 |
14
+ | --- | --- |
15
+ | `--limr-font-text`, `--limr-font-code` | 正文与代码字体栈 |
16
+ | `--limr-font-size`, `--limr-line-height` | 正文字号和行高 |
17
+ | `--limr-font-features` | 正文 OpenType 特性,默认 `'palt' 1`,使中文字体的弯引号等标点采用比例宽度;`normal` 可恢复字体原有宽度 |
18
+ | `--limr-emphasis-spacing` | 斜体末尾的光学留白,默认 `.08em`;不改变左侧间距 |
19
+ | `--limr-list-item-gap` | 列表项和嵌套层级前后的统一间距,默认 `.375rem` |
20
+ | `--limr-text`, `--limr-heading`, `--limr-secondary`, `--limr-muted` | 文本层次 |
21
+ | `--limr-background`, `--limr-surface`, `--limr-border` | 背景与边框 |
22
+ | `--limr-link`, `--limr-accent`, `--limr-selection` | 链接、激活与选区颜色 |
23
+ | `--limr-code-bg`, `--limr-code-header`, `--limr-inline-code` | 两种主题下的代码颜色 |
24
+ | `--limr-mark-size` | 角标方形边长,默认 `.92em`,统一使用正文基准字号 |
25
+ | `--limr-motion-fast`, `--limr-motion`, `--limr-motion-slow`, `--limr-ease` | 动画时长与曲线 |
26
+ | `--limr-overlay-duration` | 悬浮预览展开/收回共用时长(560ms);兼容旧变量 `--limr-overlay-enter-duration` |
27
+ | `--limr-overlay-morph-duration`, `--limr-overlay-ease` | 预览与大卡片变换时长(480ms),浮层曲线(`cubic-bezier(.22,1,.36,1)`) |
28
+ | `--limr-video-width`, `--limr-definition-math-bg` | 视频最大宽度与释义块内公式背景 |
29
+ | `--limr-content-width`, `--limr-reader-width`, `--limr-sticky-top` | 布局上限及吸顶位置 |
30
+ | `--limr-toc-width`, `--limr-sidebar-width`, `--limr-column-gap` | 三栏宽度与间隔;默认侧栏随容器增宽 |
31
+ | `--limr-reader-min-height`, `--limr-reader-bottom-space` | 短正文的最小高度与视口底部预留空间;默认自动填充并预留 24px |
32
+ | `--limr-annotation-color`, `--limr-annotation-border`, `--limr-annotation-title`, `--limr-annotation-text`, `--limr-annotation-excerpt` | 模块通过 `color` / `sidebar` 配置提供的卡片局部色值 |
33
+ | `--limr-sidebar-padding-block` | 通用侧栏卡片顶部留白,默认 `.65rem`;底部额外补足 `2px`,Citation 使用独立规则 |
34
+ | `--limr-sidebar-padding-inline` | 关联区与内容区共用的水平留白,默认 `10px`;标题、预览、正文的文字起点一致 |
35
+ | `--limr-sidebar-reference-gap` | 灰色关联区与下方内容区之间的分隔,默认 `1px` |
36
+ | `--limr-toolbar-background`, `--limr-toolbar-border`, `--limr-toolbar-shadow`, `--limr-toolbar-radius` | 工具栏浮层背景、边框、阴影、圆角(默认 `6px`) |
37
+ | `--limr-toolbar-font-size`, `--limr-tool-icon-size`, `--limr-toolbar-accent` | 工具栏文字(默认 `.75rem`)、图标(`18px`)、选择框颜色(沿用 `--limr-accent`) |
38
+ | `--limr-toolbar-panel-width`, `--limr-toolbar-panel-max-height` | 展开内容宽度(默认 `246px`,不含内边距)与高度上限(默认 `260px`) |
39
+ | `--limr-toolbar-panel-height`, `--limr-toolbar-available-height` | 骨架测量得到的面板高度上限与所选方向空间;插件可读取,不应覆盖 |
40
+
41
+ 系统 `prefers-reduced-motion: reduce` 会关闭位移、展开与滚动动画。工具栏文字按钮使用 `.limr-underline` 从左向右展开下划线,不添加悬浮背景;复制成功原位淡出淡入为绿色“已复制”,2.4 秒后恢复。代码块内的图标复制按钮保留独立的背景与图标过渡。默认 `>` 引用块使用“注释 / Note”标题;可用 `components.blockquote` 完全替换其外观。它与插件注册的注记角注类型相互独立。
42
+
43
+ 图片外框使用 `.limr-figure` / `.limr-figures`,继承代码/公式区域的背景和边框色;`.limr-figures-grid` 使用实际测量得出的列数,图片保持长宽比。同一行图片居中对齐、caption 共用行轨道,单图与整组 caption 均居中。图组与单图分别有源码和图片 URL 复制按钮,按钮位于外框内部。`.limr-translations` 内的两个 `.limr-translation-panel` 复用可逆的高度与透明度动画,默认 480ms;隐藏侧设置 `inert`。`.limr-action-mark` 复用普通角标的图标槽与尺寸,原文、译文、对照使用不同的圆润图标,并保留状态提示及无障碍标签。
44
+
45
+ 宽屏参考 infilearn 的正文尺度:阅读器默认最大 `1800px`,正文最大 `900px`,目录和注释栏随容器宽度渐增,列间距默认 `36px`。容器不足 `1120px` 时仍切换为注释浮层,不依赖浏览器窗口宽度。宿主可用上述变量覆盖尺寸。
46
+
47
+ 同步注释侧栏由所在网格行决定高度,并使用 size/layout containment 与 `overflow: clip` 隔离内部位移。短正文自动补足可用阅读高度,注释数量不会撑大页面。悬浮角标驱动侧栏,悬浮卡片则锁定卡片命中区域并平滑移动正文;正文容器裁切位移,不改变页面滚动范围。不要把所有卡片底部的最大值赋给外层 `height` / `min-height`,也不要给这个同步列表添加 `overflow: auto`。卡片正文的长内容滚动与列表定位相互独立。
48
+
49
+ 模块颜色、边距、`sidebar.Preview` 和 Citation 单条/多条补偿的约定见[扩展指南](extensions.md)。可以通过 `.limr-sidebar-card[data-type='assistant']` 定位模块;默认卡片的有色装饰条、背景和 padding 在它的 `.limr-sidebar-card-body` 上,灰色关联区是独立的 `.limr-sidebar-reference`,两者之间留出分隔。`.limr-sidebar-preview` 使用模块配置的预览颜色和行数,展开后隐藏。浮层使用 `.limr-annotation-overlay[data-type='assistant']`,无需依赖阅读器作为 portal 的祖先。
50
+
51
+ 悬浮预览先按最终位置和尺寸排版,再从角标横坐标对应的位置裁切展开,内容不会随动画反复换行。预览在角标上方时从底部展开,在下方时从顶部展开;切换角标会等待新角标的定位结果。视口较矮时,预览高度受对应方向的剩余空间限制。允许展开的模块从预览的位置和尺寸放大至目标布局,关闭时缩回预览位置和尺寸并淡出;触摸、工具栏直接打开也采用同一几何起点。
52
+
53
+ 动画从实时画面重新取样,移开、重入和快速展开/收起均可中途反转。悬浮预览进入和退出共用 560ms,内容和外壳同时结束;鼠标移开后的跨越间隙宽限为 90ms,明确关闭时立即开始动画。组件在退场完成后才卸载,保留请求与组件状态。外壳背景与阴影由 `.limr-overlay-surface` 绘制并独立变形,`.limr-overlay-card` 内的文字、按钮与输入框不缩放。打开时聚焦对话框容器,不自动高亮“收起”按钮,Tab 导航仍保留焦点提示。
54
+
55
+ 窄屏目录使用整行 hover 背景和圆角折线箭头,内容高度、透明度、位移和箭头旋转连续过渡。内容持续挂载、隐藏时 inert,快速点击直接从当前帧反转,没有延迟卸载定时器。
56
+
57
+ 宽屏目录通过不占高度的 sticky 定位容器固定顶部,内部目录按实际可见高度单独限制尺寸,正文末尾不会把目录整体向上推出视口。`--limr-sticky-top` 控制吸顶距离,`--limr-toc-available-height` 由 Reader 测量,不应覆盖。目录标题不参与渐隐;`.limr-toc-scroll` 与正文、注释栏共用 `--limr-overflow-fade-size`(默认 `24px`),仅在对应方向有溢出时淡出,列表自身滚动也会更新渐隐边界。
58
+
59
+ 角标的鼠标命中区域保持固定,hover/按下缩放只作用于内部图形,避免边缘反复触发进入/离开。侧栏展开/收起使用纯文字和下划线渐变,仅悬浮“展开 / 收起”文字或键盘聚焦时触发;切换展开状态时保留卡片 hover。提问选项菱形按第一行文字基线对齐,公布答案时正确选项填充绿色;扩展阅读标题使用正文标题色,副标题字号更小、间距更紧凑。
60
+
61
+ 浮层隐藏原生滚动条,使用不占内容宽度的 3px 覆盖式滚动条(`.limr-overlay-scroll-thumb`)。展开/收起动画期间不显示;实际滚动时淡入,停止 800ms 后淡出,支持拖动滑块。滚轮、触摸和键盘滚动仍由原生滚动容器处理。
62
+
63
+ ## 字体资源和缓存
64
+
65
+ 爱丽丝样例中的撇号是 Unicode 弯引号 `’`(U+2019),不是全角 ASCII 撇号。默认启用字体的比例标点特性以缩小其宽度,不替换源文本,因此复制、选区和 annotation 偏移保持一致。样式包可覆盖 `--limr-font-features`,或通过 `--limr-font-text` 换用自己的字体;特性是否可用取决于字体。代码仍使用独立的等宽字体特性。
66
+
67
+ 两端对齐由渲染器的 `justify` 属性控制,默认关闭。开启时段落和列表使用 `text-align: justify`,末行和显式换行前的行保持起始侧对齐,标题、代码块及表格保持原有排版。选区与高亮使用排版后的实际文字位置测量,包含斜体末尾留白。
68
+
69
+ 默认代码字体来自 [Maple Mono v7.9 的 NF CN 版本](https://github.com/subframe7536/maple-font/releases/tag/v7.9),保留原版连字、中文、日文、Nerd 图标及原版支持的其他字形。不能把“多语言”理解为所有文字均有字形;缺失字符仍使用系统回退。四个字重/样式文件切分为 unicode-range WOFF2 子集,浏览器只按实际字符请求所需子集,`font-display: swap` 使代码先用系统等宽字体显示。Latin/Greek/Cyrillic 常规子集约 47 KB;完整字体资产约 31 MB,不会在页面初始全部下载。
70
+
71
+ `src/fonts/manifest.json` 记录来源、原始包摘要、字形覆盖和各文件大小,OFL 许可证随包分发。子集字体使用新名称 `LiMR Maple Mono NF CN`。`scripts/subset-fonts.py` 可从官方 unhinted ZIP 重建资源。WOFF2 文件名包含版本与内容摘要,构建工具可进一步生成哈希资源 URL。
72
+
73
+ 组件无法设置服务器的 HTTP 缓存头。生产部署应对带内容哈希的字体资源返回 `Cache-Control: public, max-age=31536000, immutable`;浏览器是否复用仍取决于 URL、缓存头和用户缓存状态,不应由组件重复 fetch 字体。
74
+
75
+ 本地生产预览的中英混排/希腊/西里尔/Nerd 图标夹具实际请求 4 个 Maple 子集,共 341,440 字节;刷新后没有重新传输字体正文。这是该夹具和预览服务器的观测结果,不能代替宿主应用的缓存配置。
76
+
77
+ 完全使用自己的字体时:
78
+
79
+ ```tsx
80
+ import '@linloir/limr/styles/base.css'; // 默认排版/交互样式,不引入 Maple
81
+ // 可单独 import '@linloir/limr/fonts.css',或载入应用自己的字体。
82
+ ```
83
+
84
+ ## 选区、高亮与移动端
85
+
86
+ 浏览器仍管理原生文本范围、键盘选择、复制与辅助技术;覆盖层统一文本、行内代码、公式及角标的选中高度,不用替换正文或铺设透明文字副本。覆盖层只绘制视口中的片段,并在字体、内容、尺寸和滚动变化后重新计算。全文 DOM 保留,浏览器搜索和打印不受虚拟列表影响。
87
+
88
+ 代码可部分选中;公式按整体选中,块公式继承背景边界与圆角。角标仅在两侧都有文本且范围跨过两侧文本时着色,按钮本身的背景和交互独立。自定义原子组件可给内部实际背景元素添加 `data-limr-selection-surface`,指定覆盖边界和圆角。
89
+
90
+ 图片的选区和背景高亮使用边框,避免遮住图像;下划线样式仍可使用。图片与块公式的角标直接覆盖原有右下角,不增加块高度。图片角标的按钮使用不透明的浅主题底色,不附加白色底板。文字角标与前一个字符共同换行,不单独留在新行;连接字符通过 CSS 生成,不改变源文或复制文本。译文状态图标可用 `--limr-translation-accent` 改色。
91
+
92
+ 侧栏布局优先利用上方留白,把末尾卡片收进可用高度;边界处悬浮不会强行移动正文来追齐角标。正文和侧栏在实际发生上下裁切时使用透明渐隐,跟随窗口、嵌套滚动容器及动画中的真实边界;内容完整时不会淡化边缘,打印时也不保留屏幕蒙版。`--limr-overflow-fade-size` 控制渐隐高度,默认 `24px`,设置为 `0px` 可关闭渐变。
93
+
94
+ 移动视口、触摸点击浮层和 Selection API 的程序化选择有浏览器回归检查。iOS/Android 的系统拖动手柄、放大镜和原生菜单并不能通过网页 CSS 一致接管;保留这些平台控件,不伪装成已在真机上实现了完全自定义触摸选区。实体设备的手指拖动仍需单独验收。
95
+
96
+
97
+ 工具栏外层 `.limr-selection-toolbar` 只负责定位,`.limr-toolbar-surface` 与各 `.limr-toolbar-item` 分别执行非线性位移和延后淡入。上方工具栏从下向上浮入,下方工具栏从上向下浮入;组件按序延迟 22ms,淡入再稍晚开始。`prefers-reduced-motion` 关闭这些移动和延迟。工具栏优先位于选区下方,为展开内容预留同一份空间预算;展开后按钮行保持靠近选区,面板向外生长。分隔线覆盖整个工具栏宽度,面板内容居左并受宽度约束。
98
+
99
+ `.limr-tool-icon` 默认 18px,可用 `--limr-tool-icon-size` 覆盖。图标槽约束 SVG、图片及嵌套包装的大小和溢出。文字行高为 1.5,以 1px 底部留白校正视觉中心;内置图标在自身 viewBox 内校正,不对整行施加额外位移。自绘整个 action 的 `render` 槽位需自己复用图标槽或提供等价约束。
100
+
101
+ 面板由骨架的 `OverlayScrollArea` 负责滚动:内容不足预算时自然收缩,溢出时使用 3px 覆盖式滚动条,不挤占内容布局。插件通常不需要设置高度或再提供滚动条;复杂模块可读取上述可用高度变量。外部样式包示例见 [`paper-theme/index.css`](../examples/packages/paper-theme/index.css)。
102
+
103
+ 持久高亮使用 `.limr-highlight-layer`,在各段落、代码或公式背景上方、文字下方绘制;临时选区保留独立的 `.limr-paint-layer`。两个层都只维护视口内的几何,且不拦截指针。高亮悬浮通过正文的坐标命中判断,按叠放顺序选择一个高亮,应用 `data-hovered` / `data-active` 到该高亮的全部可见片段。悬浮侧栏条目、角标或激活 annotation 时,其他片段添加 `data-muted` 暂时隐藏;离开后恢复原本的可见性。打印时隐藏绘制层,恢复语义 mark 的原生装饰。