@robono/messaging-react-native 0.8.0 → 0.10.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.
Files changed (62) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +92 -37
  3. package/SBOM.spdx.json +577 -217
  4. package/dist/account.js +7 -4
  5. package/dist/attachment-menu.js +5 -2
  6. package/dist/call-message.js +8 -5
  7. package/dist/calling.js +6 -2
  8. package/dist/conversation-details.d.ts +1 -0
  9. package/dist/conversation-details.js +11 -7
  10. package/dist/custom-message.d.ts +7 -0
  11. package/dist/custom-message.js +53 -0
  12. package/dist/customization.d.ts +49 -0
  13. package/dist/customization.js +1 -0
  14. package/dist/expo-connected-calling.js +7 -2
  15. package/dist/expo-extras.js +4 -1
  16. package/dist/expo-media.js +27 -5
  17. package/dist/expo-messenger.d.ts +41 -2
  18. package/dist/expo-messenger.js +86 -10
  19. package/dist/expo-outbox.js +22 -1
  20. package/dist/expo-screen.d.ts +1 -1
  21. package/dist/expo-screen.js +42 -31
  22. package/dist/expo-social.js +5 -2
  23. package/dist/expo.d.ts +1 -1
  24. package/dist/expo.js +1 -1
  25. package/dist/extras.js +11 -7
  26. package/dist/forward.js +8 -5
  27. package/dist/group-editor.js +9 -6
  28. package/dist/header-calls.js +9 -6
  29. package/dist/icons.js +2 -1
  30. package/dist/inbox-search.d.ts +3 -1
  31. package/dist/inbox-search.js +33 -10
  32. package/dist/inbox-view.d.ts +21 -0
  33. package/dist/inbox-view.js +32 -0
  34. package/dist/inbox.d.ts +6 -1
  35. package/dist/inbox.js +27 -18
  36. package/dist/index.d.ts +16 -6
  37. package/dist/index.js +122 -81
  38. package/dist/localization.d.ts +24 -0
  39. package/dist/localization.js +12 -0
  40. package/dist/maps-connection.js +5 -2
  41. package/dist/media-ui.js +15 -8
  42. package/dist/message-menu.js +5 -2
  43. package/dist/native-outbox.d.ts +10 -2
  44. package/dist/native-outbox.js +7 -0
  45. package/dist/polls.js +21 -16
  46. package/dist/popup.js +8 -4
  47. package/dist/public-rooms.d.ts +10 -0
  48. package/dist/public-rooms.js +78 -0
  49. package/dist/quick-send.js +6 -3
  50. package/dist/room-moderation.d.ts +22 -0
  51. package/dist/room-moderation.js +87 -0
  52. package/dist/safety.js +11 -8
  53. package/dist/saved.js +7 -4
  54. package/dist/scheduled.js +19 -14
  55. package/dist/search.js +7 -4
  56. package/dist/social.js +9 -5
  57. package/dist/translation-settings.js +7 -4
  58. package/dist/typography.d.ts +12 -0
  59. package/dist/typography.js +31 -0
  60. package/dist/voice-composer.js +11 -6
  61. package/package.json +10 -8
  62. package/setup.plugin.cjs +20 -0
