flea-qml 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (625) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +478 -2
  3. package/THIRD-PARTY-NOTICES.md +29 -0
  4. package/demos/App.java +5 -0
  5. package/demos/Dockerfile +4 -0
  6. package/demos/Main.kt +3 -0
  7. package/demos/Program.cs +1 -0
  8. package/demos/README.md +12 -0
  9. package/demos/app.dart +3 -0
  10. package/demos/app.deb +0 -0
  11. package/demos/app.js +1 -0
  12. package/demos/backup.tar +0 -0
  13. package/demos/budget.xlsx +0 -0
  14. package/demos/build.sh +2 -0
  15. package/demos/bundle.zip +0 -0
  16. package/demos/clip.mp4 +0 -0
  17. package/demos/data.sqlite +0 -0
  18. package/demos/disk.iso +0 -0
  19. package/demos/engine.cpp +5 -0
  20. package/demos/firmware.bin +0 -0
  21. package/demos/flake.nix +4 -0
  22. package/demos/folder/inside.txt +1 -0
  23. package/demos/font.ttf +0 -0
  24. package/demos/index.html +5 -0
  25. package/demos/index.php +2 -0
  26. package/demos/init.lua +1 -0
  27. package/demos/letter.docx +0 -0
  28. package/demos/lib.rs +3 -0
  29. package/demos/main.c +6 -0
  30. package/demos/main.h +3 -0
  31. package/demos/math-and-diagrams.md +200 -0
  32. package/demos/notes.tar.gz +0 -0
  33. package/demos/notes.txt +3 -0
  34. package/demos/photo.png +0 -0
  35. package/demos/program +2 -0
  36. package/demos/report.pdf +32 -0
  37. package/demos/script.py +1 -0
  38. package/demos/server.go +7 -0
  39. package/demos/settings.json +4 -0
  40. package/demos/slides.pptx +0 -0
  41. package/demos/song.mp3 +0 -0
  42. package/demos/style.css +4 -0
  43. package/demos/tool.rb +1 -0
  44. package/demos/types.ts +2 -0
  45. package/docs/pele.md +23 -0
  46. package/docs/protocol.md +3420 -0
  47. package/docs/temml.md +63 -0
  48. package/index.js +107 -0
  49. package/package.json +34 -4
  50. package/src/archive.js +402 -0
  51. package/src/archiveops.js +697 -0
  52. package/src/backend.js +369 -0
  53. package/src/bulkrename.js +95 -0
  54. package/src/clip-host.js +76 -0
  55. package/src/clip.js +462 -0
  56. package/src/code.js +168 -0
  57. package/src/compare.js +74 -0
  58. package/src/create.js +128 -0
  59. package/src/dirsize.js +147 -0
  60. package/src/figure-svg.js +530 -0
  61. package/src/figure-thread.js +23 -0
  62. package/src/figure.js +132 -0
  63. package/src/find.js +55 -0
  64. package/src/flea.js +39 -0
  65. package/src/fsinfo.js +39 -0
  66. package/src/highlight.js +141 -0
  67. package/src/html.js +52 -0
  68. package/src/kinds.js +89 -0
  69. package/src/listing.js +130 -0
  70. package/src/markdown-html.js +317 -0
  71. package/src/mathml.js +186 -0
  72. package/src/menu.js +180 -0
  73. package/src/meta.js +129 -0
  74. package/src/office.js +810 -0
  75. package/src/order.js +100 -0
  76. package/src/peek.js +49 -0
  77. package/src/pele-wrapper.js +695 -0
  78. package/src/permissions.js +180 -0
  79. package/src/places.js +313 -0
  80. package/src/preview-language.js +10 -0
  81. package/src/transfer.js +669 -0
  82. package/src/trash-record.js +41 -0
  83. package/src/trash.js +210 -0
  84. package/src/trashbrowse.js +326 -0
  85. package/src/uistate.js +393 -0
  86. package/src/uistore.js +168 -0
  87. package/src/vendor/LICENSES/Apache-2.0.txt +202 -0
  88. package/src/vendor/LICENSES/MIT-katex-2015.txt +27 -0
  89. package/src/vendor/LICENSES/MIT-katex.txt +21 -0
  90. package/src/vendor/LICENSES/MIT-mermaid.txt +21 -0
  91. package/src/vendor/LICENSES/MIT-pele.txt +40 -0
  92. package/src/vendor/LICENSES/MIT-perseus.txt +18 -0
  93. package/src/vendor/LICENSES/MIT-temml.txt +21 -0
  94. package/src/vendor/pele.js +145 -0
  95. package/src/vendor/temml.mjs +14708 -0
  96. package/src/watch.js +98 -0
  97. package/src/wayland/client.js +109 -0
  98. package/src/wayland/protocol.js +55 -0
  99. package/src/wayland/protocols/ext-data-control-v1.xml +276 -0
  100. package/src/wayland/protocols/wayland.xml +3248 -0
  101. package/src/wayland/protocols/wlr-data-control-unstable-v1.xml +278 -0
  102. package/src/wayland/resource-io.js +6 -0
  103. package/src/wayland/socket-discovery.js +26 -0
  104. package/src/wayland/transport-posix.js +120 -0
  105. package/src/wayland/transport-win32.js +11 -0
  106. package/src/wayland/transport.js +3 -0
  107. package/src/wayland/win32-resources.js +80 -0
  108. package/src/wayland/win32-wire.js +62 -0
  109. package/test/archive.test.js +80 -0
  110. package/test/bench-markdown-scroll.mjs +190 -0
  111. package/test/clip-host.test.js +113 -0
  112. package/test/code-preview.test.js +35 -0
  113. package/test/compare-ui-paths.test.js +24 -0
  114. package/test/compare.test.js +54 -0
  115. package/test/delete-trash.test.js +67 -0
  116. package/test/dirsize.test.js +138 -0
  117. package/test/file-ops.test.js +241 -0
  118. package/test/find-contents.test.js +161 -0
  119. package/test/find-input.test.js +66 -0
  120. package/test/fixtures/pele-parity.json +1006 -0
  121. package/test/highlight-launcher.test.js +35 -0
  122. package/test/html-preview.test.js +22 -0
  123. package/test/input.test.js +15 -0
  124. package/test/keymap.test.js +26 -0
  125. package/test/language-icons.test.js +36 -0
  126. package/test/launcher.test.js +51 -0
  127. package/test/manual-code-scroll.mjs +28 -0
  128. package/test/manual-column-scroll.mjs +24 -0
  129. package/test/manual-compare-ui.mjs +20 -0
  130. package/test/manual-find-status.mjs +37 -0
  131. package/test/manual-html-security.mjs +23 -0
  132. package/test/manual-html-ui.mjs +30 -0
  133. package/test/manual-syntax-preview.mjs +26 -0
  134. package/test/manual-trash-ui.mjs +86 -0
  135. package/test/markdown-diagrams.test.js +93 -0
  136. package/test/markdown-html.test.js +105 -0
  137. package/test/mathml.test.js +92 -0
  138. package/test/menu-transfer.test.js +57 -0
  139. package/test/office-preview.test.js +154 -0
  140. package/test/pele-parity.test.js +28 -0
  141. package/test/places.test.js +134 -0
  142. package/test/preview-keys.test.js +60 -0
  143. package/test/preview-language.test.js +22 -0
  144. package/test/status-filename.test.js +20 -0
  145. package/test/transfer-replace-merge.test.js +187 -0
  146. package/test/trash-address.test.js +23 -0
  147. package/test/trash-view.test.js +37 -0
  148. package/test/trashbrowse.test.js +135 -0
  149. package/ui/AboutFacts.qml +78 -0
  150. package/ui/ArchiveCards.qml +68 -0
  151. package/ui/ArchiveCompressDialog.qml +378 -0
  152. package/ui/ArchivePasswordDialog.qml +257 -0
  153. package/ui/Backend.qml +771 -0
  154. package/ui/BulkOldNames.qml +47 -0
  155. package/ui/BulkRenameDialog.qml +380 -0
  156. package/ui/CardFrame.qml +67 -0
  157. package/ui/CardScroll.qml +79 -0
  158. package/ui/CheckBox.qml +73 -0
  159. package/ui/ChromeBar.qml +360 -0
  160. package/ui/ChromeButton.qml +131 -0
  161. package/ui/ChromeModes.qml +43 -0
  162. package/ui/CodeLines.qml +256 -0
  163. package/ui/CodeRefusal.qml +52 -0
  164. package/ui/CollideConfirm.qml +147 -0
  165. package/ui/CollideHost.qml +167 -0
  166. package/ui/ColumnPane.qml +523 -0
  167. package/ui/ColumnRow.qml +380 -0
  168. package/ui/ColumnsArea.qml +594 -0
  169. package/ui/ColumnsLanding.qml +147 -0
  170. package/ui/CompareView.qml +321 -0
  171. package/ui/ContextMenu.qml +743 -0
  172. package/ui/ConvertDialog.qml +456 -0
  173. package/ui/CountedWorker.qml +7 -0
  174. package/ui/Crumb.qml +64 -0
  175. package/ui/CrumbDrop.qml +25 -0
  176. package/ui/CsvTable.qml +394 -0
  177. package/ui/CursorMark.qml +41 -0
  178. package/ui/DefaultClaim.qml +130 -0
  179. package/ui/DeviceLock.qml +47 -0
  180. package/ui/DeviceMounts.qml +540 -0
  181. package/ui/DialogButton.qml +150 -0
  182. package/ui/DialogField.qml +147 -0
  183. package/ui/DialogHeader.qml +31 -0
  184. package/ui/DialogScrim.qml +20 -0
  185. package/ui/DialogTitle.qml +37 -0
  186. package/ui/Divider.qml +9 -0
  187. package/ui/DropInto.qml +126 -0
  188. package/ui/DropTarget.qml +35 -0
  189. package/ui/DropboxMark.qml +60 -0
  190. package/ui/EmptyState.qml +150 -0
  191. package/ui/EscapeHint.qml +11 -0
  192. package/ui/FactsTable.qml +54 -0
  193. package/ui/FastScrollHandler.qml +476 -0
  194. package/ui/FatNamesConfirm.qml +157 -0
  195. package/ui/Favourites.qml +143 -0
  196. package/ui/FigureService.qml +120 -0
  197. package/ui/FileDrag.qml +267 -0
  198. package/ui/FilterStrip.qml +133 -0
  199. package/ui/FitMetrics.qml +22 -0
  200. package/ui/FlashDriveRows.qml +137 -0
  201. package/ui/FlashHost.qml +72 -0
  202. package/ui/FlashImageRow.qml +104 -0
  203. package/ui/FlashRunner.qml +119 -0
  204. package/ui/FlashStepRow.qml +172 -0
  205. package/ui/FlashStrip.qml +38 -0
  206. package/ui/FlashView.qml +397 -0
  207. package/ui/FleaMark.qml +88 -0
  208. package/ui/FlyoutFade.qml +23 -0
  209. package/ui/FontPane.qml +170 -0
  210. package/ui/Glass.qml +114 -0
  211. package/ui/GlassTagger.qml +59 -0
  212. package/ui/Glyph.qml +64 -0
  213. package/ui/GlyphSolid.qml +22 -0
  214. package/ui/GridArea.qml +664 -0
  215. package/ui/GridTile.qml +325 -0
  216. package/ui/GvfsBridge.qml +164 -0
  217. package/ui/Header.qml +433 -0
  218. package/ui/HoverTimers.qml +39 -0
  219. package/ui/HtmlClip.qml +30 -0
  220. package/ui/HtmlPane.qml +63 -0
  221. package/ui/HyprlandMark.qml +45 -0
  222. package/ui/Ipc.qml +1005 -0
  223. package/ui/IpcControls.qml +7 -0
  224. package/ui/IpcMenuState.qml +48 -0
  225. package/ui/IpcPreviewState.qml +185 -0
  226. package/ui/JumpPath.qml +51 -0
  227. package/ui/KeymapSheet.qml +561 -0
  228. package/ui/KeymapSheetResult.qml +89 -0
  229. package/ui/KindStack.qml +40 -0
  230. package/ui/LangMark.qml +51 -0
  231. package/ui/LangMarkLoader.qml +26 -0
  232. package/ui/List.qml +480 -0
  233. package/ui/LoadingState.qml +54 -0
  234. package/ui/LocalSend.qml +56 -0
  235. package/ui/LocalSendMark.qml +73 -0
  236. package/ui/MarkdownBlockView.qml +311 -0
  237. package/ui/MarkdownBlocks.qml +35 -0
  238. package/ui/MarkdownFigure.qml +254 -0
  239. package/ui/MarkdownImages.qml +72 -0
  240. package/ui/MarkdownList.qml +81 -0
  241. package/ui/MarkdownMathsText.qml +97 -0
  242. package/ui/MarkdownPane.qml +83 -0
  243. package/ui/MarkdownPictures.qml +41 -0
  244. package/ui/MarkdownQuote.qml +52 -0
  245. package/ui/MarkdownRemote.qml +82 -0
  246. package/ui/MarkdownSource.qml +155 -0
  247. package/ui/MarkdownTable.qml +222 -0
  248. package/ui/MarkdownTableScroll.qml +64 -0
  249. package/ui/MarkdownTableWheel.qml +126 -0
  250. package/ui/MarkdownText.qml +87 -0
  251. package/ui/MarkdownWorker.js +132 -0
  252. package/ui/MatchText.qml +99 -0
  253. package/ui/MediaSession.qml +38 -0
  254. package/ui/MediaSound.qml +26 -0
  255. package/ui/MediaStrip.qml +191 -0
  256. package/ui/MediaTrack.qml +36 -0
  257. package/ui/MediaVolume.qml +54 -0
  258. package/ui/MenuActionDialog.qml +396 -0
  259. package/ui/MenuEdgeFade.qml +24 -0
  260. package/ui/MenuHost.qml +227 -0
  261. package/ui/MenuRow.qml +351 -0
  262. package/ui/MountListing.qml +100 -0
  263. package/ui/NetworkDialog.qml +435 -0
  264. package/ui/NetworkForm.qml +426 -0
  265. package/ui/NetworkMounts.qml +913 -0
  266. package/ui/NetworkPlaces.qml +127 -0
  267. package/ui/OpenWithDialog.qml +613 -0
  268. package/ui/Opener.qml +115 -0
  269. package/ui/Pane.qml +1296 -0
  270. package/ui/PaneMenuActions.qml +527 -0
  271. package/ui/PanePath.qml +90 -0
  272. package/ui/PaneRail.qml +239 -0
  273. package/ui/PaneStates.qml +88 -0
  274. package/ui/PaneSwap.qml +339 -0
  275. package/ui/PaneWire.qml +605 -0
  276. package/ui/ParkedWait.qml +9 -0
  277. package/ui/PathEntry.qml +186 -0
  278. package/ui/PathJump.qml +400 -0
  279. package/ui/PdfViewer.qml +297 -0
  280. package/ui/PermissionsDialog.qml +658 -0
  281. package/ui/PermissionsHeadings.qml +31 -0
  282. package/ui/PhoneMounts.qml +67 -0
  283. package/ui/PickerAnswers.qml +75 -0
  284. package/ui/PickerBox.qml +26 -0
  285. package/ui/PickerChrome.qml +295 -0
  286. package/ui/PickerFilter.qml +97 -0
  287. package/ui/PickerGrid.qml +308 -0
  288. package/ui/PickerHeader.qml +28 -0
  289. package/ui/PickerLifecycle.qml +27 -0
  290. package/ui/PickerList.qml +218 -0
  291. package/ui/PickerListing.qml +149 -0
  292. package/ui/PickerPathBar.qml +127 -0
  293. package/ui/PickerPlaces.qml +189 -0
  294. package/ui/PickerRecent.qml +92 -0
  295. package/ui/PickerSave.qml +101 -0
  296. package/ui/PickerSelection.qml +155 -0
  297. package/ui/PickerWindow.qml +846 -0
  298. package/ui/PowerSectorsReader.qml +10 -0
  299. package/ui/PrebuildDriver.qml +146 -0
  300. package/ui/Preview.qml +1004 -0
  301. package/ui/PreviewAnimation.qml +24 -0
  302. package/ui/PreviewArchive.qml +66 -0
  303. package/ui/PreviewColumn.qml +551 -0
  304. package/ui/PreviewEdge.qml +63 -0
  305. package/ui/PreviewFacts.qml +30 -0
  306. package/ui/PreviewFactsLine.qml +34 -0
  307. package/ui/PreviewHtml.qml +233 -0
  308. package/ui/PreviewImage.qml +253 -0
  309. package/ui/PreviewImagePan.qml +13 -0
  310. package/ui/PreviewImageSharp.qml +32 -0
  311. package/ui/PreviewLines.qml +106 -0
  312. package/ui/PreviewMarkdown.qml +706 -0
  313. package/ui/PreviewMedia.qml +250 -0
  314. package/ui/PreviewPdf.qml +482 -0
  315. package/ui/PreviewScroll.qml +201 -0
  316. package/ui/PreviewSwap.qml +335 -0
  317. package/ui/PreviewText.qml +149 -0
  318. package/ui/ProtocolChip.qml +18 -0
  319. package/ui/QuickLookArchive.qml +38 -0
  320. package/ui/QuickLookBar.qml +103 -0
  321. package/ui/QuickLookPrepare.qml +355 -0
  322. package/ui/QuickLookSwap.qml +10 -0
  323. package/ui/QuickLookWarm.qml +65 -0
  324. package/ui/RailDrop.qml +155 -0
  325. package/ui/RailHeading.qml +19 -0
  326. package/ui/RailPlaces.qml +38 -0
  327. package/ui/RailTrashRow.qml +67 -0
  328. package/ui/RenameField.qml +353 -0
  329. package/ui/RendererRetry.qml +11 -0
  330. package/ui/ResizeHandle.qml +52 -0
  331. package/ui/Reveal.qml +54 -0
  332. package/ui/Row.qml +476 -0
  333. package/ui/RowDrag.qml +213 -0
  334. package/ui/RowDropTarget.qml +27 -0
  335. package/ui/RunCard.qml +286 -0
  336. package/ui/Scripts.qml +65 -0
  337. package/ui/SearchStrip.qml +232 -0
  338. package/ui/SelectionBand.qml +140 -0
  339. package/ui/SelectionPreview.qml +370 -0
  340. package/ui/SettingsFavourite.qml +122 -0
  341. package/ui/SettingsGroup.qml +96 -0
  342. package/ui/SettingsHint.qml +12 -0
  343. package/ui/SettingsMetrics.qml +29 -0
  344. package/ui/SettingsPane.qml +178 -0
  345. package/ui/SettingsPanel.qml +547 -0
  346. package/ui/SettingsRail.qml +128 -0
  347. package/ui/SettingsRow.qml +409 -0
  348. package/ui/SettingsRuler.qml +85 -0
  349. package/ui/SettingsSegment.qml +85 -0
  350. package/ui/ShareBrowser.qml +113 -0
  351. package/ui/ShareLink.qml +67 -0
  352. package/ui/ShelfPins.qml +101 -0
  353. package/ui/Sidebar.qml +732 -0
  354. package/ui/SidebarRow.qml +358 -0
  355. package/ui/Spinner.qml +60 -0
  356. package/ui/StableModel.qml +89 -0
  357. package/ui/StateMessage.qml +84 -0
  358. package/ui/StatusBar.qml +512 -0
  359. package/ui/StatusFileName.qml +27 -0
  360. package/ui/TabBar.qml +673 -0
  361. package/ui/TabDragGeometry.qml +60 -0
  362. package/ui/TagMenuMark.qml +52 -0
  363. package/ui/TagRailSection.qml +53 -0
  364. package/ui/TagSlot.qml +40 -0
  365. package/ui/TagState.qml +150 -0
  366. package/ui/TagSwatch.qml +28 -0
  367. package/ui/Taildrop.qml +86 -0
  368. package/ui/TailscaleMark.qml +50 -0
  369. package/ui/Theme.qml +460 -0
  370. package/ui/ThemeColors.qml +43 -0
  371. package/ui/TransferCard.qml +239 -0
  372. package/ui/TrashConfirm.qml +129 -0
  373. package/ui/TrashDropHandler.qml +11 -0
  374. package/ui/TrashHost.qml +202 -0
  375. package/ui/TrashMonitor.qml +30 -0
  376. package/ui/TrashToolbar.qml +19 -0
  377. package/ui/TrashView.qml +492 -0
  378. package/ui/UnlockDialog.qml +450 -0
  379. package/ui/UnlockHost.qml +206 -0
  380. package/ui/UpdateCheck.qml +97 -0
  381. package/ui/UserDirs.qml +25 -0
  382. package/ui/ViewState.qml +565 -0
  383. package/ui/ViewportScrollBar.qml +195 -0
  384. package/ui/ViewportScrollBars.qml +25 -0
  385. package/ui/WebPreview.qml +33 -0
  386. package/ui/WebPreviewView.qml +26 -0
  387. package/ui/WindowBody.qml +827 -0
  388. package/ui/WindowDrag.qml +35 -0
  389. package/ui/boot/Commons/AudioNodes.qml +50 -0
  390. package/ui/boot/Commons/AudioNodesModel.js +96 -0
  391. package/ui/boot/Commons/Border.qml +243 -0
  392. package/ui/boot/Commons/BorderGeometry.js +373 -0
  393. package/ui/boot/Commons/Color.qml +258 -0
  394. package/ui/boot/Commons/I18n.qml +118 -0
  395. package/ui/boot/Commons/InputDevices.qml +112 -0
  396. package/ui/boot/Commons/InputMethodState.qml +38 -0
  397. package/ui/boot/Commons/IpcRegistry.qml +77 -0
  398. package/ui/boot/Commons/Numbers.js +19 -0
  399. package/ui/boot/Commons/Plural.js +91 -0
  400. package/ui/boot/Commons/ShellIpc.qml +12 -0
  401. package/ui/boot/Commons/Style.qml +561 -0
  402. package/ui/boot/Commons/Translations.qml +100 -0
  403. package/ui/boot/Commons/UntypedInput.qml +152 -0
  404. package/ui/boot/Commons/Util.qml +188 -0
  405. package/ui/boot/Commons/qmldir +13 -0
  406. package/ui/boot/LICENSE-omarchy +20 -0
  407. package/ui/boot/Ui/BackgroundMedia.qml +49 -0
  408. package/ui/boot/Ui/BarIconButton.qml +106 -0
  409. package/ui/boot/Ui/BarIconContent.qml +38 -0
  410. package/ui/boot/Ui/BarIndicator.qml +53 -0
  411. package/ui/boot/Ui/BarWidget.qml +50 -0
  412. package/ui/boot/Ui/BorderOverlay.qml +54 -0
  413. package/ui/boot/Ui/BorderSurface.qml +40 -0
  414. package/ui/boot/Ui/Button.qml +224 -0
  415. package/ui/boot/Ui/ButtonGroup.qml +131 -0
  416. package/ui/boot/Ui/ConfirmDialog.qml +134 -0
  417. package/ui/boot/Ui/CursorSurface.qml +42 -0
  418. package/ui/boot/Ui/Dropdown.qml +245 -0
  419. package/ui/boot/Ui/FilterInput.qml +26 -0
  420. package/ui/boot/Ui/IconContentBounds.qml +141 -0
  421. package/ui/boot/Ui/KeyboardPanel.qml +453 -0
  422. package/ui/boot/Ui/MultiSelect.qml +624 -0
  423. package/ui/boot/Ui/NumberField.qml +86 -0
  424. package/ui/boot/Ui/OpticalGlyph.qml +68 -0
  425. package/ui/boot/Ui/OverlayWindow.qml +102 -0
  426. package/ui/boot/Ui/Panel.qml +60 -0
  427. package/ui/boot/Ui/PanelActionButton.qml +105 -0
  428. package/ui/boot/Ui/PanelController.qml +16 -0
  429. package/ui/boot/Ui/PanelHero.qml +112 -0
  430. package/ui/boot/Ui/PanelKeyCatcher.qml +100 -0
  431. package/ui/boot/Ui/PanelSectionHeader.qml +31 -0
  432. package/ui/boot/Ui/PanelSeparator.qml +19 -0
  433. package/ui/boot/Ui/PanelSlider.qml +156 -0
  434. package/ui/boot/Ui/PanelToolTip.qml +50 -0
  435. package/ui/boot/Ui/PluginBarApi.qml +89 -0
  436. package/ui/boot/Ui/PointerMoveGate.qml +54 -0
  437. package/ui/boot/Ui/PopupCard.qml +181 -0
  438. package/ui/boot/Ui/ScreenMoveRemap.qml +43 -0
  439. package/ui/boot/Ui/SearchableDropdown.qml +354 -0
  440. package/ui/boot/Ui/SizedImage.qml +125 -0
  441. package/ui/boot/Ui/SpeedTestOverlay.qml +412 -0
  442. package/ui/boot/Ui/TextField.qml +58 -0
  443. package/ui/boot/Ui/Toggle.qml +118 -0
  444. package/ui/boot/Ui/ToggleSwitch.qml +115 -0
  445. package/ui/boot/Ui/WidgetButton.qml +172 -0
  446. package/ui/boot/Ui/qmldir +41 -0
  447. package/ui/boot/fleatab.qml +50 -0
  448. package/ui/boot/picker.qml +39 -0
  449. package/ui/boot/shell.qml +122 -0
  450. package/ui/boot/tabtearoff.qml +51 -0
  451. package/ui/js/Anchor.js +379 -0
  452. package/ui/js/AnchorHold.js +162 -0
  453. package/ui/js/Archive.js +157 -0
  454. package/ui/js/ArchiveCard.js +44 -0
  455. package/ui/js/ArchiveOps.js +44 -0
  456. package/ui/js/BackReturn.js +118 -0
  457. package/ui/js/BulkRename.js +100 -0
  458. package/ui/js/Buttons.js +54 -0
  459. package/ui/js/ChromeKeys.js +116 -0
  460. package/ui/js/ClipMarks.js +73 -0
  461. package/ui/js/ClipSelection.js +67 -0
  462. package/ui/js/Clipboard.js +179 -0
  463. package/ui/js/Cloud.js +97 -0
  464. package/ui/js/CodeRuns.js +72 -0
  465. package/ui/js/Collide.js +212 -0
  466. package/ui/js/ColumnFit.js +28 -0
  467. package/ui/js/ColumnMenu.js +111 -0
  468. package/ui/js/Columns.js +298 -0
  469. package/ui/js/ColumnsCarry.js +103 -0
  470. package/ui/js/Compare.js +74 -0
  471. package/ui/js/Contrast.js +157 -0
  472. package/ui/js/ControlReader.js +42 -0
  473. package/ui/js/Convert.js +52 -0
  474. package/ui/js/CopyAs.js +52 -0
  475. package/ui/js/Crumbs.js +178 -0
  476. package/ui/js/Csv.js +231 -0
  477. package/ui/js/Density.js +44 -0
  478. package/ui/js/Devices.js +440 -0
  479. package/ui/js/DirSizes.js +180 -0
  480. package/ui/js/Drag.js +364 -0
  481. package/ui/js/DragOut.js +166 -0
  482. package/ui/js/DropDev.js +52 -0
  483. package/ui/js/Dropbox.js +41 -0
  484. package/ui/js/Eject.js +217 -0
  485. package/ui/js/Errors.js +188 -0
  486. package/ui/js/ExtThumbs.js +115 -0
  487. package/ui/js/Facts.js +402 -0
  488. package/ui/js/FigureDate.js +14 -0
  489. package/ui/js/Filter.js +285 -0
  490. package/ui/js/Find.js +46 -0
  491. package/ui/js/Flash.js +184 -0
  492. package/ui/js/FlashCard.js +79 -0
  493. package/ui/js/FlashEndings.js +125 -0
  494. package/ui/js/FlashPane.js +116 -0
  495. package/ui/js/FleaBin.js +12 -0
  496. package/ui/js/Focus.js +502 -0
  497. package/ui/js/FolderSorts.js +108 -0
  498. package/ui/js/FolderViews.js +44 -0
  499. package/ui/js/Format.js +305 -0
  500. package/ui/js/Fuzzy.js +141 -0
  501. package/ui/js/GlassTag.js +72 -0
  502. package/ui/js/Grid.js +33 -0
  503. package/ui/js/GridGeometry.js +90 -0
  504. package/ui/js/GridNames.js +153 -0
  505. package/ui/js/GvfsBridge.js +200 -0
  506. package/ui/js/HostClipboard.js +29 -0
  507. package/ui/js/Icons.js +218 -0
  508. package/ui/js/Input.js +50 -0
  509. package/ui/js/Jump.js +200 -0
  510. package/ui/js/KeyName.js +64 -0
  511. package/ui/js/Keymap.js +401 -0
  512. package/ui/js/Kinds.js +164 -0
  513. package/ui/js/LICENSES/ISC-lucide.txt +43 -0
  514. package/ui/js/LangMarkPaths.js +47 -0
  515. package/ui/js/LangMarks.js +120 -0
  516. package/ui/js/Lists.js +11 -0
  517. package/ui/js/LocalSend.js +39 -0
  518. package/ui/js/LockedMenu.js +63 -0
  519. package/ui/js/MakeDefault.js +186 -0
  520. package/ui/js/MarkBox.js +7 -0
  521. package/ui/js/Markdown.js +119 -0
  522. package/ui/js/MarkdownLists.js +86 -0
  523. package/ui/js/MarkdownMaths.js +58 -0
  524. package/ui/js/MarkdownPictures.js +32 -0
  525. package/ui/js/MarkdownPrepared.js +139 -0
  526. package/ui/js/MarkdownTableFit.js +34 -0
  527. package/ui/js/Marks.js +148 -0
  528. package/ui/js/Marquee.js +96 -0
  529. package/ui/js/Match.js +93 -0
  530. package/ui/js/Material.js +109 -0
  531. package/ui/js/MdBlocks.js +437 -0
  532. package/ui/js/MdBreak.js +71 -0
  533. package/ui/js/MdChunks.js +70 -0
  534. package/ui/js/MdContainer.js +137 -0
  535. package/ui/js/MdDocument.js +337 -0
  536. package/ui/js/MdEmph.js +97 -0
  537. package/ui/js/MdEntity.js +108 -0
  538. package/ui/js/MdEntityTable.js +223 -0
  539. package/ui/js/MdEscape.js +59 -0
  540. package/ui/js/MdFront.js +37 -0
  541. package/ui/js/MdHold.js +32 -0
  542. package/ui/js/MdHtml.js +307 -0
  543. package/ui/js/MdHtmlBlock.js +290 -0
  544. package/ui/js/MdHtmlHeading.js +53 -0
  545. package/ui/js/MdHtmlImage.js +179 -0
  546. package/ui/js/MdInline.js +154 -0
  547. package/ui/js/MdItems.js +212 -0
  548. package/ui/js/MdLeaf.js +309 -0
  549. package/ui/js/MdLink.js +196 -0
  550. package/ui/js/MdMath.js +67 -0
  551. package/ui/js/MdParagraphs.js +138 -0
  552. package/ui/js/MdRefs.js +232 -0
  553. package/ui/js/MdResolve.js +226 -0
  554. package/ui/js/MdRun.js +300 -0
  555. package/ui/js/MdUrl.js +226 -0
  556. package/ui/js/Menu.js +514 -0
  557. package/ui/js/MenuContext.js +85 -0
  558. package/ui/js/MenuFit.js +13 -0
  559. package/ui/js/MenuRefresh.js +74 -0
  560. package/ui/js/MenuWheel.js +35 -0
  561. package/ui/js/Messages.js +186 -0
  562. package/ui/js/Motion.js +16 -0
  563. package/ui/js/Mounts.js +320 -0
  564. package/ui/js/MouseNav.js +13 -0
  565. package/ui/js/Nav.js +329 -0
  566. package/ui/js/NetFs.js +26 -0
  567. package/ui/js/OpenWith.js +83 -0
  568. package/ui/js/Ops.js +585 -0
  569. package/ui/js/Palette.js +33 -0
  570. package/ui/js/PathBar.js +260 -0
  571. package/ui/js/Permissions.js +179 -0
  572. package/ui/js/Phones.js +112 -0
  573. package/ui/js/Picker.js +353 -0
  574. package/ui/js/PlaceMenu.js +96 -0
  575. package/ui/js/Places.js +265 -0
  576. package/ui/js/PreviewAsk.js +21 -0
  577. package/ui/js/PreviewKeys.js +155 -0
  578. package/ui/js/PreviewSettle.js +29 -0
  579. package/ui/js/PreviewSwap.js +101 -0
  580. package/ui/js/PropertyFacts.js +144 -0
  581. package/ui/js/Protocols.js +296 -0
  582. package/ui/js/QuickLookKinds.js +27 -0
  583. package/ui/js/QuickLookRect.js +24 -0
  584. package/ui/js/RailDrop.js +51 -0
  585. package/ui/js/RailKeys.js +87 -0
  586. package/ui/js/RailMenu.js +133 -0
  587. package/ui/js/Recent.js +135 -0
  588. package/ui/js/RecentMode.js +156 -0
  589. package/ui/js/Reload.js +60 -0
  590. package/ui/js/Renderer.js +9 -0
  591. package/ui/js/RunFile.js +143 -0
  592. package/ui/js/Scripts.js +28 -0
  593. package/ui/js/Scroll.js +304 -0
  594. package/ui/js/ScrollOff.js +69 -0
  595. package/ui/js/Search.js +478 -0
  596. package/ui/js/Selection.js +97 -0
  597. package/ui/js/Settings.js +476 -0
  598. package/ui/js/SettingsAbout.js +97 -0
  599. package/ui/js/SettingsShelf.js +52 -0
  600. package/ui/js/SheetKeys.js +42 -0
  601. package/ui/js/SheetQuery.js +281 -0
  602. package/ui/js/ShelfPile.js +27 -0
  603. package/ui/js/SlowClick.js +53 -0
  604. package/ui/js/SlowOp.js +6 -0
  605. package/ui/js/Sort.js +134 -0
  606. package/ui/js/Startup.js +63 -0
  607. package/ui/js/StateWords.js +17 -0
  608. package/ui/js/Status.js +238 -0
  609. package/ui/js/Swap.js +166 -0
  610. package/ui/js/TabMove.js +39 -0
  611. package/ui/js/Tabs.js +736 -0
  612. package/ui/js/Tags.js +134 -0
  613. package/ui/js/Taildrop.js +128 -0
  614. package/ui/js/Tap.js +174 -0
  615. package/ui/js/TextSize.js +107 -0
  616. package/ui/js/Thumbs.js +158 -0
  617. package/ui/js/Transfer.js +172 -0
  618. package/ui/js/Trash.js +81 -0
  619. package/ui/js/TrashDates.js +47 -0
  620. package/ui/js/TrashDrop.js +64 -0
  621. package/ui/js/UiState.js +438 -0
  622. package/ui/js/Unlock.js +152 -0
  623. package/ui/js/Update.js +130 -0
  624. package/ui/js/UserDirs.js +56 -0
  625. package/ui/qmldir +228 -0
