@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
@@ -3,6 +3,7 @@
3
3
  import "../../shared/renamed-storage.mjs";
4
4
  import { OUTER, can, captureLayout, editableAhead, firstHost, isHost, limitText, markFrames, markKinds, matchesSource, newHost, newMention, ownHTML, plainText, prepareBlock, splitBlock, textEnd, tidyEmptied, unitElement, withLeads } from "./core.mjs";
5
5
  import { createBlocks } from "./blocks.mjs";
6
+ import { hiddenByFold, reveal } from "./folded.mjs";
6
7
  import { createFlags } from "./flags.mjs";
7
8
  import { createFrame } from "./frame.mjs";
8
9
  import { createHistory } from "./history.mjs";
@@ -14,10 +15,12 @@ import { createCommits, kindOf } from "./commit.mjs";
14
15
  import { createConflicts, packageChanged, unfit } from "./conflicts.mjs";
15
16
  import { checkLeft, createAutosave, keepWith, lostKey, pendingKey, readLost, recover, reloadView, setReloader, takeView, viewNow } from "./autosave.mjs";
16
17
  import { SOLO, connectWorkbench } from "./session.mjs";
18
+ import { lookOfElement } from "../../shared/document-look.mjs";
17
19
  import { belowTargets, convertBlock, convertGroup, groupParents, groupTargets, noTextToCarry, targetsOf, touchedBy, turnInto, turnParents, turnUnit, typeOf } from "./convert.mjs";
18
20
  import { joinCode, rangeAt, rangeOffsets } from "./marks.mjs";
19
- import { addStyle, button, copyAddress, element, layer } from "./ui.mjs";
21
+ import { addStyle, copyAddress, element, layer, textButton } from "./ui.mjs";
20
22
  import { createClipboard } from "./clipboard/index.mjs";
23
+ import { serveFiles } from "./served.mjs";
21
24
  import { createFormatting } from "./format-bar/index.mjs";
22
25
  import { connectHints, hideHint, readOnlyReason, scheduleHint, trackPointer } from "./hints/index.mjs";
23
26
  import { createInsert } from "./insert/index.mjs";
@@ -26,7 +29,8 @@ import { bookmarkItems, connectViews, linkTitle, offerViews } from "./links/view
26
29
  import { connectChipFills } from "./chip-fills.mjs";
27
30
  import { connectFormula, dismissFormula, formulaBoxNode, loadKatex, openFormula } from "./formula/index.mjs";
28
31
  import { settlePads } from "./pads.mjs";
29
- import { beforeDelete, codeArrow, codeClick, codePress, settleCodeEdge } from "./typing/code-edges.mjs";
32
+ import { followLongRuns } from "./long-runs.mjs";
33
+ import { beforeDelete, codeArrow, codeClick, codePress, deletedBack, deletingBack, settleCodeEdge, takeEntry } from "./typing/code-edges.mjs";
30
34
  import { createMarkdown } from "./markdown/index.mjs";
31
35
  import { createResize } from "./resize/index.mjs";
32
36
  import { connectPages, fieldOpen, keptByComponent, menuRow, modalOps, pageAt, pageIcon, pageObjects, pageOf, pageOfHost, pageOfType, pageOfUnit, panelOpen, typedAsIs } from "./page-objects.mjs";
@@ -42,6 +46,7 @@ import { createSelectAll, topStep } from "./select-all/index.mjs";
42
46
  import { revealText } from "./find/index.mjs";
43
47
  import { createOutline } from "./outline/index.mjs";
44
48
  import { createAnnotate } from "./annotate/index.mjs";
49
+ import { createChanges as createAgentChanges } from "./changes/index.mjs";
45
50
  import { BLOCK_TYPES, HOSTS, PLAIN_TEXT, TYPE_INFO, accepts, blankSaysOf, boxOwner, texOnly, textFilters } from "../components/registry.mjs";
46
51
  import { createPages } from "../components/pages.mjs";
47
52
  import { openMediaPicker } from "./emoji-picker/index.mjs";
@@ -54,6 +59,7 @@ import { goBackTo, placeIn, unmoved } from "../../shared/reading-place.mjs";
54
59
  import { heldList, holdPages } from "./links/pages.mjs";
55
60
  import { hideBlocks } from "./offered.mjs";
56
61
  import { local, storageOf } from "./storage.mjs";
62
+ import { createTodoWrites } from "./todo-writes.mjs";
57
63
  import { language, t } from "../../shared/i18n/index.mjs";
58
64
 
59
65
  // In-place editing for the live preview (`npm run dev:local` only; never exported).
@@ -77,6 +83,7 @@ import { language, t } from "../../shared/i18n/index.mjs";
77
83
  // select-all/ Ctrl+A: the block's text, then its container's blocks, one level a press, then the page
78
84
  // outline/ 目录: the page's headings at its right (the room there is margin.mjs's)
79
85
  // annotate/ 批注: started from the format bar, a block's button or Ctrl+Alt+M; cards in the margin, with no room markers in the gutter and the card by the words
86
+ // changes/ the Agent's changes (设置 › 显示变更): what an Agent wrote since the reader last kept or reverted it, marked; the bar at the bottom
80
87
  // blocks.mjs the block tools: handle/, block-menu/, selection/, drag/
81
88
  //
82
89
  // and the components' own editing (src/editor/components/<name>/page.mjs). Undo and redo are
@@ -103,6 +110,7 @@ let markdown = null; // Markdown shortcuts as the reader types (markdown/)
103
110
  let selectAll = null; // Ctrl+A widening step by step (select-all/)
104
111
  let outline = null; // the page's headings at its right (outline/), not on a page opened on its own (?solo)
105
112
  let annotate = null; // 批注 (annotate/), on every page of a session
113
+ let agentChanges = null; // what an Agent changed, under review (changes/), on every page of a session
106
114
  let editing = false;
107
115
  let composing = false; // an input method is composing
108
116
  // A composition ends with compositionend, which Chrome does not always send (a paste over the text
@@ -112,6 +120,7 @@ const compositionOver = (event) => {
112
120
  if (composing && !event.isComposing && event.keyCode !== 229) composing = false;
113
121
  };
114
122
  let pressing = false; // the main button is down on the page (a click or a drag under way)
123
+ let pressedText = null; // the text block a press of the main button came down in (onPointerDown), for the click that ends it
115
124
  let commits = null; // the page's commits (commit.mjs)
