@heycys/gallery 0.1.2 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (338) hide show
  1. package/THIRD-PARTY-NOTICES.md +2 -2
  2. package/browser/editor/components/align.mjs +58 -0
  3. package/browser/editor/components/code/index.mjs +1 -1
  4. package/browser/editor/components/embed/page.mjs +1 -1
  5. package/browser/editor/components/file/page.mjs +4 -4
  6. package/browser/editor/components/heading/index.mjs +7 -6
  7. package/browser/editor/components/icon/page.mjs +6 -4
  8. package/browser/editor/components/icons.mjs +5 -2
  9. package/browser/editor/components/image/index.mjs +2 -0
  10. package/browser/editor/components/image/page.mjs +172 -90
  11. package/browser/editor/components/installed/index.mjs +6 -2
  12. package/browser/editor/components/installed/page.mjs +80 -13
  13. package/browser/editor/components/media/icons.mjs +13 -8
  14. package/browser/editor/components/media/page.mjs +5 -3
  15. package/browser/editor/components/media/toolbar.mjs +12 -3
  16. package/browser/editor/components/paragraph/index.mjs +4 -3
  17. package/browser/editor/components/registry.mjs +17 -5
  18. package/browser/editor/components/table/index.mjs +4 -2
  19. package/browser/editor/page/after/index.mjs +288 -0
  20. package/browser/editor/page/align.mjs +91 -0
  21. package/browser/editor/page/beside.mjs +5 -6
  22. package/browser/editor/page/block-menu/index.mjs +6 -3
  23. package/browser/editor/page/blocks.mjs +3 -1
  24. package/browser/editor/page/board/hint.mjs +64 -27
  25. package/browser/editor/page/board/index.mjs +160 -71
  26. package/browser/editor/page/board/motion.mjs +177 -0
  27. package/browser/editor/page/board/settings.mjs +4 -3
  28. package/browser/editor/page/clipboard/import/read.mjs +20 -2
  29. package/browser/editor/page/clipboard/index.mjs +10 -3
  30. package/browser/editor/page/clipboard/own/blocks.mjs +3 -4
  31. package/browser/editor/page/clipboard/own/describe.mjs +6 -2
  32. package/browser/editor/page/commit.mjs +2 -2
  33. package/browser/editor/page/core.mjs +3 -1
  34. package/browser/editor/page/custom-page.mjs +15 -11
  35. package/browser/editor/page/editor.mjs +31 -14
  36. package/browser/editor/page/history.mjs +19 -4
  37. package/browser/editor/page/insert/index.mjs +20 -22
  38. package/browser/editor/page/menu.mjs +15 -7
  39. package/browser/editor/page/page-objects.mjs +3 -7
  40. package/browser/editor/page/present-links.mjs +5 -4
  41. package/browser/editor/page/present-shell.mjs +63 -0
  42. package/browser/editor/page/selection/index.mjs +10 -2
  43. package/browser/editor/page/table/binding.mjs +87 -0
  44. package/browser/editor/page/table/icons.mjs +0 -2
  45. package/browser/editor/page/table/index.mjs +10 -14
  46. package/browser/editor/page/table/views.mjs +5 -52
  47. package/browser/editor/page/table/widths.mjs +82 -10
  48. package/browser/editor/page/typing/index.mjs +44 -12
  49. package/browser/editor/page/typing/leave.mjs +19 -5
  50. package/browser/shared/block-packs.mjs +23 -8
  51. package/browser/shared/component-catalog.mjs +15 -8
  52. package/browser/shared/component-source.mjs +3 -1
  53. package/browser/shared/components/heading.mjs +2 -1
  54. package/browser/shared/components/installed.mjs +1 -1
  55. package/browser/shared/components/page.mjs +2 -0
  56. package/browser/shared/components/paragraph.mjs +8 -1
  57. package/browser/shared/components/table.mjs +1 -0
  58. package/browser/shared/document-copy.mjs +43 -0
  59. package/browser/shared/drafts.mjs +10 -3
  60. package/browser/shared/emoji/icon-value.mjs +2 -2
  61. package/browser/shared/emoji/line-icons.mjs +37 -0
  62. package/browser/shared/extensions.mjs +83 -7
  63. package/browser/shared/http.mjs +9 -0
  64. package/browser/shared/i18n/en.mjs +50 -17
  65. package/browser/shared/outline-shape.mjs +6 -0
  66. package/browser/shared/outline.mjs +165 -12
  67. package/browser/shared/pack-manifest.mjs +12 -1
  68. package/browser/shared/pages.mjs +169 -57
  69. package/browser/shared/pinyin.mjs +92 -0
  70. package/browser/shared/present-step.mjs +17 -0
  71. package/browser/shared/sidebar-head.mjs +70 -0
  72. package/browser/shared/web-links.mjs +5 -0
  73. package/browser/shared/workspace-columns.mjs +11 -7
  74. package/dist/{chunk-N7AZZLGT.mjs → chunk-2GKGEVMR.mjs} +29 -24
  75. package/dist/chunk-2OHANJ6Q.mjs +2 -0
  76. package/dist/{chunk-HYMEEXKN.mjs → chunk-2RKIHJI2.mjs} +1 -1
  77. package/dist/{chunk-742D2WWJ.mjs → chunk-36FIRJIF.mjs} +2 -2
  78. package/dist/{chunk-BPL64HGA.mjs → chunk-3A5I2GJK.mjs} +1 -1
  79. package/dist/{chunk-RFDZXFJF.mjs → chunk-3OFXMN6N.mjs} +1 -1
  80. package/dist/chunk-46ACXOU5.mjs +2 -0
  81. package/dist/{chunk-PUOQ65NC.mjs → chunk-4AMTKWDO.mjs} +1 -1
  82. package/dist/{chunk-VTKNEYT3.mjs → chunk-4DNHHJSL.mjs} +1 -1
  83. package/dist/chunk-5DPABPBI.mjs +2 -0
  84. package/dist/chunk-5IIH335D.mjs +3 -0
  85. package/dist/chunk-5L26JUYA.mjs +2 -0
  86. package/dist/{chunk-3NJACR4W.mjs → chunk-5MEXZ2UF.mjs} +1 -1
  87. package/dist/{chunk-ZHEHPMBK.mjs → chunk-6MPKCH3P.mjs} +1 -1
  88. package/dist/{chunk-C564NU2H.mjs → chunk-74RPP2M2.mjs} +1 -1
  89. package/dist/chunk-7M2BQQGZ.mjs +2 -0
  90. package/dist/{chunk-VXACTLO3.mjs → chunk-7M7UPWU6.mjs} +1 -1
  91. package/dist/{chunk-ZB4H7ZN4.mjs → chunk-7N2LPG33.mjs} +1 -1
  92. package/dist/{chunk-UBBRTJ2R.mjs → chunk-7XDYK3UC.mjs} +1 -1
  93. package/dist/chunk-AEMVZYZQ.mjs +166 -0
  94. package/dist/{chunk-POQSE4C2.mjs → chunk-AFGUR7SY.mjs} +1 -1
  95. package/dist/{chunk-QKXMPUXC.mjs → chunk-AMDGVDNV.mjs} +1 -1
  96. package/dist/{chunk-KTKHRC6H.mjs → chunk-ASAXY2DJ.mjs} +1 -1
  97. package/dist/{chunk-NVRNLK25.mjs → chunk-BYSF5UMM.mjs} +2 -2
  98. package/dist/{chunk-U3SSPL4K.mjs → chunk-CCSGFCLZ.mjs} +1 -1
  99. package/dist/{chunk-NWFBE2YA.mjs → chunk-CG3UHDKH.mjs} +1 -1
  100. package/dist/chunk-CPS4SRPF.mjs +5 -0
  101. package/dist/{chunk-B4P2CM2J.mjs → chunk-CZ5KJSGK.mjs} +1 -1
  102. package/dist/chunk-DAMVDXR3.mjs +2 -0
  103. package/dist/{chunk-NG375ILQ.mjs → chunk-DH6GMDNN.mjs} +1 -1
  104. package/dist/chunk-DHB7UZ7F.mjs +3 -0
  105. package/dist/{chunk-MHW7ZKOU.mjs → chunk-DKR7LFIY.mjs} +1 -1
  106. package/dist/chunk-DLFZJJEE.mjs +2 -0
  107. package/dist/{chunk-6EZ7FNIK.mjs → chunk-F4ZA6JRZ.mjs} +1 -1
  108. package/dist/{chunk-6VTU6KEO.mjs → chunk-FCK6NXON.mjs} +1 -1
  109. package/dist/{chunk-ZWPMCK7P.mjs → chunk-FX42XU6J.mjs} +1 -1
  110. package/dist/chunk-FXQBADMN.mjs +5 -0
  111. package/dist/{chunk-W3BGBJQW.mjs → chunk-G4YP7GVC.mjs} +1 -1
  112. package/dist/{chunk-V6XZ4VIR.mjs → chunk-GWOYMENX.mjs} +1 -1
  113. package/dist/chunk-HATA2W7X.mjs +2 -0
  114. package/dist/{chunk-YI43RG4P.mjs → chunk-HBAUKKQH.mjs} +1 -1
  115. package/dist/{chunk-MAFIGVXY.mjs → chunk-HM4E43VM.mjs} +1 -1
  116. package/dist/{chunk-CRJEG7MT.mjs → chunk-JI6T3A4Y.mjs} +1 -1
  117. package/dist/{chunk-NFMCP2HI.mjs → chunk-JJNRIFND.mjs} +2 -2
  118. package/dist/chunk-JL6R4FG4.mjs +4 -0
  119. package/dist/{chunk-UMHUSOPJ.mjs → chunk-JXLSHVJ2.mjs} +1 -1
  120. package/dist/{chunk-FJYN7RTH.mjs → chunk-KFZBYDIS.mjs} +1 -1
  121. package/dist/{chunk-ZTHICSSF.mjs → chunk-KH24LWAT.mjs} +1 -1
  122. package/dist/{chunk-RKPWLGZ3.mjs → chunk-KUILYI7H.mjs} +1 -1
  123. package/dist/{chunk-RMECZA2K.mjs → chunk-L7W624FD.mjs} +1 -1
  124. package/dist/chunk-LE44MD3O.mjs +4 -0
  125. package/dist/{chunk-4K5KC6V2.mjs → chunk-LV24RY2E.mjs} +1 -1
  126. package/dist/{chunk-43B75J5T.mjs → chunk-MKTX5PGV.mjs} +1 -1
  127. package/dist/{chunk-LKX55H76.mjs → chunk-NAGMRVW4.mjs} +1 -1
  128. package/dist/{chunk-D4CKRD3V.mjs → chunk-NFABH3QW.mjs} +2 -2
  129. package/dist/{chunk-PVER7LSC.mjs → chunk-NIW7F7LU.mjs} +2 -2
  130. package/dist/{chunk-PAREWQGB.mjs → chunk-NWRZXELO.mjs} +1 -1
  131. package/dist/{chunk-OJKMINIU.mjs → chunk-OU3S466R.mjs} +15 -15
  132. package/dist/{chunk-5ZJA7CXT.mjs → chunk-PAFSFVYB.mjs} +1 -1
  133. package/dist/chunk-QCEATQC4.mjs +2 -0
  134. package/dist/{chunk-Y34NR5JL.mjs → chunk-QJ3TFJLQ.mjs} +1 -1
  135. package/dist/{chunk-IA4PSIMD.mjs → chunk-QK3VISCA.mjs} +1 -1
  136. package/dist/{chunk-ZUNVAXLH.mjs → chunk-QXVNUASA.mjs} +1 -1
  137. package/dist/{chunk-GRAXKKG4.mjs → chunk-QZ35UAB4.mjs} +1 -1
  138. package/dist/{chunk-UGWYKHBL.mjs → chunk-S2Y7VI4H.mjs} +2 -2
  139. package/dist/{chunk-OW5NWPOJ.mjs → chunk-SAHS56QM.mjs} +1 -1
  140. package/dist/{chunk-QOUEFUCH.mjs → chunk-SOD23RGL.mjs} +1 -1
  141. package/dist/chunk-TDWJKOLN.mjs +2 -0
  142. package/dist/{chunk-V6RIYQZZ.mjs → chunk-TOE6DPLH.mjs} +1 -1
  143. package/dist/chunk-UGO5N3EI.mjs +15 -0
  144. package/dist/{chunk-Q47PLKIJ.mjs → chunk-UGWMMEJ5.mjs} +1 -1
  145. package/dist/{chunk-NWR2LT5B.mjs → chunk-V5JRSGZF.mjs} +1 -1
  146. package/dist/{chunk-BZ5RAF7L.mjs → chunk-VA3KAQZD.mjs} +1 -1
  147. package/dist/chunk-VG5JEIUQ.mjs +12 -0
  148. package/dist/{chunk-UNOYVIYR.mjs → chunk-VGTMLQWZ.mjs} +1 -1
  149. package/dist/chunk-VKSRM7EY.mjs +22 -0
  150. package/dist/{chunk-YQGT4AB2.mjs → chunk-VNUWREXU.mjs} +1 -1
  151. package/dist/{chunk-AGDILNWB.mjs → chunk-VPVOAJ7X.mjs} +1 -1
  152. package/dist/{chunk-HLYV7RIH.mjs → chunk-WCWYNFDF.mjs} +1 -1
  153. package/dist/chunk-WTEGUPFG.mjs +16 -0
  154. package/dist/{chunk-N76HWBA3.mjs → chunk-XKOHV4H6.mjs} +1 -1
  155. package/dist/{chunk-HMYTM3GT.mjs → chunk-XMKHCUI6.mjs} +1 -1
  156. package/dist/{chunk-OUUP3WKT.mjs → chunk-XQRUG4G3.mjs} +1 -1
  157. package/dist/{chunk-32ZUEFZ7.mjs → chunk-YBB5LWZK.mjs} +1 -1
  158. package/dist/{chunk-SX4LJYT6.mjs → chunk-YFJU3O7G.mjs} +1 -1
  159. package/dist/chunk-YPPJVDQI.mjs +2 -0
  160. package/dist/chunk-ZANMKAWS.mjs +2 -0
  161. package/dist/{chunk-6QBHU4DF.mjs → chunk-ZCP7BTOZ.mjs} +1 -1
  162. package/dist/{chunk-ERLAIBOA.mjs → chunk-ZEY2RLBT.mjs} +2 -2
  163. package/dist/{chunk-SQ6Y2ZMA.mjs → chunk-ZO7SFB2E.mjs} +2 -2
  164. package/dist/cli.mjs +1 -1
  165. package/dist/server.mjs +1 -1
  166. package/dist/worker.mjs +1 -1
  167. package/kit/board.css +5 -5
  168. package/kit/code.js +15 -15
  169. package/kit/math.js +1 -1
  170. package/kit/report.css +123 -44
  171. package/kit/runtime.js +45 -7
  172. package/kit/tables.js +2 -0
  173. package/kit/ui.js +2 -0
  174. package/package.json +1 -1
  175. package/packs/gallery/chart-view/kit.js +3 -3
  176. package/packs/gallery/chart-view/writing.md +1 -1
  177. package/packs/gallery/countdown/component.json +1 -1
  178. package/packs/gallery/countdown/kit.js +89 -29
  179. package/packs/gallery/countdown/preview.svg +1 -1
  180. package/packs/gallery/countdown/style.css +88 -100
  181. package/packs/gallery/countdown/writing.md +2 -2
  182. package/packs/gallery/habit/component.json +3 -3
  183. package/packs/gallery/habit/kit.js +114 -75
  184. package/packs/gallery/habit/preview.svg +1 -1
  185. package/packs/gallery/habit/style.css +133 -205
  186. package/packs/gallery/habit/writing.md +2 -2
  187. package/packs/gallery/heatmap/component.json +2 -2
  188. package/packs/gallery/heatmap/kit.js +335 -173
  189. package/packs/gallery/heatmap/preview.svg +1 -1
  190. package/packs/gallery/heatmap/style.css +158 -170
  191. package/packs/gallery/heatmap/writing.md +2 -2
  192. package/packs/gallery/kanban/kit.js +3 -3
  193. package/packs/gallery/kanban/writing.md +1 -1
  194. package/packs/gallery/metric/kit.js +3 -3
  195. package/packs/gallery/metric/writing.md +1 -1
  196. package/packs/gallery/note/component.json +3 -3
  197. package/packs/gallery/note/kit.js +40 -13
  198. package/packs/gallery/note/preview.svg +1 -1
  199. package/packs/gallery/note/style.css +51 -30
  200. package/packs/gallery/note/writing.md +2 -2
  201. package/packs/gallery/recent/component.json +2 -2
  202. package/packs/gallery/recent/kit.js +141 -86
  203. package/packs/gallery/recent/preview.svg +1 -1
  204. package/packs/gallery/recent/style.css +53 -126
  205. package/packs/gallery/recent/writing.md +2 -2
  206. package/packs/gallery/static/component.json +2 -2
  207. package/packs/gallery/static/preview.svg +1 -1
  208. package/packs/gallery/static/style.css +99 -66
  209. package/packs/gallery/static/writing.md +2 -2
  210. package/packs/gallery/stats/component.json +3 -3
  211. package/packs/gallery/stats/kit.js +253 -72
  212. package/packs/gallery/stats/preview.svg +1 -1
  213. package/packs/gallery/stats/style.css +64 -142
  214. package/packs/gallery/stats/writing.md +2 -2
  215. package/packs/gallery/today/component.json +2 -2
  216. package/packs/gallery/today/kit.js +62 -27
  217. package/packs/gallery/today/preview.svg +1 -1
  218. package/packs/gallery/today/style.css +101 -72
  219. package/packs/gallery/today/writing.md +2 -2
  220. package/packs/gallery/todos/component.json +1 -1
  221. package/packs/gallery/todos/kit.js +218 -71
  222. package/packs/gallery/todos/preview.svg +1 -1
  223. package/packs/gallery/todos/style.css +170 -223
  224. package/packs/gallery/todos/writing.md +1 -1
  225. package/packs/gallery/weather/component.json +2 -2
  226. package/packs/gallery/weather/kit.js +165 -90
  227. package/packs/gallery/weather/preview.svg +1 -1
  228. package/packs/gallery/weather/style.css +100 -218
  229. package/packs/gallery/weather/writing.md +1 -1
  230. package/packs/gallery-soft/countdown/component.json +18 -0
  231. package/packs/gallery-soft/countdown/example.html +3 -0
  232. package/packs/gallery-soft/countdown/kit.js +206 -0
  233. package/packs/gallery-soft/countdown/preview.svg +1 -0
  234. package/packs/gallery-soft/countdown/style.css +211 -0
  235. package/packs/gallery-soft/countdown/template.html +3 -0
  236. package/packs/gallery-soft/countdown/writing.md +24 -0
  237. package/packs/gallery-soft/habit/component.json +14 -0
  238. package/packs/gallery-soft/habit/example.html +3 -0
  239. package/packs/gallery-soft/habit/kit.js +366 -0
  240. package/packs/gallery-soft/habit/preview.svg +1 -0
  241. package/packs/gallery-soft/habit/style.css +251 -0
  242. package/packs/gallery-soft/habit/template.html +3 -0
  243. package/packs/gallery-soft/habit/writing.md +23 -0
  244. package/packs/gallery-soft/heatmap/component.json +18 -0
  245. package/packs/gallery-soft/heatmap/example.html +3 -0
  246. package/packs/gallery-soft/heatmap/kit.js +498 -0
  247. package/packs/gallery-soft/heatmap/preview.svg +1 -0
  248. package/packs/gallery-soft/heatmap/style.css +181 -0
  249. package/packs/gallery-soft/heatmap/template.html +3 -0
  250. package/packs/gallery-soft/heatmap/writing.md +23 -0
  251. package/packs/gallery-soft/note/component.json +14 -0
  252. package/packs/gallery-soft/note/example.html +3 -0
  253. package/packs/gallery-soft/note/kit.js +162 -0
  254. package/packs/gallery-soft/note/preview.svg +1 -0
  255. package/packs/gallery-soft/note/style.css +148 -0
  256. package/packs/gallery-soft/note/template.html +3 -0
  257. package/packs/gallery-soft/note/writing.md +20 -0
  258. package/packs/gallery-soft/recent/component.json +13 -0
  259. package/packs/gallery-soft/recent/example.html +1 -0
  260. package/packs/gallery-soft/recent/kit.js +335 -0
  261. package/packs/gallery-soft/recent/preview.svg +1 -0
  262. package/packs/gallery-soft/recent/style.css +160 -0
  263. package/packs/gallery-soft/recent/template.html +1 -0
  264. package/packs/gallery-soft/recent/writing.md +17 -0
  265. package/packs/gallery-soft/static/component.json +13 -0
  266. package/packs/gallery-soft/static/example.html +12 -0
  267. package/packs/gallery-soft/static/preview.svg +1 -0
  268. package/packs/gallery-soft/static/style.css +186 -0
  269. package/packs/gallery-soft/static/template.html +1 -0
  270. package/packs/gallery-soft/static/writing.md +20 -0
  271. package/packs/gallery-soft/stats/component.json +13 -0
  272. package/packs/gallery-soft/stats/example.html +1 -0
  273. package/packs/gallery-soft/stats/kit.js +341 -0
  274. package/packs/gallery-soft/stats/preview.svg +1 -0
  275. package/packs/gallery-soft/stats/style.css +119 -0
  276. package/packs/gallery-soft/stats/template.html +1 -0
  277. package/packs/gallery-soft/stats/writing.md +13 -0
  278. package/packs/gallery-soft/today/component.json +12 -0
  279. package/packs/gallery-soft/today/example.html +1 -0
  280. package/packs/gallery-soft/today/kit.js +222 -0
  281. package/packs/gallery-soft/today/preview.svg +1 -0
  282. package/packs/gallery-soft/today/style.css +178 -0
  283. package/packs/gallery-soft/today/template.html +1 -0
  284. package/packs/gallery-soft/today/writing.md +16 -0
  285. package/packs/gallery-soft/todos/component.json +19 -0
  286. package/packs/gallery-soft/todos/example.html +3 -0
  287. package/packs/gallery-soft/todos/kit.js +527 -0
  288. package/packs/gallery-soft/todos/preview.svg +1 -0
  289. package/packs/gallery-soft/todos/style.css +212 -0
  290. package/packs/gallery-soft/todos/template.html +3 -0
  291. package/packs/gallery-soft/todos/writing.md +32 -0
  292. package/packs/gallery-soft/weather/component.json +19 -0
  293. package/packs/gallery-soft/weather/example.html +3 -0
  294. package/packs/gallery-soft/weather/kit.js +411 -0
  295. package/packs/gallery-soft/weather/preview.svg +1 -0
  296. package/packs/gallery-soft/weather/style.css +185 -0
  297. package/packs/gallery-soft/weather/template.html +3 -0
  298. package/packs/gallery-soft/weather/writing.md +28 -0
  299. package/release.json +10 -10
  300. package/skill/SKILL.md +15 -14
  301. package/skill/references/building-blocks.md +4 -4
  302. package/skill/references/extensions.md +11 -7
  303. package/skill/references/pages-and-data.md +13 -9
  304. package/skill/references/writing-html.md +2 -0
  305. package/web/assets/index-BHC5ZOMh.js +15 -0
  306. package/web/assets/index-xP0uw3a0.css +1 -0
  307. package/web/index.html +2 -2
  308. package/dist/chunk-2NRBY6AJ.mjs +0 -2
  309. package/dist/chunk-35NQ4PLQ.mjs +0 -2
  310. package/dist/chunk-3KJHLHUO.mjs +0 -2
  311. package/dist/chunk-4AV456RQ.mjs +0 -2
  312. package/dist/chunk-5XYHDBJ5.mjs +0 -2
  313. package/dist/chunk-6A53MZYZ.mjs +0 -2
  314. package/dist/chunk-6EXH3ORZ.mjs +0 -166
  315. package/dist/chunk-BVEFGE4B.mjs +0 -2
  316. package/dist/chunk-D4EURAX4.mjs +0 -4
  317. package/dist/chunk-DQCE7TJY.mjs +0 -5
  318. package/dist/chunk-FWNRPMCJ.mjs +0 -12
  319. package/dist/chunk-FWW4CSAZ.mjs +0 -2
  320. package/dist/chunk-GY3FAUVM.mjs +0 -2
  321. package/dist/chunk-JVHHHGEA.mjs +0 -3
  322. package/dist/chunk-L7UP52JO.mjs +0 -2
  323. package/dist/chunk-NAMN3RAF.mjs +0 -2
  324. package/dist/chunk-PZDLJJTJ.mjs +0 -3
  325. package/dist/chunk-SXHBYZST.mjs +0 -16
  326. package/dist/chunk-TEZAWDSQ.mjs +0 -2
  327. package/dist/chunk-UFNYFFKO.mjs +0 -20
  328. package/dist/chunk-UKSHDZZ6.mjs +0 -2
  329. package/dist/chunk-VJPFVNNW.mjs +0 -15
  330. package/dist/chunk-VS3ZMVGX.mjs +0 -5
  331. package/web/assets/index-BK2e_07w.js +0 -13
  332. package/web/assets/index-CWFI83mF.css +0 -1
  333. /package/dist/{chunk-YEY3RSFQ.mjs → chunk-5MMN3N5J.mjs} +0 -0
  334. /package/dist/{chunk-UH4SIXTR.mjs → chunk-74UW7QSL.mjs} +0 -0
  335. /package/dist/{chunk-W7XHE4CT.mjs → chunk-EKGYYOSP.mjs} +0 -0
  336. /package/dist/{chunk-QAIHRH3I.mjs → chunk-KNZJT4ET.mjs} +0 -0
  337. /package/dist/{chunk-A55HN5OK.mjs → chunk-N3DSBH5S.mjs} +0 -0
  338. /package/dist/{chunk-QR6A54KJ.mjs → chunk-ZW2A6GBW.mjs} +0 -0
