@paymanai/payman-ask-sdk 2.0.5 → 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/dist/index.mjs CHANGED
@@ -2498,6 +2498,136 @@ function ImageLightboxV2({ src, alt, onClose }) {
2498
2498
  document.body
2499
2499
  );
2500
2500
  }
2501
+ function slugify(value) {
2502
+ const slug = value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
2503
+ return slug || "category";
2504
+ }
2505
+ function formatSuggestionTitle(value) {
2506
+ return value.replace(
2507
+ /\b(Good (?:morning|afternoon|evening))[ \t]+(?=how can I help)/i,
2508
+ "$1 - "
2509
+ );
2510
+ }
2511
+ function CategoryGlyph({ label }) {
2512
+ const normalizedLabel = label.toLowerCase();
2513
+ 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";
2514
+ return /* @__PURE__ */ jsxs("span", { className: "payman-v2-prompt-category-icon", "aria-hidden": "true", children: [
2515
+ icon === "arrow" && /* @__PURE__ */ jsx("svg", { viewBox: "0 0 20 20", focusable: "false", children: /* @__PURE__ */ jsx("path", { d: "M4 10h11m0 0-4-4m4 4-4 4" }) }),
2516
+ icon === "card" && /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 20 20", focusable: "false", children: [
2517
+ /* @__PURE__ */ jsx("rect", { x: "3.5", y: "5.5", width: "13", height: "9", rx: "1.5" }),
2518
+ /* @__PURE__ */ jsx("path", { d: "M3.5 8h13" })
2519
+ ] }),
2520
+ icon === "chart" && /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 20 20", focusable: "false", children: [
2521
+ /* @__PURE__ */ jsx("path", { d: "M4 15.5V4.5" }),
2522
+ /* @__PURE__ */ jsx("path", { d: "M4 15.5h12" }),
2523
+ /* @__PURE__ */ jsx("path", { d: "m6.5 12 3-3 2 2 3.5-4" })
2524
+ ] }),
2525
+ icon === "clock" && /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 20 20", focusable: "false", children: [
2526
+ /* @__PURE__ */ jsx("circle", { cx: "10", cy: "10", r: "6" }),
2527
+ /* @__PURE__ */ jsx("path", { d: "M10 6.5V10l2.5 1.5" })
2528
+ ] }),
2529
+ icon === "spark" && /* @__PURE__ */ jsx("svg", { viewBox: "0 0 20 20", focusable: "false", children: /* @__PURE__ */ jsx("path", { d: "M10 3.5 11.5 8l4 2-4 2L10 16.5 8.5 12l-4-2 4-2L10 3.5Z" }) })
2530
+ ] });
2531
+ }
2532
+ function PromptSuggestionsV2({
2533
+ title,
2534
+ categories,
2535
+ disabled = false,
2536
+ onPromptClick
2537
+ }) {
2538
+ const shouldReduceMotion = useReducedMotion();
2539
+ const validCategories = useMemo(
2540
+ () => categories.filter((category) => category.prompts.length > 0),
2541
+ [categories]
2542
+ );
2543
+ const [activeCategoryIndex, setActiveCategoryIndex] = useState(null);
2544
+ useEffect(() => {
2545
+ if (activeCategoryIndex != null && (activeCategoryIndex < 0 || activeCategoryIndex >= validCategories.length)) {
2546
+ setActiveCategoryIndex(null);
2547
+ }
2548
+ }, [activeCategoryIndex, validCategories.length]);
2549
+ if (validCategories.length === 0) return null;
2550
+ const fadeTransition = { duration: 0.18, ease: "easeOut" };
2551
+ const rootMotionProps = shouldReduceMotion ? {} : {
2552
+ initial: { opacity: 0, y: 4 },
2553
+ animate: { opacity: 1, y: 0 },
2554
+ transition: fadeTransition
2555
+ };
2556
+ const getBubbleMotionProps = (index) => shouldReduceMotion ? {} : {
2557
+ initial: { opacity: 0, y: 4 },
2558
+ animate: { opacity: 1, y: 0 },
2559
+ transition: { ...fadeTransition, delay: 0.04 * index }
2560
+ };
2561
+ const activeCategory = activeCategoryIndex == null ? null : validCategories[activeCategoryIndex] ?? null;
2562
+ const activePanelId = activeCategoryIndex == null ? void 0 : `payman-v2-prompt-panel-${slugify(activeCategory?.label ?? "category")}-${activeCategoryIndex}`;
2563
+ const displayTitle = title ? formatSuggestionTitle(title) : void 0;
2564
+ return /* @__PURE__ */ jsxs(motion.div, { className: "payman-v2-prompt-root", ...rootMotionProps, children: [
2565
+ displayTitle && /* @__PURE__ */ jsx("h2", { className: "payman-v2-prompt-title", children: displayTitle }),
2566
+ /* @__PURE__ */ jsx("div", { className: "payman-v2-prompt-category-row", "aria-label": "Prompt categories", children: validCategories.map((category, categoryIndex) => {
2567
+ const isActive = activeCategoryIndex === categoryIndex;
2568
+ const categoryId = `payman-v2-prompt-cat-${slugify(category.label)}-${categoryIndex}`;
2569
+ const panelId = `payman-v2-prompt-panel-${slugify(category.label)}-${categoryIndex}`;
2570
+ return /* @__PURE__ */ jsxs(
2571
+ motion.button,
2572
+ {
2573
+ id: categoryId,
2574
+ type: "button",
2575
+ "aria-expanded": isActive,
2576
+ "aria-controls": panelId,
2577
+ onClick: () => setActiveCategoryIndex(
2578
+ (currentIndex) => currentIndex === categoryIndex ? null : categoryIndex
2579
+ ),
2580
+ className: "payman-v2-prompt-category-bubble",
2581
+ "data-active": isActive ? "true" : "false",
2582
+ ...getBubbleMotionProps(categoryIndex),
2583
+ children: [
2584
+ category.icon ?? /* @__PURE__ */ jsx(CategoryGlyph, { label: category.label }),
2585
+ /* @__PURE__ */ jsx("span", { children: category.label })
2586
+ ]
2587
+ },
2588
+ `${category.label}-${categoryIndex}`
2589
+ );
2590
+ }) }),
2591
+ /* @__PURE__ */ jsx(AnimatePresence, { initial: false, mode: "wait", children: activeCategory && activeCategoryIndex != null && /* @__PURE__ */ jsx(
2592
+ motion.section,
2593
+ {
2594
+ id: activePanelId,
2595
+ role: "region",
2596
+ "aria-labelledby": `payman-v2-prompt-cat-${slugify(activeCategory.label)}-${activeCategoryIndex}`,
2597
+ className: "payman-v2-prompt-category",
2598
+ initial: shouldReduceMotion ? void 0 : { opacity: 0, y: -2 },
2599
+ animate: shouldReduceMotion ? void 0 : { opacity: 1, y: 0 },
2600
+ exit: shouldReduceMotion ? void 0 : { opacity: 0, y: -2 },
2601
+ transition: fadeTransition,
2602
+ children: /* @__PURE__ */ jsx(
2603
+ "div",
2604
+ {
2605
+ className: "payman-v2-prompt-row",
2606
+ role: "group",
2607
+ "aria-label": `${activeCategory.label} prompts`,
2608
+ children: activeCategory.prompts.map((prompt, promptIndex) => /* @__PURE__ */ jsxs(
2609
+ motion.button,
2610
+ {
2611
+ type: "button",
2612
+ disabled,
2613
+ onClick: () => onPromptClick(prompt),
2614
+ className: "payman-v2-prompt-bubble",
2615
+ "aria-label": `Use suggested prompt: ${prompt}`,
2616
+ ...getBubbleMotionProps(promptIndex),
2617
+ children: [
2618
+ /* @__PURE__ */ jsx("span", { children: prompt }),
2619
+ /* @__PURE__ */ jsx("span", { className: "payman-v2-prompt-option-arrow", "aria-hidden": "true", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 20 20", focusable: "false", children: /* @__PURE__ */ jsx("path", { d: "M7 13 13 7m0 0H8m5 0v5" }) }) })
2620
+ ]
2621
+ },
2622
+ `${prompt}-${promptIndex}`
2623
+ ))
2624
+ }
2625
+ )
2626
+ },
2627
+ `${activeCategory.label}-${activeCategoryIndex}`
2628
+ ) })
2629
+ ] });
2630
+ }
2501
2631
  var DEFAULT_WIDTH = 260;
2502
2632
  var DEFAULT_MIN_WIDTH = 220;
2503
2633
  var DEFAULT_MAX_WIDTH = 440;
@@ -3692,6 +3822,8 @@ var PaymanChat = forwardRef(function PaymanChat2({
3692
3822
  const emptyStateText = ui.emptyState?.text ?? DEFAULT_EMPTY_STATE_TEXT;
3693
3823
  const showEmptyStateIcon = ui.emptyState?.icon ?? true;
3694
3824
  const emptyStateComponent = ui.emptyState?.content;
3825
+ const suggestions = ui.emptyState?.suggestions;
3826
+ const showSuggestions = suggestions != null && suggestions.enabled !== false && suggestions.categories.some((category) => category.prompts.length > 0);
3695
3827
  const showResetButton = ui.input?.showResetButton ?? false;
3696
3828
  const attachments = normalizeAttachments(ui.input?.attachments);
3697
3829
  const voice = normalizeVoice(ui.input?.voice);
@@ -3850,13 +3982,13 @@ var PaymanChat = forwardRef(function PaymanChat2({
3850
3982
  v2VerificationPending
3851
3983
  ]);
3852
3984
  const hideV2SendDuringVerification = v2UserAction != null && v2UserAction.status !== "approved" && v2UserAction.status !== "rejected";
3853
- const handleV2Send = (text) => {
3985
+ const handleV2Send = useCallback((text) => {
3854
3986
  if (isRecording) stopRecording();
3855
3987
  if (text.trim()) {
3856
3988
  setEditingMessageId(null);
3857
3989
  void sendMessage(text.trim());
3858
3990
  }
3859
- };
3991
+ }, [isRecording, sendMessage, stopRecording]);
3860
3992
  const handleEditMessageDraft = useCallback(
3861
3993
  (messageId) => {
3862
3994
  const targetMessage = messages.find((m) => m.id === messageId);
@@ -3996,7 +4128,10 @@ var PaymanChat = forwardRef(function PaymanChat2({
3996
4128
  {
3997
4129
  text: emptyStateText,
3998
4130
  content: emptyStateComponent,
3999
- showIcon: showEmptyStateIcon
4131
+ showIcon: showEmptyStateIcon && !showSuggestions,
4132
+ suggestions: showSuggestions ? suggestions : void 0,
4133
+ onPromptClick: handleV2Send,
4134
+ isStreaming: isWaitingForResponse
4000
4135
  }
4001
4136
  ),
4002
4137
  /* @__PURE__ */ jsx(
@@ -4105,7 +4240,10 @@ var PaymanChat = forwardRef(function PaymanChat2({
4105
4240
  function EmptyState2({
4106
4241
  text,
4107
4242
  content,
4108
- showIcon
4243
+ showIcon,
4244
+ suggestions,
4245
+ onPromptClick,
4246
+ isStreaming
4109
4247
  }) {
4110
4248
  return /* @__PURE__ */ jsxs(
4111
4249
  "div",
@@ -4122,7 +4260,7 @@ function EmptyState2({
4122
4260
  },
4123
4261
  children: [
4124
4262
  content,
4125
- showIcon && !content && /* @__PURE__ */ jsx(
4263
+ showIcon && !content && !suggestions && /* @__PURE__ */ jsx(
4126
4264
  "div",
4127
4265
  {
4128
4266
  "aria-hidden": "true",
@@ -4134,7 +4272,15 @@ function EmptyState2({
4134
4272
  }
4135
4273
  }
4136
4274
  ),
4137
- /* @__PURE__ */ jsx(
4275
+ suggestions && onPromptClick ? /* @__PURE__ */ jsx(
4276
+ PromptSuggestionsV2,
4277
+ {
4278
+ title: suggestions.title ?? text,
4279
+ categories: suggestions.categories,
4280
+ disabled: isStreaming,
4281
+ onPromptClick
4282
+ }
4283
+ ) : /* @__PURE__ */ jsx(
4138
4284
  "div",
4139
4285
  {
4140
4286
  style: {