@esportsplus/ui 0.57.0 → 0.58.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 (490) hide show
  1. package/README.md +123 -39
  2. package/build/components/accordion/group.d.ts +14 -0
  3. package/build/components/accordion/group.js +21 -0
  4. package/build/components/accordion/index.d.ts +9 -0
  5. package/build/components/accordion/index.js +20 -3
  6. package/build/components/accordion/scss/index.scss +1 -1
  7. package/build/components/announcement/scss/index.scss +1 -1
  8. package/build/components/breadcrumb/scss/index.scss +1 -1
  9. package/build/components/button/scss/index.scss +1 -1
  10. package/build/components/button/sidebar.d.ts +3 -0
  11. package/build/components/button/sidebar.js +40 -10
  12. package/build/components/capslock/index.js +1 -1
  13. package/build/components/capslock/scss/index.scss +1 -1
  14. package/build/components/card/scss/index.scss +1 -1
  15. package/build/components/cc/scss/index.scss +1 -1
  16. package/build/components/chat-minimap/scss/index.scss +1 -1
  17. package/build/components/checkbox/scss/index.scss +1 -1
  18. package/build/components/color-picker/index.d.ts +1 -0
  19. package/build/components/color-picker/index.js +166 -136
  20. package/build/components/color-picker/scss/index.scss +1 -1
  21. package/build/components/command/index.d.ts +0 -1
  22. package/build/components/command/index.js +3 -2
  23. package/build/components/command/scss/index.scss +1 -1
  24. package/build/components/copy/scss/index.scss +1 -1
  25. package/build/components/counter/scss/index.scss +1 -1
  26. package/build/components/datalist/index.js +3 -3
  27. package/build/components/datalist/scss/index.scss +1 -1
  28. package/build/components/dock/scss/index.scss +1 -1
  29. package/build/components/editor/code/index.d.ts +0 -1
  30. package/build/components/editor/code/index.js +0 -1
  31. package/build/components/editor/code/minimap.d.ts +2 -1
  32. package/build/components/editor/code/minimap.js +5 -2
  33. package/build/components/editor/code/view.d.ts +3 -1
  34. package/build/components/editor/code/view.js +37 -26
  35. package/build/components/editor/diffs/index.d.ts +0 -1
  36. package/build/components/editor/diffs/index.js +0 -1
  37. package/build/components/editor/diffs/merge.js +7 -3
  38. package/build/components/editor/diffs/view.js +3 -1
  39. package/build/components/editor/index.d.ts +4 -1
  40. package/build/components/editor/index.js +2 -1
  41. package/build/components/editor/markdown/editing.js +22 -3
  42. package/build/components/editor/markdown/erase.d.ts +9 -0
  43. package/build/components/editor/markdown/erase.js +78 -0
  44. package/build/components/editor/markdown/index.d.ts +0 -1
  45. package/build/components/editor/markdown/index.js +0 -1
  46. package/build/components/editor/markdown/layout.d.ts +2 -9
  47. package/build/components/editor/markdown/layout.js +2 -7
  48. package/build/components/editor/markdown/render.d.ts +0 -1
  49. package/build/components/editor/markdown/render.js +287 -235
  50. package/build/components/editor/markdown/view.js +566 -667
  51. package/build/components/editor/viewer/index.d.ts +27 -0
  52. package/build/components/editor/viewer/index.js +250 -0
  53. package/build/components/editor/viewer/model.d.ts +15 -0
  54. package/build/components/editor/viewer/model.js +73 -0
  55. package/build/components/editor/workspace/index.d.ts +6 -2
  56. package/build/components/editor/workspace/index.js +243 -137
  57. package/build/components/editor/workspace/keybindings.d.ts +37 -0
  58. package/build/components/editor/workspace/keybindings.js +288 -0
  59. package/build/components/editor/workspace/model.d.ts +55 -2
  60. package/build/components/editor/workspace/model.js +141 -3
  61. package/build/components/editor/workspace/navigate.d.ts +19 -0
  62. package/build/components/editor/workspace/navigate.js +118 -0
  63. package/build/components/editor/workspace/session.d.ts +29 -0
  64. package/build/components/editor/workspace/session.js +373 -0
  65. package/build/components/editor/workspace/shortcuts.d.ts +19 -0
  66. package/build/components/editor/workspace/shortcuts.js +185 -0
  67. package/build/components/editor/workspace/status.d.ts +34 -0
  68. package/build/components/editor/workspace/status.js +193 -0
  69. package/build/components/editor/workspace/statusbar.d.ts +15 -0
  70. package/build/components/editor/workspace/statusbar.js +190 -0
  71. package/build/components/editor/workspace/strip.d.ts +27 -0
  72. package/build/components/editor/workspace/strip.js +239 -0
  73. package/build/components/editor/workspace/tabs.d.ts +15 -0
  74. package/build/components/editor/workspace/tabs.js +63 -0
  75. package/build/components/error/index.js +1 -1
  76. package/build/components/error/scss/index.scss +1 -1
  77. package/build/components/filter/index.js +5 -3
  78. package/build/components/filter/scss/index.scss +1 -1
  79. package/build/components/frame/scss/index.scss +1 -1
  80. package/build/components/heatmap/index.js +3 -3
  81. package/build/components/heatmap/scss/index.scss +1 -1
  82. package/build/components/highlight/scss/index.scss +1 -1
  83. package/build/components/icon/scss/index.scss +1 -1
  84. package/build/components/image/scss/index.scss +1 -1
  85. package/build/components/index.d.ts +2 -0
  86. package/build/components/index.js +2 -0
  87. package/build/components/inline-edit/scss/index.scss +1 -1
  88. package/build/components/input/scss/index.scss +1 -1
  89. package/build/components/link/scss/index.scss +1 -1
  90. package/build/components/loading/scss/index.scss +1 -1
  91. package/build/components/marquee/scss/index.scss +1 -1
  92. package/build/components/metric/scss/index.scss +1 -1
  93. package/build/components/nav/index.d.ts +1 -1
  94. package/build/components/nav/scss/index.scss +1 -1
  95. package/build/components/nav/tree.d.ts +3 -1
  96. package/build/components/nav/tree.js +30 -60
  97. package/build/components/notification/scss/index.scss +1 -1
  98. package/build/components/overlay/scss/index.scss +1 -1
  99. package/build/components/page/scss/index.scss +1 -1
  100. package/build/components/pagination/arrows.d.ts +15 -0
  101. package/build/components/pagination/arrows.js +65 -0
  102. package/build/components/pagination/cards.d.ts +23 -0
  103. package/build/components/pagination/cards.js +66 -0
  104. package/build/components/pagination/index.d.ts +5 -0
  105. package/build/components/pagination/index.js +3 -1
  106. package/build/components/pagination/scss/index.scss +1 -1
  107. package/build/components/progress/scss/index.scss +1 -1
  108. package/build/components/pull-to-refresh/scss/index.scss +1 -1
  109. package/build/components/range/index.js +1 -1
  110. package/build/components/range/scss/index.scss +1 -1
  111. package/build/components/relative-time/scss/index.scss +1 -1
  112. package/build/components/root/scss/index.scss +1 -1
  113. package/build/components/section/scss/index.scss +2 -0
  114. package/build/components/select/index.d.ts +1 -0
  115. package/build/components/select/index.js +16 -11
  116. package/build/components/select/scss/index.scss +1 -1
  117. package/build/components/shortcut-recorder/scss/index.scss +1 -1
  118. package/build/components/sortable/scss/index.scss +1 -1
  119. package/build/components/sticky-header/index.js +3 -3
  120. package/build/components/sticky-header/scss/index.scss +1 -1
  121. package/build/components/story/scss/index.scss +1 -1
  122. package/build/components/surface-field/scss/index.scss +1 -1
  123. package/build/components/tasklist/scss/index.scss +1 -1
  124. package/build/components/text/scss/index.scss +1 -1
  125. package/build/components/textarea/scss/index.scss +1 -1
  126. package/build/{css-utilities → components}/theme/index.d.ts +1 -1
  127. package/build/{css-utilities → components}/theme/index.js +15 -5
  128. package/build/components/theme/scss/index.scss +2 -0
  129. package/build/components/theme-picker/index.d.ts +52 -0
  130. package/build/components/theme-picker/index.js +167 -0
  131. package/build/components/theme-picker/scss/index.scss +2 -0
  132. package/build/components/toast/index.js +3 -5
  133. package/build/components/toast/scss/index.scss +1 -1
  134. package/build/components/tooltip/menu.js +3 -1
  135. package/build/components/tooltip/scss/index.scss +1 -1
  136. package/build/components/typewriter/scss/index.scss +1 -1
  137. package/build/components/uptime/scss/index.scss +1 -1
  138. package/build/components/usage-meter/scss/index.scss +1 -1
  139. package/build/{css-utilities → modifiers}/glass/index.d.ts +2 -2
  140. package/build/modifiers/glass/index.js +28 -0
  141. package/build/modifiers/glass/scss/index.scss +2 -0
  142. package/build/{css-utilities → modifiers}/index.d.ts +0 -1
  143. package/build/{css-utilities → modifiers}/index.js +0 -1
  144. package/build/modifiers/scrollbar/index.d.ts +72 -0
  145. package/build/{css-utilities → modifiers}/scrollbar/index.js +52 -19
  146. package/build/modifiers/scrollbar/scss/index.scss +2 -0
  147. package/build/normalize/scss/index.scss +1 -2
  148. package/layer.scss +1 -1
  149. package/package.json +11 -18
  150. package/scripts/code-editor-markdown.test.mjs +45 -14
  151. package/scripts/code-viewer.test.mjs +69 -0
  152. package/scripts/workspace-keybindings.test.mjs +273 -0
  153. package/scripts/workspace-session.test.mjs +349 -0
  154. package/scripts/workspace-status.test.mjs +229 -0
  155. package/scripts/workspace-tabs.test.mjs +142 -0
  156. package/src/components/accordion/group.ts +39 -0
  157. package/src/components/accordion/index.ts +32 -6
  158. package/src/components/accordion/scss/index.scss +12 -21
  159. package/src/components/accordion/scss/variables.scss +18 -3
  160. package/src/components/announcement/scss/index.scss +4 -4
  161. package/src/components/announcement/scss/variables.scss +6 -6
  162. package/src/components/banner/scss/index.scss +1 -1
  163. package/src/components/breadcrumb/scss/index.scss +35 -50
  164. package/src/components/breadcrumb/scss/variables.scss +23 -31
  165. package/src/components/button/scss/_fan.scss +39 -43
  166. package/src/components/button/scss/_morph.scss +66 -78
  167. package/src/components/button/scss/_sidebar.scss +41 -30
  168. package/src/components/button/scss/_split.scss +9 -9
  169. package/src/components/button/scss/index.scss +23 -19
  170. package/src/components/button/scss/variables.scss +94 -90
  171. package/src/components/button/sidebar.ts +36 -24
  172. package/src/components/capslock/index.ts +2 -2
  173. package/src/components/capslock/scss/index.scss +11 -6
  174. package/src/components/capslock/scss/variables.scss +3 -5
  175. package/src/components/card/scss/_expand.scss +58 -64
  176. package/src/components/card/scss/index.scss +40 -21
  177. package/src/components/card/scss/variables.scss +40 -31
  178. package/src/components/cc/scss/index.scss +68 -68
  179. package/src/components/cc/scss/variables.scss +13 -14
  180. package/src/components/chat-minimap/scss/index.scss +24 -16
  181. package/src/components/chat-minimap/scss/variables.scss +37 -37
  182. package/src/components/checkbox/scss/index.scss +54 -52
  183. package/src/components/checkbox/scss/variables.scss +37 -39
  184. package/src/components/color-picker/index.ts +157 -120
  185. package/src/components/color-picker/scss/index.scss +159 -96
  186. package/src/components/color-picker/scss/variables.scss +33 -15
  187. package/src/components/command/index.ts +3 -2
  188. package/src/components/command/scss/index.scss +10 -14
  189. package/src/components/command/scss/variables.scss +12 -35
  190. package/src/components/copy/scss/index.scss +6 -6
  191. package/src/components/copy/scss/variables.scss +12 -15
  192. package/src/components/counter/scss/index.scss +14 -14
  193. package/src/components/counter/scss/variables.scss +1 -1
  194. package/src/components/datalist/index.ts +3 -3
  195. package/src/components/datalist/scss/index.scss +7 -6
  196. package/src/components/datalist/scss/variables.scss +7 -3
  197. package/src/components/dock/scss/index.scss +10 -15
  198. package/src/components/dock/scss/variables.scss +29 -25
  199. package/src/components/editor/code/index.ts +0 -1
  200. package/src/components/editor/code/minimap.ts +13 -5
  201. package/src/components/editor/code/scss/_editor.scss +83 -81
  202. package/src/components/editor/code/scss/_features.scss +106 -97
  203. package/src/components/editor/code/scss/_services.scss +27 -25
  204. package/src/components/editor/code/scss/index.scss +0 -1
  205. package/src/components/editor/code/scss/variables.scss +30 -26
  206. package/src/components/editor/code/view.ts +14 -5
  207. package/src/components/editor/diffs/index.ts +0 -1
  208. package/src/components/editor/diffs/merge.ts +2 -1
  209. package/src/components/editor/diffs/scss/_diffs.scss +67 -57
  210. package/src/components/editor/diffs/scss/_merge.scss +17 -14
  211. package/src/components/editor/diffs/scss/index.scss +0 -1
  212. package/src/components/editor/diffs/scss/variables.scss +25 -18
  213. package/src/components/editor/diffs/view.ts +2 -1
  214. package/src/components/editor/index.ts +7 -1
  215. package/src/components/editor/markdown/editing.ts +38 -3
  216. package/src/components/editor/markdown/erase.ts +124 -0
  217. package/src/components/editor/markdown/index.ts +0 -1
  218. package/src/components/editor/markdown/layout.ts +3 -12
  219. package/src/components/editor/markdown/render.ts +65 -37
  220. package/src/components/editor/markdown/scss/index.scss +92 -124
  221. package/src/components/editor/markdown/scss/variables.scss +39 -19
  222. package/src/components/editor/markdown/view.ts +737 -786
  223. package/src/components/editor/tree/scss/index.scss +121 -110
  224. package/src/components/editor/tree/scss/variables.scss +48 -54
  225. package/src/components/editor/viewer/index.ts +321 -0
  226. package/src/components/editor/viewer/model.ts +130 -0
  227. package/src/components/editor/viewer/scss/_viewer.scss +302 -0
  228. package/src/components/editor/viewer/scss/index.scss +2 -0
  229. package/src/components/editor/viewer/scss/variables.scss +69 -0
  230. package/src/components/editor/workspace/index.ts +159 -31
  231. package/src/components/editor/workspace/keybindings.ts +447 -0
  232. package/src/components/editor/workspace/model.ts +233 -3
  233. package/src/components/editor/workspace/navigate.ts +194 -0
  234. package/src/components/editor/workspace/scss/index.scss +72 -59
  235. package/src/components/editor/workspace/scss/keybindings.scss +190 -0
  236. package/src/components/editor/workspace/scss/status.scss +122 -0
  237. package/src/components/editor/workspace/scss/tabs.scss +56 -0
  238. package/src/components/editor/workspace/session.ts +551 -0
  239. package/src/components/editor/workspace/shortcuts.ts +255 -0
  240. package/src/components/editor/workspace/status.ts +259 -0
  241. package/src/components/editor/workspace/statusbar.ts +255 -0
  242. package/src/components/editor/workspace/strip.ts +273 -0
  243. package/src/components/editor/workspace/tabs.ts +106 -0
  244. package/src/components/error/index.ts +1 -1
  245. package/src/components/error/scss/index.scss +19 -19
  246. package/src/components/error/scss/variables.scss +2 -2
  247. package/src/components/filter/index.ts +7 -2
  248. package/src/components/filter/scss/index.scss +1 -1
  249. package/src/components/filter/scss/variables.scss +11 -10
  250. package/src/components/frame/scss/index.scss +12 -12
  251. package/src/components/frame/scss/variables.scss +8 -8
  252. package/src/components/heatmap/index.ts +3 -3
  253. package/src/components/heatmap/scss/index.scss +28 -26
  254. package/src/components/heatmap/scss/variables.scss +18 -17
  255. package/src/components/highlight/scss/index.scss +17 -13
  256. package/src/components/highlight/scss/variables.scss +8 -10
  257. package/src/components/icon/scss/index.scss +10 -0
  258. package/src/components/icon/scss/variables.scss +5 -0
  259. package/src/components/image/scss/index.scss +9 -9
  260. package/src/components/image/scss/variables.scss +7 -2
  261. package/src/components/index.ts +2 -0
  262. package/src/components/inline-edit/scss/index.scss +99 -104
  263. package/src/components/inline-edit/scss/variables.scss +40 -39
  264. package/src/components/input/scss/_field.scss +6 -20
  265. package/src/components/input/scss/_scrub.scss +10 -8
  266. package/src/components/input/scss/_tag.scss +35 -37
  267. package/src/components/input/scss/variables.scss +100 -99
  268. package/src/components/link/scss/index.scss +4 -1
  269. package/src/components/loading/scss/index.scss +1 -1
  270. package/src/components/loading/scss/variables.scss +1 -1
  271. package/src/components/marquee/scss/index.scss +9 -5
  272. package/src/components/marquee/scss/variables.scss +3 -1
  273. package/src/components/metric/scss/_flash.scss +3 -1
  274. package/src/components/metric/scss/index.scss +8 -6
  275. package/src/components/metric/scss/variables.scss +26 -20
  276. package/src/components/nav/index.ts +1 -1
  277. package/src/components/nav/scss/index.scss +12 -40
  278. package/src/components/nav/scss/variables.scss +30 -11
  279. package/src/components/nav/tree.ts +19 -62
  280. package/src/components/notification/scss/index.scss +7 -7
  281. package/src/components/notification/scss/variables.scss +7 -9
  282. package/src/components/overlay/scss/index.scss +181 -170
  283. package/src/components/overlay/scss/variables.scss +26 -57
  284. package/src/components/page/scss/index.scss +12 -11
  285. package/src/components/page/scss/variables.scss +5 -0
  286. package/src/components/pagination/arrows.ts +58 -0
  287. package/src/components/pagination/cards.ts +57 -0
  288. package/src/components/pagination/index.ts +4 -1
  289. package/src/components/pagination/scss/_arrows.scss +69 -0
  290. package/src/components/pagination/scss/_cards.scss +121 -0
  291. package/src/components/pagination/scss/_dots.scss +2 -5
  292. package/src/components/pagination/scss/index.scss +8 -6
  293. package/src/components/pagination/scss/variables.scss +87 -37
  294. package/src/components/progress/scss/_text.scss +21 -18
  295. package/src/components/progress/scss/index.scss +1 -1
  296. package/src/components/progress/scss/variables.scss +12 -12
  297. package/src/components/pull-to-refresh/scss/index.scss +2 -1
  298. package/src/components/pull-to-refresh/scss/variables.scss +11 -6
  299. package/src/components/range/index.ts +1 -1
  300. package/src/components/range/scss/_filter.scss +62 -51
  301. package/src/components/range/scss/_slider.scss +78 -75
  302. package/src/components/range/scss/_vertical.scss +6 -6
  303. package/src/components/range/scss/index.scss +3 -2
  304. package/src/components/range/scss/variables.scss +26 -23
  305. package/src/components/relative-time/scss/index.scss +27 -27
  306. package/src/components/relative-time/scss/variables.scss +10 -12
  307. package/src/components/root/scss/index.scss +71 -43
  308. package/src/components/root/scss/variables.scss +35 -31
  309. package/src/components/section/scss/index.scss +31 -0
  310. package/src/components/section/scss/variables.scss +21 -0
  311. package/src/components/select/index.ts +11 -6
  312. package/src/components/select/scss/index.scss +21 -32
  313. package/src/components/select/scss/variables.scss +25 -18
  314. package/src/components/shortcut-recorder/scss/index.scss +13 -12
  315. package/src/components/shortcut-recorder/scss/variables.scss +12 -13
  316. package/src/components/sortable/scss/index.scss +47 -44
  317. package/src/components/sortable/scss/variables.scss +4 -5
  318. package/src/components/sticky-header/index.ts +4 -4
  319. package/src/components/sticky-header/scss/index.scss +14 -13
  320. package/src/components/sticky-header/scss/variables.scss +9 -9
  321. package/src/components/story/scss/index.scss +26 -30
  322. package/src/components/story/scss/variables.scss +16 -9
  323. package/src/components/surface-field/scss/index.scss +45 -40
  324. package/src/components/surface-field/scss/variables.scss +5 -6
  325. package/src/components/tasklist/scss/index.scss +19 -19
  326. package/src/components/tasklist/scss/variables.scss +26 -29
  327. package/src/components/text/scss/index.scss +2 -1
  328. package/src/components/textarea/scss/variables.scss +1 -1
  329. package/src/{css-utilities → components}/theme/index.ts +17 -3
  330. package/src/components/theme/scss/index.scss +1 -0
  331. package/src/components/theme/scss/variables.scss +78 -0
  332. package/src/components/theme-picker/index.ts +231 -0
  333. package/src/components/theme-picker/scss/index.scss +264 -0
  334. package/src/components/toast/index.ts +28 -30
  335. package/src/components/toast/scss/index.scss +87 -87
  336. package/src/components/toast/scss/variables.scss +39 -39
  337. package/src/components/tooltip/menu.ts +4 -1
  338. package/src/components/tooltip/scss/_east.scss +10 -10
  339. package/src/components/tooltip/scss/_menu.scss +284 -269
  340. package/src/components/tooltip/scss/_north.scss +10 -10
  341. package/src/components/tooltip/scss/_shared.scss +7 -7
  342. package/src/components/tooltip/scss/_south.scss +10 -10
  343. package/src/components/tooltip/scss/_west.scss +10 -10
  344. package/src/components/tooltip/scss/index.scss +21 -20
  345. package/src/components/tooltip/scss/variables.scss +104 -96
  346. package/src/components/typewriter/scss/_retype.scss +12 -11
  347. package/src/components/typewriter/scss/_rotate.scss +2 -1
  348. package/src/components/typewriter/scss/variables.scss +41 -39
  349. package/src/components/uptime/scss/index.scss +15 -15
  350. package/src/components/uptime/scss/variables.scss +8 -8
  351. package/src/components/usage-meter/scss/index.scss +3 -1
  352. package/src/components/usage-meter/scss/variables.scss +5 -5
  353. package/src/css-utilities/absolute.scss +64 -0
  354. package/src/css-utilities/background.scss +43 -0
  355. package/src/css-utilities/border.scss +45 -0
  356. package/src/css-utilities/box-shadow.scss +29 -0
  357. package/src/css-utilities/color.scss +41 -0
  358. package/src/css-utilities/flex.scss +64 -0
  359. package/src/css-utilities/font/geist/{scss/index.scss → index.scss} +12 -4
  360. package/src/css-utilities/font/montserrat/Montserrat-Italic-Variable.woff2 +0 -0
  361. package/src/css-utilities/font/montserrat/Montserrat-Variable.woff2 +0 -0
  362. package/src/css-utilities/font/montserrat/OFL.txt +93 -0
  363. package/src/css-utilities/font/montserrat/index.scss +38 -0
  364. package/src/{shared/scss → css-utilities}/icon.scss +1 -1
  365. package/src/css-utilities/{inline/scss/index.scss → inline.scss} +1 -1
  366. package/src/css-utilities/{skeleton/scss/index.scss → skeleton.scss} +11 -11
  367. package/src/css-utilities/surface.scss +266 -0
  368. package/src/css-utilities/text.scss +191 -0
  369. package/src/modifiers/glass/index.ts +44 -0
  370. package/src/{css-utilities → modifiers}/glass/scss/index.scss +6 -6
  371. package/src/{css-utilities → modifiers}/glass/scss/variables.scss +1 -1
  372. package/src/{css-utilities → modifiers}/index.ts +0 -1
  373. package/src/{css-utilities → modifiers}/scrollbar/index.ts +92 -17
  374. package/src/{css-utilities → modifiers}/scrollbar/scss/index.scss +178 -177
  375. package/src/{css-utilities → modifiers}/scrollbar/scss/variables.scss +28 -21
  376. package/src/normalize/scss/index.scss +4 -2
  377. package/src/shared/scss/color-weights.scss +19 -0
  378. package/src/shared/scss/index.scss +1 -12
  379. package/src/tokens/scss/blur.scss +5 -0
  380. package/src/tokens/scss/color.scss +74 -50
  381. package/src/tokens/scss/index.scss +1 -2
  382. package/src/tokens/scss/size.scss +0 -2
  383. package/src/tokens/scss/state.scss +3 -2
  384. package/src/tokens/scss/transition.scss +19 -2
  385. package/storage/svg/monitor.svg +1 -0
  386. package/storage/svg/moon.svg +1 -0
  387. package/storage/svg/pin.svg +1 -0
  388. package/storage/svg/sun.svg +1 -0
  389. package/vite.config.ts +33 -8
  390. package/build/css-utilities/background/scss/index.scss +0 -2
  391. package/build/css-utilities/border/scss/index.scss +0 -2
  392. package/build/css-utilities/color/scss/index.scss +0 -2
  393. package/build/css-utilities/flex/scss/index.scss +0 -2
  394. package/build/css-utilities/font/geist/index.d.ts +0 -1
  395. package/build/css-utilities/font/geist/index.js +0 -1
  396. package/build/css-utilities/font/geist/scss/index.scss +0 -2
  397. package/build/css-utilities/font/montserrat/index.d.ts +0 -1
  398. package/build/css-utilities/font/montserrat/index.js +0 -1
  399. package/build/css-utilities/font/montserrat/scss/Montserrat-Bold.woff +0 -0
  400. package/build/css-utilities/font/montserrat/scss/Montserrat-Bold.woff2 +0 -0
  401. package/build/css-utilities/font/montserrat/scss/Montserrat-BoldItalic.woff +0 -0
  402. package/build/css-utilities/font/montserrat/scss/Montserrat-BoldItalic.woff2 +0 -0
  403. package/build/css-utilities/font/montserrat/scss/Montserrat-Italic.woff +0 -0
  404. package/build/css-utilities/font/montserrat/scss/Montserrat-Italic.woff2 +0 -0
  405. package/build/css-utilities/font/montserrat/scss/Montserrat-Medium.woff +0 -0
  406. package/build/css-utilities/font/montserrat/scss/Montserrat-Medium.woff2 +0 -0
  407. package/build/css-utilities/font/montserrat/scss/Montserrat-MediumItalic.woff +0 -0
  408. package/build/css-utilities/font/montserrat/scss/Montserrat-MediumItalic.woff2 +0 -0
  409. package/build/css-utilities/font/montserrat/scss/Montserrat-Regular.woff +0 -0
  410. package/build/css-utilities/font/montserrat/scss/Montserrat-Regular.woff2 +0 -0
  411. package/build/css-utilities/font/montserrat/scss/Montserrat-SemiBold.woff +0 -0
  412. package/build/css-utilities/font/montserrat/scss/Montserrat-SemiBold.woff2 +0 -0
  413. package/build/css-utilities/font/montserrat/scss/Montserrat-SemiBoldItalic.woff +0 -0
  414. package/build/css-utilities/font/montserrat/scss/Montserrat-SemiBoldItalic.woff2 +0 -0
  415. package/build/css-utilities/font/montserrat/scss/index.scss +0 -2
  416. package/build/css-utilities/glass/index.js +0 -26
  417. package/build/css-utilities/glass/scss/index.scss +0 -2
  418. package/build/css-utilities/index.scss +0 -2
  419. package/build/css-utilities/inline/scss/index.scss +0 -2
  420. package/build/css-utilities/scrollbar/index.d.ts +0 -42
  421. package/build/css-utilities/scrollbar/scss/index.scss +0 -2
  422. package/build/css-utilities/skeleton/scss/index.scss +0 -2
  423. package/build/css-utilities/text/scss/index.scss +0 -2
  424. package/build/themes/dark/index.d.ts +0 -3
  425. package/build/themes/dark/index.js +0 -3
  426. package/build/themes/dark/input.d.ts +0 -3
  427. package/build/themes/dark/input.js +0 -12
  428. package/build/themes/dark/select.d.ts +0 -3
  429. package/build/themes/dark/select.js +0 -23
  430. package/build/themes/dark/textarea.d.ts +0 -2186
  431. package/build/themes/dark/textarea.js +0 -11
  432. package/src/css-utilities/background/scss/index.scss +0 -1
  433. package/src/css-utilities/background/scss/variables.scss +0 -18
  434. package/src/css-utilities/border/scss/index.scss +0 -1
  435. package/src/css-utilities/border/scss/variables.scss +0 -23
  436. package/src/css-utilities/color/scss/index.scss +0 -1
  437. package/src/css-utilities/color/scss/variables.scss +0 -17
  438. package/src/css-utilities/flex/scss/index.scss +0 -57
  439. package/src/css-utilities/flex/scss/variables.scss +0 -16
  440. package/src/css-utilities/font/geist/index.ts +0 -1
  441. package/src/css-utilities/font/montserrat/index.ts +0 -1
  442. package/src/css-utilities/font/montserrat/scss/Montserrat-Bold.woff +0 -0
  443. package/src/css-utilities/font/montserrat/scss/Montserrat-Bold.woff2 +0 -0
  444. package/src/css-utilities/font/montserrat/scss/Montserrat-BoldItalic.woff +0 -0
  445. package/src/css-utilities/font/montserrat/scss/Montserrat-BoldItalic.woff2 +0 -0
  446. package/src/css-utilities/font/montserrat/scss/Montserrat-Italic.woff +0 -0
  447. package/src/css-utilities/font/montserrat/scss/Montserrat-Italic.woff2 +0 -0
  448. package/src/css-utilities/font/montserrat/scss/Montserrat-Medium.woff +0 -0
  449. package/src/css-utilities/font/montserrat/scss/Montserrat-Medium.woff2 +0 -0
  450. package/src/css-utilities/font/montserrat/scss/Montserrat-MediumItalic.woff +0 -0
  451. package/src/css-utilities/font/montserrat/scss/Montserrat-MediumItalic.woff2 +0 -0
  452. package/src/css-utilities/font/montserrat/scss/Montserrat-Regular.woff +0 -0
  453. package/src/css-utilities/font/montserrat/scss/Montserrat-Regular.woff2 +0 -0
  454. package/src/css-utilities/font/montserrat/scss/Montserrat-SemiBold.woff +0 -0
  455. package/src/css-utilities/font/montserrat/scss/Montserrat-SemiBold.woff2 +0 -0
  456. package/src/css-utilities/font/montserrat/scss/Montserrat-SemiBoldItalic.woff +0 -0
  457. package/src/css-utilities/font/montserrat/scss/Montserrat-SemiBoldItalic.woff2 +0 -0
  458. package/src/css-utilities/font/montserrat/scss/index.scss +0 -94
  459. package/src/css-utilities/glass/index.ts +0 -42
  460. package/src/css-utilities/index.scss +0 -13
  461. package/src/css-utilities/skeleton/scss/variables.scss +0 -3
  462. package/src/css-utilities/text/scss/index.scss +0 -152
  463. package/src/css-utilities/text/scss/variables.scss +0 -22
  464. package/src/shared/scss/absolute.scss +0 -28
  465. package/src/shared/scss/background.scss +0 -21
  466. package/src/shared/scss/border.scss +0 -21
  467. package/src/shared/scss/color.scss +0 -21
  468. package/src/shared/scss/position.scss +0 -55
  469. package/src/shared/scss/text.scss +0 -31
  470. package/src/themes/dark/index.ts +0 -3
  471. package/src/themes/dark/input.ts +0 -16
  472. package/src/themes/dark/select.ts +0 -28
  473. package/src/themes/dark/textarea.ts +0 -13
  474. package/src/tokens/scss/box-shadow.scss +0 -23
  475. package/src/tokens/scss/font-family.scss +0 -5
  476. package/storage/code.md +0 -180
  477. package/storage/editor-features.md +0 -227
  478. package/build/css-utilities/font/geist/{scss/Geist-Italic-Variable.woff2 → Geist-Italic-Variable.woff2} +0 -0
  479. package/build/css-utilities/font/geist/{scss/Geist-Variable.woff2 → Geist-Variable.woff2} +0 -0
  480. package/build/css-utilities/font/geist/{scss/GeistMono-Italic-Variable.woff2 → GeistMono-Italic-Variable.woff2} +0 -0
  481. package/build/css-utilities/font/geist/{scss/GeistMono-Variable.woff2 → GeistMono-Variable.woff2} +0 -0
  482. package/src/{shared/scss → css-utilities}/anchor.scss +6 -6
  483. package/src/{shared/scss → css-utilities}/drag.scss +0 -0
  484. package/src/css-utilities/font/geist/{scss/Geist-Italic-Variable.woff2 → Geist-Italic-Variable.woff2} +0 -0
  485. package/src/css-utilities/font/geist/{scss/Geist-Variable.woff2 → Geist-Variable.woff2} +0 -0
  486. package/src/css-utilities/font/geist/{scss/GeistMono-Italic-Variable.woff2 → GeistMono-Italic-Variable.woff2} +0 -0
  487. package/src/css-utilities/font/geist/{scss/GeistMono-Variable.woff2 → GeistMono-Variable.woff2} +0 -0
  488. package/src/{shared/scss → css-utilities}/hidden.scss +11 -11
  489. /package/src/{shared/scss → css-utilities}/layer.scss +0 -0
  490. /package/src/{shared/scss → css-utilities}/reset.scss +0 -0
