@gjermundgaraba-designs/pixel-paper 0.26.0 → 0.27.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 (940) hide show
  1. package/DESIGN.md +28 -3
  2. package/dist/src/adapters/diagram.d.ts +38 -0
  3. package/dist/src/adapters/diagram.d.ts.map +1 -0
  4. package/dist/src/adapters/diagram.js +206 -0
  5. package/dist/src/adapters/mermaid.d.ts +2 -20
  6. package/dist/src/adapters/mermaid.d.ts.map +1 -1
  7. package/dist/src/adapters/mermaid.js +9 -229
  8. package/dist/src/announcer/announcer.d.ts +0 -4
  9. package/dist/src/announcer/announcer.d.ts.map +1 -1
  10. package/dist/src/announcer/announcer.js +19 -18
  11. package/dist/src/attributes/attributes.d.ts.map +1 -1
  12. package/dist/src/{audioFrame/audioFrame.d.ts → audio-frame/audio-frame.d.ts} +1 -1
  13. package/dist/src/audio-frame/audio-frame.d.ts.map +1 -0
  14. package/dist/src/{audioFrame/audioFrame.js → audio-frame/audio-frame.js} +1 -1
  15. package/dist/src/audio-frame/index.d.ts +3 -0
  16. package/dist/src/audio-frame/index.d.ts.map +1 -0
  17. package/dist/src/audio-frame/index.js +1 -0
  18. package/dist/src/banner/banner.d.ts.map +1 -1
  19. package/dist/src/banner/index.d.ts.map +1 -1
  20. package/dist/src/{barChart/barChart.d.ts → bar-chart/bar-chart.d.ts} +2 -2
  21. package/dist/src/bar-chart/bar-chart.d.ts.map +1 -0
  22. package/dist/src/{barChart/barChart.js → bar-chart/bar-chart.js} +40 -35
  23. package/dist/src/bar-chart/index.d.ts +3 -0
  24. package/dist/src/bar-chart/index.d.ts.map +1 -0
  25. package/dist/src/bar-chart/index.js +1 -0
  26. package/dist/src/bench/bench.d.ts.map +1 -1
  27. package/dist/src/bench/index.d.ts.map +1 -1
  28. package/dist/src/board/board.d.ts +45 -46
  29. package/dist/src/board/board.d.ts.map +1 -1
  30. package/dist/src/board/board.js +76 -102
  31. package/dist/src/board/index.d.ts +1 -1
  32. package/dist/src/board/index.d.ts.map +1 -1
  33. package/dist/src/button/button.d.ts +1 -2
  34. package/dist/src/button/button.d.ts.map +1 -1
  35. package/dist/src/button/button.js +7 -5
  36. package/dist/src/button/index.d.ts +1 -1
  37. package/dist/src/button/index.d.ts.map +1 -1
  38. package/dist/src/card/card.d.ts.map +1 -1
  39. package/dist/src/card/card.js +4 -2
  40. package/dist/src/card/index.d.ts.map +1 -1
  41. package/dist/src/{chartTable/chartTable.d.ts → chart-table/chart-table.d.ts} +4 -14
  42. package/dist/src/chart-table/chart-table.d.ts.map +1 -0
  43. package/dist/src/{chartTable/chartTable.js → chart-table/chart-table.js} +9 -16
  44. package/dist/src/chip/chip.d.ts.map +1 -1
  45. package/dist/src/chip/chip.js +4 -2
  46. package/dist/src/chip/index.d.ts.map +1 -1
  47. package/dist/src/choice/choice.d.ts.map +1 -1
  48. package/dist/src/choice/choice.js +3 -1
  49. package/dist/src/choice/index.d.ts.map +1 -1
  50. package/dist/src/choices/choices.d.ts.map +1 -1
  51. package/dist/src/choices/index.d.ts.map +1 -1
  52. package/dist/src/{codeEditor/codeEditor.d.ts → code-editor/code-editor.d.ts} +1 -1
  53. package/dist/src/code-editor/code-editor.d.ts.map +1 -0
  54. package/dist/src/{codeEditor/codeEditor.js → code-editor/code-editor.js} +2 -2
  55. package/dist/src/code-editor/index.d.ts +3 -0
  56. package/dist/src/code-editor/index.d.ts.map +1 -0
  57. package/dist/src/code-editor/index.js +1 -0
  58. package/dist/src/{codeSurface/codeSurface.d.ts → code-surface/code-surface.d.ts} +1 -1
  59. package/dist/src/code-surface/code-surface.d.ts.map +1 -0
  60. package/dist/src/{codeSurface/codeSurface.js → code-surface/code-surface.js} +6 -1
  61. package/dist/src/code-surface/index.d.ts +3 -0
  62. package/dist/src/code-surface/index.d.ts.map +1 -0
  63. package/dist/src/code-surface/index.js +1 -0
  64. package/dist/src/{commandPalette/commandPalette.d.ts → command-palette/command-palette.d.ts} +85 -77
  65. package/dist/src/command-palette/command-palette.d.ts.map +1 -0
  66. package/dist/src/command-palette/command-palette.js +625 -0
  67. package/dist/src/{commandPalette → command-palette}/index.d.ts +2 -2
  68. package/dist/src/command-palette/index.d.ts.map +1 -0
  69. package/dist/src/{commandPalette → command-palette}/index.js +1 -1
  70. package/dist/src/{commandPalette → command-palette}/keys.d.ts +0 -21
  71. package/dist/src/command-palette/keys.d.ts.map +1 -0
  72. package/dist/src/command-palette/keys.js +85 -0
  73. package/dist/src/{commandPalette → command-palette}/match.d.ts +5 -11
  74. package/dist/src/command-palette/match.d.ts.map +1 -0
  75. package/dist/src/{commandPalette → command-palette}/match.js +20 -24
  76. package/dist/src/{commandPalette → command-palette}/message.d.ts +37 -26
  77. package/dist/src/command-palette/message.d.ts.map +1 -0
  78. package/dist/src/{commandPalette → command-palette}/message.js +8 -20
  79. package/dist/src/{confirmDialog/confirmDialog.d.ts → confirm-dialog/confirm-dialog.d.ts} +1 -1
  80. package/dist/src/confirm-dialog/confirm-dialog.d.ts.map +1 -0
  81. package/dist/src/{confirmDialog/confirmDialog.js → confirm-dialog/confirm-dialog.js} +18 -23
  82. package/dist/src/confirm-dialog/index.d.ts +3 -0
  83. package/dist/src/confirm-dialog/index.d.ts.map +1 -0
  84. package/dist/src/{confirmDialog → confirm-dialog}/index.js +1 -1
  85. package/dist/src/{contextMenu/contextMenu.d.ts → context-menu/context-menu.d.ts} +18 -21
  86. package/dist/src/context-menu/context-menu.d.ts.map +1 -0
  87. package/dist/src/{contextMenu/contextMenu.js → context-menu/context-menu.js} +45 -57
  88. package/dist/src/{contextMenu → context-menu}/index.d.ts +2 -2
  89. package/dist/src/context-menu/index.d.ts.map +1 -0
  90. package/dist/src/{contextMenu → context-menu}/index.js +1 -1
  91. package/dist/src/{copyButton/copyButton.d.ts → copy-button/copy-button.d.ts} +5 -7
  92. package/dist/src/copy-button/copy-button.d.ts.map +1 -0
  93. package/dist/src/{copyButton/copyButton.js → copy-button/copy-button.js} +18 -27
  94. package/dist/src/copy-button/index.d.ts +3 -0
  95. package/dist/src/copy-button/index.d.ts.map +1 -0
  96. package/dist/src/copy-button/index.js +1 -0
  97. package/dist/src/crumbs/crumbs.d.ts +1 -1
  98. package/dist/src/crumbs/crumbs.d.ts.map +1 -1
  99. package/dist/src/crumbs/index.d.ts.map +1 -1
  100. package/dist/src/deck/deck.d.ts.map +1 -1
  101. package/dist/src/deck/index.d.ts.map +1 -1
  102. package/dist/src/dialog/dialog.d.ts +6 -14
  103. package/dist/src/dialog/dialog.d.ts.map +1 -1
  104. package/dist/src/dialog/dialog.js +29 -36
  105. package/dist/src/dialog/fold.d.ts +3 -3
  106. package/dist/src/dialog/fold.d.ts.map +1 -1
  107. package/dist/src/dialog/fold.js +5 -4
  108. package/dist/src/dialog/index.d.ts +1 -1
  109. package/dist/src/dialog/index.d.ts.map +1 -1
  110. package/dist/src/disclosure/disclosure.d.ts.map +1 -1
  111. package/dist/src/disclosure/disclosure.js +3 -1
  112. package/dist/src/disclosure/index.d.ts.map +1 -1
  113. package/dist/src/dom/html-element.d.ts +3 -0
  114. package/dist/src/dom/html-element.d.ts.map +1 -0
  115. package/dist/src/dom/html-element.js +6 -0
  116. package/dist/src/drag/drag.d.ts +0 -34
  117. package/dist/src/drag/drag.d.ts.map +1 -1
  118. package/dist/src/drag/drag.js +27 -73
  119. package/dist/src/{dropZone/dropZone.d.ts → drop-zone/drop-zone.d.ts} +3 -3
  120. package/dist/src/drop-zone/drop-zone.d.ts.map +1 -0
  121. package/dist/src/{dropZone/dropZone.js → drop-zone/drop-zone.js} +13 -19
  122. package/dist/src/drop-zone/index.d.ts +3 -0
  123. package/dist/src/drop-zone/index.d.ts.map +1 -0
  124. package/dist/src/drop-zone/index.js +1 -0
  125. package/dist/src/{editableTitle/editableTitle.d.ts → editable-title/editable-title.d.ts} +14 -12
  126. package/dist/src/editable-title/editable-title.d.ts.map +1 -0
  127. package/dist/src/{editableTitle/editableTitle.js → editable-title/editable-title.js} +33 -39
  128. package/dist/src/editable-title/index.d.ts +4 -0
  129. package/dist/src/editable-title/index.d.ts.map +1 -0
  130. package/dist/src/{editableTitle → editable-title}/index.js +1 -1
  131. package/dist/src/{emptyState/emptyState.d.ts → empty-state/empty-state.d.ts} +1 -1
  132. package/dist/src/empty-state/empty-state.d.ts.map +1 -0
  133. package/dist/src/{emptyState/emptyState.js → empty-state/empty-state.js} +5 -2
  134. package/dist/src/empty-state/index.d.ts +3 -0
  135. package/dist/src/empty-state/index.d.ts.map +1 -0
  136. package/dist/src/empty-state/index.js +1 -0
  137. package/dist/src/{errorSummary/errorSummary.d.ts → error-summary/error-summary.d.ts} +2 -2
  138. package/dist/src/error-summary/error-summary.d.ts.map +1 -0
  139. package/dist/src/{errorSummary/errorSummary.js → error-summary/error-summary.js} +7 -5
  140. package/dist/src/error-summary/index.d.ts +3 -0
  141. package/dist/src/error-summary/index.d.ts.map +1 -0
  142. package/dist/src/error-summary/index.js +1 -0
  143. package/dist/src/field/field.d.ts +2 -7
  144. package/dist/src/field/field.d.ts.map +1 -1
  145. package/dist/src/field/field.js +12 -13
  146. package/dist/src/field/index.d.ts.map +1 -1
  147. package/dist/src/{fieldGrid/fieldGrid.d.ts → field-grid/field-grid.d.ts} +1 -1
  148. package/dist/src/field-grid/field-grid.d.ts.map +1 -0
  149. package/dist/src/{fieldGrid/fieldGrid.js → field-grid/field-grid.js} +1 -1
  150. package/dist/src/field-grid/index.d.ts +3 -0
  151. package/dist/src/field-grid/index.d.ts.map +1 -0
  152. package/dist/src/field-grid/index.js +1 -0
  153. package/dist/src/fields/fields.d.ts.map +1 -1
  154. package/dist/src/fields/fields.js +4 -1
  155. package/dist/src/fields/index.d.ts.map +1 -1
  156. package/dist/src/fieldset/fieldset.d.ts.map +1 -1
  157. package/dist/src/fieldset/index.d.ts.map +1 -1
  158. package/dist/src/{fileTree/fileTree.d.ts → file-tree/file-tree.d.ts} +5 -5
  159. package/dist/src/file-tree/file-tree.d.ts.map +1 -0
  160. package/dist/src/file-tree/file-tree.js +242 -0
  161. package/dist/src/file-tree/index.d.ts +3 -0
  162. package/dist/src/file-tree/index.d.ts.map +1 -0
  163. package/dist/src/{fileTree → file-tree}/index.js +1 -1
  164. package/dist/src/{filterChip/filterChip.d.ts → filter-chip/filter-chip.d.ts} +1 -1
  165. package/dist/src/filter-chip/filter-chip.d.ts.map +1 -0
  166. package/dist/src/{filterChip/filterChip.js → filter-chip/filter-chip.js} +11 -7
  167. package/dist/src/filter-chip/index.d.ts +3 -0
  168. package/dist/src/filter-chip/index.d.ts.map +1 -0
  169. package/dist/src/filter-chip/index.js +1 -0
  170. package/dist/src/{filterStrip/filterStrip.d.ts → filter-strip/filter-strip.d.ts} +1 -1
  171. package/dist/src/filter-strip/filter-strip.d.ts.map +1 -0
  172. package/dist/src/{filterStrip/filterStrip.js → filter-strip/filter-strip.js} +1 -1
  173. package/dist/src/filter-strip/index.d.ts +3 -0
  174. package/dist/src/filter-strip/index.d.ts.map +1 -0
  175. package/dist/src/filter-strip/index.js +1 -0
  176. package/dist/src/{flashWord/flashWord.d.ts → flash-word/flash-word.d.ts} +2 -2
  177. package/dist/src/flash-word/flash-word.d.ts.map +1 -0
  178. package/dist/src/{flashWord/flashWord.js → flash-word/flash-word.js} +2 -3
  179. package/dist/src/flash-word/index.d.ts +3 -0
  180. package/dist/src/flash-word/index.d.ts.map +1 -0
  181. package/dist/src/flash-word/index.js +1 -0
  182. package/dist/src/focus/focus.d.ts.map +1 -1
  183. package/dist/src/focus/focus.js +0 -2
  184. package/dist/src/format/format.d.ts +0 -7
  185. package/dist/src/format/format.d.ts.map +1 -1
  186. package/dist/src/format/format.js +7 -16
  187. package/dist/src/format/index.d.ts.map +1 -1
  188. package/dist/src/glyph/glyph.d.ts +1 -2
  189. package/dist/src/glyph/glyph.d.ts.map +1 -1
  190. package/dist/src/glyph/glyph.js +0 -2
  191. package/dist/src/glyph/glyphs.d.ts +19 -4
  192. package/dist/src/glyph/glyphs.d.ts.map +1 -1
  193. package/dist/src/glyph/glyphs.js +2577 -2594
  194. package/dist/src/glyph/index.d.ts.map +1 -1
  195. package/dist/src/group/group.d.ts.map +1 -1
  196. package/dist/src/group/index.d.ts.map +1 -1
  197. package/dist/src/history/history.d.ts +1 -1
  198. package/dist/src/history/history.d.ts.map +1 -1
  199. package/dist/src/history/history.js +6 -3
  200. package/dist/src/history/index.d.ts.map +1 -1
  201. package/dist/src/{iconButton/iconButton.d.ts → icon-button/icon-button.d.ts} +1 -1
  202. package/dist/src/icon-button/icon-button.d.ts.map +1 -0
  203. package/dist/src/{iconButton/iconButton.js → icon-button/icon-button.js} +6 -4
  204. package/dist/src/icon-button/index.d.ts +3 -0
  205. package/dist/src/icon-button/index.d.ts.map +1 -0
  206. package/dist/src/icon-button/index.js +1 -0
  207. package/dist/src/identity/identity.d.ts.map +1 -1
  208. package/dist/src/identity/index.d.ts.map +1 -1
  209. package/dist/src/{imageFrame/imageFrame.d.ts → image-frame/image-frame.d.ts} +1 -1
  210. package/dist/src/image-frame/image-frame.d.ts.map +1 -0
  211. package/dist/src/{imageFrame/imageFrame.js → image-frame/image-frame.js} +19 -12
  212. package/dist/src/image-frame/index.d.ts +3 -0
  213. package/dist/src/image-frame/index.d.ts.map +1 -0
  214. package/dist/src/image-frame/index.js +1 -0
  215. package/dist/src/index.d.ts +41 -41
  216. package/dist/src/index.d.ts.map +1 -1
  217. package/dist/src/index.js +41 -41
  218. package/dist/src/inline-input/index.d.ts +3 -0
  219. package/dist/src/inline-input/index.d.ts.map +1 -0
  220. package/dist/src/{inlineInput → inline-input}/index.js +1 -1
  221. package/dist/src/{inlineInput/inlineInput.d.ts → inline-input/inline-input.d.ts} +8 -12
  222. package/dist/src/inline-input/inline-input.d.ts.map +1 -0
  223. package/dist/src/{inlineInput/inlineInput.js → inline-input/inline-input.js} +60 -75
  224. package/dist/src/key-help/index.d.ts +3 -0
  225. package/dist/src/key-help/index.d.ts.map +1 -0
  226. package/dist/src/{keyHelp → key-help}/index.js +1 -1
  227. package/dist/src/{keyHelp/keyHelp.d.ts → key-help/key-help.d.ts} +7 -7
  228. package/dist/src/key-help/key-help.d.ts.map +1 -0
  229. package/dist/src/{keyHelp/keyHelp.js → key-help/key-help.js} +48 -47
  230. package/dist/src/key-hint/index.d.ts +4 -0
  231. package/dist/src/key-hint/index.d.ts.map +1 -0
  232. package/dist/src/key-hint/index.js +2 -0
  233. package/dist/src/{keyHint/keyHint.d.ts → key-hint/key-hint.d.ts} +2 -2
  234. package/dist/src/key-hint/key-hint.d.ts.map +1 -0
  235. package/dist/src/{keyHint/keyHint.js → key-hint/key-hint.js} +2 -2
  236. package/dist/src/{keyHint/keyLabel.d.ts → key-hint/key-label.d.ts} +2 -3
  237. package/dist/src/key-hint/key-label.d.ts.map +1 -0
  238. package/dist/src/{keyHint/keyLabel.js → key-hint/key-label.js} +29 -24
  239. package/dist/src/keymap/index.d.ts.map +1 -1
  240. package/dist/src/keymap/keymap.d.ts +2 -2
  241. package/dist/src/keymap/keymap.d.ts.map +1 -1
  242. package/dist/src/keymap/keymap.js +3 -1
  243. package/dist/src/keys/keys.d.ts +0 -2
  244. package/dist/src/keys/keys.d.ts.map +1 -1
  245. package/dist/src/keys/keys.js +0 -2
  246. package/dist/src/line-chart/index.d.ts +3 -0
  247. package/dist/src/line-chart/index.d.ts.map +1 -0
  248. package/dist/src/line-chart/index.js +1 -0
  249. package/dist/src/{lineChart/lineChart.d.ts → line-chart/line-chart.d.ts} +2 -2
  250. package/dist/src/line-chart/line-chart.d.ts.map +1 -0
  251. package/dist/src/{lineChart/lineChart.js → line-chart/line-chart.js} +52 -44
  252. package/dist/src/line-diff/diff.d.ts +29 -0
  253. package/dist/src/line-diff/diff.d.ts.map +1 -0
  254. package/dist/src/line-diff/diff.js +85 -0
  255. package/dist/src/line-diff/index.d.ts +5 -0
  256. package/dist/src/line-diff/index.d.ts.map +1 -0
  257. package/dist/src/line-diff/index.js +2 -0
  258. package/dist/src/{lineDiff/lineDiff.d.ts → line-diff/line-diff.d.ts} +1 -1
  259. package/dist/src/line-diff/line-diff.d.ts.map +1 -0
  260. package/dist/src/{lineDiff/lineDiff.js → line-diff/line-diff.js} +26 -19
  261. package/dist/src/{lineDiff → line-diff}/patch.d.ts +5 -9
  262. package/dist/src/line-diff/patch.d.ts.map +1 -0
  263. package/dist/src/{lineDiff → line-diff}/patch.js +54 -62
  264. package/dist/src/link-button/index.d.ts +3 -0
  265. package/dist/src/link-button/index.d.ts.map +1 -0
  266. package/dist/src/link-button/index.js +1 -0
  267. package/dist/src/{linkButton/linkButton.d.ts → link-button/link-button.d.ts} +2 -2
  268. package/dist/src/link-button/link-button.d.ts.map +1 -0
  269. package/dist/src/{linkButton/linkButton.js → link-button/link-button.js} +1 -1
  270. package/dist/src/link-state/index.d.ts +3 -0
  271. package/dist/src/link-state/index.d.ts.map +1 -0
  272. package/dist/src/link-state/index.js +1 -0
  273. package/dist/src/{linkState/linkState.d.ts → link-state/link-state.d.ts} +1 -1
  274. package/dist/src/link-state/link-state.d.ts.map +1 -0
  275. package/dist/src/link-state/link-state.js +24 -0
  276. package/dist/src/live-region/index.d.ts +3 -0
  277. package/dist/src/live-region/index.d.ts.map +1 -0
  278. package/dist/src/live-region/index.js +1 -0
  279. package/dist/src/{liveRegion/liveRegion.d.ts → live-region/live-region.d.ts} +6 -3
  280. package/dist/src/live-region/live-region.d.ts.map +1 -0
  281. package/dist/src/{liveRegion/liveRegion.js → live-region/live-region.js} +7 -5
  282. package/dist/src/loading/index.d.ts.map +1 -1
  283. package/dist/src/loading/loading.d.ts.map +1 -1
  284. package/dist/src/loading/loading.js +5 -1
  285. package/dist/src/mark/index.d.ts.map +1 -1
  286. package/dist/src/mark/mark.d.ts +0 -4
  287. package/dist/src/mark/mark.d.ts.map +1 -1
  288. package/dist/src/mark/mark.js +6 -3
  289. package/dist/src/media/index.d.ts.map +1 -1
  290. package/dist/src/media/media.d.ts +17 -42
  291. package/dist/src/media/media.d.ts.map +1 -1
  292. package/dist/src/media/media.js +106 -104
  293. package/dist/src/menu/index.d.ts.map +1 -1
  294. package/dist/src/menu/item.d.ts +8 -8
  295. package/dist/src/menu/item.d.ts.map +1 -1
  296. package/dist/src/menu/menu.d.ts +2 -5
  297. package/dist/src/menu/menu.d.ts.map +1 -1
  298. package/dist/src/menu/menu.js +19 -30
  299. package/dist/src/menu/slip.d.ts +4 -18
  300. package/dist/src/menu/slip.d.ts.map +1 -1
  301. package/dist/src/menu/slip.js +36 -36
  302. package/dist/src/meter/index.d.ts.map +1 -1
  303. package/dist/src/meter/meter.d.ts +1 -1
  304. package/dist/src/meter/meter.d.ts.map +1 -1
  305. package/dist/src/meter/meter.js +12 -15
  306. package/dist/src/monogram/index.d.ts.map +1 -1
  307. package/dist/src/monogram/monogram.d.ts.map +1 -1
  308. package/dist/src/monogram/monogram.js +9 -8
  309. package/dist/src/nav-strip/index.d.ts +3 -0
  310. package/dist/src/nav-strip/index.d.ts.map +1 -0
  311. package/dist/src/nav-strip/index.js +1 -0
  312. package/dist/src/{navStrip/navStrip.d.ts → nav-strip/nav-strip.d.ts} +3 -6
  313. package/dist/src/nav-strip/nav-strip.d.ts.map +1 -0
  314. package/dist/src/nav-strip/nav-strip.js +25 -0
  315. package/dist/src/notice/index.d.ts.map +1 -1
  316. package/dist/src/notice/notice.d.ts +0 -4
  317. package/dist/src/notice/notice.d.ts.map +1 -1
  318. package/dist/src/notice/notice.js +1 -4
  319. package/dist/src/outcome/index.d.ts.map +1 -1
  320. package/dist/src/outcome/outcome.d.ts.map +1 -1
  321. package/dist/src/outcome/outcome.js +1 -1
  322. package/dist/src/page-head/index.d.ts +3 -0
  323. package/dist/src/page-head/index.d.ts.map +1 -0
  324. package/dist/src/page-head/index.js +1 -0
  325. package/dist/src/{pageHead/pageHead.d.ts → page-head/page-head.d.ts} +1 -1
  326. package/dist/src/page-head/page-head.d.ts.map +1 -0
  327. package/dist/src/{pageHead/pageHead.js → page-head/page-head.js} +1 -1
  328. package/dist/src/panel/index.d.ts.map +1 -1
  329. package/dist/src/panel/panel.d.ts +0 -1
  330. package/dist/src/panel/panel.d.ts.map +1 -1
  331. package/dist/src/panel/panel.js +0 -1
  332. package/dist/src/password-field/index.d.ts +3 -0
  333. package/dist/src/password-field/index.d.ts.map +1 -0
  334. package/dist/src/password-field/index.js +1 -0
  335. package/dist/src/{passwordField/passwordField.d.ts → password-field/password-field.d.ts} +1 -1
  336. package/dist/src/password-field/password-field.d.ts.map +1 -0
  337. package/dist/src/{passwordField/passwordField.js → password-field/password-field.js} +4 -5
  338. package/dist/src/places/index.d.ts.map +1 -1
  339. package/dist/src/places/places.d.ts +3 -4
  340. package/dist/src/places/places.d.ts.map +1 -1
  341. package/dist/src/places/places.js +8 -2
  342. package/dist/src/props-list/index.d.ts +3 -0
  343. package/dist/src/props-list/index.d.ts.map +1 -0
  344. package/dist/src/props-list/index.js +1 -0
  345. package/dist/src/{propsList/propsList.d.ts → props-list/props-list.d.ts} +2 -2
  346. package/dist/src/props-list/props-list.d.ts.map +1 -0
  347. package/dist/src/{propsList/propsList.js → props-list/props-list.js} +2 -2
  348. package/dist/src/prose/index.d.ts.map +1 -1
  349. package/dist/src/prose/prose.d.ts.map +1 -1
  350. package/dist/src/query-chip/index.d.ts +3 -0
  351. package/dist/src/query-chip/index.d.ts.map +1 -0
  352. package/dist/src/query-chip/index.js +1 -0
  353. package/dist/src/{queryChip/queryChip.d.ts → query-chip/query-chip.d.ts} +1 -1
  354. package/dist/src/query-chip/query-chip.d.ts.map +1 -0
  355. package/dist/src/{queryChip/queryChip.js → query-chip/query-chip.js} +7 -4
  356. package/dist/src/{radioChoices → radio-choices}/index.d.ts +2 -2
  357. package/dist/src/radio-choices/index.d.ts.map +1 -0
  358. package/dist/src/{radioChoices → radio-choices}/index.js +1 -1
  359. package/dist/src/{radioChoices/radioChoices.d.ts → radio-choices/radio-choices.d.ts} +3 -3
  360. package/dist/src/radio-choices/radio-choices.d.ts.map +1 -0
  361. package/dist/src/{radioChoices/radioChoices.js → radio-choices/radio-choices.js} +25 -24
  362. package/dist/src/rail/index.d.ts.map +1 -1
  363. package/dist/src/rail/rail.d.ts +16 -32
  364. package/dist/src/rail/rail.d.ts.map +1 -1
  365. package/dist/src/rail/rail.js +97 -65
  366. package/dist/src/reel/index.d.ts +1 -1
  367. package/dist/src/reel/index.d.ts.map +1 -1
  368. package/dist/src/reel/layout.d.ts +12 -54
  369. package/dist/src/reel/layout.d.ts.map +1 -1
  370. package/dist/src/reel/layout.js +120 -145
  371. package/dist/src/reel/reel.d.ts +35 -34
  372. package/dist/src/reel/reel.d.ts.map +1 -1
  373. package/dist/src/reel/reel.js +253 -233
  374. package/dist/src/remote/index.d.ts.map +1 -1
  375. package/dist/src/remote/remote.d.ts +2 -2
  376. package/dist/src/remote/remote.d.ts.map +1 -1
  377. package/dist/src/remote/remote.js +6 -2
  378. package/dist/src/rows/index.d.ts.map +1 -1
  379. package/dist/src/rows/rows.d.ts +2 -2
  380. package/dist/src/rows/rows.d.ts.map +1 -1
  381. package/dist/src/rows/rows.js +16 -7
  382. package/dist/src/scheme/index.d.ts +1 -1
  383. package/dist/src/scheme/index.d.ts.map +1 -1
  384. package/dist/src/scheme/index.js +1 -1
  385. package/dist/src/scheme/{schemeSwitch.d.ts → scheme-switch.d.ts} +2 -2
  386. package/dist/src/scheme/scheme-switch.d.ts.map +1 -0
  387. package/dist/src/scheme/{schemeSwitch.js → scheme-switch.js} +33 -38
  388. package/dist/src/scheme/scheme.d.ts +0 -2
  389. package/dist/src/scheme/scheme.d.ts.map +1 -1
  390. package/dist/src/scheme/scheme.js +0 -2
  391. package/dist/src/secret/index.d.ts.map +1 -1
  392. package/dist/src/secret/secret.d.ts.map +1 -1
  393. package/dist/src/segmented/index.d.ts.map +1 -1
  394. package/dist/src/segmented/segmented.d.ts.map +1 -1
  395. package/dist/src/segmented/segmented.js +14 -3
  396. package/dist/src/select-all/index.d.ts +3 -0
  397. package/dist/src/select-all/index.d.ts.map +1 -0
  398. package/dist/src/select-all/index.js +1 -0
  399. package/dist/src/{selectAll/selectAll.d.ts → select-all/select-all.d.ts} +1 -1
  400. package/dist/src/select-all/select-all.d.ts.map +1 -0
  401. package/dist/src/{selectAll/selectAll.js → select-all/select-all.js} +2 -2
  402. package/dist/src/select-field/index.d.ts +3 -0
  403. package/dist/src/select-field/index.d.ts.map +1 -0
  404. package/dist/src/select-field/index.js +1 -0
  405. package/dist/src/{selectField/selectField.d.ts → select-field/select-field.d.ts} +2 -2
  406. package/dist/src/select-field/select-field.d.ts.map +1 -0
  407. package/dist/src/{selectField/selectField.js → select-field/select-field.js} +10 -7
  408. package/dist/src/sheet/index.d.ts.map +1 -1
  409. package/dist/src/sheet/sheet.d.ts.map +1 -1
  410. package/dist/src/sheet/sheet.js +4 -1
  411. package/dist/src/skip-link/index.d.ts +2 -0
  412. package/dist/src/skip-link/index.d.ts.map +1 -0
  413. package/dist/src/skip-link/index.js +1 -0
  414. package/dist/src/{skipLink/skipLink.d.ts → skip-link/skip-link.d.ts} +1 -3
  415. package/dist/src/skip-link/skip-link.d.ts.map +1 -0
  416. package/dist/src/{skipLink/skipLink.js → skip-link/skip-link.js} +7 -11
  417. package/dist/src/slot/slot.d.ts +1 -4
  418. package/dist/src/slot/slot.d.ts.map +1 -1
  419. package/dist/src/slot/slot.js +3 -3
  420. package/dist/src/sortable/index.d.ts.map +1 -1
  421. package/dist/src/sortable/sortable.d.ts +44 -44
  422. package/dist/src/sortable/sortable.d.ts.map +1 -1
  423. package/dist/src/sortable/sortable.js +60 -93
  424. package/dist/src/stack/index.d.ts.map +1 -1
  425. package/dist/src/stack/stack.d.ts.map +1 -1
  426. package/dist/src/stack/stack.js +0 -2
  427. package/dist/src/stage/index.d.ts.map +1 -1
  428. package/dist/src/stage/stage.d.ts +1 -1
  429. package/dist/src/stage/stage.d.ts.map +1 -1
  430. package/dist/src/stage/stage.js +4 -1
  431. package/dist/src/stat/index.d.ts.map +1 -1
  432. package/dist/src/stat/stat.d.ts +1 -1
  433. package/dist/src/stat/stat.d.ts.map +1 -1
  434. package/dist/src/stat/stat.js +17 -8
  435. package/dist/src/status-bar/index.d.ts +4 -0
  436. package/dist/src/status-bar/index.d.ts.map +1 -0
  437. package/dist/src/status-bar/index.js +2 -0
  438. package/dist/src/{statusBar/statusBar.d.ts → status-bar/status-bar.d.ts} +4 -4
  439. package/dist/src/status-bar/status-bar.d.ts.map +1 -0
  440. package/dist/src/{statusBar/statusBar.js → status-bar/status-bar.js} +5 -6
  441. package/dist/src/subscription/{prefixKeys.d.ts → prefix-keys.d.ts} +1 -2
  442. package/dist/src/subscription/prefix-keys.d.ts.map +1 -0
  443. package/dist/src/subscription/{prefixKeys.js → prefix-keys.js} +2 -5
  444. package/dist/src/table/index.d.ts.map +1 -1
  445. package/dist/src/table/table.d.ts +1 -1
  446. package/dist/src/table/table.d.ts.map +1 -1
  447. package/dist/src/table/table.js +19 -7
  448. package/dist/src/tabs/index.d.ts.map +1 -1
  449. package/dist/src/tabs/tabs.d.ts +4 -4
  450. package/dist/src/tabs/tabs.d.ts.map +1 -1
  451. package/dist/src/tabs/tabs.js +1 -6
  452. package/dist/src/tag/index.d.ts.map +1 -1
  453. package/dist/src/tag/tag.d.ts.map +1 -1
  454. package/dist/src/tag/tag.js +4 -1
  455. package/dist/src/text-button/index.d.ts +3 -0
  456. package/dist/src/text-button/index.d.ts.map +1 -0
  457. package/dist/src/text-button/index.js +1 -0
  458. package/dist/src/{textButton/textButton.d.ts → text-button/text-button.d.ts} +1 -1
  459. package/dist/src/text-button/text-button.d.ts.map +1 -0
  460. package/dist/src/{textButton/textButton.js → text-button/text-button.js} +2 -2
  461. package/dist/src/textarea-field/index.d.ts +3 -0
  462. package/dist/src/textarea-field/index.d.ts.map +1 -0
  463. package/dist/src/textarea-field/index.js +1 -0
  464. package/dist/src/{textareaField/textareaField.d.ts → textarea-field/textarea-field.d.ts} +1 -1
  465. package/dist/src/textarea-field/textarea-field.d.ts.map +1 -0
  466. package/dist/src/{textareaField/textareaField.js → textarea-field/textarea-field.js} +2 -2
  467. package/dist/src/time/index.d.ts.map +1 -1
  468. package/dist/src/time/time.d.ts.map +1 -1
  469. package/dist/src/time/time.js +16 -9
  470. package/dist/src/tips/index.d.ts.map +1 -1
  471. package/dist/src/tips/tips.d.ts +7 -18
  472. package/dist/src/tips/tips.d.ts.map +1 -1
  473. package/dist/src/tips/tips.js +67 -65
  474. package/dist/src/toast/index.d.ts.map +1 -1
  475. package/dist/src/toast/stack.d.ts +1 -8
  476. package/dist/src/toast/stack.d.ts.map +1 -1
  477. package/dist/src/toast/stack.js +5 -18
  478. package/dist/src/toast/toast.d.ts +3 -5
  479. package/dist/src/toast/toast.d.ts.map +1 -1
  480. package/dist/src/toast/toast.js +42 -39
  481. package/dist/src/toc/index.d.ts.map +1 -1
  482. package/dist/src/toc/toc.d.ts +3 -3
  483. package/dist/src/toc/toc.d.ts.map +1 -1
  484. package/dist/src/toc/toc.js +10 -7
  485. package/dist/src/toolbar/index.d.ts.map +1 -1
  486. package/dist/src/toolbar/toolbar.d.ts +1 -1
  487. package/dist/src/toolbar/toolbar.d.ts.map +1 -1
  488. package/dist/src/toolbar/toolbar.js +27 -24
  489. package/dist/src/{topBar/barHeight.d.ts → top-bar/bar-height.d.ts} +1 -2
  490. package/dist/src/top-bar/bar-height.d.ts.map +1 -0
  491. package/dist/src/{topBar/barHeight.js → top-bar/bar-height.js} +20 -13
  492. package/dist/src/top-bar/index.d.ts +4 -0
  493. package/dist/src/top-bar/index.d.ts.map +1 -0
  494. package/dist/src/top-bar/index.js +2 -0
  495. package/dist/src/{topBar/topBar.d.ts → top-bar/top-bar.d.ts} +3 -3
  496. package/dist/src/top-bar/top-bar.d.ts.map +1 -0
  497. package/dist/src/{topBar/topBar.js → top-bar/top-bar.js} +2 -2
  498. package/dist/src/video-frame/index.d.ts +3 -0
  499. package/dist/src/video-frame/index.d.ts.map +1 -0
  500. package/dist/src/video-frame/index.js +1 -0
  501. package/dist/src/{videoFrame/videoFrame.d.ts → video-frame/video-frame.d.ts} +1 -1
  502. package/dist/src/video-frame/video-frame.d.ts.map +1 -0
  503. package/dist/src/{videoFrame/videoFrame.js → video-frame/video-frame.js} +11 -7
  504. package/dist/src/wall/index.d.ts.map +1 -1
  505. package/dist/src/wall/wall.d.ts.map +1 -1
  506. package/dist/src/window/index.d.ts.map +1 -1
  507. package/dist/src/window/window.d.ts +2 -2
  508. package/dist/src/window/window.d.ts.map +1 -1
  509. package/dist/src/window/window.js +4 -2
  510. package/dist/src/wordmark/index.d.ts.map +1 -1
  511. package/dist/src/wordmark/wordmark.d.ts.map +1 -1
  512. package/dist/src/wrap/index.d.ts.map +1 -1
  513. package/dist/src/wrap/wrap.d.ts.map +1 -1
  514. package/package.json +6 -6
  515. package/src/adapters/diagram.ts +278 -0
  516. package/src/adapters/mermaid.ts +13 -273
  517. package/src/announcer/announcer.ts +54 -35
  518. package/src/attributes/attributes.ts +3 -1
  519. package/src/{audioFrame/audioFrame.ts → audio-frame/audio-frame.ts} +4 -6
  520. package/src/audio-frame/index.ts +3 -0
  521. package/src/banner/banner.ts +5 -4
  522. package/src/banner/index.ts +1 -0
  523. package/src/{barChart/barChart.ts → bar-chart/bar-chart.ts} +81 -43
  524. package/src/bar-chart/index.ts +3 -0
  525. package/src/bench/bench.ts +5 -4
  526. package/src/bench/index.ts +1 -0
  527. package/src/board/board.ts +338 -243
  528. package/src/board/index.ts +8 -1
  529. package/src/button/button.ts +24 -16
  530. package/src/button/index.ts +8 -1
  531. package/src/card/card.ts +23 -21
  532. package/src/card/index.ts +1 -0
  533. package/src/chart-table/chart-table.ts +87 -0
  534. package/src/chip/chip.ts +13 -9
  535. package/src/chip/index.ts +1 -0
  536. package/src/choice/choice.ts +13 -7
  537. package/src/choice/index.ts +1 -0
  538. package/src/choices/choices.ts +4 -3
  539. package/src/choices/index.ts +1 -0
  540. package/src/{codeEditor/codeEditor.ts → code-editor/code-editor.ts} +5 -4
  541. package/src/code-editor/index.ts +3 -0
  542. package/src/{codeSurface/codeSurface.ts → code-surface/code-surface.ts} +11 -5
  543. package/src/code-surface/index.ts +3 -0
  544. package/src/{commandPalette/commandPalette.ts → command-palette/command-palette.ts} +470 -295
  545. package/src/{commandPalette → command-palette}/index.ts +12 -2
  546. package/src/{commandPalette → command-palette}/keys.ts +44 -43
  547. package/src/{commandPalette → command-palette}/match.ts +42 -30
  548. package/src/{commandPalette → command-palette}/message.ts +13 -20
  549. package/src/{confirmDialog/confirmDialog.ts → confirm-dialog/confirm-dialog.ts} +51 -46
  550. package/src/{confirmDialog → confirm-dialog}/index.ts +3 -2
  551. package/src/{contextMenu/contextMenu.ts → context-menu/context-menu.ts} +71 -70
  552. package/src/{contextMenu → context-menu}/index.ts +4 -2
  553. package/src/{copyButton/copyButton.ts → copy-button/copy-button.ts} +51 -54
  554. package/src/{copyButton → copy-button}/index.ts +3 -2
  555. package/src/crumbs/crumbs.ts +7 -6
  556. package/src/crumbs/index.ts +1 -0
  557. package/src/deck/deck.ts +4 -3
  558. package/src/deck/index.ts +1 -0
  559. package/src/dialog/dialog.ts +135 -113
  560. package/src/dialog/fold.ts +44 -25
  561. package/src/dialog/index.ts +9 -1
  562. package/src/disclosure/disclosure.ts +14 -8
  563. package/src/disclosure/index.ts +1 -0
  564. package/src/dom/html-element.ts +10 -0
  565. package/src/drag/drag.ts +102 -119
  566. package/src/{dropZone/dropZone.ts → drop-zone/drop-zone.ts} +43 -43
  567. package/src/drop-zone/index.ts +11 -0
  568. package/src/{editableTitle/editableTitle.ts → editable-title/editable-title.ts} +29 -32
  569. package/src/{editableTitle → editable-title}/index.ts +4 -2
  570. package/src/{emptyState/emptyState.ts → empty-state/empty-state.ts} +9 -5
  571. package/src/empty-state/index.ts +3 -0
  572. package/src/{errorSummary/errorSummary.ts → error-summary/error-summary.ts} +16 -7
  573. package/src/error-summary/index.ts +3 -0
  574. package/src/field/field.ts +38 -28
  575. package/src/field/index.ts +1 -0
  576. package/src/{fieldGrid/fieldGrid.ts → field-grid/field-grid.ts} +4 -3
  577. package/src/field-grid/index.ts +3 -0
  578. package/src/fields/fields.ts +9 -5
  579. package/src/fields/index.ts +1 -0
  580. package/src/fieldset/fieldset.ts +6 -5
  581. package/src/fieldset/index.ts +1 -0
  582. package/src/{fileTree/fileTree.ts → file-tree/file-tree.ts} +241 -166
  583. package/src/file-tree/index.ts +12 -0
  584. package/src/{filterChip/filterChip.ts → filter-chip/filter-chip.ts} +32 -13
  585. package/src/filter-chip/index.ts +3 -0
  586. package/src/{filterStrip/filterStrip.ts → filter-strip/filter-strip.ts} +4 -3
  587. package/src/filter-strip/index.ts +3 -0
  588. package/src/{flashWord/flashWord.ts → flash-word/flash-word.ts} +9 -7
  589. package/src/flash-word/index.ts +3 -0
  590. package/src/focus/focus.ts +5 -5
  591. package/src/format/format.ts +37 -31
  592. package/src/format/index.ts +1 -0
  593. package/src/glyph/glyph.ts +7 -6
  594. package/src/glyph/glyphs.ts +2601 -2611
  595. package/src/glyph/index.ts +3 -0
  596. package/src/group/group.ts +4 -3
  597. package/src/group/index.ts +1 -0
  598. package/src/history/history.ts +18 -10
  599. package/src/history/index.ts +1 -0
  600. package/src/{iconButton/iconButton.ts → icon-button/icon-button.ts} +13 -7
  601. package/src/icon-button/index.ts +3 -0
  602. package/src/identity/identity.ts +7 -6
  603. package/src/identity/index.ts +1 -0
  604. package/src/{imageFrame/imageFrame.ts → image-frame/image-frame.ts} +43 -25
  605. package/src/image-frame/index.ts +3 -0
  606. package/src/index.ts +139 -41
  607. package/src/{inlineInput → inline-input}/index.ts +3 -2
  608. package/src/{inlineInput/inlineInput.ts → inline-input/inline-input.ts} +97 -88
  609. package/src/{keyHelp → key-help}/index.ts +3 -2
  610. package/src/{keyHelp/keyHelp.ts → key-help/key-help.ts} +74 -62
  611. package/src/key-hint/index.ts +5 -0
  612. package/src/{keyHint/keyHint.ts → key-hint/key-hint.ts} +10 -5
  613. package/src/{keyHint/keyLabel.ts → key-hint/key-label.ts} +43 -22
  614. package/src/keymap/index.ts +1 -0
  615. package/src/keymap/keymap.ts +23 -9
  616. package/src/keys/keys.ts +0 -2
  617. package/src/line-chart/index.ts +3 -0
  618. package/src/{lineChart/lineChart.ts → line-chart/line-chart.ts} +71 -49
  619. package/src/line-diff/diff.ts +196 -0
  620. package/src/line-diff/index.ts +7 -0
  621. package/src/{lineDiff/lineDiff.ts → line-diff/line-diff.ts} +45 -23
  622. package/src/{lineDiff → line-diff}/patch.ts +104 -76
  623. package/src/link-button/index.ts +3 -0
  624. package/src/{linkButton/linkButton.ts → link-button/link-button.ts} +7 -5
  625. package/src/link-state/index.ts +3 -0
  626. package/src/{linkState/linkState.ts → link-state/link-state.ts} +20 -9
  627. package/src/live-region/index.ts +3 -0
  628. package/src/{liveRegion/liveRegion.ts → live-region/live-region.ts} +15 -11
  629. package/src/loading/index.ts +1 -0
  630. package/src/loading/loading.ts +10 -5
  631. package/src/mark/index.ts +1 -0
  632. package/src/mark/mark.ts +17 -15
  633. package/src/media/index.ts +1 -0
  634. package/src/media/media.ts +255 -157
  635. package/src/menu/index.ts +4 -0
  636. package/src/menu/item.ts +10 -11
  637. package/src/menu/menu.ts +110 -97
  638. package/src/menu/slip.ts +129 -92
  639. package/src/meter/index.ts +1 -0
  640. package/src/meter/meter.ts +52 -33
  641. package/src/monogram/index.ts +1 -0
  642. package/src/monogram/monogram.ts +27 -19
  643. package/src/nav-strip/index.ts +3 -0
  644. package/src/{navStrip/navStrip.ts → nav-strip/nav-strip.ts} +21 -13
  645. package/src/notice/index.ts +1 -0
  646. package/src/notice/notice.ts +24 -16
  647. package/src/outcome/index.ts +1 -0
  648. package/src/outcome/outcome.ts +14 -6
  649. package/src/page-head/index.ts +3 -0
  650. package/src/{pageHead/pageHead.ts → page-head/page-head.ts} +6 -5
  651. package/src/panel/index.ts +1 -0
  652. package/src/panel/panel.ts +6 -6
  653. package/src/password-field/index.ts +3 -0
  654. package/src/{passwordField/passwordField.ts → password-field/password-field.ts} +13 -13
  655. package/src/pixel-paper.css +26 -508
  656. package/src/places/index.ts +1 -0
  657. package/src/places/places.ts +22 -11
  658. package/src/props-list/index.ts +3 -0
  659. package/src/{propsList/propsList.ts → props-list/props-list.ts} +6 -6
  660. package/src/prose/index.ts +1 -0
  661. package/src/prose/prose.ts +4 -4
  662. package/src/query-chip/index.ts +3 -0
  663. package/src/{queryChip/queryChip.ts → query-chip/query-chip.ts} +18 -7
  664. package/src/{radioChoices → radio-choices}/index.ts +3 -2
  665. package/src/{radioChoices/radioChoices.ts → radio-choices/radio-choices.ts} +79 -65
  666. package/src/rail/index.ts +1 -0
  667. package/src/rail/rail.ts +291 -225
  668. package/src/reel/index.ts +8 -1
  669. package/src/reel/layout.ts +393 -238
  670. package/src/reel/reel.ts +750 -452
  671. package/src/remote/index.ts +1 -0
  672. package/src/remote/remote.ts +18 -11
  673. package/src/rows/index.ts +1 -0
  674. package/src/rows/rows.ts +83 -47
  675. package/src/scheme/index.ts +3 -1
  676. package/src/scheme/{schemeSwitch.ts → scheme-switch.ts} +24 -35
  677. package/src/scheme/scheme.ts +4 -4
  678. package/src/secret/index.ts +1 -0
  679. package/src/secret/secret.ts +5 -4
  680. package/src/segmented/index.ts +1 -0
  681. package/src/segmented/segmented.ts +22 -10
  682. package/src/select-all/index.ts +3 -0
  683. package/src/{selectAll/selectAll.ts → select-all/select-all.ts} +9 -8
  684. package/src/{selectField → select-field}/index.ts +3 -2
  685. package/src/{selectField/selectField.ts → select-field/select-field.ts} +25 -11
  686. package/src/sheet/index.ts +1 -0
  687. package/src/sheet/sheet.ts +9 -5
  688. package/src/skip-link/index.ts +1 -0
  689. package/src/{skipLink/skipLink.ts → skip-link/skip-link.ts} +9 -15
  690. package/src/slot/slot.ts +5 -6
  691. package/src/sortable/index.ts +1 -0
  692. package/src/sortable/sortable.ts +287 -206
  693. package/src/stack/index.ts +1 -0
  694. package/src/stack/stack.ts +6 -7
  695. package/src/stage/index.ts +1 -0
  696. package/src/stage/stage.ts +12 -8
  697. package/src/stat/index.ts +1 -0
  698. package/src/stat/stat.ts +39 -20
  699. package/src/status-bar/index.ts +5 -0
  700. package/src/{statusBar/statusBar.ts → status-bar/status-bar.ts} +18 -11
  701. package/src/subscription/{prefixKeys.ts → prefix-keys.ts} +5 -6
  702. package/src/table/index.ts +1 -0
  703. package/src/table/table.ts +49 -24
  704. package/src/tabs/index.ts +1 -0
  705. package/src/tabs/tabs.ts +58 -60
  706. package/src/tag/index.ts +1 -0
  707. package/src/tag/tag.ts +14 -7
  708. package/src/text-button/index.ts +3 -0
  709. package/src/{textButton/textButton.ts → text-button/text-button.ts} +7 -5
  710. package/src/textarea-field/index.ts +3 -0
  711. package/src/{textareaField/textareaField.ts → textarea-field/textarea-field.ts} +15 -7
  712. package/src/time/index.ts +1 -0
  713. package/src/time/time.ts +58 -25
  714. package/src/tips/index.ts +1 -0
  715. package/src/tips/tips.ts +183 -127
  716. package/src/toast/index.ts +3 -0
  717. package/src/toast/stack.ts +22 -23
  718. package/src/toast/toast.ts +168 -100
  719. package/src/toc/index.ts +1 -0
  720. package/src/toc/toc.ts +42 -27
  721. package/src/tokens.css +7 -24
  722. package/src/toolbar/index.ts +1 -0
  723. package/src/toolbar/toolbar.ts +78 -40
  724. package/src/{topBar/barHeight.ts → top-bar/bar-height.ts} +26 -12
  725. package/src/top-bar/index.ts +5 -0
  726. package/src/{topBar/topBar.ts → top-bar/top-bar.ts} +13 -7
  727. package/src/video-frame/index.ts +3 -0
  728. package/src/{videoFrame/videoFrame.ts → video-frame/video-frame.ts} +31 -18
  729. package/src/wall/index.ts +1 -0
  730. package/src/wall/wall.ts +13 -10
  731. package/src/window/index.ts +1 -0
  732. package/src/window/window.ts +15 -9
  733. package/src/wordmark/index.ts +1 -0
  734. package/src/wordmark/wordmark.ts +4 -3
  735. package/src/wrap/index.ts +1 -0
  736. package/src/wrap/wrap.ts +4 -3
  737. package/dist/src/audioFrame/audioFrame.d.ts.map +0 -1
  738. package/dist/src/audioFrame/index.d.ts +0 -3
  739. package/dist/src/audioFrame/index.d.ts.map +0 -1
  740. package/dist/src/audioFrame/index.js +0 -1
  741. package/dist/src/barChart/barChart.d.ts.map +0 -1
  742. package/dist/src/barChart/index.d.ts +0 -3
  743. package/dist/src/barChart/index.d.ts.map +0 -1
  744. package/dist/src/barChart/index.js +0 -1
  745. package/dist/src/chartTable/chartTable.d.ts.map +0 -1
  746. package/dist/src/codeEditor/codeEditor.d.ts.map +0 -1
  747. package/dist/src/codeEditor/index.d.ts +0 -3
  748. package/dist/src/codeEditor/index.d.ts.map +0 -1
  749. package/dist/src/codeEditor/index.js +0 -1
  750. package/dist/src/codeSurface/codeSurface.d.ts.map +0 -1
  751. package/dist/src/codeSurface/index.d.ts +0 -3
  752. package/dist/src/codeSurface/index.d.ts.map +0 -1
  753. package/dist/src/codeSurface/index.js +0 -1
  754. package/dist/src/commandPalette/commandPalette.d.ts.map +0 -1
  755. package/dist/src/commandPalette/commandPalette.js +0 -611
  756. package/dist/src/commandPalette/index.d.ts.map +0 -1
  757. package/dist/src/commandPalette/keys.d.ts.map +0 -1
  758. package/dist/src/commandPalette/keys.js +0 -102
  759. package/dist/src/commandPalette/match.d.ts.map +0 -1
  760. package/dist/src/commandPalette/message.d.ts.map +0 -1
  761. package/dist/src/confirmDialog/confirmDialog.d.ts.map +0 -1
  762. package/dist/src/confirmDialog/index.d.ts +0 -3
  763. package/dist/src/confirmDialog/index.d.ts.map +0 -1
  764. package/dist/src/contextMenu/contextMenu.d.ts.map +0 -1
  765. package/dist/src/contextMenu/index.d.ts.map +0 -1
  766. package/dist/src/copyButton/copyButton.d.ts.map +0 -1
  767. package/dist/src/copyButton/index.d.ts +0 -3
  768. package/dist/src/copyButton/index.d.ts.map +0 -1
  769. package/dist/src/copyButton/index.js +0 -1
  770. package/dist/src/dropZone/dropZone.d.ts.map +0 -1
  771. package/dist/src/dropZone/index.d.ts +0 -3
  772. package/dist/src/dropZone/index.d.ts.map +0 -1
  773. package/dist/src/dropZone/index.js +0 -1
  774. package/dist/src/editableTitle/editableTitle.d.ts.map +0 -1
  775. package/dist/src/editableTitle/index.d.ts +0 -4
  776. package/dist/src/editableTitle/index.d.ts.map +0 -1
  777. package/dist/src/emptyState/emptyState.d.ts.map +0 -1
  778. package/dist/src/emptyState/index.d.ts +0 -3
  779. package/dist/src/emptyState/index.d.ts.map +0 -1
  780. package/dist/src/emptyState/index.js +0 -1
  781. package/dist/src/errorSummary/errorSummary.d.ts.map +0 -1
  782. package/dist/src/errorSummary/index.d.ts +0 -3
  783. package/dist/src/errorSummary/index.d.ts.map +0 -1
  784. package/dist/src/errorSummary/index.js +0 -1
  785. package/dist/src/fieldGrid/fieldGrid.d.ts.map +0 -1
  786. package/dist/src/fieldGrid/index.d.ts +0 -3
  787. package/dist/src/fieldGrid/index.d.ts.map +0 -1
  788. package/dist/src/fieldGrid/index.js +0 -1
  789. package/dist/src/fileTree/fileTree.d.ts.map +0 -1
  790. package/dist/src/fileTree/fileTree.js +0 -230
  791. package/dist/src/fileTree/index.d.ts +0 -3
  792. package/dist/src/fileTree/index.d.ts.map +0 -1
  793. package/dist/src/filterChip/filterChip.d.ts.map +0 -1
  794. package/dist/src/filterChip/index.d.ts +0 -3
  795. package/dist/src/filterChip/index.d.ts.map +0 -1
  796. package/dist/src/filterChip/index.js +0 -1
  797. package/dist/src/filterStrip/filterStrip.d.ts.map +0 -1
  798. package/dist/src/filterStrip/index.d.ts +0 -3
  799. package/dist/src/filterStrip/index.d.ts.map +0 -1
  800. package/dist/src/filterStrip/index.js +0 -1
  801. package/dist/src/flashWord/flashWord.d.ts.map +0 -1
  802. package/dist/src/flashWord/index.d.ts +0 -3
  803. package/dist/src/flashWord/index.d.ts.map +0 -1
  804. package/dist/src/flashWord/index.js +0 -1
  805. package/dist/src/iconButton/iconButton.d.ts.map +0 -1
  806. package/dist/src/iconButton/index.d.ts +0 -3
  807. package/dist/src/iconButton/index.d.ts.map +0 -1
  808. package/dist/src/iconButton/index.js +0 -1
  809. package/dist/src/imageFrame/imageFrame.d.ts.map +0 -1
  810. package/dist/src/imageFrame/index.d.ts +0 -3
  811. package/dist/src/imageFrame/index.d.ts.map +0 -1
  812. package/dist/src/imageFrame/index.js +0 -1
  813. package/dist/src/inlineInput/index.d.ts +0 -3
  814. package/dist/src/inlineInput/index.d.ts.map +0 -1
  815. package/dist/src/inlineInput/inlineInput.d.ts.map +0 -1
  816. package/dist/src/keyHelp/index.d.ts +0 -3
  817. package/dist/src/keyHelp/index.d.ts.map +0 -1
  818. package/dist/src/keyHelp/keyHelp.d.ts.map +0 -1
  819. package/dist/src/keyHint/index.d.ts +0 -4
  820. package/dist/src/keyHint/index.d.ts.map +0 -1
  821. package/dist/src/keyHint/index.js +0 -2
  822. package/dist/src/keyHint/keyHint.d.ts.map +0 -1
  823. package/dist/src/keyHint/keyLabel.d.ts.map +0 -1
  824. package/dist/src/lineChart/index.d.ts +0 -3
  825. package/dist/src/lineChart/index.d.ts.map +0 -1
  826. package/dist/src/lineChart/index.js +0 -1
  827. package/dist/src/lineChart/lineChart.d.ts.map +0 -1
  828. package/dist/src/lineDiff/diff.d.ts +0 -41
  829. package/dist/src/lineDiff/diff.d.ts.map +0 -1
  830. package/dist/src/lineDiff/diff.js +0 -92
  831. package/dist/src/lineDiff/index.d.ts +0 -5
  832. package/dist/src/lineDiff/index.d.ts.map +0 -1
  833. package/dist/src/lineDiff/index.js +0 -2
  834. package/dist/src/lineDiff/lineDiff.d.ts.map +0 -1
  835. package/dist/src/lineDiff/patch.d.ts.map +0 -1
  836. package/dist/src/linkButton/index.d.ts +0 -3
  837. package/dist/src/linkButton/index.d.ts.map +0 -1
  838. package/dist/src/linkButton/index.js +0 -1
  839. package/dist/src/linkButton/linkButton.d.ts.map +0 -1
  840. package/dist/src/linkState/index.d.ts +0 -3
  841. package/dist/src/linkState/index.d.ts.map +0 -1
  842. package/dist/src/linkState/index.js +0 -1
  843. package/dist/src/linkState/linkState.d.ts.map +0 -1
  844. package/dist/src/linkState/linkState.js +0 -14
  845. package/dist/src/liveRegion/index.d.ts +0 -3
  846. package/dist/src/liveRegion/index.d.ts.map +0 -1
  847. package/dist/src/liveRegion/index.js +0 -1
  848. package/dist/src/liveRegion/liveRegion.d.ts.map +0 -1
  849. package/dist/src/navStrip/index.d.ts +0 -3
  850. package/dist/src/navStrip/index.d.ts.map +0 -1
  851. package/dist/src/navStrip/index.js +0 -1
  852. package/dist/src/navStrip/navStrip.d.ts.map +0 -1
  853. package/dist/src/navStrip/navStrip.js +0 -27
  854. package/dist/src/pageHead/index.d.ts +0 -3
  855. package/dist/src/pageHead/index.d.ts.map +0 -1
  856. package/dist/src/pageHead/index.js +0 -1
  857. package/dist/src/pageHead/pageHead.d.ts.map +0 -1
  858. package/dist/src/passwordField/index.d.ts +0 -3
  859. package/dist/src/passwordField/index.d.ts.map +0 -1
  860. package/dist/src/passwordField/index.js +0 -1
  861. package/dist/src/passwordField/passwordField.d.ts.map +0 -1
  862. package/dist/src/propsList/index.d.ts +0 -3
  863. package/dist/src/propsList/index.d.ts.map +0 -1
  864. package/dist/src/propsList/index.js +0 -1
  865. package/dist/src/propsList/propsList.d.ts.map +0 -1
  866. package/dist/src/queryChip/index.d.ts +0 -3
  867. package/dist/src/queryChip/index.d.ts.map +0 -1
  868. package/dist/src/queryChip/index.js +0 -1
  869. package/dist/src/queryChip/queryChip.d.ts.map +0 -1
  870. package/dist/src/radioChoices/index.d.ts.map +0 -1
  871. package/dist/src/radioChoices/radioChoices.d.ts.map +0 -1
  872. package/dist/src/scheme/schemeSwitch.d.ts.map +0 -1
  873. package/dist/src/selectAll/index.d.ts +0 -3
  874. package/dist/src/selectAll/index.d.ts.map +0 -1
  875. package/dist/src/selectAll/index.js +0 -1
  876. package/dist/src/selectAll/selectAll.d.ts.map +0 -1
  877. package/dist/src/selectField/index.d.ts +0 -3
  878. package/dist/src/selectField/index.d.ts.map +0 -1
  879. package/dist/src/selectField/index.js +0 -1
  880. package/dist/src/selectField/selectField.d.ts.map +0 -1
  881. package/dist/src/skipLink/index.d.ts +0 -2
  882. package/dist/src/skipLink/index.d.ts.map +0 -1
  883. package/dist/src/skipLink/index.js +0 -1
  884. package/dist/src/skipLink/skipLink.d.ts.map +0 -1
  885. package/dist/src/statusBar/index.d.ts +0 -4
  886. package/dist/src/statusBar/index.d.ts.map +0 -1
  887. package/dist/src/statusBar/index.js +0 -2
  888. package/dist/src/statusBar/statusBar.d.ts.map +0 -1
  889. package/dist/src/subscription/prefixKeys.d.ts.map +0 -1
  890. package/dist/src/textButton/index.d.ts +0 -3
  891. package/dist/src/textButton/index.d.ts.map +0 -1
  892. package/dist/src/textButton/index.js +0 -1
  893. package/dist/src/textButton/textButton.d.ts.map +0 -1
  894. package/dist/src/textareaField/index.d.ts +0 -3
  895. package/dist/src/textareaField/index.d.ts.map +0 -1
  896. package/dist/src/textareaField/index.js +0 -1
  897. package/dist/src/textareaField/textareaField.d.ts.map +0 -1
  898. package/dist/src/topBar/barHeight.d.ts.map +0 -1
  899. package/dist/src/topBar/index.d.ts +0 -4
  900. package/dist/src/topBar/index.d.ts.map +0 -1
  901. package/dist/src/topBar/index.js +0 -2
  902. package/dist/src/topBar/topBar.d.ts.map +0 -1
  903. package/dist/src/videoFrame/index.d.ts +0 -3
  904. package/dist/src/videoFrame/index.d.ts.map +0 -1
  905. package/dist/src/videoFrame/index.js +0 -1
  906. package/dist/src/videoFrame/videoFrame.d.ts.map +0 -1
  907. package/src/audioFrame/index.ts +0 -2
  908. package/src/barChart/index.ts +0 -2
  909. package/src/chartTable/chartTable.ts +0 -88
  910. package/src/codeEditor/index.ts +0 -2
  911. package/src/codeSurface/index.ts +0 -2
  912. package/src/dropZone/index.ts +0 -2
  913. package/src/emptyState/index.ts +0 -2
  914. package/src/errorSummary/index.ts +0 -2
  915. package/src/fieldGrid/index.ts +0 -2
  916. package/src/fileTree/index.ts +0 -2
  917. package/src/filterChip/index.ts +0 -2
  918. package/src/filterStrip/index.ts +0 -2
  919. package/src/flashWord/index.ts +0 -2
  920. package/src/iconButton/index.ts +0 -2
  921. package/src/imageFrame/index.ts +0 -2
  922. package/src/keyHint/index.ts +0 -3
  923. package/src/lineChart/index.ts +0 -2
  924. package/src/lineDiff/diff.ts +0 -182
  925. package/src/lineDiff/index.ts +0 -4
  926. package/src/linkButton/index.ts +0 -2
  927. package/src/linkState/index.ts +0 -2
  928. package/src/liveRegion/index.ts +0 -2
  929. package/src/navStrip/index.ts +0 -2
  930. package/src/pageHead/index.ts +0 -2
  931. package/src/passwordField/index.ts +0 -2
  932. package/src/propsList/index.ts +0 -2
  933. package/src/queryChip/index.ts +0 -2
  934. package/src/selectAll/index.ts +0 -2
  935. package/src/skipLink/index.ts +0 -1
  936. package/src/statusBar/index.ts +0 -3
  937. package/src/textButton/index.ts +0 -2
  938. package/src/textareaField/index.ts +0 -2
  939. package/src/topBar/index.ts +0 -3
  940. package/src/videoFrame/index.ts +0 -2
