@pushframe/sdk 0.1.5 → 0.1.8
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/lib/commonjs/PushframeProvider.js +69 -0
- package/lib/commonjs/PushframeProvider.js.map +1 -0
- package/lib/commonjs/PushframeScreen.js +69 -0
- package/lib/commonjs/PushframeScreen.js.map +1 -0
- package/lib/commonjs/bindings.js +73 -0
- package/lib/commonjs/bindings.js.map +1 -0
- package/lib/commonjs/components/ButtonComponent.js +72 -0
- package/lib/commonjs/components/ButtonComponent.js.map +1 -0
- package/lib/commonjs/components/FlatListComponent.js +73 -0
- package/lib/commonjs/components/FlatListComponent.js.map +1 -0
- package/lib/commonjs/components/ImageComponent.js +67 -0
- package/lib/commonjs/components/ImageComponent.js.map +1 -0
- package/lib/commonjs/components/PushFrameComponent.js +179 -0
- package/lib/commonjs/components/PushFrameComponent.js.map +1 -0
- package/lib/commonjs/components/PushFrameProvider.js +115 -0
- package/lib/commonjs/components/PushFrameProvider.js.map +1 -0
- package/lib/commonjs/components/PushFrameScreen.js +39 -0
- package/lib/commonjs/components/PushFrameScreen.js.map +1 -0
- package/lib/commonjs/components/ScrollViewComponent.js +64 -0
- package/lib/commonjs/components/ScrollViewComponent.js.map +1 -0
- package/lib/commonjs/components/StackComponent.js +61 -0
- package/lib/commonjs/components/StackComponent.js.map +1 -0
- package/lib/commonjs/components/TextComponent.js +62 -0
- package/lib/commonjs/components/TextComponent.js.map +1 -0
- package/lib/commonjs/conditions.js +44 -0
- package/lib/commonjs/conditions.js.map +1 -0
- package/lib/commonjs/context/PushFrameContext.js +33 -0
- package/lib/commonjs/context/PushFrameContext.js.map +1 -0
- package/lib/commonjs/index.js +200 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/overlays/BottomSheetHost.js +144 -0
- package/lib/commonjs/overlays/BottomSheetHost.js.map +1 -0
- package/lib/commonjs/overlays/ToastHost.js +135 -0
- package/lib/commonjs/overlays/ToastHost.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/primitives/ActivityIndicator.js +24 -0
- package/lib/commonjs/primitives/ActivityIndicator.js.map +1 -0
- package/lib/commonjs/primitives/FlatList.js +34 -0
- package/lib/commonjs/primitives/FlatList.js.map +1 -0
- package/lib/commonjs/primitives/Image.js +33 -0
- package/lib/commonjs/primitives/Image.js.map +1 -0
- package/lib/commonjs/primitives/KeyboardAvoidingView.js +24 -0
- package/lib/commonjs/primitives/KeyboardAvoidingView.js.map +1 -0
- package/lib/commonjs/primitives/Modal.js +24 -0
- package/lib/commonjs/primitives/Modal.js.map +1 -0
- package/lib/commonjs/primitives/Pressable.js +26 -0
- package/lib/commonjs/primitives/Pressable.js.map +1 -0
- package/lib/commonjs/primitives/SafeAreaView.js +38 -0
- package/lib/commonjs/primitives/SafeAreaView.js.map +1 -0
- package/lib/commonjs/primitives/ScrollView.js +26 -0
- package/lib/commonjs/primitives/ScrollView.js.map +1 -0
- package/lib/commonjs/primitives/StatusBar.js +24 -0
- package/lib/commonjs/primitives/StatusBar.js.map +1 -0
- package/lib/commonjs/primitives/Switch.js +28 -0
- package/lib/commonjs/primitives/Switch.js.map +1 -0
- package/lib/commonjs/primitives/Text.js +37 -0
- package/lib/commonjs/primitives/Text.js.map +1 -0
- package/lib/commonjs/primitives/TextInput.js +31 -0
- package/lib/commonjs/primitives/TextInput.js.map +1 -0
- package/lib/commonjs/primitives/View.js +24 -0
- package/lib/commonjs/primitives/View.js.map +1 -0
- package/lib/commonjs/primitives/index.js +97 -0
- package/lib/commonjs/primitives/index.js.map +1 -0
- package/lib/commonjs/registry/ComponentRegistry.js +70 -0
- package/lib/commonjs/registry/ComponentRegistry.js.map +1 -0
- package/lib/commonjs/registry.js +94 -0
- package/lib/commonjs/registry.js.map +1 -0
- package/lib/commonjs/renderer/RecursiveRenderer.js +202 -0
- package/lib/commonjs/renderer/RecursiveRenderer.js.map +1 -0
- package/lib/commonjs/renderer/bindingResolver.js +98 -0
- package/lib/commonjs/renderer/bindingResolver.js.map +1 -0
- package/lib/commonjs/renderer/conditionalEvaluator.js +31 -0
- package/lib/commonjs/renderer/conditionalEvaluator.js.map +1 -0
- package/lib/commonjs/renderer.js +107 -0
- package/lib/commonjs/renderer.js.map +1 -0
- package/lib/commonjs/schema.js +79 -0
- package/lib/commonjs/schema.js.map +1 -0
- package/lib/commonjs/transformer/index.js +1055 -0
- package/lib/commonjs/transformer/index.js.map +1 -0
- package/lib/commonjs/transport.js +86 -0
- package/lib/commonjs/transport.js.map +1 -0
- package/lib/module/PushframeProvider.js +62 -0
- package/lib/module/PushframeProvider.js.map +1 -0
- package/lib/module/PushframeScreen.js +65 -0
- package/lib/module/PushframeScreen.js.map +1 -0
- package/lib/module/bindings.js +68 -0
- package/lib/module/bindings.js.map +1 -0
- package/lib/module/components/ButtonComponent.js +67 -0
- package/lib/module/components/ButtonComponent.js.map +1 -0
- package/lib/module/components/FlatListComponent.js +68 -0
- package/lib/module/components/FlatListComponent.js.map +1 -0
- package/lib/module/components/ImageComponent.js +62 -0
- package/lib/module/components/ImageComponent.js.map +1 -0
- package/lib/module/components/PushFrameComponent.js +174 -0
- package/lib/module/components/PushFrameComponent.js.map +1 -0
- package/lib/module/components/PushFrameProvider.js +110 -0
- package/lib/module/components/PushFrameProvider.js.map +1 -0
- package/lib/module/components/PushFrameScreen.js +34 -0
- package/lib/module/components/PushFrameScreen.js.map +1 -0
- package/lib/module/components/ScrollViewComponent.js +59 -0
- package/lib/module/components/ScrollViewComponent.js.map +1 -0
- package/lib/module/components/StackComponent.js +56 -0
- package/lib/module/components/StackComponent.js.map +1 -0
- package/lib/module/components/TextComponent.js +57 -0
- package/lib/module/components/TextComponent.js.map +1 -0
- package/lib/module/conditions.js +40 -0
- package/lib/module/conditions.js.map +1 -0
- package/lib/module/context/PushFrameContext.js +29 -0
- package/lib/module/context/PushFrameContext.js.map +1 -0
- package/lib/module/index.js +99 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/overlays/BottomSheetHost.js +139 -0
- package/lib/module/overlays/BottomSheetHost.js.map +1 -0
- package/lib/module/overlays/ToastHost.js +130 -0
- package/lib/module/overlays/ToastHost.js.map +1 -0
- package/lib/module/primitives/ActivityIndicator.js +19 -0
- package/lib/module/primitives/ActivityIndicator.js.map +1 -0
- package/lib/module/primitives/FlatList.js +29 -0
- package/lib/module/primitives/FlatList.js.map +1 -0
- package/lib/module/primitives/Image.js +28 -0
- package/lib/module/primitives/Image.js.map +1 -0
- package/lib/module/primitives/KeyboardAvoidingView.js +19 -0
- package/lib/module/primitives/KeyboardAvoidingView.js.map +1 -0
- package/lib/module/primitives/Modal.js +19 -0
- package/lib/module/primitives/Modal.js.map +1 -0
- package/lib/module/primitives/Pressable.js +21 -0
- package/lib/module/primitives/Pressable.js.map +1 -0
- package/lib/module/primitives/SafeAreaView.js +33 -0
- package/lib/module/primitives/SafeAreaView.js.map +1 -0
- package/lib/module/primitives/ScrollView.js +21 -0
- package/lib/module/primitives/ScrollView.js.map +1 -0
- package/lib/module/primitives/StatusBar.js +19 -0
- package/lib/module/primitives/StatusBar.js.map +1 -0
- package/lib/module/primitives/Switch.js +23 -0
- package/lib/module/primitives/Switch.js.map +1 -0
- package/lib/module/primitives/Text.js +32 -0
- package/lib/module/primitives/Text.js.map +1 -0
- package/lib/module/primitives/TextInput.js +26 -0
- package/lib/module/primitives/TextInput.js.map +1 -0
- package/lib/module/primitives/View.js +19 -0
- package/lib/module/primitives/View.js.map +1 -0
- package/lib/module/primitives/index.js +16 -0
- package/lib/module/primitives/index.js.map +1 -0
- package/lib/module/registry/ComponentRegistry.js +66 -0
- package/lib/module/registry/ComponentRegistry.js.map +1 -0
- package/lib/module/registry.js +88 -0
- package/lib/module/registry.js.map +1 -0
- package/lib/module/renderer/RecursiveRenderer.js +197 -0
- package/lib/module/renderer/RecursiveRenderer.js.map +1 -0
- package/lib/module/renderer/bindingResolver.js +92 -0
- package/lib/module/renderer/bindingResolver.js.map +1 -0
- package/lib/module/renderer/conditionalEvaluator.js +28 -0
- package/lib/module/renderer/conditionalEvaluator.js.map +1 -0
- package/lib/module/renderer.js +103 -0
- package/lib/module/renderer.js.map +1 -0
- package/lib/module/schema.js +74 -0
- package/lib/module/schema.js.map +1 -0
- package/lib/module/transformer/index.js +1051 -0
- package/lib/module/transformer/index.js.map +1 -0
- package/lib/module/transport.js +82 -0
- package/lib/module/transport.js.map +1 -0
- package/lib/typescript/PushframeProvider.d.ts +58 -0
- package/lib/typescript/PushframeProvider.d.ts.map +1 -0
- package/lib/typescript/PushframeScreen.d.ts +36 -0
- package/lib/typescript/PushframeScreen.d.ts.map +1 -0
- package/lib/typescript/bindings.d.ts +29 -0
- package/lib/typescript/bindings.d.ts.map +1 -0
- package/lib/typescript/components/ButtonComponent.d.ts +11 -0
- package/lib/typescript/components/ButtonComponent.d.ts.map +1 -0
- package/lib/typescript/components/FlatListComponent.d.ts +28 -0
- package/lib/typescript/components/FlatListComponent.d.ts.map +1 -0
- package/lib/typescript/components/ImageComponent.d.ts +12 -0
- package/lib/typescript/components/ImageComponent.d.ts.map +1 -0
- package/lib/typescript/components/PushFrameComponent.d.ts +48 -0
- package/lib/typescript/components/PushFrameComponent.d.ts.map +1 -0
- package/lib/typescript/components/PushFrameProvider.d.ts +51 -0
- package/lib/typescript/components/PushFrameProvider.d.ts.map +1 -0
- package/lib/typescript/components/PushFrameScreen.d.ts +15 -0
- package/lib/typescript/components/PushFrameScreen.d.ts.map +1 -0
- package/lib/typescript/components/ScrollViewComponent.d.ts +19 -0
- package/lib/typescript/components/ScrollViewComponent.d.ts.map +1 -0
- package/lib/typescript/components/StackComponent.d.ts +16 -0
- package/lib/typescript/components/StackComponent.d.ts.map +1 -0
- package/lib/typescript/components/TextComponent.d.ts +13 -0
- package/lib/typescript/components/TextComponent.d.ts.map +1 -0
- package/lib/typescript/conditions.d.ts +12 -0
- package/lib/typescript/conditions.d.ts.map +1 -0
- package/lib/typescript/context/PushFrameContext.d.ts +57 -0
- package/lib/typescript/context/PushFrameContext.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +74 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/overlays/BottomSheetHost.d.ts +21 -0
- package/lib/typescript/overlays/BottomSheetHost.d.ts.map +1 -0
- package/lib/typescript/overlays/ToastHost.d.ts +12 -0
- package/lib/typescript/overlays/ToastHost.d.ts.map +1 -0
- package/lib/typescript/primitives/ActivityIndicator.d.ts +12 -0
- package/lib/typescript/primitives/ActivityIndicator.d.ts.map +1 -0
- package/lib/typescript/primitives/FlatList.d.ts +29 -0
- package/lib/typescript/primitives/FlatList.d.ts.map +1 -0
- package/lib/typescript/primitives/Image.d.ts +20 -0
- package/lib/typescript/primitives/Image.d.ts.map +1 -0
- package/lib/typescript/primitives/KeyboardAvoidingView.d.ts +12 -0
- package/lib/typescript/primitives/KeyboardAvoidingView.d.ts.map +1 -0
- package/lib/typescript/primitives/Modal.d.ts +12 -0
- package/lib/typescript/primitives/Modal.d.ts.map +1 -0
- package/lib/typescript/primitives/Pressable.d.ts +14 -0
- package/lib/typescript/primitives/Pressable.d.ts.map +1 -0
- package/lib/typescript/primitives/SafeAreaView.d.ts +20 -0
- package/lib/typescript/primitives/SafeAreaView.d.ts.map +1 -0
- package/lib/typescript/primitives/ScrollView.d.ts +15 -0
- package/lib/typescript/primitives/ScrollView.d.ts.map +1 -0
- package/lib/typescript/primitives/StatusBar.d.ts +12 -0
- package/lib/typescript/primitives/StatusBar.d.ts.map +1 -0
- package/lib/typescript/primitives/Switch.d.ts +19 -0
- package/lib/typescript/primitives/Switch.d.ts.map +1 -0
- package/lib/typescript/primitives/Text.d.ts +25 -0
- package/lib/typescript/primitives/Text.d.ts.map +1 -0
- package/lib/typescript/primitives/TextInput.d.ts +25 -0
- package/lib/typescript/primitives/TextInput.d.ts.map +1 -0
- package/lib/typescript/primitives/View.d.ts +12 -0
- package/lib/typescript/primitives/View.d.ts.map +1 -0
- package/lib/typescript/primitives/index.d.ts +27 -0
- package/lib/typescript/primitives/index.d.ts.map +1 -0
- package/lib/typescript/registry/ComponentRegistry.d.ts +21 -0
- package/lib/typescript/registry/ComponentRegistry.d.ts.map +1 -0
- package/lib/typescript/registry.d.ts +57 -0
- package/lib/typescript/registry.d.ts.map +1 -0
- package/lib/typescript/renderer/RecursiveRenderer.d.ts +32 -0
- package/lib/typescript/renderer/RecursiveRenderer.d.ts.map +1 -0
- package/lib/typescript/renderer/bindingResolver.d.ts +26 -0
- package/lib/typescript/renderer/bindingResolver.d.ts.map +1 -0
- package/lib/typescript/renderer/conditionalEvaluator.d.ts +15 -0
- package/lib/typescript/renderer/conditionalEvaluator.d.ts.map +1 -0
- package/lib/typescript/renderer.d.ts +29 -0
- package/lib/typescript/renderer.d.ts.map +1 -0
- package/lib/typescript/schema.d.ts +84 -0
- package/lib/typescript/schema.d.ts.map +1 -0
- package/lib/typescript/transformer/index.d.ts +49 -0
- package/lib/typescript/transformer/index.d.ts.map +1 -0
- package/lib/typescript/transport.d.ts +19 -0
- package/lib/typescript/transport.d.ts.map +1 -0
- package/package.json +20 -18
- package/src/PushframeProvider.tsx +119 -0
- package/src/PushframeScreen.tsx +107 -0
- package/src/bindings.ts +72 -0
- package/src/components/ButtonComponent.tsx +87 -0
- package/src/components/FlatListComponent.tsx +86 -0
- package/src/components/ImageComponent.tsx +70 -0
- package/src/components/PushFrameComponent.tsx +221 -0
- package/src/components/PushFrameProvider.tsx +177 -0
- package/src/components/PushFrameScreen.tsx +30 -0
- package/src/components/ScrollViewComponent.tsx +65 -0
- package/src/components/StackComponent.tsx +69 -0
- package/src/components/TextComponent.tsx +60 -0
- package/src/conditions.ts +46 -0
- package/src/context/PushFrameContext.ts +89 -0
- package/src/index.ts +119 -0
- package/src/overlays/BottomSheetHost.tsx +175 -0
- package/src/overlays/ToastHost.tsx +147 -0
- package/src/primitives/ActivityIndicator.tsx +21 -0
- package/src/primitives/FlatList.tsx +49 -0
- package/src/primitives/Image.tsx +26 -0
- package/src/primitives/KeyboardAvoidingView.tsx +21 -0
- package/src/primitives/Modal.tsx +17 -0
- package/src/primitives/Pressable.tsx +19 -0
- package/src/primitives/SafeAreaView.tsx +42 -0
- package/src/primitives/ScrollView.tsx +21 -0
- package/src/primitives/StatusBar.tsx +17 -0
- package/src/primitives/Switch.tsx +24 -0
- package/src/primitives/Text.tsx +43 -0
- package/src/primitives/TextInput.tsx +42 -0
- package/src/primitives/View.tsx +17 -0
- package/src/primitives/index.ts +38 -0
- package/src/registry/ComponentRegistry.ts +99 -0
- package/src/registry.ts +99 -0
- package/src/renderer/RecursiveRenderer.tsx +242 -0
- package/src/renderer/bindingResolver.ts +94 -0
- package/src/renderer/conditionalEvaluator.ts +29 -0
- package/src/renderer.tsx +124 -0
- package/src/schema.ts +132 -0
- package/src/transformer/index.ts +1016 -0
- package/src/transport.ts +104 -0
- package/dist/index.d.mts +0 -534
- package/dist/index.d.ts +0 -534
- package/dist/index.js +0 -1572
- package/dist/index.js.map +0 -1
- package/dist/index.mjs +0 -1541
- package/dist/index.mjs.map +0 -1
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { TouchableOpacity, Text, StyleSheet, ActivityIndicator } from 'react-native';
|
|
3
|
+
import type { PushframeComponentProps } from '../registry';
|
|
4
|
+
|
|
5
|
+
export type ButtonVariant = 'primary' | 'secondary' | 'ghost';
|
|
6
|
+
|
|
7
|
+
export interface ButtonProps {
|
|
8
|
+
label?: string;
|
|
9
|
+
variant?: ButtonVariant;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
loading?: boolean;
|
|
12
|
+
onPress?: () => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function ButtonComponent({ props }: PushframeComponentProps<ButtonProps>) {
|
|
16
|
+
const { label = 'Button', variant = 'primary', disabled = false, loading = false, onPress } = props;
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<TouchableOpacity
|
|
20
|
+
style={[
|
|
21
|
+
styles.base,
|
|
22
|
+
variant === 'secondary' && styles.secondary,
|
|
23
|
+
variant === 'ghost' && styles.ghost,
|
|
24
|
+
(disabled || loading) && styles.disabled,
|
|
25
|
+
]}
|
|
26
|
+
onPress={onPress}
|
|
27
|
+
disabled={disabled || loading}
|
|
28
|
+
activeOpacity={0.8}
|
|
29
|
+
>
|
|
30
|
+
{loading ? (
|
|
31
|
+
<ActivityIndicator
|
|
32
|
+
size="small"
|
|
33
|
+
color={variant === 'primary' ? '#ffffff' : '#2563eb'}
|
|
34
|
+
/>
|
|
35
|
+
) : (
|
|
36
|
+
<Text
|
|
37
|
+
style={[
|
|
38
|
+
styles.label,
|
|
39
|
+
variant === 'secondary' && styles.labelSecondary,
|
|
40
|
+
variant === 'ghost' && styles.labelGhost,
|
|
41
|
+
(disabled || loading) && styles.labelDisabled,
|
|
42
|
+
]}
|
|
43
|
+
>
|
|
44
|
+
{label}
|
|
45
|
+
</Text>
|
|
46
|
+
)}
|
|
47
|
+
</TouchableOpacity>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const styles = StyleSheet.create({
|
|
52
|
+
base: {
|
|
53
|
+
backgroundColor: '#2563eb',
|
|
54
|
+
paddingVertical: 12,
|
|
55
|
+
paddingHorizontal: 24,
|
|
56
|
+
borderRadius: 8,
|
|
57
|
+
alignItems: 'center',
|
|
58
|
+
justifyContent: 'center',
|
|
59
|
+
minHeight: 44,
|
|
60
|
+
},
|
|
61
|
+
secondary: {
|
|
62
|
+
backgroundColor: 'transparent',
|
|
63
|
+
borderWidth: 1.5,
|
|
64
|
+
borderColor: '#2563eb',
|
|
65
|
+
},
|
|
66
|
+
ghost: {
|
|
67
|
+
backgroundColor: 'transparent',
|
|
68
|
+
borderWidth: 0,
|
|
69
|
+
},
|
|
70
|
+
disabled: {
|
|
71
|
+
opacity: 0.4,
|
|
72
|
+
},
|
|
73
|
+
label: {
|
|
74
|
+
color: '#ffffff',
|
|
75
|
+
fontSize: 16,
|
|
76
|
+
fontWeight: '600',
|
|
77
|
+
},
|
|
78
|
+
labelSecondary: {
|
|
79
|
+
color: '#2563eb',
|
|
80
|
+
},
|
|
81
|
+
labelGhost: {
|
|
82
|
+
color: '#2563eb',
|
|
83
|
+
},
|
|
84
|
+
labelDisabled: {
|
|
85
|
+
opacity: 0.6,
|
|
86
|
+
},
|
|
87
|
+
});
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { FlatList, View } from 'react-native';
|
|
3
|
+
import type { ReactElement } from 'react';
|
|
4
|
+
import type { PushframeComponentProps } from '../registry';
|
|
5
|
+
|
|
6
|
+
export interface FlatListProps {
|
|
7
|
+
/**
|
|
8
|
+
* Array of data items to render. Typically bound from context via
|
|
9
|
+
* { "$bind": "path.to.array" }. Each item is available as `item` and
|
|
10
|
+
* the index as `index` inside the item template (first child node).
|
|
11
|
+
*/
|
|
12
|
+
data?: Record<string, unknown>[];
|
|
13
|
+
/**
|
|
14
|
+
* Name of the field on each item to use as the React key.
|
|
15
|
+
* @default "id"
|
|
16
|
+
*/
|
|
17
|
+
keyExtractor?: string;
|
|
18
|
+
horizontal?: boolean;
|
|
19
|
+
numColumns?: number;
|
|
20
|
+
padding?: number;
|
|
21
|
+
paddingTop?: number;
|
|
22
|
+
paddingBottom?: number;
|
|
23
|
+
paddingLeft?: number;
|
|
24
|
+
paddingRight?: number;
|
|
25
|
+
backgroundColor?: string;
|
|
26
|
+
flex?: number;
|
|
27
|
+
showsScrollIndicator?: boolean;
|
|
28
|
+
/** Height of the separator between items (vertical lists only). */
|
|
29
|
+
itemSeparatorHeight?: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function FlatListComponent({
|
|
33
|
+
props,
|
|
34
|
+
rawChildren,
|
|
35
|
+
renderChild,
|
|
36
|
+
}: PushframeComponentProps<FlatListProps>) {
|
|
37
|
+
const {
|
|
38
|
+
data = [],
|
|
39
|
+
keyExtractor = 'id',
|
|
40
|
+
horizontal = false,
|
|
41
|
+
numColumns = 1,
|
|
42
|
+
padding,
|
|
43
|
+
paddingTop,
|
|
44
|
+
paddingBottom,
|
|
45
|
+
paddingLeft,
|
|
46
|
+
paddingRight,
|
|
47
|
+
backgroundColor,
|
|
48
|
+
flex,
|
|
49
|
+
showsScrollIndicator = true,
|
|
50
|
+
itemSeparatorHeight = 0,
|
|
51
|
+
} = props;
|
|
52
|
+
|
|
53
|
+
// The first child node is used as the item template.
|
|
54
|
+
const itemTemplate = rawChildren?.[0];
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<FlatList
|
|
58
|
+
data={data}
|
|
59
|
+
horizontal={horizontal}
|
|
60
|
+
numColumns={horizontal ? 1 : numColumns}
|
|
61
|
+
showsHorizontalScrollIndicator={horizontal ? showsScrollIndicator : false}
|
|
62
|
+
showsVerticalScrollIndicator={!horizontal ? showsScrollIndicator : false}
|
|
63
|
+
keyExtractor={(item, index) =>
|
|
64
|
+
String((item as Record<string, unknown>)[keyExtractor] ?? index)
|
|
65
|
+
}
|
|
66
|
+
renderItem={({ item, index }) => {
|
|
67
|
+
if (!itemTemplate || !renderChild) return null;
|
|
68
|
+
return renderChild(itemTemplate, { item, index }) as ReactElement | null;
|
|
69
|
+
}}
|
|
70
|
+
ItemSeparatorComponent={
|
|
71
|
+
itemSeparatorHeight > 0
|
|
72
|
+
? () => <View style={{ height: itemSeparatorHeight }} />
|
|
73
|
+
: undefined
|
|
74
|
+
}
|
|
75
|
+
style={[
|
|
76
|
+
padding !== undefined && { padding },
|
|
77
|
+
paddingTop !== undefined && { paddingTop },
|
|
78
|
+
paddingBottom !== undefined && { paddingBottom },
|
|
79
|
+
paddingLeft !== undefined && { paddingLeft },
|
|
80
|
+
paddingRight !== undefined && { paddingRight },
|
|
81
|
+
backgroundColor !== undefined && { backgroundColor },
|
|
82
|
+
flex !== undefined && { flex },
|
|
83
|
+
]}
|
|
84
|
+
/>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Image, StyleSheet, View, Text } from 'react-native';
|
|
3
|
+
import type { PushframeComponentProps } from '../registry';
|
|
4
|
+
|
|
5
|
+
export type ImageResizeMode = 'cover' | 'contain' | 'stretch' | 'center';
|
|
6
|
+
|
|
7
|
+
export interface ImageProps {
|
|
8
|
+
src?: string;
|
|
9
|
+
alt?: string;
|
|
10
|
+
width?: number;
|
|
11
|
+
height?: number;
|
|
12
|
+
resizeMode?: ImageResizeMode;
|
|
13
|
+
borderRadius?: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function ImageComponent({ props }: PushframeComponentProps<ImageProps>) {
|
|
17
|
+
const {
|
|
18
|
+
src,
|
|
19
|
+
alt = '',
|
|
20
|
+
width,
|
|
21
|
+
height = 200,
|
|
22
|
+
resizeMode = 'cover',
|
|
23
|
+
borderRadius,
|
|
24
|
+
} = props;
|
|
25
|
+
|
|
26
|
+
if (!src) {
|
|
27
|
+
return (
|
|
28
|
+
<View
|
|
29
|
+
style={[
|
|
30
|
+
styles.placeholder,
|
|
31
|
+
width !== undefined && { width },
|
|
32
|
+
{ height },
|
|
33
|
+
borderRadius !== undefined && { borderRadius },
|
|
34
|
+
]}
|
|
35
|
+
>
|
|
36
|
+
<Text style={styles.placeholderText}>{alt || 'No image'}</Text>
|
|
37
|
+
</View>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<Image
|
|
43
|
+
source={{ uri: src }}
|
|
44
|
+
accessibilityLabel={alt}
|
|
45
|
+
resizeMode={resizeMode}
|
|
46
|
+
style={[
|
|
47
|
+
styles.image,
|
|
48
|
+
width !== undefined && { width },
|
|
49
|
+
{ height },
|
|
50
|
+
borderRadius !== undefined && { borderRadius },
|
|
51
|
+
]}
|
|
52
|
+
/>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const styles = StyleSheet.create({
|
|
57
|
+
image: {
|
|
58
|
+
width: '100%',
|
|
59
|
+
},
|
|
60
|
+
placeholder: {
|
|
61
|
+
width: '100%',
|
|
62
|
+
backgroundColor: '#e5e7eb',
|
|
63
|
+
alignItems: 'center',
|
|
64
|
+
justifyContent: 'center',
|
|
65
|
+
},
|
|
66
|
+
placeholderText: {
|
|
67
|
+
color: '#9ca3af',
|
|
68
|
+
fontSize: 14,
|
|
69
|
+
},
|
|
70
|
+
});
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import React, { useCallback, useEffect, useState } from 'react';
|
|
2
|
+
import type { ReactNode, ReactElement } from 'react';
|
|
3
|
+
import { usePushFrameContext } from '../context/PushFrameContext';
|
|
4
|
+
import type { SchemaNode, ToastPayload, BottomSheetPayload } from '../context/PushFrameContext';
|
|
5
|
+
import { RecursiveRenderer } from '../renderer/RecursiveRenderer';
|
|
6
|
+
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
// Shared slot props (used by both Screen and Component)
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
|
|
11
|
+
export interface PushFrameSlotProps {
|
|
12
|
+
/** ID of the screen/component to fetch from the delivery service. */
|
|
13
|
+
id: string;
|
|
14
|
+
/**
|
|
15
|
+
* Data context local to this slot. Merged with the Provider context;
|
|
16
|
+
* local keys win on conflict.
|
|
17
|
+
*/
|
|
18
|
+
context?: Record<string, unknown>;
|
|
19
|
+
/**
|
|
20
|
+
* External loading signal from the host app. When true, loading UI is shown
|
|
21
|
+
* even if the schema has already been fetched.
|
|
22
|
+
*/
|
|
23
|
+
isLoading?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Loading UI shown while isLoading=true OR schema is being fetched.
|
|
26
|
+
* Falls back to Provider-level loadingComponent.
|
|
27
|
+
*/
|
|
28
|
+
loadingComponent?: ReactNode;
|
|
29
|
+
/**
|
|
30
|
+
* Fallback UI shown on fetch error or unresolvable component type.
|
|
31
|
+
* Falls back to Provider-level fallbackComponent.
|
|
32
|
+
*/
|
|
33
|
+
fallbackComponent?: ReactNode;
|
|
34
|
+
/**
|
|
35
|
+
* Slot-level action handler. Return true to stop the action from bubbling
|
|
36
|
+
* to the Provider-level onAction.
|
|
37
|
+
*/
|
|
38
|
+
onAction?: (action: string, payload?: Record<string, unknown>) => boolean | void;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
// Schema fetch
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
|
|
45
|
+
async function fetchSchema(
|
|
46
|
+
baseUrl: string,
|
|
47
|
+
apiKey: string,
|
|
48
|
+
path: string,
|
|
49
|
+
): Promise<SchemaNode> {
|
|
50
|
+
const url = new URL(path, baseUrl + '/').toString();
|
|
51
|
+
const headers: Record<string, string> = {
|
|
52
|
+
Accept: 'application/json',
|
|
53
|
+
Authorization: `Bearer ${apiKey}`,
|
|
54
|
+
'x-project-key': apiKey,
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const res = await fetch(url, { headers });
|
|
58
|
+
if (!res.ok) {
|
|
59
|
+
throw new Error(`[PushFrame] HTTP ${res.status} fetching "${path}"`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const envelope = (await res.json()) as { schema?: SchemaNode } & SchemaNode;
|
|
63
|
+
return envelope.schema ?? envelope;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
// PushFrameComponent
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
|
|
70
|
+
interface PushFrameComponentInternalProps extends PushFrameSlotProps {
|
|
71
|
+
/** Resource type — determines which delivery endpoint to hit. */
|
|
72
|
+
resourceType: 'screens' | 'components';
|
|
73
|
+
/** When true, wraps the rendered output with flex:1 (used by Screen). */
|
|
74
|
+
fullscreen?: boolean;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function PushFrameComponentInternal({
|
|
78
|
+
id,
|
|
79
|
+
resourceType,
|
|
80
|
+
context: slotContext,
|
|
81
|
+
isLoading: externalLoading,
|
|
82
|
+
loadingComponent: slotLoading,
|
|
83
|
+
fallbackComponent: slotFallback,
|
|
84
|
+
onAction: slotOnAction,
|
|
85
|
+
fullscreen,
|
|
86
|
+
}: PushFrameComponentInternalProps) {
|
|
87
|
+
const {
|
|
88
|
+
apiKey,
|
|
89
|
+
baseUrl,
|
|
90
|
+
appVersion,
|
|
91
|
+
globalContext,
|
|
92
|
+
registry,
|
|
93
|
+
loadingComponent: providerLoading,
|
|
94
|
+
fallbackComponent: providerFallback,
|
|
95
|
+
onAction: providerOnAction,
|
|
96
|
+
onError,
|
|
97
|
+
showToast,
|
|
98
|
+
showBottomSheet,
|
|
99
|
+
dismissBottomSheet,
|
|
100
|
+
} = usePushFrameContext();
|
|
101
|
+
|
|
102
|
+
const [schema, setSchema] = useState<SchemaNode | null>(null);
|
|
103
|
+
const [fetchError, setFetchError] = useState<Error | null>(null);
|
|
104
|
+
const [isFetching, setIsFetching] = useState(true);
|
|
105
|
+
|
|
106
|
+
// Build fetch path: {resourceType}/{id}/{appVersion} — "null" when not set
|
|
107
|
+
const fetchPath = `${resourceType}/${encodeURIComponent(id)}/${encodeURIComponent(appVersion ?? 'null')}`;
|
|
108
|
+
|
|
109
|
+
// Merged data context: provider → slot (local wins)
|
|
110
|
+
const mergedContext = slotContext ? { ...globalContext, ...slotContext } : globalContext;
|
|
111
|
+
|
|
112
|
+
// Resolved UI components with fallback precedence
|
|
113
|
+
const loadingUI = slotLoading !== undefined ? slotLoading : providerLoading;
|
|
114
|
+
const fallbackUI = slotFallback !== undefined ? slotFallback : providerFallback;
|
|
115
|
+
|
|
116
|
+
// Fetch schema
|
|
117
|
+
useEffect(() => {
|
|
118
|
+
let cancelled = false;
|
|
119
|
+
setSchema(null);
|
|
120
|
+
setFetchError(null);
|
|
121
|
+
setIsFetching(true);
|
|
122
|
+
|
|
123
|
+
fetchSchema(baseUrl, apiKey, fetchPath)
|
|
124
|
+
.then((s) => {
|
|
125
|
+
if (!cancelled) {
|
|
126
|
+
setSchema(s);
|
|
127
|
+
setIsFetching(false);
|
|
128
|
+
}
|
|
129
|
+
})
|
|
130
|
+
.catch((err: unknown) => {
|
|
131
|
+
if (!cancelled) {
|
|
132
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
133
|
+
setFetchError(error);
|
|
134
|
+
setIsFetching(false);
|
|
135
|
+
onError?.(error);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
return () => {
|
|
140
|
+
cancelled = true;
|
|
141
|
+
};
|
|
142
|
+
}, [fetchPath, baseUrl, apiKey, onError]);
|
|
143
|
+
|
|
144
|
+
// Dispatch action — handles built-ins, then bubbles via slot → provider
|
|
145
|
+
const dispatchAction = useCallback(
|
|
146
|
+
(action: string, payload?: Record<string, unknown>) => {
|
|
147
|
+
// Built-in actions — never bubble to host app
|
|
148
|
+
if (action === 'show-toast') {
|
|
149
|
+
showToast(payload as unknown as ToastPayload);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
if (action === 'show-bottom-sheet') {
|
|
153
|
+
showBottomSheet(payload as unknown as BottomSheetPayload);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (action === 'dismiss-bottom-sheet') {
|
|
157
|
+
dismissBottomSheet();
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (action === 'scroll-to') {
|
|
161
|
+
// scroll-to is handled by the ScrollView primitive via ref; no bubbling needed
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Bubble: slot onAction first; if it returns true, stop
|
|
166
|
+
const stopped = slotOnAction?.(action, payload);
|
|
167
|
+
if (stopped) return;
|
|
168
|
+
|
|
169
|
+
// Provider onAction
|
|
170
|
+
providerOnAction?.(action, payload);
|
|
171
|
+
},
|
|
172
|
+
[showToast, showBottomSheet, dismissBottomSheet, slotOnAction, providerOnAction],
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
// Loading state: external flag OR schema not yet fetched
|
|
176
|
+
const isShowingLoader = externalLoading || isFetching;
|
|
177
|
+
|
|
178
|
+
if (isShowingLoader) {
|
|
179
|
+
return (loadingUI as ReactElement | null) ?? null;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (fetchError || !schema) {
|
|
183
|
+
return (fallbackUI as ReactElement | null) ?? null;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const rendered = (
|
|
187
|
+
<RecursiveRenderer
|
|
188
|
+
node={schema}
|
|
189
|
+
context={mergedContext}
|
|
190
|
+
registry={registry}
|
|
191
|
+
dispatchAction={dispatchAction}
|
|
192
|
+
fallbackComponent={fallbackUI}
|
|
193
|
+
/>
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
if (fullscreen) {
|
|
197
|
+
// PushFrame.Screen wraps with flex:1
|
|
198
|
+
return <>{rendered}</>;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return rendered;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// ---------------------------------------------------------------------------
|
|
205
|
+
// Public PushFrameComponent
|
|
206
|
+
// ---------------------------------------------------------------------------
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Fetches a component schema from GET /components/:id[/:appVersion] on the
|
|
210
|
+
* delivery service and renders it inline using RecursiveRenderer.
|
|
211
|
+
*
|
|
212
|
+
* Context is merged: Provider context → slot context (local wins).
|
|
213
|
+
* Actions bubble: slot onAction → Provider onAction.
|
|
214
|
+
* Built-in actions (show-toast, show-bottom-sheet, etc.) are handled internally.
|
|
215
|
+
*/
|
|
216
|
+
export function PushFrameComponent(props: PushFrameSlotProps) {
|
|
217
|
+
return <PushFrameComponentInternal {...props} resourceType="components" />;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Re-export internal for Screen to use
|
|
221
|
+
export { PushFrameComponentInternal };
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import React, { useCallback, useMemo, useRef } from 'react';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
import { PushFrameContext } from '../context/PushFrameContext';
|
|
4
|
+
import type {
|
|
5
|
+
PushFrameContextValue,
|
|
6
|
+
ToastPayload,
|
|
7
|
+
BottomSheetPayload,
|
|
8
|
+
SchemaNode,
|
|
9
|
+
} from '../context/PushFrameContext';
|
|
10
|
+
import { ComponentRegistry } from '../registry/ComponentRegistry';
|
|
11
|
+
import { ToastHost } from '../overlays/ToastHost';
|
|
12
|
+
import type { ToastHostHandle } from '../overlays/ToastHost';
|
|
13
|
+
import { BottomSheetHost } from '../overlays/BottomSheetHost';
|
|
14
|
+
import type { BottomSheetHostHandle } from '../overlays/BottomSheetHost';
|
|
15
|
+
import { RecursiveRenderer } from '../renderer/RecursiveRenderer';
|
|
16
|
+
|
|
17
|
+
const DEFAULT_BASE_URL = 'https://api.pushframe.io';
|
|
18
|
+
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Props
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
export interface PushFrameProviderProps {
|
|
24
|
+
/** Pushframe API key — sent as Authorization header on all fetches. */
|
|
25
|
+
apiKey: string;
|
|
26
|
+
/**
|
|
27
|
+
* Runtime data context. Screens/Components bind to this via {{expressions}}.
|
|
28
|
+
* Merged at the Provider level; slot-level context wins on conflict.
|
|
29
|
+
*/
|
|
30
|
+
context?: Record<string, unknown>;
|
|
31
|
+
/**
|
|
32
|
+
* Base URL of the Pushframe delivery service.
|
|
33
|
+
* Defaults to the production endpoint: https://api.pushframe.io
|
|
34
|
+
*/
|
|
35
|
+
baseUrl?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Semver string appended to fetch paths for schema version targeting.
|
|
38
|
+
* e.g. "1.2.3" → GET /screens/home/1.2.3
|
|
39
|
+
* When not provided, "null" is sent as the appVersion in the URL.
|
|
40
|
+
*/
|
|
41
|
+
appVersion?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Developer-registered native components merged into the ComponentRegistry.
|
|
44
|
+
* Built-in types cannot be overridden — conflicting keys are warned and skipped.
|
|
45
|
+
*/
|
|
46
|
+
components?: Record<string, React.ComponentType<unknown>>;
|
|
47
|
+
/** Default loading UI shown while schema is fetching or isLoading=true. */
|
|
48
|
+
loadingComponent?: ReactNode;
|
|
49
|
+
/** Default fallback UI shown on fetch error or unknown component type. */
|
|
50
|
+
fallbackComponent?: ReactNode;
|
|
51
|
+
/**
|
|
52
|
+
* Global action handler. Receives actions that are not handled as built-ins
|
|
53
|
+
* and were not stopped by a slot-level onAction.
|
|
54
|
+
*/
|
|
55
|
+
onAction?: (action: string, payload?: Record<string, unknown>) => void;
|
|
56
|
+
/** Called whenever a fetch or render error occurs. */
|
|
57
|
+
onError?: (error: Error) => void;
|
|
58
|
+
children: ReactNode;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
// PushFrameProvider
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Root provider for the PushFrame SDK.
|
|
67
|
+
*
|
|
68
|
+
* Wrap your app (or a subtree) in this provider. All PushFrame.Screen and
|
|
69
|
+
* PushFrame.Component slots inside will fetch their schemas from the delivery
|
|
70
|
+
* service and render them using the shared ComponentRegistry and context.
|
|
71
|
+
*
|
|
72
|
+
* Also renders the ToastHost and BottomSheetHost overlay hosts at root level
|
|
73
|
+
* so any component in the tree can trigger them via built-in actions.
|
|
74
|
+
*/
|
|
75
|
+
export function PushFrameProvider({
|
|
76
|
+
apiKey,
|
|
77
|
+
context = {},
|
|
78
|
+
baseUrl = DEFAULT_BASE_URL,
|
|
79
|
+
appVersion,
|
|
80
|
+
components,
|
|
81
|
+
loadingComponent,
|
|
82
|
+
fallbackComponent,
|
|
83
|
+
onAction,
|
|
84
|
+
onError,
|
|
85
|
+
children,
|
|
86
|
+
}: PushFrameProviderProps) {
|
|
87
|
+
// Registry — created once (components prop should be stable)
|
|
88
|
+
const registry = useMemo(
|
|
89
|
+
() => new ComponentRegistry(components),
|
|
90
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
91
|
+
[],
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
// Overlay refs
|
|
95
|
+
const toastRef = useRef<ToastHostHandle>(null);
|
|
96
|
+
const bottomSheetRef = useRef<BottomSheetHostHandle>(null);
|
|
97
|
+
|
|
98
|
+
const showToast = useCallback((payload: ToastPayload) => {
|
|
99
|
+
toastRef.current?.show(payload);
|
|
100
|
+
}, []);
|
|
101
|
+
|
|
102
|
+
const showBottomSheet = useCallback((payload: BottomSheetPayload) => {
|
|
103
|
+
bottomSheetRef.current?.show(payload);
|
|
104
|
+
}, []);
|
|
105
|
+
|
|
106
|
+
const dismissBottomSheet = useCallback(() => {
|
|
107
|
+
bottomSheetRef.current?.dismiss();
|
|
108
|
+
}, []);
|
|
109
|
+
|
|
110
|
+
// renderContent for BottomSheetHost — renders a schema node with the Provider's registry
|
|
111
|
+
const renderBottomSheetContent = useCallback(
|
|
112
|
+
(schema: SchemaNode, sheetContext?: Record<string, unknown>) => {
|
|
113
|
+
const mergedContext = sheetContext ? { ...context, ...sheetContext } : context;
|
|
114
|
+
// No-op dispatchAction for bottom sheet content (actions bubble via onAction)
|
|
115
|
+
const dispatchAction = (action: string, payload?: Record<string, unknown>) => {
|
|
116
|
+
if (action === 'dismiss-bottom-sheet') {
|
|
117
|
+
dismissBottomSheet();
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (action === 'show-toast') {
|
|
121
|
+
showToast(payload as unknown as ToastPayload);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
onAction?.(action, payload);
|
|
125
|
+
};
|
|
126
|
+
return (
|
|
127
|
+
<RecursiveRenderer
|
|
128
|
+
node={schema}
|
|
129
|
+
context={mergedContext}
|
|
130
|
+
registry={registry}
|
|
131
|
+
dispatchAction={dispatchAction}
|
|
132
|
+
fallbackComponent={fallbackComponent}
|
|
133
|
+
/>
|
|
134
|
+
);
|
|
135
|
+
},
|
|
136
|
+
[context, registry, fallbackComponent, onAction, dismissBottomSheet, showToast],
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
const contextValue = useMemo<PushFrameContextValue>(
|
|
140
|
+
() => ({
|
|
141
|
+
apiKey,
|
|
142
|
+
baseUrl,
|
|
143
|
+
appVersion,
|
|
144
|
+
globalContext: context,
|
|
145
|
+
registry,
|
|
146
|
+
loadingComponent,
|
|
147
|
+
fallbackComponent,
|
|
148
|
+
onAction,
|
|
149
|
+
onError,
|
|
150
|
+
showToast,
|
|
151
|
+
showBottomSheet,
|
|
152
|
+
dismissBottomSheet,
|
|
153
|
+
}),
|
|
154
|
+
[
|
|
155
|
+
apiKey,
|
|
156
|
+
baseUrl,
|
|
157
|
+
appVersion,
|
|
158
|
+
context,
|
|
159
|
+
registry,
|
|
160
|
+
loadingComponent,
|
|
161
|
+
fallbackComponent,
|
|
162
|
+
onAction,
|
|
163
|
+
onError,
|
|
164
|
+
showToast,
|
|
165
|
+
showBottomSheet,
|
|
166
|
+
dismissBottomSheet,
|
|
167
|
+
],
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
return (
|
|
171
|
+
<PushFrameContext.Provider value={contextValue}>
|
|
172
|
+
{children}
|
|
173
|
+
<ToastHost ref={toastRef} />
|
|
174
|
+
<BottomSheetHost ref={bottomSheetRef} renderContent={renderBottomSheetContent} />
|
|
175
|
+
</PushFrameContext.Provider>
|
|
176
|
+
);
|
|
177
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View, StyleSheet } from 'react-native';
|
|
3
|
+
import { PushFrameComponentInternal } from './PushFrameComponent';
|
|
4
|
+
import type { PushFrameSlotProps } from './PushFrameComponent';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Fetches a screen schema from GET /screens/:id[/:appVersion] on the delivery
|
|
8
|
+
* service and renders it with flex:1 sizing (full-page layout).
|
|
9
|
+
*
|
|
10
|
+
* Identical to PushFrame.Component in behaviour, but:
|
|
11
|
+
* - Fetches from /screens/:id instead of /components/:id
|
|
12
|
+
* - Applies flex:1 to its container so it fills the available space
|
|
13
|
+
*
|
|
14
|
+
* Context is merged: Provider context → slot context (local wins).
|
|
15
|
+
* Actions bubble: slot onAction → Provider onAction.
|
|
16
|
+
* Built-in actions (show-toast, show-bottom-sheet, etc.) are handled internally.
|
|
17
|
+
*/
|
|
18
|
+
export function PushFrameScreen(props: PushFrameSlotProps) {
|
|
19
|
+
return (
|
|
20
|
+
<View style={styles.container}>
|
|
21
|
+
<PushFrameComponentInternal {...props} resourceType="screens" fullscreen />
|
|
22
|
+
</View>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const styles = StyleSheet.create({
|
|
27
|
+
container: {
|
|
28
|
+
flex: 1,
|
|
29
|
+
},
|
|
30
|
+
});
|