@@ -0,0 +1,31 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, forwardRef, useContext, useMemo } from 'react';
3
+ import { Platform, StyleSheet, Text as NativeText, TextInput as NativeTextInput } from 'react-native';
4
+ const defaults = { fontFamily: undefined, scale: 1 };
5
+ const Typography = createContext(defaults), InsideText = createContext(false);
6
+ /** Local to this Messenger. Does not change host-app text or device accessibility scaling. */
7
+ export function MessagingTypography({ appearance, children }) {
8
+ const font = appearance.presentation?.font ?? 'system', scale = appearance.presentation?.textScale ?? 1;
9
+ const value = useMemo(() => ({ fontFamily: font === 'serif' ? Platform.OS === 'ios' ? 'Georgia' : Platform.OS === 'web' ? 'Georgia, "Times New Roman", serif' : 'serif' : font === 'monospace' ? Platform.OS === 'ios' ? 'Menlo' : Platform.OS === 'web' ? 'Menlo, Consolas, monospace' : 'monospace' : undefined, scale: [1, 1.15, 1.3].includes(scale) ? scale : 1 }), [font, scale]);
10
+ return _jsx(Typography.Provider, { value: value, children: children });
11
+ }
12
+ function useTextStyle(style, nested = false) {
13
+ const { fontFamily, scale } = useContext(Typography), flat = StyleSheet.flatten(style) ?? {};
14
+ const base = typeof flat.fontSize === 'number' ? flat.fontSize : nested ? undefined : 14;
15
+ const resolved = { ...(fontFamily ? { fontFamily } : {}), ...flat };
16
+ if (scale !== 1) {
17
+ if (base !== undefined)
18
+ resolved.fontSize = base * scale;
19
+ if (typeof flat.lineHeight === 'number')
20
+ resolved.lineHeight = flat.lineHeight * scale;
21
+ }
22
+ return resolved;
23
+ }
24
+ export const Text = forwardRef(function MessagingText({ style, children, ...props }, ref) {
25
+ const nested = useContext(InsideText), resolved = useTextStyle(style, nested);
26
+ return _jsx(InsideText.Provider, { value: true, children: _jsx(NativeText, { ...props, ref: ref, style: resolved, children: children }) });
27
+ });
28
+ export const TextInput = forwardRef(function MessagingTextInput({ style, ...props }, ref) {
29
+ const resolved = useTextStyle(style);
30
+ return _jsx(NativeTextInput, { ...props, ref: ref, style: resolved });
31
+ });
@@ -1,20 +1,25 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { ActivityIndicator, Pressable, Text, View } from 'react-native';
2
+ import { Text } from './typography.js';
3
+ import { useRobonoLocale } from './localization.js';
4
+ import { ActivityIndicator, Pressable, View } from 'react-native';
3
5
  import { MessageIcon, duration, composerSurface } from './icons.js';
4
6
  function Waveform({ samples = [], color }) {
5
- return _jsx(View, { accessibilityLabel: "Recording waveform", style: { flex: 1, minWidth: 0, height: 24, flexDirection: 'row', alignItems: 'center', gap: 2, overflow: 'hidden' }, children: Array.from({ length: 28 }, (_, i) => { const value = samples[Math.floor(i * samples.length / 28)] ?? 0; return _jsx(View, { style: { flex: 1, borderRadius: 2, height: 3 + Math.max(0, Math.min(1, value)) * 21, backgroundColor: color, opacity: samples.length ? .8 : .25 } }, i); }) });
7
+ const { text: uiText, locale: uiLocale, number: uiNumber, count: uiCount } = useRobonoLocale();
8
+ return _jsx(View, { accessibilityLabel: uiText("Recording waveform"), style: { flex: 1, minWidth: 0, height: 24, flexDirection: 'row', alignItems: 'center', gap: 2, overflow: 'hidden' }, children: Array.from({ length: 28 }, (_, i) => { const value = samples[Math.floor(i * samples.length / 28)] ?? 0; return _jsx(View, { style: { flex: 1, borderRadius: 2, height: 3 + Math.max(0, Math.min(1, value)) * 21, backgroundColor: color, opacity: samples.length ? .8 : .25 } }, i); }) });
6
9
  }
7
10
  /** Messenger's inline recorder; adapters supply media state and the optional text composer. */
