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.
- package/API.md +1941 -23
- package/README.md +31 -4
- package/dist/app/activation/alarm-argument.d.ts +28 -0
- package/dist/app/activation/alarm-argument.d.ts.map +1 -0
- package/dist/app/activation/alarm-argument.js +44 -0
- package/dist/app/activation/alarm-argument.js.map +1 -0
- package/dist/app/activation/classify.d.ts +25 -8
- package/dist/app/activation/classify.d.ts.map +1 -1
- package/dist/app/activation/classify.js +34 -5
- package/dist/app/activation/classify.js.map +1 -1
- package/dist/app/activation/index.d.ts +1 -1
- package/dist/app/activation/index.d.ts.map +1 -1
- package/dist/app/activation/jump-list-argument.d.ts +20 -0
- package/dist/app/activation/jump-list-argument.d.ts.map +1 -0
- package/dist/app/activation/jump-list-argument.js +28 -0
- package/dist/app/activation/jump-list-argument.js.map +1 -0
- package/dist/app/activation/kinds.d.ts +16 -1
- package/dist/app/activation/kinds.d.ts.map +1 -1
- package/dist/app/activation/kinds.js +3 -1
- package/dist/app/activation/kinds.js.map +1 -1
- package/dist/app/activation/receive.d.ts +3 -1
- package/dist/app/activation/receive.d.ts.map +1 -1
- package/dist/app/activation/receive.js +13 -1
- package/dist/app/activation/receive.js.map +1 -1
- package/dist/app/activation/registration.d.ts +14 -0
- package/dist/app/activation/registration.d.ts.map +1 -1
- package/dist/app/activation/registration.js +11 -3
- package/dist/app/activation/registration.js.map +1 -1
- package/dist/app/activation/scheme.d.ts +7 -0
- package/dist/app/activation/scheme.d.ts.map +1 -1
- package/dist/app/activation/scheme.js +10 -1
- package/dist/app/activation/scheme.js.map +1 -1
- package/dist/app/index.d.ts +2 -0
- package/dist/app/index.d.ts.map +1 -1
- package/dist/app/index.js +1 -0
- package/dist/app/index.js.map +1 -1
- package/dist/app/instance-pipe.d.ts.map +1 -1
- package/dist/app/instance-pipe.js +1 -2
- package/dist/app/instance-pipe.js.map +1 -1
- package/dist/app/jump-list/index.d.ts +62 -0
- package/dist/app/jump-list/index.d.ts.map +1 -0
- package/dist/app/jump-list/index.js +51 -0
- package/dist/app/jump-list/index.js.map +1 -0
- package/dist/app/jump-list/native.d.ts +9 -0
- package/dist/app/jump-list/native.d.ts.map +1 -0
- package/dist/app/jump-list/native.js +284 -0
- package/dist/app/jump-list/native.js.map +1 -0
- package/dist/app/jump-list/tasks.d.ts +86 -0
- package/dist/app/jump-list/tasks.d.ts.map +1 -0
- package/dist/app/jump-list/tasks.js +89 -0
- package/dist/app/jump-list/tasks.js.map +1 -0
- package/dist/app/launch-command.d.ts +11 -6
- package/dist/app/launch-command.d.ts.map +1 -1
- package/dist/app/launch-command.js +16 -5
- package/dist/app/launch-command.js.map +1 -1
- package/dist/app/schedule/alarm.d.ts +10 -0
- package/dist/app/schedule/alarm.d.ts.map +1 -0
- package/dist/app/schedule/alarm.js +2 -0
- package/dist/app/schedule/alarm.js.map +1 -0
- package/dist/app/schedule/alarms.d.ts +78 -0
- package/dist/app/schedule/alarms.d.ts.map +1 -0
- package/dist/app/schedule/alarms.js +192 -0
- package/dist/app/schedule/alarms.js.map +1 -0
- package/dist/app/schedule/backend.d.ts +19 -0
- package/dist/app/schedule/backend.d.ts.map +1 -0
- package/dist/app/schedule/backend.js +3 -0
- package/dist/app/schedule/backend.js.map +1 -0
- package/dist/app/schedule/events.d.ts +30 -0
- package/dist/app/schedule/events.d.ts.map +1 -0
- package/dist/app/schedule/events.js +45 -0
- package/dist/app/schedule/events.js.map +1 -0
- package/dist/app/schedule/index.d.ts +7 -0
- package/dist/app/schedule/index.d.ts.map +1 -0
- package/dist/app/schedule/index.js +3 -0
- package/dist/app/schedule/index.js.map +1 -0
- package/dist/app/schedule/native.d.ts +19 -0
- package/dist/app/schedule/native.d.ts.map +1 -0
- package/dist/app/schedule/native.js +74 -0
- package/dist/app/schedule/native.js.map +1 -0
- package/dist/app/schedule/occurrence.d.ts +27 -0
- package/dist/app/schedule/occurrence.d.ts.map +1 -0
- package/dist/app/schedule/occurrence.js +34 -0
- package/dist/app/schedule/occurrence.js.map +1 -0
- package/dist/app/schedule/xml.d.ts +29 -0
- package/dist/app/schedule/xml.d.ts.map +1 -0
- package/dist/app/schedule/xml.js +93 -0
- package/dist/app/schedule/xml.js.map +1 -0
- package/dist/app/shell/app-paths.d.ts +46 -0
- package/dist/app/shell/app-paths.d.ts.map +1 -0
- package/dist/app/shell/app-paths.js +117 -0
- package/dist/app/shell/app-paths.js.map +1 -0
- package/dist/app/shell/backend.d.ts +26 -0
- package/dist/app/shell/backend.d.ts.map +1 -0
- package/dist/app/shell/backend.js +2 -0
- package/dist/app/shell/backend.js.map +1 -0
- package/dist/app/shell/index.d.ts +12 -0
- package/dist/app/shell/index.d.ts.map +1 -0
- package/dist/app/shell/index.js +6 -0
- package/dist/app/shell/index.js.map +1 -0
- package/dist/app/shell/kinds.d.ts +49 -0
- package/dist/app/shell/kinds.d.ts.map +1 -0
- package/dist/app/shell/kinds.js +37 -0
- package/dist/app/shell/kinds.js.map +1 -0
- package/dist/app/shell/native.d.ts +9 -0
- package/dist/app/shell/native.d.ts.map +1 -0
- package/dist/app/shell/native.js +280 -0
- package/dist/app/shell/native.js.map +1 -0
- package/dist/app/shell/open-with.d.ts +31 -0
- package/dist/app/shell/open-with.d.ts.map +1 -0
- package/dist/app/shell/open-with.js +45 -0
- package/dist/app/shell/open-with.js.map +1 -0
- package/dist/app/shell/paths.d.ts +17 -0
- package/dist/app/shell/paths.d.ts.map +1 -0
- package/dist/app/shell/paths.js +27 -0
- package/dist/app/shell/paths.js.map +1 -0
- package/dist/app/shell/shortcut.d.ts +77 -0
- package/dist/app/shell/shortcut.d.ts.map +1 -0
- package/dist/app/shell/shortcut.js +104 -0
- package/dist/app/shell/shortcut.js.map +1 -0
- package/dist/app/shell/trash.d.ts +20 -0
- package/dist/app/shell/trash.d.ts.map +1 -0
- package/dist/app/shell/trash.js +40 -0
- package/dist/app/shell/trash.js.map +1 -0
- package/dist/app/tray-instance.d.ts +39 -0
- package/dist/app/tray-instance.d.ts.map +1 -0
- package/dist/app/tray-instance.js +65 -0
- package/dist/app/tray-instance.js.map +1 -0
- package/dist/automation/backend.d.ts +51 -0
- package/dist/automation/backend.d.ts.map +1 -0
- package/dist/automation/backend.js +5 -0
- package/dist/automation/backend.js.map +1 -0
- package/dist/automation/client.d.ts +97 -0
- package/dist/automation/client.d.ts.map +1 -0
- package/dist/automation/client.js +203 -0
- package/dist/automation/client.js.map +1 -0
- package/dist/automation/ids.d.ts +90 -0
- package/dist/automation/ids.d.ts.map +1 -0
- package/dist/automation/ids.js +84 -0
- package/dist/automation/ids.js.map +1 -0
- package/dist/automation/index.d.ts +13 -0
- package/dist/automation/index.d.ts.map +1 -0
- package/dist/automation/index.js +8 -0
- package/dist/automation/index.js.map +1 -0
- package/dist/automation/native.d.ts +11 -0
- package/dist/automation/native.d.ts.map +1 -0
- package/dist/automation/native.js +595 -0
- package/dist/automation/native.js.map +1 -0
- package/dist/automation/text.d.ts +50 -0
- package/dist/automation/text.d.ts.map +1 -0
- package/dist/automation/text.js +110 -0
- package/dist/automation/text.js.map +1 -0
- package/dist/automation/with-client.d.ts +13 -0
- package/dist/automation/with-client.d.ts.map +1 -0
- package/dist/automation/with-client.js +19 -0
- package/dist/automation/with-client.js.map +1 -0
- package/dist/automation/worker-job.d.ts +32 -0
- package/dist/automation/worker-job.d.ts.map +1 -0
- package/dist/automation/worker-job.js +69 -0
- package/dist/automation/worker-job.js.map +1 -0
- package/dist/automation/worker.d.ts +44 -0
- package/dist/automation/worker.d.ts.map +1 -0
- package/dist/automation/worker.js +70 -0
- package/dist/automation/worker.js.map +1 -0
- package/dist/bindings/.dynwinrt-managed +1 -1
- package/dist/chrome/action/action-types.d.ts +48 -0
- package/dist/chrome/action/action-types.d.ts.map +1 -0
- package/dist/chrome/action/action-types.js +86 -0
- package/dist/chrome/action/action-types.js.map +1 -0
- package/dist/chrome/action/chrome-action.d.ts +117 -0
- package/dist/chrome/action/chrome-action.d.ts.map +1 -0
- package/dist/chrome/action/chrome-action.js +181 -0
- package/dist/chrome/action/chrome-action.js.map +1 -0
- package/dist/chrome/action/create-chrome-action.d.ts +23 -0
- package/dist/chrome/action/create-chrome-action.d.ts.map +1 -0
- package/dist/chrome/action/create-chrome-action.js +24 -0
- package/dist/chrome/action/create-chrome-action.js.map +1 -0
- package/dist/chrome/action/index.d.ts +7 -0
- package/dist/chrome/action/index.d.ts.map +1 -0
- package/dist/chrome/action/index.js +4 -0
- package/dist/chrome/action/index.js.map +1 -0
- package/dist/chrome/commands/chrome-commands.d.ts +62 -0
- package/dist/chrome/commands/chrome-commands.d.ts.map +1 -0
- package/dist/chrome/commands/chrome-commands.js +133 -0
- package/dist/chrome/commands/chrome-commands.js.map +1 -0
- package/dist/chrome/commands/command-types.d.ts +45 -0
- package/dist/chrome/commands/command-types.d.ts.map +1 -0
- package/dist/chrome/commands/command-types.js +27 -0
- package/dist/chrome/commands/command-types.js.map +1 -0
- package/dist/chrome/commands/index.d.ts +7 -0
- package/dist/chrome/commands/index.d.ts.map +1 -0
- package/dist/chrome/commands/index.js +4 -0
- package/dist/chrome/commands/index.js.map +1 -0
- package/dist/chrome/commands/shortcut.d.ts +24 -0
- package/dist/chrome/commands/shortcut.d.ts.map +1 -0
- package/dist/chrome/commands/shortcut.js +86 -0
- package/dist/chrome/commands/shortcut.js.map +1 -0
- package/dist/chrome/context-menus/build-menu.d.ts +26 -0
- package/dist/chrome/context-menus/build-menu.d.ts.map +1 -0
- package/dist/chrome/context-menus/build-menu.js +97 -0
- package/dist/chrome/context-menus/build-menu.js.map +1 -0
- package/dist/chrome/context-menus/chrome-context-menus.d.ts +61 -0
- package/dist/chrome/context-menus/chrome-context-menus.d.ts.map +1 -0
- package/dist/chrome/context-menus/chrome-context-menus.js +219 -0
- package/dist/chrome/context-menus/chrome-context-menus.js.map +1 -0
- package/dist/chrome/context-menus/context-menu-entry.d.ts +20 -0
- package/dist/chrome/context-menus/context-menu-entry.d.ts.map +1 -0
- package/dist/chrome/context-menus/context-menu-entry.js +16 -0
- package/dist/chrome/context-menus/context-menu-entry.js.map +1 -0
- package/dist/chrome/context-menus/context-menu-schema.d.ts +29 -0
- package/dist/chrome/context-menus/context-menu-schema.d.ts.map +1 -0
- package/dist/chrome/context-menus/context-menu-schema.js +38 -0
- package/dist/chrome/context-menus/context-menu-schema.js.map +1 -0
- package/dist/chrome/context-menus/context-menu-types.d.ts +74 -0
- package/dist/chrome/context-menus/context-menu-types.d.ts.map +1 -0
- package/dist/chrome/context-menus/context-menu-types.js +29 -0
- package/dist/chrome/context-menus/context-menu-types.js.map +1 -0
- package/dist/chrome/context-menus/index.d.ts +5 -0
- package/dist/chrome/context-menus/index.d.ts.map +1 -0
- package/dist/chrome/context-menus/index.js +4 -0
- package/dist/chrome/context-menus/index.js.map +1 -0
- package/dist/chrome/i18n/chrome-i18n.d.ts +78 -0
- package/dist/chrome/i18n/chrome-i18n.d.ts.map +1 -0
- package/dist/chrome/i18n/chrome-i18n.js +151 -0
- package/dist/chrome/i18n/chrome-i18n.js.map +1 -0
- package/dist/chrome/i18n/detect-language.d.ts +23 -0
- package/dist/chrome/i18n/detect-language.d.ts.map +1 -0
- package/dist/chrome/i18n/detect-language.js +55 -0
- package/dist/chrome/i18n/detect-language.js.map +1 -0
- package/dist/chrome/i18n/index.d.ts +6 -0
- package/dist/chrome/i18n/index.d.ts.map +1 -0
- package/dist/chrome/i18n/index.js +3 -0
- package/dist/chrome/i18n/index.js.map +1 -0
- package/dist/chrome/i18n/language-defaults.d.ts +17 -0
- package/dist/chrome/i18n/language-defaults.d.ts.map +1 -0
- package/dist/chrome/i18n/language-defaults.js +123 -0
- package/dist/chrome/i18n/language-defaults.js.map +1 -0
- package/dist/chrome/i18n/locale-chain.d.ts +26 -0
- package/dist/chrome/i18n/locale-chain.d.ts.map +1 -0
- package/dist/chrome/i18n/locale-chain.js +38 -0
- package/dist/chrome/i18n/locale-chain.js.map +1 -0
- package/dist/chrome/i18n/message-format.d.ts +14 -0
- package/dist/chrome/i18n/message-format.d.ts.map +1 -0
- package/dist/chrome/i18n/message-format.js +40 -0
- package/dist/chrome/i18n/message-format.js.map +1 -0
- package/dist/chrome/i18n/messages-schema.d.ts +22 -0
- package/dist/chrome/i18n/messages-schema.d.ts.map +1 -0
- package/dist/chrome/i18n/messages-schema.js +48 -0
- package/dist/chrome/i18n/messages-schema.js.map +1 -0
- package/dist/chrome/install.d.ts +47 -0
- package/dist/chrome/install.d.ts.map +1 -0
- package/dist/chrome/install.js +35 -0
- package/dist/chrome/install.js.map +1 -0
- package/dist/chrome/notifications/chrome-notifications.d.ts +69 -0
- package/dist/chrome/notifications/chrome-notifications.d.ts.map +1 -0
- package/dist/chrome/notifications/chrome-notifications.js +201 -0
- package/dist/chrome/notifications/chrome-notifications.js.map +1 -0
- package/dist/chrome/notifications/index.d.ts +5 -0
- package/dist/chrome/notifications/index.d.ts.map +1 -0
- package/dist/chrome/notifications/index.js +4 -0
- package/dist/chrome/notifications/index.js.map +1 -0
- package/dist/chrome/notifications/notification-mapping.d.ts +35 -0
- package/dist/chrome/notifications/notification-mapping.d.ts.map +1 -0
- package/dist/chrome/notifications/notification-mapping.js +47 -0
- package/dist/chrome/notifications/notification-mapping.js.map +1 -0
- package/dist/chrome/notifications/notification-schema.d.ts +50 -0
- package/dist/chrome/notifications/notification-schema.d.ts.map +1 -0
- package/dist/chrome/notifications/notification-schema.js +68 -0
- package/dist/chrome/notifications/notification-schema.js.map +1 -0
- package/dist/chrome/notifications/notification-types.d.ts +50 -0
- package/dist/chrome/notifications/notification-types.d.ts.map +1 -0
- package/dist/chrome/notifications/notification-types.js +13 -0
- package/dist/chrome/notifications/notification-types.js.map +1 -0
- package/dist/chrome/permissions/chrome-permissions.d.ts +82 -0
- package/dist/chrome/permissions/chrome-permissions.d.ts.map +1 -0
- package/dist/chrome/permissions/chrome-permissions.js +190 -0
- package/dist/chrome/permissions/chrome-permissions.js.map +1 -0
- package/dist/chrome/permissions/index.d.ts +6 -0
- package/dist/chrome/permissions/index.d.ts.map +1 -0
- package/dist/chrome/permissions/index.js +4 -0
- package/dist/chrome/permissions/index.js.map +1 -0
- package/dist/chrome/permissions/permission-schema.d.ts +19 -0
- package/dist/chrome/permissions/permission-schema.d.ts.map +1 -0
- package/dist/chrome/permissions/permission-schema.js +60 -0
- package/dist/chrome/permissions/permission-schema.js.map +1 -0
- package/dist/chrome/permissions/permission-table.d.ts +15 -0
- package/dist/chrome/permissions/permission-table.d.ts.map +1 -0
- package/dist/chrome/permissions/permission-table.js +49 -0
- package/dist/chrome/permissions/permission-table.js.map +1 -0
- package/dist/chrome/permissions/permission-types.d.ts +6 -0
- package/dist/chrome/permissions/permission-types.d.ts.map +1 -0
- package/dist/chrome/permissions/permission-types.js +2 -0
- package/dist/chrome/permissions/permission-types.js.map +1 -0
- package/dist/chrome/runtime/identity.d.ts +58 -0
- package/dist/chrome/runtime/identity.d.ts.map +1 -0
- package/dist/chrome/runtime/identity.js +79 -0
- package/dist/chrome/runtime/identity.js.map +1 -0
- package/dist/chrome/runtime/index.d.ts +11 -0
- package/dist/chrome/runtime/index.d.ts.map +1 -0
- package/dist/chrome/runtime/index.js +6 -0
- package/dist/chrome/runtime/index.js.map +1 -0
- package/dist/chrome/runtime/installed.d.ts +47 -0
- package/dist/chrome/runtime/installed.d.ts.map +1 -0
- package/dist/chrome/runtime/installed.js +61 -0
- package/dist/chrome/runtime/installed.js.map +1 -0
- package/dist/chrome/runtime/link.d.ts +62 -0
- package/dist/chrome/runtime/link.d.ts.map +1 -0
- package/dist/chrome/runtime/link.js +154 -0
- package/dist/chrome/runtime/link.js.map +1 -0
- package/dist/chrome/runtime/message-event.d.ts +44 -0
- package/dist/chrome/runtime/message-event.d.ts.map +1 -0
- package/dist/chrome/runtime/message-event.js +95 -0
- package/dist/chrome/runtime/message-event.js.map +1 -0
- package/dist/chrome/runtime/native-host.d.ts +65 -0
- package/dist/chrome/runtime/native-host.d.ts.map +1 -0
- package/dist/chrome/runtime/native-host.js +165 -0
- package/dist/chrome/runtime/native-host.js.map +1 -0
- package/dist/chrome/runtime/native-message.d.ts +35 -0
- package/dist/chrome/runtime/native-message.d.ts.map +1 -0
- package/dist/chrome/runtime/native-message.js +68 -0
- package/dist/chrome/runtime/native-message.js.map +1 -0
- package/dist/chrome/runtime/port.d.ts +59 -0
- package/dist/chrome/runtime/port.d.ts.map +1 -0
- package/dist/chrome/runtime/port.js +84 -0
- package/dist/chrome/runtime/port.js.map +1 -0
- package/dist/chrome/runtime/runtime.d.ts +165 -0
- package/dist/chrome/runtime/runtime.d.ts.map +1 -0
- package/dist/chrome/runtime/runtime.js +244 -0
- package/dist/chrome/runtime/runtime.js.map +1 -0
- package/dist/chrome/storage/chrome-storage.d.ts +43 -0
- package/dist/chrome/storage/chrome-storage.d.ts.map +1 -0
- package/dist/chrome/storage/chrome-storage.js +80 -0
- package/dist/chrome/storage/chrome-storage.js.map +1 -0
- package/dist/chrome/storage/index.d.ts +7 -0
- package/dist/chrome/storage/index.d.ts.map +1 -0
- package/dist/chrome/storage/index.js +4 -0
- package/dist/chrome/storage/index.js.map +1 -0
- package/dist/chrome/storage/storage-area.d.ts +98 -0
- package/dist/chrome/storage/storage-area.d.ts.map +1 -0
- package/dist/chrome/storage/storage-area.js +251 -0
- package/dist/chrome/storage/storage-area.js.map +1 -0
- package/dist/chrome/storage/storage-types.d.ts +91 -0
- package/dist/chrome/storage/storage-types.d.ts.map +1 -0
- package/dist/chrome/storage/storage-types.js +72 -0
- package/dist/chrome/storage/storage-types.js.map +1 -0
- package/dist/chrome/system/create-chrome-system.d.ts +27 -0
- package/dist/chrome/system/create-chrome-system.d.ts.map +1 -0
- package/dist/chrome/system/create-chrome-system.js +25 -0
- package/dist/chrome/system/create-chrome-system.js.map +1 -0
- package/dist/chrome/system/index.d.ts +11 -0
- package/dist/chrome/system/index.d.ts.map +1 -0
- package/dist/chrome/system/index.js +8 -0
- package/dist/chrome/system/index.js.map +1 -0
- package/dist/chrome/system/system-backend.d.ts +50 -0
- package/dist/chrome/system/system-backend.d.ts.map +1 -0
- package/dist/chrome/system/system-backend.js +60 -0
- package/dist/chrome/system/system-backend.js.map +1 -0
- package/dist/chrome/system/system-cpu.d.ts +29 -0
- package/dist/chrome/system/system-cpu.d.ts.map +1 -0
- package/dist/chrome/system/system-cpu.js +43 -0
- package/dist/chrome/system/system-cpu.js.map +1 -0
- package/dist/chrome/system/system-display.d.ts +40 -0
- package/dist/chrome/system/system-display.d.ts.map +1 -0
- package/dist/chrome/system/system-display.js +81 -0
- package/dist/chrome/system/system-display.js.map +1 -0
- package/dist/chrome/system/system-memory.d.ts +17 -0
- package/dist/chrome/system/system-memory.d.ts.map +1 -0
- package/dist/chrome/system/system-memory.js +20 -0
- package/dist/chrome/system/system-memory.js.map +1 -0
- package/dist/chrome/system/system-storage.d.ts +25 -0
- package/dist/chrome/system/system-storage.d.ts.map +1 -0
- package/dist/chrome/system/system-storage.js +29 -0
- package/dist/chrome/system/system-storage.js.map +1 -0
- package/dist/chrome/system/system-types.d.ts +94 -0
- package/dist/chrome/system/system-types.d.ts.map +1 -0
- package/dist/chrome/system/system-types.js +7 -0
- package/dist/chrome/system/system-types.js.map +1 -0
- package/dist/chrome/windows/chrome-windows.d.ts +190 -0
- package/dist/chrome/windows/chrome-windows.d.ts.map +1 -0
- package/dist/chrome/windows/chrome-windows.js +292 -0
- package/dist/chrome/windows/chrome-windows.js.map +1 -0
- package/dist/chrome/windows/create-chrome-windows.d.ts +11 -0
- package/dist/chrome/windows/create-chrome-windows.d.ts.map +1 -0
- package/dist/chrome/windows/create-chrome-windows.js +12 -0
- package/dist/chrome/windows/create-chrome-windows.js.map +1 -0
- package/dist/chrome/windows/index.d.ts +8 -0
- package/dist/chrome/windows/index.d.ts.map +1 -0
- package/dist/chrome/windows/index.js +5 -0
- package/dist/chrome/windows/index.js.map +1 -0
- package/dist/chrome/windows/window-schema.d.ts +54 -0
- package/dist/chrome/windows/window-schema.d.ts.map +1 -0
- package/dist/chrome/windows/window-schema.js +28 -0
- package/dist/chrome/windows/window-schema.js.map +1 -0
- package/dist/chrome/windows/window-surface.d.ts +23 -0
- package/dist/chrome/windows/window-surface.d.ts.map +1 -0
- package/dist/chrome/windows/window-surface.js +2 -0
- package/dist/chrome/windows/window-surface.js.map +1 -0
- package/dist/chrome/windows/window-types.d.ts +68 -0
- package/dist/chrome/windows/window-types.d.ts.map +1 -0
- package/dist/chrome/windows/window-types.js +21 -0
- package/dist/chrome/windows/window-types.js.map +1 -0
- package/dist/chrome/windows/windows-surface.d.ts +30 -0
- package/dist/chrome/windows/windows-surface.d.ts.map +1 -0
- package/dist/chrome/windows/windows-surface.js +105 -0
- package/dist/chrome/windows/windows-surface.js.map +1 -0
- package/dist/components/convert.d.ts +2 -1
- package/dist/components/convert.d.ts.map +1 -1
- package/dist/components/convert.js.map +1 -1
- package/dist/components/hand-written/Window.svelte +2 -0
- package/dist/components/hand-written/items/item-rows.svelte.d.ts +11 -0
- package/dist/components/hand-written/items/item-rows.svelte.d.ts.map +1 -1
- package/dist/components/hand-written/items/item-rows.svelte.js +29 -0
- package/dist/components/hand-written/items/item-rows.svelte.js.map +1 -1
- package/dist/components/hand-written/items/items-host.svelte.d.ts.map +1 -1
- package/dist/components/hand-written/items/items-host.svelte.js +1 -0
- package/dist/components/hand-written/items/items-host.svelte.js.map +1 -1
- package/dist/components/hand-written/items/repeater-host.svelte.d.ts.map +1 -1
- package/dist/components/hand-written/items/repeater-host.svelte.js +1 -0
- package/dist/components/hand-written/items/repeater-host.svelte.js.map +1 -1
- package/dist/components/window-context.d.ts +14 -0
- package/dist/components/window-context.d.ts.map +1 -0
- package/dist/components/window-context.js +20 -0
- package/dist/components/window-context.js.map +1 -0
- package/dist/composition/expression.d.ts +1 -1
- package/dist/data-transfer/clipboard.d.ts +8 -0
- package/dist/data-transfer/clipboard.d.ts.map +1 -1
- package/dist/data-transfer/clipboard.js +6 -0
- package/dist/data-transfer/clipboard.js.map +1 -1
- package/dist/data-transfer/data-transfer.d.ts +17 -0
- package/dist/data-transfer/data-transfer.d.ts.map +1 -1
- package/dist/data-transfer/data-transfer.js +17 -1
- package/dist/data-transfer/data-transfer.js.map +1 -1
- package/dist/data-transfer/drag-effects.d.ts +2 -2
- package/dist/data-transfer/package-io.d.ts +20 -1
- package/dist/data-transfer/package-io.d.ts.map +1 -1
- package/dist/data-transfer/package-io.js +26 -1
- package/dist/data-transfer/package-io.js.map +1 -1
- package/dist/data-transfer/winrt-package.d.ts +5 -0
- package/dist/data-transfer/winrt-package.d.ts.map +1 -1
- package/dist/data-transfer/winrt-package.js +52 -1
- package/dist/data-transfer/winrt-package.js.map +1 -1
- package/dist/downloads/chrome-downloads.d.ts +120 -0
- package/dist/downloads/chrome-downloads.d.ts.map +1 -0
- package/dist/downloads/chrome-downloads.js +389 -0
- package/dist/downloads/chrome-downloads.js.map +1 -0
- package/dist/downloads/chrome-event.d.ts +20 -0
- package/dist/downloads/chrome-event.d.ts.map +1 -0
- package/dist/downloads/chrome-event.js +39 -0
- package/dist/downloads/chrome-event.js.map +1 -0
- package/dist/downloads/download-query.d.ts +14 -0
- package/dist/downloads/download-query.d.ts.map +1 -0
- package/dist/downloads/download-query.js +152 -0
- package/dist/downloads/download-query.js.map +1 -0
- package/dist/downloads/download-record.d.ts +149 -0
- package/dist/downloads/download-record.d.ts.map +1 -0
- package/dist/downloads/download-record.js +142 -0
- package/dist/downloads/download-record.js.map +1 -0
- package/dist/downloads/download-target.d.ts +29 -0
- package/dist/downloads/download-target.d.ts.map +1 -0
- package/dist/downloads/download-target.js +68 -0
- package/dist/downloads/download-target.js.map +1 -0
- package/dist/downloads/download-transfer.d.ts +30 -0
- package/dist/downloads/download-transfer.d.ts.map +1 -0
- package/dist/downloads/download-transfer.js +126 -0
- package/dist/downloads/download-transfer.js.map +1 -0
- package/dist/downloads/download-types.d.ts +214 -0
- package/dist/downloads/download-types.d.ts.map +1 -0
- package/dist/downloads/download-types.js +92 -0
- package/dist/downloads/download-types.js.map +1 -0
- package/dist/downloads/fetch-to-file.d.ts +99 -0
- package/dist/downloads/fetch-to-file.d.ts.map +1 -0
- package/dist/downloads/fetch-to-file.js +188 -0
- package/dist/downloads/fetch-to-file.js.map +1 -0
- package/dist/downloads/index.d.ts +10 -0
- package/dist/downloads/index.d.ts.map +1 -0
- package/dist/downloads/index.js +6 -0
- package/dist/downloads/index.js.map +1 -0
- package/dist/downloads/interrupt-reason.d.ts +12 -0
- package/dist/downloads/interrupt-reason.d.ts.map +1 -0
- package/dist/downloads/interrupt-reason.js +57 -0
- package/dist/downloads/interrupt-reason.js.map +1 -0
- package/dist/downloads/taskbar-progress.d.ts +4 -0
- package/dist/downloads/taskbar-progress.d.ts.map +1 -0
- package/dist/downloads/taskbar-progress.js +2 -0
- package/dist/downloads/taskbar-progress.js.map +1 -0
- package/dist/downloads/zone-identifier.d.ts +21 -0
- package/dist/downloads/zone-identifier.d.ts.map +1 -0
- package/dist/downloads/zone-identifier.js +38 -0
- package/dist/downloads/zone-identifier.js.map +1 -0
- package/dist/enums.d.ts +6 -0
- package/dist/enums.d.ts.map +1 -1
- package/dist/enums.js +6 -0
- package/dist/enums.js.map +1 -1
- package/dist/forms/form-field-props.d.ts +2 -2
- package/dist/incremental/incremental-source.svelte.d.ts +71 -0
- package/dist/incremental/incremental-source.svelte.d.ts.map +1 -0
- package/dist/incremental/incremental-source.svelte.js +138 -0
- package/dist/incremental/incremental-source.svelte.js.map +1 -0
- package/dist/incremental/index.d.ts +5 -0
- package/dist/incremental/index.d.ts.map +1 -0
- package/dist/incremental/index.js +3 -0
- package/dist/incremental/index.js.map +1 -0
- package/dist/incremental/state.d.ts +35 -0
- package/dist/incremental/state.d.ts.map +1 -0
- package/dist/incremental/state.js +12 -0
- package/dist/incremental/state.js.map +1 -0
- package/dist/media/index.d.ts +1 -0
- package/dist/media/index.d.ts.map +1 -1
- package/dist/media/index.js.map +1 -1
- package/dist/picture-source.d.ts +25 -0
- package/dist/picture-source.d.ts.map +1 -0
- package/dist/picture-source.js +2 -0
- package/dist/picture-source.js.map +1 -0
- package/dist/progress/TaskbarProgress.d.svelte.ts +6 -0
- package/dist/progress/TaskbarProgress.svelte +32 -0
- package/dist/progress/aggregate.d.ts +23 -0
- package/dist/progress/aggregate.d.ts.map +1 -0
- package/dist/progress/aggregate.js +59 -0
- package/dist/progress/aggregate.js.map +1 -0
- package/dist/progress/core.d.ts +14 -0
- package/dist/progress/core.d.ts.map +1 -0
- package/dist/progress/core.js +8 -0
- package/dist/progress/core.js.map +1 -0
- package/dist/progress/index.d.ts +5 -0
- package/dist/progress/index.d.ts.map +1 -0
- package/dist/progress/index.js +4 -0
- package/dist/progress/index.js.map +1 -0
- package/dist/progress/progress-event.d.ts +18 -0
- package/dist/progress/progress-event.d.ts.map +1 -0
- package/dist/progress/progress-event.js +19 -0
- package/dist/progress/progress-event.js.map +1 -0
- package/dist/progress/progress-operation.d.ts +163 -0
- package/dist/progress/progress-operation.d.ts.map +1 -0
- package/dist/progress/progress-operation.js +356 -0
- package/dist/progress/progress-operation.js.map +1 -0
- package/dist/progress/progress-registry.d.ts +89 -0
- package/dist/progress/progress-registry.d.ts.map +1 -0
- package/dist/progress/progress-registry.js +187 -0
- package/dist/progress/progress-registry.js.map +1 -0
- package/dist/progress/progress-source.d.ts +46 -0
- package/dist/progress/progress-source.d.ts.map +1 -0
- package/dist/progress/progress-source.js +31 -0
- package/dist/progress/progress-source.js.map +1 -0
- package/dist/progress/progress-state.d.ts +54 -0
- package/dist/progress/progress-state.d.ts.map +1 -0
- package/dist/progress/progress-state.js +35 -0
- package/dist/progress/progress-state.js.map +1 -0
- package/dist/progress/progress-text.d.ts +10 -0
- package/dist/progress/progress-text.d.ts.map +1 -0
- package/dist/progress/progress-text.js +23 -0
- package/dist/progress/progress-text.js.map +1 -0
- package/dist/progress/scoped-source.d.ts +31 -0
- package/dist/progress/scoped-source.d.ts.map +1 -0
- package/dist/progress/scoped-source.js +46 -0
- package/dist/progress/scoped-source.js.map +1 -0
- package/dist/progress/taskbar-progress-props.d.ts +15 -0
- package/dist/progress/taskbar-progress-props.d.ts.map +1 -0
- package/dist/progress/taskbar-progress-props.js +2 -0
- package/dist/progress/taskbar-progress-props.js.map +1 -0
- package/dist/progress/taskbar-progress.d.ts +44 -0
- package/dist/progress/taskbar-progress.d.ts.map +1 -0
- package/dist/progress/taskbar-progress.js +62 -0
- package/dist/progress/taskbar-progress.js.map +1 -0
- package/dist/progress/track-operation.d.ts +36 -0
- package/dist/progress/track-operation.d.ts.map +1 -0
- package/dist/progress/track-operation.js +53 -0
- package/dist/progress/track-operation.js.map +1 -0
- package/dist/renderer/host/host.d.ts.map +1 -1
- package/dist/renderer/host/host.js +11 -14
- package/dist/renderer/host/host.js.map +1 -1
- package/dist/store/states.d.ts +2 -2
- package/dist/store/windows-packages.d.ts +2 -2
- package/dist/store/windows-store.d.ts +2 -2
- package/dist/tray/TrayIcon.d.svelte.ts +14 -2
- package/dist/tray/TrayIcon.svelte +65 -18
- package/dist/tray/TrayMenuFlyout.d.svelte.ts +6 -0
- package/dist/tray/TrayMenuFlyout.svelte +108 -0
- package/dist/tray/balloons.d.ts +7 -0
- package/dist/tray/balloons.d.ts.map +1 -0
- package/dist/tray/balloons.js +53 -0
- package/dist/tray/balloons.js.map +1 -0
- package/dist/tray/bounds.d.ts +7 -0
- package/dist/tray/bounds.d.ts.map +1 -0
- package/dist/tray/bounds.js +15 -0
- package/dist/tray/bounds.js.map +1 -0
- package/dist/tray/flyout-model.d.ts +43 -0
- package/dist/tray/flyout-model.d.ts.map +1 -0
- package/dist/tray/flyout-model.js +55 -0
- package/dist/tray/flyout-model.js.map +1 -0
- package/dist/tray/flyout-picker.d.ts +24 -0
- package/dist/tray/flyout-picker.d.ts.map +1 -0
- package/dist/tray/flyout-picker.js +46 -0
- package/dist/tray/flyout-picker.js.map +1 -0
- package/dist/tray/index.d.ts +3 -0
- package/dist/tray/index.d.ts.map +1 -1
- package/dist/tray/index.js +1 -0
- package/dist/tray/index.js.map +1 -1
- package/dist/tray/menu/default-profile.d.ts +12 -0
- package/dist/tray/menu/default-profile.d.ts.map +1 -0
- package/dist/tray/menu/default-profile.js +17 -0
- package/dist/tray/menu/default-profile.js.map +1 -0
- package/dist/tray/menu/define.d.ts +10 -0
- package/dist/tray/menu/define.d.ts.map +1 -0
- package/dist/tray/menu/define.js +11 -0
- package/dist/tray/menu/define.js.map +1 -0
- package/dist/tray/menu/describe.d.ts +12 -0
- package/dist/tray/menu/describe.d.ts.map +1 -0
- package/dist/tray/menu/describe.js +31 -0
- package/dist/tray/menu/describe.js.map +1 -0
- package/dist/tray/menu/expand.d.ts +20 -0
- package/dist/tray/menu/expand.d.ts.map +1 -0
- package/dist/tray/menu/expand.js +56 -0
- package/dist/tray/menu/expand.js.map +1 -0
- package/dist/tray/menu/index.d.ts +10 -0
- package/dist/tray/menu/index.d.ts.map +1 -0
- package/dist/tray/menu/index.js +9 -0
- package/dist/tray/menu/index.js.map +1 -0
- package/dist/tray/menu/profile-file.d.ts +22 -0
- package/dist/tray/menu/profile-file.d.ts.map +1 -0
- package/dist/tray/menu/profile-file.js +35 -0
- package/dist/tray/menu/profile-file.js.map +1 -0
- package/dist/tray/menu/profile.d.ts +29 -0
- package/dist/tray/menu/profile.d.ts.map +1 -0
- package/dist/tray/menu/profile.js +32 -0
- package/dist/tray/menu/profile.js.map +1 -0
- package/dist/tray/menu/resolve-lite.d.ts +44 -0
- package/dist/tray/menu/resolve-lite.d.ts.map +1 -0
- package/dist/tray/menu/resolve-lite.js +169 -0
- package/dist/tray/menu/resolve-lite.js.map +1 -0
- package/dist/tray/menu/resolve.d.ts +21 -0
- package/dist/tray/menu/resolve.d.ts.map +1 -0
- package/dist/tray/menu/resolve.js +56 -0
- package/dist/tray/menu/resolve.js.map +1 -0
- package/dist/tray/menu/types.d.ts +208 -0
- package/dist/tray/menu/types.d.ts.map +1 -0
- package/dist/tray/menu/types.js +19 -0
- package/dist/tray/menu/types.js.map +1 -0
- package/dist/tray/menu/values.d.ts +14 -0
- package/dist/tray/menu/values.d.ts.map +1 -0
- package/dist/tray/menu/values.js +15 -0
- package/dist/tray/menu/values.js.map +1 -0
- package/dist/tray/menu-svelte/TrayMenu.d.svelte.ts +6 -0
- package/dist/tray/menu-svelte/TrayMenu.svelte +20 -0
- package/dist/tray/menu-svelte/TrayMenuEditor.d.svelte.ts +17 -0
- package/dist/tray/menu-svelte/TrayMenuEditor.svelte +322 -0
- package/dist/tray/menu-svelte/TrayMenuHeader.d.svelte.ts +6 -0
- package/dist/tray/menu-svelte/TrayMenuHeader.svelte +9 -0
- package/dist/tray/menu-svelte/TrayMenuItem.d.svelte.ts +6 -0
- package/dist/tray/menu-svelte/TrayMenuItem.svelte +10 -0
- package/dist/tray/menu-svelte/TrayMenuOperations.d.svelte.ts +6 -0
- package/dist/tray/menu-svelte/TrayMenuOperations.svelte +33 -0
- package/dist/tray/menu-svelte/TrayMenuProgress.d.svelte.ts +6 -0
- package/dist/tray/menu-svelte/TrayMenuProgress.svelte +28 -0
- package/dist/tray/menu-svelte/TrayMenuSeparator.d.svelte.ts +6 -0
- package/dist/tray/menu-svelte/TrayMenuSeparator.svelte +9 -0
- package/dist/tray/menu-svelte/TrayMenuSubmenu.d.svelte.ts +6 -0
- package/dist/tray/menu-svelte/TrayMenuSubmenu.svelte +11 -0
- package/dist/tray/menu-svelte/collect.d.ts +22 -0
- package/dist/tray/menu-svelte/collect.d.ts.map +1 -0
- package/dist/tray/menu-svelte/collect.js +53 -0
- package/dist/tray/menu-svelte/collect.js.map +1 -0
- package/dist/tray/menu-svelte/edit-profile.d.ts +100 -0
- package/dist/tray/menu-svelte/edit-profile.d.ts.map +1 -0
- package/dist/tray/menu-svelte/edit-profile.js +200 -0
- package/dist/tray/menu-svelte/edit-profile.js.map +1 -0
- package/dist/tray/menu-svelte/editor-labels.d.ts +33 -0
- package/dist/tray/menu-svelte/editor-labels.d.ts.map +1 -0
- package/dist/tray/menu-svelte/editor-labels.js +30 -0
- package/dist/tray/menu-svelte/editor-labels.js.map +1 -0
- package/dist/tray/menu-svelte/editor-props.d.ts +22 -0
- package/dist/tray/menu-svelte/editor-props.d.ts.map +1 -0
- package/dist/tray/menu-svelte/editor-props.js +2 -0
- package/dist/tray/menu-svelte/editor-props.js.map +1 -0
- package/dist/tray/menu-svelte/index.d.ts +14 -0
- package/dist/tray/menu-svelte/index.d.ts.map +1 -0
- package/dist/tray/menu-svelte/index.js +11 -0
- package/dist/tray/menu-svelte/index.js.map +1 -0
- package/dist/tray/menu-svelte/menu-node.d.ts +125 -0
- package/dist/tray/menu-svelte/menu-node.d.ts.map +1 -0
- package/dist/tray/menu-svelte/menu-node.js +82 -0
- package/dist/tray/menu-svelte/menu-node.js.map +1 -0
- package/dist/tray/menu-svelte/menu-props.d.ts +51 -0
- package/dist/tray/menu-svelte/menu-props.d.ts.map +1 -0
- package/dist/tray/menu-svelte/menu-props.js +2 -0
- package/dist/tray/menu-svelte/menu-props.js.map +1 -0
- package/dist/tray/menu-svelte/menu-source.d.ts +36 -0
- package/dist/tray/menu-svelte/menu-source.d.ts.map +1 -0
- package/dist/tray/menu-svelte/menu-source.js +54 -0
- package/dist/tray/menu-svelte/menu-source.js.map +1 -0
- package/dist/tray/menu-svelte/operation-ids.d.ts +8 -0
- package/dist/tray/menu-svelte/operation-ids.d.ts.map +1 -0
- package/dist/tray/menu-svelte/operation-ids.js +20 -0
- package/dist/tray/menu-svelte/operation-ids.js.map +1 -0
- package/dist/tray/menu-svelte/preview-lines.d.ts +20 -0
- package/dist/tray/menu-svelte/preview-lines.d.ts.map +1 -0
- package/dist/tray/menu-svelte/preview-lines.js +40 -0
- package/dist/tray/menu-svelte/preview-lines.js.map +1 -0
- package/dist/tray/native.d.ts +36 -8
- package/dist/tray/native.d.ts.map +1 -1
- package/dist/tray/native.js +107 -226
- package/dist/tray/native.js.map +1 -1
- package/dist/tray/pointer-share.d.ts +27 -0
- package/dist/tray/pointer-share.d.ts.map +1 -0
- package/dist/tray/pointer-share.js +61 -0
- package/dist/tray/pointer-share.js.map +1 -0
- package/dist/tray/standalone/define-tray.d.ts +26 -0
- package/dist/tray/standalone/define-tray.d.ts.map +1 -0
- package/dist/tray/standalone/define-tray.js +15 -0
- package/dist/tray/standalone/define-tray.js.map +1 -0
- package/dist/tray/standalone/index.d.ts +14 -4
- package/dist/tray/standalone/index.d.ts.map +1 -1
- package/dist/tray/standalone/index.js +7 -1
- package/dist/tray/standalone/index.js.map +1 -1
- package/dist/tray/standalone/menu-theme.d.ts +38 -0
- package/dist/tray/standalone/menu-theme.d.ts.map +1 -0
- package/dist/tray/standalone/menu-theme.js +74 -0
- package/dist/tray/standalone/menu-theme.js.map +1 -0
- package/dist/tray/standalone/native.d.ts +44 -24
- package/dist/tray/standalone/native.d.ts.map +1 -1
- package/dist/tray/standalone/native.js +148 -76
- package/dist/tray/standalone/native.js.map +1 -1
- package/dist/tray/standalone/standalone-tray.d.ts +56 -19
- package/dist/tray/standalone/standalone-tray.d.ts.map +1 -1
- package/dist/tray/standalone/standalone-tray.js +65 -41
- package/dist/tray/standalone/standalone-tray.js.map +1 -1
- package/dist/tray/themed-icon.d.ts +7 -0
- package/dist/tray/themed-icon.d.ts.map +1 -0
- package/dist/tray/themed-icon.js +39 -0
- package/dist/tray/themed-icon.js.map +1 -0
- package/dist/tray/tray-core.d.ts +11 -10
- package/dist/tray/tray-core.d.ts.map +1 -1
- package/dist/tray/tray-core.js +21 -31
- package/dist/tray/tray-core.js.map +1 -1
- package/dist/tray/tray-extras.d.ts +61 -0
- package/dist/tray/tray-extras.d.ts.map +1 -0
- package/dist/tray/tray-extras.js +2 -0
- package/dist/tray/tray-extras.js.map +1 -0
- package/dist/tray/tray-icon-props.d.ts +18 -5
- package/dist/tray/tray-icon-props.d.ts.map +1 -1
- package/dist/tray/tray-icon.d.ts +4 -2
- package/dist/tray/tray-icon.d.ts.map +1 -1
- package/dist/tray/tray-icon.js +13 -3
- package/dist/tray/tray-icon.js.map +1 -1
- package/dist/tray/tray-manifest.d.ts +58 -0
- package/dist/tray/tray-manifest.d.ts.map +1 -0
- package/dist/tray/tray-manifest.js +66 -0
- package/dist/tray/tray-manifest.js.map +1 -0
- package/dist/tray/tray-menu-flyout-props.d.ts +15 -0
- package/dist/tray/tray-menu-flyout-props.d.ts.map +1 -0
- package/dist/tray/tray-menu-flyout-props.js +2 -0
- package/dist/tray/tray-menu-flyout-props.js.map +1 -0
- package/dist/tray/tray-menu.d.ts +2 -2
- package/dist/tray/tray-menu.d.ts.map +1 -1
- package/dist/vite/build.d.ts +5 -1
- package/dist/vite/build.d.ts.map +1 -1
- package/dist/vite/build.js +26 -5
- package/dist/vite/build.js.map +1 -1
- package/dist/vite/entrypoints/build-tray.d.ts +29 -0
- package/dist/vite/entrypoints/build-tray.d.ts.map +1 -0
- package/dist/vite/entrypoints/build-tray.js +72 -0
- package/dist/vite/entrypoints/build-tray.js.map +1 -0
- package/dist/vite/entrypoints/discover.d.ts +30 -0
- package/dist/vite/entrypoints/discover.d.ts.map +1 -0
- package/dist/vite/entrypoints/discover.js +61 -0
- package/dist/vite/entrypoints/discover.js.map +1 -0
- package/dist/vite/entrypoints/extract-tray.d.ts +15 -0
- package/dist/vite/entrypoints/extract-tray.d.ts.map +1 -0
- package/dist/vite/entrypoints/extract-tray.js +103 -0
- package/dist/vite/entrypoints/extract-tray.js.map +1 -0
- package/dist/vite/entrypoints/lower-menu-markup.d.ts +40 -0
- package/dist/vite/entrypoints/lower-menu-markup.d.ts.map +1 -0
- package/dist/vite/entrypoints/lower-menu-markup.js +339 -0
- package/dist/vite/entrypoints/lower-menu-markup.js.map +1 -0
- package/dist/vite/entrypoints/lower-tray-svelte.d.ts +14 -0
- package/dist/vite/entrypoints/lower-tray-svelte.d.ts.map +1 -0
- package/dist/vite/entrypoints/lower-tray-svelte.js +259 -0
- package/dist/vite/entrypoints/lower-tray-svelte.js.map +1 -0
- package/dist/vite/entrypoints/node-span.d.ts +13 -0
- package/dist/vite/entrypoints/node-span.d.ts.map +1 -0
- package/dist/vite/entrypoints/node-span.js +32 -0
- package/dist/vite/entrypoints/node-span.js.map +1 -0
- package/dist/vite/entrypoints/tray-dev-plugin.d.ts +9 -0
- package/dist/vite/entrypoints/tray-dev-plugin.d.ts.map +1 -0
- package/dist/vite/entrypoints/tray-dev-plugin.js +102 -0
- package/dist/vite/entrypoints/tray-dev-plugin.js.map +1 -0
- package/dist/vite/entrypoints/tray-module.d.ts +23 -0
- package/dist/vite/entrypoints/tray-module.d.ts.map +1 -0
- package/dist/vite/entrypoints/tray-module.js +58 -0
- package/dist/vite/entrypoints/tray-module.js.map +1 -0
- package/dist/vite/entrypoints/tray-process.d.ts +39 -0
- package/dist/vite/entrypoints/tray-process.d.ts.map +1 -0
- package/dist/vite/entrypoints/tray-process.js +59 -0
- package/dist/vite/entrypoints/tray-process.js.map +1 -0
- package/dist/vite/entrypoints/tray-source.d.ts +11 -0
- package/dist/vite/entrypoints/tray-source.d.ts.map +1 -0
- package/dist/vite/entrypoints/tray-source.js +20 -0
- package/dist/vite/entrypoints/tray-source.js.map +1 -0
- package/dist/vite/entrypoints/tray-svelte-error.d.ts +14 -0
- package/dist/vite/entrypoints/tray-svelte-error.d.ts.map +1 -0
- package/dist/vite/entrypoints/tray-svelte-error.js +22 -0
- package/dist/vite/entrypoints/tray-svelte-error.js.map +1 -0
- package/dist/vite/externals.d.ts +7 -0
- package/dist/vite/externals.d.ts.map +1 -0
- package/dist/vite/externals.js +18 -0
- package/dist/vite/externals.js.map +1 -0
- package/dist/vite/plugin.d.ts.map +1 -1
- package/dist/vite/plugin.js +3 -12
- package/dist/vite/plugin.js.map +1 -1
- package/dist/web-apis/clipboard.d.ts.map +1 -1
- package/dist/web-apis/clipboard.js +48 -17
- package/dist/web-apis/clipboard.js.map +1 -1
- package/dist/web-apis/dialog-types.d.ts +81 -0
- package/dist/web-apis/dialog-types.d.ts.map +1 -0
- package/dist/web-apis/dialog-types.js +14 -0
- package/dist/web-apis/dialog-types.js.map +1 -0
- package/dist/web-apis/dialogs-windows.d.ts +25 -0
- package/dist/web-apis/dialogs-windows.d.ts.map +1 -0
- package/dist/web-apis/dialogs-windows.js +114 -0
- package/dist/web-apis/dialogs-windows.js.map +1 -0
- package/dist/web-apis/dialogs.d.ts +76 -0
- package/dist/web-apis/dialogs.d.ts.map +1 -0
- package/dist/web-apis/dialogs.js +250 -0
- package/dist/web-apis/dialogs.js.map +1 -0
- package/dist/web-apis/file-read.d.ts +14 -0
- package/dist/web-apis/file-read.d.ts.map +1 -0
- package/dist/web-apis/file-read.js +37 -0
- package/dist/web-apis/file-read.js.map +1 -0
- package/dist/web-apis/file-system.d.ts +9 -0
- package/dist/web-apis/file-system.d.ts.map +1 -1
- package/dist/web-apis/file-system.js +24 -0
- package/dist/web-apis/file-system.js.map +1 -1
- package/dist/web-apis/geolocation.d.ts.map +1 -1
- package/dist/web-apis/geolocation.js +14 -8
- package/dist/web-apis/geolocation.js.map +1 -1
- package/dist/web-apis/idle.d.ts +1 -1
- package/dist/web-apis/image-codec-windows.d.ts +24 -0
- package/dist/web-apis/image-codec-windows.d.ts.map +1 -0
- package/dist/web-apis/image-codec-windows.js +107 -0
- package/dist/web-apis/image-codec-windows.js.map +1 -0
- package/dist/web-apis/image-pixels.d.ts +27 -0
- package/dist/web-apis/image-pixels.d.ts.map +1 -0
- package/dist/web-apis/image-pixels.js +152 -0
- package/dist/web-apis/image-pixels.js.map +1 -0
- package/dist/web-apis/image-types.d.ts +64 -0
- package/dist/web-apis/image-types.d.ts.map +1 -0
- package/dist/web-apis/image-types.js +23 -0
- package/dist/web-apis/image-types.js.map +1 -0
- package/dist/web-apis/images.d.ts +199 -0
- package/dist/web-apis/images.d.ts.map +1 -0
- package/dist/web-apis/images.js +476 -0
- package/dist/web-apis/images.js.map +1 -0
- package/dist/web-apis/media-access.d.ts +1 -1
- package/dist/web-apis/notification.d.ts +6 -5
- package/dist/web-apis/notification.d.ts.map +1 -1
- package/dist/web-apis/notification.js.map +1 -1
- package/dist/web-apis/page.d.ts +1 -1
- package/dist/web-apis/permissions.d.ts +17 -0
- package/dist/web-apis/permissions.d.ts.map +1 -1
- package/dist/web-apis/permissions.js +25 -0
- package/dist/web-apis/permissions.js.map +1 -1
- package/dist/web-apis/png-writer.d.ts +9 -0
- package/dist/web-apis/png-writer.d.ts.map +1 -0
- package/dist/web-apis/png-writer.js +58 -0
- package/dist/web-apis/png-writer.js.map +1 -0
- package/dist/web-apis/push.d.ts +1 -1
- package/dist/web-apis/scroll-timeline.d.ts +1 -1
- package/dist/win32-calls.d.ts +32 -0
- package/dist/win32-calls.d.ts.map +1 -1
- package/dist/win32-calls.js +44 -0
- package/dist/win32-calls.js.map +1 -1
- package/dist/win32-foreground.d.ts +14 -0
- package/dist/win32-foreground.d.ts.map +1 -0
- package/dist/win32-foreground.js +71 -0
- package/dist/win32-foreground.js.map +1 -0
- package/dist/win32-icons.d.ts.map +1 -1
- package/dist/win32-icons.js +11 -31
- package/dist/win32-icons.js.map +1 -1
- package/dist/window/create-window.d.ts +4 -1
- package/dist/window/create-window.d.ts.map +1 -1
- package/dist/window/create-window.js +2 -0
- package/dist/window/create-window.js.map +1 -1
- package/dist/window/foreground-filter.d.ts +71 -0
- package/dist/window/foreground-filter.d.ts.map +1 -0
- package/dist/window/foreground-filter.js +108 -0
- package/dist/window/foreground-filter.js.map +1 -0
- package/dist/window/foreground-native.d.ts +25 -0
- package/dist/window/foreground-native.d.ts.map +1 -0
- package/dist/window/foreground-native.js +88 -0
- package/dist/window/foreground-native.js.map +1 -0
- package/dist/window/foreground.d.ts +49 -0
- package/dist/window/foreground.d.ts.map +1 -0
- package/dist/window/foreground.js +78 -0
- package/dist/window/foreground.js.map +1 -0
- package/dist/window/taskbar-calls.d.ts +28 -0
- package/dist/window/taskbar-calls.d.ts.map +1 -1
- package/dist/window/taskbar-calls.js +34 -0
- package/dist/window/taskbar-calls.js.map +1 -1
- package/dist/window/taskbar-native.d.ts.map +1 -1
- package/dist/window/taskbar-native.js +35 -1
- package/dist/window/taskbar-native.js.map +1 -1
- package/dist/window/taskbar.d.ts +34 -5
- package/dist/window/taskbar.d.ts.map +1 -1
- package/dist/window/taskbar.js +28 -3
- package/dist/window/taskbar.js.map +1 -1
- package/dist/window/window-host.svelte.d.ts +3 -2
- package/dist/window/window-host.svelte.d.ts.map +1 -1
- package/dist/window/window-host.svelte.js.map +1 -1
- package/dist/window/window-state.d.ts +1 -1
- package/dist/winui.d.ts +7 -0
- package/dist/winui.d.ts.map +1 -1
- package/dist/winui.js +7 -0
- package/dist/winui.js.map +1 -1
- package/package.json +100 -1
- package/src/app/activation/alarm-argument.ts +55 -0
- package/src/app/activation/classify.ts +36 -5
- package/src/app/activation/index.ts +1 -1
- package/src/app/activation/jump-list-argument.ts +30 -0
- package/src/app/activation/kinds.ts +24 -2
- package/src/app/activation/receive.ts +15 -1
- package/src/app/activation/registration.ts +11 -3
- package/src/app/activation/scheme.ts +11 -1
- package/src/app/index.ts +2 -0
- package/src/app/instance-pipe.ts +1 -3
- package/src/app/jump-list/index.ts +100 -0
- package/src/app/jump-list/native.ts +309 -0
- package/src/app/jump-list/tasks.ts +166 -0
- package/src/app/launch-command.ts +19 -5
- package/src/app/schedule/alarm.ts +11 -0
- package/src/app/schedule/alarms.ts +240 -0
- package/src/app/schedule/backend.ts +23 -0
- package/src/app/schedule/events.ts +67 -0
- package/src/app/schedule/index.ts +6 -0
- package/src/app/schedule/native.ts +78 -0
- package/src/app/schedule/occurrence.ts +45 -0
- package/src/app/schedule/xml.ts +115 -0
- package/src/app/shell/app-paths.ts +145 -0
- package/src/app/shell/backend.ts +30 -0
- package/src/app/shell/index.ts +11 -0
- package/src/app/shell/kinds.ts +52 -0
- package/src/app/shell/native.ts +336 -0
- package/src/app/shell/open-with.ts +62 -0
- package/src/app/shell/paths.ts +29 -0
- package/src/app/shell/shortcut.ts +163 -0
- package/src/app/shell/trash.ts +53 -0
- package/src/app/tray-instance.ts +77 -0
- package/src/automation/backend.ts +56 -0
- package/src/automation/client.ts +327 -0
- package/src/automation/ids.ts +97 -0
- package/src/automation/index.ts +23 -0
- package/src/automation/native.ts +689 -0
- package/src/automation/text.ts +174 -0
- package/src/automation/with-client.ts +20 -0
- package/src/automation/worker-job.ts +97 -0
- package/src/automation/worker.ts +116 -0
- package/src/chrome/action/action-types.ts +123 -0
- package/src/chrome/action/chrome-action.ts +234 -0
- package/src/chrome/action/create-chrome-action.ts +35 -0
- package/src/chrome/action/index.ts +13 -0
- package/src/chrome/commands/chrome-commands.ts +174 -0
- package/src/chrome/commands/command-types.ts +48 -0
- package/src/chrome/commands/index.ts +6 -0
- package/src/chrome/commands/shortcut.ts +107 -0
- package/src/chrome/context-menus/build-menu.ts +121 -0
- package/src/chrome/context-menus/chrome-context-menus.ts +255 -0
- package/src/chrome/context-menus/context-menu-entry.ts +34 -0
- package/src/chrome/context-menus/context-menu-schema.ts +48 -0
- package/src/chrome/context-menus/context-menu-types.ts +94 -0
- package/src/chrome/context-menus/index.ts +4 -0
- package/src/chrome/i18n/chrome-i18n.ts +197 -0
- package/src/chrome/i18n/detect-language.ts +67 -0
- package/src/chrome/i18n/index.ts +5 -0
- package/src/chrome/i18n/language-defaults.ts +167 -0
- package/src/chrome/i18n/locale-chain.ts +44 -0
- package/src/chrome/i18n/message-format.ts +60 -0
- package/src/chrome/i18n/messages-schema.ts +61 -0
- package/src/chrome/install.ts +75 -0
- package/src/chrome/notifications/chrome-notifications.ts +249 -0
- package/src/chrome/notifications/index.ts +8 -0
- package/src/chrome/notifications/notification-mapping.ts +63 -0
- package/src/chrome/notifications/notification-schema.ts +80 -0
- package/src/chrome/notifications/notification-types.ts +60 -0
- package/src/chrome/permissions/chrome-permissions.ts +259 -0
- package/src/chrome/permissions/index.ts +5 -0
- package/src/chrome/permissions/permission-schema.ts +75 -0
- package/src/chrome/permissions/permission-table.ts +54 -0
- package/src/chrome/permissions/permission-types.ts +5 -0
- package/src/chrome/runtime/identity.ts +115 -0
- package/src/chrome/runtime/index.ts +10 -0
- package/src/chrome/runtime/installed.ts +85 -0
- package/src/chrome/runtime/link.ts +211 -0
- package/src/chrome/runtime/message-event.ts +126 -0
- package/src/chrome/runtime/native-host.ts +220 -0
- package/src/chrome/runtime/native-message.ts +78 -0
- package/src/chrome/runtime/port.ts +117 -0
- package/src/chrome/runtime/runtime.ts +317 -0
- package/src/chrome/storage/chrome-storage.ts +120 -0
- package/src/chrome/storage/index.ts +13 -0
- package/src/chrome/storage/storage-area.ts +318 -0
- package/src/chrome/storage/storage-types.ts +115 -0
- package/src/chrome/system/create-chrome-system.ts +32 -0
- package/src/chrome/system/index.ts +21 -0
- package/src/chrome/system/system-backend.ts +88 -0
- package/src/chrome/system/system-cpu.ts +49 -0
- package/src/chrome/system/system-display.ts +94 -0
- package/src/chrome/system/system-memory.ts +24 -0
- package/src/chrome/system/system-storage.ts +33 -0
- package/src/chrome/system/system-types.ts +112 -0
- package/src/chrome/windows/chrome-windows.ts +372 -0
- package/src/chrome/windows/create-chrome-windows.ts +13 -0
- package/src/chrome/windows/index.ts +7 -0
- package/src/chrome/windows/window-schema.ts +32 -0
- package/src/chrome/windows/window-surface.ts +27 -0
- package/src/chrome/windows/window-types.ts +80 -0
- package/src/chrome/windows/windows-surface.ts +114 -0
- package/src/components/convert.ts +2 -1
- package/src/components/hand-written/items/item-rows.svelte.ts +37 -0
- package/src/components/hand-written/items/items-host.svelte.ts +2 -0
- package/src/components/hand-written/items/repeater-host.svelte.ts +1 -0
- package/src/components/window-context.ts +23 -0
- package/src/data-transfer/clipboard.ts +15 -0
- package/src/data-transfer/data-transfer.ts +29 -1
- package/src/data-transfer/package-io.ts +36 -2
- package/src/data-transfer/winrt-package.ts +65 -1
- package/src/downloads/chrome-downloads.ts +474 -0
- package/src/downloads/chrome-event.ts +42 -0
- package/src/downloads/download-query.ts +204 -0
- package/src/downloads/download-record.ts +177 -0
- package/src/downloads/download-target.ts +79 -0
- package/src/downloads/download-transfer.ts +160 -0
- package/src/downloads/download-types.ts +176 -0
- package/src/downloads/fetch-to-file.ts +276 -0
- package/src/downloads/index.ts +22 -0
- package/src/downloads/interrupt-reason.ts +64 -0
- package/src/downloads/taskbar-progress.ts +4 -0
- package/src/downloads/zone-identifier.ts +42 -0
- package/src/enums.ts +6 -0
- package/src/incremental/incremental-source.svelte.ts +181 -0
- package/src/incremental/index.ts +4 -0
- package/src/incremental/state.ts +33 -0
- package/src/media/index.ts +1 -0
- package/src/picture-source.ts +26 -0
- package/src/progress/TaskbarProgress.d.svelte.ts +6 -0
- package/src/progress/aggregate.ts +68 -0
- package/src/progress/core.ts +13 -0
- package/src/progress/index.ts +4 -0
- package/src/progress/progress-event.ts +25 -0
- package/src/progress/progress-operation.ts +469 -0
- package/src/progress/progress-registry.ts +224 -0
- package/src/progress/progress-source.ts +66 -0
- package/src/progress/progress-state.ts +72 -0
- package/src/progress/progress-text.ts +27 -0
- package/src/progress/scoped-source.ts +56 -0
- package/src/progress/taskbar-progress-props.ts +18 -0
- package/src/progress/taskbar-progress.ts +80 -0
- package/src/progress/track-operation.ts +81 -0
- package/src/renderer/host/host.ts +12 -15
- package/src/tray/TrayIcon.d.svelte.ts +14 -2
- package/src/tray/TrayMenuFlyout.d.svelte.ts +6 -0
- package/src/tray/balloons.ts +58 -0
- package/src/tray/bounds.ts +16 -0
- package/src/tray/flyout-model.ts +77 -0
- package/src/tray/flyout-picker.ts +56 -0
- package/src/tray/index.ts +3 -0
- package/src/tray/menu/default-profile.ts +20 -0
- package/src/tray/menu/define.ts +12 -0
- package/src/tray/menu/describe.ts +39 -0
- package/src/tray/menu/expand.ts +75 -0
- package/src/tray/menu/index.ts +30 -0
- package/src/tray/menu/profile-file.ts +44 -0
- package/src/tray/menu/profile.ts +39 -0
- package/src/tray/menu/resolve-lite.ts +226 -0
- package/src/tray/menu/resolve.ts +72 -0
- package/src/tray/menu/types.ts +270 -0
- package/src/tray/menu/values.ts +21 -0
- package/src/tray/menu-svelte/TrayMenu.d.svelte.ts +6 -0
- package/src/tray/menu-svelte/TrayMenuEditor.d.svelte.ts +17 -0
- package/src/tray/menu-svelte/TrayMenuHeader.d.svelte.ts +6 -0
- package/src/tray/menu-svelte/TrayMenuItem.d.svelte.ts +6 -0
- package/src/tray/menu-svelte/TrayMenuOperations.d.svelte.ts +6 -0
- package/src/tray/menu-svelte/TrayMenuProgress.d.svelte.ts +6 -0
- package/src/tray/menu-svelte/TrayMenuSeparator.d.svelte.ts +6 -0
- package/src/tray/menu-svelte/TrayMenuSubmenu.d.svelte.ts +6 -0
- package/src/tray/menu-svelte/collect.ts +58 -0
- package/src/tray/menu-svelte/edit-profile.ts +263 -0
- package/src/tray/menu-svelte/editor-labels.ts +54 -0
- package/src/tray/menu-svelte/editor-props.ts +27 -0
- package/src/tray/menu-svelte/index.ts +21 -0
- package/src/tray/menu-svelte/menu-node.ts +119 -0
- package/src/tray/menu-svelte/menu-props.ts +72 -0
- package/src/tray/menu-svelte/menu-source.ts +83 -0
- package/src/tray/menu-svelte/operation-ids.ts +21 -0
- package/src/tray/menu-svelte/preview-lines.ts +58 -0
- package/src/tray/native.ts +134 -242
- package/src/tray/pointer-share.ts +71 -0
- package/src/tray/standalone/define-tray.ts +36 -0
- package/src/tray/standalone/index.ts +19 -6
- package/src/tray/standalone/menu-theme.ts +90 -0
- package/src/tray/standalone/native.ts +180 -106
- package/src/tray/standalone/standalone-tray.ts +146 -66
- package/src/tray/themed-icon.ts +48 -0
- package/src/tray/tray-core.ts +37 -43
- package/src/tray/tray-extras.ts +71 -0
- package/src/tray/tray-icon-props.ts +20 -5
- package/src/tray/tray-icon.ts +16 -4
- package/src/tray/tray-manifest.ts +74 -0
- package/src/tray/tray-menu-flyout-props.ts +17 -0
- package/src/tray/tray-menu.ts +2 -2
- package/src/vite/build.ts +35 -7
- package/src/vite/entrypoints/build-tray.ts +92 -0
- package/src/vite/entrypoints/discover.ts +75 -0
- package/src/vite/entrypoints/extract-tray.ts +125 -0
- package/src/vite/entrypoints/lower-menu-markup.ts +443 -0
- package/src/vite/entrypoints/lower-tray-svelte.ts +329 -0
- package/src/vite/entrypoints/node-span.ts +36 -0
- package/src/vite/entrypoints/tray-dev-plugin.ts +111 -0
- package/src/vite/entrypoints/tray-module.ts +63 -0
- package/src/vite/entrypoints/tray-process.ts +83 -0
- package/src/vite/entrypoints/tray-source.ts +21 -0
- package/src/vite/entrypoints/tray-svelte-error.ts +31 -0
- package/src/vite/externals.ts +19 -0
- package/src/vite/plugin.ts +3 -14
- package/src/web-apis/clipboard.ts +63 -16
- package/src/web-apis/dialog-types.ts +99 -0
- package/src/web-apis/dialogs-windows.ts +144 -0
- package/src/web-apis/dialogs.ts +312 -0
- package/src/web-apis/file-read.ts +43 -0
- package/src/web-apis/file-system.ts +33 -0
- package/src/web-apis/geolocation.ts +14 -8
- package/src/web-apis/image-codec-windows.ts +140 -0
- package/src/web-apis/image-pixels.ts +191 -0
- package/src/web-apis/image-types.ts +74 -0
- package/src/web-apis/images.ts +697 -0
- package/src/web-apis/notification.ts +5 -4
- package/src/web-apis/permissions.ts +31 -0
- package/src/web-apis/png-writer.ts +66 -0
- package/src/win32-calls.ts +86 -0
- package/src/win32-foreground.ts +76 -0
- package/src/win32-icons.ts +11 -31
- package/src/window/create-window.ts +7 -0
- package/src/window/foreground-filter.ts +167 -0
- package/src/window/foreground-native.ts +93 -0
- package/src/window/foreground.ts +106 -0
- package/src/window/taskbar-calls.ts +47 -0
- package/src/window/taskbar-native.ts +42 -0
- package/src/window/taskbar.ts +55 -6
- package/src/window/window-host.svelte.ts +3 -2
- package/src/winui.ts +7 -0
- 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/
|
|
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/
|
|
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,
|
|
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)
|
|
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
|
-
-
|
|
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
|
-
|
|
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:
|
|
2881
|
-
{ kind:
|
|
2882
|
-
{ kind:
|
|
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`)
|
|
2890
|
-
|
|
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
|
-
|
|
2896
|
-
|
|
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
|
-
|
|
2899
|
-
|
|
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
|
|
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
|
|
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
|
|
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`, `
|
|
4789
|
-
| `
|
|
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`,
|