@@ -0,0 +1,177 @@
1
+ // How a board's cards move while they are edited (./index.mjs; docs/render.md "Its cards edited"), the user's
2
+ // word of 2026-11-09: as smooth as the widgets of an iPhone's home screen, nothing that jumps or stutters.
3
+ //
4
+ // - glide(): the cards a change of the layout moves (a draft while a card is dragged or resized, a drop, an
5
+ // undo, 大小 ›) glide from where they were seen to where the layout now puts them (FLIP: their box before
6
+ // and after, a transform from the one to the other run to none) on a spring's ease (spring: a little
7
+ // less than critically damped, its overshoot under 2%), GLIDE ms; a card whose size changed glides its
8
+ // width and height too. A card already gliding to where the layout still puts it is left to go on; one
9
+ // the change sends elsewhere starts again from where it is seen then, so a target that changes under a
10
+ // drag never makes a card jump (interruptible).
11
+ // - createSettle(): a held card's place (or a resized card's size), axis by axis: the pointer's, or within
12
+ // `snap` px of the cells (or the size) a drop gives, those; where that changes (the card comes within the
13
+ // snap or leaves it, or the cells it stands on move) it settles from where it was carried to the new
14
+ // place in SETTLE ms on the same spring, the pointer's own motion never delayed.
15
+ // - createEdgeScroll(): near the window's top or bottom edge a gesture scrolls the page, timed by the frames'
16
+ // clock (not by the pointer's events): within BAND px of the edge, faster as the pointer is nearer it (the
17
+ // square of how far into the band, past the edge the most), FASTEST px a second at the most (12 a frame
18
+ // at 60 frames a second), and growing from nothing over RAMP ms once the pointer comes into the band, so
19
+ // that a card picked up near the edge does not set the page running.
20
+ // - prefers-reduced-motion: no glide and no settling (the layout and the snap at once); the scroll as it is.
21
+
22
+ export const GLIDE = 280; // ms a card glides to where a layout puts it
23
+ export const SETTLE = 180; // ms a held (or resized) card settles on what it snaps to, or comes off it
24
+ export const BAND = 64; // px from the window's top or bottom edge within which a gesture scrolls the page
25
+ export const FASTEST = 720; // px a second the page scrolls at the most
26
+ export const RAMP = 320; // ms over which that speed grows from nothing once the pointer is in the band
27
+
28
+ export const reduced = () => typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
29
+
30
+ // The step response of a spring (damping ZETA, settled within 0.2% at t = 1): 0 at 0, 1 at 1, still at both
31
+ // ends, a crest of under 2% past 1 at t ≈ 0.65.
32
+ const ZETA = 0.8;
33
+ const OMEGA = 6.4 / ZETA;
34
+ const DAMPED = OMEGA * Math.sqrt(1 - ZETA * ZETA);
35
+ export function spring(t) {
36
+ if (t <= 0) return 0;
37
+ if (t >= 1) return 1;
38
+ return 1 - Math.exp(-ZETA * OMEGA * t) * (Math.cos(DAMPED * t) + ((ZETA * OMEGA) / DAMPED) * Math.sin(DAMPED * t));
39
+ }
40
+ // The same as an easing a Web Animation takes (CSS linear() of 40 points), else a close cubic Bézier.
41
+ const EASE = (() => {
42
+ const points = Array.from({ length: 41 }, (_, index) => Math.round(spring(index / 40) * 10000) / 10000).join(", ");
43
+ const curve = `linear(${points})`;
44
+ return typeof CSS !== "undefined" && CSS.supports?.("transition-timing-function", curve) ? curve : "cubic-bezier(.2, .9, .25, 1)";
45
+ })();
46
+
47
+ const running = new WeakMap(); // a card -> its glide under way
48
+ // Where the kit's board script draws a card now: its cells as the CSS takes them (the board's row skip in).
49
+ const keyOf = (card) => ["x", "y", "w", "h"].map((name) => card.style.getPropertyValue(`--gallery-${name}`)).join();
50
+
51
+ /** Whether a card is gliding now. */
52
+ export const isGliding = (card) => running.has(card);
53
+
54
+ /** A card's glide stopped where it is (a gesture takes it up): it stands where the layout puts it. */
55
+ export function stopGlide(card) {
56
+ running.get(card)?.cancel();
57
+ }
58
+
59
+ /**
60
+ * `change()` run (it lays the board out at once: DocBoard.draft or .layout), and each of `cards` it moves
61
+ * glided from where it was seen to its new place. `still`: a card left out (the one a gesture holds, which
62
+ * follows the pointer); `lift`: a card kept over the others while it glides (data-ge-landing: one let go);
63
+ * `settled()`: run once every glide this started has ended (at once where none started). Gives what change() gave.
64
+ */
65
+ export function glide(cards, change, { still = null, lift = null, duration = GLIDE, settled = null } = {}) {
66
+ if (reduced()) {
67
+ const result = change();
68
+ settled?.();
69
+ return result;
70
+ }
71
+ const started = [];
72
+ const before = cards.filter((card) => card !== still).map((card) => ({ card, key: keyOf(card), box: card.getBoundingClientRect() }));
73
+ const result = change();
74
+ for (const { card, key, box } of before) {
75
+ if (!card.isConnected) continue;
76
+ const going = running.get(card);
77
+ if (going && keyOf(card) === key) continue; // on its way to where it still goes
78
+ going?.cancel();
79
+ const now = card.getBoundingClientRect();
80
+ const dx = box.left - now.left;
81
+ const dy = box.top - now.top;
82
+ const sized = Math.abs(box.width - now.width) > 0.5 || Math.abs(box.height - now.height) > 0.5;
83
+ if (Math.abs(dx) < 0.5 && Math.abs(dy) < 0.5 && !sized) continue;
84
+ const from = { transform: `translate(${dx}px, ${dy}px)` };
85
+ const to = { transform: "translate(0px, 0px)" };
86
+ if (sized) {
87
+ Object.assign(from, { width: `${box.width}px`, height: `${box.height}px` });
88
+ Object.assign(to, { width: `${now.width}px`, height: `${now.height}px` });
89
+ }
90
+ const animation = card.animate([from, to], { duration, easing: EASE });
91
+ running.set(card, animation);
92
+ if (card === lift) card.setAttribute("data-ge-landing", "");
93
+ const end = () => {
94
+ if (running.get(card) !== animation) return;
95
+ running.delete(card);
96
+ card.removeAttribute("data-ge-landing");
97
+ };
98
+ animation.addEventListener("finish", end);
99
+ animation.addEventListener("cancel", end);
100
+ started.push(animation.finished.catch(() => {}));
101
+ }
102
+ if (settled) {
103
+ if (started.length) Promise.all(started).then(settled);
104
+ else settled();
105
+ }
106
+ return result;
107
+ }
108
+
109
+ /**
110
+ * A held card's place, or a resized card's size, axis by axis (`name`: "x", "y", "w", "h"): at(name, raw,
111
+ * target, time) gives what is drawn for the pointer's `raw` and the `target` a drop gives (the cells' place
112
+ * or size, px): the target within `snap` px of it, else raw; a change of which (or of the target while on
113
+ * it) settles from where the card was carried, in `duration` ms. gliding(): whether any axis still settles.
114
+ */
115
+ export function createSettle(snap, duration = SETTLE) {
116
+ const axes = new Map();
117
+ return {
118
+ at(name, raw, target, time) {
119
+ const on = Math.abs(raw - target) <= snap;
120
+ const want = on ? target : raw;
121
+ const axis = axes.get(name);
122
+ if (!axis) {
123
+ axes.set(name, { raw, target, on, shown: want, glide: null });
124
+ return want;
125
+ }
126
+ // Where it would be had it gone with the pointer since the last time: what a settling starts from.
127
+ const carried = axis.shown + (raw - axis.raw);
128
+ if (on !== axis.on || (on && target !== axis.target)) axis.glide = reduced() ? null : { offset: carried - want, start: time };
129
+ Object.assign(axis, { raw, target, on });
130
+ let shown = want;
131
+ if (axis.glide) {
132
+ const progress = (time - axis.glide.start) / duration;
133
+ if (progress >= 1) axis.glide = null;
134
+ else shown = want + axis.glide.offset * (1 - spring(progress));
135
+ }
136
+ axis.shown = shown;
137
+ return shown;
138
+ },
139
+ gliding: () => [...axes.values()].some((axis) => axis.glide !== null),
140
+ };
141
+ }
142
+
143
+ /**
144
+ * The page scrolled near the window's edge while a gesture lasts: frame(y, time) once a frame (the pointer's
145
+ * y in the window, the frame's time), whether the page moved; stop() as the gesture ends.
146
+ */
147
+ export function createEdgeScroll({ band = BAND, fastest = FASTEST, ramp = RAMP } = {}) {
148
+ let since = null; // when the pointer came into the band
149
+ let last = null; // the last frame's time
150
+ let carry = 0; // px asked and not yet scrolled (a frame's share is seldom whole)
151
+ return {
152
+ frame(y, time) {
153
+ const step = last === null ? 0 : Math.min(34, Math.max(0, time - last)); // a stalled frame scrolls no more than two
154
+ last = time;
155
+ const into = y < band ? -(band - y) / band : y > innerHeight - band ? (y - (innerHeight - band)) / band : 0;
156
+ if (into === 0) {
157
+ since = null;
158
+ carry = 0;
159
+ return false;
160
+ }
161
+ since ??= time;
162
+ const depth = Math.min(1, Math.abs(into));
163
+ carry += Math.sign(into) * fastest * depth * depth * Math.min(1, (time - since) / ramp) * (step / 1000);
164
+ const whole = Math.trunc(carry);
165
+ if (!whole) return false;
166
+ carry -= whole;
167
+ const was = scrollY;
168
+ scrollBy(0, whole);
169
+ return scrollY !== was;
170
+ },
171
+ stop() {
172
+ since = null;
173
+ last = null;
174
+ carry = 0;
175
+ },
176
+ };
177
+ }
@@ -14,7 +14,8 @@ import { addStyle, button, element, mount } from "../ui.mjs";
14
14
  // workspace's documents by title (the workbench's outline: GET /__gallery/workspace/outline, its web