8
11
  export function VoiceMessageComposer({ appearance, maxSeconds, busy, onRecord, actions, phase = 'idle', elapsedMs = 0, waveform, error, review, onStop, onSend, onRemove, renderTextComposer, renderAttachments }) {
12
+ const { text: uiText, locale: uiLocale, number: uiNumber, count: uiCount } = useRobonoLocale();
9
13
  const c = appearance.colors, recording = phase === 'recording', waiting = phase === 'preparing' || phase === 'uploading' || (busy && phase === 'idle');
10
14
  const canSend = !!review && (phase === 'review' || phase === 'failed') && !!onSend;
11
15
  if (renderTextComposer && !recording && phase !== 'preparing' && phase !== 'uploading')
12
- return _jsxs(View, { style: { gap: 4 }, children: [renderAttachments ? renderAttachments(review, waiting) : review && _jsx(View, { style: { paddingHorizontal: 8, paddingTop: 4 }, children: review }), renderTextComposer({ sendVoice: canSend ? onSend : undefined, hasVoice: !!review, blocked: waiting }), !!error && _jsxs(View, { style: { flexDirection: 'row', alignItems: 'center', gap: 8, paddingHorizontal: 8 }, children: [_jsx(Text, { accessibilityRole: "alert", style: { color: c.foreground, fontSize: 12, flex: 1 }, children: error }), onRemove && _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: "Cancel recording", onPress: onRemove, style: { padding: 8 }, children: _jsx(MessageIcon, { name: "close", color: c.foreground, size: 18 }) })] })] });
13
- return _jsxs(View, { testID: "voice-only-composer", style: { gap: 5 }, children: [renderAttachments?.(review, waiting || recording), _jsxs(View, { style: { flexDirection: 'row', alignItems: 'flex-end', gap: 4 }, children: [_jsxs(View, { style: { flex: 1, minWidth: 0, minHeight: 44, borderRadius: 22, backgroundColor: composerSurface(c.background), flexDirection: 'row', alignItems: 'center', overflow: 'hidden' }, children: [!recording && !review && !waiting && actions, review && !renderAttachments ? _jsx(View, { style: { flex: 1, minWidth: 0, paddingLeft: 10 }, children: review }) : recording ? _jsxs(View, { style: { flex: 1, minWidth: 0, flexDirection: 'row', alignItems: 'center', gap: 6, paddingLeft: 10 }, children: [_jsx(Text, { style: { fontSize: 11, fontWeight: '800', color: c.incomingText, fontVariant: ['tabular-nums'] }, children: duration(Math.floor(elapsedMs / 1000) * 1000) }), appearance.showWaveform !== false ? _jsx(Waveform, { samples: waveform, color: c.accent }) : _jsx(View, { style: { flex: 1 } }), _jsx(Text, { style: { fontSize: 11, fontWeight: '800', color: c.incomingText, fontVariant: ['tabular-nums'] }, children: duration(maxSeconds * 1000) })] }) : _jsx(View, { style: { flex: 1, minWidth: 0, paddingHorizontal: 12 }, children: _jsx(Text, { style: { color: c.secondary, fontSize: 14, fontWeight: '800' }, children: waiting ? (phase === 'uploading' ? 'Sending…' : 'Preparing…') : `Voice up to ${maxSeconds}s` }) }), _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: recording ? 'Stop recording' : 'Voice message', disabled: waiting || !!review || phase === 'failed', onPress: recording ? onStop : onRecord, style: { width: 42, height: 44, alignItems: 'center', justifyContent: 'center', opacity: (waiting || !!review || phase === 'failed') ? .45 : 1 }, children: waiting ? _jsx(ActivityIndicator, { size: "small", color: c.accent }) : _jsx(MessageIcon, { name: "mic", color: recording ? '#c94040' : c.accent, size: 23 }) })] }), _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: canSend ? 'Send voice message' : 'Send unavailable', accessibilityState: { disabled: !canSend }, disabled: !canSend, onPress: onSend, style: { width: 44, height: 44, alignItems: 'center', justifyContent: 'center', opacity: canSend ? 1 : .4 }, children: _jsx(MessageIcon, { name: "send", color: c.accent, size: 24 }) })] }), !!error && _jsxs(View, { style: { flexDirection: 'row', alignItems: 'center', gap: 8, paddingHorizontal: 8 }, children: [_jsx(Text, { accessibilityRole: "alert", style: { color: c.foreground, fontSize: 12, flex: 1 }, children: error }), onRemove && _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: "Cancel recording", onPress: onRemove, style: { padding: 8 }, children: _jsx(MessageIcon, { name: "close", color: c.foreground, size: 18 }) })] })] });
16
+ return _jsxs(View, { style: { gap: 4 }, children: [renderAttachments ? renderAttachments(review, waiting) : review && _jsx(View, { style: { paddingHorizontal: 8, paddingTop: 4 }, children: review }), renderTextComposer({ sendVoice: canSend ? onSend : undefined, hasVoice: !!review, blocked: waiting }), !!error && _jsxs(View, { style: { flexDirection: 'row', alignItems: 'center', gap: 8, paddingHorizontal: 8 }, children: [_jsx(Text, { accessibilityRole: "alert", style: { color: c.foreground, fontSize: 12, flex: 1 }, children: error }), onRemove && _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: uiText("Cancel recording"), onPress: onRemove, style: { padding: 8 }, children: _jsx(MessageIcon, { name: "close", color: c.foreground, size: 18 }) })] })] });
17
+ return _jsxs(View, { testID: "voice-only-composer", style: { gap: 5 }, children: [renderAttachments?.(review, waiting || recording), _jsxs(View, { style: { flexDirection: 'row', alignItems: 'flex-end', gap: 4 }, children: [_jsxs(View, { style: { flex: 1, minWidth: 0, minHeight: 44, borderRadius: 22, backgroundColor: composerSurface(c.background), flexDirection: 'row', alignItems: 'center', overflow: 'hidden' }, children: [!recording && !review && !waiting && actions, review && !renderAttachments ? _jsx(View, { style: { flex: 1, minWidth: 0, paddingLeft: 10 }, children: review }) : recording ? _jsxs(View, { style: { flex: 1, minWidth: 0, flexDirection: 'row', alignItems: 'center', gap: 6, paddingLeft: 10 }, children: [_jsx(Text, { style: { fontSize: 11, fontWeight: '800', color: c.incomingText, fontVariant: ['tabular-nums'] }, children: duration(Math.floor(elapsedMs / 1000) * 1000) }), appearance.showWaveform !== false ? _jsx(Waveform, { samples: waveform, color: c.accent }) : _jsx(View, { style: { flex: 1 } }), _jsx(Text, { style: { fontSize: 11, fontWeight: '800', color: c.incomingText, fontVariant: ['tabular-nums'] }, children: duration(maxSeconds * 1000) })] }) : _jsx(View, { style: { flex: 1, minWidth: 0, paddingHorizontal: 12 }, children: _jsx(Text, { style: { color: c.secondary, fontSize: 14, fontWeight: '800' }, children: waiting ? (phase === 'uploading' ? 'Sending…' : 'Preparing…') : uiText("Voice up to {value1}s", { value1: maxSeconds }) }) }), _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: recording ? uiText("Stop recording") : uiText("Voice message"), disabled: waiting || !!review || phase === 'failed', onPress: recording ? onStop : onRecord, style: { width: 42, height: 44, alignItems: 'center', justifyContent: 'center', opacity: (waiting || !!review || phase === 'failed') ? .45 : 1 }, children: waiting ? _jsx(ActivityIndicator, { size: "small", color: c.accent }) : _jsx(MessageIcon, { name: "mic", color: recording ? '#c94040' : c.accent, size: 23 }) })] }), _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: canSend ? uiText("Send voice message") : uiText("Send unavailable"), accessibilityState: { disabled: !canSend }, disabled: !canSend, onPress: onSend, style: { width: 44, height: 44, alignItems: 'center', justifyContent: 'center', opacity: canSend ? 1 : .4 }, children: _jsx(MessageIcon, { name: "send", color: c.accent, size: 24 }) })] }), !!error && _jsxs(View, { style: { flexDirection: 'row', alignItems: 'center', gap: 8, paddingHorizontal: 8 }, children: [_jsx(Text, { accessibilityRole: "alert", style: { color: c.foreground, fontSize: 12, flex: 1 }, children: error }), onRemove && _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: uiText("Cancel recording"), onPress: onRemove, style: { padding: 8 }, children: _jsx(MessageIcon, { name: "close", color: c.foreground, size: 18 }) })] })] });
14
18
  }