@@ -0,0 +1,561 @@
1
+ import QtQuick
2
+ import qs.Commons
3
+ import "." as Flea
4
+ import "js/Keymap.js" as Keymap
5
+ import "js/Menu.js" as Menu
6
+ import "js/Places.js" as Places
7
+ import "js/RailKeys.js" as RailKeys
8
+ import "js/SheetKeys.js" as SheetKeys
9
+ import "js/SheetQuery.js" as SheetQuery
10
+
11
+ // The keymap sheet ? opens, drawn as the Keys panel on Operations.dc.html draws it. Every row comes
12
+ // from keys.toml through Keymap.sheetFor, so a key that loses its binding cannot go on being advertised.
13
+ Item {
14
+ id: root
15
+
16
+ property bool opened: false
17
+ property Item focusHolder: null
18
+ readonly property var pane: root.focusHolder ? (root.focusHolder.sheetPane || root.focusHolder) : null
19
+ // The query field appears on the first typed key only; an exact place name ranks first.
20
+ property string query: ""
21
+ // The history read once when the query line opens, never per keystroke, bounded by
22
+ // Recent.LIMIT with no per-entry stat, listed whether or not the Recent rail row is on.
23
+ property var recentPaths: []
24
+ property bool recentAsked: false
25
+ // The cursor sits on the first row, the menu lift, and arrows move it.
26
+ property int resultCursor: 0
27
+ onQueryChanged: root.resultCursor = 0
28
+ // The whole table in every state, so the cap column keeps one width whatever the query narrows to.
29
+ readonly property var sheet: root.actionRows()
30
+ // The query results across actions, the cursor row's menu, places and recent files, bounded.
31
+ readonly property var queryResults: {
32
+ if (root.query.length === 0 || !root.focusHolder)
33
+ return []
34
+ var rows = root.sheet
35
+ var actions = SheetQuery.actionCandidates(rows)
36
+ var menus = SheetQuery.menuCandidates(root.menuModel(), function (a) { return Keymap.hintFor(a) })
37
+ var places = SheetQuery.placeCandidates(root.railModel())
38
+ var recents = SheetQuery.recentCandidates(root.recentPaths, root.pane.home)
39
+ return SheetQuery.rank(actions.concat(menus, places, recents), root.query)
40
+ }
41
+ function actionRows() {
42
+ var rows = Keymap.sheetFor(ViewState.keysPreset, "gui")
43
+ return root.focusHolder && root.focusHolder.sheetActionRows ? root.focusHolder.sheetActionRows(rows) : rows
44
+ }
45
+ // The cursor row's menu rows, hidden ones included so the sheet finds a row Settings Menus hides; disabled ones never run.
46
+ function menuModel() {
47
+ var holder = root.focusHolder
48
+ if (holder && holder.sheetMenuModel) return holder.sheetMenuModel()
49
+ if (!holder || !holder.cursorRow) return []
50
+ var context = holder.contextMenu().listingContext("", true)
51
+ context.hasRow = true
52
+ return Menu.listingEntries(context)
53
+ }
54
+ function railModel() {
55
+ var bar = root.pane ? root.pane.sidebar : null
56
+ return Flea.RailPlaces.entries().concat(bar ? bar.networkEntries.concat(bar.deviceEntries) : [])
57
+ }
58
+ function ensureRecent() {
59
+ if (root.recentAsked)
60
+ return
61
+ root.recentAsked = true
62
+ recentLoader.active = true
63
+ }
64
+ // Enter runs the highlighted row the way its own surface would.
65
+ function activateResult() {
66
+ var pick = root.queryResults[root.resultCursor]
67
+ if (!pick)
68
+ return
69
+ var decided = SheetQuery.dispatch(pick)
70
+ var holder = root.focusHolder
71
+ if (!holder || decided.kind === "disabled" || decided.kind === "none")
72
+ return
73
+ if (decided.kind === "action") {
74
+ SheetQuery.runAction(holder, decided.action, function () { root.close() })
75
+ return
76
+ }
77
+ if (decided.kind === "menu" || decided.kind === "confirm") {
78
+ SheetQuery.runMenu(holder, decided.menuAction, function () { root.close() })
79
+ return
80
+ }
81
+ if (decided.kind === "place") {
82
+ var entries = root.railModel()
83
+ var at = SheetQuery.placeIndex(entries, decided)
84
+ root.close()
85
+ if (at < 0) return
86
+ var pane = root.pane, entry = entries[at]
87
+ if (pane.sidebar && entry.group !== "home" && entry.kind !== "favourite" && entry.kind !== "trash") {
88
+ var railAt = SheetQuery.placeIndex(pane.sidebar.entries, decided)
89
+ if (railAt >= 0) pane.sidebar.activate(railAt)
90
+ } else Places.openEntry(entry, { pane: pane,
91
+ opened: function (path) { RailKeys.openFrom(pane, path, pane.sidebar) },
92
+ networkHost: function () { return pane.ensureNetworkService() },
93
+ trash: function () { pane.trash.open() }, message: pane.message })
94
+ return
95
+ }
96
+ if (decided.kind === "recent") {
97
+ root.close()
98
+ root.pane.openFile(decided.path)
99
+ return
100
+ }
101
+ }
102
+ // Directive 18's footprint: the four blocks flow into two columns of equal length rather than a
103
+ // 2x2 grid, which paid twice for the taller block of each pair and grew the card to the screen.
104
+ readonly property var columnSlots: {
105
+ var flat = []
106
+ for (var g = 0; g < root.groups.length; g++) {
107
+ flat.push({ heading: root.groups[g].title, row: null })
108
+ for (var i = 0; i < root.groups[g].rows.length; i++)
109
+ flat.push({ heading: "", row: root.groups[g].rows[i] })
110
+ }
111
+ if (root.columns === 1)
112
+ return [flat]
113
+ var half = Math.ceil(flat.length / 2)
114
+ // The fold prefers a group's own boundary, which costs at most one row of imbalance here.
115
+ for (var b = half - 1; b <= half + 1; b++)
116
+ if (b > 0 && b < flat.length && flat[b].heading.length > 0)
117
+ return [flat.slice(0, b), flat.slice(b)]
118
+ // It cannot always: a group longer than a column has to break inside itself, and then the
119
+ // continuation names it again, so no row on this sheet ever sits under no heading at all.
120
+ var owner = ""
121
+ for (var k = half - 1; k >= 0; k--)
122
+ if (flat[k].heading.length > 0) {
123
+ owner = flat[k].heading
124
+ break
125
+ }
126
+ var tail = flat.slice(half)
127
+ if (owner.length > 0)
128
+ tail = [{ heading: owner, row: null }].concat(tail)
129
+ return [flat.slice(0, half), tail]
130
+ }
131
+
132
+ // KeymapSheet rule 1: a binding gets a group in keys.toml and the sheet reads it, in the order
133
+ // that table lists them, with the heading its own key carries under a raised first letter.
134
+ readonly property var groups: {
135
+ var out = []
136
+ for (var name in Keymap.SHEET_GROUPS) {
137
+ var order = Keymap.SHEET_GROUPS[name], claimed = []
138
+ // The group's own list is the order the board draws, cursor keys before the chords;
139
+ // the generated sheet is in keys.toml's file order, which puts every preset row first.
140
+ for (var i = 0; i < order.length; i++) {
141
+ var row = root.sheet.filter(function (candidate) { return candidate.action === order[i] })
142
+ if (row.length > 0)
143
+ claimed.push(row[0])
144
+ }
145
+ if (claimed.length > 0)
146
+ out.push({ title: name.charAt(0).toUpperCase() + name.slice(1), rows: claimed })
147
+ }
148
+ return out
149
+ }
150
+
151
+ // The canvas drew this panel at 300, the convert popup's width, beside four illustrative rows.
152
+ // The real sheet is sixty rows whose chords run to eighteen characters: at 300 a cap took the
153
+ // whole half-cell, the wording beside it elided to a single ellipsis, and the two columns
154
+ // overprinted each other. 480 is the Open with card's own anchor and leaves both room.
155
+ readonly property int sheetWidth: 480
156
+ readonly property int clampMargin: 8
157
+ // var, not Item: BorderSurface is a qs.Ui type qmllint cannot resolve, and Item would read as incompatible.
158
+ readonly property var cardItem: card
159
+ // A cap is sized from the type scale, never from the text inside it, so every cap is one height.
160
+ readonly property int capSize: Theme.markSize
161
+ // The 0.2.1 sheet's own row, which directive 18 makes the ceiling: the cap with one row padding
162
+ // under it. The board draws 32 around a 19 cap, but its pane holds 36 rows and this one holds 56.
163
+ readonly property int rowPitch: root.capSize + Theme.spacing.rowPaddingY
164
+ // A heading carries no cap box, so it takes the cap's own height rather than a whole row's.
165
+ readonly property int headingPitch: root.capSize
166
+ readonly property int capGap: Theme.spacing.gap
167
+
168
+ // One cap column for the whole sheet, measured off the widest chord this preset spells. Sizing
169
+ // each cap to its own text left every wording starting on a different x, and a wide chord took
170
+ // the cell whole and drew across the column beside it.
171
+ readonly property string widestCap: {
172
+ var out = ""
173
+ for (var i = 0; i < root.sheet.length; i++)
174
+ if (root.sheet[i].keys.length > out.length) out = root.sheet[i].keys
175
+ return out
176
+ }
177
+ readonly property int capWidth: Math.max(root.capSize, Math.ceil(capMetrics.width) + root.capGap)
178
+ // Board rule 4: no label is ever cut, so the floor is the widest wording this preset really
179
+ // draws. A window that cannot give two cells that much takes one column and scrolls instead.
180
+ readonly property string widestLabel: {
181
+ var out = ""
182
+ for (var i = 0; i < root.sheet.length; i++)
183
+ if (root.sheet[i].label.length > out.length) out = root.sheet[i].label
184
+ return out
185
+ }
186
+ readonly property int cellFloor: root.capWidth + root.capGap + Math.ceil(labelFloor.width)
187
+ // Two columns is what the canvas draws, and what keeps the whole map on one panel where it fits.
188
+ readonly property int columns: root.contentWidth >= 2 * root.cellFloor + Theme.spacing.rowPaddingX ? 2 : 1
189
+
190
+ // The body spans the card's inner width so a result's lift can run edge to edge; the text keeps its padded columns.
191
+ readonly property real textInset: Theme.spacing.rowPaddingX - Theme.spacing.hairline
192
+ readonly property real contentWidth: body.width - 2 * root.textInset
193
+
194
+ TextMetrics {
195
+ id: capMetrics
196
+ font.family: Theme.font.family
197
+ font.pixelSize: Theme.font.caption
198
+ text: root.widestCap
199
+ }
200
+
201
+ TextMetrics {
202
+ id: labelFloor
203
+ font.family: Theme.font.family
204
+ font.pixelSize: Theme.font.caption
205
+ text: root.widestLabel
206
+ }
207
+ readonly property real groundOpacity: 0.5
208
+ // The most of a result's label column its muted suffix may take, so a deep folder elides too and the name keeps the rest.
209
+ readonly property real whereShare: 0.5
210
+
211
+ anchors.fill: parent
212
+ visible: root.opened || root.opacity > 0
213
+ // Closed means no input, even while the fade-out is still drawn.
214
+ enabled: root.opened
215
+ opacity: 0
216
+ z: 2
217
+ Flea.Reveal { target: root; shown: root.opened; lift: card }
218
+
219
+ function open(holder) {
220
+ root.focusHolder = holder
221
+ root.query = ""
222
+ root.recentPaths = []
223
+ root.recentAsked = false
224
+ root.resultCursor = 0
225
+ recentLoader.active = false
226
+ // MenuAdditions040 callout 10: one two-byte read for the cursor row, so Make executable reads as the menu shows.
227
+ if (!holder.sheetPane) holder.checkShebang()
228
+ root.opened = true
229
+ keys.forceActiveFocus()
230
+ }
231
+ Loader {
232
+ id: recentLoader
233
+ active: false
234
+ source: "PickerRecent.qml"
235
+ onLoaded: item.refresh()
236
+ }
237
+ Connections {
238
+ target: recentLoader.item
239
+ function onRefreshed() { root.recentPaths = recentLoader.item.paths }
240
+ }
241
+
242
+ function close() {
243
+ if (!root.opened)
244
+ return
245
+ root.opened = false
246
+ if (root.focusHolder) {
247
+ if (root.focusHolder.sheetFocus) root.focusHolder.sheetFocus()
248
+ else root.focusHolder.forceActiveFocus()
249
+ }
250
+ }
251
+
252
+ // What a test reads instead of running OCR over the panel, the same idiom ui/Pane.qml's
253
+ // menuEntries() uses: one row per line, the cap and the wording it is drawn beside.
254
+ function rows() {
255
+ var out = []
256
+ // Under a query the sheet draws its results, so a test reads those instead of the resting grid.
257
+ if (root.query.length > 0) {
258
+ for (var r = 0; r < root.queryResults.length; r++)
259
+ out.push(root.queryResults[r].keys + " " + root.queryResults[r].label
260
+ + (root.queryResults[r].disabled === true ? " (disabled)" : ""))
261
+ return out.join("\n")
262
+ }
263
+ for (var g = 0; g < root.groups.length; g++) {
264
+ out.push(root.groups[g].title)
265
+ for (var i = 0; i < root.groups[g].rows.length; i++)
266
+ out.push(root.groups[g].rows[i].keys + " " + root.groups[g].rows[i].label)
267
+ }
268
+ return out.join("\n")
269
+ }
270
+
271
+ // The query results as JSON, each row's cap, wording and the muted where its delegate draws, for a test that reads the screen.
272
+ function resultState() {
273
+ var out = []
274
+ for (var r = 0; r < resultRepeater.count; r++) {
275
+ var item = resultRepeater.itemAt(r)
276
+ if (item)
277
+ out.push({ keys: item.modelData.keys, label: item.modelData.label, where: item.whereShown, disabled: item.modelData.disabled === true })
278
+ }
279
+ return JSON.stringify(out)
280
+ }
281
+
282
+ // A dimmed ground, and a click on it closes, the same shape ui/ConvertDialog.qml uses.
283
+ Rectangle {
284
+ anchors.fill: parent
285
+ color: Theme.color.background
286
+ opacity: root.groundOpacity
287
+
288
+ MouseArea {
289
+ anchors.fill: parent
290
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
291
+ hoverEnabled: true
292
+ onClicked: root.close()
293
+ onWheel: function (wheel) { wheel.accepted = true }
294
+ }
295
+ }
296
+
297
+ // The resting card's body: the title, then the taller of the two columns of the key grid.
298
+ readonly property real restBodyHeight: {
299
+ var tall = 0
300
+ for (var c = 0; c < root.columnSlots.length; c++) {
301
+ var column = 0
302
+ for (var r = 0; r < root.columnSlots[c].length; r++)
303
+ column += root.columnSlots[c][r].heading.length > 0 ? root.headingPitch : root.rowPitch
304
+ tall = Math.max(tall, column)
305
+ }
306
+ return title.implicitHeight + Theme.spacing.gap + tall
307
+ }
308
+ readonly property real restCardHeight: Math.min(root.restBodyHeight + 2 * Theme.spacing.rowPaddingX, root.height - 2 * root.clampMargin)
309
+
310
+ Rectangle {
311
+ id: card
312
+ x: Theme.cardOrigin(root.width, width)
313
+ // The rest card centres, and a query grows or shrinks it from its bottom, so the title never moves.
314
+ y: Math.round((root.height - root.restCardHeight) / 2)
315
+ width: Theme.cardSpan(Theme.space(root.sheetWidth) * Theme.dialogWidthRatio, root.width - 2 * root.clampMargin)
316
+ // Clamped to the window below its top; the body scrolls whatever the clamp cut, see ui/CardScroll.qml.
317
+ height: Theme.cardSpan(body.wanted + 2 * Theme.spacing.rowPaddingX, root.height - card.y - root.clampMargin)
318
+ color: Theme.color.surface
319
+ border.width: Theme.spacing.hairline
320
+ border.color: Theme.color.mutedFrame
321
+ // Mirrors hyprland decoration:rounding, same as ui/ConvertDialog.qml; 0 on a stock box stays square.
322
+ radius: Style.cornerRadius
323
+
324
+ Flea.CardFrame {
325
+ id: body
326
+ anchors.fill: parent
327
+ anchors.topMargin: Theme.spacing.rowPaddingX
328
+ anchors.bottomMargin: Theme.spacing.rowPaddingX
329
+ anchors.leftMargin: card.border.width
330
+ anchors.rightMargin: card.border.width
331
+
332
+ // Rule 2: the one clause a reader needs, in the corner every other surface puts it in.
333
+ title: Item {
334
+ x: root.textInset
335
+ width: root.contentWidth
336
+ height: title.implicitHeight
337
+
338
+ Text {
339
+ id: title
340
+ anchors.left: parent.left
341
+ text: "Keys"
342
+ color: Theme.color.foreground
343
+ font.family: Theme.font.family
344
+ font.pixelSize: Theme.font.bodySmall
345
+ textFormat: Text.PlainText
346
+ }
347
+
348
+ Text {
349
+ anchors.right: parent.right
350
+ anchors.baseline: title.baseline
351
+ text: "esc closes"
352
+ color: Theme.color.muted
353
+ font.family: Theme.font.family
354
+ font.pixelSize: Theme.font.caption
355
+ textFormat: Text.PlainText
356
+ }
357
+ }
358
+
359
+ Column {
360
+ x: root.textInset
361
+ width: root.contentWidth
362
+ spacing: Theme.spacing.gap
363
+
364
+ // The query line, drawn only while one stands: a ? in the cap column, the query in a hairline accent field (decided 2026-10-03: no ring).
365
+ Item {
366
+ id: queryRow
367
+ width: parent.width
368
+ height: queryRow.visible ? queryBox.height : 0
369
+ visible: root.query.length > 0
370
+
371
+ Text {
372
+ anchors.left: parent.left
373
+ anchors.verticalCenter: parent.verticalCenter
374
+ width: root.capWidth
375
+ horizontalAlignment: Text.AlignHCenter
376
+ text: "?"
377
+ color: Theme.color.muted
378
+ font.family: Theme.font.family
379
+ font.pixelSize: Theme.font.bodySmall
380
+ textFormat: Text.PlainText
381
+ }
382
+
383
+ Rectangle {
384
+ id: queryBox
385
+ anchors.left: parent.left
386
+ anchors.leftMargin: root.capWidth + root.capGap
387
+ anchors.right: parent.right
388
+ height: Theme.rowHeight - Theme.spacing.rowPaddingY
389
+ color: Theme.color.background
390
+ border.width: Theme.spacing.hairline
391
+ border.color: Theme.color.accent
392
+
393
+ TextInput {
394
+ id: queryLine
395
+ objectName: "keymapInput"
396
+ anchors.left: parent.left
397
+ anchors.right: parent.right
398
+ anchors.margins: Theme.spacing.gap
399
+ anchors.verticalCenter: parent.verticalCenter
400
+ text: root.query
401
+ color: Theme.color.foreground
402
+ selectionColor: Theme.color.accent
403
+ selectedTextColor: Theme.color.background
404
+ font.family: Theme.font.family
405
+ font.pixelSize: Theme.font.body
406
+ selectByMouse: true
407
+ clip: true
408
+ onTextEdited: {
409
+ root.query = text
410
+ if (!text.length) keys.forceActiveFocus()
411
+ }
412
+ Keys.onPressed: function (event) {
413
+ if (event.key === Qt.Key_Escape) root.close()
414
+ else if (event.key === Qt.Key_Up || event.key === Qt.Key_Down)
415
+ root.resultCursor = SheetKeys.stepCursor(root.resultCursor,
416
+ event.key === Qt.Key_Up ? -1 : 1, root.queryResults.length)
417
+ else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter)
418
+ root.activateResult()
419
+ else return
420
+ event.accepted = true
421
+ }
422
+ }
423
+
424
+ }
425
+ }
426
+
427
+ // The query results replace the key grid, one row per match with the run washed.
428
+ Column {
429
+ width: parent.width
430
+ visible: root.query.length > 0
431
+ Repeater {
432
+ id: resultRepeater
433
+ model: root.queryResults
434
+ delegate: Flea.KeymapSheetResult {
435
+ width: parent.width
436
+ resultCursor: root.resultCursor
437
+ query: root.query
438
+ capWidth: root.capWidth
439
+ capSize: root.capSize
440
+ capGap: root.capGap
441
+ rowPitch: root.rowPitch
442
+ textInset: root.textInset
443
+ whereShare: root.whereShare
444
+ }
445
+ }
446
+ }
447
+ Row {
448
+ visible: root.query.length === 0
449
+ spacing: Theme.spacing.rowPaddingX
450
+
451
+ Repeater {
452
+ model: root.columnSlots
453
+
454
+ // Equal halves, so the second column starts on one x the whole way down.
455
+ delegate: Column {
456
+ id: block
457
+ required property var modelData
458
+ width: (root.contentWidth - (root.columns - 1) * Theme.spacing.rowPaddingX) / root.columns
459
+
460
+ Repeater {
461
+ model: block.modelData
462
+
463
+ delegate: Item {
464
+ id: slot
465
+ required property var modelData
466
+ width: block.width
467
+ height: slot.modelData.heading.length > 0 ? root.headingPitch : root.rowPitch
468
+ // Nothing this cell draws may reach the cell beside it, whatever it holds.
469
+ clip: true
470
+
471
+ // A heading takes a row's own slot, so both columns keep one rhythm.
472
+ Text {
473
+ anchors.left: parent.left
474
+ anchors.bottom: parent.bottom
475
+ anchors.bottomMargin: Theme.spacing.hairline * 2
476
+ visible: slot.modelData.heading.length > 0
477
+ text: slot.modelData.heading
478
+ color: Theme.color.muted
479
+ font.family: Theme.font.family
480
+ font.pixelSize: Theme.font.caption
481
+ font.capitalization: Font.AllUppercase
482
+ font.letterSpacing: Theme.spacing.hairline
483
+ textFormat: Text.PlainText
484
+ }
485
+
486
+ Rectangle {
487
+ id: capBox
488
+ anchors.left: parent.left
489
+ anchors.verticalCenter: parent.verticalCenter
490
+ visible: slot.modelData.row !== null
491
+ // The sheet's own cap column, never this row's text: see root.capWidth.
492
+ width: root.capWidth
493
+ height: root.capSize
494
+ color: "transparent"
495
+ border.width: Theme.spacing.hairline
496
+ border.color: Theme.color.mutedFrame
497
+
498
+ Text {
499
+ anchors.fill: parent
500
+ anchors.margins: Theme.spacing.hairline
501
+ horizontalAlignment: Text.AlignHCenter
502
+ verticalAlignment: Text.AlignVCenter
503
+ text: slot.modelData.row ? slot.modelData.row.keys : ""
504
+ color: Theme.color.foreground
505
+ font.family: Theme.font.family
506
+ font.pixelSize: Theme.font.caption
507
+ textFormat: Text.PlainText
508
+ elide: Text.ElideRight
509
+ }
510
+ }
511
+
512
+ Text {
513
+ anchors.left: capBox.right
514
+ anchors.leftMargin: root.capGap
515
+ anchors.right: parent.right
516
+ anchors.verticalCenter: parent.verticalCenter
517
+ visible: slot.modelData.row !== null
518
+ text: slot.modelData.row ? slot.modelData.row.label : ""
519
+ // The wording is the sheet's own running text, so it takes the
520
+ // foreground the board draws it in; muted is for the headings.
521
+ color: Theme.color.foreground
522
+ font.family: Theme.font.family
523
+ font.pixelSize: Theme.font.caption
524
+ textFormat: Text.PlainText
525
+ elide: Text.ElideRight
526
+ }
527
+ }
528
+ }
529
+ }
530
+ }
531
+ }
532
+ }
533
+ }
534
+ }
535
+
536
+ Item {
537
+ id: keys
538
+ anchors.fill: parent
539
+ focus: true
540
+
541
+ // Esc closes the sheet from any state; every key answers through SheetKeys.sheetKey.
542
+ Keys.onPressed: function (event) {
543
+ var decision = SheetKeys.sheetKey(root.query, event.key, event.text)
544
+ if (decision === "up" || decision === "down") {
545
+ root.resultCursor = SheetKeys.stepCursor(root.resultCursor, decision === "up" ? -1 : 1, root.queryResults.length)
546
+ }
547
+ else if (decision === "activate") { root.activateResult() }
548
+ else if (decision === "backspace") { root.query = root.query.substring(0, root.query.length - 1) }
549
+ else if (decision === "type") {
550
+ if (root.query.length === 0)
551
+ root.ensureRecent()
552
+ root.query += event.text
553
+ queryLine.forceActiveFocus()
554
+ queryLine.cursorPosition = queryLine.text.length
555
+ }
556
+ else if (decision === "ignore") { event.accepted = true; return }
557
+ else { root.close() }
558
+ event.accepted = true
559
+ }
560
+ }
561
+ }
@@ -0,0 +1,89 @@
1
+ import QtQuick
2
+ import qs.Commons
3
+ import "." as Flea
4
+ import "js/SheetQuery.js" as SheetQuery
5
+
6
+ // One result row of the keymap sheet's query: the cursor lift across the card's inner width, the cap, the label with its matched run washed, and the muted where.
7
+ Item {
8
+ id: hit
9
+
10
+ required property var modelData
11
+ required property int index
12
+ // What the sheet hands down, so a row owns no sheet state.
13
+ required property int resultCursor
14
+ required property string query
15
+ required property int capWidth
16
+ required property int capSize
17
+ required property int capGap
18
+ required property int rowPitch
19
+ required property real textInset
20
+ // The most of the label column the muted where may take, so a deep folder elides too and the name keeps the rest.
21
+ required property real whereShare
22
+ height: hit.rowPitch
23
+ // What a row has left of its width after the cap column.
24
+ readonly property real labelColumn: hit.width - hit.capWidth - hit.capGap
25
+ readonly property string whereText: String(hit.modelData.where || "")
26
+ // The muted where as drawn, "" when the row shows none, so a test reads the screen and not the model.
27
+ readonly property string whereShown: hitWhere.visible ? hitWhere.text : ""
28
+ // One match run per row per keystroke, read by the label's matched run below.
29
+ readonly property var match: SheetQuery.matchOf(hit.modelData.label, hit.query)
30
+ // The lift runs across the card's inner width, past the text's padding on both sides.
31
+ Rectangle {
32
+ x: -hit.textInset
33
+ width: hit.width + 2 * hit.textInset
34
+ height: parent.height
35
+ visible: hit.index === hit.resultCursor
36
+ color: Qt.alpha(Theme.color.foreground, Theme.washHover)
37
+ }
38
+ Rectangle {
39
+ id: hitCap
40
+ anchors.left: parent.left
41
+ anchors.verticalCenter: parent.verticalCenter
42
+ width: hit.capWidth
43
+ height: hit.capSize
44
+ color: "transparent"
45
+ border.width: hit.modelData.keys.length > 0 ? Theme.spacing.hairline : 0
46
+ border.color: Qt.alpha(Theme.color.mutedFrame, hit.modelData.disabled === true ? Theme.disabledOpacity : 1)
47
+ Text {
48
+ anchors.fill: parent
49
+ anchors.margins: Theme.spacing.hairline
50
+ horizontalAlignment: Text.AlignHCenter
51
+ verticalAlignment: Text.AlignVCenter
52
+ text: hit.modelData.keys
53
+ color: hit.modelData.disabled === true ? Theme.color.muted : Theme.color.foreground
54
+ opacity: hit.modelData.disabled === true ? Theme.disabledOpacity : 1
55
+ font.family: Theme.font.family
56
+ font.pixelSize: Theme.font.caption
57
+ textFormat: Text.PlainText
58
+ elide: Text.ElideRight
59
+ }
60
+ }
61
+ Flea.MatchText {
62
+ id: hitLabel
63
+ anchors.left: hitCap.right
64
+ anchors.leftMargin: hit.capGap
65
+ anchors.verticalCenter: parent.verticalCenter
66
+ width: Math.min(implicitWidth, hit.labelColumn - hitWhere.width)
67
+ text: hit.modelData.label
68
+ color: hit.modelData.disabled === true ? Theme.color.muted : Theme.color.foreground
69
+ opacity: hit.modelData.disabled === true ? Theme.disabledOpacity : 1
70
+ pixelSize: Theme.font.caption
71
+ matchStart: hit.match ? hit.match.start : -1
72
+ matchLength: hit.match ? hit.match.length : 0
73
+ }
74
+ // Where the result lives, muted and inline right after its name, as the board draws it; it keeps its width, so a long name elides instead.
75
+ Text {
76
+ id: hitWhere
77
+ anchors.left: hitLabel.right
78
+ anchors.verticalCenter: parent.verticalCenter
79
+ width: hit.whereText.length > 0 ? Math.min(implicitWidth, hit.labelColumn * hit.whereShare) : 0
80
+ visible: hit.whereText.length > 0
81
+ text: hit.whereText.length > 0 ? " in " + hit.whereText : ""
82
+ color: Theme.color.muted
83
+ opacity: hit.modelData.disabled === true ? Theme.disabledOpacity : 1
84
+ font.family: Theme.font.family
85
+ font.pixelSize: Theme.font.caption
86
+ textFormat: Text.PlainText
87
+ elide: Text.ElideRight
88
+ }
89
+ }