@@ -1,4 +1,8 @@
1
+ import type { Command } from '../code/keymap';
1
2
  import { EditorDocument } from '../code/document';
3
+ import { sanitize } from './keybindings';
4
+ import type { FileTreeExport, FileTreeImportEntry } from '../tree';
5
+ import { closable, compareKey, compareTab, order, place } from './tabs';
2
6
 
3
7
 
4
8
  type FileOperation = {
@@ -24,6 +28,9 @@ type WorkspaceAction = {
24
28
 
25
29
  type WorkspaceChange = { paths?: readonly string[] };
26
30
 
31
+ // A read-only diff of two files, as they read when compared; its tab's document stays empty and never saves.
32
+ type WorkspaceCompare = Readonly<{ modified: string; original: string; paths: readonly [string, string] }>;
33
+
27
34
  type WorkspaceConfirmation = {
28
35
  dirty: readonly string[];
29
36
  kind: 'close' | 'delete' | 'workspace';
@@ -36,9 +43,15 @@ type WorkspaceEntry = Readonly<{ kind: 'directory' | 'file'; path: string }>;
36
43
 
37
44
  type WorkspaceHost = {
38
45
  actions?: readonly WorkspaceAction[];
46
+ // The text a file's git gutter diffs against, like its HEAD revision; null for none.
47
+ baseline?: (cwd: string, path: string) => Promise<string | null>;
39
48
  confirm?: (request: WorkspaceConfirmation) => WorkspaceDecision | Promise<WorkspaceDecision>;
40
49
  copyPath(cwd: string, path: string): void | Promise<void>;
41
50
  delete(cwd: string, paths: readonly string[]): Promise<{ operationId: string }>;
51
+ // What a file dragged out of the explorer leaves on the desktop or in another app; null for nothing.
52
+ export?: (cwd: string, path: string) => FileTreeExport | null;
53
+ // Files and folders dropped in from the OS onto 'target', a folder path or '' for the top level.
54
+ import?: (cwd: string, target: string, entries: readonly FileTreeImportEntry[]) => Promise<void>;
42
55
  list(cwd: string): Promise<readonly WorkspaceEntry[]>;
43
56
  preferences?: {
44
57
  get(): Promise<Partial<WorkspacePreferences>>;
@@ -46,18 +59,43 @@ type WorkspaceHost = {
46
59
  };
47
60
  read(cwd: string, path: string): Promise<string>;
48
61
  rename(cwd: string, source: string, destination: string): Promise<{ operationId: string }>;
62
+ session?: {
63
+ get(): Promise<WorkspaceSession | null>;
64
+ set(session: WorkspaceSession): Promise<void>;
65
+ };
49
66
  undo(cwd: string, operationId: string): Promise<void>;
50
67
  watch(cwd: string, changed: (event: WorkspaceChange) => void): VoidFunction | Promise<VoidFunction>;
51
68
  write(cwd: string, path: string, content: string): Promise<void>;
52
69
  };
53
70
 
54
71
  type WorkspacePreferences = {
72
+ autoSave: 'delay' | 'focus' | 'off';
73
+ autoSaveDelay: number;
55
74
  explorerOpen: boolean;
56
75
  explorerSide: 'left' | 'right';
76
+ // Chords over the default keys, passed to every editor as 'keybindings'.
77
+ keybindings: Readonly<Record<string, Command | null>>;
57
78
  showWhitespace: boolean;
58
79
  wrapText: boolean;
59
80
  };
60
81
 
82
+ type WorkspaceSession = {
83
+ active: string | null;
84
+ explorer: { expanded: string[]; scroll: number };
85
+ tabs: WorkspaceSessionTab[];
86
+ };
87
+
88
+ type WorkspaceSessionTab = {
89
+ // Unsaved text restored on load (hot exit); undefined when the tab was saved.
90
+ draft?: string;
91
+ folds: number[];
92
+ path: string;
93
+ pinned: boolean;
94
+ preview: boolean;
95
+ scroll: { left: number; top: number };
96
+ selection: { anchor: number; head: number };
97
+ };
98
+
61
99
  type WorkspaceState = Readonly<{
62
100
  active: WorkspaceTab | undefined;
63
101
  busy: number;
@@ -77,10 +115,13 @@ type WorkspaceState = Readonly<{
77
115
  }>;
78
116
 
79
117
  type WorkspaceTab = {
118
+ readonly compare?: WorkspaceCompare;
80
119
  readonly document: EditorDocument;
81
120
  readonly id: number;
82
121
  missing: boolean;
83
122
  path: string;
123
+ pinned: boolean;
124
+ preview: boolean;
84
125
  saved: string;
85
126
  scroll: { left: number; top: number };
86
127
  };
@@ -88,9 +129,16 @@ type WorkspaceTab = {
88
129
  type WorkspaceTarget = { column?: number; line?: number; path: string; requestId?: number | string };
89
130
 
90
131
 
132
+ const AUTO_SAVE_DELAY_MAX = 60_000;
133
+
134
+ const AUTO_SAVE_DELAY_MIN = 100;
135
+
91
136
  const DEFAULTS: WorkspacePreferences = {
137
+ autoSave: 'off',
138
+ autoSaveDelay: 1000,
92
139
  explorerOpen: true,
93
140
  explorerSide: 'right',
141
+ keybindings: {},
94
142
  showWhitespace: false,
95
143
  wrapText: false
96
144
  };
@@ -178,6 +226,7 @@ class EditorWorkspaceModel {
178
226
  private tabId = 0;
179
227
  private tabs: WorkspaceTab[] = [];
180
228
  private unwatch: VoidFunction | undefined;
229
+ private watchers = new Set<(event: WorkspaceChange) => void>();
181
230
  private watchWork = Promise.resolve();
182
231
 
183
232
 
@@ -189,6 +238,14 @@ class EditorWorkspaceModel {
189
238
 
190
239
 
191
240
  private applyPreferences(preferences: Partial<WorkspacePreferences>) {
241
+ if (preferences.autoSave === 'delay' || preferences.autoSave === 'focus' || preferences.autoSave === 'off') {
242
+ this.preferences.autoSave = preferences.autoSave;
243
+ }
244
+
245
+ if (typeof preferences.autoSaveDelay === 'number' && Number.isFinite(preferences.autoSaveDelay)) {
246
+ this.preferences.autoSaveDelay = Math.min(Math.max(Math.round(preferences.autoSaveDelay), AUTO_SAVE_DELAY_MIN), AUTO_SAVE_DELAY_MAX);
247
+ }
248
+
192
249
  for (let key of ['explorerOpen', 'showWhitespace', 'wrapText'] as const) {
193
250
  if (typeof preferences[key] === 'boolean') {
194
251
  this.preferences[key] = preferences[key];
@@ -198,6 +255,10 @@ class EditorWorkspaceModel {
198
255
  if (preferences.explorerSide === 'left' || preferences.explorerSide === 'right') {
199
256
  this.preferences.explorerSide = preferences.explorerSide;
200
257
  }
258
+
259
+ if (preferences.keybindings !== undefined) {
260
+ this.preferences.keybindings = sanitize(preferences.keybindings);
261
+ }
201
262
  }
202
263
 
203
264
  private async authorize(kind: WorkspaceConfirmation['kind'], tabs: readonly WorkspaceTab[], paths: readonly string[]) {
@@ -248,6 +309,30 @@ class EditorWorkspaceModel {
248
309
  return revisions;
249
310
  }
250
311
 
312
+ private async closeTabs(tabs: readonly WorkspaceTab[]) {
313
+ if (!tabs.length) {
314
+ return true;
315
+ }
316
+
317
+ let paths = tabs.map((tab) => tab.path);
318
+
319
+ for (let path of paths) {
320
+ this.closed.set(path, (this.closed.get(path) ?? 0) + 1);
321
+ }
322
+
323
+ if (!(await this.authorize('close', tabs, paths))) {
324
+ return false;
325
+ }
326
+
327
+ for (let tab of tabs) {
328
+ this.removeTab(tab);
329
+ }
330
+
331
+ this.emit();
332
+
333
+ return true;
334
+ }
335
+
251
336
  private desire(before: readonly WorkspaceEntry[], after: readonly WorkspaceEntry[]) {
252
337
  for (let entry of before) {
253
338
  this.overlay.set(entry.path, null);
@@ -374,6 +459,38 @@ class EditorWorkspaceModel {
374
459
  this.emit();
375
460
  }
376
461
 
462
+ /** Adds a tab whose text came from elsewhere, like a restored draft; undefined when the path is open or opening. */
463
+ adopt(path: string, content: string, saved: string, missing = false) {
464
+ if (this.disposed || this.opening.has(path) || this.tabs.some((tab) => tab.path === path)) {
465
+ return;
466
+ }
467
+
468
+ let tab: WorkspaceTab = {
469
+ document: new EditorDocument(content),
470
+ id: ++this.tabId,
471
+ missing,
472
+ path,
473
+ pinned: false,
474
+ preview: false,
475
+ saved,
476
+ scroll: { left: 0, top: 0 }
477
+ };
478
+
479
+ this.tabs.push(tab);
480
+ this.documents.set(tab.id, tab.document.subscribe((_, change) => {
481
+ if (change.textChanged && dirty(tab) !== this.dirty.get(tab.id)) {
482
+ if (dirty(tab)) {
483
+ tab.preview = false;
484
+ }
485
+
486
+ this.emit();
487
+ }
488
+ }));
489
+ this.emit();
490
+
491
+ return tab;
492
+ }
493
+
377
494
  async close(path = this.state.active?.path) {
378
495
  if (!path) {
379
496
  return false;
@@ -397,6 +514,66 @@ class EditorWorkspaceModel {
397
514
  return true;
398
515
  }
399
516
 
517
+ closeOthers(path = this.state.active?.path) {
518
+ return this.closeTabs(closable(this.tabs, 'others', path));
519
+ }
520
+
521
+ closeRight(path = this.state.active?.path) {
522
+ return this.closeTabs(closable(this.tabs, 'right', path));
523
+ }
524
+
525
+ closeSaved() {
526
+ return this.closeTabs(closable(this.tabs, 'saved'));
527
+ }
528
+
529
+ /** Opens a read-only diff of two files in a tab of its own, or shows the one already open for them. */
530
+ async compare(original: string, modified: string) {
531
+ let paths: [string, string];
532
+
533
+ try {
534
+ paths = [workspacePath(original, this.cwd), workspacePath(modified, this.cwd)];
535
+ }
536
+ catch (error) {
537
+ this.status(`Compare failed: ${message(error)}`, true);
538
+ return;
539
+ }
540
+
541
+ let cwd = this.cwd,
542
+ epoch = this.epoch,
543
+ key = compareKey(paths[0], paths[1]),
544
+ tab = this.tabs.find((tab) => tab.path === key);
545
+
546
+ if (!tab) {
547
+ let texts: string[];
548
+
549
+ try {
550
+ texts = await Promise.all([this.host.read(cwd, paths[0]), this.host.read(cwd, paths[1])]);
551
+ }
552
+ catch (error) {
553
+ if (epoch === this.epoch) {
554
+ this.status(`Compare failed: ${message(error)}`, true);
555
+ }
556
+
557
+ return;
558
+ }
559
+
560
+ if (epoch !== this.epoch || this.disposed) {
561
+ return;
562
+ }
563
+
564
+ tab = this.tabs.find((tab) => tab.path === key);
565
+
566
+ if (!tab) {
567
+ tab = compareTab(++this.tabId, { modified: texts[1], original: texts[0], paths });
568
+ this.tabs.push(tab);
569
+ }
570
+ }
571
+
572
+ this.activate(tab);
573
+
574
+ return tab;
575
+ }
576
+
400
577
  async copyPath(path: string) {
401
578
  try {
402
579
  await this.host.copyPath(this.cwd, workspacePath(path, this.cwd));
@@ -481,7 +658,17 @@ class EditorWorkspaceModel {
481
658
  this.listeners.clear();
482
659
  }
483
660
 
484
- async open(value: string, line?: number, column = 1) {
661
+ /** Hears each event the host's watcher reports, once its refresh has started. */
662
+ onWatch(listener: (event: WorkspaceChange) => void) {
663
+ this.watchers.add(listener);
664
+
665
+ return () => {
666
+ this.watchers.delete(listener);
667
+ };
668
+ }
669
+
670
+ // A preview opens in place of the last preview tab; opening the file again without 'preview' keeps its tab.
671
+ async open(value: string, line?: number, column = 1, preview = false) {
485
672
  if (this.disposed) {
486
673
  return;
487
674
  }
@@ -521,13 +708,24 @@ class EditorWorkspaceModel {
521
708
  id: ++this.tabId,
522
709
  missing: false,
523
710
  path,
711
+ pinned: false,
712
+ preview,
524
713
  saved: content,
525
714
  scroll: { left: 0, top: 0 }
526
715
  };
527
716
 
528
- this.tabs.push(tab);
717
+ let replaced = place(this.tabs, tab);
718
+
719
+ if (replaced) {
720
+ this.removeTab(replaced);
721
+ }
722
+
529
723
  this.documents.set(tab.id, tab.document.subscribe((_, change) => {
530
724
  if (change.textChanged && dirty(tab) !== this.dirty.get(tab.id)) {
725
+ if (dirty(tab)) {
726
+ tab.preview = false;
727
+ }
728
+
531
729
  this.emit();
532
730
  }
533
731
  }));
@@ -556,6 +754,10 @@ class EditorWorkspaceModel {
556
754
  return;
557
755
  }
558
756
 
757
+ if (!preview) {
758
+ tab.preview = false;
759
+ }
760
+
559
761
  if (intent === this.openIntent) {
560
762
  this.active = tab.id;
561
763
 
@@ -586,6 +788,19 @@ class EditorWorkspaceModel {
586
788
  return this.open(target.path, target.line, target.column);
587
789
  }
588
790
 
791
+ pin(path: string, pinned = true) {
792
+ let tab = this.tabs.find((tab) => tab.path === path);
793
+
794
+ if (!tab || tab.pinned === pinned) {
795
+ return;
796
+ }
797
+
798
+ tab.pinned = pinned;
799
+ tab.preview = false;
800
+ order(this.tabs);
801
+ this.emit();
802
+ }
803
+
589
804
  async refresh(_paths?: readonly string[]) {
590
805
  if (this.disposed || !this.cwd) {
591
806
  return;
@@ -640,6 +855,10 @@ class EditorWorkspaceModel {
640
855
  return;
641
856
  }
642
857
 
858
+ if (tab.compare) {
859
+ continue;
860
+ }
861
+
643
862
  tab.missing = !entries.has(tab.path);
644
863
 
645
864
  if (dirty(tab) || tab.missing) {
@@ -756,7 +975,7 @@ class EditorWorkspaceModel {
756
975
 
757
976
  save(tab = this.state.active) {
758
977
  return this.queue('Save', async () => {
759
- if (!tab || !this.tabs.includes(tab)) {
978
+ if (!tab || !this.tabs.includes(tab) || tab.compare) {
760
979
  return false;
761
980
  }
762
981
 
@@ -903,6 +1122,10 @@ class EditorWorkspaceModel {
903
1122
  let stop = await this.host.watch(this.cwd, (event) => {
904
1123
  if (epoch === this.epoch) {
905
1124
  this.watchWork = this.refresh(event.paths);
1125
+
1126
+ for (let watcher of [...this.watchers]) {
1127
+ watcher(event);
1128
+ }
906
1129
  }
907
1130
  });
908
1131
 
@@ -989,6 +1212,10 @@ class EditorWorkspaceModel {
989
1212
  });
990
1213
  }
991
1214
 
1215
+ unpin(path: string) {
1216
+ this.pin(path, false);
1217
+ }
1218
+
992
1219
  /** Tests/hosts can drain event-driven work without sleeps or polling timers. */
993
1220
  async whenIdle() {
994
1221
  for (;;) {
@@ -1012,11 +1239,14 @@ export { containsPath, DEFAULTS, dirty, EditorWorkspaceModel, workspacePath };
1012
1239
  export type {
1013
1240
  WorkspaceAction,
1014
1241
  WorkspaceChange,
1242
+ WorkspaceCompare,
1015
1243
  WorkspaceConfirmation,
1016
1244
  WorkspaceDecision,
1017
1245
  WorkspaceEntry,
1018
1246
  WorkspaceHost,
1019
1247
  WorkspacePreferences,
1248
+ WorkspaceSession,
1249
+ WorkspaceSessionTab,
1020
1250
  WorkspaceState,
1021
1251
  WorkspaceTab,
1022
1252
  WorkspaceTarget
@@ -0,0 +1,194 @@
1
+ import { effect, root } from '@esportsplus/reactivity';
2
+ import { mac } from '~/shared/platform';
3
+ import { keymap, type Command } from '../code/keymap';
4
+ import type { CodeController } from '../code/view';
5
+ import type { Selection } from '../code/document';
6
+ import type { FileTreeController, FileTreeJump } from '../tree';
7
+ import type { EditorWorkspaceModel, WorkspaceTab } from './model';
8
+ import type { WorkspaceEditorController } from './index';
9
+ import type hosted from './session';
10
+
11
+
12
+ type Options = {
13
+ // The chords the shown editor runs commands on, so a rebound command moves across files under its new keys.
14
+ bindings: () => Readonly<Record<string, Command | null>> | undefined;
15
+ hosting: ReturnType<typeof hosted>;
16
+ model: EditorWorkspaceModel;
17
+ tree: () => FileTreeController | undefined;
18
+ };
19
+
20
+ type Step = 'moved' | 'none' | 'wrapped';
21
+
22
+
23
+ const COMMANDS: Partial<Record<Command, [FileTreeJump, boolean]>> = {
24
+ nextChange: ['change', false],
25
+ nextProblem: ['problem', false],
26
+ previousChange: ['change', true],
27
+ previousProblem: ['problem', true]
28
+ };
29
+
30
+ // Diagnostics for a file just opened come from its language server a moment later.
31
+ const PROBLEMS_WAIT = 1500;
32
+
33
+
34
+ function caret(selection: Selection) {
35
+ return selection.direction === 'backward' ? selection.start : selection.end;
36
+ }
37
+
38
+ function code(controller: WorkspaceEditorController | undefined): controller is CodeController {
39
+ return !!controller && 'nextChange' in controller && 'nextProblem' in controller;
40
+ }
41
+
42
+ // The editor's own commands wrap around within the file; a caret that went back past where it was has wrapped.
43
+ function step(controller: CodeController, kind: FileTreeJump, backward: boolean): Step {
44
+ let before = caret(controller.document.selection),
45
+ moved = kind === 'change'
46
+ ? (backward ? controller.previousChange() : controller.nextChange())
47
+ : (backward ? controller.previousProblem() : controller.nextProblem());
48
+
49
+ if (!moved) {
50
+ return 'none';
51
+ }
52
+
53
+ let after = caret(controller.document.selection);
54
+
55
+ return (backward ? after >= before : after <= before) ? 'wrapped' : 'moved';
56
+ }
57
+
58
+ function reported(controller: CodeController) {
59
+ return new Promise<void>((resolve) => {
60
+ let stop = root((dispose) => {
61
+ effect(() => {
62
+ let { errors, warnings } = controller.state.problems;
63
+
64
+ if (errors || warnings) {
65
+ queueMicrotask(finish);
66
+ }
67
+ });
68
+
69
+ return dispose;
70
+ }),
71
+ timer = setTimeout(finish, PROBLEMS_WAIT);
72
+
73
+ function finish() {
74
+ clearTimeout(timer);
75
+ stop();
76
+ resolve();
77
+ }
78
+ });
79
+ }
80
+
81
+
82
+ // Next and previous change or problem across files: within the shown file first, through the editor's own
83
+ // commands, and once none are left that way, on to the next file the explorer marks, starting from its first.
84
+ const navigate = ({ bindings, hosting, model, tree }: Options) => {
85
+ let bound: ReturnType<Options['bindings']> | null = null,
86
+ resolve = keymap(mac());
87
+
88
+ async function go(kind: FileTreeJump, backward = false) {
89
+ let active = model.state.active,
90
+ controller = active && (await hosting.whenShown(active)),
91
+ left: Selection | undefined,
92
+ result: Step = 'none';
93
+
94
+ if (active && code(controller) && model.state.active === active) {
95
+ left = controller.document.selection;
96
+ result = step(controller, kind, backward);
97
+
98
+ if (result === 'moved') {
99
+ return true;
100
+ }
101
+ }
102
+
103
+ hosting.mark();
104
+
105
+ let explorer = tree(),
106
+ element = explorer && (await (backward ? explorer.previous(kind) : explorer.next(kind)));
107
+
108
+ if (!element || element.id === active?.path) {
109
+ if (result === 'none') {
110
+ model.status(kind === 'change' ? 'No changes' : 'No problems');
111
+ }
112
+
113
+ return result !== 'none';
114
+ }
115
+
116
+ // The file left behind keeps its caret where it was, not where the wrap put it.
117
+ if (result === 'wrapped' && code(controller) && left) {
118
+ controller.select(left, false);
119
+ }
120
+
121
+ let tab = await model.open(element.id);
122
+
123
+ return !!tab && model.state.active === tab && arrive(tab, kind, backward);
124
+ }
125
+
126
+ async function arrive(tab: WorkspaceTab, kind: FileTreeJump, backward: boolean) {
127
+ let controller = await hosting.whenShown(tab);
128
+
129
+ if (!code(controller) || model.state.active !== tab) {
130
+ return !!controller;
131
+ }
132
+
133
+ if (kind === 'change') {
134
+ let text = await hosting.loaded(tab.path);
135
+
136
+ if (text != null) {
137
+ controller.setBaseline(text);
138
+ }
139
+ }
140
+ else if (!controller.state.problems.errors && !controller.state.problems.warnings) {
141
+ await reported(controller);
142
+ }
143
+
144
+ if (model.state.active !== tab) {
145
+ return false;
146
+ }
147
+
148
+ // From the far end, the editor's own wrap lands on the file's first one, or its last going backward.
149
+ controller.select({ start: backward ? 0 : controller.document.value.length }, false);
150
+ step(controller, kind, backward);
151
+
152
+ return true;
153
+ }
154
+
155
+ function keydown(event: KeyboardEvent) {
156
+ if (event.defaultPrevented || event.isComposing) {
157
+ return;
158
+ }
159
+
160
+ let next = bindings();
161
+
162
+ if (next !== bound) {
163
+ bound = next;
164
+ resolve = keymap(mac(), next);
165
+ }
166
+
167
+ let command = resolve(event),
168
+ jump = command && COMMANDS[command];
169
+
170
+ if (!jump) {
171
+ return;
172
+ }
173
+
174
+ // Ahead of the editor, which would only wrap around within its own file.
175
+ event.preventDefault();
176
+ event.stopPropagation();
177
+ void go(jump[0], jump[1]);
178
+ }
179
+
180
+ return {
181
+ connect(element: HTMLElement) {
182
+ let listening = new AbortController();
183
+
184
+ element.addEventListener('keydown', keydown, { capture: true, signal: listening.signal });
185
+
186
+ return () => listening.abort();
187
+ },
188
+ go
189
+ };
190
+ };
191
+
192
+
193
+ export default navigate;
194
+ export { step };