winui-svelte 0.0.5 → 0.0.7

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 (1147) hide show
  1. package/API.md +1941 -23
  2. package/README.md +31 -4
  3. package/dist/app/activation/alarm-argument.d.ts +28 -0
  4. package/dist/app/activation/alarm-argument.d.ts.map +1 -0
  5. package/dist/app/activation/alarm-argument.js +44 -0
  6. package/dist/app/activation/alarm-argument.js.map +1 -0
  7. package/dist/app/activation/classify.d.ts +25 -8
  8. package/dist/app/activation/classify.d.ts.map +1 -1
  9. package/dist/app/activation/classify.js +34 -5
  10. package/dist/app/activation/classify.js.map +1 -1
  11. package/dist/app/activation/index.d.ts +1 -1
  12. package/dist/app/activation/index.d.ts.map +1 -1
  13. package/dist/app/activation/jump-list-argument.d.ts +20 -0
  14. package/dist/app/activation/jump-list-argument.d.ts.map +1 -0
  15. package/dist/app/activation/jump-list-argument.js +28 -0
  16. package/dist/app/activation/jump-list-argument.js.map +1 -0
  17. package/dist/app/activation/kinds.d.ts +16 -1
  18. package/dist/app/activation/kinds.d.ts.map +1 -1
  19. package/dist/app/activation/kinds.js +3 -1
  20. package/dist/app/activation/kinds.js.map +1 -1
  21. package/dist/app/activation/receive.d.ts +3 -1
  22. package/dist/app/activation/receive.d.ts.map +1 -1
  23. package/dist/app/activation/receive.js +13 -1
  24. package/dist/app/activation/receive.js.map +1 -1
  25. package/dist/app/activation/registration.d.ts +14 -0
  26. package/dist/app/activation/registration.d.ts.map +1 -1
  27. package/dist/app/activation/registration.js +11 -3
  28. package/dist/app/activation/registration.js.map +1 -1
  29. package/dist/app/activation/scheme.d.ts +7 -0
  30. package/dist/app/activation/scheme.d.ts.map +1 -1
  31. package/dist/app/activation/scheme.js +10 -1
  32. package/dist/app/activation/scheme.js.map +1 -1
  33. package/dist/app/index.d.ts +2 -0
  34. package/dist/app/index.d.ts.map +1 -1
  35. package/dist/app/index.js +1 -0
  36. package/dist/app/index.js.map +1 -1
  37. package/dist/app/instance-pipe.d.ts.map +1 -1
  38. package/dist/app/instance-pipe.js +1 -2
  39. package/dist/app/instance-pipe.js.map +1 -1
  40. package/dist/app/jump-list/index.d.ts +62 -0
  41. package/dist/app/jump-list/index.d.ts.map +1 -0
  42. package/dist/app/jump-list/index.js +51 -0
  43. package/dist/app/jump-list/index.js.map +1 -0
  44. package/dist/app/jump-list/native.d.ts +9 -0
  45. package/dist/app/jump-list/native.d.ts.map +1 -0
  46. package/dist/app/jump-list/native.js +284 -0
  47. package/dist/app/jump-list/native.js.map +1 -0
  48. package/dist/app/jump-list/tasks.d.ts +86 -0
  49. package/dist/app/jump-list/tasks.d.ts.map +1 -0
  50. package/dist/app/jump-list/tasks.js +89 -0
  51. package/dist/app/jump-list/tasks.js.map +1 -0
  52. package/dist/app/launch-command.d.ts +11 -6
  53. package/dist/app/launch-command.d.ts.map +1 -1
  54. package/dist/app/launch-command.js +16 -5
  55. package/dist/app/launch-command.js.map +1 -1
  56. package/dist/app/schedule/alarm.d.ts +10 -0
  57. package/dist/app/schedule/alarm.d.ts.map +1 -0
  58. package/dist/app/schedule/alarm.js +2 -0
  59. package/dist/app/schedule/alarm.js.map +1 -0
  60. package/dist/app/schedule/alarms.d.ts +78 -0
  61. package/dist/app/schedule/alarms.d.ts.map +1 -0
  62. package/dist/app/schedule/alarms.js +192 -0
  63. package/dist/app/schedule/alarms.js.map +1 -0
  64. package/dist/app/schedule/backend.d.ts +19 -0
  65. package/dist/app/schedule/backend.d.ts.map +1 -0
  66. package/dist/app/schedule/backend.js +3 -0
  67. package/dist/app/schedule/backend.js.map +1 -0
  68. package/dist/app/schedule/events.d.ts +30 -0
  69. package/dist/app/schedule/events.d.ts.map +1 -0
  70. package/dist/app/schedule/events.js +45 -0
  71. package/dist/app/schedule/events.js.map +1 -0
  72. package/dist/app/schedule/index.d.ts +7 -0
  73. package/dist/app/schedule/index.d.ts.map +1 -0
  74. package/dist/app/schedule/index.js +3 -0
  75. package/dist/app/schedule/index.js.map +1 -0
  76. package/dist/app/schedule/native.d.ts +19 -0
  77. package/dist/app/schedule/native.d.ts.map +1 -0
  78. package/dist/app/schedule/native.js +74 -0
  79. package/dist/app/schedule/native.js.map +1 -0
  80. package/dist/app/schedule/occurrence.d.ts +27 -0
  81. package/dist/app/schedule/occurrence.d.ts.map +1 -0
  82. package/dist/app/schedule/occurrence.js +34 -0
  83. package/dist/app/schedule/occurrence.js.map +1 -0
  84. package/dist/app/schedule/xml.d.ts +29 -0
  85. package/dist/app/schedule/xml.d.ts.map +1 -0
  86. package/dist/app/schedule/xml.js +93 -0
  87. package/dist/app/schedule/xml.js.map +1 -0
  88. package/dist/app/shell/app-paths.d.ts +46 -0
  89. package/dist/app/shell/app-paths.d.ts.map +1 -0
  90. package/dist/app/shell/app-paths.js +117 -0
  91. package/dist/app/shell/app-paths.js.map +1 -0
  92. package/dist/app/shell/backend.d.ts +26 -0
  93. package/dist/app/shell/backend.d.ts.map +1 -0
  94. package/dist/app/shell/backend.js +2 -0
  95. package/dist/app/shell/backend.js.map +1 -0
  96. package/dist/app/shell/index.d.ts +12 -0
  97. package/dist/app/shell/index.d.ts.map +1 -0
  98. package/dist/app/shell/index.js +6 -0
  99. package/dist/app/shell/index.js.map +1 -0
  100. package/dist/app/shell/kinds.d.ts +49 -0
  101. package/dist/app/shell/kinds.d.ts.map +1 -0
  102. package/dist/app/shell/kinds.js +37 -0
  103. package/dist/app/shell/kinds.js.map +1 -0
  104. package/dist/app/shell/native.d.ts +9 -0
  105. package/dist/app/shell/native.d.ts.map +1 -0
  106. package/dist/app/shell/native.js +280 -0
  107. package/dist/app/shell/native.js.map +1 -0
  108. package/dist/app/shell/open-with.d.ts +31 -0
  109. package/dist/app/shell/open-with.d.ts.map +1 -0
  110. package/dist/app/shell/open-with.js +45 -0
  111. package/dist/app/shell/open-with.js.map +1 -0
  112. package/dist/app/shell/paths.d.ts +17 -0
  113. package/dist/app/shell/paths.d.ts.map +1 -0
  114. package/dist/app/shell/paths.js +27 -0
  115. package/dist/app/shell/paths.js.map +1 -0
  116. package/dist/app/shell/shortcut.d.ts +77 -0
  117. package/dist/app/shell/shortcut.d.ts.map +1 -0
  118. package/dist/app/shell/shortcut.js +104 -0
  119. package/dist/app/shell/shortcut.js.map +1 -0
  120. package/dist/app/shell/trash.d.ts +20 -0
  121. package/dist/app/shell/trash.d.ts.map +1 -0
  122. package/dist/app/shell/trash.js +40 -0
  123. package/dist/app/shell/trash.js.map +1 -0
  124. package/dist/app/tray-instance.d.ts +39 -0
  125. package/dist/app/tray-instance.d.ts.map +1 -0
  126. package/dist/app/tray-instance.js +65 -0
  127. package/dist/app/tray-instance.js.map +1 -0
  128. package/dist/automation/backend.d.ts +51 -0
  129. package/dist/automation/backend.d.ts.map +1 -0
  130. package/dist/automation/backend.js +5 -0
  131. package/dist/automation/backend.js.map +1 -0
  132. package/dist/automation/client.d.ts +97 -0
  133. package/dist/automation/client.d.ts.map +1 -0
  134. package/dist/automation/client.js +203 -0
  135. package/dist/automation/client.js.map +1 -0
  136. package/dist/automation/ids.d.ts +90 -0
  137. package/dist/automation/ids.d.ts.map +1 -0
  138. package/dist/automation/ids.js +84 -0
  139. package/dist/automation/ids.js.map +1 -0
  140. package/dist/automation/index.d.ts +13 -0
  141. package/dist/automation/index.d.ts.map +1 -0
  142. package/dist/automation/index.js +8 -0
  143. package/dist/automation/index.js.map +1 -0
  144. package/dist/automation/native.d.ts +11 -0
  145. package/dist/automation/native.d.ts.map +1 -0
  146. package/dist/automation/native.js +595 -0
  147. package/dist/automation/native.js.map +1 -0
  148. package/dist/automation/text.d.ts +50 -0
  149. package/dist/automation/text.d.ts.map +1 -0
  150. package/dist/automation/text.js +110 -0
  151. package/dist/automation/text.js.map +1 -0
  152. package/dist/automation/with-client.d.ts +13 -0
  153. package/dist/automation/with-client.d.ts.map +1 -0
  154. package/dist/automation/with-client.js +19 -0
  155. package/dist/automation/with-client.js.map +1 -0
  156. package/dist/automation/worker-job.d.ts +32 -0
  157. package/dist/automation/worker-job.d.ts.map +1 -0
  158. package/dist/automation/worker-job.js +69 -0
  159. package/dist/automation/worker-job.js.map +1 -0
  160. package/dist/automation/worker.d.ts +44 -0
  161. package/dist/automation/worker.d.ts.map +1 -0
  162. package/dist/automation/worker.js +70 -0
  163. package/dist/automation/worker.js.map +1 -0
  164. package/dist/bindings/.dynwinrt-managed +1 -1
  165. package/dist/chrome/action/action-types.d.ts +48 -0
  166. package/dist/chrome/action/action-types.d.ts.map +1 -0
  167. package/dist/chrome/action/action-types.js +86 -0
  168. package/dist/chrome/action/action-types.js.map +1 -0
  169. package/dist/chrome/action/chrome-action.d.ts +117 -0
  170. package/dist/chrome/action/chrome-action.d.ts.map +1 -0
  171. package/dist/chrome/action/chrome-action.js +181 -0
  172. package/dist/chrome/action/chrome-action.js.map +1 -0
  173. package/dist/chrome/action/create-chrome-action.d.ts +23 -0
  174. package/dist/chrome/action/create-chrome-action.d.ts.map +1 -0
  175. package/dist/chrome/action/create-chrome-action.js +24 -0
  176. package/dist/chrome/action/create-chrome-action.js.map +1 -0
  177. package/dist/chrome/action/index.d.ts +7 -0
  178. package/dist/chrome/action/index.d.ts.map +1 -0
  179. package/dist/chrome/action/index.js +4 -0
  180. package/dist/chrome/action/index.js.map +1 -0
  181. package/dist/chrome/commands/chrome-commands.d.ts +62 -0
  182. package/dist/chrome/commands/chrome-commands.d.ts.map +1 -0
  183. package/dist/chrome/commands/chrome-commands.js +133 -0
  184. package/dist/chrome/commands/chrome-commands.js.map +1 -0
  185. package/dist/chrome/commands/command-types.d.ts +45 -0
  186. package/dist/chrome/commands/command-types.d.ts.map +1 -0
  187. package/dist/chrome/commands/command-types.js +27 -0
  188. package/dist/chrome/commands/command-types.js.map +1 -0
  189. package/dist/chrome/commands/index.d.ts +7 -0
  190. package/dist/chrome/commands/index.d.ts.map +1 -0
  191. package/dist/chrome/commands/index.js +4 -0
  192. package/dist/chrome/commands/index.js.map +1 -0
  193. package/dist/chrome/commands/shortcut.d.ts +24 -0
  194. package/dist/chrome/commands/shortcut.d.ts.map +1 -0
  195. package/dist/chrome/commands/shortcut.js +86 -0
  196. package/dist/chrome/commands/shortcut.js.map +1 -0
  197. package/dist/chrome/context-menus/build-menu.d.ts +26 -0
  198. package/dist/chrome/context-menus/build-menu.d.ts.map +1 -0
  199. package/dist/chrome/context-menus/build-menu.js +97 -0
  200. package/dist/chrome/context-menus/build-menu.js.map +1 -0
  201. package/dist/chrome/context-menus/chrome-context-menus.d.ts +61 -0
  202. package/dist/chrome/context-menus/chrome-context-menus.d.ts.map +1 -0
  203. package/dist/chrome/context-menus/chrome-context-menus.js +219 -0
  204. package/dist/chrome/context-menus/chrome-context-menus.js.map +1 -0
  205. package/dist/chrome/context-menus/context-menu-entry.d.ts +20 -0
  206. package/dist/chrome/context-menus/context-menu-entry.d.ts.map +1 -0
  207. package/dist/chrome/context-menus/context-menu-entry.js +16 -0
  208. package/dist/chrome/context-menus/context-menu-entry.js.map +1 -0
  209. package/dist/chrome/context-menus/context-menu-schema.d.ts +29 -0
  210. package/dist/chrome/context-menus/context-menu-schema.d.ts.map +1 -0
  211. package/dist/chrome/context-menus/context-menu-schema.js +38 -0
  212. package/dist/chrome/context-menus/context-menu-schema.js.map +1 -0
  213. package/dist/chrome/context-menus/context-menu-types.d.ts +74 -0
  214. package/dist/chrome/context-menus/context-menu-types.d.ts.map +1 -0
  215. package/dist/chrome/context-menus/context-menu-types.js +29 -0
  216. package/dist/chrome/context-menus/context-menu-types.js.map +1 -0
  217. package/dist/chrome/context-menus/index.d.ts +5 -0
  218. package/dist/chrome/context-menus/index.d.ts.map +1 -0
  219. package/dist/chrome/context-menus/index.js +4 -0
  220. package/dist/chrome/context-menus/index.js.map +1 -0
  221. package/dist/chrome/i18n/chrome-i18n.d.ts +78 -0
  222. package/dist/chrome/i18n/chrome-i18n.d.ts.map +1 -0
  223. package/dist/chrome/i18n/chrome-i18n.js +151 -0
  224. package/dist/chrome/i18n/chrome-i18n.js.map +1 -0
  225. package/dist/chrome/i18n/detect-language.d.ts +23 -0
  226. package/dist/chrome/i18n/detect-language.d.ts.map +1 -0
  227. package/dist/chrome/i18n/detect-language.js +55 -0
  228. package/dist/chrome/i18n/detect-language.js.map +1 -0
  229. package/dist/chrome/i18n/index.d.ts +6 -0
  230. package/dist/chrome/i18n/index.d.ts.map +1 -0
  231. package/dist/chrome/i18n/index.js +3 -0
  232. package/dist/chrome/i18n/index.js.map +1 -0
  233. package/dist/chrome/i18n/language-defaults.d.ts +17 -0
  234. package/dist/chrome/i18n/language-defaults.d.ts.map +1 -0
  235. package/dist/chrome/i18n/language-defaults.js +123 -0
  236. package/dist/chrome/i18n/language-defaults.js.map +1 -0
  237. package/dist/chrome/i18n/locale-chain.d.ts +26 -0
  238. package/dist/chrome/i18n/locale-chain.d.ts.map +1 -0
  239. package/dist/chrome/i18n/locale-chain.js +38 -0
  240. package/dist/chrome/i18n/locale-chain.js.map +1 -0
  241. package/dist/chrome/i18n/message-format.d.ts +14 -0
  242. package/dist/chrome/i18n/message-format.d.ts.map +1 -0
  243. package/dist/chrome/i18n/message-format.js +40 -0
  244. package/dist/chrome/i18n/message-format.js.map +1 -0
  245. package/dist/chrome/i18n/messages-schema.d.ts +22 -0
  246. package/dist/chrome/i18n/messages-schema.d.ts.map +1 -0
  247. package/dist/chrome/i18n/messages-schema.js +48 -0
  248. package/dist/chrome/i18n/messages-schema.js.map +1 -0
  249. package/dist/chrome/install.d.ts +47 -0
  250. package/dist/chrome/install.d.ts.map +1 -0
  251. package/dist/chrome/install.js +35 -0
  252. package/dist/chrome/install.js.map +1 -0
  253. package/dist/chrome/notifications/chrome-notifications.d.ts +69 -0
  254. package/dist/chrome/notifications/chrome-notifications.d.ts.map +1 -0
  255. package/dist/chrome/notifications/chrome-notifications.js +201 -0
  256. package/dist/chrome/notifications/chrome-notifications.js.map +1 -0
  257. package/dist/chrome/notifications/index.d.ts +5 -0
  258. package/dist/chrome/notifications/index.d.ts.map +1 -0
  259. package/dist/chrome/notifications/index.js +4 -0
  260. package/dist/chrome/notifications/index.js.map +1 -0
  261. package/dist/chrome/notifications/notification-mapping.d.ts +35 -0
  262. package/dist/chrome/notifications/notification-mapping.d.ts.map +1 -0
  263. package/dist/chrome/notifications/notification-mapping.js +47 -0
  264. package/dist/chrome/notifications/notification-mapping.js.map +1 -0
  265. package/dist/chrome/notifications/notification-schema.d.ts +50 -0
  266. package/dist/chrome/notifications/notification-schema.d.ts.map +1 -0
  267. package/dist/chrome/notifications/notification-schema.js +68 -0
  268. package/dist/chrome/notifications/notification-schema.js.map +1 -0
  269. package/dist/chrome/notifications/notification-types.d.ts +50 -0
  270. package/dist/chrome/notifications/notification-types.d.ts.map +1 -0
  271. package/dist/chrome/notifications/notification-types.js +13 -0
  272. package/dist/chrome/notifications/notification-types.js.map +1 -0
  273. package/dist/chrome/permissions/chrome-permissions.d.ts +82 -0
  274. package/dist/chrome/permissions/chrome-permissions.d.ts.map +1 -0
  275. package/dist/chrome/permissions/chrome-permissions.js +190 -0
  276. package/dist/chrome/permissions/chrome-permissions.js.map +1 -0
  277. package/dist/chrome/permissions/index.d.ts +6 -0
  278. package/dist/chrome/permissions/index.d.ts.map +1 -0
  279. package/dist/chrome/permissions/index.js +4 -0
  280. package/dist/chrome/permissions/index.js.map +1 -0
  281. package/dist/chrome/permissions/permission-schema.d.ts +19 -0
  282. package/dist/chrome/permissions/permission-schema.d.ts.map +1 -0
  283. package/dist/chrome/permissions/permission-schema.js +60 -0
  284. package/dist/chrome/permissions/permission-schema.js.map +1 -0
  285. package/dist/chrome/permissions/permission-table.d.ts +15 -0
  286. package/dist/chrome/permissions/permission-table.d.ts.map +1 -0
  287. package/dist/chrome/permissions/permission-table.js +49 -0
  288. package/dist/chrome/permissions/permission-table.js.map +1 -0
  289. package/dist/chrome/permissions/permission-types.d.ts +6 -0
  290. package/dist/chrome/permissions/permission-types.d.ts.map +1 -0
  291. package/dist/chrome/permissions/permission-types.js +2 -0
  292. package/dist/chrome/permissions/permission-types.js.map +1 -0
  293. package/dist/chrome/runtime/identity.d.ts +58 -0
  294. package/dist/chrome/runtime/identity.d.ts.map +1 -0
  295. package/dist/chrome/runtime/identity.js +79 -0
  296. package/dist/chrome/runtime/identity.js.map +1 -0
  297. package/dist/chrome/runtime/index.d.ts +11 -0
  298. package/dist/chrome/runtime/index.d.ts.map +1 -0
  299. package/dist/chrome/runtime/index.js +6 -0
  300. package/dist/chrome/runtime/index.js.map +1 -0
  301. package/dist/chrome/runtime/installed.d.ts +47 -0
  302. package/dist/chrome/runtime/installed.d.ts.map +1 -0
  303. package/dist/chrome/runtime/installed.js +61 -0
  304. package/dist/chrome/runtime/installed.js.map +1 -0
  305. package/dist/chrome/runtime/link.d.ts +62 -0
  306. package/dist/chrome/runtime/link.d.ts.map +1 -0
  307. package/dist/chrome/runtime/link.js +154 -0
  308. package/dist/chrome/runtime/link.js.map +1 -0
  309. package/dist/chrome/runtime/message-event.d.ts +44 -0
  310. package/dist/chrome/runtime/message-event.d.ts.map +1 -0
  311. package/dist/chrome/runtime/message-event.js +95 -0
  312. package/dist/chrome/runtime/message-event.js.map +1 -0
  313. package/dist/chrome/runtime/native-host.d.ts +65 -0
  314. package/dist/chrome/runtime/native-host.d.ts.map +1 -0
  315. package/dist/chrome/runtime/native-host.js +165 -0
  316. package/dist/chrome/runtime/native-host.js.map +1 -0
  317. package/dist/chrome/runtime/native-message.d.ts +35 -0
  318. package/dist/chrome/runtime/native-message.d.ts.map +1 -0
  319. package/dist/chrome/runtime/native-message.js +68 -0
  320. package/dist/chrome/runtime/native-message.js.map +1 -0
  321. package/dist/chrome/runtime/port.d.ts +59 -0
  322. package/dist/chrome/runtime/port.d.ts.map +1 -0
  323. package/dist/chrome/runtime/port.js +84 -0
  324. package/dist/chrome/runtime/port.js.map +1 -0
  325. package/dist/chrome/runtime/runtime.d.ts +165 -0
  326. package/dist/chrome/runtime/runtime.d.ts.map +1 -0
  327. package/dist/chrome/runtime/runtime.js +244 -0
  328. package/dist/chrome/runtime/runtime.js.map +1 -0
  329. package/dist/chrome/storage/chrome-storage.d.ts +43 -0
  330. package/dist/chrome/storage/chrome-storage.d.ts.map +1 -0
  331. package/dist/chrome/storage/chrome-storage.js +80 -0
  332. package/dist/chrome/storage/chrome-storage.js.map +1 -0
  333. package/dist/chrome/storage/index.d.ts +7 -0
  334. package/dist/chrome/storage/index.d.ts.map +1 -0
  335. package/dist/chrome/storage/index.js +4 -0
  336. package/dist/chrome/storage/index.js.map +1 -0
  337. package/dist/chrome/storage/storage-area.d.ts +98 -0
  338. package/dist/chrome/storage/storage-area.d.ts.map +1 -0
  339. package/dist/chrome/storage/storage-area.js +251 -0
  340. package/dist/chrome/storage/storage-area.js.map +1 -0
  341. package/dist/chrome/storage/storage-types.d.ts +91 -0
  342. package/dist/chrome/storage/storage-types.d.ts.map +1 -0
  343. package/dist/chrome/storage/storage-types.js +72 -0
  344. package/dist/chrome/storage/storage-types.js.map +1 -0
  345. package/dist/chrome/system/create-chrome-system.d.ts +27 -0
  346. package/dist/chrome/system/create-chrome-system.d.ts.map +1 -0
  347. package/dist/chrome/system/create-chrome-system.js +25 -0
  348. package/dist/chrome/system/create-chrome-system.js.map +1 -0
  349. package/dist/chrome/system/index.d.ts +11 -0
  350. package/dist/chrome/system/index.d.ts.map +1 -0
  351. package/dist/chrome/system/index.js +8 -0
  352. package/dist/chrome/system/index.js.map +1 -0
  353. package/dist/chrome/system/system-backend.d.ts +50 -0
  354. package/dist/chrome/system/system-backend.d.ts.map +1 -0
  355. package/dist/chrome/system/system-backend.js +60 -0
  356. package/dist/chrome/system/system-backend.js.map +1 -0
  357. package/dist/chrome/system/system-cpu.d.ts +29 -0
  358. package/dist/chrome/system/system-cpu.d.ts.map +1 -0
  359. package/dist/chrome/system/system-cpu.js +43 -0
  360. package/dist/chrome/system/system-cpu.js.map +1 -0
  361. package/dist/chrome/system/system-display.d.ts +40 -0
  362. package/dist/chrome/system/system-display.d.ts.map +1 -0
  363. package/dist/chrome/system/system-display.js +81 -0
  364. package/dist/chrome/system/system-display.js.map +1 -0
  365. package/dist/chrome/system/system-memory.d.ts +17 -0
  366. package/dist/chrome/system/system-memory.d.ts.map +1 -0
  367. package/dist/chrome/system/system-memory.js +20 -0
  368. package/dist/chrome/system/system-memory.js.map +1 -0
  369. package/dist/chrome/system/system-storage.d.ts +25 -0
  370. package/dist/chrome/system/system-storage.d.ts.map +1 -0
  371. package/dist/chrome/system/system-storage.js +29 -0
  372. package/dist/chrome/system/system-storage.js.map +1 -0
  373. package/dist/chrome/system/system-types.d.ts +94 -0
  374. package/dist/chrome/system/system-types.d.ts.map +1 -0
  375. package/dist/chrome/system/system-types.js +7 -0
  376. package/dist/chrome/system/system-types.js.map +1 -0
  377. package/dist/chrome/windows/chrome-windows.d.ts +190 -0
  378. package/dist/chrome/windows/chrome-windows.d.ts.map +1 -0
  379. package/dist/chrome/windows/chrome-windows.js +292 -0
  380. package/dist/chrome/windows/chrome-windows.js.map +1 -0
  381. package/dist/chrome/windows/create-chrome-windows.d.ts +11 -0
  382. package/dist/chrome/windows/create-chrome-windows.d.ts.map +1 -0
  383. package/dist/chrome/windows/create-chrome-windows.js +12 -0
  384. package/dist/chrome/windows/create-chrome-windows.js.map +1 -0
  385. package/dist/chrome/windows/index.d.ts +8 -0
  386. package/dist/chrome/windows/index.d.ts.map +1 -0
  387. package/dist/chrome/windows/index.js +5 -0
  388. package/dist/chrome/windows/index.js.map +1 -0
  389. package/dist/chrome/windows/window-schema.d.ts +54 -0
  390. package/dist/chrome/windows/window-schema.d.ts.map +1 -0
  391. package/dist/chrome/windows/window-schema.js +28 -0
  392. package/dist/chrome/windows/window-schema.js.map +1 -0
  393. package/dist/chrome/windows/window-surface.d.ts +23 -0
  394. package/dist/chrome/windows/window-surface.d.ts.map +1 -0
  395. package/dist/chrome/windows/window-surface.js +2 -0
  396. package/dist/chrome/windows/window-surface.js.map +1 -0
  397. package/dist/chrome/windows/window-types.d.ts +68 -0
  398. package/dist/chrome/windows/window-types.d.ts.map +1 -0
  399. package/dist/chrome/windows/window-types.js +21 -0
  400. package/dist/chrome/windows/window-types.js.map +1 -0
  401. package/dist/chrome/windows/windows-surface.d.ts +30 -0
  402. package/dist/chrome/windows/windows-surface.d.ts.map +1 -0
  403. package/dist/chrome/windows/windows-surface.js +105 -0
  404. package/dist/chrome/windows/windows-surface.js.map +1 -0
  405. package/dist/components/convert.d.ts +2 -1
  406. package/dist/components/convert.d.ts.map +1 -1
  407. package/dist/components/convert.js.map +1 -1
  408. package/dist/components/hand-written/Window.svelte +2 -0
  409. package/dist/components/hand-written/items/item-rows.svelte.d.ts +11 -0
  410. package/dist/components/hand-written/items/item-rows.svelte.d.ts.map +1 -1
  411. package/dist/components/hand-written/items/item-rows.svelte.js +29 -0
  412. package/dist/components/hand-written/items/item-rows.svelte.js.map +1 -1
  413. package/dist/components/hand-written/items/items-host.svelte.d.ts.map +1 -1
  414. package/dist/components/hand-written/items/items-host.svelte.js +1 -0
  415. package/dist/components/hand-written/items/items-host.svelte.js.map +1 -1
  416. package/dist/components/hand-written/items/repeater-host.svelte.d.ts.map +1 -1
  417. package/dist/components/hand-written/items/repeater-host.svelte.js +1 -0
  418. package/dist/components/hand-written/items/repeater-host.svelte.js.map +1 -1
  419. package/dist/components/window-context.d.ts +14 -0
  420. package/dist/components/window-context.d.ts.map +1 -0
  421. package/dist/components/window-context.js +20 -0
  422. package/dist/components/window-context.js.map +1 -0
  423. package/dist/composition/expression.d.ts +1 -1
  424. package/dist/data-transfer/clipboard.d.ts +8 -0
  425. package/dist/data-transfer/clipboard.d.ts.map +1 -1
  426. package/dist/data-transfer/clipboard.js +6 -0
  427. package/dist/data-transfer/clipboard.js.map +1 -1
  428. package/dist/data-transfer/data-transfer.d.ts +17 -0
  429. package/dist/data-transfer/data-transfer.d.ts.map +1 -1
  430. package/dist/data-transfer/data-transfer.js +17 -1
  431. package/dist/data-transfer/data-transfer.js.map +1 -1
  432. package/dist/data-transfer/drag-effects.d.ts +2 -2
  433. package/dist/data-transfer/package-io.d.ts +20 -1
  434. package/dist/data-transfer/package-io.d.ts.map +1 -1
  435. package/dist/data-transfer/package-io.js +26 -1
  436. package/dist/data-transfer/package-io.js.map +1 -1
  437. package/dist/data-transfer/winrt-package.d.ts +5 -0
  438. package/dist/data-transfer/winrt-package.d.ts.map +1 -1
  439. package/dist/data-transfer/winrt-package.js +52 -1
  440. package/dist/data-transfer/winrt-package.js.map +1 -1
  441. package/dist/downloads/chrome-downloads.d.ts +120 -0
  442. package/dist/downloads/chrome-downloads.d.ts.map +1 -0
  443. package/dist/downloads/chrome-downloads.js +389 -0
  444. package/dist/downloads/chrome-downloads.js.map +1 -0
  445. package/dist/downloads/chrome-event.d.ts +20 -0
  446. package/dist/downloads/chrome-event.d.ts.map +1 -0
  447. package/dist/downloads/chrome-event.js +39 -0
  448. package/dist/downloads/chrome-event.js.map +1 -0
  449. package/dist/downloads/download-query.d.ts +14 -0
  450. package/dist/downloads/download-query.d.ts.map +1 -0
  451. package/dist/downloads/download-query.js +152 -0
  452. package/dist/downloads/download-query.js.map +1 -0
  453. package/dist/downloads/download-record.d.ts +149 -0
  454. package/dist/downloads/download-record.d.ts.map +1 -0
  455. package/dist/downloads/download-record.js +142 -0
  456. package/dist/downloads/download-record.js.map +1 -0
  457. package/dist/downloads/download-target.d.ts +29 -0
  458. package/dist/downloads/download-target.d.ts.map +1 -0
  459. package/dist/downloads/download-target.js +68 -0
  460. package/dist/downloads/download-target.js.map +1 -0
  461. package/dist/downloads/download-transfer.d.ts +30 -0
  462. package/dist/downloads/download-transfer.d.ts.map +1 -0
  463. package/dist/downloads/download-transfer.js +126 -0
  464. package/dist/downloads/download-transfer.js.map +1 -0
  465. package/dist/downloads/download-types.d.ts +214 -0
  466. package/dist/downloads/download-types.d.ts.map +1 -0
  467. package/dist/downloads/download-types.js +92 -0
  468. package/dist/downloads/download-types.js.map +1 -0
  469. package/dist/downloads/fetch-to-file.d.ts +99 -0
  470. package/dist/downloads/fetch-to-file.d.ts.map +1 -0
  471. package/dist/downloads/fetch-to-file.js +188 -0
  472. package/dist/downloads/fetch-to-file.js.map +1 -0
  473. package/dist/downloads/index.d.ts +10 -0
  474. package/dist/downloads/index.d.ts.map +1 -0
  475. package/dist/downloads/index.js +6 -0
  476. package/dist/downloads/index.js.map +1 -0
  477. package/dist/downloads/interrupt-reason.d.ts +12 -0
  478. package/dist/downloads/interrupt-reason.d.ts.map +1 -0
  479. package/dist/downloads/interrupt-reason.js +57 -0
  480. package/dist/downloads/interrupt-reason.js.map +1 -0
  481. package/dist/downloads/taskbar-progress.d.ts +4 -0
  482. package/dist/downloads/taskbar-progress.d.ts.map +1 -0
  483. package/dist/downloads/taskbar-progress.js +2 -0
  484. package/dist/downloads/taskbar-progress.js.map +1 -0
  485. package/dist/downloads/zone-identifier.d.ts +21 -0
  486. package/dist/downloads/zone-identifier.d.ts.map +1 -0
  487. package/dist/downloads/zone-identifier.js +38 -0
  488. package/dist/downloads/zone-identifier.js.map +1 -0
  489. package/dist/enums.d.ts +6 -0
  490. package/dist/enums.d.ts.map +1 -1
  491. package/dist/enums.js +6 -0
  492. package/dist/enums.js.map +1 -1
  493. package/dist/forms/form-field-props.d.ts +2 -2
  494. package/dist/incremental/incremental-source.svelte.d.ts +71 -0
  495. package/dist/incremental/incremental-source.svelte.d.ts.map +1 -0
  496. package/dist/incremental/incremental-source.svelte.js +138 -0
  497. package/dist/incremental/incremental-source.svelte.js.map +1 -0
  498. package/dist/incremental/index.d.ts +5 -0
  499. package/dist/incremental/index.d.ts.map +1 -0
  500. package/dist/incremental/index.js +3 -0
  501. package/dist/incremental/index.js.map +1 -0
  502. package/dist/incremental/state.d.ts +35 -0
  503. package/dist/incremental/state.d.ts.map +1 -0
  504. package/dist/incremental/state.js +12 -0
  505. package/dist/incremental/state.js.map +1 -0
  506. package/dist/media/index.d.ts +1 -0
  507. package/dist/media/index.d.ts.map +1 -1
  508. package/dist/media/index.js.map +1 -1
  509. package/dist/picture-source.d.ts +25 -0
  510. package/dist/picture-source.d.ts.map +1 -0
  511. package/dist/picture-source.js +2 -0
  512. package/dist/picture-source.js.map +1 -0
  513. package/dist/progress/TaskbarProgress.d.svelte.ts +6 -0
  514. package/dist/progress/TaskbarProgress.svelte +32 -0
  515. package/dist/progress/aggregate.d.ts +23 -0
  516. package/dist/progress/aggregate.d.ts.map +1 -0
  517. package/dist/progress/aggregate.js +59 -0
  518. package/dist/progress/aggregate.js.map +1 -0
  519. package/dist/progress/core.d.ts +14 -0
  520. package/dist/progress/core.d.ts.map +1 -0
  521. package/dist/progress/core.js +8 -0
  522. package/dist/progress/core.js.map +1 -0
  523. package/dist/progress/index.d.ts +5 -0
  524. package/dist/progress/index.d.ts.map +1 -0
  525. package/dist/progress/index.js +4 -0
  526. package/dist/progress/index.js.map +1 -0
  527. package/dist/progress/progress-event.d.ts +18 -0
  528. package/dist/progress/progress-event.d.ts.map +1 -0
  529. package/dist/progress/progress-event.js +19 -0
  530. package/dist/progress/progress-event.js.map +1 -0
  531. package/dist/progress/progress-operation.d.ts +163 -0
  532. package/dist/progress/progress-operation.d.ts.map +1 -0
  533. package/dist/progress/progress-operation.js +356 -0
  534. package/dist/progress/progress-operation.js.map +1 -0
  535. package/dist/progress/progress-registry.d.ts +89 -0
  536. package/dist/progress/progress-registry.d.ts.map +1 -0
  537. package/dist/progress/progress-registry.js +187 -0
  538. package/dist/progress/progress-registry.js.map +1 -0
  539. package/dist/progress/progress-source.d.ts +46 -0
  540. package/dist/progress/progress-source.d.ts.map +1 -0
  541. package/dist/progress/progress-source.js +31 -0
  542. package/dist/progress/progress-source.js.map +1 -0
  543. package/dist/progress/progress-state.d.ts +54 -0
  544. package/dist/progress/progress-state.d.ts.map +1 -0
  545. package/dist/progress/progress-state.js +35 -0
  546. package/dist/progress/progress-state.js.map +1 -0
  547. package/dist/progress/progress-text.d.ts +10 -0
  548. package/dist/progress/progress-text.d.ts.map +1 -0
  549. package/dist/progress/progress-text.js +23 -0
  550. package/dist/progress/progress-text.js.map +1 -0
  551. package/dist/progress/scoped-source.d.ts +31 -0
  552. package/dist/progress/scoped-source.d.ts.map +1 -0
  553. package/dist/progress/scoped-source.js +46 -0
  554. package/dist/progress/scoped-source.js.map +1 -0
  555. package/dist/progress/taskbar-progress-props.d.ts +15 -0
  556. package/dist/progress/taskbar-progress-props.d.ts.map +1 -0
  557. package/dist/progress/taskbar-progress-props.js +2 -0
  558. package/dist/progress/taskbar-progress-props.js.map +1 -0
  559. package/dist/progress/taskbar-progress.d.ts +44 -0
  560. package/dist/progress/taskbar-progress.d.ts.map +1 -0
  561. package/dist/progress/taskbar-progress.js +62 -0
  562. package/dist/progress/taskbar-progress.js.map +1 -0
  563. package/dist/progress/track-operation.d.ts +36 -0
  564. package/dist/progress/track-operation.d.ts.map +1 -0
  565. package/dist/progress/track-operation.js +53 -0
  566. package/dist/progress/track-operation.js.map +1 -0
  567. package/dist/renderer/host/host.d.ts.map +1 -1
  568. package/dist/renderer/host/host.js +11 -14
  569. package/dist/renderer/host/host.js.map +1 -1
  570. package/dist/store/states.d.ts +2 -2
  571. package/dist/store/windows-packages.d.ts +2 -2
  572. package/dist/store/windows-store.d.ts +2 -2
  573. package/dist/tray/TrayIcon.d.svelte.ts +14 -2
  574. package/dist/tray/TrayIcon.svelte +65 -18
  575. package/dist/tray/TrayMenuFlyout.d.svelte.ts +6 -0
  576. package/dist/tray/TrayMenuFlyout.svelte +108 -0
  577. package/dist/tray/balloons.d.ts +7 -0
  578. package/dist/tray/balloons.d.ts.map +1 -0
  579. package/dist/tray/balloons.js +53 -0
  580. package/dist/tray/balloons.js.map +1 -0
  581. package/dist/tray/bounds.d.ts +7 -0
  582. package/dist/tray/bounds.d.ts.map +1 -0
  583. package/dist/tray/bounds.js +15 -0
  584. package/dist/tray/bounds.js.map +1 -0
  585. package/dist/tray/flyout-model.d.ts +43 -0
  586. package/dist/tray/flyout-model.d.ts.map +1 -0
  587. package/dist/tray/flyout-model.js +55 -0
  588. package/dist/tray/flyout-model.js.map +1 -0
  589. package/dist/tray/flyout-picker.d.ts +24 -0
  590. package/dist/tray/flyout-picker.d.ts.map +1 -0
  591. package/dist/tray/flyout-picker.js +46 -0
  592. package/dist/tray/flyout-picker.js.map +1 -0
  593. package/dist/tray/index.d.ts +3 -0
  594. package/dist/tray/index.d.ts.map +1 -1
  595. package/dist/tray/index.js +1 -0
  596. package/dist/tray/index.js.map +1 -1
  597. package/dist/tray/menu/default-profile.d.ts +12 -0
  598. package/dist/tray/menu/default-profile.d.ts.map +1 -0
  599. package/dist/tray/menu/default-profile.js +17 -0
  600. package/dist/tray/menu/default-profile.js.map +1 -0
  601. package/dist/tray/menu/define.d.ts +10 -0
  602. package/dist/tray/menu/define.d.ts.map +1 -0
  603. package/dist/tray/menu/define.js +11 -0
  604. package/dist/tray/menu/define.js.map +1 -0
  605. package/dist/tray/menu/describe.d.ts +12 -0
  606. package/dist/tray/menu/describe.d.ts.map +1 -0
  607. package/dist/tray/menu/describe.js +31 -0
  608. package/dist/tray/menu/describe.js.map +1 -0
  609. package/dist/tray/menu/expand.d.ts +20 -0
  610. package/dist/tray/menu/expand.d.ts.map +1 -0
  611. package/dist/tray/menu/expand.js +56 -0
  612. package/dist/tray/menu/expand.js.map +1 -0
  613. package/dist/tray/menu/index.d.ts +10 -0
  614. package/dist/tray/menu/index.d.ts.map +1 -0
  615. package/dist/tray/menu/index.js +9 -0
  616. package/dist/tray/menu/index.js.map +1 -0
  617. package/dist/tray/menu/profile-file.d.ts +22 -0
  618. package/dist/tray/menu/profile-file.d.ts.map +1 -0
  619. package/dist/tray/menu/profile-file.js +35 -0
  620. package/dist/tray/menu/profile-file.js.map +1 -0
  621. package/dist/tray/menu/profile.d.ts +29 -0
  622. package/dist/tray/menu/profile.d.ts.map +1 -0
  623. package/dist/tray/menu/profile.js +32 -0
  624. package/dist/tray/menu/profile.js.map +1 -0
  625. package/dist/tray/menu/resolve-lite.d.ts +44 -0
  626. package/dist/tray/menu/resolve-lite.d.ts.map +1 -0
  627. package/dist/tray/menu/resolve-lite.js +169 -0
  628. package/dist/tray/menu/resolve-lite.js.map +1 -0
  629. package/dist/tray/menu/resolve.d.ts +21 -0
  630. package/dist/tray/menu/resolve.d.ts.map +1 -0
  631. package/dist/tray/menu/resolve.js +56 -0
  632. package/dist/tray/menu/resolve.js.map +1 -0
  633. package/dist/tray/menu/types.d.ts +208 -0
  634. package/dist/tray/menu/types.d.ts.map +1 -0
  635. package/dist/tray/menu/types.js +19 -0
  636. package/dist/tray/menu/types.js.map +1 -0
  637. package/dist/tray/menu/values.d.ts +14 -0
  638. package/dist/tray/menu/values.d.ts.map +1 -0
  639. package/dist/tray/menu/values.js +15 -0
  640. package/dist/tray/menu/values.js.map +1 -0
  641. package/dist/tray/menu-svelte/TrayMenu.d.svelte.ts +6 -0
  642. package/dist/tray/menu-svelte/TrayMenu.svelte +20 -0
  643. package/dist/tray/menu-svelte/TrayMenuEditor.d.svelte.ts +17 -0
  644. package/dist/tray/menu-svelte/TrayMenuEditor.svelte +322 -0
  645. package/dist/tray/menu-svelte/TrayMenuHeader.d.svelte.ts +6 -0
  646. package/dist/tray/menu-svelte/TrayMenuHeader.svelte +9 -0
  647. package/dist/tray/menu-svelte/TrayMenuItem.d.svelte.ts +6 -0
  648. package/dist/tray/menu-svelte/TrayMenuItem.svelte +10 -0
  649. package/dist/tray/menu-svelte/TrayMenuOperations.d.svelte.ts +6 -0
  650. package/dist/tray/menu-svelte/TrayMenuOperations.svelte +33 -0
  651. package/dist/tray/menu-svelte/TrayMenuProgress.d.svelte.ts +6 -0
  652. package/dist/tray/menu-svelte/TrayMenuProgress.svelte +28 -0
  653. package/dist/tray/menu-svelte/TrayMenuSeparator.d.svelte.ts +6 -0
  654. package/dist/tray/menu-svelte/TrayMenuSeparator.svelte +9 -0
  655. package/dist/tray/menu-svelte/TrayMenuSubmenu.d.svelte.ts +6 -0
  656. package/dist/tray/menu-svelte/TrayMenuSubmenu.svelte +11 -0
  657. package/dist/tray/menu-svelte/collect.d.ts +22 -0
  658. package/dist/tray/menu-svelte/collect.d.ts.map +1 -0
  659. package/dist/tray/menu-svelte/collect.js +53 -0
  660. package/dist/tray/menu-svelte/collect.js.map +1 -0
  661. package/dist/tray/menu-svelte/edit-profile.d.ts +100 -0
  662. package/dist/tray/menu-svelte/edit-profile.d.ts.map +1 -0
  663. package/dist/tray/menu-svelte/edit-profile.js +200 -0
  664. package/dist/tray/menu-svelte/edit-profile.js.map +1 -0
  665. package/dist/tray/menu-svelte/editor-labels.d.ts +33 -0
  666. package/dist/tray/menu-svelte/editor-labels.d.ts.map +1 -0
  667. package/dist/tray/menu-svelte/editor-labels.js +30 -0
  668. package/dist/tray/menu-svelte/editor-labels.js.map +1 -0
  669. package/dist/tray/menu-svelte/editor-props.d.ts +22 -0
  670. package/dist/tray/menu-svelte/editor-props.d.ts.map +1 -0
  671. package/dist/tray/menu-svelte/editor-props.js +2 -0
  672. package/dist/tray/menu-svelte/editor-props.js.map +1 -0
  673. package/dist/tray/menu-svelte/index.d.ts +14 -0
  674. package/dist/tray/menu-svelte/index.d.ts.map +1 -0
  675. package/dist/tray/menu-svelte/index.js +11 -0
  676. package/dist/tray/menu-svelte/index.js.map +1 -0
  677. package/dist/tray/menu-svelte/menu-node.d.ts +125 -0
  678. package/dist/tray/menu-svelte/menu-node.d.ts.map +1 -0
  679. package/dist/tray/menu-svelte/menu-node.js +82 -0
  680. package/dist/tray/menu-svelte/menu-node.js.map +1 -0
  681. package/dist/tray/menu-svelte/menu-props.d.ts +51 -0
  682. package/dist/tray/menu-svelte/menu-props.d.ts.map +1 -0
  683. package/dist/tray/menu-svelte/menu-props.js +2 -0
  684. package/dist/tray/menu-svelte/menu-props.js.map +1 -0
  685. package/dist/tray/menu-svelte/menu-source.d.ts +36 -0
  686. package/dist/tray/menu-svelte/menu-source.d.ts.map +1 -0
  687. package/dist/tray/menu-svelte/menu-source.js +54 -0
  688. package/dist/tray/menu-svelte/menu-source.js.map +1 -0
  689. package/dist/tray/menu-svelte/operation-ids.d.ts +8 -0
  690. package/dist/tray/menu-svelte/operation-ids.d.ts.map +1 -0
  691. package/dist/tray/menu-svelte/operation-ids.js +20 -0
  692. package/dist/tray/menu-svelte/operation-ids.js.map +1 -0
  693. package/dist/tray/menu-svelte/preview-lines.d.ts +20 -0
  694. package/dist/tray/menu-svelte/preview-lines.d.ts.map +1 -0
  695. package/dist/tray/menu-svelte/preview-lines.js +40 -0
  696. package/dist/tray/menu-svelte/preview-lines.js.map +1 -0
  697. package/dist/tray/native.d.ts +36 -8
  698. package/dist/tray/native.d.ts.map +1 -1
  699. package/dist/tray/native.js +107 -226
  700. package/dist/tray/native.js.map +1 -1
  701. package/dist/tray/pointer-share.d.ts +27 -0
  702. package/dist/tray/pointer-share.d.ts.map +1 -0
  703. package/dist/tray/pointer-share.js +61 -0
  704. package/dist/tray/pointer-share.js.map +1 -0
  705. package/dist/tray/standalone/define-tray.d.ts +26 -0
  706. package/dist/tray/standalone/define-tray.d.ts.map +1 -0
  707. package/dist/tray/standalone/define-tray.js +15 -0
  708. package/dist/tray/standalone/define-tray.js.map +1 -0
  709. package/dist/tray/standalone/index.d.ts +14 -4
  710. package/dist/tray/standalone/index.d.ts.map +1 -1
  711. package/dist/tray/standalone/index.js +7 -1
  712. package/dist/tray/standalone/index.js.map +1 -1
  713. package/dist/tray/standalone/menu-theme.d.ts +38 -0
  714. package/dist/tray/standalone/menu-theme.d.ts.map +1 -0
  715. package/dist/tray/standalone/menu-theme.js +74 -0
  716. package/dist/tray/standalone/menu-theme.js.map +1 -0
  717. package/dist/tray/standalone/native.d.ts +44 -24
  718. package/dist/tray/standalone/native.d.ts.map +1 -1
  719. package/dist/tray/standalone/native.js +148 -76
  720. package/dist/tray/standalone/native.js.map +1 -1
  721. package/dist/tray/standalone/standalone-tray.d.ts +56 -19
  722. package/dist/tray/standalone/standalone-tray.d.ts.map +1 -1
  723. package/dist/tray/standalone/standalone-tray.js +65 -41
  724. package/dist/tray/standalone/standalone-tray.js.map +1 -1
  725. package/dist/tray/themed-icon.d.ts +7 -0
  726. package/dist/tray/themed-icon.d.ts.map +1 -0
  727. package/dist/tray/themed-icon.js +39 -0
  728. package/dist/tray/themed-icon.js.map +1 -0
  729. package/dist/tray/tray-core.d.ts +11 -10
  730. package/dist/tray/tray-core.d.ts.map +1 -1
  731. package/dist/tray/tray-core.js +21 -31
  732. package/dist/tray/tray-core.js.map +1 -1
  733. package/dist/tray/tray-extras.d.ts +61 -0
  734. package/dist/tray/tray-extras.d.ts.map +1 -0
  735. package/dist/tray/tray-extras.js +2 -0
  736. package/dist/tray/tray-extras.js.map +1 -0
  737. package/dist/tray/tray-icon-props.d.ts +18 -5
  738. package/dist/tray/tray-icon-props.d.ts.map +1 -1
  739. package/dist/tray/tray-icon.d.ts +4 -2
  740. package/dist/tray/tray-icon.d.ts.map +1 -1
  741. package/dist/tray/tray-icon.js +13 -3
  742. package/dist/tray/tray-icon.js.map +1 -1
  743. package/dist/tray/tray-manifest.d.ts +58 -0
  744. package/dist/tray/tray-manifest.d.ts.map +1 -0
  745. package/dist/tray/tray-manifest.js +66 -0
  746. package/dist/tray/tray-manifest.js.map +1 -0
  747. package/dist/tray/tray-menu-flyout-props.d.ts +15 -0
  748. package/dist/tray/tray-menu-flyout-props.d.ts.map +1 -0
  749. package/dist/tray/tray-menu-flyout-props.js +2 -0
  750. package/dist/tray/tray-menu-flyout-props.js.map +1 -0
  751. package/dist/tray/tray-menu.d.ts +2 -2
  752. package/dist/tray/tray-menu.d.ts.map +1 -1
  753. package/dist/vite/build.d.ts +5 -1
  754. package/dist/vite/build.d.ts.map +1 -1
  755. package/dist/vite/build.js +26 -5
  756. package/dist/vite/build.js.map +1 -1
  757. package/dist/vite/entrypoints/build-tray.d.ts +29 -0
  758. package/dist/vite/entrypoints/build-tray.d.ts.map +1 -0
  759. package/dist/vite/entrypoints/build-tray.js +72 -0
  760. package/dist/vite/entrypoints/build-tray.js.map +1 -0
  761. package/dist/vite/entrypoints/discover.d.ts +30 -0
  762. package/dist/vite/entrypoints/discover.d.ts.map +1 -0
  763. package/dist/vite/entrypoints/discover.js +61 -0
  764. package/dist/vite/entrypoints/discover.js.map +1 -0
  765. package/dist/vite/entrypoints/extract-tray.d.ts +15 -0
  766. package/dist/vite/entrypoints/extract-tray.d.ts.map +1 -0
  767. package/dist/vite/entrypoints/extract-tray.js +103 -0
  768. package/dist/vite/entrypoints/extract-tray.js.map +1 -0
  769. package/dist/vite/entrypoints/lower-menu-markup.d.ts +40 -0
  770. package/dist/vite/entrypoints/lower-menu-markup.d.ts.map +1 -0
  771. package/dist/vite/entrypoints/lower-menu-markup.js +339 -0
  772. package/dist/vite/entrypoints/lower-menu-markup.js.map +1 -0
  773. package/dist/vite/entrypoints/lower-tray-svelte.d.ts +14 -0
  774. package/dist/vite/entrypoints/lower-tray-svelte.d.ts.map +1 -0
  775. package/dist/vite/entrypoints/lower-tray-svelte.js +259 -0
  776. package/dist/vite/entrypoints/lower-tray-svelte.js.map +1 -0
  777. package/dist/vite/entrypoints/node-span.d.ts +13 -0
  778. package/dist/vite/entrypoints/node-span.d.ts.map +1 -0
  779. package/dist/vite/entrypoints/node-span.js +32 -0
  780. package/dist/vite/entrypoints/node-span.js.map +1 -0
  781. package/dist/vite/entrypoints/tray-dev-plugin.d.ts +9 -0
  782. package/dist/vite/entrypoints/tray-dev-plugin.d.ts.map +1 -0
  783. package/dist/vite/entrypoints/tray-dev-plugin.js +102 -0
  784. package/dist/vite/entrypoints/tray-dev-plugin.js.map +1 -0
  785. package/dist/vite/entrypoints/tray-module.d.ts +23 -0
  786. package/dist/vite/entrypoints/tray-module.d.ts.map +1 -0
  787. package/dist/vite/entrypoints/tray-module.js +58 -0
  788. package/dist/vite/entrypoints/tray-module.js.map +1 -0
  789. package/dist/vite/entrypoints/tray-process.d.ts +39 -0
  790. package/dist/vite/entrypoints/tray-process.d.ts.map +1 -0
  791. package/dist/vite/entrypoints/tray-process.js +59 -0
  792. package/dist/vite/entrypoints/tray-process.js.map +1 -0
  793. package/dist/vite/entrypoints/tray-source.d.ts +11 -0
  794. package/dist/vite/entrypoints/tray-source.d.ts.map +1 -0
  795. package/dist/vite/entrypoints/tray-source.js +20 -0
  796. package/dist/vite/entrypoints/tray-source.js.map +1 -0
  797. package/dist/vite/entrypoints/tray-svelte-error.d.ts +14 -0
  798. package/dist/vite/entrypoints/tray-svelte-error.d.ts.map +1 -0
  799. package/dist/vite/entrypoints/tray-svelte-error.js +22 -0
  800. package/dist/vite/entrypoints/tray-svelte-error.js.map +1 -0
  801. package/dist/vite/externals.d.ts +7 -0
  802. package/dist/vite/externals.d.ts.map +1 -0
  803. package/dist/vite/externals.js +18 -0
  804. package/dist/vite/externals.js.map +1 -0
  805. package/dist/vite/plugin.d.ts.map +1 -1
  806. package/dist/vite/plugin.js +3 -12
  807. package/dist/vite/plugin.js.map +1 -1
  808. package/dist/web-apis/clipboard.d.ts.map +1 -1
  809. package/dist/web-apis/clipboard.js +48 -17
  810. package/dist/web-apis/clipboard.js.map +1 -1
  811. package/dist/web-apis/dialog-types.d.ts +81 -0
  812. package/dist/web-apis/dialog-types.d.ts.map +1 -0
  813. package/dist/web-apis/dialog-types.js +14 -0
  814. package/dist/web-apis/dialog-types.js.map +1 -0
  815. package/dist/web-apis/dialogs-windows.d.ts +25 -0
  816. package/dist/web-apis/dialogs-windows.d.ts.map +1 -0
  817. package/dist/web-apis/dialogs-windows.js +114 -0
  818. package/dist/web-apis/dialogs-windows.js.map +1 -0
  819. package/dist/web-apis/dialogs.d.ts +76 -0
  820. package/dist/web-apis/dialogs.d.ts.map +1 -0
  821. package/dist/web-apis/dialogs.js +250 -0
  822. package/dist/web-apis/dialogs.js.map +1 -0
  823. package/dist/web-apis/file-read.d.ts +14 -0
  824. package/dist/web-apis/file-read.d.ts.map +1 -0
  825. package/dist/web-apis/file-read.js +37 -0
  826. package/dist/web-apis/file-read.js.map +1 -0
  827. package/dist/web-apis/file-system.d.ts +9 -0
  828. package/dist/web-apis/file-system.d.ts.map +1 -1
  829. package/dist/web-apis/file-system.js +24 -0
  830. package/dist/web-apis/file-system.js.map +1 -1
  831. package/dist/web-apis/geolocation.d.ts.map +1 -1
  832. package/dist/web-apis/geolocation.js +14 -8
  833. package/dist/web-apis/geolocation.js.map +1 -1
  834. package/dist/web-apis/idle.d.ts +1 -1
  835. package/dist/web-apis/image-codec-windows.d.ts +24 -0
  836. package/dist/web-apis/image-codec-windows.d.ts.map +1 -0
  837. package/dist/web-apis/image-codec-windows.js +107 -0
  838. package/dist/web-apis/image-codec-windows.js.map +1 -0
  839. package/dist/web-apis/image-pixels.d.ts +27 -0
  840. package/dist/web-apis/image-pixels.d.ts.map +1 -0
  841. package/dist/web-apis/image-pixels.js +152 -0
  842. package/dist/web-apis/image-pixels.js.map +1 -0
  843. package/dist/web-apis/image-types.d.ts +64 -0
  844. package/dist/web-apis/image-types.d.ts.map +1 -0
  845. package/dist/web-apis/image-types.js +23 -0
  846. package/dist/web-apis/image-types.js.map +1 -0
  847. package/dist/web-apis/images.d.ts +199 -0
  848. package/dist/web-apis/images.d.ts.map +1 -0
  849. package/dist/web-apis/images.js +476 -0
  850. package/dist/web-apis/images.js.map +1 -0
  851. package/dist/web-apis/media-access.d.ts +1 -1
  852. package/dist/web-apis/notification.d.ts +6 -5
  853. package/dist/web-apis/notification.d.ts.map +1 -1
  854. package/dist/web-apis/notification.js.map +1 -1
  855. package/dist/web-apis/page.d.ts +1 -1
  856. package/dist/web-apis/permissions.d.ts +17 -0
  857. package/dist/web-apis/permissions.d.ts.map +1 -1
  858. package/dist/web-apis/permissions.js +25 -0
  859. package/dist/web-apis/permissions.js.map +1 -1
  860. package/dist/web-apis/png-writer.d.ts +9 -0
  861. package/dist/web-apis/png-writer.d.ts.map +1 -0
  862. package/dist/web-apis/png-writer.js +58 -0
  863. package/dist/web-apis/png-writer.js.map +1 -0
  864. package/dist/web-apis/push.d.ts +1 -1
  865. package/dist/web-apis/scroll-timeline.d.ts +1 -1
  866. package/dist/win32-calls.d.ts +32 -0
  867. package/dist/win32-calls.d.ts.map +1 -1
  868. package/dist/win32-calls.js +44 -0
  869. package/dist/win32-calls.js.map +1 -1
  870. package/dist/win32-foreground.d.ts +14 -0
  871. package/dist/win32-foreground.d.ts.map +1 -0
  872. package/dist/win32-foreground.js +71 -0
  873. package/dist/win32-foreground.js.map +1 -0
  874. package/dist/win32-icons.d.ts.map +1 -1
  875. package/dist/win32-icons.js +11 -31
  876. package/dist/win32-icons.js.map +1 -1
  877. package/dist/window/create-window.d.ts +4 -1
  878. package/dist/window/create-window.d.ts.map +1 -1
  879. package/dist/window/create-window.js +2 -0
  880. package/dist/window/create-window.js.map +1 -1
  881. package/dist/window/foreground-filter.d.ts +71 -0
  882. package/dist/window/foreground-filter.d.ts.map +1 -0
  883. package/dist/window/foreground-filter.js +108 -0
  884. package/dist/window/foreground-filter.js.map +1 -0
  885. package/dist/window/foreground-native.d.ts +25 -0
  886. package/dist/window/foreground-native.d.ts.map +1 -0
  887. package/dist/window/foreground-native.js +88 -0
  888. package/dist/window/foreground-native.js.map +1 -0
  889. package/dist/window/foreground.d.ts +49 -0
  890. package/dist/window/foreground.d.ts.map +1 -0
  891. package/dist/window/foreground.js +78 -0
  892. package/dist/window/foreground.js.map +1 -0
  893. package/dist/window/taskbar-calls.d.ts +28 -0
  894. package/dist/window/taskbar-calls.d.ts.map +1 -1
  895. package/dist/window/taskbar-calls.js +34 -0
  896. package/dist/window/taskbar-calls.js.map +1 -1
  897. package/dist/window/taskbar-native.d.ts.map +1 -1
  898. package/dist/window/taskbar-native.js +35 -1
  899. package/dist/window/taskbar-native.js.map +1 -1
  900. package/dist/window/taskbar.d.ts +34 -5
  901. package/dist/window/taskbar.d.ts.map +1 -1
  902. package/dist/window/taskbar.js +28 -3
  903. package/dist/window/taskbar.js.map +1 -1
  904. package/dist/window/window-host.svelte.d.ts +3 -2
  905. package/dist/window/window-host.svelte.d.ts.map +1 -1
  906. package/dist/window/window-host.svelte.js.map +1 -1
  907. package/dist/window/window-state.d.ts +1 -1
  908. package/dist/winui.d.ts +7 -0
  909. package/dist/winui.d.ts.map +1 -1
  910. package/dist/winui.js +7 -0
  911. package/dist/winui.js.map +1 -1
  912. package/package.json +100 -1
  913. package/src/app/activation/alarm-argument.ts +55 -0
  914. package/src/app/activation/classify.ts +36 -5
  915. package/src/app/activation/index.ts +1 -1
  916. package/src/app/activation/jump-list-argument.ts +30 -0
  917. package/src/app/activation/kinds.ts +24 -2
  918. package/src/app/activation/receive.ts +15 -1
  919. package/src/app/activation/registration.ts +11 -3
  920. package/src/app/activation/scheme.ts +11 -1
  921. package/src/app/index.ts +2 -0
  922. package/src/app/instance-pipe.ts +1 -3
  923. package/src/app/jump-list/index.ts +100 -0
  924. package/src/app/jump-list/native.ts +309 -0
  925. package/src/app/jump-list/tasks.ts +166 -0
  926. package/src/app/launch-command.ts +19 -5
  927. package/src/app/schedule/alarm.ts +11 -0
  928. package/src/app/schedule/alarms.ts +240 -0
  929. package/src/app/schedule/backend.ts +23 -0
  930. package/src/app/schedule/events.ts +67 -0
  931. package/src/app/schedule/index.ts +6 -0
  932. package/src/app/schedule/native.ts +78 -0
  933. package/src/app/schedule/occurrence.ts +45 -0
  934. package/src/app/schedule/xml.ts +115 -0
  935. package/src/app/shell/app-paths.ts +145 -0
  936. package/src/app/shell/backend.ts +30 -0
  937. package/src/app/shell/index.ts +11 -0
  938. package/src/app/shell/kinds.ts +52 -0
  939. package/src/app/shell/native.ts +336 -0
  940. package/src/app/shell/open-with.ts +62 -0
  941. package/src/app/shell/paths.ts +29 -0
  942. package/src/app/shell/shortcut.ts +163 -0
  943. package/src/app/shell/trash.ts +53 -0
  944. package/src/app/tray-instance.ts +77 -0
  945. package/src/automation/backend.ts +56 -0
  946. package/src/automation/client.ts +327 -0
  947. package/src/automation/ids.ts +97 -0
  948. package/src/automation/index.ts +23 -0
  949. package/src/automation/native.ts +689 -0
  950. package/src/automation/text.ts +174 -0
  951. package/src/automation/with-client.ts +20 -0
  952. package/src/automation/worker-job.ts +97 -0
  953. package/src/automation/worker.ts +116 -0
  954. package/src/chrome/action/action-types.ts +123 -0
  955. package/src/chrome/action/chrome-action.ts +234 -0
  956. package/src/chrome/action/create-chrome-action.ts +35 -0
  957. package/src/chrome/action/index.ts +13 -0
  958. package/src/chrome/commands/chrome-commands.ts +174 -0
  959. package/src/chrome/commands/command-types.ts +48 -0
  960. package/src/chrome/commands/index.ts +6 -0
  961. package/src/chrome/commands/shortcut.ts +107 -0
  962. package/src/chrome/context-menus/build-menu.ts +121 -0
  963. package/src/chrome/context-menus/chrome-context-menus.ts +255 -0
  964. package/src/chrome/context-menus/context-menu-entry.ts +34 -0
  965. package/src/chrome/context-menus/context-menu-schema.ts +48 -0
  966. package/src/chrome/context-menus/context-menu-types.ts +94 -0
  967. package/src/chrome/context-menus/index.ts +4 -0
  968. package/src/chrome/i18n/chrome-i18n.ts +197 -0
  969. package/src/chrome/i18n/detect-language.ts +67 -0
  970. package/src/chrome/i18n/index.ts +5 -0
  971. package/src/chrome/i18n/language-defaults.ts +167 -0
  972. package/src/chrome/i18n/locale-chain.ts +44 -0
  973. package/src/chrome/i18n/message-format.ts +60 -0
  974. package/src/chrome/i18n/messages-schema.ts +61 -0
  975. package/src/chrome/install.ts +75 -0
  976. package/src/chrome/notifications/chrome-notifications.ts +249 -0
  977. package/src/chrome/notifications/index.ts +8 -0
  978. package/src/chrome/notifications/notification-mapping.ts +63 -0
  979. package/src/chrome/notifications/notification-schema.ts +80 -0
  980. package/src/chrome/notifications/notification-types.ts +60 -0
  981. package/src/chrome/permissions/chrome-permissions.ts +259 -0
  982. package/src/chrome/permissions/index.ts +5 -0
  983. package/src/chrome/permissions/permission-schema.ts +75 -0
  984. package/src/chrome/permissions/permission-table.ts +54 -0
  985. package/src/chrome/permissions/permission-types.ts +5 -0
  986. package/src/chrome/runtime/identity.ts +115 -0
  987. package/src/chrome/runtime/index.ts +10 -0
  988. package/src/chrome/runtime/installed.ts +85 -0
  989. package/src/chrome/runtime/link.ts +211 -0
  990. package/src/chrome/runtime/message-event.ts +126 -0
  991. package/src/chrome/runtime/native-host.ts +220 -0
  992. package/src/chrome/runtime/native-message.ts +78 -0
  993. package/src/chrome/runtime/port.ts +117 -0
  994. package/src/chrome/runtime/runtime.ts +317 -0
  995. package/src/chrome/storage/chrome-storage.ts +120 -0
  996. package/src/chrome/storage/index.ts +13 -0
  997. package/src/chrome/storage/storage-area.ts +318 -0
  998. package/src/chrome/storage/storage-types.ts +115 -0
  999. package/src/chrome/system/create-chrome-system.ts +32 -0
  1000. package/src/chrome/system/index.ts +21 -0
  1001. package/src/chrome/system/system-backend.ts +88 -0
  1002. package/src/chrome/system/system-cpu.ts +49 -0
  1003. package/src/chrome/system/system-display.ts +94 -0
  1004. package/src/chrome/system/system-memory.ts +24 -0
  1005. package/src/chrome/system/system-storage.ts +33 -0
  1006. package/src/chrome/system/system-types.ts +112 -0
  1007. package/src/chrome/windows/chrome-windows.ts +372 -0
  1008. package/src/chrome/windows/create-chrome-windows.ts +13 -0
  1009. package/src/chrome/windows/index.ts +7 -0
  1010. package/src/chrome/windows/window-schema.ts +32 -0
  1011. package/src/chrome/windows/window-surface.ts +27 -0
  1012. package/src/chrome/windows/window-types.ts +80 -0
  1013. package/src/chrome/windows/windows-surface.ts +114 -0
  1014. package/src/components/convert.ts +2 -1
  1015. package/src/components/hand-written/items/item-rows.svelte.ts +37 -0
  1016. package/src/components/hand-written/items/items-host.svelte.ts +2 -0
  1017. package/src/components/hand-written/items/repeater-host.svelte.ts +1 -0
  1018. package/src/components/window-context.ts +23 -0
  1019. package/src/data-transfer/clipboard.ts +15 -0
  1020. package/src/data-transfer/data-transfer.ts +29 -1
  1021. package/src/data-transfer/package-io.ts +36 -2
  1022. package/src/data-transfer/winrt-package.ts +65 -1
  1023. package/src/downloads/chrome-downloads.ts +474 -0
  1024. package/src/downloads/chrome-event.ts +42 -0
  1025. package/src/downloads/download-query.ts +204 -0
  1026. package/src/downloads/download-record.ts +177 -0
  1027. package/src/downloads/download-target.ts +79 -0
  1028. package/src/downloads/download-transfer.ts +160 -0
  1029. package/src/downloads/download-types.ts +176 -0
  1030. package/src/downloads/fetch-to-file.ts +276 -0
  1031. package/src/downloads/index.ts +22 -0
  1032. package/src/downloads/interrupt-reason.ts +64 -0
  1033. package/src/downloads/taskbar-progress.ts +4 -0
  1034. package/src/downloads/zone-identifier.ts +42 -0
  1035. package/src/enums.ts +6 -0
  1036. package/src/incremental/incremental-source.svelte.ts +181 -0
  1037. package/src/incremental/index.ts +4 -0
  1038. package/src/incremental/state.ts +33 -0
  1039. package/src/media/index.ts +1 -0
  1040. package/src/picture-source.ts +26 -0
  1041. package/src/progress/TaskbarProgress.d.svelte.ts +6 -0
  1042. package/src/progress/aggregate.ts +68 -0
  1043. package/src/progress/core.ts +13 -0
  1044. package/src/progress/index.ts +4 -0
  1045. package/src/progress/progress-event.ts +25 -0
  1046. package/src/progress/progress-operation.ts +469 -0
  1047. package/src/progress/progress-registry.ts +224 -0
  1048. package/src/progress/progress-source.ts +66 -0
  1049. package/src/progress/progress-state.ts +72 -0
  1050. package/src/progress/progress-text.ts +27 -0
  1051. package/src/progress/scoped-source.ts +56 -0
  1052. package/src/progress/taskbar-progress-props.ts +18 -0
  1053. package/src/progress/taskbar-progress.ts +80 -0
  1054. package/src/progress/track-operation.ts +81 -0
  1055. package/src/renderer/host/host.ts +12 -15
  1056. package/src/tray/TrayIcon.d.svelte.ts +14 -2
  1057. package/src/tray/TrayMenuFlyout.d.svelte.ts +6 -0
  1058. package/src/tray/balloons.ts +58 -0
  1059. package/src/tray/bounds.ts +16 -0
  1060. package/src/tray/flyout-model.ts +77 -0
  1061. package/src/tray/flyout-picker.ts +56 -0
  1062. package/src/tray/index.ts +3 -0
  1063. package/src/tray/menu/default-profile.ts +20 -0
  1064. package/src/tray/menu/define.ts +12 -0
  1065. package/src/tray/menu/describe.ts +39 -0
  1066. package/src/tray/menu/expand.ts +75 -0
  1067. package/src/tray/menu/index.ts +30 -0
  1068. package/src/tray/menu/profile-file.ts +44 -0
  1069. package/src/tray/menu/profile.ts +39 -0
  1070. package/src/tray/menu/resolve-lite.ts +226 -0
  1071. package/src/tray/menu/resolve.ts +72 -0
  1072. package/src/tray/menu/types.ts +270 -0
  1073. package/src/tray/menu/values.ts +21 -0
  1074. package/src/tray/menu-svelte/TrayMenu.d.svelte.ts +6 -0
  1075. package/src/tray/menu-svelte/TrayMenuEditor.d.svelte.ts +17 -0
  1076. package/src/tray/menu-svelte/TrayMenuHeader.d.svelte.ts +6 -0
  1077. package/src/tray/menu-svelte/TrayMenuItem.d.svelte.ts +6 -0
  1078. package/src/tray/menu-svelte/TrayMenuOperations.d.svelte.ts +6 -0
  1079. package/src/tray/menu-svelte/TrayMenuProgress.d.svelte.ts +6 -0
  1080. package/src/tray/menu-svelte/TrayMenuSeparator.d.svelte.ts +6 -0
  1081. package/src/tray/menu-svelte/TrayMenuSubmenu.d.svelte.ts +6 -0
  1082. package/src/tray/menu-svelte/collect.ts +58 -0
  1083. package/src/tray/menu-svelte/edit-profile.ts +263 -0
  1084. package/src/tray/menu-svelte/editor-labels.ts +54 -0
  1085. package/src/tray/menu-svelte/editor-props.ts +27 -0
  1086. package/src/tray/menu-svelte/index.ts +21 -0
  1087. package/src/tray/menu-svelte/menu-node.ts +119 -0
  1088. package/src/tray/menu-svelte/menu-props.ts +72 -0
  1089. package/src/tray/menu-svelte/menu-source.ts +83 -0
  1090. package/src/tray/menu-svelte/operation-ids.ts +21 -0
  1091. package/src/tray/menu-svelte/preview-lines.ts +58 -0
  1092. package/src/tray/native.ts +134 -242
  1093. package/src/tray/pointer-share.ts +71 -0
  1094. package/src/tray/standalone/define-tray.ts +36 -0
  1095. package/src/tray/standalone/index.ts +19 -6
  1096. package/src/tray/standalone/menu-theme.ts +90 -0
  1097. package/src/tray/standalone/native.ts +180 -106
  1098. package/src/tray/standalone/standalone-tray.ts +146 -66
  1099. package/src/tray/themed-icon.ts +48 -0
  1100. package/src/tray/tray-core.ts +37 -43
  1101. package/src/tray/tray-extras.ts +71 -0
  1102. package/src/tray/tray-icon-props.ts +20 -5
  1103. package/src/tray/tray-icon.ts +16 -4
  1104. package/src/tray/tray-manifest.ts +74 -0
  1105. package/src/tray/tray-menu-flyout-props.ts +17 -0
  1106. package/src/tray/tray-menu.ts +2 -2
  1107. package/src/vite/build.ts +35 -7
  1108. package/src/vite/entrypoints/build-tray.ts +92 -0
  1109. package/src/vite/entrypoints/discover.ts +75 -0
  1110. package/src/vite/entrypoints/extract-tray.ts +125 -0
  1111. package/src/vite/entrypoints/lower-menu-markup.ts +443 -0
  1112. package/src/vite/entrypoints/lower-tray-svelte.ts +329 -0
  1113. package/src/vite/entrypoints/node-span.ts +36 -0
  1114. package/src/vite/entrypoints/tray-dev-plugin.ts +111 -0
  1115. package/src/vite/entrypoints/tray-module.ts +63 -0
  1116. package/src/vite/entrypoints/tray-process.ts +83 -0
  1117. package/src/vite/entrypoints/tray-source.ts +21 -0
  1118. package/src/vite/entrypoints/tray-svelte-error.ts +31 -0
  1119. package/src/vite/externals.ts +19 -0
  1120. package/src/vite/plugin.ts +3 -14
  1121. package/src/web-apis/clipboard.ts +63 -16
  1122. package/src/web-apis/dialog-types.ts +99 -0
  1123. package/src/web-apis/dialogs-windows.ts +144 -0
  1124. package/src/web-apis/dialogs.ts +312 -0
  1125. package/src/web-apis/file-read.ts +43 -0
  1126. package/src/web-apis/file-system.ts +33 -0
  1127. package/src/web-apis/geolocation.ts +14 -8
  1128. package/src/web-apis/image-codec-windows.ts +140 -0
  1129. package/src/web-apis/image-pixels.ts +191 -0
  1130. package/src/web-apis/image-types.ts +74 -0
  1131. package/src/web-apis/images.ts +697 -0
  1132. package/src/web-apis/notification.ts +5 -4
  1133. package/src/web-apis/permissions.ts +31 -0
  1134. package/src/web-apis/png-writer.ts +66 -0
  1135. package/src/win32-calls.ts +86 -0
  1136. package/src/win32-foreground.ts +76 -0
  1137. package/src/win32-icons.ts +11 -31
  1138. package/src/window/create-window.ts +7 -0
  1139. package/src/window/foreground-filter.ts +167 -0
  1140. package/src/window/foreground-native.ts +93 -0
  1141. package/src/window/foreground.ts +106 -0
  1142. package/src/window/taskbar-calls.ts +47 -0
  1143. package/src/window/taskbar-native.ts +42 -0
  1144. package/src/window/taskbar.ts +55 -6
  1145. package/src/window/window-host.svelte.ts +3 -2
  1146. package/src/winui.ts +7 -0
  1147. package/web-types.json +422 -1
