@heycys/gallery 0.1.1 → 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 (370) hide show
  1. package/THIRD-PARTY-NOTICES.md +1 -1
  2. package/browser/editor/components/columns/page.mjs +4 -4
  3. package/browser/editor/components/embed/index.mjs +2 -2
  4. package/browser/editor/components/flowchart/add.mjs +7 -6
  5. package/browser/editor/components/flowchart/page.mjs +1 -1
  6. package/browser/editor/components/icons.mjs +8 -0
  7. package/browser/editor/components/image/crop.mjs +6 -9
  8. package/browser/editor/components/installed/index.mjs +11 -4
  9. package/browser/editor/components/installed/page.mjs +27 -16
  10. package/browser/editor/components/installed/served.mjs +6 -5
  11. package/browser/editor/components/instances.mjs +18 -0
  12. package/browser/editor/components/list/page.mjs +3 -6
  13. package/browser/editor/components/registry.mjs +13 -4
  14. package/browser/editor/components/table/index.mjs +59 -2
  15. package/browser/editor/components/table/page.mjs +1 -1
  16. package/browser/editor/page/annotate/card.mjs +3 -6
  17. package/browser/editor/page/autosave.mjs +310 -37
  18. package/browser/editor/page/board/client.mjs +57 -0
  19. package/browser/editor/page/board/hint.mjs +145 -0
  20. package/browser/editor/page/board/history.mjs +119 -0
  21. package/browser/editor/page/board/index.mjs +970 -0
  22. package/browser/editor/page/board/settings.mjs +209 -0
  23. package/browser/editor/page/caret.mjs +1 -1
  24. package/browser/editor/page/changes/bar.mjs +6 -14
  25. package/browser/editor/page/changes/index.mjs +2 -2
  26. package/browser/editor/page/clipboard/import/html.mjs +29 -6
  27. package/browser/editor/page/clipboard/import/inline.mjs +32 -0
  28. package/browser/editor/page/clipboard/import/markdown.mjs +58 -13
  29. package/browser/editor/page/clipboard/import/read.mjs +6 -1
  30. package/browser/editor/page/clipboard/import/to-blocks.mjs +44 -12
  31. package/browser/editor/page/clipboard/import/yuque.mjs +622 -0
  32. package/browser/editor/page/clipboard/index.mjs +124 -13
  33. package/browser/editor/page/clipboard/own/blocks.mjs +11 -11
  34. package/browser/editor/page/clipboard/own/chart-keys.mjs +41 -28
  35. package/browser/editor/page/clipboard/own/selection.mjs +1 -1
  36. package/browser/editor/page/columns/index.mjs +48 -46
  37. package/browser/editor/page/commit.mjs +80 -22
  38. package/browser/editor/page/conflicts.mjs +7 -7
  39. package/browser/editor/page/core.mjs +31 -15
  40. package/browser/editor/page/custom-page.mjs +106 -0
  41. package/browser/editor/page/editor.mjs +51 -14
  42. package/browser/editor/page/emoji-picker/styles.mjs +7 -12
  43. package/browser/editor/page/emoji-picker/upload.mjs +2 -2
  44. package/browser/editor/page/handle/index.mjs +5 -8
  45. package/browser/editor/page/history.mjs +24 -4
  46. package/browser/editor/page/links/index.mjs +5 -3
  47. package/browser/editor/page/links/pages.mjs +27 -9
  48. package/browser/editor/page/look.mjs +54 -3
  49. package/browser/editor/page/margin.mjs +18 -3
  50. package/browser/editor/page/media-menu/index.mjs +6 -7
  51. package/browser/editor/page/menu.mjs +18 -7
  52. package/browser/editor/page/notices.mjs +2 -2
  53. package/browser/editor/page/page-objects.mjs +13 -2
  54. package/browser/editor/page/panel.mjs +4 -9
  55. package/browser/editor/page/present-links.mjs +11 -2
  56. package/browser/editor/page/resize/index.mjs +42 -29
  57. package/browser/editor/page/served.mjs +14 -0
  58. package/browser/editor/page/session.mjs +48 -4
  59. package/browser/editor/page/slash-menu/index.mjs +3 -3
  60. package/browser/editor/page/table/cells.mjs +102 -46
  61. package/browser/editor/page/table/icons.mjs +2 -0
  62. package/browser/editor/page/table/index.mjs +29 -10
  63. package/browser/editor/page/table/pictures.mjs +299 -0
  64. package/browser/editor/page/table/views.mjs +150 -0
  65. package/browser/editor/page/text-select/index.mjs +26 -12
  66. package/browser/editor/page/todo-writes.mjs +75 -0
  67. package/browser/editor/page/typing/index.mjs +53 -3
  68. package/browser/editor/page/ui.mjs +13 -0
  69. package/browser/shared/block-packs.mjs +404 -0
  70. package/browser/shared/board-places.mjs +224 -0
  71. package/browser/shared/card-size.mjs +59 -0
  72. package/browser/shared/colors.mjs +3 -2
  73. package/browser/shared/component-catalog.mjs +323 -46
  74. package/browser/shared/component-source.mjs +37 -0
  75. package/browser/shared/components/index.mjs +12 -3
  76. package/browser/shared/components/installed.mjs +35 -3
  77. package/browser/shared/components/page.mjs +18 -8
  78. package/browser/shared/components/state.mjs +5 -1
  79. package/browser/shared/document-look.mjs +10 -5
  80. package/browser/shared/drafts.mjs +432 -0
  81. package/browser/shared/extension-sidebar.mjs +126 -0
  82. package/browser/shared/extensions.mjs +79 -0
  83. package/browser/shared/file-table.mjs +101 -0
  84. package/browser/shared/i18n/en.mjs +307 -27
  85. package/browser/shared/json-layout.mjs +47 -0
  86. package/browser/shared/net-cache.mjs +133 -0
  87. package/browser/shared/net-keys.mjs +32 -0
  88. package/browser/shared/net-policy.mjs +177 -0
  89. package/browser/shared/outline-shape.mjs +128 -0
  90. package/browser/shared/outline.mjs +331 -67
  91. package/browser/shared/pack-manifest.mjs +77 -0
  92. package/browser/shared/page-address.mjs +6 -3
  93. package/browser/shared/page-cards.mjs +308 -0
  94. package/browser/shared/page-links.mjs +69 -6
  95. package/browser/shared/pages.mjs +388 -0
  96. package/browser/shared/paths.mjs +6 -0
  97. package/browser/shared/preview-server.mjs +3 -7
  98. package/browser/shared/session.mjs +8 -1
  99. package/browser/shared/shipped-blocks.mjs +299 -0
  100. package/browser/shared/table-chart.mjs +33 -1
  101. package/browser/shared/todos.mjs +83 -0
  102. package/browser/shared/user-directory.mjs +24 -0
  103. package/browser/shared/versions.mjs +14 -0
  104. package/browser/shared/web-links.mjs +134 -0
  105. package/browser/shared/workspace-columns.mjs +120 -0
  106. package/browser/shared/workspace-name.mjs +154 -0
  107. package/browser/shared/workspace-query.mjs +125 -0
  108. package/browser/shared/workspace-registry.mjs +272 -0
  109. package/browser/shared/workspace.mjs +171 -20
  110. package/dist/chunk-2NRBY6AJ.mjs +2 -0
  111. package/dist/chunk-32ZUEFZ7.mjs +2 -0
  112. package/dist/chunk-35NQ4PLQ.mjs +2 -0
  113. package/dist/chunk-3KJHLHUO.mjs +2 -0
  114. package/dist/chunk-3NJACR4W.mjs +2 -0
  115. package/dist/chunk-4AV456RQ.mjs +2 -0
  116. package/dist/chunk-4OZWXZE5.mjs +5 -0
  117. package/dist/chunk-5XYHDBJ5.mjs +2 -0
  118. package/dist/chunk-5ZJA7CXT.mjs +2 -0
  119. package/dist/chunk-6A53MZYZ.mjs +2 -0
  120. package/dist/chunk-6EXH3ORZ.mjs +166 -0
  121. package/dist/chunk-6EZ7FNIK.mjs +3 -0
  122. package/dist/{chunk-V5JTW2LH.mjs → chunk-6QBHU4DF.mjs} +1 -1
  123. package/dist/{chunk-Y6RLRPG3.mjs → chunk-6VTU6KEO.mjs} +1 -1
  124. package/dist/chunk-B4P2CM2J.mjs +3 -0
  125. package/dist/{chunk-FDLXYYG4.mjs → chunk-BPL64HGA.mjs} +1 -1
  126. package/dist/chunk-BVEFGE4B.mjs +2 -0
  127. package/dist/{chunk-LS4F7JUM.mjs → chunk-BZ5RAF7L.mjs} +1 -1
  128. package/dist/chunk-CRJEG7MT.mjs +2 -0
  129. package/dist/{chunk-LCTHTZIL.mjs → chunk-D4CKRD3V.mjs} +91 -91
  130. package/dist/chunk-D4EURAX4.mjs +4 -0
  131. package/dist/chunk-DQCE7TJY.mjs +5 -0
  132. package/dist/chunk-DR73Y2UJ.mjs +3 -0
  133. package/dist/{chunk-TMYZB6AV.mjs → chunk-EKNHM3P4.mjs} +1 -1
  134. package/dist/{chunk-GB5SOYQJ.mjs → chunk-ERLAIBOA.mjs} +2 -2
  135. package/dist/chunk-EURLTOTZ.mjs +4 -0
  136. package/dist/chunk-FJYN7RTH.mjs +4 -0
  137. package/dist/chunk-FWNRPMCJ.mjs +12 -0
  138. package/dist/chunk-FWW4CSAZ.mjs +2 -0
  139. package/dist/{chunk-2B5E4CDJ.mjs → chunk-GPIWQ4X4.mjs} +1 -1
  140. package/dist/chunk-GY3FAUVM.mjs +2 -0
  141. package/dist/chunk-HLYV7RIH.mjs +2 -0
  142. package/dist/chunk-HMYTM3GT.mjs +15 -0
  143. package/dist/chunk-IA4PSIMD.mjs +2 -0
  144. package/dist/chunk-JEUK3ZO7.mjs +2 -0
  145. package/dist/chunk-KTKHRC6H.mjs +2 -0
  146. package/dist/chunk-L7UP52JO.mjs +2 -0
  147. package/dist/{chunk-SYGN7GLU.mjs → chunk-MHW7ZKOU.mjs} +1 -1
  148. package/dist/chunk-N76HWBA3.mjs +10 -0
  149. package/dist/chunk-N7AZZLGT.mjs +548 -0
  150. package/dist/chunk-NAMN3RAF.mjs +2 -0
  151. package/dist/{chunk-5ZKJ3H4P.mjs → chunk-NFMCP2HI.mjs} +3 -3
  152. package/dist/chunk-NG375ILQ.mjs +2 -0
  153. package/dist/chunk-NVRNLK25.mjs +6 -0
  154. package/dist/chunk-NWFBE2YA.mjs +2 -0
  155. package/dist/chunk-NWR2LT5B.mjs +2 -0
  156. package/dist/chunk-OJKMINIU.mjs +20 -0
  157. package/dist/{chunk-4FS7Z7WR.mjs → chunk-OUUP3WKT.mjs} +1 -1
  158. package/dist/{chunk-BGGDRNYQ.mjs → chunk-OW5NWPOJ.mjs} +1 -1
  159. package/dist/chunk-PAREWQGB.mjs +4 -0
  160. package/dist/chunk-POQSE4C2.mjs +2 -0
  161. package/dist/chunk-PUOQ65NC.mjs +2 -0
  162. package/dist/{chunk-XNROSH2T.mjs → chunk-PVER7LSC.mjs} +2 -2
  163. package/dist/chunk-PZDLJJTJ.mjs +3 -0
  164. package/dist/chunk-Q47PLKIJ.mjs +15 -0
  165. package/dist/chunk-Q4UEPUWF.mjs +2 -0
  166. package/dist/chunk-QKXMPUXC.mjs +2 -0
  167. package/dist/chunk-QOUEFUCH.mjs +16 -0
  168. package/dist/chunk-RFDZXFJF.mjs +13 -0
  169. package/dist/chunk-RKPWLGZ3.mjs +4 -0
  170. package/dist/chunk-RMECZA2K.mjs +2 -0
  171. package/dist/{chunk-7DTINW6U.mjs → chunk-SQ6Y2ZMA.mjs} +2 -2
  172. package/dist/chunk-SX4LJYT6.mjs +8 -0
  173. package/dist/chunk-SXHBYZST.mjs +16 -0
  174. package/dist/chunk-TANZRINB.mjs +2 -0
  175. package/dist/chunk-TEZAWDSQ.mjs +2 -0
  176. package/dist/chunk-UBBRTJ2R.mjs +24 -0
  177. package/dist/chunk-UFNYFFKO.mjs +20 -0
  178. package/dist/chunk-UGWYKHBL.mjs +170 -0
  179. package/dist/chunk-UKSHDZZ6.mjs +2 -0
  180. package/dist/chunk-UNOYVIYR.mjs +2 -0
  181. package/dist/{chunk-E7LWZRXY.mjs → chunk-V6RIYQZZ.mjs} +1 -1
  182. package/dist/chunk-VJPFVNNW.mjs +15 -0
  183. package/dist/chunk-VS3ZMVGX.mjs +5 -0
  184. package/dist/chunk-VTKNEYT3.mjs +6 -0
  185. package/dist/chunk-VXACTLO3.mjs +3 -0
  186. package/dist/chunk-YI43RG4P.mjs +2 -0
  187. package/dist/chunk-YQGT4AB2.mjs +6 -0
  188. package/dist/chunk-ZB4H7ZN4.mjs +2 -0
  189. package/dist/{chunk-IVDLMMBD.mjs → chunk-ZHEHPMBK.mjs} +1 -1
  190. package/dist/chunk-ZTHICSSF.mjs +2 -0
  191. package/dist/chunk-ZUNVAXLH.mjs +2 -0
  192. package/dist/chunk-ZWPMCK7P.mjs +2 -0
  193. package/dist/cli.mjs +1 -1
  194. package/dist/server.mjs +1 -1
  195. package/dist/{chunk-U6KNPJPR.mjs → update-fetch.mjs} +1 -1
  196. package/dist/worker.mjs +1 -1
  197. package/kit/board.css +95 -0
  198. package/kit/board.js +250 -0
  199. package/kit/charts.js +5 -71
  200. package/kit/code.js +14 -14
  201. package/kit/report.css +255 -17
  202. package/kit/runtime.js +1600 -125
  203. package/kit/state.js +10 -1
  204. package/kit/tables.js +128 -43
  205. package/kit/ui.js +77 -35
  206. package/package.json +2 -1
  207. package/packs/gallery/card/component.json +14 -0
  208. package/packs/gallery/card/example.html +10 -0
  209. package/packs/gallery/card/preview.svg +1 -0
  210. package/packs/gallery/card/style.css +6 -0
  211. package/packs/gallery/card/template.html +6 -0
  212. package/packs/gallery/card/writing.md +14 -0
  213. package/packs/gallery/chart-card/component.json +15 -0
  214. package/packs/gallery/chart-card/example.html +14 -0
  215. package/packs/gallery/chart-card/kit.js +130 -0
  216. package/packs/gallery/chart-card/preview.svg +1 -0
  217. package/packs/gallery/chart-card/style.css +42 -0
  218. package/packs/gallery/chart-card/template.html +13 -0
  219. package/packs/gallery/chart-card/writing.md +20 -0
  220. package/packs/gallery/chart-view/component.json +20 -0
  221. package/packs/gallery/chart-view/example.html +13 -0
  222. package/packs/gallery/chart-view/kit.js +355 -0
  223. package/packs/gallery/chart-view/preview.svg +1 -0
  224. package/packs/gallery/chart-view/style.css +94 -0
  225. package/packs/gallery/chart-view/template.html +3 -0
  226. package/packs/gallery/chart-view/writing.md +22 -0
  227. package/packs/gallery/countdown/component.json +18 -0
  228. package/packs/gallery/countdown/example.html +3 -0
  229. package/packs/gallery/countdown/kit.js +156 -0
  230. package/packs/gallery/countdown/preview.svg +1 -0
  231. package/packs/gallery/countdown/style.css +130 -0
  232. package/packs/gallery/countdown/template.html +3 -0
  233. package/packs/gallery/countdown/writing.md +22 -0
  234. package/packs/gallery/habit/component.json +14 -0
  235. package/packs/gallery/habit/example.html +3 -0
  236. package/packs/gallery/habit/kit.js +295 -0
  237. package/packs/gallery/habit/preview.svg +1 -0
  238. package/packs/gallery/habit/style.css +246 -0
  239. package/packs/gallery/habit/template.html +3 -0
  240. package/packs/gallery/habit/writing.md +21 -0
  241. package/packs/gallery/heatmap/component.json +18 -0
  242. package/packs/gallery/heatmap/example.html +3 -0
  243. package/packs/gallery/heatmap/kit.js +351 -0
  244. package/packs/gallery/heatmap/preview.svg +1 -0
  245. package/packs/gallery/heatmap/style.css +201 -0
  246. package/packs/gallery/heatmap/template.html +3 -0
  247. package/packs/gallery/heatmap/writing.md +21 -0
  248. package/packs/gallery/kanban/component.json +18 -0
  249. package/packs/gallery/kanban/example.html +12 -0
  250. package/packs/gallery/kanban/kit.js +540 -0
  251. package/packs/gallery/kanban/preview.svg +1 -0
  252. package/packs/gallery/kanban/style.css +212 -0
  253. package/packs/gallery/kanban/template.html +3 -0
  254. package/packs/gallery/kanban/writing.md +20 -0
  255. package/packs/gallery/metric/component.json +22 -0
  256. package/packs/gallery/metric/example.html +15 -0
  257. package/packs/gallery/metric/kit.js +248 -0
  258. package/packs/gallery/metric/preview.svg +1 -0
  259. package/packs/gallery/metric/style.css +92 -0
  260. package/packs/gallery/metric/template.html +3 -0
  261. package/packs/gallery/metric/writing.md +23 -0
  262. package/packs/gallery/note/component.json +14 -0
  263. package/packs/gallery/note/example.html +3 -0
  264. package/packs/gallery/note/kit.js +102 -0
  265. package/packs/gallery/note/preview.svg +1 -0
  266. package/packs/gallery/note/style.css +76 -0
  267. package/packs/gallery/note/template.html +3 -0
  268. package/packs/gallery/note/writing.md +18 -0
  269. package/packs/gallery/pack.json +8 -0
  270. package/packs/gallery/recent/component.json +13 -0
  271. package/packs/gallery/recent/example.html +1 -0
  272. package/packs/gallery/recent/kit.js +238 -0
  273. package/packs/gallery/recent/preview.svg +1 -0
  274. package/packs/gallery/recent/style.css +158 -0
  275. package/packs/gallery/recent/template.html +1 -0
  276. package/packs/gallery/recent/writing.md +15 -0
  277. package/packs/gallery/static/component.json +13 -0
  278. package/packs/gallery/static/example.html +11 -0
  279. package/packs/gallery/static/preview.svg +1 -0
  280. package/packs/gallery/static/style.css +138 -0
  281. package/packs/gallery/static/template.html +1 -0
  282. package/packs/gallery/static/writing.md +18 -0
  283. package/packs/gallery/stats/component.json +13 -0
  284. package/packs/gallery/stats/example.html +1 -0
  285. package/packs/gallery/stats/kit.js +166 -0
  286. package/packs/gallery/stats/preview.svg +1 -0
  287. package/packs/gallery/stats/style.css +151 -0
  288. package/packs/gallery/stats/template.html +1 -0
  289. package/packs/gallery/stats/writing.md +11 -0
  290. package/packs/gallery/today/component.json +12 -0
  291. package/packs/gallery/today/example.html +1 -0
  292. package/packs/gallery/today/kit.js +185 -0
  293. package/packs/gallery/today/preview.svg +1 -0
  294. package/packs/gallery/today/style.css +120 -0
  295. package/packs/gallery/today/template.html +1 -0
  296. package/packs/gallery/today/writing.md +14 -0
  297. package/packs/gallery/todos/component.json +19 -0
  298. package/packs/gallery/todos/example.html +3 -0
  299. package/packs/gallery/todos/kit.js +342 -0
  300. package/packs/gallery/todos/preview.svg +1 -0
  301. package/packs/gallery/todos/style.css +267 -0
  302. package/packs/gallery/todos/template.html +3 -0
  303. package/packs/gallery/todos/writing.md +30 -0
  304. package/packs/gallery/weather/component.json +19 -0
  305. package/packs/gallery/weather/example.html +3 -0
  306. package/packs/gallery/weather/kit.js +312 -0
  307. package/packs/gallery/weather/preview.svg +1 -0
  308. package/packs/gallery/weather/style.css +258 -0
  309. package/packs/gallery/weather/template.html +3 -0
  310. package/packs/gallery/weather/writing.md +26 -0
  311. package/packs/gallery-soft/pack.json +8 -0
  312. package/release.json +12 -10
  313. package/sdk/doc-kit.d.ts +396 -5
  314. package/sdk/doc-state.d.ts +2 -0
  315. package/skill/SKILL.md +56 -23
  316. package/skill/references/block-script.md +140 -0
  317. package/skill/references/building-blocks.md +257 -0
  318. package/skill/references/extensions.md +59 -0
  319. package/skill/references/pages-and-data.md +221 -0
  320. package/skill/references/writing-html.md +6 -4
  321. package/skill/sdk/doc-kit.d.ts +396 -5
  322. package/skill/sdk/doc-state.d.ts +2 -0
  323. package/web/assets/index-BK2e_07w.js +13 -0
  324. package/web/assets/index-CWFI83mF.css +1 -0
  325. package/web/index.html +2 -2
  326. package/dist/chunk-3HIRPVLU.mjs +0 -2
  327. package/dist/chunk-5MHMDLZD.mjs +0 -4
  328. package/dist/chunk-64K7IPLO.mjs +0 -255
  329. package/dist/chunk-6QXGZM36.mjs +0 -8
  330. package/dist/chunk-6RGJOMJP.mjs +0 -16
  331. package/dist/chunk-AJ73XJF3.mjs +0 -2
  332. package/dist/chunk-AUZGSZJH.mjs +0 -13
  333. package/dist/chunk-BFE45AKL.mjs +0 -2
  334. package/dist/chunk-BXO2ZY5P.mjs +0 -2
  335. package/dist/chunk-CEH4MRCC.mjs +0 -2
  336. package/dist/chunk-CY2FNNAB.mjs +0 -16
  337. package/dist/chunk-DFUDV4LX.mjs +0 -2
  338. package/dist/chunk-DKXG4XDG.mjs +0 -2
  339. package/dist/chunk-EZQ34M3F.mjs +0 -124
  340. package/dist/chunk-EZY3WC6Z.mjs +0 -15
  341. package/dist/chunk-FUKQNOQS.mjs +0 -9
  342. package/dist/chunk-JPOSLGOC.mjs +0 -6
  343. package/dist/chunk-L3QKH4OK.mjs +0 -26
  344. package/dist/chunk-LAE5NQ4B.mjs +0 -2
  345. package/dist/chunk-LEF6DRCK.mjs +0 -59
  346. package/dist/chunk-NO5NJCHO.mjs +0 -2
  347. package/dist/chunk-NQPVAU63.mjs +0 -2
  348. package/dist/chunk-NSKUTQ5J.mjs +0 -5
  349. package/dist/chunk-O35FIXRB.mjs +0 -2
  350. package/dist/chunk-P2CAZPDP.mjs +0 -3
  351. package/dist/chunk-PL6GHLGD.mjs +0 -15
  352. package/dist/chunk-QJIR2BLP.mjs +0 -6
  353. package/dist/chunk-QUPLVPB2.mjs +0 -7
  354. package/dist/chunk-R7BNENLY.mjs +0 -4
  355. package/dist/chunk-S6O4UHLC.mjs +0 -2
  356. package/dist/chunk-SGJWQKEI.mjs +0 -2
  357. package/dist/chunk-TX6JH7TR.mjs +0 -2
  358. package/dist/chunk-TYK6VNAB.mjs +0 -10
  359. package/dist/chunk-UALRNVSE.mjs +0 -4
  360. package/dist/chunk-V3HXVQEM.mjs +0 -2
  361. package/dist/chunk-V5VXUJKG.mjs +0 -2
  362. package/dist/chunk-VBXMADMP.mjs +0 -2
  363. package/dist/chunk-VNV55RUA.mjs +0 -2
  364. package/dist/chunk-VPD2PS35.mjs +0 -2
  365. package/dist/chunk-W4VKN3GF.mjs +0 -7
  366. package/dist/chunk-W5BXXPDJ.mjs +0 -3
  367. package/dist/chunk-XUNHRCOG.mjs +0 -6
  368. package/skill/references/building-components.md +0 -367
  369. package/web/assets/index-Bh74DfsV.css +0 -1
  370. package/web/assets/index-UW0RyFFt.js +0 -13