package/src/reel/reel.ts CHANGED
@@ -7,6 +7,7 @@ import {
7
7
  Option,
8
8
  Order,
9
9
  Queue,
10
+ Record,
10
11
  Schema,
11
12
  Stream,
12
13
  String,
@@ -24,6 +25,7 @@ import type * as Update from "foldkit/update";
24
25
 
25
26
  import * as Announcer from "../announcer/announcer.ts";
26
27
  import * as Button from "../button/button.ts";
28
+ import { htmlElement } from "../dom/html-element.ts";
27
29
  import {
28
30
  LEFT_BUTTON,
29
31
  escapeKeys,
@@ -33,17 +35,11 @@ import {
33
35
  splitterAttributes,
34
36
  } from "../drag/drag.ts";
35
37
  import * as Glyph from "../glyph/glyph.ts";
36
- import * as IconButton from "../iconButton/iconButton.ts";
38
+ import * as IconButton from "../icon-button/icon-button.ts";
37
39
  import { isPlain } from "../keys/keys.ts";
38
- import { prefixKeys } from "../subscription/prefixKeys.ts";
39
-
40
+ import { prefixKeys } from "../subscription/prefix-keys.ts";
40
41
  import {
41
- type Column,
42
- type ColumnBox,
43
- type Layout,
44
42
  OutMessage,
45
- type Pane,
46
- type Place,
47
43
  Resize,
48
44
  Splitter,
49
45
  Step,
@@ -71,15 +67,11 @@ import {
71
67
  whereWords,
72
68
  widthWords,
73
69
  } from "./layout.ts";
70
+ import type { Column, ColumnBox, Layout, Pane, Place } from "./layout.ts";
74
71
 
75
- // MODEL
76
-
77
- /** How the keyboard carries what it holds: said on the grip and once it is picked up. */
78
- const KEYBOARD_MOVES = "Arrow keys move it, space drops it, escape or tab puts it back.";
72
+ const KEYBOARD_MOVES =
73
+ "Arrow keys move it, space drops it, escape or tab puts it back.";
79
74
 
80
- /** The words a reel says. `{pane}` is a pane's label, `{subject}` what moves (the held pane,
81
- * or a column a key moves, by its first pane), `{where}` a place and `{column}` a column's
82
- * number. */
83
75
  const COPY = {
84
76
  paneGrip: "Move {pane}",
85
77
  gripHelp: `Press space to pick it up. ${KEYBOARD_MOVES}`,
@@ -98,40 +90,42 @@ const COPY = {
98
90
  gone: "Move cancelled.",
99
91
  };
100
92
 
101
- /** The focused pane, with where it last sat, so focus finds a neighbour when it goes. */
102
- const Focus = Schema.Struct({ paneId: Schema.String, column: Schema.Number, row: Schema.Number });
93
+ const Focus = Schema.Struct({
94
+ paneId: Schema.String,
95
+ column: Schema.Finite,
96
+ row: Schema.Finite,
97
+ });
103
98
 
104
- /** How something is held: by a pointer, pressed at (`pressX`, `pressY`) and now at (`x`,
105
- * `y`), carrying it once it has moved past the threshold; or by the keyboard, on its grip. */
106
99
  const By = defineTaggedUnion({
107
100
  Pointer: {
108
- pointerId: Schema.Number,
109
- pressX: Schema.Number,
110
- pressY: Schema.Number,
111
- x: Schema.Number,
112
- y: Schema.Number,
101
+ pointerId: Schema.Finite,
102
+ pressX: Schema.Finite,
103
+ pressY: Schema.Finite,
104
+ x: Schema.Finite,
105
+ y: Schema.Finite,
113
106
  isCarrying: Schema.Boolean,
114
107
  },
115
108
  Keyboard: {},
116
109
  });
110
+
117
111
  type By = typeof By.Type;
118
112
 
119
- /** The pane held, how, and where it would land: none while a pointer is outside the reel. */
120
113
  const Held = Schema.Struct({
121
114
  paneId: Schema.String,
122
115
  by: By,
123
116
  maybeTarget: Schema.Option(Target),
124
117
  });
118
+
125
119
  type Held = typeof Held.Type;
126
120
 
127
- /** A splitter a pointer drags, pressed at (`pressX`, `pressY`), with the resize it previews. */
128
121
  const Resizing = Schema.Struct({
129
122
  splitter: Splitter,
130
- pointerId: Schema.Number,
131
- pressX: Schema.Number,
132
- pressY: Schema.Number,
123
+ pointerId: Schema.Finite,
124
+ pressX: Schema.Finite,
125
+ pressY: Schema.Finite,
133
126
  maybeResize: Schema.Option(Resize),
134
127
  });
128
+
135
129
  type Resizing = typeof Resizing.Type;
136
130
 
137
131
  /** Schema for a reel: its id, the focused pane, what is held and a splitter being dragged. All
@@ -142,30 +136,31 @@ export const Model = Schema.Struct({
142
136
  maybeHeld: Schema.Option(Held),
143
137
  maybeResizing: Schema.Option(Resizing),
144
138
  });
139
+
145
140
  export type Model = typeof Model.Type;
146
141
 
147
142
  /** How a reel shows its panes: side by side in their columns (`Strip`), or one at a time at
148
143
  * the reel's full size under a tab per pane (`Tabs`). The application holds it and passes it
149
144
  * in; the layout is the same in both. */
150
145
  export const Arrangement = Schema.Literals(["Strip", "Tabs"]);
151
- export type Arrangement = typeof Arrangement.Type;
152
146
 
153
- // MESSAGE
147
+ export type Arrangement = typeof Arrangement.Type;
154
148
 
155
149
  const PointerAt = Schema.Struct({
156
- clientX: Schema.Number,
157
- clientY: Schema.Number,
150
+ clientX: Schema.Finite,
151
+ clientY: Schema.Finite,
158
152
  maybeTarget: Schema.Option(Target),
159
153
  });
154
+
160
155
  type PointerAt = typeof PointerAt.Type;
161
156
 
162
157
  /** Union of all Messages a reel can produce. */
163
158
  export const Message = defineMessageUnion({
164
159
  PressedGrip: {
165
160
  paneId: Schema.String,
166
- pointerId: Schema.Number,
167
- clientX: Schema.Number,
168
- clientY: Schema.Number,
161
+ pointerId: Schema.Finite,
162
+ clientX: Schema.Finite,
163
+ clientY: Schema.Finite,
169
164
  },
170
165
  PressedGripKey: { paneId: Schema.String },
171
166
  MovedPointer: PointerAt.fields,
@@ -180,14 +175,14 @@ export const Message = defineMessageUnion({
180
175
  SteppedTab: { paneId: Schema.String },
181
176
  PressedSplitter: {
182
177
  splitter: Splitter,
183
- pointerId: Schema.Number,
184
- clientX: Schema.Number,
185
- clientY: Schema.Number,
178
+ pointerId: Schema.Finite,
179
+ clientX: Schema.Finite,
180
+ clientY: Schema.Finite,
186
181
  },
187
- MovedSplitter: { share: Schema.Number },
188
- ReleasedSplitter: { share: Schema.Number },
182
+ MovedSplitter: { share: Schema.Finite },
183
+ ReleasedSplitter: { share: Schema.Finite },
189
184
  CancelledSplitter: {},
190
- PressedSplitterKey: { splitter: Splitter, share: Schema.Number },
185
+ PressedSplitterKey: { splitter: Splitter, share: Schema.Finite },
191
186
  CompletedAnnounceReel: {},
192
187
  CompletedFocusPane: {},
193
188
  CompletedFocusTab: {},
@@ -195,9 +190,8 @@ export const Message = defineMessageUnion({
195
190
  CompletedScrollIntoView: {},
196
191
  CompletedSizeLiftedPane: {},
197
192
  });
198
- export type Message = typeof Message.Type;
199
193
 
200
- // INIT
194
+ export type Message = typeof Message.Type;
201
195
 
202
196
  /** Configuration for creating a reel with `init`. The `id` must be unique in the document;
203
197
  * the reel's DOM hooks are scoped by it. */
@@ -211,72 +205,77 @@ export const init = (config: InitConfig): Model => ({
211
205
  maybeResizing: Option.none(),
212
206
  });
213
207
 
214
- // ACCESSORS
215
-
216
208
  const focusedPlace = (model: Model, layout: Layout): Option.Option<Place> =>
217
209
  Option.orElse(
218
210
  Option.flatMap(model.maybeFocus, (focus) =>
219
211
  Option.orElse(placeOf(layout, focus.paneId), () => {
220
- const column = Number.clamp(focus.column, { minimum: 0, maximum: layout.length - 1 });
212
+ const column = Number.clamp(focus.column, {
213
+ minimum: 0,
214
+ maximum: layout.length - 1,
215
+ });
216
+
221
217
  const rows = Option.match(Array.get(layout, column), {
222
218
  onNone: () => 0,
223
219
  onSome: (found) => found.panes.length,
224
220
  });
225
- return placeAt(layout, column, Number.clamp(focus.row, { minimum: 0, maximum: rows - 1 }));
226
- }),
221
+
222
+ return placeAt(
223
+ layout,
224
+ column,
225
+ Number.clamp(focus.row, { minimum: 0, maximum: rows - 1 })
226
+ );
227
+ })
227
228
  ),
228
- () => firstPlace(layout),
229
+ () => firstPlace(layout)
229
230
  );
230
231
 
231
232
  /** The pane focus is on: the one last focused, or, when it has gone from `layout`, the pane
232
233
  * now nearest its place; the first pane before any is focused. None for an empty layout. */
233
- export const focusedPaneId = (model: Model, layout: Layout): Option.Option<string> =>
234
+ export const focusedPaneId = (
235
+ model: Model,
236
+ layout: Layout
237
+ ): Option.Option<string> =>
234
238
  Option.map(focusedPlace(model, layout), ({ pane }) => pane.id);
235
239
 
236
240
  const isHolding = (model: Model): boolean => Option.isSome(model.maybeHeld);
237
241
 
238
- /** Whether nothing is held and no splitter is dragged: a grip or a splitter may be pressed. */
239
- const isIdle = (model: Model): boolean => !isHolding(model) && Option.isNone(model.maybeResizing);
242
+ const isIdle = (model: Model): boolean =>
243
+ !isHolding(model) && Option.isNone(model.maybeResizing);
240
244
 
241
- /** Whether `held` is carried: by the keyboard, or by a pointer past the threshold. */
242
245
  const isCarried = (held: Held): boolean =>
243
- By.match(held.by, { Pointer: ({ isCarrying }) => isCarrying, Keyboard: () => true });
244
-
245
- // DOM HOOKS
246
+ By.match(held.by, {
247
+ Pointer: ({ isCarrying }) => isCarrying,
248
+ Keyboard: () => true,
249
+ });
246
250
 
247
- const paneHook = (model: Model, paneId: string): string => `${model.id}/pane/${paneId}`;
251
+ const paneHook = (model: Model, paneId: string): string =>
252
+ `${model.id}/pane/${paneId}`;
248
253
 
249
- const columnHook = (model: Model, columnId: string): string => `${model.id}/column/${columnId}`;
254
+ const columnHook = (model: Model, columnId: string): string =>
255
+ `${model.id}/column/${columnId}`;
250
256
 
251
- const tabHook = (model: Model, paneId: string): string => `${model.id}/tab/${paneId}`;
257
+ const tabHook = (model: Model, paneId: string): string =>
258
+ `${model.id}/tab/${paneId}`;
252
259
 
253
260
  const scrollerOf = (reelHook: string): Option.Option<HTMLElement> =>
254
- Option.fromNullishOr(
255
- document.querySelector<HTMLElement>(`[data-reel="${CSS.escape(reelHook)}"] > .reel-view`),
256
- );
261
+ htmlElement(`[data-reel="${CSS.escape(reelHook)}"] > .reel-view`);
257
262
 
258
263
  const paneElement = (hook: string): Option.Option<HTMLElement> =>
259
- Option.fromNullishOr(
260
- document.querySelector<HTMLElement>(`[data-reel-pane="${CSS.escape(hook)}"]`),
261
- );
264
+ htmlElement(`[data-reel-pane="${CSS.escape(hook)}"]`);
262
265
 
263
- /** Puts the keyboard in `pane`: on its control marked `data-reel-focus` (a terminal's input),
264
- * or on the pane itself, without scrolling the page. */
265
266
  const focusInto = (pane: HTMLElement): void => {
266
- Option.getOrElse(
267
- Option.fromNullishOr(pane.querySelector<HTMLElement>("[data-reel-focus]")),
268
- () => pane,
269
- ).focus({ preventScroll: true });
267
+ Option.getOrElse(htmlElement("[data-reel-focus]", pane), () => pane).focus({
268
+ preventScroll: true,
269
+ });
270
270
  };
271
271
 
272
- // COMMAND
273
-
274
272
  /** Says a focus move, a move or a step of a drag through the page's live region (as
275
273
  * `Announcer.Announce` does). */
276
274
  export const AnnounceReel = Command.define("AnnounceReel", {
277
275
  args: { text: Schema.String },
278
276
  messages: [Message.CompletedAnnounceReel],
279
- execute: ({ text }) => Announcer.announce(text).pipe(Effect.as(Message.CompletedAnnounceReel())),
277
+ execute: ({ text }) =>
278
+ Announcer.announce(text).pipe(Effect.as(Message.CompletedAnnounceReel())),
280
279
  });
281
280
 
282
281
  /** Focuses the pane `paneHook` names, unless focus is already inside it: the control in it
@@ -290,10 +289,14 @@ export const FocusPane = Command.define("FocusPane", {
290
289
  yield* Render.afterCommit;
291
290
  yield* Effect.sync(() => {
292
291
  Option.map(
293
- Option.filter(paneElement(hook), (pane) => !pane.contains(document.activeElement)),
294
- focusInto,
292
+ Option.filter(
293
+ paneElement(hook),
294
+ (pane) => !pane.contains(document.activeElement)
295
+ ),
296
+ focusInto
295
297
  );
296
298
  });
299
+
297
300
  return Message.CompletedFocusPane();
298
301
  }),
299
302
  });
@@ -307,8 +310,14 @@ export const FocusTab = Command.define("FocusTab", {
307
310
  Effect.gen(function* () {
308
311
  yield* Render.afterCommit;
309
312
  yield* Effect.sync(() => {
310
- document.querySelector<HTMLElement>(`[data-reel-tab="${CSS.escape(hook)}"]`)?.focus();
313
+ Option.map(
314
+ htmlElement(`[data-reel-tab="${CSS.escape(hook)}"]`),
315
+ (tab) => {
316
+ tab.focus();
317
+ }
318
+ );
311
319
  });
320
+
312
321
  return Message.CompletedFocusTab();
313
322
  }),
314
323
  });
@@ -323,10 +332,12 @@ export const RestoreFocus = Command.define("RestoreFocus", {
323
332
  yield* Render.afterCommit;
324
333
  yield* Effect.sync(() => {
325
334
  const active = document.activeElement;
335
+
326
336
  if (active === null || active === document.body) {
327
337
  Option.map(paneElement(hook), focusInto);
328
338
  }
329
339
  });
340
+
330
341
  return Message.CompletedRestoreFocus();
331
342
  }),
332
343
  });
@@ -343,42 +354,52 @@ export const ScrollIntoView = Command.define("ScrollIntoView", {
343
354
  yield* Effect.sync(() => {
344
355
  document
345
356
  .querySelector(
346
- `[data-reel-pane="${CSS.escape(hook)}"], [data-reel-hook="${CSS.escape(hook)}"]`,
357
+ `[data-reel-pane="${CSS.escape(hook)}"], [data-reel-hook="${CSS.escape(hook)}"]`
347
358
  )
348
359
  ?.scrollIntoView({ block: "nearest", inline: "nearest" });
349
360
  });
361
+
350
362
  return Message.CompletedScrollIntoView();
351
363
  }),
352
364
  });
353
365
 
354
- // UPDATE
355
-
356
366
  /** What the reel reads from its parent as each Message arrives: the layout as the
357
367
  * application holds it now, and how the view shows it (`Strip` when not given), which
358
368
  * `perform` reads. */
359
- export type UpdateContext = Readonly<{ layout: Layout; arrangement?: Arrangement }>;
369
+ export type UpdateContext = Readonly<{
370
+ layout: Layout;
371
+ arrangement?: Arrangement;
372
+ }>;
360
373
 
361
374
  type UpdateReturn = Update.ReturnWithOutMessage<Model, Message, OutMessage>;
362
375
 
363
- /** How far a pointer moves from its press before it carries what it pressed. */
364
376
  const CARRY_THRESHOLD = 5;
365
377
 
366
378
  const withHeld = (model: Model, maybeHeld: Option.Option<Held>): Model =>
367
379
  modifyFields(model, { maybeHeld: () => maybeHeld });
368
380
 
369
- const withResizing = (model: Model, maybeResizing: Option.Option<Resizing>): Model =>
370
- modifyFields(model, { maybeResizing: () => maybeResizing });
381
+ const withResizing = (
382
+ model: Model,
383
+ maybeResizing: Option.Option<Resizing>
384
+ ): Model => modifyFields(model, { maybeResizing: () => maybeResizing });
371
385
 
372
386
  const focusOn = (model: Model, place: Place): Model =>
373
387
  modifyFields(model, {
374
388
  maybeFocus: () =>
375
- Option.some({ paneId: place.pane.id, column: place.columnIndex, row: place.row }),
389
+ Option.some({
390
+ paneId: place.pane.id,
391
+ column: place.columnIndex,
392
+ row: place.row,
393
+ }),
376
394
  });
377
395
 
378
396
  const announce = (text: string) => AnnounceReel({ text });
379
397
 
380
398
  const heldLabel = (layout: Layout, held: Held): string =>
381
- Option.getOrElse(subjectWords(layout, Subject.Pane({ paneId: held.paneId })), () => "");
399
+ Option.getOrElse(
400
+ subjectWords(layout, Subject.Pane({ paneId: held.paneId })),
401
+ () => ""
402
+ );
382
403
 
383
404
  const heldWords = (layout: Layout, held: Held): string =>
384
405
  String.capitalize(heldLabel(layout, held));
@@ -386,21 +407,26 @@ const heldWords = (layout: Layout, held: Held): string =>
386
407
  const scrollToTarget = (model: Model, layout: Layout, target: Target) =>
387
408
  Array.fromOption(
388
409
  Option.map(columnOfTarget(layout, target), (columnId) =>
389
- ScrollIntoView({ hook: columnHook(model, columnId) }),
390
- ),
410
+ ScrollIntoView({ hook: columnHook(model, columnId) })
411
+ )
391
412
  );
392
413
 
393
- /** Lets go of the held pane: dropped at its target when it is carried and the drop changes
394
- * something (reported as the request), put back otherwise, said in `putBack`'s words. */
395
- const letGo = (model: Model, layout: Layout, held: Held, putBack: string): UpdateReturn => {
414
+ const letGo = (
415
+ model: Model,
416
+ layout: Layout,
417
+ held: Held,
418
+ putBack: string
419
+ ): UpdateReturn => {
396
420
  const released = withHeld(model, Option.none());
421
+
397
422
  if (!isCarried(held)) {
398
423
  return { model: released };
399
424
  }
400
425
 
401
426
  const subject = heldWords(layout, held);
427
+
402
428
  const maybeRequest = Option.flatMap(held.maybeTarget, (target) =>
403
- requestOf(layout, held.paneId, target),
429
+ requestOf(layout, held.paneId, target)
404
430
  );
405
431
 
406
432
  return Option.match(maybeRequest, {
@@ -415,10 +441,13 @@ const letGo = (model: Model, layout: Layout, held: Held, putBack: string): Updat
415
441
  fill(COPY.dropped, {
416
442
  subject,
417
443
  where: Option.getOrElse(
418
- whereWords(apply(layout, request), Subject.Pane({ paneId: held.paneId })),
419
- () => WHERE_IT_WAS,
444
+ whereWords(
445
+ apply(layout, request),
446
+ Subject.Pane({ paneId: held.paneId })
447
+ ),
448
+ () => WHERE_IT_WAS
420
449
  ),
421
- }),
450
+ })
422
451
  ),
423
452
  ],
424
453
  outMessage: request,
@@ -429,109 +458,156 @@ const letGo = (model: Model, layout: Layout, held: Held, putBack: string): Updat
429
458
  const cancel = (model: Model, layout: Layout, held: Held): UpdateReturn =>
430
459
  letGo(model, layout, { ...held, maybeTarget: Option.none() }, COPY.cancelled);
431
460
 
432
- const lift = (model: Model, layout: Layout, paneId: string, by: By): UpdateReturn =>
461
+ const lift = (
462
+ model: Model,
463
+ layout: Layout,
464
+ paneId: string,
465
+ by: By
466
+ ): UpdateReturn =>
433
467
  Option.match(
434
468
  Option.filter(originOf(layout, paneId), () => isIdle(model)),
435
469
  {
436
470
  onNone: () => ({ model }),
437
471
  onSome: (origin) => {
438
472
  const held: Held = { paneId, by, maybeTarget: Option.some(origin) };
473
+
439
474
  return {
440
475
  model: withHeld(model, Option.some(held)),
441
476
  commands:
442
477
  by._tag === "Keyboard"
443
- ? [announce(fill(COPY.pickedUpByKeyboard, { subject: heldWords(layout, held) }))]
478
+ ? [
479
+ announce(
480
+ fill(COPY.pickedUpByKeyboard, {
481
+ subject: heldWords(layout, held),
482
+ })
483
+ ),
484
+ ]
444
485
  : [],
445
486
  };
446
487
  },
447
- },
488
+ }
448
489
  );
449
490
 
450
- const movePointer = (model: Model, layout: Layout, held: Held, pointer: PointerAt): UpdateReturn =>
491
+ const movePointer = (
492
+ model: Model,
493
+ layout: Layout,
494
+ held: Held,
495
+ pointer: PointerAt
496
+ ): UpdateReturn =>
451
497
  By.match(held.by, {
452
498
  Keyboard: () => ({ model }),
453
499
  Pointer: (by) => {
454
500
  const isCarrying =
455
501
  by.isCarrying ||
456
- Math.hypot(pointer.clientX - by.pressX, pointer.clientY - by.pressY) > CARRY_THRESHOLD;
502
+ Math.hypot(pointer.clientX - by.pressX, pointer.clientY - by.pressY) >
503
+ CARRY_THRESHOLD;
504
+
457
505
  const next: Held = {
458
506
  ...held,
459
- by: By.Pointer({ ...by, x: pointer.clientX, y: pointer.clientY, isCarrying }),
507
+ by: By.Pointer({
508
+ ...by,
509
+ x: pointer.clientX,
510
+ y: pointer.clientY,
511
+ isCarrying,
512
+ }),
460
513
  maybeTarget: isCarrying ? pointer.maybeTarget : held.maybeTarget,
461
514
  };
515
+
462
516
  return {
463
517
  model: withHeld(model, Option.some(next)),
464
518
  commands:
465
519
  isCarrying && !by.isCarrying
466
- ? [announce(fill(COPY.pickedUp, { subject: heldWords(layout, held) }))]
520
+ ? [
521
+ announce(
522
+ fill(COPY.pickedUp, { subject: heldWords(layout, held) })
523
+ ),
524
+ ]
467
525
  : [],
468
526
  };
469
527
  },
470
528
  });
471
529
 
472
- /** A keyboard step of what is held, resolved from the layout, with the reel scrolled to the
473
- * column it lands by. */
474
- const stepHeld = (model: Model, layout: Layout, held: Held, step: Step): UpdateReturn =>
530
+ const stepHeld = (
531
+ model: Model,
532
+ layout: Layout,
533
+ held: Held,
534
+ step: Step
535
+ ): UpdateReturn =>
475
536
  Option.match(
476
537
  Option.filter(held.maybeTarget, () => held.by._tag === "Keyboard"),
477
538
  {
478
539
  onNone: () => ({ model }),
479
540
  onSome: (target) => {
480
541
  const next = steppedTarget(layout, held.paneId, target, step);
542
+
481
543
  if (Equal.equals(next, target)) {
482
544
  return { model };
483
545
  }
546
+
484
547
  return {
485
- model: withHeld(model, Option.some({ ...held, maybeTarget: Option.some(next) })),
548
+ model: withHeld(
549
+ model,
550
+ Option.some({ ...held, maybeTarget: Option.some(next) })
551
+ ),
486
552
  commands: [
487
553
  announce(
488
554
  fill(COPY.over, {
489
555
  subject: heldWords(layout, held),
490
556
  where: landingWords(layout, held.paneId, next),
491
- }),
557
+ })
492
558
  ),
493
559
  ...scrollToTarget(model, layout, next),
494
560
  ],
495
561
  };
496
562
  },
497
- },
563
+ }
498
564
  );
499
565
 
500
- const whileHeld = (model: Model, f: (held: Held) => UpdateReturn): UpdateReturn =>
566
+ const whileHeld = (
567
+ model: Model,
568
+ f: (held: Held) => UpdateReturn
569
+ ): UpdateReturn =>
501
570
  Option.match(model.maybeHeld, { onNone: () => ({ model }), onSome: f });
502
571
 
503
- const whileHeldBy = (model: Model, by: By["_tag"], f: (held: Held) => UpdateReturn): UpdateReturn =>
572
+ const whileHeldBy = (
573
+ model: Model,
574
+ by: By["_tag"],
575
+ f: (held: Held) => UpdateReturn
576
+ ): UpdateReturn =>
504
577
  whileHeld(model, (held) => (held.by._tag === by ? f(held) : { model }));
505
578
 
506
- /** The resize a splitter dragged `share` of its scale asks for: previewed while it moves, and
507
- * asked for when it is let go. */
508
579
  const resizeSplitter = (
509
580
  model: Model,
510
581
  layout: Layout,
511
582
  share: number,
512
- isLetGo: boolean,
583
+ isLetGo: boolean
513
584
  ): UpdateReturn =>
514
585
  Option.match(model.maybeResizing, {
515
586
  onNone: () => ({ model }),
516
587
  onSome: (resizing) => {
517
588
  const maybeResize = resizeOf(layout, resizing.splitter, share);
589
+
518
590
  if (!isLetGo) {
519
- return { model: withResizing(model, Option.some({ ...resizing, maybeResize })) };
591
+ return {
592
+ model: withResizing(model, Option.some({ ...resizing, maybeResize })),
593
+ };
520
594
  }
595
+
521
596
  return Option.match(maybeResize, {
522
597
  onNone: () => ({ model: withResizing(model, Option.none()) }),
523
- onSome: (resize) => ({ model: withResizing(model, Option.none()), outMessage: resize }),
598
+ onSome: (resize) => ({
599
+ model: withResizing(model, Option.none()),
600
+ outMessage: resize,
601
+ }),
524
602
  });
525
603
  },
526
604
  });
527
605
 
528
- /** Shows the pane `paneId` under its tab and moves the keyboard as `focus` says: into the
529
- * pane for a press, onto the tab for an arrow. */
530
606
  const selectTab = (
531
607
  model: Model,
532
608
  layout: Layout,
533
609
  paneId: string,
534
- focus: Command.Command<Message>,
610
+ focus: Command.Command<Message>
535
611
  ): UpdateReturn =>
536
612
  Option.match(placeOf(layout, paneId), {
537
613
  onNone: () => ({ model }),
@@ -540,7 +616,11 @@ const selectTab = (
540
616
 
541
617
  /** Processes a reel Message against the layout as the application holds it now, and returns
542
618
  * the next Model, Commands and OutMessage. */
543
- export const update = (model: Model, message: Message, context: UpdateContext): UpdateReturn => {
619
+ export const update = (
620
+ model: Model,
621
+ message: Message,
622
+ context: UpdateContext
623
+ ): UpdateReturn => {
544
624
  const { layout } = context;
545
625
 
546
626
  return Message.match<UpdateReturn>(message, {
@@ -556,47 +636,72 @@ export const update = (model: Model, message: Message, context: UpdateContext):
556
636
  x: clientX,
557
637
  y: clientY,
558
638
  isCarrying: false,
559
- }),
639
+ })
560
640
  ),
561
641
  PressedGripKey: ({ paneId }) => lift(model, layout, paneId, By.Keyboard()),
562
642
  MovedPointer: (pointer) =>
563
- whileHeldBy(model, "Pointer", (held) => movePointer(model, layout, held, pointer)),
643
+ whileHeldBy(model, "Pointer", (held) =>
644
+ movePointer(model, layout, held, pointer)
645
+ ),
564
646
  ReleasedPointer: (pointer) =>
565
647
  whileHeldBy(model, "Pointer", (held) =>
566
648
  letGo(
567
649
  model,
568
650
  layout,
569
- isCarried(held) ? { ...held, maybeTarget: pointer.maybeTarget } : held,
570
- COPY.putBack,
571
- ),
651
+ isCarried(held)
652
+ ? { ...held, maybeTarget: pointer.maybeTarget }
653
+ : held,
654
+ COPY.putBack
655
+ )
572
656
  ),
573
657
  CancelledPointer: () =>
574
658
  whileHeldBy(model, "Pointer", (held) =>
575
- letGo(model, layout, { ...held, maybeTarget: Option.none() }, COPY.putBack),
659
+ letGo(
660
+ model,
661
+ layout,
662
+ { ...held, maybeTarget: Option.none() },
663
+ COPY.putBack
664
+ )
576
665
  ),
577
666
  SteppedHeld: ({ step }) =>
578
- whileHeldBy(model, "Keyboard", (held) => stepHeld(model, layout, held, step)),
667
+ whileHeldBy(model, "Keyboard", (held) =>
668
+ stepHeld(model, layout, held, step)
669
+ ),
579
670
  DroppedHeld: () =>
580
- whileHeldBy(model, "Keyboard", (held) => letGo(model, layout, held, COPY.putBack)),
581
- LeftGrip: () => whileHeldBy(model, "Keyboard", (held) => cancel(model, layout, held)),
671
+ whileHeldBy(model, "Keyboard", (held) =>
672
+ letGo(model, layout, held, COPY.putBack)
673
+ ),
674
+ LeftGrip: () =>
675
+ whileHeldBy(model, "Keyboard", (held) => cancel(model, layout, held)),
582
676
  PressedEscape: () =>
583
677
  Option.isSome(model.maybeResizing)
584
678
  ? { model: withResizing(model, Option.none()) }
585
679
  : whileHeld(model, (held) => cancel(model, layout, held)),
586
680
  PressedTab: ({ paneId }) =>
587
- selectTab(model, layout, paneId, FocusPane({ paneHook: paneHook(model, paneId) })),
681
+ selectTab(
682
+ model,
683
+ layout,
684
+ paneId,
685
+ FocusPane({ paneHook: paneHook(model, paneId) })
686
+ ),
588
687
  SteppedTab: ({ paneId }) =>
589
- selectTab(model, layout, paneId, FocusTab({ tabHook: tabHook(model, paneId) })),
688
+ selectTab(
689
+ model,
690
+ layout,
691
+ paneId,
692
+ FocusTab({ tabHook: tabHook(model, paneId) })
693
+ ),
590
694
  FocusedPane: ({ paneId }) =>
591
695
  Option.match(
592
696
  Option.filter(
593
697
  placeOf(layout, paneId),
594
- () => !Option.exists(model.maybeFocus, (focus) => focus.paneId === paneId),
698
+ () =>
699
+ !Option.exists(model.maybeFocus, (focus) => focus.paneId === paneId)
595
700
  ),
596
701
  {
597
702
  onNone: () => ({ model }),
598
703
  onSome: (place) => ({ model: focusOn(model, place) }),
599
- },
704
+ }
600
705
  ),
601
706
  PressedSplitter: ({ splitter, pointerId, clientX, clientY }) =>
602
707
  !isIdle(model) || !isSplitterPresent(layout, splitter)
@@ -610,7 +715,7 @@ export const update = (model: Model, message: Message, context: UpdateContext):
610
715
  pressX: clientX,
611
716
  pressY: clientY,
612
717
  maybeResize: Option.none(),
613
- }),
718
+ })
614
719
  ),
