flea-qml 0.0.0-stage → 0.2.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 (637) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +511 -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 +407 -0
  51. package/src/archiveops.js +728 -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 +135 -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/terminal-server.js +95 -0
  82. package/src/terminal-shell.js +26 -0
  83. package/src/transfer.js +669 -0
  84. package/src/trash-record.js +41 -0
  85. package/src/trash.js +210 -0
  86. package/src/trashbrowse.js +327 -0
  87. package/src/uistate.js +393 -0
  88. package/src/uistore.js +168 -0
  89. package/src/vendor/LICENSES/Apache-2.0.txt +202 -0
  90. package/src/vendor/LICENSES/MIT-katex-2015.txt +27 -0
  91. package/src/vendor/LICENSES/MIT-katex.txt +21 -0
  92. package/src/vendor/LICENSES/MIT-mermaid.txt +21 -0
  93. package/src/vendor/LICENSES/MIT-pele.txt +40 -0
  94. package/src/vendor/LICENSES/MIT-perseus.txt +18 -0
  95. package/src/vendor/LICENSES/MIT-temml.txt +21 -0
  96. package/src/vendor/pele.js +145 -0
  97. package/src/vendor/temml.mjs +14708 -0
  98. package/src/watch.js +98 -0
  99. package/src/wayland/client.js +109 -0
  100. package/src/wayland/protocol.js +55 -0
  101. package/src/wayland/protocols/ext-data-control-v1.xml +276 -0
  102. package/src/wayland/protocols/wayland.xml +3248 -0
  103. package/src/wayland/protocols/wlr-data-control-unstable-v1.xml +278 -0
  104. package/src/wayland/resource-io.js +6 -0
  105. package/src/wayland/socket-discovery.js +26 -0
  106. package/src/wayland/transport-posix.js +120 -0
  107. package/src/wayland/transport-win32.js +11 -0
  108. package/src/wayland/transport.js +3 -0
  109. package/src/wayland/win32-resources.js +80 -0
  110. package/src/wayland/win32-wire.js +62 -0
  111. package/test/archive.test.js +80 -0
  112. package/test/bench-markdown-scroll.mjs +190 -0
  113. package/test/clip-host.test.js +113 -0
  114. package/test/code-preview.test.js +35 -0
  115. package/test/compare-ui-paths.test.js +24 -0
  116. package/test/compare.test.js +54 -0
  117. package/test/delete-trash.test.js +67 -0
  118. package/test/dirsize.test.js +138 -0
  119. package/test/file-ops.test.js +307 -0
  120. package/test/file-url.test.js +24 -0
  121. package/test/find-contents.test.js +161 -0
  122. package/test/find-input.test.js +66 -0
  123. package/test/fixtures/pele-parity.json +1006 -0
  124. package/test/highlight-launcher.test.js +35 -0
  125. package/test/html-preview.test.js +22 -0
  126. package/test/input.test.js +15 -0
  127. package/test/keymap.test.js +26 -0
  128. package/test/language-icons.test.js +36 -0
  129. package/test/launcher.test.js +51 -0
  130. package/test/manual-archive-here-ui.mjs +47 -0
  131. package/test/manual-code-scroll.mjs +28 -0
  132. package/test/manual-column-scroll.mjs +24 -0
  133. package/test/manual-compare-ui.mjs +20 -0
  134. package/test/manual-find-status.mjs +37 -0
  135. package/test/manual-folder-focus.mjs +63 -0
  136. package/test/manual-html-security.mjs +23 -0
  137. package/test/manual-html-ui.mjs +30 -0
  138. package/test/manual-syntax-preview.mjs +26 -0
  139. package/test/manual-terminal-lifecycle.mjs +42 -0
  140. package/test/manual-terminal-navigation.mjs +48 -0
  141. package/test/manual-terminal-ui.mjs +47 -0
  142. package/test/manual-trash-ui.mjs +86 -0
  143. package/test/markdown-diagrams.test.js +93 -0
  144. package/test/markdown-html.test.js +105 -0
  145. package/test/mathml.test.js +92 -0
  146. package/test/menu-transfer.test.js +57 -0
  147. package/test/office-preview.test.js +154 -0
  148. package/test/pele-parity.test.js +28 -0
  149. package/test/places.test.js +134 -0
  150. package/test/preview-keys.test.js +60 -0
  151. package/test/preview-language.test.js +22 -0
  152. package/test/status-filename.test.js +20 -0
  153. package/test/transfer-replace-merge.test.js +187 -0
  154. package/test/trash-address.test.js +23 -0
  155. package/test/trash-view.test.js +37 -0
  156. package/test/trashbrowse.test.js +135 -0
  157. package/ui/AboutFacts.qml +78 -0
  158. package/ui/ArchiveCards.qml +95 -0
  159. package/ui/ArchiveCompressDialog.qml +378 -0
  160. package/ui/ArchiveHereConfirm.qml +127 -0
  161. package/ui/ArchivePasswordDialog.qml +257 -0
  162. package/ui/Backend.qml +775 -0
  163. package/ui/BulkOldNames.qml +47 -0
  164. package/ui/BulkRenameDialog.qml +380 -0
  165. package/ui/CardFrame.qml +67 -0
  166. package/ui/CardScroll.qml +79 -0
  167. package/ui/CheckBox.qml +73 -0
  168. package/ui/ChromeBar.qml +360 -0
  169. package/ui/ChromeButton.qml +131 -0
  170. package/ui/ChromeModes.qml +43 -0
  171. package/ui/CodeLines.qml +256 -0
  172. package/ui/CodeRefusal.qml +52 -0
  173. package/ui/CollideConfirm.qml +147 -0
  174. package/ui/CollideHost.qml +167 -0
  175. package/ui/ColumnPane.qml +525 -0
  176. package/ui/ColumnRow.qml +380 -0
  177. package/ui/ColumnsArea.qml +594 -0
  178. package/ui/ColumnsLanding.qml +147 -0
  179. package/ui/CompareView.qml +321 -0
  180. package/ui/ContextMenu.qml +743 -0
  181. package/ui/ConvertDialog.qml +456 -0
  182. package/ui/CountedWorker.qml +7 -0
  183. package/ui/Crumb.qml +64 -0
  184. package/ui/CrumbDrop.qml +25 -0
  185. package/ui/CsvTable.qml +394 -0
  186. package/ui/CursorMark.qml +41 -0
  187. package/ui/DefaultClaim.qml +130 -0
  188. package/ui/DeviceLock.qml +47 -0
  189. package/ui/DeviceMounts.qml +540 -0
  190. package/ui/DialogButton.qml +150 -0
  191. package/ui/DialogField.qml +147 -0
  192. package/ui/DialogHeader.qml +31 -0
  193. package/ui/DialogScrim.qml +20 -0
  194. package/ui/DialogTitle.qml +37 -0
  195. package/ui/Divider.qml +9 -0
  196. package/ui/DropInto.qml +126 -0
  197. package/ui/DropTarget.qml +35 -0
  198. package/ui/DropboxMark.qml +60 -0
  199. package/ui/EmptyState.qml +150 -0
  200. package/ui/EscapeHint.qml +11 -0
  201. package/ui/FactsTable.qml +54 -0
  202. package/ui/FastScrollHandler.qml +476 -0
  203. package/ui/FatNamesConfirm.qml +157 -0
  204. package/ui/Favourites.qml +143 -0
  205. package/ui/FigureService.qml +120 -0
  206. package/ui/FileDrag.qml +267 -0
  207. package/ui/FilterStrip.qml +133 -0
  208. package/ui/FitMetrics.qml +22 -0
  209. package/ui/FlashDriveRows.qml +137 -0
  210. package/ui/FlashHost.qml +72 -0
  211. package/ui/FlashImageRow.qml +104 -0
  212. package/ui/FlashRunner.qml +119 -0
  213. package/ui/FlashStepRow.qml +172 -0
  214. package/ui/FlashStrip.qml +38 -0
  215. package/ui/FlashView.qml +397 -0
  216. package/ui/FleaMark.qml +88 -0
  217. package/ui/FlyoutFade.qml +23 -0
  218. package/ui/FontPane.qml +170 -0
  219. package/ui/Glass.qml +114 -0
  220. package/ui/GlassTagger.qml +59 -0
  221. package/ui/Glyph.qml +64 -0
  222. package/ui/GlyphSolid.qml +22 -0
  223. package/ui/GridArea.qml +664 -0
  224. package/ui/GridTile.qml +325 -0
  225. package/ui/GvfsBridge.qml +164 -0
  226. package/ui/Header.qml +433 -0
  227. package/ui/HoverTimers.qml +39 -0
  228. package/ui/HtmlClip.qml +30 -0
  229. package/ui/HtmlPane.qml +63 -0
  230. package/ui/HyprlandMark.qml +45 -0
  231. package/ui/Ipc.qml +1005 -0
  232. package/ui/IpcControls.qml +7 -0
  233. package/ui/IpcMenuState.qml +48 -0
  234. package/ui/IpcPreviewState.qml +185 -0
  235. package/ui/JumpPath.qml +51 -0
  236. package/ui/KeymapSheet.qml +561 -0
  237. package/ui/KeymapSheetResult.qml +89 -0
  238. package/ui/KindStack.qml +40 -0
  239. package/ui/LangMark.qml +51 -0
  240. package/ui/LangMarkLoader.qml +26 -0
  241. package/ui/List.qml +480 -0
  242. package/ui/LoadingState.qml +54 -0
  243. package/ui/LocalSend.qml +56 -0
  244. package/ui/LocalSendMark.qml +73 -0
  245. package/ui/MarkdownBlockView.qml +311 -0
  246. package/ui/MarkdownBlocks.qml +35 -0
  247. package/ui/MarkdownFigure.qml +254 -0
  248. package/ui/MarkdownImages.qml +72 -0
  249. package/ui/MarkdownList.qml +81 -0
  250. package/ui/MarkdownMathsText.qml +97 -0
  251. package/ui/MarkdownPane.qml +83 -0
  252. package/ui/MarkdownPictures.qml +41 -0
  253. package/ui/MarkdownQuote.qml +52 -0
  254. package/ui/MarkdownRemote.qml +82 -0
  255. package/ui/MarkdownSource.qml +155 -0
  256. package/ui/MarkdownTable.qml +222 -0
  257. package/ui/MarkdownTableScroll.qml +64 -0
  258. package/ui/MarkdownTableWheel.qml +126 -0
  259. package/ui/MarkdownText.qml +87 -0
  260. package/ui/MarkdownWorker.js +132 -0
  261. package/ui/MatchText.qml +99 -0
  262. package/ui/MediaSession.qml +38 -0
  263. package/ui/MediaSound.qml +26 -0
  264. package/ui/MediaStrip.qml +191 -0
  265. package/ui/MediaTrack.qml +36 -0
  266. package/ui/MediaVolume.qml +54 -0
  267. package/ui/MenuActionDialog.qml +396 -0
  268. package/ui/MenuEdgeFade.qml +24 -0
  269. package/ui/MenuHost.qml +227 -0
  270. package/ui/MenuRow.qml +351 -0
  271. package/ui/MountListing.qml +100 -0
  272. package/ui/NetworkDialog.qml +435 -0
  273. package/ui/NetworkForm.qml +426 -0
  274. package/ui/NetworkMounts.qml +913 -0
  275. package/ui/NetworkPlaces.qml +127 -0
  276. package/ui/OpenWithDialog.qml +613 -0
  277. package/ui/Opener.qml +95 -0
  278. package/ui/Pane.qml +1320 -0
  279. package/ui/PaneMenuActions.qml +527 -0
  280. package/ui/PanePath.qml +90 -0
  281. package/ui/PaneRail.qml +268 -0
  282. package/ui/PaneStates.qml +88 -0
  283. package/ui/PaneSwap.qml +339 -0
  284. package/ui/PaneWire.qml +601 -0
  285. package/ui/ParkedWait.qml +9 -0
  286. package/ui/PathEntry.qml +186 -0
  287. package/ui/PathJump.qml +400 -0
  288. package/ui/PdfViewer.qml +297 -0
  289. package/ui/PermissionsDialog.qml +658 -0
  290. package/ui/PermissionsHeadings.qml +31 -0
  291. package/ui/PhoneMounts.qml +67 -0
  292. package/ui/PickerAnswers.qml +75 -0
  293. package/ui/PickerBox.qml +26 -0
  294. package/ui/PickerChrome.qml +295 -0
  295. package/ui/PickerFilter.qml +97 -0
  296. package/ui/PickerGrid.qml +308 -0
  297. package/ui/PickerHeader.qml +28 -0
  298. package/ui/PickerLifecycle.qml +27 -0
  299. package/ui/PickerList.qml +218 -0
  300. package/ui/PickerListing.qml +149 -0
  301. package/ui/PickerPathBar.qml +127 -0
  302. package/ui/PickerPlaces.qml +189 -0
  303. package/ui/PickerRecent.qml +92 -0
  304. package/ui/PickerSave.qml +101 -0
  305. package/ui/PickerSelection.qml +155 -0
  306. package/ui/PickerWindow.qml +846 -0
  307. package/ui/PowerSectorsReader.qml +10 -0
  308. package/ui/PrebuildDriver.qml +146 -0
  309. package/ui/Preview.qml +1005 -0
  310. package/ui/PreviewAnimation.qml +24 -0
  311. package/ui/PreviewArchive.qml +91 -0
  312. package/ui/PreviewColumn.qml +553 -0
  313. package/ui/PreviewEdge.qml +63 -0
  314. package/ui/PreviewFacts.qml +30 -0
  315. package/ui/PreviewFactsLine.qml +34 -0
  316. package/ui/PreviewHtml.qml +233 -0
  317. package/ui/PreviewImage.qml +253 -0
  318. package/ui/PreviewImagePan.qml +13 -0
  319. package/ui/PreviewImageSharp.qml +32 -0
  320. package/ui/PreviewLines.qml +106 -0
  321. package/ui/PreviewMarkdown.qml +706 -0
  322. package/ui/PreviewMedia.qml +250 -0
  323. package/ui/PreviewPdf.qml +482 -0
  324. package/ui/PreviewScroll.qml +201 -0
  325. package/ui/PreviewSwap.qml +335 -0
  326. package/ui/PreviewText.qml +149 -0
  327. package/ui/ProtocolChip.qml +18 -0
  328. package/ui/QuickLookArchive.qml +41 -0
  329. package/ui/QuickLookBar.qml +103 -0
  330. package/ui/QuickLookPrepare.qml +355 -0
  331. package/ui/QuickLookSwap.qml +10 -0
  332. package/ui/QuickLookWarm.qml +65 -0
  333. package/ui/RailDrop.qml +155 -0
  334. package/ui/RailHeading.qml +19 -0
  335. package/ui/RailPlaces.qml +38 -0
  336. package/ui/RailTrashRow.qml +67 -0
  337. package/ui/RenameField.qml +353 -0
  338. package/ui/RendererRetry.qml +11 -0
  339. package/ui/ResizeHandle.qml +52 -0
  340. package/ui/Reveal.qml +54 -0
  341. package/ui/Row.qml +476 -0
  342. package/ui/RowDrag.qml +213 -0
  343. package/ui/RowDropTarget.qml +27 -0
  344. package/ui/RunCard.qml +286 -0
  345. package/ui/Scripts.qml +65 -0
  346. package/ui/SearchStrip.qml +232 -0
  347. package/ui/SelectionBand.qml +140 -0
  348. package/ui/SelectionPreview.qml +370 -0
  349. package/ui/SettingsFavourite.qml +122 -0
  350. package/ui/SettingsGroup.qml +96 -0
  351. package/ui/SettingsHint.qml +12 -0
  352. package/ui/SettingsMetrics.qml +29 -0
  353. package/ui/SettingsPane.qml +178 -0
  354. package/ui/SettingsPanel.qml +547 -0
  355. package/ui/SettingsRail.qml +128 -0
  356. package/ui/SettingsRow.qml +409 -0
  357. package/ui/SettingsRuler.qml +85 -0
  358. package/ui/SettingsSegment.qml +85 -0
  359. package/ui/ShareBrowser.qml +113 -0
  360. package/ui/ShareLink.qml +67 -0
  361. package/ui/ShelfPins.qml +101 -0
  362. package/ui/Sidebar.qml +728 -0
  363. package/ui/SidebarRow.qml +358 -0
  364. package/ui/Spinner.qml +60 -0
  365. package/ui/StableModel.qml +89 -0
  366. package/ui/StateMessage.qml +84 -0
  367. package/ui/StatusBar.qml +512 -0
  368. package/ui/StatusFileName.qml +27 -0
  369. package/ui/TabBar.qml +673 -0
  370. package/ui/TabDragGeometry.qml +60 -0
  371. package/ui/TagMenuMark.qml +52 -0
  372. package/ui/TagRailSection.qml +53 -0
  373. package/ui/TagSlot.qml +40 -0
  374. package/ui/TagState.qml +150 -0
  375. package/ui/TagSwatch.qml +28 -0
  376. package/ui/Taildrop.qml +86 -0
  377. package/ui/TailscaleMark.qml +50 -0
  378. package/ui/TerminalService.qml +69 -0
  379. package/ui/TerminalTab.qml +48 -0
  380. package/ui/TerminalTabs.qml +27 -0
  381. package/ui/Theme.qml +460 -0
  382. package/ui/ThemeColors.qml +43 -0
  383. package/ui/TransferCard.qml +239 -0
  384. package/ui/TrashConfirm.qml +129 -0
  385. package/ui/TrashDropHandler.qml +11 -0
  386. package/ui/TrashHost.qml +202 -0
  387. package/ui/TrashMonitor.qml +30 -0
  388. package/ui/TrashToolbar.qml +19 -0
  389. package/ui/TrashView.qml +492 -0
  390. package/ui/UnlockDialog.qml +450 -0
  391. package/ui/UnlockHost.qml +206 -0
  392. package/ui/UpdateCheck.qml +97 -0
  393. package/ui/UserDirs.qml +25 -0
  394. package/ui/ViewState.qml +565 -0
  395. package/ui/ViewportScrollBar.qml +195 -0
  396. package/ui/ViewportScrollBars.qml +25 -0
  397. package/ui/WebPreview.qml +33 -0
  398. package/ui/WebPreviewView.qml +26 -0
  399. package/ui/WindowBody.qml +829 -0
  400. package/ui/WindowDrag.qml +35 -0
  401. package/ui/boot/Commons/AudioNodes.qml +50 -0
  402. package/ui/boot/Commons/AudioNodesModel.js +96 -0
  403. package/ui/boot/Commons/Border.qml +243 -0
  404. package/ui/boot/Commons/BorderGeometry.js +373 -0
  405. package/ui/boot/Commons/Color.qml +258 -0
  406. package/ui/boot/Commons/I18n.qml +118 -0
  407. package/ui/boot/Commons/InputDevices.qml +112 -0
  408. package/ui/boot/Commons/InputMethodState.qml +38 -0
  409. package/ui/boot/Commons/IpcRegistry.qml +77 -0
  410. package/ui/boot/Commons/Numbers.js +19 -0
  411. package/ui/boot/Commons/Plural.js +91 -0
  412. package/ui/boot/Commons/ShellIpc.qml +12 -0
  413. package/ui/boot/Commons/Style.qml +561 -0
  414. package/ui/boot/Commons/Translations.qml +100 -0
  415. package/ui/boot/Commons/UntypedInput.qml +152 -0
  416. package/ui/boot/Commons/Util.qml +188 -0
  417. package/ui/boot/Commons/qmldir +13 -0
  418. package/ui/boot/LICENSE-omarchy +20 -0
  419. package/ui/boot/Ui/BackgroundMedia.qml +49 -0
  420. package/ui/boot/Ui/BarIconButton.qml +106 -0
  421. package/ui/boot/Ui/BarIconContent.qml +38 -0
  422. package/ui/boot/Ui/BarIndicator.qml +53 -0
  423. package/ui/boot/Ui/BarWidget.qml +50 -0
  424. package/ui/boot/Ui/BorderOverlay.qml +54 -0
  425. package/ui/boot/Ui/BorderSurface.qml +40 -0
  426. package/ui/boot/Ui/Button.qml +224 -0
  427. package/ui/boot/Ui/ButtonGroup.qml +131 -0
  428. package/ui/boot/Ui/ConfirmDialog.qml +134 -0
  429. package/ui/boot/Ui/CursorSurface.qml +42 -0
  430. package/ui/boot/Ui/Dropdown.qml +245 -0
  431. package/ui/boot/Ui/FilterInput.qml +26 -0
  432. package/ui/boot/Ui/IconContentBounds.qml +141 -0
  433. package/ui/boot/Ui/KeyboardPanel.qml +453 -0
  434. package/ui/boot/Ui/MultiSelect.qml +624 -0
  435. package/ui/boot/Ui/NumberField.qml +86 -0
  436. package/ui/boot/Ui/OpticalGlyph.qml +68 -0
  437. package/ui/boot/Ui/OverlayWindow.qml +102 -0
  438. package/ui/boot/Ui/Panel.qml +60 -0
  439. package/ui/boot/Ui/PanelActionButton.qml +105 -0
  440. package/ui/boot/Ui/PanelController.qml +16 -0
  441. package/ui/boot/Ui/PanelHero.qml +112 -0
  442. package/ui/boot/Ui/PanelKeyCatcher.qml +100 -0
  443. package/ui/boot/Ui/PanelSectionHeader.qml +31 -0
  444. package/ui/boot/Ui/PanelSeparator.qml +19 -0
  445. package/ui/boot/Ui/PanelSlider.qml +156 -0
  446. package/ui/boot/Ui/PanelToolTip.qml +50 -0
  447. package/ui/boot/Ui/PluginBarApi.qml +89 -0
  448. package/ui/boot/Ui/PointerMoveGate.qml +54 -0
  449. package/ui/boot/Ui/PopupCard.qml +181 -0
  450. package/ui/boot/Ui/ScreenMoveRemap.qml +43 -0
  451. package/ui/boot/Ui/SearchableDropdown.qml +354 -0
  452. package/ui/boot/Ui/SizedImage.qml +125 -0
  453. package/ui/boot/Ui/SpeedTestOverlay.qml +412 -0
  454. package/ui/boot/Ui/TextField.qml +58 -0
  455. package/ui/boot/Ui/Toggle.qml +118 -0
  456. package/ui/boot/Ui/ToggleSwitch.qml +115 -0
  457. package/ui/boot/Ui/WidgetButton.qml +172 -0
  458. package/ui/boot/Ui/qmldir +41 -0
  459. package/ui/boot/fleatab.qml +50 -0
  460. package/ui/boot/picker.qml +39 -0
  461. package/ui/boot/shell.qml +131 -0
  462. package/ui/boot/tabtearoff.qml +51 -0
  463. package/ui/js/Anchor.js +379 -0
  464. package/ui/js/AnchorHold.js +162 -0
  465. package/ui/js/Archive.js +157 -0
  466. package/ui/js/ArchiveCard.js +44 -0
  467. package/ui/js/ArchiveOps.js +44 -0
  468. package/ui/js/BackReturn.js +118 -0
  469. package/ui/js/BulkRename.js +100 -0
  470. package/ui/js/Buttons.js +54 -0
  471. package/ui/js/ChromeKeys.js +116 -0
  472. package/ui/js/ClipMarks.js +73 -0
  473. package/ui/js/ClipSelection.js +67 -0
  474. package/ui/js/Clipboard.js +179 -0
  475. package/ui/js/Cloud.js +97 -0
  476. package/ui/js/CodeRuns.js +72 -0
  477. package/ui/js/Collide.js +212 -0
  478. package/ui/js/ColumnFit.js +28 -0
  479. package/ui/js/ColumnMenu.js +111 -0
  480. package/ui/js/Columns.js +298 -0
  481. package/ui/js/ColumnsCarry.js +103 -0
  482. package/ui/js/Compare.js +74 -0
  483. package/ui/js/Contrast.js +157 -0
  484. package/ui/js/ControlReader.js +42 -0
  485. package/ui/js/Convert.js +52 -0
  486. package/ui/js/CopyAs.js +52 -0
  487. package/ui/js/Crumbs.js +178 -0
  488. package/ui/js/Csv.js +231 -0
  489. package/ui/js/Density.js +44 -0
  490. package/ui/js/Devices.js +440 -0
  491. package/ui/js/DirSizes.js +180 -0
  492. package/ui/js/Drag.js +360 -0
  493. package/ui/js/DragOut.js +166 -0
  494. package/ui/js/DropDev.js +52 -0
  495. package/ui/js/Dropbox.js +41 -0
  496. package/ui/js/Eject.js +217 -0
  497. package/ui/js/Errors.js +188 -0
  498. package/ui/js/ExtThumbs.js +115 -0
  499. package/ui/js/Facts.js +402 -0
  500. package/ui/js/FigureDate.js +14 -0
  501. package/ui/js/Filter.js +285 -0
  502. package/ui/js/Find.js +46 -0
  503. package/ui/js/Flash.js +184 -0
  504. package/ui/js/FlashCard.js +79 -0
  505. package/ui/js/FlashEndings.js +125 -0
  506. package/ui/js/FlashPane.js +116 -0
  507. package/ui/js/FleaBin.js +12 -0
  508. package/ui/js/Focus.js +504 -0
  509. package/ui/js/FolderSorts.js +108 -0
  510. package/ui/js/FolderViews.js +44 -0
  511. package/ui/js/Format.js +314 -0
  512. package/ui/js/Fuzzy.js +141 -0
  513. package/ui/js/GlassTag.js +72 -0
  514. package/ui/js/Grid.js +33 -0
  515. package/ui/js/GridGeometry.js +90 -0
  516. package/ui/js/GridNames.js +153 -0
  517. package/ui/js/GvfsBridge.js +200 -0
  518. package/ui/js/HostClipboard.js +29 -0
  519. package/ui/js/Icons.js +218 -0
  520. package/ui/js/Input.js +50 -0
  521. package/ui/js/Jump.js +200 -0
  522. package/ui/js/KeyName.js +64 -0
  523. package/ui/js/Keymap.js +401 -0
  524. package/ui/js/Kinds.js +164 -0
  525. package/ui/js/LICENSES/ISC-lucide.txt +43 -0
  526. package/ui/js/LangMarkPaths.js +47 -0
  527. package/ui/js/LangMarks.js +120 -0
  528. package/ui/js/Lists.js +11 -0
  529. package/ui/js/LocalSend.js +39 -0
  530. package/ui/js/LockedMenu.js +63 -0
  531. package/ui/js/MakeDefault.js +186 -0
  532. package/ui/js/MarkBox.js +7 -0
  533. package/ui/js/Markdown.js +119 -0
  534. package/ui/js/MarkdownLists.js +86 -0
  535. package/ui/js/MarkdownMaths.js +58 -0
  536. package/ui/js/MarkdownPictures.js +32 -0
  537. package/ui/js/MarkdownPrepared.js +139 -0
  538. package/ui/js/MarkdownTableFit.js +34 -0
  539. package/ui/js/Marks.js +148 -0
  540. package/ui/js/Marquee.js +96 -0
  541. package/ui/js/Match.js +93 -0
  542. package/ui/js/Material.js +109 -0
  543. package/ui/js/MdBlocks.js +437 -0
  544. package/ui/js/MdBreak.js +71 -0
  545. package/ui/js/MdChunks.js +70 -0
  546. package/ui/js/MdContainer.js +137 -0
  547. package/ui/js/MdDocument.js +337 -0
  548. package/ui/js/MdEmph.js +97 -0
  549. package/ui/js/MdEntity.js +108 -0
  550. package/ui/js/MdEntityTable.js +223 -0
  551. package/ui/js/MdEscape.js +59 -0
  552. package/ui/js/MdFront.js +37 -0
  553. package/ui/js/MdHold.js +32 -0
  554. package/ui/js/MdHtml.js +307 -0
  555. package/ui/js/MdHtmlBlock.js +290 -0
  556. package/ui/js/MdHtmlHeading.js +53 -0
  557. package/ui/js/MdHtmlImage.js +179 -0
  558. package/ui/js/MdInline.js +154 -0
  559. package/ui/js/MdItems.js +212 -0
  560. package/ui/js/MdLeaf.js +309 -0
  561. package/ui/js/MdLink.js +196 -0
  562. package/ui/js/MdMath.js +67 -0
  563. package/ui/js/MdParagraphs.js +138 -0
  564. package/ui/js/MdRefs.js +232 -0
  565. package/ui/js/MdResolve.js +226 -0
  566. package/ui/js/MdRun.js +300 -0
  567. package/ui/js/MdUrl.js +226 -0
  568. package/ui/js/Menu.js +514 -0
  569. package/ui/js/MenuContext.js +85 -0
  570. package/ui/js/MenuFit.js +13 -0
  571. package/ui/js/MenuRefresh.js +74 -0
  572. package/ui/js/MenuWheel.js +35 -0
  573. package/ui/js/Messages.js +186 -0
  574. package/ui/js/Motion.js +16 -0
  575. package/ui/js/Mounts.js +320 -0
  576. package/ui/js/MouseNav.js +13 -0
  577. package/ui/js/Nav.js +329 -0
  578. package/ui/js/NetFs.js +26 -0
  579. package/ui/js/OpenWith.js +83 -0
  580. package/ui/js/Ops.js +585 -0
  581. package/ui/js/Palette.js +33 -0
  582. package/ui/js/PathBar.js +260 -0
  583. package/ui/js/Permissions.js +179 -0
  584. package/ui/js/Phones.js +112 -0
  585. package/ui/js/Picker.js +353 -0
  586. package/ui/js/PlaceMenu.js +96 -0
  587. package/ui/js/Places.js +265 -0
  588. package/ui/js/PreviewAsk.js +21 -0
  589. package/ui/js/PreviewKeys.js +155 -0
  590. package/ui/js/PreviewSettle.js +29 -0
  591. package/ui/js/PreviewSwap.js +101 -0
  592. package/ui/js/PropertyFacts.js +144 -0
  593. package/ui/js/Protocols.js +296 -0
  594. package/ui/js/QuickLookKinds.js +27 -0
  595. package/ui/js/QuickLookRect.js +24 -0
  596. package/ui/js/RailDrop.js +51 -0
  597. package/ui/js/RailKeys.js +87 -0
  598. package/ui/js/RailMenu.js +133 -0
  599. package/ui/js/Recent.js +135 -0
  600. package/ui/js/RecentMode.js +156 -0
  601. package/ui/js/Reload.js +60 -0
  602. package/ui/js/Renderer.js +9 -0
  603. package/ui/js/RunFile.js +143 -0
  604. package/ui/js/Scripts.js +28 -0
  605. package/ui/js/Scroll.js +304 -0
  606. package/ui/js/ScrollOff.js +69 -0
  607. package/ui/js/Search.js +478 -0
  608. package/ui/js/Selection.js +97 -0
  609. package/ui/js/Settings.js +476 -0
  610. package/ui/js/SettingsAbout.js +97 -0
  611. package/ui/js/SettingsShelf.js +52 -0
  612. package/ui/js/SheetKeys.js +42 -0
  613. package/ui/js/SheetQuery.js +281 -0
  614. package/ui/js/ShelfPile.js +27 -0
  615. package/ui/js/SlowClick.js +53 -0
  616. package/ui/js/SlowOp.js +6 -0
  617. package/ui/js/Sort.js +134 -0
  618. package/ui/js/Startup.js +63 -0
  619. package/ui/js/StateWords.js +17 -0
  620. package/ui/js/Status.js +238 -0
  621. package/ui/js/Swap.js +166 -0
  622. package/ui/js/TabMove.js +39 -0
  623. package/ui/js/Tabs.js +751 -0
  624. package/ui/js/Tags.js +134 -0
  625. package/ui/js/Taildrop.js +128 -0
  626. package/ui/js/Tap.js +180 -0
  627. package/ui/js/TextSize.js +107 -0
  628. package/ui/js/Thumbs.js +158 -0
  629. package/ui/js/Transfer.js +172 -0
  630. package/ui/js/Trash.js +84 -0
  631. package/ui/js/TrashDates.js +47 -0
  632. package/ui/js/TrashDrop.js +64 -0
  633. package/ui/js/UiState.js +438 -0
  634. package/ui/js/Unlock.js +152 -0
  635. package/ui/js/Update.js +130 -0
  636. package/ui/js/UserDirs.js +56 -0
  637. package/ui/qmldir +230 -0
