@vinaverse/react-native 0.1.0-alpha.4 → 0.1.0-alpha.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +122 -0
  2. package/dist/ask.cjs +58 -0
  3. package/dist/ask.cjs.map +1 -0
  4. package/dist/ask.d.cts +25 -0
  5. package/dist/ask.d.ts +25 -0
  6. package/dist/ask.js +5 -0
  7. package/dist/ask.js.map +1 -0
  8. package/dist/chat.cjs +266 -0
  9. package/dist/chat.cjs.map +1 -0
  10. package/dist/chat.d.cts +449 -0
  11. package/dist/chat.d.ts +449 -0
  12. package/dist/chat.js +5 -0
  13. package/dist/chat.js.map +1 -0
  14. package/dist/chunk-643GOUTG.cjs +75 -0
  15. package/dist/chunk-643GOUTG.cjs.map +1 -0
  16. package/dist/chunk-H2Y2YW2Q.cjs +2651 -0
  17. package/dist/chunk-H2Y2YW2Q.cjs.map +1 -0
  18. package/dist/chunk-NJWRZ55G.js +254 -0
  19. package/dist/chunk-NJWRZ55G.js.map +1 -0
  20. package/dist/chunk-OGPMGGYS.cjs +261 -0
  21. package/dist/chunk-OGPMGGYS.cjs.map +1 -0
  22. package/dist/chunk-OWUKWVEZ.cjs +53 -0
  23. package/dist/chunk-OWUKWVEZ.cjs.map +1 -0
  24. package/dist/chunk-PRXHS57U.js +40 -0
  25. package/dist/chunk-PRXHS57U.js.map +1 -0
  26. package/dist/chunk-PYPO6F7L.cjs +44 -0
  27. package/dist/chunk-PYPO6F7L.cjs.map +1 -0
  28. package/dist/chunk-SF6LJTVJ.js +2567 -0
  29. package/dist/chunk-SF6LJTVJ.js.map +1 -0
  30. package/dist/chunk-WKRCCPSN.js +48 -0
  31. package/dist/chunk-WKRCCPSN.js.map +1 -0
  32. package/dist/chunk-Y7P7DDHD.js +73 -0
  33. package/dist/chunk-Y7P7DDHD.js.map +1 -0
  34. package/dist/index.cjs +290 -2299
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +11 -360
  37. package/dist/index.d.ts +11 -360
  38. package/dist/index.js +5 -2254
  39. package/dist/index.js.map +1 -1
  40. package/dist/launcher.cjs +79 -0
  41. package/dist/launcher.cjs.map +1 -0
  42. package/dist/launcher.d.cts +121 -0
  43. package/dist/launcher.d.ts +121 -0
  44. package/dist/launcher.js +6 -0
  45. package/dist/launcher.js.map +1 -0
  46. package/dist/theme-BhiEGv64.d.cts +35 -0
  47. package/dist/theme-BhiEGv64.d.ts +35 -0
  48. package/package.json +114 -9
package/dist/index.cjs CHANGED
@@ -1,2305 +1,296 @@
1
1
  'use strict';
2
2
 
3
- var flashList = require('@shopify/flash-list');
4
- var react$1 = require('@vinaverse/react');
5
- var reactNative = require('react-native');
6
- var react = require('react');
7
- var jsxRuntime = require('react/jsx-runtime');
8
- var tokens = require('@vinaverse/tokens');
9
- var conversation = require('@vinaverse/client/conversation');
3
+ var chunkH2Y2YW2Q_cjs = require('./chunk-H2Y2YW2Q.cjs');
4
+ var chunkOGPMGGYS_cjs = require('./chunk-OGPMGGYS.cjs');
5
+ var chunkPYPO6F7L_cjs = require('./chunk-PYPO6F7L.cjs');
6
+ var chunk643GOUTG_cjs = require('./chunk-643GOUTG.cjs');
7
+ var chunkOWUKWVEZ_cjs = require('./chunk-OWUKWVEZ.cjs');
10
8
 