615
720
  },
616
721
  MovedSplitter: ({ share }) => resizeSplitter(model, layout, share, false),
@@ -630,8 +735,6 @@ export const update = (model: Model, message: Message, context: UpdateContext):
630
735
  });
631
736
  };
632
737
 
633
- // CAPABILITIES
634
-
635
738
  /**
636
739
  * Brings the reel in line with a layout that changed: call it whenever the application changes
637
740
  * the layout, by a request it applied, another client's or one of its own (a pane closed). The
@@ -640,26 +743,34 @@ export const update = (model: Model, message: Message, context: UpdateContext):
640
743
  * gone is cancelled, and one whose target's column has gone aims where it started;
641
744
  * a splitter whose column or pane has gone lets go.
642
745
  */
643
- export const reconcile = (model: Model, context: UpdateContext): UpdateReturn => {
746
+ export const reconcile = (
747
+ model: Model,
748
+ context: UpdateContext
749
+ ): UpdateReturn => {
644
750
  const { layout } = context;
751
+
645
752
  const isFocusGone = Option.exists(model.maybeFocus, (focus) =>
646
- Option.isNone(placeOf(layout, focus.paneId)),
753
+ Option.isNone(placeOf(layout, focus.paneId))
647
754
  );
755
+
648
756
  const maybePlace = Option.filter(focusedPlace(model, layout), () =>
649
- Option.isSome(model.maybeFocus),
757
+ Option.isSome(model.maybeFocus)
650
758
  );
759
+
651
760
  const focused = Option.match(maybePlace, {
652
761
  onNone: () => model,
653
762
  onSome: (place) => focusOn(model, place),
654
763
  });
764
+
655
765
  const restore = Array.fromOption(
656
766
  Option.map(
657
767
  Option.filter(maybePlace, () => isFocusGone),
658
- (place) => RestoreFocus({ paneHook: paneHook(model, place.pane.id) }),
659
- ),
768
+ (place) => RestoreFocus({ paneHook: paneHook(model, place.pane.id) })
769
+ )
660
770
  );
771
+
661
772
  const settled = Option.exists(model.maybeResizing, ({ splitter }) =>
662
- isSplitterPresent(layout, splitter),
773
+ isSplitterPresent(layout, splitter)
663
774
  )
664
775
  ? focused
665
776
  : withResizing(focused, Option.none());
@@ -673,10 +784,17 @@ export const reconcile = (model: Model, context: UpdateContext): UpdateReturn =>
673
784
  commands: [...restore, announce(COPY.gone)],
674
785
  };
