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
@@ -0,0 +1,695 @@
1
+ // Flea MIT wrapper; source: tools/vendor-js/mermaid-entry.mjs at Flea 5da918109.
2
+ import { detectType, render } from "./vendor/pele.js";
3
+
4
+ // A face is a per-character advance table for printable ASCII, 32 to 126, in thousandths of an em.
5
+ const TABLE_FIRST = 32;
6
+ const TABLE_LENGTH = 95;
7
+ const THOUSAND = 1000;
8
+ const STYLE_BOLD = 1;
9
+ // A share of one colour mixed into another, for the chart series derived from the theme's roles.
10
+ const HALF = 0.5;
11
+ const MOSTLY = 0.7;
12
+ const HEX_RADIX = 16;
13
+ // CSS color-mix writes each share as a percentage.
14
+ const PERCENT = 100;
15
+ // A Gantt today marker draws at this hour UTC of the day the request names, which the helper formats back to that date.
16
+ const MIDDAY_HOUR = 12;
17
+ // The space Pele lays round the drawing, in px, so a border stroke on the canvas edge is not cut.
18
+ const PADDING = 1;
19
+ const FALLBACK_BODY_PX = 14;
20
+ // v0.3.12 laid every diagram out at body 13 and scaled the whole canvas to the theme's body size, so boxes, gaps and strokes keep their proportion.
21
+ const LAYOUT_PX = 13;
22
+ // v0.3.12's participant, 80 by 40 and 60 apart; Pele steps a message by its margin less 35 plus the label's 33, so 42 keeps v0.3.12's 40.
23
+ const SEQUENCE = { width: 80, height: 40, actorMargin: 60, messageMargin: 42 };
24
+ // Pele draws a first message 46 below its participants and closes 20 under the last; v0.3.12 drew 20, closed 40 and set a label 2.5 lower.
25
+ const FIRST_ROW_RISE = 26;
26
+ const FOOTER_RISE = 6;
27
+ const LABEL_DROP = 2.5;
28
+ // v0.3.12's flowchart box: square corners, at least 60 wide, 41.95 wider than its label, 16.9 a line plus 20 high, under a 0.75 stroke.
29
+ const BOX = { minWidth: 60, padX: 41.95, line: 16.9, padY: 20, stroke: "0.75" };
30
+ // Pele 1.6.0's box is at least 48 wide and 36 wider than its label.
31
+ const PELE_BOX = { minWidth: 48, padX: 36 };
32
+ // Two coordinates closer than this are the same point; a marker this near a path's end belongs to that end.
33
+ const EPSILON = 0.6;
34
+ const MARKER_REACH = 16;
35
+ const PLACES = 100;
36
+ const LIFELINES = '<g class="pele-lifelines" stroke-width="0.75" stroke-dasharray="6 4"';
37
+
38
+ // Sample input: "--- \ntitle: A\n---\nsequenceDiagram" answers 18, through the closing line's break; a source without front matter answers 0.
39
+ // Pele 1.6.0's own front matter scan, line for line, so the defaults land exactly where Pele's front matter ends.
40
+ function frontMatterLength(e) {
41
+ const blank = (c) => c !== undefined && /\s/.test(c);
42
+ const isBreak = (c) => c === "\n" || c === "\r";
43
+ let t = 0;
44
+ while (t < e.length && blank(e[t]) && !isBreak(e[t]))
45
+ t++;
46
+ const fence = e.slice(0, t) + "---";
47
+ if (!e.startsWith("---", t))
48
+ return 0;
49
+ const opens = [];
50
+ for (let u = t + 3; u < e.length && blank(e[u]); u++) {
51
+ if (isBreak(e[u]))
52
+ opens.push(u);
53
+ }
54
+ if (opens.length === 0)
55
+ return 0;
56
+ const closeEnd = (u) => {
57
+ if (!isBreak(e[u]) || !e.startsWith(fence, u + 1))
58
+ return -1;
59
+ let end = -1;
60
+ for (let g = u + 1 + fence.length; g < e.length && blank(e[g]); g++) {
61
+ if (isBreak(e[g]))
62
+ end = g;
63
+ }
64
+ return end;
65
+ };
66
+ const marker = "\n" + fence;
67
+ let last = -1;
68
+ for (let u = e.lastIndexOf(marker); u > opens[0]; u = e.lastIndexOf(marker, u - 1)) {
69
+ if (closeEnd(u) !== -1) {
70
+ last = u;
71
+ break;
72
+ }
73
+ }
74
+ if (last === -1)
75
+ return 0;
76
+ let open = opens[0];
77
+ for (const u of opens) {
78
+ if (u < last)
79
+ open = u;
80
+ }
81
+ const start = open + 1;
82
+ for (let u = e.indexOf(marker, start > 0 ? start - 1 : 0); u !== -1 && u <= last; u = e.indexOf(marker, u + 1)) {
83
+ if (u < start)
84
+ continue;
85
+ const end = closeEnd(u);
86
+ if (end !== -1)
87
+ return end + 1;
88
+ }
89
+ return 0;
90
+ }
91
+
92
+ // Sample input: '"sequence": {"x": {"y": 1}, "width": 120}}' after config's opening brace adds "x" and "width"; each key lives until its own object closes.
93
+ function flowKeys(text, base, found) {
94
+ const keys = [];
95
+ let depth = 1;
96
+ let word = "";
97
+ for (let i = 0; i < text.length; i++) {
98
+ const c = text[i];
99
+ if (c === '"' || c === "'") {
100
+ const end = text.indexOf(c, i + 1);
101
+ word = text.slice(i + 1, end < 0 ? text.length : end);
102
+ i = end < 0 ? text.length : end;
103
+ continue;
104
+ }
105
+ if (c === ":") {
106
+ while (keys.length > 0 && keys[keys.length - 1].depth >= depth)
107
+ keys.pop();
108
+ keys.push({ key: word.trim(), depth });
109
+ const path = base.concat(keys.map((k) => k.key));
110
+ if (path.length === 3 && path[0] === "config" && path[1] === "sequence")
111
+ found.add(path[2]);
112
+ } else if (c === "{") {
113
+ depth++;
114
+ } else if (c === "}") {
115
+ depth--;
116
+ while (keys.length > 0 && keys[keys.length - 1].depth > depth)
117
+ keys.pop();
118
+ }
119
+ word = c === ":" || c === "{" || c === "}" || c === "," ? "" : word + c;
120
+ }
121
+ }
122
+
123
+ // Sample input: "---\ntitle: Login sequence: happy\nconfig:\n sequence:\n width: 120\n flowchart:\n width: 200\n---\n" answers {"width"}.
124
+ // Front matter is YAML: a block key's parents are the keys above it indented less, and a flow value is read by its braces.
125
+ function frontSequenceKeys(front) {
126
+ const found = new Set();
127
+ const parents = [];
128
+ const lines = front.split(/\r?\n/);
129
+ for (let n = 1; n < lines.length; n++) {
130
+ const line = lines[n];
131
+ const key = line.trim().match(/^["']?([\w-]+)["']?\s*:(.*)$/);
132
+ if (line.trim() === "---" || !key)
133
+ continue;
134
+ const indent = line.length - line.trimStart().length;
135
+ while (parents.length > 0 && parents[parents.length - 1].indent >= indent)
136
+ parents.pop();
137
+ const path = parents.map((p) => p.key).concat(key[1]);
138
+ const value = key[2].trim();
139
+ if (path.length === 3 && path[0] === "config" && path[1] === "sequence")
140
+ found.add(path[2]);
141
+ if (value.startsWith("{")) {
142
+ let text = value;
143
+ while (n + 1 < lines.length && (text.split("{").length > text.split("}").length) && lines[n + 1].trim() !== "---")
144
+ text += "\n" + lines[++n];
145
+ flowKeys(text.slice(1), path, found);
146
+ } else if (value === "" || value.startsWith("#")) {
147
+ parents.push({ indent, key: key[1] });
148
+ }
149
+ }
150
+ return found;
151
+ }
152
+
153
+ // Sample input: "---\nconfig:\n sequence:\n width: 120\n---\nsequenceDiagram" keeps its 120 and gains the default height and gap.
154
+ // Pele merges directives key by key but its render config whole, so the defaults go in as the first directive, leaving out what front matter names.
155
+ function withSequenceDefaults(source) {
156
+ if (detectType(source) !== "sequence")
157
+ return source;
158
+ const front = source.slice(0, frontMatterLength(source));
159
+ const named = frontSequenceKeys(front);
160
+ const defaults = {};
161
+ for (const [key, value] of Object.entries(SEQUENCE)) {
162
+ if (!named.has(key))
163
+ defaults[key] = value;
164
+ }
165
+ return front + "%%{init: " + JSON.stringify({ sequence: defaults }) + "}%%\n" + source.slice(front.length);
166
+ }
167
+
168
+ // A pass that meets a drawing it cannot place exactly throws this and hands Pele's own drawing on unchanged.
169
+ const UNPLACED = new Error("unplaced");
170
+ const rounded = (v) => String(Math.round(v * PLACES) / PLACES);
171
+
172
+ // Sample input: "M25,45L25,86H30Z" reads [["M",[25,45]],["L",[25,86]],["H",[30]],["Z",[]]]; a relative command throws UNPLACED.
173
+ function parsePath(d) {
174
+ const segments = [];
175
+ for (const m of d.matchAll(/([A-Za-z])([^A-Za-z]*)/g)) {
176
+ if (!"MLCQSTAHVZ".includes(m[1]))
177
+ throw UNPLACED;
178
+ segments.push([m[1], (m[2].match(/-?(?:\d+\.?\d*|\.\d+)/g) || []).map(Number)]);
179
+ }
180
+ return segments;
181
+ }
182
+
183
+ // The [x, y] slots of one command's numbers, -1 where the command carries no such axis.
184
+ function slots(command, count) {
185
+ const out = [];
186
+ if (command === "H" || command === "V") {
187
+ for (let i = 0; i < count; i++)
188
+ out.push(command === "H" ? [i, -1] : [-1, i]);
189
+ } else if (command === "A") {
190
+ for (let i = 0; i + 6 < count; i += 7)
191
+ out.push([i + 5, i + 6]);
192
+ } else {
193
+ for (let i = 0; i + 1 < count; i += 2)
194
+ out.push([i, i + 1]);
195
+ }
196
+ return out;
197
+ }
198
+
199
+ // Sample input: ("M0,40V99", f) hands f [0, 40] then [NaN, 99] with their place and count, and writes back what f answers.
200
+ function mapPath(d, f) {
201
+ const segments = parsePath(d);
202
+ const all = [];
203
+ for (const [command, numbers] of segments) {
204
+ for (const slot of slots(command, numbers.length))
205
+ all.push([numbers, slot]);
206
+ }
207
+ all.forEach(([numbers, [xi, yi]], at) => {
208
+ const p = f([xi < 0 ? NaN : numbers[xi], yi < 0 ? NaN : numbers[yi]], at, all.length);
209
+ if (xi >= 0)
210
+ numbers[xi] = p[0];
211
+ if (yi >= 0)
212
+ numbers[yi] = p[1];
213
+ });
214
+ return segments.map(([command, numbers]) => command + numbers.map(rounded).join(",")).join("");
215
+ }
216
+
217
+ // Sample input: ('<rect x="-24" width="48"/>', "width") answers 48; a missing attribute answers NaN.
218
+ function attr(tag, name) {
219
+ const m = tag.match(new RegExp(`\\s${name}="([^"]*)"`));
220
+ return m ? Number(m[1]) : NaN;
221
+ }
222
+
223
+ function setAttr(tag, name, value) {
224
+ return tag.replace(new RegExp(`(\\s${name}=")[^"]*"`), (all, head) => head + (typeof value === "string" ? value : rounded(value)) + '"');
225
+ }
226
+
227
+ // Sample input: ('<rect x="1" y="2"/>', p => [p[0], p[1] + 5]) reads '<rect x="1" y="7"/>'; d and points move point by point.
228
+ function mapTag(tag, f) {
229
+ let out = tag;
230
+ for (const [a, b] of [["x", "y"], ["x1", "y1"], ["x2", "y2"], ["cx", "cy"]]) {
231
+ const p = [attr(tag, a), attr(tag, b)];
232
+ if (Number.isNaN(p[0]) && Number.isNaN(p[1]))
233
+ continue;
234
+ const q = f(p);
235
+ out = Number.isNaN(p[0]) ? out : setAttr(out, a, q[0]);
236
+ out = Number.isNaN(p[1]) ? out : setAttr(out, b, q[1]);
237
+ }
238
+ const d = tag.match(/\sd="([^"]*)"/);
239
+ if (d)
240
+ out = setAttr(out, "d", mapPath(d[1], f));
241
+ const points = tag.match(/\spoints="([^"]*)"/);
242
+ if (points)
243
+ out = setAttr(out, "points", mapPath("M" + points[1].trim().replace(/\s+/g, ","), f).slice(1).replace(/([^,]*,[^,]*),/g, "$1 "));
244
+ return out;
245
+ }
246
+
247
+ // Sample input: a path's d answers its points in order, [NaN, y] for a V; a circle answers its centre, any other tag its x and y.
248
+ function pointsOf(tag) {
249
+ const found = [];
250
+ mapTag(tag, (p) => {
251
+ found.push(p);
252
+ return p;
253
+ });
254
+ return found;
255
+ }
256
+
257
+ // Sample input: (svg, index of '<g class="a">') answers the index just past that group's own '</g>', counting the groups nested in it.
258
+ function groupEnd(svg, open) {
259
+ let depth = 0;
260
+ const re = /<g\b[^>]*>|<\/g>/g;
261
+ re.lastIndex = open;
262
+ for (let m = re.exec(svg); m !== null; m = re.exec(svg)) {
263
+ depth += m[0] === "</g>" ? -1 : 1;
264
+ if (depth === 0)
265
+ return re.lastIndex;
266
+ }
267
+ throw UNPLACED;
268
+ }
269
+
270
+ // Sample input: ('<svg viewBox="0 0 50 138" width="50" height="138">', 1, 0, 120) reads viewBox="0 0 50 120" with height 120.
271
+ function setCanvas(svg, axis, from, to) {
272
+ return svg.replace(/^<svg\b[^>]*>/, (root) => {
273
+ const box = (root.match(/\sviewBox="([^"]*)"/) || [0, "0 0 0 0"])[1].split(/[\s,]+/).map(Number);
274
+ box[axis] = from;
275
+ box[axis + 2] = to - from;
276
+ return setAttr(setAttr(root, "viewBox", box.map(rounded).join(" ")), axis === 0 ? "width" : "height", box[axis + 2]);
277
+ });
278
+ }
279
+
280
+ // Sample input: '%%{init: {"sequence": {"messageMargin": 35}}}%%' or front matter naming config.sequence.messageMargin sets one; a message reading "messageMargin" does not.
281
+ function ownMargin(source) {
282
+ const front = source.slice(0, frontMatterLength(source));
283
+ return frontSequenceKeys(front).has("messageMargin") || [...source.matchAll(/%%\{[^]*?\}%%/g)].some((m) => m[0].includes("messageMargin"));
284
+ }
285
+
286
+ // Only a straight first message moves: a note, frame, rect or activation above it, a created or destroyed participant, no closing row or a source's own messageMargin keeps Pele's rows.
287
+ function oldMessageRows(svg, source) {
288
+ try {
289
+ return messageRows(svg, source);
290
+ } catch (error) {
291
+ if (error === UNPLACED)
292
+ return svg;
293
+ throw error;
294
+ }
295
+ }
296
+
297
+ // Sample input: Pele's '<path class="pele-lifeline" d="M0,46V112"/>' and '<g class="pele-edge pele-message"><path d="M0,92H140"/>' rise to a message 20 below.
298
+ function messageRows(svg, source) {
299
+ if (ownMargin(source) || svg.includes('class="pele-destroys"') || !svg.includes("pele-actor-footer"))
300
+ return svg;
301
+ const lifelines = [...svg.matchAll(/<path class="pele-lifeline"[^>]*\sd="M[-\d.]+,([-\d.]+)V([-\d.]+)"/g)].map((m) => Number(m[1]));
302
+ const messages = [...svg.matchAll(/<g class="pele-edge pele-message"[^>]*><path d="M[-\d.]+,([-\d.]+)([^"]*)"/g)].map((m) => [Number(m[1]), m[2]]);
303
+ if (lifelines.length === 0 || lifelines.some((y) => y !== lifelines[0]) || messages.length === 0)
304
+ return svg;
305
+ const first = messages.reduce((a, b) => (b[0] < a[0] ? b : a));
306
+ if (!/^H[-\d.]+$/.test(first[1]))
307
+ return svg;
308
+ for (const name of ["rects", "activations", "frames", "notes"]) {
309
+ const open = svg.indexOf(`<g class="pele-${name}"`);
310
+ if (open >= 0 && [...svg.slice(open, groupEnd(svg, open)).matchAll(/\sy="([-\d.]+)"/g)].some((m) => Number(m[1]) < first[0]))
311
+ return svg;
312
+ }
313
+ const rise = (by) => (tag) => tag.replace(/>$/, ` transform="translate(0,${rounded(-by)})">`);
314
+ let out = svg.replace(/<g class="pele-(?:rects|activations|frames|edges|notes)"[^>]*>/g, rise(FIRST_ROW_RISE))
315
+ .replace(/<g class="pele-edge-labels"[^>]*>/, rise(FIRST_ROW_RISE - LABEL_DROP))
316
+ .replace(/<g class="pele-node pele-actor[^"]*pele-actor-footer[^"]*"[^>]*>/g, rise(FOOTER_RISE))
317
+ .replace(/(<path class="pele-lifeline"[^>]*\sd="M[-\d.]+,[-\d.]+V)([-\d.]+)/g, (all, head, end) => head + rounded(Number(end) - FOOTER_RISE))
318
+ .replace(/(<g class="pele-cluster pele-box"[^>]*><rect\b[^>]*\sheight=")([-\d.]+)/g, (all, head, h) => head + rounded(Number(h) - FOOTER_RISE));
319
+ const box = out.match(/^<svg\b[^>]*\sviewBox="([^"]*)"/)[1].split(/[\s,]+/).map(Number);
320
+ return setCanvas(out, 1, box[1], box[1] + box[3] - FOOTER_RISE);
321
+ }
322
+
323
+ // Sample input: '<circle r="26.53"/><text>Done</text>' answers [26.53, 26.53], how far a node's own shapes reach from its centre, its text left out.
324
+ function halfOf(body) {
325
+ const half = [0, 0];
326
+ const reach = (p) => p.forEach((v, i) => {
327
+ half[i] = Number.isNaN(v) ? half[i] : Math.max(half[i], Math.abs(v));
328
+ });
329
+ for (const tag of body.match(/<(?!text|tspan)[a-z]+\b[^>]*>/g) || []) {
330
+ const name = tag.match(/^<([a-z]+)/)[1];
331
+ const [x, y, w, h, cx, cy] = ["x", "y", "width", "height", "cx", "cy"].map((key) => attr(tag, key) || 0);
332
+ const [rx, ry] = name === "circle" ? [attr(tag, "r"), attr(tag, "r")] : [attr(tag, "rx"), attr(tag, "ry")];
333
+ if (name === "circle" || name === "ellipse")
334
+ [[cx - rx, cy - ry], [cx + rx, cy + ry]].forEach(reach);
335
+ else if (w > 0 || h > 0)
336
+ [[x, y], [x + w, y + h]].forEach(reach);
337
+ else
338
+ pointsOf(tag).forEach(reach);
339
+ }
340
+ return half;
341
+ }
342
+
343
+ // Sample input: '<g class="pele-node pele-shape-rect" transform="translate(25,23)"><rect x="-24" y="-22" width="48" height="44"/><text class="pele-label" x="0" y="4.55">A</text></g>'.
344
+ function nodesOf(svg) {
345
+ const nodes = [];
346
+ for (const m of svg.matchAll(/<g class="pele-node pele-shape-([\w-]+)[^"]*"[^>]*\stransform="translate\(([-\d.]+),([-\d.]+)\)"[^>]*>/g)) {
347
+ const end = groupEnd(svg, m.index);
348
+ const body = svg.slice(m.index + m[0].length, end - "</g>".length);
349
+ const node = { open: m[0], at: m.index, end, body, c: [Number(m[2]), Number(m[3])], box: null, half: halfOf(body) };
350
+ const rect = body.match(/^<rect\b[^>]*>/);
351
+ // One label line is the text itself; Pele sets each line of a longer label as a tspan carrying its own y.
352
+ const label = rect && /^<text class="pele-label"[^>]*>(?:[^<]*|(?:<tspan\b[^>]*>[^<]*<\/tspan>)+)<\/text>$/.test(body.slice(rect[0].length)) ? body.slice(rect[0].length) : "";
353
+ const lines = label.match(/<tspan\b[^>]*\sy="[^"]*"[^>]*>/g) || label.match(/^<text\b[^>]*\sy="[^"]*"[^>]*>/g) || [];
354
+ if (m[1] === "rect" && label && lines.length > 0) {
355
+ const [x, y, w, h] = ["x", "y", "width", "height"].map((name) => attr(rect[0], name));
356
+ if (Math.abs(x + w / 2) < EPSILON && Math.abs(y + h / 2) < EPSILON) {
357
+ const count = lines.length;
358
+ const width = w > PELE_BOX.minWidth + EPSILON ? Math.max(BOX.minWidth, w - PELE_BOX.padX + BOX.padX) : BOX.minWidth;
359
+ node.box = { rect: rect[0], label, lines, half: [w / 2, h / 2], next: [width / 2, (count * BOX.line + BOX.padY) / 2] };
360
+ }
361
+ }
362
+ node.next = node.box ? node.box.next : node.half;
363
+ node.half = node.box ? node.box.half : node.half;
364
+ nodes.push(node);
365
+ }
366
+ return nodes;
367
+ }
368
+
369
+ // Sample input: two ranks of 44 high boxes 92 apart answer a remap that shrinks each to 36.9 and keeps 48 between them; a rank whose other shapes reach further keeps its size.
370
+ function rankRemap(nodes, axis) {
371
+ const ranks = new Map();
372
+ for (const node of nodes) {
373
+ const key = rounded(node.c[axis]);
374
+ const rank = ranks.get(key) || { c: node.c[axis], e: 0, next: 0 };
375
+ rank.e = Math.max(rank.e, node.half[axis]);
376
+ rank.next = Math.max(rank.next, node.next[axis]);
377
+ ranks.set(key, rank);
378
+ }
379
+ // Ranks that overlap along the flow, as side by side subgraphs laid out apart do, keep their spacing and only move together.
380
+ const bands = [];
381
+ for (const r of [...ranks.values()].sort((a, b) => a.c - b.c)) {
382
+ const last = bands[bands.length - 1];
383
+ if (last && last.c + last.e > r.c - r.e + EPSILON) {
384
+ const [low, high] = [Math.min(last.c - last.e, r.c - r.e), Math.max(last.c + last.e, r.c + r.e)];
385
+ bands[bands.length - 1] = { c: (low + high) / 2, e: (high - low) / 2, next: (high - low) / 2 };
386
+ } else {
387
+ bands.push(r);
388
+ }
389
+ }
390
+ const changed = bands.filter((r) => r.e > 0 && Math.abs(r.e - r.next) > 0);
391
+ return (v) => {
392
+ let shift = 0;
393
+ for (const r of changed) {
394
+ const d = r.e - r.next;
395
+ if (v < r.c - r.e)
396
+ break;
397
+ if (v <= r.c + r.e)
398
+ return r.c - shift - d + (v - r.c) * r.next / r.e;
399
+ shift += 2 * d;
400
+ }
401
+ return v - shift;
402
+ };
403
+ }
404
+
405
+ // Sample input: Pele's "flowchart TD\n A --> B" with round 48 by 44 boxes reads v0.3.12's square 60 by 36.9, every edge end, marker, label and group moved with its rank.
406
+ function oldFlowchartBoxes(svg, source) {
407
+ const axis = /^\s*(?:flowchart|graph)(?:-elk)?\s+(?:LR|RL)\b/m.test(source) ? 0 : 1;
408
+ // A group is known by its first class, which Pele writes before any class the source gives it, and every pass below matches that word alone.
409
+ const groups = [...svg.matchAll(/<g class="([\w-]+)/g)].map((m) => m[1]);
410
+ const known = ["pele-clusters", "pele-cluster", "pele-cluster-titles", "pele-cluster-title", "pele-edges", "pele-edge", "pele-edge-labels", "pele-edge-label", "pele-nodes", "pele-node"];
411
+ if (groups.some((name) => !known.includes(name)))
412
+ return svg;
413
+ try {
414
+ const nodes = nodesOf(svg);
415
+ if (!nodes.some((node) => node.box))
416
+ return svg;
417
+ const remap = rankRemap(nodes, axis);
418
+ const along = (p) => p.map((v, i) => (i === axis && !Number.isNaN(v) ? remap(v) : v));
419
+ const centre = (node) => along(node.c);
420
+ // A point on a box's side stays on that side at the same offset along it, held inside the box; a point on another shape moves with its centre.
421
+ const onNode = (node, p) => {
422
+ const c = centre(node);
423
+ return p.map((v, i) => {
424
+ const r = v - node.c[i];
425
+ const [half, next] = [node.half[i], node.next[i]];
426
+ return c[i] + (!node.box ? r : Math.abs(Math.abs(r) - half) < EPSILON ? Math.sign(r) * next : Math.max(-next, Math.min(next, r)));
427
+ });
428
+ };
429
+ const inside = (node, p) => [0, 1].every((i) => Math.abs(p[i] - node.c[i]) <= node.half[i] + EPSILON);
430
+ const owner = (p) => nodes.find((node) => node.box && inside(node, p) && [0, 1].some((i) => Math.abs(Math.abs(p[i] - node.c[i]) - node.half[i]) < EPSILON))
431
+ || nodes.find((node) => !node.box && inside(node, p));
432
+ const edits = [];
433
+ for (const node of nodes) {
434
+ const c = centre(node);
435
+ let body = node.body;
436
+ if (node.box) {
437
+ const [w, h] = node.box.next.map((v) => 2 * v);
438
+ let rect = setAttr(setAttr(setAttr(setAttr(node.box.rect, "x", -w / 2), "y", -h / 2), "width", w), "height", h);
439
+ // Pele writes pele-radius as the style's first declaration, rx:4px; v0.3.12's box is square, and a source's own rx or ry after it wins.
440
+ rect = rect.replace(/(\sstyle=")rx:[^;"]*;?/, "$1").replace(/\sstyle=""/, "").replace(/\sr[xy]="[^"]*"/g, "");
441
+ rect = /\sstroke-width="/.test(rect) ? rect : rect.replace(/\s*(\/?)>$/, ` stroke-width="${BOX.stroke}"$1>`);
442
+ const ys = node.box.lines.map((line) => attr(line, "y"));
443
+ const mid = (ys[0] + ys[ys.length - 1]) / 2;
444
+ const pitch = ys.length > 1 ? (ys[ys.length - 1] - ys[0]) / (ys.length - 1) : 1;
445
+ body = rect + node.box.lines.reduce((text, line, i) => text.replace(line, setAttr(line, "y", mid + (ys[i] - mid) * BOX.line / pitch)), node.box.label);
446
+ }
447
+ edits.push([node.at, node.end, node.open.replace(/translate\([^)]*\)/, `translate(${rounded(c[0])},${rounded(c[1])})`) + body + "</g>"]);
448
+ }
449
+ for (const m of svg.matchAll(/<g class="pele-edge(?:\s[^"]*)?"[^>]*>/g)) {
450
+ const end = groupEnd(svg, m.index);
451
+ const tags = svg.slice(m.index + m[0].length, end - "</g>".length).match(/<[^/][^>]*>|<\/[^>]*>/g) || [];
452
+ const main = tags.findIndex((tag) => tag.startsWith("<path") && !tag.includes("pele-marker"));
453
+ if (main < 0)
454
+ throw UNPLACED;
455
+ const line = pointsOf(tags[main]);
456
+ const ends = [line[0], line[line.length - 1]];
457
+ const near = (tag) => {
458
+ const reach = ends.map((e) => Math.min(...pointsOf(tag).filter((p) => !p.some(Number.isNaN)).map((p) => Math.hypot(p[0] - e[0], p[1] - e[1]))));
459
+ return reach[0] < MARKER_REACH || reach[1] < MARKER_REACH ? (reach[0] <= reach[1] ? 0 : 1) : -1;
460
+ };
461
+ const marks = tags.map((tag, i) => (i !== main && tag.includes("pele-marker") ? near(tag) : -1));
462
+ const shift = ends.map((e, side) => {
463
+ const candidates = [e].concat(...tags.filter((t, i) => marks[i] === side).map(pointsOf));
464
+ for (const p of candidates) {
465
+ const node = Number.isNaN(p[0]) || Number.isNaN(p[1]) ? undefined : owner(p);
466
+ if (node) {
467
+ const q = onNode(node, p);
468
+ const r = along(p);
469
+ return [q[0] - r[0], q[1] - r[1]];
470
+ }
471
+ }
472
+ return [0, 0];
473
+ });
474
+ const moved = (side) => (p) => along(p).map((v, i) => v + (side < 0 ? 0 : shift[side][i]));
475
+ const out = tags.map((tag, i) => (tag.startsWith("</") ? tag : i === main
476
+ ? setAttr(tag, "d", mapPath(tag.match(/\sd="([^"]*)"/)[1], (p, at, count) => moved(at === 0 ? 0 : at === count - 1 ? 1 : -1)(p)))
477
+ : mapTag(tag, moved(marks[i]))));
478
+ edits.push([m.index + m[0].length, end - "</g>".length, out.join("")]);
479
+ }
480
+ for (const m of svg.matchAll(/<g class="pele-(edge-label|cluster-title|cluster)(?:\s[^"]*)?"[^>]*>/g)) {
481
+ const end = groupEnd(svg, m.index);
482
+ const tags = svg.slice(m.index + m[0].length, end - "</g>".length).match(/<[^>]*>|[^<]+/g) || [];
483
+ const rect = tags.find((tag) => tag.startsWith("<rect"));
484
+ const size = axis === 0 ? "width" : "height";
485
+ const from = rect ? attr(rect, axis === 0 ? "x" : "y") : NaN;
486
+ const cluster = m[1] === "cluster";
487
+ const text = tags.find((tag) => tag.startsWith("<text"));
488
+ const anchor = cluster ? from : rect ? from + attr(rect, size) / 2 : text ? attr(text, axis === 0 ? "x" : "y") : NaN;
489
+ if (Number.isNaN(anchor))
490
+ throw UNPLACED;
491
+ const delta = remap(anchor) - anchor;
492
+ const out = tags.map((tag) => {
493
+ if (!tag.startsWith("<") || tag.startsWith("</"))
494
+ return tag;
495
+ if (cluster && tag === rect)
496
+ return setAttr(setAttr(tag, axis === 0 ? "x" : "y", remap(from)), size, remap(from + attr(tag, size)) - remap(from));
497
+ return mapTag(tag, (p) => p.map((v, i) => (i === axis ? v + delta : v)));
498
+ });
499
+ edits.push([m.index + m[0].length, end - "</g>".length, out.join("")]);
500
+ }
501
+ edits.sort((a, b) => b[0] - a[0]);
502
+ let out = svg;
503
+ for (const [from, to, text] of edits)
504
+ out = out.slice(0, from) + text + out.slice(to);
505
+ const box = out.match(/^<svg\b[^>]*\sviewBox="([^"]*)"/)[1].split(/[\s,]+/).map(Number);
506
+ out = setCanvas(out, axis, box[axis], remap(box[axis] + box[axis + 2]));
507
+ // A box that grew across the flow widens the canvas to hold it, as Pele's padding held the narrower one.
508
+ const across = 1 - axis;
509
+ const reach = nodes.filter((node) => node.box).map((node) => [node.c[across] - node.box.next[across], node.c[across] + node.box.next[across]]);
510
+ const low = Math.min(box[across], ...reach.map((r) => r[0] - PADDING));
511
+ const high = Math.max(box[across] + box[across + 2], ...reach.map((r) => r[1] + PADDING));
512
+ return setCanvas(out, across, low, high);
513
+ } catch (error) {
514
+ if (error === UNPLACED)
515
+ return svg;
516
+ throw error;
517
+ }
518
+ }
519
+
520
+ // Sample input: a canvas 52 wide at body 14 reads width 56 over the same viewBox, the way v0.3.12 scaled a body 13 drawing, unrounded as it was.
521
+ function scaledCanvas(svg, bodyPx) {
522
+ const share = (bodyPx > 0 ? bodyPx : FALLBACK_BODY_PX) / LAYOUT_PX;
523
+ return svg.replace(/^<svg\b[^>]*>/, (root) => root.replace(/\s(width|height)="([\d.]+)"/g,
524
+ (all, name, value) => ` ${name}="${Number(value) * share}"`));
525
+ }
526
+
527
+ // Sample input: 95 positive numbers answer { table, mean } in em; anything else answers null.
528
+ function faceOf(thousandths) {
529
+ if (!Array.isArray(thousandths) || thousandths.length !== TABLE_LENGTH || !thousandths.every((v) => v > 0 && v < Infinity))
530
+ return null;
531
+ const table = thousandths.map((v) => v / THOUSAND);
532
+ return { table, mean: table.reduce((sum, v) => sum + v, 0) / TABLE_LENGTH };
533
+ }
534
+
535
+ // Wide East Asian blocks and fullwidth forms take two cells, as in Pele's own table measurer.
536
+ function isWide(c) {
537
+ return (c >= 0x1100 && c <= 0x115f) || (c >= 0x2e80 && c <= 0xa4cf) || (c >= 0xac00 && c <= 0xd7a3) || (c >= 0xf900 && c <= 0xfaff)
538
+ || (c >= 0xfe30 && c <= 0xfe4f) || (c >= 0xff00 && c <= 0xff60) || (c >= 0xffe0 && c <= 0xffe6) || (c >= 0x20000 && c <= 0x3fffd);
539
+ }
540
+
541
+ // Combining marks, zero-width spaces and joiners, variation selectors and the byte order mark draw nothing.
542
+ function isZeroWidth(c) {
543
+ return (c >= 0x300 && c <= 0x36f) || (c >= 0x200b && c <= 0x200f) || (c >= 0xfe00 && c <= 0xfe0f) || c === 0xfeff;
544
+ }
545
+
546
+ // Sample input: "Wi" at 14 px sums the font's own W and i advances; a CJK character counts twice the table's mean, any other non-ASCII once.
547
+ function measurerOf(theme) {
548
+ const regular = faceOf(theme.advances);
549
+ if (!regular)
550
+ return undefined;
551
+ const bold = faceOf(theme.boldAdvances) || regular;
552
+ return {
553
+ width(text, size, style) {
554
+ const face = style & STYLE_BOLD ? bold : regular;
555
+ let em = 0;
556
+ for (const ch of text) {
557
+ const c = ch.codePointAt(0);
558
+ if (c < TABLE_FIRST)
559
+ continue;
560
+ if (c < TABLE_FIRST + TABLE_LENGTH)
561
+ em += face.table[c - TABLE_FIRST];
562
+ else if (!isZeroWidth(c))
563
+ em += isWide(c) ? 2 * face.mean : face.mean;
564
+ }
565
+ return em * size;
566
+ }
567
+ };
568
+ }
569
+
570
+ // Sample input: ("#ffffff", "#000000", 0.7) answers #b3b3b3; a colour that is not #rgb or #rrggbb answers the first one unchanged.
571
+ function mix(a, b, share) {
572
+ const rgb = (h) => {
573
+ const s = String(h).trim().replace(/^#([0-9a-f])([0-9a-f])([0-9a-f])$/i, "#$1$1$2$2$3$3");
574
+ return /^#[0-9a-f]{6}$/i.test(s) ? [1, 3, 5].map((i) => parseInt(s.slice(i, i + 2), HEX_RADIX)) : null;
575
+ };
576
+ const x = rgb(a);
577
+ const y = rgb(b);
578
+ if (!x || !y)
579
+ return a;
580
+ return "#" + x.map((v, i) => Math.round(v * share + y[i] * (1 - share)).toString(HEX_RADIX).padStart(2, "0")).join("");
581
+ }
582
+
583
+ // Every Pele variable as the concrete value of the Flea theme role that draws it.
584
+ function rolesOf(theme) {
585
+ const bg = theme.bg || "#ffffff";
586
+ const fg = theme.fg || "#000000";
587
+ const accent = theme.accent || fg;
588
+ const muted = theme.muted || fg;
589
+ const surface = theme.surface || bg;
590
+ const font = theme.font || "sans-serif";
591
+ return {
592
+ "pele-bg": bg,
593
+ "pele-fg": fg,
594
+ "pele-muted": muted,
595
+ // Edges and borders draw in the muted role and subgraphs on the pane ground, as the figure path drew them before.
596
+ "pele-line": muted,
597
+ "pele-border": muted,
598
+ "pele-surface": surface,
599
+ "pele-surface-alt": bg,
600
+ "pele-accent": accent,
601
+ "pele-critical": accent,
602
+ "pele-error": accent,
603
+ "pele-font": font,
604
+ "pele-font-mono": font,
605
+ "pele-radius": "4px",
606
+ "pele-title-weight": "bold",
607
+ "pele-heading-weight": "bold",
608
+ "pele-bold-weight": "bold",
609
+ // Eight chart series from the four colour roles: each pure, then each mixed toward another, so neighbours differ in hue or in lightness.
610
+ "pele-series-1": accent,
611
+ "pele-series-2": fg,
612
+ "pele-series-3": muted,
613
+ "pele-series-4": mix(accent, bg, HALF),
614
+ "pele-series-5": mix(accent, fg, HALF),
615
+ "pele-series-6": mix(fg, bg, MOSTLY),
616
+ "pele-series-7": mix(muted, accent, HALF),
617
+ "pele-series-8": mix(muted, bg, MOSTLY)
618
+ };
619
+ }
620
+
621
+ // A theme alias chain 12 deep still resolves; deeper nesting refuses, so a cyclic alias fails instead of hanging the helper.
622
+ const RESOLVER_DEPTH_MAX = 12;
623
+
624
+ // Sample input: 'a="var(--_x)" b="var(--y, #fff)"' with --_x defined as var(--z) and --z as #000 reads 'a="#000" b="#fff"'.
625
+ function resolve(text, table, depth) {
626
+ return text.replace(/var\(\s*--([\w-]+)\s*(?:,((?:[^()]|\([^()]*\))*))?\)/g, (all, name, fallback) => {
627
+ if (depth > RESOLVER_DEPTH_MAX)
628
+ throw new Error("diagram style nests too deep");
629
+ if (Object.prototype.hasOwnProperty.call(table, name))
630
+ return resolve(table[name], table, depth + 1);
631
+ if (fallback !== undefined)
632
+ return resolve(fallback.trim(), table, depth + 1);
633
+ return all;
634
+ });
635
+ }
636
+
637
+ // The root's private aliases (--_bg:var(--pele-bg,#fff); ...) join the table, so each alias reads its role's value.
638
+ function aliasesOf(svg, table) {
639
+ const root = svg.match(/^<svg\b[^>]*\sstyle="([^"]*)"/);
640
+ const out = Object.assign({}, table);
641
+ if (root) {
642
+ for (const declaration of root[1].split(";")) {
643
+ const at = declaration.indexOf(":");
644
+ const name = declaration.slice(0, at).trim();
645
+ if (at > 0 && name.startsWith("--"))
646
+ out[name.slice(2)] = declaration.slice(at + 1).trim();
647
+ }
648
+ }
649
+ return out;
650
+ }
651
+
652
+ // Sample input: '<text fill="var(--x)">var(--x)</text>' hands the rewrite "var(--x)" once, from the fill: every attribute value, in either quote style, and never a label's words.
653
+ function inAttributes(svg, rewrite) {
654
+ return svg.replace(/<[^<>"']*(?:(?:"[^"]*"|'[^']*')[^<>"']*)*>/g, (tag) => tag.replace(/(=\s*)(?:"([^"]*)"|'([^']*)')/g,
655
+ (all, equals, double, single) => (double !== undefined ? equals + '"' + rewrite(double) + '"' : equals + "'" + rewrite(single) + "'")));
656
+ }
657
+
658
+ // Sample input: a theme without today answers this day's noon UTC in ms; the helper's jail pins TZ=UTC, so local getters read it back as the asked day.
659
+ function todayOf(theme) {
660
+ if (theme.today > 0)
661
+ return theme.today;
662
+ const now = new Date();
663
+ return new Date(now.getFullYear(), now.getMonth(), now.getDate(), MIDDAY_HOUR).getTime();
664
+ }
665
+
666
+ // Sample input: 'stroke="color-mix(in srgb,#ffffff 25%,#000000)"' reads 'stroke="#404040"', since neither renderer reads color-mix.
667
+ function mixed(text) {
668
+ return text.replace(/color-mix\(\s*in srgb\s*,\s*(#(?:[0-9a-f]{3}){1,2})\s+([\d.]+)%\s*,\s*(#(?:[0-9a-f]{3}){1,2})\s*\)/gi,
669
+ (all, a, share, b) => mix(a, b, parseFloat(share) / PERCENT));
670
+ }
671
+
672
+ // One diagram as SVG whose every colour, font and weight is a concrete value of the theme it is handed.
673
+ export function mermaidToSvg(source, theme) {
674
+ theme = theme || {};
675
+ const result = render(withSequenceDefaults(source), {
676
+ measurer: measurerOf(theme),
677
+ fontFamily: theme.font || "sans-serif",
678
+ fontFamilyMono: theme.font || "monospace",
679
+ fontSize: LAYOUT_PX,
680
+ padding: PADDING,
681
+ responsive: false,
682
+ autoDirection: false,
683
+ links: false,
684
+ images: false,
685
+ idPrefix: "flea",
686
+ // A Gantt today marker moves once a day, so one day's renders match byte for byte.
687
+ now: todayOf(theme)
688
+ });
689
+ const svg = result.svg.replace('<g class="pele-lifelines"', LIFELINES);
690
+ const table = aliasesOf(svg, rolesOf(theme));
691
+ const drawn = inAttributes(svg, (value) => mixed(resolve(value, table, 0)));
692
+ const type = detectType(source);
693
+ const old = type === "sequence" ? oldMessageRows(drawn, source) : type === "flowchart" ? oldFlowchartBoxes(drawn, source) : drawn;
694
+ return scaledCanvas(old, theme.bodyPx);
695
+ }