package/ui/js/Tags.js ADDED
@@ -0,0 +1,134 @@
1
+ .pragma library
2
+
3
+ .import "Format.js" as Format
4
+ .import "Status.js" as Status
5
+
6
+ // Flea's seven tag names in menu order, which is also the 1 to 7 key order; src/backend/tags.rs NAMES is the same list.
7
+ var NAMES = ["Red", "Orange", "Yellow", "Green", "Blue", "Purple", "Gray"]
8
+
9
+ // The board's tag swatch square, in px.
10
+ var SWATCH_SIZE = 14
11
+
12
+ // The smaller swatch Properties040's Tags pair draws beside its 14 px text, in px.
13
+ var PAIR_SWATCH_SIZE = 10
14
+
15
+ // The digit each name answers to, "" when no digit names it.
16
+ function keyFor(name) {
17
+ var at = NAMES.indexOf(name)
18
+ return at < 0 ? "" : String(at + 1)
19
+ }
20
+
21
+ var APPLIED = "applied"
22
+ var MIXED = "mixed"
23
+ var ABSENT = "absent"
24
+
25
+ // Across a selection: applied when every file carries it, mixed when some do, absent otherwise.
26
+ function stateFor(files, name) {
27
+ var have = 0
28
+ for (var i = 0; i < files.length; i++) {
29
+ if (files[i].indexOf(name) >= 0) {
30
+ have++
31
+ }
32
+ }
33
+ if (have === 0) {
34
+ return ABSENT
35
+ }
36
+ return have === files.length ? APPLIED : MIXED
37
+ }
38
+
39
+ function statesFor(files) {
40
+ var states = {}
41
+ for (var i = 0; i < NAMES.length; i++) {
42
+ states[NAMES[i]] = stateFor(files, NAMES[i])
43
+ }
44
+ return states
45
+ }
46
+
47
+ // The same states from a backend read: the names every target carries, then the names only some carry.
48
+ function statesFrom(applied, mixed) {
49
+ var states = {}
50
+ for (var i = 0; i < NAMES.length; i++)
51
+ states[NAMES[i]] = applied.indexOf(NAMES[i]) >= 0 ? APPLIED : mixed.indexOf(NAMES[i]) >= 0 ? MIXED : ABSENT
52
+ return states
53
+ }
54
+
55
+ // The status bar's own sentence after a tag change; the count agrees with ui/js/Ops.js nouns.
56
+ function statusLine(ok, name) {
57
+ if (ok === 1) return Format.fill("Tagged %1 item %2", ok, name) + Status.undoHint()
58
+ return Format.fill("Tagged %1 items %2", ok, name) + Status.undoHint()
59
+ }
60
+
61
+ // The same sentence for clearing every tag off the named rows.
62
+ function clearedLine(ok) {
63
+ if (ok === 1) return Format.fill("Removed all tags from %1 item", ok) + Status.undoHint()
64
+ return Format.fill("Removed all tags from %1 items", ok) + Status.undoHint()
65
+ }
66
+
67
+ // The same sentence for taking one tag off the named rows.
68
+ function removedLine(ok, name) {
69
+ if (ok === 1) return Format.fill("Removed %1 from %2 item", name, ok) + Status.undoHint()
70
+ return Format.fill("Removed %1 from %2 items", name, ok) + Status.undoHint()
71
+ }
72
+
73
+ // The line for a settagged answer, read from the op the backend applied rather than from the UI's guess.
74
+ function changedLine(op, ok, name) {
75
+ if (op === "clear") return clearedLine(ok)
76
+ return op === "remove" ? removedLine(ok, name) : statusLine(ok, name)
77
+ }
78
+
79
+ // The line when rows were skipped: the backend leaves out every row that is neither a file nor a folder, so the fragment counts items, not links.
80
+ function skippedLine(names) {
81
+ if (names.length === 1) return Format.fill("%1 item skipped", Format.count(names.length))
82
+ return Format.fill("%1 items skipped", Format.count(names.length))
83
+ }
84
+
85
+ // The whole answer line: the changed sentence, the skip fragment ahead of its undo hint, only the skip when nothing changed, and empty when neither holds.
86
+ function doneLine(op, ok, name, skipped) {
87
+ var skip = skipped && skipped.length > 0 ? skippedLine(skipped) : ""
88
+ if (ok <= 0) return skip
89
+ var changed = changedLine(op, ok, name)
90
+ if (skip === "") return changed
91
+ return changed.replace(/ \u00b7 z undoes$/, function () { return Format.fill(" \u00b7 %1 \u00b7 z undoes", skip) })
92
+ }
93
+
94
+ // The flyout's rows: seven swatches with digit hints, then Remove all tags under a separator.
95
+ var CLEAR_ID = "__clear__"
96
+ function tagEntries(states, fallback) {
97
+ var out = []
98
+ for (var i = 0; i < NAMES.length; i++) {
99
+ out.push({ id: NAMES[i], label: NAMES[i], glyph: "tag", keyHint: String(i + 1), tagRow: { swatch: NAMES[i], fallback: fallback === true,
100
+ state: (states || {})[NAMES[i]] || ABSENT, digit: String(i + 1) } })
101
+ }
102
+ out.push({ separator: true })
103
+ out.push({ id: CLEAR_ID, label: "Remove all tags", glyph: "x" })
104
+ return out
105
+ }
106
+
107
+ // One rows reply: every row learns whether the folder's slot stands, and inUse gains the tags seen; fresh starts the latch over.
108
+ function stamp(items, latched, inUse, fresh) {
109
+ var tagged = false
110
+ var grew = false
111
+ for (var i = 0; i < items.length; i++) {
112
+ var names = items[i].tg
113
+ if (names === undefined) continue
114
+ tagged = true
115
+ for (var j = 0; j < names.length; j++) {
116
+ if (inUse[names[j]] === true) continue
117
+ inUse[names[j]] = true
118
+ grew = true
119
+ }
120
+ }
121
+ var stands = tagged || (latched && !fresh)
122
+ for (var k = 0; k < items.length; k++) items[k].shown = stands
123
+ return { latched: stands, grew: grew }
124
+ }
125
+
126
+ // The TAGS section lists only tags in use, each row the rail's own entry shape.
127
+ function railEntries(inUse) {
128
+ var out = []
129
+ for (var i = 0; i < NAMES.length; i++) {
130
+ if (inUse[NAMES[i]] === true)
131
+ out.push({ label: NAMES[i], kind: "tag", tag: NAMES[i], glyph: "tag", swatch: NAMES[i], digit: String(i + 1) })
132
+ }
133
+ return out
134
+ }
@@ -0,0 +1,128 @@
1
+ .pragma library
2
+
3
+ // Adapted verbatim from the OEM tailscale plugin's own Model.js, read at
4
+ // /usr/share/omarchy/shell/plugins/panels/tailscale/Model.js: isTaildropTarget,
5
+ // displayHostName/shortDnsName/cleanDnsName and the Online/Mullvad filter in parseStatus.
6
+
7
+ // Sample input: `tailscale status --json`, trimmed to the fields this file reads.
8
+ // {"Self":{"UserID":1000000000000001},"Peer":{"nodekey:...":{"HostName":"laptop",
9
+ // "DNSName":"laptop.example-net.ts.net.","Online":true,"TaildropTarget":1,
10
+ // "TailscaleIPs":["100.1.2.3"],"UserID":1000000000000001}}}
11
+ function parsePeers(raw) {
12
+ var text = String(raw || "").trim()
13
+ if (text === "")
14
+ return []
15
+ var data
16
+ try {
17
+ data = JSON.parse(text)
18
+ } catch (e) {
19
+ return []
20
+ }
21
+ if (!data || typeof data !== "object" || Array.isArray(data)) return []
22
+ var selfUserId = String((data.Self && data.Self.UserID) || "")
23
+ var rawPeers = (data && data.Peer) || {}
24
+ var out = []
25
+ for (var id in rawPeers) {
26
+ var peer = rawPeers[id] || {}
27
+ if (!peer.Online)
28
+ continue
29
+ if (isMullvad(peer))
30
+ continue
31
+ if (!isTaildropTarget(peer, selfUserId))
32
+ continue
33
+ var address = peerAddress(peer)
34
+ if (address === "")
35
+ continue
36
+ out.push({ id: id, label: displayHostName(peer.HostName, peer.DNSName), address: address })
37
+ }
38
+ out.sort(function (a, b) { return a.label.localeCompare(b.label) })
39
+ return out
40
+ }
41
+
42
+ // The code names the state for logic (statusFailed, invalid, signedOut, stopped, disabled, noPeers, or "" when ready); the reason is for people.
43
+ // Sample input: {"BackendState":"Running","Self":{"CapMap":{"https://tailscale.com/cap/file-sharing":[]}},"Peer":{}}.
44
+ function status(raw, exitCode, error) {
45
+ if (exitCode !== 0) return { peers: [], reason: String(error || "Tailscale could not be checked").trim(), code: "statusFailed" }
46
+ var data
47
+ try { data = JSON.parse(raw) } catch (e) { return { peers: [], reason: "invalid status", code: "invalid" } }
48
+ if (!data || typeof data !== "object") return { peers: [], reason: "invalid status", code: "invalid" }
49
+ if (data.BackendState === "NeedsLogin") return { peers: [], reason: "signed out", code: "signedOut" }
50
+ if (data.BackendState !== "Running") return { peers: [], reason: String(data.BackendState || "unavailable").toLowerCase(), code: "stopped" }
51
+ var self = data.Self || {}, capability = "https://tailscale.com/cap/file-sharing"
52
+ var capabilities = Array.isArray(self.Capabilities) ? self.Capabilities : []
53
+ if (!(self.CapMap && self.CapMap[capability] !== undefined)
54
+ && capabilities.indexOf(capability) < 0)
55
+ return { peers: [], reason: "disabled for this account", code: "disabled" }
56
+ var peers = parsePeers(raw)
57
+ return { peers: peers, reason: peers.length ? "" : "no peers", code: peers.length ? "" : "noPeers" }
58
+ }
59
+
60
+ // A specific TaildropTarget wins outright; 0 (unset) falls back to "do we own it too".
61
+ function isTaildropTarget(peer, selfUserId) {
62
+ var target = peer && peer.TaildropTarget
63
+ if (typeof target === "number" && target !== 0)
64
+ return target === 1
65
+ var owner = String((peer && peer.UserID) || "")
66
+ return owner !== "" && owner === String(selfUserId || "")
67
+ }
68
+
69
+ function cleanDnsName(name) {
70
+ var value = String(name || "")
71
+ return value.charAt(value.length - 1) === "." ? value.slice(0, -1) : value
72
+ }
73
+
74
+ function shortDnsName(name) {
75
+ var clean = cleanDnsName(name)
76
+ return clean === "" ? "" : (clean.split(".")[0] || clean)
77
+ }
78
+
79
+ function displayHostName(hostName, dnsName) {
80
+ var host = String(hostName || "")
81
+ if (host !== "" && host.toLowerCase() !== "localhost")
82
+ return host
83
+ return shortDnsName(dnsName) || host || "Unknown"
84
+ }
85
+
86
+ // An exit-node relay peer, never a real send target; see the OEM's own isMullvadPeer.
87
+ function isMullvad(peer) {
88
+ var suffix = ".mullvad.ts.net"
89
+ var dnsName = cleanDnsName((peer && peer.DNSName) || "").toLowerCase()
90
+ var hostName = String((peer && peer.HostName) || "").toLowerCase()
91
+ return endsWith(dnsName, suffix) || endsWith(hostName, suffix)
92
+ }
93
+
94
+ function endsWith(value, suffix) {
95
+ return value.length > suffix.length && value.lastIndexOf(suffix) === value.length - suffix.length
96
+ }
97
+
98
+ // omarchy-tailscale-send resolves its own "$machine" argument the same three ways.
99
+ function peerAddress(peer) {
100
+ if (!peer)
101
+ return ""
102
+ if (peer.DNSName)
103
+ return cleanDnsName(peer.DNSName)
104
+ if (peer.HostName)
105
+ return String(peer.HostName)
106
+ var ips = filterIPv4(peer.TailscaleIPs || [])
107
+ return ips.length > 0 ? ips[0] : ""
108
+ }
109
+
110
+ function filterIPv4(ips) {
111
+ var result = []
112
+ if (!ips || typeof ips.length !== "number")
113
+ return result
114
+ for (var i = 0; i < ips.length; i++) {
115
+ var ip = String(ips[i] || "")
116
+ if (/^100\./.test(ip))
117
+ result.push(ip)
118
+ }
119
+ return result
120
+ }
121
+
122
+ function byId(peers, id) {
123
+ for (var i = 0; i < peers.length; i++) {
124
+ if (peers[i].id === id)
125
+ return peers[i]
126
+ }
127
+ return null
128
+ }
package/ui/js/Tap.js ADDED
@@ -0,0 +1,180 @@
1
+ .pragma library
2
+ .import "Search.js" as Search
3
+ .import "Tabs.js" as Tabs
4
+ .import "Filter.js" as Filter
5
+
6
+ // flea-qml: a pointer on the list takes the keys back from a query line, as the arrows already do
7
+ // (ui/js/Focus.js leavesLine): the filter keeps its query standing and gives up its caret, and a Find
8
+ // line hands the keys to the results without running. Otherwise the next Space or letter is typed
9
+ // into the line the pointer has just left.
10
+ function focusListing(root) {
11
+ if (root.renameEditor && root.renameEditor()) return
12
+ root.focusView = "list"
13
+ if (root.listArea) root.listArea.forceActiveFocus()
14
+ }
15
+ function releaseLines(root) {
16
+ if (root.filterTyping) Filter.commit(root)
17
+ if (root.searchMode === Search.TYPING) root.searchMode = Search.RESULTS
18
+ focusListing(root)
19
+ }
20
+
21
+ // Hit the drawn label instead of the whole name slot, including centered grid captions.
22
+ function onName(label, owner, point, centered) {
23
+ if (!label || !label.visible) return false
24
+ var at = label.mapFromItem(owner, point.x, point.y)
25
+ var width = Math.min(label.width, label.contentWidth === undefined ? label.implicitWidth : label.contentWidth)
26
+ var height = Math.min(label.height, label.contentHeight === undefined ? label.implicitHeight : label.contentHeight)
27
+ var left = centered ? (label.width - width) / 2 : 0
28
+ return at.x >= left && at.x < left + width && at.y >= 0 && at.y < height
29
+ }
30
+
31
+ // The pointer contract, declared in keys.toml's [[pointer]] table and decided here and nowhere
32
+ // else. tests/js/tap.js drives every row of Keymap.POINTER through the three functions below, so a
33
+ // click cannot change meaning without the table saying so and the table cannot advertise a click the
34
+ // code does not make.
35
+ //
36
+ // The rule is macOS's and the operator's: one tap selects, the second opens. The single-tap action is
37
+ // idempotent on a row, so it runs on both taps of a double click rather than behind a double-click
38
+ // timer, which would delay every selection by the whole mouseDoubleClickInterval.
39
+
40
+ // A view keeps its delegates across a re-list, so a tap count can outlive the row its first tap named.
41
+ var firstTap = null
42
+ // A later tap counts only on the row its gesture's first tap named; a tap on another row answers 0 and starts the count again.
43
+ function gestureCount(index, tapCount, root) {
44
+ var row = index >= 0 ? root.rowFor(index) : null
45
+ var key = String(root.path) + "\n" + (row ? row.n : "")
46
+ if (tapCount === 1 || firstTap === null || firstTap.pane !== root) {
47
+ firstTap = { pane: root, key: key, base: 0 }
48
+ return tapCount
49
+ }
50
+ if (firstTap.key !== key) {
51
+ firstTap = { pane: root, key: key, base: tapCount }
52
+ return 0
53
+ }
54
+ return tapCount - firstTap.base
55
+ }
56
+
57
+ // One tap selects, the second opens; a click carries context 0 so the list never moves under the pointer.
58
+ function tapped(index, tapCount, modifiers, root) {
59
+ if (index < 0) return
60
+ releaseLines(root)
61
+ tapCount = gestureCount(index, tapCount, root)
62
+ if (tapCount === 0) return
63
+ // Single-click mode opens on the first tap alone, so later taps of one gesture add nothing.
64
+ if (root.singleClick === true && tapCount !== 1) return
65
+ // Finder's two selection modifiers. Neither ever opens, and only the first tap of one counts,
66
+ // so a modified double click selects once instead of toggling itself back off.
67
+ if (modifiers & Qt.ControlModifier) {
68
+ if (tapCount === 1) root.toggleSelectAt(index)
69
+ return
70
+ }
71
+ if (modifiers & Qt.ShiftModifier) {
72
+ if (tapCount === 1) root.extendSelectionTo(index)
73
+ return
74
+ }
75
+ // What a tap means is the search's to say, not this file's. flea-qml: on Find's results it is the
76
+ // same as anywhere, select on one tap and open on two, so the pointer browses results and the
77
+ // search stays; upstream revealed on the first tap. ui/js/Search.js activateAction answers it.
78
+ var verb = Search.activateAction(root)
79
+ if (verb === "reveal" && tapCount !== 1)
80
+ return
81
+ // Finder commits an open rename on click-away first, so its text lands before the selection moves.
82
+ root.commitOpenRename()
83
+ // A plain tap replaces the selection, so the next shift+click extends from a row on screen.
84
+ root.selectOnly(index, 0)
85
+ if (tapCount === 2 || verb === "reveal")
86
+ root.act(verb)
87
+ // Single-click mode opens files and folders on one tap, like the middle column already does.
88
+ if (tapCount === 1 && verb === "open" && root.singleClick === true)
89
+ root.act("open")
90
+ }
91
+
92
+ // The columns view's own middle column, and ui/ColumnsArea.qml is its only caller, which is what
93
+ // keeps this out of the list and the grid. Its two neighbour columns already go into a directory on
94
+ // one tap, and the operator's 2026-09-11 ruling is that the column holding the cursor does the same,
95
+ // which is Finder's column view. A directory alone: everything else is an ordinary listing tap and
96
+ // reads tapped() above, so a file still opens on the second tap and a modifier still only selects.
97
+ function tappedMiddle(index, tapCount, modifiers, root) {
98
+ if (index >= 0) releaseLines(root)
99
+ var row = index >= 0 ? root.rowFor(index) : null
100
+ var plain = (modifiers & (Qt.ControlModifier | Qt.ShiftModifier)) === 0
101
+ // tapped() counts the gesture itself, so a tap is counted once on either path.
102
+ // flea-qml: a folder among Find's results is a result like any other: one tap selects it and the
103
+ // search stays; only a plain folder listing goes in on one tap.
104
+ if (!row || !row.d || !plain || Search.live(root)) {
105
+ tapped(index, tapCount, modifiers, root)
106
+ return
107
+ }
108
+ tapCount = gestureCount(index, tapCount, root)
109
+ if (tapCount === 0) return
110
+ // The first tap moved the pane, so a second one is another directory's row, the same reason
111
+ // tappedColumn refuses to reveal a neighbour twice.
112
+ if (tapCount !== 1)
113
+ return
114
+ root.commitOpenRename()
115
+ root.selectOnly(index, 0)
116
+ // A directory listed as a search result is still a result, so the one decision point answers here
117
+ // too: it reveals rather than opening, exactly as the same row does in the list view.
118
+ root.act(Search.activateAction(root))
119
+ }
120
+
121
+ // Right click, in all three views: the row under the pointer takes the cursor and the menu opens there.
122
+ // Which rows it then means is decided by the pressed row, ui/js/Drag.js carried()'s rule for the
123
+ // pointer's other gesture: pressed inside the selection the menu addresses all of it, pressed outside
124
+ // it that row replaces the selection. Every entry ui/ContextMenu.qml draws is built from the cursor
125
+ // row while Move to Trash, Compress and Move to Dropbox dispatch through Ops.targetIndices, which
126
+ // prefers the selection, so a right click that left a selection elsewhere standing trashed rows the
127
+ // menu had never described.
128
+ function tappedMenu(index, eventPoint, root, menu) {
129
+ releaseLines(root)
130
+ var picked = root.selectedIndices()
131
+ if (picked.length > 0 && picked.indexOf(index) < 0)
132
+ root.clearSelection()
133
+ root.setCursor(index, 0)
134
+ menu.openAt(eventPoint.scenePosition)
135
+ root.cancelSlowClick()
136
+ }
137
+
138
+ // A right click that landed on no row raises the directory's own menu, in all three views and the
139
+ // Trash; a row's own TapHandler has already answered for a row. A TapHandler declared inside a
140
+ // ListView or GridView belongs to its contentItem, so its position is already the content coordinate
141
+ // indexAt takes: adding contentY again read every row past the first screenful as empty space.
142
+ function onBackground(view, eventPoint) {
143
+ return view.indexAt(eventPoint.position.x, eventPoint.position.y) < 0
144
+ }
145
+
146
+ // A neighbour column in the columns view is a peek with no cursor of its own, so its rows answer a
147
+ // verb rather than acting. One tap on a directory makes it the pane's listing, which is the column
148
+ // view's own reveal and not an open; only a second tap opens a file. A peeked row belongs to another
149
+ // directory and every menu action addresses the pane's cursor, so a right click there is routed by
150
+ // ColumnPane to menuOnNeighbour before this is asked.
151
+ function tappedColumn(row, button, tapCount) {
152
+ if (!row || button === Qt.RightButton)
153
+ return ""
154
+ if (button === Qt.MiddleButton)
155
+ return row.d && tapCount === 1 ? "openTab" : ""
156
+ if (row.d)
157
+ return tapCount === 1 ? "reveal" : ""
158
+ return tapCount === 2 ? "open" : ""
159
+ }
160
+
161
+ // Middle click on a directory opens it in a new tab; a file has no directory to show.
162
+ function tabTarget(row, base, root) {
163
+ return row && row.d && typeof row.n === "string" ? root.join(base, row.n) : ""
164
+ }
165
+
166
+ function tappedTab(row, base, root) {
167
+ var target = tabTarget(row, base, root)
168
+ if (target.length === 0)
169
+ return
170
+ root.commitOpenRename()
171
+ Tabs.openNew(root, target)
172
+ }
173
+
174
+ // The slow click renames on the pane's timer; a second tap opens through tapped() instead, so only a lone tap on the name arms it.
175
+ function slowTap(pane, armed, index, modifiers, dragActive, wasSole) {
176
+ if (armed)
177
+ pane.armSlowClick(index, modifiers, dragActive, wasSole)
178
+ else
179
+ pane.cancelSlowClick()
180
+ }
@@ -0,0 +1,107 @@
1
+ .pragma library
2
+
3
+ .import "Format.js" as Format
4
+ .import "KeyName.js" as KeyName
5
+
6
+ // Flea's text size, which is the Display section's one control. The SettingsScale board rules the
7
+ // shape: Omarchy owns the size by default, and an override pins one stop from Omarchy's own range
8
+ // rather than a free number or a multiplier of its own. The monitor scale beside it belongs to the
9
+ // compositor, which is why nothing here steps or cycles one.
10
+
11
+ // Whole sentences with "%1" for a value, filled by fill so each translates as one.
12
+ var WORDS = {
13
+ followsOmarchy: "Text size follows Omarchy, %1",
14
+ override: "Text size %1. %2 follows Omarchy again",
15
+ overrideAlone: "Text size %1"
16
+ }
17
+
18
+ // The board's seven documented stops, in px, read off its own layout table. They are not
19
+ // contiguous: 13, 15, 17, 18 and 19 are not stops. The range is the OEM one, 9 to 20, so Flea
20
+ // offers no size Omarchy does not.
21
+ var STOPS = [9, 10, 11, 12, 14, 16, 20]
22
+
23
+ // Omarchy's own type ladder, from Commons/Style.qml, whose bodySmall is fontPx(0.917) and caption
24
+ // fontPx(0.833) over the base size. Running the same two ratios at a stop is what makes an override
25
+ // the size Omarchy itself would have drawn, rather than a second ladder that can disagree with it.
26
+ var BODY_RATIO = 1.0
27
+ var BODY_SMALL_RATIO = 0.917
28
+ var CAPTION_RATIO = 0.833
29
+
30
+ var FOLLOW = "system"
31
+
32
+ function follow() {
33
+ return { mode: FOLLOW }
34
+ }
35
+
36
+ // Follow Omarchy is the default, and the board names its stored shape: {"mode":"system"}. An
37
+ // override is the same key holding a number instead, which is src/uischema.rs's own display.textSize
38
+ // rule: "system", or one stop the OEM panel could have produced. There is no second stored shape.
39
+ function following(stored) {
40
+ return !stored || !(Number(stored.mode) > 0)
41
+ }
42
+
43
+ // The nearest stop, so a base Omarchy invented that is not on the list still enters the override on
44
+ // a real stop, and a hand-edited file cannot pin a free number. A tie takes the smaller stop, which
45
+ // is what the strict comparison below does: 13 enters at 12 and 15 at 14, so nothing grows unasked.
46
+ function nearest(px) {
47
+ var best = STOPS[0]
48
+ for (var i = 1; i < STOPS.length; i++) {
49
+ if (Math.abs(STOPS[i] - px) < Math.abs(best - px))
50
+ best = STOPS[i]
51
+ }
52
+ return best
53
+ }
54
+
55
+ // The size Flea actually draws at: Omarchy's own while following, the stored stop while overriding.
56
+ function effective(stored, omarchyBase) {
57
+ return following(stored) ? omarchyBase : nearest(Number(stored.mode))
58
+ }
59
+
60
+ // Switching to Override starts on the stop beside the size already on screen, so the switch itself
61
+ // changes nothing and only a step does.
62
+ function pin(stored, omarchyBase) {
63
+ return { mode: nearest(effective(stored, omarchyBase)) }
64
+ }
65
+
66
+ // One stop along the list, clamped at both ends. Stepping while following becomes an override,
67
+ // which is what the first press of Ctrl+Shift+Plus should do.
68
+ function stepped(stored, omarchyBase, direction) {
69
+ var at = STOPS.indexOf(pin(stored, omarchyBase).mode)
70
+ var to = Math.max(0, Math.min(STOPS.length - 1, at + direction))
71
+ return { mode: STOPS[to] }
72
+ }
73
+
74
+ // A stored value another hand wrote, and 0.1.3's own {"mode":"override","px":N}: anything this
75
+ // cannot read as a size follows Omarchy, which is both the default and the state deleting ui.json
76
+ // restores, and a number that is not a stop lands on the nearest one rather than pinning a size the
77
+ // OEM panel could not produce. src/uistate.rs refuses the same shapes on the way in.
78
+ function parse(stored) {
79
+ var px = stored ? Number(stored.mode) : NaN
80
+ return px > 0 ? { mode: nearest(px) } : follow()
81
+ }
82
+
83
+ // One action-to-delta mapping for every caller, so Focus and the Trash host cannot drift apart.
84
+ function direction(action) {
85
+ return action === "textSizeReset" ? 0 : (action === "textSizeUp" ? 1 : -1)
86
+ }
87
+
88
+ function body(base) {
89
+ return Math.max(1, Math.round(base * BODY_RATIO))
90
+ }
91
+
92
+ function bodySmall(base) {
93
+ return Math.max(1, Math.round(base * BODY_SMALL_RATIO))
94
+ }
95
+
96
+ function caption(base) {
97
+ return Math.max(1, Math.round(base * CAPTION_RATIO))
98
+ }
99
+
100
+ // The sentence the status bar shows, because a size changed by a chord with the panel shut is
101
+ // otherwise a state with no readout and no named way back.
102
+ function announce(stored, omarchyBase) {
103
+ var px = effective(stored, omarchyBase) + "px"
104
+ if (following(stored)) return Format.fill(WORDS.followsOmarchy, px)
105
+ var reset = KeyName.keyFor("textSizeReset")
106
+ return reset.length > 0 ? Format.fill(WORDS.override, px, reset) : Format.fill(WORDS.overrideAlone, px)
107
+ }