@@ -0,0 +1,150 @@
1
+ import { TABLE } from "../../components/kit.mjs";
2
+ import { insertRow, moveRow, removeRows, tableState } from "../../components/table/page.mjs";
3
+ import { tableOf } from "../../components/table/grid.mjs";
4
+ import { ownHTML } from "../core.mjs";
5
+ import { menuEntry, viewKeys } from "../page-objects.mjs";
6
+ import { CHART_SOURCE, TABLE_READERS, VIEW_FROM, nextChartKey } from "../../../shared/table-chart.mjs";
7
+ import { t } from "../../../shared/i18n/index.mjs";
8
+ import { TABLE_ICONS } from "./icons.mjs";
9
+
10
+ // The views of a table (docs/editor.md, "Table views"; the plan's 阶段 4): an instance of a custom
11
+ // block whose needs hold "tables", bound to a table of the document by the key its frame carries
12
+ // (shared/table-chart.mjs VIEW_FROM, the key a chart drawn from a table reads it by), reads the table's
13
+ // rows (the kit's context.table()) and changes them only by asking: a doc-table-intent the kit puts on
14
+ // the instance (runtime/kernel.js), which these tools answer at once, made as the table's own tools make
15
+ // a change, so that a view has no commit, undo or conflict of its own:
16
+ //
17
+ // set one cell's words: a text step of that cell (history.mjs recordStep), its commit a cell's text
18
+ // as typing's is, merged word by word with someone else's change of the cell (source/merge.mjs);
19
+ // move a row put before or after another, the cells it names set in the same step (a card dropped
20
+ // in another column: its status and its place);
21
+ // add a row put in after another or last, its cells' words those it names;
22
+ // remove a row taken out (never the last of the body, as the tools' 删除);
23
+ // check nothing: answered as the others would be (the kit's table().canEdit()), so that a view of a
24
+ // table these tools do not manage shows it read-only;
25
+ //
26
+ // move, add and remove are the table tools' operations (components/table/page.mjs moveRow, insertRow,
27
+ // removeRows) in one undo step each (index.mjs change), their commit the table's operation, which a
28
+ // change someone else made to the table meanwhile holds back as a conflict with its card, as any. Only a
29
+ // table these tools manage (GRID: written as the kit writes one) and with no merged cell takes them: a
30
+ // view of any other is read-only, as it is in an export (the kit asks nothing there). Its rows of data
31
+ // are those after its header row: the head's rows, or with no head its body's first row, which a view
32
+ // reads its columns' names from; no intent puts a row there or takes that one.
33
+ //
34
+ // 视图 › of a table's block menu (menuRow) lists the custom blocks that read tables and that the
35
+ // document's menus would offer (their `readsTables` row of the custom blocks' menu variants, which follows
36
+ // the 组件列表 switches; page-objects.mjs viewKeys: no other menu lists them, as one put in unbound only
37
+ // says it has no table) and puts one in right after the table bound to it, in one undo step: the table's key
38
+ // where it names this table (the first frame carrying it, as the kit and the checks read a key), or a new
39
+ // one (the first of t1, t2 … the page does not hold) put on its frame in that step (a table made from "/"
40
+ // has none; the second of two an Agent wrote with one key is not the one it names). The commit writes
41
+ // both, and the server makes sure of the key against the file (source/chart-keys.mjs relinkMade); a key
42
+ // it gives the pair anew the page follows, its undo steps too (page/commit.mjs apply, history.mjs rekeyed).
43
+
44
+ /**
45
+ * active(): whether the page edits now. change(unit, mutate, said, touched): the table tools' one undo
46
+ * step (index.mjs). tableAt(node): the table unit these tools manage that a node is in. recordStep(host,
47
+ * before): a text step of a text block (history.mjs). insertBelow(unit, key, { attributes, done }): a
48
+ * block of the menu's `key` put in below a block in one undo step, `attributes` ([element, names]) recorded
49
+ * with it and `done(made)` run in it on the new block (editor.mjs insertBelow). drawn(): the tools drawn
50
+ * again (a row taken out).
51
+ */
52
+ export function createViews({ active, change, tableAt, recordStep, insertBelow, drawn = () => {} }) {
53
+ const merged = (rows) => rows.some((row) => [...row.cells].some((cell) => cell.rowSpan !== 1 || cell.colSpan !== 1));
54
+ const writable = (cell) => cell?.getAttribute("contenteditable") === "true";
55
+ const holds = (cell, text) => cell.textContent === text && cell.childElementCount === 0;
56
+
57
+ // What a view asks (`detail` of doc-table-intent: kernel.js tableView), made, or refused (false).
58
+ function run({ table, op, row = null, before = null, after = null, cells = [] }) {
59
+ if (!active() || !table?.isConnected) return false;
60
+ const unit = tableAt(table);
61
+ if (!unit || tableOf(unit) !== table) return false;
62
+ const state = tableState(unit);
63
+ if (merged(state.rows) || !Array.isArray(cells) || !cells.every(([column, text]) => Number.isInteger(column) && column >= 0 && column < state.columns && typeof text === "string")) return false;
64
+ // A view's table().canEdit(): whether an intent of this table would be taken now, nothing changed.
65
+ if (op === "check") return true;
66
+ // Its rows of data: after the header a view reads its names from (the head, else the body's first row).
67
+ const all = state.rows;
68
+ const data = all.slice(Math.max(1, state.head?.rows.length ?? 0));
69
+ const ofData = (node) => data.includes(node);
70
+ const cellsOf = (target) => cells.map(([column]) => target.cells[column]);
71
+ if (op === "set") {
72
+ if (!ofData(row) || cells.length !== 1) return false;
73
+ const [[column, text]] = cells;
74
+ const cell = row.cells[column];
75
+ if (!writable(cell)) return false;
76
+ if (holds(cell, text)) return true;
77
+ const was = ownHTML(cell);
78
+ cell.textContent = text;
79
+ recordStep(cell, was);
80
+ return true;
81
+ }
82
+ if (op === "move") {
83
+ const target = before ?? after;
84
+ if (!ofData(row) || (target && !ofData(target)) || !cellsOf(row).every(writable)) return false;
85
+ const from = all.indexOf(row);
86
+ const rest = all.filter((node) => node !== row);
87
+ const to = !target || target === row ? from : before ? rest.indexOf(before) : rest.indexOf(after) + 1;
88
+ if (to === from && cells.every(([column, text]) => holds(row.cells[column], text))) return true;
89
+ return change(unit, () => {
90
+ if (to !== from && moveRow(unit, from, to) === false) return false;
91
+ for (const [column, text] of cells) row.cells[column].textContent = text;
92
+ return true;
93
+ }, null, cellsOf(row)) !== null;
94
+ }
95
+ if (op === "add") {
96
+ if (after && !ofData(after)) return false;
97
+ const at = after ? all.indexOf(after) + 1 : all.length;
98
+ return change(unit, () => {
99
+ const made = insertRow(unit, at);
100
+ for (const [column, text] of cells) if (made.cells[column]) made.cells[column].textContent = text;
101
+ return made;
102
+ }, null) !== null;
103
+ }
104
+ if (op === "remove") {
105
+ if (!ofData(row)) return false;
106
+ const at = all.indexOf(row);
107
+ const done = change(unit, () => removeRows(unit, at, at), null) !== null;
108
+ drawn();
109
+ return done;
110
+ }
111
+ return false;
112
+ }
113
+ document.addEventListener("doc-table-intent", (event) => {
114
+ if (run(event.detail ?? {})) event.preventDefault();
115
+ });
116
+
117
+ // The frame a key names, as the kit reads it (runtime/table-reading.js frameOf) and the checks do: the
118
+ // first that carries it, none of a dev block's.
119
+ const frameOf = (key) => [...document.querySelectorAll(`[${CHART_SOURCE}]`)].find((node) => node.getAttribute(CHART_SOURCE) === key && node.matches(TABLE.frame) && !node.closest("[data-doc-dev]")) ?? null;
120
+ // A view of the block `key` put in right after `unit`, bound to its table: by its key where that names
121
+ // it, else by a new one put on it in the same step (a table made from "/" has none; one of two an Agent
122
+ // wrote with one key is not the one it names, the first: a view by it would read and change that one).
123
+ function insertView(unit, key) {
124
+ const own = unit.getAttribute(CHART_SOURCE);
125
+ const taken = new Set([...document.querySelectorAll([CHART_SOURCE, ...TABLE_READERS].map((name) => `[${name}]`).join(", "))].flatMap((node) => [CHART_SOURCE, ...TABLE_READERS].map((name) => node.getAttribute(name)).filter((value) => value !== null)));
126
+ const bound = own !== null && frameOf(own) === unit ? own : nextChartKey(taken);
127
+ insertBelow(unit, key, {
128
+ attributes: [[unit, [CHART_SOURCE]]],
129
+ done(made) {
130
+ made?.setAttribute(VIEW_FROM, bound);
131
+ if (bound !== own) unit.setAttribute(CHART_SOURCE, bound);
132
+ },
133
+ });
134
+ }
135
+
136
+ return {
137
+ /** The 视图 › row of a table's block menu: one for each custom block that reads tables, or null where there is none or the table cannot be read as rows (no frame, a merged cell). */
138
+ menuRow(unit) {
139
+ const keys = viewKeys();
140
+ if (keys.length === 0 || !unit.matches(TABLE.frame) || merged(tableState(unit).rows)) return null;
141
+ return {
142
+ label: t("视图"), icon: TABLE_ICONS.view,
143
+ submenu: () => viewKeys().map((key) => {
144
+ const row = menuEntry(key).variant;
145
+ return { label: row.label, icon: row.icon, run: () => insertView(unit, key) };
146
+ }),
147
+ };
148
+ },
149
+ };
150
+ }
@@ -1,7 +1,7 @@
1
1
  import { chipBox } from "../chip-fills.mjs";