15
19
  export function VoiceDraftPlayback({ appearance, playing, positionMs = 0, durationMs = 0, waveform, onToggle, onRemove, disabled = false, error, compact = false }) {
20
+ const { text: uiText, locale: uiLocale, number: uiNumber, count: uiCount } = useRobonoLocale();
16
21
  const c = appearance.colors;
17
22
  if (compact)
18
- return _jsxs(View, { style: { width: 88, height: 84, paddingTop: 8, paddingRight: 10 }, children: [_jsxs(View, { style: { width: 76, height: 76, borderRadius: 9, borderWidth: 1, borderColor: c.secondary + '40', backgroundColor: c.background, alignItems: 'center', justifyContent: 'center', gap: 2 }, children: [_jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: playing ? 'Pause recorded voice message' : 'Play recorded voice message', disabled: disabled, onPress: onToggle, style: { width: 44, height: 38, alignItems: 'center', justifyContent: 'center' }, children: _jsx(View, { style: { width: 28, height: 28, borderRadius: 14, backgroundColor: c.accent, alignItems: 'center', justifyContent: 'center' }, children: _jsx(MessageIcon, { name: playing ? 'pause' : 'play', color: "#fff", size: 18 }) }) }), _jsx(Text, { style: { fontSize: 10, fontWeight: '800', color: c.foreground }, children: duration(positionMs >= durationMs ? durationMs : durationMs - positionMs) })] }), _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: "Remove voice message", disabled: disabled, onPress: onRemove, style: { position: 'absolute', right: 0, top: 0, width: 30, height: 30, alignItems: 'center', justifyContent: 'center' }, children: _jsx(View, { style: { width: 22, height: 22, borderRadius: 11, backgroundColor: c.foreground, alignItems: 'center', justifyContent: 'center' }, children: _jsx(MessageIcon, { name: "close", color: c.background, size: 14 }) }) }), !!error && _jsx(Text, { accessibilityRole: "alert", style: { color: c.foreground, fontSize: 11 }, children: error })] });
19
- return _jsxs(View, { style: { flex: 1, minWidth: 0, gap: 3 }, children: [_jsxs(View, { style: { flexDirection: 'row', alignItems: 'center', gap: 7, minHeight: 44 }, children: [_jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: playing ? 'Pause recorded voice message' : 'Play recorded voice message', disabled: disabled, onPress: onToggle, style: { width: 32, height: 32, borderRadius: 16, backgroundColor: c.accent, alignItems: 'center', justifyContent: 'center' }, children: _jsx(MessageIcon, { name: playing ? 'pause' : 'play', color: "#fff", size: 17 }) }), appearance.showWaveform !== false ? _jsx(Waveform, { samples: waveform, color: c.accent }) : _jsx(View, { style: { flex: 1 } }), _jsx(Text, { style: { fontSize: 12, fontWeight: '800', color: c.incomingText, fontVariant: ['tabular-nums'] }, children: duration(positionMs >= durationMs ? durationMs : durationMs - positionMs) }), _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: "Remove voice message", disabled: disabled, onPress: onRemove, style: { width: 30, height: 44, alignItems: 'center', justifyContent: 'center' }, children: _jsx(MessageIcon, { name: "close", color: c.incomingText, size: 16 }) })] }), !!error && _jsxs(View, { style: { flexDirection: 'row', alignItems: 'center', gap: 8, paddingHorizontal: 8 }, children: [_jsx(Text, { accessibilityRole: "alert", style: { color: c.foreground, fontSize: 12, flex: 1 }, children: error }), onRemove && _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: "Cancel recording", onPress: onRemove, style: { padding: 8 }, children: _jsx(MessageIcon, { name: "close", color: c.foreground, size: 18 }) })] })] });
23
+ return _jsxs(View, { style: { width: 88, height: 84, paddingTop: 8, paddingRight: 10 }, children: [_jsxs(View, { style: { width: 76, height: 76, borderRadius: 9, borderWidth: 1, borderColor: c.secondary + '40', backgroundColor: c.background, alignItems: 'center', justifyContent: 'center', gap: 2 }, children: [_jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: playing ? uiText("Pause recorded voice message") : uiText("Play recorded voice message"), disabled: disabled, onPress: onToggle, style: { width: 44, height: 38, alignItems: 'center', justifyContent: 'center' }, children: _jsx(View, { style: { width: 28, height: 28, borderRadius: 14, backgroundColor: c.accent, alignItems: 'center', justifyContent: 'center' }, children: _jsx(MessageIcon, { name: playing ? 'pause' : 'play', color: "#fff", size: 18 }) }) }), _jsx(Text, { style: { fontSize: 10, fontWeight: '800', color: c.foreground }, children: duration(positionMs >= durationMs ? durationMs : durationMs - positionMs) })] }), _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: uiText("Remove voice message"), disabled: disabled, onPress: onRemove, style: { position: 'absolute', right: 0, top: 0, width: 30, height: 30, alignItems: 'center', justifyContent: 'center' }, children: _jsx(View, { style: { width: 22, height: 22, borderRadius: 11, backgroundColor: c.foreground, alignItems: 'center', justifyContent: 'center' }, children: _jsx(MessageIcon, { name: "close", color: c.background, size: 14 }) }) }), !!error && _jsx(Text, { accessibilityRole: "alert", style: { color: c.foreground, fontSize: 11 }, children: error })] });
24
+ return _jsxs(View, { style: { flex: 1, minWidth: 0, gap: 3 }, children: [_jsxs(View, { style: { flexDirection: 'row', alignItems: 'center', gap: 7, minHeight: 44 }, children: [_jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: playing ? uiText("Pause recorded voice message") : uiText("Play recorded voice message"), disabled: disabled, onPress: onToggle, style: { width: 32, height: 32, borderRadius: 16, backgroundColor: c.accent, alignItems: 'center', justifyContent: 'center' }, children: _jsx(MessageIcon, { name: playing ? 'pause' : 'play', color: "#fff", size: 17 }) }), appearance.showWaveform !== false ? _jsx(Waveform, { samples: waveform, color: c.accent }) : _jsx(View, { style: { flex: 1 } }), _jsx(Text, { style: { fontSize: 12, fontWeight: '800', color: c.incomingText, fontVariant: ['tabular-nums'] }, children: duration(positionMs >= durationMs ? durationMs : durationMs - positionMs) }), _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: uiText("Remove voice message"), disabled: disabled, onPress: onRemove, style: { width: 30, height: 44, alignItems: 'center', justifyContent: 'center' }, children: _jsx(MessageIcon, { name: "close", color: c.incomingText, size: 16 }) })] }), !!error && _jsxs(View, { style: { flexDirection: 'row', alignItems: 'center', gap: 8, paddingHorizontal: 8 }, children: [_jsx(Text, { accessibilityRole: "alert", style: { color: c.foreground, fontSize: 12, flex: 1 }, children: error }), onRemove && _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: uiText("Cancel recording"), onPress: onRemove, style: { padding: 8 }, children: _jsx(MessageIcon, { name: "close", color: c.foreground, size: 18 }) })] })] });
20
25
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robono/messaging-react-native",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "description": "Optional, composable direct and group messaging screens for Robono.",
@@ -36,7 +36,8 @@
36
36
  "./expo-notifications": {
37
37
  "types": "./dist/expo-notifications.d.ts",
38
38
  "import": "./dist/expo-notifications.js"
39
- }
39
+ },
40
+ "./setup": "./setup.plugin.cjs"
40
41
  },
