@heycys/gallery 0.1.0 → 0.1.2

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 (465) hide show
  1. package/THIRD-PARTY-NOTICES.md +51 -1
  2. package/browser/editor/components/callout/index.mjs +40 -15
  3. package/browser/editor/components/columns/page.mjs +45 -32
  4. package/browser/editor/components/details/index.mjs +2 -1
  5. package/browser/editor/components/dialog/index.mjs +2 -1
  6. package/browser/editor/components/dialog/page.mjs +0 -18
  7. package/browser/editor/components/divider/index.mjs +1 -1
  8. package/browser/editor/components/embed/index.mjs +2 -2
  9. package/browser/editor/components/figure/page.mjs +10 -1
  10. package/browser/editor/components/file/page.mjs +2 -2
  11. package/browser/editor/components/flowchart/add.mjs +7 -6
  12. package/browser/editor/components/flowchart/page.mjs +1 -1
  13. package/browser/editor/components/heading/index.mjs +2 -0
  14. package/browser/editor/components/heading/page.mjs +6 -0
  15. package/browser/editor/components/highlight/index.mjs +4 -20
  16. package/browser/editor/components/icons.mjs +13 -2
  17. package/browser/editor/components/image/crop.mjs +6 -9
  18. package/browser/editor/components/image/page.mjs +2 -2
  19. package/browser/editor/components/installed/index.mjs +82 -29
  20. package/browser/editor/components/installed/page.mjs +146 -34
  21. package/browser/editor/components/installed/served.mjs +6 -5
  22. package/browser/editor/components/instances.mjs +18 -0
  23. package/browser/editor/components/kit.mjs +3 -0
  24. package/browser/editor/components/list/page.mjs +3 -6
  25. package/browser/editor/components/media/page.mjs +44 -14
  26. package/browser/editor/components/pages.mjs +2 -2
  27. package/browser/editor/components/registry.mjs +68 -33
  28. package/browser/editor/components/section/index.mjs +2 -1
  29. package/browser/editor/components/set-apart.mjs +24 -0
  30. package/browser/editor/components/table/index.mjs +64 -5
  31. package/browser/editor/components/table/page.mjs +30 -19
  32. package/browser/editor/page/annotate/anchors.mjs +4 -3
  33. package/browser/editor/page/annotate/card.mjs +3 -6
  34. package/browser/editor/page/annotate/index.mjs +61 -34
  35. package/browser/editor/page/autosave.mjs +357 -38
  36. package/browser/editor/page/beside.mjs +5 -5
  37. package/browser/editor/page/block-menu/colors.mjs +3 -1
  38. package/browser/editor/page/block-menu/index.mjs +8 -6
  39. package/browser/editor/page/blocks.mjs +16 -7
  40. package/browser/editor/page/board/client.mjs +57 -0
  41. package/browser/editor/page/board/hint.mjs +145 -0
  42. package/browser/editor/page/board/history.mjs +119 -0
  43. package/browser/editor/page/board/index.mjs +970 -0
  44. package/browser/editor/page/board/settings.mjs +209 -0
  45. package/browser/editor/page/caret.mjs +5 -2
  46. package/browser/editor/page/changes/bar.mjs +94 -0
  47. package/browser/editor/page/changes/ghost.mjs +206 -0
  48. package/browser/editor/page/changes/gone-words.mjs +94 -0
  49. package/browser/editor/page/changes/index.mjs +447 -0
  50. package/browser/editor/page/changes/words.mjs +27 -0
  51. package/browser/editor/page/clipboard/import/colors.mjs +3 -3
  52. package/browser/editor/page/clipboard/import/html.mjs +29 -6
  53. package/browser/editor/page/clipboard/import/inline.mjs +32 -0
  54. package/browser/editor/page/clipboard/import/markdown.mjs +58 -13
  55. package/browser/editor/page/clipboard/import/read.mjs +6 -1
  56. package/browser/editor/page/clipboard/import/to-blocks.mjs +44 -12
  57. package/browser/editor/page/clipboard/import/yuque.mjs +622 -0
  58. package/browser/editor/page/clipboard/index.mjs +156 -26
  59. package/browser/editor/page/clipboard/own/blocks.mjs +25 -16
  60. package/browser/editor/page/clipboard/own/chart-keys.mjs +41 -28
  61. package/browser/editor/page/clipboard/own/describe.mjs +16 -7
  62. package/browser/editor/page/clipboard/own/export.mjs +6 -6
  63. package/browser/editor/page/clipboard/own/selection.mjs +3 -3
  64. package/browser/editor/page/clipboard/own/writers.mjs +0 -11
  65. package/browser/editor/page/columns/index.mjs +48 -46
  66. package/browser/editor/page/commit.mjs +98 -25
  67. package/browser/editor/page/conflicts.mjs +13 -33
  68. package/browser/editor/page/convert.mjs +8 -7
  69. package/browser/editor/page/core.mjs +81 -27
  70. package/browser/editor/page/custom-page.mjs +106 -0
  71. package/browser/editor/page/drag/index.mjs +40 -24
  72. package/browser/editor/page/drag/preview.mjs +9 -4
  73. package/browser/editor/page/editor.mjs +120 -28
  74. package/browser/editor/page/emoji-picker/emoji-tab.mjs +22 -13
  75. package/browser/editor/page/emoji-picker/grid.mjs +7 -5
  76. package/browser/editor/page/emoji-picker/icon-tab.mjs +4 -4
  77. package/browser/editor/page/emoji-picker/icons.mjs +0 -1
  78. package/browser/editor/page/emoji-picker/index.mjs +11 -9
  79. package/browser/editor/page/emoji-picker/styles.mjs +156 -2
  80. package/browser/editor/page/emoji-picker/support.mjs +6 -4
  81. package/browser/editor/page/emoji-picker/upload.mjs +14 -13
  82. package/browser/editor/page/fills.mjs +5 -3
  83. package/browser/editor/page/fold/index.mjs +348 -0
  84. package/browser/editor/page/fold/rule.mjs +125 -0
  85. package/browser/editor/page/folded.mjs +23 -0
  86. package/browser/editor/page/format-bar/bar.mjs +2 -1
  87. package/browser/editor/page/format-bar/index.mjs +1 -1
  88. package/browser/editor/page/geometry.mjs +8 -6
  89. package/browser/editor/page/handle/index.mjs +22 -14
  90. package/browser/editor/page/hints/index.mjs +1 -1
  91. package/browser/editor/page/history.mjs +24 -4
  92. package/browser/editor/page/insert/index.mjs +30 -17
  93. package/browser/editor/page/links/index.mjs +5 -3
  94. package/browser/editor/page/links/pages.mjs +27 -9
  95. package/browser/editor/page/long-runs.mjs +75 -0
  96. package/browser/editor/page/look.mjs +69 -6
  97. package/browser/editor/page/margin.mjs +63 -27
  98. package/browser/editor/page/media-menu/index.mjs +6 -7
  99. package/browser/editor/page/menu.mjs +86 -31
  100. package/browser/editor/page/merge.mjs +24 -0
  101. package/browser/editor/page/notices.mjs +3 -3
  102. package/browser/editor/page/offered.mjs +1 -1
  103. package/browser/editor/page/outline/folds.mjs +11 -10
  104. package/browser/editor/page/outline/index.mjs +131 -45
  105. package/browser/editor/page/outline/list.mjs +23 -11
  106. package/browser/editor/page/outline/read.mjs +1 -1
  107. package/browser/editor/page/outline/strip.mjs +7 -1
  108. package/browser/editor/page/page-objects.mjs +13 -2
  109. package/browser/editor/page/panel.mjs +9 -13
  110. package/browser/editor/page/present-links.mjs +11 -2
  111. package/browser/editor/page/resize/index.mjs +42 -29
  112. package/browser/editor/page/selection/delete.mjs +8 -6
  113. package/browser/editor/page/selection/index.mjs +10 -3
  114. package/browser/editor/page/served.mjs +14 -0
  115. package/browser/editor/page/session.mjs +101 -6
  116. package/browser/editor/page/slash-menu/index.mjs +3 -3
  117. package/browser/editor/page/table/cell-bar.mjs +4 -1
  118. package/browser/editor/page/table/cells.mjs +103 -47
  119. package/browser/editor/page/table/icons.mjs +3 -1
  120. package/browser/editor/page/table/index.mjs +40 -16
  121. package/browser/editor/page/table/pictures.mjs +299 -0
  122. package/browser/editor/page/table/views.mjs +150 -0
  123. package/browser/editor/page/table/widths.mjs +9 -4
  124. package/browser/editor/page/text-select/index.mjs +43 -14
  125. package/browser/editor/page/todo-writes.mjs +75 -0
  126. package/browser/editor/page/tooltip.mjs +1 -1
  127. package/browser/editor/page/type-grid.mjs +4 -3
  128. package/browser/editor/page/typing/code-edges.mjs +63 -17
  129. package/browser/editor/page/typing/index.mjs +65 -9
  130. package/browser/editor/page/typing/leave.mjs +1 -1
  131. package/browser/editor/page/ui.mjs +13 -0
  132. package/browser/shared/annotations.mjs +8 -10
  133. package/browser/shared/block-packs.mjs +404 -0
  134. package/browser/shared/board-places.mjs +224 -0
  135. package/browser/shared/card-size.mjs +59 -0
  136. package/browser/shared/code-folds.mjs +5 -1
  137. package/browser/shared/colors.mjs +17 -14
  138. package/browser/shared/component-catalog.mjs +345 -54
  139. package/browser/shared/component-source.mjs +37 -0
  140. package/browser/shared/components/callout.mjs +4 -2
  141. package/browser/shared/components/index.mjs +72 -9
  142. package/browser/shared/components/installed.mjs +110 -8
  143. package/browser/shared/components/page.mjs +22 -3
  144. package/browser/shared/components/state.mjs +5 -1
  145. package/browser/shared/components/table.mjs +1 -1
  146. package/browser/shared/components/text.mjs +2 -2
  147. package/browser/shared/document-look.mjs +183 -0
  148. package/browser/shared/drafts.mjs +432 -0
  149. package/browser/shared/emoji/data/LICENSE-lucide.txt +43 -0
  150. package/browser/shared/emoji/data/README.md +4 -2
  151. package/browser/shared/emoji/data/categories.json +1 -1
  152. package/browser/shared/emoji/data/keywords-en.json +1 -1
  153. package/browser/shared/emoji/data/keywords-zh.json +1 -1
  154. package/browser/shared/emoji/data/names.json +1 -1
  155. package/browser/shared/emoji/data/positions.json +1 -1
  156. package/browser/shared/emoji/data/twemoji-index.json +1 -1
  157. package/browser/shared/emoji/data/twemoji-svg.bin +0 -0
  158. package/browser/shared/emoji/data.mjs +10 -12
  159. package/browser/shared/emoji/emoji.mjs +8 -7
  160. package/browser/shared/emoji/icon-value.mjs +4 -3
  161. package/browser/shared/extension-sidebar.mjs +126 -0
  162. package/browser/shared/extensions.mjs +79 -0
  163. package/browser/shared/file-table.mjs +101 -0
  164. package/browser/shared/html-tree.mjs +11 -5
  165. package/browser/shared/i18n/en.mjs +374 -35
  166. package/browser/shared/json-layout.mjs +47 -0
  167. package/browser/shared/long-runs.mjs +39 -0
  168. package/browser/shared/net-cache.mjs +133 -0
  169. package/browser/shared/net-keys.mjs +32 -0
  170. package/browser/shared/net-policy.mjs +177 -0
  171. package/browser/shared/new-names.mjs +5 -2
  172. package/browser/shared/outline-shape.mjs +128 -0
  173. package/browser/shared/outline.mjs +458 -0
  174. package/browser/shared/pack-manifest.mjs +77 -0
  175. package/browser/shared/page-address.mjs +6 -3
  176. package/browser/shared/page-cards.mjs +308 -0
  177. package/browser/shared/page-links.mjs +69 -6
  178. package/browser/shared/pages.mjs +388 -0
  179. package/browser/shared/paths.mjs +6 -0
  180. package/browser/shared/preferences.mjs +10 -4
  181. package/browser/shared/preview-server.mjs +3 -7
  182. package/browser/shared/session.mjs +13 -5
  183. package/browser/shared/shipped-blocks.mjs +299 -0
  184. package/browser/shared/table-chart.mjs +33 -1
  185. package/browser/shared/todos.mjs +83 -0
  186. package/browser/shared/user-directory.mjs +24 -0
  187. package/browser/shared/versions.mjs +14 -0
  188. package/browser/shared/web-links.mjs +134 -0
  189. package/browser/shared/workspace-columns.mjs +120 -0
  190. package/browser/shared/workspace-look.mjs +91 -0
  191. package/browser/shared/workspace-name.mjs +154 -0
  192. package/browser/shared/workspace-query.mjs +125 -0
  193. package/browser/shared/workspace-registry.mjs +272 -0
  194. package/browser/shared/workspace.mjs +171 -20
  195. package/browser/shared/zoom.mjs +5 -5
  196. package/dist/chunk-2NRBY6AJ.mjs +2 -0
  197. package/dist/chunk-32ZUEFZ7.mjs +2 -0
  198. package/dist/chunk-35NQ4PLQ.mjs +2 -0
  199. package/dist/chunk-3KJHLHUO.mjs +2 -0
  200. package/dist/chunk-3NJACR4W.mjs +2 -0
  201. package/dist/chunk-4AV456RQ.mjs +2 -0
  202. package/dist/chunk-4OZWXZE5.mjs +5 -0
  203. package/dist/chunk-5XYHDBJ5.mjs +2 -0
  204. package/dist/chunk-5ZJA7CXT.mjs +2 -0
  205. package/dist/chunk-6A53MZYZ.mjs +2 -0
  206. package/dist/chunk-6EXH3ORZ.mjs +166 -0
  207. package/dist/chunk-6EZ7FNIK.mjs +3 -0
  208. package/dist/{chunk-UXUK4PMC.mjs → chunk-6QBHU4DF.mjs} +1 -1
  209. package/dist/{chunk-6U2SLSDN.mjs → chunk-6VTU6KEO.mjs} +1 -1
  210. package/dist/chunk-B4P2CM2J.mjs +3 -0
  211. package/dist/chunk-BPL64HGA.mjs +4 -0
  212. package/dist/chunk-BVEFGE4B.mjs +2 -0
  213. package/dist/chunk-BZ5RAF7L.mjs +2 -0
  214. package/dist/chunk-CRJEG7MT.mjs +2 -0
  215. package/dist/{chunk-B3VTYBYR.mjs → chunk-D4CKRD3V.mjs} +91 -91
  216. package/dist/chunk-D4EURAX4.mjs +4 -0
  217. package/dist/chunk-DQCE7TJY.mjs +5 -0
  218. package/dist/chunk-DR73Y2UJ.mjs +3 -0
  219. package/dist/{chunk-TMYZB6AV.mjs → chunk-EKNHM3P4.mjs} +1 -1
  220. package/dist/{chunk-DB4WKGYF.mjs → chunk-ERLAIBOA.mjs} +2 -2
  221. package/dist/chunk-EURLTOTZ.mjs +4 -0
  222. package/dist/chunk-FJYN7RTH.mjs +4 -0
  223. package/dist/chunk-FWNRPMCJ.mjs +12 -0
  224. package/dist/chunk-FWW4CSAZ.mjs +2 -0
  225. package/dist/{chunk-2B5E4CDJ.mjs → chunk-GPIWQ4X4.mjs} +1 -1
  226. package/dist/chunk-GY3FAUVM.mjs +2 -0
  227. package/dist/chunk-HLYV7RIH.mjs +2 -0
  228. package/dist/chunk-HMYTM3GT.mjs +15 -0
  229. package/dist/chunk-IA4PSIMD.mjs +2 -0
  230. package/dist/chunk-JEUK3ZO7.mjs +2 -0
  231. package/dist/chunk-JVHHHGEA.mjs +3 -0
  232. package/dist/chunk-KTKHRC6H.mjs +2 -0
  233. package/dist/chunk-L7UP52JO.mjs +2 -0
  234. package/dist/chunk-MHW7ZKOU.mjs +2 -0
  235. package/dist/chunk-N76HWBA3.mjs +10 -0
  236. package/dist/chunk-N7AZZLGT.mjs +548 -0
  237. package/dist/chunk-NAMN3RAF.mjs +2 -0
  238. package/dist/{chunk-YXAUQPVK.mjs → chunk-NFMCP2HI.mjs} +3 -3
  239. package/dist/chunk-NG375ILQ.mjs +2 -0
  240. package/dist/chunk-NVRNLK25.mjs +6 -0
  241. package/dist/chunk-NWFBE2YA.mjs +2 -0
  242. package/dist/chunk-NWR2LT5B.mjs +2 -0
  243. package/dist/chunk-OJKMINIU.mjs +20 -0
  244. package/dist/chunk-OUUP3WKT.mjs +2 -0
  245. package/dist/chunk-OW5NWPOJ.mjs +10 -0
  246. package/dist/chunk-PAREWQGB.mjs +4 -0
  247. package/dist/chunk-POQSE4C2.mjs +2 -0
  248. package/dist/chunk-PUOQ65NC.mjs +2 -0
  249. package/dist/{chunk-Z52HTUW7.mjs → chunk-PVER7LSC.mjs} +2 -2
  250. package/dist/chunk-PZDLJJTJ.mjs +3 -0
  251. package/dist/chunk-Q47PLKIJ.mjs +15 -0
  252. package/dist/chunk-Q4UEPUWF.mjs +2 -0
  253. package/dist/chunk-QKXMPUXC.mjs +2 -0
  254. package/dist/chunk-QOUEFUCH.mjs +16 -0
  255. package/dist/chunk-RFDZXFJF.mjs +13 -0
  256. package/dist/chunk-RKPWLGZ3.mjs +4 -0
  257. package/dist/chunk-RMECZA2K.mjs +2 -0
  258. package/dist/{chunk-EUX7IC5J.mjs → chunk-SQ6Y2ZMA.mjs} +2 -2
  259. package/dist/chunk-SX4LJYT6.mjs +8 -0
  260. package/dist/chunk-SXHBYZST.mjs +16 -0
  261. package/dist/chunk-TANZRINB.mjs +2 -0
  262. package/dist/chunk-TEZAWDSQ.mjs +2 -0
  263. package/dist/chunk-UBBRTJ2R.mjs +24 -0
  264. package/dist/chunk-UFNYFFKO.mjs +20 -0
  265. package/dist/chunk-UGWYKHBL.mjs +170 -0
  266. package/dist/chunk-UKSHDZZ6.mjs +2 -0
  267. package/dist/chunk-UMHUSOPJ.mjs +2 -0
  268. package/dist/chunk-UNOYVIYR.mjs +2 -0
  269. package/dist/chunk-V6RIYQZZ.mjs +4 -0
  270. package/dist/chunk-VJPFVNNW.mjs +15 -0
  271. package/dist/chunk-VS3ZMVGX.mjs +5 -0
  272. package/dist/chunk-VTKNEYT3.mjs +6 -0
  273. package/dist/chunk-VXACTLO3.mjs +3 -0
  274. package/dist/chunk-W3BGBJQW.mjs +2 -0
  275. package/dist/chunk-YI43RG4P.mjs +2 -0
  276. package/dist/chunk-YQGT4AB2.mjs +6 -0
  277. package/dist/chunk-ZB4H7ZN4.mjs +2 -0
  278. package/dist/{chunk-ACOPDCNB.mjs → chunk-ZHEHPMBK.mjs} +1 -1
  279. package/dist/chunk-ZTHICSSF.mjs +2 -0
  280. package/dist/chunk-ZUNVAXLH.mjs +2 -0
  281. package/dist/chunk-ZWPMCK7P.mjs +2 -0
  282. package/dist/cli.mjs +1 -1
  283. package/dist/server.mjs +1 -1
  284. package/dist/{chunk-EVJ3BX3M.mjs → update-fetch.mjs} +1 -1
  285. package/dist/worker.mjs +1 -1
  286. package/kit/board.css +95 -0
  287. package/kit/board.js +250 -0
  288. package/kit/charts.js +5 -71
  289. package/kit/code.js +14 -14
  290. package/kit/math.js +18 -2
  291. package/kit/report.css +500 -151
  292. package/kit/runtime.js +1720 -170
  293. package/kit/state.js +10 -1
  294. package/kit/tables.js +172 -37
  295. package/kit/ui.js +166 -27
  296. package/package.json +2 -1
  297. package/packs/gallery/card/component.json +14 -0
  298. package/packs/gallery/card/example.html +10 -0
  299. package/packs/gallery/card/preview.svg +1 -0
  300. package/packs/gallery/card/style.css +6 -0
  301. package/packs/gallery/card/template.html +6 -0
  302. package/packs/gallery/card/writing.md +14 -0
  303. package/packs/gallery/chart-card/component.json +15 -0
  304. package/packs/gallery/chart-card/example.html +14 -0
  305. package/packs/gallery/chart-card/kit.js +130 -0
  306. package/packs/gallery/chart-card/preview.svg +1 -0
  307. package/packs/gallery/chart-card/style.css +42 -0
  308. package/packs/gallery/chart-card/template.html +13 -0
  309. package/packs/gallery/chart-card/writing.md +20 -0
  310. package/packs/gallery/chart-view/component.json +20 -0
  311. package/packs/gallery/chart-view/example.html +13 -0
  312. package/packs/gallery/chart-view/kit.js +355 -0
  313. package/packs/gallery/chart-view/preview.svg +1 -0
  314. package/packs/gallery/chart-view/style.css +94 -0
  315. package/packs/gallery/chart-view/template.html +3 -0
  316. package/packs/gallery/chart-view/writing.md +22 -0
  317. package/packs/gallery/countdown/component.json +18 -0
  318. package/packs/gallery/countdown/example.html +3 -0
  319. package/packs/gallery/countdown/kit.js +156 -0
  320. package/packs/gallery/countdown/preview.svg +1 -0
  321. package/packs/gallery/countdown/style.css +130 -0
  322. package/packs/gallery/countdown/template.html +3 -0
  323. package/packs/gallery/countdown/writing.md +22 -0
  324. package/packs/gallery/habit/component.json +14 -0
  325. package/packs/gallery/habit/example.html +3 -0
  326. package/packs/gallery/habit/kit.js +295 -0
  327. package/packs/gallery/habit/preview.svg +1 -0
  328. package/packs/gallery/habit/style.css +246 -0
  329. package/packs/gallery/habit/template.html +3 -0
  330. package/packs/gallery/habit/writing.md +21 -0
  331. package/packs/gallery/heatmap/component.json +18 -0
  332. package/packs/gallery/heatmap/example.html +3 -0
  333. package/packs/gallery/heatmap/kit.js +351 -0
  334. package/packs/gallery/heatmap/preview.svg +1 -0
  335. package/packs/gallery/heatmap/style.css +201 -0
  336. package/packs/gallery/heatmap/template.html +3 -0
  337. package/packs/gallery/heatmap/writing.md +21 -0
  338. package/packs/gallery/kanban/component.json +18 -0
  339. package/packs/gallery/kanban/example.html +12 -0
  340. package/packs/gallery/kanban/kit.js +540 -0
  341. package/packs/gallery/kanban/preview.svg +1 -0
  342. package/packs/gallery/kanban/style.css +212 -0
  343. package/packs/gallery/kanban/template.html +3 -0
  344. package/packs/gallery/kanban/writing.md +20 -0
  345. package/packs/gallery/metric/component.json +22 -0
  346. package/packs/gallery/metric/example.html +15 -0
  347. package/packs/gallery/metric/kit.js +248 -0
  348. package/packs/gallery/metric/preview.svg +1 -0
  349. package/packs/gallery/metric/style.css +92 -0
  350. package/packs/gallery/metric/template.html +3 -0
  351. package/packs/gallery/metric/writing.md +23 -0
  352. package/packs/gallery/note/component.json +14 -0
  353. package/packs/gallery/note/example.html +3 -0
  354. package/packs/gallery/note/kit.js +102 -0
  355. package/packs/gallery/note/preview.svg +1 -0
  356. package/packs/gallery/note/style.css +76 -0
  357. package/packs/gallery/note/template.html +3 -0
  358. package/packs/gallery/note/writing.md +18 -0
  359. package/packs/gallery/pack.json +8 -0
  360. package/packs/gallery/recent/component.json +13 -0
  361. package/packs/gallery/recent/example.html +1 -0
  362. package/packs/gallery/recent/kit.js +238 -0
  363. package/packs/gallery/recent/preview.svg +1 -0
  364. package/packs/gallery/recent/style.css +158 -0
  365. package/packs/gallery/recent/template.html +1 -0
  366. package/packs/gallery/recent/writing.md +15 -0
  367. package/packs/gallery/static/component.json +13 -0
  368. package/packs/gallery/static/example.html +11 -0
  369. package/packs/gallery/static/preview.svg +1 -0
  370. package/packs/gallery/static/style.css +138 -0
  371. package/packs/gallery/static/template.html +1 -0
  372. package/packs/gallery/static/writing.md +18 -0
  373. package/packs/gallery/stats/component.json +13 -0
  374. package/packs/gallery/stats/example.html +1 -0
  375. package/packs/gallery/stats/kit.js +166 -0
  376. package/packs/gallery/stats/preview.svg +1 -0
  377. package/packs/gallery/stats/style.css +151 -0
  378. package/packs/gallery/stats/template.html +1 -0
  379. package/packs/gallery/stats/writing.md +11 -0
  380. package/packs/gallery/today/component.json +12 -0
  381. package/packs/gallery/today/example.html +1 -0
  382. package/packs/gallery/today/kit.js +185 -0
  383. package/packs/gallery/today/preview.svg +1 -0
  384. package/packs/gallery/today/style.css +120 -0
  385. package/packs/gallery/today/template.html +1 -0
  386. package/packs/gallery/today/writing.md +14 -0
  387. package/packs/gallery/todos/component.json +19 -0
  388. package/packs/gallery/todos/example.html +3 -0
  389. package/packs/gallery/todos/kit.js +342 -0
  390. package/packs/gallery/todos/preview.svg +1 -0
  391. package/packs/gallery/todos/style.css +267 -0
  392. package/packs/gallery/todos/template.html +3 -0
  393. package/packs/gallery/todos/writing.md +30 -0
  394. package/packs/gallery/weather/component.json +19 -0
  395. package/packs/gallery/weather/example.html +3 -0
  396. package/packs/gallery/weather/kit.js +312 -0
  397. package/packs/gallery/weather/preview.svg +1 -0
  398. package/packs/gallery/weather/style.css +258 -0
  399. package/packs/gallery/weather/template.html +3 -0
  400. package/packs/gallery/weather/writing.md +26 -0
  401. package/packs/gallery-soft/pack.json +8 -0
  402. package/release.json +13 -11
  403. package/sdk/doc-kit.d.ts +404 -7
  404. package/sdk/doc-state.d.ts +2 -0
  405. package/skill/SKILL.md +71 -26
  406. package/skill/references/block-script.md +140 -0
  407. package/skill/references/building-blocks.md +257 -0
  408. package/skill/references/example-report.html +1 -1
  409. package/skill/references/extensions.md +59 -0
  410. package/skill/references/pages-and-data.md +221 -0
  411. package/skill/references/writing-html.md +9 -7
  412. package/skill/sdk/doc-kit.d.ts +404 -7
  413. package/skill/sdk/doc-state.d.ts +2 -0
  414. package/web/assets/index-BK2e_07w.js +13 -0
  415. package/web/assets/index-CWFI83mF.css +1 -0
  416. package/web/index.html +2 -2
  417. package/browser/editor/components/callout/page.mjs +0 -13
  418. package/dist/chunk-2PBALTR3.mjs +0 -57
  419. package/dist/chunk-3LA3EMDE.mjs +0 -15
  420. package/dist/chunk-5FRMCDPY.mjs +0 -16
  421. package/dist/chunk-5LEK2CBS.mjs +0 -2
  422. package/dist/chunk-5OFN5AHC.mjs +0 -2
  423. package/dist/chunk-5SIYS5HN.mjs +0 -2
  424. package/dist/chunk-5TEK3RAD.mjs +0 -2
  425. package/dist/chunk-6CYG3Z4V.mjs +0 -2
  426. package/dist/chunk-7GHT2UCA.mjs +0 -15
  427. package/dist/chunk-7QQBR7PB.mjs +0 -2
  428. package/dist/chunk-ATCJYAR4.mjs +0 -2
  429. package/dist/chunk-C7HWOBIF.mjs +0 -2
  430. package/dist/chunk-E7VYDG2X.mjs +0 -2
  431. package/dist/chunk-EZY3WC6Z.mjs +0 -15
  432. package/dist/chunk-FQGQH4KM.mjs +0 -2
  433. package/dist/chunk-G7TOXONE.mjs +0 -6
  434. package/dist/chunk-GPF4YWWB.mjs +0 -9
  435. package/dist/chunk-GYQV7Y4J.mjs +0 -120
  436. package/dist/chunk-HMHK3EQ6.mjs +0 -2
  437. package/dist/chunk-HQQMJCQJ.mjs +0 -10
  438. package/dist/chunk-IERUOGC3.mjs +0 -6
  439. package/dist/chunk-ITNLYXXV.mjs +0 -3
  440. package/dist/chunk-L4DVONOG.mjs +0 -2
  441. package/dist/chunk-LAE5NQ4B.mjs +0 -2
  442. package/dist/chunk-LC7YNQFG.mjs +0 -2
  443. package/dist/chunk-LHTFLRB6.mjs +0 -4
  444. package/dist/chunk-NFIBI4IP.mjs +0 -26
  445. package/dist/chunk-NSKUTQ5J.mjs +0 -5
  446. package/dist/chunk-O52JMOCZ.mjs +0 -2
  447. package/dist/chunk-P2CAZPDP.mjs +0 -3
  448. package/dist/chunk-QMQUXTU4.mjs +0 -12
  449. package/dist/chunk-QVWVFC5K.mjs +0 -6
  450. package/dist/chunk-QYKCJ7FG.mjs +0 -8
  451. package/dist/chunk-QZY6Q64C.mjs +0 -2
  452. package/dist/chunk-TDQP3DKQ.mjs +0 -10
  453. package/dist/chunk-TX6JH7TR.mjs +0 -2
  454. package/dist/chunk-UNUEWH4S.mjs +0 -2
  455. package/dist/chunk-V4CPWKMZ.mjs +0 -2
  456. package/dist/chunk-VACRB2NE.mjs +0 -3
  457. package/dist/chunk-W63L7367.mjs +0 -7
  458. package/dist/chunk-W7CXPCRV.mjs +0 -6
  459. package/dist/chunk-XINNG4F2.mjs +0 -4
  460. package/dist/chunk-YL2DPWVS.mjs +0 -4
  461. package/dist/chunk-YZ5Z6H4W.mjs +0 -4
  462. package/dist/chunk-ZBIM6ARY.mjs +0 -216
  463. package/skill/references/building-components.md +0 -327
  464. package/web/assets/index-B6Ai3wsa.js +0 -13
  465. package/web/assets/index-SYPC3EZy.css +0 -1