116
125
  let autosave = null; // when they go (autosave.mjs)
117
126
  let conflicts = null; // what the file refused, for the reader to decide (conflicts.mjs)
@@ -150,7 +159,8 @@ const STYLE = `
150
159
  as the element's own outline. Selected blocks get a fill instead (selection/). */
151
160
  /* Editable text has a text block's corners and, framed, a light fill under the pointer, unless its
152
161
  component declares others: --ge-text-radius, and --ge-text-tint (none: plain, as Notion's and
153
- Feishu's; a cell, a callout, a code block and its title, a disclosure's title). */
162
+ Feishu's; a cell, a code block and its title, a disclosure's title, a media block's
163
+ caption, a card's title and caption). */
154
164
  [data-ge-editing] [contenteditable="true"] { border-radius: var(--ge-text-radius, 3px); }
155
165
  [data-ge-editing] [contenteditable="true"]:focus { outline: none; }
156
166
  [data-ge-editing] [data-ge-round="box"] { border-radius: 8px; }
@@ -260,7 +270,12 @@ const { newParagraph } = insert;
260
270
 
261
271
  // The icon picker's images go into the report's folder (editor/media-store.mjs), where the server serves them.
262
272
  const assetUrl = (file) => mediaUrl("asset", MAP.slug, file);
273
+ serveFiles(assetUrl); // a table cell's pictures (单元格里的图片) show where the server serves them
263
274
  connectPicker({ slug: MAP.slug, token: MAP.token, notify: say });
275
+ // A block of the page checking a to-do of a document (context.workspace.setTodo: ./todo-writes.mjs): written
276
+ // by the workspace's service, this one's too as any write it did not make, which the page merges; no step of
277
+ // its undo (only a custom page keeps one: board/).
278
+ createTodoWrites({ token: MAP.token }).listen();
264
279
  // Whether a block tool may act: the page edits, no reload is on its way and no field of a component is being edited.
265
280
  const active = () => editing && !autosave?.state.reloading && !fieldOpen();
266
281
  // A picture or file sent to the report's folder (kind: "image", "file" or "embed"): the server's answer.
@@ -307,9 +322,10 @@ connectPages(createPages({
307
322
  })); // what the engines ask of a component (page-objects.mjs)
308
323
 
309
324
  const typing = createTyping({
310
- struct, say, keepText: (node) => blocks.keepText(node), paragraphBefore: insert.paragraphBefore, paragraphAfter: insert.paragraphAfter, removeBlocks: (units) => blocks.remove(units), selectBlock: (unit) => blocks.select(unit),
325
+ struct, say, keepText: (node) => blocks.keepText(node), paragraphBefore: insert.paragraphBefore, removeBlocks: (units) => blocks.remove(units), selectBlock: (unit) => blocks.select(unit),
311
326
  adding: () => slash?.adding ?? null,
312
327
  leave: createLeaving({ struct, touchedBy, convertHost, typeOf, targetsOf }),
328
+ showHidden: (node) => blocks?.folds.showAround(node), // a folded heading's section opened before a join takes in its words (fold/)
313
329
  });
314
330
  // Selecting text across blocks: its listeners go before the editor's own keys and clipboard.
315
331
  const crossText = createTextSelection({
@@ -363,6 +379,7 @@ const clipboard = createClipboard({
363
379
  pageLink: pageLinkOf,
364
380
  titleBold: () => formatting?.armed ?? false, // a node's empty title: what is pasted there bold, as typed
365
381
  showCaret,
382
+ pictures: () => tables?.pictures ?? null, // a table cell's (table/pictures.mjs)
366
383
  });
367
384
 
368
385
  // ---------- editing ----------
@@ -411,6 +428,8 @@ function enter() {
411
428
  });
412
429
  layout = captureLayout(document, MAP);
413
430
  markFrames(document, layout, hosts);
431
+ // A text block holding a long run (a path, a URL) breaks anywhere, judged now and as its text changes (long-runs.mjs).
432
+ followLongRuns(document.querySelector("main") ?? document.body);
414
433
  commits = createCommits({ root: document, map: MAP, baselines, units, boxes, getLayout: () => layout, setLayout: (next) => (layout = next) });
415
434
  // Commits wait while an input method composes, a formula is being edited (formula/), the "/" menu
416
435
  // or the "@" menu stands on what is typed for it (half of it is no text of the file's) or a gap
@@ -429,16 +448,19 @@ function enter() {
429
448
  conflicts.add(entries.map((entry) => ({ ...entry, key: `r:${entry.key}`, revert: entry.key, kind: entry.written ? "reverted-source" : entry.unit === undefined ? "reverted" : "reverted-unit" })));
430
449
  say(t("AI 的写入把你之前保存的 {0} 处修改改回去了:在左下方选择保留哪一边。", entries.length), "error");
431
450
  },
451
+ listed: () => showLost(), // a block the page before this one made, which someone else's write took out
432
452
  });
433
453
  conflicts = createConflicts({ act: decide, nodeOf: conflictNode, restorable, copyBlock: (node) => clipboard.copyBlocks([node]), say });
434
454
  editing = true;
435
455
  document.documentElement.setAttribute("data-ge-editing", "");
456
+ typing.untitled(); // an empty title says 未命名文档 from the start
457
+ blocks?.folds.start(); // what was folded, folded again in this task: no frame shows it open (fold/)
436
458
  refresh();
437
459
  for (const page of pageObjects()) page.entered?.();
438
460
  }
439
461
 
440
462
  // What the page says when what a component wrote went by a manifest that changed: given up, the page shown again.
441
- const outdatedNotice = () => t("组件包刚刚变了,这次改动没有保存,页面已按新的组件重新显示。");
463
+ const outdatedNotice = () => t("自定义块刚刚变了,这次改动没有保存,页面已按新的块重新显示。");
442
464
 
443
465
  // What 仍然调整 wrote over someone else's change of what a component writes, by page unit: the step that
444
466
  // gives theirs back (installed/ overwrite), and when its write went in, all of it (commit.mjs `forced`).
@@ -453,8 +475,10 @@ const keepsOverwrite = (asked) => !asked && [...overwrites.values()].some(({ lan
453
475
 
454
476
  // A commit was taken in (commit.mjs): a block merged with someone else's words shows the merge;
455
477
  // what the file refused is flagged and held back, the rest goes on.
456
- function committed({ conflicts: held, merged, outdated, forced = [] }, receipt) {
478
+ function committed({ conflicts: held, merged, outdated, forced = [], rekeyed = [] }, receipt) {
479
+ agentChanges?.committed(receipt);
457
480
  for (const host of merged) history.merged(host);
481
+ history.rekeyed(rekeyed); // the keys of tables the file gave otherwise, in the steps that recorded them
458
482
  for (const unit of forced) {
459
483
  const written = overwrites.get(unit);
460
484
  if (!written || written.landed > 0) continue;
@@ -472,7 +496,7 @@ function committed({ conflicts: held, merged, outdated, forced = [] }, receipt)
472
496
  conflicts.add(held);
473
497
  const conflicted = held.filter((entry) => !unfit(entry) && !packageChanged(entry)).length;
474
498
  const packaged = held.filter(packageChanged).length;
475
- say(conflicted > 0 ? t("{0} 处修改和文件的最新版本冲突,没有保存:在左下方选择怎么处理。", conflicted) : packaged > 0 ? t("组件包刚刚变了,{0} 处修改没有保存:在左下方选择怎么处理。", packaged) : t("{0} 处内容文档存不下,没有保存:在左下方选择怎么处理。", held.length), "error");
499
+ say(conflicted > 0 ? t("{0} 处修改和文件的最新版本冲突,没有保存:在左下方选择怎么处理。", conflicted) : packaged > 0 ? t("自定义块刚刚变了,{0} 处修改没有保存:在左下方选择怎么处理。", packaged) : t("{0} 处内容文档存不下,没有保存:在左下方选择怎么处理。", held.length), "error");
476
500
  }
477
501
  else if (outdated || merged.length > 0 || receipt.texts?.some((entry) => entry.status === "merged")) {
478
502
  const count = receipt.texts.filter((entry) => entry.status === "merged").length;
@@ -599,6 +623,7 @@ function markChanged(now = false) {
599
623
  conflicts?.reflag();
600
624
  }
601
625
  if (messageKind() === "error") settle(); // the reader is dealing with it
626
+ typing.untitled(); // a title emptied (or filled) by any change says 未命名文档 (or nothing) at once
602
627
  lastChange = Date.now();
603
628
  discrete ||= now;
604
629
  const counting = checkPending;
@@ -678,7 +703,10 @@ function afterConvert(focus, type, said) {
678
703
  * heading) and the new block turns into the type; below any other block, an empty paragraph of its
679
704
  * box does (the first box out that takes one). One undo step.
680
705
  */
681
- function insertBelow(target, type, typed = null) {
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) {
682
710
  const splits = isHost(target) && can(target, "split");
683
711
  let after = target;
684
712
  while (!splits && after && !accepts(after.parentElement?.getAttribute("data-ge-box-kind"), "paragraph")) after = after.parentElement?.closest(OUTER);
@@ -696,10 +724,12 @@ function insertBelow(target, type, typed = null) {
696
724
  after.after(fresh);
697
725
  }
698
726
  if (!fresh) return null;
727
+ const prior = fresh.previousSibling; // what the new block stands right after, made where the paragraph was
699
728
  const turned = type === "paragraph" && fresh.localName === "p" ? { focus: null, created: [] } : convertBlock(fresh, type, { fresh: true });
729
+ also?.done?.(fresh.isConnected ? fresh : prior?.nextElementSibling ?? null);
700
730
  const focus = turned.focus ?? fresh;
701
731
  return { touched: splits ? [target, focus] : [focus], focus, created: turned.created };
702
- });
732
+ }, { attributes: also?.attributes ?? [] });
703
733
  if (result) afterConvert(result.focus, type, t("已插入{0}", menuRow(type).label));
704
734
  }
705
735
 
@@ -757,7 +787,7 @@ function convertUnit(unit, type, { loaded = false } = {}) {
757
787
  if (!made || !onCreated(type, result.focus)) {
758
788
  if (emptied && isHost(result.focus)) caretAt(result.focus, "start");
759
789
  else {
760
- // What it is now: the new highlight block a block went into, as a disclosure (notion-lite's
790
+ // What it is now: the new highlight block or callout a block went into, as a disclosure (notion-lite's
761
791
  // transformBlocks selects the callout), the flowchart a block or a list went into (a container
762
792
  // of a type that takes a block as it is, no `wraps`), else the block holding the text.
763
793
  const { container, wraps } = BLOCK_TYPES[type];
@@ -946,6 +976,18 @@ function onBeforeInput(event) {
946
976
  } else if (type === "insertLineBreak" && can(host, "plain")) {
947
977
  event.preventDefault();
948
978
  say(limitText(host, "split"));
979
+ } else if (/^delete[A-Za-z]+(Backward|Forward)$/.test(type) && !event.isComposing && textFilters(host)) {
980
+ // Backspace or Delete beside a component's entry whose keydown onKeydown passed by (an input
981
+ // method's, keyCode 229): the whole entry, as there (typing/code-edges.mjs takeEntry). A
982
+ // deletion backward the browser does: the caret kept outside inline code it comes to (deletedBack).
983
+ const back = type.endsWith("Backward");
984
+ const before = type === "deleteContentBackward" || type === "deleteContentForward" ? ownHTML(host) : null;
985
+ const removed = before !== null ? takeEntry(host, back) : undefined;
986
+ if (removed) {
987
+ event.preventDefault();
988
+ recordStep(host, before);
989
+ say(removed);
990
+ } else if (back) deletingBack(host);
949
991
  } else if (type.startsWith("format")) {
950
992
  event.preventDefault(); // formatting goes through format-bar/: the kit's markup only
951
993
  } else if (type === "insertFromDrop" || type === "deleteByDrag") {
@@ -974,6 +1016,7 @@ function onInput(event) {
974
1016
  }
975
1017
  // What stood between two pieces of inline code deleted: they are one (marks.mjs joinCode).
976
1018
  if (event.inputType.startsWith("delete") && textFilters(host)) joinCode(host);
1019
+ if (event.inputType.startsWith("delete") && event.inputType.endsWith("Backward") && textFilters(host)) deletedBack(host);
977
1020
  pageOf(host)?.typed?.(host);
978
1021
  recordText(host);
979
1022
  markdown.typed(host, event.data);
@@ -1012,6 +1055,7 @@ function onPointerDown(event) {
1012
1055
  hideHint();
1013
1056
  endArrowRun();
1014
1057
  if (event.button === 0) pressing = true;
1058
+ pressedText = event.button === 0 && editing ? editable(event.target) : null;
1015
1059
  // What the press came down on may take it, by its component's `press`: code opens for editing, a
1016
1060
  // display formula goes into the formula editor, and no caret goes in.
1017
1061
  if (editing && event.button === 0 && pageAt(event.target)?.press?.(event)) return;
@@ -1033,6 +1077,9 @@ function onSelectionChange() {
1033
1077
  formatting.schedule();
1034
1078
  if (!composing) formatting.moved();
1035
1079
  const selection = getSelection();
1080
+ // The caret, or an end of a text selection, in what a folded heading hides (undo put it back there):
1081
+ // the fold opens (fold/).
1082
+ for (const end of [selection.anchorNode, selection.focusNode]) if (end && hiddenByFold(end)) blocks?.folds.showAround(end);
1036
1083
  const host = selection.rangeCount ? editable(selection.anchorNode) : null;
1037
1084
  // A text block no step named, one a block made on the page came with: what the caret finds there is
1038
1085
  // what the first change of it undoes to, as a change is only seen once made.
@@ -1130,7 +1177,8 @@ async function newSubpage(title) {
1130
1177
  }
1131
1178
 
1132
1179
  // The report's title as the reader sees it now (while editing, the title block's text).
1133
- const currentTitle = () => (document.querySelector('[data-ge-kind="title"]') ?? document.querySelector("h1.doc-title, .doc-header h1"))?.textContent.replace(/\s+/g, " ").trim() ?? "";
1180
+ const titleNode = () => document.querySelector('[data-ge-kind="title"]') ?? document.querySelector("h1.doc-title, .doc-header h1");
1181
+ const currentTitle = () => titleNode()?.textContent.replace(/\s+/g, " ").trim() ?? "";
1134
1182
 
1135
1183
  // This page, as the list of pages takes it (links/pages.mjs).
1136
1184
  const thisPage = () => ({ slug: MAP.slug, title: currentTitle() });
@@ -1173,7 +1221,10 @@ const COMMANDS = {
1173
1221
  },
1174
1222
  // 搜索文档 opened the report at a hit: its words scrolled into view and marked for a moment (find/).
1175
1223
  async reveal(message) {
1176
- return revealText(message, (node) => modalOps().show(node));
1224
+ return revealText(message, (node) => {
1225
+ blocks?.folds.showAround(node); // a folded heading's section opened (fold/)
1226
+ return modalOps().show(node);
1227
+ });
1177
1228
  },
1178
1229
  // A link or an address opened the report at a block.
1179
1230
  async "reveal-block"({ block }) {
@@ -1222,11 +1273,12 @@ const COMMANDS = {
1222
1273
  // ---------- links to blocks and documents ----------
1223
1274
 
1224
1275
  // The block of this id, once the page is drawn (what its charts move is moved by then), or an element
1225
- // of this id (an address may name a heading's): what hides it opened (the kit's DocKit.reveal: a
1226
- // detail card that does not hold it closed, a disclosure, a tab, the card it is in), in the middle of
1227
- // the window and selected, as notion-lite's revealBlock, and the keys are the page's. What was just
1228
- // shown lays itself out in the frames after (a tab's tables) and a card closed gives the focus back
1229
- // then, so it is brought there again before it is selected. A block that is gone is said, unless
1276
+ // of this id (an address may name a heading's): what hides it opened (a folded heading's section,
1277
+ // folded.mjs reveal, then the kit's DocKit.reveal: a detail card that does not hold it closed, a
1278
+ // disclosure, a tab, the card it is in), in the middle of the window and selected, as notion-lite's
1279
+ // revealBlock, and the keys are the page's. What was just shown lays itself out in the frames after (a
1280
+ // tab's tables) and a card closed gives the focus back then, so it is brought there again before it is
1281
+ // selected. A block that is gone is said, unless
1230
1282
  // `quiet`, the page staying as it is; #top with no such element is the top of the page, as for a browser.
1231
1283
  // A later step (a link, the way back or forth, an address) started past its waits leaves it there.
1232
1284
  async function revealBlock(id, { quiet = false } = {}) {
@@ -1239,7 +1291,7 @@ async function revealBlock(id, { quiet = false } = {}) {
1239
1291
  else if (!quiet) say(t("这个块已经不在了。"));
1240
1292
  return { ok: false, reason: "missing" };
1241
1293
  }
1242
- globalThis.DocKit.reveal(block);
1294
+ reveal(block); // a fold over it too (fold/)
1243
1295
  block.scrollIntoView({ block: "center" });
1244
1296
  await painted();
1245
1297
  await painted();
@@ -1418,7 +1470,22 @@ function handOff() {
1418
1470
  // The workbench around the page, if any: it hears the page's state and notices, and asks it to save,
1419
1471
  // close and show the report again.
1420
1472
  function connect() {
1421
- workbench = connectWorkbench({ slug: MAP.slug, snapshot: () => ({ title: currentTitle(), icon: pageIcon(), state: sessionState(), annotations: annotate?.count() }), commands: COMMANDS, modals: modalOps() });
1473
+ // The look the page shows (字体与布局: its <html>'s, src/shared/document-look.mjs), which the workbench's
1474
+ // 更多 marks as chosen; told again when it changes (the kit's ui.js, doc-look-change).
1475
+ // `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() });
1477
+ addEventListener("doc-look-change", () => workbench?.update());
1478
+ // A block's context.workspace.open (the kit's runtime/workspace.js): a document, or a block of one, goes
1479
+ // where a link to it goes (goTo: in the workbench, its address; on its own, the page once saved); a custom
1480
+ // page, the workbench's #@<slug>, or /pages/<slug> once saved.
1481
+ addEventListener("doc-open-request", (event) => {
1482
+ const { slug = null, block = null, page = null } = event.detail ?? {};
1483
+ event.preventDefault();
1484
+ if (page) {
1485
+ if (window.parent !== window && !SOLO) workbench?.open({ hash: `@${page}` });
1486
+ else COMMANDS["prepare-close"]().then(() => location.assign(`/pages/${page}`));
1487
+ } else goTo({ slug, block }, `/generated/${slug}.html${block ? `#${encodeURIComponent(block)}` : ""}`);
1488
+ });
1422
1489
  relayTo(workbench ? workbench.notice : null, workbench ? workbench.noticeRoom : null); // the workbench shows the page's notices, above the page's bottom panels
1423
1490
  handOff();
1424
1491
  // A page on its own in a frame (?solo: the 写作偏好 dialog's, which no session asks to save) is saved
@@ -1471,11 +1538,16 @@ async function start() {
1471
1538
  else if (typeof state.docBlock === "string") revealBlock(state.docBlock, { quiet: true });
1472
1539
  });