11
- // src/cards/CardCarousel.tsx
12
- var ChatContext = react.createContext(null);
13
- function ChatContextProvider(props) {
14
- return /* @__PURE__ */ jsxRuntime.jsx(ChatContext.Provider, { value: props.value, children: props.children });
15
- }
16
- function useChat() {
17
- const value = react.useContext(ChatContext);
18
- if (!value)
19
- throw new Error(
20
- "Vinaverse parts render inside <VinaverseChat> or <VinaverseChatProvider>."
21
- );
22
- return value;
23
- }
24
- function createTheme(scheme, overrides = {}) {
25
- return {
26
- scheme,
27
- colors: { ...tokens.colors(scheme), ...overrides[scheme] },
28
- font: {
29
- ...tokens.font,
30
- ...overrides.fontFamily ? { family: overrides.fontFamily } : {}
31
- },
32
- space: { ...tokens.space, ...overrides.space },
33
- radius: { ...tokens.radius, ...overrides.radius },
34
- motion: tokens.motion,
35
- size: tokens.size
36
- };
37
- }
38
- function themeProblems(overrides = {}) {
39
- return ["light", "dark"].flatMap(
40
- (scheme) => tokens.contrastProblems(createTheme(scheme, overrides).colors).map(
41
- (p) => `${scheme}: ${p.foreground} on ${p.background} is ${p.ratio.toFixed(2)}:1, below ${p.minimum}:1`
42
- )
43
- );
44
- }
45
- var ThemeContext = react.createContext(createTheme("light"));
46
- function ThemeProvider(props) {
47
- const system = reactNative.useColorScheme();
48
- const setting = props.colorScheme ?? "system";
49
- const scheme = setting === "system" ? system === "dark" ? "dark" : "light" : setting;
50
- const overrides = props.theme;
51
- const value = react.useMemo(
52
- () => createTheme(scheme, overrides),
53
- [scheme, overrides]
54
- );
55
- return /* @__PURE__ */ jsxRuntime.jsx(ThemeContext.Provider, { value, children: props.children });
56
- }
57
- function useTheme() {
58
- return react.useContext(ThemeContext);
59
- }
60
- var Button = react.memo(function Button2(props) {
61
- const { colors: colors2, radius: radius2, space: space2, size: size3, font: font2 } = useTheme();
62
- const variant = props.variant ?? "secondary";
63
- const inactive = props.disabled === true || props.busy === true;
64
- const filled = variant === "primary" || props.selected === true;
65
- const background = filled ? colors2.primary : variant === "secondary" ? colors2.surface : "transparent";
66
- const foreground = filled ? colors2.onPrimary : colors2.primary;
67
- const checkable = props.role === "radio" || props.role === "checkbox";
68
- return /* @__PURE__ */ jsxRuntime.jsxs(
69
- reactNative.Pressable,
70
- {
71
- accessibilityRole: props.role ?? "button",
72
- accessibilityLabel: props.label,
73
- ...props.hint ? { accessibilityHint: props.hint } : {},
74
- accessibilityState: {
75
- disabled: inactive,
76
- busy: props.busy === true,
77
- ...checkable ? props.role === "radio" ? { selected: props.selected === true } : { checked: props.selected === true } : {}
78
- },
79
- disabled: inactive,
80
- onPress: props.onPress,
81
- ...props.testID ? { testID: props.testID } : {},
82
- style: ({ pressed }) => ({
83
- minHeight: size3.touchTarget,
84
- minWidth: size3.touchTarget,
85
- paddingHorizontal: space2.md,
86
- paddingVertical: space2.sm,
87
- borderRadius: radius2.md,
88
- borderWidth: variant === "text" ? 0 : 1,
89
- borderColor: filled ? colors2.primary : colors2.border,
90
- backgroundColor: background,
91
- opacity: inactive ? 0.55 : pressed ? 0.8 : 1,
92
- alignItems: "center",
93
- justifyContent: "center",
94
- flexDirection: "row",
95
- gap: space2.xs
96
- }),
97
- children: [
98
- props.busy ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.ActivityIndicator, { color: foreground }) : null,
99
- props.children ?? /* @__PURE__ */ jsxRuntime.jsx(
100
- reactNative.Text,
101
- {
102
- style: {
103
- color: foreground,
104
- fontSize: font2.size.md,
105
- fontWeight: "500",
106
- ...font2.family ? { fontFamily: font2.family } : {}
107
- },
108
- children: props.label
109
- }
110
- )
111
- ]
112
- }
113
- );
114
- });
115
- function cardOf(held) {
116
- return held.card;
117
- }
118
- function CardFrame(props) {
119
- const { colors: colors2, radius: radius2, space: space2 } = useTheme();
120
- return /* @__PURE__ */ jsxRuntime.jsx(
121
- reactNative.View,
122
- {
123
- accessibilityLabel: props.label,
124
- ...props.restored ? {
125
- pointerEvents: "none",
126
- accessibilityState: { disabled: true }
127
- } : {},
128
- ...props.testID ? { testID: props.testID } : {},
129
- style: {
130
- marginHorizontal: 16,
131
- marginTop: space2.sm,
132
- padding: space2.md,
133
- gap: space2.sm,
134
- borderRadius: radius2.lg,
135
- borderWidth: 1,
136
- borderColor: colors2.divider,
137
- backgroundColor: colors2.background,
138
- opacity: props.restored ? 0.7 : 1,
139
- maxWidth: 520,
140
- alignSelf: "stretch"
141
- },
142
- children: props.children
143
- }
144
- );
145
- }
146
- function Title(props) {
147
- const { colors: colors2, font: font2 } = useTheme();
148
- return /* @__PURE__ */ jsxRuntime.jsx(
149
- reactNative.Text,
150
- {
151
- accessibilityRole: "header",
152
- numberOfLines: props.numberOfLines,
153
- style: {
154
- color: colors2.text,
155
- fontSize: font2.size.md,
156
- fontWeight: "600",
157
- ...font2.family ? { fontFamily: font2.family } : {}
158
- },
159
- children: props.children
160
- }
161
- );
162
- }
163
- function Body(props) {
164
- const { colors: colors2, font: font2 } = useTheme();
165
- return /* @__PURE__ */ jsxRuntime.jsx(
166
- reactNative.Text,
167
- {
168
- style: {
169
- color: props.danger ? colors2.danger : props.muted ? colors2.textMuted : colors2.text,
170
- fontSize: props.muted ? font2.size.sm : font2.size.md,
171
- lineHeight: (props.muted ? font2.size.sm : font2.size.md) * font2.lineHeight,
172
- ...font2.family ? { fontFamily: font2.family } : {}
173
- },
174
- children: props.children
175
- }
176
- );
177
- }
178
- function useLink(link, held) {
179
- const { store, handlers } = useChat();
180
- if (!link || !store.checkLink(link)) return null;
181
- return () => handlers.current?.onOpenLink?.(link, held);
182
- }
183
- function ratingText(valuePpm, locale) {
184
- const value = valuePpm / 1e6;
185
- try {
186
- return new Intl.NumberFormat(locale, {
187
- minimumFractionDigits: 1,
188
- maximumFractionDigits: 1
189
- }).format(value);
190
- } catch {
191
- return value.toFixed(1);
192
- }
193
- }
194
- function safeImage(url) {
195
- return url && /^https:\/\//i.test(url) ? url : null;
196
- }
197
- function InfoCard(props) {
198
- const card = cardOf(props.card);
199
- const { locale, t } = react$1.useCopy();
200
- const { slots, timeZone } = useChat();
201
- const { colors: colors2, radius: radius2, space: space2, font: font2 } = useTheme();
202
- const image = safeImage(card.image_url);
203
- const Img = slots.Image ?? reactNative.Image;
204
- const money = card.price ?? card.price_from;
205
- const rating = card.rating ? ratingText(card.rating.value_ppm, locale) : null;
206
- const amount = money ? react$1.formatMoney(money.amount, money.currency, locale) : null;
207
- const price = amount && !card.price ? t("priceFrom", { price: amount }) : amount;
208
- const when = card.starts_at ? react$1.formatTimeRange(card.starts_at, void 0, locale, timeZone) : null;
209
- const label = [
210
- card.title,
211
- card.subtitle,
212
- rating && `\u2605 ${rating}`,
213
- price,
214
- when
215
- ].filter(Boolean).join(", ");
216
- return /* @__PURE__ */ jsxRuntime.jsxs(
217
- CardFrame,
218
- {
219
- label,
220
- restored: props.restored,
221
- testID: `vinaverse-card-${card.id}`,
222
- children: [
223
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { flexDirection: "row", gap: space2.md }, children: [
224
- image ? /* @__PURE__ */ jsxRuntime.jsx(
225
- Img,
226
- {
227
- source: { uri: image },
228
- style: {
229
- width: 64,
230
- height: 64,
231
- borderRadius: radius2.md,
232
- backgroundColor: colors2.surface
233
- },
234
- accessible: false
235
- }
236
- ) : null,
237
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { flex: 1, gap: space2.xxs }, children: [
238
- /* @__PURE__ */ jsxRuntime.jsx(Title, { numberOfLines: 2, children: card.title }),
239
- card.subtitle ? /* @__PURE__ */ jsxRuntime.jsx(Body, { muted: true, children: card.subtitle }) : null,
240
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: colors2.textMuted, fontSize: font2.size.sm }, children: [
241
- rating && `\u2605 ${rating}${card.rating ? ` (${card.rating.count})` : ""}`,
242
- price,
243
- when
244
- ].filter(Boolean).join(" \xB7 ") })
245
- ] })
246
- ] }),
247
- card.body ? /* @__PURE__ */ jsxRuntime.jsx(Body, { children: card.body }) : null,
248
- /* @__PURE__ */ jsxRuntime.jsx(Badges, { badges: card.badges }),
249
- props.restored ? null : /* @__PURE__ */ jsxRuntime.jsx(CardActions, { ...props })
250
- ]
251
- }
252
- );
253
- }
254
- function Badges(props) {
255
- const { colors: colors2, radius: radius2, space: space2, font: font2 } = useTheme();
256
- if (!props.badges?.length) return null;
257
- return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { flexDirection: "row", flexWrap: "wrap", gap: space2.xs }, children: props.badges.map((b) => /* @__PURE__ */ jsxRuntime.jsx(
258
- reactNative.Text,
259
- {
260
- style: {
261
- color: colors2.text,
262
- backgroundColor: colors2.surface,
263
- borderRadius: radius2.pill,
264
- paddingHorizontal: space2.sm,
265
- paddingVertical: space2.xxs,
266
- fontSize: font2.size.xs
267
- },
268
- children: b
269
- },
270
- b
271
- )) });
272
- }
273
- function CardActions(props) {
274
- const card = cardOf(props.card);
275
- const { space: space2 } = useTheme();
276
- if (!card.actions?.length) return null;
277
- return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { flexDirection: "row", flexWrap: "wrap", gap: space2.sm }, children: card.actions.map((a) => /* @__PURE__ */ jsxRuntime.jsx(
278
- Action,
279
- {
280
- held: props.card,
281
- action: a.action,
282
- label: a.label,
283
- link: a.deep_link
284
- },
285
- `${a.action}:${a.label}`
286
- )) });
287
- }
288
- function Action(props) {
289
- const { store, handlers } = useChat();
290
- const open = useLink(props.link, props.held);
291
- if (props.link && !open) return null;
292
- return /* @__PURE__ */ jsxRuntime.jsx(
293
- Button,
294
- {
295
- label: props.label,
296
- role: open ? "link" : "button",
297
- onPress: () => {
298
- if (open) return open();
299
- store.cardAction(props.held.id, props.action);
300
- handlers.current?.onCardAction?.(props.held, props.action);
301
- }
302
- }
303
- );
304
- }
305
- function LinksCard(props) {
306
- const card = cardOf(props.card);
307
- const { store, handlers } = useChat();
308
- const links = (card.links ?? []).filter(
309
- (l) => /^https:\/\//i.test(l.url) || store.checkLink(l.url)
310
- );
311
- return /* @__PURE__ */ jsxRuntime.jsxs(
312
- CardFrame,
313
- {
314
- label: [card.title, ...links.map((l) => l.label)].join(", "),
315
- restored: props.restored,
316
- testID: `vinaverse-card-${card.id}`,
317
- children: [
318
- /* @__PURE__ */ jsxRuntime.jsx(Title, { children: card.title }),
319
- links.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
320
- Button,
321
- {
322
- label: l.label,
323
- role: "link",
324
- variant: "secondary",
325
- disabled: props.restored,
326
- onPress: () => {
327
- const open = handlers.current?.onOpenLink;
328
- if (open) open(l.url, props.card);
329
- else void reactNative.Linking.openURL(l.url);
330
- }
331
- },
332
- l.url
333
- ))
334
- ]
335
- }
336
- );
337
- }
338
- function ListingCard(props) {
339
- const card = cardOf(props.card);
340
- const { locale, t } = react$1.useCopy();
341
- const { slots, timeZone } = useChat();
342
- const { colors: colors2, radius: radius2, space: space2, font: font2 } = useTheme();
343
- const [failed, setFailed] = react.useState(null);
344
- const photoUrl = safeImage(card.images?.[0]?.url ?? card.image_url);
345
- const hero = photoUrl === failed ? null : photoUrl;
346
- const Img = slots.Image ?? reactNative.Image;
347
- const rating = card.rating ? `\u2605 ${ratingText(card.rating.value_ppm, locale)} (${card.rating.count})` : null;
348
- const price = card.price_from ? t("priceFrom", {
349
- price: react$1.formatMoney(
350
- card.price_from.amount,
351
- card.price_from.currency,
352
- locale
353
- )
354
- }) : null;
355
- const next = card.next_available ? t("nextAvailable", {
356
- time: react$1.formatTimeRange(card.next_available, void 0, locale, timeZone)
357
- }) : null;
358
- const photo = {
359
- width: "100%",
360
- aspectRatio: 1.6,
361
- borderRadius: radius2.md
362
- };
363
- return /* @__PURE__ */ jsxRuntime.jsxs(
364
- CardFrame,
365
- {
366
- label: [card.title, card.subtitle, rating, price, next].filter(Boolean).join(", "),
367
- restored: props.restored,
368
- testID: `vinaverse-card-${card.id}`,
369
- children: [
370
- hero ? /* @__PURE__ */ jsxRuntime.jsx(
371
- Img,
372
- {
373
- source: { uri: hero },
374
- onError: () => setFailed(hero),
375
- style: { ...photo, backgroundColor: colors2.surface },
376
- accessible: false,
377
- testID: `vinaverse-photo-${card.id}`
378
- }
379
- ) : /* @__PURE__ */ jsxRuntime.jsx(
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
- ] }),
409
- card.body ? /* @__PURE__ */ jsxRuntime.jsx(Body, { children: card.body }) : null,
410
- /* @__PURE__ */ jsxRuntime.jsx(Badges, { badges: next ? [next, ...card.badges ?? []] : card.badges }),
411
- props.restored ? null : /* @__PURE__ */ jsxRuntime.jsx(CardActions, { ...props })
412
- ]
413
- }
414
- );
415
- }
416
- function monogram(title) {
417
- return title.split(/\s+/).filter(Boolean).slice(0, 2).map((w) => [...w][0]?.toUpperCase() ?? "").join("");
418
- }
419
- function NextStepCard(props) {
420
- const card = cardOf(props.card);
421
- const action = card.actions?.[0];
422
- const open = useLink(action?.deep_link, props.card);
423
- return /* @__PURE__ */ jsxRuntime.jsxs(
424
- CardFrame,
425
- {
426
- label: [card.title, card.body].filter(Boolean).join(". "),
427
- restored: props.restored,
428
- testID: `vinaverse-card-${card.id}`,
429
- children: [
430
- /* @__PURE__ */ jsxRuntime.jsx(Title, { children: card.title }),
431
- card.body ? /* @__PURE__ */ jsxRuntime.jsx(Body, { muted: true, children: card.body }) : null,
432
- action && open && !props.restored ? /* @__PURE__ */ jsxRuntime.jsx(
433
- Button,
434
- {
435
- label: action.label,
436
- variant: "primary",
437
- role: "link",
438
- onPress: open
439
- }
440
- ) : null
441
- ]
442
- }
443
- );
444
- }
445
- function fieldText(type, value, locale, timeZone) {
446
- if (value === null || value === void 0) return "";
447
- const v = value;
448
- switch (type) {
449
- case "list":
450
- return Array.isArray(value) ? value.join(", ") : String(value);
451
- case "time_range":
452
- return react$1.formatTimeRange(
453
- String(v.start ?? ""),
454
- typeof v.end === "string" ? v.end : void 0,
455
- locale,
456
- timeZone
457
- );
458
- case "money_cents":
459
- return react$1.formatMoney(
460
- Number(v.amount ?? 0),
461
- String(v.currency ?? "USD"),
462
- locale
463
- );
464
- case "address":
465
- return ["line1", "line2", "city", "region", "postal_code", "country"].map((k) => v[k]).filter((p) => typeof p === "string" && p).join(", ");
466
- case "weekly_hours": {
467
- const entries = Array.isArray(v.entries) ? v.entries : [];
468
- return entries.map((e) => `${weekday(e.day, locale)} ${e.start}\u2013${e.end}`).join(", ");
469
- }
470
- default:
471
- return typeof value === "object" ? JSON.stringify(value) : String(value);
472
- }
473
- }
474
- var DAYS = ["mon", "tue", "wed", "thu", "fri", "sat", "sun"];
475
- function weekday(day, locale) {
476
- const i = DAYS.indexOf(day);
477
- if (i < 0) return day;
478
- try {
479
- return new Intl.DateTimeFormat(locale, {
480
- weekday: "short",
481
- timeZone: "UTC"
482
- }).format(new Date(Date.UTC(2024, 0, 1 + i)));
483
- } catch {
484
- return day;
485
- }
486
- }
487
- function outcomeText(t, outcome, status) {
488
- if (outcome === "confirmed") return t("proposalConfirmed");
489
- if (outcome === "declined") return t("proposalDeclined");
490
- if (outcome === "failed") return t("proposalFailed");
491
- if (outcome === "expired") return t("proposalExpired");
492
- if (status === "confirmed") return t("proposalConfirmed");
493
- if (status === "declined") return t("proposalDeclined");
494
- if (status === "expired") return t("proposalExpired");
495
- if (status !== "pending") return t("proposalSettled");
496
- return null;
497
- }
498
- function ProposalCard(props) {
499
- const card = cardOf(props.card);
500
- const proposal = card.proposal;
501
- const { t, locale } = react$1.useCopy();
502
- const { store, handlers, timeZone } = useChat();
503
- const { colors: colors2, space: space2, font: font2 } = useTheme();
504
- const edit = useLink(proposal?.edit_deep_link, props.card);
505
- if (!proposal) return null;
506
- const settled = outcomeText(t, props.card.outcome, proposal.status);
507
- const actionable = settled === null && !props.restored;
508
- const decide = (decision) => {
509
- const onProposal = handlers.current?.onProposal;
510
- if (!onProposal) return;
511
- store.decideProposal(
512
- props.card.id,
513
- () => onProposal(props.card, decision)
514
- ).catch(
515
- (error) => handlers.current?.onWarning?.(`Vinaverse proposal: ${String(error)}`)
516
- );
517
- };
518
- const fields = proposal.fields.map((f) => {
519
- const after = fieldText(f.type, f.after, locale, timeZone);
520
- const before = f.before === void 0 || f.before === null ? null : fieldText(f.type, f.before, locale, timeZone);
521
- return {
522
- key: f.key,
523
- label: f.label,
524
- value: before !== null && before !== after ? `${before} \u2192 ${after}` : after
525
- };
526
- });
527
- return /* @__PURE__ */ jsxRuntime.jsxs(
528
- CardFrame,
529
- {
530
- label: [
531
- proposal.title,
532
- proposal.summary,
533
- ...fields.map((f) => `${f.label}: ${f.value}`),
534
- settled
535
- ].filter(Boolean).join(". "),
536
- restored: props.restored,
537
- testID: `vinaverse-proposal-${card.id}`,
538
- children: [
539
- /* @__PURE__ */ jsxRuntime.jsx(Title, { children: proposal.title }),
540
- /* @__PURE__ */ jsxRuntime.jsx(Body, { muted: true, children: proposal.summary }),
541
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { gap: space2.xs }, children: fields.map((f) => /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { flexDirection: "row", gap: space2.sm }, children: [
542
- /* @__PURE__ */ jsxRuntime.jsx(
543
- reactNative.Text,
544
- {
545
- style: {
546
- color: colors2.textMuted,
547
- fontSize: font2.size.sm,
548
- minWidth: 72
549
- },
550
- children: f.label
551
- }
552
- ),
553
- /* @__PURE__ */ jsxRuntime.jsx(
554
- reactNative.Text,
555
- {
556
- style: { color: colors2.text, fontSize: font2.size.sm, flex: 1 },
557
- children: f.value
558
- }
559
- )
560
- ] }, f.key)) }),
561
- settled ? /* @__PURE__ */ jsxRuntime.jsx(
562
- reactNative.Text,
563
- {
564
- style: {
565
- color: props.card.outcome === "confirmed" || proposal.status === "confirmed" ? colors2.success : colors2.textMuted,
566
- fontSize: font2.size.sm,
567
- fontWeight: "600"
568
- },
569
- children: settled
570
- }
571
- ) : null,
572
- actionable ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { flexDirection: "row", flexWrap: "wrap", gap: space2.sm }, children: [
573
- /* @__PURE__ */ jsxRuntime.jsx(
574
- Button,
575
- {
576
- label: t("proposalConfirm"),
577
- variant: "primary",
578
- busy: props.busy,
579
- disabled: props.busy,
580
- onPress: () => decide("confirm"),
581
- testID: "vinaverse-proposal-confirm"
582
- }
583
- ),
584
- /* @__PURE__ */ jsxRuntime.jsx(
585
- Button,
586
- {
587
- label: t("proposalDecline"),
588
- disabled: props.busy,
589
- onPress: () => decide("decline"),
590
- testID: "vinaverse-proposal-decline"
591
- }
592
- ),
593
- edit ? /* @__PURE__ */ jsxRuntime.jsx(
594
- Button,
595
- {
596
- label: t("proposalChange"),
597
- variant: "text",
598
- role: "link",
599
- onPress: edit
600
- }
601
- ) : null
602
- ] }) : null
603
- ]
604
- }
605
- );
606
- }
607
- var KNOWN = /* @__PURE__ */ new Set([
608
- "single_choice",
609
- "multi_choice",
610
- "image_choice",
611
- "yes_no",
612
- "list_choice",
613
- "rate_each",
614
- "short_text",
615
- "long_text",
616
- "date",
617
- "number",
618
- "scale",
619
- "photo"
620
- ]);
621
- var ONE_TAP = /* @__PURE__ */ new Set(["single_choice", "yes_no", "list_choice", "scale"]);
622
- function QuestionCard(props) {
623
- const held = props.card;
624
- const question = held.question;
625
- const { store, handlers } = useChat();
626
- const { t, locale } = react$1.useCopy();
627
- const { colors: colors2, font: font2, space: space2 } = useTheme();
628
- const needsSocket = react$1.useConversationSelector(
629
- store,
630
- (v) => v.answersNeedWebSocket
631
- );
632
- if (!question) return null;
633
- const send = (answer, questionId = question.question_id) => {
634
- try {
635
- store.answer(held.id, questionId, answer);
636
- } catch (error) {
637
- handlers.current?.onWarning?.(`Vinaverse answer: ${String(error)}`);
638
- }
639
- };
640
- const locked = held.locked.includes(question.question_id);
641
- const state = question.state;
642
- const open = state === "open" && !locked && !props.restored;
643
- const summary = state === "answered" ? answerText(question, locale, t("questionOther")) : null;
644
- return /* @__PURE__ */ jsxRuntime.jsxs(
645
- CardFrame,
646
- {
647
- label: [question.prompt, summary].filter(Boolean).join(". "),
648
- restored: props.restored,
649
- testID: `vinaverse-question-${held.id}`,
650
- children: [
651
- question.progress ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: colors2.textMuted, fontSize: font2.size.xs }, children: t("questionStep", {
652
- step: question.progress.step,
653
- total: question.progress.total
654
- }) }) : null,
655
- /* @__PURE__ */ jsxRuntime.jsx(Title, { children: question.prompt }),
656
- question.help ? /* @__PURE__ */ jsxRuntime.jsx(Body, { muted: true, children: question.help }) : null,
657
- state === "answered" ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { gap: space2.xxs }, children: [
658
- /* @__PURE__ */ jsxRuntime.jsx(Body, { muted: true, children: t("questionAnswered") }),
659
- summary ? /* @__PURE__ */ jsxRuntime.jsx(Body, { children: summary }) : null
660
- ] }) : state === "superseded" ? /* @__PURE__ */ jsxRuntime.jsx(Body, { muted: true, children: t("questionReplaced") }) : !KNOWN.has(question.kind) || needsSocket ? /* @__PURE__ */ jsxRuntime.jsx(Body, { muted: true, children: t("typeAnswerBelow") }) : question.kind === "rate_each" ? /* @__PURE__ */ jsxRuntime.jsx(
661
- RateEach,
662
- {
663
- question,
664
- locked: held.locked,
665
- enabled: !props.restored,
666
- send
667
- }
668
- ) : /* @__PURE__ */ jsxRuntime.jsx(
669
- Answer,
670
- {
671
- question,
672
- enabled: open,
673
- send,
674
- held
675
- },
676
- question.question_id
677
- )
678
- ]
679
- }
680
- );
681
- }
682
- function Answer(props) {
683
- const { question, send, enabled } = props;
684
- const { t } = react$1.useCopy();
685
- const { space: space2 } = useTheme();
686
- const { handlers } = useChat();
687
- const [draft, setDraft] = react.useState({});
688
- const kind = question.kind;
689
- const oneTap = ONE_TAP.has(kind) && !question.allows_other;
690
- const problem = conversation.answerProblem(question, draft);
691
- const submit = (answer = draft) => {
692
- if (conversation.answerProblem(question, answer) === null)
693
- send(answer);
694
- };
695
- const input = (() => {
696
- switch (kind) {
697
- case "short_text":
698
- case "long_text":
699
- return /* @__PURE__ */ jsxRuntime.jsx(
700
- TextAnswer,
701
- {
702
- question,
703
- enabled,
704
- value: draft.text ?? "",
705
- onChange: (text) => setDraft({ text })
706
- }
707
- );
708
- case "number":
709
- return /* @__PURE__ */ jsxRuntime.jsx(
710
- NumberAnswer,
711
- {
712
- question,
713
- enabled,
714
- value: draft.number,
715
- onChange: (n) => setDraft({ number: n })
716
- }
717
- );
718
- case "scale":
719
- return /* @__PURE__ */ jsxRuntime.jsx(
720
- ScaleAnswer,
721
- {
722
- question,
723
- enabled,
724
- onPick: (n) => submit({ number: n })
725
- }
726
- );
727
- case "date":
728
- return /* @__PURE__ */ jsxRuntime.jsx(
729
- DateAnswer,
730
- {
731
- question,
732
- enabled,
733
- value: draft.date,
734
- onChange: (date) => setDraft({ date })
735
- }
736
- );
737
- case "photo":
738
- return /* @__PURE__ */ jsxRuntime.jsx(
739
- Button,
740
- {
741
- label: t("questionAddPhoto"),
742
- disabled: !enabled || !handlers.current?.onPickPhoto,
743
- onPress: () => {
744
- handlers.current?.onPickPhoto?.(question, props.held).then((picked) => {
745
- if (picked) send({ upload_ref: picked.upload_ref });
746
- }).catch(
747
- (error) => handlers.current?.onWarning?.(
748
- `Vinaverse photo: ${String(error)}`
749
- )
750
- );
751
- }
752
- }
753
- );
754
- default:
755
- return /* @__PURE__ */ jsxRuntime.jsx(
756
- ChoiceAnswer,
757
- {
758
- question,
759
- enabled,
760
- draft,
761
- onChange: (next) => oneTap ? submit(next) : setDraft(next)
762
- }
763
- );
764
- }
765
- })();
766
- const tapToAnswer = oneTap || kind === "scale" || kind === "photo";
767
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { gap: space2.sm }, children: [
768
- input,
769
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { flexDirection: "row", flexWrap: "wrap", gap: space2.sm }, children: [
770
- tapToAnswer ? null : /* @__PURE__ */ jsxRuntime.jsx(
771
- Button,
772
- {
773
- label: t("questionSubmit"),
774
- variant: "primary",
775
- disabled: !enabled || problem !== null,
776
- onPress: () => submit(),
777
- testID: "vinaverse-question-submit"
778
- }
779
- ),
780
- question.required ? null : /* @__PURE__ */ jsxRuntime.jsx(
781
- Button,
782
- {
783
- label: t("questionSkip"),
784
- variant: "text",
785
- disabled: !enabled,
786
- onPress: () => send({ skipped: true })
787
- }
788
- )
789
- ] })
790
- ] });
791
- }
792
- function ChoiceAnswer(props) {
793
- const { question, draft, onChange, enabled } = props;
794
- const { t } = react$1.useCopy();
795
- const { slots } = useChat();
796
- const { colors: colors2, radius: radius2, space: space2, font: font2 } = useTheme();
797
- const [search, setSearch] = react.useState("");
798
- const multi = question.kind === "multi_choice" || question.kind === "image_choice";
799
- const values = draft.values ?? [];
800
- const other = draft.other_text;
801
- const none = question.none_of_the_above;
802
- const list = question.kind === "list_choice";
803
- const options = react.useMemo(() => {
804
- const all = question.options ?? [];
805
- const q = search.trim().toLowerCase();
806
- return list && q ? all.filter((o) => o.label.toLowerCase().includes(q)) : all;
807
- }, [question.options, search, list]);
808
- const shown = list ? options.slice(0, 50) : options;
809
- const pick = (value) => {
810
- if (none && value === none.value) return onChange({ values: [value] });
811
- const rest = values.filter((v) => v !== none?.value);
812
- const next = multi ? rest.includes(value) ? rest.filter((v) => v !== value) : [...rest, value] : [value];
813
- const keepOther = other !== void 0 && (multi || question.kind === "single_choice");
814
- onChange({
815
- ...next.length ? { values: next } : {},
816
- ...keepOther ? { other_text: other } : {}
817
- });
818
- };
819
- const Img = slots.Image ?? reactNative.Image;
820
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { gap: space2.xs }, children: [
821
- list ? /* @__PURE__ */ jsxRuntime.jsx(
822
- reactNative.TextInput,
823
- {
824
- value: search,
825
- onChangeText: setSearch,
826
- placeholder: t("questionSearch"),
827
- placeholderTextColor: colors2.textMuted,
828
- accessibilityLabel: t("questionSearch"),
829
- editable: enabled,
830
- style: {
831
- borderWidth: 1,
832
- borderColor: colors2.border,
833
- borderRadius: radius2.md,
834
- paddingHorizontal: space2.md,
835
- minHeight: 44,
836
- color: colors2.text,
837
- fontSize: font2.size.md
838
- }
839
- }
840
- ) : null,
841
- shown.map((o) => {
842
- const image = question.kind === "image_choice" ? safeImage(o.image_url) : null;
843
- return /* @__PURE__ */ jsxRuntime.jsx(
844
- Button,
845
- {
846
- label: o.label,
847
- role: multi ? "checkbox" : "radio",
848
- selected: values.includes(o.value),
849
- disabled: !enabled,
850
- ...o.description ? { hint: o.description } : {},
851
- onPress: () => pick(o.value),
852
- children: image ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { alignItems: "center", gap: space2.xs }, children: [
853
- /* @__PURE__ */ jsxRuntime.jsx(
854
- Img,
855
- {
856
- source: { uri: image },
857
- style: { width: 96, height: 96, borderRadius: radius2.md },
858
- accessible: false
859
- }
860
- ),
861
- /* @__PURE__ */ jsxRuntime.jsx(
862
- ChoiceLabel,
863
- {
864
- selected: values.includes(o.value),
865
- text: o.label
866
- }
867
- )
868
- ] }) : /* @__PURE__ */ jsxRuntime.jsx(ChoiceLabel, { selected: values.includes(o.value), text: o.label })
869
- },
870
- o.value
871
- );
872
- }),
873
- none ? /* @__PURE__ */ jsxRuntime.jsx(
874
- Button,
875
- {
876
- label: none.label,
877
- role: multi ? "checkbox" : "radio",
878
- selected: values.includes(none.value),
879
- disabled: !enabled,
880
- onPress: () => pick(none.value)
881
- }
882
- ) : null,
883
- question.allows_other ? /* @__PURE__ */ jsxRuntime.jsx(
884
- OtherText,
885
- {
886
- max: question.other_max_length ?? 500,
887
- enabled,
888
- value: other,
889
- onChange: (text) => {
890
- const kept = values.filter((v) => v !== none?.value);
891
- const withValues = question.kind === "single_choice" || multi;
892
- onChange({
893
- ...withValues && kept.length ? { values: question.kind === "single_choice" ? [] : kept } : {},
894
- ...text === void 0 ? {} : { other_text: text }
895
- });
896
- }
897
- }
898
- ) : null
899
- ] });
900
- }
901
- function ChoiceLabel(props) {
902
- const { colors: colors2, font: font2 } = useTheme();
903
- return /* @__PURE__ */ jsxRuntime.jsx(
904
- reactNative.Text,
905
- {
906
- style: {
907
- color: props.selected ? colors2.onPrimary : colors2.text,
908
- fontSize: font2.size.md,
909
- textAlign: "center"
910
- },
911
- children: props.text
912
- }
913
- );
914
- }
915
- function OtherText(props) {
916
- const { t } = react$1.useCopy();
917
- const { colors: colors2, radius: radius2, space: space2, font: font2 } = useTheme();
918
- const on = props.value !== void 0;
919
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { gap: space2.xs }, children: [
920
- /* @__PURE__ */ jsxRuntime.jsx(
921
- Button,
922
- {
923
- label: t("questionOther"),
924
- role: "checkbox",
925
- selected: on,
926
- disabled: !props.enabled,
927
- onPress: () => props.onChange(on ? void 0 : "")
928
- }
929
- ),
930
- on ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
931
- /* @__PURE__ */ jsxRuntime.jsx(
932
- reactNative.TextInput,
933
- {
934
- value: props.value,
935
- onChangeText: (text) => props.onChange(text),
936
- accessibilityLabel: t("questionOther"),
937
- testID: "vinaverse-question-other",
938
- editable: props.enabled,
939
- style: {
940
- borderWidth: 1,
941
- borderColor: colors2.border,
942
- borderRadius: radius2.md,
943
- paddingHorizontal: space2.md,
944
- minHeight: 44,
945
- color: colors2.text,
946
- fontSize: font2.size.md
947
- }
948
- }
949
- ),
950
- /* @__PURE__ */ jsxRuntime.jsx(CharactersLeft, { max: props.max, text: props.value ?? "" })
951
- ] }) : null
952
- ] });
953
- }
954
- function CharactersLeft(props) {
955
- const { t } = react$1.useCopy();
956
- const { colors: colors2, font: font2 } = useTheme();
957
- const left = props.max - conversation.codePoints(props.text);
958
- return /* @__PURE__ */ jsxRuntime.jsx(
959
- reactNative.Text,
960
- {
961
- accessibilityLiveRegion: left < 20 ? "polite" : "none",
962
- style: {
963
- color: left < 0 ? colors2.danger : colors2.textMuted,
964
- fontSize: font2.size.xs
965
- },
966
- children: t("questionCharactersLeft", { count: left })
967
- }
968
- );
969
- }
970
- function TextAnswer(props) {
971
- const { colors: colors2, radius: radius2, space: space2, font: font2 } = useTheme();
972
- const long = props.question.kind === "long_text";
973
- const max = props.question.text?.max_length ?? (long ? 2e3 : 200);
974
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { gap: space2.xs }, children: [
975
- /* @__PURE__ */ jsxRuntime.jsx(
976
- reactNative.TextInput,
977
- {
978
- value: props.value,
979
- onChangeText: props.onChange,
980
- accessibilityLabel: props.question.prompt,
981
- editable: props.enabled,
982
- multiline: long,
983
- testID: "vinaverse-question-text",
984
- style: {
985
- borderWidth: 1,
986
- borderColor: colors2.border,
987
- borderRadius: radius2.md,
988
- paddingHorizontal: space2.md,
989
- paddingVertical: space2.sm,
990
- minHeight: long ? 96 : 44,
991
- color: colors2.text,
992
- fontSize: font2.size.md,
993
- textAlignVertical: long ? "top" : "center"
994
- }
995
- }
996
- ),
997
- /* @__PURE__ */ jsxRuntime.jsx(CharactersLeft, { max, text: props.value })
998
- ] });
999
- }
1000
- function NumberAnswer(props) {
1001
- const range = props.question.number ?? { min: 0, max: 100, step: 1 };
1002
- const { colors: colors2, space: space2, font: font2 } = useTheme();
1003
- const value = props.value ?? range.min;
1004
- const clamp = (n) => Math.min(range.max, Math.max(range.min, Number(n.toFixed(6))));
1005
- const shown = `${value}${props.question.number?.unit ? ` ${props.question.number.unit}` : ""}`;
1006
- return /* @__PURE__ */ jsxRuntime.jsxs(
1007
- reactNative.View,
1008
- {
1009
- accessible: true,
1010
- accessibilityRole: "adjustable",
1011
- accessibilityLabel: props.question.prompt,
1012
- accessibilityValue: {
1013
- min: range.min,
1014
- max: range.max,
1015
- now: value,
1016
- text: shown
1017
- },
1018
- accessibilityActions: [{ name: "increment" }, { name: "decrement" }],
1019
- testID: "vinaverse-question-number",
1020
- onAccessibilityAction: (e) => props.onChange(
1021
- clamp(
1022
- value + (e.nativeEvent.actionName === "increment" ? range.step : -range.step)
1023
- )
1024
- ),
1025
- style: { flexDirection: "row", alignItems: "center", gap: space2.md },
1026
- children: [
1027
- /* @__PURE__ */ jsxRuntime.jsx(
1028
- Button,
1029
- {
1030
- label: "\u2212",
1031
- disabled: !props.enabled || value <= range.min,
1032
- onPress: () => props.onChange(clamp(value - range.step))
1033
- }
1034
- ),
1035
- /* @__PURE__ */ jsxRuntime.jsx(
1036
- reactNative.Text,
1037
- {
1038
- style: {
1039
- color: colors2.text,
1040
- fontSize: font2.size.lg,
1041
- minWidth: 64,
1042
- textAlign: "center"
1043
- },
1044
- children: shown
1045
- }
1046
- ),
1047
- /* @__PURE__ */ jsxRuntime.jsx(
1048
- Button,
1049
- {
1050
- label: "+",
1051
- disabled: !props.enabled || value >= range.max,
1052
- onPress: () => props.onChange(clamp(value + range.step))
1053
- }
1054
- )
1055
- ]
1056
- }
1057
- );
1058
- }
1059
- function ScaleAnswer(props) {
1060
- const scale = props.question.scale;
1061
- const { colors: colors2, space: space2, font: font2 } = useTheme();
1062
- if (!scale) return null;
1063
- const points = [];
1064
- for (let n = scale.min; n <= scale.max && points.length < 21; n += scale.step)
1065
- points.push(n);
1066
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { gap: space2.xs }, children: [
1067
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { flexDirection: "row", flexWrap: "wrap", gap: space2.xs }, children: points.map((n) => /* @__PURE__ */ jsxRuntime.jsx(
1068
- Button,
1069
- {
1070
- label: String(n),
1071
- role: "radio",
1072
- disabled: !props.enabled,
1073
- onPress: () => props.onPick(n)
1074
- },
1075
- n
1076
- )) }),
1077
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { flexDirection: "row", justifyContent: "space-between" }, children: [
1078
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: colors2.textMuted, fontSize: font2.size.xs }, children: scale.min_label }),
1079
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: colors2.textMuted, fontSize: font2.size.xs }, children: scale.max_label })
1080
- ] })
1081
- ] });
1082
- }
1083
- var iso = (y, m, d) => `${String(y).padStart(4, "0")}-${String(m + 1).padStart(2, "0")}-${String(d).padStart(2, "0")}`;
1084
- function DateAnswer(props) {
1085
- const { locale } = react$1.useCopy();
1086
- const { colors: colors2, space: space2, font: font2 } = useTheme();
1087
- const bounds = props.question.date;
1088
- const start = props.value ?? bounds?.min ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
1089
- const [month, setMonth] = react.useState(() => ({
1090
- y: Number(start.slice(0, 4)),
1091
- m: Number(start.slice(5, 7)) - 1
1092
- }));
1093
- const days = new Date(Date.UTC(month.y, month.m + 1, 0)).getUTCDate();
1094
- const title = (() => {
1095
- try {
1096
- return new Intl.DateTimeFormat(locale, {
1097
- month: "long",
1098
- year: "numeric",
1099
- timeZone: "UTC"
1100
- }).format(new Date(Date.UTC(month.y, month.m, 1)));
1101
- } catch {
1102
- return `${month.y}-${month.m + 1}`;
1103
- }
1104
- })();
1105
- const move = (by) => {
1106
- const d = new Date(Date.UTC(month.y, month.m + by, 1));
1107
- setMonth({ y: d.getUTCFullYear(), m: d.getUTCMonth() });
1108
- };
1109
- const outside = (date) => bounds?.min !== void 0 && date < bounds.min || bounds?.max !== void 0 && date > bounds.max;
1110
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { gap: space2.xs }, children: [
1111
- /* @__PURE__ */ jsxRuntime.jsxs(
1112
- reactNative.View,
1113
- {
1114
- style: {
1115
- flexDirection: "row",
1116
- alignItems: "center",
1117
- justifyContent: "space-between"
1118
- },
1119
- children: [
1120
- /* @__PURE__ */ jsxRuntime.jsx(
1121
- Button,
1122
- {
1123
- label: "\u2039",
1124
- variant: "text",
1125
- disabled: !props.enabled,
1126
- onPress: () => move(-1)
1127
- }
1128
- ),
1129
- /* @__PURE__ */ jsxRuntime.jsx(
1130
- reactNative.Text,
1131
- {
1132
- accessibilityRole: "header",
1133
- style: { color: colors2.text, fontSize: font2.size.md },
1134
- children: title
1135
- }
1136
- ),
1137
- /* @__PURE__ */ jsxRuntime.jsx(
1138
- Button,
1139
- {
1140
- label: "\u203A",
1141
- variant: "text",
1142
- disabled: !props.enabled,
1143
- onPress: () => move(1)
1144
- }
1145
- )
1146
- ]
1147
- }
1148
- ),
1149
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { flexDirection: "row", flexWrap: "wrap", gap: space2.xxs }, children: Array.from({ length: days }, (_, i) => {
1150
- const date = iso(month.y, month.m, i + 1);
1151
- return /* @__PURE__ */ jsxRuntime.jsx(
1152
- Button,
1153
- {
1154
- label: String(i + 1),
1155
- hint: react$1.formatDate(date, locale),
1156
- role: "radio",
1157
- selected: props.value === date,
1158
- disabled: !props.enabled || outside(date),
1159
- onPress: () => props.onChange(date)
1160
- },
1161
- date
1162
- );
1163
- }) }),
1164
- props.value ? /* @__PURE__ */ jsxRuntime.jsx(Body, { muted: true, children: react$1.formatDate(props.value, locale) }) : null
1165
- ] });
1166
- }
1167
- function RateEach(props) {
1168
- const { question } = props;
1169
- const { t } = react$1.useCopy();
1170
- const { colors: colors2, space: space2, font: font2 } = useTheme();
1171
- const answered = new Map(
1172
- (question.row_answers ?? []).map((r) => [
1173
- r.question_id,
1174
- (r.answer.values ?? [])[0]
1175
- ])
1176
- );
1177
- const open = (question.rows ?? []).filter(
1178
- (r) => !props.locked.includes(r.question_id)
1179
- );
1180
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { gap: space2.md }, children: [
1181
- (question.rows ?? []).map((row) => {
1182
- const done = props.locked.includes(row.question_id);
1183
- return /* @__PURE__ */ jsxRuntime.jsxs(
1184
- reactNative.View,
1185
- {
1186
- accessibilityLabel: row.label,
1187
- style: { gap: space2.xs },
1188
- children: [
1189
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: colors2.text, fontSize: font2.size.sm }, children: row.label }),
1190
- /* @__PURE__ */ jsxRuntime.jsx(
1191
- reactNative.View,
1192
- {
1193
- style: { flexDirection: "row", flexWrap: "wrap", gap: space2.xs },
1194
- children: (question.options ?? []).map((o) => /* @__PURE__ */ jsxRuntime.jsx(
1195
- Button,
1196
- {
1197
- label: o.label,
1198
- role: "radio",
1199
- selected: answered.get(row.question_id) === o.value,
1200
- disabled: !props.enabled || done,
1201
- onPress: () => props.send({ values: [o.value] }, row.question_id)
1202
- },
1203
- o.value
1204
- ))
1205
- }
1206
- )
1207
- ]
1208
- },
1209
- row.question_id
1210
- );
1211
- }),
1212
- question.required || open.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(
1213
- Button,
1214
- {
1215
- label: t("questionSkip"),
1216
- variant: "text",
1217
- disabled: !props.enabled,
1218
- onPress: () => {
1219
- for (const row of open)
1220
- props.send({ skipped: true }, row.question_id);
1221
- }
1222
- }
1223
- )
1224
- ] });
1225
- }
1226
- function answerText(question, locale, otherLabel) {
1227
- const answer = question.answer;
1228
- if (!answer || answer.skipped) return null;
1229
- const labels = new Map(
1230
- (question.options ?? []).map((o) => [o.value, o.label])
1231
- );
1232
- if (question.none_of_the_above)
1233
- labels.set(
1234
- question.none_of_the_above.value,
1235
- question.none_of_the_above.label
1236
- );
1237
- const parts = [
1238
- ...(answer.values ?? []).map((v) => labels.get(v) ?? v),
1239
- ...answer.other_text ? [`${otherLabel}: ${answer.other_text}`] : [],
1240
- ...answer.text ? [answer.text] : [],
1241
- ...answer.number !== void 0 ? [String(answer.number)] : [],
1242
- ...answer.date ? [react$1.formatDate(answer.date, locale)] : [],
1243
- ...answer.upload_ref ? ["\u{1F4F7}"] : []
1244
- ];
1245
- return parts.length ? parts.join(", ") : null;
1246
- }
1247
- function TimeSlotsCard(props) {
1248
- const card = cardOf(props.card);
1249
- const { locale } = react$1.useCopy();
1250
- const { timeZone } = useChat();
1251
- const { colors: colors2, radius: radius2, space: space2, font: font2 } = useTheme();
1252
- const slots = (card.slots ?? []).map(
1253
- (s) => react$1.formatTimeRange(s.start, s.end, locale, timeZone)
1254
- );
1255
- return /* @__PURE__ */ jsxRuntime.jsxs(
1256
- CardFrame,
1257
- {
1258
- label: [card.title, ...slots].join(", "),
1259
- restored: props.restored,
1260
- testID: `vinaverse-card-${card.id}`,
1261
- children: [
1262
- /* @__PURE__ */ jsxRuntime.jsx(Title, { children: card.title }),
1263
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { flexDirection: "row", flexWrap: "wrap", gap: space2.xs }, children: slots.map((s) => /* @__PURE__ */ jsxRuntime.jsx(
1264
- reactNative.Text,
1265
- {
1266
- style: {
1267
- color: colors2.text,
1268
- borderWidth: 1,
1269
- borderColor: colors2.border,
1270
- borderRadius: radius2.pill,
1271
- paddingHorizontal: space2.md,
1272
- paddingVertical: space2.xs,
1273
- fontSize: font2.size.sm
1274
- },
1275
- children: s
1276
- },
1277
- s
1278
- )) })
1279
- ]
1280
- }
1281
- );
1282
- }
1283
- var DEFAULTS = {
1284
- proposal: ProposalCard,
1285
- question: QuestionCard,
1286
- next_step: NextStepCard,
1287
- time_slots: TimeSlotsCard,
1288
- professional: ListingCard,
1289
- workspace: ListingCard,
1290
- links: LinksCard
1291
- };
1292
- function defaultCard(kind) {
1293
- return DEFAULTS[kind] ?? InfoCard;
1294
- }
1295
- var CardView = react.memo(function CardView2(props) {
1296
- const { slots } = useChat();
1297
- const { card, busy } = props.item;
1298
- const Default = defaultCard(card.kind);
1299
- const Custom = slots.cards?.[card.kind];
1300
- const own = { card, busy, restored: props.item.restored === true };
1301
- return Custom ? /* @__PURE__ */ jsxRuntime.jsx(Custom, { ...own, Default }) : /* @__PURE__ */ jsxRuntime.jsx(Default, { ...own });
1302
- });
1303
- var keyOf = (item) => item.key;
1304
- var kindOf = (item) => item.card.kind;
1305
- function CardCarousel(props) {
1306
- const { width } = reactNative.useWindowDimensions();
1307
- const { t } = react$1.useCopy();
1308
- const size3 = Math.min(Math.round(width * 0.8), 360);
1309
- return /* @__PURE__ */ jsxRuntime.jsx(
1310
- reactNative.View,
1311
- {
1312
- accessibilityRole: "list",
1313
- accessibilityLabel: t("cardsInRow", {
1314
- count: String(props.items.length)
1315
- }),
1316
- children: /* @__PURE__ */ jsxRuntime.jsx(
1317
- flashList.FlashList,
1318
- {
1319
- horizontal: true,
1320
- data: props.items,
1321
- keyExtractor: keyOf,
1322
- getItemType: kindOf,
1323
- renderItem: ({ item }) => /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { width: size3 }, children: /* @__PURE__ */ jsxRuntime.jsx(CardView, { item }) }),
1324
- snapToInterval: size3,
1325
- decelerationRate: "fast",
1326
- showsHorizontalScrollIndicator: false
1327
- }
1328
- )
1329
- }
1330
- );
1331
- }
1332
- var ActivityLine = react.memo(function ActivityLine2() {
1333
- const { store } = useChat();
1334
- const { t } = react$1.useCopy();
1335
- const { colors: colors2, space: space2, font: font2 } = useTheme();
1336
- const activity = react$1.useConversationSelector(store, (v) => v.activity);
1337
- const waiting = react$1.useConversationSelector(
1338
- store,
1339
- (v) => v.responding && v.items.at(-1)?.type === "message" && v.items.at(-1).role === "person"
1340
- );
1341
- const name = react$1.useConversationSelector(store, (v) => v.agent.name);
1342
- const running = activity.filter((a) => a.state === "running").at(-1);
1343
- if (!running && !waiting) return null;
1344
- const text = running?.label ?? t("working", { agent: name ?? t("agentFallbackName") });
1345
- return /* @__PURE__ */ jsxRuntime.jsx(
1346
- reactNative.View,
1347
- {
1348
- accessibilityLiveRegion: "polite",
1349
- style: { paddingHorizontal: space2.lg, paddingVertical: space2.sm },
1350
- children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: colors2.textMuted, fontSize: font2.size.sm }, children: text })
1351
- }
1352
- );
1353
- });
1354
- var Avatar = react.memo(function Avatar2(props) {
1355
- const { colors: colors2, size: size3, font: font2 } = useTheme();
1356
- const { slots } = useChat();
1357
- const box = {
1358
- width: size3.avatar,
1359
- height: size3.avatar,
1360
- borderRadius: size3.avatar / 2
1361
- };
1362
- if (props.uri && !props.person) {
1363
- const Img = slots.Image ?? reactNative.Image;
1364
- return /* @__PURE__ */ jsxRuntime.jsx(
1365
- Img,
1366
- {
1367
- source: { uri: props.uri },
1368
- style: box,
1369
- accessibilityIgnoresInvertColors: true,
1370
- accessible: false,
1371
- importantForAccessibility: "no"
1372
- }
1373
- );
1374
- }
1375
- return /* @__PURE__ */ jsxRuntime.jsx(
1376
- reactNative.View,
1377
- {
1378
- accessible: false,
1379
- importantForAccessibility: "no-hide-descendants",
1380
- style: {
1381
- ...box,
1382
- backgroundColor: props.person ? colors2.staffBubble : colors2.primary,
1383
- alignItems: "center",
1384
- justifyContent: "center"
1385
- },
1386
- children: /* @__PURE__ */ jsxRuntime.jsx(
1387
- reactNative.Text,
1388
- {
1389
- style: {
1390
- color: props.person ? colors2.staffText : colors2.onPrimary,
1391
- fontSize: font2.size.sm,
1392
- fontWeight: "600"
1393
- },
1394
- children: props.person ? "\u25C9" : (props.name.trim()[0] ?? "?").toUpperCase()
1395
- }
1396
- )
1397
- }
1398
- );
1399
- });
1400
- function DefaultHeader(props) {
1401
- const { colors: colors2, space: space2, font: font2 } = useTheme();
1402
- const { t } = react$1.useCopy();
1403
- const person = props.takeoverBy !== null;
1404
- const subtitle = person ? t("staffLabel", { by: props.takeoverBy || t("staffFallbackRole") }) : t("agentLabel");
1405
- return /* @__PURE__ */ jsxRuntime.jsxs(
1406
- reactNative.View,
1407
- {
1408
- accessibilityRole: "header",
1409
- accessible: true,
1410
- accessibilityLabel: `${props.name}, ${subtitle}`,
1411
- style: {
1412
- flexDirection: "row",
1413
- alignItems: "center",
1414
- gap: space2.sm,
1415
- paddingHorizontal: space2.lg,
1416
- paddingVertical: space2.sm,
1417
- backgroundColor: colors2.background,
1418
- borderBottomWidth: 1,
1419
- borderBottomColor: colors2.divider
1420
- },
1421
- children: [
1422
- /* @__PURE__ */ jsxRuntime.jsx(Avatar, { name: props.name, uri: props.avatarUrl, person }),
1423
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { flexShrink: 1 }, children: [
1424
- /* @__PURE__ */ jsxRuntime.jsx(
1425
- reactNative.Text,
1426
- {
1427
- numberOfLines: 1,
1428
- style: {
1429
- color: colors2.text,
1430
- fontSize: font2.size.md,
1431
- fontWeight: "600",
1432
- ...font2.family ? { fontFamily: font2.family } : {}
1433
- },
1434
- children: props.name
1435
- }
1436
- ),
1437
- /* @__PURE__ */ jsxRuntime.jsx(
1438
- reactNative.Text,
1439
- {
1440
- numberOfLines: 1,
1441
- style: {
1442
- color: person ? colors2.staffAccent : colors2.textMuted,
1443
- fontSize: font2.size.xs
1444
- },
1445
- children: subtitle
1446
- }
1447
- )
1448
- ] })
1449
- ]
1450
- }
1451
- );
1452
- }
1453
- var ChatHeader = react.memo(function ChatHeader2() {
1454
- const { store, slots, agentAvatar } = useChat();
1455
- const { t } = react$1.useCopy();
1456
- const agent = react$1.useConversationSelector(store, (v) => v.agent);
1457
- const takeover = react$1.useConversationSelector(store, (v) => v.takeover);
1458
- const Header = slots.Header;
1459
- const props = {
1460
- name: agent.name ?? t("agentFallbackName"),
1461
- avatarUrl: agentAvatar ?? agent.avatarUrl,
1462
- takeoverBy: takeover ? takeover.by ?? "" : null
1463
- };
1464
- return Header ? /* @__PURE__ */ jsxRuntime.jsx(Header, { ...props, Default: DefaultHeader }) : /* @__PURE__ */ jsxRuntime.jsx(DefaultHeader, { ...props });
1465
- });
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
- function DefaultComposer(props) {
1498
- const { t, direction } = react$1.useCopy();
1499
- const { colors: colors2, radius: radius2, space: space2, font: font2, size: size3 } = useTheme();
1500
- const [text, setText] = react.useState("");
1501
- const length = conversation.codePoints(text);
1502
- const canSend = text.trim().length > 0 && length <= conversation.MAX_TEXT;
1503
- const send = () => {
1504
- if (!canSend) return;
1505
- props.onSend(text);
1506
- setText("");
1507
- };
1508
- return /* @__PURE__ */ jsxRuntime.jsxs(
1509
- reactNative.View,
1510
- {
1511
- style: {
1512
- flexDirection: "row",
1513
- alignItems: "flex-end",
1514
- gap: space2.sm,
1515
- paddingHorizontal: space2.lg,
1516
- paddingVertical: space2.sm,
1517
- borderTopWidth: 1,
1518
- borderTopColor: colors2.divider,
1519
- backgroundColor: colors2.background
1520
- },
1521
- children: [
1522
- /* @__PURE__ */ jsxRuntime.jsx(
1523
- reactNative.TextInput,
1524
- {
1525
- value: text,
1526
- onChangeText: setText,
1527
- placeholder: props.placeholder,
1528
- placeholderTextColor: colors2.textMuted,
1529
- accessibilityLabel: props.placeholder,
1530
- multiline: true,
1531
- maxLength: conversation.MAX_TEXT * 2,
1532
- testID: "vinaverse-composer-input",
1533
- style: {
1534
- flex: 1,
1535
- minHeight: size3.touchTarget,
1536
- maxHeight: 140,
1537
- paddingHorizontal: space2.md,
1538
- paddingVertical: space2.sm,
1539
- borderRadius: radius2.lg,
1540
- borderWidth: 1,
1541
- borderColor: colors2.border,
1542
- color: colors2.text,
1543
- backgroundColor: colors2.surface,
1544
- fontSize: font2.size.md,
1545
- textAlign: direction === "rtl" ? "right" : "left",
1546
- writingDirection: direction,
1547
- ...font2.family ? { fontFamily: font2.family } : {}
1548
- }
1549
- }
1550
- ),
1551
- props.responding && !text ? /* @__PURE__ */ jsxRuntime.jsx(
1552
- Button,
1553
- {
1554
- label: t("stop"),
1555
- onPress: props.onStop,
1556
- testID: "vinaverse-stop"
1557
- }
1558
- ) : /* @__PURE__ */ jsxRuntime.jsx(
1559
- Button,
1560
- {
1561
- label: t("send"),
1562
- variant: "primary",
1563
- disabled: !canSend,
1564
- onPress: send,
1565
- testID: "vinaverse-send"
1566
- }
1567
- )
1568
- ]
1569
- }
1570
- );
1571
- }
1572
- var Composer = react.memo(function Composer2(props) {
1573
- const { store, slots } = useChat();
1574
- const { t } = react$1.useCopy();
1575
- const takeover = react$1.useConversationSelector(store, (v) => v.takeover);
1576
- const name = react$1.useConversationSelector(store, (v) => v.agent.name);
1577
- const responding = react$1.useConversationSelector(store, (v) => v.responding);
1578
- const { onError } = props;
1579
- const onSend = react.useCallback(
1580
- (text) => {
1581
- try {
1582
- store.send(text);
1583
- } catch (error) {
1584
- onError?.(error);
1585
- }
1586
- },
1587
- [store, onError]
1588
- );
1589
- const onStop = react.useCallback(() => store.cancel(), [store]);
1590
- const placeholder = takeover ? t("composerPlaceholderTakeover", {
1591
- by: takeover.by || t("staffFallbackRole")
1592
- }) : t("composerPlaceholder", { agent: name ?? t("agentFallbackName") });
1593
- const Slot = slots.Composer;
1594
- const own = { placeholder, responding, onSend, onStop };
1595
- return Slot ? /* @__PURE__ */ jsxRuntime.jsx(Slot, { ...own, Default: DefaultComposer }) : /* @__PURE__ */ jsxRuntime.jsx(DefaultComposer, { ...own });
1596
- });
1597
- var DisclosureBar = react.memo(function DisclosureBar2() {
1598
- const { store } = useChat();
1599
- const { t } = react$1.useCopy();
1600
- const theme = useTheme();
1601
- const { space: space2, font: font2 } = theme;
1602
- const disclosure = react$1.useConversationSelector(store, (v) => v.disclosure);
1603
- const [open, setOpen] = react.useState(false);
1604
- const legible = tokens.contrastRatio(
1605
- theme.colors.disclosureText,
1606
- theme.colors.disclosureBackground
1607
- ) >= 4.5;
1608
- const pair = legible ? theme.colors : tokens.colors(theme.scheme);
1609
- const text = disclosure ?? t("disclosureFallback");
1610
- return /* @__PURE__ */ jsxRuntime.jsx(
1611
- reactNative.Pressable,
1612
- {
1613
- accessibilityRole: "text",
1614
- accessibilityLabel: text,
1615
- onPress: () => setOpen((o) => !o),
1616
- testID: "vinaverse-disclosure",
1617
- style: {
1618
- backgroundColor: pair.disclosureBackground,
1619
- paddingHorizontal: space2.lg,
1620
- paddingVertical: space2.xs
1621
- },
1622
- children: /* @__PURE__ */ jsxRuntime.jsx(
1623
- reactNative.Text,
1624
- {
1625
- numberOfLines: open ? void 0 : 2,
1626
- style: {
1627
- color: pair.disclosureText,
1628
- // never below the disclosure's minimum, whatever the tenant's type scale
1629
- fontSize: Math.max(font2.size.xs, tokens.size.disclosureFontMin),
1630
- lineHeight: Math.max(font2.size.xs, tokens.size.disclosureFontMin) * font2.lineHeight
1631
- },
1632
- children: text
1633
- }
1634
- )
1635
- }
1636
- );
1637
- });
1638
- function FailureActionButton(props) {
1639
- const { handlers, failureAction } = useChat();
1640
- const { t } = react$1.useCopy();
1641
- if (!failureAction) return null;
1642
- return /* @__PURE__ */ jsxRuntime.jsx(
1643
- Button,
1644
- {
1645
- label: failureAction.label ?? t("talkToPerson"),
1646
- variant: "text",
1647
- onPress: () => handlers.current.failureAction?.onPress(props.state)
1648
- }
1649
- );
1650
- }
1651
- function FailureSlot(props) {
1652
- const { slot: Slot, state, Default } = props;
1653
- return Slot ? /* @__PURE__ */ jsxRuntime.jsx(Slot, { state, Default }) : /* @__PURE__ */ jsxRuntime.jsx(Default, { state });
1654
- }
1655
- function DefaultBubble(props) {
1656
- const { colors: colors2, radius: radius2, space: space2, font: font2 } = useTheme();
1657
- const role = props.item.role;
1658
- const [background, foreground] = role === "person" ? [colors2.personBubble, colors2.personText] : role === "staff" ? [colors2.staffBubble, colors2.staffText] : [colors2.agentBubble, colors2.agentText];
1659
- return /* @__PURE__ */ jsxRuntime.jsx(
1660
- reactNative.View,
1661
- {
1662
- style: {
1663
- backgroundColor: background,
1664
- borderRadius: radius2.lg,
1665
- paddingHorizontal: space2.md,
1666
- paddingVertical: space2.sm
1667
- },
1668
- children: /* @__PURE__ */ jsxRuntime.jsx(
1669
- reactNative.Text,
1670
- {
1671
- selectable: true,
1672
- style: {
1673
- color: foreground,
1674
- fontSize: font2.size.md,
1675
- lineHeight: font2.size.md * font2.lineHeight,
1676
- ...font2.family ? { fontFamily: font2.family } : {}
1677
- },
1678
- children: props.text
1679
- }
1680
- )
1681
- }
1682
- );
1683
- }
1684
- function useAuthor(item) {
1685
- const { t } = react$1.useCopy();
1686
- const { store } = useChat();
1687
- const name = store.getSnapshot().agent.name ?? t("agentFallbackName");
1688
- const by = store.getSnapshot().takeover?.by;
1689
- if (item.role === "person") return t("you");
1690
- if (item.role === "staff")
1691
- return t("staffLabel", { by: by || t("staffFallbackRole") });
1692
- return `${name} \xB7 ${t("agentLabel")}`;
1693
- }
1694
- var MessageBubble = react.memo(function MessageBubble2(props) {
1695
- const { item } = props;
1696
- return /* @__PURE__ */ jsxRuntime.jsx(Frame, { item, text: item.text, showAuthor: props.showAuthor });
1697
- });
1698
- var StreamingBubble = react.memo(function StreamingBubble2(props) {
1699
- const { store } = useChat();
1700
- const text = react$1.useStreamingText(store, props.item.key) ?? "";
1701
- return /* @__PURE__ */ jsxRuntime.jsx(Frame, { item: props.item, text, showAuthor: props.showAuthor });
1702
- });
1703
- function Frame(props) {
1704
- const { item, text } = props;
1705
- const { store, slots } = useChat();
1706
- const { t } = react$1.useCopy();
1707
- const { colors: colors2, space: space2, font: font2 } = useTheme();
1708
- const author = useAuthor(item);
1709
- const mine = item.role === "person";
1710
- const status = item.state === "sending" ? t("messageSending") : item.state === "held" ? t("messageHeld") : item.state === "not_sent" ? item.rejection?.message || t("messageNotSent") : item.state === "delivered" ? t("messageDelivered") : item.partial ? t("messageCutOff") : null;
1711
- const Bubble = slots.MessageBubble;
1712
- const bubble = Bubble ? /* @__PURE__ */ jsxRuntime.jsx(Bubble, { item, text, Default: DefaultBubble }) : /* @__PURE__ */ jsxRuntime.jsx(DefaultBubble, { item, text });
1713
- return /* @__PURE__ */ jsxRuntime.jsxs(
1714
- reactNative.View,
1715
- {
1716
- accessible: true,
1717
- accessibilityLabel: [author, text, status].filter(Boolean).join(". "),
1718
- style: {
1719
- alignSelf: mine ? "flex-end" : "flex-start",
1720
- maxWidth: "85%",
1721
- marginHorizontal: space2.lg,
1722
- marginTop: props.showAuthor ? space2.md : space2.xs,
1723
- opacity: item.state === "sending" || item.state === "held" ? 0.75 : 1
1724
- },
1725
- children: [
1726
- props.showAuthor && !mine ? /* @__PURE__ */ jsxRuntime.jsx(
1727
- reactNative.Text,
1728
- {
1729
- style: {
1730
- color: item.role === "staff" ? colors2.staffAccent : colors2.textMuted,
1731
- fontSize: font2.size.xs,
1732
- marginBottom: space2.xxs
1733
- },
1734
- children: author
1735
- }
1736
- ) : null,
1737
- bubble,
1738
- status ? /* @__PURE__ */ jsxRuntime.jsxs(
1739
- reactNative.View,
1740
- {
1741
- style: {
1742
- flexDirection: "row",
1743
- alignItems: "center",
1744
- justifyContent: mine ? "flex-end" : "flex-start",
1745
- gap: space2.xs,
1746
- marginTop: space2.xxs
1747
- },
1748
- children: [
1749
- /* @__PURE__ */ jsxRuntime.jsx(
1750
- reactNative.Text,
1751
- {
1752
- style: {
1753
- color: item.state === "not_sent" ? colors2.danger : colors2.textMuted,
1754
- fontSize: font2.size.xs
1755
- },
1756
- children: status
1757
- }
1758
- ),
1759
- item.state === "not_sent" ? /* @__PURE__ */ jsxRuntime.jsx(
1760
- Button,
1761
- {
1762
- label: t("tryAgain"),
1763
- variant: "text",
1764
- onPress: () => {
1765
- store.retry(item.key);
1766
- }
1767
- }
1768
- ) : null
1769
- ]
1770
- }
1771
- ) : null
1772
- ]
1773
- }
1774
- );
1775
- }
1776
- function useNativeLifecycle(store) {
1777
- react.useEffect(() => {
1778
- const apply = (state) => store.setForeground(state === "active");
1779
- apply(reactNative.AppState.currentState);
1780
- const subscription = reactNative.AppState.addEventListener("change", apply);
1781
- return () => subscription.remove();
1782
- }, [store]);
1783
- }
1784
- function useReducedMotion() {
1785
- const [reduced, setReduced] = react.useState(false);
1786
- react.useEffect(() => {
1787
- let live = true;
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;
1804
- }
1805
- function announce(text) {
1806
- if (text) reactNative.AccessibilityInfo.announceForAccessibility(text);
1807
- }
1808
- var SystemRow = react.memo(function SystemRow2(props) {
1809
- const { t } = react$1.useCopy();
1810
- const { store, slots } = useChat();
1811
- const conversationId = react$1.useConversationSelector(
1812
- store,
1813
- (v) => v.conversationId
1814
- );
1815
- const { event, data } = props.item;
1816
- if (event === "turn_failed") {
1817
- const key = props.item.key;
1818
- const state = {
1819
- kind: "turn_failed",
1820
- reason: typeof data.code === "string" ? data.code : null,
1821
- retry: data.retry === true ? () => void store.retryTurn(key) : void 0,
1822
- conversationId
1823
- };
1824
- return /* @__PURE__ */ jsxRuntime.jsx(
1825
- FailureSlot,
1826
- {
1827
- slot: slots.Error,
1828
- state,
1829
- Default: DefaultTurnFailed
1830
- }
1831
- );
1832
- }
1833
- const agent = store.getSnapshot().agent.name ?? t("agentFallbackName");
1834
- const text = (() => {
1835
- switch (event) {
1836
- case "takeover_started":
1837
- return t("takeoverStarted", {
1838
- by: data.by || t("staffFallbackRole")
1839
- });
1840
- case "takeover_ended":
1841
- return t("takeoverEnded", { agent });
1842
- case "handoff_created":
1843
- return data.expected_response ? t("handoffCreated", { expected: data.expected_response }) : t("handoffCreatedNoTime");
1844
- case "flow_completed":
1845
- return data.result === "ok" ? t("flowSent") : data.result === "failed" ? t("flowNotSent") : null;
1846
- default:
1847
- return null;
1848
- }
1849
- })();
1850
- if (!text) return null;
1851
- return /* @__PURE__ */ jsxRuntime.jsx(Line, { text });
1852
- });
1853
- function DefaultTurnFailed(props) {
1854
- const { t } = react$1.useCopy();
1855
- const { failureAction } = useChat();
1856
- const text = t("turnFailed");
1857
- if (!failureAction) return /* @__PURE__ */ jsxRuntime.jsx(Line, { text, danger: true });
1858
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { alignItems: "center" }, children: [
1859
- /* @__PURE__ */ jsxRuntime.jsx(Line, { text, danger: true }),
1860
- /* @__PURE__ */ jsxRuntime.jsx(FailureActionButton, { state: props.state })
1861
- ] });
1862
- }
1863
- function Line(props) {
1864
- const { colors: colors2, space: space2, font: font2 } = useTheme();
1865
- return /* @__PURE__ */ jsxRuntime.jsx(
1866
- reactNative.View,
1867
- {
1868
- accessible: true,
1869
- accessibilityLabel: props.text,
1870
- style: {
1871
- alignItems: "center",
1872
- paddingHorizontal: space2.xl,
1873
- paddingVertical: space2.sm
1874
- },
1875
- children: /* @__PURE__ */ jsxRuntime.jsx(
1876
- reactNative.Text,
1877
- {
1878
- style: {
1879
- color: props.danger ? colors2.danger : colors2.textMuted,
1880
- fontSize: font2.size.sm,
1881
- textAlign: "center"
1882
- },
1883
- children: props.text
1884
- }
1885
- )
1886
- }
1887
- );
1888
- }
1889
- var Welcome = react.memo(function Welcome2(props) {
1890
- const { colors: colors2, radius: radius2, space: space2, font: font2 } = useTheme();
1891
- return /* @__PURE__ */ jsxRuntime.jsxs(
1892
- reactNative.View,
1893
- {
1894
- style: { padding: space2.lg, gap: space2.md },
1895
- testID: "vinaverse-welcome",
1896
- children: [
1897
- /* @__PURE__ */ jsxRuntime.jsx(
1898
- reactNative.Text,
1899
- {
1900
- style: {
1901
- alignSelf: "flex-start",
1902
- maxWidth: "85%",
1903
- color: colors2.agentText,
1904
- backgroundColor: colors2.agentBubble,
1905
- borderRadius: radius2.lg,
1906
- paddingHorizontal: space2.md,
1907
- paddingVertical: space2.sm,
1908
- fontSize: font2.size.md,
1909
- lineHeight: font2.size.md * font2.lineHeight
1910
- },
1911
- children: props.welcome.text
1912
- }
1913
- ),
1914
- 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(
1915
- Button,
1916
- {
1917
- label: chip.label,
1918
- onPress: () => props.onChip(chip.message)
1919
- },
1920
- chip.label
1921
- )) }) : null
1922
- ]
1923
- }
1924
- );
1925
- });
1926
- var keyOf2 = (item) => item.key;
1927
- function itemType(item) {
1928
- if (item.type === "card") return `card:${item.card.kind}`;
1929
- if (item.type === "message")
1930
- return item.state === "streaming" ? "streaming" : `message:${item.role}`;
1931
- return "system";
1932
- }
1933
- function authorOf(item) {
1934
- return item?.type === "message" ? item.role : null;
1935
- }
1936
- function carousels(items, previous) {
1937
- const runs = /* @__PURE__ */ new Map();
1938
- const inside = /* @__PURE__ */ new Set();
1939
- const groupOf = (item) => {
1940
- if (item?.type !== "card") return null;
1941
- const group = item.card.card.group;
1942
- return group?.layout === "carousel" && typeof group.id === "string" ? group.id : null;
1943
- };
1944
- for (let i = 0; i < items.length; i++) {
1945
- const id = groupOf(items[i]);
1946
- if (id === null) continue;
1947
- let end = i + 1;
1948
- while (end < items.length && groupOf(items[end]) === id) end++;
1949
- if (end - i > 1) {
1950
- const run = items.slice(i, end);
1951
- const key = run[0]?.key;
1952
- const before = previous.get(key);
1953
- runs.set(
1954
- key,
1955
- before && before.length === run.length && before.every((c, n) => c === run[n]) ? before : run
1956
- );
1957
- for (const card of run.slice(1)) inside.add(card.key);
1958
- }
1959
- i = end - 1;
1960
- }
1961
- return { runs, inside };
1962
- }
1963
- var Row = react.memo(function Row2(props) {
1964
- const { item } = props;
1965
- const { slots } = useChat();
1966
- const Group = slots.CardGroup;
1967
- if (props.inside) return null;
1968
- if (props.run && Group) return /* @__PURE__ */ jsxRuntime.jsx(Group, { items: props.run });
1969
- if (item.type === "card") return /* @__PURE__ */ jsxRuntime.jsx(CardView, { item });
1970
- if (item.type === "system") return /* @__PURE__ */ jsxRuntime.jsx(SystemRow, { item });
1971
- return item.state === "streaming" ? /* @__PURE__ */ jsxRuntime.jsx(StreamingBubble, { item, showAuthor: props.showAuthor }) : /* @__PURE__ */ jsxRuntime.jsx(MessageBubble, { item, showAuthor: props.showAuthor });
1972
- });
1973
- var MessageList = react.memo(function MessageList2() {
1974
- const { store, slots } = useChat();
1975
- const { t } = react$1.useCopy();
1976
- const { space: space2 } = useTheme();
1977
- const reducedMotion = useReducedMotion();
1978
- const items = react$1.useConversationSelector(store, (v) => v.items);
1979
- const opening = react$1.useConversationSelector(
1980
- store,
1981
- (v) => v.status === "starting" || v.status === "connecting"
1982
- );
1983
- const agentName = react$1.useConversationSelector(store, (v) => v.agent.name);
1984
- const welcome = react$1.useConversationSelector(store, (v) => v.welcome);
1985
- useAnnounceReplies(items);
1986
- const Group = slots.CardGroup;
1987
- const runsRef = react.useRef(/* @__PURE__ */ new Map());
1988
- const grouping = react.useMemo(
1989
- () => Group ? carousels(items, runsRef.current) : null,
1990
- [items, Group]
1991
- );
1992
- runsRef.current = grouping?.runs ?? /* @__PURE__ */ new Map();
1993
- const itemsRef = react.useRef(items);
1994
- itemsRef.current = items;
1995
- const groupingRef = react.useRef(grouping);
1996
- groupingRef.current = grouping;
1997
- const renderItem = react.useCallback(
1998
- ({ item, index }) => /* @__PURE__ */ jsxRuntime.jsx(
1999
- Row,
2000
- {
2001
- item,
2002
- showAuthor: authorOf(item) !== authorOf(itemsRef.current[index - 1]),
2003
- run: groupingRef.current?.runs.get(item.key),
2004
- inside: groupingRef.current?.inside.has(item.key) === true
2005
- }
2006
- ),
2007
- []
2008
- );
2009
- const onChip = react.useCallback(
2010
- (message) => void store.send(message),
2011
- [store]
2012
- );
2013
- const Empty = slots.EmptyState;
2014
- const empty = opening ? /* @__PURE__ */ jsxRuntime.jsx(ChatSkeleton, {}) : Empty ? /* @__PURE__ */ jsxRuntime.jsx(
2015
- Empty,
2016
- {
2017
- agentName: agentName ?? t("agentFallbackName"),
2018
- welcome,
2019
- onChip
2020
- }
2021
- ) : welcome ? /* @__PURE__ */ jsxRuntime.jsx(Welcome, { welcome, onChip }) : null;
2022
- const props = react.useMemo(
2023
- () => ({
2024
- data: items,
2025
- renderItem,
2026
- keyExtractor: keyOf2,
2027
- getItemType: itemType,
2028
- maintainVisibleContentPosition: {
2029
- startRenderingFromBottom: true,
2030
- autoscrollToBottomThreshold: 0.2,
2031
- animateAutoScrollToBottom: !reducedMotion
2032
- },
2033
- ListFooterComponent: /* @__PURE__ */ jsxRuntime.jsx(ActivityLine, {}),
2034
- ListEmptyComponent: empty,
2035
- keyboardShouldPersistTaps: "handled",
2036
- contentContainerStyle: { paddingVertical: space2.sm }
2037
- }),
2038
- [items, renderItem, reducedMotion, empty, space2.sm]
2039
- );
2040
- const List = slots.ListComponent;
2041
- return List ? /* @__PURE__ */ jsxRuntime.jsx(List, { ...props }) : /* @__PURE__ */ jsxRuntime.jsx(flashList.FlashList, { ...props });
2042
- });
2043
- function useAnnounceReplies(items) {
2044
- const seen = react.useRef(void 0);
2045
- const { t } = react$1.useCopy();
2046
- const { store } = useChat();
2047
- react.useEffect(() => {
2048
- const last = items.at(-1);
2049
- if (seen.current === void 0) {
2050
- seen.current = last?.key ?? "";
2051
- return;
2052
- }
2053
- if (last?.type !== "message" || last.role === "person") return;
2054
- if (last.state !== "sent" || last.key === seen.current) return;
2055
- seen.current = last.key;
2056
- const author = last.role === "staff" ? t("staffLabel", {
2057
- by: store.getSnapshot().takeover?.by || t("staffFallbackRole")
2058
- }) : store.getSnapshot().agent.name ?? t("agentFallbackName");
2059
- announce(`${author}: ${last.text}`);
2060
- }, [items, t, store]);
2061
- }
2062
- var CONNECTING_DELAY = tokens.motion.bannerDelay;
2063
- var StatusBanner = react.memo(function StatusBanner2() {
2064
- const { store, slots } = useChat();
2065
- const { t } = react$1.useCopy();
2066
- const banner = react$1.useConversationSelector(store, (v) => v.banner);
2067
- const status = react$1.useConversationSelector(store, (v) => v.status);
2068
- const conversationId = react$1.useConversationSelector(
2069
- store,
2070
- (v) => v.conversationId
2071
- );
2072
- const unavailable = react.useMemo(
2073
- () => ({
2074
- kind: "unavailable",
2075
- reason: status,
2076
- retry: () => store.start(),
2077
- conversationId
2078
- }),
2079
- [store, status, conversationId]
2080
- );
2081
- const [late, setLate] = react.useState(false);
2082
- react.useEffect(() => {
2083
- setLate(false);
2084
- if (banner !== "connecting") return;
2085
- const timer = setTimeout(() => setLate(true), CONNECTING_DELAY);
2086
- return () => clearTimeout(timer);
2087
- }, [banner]);
2088
- if (banner === null || banner === "connecting" && !late) return null;
2089
- if (banner === "unavailable")
2090
- return /* @__PURE__ */ jsxRuntime.jsx(
2091
- FailureSlot,
2092
- {
2093
- slot: slots.Unavailable,
2094
- state: unavailable,
2095
- Default: DefaultUnavailable
2096
- }
2097
- );
2098
- const text = {
2099
- connecting: t("bannerConnecting"),
2100
- reconnecting: t("bannerReconnecting"),
2101
- offline: t("bannerOffline"),
2102
- continued_elsewhere: t("bannerContinuedElsewhere")
2103
- }[banner];
2104
- const action = banner === "continued_elsewhere" ? /* @__PURE__ */ jsxRuntime.jsx(
2105
- Button,
2106
- {
2107
- label: t("continueHere"),
2108
- variant: "text",
2109
- onPress: () => void store.continueHere()
2110
- }
2111
- ) : banner === "offline" ? /* @__PURE__ */ jsxRuntime.jsx(
2112
- Button,
2113
- {
2114
- label: t("tryAgain"),
2115
- variant: "text",
2116
- onPress: () => store.start()
2117
- }
2118
- ) : null;
2119
- return /* @__PURE__ */ jsxRuntime.jsx(Banner, { text, children: action });
2120
- });
2121
- function DefaultUnavailable(props) {
2122
- const { t } = react$1.useCopy();
2123
- const { retry } = props.state;
2124
- return /* @__PURE__ */ jsxRuntime.jsxs(Banner, { text: t("bannerUnavailable"), children: [
2125
- retry ? /* @__PURE__ */ jsxRuntime.jsx(Button, { label: t("tryAgain"), variant: "text", onPress: retry }) : null,
2126
- /* @__PURE__ */ jsxRuntime.jsx(FailureActionButton, { state: props.state })
2127
- ] });
2128
- }
2129
- function Banner(props) {
2130
- const { colors: colors2, space: space2, font: font2 } = useTheme();
2131
- return /* @__PURE__ */ jsxRuntime.jsxs(
2132
- reactNative.View,
2133
- {
2134
- accessibilityLiveRegion: "polite",
2135
- accessibilityRole: "alert",
2136
- style: {
2137
- flexDirection: "row",
2138
- alignItems: "center",
2139
- justifyContent: "space-between",
2140
- gap: space2.sm,
2141
- paddingHorizontal: space2.lg,
2142
- paddingVertical: space2.xs,
2143
- backgroundColor: colors2.surface,
2144
- borderBottomWidth: 1,
2145
- borderBottomColor: colors2.divider
2146
- },
2147
- children: [
2148
- /* @__PURE__ */ jsxRuntime.jsx(
2149
- reactNative.Text,
2150
- {
2151
- style: { color: colors2.text, fontSize: font2.size.sm, flexShrink: 1 },
2152
- children: props.text
2153
- }
2154
- ),
2155
- props.children
2156
- ]
2157
- }
2158
- );
2159
- }
2160
- function VinaverseChatProvider(props) {
2161
- const { conversation, components, agentAvatar, timeZone } = props;
2162
- const handlers = react.useRef(props);
2163
- handlers.current = props;
2164
- const slots = useStableSlots(components);
2165
- const hasAction = props.failureAction !== void 0;
2166
- const actionLabel = props.failureAction?.label;
2167
- const failureAction = react.useMemo(
2168
- () => hasAction ? { label: actionLabel } : null,
2169
- [hasAction, actionLabel]
2170
- );
2171
- const value = react.useMemo(
2172
- () => ({
2173
- store: conversation,
2174
- handlers,
2175
- slots,
2176
- agentAvatar,
2177
- timeZone,
2178
- failureAction
2179
- }),
2180
- [conversation, slots, agentAvatar, timeZone, failureAction]
2181
- );
2182
- useNativeLifecycle(conversation);
2183
- react.useEffect(() => {
2184
- conversation.start();
2185
- }, [conversation]);
2186
- const { onWarning, theme, copy } = props;
2187
- react.useEffect(() => {
2188
- if (!onWarning) return;
2189
- for (const problem of themeProblems(theme))
2190
- onWarning(`Vinaverse theme: ${problem}`);
2191
- for (const key of react$1.bannedWordsIn(copy ?? {}))
2192
- onWarning(
2193
- `Vinaverse copy: "${key}" says assistant, bot or crew; the copy says agent.`
2194
- );
2195
- }, [onWarning, theme, copy]);
2196
- 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(ChatContextProvider, { value, children: props.children }) }) });
2197
- }
2198
- function VinaverseChat(props) {
2199
- return /* @__PURE__ */ jsxRuntime.jsx(VinaverseChatProvider, { ...props, children: /* @__PURE__ */ jsxRuntime.jsx(
2200
- Layout,
2201
- {
2202
- hideHeader: props.hideHeader === true,
2203
- keyboardVerticalOffset: props.keyboardVerticalOffset ?? 0,
2204
- keyboardBehavior: props.keyboardBehavior ?? (reactNative.Platform.OS === "ios" ? "padding" : "none"),
2205
- style: props.style,
2206
- onError: props.onWarning
2207
- }
2208
- ) });
2209
- }
2210
- function Layout(props) {
2211
- const { colors: colors2 } = useTheme();
2212
- const { direction } = react$1.useCopy();
2213
- const { onError } = props;
2214
- const reportError = react.useMemo(
2215
- () => onError ? (e) => onError(String(e)) : void 0,
2216
- [onError]
2217
- );
2218
- return /* @__PURE__ */ jsxRuntime.jsxs(
2219
- reactNative.KeyboardAvoidingView,
2220
- {
2221
- ...props.keyboardBehavior === "none" ? { enabled: false } : { behavior: props.keyboardBehavior },
2222
- keyboardVerticalOffset: props.keyboardVerticalOffset,
2223
- style: [
2224
- { flex: 1, backgroundColor: colors2.background, direction },
2225
- props.style
2226
- ],
2227
- children: [
2228
- props.hideHeader ? null : /* @__PURE__ */ jsxRuntime.jsx(ChatHeader, {}),
2229
- /* @__PURE__ */ jsxRuntime.jsx(DisclosureBar, {}),
2230
- /* @__PURE__ */ jsxRuntime.jsx(StatusBanner, {}),
2231
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { flex: 1 }, children: /* @__PURE__ */ jsxRuntime.jsx(MessageList, {}) }),
2232
- /* @__PURE__ */ jsxRuntime.jsx(Composer, { ...reportError ? { onError: reportError } : {} })
2233
- ]
2234
- }
2235
- );
2236
- }
2237
- function useStableSlots(slots) {
2238
- const held = react.useRef({});
2239
- const next = slots ?? {};
2240
- if (!sameSlots(held.current, next)) held.current = next;
2241
- return held.current;
2242
- }
2243
- function sameSlots(a, b) {
2244
- const keys = /* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)]);
2245
- for (const key of keys) {
2246
- if (key === "cards") {
2247
- const ca = a.cards ?? {};
2248
- const cb = b.cards ?? {};
2249
- const kinds = /* @__PURE__ */ new Set([...Object.keys(ca), ...Object.keys(cb)]);
2250
- for (const kind of kinds) if (ca[kind] !== cb[kind]) return false;
2251
- } else if (a[key] !== b[key]) return false;
2252
- }
2253
- return true;
2254
- }
2255
9
 
