@lorikeetai/react-native-sdk 2.1.0 → 2.2.0-beta.2
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/README.md +213 -0
- package/dist/customisations-BTaJ84md.d.cts +137 -0
- package/dist/customisations-BTaJ84md.d.cts.map +1 -0
- package/dist/customisations-BTaJ84md.d.ts +137 -0
- package/dist/customisations-BTaJ84md.d.ts.map +1 -0
- package/dist/index.cjs +2 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -135
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +1 -135
- package/dist/index.d.ts.map +1 -1
- package/dist/rolldown-runtime-xuxB8TGW.cjs +32 -0
- package/dist/voice.cjs +772 -0
- package/dist/voice.cjs.map +1 -0
- package/dist/voice.d.cts +83 -0
- package/dist/voice.d.cts.map +1 -0
- package/dist/voice.d.ts +83 -0
- package/dist/voice.d.ts.map +1 -0
- package/dist/voice.js +768 -0
- package/dist/voice.js.map +1 -0
- package/package.json +32 -3
package/dist/voice.cjs
ADDED
|
@@ -0,0 +1,772 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
const require_rolldown_runtime = require("./rolldown-runtime-xuxB8TGW.cjs");
|
|
3
|
+
let react = require("react");
|
|
4
|
+
let react_native = require("react-native");
|
|
5
|
+
let react_native_safe_area_context = require("react-native-safe-area-context");
|
|
6
|
+
let react_native_svg = require("react-native-svg");
|
|
7
|
+
react_native_svg = require_rolldown_runtime.__toESM(react_native_svg, 1);
|
|
8
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
9
|
+
let _livekit_react_native = require("@livekit/react-native");
|
|
10
|
+
let livekit_client = require("livekit-client");
|
|
11
|
+
|
|
12
|
+
// src/voice/call-icons.tsx
|
|
13
|
+
const Icon = ({ children }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native_svg.default, {
|
|
14
|
+
fill: "none",
|
|
15
|
+
height: 24,
|
|
16
|
+
viewBox: "0 0 24 24",
|
|
17
|
+
width: 24,
|
|
18
|
+
children
|
|
19
|
+
});
|
|
20
|
+
const stroke = (color) => ({
|
|
21
|
+
stroke: color,
|
|
22
|
+
strokeLinecap: "round",
|
|
23
|
+
strokeLinejoin: "round",
|
|
24
|
+
strokeWidth: 2
|
|
25
|
+
});
|
|
26
|
+
const MicIcon = ({ color }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Icon, { children: [
|
|
27
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native_svg.Path, {
|
|
28
|
+
d: "M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z",
|
|
29
|
+
...stroke(color)
|
|
30
|
+
}),
|
|
31
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native_svg.Path, {
|
|
32
|
+
d: "M19 10v2a7 7 0 0 1-14 0v-2",
|
|
33
|
+
...stroke(color)
|
|
34
|
+
}),
|
|
35
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native_svg.Line, {
|
|
36
|
+
x1: "12",
|
|
37
|
+
x2: "12",
|
|
38
|
+
y1: "19",
|
|
39
|
+
y2: "22",
|
|
40
|
+
...stroke(color)
|
|
41
|
+
})
|
|
42
|
+
] });
|
|
43
|
+
const MicOffIcon = ({ color }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Icon, { children: [
|
|
44
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native_svg.Line, {
|
|
45
|
+
x1: "2",
|
|
46
|
+
x2: "22",
|
|
47
|
+
y1: "2",
|
|
48
|
+
y2: "22",
|
|
49
|
+
...stroke(color)
|
|
50
|
+
}),
|
|
51
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native_svg.Path, {
|
|
52
|
+
d: "M18.89 13.23A7.12 7.12 0 0 0 19 12v-2",
|
|
53
|
+
...stroke(color)
|
|
54
|
+
}),
|
|
55
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native_svg.Path, {
|
|
56
|
+
d: "M5 10v2a7 7 0 0 0 12 5",
|
|
57
|
+
...stroke(color)
|
|
58
|
+
}),
|
|
59
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native_svg.Path, {
|
|
60
|
+
d: "M15 9.34V5a3 3 0 0 0-5.68-1.33",
|
|
61
|
+
...stroke(color)
|
|
62
|
+
}),
|
|
63
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native_svg.Path, {
|
|
64
|
+
d: "M9 9v3a3 3 0 0 0 5.12 2.12",
|
|
65
|
+
...stroke(color)
|
|
66
|
+
}),
|
|
67
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native_svg.Line, {
|
|
68
|
+
x1: "12",
|
|
69
|
+
x2: "12",
|
|
70
|
+
y1: "19",
|
|
71
|
+
y2: "22",
|
|
72
|
+
...stroke(color)
|
|
73
|
+
})
|
|
74
|
+
] });
|
|
75
|
+
const PhoneOffIcon = ({ color }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Icon, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native_svg.Path, {
|
|
76
|
+
d: "M10.68 13.31a16 16 0 0 0 3.41 2.6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7 2 2 0 0 1 1.72 2v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.42 19.42 0 0 1-3.33-2.67m-2.67-3.34a19.79 19.79 0 0 1-3.07-8.63A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91",
|
|
77
|
+
...stroke(color)
|
|
78
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native_svg.Line, {
|
|
79
|
+
x1: "22",
|
|
80
|
+
x2: "2",
|
|
81
|
+
y1: "2",
|
|
82
|
+
y2: "22",
|
|
83
|
+
...stroke(color)
|
|
84
|
+
})] });
|
|
85
|
+
const SPEAKER = "M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z";
|
|
86
|
+
const Volume2Icon = ({ color }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Icon, { children: [
|
|
87
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native_svg.Path, {
|
|
88
|
+
d: SPEAKER,
|
|
89
|
+
...stroke(color)
|
|
90
|
+
}),
|
|
91
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native_svg.Path, {
|
|
92
|
+
d: "M16 9a5 5 0 0 1 0 6",
|
|
93
|
+
...stroke(color)
|
|
94
|
+
}),
|
|
95
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native_svg.Path, {
|
|
96
|
+
d: "M19.364 18.364a9 9 0 0 0 0-12.728",
|
|
97
|
+
...stroke(color)
|
|
98
|
+
})
|
|
99
|
+
] });
|
|
100
|
+
const VolumeXIcon = ({ color }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Icon, { children: [
|
|
101
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native_svg.Path, {
|
|
102
|
+
d: SPEAKER,
|
|
103
|
+
...stroke(color)
|
|
104
|
+
}),
|
|
105
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native_svg.Line, {
|
|
106
|
+
x1: "22",
|
|
107
|
+
x2: "16",
|
|
108
|
+
y1: "9",
|
|
109
|
+
y2: "15",
|
|
110
|
+
...stroke(color)
|
|
111
|
+
}),
|
|
112
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native_svg.Line, {
|
|
113
|
+
x1: "16",
|
|
114
|
+
x2: "22",
|
|
115
|
+
y1: "9",
|
|
116
|
+
y2: "15",
|
|
117
|
+
...stroke(color)
|
|
118
|
+
})
|
|
119
|
+
] });
|
|
120
|
+
/** The design system's `LorikeetLogoMark`. `color` paints the whole mark in one colour. */
|
|
121
|
+
const LorikeetLogoMark = ({ color, size }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native_svg.default, {
|
|
122
|
+
fill: "none",
|
|
123
|
+
height: size,
|
|
124
|
+
viewBox: "-45 -20 274 274",
|
|
125
|
+
width: size,
|
|
126
|
+
children: [
|
|
127
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native_svg.Path, {
|
|
128
|
+
d: "M112.661 179.008C152.133 154.751 173.914 119.21 161.82 96.8859L81.0549 140.608L10.1309 179.008H112.667H112.661Z",
|
|
129
|
+
fill: color !== null && color !== void 0 ? color : "#FF29E5"
|
|
130
|
+
}),
|
|
131
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native_svg.Path, {
|
|
132
|
+
d: "M0.242676 184.284C0.242676 211.383 41.3656 233.356 92.0903 233.356C142.815 233.356 183.938 211.389 183.938 184.29H0.242676V184.284Z",
|
|
133
|
+
fill: color !== null && color !== void 0 ? color : "#4348DC"
|
|
134
|
+
}),
|
|
135
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native_svg.Path, {
|
|
136
|
+
d: "M83.4604 133.156C84.7013 131.069 85.9155 128.94 87.0924 126.763C111.185 82.1465 111.376 35.539 87.5131 22.6682L43.8872 103.459L4.88379 175.692L83.4604 133.156Z",
|
|
137
|
+
fill: color !== null && color !== void 0 ? color : "#EA4921"
|
|
138
|
+
}),
|
|
139
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native_svg.Path, {
|
|
140
|
+
d: "M49.0555 82.6487C46.4408 36.5522 25.5864 0.643799 0.242676 0.643799V92.4482V173.048L49.0555 82.6487Z",
|
|
141
|
+
fill: color !== null && color !== void 0 ? color : "#FACB12"
|
|
142
|
+
})
|
|
143
|
+
]
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// src/voice/call-theme.ts
|
|
147
|
+
const LIGHT = {
|
|
148
|
+
accent: "hsl(233, 69%, 55%)",
|
|
149
|
+
card: "hsl(240, 3%, 97%)",
|
|
150
|
+
control: "hsl(0, 0%, 100%)",
|
|
151
|
+
inverseText: "hsl(0, 0%, 100%)",
|
|
152
|
+
ring: "hsl(240, 31%, 94%)",
|
|
153
|
+
shell: "hsl(0, 0%, 100%)",
|
|
154
|
+
subtleText: "hsl(240, 3%, 31%)",
|
|
155
|
+
text: "hsl(240, 3%, 4%)"
|
|
156
|
+
};
|
|
157
|
+
const DARK = {
|
|
158
|
+
accent: "hsl(233, 68%, 65%)",
|
|
159
|
+
card: "hsl(240, 3%, 8%)",
|
|
160
|
+
control: "hsl(240, 3%, 4%)",
|
|
161
|
+
inverseText: "hsl(240, 0%, 2%)",
|
|
162
|
+
ring: "hsl(233, 69%, 15%)",
|
|
163
|
+
shell: "hsl(240, 0%, 2%)",
|
|
164
|
+
subtleText: "hsl(240, 3%, 61%)",
|
|
165
|
+
text: "hsl(240, 3%, 81%)"
|
|
166
|
+
};
|
|
167
|
+
const paintable = (colour) => {
|
|
168
|
+
var _processColor;
|
|
169
|
+
return colour !== void 0 && ((_processColor = (0, react_native.processColor)(colour)) !== null && _processColor !== void 0 ? _processColor : void 0) !== void 0 ? colour : void 0;
|
|
170
|
+
};
|
|
171
|
+
const hsl = (components) => components ? paintable(`hsl(${components})`) : void 0;
|
|
172
|
+
/** `generateVoiceWidgetThemeStyle` from the web Voice Widget, for React Native. */
|
|
173
|
+
function callColours(theme) {
|
|
174
|
+
var _hsl, _ref, _paintable, _hsl2, _hsl3, _ref2, _paintable2, _hsl4;
|
|
175
|
+
const base = (theme === null || theme === void 0 ? void 0 : theme.colorMode) === "dark" ? DARK : LIGHT;
|
|
176
|
+
return {
|
|
177
|
+
accent: (_hsl = hsl(theme === null || theme === void 0 ? void 0 : theme.brandColor)) !== null && _hsl !== void 0 ? _hsl : base.accent,
|
|
178
|
+
card: (_ref = (_paintable = paintable(theme === null || theme === void 0 ? void 0 : theme.headerBackground)) !== null && _paintable !== void 0 ? _paintable : hsl(theme === null || theme === void 0 ? void 0 : theme.brandAccentColor)) !== null && _ref !== void 0 ? _ref : base.card,
|
|
179
|
+
control: base.control,
|
|
180
|
+
inverseText: (_hsl2 = hsl(theme === null || theme === void 0 ? void 0 : theme.inverseTextColor)) !== null && _hsl2 !== void 0 ? _hsl2 : base.inverseText,
|
|
181
|
+
ring: (_hsl3 = hsl(theme === null || theme === void 0 ? void 0 : theme.subtleBrandColor)) !== null && _hsl3 !== void 0 ? _hsl3 : base.ring,
|
|
182
|
+
shell: (_ref2 = (_paintable2 = paintable(theme === null || theme === void 0 ? void 0 : theme.background)) !== null && _paintable2 !== void 0 ? _paintable2 : hsl(theme === null || theme === void 0 ? void 0 : theme.backgroundColor)) !== null && _ref2 !== void 0 ? _ref2 : base.shell,
|
|
183
|
+
subtleText: base.subtleText,
|
|
184
|
+
text: (_hsl4 = hsl(theme === null || theme === void 0 ? void 0 : theme.textColor)) !== null && _hsl4 !== void 0 ? _hsl4 : base.text
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// src/voice/call-wave.tsx
|
|
189
|
+
const BARS = 24;
|
|
190
|
+
const PHASES = 8;
|
|
191
|
+
const CYCLE_MS = 1440;
|
|
192
|
+
const STAGGER_MS = 90;
|
|
193
|
+
const MIN_HEIGHT = 8;
|
|
194
|
+
const MAX_HEIGHT = 38;
|
|
195
|
+
const STILL_HEIGHT = 20;
|
|
196
|
+
const triangle = (x) => 1 - Math.abs(2 * x - 1);
|
|
197
|
+
/**
|
|
198
|
+
* Where one bar's height peaks and troughs as the loop runs from 0 to 1, so a
|
|
199
|
+
* single animated value drives every phase.
|
|
200
|
+
*/
|
|
201
|
+
const phaseKeyframes = (phase) => {
|
|
202
|
+
const frames = /* @__PURE__ */ new Map([[0, triangle(phase)], [1, triangle(phase)]]);
|
|
203
|
+
for (const x of [0, .5]) frames.set((x - phase + 1) % 1, triangle(x));
|
|
204
|
+
const sorted = [...frames.entries()].sort(([a], [b]) => a - b);
|
|
205
|
+
return {
|
|
206
|
+
inputRange: sorted.map(([at]) => at),
|
|
207
|
+
outputRange: sorted.map(([, height]) => (MIN_HEIGHT + height * 30) / MAX_HEIGHT)
|
|
208
|
+
};
|
|
209
|
+
};
|
|
210
|
+
const useReduceMotion = () => {
|
|
211
|
+
const [reduceMotion, setReduceMotion] = (0, react.useState)(false);
|
|
212
|
+
(0, react.useEffect)(() => {
|
|
213
|
+
let mounted = true;
|
|
214
|
+
react_native.AccessibilityInfo.isReduceMotionEnabled().then((enabled) => {
|
|
215
|
+
if (mounted) setReduceMotion(enabled);
|
|
216
|
+
});
|
|
217
|
+
const subscription = react_native.AccessibilityInfo.addEventListener("reduceMotionChanged", setReduceMotion);
|
|
218
|
+
return () => {
|
|
219
|
+
mounted = false;
|
|
220
|
+
subscription.remove();
|
|
221
|
+
};
|
|
222
|
+
}, []);
|
|
223
|
+
return reduceMotion;
|
|
224
|
+
};
|
|
225
|
+
function CallWave({ active, color }) {
|
|
226
|
+
const reduceMotion = useReduceMotion();
|
|
227
|
+
const progress = (0, react.useRef)(new react_native.Animated.Value(0)).current;
|
|
228
|
+
const animate = active && !reduceMotion;
|
|
229
|
+
(0, react.useEffect)(() => {
|
|
230
|
+
if (!animate) return;
|
|
231
|
+
const loop = react_native.Animated.loop(react_native.Animated.timing(progress, {
|
|
232
|
+
duration: CYCLE_MS,
|
|
233
|
+
easing: react_native.Easing.linear,
|
|
234
|
+
toValue: 1,
|
|
235
|
+
useNativeDriver: true
|
|
236
|
+
}));
|
|
237
|
+
loop.start();
|
|
238
|
+
return () => {
|
|
239
|
+
loop.stop();
|
|
240
|
+
progress.setValue(0);
|
|
241
|
+
};
|
|
242
|
+
}, [animate, progress]);
|
|
243
|
+
const scales = (0, react.useMemo)(() => Array.from({ length: PHASES }, (_, index) => progress.interpolate(phaseKeyframes(index * STAGGER_MS / CYCLE_MS))), [progress]);
|
|
244
|
+
const stillScale = (active ? STILL_HEIGHT : MIN_HEIGHT) / MAX_HEIGHT;
|
|
245
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, {
|
|
246
|
+
accessibilityElementsHidden: true,
|
|
247
|
+
importantForAccessibility: "no-hide-descendants",
|
|
248
|
+
style: styles$1.wave,
|
|
249
|
+
children: Array.from({ length: BARS }, (_, index) => {
|
|
250
|
+
var _scales;
|
|
251
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Animated.View, { style: [
|
|
252
|
+
styles$1.bar,
|
|
253
|
+
{ backgroundColor: color },
|
|
254
|
+
{ transform: [{ scaleY: animate ? (_scales = scales[index % PHASES]) !== null && _scales !== void 0 ? _scales : stillScale : stillScale }] }
|
|
255
|
+
] }, index);
|
|
256
|
+
})
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
const styles$1 = react_native.StyleSheet.create({
|
|
260
|
+
bar: {
|
|
261
|
+
borderRadius: 999,
|
|
262
|
+
height: MAX_HEIGHT,
|
|
263
|
+
opacity: .45,
|
|
264
|
+
width: 3
|
|
265
|
+
},
|
|
266
|
+
wave: {
|
|
267
|
+
alignItems: "center",
|
|
268
|
+
flexDirection: "row",
|
|
269
|
+
gap: 3,
|
|
270
|
+
height: 48,
|
|
271
|
+
justifyContent: "center"
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
// src/voice/use-lorikeet-call.ts
|
|
276
|
+
/** The server's `LORIKEET_AGENT_IDENTITY`. The call ends when it leaves. */
|
|
277
|
+
const LORIKEET_AGENT_IDENTITY = "lorikeet-agent";
|
|
278
|
+
const errorFor = (error) => {
|
|
279
|
+
if (typeof error !== "object" || error === null || !("name" in error)) return "failed";
|
|
280
|
+
return error.name === "SecurityError" || error.name === "NotAllowedError" ? "microphone_denied" : "failed";
|
|
281
|
+
};
|
|
282
|
+
const isSession = (value) => typeof value === "object" && value !== null && "conversationId" in value && typeof value.conversationId === "string" && "token" in value && typeof value.token === "string" && "wsUrl" in value && typeof value.wsUrl === "string";
|
|
283
|
+
/**
|
|
284
|
+
* Runs a Lorikeet voice call over LiveKit's native audio, with the web Voice
|
|
285
|
+
* Widget's states and errors.
|
|
286
|
+
*/
|
|
287
|
+
function useLorikeetCall({ getSession, onError }) {
|
|
288
|
+
const [state, setState] = (0, react.useState)("idle");
|
|
289
|
+
const [error, setError] = (0, react.useState)();
|
|
290
|
+
const [ended, setEnded] = (0, react.useState)(false);
|
|
291
|
+
const [microphoneMuted, setMicrophoneMutedState] = (0, react.useState)(false);
|
|
292
|
+
const [speakerMuted, setSpeakerMutedState] = (0, react.useState)(false);
|
|
293
|
+
const stateRef = (0, react.useRef)(state);
|
|
294
|
+
const generationRef = (0, react.useRef)(0);
|
|
295
|
+
const localTrackRef = (0, react.useRef)(null);
|
|
296
|
+
const roomRef = (0, react.useRef)(null);
|
|
297
|
+
const speakerMutedRef = (0, react.useRef)(false);
|
|
298
|
+
const audioSessionActiveRef = (0, react.useRef)(false);
|
|
299
|
+
const audioSessionStoppedRef = (0, react.useRef)(Promise.resolve());
|
|
300
|
+
const optionsRef = (0, react.useRef)({
|
|
301
|
+
getSession,
|
|
302
|
+
onError
|
|
303
|
+
});
|
|
304
|
+
optionsRef.current = {
|
|
305
|
+
getSession,
|
|
306
|
+
onError
|
|
307
|
+
};
|
|
308
|
+
const transitionTo = (0, react.useCallback)((next) => {
|
|
309
|
+
stateRef.current = next;
|
|
310
|
+
setState(next);
|
|
311
|
+
}, []);
|
|
312
|
+
const cleanup = (0, react.useCallback)(() => {
|
|
313
|
+
var _localTrackRef$curren;
|
|
314
|
+
(_localTrackRef$curren = localTrackRef.current) === null || _localTrackRef$curren === void 0 || _localTrackRef$curren.stop();
|
|
315
|
+
localTrackRef.current = null;
|
|
316
|
+
const room = roomRef.current;
|
|
317
|
+
roomRef.current = null;
|
|
318
|
+
const disconnected = (room ? room.disconnect() : Promise.resolve()).catch(() => void 0);
|
|
319
|
+
if (audioSessionActiveRef.current) {
|
|
320
|
+
audioSessionActiveRef.current = false;
|
|
321
|
+
audioSessionStoppedRef.current = disconnected.then(() => _livekit_react_native.AudioSession.stopAudioSession()).catch(() => void 0);
|
|
322
|
+
}
|
|
323
|
+
}, []);
|
|
324
|
+
const resetMutes = (0, react.useCallback)(() => {
|
|
325
|
+
setMicrophoneMutedState(false);
|
|
326
|
+
setSpeakerMutedState(false);
|
|
327
|
+
speakerMutedRef.current = false;
|
|
328
|
+
}, []);
|
|
329
|
+
const end = (0, react.useCallback)(() => {
|
|
330
|
+
generationRef.current += 1;
|
|
331
|
+
cleanup();
|
|
332
|
+
setEnded(stateRef.current === "connecting" || stateRef.current === "active");
|
|
333
|
+
setError(void 0);
|
|
334
|
+
resetMutes();
|
|
335
|
+
transitionTo("idle");
|
|
336
|
+
}, [
|
|
337
|
+
cleanup,
|
|
338
|
+
resetMutes,
|
|
339
|
+
transitionTo
|
|
340
|
+
]);
|
|
341
|
+
const fail = (0, react.useCallback)((callError) => {
|
|
342
|
+
generationRef.current += 1;
|
|
343
|
+
cleanup();
|
|
344
|
+
setEnded(false);
|
|
345
|
+
setError(callError);
|
|
346
|
+
transitionTo("error");
|
|
347
|
+
}, [cleanup, transitionTo]);
|
|
348
|
+
(0, react.useEffect)(() => {
|
|
349
|
+
return () => {
|
|
350
|
+
generationRef.current += 1;
|
|
351
|
+
cleanup();
|
|
352
|
+
};
|
|
353
|
+
}, [cleanup]);
|
|
354
|
+
const start = (0, react.useCallback)(async () => {
|
|
355
|
+
if (stateRef.current !== "idle" && stateRef.current !== "error") return;
|
|
356
|
+
setError(void 0);
|
|
357
|
+
setEnded(false);
|
|
358
|
+
resetMutes();
|
|
359
|
+
transitionTo("starting");
|
|
360
|
+
const generation = ++generationRef.current;
|
|
361
|
+
const isStale = () => generationRef.current !== generation;
|
|
362
|
+
try {
|
|
363
|
+
if (!("LiveKitReactNativeGlobal" in globalThis)) (0, _livekit_react_native.registerGlobals)();
|
|
364
|
+
await audioSessionStoppedRef.current;
|
|
365
|
+
if (isStale()) return;
|
|
366
|
+
audioSessionActiveRef.current = true;
|
|
367
|
+
await _livekit_react_native.AudioSession.startAudioSession();
|
|
368
|
+
if (isStale()) return;
|
|
369
|
+
const localTrack = await (0, livekit_client.createLocalAudioTrack)();
|
|
370
|
+
if (isStale()) {
|
|
371
|
+
localTrack.stop();
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
localTrackRef.current = localTrack;
|
|
375
|
+
const session = await optionsRef.current.getSession();
|
|
376
|
+
if (isStale()) return;
|
|
377
|
+
if (session === null) {
|
|
378
|
+
fail("not_available");
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
if (!isSession(session)) throw new TypeError("getSession must resolve to { conversationId, wsUrl, token } or null");
|
|
382
|
+
transitionTo("connecting");
|
|
383
|
+
const room = new livekit_client.Room();
|
|
384
|
+
roomRef.current = room;
|
|
385
|
+
const isCurrentRoom = () => roomRef.current === room;
|
|
386
|
+
room.on(livekit_client.RoomEvent.ParticipantDisconnected, (participant) => {
|
|
387
|
+
if (isCurrentRoom() && participant.identity === "lorikeet-agent") end();
|
|
388
|
+
});
|
|
389
|
+
room.on(livekit_client.RoomEvent.TrackSubscribed, (track) => {
|
|
390
|
+
if (isCurrentRoom() && track instanceof livekit_client.RemoteAudioTrack) track.setVolume(speakerMutedRef.current ? 0 : 1);
|
|
391
|
+
});
|
|
392
|
+
let joined = false;
|
|
393
|
+
room.on(livekit_client.RoomEvent.Disconnected, () => {
|
|
394
|
+
if (isCurrentRoom() && joined) end();
|
|
395
|
+
});
|
|
396
|
+
await room.connect(session.wsUrl, session.token, { autoSubscribe: true });
|
|
397
|
+
if (isStale()) return;
|
|
398
|
+
joined = true;
|
|
399
|
+
await room.localParticipant.publishTrack(localTrack, { source: livekit_client.Track.Source.Microphone });
|
|
400
|
+
if (isStale()) return;
|
|
401
|
+
transitionTo("active");
|
|
402
|
+
} catch (caught) {
|
|
403
|
+
if (isStale()) return;
|
|
404
|
+
const callError = errorFor(caught);
|
|
405
|
+
fail(callError);
|
|
406
|
+
if (callError === "failed") try {
|
|
407
|
+
var _optionsRef$current$o, _optionsRef$current;
|
|
408
|
+
(_optionsRef$current$o = (_optionsRef$current = optionsRef.current).onError) === null || _optionsRef$current$o === void 0 || _optionsRef$current$o.call(_optionsRef$current, caught);
|
|
409
|
+
} catch {}
|
|
410
|
+
}
|
|
411
|
+
}, [
|
|
412
|
+
end,
|
|
413
|
+
fail,
|
|
414
|
+
resetMutes,
|
|
415
|
+
transitionTo
|
|
416
|
+
]);
|
|
417
|
+
return {
|
|
418
|
+
end,
|
|
419
|
+
ended,
|
|
420
|
+
error,
|
|
421
|
+
microphoneMuted,
|
|
422
|
+
setMicrophoneMuted: (0, react.useCallback)((muted) => {
|
|
423
|
+
const track = localTrackRef.current;
|
|
424
|
+
if (!track) return;
|
|
425
|
+
const reconcile = () => {
|
|
426
|
+
if (localTrackRef.current === track) setMicrophoneMutedState(track.isMuted);
|
|
427
|
+
};
|
|
428
|
+
(muted ? track.mute() : track.unmute()).then(reconcile, reconcile);
|
|
429
|
+
}, []),
|
|
430
|
+
setSpeakerMuted: (0, react.useCallback)((muted) => {
|
|
431
|
+
var _roomRef$current$remo, _roomRef$current;
|
|
432
|
+
speakerMutedRef.current = muted;
|
|
433
|
+
const participants = (_roomRef$current$remo = (_roomRef$current = roomRef.current) === null || _roomRef$current === void 0 ? void 0 : _roomRef$current.remoteParticipants.values()) !== null && _roomRef$current$remo !== void 0 ? _roomRef$current$remo : [];
|
|
434
|
+
for (const participant of participants) for (const { track } of participant.audioTrackPublications.values()) if (track instanceof livekit_client.RemoteAudioTrack) track.setVolume(muted ? 0 : 1);
|
|
435
|
+
setSpeakerMutedState(muted);
|
|
436
|
+
}, []),
|
|
437
|
+
speakerMuted,
|
|
438
|
+
start,
|
|
439
|
+
state
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// src/voice/lorikeet-call-view.tsx
|
|
444
|
+
const ERROR_MESSAGES = {
|
|
445
|
+
failed: "The call could not start. Please try again.",
|
|
446
|
+
microphone_denied: "Allow microphone access, then try again.",
|
|
447
|
+
microphone_system_denied: "Enable microphone access for your browser in system settings.",
|
|
448
|
+
not_available: "We can't start a call on this page. Please try again later."
|
|
449
|
+
};
|
|
450
|
+
const errorHeading = (error) => error === "not_available" ? "Calling isn't available right now" : "Something went wrong";
|
|
451
|
+
const formatDuration = (seconds) => `${Math.floor(seconds / 60)}:${String(seconds % 60).padStart(2, "0")}`;
|
|
452
|
+
const statusLabel = (state, seconds) => {
|
|
453
|
+
switch (state) {
|
|
454
|
+
case "active": return formatDuration(seconds);
|
|
455
|
+
case "starting": return "Starting call";
|
|
456
|
+
case "connecting": return "Connecting";
|
|
457
|
+
case "error":
|
|
458
|
+
case "idle": return;
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
/** What a screen reader hears when the call state changes. The clock is left out. */
|
|
462
|
+
const announcementFor = ({ ended, error, state }) => {
|
|
463
|
+
switch (state) {
|
|
464
|
+
case "active": return "Listening";
|
|
465
|
+
case "error": return `${errorHeading(error !== null && error !== void 0 ? error : "failed")}. ${ERROR_MESSAGES[error !== null && error !== void 0 ? error : "failed"]}`;
|
|
466
|
+
case "idle": return ended ? "Call ended" : void 0;
|
|
467
|
+
case "starting":
|
|
468
|
+
case "connecting": return statusLabel(state, 0);
|
|
469
|
+
}
|
|
470
|
+
};
|
|
471
|
+
const useCallSeconds = (state) => {
|
|
472
|
+
const [seconds, setSeconds] = (0, react.useState)(0);
|
|
473
|
+
(0, react.useEffect)(() => {
|
|
474
|
+
if (state !== "active") {
|
|
475
|
+
setSeconds(0);
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
const interval = setInterval(() => setSeconds((value) => value + 1), 1e3);
|
|
479
|
+
return () => clearInterval(interval);
|
|
480
|
+
}, [state]);
|
|
481
|
+
return seconds;
|
|
482
|
+
};
|
|
483
|
+
function CallLogo({ logoUrl }) {
|
|
484
|
+
if (!logoUrl) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LorikeetLogoMark, { size: 48 });
|
|
485
|
+
if (/\.svg($|[?#])/i.test(logoUrl)) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native_svg.SvgUri, {
|
|
486
|
+
height: 48,
|
|
487
|
+
uri: logoUrl,
|
|
488
|
+
width: 48
|
|
489
|
+
});
|
|
490
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Image, {
|
|
491
|
+
resizeMode: "contain",
|
|
492
|
+
source: { uri: logoUrl },
|
|
493
|
+
style: styles.logo
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
function CallMessage({ call, colours }) {
|
|
497
|
+
if (call.state === "error") {
|
|
498
|
+
var _call$error;
|
|
499
|
+
const error = (_call$error = call.error) !== null && _call$error !== void 0 ? _call$error : "failed";
|
|
500
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
|
|
501
|
+
style: [styles.bold, { color: colours.text }],
|
|
502
|
+
children: errorHeading(error)
|
|
503
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
|
|
504
|
+
style: [styles.body, { color: colours.subtleText }],
|
|
505
|
+
children: ERROR_MESSAGES[error]
|
|
506
|
+
})] });
|
|
507
|
+
}
|
|
508
|
+
if (call.state === "active") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
|
|
509
|
+
style: [styles.body, { color: colours.text }],
|
|
510
|
+
children: "Listening"
|
|
511
|
+
});
|
|
512
|
+
if (call.ended) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.View, {
|
|
513
|
+
style: styles.marker,
|
|
514
|
+
children: [
|
|
515
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, { style: [styles.markerRule, { backgroundColor: colours.subtleText }] }),
|
|
516
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
|
|
517
|
+
style: [styles.small, { color: colours.subtleText }],
|
|
518
|
+
children: "Call ended"
|
|
519
|
+
}),
|
|
520
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, { style: [styles.markerRule, { backgroundColor: colours.subtleText }] })
|
|
521
|
+
]
|
|
522
|
+
});
|
|
523
|
+
return null;
|
|
524
|
+
}
|
|
525
|
+
function RoundButton({ children, disabled = false, label, onPress, style }) {
|
|
526
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.TouchableOpacity, {
|
|
527
|
+
accessibilityLabel: label,
|
|
528
|
+
accessibilityRole: "button",
|
|
529
|
+
accessibilityState: { disabled },
|
|
530
|
+
disabled,
|
|
531
|
+
onPress,
|
|
532
|
+
style: [
|
|
533
|
+
styles.roundButton,
|
|
534
|
+
style,
|
|
535
|
+
disabled && styles.disabled
|
|
536
|
+
],
|
|
537
|
+
children
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
function CallActions({ call, colours }) {
|
|
541
|
+
if (call.state === "idle" || call.state === "error") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.TouchableOpacity, {
|
|
542
|
+
accessibilityRole: "button",
|
|
543
|
+
onPress: () => void call.start(),
|
|
544
|
+
style: [styles.startButton, { backgroundColor: colours.accent }],
|
|
545
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
|
|
546
|
+
style: [styles.bold, { color: colours.inverseText }],
|
|
547
|
+
children: "Start call"
|
|
548
|
+
})
|
|
549
|
+
});
|
|
550
|
+
const inactive = call.state !== "active";
|
|
551
|
+
const control = { backgroundColor: colours.control };
|
|
552
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.View, {
|
|
553
|
+
style: styles.controls,
|
|
554
|
+
children: [
|
|
555
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(RoundButton, {
|
|
556
|
+
disabled: inactive,
|
|
557
|
+
label: call.microphoneMuted ? "Unmute microphone" : "Mute microphone",
|
|
558
|
+
onPress: () => call.setMicrophoneMuted(!call.microphoneMuted),
|
|
559
|
+
style: control,
|
|
560
|
+
children: call.microphoneMuted ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MicOffIcon, { color: colours.accent }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MicIcon, { color: colours.accent })
|
|
561
|
+
}),
|
|
562
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(RoundButton, {
|
|
563
|
+
label: "End call",
|
|
564
|
+
onPress: call.end,
|
|
565
|
+
style: { backgroundColor: colours.accent },
|
|
566
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PhoneOffIcon, { color: colours.inverseText })
|
|
567
|
+
}),
|
|
568
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(RoundButton, {
|
|
569
|
+
disabled: inactive,
|
|
570
|
+
label: call.speakerMuted ? "Unmute speaker" : "Mute speaker",
|
|
571
|
+
onPress: () => call.setSpeakerMuted(!call.speakerMuted),
|
|
572
|
+
style: control,
|
|
573
|
+
children: call.speakerMuted ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(VolumeXIcon, { color: colours.accent }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Volume2Icon, { color: colours.accent })
|
|
574
|
+
})
|
|
575
|
+
]
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
function PoweredBy({ color }) {
|
|
579
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.TouchableOpacity, {
|
|
580
|
+
accessibilityLabel: "Powered by Lorikeet",
|
|
581
|
+
accessibilityRole: "link",
|
|
582
|
+
onPress: () => void react_native.Linking.openURL("https://lorikeetcx.ai"),
|
|
583
|
+
style: styles.poweredBy,
|
|
584
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(LorikeetLogoMark, {
|
|
585
|
+
color,
|
|
586
|
+
size: 16
|
|
587
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
|
|
588
|
+
style: [styles.small, { color }],
|
|
589
|
+
children: "Powered by Lorikeet"
|
|
590
|
+
})]
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
/** The web Voice Widget's call screen and copy, on `useLorikeetCall`. */
|
|
594
|
+
function LorikeetCallView({ customisations, getSession, onError, style }) {
|
|
595
|
+
const call = useLorikeetCall({
|
|
596
|
+
getSession,
|
|
597
|
+
onError
|
|
598
|
+
});
|
|
599
|
+
const seconds = useCallSeconds(call.state);
|
|
600
|
+
const colours = callColours(customisations === null || customisations === void 0 ? void 0 : customisations.theme);
|
|
601
|
+
const status = statusLabel(call.state, seconds);
|
|
602
|
+
const announcement = announcementFor(call);
|
|
603
|
+
const liveRegion = react_native.Platform.OS === "android" ? "polite" : void 0;
|
|
604
|
+
(0, react.useEffect)(() => {
|
|
605
|
+
if (react_native.Platform.OS === "ios" && announcement) react_native.AccessibilityInfo.announceForAccessibilityWithOptions(announcement, { queue: true });
|
|
606
|
+
}, [announcement]);
|
|
607
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native_safe_area_context.SafeAreaView, {
|
|
608
|
+
style: [
|
|
609
|
+
styles.shell,
|
|
610
|
+
{ backgroundColor: colours.shell },
|
|
611
|
+
style
|
|
612
|
+
],
|
|
613
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.View, {
|
|
614
|
+
style: styles.ringed,
|
|
615
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, { style: [
|
|
616
|
+
react_native.StyleSheet.absoluteFill,
|
|
617
|
+
styles.ring,
|
|
618
|
+
{ backgroundColor: colours.ring }
|
|
619
|
+
] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.View, {
|
|
620
|
+
style: [styles.card, {
|
|
621
|
+
backgroundColor: colours.card,
|
|
622
|
+
shadowColor: colours.accent
|
|
623
|
+
}],
|
|
624
|
+
children: [
|
|
625
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.View, {
|
|
626
|
+
style: styles.identity,
|
|
627
|
+
children: [
|
|
628
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(CallLogo, { logoUrl: customisations === null || customisations === void 0 ? void 0 : customisations.logoUrl }),
|
|
629
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
|
|
630
|
+
accessibilityRole: "header",
|
|
631
|
+
numberOfLines: 1,
|
|
632
|
+
style: [styles.bold, { color: colours.text }],
|
|
633
|
+
children: (customisations === null || customisations === void 0 ? void 0 : customisations.title) || "Lorikeet AI Agent"
|
|
634
|
+
}),
|
|
635
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.Text, {
|
|
636
|
+
accessibilityElementsHidden: !status,
|
|
637
|
+
accessibilityLiveRegion: call.state === "active" ? "none" : liveRegion,
|
|
638
|
+
style: [styles.small, { color: colours.text }],
|
|
639
|
+
children: status
|
|
640
|
+
})
|
|
641
|
+
]
|
|
642
|
+
}),
|
|
643
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(CallWave, {
|
|
644
|
+
active: call.state === "active",
|
|
645
|
+
color: colours.accent
|
|
646
|
+
}),
|
|
647
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_native.View, {
|
|
648
|
+
accessibilityLiveRegion: liveRegion,
|
|
649
|
+
style: styles.message,
|
|
650
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CallMessage, {
|
|
651
|
+
call,
|
|
652
|
+
colours
|
|
653
|
+
})
|
|
654
|
+
}),
|
|
655
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_native.View, {
|
|
656
|
+
style: styles.footer,
|
|
657
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(CallActions, {
|
|
658
|
+
call,
|
|
659
|
+
colours
|
|
660
|
+
}), (customisations === null || customisations === void 0 ? void 0 : customisations.useSubtleBranding) ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PoweredBy, { color: colours.subtleText })]
|
|
661
|
+
})
|
|
662
|
+
]
|
|
663
|
+
})]
|
|
664
|
+
})
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
const styles = react_native.StyleSheet.create({
|
|
668
|
+
body: {
|
|
669
|
+
fontSize: 14,
|
|
670
|
+
lineHeight: 20,
|
|
671
|
+
textAlign: "center"
|
|
672
|
+
},
|
|
673
|
+
bold: {
|
|
674
|
+
fontSize: 14,
|
|
675
|
+
fontWeight: "600",
|
|
676
|
+
lineHeight: 20,
|
|
677
|
+
textAlign: "center"
|
|
678
|
+
},
|
|
679
|
+
card: {
|
|
680
|
+
alignItems: "center",
|
|
681
|
+
borderColor: "rgba(255, 255, 255, 0.8)",
|
|
682
|
+
borderRadius: 20,
|
|
683
|
+
borderWidth: 1,
|
|
684
|
+
elevation: 8,
|
|
685
|
+
flex: 1,
|
|
686
|
+
justifyContent: "space-between",
|
|
687
|
+
paddingHorizontal: 24,
|
|
688
|
+
paddingVertical: 32,
|
|
689
|
+
shadowOffset: {
|
|
690
|
+
height: 18,
|
|
691
|
+
width: 0
|
|
692
|
+
},
|
|
693
|
+
shadowOpacity: .28,
|
|
694
|
+
shadowRadius: 17
|
|
695
|
+
},
|
|
696
|
+
controls: {
|
|
697
|
+
alignItems: "center",
|
|
698
|
+
flexDirection: "row",
|
|
699
|
+
gap: 12
|
|
700
|
+
},
|
|
701
|
+
disabled: { opacity: .5 },
|
|
702
|
+
footer: {
|
|
703
|
+
alignItems: "center",
|
|
704
|
+
gap: 16
|
|
705
|
+
},
|
|
706
|
+
identity: {
|
|
707
|
+
alignItems: "center",
|
|
708
|
+
gap: 8,
|
|
709
|
+
maxWidth: 320
|
|
710
|
+
},
|
|
711
|
+
logo: {
|
|
712
|
+
height: 48,
|
|
713
|
+
width: 48
|
|
714
|
+
},
|
|
715
|
+
marker: {
|
|
716
|
+
alignItems: "center",
|
|
717
|
+
flexDirection: "row",
|
|
718
|
+
gap: 8,
|
|
719
|
+
width: "100%"
|
|
720
|
+
},
|
|
721
|
+
markerRule: {
|
|
722
|
+
flex: 1,
|
|
723
|
+
height: react_native.StyleSheet.hairlineWidth,
|
|
724
|
+
opacity: .4
|
|
725
|
+
},
|
|
726
|
+
message: {
|
|
727
|
+
gap: 4,
|
|
728
|
+
justifyContent: "center",
|
|
729
|
+
maxWidth: 320,
|
|
730
|
+
minHeight: 96,
|
|
731
|
+
width: "100%"
|
|
732
|
+
},
|
|
733
|
+
poweredBy: {
|
|
734
|
+
alignItems: "center",
|
|
735
|
+
flexDirection: "row",
|
|
736
|
+
gap: 2
|
|
737
|
+
},
|
|
738
|
+
ring: {
|
|
739
|
+
borderRadius: 27,
|
|
740
|
+
opacity: .8
|
|
741
|
+
},
|
|
742
|
+
ringed: {
|
|
743
|
+
flex: 1,
|
|
744
|
+
padding: 7
|
|
745
|
+
},
|
|
746
|
+
roundButton: {
|
|
747
|
+
alignItems: "center",
|
|
748
|
+
borderRadius: 24,
|
|
749
|
+
height: 48,
|
|
750
|
+
justifyContent: "center",
|
|
751
|
+
width: 48
|
|
752
|
+
},
|
|
753
|
+
shell: {
|
|
754
|
+
flex: 1,
|
|
755
|
+
padding: 16
|
|
756
|
+
},
|
|
757
|
+
small: {
|
|
758
|
+
fontSize: 12,
|
|
759
|
+
lineHeight: 16,
|
|
760
|
+
textAlign: "center"
|
|
761
|
+
},
|
|
762
|
+
startButton: {
|
|
763
|
+
borderRadius: 8,
|
|
764
|
+
justifyContent: "center",
|
|
765
|
+
minHeight: 40,
|
|
766
|
+
paddingHorizontal: 16
|
|
767
|
+
}
|
|
768
|
+
});
|
|
769
|
+
|
|
770
|
+
exports.LorikeetCallView = LorikeetCallView;
|
|
771
|
+
exports.useLorikeetCall = useLorikeetCall;
|
|
772
|
+
//# sourceMappingURL=voice.cjs.map
|