@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
@@ -1,6 +1,5 @@
1
1
  import { MEDIA_BLOCKS, MEDIA_CLASS, mediaBlockOf } from "../../../shared/components/index.mjs";
2
2
  import { caretAt } from "../../page/caret.mjs";
3
- import { UNIT } from "../../page/core.mjs";
4
3
  import { openMediaMenu } from "../../page/media-menu/index.mjs";
5
4
  import { keptByComponent } from "../../page/page-objects.mjs";
6
5
  import { blobBase64 } from "../../page/post.mjs";
@@ -8,6 +7,7 @@ import { addStyle } from "../../page/ui.mjs";
8
7
  import { barClass } from "../placeholder-bar.mjs";
9
8
  import { captionOf } from "./parts.mjs";
10
9
  import { TOOLBAR_STYLE } from "./toolbar.mjs";
10
+ import { ZWSP } from "../../../shared/inline-spacing.mjs";
11
11
  import { t } from "../../../shared/i18n/index.mjs";
12
12
 
13
13
  // What the four media blocks (图片, 文件, 网页书签, 嵌入) do on the page alike (notion-lite's
@@ -15,13 +15,17 @@ import { t } from "../../../shared/i18n/index.mjs";
15
15
  // block's menu; what is chosen replaces the placeholder with a NEW element (never the same one, so
16
16
  // that undo brings back the placeholder as it was and the file loses the block); a caption shows
17
17
  // once it is asked for or focused, goes out of sight when it is left empty, and Enter in it makes a
18
- // paragraph after the block. What a block makes of what is chosen (its picture, row, card or frame),
19
- // its menu, rows and tools are its own (image/, file/, bookmark/, embed/ page.mjs).
18
+ // paragraph after the block; Backspace or Delete in an empty one closes it and selects its block. It
19
+ // is plain text under the block, with no fill under the pointer or the caret. What a block makes of
20
+ // what is chosen (its picture, row, card or frame), its menu, rows and tools are its own (image/,
21
+ // file/, bookmark/, embed/ page.mjs).
20
22
 
21
23
  const STYLE = `${TOOLBAR_STYLE}
22
24
  /* A caption is shown with words, while it has the caret, or once 标题 asks for it (data-ge-caption), with Notion's placeholder. */
23
25
  ${MEDIA_BLOCKS.map((id) => `[data-ge-editing] .${MEDIA_CLASS[id]}[data-ge-caption] > figcaption`).join(", ")} { display: block; }
24
26
  ${MEDIA_BLOCKS.map((id) => `[data-ge-editing] .${MEDIA_CLASS[id]} > figcaption:empty::before`).join(", ")} { content: ${JSON.stringify(t("写一个标题…"))}; color: var(--ge-tx3); }
27
+ /* A caption is plain text under its block, as Notion's and Feishu's: no fill under the pointer or the caret (editor.mjs's --ge-text-tint). */
28
+ [data-ge-editing] [data-ge-kind="mediaCaption"][contenteditable="true"] { --ge-text-tint: none; }
25
29
  `;
26
30
 
27
31
  // Every media placeholder (a gray bar), by the selector the page finds it by.