@@ -29,11 +29,13 @@ import { unpack } from "./sync-state.mjs";
29
29
  // (settled) and the reader pauses, the page reloads to show it, where the reader was
30
30
  // (reloadView). Only when that write put texts the reader committed back as they were (an Agent
31
31
  // writing the whole file from what it read earlier) does the page ask first: it keeps the texts it
32
- // committed (commits.committed(), and those of its earlier loads in sessionStorage), the blocks it
33
- // made and moved this load (commits.placedUnits()) and what its components wrote (commits.written(),
34
- // those of earlier loads too), and the server says which the file now has as before (POST
35
- // /__gallery/edit/reverted): a text as it was, a block it made gone, a block it moved back in the unit
36
- // it was in, a part as before a write of the page's.
32
+ // committed (commits.committed(), and those of its earlier loads: the journal), the blocks it
33
+ // made and moved this load (commits.placedUnits(), and those earlier loads made) and what its
34
+ // components wrote (commits.written(), those of earlier loads too), and the server says which the
35
+ // file now has as before (POST /__gallery/edit/reverted): a text as it was, a block it made gone, a
36
+ // block it moved back in the unit it was in, a part as before a write of the page's. A page going away
37
+ // keeps all of it in localStorage (journalKey) with the version of the file it last knew; the next
38
+ // page of the document, in this tab or another, opening on another version, asks at once.
37
39
 