2256
- exports.ActivityLine = ActivityLine;
2257
- exports.Avatar = Avatar;
2258
- exports.Button = Button;
2259
- exports.CardActions = CardActions;
2260
- exports.CardCarousel = CardCarousel;
2261
- exports.CardFrame = CardFrame;
2262
- exports.CardView = CardView;
2263
- exports.ChatHeader = ChatHeader;
2264
- exports.ChatSkeleton = ChatSkeleton;
2265
- exports.Composer = Composer;
2266
- exports.DefaultBubble = DefaultBubble;
2267
- exports.DefaultComposer = DefaultComposer;
2268
- exports.DefaultHeader = DefaultHeader;
2269
- exports.DefaultTurnFailed = DefaultTurnFailed;
2270
- exports.DefaultUnavailable = DefaultUnavailable;
2271
- exports.DisclosureBar = DisclosureBar;
2272
- exports.FailureActionButton = FailureActionButton;
2273
- exports.InfoCard = InfoCard;
2274
- exports.LinksCard = LinksCard;
2275
- exports.ListingCard = ListingCard;
2276
- exports.MessageBubble = MessageBubble;
2277
- exports.MessageList = MessageList;
2278
- exports.NextStepCard = NextStepCard;
2279
- exports.ProposalCard = ProposalCard;
2280
- exports.QuestionCard = QuestionCard;
2281
- exports.Row = Row;
2282
- exports.StatusBanner = StatusBanner;
2283
- exports.StreamingBubble = StreamingBubble;
2284
- exports.SystemRow = SystemRow;
2285
- exports.ThemeProvider = ThemeProvider;
2286
- exports.TimeSlotsCard = TimeSlotsCard;
2287
- exports.VinaverseChat = VinaverseChat;
2288
- exports.VinaverseChatProvider = VinaverseChatProvider;
2289
- exports.Welcome = Welcome;
2290
- exports.announce = announce;
2291
- exports.answerText = answerText;
2292
- exports.carousels = carousels;
2293
- exports.createTheme = createTheme;
2294
- exports.defaultCard = defaultCard;
2295
- exports.fieldText = fieldText;
2296
- exports.itemType = itemType;
2297
- exports.monogram = monogram;
2298
- exports.ratingText = ratingText;
2299
- exports.themeProblems = themeProblems;
2300
- exports.useChat = useChat;
2301
- exports.useNativeLifecycle = useNativeLifecycle;
2302
- exports.useReducedMotion = useReducedMotion;
2303
- exports.useTheme = useTheme;
10
+
11
+ Object.defineProperty(exports, "ActivityLine", {
12
+ enumerable: true,
13
+ get: function () { return chunkH2Y2YW2Q_cjs.ActivityLine; }
14
+ });
15
+ Object.defineProperty(exports, "AgentChat", {
16
+ enumerable: true,
17
+ get: function () { return chunkH2Y2YW2Q_cjs.AgentChat; }
18
+ });
19
+ Object.defineProperty(exports, "AgentFooter", {
20
+ enumerable: true,
21
+ get: function () { return chunkH2Y2YW2Q_cjs.AgentFooter; }
22
+ });
23
+ Object.defineProperty(exports, "AgentRuntimeProvider", {
24
+ enumerable: true,
25
+ get: function () { return chunkH2Y2YW2Q_cjs.AgentRuntimeProvider; }
26
+ });
27
+ Object.defineProperty(exports, "Avatar", {
28
+ enumerable: true,
29
+ get: function () { return chunkH2Y2YW2Q_cjs.Avatar; }
30
+ });
31
+ Object.defineProperty(exports, "Button", {
32
+ enumerable: true,
33
+ get: function () { return chunkH2Y2YW2Q_cjs.Button; }
34
+ });
35
+ Object.defineProperty(exports, "CardActions", {
36
+ enumerable: true,
37
+ get: function () { return chunkH2Y2YW2Q_cjs.CardActions; }
38
+ });
39
+ Object.defineProperty(exports, "CardCarousel", {
40
+ enumerable: true,
41
+ get: function () { return chunkH2Y2YW2Q_cjs.CardCarousel; }
42
+ });
43
+ Object.defineProperty(exports, "CardFrame", {
44
+ enumerable: true,
45
+ get: function () { return chunkH2Y2YW2Q_cjs.CardFrame; }
46
+ });
47
+ Object.defineProperty(exports, "CardView", {
48
+ enumerable: true,
49
+ get: function () { return chunkH2Y2YW2Q_cjs.CardView; }
50
+ });
51
+ Object.defineProperty(exports, "ChatHeader", {
52
+ enumerable: true,
53
+ get: function () { return chunkH2Y2YW2Q_cjs.ChatHeader; }
54
+ });
55
+ Object.defineProperty(exports, "ChatSkeleton", {
56
+ enumerable: true,
57
+ get: function () { return chunkH2Y2YW2Q_cjs.ChatSkeleton; }
58
+ });
59
+ Object.defineProperty(exports, "Composer", {
60
+ enumerable: true,
61
+ get: function () { return chunkH2Y2YW2Q_cjs.Composer; }
62
+ });
63
+ Object.defineProperty(exports, "DefaultBubble", {
64
+ enumerable: true,
65
+ get: function () { return chunkH2Y2YW2Q_cjs.DefaultBubble; }
66
+ });
67
+ Object.defineProperty(exports, "DefaultComposer", {
68
+ enumerable: true,
69
+ get: function () { return chunkH2Y2YW2Q_cjs.DefaultComposer; }
70
+ });
71
+ Object.defineProperty(exports, "DefaultEnded", {
72
+ enumerable: true,
73
+ get: function () { return chunkH2Y2YW2Q_cjs.DefaultEnded; }
74
+ });
75
+ Object.defineProperty(exports, "DefaultHeader", {
76
+ enumerable: true,
77
+ get: function () { return chunkH2Y2YW2Q_cjs.DefaultHeader; }
78
+ });
79
+ Object.defineProperty(exports, "DefaultTurnFailed", {
80
+ enumerable: true,
81
+ get: function () { return chunkH2Y2YW2Q_cjs.DefaultTurnFailed; }
82
+ });
83
+ Object.defineProperty(exports, "DefaultUnavailable", {
84
+ enumerable: true,
85
+ get: function () { return chunkH2Y2YW2Q_cjs.DefaultUnavailable; }
86
+ });
87
+ Object.defineProperty(exports, "DefaultUnavailableScreen", {
88
+ enumerable: true,
89
+ get: function () { return chunkH2Y2YW2Q_cjs.DefaultUnavailableScreen; }
90
+ });
91
+ Object.defineProperty(exports, "DefaultUnreachable", {
92
+ enumerable: true,
93
+ get: function () { return chunkH2Y2YW2Q_cjs.DefaultUnreachable; }
94
+ });
95
+ Object.defineProperty(exports, "DisclosureBar", {
96
+ enumerable: true,
97
+ get: function () { return chunkH2Y2YW2Q_cjs.DisclosureBar; }
98
+ });
99
+ Object.defineProperty(exports, "FailureActionButton", {
100
+ enumerable: true,
101
+ get: function () { return chunkH2Y2YW2Q_cjs.FailureActionButton; }
102
+ });
103
+ Object.defineProperty(exports, "InfoCard", {
104
+ enumerable: true,
105
+ get: function () { return chunkH2Y2YW2Q_cjs.InfoCard; }
106
+ });
107
+ Object.defineProperty(exports, "LinksCard", {
108
+ enumerable: true,
109
+ get: function () { return chunkH2Y2YW2Q_cjs.LinksCard; }
110
+ });
111
+ Object.defineProperty(exports, "ListingCard", {
112
+ enumerable: true,
113
+ get: function () { return chunkH2Y2YW2Q_cjs.ListingCard; }
114
+ });
115
+ Object.defineProperty(exports, "MessageBubble", {
116
+ enumerable: true,
117
+ get: function () { return chunkH2Y2YW2Q_cjs.MessageBubble; }
118
+ });
119
+ Object.defineProperty(exports, "MessageList", {
120
+ enumerable: true,
121
+ get: function () { return chunkH2Y2YW2Q_cjs.MessageList; }
122
+ });
123
+ Object.defineProperty(exports, "NextStepCard", {
124
+ enumerable: true,
125
+ get: function () { return chunkH2Y2YW2Q_cjs.NextStepCard; }
126
+ });
127
+ Object.defineProperty(exports, "ProposalCard", {
128
+ enumerable: true,
129
+ get: function () { return chunkH2Y2YW2Q_cjs.ProposalCard; }
130
+ });
131
+ Object.defineProperty(exports, "QuestionCard", {
132
+ enumerable: true,
133
+ get: function () { return chunkH2Y2YW2Q_cjs.QuestionCard; }
134
+ });
135
+ Object.defineProperty(exports, "Row", {
136
+ enumerable: true,
137
+ get: function () { return chunkH2Y2YW2Q_cjs.Row; }
138
+ });
139
+ Object.defineProperty(exports, "StatusBanner", {
140
+ enumerable: true,
141
+ get: function () { return chunkH2Y2YW2Q_cjs.StatusBanner; }
142
+ });
143
+ Object.defineProperty(exports, "StreamingBubble", {
144
+ enumerable: true,
145
+ get: function () { return chunkH2Y2YW2Q_cjs.StreamingBubble; }
146
+ });
147
+ Object.defineProperty(exports, "SystemRow", {
148
+ enumerable: true,
149
+ get: function () { return chunkH2Y2YW2Q_cjs.SystemRow; }
150
+ });
151
+ Object.defineProperty(exports, "TimeSlotsCard", {
152
+ enumerable: true,
153
+ get: function () { return chunkH2Y2YW2Q_cjs.TimeSlotsCard; }
154
+ });
155
+ Object.defineProperty(exports, "VinaverseChat", {
156
+ enumerable: true,
157
+ get: function () { return chunkH2Y2YW2Q_cjs.VinaverseChat; }
158
+ });
159
+ Object.defineProperty(exports, "VinaverseChatProvider", {
160
+ enumerable: true,
161
+ get: function () { return chunkH2Y2YW2Q_cjs.VinaverseChatProvider; }
162
+ });
163
+ Object.defineProperty(exports, "Welcome", {
164
+ enumerable: true,
165
+ get: function () { return chunkH2Y2YW2Q_cjs.Welcome; }
166
+ });
167
+ Object.defineProperty(exports, "allowedImage", {
168
+ enumerable: true,
169
+ get: function () { return chunkH2Y2YW2Q_cjs.allowedImage; }
170
+ });
171
+ Object.defineProperty(exports, "answerText", {
172
+ enumerable: true,
173
+ get: function () { return chunkH2Y2YW2Q_cjs.answerText; }
174
+ });
175
+ Object.defineProperty(exports, "carousels", {
176
+ enumerable: true,
177
+ get: function () { return chunkH2Y2YW2Q_cjs.carousels; }
178
+ });
179
+ Object.defineProperty(exports, "defaultCard", {
180
+ enumerable: true,
181
+ get: function () { return chunkH2Y2YW2Q_cjs.defaultCard; }
182
+ });
183
+ Object.defineProperty(exports, "fieldText", {
184
+ enumerable: true,
185
+ get: function () { return chunkH2Y2YW2Q_cjs.fieldText; }
186
+ });
187
+ Object.defineProperty(exports, "greetedKey", {
188
+ enumerable: true,
189
+ get: function () { return chunkH2Y2YW2Q_cjs.greetedKey; }
190
+ });
191
+ Object.defineProperty(exports, "itemType", {
192
+ enumerable: true,
193
+ get: function () { return chunkH2Y2YW2Q_cjs.itemType; }
194
+ });
195
+ Object.defineProperty(exports, "monogram", {
196
+ enumerable: true,
197
+ get: function () { return chunkH2Y2YW2Q_cjs.monogram; }
198
+ });
199
+ Object.defineProperty(exports, "newestWholeReply", {
200
+ enumerable: true,
201
+ get: function () { return chunkH2Y2YW2Q_cjs.newestWholeReply; }
202
+ });
203
+ Object.defineProperty(exports, "ratingText", {
204
+ enumerable: true,
205
+ get: function () { return chunkH2Y2YW2Q_cjs.ratingText; }
206
+ });
207
+ Object.defineProperty(exports, "useAgentConversation", {
208
+ enumerable: true,
209
+ get: function () { return chunkH2Y2YW2Q_cjs.useAgentConversation; }
210
+ });
211
+ Object.defineProperty(exports, "useAgentFeatures", {
212
+ enumerable: true,
213
+ get: function () { return chunkH2Y2YW2Q_cjs.useAgentFeatures; }
214
+ });
215
+ Object.defineProperty(exports, "useAgentLauncher", {
216
+ enumerable: true,
217
+ get: function () { return chunkH2Y2YW2Q_cjs.useAgentLauncher; }
218
+ });
219
+ Object.defineProperty(exports, "useAgentName", {
220
+ enumerable: true,
221
+ get: function () { return chunkH2Y2YW2Q_cjs.useAgentName; }
222
+ });
223
+ Object.defineProperty(exports, "useAgentProfile", {
224
+ enumerable: true,
225
+ get: function () { return chunkH2Y2YW2Q_cjs.useAgentProfile; }
226
+ });
227
+ Object.defineProperty(exports, "useAgentRuntime", {
228
+ enumerable: true,
229
+ get: function () { return chunkH2Y2YW2Q_cjs.useAgentRuntime; }
230
+ });
231
+ Object.defineProperty(exports, "useAgentStatus", {
232
+ enumerable: true,
233
+ get: function () { return chunkH2Y2YW2Q_cjs.useAgentStatus; }
234
+ });
235
+ Object.defineProperty(exports, "useChat", {
236
+ enumerable: true,
237
+ get: function () { return chunkH2Y2YW2Q_cjs.useChat; }
238
+ });
239
+ Object.defineProperty(exports, "AgentLauncher", {
240
+ enumerable: true,
241
+ get: function () { return chunkOGPMGGYS_cjs.AgentLauncher; }
242
+ });
243
+ Object.defineProperty(exports, "LAUNCHER_SIZE", {
244
+ enumerable: true,
245
+ get: function () { return chunkOGPMGGYS_cjs.LAUNCHER_SIZE; }
246
+ });
247
+ Object.defineProperty(exports, "LauncherButton", {
248
+ enumerable: true,
249
+ get: function () { return chunkOGPMGGYS_cjs.LauncherButton; }
250
+ });
251
+ Object.defineProperty(exports, "LauncherEntrance", {
252
+ enumerable: true,
253
+ get: function () { return chunkOGPMGGYS_cjs.LauncherEntrance; }
254
+ });
255
+ Object.defineProperty(exports, "LauncherGreeting", {
256
+ enumerable: true,
257
+ get: function () { return chunkOGPMGGYS_cjs.LauncherGreeting; }
258
+ });
259
+ Object.defineProperty(exports, "useKeyboardShown", {
260
+ enumerable: true,
261
+ get: function () { return chunkOGPMGGYS_cjs.useKeyboardShown; }
262
+ });
263
+ Object.defineProperty(exports, "announce", {
264
+ enumerable: true,
265
+ get: function () { return chunkPYPO6F7L_cjs.announce; }
266
+ });
267
+ Object.defineProperty(exports, "useNativeLifecycle", {
268
+ enumerable: true,
269
+ get: function () { return chunkPYPO6F7L_cjs.useNativeLifecycle; }
270
+ });
271
+ Object.defineProperty(exports, "useReducedMotion", {
272
+ enumerable: true,
273
+ get: function () { return chunkPYPO6F7L_cjs.useReducedMotion; }
274
+ });
275
+ Object.defineProperty(exports, "AskAboutRow", {
276
+ enumerable: true,
277
+ get: function () { return chunk643GOUTG_cjs.AskAboutRow; }
278
+ });
279
+ Object.defineProperty(exports, "ThemeProvider", {
280
+ enumerable: true,
281
+ get: function () { return chunkOWUKWVEZ_cjs.ThemeProvider; }
282
+ });
283
+ Object.defineProperty(exports, "createTheme", {
284
+ enumerable: true,
285
+ get: function () { return chunkOWUKWVEZ_cjs.createTheme; }
286
+ });
287
+ Object.defineProperty(exports, "themeProblems", {
288
+ enumerable: true,
289
+ get: function () { return chunkOWUKWVEZ_cjs.themeProblems; }
290
+ });
291
+ Object.defineProperty(exports, "useTheme", {
292
+ enumerable: true,
293
+ get: function () { return chunkOWUKWVEZ_cjs.useTheme; }
294
+ });
2304
295
  //# sourceMappingURL=index.cjs.map
2305
296
  //# sourceMappingURL=index.cjs.map