Skip to main content

fission_core/
lib.rs

1//! # fission-core
2//!
3//! The runtime, widget system, and action/reducer architecture for the Fission UI
4//! framework.
5//!
6//! `fission-core` provides:
7//!
8//! - A **declarative widget tree** built from composable primitives ([`Widget`]).
9//! - A **unidirectional data-flow** pipeline: [`Action`] -> [`Runtime::dispatch`] -> reducer
10//!   -> mutated [`GlobalState`].
11//! - An **effect system** for async side-effects ([`Effect`], [`RuntimeEffect`]).
12//! - Built-in widgets: [`Button`], [`Text`], [`TextInput`], [`Container`], [`Row`],
13//!   [`Column`], [`Scroll`], [`ZStack`], [`Grid`], [`LazyColumn`], and more.
14//!
15//! ## Getting started
16//!
17//! ```rust,ignore
18//! use fission_core::*;
19//! use fission_core::ui::*;
20//!
21//! // Define application state
22//! #[derive(Debug, Default)]
23//! struct MyState { value: String }
24//! impl GlobalState for MyState {}
25//!
26//! // Build a widget tree value
27//! struct MyWidget;
28//! impl From<MyWidget> for Widget {
29//!     fn from(_: MyWidget) -> Widget {
30//!         let (_, view) = fission_core::build::current::<MyState>();
31//!         Text::new(&*view.state().value).into()
32//!     }
33//! }
34//! ```
35
36use anyhow::Result;
37use lazy_static::lazy_static;
38use std::any::TypeId;
39use std::collections::HashMap;
40
41extern crate self as fission_core;
42
43pub mod action;
44pub mod async_runtime;
45pub mod build;
46mod build_context;
47pub mod capability; // New
48pub mod context; // New
49pub mod diff;
50pub mod effect; // New
51pub mod env;
52pub mod event;
53pub mod hit_test;
54pub mod input;
55pub(crate) mod lowering;
56pub mod media;
57pub mod platform;
58pub mod platform_barcode;
59pub mod platform_biometric;
60pub mod platform_bluetooth;
61pub mod platform_camera;
62pub mod platform_clipboard;
63pub mod platform_geolocation;
64pub mod platform_haptics;
65pub mod platform_microphone;
66pub mod platform_nfc;
67pub mod platform_passkey;
68pub mod platform_volume;
69pub mod platform_wifi;
70pub mod registry;
71pub mod runtime;
72pub mod scrollbar;
73pub mod state;
74pub mod time;
75pub mod ui;
76
77pub mod view;
78
79#[doc(hidden)]
80/// Framework integration boundary for first-party shells, renderers, test
81/// harnesses, and generated widget implementations.
82///
83/// This module is not part of the application authoring API. Application code
84/// should construct `Widget` values from widget structs and components instead
85/// of calling lowering helpers directly.
86pub mod internal {
87    pub use crate::build_context::BuildCtx;
88    pub use crate::lowering::{
89        build_layout_tree, wrap_zstack_child, InternalIrBuilder, InternalLoweringCx,
90    };
91    use crate::Widget;
92    use fission_ir::WidgetId;
93
94    pub fn custom_render_widget(node: InternalRenderNode) -> Widget {
95        Widget::custom(node)
96    }
97
98    pub fn lower_widget(widget: &Widget, cx: &mut InternalLoweringCx) -> WidgetId {
99        widget.lower(cx)
100    }
101
102    pub fn lower_widget_to_ir(widget: &Widget) -> fission_ir::CoreIR {
103        let env = crate::Env::default();
104        let runtime_state = crate::RuntimeState::default();
105        let mut cx = InternalLoweringCx::new(&env, &runtime_state, None, None);
106        widget.lower(&mut cx);
107        cx.ir
108    }
109
110    pub fn widget_kind_name(widget: &Widget) -> &'static str {
111        widget.kind_name()
112    }
113
114    pub fn widget_as_row(widget: &Widget) -> Option<&crate::ui::Row> {
115        widget.as_row()
116    }
117
118    pub fn widget_as_column(widget: &Widget) -> Option<&crate::ui::Column> {
119        widget.as_column()
120    }
121
122    pub fn widget_as_container(widget: &Widget) -> Option<&crate::ui::Container> {
123        widget.as_container()
124    }
125
126    pub fn widget_as_scroll(widget: &Widget) -> Option<&crate::ui::Scroll> {
127        widget.as_scroll()
128    }
129
130    pub fn widget_as_rich_text(widget: &Widget) -> Option<&crate::ui::RichText> {
131        widget.as_rich_text()
132    }
133
134    pub fn widget_as_text(widget: &Widget) -> Option<&crate::ui::Text> {
135        widget.as_text()
136    }
137
138    pub fn widget_as_text_input(widget: &Widget) -> Option<&crate::ui::TextInput> {
139        widget.as_text_input()
140    }
141
142    pub fn widget_as_button(widget: &Widget) -> Option<&crate::ui::Button> {
143        widget.as_button()
144    }
145
146    pub fn widget_as_gesture_detector(widget: &Widget) -> Option<&crate::ui::GestureDetector> {
147        widget.as_gesture_detector()
148    }
149
150    pub fn widget_as_zstack(widget: &Widget) -> Option<&crate::ui::ZStack> {
151        widget.as_zstack()
152    }
153
154    pub use crate::ui::custom_render::{
155        downcast_render_object, CustomEventResult, CustomHitResult, CustomRender,
156        CustomRenderObject,
157    };
158    pub use crate::ui::node::{CustomWidget, InternalRenderNode};
159    pub use crate::ui::traits::{InternalLower, InternalLowerer};
160}
161
162pub mod public {
163    pub mod action {
164        pub use crate::action::*;
165    }
166    pub mod env {
167        pub use crate::env::*;
168    }
169    pub mod event {
170        pub use crate::event::*;
171    }
172    pub mod hit_test {
173        pub use crate::hit_test::*;
174    }
175    pub mod registry {
176        pub use crate::registry::*;
177    }
178    pub mod ui {
179        pub use crate::ui::widgets::*;
180        pub use crate::ui::Widget;
181
182        pub mod widgets {
183            pub use crate::ui::widgets::*;
184        }
185    }
186    pub mod view {
187        pub use crate::view::*;
188    }
189
190    pub use crate::action::{Action, ActionEnvelope, ActionId, ActionScopeId, GlobalState};
191    pub use crate::async_runtime::{
192        BoxFuture, JobCtx, JobRef, JobSpec, ResourceExecutionContext, ServiceBindings, ServiceCtx,
193        ServiceRunner, ServiceSlot, ServiceSpec, ServiceType,
194    };
195    pub use crate::capability::{
196        CapabilityCtx, CapabilityInvocationPayload, CapabilityType, OpenUrlCapability,
197        OpenUrlRequest, OperationCapability, PickOpenFilesCapability, PickOpenFilesError,
198        PickOpenFilesRequest, PickOpenFilesResult, PickedFile, OPEN_URL, PICK_OPEN_FILES,
199    };
200    pub use crate::context::{
201        BarcodeScannerEffects, BiometricEffects, BluetoothEffects, CameraEffects, ClipboardEffects,
202        Effects, GeolocationEffects, HapticEffects, MicrophoneEffects, NfcEffects,
203        NotificationEffects, PasskeyEffects, ReducerContext, VolumeEffects, WifiEffects,
204    }; // New
205    pub use crate::effect::{ActionInput, Effect, EffectEnvelope, RuntimeEffect};
206    pub use crate::env::{
207        Clipboard, Env, ImeHandler, InteractionStateMap, RuntimeState, ScrollStateMap, WindowEnv,
208        WindowTitle,
209    };
210    pub use crate::runtime::Runtime;
211    pub use crate::state::{LocalStateKey, LocalStateStore, StateField};
212
213    pub use crate::build::{BuildCtxHandle, ViewHandle};
214    pub use crate::event::{
215        InputEvent, KeyCode, KeyEvent, LifecycleEvent, PointerButton, PointerEvent,
216    };
217    pub use crate::platform::{
218        CancelAllNotificationsCapability, CancelNotificationCapability, CancelNotificationRequest,
219        DeepLink, DeepLinkConfig, DeepLinkReceived, DeepLinkSource,
220        GetNotificationSettingsCapability, NotificationActionButton, NotificationError,
221        NotificationId, NotificationPermission, NotificationPermissionRequest, NotificationReceipt,
222        NotificationRequest, NotificationResponse, NotificationResponseReceived,
223        NotificationSchedule, NotificationSettings, NotificationSound, PushPlatform,
224        PushRegistration, PushRegistrationRequest, RegisterPushNotificationsCapability,
225        RequestNotificationPermissionCapability, ScheduleNotificationCapability,
226        SetBadgeCountCapability, SetBadgeCountRequest, ShowNotificationCapability,
227        UnregisterPushNotificationsCapability, CANCEL_ALL_NOTIFICATIONS, CANCEL_NOTIFICATION,
228        GET_NOTIFICATION_SETTINGS, REGISTER_PUSH_NOTIFICATIONS, REQUEST_NOTIFICATION_PERMISSION,
229        SCHEDULE_NOTIFICATION, SET_BADGE_COUNT, SHOW_NOTIFICATION, UNREGISTER_PUSH_NOTIFICATIONS,
230    };
231    pub use crate::platform_barcode::{
232        BarcodeFormat, BarcodeImageDecodeRequest, BarcodePoint, BarcodeScanRequest,
233        BarcodeScanResult, BarcodeScanResults, BarcodeScannerError, CancelBarcodeScanCapability,
234        DecodeBarcodeImageCapability, ScanBarcodeCapability, CANCEL_BARCODE_SCAN,
235        DECODE_BARCODE_IMAGE, SCAN_BARCODE,
236    };
237    pub use crate::platform_biometric::{
238        AuthenticateBiometricCapability, BiometricAuthenticateRequest, BiometricAuthenticateResult,
239        BiometricAvailability, BiometricError, BiometricKind, BiometricStrength,
240        CancelBiometricAuthenticationCapability, GetBiometricAvailabilityCapability,
241        AUTHENTICATE_BIOMETRIC, CANCEL_BIOMETRIC_AUTHENTICATION, GET_BIOMETRIC_AVAILABILITY,
242    };
243    pub use crate::platform_bluetooth::{
244        BluetoothAdvertiseReceipt, BluetoothAdvertiseRequest, BluetoothAvailability,
245        BluetoothConnectRequest, BluetoothConnection, BluetoothDevice, BluetoothDisconnectRequest,
246        BluetoothError, BluetoothMode, BluetoothPermission, BluetoothPermissionRequest,
247        BluetoothReadRequest, BluetoothReadResult, BluetoothScanRequest, BluetoothScanResult,
248        BluetoothStopAdvertiseRequest, BluetoothWriteRequest, ConnectBluetoothDeviceCapability,
249        DisconnectBluetoothDeviceCapability, GetBluetoothAvailabilityCapability,
250        ReadBluetoothCharacteristicCapability, RequestBluetoothPermissionCapability,
251        ScanBluetoothDevicesCapability, StartBluetoothAdvertisingCapability,
252        StopBluetoothAdvertisingCapability, WriteBluetoothCharacteristicCapability,
253        CONNECT_BLUETOOTH_DEVICE, DISCONNECT_BLUETOOTH_DEVICE, GET_BLUETOOTH_AVAILABILITY,
254        READ_BLUETOOTH_CHARACTERISTIC, REQUEST_BLUETOOTH_PERMISSION, SCAN_BLUETOOTH_DEVICES,
255        START_BLUETOOTH_ADVERTISING, STOP_BLUETOOTH_ADVERTISING, WRITE_BLUETOOTH_CHARACTERISTIC,
256    };
257    pub use crate::platform_camera::{
258        CameraAvailability, CameraCapture, CameraCaptureRequest, CameraDevice, CameraError,
259        CameraFacing, CameraFlashMode, CameraFlashlightRequest, CameraImageFormat,
260        CameraPermission, CameraPermissionRequest, CameraResolution, CancelCameraCaptureCapability,
261        CapturePhotoCapability, GetCameraAvailabilityCapability, RequestCameraPermissionCapability,
262        SetCameraFlashlightCapability, CANCEL_CAMERA_CAPTURE, CAPTURE_PHOTO,
263        GET_CAMERA_AVAILABILITY, REQUEST_CAMERA_PERMISSION, SET_CAMERA_FLASHLIGHT,
264    };
265    pub use crate::platform_clipboard::{
266        ClearClipboardCapability, ClipboardContent, ClipboardError, ClipboardItem, ClipboardText,
267        ClipboardWriteTextRequest, ReadClipboardContentCapability, ReadClipboardTextCapability,
268        WriteClipboardContentCapability, WriteClipboardTextCapability, CLEAR_CLIPBOARD,
269        READ_CLIPBOARD_CONTENT, READ_CLIPBOARD_TEXT, WRITE_CLIPBOARD_CONTENT, WRITE_CLIPBOARD_TEXT,
270    };
271    pub use crate::platform_geolocation::{
272        GeolocationError, GeolocationPermission, GeolocationPermissionRequest, GeolocationPosition,
273        GeolocationPositionRequest, GetCurrentPositionCapability,
274        GetGeolocationPermissionCapability, RequestGeolocationPermissionCapability,
275        GET_CURRENT_POSITION, GET_GEOLOCATION_PERMISSION, REQUEST_GEOLOCATION_PERMISSION,
276    };
277    pub use crate::platform_haptics::{
278        HapticError, HapticImpactCapability, HapticImpactRequest, HapticImpactStyle,
279        HapticNotificationCapability, HapticNotificationKind, HapticNotificationRequest,
280        HapticPatternCapability, HapticPatternRequest, HapticPatternStep,
281        HapticSelectionCapability, HAPTIC_IMPACT, HAPTIC_NOTIFICATION, HAPTIC_PATTERN,
282        HAPTIC_SELECTION,
283    };
284    pub use crate::platform_microphone::{
285        AudioSampleFormat, CancelMicrophoneCaptureCapability, CaptureMicrophoneAudioCapability,
286        GetMicrophoneAvailabilityCapability, MicrophoneAvailability, MicrophoneCapture,
287        MicrophoneCaptureRequest, MicrophoneDevice, MicrophoneError, MicrophonePermission,
288        MicrophonePermissionRequest, RequestMicrophonePermissionCapability,
289        CANCEL_MICROPHONE_CAPTURE, CAPTURE_MICROPHONE_AUDIO, GET_MICROPHONE_AVAILABILITY,
290        REQUEST_MICROPHONE_PERMISSION,
291    };
292    pub use crate::platform_nfc::{
293        CancelNfcSessionCapability, EmulateNfcTagCapability, GetNfcAvailabilityCapability,
294        NfcAvailability, NfcEmulationRequest, NfcError, NfcRecord, NfcRecordTypeNameFormat,
295        NfcScanRequest, NfcSessionReceipt, NfcTag, NfcTagDiscovered, NfcTechnology,
296        NfcWriteRequest, ScanNfcTagCapability, WriteNfcTagCapability, CANCEL_NFC_SESSION,
297        EMULATE_NFC_TAG, GET_NFC_AVAILABILITY, SCAN_NFC_TAG, WRITE_NFC_TAG,
298    };
299    pub use crate::platform_passkey::{
300        AuthenticatePasskeyCapability, CancelPasskeyOperationCapability,
301        GetPasskeyAvailabilityCapability, PasskeyAlgorithm, PasskeyAttestationConveyance,
302        PasskeyAuthenticationRequest, PasskeyAuthenticationResult, PasskeyAuthenticatorAttachment,
303        PasskeyAuthenticatorSelection, PasskeyAvailability, PasskeyCredentialDescriptor,
304        PasskeyError, PasskeyMediation, PasskeyRegistrationRequest, PasskeyRegistrationResult,
305        PasskeyRelyingParty, PasskeyResidentKeyRequirement, PasskeyTransport, PasskeyUser,
306        PasskeyUserVerification, RegisterPasskeyCapability, AUTHENTICATE_PASSKEY,
307        CANCEL_PASSKEY_OPERATION, GET_PASSKEY_AVAILABILITY, REGISTER_PASSKEY,
308    };
309    pub use crate::platform_volume::{
310        AdjustVolumeLevelCapability, GetVolumeLevelCapability, SetVolumeLevelCapability,
311        VolumeAdjustDirection, VolumeAdjustRequest, VolumeError, VolumeLevel, VolumeSetRequest,
312        VolumeStream, ADJUST_VOLUME_LEVEL, GET_VOLUME_LEVEL, SET_VOLUME_LEVEL,
313    };
314    pub use crate::platform_wifi::{
315        ConnectWifiNetworkCapability, DisconnectWifiNetworkCapability,
316        GetWifiAvailabilityCapability, RequestWifiPermissionCapability, ScanWifiNetworksCapability,
317        WifiAvailability, WifiConnectRequest, WifiConnection, WifiDisconnectRequest, WifiError,
318        WifiNetwork, WifiPermission, WifiPermissionRequest, WifiScanRequest, WifiScanResult,
319        WifiSecurity, CONNECT_WIFI_NETWORK, DISCONNECT_WIFI_NETWORK, GET_WIFI_AVAILABILITY,
320        REQUEST_WIFI_PERMISSION, SCAN_WIFI_NETWORKS,
321    };
322    pub use crate::registry::{
323        ActionRegistry, AnimationPropertyId, AnimationRequest, AnimationStartValue, EasingFunction,
324        Handler, JobResource, PortalLayer, ResourceKey, ResourcePolicy, ResourceRegistry,
325        RuntimeResourceDeclaration, RuntimeResourceKind, ServiceResource, TimerResource,
326        VideoRegistration,
327    };
328    pub use crate::time::{Clock, CurrentTime};
329    pub use crate::ui::{
330        provider, ActionScope, BadgeTone, Button, ButtonHierarchy, CardPattern, Column,
331        ComponentSize, ComponentState, CustomWidget, Provider, Row, Text, Widget, WidgetIdExt,
332    };
333    pub use crate::view::{ComputedView, FissionViewField, Selector, ValueView, View};
334    pub use crate::{reduce, reduce_with, widgets, with_reducer};
335    pub use fission_ir::op;
336    pub use fission_ir::{EmbedKind, Op, Role, Semantics, WidgetId};
337    pub use fission_layout::{
338        BoxConstraints, FlexDirection, LayoutEngine, LayoutOp, LayoutPoint, LayoutRect, LayoutSize,
339        LayoutSnapshot, LayoutUnit, TextMeasurer,
340    };
341}
342
343#[cfg(test)]
344mod tests;
345
346pub use action::{Action, ActionEnvelope, ActionId, ActionScopeId, GlobalState};
347pub use async_runtime::{
348    BoxFuture, JobCtx, JobRef, JobSpec, ResourceExecutionContext, ServiceBindings, ServiceCtx,
349    ServiceRunner, ServiceSlot, ServiceSpec, ServiceType,
350};
351pub use capability::{
352    CapabilityCtx, CapabilityInvocationPayload, CapabilityType, OpenUrlCapability, OpenUrlRequest,
353    OperationCapability, PickOpenFilesCapability, PickOpenFilesError, PickOpenFilesRequest,
354    PickOpenFilesResult, PickedFile, OPEN_URL, PICK_OPEN_FILES,
355};
356pub use context::{
357    BarcodeScannerEffects, BiometricEffects, BluetoothEffects, CameraEffects, ClipboardEffects,
358    Effects, GeolocationEffects, HapticEffects, MicrophoneEffects, NfcEffects, NotificationEffects,
359    PasskeyEffects, ReducerContext, VolumeEffects, WifiEffects,
360}; // New
361pub use effect::{ActionInput, Effect, EffectEnvelope, RuntimeEffect};
362pub use env::{
363    Clipboard, Env, ImeHandler, InteractionStateMap, RuntimeState, ScrollStateMap, WindowEnv,
364    WindowTitle,
365};
366pub use runtime::Runtime;
367pub use state::{LocalStateKey, LocalStateStore, StateField};
368
369pub use build::{BuildCtxHandle, ViewHandle};
370pub use event::{InputEvent, KeyCode, KeyEvent, LifecycleEvent, PointerButton, PointerEvent};
371pub use fission_ir::op;
372pub use fission_ir::{EmbedKind, Op, Role, Semantics, WidgetId};
373pub use fission_layout::{
374    BoxConstraints, FlexDirection, LayoutEngine, LayoutOp, LayoutPoint, LayoutRect, LayoutSize,
375    LayoutSnapshot, LayoutUnit, TextMeasurer,
376};
377pub use platform::{
378    CancelAllNotificationsCapability, CancelNotificationCapability, CancelNotificationRequest,
379    DeepLink, DeepLinkConfig, DeepLinkReceived, DeepLinkSource, GetNotificationSettingsCapability,
380    NotificationActionButton, NotificationError, NotificationId, NotificationPermission,
381    NotificationPermissionRequest, NotificationReceipt, NotificationRequest, NotificationResponse,
382    NotificationResponseReceived, NotificationSchedule, NotificationSettings, NotificationSound,
383    PushPlatform, PushRegistration, PushRegistrationRequest, RegisterPushNotificationsCapability,
384    RequestNotificationPermissionCapability, ScheduleNotificationCapability,
385    SetBadgeCountCapability, SetBadgeCountRequest, ShowNotificationCapability,
386    UnregisterPushNotificationsCapability, CANCEL_ALL_NOTIFICATIONS, CANCEL_NOTIFICATION,
387    GET_NOTIFICATION_SETTINGS, REGISTER_PUSH_NOTIFICATIONS, REQUEST_NOTIFICATION_PERMISSION,
388    SCHEDULE_NOTIFICATION, SET_BADGE_COUNT, SHOW_NOTIFICATION, UNREGISTER_PUSH_NOTIFICATIONS,
389};
390pub use platform_barcode::{
391    BarcodeFormat, BarcodeImageDecodeRequest, BarcodePoint, BarcodeScanRequest, BarcodeScanResult,
392    BarcodeScanResults, BarcodeScannerError, CancelBarcodeScanCapability,
393    DecodeBarcodeImageCapability, ScanBarcodeCapability, CANCEL_BARCODE_SCAN, DECODE_BARCODE_IMAGE,
394    SCAN_BARCODE,
395};
396pub use platform_biometric::{
397    AuthenticateBiometricCapability, BiometricAuthenticateRequest, BiometricAuthenticateResult,
398    BiometricAvailability, BiometricError, BiometricKind, BiometricStrength,
399    CancelBiometricAuthenticationCapability, GetBiometricAvailabilityCapability,
400    AUTHENTICATE_BIOMETRIC, CANCEL_BIOMETRIC_AUTHENTICATION, GET_BIOMETRIC_AVAILABILITY,
401};
402pub use platform_bluetooth::{
403    BluetoothAdvertiseReceipt, BluetoothAdvertiseRequest, BluetoothAvailability,
404    BluetoothConnectRequest, BluetoothConnection, BluetoothDevice, BluetoothDisconnectRequest,
405    BluetoothError, BluetoothMode, BluetoothPermission, BluetoothPermissionRequest,
406    BluetoothReadRequest, BluetoothReadResult, BluetoothScanRequest, BluetoothScanResult,
407    BluetoothStopAdvertiseRequest, BluetoothWriteRequest, ConnectBluetoothDeviceCapability,
408    DisconnectBluetoothDeviceCapability, GetBluetoothAvailabilityCapability,
409    ReadBluetoothCharacteristicCapability, RequestBluetoothPermissionCapability,
410    ScanBluetoothDevicesCapability, StartBluetoothAdvertisingCapability,
411    StopBluetoothAdvertisingCapability, WriteBluetoothCharacteristicCapability,
412    CONNECT_BLUETOOTH_DEVICE, DISCONNECT_BLUETOOTH_DEVICE, GET_BLUETOOTH_AVAILABILITY,
413    READ_BLUETOOTH_CHARACTERISTIC, REQUEST_BLUETOOTH_PERMISSION, SCAN_BLUETOOTH_DEVICES,
414    START_BLUETOOTH_ADVERTISING, STOP_BLUETOOTH_ADVERTISING, WRITE_BLUETOOTH_CHARACTERISTIC,
415};
416pub use platform_camera::{
417    CameraAvailability, CameraCapture, CameraCaptureRequest, CameraDevice, CameraError,
418    CameraFacing, CameraFlashMode, CameraFlashlightRequest, CameraImageFormat, CameraPermission,
419    CameraPermissionRequest, CameraResolution, CancelCameraCaptureCapability,
420    CapturePhotoCapability, GetCameraAvailabilityCapability, RequestCameraPermissionCapability,
421    SetCameraFlashlightCapability, CANCEL_CAMERA_CAPTURE, CAPTURE_PHOTO, GET_CAMERA_AVAILABILITY,
422    REQUEST_CAMERA_PERMISSION, SET_CAMERA_FLASHLIGHT,
423};
424pub use platform_clipboard::{
425    ClearClipboardCapability, ClipboardContent, ClipboardError, ClipboardItem, ClipboardText,
426    ClipboardWriteTextRequest, ReadClipboardContentCapability, ReadClipboardTextCapability,
427    WriteClipboardContentCapability, WriteClipboardTextCapability, CLEAR_CLIPBOARD,
428    READ_CLIPBOARD_CONTENT, READ_CLIPBOARD_TEXT, WRITE_CLIPBOARD_CONTENT, WRITE_CLIPBOARD_TEXT,
429};
430pub use platform_geolocation::{
431    GeolocationError, GeolocationPermission, GeolocationPermissionRequest, GeolocationPosition,
432    GeolocationPositionRequest, GetCurrentPositionCapability, GetGeolocationPermissionCapability,
433    RequestGeolocationPermissionCapability, GET_CURRENT_POSITION, GET_GEOLOCATION_PERMISSION,
434    REQUEST_GEOLOCATION_PERMISSION,
435};
436pub use platform_haptics::{
437    HapticError, HapticImpactCapability, HapticImpactRequest, HapticImpactStyle,
438    HapticNotificationCapability, HapticNotificationKind, HapticNotificationRequest,
439    HapticPatternCapability, HapticPatternRequest, HapticPatternStep, HapticSelectionCapability,
440    HAPTIC_IMPACT, HAPTIC_NOTIFICATION, HAPTIC_PATTERN, HAPTIC_SELECTION,
441};
442pub use platform_microphone::{
443    AudioSampleFormat, CancelMicrophoneCaptureCapability, CaptureMicrophoneAudioCapability,
444    GetMicrophoneAvailabilityCapability, MicrophoneAvailability, MicrophoneCapture,
445    MicrophoneCaptureRequest, MicrophoneDevice, MicrophoneError, MicrophonePermission,
446    MicrophonePermissionRequest, RequestMicrophonePermissionCapability, CANCEL_MICROPHONE_CAPTURE,
447    CAPTURE_MICROPHONE_AUDIO, GET_MICROPHONE_AVAILABILITY, REQUEST_MICROPHONE_PERMISSION,
448};
449pub use platform_nfc::{
450    CancelNfcSessionCapability, EmulateNfcTagCapability, GetNfcAvailabilityCapability,
451    NfcAvailability, NfcEmulationRequest, NfcError, NfcRecord, NfcRecordTypeNameFormat,
452    NfcScanRequest, NfcSessionReceipt, NfcTag, NfcTagDiscovered, NfcTechnology, NfcWriteRequest,
453    ScanNfcTagCapability, WriteNfcTagCapability, CANCEL_NFC_SESSION, EMULATE_NFC_TAG,
454    GET_NFC_AVAILABILITY, SCAN_NFC_TAG, WRITE_NFC_TAG,
455};
456pub use platform_passkey::{
457    AuthenticatePasskeyCapability, CancelPasskeyOperationCapability,
458    GetPasskeyAvailabilityCapability, PasskeyAlgorithm, PasskeyAttestationConveyance,
459    PasskeyAuthenticationRequest, PasskeyAuthenticationResult, PasskeyAuthenticatorAttachment,
460    PasskeyAuthenticatorSelection, PasskeyAvailability, PasskeyCredentialDescriptor, PasskeyError,
461    PasskeyMediation, PasskeyRegistrationRequest, PasskeyRegistrationResult, PasskeyRelyingParty,
462    PasskeyResidentKeyRequirement, PasskeyTransport, PasskeyUser, PasskeyUserVerification,
463    RegisterPasskeyCapability, AUTHENTICATE_PASSKEY, CANCEL_PASSKEY_OPERATION,
464    GET_PASSKEY_AVAILABILITY, REGISTER_PASSKEY,
465};
466pub use platform_volume::{
467    AdjustVolumeLevelCapability, GetVolumeLevelCapability, SetVolumeLevelCapability,
468    VolumeAdjustDirection, VolumeAdjustRequest, VolumeError, VolumeLevel, VolumeSetRequest,
469    VolumeStream, ADJUST_VOLUME_LEVEL, GET_VOLUME_LEVEL, SET_VOLUME_LEVEL,
470};
471pub use platform_wifi::{
472    ConnectWifiNetworkCapability, DisconnectWifiNetworkCapability, GetWifiAvailabilityCapability,
473    RequestWifiPermissionCapability, ScanWifiNetworksCapability, WifiAvailability,
474    WifiConnectRequest, WifiConnection, WifiDisconnectRequest, WifiError, WifiNetwork,
475    WifiPermission, WifiPermissionRequest, WifiScanRequest, WifiScanResult, WifiSecurity,
476    CONNECT_WIFI_NETWORK, DISCONNECT_WIFI_NETWORK, GET_WIFI_AVAILABILITY, REQUEST_WIFI_PERMISSION,
477    SCAN_WIFI_NETWORKS,
478};
479pub use registry::{
480    ActionRegistry, AnimationPropertyId, AnimationRequest, AnimationStartValue, EasingFunction,
481    Handler, JobResource, PortalLayer, ResourceKey, ResourcePolicy, ResourceRegistry,
482    RuntimeResourceDeclaration, RuntimeResourceKind, ServiceResource, TimerResource,
483    VideoRegistration,
484};
485pub use time::{Clock, CurrentTime};
486pub use ui::{
487    provider, ActionScope, BadgeTone, Button, ButtonHierarchy, CardPattern, Column, ComponentSize,
488    ComponentState, CustomWidget, Provider, Row, Text, Widget, WidgetIdExt,
489};
490pub use view::{ComputedView, FissionViewField, Selector, ValueView, View};
491
492/// Coerces a reducer function item or non-capturing closure to the handler
493/// function-pointer type Rust can infer from the surrounding `ctx.bind(...)`
494/// call.
495///
496/// ```rust,ignore
497/// use fission::prelude::*;
498///
499/// let on_press = with_reducer!(ctx, Increment, on_increment);
500/// ```
501#[macro_export]
502macro_rules! reduce_with {
503    ($handler:expr $(,)?) => {
504        $handler as $crate::Handler<_, _>
505    };
506}
507
508/// Short alias for [`reduce_with!`].
509#[macro_export]
510macro_rules! reduce {
511    ($handler:expr $(,)?) => {
512        $crate::reduce_with!($handler)
513    };
514}
515
516/// Builds a `Vec<Widget>` from widget expressions without repeated `.into()` calls.
517///
518/// Dynamic children may still be produced with normal iterators and
519/// `collect::<Vec<Widget>>()`; this macro is only syntax sugar for
520/// literal child lists.
521#[macro_export]
522macro_rules! widgets {
523    ($($widget:expr),* $(,)?) => {
524        {
525            let mut widgets = ::std::vec::Vec::<$crate::Widget>::new();
526            $(
527                widgets.push($crate::Widget::from($widget));
528            )*
529            widgets
530        }
531    };
532}
533
534/// Binds an action to a reducer in one expression.
535///
536/// ```rust,ignore
537/// use fission::prelude::*;
538///
539/// let on_press = with_reducer!(ctx, Increment, on_increment);
540/// ```
541#[macro_export]
542macro_rules! with_reducer {
543    ($ctx:expr, $action:expr, $handler:expr $(,)?) => {
544        $ctx.bind($action, $crate::reduce_with!($handler))
545    };
546}
547
548/// A frame-tick action that advances the runtime clock by a delta.
549///
550/// The platform shell dispatches `Tick` once per frame so that animations,
551/// timers, and other time-dependent logic can progress.
552///
553/// # Example
554///
555/// ```rust,ignore
556/// // Advance the runtime by 16 ms (~60 fps)
557/// runtime.tick(16)?;
558/// ```
559#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
560pub struct Tick {
561    /// Delta time in milliseconds since the last tick.
562    pub dt: CurrentTime,
563}
564
565impl Action for Tick {
566    fn static_id() -> ActionId {
567        *TICK_ACTION_ID
568    }
569}
570
571lazy_static! {
572    pub static ref TICK_ACTION_ID: ActionId = ActionId::from_name("fission_core::Tick");
573}
574
575/// An action that sets the runtime clock to an absolute timestamp.
576///
577/// Unlike [`Tick`] which advances by a delta, `AdvanceTo` jumps directly to
578/// the given time. Useful for testing and deterministic replay.
579///
580/// # Example
581///
582/// ```rust,ignore
583/// let envelope: ActionEnvelope = AdvanceTo { time: 5000 }.into();
584/// runtime.dispatch(envelope, WidgetId::from_u128(0))?;
585/// ```
586#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
587pub struct AdvanceTo {
588    /// The absolute time (in milliseconds) to set the clock to.
589    pub time: CurrentTime,
590}
591
592impl Action for AdvanceTo {
593    fn static_id() -> ActionId {
594        *ADVANCE_TO_ACTION_ID
595    }
596}
597
598lazy_static! {
599    pub static ref ADVANCE_TO_ACTION_ID: ActionId = ActionId::from_name("fission_core::AdvanceTo");
600}
601
602/// A type-erased reducer function stored in the [`Runtime`].
603///
604/// `BoxedReducer` is the internal representation used by the runtime to invoke
605/// reducers without knowing the concrete `GlobalState` or `Action` types.
606pub(crate) type BoxedReducer = Box<
607    dyn FnMut(
608            &mut HashMap<TypeId, Box<dyn GlobalState>>,
609            &ActionEnvelope,
610            WidgetId,
611            &mut Vec<EffectEnvelope>,
612            &ActionInput,
613        ) -> Result<()>
614        + Send
615        + Sync,
616>;