15
15
  // links no documents), the slug what is kept. A choice from a list (select, document) is a field that
16
16
  // opens the editor's own menu card under it (menu.mjs: rows, the chosen one checked, ↑/↓ Enter Escape from
17
- // the field), not a native <select>: the page cannot style that one's popup, which a browser draws in
17
+ // the field), a choice of the caller's (type "choice", `choices`: [[value, words]], what a document block adds
18
+ // to its fields: the table a view reads) too, not a native <select>: the page cannot style that one's popup, which a browser draws in
18
19
  // the system's colours (a white list with pale words in a dark page, the user's picture of 2026-11-09).
19
20
  // While the form stands, the page is not shown again under it (the board's idle).
20
21
 
@@ -92,9 +93,9 @@ export async function openSettings({ fields, values, name, anchor, save }) {
92
93
  continue;
93
94
  }
94
95
  let control;
95
- const choice = field.type === "select" || field.type === "document"; // chosen from a list
96
+ const choice = field.type === "select" || field.type === "document" || field.type === "choice"; // chosen from a list
96
97
  if (choice) {
97
- const options = field.type === "select" ? field.options.map((option) => [String(option), String(option)]) : [["", t("(未选择)")], ...listed.map(({ slug, title }) => [slug, title])];
98
+ const options = field.type === "select" ? field.options.map((option) => [String(option), String(option)]) : field.type === "choice" ? field.choices : [["", t("(未选择)")], ...listed.map(({ slug, title }) => [slug, title])];
98
99
  if (field.type === "document" && value && !listed.some(({ slug }) => slug === value)) options.push([String(value), String(value)]);
99
100
  const text = element("span", { class: "ge-board-pick-text" });
100
101
  control = element("button", { type: "button", class: "ge-board-pick", "data-key": field.key, "aria-haspopup": "menu", "aria-expanded": "false" }, text, element("span", { html: CHEVRON }));
@@ -14,7 +14,8 @@ import { addressOf } from "../../links/address.mjs";
14
14
  // formatting" (html.mjs containsRichFormatting; WordPress's always): spans, divs and paragraphs
15
15
  // alone paste as their text.
16
16
  // - Office's HTML (its namespaces) that looks like Word's goes through the Word filter (office.mjs).
17
- // - A whole $$ formula $$ → a formula block; several lines from VS Code → code in its language.
17
+ // - A whole $$ formula $$ → a formula block; IDE Markdown → document blocks, other IDE code →
18
+ // code in its language. An unspecified IDE language can be Markdown by its parsed structure.
18
19
  // - HTML: several lines of text, or a table → blocks (html.mjs htmlToBlocks); else one rich text.
19
20
  // - No HTML: several lines → Markdown (markdown.mjs); one line → inline Markdown (bold, links,
20
21
  // addresses, formulas) when it has any, else plain text. A whole line that is a display formula
@@ -89,6 +90,20 @@ function sameAddress(one, other) {
89
90
  }
90
91
  }
