@tekibo/feedpulse-sdk 2.0.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.js ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class n{constructor(e){this.queue=[],this.flushInterval=null,this.observer=null,this.intersectionObserver=null,this.seenInView=new Set,this.config={endpoint:"https://feedpulse.dev/api/ingest",batchInterval:5e3,...e},this.visitorId=this.getOrCreateVisitorId(),this.sessionId=this.generateSessionId()}init(){this.startFlushInterval(),this.attachGlobalListeners(),this.observeDOM()}attachGlobalListeners(){document.addEventListener("click",i=>{const s=i.target.closest("[data-fp-id]");s&&this.track("click",s.getAttribute("data-fp-id"),{x:i.clientX,y:i.clientY})},{passive:!0});let e=0,t=null;document.addEventListener("mouseover",i=>{const s=i.target.closest("[data-fp-id]");s&&(e=Date.now(),t=s.getAttribute("data-fp-id"))},{passive:!0}),document.addEventListener("mouseout",i=>{if(!i.target.closest("[data-fp-id]")||!t)return;const r=Date.now()-e;r>500&&this.track("hover",t,{hoverDuration:r}),t=null},{passive:!0})}observeDOM(){this.intersectionObserver=new IntersectionObserver(t=>{for(const i of t){const s=i.target.dataset.fpId;!s||!i.isIntersecting||this.seenInView.has(s)||(this.seenInView.add(s),this.track("scroll_into_view",s,{scrollDepth:Math.round(window.scrollY/Math.max(1,document.body.scrollHeight)*100)}))}},{threshold:.5});const e=()=>{document.querySelectorAll("[data-fp-id]").forEach(t=>{this.intersectionObserver?.observe(t)})};e(),this.observer=new MutationObserver(()=>e()),this.observer.observe(document.body,{childList:!0,subtree:!0})}track(e,t,i){this.queue.push({projectApiKey:this.config.apiKey,elementId:t,eventType:e,sessionId:this.sessionId,visitorId:this.visitorId,page:window.location.pathname,referrer:document.referrer,device:this.getDeviceType(),browser:this.getBrowser(),os:this.getOS(),metadata:i,timestamp:new Date().toISOString()})}trackFeedback(e,t,i){!t&&!i||this.sendImmediate([{projectApiKey:this.config.apiKey,elementId:e??"__page__",eventType:"feedback",sessionId:this.sessionId,visitorId:this.visitorId,page:window.location.pathname,device:this.getDeviceType(),metadata:{rating:t,message:i},timestamp:new Date().toISOString()}])}async flush(){if(this.queue.length===0)return;const e=[...this.queue];this.queue=[],await this.sendImmediate(e)}async sendImmediate(e){try{await fetch(this.config.endpoint,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({events:e}),keepalive:!0})}catch{}}startFlushInterval(){this.flushInterval=setInterval(()=>this.flush(),this.config.batchInterval),window.addEventListener("beforeunload",()=>this.flush()),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&this.flush()})}getOrCreateVisitorId(){const e="__fp_vid";let t=localStorage.getItem(e);return t||(t=crypto.randomUUID(),localStorage.setItem(e,t)),t}generateSessionId(){return`${Date.now()}-${Math.random().toString(36).slice(2)}`}getDeviceType(){const e=navigator.userAgent;return/Mobi|Android/i.test(e)?"mobile":/Tablet|iPad/i.test(e)?"tablet":"desktop"}getBrowser(){const e=navigator.userAgent;return e.includes("Edg")?"Edge":e.includes("Chrome")?"Chrome":e.includes("Firefox")?"Firefox":e.includes("Safari")?"Safari":"Other"}getOS(){const e=navigator.userAgent;return e.includes("Windows")?"Windows":e.includes("Mac")?"macOS":e.includes("Linux")?"Linux":e.includes("Android")?"Android":/iPhone|iOS/.test(e)?"iOS":"Other"}destroy(){this.flushInterval&&clearInterval(this.flushInterval),this.observer?.disconnect(),this.intersectionObserver?.disconnect(),this.flush()}}exports.FeedPulseTracker=n;
package/dist/index.mjs ADDED
@@ -0,0 +1,124 @@
1
+ class o {
2
+ constructor(e) {
3
+ this.queue = [], this.flushInterval = null, this.observer = null, this.intersectionObserver = null, this.seenInView = /* @__PURE__ */ new Set(), this.config = {
4
+ endpoint: "https://feedpulse.dev/api/ingest",
5
+ batchInterval: 5e3,
6
+ ...e
7
+ }, this.visitorId = this.getOrCreateVisitorId(), this.sessionId = this.generateSessionId();
8
+ }
9
+ init() {
10
+ this.startFlushInterval(), this.attachGlobalListeners(), this.observeDOM();
11
+ }
12
+ attachGlobalListeners() {
13
+ document.addEventListener("click", (i) => {
14
+ const s = i.target.closest("[data-fp-id]");
15
+ s && this.track("click", s.getAttribute("data-fp-id"), {
16
+ x: i.clientX,
17
+ y: i.clientY
18
+ });
19
+ }, { passive: !0 });
20
+ let e = 0, t = null;
21
+ document.addEventListener("mouseover", (i) => {
22
+ const s = i.target.closest("[data-fp-id]");
23
+ s && (e = Date.now(), t = s.getAttribute("data-fp-id"));
24
+ }, { passive: !0 }), document.addEventListener("mouseout", (i) => {
25
+ if (!i.target.closest("[data-fp-id]") || !t)
26
+ return;
27
+ const r = Date.now() - e;
28
+ r > 500 && this.track("hover", t, { hoverDuration: r }), t = null;
29
+ }, { passive: !0 });
30
+ }
31
+ observeDOM() {
32
+ this.intersectionObserver = new IntersectionObserver((t) => {
33
+ for (const i of t) {
34
+ const s = i.target.dataset.fpId;
35
+ !s || !i.isIntersecting || this.seenInView.has(s) || (this.seenInView.add(s), this.track("scroll_into_view", s, {
36
+ scrollDepth: Math.round(window.scrollY / Math.max(1, document.body.scrollHeight) * 100)
37
+ }));
38
+ }
39
+ }, { threshold: 0.5 });
40
+ const e = () => {
41
+ document.querySelectorAll("[data-fp-id]").forEach((t) => {
42
+ this.intersectionObserver?.observe(t);
43
+ });
44
+ };
45
+ e(), this.observer = new MutationObserver(() => e()), this.observer.observe(document.body, { childList: !0, subtree: !0 });
46
+ }
47
+ track(e, t, i) {
48
+ this.queue.push({
49
+ projectApiKey: this.config.apiKey,
50
+ elementId: t,
51
+ eventType: e,
52
+ sessionId: this.sessionId,
53
+ visitorId: this.visitorId,
54
+ page: window.location.pathname,
55
+ referrer: document.referrer,
56
+ device: this.getDeviceType(),
57
+ browser: this.getBrowser(),
58
+ os: this.getOS(),
59
+ metadata: i,
60
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
61
+ });
62
+ }
63
+ trackFeedback(e, t, i) {
64
+ !t && !i || this.sendImmediate([{
65
+ projectApiKey: this.config.apiKey,
66
+ elementId: e ?? "__page__",
67
+ eventType: "feedback",
68
+ sessionId: this.sessionId,
69
+ visitorId: this.visitorId,
70
+ page: window.location.pathname,
71
+ device: this.getDeviceType(),
72
+ metadata: { rating: t, message: i },
73
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
74
+ }]);
75
+ }
76
+ async flush() {
77
+ if (this.queue.length === 0)
78
+ return;
79
+ const e = [...this.queue];
80
+ this.queue = [], await this.sendImmediate(e);
81
+ }
82
+ async sendImmediate(e) {
83
+ try {
84
+ await fetch(this.config.endpoint, {
85
+ method: "POST",
86
+ headers: { "content-type": "application/json" },
87
+ body: JSON.stringify({ events: e }),
88
+ keepalive: !0
89
+ });
90
+ } catch {
91
+ }
92
+ }
93
+ startFlushInterval() {
94
+ this.flushInterval = setInterval(() => this.flush(), this.config.batchInterval), window.addEventListener("beforeunload", () => this.flush()), document.addEventListener("visibilitychange", () => {
95
+ document.visibilityState === "hidden" && this.flush();
96
+ });
97
+ }
98
+ getOrCreateVisitorId() {
99
+ const e = "__fp_vid";
100
+ let t = localStorage.getItem(e);
101
+ return t || (t = crypto.randomUUID(), localStorage.setItem(e, t)), t;
102
+ }
103
+ generateSessionId() {
104
+ return `${Date.now()}-${Math.random().toString(36).slice(2)}`;
105
+ }
106
+ getDeviceType() {
107
+ const e = navigator.userAgent;
108
+ return /Mobi|Android/i.test(e) ? "mobile" : /Tablet|iPad/i.test(e) ? "tablet" : "desktop";
109
+ }
110
+ getBrowser() {
111
+ const e = navigator.userAgent;
112
+ return e.includes("Edg") ? "Edge" : e.includes("Chrome") ? "Chrome" : e.includes("Firefox") ? "Firefox" : e.includes("Safari") ? "Safari" : "Other";
113
+ }
114
+ getOS() {
115
+ const e = navigator.userAgent;
116
+ return e.includes("Windows") ? "Windows" : e.includes("Mac") ? "macOS" : e.includes("Linux") ? "Linux" : e.includes("Android") ? "Android" : /iPhone|iOS/.test(e) ? "iOS" : "Other";
117
+ }
118
+ destroy() {
119
+ this.flushInterval && clearInterval(this.flushInterval), this.observer?.disconnect(), this.intersectionObserver?.disconnect(), this.flush();
120
+ }
121
+ }
122
+ export {
123
+ o as FeedPulseTracker
124
+ };
package/dist/nuxt.js ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("vue"),x=require("./index.js"),c=Symbol("feedpulse");function p(){return e.inject(c,null)}const g=e.defineComponent({__name:"FeedPulseProvider",props:{apiKey:{},endpoint:{}},setup(t){const n=t,d=new x.FeedPulseTracker({apiKey:n.apiKey,endpoint:n.endpoint});return e.provide(c,d),e.onMounted(()=>d.init()),e.onBeforeUnmount(()=>d.destroy()),(r,o)=>e.renderSlot(r.$slots,"default")}}),b={key:1,style:{background:"#fff",border:"1px solid #e5e7eb","border-radius":"12px",padding:"16px",width:"280px","box-shadow":"0 10px 25px rgba(0,0,0,0.15)"}},k={style:{margin:"0 0 12px","font-weight":"600",color:"#111"}},v={style:{display:"flex",gap:"6px","margin-bottom":"12px"}},y=["onClick"],h={key:1,style:{"text-align":"center",padding:"16px",color:"#111"}},E=e.defineComponent({__name:"FeedPulseWidget",props:{id:{},placeholder:{},position:{default:"bottom-right"}},setup(t){const n=t,d=p(),r=e.ref(n.position==="inline"),o=e.ref(null),s=e.ref(""),a=e.ref(!1);function m(u){o.value=u}function f(){!o.value&&!s.value.trim()||(d?.trackFeedback(n.id??null,o.value,s.value||null),a.value=!0,setTimeout(()=>{r.value=n.position==="inline",a.value=!1,o.value=null,s.value=""},2e3))}return(u,l)=>(e.openBlock(),e.createElementBlock("div",{class:"feedpulse-widget",style:e.normalizeStyle(t.position!=="inline"?`position:fixed; ${t.position==="bottom-right"?"right:24px":"left:24px"}; bottom:24px; z-index:9999;`:"")},[t.position!=="inline"?(e.openBlock(),e.createElementBlock("button",{key:0,style:{background:"#6366f1",color:"#fff",border:"none","border-radius":"50%",width:"48px",height:"48px","font-size":"20px",cursor:"pointer"},onClick:l[0]||(l[0]=i=>r.value=!r.value)}," 💬 ")):e.createCommentVNode("",!0),r.value?(e.openBlock(),e.createElementBlock("div",b,[a.value?(e.openBlock(),e.createElementBlock("div",h,[...l[2]||(l[2]=[e.createElementVNode("p",{style:{"font-size":"28px",margin:"0"}}," 🎉 ",-1),e.createElementVNode("p",{style:{margin:"8px 0 0","font-weight":"600"}}," Thanks for your feedback! ",-1)])])):(e.openBlock(),e.createElementBlock(e.Fragment,{key:0},[e.createElementVNode("p",k,e.toDisplayString(t.placeholder??"How was your experience?"),1),e.createElementVNode("div",v,[(e.openBlock(),e.createElementBlock(e.Fragment,null,e.renderList(5,i=>e.createElementVNode("button",{key:i,style:e.normalizeStyle({background:"none",border:"none",cursor:"pointer",fontSize:"24px",opacity:o.value!==null&&i<=o.value?1:.3}),onClick:w=>m(i)}," ⭐ ",12,y)),64))]),e.withDirectives(e.createElementVNode("textarea",{"onUpdate:modelValue":l[1]||(l[1]=i=>s.value=i),placeholder:"Tell us more (optional)...",rows:"3",style:{width:"100%",padding:"8px",border:"1px solid #d1d5db","border-radius":"8px",resize:"none","font-size":"14px"}},null,512),[[e.vModelText,s.value]]),e.createElementVNode("button",{style:{"margin-top":"10px",width:"100%",background:"#6366f1",color:"#fff",border:"none","border-radius":"8px",padding:"10px","font-weight":"600",cursor:"pointer"},onClick:f}," Submit Feedback ")],64))])):e.createCommentVNode("",!0)],4))}});exports.FeedPulseProvider=g;exports.FeedPulseWidget=E;exports.useFeedPulse=p;
package/dist/nuxt.mjs ADDED
@@ -0,0 +1,86 @@
1
+ import { inject as h, defineComponent as g, provide as w, onMounted as F, onBeforeUnmount as P, renderSlot as _, ref as p, createElementBlock as s, openBlock as d, normalizeStyle as x, createCommentVNode as m, Fragment as b, createElementVNode as o, withDirectives as z, toDisplayString as S, renderList as C, vModelText as E } from "vue";
2
+ import { FeedPulseTracker as T } from "./index.mjs";
3
+ const v = /* @__PURE__ */ Symbol("feedpulse");
4
+ function $() {
5
+ return h(v, null);
6
+ }
7
+ const W = /* @__PURE__ */ g({
8
+ __name: "FeedPulseProvider",
9
+ props: {
10
+ apiKey: {},
11
+ endpoint: {}
12
+ },
13
+ setup(e) {
14
+ const n = e, a = new T({
15
+ apiKey: n.apiKey,
16
+ endpoint: n.endpoint
17
+ });
18
+ return w(v, a), F(() => a.init()), P(() => a.destroy()), (i, t) => _(i.$slots, "default");
19
+ }
20
+ }), K = {
21
+ key: 1,
22
+ style: { background: "#fff", border: "1px solid #e5e7eb", "border-radius": "12px", padding: "16px", width: "280px", "box-shadow": "0 10px 25px rgba(0,0,0,0.15)" }
23
+ }, B = { style: { margin: "0 0 12px", "font-weight": "600", color: "#111" } }, D = { style: { display: "flex", gap: "6px", "margin-bottom": "12px" } }, U = ["onClick"], V = {
24
+ key: 1,
25
+ style: { "text-align": "center", padding: "16px", color: "#111" }
26
+ }, j = /* @__PURE__ */ g({
27
+ __name: "FeedPulseWidget",
28
+ props: {
29
+ id: {},
30
+ placeholder: {},
31
+ position: { default: "bottom-right" }
32
+ },
33
+ setup(e) {
34
+ const n = e, a = $(), i = p(n.position === "inline"), t = p(null), u = p(""), c = p(!1);
35
+ function y(f) {
36
+ t.value = f;
37
+ }
38
+ function k() {
39
+ !t.value && !u.value.trim() || (a?.trackFeedback(n.id ?? null, t.value, u.value || null), c.value = !0, setTimeout(() => {
40
+ i.value = n.position === "inline", c.value = !1, t.value = null, u.value = "";
41
+ }, 2e3));
42
+ }
43
+ return (f, r) => (d(), s("div", {
44
+ class: "feedpulse-widget",
45
+ style: x(e.position !== "inline" ? `position:fixed; ${e.position === "bottom-right" ? "right:24px" : "left:24px"}; bottom:24px; z-index:9999;` : "")
46
+ }, [
47
+ e.position !== "inline" ? (d(), s("button", {
48
+ key: 0,
49
+ style: { background: "#6366f1", color: "#fff", border: "none", "border-radius": "50%", width: "48px", height: "48px", "font-size": "20px", cursor: "pointer" },
50
+ onClick: r[0] || (r[0] = (l) => i.value = !i.value)
51
+ }, " 💬 ")) : m("", !0),
52
+ i.value ? (d(), s("div", K, [
53
+ c.value ? (d(), s("div", V, [...r[2] || (r[2] = [
54
+ o("p", { style: { "font-size": "28px", margin: "0" } }, " 🎉 ", -1),
55
+ o("p", { style: { margin: "8px 0 0", "font-weight": "600" } }, " Thanks for your feedback! ", -1)
56
+ ])])) : (d(), s(b, { key: 0 }, [
57
+ o("p", B, S(e.placeholder ?? "How was your experience?"), 1),
58
+ o("div", D, [
59
+ (d(), s(b, null, C(5, (l) => o("button", {
60
+ key: l,
61
+ style: x({ background: "none", border: "none", cursor: "pointer", fontSize: "24px", opacity: t.value !== null && l <= t.value ? 1 : 0.3 }),
62
+ onClick: (L) => y(l)
63
+ }, " ⭐ ", 12, U)), 64))
64
+ ]),
65
+ z(o("textarea", {
66
+ "onUpdate:modelValue": r[1] || (r[1] = (l) => u.value = l),
67
+ placeholder: "Tell us more (optional)...",
68
+ rows: "3",
69
+ style: { width: "100%", padding: "8px", border: "1px solid #d1d5db", "border-radius": "8px", resize: "none", "font-size": "14px" }
70
+ }, null, 512), [
71
+ [E, u.value]
72
+ ]),
73
+ o("button", {
74
+ style: { "margin-top": "10px", width: "100%", background: "#6366f1", color: "#fff", border: "none", "border-radius": "8px", padding: "10px", "font-weight": "600", cursor: "pointer" },
75
+ onClick: k
76
+ }, " Submit Feedback ")
77
+ ], 64))
78
+ ])) : m("", !0)
79
+ ], 4));
80
+ }
81
+ });
82
+ export {
83
+ W as FeedPulseProvider,
84
+ j as FeedPulseWidget,
85
+ $ as useFeedPulse
86
+ };
package/dist/react.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const m=require("react"),ne=require("./index.js");var S={exports:{}},g={};var z;function oe(){if(z)return g;z=1;var i=Symbol.for("react.transitional.element"),d=Symbol.for("react.fragment");function l(c,a,u){var f=null;if(u!==void 0&&(f=""+u),a.key!==void 0&&(f=""+a.key),"key"in a){u={};for(var b in a)b!=="key"&&(u[b]=a[b])}else u=a;return a=u.ref,{$$typeof:i,type:c,key:f,ref:a!==void 0?a:null,props:u}}return g.Fragment=d,g.jsx=l,g.jsxs=l,g}var x={};var D;function ae(){return D||(D=1,process.env.NODE_ENV!=="production"&&(function(){function i(e){if(e==null)return null;if(typeof e=="function")return e.$$typeof===ee?null:e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case P:return"Fragment";case V:return"Profiler";case J:return"StrictMode";case H:return"Suspense";case Z:return"SuspenseList";case K:return"Activity"}if(typeof e=="object")switch(typeof e.tag=="number"&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),e.$$typeof){case U:return"Portal";case X:return e.displayName||"Context";case G:return(e._context.displayName||"Context")+".Consumer";case B:var r=e.render;return e=e.displayName,e||(e=r.displayName||r.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case Q:return r=e.displayName||null,r!==null?r:i(e.type)||"Memo";case j:r=e._payload,e=e._init;try{return i(e(r))}catch{}}return null}function d(e){return""+e}function l(e){try{d(e);var r=!1}catch{r=!0}if(r){r=console;var t=r.error,n=typeof Symbol=="function"&&Symbol.toStringTag&&e[Symbol.toStringTag]||e.constructor.name||"Object";return t.call(r,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",n),d(e)}}function c(e){if(e===P)return"<>";if(typeof e=="object"&&e!==null&&e.$$typeof===j)return"<...>";try{var r=i(e);return r?"<"+r+">":"<...>"}catch{return"<...>"}}function a(){var e=w.A;return e===null?null:e.getOwner()}function u(){return Error("react-stack-top-frame")}function f(e){if(N.call(e,"key")){var r=Object.getOwnPropertyDescriptor(e,"key").get;if(r&&r.isReactWarning)return!1}return e.key!==void 0}function b(e,r){function t(){F||(F=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",r))}t.isReactWarning=!0,Object.defineProperty(e,"key",{get:t,configurable:!0})}function R(){var e=i(this.type);return Y[e]||(Y[e]=!0,console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")),e=this.props.ref,e!==void 0?e:null}function T(e,r,t,n,y,A){var o=t.ref;return e={$$typeof:p,type:e,key:r,props:t,_owner:n},(o!==void 0?o:null)!==null?Object.defineProperty(e,"ref",{enumerable:!1,get:R}):Object.defineProperty(e,"ref",{enumerable:!1,value:null}),e._store={},Object.defineProperty(e._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(e,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(e,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:y}),Object.defineProperty(e,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:A}),Object.freeze&&(Object.freeze(e.props),Object.freeze(e)),e}function k(e,r,t,n,y,A){var o=r.children;if(o!==void 0)if(n)if(re(o)){for(n=0;n<o.length;n++)v(o[n]);Object.freeze&&Object.freeze(o)}else console.error("React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.");else v(o);if(N.call(r,"key")){o=i(e);var _=Object.keys(r).filter(function(te){return te!=="key"});n=0<_.length?"{key: someKey, "+_.join(": ..., ")+": ...}":"{key: someKey}",W[o+n]||(_=0<_.length?"{"+_.join(": ..., ")+": ...}":"{}",console.error(`A props object containing a "key" prop is being spread into JSX:
2
+ let props = %s;
3
+ <%s {...props} />
4
+ React keys must be passed directly to JSX without using spread:
5
+ let props = %s;
6
+ <%s key={someKey} {...props} />`,n,o,_,o),W[o+n]=!0)}if(o=null,t!==void 0&&(l(t),o=""+t),f(r)&&(l(r.key),o=""+r.key),"key"in r){t={};for(var C in r)C!=="key"&&(t[C]=r[C])}else t=r;return o&&b(t,typeof e=="function"?e.displayName||e.name||"Unknown":e),T(e,o,t,a(),y,A)}function v(e){h(e)?e._store&&(e._store.validated=1):typeof e=="object"&&e!==null&&e.$$typeof===j&&(e._payload.status==="fulfilled"?h(e._payload.value)&&e._payload.value._store&&(e._payload.value._store.validated=1):e._store&&(e._store.validated=1))}function h(e){return typeof e=="object"&&e!==null&&e.$$typeof===p}var E=m,p=Symbol.for("react.transitional.element"),U=Symbol.for("react.portal"),P=Symbol.for("react.fragment"),J=Symbol.for("react.strict_mode"),V=Symbol.for("react.profiler"),G=Symbol.for("react.consumer"),X=Symbol.for("react.context"),B=Symbol.for("react.forward_ref"),H=Symbol.for("react.suspense"),Z=Symbol.for("react.suspense_list"),Q=Symbol.for("react.memo"),j=Symbol.for("react.lazy"),K=Symbol.for("react.activity"),ee=Symbol.for("react.client.reference"),w=E.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,N=Object.prototype.hasOwnProperty,re=Array.isArray,O=console.createTask?console.createTask:function(){return null};E={react_stack_bottom_frame:function(e){return e()}};var F,Y={},I=E.react_stack_bottom_frame.bind(E,u)(),$=O(c(u)),W={};x.Fragment=P,x.jsx=function(e,r,t){var n=1e4>w.recentlyCreatedOwnerStacks++;return k(e,r,t,!1,n?Error("react-stack-top-frame"):I,n?O(c(e)):$)},x.jsxs=function(e,r,t){var n=1e4>w.recentlyCreatedOwnerStacks++;return k(e,r,t,!0,n?Error("react-stack-top-frame"):I,n?O(c(e)):$)}})()),x}var M;function se(){return M||(M=1,process.env.NODE_ENV==="production"?S.exports=oe():S.exports=ae()),S.exports}var s=se();const L=m.createContext({tracker:null});function le({apiKey:i,endpoint:d,children:l}){const c=m.useRef(null);return m.useEffect(()=>(c.current=new ne.FeedPulseTracker({apiKey:i,endpoint:d}),c.current.init(),()=>c.current?.destroy()),[i,d]),s.jsx(L.Provider,{value:{tracker:c.current},children:l})}function q(){return m.useContext(L)}function ue({id:i,placeholder:d,position:l="bottom-right"}){const{tracker:c}=q(),[a,u]=m.useState(l==="inline"),[f,b]=m.useState(null),[R,T]=m.useState(""),[k,v]=m.useState(!1),h=()=>{!f&&!R.trim()||(c?.trackFeedback(i??null,f,R||null),v(!0),setTimeout(()=>{u(l==="inline"),v(!1),b(null),T("")},2e3))},E=l!=="inline"?{position:"fixed",bottom:24,[l==="bottom-right"?"right":"left"]:24,zIndex:9999}:{};return s.jsxs("div",{style:E,children:[l!=="inline"&&s.jsx("button",{onClick:()=>u(!a),style:{background:"#6366f1",color:"#fff",border:"none",borderRadius:"50%",width:48,height:48,fontSize:20,cursor:"pointer"},children:"💬"}),a&&s.jsx("div",{style:{background:"#fff",border:"1px solid #e5e7eb",borderRadius:12,padding:16,width:280,boxShadow:"0 10px 25px rgba(0,0,0,0.15)"},children:k?s.jsxs("div",{style:{textAlign:"center",padding:16},children:[s.jsx("p",{style:{fontSize:28,margin:0},children:"🎉"}),s.jsx("p",{style:{margin:"8px 0 0",fontWeight:600},children:"Thanks for your feedback!"})]}):s.jsxs(s.Fragment,{children:[s.jsx("p",{style:{margin:"0 0 12px",fontWeight:600},children:d??"How was your experience?"}),s.jsx("div",{style:{display:"flex",gap:6,marginBottom:12},children:[1,2,3,4,5].map(p=>s.jsx("button",{onClick:()=>b(p),style:{background:"none",border:"none",cursor:"pointer",fontSize:24,opacity:f!==null&&p<=f?1:.3},children:"⭐"},p))}),s.jsx("textarea",{value:R,onChange:p=>T(p.target.value),placeholder:"Tell us more (optional)...",rows:3,style:{width:"100%",padding:8,border:"1px solid #d1d5db",borderRadius:8,resize:"none",fontSize:14}}),s.jsx("button",{onClick:h,style:{marginTop:10,width:"100%",background:"#6366f1",color:"#fff",border:"none",borderRadius:8,padding:10,fontWeight:600,cursor:"pointer"},children:"Submit Feedback"})]})})]})}exports.FeedPulseProvider=le;exports.FeedPulseWidget=ue;exports.useFeedPulse=q;
package/dist/react.mjs ADDED
@@ -0,0 +1,329 @@
1
+ import te, { createContext as ne, useRef as oe, useEffect as ae, useContext as se, useState as y } from "react";
2
+ import { FeedPulseTracker as le } from "./index.mjs";
3
+ var S = { exports: {} }, v = {};
4
+ var z;
5
+ function ue() {
6
+ if (z) return v;
7
+ z = 1;
8
+ var i = /* @__PURE__ */ Symbol.for("react.transitional.element"), d = /* @__PURE__ */ Symbol.for("react.fragment");
9
+ function l(c, a, u) {
10
+ var f = null;
11
+ if (u !== void 0 && (f = "" + u), a.key !== void 0 && (f = "" + a.key), "key" in a) {
12
+ u = {};
13
+ for (var m in a)
14
+ m !== "key" && (u[m] = a[m]);
15
+ } else u = a;
16
+ return a = u.ref, {
17
+ $$typeof: i,
18
+ type: c,
19
+ key: f,
20
+ ref: a !== void 0 ? a : null,
21
+ props: u
22
+ };
23
+ }
24
+ return v.Fragment = d, v.jsx = l, v.jsxs = l, v;
25
+ }
26
+ var g = {};
27
+ var D;
28
+ function ie() {
29
+ return D || (D = 1, process.env.NODE_ENV !== "production" && (function() {
30
+ function i(e) {
31
+ if (e == null) return null;
32
+ if (typeof e == "function")
33
+ return e.$$typeof === K ? null : e.displayName || e.name || null;
34
+ if (typeof e == "string") return e;
35
+ switch (e) {
36
+ case j:
37
+ return "Fragment";
38
+ case J:
39
+ return "Profiler";
40
+ case q:
41
+ return "StrictMode";
42
+ case B:
43
+ return "Suspense";
44
+ case H:
45
+ return "SuspenseList";
46
+ case Q:
47
+ return "Activity";
48
+ }
49
+ if (typeof e == "object")
50
+ switch (typeof e.tag == "number" && console.error(
51
+ "Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."
52
+ ), e.$$typeof) {
53
+ case U:
54
+ return "Portal";
55
+ case G:
56
+ return e.displayName || "Context";
57
+ case V:
58
+ return (e._context.displayName || "Context") + ".Consumer";
59
+ case X:
60
+ var r = e.render;
61
+ return e = e.displayName, e || (e = r.displayName || r.name || "", e = e !== "" ? "ForwardRef(" + e + ")" : "ForwardRef"), e;
62
+ case Z:
63
+ return r = e.displayName || null, r !== null ? r : i(e.type) || "Memo";
64
+ case w:
65
+ r = e._payload, e = e._init;
66
+ try {
67
+ return i(e(r));
68
+ } catch {
69
+ }
70
+ }
71
+ return null;
72
+ }
73
+ function d(e) {
74
+ return "" + e;
75
+ }
76
+ function l(e) {
77
+ try {
78
+ d(e);
79
+ var r = !1;
80
+ } catch {
81
+ r = !0;
82
+ }
83
+ if (r) {
84
+ r = console;
85
+ var t = r.error, n = typeof Symbol == "function" && Symbol.toStringTag && e[Symbol.toStringTag] || e.constructor.name || "Object";
86
+ return t.call(
87
+ r,
88
+ "The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",
89
+ n
90
+ ), d(e);
91
+ }
92
+ }
93
+ function c(e) {
94
+ if (e === j) return "<>";
95
+ if (typeof e == "object" && e !== null && e.$$typeof === w)
96
+ return "<...>";
97
+ try {
98
+ var r = i(e);
99
+ return r ? "<" + r + ">" : "<...>";
100
+ } catch {
101
+ return "<...>";
102
+ }
103
+ }
104
+ function a() {
105
+ var e = P.A;
106
+ return e === null ? null : e.getOwner();
107
+ }
108
+ function u() {
109
+ return Error("react-stack-top-frame");
110
+ }
111
+ function f(e) {
112
+ if (N.call(e, "key")) {
113
+ var r = Object.getOwnPropertyDescriptor(e, "key").get;
114
+ if (r && r.isReactWarning) return !1;
115
+ }
116
+ return e.key !== void 0;
117
+ }
118
+ function m(e, r) {
119
+ function t() {
120
+ F || (F = !0, console.error(
121
+ "%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",
122
+ r
123
+ ));
124
+ }
125
+ t.isReactWarning = !0, Object.defineProperty(e, "key", {
126
+ get: t,
127
+ configurable: !0
128
+ });
129
+ }
130
+ function _() {
131
+ var e = i(this.type);
132
+ return Y[e] || (Y[e] = !0, console.error(
133
+ "Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release."
134
+ )), e = this.props.ref, e !== void 0 ? e : null;
135
+ }
136
+ function x(e, r, t, n, h, A) {
137
+ var o = t.ref;
138
+ return e = {
139
+ $$typeof: b,
140
+ type: e,
141
+ key: r,
142
+ props: t,
143
+ _owner: n
144
+ }, (o !== void 0 ? o : null) !== null ? Object.defineProperty(e, "ref", {
145
+ enumerable: !1,
146
+ get: _
147
+ }) : Object.defineProperty(e, "ref", { enumerable: !1, value: null }), e._store = {}, Object.defineProperty(e._store, "validated", {
148
+ configurable: !1,
149
+ enumerable: !1,
150
+ writable: !0,
151
+ value: 0
152
+ }), Object.defineProperty(e, "_debugInfo", {
153
+ configurable: !1,
154
+ enumerable: !1,
155
+ writable: !0,
156
+ value: null
157
+ }), Object.defineProperty(e, "_debugStack", {
158
+ configurable: !1,
159
+ enumerable: !1,
160
+ writable: !0,
161
+ value: h
162
+ }), Object.defineProperty(e, "_debugTask", {
163
+ configurable: !1,
164
+ enumerable: !1,
165
+ writable: !0,
166
+ value: A
167
+ }), Object.freeze && (Object.freeze(e.props), Object.freeze(e)), e;
168
+ }
169
+ function k(e, r, t, n, h, A) {
170
+ var o = r.children;
171
+ if (o !== void 0)
172
+ if (n)
173
+ if (ee(o)) {
174
+ for (n = 0; n < o.length; n++)
175
+ R(o[n]);
176
+ Object.freeze && Object.freeze(o);
177
+ } else
178
+ console.error(
179
+ "React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead."
180
+ );
181
+ else R(o);
182
+ if (N.call(r, "key")) {
183
+ o = i(e);
184
+ var E = Object.keys(r).filter(function(re) {
185
+ return re !== "key";
186
+ });
187
+ n = 0 < E.length ? "{key: someKey, " + E.join(": ..., ") + ": ...}" : "{key: someKey}", W[o + n] || (E = 0 < E.length ? "{" + E.join(": ..., ") + ": ...}" : "{}", console.error(
188
+ `A props object containing a "key" prop is being spread into JSX:
189
+ let props = %s;
190
+ <%s {...props} />
191
+ React keys must be passed directly to JSX without using spread:
192
+ let props = %s;
193
+ <%s key={someKey} {...props} />`,
194
+ n,
195
+ o,
196
+ E,
197
+ o
198
+ ), W[o + n] = !0);
199
+ }
200
+ if (o = null, t !== void 0 && (l(t), o = "" + t), f(r) && (l(r.key), o = "" + r.key), "key" in r) {
201
+ t = {};
202
+ for (var C in r)
203
+ C !== "key" && (t[C] = r[C]);
204
+ } else t = r;
205
+ return o && m(
206
+ t,
207
+ typeof e == "function" ? e.displayName || e.name || "Unknown" : e
208
+ ), x(
209
+ e,
210
+ o,
211
+ t,
212
+ a(),
213
+ h,
214
+ A
215
+ );
216
+ }
217
+ function R(e) {
218
+ T(e) ? e._store && (e._store.validated = 1) : typeof e == "object" && e !== null && e.$$typeof === w && (e._payload.status === "fulfilled" ? T(e._payload.value) && e._payload.value._store && (e._payload.value._store.validated = 1) : e._store && (e._store.validated = 1));
219
+ }
220
+ function T(e) {
221
+ return typeof e == "object" && e !== null && e.$$typeof === b;
222
+ }
223
+ var p = te, b = /* @__PURE__ */ Symbol.for("react.transitional.element"), U = /* @__PURE__ */ Symbol.for("react.portal"), j = /* @__PURE__ */ Symbol.for("react.fragment"), q = /* @__PURE__ */ Symbol.for("react.strict_mode"), J = /* @__PURE__ */ Symbol.for("react.profiler"), V = /* @__PURE__ */ Symbol.for("react.consumer"), G = /* @__PURE__ */ Symbol.for("react.context"), X = /* @__PURE__ */ Symbol.for("react.forward_ref"), B = /* @__PURE__ */ Symbol.for("react.suspense"), H = /* @__PURE__ */ Symbol.for("react.suspense_list"), Z = /* @__PURE__ */ Symbol.for("react.memo"), w = /* @__PURE__ */ Symbol.for("react.lazy"), Q = /* @__PURE__ */ Symbol.for("react.activity"), K = /* @__PURE__ */ Symbol.for("react.client.reference"), P = p.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, N = Object.prototype.hasOwnProperty, ee = Array.isArray, O = console.createTask ? console.createTask : function() {
224
+ return null;
225
+ };
226
+ p = {
227
+ react_stack_bottom_frame: function(e) {
228
+ return e();
229
+ }
230
+ };
231
+ var F, Y = {}, I = p.react_stack_bottom_frame.bind(
232
+ p,
233
+ u
234
+ )(), $ = O(c(u)), W = {};
235
+ g.Fragment = j, g.jsx = function(e, r, t) {
236
+ var n = 1e4 > P.recentlyCreatedOwnerStacks++;
237
+ return k(
238
+ e,
239
+ r,
240
+ t,
241
+ !1,
242
+ n ? Error("react-stack-top-frame") : I,
243
+ n ? O(c(e)) : $
244
+ );
245
+ }, g.jsxs = function(e, r, t) {
246
+ var n = 1e4 > P.recentlyCreatedOwnerStacks++;
247
+ return k(
248
+ e,
249
+ r,
250
+ t,
251
+ !0,
252
+ n ? Error("react-stack-top-frame") : I,
253
+ n ? O(c(e)) : $
254
+ );
255
+ };
256
+ })()), g;
257
+ }
258
+ var M;
259
+ function ce() {
260
+ return M || (M = 1, process.env.NODE_ENV === "production" ? S.exports = ue() : S.exports = ie()), S.exports;
261
+ }
262
+ var s = ce();
263
+ const L = ne({ tracker: null });
264
+ function be({
265
+ apiKey: i,
266
+ endpoint: d,
267
+ children: l
268
+ }) {
269
+ const c = oe(null);
270
+ return ae(() => (c.current = new le({ apiKey: i, endpoint: d }), c.current.init(), () => c.current?.destroy()), [i, d]), /* @__PURE__ */ s.jsx(L.Provider, { value: { tracker: c.current }, children: l });
271
+ }
272
+ function fe() {
273
+ return se(L);
274
+ }
275
+ function pe({ id: i, placeholder: d, position: l = "bottom-right" }) {
276
+ const { tracker: c } = fe(), [a, u] = y(l === "inline"), [f, m] = y(null), [_, x] = y(""), [k, R] = y(!1), T = () => {
277
+ !f && !_.trim() || (c?.trackFeedback(i ?? null, f, _ || null), R(!0), setTimeout(() => {
278
+ u(l === "inline"), R(!1), m(null), x("");
279
+ }, 2e3));
280
+ }, p = l !== "inline" ? { position: "fixed", bottom: 24, [l === "bottom-right" ? "right" : "left"]: 24, zIndex: 9999 } : {};
281
+ return /* @__PURE__ */ s.jsxs("div", { style: p, children: [
282
+ l !== "inline" && /* @__PURE__ */ s.jsx(
283
+ "button",
284
+ {
285
+ onClick: () => u(!a),
286
+ style: { background: "#6366f1", color: "#fff", border: "none", borderRadius: "50%", width: 48, height: 48, fontSize: 20, cursor: "pointer" },
287
+ children: "💬"
288
+ }
289
+ ),
290
+ a && /* @__PURE__ */ s.jsx("div", { style: { background: "#fff", border: "1px solid #e5e7eb", borderRadius: 12, padding: 16, width: 280, boxShadow: "0 10px 25px rgba(0,0,0,0.15)" }, children: k ? /* @__PURE__ */ s.jsxs("div", { style: { textAlign: "center", padding: 16 }, children: [
291
+ /* @__PURE__ */ s.jsx("p", { style: { fontSize: 28, margin: 0 }, children: "🎉" }),
292
+ /* @__PURE__ */ s.jsx("p", { style: { margin: "8px 0 0", fontWeight: 600 }, children: "Thanks for your feedback!" })
293
+ ] }) : /* @__PURE__ */ s.jsxs(s.Fragment, { children: [
294
+ /* @__PURE__ */ s.jsx("p", { style: { margin: "0 0 12px", fontWeight: 600 }, children: d ?? "How was your experience?" }),
295
+ /* @__PURE__ */ s.jsx("div", { style: { display: "flex", gap: 6, marginBottom: 12 }, children: [1, 2, 3, 4, 5].map((b) => /* @__PURE__ */ s.jsx(
296
+ "button",
297
+ {
298
+ onClick: () => m(b),
299
+ style: { background: "none", border: "none", cursor: "pointer", fontSize: 24, opacity: f !== null && b <= f ? 1 : 0.3 },
300
+ children: "⭐"
301
+ },
302
+ b
303
+ )) }),
304
+ /* @__PURE__ */ s.jsx(
305
+ "textarea",
306
+ {
307
+ value: _,
308
+ onChange: (b) => x(b.target.value),
309
+ placeholder: "Tell us more (optional)...",
310
+ rows: 3,
311
+ style: { width: "100%", padding: 8, border: "1px solid #d1d5db", borderRadius: 8, resize: "none", fontSize: 14 }
312
+ }
313
+ ),
314
+ /* @__PURE__ */ s.jsx(
315
+ "button",
316
+ {
317
+ onClick: T,
318
+ style: { marginTop: 10, width: "100%", background: "#6366f1", color: "#fff", border: "none", borderRadius: 8, padding: 10, fontWeight: 600, cursor: "pointer" },
319
+ children: "Submit Feedback"
320
+ }
321
+ )
322
+ ] }) })
323
+ ] });
324
+ }
325
+ export {
326
+ be as FeedPulseProvider,
327
+ pe as FeedPulseWidget,
328
+ fe as useFeedPulse
329
+ };
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@tekibo/feedpulse-sdk",
3
+ "version": "2.0.0",
4
+ "description": "Embeddable analytics and feedback SDK for FeedPulse",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "exports": {
12
+ ".": {
13
+ "import": "./dist/index.mjs",
14
+ "require": "./dist/index.js"
15
+ },
16
+ "./nuxt": {
17
+ "import": "./dist/nuxt.mjs",
18
+ "require": "./dist/nuxt.js"
19
+ },
20
+ "./react": {
21
+ "import": "./dist/react.mjs",
22
+ "require": "./dist/react.js"
23
+ }
24
+ },
25
+ "peerDependencies": {
26
+ "react": ">=18.0.0",
27
+ "vue": ">=3.0.0"
28
+ },
29
+ "peerDependenciesMeta": {
30
+ "react": {
31
+ "optional": true
32
+ },
33
+ "vue": {
34
+ "optional": true
35
+ }
36
+ },
37
+ "scripts": {
38
+ "build": "vite build",
39
+ "dev": "vite build --watch"
40
+ },
41
+ "devDependencies": {
42
+ "@vitejs/plugin-react": "^4.7.0",
43
+ "@vitejs/plugin-vue": "^6.0.1",
44
+ "react": "^19.1.1",
45
+ "typescript": "^5.9.3",
46
+ "vite": "^7.1.12",
47
+ "vue": "^3.5.26"
48
+ }
49
+ }