675
786
  }
787
+
676
788
  const maybeTarget = Option.orElse(
677
- Option.filter(held.maybeTarget, (target) => isTargetPresent(layout, target)),
678
- () => (held.by._tag === "Keyboard" ? originOf(layout, held.paneId) : Option.none()),
789
+ Option.filter(held.maybeTarget, (target) =>
790
+ isTargetPresent(layout, target)
791
+ ),
792
+ () =>
793
+ held.by._tag === "Keyboard"
794
+ ? originOf(layout, held.paneId)
795
+ : Option.none()
679
796
  );
797
+
680
798
  return {
681
799
  model: withHeld(settled, Option.some({ ...held, maybeTarget })),
682
800
  commands: restore,
@@ -704,25 +822,33 @@ export const Action = Schema.Literals([
704
822
  "CycleWidth",
705
823
  "PullOut",
706
824
  ]);
825
+
707
826
  export type Action = typeof Action.Type;
708
827
 
709
- const focusStep = (model: Model, layout: Layout, place: Place): UpdateReturn => ({
828
+ const focusStep = (
829
+ model: Model,
830
+ layout: Layout,
831
+ place: Place
832
+ ): UpdateReturn => ({
710
833
  model: focusOn(model, place),
711
834
  commands: [
712
835
  FocusPane({ paneHook: paneHook(model, place.pane.id) }),
713
836
  ScrollIntoView({ hook: paneHook(model, place.pane.id) }),
714
- announce(fill(COPY.focused, { pane: place.pane.label, where: placeWords(layout, place) })),
837
+ announce(
838
+ fill(COPY.focused, {
839
+ pane: place.pane.label,
840
+ where: placeWords(layout, place),
841
+ })
842
+ ),
715
843
  ],
716
844
  });
717
845
 
718
- /** Asks for `request` with focus kept on the pane it moves, at its new place, the reel
719
- * scrolled to it and the move said; nothing where it would change nothing. */
720
846
  const requestStep = (
721
847
  model: Model,
722
848
  layout: Layout,
723
849
  place: Place,
724
850
  subject: Subject,
725
- maybeRequest: Option.Option<OutMessage>,
851
+ maybeRequest: Option.Option<OutMessage>
726
852
  ): UpdateReturn =>
727
853
  Option.match(
728
854
  Option.filter(maybeRequest, (request) => isChange(layout, request)),
@@ -730,50 +856,67 @@ const requestStep = (
730
856
  onNone: () => ({ model }),
731
857
  onSome: (request) => {
732
858
  const next = apply(layout, request);
733
- const landing = Option.getOrElse(placeOf(next, place.pane.id), () => place);
734
- const words = Option.getOrElse(subjectWords(layout, subject), () => place.pane.label);
735
- const where = Option.getOrElse(whereWords(next, subject), () => WHERE_IT_WAS);
859
+
860
+ const landing = Option.getOrElse(
861
+ placeOf(next, place.pane.id),
862
+ () => place
863
+ );
864
+
865
+ const words = Option.getOrElse(
866
+ subjectWords(layout, subject),
867
+ () => place.pane.label
868
+ );
869
+
870
+ const where = Option.getOrElse(
871
+ whereWords(next, subject),
872
+ () => WHERE_IT_WAS
873
+ );
736
874
 
737
875
  return {
738
876
  model: focusOn(model, landing),
739
877
  commands: [
740
878
  ScrollIntoView({ hook: paneHook(model, place.pane.id) }),
741
- announce(fill(COPY.moved, { subject: String.capitalize(words), where })),
879
+ announce(
880
+ fill(COPY.moved, { subject: String.capitalize(words), where })
881
+ ),
742
882
  ],
743
883
  outMessage: request,
744
884
  };
745
885
  },
746
- },
886
+ }
747
887
  );
748
888
 
749
- /** The panes in the order their tabs print: column by column, and down each column. */
750
- const readingOrder = (layout: Layout): ReadonlyArray<Pane> =>
889
+ const readingOrder = (layout: Layout): readonly Pane[] =>
751
890
  Array.flatMap(layout, (column) => column.panes);
752
891
 
753
- /** How far each focus key steps through the tabs: left and up to the one before, right and
754
- * down to the one after. */
755
- const TAB_STEPS: Readonly<Partial<Record<Action, number>>> = {
892
+ const TAB_STEPS: Partial<Record.ReadonlyRecord<Action, number>> = {
756
893
  FocusLeft: -1,
757
894
  FocusUp: -1,
758
895
  FocusRight: 1,
759
896
  FocusDown: 1,
760
897
  };
761
898
 
762
- /** `perform` while the panes print as tabs: a focus key moves to the tab beside the focused
763
- * pane's, past neither end; there is no column to move or size. */
764
- const performTabbed = (model: Model, action: Action, layout: Layout): UpdateReturn => {
899
+ const performTabbed = (
900
+ model: Model,
901
+ action: Action,
902
+ layout: Layout
903
+ ): UpdateReturn => {
765
904
  const panes = readingOrder(layout);
905
+
766
906
  const maybeNext = Option.flatMap(
767
907
  Option.all({
768
908
  step: Option.fromUndefinedOr(TAB_STEPS[action]),
769
909
  index: Option.flatMap(focusedPaneId(model, layout), (paneId) =>
770
- Array.findFirstIndex(panes, (pane) => pane.id === paneId),
910
+ Array.findFirstIndex(panes, (pane) => pane.id === paneId)
771
911
  ),
772
912
  }),
773
913
  ({ step, index }) =>
774
914
  Option.flatMap(Array.get(panes, index + step), (pane) =>
775
- Option.map(placeOf(layout, pane.id), (place) => ({ place, tab: index + step + 1 })),
776
- ),
915
+ Option.map(placeOf(layout, pane.id), (place) => ({
916
+ place,
917
+ tab: index + step + 1,
918
+ }))
919
+ )
777
920
  );
778
921
 
779
922
  return Option.match(
@@ -784,10 +927,16 @@ const performTabbed = (model: Model, action: Action, layout: Layout): UpdateRetu
784
927
  model: focusOn(model, place),
785
928
  commands: [
786
929
  FocusPane({ paneHook: paneHook(model, place.pane.id) }),
787
- announce(fill(COPY.focusedTab, { pane: place.pane.label, tab, tabs: panes.length })),
930
+ announce(
931
+ fill(COPY.focusedTab, {
932
+ pane: place.pane.label,
933
+ tab,
934
+ tabs: panes.length,
935
+ })
936
+ ),
788
937
  ],
789
938
  }),
790
- },
939
+ }
791
940
  );
