@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
@@ -0,0 +1,75 @@
1
+ import { TODO_EVENT, TODO_MOST, TODO_ROUTE } from "../../shared/workspace-query.mjs";
2
+ import { postAnswer } from "./post.mjs";
3
+
4
+ // To-dos of documents checked from this page (workspace.setTodo, the plan's 5.1; docs/editor.md "To-dos
5
+ // checked from another page"): the kit's ask (TODO_EVENT, cancelable on the window: { ask: { slug, ref,
6
+ // done }, answer(promise) }) taken by whoever holds the page's token (a custom page's board, a document's
7
+ // editor) and written by the workspace's service (POST TODO_ROUTE, one document a request: the edit
8
+ // service's setTodos, one commit of the reader's). The checks of one document wait in a line of their own:
9
+ // those asked while one write of it is out go together in the next (its items in the order asked, the
10
+ // last of an item winning), so that a reader ticking five boxes quickly makes two commits, not five.
11
+ // Each ask is answered { ok: true, changed, block } (`block` the item's id now, which the commit gives
12
+ // one that had none) or { ok: false, reason, message? }, never rejected.
13
+
14
+ /**
15
+ * `token`: the page map's. `done(ask, answer)`: an ask answered (the board keeps an undo step of one that
16
+ * changed its document). Returns { write(ask) (a promise of its answer), idle() (once every write asked so
17
+ * far is answered), listen() (takes the kit's asks; returns the function that stops it) }.
18
+ */
19
+ export function createTodoWrites({ token, done = () => {} }) {
20
+ const lines = new Map(); // slug -> { waiting: [{ ask, resolve }], out: Promise | null }
21
+
22
+ async function send(slug, line) {
23
+ const batch = line.waiting.splice(0, TODO_MOST);
24
+ const answer = await postAnswer(TODO_ROUTE, token, { slug, items: batch.map(({ ask }) => ({ ref: ask.ref, done: ask.done })) });
25
+ batch.forEach(({ ask, resolve }, index) => {
26
+ const result = answer?.ok ? answer.results?.[index] ?? { ok: false, reason: "failed" } : { ok: false, reason: answer?.reason === "offline" ? "offline" : answer?.reason ?? "failed", ...(typeof answer?.message === "string" ? { message: answer.message } : {}) };
27
+ try {
28
+ done(ask, result);
29
+ } finally {
30
+ resolve(result);
31
+ }
32
+ });
33
+ }
34
+
35
+ // The line of a document: written once nothing of it is out, what waits then going together.
36
+ function run(slug) {
37
+ const line = lines.get(slug);
38
+ if (line.out || line.waiting.length === 0) return;
39
+ // A microtask's wait, so that the asks of one gesture (a block checking several at once) go together.
40
+ line.out = Promise.resolve().then(() => send(slug, line)).catch(() => {}).finally(() => {
41
+ line.out = null;
42
+ if (line.waiting.length > 0) run(slug);
43
+ else lines.delete(slug);
44
+ });
45
+ }
46
+
47
+ function write(ask) {
48
+ return new Promise((resolve) => {
49
+ if (!lines.has(ask.slug)) lines.set(ask.slug, { waiting: [], out: null });
50
+ lines.get(ask.slug).waiting.push({ ask, resolve });
51
+ run(ask.slug);
52
+ });
53
+ }
54
+
55
+ return {
56
+ write,
57
+ async idle() {
58
+ for (;;) {
59
+ const out = [...lines.values()].map((line) => line.out).filter(Boolean);
60
+ if (out.length === 0) return;
61
+ await Promise.all(out);
62
+ }
63
+ },
64
+ listen() {
65
+ const take = (event) => {
66
+ const { ask, answer } = event.detail ?? {};
67
+ if (event.defaultPrevented || !ask || typeof answer !== "function") return;
68
+ event.preventDefault();
69
+ answer(write(ask));
70
+ };
71
+ addEventListener(TODO_EVENT, take);
72
+ return () => removeEventListener(TODO_EVENT, take);
73
+ },
74
+ };
75
+ }
@@ -22,7 +22,7 @@ const STYLE = `
22
22
  const DELAY = 150;
23
23
  const GAP = 6;
24
24
  const MAC = /Mac|iPhone|iPad/.test(globalThis.navigator?.platform ?? "");
25
- const KEYS = MAC ? { mod: "⌘", shift: "⇧", alt: "⌥" } : { mod: "Ctrl", shift: "⇧", alt: "Alt" };
25
+ const KEYS = MAC ? { mod: "⌘", shift: "⇧", alt: "⌥", enter: "↩" } : { mod: "Ctrl", shift: "⇧", alt: "Alt", enter: "Enter" };
26
26
  let shown = null; // { node, tip }
27
27
  let timer = 0;
28
28
 
@@ -6,8 +6,9 @@ import { t } from "../../shared/i18n/index.mjs";
6
6
 
7
7
  // The types a block can be turned into, as icons side by side (as Feishu's block menu), the block's
8
8
  // own type marked: the top of the block menu (block-menu/) and the format bar's "turn into"
9
- // (format-bar/). The buttons are the format bar's (32×28px, 4px apart, its blue for the current
10
- // one), so both read alike. Each icon names its type, and its Markdown shortcut, in a tooltip.
9
+ // (format-bar/). The buttons are the format bar's (32×28px, 4px apart; the current one marked as
10
+ // a pressed tool of the bar is, its icon's lines in the bar's blue, --ge-accent, and no fill of its
11
+ // own, so the pointer's gray fills it as any other), so both read alike. Each icon names its type, and its Markdown shortcut, in a tooltip.
11
12
  // A type that says `corner` has no cell of its own but the gray corner of that type's (a split
12
13
  // button): 小字's of 文本's, so 文本 and the headings fill one line. The corner shows only with the
13
14
  // pointer (or the keys) on the cell, or, blue, when the block is of that type. It is a click target
@@ -26,7 +27,7 @@ const STYLE = `
26
27
  .ge-type { display: flex; align-items: center; justify-content: center; width: ${CELL}px; height: 28px; padding: 0; border: 0; border-radius: 6px; background: transparent; color: var(--ge-ico); cursor: pointer; transition: background 20ms ease-in; }
