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