792
941
  };
793
942
 
@@ -802,7 +951,11 @@ const columnIdAt = (layout: Layout, index: number): Option.Option<string> =>
802
951
  * held, or where there is nowhere to go. Under tabs, only the focus keys act, stepping from tab
803
952
  * to tab.
804
953
  */
805
- export const perform = (model: Model, action: Action, context: UpdateContext): UpdateReturn => {
954
+ export const perform = (
955
+ model: Model,
956
+ action: Action,
957
+ context: UpdateContext
958
+ ): UpdateReturn => {
806
959
  const { layout, arrangement = "Strip" } = context;
807
960
 
808
961
  if (arrangement === "Tabs") {
@@ -817,26 +970,37 @@ export const perform = (model: Model, action: Action, context: UpdateContext): U
817
970
  const { column, columnIndex, row, pane } = place;
818
971
  const rows = column.panes.length;
819
972
  const paneId = pane.id;
973
+
820
974
  const ask = (
821
975
  maybeRequest: Option.Option<OutMessage>,
822
- subject: Subject = Subject.Pane({ paneId }),
976
+ subject: Subject = Subject.Pane({ paneId })
823
977
  ) => requestStep(model, layout, place, subject, maybeRequest);
978
+
824
979
  const focusAt = (toColumn: number, toRow: number): UpdateReturn =>
825
980
  Option.match(
826
981
  Option.flatMap(Array.get(layout, toColumn), (found) =>
827
982
  placeAt(
828
983
  layout,
829
984
  toColumn,
830
- Number.clamp(toRow, { minimum: 0, maximum: found.panes.length - 1 }),
831
- ),
985
+ Number.clamp(toRow, {
986
+ minimum: 0,
987
+ maximum: found.panes.length - 1,
988
+ })
989
+ )
832
990
  ),
833
991
  {
834
992
  onNone: () => ({ model }),
835
993
  onSome: (next) =>
836
- next.pane.id === paneId ? { model } : focusStep(model, layout, next),
837
- },
994
+ next.pane.id === paneId
995
+ ? { model }
996
+ : focusStep(model, layout, next),
997
+ }
838
998
  );
839
- const sideways = (toColumn: number, edge: Option.Option<string>): UpdateReturn =>
999
+
1000
+ const sideways = (
1001
+ toColumn: number,
1002
+ edge: Option.Option<string>
1003
+ ): UpdateReturn =>
840
1004
  ask(
841
1005
  Option.match(Array.get(layout, toColumn), {
842
1006
  onSome: (found) =>
@@ -845,66 +1009,100 @@ export const perform = (model: Model, action: Action, context: UpdateContext): U
845
1009
  paneId,
846
1010
  toColumnId: found.id,
847
1011
  toIndex: Math.min(row, found.panes.length),
848
- }),
1012
+ })
849
1013
  ),