@@ -30,6 +34,10 @@ const BARS = MEDIA_BLOCKS.map((id) => `main figure.${MEDIA_CLASS[id]} > .${barCl
30
34
  // What a placeholder's words were before something was under way (busy), by the words' element.
31
35
  const idleWords = new WeakMap();
32
36
 
37
+ // A caption with nothing in it: no words, no chip (a formula, a page's link); what the browser or a
38
+ // pad leaves (a <br>, a zero-width space) is nothing. A space is something: Backspace takes it.
39
+ const blank = (text) => !text.textContent.replaceAll(ZWSP, "") && !text.querySelector("[data-ge-atom]");
40
+
33
41
  /**
34
42
  * The media blocks on the page, with what the editor gives them: struct (an undo step), say,
35
43
  * active() (the block tools may act), blocks() (the block tools), newParagraph(parent, after),
@@ -78,6 +86,30 @@ export function create({ struct, finishStep, look, say, active, blocks, newParag
78
86
  event.preventDefault();
79
87
  newParagraph(figure.parentElement, figure);
80
88
  }, true);
89
+ // Backspace or Delete in an empty caption closes it (the user's rule, 2026-11-06; Notion's and
90
+ // notion-lite's do nothing there): out of sight as when the caret leaves it, the file keeping its
91
+ // empty <figcaption> (no undo step: nothing of the file changes), and its block selected, as Esc
92
+ // there does and as Backspace selects a block above that holds no text (typing/): Backspace again
93
+ // deletes the block. A key held down stops at the empty caption (`repeat`), so that holding
94
+ // Backspace to clear its words never takes the block with them.
95
+ document.addEventListener("keydown", (event) => {
96
+ if ((event.key !== "Backspace" && event.key !== "Delete") || event.ctrlKey || event.metaKey || event.altKey || event.isComposing || event.keyCode === 229) return;
97
+ const text = event.target?.closest?.('[data-ge-kind="mediaCaption"]');
98
+ const figure = text?.parentElement?.closest("figure");
99
+ if (!figure || !active() || !blank(text)) return;
100
+ event.preventDefault();
101
+ event.stopImmediatePropagation();
102
+ if (!event.repeat) closeCaption(text, figure);
103
+ }, true);
104
+
105
+ // A caption closed: emptied of what the browser left, its mark gone, its block selected (which
106
+ // takes the focus off it; where the block cannot be selected, the focus leaves it all the same).
107
+ function closeCaption(text, figure) {
108
+ text.replaceChildren();
109
+ figure.removeAttribute("data-ge-caption");
110
+ select(figure);
111
+ if (text.contains(document.activeElement)) text.blur();
112
+ }
81
113
 
82
114
  /** The parts the editing of media block `id` is made from. */
83
115
  function block(id) {
@@ -133,25 +165,23 @@ export function create({ struct, finishStep, look, say, active, blocks, newParag
133
165
  if (!pasted) select(next);
134
166
  else if (picked) blocks().select(next, { quiet: true });
135
167
  },
136
- /** The caption shown (an empty one too), the caret at its end. */
168
+ /** The caption shown (an empty one too), the caret at its end, no block left selected (notion-lite's editCaption: setSelection([])). */
137
169
  caption(figure) {
138
170
  const text = figure && captionOf(figure);
139
171
  if (!text) return;
172
+ blocks()?.clear();
140
173
  figure.setAttribute("data-ge-caption", "");
141
174
  caretAt(text, "end");
142
175
  },
143
176
  /**
144
- * `file` pasted into `host` (a text block): a new block made by `make(doc)` below its block, then
145
- * `fill(figure, file)` (its placeholder filled). Returns whether it took the file.
177
+ * `file` pasted: a new block made by `make(doc)`, put in its place by `put` (the paste's, clipboard/:
178
+ * where a block pasted there goes, one undo step; false when it could not), then `fill(figure, file)`
179
+ * (its placeholder filled). Returns whether it took the file.
146
180
  */
147
- paste(host, file, make, fill) {
148
- const unit = host?.closest?.(UNIT);
149
- if (!file || !unit?.parentElement) return false;
150
- const figure = make(host.ownerDocument);
151
- struct([unit.parentElement], [], () => {
152
- unit.after(figure);
153
- return { touched: [], focus: null };
154
- });
181
+ paste(put, file, make, fill) {
182
+ if (!file) return false;
183
+ const figure = make(document);
184
+ if (!put(figure)) return false;
155
185
  fill(figure, file);
156
186
  return true;
157
187
  },
@@ -1,5 +1,4 @@
1
1
  import { create as bookmark } from "./bookmark/page.mjs";
2
- import { create as callout } from "./callout/page.mjs";
3
2
  import { create as code } from "./code/page.mjs";
4
3
  import { create as columns } from "./columns/page.mjs";
5
4
  import { create as details } from "./details/page.mjs";
@@ -15,6 +14,7 @@ import { create as installed } from "./installed/page.mjs";
15
14
  import { create as list } from "./list/page.mjs";
16
15
  import { create as math } from "./math/page.mjs";
17
16
  import { create as media } from "./media/page.mjs";
17
+ import { create as heading } from "./heading/page.mjs";
18
18
  import { create as paragraph } from "./paragraph/page.mjs";
19
19
  import { create as section } from "./section/page.mjs";
20
20
  import { create as sheets } from "./sheets/page.mjs";
@@ -29,7 +29,7 @@ import { create as table } from "./table/page.mjs";
29
29
  // listeners onto the document as it is made, and media comes before the four blocks made of its
30
30
  // parts (block(id)). It is also the order they are asked in where every one is: the columns tidy
31
31
  // before the lists (`tidy`), an image takes a pasted file before a file block does (`acceptsFile`).
32
- const PAGES = { columns, code, list, flowchart, nodeAdder, details, dialog, callout, paragraph, section, icon, sheets, sheetPills, figure, media, image, file, bookmark, embed, math, table, installed };
32
+ const PAGES = { columns, code, list, flowchart, nodeAdder, details, dialog, paragraph, heading, section, icon, sheets, sheetPills, figure, media, image, file, bookmark, embed, math, table, installed };
33
33
 
34
34
  /**
35
35
  * Every component's page object, by its component's name (and the flowchart's "+", nodeAdder, and a
@@ -23,6 +23,7 @@ import sheets from "./sheets/index.mjs";
23
23
  import table from "./table/index.mjs";
24
24
  import widget from "./widget/index.mjs";
25
25
  import { CATEGORIES, componentOf } from "../../shared/components/index.mjs";
26
+ import { slotAround } from "../../shared/components/installed.mjs";
26
27
  import { COLOR_CLASSES } from "./colors.mjs";
27
28
  import { MEDIA_HOSTS } from "./media/parts.mjs";
28
29
  import { t } from "../../shared/i18n/index.mjs";
@@ -34,14 +35,16 @@ import { t } from "../../shared/i18n/index.mjs";
34
35
  // whose category it takes: a basic block, a container, a card or a whole block (CATEGORIES there).
35
36
  // Each describes itself:
36
37
  //
37
- // listed what 设置 › 组件 calls it (a function, as the server says it in both languages), for a
38
+ // listed what 设置 › 组件列表 calls it (a function, as the server says it in both languages), for a
38
39
  // component the reader meets in the "/" menu or as a block of its own; every component
39
- // with a type in that menu says it. hideable: false, it stays offered whatever gallery.json
40
+ // with a type in that menu says it. Its line there shows the icon of its first row in the
41
+ // "/" menu (basic before advanced, by place), or, for a component with no type there (分区),
42
+ // its first unit's `icon`; a listed component with neither throws. hideable: false, it stays offered whatever gallery.json
40
43
  // says, its switch there off and locked (文本, 标题, 列表, 分区): what a page cannot do
41
44
  // without. What is hidden goes from "/", 在下方新建 and the handle's grid and nothing else
42
45
  // (page/offered.mjs); its blocks, its Markdown shortcut and "Blocks at a glance" stay.
43
46
  // units the unit kinds it defines (blocks the reader selects, moves and deletes):
44
- // { [kind]: { name, icon?, match, chapter?, fixed?, block?, handle?, below?, boxed?, beside?, inRow?, sharesHeight?, entersAfter?, resizable?, copy?, clipboard?, sizes?, toggles?, colors?, colorDefaults?, removedEmpty?, turnsEmpty?, canHaveChildren?, emptyIsNothing?, fromWords?, attributes? } }
47
+ // { [kind]: { name, icon?, match, chapter?, fixed?, block?, handle?, below?, boxed?, beside?, inRow?, sharesHeight?, entersAfter?, resizable?, copy?, clipboard?, sizes?, toggles?, colors?, colorDefaults?, removedEmpty?, turnsEmpty?, leadsChapter?, canHaveChildren?, emptyIsNothing?, fromWords?, attributes? } }
45
48
  // match: rules an element matches by its tag (one of `tag`), its class and its
46
49
  // attribute, and by the element it stands in (`parent`: { tag?, class? }, a flowchart's
47
50
  // step being an li whose parent is an ol.doc-flow), whichever are given; every
@@ -80,25 +83,30 @@ import { t } from "../../shared/i18n/index.mjs";
80
83
  // the page, each with the test of its values. icon: what its handle shows, for a
81
84
  // kind no block type stands for (a type's own icon is its `types` entry's). removedEmpty:
82
85
  // Backspace on the one empty block in it deletes it whole (a code block, a highlight block,
83
- // a quote, a disclosure: typing/). turnsEmpty: it holds nothing to carry, so what it is
86
+ // a callout, a quote, a disclosure: typing/). turnsEmpty: it holds nothing to carry, so what it is
84
87
  // turned into is an empty block of the type, in its place (a divider line: convert.mjs).
88
+ // leadsChapter: it may stand first in a chapter as the line above its heading, so a
89
+ // folded heading with only such blocks before it covers the chapter (a divider: fold/rule.mjs).
85
90
  // canHaveChildren: notion-lite's, a block right after it goes under it by Tab, so the
86
91
  // keys of a block stand after it as they stand in what it is in (a list: under its last item).
87
92
  // emptyIsNothing: a block of it left empty counts as nothing written, in a container
88
93
  // that says `removedEmpty`. fromWords: a block of it can be made again from its words alone.
89
94
  // boxes the box kinds it defines (containers whose children are units): { [kind]: { role,
90
- // name?, classes?, find?, owner?, takenBy?, also?, leaveByEnter?, lead?, firstLineActs?, firstBlock?, groups?, holdsOne?, emptyIsNothing?, outer?, selectAll? } }, classes being the kit's classes that make an element one
95
+ // name?, classes?, find?, owner?, takenBy?, also?, leaveByEnter?, endIsPadding?, lead?, firstLineActs?, firstBlock?, groups?, holdsOne?, emptyIsNothing?, outer?, selectAll? } }, classes being the kit's classes that make an element one
91
96
  // (rank order, as above); the others the server knows by their tag (findUnits). find: where
92
97
  // a unit's box of this kind is (a list item's lists, a disclosure's content, a Sheet area's
93
- // panels); owner: the element of its unit that takes the box along (a Sheet panel's tab:
98
+ // panels, an instance's slots by their name: `find(unit, key)`); owner: the element of its unit that takes the box along (a Sheet panel's tab:
94
99
  // boxOwner); takenBy: whether a unit's element is that one, for a box of this key, told from
95
100
  // the element alone, which may be off the page with the box (takesBox);
96
101
  // also: the unit kinds it takes besides what its role takes (a highlight block's icon);
97
102
  // leaveByEnter: Enter on its empty last block moves that block out after it (typing/leave.mjs);
103
+ // endIsPadding: what is under its last block is its own padding (a highlight block, a
104
+ // callout, a disclosure's content): a click there makes no block, it is a gap like any other
105
+ // (geometry.mjs endOf, insert/ clickBlank);
98
106
  // lead: the kind of unit it opens with as its fixed head, which is no block to fall
99
107
  // between (a highlight block's icon: a box selection passes over it, a place before it is
100
108
  // the place after it); firstLineActs: its first block shows the container's handle, not a
101
- // handle of its own (Notion's disableFirstItemHoverMenu: a highlight block's, a quote's);
109
+ // handle of its own (Notion's disableFirstItemHoverMenu: a highlight block's, a callout's, a quote's);
102
110
  // firstBlock: the type its first block (after its lead) always is, its first line (a
103
111
  // flowchart's node: "paragraph", its title), which is turned into no other type (no
104
112
  // 转换为, no Markdown shortcut there) and has nothing made, dropped or pasted before it;
@@ -107,7 +115,7 @@ import { t } from "../../shared/i18n/index.mjs";
107
115
  // groups: a plain <div> with no class in it is a group of blocks, not a block of its own (the
108
116
  // same boxes as the shared descriptions' GROUPING_FLOWS: tests/unit/components.mjs);
109
117
  // holdsOne: a change that leaves it empty puts an empty paragraph in it, so there is always a
110
- // block to write in (a disclosure's content, a highlight block: core.mjs tidyEmptied);
118
+ // block to write in (a disclosure's content, a highlight block, a callout: core.mjs tidyEmptied);
111
119
  // emptyIsNothing: as on a unit, of a box that is an element of its own, by its `classes`;
112
120
  // outer: false, a block straight in it has no block around it for the reader, whatever
113
121
  // stands around its element: no 选中外层 (a detail card's content: block-info.mjs outerOf);
@@ -121,38 +129,42 @@ import { t } from "../../shared/i18n/index.mjs";
121
129
  // sealed a selector: what stands in such an element is no text of a text block around it, as
122
130
  // a list item holding it (caret.mjs editable): its own text blocks are the only hosts in it
123
131
  // readOnly why an element of it stays read-only, on hover and on a click (hints/): rules
124
- // { rank, at, says }, at a selector found from the element (closest), says the reason
132
+ // { rank, at, says }, at a selector found from the element (closest), or a function
133
+ // of the element saying whether the rule is its (an instance's own region, heldBy, which
134
+ // no selector tells from its slots), says the reason
125
135
  // in the reader's words, or null for an element that needs none, having a tool of its
126
136
  // own. Every component's rules are tried in `rank` order, with the page's (PAGE below),
127
137
  // and the first match wins: a rule ranked below the page's 80 goes before any control's,
128
138
  // and is the one that can claim a button as its own.
129
- // hosts the kinds of text block it defines (data-ge-kind): { [kind]: { name, caps, tex?, wrapped?, parts?, whole?, takes?, opensBefore?, opensAfter?, textFilters?, formula?, closed?, inner?, blankSays?, placeholder? } }, caps
139
+ // hosts the kinds of text block it defines (data-ge-kind): { [kind]: { name, caps, tex?, wrapped?, parts?, opensBefore?, textFilters?, formula?, closed?, inner?, pictures?, blankSays?, placeholder?, untitled?, opensBody? } }, caps
130
140
  // ({ bound, blockLevel }) giving what such a text block can do (source/); opensBefore:
131
141
  // Enter at its very start, with words in it, puts an empty paragraph before its block
132
- // where it does not split, as one that splits does (typing/); opensAfter: Enter at its
133
- // very end, a paragraph after its block, where it does not split; textFilters: false, what
142
+ // where it does not split, as one that splits does (typing/); textFilters: false, what
134
143
  // is typed in it is taken as it is, no inline code, no space set by itself (notion-lite's);
135
144
  // formula: false, no inline formula is offered in it or pasted as one, the kit drawing
136
145
  // none there (takesFormula);
137
146
  // closed: the page holds no text block for it until the reader opens it (a code block);
138
147
  // inner(element): the text a save takes of one, as markup, where that is not what its
139
- // nodes say (a code block's code);
148
+ // nodes say (a code block's code); pictures: it holds pictures amid its words (a table
149
+ // cell's), { show(root) (the file's made the page's: where the server serves them),
150
+ // write(element) (one's markup, "" for one of no file, null for no picture) } (core.mjs);
140
151
  // parts: the parts of components ([component id, part name]: a part of its shared
141
152
  // description edited as text, src/shared/components/) whose elements are text blocks
142
- // of this kind, found so by the server's scan; whole: the element (a selector) that is one
143
- // text block of this kind, by the scan too, while it holds inline text alone (a callout); takes: the tag of a
144
- // block that, standing alone in `whole` with nothing of its own, natural HTML makes its words; tex: its text is a formula's TeX alone; wrapped: the page makes the text block a
153
+ // of this kind, found so by the server's scan; tex: its text is a formula's TeX alone; wrapped: the page makes the text block a
145
154
  // span inside the element, which keeps its own behaviour (a Sheet tab's button);
146
155
  // blankSays: what the status line says of one left blank that must hold words, as a
147
156
  // type's says of a block of it (blankSaysOf); placeholder: what one says while it
148
- // is empty under the caret, whatever part it is (placeholderOf)
157
+ // is empty under the caret, whatever part it is (placeholderOf); untitled: it says its
158
+ // placeholder whenever it is empty, the caret in it or not (the page's title, notion-lite's
159
+ // data-ph 新页面: typing/ updatePlaceholder); opensBody: Enter in it goes to the body, what
160
+ // follows the caret a new paragraph right below it (the page's title: typing/ enterBody)
149
161
  // placeholders what an empty text block says while the caret is in it: { [part]: text }, part
150
162
  // being a part of its shared description (src/shared/components/) whose element it is
151
163
  // (placeholderOf); a heading's own is its type's `placeholder`, and a type's `placeholder:
152
164
  // false` says nothing where a block of it would (a list item)
153
165
  // types the blocks the reader can make on the page or turn a block into (the "/" menu,
154
166
  // Markdown shortcuts, the block menu), written by the server in the kit's plain markup:
155
- // { [type]: { tag, className?, kind, host?, box?, leaf?, wraps?, container?, part?, text?, inside?, tex?,
167
+ // { [type]: { tag, className?, kind, box?, leaf?, wraps?, container?, part?, text?, inside?, tex?,
156
168
  // empty?, resettable?, bare?, placeholder?, bar?, label?, icon?, hint?, markdown?, words?, turn?, menu?, fresh?,
157
169
  // corner?, preload?, onSplit?, create?, takesAsIs?, holder?, nests?, joins?, leadIcon?, fromSelection?, clipboard?, glance? } } and, for the blocks the page
158
170
  // and the server write apart from text, title?, content?, keyed?, written?,
@@ -165,7 +177,7 @@ import { t } from "../../shared/i18n/index.mjs";
165
177
  // quote's paragraph, a list item: notion-lite's `resettable`, typing/leave.mjs). leaf: the text block a block turned
166
178
  // into the type becomes; wraps: such a text block sits in a container of the type, found
167
179
  // by `container` (a selector); text: a plain text leaf; empty: a leaf written with no
168
- // text too (a paragraph, a heading, a list item, a code block, a callout: an empty
180
+ // text too (a paragraph, a heading, a list item, a code block: an empty
169
181
  // one stays, as Notion's; the page's core.mjs and the server's source/checks.mjs read
170
182
  // this and nothing else); inside: the element its text is written in, as plain text
171
183
  // (a code block's code element); tex: its text is a formula's TeX alone (a display
@@ -180,8 +192,7 @@ import { t } from "../../shared/i18n/index.mjs";
180
192
  // over (page/markdown/rules.mjs); turn: its place among
181
193
  // the types a text block is turned into; fresh: its place among the types made as an
182
194
  // empty block that stands for an empty one; menu: [group, place], its place in the "/"
183
- // menu (group "basic" or "advanced"), which the block menu's 在下方新建 shows too; host: the
184
- // kind of text block a new one is (`hosts`; "flow" without: core.mjs newHost); corner: the
195
+ // menu (group "basic" or "advanced"), which the block menu's 在下方新建 shows too; corner: the
185
196
  // type in whose cell of a type grid it sits, as a gray corner, when the grid has both
186
197
  // (type-grid.mjs); preload: true, it needs something on the page as soon as a type grid
187
198
  // offers it, and before a block with text is turned into it, which its page object's
@@ -197,7 +208,7 @@ import { t } from "../../shared/i18n/index.mjs";
197
208
  // paragraph. It returns the node the caret or the choice goes to (null: none); a type
198
209
  // without is a text block, made by convert.mjs standIn.
199
210
  // takesAsIs: a block turned into it goes into it as it is, each keeping its type (a
200
- // highlight block, a disclosure); holder: its place among the containers that turn into
211
+ // highlight block, a callout, a disclosure); holder: its place among the containers that turn into
201
212
  // one another, what they hold carried along; nests: false, none inside another of its
202
213
  // kind; joins: false, a block turned into it never joins the one beside it; leadIcon: the
203
214
  // icon a new one opens with; fromSelection: { label, icon }, its row of the format bar's
@@ -295,8 +306,10 @@ import { t } from "../../shared/i18n/index.mjs";
295
306
  // label, width }, or null; reason: why the block may not go, remove(): delete it); rowBeside(target),
296
307
  // a row for a block of another component, beside its color, every page object being asked and each
297
308
  // testing the block itself; acceptsFile(file), whether a file pasted makes a block of it, and
298
- // fromFiles(host, files), that block made below the block of `host` (notion-lite's, which gives the
299
- // data of a new block; the first page object that takes a file in their order); fromLink(figure,
309
+ // fromFiles(put, files), that block made and handed to `put(block)`, the paste's, which puts it where a
310
+ // block pasted at the caret goes (one undo step) and says whether it could (notion-lite's
311
+ // createFromFiles(files, width, place), whose fromFiles gives the data of a new block and whose place
312
+ // the paste gives; the first page object that takes a file in their order); fromLink(figure,
300
313
  // url, options), a block of the component filled from an address (notion-lite's, here the figure
301
314
  // is there first: one pasted with its address, `{ pasted: true }`, a bookmark in an embed's place).
302
315
  // What the rest of the editor asks of a component that does something of its own where every block
@@ -336,8 +349,17 @@ import { t } from "../../shared/i18n/index.mjs";
336
349
  // A new kit component gets a folder of its own and a line below.
337
350
  export const COMPONENTS = [paragraph, heading, list, flowchart, quote, callout, highlight, details, code, divider, section, sheets, table, figure, image, file, bookmark, embed, columns, math, dialog, widget, icon, installed];
338
351
 
339
- /** The built-in components 设置 › 组件 lists: { id, name() (in the language t() says it in), hideable }, by the order above. */
340
- export const LISTED_BLOCKS = COMPONENTS.filter((component) => component.listed).map(({ name, listed, hideable = true }) => ({ id: name, name: listed, hideable }));
352
+ // The "/" menu's groups, in order (MENU_GROUPS below says the same).
353
+ const MENU_GROUP_ORDER = ["basic", "advanced"];
354
+ const menuRank = ({ menu }) => MENU_GROUP_ORDER.indexOf(menu[0]) * 1000 + menu[1];
355
+ // The mark of a component's line in 设置 › 组件列表: the icon of its first row in the "/" menu, the
356
+ // same drawing; one with no type there (分区) shows its first unit's (`icon`, a kind no type stands for).
357
+ const listedIcon = ({ types = {}, units = {} }) => Object.values(types).filter((spec) => spec.menu && spec.icon).sort((a, b) => menuRank(a) - menuRank(b))[0]?.icon
358
+ ?? Object.values(units).find((unit) => unit.icon)?.icon ?? null;
359
+
360
+ /** The built-in components 设置 › 组件列表 lists: { id, name() (in the language t() says it in), icon (svg markup), hideable }, by the order above. */
361
+ export const LISTED_BLOCKS = COMPONENTS.filter((component) => component.listed).map((component) => ({ id: component.name, name: component.listed, icon: listedIcon(component), hideable: component.hideable ?? true }));
362
+ for (const { id, icon } of LISTED_BLOCKS) if (!icon) throw new Error(`component ${id} has a line in the settings (listed), so it needs an icon: a type in the "/" menu, or a unit's icon`);
341
363
 
342
364
  /** The names of those the reader may hide. */
343
365
  export const HIDEABLE = new Set(LISTED_BLOCKS.filter(({ hideable }) => hideable).map(({ id }) => id));
@@ -363,7 +385,11 @@ const PAGE = {
363
385
  hosts: {
364
386
  // A free text block may be left empty (Notion's): written as an empty element, one line high.
365
387
  flow: { opensBefore: true, caps: ({ bound }) => bound ? ["split", "merge", "links"] : ["split", "merge", "remove", "empty", "links"] },
366
- title: { name: t("文档主标题"), caps: () => ["plain"], blankSays: t("文档主标题还空着:写上标题后才会保存。") },
388
+ // The page's title may be left empty (notion-lite's page title): an untitled document, its title
389
+ // saying 未命名文档 in gray (`untitled`), never written into the file; whatever names the document
390
+ // names it so (the workbench's reportTitle, links/pages.mjs, an export's <title>). Enter in it goes to the
391
+ // body (`opensBody`: typing/ enterBody, notion-lite's page title).
392
+ title: { name: t("文档主标题"), caps: () => ["plain", "empty"], placeholder: t("未命名文档"), untitled: true, opensBody: true },
367
393
  ...MEDIA_HOSTS,
368
394
  },
369
395
  readOnly: [
@@ -487,7 +513,7 @@ export const FRESH = inOrder((spec) => spec.fresh);
487
513
  export const HOLDERS = inOrder((spec) => spec.holder);
488
514
 
489
515
  /** The "/" menu's groups of block types, in order: { basic, advanced } (the menu says their names). */
490
- export const MENU_GROUPS = Object.fromEntries(["basic", "advanced"].map((group) => [group, inOrder((spec) => (spec.menu?.[0] === group ? spec.menu[1] : undefined))]));
516
+ export const MENU_GROUPS = Object.fromEntries(MENU_GROUP_ORDER.map((group) => [group, inOrder((spec) => (spec.menu?.[0] === group ? spec.menu[1] : undefined))]));
491
517
 
492
518
  /** The types a block is made of from selected text, each with its row of the format bar's 更多 (`fromSelection`). */
493
519
  export const FROM_SELECTION = Object.entries(BLOCK_TYPES).filter(([, spec]) => spec.fromSelection).map(([type, spec]) => ({ type, ...spec.fromSelection }));
@@ -538,9 +564,12 @@ const ONE_BLOCK_AT = ONE_BLOCK.map(({ at }) => at).join(", ");
538
564
  /** What no text block around it reaches into (`sealed`), a selector, "" where no component says. */
539
565
  export const SEALED = COMPONENTS.map((component) => component.sealed).filter(Boolean).join(", ");
540
566
 
567
+ // What is one block is found inside the slot whose inside is the document's region an element stands
568
+ // in, where it does (an instance's slot holds blocks of their own: installed.mjs slotAround).
541
569
  const oneBlockOf = (element) => {
542
- let whole = element.closest(ONE_BLOCK_AT);
543
- for (let around = whole; around; around = around.parentElement?.closest(ONE_BLOCK_AT)) whole = around;
570
+ const region = slotAround(element);
571
+ let whole = null;
572
+ for (let around = element.closest(ONE_BLOCK_AT); around && (!region || region.contains(around)); around = around.parentElement?.closest(ONE_BLOCK_AT)) whole = around;
544
573
  return whole && ONE_BLOCK.find(({ at }) => whole.matches(at)).name;
545
574
  };
546
575
 
@@ -554,7 +583,8 @@ const textPartOf = (element) => TEXT_PARTS.find(({ match, at }) => [...(element.
554
583
 
555
584
  /**
556
585
  * The component an element is of, by name, or null. Nothing inside an element that is one block is
557
- * anyone else's, whatever its tag or class (a cell's list, a Sheet's tab). Else that of its kind of text
586
+ * anyone else's, whatever its tag or class (a cell's list, a Sheet's tab), but what an instance's slot
587
+ * holds, the document's blocks, each its own. Else that of its kind of text
558
588
  * block, where a component defines the kind (a cell, a tab's name), that of the text part of a
559
589
  * component it is, that of the unit it is (a flowchart's node, though an li) and last that of its type
560
590
  * (a list's item made on the page). What stands in a container is its own component's, not the
@@ -598,7 +628,7 @@ export const takesBox = (element, { kind, key }) => Boolean(element && BOXES[kin
598
628
  const FROM_WORDS = flagged("fromWords");
599
629
  export const PLAIN_TEXT = new Set(Object.keys(BLOCK_TYPES).filter((type) => FROM_WORDS.has(BLOCK_TYPES[type].kind)));
600
630
 
601
- /** Plain text leaves (paragraphs, small text, headings, callouts). */
631
+ /** Plain text leaves (paragraphs, small text, headings). */
602
632
  export const TEXT_TYPES = new Set(Object.keys(BLOCK_TYPES).filter((type) => BLOCK_TYPES[type].text));
603
633
 
604
634
  /** The heading type of each heading tag (H1 -> heading1). */
@@ -682,6 +712,8 @@ const ROLES = Object.fromEntries(Object.entries(BOXES).map(([kind, box]) => [kin
682
712
  /** What a chapter is: the page and Sheet panels hold these besides body text. */
683
713
  export const CHAPTER = flagged("chapter");
684
714
  const FIXED = flagged("fixed"); // never inside a flow
715
+ /** What may stand first in a chapter as the line above its heading (`leadsChapter`: a divider, fold/). */
716
+ export const LEADS_CHAPTER = flagged("leadsChapter");
685
717
 
686
718
  /** The kinds of box a plain <div> without a class is a group of blocks in (`groups`; source/units.mjs boxKind). */
687
719
  export const GROUPING = new Set(Object.keys(BOXES).filter((kind) => BOXES[kind].groups));
@@ -695,6 +727,9 @@ export const HOLDS_ONE = new Set(Object.keys(BOXES).filter((kind) => BOXES[kind]
695
727
  /** The box kinds whose empty last block Enter moves out after the box (`leaveByEnter`). */
696
728
  export const LEAVES_BY_ENTER = new Set(Object.keys(BOXES).filter((kind) => BOXES[kind].leaveByEnter));
697
729
 
730
+ /** Whether what is under the last block of a box of this kind is its own padding (`endIsPadding`): a click there makes no block (geometry.mjs endOf). */
731
+ export const endIsPadding = (boxKind) => Boolean(BOXES[boxKind]?.endIsPadding);
732
+
698
733
  /** The unit kinds Backspace deletes whole once nothing is written in them (`removedEmpty`). */
699
734
  export const REMOVED_EMPTY = Object.keys(UNITS).filter((kind) => UNITS[kind].removedEmpty);
700
735
 
@@ -742,7 +777,7 @@ export const hasOuter = (boxKind) => BOXES[boxKind]?.outer !== false;
742
777
  /** The unit kinds with a frame of their own (`boxed`): a double click between two makes a paragraph (insert/). */
743
778
  export const BOXED = flagged("boxed");
744
779
 
745
- /** The unit kinds a click to the right of one selects: the boxed ones and those that say `beside` (beside.mjs). */
780
+ /** The unit kinds a click to the right of one, past the text area it stands in, selects: the boxed ones and those that say `beside` (beside.mjs). */
746
781
  export const BESIDE = new Set([...BOXED, ...flagged("beside")]);
747
782
 
748
783
  /** Whether a unit of this kind stands beside another now, `element` being that unit (`beside`, `inRow`). */
@@ -1,3 +1,4 @@
1
+ import { SECTION_ICON } from "../icons.mjs";
1
2
  import { HIGHLIGHT } from "../kit.mjs";
2
3
  import { t } from "../../../shared/i18n/index.mjs";
3
4
  // 分区: section.doc-section, a container of ordinary blocks (its title is whatever heading it
@@ -18,7 +19,7 @@ export default {
18
19
  name: "section",
19
20
  listed: () => t("分区"), hideable: false,
20
21
  units: {
21
- section: { name: t("分区"), match: [{ rank: 40, tag: "section" }], chapter: true, fixed: true, handle: "bar" },
22
+ section: { name: t("分区"), icon: SECTION_ICON, match: [{ rank: 40, tag: "section" }], chapter: true, fixed: true, handle: "bar" },
22
23
  },
23
24
  boxes: {
24
25
  section: { role: "flow", name: t("分区"), groups: true },
@@ -0,0 +1,24 @@
1
+ import { escapeText } from "../../shared/escape.mjs";
2
+
3
+ /**
4
+ * How a box of blocks set apart (a highlight block, a callout: `match` its elements) is copied, one
5
+ * rule for both, their clipboard's hooks (registry.mjs `clipboard`) for the block of `type`: its
6
+ * blocks; one with words straight in it (an Agent's, a callout written the old way), a paragraph of
7
+ * what it says. A list with its class is a list, and a text block of a type of its own that type.
8
+ */
9
+ export const setApart = (type, match) => ({
10
+ describe(node, { isHost, holding, colorOf, copiedType, serializeInner, plain }) {
11
+ if (!node.matches(match) || node.matches("ul, ol") || (isHost(node) && copiedType(node))) return undefined;
12
+ const straight = [...node.childNodes].some((child) => child.nodeType === 3 && child.data.trim());
13
+ const words = isHost(node) ? serializeInner(node) : straight ? escapeText(plain(node)) : null;
14
+ const blocks = words === null ? holding(node) : [{ type: "paragraph", html: words }];
15
+ const color = colorOf(node);
16
+ return blocks ? { type, blocks, ...(color ? { color } : {}) } : null;
17
+ },
18
+ endsIn(unit, { blocksIn, boxesOf, colorOf }) {
19
+ if (!unit.matches(match)) return undefined;
20
+ const color = colorOf(unit);
21
+ return [{ type, blocks: blocksIn(boxesOf(unit)), ...(color ? { color } : {}) }];
22
+ },
23
+ check: (block, { container }) => container(block),
24
+ });
@@ -6,6 +6,8 @@ import { columnWidths, slotsOf, tileSlots, tileSpans } from "../../../shared/tab
6
6
  import { CELL_ALIGN_CLASSES, CELL_BOLD_CLASS, CELL_VALIGN_CLASSES } from "../../../shared/components/table.mjs";
7
7
  import { CHART_KEY, CHART_SOURCE } from "../../../shared/table-chart.mjs";
8
8
  import { t } from "../../../shared/i18n/index.mjs";
9
+ import { escapeAttribute } from "../../../shared/escape.mjs";
10
+ import { servedFile } from "../../page/served.mjs";
9
11
 
10
12
  const ICON = svg('<rect x="3.25" y="3.75" width="13.5" height="12.5" rx="2"/><path d="M3.25 8h13.5M3.25 12.1h13.5M8.25 3.75v12.5"/>');
11
13
 
@@ -53,7 +55,9 @@ export default {
53
55
  boxed: true,
54
56
  resizable: ".doc-table-wrap[data-ge-unit]", // its right and bottom edges, once it is in the file
55
57
  copy: "itself", // within the report a copy keeps all of its markup (its scope line, its frame's size); another report's gets the table's data (tableData) made anew
56
- attributes: { [NUMBERS]: (value) => value === "off" },
58
+ // 识别数字列 off, and the key a chart or a view reads it by (src/shared/table-chart.mjs), which 视图 ›
59
+ // of its menu puts on a table that has none (page/table/views.mjs) in the step that puts the view in.
60
+ attributes: { [NUMBERS]: (value) => value === "off", [CHART_SOURCE]: (value) => CHART_KEY.test(value) },
57
61
  sizes: {
58
62
  [SPAN]: { min: 0.15, max: 3 }, // past 1 the table is wider than the text and scrolls in its frame
59
63
  [TABLE_HEIGHT]: { min: 80, max: 4000, px: true, none: true, height: true },
@@ -62,7 +66,7 @@ export default {
62
66
  },
63
67
  components: ["doc-table-wrap", "doc-table-meta"],
64
68
  hosts: {
65
- cell: { name: t("表格单元格"), caps: () => ["empty", "links"] },
69
+ cell: { name: t("表格单元格"), caps: () => ["empty", "links"], pictures: { show: showPictures, write: writtenPicture } },
66
70
  },
67
71
  types: {
68
72
  // Made by a paste or the "/" menu (三列三行, a header row: page.mjs newTable): no class here, so
@@ -115,9 +119,11 @@ export const CELL_BOLD = CELL_BOLD_CLASS;
115
119
  export const CELL_LOOKS = [...BLOCK_COLORS, ...CELL_ALIGNS.map(([name]) => name), ...CELL_VALIGNS.map(([name]) => name), CELL_BOLD];
116
120
 
117
121
  /**
118
- * The look a cell takes when it becomes a header cell (a th: the header row's or column's toggle, a
119
- * row or column moved there, a cell made there: page.mjs) and loses when it stops being one: bold,
120
- * and the gray fill unless it has a color of its own. Nothing else of the kit's sets a header apart.
122
+ * The look a cell takes when it becomes a header row's cell (a th that is no row's header: 标题行's
123
+ * toggle, a row moved there, a cell made there: page.mjs) and loses when it stops being one: bold,
124
+ * and the gray fill unless it has a color of its own. A header column's cell (th scope="row") has
125
+ * none: 标题列 only makes the first column stay when the frame scrolls sideways (the user's,
126
+ * 2026-11-06). Nothing else of the kit's sets a header apart.
121
127
  */
122
128
  export const HEADER_LOOK = [CELL_BOLD, "doc-highlight-gray"];
123
129
 
@@ -304,3 +310,56 @@ export function tableData(element, serializeInner) {
304
310
  ...(chart && CHART_KEY.test(chart) ? { chart } : {}),
305
311
  };
306
312
  }
313
+
314
+ // ---------- a cell's pictures ----------
315
+ // 单元格里的图片 (page/table/pictures.mjs; source/blocks.mjs cellPictureProblem says what the file
316
+ // takes): an <img> amid a cell's words, a picture of the report's folder. On the page it shows where
317
+ // the server serves the folder (`src`, page/served.mjs), the file it is in data-ge-src, as an
318
+ // image block's; the cell's text writes it back from its element (the host's `pictures`, which
319
+ // core.mjs reads): <img src="assets/<file>" alt="…" width="N">, its attributes in the order the
320
+ // element has them, the file's own; one the browser put in from elsewhere, its file no picture of
321
+ // the folder, is no part of the text.
322
+
323
+ const PICTURE_FILE = /^assets\/[A-Za-z0-9][A-Za-z0-9._-]{0,80}$/;
324
+ const PICTURE_WIDTH = /^[1-9]\d{0,3}$/;
325
+ const isPicture = (node) => node?.nodeType === 1 && node.localName === "img";
326
+
327
+ /** The file of a picture in a cell (assets/<file>), or null: none the page writes. */
328
+ export const pictureFile = (img) => {
329
+ const file = img.getAttribute("data-ge-src") || img.getAttribute("src") || "";
330
+ return PICTURE_FILE.test(file) ? file : null;
331
+ };
332
+
333
+ /**
334
+ * A picture for a cell: the file `path` (assets/<file>) shown where the server serves it, its `alt`
335
+ * words, its `width` in pixels (none: the kit's own size).
336
+ */
337
+ export function cellPicture(doc, path, { alt = "", width = null } = {}) {
338
+ const img = doc.createElement("img");
339
+ img.setAttribute("src", servedFile(path));
340
+ img.setAttribute("alt", alt);
341
+ if (width) img.setAttribute("width", String(Math.round(width)));
342
+ img.setAttribute("data-ge-src", path);
343
+ img.draggable = false;
344
+ return img;
345
+ }
346
+
347
+ // A cell's pictures as the file has them made the page's (core.mjs prepareBlock): shown where the server serves them.
348
+ function showPictures(root) {
349
+ for (const img of root.querySelectorAll("img")) {
350
+ const file = img.getAttribute("src") ?? "";
351
+ if (!PICTURE_FILE.test(file)) continue;
352
+ img.setAttribute("data-ge-src", file);
353
+ img.setAttribute("src", servedFile(file));
354
+ img.draggable = false;
355
+ }
356
+ }
357
+
358
+ // A picture as the cell's text writes it: its markup, "" (no file of the folder), null (no picture).
359
+ function writtenPicture(node) {
360
+ if (!isPicture(node)) return null;
361
+ const file = pictureFile(node);
362
+ if (!file) return "";
363
+ const said = [...node.attributes].filter(({ name, value }) => name === "src" || name === "alt" || (name === "width" && PICTURE_WIDTH.test(value)));
364
+ return `<img${said.map(({ name, value }) => ` ${name}="${escapeAttribute(name === "src" ? file : value)}"`).join("")}>`;
365
+ }