38
40
  const IDLE = 1600;
39
41
  const LONGEST = 8000;
@@ -41,13 +43,45 @@ const RETRY = [1000, 2000, 5000, 10000, 30000];
41
43
  const QUIET = 1500; // how long the reader has changed nothing before the page reloads by itself
42
44
  const STORE_EVERY = 1000; // the crash buffer while typing, at most this often
43
45
  const JOURNAL_FOR = 60 * 60 * 1000; // how long a committed text is checked for being put back
46
+ const JOURNAL_SIZE = 100_000; // the most characters one document's journal keeps (the newest entries)
44
47
  const OWN_FOR = 5000; // how long the live-reload channel may still announce a version this page wrote
48
+ // A page of the Agent's own (its address's ?agent: the Agent 自用 one gallery open prints, gallery
49
+ // component try's): its commits say so (`agent`), and are no reader's edit to the review of the
50
+ // Agent's changes, so none ends a document's first writing (docs/editor.md "Agent's changes").
51
+ const AGENT_PAGE = typeof location !== "undefined" && new URLSearchParams(location.search).has("agent");
45
52
 
46
53
  // A committed text as the revert check names it, whichever load named it: the report's title, a block of
47
54
  // a unit by the unit's id (or what named the unit, with none) and its place in it, any other by what
