event.ts 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. // Copyright 2019-2024 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. /**
  5. * The event system allows you to emit events to the backend and listen to events from it.
  6. *
  7. * This package is also accessible with `window.__TAURI__.event` when [`app.withGlobalTauri`](https://tauri.app/v1/api/config/#appconfig.withglobaltauri) in `tauri.conf.json` is set to `true`.
  8. * @module
  9. */
  10. import { invoke, transformCallback } from './core'
  11. type EventTarget =
  12. | { kind: 'Any' }
  13. | { kind: 'AnyLabel'; label: string }
  14. | { kind: 'App' }
  15. | { kind: 'Window'; label: string }
  16. | { kind: 'Webview'; label: string }
  17. | { kind: 'WebviewWindow'; label: string }
  18. interface Event<T> {
  19. /** Event name */
  20. event: EventName
  21. /** Event identifier used to unlisten */
  22. id: number
  23. /** Event payload */
  24. payload: T
  25. }
  26. type EventCallback<T> = (event: Event<T>) => void
  27. type UnlistenFn = () => void
  28. type EventName = `${TauriEvent}` | (string & Record<never, never>)
  29. interface Options {
  30. /**
  31. * The event target to listen to, defaults to `{ kind: 'Any' }`, see {@link EventTarget}.
  32. *
  33. * If a string is provided, {@link EventTarget.AnyLabel} is used.
  34. */
  35. target?: string | EventTarget
  36. }
  37. /**
  38. * @since 1.1.0
  39. */
  40. enum TauriEvent {
  41. WINDOW_RESIZED = 'tauri://resize',
  42. WINDOW_MOVED = 'tauri://move',
  43. WINDOW_CLOSE_REQUESTED = 'tauri://close-requested',
  44. WINDOW_DESTROYED = 'tauri://destroyed',
  45. WINDOW_FOCUS = 'tauri://focus',
  46. WINDOW_BLUR = 'tauri://blur',
  47. WINDOW_SCALE_FACTOR_CHANGED = 'tauri://scale-change',
  48. WINDOW_THEME_CHANGED = 'tauri://theme-changed',
  49. WEBVIEW_CREATED = 'tauri://webview-created',
  50. FILE_DROP = 'tauri://file-drop',
  51. FILE_DROP_HOVER = 'tauri://file-drop-hover',
  52. FILE_DROP_CANCELLED = 'tauri://file-drop-cancelled'
  53. }
  54. /**
  55. * Unregister the event listener associated with the given name and id.
  56. *
  57. * @ignore
  58. * @param event The event name
  59. * @param eventId Event identifier
  60. * @returns
  61. */
  62. async function _unlisten(event: string, eventId: number): Promise<void> {
  63. await invoke('plugin:event|unlisten', {
  64. event,
  65. eventId
  66. })
  67. }
  68. /**
  69. * Listen to an emitted event to any {@link EventTarget|target}.
  70. *
  71. * @example
  72. * ```typescript
  73. * import { listen } from '@tauri-apps/api/event';
  74. * const unlisten = await listen<string>('error', (event) => {
  75. * console.log(`Got error, payload: ${event.payload}`);
  76. * });
  77. *
  78. * // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted
  79. * unlisten();
  80. * ```
  81. *
  82. * @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
  83. * @param handler Event handler callback.
  84. * @param options Event listening options.
  85. * @returns A promise resolving to a function to unlisten to the event.
  86. * Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
  87. *
  88. * @since 1.0.0
  89. */
  90. async function listen<T>(
  91. event: EventName,
  92. handler: EventCallback<T>,
  93. options?: Options
  94. ): Promise<UnlistenFn> {
  95. const target: EventTarget =
  96. typeof options?.target === 'string'
  97. ? { kind: 'AnyLabel', label: options.target }
  98. : options?.target ?? { kind: 'Any' }
  99. return invoke<number>('plugin:event|listen', {
  100. event,
  101. target,
  102. handler: transformCallback(handler)
  103. }).then((eventId) => {
  104. return async () => _unlisten(event, eventId)
  105. })
  106. }
  107. /**
  108. * Listens once to an emitted event to any {@link EventTarget|target}.
  109. *
  110. * @example
  111. * ```typescript
  112. * import { once } from '@tauri-apps/api/event';
  113. * interface LoadedPayload {
  114. * loggedIn: boolean,
  115. * token: string
  116. * }
  117. * const unlisten = await once<LoadedPayload>('loaded', (event) => {
  118. * console.log(`App is loaded, loggedIn: ${event.payload.loggedIn}, token: ${event.payload.token}`);
  119. * });
  120. *
  121. * // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted
  122. * unlisten();
  123. * ```
  124. *
  125. * @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
  126. * @param handler Event handler callback.
  127. * @param options Event listening options.
  128. * @returns A promise resolving to a function to unlisten to the event.
  129. * Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
  130. *
  131. * @since 1.0.0
  132. */
  133. async function once<T>(
  134. event: EventName,
  135. handler: EventCallback<T>,
  136. options?: Options
  137. ): Promise<UnlistenFn> {
  138. return listen<T>(
  139. event,
  140. (eventData) => {
  141. handler(eventData)
  142. _unlisten(event, eventData.id).catch(() => {})
  143. },
  144. options
  145. )
  146. }
  147. /**
  148. * Emits an event to all {@link EventTarget|targets}.
  149. *
  150. * @example
  151. * ```typescript
  152. * import { emit } from '@tauri-apps/api/event';
  153. * await emit('frontend-loaded', { loggedIn: true, token: 'authToken' });
  154. * ```
  155. *
  156. * @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
  157. * @param payload Event payload.
  158. *
  159. * @since 1.0.0
  160. */
  161. async function emit(event: string, payload?: unknown): Promise<void> {
  162. await invoke('plugin:event|emit', {
  163. event,
  164. payload
  165. })
  166. }
  167. /**
  168. * Emits an event to all {@link EventTarget|targets} matching the given target.
  169. *
  170. * @example
  171. * ```typescript
  172. * import { emitTo } from '@tauri-apps/api/event';
  173. * await emitTo('main', 'frontend-loaded', { loggedIn: true, token: 'authToken' });
  174. * ```
  175. *
  176. * @param target Label of the target Window/Webview/WebviewWindow or raw {@link EventTarget} object.
  177. * @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
  178. * @param payload Event payload.
  179. *
  180. * @since 1.0.0
  181. */
  182. async function emitTo(
  183. target: EventTarget | string,
  184. event: string,
  185. payload?: unknown
  186. ): Promise<void> {
  187. const eventTarget: EventTarget =
  188. typeof target === 'string' ? { kind: 'AnyLabel', label: target } : target
  189. await invoke('plugin:event|emit_to', {
  190. target: eventTarget,
  191. event,
  192. payload
  193. })
  194. }
  195. export type {
  196. Event,
  197. EventTarget,
  198. EventCallback,
  199. UnlistenFn,
  200. EventName,
  201. Options
  202. }
  203. export { listen, once, emit, emitTo, TauriEvent }