@vinaverse/react-native 0.0.0-stage → 0.1.0-alpha.11

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 (57) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +326 -2
  3. package/dist/ask.cjs +62 -0
  4. package/dist/ask.cjs.map +1 -0
  5. package/dist/ask.d.cts +38 -0
  6. package/dist/ask.d.ts +38 -0
  7. package/dist/ask.js +5 -0
  8. package/dist/ask.js.map +1 -0
  9. package/dist/chat.cjs +274 -0
  10. package/dist/chat.cjs.map +1 -0
  11. package/dist/chat.d.cts +292 -0
  12. package/dist/chat.d.ts +292 -0
  13. package/dist/chat.js +5 -0
  14. package/dist/chat.js.map +1 -0
  15. package/dist/chunk-2J2LIJLW.js +624 -0
  16. package/dist/chunk-2J2LIJLW.js.map +1 -0
  17. package/dist/chunk-4PXQ7DEY.cjs +680 -0
  18. package/dist/chunk-4PXQ7DEY.cjs.map +1 -0
  19. package/dist/chunk-6QYDPGRS.cjs +97 -0
  20. package/dist/chunk-6QYDPGRS.cjs.map +1 -0
  21. package/dist/chunk-7KPCO443.js +74 -0
  22. package/dist/chunk-7KPCO443.js.map +1 -0
  23. package/dist/chunk-EFEXTVIT.js +88 -0
  24. package/dist/chunk-EFEXTVIT.js.map +1 -0
  25. package/dist/chunk-KSHDF3MG.js +1996 -0
  26. package/dist/chunk-KSHDF3MG.js.map +1 -0
  27. package/dist/chunk-MG32E4JI.cjs +268 -0
  28. package/dist/chunk-MG32E4JI.cjs.map +1 -0
  29. package/dist/chunk-NMKJ7LIJ.cjs +76 -0
  30. package/dist/chunk-NMKJ7LIJ.cjs.map +1 -0
  31. package/dist/chunk-POJP52GE.js +261 -0
  32. package/dist/chunk-POJP52GE.js.map +1 -0
  33. package/dist/chunk-XAG2P447.cjs +2035 -0
  34. package/dist/chunk-XAG2P447.cjs.map +1 -0
  35. package/dist/context-gHCLFsJh.d.cts +212 -0
  36. package/dist/context-gHCLFsJh.d.ts +212 -0
  37. package/dist/history.cjs +673 -0
  38. package/dist/history.cjs.map +1 -0
  39. package/dist/history.d.cts +177 -0
  40. package/dist/history.d.ts +177 -0
  41. package/dist/history.js +618 -0
  42. package/dist/history.js.map +1 -0
  43. package/dist/index.cjs +304 -0
  44. package/dist/index.cjs.map +1 -0
  45. package/dist/index.d.cts +12 -0
  46. package/dist/index.d.ts +12 -0
  47. package/dist/index.js +7 -0
  48. package/dist/index.js.map +1 -0
  49. package/dist/launcher.cjs +86 -0
  50. package/dist/launcher.cjs.map +1 -0
  51. package/dist/launcher.d.cts +122 -0
  52. package/dist/launcher.d.ts +122 -0
  53. package/dist/launcher.js +5 -0
  54. package/dist/launcher.js.map +1 -0
  55. package/dist/theme-BhiEGv64.d.cts +35 -0
  56. package/dist/theme-BhiEGv64.d.ts +35 -0
  57. package/package.json +311 -3