2
2
  import { DETAILS, DIALOG } from "../../components/kit.mjs";
3
3
  import { boxRole } from "../../components/registry.mjs";
4
- import { UNIT, can, isHost, mergeInto, partsOf, removalTarget, takeOut, textEnd, unitElement } from "../core.mjs";
4
+ import { UNIT, can, isEmpty, isHost, mergeInto, partsOf, removalTarget, takeOut, textEnd, unitElement } from "../core.mjs";
5
5
  import { atomOf, caretAt, caretAtOffset, dragPlace, editable, hosts, pointRange, select } from "../caret.mjs";
6
6
  import { edgeFollower } from "../edge-scroll.mjs";
7
7
  import { FOLDED } from "../folded.mjs";
@@ -22,7 +22,9 @@ import { t } from "../../../shared/i18n/index.mjs";
22
22
  // the window's edges), drawn with the CSS Custom Highlight API in the selection's own colors, the
23
23
  // browser's selecting held off meanwhile; back in that block, the browser's again. Shift+click in
24
24
  // another block selects from the caret to there.
25
- // Its text is that of body text, headings and list items (in quotes, highlight blocks, callouts, columns…).
25
+ // Its text is that of body text, headings and list items (in quotes, highlight blocks, callouts, columns…),
26
+ // and the page's title's, which a deletion takes its part of but never joins with the body's (notion-lite's
27
+ // selection runs from its page title into the blocks; the user's: what is left of the body stays in the body).
26
28
  // A block holding none (a code block, a table, a file, an image, a formula block, a
