@symbiote-native/react 3.1.0 → 3.2.0

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.
@@ -0,0 +1,2 @@
1
+ import type { IEventValueSource } from '@symbiote-native/engine';
2
+ export declare function createEventValueHook<TSource extends IEventValueSource<TValue, TEvent>, TValue, TEvent extends string = string>(event: TEvent, getValue: (source: TSource) => TValue): (source: TSource) => TValue;
@@ -0,0 +1,14 @@
1
+ // Every `useXStatus`-style hook (`useAudioPlayerStatus`, `useAudioPlaylistStatus`, ...) binds
2
+ // this to its own event name + initial-value getter instead of repeating the subscribe wiring
3
+ import { useEffect, useState } from 'react';
4
+ export function createEventValueHook(event, getValue) {
5
+ return function useEventValue(source) {
6
+ const [value, setValue] = useState(() => getValue(source));
7
+ useEffect(() => {
8
+ setValue(getValue(source));
9
+ const subscription = source.addListener(event, setValue);
10
+ return () => subscription.remove();
11
+ }, [source]);
12
+ return value;
13
+ };
14
+ }
@@ -0,0 +1,2 @@
1
+ import { type IPermissionHookBehavior, type IPermissionHookMethods, type IPermissionHookResult } from '@symbiote-native/engine';
2
+ export declare function createPermissionHook<TPermission, TOptions extends object>(methods: IPermissionHookMethods<TPermission, TOptions>): (behavior?: IPermissionHookBehavior, methodOptions?: TOptions) => IPermissionHookResult<TPermission>;
@@ -0,0 +1,34 @@
1
+ // Every Expo-wrapper package's own permission hook (`useCameraPermissions`,
2
+ // `useCalendarPermissions`, `useRemindersPermissions`, ...) binds this factory to its `methods`
3
+ import { useEffect, useRef, useState } from 'react';
4
+ import { createPermissionApi, fetchInitialPermission, } from '@symbiote-native/engine';
5
+ export function createPermissionHook(methods) {
6
+ return function usePermission(behavior, methodOptions) {
7
+ const [status, setStatus] = useState(null);
8
+ const isMountedRef = useRef(true);
9
+ const get = behavior?.get ?? true;
10
+ const request = behavior?.request ?? false;
11
+ const apiRef = useRef(createPermissionApi(methods, value => {
12
+ if (isMountedRef.current)
13
+ setStatus(value);
14
+ }));
15
+ useEffect(() => {
16
+ isMountedRef.current = true;
17
+ return () => {
18
+ isMountedRef.current = false;
19
+ };
20
+ }, []);
21
+ useEffect(() => {
22
+ fetchInitialPermission(methods, { get, request }, methodOptions, response => {
23
+ if (isMountedRef.current)
24
+ setStatus(response);
25
+ });
26
+ // eslint-disable-next-line react-hooks/exhaustive-deps
27
+ }, [get, request]);
28
+ return [
29
+ status,
30
+ () => apiRef.current.request(methodOptions),
31
+ () => apiRef.current.get(methodOptions),
32
+ ];
33
+ };
34
+ }
@@ -0,0 +1,6 @@
1
+ export type IResourceHookController<TArgs extends unknown[], TResource> = {
2
+ resolve: (...args: TArgs) => TResource;
3
+ flushDispose: () => void;
4
+ dispose: () => void;
5
+ };
6
+ export declare function createResourceHook<TArgs extends unknown[], TResource>(createController: () => IResourceHookController<TArgs, TResource>): (...args: TArgs) => TResource;
@@ -0,0 +1,18 @@
1
+ // Every `useReleasingSharedObject`-style hook (`useAudioPlayer`, `useImageManipulator`, ...)
2
+ // binds this to its own `createXController()` instead of repeating the ref/effect wiring
3
+ import { useEffect, useRef } from 'react';
4
+ export function createResourceHook(createController) {
5
+ return function useResource(...args) {
6
+ const controllerRef = useRef(null);
7
+ if (!controllerRef.current)
8
+ controllerRef.current = createController();
9
+ const resource = controllerRef.current.resolve(...args);
10
+ useEffect(() => {
11
+ controllerRef.current?.flushDispose();
12
+ }, [resource]);
13
+ useEffect(() => {
14
+ return () => controllerRef.current?.dispose();
15
+ }, []);
16
+ return resource;
17
+ };
18
+ }
package/build/index.d.ts CHANGED
@@ -56,6 +56,9 @@ export { Alert, Share, ActionSheetIOS, Linking, Vibration, ToastAndroid, Setting
56
56
  export type { IAlertType, IAlertButtonStyle, IAlertButton, IAlertButtons, IAlertOptions, IShareContent, IShareOptions, IShareAction, IActionSheetIOSOptions, IShareActionSheetIOSOptions, IShareActionSheetError, IUrlEvent, II18nManagerConstants, IDisplayMetrics, IDisplayMetricsAndroid, IDimensionsPayload, IDimensionsSet, IDimensionsKey, IDimensionsChangeListener, IDimensionsStatic, IColorSchemeName, IColorSchemePreference, IAppStateStatus, IAppStateEvent, IKeyboardEventName, IKeyboardEvent, IKeyboardMetrics, IBackPressEventName, IBackPressHandler, IPermission, IPermissionStatus, IRationale, ILayoutAnimationType, ILayoutAnimationProperty, ILayoutAnimationConfig, ILayoutAnimationAnim, IPixelRatioStatic, } from '@symbiote-native/engine';
57
57
  export { useWindowDimensions } from './hooks/use-window-dimensions';
58
58
  export { useColorScheme } from './hooks/use-color-scheme';
59
+ export { createPermissionHook } from './hooks/create-permission-hook';
60
+ export { createResourceHook } from './hooks/create-resource-hook';
61
+ export { createEventValueHook } from './hooks/create-event-value-hook';
59
62
  export { AccessibilityInfo } from './modules/accessibility-info';
60
63
  export type { IAccessibilityChangeEvent, IAccessibilityChangeEventName, IAccessibilityChangeEventHandler, IAccessibilityAnnouncementFinishedEvent, IAnnounceForAccessibilityOptions, IAccessibilityEventType, } from './modules/accessibility-info';
61
64
  export { PanResponder } from '@symbiote-native/engine';
package/build/index.js CHANGED
@@ -62,6 +62,9 @@ export { Alert, Share, ActionSheetIOS, Linking, Vibration, ToastAndroid, Setting
62
62
  // React lifecycle over those core device-state modules.
63
63
  export { useWindowDimensions } from './hooks/use-window-dimensions.js';
64
64
  export { useColorScheme } from './hooks/use-color-scheme.js';
65
+ export { createPermissionHook } from './hooks/create-permission-hook.js';
66
+ export { createResourceHook } from './hooks/create-resource-hook.js';
67
+ export { createEventValueHook } from './hooks/create-event-value-hook.js';
65
68
  export { AccessibilityInfo } from './modules/accessibility-info';
66
69
  // Interaction subsystems: gestures, deferred work, and layout transitions.
67
70
  export { PanResponder } from '@symbiote-native/engine';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@symbiote-native/react",
3
- "version": "3.1.0",
3
+ "version": "3.2.0",
4
4
  "description": "SymbioteNative's React adapter — a react-reconciler host config (mutation mode) driving real native iOS/Android views through stock React Native Fabric.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -57,21 +57,21 @@
57
57
  },
58
58
  "dependencies": {
59
59
  "react-reconciler": "^0.33.0",
60
- "@symbiote-native/components": "3.1.3",
61
- "@symbiote-native/css-parser": "0.5.2"
60
+ "@symbiote-native/components": "3.1.4",
61
+ "@symbiote-native/css-parser": "0.5.3"
62
62
  },
63
63
  "peerDependencies": {
64
64
  "react": ">=19.0.0",
65
65
  "react-native": ">=0.86",
66
- "@symbiote-native/engine": "^1.4.0"
66
+ "@symbiote-native/engine": "^1.5.0"
67
67
  },
68
68
  "devDependencies": {
69
69
  "@types/node": "^26.0.0",
70
70
  "@types/react": "^19.2.0",
71
71
  "@types/react-reconciler": "^0.32.2",
72
72
  "react": "19.2.3",
73
- "@symbiote-native/engine": "1.4.0",
74
- "@symbiote-native/test-utils": "0.4.5"
73
+ "@symbiote-native/engine": "1.5.0",
74
+ "@symbiote-native/test-utils": "0.4.6"
75
75
  },
76
76
  "scripts": {
77
77
  "typecheck": "tsc --build",