48
55
  // names it but the words it had.
49
56
  const sameText = (block) => JSON.stringify(block?.title ? "title" : block?.unit ? [block.unit.id ?? block.unit.blockId ?? [block.unit.key, block.unit.open], block.self ? true : block.path ?? null] : { ...block, before: undefined });
50
57
 
58
+ // The journal's texts (journal()) with those of commits not answered yet (`requests`: on their way, or
59
+ // the crash buffer's) taken as committed, as committedText (commit.mjs) takes a commit's: what each
60
+ // replaced first stays where the text started, what it was between is `earlier`, and one back as it
61
+ // was first and nothing between is none; committed now (`at`).
62
+ function folded(texts, requests) {
63
+ const named = new Map(texts.map((entry) => [sameText(entry.block), entry]));
64
+ let serial = 0;
65
+ for (const request of requests) {
66
+ for (const text of request?.texts ?? []) {
67
+ const mine = text?.parts?.find((part) => part.keep)?.html;
68
+ if (typeof mine !== "string" || !text.block) continue;
69
+ const name = sameText(text.block);
70
+ const was = named.get(name);
71
+ const original = was?.original ?? text.block.before;
72
+ if (typeof original !== "string" || (was && was.mine === mine)) continue;
73
+ const earlier = [...new Set([...(was?.earlier ?? []), ...(was ? [was.mine] : [])])].filter((each) => each !== mine && each !== original).slice(-TEXTS_KEPT);
74
+ if (mine === original && earlier.length === 0) {
75
+ named.delete(name);
76
+ continue;
77
+ }
78
+ const entry = { key: was?.key ?? `f${serial++}`, block: { ...text.block, before: mine }, original, mine, ...(earlier.length > 0 ? { earlier } : {}), ...(was?.time ? { time: was.time } : {}), at: Date.now() };
79
+ named.set(name, entry);
80
+ }
81
+ }
82
+ return [...named.values()];
83
+ }
84
+
51
85
  /**
52
86
  * map: the page's map (slug, version, token); commits: createCommits(); blocked(): commits wait
53
87
  * (an input method is composing); changedAt(): when the reader last changed anything; holding(asked):
@@ -58,14 +92,14 @@ const sameText = (block) => JSON.stringify(block?.title ? "title" : block?.unit
58
92
  * warn("storage"): the crash buffer could not be written; storage: localStorage
59
93
  * (get/set/remove/keys); tab(): this tab's id (a duplicated tab takes a new one); notice(): what the
60
94
  * page says after it reloads by itself (a merge it just made), or null; session: sessionStorage
61
- * (get/set/remove); reverted(entries): texts, blocks and components' writes of the reader's that
95
+ * (get/remove), read once for the journal an earlier Gallery kept there; reverted(entries): texts, blocks and components' writes of the reader's that
62
96
  * someone else's write put back, for the reader to decide on (decide) before the page shows that
63
97
  * write (a component's with `written`: the parts, by name, and the hashes the file holds of them);
64
- * before(): called right
98
+ * listed(): words were added to what the page could not put back (lostKey), to be shown; before(): called right
65
99
  * before a commit goes, a promise it waits for (or null): what goes with the edit elsewhere is told
66
100
  * first (where the words of the reader's 批注 went: annotate/ sync).
67
101
  */