41
42
  "files": [
42
43
  "dist",
@@ -46,14 +47,15 @@
46
47
  "plugin",
47
48
  "CHANGELOG.md",
48
49
  "SBOM.spdx.json",
49
- "licenses"
50
+ "licenses",
51
+ "setup.plugin.cjs"
50
52
  ],
51
53
  "scripts": {
52
54
  "build": "tsc -p tsconfig.json",
53
55
  "prepack": "npm run build && node ../../scripts/generate-sdk-file-sbom.mjs"
54
56
  },
55
57
  "peerDependencies": {
56
- "@robono/messaging": "^0.5.0",
58
+ "@robono/messaging": "^0.7.0",
57
59
  "react": ">=18.2 <20",
58
60
  "react-native": ">=0.76 <1",
59
61
  "expo-audio": ">=55 <57",
@@ -65,7 +67,7 @@
65
67
  "expo-crypto": ">=55 <57",
66
68
  "react-native-safe-area-context": ">=5 <6",
67
69
  "react-native-svg": ">=15 <16",
68
- "@robono/calling-react-native": "^0.6.0",
70
+ "@robono/calling-react-native": "^0.8.0",
69
71
  "expo-clipboard": ">=8 <57",
70
72
  "expo-image-manipulator": ">=14 <57",
71
73
  "expo-video-thumbnails": ">=14 <57",
@@ -73,12 +75,12 @@
73
75
  "expo-blur": ">=55 <57",
74
76
  "expo-notifications": ">=55 <57",
75
77
  "expo-secure-store": ">=55 <57",
76
- "@robono/location-react-native": "^0.2.0",
78
+ "@robono/location-react-native": "^0.4.0",
77
79
  "expo-location": ">=55 <57",
78
80
  "expo-constants": ">=55 <57",
79
- "@robono/location": "^0.2.0",
81
+ "@robono/location": "^0.4.0",
80
82
  "expo-haptics": ">=55 <57",
81
- "@robono/calling": "^0.4.0"
83
+ "@robono/calling": "^0.5.0"
82
84
  },
