@vinaverse/react-native 0.1.0-alpha.3 → 0.1.0-alpha.5
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 +98 -2
- package/dist/index.cjs +1152 -166
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +401 -108
- package/dist/index.d.ts +401 -108
- package/dist/index.js +1098 -169
- package/dist/index.js.map +1 -1
- package/package.json +98 -6
package/dist/index.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { useAgentRuntime, useAgentConversation, useAgentName, useAgentLauncher, useAgentFeatures } from '@vinaverse/react/agent';
|
|
2
|
+
export { AgentRuntimeProvider, greetedKey, useAgentConversation, useAgentFeatures, useAgentLauncher, useAgentName, useAgentProfile, useAgentRuntime, useAgentStatus } from '@vinaverse/react/agent';
|
|
3
|
+
import { FlashList } from '@shopify/flash-list';
|
|
4
|
+
import { useCopy, useConversationSelector, useStreamingText, formatMoney, formatTimeRange, formatDate, bannedWordsIn, CopyProvider } from '@vinaverse/react';
|
|
5
|
+
import { Pressable, ActivityIndicator, Text, View, Image, TextInput, AccessibilityInfo, Linking, useColorScheme, useWindowDimensions, AppState, Platform, KeyboardAvoidingView, Keyboard, Animated } from 'react-native';
|
|
6
|
+
import { readCard } from '@vinaverse/client/agent';
|
|
7
|
+
import { createContext, memo, useMemo, useCallback, useState, useRef, useEffect, useContext } from 'react';
|
|
3
8
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
4
9
|
import { contrastRatio, colors, size, motion, radius, space, font, contrastProblems } from '@vinaverse/tokens';
|
|
5
|
-
import { useCopy, useConversationSelector, useStreamingText, formatTimeRange, formatMoney, formatDate, bannedWordsIn, CopyProvider } from '@vinaverse/react';
|
|
6
10
|
import { codePoints, MAX_TEXT, answerProblem } from '@vinaverse/client/conversation';
|
|
7
|
-
import { FlashList } from '@shopify/flash-list';
|
|
8
11
|
|
|
9
|
-
// src/
|
|
12
|
+
// src/index.ts
|
|
10
13
|
var ChatContext = createContext(null);
|
|
11
14
|
function ChatContextProvider(props) {
|
|
12
15
|
return /* @__PURE__ */ jsx(ChatContext.Provider, { value: props.value, children: props.children });
|
|
@@ -55,6 +58,61 @@ function ThemeProvider(props) {
|
|
|
55
58
|
function useTheme() {
|
|
56
59
|
return useContext(ThemeContext);
|
|
57
60
|
}
|
|
61
|
+
var Button = memo(function Button2(props) {
|
|
62
|
+
const { colors: colors2, radius: radius2, space: space2, size: size3, font: font2 } = useTheme();
|
|
63
|
+
const variant = props.variant ?? "secondary";
|
|
64
|
+
const inactive = props.disabled === true || props.busy === true;
|
|
65
|
+
const filled = variant === "primary" || props.selected === true;
|
|
66
|
+
const background = filled ? colors2.primary : variant === "secondary" ? colors2.surface : "transparent";
|
|
67
|
+
const foreground = filled ? colors2.onPrimary : colors2.primary;
|
|
68
|
+
const checkable = props.role === "radio" || props.role === "checkbox";
|
|
69
|
+
return /* @__PURE__ */ jsxs(
|
|
70
|
+
Pressable,
|
|
71
|
+
{
|
|
72
|
+
accessibilityRole: props.role ?? "button",
|
|
73
|
+
accessibilityLabel: props.label,
|
|
74
|
+
...props.hint ? { accessibilityHint: props.hint } : {},
|
|
75
|
+
accessibilityState: {
|
|
76
|
+
disabled: inactive,
|
|
77
|
+
busy: props.busy === true,
|
|
78
|
+
...checkable ? props.role === "radio" ? { selected: props.selected === true } : { checked: props.selected === true } : {}
|
|
79
|
+
},
|
|
80
|
+
disabled: inactive,
|
|
81
|
+
onPress: props.onPress,
|
|
82
|
+
...props.testID ? { testID: props.testID } : {},
|
|
83
|
+
style: ({ pressed }) => ({
|
|
84
|
+
minHeight: size3.touchTarget,
|
|
85
|
+
minWidth: size3.touchTarget,
|
|
86
|
+
paddingHorizontal: space2.md,
|
|
87
|
+
paddingVertical: space2.sm,
|
|
88
|
+
borderRadius: radius2.md,
|
|
89
|
+
borderWidth: variant === "text" ? 0 : 1,
|
|
90
|
+
borderColor: filled ? colors2.primary : colors2.border,
|
|
91
|
+
backgroundColor: background,
|
|
92
|
+
opacity: inactive ? 0.55 : pressed ? 0.8 : 1,
|
|
93
|
+
alignItems: "center",
|
|
94
|
+
justifyContent: "center",
|
|
95
|
+
flexDirection: "row",
|
|
96
|
+
gap: space2.xs
|
|
97
|
+
}),
|
|
98
|
+
children: [
|
|
99
|
+
props.busy ? /* @__PURE__ */ jsx(ActivityIndicator, { color: foreground }) : null,
|
|
100
|
+
props.children ?? /* @__PURE__ */ jsx(
|
|
101
|
+
Text,
|
|
102
|
+
{
|
|
103
|
+
style: {
|
|
104
|
+
color: foreground,
|
|
105
|
+
fontSize: font2.size.md,
|
|
106
|
+
fontWeight: "500",
|
|
107
|
+
...font2.family ? { fontFamily: font2.family } : {}
|
|
108
|
+
},
|
|
109
|
+
children: props.label
|
|
110
|
+
}
|
|
111
|
+
)
|
|
112
|
+
]
|
|
113
|
+
}
|
|
114
|
+
);
|
|
115
|
+
});
|
|
58
116
|
function cardOf(held) {
|
|
59
117
|
return held.card;
|
|
60
118
|
}
|
|
@@ -123,64 +181,26 @@ function useLink(link, held) {
|
|
|
123
181
|
if (!link || !store.checkLink(link)) return null;
|
|
124
182
|
return () => handlers.current?.onOpenLink?.(link, held);
|
|
125
183
|
}
|
|
184
|
+
function ratingText(valuePpm, locale) {
|
|
185
|
+
const value = valuePpm / 1e6;
|
|
186
|
+
try {
|
|
187
|
+
return new Intl.NumberFormat(locale, {
|
|
188
|
+
minimumFractionDigits: 1,
|
|
189
|
+
maximumFractionDigits: 1
|
|
190
|
+
}).format(value);
|
|
191
|
+
} catch {
|
|
192
|
+
return value.toFixed(1);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
function allowedImage(url, hosts) {
|
|
196
|
+
const safe = safeImage(url);
|
|
197
|
+
if (safe === null || !hosts) return safe;
|
|
198
|
+
const host = /^https:\/\/([^/:?#]+)/i.exec(safe)?.[1]?.toLowerCase();
|
|
199
|
+
return host && hosts.some((h) => h.toLowerCase() === host) ? safe : null;
|
|
200
|
+
}
|
|
126
201
|
function safeImage(url) {
|
|
127
202
|
return url && /^https:\/\//i.test(url) ? url : null;
|
|
128
203
|
}
|
|
129
|
-
var Button = memo(function Button2(props) {
|
|
130
|
-
const { colors: colors2, radius: radius2, space: space2, size: size3, font: font2 } = useTheme();
|
|
131
|
-
const variant = props.variant ?? "secondary";
|
|
132
|
-
const inactive = props.disabled === true || props.busy === true;
|
|
133
|
-
const filled = variant === "primary" || props.selected === true;
|
|
134
|
-
const background = filled ? colors2.primary : variant === "secondary" ? colors2.surface : "transparent";
|
|
135
|
-
const foreground = filled ? colors2.onPrimary : colors2.primary;
|
|
136
|
-
const checkable = props.role === "radio" || props.role === "checkbox";
|
|
137
|
-
return /* @__PURE__ */ jsxs(
|
|
138
|
-
Pressable,
|
|
139
|
-
{
|
|
140
|
-
accessibilityRole: props.role ?? "button",
|
|
141
|
-
accessibilityLabel: props.label,
|
|
142
|
-
...props.hint ? { accessibilityHint: props.hint } : {},
|
|
143
|
-
accessibilityState: {
|
|
144
|
-
disabled: inactive,
|
|
145
|
-
busy: props.busy === true,
|
|
146
|
-
...checkable ? props.role === "radio" ? { selected: props.selected === true } : { checked: props.selected === true } : {}
|
|
147
|
-
},
|
|
148
|
-
disabled: inactive,
|
|
149
|
-
onPress: props.onPress,
|
|
150
|
-
...props.testID ? { testID: props.testID } : {},
|
|
151
|
-
style: ({ pressed }) => ({
|
|
152
|
-
minHeight: size3.touchTarget,
|
|
153
|
-
minWidth: size3.touchTarget,
|
|
154
|
-
paddingHorizontal: space2.md,
|
|
155
|
-
paddingVertical: space2.sm,
|
|
156
|
-
borderRadius: radius2.md,
|
|
157
|
-
borderWidth: variant === "text" ? 0 : 1,
|
|
158
|
-
borderColor: filled ? colors2.primary : colors2.border,
|
|
159
|
-
backgroundColor: background,
|
|
160
|
-
opacity: inactive ? 0.55 : pressed ? 0.8 : 1,
|
|
161
|
-
alignItems: "center",
|
|
162
|
-
justifyContent: "center",
|
|
163
|
-
flexDirection: "row",
|
|
164
|
-
gap: space2.xs
|
|
165
|
-
}),
|
|
166
|
-
children: [
|
|
167
|
-
props.busy ? /* @__PURE__ */ jsx(ActivityIndicator, { color: foreground }) : null,
|
|
168
|
-
props.children ?? /* @__PURE__ */ jsx(
|
|
169
|
-
Text,
|
|
170
|
-
{
|
|
171
|
-
style: {
|
|
172
|
-
color: foreground,
|
|
173
|
-
fontSize: font2.size.md,
|
|
174
|
-
fontWeight: "500",
|
|
175
|
-
...font2.family ? { fontFamily: font2.family } : {}
|
|
176
|
-
},
|
|
177
|
-
children: props.label
|
|
178
|
-
}
|
|
179
|
-
)
|
|
180
|
-
]
|
|
181
|
-
}
|
|
182
|
-
);
|
|
183
|
-
});
|
|
184
204
|
function InfoCard(props) {
|
|
185
205
|
const card = cardOf(props.card);
|
|
186
206
|
const { locale, t } = useCopy();
|
|
@@ -189,7 +209,7 @@ function InfoCard(props) {
|
|
|
189
209
|
const image = safeImage(card.image_url);
|
|
190
210
|
const Img = slots.Image ?? Image;
|
|
191
211
|
const money = card.price ?? card.price_from;
|
|
192
|
-
const rating = card.rating ? (card.rating.value_ppm
|
|
212
|
+
const rating = card.rating ? ratingText(card.rating.value_ppm, locale) : null;
|
|
193
213
|
const amount = money ? formatMoney(money.amount, money.currency, locale) : null;
|
|
194
214
|
const price = amount && !card.price ? t("priceFrom", { price: amount }) : amount;
|
|
195
215
|
const when = card.starts_at ? formatTimeRange(card.starts_at, void 0, locale, timeZone) : null;
|
|
@@ -232,27 +252,32 @@ function InfoCard(props) {
|
|
|
232
252
|
] })
|
|
233
253
|
] }),
|
|
234
254
|
card.body ? /* @__PURE__ */ jsx(Body, { children: card.body }) : null,
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
{
|
|
238
|
-
style: {
|
|
239
|
-
color: colors2.text,
|
|
240
|
-
backgroundColor: colors2.surface,
|
|
241
|
-
borderRadius: radius2.pill,
|
|
242
|
-
paddingHorizontal: space2.sm,
|
|
243
|
-
paddingVertical: space2.xxs,
|
|
244
|
-
fontSize: font2.size.xs
|
|
245
|
-
},
|
|
246
|
-
children: b
|
|
247
|
-
},
|
|
248
|
-
b
|
|
249
|
-
)) }) : null,
|
|
250
|
-
props.restored ? null : /* @__PURE__ */ jsx(Actions, { ...props })
|
|
255
|
+
/* @__PURE__ */ jsx(Badges, { badges: card.badges }),
|
|
256
|
+
props.restored ? null : /* @__PURE__ */ jsx(CardActions, { ...props })
|
|
251
257
|
]
|
|
252
258
|
}
|
|
253
259
|
);
|
|
254
260
|
}
|
|
255
|
-
function
|
|
261
|
+
function Badges(props) {
|
|
262
|
+
const { colors: colors2, radius: radius2, space: space2, font: font2 } = useTheme();
|
|
263
|
+
if (!props.badges?.length) return null;
|
|
264
|
+
return /* @__PURE__ */ jsx(View, { style: { flexDirection: "row", flexWrap: "wrap", gap: space2.xs }, children: props.badges.map((b) => /* @__PURE__ */ jsx(
|
|
265
|
+
Text,
|
|
266
|
+
{
|
|
267
|
+
style: {
|
|
268
|
+
color: colors2.text,
|
|
269
|
+
backgroundColor: colors2.surface,
|
|
270
|
+
borderRadius: radius2.pill,
|
|
271
|
+
paddingHorizontal: space2.sm,
|
|
272
|
+
paddingVertical: space2.xxs,
|
|
273
|
+
fontSize: font2.size.xs
|
|
274
|
+
},
|
|
275
|
+
children: b
|
|
276
|
+
},
|
|
277
|
+
b
|
|
278
|
+
)) });
|
|
279
|
+
}
|
|
280
|
+
function CardActions(props) {
|
|
256
281
|
const card = cardOf(props.card);
|
|
257
282
|
const { space: space2 } = useTheme();
|
|
258
283
|
if (!card.actions?.length) return null;
|
|
@@ -284,6 +309,139 @@ function Action(props) {
|
|
|
284
309
|
}
|
|
285
310
|
);
|
|
286
311
|
}
|
|
312
|
+
function LinksCard(props) {
|
|
313
|
+
const card = cardOf(props.card);
|
|
314
|
+
const { store, handlers } = useChat();
|
|
315
|
+
const links = (card.links ?? []).filter(
|
|
316
|
+
(l) => /^https:\/\//i.test(l.url) || store.checkLink(l.url)
|
|
317
|
+
);
|
|
318
|
+
return /* @__PURE__ */ jsxs(
|
|
319
|
+
CardFrame,
|
|
320
|
+
{
|
|
321
|
+
label: [card.title, ...links.map((l) => l.label)].join(", "),
|
|
322
|
+
restored: props.restored,
|
|
323
|
+
testID: `vinaverse-card-${card.id}`,
|
|
324
|
+
children: [
|
|
325
|
+
/* @__PURE__ */ jsx(Title, { children: card.title }),
|
|
326
|
+
links.map((l) => /* @__PURE__ */ jsx(
|
|
327
|
+
Button,
|
|
328
|
+
{
|
|
329
|
+
label: l.label,
|
|
330
|
+
role: "link",
|
|
331
|
+
variant: "secondary",
|
|
332
|
+
disabled: props.restored,
|
|
333
|
+
onPress: () => {
|
|
334
|
+
const open = handlers.current?.onOpenLink;
|
|
335
|
+
if (open) open(l.url, props.card);
|
|
336
|
+
else void Linking.openURL(l.url);
|
|
337
|
+
}
|
|
338
|
+
},
|
|
339
|
+
l.url
|
|
340
|
+
))
|
|
341
|
+
]
|
|
342
|
+
}
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
function ListingCard(props) {
|
|
346
|
+
const card = cardOf(props.card);
|
|
347
|
+
const { locale, t } = useCopy();
|
|
348
|
+
const { slots, timeZone, handlers, imagePolicy } = useChat();
|
|
349
|
+
const { colors: colors2, radius: radius2, space: space2, font: font2 } = useTheme();
|
|
350
|
+
const [failed, setFailed] = useState(null);
|
|
351
|
+
const photoUrl = allowedImage(
|
|
352
|
+
card.images?.[0]?.url ?? card.image_url,
|
|
353
|
+
imagePolicy?.hosts
|
|
354
|
+
);
|
|
355
|
+
const hero = photoUrl === failed ? null : photoUrl;
|
|
356
|
+
const Img = slots.Image ?? Image;
|
|
357
|
+
const rating = card.rating ? `\u2605 ${ratingText(card.rating.value_ppm, locale)} (${card.rating.count})` : null;
|
|
358
|
+
const price = card.price_from ? t("priceFrom", {
|
|
359
|
+
price: formatMoney(
|
|
360
|
+
card.price_from.amount,
|
|
361
|
+
card.price_from.currency,
|
|
362
|
+
locale
|
|
363
|
+
)
|
|
364
|
+
}) : null;
|
|
365
|
+
const next = card.next_available ? t("nextAvailable", {
|
|
366
|
+
time: formatTimeRange(card.next_available, void 0, locale, timeZone)
|
|
367
|
+
}) : null;
|
|
368
|
+
const ref = card.ref;
|
|
369
|
+
const onOpenTarget = handlers.current?.onOpenTarget;
|
|
370
|
+
const open = ref && onOpenTarget && !props.restored ? () => onOpenTarget({ type: ref.type, id: ref.id }, props.card) : null;
|
|
371
|
+
const photo = {
|
|
372
|
+
width: "100%",
|
|
373
|
+
aspectRatio: imagePolicy?.aspectRatio ?? 1.6,
|
|
374
|
+
borderRadius: radius2.md
|
|
375
|
+
};
|
|
376
|
+
const top = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
377
|
+
hero ? /* @__PURE__ */ jsx(
|
|
378
|
+
Img,
|
|
379
|
+
{
|
|
380
|
+
source: { uri: hero },
|
|
381
|
+
onError: () => setFailed(hero),
|
|
382
|
+
style: { ...photo, backgroundColor: colors2.surface },
|
|
383
|
+
accessible: false,
|
|
384
|
+
testID: `vinaverse-photo-${card.id}`
|
|
385
|
+
}
|
|
386
|
+
) : imagePolicy?.Placeholder ? /* @__PURE__ */ jsx(View, { style: photo, testID: `vinaverse-placeholder-${card.id}`, children: /* @__PURE__ */ jsx(imagePolicy.Placeholder, { title: card.title }) }) : /* @__PURE__ */ jsx(
|
|
387
|
+
View,
|
|
388
|
+
{
|
|
389
|
+
accessible: false,
|
|
390
|
+
importantForAccessibility: "no-hide-descendants",
|
|
391
|
+
testID: `vinaverse-monogram-${card.id}`,
|
|
392
|
+
style: {
|
|
393
|
+
...photo,
|
|
394
|
+
backgroundColor: colors2.surface,
|
|
395
|
+
alignItems: "center",
|
|
396
|
+
justifyContent: "center"
|
|
397
|
+
},
|
|
398
|
+
children: /* @__PURE__ */ jsx(
|
|
399
|
+
Text,
|
|
400
|
+
{
|
|
401
|
+
style: {
|
|
402
|
+
color: colors2.textMuted,
|
|
403
|
+
fontSize: font2.size.xl,
|
|
404
|
+
fontWeight: "600"
|
|
405
|
+
},
|
|
406
|
+
children: monogram(card.title)
|
|
407
|
+
}
|
|
408
|
+
)
|
|
409
|
+
}
|
|
410
|
+
),
|
|
411
|
+
/* @__PURE__ */ jsxs(View, { style: { gap: space2.xxs }, children: [
|
|
412
|
+
/* @__PURE__ */ jsx(Title, { numberOfLines: 2, children: card.title }),
|
|
413
|
+
card.subtitle ? /* @__PURE__ */ jsx(Body, { muted: true, children: card.subtitle }) : null,
|
|
414
|
+
rating || price ? /* @__PURE__ */ jsx(Body, { muted: true, children: [rating, price].filter(Boolean).join(" \xB7 ") }) : null
|
|
415
|
+
] })
|
|
416
|
+
] });
|
|
417
|
+
return /* @__PURE__ */ jsxs(
|
|
418
|
+
CardFrame,
|
|
419
|
+
{
|
|
420
|
+
label: [card.title, card.subtitle, rating, price, next].filter(Boolean).join(", "),
|
|
421
|
+
restored: props.restored,
|
|
422
|
+
testID: `vinaverse-card-${card.id}`,
|
|
423
|
+
children: [
|
|
424
|
+
open ? /* @__PURE__ */ jsx(
|
|
425
|
+
Pressable,
|
|
426
|
+
{
|
|
427
|
+
accessibilityRole: "link",
|
|
428
|
+
accessibilityLabel: card.title,
|
|
429
|
+
onPress: open,
|
|
430
|
+
style: { gap: space2.sm },
|
|
431
|
+
testID: `vinaverse-open-${card.id}`,
|
|
432
|
+
children: top
|
|
433
|
+
}
|
|
434
|
+
) : top,
|
|
435
|
+
card.body ? /* @__PURE__ */ jsx(Body, { children: card.body }) : null,
|
|
436
|
+
/* @__PURE__ */ jsx(Badges, { badges: next ? [next, ...card.badges ?? []] : card.badges }),
|
|
437
|
+
props.restored ? null : /* @__PURE__ */ jsx(CardActions, { ...props })
|
|
438
|
+
]
|
|
439
|
+
}
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
function monogram(title) {
|
|
443
|
+
return title.split(/\s+/).filter(Boolean).slice(0, 2).map((w) => [...w][0]?.toUpperCase() ?? "").join("");
|
|
444
|
+
}
|
|
287
445
|
function NextStepCard(props) {
|
|
288
446
|
const card = cardOf(props.card);
|
|
289
447
|
const action = card.actions?.[0];
|
|
@@ -1152,7 +1310,10 @@ var DEFAULTS = {
|
|
|
1152
1310
|
proposal: ProposalCard,
|
|
1153
1311
|
question: QuestionCard,
|
|
1154
1312
|
next_step: NextStepCard,
|
|
1155
|
-
time_slots: TimeSlotsCard
|
|
1313
|
+
time_slots: TimeSlotsCard,
|
|
1314
|
+
professional: ListingCard,
|
|
1315
|
+
workspace: ListingCard,
|
|
1316
|
+
links: LinksCard
|
|
1156
1317
|
};
|
|
1157
1318
|
function defaultCard(kind) {
|
|
1158
1319
|
return DEFAULTS[kind] ?? InfoCard;
|
|
@@ -1162,9 +1323,39 @@ var CardView = memo(function CardView2(props) {
|
|
|
1162
1323
|
const { card, busy } = props.item;
|
|
1163
1324
|
const Default = defaultCard(card.kind);
|
|
1164
1325
|
const Custom = slots.cards?.[card.kind];
|
|
1165
|
-
const
|
|
1326
|
+
const read = useMemo(() => readCard(card.card), [card]);
|
|
1327
|
+
const own = { card, read, busy, restored: props.item.restored === true };
|
|
1166
1328
|
return Custom ? /* @__PURE__ */ jsx(Custom, { ...own, Default }) : /* @__PURE__ */ jsx(Default, { ...own });
|
|
1167
1329
|
});
|
|
1330
|
+
var keyOf = (item) => item.key;
|
|
1331
|
+
var kindOf = (item) => item.card.kind;
|
|
1332
|
+
function CardCarousel(props) {
|
|
1333
|
+
const { width } = useWindowDimensions();
|
|
1334
|
+
const { t } = useCopy();
|
|
1335
|
+
const size3 = Math.min(Math.round(width * 0.8), 360);
|
|
1336
|
+
return /* @__PURE__ */ jsx(
|
|
1337
|
+
View,
|
|
1338
|
+
{
|
|
1339
|
+
accessibilityRole: "list",
|
|
1340
|
+
accessibilityLabel: t("cardsInRow", {
|
|
1341
|
+
count: String(props.items.length)
|
|
1342
|
+
}),
|
|
1343
|
+
children: /* @__PURE__ */ jsx(
|
|
1344
|
+
FlashList,
|
|
1345
|
+
{
|
|
1346
|
+
horizontal: true,
|
|
1347
|
+
data: props.items,
|
|
1348
|
+
keyExtractor: keyOf,
|
|
1349
|
+
getItemType: kindOf,
|
|
1350
|
+
renderItem: ({ item }) => /* @__PURE__ */ jsx(View, { style: { width: size3 }, children: /* @__PURE__ */ jsx(CardView, { item }) }),
|
|
1351
|
+
snapToInterval: size3,
|
|
1352
|
+
decelerationRate: "fast",
|
|
1353
|
+
showsHorizontalScrollIndicator: false
|
|
1354
|
+
}
|
|
1355
|
+
)
|
|
1356
|
+
}
|
|
1357
|
+
);
|
|
1358
|
+
}
|
|
1168
1359
|
var ActivityLine = memo(function ActivityLine2() {
|
|
1169
1360
|
const { store } = useChat();
|
|
1170
1361
|
const { t } = useCopy();
|
|
@@ -1187,6 +1378,38 @@ var ActivityLine = memo(function ActivityLine2() {
|
|
|
1187
1378
|
}
|
|
1188
1379
|
);
|
|
1189
1380
|
});
|
|
1381
|
+
function useNativeLifecycle(store) {
|
|
1382
|
+
useEffect(() => {
|
|
1383
|
+
const apply = (state) => store.setForeground(state === "active");
|
|
1384
|
+
apply(AppState.currentState);
|
|
1385
|
+
const subscription = AppState.addEventListener("change", apply);
|
|
1386
|
+
return () => subscription.remove();
|
|
1387
|
+
}, [store]);
|
|
1388
|
+
}
|
|
1389
|
+
function useReducedMotion() {
|
|
1390
|
+
const [reduced, setReduced] = useState(false);
|
|
1391
|
+
useEffect(() => {
|
|
1392
|
+
let live = true;
|
|
1393
|
+
AccessibilityInfo.isReduceMotionEnabled().then(
|
|
1394
|
+
(value) => {
|
|
1395
|
+
if (live) setReduced(value);
|
|
1396
|
+
},
|
|
1397
|
+
() => void 0
|
|
1398
|
+
);
|
|
1399
|
+
const subscription = AccessibilityInfo.addEventListener(
|
|
1400
|
+
"reduceMotionChanged",
|
|
1401
|
+
setReduced
|
|
1402
|
+
);
|
|
1403
|
+
return () => {
|
|
1404
|
+
live = false;
|
|
1405
|
+
subscription.remove();
|
|
1406
|
+
};
|
|
1407
|
+
}, []);
|
|
1408
|
+
return reduced;
|
|
1409
|
+
}
|
|
1410
|
+
function announce(text) {
|
|
1411
|
+
if (text) AccessibilityInfo.announceForAccessibility(text);
|
|
1412
|
+
}
|
|
1190
1413
|
var Avatar = memo(function Avatar2(props) {
|
|
1191
1414
|
const { colors: colors2, size: size3, font: font2 } = useTheme();
|
|
1192
1415
|
const { slots } = useChat();
|
|
@@ -1299,37 +1522,6 @@ var ChatHeader = memo(function ChatHeader2() {
|
|
|
1299
1522
|
};
|
|
1300
1523
|
return Header ? /* @__PURE__ */ jsx(Header, { ...props, Default: DefaultHeader }) : /* @__PURE__ */ jsx(DefaultHeader, { ...props });
|
|
1301
1524
|
});
|
|
1302
|
-
var ChatSkeleton = memo(function ChatSkeleton2() {
|
|
1303
|
-
const { colors: colors2, radius: radius2, space: space2 } = useTheme();
|
|
1304
|
-
const row = (width, end) => /* @__PURE__ */ jsx(
|
|
1305
|
-
View,
|
|
1306
|
-
{
|
|
1307
|
-
style: {
|
|
1308
|
-
alignSelf: end ? "flex-end" : "flex-start",
|
|
1309
|
-
width,
|
|
1310
|
-
height: 40,
|
|
1311
|
-
borderRadius: radius2.lg,
|
|
1312
|
-
backgroundColor: colors2.surface,
|
|
1313
|
-
marginHorizontal: space2.lg,
|
|
1314
|
-
marginTop: space2.md
|
|
1315
|
-
}
|
|
1316
|
-
}
|
|
1317
|
-
);
|
|
1318
|
-
return /* @__PURE__ */ jsxs(
|
|
1319
|
-
View,
|
|
1320
|
-
{
|
|
1321
|
-
accessible: true,
|
|
1322
|
-
accessibilityRole: "progressbar",
|
|
1323
|
-
accessibilityState: { busy: true },
|
|
1324
|
-
testID: "vinaverse-skeleton",
|
|
1325
|
-
children: [
|
|
1326
|
-
row("62%", false),
|
|
1327
|
-
row("45%", true),
|
|
1328
|
-
row("70%", false)
|
|
1329
|
-
]
|
|
1330
|
-
}
|
|
1331
|
-
);
|
|
1332
|
-
});
|
|
1333
1525
|
function DefaultComposer(props) {
|
|
1334
1526
|
const { t, direction } = useCopy();
|
|
1335
1527
|
const { colors: colors2, radius: radius2, space: space2, font: font2, size: size3 } = useTheme();
|
|
@@ -1471,23 +1663,37 @@ var DisclosureBar = memo(function DisclosureBar2() {
|
|
|
1471
1663
|
}
|
|
1472
1664
|
);
|
|
1473
1665
|
});
|
|
1474
|
-
function
|
|
1475
|
-
const {
|
|
1476
|
-
const
|
|
1477
|
-
|
|
1478
|
-
return /* @__PURE__ */ jsx(
|
|
1479
|
-
Button,
|
|
1666
|
+
var ChatSkeleton = memo(function ChatSkeleton2() {
|
|
1667
|
+
const { colors: colors2, radius: radius2, space: space2 } = useTheme();
|
|
1668
|
+
const row = (width, end) => /* @__PURE__ */ jsx(
|
|
1669
|
+
View,
|
|
1480
1670
|
{
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1671
|
+
style: {
|
|
1672
|
+
alignSelf: end ? "flex-end" : "flex-start",
|
|
1673
|
+
width,
|
|
1674
|
+
height: 40,
|
|
1675
|
+
borderRadius: radius2.lg,
|
|
1676
|
+
backgroundColor: colors2.surface,
|
|
1677
|
+
marginHorizontal: space2.lg,
|
|
1678
|
+
marginTop: space2.md
|
|
1679
|
+
}
|
|
1484
1680
|
}
|
|
1485
1681
|
);
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1682
|
+
return /* @__PURE__ */ jsxs(
|
|
1683
|
+
View,
|
|
1684
|
+
{
|
|
1685
|
+
accessible: true,
|
|
1686
|
+
accessibilityRole: "progressbar",
|
|
1687
|
+
accessibilityState: { busy: true },
|
|
1688
|
+
testID: "vinaverse-skeleton",
|
|
1689
|
+
children: [
|
|
1690
|
+
row("62%", false),
|
|
1691
|
+
row("45%", true),
|
|
1692
|
+
row("70%", false)
|
|
1693
|
+
]
|
|
1694
|
+
}
|
|
1695
|
+
);
|
|
1696
|
+
});
|
|
1491
1697
|
function DefaultBubble(props) {
|
|
1492
1698
|
const { colors: colors2, radius: radius2, space: space2, font: font2 } = useTheme();
|
|
1493
1699
|
const role = props.item.role;
|
|
@@ -1609,37 +1815,22 @@ function Frame(props) {
|
|
|
1609
1815
|
}
|
|
1610
1816
|
);
|
|
1611
1817
|
}
|
|
1612
|
-
function
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
AccessibilityInfo.isReduceMotionEnabled().then(
|
|
1625
|
-
(value) => {
|
|
1626
|
-
if (live) setReduced(value);
|
|
1627
|
-
},
|
|
1628
|
-
() => void 0
|
|
1629
|
-
);
|
|
1630
|
-
const subscription = AccessibilityInfo.addEventListener(
|
|
1631
|
-
"reduceMotionChanged",
|
|
1632
|
-
setReduced
|
|
1633
|
-
);
|
|
1634
|
-
return () => {
|
|
1635
|
-
live = false;
|
|
1636
|
-
subscription.remove();
|
|
1637
|
-
};
|
|
1638
|
-
}, []);
|
|
1639
|
-
return reduced;
|
|
1818
|
+
function FailureActionButton(props) {
|
|
1819
|
+
const { handlers, failureAction } = useChat();
|
|
1820
|
+
const { t } = useCopy();
|
|
1821
|
+
if (!failureAction) return null;
|
|
1822
|
+
return /* @__PURE__ */ jsx(
|
|
1823
|
+
Button,
|
|
1824
|
+
{
|
|
1825
|
+
label: failureAction.label ?? t("talkToPerson"),
|
|
1826
|
+
variant: "text",
|
|
1827
|
+
onPress: () => handlers.current.failureAction?.onPress(props.state)
|
|
1828
|
+
}
|
|
1829
|
+
);
|
|
1640
1830
|
}
|
|
1641
|
-
function
|
|
1642
|
-
|
|
1831
|
+
function FailureSlot(props) {
|
|
1832
|
+
const { slot: Slot, state, Default } = props;
|
|
1833
|
+
return Slot ? /* @__PURE__ */ jsx(Slot, { state, Default }) : /* @__PURE__ */ jsx(Default, { state });
|
|
1643
1834
|
}
|
|
1644
1835
|
var SystemRow = memo(function SystemRow2(props) {
|
|
1645
1836
|
const { t } = useCopy();
|
|
@@ -1722,7 +1913,44 @@ function Line(props) {
|
|
|
1722
1913
|
}
|
|
1723
1914
|
);
|
|
1724
1915
|
}
|
|
1725
|
-
var
|
|
1916
|
+
var Welcome = memo(function Welcome2(props) {
|
|
1917
|
+
const { colors: colors2, radius: radius2, space: space2, font: font2 } = useTheme();
|
|
1918
|
+
return /* @__PURE__ */ jsxs(
|
|
1919
|
+
View,
|
|
1920
|
+
{
|
|
1921
|
+
style: { padding: space2.lg, gap: space2.md },
|
|
1922
|
+
testID: "vinaverse-welcome",
|
|
1923
|
+
children: [
|
|
1924
|
+
/* @__PURE__ */ jsx(
|
|
1925
|
+
Text,
|
|
1926
|
+
{
|
|
1927
|
+
style: {
|
|
1928
|
+
alignSelf: "flex-start",
|
|
1929
|
+
maxWidth: "85%",
|
|
1930
|
+
color: colors2.agentText,
|
|
1931
|
+
backgroundColor: colors2.agentBubble,
|
|
1932
|
+
borderRadius: radius2.lg,
|
|
1933
|
+
paddingHorizontal: space2.md,
|
|
1934
|
+
paddingVertical: space2.sm,
|
|
1935
|
+
fontSize: font2.size.md,
|
|
1936
|
+
lineHeight: font2.size.md * font2.lineHeight
|
|
1937
|
+
},
|
|
1938
|
+
children: props.welcome.text
|
|
1939
|
+
}
|
|
1940
|
+
),
|
|
1941
|
+
props.welcome.chips.length ? /* @__PURE__ */ jsx(View, { style: { flexDirection: "row", flexWrap: "wrap", gap: space2.sm }, children: props.welcome.chips.map((chip) => /* @__PURE__ */ jsx(
|
|
1942
|
+
Button,
|
|
1943
|
+
{
|
|
1944
|
+
label: chip.label,
|
|
1945
|
+
onPress: () => props.onChip(chip.message)
|
|
1946
|
+
},
|
|
1947
|
+
chip.label
|
|
1948
|
+
)) }) : null
|
|
1949
|
+
]
|
|
1950
|
+
}
|
|
1951
|
+
);
|
|
1952
|
+
});
|
|
1953
|
+
var keyOf2 = (item) => item.key;
|
|
1726
1954
|
function itemType(item) {
|
|
1727
1955
|
if (item.type === "card") return `card:${item.card.kind}`;
|
|
1728
1956
|
if (item.type === "message")
|
|
@@ -1732,43 +1960,111 @@ function itemType(item) {
|
|
|
1732
1960
|
function authorOf(item) {
|
|
1733
1961
|
return item?.type === "message" ? item.role : null;
|
|
1734
1962
|
}
|
|
1963
|
+
function carousels(items, previous) {
|
|
1964
|
+
const runs = /* @__PURE__ */ new Map();
|
|
1965
|
+
const inside = /* @__PURE__ */ new Set();
|
|
1966
|
+
const groupOf = (item) => {
|
|
1967
|
+
if (item?.type !== "card") return null;
|
|
1968
|
+
const group = item.card.card.group;
|
|
1969
|
+
return group?.layout === "carousel" && typeof group.id === "string" ? group.id : null;
|
|
1970
|
+
};
|
|
1971
|
+
for (let i = 0; i < items.length; i++) {
|
|
1972
|
+
const id = groupOf(items[i]);
|
|
1973
|
+
if (id === null) continue;
|
|
1974
|
+
let end = i + 1;
|
|
1975
|
+
while (end < items.length && groupOf(items[end]) === id) end++;
|
|
1976
|
+
if (end - i > 1) {
|
|
1977
|
+
const run = items.slice(i, end);
|
|
1978
|
+
const key = run[0]?.key;
|
|
1979
|
+
const before = previous.get(key);
|
|
1980
|
+
runs.set(
|
|
1981
|
+
key,
|
|
1982
|
+
before && before.length === run.length && before.every((c, n) => c === run[n]) ? before : run
|
|
1983
|
+
);
|
|
1984
|
+
for (const card of run.slice(1)) inside.add(card.key);
|
|
1985
|
+
}
|
|
1986
|
+
i = end - 1;
|
|
1987
|
+
}
|
|
1988
|
+
return { runs, inside };
|
|
1989
|
+
}
|
|
1735
1990
|
var Row = memo(function Row2(props) {
|
|
1736
1991
|
const { item } = props;
|
|
1992
|
+
const { slots } = useChat();
|
|
1993
|
+
const Group = slots.CardGroup;
|
|
1994
|
+
if (props.inside) return null;
|
|
1995
|
+
if (props.run && Group) return /* @__PURE__ */ jsx(Group, { items: props.run });
|
|
1737
1996
|
if (item.type === "card") return /* @__PURE__ */ jsx(CardView, { item });
|
|
1738
1997
|
if (item.type === "system") return /* @__PURE__ */ jsx(SystemRow, { item });
|
|
1739
1998
|
return item.state === "streaming" ? /* @__PURE__ */ jsx(StreamingBubble, { item, showAuthor: props.showAuthor }) : /* @__PURE__ */ jsx(MessageBubble, { item, showAuthor: props.showAuthor });
|
|
1740
1999
|
});
|
|
1741
2000
|
var MessageList = memo(function MessageList2() {
|
|
1742
|
-
const { store, slots } = useChat();
|
|
2001
|
+
const { store, slots, starters, handlers, imagePolicy } = useChat();
|
|
1743
2002
|
const { t } = useCopy();
|
|
1744
2003
|
const { space: space2 } = useTheme();
|
|
1745
2004
|
const reducedMotion = useReducedMotion();
|
|
1746
2005
|
const items = useConversationSelector(store, (v) => v.items);
|
|
2006
|
+
usePrefetchPhotos(items, handlers.current?.prefetchImage, imagePolicy?.hosts);
|
|
1747
2007
|
const opening = useConversationSelector(
|
|
1748
2008
|
store,
|
|
1749
2009
|
(v) => v.status === "starting" || v.status === "connecting"
|
|
1750
2010
|
);
|
|
1751
2011
|
const agentName = useConversationSelector(store, (v) => v.agent.name);
|
|
2012
|
+
const served = useConversationSelector(store, (v) => v.welcome);
|
|
2013
|
+
const welcome = useMemo(
|
|
2014
|
+
() => served ?? (starters?.length ? {
|
|
2015
|
+
text: t("welcomeFallback", {
|
|
2016
|
+
agent: agentName ?? t("agentFallbackName")
|
|
2017
|
+
}),
|
|
2018
|
+
chips: [...starters]
|
|
2019
|
+
} : null),
|
|
2020
|
+
[served, starters, t, agentName]
|
|
2021
|
+
);
|
|
1752
2022
|
useAnnounceReplies(items);
|
|
2023
|
+
const Group = slots.CardGroup;
|
|
2024
|
+
const runsRef = useRef(/* @__PURE__ */ new Map());
|
|
2025
|
+
const grouping = useMemo(
|
|
2026
|
+
() => Group ? carousels(items, runsRef.current) : null,
|
|
2027
|
+
[items, Group]
|
|
2028
|
+
);
|
|
2029
|
+
runsRef.current = grouping?.runs ?? /* @__PURE__ */ new Map();
|
|
1753
2030
|
const itemsRef = useRef(items);
|
|
1754
2031
|
itemsRef.current = items;
|
|
2032
|
+
const groupingRef = useRef(grouping);
|
|
2033
|
+
groupingRef.current = grouping;
|
|
1755
2034
|
const renderItem = useCallback(
|
|
1756
2035
|
({ item, index }) => /* @__PURE__ */ jsx(
|
|
1757
2036
|
Row,
|
|
1758
2037
|
{
|
|
1759
2038
|
item,
|
|
1760
|
-
showAuthor: authorOf(item) !== authorOf(itemsRef.current[index - 1])
|
|
2039
|
+
showAuthor: authorOf(item) !== authorOf(itemsRef.current[index - 1]),
|
|
2040
|
+
run: groupingRef.current?.runs.get(item.key),
|
|
2041
|
+
inside: groupingRef.current?.inside.has(item.key) === true
|
|
1761
2042
|
}
|
|
1762
2043
|
),
|
|
1763
2044
|
[]
|
|
1764
2045
|
);
|
|
2046
|
+
const onChip = useCallback(
|
|
2047
|
+
(message) => {
|
|
2048
|
+
store.send(message);
|
|
2049
|
+
const chip = welcome?.chips.find((c) => c.message === message);
|
|
2050
|
+
if (chip) handlers.current?.onChip?.(chip);
|
|
2051
|
+
},
|
|
2052
|
+
[store, welcome, handlers]
|
|
2053
|
+
);
|
|
1765
2054
|
const Empty = slots.EmptyState;
|
|
1766
|
-
const empty = opening ? /* @__PURE__ */ jsx(ChatSkeleton, {}) : Empty ? /* @__PURE__ */ jsx(
|
|
2055
|
+
const empty = opening ? /* @__PURE__ */ jsx(ChatSkeleton, {}) : Empty ? /* @__PURE__ */ jsx(
|
|
2056
|
+
Empty,
|
|
2057
|
+
{
|
|
2058
|
+
agentName: agentName ?? t("agentFallbackName"),
|
|
2059
|
+
welcome,
|
|
2060
|
+
onChip
|
|
2061
|
+
}
|
|
2062
|
+
) : welcome ? /* @__PURE__ */ jsx(Welcome, { welcome, onChip }) : null;
|
|
1767
2063
|
const props = useMemo(
|
|
1768
2064
|
() => ({
|
|
1769
2065
|
data: items,
|
|
1770
2066
|
renderItem,
|
|
1771
|
-
keyExtractor:
|
|
2067
|
+
keyExtractor: keyOf2,
|
|
1772
2068
|
getItemType: itemType,
|
|
1773
2069
|
maintainVisibleContentPosition: {
|
|
1774
2070
|
startRenderingFromBottom: true,
|
|
@@ -1785,10 +2081,25 @@ var MessageList = memo(function MessageList2() {
|
|
|
1785
2081
|
const List = slots.ListComponent;
|
|
1786
2082
|
return List ? /* @__PURE__ */ jsx(List, { ...props }) : /* @__PURE__ */ jsx(FlashList, { ...props });
|
|
1787
2083
|
});
|
|
2084
|
+
function usePrefetchPhotos(items, prefetch, hosts) {
|
|
2085
|
+
const done = useRef(/* @__PURE__ */ new Set());
|
|
2086
|
+
useEffect(() => {
|
|
2087
|
+
if (!prefetch) return;
|
|
2088
|
+
for (const item of items) {
|
|
2089
|
+
if (item.type !== "card") continue;
|
|
2090
|
+
const card = item.card.card;
|
|
2091
|
+
const url = allowedImage(card.images?.[0]?.url ?? card.image_url, hosts);
|
|
2092
|
+
if (url && !done.current.has(url)) {
|
|
2093
|
+
done.current.add(url);
|
|
2094
|
+
prefetch(url);
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
}, [items, prefetch, hosts]);
|
|
2098
|
+
}
|
|
1788
2099
|
function useAnnounceReplies(items) {
|
|
1789
2100
|
const seen = useRef(void 0);
|
|
1790
2101
|
const { t } = useCopy();
|
|
1791
|
-
const { store } = useChat();
|
|
2102
|
+
const { store, handlers } = useChat();
|
|
1792
2103
|
useEffect(() => {
|
|
1793
2104
|
const last = items.at(-1);
|
|
1794
2105
|
if (seen.current === void 0) {
|
|
@@ -1801,8 +2112,8 @@ function useAnnounceReplies(items) {
|
|
|
1801
2112
|
const author = last.role === "staff" ? t("staffLabel", {
|
|
1802
2113
|
by: store.getSnapshot().takeover?.by || t("staffFallbackRole")
|
|
1803
2114
|
}) : store.getSnapshot().agent.name ?? t("agentFallbackName");
|
|
1804
|
-
announce(`${author}: ${last.text}`);
|
|
1805
|
-
}, [items, t, store]);
|
|
2115
|
+
(handlers.current?.announce ?? announce)(`${author}: ${last.text}`);
|
|
2116
|
+
}, [items, t, store, handlers]);
|
|
1806
2117
|
}
|
|
1807
2118
|
var CONNECTING_DELAY = motion.bannerDelay;
|
|
1808
2119
|
var StatusBanner = memo(function StatusBanner2() {
|
|
@@ -1903,7 +2214,14 @@ function Banner(props) {
|
|
|
1903
2214
|
);
|
|
1904
2215
|
}
|
|
1905
2216
|
function VinaverseChatProvider(props) {
|
|
1906
|
-
const {
|
|
2217
|
+
const {
|
|
2218
|
+
conversation,
|
|
2219
|
+
components,
|
|
2220
|
+
agentAvatar,
|
|
2221
|
+
timeZone,
|
|
2222
|
+
starters,
|
|
2223
|
+
imagePolicy
|
|
2224
|
+
} = props;
|
|
1907
2225
|
const handlers = useRef(props);
|
|
1908
2226
|
handlers.current = props;
|
|
1909
2227
|
const slots = useStableSlots(components);
|
|
@@ -1920,9 +2238,19 @@ function VinaverseChatProvider(props) {
|
|
|
1920
2238
|
slots,
|
|
1921
2239
|
agentAvatar,
|
|
1922
2240
|
timeZone,
|
|
1923
|
-
failureAction
|
|
2241
|
+
failureAction,
|
|
2242
|
+
starters,
|
|
2243
|
+
imagePolicy
|
|
1924
2244
|
}),
|
|
1925
|
-
[
|
|
2245
|
+
[
|
|
2246
|
+
conversation,
|
|
2247
|
+
slots,
|
|
2248
|
+
agentAvatar,
|
|
2249
|
+
timeZone,
|
|
2250
|
+
failureAction,
|
|
2251
|
+
starters,
|
|
2252
|
+
imagePolicy
|
|
2253
|
+
]
|
|
1926
2254
|
);
|
|
1927
2255
|
useNativeLifecycle(conversation);
|
|
1928
2256
|
useEffect(() => {
|
|
@@ -1948,7 +2276,9 @@ function VinaverseChat(props) {
|
|
|
1948
2276
|
keyboardVerticalOffset: props.keyboardVerticalOffset ?? 0,
|
|
1949
2277
|
keyboardBehavior: props.keyboardBehavior ?? (Platform.OS === "ios" ? "padding" : "none"),
|
|
1950
2278
|
style: props.style,
|
|
1951
|
-
onError: props.onWarning
|
|
2279
|
+
onError: props.onWarning,
|
|
2280
|
+
suggestion: props.suggestion ?? null,
|
|
2281
|
+
footer: props.footer
|
|
1952
2282
|
}
|
|
1953
2283
|
) });
|
|
1954
2284
|
}
|
|
@@ -1974,11 +2304,27 @@ function Layout(props) {
|
|
|
1974
2304
|
/* @__PURE__ */ jsx(DisclosureBar, {}),
|
|
1975
2305
|
/* @__PURE__ */ jsx(StatusBanner, {}),
|
|
1976
2306
|
/* @__PURE__ */ jsx(View, { style: { flex: 1 }, children: /* @__PURE__ */ jsx(MessageList, {}) }),
|
|
1977
|
-
/* @__PURE__ */ jsx(
|
|
2307
|
+
props.suggestion ? /* @__PURE__ */ jsx(Suggestion, { chip: props.suggestion }) : null,
|
|
2308
|
+
/* @__PURE__ */ jsx(Composer, { ...reportError ? { onError: reportError } : {} }),
|
|
2309
|
+
props.footer
|
|
1978
2310
|
]
|
|
1979
2311
|
}
|
|
1980
2312
|
);
|
|
1981
2313
|
}
|
|
2314
|
+
function Suggestion(props) {
|
|
2315
|
+
const { store, handlers } = useChat();
|
|
2316
|
+
const { space: space2 } = useTheme();
|
|
2317
|
+
return /* @__PURE__ */ jsx(View, { style: { paddingHorizontal: space2.lg, alignItems: "flex-start" }, children: /* @__PURE__ */ jsx(
|
|
2318
|
+
Button,
|
|
2319
|
+
{
|
|
2320
|
+
label: props.chip.label,
|
|
2321
|
+
onPress: () => {
|
|
2322
|
+
store.send(props.chip.message);
|
|
2323
|
+
handlers.current?.onChip?.(props.chip);
|
|
2324
|
+
}
|
|
2325
|
+
}
|
|
2326
|
+
) });
|
|
2327
|
+
}
|
|
1982
2328
|
function useStableSlots(slots) {
|
|
1983
2329
|
const held = useRef({});
|
|
1984
2330
|
const next = slots ?? {};
|
|
@@ -1997,7 +2343,590 @@ function sameSlots(a, b) {
|
|
|
1997
2343
|
}
|
|
1998
2344
|
return true;
|
|
1999
2345
|
}
|
|
2346
|
+
function AgentChat(props) {
|
|
2347
|
+
const {
|
|
2348
|
+
agentKey,
|
|
2349
|
+
place,
|
|
2350
|
+
entryPoint,
|
|
2351
|
+
askAbout,
|
|
2352
|
+
onContact,
|
|
2353
|
+
onOpenPrivacy,
|
|
2354
|
+
components,
|
|
2355
|
+
agentName,
|
|
2356
|
+
opener,
|
|
2357
|
+
...chat
|
|
2358
|
+
} = props;
|
|
2359
|
+
const runtime = useAgentRuntime();
|
|
2360
|
+
const { conversation, state, startNew } = useAgentConversation(agentKey, {
|
|
2361
|
+
place: place ?? null,
|
|
2362
|
+
entryPoint: entryPoint ?? null
|
|
2363
|
+
});
|
|
2364
|
+
const store = conversation.store;
|
|
2365
|
+
const spoke = useConversationSelector(
|
|
2366
|
+
store,
|
|
2367
|
+
(v) => v.items.some((i) => i.type === "message" && i.role === "person")
|
|
2368
|
+
);
|
|
2369
|
+
const { Ended, Unreachable, UnavailableScreen, Footer, ...slots } = components ?? {};
|
|
2370
|
+
const copy = useMemo(
|
|
2371
|
+
() => agentName ? { ...props.copy, agentFallbackName: agentName } : props.copy,
|
|
2372
|
+
[agentName, props.copy]
|
|
2373
|
+
);
|
|
2374
|
+
const events = {
|
|
2375
|
+
onOpenTarget: chat.onOpenTarget ? (target, card) => {
|
|
2376
|
+
runtime.emit({
|
|
2377
|
+
type: "target_opened",
|
|
2378
|
+
key: conversation.key,
|
|
2379
|
+
cardId: card.id,
|
|
2380
|
+
kind: target.type
|
|
2381
|
+
});
|
|
2382
|
+
chat.onOpenTarget?.(target, card);
|
|
2383
|
+
} : void 0,
|
|
2384
|
+
onOpenLink: chat.onOpenLink ? (link, card) => {
|
|
2385
|
+
runtime.emit({
|
|
2386
|
+
type: "link_opened",
|
|
2387
|
+
key: conversation.key,
|
|
2388
|
+
cardId: card.id,
|
|
2389
|
+
kind: card.kind
|
|
2390
|
+
});
|
|
2391
|
+
chat.onOpenLink?.(link, card);
|
|
2392
|
+
} : void 0,
|
|
2393
|
+
onChip: (chip) => {
|
|
2394
|
+
runtime.emit({ type: "chip_tapped", key: conversation.key });
|
|
2395
|
+
chat.onChip?.(chip);
|
|
2396
|
+
}
|
|
2397
|
+
};
|
|
2398
|
+
const shared = {
|
|
2399
|
+
...chat,
|
|
2400
|
+
...events.onOpenTarget ? { onOpenTarget: events.onOpenTarget } : {},
|
|
2401
|
+
...events.onOpenLink ? { onOpenLink: events.onOpenLink } : {},
|
|
2402
|
+
onChip: events.onChip,
|
|
2403
|
+
...copy ? { copy } : {},
|
|
2404
|
+
...onContact && !chat.failureAction ? { failureAction: { onPress: () => onContact() } } : {},
|
|
2405
|
+
conversation: store,
|
|
2406
|
+
components: slots
|
|
2407
|
+
};
|
|
2408
|
+
if (state.failure === "ended")
|
|
2409
|
+
return /* @__PURE__ */ jsx(VinaverseChatProvider, { ...shared, children: /* @__PURE__ */ jsx(Centered, { children: Ended ? /* @__PURE__ */ jsx(
|
|
2410
|
+
Ended,
|
|
2411
|
+
{
|
|
2412
|
+
onStartNew: startNew,
|
|
2413
|
+
code: state.code,
|
|
2414
|
+
Default: DefaultEnded
|
|
2415
|
+
}
|
|
2416
|
+
) : /* @__PURE__ */ jsx(DefaultEnded, { onStartNew: startNew, code: state.code }) }) });
|
|
2417
|
+
if (state.failure === "unreachable")
|
|
2418
|
+
return /* @__PURE__ */ jsx(VinaverseChatProvider, { ...shared, children: /* @__PURE__ */ jsx(Centered, { children: Unreachable ? /* @__PURE__ */ jsx(
|
|
2419
|
+
Unreachable,
|
|
2420
|
+
{
|
|
2421
|
+
onRetry: conversation.retry,
|
|
2422
|
+
reason: state.reason,
|
|
2423
|
+
Default: DefaultUnreachable
|
|
2424
|
+
}
|
|
2425
|
+
) : /* @__PURE__ */ jsx(
|
|
2426
|
+
DefaultUnreachable,
|
|
2427
|
+
{
|
|
2428
|
+
onRetry: conversation.retry,
|
|
2429
|
+
reason: state.reason
|
|
2430
|
+
}
|
|
2431
|
+
) }) });
|
|
2432
|
+
if (state.failure === "unavailable") {
|
|
2433
|
+
const own = {
|
|
2434
|
+
reason: state.reason,
|
|
2435
|
+
code: state.code,
|
|
2436
|
+
onContact,
|
|
2437
|
+
onRetry: conversation.retry
|
|
2438
|
+
};
|
|
2439
|
+
return /* @__PURE__ */ jsx(VinaverseChatProvider, { ...shared, children: /* @__PURE__ */ jsx(Centered, { children: UnavailableScreen ? /* @__PURE__ */ jsx(UnavailableScreen, { ...own, Default: DefaultUnavailableScreen }) : /* @__PURE__ */ jsx(DefaultUnavailableScreen, { ...own }) }) });
|
|
2440
|
+
}
|
|
2441
|
+
return /* @__PURE__ */ jsx(
|
|
2442
|
+
VinaverseChat,
|
|
2443
|
+
{
|
|
2444
|
+
...shared,
|
|
2445
|
+
suggestion: opener && !spoke ? opener : state.moved && askAbout ? { label: askAbout, message: askAbout } : null,
|
|
2446
|
+
footer: Footer === null ? null : /* @__PURE__ */ jsx(
|
|
2447
|
+
FooterFor,
|
|
2448
|
+
{
|
|
2449
|
+
store,
|
|
2450
|
+
state,
|
|
2451
|
+
rate: conversation.rate,
|
|
2452
|
+
Footer,
|
|
2453
|
+
onOpenPrivacy
|
|
2454
|
+
}
|
|
2455
|
+
)
|
|
2456
|
+
}
|
|
2457
|
+
);
|
|
2458
|
+
}
|
|
2459
|
+
function FooterFor(props) {
|
|
2460
|
+
const turnId = useConversationSelector(props.store, newestWholeReply);
|
|
2461
|
+
const own = {
|
|
2462
|
+
turnId,
|
|
2463
|
+
rating: turnId ? props.state.ratings.get(turnId) : void 0,
|
|
2464
|
+
onRate: (rating) => {
|
|
2465
|
+
if (turnId) props.rate(turnId, rating);
|
|
2466
|
+
},
|
|
2467
|
+
onOpenPrivacy: props.onOpenPrivacy
|
|
2468
|
+
};
|
|
2469
|
+
const { Footer } = props;
|
|
2470
|
+
return Footer ? /* @__PURE__ */ jsx(Footer, { ...own, Default: AgentFooter }) : /* @__PURE__ */ jsx(AgentFooter, { ...own });
|
|
2471
|
+
}
|
|
2472
|
+
function newestWholeReply(view) {
|
|
2473
|
+
for (let i = view.items.length - 1; i >= 0; i--) {
|
|
2474
|
+
const item = view.items[i];
|
|
2475
|
+
if (item?.type !== "message" || item.role !== "agent") continue;
|
|
2476
|
+
const whole = item.state === "sent" && !item.partial && !item.refusal && item.key.startsWith("a:");
|
|
2477
|
+
return whole ? item.key.slice(2) : null;
|
|
2478
|
+
}
|
|
2479
|
+
return null;
|
|
2480
|
+
}
|
|
2481
|
+
function Centered(props) {
|
|
2482
|
+
const { colors: colors2, space: space2 } = useTheme();
|
|
2483
|
+
return /* @__PURE__ */ jsx(
|
|
2484
|
+
View,
|
|
2485
|
+
{
|
|
2486
|
+
style: {
|
|
2487
|
+
flex: 1,
|
|
2488
|
+
alignItems: "center",
|
|
2489
|
+
justifyContent: "center",
|
|
2490
|
+
padding: space2.xl,
|
|
2491
|
+
backgroundColor: colors2.background
|
|
2492
|
+
},
|
|
2493
|
+
children: props.children
|
|
2494
|
+
}
|
|
2495
|
+
);
|
|
2496
|
+
}
|
|
2497
|
+
function Notice(props) {
|
|
2498
|
+
const { colors: colors2, space: space2, font: font2 } = useTheme();
|
|
2499
|
+
return /* @__PURE__ */ jsxs(
|
|
2500
|
+
View,
|
|
2501
|
+
{
|
|
2502
|
+
accessibilityRole: "alert",
|
|
2503
|
+
style: { alignItems: "center", gap: space2.md },
|
|
2504
|
+
children: [
|
|
2505
|
+
/* @__PURE__ */ jsx(
|
|
2506
|
+
Text,
|
|
2507
|
+
{
|
|
2508
|
+
style: {
|
|
2509
|
+
color: colors2.text,
|
|
2510
|
+
fontSize: font2.size.lg,
|
|
2511
|
+
fontWeight: "600",
|
|
2512
|
+
textAlign: "center"
|
|
2513
|
+
},
|
|
2514
|
+
children: props.title
|
|
2515
|
+
}
|
|
2516
|
+
),
|
|
2517
|
+
/* @__PURE__ */ jsx(
|
|
2518
|
+
Text,
|
|
2519
|
+
{
|
|
2520
|
+
style: {
|
|
2521
|
+
color: colors2.textMuted,
|
|
2522
|
+
fontSize: font2.size.md,
|
|
2523
|
+
textAlign: "center"
|
|
2524
|
+
},
|
|
2525
|
+
children: props.body
|
|
2526
|
+
}
|
|
2527
|
+
),
|
|
2528
|
+
props.action && props.onPress ? /* @__PURE__ */ jsx(
|
|
2529
|
+
Button,
|
|
2530
|
+
{
|
|
2531
|
+
label: props.action,
|
|
2532
|
+
variant: "primary",
|
|
2533
|
+
onPress: props.onPress
|
|
2534
|
+
}
|
|
2535
|
+
) : null
|
|
2536
|
+
]
|
|
2537
|
+
}
|
|
2538
|
+
);
|
|
2539
|
+
}
|
|
2540
|
+
function DefaultEnded(props) {
|
|
2541
|
+
const { t } = useCopy();
|
|
2542
|
+
return /* @__PURE__ */ jsx(
|
|
2543
|
+
Notice,
|
|
2544
|
+
{
|
|
2545
|
+
title: t("agentEnded"),
|
|
2546
|
+
body: t("agentEndedBody"),
|
|
2547
|
+
action: t("agentStartOver"),
|
|
2548
|
+
onPress: props.onStartNew
|
|
2549
|
+
}
|
|
2550
|
+
);
|
|
2551
|
+
}
|
|
2552
|
+
function DefaultUnavailableScreen(props) {
|
|
2553
|
+
const { t } = useCopy();
|
|
2554
|
+
const name = useAgentName(t("agentFallbackName"));
|
|
2555
|
+
const title = t("agentOff", { agent: name });
|
|
2556
|
+
return /* @__PURE__ */ jsx(
|
|
2557
|
+
Notice,
|
|
2558
|
+
{
|
|
2559
|
+
title: title.charAt(0).toUpperCase() + title.slice(1),
|
|
2560
|
+
body: t("agentOffBody"),
|
|
2561
|
+
...props.onContact ? { action: t("talkToPerson"), onPress: props.onContact } : {}
|
|
2562
|
+
}
|
|
2563
|
+
);
|
|
2564
|
+
}
|
|
2565
|
+
function DefaultUnreachable(props) {
|
|
2566
|
+
const { t } = useCopy();
|
|
2567
|
+
const name = useAgentName(t("agentFallbackName"));
|
|
2568
|
+
return /* @__PURE__ */ jsx(
|
|
2569
|
+
Notice,
|
|
2570
|
+
{
|
|
2571
|
+
title: t("agentUnreachable", { agent: name }),
|
|
2572
|
+
body: t("agentUnreachableBody"),
|
|
2573
|
+
action: t("tryAgain"),
|
|
2574
|
+
onPress: props.onRetry
|
|
2575
|
+
}
|
|
2576
|
+
);
|
|
2577
|
+
}
|
|
2578
|
+
function AgentFooter(props) {
|
|
2579
|
+
const { t } = useCopy();
|
|
2580
|
+
const { colors: colors2, space: space2, font: font2 } = useTheme();
|
|
2581
|
+
const muted = { color: colors2.textMuted, fontSize: font2.size.sm };
|
|
2582
|
+
return /* @__PURE__ */ jsxs(
|
|
2583
|
+
View,
|
|
2584
|
+
{
|
|
2585
|
+
style: {
|
|
2586
|
+
flexDirection: "row",
|
|
2587
|
+
flexWrap: "wrap",
|
|
2588
|
+
alignItems: "center",
|
|
2589
|
+
gap: space2.xs,
|
|
2590
|
+
paddingHorizontal: space2.lg
|
|
2591
|
+
},
|
|
2592
|
+
children: [
|
|
2593
|
+
props.turnId === null ? null : props.rating ? /* @__PURE__ */ jsx(Text, { style: muted, children: t("helpfulThanks") }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2594
|
+
/* @__PURE__ */ jsx(Text, { style: muted, children: t("helpful") }),
|
|
2595
|
+
/* @__PURE__ */ jsx(
|
|
2596
|
+
Button,
|
|
2597
|
+
{
|
|
2598
|
+
label: t("helpfulYes"),
|
|
2599
|
+
variant: "text",
|
|
2600
|
+
onPress: () => props.onRate("up")
|
|
2601
|
+
}
|
|
2602
|
+
),
|
|
2603
|
+
/* @__PURE__ */ jsx(
|
|
2604
|
+
Button,
|
|
2605
|
+
{
|
|
2606
|
+
label: t("helpfulNo"),
|
|
2607
|
+
variant: "text",
|
|
2608
|
+
onPress: () => props.onRate("down")
|
|
2609
|
+
}
|
|
2610
|
+
)
|
|
2611
|
+
] }),
|
|
2612
|
+
props.onOpenPrivacy ? /* @__PURE__ */ jsx(
|
|
2613
|
+
Button,
|
|
2614
|
+
{
|
|
2615
|
+
label: t("privacy"),
|
|
2616
|
+
variant: "text",
|
|
2617
|
+
role: "link",
|
|
2618
|
+
onPress: props.onOpenPrivacy
|
|
2619
|
+
}
|
|
2620
|
+
) : null
|
|
2621
|
+
]
|
|
2622
|
+
}
|
|
2623
|
+
);
|
|
2624
|
+
}
|
|
2625
|
+
var LAUNCHER_SIZE = 56;
|
|
2626
|
+
function AgentLauncher(props) {
|
|
2627
|
+
return /* @__PURE__ */ jsx(CopyProvider, { locale: props.locale, copy: props.copy, children: /* @__PURE__ */ jsx(ThemeProvider, { theme: props.theme, colorScheme: props.colorScheme, children: /* @__PURE__ */ jsx(Launcher, { ...props }) }) });
|
|
2628
|
+
}
|
|
2629
|
+
function useKeyboardShown() {
|
|
2630
|
+
const [shown, setShown] = useState(false);
|
|
2631
|
+
useEffect(() => {
|
|
2632
|
+
const show = Keyboard.addListener("keyboardDidShow", () => setShown(true));
|
|
2633
|
+
const hide = Keyboard.addListener("keyboardDidHide", () => setShown(false));
|
|
2634
|
+
return () => {
|
|
2635
|
+
show.remove();
|
|
2636
|
+
hide.remove();
|
|
2637
|
+
};
|
|
2638
|
+
}, []);
|
|
2639
|
+
return shown;
|
|
2640
|
+
}
|
|
2641
|
+
function Launcher(props) {
|
|
2642
|
+
const { t } = useCopy();
|
|
2643
|
+
const name = useAgentName(t("agentFallbackName"));
|
|
2644
|
+
const keyboard = useKeyboardShown();
|
|
2645
|
+
const reducedMotion = useReducedMotion();
|
|
2646
|
+
const { route = null, routes, mode } = props;
|
|
2647
|
+
const visible = props.hidden !== true && !(keyboard && props.hideWithKeyboard !== false) && (!routes || route !== null && routes.includes(route));
|
|
2648
|
+
const launcher = useAgentLauncher({
|
|
2649
|
+
subject: props.subject,
|
|
2650
|
+
mode,
|
|
2651
|
+
visible,
|
|
2652
|
+
onOpen: () => props.onOpen({ route, mode }),
|
|
2653
|
+
...props.storage ? { storage: props.storage } : {},
|
|
2654
|
+
...props.storageKey ? { storageKey: props.storageKey } : {},
|
|
2655
|
+
...props.delayMs === void 0 ? {} : { delayMs: props.delayMs }
|
|
2656
|
+
});
|
|
2657
|
+
const text = typeof props.greeting === "function" ? props.greeting(mode) : props.greeting ?? t("launcherGreeting", { agent: name });
|
|
2658
|
+
const say = props.announce ?? announce;
|
|
2659
|
+
const said = useRef(false);
|
|
2660
|
+
useEffect(() => {
|
|
2661
|
+
if (!launcher.greets) {
|
|
2662
|
+
said.current = false;
|
|
2663
|
+
return;
|
|
2664
|
+
}
|
|
2665
|
+
if (said.current) return;
|
|
2666
|
+
said.current = true;
|
|
2667
|
+
say(text);
|
|
2668
|
+
}, [launcher.greets, text, say]);
|
|
2669
|
+
if (!launcher.shows) return null;
|
|
2670
|
+
const edge = props.placement?.edge ?? "right";
|
|
2671
|
+
const look = props.appearance ?? {};
|
|
2672
|
+
const greeting = {
|
|
2673
|
+
text,
|
|
2674
|
+
closeLabel: t("close"),
|
|
2675
|
+
onOpen: launcher.open,
|
|
2676
|
+
onClose: launcher.dismiss,
|
|
2677
|
+
tail: look.tail !== false,
|
|
2678
|
+
edge
|
|
2679
|
+
};
|
|
2680
|
+
const button = {
|
|
2681
|
+
label: t("launcherOpen", { agent: name }),
|
|
2682
|
+
name,
|
|
2683
|
+
onPress: launcher.open,
|
|
2684
|
+
Mark: props.Mark,
|
|
2685
|
+
ring: look.ring ?? null,
|
|
2686
|
+
shadow: look.shadow !== false
|
|
2687
|
+
};
|
|
2688
|
+
const { Greeting, Button: Button3, Entrance } = props.components ?? {};
|
|
2689
|
+
const enter = (part, children) => Entrance ? /* @__PURE__ */ jsx(
|
|
2690
|
+
Entrance,
|
|
2691
|
+
{
|
|
2692
|
+
part,
|
|
2693
|
+
reducedMotion,
|
|
2694
|
+
Default: LauncherEntrance,
|
|
2695
|
+
children
|
|
2696
|
+
}
|
|
2697
|
+
) : /* @__PURE__ */ jsx(LauncherEntrance, { part, reducedMotion, children });
|
|
2698
|
+
return /* @__PURE__ */ jsxs(
|
|
2699
|
+
View,
|
|
2700
|
+
{
|
|
2701
|
+
pointerEvents: "box-none",
|
|
2702
|
+
style: [
|
|
2703
|
+
{
|
|
2704
|
+
position: "absolute",
|
|
2705
|
+
bottom: props.placement?.bottom ?? 16,
|
|
2706
|
+
[edge]: props.placement?.inset ?? 16,
|
|
2707
|
+
alignItems: edge === "right" ? "flex-end" : "flex-start",
|
|
2708
|
+
gap: 8
|
|
2709
|
+
},
|
|
2710
|
+
props.style
|
|
2711
|
+
],
|
|
2712
|
+
testID: "vinaverse-launcher",
|
|
2713
|
+
children: [
|
|
2714
|
+
launcher.greets ? enter(
|
|
2715
|
+
"greeting",
|
|
2716
|
+
Greeting ? /* @__PURE__ */ jsx(Greeting, { ...greeting, Default: LauncherGreeting }) : /* @__PURE__ */ jsx(LauncherGreeting, { ...greeting })
|
|
2717
|
+
) : null,
|
|
2718
|
+
enter(
|
|
2719
|
+
"button",
|
|
2720
|
+
Button3 ? /* @__PURE__ */ jsx(Button3, { ...button, Default: LauncherButton }) : /* @__PURE__ */ jsx(LauncherButton, { ...button })
|
|
2721
|
+
)
|
|
2722
|
+
]
|
|
2723
|
+
}
|
|
2724
|
+
);
|
|
2725
|
+
}
|
|
2726
|
+
function LauncherEntrance(props) {
|
|
2727
|
+
const { motion: motion3 } = useTheme();
|
|
2728
|
+
const shown = useRef(new Animated.Value(props.reducedMotion ? 1 : 0)).current;
|
|
2729
|
+
useEffect(() => {
|
|
2730
|
+
if (props.reducedMotion) {
|
|
2731
|
+
shown.setValue(1);
|
|
2732
|
+
return;
|
|
2733
|
+
}
|
|
2734
|
+
const run = Animated.timing(shown, {
|
|
2735
|
+
toValue: 1,
|
|
2736
|
+
duration: motion3.normal,
|
|
2737
|
+
useNativeDriver: true
|
|
2738
|
+
});
|
|
2739
|
+
run.start();
|
|
2740
|
+
return () => run.stop();
|
|
2741
|
+
}, [shown, props.reducedMotion, motion3.normal]);
|
|
2742
|
+
return /* @__PURE__ */ jsx(
|
|
2743
|
+
Animated.View,
|
|
2744
|
+
{
|
|
2745
|
+
pointerEvents: "box-none",
|
|
2746
|
+
style: {
|
|
2747
|
+
opacity: shown,
|
|
2748
|
+
transform: [
|
|
2749
|
+
{
|
|
2750
|
+
scale: shown.interpolate({
|
|
2751
|
+
inputRange: [0, 1],
|
|
2752
|
+
outputRange: [0.9, 1]
|
|
2753
|
+
})
|
|
2754
|
+
}
|
|
2755
|
+
]
|
|
2756
|
+
},
|
|
2757
|
+
testID: `vinaverse-launcher-entrance-${props.part}`,
|
|
2758
|
+
children: props.children
|
|
2759
|
+
}
|
|
2760
|
+
);
|
|
2761
|
+
}
|
|
2762
|
+
function LauncherGreeting(props) {
|
|
2763
|
+
const { colors: colors2, radius: radius2, space: space2, font: font2 } = useTheme();
|
|
2764
|
+
return /* @__PURE__ */ jsxs(
|
|
2765
|
+
View,
|
|
2766
|
+
{
|
|
2767
|
+
style: {
|
|
2768
|
+
maxWidth: 296,
|
|
2769
|
+
flexDirection: "row",
|
|
2770
|
+
alignItems: "flex-start",
|
|
2771
|
+
borderRadius: radius2.lg,
|
|
2772
|
+
backgroundColor: colors2.text
|
|
2773
|
+
},
|
|
2774
|
+
testID: "vinaverse-launcher-greeting",
|
|
2775
|
+
children: [
|
|
2776
|
+
props.tail ? /* @__PURE__ */ jsx(
|
|
2777
|
+
View,
|
|
2778
|
+
{
|
|
2779
|
+
accessible: false,
|
|
2780
|
+
style: {
|
|
2781
|
+
position: "absolute",
|
|
2782
|
+
bottom: -5,
|
|
2783
|
+
[props.edge]: LAUNCHER_SIZE / 2 - 6,
|
|
2784
|
+
width: 12,
|
|
2785
|
+
height: 12,
|
|
2786
|
+
backgroundColor: colors2.text,
|
|
2787
|
+
transform: [{ rotate: "45deg" }]
|
|
2788
|
+
},
|
|
2789
|
+
testID: "vinaverse-launcher-tail"
|
|
2790
|
+
}
|
|
2791
|
+
) : null,
|
|
2792
|
+
/* @__PURE__ */ jsx(
|
|
2793
|
+
Pressable,
|
|
2794
|
+
{
|
|
2795
|
+
accessibilityRole: "button",
|
|
2796
|
+
accessibilityLabel: props.text,
|
|
2797
|
+
onPress: props.onOpen,
|
|
2798
|
+
style: {
|
|
2799
|
+
flexShrink: 1,
|
|
2800
|
+
paddingVertical: space2.sm,
|
|
2801
|
+
paddingLeft: space2.md
|
|
2802
|
+
},
|
|
2803
|
+
children: /* @__PURE__ */ jsx(Text, { style: { color: colors2.background, fontSize: font2.size.md }, children: props.text })
|
|
2804
|
+
}
|
|
2805
|
+
),
|
|
2806
|
+
/* @__PURE__ */ jsx(
|
|
2807
|
+
Pressable,
|
|
2808
|
+
{
|
|
2809
|
+
accessibilityRole: "button",
|
|
2810
|
+
accessibilityLabel: props.closeLabel,
|
|
2811
|
+
onPress: props.onClose,
|
|
2812
|
+
style: {
|
|
2813
|
+
minWidth: 44,
|
|
2814
|
+
minHeight: 44,
|
|
2815
|
+
alignItems: "center",
|
|
2816
|
+
justifyContent: "center"
|
|
2817
|
+
},
|
|
2818
|
+
testID: "vinaverse-launcher-close",
|
|
2819
|
+
children: /* @__PURE__ */ jsx(Text, { style: { color: colors2.background, fontSize: font2.size.md }, children: "\xD7" })
|
|
2820
|
+
}
|
|
2821
|
+
)
|
|
2822
|
+
]
|
|
2823
|
+
}
|
|
2824
|
+
);
|
|
2825
|
+
}
|
|
2826
|
+
function LauncherButton(props) {
|
|
2827
|
+
const { colors: colors2, font: font2 } = useTheme();
|
|
2828
|
+
const { Mark, ring } = props;
|
|
2829
|
+
return /* @__PURE__ */ jsx(
|
|
2830
|
+
Pressable,
|
|
2831
|
+
{
|
|
2832
|
+
accessibilityRole: "button",
|
|
2833
|
+
accessibilityLabel: props.label,
|
|
2834
|
+
onPress: props.onPress,
|
|
2835
|
+
style: ({ pressed }) => ({
|
|
2836
|
+
width: LAUNCHER_SIZE,
|
|
2837
|
+
height: LAUNCHER_SIZE,
|
|
2838
|
+
borderRadius: LAUNCHER_SIZE / 2,
|
|
2839
|
+
alignItems: "center",
|
|
2840
|
+
justifyContent: "center",
|
|
2841
|
+
backgroundColor: colors2.primary,
|
|
2842
|
+
opacity: pressed ? 0.85 : 1,
|
|
2843
|
+
...ring ? { borderWidth: ring.width, borderColor: ring.color } : {},
|
|
2844
|
+
...props.shadow ? {
|
|
2845
|
+
elevation: 6,
|
|
2846
|
+
shadowColor: "#000",
|
|
2847
|
+
shadowOpacity: 0.2,
|
|
2848
|
+
shadowRadius: 8,
|
|
2849
|
+
shadowOffset: { width: 0, height: 3 }
|
|
2850
|
+
} : {}
|
|
2851
|
+
}),
|
|
2852
|
+
testID: "vinaverse-launcher-button",
|
|
2853
|
+
children: Mark ? /* @__PURE__ */ jsx(Mark, { size: 34, color: colors2.onPrimary }) : /* @__PURE__ */ jsx(
|
|
2854
|
+
Text,
|
|
2855
|
+
{
|
|
2856
|
+
style: {
|
|
2857
|
+
color: colors2.onPrimary,
|
|
2858
|
+
fontSize: font2.size.lg,
|
|
2859
|
+
fontWeight: "600"
|
|
2860
|
+
},
|
|
2861
|
+
children: (props.name.trim()[0] ?? "?").toUpperCase()
|
|
2862
|
+
}
|
|
2863
|
+
)
|
|
2864
|
+
}
|
|
2865
|
+
);
|
|
2866
|
+
}
|
|
2867
|
+
function AskAboutRow(props) {
|
|
2868
|
+
return /* @__PURE__ */ jsx(CopyProvider, { locale: props.locale, copy: props.copy, children: /* @__PURE__ */ jsx(ThemeProvider, { theme: props.theme, colorScheme: props.colorScheme, children: /* @__PURE__ */ jsx(Row3, { ...props }) }) });
|
|
2869
|
+
}
|
|
2870
|
+
function Row3(props) {
|
|
2871
|
+
const { t } = useCopy();
|
|
2872
|
+
const { colors: colors2, radius: radius2, space: space2, font: font2 } = useTheme();
|
|
2873
|
+
const name = useAgentName(t("agentFallbackName"));
|
|
2874
|
+
const { available } = useAgentFeatures();
|
|
2875
|
+
const [shows, setShows] = useState(null);
|
|
2876
|
+
if (shows === null && available) setShows(true);
|
|
2877
|
+
if (!shows) return null;
|
|
2878
|
+
const { Mark } = props;
|
|
2879
|
+
return /* @__PURE__ */ jsxs(
|
|
2880
|
+
Pressable,
|
|
2881
|
+
{
|
|
2882
|
+
accessibilityRole: "button",
|
|
2883
|
+
accessibilityLabel: props.body ? `${props.title}. ${props.body}` : props.title,
|
|
2884
|
+
onPress: props.onPress,
|
|
2885
|
+
style: ({ pressed }) => ({
|
|
2886
|
+
flexDirection: "row",
|
|
2887
|
+
alignItems: "center",
|
|
2888
|
+
gap: space2.md,
|
|
2889
|
+
padding: space2.md,
|
|
2890
|
+
borderRadius: radius2.lg,
|
|
2891
|
+
backgroundColor: colors2.surface,
|
|
2892
|
+
opacity: pressed ? 0.85 : 1
|
|
2893
|
+
}),
|
|
2894
|
+
testID: "vinaverse-ask-about",
|
|
2895
|
+
children: [
|
|
2896
|
+
/* @__PURE__ */ jsx(
|
|
2897
|
+
View,
|
|
2898
|
+
{
|
|
2899
|
+
style: {
|
|
2900
|
+
width: 36,
|
|
2901
|
+
height: 36,
|
|
2902
|
+
borderRadius: 18,
|
|
2903
|
+
alignItems: "center",
|
|
2904
|
+
justifyContent: "center",
|
|
2905
|
+
backgroundColor: colors2.primary
|
|
2906
|
+
},
|
|
2907
|
+
children: Mark ? /* @__PURE__ */ jsx(Mark, { size: 22, color: colors2.onPrimary }) : /* @__PURE__ */ jsx(Text, { style: { color: colors2.onPrimary, fontWeight: "600" }, children: (name.trim()[0] ?? "?").toUpperCase() })
|
|
2908
|
+
}
|
|
2909
|
+
),
|
|
2910
|
+
/* @__PURE__ */ jsxs(View, { style: { flex: 1, gap: space2.xxs }, children: [
|
|
2911
|
+
/* @__PURE__ */ jsx(
|
|
2912
|
+
Text,
|
|
2913
|
+
{
|
|
2914
|
+
style: {
|
|
2915
|
+
color: colors2.text,
|
|
2916
|
+
fontSize: font2.size.md,
|
|
2917
|
+
fontWeight: "600"
|
|
2918
|
+
},
|
|
2919
|
+
children: props.title
|
|
2920
|
+
}
|
|
2921
|
+
),
|
|
2922
|
+
props.body ? /* @__PURE__ */ jsx(Text, { style: { color: colors2.textMuted, fontSize: font2.size.sm }, children: props.body }) : null
|
|
2923
|
+
] }),
|
|
2924
|
+
/* @__PURE__ */ jsx(Text, { style: { color: colors2.textMuted, fontSize: font2.size.lg }, children: "\u203A" })
|
|
2925
|
+
]
|
|
2926
|
+
}
|
|
2927
|
+
);
|
|
2928
|
+
}
|
|
2000
2929
|
|
|
2001
|
-
export { ActivityLine, Avatar, Button, CardFrame, CardView, ChatHeader, ChatSkeleton, Composer, DefaultBubble, DefaultComposer, DefaultHeader, DefaultTurnFailed, DefaultUnavailable, DisclosureBar, FailureActionButton, InfoCard, MessageBubble, MessageList, NextStepCard, ProposalCard, QuestionCard, Row, StatusBanner, StreamingBubble, SystemRow, ThemeProvider, TimeSlotsCard, VinaverseChat, VinaverseChatProvider, announce, answerText, createTheme, defaultCard, fieldText, itemType, themeProblems, useChat, useNativeLifecycle, useReducedMotion, useTheme };
|
|
2930
|
+
export { ActivityLine, AgentChat, AgentFooter, AgentLauncher, AskAboutRow, Avatar, Button, CardActions, CardCarousel, CardFrame, CardView, ChatHeader, ChatSkeleton, Composer, DefaultBubble, DefaultComposer, DefaultEnded, DefaultHeader, DefaultTurnFailed, DefaultUnavailable, DefaultUnavailableScreen, DefaultUnreachable, DisclosureBar, FailureActionButton, InfoCard, LAUNCHER_SIZE, LauncherButton, LauncherEntrance, LauncherGreeting, LinksCard, ListingCard, MessageBubble, MessageList, NextStepCard, ProposalCard, QuestionCard, Row, StatusBanner, StreamingBubble, SystemRow, ThemeProvider, TimeSlotsCard, VinaverseChat, VinaverseChatProvider, Welcome, allowedImage, announce, answerText, carousels, createTheme, defaultCard, fieldText, itemType, monogram, newestWholeReply, ratingText, themeProblems, useChat, useKeyboardShown, useNativeLifecycle, useReducedMotion, useTheme };
|
|
2002
2931
|
//# sourceMappingURL=index.js.map
|
|
2003
2932
|
//# sourceMappingURL=index.js.map
|