package/API.md CHANGED
@@ -18,6 +18,7 @@ monorepo needs no build step (the repository is a pnpm workspace, see
18
18
  | `winui-svelte/host` | `src/renderer/host/host.ts` | `renderer`, the renderer WinUI controls are built through (`mountControl` makes it the active one), and the mount-target plumbing below; not for app code |
19
19
  | `winui-svelte/scroll-timeline` | `src/web-apis/scroll-timeline.ts` | `installScrollTimeline()`: `ScrollTimeline`, `ViewTimeline` and `element.animate(keyframes, { timeline })` over Composition (the CSS side is `winui-svelte/css/scroll-timeline`, which a sheet that uses `animation-timeline` imports) |
20
20
  | `winui-svelte/view-transitions` | `src/web-apis/view-transitions.ts` | `installViewTransitions()`: `document.startViewTransition` and `ViewTransition` over WinUI's connected animations (the CSS side is `winui-svelte/css/view-transition`, which a sheet or style attribute that sets `view-transition-name` imports) |
21
+ | `winui-svelte/dialogs` | `src/web-apis/dialogs.ts` | `installDialogs()`, `showDialog()`, `useDialogWindow()`, `DialogResult`, `DialogButton`: `alert`, `confirm` and `prompt` over `ContentDialog`, as promises (opt-in; see Dialogs) |
21
22
  | `winui-svelte/element-animation` | `src/renderer/host/element-animation.ts` | `enableElementAnimation()`: what Svelte's `transition:`, `in:`, `out:`, `animate:` and `svelte/motion` ask of an element, on WinUI controls (the Vite plugin calls it from a component that uses them; otherwise not bundled) |
22
23
  | `winui-svelte/attached-owners` | `src/components/attached-owners.ts` | `preloadAttachedOwners(names)`: loads the modules attached properties (`canvasLeft`, `gridRow`) are written through (the Vite plugin calls it from a component whose markup or script names one, so the property is set with the control; a prop named nowhere, built from a computed key, needs `await preloadAttachedOwners(["Canvas"])` first, or its control throws) |
23
24
  | `winui-svelte/settings` | `src/settings/index.ts` | `SettingsCard`, `SettingsExpander`: Fluent settings cards after the Community Toolkit's (opt-in) |
@@ -37,20 +38,34 @@ monorepo needs no build step (the repository is a pnpm workspace, see
37
38
  | `winui-svelte/bootstrap` | `src/window/bootstrap.ts` | `initWindowsAppSdk()`; imports nothing of WinRT, safe on the host's main thread |
38
39
  | `winui-svelte/thread` | `src/window/thread.ts` | `runOnUiThread()`; imports only dynwinrt, so the apartment comes first |
39
40
  | `winui-svelte/window` | `src/window/index.ts` | `runWindow()`, `exitApplication()`, `createWindow()`, `startTimer()`, `systemSettings()`, the picker options (see App services) |
40
- | `winui-svelte/app` | `src/app/index.ts` | `ensureSingleInstance()`, `notify()`, `activateInstance()`, `activateOrLaunch()`, `launchApp()`, `relaunch()`, `restartAfterCrash()` (opt-in; see App lifecycle) |
41
+ | `winui-svelte/window/foreground` | `src/window/foreground.ts` | `trackForeground()`, `bringWindowToFront()`, `shouldRestore()` (opt-in; see Following the foreground app) |
42
+ | `winui-svelte/app` | `src/app/index.ts` | `ensureSingleInstance()`, `notify()`, `activateInstance()`, `activateOrLaunch()`, `launchApp()`, `startTray()`, `relaunch()`, `restartAfterCrash()` (opt-in; see App lifecycle) |
43
+ | `winui-svelte/app/shell` | `src/app/shell/index.ts` | `trash()`, `openWith()`, `createShortcut()`, `readShortcut()`, `registerAppPath()`, `ShellFailure` (opt-in; see Shell verbs) |
41
44
  | `winui-svelte/app/activation` | `src/app/activation/index.ts` | `installProtocolHandlers()`, `registerFileTypes()`, `launchAtLogin()`, `startActivation()`, `ActivationKind` (opt-in; see Activation) |
45
+ | `winui-svelte/app/jump-list` | `src/app/jump-list/index.ts` | `setJumpListTasks()`, `clearJumpList()` (opt-in; see Jump list tasks) |
42
46
  | `winui-svelte/data-transfer` | `src/data-transfer/index.ts` | `enableDragEvents()`, `dropzone`, `draggable`, `filePicker`, `pickFiles`, `pickSaveFile`, `clipboard`, `launchUri` / `launchFile` / `openFolder` / `revealInExplorer`, `share`, `NativeFile`, `DataTransfer`, `DragEvent` (opt-in; see Data transfer) |
47
+ | `winui-svelte/incremental` | `src/incremental/index.ts` | `createIncrementalSource()`, `IncrementalSource`, `IncrementalStatus`, `IncrementalState` (opt-in; see Incremental loading) |
48
+ | `winui-svelte/downloads` | `src/downloads/index.ts` | `Downloads` (`chrome.downloads`), `fetchToFile()`, `markOfTheWeb()`, `DownloadError` (opt-in; see Downloads) |
49
+ | `winui-svelte/chrome/runtime` | `src/chrome/runtime/index.ts` | `Runtime` (`chrome.runtime`), `Port`, `InstallReason`, the native messaging codec (opt-in; see Chrome runtime) |
50
+ | `winui-svelte/chrome/notifications` | `src/chrome/notifications/index.ts` | `ChromeNotifications` (`chrome.notifications`), `NotificationTemplateType`, `NotificationPermissionLevel` (opt-in; see Chrome notifications) |
51
+
52
+ | `winui-svelte/chrome/commands` | `src/chrome/commands/index.ts` | `ChromeCommands` (`chrome.commands`), `parseShortcut()` (opt-in; see Chrome commands) |
53
+ | `winui-svelte/chrome/action` | `src/chrome/action/index.ts` | `ChromeAction` (`chrome.action`), `createChromeAction()` (opt-in; see Chrome action) |
54
+ | `winui-svelte/chrome/i18n` | `src/chrome/i18n/index.ts` | `ChromeI18n` (`chrome.i18n`), `installLanguageDefaults()` (opt-in; see Chrome i18n) |
55
+ | `winui-svelte/chrome/install` | `src/chrome/install.ts` | `installChromeApis()`, `ChromeGlobal`, `ChromeAlarms`, `ChromeSystem` (opt-in; see Chrome global) |
43
56
  | `winui-svelte/input` | `src/input/index.ts` | `enableInputEvents()`, `setPointerCapture` / `releasePointerCapture` / `hasPointerCapture`, `activeElement()`, `moveFocus()`, `trapFocus()`, `PointerType`, `PointerEvent` / `WheelEvent` / `KeyboardEvent` / `FocusEvent` (opt-in; see Input events and focus) |
44
57
  | `winui-svelte/media` | `src/media/index.ts` | `bitmapImageOf()`, `svgImageSourceOf()`, `decodeDataUri()`, `createMediaPlayer()`, `mediaSourceOfBytes()`, `observePlayback()`, `PlaybackState` (opt-in; see Media) |
45
58
  | `winui-svelte/win2d` | `src/win2d/index.ts` | `Canvas`, the Win2D controls, the drawing helpers and Win2D classes, `applyEffect` (opt-in; see Win2D) |
46
59
  | `winui-svelte/enums` | `src/enums.ts` | every closed set a prop or option takes: WinUI's enums, `ThemeBrush`, `ColorKeyword`, `Backdrop`, `WindowTheme`, `TrayBalloonIcon` and the rest (see Closed sets) |
47
60
  | `winui-svelte/win2d/context-2d` | `src/win2d/context-2d/index.ts` | `Canvas2D`, `createCanvas2D`, `CanvasElement`, `Context2D`, `Path2D` and the rest of the HTML Canvas 2D API over Win2D (opt-in; see Canvas 2D) |
48
61
  | `winui-svelte/tray` | `src/tray/index.ts` | `TrayIcon` (with its `menu`), `createTrayIcon()`, `placeMenuWindow()`, `hideToTray()`, `restoreFromTray()`, `toggleInTray()`, `removeAllTrayIcons()`, `TrayGesture` (opt-in; see System tray) |
49
- | `winui-svelte/tray/standalone` | `src/tray/standalone/index.ts` | `createStandaloneTray()`, `NativeMenuEntryKind`, and the `winui-svelte/app` calls that start or signal the app: a tray with no window, no WinUI and no components (opt-in; see Tray with no window) |
62
+ | `winui-svelte/progress/core` | `src/progress/core.ts` | `ProgressRegistry`, `defaultProgressRegistry()`, `ProgressOperation`, `trackOperation()`, `progressText()` and the types, with no Svelte component and no taskbar code, for a process with no window (opt-in; see Progress) |
63
+ | `winui-svelte/tray/standalone` | `src/tray/standalone/index.ts` | `createStandaloneTray()`, `defineTray()`, its opt-in parts `balloons`, `bounds` and `themedIcon`, `MenuItemKind`, `MenuLevel`, and the `winui-svelte/app` calls that start or signal the app: a tray with no window, no WinUI and no components (opt-in; see Tray with no window) |
50
64
  | `winui-svelte/notice` | `src/notice/index.ts` | `showNotice()`, `NoticeIcon`, `NoticeButtons`, `NoticeButton`: a message box with no window or app (opt-in; see Notice with no app) |
51
65
  | `winui-svelte/forms` | `src/forms/index.ts` | `Form`, `FormField`, `textField`, `numberField`, `selectField` and the other field attachments, `formButton`, `FormValues`, `validityOf` (opt-in; see Forms) |
52
66
  | `winui-svelte/store` | `src/store/index.ts` | `getAppLicense`, `watchLicense`, `checkForUpdates`, `watchPackages`, `getStartupTask`, `getPackageInfo`: the Store and package APIs, answering `hasPackage: false` outside a package (opt-in) |
53
67
  | `winui-svelte/accessibility`, `/accessibility/audit` | `src/accessibility/index.ts`, `src/accessibility/audit/index.ts` | `announce`, `liveRegion`, `LivePriority`; `auditAccessibility`, `accessibilityRules` (opt-in; see Accessibility) |
68
+ | `winui-svelte/automation` | `src/automation/index.ts` | `withUiaClient`, `createUiaWorker`, `readWindowText`, `UiaControlType`: a UI Automation client that reads the text of another window (opt-in; see UI Automation client) |
54
69
  | `winui-svelte/devices` | `src/devices/index.ts` | device enumeration, input devices, Bluetooth, printers, power, network, display, audio, gamepads and sensors, each also at `winui-svelte/devices/<area>` (opt-in; see Windows devices) |
55
70
 
56
71
  The table is the source layout: `exports` point at `.ts` files so the monorepo
@@ -740,11 +755,13 @@ type WindowOptions<Props> = {
740
755
  size?: { width: number; height: number }; // device pixels
741
756
  backdrop?: Backdrop; // "acrylic" | "acrylicBase" | "acrylicThin" | "mica" | "micaAlt" | "none" | "transparent"
742
757
  extendsIntoTitleBar?: boolean;
758
+ onclosing?: () => boolean | void; // AppWindow.Closing: return true to keep the window open
743
759
  isBackground?: boolean; // shown without activating (tests, captures)
744
760
  } & ({ component: Component<Props>; props: Props } | { control: FrameworkElement });
745
761
 
746
762
  interface AppWindow<Props> {
747
763
  readonly window: Window;
764
+ readonly handle: WindowHandle; // what chromeWindowSurface and the rest of the window API take
748
765
  readonly mounted: Mounted<Props> | null; // null for a control
749
766
  close(): void;
750
767
  onClosed(listener: () => void): void;
@@ -1354,7 +1371,7 @@ const vertical: Orientation = 1;
1354
1371
  | A path geometry (`GeometryInput`, on `PathIcon` and `Path`) | Path Markup Syntax text or a `Geometry` | `data="M0,0 L10,10"` |
1355
1372
  | A font family (`FontFamilyInput`) | a family name or a `FontFamily` | `"Segoe UI Variable"` |
1356
1373
  | A grid length (`GridLengthInput`) | pixels, or `GridLengthText` as XAML writes it | `"Auto"`, `"2*"`, `"120"` |
1357
- | The package's own | `Backdrop`, `WindowTheme`, `TitleBarHeight`, `WindowPresentation`, `PickerLocation`, `NavigationCacheMode`, `NavigationMode`, `MoveDirection`, `XamlKind`, `FocusKind`, `TrayGesture`, `TrayBalloonIcon`, `ConnectedAnimationKind` | `backdrop={Backdrop.mica}` |
1374
+ | The package's own | `Backdrop`, `WindowTheme`, `TitleBarHeight`, `WindowPresentation`, `PickerLocation`, `NavigationCacheMode`, `NavigationMode`, `MoveDirection`, `XamlKind`, `FocusKind`, `TrayGesture`, `TrayBalloonIcon`, `ConnectedAnimationKind`, `DialogResult`, `DialogButton` | `backdrop={Backdrop.mica}` |
1358
1375
 
1359
1376
  A WinUI enum's members keep WinUI's names and case (`"Minimal"`, not
1360
1377
  `"minimal"`), as the metadata and the docs have them; the package's own sets
@@ -2558,9 +2575,13 @@ An opt-in subpath: an app that does not import it does not bundle it
2558
2575
  redirects to it
2559
2576
  An app whose windows run in a worker thread passes `entryScript`, the script
2560
2577
  that starts the process, because `process.argv[1]` there is the worker's
2578
+ A single executable application (a Node `node:sea` build, where
2579
+ `process.execPath` is the app's own exe) is relaunched as the exe and
2580
+ `arguments`, with no script and no Node flags
2561
2581
  - `restartAfterCrash({ arguments, conditions })` is
2562
2582
  `RegisterApplicationRestart`: Windows starts the same Node and entry
2563
- script with `arguments` after a crash, a hang, an update that closes the
2583
+ script (a single executable: its own exe) with `arguments` after a crash,
2584
+ a hang, an update that closes the
2564
2585
  app or a reboot for one; `conditions` is a subset of `RestartCondition`
2565
2586
  (`crash`, `hang`, `update`, `reboot`; all by default)
2566
2587
  Limits: no callback (a crashed Node cannot run code, so
@@ -2618,10 +2639,13 @@ if (!single.isPrimary) {
2618
2639
  - `ActivationEvent` is a union on `kind` (`ActivationKind`, also from
2619
2640
  `winui-svelte/enums`): `launch` (started by hand), `file` (`files`, absolute
2620
2641
  paths of existing files), `protocol` (`uri`, `scheme`), `startup` (started
2621
- at sign-in) and `redirect` (a later copy with nothing to open)
2642
+ at sign-in), `redirect` (a later copy with nothing to open) and `jumpList`
2643
+ (`taskId`, a task of the jump list was chosen; see Jump list tasks) and
2644
+ `alarm` (`alarm`, an alarm of `winui-svelte/app/schedule` went off; it also
2645
+ reaches `onAlarm`)
2622
2646
  Every event has `isRedirect`, `arguments` and `workingDirectory`; a link
2623
2647
  sent by a later copy is `protocol` with `isRedirect: true`
2624
- - A link wins over files, files win over the startup marker; an argument
2648
+ - An alarm wins over a jump list task, a jump list task wins over a link, a link wins over files, files win over the startup marker; an argument
2625
2649
  that fits none stays in `arguments`
2626
2650
  Arguments are checked with a schema (up to 1024 of them, up to 32767
2627
2651
  characters each, no NUL); a failure goes to `onError`, the rest go on
@@ -2661,6 +2685,190 @@ if (!single.isPrimary) {
2661
2685
  `test/activation.test.ts` starts real second copies with a link, a file and
2662
2686
  nothing, and checks the first hears each as one event
2663
2687
 
2688
+ ### Jump list tasks (`winui-svelte/app/jump-list`)
2689
+
2690
+ Entries in the Tasks section of the taskbar button's right-click menu
2691
+ (`ICustomDestinationList`, `IObjectCollection` and `IShellLink`)
2692
+ No package identity is needed; an opt-in subpath
2693
+ Thumbnail toolbar buttons cannot be built from Node (their click is a sent
2694
+ message that no hook receives), so a task is the way to put a command there
2695
+
2696
+ ```ts
2697
+ import { startActivation } from "winui-svelte/app/activation";
2698
+ import { setJumpListTasks } from "winui-svelte/app/jump-list";
2699
+
2700
+ const list = setJumpListTasks({
2701
+ tasks: [
2702
+ { id: "new-note", title: "New note", arguments: ["--new"] },
2703
+ { id: "inbox", title: "Open inbox", arguments: ["--inbox"], icon: "inbox.ico" },
2704
+ ],
2705
+ });
2706
+
2707
+ startActivation({
2708
+ key: "com.example.notes",
2709
+ window: mainWindow,
2710
+ onActivation(event) {
2711
+ const task = list.taskOf(event);
2712
+ if (task?.id === "new-note") newNote();
2713
+ },
2714
+ });
2715
+ ```
2716
+
2717
+ - `setJumpListTasks({ tasks, appUserModelId, command })` replaces the Tasks
2718
+ of the list and returns `{ tasks, taskOf(event) }`; `tasks` is a `const`
2719
+ generic, so `task.id` is the union of your ids
2720
+ - `clearJumpList({ appUserModelId })` deletes the whole list
2721
+ - A `JumpListTask` is `{ id, title, arguments, description, icon, iconIndex,
2722
+ workingDirectory }`; `id` is letters, digits, `_`, `.` and `-`, 64 at most,
2723
+ and unique; `icon` is a file path (`PictureSource`, but a `data:`, `http(s)`
2724
+ or `ms-appx` URI is a `TypeError`): an .ico, or an .exe or .dll with
2725
+ `iconIndex`
2726
+ - A click starts `command` (this process's Node and entry script by default,
2727
+ as `registerFileTypes` does; a bundled executable passes its own) with the
2728
+ marker `--winui-svelte-jump-list=<id>` and then the task's `arguments`,
2729
+ quoted for `CommandLineToArgvW`
2730
+ `startActivation` hands that to the running copy through the single
2731
+ instance redirect as a `jumpList` event: `taskId` is the id and `arguments`
2732
+ are the task's own; a first start gets the same event with `isRedirect:
2733
+ false`
2734
+ - The list belongs to the process's AppUserModelID and Windows shows nothing,
2735
+ without an error, when a window has another; so the call throws when the
2736
+ process has none (give `<Window>` an `appUserModelId`, or call
2737
+ `joinAppUserModel`) or when `appUserModelId` differs from it
2738
+ - Keep the tasks static, as Microsoft advises: set them once at start
2739
+ - Call it on a thread with COM (the UI thread of a window has it)
2740
+ - `src/app/jump-list/native.test.ts` commits a list under a unique
2741
+ AppUserModelID in the test process, checks that Windows wrote its
2742
+ custom destinations file, and deletes the list, even when it fails
2743
+
2744
+ ### Shell verbs (`winui-svelte/app/shell`)
2745
+
2746
+ What Explorer's context menu does, from code
2747
+ There is no web API for these; the names follow the launcher helpers of
2748
+ `winui-svelte/data-transfer`, which stay the home of `launchUri`,
2749
+ `launchFile`, `openFolder` and `revealInExplorer`
2750
+ An opt-in subpath: an app that does not import it does not bundle it
2751
+
2752
+ ```ts
2753
+ import { createShortcut, openWith, readShortcut, registerAppPath, trash } from "winui-svelte/app/shell";
2754
+
2755
+ const result = trash({ paths: ["C:\\Users\\me\\old.txt"] });
2756
+ if (!result.ok) console.warn(result.reason, result.message);
2757
+
2758
+ createShortcut({
2759
+ path: "C:\\Users\\me\\Desktop\\Notes.lnk",
2760
+ target: "C:\\Apps\\notes.exe",
2761
+ arguments: ["--open", "my notes.txt"],
2762
+ workingDirectory: "C:\\Apps",
2763
+ icon: { path: "C:\\Apps\\notes.exe", index: 0 },
2764
+ description: "Open my notes",
2765
+ });
2766
+ const link = readShortcut({ path: "C:\\Users\\me\\Desktop\\Notes.lnk" });
2767
+ await openWith({ path: "C:\\Users\\me\\photo.png" });
2768
+ registerAppPath({ name: "notes", program: "C:\\Apps\\notes.exe" });
2769
+ ```
2770
+
2771
+ - Every verb returns `{ ok: true }` or `{ ok: false, reason, message }`;
2772
+ `reason` is a `ShellFailure` (`invalid`, `not-found`, `exists`,
2773
+ `owned-by-another`, `aborted`, `failed`)
2774
+ - These act on the user's own files; they check and then act, and none
2775
+ asks the user first
2776
+ - Paths are data: each must be a full path with no control character and not a
2777
+ device path; none is built into a command line
2778
+ - `trash` sends to the Recycle Bin (`SHFileOperationW` with
2779
+ `FOF_ALLOWUNDO`) and never deletes for good; when Windows would have to
2780
+ (a drive without a bin, a file too big for it) it asks, and nothing goes
2781
+ unless the user agrees; all the paths are checked before any is touched
2782
+ - `openWith` shows the Windows "Open with" list for a file
2783
+ (`LauncherOptions.DisplayApplicationPicker`), so it takes a file and never a
2784
+ program; it opens a dialog and is only unit-tested with a fake
2785
+ - `createShortcut` writes only the `.lnk` file (`IShellLink` and
2786
+ `IPersistFile`); each argument is quoted by the same rule as the
2787
+ activation registrations, and an existing file is kept unless
2788
+ `shouldOverwrite` is set; the target is not required to exist
2789
+ - `readShortcut` gives the target as stored, without searching for a moved
2790
+ one and without running anything
2791
+ - `registerAppPath` writes a key under `HKEY_CURRENT_USER` (App Paths) with a
2792
+ marker value, only when the key is free or the package made it;
2793
+ `unregisterAppPath` removes only a key with the marker; the name is an
2794
+ identifier that is not a name Windows or a common tool answers to, and the
2795
+ program is a full path ending in `.exe`; the machine-wide hive is out of reach
2796
+ - A shortcut that carries an AUMID (for toast identity) is not offered yet
2797
+ - `src/app/shell/native.test.ts` recycles a file, writes and reads a
2798
+ shortcut in a folder it creates under the temp directory and removes, and
2799
+ registers and removes an App Paths alias with a unique name
2800
+
2801
+ ### Alarms (`winui-svelte/app/schedule`)
2802
+
2803
+ Starts the app at a time, once or on a repeat, through Task Scheduler, and
2804
+ tells it which alarm went off
2805
+ The shape is `chrome.alarms` (`create`, `get`, `getAll`, `clear`, `clearAll`,
2806
+ `onAlarm`, the `Alarm` type) with promises instead of callbacks, and
2807
+ `chrome.runtime.onStartup` for the start at sign-in
2808
+ An opt-in subpath: an app that does not import it does not bundle it
2809
+
2810
+ ```ts
2811
+ import { ActivationKind, startActivation } from "winui-svelte/app/activation";
2812
+ import * as alarms from "winui-svelte/app/schedule";
2813
+
2814
+ alarms.onAlarm.addListener(alarm => sync(alarm.name));
2815
+ alarms.onStartup.addListener(() => restoreSession());
2816
+ startActivation({ key: "my-app", onActivation: () => {} });
2817
+
2818
+ await alarms.create("nightly-sync", { when: Date.now() + 3_600_000, periodInMinutes: 1440 });
2819
+ await alarms.get("nightly-sync"); // { name, scheduledTime, periodInMinutes: 1440 }
2820
+ await alarms.getAll(); // every alarm this package made
2821
+ await alarms.clear("nightly-sync"); // true
2822
+ await alarms.clearAll(); // false
2823
+ ```
2824
+
2825
+ - `create(name, { when, delayInMinutes, periodInMinutes })` is Chrome's:
2826
+ `when` is milliseconds since 1970, `delayInMinutes` counts from now, and
2827
+ with only `periodInMinutes` the first run is one period away; `when` and
2828
+ `delayInMinutes` together, or none of the three, throw; creating a name again
2829
+ replaces its alarm
2830
+ - `name` is letters, digits, `.`, `_` and `-` (a task name, not free text)
2831
+ - Chrome's one-minute minimum for `delayInMinutes` is not applied: a delay
2832
+ can be seconds, and a time in the past runs at once
2833
+ - `periodInMinutes` is 1 to 44640 (Task Scheduler cannot repeat faster than
2834
+ a minute, nor slower than 31 days)
2835
+ - Extras, optional members of the same object: `arguments` (reach the
2836
+ started copy after the entry script), `runWhenOnBattery` (true by
2837
+ default), `command` (a bundled executable instead of Node) and `backend`
2838
+ (a test)
2839
+ - `get`, `getAll`, `clear` and `clearAll` read and remove only the tasks in the
2840
+ `winui-svelte` folder of Task Scheduler, so a task of another program can
2841
+ neither be listed nor removed from here; `scheduledTime` is the next run
2842
+ - `onAlarm` and `onStartup` have `addListener`, `removeListener` and
2843
+ `hasListener`; they are called by `startActivation`, so call it for the
2844
+ alarms to arrive
2845
+ - A task runs the app again with a marker argument, which becomes an `alarm`
2846
+ activation (`event.alarm`) and also reaches `onAlarm`; if the app is open,
2847
+ the new copy hands the activation to it and exits, so the listener of the
2848
+ running app hears it, and if it is closed, the started copy hears it
2849
+ - `onStartup` is called for a `startup` activation, that is when Windows
2850
+ starts the app at sign-in; turning that start on or off is `launchAtLogin`
2851
+ of `winui-svelte/app/activation` (the Run key listed in Settings, Apps,
2852
+ Startup), which this module does not repeat
2853
+ - How it works: the package writes a Task Scheduler 1.2 XML definition to a
2854
+ private temporary file and runs `schtasks.exe /Create /XML` (found by
2855
+ `SystemRoot`), so no COM is involved; the task runs as the signed-in user
2856
+ with normal rights (no administrator), with no time limit, and a start
2857
+ missed while the PC was off is made up when it is next on; the alarm's first
2858
+ time and period are kept in the task's description, which is how `get`
2859
+ reads them back
2860
+ - A one-shot alarm's task deletes itself a day after its time
2861
+ - Limits:
2862
+ - The task runs only while the user is signed in
2863
+ - `schtasks` is the only gate: Group Policy can forbid task creation, and
2864
+ then `create` rejects with its message
2865
+ - Moving or reinstalling the app leaves a task that points at the old path
2866
+ until the alarm is created again
2867
+ - `src/app/schedule/schedule.test.ts` checks the generated XML, the quoting
2868
+ and escaping of arguments, the marker argument and the activation it
2869
+ becomes, and an alarm's round trip to a task and back over a fake backend; no
2870
+ real task is made
2871
+
2664
2872
  ### Global hotkeys (`winui-svelte/app/hotkeys`)
2665
2873
 
2666
2874
  A system-wide key combination, heard whichever app has the focus
@@ -2726,6 +2934,65 @@ const hotkey = registerHotkey({
2726
2934
  posts `WM_HOTKEY` to the thread itself with `PostThreadMessageW`; no key is
2727
2935
  pressed
2728
2936
 
2937
+ ### Following the foreground app (`winui-svelte/window/foreground`)
2938
+
2939
+ Opt-in; nothing runs at import
2940
+
2941
+ ```ts
2942
+ import {
2943
+ bringWindowToFront,
2944
+ shouldRestore,
2945
+ trackForeground
2946
+ } from "winui-svelte/window/foreground";
2947
+
2948
+ const tracker = trackForeground({
2949
+ ownWindows: () => [pillHwnd],
2950
+ onChanged: ({ hwnd, isRealApp }) => {}
2951
+ });
2952
+ tracker.lastRealApp; // bigint | null, the last real app that was in front
2953
+ tracker.current; // bigint | null
2954
+ tracker.stop(); // idempotent
2955
+
2956
+ const isBack = shouldRestore({
2957
+ lastRealApp: tracker.lastRealApp,
2958
+ foreground: tracker.foreground
2959
+ });
2960
+ if (isBack && tracker.lastRealApp !== null) {
2961
+ bringWindowToFront(tracker.lastRealApp); // true when Windows took it
2962
+ }
2963
+ ```
2964
+
2965
+ - `trackForeground({ onChanged, ownWindows, ignoredClasses, tracking,
2966
+ intervalMilliseconds })` runs on the UI thread of a `runWindow` app
2967
+ - `tracking: "events"` (default, `ForegroundTracking.events`): the shell posts
2968
+ a message to a hidden window of the app on each change
2969
+ (`RegisterShellHookWindow` and `SHELLHOOK`), the message pump reads it, and
2970
+ `GetForegroundWindow` is read once; an idle foreground costs nothing
2971
+ dynwinrt delivers no native callbacks, so `SetWinEventHook` cannot be used
2972
+ If Windows refuses the registration, use `tracking: "polling"`
2973
+ - `tracking: "polling"`: one `GetForegroundWindow` per `intervalMilliseconds`
2974
+ (100 by default, 16 at least); latency is one tick
2975
+ The class and the process of a window are read once, when it is first seen
2976
+ - The filter: a real app is not the desktop, not a shell class
2977
+ (`ForegroundShellClass`: `Progman`, `WorkerW`, `Shell_TrayWnd`,
2978
+ `Shell_SecondaryTrayWnd`, `CopilotKeyPressFocusFrame`), not a window of
2979
+ this process, and not in `ownWindows()` or `ignoredClasses`
2980
+ `lastRealApp` changes only on a real app
2981
+ - `bringWindowToFront(hwnd)` joins this thread to the foreground thread's
2982
+ input for `BringWindowToTop` and `SetForegroundWindow`, then detaches,
2983
+ because a hotkey's key releases went to the app in front and Windows'
2984
+ foreground lock refuses a plain call; it restores a minimized window first,
2985
+ sends no input and returns whether the window ended in front
2986
+ It is best effort: a foreground window of a higher integrity level or a hung
2987
+ one still refuses; the tray menu window takes the foreground through it
2988
+ - Not measured yet: the idle cost of each mode (the tray's 30 Hz timer costs
2989
+ about 2 percent of a core in an idle window)
2990
+
2991
+ Manual checklist: press the app's hotkey from Notepad, then from the desktop,
2992
+ then from a browser on a second monitor; each time the key goes back to where
2993
+ it was; then Alt+Tab to another app while the overlay is up and confirm it is
2994
+ not pulled back
2995
+
2729
2996
  ### System tray (`winui-svelte/tray`)
2730
2997
 
2731
2998
  WinUI and the Windows App SDK have no notification-area API (apps call
@@ -2847,6 +3114,239 @@ window's content
2847
3114
  A Tauri or Electron host that already has a tray should keep it: two icons
2848
3115
  would show, and this one lives and dies with the WinUI window's process
2849
3116
 
3117
+ ### One tray menu for every renderer (`winui-svelte/tray/menu`)
3118
+
3119
+ A pure model of a tray menu: no WinUI, no Win32, so it runs under
3120
+ `node --test` and in a tray-only bundle
3121
+ You declare items once; the user picks how much of the menu to see, from the
3122
+ simple menu of a dictation app to the long one of a screenshot tool, and then
3123
+ hides, shows and reorders single items; a renderer draws what `resolveMenu`
3124
+ returns
3125
+ An opt-in subpath: an app that does not import it does not bundle it
3126
+
3127
+ ```ts
3128
+ import { defineMenu, MenuItemKind, MenuLevel, resolveMenu } from "winui-svelte/tray/menu";
3129
+
3130
+ // The simple style: three commands and a separator, no levels set
3131
+ const simple = defineMenu([
3132
+ { kind: MenuItemKind.COMMAND, id: "toggle", label: "Start dictation" },
3133
+ { kind: MenuItemKind.COMMAND, id: "settings", label: "Settings" },
3134
+ { kind: MenuItemKind.SEPARATOR, id: "line" },
3135
+ { kind: MenuItemKind.COMMAND, id: "quit", label: "Quit", isRequired: true }
3136
+ ]);
3137
+
3138
+ // The complex style: the same model with levels
3139
+ const complex = defineMenu([
3140
+ { kind: MenuItemKind.HEADER, id: "capture-header", label: "Capture" },
3141
+ {
3142
+ kind: MenuItemKind.SUBMENU,
3143
+ id: "capture",
3144
+ label: "Capture",
3145
+ items: [
3146
+ { kind: MenuItemKind.COMMAND, id: "region", label: "Region", shortcut: "Ctrl+Shift+4" },
3147
+ { kind: MenuItemKind.COMMAND, id: "scroll", label: "Scrolling", level: MenuLevel.FULL }
3148
+ ]
3149
+ },
3150
+ {
3151
+ kind: MenuItemKind.SUBMENU,
3152
+ id: "recent",
3153
+ label: "Recent uploads",
3154
+ level: MenuLevel.STANDARD,
3155
+ emptyLabel: "Nothing uploaded yet",
3156
+ maxItems: 10,
3157
+ items: () => recentUploads().map(({ name }) => ({ kind: MenuItemKind.COMMAND, id: `recent-${name}`, label: name }))
3158
+ },
3159
+ {
3160
+ kind: MenuItemKind.CHECK,
3161
+ id: "autostart",
3162
+ label: "Start with Windows",
3163
+ level: MenuLevel.STANDARD,
3164
+ isChecked: () => isAutostart(),
3165
+ staysOpen: true
3166
+ },
3167
+ { kind: MenuItemKind.COMMAND, id: "quit", label: "Quit", isRequired: true }
3168
+ ]);
3169
+
3170
+ // Call it each time the menu opens: functions are read now
3171
+ const lines = resolveMenu({
3172
+ items: complex,
3173
+ profile: { level: MenuLevel.STANDARD, hidden: ["region"], shown: [], order: {} }
3174
+ });
3175
+ ```
3176
+
3177
+ - `MenuItem` is a union on `kind`: `command`, `check`, `radio`, `submenu`,
3178
+ `separator` and `header` (`MenuItemKind`); a field belongs to the kinds that
3179
+ have it, so a command with `isChecked` or a radio with no `group` fails to
3180
+ compile
3181
+ - Every item has a unique, stable `id`; the profile of the user is keyed by it
3182
+ `defineMenu` keeps the ids as literal types, and `MenuProfile` typed with
3183
+ `MenuIds` of the menu (and the `profile` of `resolveMenu`) rejects an id
3184
+ that is not in the menu
3185
+ - `level` is the lowest detail level that shows the item (`MenuLevel`:
3186
+ `simple`, `standard`, `full`; `simple` when left out); `isRequired` cannot
3187
+ be hidden by the user
3188
+ - `label`, `isEnabled`, `isVisible`, `isChecked`, `isBold` and `badge` may be
3189
+ a value or a function, read each time `resolveMenu` runs
3190
+ - `items` of a submenu may be a function that makes the children each time;
3191
+ `sort` and `maxItems` order and cap such a list, and `emptyLabel` shows a
3192
+ disabled line when it is empty instead of dropping the submenu
3193
+ - `staysOpen` keeps the menu open after the pick (the renderer then refreshes
3194
+ labels and ticks only); `closeThenRun` (true unless set to false) runs
3195
+ `onselect` after the menu has closed, so that a dialog can open
3196
+ - A submenu may have its own `onselect` and `autoExpand`
3197
+ - `icon` is a path, a glyph or `IconPixels`; `shortcut` is display text only,
3198
+ the menu does not bind the key
3199
+ - `MenuProfile` is plain JSON: `level`, `hidden` (ids the level shows that
3200
+ the user hid), `shown` (ids above the level that the user turned on) and
3201
+ `order` (child ids in the user order, keyed by parent id, `""` for the root)
3202
+ - `resolveMenu({ items, profile })` returns `ResolvedMenuItem[]`: final text,
3203
+ booleans and a `select()` per line, with separators collapsed, headers with
3204
+ nothing under them dropped and empty submenus dropped; it throws
3205
+ `MenuModelError` for a repeated id or a radio with no group
3206
+ - `describeMenu({ items })` lists every item with its id, kind, label, level,
3207
+ parent id and `isRequired`, for an editor
3208
+ - `defaultProfile({ level })`, `parseProfile({ value })` and `profileSchema`
3209
+ (a field that is wrong falls back to its default, nothing throws),
3210
+ `loadProfile({ file })` and `saveProfile({ file, profile })` (the file is
3211
+ replaced atomically)
3212
+ - Not in the model: the actions of the icon itself (left, double and middle
3213
+ click) stay on the tray icon options
3214
+
3215
+ ### The tray menu in a window (`winui-svelte/tray/menu/svelte`)
3216
+
3217
+ The model of `winui-svelte/tray/menu` drawn by `<TrayIcon>` as a WinUI
3218
+ `MenuFlyout`, from an array or from markup
3219
+ An opt-in subpath; a consumer that imports only `winui-svelte/tray/menu`
3220
+ bundles no Svelte and no component
3221
+
3222
+ ```svelte
3223
+ <script lang="ts">
3224
+ import { MenuLevel } from "winui-svelte/enums";
3225
+ import { TrayIcon } from "winui-svelte/tray";
3226
+ import { TrayMenu, TrayMenuItem, TrayMenuSeparator, TrayMenuSubmenu } from "winui-svelte/tray/menu/svelte";
3227
+
3228
+ let isAutostart = $state(false);
3229
+ let recent = $state(["a.png", "b.png"]);
3230
+ </script>
3231
+
3232
+ <TrayIcon icon="app.ico" tooltip="My app">
3233
+ <TrayMenu profile={savedProfile}>
3234
+ <TrayMenuItem id="open" label="Open" onselect={showWindow} />
3235
+ <TrayMenuItem id="autostart" kind="check" label="Start with Windows"
3236
+ isChecked={isAutostart} level={MenuLevel.STANDARD} staysOpen
3237
+ onselect={() => (isAutostart = !isAutostart)} />
3238
+ <TrayMenuSubmenu id="recent" label="Recent" emptyLabel="Nothing yet">
3239
+ {#each recent as name (name)}
3240
+ <TrayMenuItem id={`recent.${name}`} label={name} />
3241
+ {/each}
3242
+ </TrayMenuSubmenu>
3243
+ <TrayMenuSeparator id="line" />
3244
+ <TrayMenuItem id="quit" label="Quit" isRequired onselect={quit} />
3245
+ </TrayMenu>
3246
+ </TrayIcon>
3247
+ ```
3248
+
3249
+ - `<TrayIcon menu={items} profile={profile}>` takes the array of
3250
+ `defineMenu` instead of markup, or the `menu` snippet of a hand-written
3251
+ flyout as before; the three never mix
3252
+ The ids of the array stay literal, so `profile` rejects an id the menu does
3253
+ not have
3254
+ - `<TrayMenu>` and its children are inert elements: they draw nothing, the
3255
+ tray walks the tree each time the menu opens, so order, nesting, `{#if}`,
3256
+ keyed `{#each}` and reactive props all work, with no second renderer
3257
+ - The props are the fields of the model's own items (`TrayMenuItem` takes a
3258
+ `kind` of `command`, `check` or `radio`; a tick on a command or a radio with
3259
+ no `group` fails `svelte-check`), and an unknown attribute fails too
3260
+ - Markup cannot carry a literal union, so ids written in markup are plain
3261
+ `string`; the exported `collectMenu` reads a `TrayMenu` element into the same
3262
+ `MenuItem[]`
3263
+ - A `TrayMenu` has a `profile` of its own, used for its lines
3264
+ `profile` on `TrayIcon` applies to `menu={items}`
3265
+ - The flyout is built from `resolveMenu` each time the menu opens: a command is
3266
+ a `MenuFlyoutItem`, a check a `ToggleMenuFlyoutItem`, a radio a
3267
+ `RadioMenuFlyoutItem` (its `group` is the `GroupName`), a submenu a
3268
+ `MenuFlyoutSubItem`, a header a disabled bold item
3269
+ `isBold` is the font weight; `icon` is drawn as a glyph (`FontIcon`) or, for
3270
+ a path to an `.ico` or `.png`, an `ImageIcon`; `IconPixels` is not drawn
3271
+ A flyout has one trailing column, the keyboard accelerator's, so it shows
3272
+ the `badge` and then the `shortcut` as text
3273
+ - `onselect` runs after the flyout has closed, on the next turn
3274
+ (`closeThenRun`, true unless set to false)
3275
+ - `staysOpen`: WinUI closes a flyout when an item is invoked, and offers no
3276
+ property to keep it open, so the item runs after the close and the flyout is
3277
+ built again from the model, at the same point, with the new labels and ticks
3278
+ The menu blinks once; every other pick closes the menu
3279
+ - `TrayMenuFlyout` (from `winui-svelte/tray`) is that flyout on its own: put
3280
+ it in a `menu` snippet with `resolve={() => resolveMenu({ items })}` and
3281
+ `onclose={close}`; `onflyout` hands over the native `MenuFlyout` to read
3282
+ - Not drawn by WinUI: a submenu row's own `onselect` (a `MenuFlyoutSubItem` has
3283
+ no click) and `autoExpand` (it has no member to open it from code)
3284
+
3285
+ ### Letting the user customize the tray menu (`winui-svelte/tray/menu/svelte`)
3286
+
3287
+ `<TrayMenuEditor>` is the settings control for a tray menu: the user picks how
3288
+ much of it shows, from three lines to a ShareX-like menu "and everything in
3289
+ between"
3290
+ It edits a `MenuProfile` and says so; it never reads or writes a file
3291
+
3292
+ The three levels are the `level` of each item (`simple` when left out):
3293
+
3294
+ | Level | The user gets | Shown items |
3295
+ |---|---|---|
3296
+ | Simple | The few lines every user needs | Items of level `simple` |
3297
+ | Standard | The usual set | `simple` and `standard` |
3298
+ | Full | Everything the app can do | All |
3299
+
3300
+ ```svelte
3301
+ <script lang="ts">
3302
+ import { TrayIcon } from "winui-svelte/tray";
3303
+ import { loadProfile, saveProfile } from "winui-svelte/tray/menu";
3304
+ import { TrayMenuEditor } from "winui-svelte/tray/menu/svelte";
3305
+ import { items } from "./menu.ts";
3306
+
3307
+ const FILE = "tray-menu.json";
3308
+ let profile = $state(loadProfile({ file: FILE }));
3309
+ </script>
3310
+
3311
+ <TrayMenuEditor {items} isPreviewShown bind:profile
3312
+ onchange={next => saveProfile({ file: FILE, profile: next })} />
3313
+
3314
+ <TrayIcon icon="app.ico" menu={items} {profile} />
3315
+ ```
3316
+
3317
+ | Prop | Meaning |
3318
+ |---|---|
3319
+ | `items` | The menu `defineMenu` declares; the ids stay literal |
3320
+ | `profile` | The user's choice, bindable; the default profile when left out |
3321
+ | `onchange(profile)` | Runs with the new profile after every edit; save it here |
3322
+ | `onsave(profile)` | Adds a Save button that runs this, for an app that saves on request |
3323
+ | `labels` | The strings of the editor, each optional and English by default (`DEFAULT_EDITOR_LABELS`); `{name}` stands for an item's label |
3324
+ | `isPreviewShown` | Lists the menu as it resolves under the profile, as plain rows |
3325
+
3326
+ - The detail level is three radio buttons: Simple, Standard, Full
3327
+ Changing it keeps the user's tweaks: an item the user hid stays hidden at
3328
+ every level, and one the user turned on above the level stays on
3329
+ The word "Custom" appears beside the level while the profile has any tweak
3330
+ (a hidden or shown item, or a menu in another order); the level alone is not
3331
+ a tweak
3332
+ - Below it is a tree of every item (`describeMenu`), submenus with their
3333
+ children indented
3334
+ Each row has a check for "shown" (what the level, `hidden` and `shown` make
3335
+ of it), the lowest level that includes the item as text, and Up and Down
3336
+ buttons that move it within its own menu (the whole tree is reachable with
3337
+ Tab, Space and Enter, and no operation needs a drag)
3338
+ - An item with `isRequired` is locked on and says "Always shown"
3339
+ - "Reset to default" returns to `defaultProfile()` and is disabled while the
3340
+ profile already is that
3341
+ - Every control has an `automationName`, the title and sections are headings,
3342
+ and no state is told by color alone
3343
+ - The functions behind it are pure and tested without a window:
3344
+ `src/tray/menu-svelte/edit-profile.ts` (`setLevel`, `setItemShown`,
3345
+ `moveItem`, `editorRows`, `hasTweaks`)
3346
+ - `examples/tray-menu-editor` puts the editor beside the tray icon it edits, on
3347
+ a ShareX-like menu with Capture, Upload and Tools submenus, a dynamic recent
3348
+ list, a check item and a required Exit; its simple level is a three-line menu
3349
+
2850
3350
  ### Tray with no window (`winui-svelte/tray/standalone`)
2851
3351
 
2852
3352
  A tray that runs in a process of its own, plain Node, with no `Window`, no
@@ -2861,7 +3361,7 @@ for the menu and its timers run on the dispatcher queue
2861
3361
  import {
2862
3362
  activateOrLaunch,
2863
3363
  createStandaloneTray,
2864
- NativeMenuEntryKind
3364
+ MenuItemKind
2865
3365
  } from "winui-svelte/tray/standalone";
2866
3366
 
2867
3367
  function openPanel() {
@@ -2877,26 +3377,77 @@ createStandaloneTray({
2877
3377
  tooltip: "Panel",
2878
3378
  onclick: openPanel,
2879
3379
  menu: [
2880
- { kind: NativeMenuEntryKind.COMMAND, label: "Open", onselect: openPanel },
2881
- { kind: NativeMenuEntryKind.SEPARATOR },
2882
- { kind: NativeMenuEntryKind.COMMAND, label: "Quit", onselect: () => process.exit(0) }
3380
+ { kind: MenuItemKind.COMMAND, id: "open", label: "Open", onselect: openPanel },
3381
+ { kind: MenuItemKind.SEPARATOR, id: "line" },
3382
+ { kind: MenuItemKind.COMMAND, id: "quit", label: "Quit", onselect: () => process.exit(0) }
2883
3383
  ]
2884
3384
  });
2885
3385
  ```
2886
3386
 
2887
3387
  - `createStandaloneTray(options)` takes the icon's options (`icon`,
2888
3388
  `tooltip`, `isVisible`, `guid`, `onclick`, `ondoubleclick`,
2889
- `onmiddleclick`) and `menu`, and returns the same handle as
2890
- `createTrayIcon` (`update`, `notify`, `bounds`, `isRegistered`, `remove`)
3389
+ `onmiddleclick`), `menu`, `extras`, and `resolve` with `profile`, and returns
3390
+ a handle with `update`, `isRegistered` and `remove`, plus `notify` and
3391
+ `bounds` when their extras are passed
2891
3392
  The icon keeps the process alive; `remove()` or the process ending takes it
2892
3393
  out of the tray
3394
+ - `colorScheme` is the menu's `color-scheme` as the web says it: `"light dark"`
3395
+ (the default) makes the popup dark when Windows' app theme is, `"light"` and
3396
+ `"dark"` force one; `MenuColorScheme` names the three values
3397
+ It uses uxtheme's `SetPreferredAppMode` and `FlushMenuThemes` (ordinals 135
3398
+ and 136), applied before each menu opens, so it affects the process's other
3399
+ native menus too
3400
+ - The default is the smallest tray: an icon from one `.ico` path, clicks,
3401
+ `update`, `remove` and the menu
3402
+ Three parts are opt-in, each one import from the same entry, passed in
3403
+ `extras`, and none of their code is in the bundle unless passed:
3404
+ `balloons` adds `notify`, `bounds` adds `bounds()`, and `themedIcon` lets
3405
+ `icon` be `{ forLightTaskbar, forDarkTaskbar }`, swapped as the taskbar theme
3406
+ changes
3407
+ The handle has `notify` or `bounds` only when its extra is passed, and a
3408
+ theme pair is accepted only with `themedIcon`; otherwise it fails to compile
3409
+ `createTrayIcon` and `TrayIcon` of `winui-svelte/tray` include all three
3410
+
3411
+ ```ts
3412
+ import { balloons, bounds, createStandaloneTray, themedIcon } from "winui-svelte/tray/standalone";
3413
+
3414
+ const tray = createStandaloneTray({
3415
+ icon: { forLightTaskbar: "dark.ico", forDarkTaskbar: "light.ico" },
3416
+ extras: [balloons, bounds, themedIcon]
3417
+ });
3418
+ tray.notify({ title: "Ready" });
3419
+ ```
3420
+
2893
3421
  - The menu is Windows' own popup menu (`TrackPopupMenuEx`), made on a right
2894
3422
  click and destroyed when it closes; nothing of it exists while idle
2895
- A command is `{ kind, label, onselect, isEnabled }`, a line is
2896
- `{ kind: NativeMenuEntryKind.SEPARATOR }`
3423
+ `menu` is the same model as the windowed tray's (`winui-svelte/tray/menu`):
3424
+ commands, checks, radios, submenus to any depth, separators and headers,
3425
+ each with an `id` (a separator too), and values that are functions are read
3426
+ each time the menu opens, as are lazy submenu `items`
3427
+ The menu is drawn by the lite resolver by default: every item is shown in
3428
+ declared order, with dynamic values, `isVisible`, `emptyLabel`, `sort` and
3429
+ `maxItems` applied, and `level` and `isRequired` ignored; it leaves the
3430
+ level and profile code out of the bundle
3431
+ For levels, a user profile and ordering, opt in with one import:
3432
+ `resolve: resolveMenu` from the same entry, and then `profile`, the user's
3433
+ choice of level, hidden, shown and order (a `MenuProfile` with a
3434
+ `MenuLevel`, or a function that gives one, for example from
3435
+ `loadProfile`)
3436
+ The ids are literal types: `profile` accepts only ids of `menu`, and a
3437
+ wrong one fails to compile; a `profile` without `resolve: resolveMenu` also
3438
+ fails to compile, so a profile is never ignored in silence
3439
+ Windows draws a check as a tick, a radio as a dot, a header as a disabled
3440
+ bold line, a shortcut right-aligned and a badge after the label
3441
+ `staysOpen` closes and reopens the menu at the same point, with fresh
3442
+ labels and ticks, right after the line runs; `onselect` otherwise runs on
3443
+ the next turn after the menu is gone (`closeThenRun: false` runs it as the
3444
+ menu closes)
3445
+ A submenu's own `onselect` and `autoExpand`, and every `icon`, do nothing
3446
+ here: Windows opens a submenu row without reporting a pick, and no pixel
3447
+ or file icon is drawn
2897
3448
  The menu is modal: the thread runs its own message loop until it closes
2898
- It does not follow a dark system theme, which a native popup menu does not
2899
- without an undocumented call; a menu that must match the theme belongs in
3449
+ `colorScheme` makes it follow the system theme through an undocumented
3450
+ uxtheme call; a menu that must be drawn in WinUI belongs in
2900
3451
  `winui-svelte/tray` with `TrayIcon`'s `menu` snippet
2901
3452
  - The same entry re-exports `activateInstance`, `activateOrLaunch` and
2902
3453
  `launchApp` from `winui-svelte/app` (App lifecycle), so a tray imports from
@@ -2907,6 +3458,234 @@ createStandaloneTray({
2907
3458
  component, window or renderer module, or a component's name, is in the
2908
3459
  output, or if it grows past its budget
2909
3460
 
3461
+ ### Trays and windows are independent
3462
+
3463
+ Neither needs the other
3464
+ A process can have zero windows and several tray icons, or windows and
3465
+ taskbar buttons and no tray; nothing is created for the part you leave out
3466
+
3467
+ ```ts
3468
+ // Zero windows, two icons, one Node process
3469
+ import { createStandaloneTray, MenuColorScheme, MenuItemKind } from "winui-svelte/tray/standalone";
3470
+ import { defaultProgressRegistry, progressText } from "winui-svelte/progress/core";
3471
+
3472
+ createStandaloneTray({
3473
+ icon: "recorder.ico",
3474
+ tooltip: "Recorder",
3475
+ colorScheme: MenuColorScheme.DARK,
3476
+ menu: () => [{
3477
+ kind: MenuItemKind.COMMAND,
3478
+ id: "status",
3479
+ label: progressText(defaultProgressRegistry().snapshot),
3480
+ onselect() {}
3481
+ }]
3482
+ });
3483
+
3484
+ createStandaloneTray({
3485
+ icon: "uploads.ico",
3486
+ tooltip: "Uploads",
3487
+ colorScheme: MenuColorScheme.LIGHT,
3488
+ menu: [{ kind: MenuItemKind.COMMAND, id: "quit", label: "Quit", onselect: () => process.exit(0) }]
3489
+ });
3490
+ ```
3491
+
3492
+ ```svelte
3493
+ <!-- Windows and a taskbar button, no tray -->
3494
+ <script lang="ts">
3495
+ import { Window } from "winui-svelte/components";
3496
+ import { TaskbarProgress } from "winui-svelte/progress";
3497
+ </script>
3498
+
3499
+ <Window>
3500
+ <TaskbarProgress />
3501
+ </Window>
3502
+ ```
3503
+
3504
+ - Each `createStandaloneTray` has an identity of its own (its own hidden owner
3505
+ window and a unique id, and its own `guid` when you pass one), its own
3506
+ timer, its own menu and its own state; `remove()` takes out that icon only
3507
+ and the exit hook takes out all of them
3508
+ - Clicks are polled, and Windows keeps one "pressed since the last read"
3509
+ flag for the whole process, which the first read clears; the trays of a
3510
+ process share that read, so each icon hears a click shorter than its
3511
+ polling interval (the flag can still be cleared by another process or by
3512
+ other code of yours that calls `GetAsyncKeyState`)
3513
+ - The menu theme is one setting per process (uxtheme's preferred app mode);
3514
+ a tray sets its own `colorScheme` right before each of its menus opens, so
3515
+ two trays with different schemes each get theirs, because only one menu is
3516
+ open at a time
3517
+ The setting then stays until the next menu opens, so another popup menu in
3518
+ the same process (a window's) shows in the scheme of the tray that spoke
3519
+ last
3520
+ - `winui-svelte/progress/core` is the progress registry, operations and
3521
+ `progressText` with no Svelte component and no taskbar code, so a
3522
+ tray-only process can show progress; `winui-svelte/progress` adds
3523
+ `TaskbarProgress` and `bindTaskbarProgress`, which are the only part that
3524
+ needs a window
3525
+ - `scripts/pack/independence.test.ts` walks the imports and fails if the
3526
+ standalone tray reaches a component, the renderer, the window runtime or
3527
+ taskbar code, if the taskbar progress reaches a tray, or if a window
3528
+ reaches a tray; `scripts/pack/tray-only.test.ts` bundles two trays with the
3529
+ registry and fails on the same, or on a growing size
3530
+
3531
+ ### Tray as an entrypoint (`entrypoints/tray.ts`)
3532
+
3533
+ The app does not have to know it has a tray; the tray is its own file, found
3534
+ by its name and built into a small bundle for a process of its own
3535
+
3536
+ ```text
3537
+ my-app/
3538
+ entrypoints/
3539
+ main.ts -> dist/main.js
3540
+ window.ts -> dist/window.js
3541
+ tray.ts -> dist/tray.js, dist/tray.json, dist/tray.ico
3542
+ ```
3543
+
3544
+ `main.ts` and `window.ts` never import `tray.ts`; `buildApp` (and the dev
3545
+ server of `winuiSvelte()`) discover the folder, so `entries` is optional, and a
3546
+ name given in `entries` wins over the file found
3547
+
3548
+ ```ts
3549
+ import { activateOrLaunch, defineTray, MenuItemKind, MenuLevel, resolveMenu } from "winui-svelte/tray/standalone";
3550
+
3551
+ export default defineTray({
3552
+ icon: "tray.ico",
3553
+ tooltip: "My app",
3554
+ guid: "7d1c5a52-3f1b-4a63-9f5e-2f4d6b0c8a11",
3555
+ onactivate: openApp,
3556
+ resolve: resolveMenu,
3557
+ menu: [
3558
+ { kind: MenuItemKind.COMMAND, id: "open", label: "Open", isRequired: true, onselect: openApp },
3559
+ { kind: MenuItemKind.COMMAND, id: "capture", label: "Capture", level: MenuLevel.STANDARD }
3560
+ ]
3561
+ });
3562
+ ```
3563
+
3564
+ - `defineTray` returns its argument; it takes the options of
3565
+ `createStandaloneTray` (`menu`, `resolve`, `profile`, `extras`, the click
3566
+ handlers) with the ids of `menu` as a literal union, so a `profile` that names
3567
+ an id the menu lacks is a type error, and `profile` needs `resolve`
3568
+ - `guid` is required: it keeps the icon's place in the tray and names the one
3569
+ tray process, so a second `tray.js` exits at once
3570
+ - `onactivate` runs on a left click when `onclick` is not given
3571
+ - `export default [defineTray({ ... }), defineTray({ ... })]` defines several
3572
+ trays in one entrypoint: one `tray.js`, one process, each tray with its own
3573
+ `guid`, icon, tooltip, menu and `colorScheme` (every `guid` must differ)
3574
+ The first tray's `guid` names the process, so keep the order; `tray.json` is
3575
+ the single manifest for one tray and `{ "trays": [ ... ] }` for several, and
3576
+ `startTray()` reads the first `guid` from either
3577
+ The markup form (`tray.svelte`) is one tray; use `tray.ts` for several
3578
+ `examples/tray-multiple` is a two-icon entrypoint with no window
3579
+ - The build reads `icon`, `tooltip` and `guid` from the syntax tree, never by
3580
+ running the file, so a top-level import of WinRT in `tray.ts` does not
3581
+ execute at build; `icon` and `guid` must be string literals, and the icon a
3582
+ file inside the folder of `tray.ts` (written there as `icon: "tray.ico"`,
3583
+ copied to the same relative path in the output)
3584
+ - `tray.js` is the wrapper the build writes (a virtual module, like WXT's
3585
+ background): it imports the default export, calls `claimTrayInstance({ guid })`
3586
+ (the right to be the one tray for the `guid`; false in a second copy) and then
3587
+ `createStandaloneTray`; `tray.json` holds what was read
3588
+ - `startTray()` from `winui-svelte/app` starts `tray.js` detached once; it is
3589
+ optional, for an installer, a launcher or the app's own start; it reads
3590
+ `tray.json` for the `guid`, so the key is derived in one place
3591
+ (`trayInstanceKey(guid)`); `activateOrLaunch` is how the tray reaches the app
3592
+ - Under the dev server the tray is built into `.winui/tray` and started; a
3593
+ change to it rebuilds and restarts the process (no HMR, as WXT's background)
3594
+ after stopping the Node process whose pid `.winui/tray.pid` holds
3595
+ - The icon of a stopped process stays in the notification area until the
3596
+ pointer passes over it; that is how Windows handles an icon whose process
3597
+ was ended
3598
+ - The bundle holds no component and no window runtime; most of its size is
3599
+ zod, which a bundle for Node carries (`scripts/pack/tray-entrypoint.test.ts`
3600
+ keeps its budget)
3601
+ - `tray.svelte` is the same entrypoint written as markup (next section); a
3602
+ folder with both `tray.ts` and `tray.svelte` is an error
3603
+
3604
+ The working example is `examples/tray-entrypoint`
3605
+
3606
+ #### The tray written as markup (`entrypoints/tray.svelte`)
3607
+
3608
+ The menu can be written with the components of
3609
+ `winui-svelte/tray/menu/svelte`; the build reads the file with Svelte's parser
3610
+ and lowers the markup to the plain model of `tray.ts`, so none of Svelte's
3611
+ runtime is in `tray.js` (about 40 KB that a tray-only process cannot carry)
3612
+
3613
+ ```svelte
3614
+ <script module lang="ts">
3615
+ import { activateOrLaunch, resolveMenu } from "winui-svelte/tray/standalone";
3616
+
3617
+ let isAutostart = false;
3618
+
3619
+ function openApp() {
3620
+ void activateOrLaunch({ key: "my-app", activation: { arguments: [], workingDirectory: "." }, launch: { command: process.execPath, arguments: ["main.js"] } });
3621
+ }
3622
+
3623
+ function recentCaptures() {
3624
+ return ["a.png", "b.png"];
3625
+ }
3626
+
3627
+ export const options = {
3628
+ icon: "tray.ico",
3629
+ tooltip: "My app",
3630
+ guid: "7d1c5a52-3f1b-4a63-9f5e-2f4d6b0c8a11",
3631
+ onactivate: openApp,
3632
+ resolve: resolveMenu
3633
+ };
3634
+ </script>
3635
+
3636
+ <script lang="ts">
3637
+ import { TrayMenu, TrayMenuItem, TrayMenuSubmenu } from "winui-svelte/tray/menu/svelte";
3638
+ </script>
3639
+
3640
+ <TrayMenu>
3641
+ <TrayMenuItem id="open" label="Open" isRequired onselect={openApp} />
3642
+ <TrayMenuSubmenu id="recent" label="Recent" emptyLabel="Nothing yet">
3643
+ {#each recentCaptures() as name, iCapture (name)}
3644
+ <TrayMenuItem id={`recent.${iCapture}`} label={name} />
3645
+ {/each}
3646
+ </TrayMenuSubmenu>
3647
+ {#if isAutostart}
3648
+ <TrayMenuItem id="delay" label="Delay at sign-in" />
3649
+ {/if}
3650
+ </TrayMenu>
3651
+ ```
3652
+
3653
+ - `<script module>` holds `export const options = { ... }`, the options of
3654
+ `defineTray` except `menu` (the markup is the menu); the build reads `icon`,
3655
+ `tooltip` and `guid` from its literals as it does for `tray.ts`, and
3656
+ everything `options` uses (functions, imports) lives in the same script,
3657
+ because Svelte keeps a module script apart from the instance script; a
3658
+ `satisfies` on the object is read through
3659
+ - The menu is read each time it opens, like the dynamic values of the model, so
3660
+ a plain `let` and a plain function are always current; there is no `$state`,
3661
+ `$derived`, `$effect`, `$props`, `$bindable`, `$inspect` or `$host` (the build
3662
+ refuses them, since nothing would re-run)
3663
+ - Supported: `TrayMenu` (once, the root, no attributes), `TrayMenuItem` (a
3664
+ command, or `kind="check"` or `kind="radio"`), `TrayMenuSubmenu`,
3665
+ `TrayMenuSeparator` and `TrayMenuHeader`, imported by name; attributes as
3666
+ `label="text"`, `label="x {y}"`, `label={expression}`, `{shorthand}`, a bare
3667
+ boolean (`isRequired`), `{...spread}` and `onselect={handler}`; `{#if}`,
3668
+ `{:else if}` and `{:else}`; `{#each list as item, index (key)}` over an array
3669
+ (the key is not used, the `id` is the identity); `{@const}`; the children of
3670
+ a submenu become its `items` function
3671
+ - Refused with an error that names the file, the line and the construct:
3672
+ components of your own, other elements, `{#await}`, `{#key}`, `{#snippet}`,
3673
+ `{@render}`, `{@html}`, `{@debug}`, `bind:`, `use:`, `on:`, `class:`,
3674
+ `style:`, `let:`, transitions, `animate:`, `{@attach}`, `<svelte:*>`, text
3675
+ between the lines, `{:else}` of an `{#each}` (give the submenu an
3676
+ `emptyLabel`), a `<style>` block and importing a `.svelte` file
3677
+ - Each line becomes an object literal and `menu` the function that returns
3678
+ them: `{#if}` spreads a conditional array, `{#each}` spreads `flatMap`, so
3679
+ `defineTray` receives `menu: () => [ ... ]` (a function is accepted wherever
3680
+ an array is, by `createStandaloneTray` too)
3681
+ - `svelte-check` and the editor check the markup against the props of the
3682
+ components, so a wrong attribute or value is an error there; the build
3683
+ checks nothing, as for any `.svelte` file
3684
+ - A `tray.svelte` built to `tray.js` is within a few dozen bytes of the same
3685
+ tray written in `tray.ts` (`scripts/pack/tray-svelte-entrypoint.test.ts`)
3686
+
3687
+ The working example is `examples/tray-entrypoint-svelte`
3688
+
2910
3689
  ### Notice with no app (`winui-svelte/notice`)
2911
3690
 
2912
3691
  `showNotice` shows a message box before there is a window or an app: the
@@ -2952,7 +3731,8 @@ const isConfirmed = pressed === NoticeButton.YES;
2952
3731
  ### Taskbar button (`winui-svelte/window/taskbar`)
2953
3732
 
2954
3733
  `handle.taskbar` is the window's button on the taskbar: a progress bar, an
2955
- overlay icon and flashing, over `ITaskbarList3` and `FlashWindowEx`
3734
+ overlay icon, flashing and the thumbnail's tooltip and clip, over
3735
+ `ITaskbarList3` and `FlashWindowEx`
2956
3736
  No package identity is needed; call it on the UI thread
2957
3737
  The shell calls need the real desktop shell, so a window on a desktop of its
2958
3738
  own gets `E_NOTIMPL`; a window that has no taskbar button (a background or
@@ -2978,6 +3758,15 @@ handle.taskbar.flash({ count: 2 });
2978
3758
  - `flash({ count, until })`: `until` is a `TaskbarFlashUntil` (`count`, the
2979
3759
  default, flashes `count` times, 3 by default; `foreground` until the window is
2980
3760
  brought forward; `stopped` until `stopFlashing()`)
3761
+ - `setThumbnailTooltip(text)`: the text above the window's thumbnail on hover
3762
+ (259 characters at most, else a `RangeError`; empty shows the title again)
3763
+ - `setThumbnailClip({ x, y, width, height })`: shows only that part of the
3764
+ window in the thumbnail, in pixels of the client area, inside it; `null`
3765
+ shows all of it; whole numbers with a positive size, else a `TypeError`
3766
+ `SetThumbnailClip` gets `E_NOTIMPL` on a desktop of its own, so only a fake
3767
+ tests it
3768
+ - Thumbnail toolbar buttons are not offered: their click is a sent message
3769
+ that Node cannot receive; use jump list tasks (`winui-svelte/app/jump-list`)
2981
3770
  - `createTaskbarButton(hwnd)` and `TaskbarButton` take a window handle
2982
3771
  (`appWindow.id.value`) directly; `taskbarBadgeBackend(button)` is the
2983
3772
  `fallback` for `installBadging`
@@ -3020,6 +3809,708 @@ handle.taskbar.flash({ count: 2 });
3020
3809
  The working example is `examples/services` (`test/services.test.ts` runs it in
3021
3810
  a real window; the dialogs themselves need a person and are not opened there)
3022
3811
 
3812
+ ## ChromePermissions (`winui-svelte/chrome/permissions`)
3813
+
3814
+ `chrome.permissions` for a native app, with Chrome's names and shapes:
3815
+ `getAll()`, `contains(permissions)`, `request(permissions)`,
3816
+ `remove(permissions)`, `onAdded` and `onRemoved` (a `ChromeEvent`), and
3817
+ `Permissions { permissions, origins }`
3818
+ Opt-in: nothing is bundled until an app imports it, importing does no work,
3819
+ and no global is installed
3820
+
3821
+ ```ts
3822
+ import { ChromePermissions } from "winui-svelte/chrome/permissions";
3823
+
3824
+ const permissions = new ChromePermissions();
3825
+ permissions.onAdded.addListener(({ permissions: names }) => console.log(names));
3826
+ const isAllowed = await permissions.request({
3827
+ permissions: ["geolocation"],
3828
+ openSettings: true
3829
+ });
3830
+ ```
3831
+
3832
+ There is no per-site prompt in a native app; a permission is the OS consent
3833
+ the Permissions API already reports (`registerPermission` providers, so the
3834
+ Web APIs stay the single source of truth)
3835
+ The app holds a native permission when it asked for it and Windows allows it
3836
+ now; if either side takes it back, `contains` turns false
3837
+ The names the app asked for are saved in `chrome-permissions.json` in the
3838
+ app's data folder (`appDataFolder`, the folder `localStorage` uses), kept
3839
+ by an atomic write
3840
+
3841
+ | Chrome name | Held when | Backed by |
3842
+ | --- | --- | --- |
3843
+ | `audioCapture` | allowed | `microphone` |
3844
+ | `videoCapture` | allowed | `camera` |
3845
+ | `geolocation` | allowed | `geolocation` |
3846
+ | `notifications` | allowed | `notifications` |
3847
+ | `clipboardRead`, `clipboardWrite` | allowed | `clipboard-read`, `clipboard-write` |
3848
+ | `idle` | allowed | `idle-detection` |
3849
+ | `bluetooth` | allowed | `bluetooth` |
3850
+ | `gcm` | allowed | `push` |
3851
+ | `power` | allowed | `screen-wake-lock` |
3852
+ | `unlimitedStorage` | allowed | `persistent-storage` |
3853
+ | `activeTab`, `alarms`, `background`, `contextMenus`, `cookies`, `declarativeNetRequest`, `downloads`, `offscreen`, `scripting`, `storage`, `tabs`, `webRequest`, `windows` | always | nothing; no native meaning, and `remove` answers false |
3854
+ | any other name | never | `contains` and `request` reject with an `Error` |
3855
+ | origins (`<all_urls>` and match patterns) | always | nothing; a native app has no host permissions, a bad pattern rejects, `remove` answers false |
3856
+
3857
+ - The table is data you can read: `NATIVE_PERMISSIONS` (a `Map` from a Chrome
3858
+ name to the Web permissions behind it), `GRANTED_BY_DEFAULT` (a `Set` of the
3859
+ always-held names) and `ALL_URLS` (`<all_urls>`)
3860
+ - `request` checks each missing native permission: a state of `prompt` calls
3861
+ the provider's `request` (location shows the Windows prompt through
3862
+ `Geolocator.RequestAccessAsync`); camera and microphone are asked by the
3863
+ first device open, so they stay refused until Windows allows them
3864
+ - All requested permissions must be allowed, or `request` answers false and
3865
+ saves nothing; `onAdded` fires with the new ones
3866
+ - WinUI-only extra: `openSettings: true` in the object of `request` opens the
3867
+ Settings page with the switch (`ms-settings:privacy-webcam`,
3868
+ `privacy-microphone`, `privacy-location`, `notifications`, `bluetooth`,
3869
+ else `privacy`) when a permission stays refused; the answer is still false
3870
+ - `remove` forgets the saved grant and fires `onRemoved`; Windows keeps its own
3871
+ switch
3872
+ - Options of the constructor: `file`, `appName`, `location`, `environment`
3873
+ and `openSettings`, the stand-ins for tests
3874
+
3875
+ ## ChromeContextMenus (`winui-svelte/chrome/context-menus`)
3876
+
3877
+ `chrome.contextMenus` for a native app, with Chrome's names and shapes:
3878
+ `create(properties)` (answers the id), `update(id, properties)`,
3879
+ `remove(id)`, `removeAll()` and `onClicked` (a `ChromeEvent`); the item
3880
+ types `normal`, `checkbox`, `radio` and `separator`, and `title`, `id`,
3881
+ `checked`, `enabled`, `visible`, `contexts`, `parentId` and `onclick`
3882
+ Opt-in: nothing is bundled until an app imports it, importing does no work,
3883
+ and no global is installed
3884
+
3885
+ The items live in one list and are drawn by the tray menu model
3886
+ (`winui-svelte/tray/menu`), not by a second menu implementation:
3887
+ `menu(surface)` answers the lines for `TrayIcon` (`menu={...}`) or for a
3888
+ window's context flyout, in the same `MenuItem` shape
3889
+ The array is the same object each time and is rewritten in place when an item
3890
+ changes, so a menu that reads it when it opens shows the current items
3891
+
3892
+ ```ts
3893
+ import { ChromeContextMenus, ContextMenuSurface } from "winui-svelte/chrome/context-menus";
3894
+
3895
+ const menus = new ChromeContextMenus();
3896
+ menus.create({ id: "pause", title: "Pause", type: "checkbox", contexts: ["action"] });
3897
+ menus.onClicked.addListener(({ menuItemId, checked }) => console.log(menuItemId, checked));
3898
+ const lines = menus.menu(ContextMenuSurface.TRAY);
3899
+ ```
3900
+
3901
+ | Context | Surface | Shown |
3902
+ | --- | --- | --- |
3903
+ | `action`, `browser_action`, `page_action` | `tray` | in the tray icon's menu |
3904
+ | `page` | `window` | in the context flyout of a window |
3905
+ | `all` | both | in both |
3906
+ | `frame`, `selection`, `link`, `editable`, `image`, `video`, `audio`, `launcher` | none | accepted and ignored; there is no page under a native menu |
3907
+
3908
+ - `contexts` is `["page"]` when left out, as in Chrome
3909
+ - `documentUrlPatterns` and `targetUrlPatterns` are accepted and ignored
3910
+ - A radio belongs to the run of radios next to it among its siblings; a pick
3911
+ ticks it and unticks the others of the run
3912
+ - A pick of a checkbox flips it; `onclick` runs first, then `onClicked`
3913
+ fires with `menuItemId`, `parentMenuItemId`, `checked`, `wasChecked` and
3914
+ `editable` (always false); there is no `pageUrl`, `selectionText` or tab
3915
+ - An item with children is drawn as a submenu; a hidden item leaves out its
3916
+ children
3917
+ - `create` throws, and `update` and `remove` reject, with an `Error` for a
3918
+ duplicate id, an unknown id or parent, a parent under the item, a missing
3919
+ title, or a key Chrome does not know
3920
+ - Not mirrored: the callback arguments (use the promises), Chrome's grouping of
3921
+ several top-level items under the extension's name, and the limit of six
3922
+ top-level `action` items
3923
+ - Public exports: `ChromeContextMenus`, `ContextItemType`,
3924
+ `ContextMenuSurface`, `ContextType`, `ChromeEvent`, and the types
3925
+ `CreateProperties`, `OnClickData` and `UpdateProperties`
3926
+
3927
+ ## Downloads (`winui-svelte/downloads`)
3928
+
3929
+ Downloads on the two APIs an app already knows: the web's `fetch` with the File
3930
+ System Access API, and `chrome.downloads`
3931
+ Opt-in: nothing is bundled until an app imports it, and importing does no work
3932
+
3933
+ ### Web layer: `fetchToFile`
3934
+
3935
+ `fetchToFile` streams a URL into the file handle `showSaveFilePicker` gave
3936
+ (`installFileSystem` defines it), resumes with a Range request and marks the
3937
+ finished file as downloaded from the Internet
3938
+
3939
+ ```ts
3940
+ import { fetchToFile } from "winui-svelte/downloads";
3941
+
3942
+ const handle = await showSaveFilePicker({ suggestedName: "setup.exe" });
3943
+ await fetchToFile({
3944
+ url: "https://example.com/setup.exe",
3945
+ handle,
3946
+ onprogress: ({ loaded, total }) => console.log(loaded, total)
3947
+ });
3948
+ ```
3949
+
3950
+ - The body goes through `FileSystemWritableFileStream`; when it is whole the
3951
+ file gets a `Zone.Identifier` alternate data stream with `ZoneId=3` and
3952
+ `HostUrl` (the final address, without credentials), as a browser's download
3953
+ would, so Explorer and SmartScreen warn before it runs; a volume with no
3954
+ streams (FAT, a share) stays unmarked
3955
+ - A failed or cancelled (`signal`) read keeps the bytes that arrived;
3956
+ `resume: true` sends `Range: bytes=<size of the file>-` and appends to it
3957
+ when the server answers 206 with the matching `Content-Range`; a server that
3958
+ ignores the range (200) or refuses it (416) makes the download start over
3959
+ - `onprogress({ loaded, total })` runs after every chunk; `total` is undefined
3960
+ when the server sends no length or compresses the body
3961
+ - A non-2xx answer throws `DownloadError` with the `status`; `headers`,
3962
+ `method` and `body` shape the request and `fetch` stands in for the global
3963
+ one (the tests do)
3964
+ - `requestDownload` and `streamToFile` are the two halves of `fetchToFile`, for
3965
+ an app that decides the file after the headers arrive;
3966
+ `markOfTheWeb({ path, hostUrl })` marks a file saved another way and
3967
+ `zoneIdentifierText(hostUrl)` is the stream's text
3968
+
3969
+ ### Chrome layer: `Downloads`
3970
+
3971
+ `Downloads` is `chrome.downloads` with the same names and shapes; where Chrome
3972
+ takes a callback, a method returns a promise
3973
+
3974
+ ```ts
3975
+ import { Downloads } from "winui-svelte/downloads";
3976
+
3977
+ const downloads = new Downloads();
3978
+ downloads.onChanged.addListener(({ id, state }) => {
3979
+ if (state?.current === "complete") {
3980
+ console.log(`download ${id} is done`);
3981
+ }
3982
+ });
3983
+ const id = await downloads.download({
3984
+ url: "https://example.com/setup.exe",
3985
+ filename: "installers/setup.exe",
3986
+ conflictAction: "uniquify",
3987
+ taskbar: handle.taskbar
3988
+ });
3989
+ await downloads.pause(id);
3990
+ await downloads.resume(id);
3991
+ const [item] = await downloads.search({ id });
3992
+ ```
3993
+
3994
+ - `download({ url, filename, saveAs, conflictAction, headers, method, body })`
3995
+ returns the id once the download has started; the options are checked with
3996
+ zod, so a bad `url`, `method` or an unknown key rejects; `filename` is
3997
+ relative to the downloads folder (`directory` of the constructor, the user's
3998
+ Downloads folder by default) and may not leave it
3999
+ - The file name is `filename`, else the server's `Content-Disposition`, else
4000
+ the last part of the address; `conflictAction` is `uniquify` (the default,
4001
+ `name (1).ext`), `overwrite` or `prompt`; `saveAs` and `prompt` ask with the
4002
+ global `showSaveFilePicker` (or `pickSaveFile` of the constructor)
4003
+ - The bytes arrive in the file's name plus `.part`, renamed when whole, with
4004
+ the Mark of the Web
4005
+ - `pause(id)` keeps the bytes (`paused: true`, `canResume: true`) and
4006
+ `resume(id)` asks for the rest with a Range request; a dropped connection
4007
+ ends `interrupted` with `NETWORK_FAILED` and can resume too; `cancel(id)`
4008
+ deletes the bytes and ends `interrupted` with `USER_CANCELED`
4009
+ - `search(query)` takes Chrome's `DownloadQuery` (`query` terms, with a leading
4010
+ `-` to exclude, `filenameRegex`, `urlRegex`, `startedBefore` and the other
4011
+ time bounds, `totalBytesGreater`, `limit`, `orderBy` and every field as an
4012
+ exact match); `erase(query)` removes the ones that are not running from the
4013
+ list and returns their ids, the files stay; `removeFile(id)` deletes the file
4014
+ - `show(id)` and `showDefaultFolder()` open Explorer through `revealInExplorer`
4015
+ - `onCreated` gets the `DownloadItem`, `onChanged` a `DownloadDelta` with only
4016
+ what changed (`state`, `paused`, `bytesReceived`, `totalBytes`, `error`,
4017
+ `canResume`, `filename`, and so on) and `onErased` the id; they have
4018
+ `addListener`, `removeListener`, `hasListener` and `hasListeners`
4019
+ - The closed sets are `DownloadState` (`in_progress`, `interrupted`,
4020
+ `complete`), `FilenameConflictAction`, `HttpMethod` and `InterruptReason`,
4021
+ and `ChromeEvent` is the class of the three events
4022
+ - `DownloadItem.totalBytes` and `fileSize` are -1 while unknown, as in Chrome;
4023
+ the `error` values are `InterruptReason`'s, and an HTTP status maps to
4024
+ `SERVER_UNAUTHORIZED`, `SERVER_FORBIDDEN`, `SERVER_BAD_CONTENT` or
4025
+ `SERVER_FAILED`
4026
+ - `taskbar` is the one extra member of the options object: `handle.taskbar`
4027
+ shows a bar that fills as the download goes (a marquee when the size is
4028
+ unknown), yellow while paused, removed when it ends and red when it fails
4029
+ - Not mirrored: `open`, `getFileIcon`, `acceptDanger`, `setShelfEnabled`,
4030
+ `onDeterminingFilename` and the danger types, a download here is always safe
4031
+ - `src/downloads/fetch-to-file.test.ts` and `chrome-downloads.test.ts` run
4032
+ against a local HTTP server with Range support
4033
+
4034
+ ## Chrome storage (`winui-svelte/chrome/storage`)
4035
+
4036
+ `chrome.storage` with the same areas, names and shapes; where Chrome takes a
4037
+ callback, a method returns a promise
4038
+ Opt-in: nothing is bundled until an app imports it, and importing does no work
4039
+
4040
+ ```ts
4041
+ import { ChromeStorage } from "winui-svelte/chrome/storage";
4042
+
4043
+ const storage = new ChromeStorage();
4044
+ storage.onChanged.addListener((changes, areaName) => {
4045
+ console.log(areaName, changes);
4046
+ });
4047
+ await storage.local.set({ theme: "dark", volume: 0.8 });
4048
+ const { theme } = await storage.local.get({ theme: "light" });
4049
+ await storage.session.set({ token: "abc" });
4050
+ await storage.local.remove(["volume"]);
4051
+ const bytes = await storage.local.getBytesInUse();
4052
+ ```
4053
+
4054
+ - Areas: `local`, `sync`, `session` and `managed`, each a `StorageArea` with
4055
+ `get`, `getKeys`, `getBytesInUse`, `set`, `remove`, `clear`,
4056
+ `setAccessLevel` and `onChanged`; `ChromeStorage.onChanged` fires for every
4057
+ area with `(changes, areaName)`
4058
+ - `get(keys)` takes a key, an array of keys, an object of defaults, or null or
4059
+ nothing for every item; arguments are checked with zod and a wrong one
4060
+ rejects
4061
+ - Values are JSON, as in Chrome: a value JSON cannot hold (a function,
4062
+ `undefined`) is left out, `NaN` becomes `null` and a `Date` becomes its
4063
+ string; the stored files are checked with zod and a corrupt one reads as
4064
+ empty
4065
+ - `local` is a JSON file in the app's local data folder, next to
4066
+ `localStorage` (`chrome-storage-local.json`, written atomically after every
4067
+ change); `session` is in memory and ends with the process; the file is read
4068
+ on the first call to the area
4069
+ - `sync` is a local fallback: Windows has no sync service an unpackaged app
4070
+ can use (roaming settings are deprecated), so `chrome-storage-sync.json`
4071
+ lives beside the local file and values never reach another PC; Chrome's
4072
+ `sync` limits apply (`QUOTA_BYTES` 102400, `QUOTA_BYTES_PER_ITEM` 8192,
4073
+ `MAX_ITEMS` 512) so code meets the same errors; the write-rate constants are
4074
+ published and not enforced
4075
+ - `managed` is read-only and always empty: `set`, `remove` and `clear` reject
4076
+ with `This is a read-only store.`, and `get` answers the defaults
4077
+ - `QUOTA_BYTES` is 10485760 for `local` and `session`, and a write that would
4078
+ pass a quota rejects and stores nothing; `getBytesInUse` counts each key's
4079
+ length plus its JSON text, as Chrome does
4080
+ - `onChanged` gets `{ key: { oldValue, newValue } }` only for keys that
4081
+ changed (`oldValue` is missing for a new key, `newValue` for a removed one);
4082
+ a write that changes nothing fires nothing
4083
+ - `setAccessLevel({ accessLevel })` takes `AccessLevel`'s values and keeps
4084
+ them; every context of a native app is trusted, so it changes nothing
4085
+ - A change made by another process is not seen, and `ChromeStorage` takes
4086
+ `appName`, `environment`, `localFile` and `syncFile` (the tests give an
4087
+ in-memory file); the closed sets are `StorageAreaName` and `AccessLevel`
4088
+ - `LOCAL_QUOTA`, `SESSION_QUOTA` and `SYNC_QUOTA` hold the numbers each area
4089
+ publishes, for code that wants them without making a `ChromeStorage`
4090
+ - `src/chrome/storage/chrome-storage.test.ts` runs against an in-memory file
4091
+
4092
+ ## Chrome runtime (`winui-svelte/chrome/runtime`)
4093
+
4094
+ `chrome.runtime` for a native app: the manifest, messages and ports between the
4095
+ app's own contexts, native messaging hosts, and the install and exit events
4096
+ Opt-in: nothing is bundled until an app imports it, importing does no work, and
4097
+ no global `chrome` is installed; make one `Runtime` in each context that wants
4098
+ one
4099
+
4100
+ ```ts
4101
+ import { Runtime } from "winui-svelte/chrome/runtime";
4102
+
4103
+ const runtime = new Runtime();
4104
+ runtime.addLink(transport);
4105
+ runtime.onMessage.addListener((message, sender, sendResponse) => {
4106
+ sendResponse({ echo: message });
4107
+ });
4108
+ const answer = await runtime.sendMessage({ hello: "world" });
4109
+ ```
4110
+
4111
+ - Where Chrome sets `chrome.runtime.lastError`, a promise rejects or a `Port`
4112
+ has an `error`; there is no `lastError`
4113
+ - `getManifest()` gives `{ manifest_version: 3, name, version, description }`
4114
+ from the package identity when the app has one, else from the nearest
4115
+ `package.json` above the entry script; `id` is the package family name, or
4116
+ the `package.json` name; `getURL(path)` is `ms-appx:///path` in a package and
4117
+ a `file:` URL under the folder of `package.json` otherwise;
4118
+ `getPlatformInfo()` is `{ os: "win", arch }` with Chrome's architecture names
4119
+ - Contexts are joined by `addLink(transport)`, with any transport of
4120
+ `winui-svelte/state` (a worker's message port, stdio, memory); the call
4121
+ returns how to leave; messages are `defineMessaging` requests, so framing,
4122
+ timeouts (`timeoutMilliseconds`) and a closed link are the messaging layer's
4123
+ own, and every frame is checked with zod
4124
+ - `sendMessage(message)` reaches every other linked context and resolves with
4125
+ the first answer; a listener answers with `sendResponse`, by returning `true`
4126
+ and calling it later, or by returning a promise; it resolves `undefined` when
4127
+ listeners heard it and none answered, and rejects with Chrome's own "Receiving end does not exist" error when no
4128
+ context is linked or none listens; a listener that throws or rejects rejects the sender
4129
+ - `connect({ name })` opens a `Port` to every other linked context, which hears
4130
+ it in `onConnect`; `Port` has `postMessage`, `onMessage`, `onDisconnect`,
4131
+ `disconnect()`, `name` and `sender`; a port ends when the link closes, and
4132
+ `error` says why when something failed
4133
+ - `connectNative(application)` and `sendNativeMessage({ application, message })`
4134
+ start a registered host and speak the native messaging protocol on its stdio
4135
+ (four bytes of length, then JSON; a host's message is limited to 1 MiB)
4136
+ - A host is registered as in Chrome: a key
4137
+ `Software\winui-svelte\NativeMessagingHosts\<name>` below
4138
+ `HKEY_CURRENT_USER` whose default value is the path of the manifest (`name`,
4139
+ `path`, `type: "stdio"`, `allowed_origins`); the host gets the app's origin,
4140
+ `winui-svelte://<id>/`, as its first argument, and an `allowed_origins` that
4141
+ omits it refuses the host; a host is an executable, not a script;
4142
+ `resolveHost`, `registry` and `spawnHost` stand in for the lookup and the
4143
+ start in a test
4144
+ - `onInstalled` fires from `detectInstalled()`, which an app calls once at
4145
+ start: `{ reason: "install" }` on a first run, `{ reason: "update",
4146
+ previousVersion }` when the version changed, nothing when it is the same; the
4147
+ last version is kept in `%LOCALAPPDATA%\winui-svelte\runtime\<id>.json`, or
4148
+ in the `versionStore` you give
4149
+ - `onStartup` is the `onStartup` of `winui-svelte/app/schedule`, fired by
4150
+ `startActivation` for a `startup` activation (see `launchAtLogin`), not a
4151
+ second source
4152
+ - `onSuspend` fires when the process exits, the only suspend a desktop app
4153
+ has; `suspendSource` changes what it listens to; `dispose()` stops it and
4154
+ closes the links
4155
+ - `reload()` is `relaunch` of `winui-svelte/app`
4156
+ - The protocol's pieces are exported for a host written in Node:
4157
+ `encodeNativeMessage(message)`, `NativeMessageDecoder` (`push(chunk)` returns
4158
+ the messages a chunk completed), `NativeMessageError`, `MAX_HOST_MESSAGE_BYTES`
4159
+ and `NATIVE_HOST_REGISTRY_KEY`, the registry key below `HKEY_CURRENT_USER`
4160
+ that holds the hosts
4161
+ - Not mirrored: `onMessageExternal`, `onConnectExternal`, `onSuspendCanceled`,
4162
+ `onUpdateAvailable`, `requestUpdateCheck`, `restart`, `setUninstallURL`,
4163
+ `openOptionsPage`, `getContexts`, `getPackageDirectoryEntry`
4164
+ - The single-instance pipe stays the way a second copy of the app reaches the
4165
+ first (`startActivation`); contexts of one copy talk over their transports
4166
+ - `src/chrome/runtime/runtime.test.ts` runs it over in-memory links and a child
4167
+ process that echoes in the native messaging protocol
4168
+
4169
+ ## Chrome notifications (`winui-svelte/chrome/notifications`)
4170
+
4171
+ `chrome.notifications` for a native app, with Chrome's names and shapes; where
4172
+ Chrome takes a callback, a method returns a promise
4173
+ It delegates to the web `Notification` (`winui-svelte/web-apis/notification`),
4174
+ so there is one notification pipeline: the same permission, the same Windows
4175
+ app notifications and the same progress bar
4176
+ Opt-in: nothing is bundled until an app imports it, importing does no work, and
4177
+ no global is installed
4178
+ `installNotification()` must have run, as for the web `Notification`
4179
+
4180
+ ```ts
4181
+ import { ChromeNotifications } from "winui-svelte/chrome/notifications";
4182
+
4183
+ const notifications = new ChromeNotifications();
4184
+ notifications.onButtonClicked.addListener((id, index) => console.log(id, index));
4185
+ await notifications.create("sync", {
4186
+ type: "progress",
4187
+ title: "Syncing",
4188
+ message: "Uploading photos",
4189
+ progress: 10,
4190
+ buttons: [{ title: "Pause" }]
4191
+ });
4192
+ await notifications.update("sync", { progress: 60 });
4193
+ ```
4194
+
4195
+ - Exports: `ChromeNotifications`, `ChromeEvent`, `NotificationTemplateType`
4196
+ (`basic`, `image`, `list`, `progress`) and `NotificationPermissionLevel`
4197
+ (`granted`, `denied`), and the option types
4198
+ - `create(id, options)` resolves with the id (made up for a missing or empty
4199
+ one); the same id replaces the notification that is up, without `onClosed`
4200
+ The first call asks Windows for the permission and rejects with an `Error`
4201
+ when it is refused
4202
+ - `type`, `title` and `message` are required, and so is `imageUrl` for `image`,
4203
+ `items` for `list` and `progress` (0 to 100) for `progress`; `iconUrl` is
4204
+ optional, since an unpackaged app may have none; options are checked with a
4205
+ schema and a bad one rejects with an `Error`
4206
+ - `update(id, options)` merges into the notification and answers false when
4207
+ there is none; a change of `progress` alone moves the bar in place
4208
+ (`Notification.update`), anything else shows it again under its id
4209
+ - `clear(id)` removes it and answers false when there is none; `getAll()`
4210
+ answers an object with each id as a key and `true` as the value, for the
4211
+ notifications this run holds
4212
+ - `getPermissionLevel()` reads `Notification.permission`: `granted`, else
4213
+ `denied` (including "not asked yet", which the first `create` settles)
4214
+ - `onClicked(id)`, `onButtonClicked(id, buttonIndex)` and `onClosed(id, byUser)`
4215
+ are `ChromeEvent`s; Windows removes a clicked toast, so a click is followed
4216
+ by `onClosed(id, true)`, `clear` fires `onClosed(id, false)`, and a swipe away
4217
+ is not reported
4218
+ - `isClickable: false` silences `onClicked` for the body, not the buttons
4219
+ - Mapping: `message` is the body, `list` adds one `title: message` line per
4220
+ item, `image` uses `imageUrl`, `contextMessage` is the attribution,
4221
+ `eventTime` the timestamp, `buttons` (at most 2) become actions named by
4222
+ their index, `priority` below 0 is silent and 2 requires interaction, and
4223
+ `requireInteraction` and `silent` pass through
4224
+ - Not mirrored: `onPermissionLevelChanged` and `onShowSettings`
4225
+ - `src/chrome/notifications/chrome-notifications.test.ts` runs the web
4226
+ `Notification` over a stand-in for the Windows App SDK; no toast is shown
4227
+
4228
+ ## Chrome commands (`winui-svelte/chrome/commands`)
4229
+
4230
+ `chrome.commands` for a native app: the manifest's `commands` key as global
4231
+ hotkeys, over `registerHotkey` of `winui-svelte/app/hotkeys`
4232
+ Opt-in: nothing is bundled until an app imports it, importing does no work, and
4233
+ no global `chrome` is installed
4234
+
4235
+ ```ts
4236
+ import { ChromeCommands } from "winui-svelte/chrome/commands";
4237
+
4238
+ const commands = new ChromeCommands({
4239
+ commands: {
4240
+ toggle: {
4241
+ suggested_key: { default: "Ctrl+Shift+Y", mac: "Command+Shift+Y" },
4242
+ description: "Toggle the panel"
4243
+ }
4244
+ }
4245
+ });
4246
+ commands.onCommand.addListener(name => console.log(name));
4247
+ const failures = commands.start();
4248
+ const all = await commands.getAll();
4249
+ ```
4250
+
4251
+ - `start()` registers every shortcut (call it on the UI thread, where
4252
+ `registerHotkey` belongs) and returns the commands whose shortcut was
4253
+ refused, as `{ name, error }`; a clash with another app leaves that command
4254
+ unassigned, so its `getAll` shortcut is empty, as in Chrome; `stop()` gives
4255
+ the shortcuts back
4256
+ - `getAll()` resolves with `{ name, description, shortcut }` for each command
4257
+ in the manifest's order, the shortcut spelled `"Ctrl+Shift+Y"`
4258
+ - `suggested_key` is a string or one per platform; `windows` then `default`
4259
+ is used, and `mac`, `linux` and `chromeos` are ignored
4260
+ - `Ctrl`, `Alt` and `Shift` are as in Chrome; `Command` and `MacCtrl` mean
4261
+ Ctrl; keys are `A` to `Z`, `0` to `9`, `F1` to `F12`, `Comma`, `Period`,
4262
+ `Home`, `End`, `PageUp`, `PageDown`, `Space`, `Insert`, `Delete`, `Up`,
4263
+ `Down`, `Left`, `Right` and the four media keys; `parseShortcut(text)`
4264
+ reads one into the `HotkeyChord` and the display spelling, and throws for
4265
+ anything else
4266
+ - A bad manifest (a shortcut Chrome would not take, or a wrong shape, checked
4267
+ with zod) throws from the constructor
4268
+ - Chrome keeps most shortcuts inside the browser; a native app has no such
4269
+ scope, so every shortcut with a key is system-wide and `global` changes
4270
+ nothing
4271
+ - `_execute_action` (and `_execute_browser_action`, `_execute_page_action`)
4272
+ call `onExecuteAction` when you give it, as Chrome treats them as a click on
4273
+ the action (pass `() => action.click()` of `winui-svelte/chrome/action`),
4274
+ and fire `onCommand` otherwise
4275
+ - `onCommand` is a `ChromeEvent` and is called with the name only, there is no
4276
+ tab; `register` stands in for `registerHotkey` in a test
4277
+ - Not mirrored: `onChanged`, and the shortcut customisation page
4278
+ - `src/chrome/commands/chrome-commands.test.ts` runs it over a fake registrar,
4279
+ so no real hotkey is registered
4280
+
4281
+ ## Chrome i18n (`winui-svelte/chrome/i18n`)
4282
+
4283
+ `chrome.i18n` for a native app: `getMessage` is synchronous, over the
4284
+ standard `_locales/<locale>/messages.json` files, so an unmodified
4285
+ extension's locale folder works
4286
+ Opt-in: nothing is bundled until an app imports it, importing does no work, and
4287
+ no global `chrome` is installed
4288
+
4289
+ ```ts
4290
+ import { ChromeI18n, installLanguageDefaults } from "winui-svelte/chrome/i18n";
4291
+
4292
+ const i18n = new ChromeI18n();
4293
+ i18n.getMessage("greeting", ["Ann", "3"]);
4294
+ installLanguageDefaults(i18n);
4295
+ ```
4296
+
4297
+ - `getMessage(name, substitutions)` takes a string or up to nine strings;
4298
+ `$1` to `$9` are the substitutions, `$NAME$` is the content of the
4299
+ message's `placeholders` entry of that name (which may hold `$1`), and `$$`
4300
+ is a dollar sign; names are matched without case; an unknown name gives an
4301
+ empty string, as in Chrome
4302
+ - Lookup is per message: the exact locale (`pt-BR` is the folder `pt_BR`),
4303
+ then its language (`pt`), then the `default_locale` of `manifest.json`
4304
+ beside the folder; `localesFolder`, `root`, `defaultLocale`, `uiLanguage` and
4305
+ `acceptLanguages` override the defaults (the app's root, `_locales` in it,
4306
+ the system language)
4307
+ - The predefined messages are `@@extension_id`, `@@ui_locale` (`en_US`),
4308
+ `@@bidi_dir`, `@@bidi_reversed_dir`, `@@bidi_start_edge` and
4309
+ `@@bidi_end_edge`
4310
+ - `getUILanguage()` is a BCP 47 tag; `getAcceptLanguages()` resolves with the
4311
+ list; `detectLanguage(text)` tells scripts apart (Arabic, Hebrew, Cyrillic,
4312
+ Greek, Thai, Devanagari, Hangul, kana and Han) and answers `und` for
4313
+ Latin-script text, where Chrome uses a trained model
4314
+ - Every `messages.json` is checked with zod; a malformed one throws from
4315
+ `getMessage`
4316
+ - `installLanguageDefaults(source)` makes `navigator.language`,
4317
+ `navigator.languages`, the default locale of the `Intl` formats and of
4318
+ `toLocaleString` (and its date and time forms) follow the same source, so
4319
+ they agree with `chrome.i18n`; a locale a caller passes still wins; it
4320
+ returns the function that undoes it
4321
+ - `src/chrome/i18n/chrome-i18n.test.ts` runs it over in-memory files
4322
+
4323
+ ## Chrome global (`winui-svelte/chrome/install`)
4324
+
4325
+ `installChromeApis` defines `globalThis.chrome` for code written for a Chrome
4326
+ extension
4327
+ Opt-in: importing does no work, and the global holds exactly the namespaces the
4328
+ app passes, so the bundle holds only what the app imported to make them
4329
+
4330
+ ```ts
4331
+ import { installChromeApis } from "winui-svelte/chrome/install";
4332
+ import { ChromeI18n } from "winui-svelte/chrome/i18n";
4333
+ import { ChromeStorage } from "winui-svelte/chrome/storage";
4334
+ import * as alarms from "winui-svelte/app/schedule";
4335
+
4336
+ const uninstall = installChromeApis({
4337
+ storage: new ChromeStorage(),
4338
+ i18n: new ChromeI18n(),
4339
+ alarms
4340
+ });
4341
+ await chrome.storage.local.set({ theme: "dark" });
4342
+ ```
4343
+
4344
+ - `ChromeGlobal` is the options object and the type of `globalThis.chrome`; its
4345
+ members are `storage`, `runtime`, `permissions`, `contextMenus`, `commands`,
4346
+ `action`, `notifications`, `i18n`, `alarms`, `downloads`, `system` and `windows`, each optional,
4347
+ each an instance (or, for `alarms`, the `ChromeAlarms` calls and events of
4348
+ `winui-svelte/app/schedule`); the object is open to more namespaces as they
4349
+ are mirrored
4350
+ - The package declares no global type; to type `chrome` in your app, declare
4351
+ `var chrome: ChromeGlobal` in your own `declare global`
4352
+ - A `chrome` object that is already there keeps its other members; the
4353
+ returned function puts the previous one back
4354
+ - It does not call `installLanguageDefaults`; do that where you want
4355
+ `navigator.language` and `Intl` to follow `chrome.i18n`
4356
+ - `src/chrome/install.test.ts` covers it
4357
+
4358
+ ## Chrome action (`winui-svelte/chrome/action`)
4359
+
4360
+ `chrome.action` for a native app, over the tray icon (`winui-svelte/tray`)
4361
+ Opt-in: nothing is bundled until an app imports it, importing does no work, and
4362
+ no global `chrome` is installed
4363
+
4364
+ ```ts
4365
+ import { createChromeAction } from "winui-svelte/chrome/action";
4366
+
4367
+ const { action, tray } = createChromeAction({
4368
+ icon: "app.ico",
4369
+ title: "Inbox",
4370
+ guid: "0b3c0a53-2a8f-4a5e-9d57-1c2f7c1a9f10"
4371
+ });
4372
+ action.onClicked.addListener(() => console.log("clicked"));
4373
+ await action.setBadgeText({ text: "3" });
4374
+ ```
4375
+
4376
+ - `createChromeAction(options)` takes the options of `createTrayIcon` (except
4377
+ `onclick`) and `title`, makes the tray icon and returns `{ action, tray }`;
4378
+ call it on the UI thread; the left click is `onClicked`, the other gestures
4379
+ go to the tray as given; `createTray` stands in for `createTrayIcon` in a test
4380
+ - `new ChromeAction({ title, tray })` is the same without making the tray: give
4381
+ the tray's `onclick` to `action.click()`, then `attach(tray)` (a tray from
4382
+ `defineTray` fits), through the `ActionTray` shape
4383
+ - `setTitle({ title })` and `getTitle()` are the tooltip, kept to what the shell
4384
+ holds (127 characters)
4385
+ - `setIcon({ path })` swaps the icon file; `path` is a string or
4386
+ `{ forLightTaskbar, forDarkTaskbar }`; Chrome's `imageData` and size maps
4387
+ are rejected
4388
+ - `setBadgeText({ text })` and `getBadgeText()`: the tray cannot paint on an
4389
+ icon (icons are files loaded by path, and drawing needs a new icon file on
4390
+ every change), so the badge is a tooltip suffix, `"Inbox (3)"`; empty text
4391
+ clears it
4392
+ - `setBadgeBackgroundColor({ color })` and `getBadgeBackgroundColor()` keep the
4393
+ color (four channels, or `#rgb`, `#rgba`, `#rrggbb`, `#rrggbbaa`; Chrome's
4394
+ red until set) and nothing draws it
4395
+ - `enable()`, `disable()` and `isEnabled()`: a disabled action still shows
4396
+ (the tray cannot grey an icon) but a click on it is ignored
4397
+ - Every method returns a promise and rejects on a bad argument (zod); `tabId`
4398
+ is accepted and ignored, there are no tabs, so everything is global
4399
+ - `onClicked` is a `ChromeEvent` and is called with no argument
4400
+ - Not mirrored: `setPopup`, `getPopup`, `openPopup`, `getUserSettings`,
4401
+ `setBadgeTextColor`, `onUserSettingsChanged`
4402
+ - `src/chrome/action/chrome-action.test.ts` runs it over a fake tray
4403
+
4404
+ ## Chrome system (`winui-svelte/chrome/system`)
4405
+
4406
+ `chrome.system` for a native app: `cpu`, `memory`, `storage` and `display`
4407
+ with Chrome's names and promises, over Node's `os` and the display areas
4408
+ that `winui-svelte/devices/display` and the web `screen` read
4409
+ Opt-in: nothing is bundled until an app imports it, importing does no work, and
4410
+ no global `chrome` is installed
4411
+
4412
+ ```ts
4413
+ import { createChromeSystem } from "winui-svelte/chrome/system";
4414
+
4415
+ const system = createChromeSystem();
4416
+ const cpu = await system.cpu.getInfo();
4417
+ const memory = await system.memory.getInfo();
4418
+ const drives = await system.storage.getInfo();
4419
+ const displays = await system.display.getInfo();
4420
+ system.display.onDisplayChanged.addListener(() => console.log("changed"));
4421
+ ```
4422
+
4423
+ - `createChromeSystem(options)` returns `{ cpu, memory, storage, display }`
4424
+ (`SystemCpu`, `SystemMemory`, `SystemStorage`, `SystemDisplay`); nothing is
4425
+ read until a method is called; `backend` stands in for the machine in a
4426
+ test, and `windowsSystemBackend()` is the default (`SystemBackend` is its
4427
+ shape)
4428
+ - `cpu.getInfo()` resolves with `numOfProcessors`, `archName` (`x86-64`,
4429
+ `arm64`, `x86-32`, `arm`), `modelName`, `features`, `processors` (the
4430
+ `kernel`, `user`, `idle` and `total` milliseconds of each) and an empty
4431
+ `temperatures`; `features` is `mmx`, `sse` and `sse2` on x64 and empty
4432
+ elsewhere, as Node reports no others
4433
+ - `memory.getInfo()` resolves with `capacity` and `availableCapacity` in bytes
4434
+ - `storage.getInfo()` resolves with `{ id, name, type, capacity }` for each
4435
+ drive letter, `type` one of `StorageUnitType` (`fixed`, `removable`,
4436
+ `unknown`), read with `GetDriveTypeW`
4437
+ - `storage.onAttached` and `storage.onDetached` are not mirrored: Windows
4438
+ tells an app about a drive coming or going only through a hidden window's
4439
+ `WM_DEVICECHANGE` or a `DeviceWatcher` that needs a package identity; call
4440
+ `getInfo` again
4441
+ - `display.getInfo(flags)` resolves with one record per display area, the
4442
+ primary first: `id`, `name` (`Display 1` and so on), `isPrimary`,
4443
+ `isEnabled`, `dpiX`, `dpiY` (the system scale times 96), `bounds` and
4444
+ `workArea` as `{ left, top, width, height }` in screen pixels;
4445
+ `mirroringSourceId` is empty and `rotation` 0, as Windows tells an app
4446
+ neither; `singleUnified` is accepted and ignored; a flag of the wrong
4447
+ type rejects (zod)
4448
+ - `display.onDisplayChanged` is a `ChromeEvent` called with no argument; the
4449
+ display watcher runs only while a listener is added
4450
+ - Not here on purpose: `chrome.idle` is the web `IdleDetector` and
4451
+ `chrome.desktopCapture` the web `getDisplayMedia`, both already covered
4452
+ - `src/chrome/system/chrome-system.test.ts` runs it over a fake backend
4453
+
4454
+ ## Chrome windows (`winui-svelte/chrome/windows`)
4455
+
4456
+ `chrome.windows` for the windows of a native app, over `WindowHandle`
4457
+ Opt-in: nothing is bundled until an app imports it, importing does no work, and
4458
+ no global `chrome` is installed
4459
+
4460
+ ```ts
4461
+ import { createWindow } from "winui-svelte/window";
4462
+ import { chromeWindowSurface, createChromeWindows, WindowState } from "winui-svelte/chrome/windows";
4463
+
4464
+ const windows = createChromeWindows({
4465
+ open: () => chromeWindowSurface(createWindow({ component: Panel, props: {} }).handle)
4466
+ });
4467
+ windows.track({
4468
+ surface: chromeWindowSurface(mainHandle),
4469
+ isCurrent: true
4470
+ });
4471
+ windows.onFocusChanged.addListener(windowId => console.log(windowId));
4472
+ const panel = await windows.create({ width: 400, height: 300 });
4473
+ await windows.update(panel.id, { state: WindowState.maximized });
4474
+ await windows.remove(panel.id);
4475
+ ```
4476
+
4477
+ - `createChromeWindows(options)` makes a `ChromeWindows`; make one and share
4478
+ it, since the windows it knows and their ids live in it; no process-wide
4479
+ list of windows exists, so the app hands it the windows
4480
+ - `track({ surface, isCurrent })` starts reporting a window, gives it an id
4481
+ from 1 and fires `onCreated`; `chromeWindowSurface(handle)` makes a
4482
+ `ChromeWindowSurface` of a `WindowHandle` (`bind:handle` on `<Window>`, or
4483
+ the `handle` of what `createWindow` returns); a window leaves when it
4484
+ closes, firing `onRemoved`
4485
+ - `create(createData)` calls the `open` option, which makes the content,
4486
+ tracks what it returns and then applies `left`, `top`, `width`, `height`,
4487
+ `state` and `focused`; without `open` it rejects; `url`, `tabId`, `type`,
4488
+ `incognito` and `setSelfAsOpener` reach `open` and nothing else
4489
+ - `get(windowId)`, `getCurrent()`, `getLastFocused()` and `getAll()` resolve
4490
+ with a `ChromeWindow`: `id`, `focused`, `top`, `left`, `width`, `height`,
4491
+ `state`, `alwaysOnTop`, `incognito` (always false) and `type` (always
4492
+ `normal`); places and sizes are in device pixels, as `AppWindow` has them;
4493
+ `populate` and `windowTypes` are accepted and ignored, there are no tabs
4494
+ - `WINDOW_ID_CURRENT` (-2) names the window `track` marked current, else the
4495
+ last focused; `WINDOW_ID_NONE` (-1) is what `onFocusChanged` reports when
4496
+ focus leaves the app's windows
4497
+ - `update(windowId, updateInfo)` takes `left`, `top`, `width`, `height`,
4498
+ `state` (`WindowState`: `normal`, `minimized`, `maximized`, `fullscreen`,
4499
+ `locked-fullscreen`, the last as full screen), `focused` (true brings the
4500
+ window forward; false changes nothing) and `drawAttention` (flashes the
4501
+ taskbar button until the window is brought forward); as in Chrome a place
4502
+ or size cannot go with a state other than `normal`, and `focused` cannot go
4503
+ with `minimized`
4504
+ - `remove(windowId)` closes the window; `onRemoved` fires once it has closed,
4505
+ so a close guard on the window keeps it
4506
+ - Every method returns a promise and rejects on a bad argument (zod) or an
4507
+ unknown id; `WindowType` lists Chrome's types, and every window is `normal`
4508
+ - `onCreated`, `onRemoved`, `onFocusChanged` and `onBoundsChanged` are
4509
+ `ChromeEvent`s; `onBoundsChanged` fires after a move or a resize
4510
+ - Not mirrored: `tabs` in a window, `create`'s `focused: false` and `incognito`
4511
+ effects, and `onBoundsChanged`'s separate move and resize
4512
+ - `src/chrome/windows/chrome-windows.test.ts` runs it over fake windows
4513
+
3023
4514
  ## Data transfer (`winui-svelte/data-transfer`)
3024
4515
 
3025
4516
  Drag and drop, file dialogs, the clipboard and the launcher, in the web's
@@ -3169,8 +4660,17 @@ picker code in `src/window/pickers.ts` is the one used)
3169
4660
 
3170
4661
  `clipboard.readText()`, `readHtml()`, `read({ formats })` (a `DataTransfer`),
3171
4662
  `types()`, `writeText(text)`, `write({ text, html, uri, files, bitmap, custom,
3172
- shouldPersist })`, `clear()` and `onChange(callback)` (returns what stops it)
4663
+ shouldPersist, deferred })`, `clear()` and `onChange(callback)` (returns what
4664
+ stops it)
3173
4665
  `write` replaces the clipboard's whole content
4666
+ `deferred` maps a type to a provider (`() => Promise<string | NativeFile>`) that
4667
+ Windows runs when something pastes, through `DataPackage.SetDataProvider`; a
4668
+ source does the same for a drag with `event.dataTransfer.setDeferredData({
4669
+ type, provider })` in `dragstart`, and the data is made at the drop
4670
+ A type starting with `image/` is a picture, so its provider gives a `NativeFile`
4671
+ A provider that rejects leaves its format empty
4672
+ Windows runs a provider on the UI thread, and `shouldPersist` runs them at
4673
+ once, before the app exits
3174
4674
 
3175
4675
  ### Launcher and share
3176
4676
 
@@ -3207,6 +4707,242 @@ takes drops, through the handlers a real drop reaches, and resolves with the
3207
4707
  operation the control accepted (`0` when it refused); it sends no input, so an
3208
4708
  app can test its drop handling in a real window
3209
4709
 
4710
+ ## Progress (`winui-svelte/progress`)
4711
+
4712
+ One progress object for any long work: a download, a file read, a copy, an OCR
4713
+ pass; it is a promise, an `EventTarget` with the platform events, and
4714
+ reactive state, in one value
4715
+ Operations list themselves in an app-wide registry, so the taskbar button and
4716
+ the tray show them with no setup
4717
+ Opt-in: nothing is bundled until an app imports it, and importing does no work
4718
+
4719
+ ### Five call sites
4720
+
4721
+ ```svelte
4722
+ <script lang="ts">
4723
+ import { Button, ProgressBar, TextBlock, Window } from "winui-svelte/components";
4724
+ import { fetchToFile } from "winui-svelte/downloads";
4725
+ import { TaskbarProgress } from "winui-svelte/progress";
4726
+
4727
+ // 1. A download with a bar: fetchToFile returns the operation at once
4728
+ const download = fetchToFile({ url, handle });
4729
+ download.then(size => console.log("saved", size)); // or: await download
4730
+ </script>
4731
+
4732
+ <Window>
4733
+ <TaskbarProgress /> <!-- 4. the taskbar shows every running operation -->
4734
+ <ProgressBar {...download.barProps} /> <!-- value, isIndeterminate, showPaused, showError -->
4735
+ <TextBlock>{download.loaded} of {download.total ?? "?"}</TextBlock>
4736
+ <Button onclick={() => download.cancel()}>Cancel</Button>
4737
+ </Window>
4738
+ ```
4739
+
4740
+ ```ts
4741
+ // 2. Reading a file from disk, with progress and cancel
4742
+ const read = handle.read({ onprogress: event => console.log(event.loaded, event.total) });
4743
+ const file = await read; // a File, like getFile()
4744
+ read.cancel(); // or abort the signal given in the options
4745
+
4746
+ // 3. Any other long work: one call, no lifecycle code
4747
+ const copy = trackOperation({
4748
+ label: "Copying photos",
4749
+ group: "sync",
4750
+ async run(operation) {
4751
+ for await (const chunk of source) {
4752
+ await write(chunk);
4753
+ operation.update({ loaded: (written += chunk.byteLength), total });
4754
+ operation.signal.throwIfAborted();
4755
+ }
4756
+ }
4757
+ });
4758
+
4759
+ // 5. Retry: a failed fetchToFile continues where it stopped
4760
+ await fetchToFile({ url, handle, resume: true });
4761
+ ```
4762
+
4763
+ ```svelte
4764
+ <!-- Tray menu, in tray.svelte markup -->
4765
+ <TrayMenu>
4766
+ <TrayMenuProgress id="progress" /> <!-- "setup.exe - 45%", hidden when idle -->
4767
+ <TrayMenuOperations id="operations" label="Running" emptyLabel="Nothing running" />
4768
+ </TrayMenu>
4769
+ ```
4770
+
4771
+ `{...download.barProps}` spreads onto a `ProgressBar`; Svelte then cannot tell
4772
+ at build time whether a scoped class selector matches that bar, so write the
4773
+ five props out when the same component has a `<style>` rule for its siblings
4774
+
4775
+ ### Several windows and tray icons
4776
+
4777
+ The registry is app-wide; what a taskbar button or a tray line shows is scoped
4778
+ by `group` (a name an operation is given) or by an operation or registry given
4779
+ as `of`
4780
+ A `<TaskbarProgress />` drives the taskbar button of the window it sits in;
4781
+ `window={handle}` picks another
4782
+
4783
+ ```svelte
4784
+ <script lang="ts">
4785
+ const upload = trackOperation({ group: "uploads", run });
4786
+ const download = fetchToFile({ url, handle, group: "downloads" });
4787
+ </script>
4788
+
4789
+ <!-- Window A: its taskbar button shows the downloads only -->
4790
+ <Window bind:handle={windowA}>
4791
+ <TaskbarProgress group="downloads" />
4792
+ </Window>
4793
+
4794
+ <!-- Window B: its own button shows one upload; window A is not touched -->
4795
+ <Window>
4796
+ <TaskbarProgress of={upload} />
4797
+ </Window>
4798
+
4799
+ <!-- The main window drives window A from outside -->
4800
+ <TaskbarProgress window={windowA} group="downloads" />
4801
+
4802
+ <!-- Two tray icons, each with its own menu and its own scope -->
4803
+ <TrayIcon>
4804
+ <TrayMenu>
4805
+ <TrayMenuProgress id="downloads" group="downloads" />
4806
+ </TrayMenu>
4807
+ </TrayIcon>
4808
+ <TrayIcon>
4809
+ <TrayMenu>
4810
+ <TrayMenuOperations id="uploads" label="Uploads" group="uploads" />
4811
+ </TrayMenu>
4812
+ </TrayIcon>
4813
+ ```
4814
+
4815
+ ### `ProgressOperation`
4816
+
4817
+ - It is `PromiseLike`: `await operation` gives the value passed to `complete`
4818
+ and throws the reason of `fail` or `cancel` (an `AbortError` by default); an
4819
+ operation nobody awaits raises no unhandled rejection
4820
+ - It is an `EventTarget` that fires `loadstart`, `progress`, `load`, `error`,
4821
+ `abort` and `loadend` as `OperationProgressEvent` (`lengthComputable`,
4822
+ `loaded`, `total`), in the order `XMLHttpRequest` and `FileReader` use, plus
4823
+ `pause`, `resume` and `change`; `onprogress` and its kin work as properties
4824
+ and as options
4825
+ - `value` (0 to 1), `loaded`, `total`, `state`, `isIndeterminate`,
4826
+ `showPaused`, `showError`, `label` and `barProps` are reactive in markup and
4827
+ in `$effect`, with the meaning `ProgressBar` gives them: a total that is
4828
+ unknown is indeterminate
4829
+ - `$operation` works too: it has `subscribe` and so is a Svelte store
4830
+ - `signal` is an `AbortSignal` that aborts on `cancel()`; a `signal` given to
4831
+ the constructor cancels the operation when it aborts
4832
+ - `start`, `update({ loaded, total })`, `pause`, `resume`, `complete(value)`
4833
+ and `fail(reason)` are for the code doing the work; `resume` also retries an
4834
+ errored operation (the other final states are final)
4835
+ - `ProgressState` is the closed set of states: `idle`, `running`, `paused`,
4836
+ `complete`, `error`, `canceled`
4837
+
4838
+ ### Registry and scopes
4839
+
4840
+ - `defaultProgressRegistry()` is the app-wide registry; an operation lists
4841
+ itself there unless it gets `registry: otherRegistry` or `registry: false`
4842
+ - A finished or canceled operation leaves; a failed one stays so a red bar
4843
+ is not lost, until `clearFailed()` or `remove(operation)`
4844
+ - `registry.where("sync")` or `registry.where(operation => ...)` is a scoped
4845
+ registry that follows the first (call `dispose()` when done);
4846
+ `<TaskbarProgress group>` and the tray components do this for you
4847
+ - `snapshot`, `value`, `count`, `state`, `isIndeterminate`, `showPaused` and
4848
+ `showError` are the aggregate: the bar covers the operations that know their
4849
+ total, and is indeterminate only when none does; `paused` when all that are
4850
+ left are paused; `error` when only failed ones are left; `count` is the
4851
+ number unfinished
4852
+ - `aggregateSnapshots` is that rule as a pure function
4853
+
4854
+ ### Taskbar and tray
4855
+
4856
+ - `<TaskbarProgress of group window taskbar />` draws nothing and keeps the
4857
+ taskbar button in step: a bar, a marquee when the total is unknown, paused
4858
+ yellow, error red, gone when nothing is left; the shell is told only when the
4859
+ bar moves by a thousandth
4860
+ - `bindTaskbarProgress({ source, taskbar })` is the same without markup (the
4861
+ `taskbar` option of `Downloads.download` uses it); `taskbarOptionsOf` is the
4862
+ mapping
4863
+ - `<TrayMenuProgress id of group />` is a command line with the text of
4864
+ `progressText(snapshot)`, hidden while nothing runs; `onselect` is yours
4865
+ - `<TrayMenuOperations id label of group />` is a submenu with a line per
4866
+ running operation; picking a line cancels it
4867
+ - `Downloads` gives each download an operation (`progress: registry` in its
4868
+ options picks the registry, `group` in `download({ ... })` the group), and
4869
+ `fetchToFile` returns one; `FileSystemFileHandle.read` is the extra (WinUI
4870
+ only) that reads a file in 1 MiB chunks
4871
+ - `trackStream({ stream, operation })` passes a `ReadableStream` through and
4872
+ reports the bytes; `trackOperation` is the whole lifecycle for any async work
4873
+
4874
+ ## Incremental loading (`winui-svelte/incremental`)
4875
+
4876
+ A list that loads its next batch as the user scrolls near the end, for
4877
+ `ListView`, `GridView`, `ItemsRepeater`, `ItemsView` and `BreadcrumbBar`
4878
+ Opt-in: nothing is bundled until an app imports it, and importing does no work
4879
+
4880
+ ```svelte
4881
+ <script lang="ts">
4882
+ import { ListView } from "winui-svelte/components";
4883
+ import { createIncrementalSource, IncrementalStatus } from "winui-svelte/incremental";
4884
+
4885
+ const source = createIncrementalSource<Post>({
4886
+ batchSize: 25,
4887
+ load: ({ offset, count, signal }) => fetchPosts({ offset, count, signal })
4888
+ });
4889
+ </script>
4890
+
4891
+ <ListView incremental={source} item={postRow} items={source.items} key={post => post.id} />
4892
+ {#if source.state.status === IncrementalStatus.ERROR}
4893
+ <button onclick={() => source.retry()}>Try again</button>
4894
+ {/if}
4895
+ ```
4896
+
4897
+ `createIncrementalSource({ load, batchSize, threshold, isLast })` (options:
4898
+ `IncrementalSourceOptions`) returns an `IncrementalSource`, generic over the item;
4899
+ `IncrementalLoading` is what a list asks of its `incremental` prop
4900
+ `load({ offset, count, signal })` resolves with the next items; fewer than
4901
+ `count` (or none) is the last batch, and `isLast({ batch, items })` decides when
4902
+ the size cannot (a server that sends a cursor)
4903
+ `batchSize` is 20 and `threshold` is 5 by default: the next batch loads when
4904
+ the control realizes an item within `threshold` of the end
4905
+ The source holds `items` and `state`, both reactive
4906
+ `state` is `{ status: "idle" | "loading" | "done" }` or
4907
+ `{ status: "error", error }`; `IncrementalStatus` names the four (also in
4908
+ `winui-svelte/enums`)
4909
+
4910
+ - `loadMore()` loads now; while a load is in flight it returns that load's
4911
+ promise, so a load never runs twice, and it never rejects
4912
+ - A failure is the `error` state and stays until `retry()`; the list does not
4913
+ retry by itself
4914
+ - `cancel()` aborts the load in flight through its `AbortSignal` and drops its
4915
+ result; `reset()` also clears the items, and a bound list loads the first
4916
+ batch again; `dispose()` aborts for good
4917
+ - A list bound to a source starts it, so the first batch needs no call
4918
+
4919
+ ### The mechanism, and why
4920
+
4921
+ WinUI's own is `ISupportIncrementalLoading` on the items source, which the
4922
+ list calls when it nears its end (`IncrementalLoadingTrigger`)
4923
+ winui-svelte does not use it: the items of these lists are a native vector of
4924
+ keys (see Items), and the interface belongs on the collection itself, which
4925
+ would have to be a JavaScript-made `IBindableVector`,
4926
+ `INotifyCollectionChanged` and `ISupportIncrementalLoading` returning an
4927
+ `IAsyncOperation`
4928
+ dynwinrt (0.1.0-preview.23) can make a COM object from a callback
4929
+ (`createComObject`), but nothing in this package has proved that WinUI binds it
4930
+ as an items source, and the same table would have to answer a bindable vector's
4931
+ every call, so it was not built
4932
+ Instead the control's own realization tells the source: ListView and GridView
4933
+ report each container's index through `ContainerContentChanging`, the repeaters
4934
+ through `ElementPrepared`, and the source loads when that index is within
4935
+ `threshold` of the end
4936
+ The report is made after the layout pass (a timer of zero, the furthest index of
4937
+ the pass), because a source that changes `state` during it changes the app's
4938
+ markup (a footer) while WinUI measures, which WinUI refuses
4939
+ `ScrollViewer.ChangeView` and a real scroll reach the source the same way
4940
+ (`test/incremental-list.test.ts`)
4941
+
4942
+ A loading footer, an error row or a "no more" line is markup of the app, beside
4943
+ the list, from `source.state`; the list has no footer snippet of its own
4944
+ The example is `examples/incremental-list`
4945
+
3210
4946
  ## Input events and focus (`winui-svelte/input`)
3211
4947
 
3212
4948
  The web's pointer, wheel, keyboard and focus events on any element, and focus
@@ -3361,6 +5097,7 @@ needs
3361
5097
  | `element.animate()`, `Animation`, `KeyframeEffect` | `winui-svelte/web-apis/animations` | web plus extras | none | done |
3362
5098
  | `ScrollTimeline`, `ViewTimeline`, `element.animate(keyframes, { timeline })` | `winui-svelte/scroll-timeline` | web | none | done |
3363
5099
  | `document.startViewTransition`, `ViewTransition`, `view-transition-name` | `winui-svelte/view-transitions` | web plus extras | none | done |
5100
+ | `alert`, `confirm`, `prompt` | `winui-svelte/dialogs` | web (as promises) plus extras | none | done |
3364
5101
  | `navigator.mediaDevices` (`getUserMedia`, `getDisplayMedia`, `enumerateDevices`), `MediaStream`, `MediaRecorder` | `winui-svelte/web-apis/media-devices` | web plus extras | none (a camera or microphone needs the Windows privacy switch on) | done |
3365
5102
  | `speechSynthesis`, `SpeechSynthesisUtterance`, `SpeechRecognition` (SSML, silences, scenario, phrases) | `winui-svelte/web-apis/speech` | web plus extras | none | done |
3366
5103
  | `navigator.mediaSession`, `MediaMetadata` | `winui-svelte/web-apis/media-session` | web plus extras | none | done |
@@ -3373,6 +5110,7 @@ needs
3373
5110
  | `navigator.credentials`, `PasswordCredential`, `PublicKeyCredential` (Windows Hello) | `winui-svelte/web-apis/credentials` | web plus extras | none | done |
3374
5111
  | `EyeDropper` | `winui-svelte/web-apis/eye-dropper` | web plus extras | none | done |
3375
5112
  | `FontFace`, `document.fonts` (font files of the app) | `winui-svelte/web-apis/fonts` | web plus extras | none | done |
5113
+ | `createImageBitmap`, `ImageBitmap`, `ImageDecoder`, canvas `toBlob`, `convertToBlob`, `toDataURL` (PNG, JPEG, GIF, BMP, TIFF) | `winui-svelte/web-apis/images` | web plus extras | none | done |
3376
5114
  | `navigator.contacts` (Contact Picker) | `winui-svelte/web-apis/contacts` | web plus extras | for most apps, package identity | done |
3377
5115
 
3378
5116
  Every row is built and tested; the timers (`setTimeout`, `setInterval`,
@@ -3406,7 +5144,9 @@ names the APIs register: `geolocation`, `accelerometer`, `screen-wake-lock`
3406
5144
  and so on) and `PermissionStateName` (`granted`, `denied`, `prompt`) are the
3407
5145
  spec's; an API registers its permission
3408
5146
  with `registerPermission({ name, provider })` and calls
3409
- `announcePermissionChange(name)` when it moves, so open statuses fire `change`
5147
+ `announcePermissionChange(name)` when it moves, so open statuses fire `change`; a provider may add `request()` (the system
5148
+ prompt), which `requestPermission(name)` calls and `readPermission(name)` reads
5149
+ back, as `chrome.permissions` does
3410
5150
 
3411
5151
  ### The three kinds and the extras convention
3412
5152
 
@@ -3664,8 +5404,11 @@ Each is `install<Name>()` from its own subpath and takes an optional `backend`
3664
5404
  the always granted `clipboard-read` and `clipboard-write` permissions
3665
5405
  More than one item, or a type the clipboard cannot take, rejects with
3666
5406
  `NotAllowedError`
5407
+ A type whose value is a promise (`new ClipboardItem({ "text/html": promise })`)
5408
+ is delayed-rendered: `write` resolves at once and the promise is awaited
5409
+ when something pastes
3667
5410
  Extras: `readContent({ formats })` (copied files in `files`, custom formats
3668
- as text), `writeContent({ files, custom, bitmap, shouldPersist })`,
5411
+ as text), `writeContent({ files, custom, bitmap, deferred, shouldPersist })`,
3669
5412
  `formats()` and `history()` (Win+V, empty when history is off)
3670
5413
  `windowsClipboardBackend()` is the real backend, for a test to wrap
3671
5414
  - `winui-svelte/web-apis/share`: `installShare()` defines `navigator.share`
@@ -3904,6 +5647,73 @@ old element to the new one
3904
5647
  `:active-view-transition-type()` have no counterpart, and `types` is carried
3905
5648
  but read by nothing
3906
5649
 
5650
+ #### Dialogs (`winui-svelte/dialogs`)
5651
+
5652
+ `installDialogs()` defines `alert`, `confirm` and `prompt` on the global scope
5653
+ over WinUI's `ContentDialog`
5654
+
5655
+ ```svelte
5656
+ <script lang="ts">
5657
+ import { installDialogs, useDialogWindow } from "winui-svelte/dialogs";
5658
+ import type { WindowHandle } from "winui-svelte/components";
5659
+
5660
+ installDialogs();
5661
+ let handle = $state<WindowHandle>();
5662
+
5663
+ $effect(() => {
5664
+ if (!handle) {
5665
+ return;
5666
+ }
5667
+
5668
+ return useDialogWindow(handle);
5669
+ });
5670
+
5671
+ async function remove() {
5672
+ const isSure = await confirm("Delete this file?");
5673
+ if (isSure) {
5674
+ await alert("Deleted");
5675
+ }
5676
+ }
5677
+ </script>
5678
+ ```
5679
+
5680
+ - Decision: they return promises, where the browser's block, because a
5681
+ `ContentDialog` is asynchronous and the thread that would block is the one
5682
+ that pumps the window, so a blocking version would freeze the dialog it
5683
+ waits for; the web names are kept, so that a library written for a browser still calls them,
5684
+ and the result is awaited: `await confirm(text)`. The other way (new names
5685
+ and no globals) would make every such library need a patch; the cost of this
5686
+ way is that `if (confirm(text))` is always true, because a promise is
5687
+ truthy, and `lib.dom` still types the globals as synchronous; in your own
5688
+ code call `showAlert`, `showConfirm` and `showPrompt` (the same functions,
5689
+ typed as promises) and leave the globals to libraries
5690
+ - `alert(message)` resolves when the dialog closes, `confirm(message)`
5691
+ resolves `true` for OK, `prompt(message, default)` resolves with the text or
5692
+ `null` for Cancel, Escape or the close button; a message that is not a
5693
+ string is shown as `String(message)`
5694
+ - `showDialog({ content, title, primaryButtonText, secondaryButtonText,
5695
+ closeButtonText, defaultButton, input, signal })` is the WinUI form: three
5696
+ buttons, the button Enter presses (`DialogButton`), a text box
5697
+ (`{ value, placeholder, isMultiline }`) and an `AbortSignal` that closes the
5698
+ dialog like Escape; it resolves with `{ result, text }`, where `result` is a
5699
+ `DialogResult` (`primary`, `secondary` or `none`) and `text` is the box when
5700
+ the primary button closed a dialog that had one
5701
+ - Which window: `useDialogWindow(handle)` takes the handle `bind:handle`
5702
+ gives, for each window; the dialog opens in the one activated last, and the
5703
+ function it returns stops following the window
5704
+ - One at a time: WinUI shows one `ContentDialog` per window, so a dialog asked
5705
+ for while another is open waits, in order, in the same line the
5706
+ `ContentDialog` components use; a dialog that fails does not hold the line,
5707
+ and an aborted one that still waits is rejected with an `AbortError`
5708
+ - No window: `alert` and `confirm` show a message box (`showNotice`, with the
5709
+ installed `title`), and `prompt` and `showDialog` reject with an
5710
+ `InvalidStateError`, because a message box has no text box and no third
5711
+ button
5712
+ - `installDialogs({ title, okText, cancelText })` sets the title and the
5713
+ button texts (English by default; WinUI does not translate them)
5714
+ - Not covered: a dialog that blocks the caller, and the prompt of
5715
+ `beforeunload`
5716
+
3907
5717
  ### Media devices (`winui-svelte/web-apis/media-devices`)
3908
5718
 
3909
5719
  `installMediaDevices()` defines `navigator.mediaDevices` (`enumerateDevices`,
@@ -4250,6 +6060,42 @@ anywhere on the screen
4250
6060
  - `ScreenPicker` is the one interface the polling picker (`windowsScreenPicker`)
4251
6061
  and the tests implement
4252
6062
 
6063
+ #### Images (`winui-svelte/web-apis/images`)
6064
+
6065
+ `installImageCodecs()` defines `createImageBitmap`, `ImageBitmap` and
6066
+ `ImageDecoder`, and adds `toBlob`, `convertToBlob` and `toDataURL` to
6067
+ `CanvasElement`; all of it runs on `Windows.Graphics.Imaging`, which needs no
6068
+ window and no package identity
6069
+
6070
+ - `createImageBitmap(source, options?)` and `createImageBitmap(source, sx, sy,
6071
+ sw, sh, options?)` take a `Blob`, `File` or `NativeFile` of an image file,
6072
+ `ImageData`, an `ImageBitmap` or a canvas; `imageOrientation` (`from-image`,
6073
+ `none`, `flipY`), `resizeWidth`, `resizeHeight` and `resizeQuality` work;
6074
+ `premultiplyAlpha` and `colorSpaceConversion` are read and ignored (images are
6075
+ color managed to sRGB); a file Windows cannot decode rejects with
6076
+ `InvalidStateError`
6077
+ - `ImageBitmap` has `width`, `height` and `close()`; `drawImage` and
6078
+ `createPattern` take it; extra: `toImageData()` (RGBA, not premultiplied)
6079
+ - `new ImageDecoder({ data, type })` takes bytes or a stream; `tracks` (an
6080
+ `ImageTrackList` of one `ImageTrack`), `complete`, `completed`, `decode({ frameIndex })`, `reset()`,
6081
+ `close()` and `ImageDecoder.isTypeSupported(type)`; `image` is an
6082
+ `ImageBitmap`, not a `VideoFrame`, and `duration` is not reported; a GIF
6083
+ frame is what the file stores, so an optimized GIF gives the changed area
6084
+ - Decoders: BMP, GIF, ICO, JPEG, PNG, TIFF, JPEG XR, and WebP, AVIF and HEIC
6085
+ where Windows has the codec; `isTypeSupported` asks Windows' own list
6086
+ - Encoders: PNG, JPEG (`quality` 0 to 1 is `ImageQuality`, 0.92 by default;
6087
+ transparency is drawn over black), GIF, BMP and TIFF; WebP has no Windows
6088
+ encoder, so `toBlob`, `convertToBlob` and `toDataURLAsync` give a PNG for
6089
+ `image/webp` and for any type Windows cannot write, as the platform does
6090
+ - `toDataURL(type, quality)` is synchronous and every Windows encoder is
6091
+ asynchronous, so it always returns a PNG; extra: `toDataURLAsync(type,
6092
+ quality)` encodes any type above
6093
+ - A canvas with no pixels gives `data:,`, `null` from `toBlob` and rejects
6094
+ `convertToBlob`
6095
+ - `ImageCodec` is the one interface the Windows codec (`windowsImageCodec`)
6096
+ and the tests implement; `ImageMimeType`, `ImageOrientation` and
6097
+ `ResizeQuality` are in `winui-svelte/enums`
6098
+
4253
6099
  #### Contacts (`winui-svelte/web-apis/contacts`)
4254
6100
 
4255
6101
  `installContacts()` defines `navigator.contacts` (a `ContactsManager`) with
@@ -4714,7 +6560,7 @@ and resets the context, as in a browser), `getContext("2d")` (the same
4714
6560
  `display` and any other property, with `setProperty`), `getBoundingClientRect()`,
4715
6561
  `clientWidth`, `clientHeight`, `offsetWidth`, `offsetHeight`, `addEventListener`,
4716
6562
  `removeEventListener` and `dispatchEvent`
4717
- It has no document: there is no `ownerDocument` and no `toDataURL`, and
6563
+ It has no document: there is no `ownerDocument`, and `toDataURL` and `toBlob` exist only after `installImageCodecs()`, and
4718
6564
  `parentNode` is `null`
4719
6565
 
4720
6566
  Pointer events of the control reach the canvas as DOM events: `pointerdown`,
@@ -4785,8 +6631,8 @@ Not tried: the events need a real pointer, which a test must not inject
4785
6631
  | `globalCompositeOperation` of `multiply`, `screen`, `overlay`, `darken`, `lighten`, `color-dodge`, `color-burn`, `hard-light`, `soft-light`, `difference`, `exclusion`, `hue`, `saturation`, `color`, `luminosity` | Win2D blends an effect's inputs, not a shape with the canvas; the value is ignored |
4786
6632
  | `filter` | it is always `none`; use a Win2D effect on the image |
4787
6633
  | `letterSpacing`, `wordSpacing`, `fontKerning`, `fontStretch`, `fontVariantCaps`, `textRendering` | No Win2D equivalent set per draw call |
4788
- | `drawImage` of an `HTMLImageElement`, `ImageBitmap`, `HTMLVideoElement` or `OffscreenCanvas` | There is no DOM; decode with `loadBitmap`, or draw another `CanvasElement` |
4789
- | `toDataURL`, `toBlob`, `transferControlToOffscreen`, `captureStream` | No encoder is exposed on the canvas; `canvas.target.saveAsync` writes a PNG or JPEG file |
6634
+ | `drawImage` of an `HTMLImageElement`, `HTMLVideoElement` or `OffscreenCanvas` | There is no DOM; decode with `loadBitmap`, or draw another `CanvasElement`; an `ImageBitmap` from `winui-svelte/web-apis/images` draws |
6635
+ | `transferControlToOffscreen`, `captureStream` | There is no `OffscreenCanvas` or media stream; `toBlob`, `convertToBlob` and `toDataURL` come with `winui-svelte/web-apis/images` |
4790
6636
  | `getContext` of `webgl`, `webgl2`, `bitmaprenderer`; the `alpha`, `desynchronized` and `willReadFrequently` options | One 2D context, always with an alpha channel |
4791
6637
  | `scrollPathIntoView` | There is no element tree to scroll; the method is absent |
4792
6638
  | `requestAnimationFrame`, `devicePixelRatio`, `document`, `window` | Globals of a browser, defined by the opt-in `winui-svelte/web-apis/timing`, `/screen` and `/page`; `getComputedStyle` has no counterpart |
@@ -4800,6 +6646,78 @@ The working example is `examples/win2d` (`test/win2d.test.ts` runs it in a real
4800
6646
  window and checks the redraw; `src/win2d/win2d.test.ts` draws on a render
4801
6647
  target and checks the pixels)
4802
6648
 
6649
+ ## UI Automation client (`winui-svelte/automation`)
6650
+
6651
+ Read the exact text and headings of another window, instead of OCR; the
6652
+ counterpart of the Accessibility section, which provides automation to
6653
+ others, while this one consumes it; no web API reads another application's
6654
+ window, so this mirrors none; it is opt-in and bundles COM only when imported
6655
+
6656
+ ```ts
6657
+ import { createUiaWorker } from "winui-svelte/automation";
6658
+
6659
+ const worker = createUiaWorker();
6660
+ const text = await worker.readText({
6661
+ target: "foreground",
6662
+ excludeProcessId: process.pid,
6663
+ hardMilliseconds: 1500
6664
+ });
6665
+ // { title, blocks: [{ kind: "heading", level: 1, text }, ...], version, end }
6666
+ ```
6667
+
6668
+ `readText` runs in a worker thread in the multithreaded COM apartment; a target
6669
+ that hangs makes the call reject with `UiaTimeout` after `hardMilliseconds`,
6670
+ the worker is ended and the next call starts a new one (a blocked COM call
6671
+ cannot be cancelled); it resolves null when there is no window to read, the
6672
+ window is the excluded process's or an elevated one
6673
+
6674
+ For the lower level, `withUiaClient` gives a client on the calling thread
6675
+ (call it from a thread that joined a COM apartment) and releases every COM
6676
+ pointer it made when the callback ends:
6677
+
6678
+ ```ts
6679
+ import { UiaControlType, withUiaClient } from "winui-svelte/automation";
6680
+
6681
+ const lines = await withUiaClient(client => {
6682
+ const root = client.elementFromHandle(hwnd);
6683
+ if (root === null) {
6684
+ return [];
6685
+ }
6686
+
6687
+ const found: string[] = [];
6688
+ const walk = client.walk({
6689
+ root,
6690
+ maxElements: 400,
6691
+ maxMilliseconds: 400,
6692
+ shouldVisit: ({ controlType, isOffscreen }) => !isOffscreen && controlType !== UiaControlType.button
6693
+ });
6694
+ for (const node of walk) {
6695
+ const ranges = node.pattern("text")?.visibleRanges() ?? [];
6696
+ found.push(...ranges.map(range => range.getText(1000)));
6697
+ }
6698
+
6699
+ return found;
6700
+ });
6701
+ ```
6702
+
6703
+ | Call | What |
6704
+ |---|---|
6705
+ | `withUiaClient(use)` | creates `CUIAutomation`, runs `use(client)`, releases everything; an element used after that throws `UiaScopeEndedError` |
6706
+ | `client.elementFromHandle(hwnd)`, `client.focusedElement()` | an element, or null when it is gone or cannot be read |
6707
+ | `element.properties()` | `name`, `className`, `automationId`, `controlType`, `processId`, `isOffscreen`, `boundingRectangle`, `headingLevel` (0 for none, 1 to 9), `hasTextPattern`, `hasValuePattern` |
6708
+ | `client.walk({ root, maxElements, maxMilliseconds, shouldVisit })` | breadth first over the control view, one cached call per parent (`FindAllBuildCache`); `walk.end` is `complete`, `maxElements` or `deadline`; an element that went away is skipped; `node.skipSubtree()` prunes |
6709
+ | `element.pattern("text")` | `visibleRanges()`, `documentRange()`, and `range.getText(maxLength)` |
6710
+ | `element.pattern("value")` | `value` |
6711
+ | `readWindowText({ client, root })` | the headings and text of a window, skipping chrome and off screen elements (`UIA_CHROME_CONTROL_TYPES`); `version` changes when the text does |
6712
+ | `createUiaWorker()` | `readText({ target, excludeProcessId, hardMilliseconds, ... })` with the hard deadline; `close()` |
6713
+ | `UiaControlType`, `UiaPropertyId`, `UiaPatternName`, `HEADING_LEVEL_NONE`, `HEADING_LEVEL_FIRST` | the header's ids as `as const` sets and constants (the sets also under `winui-svelte/enums`) |
6714
+ | `UiaWalkEnd`, `TextBlockKind`, `UiaTarget` | the closed sets of a walk's end, a block's kind and a worker target (`foreground`, `focused`, or `{ hwnd }`) |
6715
+ | `UiaElementUnavailableError`, `UiaScopeEndedError`, `UiaTimeout` | the errors: an element went away, a client was used after its scope, a target did not answer in time |
6716
+
6717
+ Elements an app cannot read (elevated windows) come back as null, never an
6718
+ exception; browsers and Electron build their tree when the first client asks,
6719
+ so the first walk of such a window can be slower
6720
+
4803
6721
  ## Windows devices (`winui-svelte/devices`)
4804
6722
 
4805
6723
  Windows' own device APIs (`Windows.Devices.*`, `Windows.System.Power`,