@intentai/react 2.0.0 → 2.0.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.
Files changed (3) hide show
  1. package/dist/index.js +214 -128
  2. package/dist/index.mjs +214 -128
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -190,9 +190,9 @@ var containerVariants = {
190
190
  transition: springPresets.smooth
191
191
  },
192
192
  expanded: {
193
- width: 400,
194
- height: 520,
195
- borderRadius: 24,
193
+ width: 360,
194
+ height: "auto",
195
+ borderRadius: 20,
196
196
  transition: {
197
197
  ...springPresets.smooth,
198
198
  staggerChildren: 0.05,
@@ -277,11 +277,11 @@ var AmbientOrb = ({ audioLevel, isRecording }) => {
277
277
  const particleCount = Math.floor(audioLevel * 4);
278
278
  const newParticles = Array.from({ length: particleCount }, () => ({
279
279
  id: Math.random().toString(36).slice(2, 11),
280
- x: 120,
281
- y: 120,
280
+ x: 70,
281
+ y: 70,
282
282
  angle: Math.random() * Math.PI * 2,
283
283
  speed: 1 + Math.random() * 3,
284
- size: 2 + Math.random() * 4,
284
+ size: 2 + Math.random() * 3,
285
285
  color: Math.random() > 0.5 ? "var(--widget-primary-light)" : "var(--widget-accent)"
286
286
  }));
287
287
  setParticles((prev) => [...prev, ...newParticles].slice(-40));
@@ -294,7 +294,7 @@ var AmbientOrb = ({ audioLevel, isRecording }) => {
294
294
  return () => clearTimeout(timeout);
295
295
  }, [particles]);
296
296
  const orbScale = 1 + audioLevel * 0.2;
297
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "fiq-ambient-orb", style: { position: "relative", width: 240, height: 240 }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: 240, height: 240, viewBox: "0 0 240 240", children: [
297
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "fiq-ambient-orb", style: { position: "relative", width: 140, height: 140, margin: "0 auto" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: 140, height: 140, viewBox: "0 0 140 140", children: [
298
298
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("defs", { children: [
299
299
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("radialGradient", { id: "orbGradient", cx: "30%", cy: "30%", children: [
300
300
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("stop", { offset: "0%", stopColor: "var(--widget-accent-light)" }),
@@ -309,14 +309,14 @@ var AmbientOrb = ({ audioLevel, isRecording }) => {
309
309
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
310
310
  import_framer_motion.motion.circle,
311
311
  {
312
- cx: 120,
313
- cy: 120,
314
- r: 80,
312
+ cx: 70,
313
+ cy: 70,
314
+ r: 50,
315
315
  fill: "none",
316
316
  stroke: "var(--widget-primary-glow)",
317
317
  strokeWidth: 2,
318
318
  animate: {
319
- r: isRecording ? [80, 90, 80] : 80,
319
+ r: isRecording ? [50, 58, 50] : 50,
320
320
  opacity: isRecording ? [0.3, 0.6, 0.3] : 0.3
321
321
  },
322
322
  transition: {
@@ -329,9 +329,9 @@ var AmbientOrb = ({ audioLevel, isRecording }) => {
329
329
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
330
330
  import_framer_motion.motion.circle,
331
331
  {
332
- cx: 120,
333
- cy: 120,
334
- r: 60,
332
+ cx: 70,
333
+ cy: 70,
334
+ r: 40,
335
335
  fill: "url(#orbGradient)",
336
336
  filter: "url(#orbGlow)",
337
337
  animate: { scale: reducedMotion ? 1 : orbScale },
@@ -339,7 +339,7 @@ var AmbientOrb = ({ audioLevel, isRecording }) => {
339
339
  style: { transformOrigin: "center" }
340
340
  }
341
341
  ),
342
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { transform: "translate(100, 95)", children: [
342
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { transform: "translate(58, 55)", children: [
343
343
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
344
344
  import_framer_motion.motion.path,
345
345
  {
@@ -371,14 +371,14 @@ var AmbientOrb = ({ audioLevel, isRecording }) => {
371
371
  particles.map((particle) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
372
372
  import_framer_motion.motion.circle,
373
373
  {
374
- cx: particle.x,
375
- cy: particle.y,
374
+ cx: 70,
375
+ cy: 70,
376
376
  r: particle.size,
377
377
  fill: particle.color,
378
378
  initial: { opacity: 0.8, scale: 1 },
379
379
  animate: {
380
- cx: particle.x + Math.cos(particle.angle) * 80,
381
- cy: particle.y + Math.sin(particle.angle) * 80,
380
+ cx: 70 + Math.cos(particle.angle) * 50,
381
+ cy: 70 + Math.sin(particle.angle) * 50,
382
382
  opacity: 0,
383
383
  scale: 0.5
384
384
  },
@@ -518,6 +518,20 @@ var TranscriptionDisplay = ({ text, isLive }) => {
518
518
  }
519
519
  );
520
520
  };
521
+ var CategoryIcon = ({ icon, selected }) => {
522
+ const color = selected ? "white" : "var(--widget-primary)";
523
+ const size = 20;
524
+ const icons = {
525
+ bug: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [
526
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M8 2l1.88 1.88M14.12 3.88L16 2M9 7.13v-1a3.003 3.003 0 116 0v1" }),
527
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 014-4h4a4 4 0 014 4v3c0 3.3-2.7 6-6 6" }),
528
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 20v-9M6.53 9C4.6 8.8 3 7.1 3 5M6 13H2M3 21c0-2.1 1.7-3.9 3.8-4M20.97 5c0 2.1-1.6 3.8-3.5 4M22 13h-4M17.2 17c2.1.1 3.8 1.9 3.8 4" })
529
+ ] }),
530
+ sparkles: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 3l1.912 5.813a2 2 0 001.275 1.275L21 12l-5.813 1.912a2 2 0 00-1.275 1.275L12 21l-1.912-5.813a2 2 0 00-1.275-1.275L3 12l5.813-1.912a2 2 0 001.275-1.275L12 3z" }) }),
531
+ message: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2v10z" }) })
532
+ };
533
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: icons[icon] || icons.message });
534
+ };
521
535
  var ListeningDots = () => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { display: "flex", gap: 4 }, children: [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
522
536
  import_framer_motion.motion.span,
523
537
  {
@@ -590,10 +604,10 @@ var CategorySelector = ({ categories, selected, onSelect }) => {
590
604
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
591
605
  import_framer_motion.motion.span,
592
606
  {
593
- style: { fontSize: 20 },
594
- animate: selected === category.id ? { scale: [1, 1.3, 1], rotate: [0, 10, -10, 0] } : {},
595
- transition: { duration: 0.4 },
596
- children: category.icon
607
+ style: { display: "flex", alignItems: "center", justifyContent: "center" },
608
+ animate: selected === category.id ? { scale: [1, 1.2, 1] } : {},
609
+ transition: { duration: 0.3 },
610
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CategoryIcon, { icon: category.icon, selected: selected === category.id })
597
611
  }
598
612
  ),
599
613
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -842,11 +856,9 @@ var MagneticButton = ({ children, onClick, variant = "primary", disabled, loadin
842
856
  );
843
857
  };
844
858
  var DEFAULT_CATEGORIES = [
845
- { id: "bug", label: "Bug", icon: "\u{1F41B}" },
846
- { id: "feature", label: "Feature", icon: "\u2728" },
847
- { id: "improvement", label: "Improve", icon: "\u{1F4A1}" },
848
- { id: "praise", label: "Praise", icon: "\u2764\uFE0F" },
849
- { id: "other", label: "Other", icon: "\u{1F4AC}" }
859
+ { id: "bug", label: "Bug", icon: "bug" },
860
+ { id: "feature", label: "Feature", icon: "sparkles" },
861
+ { id: "feedback", label: "Feedback", icon: "message" }
850
862
  ];
851
863
  var PremiumVoiceWidget = ({
852
864
  position = "bottom-right",
@@ -989,6 +1001,24 @@ var PremiumVoiceWidget = ({
989
1001
  return "idle";
990
1002
  }, [isExpanded, scrollState, state]);
991
1003
  const shouldShowAttentionPulse = timeOnPage === 60 && !isExpanded && frustrationLevel < 3;
1004
+ const [showPrompt, setShowPrompt] = (0, import_react.useState)(false);
1005
+ const promptMessages = [
1006
+ "Help us improve!",
1007
+ "Got feedback?",
1008
+ "Share your thoughts",
1009
+ "We'd love to hear from you"
1010
+ ];
1011
+ const [promptMessage, setPromptMessage] = (0, import_react.useState)(promptMessages[0]);
1012
+ (0, import_react.useEffect)(() => {
1013
+ if (isExpanded) return;
1014
+ const showTimes = [30, 90, 180];
1015
+ if (showTimes.includes(timeOnPage)) {
1016
+ setPromptMessage(promptMessages[Math.floor(Math.random() * promptMessages.length)]);
1017
+ setShowPrompt(true);
1018
+ const timer = setTimeout(() => setShowPrompt(false), 4e3);
1019
+ return () => clearTimeout(timer);
1020
+ }
1021
+ }, [timeOnPage, isExpanded]);
992
1022
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WidgetContext.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
993
1023
  "div",
994
1024
  {
@@ -1001,111 +1031,167 @@ var PremiumVoiceWidget = ({
1001
1031
  fontFamily: "system-ui, -apple-system, sans-serif"
1002
1032
  },
1003
1033
  children: [
1004
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_framer_motion.AnimatePresence, { mode: "wait", children: !isExpanded && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1005
- import_framer_motion.motion.button,
1006
- {
1007
- ref: triggerRef,
1008
- variants: triggerVariants,
1009
- initial: "idle",
1010
- animate: triggerState,
1011
- exit: "hidden",
1012
- whileHover: "hover",
1013
- whileTap: "tap",
1014
- onClick: handleOpen,
1015
- onMouseEnter: () => setState("hover"),
1016
- onMouseLeave: () => setState("idle"),
1017
- "aria-label": "Open feedback widget",
1018
- "aria-expanded": isExpanded,
1019
- style: {
1020
- width: 56,
1021
- height: 56,
1022
- borderRadius: "50%",
1023
- border: "none",
1024
- cursor: "pointer",
1025
- position: "relative",
1026
- background: "var(--widget-glass-bg)",
1027
- backdropFilter: "blur(20px) saturate(180%)",
1028
- WebkitBackdropFilter: "blur(20px) saturate(180%)",
1029
- boxShadow: `
1034
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_framer_motion.AnimatePresence, { mode: "wait", children: [
1035
+ !isExpanded && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1036
+ import_framer_motion.motion.button,
1037
+ {
1038
+ ref: triggerRef,
1039
+ variants: triggerVariants,
1040
+ initial: "idle",
1041
+ animate: triggerState,
1042
+ exit: "hidden",
1043
+ whileHover: "hover",
1044
+ whileTap: "tap",
1045
+ onClick: handleOpen,
1046
+ onMouseEnter: () => setState("hover"),
1047
+ onMouseLeave: () => setState("idle"),
1048
+ "aria-label": "Open feedback widget",
1049
+ "aria-expanded": isExpanded,
1050
+ style: {
1051
+ width: 56,
1052
+ height: 56,
1053
+ borderRadius: "50%",
1054
+ border: "none",
1055
+ cursor: "pointer",
1056
+ position: "relative",
1057
+ background: "var(--widget-glass-bg)",
1058
+ backdropFilter: "blur(20px) saturate(180%)",
1059
+ WebkitBackdropFilter: "blur(20px) saturate(180%)",
1060
+ boxShadow: `
1030
1061
  inset 0 0 0 1px var(--widget-glass-highlight),
1031
1062
  0 4px 24px -4px rgba(0, 0, 0, 0.5),
1032
1063
  0 0 40px -10px var(--widget-primary-glow)
1033
1064
  `
1034
- },
1035
- children: [
1036
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BreathingRing, { isActive: !reducedMotion && triggerState === "idle" }),
1037
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1038
- "div",
1039
- {
1040
- style: {
1041
- position: "absolute",
1042
- inset: 3,
1043
- borderRadius: "50%",
1044
- background: `linear-gradient(135deg, var(--widget-primary) 0%, var(--widget-accent) 100%)`,
1045
- opacity: 0.9
1065
+ },
1066
+ children: [
1067
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BreathingRing, { isActive: !reducedMotion && triggerState === "idle" }),
1068
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1069
+ "div",
1070
+ {
1071
+ style: {
1072
+ position: "absolute",
1073
+ inset: 3,
1074
+ borderRadius: "50%",
1075
+ background: `linear-gradient(135deg, var(--widget-primary) 0%, var(--widget-accent) 100%)`,
1076
+ opacity: 0.9
1077
+ }
1046
1078
  }
1047
- }
1048
- ),
1049
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1050
- "svg",
1051
- {
1052
- width: 24,
1053
- height: 24,
1054
- viewBox: "0 0 24 24",
1055
- fill: "none",
1056
- stroke: "white",
1057
- strokeWidth: 2,
1058
- strokeLinecap: "round",
1059
- style: { position: "relative", zIndex: 1 },
1060
- children: [
1061
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z" }),
1062
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M19 10v2a7 7 0 0 1-14 0v-2" }),
1063
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "12", y1: "19", x2: "12", y2: "23" }),
1064
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "8", y1: "23", x2: "16", y2: "23" })
1065
- ]
1066
- }
1067
- ),
1068
- shouldShowAttentionPulse && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1069
- import_framer_motion.motion.div,
1070
- {
1071
- initial: { scale: 1, opacity: 1 },
1072
- animate: { scale: 1.5, opacity: 0 },
1073
- transition: { duration: 1, repeat: 3 },
1074
- style: {
1075
- position: "absolute",
1076
- inset: 0,
1077
- borderRadius: "50%",
1078
- border: "2px solid var(--widget-primary)",
1079
- pointerEvents: "none"
1079
+ ),
1080
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1081
+ "svg",
1082
+ {
1083
+ width: 24,
1084
+ height: 24,
1085
+ viewBox: "0 0 24 24",
1086
+ fill: "none",
1087
+ stroke: "white",
1088
+ strokeWidth: 2,
1089
+ strokeLinecap: "round",
1090
+ style: {
1091
+ position: "absolute",
1092
+ top: "50%",
1093
+ left: "50%",
1094
+ transform: "translate(-50%, -50%)",
1095
+ zIndex: 1
1096
+ },
1097
+ children: [
1098
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z" }),
1099
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M19 10v2a7 7 0 0 1-14 0v-2" }),
1100
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "12", y1: "19", x2: "12", y2: "23" }),
1101
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "8", y1: "23", x2: "16", y2: "23" })
1102
+ ]
1080
1103
  }
1081
- }
1082
- ),
1083
- frustrationLevel >= 5 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1084
- import_framer_motion.motion.div,
1085
- {
1086
- initial: { scale: 0 },
1087
- animate: { scale: 1 },
1088
- style: {
1089
- position: "absolute",
1090
- top: -4,
1091
- right: -4,
1092
- width: 16,
1093
- height: 16,
1094
- borderRadius: "50%",
1095
- background: "var(--widget-frustrated)",
1096
- border: "2px solid var(--widget-glass-bg)",
1097
- display: "flex",
1098
- alignItems: "center",
1099
- justifyContent: "center",
1100
- fontSize: 10
1101
- },
1102
- children: "?"
1103
- }
1104
- )
1105
- ]
1106
- },
1107
- "trigger"
1108
- ) }),
1104
+ ),
1105
+ shouldShowAttentionPulse && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1106
+ import_framer_motion.motion.div,
1107
+ {
1108
+ initial: { scale: 1, opacity: 1 },
1109
+ animate: { scale: 1.5, opacity: 0 },
1110
+ transition: { duration: 1, repeat: 3 },
1111
+ style: {
1112
+ position: "absolute",
1113
+ inset: 0,
1114
+ borderRadius: "50%",
1115
+ border: "2px solid var(--widget-primary)",
1116
+ pointerEvents: "none"
1117
+ }
1118
+ }
1119
+ ),
1120
+ frustrationLevel >= 5 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1121
+ import_framer_motion.motion.div,
1122
+ {
1123
+ initial: { scale: 0 },
1124
+ animate: { scale: 1 },
1125
+ style: {
1126
+ position: "absolute",
1127
+ top: -4,
1128
+ right: -4,
1129
+ width: 16,
1130
+ height: 16,
1131
+ borderRadius: "50%",
1132
+ background: "var(--widget-frustrated)",
1133
+ border: "2px solid var(--widget-glass-bg)",
1134
+ display: "flex",
1135
+ alignItems: "center",
1136
+ justifyContent: "center",
1137
+ fontSize: 10
1138
+ },
1139
+ children: "?"
1140
+ }
1141
+ )
1142
+ ]
1143
+ },
1144
+ "trigger"
1145
+ ),
1146
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_framer_motion.AnimatePresence, { children: showPrompt && !isExpanded && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1147
+ import_framer_motion.motion.div,
1148
+ {
1149
+ initial: { opacity: 0, x: 10, scale: 0.9 },
1150
+ animate: { opacity: 1, x: 0, scale: 1 },
1151
+ exit: { opacity: 0, x: 10, scale: 0.9 },
1152
+ transition: springPresets.smooth,
1153
+ onClick: handleOpen,
1154
+ style: {
1155
+ position: "absolute",
1156
+ right: 70,
1157
+ top: "50%",
1158
+ transform: "translateY(-50%)",
1159
+ background: "var(--widget-glass-bg)",
1160
+ backdropFilter: "blur(12px)",
1161
+ WebkitBackdropFilter: "blur(12px)",
1162
+ border: "1px solid var(--widget-glass-border)",
1163
+ borderRadius: 12,
1164
+ padding: "10px 16px",
1165
+ boxShadow: "0 4px 20px rgba(0,0,0,0.3)",
1166
+ cursor: "pointer",
1167
+ whiteSpace: "nowrap"
1168
+ },
1169
+ children: [
1170
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: {
1171
+ fontSize: 13,
1172
+ fontWeight: 500,
1173
+ color: "var(--widget-text-primary)"
1174
+ }, children: promptMessage }),
1175
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1176
+ "div",
1177
+ {
1178
+ style: {
1179
+ position: "absolute",
1180
+ right: -6,
1181
+ top: "50%",
1182
+ transform: "translateY(-50%) rotate(45deg)",
1183
+ width: 12,
1184
+ height: 12,
1185
+ background: "var(--widget-glass-bg)",
1186
+ borderRight: "1px solid var(--widget-glass-border)",
1187
+ borderTop: "1px solid var(--widget-glass-border)"
1188
+ }
1189
+ }
1190
+ )
1191
+ ]
1192
+ }
1193
+ ) })
1194
+ ] }),
1109
1195
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_framer_motion.AnimatePresence, { mode: "wait", children: isExpanded && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1110
1196
  import_framer_motion.motion.div,
1111
1197
  {
@@ -1241,7 +1327,7 @@ var PremiumVoiceWidget = ({
1241
1327
  ))
1242
1328
  }
1243
1329
  ),
1244
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { flex: 1, overflow: "auto", padding: 24 }, children: [
1330
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { padding: "20px 24px" }, children: [
1245
1331
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { marginBottom: 24 }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1246
1332
  CategorySelector,
1247
1333
  {
package/dist/index.mjs CHANGED
@@ -172,9 +172,9 @@ var containerVariants = {
172
172
  transition: springPresets.smooth
173
173
  },
174
174
  expanded: {
175
- width: 400,
176
- height: 520,
177
- borderRadius: 24,
175
+ width: 360,
176
+ height: "auto",
177
+ borderRadius: 20,
178
178
  transition: {
179
179
  ...springPresets.smooth,
180
180
  staggerChildren: 0.05,
@@ -259,11 +259,11 @@ var AmbientOrb = ({ audioLevel, isRecording }) => {
259
259
  const particleCount = Math.floor(audioLevel * 4);
260
260
  const newParticles = Array.from({ length: particleCount }, () => ({
261
261
  id: Math.random().toString(36).slice(2, 11),
262
- x: 120,
263
- y: 120,
262
+ x: 70,
263
+ y: 70,
264
264
  angle: Math.random() * Math.PI * 2,
265
265
  speed: 1 + Math.random() * 3,
266
- size: 2 + Math.random() * 4,
266
+ size: 2 + Math.random() * 3,
267
267
  color: Math.random() > 0.5 ? "var(--widget-primary-light)" : "var(--widget-accent)"
268
268
  }));
269
269
  setParticles((prev) => [...prev, ...newParticles].slice(-40));
@@ -276,7 +276,7 @@ var AmbientOrb = ({ audioLevel, isRecording }) => {
276
276
  return () => clearTimeout(timeout);
277
277
  }, [particles]);
278
278
  const orbScale = 1 + audioLevel * 0.2;
279
- return /* @__PURE__ */ jsx("div", { className: "fiq-ambient-orb", style: { position: "relative", width: 240, height: 240 }, children: /* @__PURE__ */ jsxs("svg", { width: 240, height: 240, viewBox: "0 0 240 240", children: [
279
+ return /* @__PURE__ */ jsx("div", { className: "fiq-ambient-orb", style: { position: "relative", width: 140, height: 140, margin: "0 auto" }, children: /* @__PURE__ */ jsxs("svg", { width: 140, height: 140, viewBox: "0 0 140 140", children: [
280
280
  /* @__PURE__ */ jsxs("defs", { children: [
281
281
  /* @__PURE__ */ jsxs("radialGradient", { id: "orbGradient", cx: "30%", cy: "30%", children: [
282
282
  /* @__PURE__ */ jsx("stop", { offset: "0%", stopColor: "var(--widget-accent-light)" }),
@@ -291,14 +291,14 @@ var AmbientOrb = ({ audioLevel, isRecording }) => {
291
291
  /* @__PURE__ */ jsx(
292
292
  motion.circle,
293
293
  {
294
- cx: 120,
295
- cy: 120,
296
- r: 80,
294
+ cx: 70,
295
+ cy: 70,
296
+ r: 50,
297
297
  fill: "none",
298
298
  stroke: "var(--widget-primary-glow)",
299
299
  strokeWidth: 2,
300
300
  animate: {
301
- r: isRecording ? [80, 90, 80] : 80,
301
+ r: isRecording ? [50, 58, 50] : 50,
302
302
  opacity: isRecording ? [0.3, 0.6, 0.3] : 0.3
303
303
  },
304
304
  transition: {
@@ -311,9 +311,9 @@ var AmbientOrb = ({ audioLevel, isRecording }) => {
311
311
  /* @__PURE__ */ jsx(
312
312
  motion.circle,
313
313
  {
314
- cx: 120,
315
- cy: 120,
316
- r: 60,
314
+ cx: 70,
315
+ cy: 70,
316
+ r: 40,
317
317
  fill: "url(#orbGradient)",
318
318
  filter: "url(#orbGlow)",
319
319
  animate: { scale: reducedMotion ? 1 : orbScale },
@@ -321,7 +321,7 @@ var AmbientOrb = ({ audioLevel, isRecording }) => {
321
321
  style: { transformOrigin: "center" }
322
322
  }
323
323
  ),
324
- /* @__PURE__ */ jsxs("g", { transform: "translate(100, 95)", children: [
324
+ /* @__PURE__ */ jsxs("g", { transform: "translate(58, 55)", children: [
325
325
  /* @__PURE__ */ jsx(
326
326
  motion.path,
327
327
  {
@@ -353,14 +353,14 @@ var AmbientOrb = ({ audioLevel, isRecording }) => {
353
353
  particles.map((particle) => /* @__PURE__ */ jsx(
354
354
  motion.circle,
355
355
  {
356
- cx: particle.x,
357
- cy: particle.y,
356
+ cx: 70,
357
+ cy: 70,
358
358
  r: particle.size,
359
359
  fill: particle.color,
360
360
  initial: { opacity: 0.8, scale: 1 },
361
361
  animate: {
362
- cx: particle.x + Math.cos(particle.angle) * 80,
363
- cy: particle.y + Math.sin(particle.angle) * 80,
362
+ cx: 70 + Math.cos(particle.angle) * 50,
363
+ cy: 70 + Math.sin(particle.angle) * 50,
364
364
  opacity: 0,
365
365
  scale: 0.5
366
366
  },
@@ -500,6 +500,20 @@ var TranscriptionDisplay = ({ text, isLive }) => {
500
500
  }
501
501
  );
502
502
  };
503
+ var CategoryIcon = ({ icon, selected }) => {
504
+ const color = selected ? "white" : "var(--widget-primary)";
505
+ const size = 20;
506
+ const icons = {
507
+ bug: /* @__PURE__ */ jsxs("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [
508
+ /* @__PURE__ */ jsx("path", { d: "M8 2l1.88 1.88M14.12 3.88L16 2M9 7.13v-1a3.003 3.003 0 116 0v1" }),
509
+ /* @__PURE__ */ jsx("path", { d: "M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 014-4h4a4 4 0 014 4v3c0 3.3-2.7 6-6 6" }),
510
+ /* @__PURE__ */ jsx("path", { d: "M12 20v-9M6.53 9C4.6 8.8 3 7.1 3 5M6 13H2M3 21c0-2.1 1.7-3.9 3.8-4M20.97 5c0 2.1-1.6 3.8-3.5 4M22 13h-4M17.2 17c2.1.1 3.8 1.9 3.8 4" })
511
+ ] }),
512
+ sparkles: /* @__PURE__ */ jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M12 3l1.912 5.813a2 2 0 001.275 1.275L21 12l-5.813 1.912a2 2 0 00-1.275 1.275L12 21l-1.912-5.813a2 2 0 00-1.275-1.275L3 12l5.813-1.912a2 2 0 001.275-1.275L12 3z" }) }),
513
+ message: /* @__PURE__ */ jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2v10z" }) })
514
+ };
515
+ return /* @__PURE__ */ jsx(Fragment, { children: icons[icon] || icons.message });
516
+ };
503
517
  var ListeningDots = () => /* @__PURE__ */ jsx("div", { style: { display: "flex", gap: 4 }, children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx(
504
518
  motion.span,
505
519
  {
@@ -572,10 +586,10 @@ var CategorySelector = ({ categories, selected, onSelect }) => {
572
586
  /* @__PURE__ */ jsx(
573
587
  motion.span,
574
588
  {
575
- style: { fontSize: 20 },
576
- animate: selected === category.id ? { scale: [1, 1.3, 1], rotate: [0, 10, -10, 0] } : {},
577
- transition: { duration: 0.4 },
578
- children: category.icon
589
+ style: { display: "flex", alignItems: "center", justifyContent: "center" },
590
+ animate: selected === category.id ? { scale: [1, 1.2, 1] } : {},
591
+ transition: { duration: 0.3 },
592
+ children: /* @__PURE__ */ jsx(CategoryIcon, { icon: category.icon, selected: selected === category.id })
579
593
  }
580
594
  ),
581
595
  /* @__PURE__ */ jsx(
@@ -824,11 +838,9 @@ var MagneticButton = ({ children, onClick, variant = "primary", disabled, loadin
824
838
  );
825
839
  };
826
840
  var DEFAULT_CATEGORIES = [
827
- { id: "bug", label: "Bug", icon: "\u{1F41B}" },
828
- { id: "feature", label: "Feature", icon: "\u2728" },
829
- { id: "improvement", label: "Improve", icon: "\u{1F4A1}" },
830
- { id: "praise", label: "Praise", icon: "\u2764\uFE0F" },
831
- { id: "other", label: "Other", icon: "\u{1F4AC}" }
841
+ { id: "bug", label: "Bug", icon: "bug" },
842
+ { id: "feature", label: "Feature", icon: "sparkles" },
843
+ { id: "feedback", label: "Feedback", icon: "message" }
832
844
  ];
833
845
  var PremiumVoiceWidget = ({
834
846
  position = "bottom-right",
@@ -971,6 +983,24 @@ var PremiumVoiceWidget = ({
971
983
  return "idle";
972
984
  }, [isExpanded, scrollState, state]);
973
985
  const shouldShowAttentionPulse = timeOnPage === 60 && !isExpanded && frustrationLevel < 3;
986
+ const [showPrompt, setShowPrompt] = useState(false);
987
+ const promptMessages = [
988
+ "Help us improve!",
989
+ "Got feedback?",
990
+ "Share your thoughts",
991
+ "We'd love to hear from you"
992
+ ];
993
+ const [promptMessage, setPromptMessage] = useState(promptMessages[0]);
994
+ useEffect(() => {
995
+ if (isExpanded) return;
996
+ const showTimes = [30, 90, 180];
997
+ if (showTimes.includes(timeOnPage)) {
998
+ setPromptMessage(promptMessages[Math.floor(Math.random() * promptMessages.length)]);
999
+ setShowPrompt(true);
1000
+ const timer = setTimeout(() => setShowPrompt(false), 4e3);
1001
+ return () => clearTimeout(timer);
1002
+ }
1003
+ }, [timeOnPage, isExpanded]);
974
1004
  return /* @__PURE__ */ jsx(WidgetContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs(
975
1005
  "div",
976
1006
  {
@@ -983,111 +1013,167 @@ var PremiumVoiceWidget = ({
983
1013
  fontFamily: "system-ui, -apple-system, sans-serif"
984
1014
  },
985
1015
  children: [
986
- /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: !isExpanded && /* @__PURE__ */ jsxs(
987
- motion.button,
988
- {
989
- ref: triggerRef,
990
- variants: triggerVariants,
991
- initial: "idle",
992
- animate: triggerState,
993
- exit: "hidden",
994
- whileHover: "hover",
995
- whileTap: "tap",
996
- onClick: handleOpen,
997
- onMouseEnter: () => setState("hover"),
998
- onMouseLeave: () => setState("idle"),
999
- "aria-label": "Open feedback widget",
1000
- "aria-expanded": isExpanded,
1001
- style: {
1002
- width: 56,
1003
- height: 56,
1004
- borderRadius: "50%",
1005
- border: "none",
1006
- cursor: "pointer",
1007
- position: "relative",
1008
- background: "var(--widget-glass-bg)",
1009
- backdropFilter: "blur(20px) saturate(180%)",
1010
- WebkitBackdropFilter: "blur(20px) saturate(180%)",
1011
- boxShadow: `
1016
+ /* @__PURE__ */ jsxs(AnimatePresence, { mode: "wait", children: [
1017
+ !isExpanded && /* @__PURE__ */ jsxs(
1018
+ motion.button,
1019
+ {
1020
+ ref: triggerRef,
1021
+ variants: triggerVariants,
1022
+ initial: "idle",
1023
+ animate: triggerState,
1024
+ exit: "hidden",
1025
+ whileHover: "hover",
1026
+ whileTap: "tap",
1027
+ onClick: handleOpen,
1028
+ onMouseEnter: () => setState("hover"),
1029
+ onMouseLeave: () => setState("idle"),
1030
+ "aria-label": "Open feedback widget",
1031
+ "aria-expanded": isExpanded,
1032
+ style: {
1033
+ width: 56,
1034
+ height: 56,
1035
+ borderRadius: "50%",
1036
+ border: "none",
1037
+ cursor: "pointer",
1038
+ position: "relative",
1039
+ background: "var(--widget-glass-bg)",
1040
+ backdropFilter: "blur(20px) saturate(180%)",
1041
+ WebkitBackdropFilter: "blur(20px) saturate(180%)",
1042
+ boxShadow: `
1012
1043
  inset 0 0 0 1px var(--widget-glass-highlight),
1013
1044
  0 4px 24px -4px rgba(0, 0, 0, 0.5),
1014
1045
  0 0 40px -10px var(--widget-primary-glow)
1015
1046
  `
1016
- },
1017
- children: [
1018
- /* @__PURE__ */ jsx(BreathingRing, { isActive: !reducedMotion && triggerState === "idle" }),
1019
- /* @__PURE__ */ jsx(
1020
- "div",
1021
- {
1022
- style: {
1023
- position: "absolute",
1024
- inset: 3,
1025
- borderRadius: "50%",
1026
- background: `linear-gradient(135deg, var(--widget-primary) 0%, var(--widget-accent) 100%)`,
1027
- opacity: 0.9
1047
+ },
1048
+ children: [
1049
+ /* @__PURE__ */ jsx(BreathingRing, { isActive: !reducedMotion && triggerState === "idle" }),
1050
+ /* @__PURE__ */ jsx(
1051
+ "div",
1052
+ {
1053
+ style: {
1054
+ position: "absolute",
1055
+ inset: 3,
1056
+ borderRadius: "50%",
1057
+ background: `linear-gradient(135deg, var(--widget-primary) 0%, var(--widget-accent) 100%)`,
1058
+ opacity: 0.9
1059
+ }
1028
1060
  }
1029
- }
1030
- ),
1031
- /* @__PURE__ */ jsxs(
1032
- "svg",
1033
- {
1034
- width: 24,
1035
- height: 24,
1036
- viewBox: "0 0 24 24",
1037
- fill: "none",
1038
- stroke: "white",
1039
- strokeWidth: 2,
1040
- strokeLinecap: "round",
1041
- style: { position: "relative", zIndex: 1 },
1042
- children: [
1043
- /* @__PURE__ */ jsx("path", { d: "M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z" }),
1044
- /* @__PURE__ */ jsx("path", { d: "M19 10v2a7 7 0 0 1-14 0v-2" }),
1045
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "19", x2: "12", y2: "23" }),
1046
- /* @__PURE__ */ jsx("line", { x1: "8", y1: "23", x2: "16", y2: "23" })
1047
- ]
1048
- }
1049
- ),
1050
- shouldShowAttentionPulse && /* @__PURE__ */ jsx(
1051
- motion.div,
1052
- {
1053
- initial: { scale: 1, opacity: 1 },
1054
- animate: { scale: 1.5, opacity: 0 },
1055
- transition: { duration: 1, repeat: 3 },
1056
- style: {
1057
- position: "absolute",
1058
- inset: 0,
1059
- borderRadius: "50%",
1060
- border: "2px solid var(--widget-primary)",
1061
- pointerEvents: "none"
1061
+ ),
1062
+ /* @__PURE__ */ jsxs(
1063
+ "svg",
1064
+ {
1065
+ width: 24,
1066
+ height: 24,
1067
+ viewBox: "0 0 24 24",
1068
+ fill: "none",
1069
+ stroke: "white",
1070
+ strokeWidth: 2,
1071
+ strokeLinecap: "round",
1072
+ style: {
1073
+ position: "absolute",
1074
+ top: "50%",
1075
+ left: "50%",
1076
+ transform: "translate(-50%, -50%)",
1077
+ zIndex: 1
1078
+ },
1079
+ children: [
1080
+ /* @__PURE__ */ jsx("path", { d: "M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z" }),
1081
+ /* @__PURE__ */ jsx("path", { d: "M19 10v2a7 7 0 0 1-14 0v-2" }),
1082
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "19", x2: "12", y2: "23" }),
1083
+ /* @__PURE__ */ jsx("line", { x1: "8", y1: "23", x2: "16", y2: "23" })
1084
+ ]
1062
1085
  }
1063
- }
1064
- ),
1065
- frustrationLevel >= 5 && /* @__PURE__ */ jsx(
1066
- motion.div,
1067
- {
1068
- initial: { scale: 0 },
1069
- animate: { scale: 1 },
1070
- style: {
1071
- position: "absolute",
1072
- top: -4,
1073
- right: -4,
1074
- width: 16,
1075
- height: 16,
1076
- borderRadius: "50%",
1077
- background: "var(--widget-frustrated)",
1078
- border: "2px solid var(--widget-glass-bg)",
1079
- display: "flex",
1080
- alignItems: "center",
1081
- justifyContent: "center",
1082
- fontSize: 10
1083
- },
1084
- children: "?"
1085
- }
1086
- )
1087
- ]
1088
- },
1089
- "trigger"
1090
- ) }),
1086
+ ),
1087
+ shouldShowAttentionPulse && /* @__PURE__ */ jsx(
1088
+ motion.div,
1089
+ {
1090
+ initial: { scale: 1, opacity: 1 },
1091
+ animate: { scale: 1.5, opacity: 0 },
1092
+ transition: { duration: 1, repeat: 3 },
1093
+ style: {
1094
+ position: "absolute",
1095
+ inset: 0,
1096
+ borderRadius: "50%",
1097
+ border: "2px solid var(--widget-primary)",
1098
+ pointerEvents: "none"
1099
+ }
1100
+ }
1101
+ ),
1102
+ frustrationLevel >= 5 && /* @__PURE__ */ jsx(
1103
+ motion.div,
1104
+ {
1105
+ initial: { scale: 0 },
1106
+ animate: { scale: 1 },
1107
+ style: {
1108
+ position: "absolute",
1109
+ top: -4,
1110
+ right: -4,
1111
+ width: 16,
1112
+ height: 16,
1113
+ borderRadius: "50%",
1114
+ background: "var(--widget-frustrated)",
1115
+ border: "2px solid var(--widget-glass-bg)",
1116
+ display: "flex",
1117
+ alignItems: "center",
1118
+ justifyContent: "center",
1119
+ fontSize: 10
1120
+ },
1121
+ children: "?"
1122
+ }
1123
+ )
1124
+ ]
1125
+ },
1126
+ "trigger"
1127
+ ),
1128
+ /* @__PURE__ */ jsx(AnimatePresence, { children: showPrompt && !isExpanded && /* @__PURE__ */ jsxs(
1129
+ motion.div,
1130
+ {
1131
+ initial: { opacity: 0, x: 10, scale: 0.9 },
1132
+ animate: { opacity: 1, x: 0, scale: 1 },
1133
+ exit: { opacity: 0, x: 10, scale: 0.9 },
1134
+ transition: springPresets.smooth,
1135
+ onClick: handleOpen,
1136
+ style: {
1137
+ position: "absolute",
1138
+ right: 70,
1139
+ top: "50%",
1140
+ transform: "translateY(-50%)",
1141
+ background: "var(--widget-glass-bg)",
1142
+ backdropFilter: "blur(12px)",
1143
+ WebkitBackdropFilter: "blur(12px)",
1144
+ border: "1px solid var(--widget-glass-border)",
1145
+ borderRadius: 12,
1146
+ padding: "10px 16px",
1147
+ boxShadow: "0 4px 20px rgba(0,0,0,0.3)",
1148
+ cursor: "pointer",
1149
+ whiteSpace: "nowrap"
1150
+ },
1151
+ children: [
1152
+ /* @__PURE__ */ jsx("span", { style: {
1153
+ fontSize: 13,
1154
+ fontWeight: 500,
1155
+ color: "var(--widget-text-primary)"
1156
+ }, children: promptMessage }),
1157
+ /* @__PURE__ */ jsx(
1158
+ "div",
1159
+ {
1160
+ style: {
1161
+ position: "absolute",
1162
+ right: -6,
1163
+ top: "50%",
1164
+ transform: "translateY(-50%) rotate(45deg)",
1165
+ width: 12,
1166
+ height: 12,
1167
+ background: "var(--widget-glass-bg)",
1168
+ borderRight: "1px solid var(--widget-glass-border)",
1169
+ borderTop: "1px solid var(--widget-glass-border)"
1170
+ }
1171
+ }
1172
+ )
1173
+ ]
1174
+ }
1175
+ ) })
1176
+ ] }),
1091
1177
  /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: isExpanded && /* @__PURE__ */ jsx(
1092
1178
  motion.div,
1093
1179
  {
@@ -1223,7 +1309,7 @@ var PremiumVoiceWidget = ({
1223
1309
  ))
1224
1310
  }
1225
1311
  ),
1226
- /* @__PURE__ */ jsxs("div", { style: { flex: 1, overflow: "auto", padding: 24 }, children: [
1312
+ /* @__PURE__ */ jsxs("div", { style: { padding: "20px 24px" }, children: [
1227
1313
  /* @__PURE__ */ jsx("div", { style: { marginBottom: 24 }, children: /* @__PURE__ */ jsx(
1228
1314
  CategorySelector,
1229
1315
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentai/react",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "React component for Intent AI feedback widget - easily collect user feedback with AI-powered analysis",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org",