68
- export function createAutosave({ map, commits, blocked, changedAt, holding = () => false, refresh, applied, failed, warn = () => {}, storage, tab, notice = () => null, session = null, reverted = () => {}, before = () => null }) {
102
+ export function createAutosave({ map, commits, blocked, changedAt, holding = () => false, refresh, applied, failed, warn = () => {}, storage, tab, notice = () => null, session = null, reverted = () => {}, listed = () => {}, before = () => null }) {
69
103
  let known = map.version; // the file's version as the page last knew it
70
104
  // Versions this page's commits wrote (and the one it opened on), in order, and when: the
71
105
  // live-reload channel announces them too, a little later, in the order they were written. Only
@@ -96,17 +130,39 @@ export function createAutosave({ map, commits, blocked, changedAt, holding = ()
96
130
  let unstored = false; // the crash buffer could not be written
97
131
  let storedFrom = null; // what the page held (collect()'s result) when the buffer was last written with nothing on its way; null: write it anew
98
132
  const events = []; // [version, when]: what the live-reload channel announced while a commit was on its way
99
- // Texts committed by this page's earlier loads (journalKey), still checked for a while, each under a
100
- // key of its own (`c<n>`: an earlier load's keys name its blocks, as this one's name others); what
101
- // their components wrote is the commits' own again (carry), by instance.
102
- const journalKey = `gallery-edit:${map.slug}:journal`;
133
+ // What earlier pages of the document committed, made and wrote (the journal, journalKey: what each
134
+ // page kept as it went away, by tab), taken by this one as its own: the texts, still checked for an
135
+ // hour, each under a key of its own (`c<n>`: an earlier load's keys name its blocks, as this one's
136
+ // name others); the blocks they made (`m<n>`: by the file's id, with their words), until the file is
137
+ // found without one (listed) or the page no longer shows one it was found with (the reader deleted
138
+ // it); what their components wrote, the commits' own again (carry), by instance. This tab's are taken
139
+ // as the page is made, those of tabs no longer open once it knows which are (opened).
103
140
  let carried = [];
141
+ let carriedMade = [];
142
+ let textSerial = 0;
143
+ let madeSerial = 0;
144
+ // The version of the file the page last knew: every write up to it the page's own or asked of (the
145
+ // revert check answered about it, what it put back held for the reader). What the page keeps as it
146
+ // goes away says it; null while a question about what earlier pages kept is not answered yet.
147
+ let seen = map.version;
148
+ let asking = false; // what earlier pages kept, taken, is to be asked of (the file not the version they last knew)
149
+ const adopt = (departures) => {
150
+ let ask = false;
151
+ for (const { known, entries } of departures) {
152
+ if (known !== map.version) ask = true;
153
+ carried.push(...entries.filter((entry) => entry.instance === undefined && entry.made === undefined && entry.block).map((entry) => ({ ...entry, key: `c${textSerial++}` })));
154
+ carriedMade.push(...entries.filter((entry) => typeof entry.made === "string" && !carriedMade.some((other) => other.id === entry.made))
155
+ .map(({ made, parent, text, time }) => ({ key: `m${madeSerial++}`, id: made, parent: parent ?? null, text: String(text ?? ""), time, confirmed: known === map.version })));
156
+ commits.carry(entries.filter((entry) => entry.instance !== undefined).map(({ instance, parts, time }) => ({ id: instance, parts, time })));
157
+ }
158
+ if (ask) {
159
+ asking = true;
160
+ seen = null;
161
+ }
162
+ };
104
163
  try {
105
- const kept = (JSON.parse(session?.get(journalKey) ?? "[]") ?? []).filter((entry) => entry && Date.now() - entry.time < JOURNAL_FOR);
106
- carried = kept.filter((entry) => entry.instance === undefined).map((entry, index) => ({ ...entry, key: `c${index}` }));
107
- commits.carry(kept.filter((entry) => entry.instance !== undefined).map(({ instance, parts, time }) => ({ id: instance, parts, time })));
164
+ adopt([...legacyJournal(session, map.slug), ...takeJournal(storage, map.slug, (id) => id === tab())]);
108
165
  } catch {}
109
- session?.remove(journalKey);
110
166
  const reverts = new Map(); // key -> entry: put back by someone else, waiting for the reader
111
167
  let checking = false;
112
168
  const waiters = [];
@@ -227,8 +283,11 @@ export function createAutosave({ map, commits, blocked, changedAt, holding = ()
227
283
  retryAt = 0;
228
284
  offline = false;
229
285
  known = receipt.version;
286
+ // Written over the version the page last knew, no one else's write between: the page knows this one.
287
+ if (!receipt.foreign && seen !== null && sent.request.known === seen) seen = receipt.version;
230
288
  if (receipt.wrote !== false) own.push({ version: receipt.version, at: Date.now() }); // one that changed nothing wrote no version
231
289
  if (receipt.foreign) foreign = true;
290
+ deleted(sent.request, receipt);
232
291
  applied(commits.apply(sent.pending, receipt, { alone: !foreign }), receipt);
233
292
  after = commits.collect();
234
293
  recount(after);
@@ -335,7 +394,7 @@ export function createAutosave({ map, commits, blocked, changedAt, holding = ()
335
394
  if (closed) return;
336
395
  leaving = true;
337
396
  store();
338
- keepJournal();
397
+ keepJournal([flight?.request ?? parked?.request, buffer]); // what is on its way or in the buffer, as the file is to have it
339
398
  if (flight || parked || stopped || waiting() === 0 || !buffer) return; // what is on its way is in the buffer
340
399
  postCommit(map, buffer, { keepalive: true }).catch(() => {});
341
400
  }
@@ -347,6 +406,8 @@ export function createAutosave({ map, commits, blocked, changedAt, holding = ()
347
406
  */
348
407
  function heard(version, anyway = false, at = Date.now()) {
349
408
  if (closed) return;
409
+ // A write the reader asked for is on its way (showOwn): what is heard meanwhile is its own, or heard again once it failed.
410
+ if (owning) return void (missed = true);
350
411
  // It may be the commit on its way, or one whose answer was lost: known once that one is answered
351
412
  // (as of when it was announced).
352
413
  if ((flight || parked) && !anyway) return void events.push([version, at]);
@@ -386,20 +447,45 @@ export function createAutosave({ map, commits, blocked, changedAt, holding = ()
386
447
  }
387
448
  const texts = journal();
388
449
  const units = commits.placedUnits();
450
+ // The blocks earlier pages made: those the file was not yet found with, and those the page shows (one
451
+ // found with it and no longer shown, the reader deleted).
452
+ const made = carriedMade.filter((entry) => !entry.confirmed || commits.unitOf(entry.id) !== null);
389
453
  const instances = commits.written();
390
- if (texts.length === 0 && units.length === 0 && instances.length === 0) return true;
454
+ if (texts.length === 0 && units.length === 0 && made.length === 0 && instances.length === 0) return true;
391
455
  checking = true;
392
456
  let answer = null;
393
457
  try {
394
- const response = await postJson("/__gallery/edit/reverted", map.token, { slug: map.slug, opening: map.version, texts: texts.map(({ key, block, original, earlier }) => ({ key, block, original, ...(earlier ? { earlier } : {}) })), units, instances: instances.map(({ key, id, parts }) => ({ key, id, parts })), pageIds: commits.pageIds() });
458
+ const response = await postJson("/__gallery/edit/reverted", map.token, { slug: map.slug, opening: map.version, texts: texts.map(({ key, block, original, earlier }) => ({ key, block, original, ...(earlier ? { earlier } : {}) })), units: [...units, ...made.map(({ key, id, parent }) => ({ key, id, parent }))], instances: instances.map(({ key, id, parts }) => ({ key, id, parts })), pageIds: commits.pageIds() });
395
459
  answer = await response.json();
396
460
  } catch {}
397
461
  checking = false;
398
462
  if (closed) return false;
463
+ if (answer?.ok) {
464
+ // A block an earlier page made that the file no longer has is no block of this load's to hold a
465
+ // card for: its words are listed (lostKey), as what a page could not put back is; the others are
466
+ // found with the file, asked of while the page shows them.
467
+ const gone = made.filter(({ key }) => (answer.units ?? []).some((entry) => entry.key === key && entry.gone));
468
+ // One made inside another gone (a quote's paragraph, a list's item) went with it, its words among that one's.
469
+ const goneIds = new Set(gone.map(({ id }) => id));
470
+ const words = gone.filter(({ text, parent }) => text && !goneIds.has(parent)).map(({ text }) => ({ why: "reverted", text }));
471
+ const kept = words.length === 0 || keepLost(storage, map.slug, words);
472
+ if (kept) carriedMade = carriedMade.filter((entry) => !gone.includes(entry)); // asked again otherwise
473
+ for (const entry of made) if (!gone.includes(entry)) entry.confirmed = true;
474
+ if (kept && words.length > 0) listed();
475
+ // All of it asked of (no question waits to be asked again, which may carry more): the page knows the
476
+ // file as it was answered about.
477
+ if (kept && !recheck) {
478
+ seen = answer.version ?? null;
479
+ asking = false;
480
+ }
481
+ }
482
+ // Of the blocks it made that the write took out, those inside another such go with it, one card.
483
+ const goneUnits = (answer?.units ?? []).filter(({ gone, key }) => gone && !made.some((entry) => entry.key === key)).map(({ key }) => key);
399
484
  const back = answer?.ok ? [
400
485
  ...answer.reverted.map(({ key, theirs }) => ({ ...texts.find((entry) => entry.key === key), theirs })).filter((entry) => entry.key),
401
- // A block put back: by its unit, with what it holds (the reader's words, to copy).
402
- ...(answer.units ?? []).filter(({ key }) => units.some((unit) => unit.key === key)).map(({ key, gone }) => ({ key: `p${key}`, unit: key, gone: Boolean(gone), mine: commits.unitText(key) })),
486
+ // A block put back: by its unit, with what it holds (the reader's words, to copy) and, taken out, the
487
+ // blocks taken out inside it (`within`, decided with it; what it holds that the file still has is not).
488
+ ...(answer.units ?? []).filter(({ key, gone }) => units.some((unit) => unit.key === key) && !(gone && commits.heldWithin?.(key, goneUnits))).map(({ key, gone }) => ({ key: `p${key}`, unit: key, gone: Boolean(gone), mine: commits.unitText(key), ...(gone ? { within: goneUnits.filter((inner) => commits.heldWithin?.(inner, [key])) } : {}) })),
403
489
  // Parts a component wrote put back: by its unit, with the hashes the file holds of them (`written`)
404
490
  // and what the page holds of them (`data`, the reader's, kept with the crash buffer); none the page
405
491
  // holds as the file does, however the file spells it (heldOtherwise).
@@ -448,19 +534,22 @@ export function createAutosave({ map, commits, blocked, changedAt, holding = ()
448
534
  storage.remove(bufferKey());
449
535
  storage.remove(keptKey());
450
536
  storedFrom = null; // written anew if anything stores after all
451
- keepJournal();
537
+ keepJournal(); // a write landing after that answer and before the page shown again is served is asked of there (opened)
452
538
  refresh();
453
539
  reloadView(map.slug, null, notice());
454
540
  }
455
541
 
456
- // The texts committed, this load's and earlier ones', one of each block (sameText): what an earlier
457
- // load committed of a block a later one committed too is where that text started, and what it was
458
- // between (two of one block are no one question: the server's answer would name neither); back as it
459
- // was first, it is asked of what it was between.
542
+ // The texts committed, this load's and earlier ones', one of each block (sameText): what was committed
543
+ // of a block before (`at`, when it was last committed: two tabs' pages are taken in no order of their
544
+ // own) is where that text started, and what it was between (two of one block are no one question: the
545
+ // server's answer would name neither); back as it was first, it is asked of what it was between. Joined
546
+ // with one of this load's, it goes by that one's key and naming (decide lets this load's go by its key).
460
547
  const journal = () => {
461
548
  const now = commits.committed().map((entry) => ({ ...entry, time: Date.now() }));
549
+ const own = new Set(now.map((entry) => entry.key));
462
550
  const texts = new Map();
463
- for (const entry of [...carried, ...now]) {
551
+ const when = (entry) => entry.at ?? entry.time ?? 0;
552
+ for (const entry of [...carried, ...now].sort((a, b) => when(a) - when(b))) {
464
553
  const name = sameText(entry.block);
465
554
  const was = texts.get(name);
466
555
  if (!was) {
@@ -468,7 +557,8 @@ export function createAutosave({ map, commits, blocked, changedAt, holding = ()
468
557
  continue;
469
558
  }
470
559
  const earlier = [...new Set([...(was.earlier ?? []), was.mine, entry.original, ...(entry.earlier ?? [])])].filter((text) => text !== entry.mine && text !== was.original).slice(-TEXTS_KEPT);
471
- const joined = { ...entry, original: was.original, earlier };
560
+ const named = own.has(was.key) && !own.has(entry.key) ? { key: was.key, block: { ...was.block, before: entry.mine } } : {};
561
+ const joined = { ...entry, ...named, original: was.original, earlier, time: Math.max(was.time ?? 0, entry.time ?? 0) || undefined };
472
562
  if (earlier.length === 0) delete joined.earlier;
473
563
  if (entry.mine === was.original && earlier.length === 0) texts.delete(name);
474
564
  else texts.set(name, joined);
@@ -476,16 +566,73 @@ export function createAutosave({ map, commits, blocked, changedAt, holding = ()
476
566
  return [...texts.values()];
477
567
  };
478
568
 
479
- // What the page committed (journal()) and what its components wrote (commits.written()), kept for the
480
- // next load of the page in this tab, which asks of them as its own: when it is shown again, and when
481
- // the page goes away (a reload of the reader's, another document opened in a workbench).
482
- function keepJournal() {
483
- const kept = [
484
- ...journal().map((entry) => ({ ...entry, time: entry.time ?? Date.now() })),
569
+ // A commit of the page's that the file took deleted blocks (`request`'s removals, answered `receipt`): of
570
+ // the blocks earlier pages made, those (and those made inside them) are the reader's own deletion, asked
571
+ // of by no page any more: this one's, and those kept by pages of tabs gone that no page took yet.
572
+ function deleted(request, receipt) {
573
+ const ids = (request.units ?? []).filter((op) => op.remove && !(receipt.units ?? []).some((answer) => answer.key === op.key && answer.status === "conflict"))
574
+ .flatMap((op) => [op.unit?.id, ...(op.items ?? []).map((item) => item?.id)]).filter((id) => typeof id === "string");
575
+ if (ids.length === 0) return;
576
+ const gone = madeWithin(ids, carriedMade.map(({ id, parent }) => ({ id, parent })));
577
+ carriedMade = carriedMade.filter((entry) => !gone.has(entry.id));
578
+ try {
579
+ forgetMade(storage, map.slug, ids);
580
+ } catch {}
581
+ }
582
+
583
+ // What the page committed (journal()), made (its blocks the file has, by their ids, with their words:
584
+ // this load's and those of earlier loads it still shows or has not found the file with yet) and what
585
+ // its components wrote (commits.written()), kept in the journal under this tab with the version of the
586
+ // file it last knew (`known`, null when it does not), for the next page of the document, in this tab
587
+ // or another, which takes them as its own, and asks of them at once if it opens on another version
588
+ // (opened): when the page goes to show the file again, when it goes away (a reload of the reader's,
589
+ // another document opened, the tab closed) and after a write the reader asked for (showOwn). `pending`:
590
+ // commits not answered yet (on their way, or the crash buffer's, which the next page sends), whose
591
+ // texts are taken as committed, the reader's own words (an undo back to what an earlier commit
592
+ // replaced) being no one else's write.
593
+ function keepJournal(pending = []) {
594
+ const time = Date.now();
595
+ const made = new Map();
596
+ for (const { key, id, parent, from } of commits.placedUnits()) if (from === undefined && !reverts.has(`p${key}`)) made.set(id, { made: id, parent, text: commits.unitText(key), time });
597
+ for (const entry of carriedMade) {
598
+ const unit = commits.unitOf(entry.id);
599
+ if (made.has(entry.id) || (entry.confirmed && unit === null)) continue;
600
+ made.set(entry.id, { made: entry.id, parent: entry.parent, text: (unit !== null && commits.unitText(unit)) || entry.text, time: entry.time ?? time });
601
+ }
602
+ const entries = [
603
+ ...folded(journal(), pending.filter(Boolean)).map((entry) => ({ ...entry, time: entry.time ?? time })),
485
604
  ...commits.written().map(({ id, parts, time }) => ({ instance: id, parts, time })),
605
+ ...made.values(),
486
606
  ];
487
- if (kept.length > 0) session?.set(journalKey, JSON.stringify(kept));
488
- else session?.remove(journalKey);
607
+ try {
608
+ keepDeparture(storage, map.slug, tab(), entries.length > 0 ? { known: seen, time, entries } : null);
609
+ } catch {}
610
+ }
611
+
612
+ /**
613
+ * The page opened and edits, the workbench told it is ready (`open`: the ids of the tabs that answered
614
+ * they show the document now). What pages of tabs no longer open kept is taken too (the document
615
+ * opened again in another tab), and where this page opened on another version of the file than an
616
+ * earlier page last knew (someone else's write landing while no page was there to hear of it, or
617
+ * between the last question of a page showing the file again and this page being served, which it
618
+ * never hears of as a write), all it took is asked of at once (checkReverted): a text put back is a
619
+ * card, a block made that the file no longer has is listed. On the very version, nothing is asked.
620
+ * A page done with, or going to be shown again (it kept its journal already), takes nothing: the next
621
+ * page does; one whose write (showOwn) failed takes it then.
622
+ */
623
+ let unopened = null; // opened()'s call while the page was to be shown again by showOwn: { open }
624
+ function opened(open = null) {
625
+ if (closed) return;
626
+ if (reloading) return void (unopened = { open });
627
+ if (open) {
628
+ try {
629
+ adopt(takeJournal(storage, map.slug, (id) => id !== tab() && !open.has(id)));
630
+ } catch {}
631
+ forgetOld(storage);
632
+ }
633
+ if (!asking) return;
634
+ if (checking) recheck = true;
635
+ else checkReverted();
489
636
  }
490
637
 
491
638
  /**
@@ -499,7 +646,7 @@ export function createAutosave({ map, commits, blocked, changedAt, holding = ()
499
646
  // A block put back: kept (made again, or moved again where the page has it), or the file's. Parts a
500
647
  // component wrote: written again over the file's (its hashes of them), or the file's.
501
648
  if (entry.written) commits.rewrite(entry.unit, entry.written, mine);
502
- else commits.putBack(entry.unit, { gone: entry.gone, mine });
649
+ else commits.putBack(entry.unit, { gone: entry.gone, mine, within: entry.within });
503
650
  reverts.delete(key);
504
651
  storedFrom = null;
505
652
  if (mine) changed(true);
@@ -523,6 +670,54 @@ export function createAutosave({ map, commits, blocked, changedAt, holding = ()
523
670
  return true;
524
671
  }
525
672
 
673
+ /**
674
+ * A write the reader asked for that changes the file (撤回 of the Agent's changes and its 撤销:
675
+ * changes/): `run()` makes it, resolving with whether it did (the version it wrote, when known); then the page shows the file as after a
676
+ * write of its own, at once, asking nothing of what it put back (the revert check: the reader asked
677
+ * for it), and what is heard meanwhile shows nothing first. The caller saved what waited first
678
+ * (flush) and made sure nothing waits for the reader. Resolves with whether the page goes.
679
+ */
680
+ let owning = false; // showOwn's write is on its way
681
+ let missed = false; // and the live-reload channel spoke meanwhile
682
+ async function showOwn(run) {
683
+ if (closed || reloading) return false;
684
+ reloading = owning = true;
685
+ missed = false;
686
+ clearTimeout(reloadTimer);
687
+ let done = false;
688
+ let wrote = null; // the version its write left, when run() says
689
+ try {
690
+ const result = await run();
691
+ done = Boolean(result);
692
+ if (typeof result === "string") wrote = result;
693
+ } catch {}
694
+ owning = false;
695
+ if (closed) return done;
696
+ if (!done) {
697
+ reloading = false;
698
+ refresh();
699
+ if (unopened) {
700
+ const { open } = unopened;
701
+ unopened = null;
702
+ opened(open);
703
+ }
704
+ if (missed) heard(null, true);
705
+ else if (foreign) maybeReload();
706
+ return false;
707
+ }
708
+ storage.remove(bufferKey());
709
+ storage.remove(keptKey());
710
+ storedFrom = null;
711
+ // The page knew the file it asked to be written as; a write landing before the page shown again is
712
+ // served is asked of there. Not told which version that is, or with a question of its own not answered
713
+ // yet, the next page asks whatever it opens on.
714
+ seen = asking ? null : wrote;
715
+ keepJournal();
716
+ refresh();
717
+ reloadView(map.slug, null, null);
718
+ return true;
719
+ }
720
+
526
721
  /** Show the file as it is once nothing waits (the reader gave a change up for the file's, or what the page is made of changed). */
527
722
  function reloadSoon() {
528
723
  foreign = true;
@@ -552,10 +747,12 @@ export function createAutosave({ map, commits, blocked, changedAt, holding = ()
552
747
  changed,
553
748
  flush,
554
749
  leave,
750
+ opened,
555
751
  heard,
556
752
  store,
557
753
  decide,
558
754
  reloadSoon,
755
+ showOwn,
559
756
  close,
560
757
  get state() {
561
758
  return { waiting: waiting(), syncing: Boolean(flight), offline, stopped, foreign, reloading, held: commits.issues.size + reverts.size, drafts, unstored };
@@ -566,7 +763,7 @@ export function createAutosave({ map, commits, blocked, changedAt, holding = ()
566
763
  // A commit sent: the server's answer, or { ok: false, reason: "server" } when it failed or answered
567
764
  // no JSON (a lost connection rejects: the caller reads that as offline).
568
765
  async function postCommit(map, request, { keepalive = false } = {}) {
569
- const response = await postJson("/__gallery/edit/commit", map.token, { slug: map.slug, ...request }, { keepalive });
766
+ const response = await postJson("/__gallery/edit/commit", map.token, { slug: map.slug, ...request, ...(AGENT_PAGE ? { agent: true } : {}) }, { keepalive });
570
767
  if (response.status >= 500) return { ok: false, reason: "server" };
571
768
  return response.json().catch(() => ({ ok: false, reason: "server" }));
572
769
  }
@@ -646,6 +843,128 @@ function keepLost(storage, slug, items) {
646
843
  return storage.set(lostKey(slug), JSON.stringify([...readLost(storage, slug), ...items.map((item) => ({ ...item, time }))].slice(-100))) !== false;
647
844
  }
648
845
 
846
+ /**
847
+ * Where the pages of a document keep, as they go away, what they committed, made and wrote, for the
848
+ * next page of it to ask of (createAutosave: keepJournal, opened), in localStorage: { v: 1, tabs: {
849
+ * <tab>: { known, time, entries } } }, one departure a tab, `known` the version of the file that page
850
+ * last knew (null: it did not), each entry with its `time`: a text ({ key, block, original, mine,
851
+ * earlier?, at }, `at` when it was last committed), a block made ({ made, parent, text }; taken out of
852
+ * every departure once a page's commit deletes it: forgetMade) or what a component wrote ({ instance, parts }).
853
+ * Entries are kept for JOURNAL_FOR, the newest of them JOURNAL_SIZE characters at most.
854
+ */
855
+ export const journalKey = (slug) => `gallery-edit:${slug}:journal`;
856
+ const JOURNAL_KEY = /^gallery-edit:(.+):journal$/;
857
+
858
+ // The departures the journal holds, by tab, their entries still asked of (none left: no departure).
859
+ function readJournal(storage, slug) {
860
+ let record = null;
861
+ try {
862
+ record = JSON.parse(storage.get(journalKey(slug)) ?? "null");
863
+ } catch {}
864
+ const tabs = {};
865
+ const now = Date.now();
866
+ for (const [tab, departure] of Object.entries(record?.tabs && typeof record.tabs === "object" ? record.tabs : {})) {
867
+ const entries = (Array.isArray(departure?.entries) ? departure.entries : []).filter((entry) => entry && typeof entry === "object" && now - entry.time < JOURNAL_FOR);
868
+ if (entries.length > 0) tabs[tab] = { known: typeof departure.known === "string" ? departure.known : null, time: departure.time, entries };
869
+ }
870
+ return tabs;
871
+ }
872
+
873
+ // The journal written as `tabs`, the newest entries first as long as they fit (one too long left out),
874
+ // or taken away when nothing is left. A write that fails leaves it as it was: the crash buffer comes first.
875
+ function writeJournal(storage, slug, tabs) {
876
+ const all = Object.entries(tabs).flatMap(([tab, departure]) => departure.entries.map((entry) => ({ tab, entry, size: JSON.stringify(entry).length })))
877
+ .sort((a, b) => b.entry.time - a.entry.time);
878
+ let room = JOURNAL_SIZE;
879
+ const fits = new Set();
880
+ for (const { entry, size } of all) {
881
+ if (size > room) continue;
882
+ room -= size;
883
+ fits.add(entry);
884
+ }
885
+ const kept = {};
886
+ for (const [tab, departure] of Object.entries(tabs)) {
887
+ const entries = departure.entries.filter((entry) => fits.has(entry));
888
+ if (entries.length > 0) kept[tab] = { ...departure, entries };
889
+ }
890
+ if (Object.keys(kept).length === 0) return void storage.remove(journalKey(slug));
891
+ const text = JSON.stringify({ v: 1, tabs: kept });
892
+ if (storage.get(journalKey(slug)) !== text) storage.set(journalKey(slug), text);
893
+ }
894
+
895
+ // The departures of the tabs `which` picks, taken out of the journal: [{ known, entries }].
896
+ function takeJournal(storage, slug, which) {
897
+ const tabs = readJournal(storage, slug);
898
+ const taken = Object.keys(tabs).filter(which);
899
+ if (taken.length === 0) return [];
900
+ const departures = taken.map((tab) => tabs[tab]);
901
+ for (const tab of taken) delete tabs[tab];
902
+ writeJournal(storage, slug, tabs);
903
+ return departures;
904
+ }
905
+
906
+ // The ids of `ids` and of the blocks made (`made`: [{ id, parent }]) inside one of them, at any depth.
907
+ function madeWithin(ids, made) {
908
+ const gone = new Set(ids);
909
+ for (let more = true; more;) {
910
+ more = false;
911
+ for (const { id, parent } of made) {
912
+ if (gone.has(id) || !gone.has(parent)) continue;
913
+ gone.add(id);
914
+ more = true;
915
+ }
916
+ }
917
+ return gone;
918
+ }
919
+
920
+ // The blocks made that the reader deleted (`ids`, and those made inside them) taken out of every
921
+ // departure the journal holds.
922
+ function forgetMade(storage, slug, ids) {
923
+ const tabs = readJournal(storage, slug);
924
+ let changed = false;
925
+ for (const departure of Object.values(tabs)) {
926
+ const gone = madeWithin(ids, departure.entries.filter((entry) => typeof entry.made === "string").map(({ made, parent }) => ({ id: made, parent })));
927
+ const entries = departure.entries.filter((entry) => typeof entry.made !== "string" || !gone.has(entry.made));
928
+ if (entries.length === departure.entries.length) continue;
929
+ departure.entries = entries;
930
+ changed = true;
931
+ }
932
+ if (changed) writeJournal(storage, slug, tabs);
933
+ }
934
+
935
+ // This tab's departure written (null: none), beside the other tabs'.
936
+ function keepDeparture(storage, slug, tab, departure) {
937
+ const tabs = readJournal(storage, slug);
938
+ if (departure) tabs[tab] = departure;
939
+ else if (tabs[tab]) delete tabs[tab];
940
+ else if (storage.get(journalKey(slug)) === null) return;
941
+ writeJournal(storage, slug, tabs);
942
+ }
943
+
944
+ // What a Gallery before 2026-11-08 kept for the next load in the tab (sessionStorage, under the same
945
+ // key): its entries, or { asked, entries }, read once as this tab's departure, the version it last knew
946
+ // that `asked` (none of "own" or nothing: not known).
947
+ function legacyJournal(session, slug) {
948
+ if (!session) return [];
949
+ let stored = null;
950
+ try {
951
+ stored = JSON.parse(session.get(journalKey(slug)) ?? "null");
952
+ } catch {}
953
+ session.remove(journalKey(slug));
954
+ const entries = (Array.isArray(stored) ? stored : Array.isArray(stored?.entries) ? stored.entries : []).filter((entry) => entry && typeof entry === "object" && Date.now() - entry.time < JOURNAL_FOR);
955
+ const known = !Array.isArray(stored) && typeof stored?.asked === "string" && stored.asked !== "own" ? stored.asked : null;
956
+ return entries.length > 0 ? [{ known, entries }] : [];
957
+ }
958
+
959
+ // The journals of documents whose every entry is older than JOURNAL_FOR, taken away (a document not
960
+ // opened again within the hour leaves none behind).
961
+ function forgetOld(storage) {
962
+ for (const key of storage.keys?.() ?? []) {
963
+ const slug = JOURNAL_KEY.exec(key)?.[1];
964
+ if (slug && Object.keys(readJournal(storage, slug)).length === 0) storage.remove(key);
965
+ }
966
+ }
967
+
649
968
  /**
650
969
  * Reload the page to show the file as it is now, keeping where the reader was (`view`, or now):
651
970
  * the scroll position, the block the caret was in (by its data-block-id) with the caret's offset in
@@ -6,16 +6,16 @@ import { isHost } from "./core.mjs";
6
6
  // (selection/).
7
7
 
8
8
  /**
9
- * Whether a click to the right of a block (outside it) selects it: a boxed block (a code block, a
10
- * highlight block, a disclosure, a card, a table, a divider…) or a row of columns, as opposed to text
11
- * and the boxes text flows in (a list, a quote, a section).
9
+ * Whether a click to the right of a block, past the text area it stands in (insert/ boxedBeside),
10
+ * selects it: a boxed block (a code block, a highlight block, a disclosure, a card, a table, a
11
+ * divider…) or a row of columns, as opposed to text and the boxes text flows in (a list, a quote, a
12
+ * section).
12
13
  */
13
14
  export const selectsBeside = (unit) => BESIDE.has(unit?.getAttribute?.("data-ge-unit-kind"));
14
15
 
15
16
  /**
16
17
  * Whether Enter on a block selected (the first of those selected) puts a new paragraph after them
17
18
  * (blocks.mjs, insert.paragraphAfter): a block of no text of its own, those a click to their right
18
- * selects and a 选项卡区块; not a text block among them (a callout, whose text Enter edits, a formula
19
- * block, whose editor it opens).
19
+ * selects and a 选项卡区块; not a text block among them (a formula block, whose editor it opens).
20
20
  */
21
21
  export const entersAfter = (unit) => Boolean(unit) && !isHost(unit) && ENTERS_AFTER.has(unit.getAttribute("data-ge-unit-kind"));
@@ -12,7 +12,7 @@ import { t } from "../../../shared/i18n/index.mjs";
12
12
  // show one of the nine with none of a family (a callout's background is blue: `defaults`), that
13
13
  // family has no 默认: that color is ringed for none, and picking it takes the class away. Each
14
14
  // swatch names its color in a tooltip. The swatches are drawn with the kit's own classes, so they
15
- // match the text in either theme. A pick gives every target that color of its family, the other family's staying (one
15
+ // match the text in either theme, a background's as the block's fill (`--doc-fill`). A pick gives every target that color of its family, the other family's staying (one
16
16
  // undo step: look, history.mjs; a table cell's one color: table/). Only the families the targets take show.
17
17
 
18
18
  const STYLE = `
@@ -21,6 +21,8 @@ const STYLE = `
21
21
  .ge-pop .ge-color-cell > span { display: flex; align-items: center; justify-content: center; box-sizing: border-box; width: 26px; height: 26px; border-radius: 6px;
22
22
  font-size: 16px; font-weight: 500; line-height: 1; box-shadow: inset 0 0 0 1px var(--ge-ring); }
23
23
  .ge-pop .ge-color-cell > span:not([class*="doc-text-"]) { color: var(--ge-tx); }
24
+ /* A block's background swatch shows the block's fill, not the words' deeper one the kit gives a span. */
25
+ .ge-pop .ge-color-cell > span[class*="doc-highlight-"] { background: var(--doc-fill); }
24
26
  .ge-pop .ge-color-cell:hover > span, .ge-pop .ge-color-cell[data-active] > span { box-shadow: inset 0 0 0 2px var(--ge-ring); }
25
27
  .ge-pop .ge-color-cell[aria-current="true"] > span { box-shadow: inset 0 0 0 2px var(--ge-ring-strong); }
26
28
  ${Object.entries(RINGS).map(([name, [light, dark, strong, strongDark]]) => `.ge-pop .ge-color-cell[data-ring="${name}"] { --ge-ring: light-dark(${light}, ${dark}); --ge-ring-strong: light-dark(${strong}, ${strongDark}); }`).join("\n ")}
@@ -54,7 +54,7 @@ const WIDTH = MENU_WIDTH; // the menu, as wide as its grid (no room left beside
54
54
  * color rows). copyLink(target): the block's address on the clipboard, in the click on its row; null
55
55
  * on a page no address leads to; linkAhead(): the menu opens with that row, what the click will want is read now.
56
56
  */
57
- export function createBlockMenu({ info, menu, selection, remove, turnInto, convert, turnIntoAll = () => null, convertAll = () => {}, below, belowTypes = () => [], add, look, copyLink = () => {}, linkAhead = () => {} }) {
57
+ export function createBlockMenu({ info, menu, selection, remove, takenWith = (units) => units, turnInto, convert, turnIntoAll = () => null, convertAll = () => {}, below, belowTypes = () => [], add, look, copyLink = () => {}, linkAhead = () => {} }) {
58
58
  const chapters = sectionOps();
59
59
  const columns = columnOps();
60
60
  const { kindOf, nameOf, keepText, boxKindOf } = info;
@@ -95,12 +95,13 @@ export function createBlockMenu({ info, menu, selection, remove, turnInto, conve
95
95
  // where it is. What it holds comes out as it stands, so a block in a column keeps its column, the row
96
96
  // of columns coming out whole, and one in a section in a Sheet panel ends in the panel. None for a
97
97
  // block that has no 分区与分栏 › of its own (no columns row, in a section: a list item, a flowchart's
98
- // node, a quote's later paragraph, a block an item holds).
98
+ // node, a quote's later paragraph, a block an item holds): asked of the block alone (a folded heading
99
+ // whose section a column cannot take keeps it).
99
100
  const dissolveRow = (units) => {
100
101
  const section = chapters?.dissolvesFrom(units[0]);
101
102
  if (!section || units.some((unit) => chapters.dissolvesFrom(unit) !== section)) return [];
102
103
  const own = units[0] === section;
103
- if (!own && units.some((unit) => (columns?.columnsCheck([unit]) ?? null) === null)) return [];
104
+ if (!own && units.some((unit) => (columns?.columnsCheck([unit], (alone) => [alone]) ?? null) === null)) return [];
104
105
  const reason = chapters.unwrapCheck(section);
105
106
  return [{ label: own ? t("解散分区") : t("解散所在分区"), icon: ICONS.dissolve, disabled: Boolean(reason), note: reason || undefined, run: () => chapters.unwrap(section, own ? null : units) }];
106
107
  };
@@ -149,8 +150,9 @@ export function createBlockMenu({ info, menu, selection, remove, turnInto, conve
149
150
  const colors = colorRow(group);
150
151
  items.push(...colors, ...(colors.length > 0 ? [{ separator: true }] : []));
151
152
  // Blocks next to each other in the page or a Sheet panel become a section; a selection with gaps does not.
152
- const wrap = chapters?.wrapCheck(group) ?? null;
153
- const sections = [...(wrap !== null ? [{ label: t("组成新分区"), icon: ICONS.group, disabled: Boolean(wrap), note: wrap || undefined, run: () => chapters.wrap(group) }] : []), ...dissolveRow(group)];
153
+ // A folded heading among them goes in with what it hides (fold/).
154
+ const wrap = chapters?.wrapCheck(takenWith(group)) ?? null;
155
+ const sections = [...(wrap !== null ? [{ label: t("组成新分区"), icon: ICONS.group, disabled: Boolean(wrap), note: wrap || undefined, run: () => chapters.wrap(takenWith(group)) }] : []), ...dissolveRow(group)];
154
156
  // Neighbours in one container go side by side, a column each.
155
157
  items.push(...groupRow(sections, splitRows(group)));
156
158
  items.push({ label: t("删除"), icon: ICONS.trash, hint: "Del", disabled: Boolean(refused), note, run: () => remove(group) });
@@ -193,7 +195,7 @@ export function createBlockMenu({ info, menu, selection, remove, turnInto, conve
193
195
  }
194
196
  const sections = [];
195
197
  if (chapter(target)) sections.push({ label: t("在下方新建分区"), icon: ICONS.section, run: () => add(target, "section") });
196
- if (chapters?.wrapCheck([target]) === "") sections.push({ label: t("组成新分区"), icon: ICONS.group, run: () => chapters.wrap([target]) });
198
+ if (chapters?.wrapCheck(takenWith([target])) === "") sections.push({ label: t("组成新分区"), icon: ICONS.group, run: () => chapters.wrap(takenWith([target])) });
197
199
  sections.push(...dissolveRow([target]));
198
200
  const splits = splitRows([target]);
199
201
  // 选中外层 joins 分区与分栏 › where the block has that submenu; a block with none gets none for it.