@symbiote-native/react 3.1.0 → 3.3.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.
- package/build/components/checkbox-props.d.ts +5 -0
- package/build/components/checkbox-props.js +1 -0
- package/build/descriptor-to-react/with-children.d.ts +4 -0
- package/build/descriptor-to-react/with-children.js +6 -0
- package/build/hooks/create-event-value-hook.d.ts +2 -0
- package/build/hooks/create-event-value-hook.js +14 -0
- package/build/hooks/create-permission-hook.d.ts +2 -0
- package/build/hooks/create-permission-hook.js +34 -0
- package/build/hooks/create-resource-hook.d.ts +6 -0
- package/build/hooks/create-resource-hook.js +18 -0
- package/build/hooks/use-event.d.ts +6 -0
- package/build/hooks/use-event.js +15 -0
- package/build/hooks/use-native-view-controller.d.ts +3 -0
- package/build/hooks/use-native-view-controller.js +15 -0
- package/build/index.d.ts +7 -0
- package/build/index.js +6 -0
- package/build/jsx-runtime.d.ts +2 -0
- package/package.json +6 -6
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ICheckboxProps as ICheckboxBaseProps } from '@symbiote-native/components';
|
|
2
|
+
import type { IViewProps } from '../components';
|
|
3
|
+
export type ICheckboxProps = ICheckboxBaseProps & Omit<IViewProps, keyof ICheckboxBaseProps | 'children'> & {
|
|
4
|
+
className?: string;
|
|
5
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ReactElement, ReactNode } from 'react';
|
|
2
|
+
import type { IDescriptor } from '@symbiote-native/components';
|
|
3
|
+
/** The element of a descriptor with the app children after its own, for wrappers */
|
|
4
|
+
export declare function descriptorToReactWithChildren(node: IDescriptor, children: ReactNode): ReactElement;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { createElement } from 'react';
|
|
2
|
+
import { descriptorToReact } from './index.js';
|
|
3
|
+
/** The element of a descriptor with the app children after its own, for wrappers */
|
|
4
|
+
export function descriptorToReactWithChildren(node, children) {
|
|
5
|
+
return createElement(node.type, node.props, ...node.children.map(child => typeof child === 'string' ? child : descriptorToReact(child)), children);
|
|
6
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { IEventEmitterOf, IEventName, IEventPayload, IEventsMap } from '@symbiote-native/engine';
|
|
2
|
+
/** Calls the listener for each event, the latest one, and stops when the component unmounts */
|
|
3
|
+
export declare function useEventListener<TEventsMap extends IEventsMap, TName extends IEventName<TEventsMap>>(emitter: IEventEmitterOf<TEventsMap>, eventName: TName, listener: TEventsMap[TName]): void;
|
|
4
|
+
/** The payload of the last event, `initialValue` (or `null`) until the first one */
|
|
5
|
+
export declare function useEvent<TEventsMap extends IEventsMap, TName extends IEventName<TEventsMap>>(emitter: IEventEmitterOf<TEventsMap>, eventName: TName, initialValue: IEventPayload<TEventsMap, TName>): IEventPayload<TEventsMap, TName>;
|
|
6
|
+
export declare function useEvent<TEventsMap extends IEventsMap, TName extends IEventName<TEventsMap>>(emitter: IEventEmitterOf<TEventsMap>, eventName: TName): IEventPayload<TEventsMap, TName> | null;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// React twins of `useEvent` and `useEventListener` of the `expo` package, for any emitter
|
|
2
|
+
import { useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { bindEventListener } from '@symbiote-native/engine';
|
|
4
|
+
/** Calls the listener for each event, the latest one, and stops when the component unmounts */
|
|
5
|
+
export function useEventListener(emitter, eventName, listener) {
|
|
6
|
+
// Read at each event, so a listener that changes with every render is not a new subscription
|
|
7
|
+
const latest = useRef(listener);
|
|
8
|
+
latest.current = listener;
|
|
9
|
+
useEffect(() => bindEventListener(emitter, eventName, () => latest.current), [emitter, eventName]);
|
|
10
|
+
}
|
|
11
|
+
export function useEvent(emitter, eventName, initialValue = null) {
|
|
12
|
+
const [event, setEvent] = useState(initialValue);
|
|
13
|
+
useEffect(() => bindEventListener(emitter, eventName, () => setEvent), [emitter, eventName]);
|
|
14
|
+
return event;
|
|
15
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { ReactElement, Ref } from 'react';
|
|
2
|
+
import type { ICreateNativeViewController } from '@symbiote-native/components';
|
|
3
|
+
export declare function useNativeViewController<THandle>(ref: Ref<THandle> | undefined, createController: ICreateNativeViewController<THandle>, props: object): ReactElement | null;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useEffect, useImperativeHandle, useState } from 'react';
|
|
2
|
+
import { createHostNodeHolder } from '@symbiote-native/components';
|
|
3
|
+
import { descriptorToReact } from '../descriptor-to-react/index.js';
|
|
4
|
+
// The body of a React component over a package's native view: one controller per mounted view,
|
|
5
|
+
// its handle goes to the `ref` and its descriptor is bridged to an element
|
|
6
|
+
export function useNativeViewController(ref, createController, props) {
|
|
7
|
+
const [{ host, controller }] = useState(() => {
|
|
8
|
+
const holder = createHostNodeHolder();
|
|
9
|
+
return { host: holder, controller: createController(holder.getNode) };
|
|
10
|
+
});
|
|
11
|
+
useImperativeHandle(ref, () => controller.handle, [controller]);
|
|
12
|
+
useEffect(() => () => controller.dispose?.(), [controller]);
|
|
13
|
+
const descriptor = controller.render(props);
|
|
14
|
+
return descriptor ? descriptorToReact(host.capture(descriptor)) : null;
|
|
15
|
+
}
|
package/build/index.d.ts
CHANGED
|
@@ -27,6 +27,7 @@ export type { IPressableProps, IPressState, } from './components/pressable/press
|
|
|
27
27
|
export type { ITouchableOpacityProps, ITouchableHighlightProps, } from './components/touchable/touchable-props';
|
|
28
28
|
export type { ITouchableWithoutFeedbackProps } from './components/touchable-without-feedback/touchable-without-feedback-props';
|
|
29
29
|
export type { IButtonProps } from './components/button-props';
|
|
30
|
+
export type { ICheckboxProps } from './components/checkbox-props';
|
|
30
31
|
export { FlatList } from './components/flat-list';
|
|
31
32
|
export type { IFlatListProps, IFlatListHandle } from './components/flat-list';
|
|
32
33
|
export { SectionList } from './components/section-list';
|
|
@@ -40,6 +41,7 @@ export { mount, unmount } from './render';
|
|
|
40
41
|
export { createPortal, type IPortalContainer } from './create-portal';
|
|
41
42
|
export { createTunnel, type ITunnel } from './create-tunnel';
|
|
42
43
|
export { descriptorToReact } from './descriptor-to-react';
|
|
44
|
+
export { descriptorToReactWithChildren } from './descriptor-to-react/with-children';
|
|
43
45
|
export { findNodeHandle } from './host-instance';
|
|
44
46
|
export type { IHostInstance } from './host-instance';
|
|
45
47
|
export { AppRegistry, setHostRegistrar } from './modules/app-registry';
|
|
@@ -56,6 +58,11 @@ export { Alert, Share, ActionSheetIOS, Linking, Vibration, ToastAndroid, Setting
|
|
|
56
58
|
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
59
|
export { useWindowDimensions } from './hooks/use-window-dimensions';
|
|
58
60
|
export { useColorScheme } from './hooks/use-color-scheme';
|
|
61
|
+
export { createPermissionHook } from './hooks/create-permission-hook';
|
|
62
|
+
export { createResourceHook } from './hooks/create-resource-hook';
|
|
63
|
+
export { useNativeViewController } from './hooks/use-native-view-controller';
|
|
64
|
+
export { createEventValueHook } from './hooks/create-event-value-hook';
|
|
65
|
+
export { useEvent, useEventListener } from './hooks/use-event';
|
|
59
66
|
export { AccessibilityInfo } from './modules/accessibility-info';
|
|
60
67
|
export type { IAccessibilityChangeEvent, IAccessibilityChangeEventName, IAccessibilityChangeEventHandler, IAccessibilityAnnouncementFinishedEvent, IAnnounceForAccessibilityOptions, IAccessibilityEventType, } from './modules/accessibility-info';
|
|
61
68
|
export { PanResponder } from '@symbiote-native/engine';
|
package/build/index.js
CHANGED
|
@@ -32,6 +32,7 @@ export { createTunnel } from './create-tunnel/index.js';
|
|
|
32
32
|
// an external wrapper package (e.g. @symbiote-native/slider/react over a third-party native view) can map
|
|
33
33
|
// a shared render fn's Descriptor onto React elements through the SAME bridge the adapter uses.
|
|
34
34
|
export { descriptorToReact } from './descriptor-to-react/index.js';
|
|
35
|
+
export { descriptorToReactWithChildren } from './descriptor-to-react/with-children.js';
|
|
35
36
|
export { findNodeHandle } from './host-instance.js';
|
|
36
37
|
// AppRegistry: RN's app entry point over `mount`. setHostRegistrar wires RN's own
|
|
37
38
|
// registrar so the native Fabric host finds our runnable by app key.
|
|
@@ -62,6 +63,11 @@ export { Alert, Share, ActionSheetIOS, Linking, Vibration, ToastAndroid, Setting
|
|
|
62
63
|
// React lifecycle over those core device-state modules.
|
|
63
64
|
export { useWindowDimensions } from './hooks/use-window-dimensions.js';
|
|
64
65
|
export { useColorScheme } from './hooks/use-color-scheme.js';
|
|
66
|
+
export { createPermissionHook } from './hooks/create-permission-hook.js';
|
|
67
|
+
export { createResourceHook } from './hooks/create-resource-hook.js';
|
|
68
|
+
export { useNativeViewController } from './hooks/use-native-view-controller.js';
|
|
69
|
+
export { createEventValueHook } from './hooks/create-event-value-hook.js';
|
|
70
|
+
export { useEvent, useEventListener } from './hooks/use-event.js';
|
|
65
71
|
export { AccessibilityInfo } from './modules/accessibility-info';
|
|
66
72
|
// Interaction subsystems: gestures, deferred work, and layout transitions.
|
|
67
73
|
export { PanResponder } from '@symbiote-native/engine';
|
package/build/jsx-runtime.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { Key } from 'react';
|
|
|
3
3
|
import type { IViewProps, ITextProps } from './components';
|
|
4
4
|
import type { IPressableProps } from './components/pressable/pressable-props';
|
|
5
5
|
import type { IButtonProps } from './components/button-props';
|
|
6
|
+
import type { ICheckboxProps } from './components/checkbox-props';
|
|
6
7
|
import type { IImageProps } from './components/image/image-props';
|
|
7
8
|
import type { IImageBackgroundProps } from './components/image-background-props';
|
|
8
9
|
import type { IInputAccessoryViewProps } from './components/input-accessory-view-props';
|
|
@@ -27,6 +28,7 @@ export interface ICrossedPrimitiveProps {
|
|
|
27
28
|
text: ITextProps;
|
|
28
29
|
pressable: IPressableProps;
|
|
29
30
|
button: IButtonProps;
|
|
31
|
+
checkbox: ICheckboxProps;
|
|
30
32
|
image: IImageProps;
|
|
31
33
|
'image-background': IImageBackgroundProps;
|
|
32
34
|
'input-accessory-view': IInputAccessoryViewProps;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbiote-native/react",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.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.
|
|
61
|
-
"@symbiote-native/css-parser": "0.5.
|
|
60
|
+
"@symbiote-native/components": "3.2.0",
|
|
61
|
+
"@symbiote-native/css-parser": "0.5.4"
|
|
62
62
|
},
|
|
63
63
|
"peerDependencies": {
|
|
64
64
|
"react": ">=19.0.0",
|
|
65
65
|
"react-native": ">=0.86",
|
|
66
|
-
"@symbiote-native/engine": "^1.
|
|
66
|
+
"@symbiote-native/engine": "^1.6.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.
|
|
74
|
-
"@symbiote-native/test-utils": "0.4.
|
|
73
|
+
"@symbiote-native/engine": "1.6.0",
|
|
74
|
+
"@symbiote-native/test-utils": "0.4.7"
|
|
75
75
|
},
|
|
76
76
|
"scripts": {
|
|
77
77
|
"typecheck": "tsc --build",
|