@intentai/react 2.1.1 → 2.2.0
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.d.mts +150 -6
- package/dist/index.d.ts +150 -6
- package/dist/index.js +404 -16
- package/dist/index.mjs +398 -15
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
// src/index.tsx
|
|
4
|
-
import { useEffect as
|
|
4
|
+
import { useEffect as useEffect3, useRef as useRef4, useCallback as useCallback4 } from "react";
|
|
5
5
|
|
|
6
6
|
// src/components/PremiumVoiceWidget.tsx
|
|
7
7
|
import {
|
|
@@ -98,15 +98,33 @@ var useAudioLevel = (isRecording) => {
|
|
|
98
98
|
const [audioLevel, setAudioLevel] = useState(0);
|
|
99
99
|
const analyserRef = useRef(null);
|
|
100
100
|
const animationRef = useRef();
|
|
101
|
+
const streamRef = useRef(null);
|
|
102
|
+
const audioContextRef = useRef(null);
|
|
101
103
|
useEffect(() => {
|
|
102
104
|
if (!isRecording) {
|
|
103
105
|
setAudioLevel(0);
|
|
106
|
+
if (animationRef.current) {
|
|
107
|
+
cancelAnimationFrame(animationRef.current);
|
|
108
|
+
animationRef.current = void 0;
|
|
109
|
+
}
|
|
110
|
+
if (streamRef.current) {
|
|
111
|
+
streamRef.current.getTracks().forEach((track) => track.stop());
|
|
112
|
+
streamRef.current = null;
|
|
113
|
+
}
|
|
114
|
+
if (audioContextRef.current && audioContextRef.current.state !== "closed") {
|
|
115
|
+
audioContextRef.current.close().catch(() => {
|
|
116
|
+
});
|
|
117
|
+
audioContextRef.current = null;
|
|
118
|
+
}
|
|
119
|
+
analyserRef.current = null;
|
|
104
120
|
return;
|
|
105
121
|
}
|
|
106
122
|
const initAudio = async () => {
|
|
107
123
|
try {
|
|
108
124
|
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
125
|
+
streamRef.current = stream;
|
|
109
126
|
const audioContext = new AudioContext();
|
|
127
|
+
audioContextRef.current = audioContext;
|
|
110
128
|
const source = audioContext.createMediaStreamSource(stream);
|
|
111
129
|
const analyser = audioContext.createAnalyser();
|
|
112
130
|
analyser.fftSize = 256;
|
|
@@ -130,6 +148,13 @@ var useAudioLevel = (isRecording) => {
|
|
|
130
148
|
if (animationRef.current) {
|
|
131
149
|
cancelAnimationFrame(animationRef.current);
|
|
132
150
|
}
|
|
151
|
+
if (streamRef.current) {
|
|
152
|
+
streamRef.current.getTracks().forEach((track) => track.stop());
|
|
153
|
+
}
|
|
154
|
+
if (audioContextRef.current && audioContextRef.current.state !== "closed") {
|
|
155
|
+
audioContextRef.current.close().catch(() => {
|
|
156
|
+
});
|
|
157
|
+
}
|
|
133
158
|
};
|
|
134
159
|
}, [isRecording]);
|
|
135
160
|
return audioLevel;
|
|
@@ -349,12 +374,12 @@ var AmbientOrb = ({ audioLevel, isRecording }) => {
|
|
|
349
374
|
]
|
|
350
375
|
}
|
|
351
376
|
) }),
|
|
352
|
-
particles.map((particle) => /* @__PURE__ */ jsx(
|
|
377
|
+
particles.filter((p) => p.size != null).map((particle) => /* @__PURE__ */ jsx(
|
|
353
378
|
motion.circle,
|
|
354
379
|
{
|
|
355
380
|
cx: 70,
|
|
356
381
|
cy: 70,
|
|
357
|
-
r: particle.size,
|
|
382
|
+
r: particle.size || 3,
|
|
358
383
|
fill: particle.color,
|
|
359
384
|
initial: { opacity: 0.8, scale: 1 },
|
|
360
385
|
animate: {
|
|
@@ -1601,6 +1626,359 @@ function adjustColor(color, amount) {
|
|
|
1601
1626
|
return `#${(r << 16 | g << 8 | b).toString(16).padStart(6, "0")}`;
|
|
1602
1627
|
}
|
|
1603
1628
|
|
|
1629
|
+
// src/components/IntentAIProvider.tsx
|
|
1630
|
+
import { createContext as createContext2, useContext as useContext2, useCallback as useCallback2, useMemo as useMemo2, useRef as useRef2, useEffect as useEffect2 } from "react";
|
|
1631
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1632
|
+
var IntentAIContext = createContext2(null);
|
|
1633
|
+
function useIntentAI() {
|
|
1634
|
+
const context = useContext2(IntentAIContext);
|
|
1635
|
+
if (!context) {
|
|
1636
|
+
throw new Error("useIntentAI must be used within an IntentAIProvider");
|
|
1637
|
+
}
|
|
1638
|
+
return context;
|
|
1639
|
+
}
|
|
1640
|
+
function generateSessionId() {
|
|
1641
|
+
return `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
1642
|
+
}
|
|
1643
|
+
function getDeviceInfo() {
|
|
1644
|
+
const ua = navigator.userAgent;
|
|
1645
|
+
let browser = "Unknown";
|
|
1646
|
+
let browserVersion = "Unknown";
|
|
1647
|
+
if (ua.includes("Firefox/")) {
|
|
1648
|
+
browser = "Firefox";
|
|
1649
|
+
const match = ua.match(/Firefox\/(\d+(\.\d+)?)/);
|
|
1650
|
+
if (match) browserVersion = match[1];
|
|
1651
|
+
} else if (ua.includes("Edg/")) {
|
|
1652
|
+
browser = "Edge";
|
|
1653
|
+
const match = ua.match(/Edg\/(\d+(\.\d+)?)/);
|
|
1654
|
+
if (match) browserVersion = match[1];
|
|
1655
|
+
} else if (ua.includes("Chrome/")) {
|
|
1656
|
+
browser = "Chrome";
|
|
1657
|
+
const match = ua.match(/Chrome\/(\d+(\.\d+)?)/);
|
|
1658
|
+
if (match) browserVersion = match[1];
|
|
1659
|
+
} else if (ua.includes("Safari/") && !ua.includes("Chrome")) {
|
|
1660
|
+
browser = "Safari";
|
|
1661
|
+
const match = ua.match(/Version\/(\d+(\.\d+)?)/);
|
|
1662
|
+
if (match) browserVersion = match[1];
|
|
1663
|
+
}
|
|
1664
|
+
let os = "Unknown";
|
|
1665
|
+
if (ua.includes("Windows NT 10")) os = "Windows 10";
|
|
1666
|
+
else if (ua.includes("Windows")) os = "Windows";
|
|
1667
|
+
else if (ua.includes("Mac OS X")) os = "macOS";
|
|
1668
|
+
else if (ua.includes("Android")) os = "Android";
|
|
1669
|
+
else if (ua.includes("iPhone") || ua.includes("iPad")) os = "iOS";
|
|
1670
|
+
else if (ua.includes("Linux")) os = "Linux";
|
|
1671
|
+
let device = "Desktop";
|
|
1672
|
+
if (/iPhone|iPad|iPod/.test(ua)) device = "iOS Device";
|
|
1673
|
+
else if (/Android.*Mobile/.test(ua)) device = "Android Phone";
|
|
1674
|
+
else if (/Android/.test(ua)) device = "Android Tablet";
|
|
1675
|
+
return { browser, browserVersion, os, device };
|
|
1676
|
+
}
|
|
1677
|
+
var DEFAULT_API_URL = "https://api-production-5b88.up.railway.app";
|
|
1678
|
+
function IntentAIProvider({
|
|
1679
|
+
apiKey,
|
|
1680
|
+
apiUrl = DEFAULT_API_URL,
|
|
1681
|
+
user: initialUser,
|
|
1682
|
+
metadata: initialMetadata,
|
|
1683
|
+
widgetConfig,
|
|
1684
|
+
children,
|
|
1685
|
+
disableWidget = false,
|
|
1686
|
+
onFeedbackSubmitted,
|
|
1687
|
+
onError
|
|
1688
|
+
}) {
|
|
1689
|
+
const userRef = useRef2(initialUser);
|
|
1690
|
+
const metadataRef = useRef2(initialMetadata || {});
|
|
1691
|
+
const sessionIdRef = useRef2(generateSessionId());
|
|
1692
|
+
useEffect2(() => {
|
|
1693
|
+
if (initialUser) {
|
|
1694
|
+
userRef.current = initialUser;
|
|
1695
|
+
}
|
|
1696
|
+
}, [initialUser]);
|
|
1697
|
+
useEffect2(() => {
|
|
1698
|
+
if (initialMetadata) {
|
|
1699
|
+
metadataRef.current = { ...metadataRef.current, ...initialMetadata };
|
|
1700
|
+
}
|
|
1701
|
+
}, [initialMetadata]);
|
|
1702
|
+
const identify = useCallback2((user) => {
|
|
1703
|
+
userRef.current = { ...userRef.current, ...user };
|
|
1704
|
+
}, []);
|
|
1705
|
+
const setMetadata = useCallback2((metadata) => {
|
|
1706
|
+
metadataRef.current = { ...metadataRef.current, ...metadata };
|
|
1707
|
+
}, []);
|
|
1708
|
+
const clearUser = useCallback2(() => {
|
|
1709
|
+
userRef.current = void 0;
|
|
1710
|
+
}, []);
|
|
1711
|
+
const handleSubmit = useCallback2(async (feedback) => {
|
|
1712
|
+
const deviceInfo = getDeviceInfo();
|
|
1713
|
+
const user = userRef.current;
|
|
1714
|
+
const customMetadata = metadataRef.current;
|
|
1715
|
+
const categoryMap = {
|
|
1716
|
+
bug: "BUG",
|
|
1717
|
+
feature: "FEATURE",
|
|
1718
|
+
improvement: "IMPROVEMENT",
|
|
1719
|
+
praise: "PRAISE",
|
|
1720
|
+
other: "OTHER"
|
|
1721
|
+
};
|
|
1722
|
+
const payload = {
|
|
1723
|
+
sessionId: sessionIdRef.current,
|
|
1724
|
+
type: feedback.type === "voice" ? "VOICE" : "TEXT",
|
|
1725
|
+
category: categoryMap[feedback.category.toLowerCase()] || feedback.category.toUpperCase(),
|
|
1726
|
+
rawText: feedback.type === "text" ? feedback.content : void 0,
|
|
1727
|
+
transcription: feedback.type === "voice" ? feedback.transcription || feedback.content : void 0,
|
|
1728
|
+
pageUrl: typeof window !== "undefined" ? window.location.href : "",
|
|
1729
|
+
pageTitle: typeof document !== "undefined" ? document.title : "",
|
|
1730
|
+
userId: user?.id,
|
|
1731
|
+
userEmail: user?.email,
|
|
1732
|
+
userName: user?.name,
|
|
1733
|
+
customData: {
|
|
1734
|
+
...customMetadata,
|
|
1735
|
+
...feedback.metadata
|
|
1736
|
+
},
|
|
1737
|
+
browser: deviceInfo.browser,
|
|
1738
|
+
browserVersion: deviceInfo.browserVersion,
|
|
1739
|
+
os: deviceInfo.os,
|
|
1740
|
+
device: deviceInfo.device,
|
|
1741
|
+
screenWidth: typeof window !== "undefined" ? window.screen.width : void 0,
|
|
1742
|
+
screenHeight: typeof window !== "undefined" ? window.screen.height : void 0
|
|
1743
|
+
};
|
|
1744
|
+
try {
|
|
1745
|
+
const response = await fetch(`${apiUrl}/feedback`, {
|
|
1746
|
+
method: "POST",
|
|
1747
|
+
headers: {
|
|
1748
|
+
"Content-Type": "application/json",
|
|
1749
|
+
"X-API-Key": apiKey
|
|
1750
|
+
},
|
|
1751
|
+
body: JSON.stringify(payload)
|
|
1752
|
+
});
|
|
1753
|
+
if (!response.ok) {
|
|
1754
|
+
const errorData = await response.json().catch(() => ({}));
|
|
1755
|
+
throw new Error(errorData.error || `Failed to submit feedback: ${response.status}`);
|
|
1756
|
+
}
|
|
1757
|
+
onFeedbackSubmitted?.();
|
|
1758
|
+
} catch (error) {
|
|
1759
|
+
const err = error instanceof Error ? error : new Error("Failed to submit feedback");
|
|
1760
|
+
onError?.(err);
|
|
1761
|
+
throw err;
|
|
1762
|
+
}
|
|
1763
|
+
}, [apiKey, apiUrl, onFeedbackSubmitted, onError]);
|
|
1764
|
+
const contextValue = useMemo2(() => ({
|
|
1765
|
+
identify,
|
|
1766
|
+
setMetadata,
|
|
1767
|
+
clearUser,
|
|
1768
|
+
isConfigured: Boolean(apiKey)
|
|
1769
|
+
}), [identify, setMetadata, clearUser, apiKey]);
|
|
1770
|
+
return /* @__PURE__ */ jsxs2(IntentAIContext.Provider, { value: contextValue, children: [
|
|
1771
|
+
children,
|
|
1772
|
+
!disableWidget && apiKey && /* @__PURE__ */ jsx2(
|
|
1773
|
+
PremiumVoiceWidget,
|
|
1774
|
+
{
|
|
1775
|
+
...widgetConfig,
|
|
1776
|
+
onSubmit: handleSubmit
|
|
1777
|
+
}
|
|
1778
|
+
)
|
|
1779
|
+
] });
|
|
1780
|
+
}
|
|
1781
|
+
function useIdentify() {
|
|
1782
|
+
const { identify } = useIntentAI();
|
|
1783
|
+
return identify;
|
|
1784
|
+
}
|
|
1785
|
+
function useSetMetadata() {
|
|
1786
|
+
const { setMetadata } = useIntentAI();
|
|
1787
|
+
return setMetadata;
|
|
1788
|
+
}
|
|
1789
|
+
|
|
1790
|
+
// src/components/FeedbackButton.tsx
|
|
1791
|
+
import { useCallback as useCallback3, useState as useState2, useRef as useRef3 } from "react";
|
|
1792
|
+
import { motion as motion2 } from "framer-motion";
|
|
1793
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1794
|
+
var FeedbackIcon = ({ size }) => /* @__PURE__ */ jsxs3(
|
|
1795
|
+
"svg",
|
|
1796
|
+
{
|
|
1797
|
+
width: size,
|
|
1798
|
+
height: size,
|
|
1799
|
+
viewBox: "0 0 24 24",
|
|
1800
|
+
fill: "none",
|
|
1801
|
+
stroke: "currentColor",
|
|
1802
|
+
strokeWidth: "2",
|
|
1803
|
+
strokeLinecap: "round",
|
|
1804
|
+
strokeLinejoin: "round",
|
|
1805
|
+
children: [
|
|
1806
|
+
/* @__PURE__ */ jsx3("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }),
|
|
1807
|
+
/* @__PURE__ */ jsx3("circle", { cx: "9", cy: "10", r: "1", fill: "currentColor" }),
|
|
1808
|
+
/* @__PURE__ */ jsx3("circle", { cx: "15", cy: "10", r: "1", fill: "currentColor" })
|
|
1809
|
+
]
|
|
1810
|
+
}
|
|
1811
|
+
);
|
|
1812
|
+
function FeedbackButton({
|
|
1813
|
+
variant = "primary",
|
|
1814
|
+
size = "md",
|
|
1815
|
+
showIcon = true,
|
|
1816
|
+
icon,
|
|
1817
|
+
label = "Feedback",
|
|
1818
|
+
className,
|
|
1819
|
+
style,
|
|
1820
|
+
primaryColor = "#10b981",
|
|
1821
|
+
onClick,
|
|
1822
|
+
disabled = false
|
|
1823
|
+
}) {
|
|
1824
|
+
const [isHovered, setIsHovered] = useState2(false);
|
|
1825
|
+
const [isPressed, setIsPressed] = useState2(false);
|
|
1826
|
+
const buttonRef = useRef3(null);
|
|
1827
|
+
const sizes = {
|
|
1828
|
+
sm: {
|
|
1829
|
+
padding: "8px 14px",
|
|
1830
|
+
fontSize: 13,
|
|
1831
|
+
iconSize: 14,
|
|
1832
|
+
gap: 6,
|
|
1833
|
+
borderRadius: 8
|
|
1834
|
+
},
|
|
1835
|
+
md: {
|
|
1836
|
+
padding: "10px 18px",
|
|
1837
|
+
fontSize: 14,
|
|
1838
|
+
iconSize: 16,
|
|
1839
|
+
gap: 8,
|
|
1840
|
+
borderRadius: 10
|
|
1841
|
+
},
|
|
1842
|
+
lg: {
|
|
1843
|
+
padding: "14px 24px",
|
|
1844
|
+
fontSize: 15,
|
|
1845
|
+
iconSize: 18,
|
|
1846
|
+
gap: 10,
|
|
1847
|
+
borderRadius: 12
|
|
1848
|
+
}
|
|
1849
|
+
};
|
|
1850
|
+
const sizeConfig = sizes[size];
|
|
1851
|
+
const variants = {
|
|
1852
|
+
primary: {
|
|
1853
|
+
background: `linear-gradient(145deg, ${primaryColor} 0%, ${adjustColor2(primaryColor, -20)} 100%)`,
|
|
1854
|
+
color: "white",
|
|
1855
|
+
border: "none",
|
|
1856
|
+
boxShadow: `0 4px 16px -4px ${primaryColor}66, 0 2px 4px rgba(0, 0, 0, 0.1)`
|
|
1857
|
+
},
|
|
1858
|
+
secondary: {
|
|
1859
|
+
background: "white",
|
|
1860
|
+
color: "#374151",
|
|
1861
|
+
border: "1px solid #e5e7eb",
|
|
1862
|
+
boxShadow: "0 2px 4px rgba(0, 0, 0, 0.05)"
|
|
1863
|
+
},
|
|
1864
|
+
ghost: {
|
|
1865
|
+
background: "transparent",
|
|
1866
|
+
color: "#6b7280",
|
|
1867
|
+
border: "1px solid transparent",
|
|
1868
|
+
boxShadow: "none"
|
|
1869
|
+
},
|
|
1870
|
+
minimal: {
|
|
1871
|
+
background: "transparent",
|
|
1872
|
+
color: primaryColor,
|
|
1873
|
+
border: "none",
|
|
1874
|
+
boxShadow: "none"
|
|
1875
|
+
}
|
|
1876
|
+
};
|
|
1877
|
+
const variantStyle = variants[variant];
|
|
1878
|
+
const handleClick = useCallback3(() => {
|
|
1879
|
+
if (disabled) return;
|
|
1880
|
+
if (onClick) {
|
|
1881
|
+
onClick();
|
|
1882
|
+
return;
|
|
1883
|
+
}
|
|
1884
|
+
const widget = document.querySelector(".fiq-premium-widget");
|
|
1885
|
+
if (widget) {
|
|
1886
|
+
const trigger = widget.querySelector('button[aria-label="Open feedback widget"]');
|
|
1887
|
+
if (trigger) {
|
|
1888
|
+
trigger.click();
|
|
1889
|
+
return;
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
const scriptWidget = document.getElementById("feedbackiq-widget");
|
|
1893
|
+
if (scriptWidget?.shadowRoot) {
|
|
1894
|
+
const trigger = scriptWidget.shadowRoot.querySelector(".fiq-trigger");
|
|
1895
|
+
if (trigger) {
|
|
1896
|
+
trigger.click();
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
}, [onClick, disabled]);
|
|
1900
|
+
return /* @__PURE__ */ jsxs3(
|
|
1901
|
+
motion2.button,
|
|
1902
|
+
{
|
|
1903
|
+
ref: buttonRef,
|
|
1904
|
+
onClick: handleClick,
|
|
1905
|
+
onMouseEnter: () => setIsHovered(true),
|
|
1906
|
+
onMouseLeave: () => {
|
|
1907
|
+
setIsHovered(false);
|
|
1908
|
+
setIsPressed(false);
|
|
1909
|
+
},
|
|
1910
|
+
onMouseDown: () => setIsPressed(true),
|
|
1911
|
+
onMouseUp: () => setIsPressed(false),
|
|
1912
|
+
disabled,
|
|
1913
|
+
animate: {
|
|
1914
|
+
scale: isPressed ? 0.97 : isHovered ? 1.02 : 1,
|
|
1915
|
+
y: isHovered ? -1 : 0
|
|
1916
|
+
},
|
|
1917
|
+
transition: {
|
|
1918
|
+
type: "spring",
|
|
1919
|
+
stiffness: 400,
|
|
1920
|
+
damping: 25
|
|
1921
|
+
},
|
|
1922
|
+
className,
|
|
1923
|
+
style: {
|
|
1924
|
+
display: "inline-flex",
|
|
1925
|
+
alignItems: "center",
|
|
1926
|
+
justifyContent: "center",
|
|
1927
|
+
gap: sizeConfig.gap,
|
|
1928
|
+
padding: sizeConfig.padding,
|
|
1929
|
+
fontSize: sizeConfig.fontSize,
|
|
1930
|
+
fontWeight: 600,
|
|
1931
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
1932
|
+
borderRadius: sizeConfig.borderRadius,
|
|
1933
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
1934
|
+
opacity: disabled ? 0.5 : 1,
|
|
1935
|
+
transition: "all 0.2s ease",
|
|
1936
|
+
position: "relative",
|
|
1937
|
+
overflow: "hidden",
|
|
1938
|
+
...variantStyle,
|
|
1939
|
+
...style
|
|
1940
|
+
},
|
|
1941
|
+
children: [
|
|
1942
|
+
variant === "primary" && /* @__PURE__ */ jsx3(
|
|
1943
|
+
motion2.div,
|
|
1944
|
+
{
|
|
1945
|
+
initial: { opacity: 0 },
|
|
1946
|
+
animate: { opacity: isHovered ? 0.1 : 0 },
|
|
1947
|
+
style: {
|
|
1948
|
+
position: "absolute",
|
|
1949
|
+
inset: 0,
|
|
1950
|
+
background: "white",
|
|
1951
|
+
pointerEvents: "none"
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1954
|
+
),
|
|
1955
|
+
variant === "primary" && /* @__PURE__ */ jsx3(
|
|
1956
|
+
"div",
|
|
1957
|
+
{
|
|
1958
|
+
style: {
|
|
1959
|
+
position: "absolute",
|
|
1960
|
+
inset: 0,
|
|
1961
|
+
background: "linear-gradient(180deg, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0) 50%)",
|
|
1962
|
+
borderRadius: "inherit",
|
|
1963
|
+
pointerEvents: "none"
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
),
|
|
1967
|
+
showIcon && /* @__PURE__ */ jsx3("span", { style: { display: "flex", alignItems: "center", position: "relative", zIndex: 1 }, children: icon || /* @__PURE__ */ jsx3(FeedbackIcon, { size: sizeConfig.iconSize }) }),
|
|
1968
|
+
label && /* @__PURE__ */ jsx3("span", { style: { position: "relative", zIndex: 1 }, children: label })
|
|
1969
|
+
]
|
|
1970
|
+
}
|
|
1971
|
+
);
|
|
1972
|
+
}
|
|
1973
|
+
function adjustColor2(color, amount) {
|
|
1974
|
+
const hex = color.replace("#", "");
|
|
1975
|
+
const num = parseInt(hex, 16);
|
|
1976
|
+
const r = Math.min(255, Math.max(0, (num >> 16) + amount));
|
|
1977
|
+
const g = Math.min(255, Math.max(0, (num >> 8 & 255) + amount));
|
|
1978
|
+
const b = Math.min(255, Math.max(0, (num & 255) + amount));
|
|
1979
|
+
return `#${(r << 16 | g << 8 | b).toString(16).padStart(6, "0")}`;
|
|
1980
|
+
}
|
|
1981
|
+
|
|
1604
1982
|
// src/index.tsx
|
|
1605
1983
|
function IntentAIWidget({
|
|
1606
1984
|
apiKey,
|
|
@@ -1619,9 +1997,9 @@ function IntentAIWidget({
|
|
|
1619
1997
|
onFeedbackSubmitted: _onFeedbackSubmitted,
|
|
1620
1998
|
onError
|
|
1621
1999
|
}) {
|
|
1622
|
-
const widgetRef =
|
|
1623
|
-
const scriptLoadedRef =
|
|
1624
|
-
const initWidget =
|
|
2000
|
+
const widgetRef = useRef4(null);
|
|
2001
|
+
const scriptLoadedRef = useRef4(false);
|
|
2002
|
+
const initWidget = useCallback4(() => {
|
|
1625
2003
|
if (!window.FeedbackIQ || widgetRef.current) return;
|
|
1626
2004
|
try {
|
|
1627
2005
|
widgetRef.current = new window.FeedbackIQ({
|
|
@@ -1644,7 +2022,7 @@ function IntentAIWidget({
|
|
|
1644
2022
|
void _onClose;
|
|
1645
2023
|
void _onFeedbackSubmitted;
|
|
1646
2024
|
}, [apiKey, apiUrl, widgetUrl, position, theme, primaryColor, allowVoice, allowText, allowScreenshot, customMetadata, user, onError]);
|
|
1647
|
-
|
|
2025
|
+
useEffect3(() => {
|
|
1648
2026
|
if (!widgetUrl) {
|
|
1649
2027
|
onError?.(new Error("widgetUrl is required for IntentAIWidget"));
|
|
1650
2028
|
return;
|
|
@@ -1675,39 +2053,39 @@ function IntentAIWidget({
|
|
|
1675
2053
|
}
|
|
1676
2054
|
};
|
|
1677
2055
|
}, [initWidget, onError, widgetUrl]);
|
|
1678
|
-
|
|
2056
|
+
useEffect3(() => {
|
|
1679
2057
|
if (widgetRef.current && user) {
|
|
1680
2058
|
widgetRef.current.identify(user);
|
|
1681
2059
|
}
|
|
1682
2060
|
}, [user]);
|
|
1683
|
-
|
|
2061
|
+
useEffect3(() => {
|
|
1684
2062
|
if (widgetRef.current && customMetadata) {
|
|
1685
2063
|
widgetRef.current.setMetadata(customMetadata);
|
|
1686
2064
|
}
|
|
1687
2065
|
}, [customMetadata]);
|
|
1688
2066
|
return null;
|
|
1689
2067
|
}
|
|
1690
|
-
function
|
|
1691
|
-
const open =
|
|
2068
|
+
function useWidgetControls() {
|
|
2069
|
+
const open = useCallback4(() => {
|
|
1692
2070
|
const widget = document.getElementById("feedbackiq-widget");
|
|
1693
2071
|
if (widget) {
|
|
1694
2072
|
const trigger = widget.shadowRoot?.querySelector(".fiq-trigger");
|
|
1695
2073
|
trigger?.click();
|
|
1696
2074
|
}
|
|
1697
2075
|
}, []);
|
|
1698
|
-
const close =
|
|
2076
|
+
const close = useCallback4(() => {
|
|
1699
2077
|
const widget = document.getElementById("feedbackiq-widget");
|
|
1700
2078
|
if (widget) {
|
|
1701
2079
|
const closeBtn = widget.shadowRoot?.querySelector(".fiq-close");
|
|
1702
2080
|
closeBtn?.click();
|
|
1703
2081
|
}
|
|
1704
2082
|
}, []);
|
|
1705
|
-
const identify =
|
|
2083
|
+
const identify = useCallback4((user) => {
|
|
1706
2084
|
if (window.IntentAI?.widget) {
|
|
1707
2085
|
window.IntentAI.widget.identify(user);
|
|
1708
2086
|
}
|
|
1709
2087
|
}, []);
|
|
1710
|
-
const setMetadata =
|
|
2088
|
+
const setMetadata = useCallback4((metadata) => {
|
|
1711
2089
|
if (window.IntentAI?.widget) {
|
|
1712
2090
|
window.IntentAI.widget.setMetadata(metadata);
|
|
1713
2091
|
}
|
|
@@ -1716,8 +2094,13 @@ function useIntentAI() {
|
|
|
1716
2094
|
}
|
|
1717
2095
|
var index_default = IntentAIWidget;
|
|
1718
2096
|
export {
|
|
2097
|
+
FeedbackButton,
|
|
2098
|
+
IntentAIProvider,
|
|
1719
2099
|
IntentAIWidget,
|
|
1720
2100
|
PremiumVoiceWidget,
|
|
1721
2101
|
index_default as default,
|
|
1722
|
-
|
|
2102
|
+
useIdentify,
|
|
2103
|
+
useIntentAI,
|
|
2104
|
+
useSetMetadata,
|
|
2105
|
+
useWidgetControls
|
|
1723
2106
|
};
|
package/package.json
CHANGED