1473
1540
  annotate?.start();
1541
+ agentChanges?.start();
1474
1542
  const open = await openTabs();
1475
1543
  if (open.has(TAB)) { // a duplicated tab: its own id from now on
1476
1544
  TAB = newTab();
1477
1545
  session.set(keys.tab, TAB);
1478
1546
  }
1547
+ // What earlier pages of the document committed, made and wrote (this tab's, and those of tabs no longer
1548
+ // open), asked of at once where this page opened on another version of the file than they last knew
1549
+ // (its cards and list said through the workbench).
1550
+ autosave?.opened(open);
1479
1551
  const prefix = pendingKey(MAP.slug, "");
1480
1552
  const left = local.keys().filter((key) => key.startsWith(prefix) && key !== pendingKey(MAP.slug, TAB) && !open.has(key.slice(prefix.length)));
1481
1553
  if (left.length === 0) return;
@@ -1535,7 +1607,7 @@ function showLost() {
1535
1607
  if (block) {
1536
1608
  panelItem(
1537
1609
  element("p", { text: t("文件里的这一块已被修改:复制你的版本,再粘贴到页面上。") }),
1538
- element("div", { class: "ge-actions" }, button(t("复制这一块"), () => { if (!clipboard.copyBlocks([block])) say(t("没能完成,请再试一次。"), "error"); })),
1610
+ element("div", { class: "ge-actions" }, textButton(t("复制这一块"), () => { if (!clipboard.copyBlocks([block])) say(t("没能完成,请再试一次。"), "error"); })),
1539
1611
  );
1540
1612
  continue;
1541
1613
  }
@@ -1543,10 +1615,10 @@ function showLost() {
1543
1615
  panelItem(
1544
1616
  element("p", { text: LOST[item.why] ?? LOST.refused }),
1545
1617
  element("div", { class: "ge-version", text }),
1546
- element("div", { class: "ge-actions" }, button(t("复制文字"), () => navigator.clipboard?.writeText(text).then(() => say(t("已复制。"))))),
1618
+ element("div", { class: "ge-actions" }, textButton(t("复制文字"), () => navigator.clipboard?.writeText(text).then(() => say(t("已复制。"))))),
1547
1619
  );
1548
1620
  }
1549
- panelItem(element("div", { class: "ge-actions" }, button(t("都处理好了,不再保留"), () => {
1621
+ panelItem(element("div", { class: "ge-actions" }, textButton(t("都处理好了,不再保留"), () => {
1550
1622
  local.remove(lostKey(MAP.slug));
1551
1623
  closePanel();
1552
1624
  }, { primary: true })));
@@ -1569,7 +1641,7 @@ function boot() {
1569
1641
  atMenu = createAtMenu({ composing: () => composing, page: thisPage, recordText, recordStep });
1570
1642
  markdown = createMarkdown({ slash, at: atMenu, convert: convertHost, recordStep });
1571
1643
  blocks = createBlocks({
1572
- units, boxes, active, struct, look: lookStep, say, edit: editBlock, turnInto, convert: convertUnit, turnIntoAll: groupTargets, convertAll, add: insert.addAfter, after: insert.paragraphAfter,
1644
+ slug: MAP.slug, units, boxes, active, struct, look: lookStep, say, edit: editBlock, turnInto, convert: convertUnit, turnIntoAll: groupTargets, convertAll, add: insert.addAfter, after: insert.paragraphAfter,
1573
1645
  below: insertBelow, belowTypes: belowTargets,
1574
1646
  blank: insert.clickBlank, nest: (units, delta) => pageObjects().some((page) => page.nestBlocks?.(units, delta)),
1575
1647
  keepsHandle: (node) => tables?.holds(node) ?? false,
@@ -1579,10 +1651,13 @@ function boot() {
1579
1651
  copyLink: SOLO ? null : copyBlockLink, // what ?solo shows (写作偏好) only its dialog opens: no address leads there
1580
1652
  linkAhead: () => holdPages(thisPage),
1581
1653
  });
1582
- resize = createResize({ units, active, look: lookStep, say, owns: (node) => tables?.owns(node) ?? false });
1583
- gaps = createColumnGaps({ active, struct, look: lookStep, say });
1654
+ resize = createResize({ units, active, look: lookStep, say, settle, owns: (node) => tables?.owns(node) ?? false });
1655
+ gaps = createColumnGaps({ active, struct, look: lookStep, say, settle });
1584
1656
  for (const page of pageObjects()) page.install?.(); // the round "+" at a flowchart node's right, renaming Sheet tabs
1585
- tables = createTableEditing({ active, struct, look: lookStep, selectBlock: (unit) => blocks.select(unit), resizeTable: (event, unit, axis) => resize.startTable(event, unit, axis), say, ownCells: (data) => clipboard.ownCells(data), typedKey });
1657
+ 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),
1660
+ });
1586
1661
  selectAll = createSelectAll({ blocks, say, cells: { table: () => tables.selectedTable, clear: () => tables.clear() } });
1587
1662
  createFrame(() => editing);
1588
1663
  createFlags(() => editing);
@@ -1605,14 +1680,30 @@ function boot() {
1605
1680
  changed: () => workbench?.update(),
1606
1681
  removed: (items) => workbench?.annotationsRemoved(items),
1607
1682
  });
1683
+ // Read at once, drawn once the page is ready; commits and autosave are made as the page edits (enter).
1684
+ if (!SOLO) agentChanges = createAgentChanges({
1685
+ slug: MAP.slug, token: MAP.token, commits: () => commits, autosave: () => autosave, say, session,
1686
+ across: crossText, // a selection across blocks, kept on its words as the marks go and come
1687
+ flush: async () => {
1688
+ checkAll();
1689
+ return (await autosave?.flush()) ?? "nothing";
1690
+ },
1691
+ });
1608
1692
  document.addEventListener("pointerup", (event) => {
1609
1693
  pressing = false;
1610
1694
  formatting.released();
1611
- // A click at an edge of inline code: the caret on the side it was made on.
1695
+ // A click at an edge of inline code or an entry: the caret on the side it was made on, when the
1696
+ // press came down on that text; a press elsewhere that put the caret there (a card's backdrop,
1697
+ // which closed it and put the caret at its entry; the page's empty space) leaves it at the stop
1698
+ // it is at.
1612
1699
  const selection = getSelection();
1613
1700
  const host = editing && event.button === 0 && selection.rangeCount && selection.isCollapsed ? editable(selection.anchorNode) : null;
1701
+ const pressed = pressedText;
1702
+ pressedText = null;
1614
1703
  if (host && outOfAtom(event.clientX)) return; // a click beside a formula that put the caret in it
1615
- if (host && textFilters(host)) codeClick(host, event.clientX);
1704
+ if (!host || !textFilters(host)) return;
1705
+ if (pressed && (pressed === host || pressed.contains(host))) codeClick(host, event.clientX);
1706
+ else settleCodeEdge(host);
1616
1707
  }, true);
1617
1708
  document.addEventListener("focusin", passTab, true);
1618
1709
  document.addEventListener("compositionstart", (event) => {
@@ -1711,6 +1802,7 @@ function boot() {
1711
1802
  checkAll();
1712
1803
  autosave?.leave();
1713
1804
  annotate?.leave();
1805
+ agentChanges?.leave();
1714
1806
  });
1715
1807
  document.addEventListener("visibilitychange", () => {
1716
1808
  if (!document.hidden || !autosave) return;
@@ -1,19 +1,24 @@
1
- // Taken over from notion-lite (its src/ui/media-picker/emoji-tab.js), as it is: only what it imports is
2
- // Gallery's own (support.mjs, src/shared/emoji/). Its notes, below, are notion-lite's.
1
+ // Taken over from notion-lite (its src/ui/media-picker/emoji-tab.js): its structure and behaviour as
2
+ // there, what it imports Gallery's own (support.mjs, src/shared/emoji/), and since 2026-11 (the user's
3
+ // word) its look Gallery's own (styles.mjs: the editor's palette, no blue), no 旗帜 group (the data holds
4
+ // no flag: src/shared/emoji/data/README.md), every emoji a Twemoji picture on every system, the skin
5
+ // button's hand too (the system's font only for one the pack lacks), and a group's title sticking to
6
+ // the list's top. Its notes, below, are notion-lite's, those changes written in.
3
7
  /* “表情符号”页签(943244 EmojiPicker、885963 选肤色、625478 格子和肤色变体;尺寸是线上实测)。
4
- * 分组:最近(筛选词为空时)、标注(从标注打开时,固定 26 个)、人物、动物与自然、食物与饮料、活动、旅行与地点、物品、符号、旗帜、
8
+ * 分组:最近(筛选词为空时)、标注(从标注打开时,固定 26 个)、人物、动物与自然、食物与饮料、活动、旅行与地点、物品、符号(没有旗帜:Gallery 整组去掉)、
5
9
  * 自定义(本机的自定义表情,按名字排;第一个格子是“添加表情符号”的圆形加号)
6
- * 每行 (408 − 24) / 32 = 12 个;标题 12px / 500、上 6+6 下 8;格子 32×32、圆角 4、表情 24(../emoji/emoji.js)
10
+ * 每行 (408 − 24) / 32 = 12 个;标题 12px / 500、高 28,滚动时钉在列表顶上;格子 32×32、圆角 6、表情 24(Twemoji 图,../emoji/emoji.js)
7
11
  * 筛选(943244 W):按关键词打分——筛选词里有这个表情 > “:筛选词” > 关键词等于 > 关键词开头 > 多个词都对上 > 包含,常用的加分;
8
12
  * 自定义表情的关键词是它的名字(871871 g)。结果(连同加号)超过 12 × 12 / 2 = 72 个时仍按分组显示,否则拍平成一组按分数排
9
13
  * (加号排最后);只剩加号时显示“无结果”和“添加表情符号”按钮
10
- * 底部分类栏(943244 y):上边一条 --c-borSec,内边距 8 12 10;按钮 32×32、图标 22;当前滚到的分组按钮有底色;
11
- * 没有表情的分组按钮半透明不可点(“自定义”“添加”总能点);悬停提示分组名(左对齐、在下方);点了把那一组滚到顶上,
14
+ * 底部分类栏(943244 y):上边一条 --ge-line,内边距 6 12 8;按钮 28×28、图标 18;当前滚到的分组按钮有底色;
15
+ * 没有表情的分组按钮半透明不可点(“自定义”“添加”总能点);悬停提示分组名(左对齐、在下方);点了把那一组(连同组名)滚到顶上,
12
16
  * “添加”打开“添加表情符号”浮层。筛选结果拍平时不显示
13
- * 最近(943244 F):常用表情按次数、时间排,取 2 行;选中一个表情记一次(../emoji/data.js recordEmojiUse)
17
+ * 最近(943244 F):常用表情按次数、时间排,取 2 行,只取数据还认得的和自定义表情(以前用过的旗不再出现);打开时读一次;
18
+ * 选中一个表情记一次(../emoji/data.js recordEmojiUse)
14
19
  * 格子(625478):没设过肤色时点有肤色变体的表情,先弹出一排变体(选了正好 5 个变体的就记下肤色);
15
20
  * 自定义表情(758388)24×24、contain,提示是它的名字
16
- * 右边按钮(885963):选肤色,28×28、字号 20 的“✋”(设过就是那个肤色的手),点开一排六只手
21
+ * 右边按钮(885963):选肤色,28×28、18 的“✋”(Twemoji 图,设过就是那个肤色的手;数据到了再画),点开一排六只手
17
22
  * 随机(859941):活动 / 物品 / 旅行与地点里随便一个,选上但不关菜单
18
23
  * 添加表情符号(943244 Y → 757573 → 749527 tM):在加号 / 底栏按钮 / 无结果按钮下面打开 ./upload.js 的浮层;
19
24
  * 存好以后交给 env.uploaded(选上这个表情、关菜单)
@@ -52,7 +57,6 @@ const CATEGORIES = [
52
57
  { id: 'travel', category: 'Travel & Places', title: t("旅行与地点"), icon: 'airplane' },
53
58
  { id: 'objects', category: 'Objects', title: t("物品"), icon: 'lightBulbBright' },
54
59
  { id: 'symbols', category: 'Symbols', title: t("符号"), icon: 'checkmarkCircle' },
55
- { id: 'flags', category: 'Flags', title: t("旗帜"), icon: 'flag' },
56
60
  { id: 'custom', title: t("自定义"), icon: 'squareGrid2X2' },
57
61
  { id: 'add', title: ADD_LABEL, icon: 'plusCircle' },
58
62
  ];
@@ -89,7 +93,7 @@ function rank(emoji, filter, splitFilter) {
89
93
 
90
94
  /* 943244 W:分好组、切成一行行。返回 { categorized, rows: [{ id, title?, emojis }] };只剩加号时 rows 是 [{ emojis: [ADD] }] */
91
95
  function buildRows(rawFilter, isCallout, recent) {
92
- const cats = [!rawFilter.trim() ? CATEGORY.recent : null, isCallout ? CATEGORY.callout : null, ...CATEGORIES.slice(2, 10), CATEGORY.custom].filter(Boolean);
96
+ const cats = [!rawFilter.trim() ? CATEGORY.recent : null, isCallout ? CATEGORY.callout : null, ...CATEGORIES.filter(c => c.category), CATEGORY.custom].filter(Boolean);
93
97
  const filter = normalizeFilter(rawFilter) ?? '';
94
98
  const split = rawFilter.split(' ').filter(Boolean);
95
99
  const rows = [];
@@ -152,7 +156,7 @@ export function createEmojiTab(env) {
152
156
  el.className = 'nmm-body';
153
157
  el.innerHTML = `<div class="nmm-scroller notion-scroller vertical"><div role="grid" class="nmm-grid"></div></div><div class="nmm-categories"></div>`;
154
158
  const grid = el.querySelector('.nmm-grid'), scroller = el.querySelector('.nmm-scroller'), bar = el.querySelector('.nmm-categories');
155
- const recent = recentEmojis(PER_ROW);
159
+ let recent = null; // read once, when the data is in (render; Notion's: not reordered while open)
156
160
  let view = { categorized: true, rows: [] }, lastFilter = '', addPopup = null;
157
161
  const focus = createGridFocus({ scroller, grid, rows: () => view.rows.map(r => r.emojis.length) });
158
162
 
@@ -174,6 +178,10 @@ export function createEmojiTab(env) {
174
178
  function render(filter) {
175
179
  lastFilter = filter;
176
180
  if (!emojiDataLoaded()) { grid.innerHTML = ''; bar.hidden = true; view = { categorized: true, rows: [] }; return; } // 数据加载完再画
181
+ if (recent === null) { // 数据到了:最近(只要还认得的,去掉的旗不再出现)读一次,选肤色的手画成 Twemoji 图
182
+ recent = recentEmojis(PER_ROW, e => isCustomEmojiString(e) || Boolean(emojiInfo(e)));
183
+ paintSkin();
184
+ }
177
185
  view = buildRows(filter, env.isCallout, recent);
178
186
  const { rows } = view;
179
187
  let html = '';
@@ -205,7 +213,7 @@ export function createEmojiTab(env) {
205
213
  const present = new Set(view.rows.map(r => r.id));
206
214
  const enabled = c => c.id === 'custom' || c.id === 'add' || present.has(c.id);
207
215
  bar.innerHTML = CATEGORIES.filter(c => c.id !== 'callout').map(c =>
208
- `<div role="button" tabindex="-1" class="nmm-category${enabled(c) ? '' : ' disabled'}" data-category="${c.id}" aria-label="${t("跳转到类别:{0}", esc(c.category ?? c.id))}" aria-pressed="false"${enabled(c) ? '' : ' aria-disabled="true"'}>${icon(c.icon, 22)}</div>`).join('');
216
+ `<div role="button" tabindex="-1" class="nmm-category${enabled(c) ? '' : ' disabled'}" data-category="${c.id}" aria-label="${t("跳转到类别:{0}", esc(c.category ?? c.id))}" aria-pressed="false"${enabled(c) ? '' : ' aria-disabled="true"'}>${icon(c.icon, 18)}</div>`).join('');
209
217
  for (const b of bar.children) hoverTooltip(b, CATEGORY[b.dataset.category].title, { placement: 'bottom', align: 'start' });
210
218
  updateBarFocus();
211
219
  }
@@ -258,7 +266,8 @@ export function createEmojiTab(env) {
258
266
  right.className = 'nmm-skin-wrap';
259
267
  right.innerHTML = `<div role="button" tabindex="0" class="nmm-skin" data-act="skin"></div>`;
260
268
  const skinBtn = right.firstElementChild;
261
- const paintSkin = () => { const tone = getSkinTone(); skinBtn.textContent = tone !== undefined ? SKIN_TONE_HANDS[tone] : '✋'; };
269
+ // The hand as a Twemoji picture (a placeholder of its size until the data is in: render paints it again then).
270
+ function paintSkin() { skinBtn.innerHTML = emojiHTML(SKIN_TONE_HANDS[getSkinTone() ?? 0], { size: 18 }); }
262
271
  paintSkin();
263
272
  hoverTooltip(skinBtn, t("选择肤色"), { placement: 'bottom' });
264
273
  skinBtn.addEventListener('click', () => {
@@ -1,7 +1,8 @@
1
- // Taken over from notion-lite (its src/ui/media-picker/grid.js), as it is: only what it imports is
2
- // Gallery's own (support.mjs, src/shared/emoji/). Its notes, below, are notion-lite's.
1
+ // Taken over from notion-lite (its src/ui/media-picker/grid.js): what it imports is Gallery's own
2
+ // (support.mjs, src/shared/emoji/), its look too (styles.mjs: a deeper gray, no blue ring), and a cell the
3
+ // keys reach stays below a group's title stuck at the list's top. Its notes, below, are notion-lite's.
3
4
  /* 表情 / 图标格子共用的焦点(558045 Grid + 625478 / 485357 H 的提示):
4
- * 鼠标悬停和方向键共用一个焦点(有底色);方向键不绕回,上下按列对齐(短的一行取最后一个);键盘移动时焦点格有蓝色焦点环、
5
+ * 鼠标悬停和方向键共用一个焦点(有底色);方向键不绕回,上下按列对齐(短的一行取最后一个);键盘移动时焦点格是更深的灰底、
5
6
  * 滚进视野,并且一直显示名字(forceVisibleState);鼠标悬停 150ms 后在下方显示名字(closeDelay 0)。
6
7
  * 懒加载:格子里 img[data-src] / img[data-svg](表情包里的码点)滚到附近才换成 src(../emoji/emoji.js lazySrc;矢量表情一千多张,一次全做太慢)。
7
8
  * 格子是 .nmm-cell[data-r][data-c],提示文字在 data-tip(没有就用 aria-label)。
@@ -25,8 +26,9 @@ export function createGridFocus({ scroller, grid, rows }) {
25
26
  cell.classList.add('focused');
26
27
  if (!byKeyboard) return;
27
28
  cell.classList.add('focus-visible');
28
- const cr = cell.getBoundingClientRect(), sr = scroller.getBoundingClientRect();
29
- if (cr.top < sr.top) scroller.scrollTop -= sr.top - cr.top;
29
+ const cover = grid.querySelector('.nmm-section-title')?.offsetHeight ?? 0; // a group's title stays at the top (styles.mjs: sticky); a flat search has none
30
+ const cr = cell.getBoundingClientRect(), sr = scroller.getBoundingClientRect(), top = sr.top + cover;
31
+ if (cr.top < top) scroller.scrollTop -= top - cr.top;
30
32
  else if (cr.bottom > sr.bottom) scroller.scrollTop += cr.bottom - sr.bottom;
31
33
  if (tipOf(cell)) showTooltip(cell.getBoundingClientRect(), tipOf(cell), { placement: 'bottom' });
32
34
  }
@@ -1,4 +1,4 @@
1
- // The 图标 tab (notion-lite's src/ui/media-picker/icon-tab.js, its grid, colors and sizes as there),
1
+ // The 图标 tab (notion-lite's src/ui/media-picker/icon-tab.js, its grid and behaviour as there, its look Gallery's own: styles.mjs),
2
2
  // its icons Gallery's own: two open-source sets of the same 443 things, MingCute and Tabler, and
3
3
  // Tabler's 40 numbers, in 12 categories (src/shared/emoji/glyphs.mjs). Its notes, below, are
4
4
  // notion-lite's, the icons' own changed.
@@ -13,8 +13,8 @@
13
13
  * 数字只有 Tabler 有:切换时不动,选中的也总是 Tabler 的值(提示里写明 Tabler)
14
14
  * 颜色(icon_picker_color):设了就直接用这个颜色插入、格子也显示这个颜色;没设(“每次询问”)时格子显示默认灰色,
15
15
  * 点一下先弹出 10 种颜色(两行各 5 个、行内边距 2、间距 1,贴在格子下面)再选
16
- * 右边按钮(q):选图标颜色——28×28 带边框,圆圈图标描边 / 填充是当前颜色(没设时描边浅灰、填充 --c-icoTer);
17
- * 菜单 134 宽:两行色块(22×22、圆角 6,没设颜色时这两行半透明)+ 分隔线下“每次询问”开关
16
+ * 右边按钮(q):选图标颜色——28×28 无框,圆圈图标描边 / 填充是当前颜色(没设时描边浅灰、填充 --ge-ico3);
17
+ * 菜单 160 宽:两行色块(26×26、圆角 6,没设颜色时这两行半透明)+ 分隔线下“每次询问”开关(开是中性灰,不用蓝)
18
18
  * 随机:随便一组里这一套的图标,颜色用设好的,没设就随便一种;选上但不关菜单
19
19
  * 选中一个图标:记进最近(按组记,两套共用),值是 `/icons/<名字>_<颜色>.svg`(MingCute)或 `/icons/tabler/<名字>_<颜色>.svg`(数字总是这个)。
20
20
  * createIconTab(env) → { el, left, right, load(), render(filter), move(key), activateFocused(), random() }
@@ -178,7 +178,7 @@ export function createIconTab(env) {
178
178
  function paintColor() {
179
179
  const color = getIconColor(), values = ICON_COLOR_BY_THEME[theme()];
180
180
  colorBtn.setAttribute('aria-label', t("选择图标颜色,已选定 {0}", color ? colorWord(color) : t("无颜色")));
181
- colorBtn.innerHTML = `<svg viewBox="0 0 16 16" aria-hidden="true" style="width:14px;height:14px;display:block;stroke:${color ? values[color] : values.lightgray};fill:${color ? values[color] : 'var(--c-icoTer)'}">${CIRCLE_16}</svg>`;
181
+ colorBtn.innerHTML = `<svg viewBox="0 0 16 16" aria-hidden="true" style="width:14px;height:14px;display:block;stroke:${color ? values[color] : values.lightgray};fill:${color ? values[color] : 'var(--ge-ico3)'}">${CIRCLE_16}</svg>`;
182
182
  }
183
183
  paintColor();
184
184
  hoverTooltip(colorBtn, t("选择图标颜色"), { placement: 'bottom' });
@@ -13,7 +13,6 @@ const ICONS = {
13
13
  airplane: svg('<path d="M17.25 10c0-.9-.8-1.5-1.7-1.5H11L7.5 3.5H5.75l1.75 5H4.25L3 7H2l.75 3L2 13h1l1.25-1.5H7.5l-1.75 5H7.5L11 11.5h4.55c.9 0 1.7-.6 1.7-1.5z"/>'),
14
14
  lightBulbBright: svg('<path d="M10 2.75a5 5 0 0 0-3 9c.6.5 1 1.2 1 2v.5h4v-.5c0-.8.4-1.5 1-2a5 5 0 0 0-3-9z"/><path d="M8.25 16.5h3.5"/>'),
15
15
  checkmarkCircle: svg('<circle cx="10" cy="10" r="7.25"/><path d="m6.75 10.25 2.4 2.4 4.1-4.9"/>'),
16
- flag: svg('<path d="M5.25 17V3.75"/><path d="M5.25 4.75c2.5-1.5 4.5 1.5 7 0 1-.6 2-.8 2.75-.7v6.5c-.75-.1-1.75.1-2.75.7-2.5 1.5-4.5-1.5-7 0"/>'),
17
16
  squareGrid2X2: svg('<rect x="3.5" y="3.5" width="5" height="5" rx="1.25"/><rect x="11.5" y="3.5" width="5" height="5" rx="1.25"/><rect x="3.5" y="11.5" width="5" height="5" rx="1.25"/><rect x="11.5" y="11.5" width="5" height="5" rx="1.25"/>'),
18
17
  plusCircle: svg('<circle cx="10" cy="10" r="7.25"/><path d="M10 6.75v6.5M6.75 10h6.5"/>'),
19
18
  xMarkCircle: svg('<circle cx="10" cy="10" r="7.25"/><path d="m7.75 7.75 4.5 4.5m0-4.5-4.5 4.5"/>'),