@heycys/gallery 0.0.0-stage → 0.1.0

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 (785) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +50 -2
  3. package/THIRD-PARTY-NOTICES.md +3253 -0
  4. package/assets/writing-preferences.md +107 -0
  5. package/bin/gallery.mjs +10 -0
  6. package/browser/editor/components/bookmark/icons.mjs +6 -0
  7. package/browser/editor/components/bookmark/index.mjs +80 -0
  8. package/browser/editor/components/bookmark/page.mjs +147 -0
  9. package/browser/editor/components/builders.mjs +19 -0
  10. package/browser/editor/components/callout/index.mjs +39 -0
  11. package/browser/editor/components/callout/page.mjs +13 -0
  12. package/browser/editor/components/code/index.mjs +327 -0
  13. package/browser/editor/components/code/page.mjs +561 -0
  14. package/browser/editor/components/colors.mjs +50 -0
  15. package/browser/editor/components/columns/index.mjs +104 -0
  16. package/browser/editor/components/columns/page.mjs +297 -0
  17. package/browser/editor/components/details/index.mjs +72 -0
  18. package/browser/editor/components/details/page.mjs +86 -0
  19. package/browser/editor/components/dialog/index.mjs +83 -0
  20. package/browser/editor/components/dialog/page.mjs +219 -0
  21. package/browser/editor/components/divider/index.mjs +48 -0
  22. package/browser/editor/components/embed/icons.mjs +11 -0
  23. package/browser/editor/components/embed/index.mjs +123 -0
  24. package/browser/editor/components/embed/page.mjs +309 -0
  25. package/browser/editor/components/figure/index.mjs +87 -0
  26. package/browser/editor/components/figure/page.mjs +33 -0
  27. package/browser/editor/components/file/icons.mjs +14 -0
  28. package/browser/editor/components/file/index.mjs +77 -0
  29. package/browser/editor/components/file/page.mjs +114 -0
  30. package/browser/editor/components/flowchart/add.mjs +123 -0
  31. package/browser/editor/components/flowchart/index.mjs +246 -0
  32. package/browser/editor/components/flowchart/page.mjs +453 -0
  33. package/browser/editor/components/heading/index.mjs +51 -0
  34. package/browser/editor/components/highlight/index.mjs +79 -0
  35. package/browser/editor/components/icon/index.mjs +57 -0
  36. package/browser/editor/components/icon/page.mjs +286 -0
  37. package/browser/editor/components/icons.mjs +45 -0
  38. package/browser/editor/components/image/crop.mjs +189 -0
  39. package/browser/editor/components/image/index.mjs +104 -0
  40. package/browser/editor/components/image/page.mjs +385 -0
  41. package/browser/editor/components/image/viewer.mjs +213 -0
  42. package/browser/editor/components/installed/index.mjs +133 -0
  43. package/browser/editor/components/installed/page.mjs +422 -0
  44. package/browser/editor/components/installed/served.mjs +35 -0
  45. package/browser/editor/components/kit.mjs +64 -0
  46. package/browser/editor/components/list/index.mjs +194 -0
  47. package/browser/editor/components/list/join.mjs +68 -0
  48. package/browser/editor/components/list/numbers.mjs +107 -0
  49. package/browser/editor/components/list/page.mjs +632 -0
  50. package/browser/editor/components/math/index.mjs +88 -0
  51. package/browser/editor/components/math/page.mjs +236 -0
  52. package/browser/editor/components/math/tex-logo.mjs +6 -0
  53. package/browser/editor/components/media/icons.mjs +19 -0
  54. package/browser/editor/components/media/page.mjs +162 -0
  55. package/browser/editor/components/media/parts.mjs +60 -0
  56. package/browser/editor/components/media/size.mjs +20 -0
  57. package/browser/editor/components/media/toolbar.mjs +37 -0
  58. package/browser/editor/components/media/write.mjs +7 -0
  59. package/browser/editor/components/pages.mjs +46 -0
  60. package/browser/editor/components/paragraph/index.mjs +43 -0
  61. package/browser/editor/components/paragraph/page.mjs +52 -0
  62. package/browser/editor/components/placeholder-bar.mjs +17 -0
  63. package/browser/editor/components/placeholder.mjs +128 -0
  64. package/browser/editor/components/quote/index.mjs +33 -0
  65. package/browser/editor/components/registry.mjs +833 -0
  66. package/browser/editor/components/rows.mjs +16 -0
  67. package/browser/editor/components/section/index.mjs +41 -0
  68. package/browser/editor/components/section/page.mjs +141 -0
  69. package/browser/editor/components/sheets/index.mjs +137 -0
  70. package/browser/editor/components/sheets/page.mjs +227 -0
  71. package/browser/editor/components/sheets/pills.mjs +226 -0
  72. package/browser/editor/components/table/grid.mjs +73 -0
  73. package/browser/editor/components/table/index.mjs +306 -0
  74. package/browser/editor/components/table/page.mjs +672 -0
  75. package/browser/editor/components/table/slots.mjs +41 -0
  76. package/browser/editor/components/widget/index.mjs +50 -0
  77. package/browser/editor/page/annotate/anchors.mjs +229 -0
  78. package/browser/editor/page/annotate/card.mjs +102 -0
  79. package/browser/editor/page/annotate/index.mjs +1629 -0
  80. package/browser/editor/page/at-menu/index.mjs +317 -0
  81. package/browser/editor/page/autosave.mjs +977 -0
  82. package/browser/editor/page/beside.mjs +21 -0
  83. package/browser/editor/page/block-info.mjs +63 -0
  84. package/browser/editor/page/block-menu/colors.mjs +82 -0
  85. package/browser/editor/page/block-menu/index.mjs +215 -0
  86. package/browser/editor/page/blocks.mjs +246 -0
  87. package/browser/editor/page/caret.mjs +679 -0
  88. package/browser/editor/page/chip-fills.mjs +126 -0
  89. package/browser/editor/page/clipboard/import/colors.mjs +192 -0
  90. package/browser/editor/page/clipboard/import/html.mjs +792 -0
  91. package/browser/editor/page/clipboard/import/inline.mjs +232 -0
  92. package/browser/editor/page/clipboard/import/languages.mjs +42 -0
  93. package/browser/editor/page/clipboard/import/markdown.mjs +760 -0
  94. package/browser/editor/page/clipboard/import/math.mjs +100 -0
  95. package/browser/editor/page/clipboard/import/office.mjs +245 -0
  96. package/browser/editor/page/clipboard/import/read.mjs +120 -0
  97. package/browser/editor/page/clipboard/import/rich.mjs +29 -0
  98. package/browser/editor/page/clipboard/import/to-blocks.mjs +290 -0
  99. package/browser/editor/page/clipboard/index.mjs +797 -0
  100. package/browser/editor/page/clipboard/own/blocks.mjs +202 -0
  101. package/browser/editor/page/clipboard/own/chart-keys.mjs +58 -0
  102. package/browser/editor/page/clipboard/own/describe.mjs +115 -0
  103. package/browser/editor/page/clipboard/own/export.mjs +167 -0
  104. package/browser/editor/page/clipboard/own/ids.mjs +39 -0
  105. package/browser/editor/page/clipboard/own/index.mjs +13 -0
  106. package/browser/editor/page/clipboard/own/rules.mjs +44 -0
  107. package/browser/editor/page/clipboard/own/selection.mjs +159 -0
  108. package/browser/editor/page/clipboard/own/writers.mjs +326 -0
  109. package/browser/editor/page/columns/index.mjs +360 -0
  110. package/browser/editor/page/commit.mjs +1798 -0
  111. package/browser/editor/page/conflicts.mjs +269 -0
  112. package/browser/editor/page/convert.mjs +830 -0
  113. package/browser/editor/page/core.mjs +1655 -0
  114. package/browser/editor/page/drag/drop.mjs +307 -0
  115. package/browser/editor/page/drag/index.mjs +335 -0
  116. package/browser/editor/page/drag/preview.mjs +121 -0
  117. package/browser/editor/page/edge-scroll.mjs +50 -0
  118. package/browser/editor/page/editor.mjs +1725 -0
  119. package/browser/editor/page/emoji-picker/emoji-tab.mjs +278 -0
  120. package/browser/editor/page/emoji-picker/glyph-html.mjs +26 -0
  121. package/browser/editor/page/emoji-picker/grid.mjs +79 -0
  122. package/browser/editor/page/emoji-picker/icon-tab.mjs +217 -0
  123. package/browser/editor/page/emoji-picker/icons.mjs +32 -0
  124. package/browser/editor/page/emoji-picker/index.mjs +164 -0
  125. package/browser/editor/page/emoji-picker/styles.mjs +2 -0
  126. package/browser/editor/page/emoji-picker/support.mjs +202 -0
  127. package/browser/editor/page/emoji-picker/upload.mjs +235 -0
  128. package/browser/editor/page/export-report.mjs +23 -0
  129. package/browser/editor/page/fills.mjs +60 -0
  130. package/browser/editor/page/find/index.mjs +107 -0
  131. package/browser/editor/page/flags.mjs +70 -0
  132. package/browser/editor/page/format-bar/bar.mjs +448 -0
  133. package/browser/editor/page/format-bar/brush.mjs +77 -0
  134. package/browser/editor/page/format-bar/colors.mjs +46 -0
  135. package/browser/editor/page/format-bar/index.mjs +404 -0
  136. package/browser/editor/page/formula/index.mjs +236 -0
  137. package/browser/editor/page/formula/panel.mjs +336 -0
  138. package/browser/editor/page/formula/symbols.mjs +156 -0
  139. package/browser/editor/page/frame.mjs +74 -0
  140. package/browser/editor/page/frames.mjs +196 -0
  141. package/browser/editor/page/geometry.mjs +400 -0
  142. package/browser/editor/page/gesture.mjs +45 -0
  143. package/browser/editor/page/handle/index.mjs +639 -0
  144. package/browser/editor/page/handle-sizes.mjs +14 -0
  145. package/browser/editor/page/hints/index.mjs +84 -0
  146. package/browser/editor/page/history.mjs +401 -0
  147. package/browser/editor/page/insert/index.mjs +243 -0
  148. package/browser/editor/page/kept.mjs +38 -0
  149. package/browser/editor/page/links/address.mjs +40 -0
  150. package/browser/editor/page/links/index.mjs +866 -0
  151. package/browser/editor/page/links/pages.mjs +131 -0
  152. package/browser/editor/page/links/views.mjs +369 -0
  153. package/browser/editor/page/look.mjs +65 -0
  154. package/browser/editor/page/made.mjs +24 -0
  155. package/browser/editor/page/margin.mjs +352 -0
  156. package/browser/editor/page/markdown/index.mjs +88 -0
  157. package/browser/editor/page/markdown/rules.mjs +33 -0
  158. package/browser/editor/page/marks.mjs +377 -0
  159. package/browser/editor/page/media-menu/index.mjs +158 -0
  160. package/browser/editor/page/menu.mjs +500 -0
  161. package/browser/editor/page/merge.mjs +100 -0
  162. package/browser/editor/page/notices.mjs +142 -0
  163. package/browser/editor/page/offered.mjs +32 -0
  164. package/browser/editor/page/outline/folds.mjs +52 -0
  165. package/browser/editor/page/outline/index.mjs +697 -0
  166. package/browser/editor/page/outline/list.mjs +172 -0
  167. package/browser/editor/page/outline/read.mjs +201 -0
  168. package/browser/editor/page/outline/strip.mjs +281 -0
  169. package/browser/editor/page/outline/tree.mjs +248 -0
  170. package/browser/editor/page/overlay-layer.mjs +227 -0
  171. package/browser/editor/page/overlays.mjs +205 -0
  172. package/browser/editor/page/own.mjs +28 -0
  173. package/browser/editor/page/pads.mjs +71 -0
  174. package/browser/editor/page/page-objects.mjs +105 -0
  175. package/browser/editor/page/panel.mjs +64 -0
  176. package/browser/editor/page/placement.mjs +58 -0
  177. package/browser/editor/page/post.mjs +41 -0
  178. package/browser/editor/page/present-links.mjs +50 -0
  179. package/browser/editor/page/quiet.mjs +48 -0
  180. package/browser/editor/page/resize/index.mjs +327 -0
  181. package/browser/editor/page/select-all/index.mjs +262 -0
  182. package/browser/editor/page/selection/delete.mjs +59 -0
  183. package/browser/editor/page/selection/index.mjs +157 -0
  184. package/browser/editor/page/selection/marquee.mjs +174 -0
  185. package/browser/editor/page/session.mjs +117 -0
  186. package/browser/editor/page/slash-menu/index.mjs +291 -0
  187. package/browser/editor/page/storage.mjs +48 -0
  188. package/browser/editor/page/sync-state.mjs +267 -0
  189. package/browser/editor/page/table/aligns.mjs +29 -0
  190. package/browser/editor/page/table/cell-bar.mjs +138 -0
  191. package/browser/editor/page/table/cells.mjs +527 -0
  192. package/browser/editor/page/table/icons.mjs +40 -0
  193. package/browser/editor/page/table/index.mjs +985 -0
  194. package/browser/editor/page/table/lists.mjs +187 -0
  195. package/browser/editor/page/table/widths.mjs +308 -0
  196. package/browser/editor/page/tex.mjs +32 -0
  197. package/browser/editor/page/text-select/index.mjs +656 -0
  198. package/browser/editor/page/tooltip.mjs +98 -0
  199. package/browser/editor/page/type-grid.mjs +82 -0
  200. package/browser/editor/page/typing/code-edges.mjs +228 -0
  201. package/browser/editor/page/typing/index.mjs +276 -0
  202. package/browser/editor/page/typing/leave.mjs +68 -0
  203. package/browser/editor/page/ui.mjs +160 -0
  204. package/browser/shared/annotations.mjs +571 -0
  205. package/browser/shared/code-folds.mjs +10 -0
  206. package/browser/shared/code-languages.mjs +70 -0
  207. package/browser/shared/code-lines.mjs +30 -0
  208. package/browser/shared/colors.mjs +28 -0
  209. package/browser/shared/component-catalog.mjs +559 -0
  210. package/browser/shared/components/bookmark.mjs +26 -0
  211. package/browser/shared/components/callout.mjs +7 -0
  212. package/browser/shared/components/chart.mjs +20 -0
  213. package/browser/shared/components/code.mjs +37 -0
  214. package/browser/shared/components/columns.mjs +16 -0
  215. package/browser/shared/components/details.mjs +15 -0
  216. package/browser/shared/components/dialog.mjs +28 -0
  217. package/browser/shared/components/diff.mjs +18 -0
  218. package/browser/shared/components/divider.mjs +6 -0
  219. package/browser/shared/components/embed.mjs +25 -0
  220. package/browser/shared/components/figure.mjs +14 -0
  221. package/browser/shared/components/file.mjs +23 -0
  222. package/browser/shared/components/heading.mjs +6 -0
  223. package/browser/shared/components/highlight.mjs +9 -0
  224. package/browser/shared/components/icon.mjs +18 -0
  225. package/browser/shared/components/image.mjs +39 -0
  226. package/browser/shared/components/index.mjs +342 -0
  227. package/browser/shared/components/installed.mjs +162 -0
  228. package/browser/shared/components/list.mjs +146 -0
  229. package/browser/shared/components/math.mjs +49 -0
  230. package/browser/shared/components/mention.mjs +33 -0
  231. package/browser/shared/components/page.mjs +37 -0
  232. package/browser/shared/components/paragraph.mjs +9 -0
  233. package/browser/shared/components/quote.mjs +6 -0
  234. package/browser/shared/components/section.mjs +8 -0
  235. package/browser/shared/components/sheets.mjs +80 -0
  236. package/browser/shared/components/state.mjs +20 -0
  237. package/browser/shared/components/table.mjs +49 -0
  238. package/browser/shared/components/text.mjs +14 -0
  239. package/browser/shared/components/widget.mjs +10 -0
  240. package/browser/shared/copy-ids.mjs +72 -0
  241. package/browser/shared/css-references.mjs +110 -0
  242. package/browser/shared/emoji/custom.mjs +91 -0
  243. package/browser/shared/emoji/data/LICENSE-mingcute.txt +202 -0
  244. package/browser/shared/emoji/data/LICENSE-tabler.txt +21 -0
  245. package/browser/shared/emoji/data/README.md +26 -0
  246. package/browser/shared/emoji/data/categories.json +1 -0
  247. package/browser/shared/emoji/data/icons.json +1 -0
  248. package/browser/shared/emoji/data/keywords-en.json +1 -0
  249. package/browser/shared/emoji/data/keywords-zh.json +1 -0
  250. package/browser/shared/emoji/data/names.json +1 -0
  251. package/browser/shared/emoji/data/positions.json +1 -0
  252. package/browser/shared/emoji/data/twemoji-index.json +1 -0
  253. package/browser/shared/emoji/data/twemoji-svg.bin +0 -0
  254. package/browser/shared/emoji/data.mjs +196 -0
  255. package/browser/shared/emoji/emoji.mjs +37 -0
  256. package/browser/shared/emoji/glyphs.mjs +134 -0
  257. package/browser/shared/emoji/icon-value.mjs +90 -0
  258. package/browser/shared/escape.mjs +20 -0
  259. package/browser/shared/export-wrap.mjs +89 -0
  260. package/browser/shared/files.mjs +33 -0
  261. package/browser/shared/html-tree.mjs +53 -0
  262. package/browser/shared/http.mjs +22 -0
  263. package/browser/shared/i18n/en.mjs +1164 -0
  264. package/browser/shared/i18n/index.mjs +132 -0
  265. package/browser/shared/ids.mjs +24 -0
  266. package/browser/shared/import-types.mjs +23 -0
  267. package/browser/shared/inline-spacing.mjs +97 -0
  268. package/browser/shared/layers.mjs +42 -0
  269. package/browser/shared/media.mjs +162 -0
  270. package/browser/shared/new-names.mjs +64 -0
  271. package/browser/shared/number-reading.mjs +92 -0
  272. package/browser/shared/old-names.mjs +143 -0
  273. package/browser/shared/page-address.mjs +140 -0
  274. package/browser/shared/page-links.mjs +86 -0
  275. package/browser/shared/paths.mjs +73 -0
  276. package/browser/shared/preferences.mjs +110 -0
  277. package/browser/shared/preview-server.mjs +247 -0
  278. package/browser/shared/qa-levels.mjs +93 -0
  279. package/browser/shared/reading-place.mjs +91 -0
  280. package/browser/shared/renamed-storage.mjs +220 -0
  281. package/browser/shared/reports.mjs +46 -0
  282. package/browser/shared/search.mjs +85 -0
  283. package/browser/shared/session.mjs +76 -0
  284. package/browser/shared/table-chart.mjs +113 -0
  285. package/browser/shared/table-hides.mjs +120 -0
  286. package/browser/shared/table-slots.mjs +75 -0
  287. package/browser/shared/words.mjs +23 -0
  288. package/browser/shared/workspace.mjs +535 -0
  289. package/browser/shared/writing-preferences.mjs +68 -0
  290. package/browser/shared/zoom.mjs +57 -0
  291. package/dist/chunk-2B5E4CDJ.mjs +2 -0
  292. package/dist/chunk-2PBALTR3.mjs +57 -0
  293. package/dist/chunk-342HXE3Q.mjs +2 -0
  294. package/dist/chunk-3LA3EMDE.mjs +15 -0
  295. package/dist/chunk-43B75J5T.mjs +2 -0
  296. package/dist/chunk-4K5KC6V2.mjs +2 -0
  297. package/dist/chunk-5FRMCDPY.mjs +16 -0
  298. package/dist/chunk-5L7RYZCL.mjs +2 -0
  299. package/dist/chunk-5LEK2CBS.mjs +2 -0
  300. package/dist/chunk-5OFN5AHC.mjs +2 -0
  301. package/dist/chunk-5SIYS5HN.mjs +2 -0
  302. package/dist/chunk-5TEK3RAD.mjs +2 -0
  303. package/dist/chunk-6CYG3Z4V.mjs +2 -0
  304. package/dist/chunk-6U2SLSDN.mjs +3 -0
  305. package/dist/chunk-742D2WWJ.mjs +19 -0
  306. package/dist/chunk-7GHT2UCA.mjs +15 -0
  307. package/dist/chunk-7QQBR7PB.mjs +2 -0
  308. package/dist/chunk-A55HN5OK.mjs +2 -0
  309. package/dist/chunk-ACOPDCNB.mjs +2 -0
  310. package/dist/chunk-AGDILNWB.mjs +2 -0
  311. package/dist/chunk-ATCJYAR4.mjs +2 -0
  312. package/dist/chunk-B3VTYBYR.mjs +960 -0
  313. package/dist/chunk-C564NU2H.mjs +77 -0
  314. package/dist/chunk-C7HWOBIF.mjs +2 -0
  315. package/dist/chunk-DB4WKGYF.mjs +7 -0
  316. package/dist/chunk-E7VYDG2X.mjs +2 -0
  317. package/dist/chunk-EUX7IC5J.mjs +48 -0
  318. package/dist/chunk-EVJ3BX3M.mjs +2 -0
  319. package/dist/chunk-EZY3WC6Z.mjs +15 -0
  320. package/dist/chunk-FQGQH4KM.mjs +2 -0
  321. package/dist/chunk-G7TOXONE.mjs +6 -0
  322. package/dist/chunk-GPF4YWWB.mjs +9 -0
  323. package/dist/chunk-GRAXKKG4.mjs +2 -0
  324. package/dist/chunk-GYQV7Y4J.mjs +120 -0
  325. package/dist/chunk-HMHK3EQ6.mjs +2 -0
  326. package/dist/chunk-HQQMJCQJ.mjs +10 -0
  327. package/dist/chunk-HYMEEXKN.mjs +4 -0
  328. package/dist/chunk-IERUOGC3.mjs +6 -0
  329. package/dist/chunk-ITNLYXXV.mjs +3 -0
  330. package/dist/chunk-L4DVONOG.mjs +2 -0
  331. package/dist/chunk-LAE5NQ4B.mjs +2 -0
  332. package/dist/chunk-LC7YNQFG.mjs +2 -0
  333. package/dist/chunk-LHTFLRB6.mjs +4 -0
  334. package/dist/chunk-LKX55H76.mjs +2 -0
  335. package/dist/chunk-MAFIGVXY.mjs +2 -0
  336. package/dist/chunk-NFIBI4IP.mjs +26 -0
  337. package/dist/chunk-NSKUTQ5J.mjs +5 -0
  338. package/dist/chunk-O52JMOCZ.mjs +2 -0
  339. package/dist/chunk-P2CAZPDP.mjs +3 -0
  340. package/dist/chunk-QAIHRH3I.mjs +13 -0
  341. package/dist/chunk-QMQUXTU4.mjs +12 -0
  342. package/dist/chunk-QR6A54KJ.mjs +3 -0
  343. package/dist/chunk-QVWVFC5K.mjs +6 -0
  344. package/dist/chunk-QYKCJ7FG.mjs +8 -0
  345. package/dist/chunk-QZY6Q64C.mjs +2 -0
  346. package/dist/chunk-TDQP3DKQ.mjs +10 -0
  347. package/dist/chunk-TMYZB6AV.mjs +2 -0
  348. package/dist/chunk-TX6JH7TR.mjs +2 -0
  349. package/dist/chunk-U3SSPL4K.mjs +8 -0
  350. package/dist/chunk-UH4SIXTR.mjs +2 -0
  351. package/dist/chunk-UNUEWH4S.mjs +2 -0
  352. package/dist/chunk-UXUK4PMC.mjs +27 -0
  353. package/dist/chunk-V4CPWKMZ.mjs +2 -0
  354. package/dist/chunk-V6XZ4VIR.mjs +2 -0
  355. package/dist/chunk-VACRB2NE.mjs +3 -0
  356. package/dist/chunk-W63L7367.mjs +7 -0
  357. package/dist/chunk-W7CXPCRV.mjs +6 -0
  358. package/dist/chunk-W7XHE4CT.mjs +2 -0
  359. package/dist/chunk-XINNG4F2.mjs +4 -0
  360. package/dist/chunk-Y34NR5JL.mjs +2 -0
  361. package/dist/chunk-YEY3RSFQ.mjs +2 -0
  362. package/dist/chunk-YL2DPWVS.mjs +4 -0
  363. package/dist/chunk-YXAUQPVK.mjs +8 -0
  364. package/dist/chunk-YZ5Z6H4W.mjs +4 -0
  365. package/dist/chunk-Z52HTUW7.mjs +4 -0
  366. package/dist/chunk-ZBIM6ARY.mjs +216 -0
  367. package/dist/cli.mjs +2 -0
  368. package/dist/server.mjs +2 -0
  369. package/dist/worker.mjs +5 -0
  370. package/kit/charts.js +355 -0
  371. package/kit/code.js +164 -0
  372. package/kit/dialogs.js +157 -0
  373. package/kit/math.js +1988 -0
  374. package/kit/report.css +2821 -0
  375. package/kit/runtime.js +1707 -0
  376. package/kit/sheets.js +123 -0
  377. package/kit/state.js +217 -0
  378. package/kit/tables.js +1449 -0
  379. package/kit/tokens.js +29 -0
  380. package/kit/ui.js +561 -0
  381. package/package.json +41 -4
  382. package/release.json +25 -0
  383. package/sdk/column-widths.d.ts +56 -0
  384. package/sdk/doc-charts.d.ts +82 -0
  385. package/sdk/doc-code.d.ts +28 -0
  386. package/sdk/doc-dialogs.d.ts +4 -0
  387. package/sdk/doc-kit.d.ts +141 -0
  388. package/sdk/doc-math.d.ts +3 -0
  389. package/sdk/doc-sheets.d.ts +15 -0
  390. package/sdk/doc-state.d.ts +41 -0
  391. package/sdk/doc-tables.d.ts +24 -0
  392. package/sdk/doc-tokens.d.ts +22 -0
  393. package/sdk/index.d.ts +30 -0
  394. package/skill/SKILL.md +138 -0
  395. package/skill/agents/openai.yaml +5 -0
  396. package/skill/references/building-components.md +327 -0
  397. package/skill/references/example-report.html +356 -0
  398. package/skill/references/writing-html.md +187 -0
  399. package/skill/sdk/column-widths.d.ts +56 -0
  400. package/skill/sdk/doc-charts.d.ts +82 -0
  401. package/skill/sdk/doc-code.d.ts +28 -0
  402. package/skill/sdk/doc-dialogs.d.ts +4 -0
  403. package/skill/sdk/doc-kit.d.ts +141 -0
  404. package/skill/sdk/doc-math.d.ts +3 -0
  405. package/skill/sdk/doc-sheets.d.ts +15 -0
  406. package/skill/sdk/doc-state.d.ts +41 -0
  407. package/skill/sdk/doc-tables.d.ts +24 -0
  408. package/skill/sdk/doc-tokens.d.ts +22 -0
  409. package/skill/sdk/index.d.ts +30 -0
  410. package/starter/doc.html +21 -0
  411. package/starter/doc.json +5 -0
  412. package/vendor/d3.v7.9.0.min.js +2 -0
  413. package/vendor/katex/auto-render.min.js +1 -0
  414. package/vendor/katex/contrib/mhchem.min.js +1 -0
  415. package/vendor/katex/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  416. package/vendor/katex/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  417. package/vendor/katex/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  418. package/vendor/katex/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  419. package/vendor/katex/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  420. package/vendor/katex/fonts/KaTeX_Main-Bold.woff2 +0 -0
  421. package/vendor/katex/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  422. package/vendor/katex/fonts/KaTeX_Main-Italic.woff2 +0 -0
  423. package/vendor/katex/fonts/KaTeX_Main-Regular.woff2 +0 -0
  424. package/vendor/katex/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  425. package/vendor/katex/fonts/KaTeX_Math-Italic.woff2 +0 -0
  426. package/vendor/katex/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  427. package/vendor/katex/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  428. package/vendor/katex/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  429. package/vendor/katex/fonts/KaTeX_Script-Regular.woff2 +0 -0
  430. package/vendor/katex/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  431. package/vendor/katex/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  432. package/vendor/katex/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  433. package/vendor/katex/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  434. package/vendor/katex/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  435. package/vendor/katex/katex.min.css +1 -0
  436. package/vendor/katex/katex.min.js +1 -0
  437. package/vendor/pdfjs/LICENSE +177 -0
  438. package/vendor/pdfjs/cmaps/78-EUC-H.bcmap +0 -0
  439. package/vendor/pdfjs/cmaps/78-EUC-V.bcmap +0 -0
  440. package/vendor/pdfjs/cmaps/78-H.bcmap +0 -0
  441. package/vendor/pdfjs/cmaps/78-RKSJ-H.bcmap +0 -0
  442. package/vendor/pdfjs/cmaps/78-RKSJ-V.bcmap +0 -0
  443. package/vendor/pdfjs/cmaps/78-V.bcmap +0 -0
  444. package/vendor/pdfjs/cmaps/78ms-RKSJ-H.bcmap +0 -0
  445. package/vendor/pdfjs/cmaps/78ms-RKSJ-V.bcmap +0 -0
  446. package/vendor/pdfjs/cmaps/83pv-RKSJ-H.bcmap +0 -0
  447. package/vendor/pdfjs/cmaps/90ms-RKSJ-H.bcmap +0 -0
  448. package/vendor/pdfjs/cmaps/90ms-RKSJ-V.bcmap +0 -0
  449. package/vendor/pdfjs/cmaps/90msp-RKSJ-H.bcmap +0 -0
  450. package/vendor/pdfjs/cmaps/90msp-RKSJ-V.bcmap +0 -0
  451. package/vendor/pdfjs/cmaps/90pv-RKSJ-H.bcmap +0 -0
  452. package/vendor/pdfjs/cmaps/90pv-RKSJ-V.bcmap +0 -0
  453. package/vendor/pdfjs/cmaps/Add-H.bcmap +0 -0
  454. package/vendor/pdfjs/cmaps/Add-RKSJ-H.bcmap +0 -0
  455. package/vendor/pdfjs/cmaps/Add-RKSJ-V.bcmap +0 -0
  456. package/vendor/pdfjs/cmaps/Add-V.bcmap +0 -0
  457. package/vendor/pdfjs/cmaps/Adobe-CNS1-0.bcmap +0 -0
  458. package/vendor/pdfjs/cmaps/Adobe-CNS1-1.bcmap +0 -0
  459. package/vendor/pdfjs/cmaps/Adobe-CNS1-2.bcmap +0 -0
  460. package/vendor/pdfjs/cmaps/Adobe-CNS1-3.bcmap +0 -0
  461. package/vendor/pdfjs/cmaps/Adobe-CNS1-4.bcmap +0 -0
  462. package/vendor/pdfjs/cmaps/Adobe-CNS1-5.bcmap +0 -0
  463. package/vendor/pdfjs/cmaps/Adobe-CNS1-6.bcmap +0 -0
  464. package/vendor/pdfjs/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
  465. package/vendor/pdfjs/cmaps/Adobe-GB1-0.bcmap +0 -0
  466. package/vendor/pdfjs/cmaps/Adobe-GB1-1.bcmap +0 -0
  467. package/vendor/pdfjs/cmaps/Adobe-GB1-2.bcmap +0 -0
  468. package/vendor/pdfjs/cmaps/Adobe-GB1-3.bcmap +0 -0
  469. package/vendor/pdfjs/cmaps/Adobe-GB1-4.bcmap +0 -0
  470. package/vendor/pdfjs/cmaps/Adobe-GB1-5.bcmap +0 -0
  471. package/vendor/pdfjs/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
  472. package/vendor/pdfjs/cmaps/Adobe-Japan1-0.bcmap +0 -0
  473. package/vendor/pdfjs/cmaps/Adobe-Japan1-1.bcmap +0 -0
  474. package/vendor/pdfjs/cmaps/Adobe-Japan1-2.bcmap +0 -0
  475. package/vendor/pdfjs/cmaps/Adobe-Japan1-3.bcmap +0 -0
  476. package/vendor/pdfjs/cmaps/Adobe-Japan1-4.bcmap +0 -0
  477. package/vendor/pdfjs/cmaps/Adobe-Japan1-5.bcmap +0 -0
  478. package/vendor/pdfjs/cmaps/Adobe-Japan1-6.bcmap +0 -0
  479. package/vendor/pdfjs/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
  480. package/vendor/pdfjs/cmaps/Adobe-Korea1-0.bcmap +0 -0
  481. package/vendor/pdfjs/cmaps/Adobe-Korea1-1.bcmap +0 -0
  482. package/vendor/pdfjs/cmaps/Adobe-Korea1-2.bcmap +0 -0
  483. package/vendor/pdfjs/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
  484. package/vendor/pdfjs/cmaps/B5-H.bcmap +0 -0
  485. package/vendor/pdfjs/cmaps/B5-V.bcmap +0 -0
  486. package/vendor/pdfjs/cmaps/B5pc-H.bcmap +0 -0
  487. package/vendor/pdfjs/cmaps/B5pc-V.bcmap +0 -0
  488. package/vendor/pdfjs/cmaps/CNS-EUC-H.bcmap +0 -0
  489. package/vendor/pdfjs/cmaps/CNS-EUC-V.bcmap +0 -0
  490. package/vendor/pdfjs/cmaps/CNS1-H.bcmap +0 -0
  491. package/vendor/pdfjs/cmaps/CNS1-V.bcmap +0 -0
  492. package/vendor/pdfjs/cmaps/CNS2-H.bcmap +0 -0
  493. package/vendor/pdfjs/cmaps/CNS2-V.bcmap +3 -0
  494. package/vendor/pdfjs/cmaps/ETHK-B5-H.bcmap +0 -0
  495. package/vendor/pdfjs/cmaps/ETHK-B5-V.bcmap +0 -0
  496. package/vendor/pdfjs/cmaps/ETen-B5-H.bcmap +0 -0
  497. package/vendor/pdfjs/cmaps/ETen-B5-V.bcmap +0 -0
  498. package/vendor/pdfjs/cmaps/ETenms-B5-H.bcmap +3 -0
  499. package/vendor/pdfjs/cmaps/ETenms-B5-V.bcmap +0 -0
  500. package/vendor/pdfjs/cmaps/EUC-H.bcmap +0 -0
  501. package/vendor/pdfjs/cmaps/EUC-V.bcmap +0 -0
  502. package/vendor/pdfjs/cmaps/Ext-H.bcmap +0 -0
  503. package/vendor/pdfjs/cmaps/Ext-RKSJ-H.bcmap +0 -0
  504. package/vendor/pdfjs/cmaps/Ext-RKSJ-V.bcmap +0 -0
  505. package/vendor/pdfjs/cmaps/Ext-V.bcmap +0 -0
  506. package/vendor/pdfjs/cmaps/GB-EUC-H.bcmap +0 -0
  507. package/vendor/pdfjs/cmaps/GB-EUC-V.bcmap +0 -0
  508. package/vendor/pdfjs/cmaps/GB-H.bcmap +4 -0
  509. package/vendor/pdfjs/cmaps/GB-V.bcmap +0 -0
  510. package/vendor/pdfjs/cmaps/GBK-EUC-H.bcmap +0 -0
  511. package/vendor/pdfjs/cmaps/GBK-EUC-V.bcmap +0 -0
  512. package/vendor/pdfjs/cmaps/GBK2K-H.bcmap +0 -0
  513. package/vendor/pdfjs/cmaps/GBK2K-V.bcmap +0 -0
  514. package/vendor/pdfjs/cmaps/GBKp-EUC-H.bcmap +0 -0
  515. package/vendor/pdfjs/cmaps/GBKp-EUC-V.bcmap +0 -0
  516. package/vendor/pdfjs/cmaps/GBT-EUC-H.bcmap +0 -0
  517. package/vendor/pdfjs/cmaps/GBT-EUC-V.bcmap +0 -0
  518. package/vendor/pdfjs/cmaps/GBT-H.bcmap +0 -0
  519. package/vendor/pdfjs/cmaps/GBT-V.bcmap +0 -0
  520. package/vendor/pdfjs/cmaps/GBTpc-EUC-H.bcmap +0 -0
  521. package/vendor/pdfjs/cmaps/GBTpc-EUC-V.bcmap +0 -0
  522. package/vendor/pdfjs/cmaps/GBpc-EUC-H.bcmap +0 -0
  523. package/vendor/pdfjs/cmaps/GBpc-EUC-V.bcmap +0 -0
  524. package/vendor/pdfjs/cmaps/H.bcmap +0 -0
  525. package/vendor/pdfjs/cmaps/HKdla-B5-H.bcmap +0 -0
  526. package/vendor/pdfjs/cmaps/HKdla-B5-V.bcmap +0 -0
  527. package/vendor/pdfjs/cmaps/HKdlb-B5-H.bcmap +0 -0
  528. package/vendor/pdfjs/cmaps/HKdlb-B5-V.bcmap +0 -0
  529. package/vendor/pdfjs/cmaps/HKgccs-B5-H.bcmap +0 -0
  530. package/vendor/pdfjs/cmaps/HKgccs-B5-V.bcmap +0 -0
  531. package/vendor/pdfjs/cmaps/HKm314-B5-H.bcmap +0 -0
  532. package/vendor/pdfjs/cmaps/HKm314-B5-V.bcmap +0 -0
  533. package/vendor/pdfjs/cmaps/HKm471-B5-H.bcmap +0 -0
  534. package/vendor/pdfjs/cmaps/HKm471-B5-V.bcmap +0 -0
  535. package/vendor/pdfjs/cmaps/HKscs-B5-H.bcmap +0 -0
  536. package/vendor/pdfjs/cmaps/HKscs-B5-V.bcmap +0 -0
  537. package/vendor/pdfjs/cmaps/Hankaku.bcmap +0 -0
  538. package/vendor/pdfjs/cmaps/Hiragana.bcmap +0 -0
  539. package/vendor/pdfjs/cmaps/KSC-EUC-H.bcmap +0 -0
  540. package/vendor/pdfjs/cmaps/KSC-EUC-V.bcmap +0 -0
  541. package/vendor/pdfjs/cmaps/KSC-H.bcmap +0 -0
  542. package/vendor/pdfjs/cmaps/KSC-Johab-H.bcmap +0 -0
  543. package/vendor/pdfjs/cmaps/KSC-Johab-V.bcmap +0 -0
  544. package/vendor/pdfjs/cmaps/KSC-V.bcmap +0 -0
  545. package/vendor/pdfjs/cmaps/KSCms-UHC-H.bcmap +0 -0
  546. package/vendor/pdfjs/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
  547. package/vendor/pdfjs/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
  548. package/vendor/pdfjs/cmaps/KSCms-UHC-V.bcmap +0 -0
  549. package/vendor/pdfjs/cmaps/KSCpc-EUC-H.bcmap +0 -0
  550. package/vendor/pdfjs/cmaps/KSCpc-EUC-V.bcmap +0 -0
  551. package/vendor/pdfjs/cmaps/Katakana.bcmap +0 -0
  552. package/vendor/pdfjs/cmaps/LICENSE +36 -0
  553. package/vendor/pdfjs/cmaps/NWP-H.bcmap +0 -0
  554. package/vendor/pdfjs/cmaps/NWP-V.bcmap +0 -0
  555. package/vendor/pdfjs/cmaps/RKSJ-H.bcmap +0 -0
  556. package/vendor/pdfjs/cmaps/RKSJ-V.bcmap +0 -0
  557. package/vendor/pdfjs/cmaps/Roman.bcmap +0 -0
  558. package/vendor/pdfjs/cmaps/UniCNS-UCS2-H.bcmap +0 -0
  559. package/vendor/pdfjs/cmaps/UniCNS-UCS2-V.bcmap +0 -0
  560. package/vendor/pdfjs/cmaps/UniCNS-UTF16-H.bcmap +0 -0
  561. package/vendor/pdfjs/cmaps/UniCNS-UTF16-V.bcmap +0 -0
  562. package/vendor/pdfjs/cmaps/UniCNS-UTF32-H.bcmap +0 -0
  563. package/vendor/pdfjs/cmaps/UniCNS-UTF32-V.bcmap +0 -0
  564. package/vendor/pdfjs/cmaps/UniCNS-UTF8-H.bcmap +0 -0
  565. package/vendor/pdfjs/cmaps/UniCNS-UTF8-V.bcmap +0 -0
  566. package/vendor/pdfjs/cmaps/UniGB-UCS2-H.bcmap +0 -0
  567. package/vendor/pdfjs/cmaps/UniGB-UCS2-V.bcmap +0 -0
  568. package/vendor/pdfjs/cmaps/UniGB-UTF16-H.bcmap +0 -0
  569. package/vendor/pdfjs/cmaps/UniGB-UTF16-V.bcmap +0 -0
  570. package/vendor/pdfjs/cmaps/UniGB-UTF32-H.bcmap +0 -0
  571. package/vendor/pdfjs/cmaps/UniGB-UTF32-V.bcmap +0 -0
  572. package/vendor/pdfjs/cmaps/UniGB-UTF8-H.bcmap +0 -0
  573. package/vendor/pdfjs/cmaps/UniGB-UTF8-V.bcmap +0 -0
  574. package/vendor/pdfjs/cmaps/UniJIS-UCS2-H.bcmap +0 -0
  575. package/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
  576. package/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
  577. package/vendor/pdfjs/cmaps/UniJIS-UCS2-V.bcmap +0 -0
  578. package/vendor/pdfjs/cmaps/UniJIS-UTF16-H.bcmap +0 -0
  579. package/vendor/pdfjs/cmaps/UniJIS-UTF16-V.bcmap +0 -0
  580. package/vendor/pdfjs/cmaps/UniJIS-UTF32-H.bcmap +0 -0
  581. package/vendor/pdfjs/cmaps/UniJIS-UTF32-V.bcmap +0 -0
  582. package/vendor/pdfjs/cmaps/UniJIS-UTF8-H.bcmap +0 -0
  583. package/vendor/pdfjs/cmaps/UniJIS-UTF8-V.bcmap +0 -0
  584. package/vendor/pdfjs/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
  585. package/vendor/pdfjs/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
  586. package/vendor/pdfjs/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
  587. package/vendor/pdfjs/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
  588. package/vendor/pdfjs/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
  589. package/vendor/pdfjs/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
  590. package/vendor/pdfjs/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
  591. package/vendor/pdfjs/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
  592. package/vendor/pdfjs/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
  593. package/vendor/pdfjs/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
  594. package/vendor/pdfjs/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
  595. package/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
  596. package/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
  597. package/vendor/pdfjs/cmaps/UniKS-UCS2-H.bcmap +0 -0
  598. package/vendor/pdfjs/cmaps/UniKS-UCS2-V.bcmap +0 -0
  599. package/vendor/pdfjs/cmaps/UniKS-UTF16-H.bcmap +0 -0
  600. package/vendor/pdfjs/cmaps/UniKS-UTF16-V.bcmap +0 -0
  601. package/vendor/pdfjs/cmaps/UniKS-UTF32-H.bcmap +0 -0
  602. package/vendor/pdfjs/cmaps/UniKS-UTF32-V.bcmap +0 -0
  603. package/vendor/pdfjs/cmaps/UniKS-UTF8-H.bcmap +0 -0
  604. package/vendor/pdfjs/cmaps/UniKS-UTF8-V.bcmap +0 -0
  605. package/vendor/pdfjs/cmaps/V.bcmap +0 -0
  606. package/vendor/pdfjs/cmaps/WP-Symbol.bcmap +0 -0
  607. package/vendor/pdfjs/legacy/build/pdf.min.mjs +27 -0
  608. package/vendor/pdfjs/legacy/build/pdf.worker.min.mjs +27 -0
  609. package/vendor/pdfjs/standard_fonts/FoxitDingbats.pfb +0 -0
  610. package/vendor/pdfjs/standard_fonts/FoxitFixed.pfb +0 -0
  611. package/vendor/pdfjs/standard_fonts/FoxitFixedBold.pfb +0 -0
  612. package/vendor/pdfjs/standard_fonts/FoxitFixedBoldItalic.pfb +0 -0
  613. package/vendor/pdfjs/standard_fonts/FoxitFixedItalic.pfb +0 -0
  614. package/vendor/pdfjs/standard_fonts/FoxitSerif.pfb +0 -0
  615. package/vendor/pdfjs/standard_fonts/FoxitSerifBold.pfb +0 -0
  616. package/vendor/pdfjs/standard_fonts/FoxitSerifBoldItalic.pfb +0 -0
  617. package/vendor/pdfjs/standard_fonts/FoxitSerifItalic.pfb +0 -0
  618. package/vendor/pdfjs/standard_fonts/FoxitSymbol.pfb +0 -0
  619. package/vendor/pdfjs/standard_fonts/LICENSE_FOXIT +27 -0
  620. package/vendor/pdfjs/standard_fonts/LICENSE_LIBERATION +363 -0
  621. package/vendor/pdfjs/standard_fonts/LiberationSans-Bold.ttf +0 -0
  622. package/vendor/pdfjs/standard_fonts/LiberationSans-BoldItalic.ttf +0 -0
  623. package/vendor/pdfjs/standard_fonts/LiberationSans-Italic.ttf +0 -0
  624. package/vendor/pdfjs/standard_fonts/LiberationSans-Regular.ttf +0 -0
  625. package/vendor/types/@types/d3/LICENSE +21 -0
  626. package/vendor/types/@types/d3/index.d.ts +39 -0
  627. package/vendor/types/@types/d3/package.json +81 -0
  628. package/vendor/types/@types/d3-array/LICENSE +21 -0
  629. package/vendor/types/@types/d3-array/index.d.ts +1118 -0
  630. package/vendor/types/@types/d3-array/package.json +56 -0
  631. package/vendor/types/@types/d3-axis/LICENSE +21 -0
  632. package/vendor/types/@types/d3-axis/index.d.ts +293 -0
  633. package/vendor/types/@types/d3-axis/package.json +47 -0
  634. package/vendor/types/@types/d3-brush/LICENSE +21 -0
  635. package/vendor/types/@types/d3-brush/index.d.ts +255 -0
  636. package/vendor/types/@types/d3-brush/package.json +42 -0
  637. package/vendor/types/@types/d3-chord/LICENSE +21 -0
  638. package/vendor/types/@types/d3-chord/index.d.ts +471 -0
  639. package/vendor/types/@types/d3-chord/package.json +40 -0
  640. package/vendor/types/@types/d3-color/LICENSE +21 -0
  641. package/vendor/types/@types/d3-color/index.d.ts +669 -0
  642. package/vendor/types/@types/d3-color/package.json +55 -0
  643. package/vendor/types/@types/d3-contour/LICENSE +21 -0
  644. package/vendor/types/@types/d3-contour/index.d.ts +222 -0
  645. package/vendor/types/@types/d3-contour/package.json +38 -0
  646. package/vendor/types/@types/d3-delaunay/LICENSE +21 -0
  647. package/vendor/types/@types/d3-delaunay/index.d.ts +316 -0
  648. package/vendor/types/@types/d3-delaunay/package.json +30 -0
  649. package/vendor/types/@types/d3-dispatch/LICENSE +21 -0
  650. package/vendor/types/@types/d3-dispatch/index.d.ts +96 -0
  651. package/vendor/types/@types/d3-dispatch/package.json +51 -0
  652. package/vendor/types/@types/d3-drag/LICENSE +21 -0
  653. package/vendor/types/@types/d3-drag/index.d.ts +395 -0
  654. package/vendor/types/@types/d3-drag/package.json +42 -0
  655. package/vendor/types/@types/d3-dsv/LICENSE +21 -0
  656. package/vendor/types/@types/d3-dsv/index.d.ts +482 -0
  657. package/vendor/types/@types/d3-dsv/package.json +45 -0
  658. package/vendor/types/@types/d3-ease/LICENSE +21 -0
  659. package/vendor/types/@types/d3-ease/index.d.ts +316 -0
  660. package/vendor/types/@types/d3-ease/package.json +40 -0
  661. package/vendor/types/@types/d3-fetch/LICENSE +21 -0
  662. package/vendor/types/@types/d3-fetch/index.d.ts +282 -0
  663. package/vendor/types/@types/d3-fetch/package.json +37 -0
  664. package/vendor/types/@types/d3-force/LICENSE +21 -0
  665. package/vendor/types/@types/d3-force/index.d.ts +899 -0
  666. package/vendor/types/@types/d3-force/package.json +45 -0
  667. package/vendor/types/@types/d3-format/LICENSE +21 -0
  668. package/vendor/types/@types/d3-format/index.d.ts +337 -0
  669. package/vendor/types/@types/d3-format/package.json +45 -0
  670. package/vendor/types/@types/d3-geo/LICENSE +21 -0
  671. package/vendor/types/@types/d3-geo/index.d.ts +1371 -0
  672. package/vendor/types/@types/d3-geo/package.json +48 -0
  673. package/vendor/types/@types/d3-hierarchy/LICENSE +21 -0
  674. package/vendor/types/@types/d3-hierarchy/index.d.ts +928 -0
  675. package/vendor/types/@types/d3-hierarchy/package.json +50 -0
  676. package/vendor/types/@types/d3-interpolate/LICENSE +21 -0
  677. package/vendor/types/@types/d3-interpolate/index.d.ts +387 -0
  678. package/vendor/types/@types/d3-interpolate/package.json +47 -0
  679. package/vendor/types/@types/d3-path/LICENSE +21 -0
  680. package/vendor/types/@types/d3-path/index.d.ts +108 -0
  681. package/vendor/types/@types/d3-path/package.json +41 -0
  682. package/vendor/types/@types/d3-polygon/LICENSE +21 -0
  683. package/vendor/types/@types/d3-polygon/index.d.ts +41 -0
  684. package/vendor/types/@types/d3-polygon/package.json +40 -0
  685. package/vendor/types/@types/d3-quadtree/LICENSE +21 -0
  686. package/vendor/types/@types/d3-quadtree/index.d.ts +204 -0
  687. package/vendor/types/@types/d3-quadtree/package.json +45 -0
  688. package/vendor/types/@types/d3-random/LICENSE +21 -0
  689. package/vendor/types/@types/d3-random/index.d.ts +313 -0
  690. package/vendor/types/@types/d3-random/package.json +41 -0
  691. package/vendor/types/@types/d3-scale/LICENSE +21 -0
  692. package/vendor/types/@types/d3-scale/index.d.ts +2669 -0
  693. package/vendor/types/@types/d3-scale/package.json +53 -0
  694. package/vendor/types/@types/d3-scale-chromatic/LICENSE +21 -0
  695. package/vendor/types/@types/d3-scale-chromatic/index.d.ts +520 -0
  696. package/vendor/types/@types/d3-scale-chromatic/package.json +46 -0
  697. package/vendor/types/@types/d3-selection/LICENSE +21 -0
  698. package/vendor/types/@types/d3-selection/index.d.ts +1210 -0
  699. package/vendor/types/@types/d3-selection/package.json +56 -0
  700. package/vendor/types/@types/d3-shape/LICENSE +21 -0
  701. package/vendor/types/@types/d3-shape/index.d.ts +2792 -0
  702. package/vendor/types/@types/d3-shape/package.json +53 -0
  703. package/vendor/types/@types/d3-time/LICENSE +21 -0
  704. package/vendor/types/@types/d3-time/index.d.ts +697 -0
  705. package/vendor/types/@types/d3-time/package.json +46 -0
  706. package/vendor/types/@types/d3-time-format/LICENSE +21 -0
  707. package/vendor/types/@types/d3-time-format/index.d.ts +202 -0
  708. package/vendor/types/@types/d3-time-format/package.json +40 -0
  709. package/vendor/types/@types/d3-timer/LICENSE +21 -0
  710. package/vendor/types/@types/d3-timer/index.d.ts +68 -0
  711. package/vendor/types/@types/d3-timer/package.json +45 -0
  712. package/vendor/types/@types/d3-transition/LICENSE +21 -0
  713. package/vendor/types/@types/d3-transition/index.d.ts +664 -0
  714. package/vendor/types/@types/d3-transition/package.json +47 -0
  715. package/vendor/types/@types/d3-zoom/LICENSE +21 -0
  716. package/vendor/types/@types/d3-zoom/index.d.ts +611 -0
  717. package/vendor/types/@types/d3-zoom/package.json +48 -0
  718. package/vendor/types/@types/geojson/LICENSE +21 -0
  719. package/vendor/types/@types/geojson/index.d.ts +202 -0
  720. package/vendor/types/@types/geojson/package.json +46 -0
  721. package/vendor/typescript/LICENSE.txt +55 -0
  722. package/vendor/typescript/lib.decorators.d.ts +384 -0
  723. package/vendor/typescript/lib.decorators.legacy.d.ts +22 -0
  724. package/vendor/typescript/lib.dom.d.ts +39429 -0
  725. package/vendor/typescript/lib.dom.iterable.d.ts +571 -0
  726. package/vendor/typescript/lib.es2015.collection.d.ts +147 -0
  727. package/vendor/typescript/lib.es2015.core.d.ts +597 -0
  728. package/vendor/typescript/lib.es2015.d.ts +28 -0
  729. package/vendor/typescript/lib.es2015.generator.d.ts +77 -0
  730. package/vendor/typescript/lib.es2015.iterable.d.ts +605 -0
  731. package/vendor/typescript/lib.es2015.promise.d.ts +81 -0
  732. package/vendor/typescript/lib.es2015.proxy.d.ts +128 -0
  733. package/vendor/typescript/lib.es2015.reflect.d.ts +144 -0
  734. package/vendor/typescript/lib.es2015.symbol.d.ts +46 -0
  735. package/vendor/typescript/lib.es2015.symbol.wellknown.d.ts +326 -0
  736. package/vendor/typescript/lib.es2016.array.include.d.ts +116 -0
  737. package/vendor/typescript/lib.es2016.d.ts +21 -0
  738. package/vendor/typescript/lib.es2016.intl.d.ts +31 -0
  739. package/vendor/typescript/lib.es2017.arraybuffer.d.ts +21 -0
  740. package/vendor/typescript/lib.es2017.d.ts +26 -0
  741. package/vendor/typescript/lib.es2017.date.d.ts +31 -0
  742. package/vendor/typescript/lib.es2017.intl.d.ts +44 -0
  743. package/vendor/typescript/lib.es2017.object.d.ts +49 -0
  744. package/vendor/typescript/lib.es2017.sharedmemory.d.ts +135 -0
  745. package/vendor/typescript/lib.es2017.string.d.ts +45 -0
  746. package/vendor/typescript/lib.es2017.typedarrays.d.ts +53 -0
  747. package/vendor/typescript/lib.es2018.asyncgenerator.d.ts +77 -0
  748. package/vendor/typescript/lib.es2018.asynciterable.d.ts +53 -0
  749. package/vendor/typescript/lib.es2018.d.ts +24 -0
  750. package/vendor/typescript/lib.es2018.intl.d.ts +83 -0
  751. package/vendor/typescript/lib.es2018.promise.d.ts +30 -0
  752. package/vendor/typescript/lib.es2018.regexp.d.ts +37 -0
  753. package/vendor/typescript/lib.es2019.array.d.ts +79 -0
  754. package/vendor/typescript/lib.es2019.d.ts +24 -0
  755. package/vendor/typescript/lib.es2019.intl.d.ts +23 -0
  756. package/vendor/typescript/lib.es2019.object.d.ts +33 -0
  757. package/vendor/typescript/lib.es2019.string.d.ts +37 -0
  758. package/vendor/typescript/lib.es2019.symbol.d.ts +24 -0
  759. package/vendor/typescript/lib.es2020.bigint.d.ts +765 -0
  760. package/vendor/typescript/lib.es2020.d.ts +27 -0
  761. package/vendor/typescript/lib.es2020.date.d.ts +42 -0
  762. package/vendor/typescript/lib.es2020.intl.d.ts +474 -0
  763. package/vendor/typescript/lib.es2020.number.d.ts +28 -0
  764. package/vendor/typescript/lib.es2020.promise.d.ts +47 -0
  765. package/vendor/typescript/lib.es2020.sharedmemory.d.ts +99 -0
  766. package/vendor/typescript/lib.es2020.string.d.ts +44 -0
  767. package/vendor/typescript/lib.es2020.symbol.wellknown.d.ts +41 -0
  768. package/vendor/typescript/lib.es2021.d.ts +23 -0
  769. package/vendor/typescript/lib.es2021.intl.d.ts +166 -0
  770. package/vendor/typescript/lib.es2021.promise.d.ts +48 -0
  771. package/vendor/typescript/lib.es2021.string.d.ts +33 -0
  772. package/vendor/typescript/lib.es2021.weakref.d.ts +78 -0
  773. package/vendor/typescript/lib.es2022.array.d.ts +121 -0
  774. package/vendor/typescript/lib.es2022.d.ts +25 -0
  775. package/vendor/typescript/lib.es2022.error.d.ts +75 -0
  776. package/vendor/typescript/lib.es2022.intl.d.ts +145 -0
  777. package/vendor/typescript/lib.es2022.object.d.ts +26 -0
  778. package/vendor/typescript/lib.es2022.regexp.d.ts +39 -0
  779. package/vendor/typescript/lib.es2022.string.d.ts +25 -0
  780. package/vendor/typescript/lib.es5.d.ts +4601 -0
  781. package/vendor/typescript/package.json +4 -0
  782. package/vendor/typescript/typescript.js +446 -0
  783. package/web/assets/index-B6Ai3wsa.js +13 -0
  784. package/web/assets/index-SYPC3EZy.css +1 -0
  785. package/web/index.html +14 -0
