@vinaverse/react-native 0.1.0-alpha.4 → 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 +66 -0
- package/dist/index.cjs +854 -129
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +337 -90
- package/dist/index.d.ts +337 -90
- package/dist/index.js +808 -132
- package/dist/index.js.map +1 -1
- package/package.json +68 -8
package/dist/index.cjs
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var agent = require('@vinaverse/react/agent');
|
|
3
4
|
var flashList = require('@shopify/flash-list');
|
|
4
5
|
var react$1 = require('@vinaverse/react');
|
|
5
6
|
var reactNative = require('react-native');
|
|
7
|
+
var agent$1 = require('@vinaverse/client/agent');
|
|
6
8
|
var react = require('react');
|
|
7
9
|
var jsxRuntime = require('react/jsx-runtime');
|
|
8
10
|
var tokens = require('@vinaverse/tokens');
|
|
9
11
|
var conversation = require('@vinaverse/client/conversation');
|
|
10
12
|
|
|
11
|
-
// src/
|
|
13
|
+
// src/index.ts
|
|
12
14
|
var ChatContext = react.createContext(null);
|
|
13
15
|
function ChatContextProvider(props) {
|
|
14
16
|
return /* @__PURE__ */ jsxRuntime.jsx(ChatContext.Provider, { value: props.value, children: props.children });
|
|
@@ -191,6 +193,12 @@ function ratingText(valuePpm, locale) {
|
|
|
191
193
|
return value.toFixed(1);
|
|
192
194
|
}
|
|
193
195
|
}
|
|
196
|
+
function allowedImage(url, hosts) {
|
|
197
|
+
const safe = safeImage(url);
|
|
198
|
+
if (safe === null || !hosts) return safe;
|
|
199
|
+
const host = /^https:\/\/([^/:?#]+)/i.exec(safe)?.[1]?.toLowerCase();
|
|
200
|
+
return host && hosts.some((h) => h.toLowerCase() === host) ? safe : null;
|
|
201
|
+
}
|
|
194
202
|
function safeImage(url) {
|
|
195
203
|
return url && /^https:\/\//i.test(url) ? url : null;
|
|
196
204
|
}
|
|
@@ -338,10 +346,13 @@ function LinksCard(props) {
|
|
|
338
346
|
function ListingCard(props) {
|
|
339
347
|
const card = cardOf(props.card);
|
|
340
348
|
const { locale, t } = react$1.useCopy();
|
|
341
|
-
const { slots, timeZone } = useChat();
|
|
349
|
+
const { slots, timeZone, handlers, imagePolicy } = useChat();
|
|
342
350
|
const { colors: colors2, radius: radius2, space: space2, font: font2 } = useTheme();
|
|
343
351
|
const [failed, setFailed] = react.useState(null);
|
|
344
|
-
const photoUrl =
|
|
352
|
+
const photoUrl = allowedImage(
|
|
353
|
+
card.images?.[0]?.url ?? card.image_url,
|
|
354
|
+
imagePolicy?.hosts
|
|
355
|
+
);
|
|
345
356
|
const hero = photoUrl === failed ? null : photoUrl;
|
|
346
357
|
const Img = slots.Image ?? reactNative.Image;
|
|
347
358
|
const rating = card.rating ? `\u2605 ${ratingText(card.rating.value_ppm, locale)} (${card.rating.count})` : null;
|
|
@@ -355,11 +366,55 @@ function ListingCard(props) {
|
|
|
355
366
|
const next = card.next_available ? t("nextAvailable", {
|
|
356
367
|
time: react$1.formatTimeRange(card.next_available, void 0, locale, timeZone)
|
|
357
368
|
}) : null;
|
|
369
|
+
const ref = card.ref;
|
|
370
|
+
const onOpenTarget = handlers.current?.onOpenTarget;
|
|
371
|
+
const open = ref && onOpenTarget && !props.restored ? () => onOpenTarget({ type: ref.type, id: ref.id }, props.card) : null;
|
|
358
372
|
const photo = {
|
|
359
373
|
width: "100%",
|
|
360
|
-
aspectRatio: 1.6,
|
|
374
|
+
aspectRatio: imagePolicy?.aspectRatio ?? 1.6,
|
|
361
375
|
borderRadius: radius2.md
|
|
362
376
|
};
|
|
377
|
+
const top = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
378
|
+
hero ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
379
|
+
Img,
|
|
380
|
+
{
|
|
381
|
+
source: { uri: hero },
|
|
382
|
+
onError: () => setFailed(hero),
|
|
383
|
+
style: { ...photo, backgroundColor: colors2.surface },
|
|
384
|
+
accessible: false,
|
|
385
|
+
testID: `vinaverse-photo-${card.id}`
|
|
386
|
+
}
|
|
387
|
+
) : imagePolicy?.Placeholder ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: photo, testID: `vinaverse-placeholder-${card.id}`, children: /* @__PURE__ */ jsxRuntime.jsx(imagePolicy.Placeholder, { title: card.title }) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
388
|
+
reactNative.View,
|
|
389
|
+
{
|
|
390
|
+
accessible: false,
|
|
391
|
+
importantForAccessibility: "no-hide-descendants",
|
|
392
|
+
testID: `vinaverse-monogram-${card.id}`,
|
|
393
|
+
style: {
|
|
394
|
+
...photo,
|
|
395
|
+
backgroundColor: colors2.surface,
|
|
396
|
+
alignItems: "center",
|
|
397
|
+
justifyContent: "center"
|
|
398
|
+
},
|
|
399
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
400
|
+
reactNative.Text,
|
|
401
|
+
{
|
|
402
|
+
style: {
|
|
403
|
+
color: colors2.textMuted,
|
|
404
|
+
fontSize: font2.size.xl,
|
|
405
|
+
fontWeight: "600"
|
|
406
|
+
},
|
|
407
|
+
children: monogram(card.title)
|
|
408
|
+
}
|
|
409
|
+
)
|
|
410
|
+
}
|
|
411
|
+
),
|
|
412
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { gap: space2.xxs }, children: [
|
|
413
|
+
/* @__PURE__ */ jsxRuntime.jsx(Title, { numberOfLines: 2, children: card.title }),
|
|
414
|
+
card.subtitle ? /* @__PURE__ */ jsxRuntime.jsx(Body, { muted: true, children: card.subtitle }) : null,
|
|
415
|
+
rating || price ? /* @__PURE__ */ jsxRuntime.jsx(Body, { muted: true, children: [rating, price].filter(Boolean).join(" \xB7 ") }) : null
|
|
416
|
+
] })
|
|
417
|
+
] });
|
|
363
418
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
364
419
|
CardFrame,
|
|
365
420
|
{
|
|
@@ -367,45 +422,17 @@ function ListingCard(props) {
|
|
|
367
422
|
restored: props.restored,
|
|
368
423
|
testID: `vinaverse-card-${card.id}`,
|
|
369
424
|
children: [
|
|
370
|
-
|
|
371
|
-
|
|
425
|
+
open ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
426
|
+
reactNative.Pressable,
|
|
372
427
|
{
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
testID: `vinaverse-
|
|
428
|
+
accessibilityRole: "link",
|
|
429
|
+
accessibilityLabel: card.title,
|
|
430
|
+
onPress: open,
|
|
431
|
+
style: { gap: space2.sm },
|
|
432
|
+
testID: `vinaverse-open-${card.id}`,
|
|
433
|
+
children: top
|
|
378
434
|
}
|
|
379
|
-
) :
|
|
380
|
-
reactNative.View,
|
|
381
|
-
{
|
|
382
|
-
accessible: false,
|
|
383
|
-
importantForAccessibility: "no-hide-descendants",
|
|
384
|
-
testID: `vinaverse-monogram-${card.id}`,
|
|
385
|
-
style: {
|
|
386
|
-
...photo,
|
|
387
|
-
backgroundColor: colors2.surface,
|
|
388
|
-
alignItems: "center",
|
|
389
|
-
justifyContent: "center"
|
|
390
|
-
},
|
|
391
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
392
|
-
reactNative.Text,
|
|
393
|
-
{
|
|
394
|
-
style: {
|
|
395
|
-
color: colors2.textMuted,
|
|
396
|
-
fontSize: font2.size.xl,
|
|
397
|
-
fontWeight: "600"
|
|
398
|
-
},
|
|
399
|
-
children: monogram(card.title)
|
|
400
|
-
}
|
|
401
|
-
)
|
|
402
|
-
}
|
|
403
|
-
),
|
|
404
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { gap: space2.xxs }, children: [
|
|
405
|
-
/* @__PURE__ */ jsxRuntime.jsx(Title, { numberOfLines: 2, children: card.title }),
|
|
406
|
-
card.subtitle ? /* @__PURE__ */ jsxRuntime.jsx(Body, { muted: true, children: card.subtitle }) : null,
|
|
407
|
-
rating || price ? /* @__PURE__ */ jsxRuntime.jsx(Body, { muted: true, children: [rating, price].filter(Boolean).join(" \xB7 ") }) : null
|
|
408
|
-
] }),
|
|
435
|
+
) : top,
|
|
409
436
|
card.body ? /* @__PURE__ */ jsxRuntime.jsx(Body, { children: card.body }) : null,
|
|
410
437
|
/* @__PURE__ */ jsxRuntime.jsx(Badges, { badges: next ? [next, ...card.badges ?? []] : card.badges }),
|
|
411
438
|
props.restored ? null : /* @__PURE__ */ jsxRuntime.jsx(CardActions, { ...props })
|
|
@@ -1297,7 +1324,8 @@ var CardView = react.memo(function CardView2(props) {
|
|
|
1297
1324
|
const { card, busy } = props.item;
|
|
1298
1325
|
const Default = defaultCard(card.kind);
|
|
1299
1326
|
const Custom = slots.cards?.[card.kind];
|
|
1300
|
-
const
|
|
1327
|
+
const read = react.useMemo(() => agent$1.readCard(card.card), [card]);
|
|
1328
|
+
const own = { card, read, busy, restored: props.item.restored === true };
|
|
1301
1329
|
return Custom ? /* @__PURE__ */ jsxRuntime.jsx(Custom, { ...own, Default }) : /* @__PURE__ */ jsxRuntime.jsx(Default, { ...own });
|
|
1302
1330
|
});
|
|
1303
1331
|
var keyOf = (item) => item.key;
|
|
@@ -1351,6 +1379,38 @@ var ActivityLine = react.memo(function ActivityLine2() {
|
|
|
1351
1379
|
}
|
|
1352
1380
|
);
|
|
1353
1381
|
});
|
|
1382
|
+
function useNativeLifecycle(store) {
|
|
1383
|
+
react.useEffect(() => {
|
|
1384
|
+
const apply = (state) => store.setForeground(state === "active");
|
|
1385
|
+
apply(reactNative.AppState.currentState);
|
|
1386
|
+
const subscription = reactNative.AppState.addEventListener("change", apply);
|
|
1387
|
+
return () => subscription.remove();
|
|
1388
|
+
}, [store]);
|
|
1389
|
+
}
|
|
1390
|
+
function useReducedMotion() {
|
|
1391
|
+
const [reduced, setReduced] = react.useState(false);
|
|
1392
|
+
react.useEffect(() => {
|
|
1393
|
+
let live = true;
|
|
1394
|
+
reactNative.AccessibilityInfo.isReduceMotionEnabled().then(
|
|
1395
|
+
(value) => {
|
|
1396
|
+
if (live) setReduced(value);
|
|
1397
|
+
},
|
|
1398
|
+
() => void 0
|
|
1399
|
+
);
|
|
1400
|
+
const subscription = reactNative.AccessibilityInfo.addEventListener(
|
|
1401
|
+
"reduceMotionChanged",
|
|
1402
|
+
setReduced
|
|
1403
|
+
);
|
|
1404
|
+
return () => {
|
|
1405
|
+
live = false;
|
|
1406
|
+
subscription.remove();
|
|
1407
|
+
};
|
|
1408
|
+
}, []);
|
|
1409
|
+
return reduced;
|
|
1410
|
+
}
|
|
1411
|
+
function announce(text) {
|
|
1412
|
+
if (text) reactNative.AccessibilityInfo.announceForAccessibility(text);
|
|
1413
|
+
}
|
|
1354
1414
|
var Avatar = react.memo(function Avatar2(props) {
|
|
1355
1415
|
const { colors: colors2, size: size3, font: font2 } = useTheme();
|
|
1356
1416
|
const { slots } = useChat();
|
|
@@ -1463,37 +1523,6 @@ var ChatHeader = react.memo(function ChatHeader2() {
|
|
|
1463
1523
|
};
|
|
1464
1524
|
return Header ? /* @__PURE__ */ jsxRuntime.jsx(Header, { ...props, Default: DefaultHeader }) : /* @__PURE__ */ jsxRuntime.jsx(DefaultHeader, { ...props });
|
|
1465
1525
|
});
|
|
1466
|
-
var ChatSkeleton = react.memo(function ChatSkeleton2() {
|
|
1467
|
-
const { colors: colors2, radius: radius2, space: space2 } = useTheme();
|
|
1468
|
-
const row = (width, end) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1469
|
-
reactNative.View,
|
|
1470
|
-
{
|
|
1471
|
-
style: {
|
|
1472
|
-
alignSelf: end ? "flex-end" : "flex-start",
|
|
1473
|
-
width,
|
|
1474
|
-
height: 40,
|
|
1475
|
-
borderRadius: radius2.lg,
|
|
1476
|
-
backgroundColor: colors2.surface,
|
|
1477
|
-
marginHorizontal: space2.lg,
|
|
1478
|
-
marginTop: space2.md
|
|
1479
|
-
}
|
|
1480
|
-
}
|
|
1481
|
-
);
|
|
1482
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1483
|
-
reactNative.View,
|
|
1484
|
-
{
|
|
1485
|
-
accessible: true,
|
|
1486
|
-
accessibilityRole: "progressbar",
|
|
1487
|
-
accessibilityState: { busy: true },
|
|
1488
|
-
testID: "vinaverse-skeleton",
|
|
1489
|
-
children: [
|
|
1490
|
-
row("62%", false),
|
|
1491
|
-
row("45%", true),
|
|
1492
|
-
row("70%", false)
|
|
1493
|
-
]
|
|
1494
|
-
}
|
|
1495
|
-
);
|
|
1496
|
-
});
|
|
1497
1526
|
function DefaultComposer(props) {
|
|
1498
1527
|
const { t, direction } = react$1.useCopy();
|
|
1499
1528
|
const { colors: colors2, radius: radius2, space: space2, font: font2, size: size3 } = useTheme();
|
|
@@ -1635,23 +1664,37 @@ var DisclosureBar = react.memo(function DisclosureBar2() {
|
|
|
1635
1664
|
}
|
|
1636
1665
|
);
|
|
1637
1666
|
});
|
|
1638
|
-
function
|
|
1639
|
-
const {
|
|
1640
|
-
const
|
|
1641
|
-
|
|
1642
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1643
|
-
Button,
|
|
1667
|
+
var ChatSkeleton = react.memo(function ChatSkeleton2() {
|
|
1668
|
+
const { colors: colors2, radius: radius2, space: space2 } = useTheme();
|
|
1669
|
+
const row = (width, end) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1670
|
+
reactNative.View,
|
|
1644
1671
|
{
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1672
|
+
style: {
|
|
1673
|
+
alignSelf: end ? "flex-end" : "flex-start",
|
|
1674
|
+
width,
|
|
1675
|
+
height: 40,
|
|
1676
|
+
borderRadius: radius2.lg,
|
|
1677
|
+
backgroundColor: colors2.surface,
|
|
1678
|
+
marginHorizontal: space2.lg,
|
|
1679
|
+
marginTop: space2.md
|
|
1680
|
+
}
|
|
1648
1681
|
}
|
|
1649
1682
|
);
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1683
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1684
|
+
reactNative.View,
|
|
1685
|
+
{
|
|
1686
|
+
accessible: true,
|
|
1687
|
+
accessibilityRole: "progressbar",
|
|
1688
|
+
accessibilityState: { busy: true },
|
|
1689
|
+
testID: "vinaverse-skeleton",
|
|
1690
|
+
children: [
|
|
1691
|
+
row("62%", false),
|
|
1692
|
+
row("45%", true),
|
|
1693
|
+
row("70%", false)
|
|
1694
|
+
]
|
|
1695
|
+
}
|
|
1696
|
+
);
|
|
1697
|
+
});
|
|
1655
1698
|
function DefaultBubble(props) {
|
|
1656
1699
|
const { colors: colors2, radius: radius2, space: space2, font: font2 } = useTheme();
|
|
1657
1700
|
const role = props.item.role;
|
|
@@ -1773,37 +1816,22 @@ function Frame(props) {
|
|
|
1773
1816
|
}
|
|
1774
1817
|
);
|
|
1775
1818
|
}
|
|
1776
|
-
function
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
reactNative.AccessibilityInfo.isReduceMotionEnabled().then(
|
|
1789
|
-
(value) => {
|
|
1790
|
-
if (live) setReduced(value);
|
|
1791
|
-
},
|
|
1792
|
-
() => void 0
|
|
1793
|
-
);
|
|
1794
|
-
const subscription = reactNative.AccessibilityInfo.addEventListener(
|
|
1795
|
-
"reduceMotionChanged",
|
|
1796
|
-
setReduced
|
|
1797
|
-
);
|
|
1798
|
-
return () => {
|
|
1799
|
-
live = false;
|
|
1800
|
-
subscription.remove();
|
|
1801
|
-
};
|
|
1802
|
-
}, []);
|
|
1803
|
-
return reduced;
|
|
1819
|
+
function FailureActionButton(props) {
|
|
1820
|
+
const { handlers, failureAction } = useChat();
|
|
1821
|
+
const { t } = react$1.useCopy();
|
|
1822
|
+
if (!failureAction) return null;
|
|
1823
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1824
|
+
Button,
|
|
1825
|
+
{
|
|
1826
|
+
label: failureAction.label ?? t("talkToPerson"),
|
|
1827
|
+
variant: "text",
|
|
1828
|
+
onPress: () => handlers.current.failureAction?.onPress(props.state)
|
|
1829
|
+
}
|
|
1830
|
+
);
|
|
1804
1831
|
}
|
|
1805
|
-
function
|
|
1806
|
-
|
|
1832
|
+
function FailureSlot(props) {
|
|
1833
|
+
const { slot: Slot, state, Default } = props;
|
|
1834
|
+
return Slot ? /* @__PURE__ */ jsxRuntime.jsx(Slot, { state, Default }) : /* @__PURE__ */ jsxRuntime.jsx(Default, { state });
|
|
1807
1835
|
}
|
|
1808
1836
|
var SystemRow = react.memo(function SystemRow2(props) {
|
|
1809
1837
|
const { t } = react$1.useCopy();
|
|
@@ -1971,17 +1999,27 @@ var Row = react.memo(function Row2(props) {
|
|
|
1971
1999
|
return item.state === "streaming" ? /* @__PURE__ */ jsxRuntime.jsx(StreamingBubble, { item, showAuthor: props.showAuthor }) : /* @__PURE__ */ jsxRuntime.jsx(MessageBubble, { item, showAuthor: props.showAuthor });
|
|
1972
2000
|
});
|
|
1973
2001
|
var MessageList = react.memo(function MessageList2() {
|
|
1974
|
-
const { store, slots } = useChat();
|
|
2002
|
+
const { store, slots, starters, handlers, imagePolicy } = useChat();
|
|
1975
2003
|
const { t } = react$1.useCopy();
|
|
1976
2004
|
const { space: space2 } = useTheme();
|
|
1977
2005
|
const reducedMotion = useReducedMotion();
|
|
1978
2006
|
const items = react$1.useConversationSelector(store, (v) => v.items);
|
|
2007
|
+
usePrefetchPhotos(items, handlers.current?.prefetchImage, imagePolicy?.hosts);
|
|
1979
2008
|
const opening = react$1.useConversationSelector(
|
|
1980
2009
|
store,
|
|
1981
2010
|
(v) => v.status === "starting" || v.status === "connecting"
|
|
1982
2011
|
);
|
|
1983
2012
|
const agentName = react$1.useConversationSelector(store, (v) => v.agent.name);
|
|
1984
|
-
const
|
|
2013
|
+
const served = react$1.useConversationSelector(store, (v) => v.welcome);
|
|
2014
|
+
const welcome = react.useMemo(
|
|
2015
|
+
() => served ?? (starters?.length ? {
|
|
2016
|
+
text: t("welcomeFallback", {
|
|
2017
|
+
agent: agentName ?? t("agentFallbackName")
|
|
2018
|
+
}),
|
|
2019
|
+
chips: [...starters]
|
|
2020
|
+
} : null),
|
|
2021
|
+
[served, starters, t, agentName]
|
|
2022
|
+
);
|
|
1985
2023
|
useAnnounceReplies(items);
|
|
1986
2024
|
const Group = slots.CardGroup;
|
|
1987
2025
|
const runsRef = react.useRef(/* @__PURE__ */ new Map());
|
|
@@ -2007,8 +2045,12 @@ var MessageList = react.memo(function MessageList2() {
|
|
|
2007
2045
|
[]
|
|
2008
2046
|
);
|
|
2009
2047
|
const onChip = react.useCallback(
|
|
2010
|
-
(message) =>
|
|
2011
|
-
|
|
2048
|
+
(message) => {
|
|
2049
|
+
store.send(message);
|
|
2050
|
+
const chip = welcome?.chips.find((c) => c.message === message);
|
|
2051
|
+
if (chip) handlers.current?.onChip?.(chip);
|
|
2052
|
+
},
|
|
2053
|
+
[store, welcome, handlers]
|
|
2012
2054
|
);
|
|
2013
2055
|
const Empty = slots.EmptyState;
|
|
2014
2056
|
const empty = opening ? /* @__PURE__ */ jsxRuntime.jsx(ChatSkeleton, {}) : Empty ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2040,10 +2082,25 @@ var MessageList = react.memo(function MessageList2() {
|
|
|
2040
2082
|
const List = slots.ListComponent;
|
|
2041
2083
|
return List ? /* @__PURE__ */ jsxRuntime.jsx(List, { ...props }) : /* @__PURE__ */ jsxRuntime.jsx(flashList.FlashList, { ...props });
|
|
2042
2084
|
});
|
|
2085
|
+
function usePrefetchPhotos(items, prefetch, hosts) {
|
|
2086
|
+
const done = react.useRef(/* @__PURE__ */ new Set());
|
|
2087
|
+
react.useEffect(() => {
|
|
2088
|
+
if (!prefetch) return;
|
|
2089
|
+
for (const item of items) {
|
|
2090
|
+
if (item.type !== "card") continue;
|
|
2091
|
+
const card = item.card.card;
|
|
2092
|
+
const url = allowedImage(card.images?.[0]?.url ?? card.image_url, hosts);
|
|
2093
|
+
if (url && !done.current.has(url)) {
|
|
2094
|
+
done.current.add(url);
|
|
2095
|
+
prefetch(url);
|
|
2096
|
+
}
|
|
2097
|
+
}
|
|
2098
|
+
}, [items, prefetch, hosts]);
|
|
2099
|
+
}
|
|
2043
2100
|
function useAnnounceReplies(items) {
|
|
2044
2101
|
const seen = react.useRef(void 0);
|
|
2045
2102
|
const { t } = react$1.useCopy();
|
|
2046
|
-
const { store } = useChat();
|
|
2103
|
+
const { store, handlers } = useChat();
|
|
2047
2104
|
react.useEffect(() => {
|
|
2048
2105
|
const last = items.at(-1);
|
|
2049
2106
|
if (seen.current === void 0) {
|
|
@@ -2056,8 +2113,8 @@ function useAnnounceReplies(items) {
|
|
|
2056
2113
|
const author = last.role === "staff" ? t("staffLabel", {
|
|
2057
2114
|
by: store.getSnapshot().takeover?.by || t("staffFallbackRole")
|
|
2058
2115
|
}) : store.getSnapshot().agent.name ?? t("agentFallbackName");
|
|
2059
|
-
announce(`${author}: ${last.text}`);
|
|
2060
|
-
}, [items, t, store]);
|
|
2116
|
+
(handlers.current?.announce ?? announce)(`${author}: ${last.text}`);
|
|
2117
|
+
}, [items, t, store, handlers]);
|
|
2061
2118
|
}
|
|
2062
2119
|
var CONNECTING_DELAY = tokens.motion.bannerDelay;
|
|
2063
2120
|
var StatusBanner = react.memo(function StatusBanner2() {
|
|
@@ -2158,7 +2215,14 @@ function Banner(props) {
|
|
|
2158
2215
|
);
|
|
2159
2216
|
}
|
|
2160
2217
|
function VinaverseChatProvider(props) {
|
|
2161
|
-
const {
|
|
2218
|
+
const {
|
|
2219
|
+
conversation,
|
|
2220
|
+
components,
|
|
2221
|
+
agentAvatar,
|
|
2222
|
+
timeZone,
|
|
2223
|
+
starters,
|
|
2224
|
+
imagePolicy
|
|
2225
|
+
} = props;
|
|
2162
2226
|
const handlers = react.useRef(props);
|
|
2163
2227
|
handlers.current = props;
|
|
2164
2228
|
const slots = useStableSlots(components);
|
|
@@ -2175,9 +2239,19 @@ function VinaverseChatProvider(props) {
|
|
|
2175
2239
|
slots,
|
|
2176
2240
|
agentAvatar,
|
|
2177
2241
|
timeZone,
|
|
2178
|
-
failureAction
|
|
2242
|
+
failureAction,
|
|
2243
|
+
starters,
|
|
2244
|
+
imagePolicy
|
|
2179
2245
|
}),
|
|
2180
|
-
[
|
|
2246
|
+
[
|
|
2247
|
+
conversation,
|
|
2248
|
+
slots,
|
|
2249
|
+
agentAvatar,
|
|
2250
|
+
timeZone,
|
|
2251
|
+
failureAction,
|
|
2252
|
+
starters,
|
|
2253
|
+
imagePolicy
|
|
2254
|
+
]
|
|
2181
2255
|
);
|
|
2182
2256
|
useNativeLifecycle(conversation);
|
|
2183
2257
|
react.useEffect(() => {
|
|
@@ -2203,7 +2277,9 @@ function VinaverseChat(props) {
|
|
|
2203
2277
|
keyboardVerticalOffset: props.keyboardVerticalOffset ?? 0,
|
|
2204
2278
|
keyboardBehavior: props.keyboardBehavior ?? (reactNative.Platform.OS === "ios" ? "padding" : "none"),
|
|
2205
2279
|
style: props.style,
|
|
2206
|
-
onError: props.onWarning
|
|
2280
|
+
onError: props.onWarning,
|
|
2281
|
+
suggestion: props.suggestion ?? null,
|
|
2282
|
+
footer: props.footer
|
|
2207
2283
|
}
|
|
2208
2284
|
) });
|
|
2209
2285
|
}
|
|
@@ -2229,11 +2305,27 @@ function Layout(props) {
|
|
|
2229
2305
|
/* @__PURE__ */ jsxRuntime.jsx(DisclosureBar, {}),
|
|
2230
2306
|
/* @__PURE__ */ jsxRuntime.jsx(StatusBanner, {}),
|
|
2231
2307
|
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { flex: 1 }, children: /* @__PURE__ */ jsxRuntime.jsx(MessageList, {}) }),
|
|
2232
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2308
|
+
props.suggestion ? /* @__PURE__ */ jsxRuntime.jsx(Suggestion, { chip: props.suggestion }) : null,
|
|
2309
|
+
/* @__PURE__ */ jsxRuntime.jsx(Composer, { ...reportError ? { onError: reportError } : {} }),
|
|
2310
|
+
props.footer
|
|
2233
2311
|
]
|
|
2234
2312
|
}
|
|
2235
2313
|
);
|
|
2236
2314
|
}
|
|
2315
|
+
function Suggestion(props) {
|
|
2316
|
+
const { store, handlers } = useChat();
|
|
2317
|
+
const { space: space2 } = useTheme();
|
|
2318
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { paddingHorizontal: space2.lg, alignItems: "flex-start" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2319
|
+
Button,
|
|
2320
|
+
{
|
|
2321
|
+
label: props.chip.label,
|
|
2322
|
+
onPress: () => {
|
|
2323
|
+
store.send(props.chip.message);
|
|
2324
|
+
handlers.current?.onChip?.(props.chip);
|
|
2325
|
+
}
|
|
2326
|
+
}
|
|
2327
|
+
) });
|
|
2328
|
+
}
|
|
2237
2329
|
function useStableSlots(slots) {
|
|
2238
2330
|
const held = react.useRef({});
|
|
2239
2331
|
const next = slots ?? {};
|
|
@@ -2252,8 +2344,631 @@ function sameSlots(a, b) {
|
|
|
2252
2344
|
}
|
|
2253
2345
|
return true;
|
|
2254
2346
|
}
|
|
2347
|
+
function AgentChat(props) {
|
|
2348
|
+
const {
|
|
2349
|
+
agentKey,
|
|
2350
|
+
place,
|
|
2351
|
+
entryPoint,
|
|
2352
|
+
askAbout,
|
|
2353
|
+
onContact,
|
|
2354
|
+
onOpenPrivacy,
|
|
2355
|
+
components,
|
|
2356
|
+
agentName,
|
|
2357
|
+
opener,
|
|
2358
|
+
...chat
|
|
2359
|
+
} = props;
|
|
2360
|
+
const runtime = agent.useAgentRuntime();
|
|
2361
|
+
const { conversation, state, startNew } = agent.useAgentConversation(agentKey, {
|
|
2362
|
+
place: place ?? null,
|
|
2363
|
+
entryPoint: entryPoint ?? null
|
|
2364
|
+
});
|
|
2365
|
+
const store = conversation.store;
|
|
2366
|
+
const spoke = react$1.useConversationSelector(
|
|
2367
|
+
store,
|
|
2368
|
+
(v) => v.items.some((i) => i.type === "message" && i.role === "person")
|
|
2369
|
+
);
|
|
2370
|
+
const { Ended, Unreachable, UnavailableScreen, Footer, ...slots } = components ?? {};
|
|
2371
|
+
const copy = react.useMemo(
|
|
2372
|
+
() => agentName ? { ...props.copy, agentFallbackName: agentName } : props.copy,
|
|
2373
|
+
[agentName, props.copy]
|
|
2374
|
+
);
|
|
2375
|
+
const events = {
|
|
2376
|
+
onOpenTarget: chat.onOpenTarget ? (target, card) => {
|
|
2377
|
+
runtime.emit({
|
|
2378
|
+
type: "target_opened",
|
|
2379
|
+
key: conversation.key,
|
|
2380
|
+
cardId: card.id,
|
|
2381
|
+
kind: target.type
|
|
2382
|
+
});
|
|
2383
|
+
chat.onOpenTarget?.(target, card);
|
|
2384
|
+
} : void 0,
|
|
2385
|
+
onOpenLink: chat.onOpenLink ? (link, card) => {
|
|
2386
|
+
runtime.emit({
|
|
2387
|
+
type: "link_opened",
|
|
2388
|
+
key: conversation.key,
|
|
2389
|
+
cardId: card.id,
|
|
2390
|
+
kind: card.kind
|
|
2391
|
+
});
|
|
2392
|
+
chat.onOpenLink?.(link, card);
|
|
2393
|
+
} : void 0,
|
|
2394
|
+
onChip: (chip) => {
|
|
2395
|
+
runtime.emit({ type: "chip_tapped", key: conversation.key });
|
|
2396
|
+
chat.onChip?.(chip);
|
|
2397
|
+
}
|
|
2398
|
+
};
|
|
2399
|
+
const shared = {
|
|
2400
|
+
...chat,
|
|
2401
|
+
...events.onOpenTarget ? { onOpenTarget: events.onOpenTarget } : {},
|
|
2402
|
+
...events.onOpenLink ? { onOpenLink: events.onOpenLink } : {},
|
|
2403
|
+
onChip: events.onChip,
|
|
2404
|
+
...copy ? { copy } : {},
|
|
2405
|
+
...onContact && !chat.failureAction ? { failureAction: { onPress: () => onContact() } } : {},
|
|
2406
|
+
conversation: store,
|
|
2407
|
+
components: slots
|
|
2408
|
+
};
|
|
2409
|
+
if (state.failure === "ended")
|
|
2410
|
+
return /* @__PURE__ */ jsxRuntime.jsx(VinaverseChatProvider, { ...shared, children: /* @__PURE__ */ jsxRuntime.jsx(Centered, { children: Ended ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2411
|
+
Ended,
|
|
2412
|
+
{
|
|
2413
|
+
onStartNew: startNew,
|
|
2414
|
+
code: state.code,
|
|
2415
|
+
Default: DefaultEnded
|
|
2416
|
+
}
|
|
2417
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(DefaultEnded, { onStartNew: startNew, code: state.code }) }) });
|
|
2418
|
+
if (state.failure === "unreachable")
|
|
2419
|
+
return /* @__PURE__ */ jsxRuntime.jsx(VinaverseChatProvider, { ...shared, children: /* @__PURE__ */ jsxRuntime.jsx(Centered, { children: Unreachable ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2420
|
+
Unreachable,
|
|
2421
|
+
{
|
|
2422
|
+
onRetry: conversation.retry,
|
|
2423
|
+
reason: state.reason,
|
|
2424
|
+
Default: DefaultUnreachable
|
|
2425
|
+
}
|
|
2426
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2427
|
+
DefaultUnreachable,
|
|
2428
|
+
{
|
|
2429
|
+
onRetry: conversation.retry,
|
|
2430
|
+
reason: state.reason
|
|
2431
|
+
}
|
|
2432
|
+
) }) });
|
|
2433
|
+
if (state.failure === "unavailable") {
|
|
2434
|
+
const own = {
|
|
2435
|
+
reason: state.reason,
|
|
2436
|
+
code: state.code,
|
|
2437
|
+
onContact,
|
|
2438
|
+
onRetry: conversation.retry
|
|
2439
|
+
};
|
|
2440
|
+
return /* @__PURE__ */ jsxRuntime.jsx(VinaverseChatProvider, { ...shared, children: /* @__PURE__ */ jsxRuntime.jsx(Centered, { children: UnavailableScreen ? /* @__PURE__ */ jsxRuntime.jsx(UnavailableScreen, { ...own, Default: DefaultUnavailableScreen }) : /* @__PURE__ */ jsxRuntime.jsx(DefaultUnavailableScreen, { ...own }) }) });
|
|
2441
|
+
}
|
|
2442
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2443
|
+
VinaverseChat,
|
|
2444
|
+
{
|
|
2445
|
+
...shared,
|
|
2446
|
+
suggestion: opener && !spoke ? opener : state.moved && askAbout ? { label: askAbout, message: askAbout } : null,
|
|
2447
|
+
footer: Footer === null ? null : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2448
|
+
FooterFor,
|
|
2449
|
+
{
|
|
2450
|
+
store,
|
|
2451
|
+
state,
|
|
2452
|
+
rate: conversation.rate,
|
|
2453
|
+
Footer,
|
|
2454
|
+
onOpenPrivacy
|
|
2455
|
+
}
|
|
2456
|
+
)
|
|
2457
|
+
}
|
|
2458
|
+
);
|
|
2459
|
+
}
|
|
2460
|
+
function FooterFor(props) {
|
|
2461
|
+
const turnId = react$1.useConversationSelector(props.store, newestWholeReply);
|
|
2462
|
+
const own = {
|
|
2463
|
+
turnId,
|
|
2464
|
+
rating: turnId ? props.state.ratings.get(turnId) : void 0,
|
|
2465
|
+
onRate: (rating) => {
|
|
2466
|
+
if (turnId) props.rate(turnId, rating);
|
|
2467
|
+
},
|
|
2468
|
+
onOpenPrivacy: props.onOpenPrivacy
|
|
2469
|
+
};
|
|
2470
|
+
const { Footer } = props;
|
|
2471
|
+
return Footer ? /* @__PURE__ */ jsxRuntime.jsx(Footer, { ...own, Default: AgentFooter }) : /* @__PURE__ */ jsxRuntime.jsx(AgentFooter, { ...own });
|
|
2472
|
+
}
|
|
2473
|
+
function newestWholeReply(view) {
|
|
2474
|
+
for (let i = view.items.length - 1; i >= 0; i--) {
|
|
2475
|
+
const item = view.items[i];
|
|
2476
|
+
if (item?.type !== "message" || item.role !== "agent") continue;
|
|
2477
|
+
const whole = item.state === "sent" && !item.partial && !item.refusal && item.key.startsWith("a:");
|
|
2478
|
+
return whole ? item.key.slice(2) : null;
|
|
2479
|
+
}
|
|
2480
|
+
return null;
|
|
2481
|
+
}
|
|
2482
|
+
function Centered(props) {
|
|
2483
|
+
const { colors: colors2, space: space2 } = useTheme();
|
|
2484
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2485
|
+
reactNative.View,
|
|
2486
|
+
{
|
|
2487
|
+
style: {
|
|
2488
|
+
flex: 1,
|
|
2489
|
+
alignItems: "center",
|
|
2490
|
+
justifyContent: "center",
|
|
2491
|
+
padding: space2.xl,
|
|
2492
|
+
backgroundColor: colors2.background
|
|
2493
|
+
},
|
|
2494
|
+
children: props.children
|
|
2495
|
+
}
|
|
2496
|
+
);
|
|
2497
|
+
}
|
|
2498
|
+
function Notice(props) {
|
|
2499
|
+
const { colors: colors2, space: space2, font: font2 } = useTheme();
|
|
2500
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2501
|
+
reactNative.View,
|
|
2502
|
+
{
|
|
2503
|
+
accessibilityRole: "alert",
|
|
2504
|
+
style: { alignItems: "center", gap: space2.md },
|
|
2505
|
+
children: [
|
|
2506
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2507
|
+
reactNative.Text,
|
|
2508
|
+
{
|
|
2509
|
+
style: {
|
|
2510
|
+
color: colors2.text,
|
|
2511
|
+
fontSize: font2.size.lg,
|
|
2512
|
+
fontWeight: "600",
|
|
2513
|
+
textAlign: "center"
|
|
2514
|
+
},
|
|
2515
|
+
children: props.title
|
|
2516
|
+
}
|
|
2517
|
+
),
|
|
2518
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2519
|
+
reactNative.Text,
|
|
2520
|
+
{
|
|
2521
|
+
style: {
|
|
2522
|
+
color: colors2.textMuted,
|
|
2523
|
+
fontSize: font2.size.md,
|
|
2524
|
+
textAlign: "center"
|
|
2525
|
+
},
|
|
2526
|
+
children: props.body
|
|
2527
|
+
}
|
|
2528
|
+
),
|
|
2529
|
+
props.action && props.onPress ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2530
|
+
Button,
|
|
2531
|
+
{
|
|
2532
|
+
label: props.action,
|
|
2533
|
+
variant: "primary",
|
|
2534
|
+
onPress: props.onPress
|
|
2535
|
+
}
|
|
2536
|
+
) : null
|
|
2537
|
+
]
|
|
2538
|
+
}
|
|
2539
|
+
);
|
|
2540
|
+
}
|
|
2541
|
+
function DefaultEnded(props) {
|
|
2542
|
+
const { t } = react$1.useCopy();
|
|
2543
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2544
|
+
Notice,
|
|
2545
|
+
{
|
|
2546
|
+
title: t("agentEnded"),
|
|
2547
|
+
body: t("agentEndedBody"),
|
|
2548
|
+
action: t("agentStartOver"),
|
|
2549
|
+
onPress: props.onStartNew
|
|
2550
|
+
}
|
|
2551
|
+
);
|
|
2552
|
+
}
|
|
2553
|
+
function DefaultUnavailableScreen(props) {
|
|
2554
|
+
const { t } = react$1.useCopy();
|
|
2555
|
+
const name = agent.useAgentName(t("agentFallbackName"));
|
|
2556
|
+
const title = t("agentOff", { agent: name });
|
|
2557
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2558
|
+
Notice,
|
|
2559
|
+
{
|
|
2560
|
+
title: title.charAt(0).toUpperCase() + title.slice(1),
|
|
2561
|
+
body: t("agentOffBody"),
|
|
2562
|
+
...props.onContact ? { action: t("talkToPerson"), onPress: props.onContact } : {}
|
|
2563
|
+
}
|
|
2564
|
+
);
|
|
2565
|
+
}
|
|
2566
|
+
function DefaultUnreachable(props) {
|
|
2567
|
+
const { t } = react$1.useCopy();
|
|
2568
|
+
const name = agent.useAgentName(t("agentFallbackName"));
|
|
2569
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2570
|
+
Notice,
|
|
2571
|
+
{
|
|
2572
|
+
title: t("agentUnreachable", { agent: name }),
|
|
2573
|
+
body: t("agentUnreachableBody"),
|
|
2574
|
+
action: t("tryAgain"),
|
|
2575
|
+
onPress: props.onRetry
|
|
2576
|
+
}
|
|
2577
|
+
);
|
|
2578
|
+
}
|
|
2579
|
+
function AgentFooter(props) {
|
|
2580
|
+
const { t } = react$1.useCopy();
|
|
2581
|
+
const { colors: colors2, space: space2, font: font2 } = useTheme();
|
|
2582
|
+
const muted = { color: colors2.textMuted, fontSize: font2.size.sm };
|
|
2583
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2584
|
+
reactNative.View,
|
|
2585
|
+
{
|
|
2586
|
+
style: {
|
|
2587
|
+
flexDirection: "row",
|
|
2588
|
+
flexWrap: "wrap",
|
|
2589
|
+
alignItems: "center",
|
|
2590
|
+
gap: space2.xs,
|
|
2591
|
+
paddingHorizontal: space2.lg
|
|
2592
|
+
},
|
|
2593
|
+
children: [
|
|
2594
|
+
props.turnId === null ? null : props.rating ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: muted, children: t("helpfulThanks") }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2595
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: muted, children: t("helpful") }),
|
|
2596
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2597
|
+
Button,
|
|
2598
|
+
{
|
|
2599
|
+
label: t("helpfulYes"),
|
|
2600
|
+
variant: "text",
|
|
2601
|
+
onPress: () => props.onRate("up")
|
|
2602
|
+
}
|
|
2603
|
+
),
|
|
2604
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2605
|
+
Button,
|
|
2606
|
+
{
|
|
2607
|
+
label: t("helpfulNo"),
|
|
2608
|
+
variant: "text",
|
|
2609
|
+
onPress: () => props.onRate("down")
|
|
2610
|
+
}
|
|
2611
|
+
)
|
|
2612
|
+
] }),
|
|
2613
|
+
props.onOpenPrivacy ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2614
|
+
Button,
|
|
2615
|
+
{
|
|
2616
|
+
label: t("privacy"),
|
|
2617
|
+
variant: "text",
|
|
2618
|
+
role: "link",
|
|
2619
|
+
onPress: props.onOpenPrivacy
|
|
2620
|
+
}
|
|
2621
|
+
) : null
|
|
2622
|
+
]
|
|
2623
|
+
}
|
|
2624
|
+
);
|
|
2625
|
+
}
|
|
2626
|
+
var LAUNCHER_SIZE = 56;
|
|
2627
|
+
function AgentLauncher(props) {
|
|
2628
|
+
return /* @__PURE__ */ jsxRuntime.jsx(react$1.CopyProvider, { locale: props.locale, copy: props.copy, children: /* @__PURE__ */ jsxRuntime.jsx(ThemeProvider, { theme: props.theme, colorScheme: props.colorScheme, children: /* @__PURE__ */ jsxRuntime.jsx(Launcher, { ...props }) }) });
|
|
2629
|
+
}
|
|
2630
|
+
function useKeyboardShown() {
|
|
2631
|
+
const [shown, setShown] = react.useState(false);
|
|
2632
|
+
react.useEffect(() => {
|
|
2633
|
+
const show = reactNative.Keyboard.addListener("keyboardDidShow", () => setShown(true));
|
|
2634
|
+
const hide = reactNative.Keyboard.addListener("keyboardDidHide", () => setShown(false));
|
|
2635
|
+
return () => {
|
|
2636
|
+
show.remove();
|
|
2637
|
+
hide.remove();
|
|
2638
|
+
};
|
|
2639
|
+
}, []);
|
|
2640
|
+
return shown;
|
|
2641
|
+
}
|
|
2642
|
+
function Launcher(props) {
|
|
2643
|
+
const { t } = react$1.useCopy();
|
|
2644
|
+
const name = agent.useAgentName(t("agentFallbackName"));
|
|
2645
|
+
const keyboard = useKeyboardShown();
|
|
2646
|
+
const reducedMotion = useReducedMotion();
|
|
2647
|
+
const { route = null, routes, mode } = props;
|
|
2648
|
+
const visible = props.hidden !== true && !(keyboard && props.hideWithKeyboard !== false) && (!routes || route !== null && routes.includes(route));
|
|
2649
|
+
const launcher = agent.useAgentLauncher({
|
|
2650
|
+
subject: props.subject,
|
|
2651
|
+
mode,
|
|
2652
|
+
visible,
|
|
2653
|
+
onOpen: () => props.onOpen({ route, mode }),
|
|
2654
|
+
...props.storage ? { storage: props.storage } : {},
|
|
2655
|
+
...props.storageKey ? { storageKey: props.storageKey } : {},
|
|
2656
|
+
...props.delayMs === void 0 ? {} : { delayMs: props.delayMs }
|
|
2657
|
+
});
|
|
2658
|
+
const text = typeof props.greeting === "function" ? props.greeting(mode) : props.greeting ?? t("launcherGreeting", { agent: name });
|
|
2659
|
+
const say = props.announce ?? announce;
|
|
2660
|
+
const said = react.useRef(false);
|
|
2661
|
+
react.useEffect(() => {
|
|
2662
|
+
if (!launcher.greets) {
|
|
2663
|
+
said.current = false;
|
|
2664
|
+
return;
|
|
2665
|
+
}
|
|
2666
|
+
if (said.current) return;
|
|
2667
|
+
said.current = true;
|
|
2668
|
+
say(text);
|
|
2669
|
+
}, [launcher.greets, text, say]);
|
|
2670
|
+
if (!launcher.shows) return null;
|
|
2671
|
+
const edge = props.placement?.edge ?? "right";
|
|
2672
|
+
const look = props.appearance ?? {};
|
|
2673
|
+
const greeting = {
|
|
2674
|
+
text,
|
|
2675
|
+
closeLabel: t("close"),
|
|
2676
|
+
onOpen: launcher.open,
|
|
2677
|
+
onClose: launcher.dismiss,
|
|
2678
|
+
tail: look.tail !== false,
|
|
2679
|
+
edge
|
|
2680
|
+
};
|
|
2681
|
+
const button = {
|
|
2682
|
+
label: t("launcherOpen", { agent: name }),
|
|
2683
|
+
name,
|
|
2684
|
+
onPress: launcher.open,
|
|
2685
|
+
Mark: props.Mark,
|
|
2686
|
+
ring: look.ring ?? null,
|
|
2687
|
+
shadow: look.shadow !== false
|
|
2688
|
+
};
|
|
2689
|
+
const { Greeting, Button: Button3, Entrance } = props.components ?? {};
|
|
2690
|
+
const enter = (part, children) => Entrance ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2691
|
+
Entrance,
|
|
2692
|
+
{
|
|
2693
|
+
part,
|
|
2694
|
+
reducedMotion,
|
|
2695
|
+
Default: LauncherEntrance,
|
|
2696
|
+
children
|
|
2697
|
+
}
|
|
2698
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(LauncherEntrance, { part, reducedMotion, children });
|
|
2699
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2700
|
+
reactNative.View,
|
|
2701
|
+
{
|
|
2702
|
+
pointerEvents: "box-none",
|
|
2703
|
+
style: [
|
|
2704
|
+
{
|
|
2705
|
+
position: "absolute",
|
|
2706
|
+
bottom: props.placement?.bottom ?? 16,
|
|
2707
|
+
[edge]: props.placement?.inset ?? 16,
|
|
2708
|
+
alignItems: edge === "right" ? "flex-end" : "flex-start",
|
|
2709
|
+
gap: 8
|
|
2710
|
+
},
|
|
2711
|
+
props.style
|
|
2712
|
+
],
|
|
2713
|
+
testID: "vinaverse-launcher",
|
|
2714
|
+
children: [
|
|
2715
|
+
launcher.greets ? enter(
|
|
2716
|
+
"greeting",
|
|
2717
|
+
Greeting ? /* @__PURE__ */ jsxRuntime.jsx(Greeting, { ...greeting, Default: LauncherGreeting }) : /* @__PURE__ */ jsxRuntime.jsx(LauncherGreeting, { ...greeting })
|
|
2718
|
+
) : null,
|
|
2719
|
+
enter(
|
|
2720
|
+
"button",
|
|
2721
|
+
Button3 ? /* @__PURE__ */ jsxRuntime.jsx(Button3, { ...button, Default: LauncherButton }) : /* @__PURE__ */ jsxRuntime.jsx(LauncherButton, { ...button })
|
|
2722
|
+
)
|
|
2723
|
+
]
|
|
2724
|
+
}
|
|
2725
|
+
);
|
|
2726
|
+
}
|
|
2727
|
+
function LauncherEntrance(props) {
|
|
2728
|
+
const { motion: motion3 } = useTheme();
|
|
2729
|
+
const shown = react.useRef(new reactNative.Animated.Value(props.reducedMotion ? 1 : 0)).current;
|
|
2730
|
+
react.useEffect(() => {
|
|
2731
|
+
if (props.reducedMotion) {
|
|
2732
|
+
shown.setValue(1);
|
|
2733
|
+
return;
|
|
2734
|
+
}
|
|
2735
|
+
const run = reactNative.Animated.timing(shown, {
|
|
2736
|
+
toValue: 1,
|
|
2737
|
+
duration: motion3.normal,
|
|
2738
|
+
useNativeDriver: true
|
|
2739
|
+
});
|
|
2740
|
+
run.start();
|
|
2741
|
+
return () => run.stop();
|
|
2742
|
+
}, [shown, props.reducedMotion, motion3.normal]);
|
|
2743
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2744
|
+
reactNative.Animated.View,
|
|
2745
|
+
{
|
|
2746
|
+
pointerEvents: "box-none",
|
|
2747
|
+
style: {
|
|
2748
|
+
opacity: shown,
|
|
2749
|
+
transform: [
|
|
2750
|
+
{
|
|
2751
|
+
scale: shown.interpolate({
|
|
2752
|
+
inputRange: [0, 1],
|
|
2753
|
+
outputRange: [0.9, 1]
|
|
2754
|
+
})
|
|
2755
|
+
}
|
|
2756
|
+
]
|
|
2757
|
+
},
|
|
2758
|
+
testID: `vinaverse-launcher-entrance-${props.part}`,
|
|
2759
|
+
children: props.children
|
|
2760
|
+
}
|
|
2761
|
+
);
|
|
2762
|
+
}
|
|
2763
|
+
function LauncherGreeting(props) {
|
|
2764
|
+
const { colors: colors2, radius: radius2, space: space2, font: font2 } = useTheme();
|
|
2765
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2766
|
+
reactNative.View,
|
|
2767
|
+
{
|
|
2768
|
+
style: {
|
|
2769
|
+
maxWidth: 296,
|
|
2770
|
+
flexDirection: "row",
|
|
2771
|
+
alignItems: "flex-start",
|
|
2772
|
+
borderRadius: radius2.lg,
|
|
2773
|
+
backgroundColor: colors2.text
|
|
2774
|
+
},
|
|
2775
|
+
testID: "vinaverse-launcher-greeting",
|
|
2776
|
+
children: [
|
|
2777
|
+
props.tail ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2778
|
+
reactNative.View,
|
|
2779
|
+
{
|
|
2780
|
+
accessible: false,
|
|
2781
|
+
style: {
|
|
2782
|
+
position: "absolute",
|
|
2783
|
+
bottom: -5,
|
|
2784
|
+
[props.edge]: LAUNCHER_SIZE / 2 - 6,
|
|
2785
|
+
width: 12,
|
|
2786
|
+
height: 12,
|
|
2787
|
+
backgroundColor: colors2.text,
|
|
2788
|
+
transform: [{ rotate: "45deg" }]
|
|
2789
|
+
},
|
|
2790
|
+
testID: "vinaverse-launcher-tail"
|
|
2791
|
+
}
|
|
2792
|
+
) : null,
|
|
2793
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2794
|
+
reactNative.Pressable,
|
|
2795
|
+
{
|
|
2796
|
+
accessibilityRole: "button",
|
|
2797
|
+
accessibilityLabel: props.text,
|
|
2798
|
+
onPress: props.onOpen,
|
|
2799
|
+
style: {
|
|
2800
|
+
flexShrink: 1,
|
|
2801
|
+
paddingVertical: space2.sm,
|
|
2802
|
+
paddingLeft: space2.md
|
|
2803
|
+
},
|
|
2804
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: colors2.background, fontSize: font2.size.md }, children: props.text })
|
|
2805
|
+
}
|
|
2806
|
+
),
|
|
2807
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2808
|
+
reactNative.Pressable,
|
|
2809
|
+
{
|
|
2810
|
+
accessibilityRole: "button",
|
|
2811
|
+
accessibilityLabel: props.closeLabel,
|
|
2812
|
+
onPress: props.onClose,
|
|
2813
|
+
style: {
|
|
2814
|
+
minWidth: 44,
|
|
2815
|
+
minHeight: 44,
|
|
2816
|
+
alignItems: "center",
|
|
2817
|
+
justifyContent: "center"
|
|
2818
|
+
},
|
|
2819
|
+
testID: "vinaverse-launcher-close",
|
|
2820
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: colors2.background, fontSize: font2.size.md }, children: "\xD7" })
|
|
2821
|
+
}
|
|
2822
|
+
)
|
|
2823
|
+
]
|
|
2824
|
+
}
|
|
2825
|
+
);
|
|
2826
|
+
}
|
|
2827
|
+
function LauncherButton(props) {
|
|
2828
|
+
const { colors: colors2, font: font2 } = useTheme();
|
|
2829
|
+
const { Mark, ring } = props;
|
|
2830
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2831
|
+
reactNative.Pressable,
|
|
2832
|
+
{
|
|
2833
|
+
accessibilityRole: "button",
|
|
2834
|
+
accessibilityLabel: props.label,
|
|
2835
|
+
onPress: props.onPress,
|
|
2836
|
+
style: ({ pressed }) => ({
|
|
2837
|
+
width: LAUNCHER_SIZE,
|
|
2838
|
+
height: LAUNCHER_SIZE,
|
|
2839
|
+
borderRadius: LAUNCHER_SIZE / 2,
|
|
2840
|
+
alignItems: "center",
|
|
2841
|
+
justifyContent: "center",
|
|
2842
|
+
backgroundColor: colors2.primary,
|
|
2843
|
+
opacity: pressed ? 0.85 : 1,
|
|
2844
|
+
...ring ? { borderWidth: ring.width, borderColor: ring.color } : {},
|
|
2845
|
+
...props.shadow ? {
|
|
2846
|
+
elevation: 6,
|
|
2847
|
+
shadowColor: "#000",
|
|
2848
|
+
shadowOpacity: 0.2,
|
|
2849
|
+
shadowRadius: 8,
|
|
2850
|
+
shadowOffset: { width: 0, height: 3 }
|
|
2851
|
+
} : {}
|
|
2852
|
+
}),
|
|
2853
|
+
testID: "vinaverse-launcher-button",
|
|
2854
|
+
children: Mark ? /* @__PURE__ */ jsxRuntime.jsx(Mark, { size: 34, color: colors2.onPrimary }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2855
|
+
reactNative.Text,
|
|
2856
|
+
{
|
|
2857
|
+
style: {
|
|
2858
|
+
color: colors2.onPrimary,
|
|
2859
|
+
fontSize: font2.size.lg,
|
|
2860
|
+
fontWeight: "600"
|
|
2861
|
+
},
|
|
2862
|
+
children: (props.name.trim()[0] ?? "?").toUpperCase()
|
|
2863
|
+
}
|
|
2864
|
+
)
|
|
2865
|
+
}
|
|
2866
|
+
);
|
|
2867
|
+
}
|
|
2868
|
+
function AskAboutRow(props) {
|
|
2869
|
+
return /* @__PURE__ */ jsxRuntime.jsx(react$1.CopyProvider, { locale: props.locale, copy: props.copy, children: /* @__PURE__ */ jsxRuntime.jsx(ThemeProvider, { theme: props.theme, colorScheme: props.colorScheme, children: /* @__PURE__ */ jsxRuntime.jsx(Row3, { ...props }) }) });
|
|
2870
|
+
}
|
|
2871
|
+
function Row3(props) {
|
|
2872
|
+
const { t } = react$1.useCopy();
|
|
2873
|
+
const { colors: colors2, radius: radius2, space: space2, font: font2 } = useTheme();
|
|
2874
|
+
const name = agent.useAgentName(t("agentFallbackName"));
|
|
2875
|
+
const { available } = agent.useAgentFeatures();
|
|
2876
|
+
const [shows, setShows] = react.useState(null);
|
|
2877
|
+
if (shows === null && available) setShows(true);
|
|
2878
|
+
if (!shows) return null;
|
|
2879
|
+
const { Mark } = props;
|
|
2880
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2881
|
+
reactNative.Pressable,
|
|
2882
|
+
{
|
|
2883
|
+
accessibilityRole: "button",
|
|
2884
|
+
accessibilityLabel: props.body ? `${props.title}. ${props.body}` : props.title,
|
|
2885
|
+
onPress: props.onPress,
|
|
2886
|
+
style: ({ pressed }) => ({
|
|
2887
|
+
flexDirection: "row",
|
|
2888
|
+
alignItems: "center",
|
|
2889
|
+
gap: space2.md,
|
|
2890
|
+
padding: space2.md,
|
|
2891
|
+
borderRadius: radius2.lg,
|
|
2892
|
+
backgroundColor: colors2.surface,
|
|
2893
|
+
opacity: pressed ? 0.85 : 1
|
|
2894
|
+
}),
|
|
2895
|
+
testID: "vinaverse-ask-about",
|
|
2896
|
+
children: [
|
|
2897
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2898
|
+
reactNative.View,
|
|
2899
|
+
{
|
|
2900
|
+
style: {
|
|
2901
|
+
width: 36,
|
|
2902
|
+
height: 36,
|
|
2903
|
+
borderRadius: 18,
|
|
2904
|
+
alignItems: "center",
|
|
2905
|
+
justifyContent: "center",
|
|
2906
|
+
backgroundColor: colors2.primary
|
|
2907
|
+
},
|
|
2908
|
+
children: Mark ? /* @__PURE__ */ jsxRuntime.jsx(Mark, { size: 22, color: colors2.onPrimary }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: colors2.onPrimary, fontWeight: "600" }, children: (name.trim()[0] ?? "?").toUpperCase() })
|
|
2909
|
+
}
|
|
2910
|
+
),
|
|
2911
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { flex: 1, gap: space2.xxs }, children: [
|
|
2912
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2913
|
+
reactNative.Text,
|
|
2914
|
+
{
|
|
2915
|
+
style: {
|
|
2916
|
+
color: colors2.text,
|
|
2917
|
+
fontSize: font2.size.md,
|
|
2918
|
+
fontWeight: "600"
|
|
2919
|
+
},
|
|
2920
|
+
children: props.title
|
|
2921
|
+
}
|
|
2922
|
+
),
|
|
2923
|
+
props.body ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: colors2.textMuted, fontSize: font2.size.sm }, children: props.body }) : null
|
|
2924
|
+
] }),
|
|
2925
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: colors2.textMuted, fontSize: font2.size.lg }, children: "\u203A" })
|
|
2926
|
+
]
|
|
2927
|
+
}
|
|
2928
|
+
);
|
|
2929
|
+
}
|
|
2255
2930
|
|
|
2931
|
+
Object.defineProperty(exports, "AgentRuntimeProvider", {
|
|
2932
|
+
enumerable: true,
|
|
2933
|
+
get: function () { return agent.AgentRuntimeProvider; }
|
|
2934
|
+
});
|
|
2935
|
+
Object.defineProperty(exports, "greetedKey", {
|
|
2936
|
+
enumerable: true,
|
|
2937
|
+
get: function () { return agent.greetedKey; }
|
|
2938
|
+
});
|
|
2939
|
+
Object.defineProperty(exports, "useAgentConversation", {
|
|
2940
|
+
enumerable: true,
|
|
2941
|
+
get: function () { return agent.useAgentConversation; }
|
|
2942
|
+
});
|
|
2943
|
+
Object.defineProperty(exports, "useAgentFeatures", {
|
|
2944
|
+
enumerable: true,
|
|
2945
|
+
get: function () { return agent.useAgentFeatures; }
|
|
2946
|
+
});
|
|
2947
|
+
Object.defineProperty(exports, "useAgentLauncher", {
|
|
2948
|
+
enumerable: true,
|
|
2949
|
+
get: function () { return agent.useAgentLauncher; }
|
|
2950
|
+
});
|
|
2951
|
+
Object.defineProperty(exports, "useAgentName", {
|
|
2952
|
+
enumerable: true,
|
|
2953
|
+
get: function () { return agent.useAgentName; }
|
|
2954
|
+
});
|
|
2955
|
+
Object.defineProperty(exports, "useAgentProfile", {
|
|
2956
|
+
enumerable: true,
|
|
2957
|
+
get: function () { return agent.useAgentProfile; }
|
|
2958
|
+
});
|
|
2959
|
+
Object.defineProperty(exports, "useAgentRuntime", {
|
|
2960
|
+
enumerable: true,
|
|
2961
|
+
get: function () { return agent.useAgentRuntime; }
|
|
2962
|
+
});
|
|
2963
|
+
Object.defineProperty(exports, "useAgentStatus", {
|
|
2964
|
+
enumerable: true,
|
|
2965
|
+
get: function () { return agent.useAgentStatus; }
|
|
2966
|
+
});
|
|
2256
2967
|
exports.ActivityLine = ActivityLine;
|
|
2968
|
+
exports.AgentChat = AgentChat;
|
|
2969
|
+
exports.AgentFooter = AgentFooter;
|
|
2970
|
+
exports.AgentLauncher = AgentLauncher;
|
|
2971
|
+
exports.AskAboutRow = AskAboutRow;
|
|
2257
2972
|
exports.Avatar = Avatar;
|
|
2258
2973
|
exports.Button = Button;
|
|
2259
2974
|
exports.CardActions = CardActions;
|
|
@@ -2265,12 +2980,19 @@ exports.ChatSkeleton = ChatSkeleton;
|
|
|
2265
2980
|
exports.Composer = Composer;
|
|
2266
2981
|
exports.DefaultBubble = DefaultBubble;
|
|
2267
2982
|
exports.DefaultComposer = DefaultComposer;
|
|
2983
|
+
exports.DefaultEnded = DefaultEnded;
|
|
2268
2984
|
exports.DefaultHeader = DefaultHeader;
|
|
2269
2985
|
exports.DefaultTurnFailed = DefaultTurnFailed;
|
|
2270
2986
|
exports.DefaultUnavailable = DefaultUnavailable;
|
|
2987
|
+
exports.DefaultUnavailableScreen = DefaultUnavailableScreen;
|
|
2988
|
+
exports.DefaultUnreachable = DefaultUnreachable;
|
|
2271
2989
|
exports.DisclosureBar = DisclosureBar;
|
|
2272
2990
|
exports.FailureActionButton = FailureActionButton;
|
|
2273
2991
|
exports.InfoCard = InfoCard;
|
|
2992
|
+
exports.LAUNCHER_SIZE = LAUNCHER_SIZE;
|
|
2993
|
+
exports.LauncherButton = LauncherButton;
|
|
2994
|
+
exports.LauncherEntrance = LauncherEntrance;
|
|
2995
|
+
exports.LauncherGreeting = LauncherGreeting;
|
|
2274
2996
|
exports.LinksCard = LinksCard;
|
|
2275
2997
|
exports.ListingCard = ListingCard;
|
|
2276
2998
|
exports.MessageBubble = MessageBubble;
|
|
@@ -2287,6 +3009,7 @@ exports.TimeSlotsCard = TimeSlotsCard;
|
|
|
2287
3009
|
exports.VinaverseChat = VinaverseChat;
|
|
2288
3010
|
exports.VinaverseChatProvider = VinaverseChatProvider;
|
|
2289
3011
|
exports.Welcome = Welcome;
|
|
3012
|
+
exports.allowedImage = allowedImage;
|
|
2290
3013
|
exports.announce = announce;
|
|
2291
3014
|
exports.answerText = answerText;
|
|
2292
3015
|
exports.carousels = carousels;
|
|
@@ -2295,9 +3018,11 @@ exports.defaultCard = defaultCard;
|
|
|
2295
3018
|
exports.fieldText = fieldText;
|
|
2296
3019
|
exports.itemType = itemType;
|
|
2297
3020
|
exports.monogram = monogram;
|
|
3021
|
+
exports.newestWholeReply = newestWholeReply;
|
|
2298
3022
|
exports.ratingText = ratingText;
|
|
2299
3023
|
exports.themeProblems = themeProblems;
|
|
2300
3024
|
exports.useChat = useChat;
|
|
3025
|
+
exports.useKeyboardShown = useKeyboardShown;
|
|
2301
3026
|
exports.useNativeLifecycle = useNativeLifecycle;
|
|
2302
3027
|
exports.useReducedMotion = useReducedMotion;
|
|
2303
3028
|
exports.useTheme = useTheme;
|