waybetter 0.1.0 → 0.6.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 (515) hide show
  1. package/README.md +143 -9
  2. package/bin/waybetter.mjs +46 -0
  3. package/build/runtime.mjs +105 -0
  4. package/cli/buildenv.mjs +130 -0
  5. package/cli/dev.mjs +97 -0
  6. package/cli/i18n.mjs +382 -0
  7. package/cli/manifests.mjs +383 -0
  8. package/cli/privacy.mjs +768 -0
  9. package/cli/release.mjs +444 -0
  10. package/cli/remote.mjs +260 -0
  11. package/cli/store.mjs +326 -0
  12. package/cli/strings.mjs +121 -0
  13. package/dist/runtime/column.d.ts +93 -0
  14. package/dist/runtime/column.js +451 -0
  15. package/dist/runtime/column.js.map +1 -0
  16. package/dist/runtime/commandReport.d.ts +19 -0
  17. package/dist/runtime/commandReport.js +47 -0
  18. package/dist/runtime/commandReport.js.map +1 -0
  19. package/dist/runtime/commands.d.ts +72 -0
  20. package/dist/runtime/commands.js +214 -0
  21. package/dist/runtime/commands.js.map +1 -0
  22. package/dist/runtime/devErrors.d.ts +16 -0
  23. package/dist/runtime/devErrors.js +30 -0
  24. package/dist/runtime/devErrors.js.map +1 -0
  25. package/dist/runtime/domHub.d.ts +21 -0
  26. package/dist/runtime/domHub.js +139 -4
  27. package/dist/runtime/domHub.js.map +1 -1
  28. package/dist/runtime/featureModules.d.ts +157 -0
  29. package/dist/runtime/featureModules.js +484 -0
  30. package/dist/runtime/featureModules.js.map +1 -0
  31. package/dist/runtime/featureTable.d.ts +144 -0
  32. package/dist/runtime/featureTable.js +223 -0
  33. package/dist/runtime/featureTable.js.map +1 -0
  34. package/dist/runtime/fonts.d.ts +22 -0
  35. package/dist/runtime/fonts.js +72 -0
  36. package/dist/runtime/fonts.js.map +1 -0
  37. package/dist/runtime/i18n.d.ts +138 -0
  38. package/dist/runtime/i18n.js +614 -0
  39. package/dist/runtime/i18n.js.map +1 -0
  40. package/dist/runtime/i18nCheck.d.ts +30 -0
  41. package/dist/runtime/i18nCheck.js +224 -0
  42. package/dist/runtime/i18nCheck.js.map +1 -0
  43. package/dist/runtime/pageLang.d.ts +8 -0
  44. package/dist/runtime/pageLang.js +64 -0
  45. package/dist/runtime/pageLang.js.map +1 -0
  46. package/dist/runtime/pageStrings.d.ts +35 -0
  47. package/dist/runtime/pageStrings.js +76 -0
  48. package/dist/runtime/pageStrings.js.map +1 -0
  49. package/dist/runtime/panelButton.d.ts +33 -0
  50. package/dist/runtime/panelButton.js +83 -0
  51. package/dist/runtime/panelButton.js.map +1 -0
  52. package/dist/runtime/permissions.d.ts +47 -0
  53. package/dist/runtime/permissions.js +141 -0
  54. package/dist/runtime/permissions.js.map +1 -0
  55. package/dist/runtime/pluginApi.d.ts +51 -2
  56. package/dist/runtime/pluginApi.js +137 -22
  57. package/dist/runtime/pluginApi.js.map +1 -1
  58. package/dist/runtime/pluginI18n.d.ts +29 -0
  59. package/dist/runtime/pluginI18n.js +119 -0
  60. package/dist/runtime/pluginI18n.js.map +1 -0
  61. package/dist/runtime/settingsForm.d.ts +66 -0
  62. package/dist/runtime/settingsForm.js +114 -0
  63. package/dist/runtime/settingsForm.js.map +1 -0
  64. package/dist/runtime/site.d.ts +5 -0
  65. package/dist/runtime/site.js +1 -1
  66. package/dist/runtime/site.js.map +1 -1
  67. package/dist/runtime/siteRuntime.d.ts +144 -0
  68. package/dist/runtime/siteRuntime.js +175 -0
  69. package/dist/runtime/siteRuntime.js.map +1 -0
  70. package/dist/runtime/stringPackHook.d.ts +84 -0
  71. package/dist/runtime/stringPackHook.js +220 -0
  72. package/dist/runtime/stringPackHook.js.map +1 -0
  73. package/dist/runtime/stringPackTranslate.d.ts +59 -0
  74. package/dist/runtime/stringPackTranslate.js +264 -0
  75. package/dist/runtime/stringPackTranslate.js.map +1 -0
  76. package/dist/runtime/stringPacks.d.ts +200 -0
  77. package/dist/runtime/stringPacks.js +474 -0
  78. package/dist/runtime/stringPacks.js.map +1 -0
  79. package/dist/runtime/styles.d.ts +15 -0
  80. package/dist/runtime/styles.js +81 -0
  81. package/dist/runtime/styles.js.map +1 -0
  82. package/dist/runtime/textNet.d.ts +15 -0
  83. package/dist/runtime/textNet.js +131 -0
  84. package/dist/runtime/textNet.js.map +1 -0
  85. package/dist/runtime/themeApi.d.ts +121 -0
  86. package/dist/runtime/themeApi.js +220 -0
  87. package/dist/runtime/themeApi.js.map +1 -0
  88. package/dist/runtime/themeChoice.d.ts +52 -0
  89. package/dist/runtime/themeChoice.js +69 -0
  90. package/dist/runtime/themeChoice.js.map +1 -0
  91. package/dist/runtime/themeComponents.d.ts +435 -0
  92. package/dist/runtime/themeComponents.js +463 -0
  93. package/dist/runtime/themeComponents.js.map +1 -0
  94. package/dist/runtime/themeDecor.d.ts +73 -0
  95. package/dist/runtime/themeDecor.js +131 -0
  96. package/dist/runtime/themeDecor.js.map +1 -0
  97. package/dist/runtime/themeDoctor.d.ts +11 -0
  98. package/dist/runtime/themeDoctor.js +51 -0
  99. package/dist/runtime/themeDoctor.js.map +1 -0
  100. package/dist/runtime/themeIcons.d.ts +130 -0
  101. package/dist/runtime/themeIcons.js +263 -0
  102. package/dist/runtime/themeIcons.js.map +1 -0
  103. package/dist/runtime/themeRuntime.d.ts +100 -0
  104. package/dist/runtime/themeRuntime.js +497 -0
  105. package/dist/runtime/themeRuntime.js.map +1 -0
  106. package/dist/runtime/themeSchema.d.ts +10 -0
  107. package/dist/runtime/themeSchema.js +150 -0
  108. package/dist/runtime/themeSchema.js.map +1 -0
  109. package/dist/runtime/themeSpec.d.ts +259 -0
  110. package/dist/runtime/themeSpec.js +439 -0
  111. package/dist/runtime/themeSpec.js.map +1 -0
  112. package/dist/runtime/themeTokens.d.ts +12 -0
  113. package/dist/runtime/themeTokens.js +14 -6
  114. package/dist/runtime/themeTokens.js.map +1 -1
  115. package/dist/runtime/themeVariants.d.ts +30 -0
  116. package/dist/runtime/themeVariants.js +53 -0
  117. package/dist/runtime/themeVariants.js.map +1 -0
  118. package/dist/runtime/ui.d.ts +192 -0
  119. package/dist/runtime/ui.js +926 -0
  120. package/dist/runtime/ui.js.map +1 -0
  121. package/dist/shell/InstallDialog.d.ts +40 -0
  122. package/dist/shell/InstallDialog.js +170 -0
  123. package/dist/shell/InstallDialog.js.map +1 -0
  124. package/dist/shell/StoreView.d.ts +66 -0
  125. package/dist/shell/StoreView.js +103 -0
  126. package/dist/shell/StoreView.js.map +1 -0
  127. package/dist/shell/addressModel.js.map +1 -1
  128. package/dist/shell/chrome.js.map +1 -1
  129. package/dist/shell/deckModel.d.ts +117 -0
  130. package/dist/shell/deckModel.js +267 -0
  131. package/dist/shell/deckModel.js.map +1 -0
  132. package/dist/shell/frame/AccountSwitcher.d.ts +42 -0
  133. package/dist/shell/frame/AccountSwitcher.js +243 -0
  134. package/dist/shell/frame/AccountSwitcher.js.map +1 -0
  135. package/dist/shell/frame/AddColumnDialog.d.ts +8 -0
  136. package/dist/shell/frame/AddColumnDialog.js +81 -0
  137. package/dist/shell/frame/AddColumnDialog.js.map +1 -0
  138. package/dist/shell/frame/AppMenu.d.ts +21 -0
  139. package/dist/shell/frame/AppMenu.js +642 -0
  140. package/dist/shell/frame/AppMenu.js.map +1 -0
  141. package/dist/shell/frame/CommandPalette.d.ts +7 -0
  142. package/dist/shell/frame/CommandPalette.js +118 -0
  143. package/dist/shell/frame/CommandPalette.js.map +1 -0
  144. package/dist/shell/frame/DeckView.d.ts +13 -0
  145. package/dist/shell/frame/DeckView.js +287 -0
  146. package/dist/shell/frame/DeckView.js.map +1 -0
  147. package/dist/shell/frame/FindBar.d.ts +10 -0
  148. package/dist/shell/frame/FindBar.js +108 -0
  149. package/dist/shell/frame/FindBar.js.map +1 -0
  150. package/dist/shell/frame/MediaPanel.d.ts +8 -0
  151. package/dist/shell/frame/MediaPanel.js +76 -0
  152. package/dist/shell/frame/MediaPanel.js.map +1 -0
  153. package/dist/shell/frame/NewTabPage.d.ts +9 -0
  154. package/dist/shell/frame/NewTabPage.js +71 -0
  155. package/dist/shell/frame/NewTabPage.js.map +1 -0
  156. package/dist/shell/frame/PaneTheme.d.ts +16 -0
  157. package/dist/shell/frame/PaneTheme.js +67 -0
  158. package/dist/shell/frame/PaneTheme.js.map +1 -0
  159. package/dist/shell/frame/ReportDialog.d.ts +3 -0
  160. package/dist/shell/frame/ReportDialog.js +95 -0
  161. package/dist/shell/frame/ReportDialog.js.map +1 -0
  162. package/dist/shell/frame/Shell.d.ts +8 -0
  163. package/dist/shell/frame/Shell.js +1131 -0
  164. package/dist/shell/frame/Shell.js.map +1 -0
  165. package/dist/shell/frame/Titlebar.d.ts +16 -0
  166. package/dist/shell/frame/Titlebar.js +77 -0
  167. package/dist/shell/frame/Titlebar.js.map +1 -0
  168. package/dist/shell/frame/TitlebarExtras.d.ts +4 -0
  169. package/dist/shell/frame/TitlebarExtras.js +202 -0
  170. package/dist/shell/frame/TitlebarExtras.js.map +1 -0
  171. package/dist/shell/frame/WebPanel.d.ts +4 -0
  172. package/dist/shell/frame/WebPanel.js +182 -0
  173. package/dist/shell/frame/WebPanel.js.map +1 -0
  174. package/dist/shell/frame/accountModel.d.ts +49 -0
  175. package/dist/shell/frame/accountModel.js +67 -0
  176. package/dist/shell/frame/accountModel.js.map +1 -0
  177. package/dist/shell/frame/accountSwitcher.css +91 -0
  178. package/dist/shell/frame/appI18n.d.ts +44 -0
  179. package/dist/shell/frame/appI18n.js +64 -0
  180. package/dist/shell/frame/appI18n.js.map +1 -0
  181. package/dist/shell/frame/appMenu.css +121 -0
  182. package/dist/shell/frame/backupModel.d.ts +38 -0
  183. package/dist/shell/frame/backupModel.js +192 -0
  184. package/dist/shell/frame/backupModel.js.map +1 -0
  185. package/dist/shell/frame/boot.d.ts +8 -0
  186. package/dist/shell/frame/boot.js +35 -0
  187. package/dist/shell/frame/boot.js.map +1 -0
  188. package/dist/shell/frame/brand.d.ts +1 -0
  189. package/dist/shell/frame/brand.js +4 -0
  190. package/dist/shell/frame/brand.js.map +1 -0
  191. package/dist/shell/frame/bridge.d.ts +35 -0
  192. package/dist/shell/frame/bridge.js +70 -0
  193. package/dist/shell/frame/bridge.js.map +1 -0
  194. package/dist/shell/frame/chromeTheme.d.ts +29 -0
  195. package/dist/shell/frame/chromeTheme.js +81 -0
  196. package/dist/shell/frame/chromeTheme.js.map +1 -0
  197. package/dist/shell/frame/deck.css +209 -0
  198. package/dist/shell/frame/deckStore.d.ts +89 -0
  199. package/dist/shell/frame/deckStore.js +239 -0
  200. package/dist/shell/frame/deckStore.js.map +1 -0
  201. package/dist/shell/frame/devHost.d.ts +35 -0
  202. package/dist/shell/frame/devHost.js +80 -0
  203. package/dist/shell/frame/devHost.js.map +1 -0
  204. package/dist/shell/frame/devModel.d.ts +7 -0
  205. package/dist/shell/frame/devModel.js +17 -0
  206. package/dist/shell/frame/devModel.js.map +1 -0
  207. package/dist/shell/frame/diag.d.ts +7 -0
  208. package/dist/shell/frame/diag.js +39 -0
  209. package/dist/shell/frame/diag.js.map +1 -0
  210. package/dist/shell/frame/findBar.css +14 -0
  211. package/dist/shell/frame/frameMessages.d.ts +248 -0
  212. package/dist/shell/frame/frameMessages.js +252 -0
  213. package/dist/shell/frame/frameMessages.js.map +1 -0
  214. package/dist/shell/frame/hooks.d.ts +39 -0
  215. package/dist/shell/frame/hooks.js +97 -0
  216. package/dist/shell/frame/hooks.js.map +1 -0
  217. package/dist/shell/frame/i18n.d.ts +27 -0
  218. package/dist/shell/frame/i18n.js +66 -0
  219. package/dist/shell/frame/i18n.js.map +1 -0
  220. package/dist/shell/frame/iconPack.d.ts +11 -0
  221. package/dist/shell/frame/iconPack.js +45 -0
  222. package/dist/shell/frame/iconPack.js.map +1 -0
  223. package/dist/shell/frame/icons.d.ts +71 -0
  224. package/dist/shell/frame/icons.js +75 -0
  225. package/dist/shell/frame/icons.js.map +1 -0
  226. package/dist/shell/frame/index.d.ts +34 -0
  227. package/dist/shell/frame/index.js +43 -0
  228. package/dist/shell/frame/index.js.map +1 -0
  229. package/dist/shell/frame/language.d.ts +58 -0
  230. package/dist/shell/frame/language.js +165 -0
  231. package/dist/shell/frame/language.js.map +1 -0
  232. package/dist/shell/frame/mediaModel.d.ts +34 -0
  233. package/dist/shell/frame/mediaModel.js +53 -0
  234. package/dist/shell/frame/mediaModel.js.map +1 -0
  235. package/dist/shell/frame/menuMessages.en.json +54 -0
  236. package/dist/shell/frame/menuModel.d.ts +277 -0
  237. package/dist/shell/frame/menuModel.js +293 -0
  238. package/dist/shell/frame/menuModel.js.map +1 -0
  239. package/dist/shell/frame/paletteModel.d.ts +139 -0
  240. package/dist/shell/frame/paletteModel.js +112 -0
  241. package/dist/shell/frame/paletteModel.js.map +1 -0
  242. package/dist/shell/frame/paneTheme.css +9 -0
  243. package/dist/shell/frame/pluginCommandStore.d.ts +23 -0
  244. package/dist/shell/frame/pluginCommandStore.js +70 -0
  245. package/dist/shell/frame/pluginCommandStore.js.map +1 -0
  246. package/dist/shell/frame/reportModel.d.ts +52 -0
  247. package/dist/shell/frame/reportModel.js +105 -0
  248. package/dist/shell/frame/reportModel.js.map +1 -0
  249. package/dist/shell/frame/safeStore.d.ts +7 -0
  250. package/dist/shell/frame/safeStore.js +40 -0
  251. package/dist/shell/frame/safeStore.js.map +1 -0
  252. package/dist/shell/frame/searchInput.d.ts +2 -0
  253. package/dist/shell/frame/searchInput.js +11 -0
  254. package/dist/shell/frame/searchInput.js.map +1 -0
  255. package/dist/shell/frame/shell.css +629 -0
  256. package/dist/shell/frame/site.d.ts +206 -0
  257. package/dist/shell/frame/site.js +22 -0
  258. package/dist/shell/frame/site.js.map +1 -0
  259. package/dist/shell/frame/state.d.ts +99 -0
  260. package/dist/shell/frame/state.js +284 -0
  261. package/dist/shell/frame/state.js.map +1 -0
  262. package/dist/shell/frame/syncGate.d.ts +10 -0
  263. package/dist/shell/frame/syncGate.js +36 -0
  264. package/dist/shell/frame/syncGate.js.map +1 -0
  265. package/dist/shell/frame/syncHost.d.ts +35 -0
  266. package/dist/shell/frame/syncHost.js +85 -0
  267. package/dist/shell/frame/syncHost.js.map +1 -0
  268. package/dist/shell/frame/tabStill.d.ts +2 -0
  269. package/dist/shell/frame/tabStill.js +62 -0
  270. package/dist/shell/frame/tabStill.js.map +1 -0
  271. package/dist/shell/frame/themeScopes.d.ts +29 -0
  272. package/dist/shell/frame/themeScopes.js +61 -0
  273. package/dist/shell/frame/themeScopes.js.map +1 -0
  274. package/dist/shell/frame/themeStore.d.ts +99 -0
  275. package/dist/shell/frame/themeStore.js +252 -0
  276. package/dist/shell/frame/themeStore.js.map +1 -0
  277. package/dist/shell/frame/windowBinding.d.ts +2 -0
  278. package/dist/shell/frame/windowBinding.js +7 -0
  279. package/dist/shell/frame/windowBinding.js.map +1 -0
  280. package/dist/shell/frame/workspaceModel.d.ts +82 -0
  281. package/dist/shell/frame/workspaceModel.js +250 -0
  282. package/dist/shell/frame/workspaceModel.js.map +1 -0
  283. package/dist/shell/frame/workspaces.css +84 -0
  284. package/dist/shell/frame/workspaces.d.ts +22 -0
  285. package/dist/shell/frame/workspaces.js +125 -0
  286. package/dist/shell/frame/workspaces.js.map +1 -0
  287. package/dist/shell/frame/zoomStore.d.ts +10 -0
  288. package/dist/shell/frame/zoomStore.js +65 -0
  289. package/dist/shell/frame/zoomStore.js.map +1 -0
  290. package/dist/shell/installController.d.ts +122 -0
  291. package/dist/shell/installController.js +146 -0
  292. package/dist/shell/installController.js.map +1 -0
  293. package/dist/shell/installerMessages.d.ts +30 -0
  294. package/dist/shell/installerMessages.js +36 -0
  295. package/dist/shell/installerMessages.js.map +1 -0
  296. package/dist/shell/linkDrop.js.map +1 -1
  297. package/dist/shell/messages.d.ts +16 -0
  298. package/dist/shell/messages.js +27 -0
  299. package/dist/shell/messages.js.map +1 -0
  300. package/dist/shell/palette.js.map +1 -1
  301. package/dist/shell/paneModel.d.ts +22 -0
  302. package/dist/shell/paneModel.js +24 -1
  303. package/dist/shell/paneModel.js.map +1 -1
  304. package/dist/shell/panel/Appearance.d.ts +8 -0
  305. package/dist/shell/panel/Appearance.js +256 -0
  306. package/dist/shell/panel/Appearance.js.map +1 -0
  307. package/dist/shell/panel/BackupPanel.d.ts +5 -0
  308. package/dist/shell/panel/BackupPanel.js +198 -0
  309. package/dist/shell/panel/BackupPanel.js.map +1 -0
  310. package/dist/shell/panel/DeveloperPanel.d.ts +4 -0
  311. package/dist/shell/panel/DeveloperPanel.js +51 -0
  312. package/dist/shell/panel/DeveloperPanel.js.map +1 -0
  313. package/dist/shell/panel/FeatureToggles.d.ts +13 -0
  314. package/dist/shell/panel/FeatureToggles.js +42 -0
  315. package/dist/shell/panel/FeatureToggles.js.map +1 -0
  316. package/dist/shell/panel/Home.d.ts +3 -0
  317. package/dist/shell/panel/Home.js +23 -0
  318. package/dist/shell/panel/Home.js.map +1 -0
  319. package/dist/shell/panel/IconPackInstall.d.ts +15 -0
  320. package/dist/shell/panel/IconPackInstall.js +41 -0
  321. package/dist/shell/panel/IconPackInstall.js.map +1 -0
  322. package/dist/shell/panel/LanguageSettings.d.ts +1 -0
  323. package/dist/shell/panel/LanguageSettings.js +54 -0
  324. package/dist/shell/panel/LanguageSettings.js.map +1 -0
  325. package/dist/shell/panel/MakePanel.d.ts +3 -0
  326. package/dist/shell/panel/MakePanel.js +237 -0
  327. package/dist/shell/panel/MakePanel.js.map +1 -0
  328. package/dist/shell/panel/MarkdownDoc.d.ts +6 -0
  329. package/dist/shell/panel/MarkdownDoc.js +35 -0
  330. package/dist/shell/panel/MarkdownDoc.js.map +1 -0
  331. package/dist/shell/panel/Modes.d.ts +40 -0
  332. package/dist/shell/panel/Modes.js +270 -0
  333. package/dist/shell/panel/Modes.js.map +1 -0
  334. package/dist/shell/panel/NavIcon.d.ts +4 -0
  335. package/dist/shell/panel/NavIcon.js +6 -0
  336. package/dist/shell/panel/NavIcon.js.map +1 -0
  337. package/dist/shell/panel/Panel.d.ts +7 -0
  338. package/dist/shell/panel/Panel.js +139 -0
  339. package/dist/shell/panel/Panel.js.map +1 -0
  340. package/dist/shell/panel/PluginFeatures.d.ts +24 -0
  341. package/dist/shell/panel/PluginFeatures.js +165 -0
  342. package/dist/shell/panel/PluginFeatures.js.map +1 -0
  343. package/dist/shell/panel/Plugins.d.ts +33 -0
  344. package/dist/shell/panel/Plugins.js +112 -0
  345. package/dist/shell/panel/Plugins.js.map +1 -0
  346. package/dist/shell/panel/PowerSettings.d.ts +4 -0
  347. package/dist/shell/panel/PowerSettings.js +52 -0
  348. package/dist/shell/panel/PowerSettings.js.map +1 -0
  349. package/dist/shell/panel/Settings.d.ts +23 -0
  350. package/dist/shell/panel/Settings.js +116 -0
  351. package/dist/shell/panel/Settings.js.map +1 -0
  352. package/dist/shell/panel/ShareSetup.d.ts +8 -0
  353. package/dist/shell/panel/ShareSetup.js +130 -0
  354. package/dist/shell/panel/ShareSetup.js.map +1 -0
  355. package/dist/shell/panel/StoreSection.d.ts +6 -0
  356. package/dist/shell/panel/StoreSection.js +48 -0
  357. package/dist/shell/panel/StoreSection.js.map +1 -0
  358. package/dist/shell/panel/StringPacks.d.ts +11 -0
  359. package/dist/shell/panel/StringPacks.js +106 -0
  360. package/dist/shell/panel/StringPacks.js.map +1 -0
  361. package/dist/shell/panel/ThemeBuilder.d.ts +5 -0
  362. package/dist/shell/panel/ThemeBuilder.js +205 -0
  363. package/dist/shell/panel/ThemeBuilder.js.map +1 -0
  364. package/dist/shell/panel/backup.css +34 -0
  365. package/dist/shell/panel/builder.css +232 -0
  366. package/dist/shell/panel/builderModel.d.ts +55 -0
  367. package/dist/shell/panel/builderModel.js +95 -0
  368. package/dist/shell/panel/builderModel.js.map +1 -0
  369. package/dist/shell/panel/compare.d.ts +10 -0
  370. package/dist/shell/panel/compare.js +51 -0
  371. package/dist/shell/panel/compare.js.map +1 -0
  372. package/dist/shell/panel/controls.d.ts +135 -0
  373. package/dist/shell/panel/controls.js +213 -0
  374. package/dist/shell/panel/controls.js.map +1 -0
  375. package/dist/shell/panel/featureModel.d.ts +69 -0
  376. package/dist/shell/panel/featureModel.js +79 -0
  377. package/dist/shell/panel/featureModel.js.map +1 -0
  378. package/dist/shell/panel/fonts/FontBrowser.d.ts +10 -0
  379. package/dist/shell/panel/fonts/FontBrowser.js +189 -0
  380. package/dist/shell/panel/fonts/FontBrowser.js.map +1 -0
  381. package/dist/shell/panel/fonts/FontRoles.d.ts +20 -0
  382. package/dist/shell/panel/fonts/FontRoles.js +77 -0
  383. package/dist/shell/panel/fonts/FontRoles.js.map +1 -0
  384. package/dist/shell/panel/fonts/catalog.d.ts +37 -0
  385. package/dist/shell/panel/fonts/catalog.js +68 -0
  386. package/dist/shell/panel/fonts/catalog.js.map +1 -0
  387. package/dist/shell/panel/fonts/googleFontsCatalog.json +1 -0
  388. package/dist/shell/panel/index.d.ts +20 -0
  389. package/dist/shell/panel/index.js +34 -0
  390. package/dist/shell/panel/index.js.map +1 -0
  391. package/dist/shell/panel/languageModel.d.ts +5 -0
  392. package/dist/shell/panel/languageModel.js +7 -0
  393. package/dist/shell/panel/languageModel.js.map +1 -0
  394. package/dist/shell/panel/make.css +72 -0
  395. package/dist/shell/panel/makeModel.d.ts +32 -0
  396. package/dist/shell/panel/makeModel.js +84 -0
  397. package/dist/shell/panel/makeModel.js.map +1 -0
  398. package/dist/shell/panel/markdown.d.ts +46 -0
  399. package/dist/shell/panel/markdown.js +100 -0
  400. package/dist/shell/panel/markdown.js.map +1 -0
  401. package/dist/shell/panel/nav.d.ts +12 -0
  402. package/dist/shell/panel/nav.js +50 -0
  403. package/dist/shell/panel/nav.js.map +1 -0
  404. package/dist/shell/panel/panel.css +401 -0
  405. package/dist/shell/panel/panelMessages.d.ts +763 -0
  406. package/dist/shell/panel/panelMessages.js +767 -0
  407. package/dist/shell/panel/panelMessages.js.map +1 -0
  408. package/dist/shell/panel/plugins.css +59 -0
  409. package/dist/shell/panel/setupModel.d.ts +87 -0
  410. package/dist/shell/panel/setupModel.js +152 -0
  411. package/dist/shell/panel/setupModel.js.map +1 -0
  412. package/dist/shell/panel/site.d.ts +259 -0
  413. package/dist/shell/panel/site.js +25 -0
  414. package/dist/shell/panel/site.js.map +1 -0
  415. package/dist/shell/panel/strings.css +7 -0
  416. package/dist/shell/panel/themes.d.ts +10 -0
  417. package/dist/shell/panel/themes.js +8 -0
  418. package/dist/shell/panel/themes.js.map +1 -0
  419. package/dist/shell/profileModel.d.ts +3 -2
  420. package/dist/shell/profileModel.js +7 -5
  421. package/dist/shell/profileModel.js.map +1 -1
  422. package/dist/shell/store.css +230 -0
  423. package/dist/shell/storeMessages.d.ts +169 -0
  424. package/dist/shell/storeMessages.js +172 -0
  425. package/dist/shell/storeMessages.js.map +1 -0
  426. package/dist/shell/storeModel.d.ts +181 -0
  427. package/dist/shell/storeModel.js +133 -0
  428. package/dist/shell/storeModel.js.map +1 -0
  429. package/dist/shell/stringPacksModel.d.ts +44 -0
  430. package/dist/shell/stringPacksModel.js +94 -0
  431. package/dist/shell/stringPacksModel.js.map +1 -0
  432. package/dist/shell/updateModel.d.ts +2 -1
  433. package/dist/shell/updateModel.js +5 -4
  434. package/dist/shell/updateModel.js.map +1 -1
  435. package/dist/shell/windowControls.d.ts +4 -0
  436. package/dist/shell/windowControls.js +5 -0
  437. package/dist/shell/windowControls.js.map +1 -1
  438. package/i18n-config.schema.json +29 -0
  439. package/i18n-meta.schema.json +26 -0
  440. package/i18n.schema.json +42 -0
  441. package/icons.schema.json +646 -0
  442. package/languages.schema.json +23 -0
  443. package/locales/ar-x-fm.json +11 -0
  444. package/locales/ar.json +1281 -0
  445. package/locales/bg.json +1280 -0
  446. package/locales/bn.json +1280 -0
  447. package/locales/ca.json +1280 -0
  448. package/locales/cs.json +1280 -0
  449. package/locales/da.json +1280 -0
  450. package/locales/de.json +1280 -0
  451. package/locales/el.json +1280 -0
  452. package/locales/en-GB.json +27 -0
  453. package/locales/en.json +1280 -0
  454. package/locales/en.meta.json +51 -0
  455. package/locales/es.json +1280 -0
  456. package/locales/eu.json +1280 -0
  457. package/locales/fa.json +1281 -0
  458. package/locales/fi.json +1280 -0
  459. package/locales/fil.json +1280 -0
  460. package/locales/fr.json +1280 -0
  461. package/locales/ga.json +1280 -0
  462. package/locales/gl.json +1280 -0
  463. package/locales/gu.json +1280 -0
  464. package/locales/ha.json +1280 -0
  465. package/locales/he.json +1281 -0
  466. package/locales/hi.json +1280 -0
  467. package/locales/hr.json +1280 -0
  468. package/locales/hu.json +1279 -0
  469. package/locales/id.json +1280 -0
  470. package/locales/ig.json +1280 -0
  471. package/locales/it.json +1280 -0
  472. package/locales/ja.json +1280 -0
  473. package/locales/kn.json +1280 -0
  474. package/locales/ko.json +1280 -0
  475. package/locales/mr.json +1280 -0
  476. package/locales/ms.json +1280 -0
  477. package/locales/nb.json +1280 -0
  478. package/locales/nl.json +1280 -0
  479. package/locales/pl.json +1280 -0
  480. package/locales/pt.json +1280 -0
  481. package/locales/ro.json +1280 -0
  482. package/locales/ru.json +1280 -0
  483. package/locales/sk.json +1280 -0
  484. package/locales/sr.json +1280 -0
  485. package/locales/sv.json +1280 -0
  486. package/locales/ta.json +1280 -0
  487. package/locales/th.json +1280 -0
  488. package/locales/tr.json +1280 -0
  489. package/locales/uk.json +1280 -0
  490. package/locales/ur.json +1281 -0
  491. package/locales/vi.json +1280 -0
  492. package/locales/yo.json +1280 -0
  493. package/locales/zh-Hans.json +1280 -0
  494. package/locales/zh-Hant.json +1280 -0
  495. package/package.json +148 -6
  496. package/store-catalog.schema.json +65 -0
  497. package/theme.schema.json +4659 -0
  498. package/windows/installer.nsi +926 -0
  499. package/windows/languages/Basque.nsh +28 -0
  500. package/windows/languages/Catalan.nsh +28 -0
  501. package/windows/languages/Croatian.nsh +28 -0
  502. package/windows/languages/Czech.nsh +28 -0
  503. package/windows/languages/Danish.nsh +28 -0
  504. package/windows/languages/Finnish.nsh +28 -0
  505. package/windows/languages/Galician.nsh +28 -0
  506. package/windows/languages/Greek.nsh +28 -0
  507. package/windows/languages/Hungarian.nsh +28 -0
  508. package/windows/languages/Indonesian.nsh +28 -0
  509. package/windows/languages/Irish.nsh +28 -0
  510. package/windows/languages/Malay.nsh +28 -0
  511. package/windows/languages/Polish.nsh +28 -0
  512. package/windows/languages/Romanian.nsh +28 -0
  513. package/windows/languages/Serbian.nsh +28 -0
  514. package/windows/languages/Slovak.nsh +28 -0
  515. package/windows/languages/Thai.nsh +28 -0
