@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.cjs
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var agent = require('@vinaverse/react/agent');
|
|
4
|
+
var flashList = require('@shopify/flash-list');
|
|
5
|
+
var react$1 = require('@vinaverse/react');
|
|
3
6
|
var reactNative = require('react-native');
|
|
7
|
+
var agent$1 = require('@vinaverse/client/agent');
|
|
4
8
|
var react = require('react');
|
|
5
9
|
var jsxRuntime = require('react/jsx-runtime');
|
|
6
10
|
var tokens = require('@vinaverse/tokens');
|
|
7
|
-
var react$1 = require('@vinaverse/react');
|
|
8
11
|
var conversation = require('@vinaverse/client/conversation');
|
|
9
|
-
var flashList = require('@shopify/flash-list');
|
|
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 });
|
|
@@ -57,6 +59,61 @@ function ThemeProvider(props) {
|
|
|
57
59
|
function useTheme() {
|
|
58
60
|
return react.useContext(ThemeContext);
|
|
59
61
|
}
|
|
62
|
+
var Button = react.memo(function Button2(props) {
|
|
63
|
+
const { colors: colors2, radius: radius2, space: space2, size: size3, font: font2 } = useTheme();
|
|
64
|
+
const variant = props.variant ?? "secondary";
|
|
65
|
+
const inactive = props.disabled === true || props.busy === true;
|
|
66
|
+
const filled = variant === "primary" || props.selected === true;
|
|
67
|
+
const background = filled ? colors2.primary : variant === "secondary" ? colors2.surface : "transparent";
|
|
68
|
+
const foreground = filled ? colors2.onPrimary : colors2.primary;
|
|
69
|
+
const checkable = props.role === "radio" || props.role === "checkbox";
|
|
70
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
71
|
+
reactNative.Pressable,
|
|
72
|
+
{
|
|
73
|
+
accessibilityRole: props.role ?? "button",
|
|
74
|
+
accessibilityLabel: props.label,
|
|
75
|
+
...props.hint ? { accessibilityHint: props.hint } : {},
|
|
76
|
+
accessibilityState: {
|
|
77
|
+
disabled: inactive,
|
|
78
|
+
busy: props.busy === true,
|
|
79
|
+
...checkable ? props.role === "radio" ? { selected: props.selected === true } : { checked: props.selected === true } : {}
|
|
80
|
+
},
|
|
81
|
+
disabled: inactive,
|
|
82
|
+
onPress: props.onPress,
|
|
83
|
+
...props.testID ? { testID: props.testID } : {},
|
|
84
|
+
style: ({ pressed }) => ({
|
|
85
|
+
minHeight: size3.touchTarget,
|
|
86
|
+
minWidth: size3.touchTarget,
|
|
87
|
+
paddingHorizontal: space2.md,
|
|
88
|
+
paddingVertical: space2.sm,
|
|
89
|
+
borderRadius: radius2.md,
|
|
90
|
+
borderWidth: variant === "text" ? 0 : 1,
|
|
91
|
+
borderColor: filled ? colors2.primary : colors2.border,
|
|
92
|
+
backgroundColor: background,
|
|
93
|
+
opacity: inactive ? 0.55 : pressed ? 0.8 : 1,
|
|
94
|
+
alignItems: "center",
|
|
95
|
+
justifyContent: "center",
|
|
96
|
+
flexDirection: "row",
|
|
97
|
+
gap: space2.xs
|
|
98
|
+
}),
|
|
99
|
+
children: [
|
|
100
|
+
props.busy ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: foreground }) : null,
|
|
101
|
+
props.children ?? /* @__PURE__ */ jsxRuntime.jsx(
|
|
102
|
+
reactNative.Text,
|
|
103
|
+
{
|
|
104
|
+
style: {
|
|
105
|
+
color: foreground,
|
|
106
|
+
fontSize: font2.size.md,
|
|
107
|
+
fontWeight: "500",
|
|
108
|
+
...font2.family ? { fontFamily: font2.family } : {}
|
|
109
|
+
},
|
|
110
|
+
children: props.label
|
|
111
|
+
}
|
|
112
|
+
)
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
);
|
|
116
|
+
});
|
|
60
117
|
function cardOf(held) {
|
|
61
118
|
return held.card;
|
|
62
119
|
}
|
|
@@ -125,64 +182,26 @@ function useLink(link, held) {
|
|
|
125
182
|
if (!link || !store.checkLink(link)) return null;
|
|
126
183
|
return () => handlers.current?.onOpenLink?.(link, held);
|
|
127
184
|
}
|
|
185
|
+
function ratingText(valuePpm, locale) {
|
|
186
|
+
const value = valuePpm / 1e6;
|
|
187
|
+
try {
|
|
188
|
+
return new Intl.NumberFormat(locale, {
|
|
189
|
+
minimumFractionDigits: 1,
|
|
190
|
+
maximumFractionDigits: 1
|
|
191
|
+
}).format(value);
|
|
192
|
+
} catch {
|
|
193
|
+
return value.toFixed(1);
|
|
194
|
+
}
|
|
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
|
+
}
|
|
128
202
|
function safeImage(url) {
|
|
129
203
|
return url && /^https:\/\//i.test(url) ? url : null;
|
|
130
204
|
}
|
|
131
|
-
var Button = react.memo(function Button2(props) {
|
|
132
|
-
const { colors: colors2, radius: radius2, space: space2, size: size3, font: font2 } = useTheme();
|
|
133
|
-
const variant = props.variant ?? "secondary";
|
|
134
|
-
const inactive = props.disabled === true || props.busy === true;
|
|
135
|
-
const filled = variant === "primary" || props.selected === true;
|
|
136
|
-
const background = filled ? colors2.primary : variant === "secondary" ? colors2.surface : "transparent";
|
|
137
|
-
const foreground = filled ? colors2.onPrimary : colors2.primary;
|
|
138
|
-
const checkable = props.role === "radio" || props.role === "checkbox";
|
|
139
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
140
|
-
reactNative.Pressable,
|
|
141
|
-
{
|
|
142
|
-
accessibilityRole: props.role ?? "button",
|
|
143
|
-
accessibilityLabel: props.label,
|
|
144
|
-
...props.hint ? { accessibilityHint: props.hint } : {},
|
|
145
|
-
accessibilityState: {
|
|
146
|
-
disabled: inactive,
|
|
147
|
-
busy: props.busy === true,
|
|
148
|
-
...checkable ? props.role === "radio" ? { selected: props.selected === true } : { checked: props.selected === true } : {}
|
|
149
|
-
},
|
|
150
|
-
disabled: inactive,
|
|
151
|
-
onPress: props.onPress,
|
|
152
|
-
...props.testID ? { testID: props.testID } : {},
|
|
153
|
-
style: ({ pressed }) => ({
|
|
154
|
-
minHeight: size3.touchTarget,
|
|
155
|
-
minWidth: size3.touchTarget,
|
|
156
|
-
paddingHorizontal: space2.md,
|
|
157
|
-
paddingVertical: space2.sm,
|
|
158
|
-
borderRadius: radius2.md,
|
|
159
|
-
borderWidth: variant === "text" ? 0 : 1,
|
|
160
|
-
borderColor: filled ? colors2.primary : colors2.border,
|
|
161
|
-
backgroundColor: background,
|
|
162
|
-
opacity: inactive ? 0.55 : pressed ? 0.8 : 1,
|
|
163
|
-
alignItems: "center",
|
|
164
|
-
justifyContent: "center",
|
|
165
|
-
flexDirection: "row",
|
|
166
|
-
gap: space2.xs
|
|
167
|
-
}),
|
|
168
|
-
children: [
|
|
169
|
-
props.busy ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: foreground }) : null,
|
|
170
|
-
props.children ?? /* @__PURE__ */ jsxRuntime.jsx(
|
|
171
|
-
reactNative.Text,
|
|
172
|
-
{
|
|
173
|
-
style: {
|
|
174
|
-
color: foreground,
|
|
175
|
-
fontSize: font2.size.md,
|
|
176
|
-
fontWeight: "500",
|
|
177
|
-
...font2.family ? { fontFamily: font2.family } : {}
|
|
178
|
-
},
|
|
179
|
-
children: props.label
|
|
180
|
-
}
|
|
181
|
-
)
|
|
182
|
-
]
|
|
183
|
-
}
|
|
184
|
-
);
|
|
185
|
-
});
|
|
186
205
|
function InfoCard(props) {
|
|
187
206
|
const card = cardOf(props.card);
|
|
188
207
|
const { locale, t } = react$1.useCopy();
|
|
@@ -191,7 +210,7 @@ function InfoCard(props) {
|
|
|
191
210
|
const image = safeImage(card.image_url);
|
|
192
211
|
const Img = slots.Image ?? reactNative.Image;
|
|
193
212
|
const money = card.price ?? card.price_from;
|
|
194
|
-
const rating = card.rating ? (card.rating.value_ppm
|
|
213
|
+
const rating = card.rating ? ratingText(card.rating.value_ppm, locale) : null;
|
|
195
214
|
const amount = money ? react$1.formatMoney(money.amount, money.currency, locale) : null;
|
|
196
215
|
const price = amount && !card.price ? t("priceFrom", { price: amount }) : amount;
|
|
197
216
|
const when = card.starts_at ? react$1.formatTimeRange(card.starts_at, void 0, locale, timeZone) : null;
|
|
@@ -234,27 +253,32 @@ function InfoCard(props) {
|
|
|
234
253
|
] })
|
|
235
254
|
] }),
|
|
236
255
|
card.body ? /* @__PURE__ */ jsxRuntime.jsx(Body, { children: card.body }) : null,
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
{
|
|
240
|
-
style: {
|
|
241
|
-
color: colors2.text,
|
|
242
|
-
backgroundColor: colors2.surface,
|
|
243
|
-
borderRadius: radius2.pill,
|
|
244
|
-
paddingHorizontal: space2.sm,
|
|
245
|
-
paddingVertical: space2.xxs,
|
|
246
|
-
fontSize: font2.size.xs
|
|
247
|
-
},
|
|
248
|
-
children: b
|
|
249
|
-
},
|
|
250
|
-
b
|
|
251
|
-
)) }) : null,
|
|
252
|
-
props.restored ? null : /* @__PURE__ */ jsxRuntime.jsx(Actions, { ...props })
|
|
256
|
+
/* @__PURE__ */ jsxRuntime.jsx(Badges, { badges: card.badges }),
|
|
257
|
+
props.restored ? null : /* @__PURE__ */ jsxRuntime.jsx(CardActions, { ...props })
|
|
253
258
|
]
|
|
254
259
|
}
|
|
255
260
|
);
|
|
256
261
|
}
|
|
257
|
-
function
|
|
262
|
+
function Badges(props) {
|
|
263
|
+
const { colors: colors2, radius: radius2, space: space2, font: font2 } = useTheme();
|
|
264
|
+
if (!props.badges?.length) return null;
|
|
265
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { flexDirection: "row", flexWrap: "wrap", gap: space2.xs }, children: props.badges.map((b) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
266
|
+
reactNative.Text,
|
|
267
|
+
{
|
|
268
|
+
style: {
|
|
269
|
+
color: colors2.text,
|
|
270
|
+
backgroundColor: colors2.surface,
|
|
271
|
+
borderRadius: radius2.pill,
|
|
272
|
+
paddingHorizontal: space2.sm,
|
|
273
|
+
paddingVertical: space2.xxs,
|
|
274
|
+
fontSize: font2.size.xs
|
|
275
|
+
},
|
|
276
|
+
children: b
|
|
277
|
+
},
|
|
278
|
+
b
|
|
279
|
+
)) });
|
|
280
|
+
}
|
|
281
|
+
function CardActions(props) {
|
|
258
282
|
const card = cardOf(props.card);
|
|
259
283
|
const { space: space2 } = useTheme();
|
|
260
284
|
if (!card.actions?.length) return null;
|
|
@@ -286,6 +310,139 @@ function Action(props) {
|
|
|
286
310
|
}
|
|
287
311
|
);
|
|
288
312
|
}
|
|
313
|
+
function LinksCard(props) {
|
|
314
|
+
const card = cardOf(props.card);
|
|
315
|
+
const { store, handlers } = useChat();
|
|
316
|
+
const links = (card.links ?? []).filter(
|
|
317
|
+
(l) => /^https:\/\//i.test(l.url) || store.checkLink(l.url)
|
|
318
|
+
);
|
|
319
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
320
|
+
CardFrame,
|
|
321
|
+
{
|
|
322
|
+
label: [card.title, ...links.map((l) => l.label)].join(", "),
|
|
323
|
+
restored: props.restored,
|
|
324
|
+
testID: `vinaverse-card-${card.id}`,
|
|
325
|
+
children: [
|
|
326
|
+
/* @__PURE__ */ jsxRuntime.jsx(Title, { children: card.title }),
|
|
327
|
+
links.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
328
|
+
Button,
|
|
329
|
+
{
|
|
330
|
+
label: l.label,
|
|
331
|
+
role: "link",
|
|
332
|
+
variant: "secondary",
|
|
333
|
+
disabled: props.restored,
|
|
334
|
+
onPress: () => {
|
|
335
|
+
const open = handlers.current?.onOpenLink;
|
|
336
|
+
if (open) open(l.url, props.card);
|
|
337
|
+
else void reactNative.Linking.openURL(l.url);
|
|
338
|
+
}
|
|
339
|
+
},
|
|
340
|
+
l.url
|
|
341
|
+
))
|
|
342
|
+
]
|
|
343
|
+
}
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
function ListingCard(props) {
|
|
347
|
+
const card = cardOf(props.card);
|
|
348
|
+
const { locale, t } = react$1.useCopy();
|
|
349
|
+
const { slots, timeZone, handlers, imagePolicy } = useChat();
|
|
350
|
+
const { colors: colors2, radius: radius2, space: space2, font: font2 } = useTheme();
|
|
351
|
+
const [failed, setFailed] = react.useState(null);
|
|
352
|
+
const photoUrl = allowedImage(
|
|
353
|
+
card.images?.[0]?.url ?? card.image_url,
|
|
354
|
+
imagePolicy?.hosts
|
|
355
|
+
);
|
|
356
|
+
const hero = photoUrl === failed ? null : photoUrl;
|
|
357
|
+
const Img = slots.Image ?? reactNative.Image;
|
|
358
|
+
const rating = card.rating ? `\u2605 ${ratingText(card.rating.value_ppm, locale)} (${card.rating.count})` : null;
|
|
359
|
+
const price = card.price_from ? t("priceFrom", {
|
|
360
|
+
price: react$1.formatMoney(
|
|
361
|
+
card.price_from.amount,
|
|
362
|
+
card.price_from.currency,
|
|
363
|
+
locale
|
|
364
|
+
)
|
|
365
|
+
}) : null;
|
|
366
|
+
const next = card.next_available ? t("nextAvailable", {
|
|
367
|
+
time: react$1.formatTimeRange(card.next_available, void 0, locale, timeZone)
|
|
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;
|
|
372
|
+
const photo = {
|
|
373
|
+
width: "100%",
|
|
374
|
+
aspectRatio: imagePolicy?.aspectRatio ?? 1.6,
|
|
375
|
+
borderRadius: radius2.md
|
|
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
|
+
] });
|
|
418
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
419
|
+
CardFrame,
|
|
420
|
+
{
|
|
421
|
+
label: [card.title, card.subtitle, rating, price, next].filter(Boolean).join(", "),
|
|
422
|
+
restored: props.restored,
|
|
423
|
+
testID: `vinaverse-card-${card.id}`,
|
|
424
|
+
children: [
|
|
425
|
+
open ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
426
|
+
reactNative.Pressable,
|
|
427
|
+
{
|
|
428
|
+
accessibilityRole: "link",
|
|
429
|
+
accessibilityLabel: card.title,
|
|
430
|
+
onPress: open,
|
|
431
|
+
style: { gap: space2.sm },
|
|
432
|
+
testID: `vinaverse-open-${card.id}`,
|
|
433
|
+
children: top
|
|
434
|
+
}
|
|
435
|
+
) : top,
|
|
436
|
+
card.body ? /* @__PURE__ */ jsxRuntime.jsx(Body, { children: card.body }) : null,
|
|
437
|
+
/* @__PURE__ */ jsxRuntime.jsx(Badges, { badges: next ? [next, ...card.badges ?? []] : card.badges }),
|
|
438
|
+
props.restored ? null : /* @__PURE__ */ jsxRuntime.jsx(CardActions, { ...props })
|
|
439
|
+
]
|
|
440
|
+
}
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
function monogram(title) {
|
|
444
|
+
return title.split(/\s+/).filter(Boolean).slice(0, 2).map((w) => [...w][0]?.toUpperCase() ?? "").join("");
|
|
445
|
+
}
|
|
289
446
|
function NextStepCard(props) {
|
|
290
447
|
const card = cardOf(props.card);
|
|
291
448
|
const action = card.actions?.[0];
|
|
@@ -1154,7 +1311,10 @@ var DEFAULTS = {
|
|
|
1154
1311
|
proposal: ProposalCard,
|
|
1155
1312
|
question: QuestionCard,
|
|
1156
1313
|
next_step: NextStepCard,
|
|
1157
|
-
time_slots: TimeSlotsCard
|
|
1314
|
+
time_slots: TimeSlotsCard,
|
|
1315
|
+
professional: ListingCard,
|
|
1316
|
+
workspace: ListingCard,
|
|
1317
|
+
links: LinksCard
|
|
1158
1318
|
};
|
|
1159
1319
|
function defaultCard(kind) {
|
|
1160
1320
|
return DEFAULTS[kind] ?? InfoCard;
|
|
@@ -1164,9 +1324,39 @@ var CardView = react.memo(function CardView2(props) {
|
|
|
1164
1324
|
const { card, busy } = props.item;
|
|
1165
1325
|
const Default = defaultCard(card.kind);
|
|
1166
1326
|
const Custom = slots.cards?.[card.kind];
|
|
1167
|
-
const
|
|
1327
|
+
const read = react.useMemo(() => agent$1.readCard(card.card), [card]);
|
|
1328
|
+
const own = { card, read, busy, restored: props.item.restored === true };
|
|
1168
1329
|
return Custom ? /* @__PURE__ */ jsxRuntime.jsx(Custom, { ...own, Default }) : /* @__PURE__ */ jsxRuntime.jsx(Default, { ...own });
|
|
1169
1330
|
});
|
|
1331
|
+
var keyOf = (item) => item.key;
|
|
1332
|
+
var kindOf = (item) => item.card.kind;
|
|
1333
|
+
function CardCarousel(props) {
|
|
1334
|
+
const { width } = reactNative.useWindowDimensions();
|
|
1335
|
+
const { t } = react$1.useCopy();
|
|
1336
|
+
const size3 = Math.min(Math.round(width * 0.8), 360);
|
|
1337
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1338
|
+
reactNative.View,
|
|
1339
|
+
{
|
|
1340
|
+
accessibilityRole: "list",
|
|
1341
|
+
accessibilityLabel: t("cardsInRow", {
|
|
1342
|
+
count: String(props.items.length)
|
|
1343
|
+
}),
|
|
1344
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1345
|
+
flashList.FlashList,
|
|
1346
|
+
{
|
|
1347
|
+
horizontal: true,
|
|
1348
|
+
data: props.items,
|
|
1349
|
+
keyExtractor: keyOf,
|
|
1350
|
+
getItemType: kindOf,
|
|
1351
|
+
renderItem: ({ item }) => /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { width: size3 }, children: /* @__PURE__ */ jsxRuntime.jsx(CardView, { item }) }),
|
|
1352
|
+
snapToInterval: size3,
|
|
1353
|
+
decelerationRate: "fast",
|
|
1354
|
+
showsHorizontalScrollIndicator: false
|
|
1355
|
+
}
|
|
1356
|
+
)
|
|
1357
|
+
}
|
|
1358
|
+
);
|
|
1359
|
+
}
|
|
1170
1360
|
var ActivityLine = react.memo(function ActivityLine2() {
|
|
1171
1361
|
const { store } = useChat();
|
|
1172
1362
|
const { t } = react$1.useCopy();
|
|
@@ -1189,6 +1379,38 @@ var ActivityLine = react.memo(function ActivityLine2() {
|
|
|
1189
1379
|
}
|
|
1190
1380
|
);
|
|
1191
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
|
+
}
|
|
1192
1414
|
var Avatar = react.memo(function Avatar2(props) {
|
|
1193
1415
|
const { colors: colors2, size: size3, font: font2 } = useTheme();
|
|
1194
1416
|
const { slots } = useChat();
|
|
@@ -1301,37 +1523,6 @@ var ChatHeader = react.memo(function ChatHeader2() {
|
|
|
1301
1523
|
};
|
|
1302
1524
|
return Header ? /* @__PURE__ */ jsxRuntime.jsx(Header, { ...props, Default: DefaultHeader }) : /* @__PURE__ */ jsxRuntime.jsx(DefaultHeader, { ...props });
|
|
1303
1525
|
});
|
|
1304
|
-
var ChatSkeleton = react.memo(function ChatSkeleton2() {
|
|
1305
|
-
const { colors: colors2, radius: radius2, space: space2 } = useTheme();
|
|
1306
|
-
const row = (width, end) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1307
|
-
reactNative.View,
|
|
1308
|
-
{
|
|
1309
|
-
style: {
|
|
1310
|
-
alignSelf: end ? "flex-end" : "flex-start",
|
|
1311
|
-
width,
|
|
1312
|
-
height: 40,
|
|
1313
|
-
borderRadius: radius2.lg,
|
|
1314
|
-
backgroundColor: colors2.surface,
|
|
1315
|
-
marginHorizontal: space2.lg,
|
|
1316
|
-
marginTop: space2.md
|
|
1317
|
-
}
|
|
1318
|
-
}
|
|
1319
|
-
);
|
|
1320
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1321
|
-
reactNative.View,
|
|
1322
|
-
{
|
|
1323
|
-
accessible: true,
|
|
1324
|
-
accessibilityRole: "progressbar",
|
|
1325
|
-
accessibilityState: { busy: true },
|
|
1326
|
-
testID: "vinaverse-skeleton",
|
|
1327
|
-
children: [
|
|
1328
|
-
row("62%", false),
|
|
1329
|
-
row("45%", true),
|
|
1330
|
-
row("70%", false)
|
|
1331
|
-
]
|
|
1332
|
-
}
|
|
1333
|
-
);
|
|
1334
|
-
});
|
|
1335
1526
|
function DefaultComposer(props) {
|
|
1336
1527
|
const { t, direction } = react$1.useCopy();
|
|
1337
1528
|
const { colors: colors2, radius: radius2, space: space2, font: font2, size: size3 } = useTheme();
|
|
@@ -1473,23 +1664,37 @@ var DisclosureBar = react.memo(function DisclosureBar2() {
|
|
|
1473
1664
|
}
|
|
1474
1665
|
);
|
|
1475
1666
|
});
|
|
1476
|
-
function
|
|
1477
|
-
const {
|
|
1478
|
-
const
|
|
1479
|
-
|
|
1480
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1481
|
-
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,
|
|
1482
1671
|
{
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
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
|
+
}
|
|
1486
1681
|
}
|
|
1487
1682
|
);
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
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
|
+
});
|
|
1493
1698
|
function DefaultBubble(props) {
|
|
1494
1699
|
const { colors: colors2, radius: radius2, space: space2, font: font2 } = useTheme();
|
|
1495
1700
|
const role = props.item.role;
|
|
@@ -1611,37 +1816,22 @@ function Frame(props) {
|
|
|
1611
1816
|
}
|
|
1612
1817
|
);
|
|
1613
1818
|
}
|
|
1614
|
-
function
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
reactNative.AccessibilityInfo.isReduceMotionEnabled().then(
|
|
1627
|
-
(value) => {
|
|
1628
|
-
if (live) setReduced(value);
|
|
1629
|
-
},
|
|
1630
|
-
() => void 0
|
|
1631
|
-
);
|
|
1632
|
-
const subscription = reactNative.AccessibilityInfo.addEventListener(
|
|
1633
|
-
"reduceMotionChanged",
|
|
1634
|
-
setReduced
|
|
1635
|
-
);
|
|
1636
|
-
return () => {
|
|
1637
|
-
live = false;
|
|
1638
|
-
subscription.remove();
|
|
1639
|
-
};
|
|
1640
|
-
}, []);
|
|
1641
|
-
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
|
+
);
|
|
1642
1831
|
}
|
|
1643
|
-
function
|
|
1644
|
-
|
|
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 });
|
|
1645
1835
|
}
|
|
1646
1836
|
var SystemRow = react.memo(function SystemRow2(props) {
|
|
1647
1837
|
const { t } = react$1.useCopy();
|
|
@@ -1724,7 +1914,44 @@ function Line(props) {
|
|
|
1724
1914
|
}
|
|
1725
1915
|
);
|
|
1726
1916
|
}
|
|
1727
|
-
var
|
|
1917
|
+
var Welcome = react.memo(function Welcome2(props) {
|
|
1918
|
+
const { colors: colors2, radius: radius2, space: space2, font: font2 } = useTheme();
|
|
1919
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1920
|
+
reactNative.View,
|
|
1921
|
+
{
|
|
1922
|
+
style: { padding: space2.lg, gap: space2.md },
|
|
1923
|
+
testID: "vinaverse-welcome",
|
|
1924
|
+
children: [
|
|
1925
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1926
|
+
reactNative.Text,
|
|
1927
|
+
{
|
|
1928
|
+
style: {
|
|
1929
|
+
alignSelf: "flex-start",
|
|
1930
|
+
maxWidth: "85%",
|
|
1931
|
+
color: colors2.agentText,
|
|
1932
|
+
backgroundColor: colors2.agentBubble,
|
|
1933
|
+
borderRadius: radius2.lg,
|
|
1934
|
+
paddingHorizontal: space2.md,
|
|
1935
|
+
paddingVertical: space2.sm,
|
|
1936
|
+
fontSize: font2.size.md,
|
|
1937
|
+
lineHeight: font2.size.md * font2.lineHeight
|
|
1938
|
+
},
|
|
1939
|
+
children: props.welcome.text
|
|
1940
|
+
}
|
|
1941
|
+
),
|
|
1942
|
+
props.welcome.chips.length ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { flexDirection: "row", flexWrap: "wrap", gap: space2.sm }, children: props.welcome.chips.map((chip) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1943
|
+
Button,
|
|
1944
|
+
{
|
|
1945
|
+
label: chip.label,
|
|
1946
|
+
onPress: () => props.onChip(chip.message)
|
|
1947
|
+
},
|
|
1948
|
+
chip.label
|
|
1949
|
+
)) }) : null
|
|
1950
|
+
]
|
|
1951
|
+
}
|
|
1952
|
+
);
|
|
1953
|
+
});
|
|
1954
|
+
var keyOf2 = (item) => item.key;
|
|
1728
1955
|
function itemType(item) {
|
|
1729
1956
|
if (item.type === "card") return `card:${item.card.kind}`;
|
|
1730
1957
|
if (item.type === "message")
|
|
@@ -1734,43 +1961,111 @@ function itemType(item) {
|
|
|
1734
1961
|
function authorOf(item) {
|
|
1735
1962
|
return item?.type === "message" ? item.role : null;
|
|
1736
1963
|
}
|
|
1964
|
+
function carousels(items, previous) {
|
|
1965
|
+
const runs = /* @__PURE__ */ new Map();
|
|
1966
|
+
const inside = /* @__PURE__ */ new Set();
|
|
1967
|
+
const groupOf = (item) => {
|
|
1968
|
+
if (item?.type !== "card") return null;
|
|
1969
|
+
const group = item.card.card.group;
|
|
1970
|
+
return group?.layout === "carousel" && typeof group.id === "string" ? group.id : null;
|
|
1971
|
+
};
|
|
1972
|
+
for (let i = 0; i < items.length; i++) {
|
|
1973
|
+
const id = groupOf(items[i]);
|
|
1974
|
+
if (id === null) continue;
|
|
1975
|
+
let end = i + 1;
|
|
1976
|
+
while (end < items.length && groupOf(items[end]) === id) end++;
|
|
1977
|
+
if (end - i > 1) {
|
|
1978
|
+
const run = items.slice(i, end);
|
|
1979
|
+
const key = run[0]?.key;
|
|
1980
|
+
const before = previous.get(key);
|
|
1981
|
+
runs.set(
|
|
1982
|
+
key,
|
|
1983
|
+
before && before.length === run.length && before.every((c, n) => c === run[n]) ? before : run
|
|
1984
|
+
);
|
|
1985
|
+
for (const card of run.slice(1)) inside.add(card.key);
|
|
1986
|
+
}
|
|
1987
|
+
i = end - 1;
|
|
1988
|
+
}
|
|
1989
|
+
return { runs, inside };
|
|
1990
|
+
}
|
|
1737
1991
|
var Row = react.memo(function Row2(props) {
|
|
1738
1992
|
const { item } = props;
|
|
1993
|
+
const { slots } = useChat();
|
|
1994
|
+
const Group = slots.CardGroup;
|
|
1995
|
+
if (props.inside) return null;
|
|
1996
|
+
if (props.run && Group) return /* @__PURE__ */ jsxRuntime.jsx(Group, { items: props.run });
|
|
1739
1997
|
if (item.type === "card") return /* @__PURE__ */ jsxRuntime.jsx(CardView, { item });
|
|
1740
1998
|
if (item.type === "system") return /* @__PURE__ */ jsxRuntime.jsx(SystemRow, { item });
|
|
1741
1999
|
return item.state === "streaming" ? /* @__PURE__ */ jsxRuntime.jsx(StreamingBubble, { item, showAuthor: props.showAuthor }) : /* @__PURE__ */ jsxRuntime.jsx(MessageBubble, { item, showAuthor: props.showAuthor });
|
|
1742
2000
|
});
|
|
1743
2001
|
var MessageList = react.memo(function MessageList2() {
|
|
1744
|
-
const { store, slots } = useChat();
|
|
2002
|
+
const { store, slots, starters, handlers, imagePolicy } = useChat();
|
|
1745
2003
|
const { t } = react$1.useCopy();
|
|
1746
2004
|
const { space: space2 } = useTheme();
|
|
1747
2005
|
const reducedMotion = useReducedMotion();
|
|
1748
2006
|
const items = react$1.useConversationSelector(store, (v) => v.items);
|
|
2007
|
+
usePrefetchPhotos(items, handlers.current?.prefetchImage, imagePolicy?.hosts);
|
|
1749
2008
|
const opening = react$1.useConversationSelector(
|
|
1750
2009
|
store,
|
|
1751
2010
|
(v) => v.status === "starting" || v.status === "connecting"
|
|
1752
2011
|
);
|
|
1753
2012
|
const agentName = react$1.useConversationSelector(store, (v) => v.agent.name);
|
|
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
|
+
);
|
|
1754
2023
|
useAnnounceReplies(items);
|
|
2024
|
+
const Group = slots.CardGroup;
|
|
2025
|
+
const runsRef = react.useRef(/* @__PURE__ */ new Map());
|
|
2026
|
+
const grouping = react.useMemo(
|
|
2027
|
+
() => Group ? carousels(items, runsRef.current) : null,
|
|
2028
|
+
[items, Group]
|
|
2029
|
+
);
|
|
2030
|
+
runsRef.current = grouping?.runs ?? /* @__PURE__ */ new Map();
|
|
1755
2031
|
const itemsRef = react.useRef(items);
|
|
1756
2032
|
itemsRef.current = items;
|
|
2033
|
+
const groupingRef = react.useRef(grouping);
|
|
2034
|
+
groupingRef.current = grouping;
|
|
1757
2035
|
const renderItem = react.useCallback(
|
|
1758
2036
|
({ item, index }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1759
2037
|
Row,
|
|
1760
2038
|
{
|
|
1761
2039
|
item,
|
|
1762
|
-
showAuthor: authorOf(item) !== authorOf(itemsRef.current[index - 1])
|
|
2040
|
+
showAuthor: authorOf(item) !== authorOf(itemsRef.current[index - 1]),
|
|
2041
|
+
run: groupingRef.current?.runs.get(item.key),
|
|
2042
|
+
inside: groupingRef.current?.inside.has(item.key) === true
|
|
1763
2043
|
}
|
|
1764
2044
|
),
|
|
1765
2045
|
[]
|
|
1766
2046
|
);
|
|
2047
|
+
const onChip = react.useCallback(
|
|
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]
|
|
2054
|
+
);
|
|
1767
2055
|
const Empty = slots.EmptyState;
|
|
1768
|
-
const empty = opening ? /* @__PURE__ */ jsxRuntime.jsx(ChatSkeleton, {}) : Empty ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2056
|
+
const empty = opening ? /* @__PURE__ */ jsxRuntime.jsx(ChatSkeleton, {}) : Empty ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2057
|
+
Empty,
|
|
2058
|
+
{
|
|
2059
|
+
agentName: agentName ?? t("agentFallbackName"),
|
|
2060
|
+
welcome,
|
|
2061
|
+
onChip
|
|
2062
|
+
}
|
|
2063
|
+
) : welcome ? /* @__PURE__ */ jsxRuntime.jsx(Welcome, { welcome, onChip }) : null;
|
|
1769
2064
|
const props = react.useMemo(
|
|
1770
2065
|
() => ({
|
|
1771
2066
|
data: items,
|
|
1772
2067
|
renderItem,
|
|
1773
|
-
keyExtractor:
|
|
2068
|
+
keyExtractor: keyOf2,
|
|
1774
2069
|
getItemType: itemType,
|
|
1775
2070
|
maintainVisibleContentPosition: {
|
|
1776
2071
|
startRenderingFromBottom: true,
|
|
@@ -1787,10 +2082,25 @@ var MessageList = react.memo(function MessageList2() {
|
|
|
1787
2082
|
const List = slots.ListComponent;
|
|
1788
2083
|
return List ? /* @__PURE__ */ jsxRuntime.jsx(List, { ...props }) : /* @__PURE__ */ jsxRuntime.jsx(flashList.FlashList, { ...props });
|
|
1789
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
|
+
}
|
|
1790
2100
|
function useAnnounceReplies(items) {
|
|
1791
2101
|
const seen = react.useRef(void 0);
|
|
1792
2102
|
const { t } = react$1.useCopy();
|
|
1793
|
-
const { store } = useChat();
|
|
2103
|
+
const { store, handlers } = useChat();
|
|
1794
2104
|
react.useEffect(() => {
|
|
1795
2105
|
const last = items.at(-1);
|
|
1796
2106
|
if (seen.current === void 0) {
|
|
@@ -1803,8 +2113,8 @@ function useAnnounceReplies(items) {
|
|
|
1803
2113
|
const author = last.role === "staff" ? t("staffLabel", {
|
|
1804
2114
|
by: store.getSnapshot().takeover?.by || t("staffFallbackRole")
|
|
1805
2115
|
}) : store.getSnapshot().agent.name ?? t("agentFallbackName");
|
|
1806
|
-
announce(`${author}: ${last.text}`);
|
|
1807
|
-
}, [items, t, store]);
|
|
2116
|
+
(handlers.current?.announce ?? announce)(`${author}: ${last.text}`);
|
|
2117
|
+
}, [items, t, store, handlers]);
|
|
1808
2118
|
}
|
|
1809
2119
|
var CONNECTING_DELAY = tokens.motion.bannerDelay;
|
|
1810
2120
|
var StatusBanner = react.memo(function StatusBanner2() {
|
|
@@ -1905,7 +2215,14 @@ function Banner(props) {
|
|
|
1905
2215
|
);
|
|
1906
2216
|
}
|
|
1907
2217
|
function VinaverseChatProvider(props) {
|
|
1908
|
-
const {
|
|
2218
|
+
const {
|
|
2219
|
+
conversation,
|
|
2220
|
+
components,
|
|
2221
|
+
agentAvatar,
|
|
2222
|
+
timeZone,
|
|
2223
|
+
starters,
|
|
2224
|
+
imagePolicy
|
|
2225
|
+
} = props;
|
|
1909
2226
|
const handlers = react.useRef(props);
|
|
1910
2227
|
handlers.current = props;
|
|
1911
2228
|
const slots = useStableSlots(components);
|
|
@@ -1922,9 +2239,19 @@ function VinaverseChatProvider(props) {
|
|
|
1922
2239
|
slots,
|
|
1923
2240
|
agentAvatar,
|
|
1924
2241
|
timeZone,
|
|
1925
|
-
failureAction
|
|
2242
|
+
failureAction,
|
|
2243
|
+
starters,
|
|
2244
|
+
imagePolicy
|
|
1926
2245
|
}),
|
|
1927
|
-
[
|
|
2246
|
+
[
|
|
2247
|
+
conversation,
|
|
2248
|
+
slots,
|
|
2249
|
+
agentAvatar,
|
|
2250
|
+
timeZone,
|
|
2251
|
+
failureAction,
|
|
2252
|
+
starters,
|
|
2253
|
+
imagePolicy
|
|
2254
|
+
]
|
|
1928
2255
|
);
|
|
1929
2256
|
useNativeLifecycle(conversation);
|
|
1930
2257
|
react.useEffect(() => {
|
|
@@ -1950,7 +2277,9 @@ function VinaverseChat(props) {
|
|
|
1950
2277
|
keyboardVerticalOffset: props.keyboardVerticalOffset ?? 0,
|
|
1951
2278
|
keyboardBehavior: props.keyboardBehavior ?? (reactNative.Platform.OS === "ios" ? "padding" : "none"),
|
|
1952
2279
|
style: props.style,
|
|
1953
|
-
onError: props.onWarning
|
|
2280
|
+
onError: props.onWarning,
|
|
2281
|
+
suggestion: props.suggestion ?? null,
|
|
2282
|
+
footer: props.footer
|
|
1954
2283
|
}
|
|
1955
2284
|
) });
|
|
1956
2285
|
}
|
|
@@ -1976,11 +2305,27 @@ function Layout(props) {
|
|
|
1976
2305
|
/* @__PURE__ */ jsxRuntime.jsx(DisclosureBar, {}),
|
|
1977
2306
|
/* @__PURE__ */ jsxRuntime.jsx(StatusBanner, {}),
|
|
1978
2307
|
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { flex: 1 }, children: /* @__PURE__ */ jsxRuntime.jsx(MessageList, {}) }),
|
|
1979
|
-
/* @__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
|
|
1980
2311
|
]
|
|
1981
2312
|
}
|
|
1982
2313
|
);
|
|
1983
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
|
+
}
|
|
1984
2329
|
function useStableSlots(slots) {
|
|
1985
2330
|
const held = react.useRef({});
|
|
1986
2331
|
const next = slots ?? {};
|
|
@@ -1999,10 +2344,635 @@ function sameSlots(a, b) {
|
|
|
1999
2344
|
}
|
|
2000
2345
|
return true;
|
|
2001
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
|
+
}
|
|
2002
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
|
+
});
|
|
2003
2967
|
exports.ActivityLine = ActivityLine;
|
|
2968
|
+
exports.AgentChat = AgentChat;
|
|
2969
|
+
exports.AgentFooter = AgentFooter;
|
|
2970
|
+
exports.AgentLauncher = AgentLauncher;
|
|
2971
|
+
exports.AskAboutRow = AskAboutRow;
|
|
2004
2972
|
exports.Avatar = Avatar;
|
|
2005
2973
|
exports.Button = Button;
|
|
2974
|
+
exports.CardActions = CardActions;
|
|
2975
|
+
exports.CardCarousel = CardCarousel;
|
|
2006
2976
|
exports.CardFrame = CardFrame;
|
|
2007
2977
|
exports.CardView = CardView;
|
|
2008
2978
|
exports.ChatHeader = ChatHeader;
|
|
@@ -2010,12 +2980,21 @@ exports.ChatSkeleton = ChatSkeleton;
|
|
|
2010
2980
|
exports.Composer = Composer;
|
|
2011
2981
|
exports.DefaultBubble = DefaultBubble;
|
|
2012
2982
|
exports.DefaultComposer = DefaultComposer;
|
|
2983
|
+
exports.DefaultEnded = DefaultEnded;
|
|
2013
2984
|
exports.DefaultHeader = DefaultHeader;
|
|
2014
2985
|
exports.DefaultTurnFailed = DefaultTurnFailed;
|
|
2015
2986
|
exports.DefaultUnavailable = DefaultUnavailable;
|
|
2987
|
+
exports.DefaultUnavailableScreen = DefaultUnavailableScreen;
|
|
2988
|
+
exports.DefaultUnreachable = DefaultUnreachable;
|
|
2016
2989
|
exports.DisclosureBar = DisclosureBar;
|
|
2017
2990
|
exports.FailureActionButton = FailureActionButton;
|
|
2018
2991
|
exports.InfoCard = InfoCard;
|
|
2992
|
+
exports.LAUNCHER_SIZE = LAUNCHER_SIZE;
|
|
2993
|
+
exports.LauncherButton = LauncherButton;
|
|
2994
|
+
exports.LauncherEntrance = LauncherEntrance;
|
|
2995
|
+
exports.LauncherGreeting = LauncherGreeting;
|
|
2996
|
+
exports.LinksCard = LinksCard;
|
|
2997
|
+
exports.ListingCard = ListingCard;
|
|
2019
2998
|
exports.MessageBubble = MessageBubble;
|
|
2020
2999
|
exports.MessageList = MessageList;
|
|
2021
3000
|
exports.NextStepCard = NextStepCard;
|
|
@@ -2029,14 +3008,21 @@ exports.ThemeProvider = ThemeProvider;
|
|
|
2029
3008
|
exports.TimeSlotsCard = TimeSlotsCard;
|
|
2030
3009
|
exports.VinaverseChat = VinaverseChat;
|
|
2031
3010
|
exports.VinaverseChatProvider = VinaverseChatProvider;
|
|
3011
|
+
exports.Welcome = Welcome;
|
|
3012
|
+
exports.allowedImage = allowedImage;
|
|
2032
3013
|
exports.announce = announce;
|
|
2033
3014
|
exports.answerText = answerText;
|
|
3015
|
+
exports.carousels = carousels;
|
|
2034
3016
|
exports.createTheme = createTheme;
|
|
2035
3017
|
exports.defaultCard = defaultCard;
|
|
2036
3018
|
exports.fieldText = fieldText;
|
|
2037
3019
|
exports.itemType = itemType;
|
|
3020
|
+
exports.monogram = monogram;
|
|
3021
|
+
exports.newestWholeReply = newestWholeReply;
|
|
3022
|
+
exports.ratingText = ratingText;
|
|
2038
3023
|
exports.themeProblems = themeProblems;
|
|
2039
3024
|
exports.useChat = useChat;
|
|
3025
|
+
exports.useKeyboardShown = useKeyboardShown;
|
|
2040
3026
|
exports.useNativeLifecycle = useNativeLifecycle;
|
|
2041
3027
|
exports.useReducedMotion = useReducedMotion;
|
|
2042
3028
|
exports.useTheme = useTheme;
|