@meridial/react 0.1.0 → 0.1.1

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.
@@ -19,7 +19,7 @@ import {
19
19
  useMergedRefs,
20
20
  useRenderElement,
21
21
  useStableCallback
22
- } from "./chunk-QCWLFL7O.js";
22
+ } from "./chunk-PRTYKFO3.js";
23
23
 
24
24
  // src/voicebox.tsx
25
25
  import {
@@ -35,7 +35,7 @@ import {
35
35
  useRef as useRef6,
36
36
  useState as useState9,
37
37
  useMemo as useMemo5,
38
- useEffect as useEffect5,
38
+ useEffect as useEffect6,
39
39
  useCallback as useCallback5
40
40
  } from "react";
41
41
  import { ChatFeedback01Icon, Loading03Icon as Loading03Icon3 } from "@hugeicons/core-free-icons";
@@ -1015,7 +1015,7 @@ function StartAudioButton({
1015
1015
  }
1016
1016
 
1017
1017
  // src/components/workflow-execution.tsx
1018
- import { useState as useState7, useCallback as useCallback4, useRef as useRef5 } from "react";
1018
+ import { useState as useState7, useCallback as useCallback4, useEffect as useEffect5, useRef as useRef5 } from "react";
1019
1019
  import { createPortal } from "react-dom";
1020
1020
  import {
1021
1021
  motion,
@@ -1035,8 +1035,10 @@ var SPRING_CONFIG = { stiffness: 120, damping: 20, mass: 0.8 };
1035
1035
  var CURSOR_OFFSET = 16;
1036
1036
  function WorkflowExecution({
1037
1037
  workflow,
1038
+ attribute = "data-meridial-id",
1038
1039
  cursor,
1039
1040
  onClose,
1041
+ onStepChange,
1040
1042
  onError
1041
1043
  }) {
1042
1044
  const [currentIndex, setCurrentIndex] = useState7(0);
@@ -1044,6 +1046,9 @@ function WorkflowExecution({
1044
1046
  const currentStep = steps[currentIndex];
1045
1047
  const isFirstStep = currentIndex === 0;
1046
1048
  const isLastStep = currentIndex === steps.length - 1;
1049
+ useEffect5(() => {
1050
+ onStepChange?.(currentIndex);
1051
+ }, [currentIndex, onStepChange]);
1047
1052
  const handleBack = useCallback4(() => {
1048
1053
  setCurrentIndex((prev) => Math.max(0, prev - 1));
1049
1054
  }, []);
@@ -1065,6 +1070,7 @@ function WorkflowExecution({
1065
1070
  totalSteps: steps.length,
1066
1071
  isFirstStep,
1067
1072
  isLastStep,
1073
+ attribute,
1068
1074
  cursor,
1069
1075
  onBack: handleBack,
1070
1076
  onNext: handleNext,
@@ -1078,13 +1084,15 @@ function ExecutionOverlay({
1078
1084
  totalSteps,
1079
1085
  isFirstStep,
1080
1086
  isLastStep,
1087
+ attribute,
1081
1088
  cursor,
1082
1089
  onBack,
1083
1090
  onNext,
1084
1091
  onError
1085
1092
  }) {
1093
+ const cssSelector = `[${attribute}="${step.elementId}"]`;
1086
1094
  const { rect } = useElementTracker({
1087
- selector: step.elementId,
1095
+ selector: cssSelector,
1088
1096
  urlPath: step.urlPath,
1089
1097
  onError: onError ? (msg) => {
1090
1098
  if (msg !== null) onError(msg);
@@ -1368,21 +1376,16 @@ import { HugeiconsIcon as HugeiconsIcon6 } from "@hugeicons/react";
1368
1376
  import {
1369
1377
  Call02Icon,
1370
1378
  ViewOffSlashIcon,
1371
- ArrowDown01Icon,
1372
- PlayIcon
1379
+ PlayIcon,
1380
+ Cancel01Icon,
1381
+ StarIcon
1373
1382
  } from "@hugeicons/core-free-icons";
1374
1383
  import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
1375
- var POSITIONS = [
1376
- "top-left",
1377
- "top-right",
1378
- "bottom-left",
1379
- "bottom-right"
1380
- ];
1381
1384
  var POSITION_LABELS = {
1382
- "top-left": "TL",
1383
- "top-right": "TR",
1384
- "bottom-left": "BL",
1385
- "bottom-right": "BR"
1385
+ "top-left": "Top Left",
1386
+ "top-right": "Top Right",
1387
+ "bottom-left": "Bottom Left",
1388
+ "bottom-right": "Bottom Right"
1386
1389
  };
1387
1390
  var MENU_PLACEMENT = {
1388
1391
  "bottom-right": {
@@ -1407,22 +1410,31 @@ var MENU_PLACEMENT = {
1407
1410
  }
1408
1411
  };
1409
1412
  function VoiceboxMenu({
1410
- favoriteWorkflows,
1413
+ workflows,
1411
1414
  position,
1415
+ playingWorkflowId,
1416
+ playingStepIndex = 0,
1412
1417
  onPositionChange,
1413
1418
  onHide,
1414
1419
  onAskMeridial,
1415
- onPlayGuide
1420
+ onPlayGuide,
1421
+ onAbortGuide
1416
1422
  }) {
1417
1423
  const placement = MENU_PLACEMENT[position];
1418
- const [guidesExpanded, setGuidesExpanded] = useState8(false);
1419
- const hasFavorites = favoriteWorkflows.length > 0;
1424
+ const [activeTab, setActiveTab] = useState8("settings");
1425
+ const sortedWorkflows = [...workflows].sort((a, b) => {
1426
+ if (a.isFavorite && !b.isFavorite) return -1;
1427
+ if (!a.isFavorite && b.isFavorite) return 1;
1428
+ return 0;
1429
+ });
1420
1430
  return /* @__PURE__ */ jsxs7(
1421
1431
  motion2.div,
1422
1432
  {
1423
1433
  "data-meridial-ui": true,
1434
+ onClick: (e) => e.stopPropagation(),
1424
1435
  className: cn(
1425
- "absolute z-50 w-56 overflow-hidden rounded-lg border border-border bg-card shadow-lg",
1436
+ "absolute z-50 w-72 overflow-hidden rounded-lg border border-border bg-card shadow-lg",
1437
+ "[&::-webkit-scrollbar]:hidden scrollbar-none",
1426
1438
  placement.className
1427
1439
  ),
1428
1440
  initial: { opacity: 0, scale: 0.9 },
@@ -1433,108 +1445,173 @@ function VoiceboxMenu({
1433
1445
  },
1434
1446
  transition: { duration: 0.15, ease: "easeOut" },
1435
1447
  children: [
1436
- hasFavorites && /* @__PURE__ */ jsxs7("div", { "data-meridial-ui": true, className: "border-b border-border", children: [
1437
- /* @__PURE__ */ jsxs7(
1448
+ /* @__PURE__ */ jsxs7("div", { "data-meridial-ui": true, className: "flex border-b border-border", children: [
1449
+ /* @__PURE__ */ jsx12(
1438
1450
  "button",
1439
1451
  {
1440
1452
  "data-meridial-ui": true,
1441
- onClick: () => setGuidesExpanded((prev) => !prev),
1442
- className: "flex w-full cursor-pointer items-center justify-between px-3 py-2",
1443
- children: [
1444
- /* @__PURE__ */ jsx12("span", { className: "text-xs font-medium tracking-wider text-muted-foreground", children: "Top Guides" }),
1453
+ onClick: () => setActiveTab("settings"),
1454
+ className: cn(
1455
+ "flex-1 cursor-pointer px-3 py-2 text-xs font-medium tracking-wider transition-colors",
1456
+ activeTab === "settings" ? "border-b-2 border-primary text-foreground" : "text-muted-foreground hover:text-foreground"
1457
+ ),
1458
+ children: "Settings"
1459
+ }
1460
+ ),
1461
+ /* @__PURE__ */ jsx12(
1462
+ "button",
1463
+ {
1464
+ "data-meridial-ui": true,
1465
+ onClick: () => setActiveTab("guides"),
1466
+ className: cn(
1467
+ "flex-1 cursor-pointer px-3 py-2 text-xs font-medium tracking-wider transition-colors",
1468
+ activeTab === "guides" ? "border-b-2 border-primary text-foreground" : "text-muted-foreground hover:text-foreground"
1469
+ ),
1470
+ children: "Guides"
1471
+ }
1472
+ )
1473
+ ] }),
1474
+ /* @__PURE__ */ jsx12(AnimatePresence2, { mode: "wait", children: activeTab === "settings" ? /* @__PURE__ */ jsxs7(
1475
+ motion2.div,
1476
+ {
1477
+ initial: { opacity: 0 },
1478
+ animate: { opacity: 1 },
1479
+ exit: { opacity: 0 },
1480
+ transition: { duration: 0.1 },
1481
+ className: "flex flex-col gap-0 h-[200px]",
1482
+ children: [
1483
+ /* @__PURE__ */ jsxs7(
1484
+ "div",
1485
+ {
1486
+ "data-meridial-ui": true,
1487
+ className: "border-b border-border px-3 py-2.5",
1488
+ children: [
1489
+ /* @__PURE__ */ jsx12("span", { className: "mb-1.5 block text-xs font-medium tracking-wider text-muted-foreground", children: "Position" }),
1490
+ /* @__PURE__ */ jsx12("div", { className: "grid grid-cols-2 gap-1", children: Object.entries(POSITION_LABELS).map(([pos, label]) => /* @__PURE__ */ jsx12(
1491
+ "button",
1492
+ {
1493
+ "data-meridial-ui": true,
1494
+ onClick: () => onPositionChange(pos),
1495
+ className: cn(
1496
+ "cursor-pointer rounded px-2 py-1.5 text-xs font-medium transition-colors",
1497
+ pos === position ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground hover:bg-muted/80 hover:text-foreground"
1498
+ ),
1499
+ children: label
1500
+ },
1501
+ pos
1502
+ )) })
1503
+ ]
1504
+ }
1505
+ ),
1506
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center justify-between border-b border-border px-3 py-2.5", children: [
1507
+ /* @__PURE__ */ jsx12("span", { className: "text-xs font-medium tracking-wider text-muted-foreground", children: "Hide Until Next Visit" }),
1445
1508
  /* @__PURE__ */ jsx12(
1446
- HugeiconsIcon6,
1509
+ Button,
1447
1510
  {
1448
- icon: ArrowDown01Icon,
1449
- size: 14,
1450
- className: cn(
1451
- "shrink-0 text-muted-foreground transition-transform duration-200",
1452
- guidesExpanded && "rotate-180"
1511
+ variant: "ghost",
1512
+ size: "sm",
1513
+ "data-meridial-ui": true,
1514
+ onClick: onHide,
1515
+ children: /* @__PURE__ */ jsx12(
1516
+ HugeiconsIcon6,
1517
+ {
1518
+ icon: ViewOffSlashIcon,
1519
+ size: 16,
1520
+ className: "shrink-0"
1521
+ }
1453
1522
  )
1454
1523
  }
1455
1524
  )
1456
- ]
1457
- }
1458
- ),
1459
- /* @__PURE__ */ jsx12(AnimatePresence2, { initial: false, children: guidesExpanded && /* @__PURE__ */ jsx12(
1460
- motion2.div,
1461
- {
1462
- initial: { height: 0, opacity: 0 },
1463
- animate: { height: "auto", opacity: 1 },
1464
- exit: { height: 0, opacity: 0 },
1465
- transition: { duration: 0.15, ease: "easeOut" },
1466
- style: { overflow: "hidden" },
1467
- children: /* @__PURE__ */ jsx12("div", { className: "flex flex-col gap-0.5 px-3 pb-2", children: favoriteWorkflows.map((wf) => /* @__PURE__ */ jsxs7(
1468
- "button",
1525
+ ] }),
1526
+ /* @__PURE__ */ jsx12("div", { className: "flex items-center justify-center p-2", children: /* @__PURE__ */ jsxs7(
1527
+ Button,
1469
1528
  {
1470
1529
  "data-meridial-ui": true,
1471
- onClick: () => onPlayGuide(wf),
1472
- className: "flex w-full cursor-pointer items-center gap-2 rounded px-1.5 py-1 text-left text-sm text-foreground hover:bg-muted/50",
1530
+ onClick: onAskMeridial,
1531
+ variant: "default",
1532
+ className: "w-full",
1473
1533
  children: [
1474
1534
  /* @__PURE__ */ jsx12(
1475
1535
  HugeiconsIcon6,
1476
1536
  {
1477
- icon: PlayIcon,
1537
+ icon: Call02Icon,
1478
1538
  size: 16,
1479
- className: "shrink-0 text-primary fill-primary/60"
1539
+ className: "shrink-0"
1480
1540
  }
1481
1541
  ),
1482
- /* @__PURE__ */ jsx12("span", { className: "truncate", children: wf.name })
1542
+ "Ask For Help"
1543
+ ]
1544
+ }
1545
+ ) })
1546
+ ]
1547
+ },
1548
+ "settings"
1549
+ ) : /* @__PURE__ */ jsx12(
1550
+ motion2.div,
1551
+ {
1552
+ initial: { opacity: 0 },
1553
+ animate: { opacity: 1 },
1554
+ exit: { opacity: 0 },
1555
+ transition: { duration: 0.1 },
1556
+ className: "h-[200px] overflow-y-auto",
1557
+ children: sortedWorkflows.length === 0 ? /* @__PURE__ */ jsx12("div", { className: "flex h-full items-center justify-center text-xs text-muted-foreground", children: "No guides available" }) : /* @__PURE__ */ jsx12("div", { className: "flex flex-col gap-0.5 p-2", children: sortedWorkflows.map((wf) => {
1558
+ const isPlaying = wf.id === playingWorkflowId;
1559
+ const totalSteps = wf.steps.length;
1560
+ const progressPercent = isPlaying && totalSteps > 0 ? (playingStepIndex + 1) / totalSteps * 100 : 0;
1561
+ return /* @__PURE__ */ jsxs7(
1562
+ "div",
1563
+ {
1564
+ "data-meridial-ui": true,
1565
+ className: "relative overflow-hidden rounded-md px-3 py-2 hover:bg-muted",
1566
+ children: [
1567
+ isPlaying && /* @__PURE__ */ jsx12(
1568
+ "div",
1569
+ {
1570
+ className: "absolute inset-0 bg-primary/10 transition-[width] duration-300 ease-out",
1571
+ style: { width: `${progressPercent}%` }
1572
+ }
1573
+ ),
1574
+ /* @__PURE__ */ jsxs7("div", { className: "relative flex items-start gap-2", children: [
1575
+ /* @__PURE__ */ jsxs7("div", { className: "min-w-0 flex-1", children: [
1576
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-1", children: [
1577
+ wf.isFavorite && /* @__PURE__ */ jsx12(
1578
+ HugeiconsIcon6,
1579
+ {
1580
+ icon: StarIcon,
1581
+ size: 12,
1582
+ className: "shrink-0 fill-amber-400 text-amber-400"
1583
+ }
1584
+ ),
1585
+ /* @__PURE__ */ jsx12("span", { className: "line-clamp-1 text-sm font-medium text-foreground", children: wf.name })
1586
+ ] }),
1587
+ wf.description && /* @__PURE__ */ jsx12("p", { className: "line-clamp-2 mt-0.5 text-xs text-muted-foreground", children: wf.description })
1588
+ ] }),
1589
+ /* @__PURE__ */ jsx12(
1590
+ Button,
1591
+ {
1592
+ variant: "ghost",
1593
+ size: "icon",
1594
+ "data-meridial-ui": true,
1595
+ onClick: () => isPlaying ? onAbortGuide() : onPlayGuide(wf),
1596
+ children: /* @__PURE__ */ jsx12(
1597
+ HugeiconsIcon6,
1598
+ {
1599
+ icon: isPlaying ? Cancel01Icon : PlayIcon,
1600
+ size: 16,
1601
+ className: isPlaying ? "" : "fill-primary/60 text-primary"
1602
+ }
1603
+ )
1604
+ }
1605
+ )
1606
+ ] })
1483
1607
  ]
1484
1608
  },
1485
1609
  wf.id
1486
- )) })
1487
- }
1488
- ) })
1489
- ] }),
1490
- /* @__PURE__ */ jsxs7("div", { "data-meridial-ui": true, className: "border-b border-border px-3 py-2", children: [
1491
- /* @__PURE__ */ jsx12("span", { className: "text-xs font-medium tracking-wider text-muted-foreground", children: "Position" }),
1492
- /* @__PURE__ */ jsx12("div", { className: "mt-1 grid grid-cols-4 gap-1", children: POSITIONS.map((pos) => /* @__PURE__ */ jsx12(
1493
- "button",
1494
- {
1495
- "data-meridial-ui": true,
1496
- onClick: () => onPositionChange(pos),
1497
- className: cn(
1498
- "cursor-pointer rounded px-2 py-1 text-xs font-medium transition-colors",
1499
- pos === position ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground hover:bg-muted/80 hover:text-foreground"
1500
- ),
1501
- children: POSITION_LABELS[pos]
1502
- },
1503
- pos
1504
- )) })
1505
- ] }),
1506
- /* @__PURE__ */ jsxs7("div", { className: "px-3 py-2 flex items-center justify-between", children: [
1507
- /* @__PURE__ */ jsx12("span", { className: "text-xs font-medium uppercase tracking-wider text-muted-foreground", children: "Hide Until Next Visit" }),
1508
- /* @__PURE__ */ jsx12(Button, { variant: "ghost", size: "sm", "data-meridial-ui": true, onClick: onHide, children: /* @__PURE__ */ jsx12(
1509
- HugeiconsIcon6,
1510
- {
1511
- icon: ViewOffSlashIcon,
1512
- size: 16,
1513
- className: "shrink-0"
1514
- }
1515
- ) })
1516
- ] }),
1517
- /* @__PURE__ */ jsx12(Separator, {}),
1518
- /* @__PURE__ */ jsxs7("div", { className: "px-3 py-2 flex items-center justify-between", children: [
1519
- /* @__PURE__ */ jsx12("span", { className: "text-xs font-medium tracking-wider text-muted-foreground", children: "Ask For Help" }),
1520
- /* @__PURE__ */ jsx12(
1521
- Button,
1522
- {
1523
- "data-meridial-ui": true,
1524
- onClick: onAskMeridial,
1525
- variant: "ghost",
1526
- size: "sm",
1527
- children: /* @__PURE__ */ jsx12(
1528
- HugeiconsIcon6,
1529
- {
1530
- icon: Call02Icon,
1531
- size: 16,
1532
- className: "shrink-0 fill-primary/60 text-primary"
1533
- }
1534
- )
1535
- }
1536
- )
1537
- ] })
1610
+ );
1611
+ }) })
1612
+ },
1613
+ "guides"
1614
+ ) })
1538
1615
  ]
1539
1616
  }
1540
1617
  );
@@ -1548,12 +1625,6 @@ var BADGE_POSITION_CLASSES = {
1548
1625
  "top-right": "right-6 top-6",
1549
1626
  "top-left": "left-6 top-6"
1550
1627
  };
1551
- var BAR_POSITION_CLASSES = {
1552
- "bottom-right": "right-4 bottom-4",
1553
- "bottom-left": "left-4 bottom-4",
1554
- "top-right": "right-4 top-4",
1555
- "top-left": "left-4 top-4"
1556
- };
1557
1628
  function VoiceboxBadge({
1558
1629
  triggerIcon,
1559
1630
  onClick
@@ -1572,9 +1643,9 @@ function VoiceboxBadge({
1572
1643
  function VoiceboxContent({
1573
1644
  baseUrl,
1574
1645
  publishableKey,
1646
+ attribute,
1575
1647
  tools,
1576
1648
  cursor,
1577
- barPosition,
1578
1649
  initialWorkflow,
1579
1650
  onDisconnect,
1580
1651
  onError
@@ -1610,7 +1681,7 @@ function VoiceboxContent({
1610
1681
  );
1611
1682
  useToolRegistration(tools, triggerOutcomeBar);
1612
1683
  useDraggable(draggableRef);
1613
- useEffect5(() => {
1684
+ useEffect6(() => {
1614
1685
  if (!publishableKey) return;
1615
1686
  fetch(`${baseUrl}/api/workflows`, {
1616
1687
  headers: { Authorization: `Bearer ${publishableKey}` }
@@ -1622,7 +1693,7 @@ function VoiceboxContent({
1622
1693
  );
1623
1694
  });
1624
1695
  }, [baseUrl, publishableKey]);
1625
- useEffect5(() => {
1696
+ useEffect6(() => {
1626
1697
  room.registerRpcMethod("workflow:execute", async (rpcData) => {
1627
1698
  try {
1628
1699
  const { slug } = JSON.parse(rpcData.payload);
@@ -1654,7 +1725,7 @@ function VoiceboxContent({
1654
1725
  }, [room]);
1655
1726
  const { state } = useAgent();
1656
1727
  const { start } = useSessionContext3();
1657
- useEffect5(() => {
1728
+ useEffect6(() => {
1658
1729
  if (!autoStarted.current) {
1659
1730
  autoStarted.current = true;
1660
1731
  start();
@@ -1671,91 +1742,107 @@ function VoiceboxContent({
1671
1742
  WorkflowExecution,
1672
1743
  {
1673
1744
  workflow: activeWorkflow.workflow,
1745
+ attribute,
1674
1746
  cursor,
1675
- onClose: () => setActiveWorkflow(null),
1747
+ onClose: () => {
1748
+ setActiveWorkflow(null);
1749
+ triggerOutcomeBar();
1750
+ },
1676
1751
  onError
1677
1752
  }
1678
1753
  ),
1679
- /* @__PURE__ */ jsxs8(
1680
- "div",
1754
+ /* @__PURE__ */ jsx13(
1755
+ motion3.div,
1681
1756
  {
1682
- ref: draggableRef,
1683
- "data-meridial-ui": true,
1684
- className: cn(
1685
- "fixed z-50 w-96 items-stretch rounded border border-border bg-card shadow-md",
1686
- BAR_POSITION_CLASSES[barPosition]
1687
- ),
1688
- children: [
1689
- /* @__PURE__ */ jsx13(AnimatePresence3, { initial: false, children: showTranscript && /* @__PURE__ */ jsx13(
1690
- motion3.div,
1691
- {
1692
- initial: { height: 0, opacity: 0 },
1693
- animate: { height: "auto", opacity: 1 },
1694
- exit: { height: 0, opacity: 0 },
1695
- transition: { duration: 0.24, ease: "easeOut" },
1696
- style: { overflow: "hidden" },
1697
- children: /* @__PURE__ */ jsx13(AgentTranscriptPanel, {})
1698
- }
1699
- ) }),
1700
- /* @__PURE__ */ jsx13(AnimatePresence3, { initial: false, children: showOutcomeBar && /* @__PURE__ */ jsx13(
1701
- motion3.div,
1702
- {
1703
- initial: { height: 0, opacity: 0 },
1704
- animate: { height: "auto", opacity: 1 },
1705
- exit: { height: 0, opacity: 0 },
1706
- transition: { duration: 0.24, ease: "easeOut" },
1707
- style: { overflow: "hidden" },
1708
- children: /* @__PURE__ */ jsx13(OutcomeBar, { onSubmit: handleOutcomeSubmit })
1709
- }
1710
- ) }),
1711
- /* @__PURE__ */ jsxs8("div", { "data-meridial-ui": true, className: "flex h-12 items-center", children: [
1712
- /* @__PURE__ */ jsx13(DragHandle, { className: "px-2" }),
1713
- /* @__PURE__ */ jsx13(Separator, { orientation: "vertical", className: "h-full" }),
1714
- /* @__PURE__ */ jsxs8("div", { className: "relative flex h-full flex-1 items-center justify-between px-2", children: [
1715
- /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
1716
- /* @__PURE__ */ jsx13(
1717
- AgentTrackControl,
1718
- {
1719
- source: "microphone",
1720
- pressed: microphoneToggle.enabled,
1721
- pending: microphoneToggle.pending,
1722
- disabled: microphoneToggle.pending,
1723
- audioTrack: microphoneTrack,
1724
- onPressedChange: microphoneToggle.toggle
1725
- }
1726
- ),
1727
- /* @__PURE__ */ jsx13(
1728
- Toggle3,
1729
- {
1730
- disabled: isDisconnected || isConnecting,
1731
- pressed: showTranscript,
1732
- "aria-label": "Toggle transcript",
1733
- onPressedChange: setShowTranscript,
1734
- className: cn(
1735
- "size-9 rounded-lg",
1736
- showTranscript ? "bg-muted text-foreground" : "bg-transparent text-muted-foreground hover:text-foreground"
1757
+ initial: { opacity: 0, y: 20 },
1758
+ animate: { opacity: 1, y: 0 },
1759
+ transition: { duration: 0.3, ease: "easeOut" },
1760
+ className: "fixed inset-x-0 bottom-8 z-50 flex justify-center",
1761
+ children: /* @__PURE__ */ jsxs8(
1762
+ "div",
1763
+ {
1764
+ ref: draggableRef,
1765
+ "data-meridial-ui": true,
1766
+ className: "w-96 items-stretch rounded border border-border bg-card shadow-md",
1767
+ children: [
1768
+ /* @__PURE__ */ jsx13(AnimatePresence3, { initial: false, children: showTranscript && /* @__PURE__ */ jsx13(
1769
+ motion3.div,
1770
+ {
1771
+ initial: { height: 0, opacity: 0 },
1772
+ animate: { height: "auto", opacity: 1 },
1773
+ exit: { height: 0, opacity: 0 },
1774
+ transition: { duration: 0.24, ease: "easeOut" },
1775
+ style: { overflow: "hidden" },
1776
+ children: /* @__PURE__ */ jsx13(AgentTranscriptPanel, {})
1777
+ }
1778
+ ) }),
1779
+ /* @__PURE__ */ jsx13(AnimatePresence3, { initial: false, children: showOutcomeBar && /* @__PURE__ */ jsx13(
1780
+ motion3.div,
1781
+ {
1782
+ initial: { height: 0, opacity: 0 },
1783
+ animate: { height: "auto", opacity: 1 },
1784
+ exit: { height: 0, opacity: 0 },
1785
+ transition: { duration: 0.24, ease: "easeOut" },
1786
+ style: { overflow: "hidden" },
1787
+ children: /* @__PURE__ */ jsx13(OutcomeBar, { onSubmit: handleOutcomeSubmit })
1788
+ }
1789
+ ) }),
1790
+ /* @__PURE__ */ jsxs8("div", { "data-meridial-ui": true, className: "flex h-12 items-center", children: [
1791
+ /* @__PURE__ */ jsx13(DragHandle, { className: "px-2" }),
1792
+ /* @__PURE__ */ jsx13(Separator, { orientation: "vertical", className: "h-full" }),
1793
+ /* @__PURE__ */ jsxs8("div", { className: "relative flex h-full flex-1 items-center justify-between px-2", children: [
1794
+ /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
1795
+ /* @__PURE__ */ jsx13(
1796
+ AgentTrackControl,
1797
+ {
1798
+ source: "microphone",
1799
+ pressed: microphoneToggle.enabled,
1800
+ pending: microphoneToggle.pending,
1801
+ disabled: microphoneToggle.pending,
1802
+ audioTrack: microphoneTrack,
1803
+ onPressedChange: microphoneToggle.toggle
1804
+ }
1737
1805
  ),
1738
- children: /* @__PURE__ */ jsx13(HugeiconsIcon7, { icon: ChatFeedback01Icon })
1739
- }
1740
- ),
1741
- /* @__PURE__ */ jsx13(
1742
- AgentAudioVisualizerBar,
1743
- {
1744
- barCount: 12,
1745
- state,
1746
- audioTrack: microphoneTrack,
1747
- className: "mx-4"
1748
- }
1749
- )
1750
- ] }),
1751
- isConnecting ? /* @__PURE__ */ jsxs8(Button, { variant: "outline", children: [
1752
- /* @__PURE__ */ jsx13("span", { children: "Connecting" }),
1753
- /* @__PURE__ */ jsx13(HugeiconsIcon7, { icon: Loading03Icon3, className: "animate-spin" })
1754
- ] }) : /* @__PURE__ */ jsx13(AgentDisconnectButton, { onClick: handleDisconnect }),
1755
- /* @__PURE__ */ jsx13(StartAudioButton, { label: "Start Audio" })
1756
- ] })
1757
- ] })
1758
- ]
1806
+ /* @__PURE__ */ jsx13(
1807
+ Toggle3,
1808
+ {
1809
+ disabled: isDisconnected || isConnecting,
1810
+ pressed: showTranscript,
1811
+ "aria-label": "Toggle transcript",
1812
+ onPressedChange: setShowTranscript,
1813
+ className: cn(
1814
+ "size-9 rounded-lg",
1815
+ showTranscript ? "bg-muted text-foreground" : "bg-transparent text-muted-foreground hover:text-foreground"
1816
+ ),
1817
+ children: /* @__PURE__ */ jsx13(HugeiconsIcon7, { icon: ChatFeedback01Icon })
1818
+ }
1819
+ ),
1820
+ /* @__PURE__ */ jsx13(
1821
+ AgentAudioVisualizerBar,
1822
+ {
1823
+ barCount: 12,
1824
+ state,
1825
+ audioTrack: microphoneTrack,
1826
+ className: "mx-4"
1827
+ }
1828
+ )
1829
+ ] }),
1830
+ isConnecting ? /* @__PURE__ */ jsxs8(Button, { variant: "outline", children: [
1831
+ /* @__PURE__ */ jsx13("span", { children: "Connecting" }),
1832
+ /* @__PURE__ */ jsx13(
1833
+ HugeiconsIcon7,
1834
+ {
1835
+ icon: Loading03Icon3,
1836
+ className: "animate-spin"
1837
+ }
1838
+ )
1839
+ ] }) : /* @__PURE__ */ jsx13(AgentDisconnectButton, { onClick: handleDisconnect }),
1840
+ /* @__PURE__ */ jsx13(StartAudioButton, { label: "Start Audio" })
1841
+ ] })
1842
+ ] })
1843
+ ]
1844
+ }
1845
+ )
1759
1846
  }
1760
1847
  )
1761
1848
  ] });
@@ -1764,6 +1851,7 @@ function Voicebox({
1764
1851
  baseUrl = "",
1765
1852
  publishableKey,
1766
1853
  identifier,
1854
+ attribute,
1767
1855
  tools,
1768
1856
  triggerIcon,
1769
1857
  cursor,
@@ -1778,24 +1866,26 @@ function Voicebox({
1778
1866
  if (typeof window === "undefined") return "bottom-right";
1779
1867
  return localStorage.getItem(STORAGE_KEYS.triggerPos) || "bottom-right";
1780
1868
  });
1781
- const [favoriteWorkflows, setFavoriteWorkflows] = useState9([]);
1869
+ const [allWorkflows, setAllWorkflows] = useState9([]);
1782
1870
  const [initialWorkflow, setInitialWorkflow] = useState9(null);
1783
1871
  const [guideWorkflow, setGuideWorkflow] = useState9(null);
1784
- useEffect5(() => {
1872
+ const [playingWorkflowId, setPlayingWorkflowId] = useState9(
1873
+ null
1874
+ );
1875
+ const [playingStepIndex, setPlayingStepIndex] = useState9(0);
1876
+ useEffect6(() => {
1785
1877
  if (sessionStorage.getItem(STORAGE_KEYS.hidden) === "true") {
1786
1878
  setHidden(true);
1787
1879
  }
1788
1880
  }, []);
1789
- useEffect5(() => {
1881
+ useEffect6(() => {
1790
1882
  if (!publishableKey) return;
1791
1883
  fetch(`${baseUrl}/api/workflows`, {
1792
1884
  headers: { Authorization: `Bearer ${publishableKey}` }
1793
1885
  }).then((r) => r.json()).then((data) => {
1794
1886
  const parsed = apiWorkflowsResponseSchema.safeParse(data);
1795
1887
  if (parsed.success && parsed.data.workflows) {
1796
- setFavoriteWorkflows(
1797
- parsed.data.workflows.filter((w) => w.isFavorite)
1798
- );
1888
+ setAllWorkflows(parsed.data.workflows);
1799
1889
  }
1800
1890
  }).catch(() => {
1801
1891
  });
@@ -1861,73 +1951,73 @@ function Voicebox({
1861
1951
  configured: true,
1862
1952
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
1863
1953
  });
1864
- setView("guide");
1954
+ setPlayingWorkflowId(wf.id);
1955
+ setPlayingStepIndex(0);
1956
+ };
1957
+ const handleAbortGuide = () => {
1958
+ setGuideWorkflow(null);
1959
+ setPlayingWorkflowId(null);
1960
+ setPlayingStepIndex(0);
1865
1961
  };
1866
1962
  const handleBadgeClick = () => {
1867
1963
  setView((prev) => prev === "menu" ? "badge" : "menu");
1868
1964
  };
1869
1965
  if (hidden) return null;
1870
- return /* @__PURE__ */ jsx13(AgentSessionProvider, { session, children: view === "call" ? /* @__PURE__ */ jsx13(
1871
- VoiceboxContent,
1872
- {
1873
- baseUrl,
1874
- publishableKey,
1875
- tools,
1876
- cursor,
1877
- barPosition: badgePosition,
1878
- initialWorkflow,
1879
- onDisconnect: handleDisconnect,
1880
- onError
1881
- }
1882
- ) : view === "guide" && guideWorkflow ? /* @__PURE__ */ jsxs8(Fragment4, { children: [
1883
- /* @__PURE__ */ jsx13(
1966
+ return /* @__PURE__ */ jsxs8(AgentSessionProvider, { session, children: [
1967
+ guideWorkflow && /* @__PURE__ */ jsx13(
1884
1968
  WorkflowExecution,
1885
1969
  {
1886
1970
  workflow: guideWorkflow,
1971
+ attribute,
1887
1972
  cursor,
1888
1973
  onClose: () => {
1889
1974
  setGuideWorkflow(null);
1890
- setView("badge");
1975
+ setPlayingWorkflowId(null);
1976
+ setPlayingStepIndex(0);
1891
1977
  },
1978
+ onStepChange: (index) => setPlayingStepIndex(index),
1892
1979
  onError
1893
1980
  }
1894
1981
  ),
1895
- /* @__PURE__ */ jsx13(
1982
+ view === "call" ? /* @__PURE__ */ jsx13(
1983
+ VoiceboxContent,
1984
+ {
1985
+ baseUrl,
1986
+ publishableKey,
1987
+ attribute,
1988
+ tools,
1989
+ cursor,
1990
+ initialWorkflow,
1991
+ onDisconnect: handleDisconnect,
1992
+ onError
1993
+ }
1994
+ ) : /* @__PURE__ */ jsxs8(
1896
1995
  "div",
1897
1996
  {
1898
1997
  className: cn("fixed z-50", BADGE_POSITION_CLASSES[badgePosition]),
1899
- children: /* @__PURE__ */ jsx13(
1900
- VoiceboxBadge,
1901
- {
1902
- triggerIcon,
1903
- onClick: handleBadgeClick
1904
- }
1905
- )
1998
+ children: [
1999
+ /* @__PURE__ */ jsx13(AnimatePresence3, { children: view === "menu" && /* @__PURE__ */ jsx13(
2000
+ VoiceboxMenu,
2001
+ {
2002
+ workflows: allWorkflows,
2003
+ position: badgePosition,
2004
+ playingWorkflowId,
2005
+ playingStepIndex,
2006
+ onPositionChange: handlePositionChange,
2007
+ onHide: handleHide,
2008
+ onAskMeridial: handleAskMeridial,
2009
+ onPlayGuide: handlePlayGuide,
2010
+ onAbortGuide: handleAbortGuide
2011
+ }
2012
+ ) }),
2013
+ /* @__PURE__ */ jsx13(VoiceboxBadge, { triggerIcon, onClick: handleBadgeClick })
2014
+ ]
1906
2015
  }
1907
2016
  )
1908
- ] }) : /* @__PURE__ */ jsxs8(
1909
- "div",
1910
- {
1911
- className: cn("fixed z-50", BADGE_POSITION_CLASSES[badgePosition]),
1912
- children: [
1913
- /* @__PURE__ */ jsx13(AnimatePresence3, { children: view === "menu" && /* @__PURE__ */ jsx13(
1914
- VoiceboxMenu,
1915
- {
1916
- favoriteWorkflows,
1917
- position: badgePosition,
1918
- onPositionChange: handlePositionChange,
1919
- onHide: handleHide,
1920
- onAskMeridial: handleAskMeridial,
1921
- onPlayGuide: handlePlayGuide
1922
- }
1923
- ) }),
1924
- /* @__PURE__ */ jsx13(VoiceboxBadge, { triggerIcon, onClick: handleBadgeClick })
1925
- ]
1926
- }
1927
- ) });
2017
+ ] });
1928
2018
  }
1929
2019
 
1930
2020
  export {
1931
2021
  Voicebox
1932
2022
  };
1933
- //# sourceMappingURL=chunk-WCRZUGN4.js.map
2023
+ //# sourceMappingURL=chunk-BWBGNRKO.js.map