27
29
  // divider…) is taken whole as it passes it, filled as a selected block is (selection/ mark), its
28
30
  // own text not marked: over one, an end of the selection stands before it or after it, as the drag
@@ -108,6 +110,10 @@ function lineStrips(texts, origin) {
108
110
 
109
111
  // The text blocks it takes text from, and a deletion joins: body text, headings, list items.
110
112
  const isText = (host) => isHost(host) && (host.getAttribute("data-ge-kind") ?? "flow") === "flow";
113
+ // The page's title: text it takes too (drawn, copied, deleted), kept apart: a deletion leaves it what
114
+ // stands outside the selection and joins nothing to it (remove).
115
+ const isTitle = (host) => isHost(host) && host.getAttribute("data-ge-kind") === "title";
116
+ const isPiece = (host) => isText(host) || isTitle(host);
111
117
  const textHosts = (unit) => [...unit.querySelectorAll("[data-ge-block], [data-ge-new]")].filter((node) => isHost(node) && isText(node));
112
118
 
113
119
  // The outermost block around `node` holding no text of the body (a code block, a table, a file…),
@@ -194,12 +200,12 @@ export function createTextSelection({ isEditing, struct, say, keepText, selectUn
194
200
  function pointAt(x, y, from) {
195
201
  const place = dragPlace([from.node, from.offset], x, y);
196
202
  const host = place && editable(place[0]);
197
- if (host?.closest("main") && isText(host)) return { host, node: place[0], offset: place[1] };
203
+ if (host?.closest("main") && isPiece(host)) return { host, node: place[0], offset: place[1] };
198
204
  const whole = wholeOf(document.elementFromPoint(x, y));
199
205
  if (whole) return edge(whole, !from || before(from, edge(whole, false)));
200
206
  let best = null;
201
207
  let bestScore = null;
202
- for (const each of hosts().filter((node) => node.closest("main") && isText(node))) {
208
+ for (const each of hosts().filter((node) => node.closest("main") && isPiece(node))) {
203
209
  const rect = each.getBoundingClientRect();
204
210
  // By height, then (level ones: columns side by side) by width; of nested ones, the innermost.
205
211
  const score = gapScore(rect, x, y);
@@ -220,7 +226,7 @@ export function createTextSelection({ isEditing, struct, say, keepText, selectUn
220
226
  // Where the selection starts, `focus` being its other end: the press's place in body text; begun
221
227
  // in a block taken whole (its code, a cell), that block's edge away from `focus`.
222
228
  function startOf(anchor, focus) {
223
- if (isText(anchor.host)) return anchor;
229
+ if (isPiece(anchor.host)) return anchor;
224
230
  const whole = wholeOf(anchor.host) ?? unitElement(anchor.host);
225
231
  if (!whole) return anchor;
226
232
  const head = edge(whole, false);
@@ -243,7 +249,7 @@ export function createTextSelection({ isEditing, struct, say, keepText, selectUn
243
249
  // text it reaches: none when its text stands before the start (the selection begun in a block the
244
250
  // item holds) or after the end.
245
251
  const reaches = (host) => host === selection.start.host || host === selection.end.host || (range.isPointInRange(host, 0) && range.isPointInRange(host, textEnd(host)));
246
- const texts = hosts().filter((host) => host.closest("main") && isText(host) && range.intersectsNode(host) && reaches(host) && !folded(host)).map((host) => {
252
+ const texts = hosts().filter((host) => host.closest("main") && isPiece(host) && range.intersectsNode(host) && reaches(host) && !folded(host)).map((host) => {
247
253
  const part = document.createRange();
248
254
  part.setStart(host, 0);
249
255
  part.setEnd(host, textEnd(host));
@@ -496,7 +502,7 @@ export function createTextSelection({ isEditing, struct, say, keepText, selectUn
496
502
  select(range);
497
503
  return;
498
504
  }
499
- const texts = hosts().filter((host) => host.closest("main") && isText(host));
505
+ const texts = hosts().filter((host) => host.closest("main") && isPiece(host));
500
506
  const next = texts.find((host) => before(point, { node: host, offset: 0 }));
501
507
  const previous = texts.filter((host) => before({ node: host, offset: textEnd(host) }, point)).at(-1);
502
508
  const host = forward ? next ?? previous : previous ?? next;
@@ -504,14 +510,17 @@ export function createTextSelection({ isEditing, struct, say, keepText, selectUn
504
510
  }
505
511
 
506
512
  // Delete it: the first block keeps its text before it and takes the last block's after it, the
507
- // blocks between go (those taken whole among them); one undo step, the caret where it began.
513
+ // blocks between go (those taken whole among them); one undo step, the caret where it began. From
514
+ // the page's title (`apart`) nothing joins: the title keeps what stands before it (empty, it says
515
+ // 未命名文档), the last block what stands after it in a block of its own (gone when that is nothing).
508
516
  // Returns whether it went.
509
517
  function remove() {
510
518
  const selection = cross;
511
519
  const { start, end } = selection;
512
520
  letGo();
513
521
  if (!(start.host ?? start.node).isConnected || !(end.host ?? end.node).isConnected) return false;
514
- if (![start.host, end.host].every((host) => !host || isText(host))) {
522
+ const apart = isTitle(start.host) || isTitle(end.host);
523
+ if (![start.host, end.host].every((host) => !host || isPiece(host))) {
515
524
  say(t("跨块删除只支持正文、标题和列表里的文字。"));
516
525
  return false;
517
526
  }
@@ -553,9 +562,14 @@ export function createTextSelection({ isEditing, struct, say, keepText, selectUn
553
562
  }
554
563
  for (const target of targets) takeOut(target);
555
564
  // Joined unless the two cannot be (a block that may not merge, lists that cannot go along):
556
- // then each keeps what is left of its text.
557
- if (start.host && end.host && mergeInto(start.host, end.host, { anyKind: true }) && endTarget !== end.host && endTarget.isConnected) takeOut(endTarget);
558
- if (start.host) joinCode(start.host); // inline code meeting inline code at the join is one piece
565
+ // then each keeps what is left of its text. Apart from the title, the last block left empty
566
+ // goes as the blocks between do (it was all selected), else it stays with its rest.
567
+ if (apart) {
568
+ const last = isTitle(end.host) ? null : end.host;
569
+ if (last && endTarget && isEmpty(last) && can(last, "remove") && !keepText(endTarget)) takeOut(endTarget);
570
+ } else if (start.host && end.host && mergeInto(start.host, end.host, { anyKind: true }) && endTarget !== end.host && endTarget.isConnected) takeOut(endTarget);
571
+ if (start.host && !apart) joinCode(start.host); // inline code meeting inline code at the join is one piece
572
+ if (isTitle(start.host) && isEmpty(start.host)) start.host.replaceChildren(); // no <br> left in an emptied title
559
573
  return { touched: touched.filter((host) => host.isConnected), focus: start.host ?? end.host ?? null };
560
574
  });
561
575
  if (!result) return false;
@@ -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
+ }
@@ -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).
@@ -61,8 +63,43 @@ export function createTyping({ struct, say, keepText, paragraphBefore, removeBlo
61
63
  return Boolean(key(pageOf(host)?.keys ?? {})?.(ctx, ...rest) || pagesAround(host).some((page) => key(page.keys?.around ?? {})?.(ctx, ...rest)));
62
64
  }
63
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
+
64
100
  // Enter.
65
101
  function split(host) {
102
+ if (HOSTS[host.getAttribute("data-ge-kind")]?.opensBody) return enterBody(host);
66
103
  // The caret at the very start of a block with text: an empty paragraph goes before the block and
67
104
  // the caret stays (a block that splits does this itself, splitBlock). This comes first: in a code
68
105
  // block too, whose own Enter breaks the line.
@@ -266,10 +303,23 @@ export function createTyping({ struct, say, keepText, paragraphBefore, removeBlo
266
303
  if (hint) host.setAttribute("data-ge-placeholder", hint);
267
304
  else host?.removeAttribute("data-ge-placeholder");
268
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
+ }
269
319
  }
270
320
 
271
321
  return {
272
- split, backspace, forwardDelete, autoSpace, updatePlaceholder,
322
+ split, backspace, forwardDelete, autoSpace, updatePlaceholder, untitled,
273
323
  /** Tab (`back`: Shift+Tab). Whether the key was taken. */
274
324
  tab: (host, back) => asked((keys) => keys.tab, host, back),
275
325
  /** Ctrl+Enter. Whether the key was taken. */
@@ -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;