91
92
 
93
+ // VS Code and Cursor copy syntax-colored HTML beside the source text, even for Markdown. Use
94
+ // the same Markdown reader as an ordinary text paste, not the colored HTML. A Markdown language
95
+ // hint is enough; for an unspecified language, require some structure or inline formatting the
96
+ // reader actually recognizes. Unrecognized lines remain text; the whole selection need not be
97
+ // valid Markdown. A declared programming language wins over lookalike comments and operators.
98
+ function editorMarkdown({ text, language }) {
99
+ if (language !== "Markdown" && language !== "Plain Text") return null;
100
+ const specs = fromMarkdown(text);
101
+ if (language === "Markdown") return specs;
102
+ const marked = (blocks) => blocks.some((block) => block.type !== "text"
103
+ || block.title.some((piece) => piece[1]?.length) || marked(block.children));
104
+ return !addressOf(text) && marked(specs) ? specs : null;
105
+ }
106
+
92
107
  /**
93
108
  * Another program's content as { kind: "blocks", specs } | { kind: "rich", title } | { kind: "plain",
94
109
  * text } (notion-lite readClipboard, after the editor's own formats).
@@ -98,11 +113,14 @@ export function readExternal(data, options = {}) {
98
113
  const yuque = readYuque(data, options);
99
114
  if (yuque) return yuque;
100
115
  const external = externalContent(data, options);
101
- const { text, html } = external;
116
+ const { text } = external;
102
117
  const convert = { colors: external.colors };
103
118
  const equation = EQUATION.exec(text)?.[1];
104
119
  if (equation?.trim()) return { kind: "blocks", specs: [{ type: "equation", title: [[equation]], props: {}, children: [] }] };
120
+ const markdown = editorMarkdown(external);
121
+ if (markdown?.length && (multiline(text) || markdown.some((block) => block.type !== "text"))) return { kind: "blocks", specs: markdown };
105
122
  if (multiline(text) && external.language) return { kind: "blocks", specs: [{ type: "code", title: [[text]], props: { language: external.language }, children: [] }] };
123
+ const html = markdown ? "" : external.html;
106
124
  if (html) {
107
125
  if (multiline(text) || external.isTable) {
108
126
  const specs = mathifySpecs(htmlToBlocks(parseClipboardHTML(html, options), convert));
@@ -5,7 +5,7 @@ import { formulaMaker } from "../formula/index.mjs";
5
5
  import { inlineItems, spaceAround } from "../../../shared/inline-spacing.mjs";
6
6
  import { caretAt, editable, hostOf, select } from "../caret.mjs";
7
7
  import { formatRange, joinMarks, outOfMarks, rangeAt, rangeOffsets } from "../marks.mjs";
8
- import { BASIC_UNITS, HOSTS, KIND_NAMES, accepts, clipboardOf, takesFormula, texOnly } from "../../components/registry.mjs";
8
+ import { BASIC_UNITS, HOSTS, KIND_NAMES, accepts, clipboardOf, replacedByFile, takesFormula, texOnly } from "../../components/registry.mjs";
9
9
  import { listType } from "../../components/list/index.mjs";
10
10
  import { nodeAround } from "../../components/flowchart/index.mjs";
11
11
  import { cellsData } from "../../components/table/index.mjs";
@@ -284,7 +284,9 @@ export function createClipboard({ editing, blocks, struct, recordText, say, load
284
284
  // anchor.parent, after })): right after the block of `at` (unitElement: a new code block's code stands
285
285
  // for the block), whole, where a block pasted there goes (placeFor: the first box out that takes it, a
286
286
  // list or quote that does not splitting after the block), one undo step (`put`, handed to the
287
- // component, which makes the block and fills it). Returns whether one did.
287
+ // component, which makes the block and fills it, the fill part of that step). An empty block of a kind
288
+ // that says `replacedByFile` (an empty paragraph: notion-lite's pasteFiles removes an empty text block)
289
+ // gives its place to the block instead of staying before it. Returns whether one did.
288
290
  const fromFiles = (at, files) => {
289
291
  const unit = unitElement(at);
290
292
  if (!unit?.closest("main")) return false;
@@ -294,7 +296,12 @@ export function createClipboard({ editing, blocks, struct, recordText, say, load
294
296
  say(t("这里放不下这种块。"));
295
297
  return false;
296
298
  }
297
- struct(place.parents, [], () => ({ touched: [], focus: null, created: placeAfter(place, [block]) }));
299
+ const replaced = replacedByFile(unit.getAttribute("data-ge-unit-kind")) && removableEmpty(unit, unit) && !isFirstLine(unit);
300
+ struct([...new Set([unit.parentElement, ...place.parents])], [], () => {
301
+ const created = placeAfter(place, [block]);
302
+ if (replaced) removalTarget(unit).remove();
303
+ return { touched: [], focus: null, created };
304
+ });
298
305
  return true;
299
306
  };
300
307
  return pageObjects().some((page) => {
@@ -2,9 +2,8 @@ import { escapeText } from "../../../../shared/escape.mjs";
2
2
  import { heldIn, newContainer, newHost, pastedLines } from "../../core.mjs";
3
3
  import { pageBuild } from "../../../components/builders.mjs";
4
4
  import { BLOCK_TYPES, COPIED_AS_ITSELF, HOLDS_ONE, TEXT_TYPES, TOGGLES, UNSAID, accepts, clipboardHooks, clipboardOf, isLead, sizeValue } from "../../../components/registry.mjs";
5
- import { BLOCK_COLORS } from "../../../components/colors.mjs";
6
5
  import { MAX_CELL_HTML } from "../../../components/table/index.mjs";
7
- import { copied, copyOf } from "./describe.mjs";
6
+ import { BLOCK_LOOKS, copied, copyOf } from "./describe.mjs";
8
7
  import { imageSource, kindOfBlock, webPage } from "./rules.mjs";
9
8
 
10
9
  // Described blocks (describe.mjs and selection.mjs, and import/to-blocks.mjs for other programs' content) made (build),
@@ -42,7 +41,7 @@ export function checkBlocks(blocks) {
42
41
  const { type } = block;
43
42
  const clip = clipboardOf(type);
44
43
  if (box && !accepts(box, kindOfBlock(block)) && clip.pastedIn !== box) return false;
45
- if (block.color !== undefined && (typeof block.color !== "string" || !block.color.split(" ").every((name) => BLOCK_COLORS.includes(name)))) return false;
44
+ if (block.color !== undefined && (typeof block.color !== "string" || !block.color.split(" ").every((name) => BLOCK_LOOKS.includes(name)))) return false;
46
45
  if (TEXT_TYPES.has(type)) return string(block.html);
47
46
  if (type === "copy") return COPIES.has(block.kind) && Number.isInteger(block.unit) && [block.report, block.text, block.html].every((value) => typeof value === "string")
48
47
  && (block.data === undefined || (Boolean(clipboardOf(block.data?.type).data) && valid(block.data)));
@@ -120,7 +119,7 @@ function inline(doc, html, { formula = null, mention = null, picture = null } =
120
119
  }
121
120
 
122
121
 
123
- // A block's colors (`color`: their classes, one of each family), those its kind takes (TOGGLES).
122
+ // A block's colors (`color`: their classes, one of each family, and a text block's alignment and indent), those its kind takes (TOGGLES).
124
123
  function colored(element, block) {
125
124
  for (const name of block.color?.split(" ") ?? []) if (TOGGLES[element.getAttribute("data-ge-unit-kind")]?.includes(name)) element.classList.add(name);
126
125
  return element;
@@ -1,5 +1,6 @@
1
1
  import { isHost, nestedBlocks, serializeInner, unitsOf } from "../../core.mjs";
2
2
  import { BLOCK_TYPES, COPIED_AS_ITSELF, COPY_KEEPS, TEXT_TYPES, askClipboard, clipboardOf, sizeValue, unitClipboard } from "../../../components/registry.mjs";
3
+ import { ALIGN_TOGGLES, TEXT_BLOCKS } from "../../../components/align.mjs";
3
4
  import { BLOCK_COLORS } from "../../../components/colors.mjs";
4
5
  import { containerType, typeOf } from "../../convert.mjs";
5
6
  import { pageOfType, pageOfUnit } from "../../page-objects.mjs";
@@ -72,8 +73,11 @@ export function copied(doc, block) {
72
73
  return (typeof block.data?.html === "string" ? copy.outerHTML === block.html : copy.textContent === block.text) ? unit : null;
73
74
  }
74
75
 
75
- /** A block's colors (their classes, space-separated), or null. */
76
- export const colorOf = (node) => BLOCK_COLORS.filter((name) => node.classList.contains(name)).join(" ") || null;
76
+ /** The classes a block's copy carries as its `color`: its colors, and a paragraph's or a heading's alignment and indent. */
77
+ export const BLOCK_LOOKS = [...BLOCK_COLORS, ...ALIGN_TOGGLES];
78
+
79
+ /** A block's colors, and a text block's alignment and indent (their classes, space-separated), or null. */
80
+ export const colorOf = (node) => (node.matches?.(TEXT_BLOCKS) ? BLOCK_LOOKS : BLOCK_COLORS).filter((name) => node.classList.contains(name)).join(" ") || null;
77
81
 