83
85
  "license": "SEE LICENSE IN LICENSE",
84
86
  "peerDependenciesMeta": {
@@ -0,0 +1,20 @@
1
+ const {withPlugins,createRunOncePlugin}=require('expo/config-plugins');
2
+ const fs=require('node:fs');
3
+ const path=require('node:path');
4
+
5
+ /** One composition point for hosted Messenger. Explicit host plugin choices win. */
6
+ module.exports=createRunOncePlugin(config=>{
7
+ const existing=new Set((config.plugins??[]).map(p=>Array.isArray(p)?p[0]:p));
8
+ const plugins=[
9
+ ['expo-sensors',{motionPermission:'Allow this app to share device movement with the people you choose. This does not share your location.'}],
10
+ ['expo-location',{locationWhenInUsePermission:'Allow location access when you choose to share weather or your location.'}],
11
+ ['expo-audio',{microphonePermission:'Allow microphone access for voice messages and calls.',enableBackgroundRecording:false}],
12
+ ['expo-image-picker',{cameraPermission:'Allow camera access to take photos and videos for messages.'}],
13
+ 'expo-notifications','@robono/messaging-react-native',
14
+ ['@robono/calling-react-native',{video:true,screenSharing:true}],
15
+ ];
16
+ const root=config._internal?.projectRoot;
17
+ const accessFiles={ios:'.robono/maps-ios.json',android:'.robono/maps-android.json'};
18
+ if(root&&Object.values(accessFiles).every(file=>fs.existsSync(path.join(root,file))))plugins.push(['@robono/location-react-native',{accessFiles,background:true}]);
19
+ return withPlugins(config,plugins.filter(p=>!existing.has(Array.isArray(p)?p[0]:p)));
20
+ },'@robono/messaging-react-native/setup',require('./package.json').version);