850
1014
  onNone: () =>
851
1015
  Option.liftPredicate(
852
- OutMessage.PulledOutPane({ paneId, maybeBeforeColumnId: edge }),
853
- () => rows > 1,
1016
+ OutMessage.PulledOutPane({
1017
+ paneId,
1018
+ maybeBeforeColumnId: edge,
1019
+ }),
1020
+ () => rows > 1
854
1021
  ),
855
- }),
1022
+ })
856
1023
  );
857
- const moveColumn = (maybeBefore: Option.Option<Option.Option<string>>): UpdateReturn =>
1024
+
1025
+ const moveColumn = (
1026
+ maybeBefore: Option.Option<Option.Option<string>>
1027
+ ): UpdateReturn =>
858
1028
  ask(
859
1029
  Option.map(maybeBefore, (maybeBeforeColumnId) =>
860
- OutMessage.MovedColumn({ columnId: column.id, maybeBeforeColumnId }),
1030
+ OutMessage.MovedColumn({
1031
+ columnId: column.id,
1032
+ maybeBeforeColumnId,
1033
+ })
861
1034
  ),
862
- Subject.Column({ columnId: column.id }),
1035
+ Subject.Column({ columnId: column.id })
863
1036
  );
864
1037
 
865
1038
  return Match.value(action).pipe(
866
1039
  Match.withReturnType<UpdateReturn>(),
867
1040
  Match.when("FocusLeft", () => focusAt(columnIndex - 1, row)),
868
1041
  Match.when("FocusRight", () => focusAt(columnIndex + 1, row)),
869
- Match.when("FocusUp", () => (row > 0 ? focusAt(columnIndex, row - 1) : { model })),
1042
+ Match.when("FocusUp", () =>
1043
+ row > 0 ? focusAt(columnIndex, row - 1) : { model }
1044
+ ),
870
1045
  Match.when("FocusDown", () => focusAt(columnIndex, row + 1)),
871
1046
  Match.when("MovePaneUp", () =>
872
1047
  ask(
873
1048
  Option.some(
874
- OutMessage.MovedPane({ paneId, toColumnId: column.id, toIndex: row - 1 }),
875
- ),
876
- ),
1049
+ OutMessage.MovedPane({
1050
+ paneId,
1051
+ toColumnId: column.id,
1052
+ toIndex: row - 1,
1053
+ })
1054
+ )
1055
+ )
877
1056
  ),
878
1057
  Match.when("MovePaneDown", () =>
879
1058
  ask(
880
1059
  Option.some(
881
- OutMessage.MovedPane({ paneId, toColumnId: column.id, toIndex: row + 1 }),
882
- ),
883
- ),
1060
+ OutMessage.MovedPane({
1061
+ paneId,
1062
+ toColumnId: column.id,
1063
+ toIndex: row + 1,
1064
+ })
1065
+ )
1066
+ )
1067
+ ),
1068
+ Match.when("MovePaneLeft", () =>
1069
+ sideways(columnIndex - 1, columnIdAt(layout, 0))
1070
+ ),
1071
+ Match.when("MovePaneRight", () =>
1072
+ sideways(columnIndex + 1, Option.none())
884
1073
  ),
885
- Match.when("MovePaneLeft", () => sideways(columnIndex - 1, columnIdAt(layout, 0))),
886
- Match.when("MovePaneRight", () => sideways(columnIndex + 1, Option.none())),
887
1074
  Match.when("MoveColumnLeft", () =>
888
1075
  moveColumn(
889
- Option.map(columnIdAt(layout, columnIndex - 1), (before) => Option.some(before)),
890
- ),
1076
+ Option.map(columnIdAt(layout, columnIndex - 1), (before) =>
1077
+ Option.some(before)
1078
+ )
1079
+ )
891
1080
  ),
892
1081
  Match.when("MoveColumnRight", () =>
893
1082
  moveColumn(
894
1083
  Option.map(columnIdAt(layout, columnIndex + 1), () =>
895
- columnIdAt(layout, columnIndex + 2),
896
- ),
897
- ),
1084
+ columnIdAt(layout, columnIndex + 2)
1085
+ )
1086
+ )
898
1087
  ),
899
1088
  Match.when("CycleWidth", () => {
900
1089
  const width = nextPreset(column.width);
1090
+
901
1091
  return {
902
1092
  model,
903
1093
  commands: [
904
1094
  ScrollIntoView({ hook: paneHook(model, paneId) }),
905
- announce(fill(COPY.widened, { column: columnIndex + 1, width: widthWords(width) })),
1095
+ announce(
1096
+ fill(COPY.widened, {
1097
+ column: columnIndex + 1,
1098
+ width: widthWords(width),
1099
+ })
1100
+ ),
906
1101
  ],
907
- outMessage: OutMessage.ResizedColumn({ columnId: column.id, width }),
1102
+ outMessage: OutMessage.ResizedColumn({
1103
+ columnId: column.id,
1104
+ width,
1105
+ }),
908
1106
  };
909
1107
  }),
910
1108
  Match.when("PullOut", () =>
@@ -914,60 +1112,59 @@ export const perform = (model: Model, action: Action, context: UpdateContext): U
914
1112
  paneId,
915
1113
  maybeBeforeColumnId: columnIdAt(layout, columnIndex + 1),
916
1114
  }),
917
- () => rows > 1,
918
- ),
919
- ),
1115
+ () => rows > 1
1116
+ )
1117
+ )
920
1118
  ),
921
- Match.exhaustive,
1119
+ Match.exhaustive
922
1120
  );
923
1121
  },
924
- },
1122
+ }
925
1123
  );
926
1124
  };
927
1125
 
928
- // SUBSCRIPTION
929
-
930
- /** How near the reel's edges a carried pane scrolls it, how fast, and the longest frame it
931
- * counts, so a tab coming back from the background does not jump. */
932
1126
  const EDGE_SCROLL = 40;
933
1127
  const EDGE_SCROLL_PIXELS_PER_MILLI = 0.8;
934
1128
  const LONGEST_FRAME_MILLIS = 50;
935
1129
 
936
- /** A column as the pointer reads it from the page: its edges. */
937
- const columnBoxOf = (element: Element): ColumnBox => {
1130
+ const columnBoxOf = (element: HTMLElement): ColumnBox => {
938
1131
  const rect = element.getBoundingClientRect();
1132
+
939
1133
  return {
940
- id: element.getAttribute("data-reel-column") ?? "",
1134
+ id: element.dataset["reelColumn"] ?? "",
941
1135
  left: rect.left,
942
1136
  right: rect.right,
943
1137
  };
944
1138
  };
945
1139
 
946
- /** The middles of a column's slots but the held pane's. */
947
- const slotMiddlesOf = (element: Element, heldId: string): ReadonlyArray<number> =>
1140
+ const slotMiddlesOf = (
1141
+ element: HTMLElement,
1142
+ heldId: string
1143
+ ): readonly number[] =>
948
1144
  Array.map(
949
1145
  Array.filter(
950
- Array.fromIterable(element.querySelectorAll("[data-reel-slot]")),
951
- (slot) => slot.getAttribute("data-reel-slot") !== heldId,
1146
+ Array.fromIterable(
1147
+ element.querySelectorAll<HTMLElement>("[data-reel-slot]")
1148
+ ),
1149
+ (slot) => slot.dataset["reelSlot"] !== heldId
952
1150
  ),
953
1151
  (slot) => {
954
1152
  const slotRect = slot.getBoundingClientRect();
1153
+
955
1154
  return slotRect.top + slotRect.height / 2;
956
- },
1155
+ }
957
1156
  );
958
1157
 
959
- /** Where a pointer at (`clientX`, `clientY`) would drop the pane `paneId` in the reel
960
- * `reelHook` names, read from where its columns sit and the slots of the one it is over: none
961
- * outside the reel. */
962
1158
  const pointerTarget = (
963
1159
  reelHook: string,
964
1160
  paneId: string,
965
1161
  clientX: number,
966
- clientY: number,
1162
+ clientY: number
967
1163
  ): Option.Option<Target> =>
968
1164
  Option.map(
969
1165
  Option.filter(scrollerOf(reelHook), (view) => {
970
1166
  const rect = view.getBoundingClientRect();
1167
+
971
1168
  return (
972
1169
  clientX >= rect.left &&
973
1170
  clientX <= rect.right &&
@@ -976,72 +1173,91 @@ const pointerTarget = (
976
1173
  );
977
1174
  }),
978
1175
  (view) => {
979
- const columns = Array.fromIterable(view.querySelectorAll("[data-reel-column]"));
980
- return targetAtPoint(Array.map(columns, columnBoxOf), clientX, clientY, (index) =>
981
- Option.match(Array.get(columns, index), {
982
- onNone: () => [],
983
- onSome: (column) => slotMiddlesOf(column, paneId),
984
- }),
1176
+ const columns = Array.fromIterable(
1177
+ view.querySelectorAll<HTMLElement>("[data-reel-column]")
985
1178
  );
986
- },
1179
+
1180
+ return targetAtPoint(
1181
+ Array.map(columns, columnBoxOf),
1182
+ clientX,
1183
+ clientY,
1184
+ (index) =>
1185
+ Option.match(Array.get(columns, index), {
1186
+ onNone: () => [],
1187
+ onSome: (column) => slotMiddlesOf(column, paneId),
1188
+ })
1189
+ );
1190
+ }
987
1191
  );
988
1192
 
989
1193
  const PointerHold = Schema.Struct({
990
1194
  reelHook: Schema.String,
991
1195
  paneId: Schema.String,
992
- pointerId: Schema.Number,
1196
+ pointerId: Schema.Finite,
993
1197
  });
1198
+
994
1199
  type PointerHold = typeof PointerHold.Type;
995
1200
 
996
1201
  const pointerAt = (hold: PointerHold, event: PointerEvent): PointerAt => ({
997
1202
  clientX: event.clientX,
998
1203
  clientY: event.clientY,
999
- maybeTarget: pointerTarget(hold.reelHook, hold.paneId, event.clientX, event.clientY),
1204
+ maybeTarget: pointerTarget(
1205
+ hold.reelHook,
1206
+ hold.paneId,
1207
+ event.clientX,
1208
+ event.clientY
1209
+ ),
1000
1210
  });
1001
1211
 
1002
- /** The pressing pointer's moves, release and cancel; another pointer's are not the reel's. A
1003
- * pointer reports moves faster than the page draws, and each reads the reel's layout, so its
1004
- * moves are read once a frame, at the latest; a release first reads the move not read yet,
1005
- * so the pane is carried as far as the pointer went, and a cancel drops it. */
1006
1212
  const pointerMessages = (hold: PointerHold): Stream.Stream<Message> =>
1007
1213
  Stream.callback<Message>((queue) =>
1008
1214
  Effect.acquireRelease(
1009
1215
  Effect.sync(() => {
1010
1216
  const state = { maybeMove: Option.none<PointerEvent>(), frame: 0 };
1011
- const offer = (message: Message): void => {
1012
- Queue.offerUnsafe(queue, message);
1013
- };
1217
+
1014
1218
  const readMove = (): void => {
1015
1219
  cancelAnimationFrame(state.frame);
1016
- Option.map(state.maybeMove, (event) =>
1017
- offer(Message.MovedPointer(pointerAt(hold, event))),
1018
- );
1220
+ Option.map(state.maybeMove, (event) => {
1221
+ Queue.offerUnsafe(
1222
+ queue,
1223
+ Message.MovedPointer(pointerAt(hold, event))
1224
+ );
1225
+ });
1019
1226
  state.maybeMove = Option.none();
1020
1227
  };
1228
+
1021
1229
  const onMove = (event: PointerEvent): void => {
1022
1230
  if (event.pointerId === hold.pointerId) {
1023
1231
  if (Option.isNone(state.maybeMove)) {
1024
1232
  state.frame = requestAnimationFrame(readMove);
1025
1233
  }
1234
+
1026
1235
  state.maybeMove = Option.some(event);
1027
1236
  }
1028
1237
  };
1238
+
1029
1239
  const onUp = (event: PointerEvent): void => {
1030
1240
  if (event.pointerId === hold.pointerId) {
1031
1241
  readMove();
1032
- offer(Message.ReleasedPointer(pointerAt(hold, event)));
1242
+ Queue.offerUnsafe(
1243
+ queue,
1244
+ Message.ReleasedPointer(pointerAt(hold, event))
1245
+ );
1033
1246
  }
1034
1247
  };
1248
+
1035
1249
  const onCancel = (event: PointerEvent): void => {
1036
1250
  if (event.pointerId === hold.pointerId) {
1037
1251
  cancelAnimationFrame(state.frame);
1038
1252
  state.maybeMove = Option.none();
1039
- offer(Message.CancelledPointer());
1253
+ Queue.offerUnsafe(queue, Message.CancelledPointer());
1040
1254
  }
1041
1255
  };
1256
+
1042
1257
  document.addEventListener("pointermove", onMove);
1043
1258
  document.addEventListener("pointerup", onUp);
1044
1259
  document.addEventListener("pointercancel", onCancel);
1260
+
1045
1261
  return { state, onMove, onUp, onCancel };
1046
1262
  }),
1047
1263
  ({ state, onMove, onUp, onCancel }) =>
@@ -1050,23 +1266,20 @@ const pointerMessages = (hold: PointerHold): Stream.Stream<Message> =>
1050
1266
  document.removeEventListener("pointermove", onMove);
1051
1267
  document.removeEventListener("pointerup", onUp);
1052
1268
  document.removeEventListener("pointercancel", onCancel);
1053
- }),
1054
- ),
1269
+ })
1270
+ )
1055
1271
  );
1056
1272
 
1057
- /** Which way a pointer at `at` scrolls a box from `low` to `high`: towards the edge it is near. */
1058
1273
  const towards = (at: number, low: number, high: number): number => {
1059
1274
  if (at < low + EDGE_SCROLL) {
1060
1275
  return -1;
1061
1276
  } else if (at > high - EDGE_SCROLL) {
1062
1277
  return 1;
1063
- } else {
1064
- return 0;
1065
1278
  }
1279
+
1280
+ return 0;
1066
1281
  };
1067
1282
 
1068
- /** While a pointer carries a pane near the reel's edges, the reel scrolls that way,
1069
- * by the time each frame took, so a drop can reach a column or a place out of view. */
1070
1283
  const edgeScroll = (hold: PointerHold): Stream.Stream<never> =>