@@ -0,0 +1,985 @@
1
+ import { colorLook } from "../../components/colors.mjs";
2
+ import { TABLE } from "../../components/kit.mjs";
3
+ import { SPAN } from "../../../shared/media.mjs";
4
+ import { parsedValue } from "../../../shared/number-reading.mjs";
5
+ import { lookRow } from "../../components/rows.mjs";
6
+ import { GRID, NUMBERS, TABLE_HEIGHT } from "../../components/table/index.mjs";
7
+ import { tableOf } from "../../components/table/grid.mjs";
8
+ import { columnRange, duplicateColumns, duplicateRows, insertColumn, insertRow, mergeCells, moveColumn, moveRow, optimizeTable, relayout, removeColumns, removeRows, rowRange, setHeaderColumn, setHeaderRow, splitCell, tableParts, tableSlots, tableState } from "../../components/table/page.mjs";
9
+ import { cellsIn, closeRect } from "../../components/table/slots.mjs";
10
+ import { COLOR_ICON, COLOR_WIDTH, colorItems } from "../block-menu/colors.mjs";
11
+ import { caretAt, editable } from "../caret.mjs";
12
+ import { gestureLock } from "../gesture.mjs";
13
+ import { kept } from "../kept.mjs";
14
+ import { ICONS as MENU_ICONS, createMenu } from "../menu.mjs";
15
+ import { drawAt, drawBox, layerOf } from "../overlay-layer.mjs";
16
+ import { own } from "../overlays.mjs";
17
+ import { hideTooltip, tooltip } from "../tooltip.mjs";
18
+ import { MENU_WIDTH } from "../type-grid.mjs";
19
+ import { addStyle, element } from "../ui.mjs";
20
+ import { alignItems, alignLook } from "./aligns.mjs";
21
+ import { clearCells, createCells } from "./cells.mjs";
22
+ import { TABLE_ICONS } from "./icons.mjs";
23
+ import { createColumnWidths } from "./widths.mjs";
24
+ import { t } from "../../../shared/i18n/index.mjs";
25
+
26
+ // A table's own tools (notion-lite's simple table, src/blocks/table/; the plan's T2, its rules in
27
+ // table-math-plan-2026-10-18.md), for a table written as the kit writes one (the unit the server marked GRID):
28
+ //
29
+ // - The selection: cells (a rectangle between two of them, cells.mjs, grown so that it cuts no
30
+ // merged cell), rows or columns, of one table; { unit, type: "cell" | "row" | "column", anchor,
31
+ // focus: [row, column] (slots: shared/table-slots.mjs), editing: the caret in that one cell }.
32
+ // It is drawn as a 2px blue frame around it, light blue inside (not the caret's cell: it is the
33
+ // text's); a row's or column's grip turns blue.
34
+ // - Merged cells (Feishu's 合并单元格, from the cells' bar): the selected cells made one, a merged
35
+ // cell made separate cells again (components/table/page.mjs mergeCells, splitCell).
36
+ // - The grips: a small grip on the top edge of a column and the left edge of a row, on the edge's
37
+ // line (notion-lite's: an 18×6 pill), a white button with drag dots under the pointer. Each shows
38
+ // only with the pointer at its edge (REACH: the table's top edge over that column, its left edge
39
+ // beside that row; the user's, 2026-10-23: none while the pointer, or the caret, is just in a
40
+ // cell), and a selected row's or column's stays while it is selected. A press selects the row or
41
+ // column; let go without moving, its menu opens (列: below the grip; 行: right of it), with a
42
+ // search field: 标题行 / 标题列 (on the first, switched in place), 颜色 ›, 对齐 › (columns), insert
43
+ // either side (the new one selected), 创建副本, 清除内容, 删除 (not the last). Dragged past 3px, it
44
+ // moves (a blue line where it goes, a pale copy under the pointer; Esc cancels); moved first, a
45
+ // row (column) is the header one.
46
+ // - The + points (Feishu's): at the ends of a column's top edge and a row's left edge, with that
47
+ // column's (row's) grip, a dot that turns into a blue + with a line across the table: a click puts
48
+ // a column or row in there.
49
+ // - The columns' widths (widths.mjs): a strip on each column's right edge sizes it.
50
+ // - The corner: with the pointer on the table, a round + just past its bottom right corner (the
51
+ // only one: no bars along its edges). A click adds a row; dragged, it adds rows down and columns
52
+ // right, one more per 32px (rows) or 120px (columns), and dragged back the empty last ones go (it
53
+ // stops at one that is not), across, down or both at once.
54
+ // A table wider or taller than its frame scrolls in it: the tools stand by what the frame shows of
55
+ // it (the geometry's view), the grips and + points of the rows and columns in sight.
56
+ // Each change is one undo step; the page writes it as one operation of the table (grid.mjs). The
57
+ // keys and the cells' bar are cells.mjs's.
58
+
59
+ const STYLE = `
60
+ .ge-tgrip { display: flex; align-items: center; justify-content: center; cursor: grab; pointer-events: auto; }
61
+ .ge-tgrip > i { box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid light-dark(#ffffff, #191919); border-radius: 4px; background: light-dark(#d3d1cb, #5a5a58); transition: width 100ms, height 100ms, background 100ms; }
62
+ .ge-tgrip[data-axis="column"] > i { width: 18px; height: 6px; }
63
+ .ge-tgrip[data-axis="row"] > i { width: 6px; height: 18px; }
64
+ .ge-tgrip > i > svg { display: none; flex: none; width: 16px; height: 16px; fill: var(--ge-tx3); }
65
+ .ge-tgrip[data-axis="column"] > i > svg { transform: rotate(90deg); }
66
+ .ge-tgrip:is(:hover, [data-on], [data-selected]) > i { border: 1px solid var(--ge-line-strong); background: var(--ge-bg); box-shadow: 0 1px 2px rgb(0 0 0 / 8%); }
67
+ /* It comes in under the pointer only: a selected grip is drawn anew as the pointer moves over the table, and stays still. */
68
+ .ge-tgrip:hover:not([data-selected], [data-on]) > i { animation: ge-tgrip-in 100ms ease-out; }
69
+ .ge-tgrip[data-axis="column"]:is(:hover, [data-on], [data-selected]) > i { width: 22px; height: 14px; }
70
+ .ge-tgrip[data-axis="row"]:is(:hover, [data-on], [data-selected]) > i { width: 14px; height: 22px; }
71
+ .ge-tgrip:is(:hover, [data-on], [data-selected]) > i > svg { display: block; }
72
+ .ge-tgrip[data-selected] > i { border-color: var(--ge-accent); background: var(--ge-accent); }
73
+ .ge-tgrip[data-selected] > i > svg { fill: #ffffff; }
74
+ @keyframes ge-tgrip-in { from { transform: scale(.7); opacity: 0; } }
75
+ .ge-tplus { display: grid; place-items: center; width: 18px; height: 18px; cursor: pointer; pointer-events: auto; }
76
+ .ge-tplus > i { display: grid; place-items: center; width: 4px; height: 4px; border-radius: 50%; background: light-dark(#c9c7c2, #6b6b68); transition: width 100ms, height 100ms, background 100ms; }
77
+ .ge-tplus > i > svg { display: none; width: 10px; height: 10px; fill: none; stroke: #ffffff; stroke-width: 2; stroke-linecap: round; }
78
+ .ge-tplus:hover > i { width: 18px; height: 18px; background: var(--ge-accent); box-shadow: 0 0 0 2px light-dark(#ffffff, #191919); }
79
+ .ge-tplus:hover > i > svg { display: block; }
80
+ .ge-tline { border-radius: 1px; background: var(--ge-accent); pointer-events: none; }
81
+ .ge-tgrow { box-sizing: border-box; display: grid; place-items: center; border: 1px solid var(--ge-line-strong); border-radius: 50%; background: var(--ge-bg); color: var(--ge-tx3); box-shadow: 0 1px 2px rgb(0 0 0 / 6%); cursor: nwse-resize; pointer-events: auto; transition: background 80ms, color 80ms; }
82
+ .ge-tgrow:hover, .ge-tgrow[data-on] { background: light-dark(#f1f1ef, #2f2f2f); color: light-dark(#55534e, #c4c1bb); }
83
+ .ge-tgrow > svg { width: 10px; height: 10px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }
84
+ .ge-tframe { box-sizing: border-box; border: 2px solid var(--ge-accent); border-radius: 2px; background: color-mix(in srgb, var(--ge-accent) 9%, transparent); pointer-events: none; }
85
+ .ge-tghost { overflow: visible; border-radius: 2px; box-shadow: 0 0 0 1px rgb(15 15 15 / 5%), 0 3px 6px rgb(15 15 15 / 10%), 0 9px 24px rgb(15 15 15 / 20%); opacity: .9; pointer-events: none; }
86
+ .ge-tghost > .ge-tghost-cells { position: absolute; inset: 0; overflow: hidden; border-radius: 2px; }
87
+ .ge-tghost-cells > div { position: absolute; box-sizing: border-box; overflow: hidden; }
88
+ .ge-tghost > .ge-tghost-frame { position: absolute; inset: -0.5px; border: 2px solid var(--ge-accent); border-radius: 2px; }
89
+ .ge-tghost > .ge-tghost-grip { position: absolute; display: flex; align-items: center; justify-content: center; box-sizing: border-box; border: 1px solid var(--ge-accent); border-radius: 4px; background: var(--ge-accent); }
90
+ .ge-tghost[data-axis="column"] > .ge-tghost-grip { top: -7.5px; left: 50%; width: 22px; height: 14px; margin-left: -11px; }
91
+ .ge-tghost[data-axis="row"] > .ge-tghost-grip { left: -7.5px; top: 50%; width: 14px; height: 22px; margin-top: -11px; }
92
+ .ge-tghost > .ge-tghost-grip > svg { flex: none; width: 16px; height: 16px; fill: #ffffff; }
93
+ .ge-tghost[data-axis="column"] > .ge-tghost-grip > svg { transform: rotate(90deg); }
94
+ /* A sortable header being written in: no arrow (the kit's, tables/sort.js) to press by mistake. */
95
+ .doc-table th:focus-within > .doc-table-sort-button { display: none; }
96
+ .ge-tsize { width: max-content; padding: 2px 8px; border-radius: 6px; background: var(--ge-tip-bg); color: #ffffff; font: 12px/18px ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif; white-space: nowrap; pointer-events: none; }
97
+ ${gestureLock("data-ge-tdrag", { cursor: "grabbing", select: true })}
98
+ `;
99
+ const ICONS = TABLE_ICONS;
100
+ const STEP = { row: [32, 8], column: [120, 30] }; // a bar dragged this far adds one more (after the slack)
101
+ const DRAG = 3; // a press on a grip moved this far drags it
102
+ const REACH = { out: 12, in: 8 }; // the pointer this near the table's top (left) edge, outside it or in, shows a column's (row's) grip and + points
103
+
104
+ /**
105
+ * active(): whether the tools may show. struct(parents, touched, mutate): the editor's undoable
106
+ * structural change; look(elements, change, select): a change of classes and sizes as one undo step. selectBlock(unit):
107
+ * select the table as a block (Esc). resizeTable(event, unit, axis): a drag of the table's width
108
+ * ("x") or scroll height ("y") from an armed edge (resize/). say: the status line. ownCells(data): the
109
+ * page's own text or blocks on the clipboard as rows of cells' inline HTML, or null (clipboard/).
110
+ * typedKey(event): a key that is the "/" or "@" menu's, standing on a cell's text (slash-menu/, at-menu/), comes before the cell's.
111
+ */
112
+ export function createTableEditing({ active, struct, look, selectBlock, resizeTable = () => false, say, ownCells = () => null, typedKey = () => false }) {
113
+ addStyle(STYLE);
114
+ const menu = createMenu();
115
+ let hover = null; // { unit, row, column, edges: { row, column } }: the cell under the pointer, and whether it is at the table's left (top) edge (edgesAt)
116
+ let sel = null; // the selection (above)
117
+ let drag = null; // a grip pressed: { unit, axis, from, to, x, y, moved } | the corner: { unit, x, y, ops, counts, moved }
118
+ let keyboard = false; // the keys moved the selection: the hover tools wait for the pointer
119
+ const nodes = new Set();
120
+ const drawn = (node) => (nodes.add(node), own(node, "table tools", { alive: () => nodes.has(node) }));
121
+ const grips = { column: null, row: null }; // the selection's grips drawn now (its menu stands by one)
122
+
123
+ // ---------- where things are ----------
124
+
125
+ // The table unit with a grid (GRID) a node is in, or null.
126
+ const tableAt = (node) => {
127
+ const unit = node?.closest?.(`main [data-ge-unit-kind="table"][${GRID}]`);
128
+ return unit && !unit.closest("[data-ge-lock], [inert]") ? unit : null;
129
+ };
130
+ const rectOf = (node) => node.getBoundingClientRect();
131
+ // The table's box, what its frame shows of it (view: the box, or the part in sight when the table
132
+ // scrolls inside its frame), its columns (left, right: the slots', shared/table-slots.mjs) and rows (top,
133
+ // bottom); window coordinates.
134
+ function geometry(unit) {
135
+ const { rows, table, slots } = tableState(unit);
136
+ const box = rectOf(table);
137
+ return {
138
+ box,
139
+ view: viewOf(unit, table, box),
140
+ columns: slots ? columnEdges(slots) : [...(rows[0]?.cells ?? [])].map((cell) => ({ left: rectOf(cell).left, right: rectOf(cell).right })),
141
+ rows: rows.map((row) => ({ top: rectOf(row).top, bottom: rectOf(row).bottom })),
142
+ };
143
+ }
144
+ // What a table's frame shows of it (the table's box, or the part in sight when it scrolls inside its frame).
145
+ function viewOf(unit, table = tableOf(unit), box = rectOf(table)) {
146
+ const frame = rectOf(unit);
147
+ const inside = unit === table ? box : { left: frame.left + unit.clientLeft, top: frame.top + unit.clientTop, right: frame.left + unit.clientLeft + unit.clientWidth, bottom: frame.top + unit.clientTop + unit.clientHeight };
148
+ return { left: Math.max(box.left, inside.left), top: Math.max(box.top, inside.top), right: Math.min(box.right, inside.right), bottom: Math.min(box.bottom, inside.bottom) };
149
+ }
150
+ /**
151
+ * Whether a point is at a table's edges where its grips stand ({ column, row }): within REACH of
152
+ * the top edge in sight (over its columns: a column's grip and + points), of the left edge (beside
153
+ * its rows: a row's).
154
+ */
155
+ function edgesAt(unit, x, y) {
156
+ const view = viewOf(unit);
157
+ const across = x >= view.left - REACH.out && x <= view.right + REACH.out;
158
+ const along = y >= view.top - REACH.out && y <= view.bottom + REACH.out;
159
+ return {
160
+ column: across && y >= view.top - REACH.out && y <= view.top + REACH.in,
161
+ row: along && x >= view.left - REACH.out && x <= view.left + REACH.in,
162
+ };
163
+ }
164
+ // The columns' edges: where the cells of one column begin and end (a merged cell's own ones
165
+ // where no such cell says), those no cell says shared out evenly between the ones around them.
166
+ function columnEdges(slots) {
167
+ const edges = Array(slots.columns + 1).fill(null);
168
+ const places = [...slots.places].sort(([, a], [, b]) => a.cols - b.cols);
169
+ for (const [cell, place] of places) {
170
+ const rect = rectOf(cell);
171
+ edges[place.c] ??= rect.left;
172
+ edges[place.c + place.cols] ??= rect.right;
173
+ }
174
+ for (let c = 0; c <= slots.columns; c++) {
175
+ if (edges[c] !== null) continue;
176
+ let next = c + 1;
177
+ while (edges[next] === null) next++;
178
+ edges[c] = edges[c - 1] + (edges[next] - edges[c - 1]) / (next - c + 1);
179
+ }
180
+ return Array.from({ length: slots.columns }, (_, c) => ({ left: edges[c], right: edges[c + 1] }));
181
+ }
182
+ /** Whether a row's (column's) middle is in sight in its frame. */
183
+ function inSight(g, axis, index) {
184
+ const at = axis === "column" ? g.columns[index] : g.rows[index];
185
+ if (!at) return false;
186
+ const middle = axis === "column" ? (at.left + at.right) / 2 : (at.top + at.bottom) / 2;
187
+ return axis === "column" ? middle >= g.view.left && middle <= g.view.right : middle >= g.view.top && middle <= g.view.bottom;
188
+ }
189
+ /** The cell of a table's slots (tableSlots, read once for what is asked of it) covering the slot [row, column], or null. */
190
+ const cellOf = (slots, [r, c]) => slots?.matrix[r]?.[c] ?? null;
191
+ /** Where a cell is in its table's slots: its top left slot [row, column], or null. */
192
+ function placeOf(slots, cell) {
193
+ const place = slots?.places.get(cell);
194
+ return place ? [place.r, place.c] : null;
195
+ }
196
+ /** The cell at a point of the window, the nearest one when it is outside the table: [row, column]. */
197
+ function cellAt(unit, x, y) {
198
+ const g = geometry(unit);
199
+ if (g.rows.length === 0 || g.columns.length === 0) return null;
200
+ const r = g.rows.findIndex((row) => y < row.bottom);
201
+ const c = g.columns.findIndex((column) => x < column.right);
202
+ return [r < 0 ? g.rows.length - 1 : r, c < 0 ? g.columns.length - 1 : c];
203
+ }
204
+
205
+ // ---------- the selection ----------
206
+
207
+ /**
208
+ * The selection's rectangle: { r0, r1, c0, c1 } (inclusive; a row's all its columns, a column's all
209
+ * its rows; cells grown so that it cuts no merged cell).
210
+ */
211
+ function bounds(s = sel) {
212
+ const { rows, columns, slots } = tableState(s.unit);
213
+ const [ar, ac] = s.anchor;
214
+ const [fr, fc] = s.focus;
215
+ const rect = {
216
+ r0: s.type === "column" ? 0 : Math.min(ar, fr), r1: s.type === "column" ? rows.length - 1 : Math.max(ar, fr),
217
+ c0: s.type === "row" ? 0 : Math.min(ac, fc), c1: s.type === "row" ? columns - 1 : Math.max(ac, fc),
218
+ };
219
+ return s.type === "cell" && slots && rect.r1 < rows.length && rect.c1 < columns ? closeRect(slots, rect) : rect;
220
+ }
221
+ /** The selected cells (those covering the selection's slots), each once, row by row. */
222
+ function selectedCells(s = sel) {
223
+ if (!s?.unit.isConnected) return [];
224
+ const { slots } = tableState(s.unit);
225
+ return slots ? cellsIn(slots, bounds(s)) : [];
226
+ }
227
+
228
+ // A selection made (no caret: the text selection goes, and the focus with it).
229
+ function select(next) {
230
+ sel = next;
231
+ if (next && !next.editing) {
232
+ getSelection().removeAllRanges();
233
+ const focused = document.activeElement;
234
+ if (focused?.closest?.("td, th") && next.unit.contains(focused)) focused.blur();
235
+ }
236
+ if (!next) menu.close();
237
+ draw();
238
+ }
239
+ const tools = {
240
+ get sel() { return sel; },
241
+ selectCells: (unit, anchor, focus = anchor) => select({ unit, type: "cell", anchor, focus, editing: false }),
242
+ selectRows: (unit, from, to = from) => select({ unit, type: "row", anchor: [from, 0], focus: [to, 0], editing: false }),
243
+ selectColumns: (unit, from, to = from) => select({ unit, type: "column", anchor: [0, from], focus: [0, to], editing: false }),
244
+ /** The caret in a cell (where: "start" | "end"), the cell its selection. */
245
+ editCell(unit, at, where = "end") {
246
+ const slots = tableSlots(unit);
247
+ const cell = cellOf(slots, at);
248
+ if (!cell) return;
249
+ at = placeOf(slots, cell);
250
+ sel = { unit, type: "cell", anchor: at, focus: at, editing: true };
251
+ caretAt(cell, where);
252
+ draw();
253
+ },
254
+ /** The caret came into a cell by itself (a click, the arrows): its selection. */
255
+ editing(unit, at) {
256
+ sel = { unit, type: "cell", anchor: at, focus: at, editing: true };
257
+ draw();
258
+ },
259
+ clear: () => select(null),
260
+ selectBlock: (unit) => {
261
+ select(null);
262
+ selectBlock(unit);
263
+ },
264
+ bounds, selectedCells, tableAt, placeOf, cellOf, cellAt, geometry, change, insert, removeRange, duplicate, merge, split, look, struct, say,
265
+ active,
266
+ menuOpen: () => menu.isOpen,
267
+ typedKey,
268
+ resizeTable,
269
+ ownCells,
270
+ dragging: () => drag !== null,
271
+ keys: (on) => {
272
+ keyboard = on;
273
+ draw();
274
+ },
275
+ draw: () => draw(),
276
+ };
277
+ const cells = createCells(tools);
278
+ const widths = createColumnWidths(tools);
279
+
280
+ // ---------- drawing ----------
281
+
282
+ const clear = () => {
283
+ for (const node of nodes) node.remove();
284
+ nodes.clear();
285
+ grips.column = grips.row = null;
286
+ };
287
+
288
+ // The table the tools stand by, watched: the kit lays it out again after a change (its columns'
289
+ // widths), and the tools follow.
290
+ let watched = null;
291
+ const watch = new ResizeObserver(() => { if (!drag && (hover || sel)) draw(); });
292
+ function follow(unit) {
293
+ const { table, rows } = unit ? tableParts(unit) : {};
294
+ const key = table ? [table, ...rows, ...(rows[0]?.cells ?? [])] : [];
295
+ if (watched && watched.length === key.length && watched.every((node, index) => node === key[index])) return;
296
+ watch.disconnect();
297
+ key.forEach((node) => watch.observe(node));
298
+ watched = key;
299
+ }
300
+
301
+ function draw() {
302
+ clear();
303
+ if (sel && !sel.unit.isConnected) sel = null;
304
+ const unit = sel?.unit ?? hover?.unit;
305
+ follow(unit?.isConnected ? unit : null);
306
+ cells.update();
307
+ if (!unit?.isConnected || !active()) return widths.disarm();
308
+ const layer = layerOf(unit);
309
+ const g = geometry(unit);
310
+ // The hovered cell, while the table still has it (a row or column taken out may have been it).
311
+ const pointer = hover?.unit === unit && !keyboard && g.rows[hover.row] && g.columns[hover.column] ? hover : null;
312
+ // The grips: the hovered cell's column with the pointer at the table's top edge, its row at the
313
+ // left edge (edgesAt); the selected rows or columns (blue).
314
+ const shown = { row: new Set(), column: new Set() };
315
+ if (sel?.type === "row" || sel?.type === "column") {
316
+ const { r0, r1, c0, c1 } = bounds();
317
+ const [from, to] = sel.type === "row" ? [r0, r1] : [c0, c1];
318
+ for (let index = from; index <= to; index++) shown[sel.type].add(index);
319
+ }
320
+ if (pointer && !drag?.ops) {
321
+ if ((!drag || drag.axis === "column") && pointer.edges.column) shown.column.add(pointer.column);
322
+ if ((!drag || drag.axis === "row") && pointer.edges.row) shown.row.add(pointer.row);
323
+ }
324
+ // Moved, the rows (columns) dragged are their copy under the pointer, with their frame and grip (dragTo).
325
+ const moving = Boolean(drag?.moved && drag.ghost);
326
+ if (moving) shown.row.clear(), shown.column.clear();
327
+ // The selected cells (rows, columns) framed (under the grips on its edge); the caret's cell is not.
328
+ if (sel && sel.unit === unit && !moving && !sel.editing) frame(layer, g);
329
+ for (const axis of ["column", "row"]) for (const index of shown[axis]) if (inSight(g, axis, index)) grip(layer, unit, axis, index, g);
330
+ if ((pointer && !drag) || widths.dragging) widths.draw(layer, unit, g, drawn);
331
+ else widths.disarm();
332
+ if (pointer && !drag && !widths.dragging) {
333
+ if (pointer.edges.column) for (const at of [pointer.column, pointer.column + 1]) plus(layer, unit, "column", at, g);
334
+ if (pointer.edges.row) for (const at of [pointer.row, pointer.row + 1]) plus(layer, unit, "row", at, g);
335
+ }
336
+ if (drag?.ops || (pointer && !drag)) corner(layer, unit, g);
337
+ if (drag?.moved && drag.to !== undefined && drag.to !== drag.from && (drag.axis === "row" ? g.rows : g.columns)[drag.to]) dropLine(layer, g, drag);
338
+ }
339
+
340
+ function grip(layer, unit, axis, index, g) {
341
+ const node = drawn(element("div", { class: "ge-tgrip", "data-axis": axis, "data-doc-dev": "", html: `<i>${ICONS.dots}</i>`, role: "button", "aria-label": axis === "column" ? t("移动列") : t("移动行") }));
342
+ if (sel?.type === axis && sel.unit === unit) {
343
+ const { r0, r1, c0, c1 } = bounds();
344
+ const [from, to] = axis === "row" ? [r0, r1] : [c0, c1];
345
+ if (index >= from && index <= to) node.setAttribute("data-selected", "");
346
+ if (index === from) grips[axis] = node;
347
+ }
348
+ if (drag?.axis === axis && drag.from === index) node.setAttribute("data-on", "");
349
+ // On the line of the table's edge in sight (the frame's border, half a pixel out): across the
350
+ // column's top, along the row's left.
351
+ const size = axis === "column" ? { w: 26, h: 16 } : { w: 16, h: 26 };
352
+ const x = axis === "column" ? (g.columns[index].left + g.columns[index].right) / 2 : g.view.left - 0.5;
353
+ const y = axis === "column" ? g.view.top - 0.5 : (g.rows[index].top + g.rows[index].bottom) / 2;
354
+ drawBox(node, layer, { left: x - size.w / 2, top: y - size.h / 2, right: x + size.w / 2, bottom: y + size.h / 2 });
355
+ node.addEventListener("pointerdown", (event) => {
356
+ if (event.button !== 0) return;
357
+ event.preventDefault();
358
+ event.stopImmediatePropagation();
359
+ menu.close();
360
+ hideTooltip();
361
+ // The rows or columns selected, no caret left in text, nor the focus (which would bring the
362
+ // caret back): a caret elsewhere would let the selection go (cells.mjs). The keys go to the
363
+ // menu and the selection.
364
+ if (editable(document.activeElement)) document.activeElement.blur();
365
+ getSelection().removeAllRanges();
366
+ if (axis === "row") tools.selectRows(unit, index);
367
+ else tools.selectColumns(unit, index);
368
+ drag = { unit, axis, from: index, to: index, x: event.clientX, y: event.clientY, moved: false };
369
+ document.documentElement.setPointerCapture?.(event.pointerId);
370
+ });
371
+ }
372
+
373
+ function plus(layer, unit, axis, at, g) {
374
+ const x = axis === "column" ? (at < g.columns.length ? g.columns[at].left : g.columns[at - 1].right) : g.view.left;
375
+ const y = axis === "column" ? g.view.top : at < g.rows.length ? g.rows[at].top : g.rows[at - 1].bottom;
376
+ // Only on an edge in sight.
377
+ if (axis === "column" ? x < g.view.left - 1 || x > g.view.right + 1 : y < g.view.top - 1 || y > g.view.bottom + 1) return;
378
+ const node = drawn(element("div", { class: "ge-tplus", "data-doc-dev": "", html: `<i>${ICONS.plus}</i>` }));
379
+ tooltip(node, axis === "column" ? t("在这里插入一列") : t("在这里插入一行"));
380
+ drawBox(node, layer, { left: x - 9, top: y - 9, right: x + 9, bottom: y + 9 });
381
+ const line = element("div", { class: "ge-tline", "data-doc-dev": "" });
382
+ node.addEventListener("pointerenter", () => {
383
+ drawn(line);
384
+ layer.insertBefore(line, node); // under the +, which stays whole
385
+ if (axis === "column") drawBox(line, layer, { left: x - 1, top: g.view.top, right: x + 1, bottom: g.view.bottom });
386
+ else drawBox(line, layer, { left: g.view.left, top: y - 1, right: g.view.right, bottom: y + 1 });
387
+ });
388
+ node.addEventListener("pointerleave", () => line.remove());
389
+ node.addEventListener("pointerdown", (event) => {
390
+ event.preventDefault();
391
+ event.stopImmediatePropagation();
392
+ insert(unit, axis, at);
393
+ });
394
+ }
395
+
396
+ // The corner: a round + just past the bottom right corner of what the frame shows (clear of the
397
+ // right edge's strip, widths.mjs); while it is dragged, pressed.
398
+ function corner(layer, unit, g) {
399
+ const node = drawn(element("div", { class: "ge-tgrow", "data-doc-dev": "", html: ICONS.grow, role: "button", "aria-label": t("添加行或列") }));
400
+ if (drag?.ops) node.setAttribute("data-on", "");
401
+ else tooltip(node, t("点击以添加新行"), t("拖动以添加或移除行和列"));
402
+ drawBox(node, layer, { left: g.view.right + 2, top: g.view.bottom + 2, right: g.view.right + 20, bottom: g.view.bottom + 20 });
403
+ node.addEventListener("pointerdown", (event) => {
404
+ if (event.button !== 0) return;
405
+ event.preventDefault();
406
+ event.stopImmediatePropagation();
407
+ hideTooltip();
408
+ drag = { unit, x: event.clientX, y: event.clientY, ops: [], counts: { row: 0, column: 0 }, moved: false };
409
+ document.documentElement.setPointerCapture?.(event.pointerId);
410
+ });
411
+ }
412
+
413
+ // Around the selection, 2px blue (notion-lite's frame, half a pixel past the cells), cut to what
414
+ // the frame shows.
415
+ function frame(layer, g) {
416
+ const { r0, r1, c0, c1 } = bounds();
417
+ if (!g.rows[r0] || !g.rows[r1] || !g.columns[c0] || !g.columns[c1]) return;
418
+ const box = {
419
+ left: Math.max(g.columns[c0].left, g.view.left) - 0.5, top: Math.max(g.rows[r0].top, g.view.top) - 0.5,
420
+ right: Math.min(g.columns[c1].right, g.view.right) + 0.5, bottom: Math.min(g.rows[r1].bottom, g.view.bottom) + 0.5,
421
+ };
422
+ if (box.right - box.left < 2 || box.bottom - box.top < 2) return;
423
+ drawBox(drawn(element("div", { class: "ge-tframe", "data-doc-dev": "" })), layer, box);
424
+ }
425
+
426
+ function dropLine(layer, g, { axis, from, to }) {
427
+ const node = drawn(element("div", { class: "ge-tline", "data-doc-dev": "" }));
428
+ if (axis === "column") {
429
+ const x = to > from ? g.columns[to].right : g.columns[to].left;
430
+ drawBox(node, layer, { left: x - 1.5, top: g.view.top, right: x + 1.5, bottom: g.view.bottom });
431
+ } else {
432
+ const y = to > from ? g.rows[to].bottom : g.rows[to].top;
433
+ drawBox(node, layer, { left: g.view.left, top: y - 1.5, right: g.view.right, bottom: y + 1.5 });
434
+ }
435
+ }
436
+
437
+ // The rows (columns) dragged as they look, going with the pointer (notion-lite's): their cells in
438
+ // their places, sizes, words and fills on the table's background (no table of the kit's, which its
439
+ // runtime would lay out), the part the frame shows, a shadow under them, the selection's frame
440
+ // around them and their grip on it, blue. Returns { node, size, offset } (offset: where the copy
441
+ // begins along its axis, from the table's edge in sight).
442
+ function ghostOf(unit, axis, [from, to]) {
443
+ const { slots, table, rows, columns } = tableState(unit);
444
+ const g = geometry(unit);
445
+ const box = axis === "column"
446
+ ? { left: g.columns[from].left, right: g.columns[to].right, top: g.view.top, bottom: g.view.bottom }
447
+ : { left: g.view.left, right: g.view.right, top: g.rows[from].top, bottom: g.rows[to].bottom };
448
+ const cells = cellsIn(slots, axis === "column" ? { r0: 0, r1: rows.length - 1, c0: from, c1: to } : { r0: from, r1: to, c0: 0, c1: columns - 1 });
449
+ const copies = cells.map((cell) => {
450
+ const rect = rectOf(cell);
451
+ const style = getComputedStyle(cell);
452
+ const copy = element("div");
453
+ copy.style.cssText = `left: ${rect.left - box.left}px; top: ${rect.top - box.top}px; width: ${rect.width}px; height: ${rect.height}px; padding: ${style.padding}; background: ${style.backgroundColor}; color: ${style.color}; font: ${style.font}; text-align: ${style.textAlign}; border-right: ${style.borderRightWidth} solid ${style.borderRightColor}; border-bottom: ${style.borderBottomWidth} solid ${style.borderBottomColor}`;
454
+ // Its content as shown, without what makes it the page's (block marks, editing, ids).
455
+ copy.append(...[...cell.childNodes].map((node) => node.cloneNode(true)));
456
+ for (const inner of copy.querySelectorAll("*")) for (const { name } of [...inner.attributes]) if (/^(data-ge-|contenteditable$|id$)/.test(name)) inner.removeAttribute(name);
457
+ return copy;
458
+ });
459
+ const node = own(element("div", { class: "ge-tghost", "data-axis": axis, "data-doc-dev": "" },
460
+ element("div", { class: "ge-tghost-cells" }, ...copies), element("i", { class: "ge-tghost-frame" }), element("b", { class: "ge-tghost-grip", html: ICONS.dots })), "table ghost", { alive: () => drag?.ghost === node });
461
+ node.style.background = getComputedStyle(table).backgroundColor;
462
+ return { node, size: { width: box.right - box.left, height: box.bottom - box.top }, offset: axis === "column" ? box.left - g.view.left : box.top - g.view.top };
463
+ }
464
+
465
+ // ---------- what they do ----------
466
+
467
+ // The parents a change of the table touches: its sections and rows (their child lists).
468
+ const parentsOf = (unit) => {
469
+ const { table, rows } = tableParts(unit);
470
+ return [table, ...table.querySelectorAll(":scope > thead, :scope > tbody"), ...rows];
471
+ };
472
+
473
+ // One undo step: the table's sections and rows as child lists (a thead it puts in made), the cells
474
+ // it makes (a new one, a retagged one) and `touched` (cells whose text it changes) with their text.
475
+ // Returns what mutate made, or null.
476
+ function change(unit, mutate, said, touched = []) {
477
+ let made = [];
478
+ const { head, rows: rowsBefore } = tableParts(unit);
479
+ const cellsBefore = new Set(rowsBefore.flatMap((row) => [...row.cells]));
480
+ // The cells' spans and widths, which the change may set, recorded with it; the frame's sizes and
481
+ // 识别数字列 (一键优化).
482
+ const attributes = [...[...cellsBefore].map((cell) => [cell, ["rowspan", "colspan", "style"]]), [unit, ["style", NUMBERS]]];
483
+ const result = struct(parentsOf(unit), touched, () => {
484
+ const out = mutate();
485
+ if (out === false) return null;
486
+ made = Array.isArray(out) ? out : out && out !== true ? [out] : [];
487
+ const now = tableState(unit);
488
+ const created = now.head && now.head !== head ? [now.head] : [];
489
+ const fresh = now.rows.flatMap((row) => [...row.cells]).filter((cell) => !cellsBefore.has(cell));
490
+ return { touched: [...touched, ...fresh], focus: null, created };
491
+ }, { attributes });
492
+ if (result && said) say(t("{0} · Ctrl+Z 撤销", said));
493
+ return result ? made : null;
494
+ }
495
+
496
+ /** A row or column put in at `at`, selected (notion-lite's). */
497
+ function insert(unit, axis, at) {
498
+ const made = change(unit, () => (axis === "column" ? insertColumn(unit, at) : insertRow(unit, at)), axis === "column" ? t("已插入一列") : t("已插入一行"));
499
+ if (!made) return;
500
+ if (axis === "column") tools.selectColumns(unit, at);
501
+ else tools.selectRows(unit, at);
502
+ }
503
+
504
+ /** Columns (rows) `from` … `to` taken out, never every one; returns whether they were. */
505
+ function removeRange(unit, axis, from, to) {
506
+ const done = change(unit, () => (axis === "column" ? removeColumns(unit, from, to) : removeRows(unit, from, to)), axis === "column" ? t("已删除列") : t("已删除行"));
507
+ if (done === null) say(axis === "column" ? t("表格至少要留一列。") : t("表格至少要留一行正文。"));
508
+ draw();
509
+ return done !== null;
510
+ }
511
+
512
+ // The menu of the selected rows or columns (notion-lite's, with the plan's 对齐 for columns).
513
+ function openMenu() {
514
+ const anchor = sel && grips[sel.type];
515
+ if (!anchor) return;
516
+ const { unit, type } = sel;
517
+ const { r0, r1, c0, c1 } = bounds();
518
+ const [from, to] = type === "row" ? [r0, r1] : [c0, c1];
519
+ const state = tableState(unit);
520
+ const count = type === "row" ? state.rows.length : state.columns;
521
+ const targets = selectedCells();
522
+ const items = [];
523
+ // 标题行 / 标题列: switched in place, the menu stays.
524
+ if (type === "row" && from === 0 && to === 0) items.push({ label: t("标题行"), icon: ICONS.headerRow, checked: state.headerRow, run: () => { headerRow(unit, state); reopen(); } });
525
+ if (type === "column" && from === 0 && to === 0) items.push({ label: t("标题列"), icon: ICONS.headerColumn, checked: state.headerColumn, run: () => { change(unit, () => setHeaderColumn(unit, !state.headerColumn), state.headerColumn ? t("已取消标题列") : t("已设为标题列")); reopen(); } });
526
+ items.push({ label: t("颜色"), icon: COLOR_ICON, width: COLOR_WIDTH, submenu: () => colorItems(targets, (cells, color) => look(cells, colorLook(color, { only: true })), () => menu.close(), { recent: false }) });
527
+ if (type === "column") {
528
+ // The three alignments, then the three vertical ones (aligns.mjs): each the cells' own class of its kind.
529
+ const alignments = alignItems(targets, (name) => look(targets, alignLook(name)));
530
+ items.push({ label: t("对齐"), icon: ICONS["doc-align-left"], submenu: () => [...alignments.filter((item) => !item.vertical), { separator: true }, ...alignments.filter((item) => item.vertical)] });
531
+ }
532
+ items.push({ separator: true });
533
+ if (type === "row") items.push({ label: t("在上方插入"), icon: ICONS.above, run: () => insert(unit, "row", from) }, { label: t("在下方插入"), icon: ICONS.below, run: () => insert(unit, "row", to + 1) });
534
+ else items.push({ label: t("在左侧插入"), icon: ICONS.left, run: () => insert(unit, "column", from) }, { label: t("在右侧插入"), icon: ICONS.right, run: () => insert(unit, "column", to + 1) });
535
+ if (type === "column") {
536
+ // The columns' widths: shared out equally (several selected); the kit's own, or fixed as they are.
537
+ if (to > from) items.push({ label: t("均分列宽"), icon: ICONS.even, run: () => widths.even(unit, from, to) });
538
+ items.push({ label: t("一键调整列宽"), icon: ICONS.autoWidth, run: () => widths.fit(unit) });
539
+ }
540
+ items.push(
541
+ { label: t("创建副本"), icon: ICONS.duplicate, hint: "Ctrl+D", run: () => duplicate(unit, type, from, to) },
542
+ { label: t("清除内容"), icon: ICONS.clear, run: () => { clearCells(tools, targets); tools.clear(); } },
543
+ );
544
+ const all = type === "row" ? from <= state.rows.length - state.body.rows.length && to >= state.rows.length - 1 : to - from + 1 >= count;
545
+ if (count > 1 && !all) items.push({ separator: true }, { label: t("删除"), icon: ICONS.trash, hint: "Del", run: () => { if (removeRange(unit, type, from, to)) tools.clear(); } });
546
+ // As wide as the block menu, no search field: its rows are few.
547
+ const rect = anchor.getBoundingClientRect();
548
+ menu.open(items, { left: rect.left, right: rect.right, top: rect.top, bottom: rect.bottom }, { label: type === "column" ? t("列") : t("行"), side: type === "row" ? "right" : undefined, width: MENU_WIDTH, onClose: () => draw() });
549
+ }
550
+ const reopen = () => requestAnimationFrame(() => { if (sel) openMenu(); });
551
+ // 一键优化 (page.mjs optimizeTable), one undo step.
552
+ function optimize(unit) {
553
+ if (change(unit, () => optimizeTable(unit), t("已一键优化")) === null) say(t("这个表格已经是优化后的样子。"));
554
+ relayout(unit);
555
+ }
556
+ // 识别数字列 (an action, as 一键优化's part of it): the kit reads the table's numeric columns again
557
+ // (index.mjs NUMBERS taken off: centered, sortable by their header's arrow), one undo step; the kit
558
+ // watches the attribute (tables/index.js), undo included.
559
+ function numbers(unit) {
560
+ if (look(unit, { attributes: { [NUMBERS]: null } })) say(t("已识别数字列 · Ctrl+Z 撤销"));
561
+ else say(t("这个表格的数字列已在识别。"));
562
+ }
563
+
564
+ // A sortable header's arrow (the kit's control, tables/sort.js) pressed while the page is edited:
565
+ // the rows sorted by its column as an edit (one undo step, saved as the table's order), not the
566
+ // kit's view of them: descending first, ascending when they are so already (by the kit's reading
567
+ // of the cells: number-reading.mjs parsedValue; missing values last). The press moves no caret.
568
+ const sortControl = (event) => {
569
+ const header = event.target?.closest?.(".doc-table-sort-button")?.closest("th");
570
+ const unit = header && active() ? tableAt(header) : null;
571
+ return unit ? { unit, header } : null;
572
+ };
573
+ document.addEventListener("pointerdown", (event) => { if (sortControl(event)) event.preventDefault(); }, true);
574
+ document.addEventListener("click", (event) => {
575
+ const found = sortControl(event);
576
+ if (!found) return;
577
+ event.preventDefault();
578
+ event.stopImmediatePropagation();
579
+ sortRows(found.unit, found.header);
580
+ }, true);
581
+ function sortRows(unit, header) {
582
+ const { rows: all, body, slots } = tableState(unit);
583
+ const column = slots?.places.get(header)?.c;
584
+ // Merged cells in its header or body (the kit's mergedCells: tables/cells.js) tie rows together: no sort.
585
+ if (!body || column === undefined || all.some((row) => [...row.cells].some((cell) => cell.rowSpan > 1 || cell.colSpan > 1))) return;
586
+ const type = header.dataset.sortType || "number";
587
+ const value = (row) => parsedValue(row.cells[column], type);
588
+ const order = (direction) => (a, b) => {
589
+ const [x, y] = [value(a), value(b)];
590
+ if (x === null || y === null) return (x === null) - (y === null); // missing last either way
591
+ const compared = typeof x === "number" && typeof y === "number" ? x - y : String(x).localeCompare(String(y), "zh-CN", { numeric: true });
592
+ return direction === "asc" ? compared : -compared;
593
+ };
594
+ const rows = [...body.rows];
595
+ const down = [...rows].sort(order("desc"));
596
+ const direction = down.every((row, index) => row === rows[index]) ? "asc" : "desc";
597
+ const sorted = direction === "desc" ? down : [...rows].sort(order("asc"));
598
+ if (sorted.every((row, index) => row === rows[index])) return void say(t("这一列已经是这个顺序。"));
599
+ change(unit, () => {
600
+ body.append(...sorted);
601
+ return true;
602
+ }, direction === "desc" ? t("已按这一列降序排列") : t("已按这一列升序排列"));
603
+ }
604
+ // 标题行 switched (refused when a merged cell ties the first row to the ones below it).
605
+ function headerRow(unit, state) {
606
+ if (change(unit, () => setHeaderRow(unit, !state.headerRow), state.headerRow ? t("已取消标题行") : t("已设为标题行")) === null && !state.headerRow) say(t("第一行和下面的行合并了单元格,不能设为标题行。"));
607
+ }
608
+
609
+ /** Rows or columns `from` … `to` (grown so that no merged cell is cut) copied after them, the copies selected. */
610
+ function duplicate(unit, type, from, to) {
611
+ const [first, last] = type === "column" ? columnRange(unit, from, to) : rowRange(unit, from, to);
612
+ const made = change(unit, () => (type === "column" ? duplicateColumns(unit, first, last) : duplicateRows(unit, first, last)), t("已创建副本"));
613
+ if (!made) return;
614
+ const size = last - first + 1;
615
+ if (type === "column") tools.selectColumns(unit, last + 1, last + size);
616
+ else tools.selectRows(unit, last + 1, last + size);
617
+ }
618
+
619
+ /** The selected cells made one (mergeCells), selected. */
620
+ function merge() {
621
+ if (!sel || sel.type !== "cell") return;
622
+ const { unit } = sel;
623
+ const b = bounds();
624
+ const list = selectedCells();
625
+ if (list.length < 2) return;
626
+ const heads = tableParts(unit).head?.rows.length ?? 0;
627
+ if (b.r0 < heads && b.r1 >= heads) return void say(t("标题行不能和正文合并。"));
628
+ const made = change(unit, () => mergeCells(unit, b), t("已合并单元格"), list);
629
+ if (made) tools.selectCells(unit, [b.r0, b.c0]);
630
+ else say(t("这些单元格不能合并。"));
631
+ }
632
+
633
+ /** A selected merged cell made separate cells (splitCell), they selected. */
634
+ function split() {
635
+ const list = selectedCells();
636
+ if (!sel || list.length !== 1) return;
637
+ const { unit } = sel;
638
+ const place = tableState(unit).slots.places.get(list[0]);
639
+ if (!place || (place.rows === 1 && place.cols === 1)) return;
640
+ if (change(unit, () => splitCell(unit, list[0]), t("已拆分单元格"), list)) tools.selectCells(unit, [place.r, place.c], [place.r + place.rows - 1, place.c + place.cols - 1]);
641
+ }
642
+
643
+ // ---------- events ----------
644
+
645
+ document.addEventListener("pointermove", (event) => {
646
+ if (drag) return dragTo(event);
647
+ if (keyboard) {
648
+ keyboard = false;
649
+ draw();
650
+ }
651
+ // A press on empty space beside a table (selection/marquee.mjs: a box selection, or a click) is
652
+ // not working the table: the tools the pointer showed there before the press (a row's grip and +
653
+ // points, its edges' strips, the corner) go at its first move and wait until it ends (notion-lite's
654
+ // hover follows the pointer, and a box selection shows its covered blocks' fills alone).
655
+ if (document.documentElement.hasAttribute("data-ge-marquee")) {
656
+ if (hover) {
657
+ hover = null;
658
+ draw();
659
+ }
660
+ return;
661
+ }
662
+ if (event.buttons || !active() || document.documentElement.hasAttribute("data-ge-drag") || document.documentElement.hasAttribute("data-ge-resize")) return;
663
+ if (event.target?.closest?.("[data-doc-dev]")) return; // on the tools themselves: keep them
664
+ const { clientX: x, clientY: y } = event;
665
+ // Just right of or below a table (its edges' grab, widths.mjs), the cell beside the pointer; just
666
+ // above or left of it (its grips' edges), the cell inside that edge.
667
+ const cell = event.target?.closest?.("td, th") ?? (nearTable(x, y) ? edgeCell(x, y) ?? outerCell(x, y) : null);
668
+ const unit = tableAt(cell);
669
+ if (unit) return point(unit, ...placeOf(tableSlots(unit), cell), edgesAt(unit, x, y));
670
+ // Near a table (its tools stand just outside what its frame shows): keep them, but the grips off
671
+ // its edges; elsewhere they go.
672
+ if (hover) {
673
+ const box = hover.unit.isConnected ? viewOf(hover.unit) : rectOf(tableOf(hover.unit));
674
+ const near = x > box.left - 30 && x < box.right + 30 && y > box.top - 30 && y < box.bottom + 30;
675
+ if (!near) {
676
+ hover = null;
677
+ draw();
678
+ } else point(hover.unit, hover.row, hover.column, { row: false, column: false });
679
+ }
680
+ }, { passive: true, capture: true });
681
+ // Over a frame (an embed's) the moves are its own document's: reaching it is the last the page hears
682
+ // of the pointer, so the hover tools go there, near the table or not (else they stood by it until the
683
+ // pointer came back to the page: the page scrolled under a still pointer, putting the caret in a
684
+ // paragraph past the table, brings the embed under it with no move the page sees). A selection stays.
685
+ document.addEventListener("pointerover", (event) => {
686
+ if (event.target?.localName !== "iframe" || drag || widths.dragging || !hover) return;
687
+ hover = null;
688
+ draw();
689
+ }, { passive: true, capture: true });
690
+ // The pointer at a table's cell [row, column], at its edges or not (edgesAt): drawn again when that changed.
691
+ function point(unit, row, column, edges) {
692
+ const moved = !hover || hover.unit !== unit || hover.row !== row || hover.column !== column || hover.edges.row !== edges.row || hover.edges.column !== edges.column;
693
+ hover = { unit, row, column, edges };
694
+ if (moved) draw();
695
+ }
696
+
697
+ // Whether a point is near enough to a table for edgeCell or outerCell to find one of its cells: they
698
+ // look REACH.out at most from the pointer, and only what a table's frame shows of it (or the
699
+ // table, where its frame does not cut it) is found there. Each of their looks is a hit test of the
700
+ // whole page (0.6–2ms on a long report), and the five of them on every move over the rest of the
701
+ // page, where most moves are, came to 2–11ms a move; now none runs there. The tables are kept
702
+ // between moves (kept.mjs), where they are is measured on the move.
703
+ const tables = kept(() => [...document.querySelectorAll(`main [data-ge-unit-kind="table"][${GRID}]`)].map((unit) => [unit, tableOf(unit)]));
704
+ function nearTable(x, y) {
705
+ const near = REACH.out + 10;
706
+ for (const pair of tables()) {
707
+ for (const node of pair) {
708
+ const rect = node?.getBoundingClientRect();
709
+ if (rect && (rect.width > 0 || rect.height > 0) && x >= rect.left - near && x <= rect.right + near && y >= rect.top - near && y <= rect.bottom + near) return true;
710
+ }
711
+ }
712
+ return false;
713
+ }
714
+
715
+ // The cell just inside a table's top (left) edge from a point just above (left of) it, within its
716
+ // grips' reach (edgesAt), or null: the cell under the point taken that far into the table (under
717
+ // the tools, when one of them stands there).
718
+ function outerCell(x, y) {
719
+ for (const [dx, dy] of [[0, REACH.out], [REACH.out, 0], [REACH.out, REACH.out]]) {
720
+ const top = document.elementFromPoint(x + dx, y + dy);
721
+ const cell = top?.closest?.("[data-doc-dev]") ? document.elementsFromPoint(x + dx, y + dy).map((node) => node.closest?.("td, th")).find(Boolean) : top?.closest?.("td, th");
722
+ const unit = tableAt(cell);
723
+ if (!unit) continue;
724
+ const view = viewOf(unit);
725
+ const edges = edgesAt(unit, x, y);
726
+ if ((edges.column && y < view.top) || (edges.row && x < view.left)) return cell;
727
+ }
728
+ return null;
729
+ }
730
+
731
+ // The cell just inside a table's right (bottom) edge from a point just past it (within the edge's
732
+ // grab, widths.mjs), or null.
733
+ function edgeCell(x, y) {
734
+ const beside = document.elementFromPoint(x - 10, y)?.closest?.("td, th");
735
+ const right = tableAt(beside);
736
+ if (right) {
737
+ const { box, view } = geometry(right);
738
+ if (box.right <= view.right + 1 && x >= box.right - 3 && x <= box.right + 8) return beside;
739
+ }
740
+ const above = document.elementFromPoint(x, y - 10)?.closest?.("td, th");
741
+ const below = tableAt(above);
742
+ if (below) {
743
+ const { view } = geometry(below);
744
+ if (x >= view.left && x <= view.right && y >= view.bottom - 3 && y <= view.bottom + 8) return above;
745
+ }
746
+ return null;
747
+ }
748
+
749
+ function dragTo(event) {
750
+ if (drag.ops) return grow(event);
751
+ if (!drag.moved && Math.abs(event.clientX - drag.x) + Math.abs(event.clientY - drag.y) < DRAG) return;
752
+ if (!drag.moved) {
753
+ drag.moved = true;
754
+ // The rows (columns) a merged cell ties to it go with it.
755
+ const range = drag.axis === "column" ? columnRange(drag.unit, drag.from) : rowRange(drag.unit, drag.from);
756
+ const copy = ghostOf(drag.unit, drag.axis, range);
757
+ drag.ghost = copy.node;
758
+ drag.size = copy.size;
759
+ // Where the press was in the copy, which it keeps.
760
+ drag.grab = (drag.axis === "column" ? drag.x : drag.y) - (drag.axis === "column" ? geometry(drag.unit).view.left : geometry(drag.unit).view.top) - copy.offset;
761
+ document.documentElement.setAttribute("data-ge-tdrag", "");
762
+ }
763
+ const g = geometry(drag.unit);
764
+ const list = drag.axis === "column" ? g.columns.map((c) => [c.left, c.right]) : g.rows.map((r) => [r.top, r.bottom]);
765
+ const at = drag.axis === "column" ? event.clientX : event.clientY;
766
+ const to = list.findIndex(([, end]) => at < end);
767
+ drag.to = to < 0 ? list.length - 1 : to;
768
+ draw();
769
+ // The copy follows the pointer along its axis, held where it was pressed, within the table in sight.
770
+ const layer = layerOf(drag.unit);
771
+ layer.append(drag.ghost); // above what was drawn anew, the line where it goes above it
772
+ for (const line of layer.querySelectorAll(":scope > .ge-tline")) layer.append(line);
773
+ const { width, height } = drag.size;
774
+ const clamp = (value, low, high) => Math.max(low, Math.min(value, Math.max(low, high)));
775
+ const left = drag.axis === "column" ? clamp(event.clientX - drag.grab, g.view.left, g.view.right - width) : g.view.left;
776
+ const top = drag.axis === "row" ? clamp(event.clientY - drag.grab, g.view.top, g.view.bottom - height) : g.view.top;
777
+ drawBox(drag.ghost, layer, { left, top, right: left + width, bottom: top + height });
778
+ }
779
+
780
+ // The corner dragged: as many rows put in below (columns right) as it went, or the empty last ones
781
+ // taken off as it comes back, across, down or both. Each move starts again from the table as the
782
+ // press found it (what the moves before did undone, the last first), then columns (in the rows
783
+ // there are) and rows (of every column): rows and columns put in and taken off never mix. Undone
784
+ // when it ends, then made again as one undo step; the frame scrolled to its end, where they are.
785
+ function grow(event) {
786
+ const { unit } = drag;
787
+ while (drag.ops.length > 0) drag.ops.pop()();
788
+ const wanted = {};
789
+ for (const axis of ["row", "column"]) {
790
+ const delta = axis === "column" ? event.clientX - drag.x : event.clientY - drag.y;
791
+ const [step, slack] = STEP[axis];
792
+ drag.moved ||= Math.abs(delta) > DRAG;
793
+ wanted[axis] = delta >= 0 ? Math.floor((delta + slack) / step) : -Math.floor((slack - delta) / step);
794
+ }
795
+ drag.counts = { row: 0, column: 0 };
796
+ for (const axis of ["column", "row"]) {
797
+ for (let i = 0; i < wanted[axis]; i++) {
798
+ const made = axis === "column" ? insertColumn(unit, tableState(unit).columns) : [insertRow(unit, tableParts(unit).rows.length)];
799
+ drag.ops.push(() => made.forEach((node) => node.remove()));
800
+ drag.counts[axis]++;
801
+ }
802
+ for (let i = 0; i > wanted[axis]; i--) {
803
+ const taken = takeLast(unit, axis);
804
+ if (!taken) break;
805
+ drag.ops.push(() => restore(taken));
806
+ drag.counts[axis]--;
807
+ }
808
+ }
809
+ toEnd(unit, drag.counts);
810
+ draw();
811
+ showSize(event);
812
+ }
813
+ // A frame that scrolls shows its end where rows (columns) went in.
814
+ function toEnd(unit, counts) {
815
+ if (counts.column > 0) unit.scrollLeft = unit.scrollWidth;
816
+ if (counts.row > 0) unit.scrollTop = unit.scrollHeight;
817
+ }
818
+
819
+ // The last row (column) taken off when it is empty, not the last one and holds no merged cell:
820
+ // what puts it back, or null.
821
+ function takeLast(unit, axis) {
822
+ const { rows, columns, body, slots } = tableState(unit);
823
+ if (axis === "row") {
824
+ const r = rows.length - 1;
825
+ const row = rows[r];
826
+ if (body.rows.length < 2 || row.textContent.trim() !== "" || slots.matrix[r].some((cell) => cell.rowSpan > 1 || slots.places.get(cell).r !== r)) return null;
827
+ const parent = row.parentElement;
828
+ row.remove();
829
+ return [{ node: row, parent, before: null }];
830
+ }
831
+ const cells = [...new Set(slots.matrix.map((row) => row[columns - 1]))];
832
+ if (columns < 2 || cells.some((cell) => cell.colSpan > 1 || cell.rowSpan > 1 || cell.textContent.trim() !== "")) return null;
833
+ return cells.map((cell) => {
834
+ const parent = cell.parentElement;
835
+ cell.remove();
836
+ return { node: cell, parent, before: null };
837
+ });
838
+ }
839
+ const restore = (taken) => taken.forEach(({ node, parent, before }) => parent.insertBefore(node, before));
840
+
841
+ let sizeTip = null;
842
+ function showSize(event) {
843
+ const { rows, columns } = tableState(drag.unit);
844
+ sizeTip ??= element("div", { class: "ge-tsize", "data-doc-dev": "" });
845
+ drawn(sizeTip); // drawn again after each redraw
846
+ sizeTip.textContent = t("{0} 列 × {1} 行", columns, rows.length);
847
+ // Below right of the pointer, as wide as its words (only placed: never given a size).
848
+ const layer = layerOf(drag.unit);
849
+ const origin = layer.getBoundingClientRect();
850
+ drawAt(sizeTip, layer, event.clientX + 12 - origin.left, event.clientY + 12 - origin.top);
851
+ }
852
+
853
+ // The drag ends: a grip's move, or the corner's rows and columns as one undo step (`cancel`: Esc).
854
+ function release(cancel = false) {
855
+ const done = drag;
856
+ drag = null;
857
+ sizeTip = null;
858
+ done?.ghost?.remove();
859
+ document.documentElement.removeAttribute("data-ge-tdrag");
860
+ if (!done) return;
861
+ if (done.ops) {
862
+ const { unit } = done;
863
+ while (done.ops.length > 0) done.ops.pop()();
864
+ const counts = { ...done.counts };
865
+ if (cancel) return draw();
866
+ // A click: one row.
867
+ if (!done.moved) {
868
+ counts.row = 1;
869
+ counts.column = 0;
870
+ }
871
+ if (counts.row === 0 && counts.column === 0) return draw();
872
+ const made = change(unit, () => {
873
+ for (const axis of ["column", "row"]) {
874
+ for (let i = 0; i < counts[axis]; i++) axis === "column" ? insertColumn(unit, tableState(unit).columns) : insertRow(unit, tableParts(unit).rows.length);
875
+ for (let i = 0; i > counts[axis]; i--) takeLast(unit, axis);
876
+ }
877
+ return true;
878
+ }, [counts.row && t("{0} {1} 行", counts.row > 0 ? t("已添加") : t("已移除"), Math.abs(counts.row)), counts.column && t("{0} {1} 列", counts.column > 0 ? t("已添加") : t("已移除"), Math.abs(counts.column))].filter(Boolean).join(t(",")));
879
+ // Laid out by the kit first: a table grown past 20 rows takes the kit's height then (tables/whole.js).
880
+ if (made) requestAnimationFrame(() => {
881
+ relayout(unit);
882
+ toEnd(unit, counts);
883
+ });
884
+ return draw();
885
+ }
886
+ if (cancel) return draw();
887
+ if (!done.moved) return openMenu();
888
+ if (done.to !== done.from) {
889
+ // [first, last] where they are now (with the rows or columns a merged cell ties them to).
890
+ const moved = change(done.unit, () => (done.axis === "column" ? moveColumn(done.unit, done.from, done.to) : moveRow(done.unit, done.from, done.to)), done.axis === "column" ? t("已移动列") : t("已移动行"));
891
+ if (moved?.length === 2) done.axis === "column" ? tools.selectColumns(done.unit, moved[0], moved[1]) : tools.selectRows(done.unit, moved[0], moved[1]);
892
+ else if (moved === null) say(done.axis === "column" ? t("合并的单元格把这几列连在一起,不能这样移动。") : t("合并的单元格把这几行连在一起,不能这样移动。"));
893
+ }
894
+ draw();
895
+ }
896
+ document.addEventListener("pointerup", () => { if (drag) release(); }, true);
897
+ document.addEventListener("pointercancel", () => { if (drag) release(true); }, true);
898
+ // Esc during a drag puts everything back.
899
+ document.addEventListener("keydown", (event) => {
900
+ if (!drag || event.key !== "Escape") return;
901
+ event.preventDefault();
902
+ event.stopImmediatePropagation();
903
+ release(true);
904
+ }, true);
905
+
906
+ // The menu's keys, before the page's (window, capturing): ↑/↓ move through it, → opens a submenu
907
+ // (颜色 ›, 对齐 ›) and ← leaves it, Enter runs a row, Esc closes it (the selection stays). A field
908
+ // in it (a submenu's) keeps its own.
909
+ addEventListener("keydown", (event) => {
910
+ if (!menu.isOpen || event.defaultPrevented || event.target?.closest?.("input, textarea") || event.ctrlKey || event.metaKey || event.altKey) return;
911
+ if (event.key === "Escape") menu.close();
912
+ else if (event.key === "ArrowLeft" || event.key === "ArrowRight") menu.move(event.key === "ArrowRight" ? 1 : -1, true);
913
+ else if (event.key === "Enter") menu.choose();
914
+ else if (!menu.arrow(event)) return;
915
+ event.preventDefault();
916
+ event.stopImmediatePropagation();
917
+ }, true);
918
+
919
+ addEventListener("scroll", () => { if (!drag) draw(); }, { passive: true, capture: true });
920
+
921
+ // The rows of a table the tools manage.
922
+ function toolRows(unit) {
923
+ const state = tableState(unit);
924
+ return [
925
+ { label: t("标题行"), icon: ICONS.headerRow, checked: state.headerRow, run: () => headerRow(unit, state) },
926
+ { label: t("标题列"), icon: ICONS.headerColumn, checked: state.headerColumn, run: () => change(unit, () => setHeaderColumn(unit, !state.headerColumn), state.headerColumn ? t("已取消标题列") : t("已设为标题列")) },
927
+ { label: t("一键优化"), icon: ICONS.magic, run: () => optimize(unit) },
928
+ { label: t("一键调整列宽"), icon: ICONS.autoWidth, run: () => widths.fit(unit) },
929
+ { label: t("均分列宽"), icon: ICONS.even, run: () => widths.even(unit) },
930
+ { label: t("识别数字列"), icon: ICONS.numbers, run: () => numbers(unit) },
931
+ ];
932
+ }
933
+
934
+ // A table's size: the reading width (in a column 铺满这一栏), and back to the default size
935
+ // once a width or a scroll height is set (resize/ drags both by the table's edges).
936
+ function layoutRows(unit) {
937
+ if (!unit.matches(TABLE.frame)) return [];
938
+ const row = (options) => lookRow({ look, say }, unit, options);
939
+ const span = unit.style.getPropertyValue(SPAN).trim();
940
+ const rows = [row({ label: unit.parentElement?.matches(".doc-column") ? t("铺满这一栏") : t("铺满正文宽度"), icon: MENU_ICONS.full, change: { sizes: { [SPAN]: "1" } }, done: t("表格已铺满") })];
941
+ if (span !== "" || unit.style.getPropertyValue(TABLE_HEIGHT).trim() !== "") {
942
+ rows.push(row({ label: t("恢复默认大小"), icon: MENU_ICONS.reset, change: { sizes: { [SPAN]: null, [TABLE_HEIGHT]: null } }, done: t("已恢复默认大小") }));
943
+ }
944
+ return rows;
945
+ }
946
+
947
+ return {
948
+ /** Take every tool away (the page stops editing, a dialog opens). */
949
+ hide() {
950
+ hover = null;
951
+ sel = null;
952
+ drag = null;
953
+ menu.close();
954
+ clear();
955
+ cells.update();
956
+ },
957
+ /** The table whose cells, rows or columns are selected (no caret in one of them), or null: Ctrl+A's step to the table whole (select-all/). */
958
+ get selectedTable() { return sel && !sel.editing && sel.unit.isConnected ? sel.unit : null; },
959
+ /** The selection let go (blocks selected instead: select-all/). */
960
+ clear: () => { if (sel) tools.clear(); },
961
+ /** A space typed into a text block: in a cell of a table the tools manage, maybe a list's item (lists.mjs). Returns whether it was. */
962
+ typed: (host, data) => /^(TD|TH)$/.test(host?.tagName ?? "") && tableAt(host) !== null && cells.typed(host, data),
963
+ /** Whether the table tools manage a table unit (one written as the kit writes one): its right edge is theirs. */
964
+ owns: (unit) => tableAt(unit) === unit,
965
+ /** Whether a drag from text block `from` into `to` is the table's (two cells of one table): it selects them. */
966
+ claims: (from, to) => {
967
+ const unit = tableAt(from);
968
+ return Boolean(unit) && /^(TD|TH)$/.test(from.tagName) && /^(TD|TH)$/.test(to?.tagName ?? "") && tableAt(to) === unit;
969
+ },
970
+ /** The editor's UI nodes to keep in the top layer when a modal dialog opens. */
971
+ get nodes() { return [...nodes, ...cells.nodes]; },
972
+ /** Whether a node is one of the tools' (a grip, an edge's strip, the corner's +, the cells' bar). */
973
+ holds: (node) => Boolean(node) && [...nodes, ...cells.nodes].some((each) => each.contains(node)),
974
+ /**
975
+ * A table's rows of its block menu (notion-lite's 表格 section, under the menu's one title): a
976
+ * table of the kind these tools manage has 标题行 and 标题列, switches (checked when on); then
977
+ * actions, each applied once (no check): 一键优化, 一键调整列宽, 均分列宽, 识别数字列; any table
978
+ * in its frame has its size's rows after them (layoutRows). [] for any other block.
979
+ */
980
+ menuItems(target) {
981
+ if (!target?.matches?.('[data-ge-unit-kind="table"]')) return [];
982
+ return [...(tableAt(target) === target ? toolRows(target) : []), ...layoutRows(target)];
983
+ },
984
+ };
985
+ }