@linloir/limr 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.en.md +123 -0
- package/README.md +122 -2
- package/benchmarks/results/browser.json +237 -0
- package/benchmarks/results/node.json +75 -0
- package/benchmarks/results/selection.json +172 -0
- package/dist/THIRD_PARTY_LICENSES.txt +117 -0
- package/dist/base.css +454 -0
- package/dist/chunk-3ILUZKDB.js +3130 -0
- package/dist/chunk-3ILUZKDB.js.map +1 -0
- package/dist/chunk-6N6TFHEN.js +83 -0
- package/dist/chunk-6N6TFHEN.js.map +1 -0
- package/dist/chunk-N77VD2YR.js +1238 -0
- package/dist/chunk-N77VD2YR.js.map +1 -0
- package/dist/chunk-TTISGBST.js +478 -0
- package/dist/chunk-TTISGBST.js.map +1 -0
- package/dist/chunk-V2OG4Y3F.js +1 -0
- package/dist/chunk-V2OG4Y3F.js.map +1 -0
- package/dist/core/index.d.ts +57 -0
- package/dist/core/index.js +39 -0
- package/dist/core/index.js.map +1 -0
- package/dist/engine-43u8B4yt.d.ts +172 -0
- package/dist/extensions/index.d.ts +130 -0
- package/dist/extensions/index.js +50 -0
- package/dist/extensions/index.js.map +1 -0
- package/dist/fonts/KaTeX_AMS-Regular.ttf +0 -0
- package/dist/fonts/KaTeX_AMS-Regular.woff +0 -0
- package/dist/fonts/KaTeX_AMS-Regular.woff2 +0 -0
- package/dist/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
- package/dist/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
- package/dist/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
- package/dist/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
- package/dist/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
- package/dist/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
- package/dist/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
- package/dist/fonts/KaTeX_Fraktur-Bold.woff +0 -0
- package/dist/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
- package/dist/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
- package/dist/fonts/KaTeX_Fraktur-Regular.woff +0 -0
- package/dist/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
- package/dist/fonts/KaTeX_Main-Bold.ttf +0 -0
- package/dist/fonts/KaTeX_Main-Bold.woff +0 -0
- package/dist/fonts/KaTeX_Main-Bold.woff2 +0 -0
- package/dist/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
- package/dist/fonts/KaTeX_Main-BoldItalic.woff +0 -0
- package/dist/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
- package/dist/fonts/KaTeX_Main-Italic.ttf +0 -0
- package/dist/fonts/KaTeX_Main-Italic.woff +0 -0
- package/dist/fonts/KaTeX_Main-Italic.woff2 +0 -0
- package/dist/fonts/KaTeX_Main-Regular.ttf +0 -0
- package/dist/fonts/KaTeX_Main-Regular.woff +0 -0
- package/dist/fonts/KaTeX_Main-Regular.woff2 +0 -0
- package/dist/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
- package/dist/fonts/KaTeX_Math-BoldItalic.woff +0 -0
- package/dist/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
- package/dist/fonts/KaTeX_Math-Italic.ttf +0 -0
- package/dist/fonts/KaTeX_Math-Italic.woff +0 -0
- package/dist/fonts/KaTeX_Math-Italic.woff2 +0 -0
- package/dist/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
- package/dist/fonts/KaTeX_SansSerif-Bold.woff +0 -0
- package/dist/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
- package/dist/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
- package/dist/fonts/KaTeX_SansSerif-Italic.woff +0 -0
- package/dist/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
- package/dist/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
- package/dist/fonts/KaTeX_SansSerif-Regular.woff +0 -0
- package/dist/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
- package/dist/fonts/KaTeX_Script-Regular.ttf +0 -0
- package/dist/fonts/KaTeX_Script-Regular.woff +0 -0
- package/dist/fonts/KaTeX_Script-Regular.woff2 +0 -0
- package/dist/fonts/KaTeX_Size1-Regular.ttf +0 -0
- package/dist/fonts/KaTeX_Size1-Regular.woff +0 -0
- package/dist/fonts/KaTeX_Size1-Regular.woff2 +0 -0
- package/dist/fonts/KaTeX_Size2-Regular.ttf +0 -0
- package/dist/fonts/KaTeX_Size2-Regular.woff +0 -0
- package/dist/fonts/KaTeX_Size2-Regular.woff2 +0 -0
- package/dist/fonts/KaTeX_Size3-Regular.ttf +0 -0
- package/dist/fonts/KaTeX_Size3-Regular.woff +0 -0
- package/dist/fonts/KaTeX_Size3-Regular.woff2 +0 -0
- package/dist/fonts/KaTeX_Size4-Regular.ttf +0 -0
- package/dist/fonts/KaTeX_Size4-Regular.woff +0 -0
- package/dist/fonts/KaTeX_Size4-Regular.woff2 +0 -0
- package/dist/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
- package/dist/fonts/KaTeX_Typewriter-Regular.woff +0 -0
- package/dist/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
- package/dist/fonts/LICENSE.txt +93 -0
- package/dist/fonts/manifest.json +2204 -0
- package/dist/fonts/maple-7.9-bold-005-5530d8c1d6.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-00f-1179d800a7.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-010-9974a942b1.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-011-9b9230baf2.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-012-c2545292b1.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-013-877b19fe05.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-014-6acf4a4e92.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-015-c889146da3.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-018-419ad5f31f.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-027-dd414483da.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-028-263744fbc7.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-029-ae3a163d8b.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-02a-515f0a82c2.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-02b-0823c5133d.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-02c-296fd5db38.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-02d-0bb4734363.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-02e-25415fed50.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-02f-19ed79a84e.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-030-21962a0327.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-031-d216fc0d68.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-032-d90ba34901.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-033-55ea37ea00.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-034-bc8649f808.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-035-03604fe40b.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-036-44fc7f77b2.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-037-8a1440f155.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-038-c65a618d5c.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-039-be05db966d.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-03a-ca3a10002d.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-03b-067b32e10b.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-03c-4da4f84530.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-03d-f0fe6a68c8.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-03e-0e97f89433.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-03f-3289a5e3bc.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-040-232dcd0d7b.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-041-e25e9a9c41.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-042-d64a2b1824.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-043-2d01cf5e52.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-044-0ab808b5f1.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-045-e41dc814b4.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-046-d5fe26344d.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-047-f322ded671.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-048-0cdcf7257f.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-049-aa280ca08a.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-04a-f51ad4d92c.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-04b-4e8c6fa3ee.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-04c-9bfdf4d743.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-04d-83ac1f5bb3.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-04e-bcec89804a.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-04f-d31e83b6ce.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-070-8a3b0fdf98.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-071-5bee0a62c4.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-072-97d891eee4.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-073-4d4c36aca0.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-074-6d3cc01e90.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-075-eab42ad657.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-076-2b1f5c4a42.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-077-1db0d50873.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-078-bc6994a28f.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-079-ad6c1757ce.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-07a-d08ed2b87d.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-07f-2f4af46cc6.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-0fc-42ed90884c.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-780-261fac1b24.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-781-377319a91b.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-782-3106f0be62.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-783-74fbfa8648.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-784-8570270664.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-785-cee8de1ded.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-786-5ab5ff7149.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-787-844b4c4373.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-788-01731198ab.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-789-f4c75fa806.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-78a-4370321ec6.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-78b-5cd412b56f.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-78c-f88e331085.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-78d-1b9b77f6e8.woff2 +0 -0
- package/dist/fonts/maple-7.9-bold-latin-3b4b2831f3.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-005-d59fef8639.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-00f-1bbda7af69.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-010-5cdd4b46a7.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-011-0d1f1ae687.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-012-4ceb000b2e.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-013-ad0a4f4313.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-014-94d54b71b3.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-015-7aede280da.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-018-f21221b1c2.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-027-d23d0e80a4.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-028-23bd6f24df.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-029-c481c0ad50.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-02a-1c134be68e.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-02b-3feb29ecfd.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-02c-de8cc5a063.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-02d-ea25c21fad.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-02e-e68d6bd335.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-02f-c88d1e92dc.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-030-f26fefe87e.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-031-f2aa1b8e22.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-032-c4fafc4aa6.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-033-288a1639ca.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-034-7c982125bc.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-035-fd1575dea2.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-036-f6bf406353.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-037-8ac1466916.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-038-e9f7fed6a6.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-039-6f90d42310.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-03a-30c9409a7e.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-03b-4f1741e9e9.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-03c-6551c74e78.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-03d-c8e2b07106.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-03e-c3e98613d4.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-03f-f1c580bad4.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-040-32e8260076.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-041-39805a0ed7.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-042-13b4d84cd3.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-043-d85780d0bd.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-044-1b5eb624d7.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-045-ad0b4f8762.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-046-9966021b3a.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-047-100d4f6f4e.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-048-a0a1e8b29c.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-049-0806f9b3cc.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-04a-28fdef78b3.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-04b-6e93ef0086.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-04c-50b8da6282.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-04d-f93277723d.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-04e-72e2644690.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-04f-4f234f1802.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-070-a3658a8a23.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-071-4987e49732.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-072-e587fa72cd.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-073-2aca01fdf6.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-074-ae89f99a60.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-075-5a77191665.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-076-4c54a87277.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-077-e47dce25ee.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-078-b0b720dab6.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-079-316ee96f6a.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-07a-b10ccb8107.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-07d-5667cb3be1.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-07f-2ac6735ff8.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-0fc-52171ca01e.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-780-3c090c5f89.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-781-ca4077b4fa.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-782-42c3d52206.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-783-d72840dd37.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-784-b9ca097e50.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-785-b81dec6af9.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-786-76c266f6f5.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-787-403bd73766.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-788-71a4b8c2c5.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-789-94527f3fa4.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-78a-81918568b8.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-78b-d0302b4bfe.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-78c-e864792049.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-78d-105ff69bf4.woff2 +0 -0
- package/dist/fonts/maple-7.9-bolditalic-latin-96412d165b.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-005-23b09473f8.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-00f-e9bf4dd93c.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-010-22933d6d77.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-011-71b0157ddc.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-012-b751ab3752.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-013-530b1d3f8b.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-014-0e842f6749.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-015-642211b03a.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-018-0c5b0001c6.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-027-9a09afbbb1.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-028-93fea67326.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-029-7d7627d4cc.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-02a-88e76d051b.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-02b-7d9219748b.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-02c-049df19d84.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-02d-663fc73c6e.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-02e-a98ed33998.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-02f-8ef9d93d09.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-030-74885d994d.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-031-4cf66c5d65.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-032-a608b7aed4.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-033-2978f66e55.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-034-38f7a0bf87.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-035-5cc45cd3b7.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-036-ca92d327e5.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-037-f887681c7d.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-038-06150b88f8.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-039-761da333b7.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-03a-1408ddaf2c.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-03b-1542b3b67c.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-03c-479f2f5011.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-03d-0f10590b11.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-03e-8b93e0ee0e.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-03f-2bd8815e3e.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-040-b85023679a.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-041-eb881b7b92.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-042-01490a139e.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-043-ffb21b6c4c.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-044-05cd1a1b14.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-045-1270935363.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-046-857077eab1.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-047-ca57774cc3.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-048-20969d6307.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-049-4066aa1a18.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-04a-1ed360d580.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-04b-2eba62d76b.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-04c-2f4effc460.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-04d-d858c0a9c1.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-04e-a19eb0289f.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-04f-8addde15f2.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-070-f0bd641f1c.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-071-e6ac564431.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-072-e6fea65bca.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-073-71621c00dc.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-074-4bd488962a.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-075-2838d95bd6.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-076-94e02ecc03.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-077-32c536ab6b.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-078-18256447bd.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-079-7a735e61cf.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-07a-2b57a6a905.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-07d-8ba1bbfb50.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-07f-0240d80c69.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-0fc-e5b20a692e.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-780-093cc90a9b.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-781-f6ec357f6d.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-782-5ca2ef4ddd.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-783-7450baabee.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-784-14a93cc4bd.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-785-d62fb8b4d7.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-786-1d2959dc83.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-787-70ae947136.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-788-cf1f156ebf.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-789-f0b79f9680.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-78a-5a53fd7870.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-78b-40be093bfd.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-78c-3b11646f8e.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-78d-b13ed8c48b.woff2 +0 -0
- package/dist/fonts/maple-7.9-italic-latin-befeb2b610.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-005-90bff107ac.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-00f-001e503e53.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-010-374da1ebb4.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-011-8f91fcc9e7.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-012-e4ec3016ef.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-013-e779e13a12.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-014-6b833ad501.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-015-4e058c4c42.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-018-6f776bc19b.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-027-92c0be3439.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-028-154c8c3039.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-029-9d88470aca.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-02a-7a94cb26f2.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-02b-1725b841c2.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-02c-e080c435d6.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-02d-a6461c4708.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-02e-2e55d9b957.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-02f-858a76fa1f.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-030-bbbe80f8ad.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-031-cafc1258ad.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-032-0ca83ecceb.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-033-6cb995f2e7.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-034-5877222be6.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-035-988d8f2d26.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-036-e91853e3ca.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-037-3eed60f359.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-038-5681f42a4a.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-039-07036fe444.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-03a-5495eead93.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-03b-d07b1d6c1e.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-03c-6291400ee0.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-03d-3787a51772.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-03e-ce4d945844.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-03f-95e98b329c.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-040-693b769fe8.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-041-7b436d2c09.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-042-9ad884cd73.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-043-372231e8e2.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-044-9922b540b1.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-045-8a88a91c22.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-046-82859ede10.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-047-6532babd62.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-048-abfdc5d7ce.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-049-adb7fa9ed3.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-04a-f3f794b1cb.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-04b-715211b8dd.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-04c-c6f978d10d.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-04d-61019a1c8f.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-04e-806d6efe85.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-04f-99d19aa8db.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-070-e94ba9445d.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-071-057314b533.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-072-a7699beb84.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-073-ebe1bd9ef4.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-074-722db38100.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-075-150ff7187b.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-076-c14595e715.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-077-6c88302a32.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-078-549b294c78.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-079-5131c42759.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-07a-c0dad221b5.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-07f-5cf5ebe065.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-0fc-b644c0c6d9.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-780-c6000d472a.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-781-86409ab7f7.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-782-9cd950637c.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-783-105c4d02df.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-784-00c042af97.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-785-022568d0b8.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-786-90b6f3aef5.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-787-e2888596c9.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-788-3416e1fda3.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-789-9ffc917b0b.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-78a-4a921d07f6.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-78b-9d71c5327b.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-78c-9ec048314b.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-78d-46a2ebd113.woff2 +0 -0
- package/dist/fonts/maple-7.9-regular-latin-59c752ba1d.woff2 +0 -0
- package/dist/fonts/maple.css +315 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +136 -0
- package/dist/index.js.map +1 -0
- package/dist/math-renderer-L6DOH4RX.js +21 -0
- package/dist/math-renderer-L6DOH4RX.js.map +1 -0
- package/dist/math.css +1 -0
- package/dist/react/index.d.ts +113 -0
- package/dist/react/index.js +59 -0
- package/dist/react/index.js.map +1 -0
- package/dist/styles.css +454 -0
- package/dist/translations-DHnYMg4h.d.ts +318 -0
- package/docs/README.md +13 -0
- package/docs/api.md +8 -0
- package/docs/assets/rendered.svg +9 -0
- package/docs/assets/source.svg +9 -0
- package/docs/en/README.md +26 -0
- package/docs/en/ai-skills.md +57 -0
- package/docs/en/annotations.md +84 -0
- package/docs/en/api.md +107 -0
- package/docs/en/architecture.md +33 -0
- package/docs/en/extensions.md +159 -0
- package/docs/en/getting-started.md +67 -0
- package/docs/en/integration.md +130 -0
- package/docs/en/modules.md +80 -0
- package/docs/en/performance.md +53 -0
- package/docs/en/plugin-packages.md +68 -0
- package/docs/en/styles.md +80 -0
- package/docs/en/syntax.md +352 -0
- package/docs/extensions.md +8 -0
- package/docs/implementation.md +8 -0
- package/docs/performance.md +8 -0
- package/docs/screenshots/blocks.png +0 -0
- package/docs/screenshots/dark.png +0 -0
- package/docs/screenshots/desktop.png +0 -0
- package/docs/screenshots/plugin-mobile.png +0 -0
- package/docs/styles.md +8 -0
- package/docs/visual-upgrade.md +8 -0
- package/docs/zh-CN/README.md +26 -0
- package/docs/zh-CN/ai-skills.md +57 -0
- package/docs/zh-CN/annotations.md +84 -0
- package/docs/zh-CN/api.md +107 -0
- package/docs/zh-CN/architecture.md +33 -0
- package/docs/zh-CN/extensions.md +159 -0
- package/docs/zh-CN/getting-started.md +67 -0
- package/docs/zh-CN/integration.md +130 -0
- package/docs/zh-CN/modules.md +80 -0
- package/docs/zh-CN/performance.md +53 -0
- package/docs/zh-CN/plugin-packages.md +68 -0
- package/docs/zh-CN/styles.md +80 -0
- package/docs/zh-CN/syntax.md +352 -0
- package/examples/assistant.tsx +52 -0
- package/examples/notes.tsx +80 -0
- package/examples/packages/paper-theme/index.css +25 -0
- package/examples/packages/paper-theme/package.json +7 -0
- package/examples/packages/reading-tools/index.d.ts +2 -0
- package/examples/packages/reading-tools/index.js +25 -0
- package/examples/packages/reading-tools/package.json +16 -0
- package/package.json +114 -3
- package/skills/limr-plugin-development/SKILL.md +22 -0
- package/skills/limr-plugin-development/agents/openai.yaml +4 -0
- package/skills/limr-plugin-development/assets/plugin-template/README.md +30 -0
- package/skills/limr-plugin-development/assets/plugin-template/package.json +36 -0
- package/skills/limr-plugin-development/assets/plugin-template/src/index.tsx +50 -0
- package/skills/limr-plugin-development/assets/plugin-template/src/styles.css +9 -0
- package/skills/limr-plugin-development/assets/plugin-template/tsconfig.json +20 -0
- package/skills/limr-plugin-development/assets/plugin-template/tsup.config.ts +8 -0
- package/skills/limr-plugin-development/references/contract.md +45 -0
- package/skills/limr-use/SKILL.md +23 -0
- package/skills/limr-use/agents/openai.yaml +4 -0
- package/skills/limr-use/references/integration.md +41 -0
- package/skills/limr-use/references/syntax.md +17 -0
|
@@ -0,0 +1,1238 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AnnotationCard,
|
|
3
|
+
Collapse,
|
|
4
|
+
DocumentProvider,
|
|
5
|
+
Markdown,
|
|
6
|
+
OverlayScrollArea,
|
|
7
|
+
copyText,
|
|
8
|
+
deleteAnnotations,
|
|
9
|
+
highlightPalette,
|
|
10
|
+
highlightSelection,
|
|
11
|
+
scrollWithMotion,
|
|
12
|
+
sourceRangeStartRect,
|
|
13
|
+
useAppearance,
|
|
14
|
+
useDocument,
|
|
15
|
+
useDocumentSelector,
|
|
16
|
+
useIsomorphicLayoutEffect,
|
|
17
|
+
useLocale,
|
|
18
|
+
useRuntime,
|
|
19
|
+
useSelection,
|
|
20
|
+
useStoreSelector,
|
|
21
|
+
useTheme
|
|
22
|
+
} from "./chunk-3ILUZKDB.js";
|
|
23
|
+
import {
|
|
24
|
+
annotationReferenceRange,
|
|
25
|
+
defaultHighlight,
|
|
26
|
+
intersects,
|
|
27
|
+
mapText,
|
|
28
|
+
rangeOf,
|
|
29
|
+
resolveAnnotationAnchors,
|
|
30
|
+
sameRange,
|
|
31
|
+
selectionFromRange
|
|
32
|
+
} from "./chunk-TTISGBST.js";
|
|
33
|
+
|
|
34
|
+
// src/components/Reader.tsx
|
|
35
|
+
import { useEffect as useEffect7, useId as useId2, useRef as useRef5, useState as useState5 } from "react";
|
|
36
|
+
|
|
37
|
+
// src/components/TableOfContents.tsx
|
|
38
|
+
import { useEffect as useEffect2, useRef } from "react";
|
|
39
|
+
|
|
40
|
+
// src/react/overflow-fade.ts
|
|
41
|
+
import { useEffect } from "react";
|
|
42
|
+
function useOverflowFade(ref, runtime, contentSelector, beforeMeasure) {
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
const host = ref.current;
|
|
45
|
+
if (!host) return;
|
|
46
|
+
let frame = 0, transitions = 0;
|
|
47
|
+
const measure = () => {
|
|
48
|
+
frame = 0;
|
|
49
|
+
beforeMeasure?.();
|
|
50
|
+
const box = host.getBoundingClientRect();
|
|
51
|
+
const viewport = window.visualViewport;
|
|
52
|
+
let top = Math.max(box.top, viewport?.offsetTop ?? 0);
|
|
53
|
+
let bottom = Math.min(box.bottom, (viewport?.offsetTop ?? 0) + (viewport?.height ?? innerHeight));
|
|
54
|
+
const root = runtime.configuration.get().scrollRoot;
|
|
55
|
+
if (root) {
|
|
56
|
+
const bounds = root.getBoundingClientRect();
|
|
57
|
+
top = Math.max(top, bounds.top + root.clientTop);
|
|
58
|
+
bottom = Math.min(bottom, bounds.top + root.clientTop + root.clientHeight);
|
|
59
|
+
}
|
|
60
|
+
const contents = [...host.querySelectorAll(contentSelector)].map((element) => element.getBoundingClientRect());
|
|
61
|
+
const clipsTop = bottom > top && contents.some((rect) => rect.top < top - 0.5);
|
|
62
|
+
const clipsBottom = bottom > top && contents.some((rect) => rect.bottom > bottom + 0.5);
|
|
63
|
+
host.toggleAttribute("data-overflow-top", clipsTop);
|
|
64
|
+
host.toggleAttribute("data-overflow-bottom", clipsBottom);
|
|
65
|
+
const set = (name, value) => {
|
|
66
|
+
const css = `${Math.max(0, value).toFixed(2)}px`;
|
|
67
|
+
if (host.style.getPropertyValue(name) !== css) host.style.setProperty(name, css);
|
|
68
|
+
};
|
|
69
|
+
set("--limr-fade-start", top - box.top);
|
|
70
|
+
set("--limr-fade-end", bottom - box.top);
|
|
71
|
+
if (transitions && host.getAnimations({ subtree: true }).some((animation) => animation.playState === "running")) schedule();
|
|
72
|
+
else transitions = 0;
|
|
73
|
+
};
|
|
74
|
+
const schedule = () => {
|
|
75
|
+
if (!frame) frame = requestAnimationFrame(measure);
|
|
76
|
+
};
|
|
77
|
+
const refresh = () => {
|
|
78
|
+
cancelAnimationFrame(frame);
|
|
79
|
+
measure();
|
|
80
|
+
};
|
|
81
|
+
const start = () => {
|
|
82
|
+
transitions++;
|
|
83
|
+
schedule();
|
|
84
|
+
};
|
|
85
|
+
const end = () => {
|
|
86
|
+
transitions = Math.max(0, transitions - 1);
|
|
87
|
+
schedule();
|
|
88
|
+
};
|
|
89
|
+
host.addEventListener("transitionrun", start);
|
|
90
|
+
host.addEventListener("transitionend", end);
|
|
91
|
+
host.addEventListener("transitioncancel", end);
|
|
92
|
+
const resize = new ResizeObserver(refresh);
|
|
93
|
+
resize.observe(host);
|
|
94
|
+
const mutation = new MutationObserver((records) => {
|
|
95
|
+
if (records.some((record) => {
|
|
96
|
+
const element = record.target instanceof Element ? record.target : record.target.parentElement;
|
|
97
|
+
return element && element !== host && !element.closest(".limr-highlight-layer,.limr-paint-layer");
|
|
98
|
+
})) refresh();
|
|
99
|
+
});
|
|
100
|
+
mutation.observe(host, { subtree: true, childList: true, characterData: true, attributes: true, attributeFilter: ["style", "class"] });
|
|
101
|
+
const unsubscribe = [runtime.layout.subscribe(schedule), runtime.viewport.subscribe(refresh), runtime.documentOffset.subscribe(schedule), runtime.configuration.subscribe(schedule)];
|
|
102
|
+
const scroll = (event) => {
|
|
103
|
+
const target = event.target;
|
|
104
|
+
if (target === window.document || target === window || target instanceof Element && target.contains(host)) refresh();
|
|
105
|
+
};
|
|
106
|
+
window.addEventListener("scroll", scroll, { capture: true, passive: true });
|
|
107
|
+
window.addEventListener("resize", schedule);
|
|
108
|
+
window.visualViewport?.addEventListener("resize", schedule);
|
|
109
|
+
window.visualViewport?.addEventListener("scroll", refresh);
|
|
110
|
+
schedule();
|
|
111
|
+
return () => {
|
|
112
|
+
cancelAnimationFrame(frame);
|
|
113
|
+
resize.disconnect();
|
|
114
|
+
mutation.disconnect();
|
|
115
|
+
unsubscribe.forEach((fn) => fn());
|
|
116
|
+
host.removeEventListener("transitionrun", start);
|
|
117
|
+
host.removeEventListener("transitionend", end);
|
|
118
|
+
host.removeEventListener("transitioncancel", end);
|
|
119
|
+
window.removeEventListener("scroll", scroll, true);
|
|
120
|
+
window.removeEventListener("resize", schedule);
|
|
121
|
+
window.visualViewport?.removeEventListener("resize", schedule);
|
|
122
|
+
window.visualViewport?.removeEventListener("scroll", refresh);
|
|
123
|
+
host.removeAttribute("data-overflow-top");
|
|
124
|
+
host.removeAttribute("data-overflow-bottom");
|
|
125
|
+
host.style.removeProperty("--limr-fade-start");
|
|
126
|
+
host.style.removeProperty("--limr-fade-end");
|
|
127
|
+
};
|
|
128
|
+
}, [ref, runtime, contentSelector, beforeMeasure]);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// src/components/TableOfContents.tsx
|
|
132
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
133
|
+
function TableOfContents({ title, maxDepth = 6, followActive = true, topInset = 24, updateHash = false, className, style }) {
|
|
134
|
+
const runtime = useRuntime();
|
|
135
|
+
const appearance = useAppearance();
|
|
136
|
+
const theme = useTheme(), locale = useLocale();
|
|
137
|
+
const headings = useDocumentSelector((doc) => doc.headings);
|
|
138
|
+
useStoreSelector(runtime.layout, (value) => value);
|
|
139
|
+
const active = useStoreSelector(runtime.interaction, (state) => state.activeHeading);
|
|
140
|
+
const list = useRef(null);
|
|
141
|
+
useOverflowFade(list, runtime, ":scope > ol");
|
|
142
|
+
const manualUntil = useRef(0);
|
|
143
|
+
const timer = useRef(void 0);
|
|
144
|
+
const visible = headings.filter((heading) => heading.level <= maxDepth && !runtime.headings.get(heading.id)?.closest("[inert]"));
|
|
145
|
+
visible.sort((a, b) => {
|
|
146
|
+
const left = runtime.headings.get(a.id), right = runtime.headings.get(b.id);
|
|
147
|
+
return left && right && left !== right ? left.compareDocumentPosition(right) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1 : 0;
|
|
148
|
+
});
|
|
149
|
+
const minimum = Math.min(...visible.map((heading) => heading.level), 6);
|
|
150
|
+
useEffect2(() => {
|
|
151
|
+
if (!followActive || !active) return;
|
|
152
|
+
const follow = () => {
|
|
153
|
+
const container = list.current;
|
|
154
|
+
if (!container || container.clientHeight === 0) return;
|
|
155
|
+
const element = Array.from(container.querySelectorAll("[data-heading]")).find((item) => item.dataset.heading === active);
|
|
156
|
+
if (!element) return;
|
|
157
|
+
const top = element.getBoundingClientRect().top - container.getBoundingClientRect().top + container.scrollTop - topInset;
|
|
158
|
+
const target = Math.max(0, Math.min(top, container.scrollHeight - container.clientHeight));
|
|
159
|
+
if (Math.abs(target - container.scrollTop) > 1) scrollWithMotion(container, target);
|
|
160
|
+
};
|
|
161
|
+
const delay = Math.max(0, manualUntil.current - Date.now());
|
|
162
|
+
timer.current = setTimeout(follow, delay);
|
|
163
|
+
return () => clearTimeout(timer.current);
|
|
164
|
+
}, [active, headings, followActive, topInset]);
|
|
165
|
+
const manual = () => {
|
|
166
|
+
manualUntil.current = Date.now() + 1200;
|
|
167
|
+
clearTimeout(timer.current);
|
|
168
|
+
};
|
|
169
|
+
return /* @__PURE__ */ jsxs("nav", { className: `limr-toc ${className ?? ""}`, style, "data-limr-theme": theme, "data-limr-appearance": appearance, "aria-label": title ?? locale.contents, children: [
|
|
170
|
+
/* @__PURE__ */ jsx("div", { className: "limr-toc-title", children: title ?? locale.contents }),
|
|
171
|
+
/* @__PURE__ */ jsx("div", { className: "limr-toc-scroll", ref: list, onWheel: manual, onTouchStart: manual, onKeyDown: manual, tabIndex: 0, children: /* @__PURE__ */ jsx("ol", { children: visible.map((heading) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
|
|
172
|
+
"a",
|
|
173
|
+
{
|
|
174
|
+
"data-heading": heading.id,
|
|
175
|
+
href: `#${heading.id}`,
|
|
176
|
+
"aria-current": heading.id === active ? "location" : void 0,
|
|
177
|
+
style: { paddingInlineStart: 12 + Math.min(heading.level - minimum, 4) * 14 },
|
|
178
|
+
onClick: (event) => {
|
|
179
|
+
event.preventDefault();
|
|
180
|
+
runtime.scrollToHeading(heading.id);
|
|
181
|
+
if (updateHash) history.replaceState(history.state, "", `#${heading.id}`);
|
|
182
|
+
},
|
|
183
|
+
children: /* @__PURE__ */ jsx("span", { className: "limr-underline", children: heading.text })
|
|
184
|
+
}
|
|
185
|
+
) }, heading.id)) }) })
|
|
186
|
+
] });
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// src/components/AnnotationSidebar.tsx
|
|
190
|
+
import { useCallback, useEffect as useEffect4, useMemo, useRef as useRef2, useState as useState2, useSyncExternalStore } from "react";
|
|
191
|
+
import { flushSync } from "react-dom";
|
|
192
|
+
|
|
193
|
+
// src/components/AnnotationContent.tsx
|
|
194
|
+
import { useEffect as useEffect3, useState } from "react";
|
|
195
|
+
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
196
|
+
function AnnotationContent({ annotationId, presentation, expanded = true, enabled = true }) {
|
|
197
|
+
const runtime = useRuntime();
|
|
198
|
+
const annotation = useStoreSelector(runtime.decorations, (state) => state.annotations.get(annotationId));
|
|
199
|
+
const editing = useStoreSelector(runtime.interaction, (state) => state.editing === annotationId);
|
|
200
|
+
const definition = useStoreSelector(runtime.configuration, () => runtime.annotationTypes.get(annotation?.type ?? "citation"));
|
|
201
|
+
const version = useStoreSelector(runtime.resourceVersions, (versions) => versions.get(annotationId) ?? 0);
|
|
202
|
+
const [loaded, setLoaded] = useState({ id: annotationId, loading: !!definition?.load, error: null });
|
|
203
|
+
useEffect3(() => {
|
|
204
|
+
if (!definition?.load || !annotation || !enabled) return;
|
|
205
|
+
let disposed = false;
|
|
206
|
+
setLoaded({ id: annotationId, loading: true, error: null });
|
|
207
|
+
const request = runtime.resources.acquire(runtime.getResourceKey(annotation), (signal) => definition.load(annotation, { signal }));
|
|
208
|
+
request.promise.then((data) => {
|
|
209
|
+
if (!disposed) setLoaded({ id: annotationId, data, loading: false, error: null });
|
|
210
|
+
}).catch((error) => {
|
|
211
|
+
if (!disposed) setLoaded({ id: annotationId, loading: false, error: error instanceof Error ? error : new Error(String(error)) });
|
|
212
|
+
});
|
|
213
|
+
return () => {
|
|
214
|
+
disposed = true;
|
|
215
|
+
request.release();
|
|
216
|
+
};
|
|
217
|
+
}, [runtime, annotation, annotationId, definition, version, enabled]);
|
|
218
|
+
const retry = () => runtime.invalidateAnnotation(annotationId);
|
|
219
|
+
const Content = definition?.Content;
|
|
220
|
+
const current = loaded.id === annotationId ? loaded : { loading: !!definition?.load, error: null, data: void 0 };
|
|
221
|
+
if (!annotation) return /* @__PURE__ */ jsxs2("span", { className: "limr-muted", children: [
|
|
222
|
+
runtime.locale.unavailable,
|
|
223
|
+
" \xB7 ",
|
|
224
|
+
annotationId
|
|
225
|
+
] });
|
|
226
|
+
if (!Content) return /* @__PURE__ */ jsxs2("span", { className: "limr-muted", children: [
|
|
227
|
+
runtime.locale.unavailable,
|
|
228
|
+
" \xB7 ",
|
|
229
|
+
annotation.type
|
|
230
|
+
] });
|
|
231
|
+
return /* @__PURE__ */ jsx2(Content, { editing, annotation, data: definition?.load ? current.data ?? annotation.data : annotation.data, loading: definition?.load ? current.loading : false, error: current.error, retry, presentation, expanded });
|
|
232
|
+
}
|
|
233
|
+
function AnnotationGroup({ occurrence, presentation, expanded = true, enabled = true }) {
|
|
234
|
+
return /* @__PURE__ */ jsx2(Fragment, { children: occurrence.annotationIds.map((id) => /* @__PURE__ */ jsx2("div", { className: "limr-annotation-entry", children: /* @__PURE__ */ jsx2(AnnotationContent, { annotationId: id, presentation, expanded, enabled }) }, id)) });
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// src/components/annotation-reference.ts
|
|
238
|
+
function annotationReferenceText(document2, occurrence) {
|
|
239
|
+
const referenceRange = annotationReferenceRange(document2, occurrence);
|
|
240
|
+
const blocks = document2.blocks.filter((block) => intersects(block.range, referenceRange));
|
|
241
|
+
let reference = "";
|
|
242
|
+
const visit = (node) => {
|
|
243
|
+
const range = rangeOf(node);
|
|
244
|
+
if (!intersects(range, referenceRange) || ["annotationReference", "footnoteReference", "annotationDefinition", "definition"].includes(node.type)) return;
|
|
245
|
+
if (node.value !== void 0) {
|
|
246
|
+
const mapping = mapText(document2.source, node.value, range);
|
|
247
|
+
reference += node.value.split("").filter((_, index) => mapping.ends[index] > referenceRange.start && mapping.starts[index] < referenceRange.end).join("");
|
|
248
|
+
} else if (node.type === "image") reference += String(node.alt ?? "");
|
|
249
|
+
else node.children?.forEach(visit);
|
|
250
|
+
};
|
|
251
|
+
blocks.forEach((block, index) => {
|
|
252
|
+
if (index) reference += " ";
|
|
253
|
+
visit(block.node);
|
|
254
|
+
});
|
|
255
|
+
if (!occurrence.embedded) reference ||= occurrence.quote ?? document2.source.slice(referenceRange.start, referenceRange.end);
|
|
256
|
+
return reference.replace(/\s+/g, " ").trim();
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// src/components/AnnotationSidebar.tsx
|
|
260
|
+
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
261
|
+
var alignSidebar = (items, { activeId, gap, height, prioritizeActive }) => {
|
|
262
|
+
const positions = items.map((item) => item.anchorTop);
|
|
263
|
+
const activeIndex = items.findIndex((item) => item.id === activeId);
|
|
264
|
+
const pivot = activeIndex < 0 ? 0 : activeIndex;
|
|
265
|
+
if (!items.length) return /* @__PURE__ */ new Map();
|
|
266
|
+
positions[pivot] = height === void 0 ? items[pivot].anchorTop : Math.max(0, Math.min(items[pivot].anchorTop, height - items[pivot].height));
|
|
267
|
+
for (let i = pivot - 1; i >= 0; i--) positions[i] = Math.min(items[i].anchorTop, positions[i + 1] - items[i].height - gap);
|
|
268
|
+
for (let i = pivot + 1; i < items.length; i++) positions[i] = Math.max(items[i].anchorTop, positions[i - 1] + items[i - 1].height + gap);
|
|
269
|
+
if (height !== void 0 && items.reduce((sum, item) => sum + item.height, gap * (items.length - 1)) <= height) {
|
|
270
|
+
const start = prioritizeActive && activeIndex >= 0 ? pivot + 1 : 0;
|
|
271
|
+
for (let i = items.length - 1; i >= start; i--) positions[i] = Math.min(positions[i], (i === items.length - 1 ? height : positions[i + 1] - gap) - items[i].height);
|
|
272
|
+
if (start || activeIndex < 0 || positions[0] >= 0) for (let i = start; i < items.length; i++) positions[i] = Math.max(positions[i], i === 0 ? 0 : positions[i - 1] + items[i - 1].height + gap);
|
|
273
|
+
}
|
|
274
|
+
return new Map(items.map((item, index) => [item.id, positions[index]]));
|
|
275
|
+
};
|
|
276
|
+
function AnnotationSidebar({ sync = "document", gap = 14, positioner = alignSidebar, renderCard, className, style }) {
|
|
277
|
+
const runtime = useRuntime();
|
|
278
|
+
const document2 = useDocument();
|
|
279
|
+
const appearance = useAppearance();
|
|
280
|
+
const theme = useTheme(), locale = useLocale();
|
|
281
|
+
const decorations = useStoreSelector(runtime.decorations, (value) => value);
|
|
282
|
+
const active = useStoreSelector(runtime.interaction, (state) => state.active);
|
|
283
|
+
const hovered = useStoreSelector(runtime.interaction, (state) => state.hovered);
|
|
284
|
+
const hoverSource = useStoreSelector(runtime.interaction, (state) => state.hoverSource);
|
|
285
|
+
const activeSource = useStoreSelector(runtime.interaction, (state) => state.activeSource);
|
|
286
|
+
useSyncExternalStore(runtime.configuration.subscribe, runtime.configuration.get, runtime.configuration.get);
|
|
287
|
+
const layout = useSyncExternalStore(runtime.layout.subscribe, runtime.layout.get, runtime.layout.get);
|
|
288
|
+
const viewport = useSyncExternalStore(runtime.viewport.subscribe, runtime.viewport.get, runtime.viewport.get);
|
|
289
|
+
const rail = useRef2(null);
|
|
290
|
+
const cards = useRef2(/* @__PURE__ */ new Map());
|
|
291
|
+
const [sizes, setSizes] = useState2(/* @__PURE__ */ new Map());
|
|
292
|
+
const [minimumSizes, setMinimumSizes] = useState2(/* @__PURE__ */ new Map());
|
|
293
|
+
const [anchorTops, setAnchorTops] = useState2(/* @__PURE__ */ new Map());
|
|
294
|
+
const [railHeight, setRailHeight] = useState2(0);
|
|
295
|
+
const measured = useRef2({ sizes: /* @__PURE__ */ new Map(), minimum: /* @__PURE__ */ new Map(), height: 0 });
|
|
296
|
+
const resizeFrame = useRef2(0);
|
|
297
|
+
const [viewportTop, setViewportTop] = useState2(0);
|
|
298
|
+
const [viewportHeight, setViewportHeight] = useState2(0);
|
|
299
|
+
const [cardLock, setCardLock] = useState2(null);
|
|
300
|
+
const lastFocus = useRef2(null);
|
|
301
|
+
const [release, setRelease] = useState2(null);
|
|
302
|
+
const occurrences = useMemo(() => {
|
|
303
|
+
const values = [...decorations.occurrences].sort((a, b) => a.range.start - b.range.start || a.range.end - b.range.end || a.id.localeCompare(b.id));
|
|
304
|
+
if (sync === "none") {
|
|
305
|
+
for (const annotation of decorations.annotations.values()) if (annotation.type !== "highlight" && !values.some((item) => item.annotationIds.includes(annotation.id))) values.push({ id: `unanchored-${annotation.id}`, range: { start: 0, end: 0 }, annotationIds: [annotation.id] });
|
|
306
|
+
}
|
|
307
|
+
return values;
|
|
308
|
+
}, [decorations, sync]);
|
|
309
|
+
const references = useMemo(() => new Map(occurrences.map((occurrence) => [occurrence.id, annotationReferenceText(document2, occurrence)])), [document2, occurrences]);
|
|
310
|
+
const annotationGroups = useMemo(() => new Map(occurrences.map((occurrence) => [occurrence.id, occurrence.annotationIds.flatMap((id) => {
|
|
311
|
+
const annotation = decorations.annotations.get(id);
|
|
312
|
+
return annotation ? [annotation] : [];
|
|
313
|
+
})])), [decorations, occurrences]);
|
|
314
|
+
const measure = useCallback((beforePaint = false) => {
|
|
315
|
+
const next = /* @__PURE__ */ new Map();
|
|
316
|
+
const minimum = /* @__PURE__ */ new Map();
|
|
317
|
+
cards.current.forEach((element2, id) => {
|
|
318
|
+
const height2 = element2.getBoundingClientRect().height;
|
|
319
|
+
next.set(id, height2);
|
|
320
|
+
const panels = [...element2.querySelectorAll(":scope > .limr-sidebar-card-body > .limr-collapse")];
|
|
321
|
+
minimum.set(id, height2 - panels.reduce((sum, panel) => sum + panel.getBoundingClientRect().height, 0));
|
|
322
|
+
});
|
|
323
|
+
const height = rail.current?.getBoundingClientRect().height ?? 0;
|
|
324
|
+
const old = measured.current;
|
|
325
|
+
if (old.height === height && old.sizes.size === next.size && [...next].every(([id, size2]) => size2 === old.sizes.get(id) && Math.abs(minimum.get(id) - (old.minimum.get(id) ?? 0)) < 0.5)) return;
|
|
326
|
+
measured.current = { sizes: next, minimum, height };
|
|
327
|
+
const update = () => {
|
|
328
|
+
setSizes(next);
|
|
329
|
+
setMinimumSizes(minimum);
|
|
330
|
+
setRailHeight(height);
|
|
331
|
+
};
|
|
332
|
+
if (!beforePaint) {
|
|
333
|
+
update();
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
const element = rail.current;
|
|
337
|
+
element?.setAttribute("data-resizing", "");
|
|
338
|
+
flushSync(update);
|
|
339
|
+
cancelAnimationFrame(resizeFrame.current);
|
|
340
|
+
resizeFrame.current = requestAnimationFrame(() => {
|
|
341
|
+
resizeFrame.current = requestAnimationFrame(() => element?.removeAttribute("data-resizing"));
|
|
342
|
+
});
|
|
343
|
+
}, []);
|
|
344
|
+
const prepareFade = useCallback(() => measure(true), [measure]);
|
|
345
|
+
useOverflowFade(rail, runtime, ":scope > .limr-sidebar-card", prepareFade);
|
|
346
|
+
useEffect4(() => {
|
|
347
|
+
const observer = new ResizeObserver(() => measure(true));
|
|
348
|
+
if (rail.current) observer.observe(rail.current);
|
|
349
|
+
cards.current.forEach((element) => observer.observe(element));
|
|
350
|
+
measure();
|
|
351
|
+
return () => observer.disconnect();
|
|
352
|
+
}, [occurrences, measure, anchorTops]);
|
|
353
|
+
useEffect4(() => () => cancelAnimationFrame(resizeFrame.current), []);
|
|
354
|
+
useIsomorphicLayoutEffect(() => {
|
|
355
|
+
if (sync === "none" || !rail.current) return;
|
|
356
|
+
const top = rail.current.getBoundingClientRect().top;
|
|
357
|
+
const values = /* @__PURE__ */ new Map();
|
|
358
|
+
const displacement2 = runtime.getContentOffset();
|
|
359
|
+
for (const occurrence of occurrences) {
|
|
360
|
+
const marker = runtime.anchors.get(occurrence.id);
|
|
361
|
+
if (!marker || marker.closest("[inert]")) continue;
|
|
362
|
+
const rect = sourceRangeStartRect(runtime, decorations.referenceRanges.get(occurrence.id) ?? occurrence.range);
|
|
363
|
+
values.set(occurrence.id, (rect || marker.getBoundingClientRect()).top - top - displacement2);
|
|
364
|
+
}
|
|
365
|
+
setAnchorTops((old) => old.size === values.size && [...values].every(([id, value]) => Math.abs(value - (old.get(id) ?? -Infinity)) < 0.5) ? old : values);
|
|
366
|
+
}, [runtime, decorations.referenceRanges, occurrences, layout, sync]);
|
|
367
|
+
useIsomorphicLayoutEffect(() => {
|
|
368
|
+
if (sync !== "document" || !rail.current) return;
|
|
369
|
+
const root = runtime.configuration.get().scrollRoot;
|
|
370
|
+
const bounds = rail.current.getBoundingClientRect();
|
|
371
|
+
const top = Math.max(bounds.top, runtime.getViewportTop() + (root?.clientTop ?? 0), window.visualViewport?.offsetTop ?? 0);
|
|
372
|
+
const bottom = Math.min(bounds.bottom, root ? runtime.getViewportTop() + root.clientTop + root.clientHeight : Infinity, (window.visualViewport?.offsetTop ?? 0) + (window.visualViewport?.height ?? innerHeight));
|
|
373
|
+
setViewportTop(Math.max(0, top - bounds.top + (runtime.configuration.get().scrollOffset ?? 24)));
|
|
374
|
+
setViewportHeight(Math.max(0, bottom - top));
|
|
375
|
+
}, [runtime, layout, viewport, sync]);
|
|
376
|
+
useEffect4(() => {
|
|
377
|
+
const dismiss = (event) => {
|
|
378
|
+
if (event.button !== 0) return;
|
|
379
|
+
const target = event.target;
|
|
380
|
+
if (!(target instanceof Element)) return;
|
|
381
|
+
const card = target.closest(".limr-sidebar-card");
|
|
382
|
+
const marker = target.closest("[data-limr-anchor]");
|
|
383
|
+
if (card && rail.current?.contains(card) || marker && runtime.anchors.get(marker.dataset.limrAnchor) === marker) return;
|
|
384
|
+
if (target.closest(".limr-overlay-positioner,.limr-selection-toolbar")) return;
|
|
385
|
+
const { active: active2, hovered: hovered2 } = runtime.interaction.get();
|
|
386
|
+
if (active2 || hovered2) runtime.activate(null);
|
|
387
|
+
};
|
|
388
|
+
const escape = (event) => {
|
|
389
|
+
if (event.key !== "Escape" || event.defaultPrevented || !runtime.interaction.get().active) return;
|
|
390
|
+
const anchor = runtime.anchors.get(runtime.interaction.get().active);
|
|
391
|
+
anchor?.focus({ preventScroll: true });
|
|
392
|
+
runtime.activate(null);
|
|
393
|
+
};
|
|
394
|
+
window.document.addEventListener("pointerdown", dismiss);
|
|
395
|
+
window.document.addEventListener("keydown", escape);
|
|
396
|
+
return () => {
|
|
397
|
+
window.document.removeEventListener("pointerdown", dismiss);
|
|
398
|
+
window.document.removeEventListener("keydown", escape);
|
|
399
|
+
if (sync === "document") runtime.documentOffset.set(0);
|
|
400
|
+
};
|
|
401
|
+
}, [runtime, sync]);
|
|
402
|
+
const items = occurrences.filter((item) => sync === "none" || anchorTops.has(item.id));
|
|
403
|
+
if (sync !== "none") items.sort((a, b) => (anchorTops.get(a.id) ?? 0) - (anchorTops.get(b.id) ?? 0));
|
|
404
|
+
const readingId = items.find((item) => (anchorTops.get(item.id) ?? 0) >= viewportTop)?.id ?? items.at(-1)?.id ?? null;
|
|
405
|
+
const alignmentId = hovered ?? active ?? readingId;
|
|
406
|
+
const focusedId = hovered ?? active;
|
|
407
|
+
const source = hovered ? hoverSource : active ? activeSource : null;
|
|
408
|
+
const locked = source === "sidebar" && cardLock?.id === alignmentId ? cardLock : null;
|
|
409
|
+
const lockedTop = locked?.top;
|
|
410
|
+
useIsomorphicLayoutEffect(() => {
|
|
411
|
+
const previous = lastFocus.current;
|
|
412
|
+
lastFocus.current = focusedId ? { id: focusedId, top: lockedTop } : null;
|
|
413
|
+
if (focusedId || sync !== "document" || !rail.current || matchMedia("(prefers-reduced-motion: reduce)").matches) {
|
|
414
|
+
setRelease(null);
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
if (!previous) return;
|
|
418
|
+
const style2 = getComputedStyle(rail.current), value = style2.getPropertyValue("--limr-motion-slow").trim();
|
|
419
|
+
const milliseconds = parseFloat(value) * (value.endsWith("ms") ? 1 : 1e3);
|
|
420
|
+
const duration = Number.isFinite(milliseconds) ? Math.max(0, milliseconds) : 460;
|
|
421
|
+
if (!duration) {
|
|
422
|
+
setRelease(null);
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
const motion = rail.current.animate([{}, {}], { duration, easing: style2.getPropertyValue("--limr-ease").trim() || "ease-out" });
|
|
426
|
+
setRelease({ ...previous, progress: 0 });
|
|
427
|
+
let frame = 0;
|
|
428
|
+
const step = () => {
|
|
429
|
+
if (motion.playState === "finished") {
|
|
430
|
+
setRelease(null);
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
setRelease({ ...previous, progress: motion.effect?.getComputedTiming().progress ?? 0 });
|
|
434
|
+
frame = requestAnimationFrame(step);
|
|
435
|
+
};
|
|
436
|
+
frame = requestAnimationFrame(step);
|
|
437
|
+
return () => {
|
|
438
|
+
cancelAnimationFrame(frame);
|
|
439
|
+
motion.cancel();
|
|
440
|
+
};
|
|
441
|
+
}, [focusedId, lockedTop, sync]);
|
|
442
|
+
const sidebarItems = items.map((item) => ({ id: item.id, anchorTop: anchorTops.get(item.id) ?? 0, height: sizes.get(item.id) ?? 80 }));
|
|
443
|
+
const positionContext = { activeId: alignmentId, gap, height: sync === "document" && railHeight > 0 ? railHeight : void 0, prioritizeActive: !!(hovered || active) };
|
|
444
|
+
const positions = new Map(positioner(locked ? sidebarItems.map((item) => item.id === locked.id ? { ...item, anchorTop: locked.top } : item) : sidebarItems, positionContext));
|
|
445
|
+
const releasing = !focusedId && release;
|
|
446
|
+
if (releasing) {
|
|
447
|
+
const origin = positioner(sidebarItems.map((item) => item.id === releasing.id && releasing.top !== void 0 ? { ...item, anchorTop: releasing.top } : item), { ...positionContext, activeId: releasing.id, prioritizeActive: true });
|
|
448
|
+
for (const [id, top] of positions) positions.set(id, top + ((origin.get(id) ?? top) - top) * (1 - releasing.progress));
|
|
449
|
+
}
|
|
450
|
+
const lockedAnchor = locked ? anchorTops.get(locked.id) ?? locked.top : 0;
|
|
451
|
+
const displacement = sync === "document" && locked ? (positions.get(locked.id) ?? locked.top) - lockedAnchor : 0;
|
|
452
|
+
useIsomorphicLayoutEffect(() => {
|
|
453
|
+
if (sync === "document") runtime.documentOffset.set(displacement);
|
|
454
|
+
}, [runtime, displacement, sync]);
|
|
455
|
+
const lockCard = (id) => {
|
|
456
|
+
if (locked?.id === id) return;
|
|
457
|
+
const card = cards.current.get(id);
|
|
458
|
+
if (card && rail.current) {
|
|
459
|
+
const origin = rail.current.getBoundingClientRect().top;
|
|
460
|
+
const top = card.getBoundingClientRect().top - origin;
|
|
461
|
+
setCardLock({ id, top });
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
return /* @__PURE__ */ jsx3("aside", { ref: rail, "aria-label": locale.annotations, className: `limr-sidebar ${className ?? ""}`, "data-sync": sync, "data-releasing": releasing ? "" : void 0, "data-limr-theme": theme, "data-limr-appearance": appearance, style, children: items.map((occurrence) => {
|
|
465
|
+
const annotation = decorations.annotations.get(occurrence.annotationIds[0]);
|
|
466
|
+
const definition = runtime.annotationTypes.get(annotation?.type ?? "citation");
|
|
467
|
+
const isActive = active === occurrence.id;
|
|
468
|
+
const palette = definition?.sidebar;
|
|
469
|
+
const Preview = palette?.Preview;
|
|
470
|
+
const available = source === "marker" && alignmentId === occurrence.id && !isActive ? Math.max(minimumSizes.get(occurrence.id) ?? 80, railHeight - (anchorTops.get(occurrence.id) ?? 0)) : railHeight;
|
|
471
|
+
const cardHeight = isActive ? Math.min(available, Math.max(minimumSizes.get(occurrence.id) ?? 80, viewportHeight || railHeight)) : available;
|
|
472
|
+
const cardStyle = {
|
|
473
|
+
"--limr-annotation-color": palette?.color ?? definition?.color,
|
|
474
|
+
"--limr-annotation-border": palette?.borderColor,
|
|
475
|
+
"--limr-annotation-title": palette?.titleColor,
|
|
476
|
+
"--limr-annotation-text": palette?.textColor,
|
|
477
|
+
"--limr-annotation-excerpt": palette?.excerptColor,
|
|
478
|
+
"--limr-annotation-preview": palette?.previewColor,
|
|
479
|
+
"--limr-sidebar-preview-lines": String(Math.max(1, Math.floor(palette?.previewLines ?? 2))),
|
|
480
|
+
...sync === "document" ? {
|
|
481
|
+
position: "absolute",
|
|
482
|
+
top: positions.get(occurrence.id) ?? 0,
|
|
483
|
+
insetInline: 0,
|
|
484
|
+
"--limr-sidebar-card-height": `${cardHeight}px`
|
|
485
|
+
} : { marginBlockEnd: gap }
|
|
486
|
+
};
|
|
487
|
+
const collapseOnContentClick = occurrence.annotationIds.every((id) => runtime.annotationTypes.get(decorations.annotations.get(id)?.type ?? "")?.sidebar?.collapseOnContentClick);
|
|
488
|
+
const activate = () => {
|
|
489
|
+
const hovering = runtime.interaction.get().hovered === occurrence.id || cards.current.get(occurrence.id)?.matches(":hover");
|
|
490
|
+
lockCard(occurrence.id);
|
|
491
|
+
runtime.activate(isActive ? null : occurrence.id, "sidebar");
|
|
492
|
+
if (hovering) runtime.hover(occurrence.id, "sidebar");
|
|
493
|
+
};
|
|
494
|
+
return /* @__PURE__ */ jsx3(
|
|
495
|
+
"div",
|
|
496
|
+
{
|
|
497
|
+
ref: (element) => {
|
|
498
|
+
if (element) cards.current.set(occurrence.id, element);
|
|
499
|
+
else cards.current.delete(occurrence.id);
|
|
500
|
+
},
|
|
501
|
+
className: "limr-sidebar-card",
|
|
502
|
+
"data-type": annotation?.type,
|
|
503
|
+
"data-locked": locked?.id === occurrence.id || void 0,
|
|
504
|
+
"data-active": isActive || hovered === occurrence.id || void 0,
|
|
505
|
+
"data-expanded": isActive || void 0,
|
|
506
|
+
"data-default-card": !renderCard || void 0,
|
|
507
|
+
"data-content-toggle": collapseOnContentClick || void 0,
|
|
508
|
+
"data-citations": occurrence.annotationIds.every((id) => decorations.annotations.get(id)?.type === "citation") || void 0,
|
|
509
|
+
"data-occurrence": occurrence.id,
|
|
510
|
+
style: cardStyle,
|
|
511
|
+
onPointerEnter: (event) => {
|
|
512
|
+
if (event.pointerType !== "touch") {
|
|
513
|
+
lockCard(occurrence.id);
|
|
514
|
+
runtime.hover(occurrence.id, "sidebar");
|
|
515
|
+
}
|
|
516
|
+
},
|
|
517
|
+
onPointerLeave: () => {
|
|
518
|
+
if (runtime.interaction.get().hovered === occurrence.id && runtime.interaction.get().hoverSource === "sidebar") runtime.hover(null);
|
|
519
|
+
},
|
|
520
|
+
onClick: (event) => {
|
|
521
|
+
if ((!isActive || collapseOnContentClick) && !renderCard && !event.defaultPrevented && !event.target.closest('button,a,input,select,textarea,summary,[role="button"],[role="link"],[contenteditable="true"],[data-limr-card-interactive]') && window.getSelection()?.isCollapsed !== false) activate();
|
|
522
|
+
},
|
|
523
|
+
children: renderCard ? renderCard({ occurrence, active: isActive, activate }) : /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
524
|
+
references.get(occurrence.id) && /* @__PURE__ */ jsx3("div", { className: "limr-sidebar-reference", title: references.get(occurrence.id), children: /* @__PURE__ */ jsx3("p", { className: "limr-sidebar-excerpt", children: references.get(occurrence.id) }) }),
|
|
525
|
+
/* @__PURE__ */ jsxs3("div", { className: "limr-sidebar-card-body", children: [
|
|
526
|
+
/* @__PURE__ */ jsxs3("button", { type: "button", className: "limr-sidebar-card-heading", onClick: activate, "aria-expanded": isActive, children: [
|
|
527
|
+
definition?.label ?? annotation?.type ?? "Reference",
|
|
528
|
+
/* @__PURE__ */ jsx3("span", { className: "limr-sidebar-toggle", children: /* @__PURE__ */ jsx3("span", { className: "limr-button-label limr-underline", children: isActive ? locale.collapse : locale.expand }, String(isActive)) })
|
|
529
|
+
] }),
|
|
530
|
+
Preview && annotation && /* @__PURE__ */ jsx3(Collapse, { open: !isActive, keepMounted: true, className: "limr-sidebar-preview-panel", children: /* @__PURE__ */ jsx3("div", { className: "limr-sidebar-preview", children: /* @__PURE__ */ jsx3(Preview, { annotation, data: annotation.data, occurrence, annotations: annotationGroups.get(occurrence.id), referenceText: references.get(occurrence.id) ?? "" }) }) }),
|
|
531
|
+
/* @__PURE__ */ jsx3(Collapse, { open: isActive, className: "limr-sidebar-expansion", children: /* @__PURE__ */ jsx3("div", { className: "limr-sidebar-card-content", children: /* @__PURE__ */ jsx3(AnnotationGroup, { occurrence, presentation: "sidebar", enabled: isActive }) }) })
|
|
532
|
+
] })
|
|
533
|
+
] })
|
|
534
|
+
},
|
|
535
|
+
occurrence.id
|
|
536
|
+
);
|
|
537
|
+
}) });
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// src/components/AnnotationOverlay.tsx
|
|
541
|
+
import { useEffect as useEffect5, useState as useState3, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
542
|
+
import { autoUpdate, flip, FloatingFocusManager, FloatingOverlay, FloatingPortal, offset, shift, size, useDismiss, useFloating, useInteractions, useRole } from "@floating-ui/react";
|
|
543
|
+
|
|
544
|
+
// src/components/card-motion.ts
|
|
545
|
+
import { useRef as useRef3 } from "react";
|
|
546
|
+
var moving = (animation) => animation?.playState === "running" || animation?.playState === "paused";
|
|
547
|
+
var durationOf = (value, fallback) => {
|
|
548
|
+
const duration = parseFloat(value) * (value.endsWith("ms") ? 1 : 1e3);
|
|
549
|
+
return Number.isFinite(duration) && duration > 0 ? duration : fallback;
|
|
550
|
+
};
|
|
551
|
+
function useCardMotion(element, host, anchor, open, expanded, ready, id, edge, previewRect, onExit) {
|
|
552
|
+
const previous = useRef3(null);
|
|
553
|
+
const reveal = useRef3(null);
|
|
554
|
+
const content = useRef3(null);
|
|
555
|
+
const hero = useRef3(null);
|
|
556
|
+
const shape = useRef3(null);
|
|
557
|
+
const state = useRef3(null);
|
|
558
|
+
const latest = useRef3({ open, onExit });
|
|
559
|
+
latest.current = { open, onExit };
|
|
560
|
+
useIsomorphicLayoutEffect(() => {
|
|
561
|
+
if (!element || !host || !ready) return;
|
|
562
|
+
const sameCard = state.current?.id === id;
|
|
563
|
+
const presentationChanged = sameCard && state.current?.expanded !== expanded;
|
|
564
|
+
const intentChanged = !sameCard || state.current?.open !== open || presentationChanged;
|
|
565
|
+
const reduced = matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
566
|
+
if (!intentChanged && !reduced) return;
|
|
567
|
+
const computed = getComputedStyle(element);
|
|
568
|
+
const shell = element.querySelector(".limr-overlay-surface");
|
|
569
|
+
const card = element.querySelector(".limr-overlay-card");
|
|
570
|
+
const previousBody = sameCard ? content.current?.effect?.target : null;
|
|
571
|
+
const body = presentationChanged || expanded ? card : previousBody?.isConnected ? previousBody : element.querySelector("[data-limr-card-body], .limr-overlay-content");
|
|
572
|
+
const bodyStyle = body ? getComputedStyle(body) : null;
|
|
573
|
+
const liveSurface = { opacity: computed.opacity, clipPath: computed.clipPath };
|
|
574
|
+
const liveTransform = computed.transform;
|
|
575
|
+
const liveBody = { opacity: bodyStyle?.opacity ?? "1", transform: bodyStyle?.transform ?? "none", clipPath: bodyStyle?.clipPath ?? "none" };
|
|
576
|
+
let before = sameCard ? previous.current : expanded ? previewRect ?? null : null;
|
|
577
|
+
if (before && sameCard && hero.current && computed.transform !== "none") {
|
|
578
|
+
const matrix = new DOMMatrixReadOnly(computed.transform);
|
|
579
|
+
before = new DOMRect(before.x + matrix.m41, before.y + matrix.m42, before.width, before.height);
|
|
580
|
+
}
|
|
581
|
+
if (before && sameCard && shell && shape.current) {
|
|
582
|
+
const matrix = new DOMMatrixReadOnly(getComputedStyle(shell).transform);
|
|
583
|
+
before = new DOMRect(before.x, before.y, before.width * matrix.a, before.height * matrix.d);
|
|
584
|
+
}
|
|
585
|
+
const target = host.getBoundingClientRect();
|
|
586
|
+
const anchorRect = anchor?.getBoundingClientRect() ?? target;
|
|
587
|
+
const originX = Math.max(0, Math.min(100, ((anchorRect.left + anchorRect.right) / 2 - target.left) / Math.max(1, target.width) * 100));
|
|
588
|
+
const radius = computed.borderRadius || "8px";
|
|
589
|
+
const collapsed = `inset(${edge === "bottom" ? 100 : 0}% ${100 - originX}% ${edge === "bottom" ? 0 : 100}% ${originX}% round ${radius})`;
|
|
590
|
+
const overflow = Math.max(48, (before?.width ?? 0) - target.width + 48, (before?.height ?? 0) - target.height + 48);
|
|
591
|
+
const revealed = `inset(-${overflow}px -${overflow}px -${overflow}px -${overflow}px round ${radius})`;
|
|
592
|
+
const cancel = () => {
|
|
593
|
+
reveal.current?.cancel();
|
|
594
|
+
content.current?.cancel();
|
|
595
|
+
hero.current?.cancel();
|
|
596
|
+
shape.current?.cancel();
|
|
597
|
+
reveal.current = content.current = hero.current = shape.current = null;
|
|
598
|
+
};
|
|
599
|
+
cancel();
|
|
600
|
+
state.current = { id, expanded, open };
|
|
601
|
+
previous.current = target;
|
|
602
|
+
if (reduced || !open && !sameCard) {
|
|
603
|
+
delete element.dataset.motion;
|
|
604
|
+
if (!open) latest.current.onExit();
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
const previewDuration = durationOf((computed.getPropertyValue("--limr-overlay-duration") || computed.getPropertyValue("--limr-overlay-enter-duration")).trim(), 560);
|
|
608
|
+
const morphDuration = durationOf(computed.getPropertyValue("--limr-overlay-morph-duration").trim(), 480);
|
|
609
|
+
const morph = open && !!before && (presentationChanged || !sameCard && expanded);
|
|
610
|
+
const returning = !open && expanded && !!previewRect;
|
|
611
|
+
const destination = returning ? previewRect : target;
|
|
612
|
+
const duration = morph || expanded ? morphDuration : previewDuration;
|
|
613
|
+
const easing = computed.getPropertyValue("--limr-overlay-ease").trim() || "cubic-bezier(.22,1,.36,1)";
|
|
614
|
+
element.dataset.motion = !open ? "closing" : morph ? "morphing" : "opening";
|
|
615
|
+
reveal.current = element.animate([
|
|
616
|
+
sameCard ? { ...liveSurface, ...morph ? { clipPath: revealed } : {} } : { opacity: 0, clipPath: morph ? revealed : collapsed },
|
|
617
|
+
{ opacity: open ? 1 : 0, clipPath: open || returning ? revealed : collapsed }
|
|
618
|
+
], { duration, easing, fill: "both" });
|
|
619
|
+
if (before && (morph || liveTransform !== "none" || returning)) {
|
|
620
|
+
const x = before.left - target.left, y = before.top - target.top;
|
|
621
|
+
const sx = before.width / Math.max(1, target.width), sy = before.height / Math.max(1, target.height);
|
|
622
|
+
hero.current = element.animate([
|
|
623
|
+
{ transform: `translate(${x}px, ${y}px)` },
|
|
624
|
+
{ transform: `translate(${destination.left - target.left}px, ${destination.top - target.top}px)` }
|
|
625
|
+
], { duration, easing, fill: "both" });
|
|
626
|
+
shape.current = shell?.animate([
|
|
627
|
+
{ transform: `scale(${sx}, ${sy})` },
|
|
628
|
+
{ transform: `scale(${destination.width / Math.max(1, target.width)}, ${destination.height / Math.max(1, target.height)})` }
|
|
629
|
+
], { duration, easing, fill: "both" }) ?? null;
|
|
630
|
+
}
|
|
631
|
+
const delay = open ? morph ? 50 : !sameCard ? 35 : 0 : 0;
|
|
632
|
+
content.current = body?.animate([
|
|
633
|
+
sameCard && !morph ? liveBody : { opacity: 0, transform: "translateY(6px)", clipPath: morph ? `inset(0px ${Math.max(0, target.width - before.width)}px ${Math.max(0, target.height - before.height)}px 0px)` : "inset(0px)" },
|
|
634
|
+
{ opacity: open ? 1 : 0, transform: open ? "translateY(0px)" : "translateY(-4px)", clipPath: returning ? `inset(0px ${Math.max(0, target.width - destination.width)}px ${Math.max(0, target.height - destination.height)}px 0px)` : "inset(0px)" }
|
|
635
|
+
], {
|
|
636
|
+
// Content and surface settle together in either direction.
|
|
637
|
+
duration: duration - delay,
|
|
638
|
+
delay,
|
|
639
|
+
easing,
|
|
640
|
+
fill: "both"
|
|
641
|
+
}) ?? null;
|
|
642
|
+
const current = reveal.current;
|
|
643
|
+
const finish = () => {
|
|
644
|
+
if (reveal.current !== current) return;
|
|
645
|
+
if (![reveal.current, content.current, hero.current, shape.current].some(moving)) {
|
|
646
|
+
delete element.dataset.motion;
|
|
647
|
+
if (!latest.current.open) latest.current.onExit();
|
|
648
|
+
else previous.current = host.getBoundingClientRect();
|
|
649
|
+
}
|
|
650
|
+
};
|
|
651
|
+
for (const animation of [reveal.current, content.current, hero.current, shape.current]) if (animation) animation.onfinish = finish;
|
|
652
|
+
finish();
|
|
653
|
+
}, [element, host, anchor, open, expanded, ready, id, edge, previewRect]);
|
|
654
|
+
useIsomorphicLayoutEffect(() => {
|
|
655
|
+
if (host && open && ready && !moving(hero.current)) previous.current = host.getBoundingClientRect();
|
|
656
|
+
});
|
|
657
|
+
useIsomorphicLayoutEffect(() => {
|
|
658
|
+
if (!host || !open) return;
|
|
659
|
+
const observer = new ResizeObserver(() => {
|
|
660
|
+
if (!moving(hero.current)) previous.current = host.getBoundingClientRect();
|
|
661
|
+
});
|
|
662
|
+
observer.observe(host);
|
|
663
|
+
return () => observer.disconnect();
|
|
664
|
+
}, [host, open, id]);
|
|
665
|
+
useIsomorphicLayoutEffect(() => () => {
|
|
666
|
+
reveal.current?.cancel();
|
|
667
|
+
content.current?.cancel();
|
|
668
|
+
hero.current?.cancel();
|
|
669
|
+
shape.current?.cancel();
|
|
670
|
+
reveal.current = content.current = hero.current = shape.current = null;
|
|
671
|
+
state.current = null;
|
|
672
|
+
previous.current = null;
|
|
673
|
+
if (element) delete element.dataset.motion;
|
|
674
|
+
}, [element]);
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
// src/components/AnnotationOverlay.tsx
|
|
678
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
679
|
+
var length = (value) => typeof value === "number" ? `${value}px` : value;
|
|
680
|
+
var idleSubscribe = () => () => {
|
|
681
|
+
};
|
|
682
|
+
function AnnotationOverlay({ disabled = false, portalRoot, previewWidth = 340, maxHeight = "80dvh" }) {
|
|
683
|
+
const runtime = useRuntime();
|
|
684
|
+
const appearance = useAppearance();
|
|
685
|
+
const theme = useTheme(), locale = useLocale();
|
|
686
|
+
const editing = useStoreSelector(runtime.interaction, (state) => state.editing);
|
|
687
|
+
const active = useStoreSelector(runtime.interaction, (state) => state.active);
|
|
688
|
+
const hovered = useStoreSelector(runtime.interaction, (state) => state.hovered);
|
|
689
|
+
const occurrences = useStoreSelector(runtime.decorations, (state) => state.occurrences);
|
|
690
|
+
useSyncExternalStore2(runtime.layout.subscribe, runtime.layout.get, runtime.layout.get);
|
|
691
|
+
const [preview, setPreview] = useState3(null);
|
|
692
|
+
const [collapsedId, setCollapsedId] = useState3(null);
|
|
693
|
+
const [, setViewportTick] = useState3(0);
|
|
694
|
+
useEffect5(() => {
|
|
695
|
+
if (active || disabled) {
|
|
696
|
+
setPreview(null);
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
if (hovered) {
|
|
700
|
+
setPreview(hovered);
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
const timer = setTimeout(() => setPreview(null), 90);
|
|
704
|
+
return () => clearTimeout(timer);
|
|
705
|
+
}, [hovered, active, disabled]);
|
|
706
|
+
useEffect5(() => {
|
|
707
|
+
const update2 = () => setViewportTick((value) => value + 1);
|
|
708
|
+
window.visualViewport?.addEventListener("resize", update2);
|
|
709
|
+
window.visualViewport?.addEventListener("scroll", update2);
|
|
710
|
+
window.addEventListener("resize", update2);
|
|
711
|
+
return () => {
|
|
712
|
+
window.visualViewport?.removeEventListener("resize", update2);
|
|
713
|
+
window.visualViewport?.removeEventListener("scroll", update2);
|
|
714
|
+
window.removeEventListener("resize", update2);
|
|
715
|
+
};
|
|
716
|
+
}, []);
|
|
717
|
+
const wantedId = active ?? preview;
|
|
718
|
+
const wanted = occurrences.find((item) => item.id === wantedId);
|
|
719
|
+
const [retained, setRetained] = useState3(null);
|
|
720
|
+
const occurrence = wanted ?? retained;
|
|
721
|
+
const id = occurrence?.id;
|
|
722
|
+
const annotation = useStoreSelector(runtime.decorations, (state) => state.annotations.get(occurrence?.annotationIds[0] ?? ""));
|
|
723
|
+
const definition = useStoreSelector(runtime.configuration, () => runtime.annotationTypes.get(annotation?.type ?? "citation"));
|
|
724
|
+
const policy = definition?.overlay?.expand;
|
|
725
|
+
const expansion = typeof policy === "function" ? annotation && policy(annotation) : policy;
|
|
726
|
+
const pinned = active === id;
|
|
727
|
+
const expanded = pinned && !!expansion && collapsedId !== id;
|
|
728
|
+
const [lastExpanded, setLastExpanded] = useState3(false);
|
|
729
|
+
const [lastPinned, setLastPinned] = useState3(false);
|
|
730
|
+
const open = !!wanted && !disabled;
|
|
731
|
+
useSyncExternalStore2(open ? runtime.viewport.subscribe : idleSubscribe, runtime.viewport.get, runtime.viewport.get);
|
|
732
|
+
useEffect5(() => {
|
|
733
|
+
if (open) {
|
|
734
|
+
setRetained(wanted);
|
|
735
|
+
setLastExpanded(expanded);
|
|
736
|
+
setLastPinned(pinned);
|
|
737
|
+
}
|
|
738
|
+
}, [wanted, open, expanded, pinned]);
|
|
739
|
+
const close = () => {
|
|
740
|
+
const anchor2 = id ? runtime.anchors.get(id) : null;
|
|
741
|
+
anchor2?.focus({ preventScroll: true });
|
|
742
|
+
runtime.activate(null);
|
|
743
|
+
runtime.hover(null);
|
|
744
|
+
setPreview(null);
|
|
745
|
+
};
|
|
746
|
+
const anchor = id ? runtime.anchors.get(id) : void 0;
|
|
747
|
+
const [previewGeometry, setPreviewGeometry] = useState3(null);
|
|
748
|
+
const fromPreview = previewGeometry?.id === id ? previewGeometry : null;
|
|
749
|
+
const requestedExpanded = open ? expanded : lastExpanded;
|
|
750
|
+
const measuringPreview = open && requestedExpanded && !fromPreview;
|
|
751
|
+
const shownExpanded = requestedExpanded && !measuringPreview;
|
|
752
|
+
const shownPinned = open ? pinned : lastPinned;
|
|
753
|
+
const centered = shownExpanded && expansion && expansion.placement === "center";
|
|
754
|
+
const anchoredExpansion = shownExpanded && !centered && fromPreview;
|
|
755
|
+
const { refs, update, floatingStyles, context, isPositioned, placement, middlewareData } = useFloating({ open, elements: { reference: anchor ?? null }, onOpenChange: (next) => {
|
|
756
|
+
if (!next) close();
|
|
757
|
+
}, strategy: "fixed", transform: false, placement: "bottom-start", whileElementsMounted: autoUpdate, middleware: [offset(8), flip({ padding: 12 }), shift({ padding: 12 }), size({ padding: 12, apply: ({ availableHeight: availableHeight2, elements }) => {
|
|
758
|
+
if (!shownExpanded) elements.floating.style.maxHeight = `${Math.max(0, Math.floor(Math.min(360, availableHeight2)))}px`;
|
|
759
|
+
else if (!centered && !fromPreview) elements.floating.style.maxHeight = `min(${length(expansion && expansion.maxHeight || maxHeight)}, ${Math.max(0, Math.floor(availableHeight2))}px)`;
|
|
760
|
+
} }, [shownExpanded, !!centered, !!fromPreview, expansion && expansion.maxHeight, maxHeight]), {
|
|
761
|
+
name: "limrAnchor",
|
|
762
|
+
options: shownExpanded,
|
|
763
|
+
fn: ({ elements }) => ({ data: { id: elements.reference.dataset?.limrAnchor, expanded: shownExpanded } })
|
|
764
|
+
}] });
|
|
765
|
+
useIsomorphicLayoutEffect(() => {
|
|
766
|
+
if (open && anchor) update();
|
|
767
|
+
}, [anchor, update, open, shownExpanded]);
|
|
768
|
+
const dismiss = useDismiss(context, { escapeKey: true, outsidePress: true });
|
|
769
|
+
const role = useRole(context, { role: "dialog" });
|
|
770
|
+
const { getFloatingProps } = useInteractions([dismiss, role]);
|
|
771
|
+
const ready = !!centered || !!anchoredExpansion || !open || isPositioned && middlewareData.limrAnchor?.id === id && middlewareData.limrAnchor?.expanded === shownExpanded;
|
|
772
|
+
const [surface, setSurface] = useState3(null);
|
|
773
|
+
const edge = (shownExpanded ? fromPreview?.placement ?? "bottom" : placement).startsWith("top") ? "bottom" : "top";
|
|
774
|
+
useCardMotion(surface, refs.floating.current, anchor, open, shownExpanded, ready && !measuringPreview, id, edge, fromPreview?.rect, () => {
|
|
775
|
+
setRetained(null);
|
|
776
|
+
setCollapsedId(null);
|
|
777
|
+
setPreviewGeometry(null);
|
|
778
|
+
});
|
|
779
|
+
useIsomorphicLayoutEffect(() => {
|
|
780
|
+
if (!shownExpanded && open && ready && refs.floating.current) {
|
|
781
|
+
const rect = refs.floating.current.getBoundingClientRect();
|
|
782
|
+
if (!fromPreview || fromPreview.placement !== placement || ["x", "y", "width", "height"].some((key) => Math.abs(rect[key] - fromPreview.rect[key]) > 0.5)) setPreviewGeometry({ id, rect, placement });
|
|
783
|
+
}
|
|
784
|
+
});
|
|
785
|
+
if (!occurrence || disabled) return null;
|
|
786
|
+
const visual = window.visualViewport;
|
|
787
|
+
const viewLeft = visual?.offsetLeft ?? 0, viewTop = visual?.offsetTop ?? 0;
|
|
788
|
+
const availableWidth = visual?.width ?? window.innerWidth, availableHeight = visual?.height ?? window.innerHeight;
|
|
789
|
+
const top = viewTop + 12;
|
|
790
|
+
const bottom = viewTop + availableHeight - 12;
|
|
791
|
+
const heightLimit = Math.max(0, bottom - top);
|
|
792
|
+
const settings = shownExpanded && expansion ? expansion : void 0;
|
|
793
|
+
const width = `min(${length(settings?.width ?? (centered ? 640 : definition?.overlay?.previewWidth ?? previewWidth))}, ${Math.max(0, availableWidth - 24)}px)`;
|
|
794
|
+
let style = { ...floatingStyles, width, maxHeight: Math.min(360, availableHeight - 24) };
|
|
795
|
+
if (settings) {
|
|
796
|
+
style = { ...style, height: settings.height === void 0 ? void 0 : `min(${length(settings.height)}, ${heightLimit}px)`, maxHeight: `min(${length(settings.maxHeight ?? maxHeight)}, ${heightLimit}px)` };
|
|
797
|
+
if (centered) style = { ...style, left: viewLeft + availableWidth / 2, top: viewTop + availableHeight / 2, transform: "translate(-50%, -50%)" };
|
|
798
|
+
else if (fromPreview) {
|
|
799
|
+
const upward = fromPreview.placement.startsWith("top");
|
|
800
|
+
const room = Math.max(0, upward ? fromPreview.rect.bottom - top : bottom - fromPreview.rect.top);
|
|
801
|
+
style = { ...style, left: fromPreview.rect.left, top: upward ? fromPreview.rect.bottom : fromPreview.rect.top, transform: upward ? "translateY(-100%)" : "none", maxWidth: viewLeft + availableWidth - 12 - fromPreview.rect.left, maxHeight: `min(${length(settings.maxHeight ?? maxHeight)}, ${room}px)` };
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
const Card = definition?.overlay?.Card;
|
|
805
|
+
const cardProps = {
|
|
806
|
+
annotation: annotation ?? { id: occurrence.annotationIds[0], type: "unknown" },
|
|
807
|
+
occurrence,
|
|
808
|
+
presentation: shownExpanded ? "expanded" : "preview",
|
|
809
|
+
expanded: shownExpanded,
|
|
810
|
+
pinned: shownPinned,
|
|
811
|
+
canExpand: !!expansion,
|
|
812
|
+
expand: () => {
|
|
813
|
+
setCollapsedId(null);
|
|
814
|
+
runtime.activate(occurrence.id);
|
|
815
|
+
},
|
|
816
|
+
collapse: () => {
|
|
817
|
+
setCollapsedId(occurrence.id);
|
|
818
|
+
runtime.activate(occurrence.id);
|
|
819
|
+
},
|
|
820
|
+
close,
|
|
821
|
+
children: /* @__PURE__ */ jsx4(AnnotationGroup, { occurrence, presentation: shownExpanded ? "expanded" : "preview", expanded: shownExpanded })
|
|
822
|
+
};
|
|
823
|
+
const modal = open && !!centered;
|
|
824
|
+
const card = /* @__PURE__ */ jsx4(FloatingFocusManager, { context, modal, disabled: !open || !pinned || measuringPreview, initialFocus: editing ? -1 : refs.floating, returnFocus: false, children: /* @__PURE__ */ jsx4("div", { ref: refs.setFloating, ...getFloatingProps(), tabIndex: -1, "aria-label": definition?.label ?? locale.annotations, className: "limr-overlay-positioner", style: { ...style, pointerEvents: open ? "auto" : "none", visibility: ready && !measuringPreview ? "visible" : "hidden" }, children: /* @__PURE__ */ jsxs4(
|
|
825
|
+
"div",
|
|
826
|
+
{
|
|
827
|
+
ref: setSurface,
|
|
828
|
+
className: `limr-annotation-overlay ${shownExpanded ? "limr-annotation-expanded" : "limr-annotation-preview"}`,
|
|
829
|
+
style: { "--limr-annotation-color": definition?.color },
|
|
830
|
+
"data-type": annotation?.type,
|
|
831
|
+
"data-state": open ? "open" : "closing",
|
|
832
|
+
"data-pinned": shownPinned || void 0,
|
|
833
|
+
"data-placement": centered ? "center" : anchoredExpansion ? fromPreview.placement : placement,
|
|
834
|
+
"data-limr-theme": theme,
|
|
835
|
+
"data-limr-appearance": appearance,
|
|
836
|
+
onPointerEnter: (event) => {
|
|
837
|
+
if (!pinned && event.pointerType !== "touch") runtime.hover(occurrence.id);
|
|
838
|
+
},
|
|
839
|
+
onPointerLeave: () => {
|
|
840
|
+
if (!pinned) runtime.hover(null);
|
|
841
|
+
},
|
|
842
|
+
children: [
|
|
843
|
+
/* @__PURE__ */ jsx4("div", { className: "limr-overlay-surface", "aria-hidden": "true" }),
|
|
844
|
+
/* @__PURE__ */ jsx4("div", { className: "limr-overlay-card", children: Card && annotation ? /* @__PURE__ */ jsx4(Card, { ...cardProps }) : /* @__PURE__ */ jsx4(AnnotationCard, { ...cardProps, title: definition?.label ?? annotation?.type ?? locale.annotations }) })
|
|
845
|
+
]
|
|
846
|
+
}
|
|
847
|
+
) }) });
|
|
848
|
+
return /* @__PURE__ */ jsx4(FloatingPortal, { root: portalRoot, children: /* @__PURE__ */ jsx4(FloatingOverlay, { className: "limr-backdrop", "data-expanded": modal || void 0, lockScroll: modal, style: { pointerEvents: modal ? "auto" : "none" }, children: card }) });
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
// src/components/SelectionToolbar.tsx
|
|
852
|
+
import { useEffect as useEffect6, useId, useMemo as useMemo2, useRef as useRef4, useState as useState4 } from "react";
|
|
853
|
+
import { autoUpdate as autoUpdate2, FloatingPortal as FloatingPortal2, offset as offset2, shift as shift2, useFloating as useFloating2 } from "@floating-ui/react";
|
|
854
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
855
|
+
var defaults = [highlightPalette(), highlightSelection(), copyText(), deleteAnnotations()];
|
|
856
|
+
function SelectionToolbar({ actions, portalRoot, maxPanelHeight = 260, className = "", style, render }) {
|
|
857
|
+
const runtime = useRuntime();
|
|
858
|
+
const appearance = useAppearance(), theme = useTheme();
|
|
859
|
+
const selection = useSelection();
|
|
860
|
+
const interaction = useStoreSelector(runtime.interaction, (value) => value);
|
|
861
|
+
const decorations = useStoreSelector(runtime.decorations, (value) => value);
|
|
862
|
+
const config = useStoreSelector(runtime.configuration, (value) => value);
|
|
863
|
+
const paint = interaction.activeHighlight ? decorations.highlights.get(interaction.activeHighlight) : null;
|
|
864
|
+
const active = decorations.occurrences.find((item) => item.id === interaction.active);
|
|
865
|
+
const hiddenActive = active && [...decorations.highlights.values()].some((item) => item.hidden && sameRange(item.range, active.range));
|
|
866
|
+
const combined = useMemo2(() => {
|
|
867
|
+
const map = new Map((actions ?? defaults).map((action) => [action.id, action]));
|
|
868
|
+
config.extensions?.forEach((extension) => extension.actions?.forEach((action) => map.set(action.id, action)));
|
|
869
|
+
actions?.forEach((action) => map.set(action.id, action));
|
|
870
|
+
const order = (action) => action.placement === "start" ? -1 : action.placement === "end" ? 1 : 0;
|
|
871
|
+
return [...map.values()].sort((a, b) => order(a) - order(b));
|
|
872
|
+
}, [config.extensions, actions]);
|
|
873
|
+
const [busy, setBusy] = useState4(null);
|
|
874
|
+
const busyRef = useRef4(false);
|
|
875
|
+
const [error, setError] = useState4(null);
|
|
876
|
+
const [expanded, setExpanded] = useState4(null);
|
|
877
|
+
const [success, setSuccess] = useState4(null);
|
|
878
|
+
const [deleteHintOpen, setDeleteHintOpen] = useState4(false);
|
|
879
|
+
const [preferredHighlight, setPreferredHighlight] = useState4(defaultHighlight);
|
|
880
|
+
const closeTimer = useRef4(void 0);
|
|
881
|
+
const successTimer = useRef4(void 0);
|
|
882
|
+
const panelId = useId();
|
|
883
|
+
const documentSnapshot = runtime.document.getSnapshot();
|
|
884
|
+
const effectiveSelection = useMemo2(() => {
|
|
885
|
+
if (selection) return selection;
|
|
886
|
+
if (interaction.editing && active?.annotationIds.includes(interaction.editing)) return null;
|
|
887
|
+
const range = paint?.range ?? (hiddenActive ? active?.range : void 0);
|
|
888
|
+
return range ? selectionFromRange(documentSnapshot, range, {
|
|
889
|
+
text: paint ? runtime.highlightReference?.text ?? annotationReferenceText(documentSnapshot, { id: paint.id, annotationIds: [], range }) : annotationReferenceText(documentSnapshot, active)
|
|
890
|
+
}) : null;
|
|
891
|
+
}, [documentSnapshot, paint, active, selection, interaction.editing, hiddenActive]);
|
|
892
|
+
const annotations = useMemo2(() => effectiveSelection ? [...decorations.annotations.values()].filter((annotation) => resolveAnnotationAnchors(annotation, documentSnapshot).some((anchor) => [...effectiveSelection.raw.ranges, ...effectiveSelection.syntax.ranges].some((range) => sameRange(anchor.range, range)))) : [], [decorations, effectiveSelection, documentSnapshot]);
|
|
893
|
+
const highlight = paint ? decorations.annotations.get(paint.annotationId) : annotations.find((annotation) => annotation.type === "highlight");
|
|
894
|
+
const highlightAppearance = highlight?.data ?? preferredHighlight;
|
|
895
|
+
const context = effectiveSelection ? {
|
|
896
|
+
...runtime.commands,
|
|
897
|
+
selection: effectiveSelection,
|
|
898
|
+
annotations,
|
|
899
|
+
highlight: highlight ?? null,
|
|
900
|
+
locale: runtime.locale,
|
|
901
|
+
addAnnotation: (annotation, options) => runtime.commands.addAnnotation(annotation, { highlight: highlightAppearance, ...options }),
|
|
902
|
+
document: documentSnapshot,
|
|
903
|
+
signal: runtime.signal,
|
|
904
|
+
clearSelection: () => runtime.clearSelection()
|
|
905
|
+
} : null;
|
|
906
|
+
const available = context ? combined.filter((action) => action.visible?.(context) ?? true) : [];
|
|
907
|
+
const expandedAction = available.find((action) => action.id === expanded && action.renderExpanded);
|
|
908
|
+
const hasPanels = available.some((action) => action.renderExpanded);
|
|
909
|
+
const open = !!context && effectiveSelection.settled && available.length > 0;
|
|
910
|
+
const { refs, floatingStyles, placement, isPositioned } = useFloating2({
|
|
911
|
+
open,
|
|
912
|
+
strategy: "fixed",
|
|
913
|
+
placement: "bottom",
|
|
914
|
+
middleware: [offset2(10), { name: "toolbarSpace", options: { hasPanels, maxPanelHeight }, fn({ rects, placement: placement2, elements }) {
|
|
915
|
+
const viewport = window.visualViewport;
|
|
916
|
+
const root = runtime.configuration.get().scrollRoot?.getBoundingClientRect();
|
|
917
|
+
const top = Math.max(viewport?.offsetTop ?? 0, root?.top ?? 0);
|
|
918
|
+
const bottom = Math.min((viewport?.offsetTop ?? 0) + (viewport?.height ?? window.innerHeight), root?.bottom ?? Infinity);
|
|
919
|
+
const above = Math.max(0, rects.reference.y - top - 20), below = Math.max(0, bottom - rects.reference.y - rects.reference.height - 20);
|
|
920
|
+
const row = (elements.floating.querySelector(".limr-toolbar-actions")?.getBoundingClientRect().height ?? 34) + (elements.floating.querySelector(".limr-toolbar-delete-hint")?.getBoundingClientRect().height ?? 0);
|
|
921
|
+
const limit = Math.max(0, parseFloat(getComputedStyle(elements.floating).getPropertyValue("--limr-toolbar-panel-max-height")) || maxPanelHeight);
|
|
922
|
+
const needed = row + (hasPanels ? limit : 0) + 24;
|
|
923
|
+
const next = below >= needed || below >= above ? "bottom" : "top";
|
|
924
|
+
const room = next === "bottom" ? below : above;
|
|
925
|
+
elements.floating.style.setProperty("--limr-toolbar-panel-height", `${Math.max(0, Math.min(limit, room - row - 24))}px`);
|
|
926
|
+
elements.floating.style.setProperty("--limr-toolbar-available-height", `${room}px`);
|
|
927
|
+
return placement2 !== next ? { reset: { placement: next } } : {};
|
|
928
|
+
} }, shift2({ padding: 10 })],
|
|
929
|
+
whileElementsMounted: autoUpdate2
|
|
930
|
+
});
|
|
931
|
+
useEffect6(() => {
|
|
932
|
+
const reference = selection ? runtime.selectionRange : paint ? runtime.highlightReference : active ? runtime.anchors.get(active.id) : null;
|
|
933
|
+
if (reference) refs.setPositionReference({ getBoundingClientRect: () => reference.getBoundingClientRect(), getClientRects: () => reference.getClientRects(), contextElement: runtime.content ?? void 0 });
|
|
934
|
+
}, [runtime, refs, selection, paint, active]);
|
|
935
|
+
const selectionKey = effectiveSelection?.raw.ranges.map((range) => `${range.start}-${range.end}`).join(",") ?? "";
|
|
936
|
+
useEffect6(() => {
|
|
937
|
+
setError(null);
|
|
938
|
+
setExpanded(null);
|
|
939
|
+
setSuccess(null);
|
|
940
|
+
setDeleteHintOpen(false);
|
|
941
|
+
clearTimeout(closeTimer.current);
|
|
942
|
+
clearTimeout(successTimer.current);
|
|
943
|
+
}, [selectionKey, open]);
|
|
944
|
+
useEffect6(() => () => {
|
|
945
|
+
clearTimeout(closeTimer.current);
|
|
946
|
+
clearTimeout(successTimer.current);
|
|
947
|
+
}, []);
|
|
948
|
+
const dismiss = () => {
|
|
949
|
+
runtime.clearSelection();
|
|
950
|
+
runtime.activate(null);
|
|
951
|
+
};
|
|
952
|
+
useEffect6(() => {
|
|
953
|
+
if (!open) return;
|
|
954
|
+
const down = (event) => {
|
|
955
|
+
if (event.target instanceof Element && event.target.closest("[data-limr-selection-ui],.limr-sidebar-card,.limr-overlay-positioner,[data-limr-anchor]")) return;
|
|
956
|
+
if (runtime.interaction.get().activeHighlight) runtime.clearSelection();
|
|
957
|
+
};
|
|
958
|
+
const key = (event) => {
|
|
959
|
+
if (event.key !== "Escape" || event.defaultPrevented) return;
|
|
960
|
+
if (expanded) {
|
|
961
|
+
setExpanded(null);
|
|
962
|
+
refs.floating.current?.querySelector(`[data-action-id="${CSS.escape(expanded)}"] button`)?.focus();
|
|
963
|
+
} else dismiss();
|
|
964
|
+
event.preventDefault();
|
|
965
|
+
};
|
|
966
|
+
document.addEventListener("pointerdown", down);
|
|
967
|
+
document.addEventListener("keydown", key);
|
|
968
|
+
return () => {
|
|
969
|
+
document.removeEventListener("pointerdown", down);
|
|
970
|
+
document.removeEventListener("keydown", key);
|
|
971
|
+
};
|
|
972
|
+
}, [open, expanded, runtime, refs]);
|
|
973
|
+
const expand = (id) => {
|
|
974
|
+
clearTimeout(closeTimer.current);
|
|
975
|
+
setExpanded(id);
|
|
976
|
+
};
|
|
977
|
+
const execute = async (action, operation) => {
|
|
978
|
+
if (!context || busyRef.current || action.disabled?.(context)) return;
|
|
979
|
+
busyRef.current = true;
|
|
980
|
+
setBusy(action.id);
|
|
981
|
+
setError(null);
|
|
982
|
+
try {
|
|
983
|
+
await operation();
|
|
984
|
+
} catch (cause) {
|
|
985
|
+
if (!runtime.signal.aborted) setError(cause instanceof Error ? cause.message : String(cause));
|
|
986
|
+
} finally {
|
|
987
|
+
busyRef.current = false;
|
|
988
|
+
if (!runtime.signal.aborted) setBusy(null);
|
|
989
|
+
}
|
|
990
|
+
};
|
|
991
|
+
const actionContext = (action) => ({
|
|
992
|
+
...context,
|
|
993
|
+
busy: !!busy,
|
|
994
|
+
expanded: expanded === action.id,
|
|
995
|
+
highlightAppearance,
|
|
996
|
+
setHighlightAppearance: setPreferredHighlight,
|
|
997
|
+
expand: () => expand(action.id),
|
|
998
|
+
collapse: () => setExpanded(null),
|
|
999
|
+
run: (operation) => execute(action, () => operation(context))
|
|
1000
|
+
});
|
|
1001
|
+
const run = (action) => execute(action, async () => {
|
|
1002
|
+
if (action.run) await action.run(actionContext(action));
|
|
1003
|
+
else if (action.renderExpanded) expanded === action.id ? setExpanded(null) : expand(action.id);
|
|
1004
|
+
if (action.successLabel && !runtime.signal.aborted) {
|
|
1005
|
+
setSuccess(action.id);
|
|
1006
|
+
clearTimeout(successTimer.current);
|
|
1007
|
+
successTimer.current = setTimeout(() => setSuccess(null), 2400);
|
|
1008
|
+
}
|
|
1009
|
+
});
|
|
1010
|
+
if (!open || !context) return null;
|
|
1011
|
+
const label = (action) => {
|
|
1012
|
+
const value = success === action.id && action.successLabel ? action.successLabel : action.label;
|
|
1013
|
+
return typeof value === "function" ? value(context) : value;
|
|
1014
|
+
};
|
|
1015
|
+
const annotationCount = annotations.filter((annotation) => annotation.type !== "highlight").length;
|
|
1016
|
+
const hint = available.some((action) => action.id === "delete-annotations") && annotationCount > 1 ? context.locale.deleteAnnotationsHint.replace("{count}", String(annotationCount)) : null;
|
|
1017
|
+
return /* @__PURE__ */ jsx5(FloatingPortal2, { root: portalRoot, children: /* @__PURE__ */ jsx5(
|
|
1018
|
+
"div",
|
|
1019
|
+
{
|
|
1020
|
+
ref: refs.setFloating,
|
|
1021
|
+
className: `limr-selection-toolbar ${className}`,
|
|
1022
|
+
style: { ...style, ...floatingStyles, visibility: isPositioned ? void 0 : "hidden" },
|
|
1023
|
+
role: "toolbar",
|
|
1024
|
+
"aria-label": "Text actions",
|
|
1025
|
+
"data-limr-selection-ui": "true",
|
|
1026
|
+
"data-limr-theme": theme,
|
|
1027
|
+
"data-limr-appearance": appearance,
|
|
1028
|
+
"data-placement": placement,
|
|
1029
|
+
"data-highlight": highlight?.id,
|
|
1030
|
+
"data-expanded": expandedAction?.id,
|
|
1031
|
+
onMouseDown: (event) => {
|
|
1032
|
+
if (!(event.target instanceof Element) || !event.target.closest("input,textarea,select,[contenteditable]")) event.preventDefault();
|
|
1033
|
+
},
|
|
1034
|
+
onPointerEnter: () => clearTimeout(closeTimer.current),
|
|
1035
|
+
onPointerLeave: (event) => {
|
|
1036
|
+
if (event.pointerType !== "mouse" || event.currentTarget.contains(document.activeElement)) return;
|
|
1037
|
+
closeTimer.current = setTimeout(() => setExpanded(null), 200);
|
|
1038
|
+
},
|
|
1039
|
+
onBlur: (event) => {
|
|
1040
|
+
if (!event.currentTarget.contains(event.relatedTarget) && !event.currentTarget.matches(":hover")) setExpanded(null);
|
|
1041
|
+
},
|
|
1042
|
+
onKeyDown: (event) => {
|
|
1043
|
+
if (event.target instanceof Element && event.target.closest(".limr-toolbar-panel")) return;
|
|
1044
|
+
if (!["ArrowRight", "ArrowLeft", "Home", "End", "ArrowDown", "ArrowUp"].includes(event.key)) return;
|
|
1045
|
+
if (event.key === "ArrowDown" || event.key === "ArrowUp") {
|
|
1046
|
+
const id = event.target.closest("[data-action-id]")?.dataset.actionId;
|
|
1047
|
+
const action = available.find((item) => item.id === id);
|
|
1048
|
+
if (action?.renderExpanded) {
|
|
1049
|
+
expand(action.id);
|
|
1050
|
+
requestAnimationFrame(() => refs.floating.current?.querySelector(".limr-toolbar-panel button,.limr-toolbar-panel input,.limr-toolbar-panel textarea")?.focus());
|
|
1051
|
+
}
|
|
1052
|
+
} else {
|
|
1053
|
+
const buttons = Array.from(event.currentTarget.querySelectorAll(".limr-toolbar-actions button:not(:disabled)"));
|
|
1054
|
+
const current = buttons.indexOf(document.activeElement);
|
|
1055
|
+
const index = event.key === "Home" ? 0 : event.key === "End" ? buttons.length - 1 : (current + (event.key === "ArrowRight" ? 1 : buttons.length - 1)) % buttons.length;
|
|
1056
|
+
buttons[index]?.focus();
|
|
1057
|
+
}
|
|
1058
|
+
event.preventDefault();
|
|
1059
|
+
},
|
|
1060
|
+
children: /* @__PURE__ */ jsxs5("div", { className: "limr-toolbar-surface", "data-ready": isPositioned || void 0, children: [
|
|
1061
|
+
/* @__PURE__ */ jsx5("div", { className: "limr-toolbar-actions", children: render ? render({ context, actions: available, run }) : available.map((action, index) => /* @__PURE__ */ jsx5(
|
|
1062
|
+
"div",
|
|
1063
|
+
{
|
|
1064
|
+
className: "limr-toolbar-item",
|
|
1065
|
+
"data-action-id": action.id,
|
|
1066
|
+
"data-active": expanded === action.id || void 0,
|
|
1067
|
+
"data-tone": action.tone,
|
|
1068
|
+
"data-status": success === action.id ? "success" : void 0,
|
|
1069
|
+
style: { "--limr-tool-index": index },
|
|
1070
|
+
onPointerEnter: (event) => {
|
|
1071
|
+
if (event.pointerType !== "mouse" || busy || action.disabled?.(context)) return;
|
|
1072
|
+
if (expandedAction && expandedAction.id !== action.id && refs.floating.current?.querySelector(".limr-toolbar-panel")?.contains(document.activeElement)) return;
|
|
1073
|
+
clearTimeout(closeTimer.current);
|
|
1074
|
+
if (action.renderExpanded) expand(action.id);
|
|
1075
|
+
else setExpanded(null);
|
|
1076
|
+
try {
|
|
1077
|
+
action.onHover?.(actionContext(action));
|
|
1078
|
+
} catch (cause) {
|
|
1079
|
+
setError(cause instanceof Error ? cause.message : String(cause));
|
|
1080
|
+
}
|
|
1081
|
+
},
|
|
1082
|
+
children: action.render ? action.render(actionContext(action)) : /* @__PURE__ */ jsxs5(
|
|
1083
|
+
"button",
|
|
1084
|
+
{
|
|
1085
|
+
className: "limr-toolbar-action",
|
|
1086
|
+
type: "button",
|
|
1087
|
+
disabled: !!busy || action.disabled?.(context),
|
|
1088
|
+
onClick: () => void run(action),
|
|
1089
|
+
"aria-label": label(action),
|
|
1090
|
+
"aria-busy": busy === action.id,
|
|
1091
|
+
"aria-expanded": action.renderExpanded ? expanded === action.id : void 0,
|
|
1092
|
+
"aria-controls": action.renderExpanded && expanded === action.id ? panelId : void 0,
|
|
1093
|
+
"aria-describedby": action.id === "delete-annotations" && hint && deleteHintOpen ? `${panelId}-delete` : void 0,
|
|
1094
|
+
onPointerEnter: (event) => {
|
|
1095
|
+
if (action.id === "delete-annotations" && event.pointerType !== "touch") setDeleteHintOpen(true);
|
|
1096
|
+
},
|
|
1097
|
+
onPointerLeave: (event) => {
|
|
1098
|
+
if (action.id === "delete-annotations") setDeleteHintOpen(event.currentTarget.matches(":focus-visible"));
|
|
1099
|
+
},
|
|
1100
|
+
onFocus: (event) => {
|
|
1101
|
+
if (action.id === "delete-annotations" && event.currentTarget.matches(":focus-visible")) setDeleteHintOpen(true);
|
|
1102
|
+
},
|
|
1103
|
+
onBlur: (event) => {
|
|
1104
|
+
if (action.id === "delete-annotations" && !event.currentTarget.matches(":hover")) setDeleteHintOpen(false);
|
|
1105
|
+
},
|
|
1106
|
+
children: [
|
|
1107
|
+
/* @__PURE__ */ jsxs5("span", { className: "limr-tool-face", "data-visible": success !== action.id || void 0, "aria-hidden": "true", children: [
|
|
1108
|
+
/* @__PURE__ */ jsx5("span", { className: "limr-tool-icon", children: typeof action.icon === "function" ? action.icon(context) : action.icon }, typeof action.label === "function" ? action.label(context) : action.label),
|
|
1109
|
+
/* @__PURE__ */ jsx5("span", { className: "limr-tool-label limr-underline", children: typeof action.label === "function" ? action.label(context) : action.label })
|
|
1110
|
+
] }),
|
|
1111
|
+
action.successLabel && /* @__PURE__ */ jsxs5("span", { className: "limr-tool-face", "data-visible": success === action.id || void 0, "aria-hidden": "true", children: [
|
|
1112
|
+
/* @__PURE__ */ jsx5("span", { className: "limr-tool-icon", children: action.successIcon ?? (typeof action.icon === "function" ? action.icon(context) : action.icon) }),
|
|
1113
|
+
/* @__PURE__ */ jsx5("span", { className: "limr-tool-label limr-underline", children: typeof action.successLabel === "function" ? action.successLabel(context) : action.successLabel })
|
|
1114
|
+
] })
|
|
1115
|
+
]
|
|
1116
|
+
}
|
|
1117
|
+
)
|
|
1118
|
+
},
|
|
1119
|
+
action.id
|
|
1120
|
+
)) }),
|
|
1121
|
+
expandedAction && /* @__PURE__ */ jsx5("div", { id: panelId, className: "limr-toolbar-panel", role: "group", "aria-label": label(expandedAction), children: /* @__PURE__ */ jsx5(OverlayScrollArea, { active: true, label: label(expandedAction), children: expandedAction.renderExpanded(actionContext(expandedAction)) }) }, expandedAction.id),
|
|
1122
|
+
hint && /* @__PURE__ */ jsx5(Collapse, { open: deleteHintOpen, keepMounted: true, className: "limr-toolbar-delete-warning", children: /* @__PURE__ */ jsx5("p", { id: `${panelId}-delete`, className: "limr-toolbar-delete-hint", children: hint }) }),
|
|
1123
|
+
error && /* @__PURE__ */ jsx5("span", { role: "alert", className: "limr-action-error", children: error })
|
|
1124
|
+
] }, selectionKey)
|
|
1125
|
+
}
|
|
1126
|
+
) });
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
// src/components/Reader.tsx
|
|
1130
|
+
import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1131
|
+
function Reader({ actions, toc = true, sidebar = true, followOutput = false, sidebarBreakpoint = 1120, fillHeight = true, className, style, ...provider }) {
|
|
1132
|
+
return /* @__PURE__ */ jsx6(DocumentProvider, { ...provider, children: /* @__PURE__ */ jsx6(ReaderLayout, { actions, toc, sidebar, followOutput, sidebarBreakpoint, fillHeight, className, style }) });
|
|
1133
|
+
}
|
|
1134
|
+
function ReaderLayout({ actions, toc, sidebar, followOutput, sidebarBreakpoint, fillHeight, className, style }) {
|
|
1135
|
+
const runtime = useRuntime();
|
|
1136
|
+
const scrollRoot = useStoreSelector(runtime.configuration, (config) => config.scrollRoot);
|
|
1137
|
+
const layout = useStoreSelector(runtime.layout, (value) => value);
|
|
1138
|
+
const appearance = useAppearance();
|
|
1139
|
+
const theme = useTheme();
|
|
1140
|
+
const ref = useRef5(null);
|
|
1141
|
+
const tocRail = useRef5(null);
|
|
1142
|
+
const content = useRef5(null);
|
|
1143
|
+
useOverflowFade(content, runtime, ":scope > .limr-prose");
|
|
1144
|
+
const [width, setWidth] = useState5(0);
|
|
1145
|
+
const [availableHeight, setAvailableHeight] = useState5(0);
|
|
1146
|
+
useIsomorphicLayoutEffect(() => {
|
|
1147
|
+
if (!fillHeight || !ref.current) return;
|
|
1148
|
+
const origin = ref.current.getBoundingClientRect().top - runtime.getViewportTop() - (scrollRoot?.clientTop ?? 0) + runtime.getScrollTop();
|
|
1149
|
+
setAvailableHeight(Math.max(0, (scrollRoot?.clientHeight ?? window.innerHeight) - origin));
|
|
1150
|
+
}, [runtime, scrollRoot, fillHeight, layout, width]);
|
|
1151
|
+
useEffect7(() => {
|
|
1152
|
+
const element = ref.current;
|
|
1153
|
+
if (!element) return;
|
|
1154
|
+
const observer = new ResizeObserver(() => {
|
|
1155
|
+
setWidth(element.clientWidth);
|
|
1156
|
+
runtime.requestLayout();
|
|
1157
|
+
});
|
|
1158
|
+
observer.observe(element);
|
|
1159
|
+
if (scrollRoot) observer.observe(scrollRoot);
|
|
1160
|
+
if (element.parentElement) observer.observe(element.parentElement);
|
|
1161
|
+
setWidth(element.clientWidth);
|
|
1162
|
+
return () => observer.disconnect();
|
|
1163
|
+
}, [runtime, scrollRoot, sidebarBreakpoint]);
|
|
1164
|
+
useIsomorphicLayoutEffect(() => {
|
|
1165
|
+
const rail = tocRail.current;
|
|
1166
|
+
if (!rail) return;
|
|
1167
|
+
let frame = 0;
|
|
1168
|
+
const measure = () => {
|
|
1169
|
+
frame = 0;
|
|
1170
|
+
if (!rail.clientWidth) return;
|
|
1171
|
+
const viewport = window.visualViewport;
|
|
1172
|
+
let top = viewport?.offsetTop ?? 0, bottom = top + (viewport?.height ?? window.innerHeight);
|
|
1173
|
+
if (scrollRoot) {
|
|
1174
|
+
const origin = scrollRoot.getBoundingClientRect().top + scrollRoot.clientTop;
|
|
1175
|
+
top = Math.max(top, origin);
|
|
1176
|
+
bottom = Math.min(bottom, origin + scrollRoot.clientHeight);
|
|
1177
|
+
}
|
|
1178
|
+
const reader = ref.current.getBoundingClientRect();
|
|
1179
|
+
rail.toggleAttribute("inert", reader.bottom <= top || reader.top >= bottom);
|
|
1180
|
+
const height = `${Math.max(0, bottom - Math.max(top, rail.getBoundingClientRect().top)).toFixed(2)}px`;
|
|
1181
|
+
if (rail.style.getPropertyValue("--limr-toc-available-height") !== height) rail.style.setProperty("--limr-toc-available-height", height);
|
|
1182
|
+
};
|
|
1183
|
+
const schedule = () => {
|
|
1184
|
+
if (!frame) frame = requestAnimationFrame(measure);
|
|
1185
|
+
};
|
|
1186
|
+
const unsubscribe = [runtime.layout.subscribe(schedule), runtime.viewport.subscribe(schedule)];
|
|
1187
|
+
window.addEventListener("scroll", schedule, { passive: true });
|
|
1188
|
+
window.addEventListener("resize", schedule);
|
|
1189
|
+
window.visualViewport?.addEventListener("resize", schedule);
|
|
1190
|
+
window.visualViewport?.addEventListener("scroll", schedule);
|
|
1191
|
+
measure();
|
|
1192
|
+
return () => {
|
|
1193
|
+
cancelAnimationFrame(frame);
|
|
1194
|
+
unsubscribe.forEach((fn) => fn());
|
|
1195
|
+
window.removeEventListener("scroll", schedule);
|
|
1196
|
+
window.removeEventListener("resize", schedule);
|
|
1197
|
+
window.visualViewport?.removeEventListener("resize", schedule);
|
|
1198
|
+
window.visualViewport?.removeEventListener("scroll", schedule);
|
|
1199
|
+
rail.removeAttribute("inert");
|
|
1200
|
+
rail.style.removeProperty("--limr-toc-available-height");
|
|
1201
|
+
};
|
|
1202
|
+
}, [runtime, scrollRoot, toc]);
|
|
1203
|
+
const sidebarVisible = !!sidebar && width >= sidebarBreakpoint;
|
|
1204
|
+
return /* @__PURE__ */ jsxs6("div", { ref, className: `limr-reader ${className ?? ""}`, style: { "--limr-reader-available-height": fillHeight ? `${availableHeight}px` : void 0, ...style }, "data-fill-height": fillHeight || void 0, "data-sidebar": sidebarVisible || void 0, "data-toc": toc && width >= 800 || void 0, "data-limr-theme": theme, "data-limr-appearance": appearance, children: [
|
|
1205
|
+
toc && /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
1206
|
+
/* @__PURE__ */ jsx6("div", { ref: tocRail, className: "limr-reader-toc", children: /* @__PURE__ */ jsx6(TableOfContents, {}) }),
|
|
1207
|
+
/* @__PURE__ */ jsx6(MobileContents, {})
|
|
1208
|
+
] }),
|
|
1209
|
+
/* @__PURE__ */ jsx6("main", { ref: content, className: "limr-reader-content", children: /* @__PURE__ */ jsx6(Markdown, { followOutput }) }),
|
|
1210
|
+
sidebarVisible && /* @__PURE__ */ jsx6(AnnotationSidebar, {}),
|
|
1211
|
+
/* @__PURE__ */ jsx6(AnnotationOverlay, { disabled: sidebarVisible }),
|
|
1212
|
+
/* @__PURE__ */ jsx6(SelectionToolbar, { actions })
|
|
1213
|
+
] });
|
|
1214
|
+
}
|
|
1215
|
+
function MobileContents() {
|
|
1216
|
+
const locale = useLocale();
|
|
1217
|
+
const [open, setOpen] = useState5(false);
|
|
1218
|
+
const id = useId2();
|
|
1219
|
+
return /* @__PURE__ */ jsxs6("div", { className: "limr-reader-mobile-toc", children: [
|
|
1220
|
+
/* @__PURE__ */ jsxs6("button", { type: "button", className: "limr-mobile-toc-toggle", "aria-expanded": open, "aria-controls": id, onClick: () => setOpen((value) => !value), children: [
|
|
1221
|
+
/* @__PURE__ */ jsx6("span", { children: locale.contents }),
|
|
1222
|
+
/* @__PURE__ */ jsx6("svg", { viewBox: "0 0 20 20", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx6("path", { d: "m6 8 4 4 4-4" }) })
|
|
1223
|
+
] }),
|
|
1224
|
+
/* @__PURE__ */ jsx6("div", { id, children: /* @__PURE__ */ jsx6(Collapse, { open, keepMounted: true, children: /* @__PURE__ */ jsx6(TableOfContents, {}) }) })
|
|
1225
|
+
] });
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
export {
|
|
1229
|
+
TableOfContents,
|
|
1230
|
+
AnnotationContent,
|
|
1231
|
+
AnnotationGroup,
|
|
1232
|
+
alignSidebar,
|
|
1233
|
+
AnnotationSidebar,
|
|
1234
|
+
AnnotationOverlay,
|
|
1235
|
+
SelectionToolbar,
|
|
1236
|
+
Reader
|
|
1237
|
+
};
|
|
1238
|
+
//# sourceMappingURL=chunk-N77VD2YR.js.map
|