78
82
  /** The type a text block is copied as: its own, the type of the text blocks of what wraps it (a quote's paragraph), or null (code, whose text is no text block's). */
79
83
  export function copiedType(host) {
@@ -1241,8 +1241,8 @@ export function createCommits({ root, map, baselines, units, boxes, getLayout, s
1241
1241
  else if (element) proposals.set(identityOf(element), id);
1242
1242
  }
1243
1243
  for (const [key, hash] of Object.entries(receipt.hashes ?? {})) if (map.units[Number(key)]) map.units[Number(key)].hash = hash;
1244
- // The keys of tables the file gave the blocks the commit made and the tables it keyed (a view's
1245
- // 视图 ›: the key its frame took, an attribute of the unit), other than the page chose
1244
+ // The keys of tables the file gave the blocks the commit made and the tables it keyed (a view
1245
+ // made from a menu: the key its frame took, an attribute of the unit), other than the page chose
1246
1246
  // (source/chart-keys.mjs: one the file had meanwhile): theirs on the page too, so that each card and
1247
1247
  // view reads the table the file links it to ({ old: new | null }, null: off a table); `rekeyed` says
1248
1248
  // which it changed ([element, name, old, new | null]), for the undo steps that recorded them (history.mjs).
@@ -10,6 +10,7 @@ import { gridOf, tableChange } from "../components/table/grid.mjs";
10
10
  import { HELD_TAGS, heldListType, listType } from "../components/list/index.mjs";
11
11
  import { isFlowchart, isStep } from "../components/flowchart/index.mjs";
12
12
  import { markEmpty } from "../components/placeholder.mjs";
13
+ import { carry } from "../components/align.mjs";
13
14
  import { unread } from "./tex.mjs";
14
15
  import { MENTION, MENTION_ICON, MENTION_PAGE } from "../../shared/components/mention.mjs";
15
16
  import { FLOW_BLOCKS } from "../../shared/components/index.mjs";
@@ -577,7 +578,8 @@ export function newTail(container, type) {
577
578
  }
578
579
 
579
580
  // New blocks split off `from` are paragraphs, or list items in a list.
580
- const newBlock = (doc, tag, from) => newHost(doc, tag === "li" ? "item" : "paragraph", from);
581
+ // A paragraph split off a paragraph or a heading keeps its alignment and indent (components/align.mjs carry).
582
+ const newBlock = (doc, tag, from) => (tag === "li" ? newHost(doc, "item", from) : carry(from, newHost(doc, "paragraph", from)));
581
583
 
582
584
  /** A new, empty paragraph, as a split makes one outside a list (the page's title's Enter: typing/ enterBody). */
583
585
  export const newParagraphHost = (doc) => newBlock(doc, "p", null);
@@ -10,10 +10,12 @@ import { connectWorkbench } from "./session.mjs";
10
10
  // slug is "@<slug>", the page's address in the workbench (#@<slug>), which no document's slug can be.
11
11
  // It answers the session's own commands (theme, keys, scroll-top: src/editor/page/session.mjs),
12
12
  // prepare-close (once the board's ops sent are answered: each is written at once, nothing else waits),
13
- // add-card (the top bar's 添加自定义块: the library of the page's first board, under the button's place that
14
- // the workbench sends) and, on the home page, restore-defaults (恢复默认卡片, the sidebar's: the board's, one step of its
15
- // undo; its answer { ok, added, skipped } the workbench says) and undo-restore ({ cards }: that step
16
- // undone while it is the board's last, the workbench's 撤销),
13
+ // add-card where it has a board (the top bar's 添加自定义块: the library of the page's first board, under the
14
+ // button's place that the workbench sends; a page with none, a blank one or one an Agent wrote with no
15
+ // board, offers no 添加自定义块) and, on a page with the default cards (its page map's `defaults`: its
16
+ // page.json's defaultCards, the default home page's), restore-defaults (恢复默认卡片, its menu's: the board's,
17
+ // one step of its undo; its answer { ok, added, skipped } the workbench says) and undo-restore ({ cards }:
18
+ // that step undone while it is the board's last, the workbench's 撤销),
17
19
  // and sends ready, reload (its live script heard that page.html or page.json changed, or a block it
18
20
  // holds: the workbench loads it again in a hidden frame and swaps it in once drawn), open (a link to a
19
21
  // document or another page, or a block's context.workspace.open: doc-open-request) and key. Opened on its own (not in a frame of the workbench), it has no
@@ -24,6 +26,13 @@ const IDLE = { editing: false, pending: false, saving: false, offline: false, co
24
26
  // Nothing stands over a custom page as a modal.
25
27
  const NO_MODALS = { open: () => [], listen() {}, closeTop: () => false };
26
28
 
29
+ // The page map (routes.mjs: its slug, its token, the version it was served at, its blocks): the boards edit.
30
+ let map = null;
31
+ try {
32
+ map = JSON.parse(document.querySelector("script[data-ge-page]")?.textContent ?? "null");
33
+ } catch {}
34
+ const hasBoard = Boolean(document.querySelector(".gallery-board"));
35
+
27
36
  let board = null;
28
37
  const session = connectWorkbench({
29
38
  slug: `@${slug}`,
@@ -35,8 +44,8 @@ const session = connectWorkbench({
35
44
  },
36
45
  // 添加自定义块 of the workbench's top bar: the library opens in the page, at `anchor` (the button's place in
37
46
  // this frame's coordinates; none: in the middle of the window), the first board's.
38
- "add-card": async ({ anchor } = {}) => (board ? board.addCard({ anchor }) : { ok: false, reason: "board" }),
39
- ...(slug === "home" ? {
47
+ ...(hasBoard ? { "add-card": async ({ anchor } = {}) => (board ? board.addCard({ anchor }) : { ok: false, reason: "board" }) } : {}),
48
+ ...(map?.defaults ? {
40
49
  "restore-defaults": async () => (board ? board.restoreDefaults() : { ok: false, reason: "board" }),
41
50
  "undo-restore": async ({ cards }) => (board ? board.undoRestore(cards) : { ok: false, reason: "board" }),
42
51
  } : {}),
@@ -44,11 +53,6 @@ const session = connectWorkbench({
44
53
  modals: NO_MODALS,
45
54
  });
46
55
 
47
- // The page map (routes.mjs: its slug, its token, the version it was served at, its blocks): the boards edit.
48
- let map = null;
49
- try {
50
- map = JSON.parse(document.querySelector("script[data-ge-page]")?.textContent ?? "null");
51
- } catch {}
52
56
  board = map?.token ? startBoard({ map, reload: () => (session ? session.reload() : location.reload()), hosted: Boolean(session) }) : null;
53
57
  // The live script (routes.mjs) shows the page again through the workbench, which swaps a new page in
54
58
  // once drawn: no reload seen; once the board's own writes, a drag, a form or a field typed in are done.
@@ -15,6 +15,7 @@ import { createCommits, kindOf } from "./commit.mjs";
15
15
  import { createConflicts, packageChanged, unfit } from "./conflicts.mjs";
16
16
  import { checkLeft, createAutosave, keepWith, lostKey, pendingKey, readLost, recover, reloadView, setReloader, takeView, viewNow } from "./autosave.mjs";
17
17
  import { SOLO, connectWorkbench } from "./session.mjs";
18
+ import { OUTLINE_OPEN_KEY, onOutlineOpen, outlineOpen, setOutlineOpen } from "../../shared/preferences.mjs";
18
19
  import { lookOfElement } from "../../shared/document-look.mjs";
19
20
  import { belowTargets, convertBlock, convertGroup, groupParents, groupTargets, noTextToCarry, targetsOf, touchedBy, turnInto, turnParents, turnUnit, typeOf } from "./convert.mjs";
20
21
  import { joinCode, rangeAt, rangeOffsets } from "./marks.mjs";
@@ -24,6 +25,7 @@ import { serveFiles } from "./served.mjs";
24
25
  import { createFormatting } from "./format-bar/index.mjs";
25
26
  import { connectHints, hideHint, readOnlyReason, scheduleHint, trackPointer } from "./hints/index.mjs";
26
27
  import { createInsert } from "./insert/index.mjs";
28
+ import { createAfter } from "./after/index.mjs";
27
29
  import { connectLinks, dismissLink, drawPasted, followLink, leadsToPage, linkBoxNode, linkHolds, linkNodes, linkOf, linkPending, openLink, pageLinkOf } from "./links/index.mjs";
28
30
  import { bookmarkItems, connectViews, linkTitle, offerViews } from "./links/views.mjs";
29
31
  import { connectChipFills } from "./chip-fills.mjs";
@@ -36,6 +38,7 @@ import { createResize } from "./resize/index.mjs";
36
38
  import { connectPages, fieldOpen, keptByComponent, menuRow, modalOps, pageAt, pageIcon, pageObjects, pageOf, pageOfHost, pageOfType, pageOfUnit, panelOpen, typedAsIs } from "./page-objects.mjs";
37
39
  import { preloading } from "./type-grid.mjs";
38
40
  import { createColumnGaps } from "./columns/index.mjs";
41
+ import { viewFrames } from "./table/binding.mjs";
39
42
  import { createTableEditing } from "./table/index.mjs";
40
43
  import { createAtMenu } from "./at-menu/index.mjs";
41
44
  import { createSlashMenu } from "./slash-menu/index.mjs";
@@ -72,6 +75,7 @@ import { language, t } from "../../shared/i18n/index.mjs";
72
75
  //
73
76
  // typing/ Enter, Backspace/Delete at block edges, auto spacing, placeholders
74
77
  // insert/ new blocks: below a block (its menu), a click below the last block, a paragraph before or after
78
+ // after/ the caret after a block of no text (a click right of it): Backspace deletes it, Enter or a key a paragraph after it
75
79
  // format-bar/ the bar over selected text and its keys (marks.mjs does the marks)
76
80
  // links/ the link box (Ctrl+K), following links; hints/: why something is read-only
77
81
  // formula/ the formula box: selected text made an inline formula (Ctrl+Shift+E)
@@ -261,7 +265,9 @@ function showLanded(node) {
261
265
  modalOps().show(node);
262
266
  }
263
267
 
264
- const insert = createInsert({ struct, blocks: () => blocks });
268
+ // The caret after a block of no text, where a click right of one puts it (insert/ clickBlank).
269
+ const after = createAfter({ struct, blocks: () => blocks, keepText: (node) => blocks.keepText(node), removeBlocks: (units) => blocks.remove(units), say, undo: () => undo(), redo: () => redo() });
270
+ const insert = createInsert({ struct, blocks: () => blocks, after });
265
271
  const { newParagraph } = insert;
266
272
 
267
273
  // What a component does on the page beyond what every block does is its own page module
@@ -326,6 +332,8 @@ const typing = createTyping({
326
332
  adding: () => slash?.adding ?? null,
327
333
  leave: createLeaving({ struct, touchedBy, convertHost, typeOf, targetsOf }),
328
334
  showHidden: (node) => blocks?.folds.showAround(node), // a folded heading's section opened before a join takes in its words (fold/)
335
+ look: lookStep, // a block's alignment and indent taken off by Backspace (align.mjs)
336
+ afterAbove: (host) => after.back(host), // Backspace right after a block of no text: the caret after it (after/)
329
337
  });
330
338
  // Selecting text across blocks: its listeners go before the editor's own keys and clipboard.
331
339
  const crossText = createTextSelection({
@@ -673,7 +681,7 @@ function convertHost(host, type, typed = null, after = null) {
673
681
  if (!focus && !typed) return null;
674
682
  const more = focus && after ? after(focus) : [];
675
683
  return { touched: [focus ?? host], focus: focus ?? host, created: [...created, ...more] };
676
- });
684
+ }, { attributes: viewFrames(type) });
677
685
  if (result) afterConvert(result.focus, type, result.focus !== host ? t("已转换为{0}", menuRow(type).label) : null);
678
686
  }
679
687
 
@@ -703,10 +711,9 @@ function afterConvert(focus, type, said) {
703
711
  * heading) and the new block turns into the type; below any other block, an empty paragraph of its
704
712
  * box does (the first box out that takes one). One undo step.
705
713
  */
706
- // `also` (a table's 视图 ›: page/table/views.mjs): `attributes` ([element, names]) the step records too, and
707
- // `done(made)` run in it on the new block (the element where the empty paragraph was), so that what binds
708
- // the block to the one above it is the same step.
709
- function insertBelow(target, type, typed = null, also = null) {
714
+ // A view of a table (a custom block that reads tables) is bound to the table above it as it is made
715
+ // (installed/page.mjs create), the tables' keys recorded in the same step (viewFrames).
716
+ function insertBelow(target, type, typed = null) {
710
717
  const splits = isHost(target) && can(target, "split");
711
718
  let after = target;
712
719
  while (!splits && after && !accepts(after.parentElement?.getAttribute("data-ge-box-kind"), "paragraph")) after = after.parentElement?.closest(OUTER);
@@ -724,12 +731,10 @@ function insertBelow(target, type, typed = null, also = null) {
724
731
  after.after(fresh);
725
732
  }
726
733
  if (!fresh) return null;
727
- const prior = fresh.previousSibling; // what the new block stands right after, made where the paragraph was
728
734
  const turned = type === "paragraph" && fresh.localName === "p" ? { focus: null, created: [] } : convertBlock(fresh, type, { fresh: true });
729
- also?.done?.(fresh.isConnected ? fresh : prior?.nextElementSibling ?? null);
730
735
  const focus = turned.focus ?? fresh;
731
736
  return { touched: splits ? [target, focus] : [focus], focus, created: turned.created };
732
- }, { attributes: also?.attributes ?? [] });
737
+ }, { attributes: viewFrames(type) });
733
738
  if (result) afterConvert(result.focus, type, t("已插入{0}", menuRow(type).label));
734
739
  }
735
740
 
@@ -782,7 +787,7 @@ function convertUnit(unit, type, { loaded = false } = {}) {
782
787
  const turned = turnUnit(unit, type);
783
788
  emptied = Boolean(turned.emptied);
784
789
  return turned.focus ? { touched: [turned.focus], focus: turned.focus, created: turned.created, select: emptied ? null : unit } : null;
785
- });
790
+ }, { attributes: viewFrames(type) });
786
791
  if (!result) return;