1071
1284
  Stream.callback<never>(() =>
1072
1285
  Effect.acquireRelease(
@@ -1076,51 +1289,57 @@ const edgeScroll = (hold: PointerHold): Stream.Stream<never> =>
1076
1289
  frame: 0,
1077
1290
  last: performance.now(),
1078
1291
  };
1292
+
1079
1293
  const onMove = (event: PointerEvent): void => {
1080
1294
  if (event.pointerId === hold.pointerId) {
1081
1295
  state.maybeAt = Option.some({ x: event.clientX, y: event.clientY });
1082
1296
  }
1083
1297
  };
1298
+
1084
1299
  const step = (now: number): void => {
1085
1300
  const distance =
1086
- Math.min(now - state.last, LONGEST_FRAME_MILLIS) * EDGE_SCROLL_PIXELS_PER_MILLI;
1301
+ Math.min(now - state.last, LONGEST_FRAME_MILLIS) *
1302
+ EDGE_SCROLL_PIXELS_PER_MILLI;
1303
+
1087
1304
  state.last = now;
1088
1305
  Option.map(
1089
1306
  Option.all({ view: scrollerOf(hold.reelHook), at: state.maybeAt }),
1090
1307
  ({ view, at }) => {
1091
1308
  const rect = view.getBoundingClientRect();
1092
- view.scrollLeft += towards(at.x, rect.left, rect.right) * distance;
1309
+ view.scrollLeft +=
1310
+ towards(at.x, rect.left, rect.right) * distance;
1093
1311
  view.scrollTop += towards(at.y, rect.top, rect.bottom) * distance;
1094
- },
1312
+ }
1095
1313
  );
1096
1314
  state.frame = requestAnimationFrame(step);
1097
1315
  };
1316
+
1098
1317
  document.addEventListener("pointermove", onMove);
1099
1318
  state.frame = requestAnimationFrame(step);
1319
+
1100
1320
  return { state, onMove };
1101
1321
  }),
1102
1322
  ({ state, onMove }) =>
1103
1323
  Effect.sync(() => {
1104
1324
  cancelAnimationFrame(state.frame);
1105
1325
  document.removeEventListener("pointermove", onMove);
1106
- }),
1107
- ).pipe(Effect.flatMap(() => Effect.never)),
1326
+ })
1327
+ ).pipe(Effect.flatMap(() => Effect.never))
1108
1328
  );
1109
1329
 
1110
1330
  const SplitterHold = Schema.Struct({
1111
1331
  reelHook: Schema.String,
1112
1332
  splitter: Splitter,
1113
- pointerId: Schema.Number,
1114
- pressX: Schema.Number,
1115
- pressY: Schema.Number,
1333
+ pointerId: Schema.Finite,
1334
+ pressX: Schema.Finite,
1335
+ pressY: Schema.Finite,
1116
1336
  });
1337
+
1117
1338
  type SplitterHold = typeof SplitterHold.Type;
1118
1339
 
1119
- const heightOf = (element: Element): number => element.getBoundingClientRect().height;
1340
+ const heightOf = (element: Element): number =>
1341
+ element.getBoundingClientRect().height;
1120
1342
 
1121
- /** The pixels a splitter's share is counted in, read when its drag begins: the reel's width
1122
- * less a gutter for a width (a column is `width × (view − gutter) − gutter` wide), its
1123
- * column's panes' height for a pane splitter. */
1124
1343
  const scaleOf = (hold: SplitterHold): number =>
1125
1344
  Option.getOrElse(
1126
1345
  Option.map(scrollerOf(hold.reelHook), (view) =>
@@ -1130,36 +1349,42 @@ const scaleOf = (hold: SplitterHold): number =>
1130
1349
  Option.getOrElse(
1131
1350
  Option.map(
1132
1351
  Option.fromNullishOr(view.querySelector(".reel-gap")),
1133
- (gap) => gap.getBoundingClientRect().width,
1352
+ (gap) => gap.getBoundingClientRect().width
1134
1353
  ),
1135
- () => 0,
1354
+ () => 0
1136
1355
  ),
1137
1356
  Split: ({ abovePaneId }) =>
1138
1357
  Number.sumAll(
1139
1358
  Array.map(
1140
1359
  Array.fromIterable(
1141
1360
  view
1142
- .querySelector(`[data-reel-slot="${CSS.escape(abovePaneId)}"]`)
1361
+ .querySelector(
1362
+ `[data-reel-slot="${CSS.escape(abovePaneId)}"]`
1363
+ )
1143
1364
  ?.closest(".reel-column")
1144
- ?.querySelectorAll("[data-reel-slot]") ?? [],
1365
+ ?.querySelectorAll("[data-reel-slot]") ?? []
1145
1366
  ),
1146
- heightOf,
1147
- ),
1367
+ heightOf
1368
+ )
1148
1369
  ),
1149
- }),
1370
+ })
1150
1371
  ),
1151
- () => 0,
1372
+ () => 0
1152
1373
  );
1153
1374
 
1154
- /** The dragging pointer's moves, release and cancel, as shares of the splitter's scale. */
1155
1375
  const splitterMessages = (hold: SplitterHold): Stream.Stream<Message> =>
1156
1376
  Stream.suspend(() => {
1157
1377
  const scale = scaleOf(hold);
1378
+
1158
1379
  const shareOf = (event: PointerEvent): number => {
1159
1380
  const moved =
1160
- hold.splitter._tag === "Width" ? event.clientX - hold.pressX : event.clientY - hold.pressY;
1381
+ hold.splitter._tag === "Width"
1382
+ ? event.clientX - hold.pressX
1383
+ : event.clientY - hold.pressY;
1384
+
1161
1385
  return scale > 0 ? moved / scale : 0;
1162
1386
  };
1387
+
1163
1388
  return dragMessages<Message>(hold.pointerId, {
1164
1389
  moved: (event) => Message.MovedSplitter({ share: shareOf(event) }),
1165
1390
  released: (event) => Message.ReleasedSplitter({ share: shareOf(event) }),
@@ -1167,7 +1392,10 @@ const splitterMessages = (hold: SplitterHold): Stream.Stream<Message> =>
1167
1392
  });
1168
1393
  });
1169
1394
 
1170
- const pointerHoldOf = (model: Model, isCarryingOnly: boolean): Option.Option<PointerHold> =>
1395
+ const pointerHoldOf = (
1396
+ model: Model,
1397
+ isCarryingOnly: boolean
1398
+ ): Option.Option<PointerHold> =>
1171
1399
  Option.flatMap(model.maybeHeld, ({ paneId, by }) =>
1172
1400
  By.match(by, {
1173
1401
  Keyboard: () => Option.none(),
@@ -1175,47 +1403,57 @@ const pointerHoldOf = (model: Model, isCarryingOnly: boolean): Option.Option<Poi
1175
1403
  isCarryingOnly && !isCarrying
1176
1404
  ? Option.none()
1177
1405
  : Option.some({ reelHook: model.id, paneId, pointerId }),
1178
- }),
1406
+ })
1179
1407
  );
1180
1408
 
1181
1409
  const reelSubscriptions = Subscription.make<Model, Message>()((entry) => ({
1182
1410
  pointer: entry(
1183
1411
  { maybeHold: Schema.Option(PointerHold) },
1184
1412
  {
1185
- modelToDependencies: (model) => ({ maybeHold: pointerHoldOf(model, false) }),
1413
+ modelToDependencies: (model) => ({
1414
+ maybeHold: pointerHoldOf(model, false),
1415
+ }),
1186
1416
  dependenciesToStream: ({ maybeHold }) =>
1187
1417
  Option.match(maybeHold, {
1188
1418
  onNone: () => Stream.empty,
1189
1419
  onSome: (hold) => Stream.merge(pointerMessages(hold), markDragging),
1190
1420
  }),
1191
- },
1421
+ }
1192
1422
  ),
1193
1423
  edge: entry(
1194
1424
  { maybeHold: Schema.Option(PointerHold) },
1195
1425
  {
1196
- modelToDependencies: (model) => ({ maybeHold: pointerHoldOf(model, true) }),
1426
+ modelToDependencies: (model) => ({
1427
+ maybeHold: pointerHoldOf(model, true),
1428
+ }),
1197
1429
  dependenciesToStream: ({ maybeHold }) =>
1198
- Option.match(maybeHold, { onNone: () => Stream.empty, onSome: edgeScroll }),
1199
- },
1430
+ Option.match(maybeHold, {
1431
+ onNone: () => Stream.empty,
1432
+ onSome: edgeScroll,
1433
+ }),
1434
+ }
1200
1435
  ),
1201
1436
  resize: entry(
1202
1437
  { maybeHold: Schema.Option(SplitterHold) },
1203
1438
  {
1204
1439
  modelToDependencies: (model) => ({
1205
- maybeHold: Option.map(model.maybeResizing, ({ splitter, pointerId, pressX, pressY }) => ({
1206
- reelHook: model.id,
1207
- splitter,
1208
- pointerId,
1209
- pressX,
1210
- pressY,
1211
- })),
1440
+ maybeHold: Option.map(
1441
+ model.maybeResizing,
1442
+ ({ splitter, pointerId, pressX, pressY }) => ({
1443
+ reelHook: model.id,
1444
+ splitter,
1445
+ pointerId,
1446
+ pressX,
1447
+ pressY,
1448
+ })
1449
+ ),
1212
1450
  }),
1213
1451
  dependenciesToStream: ({ maybeHold }) =>
1214
1452
  Option.match(maybeHold, {
1215
1453
  onNone: () => Stream.empty,
1216
1454
  onSome: (hold) => Stream.merge(splitterMessages(hold), markDragging),
1217
1455
  }),
1218
- },
1456
+ }
1219
1457
  ),
1220
1458
  escape: entry(
1221
1459
  { isHolding: Schema.Boolean },
@@ -1225,7 +1463,7 @@ const reelSubscriptions = Subscription.make<Model, Message>()((entry) => ({
1225
1463
  }),
1226
1464
  dependenciesToStream: ({ isHolding: isHoldingNow }) =>
1227
1465
  isHoldingNow ? escapeKeys(Message.PressedEscape()) : Stream.empty,
1228
- },
1466
+ }
1229
1467
  ),
1230
1468
  }));
1231
1469
 
