@paymanai/payman-ask-sdk 2.0.4 → 2.0.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.
- package/README.md +51 -0
- package/dist/index.d.mts +41 -1
- package/dist/index.d.ts +41 -1
- package/dist/index.js +152 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +152 -6
- package/dist/index.mjs.map +1 -1
- package/dist/index.native.js +3251 -330
- package/dist/index.native.js.map +1 -1
- package/dist/styles.css +212 -0
- package/dist/styles.css.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -93,6 +93,15 @@ type ChatConfig = {
|
|
|
93
93
|
text?: string;
|
|
94
94
|
icon?: boolean;
|
|
95
95
|
content?: React.ReactNode;
|
|
96
|
+
suggestions?: {
|
|
97
|
+
enabled?: boolean;
|
|
98
|
+
title?: string;
|
|
99
|
+
categories: Array<{
|
|
100
|
+
label: string;
|
|
101
|
+
icon?: React.ReactNode;
|
|
102
|
+
prompts: string[];
|
|
103
|
+
}>;
|
|
104
|
+
};
|
|
96
105
|
};
|
|
97
106
|
|
|
98
107
|
input?: {
|
|
@@ -154,6 +163,48 @@ Leaving the `ui` block out renders a usable ChatGPT-style surface:
|
|
|
154
163
|
|
|
155
164
|
Turn features on with booleans, and only reach for the full object form when you need custom labels, widths, or per-option toggles.
|
|
156
165
|
|
|
166
|
+
## Suggested prompts
|
|
167
|
+
|
|
168
|
+
Use `ui.emptyState.suggestions` when an app wants SDK-rendered prompt shortcuts on the first screen. Apps own the content; the SDK owns rendering, accessibility, click handling, responsive layout, and styling.
|
|
169
|
+
|
|
170
|
+
The SDK renders categories as compact bubbles first. Clicking a category reveals that category's prompts below it; clicking a prompt sends the prompt text verbatim. On narrow screens and React Native, categories become a horizontal touch scroller so the empty state stays compact.
|
|
171
|
+
|
|
172
|
+
```tsx
|
|
173
|
+
const isProd = process.env.NEXT_PUBLIC_ENV === "production";
|
|
174
|
+
const suggestions = {
|
|
175
|
+
enabled: true,
|
|
176
|
+
title: "Good evening\nHow can I help you today?",
|
|
177
|
+
categories: [
|
|
178
|
+
{ label: "ACCOUNTS", prompts: ["Show my account balance"] },
|
|
179
|
+
{ label: "PAYMENTS", prompts: ["Pay Sarah $50", "Transfer money to my savings"] },
|
|
180
|
+
...(isProd
|
|
181
|
+
? []
|
|
182
|
+
: [{ label: "SIMULATION TOOLS", prompts: ["Simulate a mid-stream error"] }]),
|
|
183
|
+
],
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
<PaymanChat
|
|
187
|
+
config={{
|
|
188
|
+
...config,
|
|
189
|
+
ui: {
|
|
190
|
+
...config.ui,
|
|
191
|
+
emptyState: {
|
|
192
|
+
...config.ui?.emptyState,
|
|
193
|
+
suggestions,
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
}}
|
|
197
|
+
/>
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
`enabled: false` hides the bubbles without removing the data. Category and prompt arrays render in the order provided, and empty categories are ignored. Bubbles disappear after the first message because they are part of the empty state.
|
|
201
|
+
|
|
202
|
+
`title` is optional and falls back to `ui.emptyState.text`. Newlines are preserved, so pass `"Good evening\nHow can I help you today?"` when you want the original two-line empty-state layout. If a single-line greeting like `"Good evening How can I help..."` is provided, the SDK inserts a dash between the greeting and question.
|
|
203
|
+
|
|
204
|
+
`icon` is optional. When omitted, the SDK chooses a small built-in glyph from the category label for common labels like payments, accounts, insights, and products.
|
|
205
|
+
|
|
206
|
+
Suggested prompts use the same `--payman-v2-*` CSS variables as the rest of the chat surface, so app-level theme overrides automatically apply to bubble background, text, border, hover, radius, and focus states. The React Native renderer uses native `Pressable` and `ScrollView` controls with the same category-first behavior.
|
|
207
|
+
|
|
157
208
|
## Session history
|
|
158
209
|
|
|
159
210
|
Pass `ui.sessionHistory: true` and provide `workflow.id` + `session.owner.id`. `<PaymanChat/>` mounts a resizable, collapsible sidebar on desktop and a hamburger-triggered drawer on mobile. Clicking a row calls `loadSession(sessionId)` — which cancels any in-flight stream, clears the current chat, fetches the conversation history, and renders it with `isHistorical: true` (renderers skip the thinking/step UI for those rows).
|
package/dist/index.d.mts
CHANGED
|
@@ -55,8 +55,39 @@ type SessionHistoryOptions = {
|
|
|
55
55
|
/** Show a sidebar "New Session" button wired to the chat reset flow. Default: false */
|
|
56
56
|
showNewSessionButton?: boolean;
|
|
57
57
|
};
|
|
58
|
+
type EmptyStatePromptCategory = {
|
|
59
|
+
/** Label shown in the category bubble, e.g. "Account". Also used as the accessible name for the prompt group. */
|
|
60
|
+
label: string;
|
|
61
|
+
/** Optional icon rendered before the label in the category bubble. */
|
|
62
|
+
icon?: React__default.ReactNode;
|
|
63
|
+
/** Prompt strings; clicking sends the string verbatim. Array order is preserved as render order. */
|
|
64
|
+
prompts: string[];
|
|
65
|
+
};
|
|
66
|
+
type EmptyStateSuggestionsConfig = {
|
|
67
|
+
/** Default: true. Pass false to hide bubbles without removing data. */
|
|
68
|
+
enabled?: boolean;
|
|
69
|
+
/** Optional heading above categories. Falls back to ui.emptyState.text. */
|
|
70
|
+
title?: string;
|
|
71
|
+
/**
|
|
72
|
+
* Categories rendered in array order. Apps that need environment-specific
|
|
73
|
+
* categories (e.g. internal-only "SIMULATION TOOLS") should filter this
|
|
74
|
+
* array on the consumer side — the SDK has no notion of dev/prod and will
|
|
75
|
+
* render exactly what is passed.
|
|
76
|
+
*/
|
|
77
|
+
categories: EmptyStatePromptCategory[];
|
|
78
|
+
};
|
|
58
79
|
type ChatUIConfig = {
|
|
59
80
|
layout?: "centered" | "full-width";
|
|
81
|
+
/**
|
|
82
|
+
* Color scheme for the React Native chat surface.
|
|
83
|
+
* Web styling continues to follow Tailwind. Default: "light".
|
|
84
|
+
*/
|
|
85
|
+
theme?: "light" | "dark";
|
|
86
|
+
/**
|
|
87
|
+
* Accent / brand color used by the native chat UI (send button, hero,
|
|
88
|
+
* focused border, etc). Defaults to Payman teal `#00858d`.
|
|
89
|
+
*/
|
|
90
|
+
accent?: string;
|
|
60
91
|
agent?: {
|
|
61
92
|
/** Default: "Assistant" */
|
|
62
93
|
name?: string;
|
|
@@ -66,10 +97,19 @@ type ChatUIConfig = {
|
|
|
66
97
|
emptyState?: {
|
|
67
98
|
/** Default: "What can I help with?" */
|
|
68
99
|
text?: string;
|
|
100
|
+
/**
|
|
101
|
+
* Small line above the main empty-state text (e.g. "Hi, Mike").
|
|
102
|
+
* Native only — web ignores this for now.
|
|
103
|
+
*/
|
|
104
|
+
eyebrow?: string;
|
|
69
105
|
/** Default: true */
|
|
70
106
|
icon?: boolean;
|
|
71
107
|
/** Custom React node rendered above the empty-state text */
|
|
72
108
|
content?: React__default.ReactNode;
|
|
109
|
+
/** Custom logo element rendered in the empty state (native only). Replaces the default HeroMark. */
|
|
110
|
+
logo?: React__default.ReactNode;
|
|
111
|
+
/** Optional app-provided prompt bubbles rendered by the SDK. */
|
|
112
|
+
suggestions?: EmptyStateSuggestionsConfig;
|
|
73
113
|
};
|
|
74
114
|
input?: {
|
|
75
115
|
/** Default: "Type your message..." */
|
|
@@ -358,4 +398,4 @@ declare function captureSentryError(error: Error | string, context: ChatSessionC
|
|
|
358
398
|
*/
|
|
359
399
|
declare function formatRelativeTime(iso: string, now?: Date): string;
|
|
360
400
|
|
|
361
|
-
export { type AssistantMessageActionsConfig, type ChatAvailability, type ChatCallbacks, type ChatConfig, ChatHeader, type ChatHeaderProps, type ChatSessionContext, type ChatUIConfig, FloatingChat, type MessageActionsConfig, type MessageListV2Props, type OtpInputProps, PaymanChat, PaymanChatContext, type PaymanChatContextValue, type PaymanChatProps, type PaymanChatRef, type SessionHistoryOptions, SessionHistorySidebar, type Stage, type StreamingMessageProps, UserActionModal, type UserActionModalProps, type UserMessageActionsConfig, type VoiceOptions, captureSentryError, cn, formatDate, formatRelativeTime, usePaymanChat, useSessionHistory };
|
|
401
|
+
export { type AssistantMessageActionsConfig, type ChatAvailability, type ChatCallbacks, type ChatConfig, ChatHeader, type ChatHeaderProps, type ChatSessionContext, type ChatUIConfig, type EmptyStatePromptCategory, type EmptyStateSuggestionsConfig, FloatingChat, type MessageActionsConfig, type MessageListV2Props, type OtpInputProps, PaymanChat, PaymanChatContext, type PaymanChatContextValue, type PaymanChatProps, type PaymanChatRef, type SessionHistoryOptions, SessionHistorySidebar, type Stage, type StreamingMessageProps, UserActionModal, type UserActionModalProps, type UserMessageActionsConfig, type VoiceOptions, captureSentryError, cn, formatDate, formatRelativeTime, usePaymanChat, useSessionHistory };
|
package/dist/index.d.ts
CHANGED
|
@@ -55,8 +55,39 @@ type SessionHistoryOptions = {
|
|
|
55
55
|
/** Show a sidebar "New Session" button wired to the chat reset flow. Default: false */
|
|
56
56
|
showNewSessionButton?: boolean;
|
|
57
57
|
};
|
|
58
|
+
type EmptyStatePromptCategory = {
|
|
59
|
+
/** Label shown in the category bubble, e.g. "Account". Also used as the accessible name for the prompt group. */
|
|
60
|
+
label: string;
|
|
61
|
+
/** Optional icon rendered before the label in the category bubble. */
|
|
62
|
+
icon?: React__default.ReactNode;
|
|
63
|
+
/** Prompt strings; clicking sends the string verbatim. Array order is preserved as render order. */
|
|
64
|
+
prompts: string[];
|
|
65
|
+
};
|
|
66
|
+
type EmptyStateSuggestionsConfig = {
|
|
67
|
+
/** Default: true. Pass false to hide bubbles without removing data. */
|
|
68
|
+
enabled?: boolean;
|
|
69
|
+
/** Optional heading above categories. Falls back to ui.emptyState.text. */
|
|
70
|
+
title?: string;
|
|
71
|
+
/**
|
|
72
|
+
* Categories rendered in array order. Apps that need environment-specific
|
|
73
|
+
* categories (e.g. internal-only "SIMULATION TOOLS") should filter this
|
|
74
|
+
* array on the consumer side — the SDK has no notion of dev/prod and will
|
|
75
|
+
* render exactly what is passed.
|
|
76
|
+
*/
|
|
77
|
+
categories: EmptyStatePromptCategory[];
|
|
78
|
+
};
|
|
58
79
|
type ChatUIConfig = {
|
|
59
80
|
layout?: "centered" | "full-width";
|
|
81
|
+
/**
|
|
82
|
+
* Color scheme for the React Native chat surface.
|
|
83
|
+
* Web styling continues to follow Tailwind. Default: "light".
|
|
84
|
+
*/
|
|
85
|
+
theme?: "light" | "dark";
|
|
86
|
+
/**
|
|
87
|
+
* Accent / brand color used by the native chat UI (send button, hero,
|
|
88
|
+
* focused border, etc). Defaults to Payman teal `#00858d`.
|
|
89
|
+
*/
|
|
90
|
+
accent?: string;
|
|
60
91
|
agent?: {
|
|
61
92
|
/** Default: "Assistant" */
|
|
62
93
|
name?: string;
|
|
@@ -66,10 +97,19 @@ type ChatUIConfig = {
|
|
|
66
97
|
emptyState?: {
|
|
67
98
|
/** Default: "What can I help with?" */
|
|
68
99
|
text?: string;
|
|
100
|
+
/**
|
|
101
|
+
* Small line above the main empty-state text (e.g. "Hi, Mike").
|
|
102
|
+
* Native only — web ignores this for now.
|
|
103
|
+
*/
|
|
104
|
+
eyebrow?: string;
|
|
69
105
|
/** Default: true */
|
|
70
106
|
icon?: boolean;
|
|
71
107
|
/** Custom React node rendered above the empty-state text */
|
|
72
108
|
content?: React__default.ReactNode;
|
|
109
|
+
/** Custom logo element rendered in the empty state (native only). Replaces the default HeroMark. */
|
|
110
|
+
logo?: React__default.ReactNode;
|
|
111
|
+
/** Optional app-provided prompt bubbles rendered by the SDK. */
|
|
112
|
+
suggestions?: EmptyStateSuggestionsConfig;
|
|
73
113
|
};
|
|
74
114
|
input?: {
|
|
75
115
|
/** Default: "Type your message..." */
|
|
@@ -358,4 +398,4 @@ declare function captureSentryError(error: Error | string, context: ChatSessionC
|
|
|
358
398
|
*/
|
|
359
399
|
declare function formatRelativeTime(iso: string, now?: Date): string;
|
|
360
400
|
|
|
361
|
-
export { type AssistantMessageActionsConfig, type ChatAvailability, type ChatCallbacks, type ChatConfig, ChatHeader, type ChatHeaderProps, type ChatSessionContext, type ChatUIConfig, FloatingChat, type MessageActionsConfig, type MessageListV2Props, type OtpInputProps, PaymanChat, PaymanChatContext, type PaymanChatContextValue, type PaymanChatProps, type PaymanChatRef, type SessionHistoryOptions, SessionHistorySidebar, type Stage, type StreamingMessageProps, UserActionModal, type UserActionModalProps, type UserMessageActionsConfig, type VoiceOptions, captureSentryError, cn, formatDate, formatRelativeTime, usePaymanChat, useSessionHistory };
|
|
401
|
+
export { type AssistantMessageActionsConfig, type ChatAvailability, type ChatCallbacks, type ChatConfig, ChatHeader, type ChatHeaderProps, type ChatSessionContext, type ChatUIConfig, type EmptyStatePromptCategory, type EmptyStateSuggestionsConfig, FloatingChat, type MessageActionsConfig, type MessageListV2Props, type OtpInputProps, PaymanChat, PaymanChatContext, type PaymanChatContextValue, type PaymanChatProps, type PaymanChatRef, type SessionHistoryOptions, SessionHistorySidebar, type Stage, type StreamingMessageProps, UserActionModal, type UserActionModalProps, type UserMessageActionsConfig, type VoiceOptions, captureSentryError, cn, formatDate, formatRelativeTime, usePaymanChat, useSessionHistory };
|
package/dist/index.js
CHANGED
|
@@ -2523,6 +2523,136 @@ function ImageLightboxV2({ src, alt, onClose }) {
|
|
|
2523
2523
|
document.body
|
|
2524
2524
|
);
|
|
2525
2525
|
}
|
|
2526
|
+
function slugify(value) {
|
|
2527
|
+
const slug = value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
2528
|
+
return slug || "category";
|
|
2529
|
+
}
|
|
2530
|
+
function formatSuggestionTitle(value) {
|
|
2531
|
+
return value.replace(
|
|
2532
|
+
/\b(Good (?:morning|afternoon|evening))[ \t]+(?=how can I help)/i,
|
|
2533
|
+
"$1 - "
|
|
2534
|
+
);
|
|
2535
|
+
}
|
|
2536
|
+
function CategoryGlyph({ label }) {
|
|
2537
|
+
const normalizedLabel = label.toLowerCase();
|
|
2538
|
+
const icon = normalizedLabel.includes("pay") || normalizedLabel.includes("transfer") ? "arrow" : normalizedLabel.includes("account") ? "card" : normalizedLabel.includes("insight") || normalizedLabel.includes("analytics") ? "chart" : normalizedLabel.includes("product") ? "clock" : "spark";
|
|
2539
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "payman-v2-prompt-category-icon", "aria-hidden": "true", children: [
|
|
2540
|
+
icon === "arrow" && /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 20 20", focusable: "false", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 10h11m0 0-4-4m4 4-4 4" }) }),
|
|
2541
|
+
icon === "card" && /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 20 20", focusable: "false", children: [
|
|
2542
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3.5", y: "5.5", width: "13", height: "9", rx: "1.5" }),
|
|
2543
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3.5 8h13" })
|
|
2544
|
+
] }),
|
|
2545
|
+
icon === "chart" && /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 20 20", focusable: "false", children: [
|
|
2546
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 15.5V4.5" }),
|
|
2547
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 15.5h12" }),
|
|
2548
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6.5 12 3-3 2 2 3.5-4" })
|
|
2549
|
+
] }),
|
|
2550
|
+
icon === "clock" && /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 20 20", focusable: "false", children: [
|
|
2551
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "10", cy: "10", r: "6" }),
|
|
2552
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10 6.5V10l2.5 1.5" })
|
|
2553
|
+
] }),
|
|
2554
|
+
icon === "spark" && /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 20 20", focusable: "false", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10 3.5 11.5 8l4 2-4 2L10 16.5 8.5 12l-4-2 4-2L10 3.5Z" }) })
|
|
2555
|
+
] });
|
|
2556
|
+
}
|
|
2557
|
+
function PromptSuggestionsV2({
|
|
2558
|
+
title,
|
|
2559
|
+
categories,
|
|
2560
|
+
disabled = false,
|
|
2561
|
+
onPromptClick
|
|
2562
|
+
}) {
|
|
2563
|
+
const shouldReduceMotion = framerMotion.useReducedMotion();
|
|
2564
|
+
const validCategories = react.useMemo(
|
|
2565
|
+
() => categories.filter((category) => category.prompts.length > 0),
|
|
2566
|
+
[categories]
|
|
2567
|
+
);
|
|
2568
|
+
const [activeCategoryIndex, setActiveCategoryIndex] = react.useState(null);
|
|
2569
|
+
react.useEffect(() => {
|
|
2570
|
+
if (activeCategoryIndex != null && (activeCategoryIndex < 0 || activeCategoryIndex >= validCategories.length)) {
|
|
2571
|
+
setActiveCategoryIndex(null);
|
|
2572
|
+
}
|
|
2573
|
+
}, [activeCategoryIndex, validCategories.length]);
|
|
2574
|
+
if (validCategories.length === 0) return null;
|
|
2575
|
+
const fadeTransition = { duration: 0.18, ease: "easeOut" };
|
|
2576
|
+
const rootMotionProps = shouldReduceMotion ? {} : {
|
|
2577
|
+
initial: { opacity: 0, y: 4 },
|
|
2578
|
+
animate: { opacity: 1, y: 0 },
|
|
2579
|
+
transition: fadeTransition
|
|
2580
|
+
};
|
|
2581
|
+
const getBubbleMotionProps = (index) => shouldReduceMotion ? {} : {
|
|
2582
|
+
initial: { opacity: 0, y: 4 },
|
|
2583
|
+
animate: { opacity: 1, y: 0 },
|
|
2584
|
+
transition: { ...fadeTransition, delay: 0.04 * index }
|
|
2585
|
+
};
|
|
2586
|
+
const activeCategory = activeCategoryIndex == null ? null : validCategories[activeCategoryIndex] ?? null;
|
|
2587
|
+
const activePanelId = activeCategoryIndex == null ? void 0 : `payman-v2-prompt-panel-${slugify(activeCategory?.label ?? "category")}-${activeCategoryIndex}`;
|
|
2588
|
+
const displayTitle = title ? formatSuggestionTitle(title) : void 0;
|
|
2589
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(framerMotion.motion.div, { className: "payman-v2-prompt-root", ...rootMotionProps, children: [
|
|
2590
|
+
displayTitle && /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "payman-v2-prompt-title", children: displayTitle }),
|
|
2591
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "payman-v2-prompt-category-row", "aria-label": "Prompt categories", children: validCategories.map((category, categoryIndex) => {
|
|
2592
|
+
const isActive = activeCategoryIndex === categoryIndex;
|
|
2593
|
+
const categoryId = `payman-v2-prompt-cat-${slugify(category.label)}-${categoryIndex}`;
|
|
2594
|
+
const panelId = `payman-v2-prompt-panel-${slugify(category.label)}-${categoryIndex}`;
|
|
2595
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2596
|
+
framerMotion.motion.button,
|
|
2597
|
+
{
|
|
2598
|
+
id: categoryId,
|
|
2599
|
+
type: "button",
|
|
2600
|
+
"aria-expanded": isActive,
|
|
2601
|
+
"aria-controls": panelId,
|
|
2602
|
+
onClick: () => setActiveCategoryIndex(
|
|
2603
|
+
(currentIndex) => currentIndex === categoryIndex ? null : categoryIndex
|
|
2604
|
+
),
|
|
2605
|
+
className: "payman-v2-prompt-category-bubble",
|
|
2606
|
+
"data-active": isActive ? "true" : "false",
|
|
2607
|
+
...getBubbleMotionProps(categoryIndex),
|
|
2608
|
+
children: [
|
|
2609
|
+
category.icon ?? /* @__PURE__ */ jsxRuntime.jsx(CategoryGlyph, { label: category.label }),
|
|
2610
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: category.label })
|
|
2611
|
+
]
|
|
2612
|
+
},
|
|
2613
|
+
`${category.label}-${categoryIndex}`
|
|
2614
|
+
);
|
|
2615
|
+
}) }),
|
|
2616
|
+
/* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { initial: false, mode: "wait", children: activeCategory && activeCategoryIndex != null && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2617
|
+
framerMotion.motion.section,
|
|
2618
|
+
{
|
|
2619
|
+
id: activePanelId,
|
|
2620
|
+
role: "region",
|
|
2621
|
+
"aria-labelledby": `payman-v2-prompt-cat-${slugify(activeCategory.label)}-${activeCategoryIndex}`,
|
|
2622
|
+
className: "payman-v2-prompt-category",
|
|
2623
|
+
initial: shouldReduceMotion ? void 0 : { opacity: 0, y: -2 },
|
|
2624
|
+
animate: shouldReduceMotion ? void 0 : { opacity: 1, y: 0 },
|
|
2625
|
+
exit: shouldReduceMotion ? void 0 : { opacity: 0, y: -2 },
|
|
2626
|
+
transition: fadeTransition,
|
|
2627
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2628
|
+
"div",
|
|
2629
|
+
{
|
|
2630
|
+
className: "payman-v2-prompt-row",
|
|
2631
|
+
role: "group",
|
|
2632
|
+
"aria-label": `${activeCategory.label} prompts`,
|
|
2633
|
+
children: activeCategory.prompts.map((prompt, promptIndex) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2634
|
+
framerMotion.motion.button,
|
|
2635
|
+
{
|
|
2636
|
+
type: "button",
|
|
2637
|
+
disabled,
|
|
2638
|
+
onClick: () => onPromptClick(prompt),
|
|
2639
|
+
className: "payman-v2-prompt-bubble",
|
|
2640
|
+
"aria-label": `Use suggested prompt: ${prompt}`,
|
|
2641
|
+
...getBubbleMotionProps(promptIndex),
|
|
2642
|
+
children: [
|
|
2643
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: prompt }),
|
|
2644
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "payman-v2-prompt-option-arrow", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 20 20", focusable: "false", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7 13 13 7m0 0H8m5 0v5" }) }) })
|
|
2645
|
+
]
|
|
2646
|
+
},
|
|
2647
|
+
`${prompt}-${promptIndex}`
|
|
2648
|
+
))
|
|
2649
|
+
}
|
|
2650
|
+
)
|
|
2651
|
+
},
|
|
2652
|
+
`${activeCategory.label}-${activeCategoryIndex}`
|
|
2653
|
+
) })
|
|
2654
|
+
] });
|
|
2655
|
+
}
|
|
2526
2656
|
var DEFAULT_WIDTH = 260;
|
|
2527
2657
|
var DEFAULT_MIN_WIDTH = 220;
|
|
2528
2658
|
var DEFAULT_MAX_WIDTH = 440;
|
|
@@ -3717,6 +3847,8 @@ var PaymanChat = react.forwardRef(function PaymanChat2({
|
|
|
3717
3847
|
const emptyStateText = ui.emptyState?.text ?? DEFAULT_EMPTY_STATE_TEXT;
|
|
3718
3848
|
const showEmptyStateIcon = ui.emptyState?.icon ?? true;
|
|
3719
3849
|
const emptyStateComponent = ui.emptyState?.content;
|
|
3850
|
+
const suggestions = ui.emptyState?.suggestions;
|
|
3851
|
+
const showSuggestions = suggestions != null && suggestions.enabled !== false && suggestions.categories.some((category) => category.prompts.length > 0);
|
|
3720
3852
|
const showResetButton = ui.input?.showResetButton ?? false;
|
|
3721
3853
|
const attachments = normalizeAttachments(ui.input?.attachments);
|
|
3722
3854
|
const voice = normalizeVoice(ui.input?.voice);
|
|
@@ -3875,13 +4007,13 @@ var PaymanChat = react.forwardRef(function PaymanChat2({
|
|
|
3875
4007
|
v2VerificationPending
|
|
3876
4008
|
]);
|
|
3877
4009
|
const hideV2SendDuringVerification = v2UserAction != null && v2UserAction.status !== "approved" && v2UserAction.status !== "rejected";
|
|
3878
|
-
const handleV2Send = (text) => {
|
|
4010
|
+
const handleV2Send = react.useCallback((text) => {
|
|
3879
4011
|
if (isRecording) stopRecording();
|
|
3880
4012
|
if (text.trim()) {
|
|
3881
4013
|
setEditingMessageId(null);
|
|
3882
4014
|
void sendMessage(text.trim());
|
|
3883
4015
|
}
|
|
3884
|
-
};
|
|
4016
|
+
}, [isRecording, sendMessage, stopRecording]);
|
|
3885
4017
|
const handleEditMessageDraft = react.useCallback(
|
|
3886
4018
|
(messageId) => {
|
|
3887
4019
|
const targetMessage = messages.find((m) => m.id === messageId);
|
|
@@ -4021,7 +4153,10 @@ var PaymanChat = react.forwardRef(function PaymanChat2({
|
|
|
4021
4153
|
{
|
|
4022
4154
|
text: emptyStateText,
|
|
4023
4155
|
content: emptyStateComponent,
|
|
4024
|
-
showIcon: showEmptyStateIcon
|
|
4156
|
+
showIcon: showEmptyStateIcon && !showSuggestions,
|
|
4157
|
+
suggestions: showSuggestions ? suggestions : void 0,
|
|
4158
|
+
onPromptClick: handleV2Send,
|
|
4159
|
+
isStreaming: isWaitingForResponse
|
|
4025
4160
|
}
|
|
4026
4161
|
),
|
|
4027
4162
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -4130,7 +4265,10 @@ var PaymanChat = react.forwardRef(function PaymanChat2({
|
|
|
4130
4265
|
function EmptyState2({
|
|
4131
4266
|
text,
|
|
4132
4267
|
content,
|
|
4133
|
-
showIcon
|
|
4268
|
+
showIcon,
|
|
4269
|
+
suggestions,
|
|
4270
|
+
onPromptClick,
|
|
4271
|
+
isStreaming
|
|
4134
4272
|
}) {
|
|
4135
4273
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4136
4274
|
"div",
|
|
@@ -4147,7 +4285,7 @@ function EmptyState2({
|
|
|
4147
4285
|
},
|
|
4148
4286
|
children: [
|
|
4149
4287
|
content,
|
|
4150
|
-
showIcon && !content && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4288
|
+
showIcon && !content && !suggestions && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4151
4289
|
"div",
|
|
4152
4290
|
{
|
|
4153
4291
|
"aria-hidden": "true",
|
|
@@ -4159,7 +4297,15 @@ function EmptyState2({
|
|
|
4159
4297
|
}
|
|
4160
4298
|
}
|
|
4161
4299
|
),
|
|
4162
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4300
|
+
suggestions && onPromptClick ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4301
|
+
PromptSuggestionsV2,
|
|
4302
|
+
{
|
|
4303
|
+
title: suggestions.title ?? text,
|
|
4304
|
+
categories: suggestions.categories,
|
|
4305
|
+
disabled: isStreaming,
|
|
4306
|
+
onPromptClick
|
|
4307
|
+
}
|
|
4308
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
4163
4309
|
"div",
|
|
4164
4310
|
{
|
|
4165
4311
|
style: {
|