787
792
  if (!made || !onCreated(type, result.focus)) {
788
793
  if (emptied && isHost(result.focus)) caretAt(result.focus, "start");
@@ -823,6 +828,7 @@ function convertAll(group, type, { select = true } = {}) {
823
828
  function onKeydown(event) {
824
829
  compositionOver(event);
825
830
  if (!editing) return;
831
+ if (after.key(event)) return; // the caret after a block: its keys are its own (after/)
826
832
  // A 批注's card is a field of its own: its keys are its own, but for Ctrl+S, which saves it and the report.
827
833
  if (annotate?.holds(event.target)) {
828
834
  const mod = event.ctrlKey || event.metaKey;
@@ -928,7 +934,8 @@ function onKeydown(event) {
928
934
  moveHostBlock(host, event.key === "ArrowUp" ? -1 : 1);
929
935
  } else if (event.key.startsWith("Arrow") && !mod && !event.altKey && !event.shiftKey && !renamed) {
930
936
  // ←/→ stop on both sides of inline code's edges (typing/code-edges.mjs); a tab's caret stays in its name.
931
- if ((textFilters(host) && codeArrow(host, event.key)) || arrow(host, event.key)) event.preventDefault();
937
+ // ← or ↑ at the start of the text right after a block of no text: the caret after that block (after/).
938
+ if ((textFilters(host) && codeArrow(host, event.key)) || after.up(host, event.key) || arrow(host, event.key)) event.preventDefault();
932
939
  }
933
940
  }
934
941
 
@@ -1243,6 +1250,15 @@ const COMMANDS = {
1243
1250
  if (!editing || !annotate) return { ok: false, reason: "editing" };
1244
1251
  return annotate.action(message);
1245
1252
  },
1253
+ // The outline (目录) switched by the workbench's 更多: a draft of another workspace is shown from that workspace's own origin,
1254
+ // whose storage the workbench cannot write (the switch is kept per origin: shared/preferences.mjs outlineOpen), so it asks and
1255
+ // this page keeps it, shown as another tab's change is (the storage event the outline listens for). Answers the switch as kept.
1256
+ async outline({ open }) {
1257
+ if (typeof open !== "boolean") return { ok: false, reason: "open" };
1258
+ setOutlineOpen(MAP.slug, open);
1259
+ dispatchEvent(new StorageEvent("storage", { key: OUTLINE_OPEN_KEY }));
1260
+ return { ok: true, outline: outlineOpen(MAP.slug) };
1261
+ },
1246
1262
  // Rename the report: its title, selected for typing (saving it updates <title> and report.json).
1247
1263
  async "edit-title"() {
1248
1264
  const title = document.querySelector('[data-ge-kind="title"]');
@@ -1473,8 +1489,9 @@ function connect() {
1473
1489
  // The look the page shows (字体与布局: its <html>'s, src/shared/document-look.mjs), which the workbench's
1474
1490
  // 更多 marks as chosen; told again when it changes (the kit's ui.js, doc-look-change).
1475
1491
  // `title`: null for a page with no title at all (the workbench names it by its doc.json); "" an untitled one (未命名文档).
1476
- workbench = connectWorkbench({ slug: MAP.slug, snapshot: () => ({ title: titleNode() ? currentTitle() : null, icon: pageIcon(), look: lookOfElement(document.documentElement), state: sessionState(), annotations: annotate?.count() }), commands: COMMANDS, modals: modalOps() });
1492
+ workbench = connectWorkbench({ slug: MAP.slug, snapshot: () => ({ title: titleNode() ? currentTitle() : null, icon: pageIcon(), look: lookOfElement(document.documentElement), state: sessionState(), annotations: annotate?.count(), outline: outlineOpen(MAP.slug) }), commands: COMMANDS, modals: modalOps() });
1477
1493
  addEventListener("doc-look-change", () => workbench?.update());
1494
+ onOutlineOpen(() => workbench?.update()); // the switch changed in another tab of this origin: the workbench's 目录 follows it (a draft's)
1478
1495
  // A block's context.workspace.open (the kit's runtime/workspace.js): a document, or a block of one, goes
1479
1496
  // where a link to it goes (goTo: in the workbench, its address; on its own, the page once saved); a custom
1480
1497
  // page, the workbench's #@<slug>, or /pages/<slug> once saved.
@@ -1655,8 +1672,8 @@ function boot() {
1655
1672
  gaps = createColumnGaps({ active, struct, look: lookStep, say, settle });
1656
1673
  for (const page of pageObjects()) page.install?.(); // the round "+" at a flowchart node's right, renaming Sheet tabs
1657
1674
  tables = createTableEditing({
1658
- active, struct, look: lookStep, selectBlock: (unit) => blocks.select(unit), resizeTable: (event, unit, axis) => resize.startTable(event, unit, axis), say, cellsOf: (data) => clipboard.cellsOf(data), upload: uploadTo, typedKey,
1659
- recordStep, insertBelow: (unit, type, also) => insertBelow(unit, type, null, also),
1675
+ active, struct, look: lookStep, selectBlock: (unit) => blocks.select(unit), resizeTable: (event, unit, axis) => resize.startTable(event, unit, axis), say, settle, cellsOf: (data) => clipboard.cellsOf(data), upload: uploadTo, typedKey,
1676
+ recordStep,
1660
1677
  });
1661
1678
  selectAll = createSelectAll({ blocks, say, cells: { table: () => tables.selectedTable, clear: () => tables.clear() } });
1662
1679
  createFrame(() => editing);