@@ -1237,28 +1475,29 @@ const reelSubscriptions = Subscription.make<Model, Message>()((entry) => ({
1237
1475
  export const subscriptions = <Prefix extends string>(keyPrefix: Prefix) =>
1238
1476
  prefixKeys(keyPrefix, reelSubscriptions);
1239
1477
 
1240
- // MOUNT
1241
-
1242
1478
  /** Sizes the copy that follows the pointer to what it lifts, and keeps the pointer where it
1243
1479
  * pressed. Measures the source once, when the copy appears. */
1244
1480
  export const SizeLiftedPane = Mount.define("SizeLiftedPane", {
1245
- args: { sourceSelector: Schema.String, pressX: Schema.Number, pressY: Schema.Number },
1481
+ args: {
1482
+ sourceSelector: Schema.String,
1483
+ pressX: Schema.Finite,
1484
+ pressY: Schema.Finite,
1485
+ },
1246
1486
  messages: [Message.CompletedSizeLiftedPane],
1247
1487
  execute: ({ element, sourceSelector, pressX, pressY }) =>
1248
1488
  Effect.sync(() => {
1249
1489
  measureLift(element, sourceSelector, pressX, pressY);
1490
+
1250
1491
  return Message.CompletedSizeLiftedPane();
1251
1492
  }),
1252
1493
  });
1253
1494
 
1254
- // VIEW
1255
-
1256
1495
  /** What the reel hands `toPaneView` for each pane: put `lead` in the Window's `lead` and give
1257
1496
  * it `id`. */
1258
1497
  export type PaneRender = Readonly<{
1259
1498
  /** The title bar's `lead`: the pane's grip, a quiet glyph button named "Move <label>", or
1260
1499
  * nothing under tabs, where a pane does not move. */
1261
- lead: ReadonlyArray<Html>;
1500
+ lead: readonly Html[];
1262
1501
  /** The window's id, unique in the document. */
1263
1502
  id: string;
1264
1503
  }>;
@@ -1278,7 +1517,7 @@ export type ViewInputs = Readonly<{
1278
1517
  * their tabs (`Tabs`). Pass the same to `perform`. */
1279
1518
  arrangement?: Arrangement;
1280
1519
  /** What a pane's tab prints before its label: a kind glyph. Nothing when not given. */
1281
- toTabLeadView?: (pane: Pane) => ReadonlyArray<Html>;
1520
+ toTabLeadView?: (pane: Pane) => readonly Html[];
1282
1521
  }>;
1283
1522
 
1284
1523
  type ReelInfo = Readonly<{
@@ -1293,10 +1532,9 @@ type ReelInfo = Readonly<{
1293
1532
 
1294
1533
  const helpId = (model: Model): string => `${model.id}-grip-help`;
1295
1534
 
1296
- /** The share of the reel or the column a splitter's arrow key moves. */
1297
1535
  const SPLITTER_STEP = 0.05;
1298
1536
 
1299
- const HELD_STEPS: Readonly<Record<string, Step>> = {
1537
+ const HELD_STEPS: Record.ReadonlyRecord<string, Step> = {
1300
1538
  ArrowUp: "Up",
1301
1539
  ArrowDown: "Down",
1302
1540
  ArrowLeft: "Left",
@@ -1305,57 +1543,75 @@ const HELD_STEPS: Readonly<Record<string, Step>> = {
1305
1543
 
1306
1544
  const isDropKey = (key: string): boolean => key === " " || key === "Enter";
1307
1545
 
1308
- /** The anchor every pane is pinned to under tabs: the one slot, the reel's full size. */
1309
1546
  const STAGE_ANCHOR = "--reel-stage";
1310
1547
 
1311
- /** The anchor that pins a pane to its slot. Pane ids are the application's, so the name is
1312
- * the pane's place in the id order, which the slot and the pane read from one list. */
1313
1548
  const anchorName = (index: number): string => `--reel-${index}`;
1314
1549
 
1315
- /** The panes in their layer's order: by id, which no move changes. */
1316
1550
  const byId = Order.mapInput(Order.String, (pane: Pane) => pane.id);
1317
1551
 
1318
- /** Where a carried drop would land, marked: none where it would change nothing. */
1552
+ const stableDomOrder = (layout: Layout): readonly Pane[] =>
1553
+ Array.sort(
1554
+ Array.flatMap(layout, (column) => column.panes),
1555
+ byId
1556
+ );
1557
+
1319
1558
  const markOf = (model: Model, layout: Layout): Option.Option<Target> =>
1320
1559
  Option.flatMap(Option.filter(model.maybeHeld, isCarried), (held) =>
1321
1560
  Option.filter(held.maybeTarget, (target) =>
1322
- Option.isSome(requestOf(layout, held.paneId, target)),
1323
- ),
1561
+ Option.isSome(requestOf(layout, held.paneId, target))
1562
+ )
1324
1563
  );
1325
1564
 
1326
1565
  const carriedIdOf = (model: Model): Option.Option<string> =>
1327
1566
  Option.map(Option.filter(model.maybeHeld, isCarried), ({ paneId }) => paneId);
1328
1567
 
1329
1568
  const gripView = (model: Model, pane: Pane, h: HtmlBuilder<Message>): Html => {
1330
- const maybeHeldHere = Option.filter(model.maybeHeld, (held) => held.paneId === pane.id);
1569
+ const maybeHeldHere = Option.filter(
1570
+ model.maybeHeld,
1571
+ (held) => held.paneId === pane.id
1572
+ );
1573
+
1331
1574
  const isHeld = Option.exists(maybeHeldHere, isCarried);
1332
- const isKeyboardHeld = Option.exists(maybeHeldHere, (held) => held.by._tag === "Keyboard");
1333
1575
 
1334
- // the keyboard holds an item on its grip: the keys are the grip's own, and focus leaving the
1335
- // grip puts the item back, so a field reached by Tab types as it should
1336
- const onGripKey: Attribute<Message> = h.OnKeyDownPreventDefault((key, modifiers) => {
1337
- if (!isPlain(modifiers)) {
1338
- return Option.none();
1339
- } else if (isKeyboardHeld) {
1340
- return isDropKey(key)
1341
- ? Option.some(Message.DroppedHeld())
1342
- : Option.map(Option.fromNullishOr(HELD_STEPS[key]), (step) =>
1343
- Message.SteppedHeld({ step }),
1344
- );
1345
- } else {
1576
+ const isKeyboardHeld = Option.exists(
1577
+ maybeHeldHere,
1578
+ (held) => held.by._tag === "Keyboard"
1579
+ );
1580
+
1581
+ const onGripKey: Attribute<Message> = h.OnKeyDownPreventDefault(
1582
+ (key, modifiers) => {
1583
+ if (!isPlain(modifiers)) {
1584
+ return Option.none();
1585
+ } else if (isKeyboardHeld) {
1586
+ return isDropKey(key)
1587
+ ? Option.some(Message.DroppedHeld())
1588
+ : Option.map(Record.get(HELD_STEPS, key), (step) =>
1589
+ Message.SteppedHeld({ step })
1590
+ );
1591
+ }
1592
+
1346
1593
  return Option.liftPredicate(
1347
1594
  Message.PressedGripKey({ paneId: pane.id }),
1348
- () => isIdle(model) && isDropKey(key),
1595
+ () => isIdle(model) && isDropKey(key)
1349
1596
  );
1350
1597
  }
1351
- });
1598
+ );
1352
1599
 
1353
1600
  const onGripPress: Attribute<Message> = h.OnPointerDown(
1354
- (_pointerType, button, _screenX, _screenY, _time, clientX, clientY, pointerId) =>
1601
+ (
1602
+ _pointerType,
1603
+ button,
1604
+ _screenX,
1605
+ _screenY,
1606
+ _time,
1607
+ clientX,
1608
+ clientY,
1609
+ pointerId
1610
+ ) =>
1355
1611
  Option.liftPredicate(
1356
1612
  Message.PressedGrip({ paneId: pane.id, pointerId, clientX, clientY }),
1357
- () => isIdle(model) && button === LEFT_BUTTON,
1358
- ),
1613
+ () => isIdle(model) && button === LEFT_BUTTON
1614
+ )
1359
1615
  );
1360
1616
 
1361
1617
  return IconButton.view(
@@ -1373,15 +1629,14 @@ const gripView = (model: Model, pane: Pane, h: HtmlBuilder<Message>): Html => {
1373
1629
  ...(isKeyboardHeld ? [h.OnBlur(Message.LeftGrip())] : []),
1374
1630
  ],
1375
1631
  },
1376
- h,
1632
+ h
1377
1633
  );
1378
1634
  };
1379
1635
 
1380
- /** A splitter's handlers: a pointer drags it, and its arrows step it by `SPLITTER_STEP`. */
1381
1636
  const reelSplitterAttributes = (
1382
1637
  model: Model,
1383
1638
  splitter: Splitter,
1384
- h: HtmlBuilder<Message>,
1639
+ h: HtmlBuilder<Message>
1385
1640
  ): ReadonlyArray<Attribute<Message>> =>
1386
1641
  splitterAttributes(
1387
1642
  {
@@ -1390,25 +1645,28 @@ const reelSplitterAttributes = (
1390
1645
  onPress: (pointerId, clientX, clientY) =>
1391
1646
  Message.PressedSplitter({ splitter, pointerId, clientX, clientY }),
1392
1647
  onStep: (direction) =>
1393
- Message.PressedSplitterKey({ splitter, share: direction * SPLITTER_STEP }),
1648
+ Message.PressedSplitterKey({
1649
+ splitter,
1650
+ share: direction * SPLITTER_STEP,
1651
+ }),
1394
1652
  },
1395
- h,
1653
+ h
1396
1654
  );
1397
1655
 
1398
- /** The pane a drop into `column` is marked on, and the class that marks it: the pane it would
1399
- * land before, or the last one when it would land at the end, the carried pane left out. */
1400
1656
  const dropMarkOf = (
1401
1657
  info: ReelInfo,
1402
- column: Column,
1658
+ column: Column
1403
1659
  ): Option.Option<Readonly<{ paneId: string; markClass: string }>> =>
1404
1660
  Option.flatMap(info.maybeMark, (mark) => {
1405
1661
  if (mark._tag !== "Into" || mark.columnId !== column.id) {
1406
1662
  return Option.none();
1407
1663
  }
1664
+
1408
1665
  const others = Array.filter(
1409
1666
  column.panes,
1410
- (pane) => !Option.contains(info.maybeCarriedId, pane.id),
1667
+ (pane) => !Option.contains(info.maybeCarriedId, pane.id)
1411
1668
  );
1669
+
1412
1670
  return Option.orElse(
1413
1671
  Option.map(Array.get(others, mark.index), ({ id }) => ({
1414
1672
  paneId: id,
@@ -1417,35 +1675,48 @@ const dropMarkOf = (
1417
1675
  () =>
1418
1676
  Option.map(
1419
1677
  Option.filter(Array.last(others), () => mark.index >= others.length),
1420
- ({ id }) => ({ paneId: id, markClass: " drop-after" }),
1421
- ),
1678
+ ({ id }) => ({ paneId: id, markClass: " drop-after" })
1679
+ )
1422
1680
  );
1423
1681
  });
1424
1682
 
1425
- const isGapMarked = (info: ReelInfo, maybeBeforeColumnId: Option.Option<string>): boolean =>
1683
+ const isGapMarked = (
1684
+ info: ReelInfo,
1685
+ maybeBeforeColumnId: Option.Option<string>
1686
+ ): boolean =>
1426
1687
  Option.exists(
1427
1688
  info.maybeMark,
1428
- (mark) => mark._tag === "Gap" && Equal.equals(mark.maybeBeforeColumnId, maybeBeforeColumnId),
1689
+ (mark) =>
1690
+ mark._tag === "Gap" &&
1691
+ Equal.equals(mark.maybeBeforeColumnId, maybeBeforeColumnId)
1429
1692
  );
1430
1693
 
1431
1694
  const slotView = (
1432
1695
  anchors: ReadonlyMap<string, string>,
1433
1696
  maybeDropMark: Option.Option<Readonly<{ paneId: string; markClass: string }>>,
1434
1697
  pane: Pane,
1435
- h: HtmlBuilder<Message>,
1698
+ h: HtmlBuilder<Message>
1436
1699
  ): Html =>
1437
1700
  h.keyed("div")(pane.id, [
1438
1701
  h.Class(
1439
1702
  `reel-slot${Option.match(
1440
1703
  Option.filter(maybeDropMark, ({ paneId }) => paneId === pane.id),
1441
- { onNone: () => "", onSome: ({ markClass }) => markClass },
1442
- )}`,
1704
+ { onNone: () => "", onSome: ({ markClass }) => markClass }
1705
+ )}`
1443
1706
  ),
1444
1707
  h.DataAttribute("reel-slot", pane.id),
1445
- h.Style({ "--reel-weight": `${pane.weight}`, "--reel-anchor": anchors.get(pane.id) ?? "none" }),
1708
+ h.Style({
1709
+ "--reel-weight": `${pane.weight}`,
1710
+ "--reel-anchor": anchors.get(pane.id) ?? "none",
1711
+ }),
1446
1712
  ]);
1447
1713
 
1448
- const splitView = (model: Model, above: Pane, share: number, h: HtmlBuilder<Message>): Html =>
1714
+ const splitView = (
1715
+ model: Model,
1716
+ above: Pane,
1717
+ share: number,
1718
+ h: HtmlBuilder<Message>
1719
+ ): Html =>
1449
1720
  h.keyed("div")(`split:${above.id}`, [
1450
1721
  h.Class("reel-split"),
1451
1722
  h.Role("separator"),
@@ -1455,7 +1726,11 @@ const splitView = (model: Model, above: Pane, share: number, h: HtmlBuilder<Mess
1455
1726
  h.AriaValuenow(Math.round(share * 100)),
1456
1727
  h.Tabindex(0),
1457
1728
  h.DataAttribute("reel-split", above.id),
1458
- ...reelSplitterAttributes(model, Splitter.Split({ abovePaneId: above.id }), h),
1729
+ ...reelSplitterAttributes(
1730
+ model,
1731
+ Splitter.Split({ abovePaneId: above.id }),
1732
+ h
1733
+ ),
1459
1734
  ]);
1460
1735
 
1461
1736
  const columnView = (
@@ -1463,19 +1738,21 @@ const columnView = (
1463
1738
  anchors: ReadonlyMap<string, string>,
1464
1739
  column: Column,
1465
1740
  index: number,
1466
- h: HtmlBuilder<Message>,
1467
- ): ReadonlyArray<Html> => {
1741
+ h: HtmlBuilder<Message>
1742
+ ): readonly Html[] => {
1468
1743
  const { model, layout } = info;
1469
1744
  const total = Number.sumAll(Array.map(column.panes, (pane) => pane.weight));
1470
1745
  const maybeDropMark = dropMarkOf(info, column);
1746
+
1471
1747
  const stack = Array.flatMap(column.panes, (pane, row) => [
1472
1748
  ...Array.fromOption(
1473
1749
  Option.map(Array.get(column.panes, row - 1), (above) =>
1474
- splitView(model, above, total > 0 ? above.weight / total : 0, h),
1475
- ),
1750
+ splitView(model, above, total > 0 ? above.weight / total : 0, h)
1751
+ )
1476
1752
  ),
1477
1753
  slotView(anchors, maybeDropMark, pane, h),
1478
1754
  ]);
1755
+
1479
1756
  const maybeNextId = Option.map(Array.get(layout, index + 1), ({ id }) => id);
1480
1757
 
1481
1758
  return [
@@ -1487,10 +1764,12 @@ const columnView = (
1487
1764
  h.DataAttribute("reel-hook", columnHook(model, column.id)),
1488
1765
  h.Style({ "--reel-width": `${column.width}` }),
1489
1766
  ],
1490
- stack,
1767
+ stack
1491
1768
  ),
1492
1769
  h.keyed("div")(`resize:${column.id}`, [
1493
- h.Class(`reel-gap reel-resize${isGapMarked(info, maybeNextId) ? " drop-here" : ""}`),
1770
+ h.Class(
1771
+ `reel-gap reel-resize${isGapMarked(info, maybeNextId) ? " drop-here" : ""}`
1772
+ ),
1494
1773
  h.Role("separator"),
1495
1774
  h.AriaLabel(fill(COPY.widthLabel, { column: index + 1 })),
1496
1775
  h.AriaValuemin(0),
@@ -1499,35 +1778,35 @@ const columnView = (
1499
1778
  h.AriaValuetext(widthWords(column.width)),
1500
1779
  h.Tabindex(0),
1501
1780
  h.DataAttribute("reel-resize", column.id),
1502
- ...reelSplitterAttributes(model, Splitter.Width({ columnId: column.id }), h),
1781
+ ...reelSplitterAttributes(
1782
+ model,
1783
+ Splitter.Width({ columnId: column.id }),
1784
+ h
1785
+ ),
1503
1786
  ]),
1504
1787
  ];
1505
1788
  };
1506
1789
 
1507
1790
  const paneLayerView = (
1508
1791
  info: ReelInfo,
1509
- panes: ReadonlyArray<Pane>,
1792
+ panesInDomOrder: readonly Pane[],
1510
1793
  anchors: ReadonlyMap<string, string>,
1511
- h: HtmlBuilder<Message>,
1794
+ h: HtmlBuilder<Message>
1512
1795
  ): Html => {
1513
1796
  const { model } = info;
1514
1797
 
1515
- // NOTE: the panes keep one order in the page, by id, whatever the layout or the arrangement:
1516
- // a move or a change to tabs changes only where each is anchored, so no pane's element is
1517
- // taken out and put back, which would drop focus, a terminal's scroll and whatever a Mount
1518
- // holds inside it. Under tabs the panes behind the focused one are hidden, not removed, and
1519
- // keep their size, so a terminal sized by its box is not resized as the tabs change.
1520
1798
  return h.div(
1521
1799
  [h.Class("reel-panes")],
1522
- Array.map(panes, (pane) => {
1800
+ Array.map(panesInDomOrder, (pane) => {
1523
1801
  const isFocused = Option.contains(info.maybeFocusedId, pane.id);
1524
1802
  const isHeld = Option.contains(info.maybeCarriedId, pane.id);
1525
1803
  const isBehind = info.isTabbed && !isFocused;
1804
+
1526
1805
  return h.keyed("div")(
1527
1806
  pane.id,
1528
1807
  [
1529
1808
  h.Class(
1530
- `reel-pane${isFocused ? " focused" : ""}${isHeld ? " drag-dim" : ""}${isBehind ? " behind" : ""}`,
1809
+ `reel-pane${isFocused ? " focused" : ""}${isHeld ? " drag-dim" : ""}${isBehind ? " behind" : ""}`
1531
1810
  ),
1532
1811
  h.DataAttribute("reel-pane", paneHook(model, pane.id)),
1533
1812
  h.Style({ "--reel-anchor": anchors.get(pane.id) ?? "none" }),
@@ -1540,15 +1819,16 @@ const paneLayerView = (
1540
1819
  lead: info.isTabbed ? [] : [gripView(model, pane, h)],
1541
1820
  id: `${model.id}-${pane.id}`,
1542
1821
  }),
1543
- ],
1822
+ ]
1544
1823
  );
1545
- }),
1824
+ })
1546
1825
  );
1547
1826
  };
1548
1827
 
1549
- /** The copy a pointer carries: the held pane's title bar, drawn by the reel from its label,
1550
- * so whatever a pane holds (a terminal, a canvas) is never built twice. */
1551
- const liftedCopyView = (info: ReelInfo, h: HtmlBuilder<Message>): ReadonlyArray<Html> => {
1828
+ const liftedCopyView = (
1829
+ info: ReelInfo,
1830
+ h: HtmlBuilder<Message>
1831
+ ): readonly Html[] => {
1552
1832
  const { model, layout } = info;
1553
1833
 
1554
1834
  return Array.fromOption(
@@ -1568,7 +1848,7 @@ const liftedCopyView = (info: ReelInfo, h: HtmlBuilder<Message>): ReadonlyArray<
1568
1848
  sourceSelector: `[data-reel-pane="${CSS.escape(paneHook(model, held.paneId))}"]`,
1569
1849
  pressX,
1570
1850
  pressY,
1571
- }),
1851
+ })
1572
1852
  ),
1573
1853
  ],
1574
1854
  [
@@ -1580,51 +1860,56 @@ const liftedCopyView = (info: ReelInfo, h: HtmlBuilder<Message>): ReadonlyArray<
1580
1860
  [
1581
1861
  h.span(
1582
1862
  [h.Class("panel-lead")],
1583
- [h.span([h.Class("iconbtn quiet")], [Glyph.view({ name: "grip" }, h)])],
1863
+ [
1864
+ h.span(
1865
+ [h.Class("iconbtn quiet")],
1866
+ [Glyph.view({ name: "grip" }, h)]
1867
+ ),
1868
+ ]
1584
1869
  ),
1585
1870
  h.h2([], [heldLabel(layout, held)]),
1586
- ],
1871
+ ]
1587
1872
  ),
1588
- ],
1873
+ ]
1589
1874
  ),
1590
- ],
1875
+ ]
1591
1876
  ),
1592
- () => isCarrying,
1877
+ () => isCarrying
1593
1878
  ),
1594
- }),
1595
- ),
1879
+ })
1880
+ )
1596
1881
  );
1597
1882
  };
1598
1883
 
1599
- /** The tab list under tabs: a tab per pane in reading order, the focused pane's selected. A
1600
- * press shows its pane and puts the keyboard in it; the side arrows (wrapping), Home and End
1601
- * select as they move and keep the keyboard on the tabs, only the selected tab being in the
1602
- * Tab order. A modified arrow is the application's. */
1603
1884
  const tabListView = (
1604
1885
  info: ReelInfo,
1605
1886
  label: string,
1606
- toTabLeadView: (pane: Pane) => ReadonlyArray<Html>,
1607
- h: HtmlBuilder<Message>,
1887
+ toTabLeadView: (pane: Pane) => readonly Html[],
1888
+ h: HtmlBuilder<Message>
1608
1889
  ): Html => {
1609
1890
  const { model, layout } = info;
1610
1891
  const panes = readingOrder(layout);
1892
+
1611
1893
  const stepTo = (index: number): Option.Option<Message> =>
1612
- Option.map(Array.get(panes, (index + panes.length) % panes.length), ({ id }) =>
1613
- Message.SteppedTab({ paneId: id }),
1894
+ Option.map(
1895
+ Array.get(panes, (index + panes.length) % panes.length),
1896
+ ({ id }) => Message.SteppedTab({ paneId: id })
1614
1897
  );
1898
+
1615
1899
  const keyOf = (index: number, key: string): Option.Option<Message> =>
1616
1900
  Match.value(key).pipe(
1617
1901
  Match.when("ArrowLeft", () => stepTo(index - 1)),
1618
1902
  Match.when("ArrowRight", () => stepTo(index + 1)),
1619
1903
  Match.when("Home", () => stepTo(0)),
1620
1904
  Match.when("End", () => stepTo(panes.length - 1)),
1621
- Match.orElse(() => Option.none()),
1905
+ Match.orElse(() => Option.none())
1622
1906
  );
1623
1907
 
1624
1908
  return h.div(
1625
1909
  [h.Class("nav tabs reel-tabs"), h.Role("tablist"), h.AriaLabel(label)],
1626
1910
  Array.map(panes, (pane, index) => {
1627
1911
  const isSelected = Option.contains(info.maybeFocusedId, pane.id);
1912
+
1628
1913
  return h.keyed("button")(
1629
1914
  pane.id,
1630
1915
  [
@@ -1636,22 +1921,24 @@ const tabListView = (
1636
1921
  h.DataAttribute("reel-tab", tabHook(model, pane.id)),
1637
1922
  h.OnClick(Message.PressedTab({ paneId: pane.id })),
1638
1923
  h.OnKeyDownPreventDefault((key, modifiers) =>
1639
- isPlain(modifiers) ? keyOf(index, key) : Option.none(),
1924
+ isPlain(modifiers) ? keyOf(index, key) : Option.none()
1640
1925
  ),
1641
1926
  ],
1642
- [...toTabLeadView(pane), h.span([h.Class("reel-tab-words")], [pane.label])],
1927
+ [
1928
+ ...toTabLeadView(pane),
1929
+ h.span([h.Class("reel-tab-words")], [pane.label]),
1930
+ ]
1643
1931
  );
1644
- }),
1932
+ })
1645
1933
  );
1646
1934
  };
1647
1935
 
1648
- const NO_TAB_LEAD = (): ReadonlyArray<Html> => [];
1936
+ const NO_TAB_LEAD = (): readonly Html[] => [];
1649
1937
 
1650
- /** The layout as it prints, with a dragged splitter's resize shown before it is asked for. */
1651
1938
  const previewed = (model: Model, layout: Layout): Layout =>
1652
1939
  Option.match(
1653
1940
  Option.flatMap(model.maybeResizing, ({ maybeResize }) => maybeResize),
1654
- { onNone: () => layout, onSome: (resize) => apply(layout, resize) },
1941
+ { onNone: () => layout, onSome: (resize) => apply(layout, resize) }
1655
1942
  );
1656
1943
 
1657
1944
  /**
@@ -1673,76 +1960,87 @@ const previewed = (model: Model, layout: Layout): Layout =>
1673
1960
  * full size where the columns were. Every pane is pinned to it, the focused one shown and the
1674
1961
  * others `.behind`, hidden and inert; there are no grips and no splitters.
1675
1962
  */
1676
- export const view = defineView<Model, Message, ViewInputs>((model, viewInputs, h): Html => {
1677
- const { label, toPaneView, arrangement = "Strip", toTabLeadView = NO_TAB_LEAD } = viewInputs;
1678
- const isTabbed = arrangement === "Tabs";
1679
- const layout = previewed(model, viewInputs.layout);
1680
- const panes = Array.sort(
1681
- Array.flatMap(layout, (column) => column.panes),
1682
- byId,
1683
- );
1684
- const anchors = new Map(
1685
- Array.map(
1686
- panes,
1687
- (pane, index) => [pane.id, isTabbed ? STAGE_ANCHOR : anchorName(index)] as const,
1688
- ),
1689
- );
1690
- const info: ReelInfo = {
1691
- model,
1692
- layout,
1693
- isTabbed,
1694
- toPaneView,
1695
- maybeFocusedId: focusedPaneId(model, layout),
1696
- maybeMark: markOf(model, layout),
1697
- maybeCarriedId: carriedIdOf(model),
1698
- };
1963
+ export const view = defineView<Model, Message, ViewInputs>(
1964
+ (model, viewInputs, h): Html => {
1965
+ const {
1966
+ label,
1967
+ toPaneView,
1968
+ arrangement = "Strip",
1969
+ toTabLeadView = NO_TAB_LEAD,
1970
+ } = viewInputs;
1971
+
1972
+ const isTabbed = arrangement === "Tabs";
1973
+ const layout = previewed(model, viewInputs.layout);
1974
+
1975
+ const panesInDomOrder = stableDomOrder(layout);
1976
+
1977
+ const anchors = new Map(
1978
+ Array.map(
1979
+ panesInDomOrder,
1980
+ (pane, index) =>
1981
+ [pane.id, isTabbed ? STAGE_ANCHOR : anchorName(index)] as const
1982
+ )
1983
+ );
1699
1984
 
1700
- const strip = (): ReadonlyArray<Html> => [
1701
- h.keyed("div")("gap:start", [
1702
- h.Class(
1703
- `reel-gap${
1704
- isGapMarked(
1705
- info,
1706
- Option.map(Array.head(layout), ({ id }) => id),
1707
- )
1708
- ? " drop-here"
1709
- : ""
1710
- }`,
1711
- ),
1712
- ]),
1713
- ...Array.flatMap(layout, (column, index) => columnView(info, anchors, column, index, h)),
1714
- ];
1985
+ const info: ReelInfo = {
1986
+ model,
1987
+ layout,
1988
+ isTabbed,
1989
+ toPaneView,
1990
+ maybeFocusedId: focusedPaneId(model, layout),
1991
+ maybeMark: markOf(model, layout),
1992
+ maybeCarriedId: carriedIdOf(model),
1993
+ };
1715
1994
 
1716
- return h.div(
1717
- [
1718
- h.Class(isTabbed ? "reel tabbed" : "reel"),
1719
- h.Role("group"),
1720
- h.AriaLabel(label),
1721
- h.DataAttribute("reel", model.id),
1722
- ],
1723
- [
1724
- ...(isTabbed ? [tabListView(info, label, toTabLeadView, h)] : []),
1725
- h.div(
1726
- [h.Class("reel-view")],
1727
- [
1728
- h.div(
1729
- [h.Class("reel-track")],
1730
- [
1731
- ...(isTabbed
1732
- ? [
1733
- h.div([
1734
- h.Class("reel-slot reel-stage"),
1735
- h.Style({ "--reel-anchor": STAGE_ANCHOR }),
1736
- ]),
1737
- ]
1738
- : strip()),
1739
- paneLayerView(info, panes, anchors, h),
1740
- ],
1741
- ),
1742
- ],
1995
+ const strip = (): readonly Html[] => [
1996
+ h.keyed("div")("gap:start", [
1997
+ h.Class(
1998
+ `reel-gap${
1999
+ isGapMarked(
2000
+ info,
2001
+ Option.map(Array.head(layout), ({ id }) => id)
2002
+ )
2003
+ ? " drop-here"
2004
+ : ""
2005
+ }`
2006
+ ),
2007
+ ]),
2008
+ ...Array.flatMap(layout, (column, index) =>
2009
+ columnView(info, anchors, column, index, h)
1743
2010
  ),
1744
- h.p([h.Id(helpId(model)), h.Class("sr-only")], [COPY.gripHelp]),
1745
- ...liftedCopyView(info, h),
1746
- ],
1747
- );
1748
- });
2011
+ ];
2012
+
2013
+ return h.div(
2014
+ [
2015
+ h.Class(isTabbed ? "reel tabbed" : "reel"),
2016
+ h.Role("group"),
2017
+ h.AriaLabel(label),
2018
+ h.DataAttribute("reel", model.id),
2019
+ ],
2020
+ [
2021
+ ...(isTabbed ? [tabListView(info, label, toTabLeadView, h)] : []),
2022
+ h.div(
2023
+ [h.Class("reel-view")],
2024
+ [
2025
+ h.div(
2026
+ [h.Class("reel-track")],
2027
+ [
2028
+ ...(isTabbed
2029
+ ? [
2030
+ h.div([
2031
+ h.Class("reel-slot reel-stage"),
2032
+ h.Style({ "--reel-anchor": STAGE_ANCHOR }),
2033
+ ]),
2034
+ ]
2035
+ : strip()),
2036
+ paneLayerView(info, panesInDomOrder, anchors, h),
2037
+ ]
2038
+ ),
2039
+ ]
2040
+ ),
2041
+ h.p([h.Id(helpId(model)), h.Class("sr-only")], [COPY.gripHelp]),
2042
+ ...liftedCopyView(info, h),
2043
+ ]
2044
+ );
2045
+ }
2046
+ );