@@ -0,0 +1,642 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ // The app menu: the titlebar's "Settings and more" button, at the far end of the titlebar cluster
3
+ // (before the caption buttons on Windows and Linux; macOS has none there). It opens on click, on
4
+ // Alt+F and F10 (Shell.tsx; a focused tab forwards the keys), from the command palette, from the
5
+ // last row of the account menu, and from the app's logo at the start of the titlebar (the same
6
+ // menu, hung under the logo on its side of the window). Its rows are the app's (`ShellSite.menu`, menuModel.ts): built-in
7
+ // ones by name, each shown only when the app serves what it needs, and the app's own.
8
+ //
9
+ // Like every shell menu it is an overlay: while open the shell is raised above the tab webviews
10
+ // (`setOverlay`), panes stay visible and nothing is dimmed. Keyboard: arrows, Home/End, type-ahead,
11
+ // the arrow pointing along the reading direction opens a submenu and the other one closes it,
12
+ // Enter or Space chooses, Esc closes one level. Submenus fly out beside the menu and stay inside
13
+ // the window (in a narrow one they lie over it). Words: menuMessages.en.json (`menuText`).
14
+ import { useEffect, useLayoutEffect, useReducer, useRef, useState } from 'react';
15
+ import { createPortal } from 'react-dom';
16
+ import { parseUpdateStatus } from "../updateModel.js";
17
+ import { invoke, listen } from "./bridge.js";
18
+ import { describe, diag } from "./diag.js";
19
+ import { decks } from "./deckStore.js";
20
+ import { refreshDev } from "./devHost.js";
21
+ import { useDev, usePaneTick, useT } from "./hooks.js";
22
+ import { formatNumber } from "./i18n.js";
23
+ import { Icon } from "./icons.js";
24
+ import { DEFAULT_MENU, ZOOM_MAX, ZOOM_MIN, findSpec, joinGroups, languageChoice, languageRows, menuText, moveStop, planMenu, shortcutText, specRows, submenuKeys, submenuLeft, typeahead, updateRow, } from "./menuModel.js";
25
+ import { ReportDialog } from "./ReportDialog.js";
26
+ import { safe, setSafeMode } from "./safeStore.js";
27
+ import { hasFeature, site } from "./site.js";
28
+ import { isWeb, setOverlay, shell } from "./state.js";
29
+ import { openWorkspaceSave } from "./TitlebarExtras.js";
30
+ import { os, startDrag, systemMenu } from "./windowBinding.js";
31
+ import { loadWorkspaces, restoreWorkspace, workspaceList, workspaces } from "./workspaces.js";
32
+ import { readZoom, stepZoom, zoomOf, zoomTarget } from "./zoomStore.js";
33
+ import './appMenu.css';
34
+ /** Opens the app menu (Alt+F / F10, the palette, the account menu's last row). */
35
+ export const openAppMenu = (request = {}) => window.dispatchEvent(new CustomEvent('bt-app-menu', { detail: request }));
36
+ const mac = os === 'macos';
37
+ /** The keys that open the menu, as the button's tooltip and the account menu write them. */
38
+ export const APP_MENU_KEYS = mac ? 'F10' : 'Alt+F';
39
+ const getError = (error) => (error instanceof Error ? error.message : String(error)).replace(/^Error: /, '');
40
+ const percent = (factor) => formatNumber(factor, { style: 'percent', maximumFractionDigits: 0 });
41
+ /** Which trigger the open menu hangs from (null: closed), for the triggers' `aria-expanded`. */
42
+ let openAt = null;
43
+ function noteOpen(at) {
44
+ if (openAt === at)
45
+ return;
46
+ openAt = at;
47
+ window.dispatchEvent(new CustomEvent('bt-app-menu-state'));
48
+ }
49
+ /** The rows of one level a key can stop on: enabled items; the zoom row counts once. */
50
+ function stopsOf(menu) {
51
+ const all = Array.from(menu.querySelectorAll('[data-item]:not(:disabled)'));
52
+ const active = document.activeElement;
53
+ const zoom = all.filter(el => 'zoom' in el.dataset);
54
+ const keep = zoom.find(el => el === active) ?? zoom.find(el => el.getAttribute('aria-disabled') !== 'true') ?? zoom[0];
55
+ return all.filter(el => !('zoom' in el.dataset) || el === keep);
56
+ }
57
+ export function AppMenu({ trigger = true } = {}) {
58
+ const t = useT();
59
+ usePaneTick();
60
+ const dev = useDev();
61
+ const config = site();
62
+ const menu = config.menu ?? {};
63
+ const [open, setOpen] = useState(false);
64
+ const [path, setPath] = useState([]);
65
+ const [anchor, setAnchor] = useState({ at: 'button', top: 50, right: 8 });
66
+ const [mode, setMode] = useState(null);
67
+ const [modeStatus, setModeStatus] = useState(null);
68
+ const [asking, setAsking] = useState(null);
69
+ const [version, setVersion] = useState('');
70
+ const [update, setUpdate] = useState({ state: 'idle' });
71
+ const [askedUpdate, setAskedUpdate] = useState(false);
72
+ const [reporting, setReporting] = useState(false);
73
+ const [error, setError] = useState('');
74
+ const [, tick] = useReducer((n) => n + 1, 0);
75
+ const button = useRef(null);
76
+ const layers = useRef(null);
77
+ const focusNext = useRef(null);
78
+ const before = useRef(null);
79
+ const hover = useRef({ el: null });
80
+ const typed = useRef({ text: '', at: 0 });
81
+ const live = useRef({ open, path });
82
+ live.current = { open, path };
83
+ // Whatever a row shows may change while the menu is open (a language or theme picked in it).
84
+ useEffect(() => {
85
+ const events = ['bt-zoom', 'bt-workspaces', 'bt-decks', 'bt-site', 'bt-safe'];
86
+ for (const event of events)
87
+ window.addEventListener(event, tick);
88
+ const off = [config.themes?.subscribe(tick), menu.languages?.subscribe(tick)];
89
+ return () => {
90
+ for (const event of events)
91
+ window.removeEventListener(event, tick);
92
+ for (const dispose of off)
93
+ dispose?.();
94
+ };
95
+ }, []);
96
+ /** Where a request without an anchor opens: the button when this app shows one, else the logo. */
97
+ const home = () => (trigger ? 'button' : 'logo');
98
+ function show(request = {}) {
99
+ const at = request.anchor ?? home();
100
+ diag(`menu open: anchor=${at} keyboard=${!!request.keyboard} hasFocus=${document.hasFocus()} active=${describe(document.activeElement)}`);
101
+ const logo = at === 'logo' ? document.querySelector('.bt-titlebar-logo') : null;
102
+ const rect = (logo ?? button.current)?.getBoundingClientRect();
103
+ if (rect) {
104
+ const top = Math.round(rect.bottom + 6);
105
+ setAnchor(logo ? { at: 'logo', top, left: Math.max(8, Math.round(rect.left - 3)) } : { at: 'button', top, right: Math.max(8, Math.round(window.innerWidth - rect.right)) });
106
+ }
107
+ const active = document.activeElement;
108
+ before.current = active && active !== document.body && document.hasFocus() ? active : null;
109
+ // Keys pressed in a tab open the menu: the shell takes the keyboard. A click on the shell already
110
+ // gave it the keyboard, so nothing native is asked for then.
111
+ if (!document.hasFocus())
112
+ invoke('shell_focus').catch(() => { });
113
+ setAsking(null);
114
+ setError('');
115
+ setPath(request.submenu ? [request.submenu] : []);
116
+ focusNext.current = request.submenu ? { level: 1, edge: 'first' } : { level: 0, edge: request.keyboard ? 'first' : 'menu' };
117
+ setOpen(true);
118
+ // What the rows show, read fresh.
119
+ void readZoom(zoomTarget());
120
+ if (hasFeature('developer'))
121
+ void refreshDev();
122
+ if (hasFeature('workspaces') && !workspaces.loaded)
123
+ void loadWorkspaces().catch(() => { });
124
+ void config.themes?.loadThemes();
125
+ menu.modes?.current().then(setMode, () => { });
126
+ menu.modes?.status?.().then(setModeStatus, () => { });
127
+ if (!version)
128
+ menu.version?.().then(setVersion, () => { });
129
+ setAskedUpdate(false);
130
+ if (hasFeature('updates'))
131
+ invoke('update_status').then(value => setUpdate(parseUpdateStatus(value)), () => { });
132
+ }
133
+ /** `escape`: back to what had focus before. `action` and `away`: nothing focused, so typing returns to the active pane. */
134
+ function close(how = 'away', why = '') {
135
+ diag(`menu close: ${how}${why ? ` (${why})` : ''} hasFocus=${document.hasFocus()}`);
136
+ clearTimeout(hover.current.timer);
137
+ hover.current = { el: null };
138
+ focusNext.current = null;
139
+ setOpen(false);
140
+ setPath([]);
141
+ setAsking(null);
142
+ setError('');
143
+ if (how === 'escape' && before.current?.isConnected)
144
+ before.current.focus();
145
+ before.current = null;
146
+ }
147
+ // The updater's steps (checking, downloading, ready) as they happen.
148
+ useEffect(() => {
149
+ if (!hasFeature('updates'))
150
+ return;
151
+ let disposed = false;
152
+ let unlisten;
153
+ listen('update-status', event => setUpdate(parseUpdateStatus(event.payload)))
154
+ .then(dispose => { if (disposed)
155
+ dispose();
156
+ else
157
+ unlisten = dispose; })
158
+ .catch(() => { });
159
+ return () => { disposed = true; unlisten?.(); };
160
+ }, []);
161
+ useEffect(() => {
162
+ const onRequest = (event) => {
163
+ const request = event.detail ?? {};
164
+ // Asked again from the other trigger, the open menu moves there instead of closing.
165
+ if (live.current.open && request.toggle && (request.anchor ?? home()) === (openAt ?? home()))
166
+ close('escape');
167
+ else
168
+ show(request);
169
+ };
170
+ window.addEventListener('bt-app-menu', onRequest);
171
+ return () => window.removeEventListener('bt-app-menu', onRequest);
172
+ }, [version]);
173
+ useEffect(() => {
174
+ if (!open)
175
+ return;
176
+ // Native tab webviews would cover the menu.
177
+ setOverlay(1);
178
+ noteOpen(anchor.at);
179
+ // The window lost the keyboard: the menu closes, unless the focus is back a moment later (taking the
180
+ // keyboard from a tab for Alt+F / F10 can pass through a blur on its way to the shell).
181
+ let leaving;
182
+ const away = () => {
183
+ diag(`menu: window blur hasFocus=${document.hasFocus()}`);
184
+ clearTimeout(leaving);
185
+ leaving = setTimeout(() => { if (!document.hasFocus())
186
+ close('away', 'blur');
187
+ else
188
+ diag('menu: blur passed, focus is back'); }, 160);
189
+ };
190
+ const resized = () => close();
191
+ // Keys while nothing in the menu has focus (a click on its padding): Esc closes, arrows enter it.
192
+ const onKey = (event) => {
193
+ if (layers.current?.contains(event.target))
194
+ return;
195
+ if (event.key === 'Escape') {
196
+ event.preventDefault();
197
+ close('escape');
198
+ return;
199
+ }
200
+ if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
201
+ event.preventDefault();
202
+ focusNext.current = { level: live.current.path.length, edge: event.key === 'ArrowDown' ? 'first' : 'last' };
203
+ tick();
204
+ }
205
+ };
206
+ window.addEventListener('blur', away);
207
+ window.addEventListener('resize', resized);
208
+ window.addEventListener('keydown', onKey);
209
+ return () => { clearTimeout(leaving); setOverlay(-1); noteOpen(null); window.removeEventListener('blur', away); window.removeEventListener('resize', resized); window.removeEventListener('keydown', onKey); };
210
+ }, [open, anchor.at]);
211
+ const layer = (level) => layers.current?.querySelector(`[data-level="${level}"]`) ?? null;
212
+ // After every render: submenus sit beside their row, inside the window; then the focus that was asked for.
213
+ useLayoutEffect(() => {
214
+ if (!open)
215
+ return;
216
+ for (let level = 1; level <= path.length; level += 1) {
217
+ const el = layer(level);
218
+ const parent = layer(level - 1);
219
+ const row = parent?.querySelector(`[data-item="${CSS.escape(path[level - 1])}"]`);
220
+ if (!el || !parent)
221
+ continue;
222
+ const edge = 8;
223
+ const box = parent.getBoundingClientRect();
224
+ el.style.maxHeight = `${window.innerHeight - edge * 2}px`;
225
+ const { width, height } = el.getBoundingClientRect();
226
+ const left = submenuLeft(box, width, window.innerWidth, edge);
227
+ // It slides in from the side it hangs on.
228
+ el.style.setProperty('--bt-app-sub-from', left < box.left ? '6px' : '-6px');
229
+ const top = Math.max(edge, Math.min((row?.getBoundingClientRect().top ?? box.top) - 6, window.innerHeight - height - edge));
230
+ el.style.left = `${Math.round(left)}px`;
231
+ el.style.top = `${Math.round(top)}px`;
232
+ }
233
+ const want = focusNext.current;
234
+ const el = want ? layer(want.level) : null;
235
+ if (!want || !el)
236
+ return;
237
+ focusNext.current = null;
238
+ const stops = stopsOf(el);
239
+ const target = want.id ? el.querySelector(`[data-item="${CSS.escape(want.id)}"]:not(:disabled)`)
240
+ : want.edge === 'menu' ? el : want.edge === 'last' ? stops[stops.length - 1] : stops[0];
241
+ (target ?? el).focus();
242
+ });
243
+ const openSub = (level, id, focus = false) => {
244
+ setPath(current => [...current.slice(0, level), id]);
245
+ setAsking(null);
246
+ setError('');
247
+ if (focus)
248
+ focusNext.current = { level: level + 1, edge: 'first' };
249
+ };
250
+ /** Closes the submenu at `level`; its row gets the focus back. */
251
+ const closeSub = (level) => {
252
+ focusNext.current = { level: level - 1, id: path[level - 1] };
253
+ setPath(current => current.slice(0, level - 1));
254
+ setAsking(null);
255
+ setError('');
256
+ };
257
+ async function activate(row, level) {
258
+ if (row.disabled)
259
+ return;
260
+ if (row.submenu) {
261
+ if (path[level] === row.id) {
262
+ focusNext.current = { level: level + 1, edge: 'first' };
263
+ tick();
264
+ }
265
+ else
266
+ openSub(level, row.id, true);
267
+ return;
268
+ }
269
+ setError('');
270
+ if (!row.keepOpen)
271
+ close('action');
272
+ try {
273
+ await row.run?.();
274
+ }
275
+ catch (failure) {
276
+ if (row.keepOpen)
277
+ setError(getError(failure));
278
+ else
279
+ console.error('[shell] menu', failure);
280
+ }
281
+ }
282
+ // -------------------------------------------------------------------------------------------
283
+ // Rows
284
+ const item = (id, label, icon, rest = {}) => ({ kind: 'item', id, label, icon, ...rest });
285
+ /** "Plugins…": a row that opens a section of the app's panel. */
286
+ const section = (name) => menuText('section', { section: name });
287
+ const active = shell.api?.activePanel;
288
+ const activeParams = active?.params;
289
+ const canSplit = !!active && (isWeb(active) || active.group.panels.length > 1);
290
+ const languageName = (code) => menu.languages?.list.find(language => language.code === code)?.name;
291
+ const themeState = config.themes?.current();
292
+ const themeId = config.themes && themeState ? config.themes.adapter.preset(themeState.choice) : '';
293
+ const modeList = menu.modes?.list() ?? [];
294
+ /** Settings → Language: the panel's Settings, scrolled to that group once it is there. */
295
+ function openSettingsAt(anchor) {
296
+ shell.openPanelSection('settings');
297
+ let tries = 0;
298
+ const find = () => {
299
+ const heading = document.getElementById(`${anchor}-h`);
300
+ if (heading)
301
+ heading.scrollIntoView({ block: 'start' });
302
+ else if ((tries += 1) < 40)
303
+ setTimeout(find, 50);
304
+ };
305
+ find();
306
+ }
307
+ function builtin(id) {
308
+ switch (id) {
309
+ case 'new-tab': return item(id, t('wb.shell.tab.new'), 'plus', { shortcut: 'Ctrl+T', run: () => shell.shortcut('new-tab') });
310
+ case 'split-right': return item(id, t('wb.shell.menu.splitRight'), 'split', { shortcut: 'Ctrl+\\', disabled: !canSplit, run: () => shell.shortcut('split-right') });
311
+ case 'split-down': return item(id, t('wb.shell.menu.splitDown'), 'splitDown', { shortcut: 'Ctrl+Shift+\\', disabled: !canSplit, run: () => shell.shortcut('split-down') });
312
+ case 'new-column': return item(id, menuText('newColumn'), 'columns', {
313
+ run: () => {
314
+ // The deck in front, else the first one; with none yet, the deck tab itself (it starts one).
315
+ const target = activeParams?.kind === 'deck' ? activeParams.deckId : decks.list[0]?.id;
316
+ shell.run(target ? { type: 'deck-add', deckId: target } : { type: 'deck' });
317
+ },
318
+ });
319
+ case 'language': return item(id, t('wb.settings.language.title'), 'globe', { submenu: true, hint: languageName(menu.languages?.state().locale) });
320
+ case 'theme': return item(id, menuText('theme'), 'palette', { submenu: true, hint: themeId ? config.themes.themeName(themeId) : undefined });
321
+ case 'mode': {
322
+ const label = modeList.find(entry => entry.id === mode)?.label;
323
+ return item(id, t('wb.modes.section'), 'layers', { submenu: true, hint: label && modeStatus?.custom ? t('wb.modes.custom', { mode: label }) : label });
324
+ }
325
+ case 'zoom': return { kind: 'zoom', id: 'zoom' };
326
+ case 'plugins': return item(id, section(t('wb.panel.section.plugins')), 'plug', { run: () => shell.openPanelSection('plugins') });
327
+ case 'store': return item(id, section(t('wb.panel.section.store')), 'bag', { run: () => shell.openPanelSection('store') });
328
+ case 'strings': return item(id, section(menuText('strings')), 'globe', { run: () => shell.openPanelSection('languages') });
329
+ case 'workspaces': return item(id, t('wb.ws.title'), 'layout', { submenu: true, hint: workspaces.store.items.find(entry => entry.id === workspaces.active)?.name });
330
+ case 'find': return item(id, menuText('find'), 'search', { shortcut: 'Ctrl+F', disabled: !(shell.api?.panels ?? []).some(panel => isWeb(panel) && panel.api.isVisible), run: () => shell.shortcut('find') });
331
+ case 'shortcuts': return item(id, menuText('shortcuts'), 'keyboard', { run: () => (menu.shortcuts ? menu.shortcuts() : shell.shortcut('command-palette')) });
332
+ case 'palette': return item(id, menuText('palette'), 'command', { shortcut: 'Ctrl+K', run: () => shell.shortcut('command-palette') });
333
+ case 'developer': return item(id, menuText('developer'), 'code', { submenu: true });
334
+ case 'updates': {
335
+ // A real check: the row asks the updater now and says what came of it (the titlebar chip stays the loud part).
336
+ const row = updateRow(update, askedUpdate, version);
337
+ return item(id, row.label, 'reload', {
338
+ hint: row.hint, title: row.title, keepOpen: row.action === 'check' || row.action === 'wait',
339
+ run: async () => {
340
+ if (row.action === 'open') {
341
+ shell.openPanelSection('updates');
342
+ return;
343
+ }
344
+ if (row.action === 'restart') {
345
+ await invoke('apply_update');
346
+ return;
347
+ }
348
+ if (row.action !== 'check')
349
+ return;
350
+ setAskedUpdate(true);
351
+ setUpdate({ state: 'checking' });
352
+ // One request, no retry: whatever the updater answers is what the row says.
353
+ try {
354
+ setUpdate(parseUpdateStatus(await invoke('update_check')));
355
+ }
356
+ catch {
357
+ setUpdate({ state: 'error', message: '' });
358
+ }
359
+ },
360
+ });
361
+ }
362
+ // Off: a submenu that says what it does before anything reloads. On: one row that leaves it.
363
+ case 'safe-mode': return safe.active
364
+ ? item(id, menuText('safeLeave'), 'shield', { run: () => setSafeMode(false) })
365
+ : item(id, menuText('safeRestart'), 'shield', { submenu: true });
366
+ case 'report': return item(id, menuText('report'), 'flag', { run: () => setReporting(true) });
367
+ case 'about': return item(id, menuText('about', { product: config.product }), 'info', { run: () => shell.openPanelSection('home') });
368
+ case 'settings': return item(id, section(t('wb.panel.section.settings')), 'settings', { run: () => shell.openPanelSection('settings') });
369
+ }
370
+ }
371
+ function submenuRows(id) {
372
+ switch (id) {
373
+ case 'language': {
374
+ const languages = menu.languages;
375
+ if (!languages)
376
+ return [];
377
+ const rows = languageRows(languages.list, languages.state(), { site: t('wb.settings.language.followSite'), system: t('wb.settings.language.followSystem'), more: menuText('moreLanguages') });
378
+ return rows.map(row => {
379
+ if (row.kind !== 'item')
380
+ return row;
381
+ const choice = languageChoice(row.id);
382
+ // Switching is live and the menu stays: what was picked can be read (or undone) on the spot.
383
+ return choice ? { ...row, keepOpen: true, run: () => languages.set(choice) } : { ...row, run: () => openSettingsAt('language') };
384
+ });
385
+ }
386
+ case 'theme': {
387
+ const themes = config.themes;
388
+ if (!themes || !themeState)
389
+ return [];
390
+ const list = themes.allThemes(themeState.choice).map(theme => item(`theme:${theme.id}`, theme.name, undefined, {
391
+ check: 'radio', checked: theme.id === themeId, keepOpen: true, swatch: themes.adapter.dots(theme),
392
+ // As Appearance does: a theme starts without the customizations made on another one.
393
+ run: () => themes.setChoice(themes.adapter.choiceForId(themeState.choice, theme.id)),
394
+ }));
395
+ return joinGroups([list, [
396
+ item('theme:builder', section(t('wb.panel.section.builder')), 'edit', { run: () => shell.openPanelSection('builder') }),
397
+ item('theme:more', menuText('moreAppearance'), 'palette', { run: () => shell.openPanelSection('themes') }),
398
+ ]]);
399
+ }
400
+ case 'mode': {
401
+ const modes = menu.modes;
402
+ if (!modes)
403
+ return [];
404
+ const name = (modeId) => modeList.find(entry => entry.id === modeId)?.label ?? modeId;
405
+ const apply = async (to, keep) => { await modes.apply(to, keep); setMode(to); close('action'); };
406
+ const at = path.indexOf('mode') + 1;
407
+ if (asking?.reapply && modeStatus) {
408
+ // What applying the mode again turns on and off, said before it happens.
409
+ return [
410
+ { kind: 'note', id: 'mode:reapply-hint', title: t('wb.modes.reapply', { mode: name(asking.to) }), text: t('wb.modes.reapplyHint', { mode: name(asking.to) }) },
411
+ ...(modeStatus.on.length ? [{ kind: 'note', id: 'mode:reapply-on', title: '', text: t('wb.modes.turnsOn', { list: modeStatus.on.join(', ') }) }] : []),
412
+ ...(modeStatus.off.length ? [{ kind: 'note', id: 'mode:reapply-off', title: '', text: t('wb.modes.turnsOff', { list: modeStatus.off.join(', ') }) }] : []),
413
+ item('mode:reapply-yes', t('wb.modes.reapply', { mode: name(asking.to) }), 'reload', { keepOpen: true, run: async () => { await modes.reapply?.(); close('action'); } }),
414
+ item('mode:cancel', t('wb.common.cancel'), 'close', { keepOpen: true, run: () => { focusNext.current = { level: at, id: 'mode:reapply' }; setAsking(null); } }),
415
+ ];
416
+ }
417
+ if (asking) {
418
+ // The question Settings asks: what was changed by hand stays, or the mode is taken as it is.
419
+ return [
420
+ { kind: 'note', id: 'mode:question', title: t('wb.modes.keepQuestion'), text: t('wb.modes.keepHint', { count: asking.changes }) },
421
+ item('mode:keep', t('wb.modes.keep'), 'check', { keepOpen: true, run: () => apply(asking.to, true) }),
422
+ item('mode:reset', t('wb.modes.reset', { mode: name(asking.to) }), 'reload', { keepOpen: true, run: () => apply(asking.to, false) }),
423
+ item('mode:cancel', t('wb.common.cancel'), 'close', { keepOpen: true, run: () => { focusNext.current = { level: at, id: `mode:${asking.to}` }; setAsking(null); } }),
424
+ ];
425
+ }
426
+ const list = modeList.map(entry => item(`mode:${entry.id}`, entry.label, undefined, {
427
+ check: 'radio', checked: entry.id === mode, keepOpen: true,
428
+ run: async () => {
429
+ if (entry.id === mode) {
430
+ close('action');
431
+ return;
432
+ }
433
+ const changes = await modes.changes(entry.id);
434
+ if (changes > 0) {
435
+ focusNext.current = { level: at, edge: 'first' };
436
+ setAsking({ to: entry.id, changes });
437
+ }
438
+ else
439
+ await apply(entry.id, false);
440
+ },
441
+ }));
442
+ if (!mode || !modeStatus?.custom || !modes.reapply)
443
+ return list;
444
+ // The mode is a starting point: the features moved on, and nothing applies it again unasked.
445
+ const grew = modeStatus.added > 0 ? [{ kind: 'note', id: 'mode:grew', title: '', text: t('wb.modes.grew', { mode: name(mode), count: modeStatus.added }) }] : [];
446
+ return joinGroups([list, [
447
+ { kind: 'note', id: 'mode:custom', title: t('wb.modes.custom', { mode: name(mode) }) },
448
+ ...grew,
449
+ item('mode:reapply', t('wb.modes.reapply', { mode: name(mode) }), 'reload', {
450
+ keepOpen: true,
451
+ run: () => {
452
+ focusNext.current = { level: at, edge: 'first' };
453
+ setAsking({ to: mode, changes: 0, reapply: true });
454
+ if (modeStatus.added > 0)
455
+ void modes.seen?.().then(() => setModeStatus({ ...modeStatus, added: 0 }), () => { });
456
+ },
457
+ }),
458
+ ]]);
459
+ }
460
+ case 'workspaces': {
461
+ const list = workspaceList();
462
+ const rows = list.length
463
+ ? list.map(entry => item(`ws:${entry.id}`, entry.name, undefined, { check: 'radio', checked: entry.id === workspaces.active, hint: t('wb.ws.tabs', { count: entry.tabs }), run: () => restoreWorkspace(entry.id) }))
464
+ : [{ kind: 'note', id: 'ws:none', title: '', text: menuText('noWorkspaces') }];
465
+ return joinGroups([rows, [item('ws:save', menuText('saveLayout'), 'plus', { run: openWorkspaceSave })]]);
466
+ }
467
+ case 'safe-mode': return [
468
+ { kind: 'note', id: 'safe:question', title: menuText('safeQuestion'), text: menuText('safeExplain') },
469
+ item('safe:confirm', menuText('safeConfirm'), 'shield', { run: () => setSafeMode(true) }),
470
+ item('safe:cancel', t('wb.common.cancel'), 'close', { keepOpen: true, run: () => closeSub(path.indexOf('safe-mode') + 1) }),
471
+ ];
472
+ case 'developer': return [
473
+ item('dev:mode', t('wb.dev.mode'), undefined, { check: 'checkbox', checked: dev.enabled, keepOpen: true, run: async () => { await invoke('dev_set', { enabled: !dev.enabled }); await refreshDev(); } }),
474
+ item('dev:folder', menuText('pluginsFolder'), 'folder', { run: () => invoke('plugins_open_folder') }),
475
+ ];
476
+ default: return specRows(findSpec(groups, id)?.submenu?.() ?? []);
477
+ }
478
+ }
479
+ const groups = menu.groups ?? DEFAULT_MENU;
480
+ const env = {
481
+ decks: !!config.deck, languages: !!menu.languages, themes: !!config.themes, modes: modeList.length > 0,
482
+ zoom: hasFeature('zoom'), find: hasFeature('find'), safeMode: hasFeature('safeMode'), store: hasFeature('store'), strings: config.features?.strings === true, workspaces: hasFeature('workspaces'), developer: hasFeature('developer'), updates: hasFeature('updates'),
483
+ };
484
+ const rootRows = () => joinGroups(planMenu(groups, env).map(group => group.flatMap(entry => (typeof entry === 'string' ? [builtin(entry)] : specRows([entry])))));
485
+ const labelOf = (id, rows) => rows.find((row) => row.kind === 'item' && row.id === id)?.label ?? '';
486
+ // -------------------------------------------------------------------------------------------
487
+ // Keyboard and pointer
488
+ function onKey(event) {
489
+ const target = event.target;
490
+ const menuEl = target.closest('[data-level]');
491
+ if (!menuEl)
492
+ return;
493
+ const level = Number(menuEl.dataset.level);
494
+ const { key } = event;
495
+ // The keyboard leads now: the row under a resting pointer takes the focus back only when the pointer moves on.
496
+ clearTimeout(hover.current.timer);
497
+ hover.current = { el: null };
498
+ const keys = submenuKeys(getComputedStyle(menuEl).direction === 'rtl');
499
+ const done = () => { event.preventDefault(); event.stopPropagation(); };
500
+ if (key === 'Escape') {
501
+ done();
502
+ if (level > 0)
503
+ closeSub(level);
504
+ else
505
+ close('escape');
506
+ return;
507
+ }
508
+ if (key === 'Tab') {
509
+ done();
510
+ close('escape');
511
+ return;
512
+ }
513
+ // The zoom row is one stop: left and right move through − + and reset (laid out left to right).
514
+ if ('zoom' in target.dataset && (key === 'ArrowLeft' || key === 'ArrowRight')) {
515
+ done();
516
+ const controls = Array.from(menuEl.querySelectorAll('[data-zoom]'));
517
+ controls[Math.max(0, Math.min(controls.length - 1, controls.indexOf(target) + (key === 'ArrowRight' ? 1 : -1)))]?.focus();
518
+ return;
519
+ }
520
+ if (key === 'ArrowDown' || key === 'ArrowUp' || key === 'Home' || key === 'End') {
521
+ done();
522
+ const stops = stopsOf(menuEl);
523
+ stops[moveStop(stops.indexOf(target), key, stops.length)]?.focus();
524
+ return;
525
+ }
526
+ if (key === keys.open) {
527
+ if (target.getAttribute('aria-haspopup') === 'menu' && target.dataset.item) {
528
+ done();
529
+ openSub(level, target.dataset.item, true);
530
+ }
531
+ return;
532
+ }
533
+ if (key === keys.close) {
534
+ if (level > 0) {
535
+ done();
536
+ closeSub(level);
537
+ }
538
+ return;
539
+ }
540
+ const now = Date.now();
541
+ const typing = !!typed.current.text && now - typed.current.at <= 700;
542
+ // Enter, and Space outside a typed word: the row's own click chooses it; on the menu itself nothing is chosen.
543
+ if (key === 'Enter' || (key === ' ' && !typing)) {
544
+ if (target === menuEl)
545
+ done();
546
+ typed.current.text = '';
547
+ return;
548
+ }
549
+ if (key.length !== 1 || event.ctrlKey || event.metaKey || event.altKey)
550
+ return;
551
+ // Type-ahead: the next row whose label starts with what was typed.
552
+ done();
553
+ typed.current = { text: typing ? typed.current.text + key : key, at: now };
554
+ const stops = stopsOf(menuEl);
555
+ const found = typeahead(stops.map(el => el.dataset.label ?? ''), stops.indexOf(target), typed.current.text);
556
+ if (found >= 0)
557
+ stops[found].focus();
558
+ }
559
+ /** The pointer moves the focus, like the arrows do: one highlight. A row with a submenu opens it after a beat. */
560
+ function onHover(row, level, el) {
561
+ if (hover.current.el === el)
562
+ return;
563
+ clearTimeout(hover.current.timer);
564
+ hover.current = { el };
565
+ if (document.activeElement !== el)
566
+ el.focus({ preventScroll: true });
567
+ if (row?.submenu) {
568
+ if (path[level] !== row.id)
569
+ hover.current.timer = setTimeout(() => openSub(level, row.id), 170);
570
+ }
571
+ else if (path.length > level) {
572
+ hover.current.timer = setTimeout(() => { setPath(current => current.slice(0, level)); setAsking(null); }, 280);
573
+ }
574
+ }
575
+ // -------------------------------------------------------------------------------------------
576
+ function renderRow(row, level, index) {
577
+ if (row.kind === 'separator')
578
+ return _jsx("hr", { role: "separator" }, `sep${index}`);
579
+ if (row.kind === 'note') {
580
+ return _jsxs("div", { className: `bt-app-note${row.tone === 'error' ? ' is-error' : ''}`, role: row.tone === 'error' ? 'alert' : 'presentation', children: [row.title && _jsx("strong", { children: row.title }), row.text && _jsx("span", { children: row.text })] }, row.id);
581
+ }
582
+ if (row.kind === 'zoom') {
583
+ const tab = zoomTarget();
584
+ const factor = zoomOf(tab);
585
+ const control = (id, label, icon, direction, off, className = '') => _jsx("button", { type: "button", role: "menuitem", tabIndex: -1, className: className, "data-item": `zoom:${id}`, "data-zoom": "", "data-label": menuText('zoom'), "aria-label": label, title: tab ? label : menuText('zoomNone'), "aria-disabled": off, onPointerMove: event => onHover(null, level, event.currentTarget), onClick: () => { if (!off)
586
+ void stepZoom(direction, tab); }, children: _jsx(Icon, { name: icon }) });
587
+ return _jsxs("div", { className: `bt-app-zoom${tab ? '' : ' is-off'}`, role: "group", "aria-label": menuText('zoom'), title: tab ? undefined : menuText('zoomNone'), children: [_jsx(Icon, { name: "zoom" }), _jsx("span", { className: "bt-menu-label", children: menuText('zoom') }), _jsxs("span", { className: "bt-app-zoom-step", children: [control('out', menuText('zoomOut'), 'minus', -1, !tab || factor <= ZOOM_MIN), _jsx("output", { className: "bt-app-zoom-value", "aria-live": "polite", children: percent(factor) }), control('in', menuText('zoomIn'), 'plus', 1, !tab || factor >= ZOOM_MAX)] }), control('reset', menuText('zoomReset'), 'reload', 0, !tab || factor === 1, 'bt-app-zoom-reset')] }, "zoom");
588
+ }
589
+ const expanded = row.submenu ? path[level] === row.id : undefined;
590
+ return _jsxs("button", { type: "button", tabIndex: -1, disabled: row.disabled, "data-item": row.id, "data-label": row.label, title: row.title, role: row.check === 'radio' ? 'menuitemradio' : row.check ? 'menuitemcheckbox' : 'menuitem', "aria-checked": row.check ? !!row.checked : undefined, "aria-haspopup": row.submenu ? 'menu' : undefined, "aria-expanded": expanded, onPointerMove: event => onHover(row, level, event.currentTarget), onClick: () => void activate(row, level), children: [row.check ? _jsx("span", { className: "bt-app-check", children: row.checked && _jsx(Icon, { name: "check" }) }) : row.icon ? _jsx(Icon, { name: row.icon }) : _jsx("span", { className: "bt-app-check" }), _jsx("span", { className: "bt-menu-label", children: row.lang ? _jsx("bdi", { lang: row.lang, dir: row.dir, children: row.label }) : row.label }), row.swatch && _jsxs("span", { className: "wb-dots", "aria-hidden": "true", style: { background: row.swatch.page }, children: [_jsx("i", { style: { background: row.swatch.bg, boxShadow: `inset 0 0 0 1px ${row.swatch.border}` } }), _jsx("i", { style: { background: row.swatch.text } }), _jsx("i", { style: { background: row.swatch.accent } })] }), row.hint && _jsx("span", { className: "bt-app-hint", children: row.hint }), row.shortcut && _jsx("span", { className: "bt-menu-keys", children: shortcutText(row.shortcut, mac) }), row.submenu && _jsx(Icon, { name: "chevronRight", className: "bt-app-chevron" })] }, row.id);
591
+ }
592
+ function renderMenus() {
593
+ const root = rootRows();
594
+ const levels = [{ rows: root, label: menuText('label') }];
595
+ path.forEach((id, index) => levels.push({ rows: submenuRows(id), label: labelOf(id, levels[index].rows) }));
596
+ // An error belongs to the level it happened on: the deepest one open.
597
+ if (error)
598
+ levels[levels.length - 1].rows = [...levels[levels.length - 1].rows, { kind: 'note', id: 'error', title: '', text: error, tone: 'error' }];
599
+ return levels.map(({ rows, label }, level) => _jsx("div", { role: "menu", "aria-label": label, tabIndex: -1, "data-level": level, className: level === 0 ? `bt-menu bt-app-menu bt-pop${anchor.at === 'logo' ? '' : ' bt-pop--right'}` : 'bt-menu bt-app-menu bt-app-sub', style: level === 0 ? { top: anchor.top, left: anchor.left, right: anchor.right, maxHeight: `calc(100vh - ${anchor.top + 8}px)` } : undefined, children: rows.map((row, index) => renderRow(row, level, index)) }, level === 0 ? 'root' : `${level}:${path[level - 1]}`));
600
+ }
601
+ const label = menuText('label');
602
+ return _jsxs(_Fragment, { children: [trigger && _jsx("button", { ref: button, type: "button", className: "bt-app-button", "aria-haspopup": "menu", "aria-expanded": open && anchor.at === 'button', "aria-label": label, title: `${label} (${APP_MENU_KEYS})`, onClick: event => (open && anchor.at === 'button' ? close('escape') : show({ keyboard: event.detail === 0 })), children: _jsxs("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", children: [_jsx("circle", { cx: "12", cy: "5.75", r: "1.6" }), _jsx("circle", { cx: "12", cy: "12", r: "1.6" }), _jsx("circle", { cx: "12", cy: "18.25", r: "1.6" })] }) }), open && createPortal(_jsx("div", { className: "bt-menu-backdrop", onMouseDown: () => close(), onContextMenu: event => { event.preventDefault(); close(); }, children: _jsx("div", { ref: layers, className: "bt-app-layers", onMouseDown: event => event.stopPropagation(), onContextMenu: event => { event.preventDefault(); event.stopPropagation(); }, onKeyDown: onKey, children: renderMenus() }) }), document.body), reporting && _jsx(ReportDialog, { onClose: () => setReporting(false) })] });
603
+ }
604
+ /**
605
+ * The app's logo at the start of the titlebar: a second trigger of the same menu, hung under the
606
+ * logo. A click opens it; a press that turns into a drag moves the window, as the titlebar around
607
+ * it does; a right-click shows the window's system menu, where a titlebar icon has always had it.
608
+ */
609
+ export function AppMenuLogo() {
610
+ useT();
611
+ const [expanded, setExpanded] = useState(openAt === 'logo');
612
+ const press = useRef(null);
613
+ useEffect(() => {
614
+ const update = () => setExpanded(openAt === 'logo');
615
+ window.addEventListener('bt-app-menu-state', update);
616
+ return () => window.removeEventListener('bt-app-menu-state', update);
617
+ }, []);
618
+ const { product, logo } = site();
619
+ const label = menuText('label');
620
+ return _jsx("button", { type: "button", className: "bt-titlebar-logo", "aria-haspopup": "menu", "aria-expanded": expanded, "aria-label": `${product}: ${label}`, title: `${product} · ${label}`, onPointerDown: event => { if (event.button === 0)
621
+ press.current = { x: event.clientX, y: event.clientY, dragged: false }; }, onPointerMove: event => {
622
+ const start = press.current;
623
+ if (!start || start.dragged || !(event.buttons & 1))
624
+ return;
625
+ // The press became a drag: the window moves, and no menu opens when the button is released.
626
+ if (Math.hypot(event.clientX - start.x, event.clientY - start.y) > 5) {
627
+ start.dragged = true;
628
+ startDrag();
629
+ }
630
+ }, onClick: event => {
631
+ const dragged = press.current?.dragged;
632
+ press.current = null;
633
+ if (!dragged)
634
+ openAppMenu({ anchor: 'logo', toggle: true, keyboard: event.detail === 0 });
635
+ }, onContextMenu: event => {
636
+ event.preventDefault();
637
+ event.stopPropagation();
638
+ const scale = window.devicePixelRatio || 1;
639
+ systemMenu(Math.round(event.screenX * scale), Math.round(event.screenY * scale));
640
+ }, children: _jsx("img", { src: logo, alt: "", draggable: false }) });
641
+ }
642
+ //# sourceMappingURL=AppMenu.js.map