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,73 @@
1
+ import { type ColorRole, type RoleColors } from './themeComponents.ts';
2
+ export declare const DIVIDER_STYLES: readonly ["none", "hairline", "solid", "dashed", "dotted", "double"];
3
+ export declare const CHROME_KINDS: readonly ["none", "titlebar", "masthead", "prompt"];
4
+ export declare const RING_STYLES: readonly ["solid", "dashed", "dotted", "double"];
5
+ export declare const MOTION_CURVES: readonly ["standard", "snappy", "spring", "linear", "steps"];
6
+ export declare const LINK_UNDERLINES: readonly ["always", "hover", "never"];
7
+ export type ThemeDecor = {
8
+ dividers?: {
9
+ style: typeof DIVIDER_STYLES[number];
10
+ color?: ColorRole;
11
+ width?: number;
12
+ };
13
+ /** A drawn frame around the main column: a window title bar, a newspaper masthead, a terminal prompt. `title` is plain text. */
14
+ chrome?: {
15
+ kind: typeof CHROME_KINDS[number];
16
+ title?: string;
17
+ };
18
+ focusRing?: {
19
+ width?: number;
20
+ style?: typeof RING_STYLES[number];
21
+ color?: ColorRole;
22
+ offset?: number;
23
+ };
24
+ selection?: {
25
+ fill: ColorRole;
26
+ text: ColorRole;
27
+ };
28
+ scrollbar?: {
29
+ width?: 'auto' | 'thin';
30
+ thumb?: ColorRole;
31
+ track?: ColorRole;
32
+ style?: 'flat' | 'classic';
33
+ };
34
+ links?: {
35
+ underline: typeof LINK_UNDERLINES[number];
36
+ };
37
+ motion?: {
38
+ duration?: number;
39
+ curve?: typeof MOTION_CURVES[number];
40
+ press?: number;
41
+ };
42
+ };
43
+ /** Text a theme may put into a drawn bar: letters, digits, spaces and a little punctuation; it is written into a CSS string. */
44
+ export declare const chromeTitle: (value: unknown) => string;
45
+ /** The `decor` group from JSON. Null when nothing valid is left. */
46
+ export declare function sanitizeDecor(value: unknown): ThemeDecor | null;
47
+ /** Where a site's decoration goes. Every entry is optional: a site without it draws nothing for that key. */
48
+ export type DecorTargets<Context> = {
49
+ /** Rows whose bottom edge is the divider between items (a site's list cells). */
50
+ divider?: string;
51
+ /** Links inside running text. */
52
+ link?: string;
53
+ /** What takes keyboard focus. */
54
+ focusable?: string;
55
+ /** What moves with `motion` (buttons, links, rows). */
56
+ moving?: string;
57
+ /** What a press shrinks. */
58
+ pressable?: string;
59
+ /** The scrollable roots. */
60
+ scroller?: string;
61
+ /** The site's drawing of each chrome kind. */
62
+ chrome?: Partial<Record<Exclude<typeof CHROME_KINDS[number], 'none'>, (title: string, ctx: Context) => string>>;
63
+ };
64
+ /**
65
+ * CSS for a theme's decoration. A focus ring is always drawn when the theme names one (at least 2px
66
+ * and 3:1 on the page's surfaces: the color is swapped for a visible one otherwise); motion only
67
+ * for people who have not asked for less of it.
68
+ */
69
+ export declare function compileDecor<Context extends {
70
+ colors: RoleColors;
71
+ }>(decor: ThemeDecor, targets: DecorTargets<Context>, ctx: Context): string[];
72
+ /** A theme's text as a CSS string literal (for `content`): the allow-list of `chromeTitle` plus escaping of what could end the string. */
73
+ export declare const cssString: (value: string) => string;
@@ -0,0 +1,131 @@
1
+ // Decoration: what a theme draws between and around the components: divider lines, a title bar or a
2
+ // masthead, the focus ring, selection, scrollbars, link underlines, the feel of motion. Fixed words
3
+ // and clamped numbers, colors by role. Where the lines and bars go is the site's (its decor targets).
4
+ // Pure.
5
+ import { contrastRatio } from "./themeApi.js";
6
+ import { COLOR_ROLES } from "./themeComponents.js";
7
+ export const DIVIDER_STYLES = ['none', 'hairline', 'solid', 'dashed', 'dotted', 'double'];
8
+ export const CHROME_KINDS = ['none', 'titlebar', 'masthead', 'prompt'];
9
+ export const RING_STYLES = ['solid', 'dashed', 'dotted', 'double'];
10
+ export const MOTION_CURVES = ['standard', 'snappy', 'spring', 'linear', 'steps'];
11
+ export const LINK_UNDERLINES = ['always', 'hover', 'never'];
12
+ const obj = (value) => value && typeof value === 'object' && !Array.isArray(value) ? value : {};
13
+ const oneOf = (value, options) => options.includes(value) ? value : undefined;
14
+ const num = (value, min, max) => typeof value === 'number' && Number.isFinite(value) ? Math.min(max, Math.max(min, value)) : undefined;
15
+ const role = (value) => oneOf(value, COLOR_ROLES);
16
+ /** Text a theme may put into a drawn bar: letters, digits, spaces and a little punctuation; it is written into a CSS string. */
17
+ export const chromeTitle = (value) => typeof value === 'string' ? value.replace(/[^\p{L}\p{N} .,:!?&+\-_/#@*~()[\]|>$]/gu, '').replace(/&/g, '+').trim().slice(0, 24) : '';
18
+ /** The `decor` group from JSON. Null when nothing valid is left. */
19
+ export function sanitizeDecor(value) {
20
+ const source = obj(value);
21
+ const out = {};
22
+ const dividers = obj(source.dividers), dividerStyle = oneOf(dividers.style, DIVIDER_STYLES);
23
+ if (dividerStyle) {
24
+ const color = role(dividers.color), width = num(dividers.width, 0, 3);
25
+ out.dividers = { style: dividerStyle, ...(color ? { color } : {}), ...(width !== undefined ? { width: +width.toFixed(1) } : {}) };
26
+ }
27
+ const chrome = obj(source.chrome), kind = oneOf(chrome.kind, CHROME_KINDS);
28
+ if (kind && kind !== 'none') {
29
+ const title = chromeTitle(chrome.title);
30
+ out.chrome = { kind, ...(title ? { title } : {}) };
31
+ }
32
+ const ring = obj(source.focusRing);
33
+ if (Object.keys(ring).length) {
34
+ const width = num(ring.width, 2, 4), style = oneOf(ring.style, RING_STYLES), color = role(ring.color), offset = num(ring.offset, 0, 4);
35
+ const focusRing = { ...(width !== undefined ? { width: Math.round(width) } : {}), ...(style ? { style } : {}), ...(color ? { color } : {}), ...(offset !== undefined ? { offset: Math.round(offset) } : {}) };
36
+ if (Object.keys(focusRing).length)
37
+ out.focusRing = focusRing;
38
+ }
39
+ const selection = obj(source.selection), fill = role(selection.fill), text = role(selection.text);
40
+ if (fill && text)
41
+ out.selection = { fill, text };
42
+ const bar = obj(source.scrollbar);
43
+ if (Object.keys(bar).length) {
44
+ const width = oneOf(bar.width, ['auto', 'thin']), thumb = role(bar.thumb), track = role(bar.track), style = oneOf(bar.style, ['flat', 'classic']);
45
+ const scrollbar = { ...(width ? { width } : {}), ...(thumb ? { thumb } : {}), ...(track ? { track } : {}), ...(style ? { style } : {}) };
46
+ if (Object.keys(scrollbar).length)
47
+ out.scrollbar = scrollbar;
48
+ }
49
+ const underline = oneOf(obj(source.links).underline, LINK_UNDERLINES);
50
+ if (underline)
51
+ out.links = { underline };
52
+ const motion = obj(source.motion);
53
+ if (Object.keys(motion).length) {
54
+ const duration = num(motion.duration, 0, 400), curve = oneOf(motion.curve, MOTION_CURVES), press = num(motion.press, 0.96, 1);
55
+ const value = { ...(duration !== undefined ? { duration: Math.round(duration) } : {}), ...(curve ? { curve } : {}), ...(press !== undefined ? { press: +press.toFixed(3) } : {}) };
56
+ if (Object.keys(value).length)
57
+ out.motion = value;
58
+ }
59
+ return Object.keys(out).length ? out : null;
60
+ }
61
+ const CURVES = {
62
+ standard: 'cubic-bezier(.2,.7,.2,1)', snappy: 'cubic-bezier(.3,1.4,.5,1)', spring: 'cubic-bezier(.2,1.6,.4,1)', linear: 'linear', steps: 'steps(3,end)',
63
+ };
64
+ /** The role among `candidates` that reaches `ratio` on every surface, else the most visible one. */
65
+ function visibleOn(colors, wanted, surfaces, ratio) {
66
+ const worst = (hex) => Math.min(...surfaces.map(surface => contrastRatio(hex, surface)));
67
+ if (worst(colors[wanted]) >= ratio)
68
+ return colors[wanted];
69
+ return ['accent', 'text', 'inverse'].map(name => colors[name]).reduce((best, hex) => worst(hex) > worst(best) ? hex : best, colors[wanted]);
70
+ }
71
+ /**
72
+ * CSS for a theme's decoration. A focus ring is always drawn when the theme names one (at least 2px
73
+ * and 3:1 on the page's surfaces: the color is swapped for a visible one otherwise); motion only
74
+ * for people who have not asked for less of it.
75
+ */
76
+ export function compileDecor(decor, targets, ctx) {
77
+ const out = [];
78
+ const { colors } = ctx;
79
+ const surfaces = [colors.bg, colors.surface, colors.page];
80
+ if (decor.dividers && targets.divider) {
81
+ const { style, color = 'border', width } = decor.dividers;
82
+ const line = style === 'none' ? '0 none' : `${style === 'hairline' ? 1 : width ?? (style === 'double' ? 3 : 1)}px ${style === 'hairline' ? 'solid' : style} ${colors[color]}`;
83
+ out.push(`:root:root :is(${targets.divider}){border-bottom:${line} !important}`);
84
+ }
85
+ if (decor.focusRing && targets.focusable) {
86
+ const { width = 2, style = 'solid', color = 'accent', offset = 2 } = decor.focusRing;
87
+ out.push(`:root:root :is(${targets.focusable}):focus-visible{outline:${Math.max(2, width)}px ${style} ${visibleOn(colors, color, surfaces, 3)} !important;outline-offset:${offset}px !important}`);
88
+ }
89
+ if (decor.selection) {
90
+ const fill = colors[decor.selection.fill];
91
+ const text = contrastRatio(colors[decor.selection.text], fill) >= 4.5 ? colors[decor.selection.text] : (contrastRatio('#ffffff', fill) >= contrastRatio('#000000', fill) ? '#ffffff' : '#000000');
92
+ out.push(`:root:root ::selection{background-color:${fill} !important;color:${text} !important}`);
93
+ }
94
+ if (decor.scrollbar) {
95
+ const { width, thumb = 'border', track, style } = decor.scrollbar;
96
+ const scroller = targets.scroller ?? 'html,body';
97
+ const thumbColor = visibleOn(colors, thumb, [track ? colors[track] : colors.page], 1.5);
98
+ out.push(`:root:root :is(${scroller}){scrollbar-color:${thumbColor} ${track ? colors[track] : 'transparent'} !important${width ? `;scrollbar-width:${width} !important` : ''}}`);
99
+ // The classic look needs the engine's own scrollbar parts; `scrollbar-color` would switch them off where both are set.
100
+ if (style === 'classic') {
101
+ const face = track ? colors[track] : colors.surface;
102
+ out.push(`@supports selector(::-webkit-scrollbar){:root:root :is(${scroller}){scrollbar-color:auto !important;scrollbar-width:auto !important}:root:root ::-webkit-scrollbar{width:16px;height:16px;background:${face}}:root:root ::-webkit-scrollbar-thumb{background:${colors.surface};box-shadow:inset -1px -1px ${colors.text},inset 1px 1px ${colors.bg},inset -2px -2px ${colors.muted},inset 2px 2px ${colors.elevated}}:root:root ::-webkit-scrollbar-corner{background:${face}}}`);
103
+ }
104
+ }
105
+ if (decor.links && targets.link) {
106
+ const { underline } = decor.links;
107
+ out.push(`:root:root :is(${targets.link}){text-decoration:${underline === 'always' ? 'underline' : 'none'} !important;text-underline-offset:2px}`);
108
+ if (underline === 'hover')
109
+ out.push(`:root:root :is(${targets.link}):hover{text-decoration:underline !important}`);
110
+ }
111
+ if (decor.motion && (targets.moving || targets.pressable)) {
112
+ const { duration, curve = 'standard', press } = decor.motion;
113
+ const rules = [];
114
+ if (duration !== undefined && targets.moving) {
115
+ rules.push(`:root:root :is(${targets.moving}){transition:background-color ${duration}ms ${CURVES[curve]},color ${duration}ms ${CURVES[curve]},border-color ${duration}ms ${CURVES[curve]},box-shadow ${duration}ms ${CURVES[curve]},transform ${duration}ms ${CURVES[curve]} !important}`);
116
+ }
117
+ if (press !== undefined && press < 1 && targets.pressable)
118
+ rules.push(`:root:root :is(${targets.pressable}):active{transform:scale(${press}) !important}`);
119
+ if (rules.length)
120
+ out.push(`@media (prefers-reduced-motion:no-preference){${rules.join('')}}`);
121
+ }
122
+ if (decor.chrome) {
123
+ const css = targets.chrome?.[decor.chrome.kind]?.(decor.chrome.title ?? '', ctx);
124
+ if (css)
125
+ out.push(css);
126
+ }
127
+ return out;
128
+ }
129
+ /** A theme's text as a CSS string literal (for `content`): the allow-list of `chromeTitle` plus escaping of what could end the string. */
130
+ export const cssString = (value) => `"${value.replace(/[\\"\n\r\f]/g, match => `\\${match.charCodeAt(0).toString(16)} `)}"`;
131
+ //# sourceMappingURL=themeDecor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"themeDecor.js","sourceRoot":"","sources":["../../../runtime/src/themeDecor.ts"],"names":[],"mappings":"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","sourcesContent":["// Decoration: what a theme draws between and around the components: divider lines, a title bar or a\n// masthead, the focus ring, selection, scrollbars, link underlines, the feel of motion. Fixed words\n// and clamped numbers, colors by role. Where the lines and bars go is the site's (its decor targets).\n// Pure.\n\nimport { contrastRatio } from './themeApi.ts';\nimport { COLOR_ROLES, type ColorRole, type RoleColors } from './themeComponents.ts';\n\nexport const DIVIDER_STYLES = ['none', 'hairline', 'solid', 'dashed', 'dotted', 'double'] as const;\nexport const CHROME_KINDS = ['none', 'titlebar', 'masthead', 'prompt'] as const;\nexport const RING_STYLES = ['solid', 'dashed', 'dotted', 'double'] as const;\nexport const MOTION_CURVES = ['standard', 'snappy', 'spring', 'linear', 'steps'] as const;\nexport const LINK_UNDERLINES = ['always', 'hover', 'never'] as const;\n\nexport type ThemeDecor = {\n dividers?: { style: typeof DIVIDER_STYLES[number]; color?: ColorRole; width?: number };\n /** A drawn frame around the main column: a window title bar, a newspaper masthead, a terminal prompt. `title` is plain text. */\n chrome?: { kind: typeof CHROME_KINDS[number]; title?: string };\n focusRing?: { width?: number; style?: typeof RING_STYLES[number]; color?: ColorRole; offset?: number };\n selection?: { fill: ColorRole; text: ColorRole };\n scrollbar?: { width?: 'auto' | 'thin'; thumb?: ColorRole; track?: ColorRole; style?: 'flat' | 'classic' };\n links?: { underline: typeof LINK_UNDERLINES[number] };\n motion?: { duration?: number; curve?: typeof MOTION_CURVES[number]; press?: number };\n};\n\nconst obj = (value: unknown): Record<string, unknown> => value && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : {};\nconst oneOf = <T extends string>(value: unknown, options: readonly T[]): T | undefined => options.includes(value as T) ? value as T : undefined;\nconst num = (value: unknown, min: number, max: number): number | undefined => typeof value === 'number' && Number.isFinite(value) ? Math.min(max, Math.max(min, value)) : undefined;\nconst role = (value: unknown) => oneOf(value, COLOR_ROLES);\n/** Text a theme may put into a drawn bar: letters, digits, spaces and a little punctuation; it is written into a CSS string. */\nexport const chromeTitle = (value: unknown) => typeof value === 'string' ? value.replace(/[^\\p{L}\\p{N} .,:!?&+\\-_/#@*~()[\\]|>$]/gu, '').replace(/&/g, '+').trim().slice(0, 24) : '';\n\n/** The `decor` group from JSON. Null when nothing valid is left. */\nexport function sanitizeDecor(value: unknown): ThemeDecor | null {\n const source = obj(value);\n const out: ThemeDecor = {};\n const dividers = obj(source.dividers), dividerStyle = oneOf(dividers.style, DIVIDER_STYLES);\n if (dividerStyle) {\n const color = role(dividers.color), width = num(dividers.width, 0, 3);\n out.dividers = { style: dividerStyle, ...(color ? { color } : {}), ...(width !== undefined ? { width: +width.toFixed(1) } : {}) };\n }\n const chrome = obj(source.chrome), kind = oneOf(chrome.kind, CHROME_KINDS);\n if (kind && kind !== 'none') { const title = chromeTitle(chrome.title); out.chrome = { kind, ...(title ? { title } : {}) }; }\n const ring = obj(source.focusRing);\n if (Object.keys(ring).length) {\n const width = num(ring.width, 2, 4), style = oneOf(ring.style, RING_STYLES), color = role(ring.color), offset = num(ring.offset, 0, 4);\n const focusRing = { ...(width !== undefined ? { width: Math.round(width) } : {}), ...(style ? { style } : {}), ...(color ? { color } : {}), ...(offset !== undefined ? { offset: Math.round(offset) } : {}) };\n if (Object.keys(focusRing).length) out.focusRing = focusRing;\n }\n const selection = obj(source.selection), fill = role(selection.fill), text = role(selection.text);\n if (fill && text) out.selection = { fill, text };\n const bar = obj(source.scrollbar);\n if (Object.keys(bar).length) {\n const width = oneOf(bar.width, ['auto', 'thin'] as const), thumb = role(bar.thumb), track = role(bar.track), style = oneOf(bar.style, ['flat', 'classic'] as const);\n const scrollbar = { ...(width ? { width } : {}), ...(thumb ? { thumb } : {}), ...(track ? { track } : {}), ...(style ? { style } : {}) };\n if (Object.keys(scrollbar).length) out.scrollbar = scrollbar;\n }\n const underline = oneOf(obj(source.links).underline, LINK_UNDERLINES);\n if (underline) out.links = { underline };\n const motion = obj(source.motion);\n if (Object.keys(motion).length) {\n const duration = num(motion.duration, 0, 400), curve = oneOf(motion.curve, MOTION_CURVES), press = num(motion.press, 0.96, 1);\n const value = { ...(duration !== undefined ? { duration: Math.round(duration) } : {}), ...(curve ? { curve } : {}), ...(press !== undefined ? { press: +press.toFixed(3) } : {}) };\n if (Object.keys(value).length) out.motion = value;\n }\n return Object.keys(out).length ? out : null;\n}\n\n/** Where a site's decoration goes. Every entry is optional: a site without it draws nothing for that key. */\nexport type DecorTargets<Context> = {\n /** Rows whose bottom edge is the divider between items (a site's list cells). */\n divider?: string;\n /** Links inside running text. */\n link?: string;\n /** What takes keyboard focus. */\n focusable?: string;\n /** What moves with `motion` (buttons, links, rows). */\n moving?: string;\n /** What a press shrinks. */\n pressable?: string;\n /** The scrollable roots. */\n scroller?: string;\n /** The site's drawing of each chrome kind. */\n chrome?: Partial<Record<Exclude<typeof CHROME_KINDS[number], 'none'>, (title: string, ctx: Context) => string>>;\n};\n\nconst CURVES: Record<typeof MOTION_CURVES[number], string> = {\n standard: 'cubic-bezier(.2,.7,.2,1)', snappy: 'cubic-bezier(.3,1.4,.5,1)', spring: 'cubic-bezier(.2,1.6,.4,1)', linear: 'linear', steps: 'steps(3,end)',\n};\n\n/** The role among `candidates` that reaches `ratio` on every surface, else the most visible one. */\nfunction visibleOn(colors: RoleColors, wanted: ColorRole, surfaces: string[], ratio: number): string {\n const worst = (hex: string) => Math.min(...surfaces.map(surface => contrastRatio(hex, surface)));\n if (worst(colors[wanted]) >= ratio) return colors[wanted];\n return (['accent', 'text', 'inverse'] as ColorRole[]).map(name => colors[name]).reduce((best, hex) => worst(hex) > worst(best) ? hex : best, colors[wanted]);\n}\n\n/**\n * CSS for a theme's decoration. A focus ring is always drawn when the theme names one (at least 2px\n * and 3:1 on the page's surfaces: the color is swapped for a visible one otherwise); motion only\n * for people who have not asked for less of it.\n */\nexport function compileDecor<Context extends { colors: RoleColors }>(decor: ThemeDecor, targets: DecorTargets<Context>, ctx: Context): string[] {\n const out: string[] = [];\n const { colors } = ctx;\n const surfaces = [colors.bg, colors.surface, colors.page];\n if (decor.dividers && targets.divider) {\n const { style, color = 'border', width } = decor.dividers;\n const line = style === 'none' ? '0 none' : `${style === 'hairline' ? 1 : width ?? (style === 'double' ? 3 : 1)}px ${style === 'hairline' ? 'solid' : style} ${colors[color]}`;\n out.push(`:root:root :is(${targets.divider}){border-bottom:${line} !important}`);\n }\n if (decor.focusRing && targets.focusable) {\n const { width = 2, style = 'solid', color = 'accent', offset = 2 } = decor.focusRing;\n out.push(`:root:root :is(${targets.focusable}):focus-visible{outline:${Math.max(2, width)}px ${style} ${visibleOn(colors, color, surfaces, 3)} !important;outline-offset:${offset}px !important}`);\n }\n if (decor.selection) {\n const fill = colors[decor.selection.fill];\n const text = contrastRatio(colors[decor.selection.text], fill) >= 4.5 ? colors[decor.selection.text] : (contrastRatio('#ffffff', fill) >= contrastRatio('#000000', fill) ? '#ffffff' : '#000000');\n out.push(`:root:root ::selection{background-color:${fill} !important;color:${text} !important}`);\n }\n if (decor.scrollbar) {\n const { width, thumb = 'border', track, style } = decor.scrollbar;\n const scroller = targets.scroller ?? 'html,body';\n const thumbColor = visibleOn(colors, thumb, [track ? colors[track] : colors.page], 1.5);\n out.push(`:root:root :is(${scroller}){scrollbar-color:${thumbColor} ${track ? colors[track] : 'transparent'} !important${width ? `;scrollbar-width:${width} !important` : ''}}`);\n // The classic look needs the engine's own scrollbar parts; `scrollbar-color` would switch them off where both are set.\n if (style === 'classic') {\n const face = track ? colors[track] : colors.surface;\n out.push(`@supports selector(::-webkit-scrollbar){:root:root :is(${scroller}){scrollbar-color:auto !important;scrollbar-width:auto !important}:root:root ::-webkit-scrollbar{width:16px;height:16px;background:${face}}:root:root ::-webkit-scrollbar-thumb{background:${colors.surface};box-shadow:inset -1px -1px ${colors.text},inset 1px 1px ${colors.bg},inset -2px -2px ${colors.muted},inset 2px 2px ${colors.elevated}}:root:root ::-webkit-scrollbar-corner{background:${face}}}`);\n }\n }\n if (decor.links && targets.link) {\n const { underline } = decor.links;\n out.push(`:root:root :is(${targets.link}){text-decoration:${underline === 'always' ? 'underline' : 'none'} !important;text-underline-offset:2px}`);\n if (underline === 'hover') out.push(`:root:root :is(${targets.link}):hover{text-decoration:underline !important}`);\n }\n if (decor.motion && (targets.moving || targets.pressable)) {\n const { duration, curve = 'standard', press } = decor.motion;\n const rules: string[] = [];\n if (duration !== undefined && targets.moving) {\n rules.push(`:root:root :is(${targets.moving}){transition:background-color ${duration}ms ${CURVES[curve]},color ${duration}ms ${CURVES[curve]},border-color ${duration}ms ${CURVES[curve]},box-shadow ${duration}ms ${CURVES[curve]},transform ${duration}ms ${CURVES[curve]} !important}`);\n }\n if (press !== undefined && press < 1 && targets.pressable) rules.push(`:root:root :is(${targets.pressable}):active{transform:scale(${press}) !important}`);\n if (rules.length) out.push(`@media (prefers-reduced-motion:no-preference){${rules.join('')}}`);\n }\n if (decor.chrome) {\n const css = targets.chrome?.[decor.chrome.kind as Exclude<typeof CHROME_KINDS[number], 'none'>]?.(decor.chrome.title ?? '', ctx);\n if (css) out.push(css);\n }\n return out;\n}\n\n/** A theme's text as a CSS string literal (for `content`): the allow-list of `chromeTitle` plus escaping of what could end the string. */\nexport const cssString = (value: string) => `\"${value.replace(/[\\\\\"\\n\\r\\f]/g, match => `\\\\${match.charCodeAt(0).toString(16)} `)}\"`;\n"]}
@@ -0,0 +1,11 @@
1
+ import { type ThemeSpec } from './themeSpec.ts';
2
+ export type DoctorAdvice = {
3
+ /** `lighter`: a lighter mechanism would do; `performance`, `accessibility`, `contrast`: a cost. */
4
+ kind: 'lighter' | 'performance' | 'accessibility' | 'contrast';
5
+ /** Stable id, for tests and translations (`wb.doctor.<id>`). */
6
+ id: string;
7
+ /** English text (the panel translates by id when it has the words). */
8
+ text: string;
9
+ };
10
+ /** Advice for a theme document. Empty when there is nothing to say. */
11
+ export declare function themeDoctor(theme: ThemeSpec): DoctorAdvice[];
@@ -0,0 +1,51 @@
1
+ // The theme doctor: advice, never a block. A theme may do anything its trust level allows; the doctor
2
+ // points at the lighter mechanism for what the theme does (a token before a component setting, a
3
+ // component setting before CSS, CSS before a script) and at performance, accessibility and contrast
4
+ // costs. Used by the import screen, the Theme Builder's report and `waybetter store check`. Pure.
5
+ import { contrastRatio } from "./themeApi.js";
6
+ import { ensureContrast } from "./themeSpec.js";
7
+ /** What a theme's free-form CSS does that a v2 group does without CSS. */
8
+ const CSS_RULES = [
9
+ { id: 'css-radius', kind: 'lighter', test: /border-radius\s*:/i, text: 'Corner radii: components.<part>.radius (or shape.radius) sets them without CSS and keeps working when the site renames its classes.' },
10
+ { id: 'css-bevel', kind: 'lighter', test: /box-shadow\s*:[^;{}]*inset[^;{}]*inset[^;{}]*inset/i, text: 'Bevelled edges: components.<part>.borderStyle "bevel-out" / "bevel-in" draws them from the theme\'s colors.' },
11
+ { id: 'css-hide', kind: 'lighter', test: /display\s*:\s*none/i, text: 'Hiding a part: components.<part>.visible (avatars, counts, names) or a layout variant (sidebar: hidden) does it, and the owner can switch it back.' },
12
+ { id: 'css-color', kind: 'lighter', test: /(?:^|[;{\s])(?:color|background(?:-color)?)\s*:\s*#[0-9a-f]{3,8}/i, text: 'Literal colors: name a role (text, muted, accent, surface…) in colors or in a component, so the contrast pass covers it.' },
13
+ { id: 'css-font', kind: 'lighter', test: /font-family\s*:/i, text: 'Fonts: font.roles sets the post, heading, numbers and mono faces without CSS.' },
14
+ { id: 'css-has', kind: 'performance', test: /:has\(/i, text: ':has() is matched again on every change of the page; keep it off rules that repeat down a timeline.' },
15
+ { id: 'css-universal', kind: 'performance', test: /(?:^|[\s,>+~])\*\s*(?:[,{>+~:\[]|$)/m, text: 'A universal selector (*) is matched against every element; anchor the rule on a part.' },
16
+ { id: 'css-blur', kind: 'performance', test: /backdrop-filter\s*:/i, text: 'Blur (backdrop-filter) is costly on parts that repeat; the glass fill of bars and panels is the cheaper place for it.' },
17
+ { id: 'css-outline-none', kind: 'accessibility', test: /outline\s*:\s*(?:none|0)\b/i, text: 'Removing the outline hides where keyboard focus is; decor.focusRing draws a visible one instead.' },
18
+ { id: 'css-motion', kind: 'accessibility', test: /(?:animation|transition)\s*:/i, text: 'Motion should stay inside @media (prefers-reduced-motion: no-preference); decor.motion does that for you.' },
19
+ ];
20
+ /** Advice for a theme document. Empty when there is nothing to say. */
21
+ export function themeDoctor(theme) {
22
+ const out = [];
23
+ const css = theme.css ?? '';
24
+ if (css.trim()) {
25
+ for (const rule of CSS_RULES)
26
+ if (rule.test.test(css))
27
+ out.push({ kind: rule.kind, id: rule.id, text: rule.text });
28
+ if (css.length > 20_000)
29
+ out.push({ kind: 'performance', id: 'css-size', text: 'More than 20,000 characters of CSS: the site recalculates styles with every rule; tokens and component settings compile to fewer rules.' });
30
+ }
31
+ if (theme.colors) {
32
+ const fixed = ensureContrast(theme.colors);
33
+ for (const role of ['text', 'muted', 'accent']) {
34
+ if (fixed[role] !== theme.colors[role])
35
+ out.push({ kind: 'contrast', id: `contrast-${role}`, text: `The ${role} color was adjusted to stay readable (${contrastRatio(theme.colors[role], theme.colors.bg).toFixed(2)}:1 on the background).` });
36
+ }
37
+ }
38
+ if (theme.components) {
39
+ const posts = theme.components.post;
40
+ if (posts?.fill === 'glass')
41
+ out.push({ kind: 'performance', id: 'glass-post', text: 'Glass on posts is not drawn: blur on every post of a timeline is too costly.' });
42
+ const text = theme.components.postText?.fontSize;
43
+ if (text !== undefined && text < 14)
44
+ out.push({ kind: 'accessibility', id: 'small-post-text', text: 'Post text under 14px is hard to read for many people.' });
45
+ }
46
+ if (theme.variants?.nav === 'top' || theme.variants?.nav === 'bottom') {
47
+ out.push({ kind: 'accessibility', id: 'nav-moved', text: 'Moving the navigation changes where people look for it; it only applies on wide panes, and the owner can turn layout changes off.' });
48
+ }
49
+ return out;
50
+ }
51
+ //# sourceMappingURL=themeDoctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"themeDoctor.js","sourceRoot":"","sources":["../../../runtime/src/themeDoctor.ts"],"names":[],"mappings":"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","sourcesContent":["// The theme doctor: advice, never a block. A theme may do anything its trust level allows; the doctor\n// points at the lighter mechanism for what the theme does (a token before a component setting, a\n// component setting before CSS, CSS before a script) and at performance, accessibility and contrast\n// costs. Used by the import screen, the Theme Builder's report and `waybetter store check`. Pure.\n\nimport { contrastRatio } from './themeApi.ts';\nimport { ensureContrast, type ThemeSpec } from './themeSpec.ts';\n\nexport type DoctorAdvice = {\n /** `lighter`: a lighter mechanism would do; `performance`, `accessibility`, `contrast`: a cost. */\n kind: 'lighter' | 'performance' | 'accessibility' | 'contrast';\n /** Stable id, for tests and translations (`wb.doctor.<id>`). */\n id: string;\n /** English text (the panel translates by id when it has the words). */\n text: string;\n};\n\ntype Rule = { id: string; kind: DoctorAdvice['kind']; test: RegExp; text: string };\n/** What a theme's free-form CSS does that a v2 group does without CSS. */\nconst CSS_RULES: Rule[] = [\n { id: 'css-radius', kind: 'lighter', test: /border-radius\\s*:/i, text: 'Corner radii: components.<part>.radius (or shape.radius) sets them without CSS and keeps working when the site renames its classes.' },\n { id: 'css-bevel', kind: 'lighter', test: /box-shadow\\s*:[^;{}]*inset[^;{}]*inset[^;{}]*inset/i, text: 'Bevelled edges: components.<part>.borderStyle \"bevel-out\" / \"bevel-in\" draws them from the theme\\'s colors.' },\n { id: 'css-hide', kind: 'lighter', test: /display\\s*:\\s*none/i, text: 'Hiding a part: components.<part>.visible (avatars, counts, names) or a layout variant (sidebar: hidden) does it, and the owner can switch it back.' },\n { id: 'css-color', kind: 'lighter', test: /(?:^|[;{\\s])(?:color|background(?:-color)?)\\s*:\\s*#[0-9a-f]{3,8}/i, text: 'Literal colors: name a role (text, muted, accent, surface…) in colors or in a component, so the contrast pass covers it.' },\n { id: 'css-font', kind: 'lighter', test: /font-family\\s*:/i, text: 'Fonts: font.roles sets the post, heading, numbers and mono faces without CSS.' },\n { id: 'css-has', kind: 'performance', test: /:has\\(/i, text: ':has() is matched again on every change of the page; keep it off rules that repeat down a timeline.' },\n { id: 'css-universal', kind: 'performance', test: /(?:^|[\\s,>+~])\\*\\s*(?:[,{>+~:\\[]|$)/m, text: 'A universal selector (*) is matched against every element; anchor the rule on a part.' },\n { id: 'css-blur', kind: 'performance', test: /backdrop-filter\\s*:/i, text: 'Blur (backdrop-filter) is costly on parts that repeat; the glass fill of bars and panels is the cheaper place for it.' },\n { id: 'css-outline-none', kind: 'accessibility', test: /outline\\s*:\\s*(?:none|0)\\b/i, text: 'Removing the outline hides where keyboard focus is; decor.focusRing draws a visible one instead.' },\n { id: 'css-motion', kind: 'accessibility', test: /(?:animation|transition)\\s*:/i, text: 'Motion should stay inside @media (prefers-reduced-motion: no-preference); decor.motion does that for you.' },\n];\n\n/** Advice for a theme document. Empty when there is nothing to say. */\nexport function themeDoctor(theme: ThemeSpec): DoctorAdvice[] {\n const out: DoctorAdvice[] = [];\n const css = theme.css ?? '';\n if (css.trim()) {\n for (const rule of CSS_RULES) if (rule.test.test(css)) out.push({ kind: rule.kind, id: rule.id, text: rule.text });\n if (css.length > 20_000) out.push({ kind: 'performance', id: 'css-size', text: 'More than 20,000 characters of CSS: the site recalculates styles with every rule; tokens and component settings compile to fewer rules.' });\n }\n if (theme.colors) {\n const fixed = ensureContrast(theme.colors);\n for (const role of ['text', 'muted', 'accent'] as const) {\n if (fixed[role] !== theme.colors[role]) out.push({ kind: 'contrast', id: `contrast-${role}`, text: `The ${role} color was adjusted to stay readable (${contrastRatio(theme.colors[role], theme.colors.bg).toFixed(2)}:1 on the background).` });\n }\n }\n if (theme.components) {\n const posts = theme.components.post;\n if (posts?.fill === 'glass') out.push({ kind: 'performance', id: 'glass-post', text: 'Glass on posts is not drawn: blur on every post of a timeline is too costly.' });\n const text = theme.components.postText?.fontSize;\n if (text !== undefined && text < 14) out.push({ kind: 'accessibility', id: 'small-post-text', text: 'Post text under 14px is hard to read for many people.' });\n }\n if (theme.variants?.nav === 'top' || theme.variants?.nav === 'bottom') {\n out.push({ kind: 'accessibility', id: 'nav-moved', text: 'Moving the navigation changes where people look for it; it only applies on wide panes, and the owner can turn layout changes off.' });\n }\n return out;\n}\n"]}
@@ -0,0 +1,130 @@
1
+ import { type ColorRole, type RoleColors } from './themeComponents.ts';
2
+ /** Semantic names a pack may draw. `.active` is a selected navigation item, `.on` an action that is set. */
3
+ export declare const ICON_NAMES: readonly ["home", "home.active", "explore", "explore.active", "notifications", "notifications.active", "messages", "messages.active", "grok", "bookmarks", "bookmarks.active", "lists", "communities", "premium", "profile", "profile.active", "more", "compose", "reply", "repost", "repost.on", "like", "like.on", "views", "bookmark", "bookmark.on", "share", "verified", "logo", "caret", "back", "close", "search", "settings", "media", "gif", "poll", "emoji", "schedule", "location", "pinned", "repostContext", "lock"];
4
+ export type IconName = typeof ICON_NAMES[number];
5
+ export declare const ICON_GROUPS: readonly ["nav", "actions", "composer", "misc"];
6
+ export type IconGroup = typeof ICON_GROUPS[number];
7
+ /** Limits of a pack (the JSON Schema and the Store check say the same). */
8
+ export declare const ICON_LIMITS: {
9
+ readonly names: 64;
10
+ readonly pathChars: 4000;
11
+ readonly layers: 6;
12
+ readonly pngChars: 6000;
13
+ readonly packBytes: 120000;
14
+ readonly labelChars: 12;
15
+ readonly overrides: 8;
16
+ };
17
+ /** Path data only: commands, numbers, separators. */
18
+ export declare const PATH_GRAMMAR: RegExp;
19
+ export type IconFill = ColorRole | string | {
20
+ from: string;
21
+ to: string;
22
+ };
23
+ export type IconGlyph = {
24
+ d: string;
25
+ rule?: 'evenodd';
26
+ stroke?: boolean;
27
+ } | {
28
+ layers: Array<{
29
+ d: string;
30
+ fill: IconFill;
31
+ opacity?: number;
32
+ rule?: 'evenodd';
33
+ }>;
34
+ } | {
35
+ png: string;
36
+ pixel?: boolean;
37
+ };
38
+ export type IconStyle = {
39
+ stroke: number;
40
+ cap: 'round' | 'square' | 'butt';
41
+ join: 'round' | 'miter' | 'bevel';
42
+ scale: number;
43
+ };
44
+ export declare const BASE_ICON_STYLE: IconStyle;
45
+ export declare const ICON_LABEL_NAMES: readonly ["reply", "repost", "like", "views", "bookmark", "share"];
46
+ export type IconLabels = Partial<Record<typeof ICON_LABEL_NAMES[number], string>>;
47
+ export type IconSymbols = {
48
+ like?: 'heart' | 'star' | 'custom';
49
+ separator?: 'dot' | 'bullet' | 'slash' | 'dash' | 'pipe' | 'none';
50
+ };
51
+ export type IconPack = {
52
+ id: string;
53
+ name: string;
54
+ description: string;
55
+ author: string;
56
+ /** SPDX id, or `own` for the author's own drawings, or a plain name for artwork under other terms. */
57
+ license: string;
58
+ /** Where the drawings come from (a project name or URL as text) and whom to credit. */
59
+ source: string;
60
+ credits: string;
61
+ version: 1;
62
+ style: IconStyle;
63
+ glyphs: Partial<Record<IconName, IconGlyph>>;
64
+ symbols?: IconSymbols;
65
+ labels?: IconLabels;
66
+ };
67
+ /** What a theme says about icons: a pack by id, plus small adjustments. Never a whole pack. */
68
+ export type ThemeIcons = {
69
+ pack?: string;
70
+ style?: Partial<IconStyle>;
71
+ overrides?: Partial<Record<IconName, IconGlyph>>;
72
+ symbols?: IconSymbols;
73
+ labels?: IconLabels;
74
+ };
75
+ /** One glyph from JSON, or null when it is not valid path data, layers or a small PNG. */
76
+ export declare function sanitizeGlyph(value: unknown): IconGlyph | null;
77
+ export declare const sanitizeIconStyle: (value: unknown, base?: IconStyle) => IconStyle;
78
+ /** Any JSON to a valid pack, or null when it has no id, no name or no valid glyph. */
79
+ export declare function sanitizeIconPack(input: unknown): IconPack | null;
80
+ /** Parses an imported `*.icons.json`; errors are human-readable. */
81
+ export declare function parseIconPackJson(json: string): {
82
+ pack: IconPack;
83
+ warnings: string[];
84
+ } | {
85
+ error: string;
86
+ };
87
+ /** The `icons` group of a theme from JSON. Null when it says nothing valid. */
88
+ export declare function sanitizeThemeIcons(value: unknown): ThemeIcons | null;
89
+ /** `theme`: follow the theme's suggestion; `site`: the site's own icons; otherwise a pack id. */
90
+ export type IconChoice = 'theme' | 'site' | string;
91
+ export declare const normalizeIconChoice: (value: unknown) => IconChoice;
92
+ export type IconCatalog = {
93
+ packs: readonly IconPack[];
94
+ get(id: string | undefined): IconPack | null;
95
+ /** The pack that is drawn: the owner's pick, else the theme's suggestion; null for the site's own icons or an unknown pack. */
96
+ resolve(choice: IconChoice, theme: ThemeIcons | null | undefined): IconPack | null;
97
+ };
98
+ export declare function createIconCatalog(builtins: readonly IconPack[], installed?: readonly IconPack[]): IconCatalog;
99
+ /** The SVG document of a glyph, built from validated data. `colors` resolves role fills of layers; a single path is black (it is used as a mask). */
100
+ export declare function glyphSvg(glyph: IconGlyph, style: IconStyle, colors?: RoleColors | null): string | null;
101
+ /** True for glyphs that carry their own colors (drawn as an image, not as a mask of the current color). */
102
+ export declare const isColored: (glyph: IconGlyph) => boolean;
103
+ /** How a site finds one of its icons: the container that holds it (stable hooks), else the start of its path data. */
104
+ export type IconMatcher = {
105
+ /** Selector of the icon's `<svg>` by its container (`[data-testid="like"] svg`). */
106
+ ctx?: string;
107
+ /** Prefixes of the site's own path data for this icon, for icons without a container hook. */
108
+ sig?: readonly string[];
109
+ group: IconGroup;
110
+ /** Needed for its group to be drawn at all (a rail never shows half ours, half the site's). */
111
+ core?: boolean;
112
+ };
113
+ export type IconTable = Partial<Record<IconName, IconMatcher>>;
114
+ /** Selectors of the `<svg>` boxes of one icon. */
115
+ export declare function iconSelectors(matcher: IconMatcher): string[];
116
+ export type IconContext = {
117
+ colors: RoleColors | null;
118
+ /** Attribute on `<html>` that lists the groups that are on (`data-wb-icons="nav actions"`); absent: every group draws. */
119
+ gate?: string;
120
+ /** The owner lets themes and packs change icons (default: yes). */
121
+ allowed?: boolean;
122
+ };
123
+ /**
124
+ * CSS that draws `pack` over a site's icons. One rule per glyph the pack has and the site's table
125
+ * knows, inside guards: forced colors remove backgrounds (a masked icon would vanish) and an engine
126
+ * without masks would paint solid squares.
127
+ */
128
+ export declare function compileIcons(pack: IconPack | null, theme: ThemeIcons | null | undefined, table: IconTable, ctx: IconContext): string;
129
+ /** The groups of `table` whose core icons are all on the page (`has(selector)` says whether one matches). Empty table entries count as present. */
130
+ export declare function iconGroupsPresent(table: IconTable, has: (selector: string) => boolean): IconGroup[];