@@ -0,0 +1,268 @@
1
+ 'use strict';
2
+
3
+ var chunk6QYDPGRS_cjs = require('./chunk-6QYDPGRS.cjs');
4
+ var react = require('@vinaverse/react');
5
+ var agent = require('@vinaverse/react/agent');
6
+ var react$1 = require('react');
7
+ var reactNative = require('react-native');
8
+ var jsxRuntime = require('react/jsx-runtime');
9
+
10
+ var LAUNCHER_SIZE = 56;
11
+ function AgentLauncher(props) {
12
+ return /* @__PURE__ */ jsxRuntime.jsx(react.CopyProvider, { locale: props.locale, copy: props.copy, children: /* @__PURE__ */ jsxRuntime.jsx(chunk6QYDPGRS_cjs.ThemeProvider, { theme: props.theme, colorScheme: props.colorScheme, children: /* @__PURE__ */ jsxRuntime.jsx(Launcher, { ...props }) }) });
13
+ }
14
+ function useKeyboardShown() {
15
+ const [shown, setShown] = react$1.useState(false);
16
+ react$1.useEffect(() => {
17
+ const ios = reactNative.Platform.OS === "ios";
18
+ const show = reactNative.Keyboard.addListener(
19
+ ios ? "keyboardWillShow" : "keyboardDidShow",
20
+ () => setShown(true)
21
+ );
22
+ const hide = reactNative.Keyboard.addListener(
23
+ ios ? "keyboardWillHide" : "keyboardDidHide",
24
+ () => setShown(false)
25
+ );
26
+ return () => {
27
+ show.remove();
28
+ hide.remove();
29
+ };
30
+ }, []);
31
+ return shown;
32
+ }
33
+ function Launcher(props) {
34
+ const { t } = react.useCopy();
35
+ const name = agent.useAgentName(t("agentFallbackName"));
36
+ const keyboard = useKeyboardShown();
37
+ const reducedMotion = chunk6QYDPGRS_cjs.useReducedMotion();
38
+ chunk6QYDPGRS_cjs.useAgentSweep(agent.useAgentRuntime());
39
+ const { route = null, routes, mode } = props;
40
+ const visible = props.hidden !== true && !(keyboard && props.hideWithKeyboard !== false) && (!routes || route !== null && routes.includes(route));
41
+ const launcher = agent.useAgentLauncher({
42
+ subject: props.subject,
43
+ mode,
44
+ visible,
45
+ onOpen: () => props.onOpen({ route, mode, entryPoint: "launcher" }),
46
+ ...props.storage ? { storage: props.storage } : {},
47
+ ...props.storageKey ? { storageKey: props.storageKey } : {},
48
+ ...props.delayMs === void 0 ? {} : { delayMs: props.delayMs }
49
+ });
50
+ const text = typeof props.greeting === "function" ? props.greeting(mode) : props.greeting ?? t("launcherGreeting", { agent: name });
51
+ const say = props.announce ?? chunk6QYDPGRS_cjs.announce;
52
+ const said = react$1.useRef(false);
53
+ react$1.useEffect(() => {
54
+ if (!launcher.greets) {
55
+ said.current = false;
56
+ return;
57
+ }
58
+ if (said.current) return;
59
+ said.current = true;
60
+ say(text);
61
+ }, [launcher.greets, text, say]);
62
+ if (!launcher.shows) return null;
63
+ const edge = props.placement?.edge ?? "right";
64
+ const look = props.appearance ?? {};
65
+ const greeting = {
66
+ text,
67
+ closeLabel: t("close"),
68
+ onOpen: launcher.open,
69
+ onClose: launcher.dismiss,
70
+ tail: look.tail !== false,
71
+ edge
72
+ };
73
+ const button = {
74
+ label: t("launcherOpen", { agent: name }),
75
+ name,
76
+ onPress: launcher.open,
77
+ Mark: props.Mark,
78
+ ring: look.ring ?? null,
79
+ shadow: look.shadow !== false
80
+ };
81
+ const { Greeting, Button, Entrance } = props.components ?? {};
82
+ const enter = (part, children) => Entrance ? /* @__PURE__ */ jsxRuntime.jsx(
83
+ Entrance,
84
+ {
85
+ part,
86
+ reducedMotion,
87
+ Default: LauncherEntrance,
88
+ children
89
+ }
90
+ ) : /* @__PURE__ */ jsxRuntime.jsx(LauncherEntrance, { part, reducedMotion, children });
91
+ return /* @__PURE__ */ jsxRuntime.jsxs(
92
+ reactNative.View,
93
+ {
94
+ pointerEvents: "box-none",
95
+ style: [
96
+ {
97
+ position: "absolute",
98
+ bottom: props.placement?.bottom ?? 16,
99
+ [edge]: props.placement?.inset ?? 16,
100
+ alignItems: edge === "right" ? "flex-end" : "flex-start",
101
+ gap: 8
102
+ },
103
+ props.style
104
+ ],
105
+ testID: "vinaverse-launcher",
106
+ children: [
107
+ launcher.greets ? enter(
108
+ "greeting",
109
+ Greeting ? /* @__PURE__ */ jsxRuntime.jsx(Greeting, { ...greeting, Default: LauncherGreeting }) : /* @__PURE__ */ jsxRuntime.jsx(LauncherGreeting, { ...greeting })
110
+ ) : null,
111
+ enter(
112
+ "button",
113
+ Button ? /* @__PURE__ */ jsxRuntime.jsx(Button, { ...button, Default: LauncherButton }) : /* @__PURE__ */ jsxRuntime.jsx(LauncherButton, { ...button })
114
+ )
115
+ ]
116
+ }
117
+ );
118
+ }
119
+ function LauncherEntrance(props) {
120
+ const { motion } = chunk6QYDPGRS_cjs.useTheme();
121
+ const shown = react$1.useRef(new reactNative.Animated.Value(props.reducedMotion ? 1 : 0)).current;
122
+ react$1.useEffect(() => {
123
+ if (props.reducedMotion) {
124
+ shown.setValue(1);
125
+ return;
126
+ }
127
+ const run = reactNative.Animated.timing(shown, {
128
+ toValue: 1,
129
+ duration: motion.normal,
130
+ useNativeDriver: true
131
+ });
132
+ run.start();
133
+ return () => run.stop();
134
+ }, [shown, props.reducedMotion, motion.normal]);
135
+ return /* @__PURE__ */ jsxRuntime.jsx(
136
+ reactNative.Animated.View,
137
+ {
138
+ pointerEvents: "box-none",
139
+ style: {
140
+ opacity: shown,
141
+ transform: [
142
+ {
143
+ scale: shown.interpolate({
144
+ inputRange: [0, 1],
145
+ outputRange: [0.9, 1]
146
+ })
147
+ }
148
+ ]
149
+ },
150
+ testID: `vinaverse-launcher-entrance-${props.part}`,
151
+ children: props.children
152
+ }
153
+ );
154
+ }
155
+ function LauncherGreeting(props) {
156
+ const { colors, radius, space, font } = chunk6QYDPGRS_cjs.useTheme();
157
+ return /* @__PURE__ */ jsxRuntime.jsxs(
158
+ reactNative.View,
159
+ {
160
+ style: {
161
+ maxWidth: 296,
162
+ flexDirection: "row",
163
+ alignItems: "flex-start",
164
+ borderRadius: radius.lg,
165
+ backgroundColor: colors.text
166
+ },
167
+ testID: "vinaverse-launcher-greeting",
168
+ children: [
169
+ props.tail ? /* @__PURE__ */ jsxRuntime.jsx(
170
+ reactNative.View,
171
+ {
172
+ accessible: false,
173
+ style: {
174
+ position: "absolute",
175
+ bottom: -5,
176
+ [props.edge]: LAUNCHER_SIZE / 2 - 6,
177
+ width: 12,
178
+ height: 12,
179
+ backgroundColor: colors.text,
180
+ transform: [{ rotate: "45deg" }]
181
+ },
182
+ testID: "vinaverse-launcher-tail"
183
+ }
184
+ ) : null,
185
+ /* @__PURE__ */ jsxRuntime.jsx(
186
+ reactNative.Pressable,
187
+ {
188
+ accessibilityRole: "button",
189
+ accessibilityLabel: props.text,
190
+ onPress: props.onOpen,
191
+ style: {
192
+ flexShrink: 1,
193
+ paddingVertical: space.sm,
194
+ paddingLeft: space.md
195
+ },
196
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: colors.background, fontSize: font.size.md }, children: props.text })
197
+ }
198
+ ),
199
+ /* @__PURE__ */ jsxRuntime.jsx(
200
+ reactNative.Pressable,
201
+ {
202
+ accessibilityRole: "button",
203
+ accessibilityLabel: props.closeLabel,
204
+ onPress: props.onClose,
205
+ style: {
206
+ minWidth: 44,
207
+ minHeight: 44,
208
+ alignItems: "center",
209
+ justifyContent: "center"
210
+ },
211
+ testID: "vinaverse-launcher-close",
212
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: colors.background, fontSize: font.size.md }, children: "\xD7" })
213
+ }
214
+ )
215
+ ]
216
+ }
217
+ );
218
+ }
219
+ function LauncherButton(props) {
220
+ const { colors, font } = chunk6QYDPGRS_cjs.useTheme();
221
+ const { Mark, ring } = props;
222
+ return /* @__PURE__ */ jsxRuntime.jsx(
223
+ reactNative.Pressable,
224
+ {
225
+ accessibilityRole: "button",
226
+ accessibilityLabel: props.label,
227
+ onPress: props.onPress,
228
+ style: ({ pressed }) => ({
229
+ width: LAUNCHER_SIZE,
230
+ height: LAUNCHER_SIZE,
231
+ borderRadius: LAUNCHER_SIZE / 2,
232
+ alignItems: "center",
233
+ justifyContent: "center",
234
+ backgroundColor: colors.primary,
235
+ opacity: pressed ? 0.85 : 1,
236
+ ...ring ? { borderWidth: ring.width, borderColor: ring.color } : {},
237
+ ...props.shadow ? {
238
+ elevation: 6,
239
+ shadowColor: "#000",
240
+ shadowOpacity: 0.2,
241
+ shadowRadius: 8,
242
+ shadowOffset: { width: 0, height: 3 }
243
+ } : {}
244
+ }),
245
+ testID: "vinaverse-launcher-button",
246
+ children: Mark ? /* @__PURE__ */ jsxRuntime.jsx(Mark, { size: 34, color: colors.onPrimary }) : /* @__PURE__ */ jsxRuntime.jsx(
247
+ reactNative.Text,
248
+ {
249
+ style: {
250
+ color: colors.onPrimary,
251
+ fontSize: font.size.lg,
252
+ fontWeight: "600"
253
+ },
254
+ children: (props.name.trim()[0] ?? "?").toUpperCase()
255
+ }
256
+ )
257
+ }
258
+ );
259
+ }
260
+
261
+ exports.AgentLauncher = AgentLauncher;
262
+ exports.LAUNCHER_SIZE = LAUNCHER_SIZE;
263
+ exports.LauncherButton = LauncherButton;
264
+ exports.LauncherEntrance = LauncherEntrance;
265
+ exports.LauncherGreeting = LauncherGreeting;
266
+ exports.useKeyboardShown = useKeyboardShown;
267
+ //# sourceMappingURL=chunk-MG32E4JI.cjs.map
268
+ //# sourceMappingURL=chunk-MG32E4JI.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/AgentLauncher.tsx"],"names":["jsx","CopyProvider","ThemeProvider","useState","useEffect","Platform","Keyboard","useCopy","useAgentName","useReducedMotion","useAgentSweep","useAgentRuntime","useAgentLauncher","announce","useRef","jsxs","View","useTheme","Animated","Pressable","Text"],"mappings":"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","file":"chunk-MG32E4JI.cjs","sourcesContent":["// The agent's floating launcher: a round button over the app's screens and, once per person and mode, a greeting\n// bubble above it, read to screen readers as it appears. Where it shows is a policy: the routes the app allows, never\n// with the keyboard up, never while the app says it should step aside (a sheet, a map). The app places it (`placement`,\n// `style`), gives its brand mark (`Mark`), sets its ring, shadow and the bubble's tail (`appearance`), and can replace\n// the button, the bubble and how they come in (slots, each given the kit's own part; no motion when reduced).\nimport { type CopyOverrides, CopyProvider, useCopy } from '@vinaverse/react';\nimport {\n type GreetingStorage,\n useAgentLauncher,\n useAgentName,\n useAgentRuntime,\n} from '@vinaverse/react/agent';\nimport {\n type ComponentType,\n type ReactNode,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport {\n Animated,\n Keyboard,\n Platform,\n Pressable,\n type StyleProp,\n Text,\n View,\n type ViewStyle,\n} from 'react-native';\nimport {\n announce as platformAnnounce,\n useAgentSweep,\n useReducedMotion,\n} from '../platform.js';\nimport {\n type ColorSchemeSetting,\n type ThemeOverrides,\n ThemeProvider,\n useTheme,\n} from '../theme.js';\n\n/** The launcher's button side, in dp. */\nexport const LAUNCHER_SIZE = 56;\n\n/** The launcher's look: a ring around the button, its shadow, the bubble's tail toward it. */\nexport interface LauncherAppearance {\n /** Default none. */\n readonly ring?: { readonly color: string; readonly width: number } | null;\n /** Default true. */\n readonly shadow?: boolean;\n /** Default true. */\n readonly tail?: boolean;\n}\n\n/** Where it floats: the screen's edge, its distance from the bottom (above a tab bar) and from the side. */\nexport interface LauncherPlacement {\n /** Default `right`. */\n readonly edge?: 'left' | 'right';\n /** Default 16. */\n readonly bottom?: number;\n /** Default 16. */\n readonly inset?: number;\n}\n\nexport interface LauncherButtonProps {\n readonly label: string;\n readonly name: string;\n readonly onPress: () => void;\n readonly Mark:\n | ComponentType<{ readonly size: number; readonly color: string }>\n | undefined;\n readonly ring: { readonly color: string; readonly width: number } | null;\n readonly shadow: boolean;\n}\nexport interface LauncherGreetingProps {\n readonly text: string;\n readonly closeLabel: string;\n readonly onOpen: () => void;\n readonly onClose: () => void;\n readonly tail: boolean;\n readonly edge: 'left' | 'right';\n}\n/** How the button and the bubble come in; `reducedMotion` when the person asked for none. */\nexport interface LauncherEntranceProps {\n readonly part: 'button' | 'greeting';\n readonly reducedMotion: boolean;\n readonly children: ReactNode;\n}\ntype Slot<P> = ComponentType<P & { readonly Default: ComponentType<P> }>;\n\n/** Where the person opened the agent from: the app's route, the mode, and `entryPoint` to give the chat. */\nexport interface LauncherContext {\n readonly route: string | null;\n readonly mode: string;\n readonly entryPoint: 'launcher';\n}\n\nexport interface AgentLauncherProps {\n readonly subject: string | null;\n readonly mode: string;\n readonly onOpen: (from: LauncherContext) => void;\n /** The app's current route; with `routes`, the launcher shows only on those. */\n readonly route?: string | null;\n readonly routes?: readonly string[];\n /** The app says step aside (a sheet is up, a map with its own cards…). */\n readonly hidden?: boolean;\n /** Hidden while the keyboard is up. Default true. */\n readonly hideWithKeyboard?: boolean;\n /** Where it remembers the greeting was shown (the app's preferences store); default: for this launch only. */\n readonly storage?: GreetingStorage;\n /** The storage's key for a person and mode (a record the app already keeps); default `greetedKey`. */\n readonly storageKey?: (subject: string | null, mode: string) => string;\n /** The greeting's words, or by mode; default the copy's `launcherGreeting`. */\n readonly greeting?: string | ((mode: string) => string);\n /** How long after showing the greeting appears. Default 1200 ms. */\n readonly delayMs?: number;\n /** The app's brand mark inside the button; default the agent name's first letter. */\n readonly Mark?: ComponentType<{\n readonly size: number;\n readonly color: string;\n }>;\n /** Reads the greeting to a screen reader as it appears. Default: the platform's. */\n readonly announce?: (text: string) => void;\n readonly components?: {\n readonly Button?: Slot<LauncherButtonProps>;\n readonly Greeting?: Slot<LauncherGreetingProps>;\n /** Default: a short fade and scale; none with reduced motion. */\n readonly Entrance?: Slot<LauncherEntranceProps>;\n };\n readonly appearance?: LauncherAppearance;\n /** Where it floats over the app's screens; `style` comes after it, for anything else. */\n readonly placement?: LauncherPlacement;\n readonly style?: StyleProp<ViewStyle>;\n /** As on the chat: the person's locale, the app's words, theme and color scheme. */\n readonly locale?: string;\n readonly copy?: CopyOverrides;\n readonly theme?: ThemeOverrides;\n readonly colorScheme?: ColorSchemeSetting;\n}\n\nexport function AgentLauncher(props: AgentLauncherProps): ReactNode {\n return (\n <CopyProvider locale={props.locale} copy={props.copy}>\n <ThemeProvider theme={props.theme} colorScheme={props.colorScheme}>\n <Launcher {...props} />\n </ThemeProvider>\n </CopyProvider>\n );\n}\n\n/** Whether the keyboard is up: on iOS from the moment it starts to rise or fall, on Android (no `Will` events) once it has. */\nexport function useKeyboardShown(): boolean {\n const [shown, setShown] = useState(false);\n useEffect(() => {\n const ios = Platform.OS === 'ios';\n const show = Keyboard.addListener(\n ios ? 'keyboardWillShow' : 'keyboardDidShow',\n () => setShown(true),\n );\n const hide = Keyboard.addListener(\n ios ? 'keyboardWillHide' : 'keyboardDidHide',\n () => setShown(false),\n );\n return () => {\n show.remove();\n hide.remove();\n };\n }, []);\n return shown;\n}\n\nfunction Launcher(props: AgentLauncherProps): ReactNode {\n const { t } = useCopy();\n const name = useAgentName(t('agentFallbackName'));\n const keyboard = useKeyboardShown();\n const reducedMotion = useReducedMotion();\n useAgentSweep(useAgentRuntime());\n const { route = null, routes, mode } = props;\n const visible =\n props.hidden !== true &&\n !(keyboard && props.hideWithKeyboard !== false) &&\n (!routes || (route !== null && routes.includes(route)));\n const launcher = useAgentLauncher({\n subject: props.subject,\n mode,\n visible,\n onOpen: () => props.onOpen({ route, mode, entryPoint: 'launcher' }),\n ...(props.storage ? { storage: props.storage } : {}),\n ...(props.storageKey ? { storageKey: props.storageKey } : {}),\n ...(props.delayMs === undefined ? {} : { delayMs: props.delayMs }),\n });\n const text =\n typeof props.greeting === 'function'\n ? props.greeting(mode)\n : (props.greeting ?? t('launcherGreeting', { agent: name }));\n const say = props.announce ?? platformAnnounce;\n const said = useRef(false);\n useEffect(() => {\n if (!launcher.greets) {\n said.current = false;\n return;\n }\n if (said.current) return;\n said.current = true; // once per greeting, however often the app's `announce` changes\n say(text);\n }, [launcher.greets, text, say]);\n if (!launcher.shows) return null;\n const edge = props.placement?.edge ?? 'right';\n const look = props.appearance ?? {};\n const greeting: LauncherGreetingProps = {\n text,\n closeLabel: t('close'),\n onOpen: launcher.open,\n onClose: launcher.dismiss,\n tail: look.tail !== false,\n edge,\n };\n const button: LauncherButtonProps = {\n label: t('launcherOpen', { agent: name }),\n name,\n onPress: launcher.open,\n Mark: props.Mark,\n ring: look.ring ?? null,\n shadow: look.shadow !== false,\n };\n const { Greeting, Button, Entrance } = props.components ?? {};\n const enter = (part: LauncherEntranceProps['part'], children: ReactNode) =>\n Entrance ? (\n <Entrance\n part={part}\n reducedMotion={reducedMotion}\n Default={LauncherEntrance}\n >\n {children}\n </Entrance>\n ) : (\n <LauncherEntrance part={part} reducedMotion={reducedMotion}>\n {children}\n </LauncherEntrance>\n );\n return (\n <View\n pointerEvents=\"box-none\"\n style={[\n {\n position: 'absolute',\n bottom: props.placement?.bottom ?? 16,\n [edge]: props.placement?.inset ?? 16,\n alignItems: edge === 'right' ? 'flex-end' : 'flex-start',\n gap: 8,\n },\n props.style,\n ]}\n testID=\"vinaverse-launcher\"\n >\n {launcher.greets\n ? enter(\n 'greeting',\n Greeting ? (\n <Greeting {...greeting} Default={LauncherGreeting} />\n ) : (\n <LauncherGreeting {...greeting} />\n ),\n )\n : null}\n {enter(\n 'button',\n Button ? (\n <Button {...button} Default={LauncherButton} />\n ) : (\n <LauncherButton {...button} />\n ),\n )}\n </View>\n );\n}\n\n/** The kit's entrance: a short fade and scale up; none when the person asked for reduced motion. */\nexport function LauncherEntrance(props: LauncherEntranceProps): ReactNode {\n const { motion } = useTheme();\n const shown = useRef(new Animated.Value(props.reducedMotion ? 1 : 0)).current;\n useEffect(() => {\n if (props.reducedMotion) {\n shown.setValue(1);\n return;\n }\n const run = Animated.timing(shown, {\n toValue: 1,\n duration: motion.normal,\n useNativeDriver: true,\n });\n run.start();\n return () => run.stop();\n }, [shown, props.reducedMotion, motion.normal]);\n return (\n <Animated.View\n pointerEvents=\"box-none\"\n style={{\n opacity: shown,\n transform: [\n {\n scale: shown.interpolate({\n inputRange: [0, 1],\n outputRange: [0.9, 1],\n }),\n },\n ],\n }}\n testID={`vinaverse-launcher-entrance-${props.part}`}\n >\n {props.children}\n </Animated.View>\n );\n}\n\n/** The kit's greeting bubble: the words (a tap opens the agent), a close button, and a tail toward the button. */\nexport function LauncherGreeting(props: LauncherGreetingProps): ReactNode {\n const { colors, radius, space, font } = useTheme();\n return (\n <View\n style={{\n maxWidth: 296,\n flexDirection: 'row',\n alignItems: 'flex-start',\n borderRadius: radius.lg,\n backgroundColor: colors.text,\n }}\n testID=\"vinaverse-launcher-greeting\"\n >\n {props.tail ? (\n <View\n accessible={false}\n style={{\n position: 'absolute',\n bottom: -5,\n [props.edge]: LAUNCHER_SIZE / 2 - 6,\n width: 12,\n height: 12,\n backgroundColor: colors.text,\n transform: [{ rotate: '45deg' }],\n }}\n testID=\"vinaverse-launcher-tail\"\n />\n ) : null}\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel={props.text}\n onPress={props.onOpen}\n style={{\n flexShrink: 1,\n paddingVertical: space.sm,\n paddingLeft: space.md,\n }}\n >\n <Text style={{ color: colors.background, fontSize: font.size.md }}>\n {props.text}\n </Text>\n </Pressable>\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel={props.closeLabel}\n onPress={props.onClose}\n style={{\n minWidth: 44,\n minHeight: 44,\n alignItems: 'center',\n justifyContent: 'center',\n }}\n testID=\"vinaverse-launcher-close\"\n >\n <Text style={{ color: colors.background, fontSize: font.size.md }}>\n ×\n </Text>\n </Pressable>\n </View>\n );\n}\n\n/** The kit's round button: the app's mark, else the agent name's first letter; its ring and shadow as asked. */\nexport function LauncherButton(props: LauncherButtonProps): ReactNode {\n const { colors, font } = useTheme();\n const { Mark, ring } = props;\n return (\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel={props.label}\n onPress={props.onPress}\n style={({ pressed }) => ({\n width: LAUNCHER_SIZE,\n height: LAUNCHER_SIZE,\n borderRadius: LAUNCHER_SIZE / 2,\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: colors.primary,\n opacity: pressed ? 0.85 : 1,\n ...(ring ? { borderWidth: ring.width, borderColor: ring.color } : {}),\n ...(props.shadow\n ? {\n elevation: 6,\n shadowColor: '#000',\n shadowOpacity: 0.2,\n shadowRadius: 8,\n shadowOffset: { width: 0, height: 3 },\n }\n : {}),\n })}\n testID=\"vinaverse-launcher-button\"\n >\n {Mark ? (\n <Mark size={34} color={colors.onPrimary} />\n ) : (\n <Text\n style={{\n color: colors.onPrimary,\n fontSize: font.size.lg,\n fontWeight: '600',\n }}\n >\n {(props.name.trim()[0] ?? '?').toUpperCase()}\n </Text>\n )}\n </Pressable>\n );\n}\n"]}
@@ -0,0 +1,76 @@
1
+ 'use strict';
2
+
3
+ var chunk6QYDPGRS_cjs = require('./chunk-6QYDPGRS.cjs');
4
+ var react = require('@vinaverse/react');
5
+ var agent = require('@vinaverse/react/agent');
6
+ var react$1 = require('react');
7
+ var reactNative = require('react-native');
8
+ var jsxRuntime = require('react/jsx-runtime');
9
+
10
+ function AskAboutRow(props) {
11
+ return /* @__PURE__ */ jsxRuntime.jsx(react.CopyProvider, { locale: props.locale, copy: props.copy, children: /* @__PURE__ */ jsxRuntime.jsx(chunk6QYDPGRS_cjs.ThemeProvider, { theme: props.theme, colorScheme: props.colorScheme, children: /* @__PURE__ */ jsxRuntime.jsx(Row, { ...props }) }) });
12
+ }
13
+ function Row(props) {
14
+ const { t } = react.useCopy();
15
+ const { colors, radius, space, font } = chunk6QYDPGRS_cjs.useTheme();
16
+ const name = agent.useAgentName(t("agentFallbackName"));
17
+ const runtime = agent.useAgentRuntime();
18
+ agent.useAgentStatus();
19
+ chunk6QYDPGRS_cjs.useAgentSweep(runtime);
20
+ const [shows] = react$1.useState(() => !!runtime.getStatus()?.available);
21
+ if (!shows) return null;
22
+ const { Mark, appearance: look } = props;
23
+ return /* @__PURE__ */ jsxRuntime.jsxs(
24
+ reactNative.Pressable,
25
+ {
26
+ accessibilityRole: "button",
27
+ accessibilityLabel: props.body ? `${props.title}. ${props.body}` : props.title,
28
+ onPress: () => props.onPress({ entryPoint: "ask" }),
29
+ style: ({ pressed }) => ({
30
+ flexDirection: "row",
31
+ alignItems: "center",
32
+ gap: space.md,
33
+ padding: space.md,
34
+ borderRadius: radius.lg,
35
+ backgroundColor: look?.background ?? colors.surface,
36
+ opacity: pressed ? 0.85 : 1
37
+ }),
38
+ testID: props.testID ?? "vinaverse-ask-about",
39
+ children: [
40
+ /* @__PURE__ */ jsxRuntime.jsx(
41
+ reactNative.View,
42
+ {
43
+ style: {
44
+ width: 36,
45
+ height: 36,
46
+ borderRadius: 18,
47
+ alignItems: "center",
48
+ justifyContent: "center",
49
+ backgroundColor: colors.primary
50
+ },
51
+ children: Mark ? /* @__PURE__ */ jsxRuntime.jsx(Mark, { size: 22, color: colors.onPrimary }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: colors.onPrimary, fontWeight: "600" }, children: (name.trim()[0] ?? "?").toUpperCase() })
52
+ }
53
+ ),
54
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { flex: 1, gap: space.xxs }, children: [
55
+ /* @__PURE__ */ jsxRuntime.jsx(
56
+ reactNative.Text,
57
+ {
58
+ style: {
59
+ color: colors.text,
60
+ fontSize: font.size.md,
61
+ fontWeight: "600"
62
+ },
63
+ children: props.title
64
+ }
65
+ ),
66
+ props.body ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: colors.textMuted, fontSize: font.size.sm }, children: props.body }) : null
67
+ ] }),
68
+ look?.chevron === false ? null : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: colors.textMuted, fontSize: font.size.lg }, children: "\u203A" })
69
+ ]
70
+ }
71
+ );
72
+ }
73
+
74
+ exports.AskAboutRow = AskAboutRow;
75
+ //# sourceMappingURL=chunk-NMKJ7LIJ.cjs.map
76
+ //# sourceMappingURL=chunk-NMKJ7LIJ.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/AskAboutRow.tsx"],"names":["jsx","CopyProvider","ThemeProvider","useCopy","useTheme","useAgentName","useAgentRuntime","useAgentStatus","useAgentSweep","useState","jsxs","Pressable","View","Text"],"mappings":"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","file":"chunk-NMKJ7LIJ.cjs","sourcesContent":["// \"Ask the agent about this\" on one of the app's own pages (a professional's, a space's, a booking's): a row that opens\n// the agent told the place. It shows only when the agent is available, decided once as the page draws, from the status\n// already read, so it never appears or disappears under content the person is reading.\nimport { type CopyOverrides, CopyProvider, useCopy } from '@vinaverse/react';\nimport {\n useAgentName,\n useAgentRuntime,\n useAgentStatus,\n} from '@vinaverse/react/agent';\nimport { type ComponentType, type ReactNode, useState } from 'react';\nimport { Pressable, Text, View } from 'react-native';\nimport { useAgentSweep } from '../platform.js';\nimport {\n type ColorSchemeSetting,\n type ThemeOverrides,\n ThemeProvider,\n useTheme,\n} from '../theme.js';\n\n/** The row's look beyond the theme. */\nexport interface AskAboutRowAppearance {\n /** A tint behind the row; default the theme's `surface`. */\n readonly background?: string;\n /** The chevron at the row's end. Default true. */\n readonly chevron?: boolean;\n}\n\nexport interface AskAboutRowProps {\n /** \"Ask Example Agent about Riley Sample\". */\n readonly title: string;\n readonly body?: string;\n /** The person asks: open the chat with `entryPoint` (`ask`), so the session says where it was opened from. */\n readonly onPress: (from: { readonly entryPoint: 'ask' }) => void;\n /** The app's brand mark at the row's start; default the agent name's first letter. */\n readonly Mark?: ComponentType<{\n readonly size: number;\n readonly color: string;\n }>;\n readonly appearance?: AskAboutRowAppearance;\n readonly locale?: string;\n readonly copy?: CopyOverrides;\n readonly theme?: ThemeOverrides;\n readonly colorScheme?: ColorSchemeSetting;\n /** The row's test id. Default `vinaverse-ask-about`. */\n readonly testID?: string;\n}\n\nexport function AskAboutRow(props: AskAboutRowProps): ReactNode {\n return (\n <CopyProvider locale={props.locale} copy={props.copy}>\n <ThemeProvider theme={props.theme} colorScheme={props.colorScheme}>\n <Row {...props} />\n </ThemeProvider>\n </CopyProvider>\n );\n}\n\nfunction Row(props: AskAboutRowProps): ReactNode {\n const { t } = useCopy();\n const { colors, radius, space, font } = useTheme();\n const name = useAgentName(t('agentFallbackName'));\n const runtime = useAgentRuntime();\n useAgentStatus(); // reads the status when none is held, for the pages after this one\n useAgentSweep(runtime);\n // Decided once, as the page draws, from the status already read: an agent unknown or unavailable then stays away for\n // the visit, and the row is never added under content the person is reading.\n const [shows] = useState(() => !!runtime.getStatus()?.available);\n if (!shows) return null;\n const { Mark, appearance: look } = props;\n return (\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel={\n props.body ? `${props.title}. ${props.body}` : props.title\n }\n onPress={() => props.onPress({ entryPoint: 'ask' })}\n style={({ pressed }) => ({\n flexDirection: 'row',\n alignItems: 'center',\n gap: space.md,\n padding: space.md,\n borderRadius: radius.lg,\n backgroundColor: look?.background ?? colors.surface,\n opacity: pressed ? 0.85 : 1,\n })}\n testID={props.testID ?? 'vinaverse-ask-about'}\n >\n <View\n style={{\n width: 36,\n height: 36,\n borderRadius: 18,\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: colors.primary,\n }}\n >\n {Mark ? (\n <Mark size={22} color={colors.onPrimary} />\n ) : (\n <Text style={{ color: colors.onPrimary, fontWeight: '600' }}>\n {(name.trim()[0] ?? '?').toUpperCase()}\n </Text>\n )}\n </View>\n <View style={{ flex: 1, gap: space.xxs }}>\n <Text\n style={{\n color: colors.text,\n fontSize: font.size.md,\n fontWeight: '600',\n }}\n >\n {props.title}\n </Text>\n {props.body ? (\n <Text style={{ color: colors.textMuted, fontSize: font.size.sm }}>\n {props.body}\n </Text>\n ) : null}\n </View>\n {look?.chevron === false ? null : (\n <Text style={{ color: colors.textMuted, fontSize: font.size.lg }}>\n ›\n </Text>\n )}\n </Pressable>\n );\n}\n"]}
@@ -0,0 +1,261 @@
1
+ import { ThemeProvider, useReducedMotion, useAgentSweep, announce, useTheme } from './chunk-EFEXTVIT.js';
2
+ import { CopyProvider, useCopy } from '@vinaverse/react';
3
+ import { useAgentName, useAgentRuntime, useAgentLauncher } from '@vinaverse/react/agent';
4
+ import { useState, useEffect, useRef } from 'react';
5
+ import { Platform, Keyboard, View, Animated, Pressable, Text } from 'react-native';
6
+ import { jsx, jsxs } from 'react/jsx-runtime';
7
+
8
+ var LAUNCHER_SIZE = 56;
9
+ function AgentLauncher(props) {
10
+ return /* @__PURE__ */ jsx(CopyProvider, { locale: props.locale, copy: props.copy, children: /* @__PURE__ */ jsx(ThemeProvider, { theme: props.theme, colorScheme: props.colorScheme, children: /* @__PURE__ */ jsx(Launcher, { ...props }) }) });
11
+ }
12
+ function useKeyboardShown() {
13
+ const [shown, setShown] = useState(false);
14
+ useEffect(() => {
15
+ const ios = Platform.OS === "ios";
16
+ const show = Keyboard.addListener(
17
+ ios ? "keyboardWillShow" : "keyboardDidShow",
18
+ () => setShown(true)
19
+ );
20
+ const hide = Keyboard.addListener(
21
+ ios ? "keyboardWillHide" : "keyboardDidHide",
22
+ () => setShown(false)
23
+ );
24
+ return () => {
25
+ show.remove();
26
+ hide.remove();
27
+ };
28
+ }, []);
29
+ return shown;
30
+ }
31
+ function Launcher(props) {
32
+ const { t } = useCopy();
33
+ const name = useAgentName(t("agentFallbackName"));
34
+ const keyboard = useKeyboardShown();
35
+ const reducedMotion = useReducedMotion();
36
+ useAgentSweep(useAgentRuntime());
37
+ const { route = null, routes, mode } = props;
38
+ const visible = props.hidden !== true && !(keyboard && props.hideWithKeyboard !== false) && (!routes || route !== null && routes.includes(route));
39
+ const launcher = useAgentLauncher({
40
+ subject: props.subject,
41
+ mode,
42
+ visible,
43
+ onOpen: () => props.onOpen({ route, mode, entryPoint: "launcher" }),
44
+ ...props.storage ? { storage: props.storage } : {},
45
+ ...props.storageKey ? { storageKey: props.storageKey } : {},
46
+ ...props.delayMs === void 0 ? {} : { delayMs: props.delayMs }
47
+ });
48
+ const text = typeof props.greeting === "function" ? props.greeting(mode) : props.greeting ?? t("launcherGreeting", { agent: name });
49
+ const say = props.announce ?? announce;
50
+ const said = useRef(false);
51
+ useEffect(() => {
52
+ if (!launcher.greets) {
53
+ said.current = false;
54
+ return;
55
+ }
56
+ if (said.current) return;
57
+ said.current = true;
58
+ say(text);
59
+ }, [launcher.greets, text, say]);
60
+ if (!launcher.shows) return null;
61
+ const edge = props.placement?.edge ?? "right";
62
+ const look = props.appearance ?? {};
63
+ const greeting = {
64
+ text,
65
+ closeLabel: t("close"),
66
+ onOpen: launcher.open,
67
+ onClose: launcher.dismiss,
68
+ tail: look.tail !== false,
69
+ edge
70
+ };
71
+ const button = {
72
+ label: t("launcherOpen", { agent: name }),
73
+ name,
74
+ onPress: launcher.open,
75
+ Mark: props.Mark,
76
+ ring: look.ring ?? null,
77
+ shadow: look.shadow !== false
78
+ };
79
+ const { Greeting, Button, Entrance } = props.components ?? {};
80
+ const enter = (part, children) => Entrance ? /* @__PURE__ */ jsx(
81
+ Entrance,
82
+ {
83
+ part,
84
+ reducedMotion,
85
+ Default: LauncherEntrance,
86
+ children
87
+ }
88
+ ) : /* @__PURE__ */ jsx(LauncherEntrance, { part, reducedMotion, children });
89
+ return /* @__PURE__ */ jsxs(
90
+ View,
91
+ {
92
+ pointerEvents: "box-none",
93
+ style: [
94
+ {
95
+ position: "absolute",
96
+ bottom: props.placement?.bottom ?? 16,
97
+ [edge]: props.placement?.inset ?? 16,
98
+ alignItems: edge === "right" ? "flex-end" : "flex-start",
99
+ gap: 8
100
+ },
101
+ props.style
102
+ ],
103
+ testID: "vinaverse-launcher",
104
+ children: [
105
+ launcher.greets ? enter(
106
+ "greeting",
107
+ Greeting ? /* @__PURE__ */ jsx(Greeting, { ...greeting, Default: LauncherGreeting }) : /* @__PURE__ */ jsx(LauncherGreeting, { ...greeting })
108
+ ) : null,
109
+ enter(
110
+ "button",
111
+ Button ? /* @__PURE__ */ jsx(Button, { ...button, Default: LauncherButton }) : /* @__PURE__ */ jsx(LauncherButton, { ...button })
112
+ )
113
+ ]
114
+ }
115
+ );
116
+ }
117
+ function LauncherEntrance(props) {
118
+ const { motion } = useTheme();
119
+ const shown = useRef(new Animated.Value(props.reducedMotion ? 1 : 0)).current;
120
+ useEffect(() => {
121
+ if (props.reducedMotion) {
122
+ shown.setValue(1);
123
+ return;
124
+ }
125
+ const run = Animated.timing(shown, {
126
+ toValue: 1,
127
+ duration: motion.normal,
128
+ useNativeDriver: true
129
+ });
130
+ run.start();
131
+ return () => run.stop();
132
+ }, [shown, props.reducedMotion, motion.normal]);
133
+ return /* @__PURE__ */ jsx(
134
+ Animated.View,
135
+ {
136
+ pointerEvents: "box-none",
137
+ style: {
138
+ opacity: shown,
139
+ transform: [
140
+ {
141
+ scale: shown.interpolate({
142
+ inputRange: [0, 1],
143
+ outputRange: [0.9, 1]
144
+ })
145
+ }
146
+ ]
147
+ },
148
+ testID: `vinaverse-launcher-entrance-${props.part}`,
149
+ children: props.children
150
+ }
151
+ );
152
+ }
153
+ function LauncherGreeting(props) {
154
+ const { colors, radius, space, font } = useTheme();
155
+ return /* @__PURE__ */ jsxs(
156
+ View,
157
+ {
158
+ style: {
159
+ maxWidth: 296,
160
+ flexDirection: "row",
161
+ alignItems: "flex-start",
162
+ borderRadius: radius.lg,
163
+ backgroundColor: colors.text
164
+ },
165
+ testID: "vinaverse-launcher-greeting",
166
+ children: [
167
+ props.tail ? /* @__PURE__ */ jsx(
168
+ View,
169
+ {
170
+ accessible: false,
171
+ style: {
172
+ position: "absolute",
173
+ bottom: -5,
174
+ [props.edge]: LAUNCHER_SIZE / 2 - 6,
175
+ width: 12,
176
+ height: 12,
177
+ backgroundColor: colors.text,
178
+ transform: [{ rotate: "45deg" }]
179
+ },
180
+ testID: "vinaverse-launcher-tail"
181
+ }
182
+ ) : null,
183
+ /* @__PURE__ */ jsx(
184
+ Pressable,
185
+ {
186
+ accessibilityRole: "button",
187
+ accessibilityLabel: props.text,
188
+ onPress: props.onOpen,
189
+ style: {
190
+ flexShrink: 1,
191
+ paddingVertical: space.sm,
192
+ paddingLeft: space.md
193
+ },
194
+ children: /* @__PURE__ */ jsx(Text, { style: { color: colors.background, fontSize: font.size.md }, children: props.text })
195
+ }
196
+ ),
197
+ /* @__PURE__ */ jsx(
198
+ Pressable,
199
+ {
200
+ accessibilityRole: "button",
201
+ accessibilityLabel: props.closeLabel,
202
+ onPress: props.onClose,
203
+ style: {
204
+ minWidth: 44,
205
+ minHeight: 44,
206
+ alignItems: "center",
207
+ justifyContent: "center"
208
+ },
209
+ testID: "vinaverse-launcher-close",
210
+ children: /* @__PURE__ */ jsx(Text, { style: { color: colors.background, fontSize: font.size.md }, children: "\xD7" })
211
+ }
212
+ )
213
+ ]
214
+ }
215
+ );
216
+ }
217
+ function LauncherButton(props) {
218
+ const { colors, font } = useTheme();
219
+ const { Mark, ring } = props;
220
+ return /* @__PURE__ */ jsx(
221
+ Pressable,
222
+ {
223
+ accessibilityRole: "button",
224
+ accessibilityLabel: props.label,
225
+ onPress: props.onPress,
226
+ style: ({ pressed }) => ({
227
+ width: LAUNCHER_SIZE,
228
+ height: LAUNCHER_SIZE,
229
+ borderRadius: LAUNCHER_SIZE / 2,
230
+ alignItems: "center",
231
+ justifyContent: "center",
232
+ backgroundColor: colors.primary,
233
+ opacity: pressed ? 0.85 : 1,
234
+ ...ring ? { borderWidth: ring.width, borderColor: ring.color } : {},
235
+ ...props.shadow ? {
236
+ elevation: 6,
237
+ shadowColor: "#000",
238
+ shadowOpacity: 0.2,
239
+ shadowRadius: 8,
240
+ shadowOffset: { width: 0, height: 3 }
241
+ } : {}
242
+ }),
243
+ testID: "vinaverse-launcher-button",
244
+ children: Mark ? /* @__PURE__ */ jsx(Mark, { size: 34, color: colors.onPrimary }) : /* @__PURE__ */ jsx(
245
+ Text,
246
+ {
247
+ style: {
248
+ color: colors.onPrimary,
249
+ fontSize: font.size.lg,
250
+ fontWeight: "600"
251
+ },
252
+ children: (props.name.trim()[0] ?? "?").toUpperCase()
253
+ }
254
+ )
255
+ }
256
+ );
257
+ }
258
+
259
+ export { AgentLauncher, LAUNCHER_SIZE, LauncherButton, LauncherEntrance, LauncherGreeting, useKeyboardShown };
260
+ //# sourceMappingURL=chunk-POJP52GE.js.map
261
+ //# sourceMappingURL=chunk-POJP52GE.js.map