27
28
  .ge-type:hover, .ge-type[data-active] { background: var(--ge-hover); }
28
29
  .ge-type:active { background: var(--ge-press); }
29
- .ge-type[aria-current="true"] { background: var(--ge-fill); color: var(--ge-accent); }
30
+ .ge-type[aria-current="true"] { color: var(--ge-accent); }
30
31
  .ge-type-pair { position: relative; border-radius: 6px; overflow: hidden; }
31
32
  .ge-type-corner { position: absolute; right: 0; bottom: 0; width: ${CORNER}px; height: ${CORNER}px; padding: 0; border: 0; background: transparent; cursor: pointer; }
32
33
  .ge-type-corner::before { content: ""; position: absolute; inset: 0; background: light-dark(rgb(55 53 47 / 12%), rgb(255 255 255 / 13%)); clip-path: path("${TRIANGLE}"); opacity: 0; transition: background 20ms ease-in, opacity 120ms ease-out; }
@@ -12,7 +12,11 @@ import { ENTRIES } from "../../components/registry.mjs";
12
12
  // the caret in a pad (pads.mjs). Code blocks are text blocks of their own (components/code/) and
13
13
  // have none of this. A component's entry in the text (`entry`: a chip as padded as code) has the
14
14
  // same stops, and Backspace at the stop after it (Delete at the one before it) takes the whole
15
- // entry away (beforeDelete says what the page says of that; editor.mjs records the step).
15
+ // entry away (takeEntry, on the key's keydown through beforeDelete and on its beforeinput where an
16
+ // input method's keydown says 229; it says what the page says of that, editor.mjs records the step).
17
+ // A Backspace that takes the last character between inline code or an entry and the caret after it
18
+ // leaves the caret outside it, at the stop after it (deletingBack, deletedBack): the browser puts it
19
+ // in at the end (an entry's: left of its icon), its end and the text after it one place to it.
16
20
 
17
21
  const EDGED = ["code", ...ENTRIES.map(({ at }) => at)].join(", ");
18
22
  const isEdged = (node) => node?.nodeType === 1 && node.matches(EDGED);
@@ -187,28 +191,48 @@ export function codePress(host, x, y) {
187
191
  }
188
192
 
189
193
  /**
190
- * Backspace or Delete with the caret in a pad at an edge: the pad goes first, the caret where the
191
- * key then takes the character beside it, as it would without the pad (keydown, before the browser
192
- * deletes or the editor merges blocks). At the stop beside a component's entry the whole entry goes,
193
- * and what the page says of that is returned; nothing otherwise.
194
+ * Backspace (`back`) at the stop after a component's entry, or Delete at the one before it: the whole
195
+ * entry goes, as a chip of the text does, the caret where it stood, and what the page says of that is
196
+ * returned; nothing otherwise. The keydown's (beforeDelete) and the beforeinput's, for a key whose
197
+ * keydown the editor passed by (an input method's, keyCode 229: editor.mjs). The pads beside it go
198
+ * with it, before the text either side of it is joined, so that no zero-width space is left in that
199
+ * text (a pad an undo step put back is part of the text beside it by then).
194
200
  */
195
- export function beforeDelete(host, key) {
201
+ export function takeEntry(host, back) {
196
202
  const selection = getSelection();
197
203
  if (!selection.rangeCount || !selection.isCollapsed) return;
198
- const back = key === "Backspace";
199
- // At the stop after an entry (or before it, for Delete): the whole entry goes.
200
204
  const outside = caretAtEdge(host);
201
205
  const entry = outside && !outside.inside ? entryOf(outside.code) : undefined;
202
- if (entry && (back ? outside.side === "end" : outside.side === "start")) {
203
- const caret = host.ownerDocument.createRange();
204
- if (isPad(selection.anchorNode)) selection.anchorNode.remove();
205
- caret.setStartBefore(outside.code);
206
- caret.collapse(true);
207
- outside.code.remove();
208
- host.normalize();
209
- select(caret);
210
- return entry.removed;
206
+ if (!entry || (back ? outside.side !== "end" : outside.side !== "start")) return;
207
+ const { code } = outside;
208
+ for (const [next, trim] of [["previousSibling", new RegExp(`${ZWSP}+$`)], ["nextSibling", new RegExp(`^${ZWSP}+`)]]) {
209
+ for (let node = code[next]; node?.nodeType === 3; node = code[next]) {
210
+ node.data = node.data.replace(trim, "");
211
+ if (node.data !== "") break;
212
+ node.remove();
213
+ }
211
214
  }
215
+ const caret = host.ownerDocument.createRange();
216
+ caret.setStartBefore(code);
217
+ caret.collapse(true);
218
+ code.remove();
219
+ host.normalize();
220
+ select(caret);
221
+ return entry.removed;
222
+ }
223
+
224
+ /**
225
+ * Backspace or Delete with the caret in a pad at an edge: the pad goes first, the caret where the
226
+ * key then takes the character beside it, as it would without the pad (keydown, before the browser
227
+ * deletes or the editor merges blocks). At the stop beside a component's entry the whole entry goes
228
+ * (takeEntry), and what the page says of that is returned; nothing otherwise.
229
+ */
230
+ export function beforeDelete(host, key) {
231
+ const back = key === "Backspace";
232
+ const removed = takeEntry(host, back);
233
+ if (removed) return removed;
234
+ const selection = getSelection();
235
+ if (!selection.rangeCount || !selection.isCollapsed) return;
212
236
  const pad = selection.anchorNode;
213
237
  if (!isPad(pad) || !host.contains(pad)) return;
214
238
  const edge = caretAtEdge(host);
@@ -226,3 +250,25 @@ export function beforeDelete(host, key) {
226
250
  caret.collapse(true);
227
251
  select(caret);
228
252
  }
253
+
254
+ // The host whose caret a deletion backward found in text outside any inline code or entry (no pad),
255
+ // for the input after it (deletedBack).
256
+ let backFrom = null;
257
+
258
+ /** A deletion backward about to happen (its beforeinput): where the caret stands, for deletedBack. */
259
+ export function deletingBack(host) {
260
+ const selection = getSelection();
261
+ const node = selection.rangeCount && selection.isCollapsed ? selection.anchorNode : null;
262
+ backFrom = node?.nodeType === 3 && !isPad(node) && !node.parentElement.closest(EDGED) ? host : null;
263
+ }
264
+
265
+ /**
266
+ * The deletion done (its input): a caret it took from the text after inline code or an entry into
267
+ * it, at its end, goes back out to the stop after it, where the reader deleting back stays.
268
+ */
269
+ export function deletedBack(host) {
270
+ const was = backFrom === host;
271
+ backFrom = null;
272
+ const edge = was && caretAtEdge(host);
273
+ if (edge && edge.inside && edge.side === "end") padCaret(edge.code, "after");
274
+ }
@@ -1,12 +1,12 @@
1
1
  import {
2
- boxKind, can, emptyContainer, isEmpty, isFirstLine, isHost, limitText, mergeWithPrevious, nestedBlocks, nestedLists, nextLine, parentItem, previousLine, removalTarget, splitBlock, takeOut, textEnd, unitElement,
2
+ UNIT, boxKind, can, emptyContainer, isEmpty, isFirstLine, isHost, limitText, mergeWithPrevious, nestedBlocks, nestedLists, nextLine, parentItem, previousLine, removalTarget, splitBlock, takeOut, textEnd, unitElement, newParagraphHost, withLeads,
3
3
  } from "../core.mjs";
4
4
  import { atEdge, caretAt, hosts, select, textNear } from "../caret.mjs";
5
5
  import { convertible } from "../convert.mjs";
6
6
  import { joinCode } from "../marks.mjs";
7
7
  import { numberWithUnit, sideOf, WORD } from "../../../shared/inline-spacing.mjs";
8
8
  import { pageOf, pagesAround } from "../page-objects.mjs";
9
- import { BLOCK_TYPES, HOSTS, firstSaysOf, placeholderOf, textFilters, textTypeOf } from "../../components/registry.mjs";
9
+ import { BLOCK_TYPES, HOSTS, accepts, firstSaysOf, placeholderOf, textFilters, textTypeOf } from "../../components/registry.mjs";
10
10
  import { t } from "../../../shared/i18n/index.mjs";
11
11
 
12
12
  // Typing in a block (docs/editor.md, "Browser side"): every key goes first to the component the block
@@ -25,6 +25,8 @@ import { t } from "../../../shared/i18n/index.mjs";
25
25
  // 3万5千), and a block written without such spaces is typed in its own way (none added).
26
26
  const HAN = /[\u2e80-\u2eff\u2f00-\u2fdf\u3040-\u309f\u30a0-\u30fa\u30fc-\u30ff\u3100-\u312f\u3200-\u32ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff]/;
27
27
  const LATIN = /[A-Za-z0-9]/;
28
+ // The text blocks that say their placeholder whenever they are empty (HOSTS' `untitled`: the page's title).
29
+ const UNTITLED = Object.keys(HOSTS).filter((kind) => HOSTS[kind].untitled).map((kind) => `main [data-ge-kind="${kind}"]`).join(", ");
28
30
  const needsSpace = (a, b, before) => ((HAN.test(a) && LATIN.test(b)) || (LATIN.test(a) && HAN.test(b))) && !numberWithUnit(a, b, before);
29
31
  // The block's own way with Chinese beside Latin letters and digits, from its text but what was just
30
32
  // typed: true when it writes them together more often than apart (a number's unit is no sign either way).
@@ -47,13 +49,12 @@ function writtenTogether(host, node, start, end) {
47
49
  /**
48
50
  * struct(parents, touched, mutate): the editor's undoable structural change (history.mjs). say: the
49
51
  * status line. keepText(unit): why a block may not go (block-info.mjs). paragraphBefore(host): an
50
- * empty paragraph before the block, the caret staying (insert/). paragraphAfter(unit): one after a
51
- * block, the caret in it, where its box takes one (insert/). removeBlocks(units): the blocks
52
+ * empty paragraph before the block, the caret staying (insert/). removeBlocks(units): the blocks
52
53
  * deleted as the selected ones are (selection/delete.mjs). adding(): the block the "/" menu the
53
54
  * handle's "+" opened is open in (slash-menu/), or null. leave: where Enter and Backspace leave a
54
- * container (leave.mjs).
55
+ * container (leave.mjs). showHidden(node): the folds hiding a block opened (fold/ showAround).
55
56
  */
56
- export function createTyping({ struct, say, keepText, paragraphBefore, paragraphAfter, removeBlocks, selectBlock = () => {}, adding = () => null, leave }) {
57
+ export function createTyping({ struct, say, keepText, paragraphBefore, removeBlocks, selectBlock = () => {}, adding = () => null, leave, showHidden = () => {} }) {
57
58
  // A key, asked of the component of the text block `host` and then of what stands around it, nearest
58
59
  // first (docs/editor.md, "The order of keys"): whether it was theirs. `ctx` is notion-lite's, as
59
60
  // much of it as a key reads, the block being an element here.
@@ -62,8 +63,43 @@ export function createTyping({ struct, say, keepText, paragraphBefore, paragraph
62
63
  return Boolean(key(pageOf(host)?.keys ?? {})?.(ctx, ...rest) || pagesAround(host).some((page) => key(page.keys?.around ?? {})?.(ctx, ...rest)));
63
64
  }
64
65
 
66
+ // Enter in the page's title (HOSTS' `opensBody`): notion-lite's splitBlock for the page (enter.js, its
67
+ // first rule): what is selected goes, what follows the caret leaves the title for a new paragraph right
68
+ // below it, the first block of the page (an empty one at its end, a new untitled document's too), and
69
+ // the caret goes to its start; the title keeps what stands before the caret, never a line break. One
70
+ // undo step, the caret back in the title where it was. Below the title is the header's first line when it has one
71
+ // (the paragraph goes before it, in the header), else the first block after the header.
72
+ function enterBody(title) {
73
+ const selection = getSelection();
74
+ if (!selection.rangeCount || !title.contains(selection.getRangeAt(0).startContainer) || !title.contains(selection.getRangeAt(0).endContainer)) return;
75
+ const range = selection.getRangeAt(0);
76
+ const header = title.parentElement;
77
+ let line = title.nextElementSibling;
78
+ while (line && !line.matches(UNIT)) line = line.nextElementSibling;
79
+ const [box, before] = line ? [header, withLeads(line)[0]] : [header.parentElement, header.nextSibling];
80
+ const paragraph = newParagraphHost(document);
81
+ if (!box?.hasAttribute("data-ge-box") || !accepts(box.getAttribute("data-ge-box-kind"), paragraph.getAttribute("data-ge-type"))) {
82
+ say(limitText(title, "split"));
83
+ return;
84
+ }
85
+ struct([...new Set([header, box])], [title], () => {
86
+ range.deleteContents();
87
+ const tail = document.createRange();
88
+ tail.setStart(range.startContainer, range.startOffset);
89
+ tail.setEnd(title, title.childNodes.length);
90
+ const moved = tail.extractContents();
91
+ if (moved.textContent.length > 0) paragraph.append(document.createTextNode(moved.textContent)); // the title's words, plain
92
+ title.normalize();
93
+ if (isEmpty(title)) title.replaceChildren();
94
+ box.insertBefore(paragraph, before);
95
+ return { touched: [title, paragraph], focus: paragraph };
96
+ }, { caret: true });
97
+ caretAt(paragraph, "start");
98
+ }
99
+
65
100
  // Enter.
66
101
  function split(host) {
102
+ if (HOSTS[host.getAttribute("data-ge-kind")]?.opensBody) return enterBody(host);
67
103
  // The caret at the very start of a block with text: an empty paragraph goes before the block and
68
104
  // the caret stays (a block that splits does this itself, splitBlock). This comes first: in a code
69
105
  // block too, whose own Enter breaks the line.
@@ -75,8 +111,7 @@ export function createTyping({ struct, say, keepText, paragraphBefore, paragraph
75
111
  // in any editor, and so does the empty last paragraph of a panel), the rule of every block.
76
112
  if (asked((keys) => keys.enter, host) || leave.enter(host)) return;
77
113
  if (!can(host, "split")) {
78
- // At the very end of a block that says so, a paragraph follows it, as one that splits would.
79
- if (!HOSTS[host.getAttribute("data-ge-kind")]?.opensAfter || !atEdge(host, true) || !paragraphAfter(host)) say(limitText(host, "split"));
114
+ say(limitText(host, "split"));
80
115
  return;
81
116
  }
82
117
  const selection = getSelection();
@@ -159,8 +194,15 @@ export function createTyping({ struct, say, keepText, paragraphBefore, paragraph
159
194
  return true;
160
195
  }
161
196
 
197
+ // A block on the line above or below that a folded heading hides (fold/: data-ge-folded on it or
198
+ // around it): its fold opens first, so a join never takes in words out of sight.
199
+ const opened = (line) => {
200
+ if (line?.closest?.("[data-ge-folded]")) showHidden(line);
201
+ };
202
+
162
203
  // Backspace at the start of a block. Returns whether it was handled.
163
204
  function backspace(host) {
205
+ opened(previousLine(host));
164
206
  // The block's component (a list item's: a nested item moves out a level, the first or last item of
165
207
  // a top-level list leaves it as body text, an emptied item holding lists stays), then what stands
166
208
  // around it (the item a block stands under; a node, at the start of its first line, holding
@@ -192,6 +234,7 @@ export function createTyping({ struct, say, keepText, paragraphBefore, paragraph
192
234
 
193
235
  // Delete at the end of a block. Returns whether it was handled.
194
236
  function forwardDelete(host) {
237
+ opened(nextLine(host));
195
238
  // Its component (an empty item holding blocks stays), then what stands around it (at the end of a
196
239
  // node's last block nothing is taken in).
197
240
  if (asked((keys) => keys.delete, host)) return true;
@@ -260,10 +303,23 @@ export function createTyping({ struct, say, keepText, paragraphBefore, paragraph
260
303
  if (hint) host.setAttribute("data-ge-placeholder", hint);
261
304
  else host?.removeAttribute("data-ge-placeholder");
262
305
  host?.toggleAttribute("data-ge-adding", add);
306
+ untitled();
307
+ }
308
+
309
+ // The page's title says 未命名文档 whenever it is empty, the caret in it or not (HOSTS' `untitled`:
310
+ // notion-lite's page title, data-ph 新页面); asked again on every move of the caret and every input,
311
+ // so an undo, a deletion across blocks and the workbench's renaming are followed too.
312
+ function untitled() {
313
+ if (!UNTITLED) return;
314
+ for (const host of document.querySelectorAll(UNTITLED)) {
315
+ if (!isHost(host)) continue;
316
+ if (isEmpty(host)) host.setAttribute("data-ge-placeholder", placeholderOf(host));
317
+ else if (host !== placeholder) host.removeAttribute("data-ge-placeholder");
318
+ }
263
319
  }
264
320
 
265
321
  return {
266
- split, backspace, forwardDelete, autoSpace, updatePlaceholder,
322
+ split, backspace, forwardDelete, autoSpace, updatePlaceholder, untitled,
267
323
  /** Tab (`back`: Shift+Tab). Whether the key was taken. */
268
324
  tab: (host, back) => asked((keys) => keys.tab, host, back),
269
325
  /** Ctrl+Enter. Whether the key was taken. */
@@ -15,7 +15,7 @@ import { BLOCK_TYPES, LEAVES_BY_ENTER, accepts } from "../../components/registry
15
15
  // - A block of a type that says `resettable` (a quote's paragraph, a list item) turns into a
16
16
  // paragraph where it stands, its container splitting around it (convert.mjs).
17
17
  // Enter in a title that goes into its content (a disclosure, a card, a code block) is another rule
18
- // (their components'), and so is Enter at the end of a block that says `opensAfter` (typing/).
18
+ // (their components').
19
19
 
20
20
  /**
21
21
  * The empty last block of a box that says `leaveByEnter`, moved out after the box (the box goes if
@@ -55,6 +55,19 @@ export function button(label, action, { primary = false, ...props } = {}) {
55
55
  return node;
56
56
  }
57
57
 
58
+ /**
59
+ * A text button in the editor's one button look (look.mjs BUTTONS, `.ge-btn`): no line, no fill, a gray
60
+ * under the pointer. `primary` the pale blue one (add, confirm, save; `data-primary`), `danger` with it the
61
+ * pale red (a delete), `quiet` a small one for looking, not deciding (`data-quiet`). A press on it leaves
62
+ * the selection where it is (button()).
63
+ */
64
+ export function textButton(label, action, { primary = false, danger = false, quiet = false, class: own = "", ...props } = {}) {
65
+ const node = button(label, action, { primary, class: `ge-btn${own ? ` ${own}` : ""}`, ...props });
66
+ if (danger) node.dataset.danger = "";
67
+ if (quiet) node.dataset.quiet = "";
68
+ return node;
69
+ }
70
+
58
71
  // Editor UI lives in the top layer with an open modal dialog, otherwise it would be inert.
59
72
  export function layer() {
60
73
  return document.querySelector(DIALOG.open) ?? document.body;
@@ -2,8 +2,8 @@ import { attr, hasClass } from "./html-tree.mjs";
2
2
  import { BLOCK_ID, randomId } from "./ids.mjs";
3
3
 
4
4
  // 批注 (docs/workbench.md "Annotations", docs/editor.md "Annotations"): the reader's suggestions for a
5
- // local Agent, each about a piece of a report: words of its text, or blocks taken whole. One with no
6
- // text is a plain mark of that place. Kept in reports/<slug>/annotations.json, never in report.html:
5
+ // local Agent, each about a piece of a report: words of its text, or blocks taken whole. One has
6
+ // words: an item with none is none (cleanItem). Kept in reports/<slug>/annotations.json, never in report.html:
7
7
  //
8
8
  // { v: 1, items: [{ id, created, updated, text, anchor }] }
9
9
  // anchor: { kind: "text", blocks: [data-block-id…], quote, prefix, suffix }
@@ -389,12 +389,13 @@ export function cleanAnchor(anchor) {
389
389
  export const sameWords = (a, b) => Boolean(a && b) && a.kind === b.kind && (a.blocks ?? []).join() === (b.blocks ?? []).join() && squash(a.quote) === squash(b.quote)
390
390
  && squash(a.prefix).slice(-CONTEXT_KEPT) === squash(b.prefix).slice(-CONTEXT_KEPT) && squash(a.suffix).slice(0, CONTEXT_KEPT) === squash(b.suffix).slice(0, CONTEXT_KEPT);
391
391
 
392
- /** An annotation as the file keeps it, from what was sent (`now`: when it is saved), or null when it is none. */
392
+ /** An annotation as the file keeps it, from what was sent (`now`: when it is saved), or null when it is none (no id, no anchor, no words). */
393
393
  export function cleanItem(item, now = new Date().toISOString()) {
394
394
  if (!item || typeof item !== "object" || typeof item.id !== "string" || !ID.test(item.id) || typeof item.text !== "string") return null;
395
395
  const anchor = cleanAnchor(item.anchor);
396
396
  if (!anchor) return null;
397
397
  const text = item.text.replace(/\r\n?/g, "\n").slice(0, TEXT_MOST);
398
+ if (!text.trim()) return null;
398
399
  return { id: item.id, created: typeof item.created === "string" ? item.created : now, updated: now, text, anchor };
399
400
  }
400
401
 
@@ -421,7 +422,6 @@ export const itemsText = (items) => (items.length === 0 ? null : `${JSON.stringi
421
422
  export const MARKDOWN_WORDS = {
422
423
  head: "以下是我对这份文档的批注,共 {0} 条。请逐条按“建议”修改底稿;每条给出它在文档里的位置、块的 data-block-id 和批注的原文。",
423
424
  headOne: "以下是我对这份文档的一条批注。请按“建议”修改底稿;它给出在文档里的位置、块的 data-block-id 和批注的原文。",
424
- marks: "没有“建议”的批注只是标记了一个位置,不用改。",
425
425
  report: "文档",
426
426
  source: "底稿",
427
427
  block: "块",
@@ -441,22 +441,20 @@ const fill = (text, ...values) => text.replace(/\{(\d+)\}/g, (whole, index) => (
441
441
  * then each annotation in page order: where it is (`where`: the tab, the headings above it, the
442
442
  * disclosure it is in; `top`: before the report's first heading, said 页首, which no tab or heading
443
443
  * named 正文 is taken for), its blocks' ids (as the file has them), its quote and the suggestion, each
444
- * of its lines a paragraph (blank lines in it make no more of them). One with no suggestion marks a
445
- * place: it has no such line, and a line under the first says what such a one is.
444
+ * of its lines a paragraph (blank lines in it make no more of them).
446
445
  * data: { title, path, items: [{ where: [text], top, blocks: [id], whole, quote, text }] }.
447
446
  */
448
447
  export function annotationsMarkdown({ title, path, items }, words = MARKDOWN_WORDS) {
449
448
  const w = { ...MARKDOWN_WORDS, ...words };
450
449
  const head = items.length === 1 && w.headOne ? w.headOne : fill(w.head, items.length);
451
- const suggestions = items.map((item) => String(item.text ?? "").replace(/\r\n?/g, "\n").split("\n").map((line) => line.trim()).filter(Boolean));
452
- const lines = [head, ...(suggestions.some((said) => said.length === 0) ? [w.marks] : []), "", `- ${w.report}${w.colon}${title}`, `- ${w.source}${w.colon}${path}`];
450
+ const lines = [head, "", `- ${w.report}${w.colon}${title}`, `- ${w.source}${w.colon}${path}`];
453
451
  items.forEach((item, index) => {
454
452
  const where = item.where?.length ? item.where.join(" › ") : item.top ? w.top : w.body;
455
453
  const ids = item.blocks?.length ? item.blocks.map((id) => `\`data-block-id="${id}"\``).join(w.comma) + (item.whole ? w.whole : "") : w.noId;
456
454
  lines.push("", `## ${index + 1}. ${where}`, "", `${w.block}${w.colon}${ids}`, "");
457
455
  for (const line of String(item.quote ?? "").split("\n")) lines.push(`> ${line}`);
458
- const said = suggestions[index];
459
- if (said.length > 0) lines.push("", `${w.suggestion}${w.colon}${said[0]}`);
456
+ const said = String(item.text ?? "").replace(/\r\n?/g, "\n").split("\n").map((line) => line.trim()).filter(Boolean);
457
+ lines.push("", `${w.suggestion}${w.colon}${said[0] ?? ""}`);
460
458
  for (const line of said.slice(1)) lines.push("", line);
461
459
  });
462
460
  return `${lines.join("\n")}\n`;