@heedkit/sdk-js 0.1.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/LICENSE +21 -0
- package/README.md +74 -0
- package/dist/heedkit.iife.js +115 -0
- package/dist/heedkit.iife.js.map +1 -0
- package/dist/index.cjs +714 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +116 -0
- package/dist/index.d.ts +116 -0
- package/dist/index.js +686 -0
- package/dist/index.js.map +1 -0
- package/package.json +57 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 HeedKit
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# @heedkit/sdk-js
|
|
2
|
+
|
|
3
|
+
Zero-dependency JavaScript SDK for HeedKit. Works in any browser, with any framework, or none at all.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
### npm
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm i @heedkit/sdk-js
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { mount } from "@heedkit/sdk-js";
|
|
15
|
+
|
|
16
|
+
mount({
|
|
17
|
+
projectKey: "fh_xxx",
|
|
18
|
+
user: { externalId: "user-123", email: "you@app.com" },
|
|
19
|
+
});
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### `<script>` tag (no build step)
|
|
23
|
+
|
|
24
|
+
```html
|
|
25
|
+
<script src="https://cdn.jsdelivr.net/npm/@heedkit/sdk-js/dist/heedkit.iife.js"></script>
|
|
26
|
+
<script>
|
|
27
|
+
HeedKit.mount({
|
|
28
|
+
projectKey: "fh_xxx",
|
|
29
|
+
user: { externalId: "user-123" },
|
|
30
|
+
});
|
|
31
|
+
</script>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
That's it — a floating "Feedback" button appears in the bottom-right and opens a themed panel.
|
|
35
|
+
|
|
36
|
+
## Options
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
mount({
|
|
40
|
+
projectKey: "fh_xxx", // required
|
|
41
|
+
apiUrl: "https://...", // optional, defaults to cloud
|
|
42
|
+
user: { externalId, email, name, avatarUrl, platform },
|
|
43
|
+
label: "Send feedback", // launcher button label
|
|
44
|
+
hideLauncher: false, // hide the FAB and call widget.open() yourself
|
|
45
|
+
container: document.body, // where to mount the launcher
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Manual control
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
const widget = mount({ projectKey: "fh_xxx", hideLauncher: true });
|
|
53
|
+
|
|
54
|
+
document.querySelector("#my-button")!.addEventListener("click", () => {
|
|
55
|
+
widget.open();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// Programmatic access:
|
|
59
|
+
const features = await widget.client.list({ sort: "top" });
|
|
60
|
+
await widget.client.vote(featureId);
|
|
61
|
+
await widget.client.submit({ title: "Dark mode", description: "..." });
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Headless (no built-in UI)
|
|
65
|
+
|
|
66
|
+
If you want to use the API client without the widget UI:
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
import { HeedKitClient } from "@heedkit/sdk-js";
|
|
70
|
+
|
|
71
|
+
const client = new HeedKitClient({ projectKey: "fh_xxx" });
|
|
72
|
+
await client.init({ externalId: "user-123" });
|
|
73
|
+
const features = await client.list();
|
|
74
|
+
```
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";var HeedKit=(()=>{var z=Object.defineProperty;var ne=Object.getOwnPropertyDescriptor;var re=Object.getOwnPropertyNames;var ae=Object.prototype.hasOwnProperty;var ie=(t,e)=>{for(var a in e)z(t,a,{get:e[a],enumerable:!0})},oe=(t,e,a,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of re(e))!ae.call(t,n)&&n!==a&&z(t,n,{get:()=>e[n],enumerable:!(o=ne(e,n))||o.enumerable});return t};var se=t=>oe(z({},"__esModule",{value:!0}),t);var he={};ie(he,{HeedKitClient:()=>C,mount:()=>J});var de="https://api.heedkit.com",q="heedkit.device_id";function le(){var t,e;try{if(typeof window=="undefined"||!window.localStorage)return null;let a=window.localStorage.getItem(q);if(a)return a;let o="dev_"+((e=(t=crypto==null?void 0:crypto.randomUUID)==null?void 0:t.call(crypto))!=null?e:Math.random().toString(36).slice(2));return window.localStorage.setItem(q,o),o}catch(a){return null}}function V(t){var e,a,o,n,s,p,h,u;return{id:String(t.id),title:t.title,description:(e=t.description)!=null?e:"",status:t.status,kind:t.kind,visibility:t.visibility,on_roadmap:(a=t.on_roadmap)!=null?a:!1,tag:(o=t.tag)!=null?o:null,vote_count:(n=t.vote_count)!=null?n:0,voted:(s=t.voted)!=null?s:!1,platform:(p=t.platform)!=null?p:null,author_name:(u=(h=t.author_name)!=null?h:t.author)!=null?u:null,created_at:t.created_at}}function $(t){var e,a,o;return{id:String(t.id),body:t.body,author_name:(a=(e=t.author_name)!=null?e:t.author)!=null?a:null,is_internal:(o=t.is_internal)!=null?o:!1,created_at:t.created_at}}var C=class{constructor(e){this.endUserId=null;this.theme={};this.projectName="";this.enabledKinds=[];this.kindVisibility={};this.kindInteractions={};this.apiUrl=e.apiUrl||de,this.projectKey=e.projectKey}async init(e={}){var p,h,u,k,v;let o={external_id:(h=(p=e.externalId)!=null?p:le())!=null?h:void 0,email:e.email,name:e.name,avatar_url:e.avatarUrl,platform:e.platform||"web"},n=await this.request("/sdk/init","POST",o);this.endUserId=n.end_user_id;let s=(u=n.project)!=null?u:n;return this.theme=s.theme||{},this.projectName=(v=(k=s.name)!=null?k:s.project_name)!=null?v:"",this.enabledKinds=s.enabled_kinds||[],this.kindVisibility=s.kind_visibility||{},this.kindInteractions=s.kind_interactions||{},n}getTheme(){return this.theme}getEnabledKinds(){return this.enabledKinds}getKindVisibility(){return this.kindVisibility}getKindInteractions(){return this.kindInteractions}getProjectName(){return this.projectName}getEndUserId(){return this.endUserId}getInteractionsFor(e){let a=this.kindInteractions[e]||{};return["upvote","downvote","plus_one","like"].filter(o=>a[o])}async list(e={}){var s;this.ensureInit();let a=new URLSearchParams({end_user_id:this.endUserId});e.status&&a.set("status",e.status),e.kind&&a.set("kind",e.kind),e.sort&&a.set("sort",e.sort);let o=await this.request(`/sdk/features?${a}`,"GET");return(Array.isArray(o)?o:(s=o.features)!=null?s:[]).map(p=>V(p))}async submit(e){this.ensureInit();let a=await this.request("/sdk/features","POST",{end_user_id:this.endUserId,title:e.title,description:e.description||"",tag:e.tag||null,kind:e.kind||"feature_request"});return V(a)}async vote(e){return this.ensureInit(),this.request(`/sdk/features/${e}/vote`,"POST",{end_user_id:this.endUserId})}async listComments(e){var n;let a=await this.request(`/sdk/features/${e}/comments`,"GET");return(Array.isArray(a)?a:(n=a.comments)!=null?n:[]).map(s=>$(s))}async comment(e,a){this.ensureInit();let o=await this.request(`/sdk/features/${e}/comments`,"POST",{end_user_id:this.endUserId,body:a});return $(o)}ensureInit(){if(!this.endUserId)throw new Error("HeedKit not initialized \u2014 call init() first")}async request(e,a,o){let n=await fetch(`${this.apiUrl}${e}`,{method:a,headers:{"Content-Type":"application/json","X-Project-Key":this.projectKey},body:o?JSON.stringify(o):void 0});if(!n.ok){let s=`HTTP ${n.status}`;try{let p=await n.json();s=p.error||p.detail||s}catch(p){}throw new Error(s)}return n.json()}};var U={feature_request:{label:"Features",placeholder:"What should we build?",tabIcon:"\u{1F4A1}"},bug_report:{label:"Bugs",placeholder:"What's broken?",tabIcon:"\u{1F41E}"},improvement:{label:"Improvements",placeholder:"What could be better?",tabIcon:"\u2728"},appreciation:{label:"Appreciation",placeholder:"What did you love?",tabIcon:"\u2764\uFE0F"},other:{label:"Other",placeholder:"Tell us anything",tabIcon:"\u{1F4AC}"}},ce={upvote:{icon:"\u25B2",label:"Upvote"},downvote:{icon:"\u25BC",label:"Downvote"},plus_one:{icon:"+1",label:"+1"},like:{icon:"\u2665",label:"Like"}},W={sm:"13px",md:"14px",lg:"16px"},G="heedkit-styles",pe=`
|
|
2
|
+
.fk-launcher {
|
|
3
|
+
position: fixed; bottom: 24px; right: 24px; z-index: 2147483645;
|
|
4
|
+
background: var(--fh-primary); color: #fff; border: 0; border-radius: 999px;
|
|
5
|
+
padding: 12px 18px; font-weight: 600; font-size: var(--fh-fs); cursor: pointer;
|
|
6
|
+
box-shadow: 0 10px 24px rgba(0,0,0,.18); font-family: var(--fh-font);
|
|
7
|
+
transition: transform .15s ease;
|
|
8
|
+
}
|
|
9
|
+
.fk-launcher:hover { transform: translateY(-1px); }
|
|
10
|
+
.fk-overlay {
|
|
11
|
+
position: fixed; inset: 0; z-index: 2147483646; display: flex;
|
|
12
|
+
align-items: center; justify-content: center; padding: 16px;
|
|
13
|
+
background: rgba(0,0,0,.45); backdrop-filter: blur(2px);
|
|
14
|
+
font-family: var(--fh-font); font-size: var(--fh-fs);
|
|
15
|
+
}
|
|
16
|
+
.fk-panel {
|
|
17
|
+
width: 100%; max-width: 520px; max-height: 85vh; display: flex; flex-direction: column;
|
|
18
|
+
background: var(--fh-bg); color: var(--fh-fg);
|
|
19
|
+
border-radius: calc(var(--fh-radius) * 1.5); overflow: hidden;
|
|
20
|
+
box-shadow: 0 20px 60px rgba(0,0,0,.3);
|
|
21
|
+
}
|
|
22
|
+
.fk-head { padding: 18px 20px 12px; border-bottom: 1px solid var(--fh-border); }
|
|
23
|
+
.fk-titlerow { display:flex; justify-content:space-between; align-items:center; }
|
|
24
|
+
.fk-title { font-size: calc(var(--fh-fs) + 6px); font-weight: 700; }
|
|
25
|
+
.fk-close {
|
|
26
|
+
background: transparent; border: 0; color: var(--fh-muted);
|
|
27
|
+
font-size: 22px; cursor: pointer; line-height: 1; padding: 0 4px;
|
|
28
|
+
}
|
|
29
|
+
.fk-modes { display:flex; gap: 6px; margin-top: 12px; }
|
|
30
|
+
.fk-mode {
|
|
31
|
+
border: 0; background: transparent; padding: 6px 12px; border-radius: 999px;
|
|
32
|
+
font-size: calc(var(--fh-fs) - 1px); font-weight: 600; cursor: pointer;
|
|
33
|
+
color: var(--fh-muted); font-family: inherit;
|
|
34
|
+
}
|
|
35
|
+
.fk-mode[data-active="true"] { background: var(--fh-primary); color: #fff; }
|
|
36
|
+
.fk-tabs {
|
|
37
|
+
display: flex; flex-wrap: wrap; gap: 6px; padding: 10px 20px; border-bottom: 1px solid var(--fh-border);
|
|
38
|
+
}
|
|
39
|
+
.fk-tab {
|
|
40
|
+
border: 0; background: var(--fh-row); color: var(--fh-fg);
|
|
41
|
+
padding: 6px 12px; border-radius: 999px;
|
|
42
|
+
font-size: calc(var(--fh-fs) - 1px); font-weight: 500; cursor: pointer; font-family: inherit;
|
|
43
|
+
display: inline-flex; align-items: center; gap: 6px;
|
|
44
|
+
}
|
|
45
|
+
.fk-tab[data-active="true"] { background: var(--fh-primary); color: #fff; }
|
|
46
|
+
.fk-body { flex: 1; overflow-y: auto; padding: 16px 20px; }
|
|
47
|
+
.fk-empty { text-align: center; padding: 32px; opacity: .6; }
|
|
48
|
+
.fk-loading { text-align: center; padding: 32px; opacity: .6; }
|
|
49
|
+
.fk-row {
|
|
50
|
+
display: flex; gap: 12px; padding: 12px; margin-bottom: 8px;
|
|
51
|
+
background: var(--fh-row); border-radius: var(--fh-radius);
|
|
52
|
+
}
|
|
53
|
+
.fk-actions { display:flex; flex-direction: column; gap: 4px; }
|
|
54
|
+
.fk-act {
|
|
55
|
+
border: 1px solid var(--fh-border); background: transparent;
|
|
56
|
+
color: var(--fh-fg); border-radius: calc(var(--fh-radius) - 4px);
|
|
57
|
+
min-width: 44px; padding: 6px 8px; cursor: pointer;
|
|
58
|
+
display: flex; flex-direction: column; align-items: center; gap: 2px;
|
|
59
|
+
font-weight: 600; font-size: calc(var(--fh-fs) - 1px); font-family: inherit;
|
|
60
|
+
}
|
|
61
|
+
.fk-act[data-voted="true"] {
|
|
62
|
+
border: 2px solid var(--fh-primary);
|
|
63
|
+
background: color-mix(in srgb, var(--fh-primary) 14%, transparent);
|
|
64
|
+
color: var(--fh-primary);
|
|
65
|
+
}
|
|
66
|
+
.fk-act[disabled] { cursor: default; opacity: .85; }
|
|
67
|
+
.fk-act .fk-glyph { font-size: calc(var(--fh-fs) + 1px); line-height: 1; }
|
|
68
|
+
.fk-meta { flex:1; min-width:0; cursor: pointer; }
|
|
69
|
+
.fk-item-title { font-weight: 600; }
|
|
70
|
+
.fk-item-desc { opacity: .7; font-size: calc(var(--fh-fs) - 1px); margin-top: 4px; }
|
|
71
|
+
.fk-item-badges { display:flex; gap:6px; margin-top:6px; flex-wrap: wrap; }
|
|
72
|
+
.fk-badge {
|
|
73
|
+
font-size: calc(var(--fh-fs) - 3px); padding: 2px 8px; border-radius: 999px;
|
|
74
|
+
background: var(--fh-border); color: var(--fh-muted); text-transform: uppercase; letter-spacing: .04em;
|
|
75
|
+
}
|
|
76
|
+
.fk-badge[data-status="planned"] { background: rgba(59,130,246,.15); color: rgb(37,99,235); }
|
|
77
|
+
.fk-badge[data-status="in_progress"] { background: rgba(234,179,8,.18); color: rgb(161,98,7); }
|
|
78
|
+
.fk-badge[data-status="shipped"] { background: rgba(34,197,94,.18); color: rgb(22,101,52); }
|
|
79
|
+
.fk-comments { margin-top: 10px; border-top: 1px solid var(--fh-border); padding-top: 10px; }
|
|
80
|
+
.fk-comment { padding: 6px 0; border-top: 1px dashed var(--fh-border); font-size: calc(var(--fh-fs) - 1px); }
|
|
81
|
+
.fk-comment:first-child { border-top: 0; }
|
|
82
|
+
.fk-comment-author { font-weight: 600; }
|
|
83
|
+
.fk-form { display: flex; flex-direction: column; gap: 12px; }
|
|
84
|
+
.fk-label { font-size: calc(var(--fh-fs) - 1px); font-weight: 500; }
|
|
85
|
+
.fk-input, .fk-textarea {
|
|
86
|
+
width: 100%; padding: 10px 12px; margin-top: 4px;
|
|
87
|
+
border-radius: calc(var(--fh-radius) - 2px);
|
|
88
|
+
border: 1px solid var(--fh-input-border); background: var(--fh-input-bg);
|
|
89
|
+
color: var(--fh-fg); font-size: var(--fh-fs); font-family: inherit;
|
|
90
|
+
box-sizing: border-box;
|
|
91
|
+
}
|
|
92
|
+
.fk-textarea { resize: vertical; min-height: 96px; }
|
|
93
|
+
.fk-input:focus, .fk-textarea:focus { outline: 2px solid var(--fh-primary); outline-offset: 1px; }
|
|
94
|
+
.fk-submit {
|
|
95
|
+
background: var(--fh-primary); color: #fff; border: 0;
|
|
96
|
+
padding: 12px 14px; border-radius: var(--fh-radius);
|
|
97
|
+
font-weight: 600; font-size: var(--fh-fs); cursor: pointer; font-family: inherit;
|
|
98
|
+
}
|
|
99
|
+
.fk-submit[disabled] { opacity: .6; cursor: not-allowed; }
|
|
100
|
+
.fk-segmented {
|
|
101
|
+
display: inline-flex; gap: 4px; padding: 4px; margin-top: 6px;
|
|
102
|
+
background: var(--fh-row); border-radius: 999px;
|
|
103
|
+
}
|
|
104
|
+
.fk-seg {
|
|
105
|
+
border: 0; background: transparent; cursor: pointer;
|
|
106
|
+
padding: 6px 12px; border-radius: 999px; font-size: calc(var(--fh-fs) - 2px);
|
|
107
|
+
font-weight: 500; color: var(--fh-muted); font-family: inherit;
|
|
108
|
+
}
|
|
109
|
+
.fk-seg[data-active="true"] {
|
|
110
|
+
background: var(--fh-bg); color: var(--fh-fg);
|
|
111
|
+
box-shadow: 0 1px 2px rgba(0,0,0,.06), 0 2px 8px rgba(0,0,0,.04);
|
|
112
|
+
}
|
|
113
|
+
.fk-error { color: rgb(220,38,38); font-size: calc(var(--fh-fs) - 1px); }
|
|
114
|
+
`;function ue(){if(document.getElementById(G))return;let t=document.createElement("style");t.id=G,t.textContent=pe,document.head.appendChild(t)}function fe(t){let e=t.mode||"light";return e==="system"?typeof window!="undefined"&&window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":e==="dark"?"dark":"light"}function Y(t,e){var u,k,v;let a=e.primary||"#0D9488",o=`${(u=e.radius)!=null?u:12}px`,n=fe(e)==="dark",s=e.font_family||e.fontFamily||"system-ui, -apple-system, sans-serif",p=(v=W[(k=e.font_size)!=null?k:"md"])!=null?v:W.md,h={"--fh-primary":a,"--fh-radius":o,"--fh-font":s,"--fh-fs":p,"--fh-bg":n?"#0F172A":"#FFFFFF","--fh-fg":n?"#F1F5F9":"#0F172A","--fh-muted":n?"#94A3B8":"#64748B","--fh-row":n?"#1E293B":"#F8FAFC","--fh-border":n?"#1E293B":"#E2E8F0","--fh-input-bg":n?"#0F172A":"#FFFFFF","--fh-input-border":n?"#334155":"#CBD5E1"};for(let[T,F]of Object.entries(h))t.style.setProperty(T,F)}function r(t,e,a){let o=document.createElement(t);if(e)for(let[n,s]of Object.entries(e))n==="class"?o.className=s:o.setAttribute(n,s);if(a)for(let n of a)n!=null&&o.appendChild(typeof n=="string"?document.createTextNode(n):n);return o}function J(t){ue();let e=t.container||document.body,a=new C(t),o=a.init(t.user||{}).catch(u=>(console.warn("[HeedKit] widget init failed; launcher disabled.",u),null)),n=null,s=null;function p(){n&&(n.remove(),n=null)}async function h(){await o&&(n||(n=me(a,a.getTheme(),p),e.appendChild(n)))}return t.hideLauncher||o.then(u=>{u&&(s=r("button",{class:"fk-launcher",type:"button"},[t.label||"Feedback"]),Y(s,a.getTheme()),s.addEventListener("click",h),e.appendChild(s))}),{client:a,open:h,close:p,destroy(){p(),s==null||s.remove()}}}function me(t,e,a){let o=r("div",{class:"fk-overlay",role:"dialog"});Y(o,e),o.addEventListener("click",i=>{i.target===o&&a()});let n=r("div",{class:"fk-panel"});o.appendChild(n);let s=t.getEnabledKinds(),p=e.group_mode||"tabs",h="browse",u=p==="tabs"&&s.length>0?s[0]:"all",k=[],v=r("div",{class:"fk-head"}),T=r("div",{class:"fk-titlerow"});T.appendChild(r("div",{class:"fk-title"},[t.getProjectName()||"Feedback"]));let F=r("button",{class:"fk-close",type:"button","aria-label":"Close"},["\xD7"]);F.addEventListener("click",a),T.appendChild(F),v.appendChild(T);let B=r("div",{class:"fk-modes"}),M=r("button",{class:"fk-mode",type:"button"},["Browse"]),H=r("button",{class:"fk-mode",type:"button"},["Suggest"]);B.append(M,H),v.appendChild(B),n.appendChild(v);let y=null;if(p==="tabs"&&s.length>0){y=r("div",{class:"fk-tabs"});let i=r("button",{class:"fk-tab",type:"button"},["All"]);i.dataset.kind="all",y.appendChild(i);for(let f of s){let d=U[f],l=r("button",{class:"fk-tab",type:"button"},[r("span",{},[d.tabIcon]),r("span",{},[d.label])]);l.dataset.kind=f,y.appendChild(l)}n.appendChild(y),y.addEventListener("click",f=>{let d=f.target.closest("[data-kind]");d&&(u=d.dataset.kind,S(),A())})}let x=r("div",{class:"fk-body"});n.appendChild(x);function R(){M.setAttribute("data-active",String(h==="browse")),H.setAttribute("data-active",String(h==="suggest")),y&&(y.style.display=h==="browse"?"":"none")}function S(){if(y)for(let i of Array.from(y.children))i.setAttribute("data-active",String(i.dataset.kind===String(u)))}async function A(){x.replaceChildren(r("div",{class:"fk-loading"},["Loading\u2026"]));try{let i={sort:"top"};u!=="all"&&(i.kind=u),k=await t.list(i)}catch(i){x.replaceChildren(r("div",{class:"fk-empty"},[`Failed to load: ${i.message}`]));return}N()}async function X(i,f){let d=await t.vote(i.id);i.voted=d.voted,i.vote_count=d.vote_count,N()}function Z(i){let f=t.getInteractionsFor(i.kind),d=(t.getTheme().show_counts||{})[i.kind]!==!1,l=r("div",{class:"fk-actions"});if(f.length===0){if(d){let c=r("button",{class:"fk-act",type:"button",disabled:"true"},[r("span",{},[String(i.vote_count)])]);l.appendChild(c)}return l}for(let c of f){let m=ce[c],g=r("button",{class:"fk-act",type:"button","aria-label":m.label},[r("span",{class:"fk-glyph"},[m.icon]),...d?[r("span",{},[String(i.vote_count)])]:[]]);(c==="upvote"||c==="like"||c==="plus_one")&&g.setAttribute("data-voted",String(i.voted)),g.addEventListener("click",b=>{b.stopPropagation(),X(i,c)}),l.appendChild(g)}return l}function N(){if(x.innerHTML="",k.length===0){x.appendChild(r("div",{class:"fk-empty"},["No items yet \u2014 be the first!"]));return}for(let i of k)x.appendChild(Q(i))}function Q(i){let f=r("div",{class:"fk-row"});f.appendChild(Z(i));let d=r("div",{class:"fk-meta"});d.appendChild(r("div",{class:"fk-item-title"},[i.title])),i.description&&d.appendChild(r("div",{class:"fk-item-desc"},[i.description]));let l=r("div",{class:"fk-item-badges"});if(i.status&&i.status!=="open"){let g=r("span",{class:"fk-badge"},[i.status.replace("_"," ")]);g.setAttribute("data-status",i.status),l.appendChild(g)}i.tag&&l.appendChild(r("span",{class:"fk-badge"},[i.tag])),l.children.length&&d.appendChild(l);let c=!1,m=r("div",{class:"fk-comments"});return m.style.display="none",d.appendChild(m),d.addEventListener("click",async()=>{let g=m.style.display==="none";if(m.style.display=g?"":"none",g&&!c){c=!0,m.replaceChildren(r("div",{class:"fk-loading"},["Loading\u2026"]));try{let b=await t.listComments(i.id);m.replaceChildren(...O(i,b))}catch(b){m.replaceChildren(r("div",{class:"fk-error"},[b.message]))}}}),f.appendChild(d),f}function O(i,f){let d=[];if(f.length===0)d.push(r("div",{class:"fk-empty"},["No replies yet."]));else for(let m of f)d.push(r("div",{class:"fk-comment"},[r("span",{class:"fk-comment-author"},[m.author_name||"Anonymous"])," \u2014 ",m.body]));let l=r("textarea",{class:"fk-textarea",placeholder:"Add a reply\u2026",rows:"2"}),c=r("button",{class:"fk-submit",type:"button"},["Reply"]);return c.addEventListener("click",async m=>{var g;if(m.stopPropagation(),!!l.value.trim()){c.disabled=!0;try{let b=await t.comment(i.id,l.value);l.value="",c.disabled=!1;let K=await t.listComments(i.id),w=(g=c.parentElement)==null?void 0:g.parentElement;w&&w.replaceChildren(...O(i,K))}catch(b){c.disabled=!1,alert(b.message)}}}),d.push(r("div",{},[l,c])),d}function ee(){x.innerHTML="";let f=t.getEnabledKinds().map(E=>({value:E,...U[E]})),d=f.length>0?f:[{value:"other",...U.other}],l=d[0].value,c=r("form",{class:"fk-form"}),m=r("label",{class:"fk-label"},["What's this about?"]),g=r("div",{class:"fk-segmented"}),b=[];for(let E of d){let _=r("button",{class:"fk-seg",type:"button"},[E.label]);_.setAttribute("data-active",String(E.value===l)),_.addEventListener("click",()=>{l=E.value,b.forEach((j,te)=>j.setAttribute("data-active",String(d[te].value===l))),w.placeholder=d.find(j=>j.value===l).placeholder}),b.push(_),g.appendChild(_)}m.appendChild(g);let K=r("label",{class:"fk-label"},["Title"]),w=r("input",{class:"fk-input",type:"text",placeholder:d[0].placeholder,required:"true"});K.appendChild(w);let D=r("label",{class:"fk-label"},["Description"]),P=r("textarea",{class:"fk-textarea",placeholder:"Any extra context helps.",rows:"4"});D.appendChild(P);let I=r("button",{class:"fk-submit",type:"submit"},["Submit"]);c.append(m,K,D,I),x.appendChild(c),c.addEventListener("submit",async E=>{if(E.preventDefault(),!!w.value.trim()){I.disabled=!0,I.textContent="Submitting\u2026";try{await t.submit({title:w.value,description:P.value,kind:l}),w.value="",P.value="",L("browse"),y&&(u=l,S()),await A()}catch(_){I.disabled=!1,I.textContent="Submit",alert(_.message)}}})}function L(i){h=i,R(),h==="browse"?A():ee()}return M.addEventListener("click",()=>L("browse")),H.addEventListener("click",()=>L("suggest")),R(),S(),L("browse"),o}return se(he);})();
|
|
115
|
+
//# sourceMappingURL=heedkit.iife.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/client.ts","../src/widget.ts"],"sourcesContent":["export { HeedKitClient } from \"./client\";\nexport type {\n Comment,\n EndUser,\n Feature,\n FeatureKind,\n HeedKitConfig,\n GroupMode,\n InitResult,\n Interaction,\n KindInteractions,\n ShowCounts,\n Theme,\n Visibility,\n} from \"./client\";\n\nexport { mount, type MountOptions, type Widget } from \"./widget\";\n","export type Visibility = \"public\" | \"private\";\n\nexport type Interaction = \"upvote\" | \"downvote\" | \"plus_one\" | \"like\";\n\nexport type KindInteractions = Partial<Record<Interaction, boolean>>;\n\nexport type ShowCounts = Partial<Record<FeatureKind, boolean>>;\n\nexport type GroupMode = \"tabs\" | \"list\";\n\nexport type Theme = {\n primary?: string;\n primaryDark?: string;\n radius?: number;\n /// `\"system\"` follows the OS color scheme at render time.\n mode?: \"light\" | \"dark\" | \"system\";\n font_family?: string;\n font_size?: \"sm\" | \"md\" | \"lg\";\n group_mode?: GroupMode;\n show_counts?: ShowCounts;\n // Older deployments may still send camelCase keys for these — kept for backcompat.\n fontFamily?: string;\n};\n\nexport type EndUser = {\n externalId?: string;\n email?: string;\n name?: string;\n avatarUrl?: string;\n platform?: string;\n};\n\nexport type FeatureKind =\n | \"feature_request\"\n | \"bug_report\"\n | \"improvement\"\n | \"appreciation\"\n | \"other\";\n\nexport type Feature = {\n id: string;\n title: string;\n description: string;\n status: \"open\" | \"planned\" | \"in_progress\" | \"shipped\" | \"declined\";\n kind: FeatureKind;\n /// Whether the item is visible beyond its author + the project team.\n visibility: Visibility;\n /// Whether the item appears on the project's roadmap (public if visibility=public).\n on_roadmap: boolean;\n tag: string | null;\n vote_count: number;\n voted: boolean;\n platform: string | null;\n author_name: string | null;\n created_at: string;\n};\n\nexport type Comment = {\n id: string;\n body: string;\n author_name: string | null;\n is_internal: boolean;\n created_at: string;\n};\n\nexport type HeedKitConfig = {\n projectKey: string;\n apiUrl?: string;\n user?: EndUser;\n};\n\n/// Project configuration returned by /sdk/init (nested under `project`).\nexport type ProjectConfig = {\n name: string;\n theme: Theme;\n enabled_kinds: FeatureKind[];\n /// Default visibility applied to new submissions of each kind.\n kind_visibility: Record<FeatureKind, Visibility>;\n /// Which interactions admin has enabled per kind. The widget should only render\n /// the affordances listed here.\n kind_interactions: Record<FeatureKind, KindInteractions>;\n is_public_roadmap?: boolean;\n};\n\nexport type InitResult = {\n end_user_id: string;\n project: ProjectConfig;\n};\n\nconst DEFAULT_API = \"https://api.heedkit.com\";\nconst DEVICE_ID_KEY = \"heedkit.device_id\";\n\n/**\n * Stable per-browser identifier persisted in localStorage. When the customer\n * doesn't pass `externalId`, we still want votes/submissions to stick to the\n * same EndUser across page loads — otherwise every refresh would create a new\n * anonymous account.\n *\n * Returns null on the server (SSR), so callers should fall back to a fresh id.\n */\nexport function getOrCreateDeviceId(): string | null {\n try {\n if (typeof window === \"undefined\" || !window.localStorage) return null;\n const existing = window.localStorage.getItem(DEVICE_ID_KEY);\n if (existing) return existing;\n const next = \"dev_\" + (crypto?.randomUUID?.() ?? Math.random().toString(36).slice(2));\n window.localStorage.setItem(DEVICE_ID_KEY, next);\n return next;\n } catch {\n // Privacy mode / disabled storage — caller falls back to anonymous.\n return null;\n }\n}\n\n/// Map a raw API feature onto the SDK shape (the backend compacts null fields and\n/// exposes the author display name as `author`).\nfunction normalizeFeature(f: any): Feature {\n return {\n id: String(f.id),\n title: f.title,\n description: f.description ?? \"\",\n status: f.status,\n kind: f.kind,\n visibility: f.visibility,\n on_roadmap: f.on_roadmap ?? false,\n tag: f.tag ?? null,\n vote_count: f.vote_count ?? 0,\n voted: f.voted ?? false,\n platform: f.platform ?? null,\n author_name: f.author_name ?? f.author ?? null,\n created_at: f.created_at,\n };\n}\n\nfunction normalizeComment(c: any): Comment {\n return {\n id: String(c.id),\n body: c.body,\n author_name: c.author_name ?? c.author ?? null,\n // The SDK endpoint only ever returns public comments.\n is_internal: c.is_internal ?? false,\n created_at: c.created_at,\n };\n}\n\nexport class HeedKitClient {\n private apiUrl: string;\n private projectKey: string;\n private endUserId: string | null = null;\n private theme: Theme = {};\n private projectName = \"\";\n private enabledKinds: FeatureKind[] = [];\n private kindVisibility: Partial<Record<FeatureKind, Visibility>> = {};\n private kindInteractions: Partial<Record<FeatureKind, KindInteractions>> = {};\n\n constructor(config: HeedKitConfig) {\n this.apiUrl = config.apiUrl || DEFAULT_API;\n this.projectKey = config.projectKey;\n }\n\n async init(user: EndUser = {}): Promise<InitResult> {\n // If the caller didn't pass an external_id, fall back to a stable\n // per-browser device id so refreshes keep the same EndUser.\n const externalId = user.externalId ?? getOrCreateDeviceId() ?? undefined;\n const body = {\n external_id: externalId,\n email: user.email,\n name: user.name,\n avatar_url: user.avatarUrl,\n platform: user.platform || \"web\",\n };\n const res = await this.request<InitResult>(\"/sdk/init\", \"POST\", body);\n this.endUserId = res.end_user_id;\n // The Rails backend nests project config under `project`; tolerate a flat\n // response from older deployments too.\n const p: any = (res as any).project ?? res;\n this.theme = p.theme || {};\n this.projectName = p.name ?? p.project_name ?? \"\";\n this.enabledKinds = p.enabled_kinds || [];\n this.kindVisibility = p.kind_visibility || {};\n this.kindInteractions = p.kind_interactions || {};\n return res;\n }\n\n getTheme() { return this.theme; }\n getEnabledKinds(): FeatureKind[] { return this.enabledKinds; }\n getKindVisibility() { return this.kindVisibility; }\n getKindInteractions() { return this.kindInteractions; }\n getProjectName() { return this.projectName; }\n getEndUserId() { return this.endUserId; }\n\n /// Convenience: which interactions are enabled for a given kind, in stable order.\n getInteractionsFor(kind: FeatureKind): Interaction[] {\n const row = this.kindInteractions[kind] || {};\n return ([\"upvote\", \"downvote\", \"plus_one\", \"like\"] as Interaction[]).filter(\n (i) => row[i]\n );\n }\n\n async list(\n opts: { status?: string; kind?: FeatureKind; sort?: \"top\" | \"new\" } = {}\n ): Promise<Feature[]> {\n this.ensureInit();\n const params = new URLSearchParams({ end_user_id: this.endUserId! });\n if (opts.status) params.set(\"status\", opts.status);\n if (opts.kind) params.set(\"kind\", opts.kind);\n if (opts.sort) params.set(\"sort\", opts.sort);\n // Rails returns { features, next_cursor }; tolerate a bare array too.\n const res = await this.request<any>(`/sdk/features?${params}`, \"GET\");\n const features = Array.isArray(res) ? res : (res.features ?? []);\n return features.map((f: any) => normalizeFeature(f));\n }\n\n async submit(input: {\n title: string;\n description?: string;\n tag?: string;\n kind?: FeatureKind;\n }): Promise<Feature> {\n this.ensureInit();\n const res = await this.request<any>(\"/sdk/features\", \"POST\", {\n end_user_id: this.endUserId,\n title: input.title,\n description: input.description || \"\",\n tag: input.tag || null,\n kind: input.kind || \"feature_request\",\n });\n return normalizeFeature(res);\n }\n\n async vote(featureId: string): Promise<{ voted: boolean; vote_count: number }> {\n this.ensureInit();\n return this.request(`/sdk/features/${featureId}/vote`, \"POST\", {\n end_user_id: this.endUserId,\n });\n }\n\n async listComments(featureId: string): Promise<Comment[]> {\n const res = await this.request<any>(`/sdk/features/${featureId}/comments`, \"GET\");\n const comments = Array.isArray(res) ? res : (res.comments ?? []);\n return comments.map((c: any) => normalizeComment(c));\n }\n\n async comment(featureId: string, body: string): Promise<Comment> {\n this.ensureInit();\n const res = await this.request<any>(`/sdk/features/${featureId}/comments`, \"POST\", {\n end_user_id: this.endUserId,\n body,\n });\n return normalizeComment(res);\n }\n\n private ensureInit() {\n if (!this.endUserId) throw new Error(\"HeedKit not initialized — call init() first\");\n }\n\n private async request<T>(path: string, method: string, body?: unknown): Promise<T> {\n const res = await fetch(`${this.apiUrl}${path}`, {\n method,\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Project-Key\": this.projectKey,\n },\n body: body ? JSON.stringify(body) : undefined,\n });\n if (!res.ok) {\n let detail = `HTTP ${res.status}`;\n try {\n const j = await res.json();\n detail = j.error || j.detail || detail; // Rails uses `error`; legacy used `detail`.\n } catch { /* non-JSON body */ }\n throw new Error(detail);\n }\n return res.json() as Promise<T>;\n }\n}\n","import {\n HeedKitClient,\n type Comment,\n type Feature,\n type FeatureKind,\n type HeedKitConfig,\n type InitResult,\n type Interaction,\n type Theme,\n} from \"./client\";\n\n// ---------------------------------------------------------------------------\n// Configuration tables\n// ---------------------------------------------------------------------------\n\nconst KIND_OPTIONS: Record<FeatureKind, { label: string; placeholder: string; tabIcon: string }> = {\n feature_request: { label: \"Features\", placeholder: \"What should we build?\", tabIcon: \"💡\" },\n bug_report: { label: \"Bugs\", placeholder: \"What's broken?\", tabIcon: \"🐞\" },\n improvement: { label: \"Improvements\", placeholder: \"What could be better?\", tabIcon: \"✨\" },\n appreciation: { label: \"Appreciation\", placeholder: \"What did you love?\", tabIcon: \"❤️\" },\n other: { label: \"Other\", placeholder: \"Tell us anything\", tabIcon: \"💬\" },\n};\n\n// Icons + a11y labels per interaction. We render only those the admin enabled.\nconst INTERACTION_META: Record<Interaction, { icon: string; label: string }> = {\n upvote: { icon: \"▲\", label: \"Upvote\" },\n downvote: { icon: \"▼\", label: \"Downvote\" },\n plus_one: { icon: \"+1\", label: \"+1\" },\n like: { icon: \"♥\", label: \"Like\" },\n};\n\nconst FONT_SIZES = { sm: \"13px\", md: \"14px\", lg: \"16px\" } as const;\n\n// ---------------------------------------------------------------------------\n// Public surface\n// ---------------------------------------------------------------------------\n\nexport type MountOptions = HeedKitConfig & {\n label?: string;\n hideLauncher?: boolean;\n container?: HTMLElement;\n};\n\nexport type Widget = {\n client: HeedKitClient;\n open: () => void;\n close: () => void;\n destroy: () => void;\n};\n\n// ---------------------------------------------------------------------------\n// Style sheet (single inject; relies on CSS custom properties for theming)\n// ---------------------------------------------------------------------------\n\nconst STYLE_ID = \"heedkit-styles\";\n\nconst CSS = `\n.fk-launcher {\n position: fixed; bottom: 24px; right: 24px; z-index: 2147483645;\n background: var(--fh-primary); color: #fff; border: 0; border-radius: 999px;\n padding: 12px 18px; font-weight: 600; font-size: var(--fh-fs); cursor: pointer;\n box-shadow: 0 10px 24px rgba(0,0,0,.18); font-family: var(--fh-font);\n transition: transform .15s ease;\n}\n.fk-launcher:hover { transform: translateY(-1px); }\n.fk-overlay {\n position: fixed; inset: 0; z-index: 2147483646; display: flex;\n align-items: center; justify-content: center; padding: 16px;\n background: rgba(0,0,0,.45); backdrop-filter: blur(2px);\n font-family: var(--fh-font); font-size: var(--fh-fs);\n}\n.fk-panel {\n width: 100%; max-width: 520px; max-height: 85vh; display: flex; flex-direction: column;\n background: var(--fh-bg); color: var(--fh-fg);\n border-radius: calc(var(--fh-radius) * 1.5); overflow: hidden;\n box-shadow: 0 20px 60px rgba(0,0,0,.3);\n}\n.fk-head { padding: 18px 20px 12px; border-bottom: 1px solid var(--fh-border); }\n.fk-titlerow { display:flex; justify-content:space-between; align-items:center; }\n.fk-title { font-size: calc(var(--fh-fs) + 6px); font-weight: 700; }\n.fk-close {\n background: transparent; border: 0; color: var(--fh-muted);\n font-size: 22px; cursor: pointer; line-height: 1; padding: 0 4px;\n}\n.fk-modes { display:flex; gap: 6px; margin-top: 12px; }\n.fk-mode {\n border: 0; background: transparent; padding: 6px 12px; border-radius: 999px;\n font-size: calc(var(--fh-fs) - 1px); font-weight: 600; cursor: pointer;\n color: var(--fh-muted); font-family: inherit;\n}\n.fk-mode[data-active=\"true\"] { background: var(--fh-primary); color: #fff; }\n.fk-tabs {\n display: flex; flex-wrap: wrap; gap: 6px; padding: 10px 20px; border-bottom: 1px solid var(--fh-border);\n}\n.fk-tab {\n border: 0; background: var(--fh-row); color: var(--fh-fg);\n padding: 6px 12px; border-radius: 999px;\n font-size: calc(var(--fh-fs) - 1px); font-weight: 500; cursor: pointer; font-family: inherit;\n display: inline-flex; align-items: center; gap: 6px;\n}\n.fk-tab[data-active=\"true\"] { background: var(--fh-primary); color: #fff; }\n.fk-body { flex: 1; overflow-y: auto; padding: 16px 20px; }\n.fk-empty { text-align: center; padding: 32px; opacity: .6; }\n.fk-loading { text-align: center; padding: 32px; opacity: .6; }\n.fk-row {\n display: flex; gap: 12px; padding: 12px; margin-bottom: 8px;\n background: var(--fh-row); border-radius: var(--fh-radius);\n}\n.fk-actions { display:flex; flex-direction: column; gap: 4px; }\n.fk-act {\n border: 1px solid var(--fh-border); background: transparent;\n color: var(--fh-fg); border-radius: calc(var(--fh-radius) - 4px);\n min-width: 44px; padding: 6px 8px; cursor: pointer;\n display: flex; flex-direction: column; align-items: center; gap: 2px;\n font-weight: 600; font-size: calc(var(--fh-fs) - 1px); font-family: inherit;\n}\n.fk-act[data-voted=\"true\"] {\n border: 2px solid var(--fh-primary);\n background: color-mix(in srgb, var(--fh-primary) 14%, transparent);\n color: var(--fh-primary);\n}\n.fk-act[disabled] { cursor: default; opacity: .85; }\n.fk-act .fk-glyph { font-size: calc(var(--fh-fs) + 1px); line-height: 1; }\n.fk-meta { flex:1; min-width:0; cursor: pointer; }\n.fk-item-title { font-weight: 600; }\n.fk-item-desc { opacity: .7; font-size: calc(var(--fh-fs) - 1px); margin-top: 4px; }\n.fk-item-badges { display:flex; gap:6px; margin-top:6px; flex-wrap: wrap; }\n.fk-badge {\n font-size: calc(var(--fh-fs) - 3px); padding: 2px 8px; border-radius: 999px;\n background: var(--fh-border); color: var(--fh-muted); text-transform: uppercase; letter-spacing: .04em;\n}\n.fk-badge[data-status=\"planned\"] { background: rgba(59,130,246,.15); color: rgb(37,99,235); }\n.fk-badge[data-status=\"in_progress\"] { background: rgba(234,179,8,.18); color: rgb(161,98,7); }\n.fk-badge[data-status=\"shipped\"] { background: rgba(34,197,94,.18); color: rgb(22,101,52); }\n.fk-comments { margin-top: 10px; border-top: 1px solid var(--fh-border); padding-top: 10px; }\n.fk-comment { padding: 6px 0; border-top: 1px dashed var(--fh-border); font-size: calc(var(--fh-fs) - 1px); }\n.fk-comment:first-child { border-top: 0; }\n.fk-comment-author { font-weight: 600; }\n.fk-form { display: flex; flex-direction: column; gap: 12px; }\n.fk-label { font-size: calc(var(--fh-fs) - 1px); font-weight: 500; }\n.fk-input, .fk-textarea {\n width: 100%; padding: 10px 12px; margin-top: 4px;\n border-radius: calc(var(--fh-radius) - 2px);\n border: 1px solid var(--fh-input-border); background: var(--fh-input-bg);\n color: var(--fh-fg); font-size: var(--fh-fs); font-family: inherit;\n box-sizing: border-box;\n}\n.fk-textarea { resize: vertical; min-height: 96px; }\n.fk-input:focus, .fk-textarea:focus { outline: 2px solid var(--fh-primary); outline-offset: 1px; }\n.fk-submit {\n background: var(--fh-primary); color: #fff; border: 0;\n padding: 12px 14px; border-radius: var(--fh-radius);\n font-weight: 600; font-size: var(--fh-fs); cursor: pointer; font-family: inherit;\n}\n.fk-submit[disabled] { opacity: .6; cursor: not-allowed; }\n.fk-segmented {\n display: inline-flex; gap: 4px; padding: 4px; margin-top: 6px;\n background: var(--fh-row); border-radius: 999px;\n}\n.fk-seg {\n border: 0; background: transparent; cursor: pointer;\n padding: 6px 12px; border-radius: 999px; font-size: calc(var(--fh-fs) - 2px);\n font-weight: 500; color: var(--fh-muted); font-family: inherit;\n}\n.fk-seg[data-active=\"true\"] {\n background: var(--fh-bg); color: var(--fh-fg);\n box-shadow: 0 1px 2px rgba(0,0,0,.06), 0 2px 8px rgba(0,0,0,.04);\n}\n.fk-error { color: rgb(220,38,38); font-size: calc(var(--fh-fs) - 1px); }\n`;\n\nfunction injectStyles() {\n if (document.getElementById(STYLE_ID)) return;\n const style = document.createElement(\"style\");\n style.id = STYLE_ID;\n style.textContent = CSS;\n document.head.appendChild(style);\n}\n\n// Resolve \"system\" mode by reading the OS preference at render time. The theme\n// object is otherwise untouched.\nfunction effectiveMode(theme: Theme): \"light\" | \"dark\" {\n const m = theme.mode || \"light\";\n if (m === \"system\") {\n return typeof window !== \"undefined\" &&\n window.matchMedia &&\n window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n ? \"dark\"\n : \"light\";\n }\n return m === \"dark\" ? \"dark\" : \"light\";\n}\n\nfunction applyTheme(root: HTMLElement, theme: Theme) {\n const primary = theme.primary || \"#0D9488\";\n const radius = `${theme.radius ?? 12}px`;\n const dark = effectiveMode(theme) === \"dark\";\n const font = theme.font_family || theme.fontFamily || \"system-ui, -apple-system, sans-serif\";\n const fs = FONT_SIZES[theme.font_size ?? \"md\"] ?? FONT_SIZES.md;\n const vars: Record<string, string> = {\n \"--fh-primary\": primary,\n \"--fh-radius\": radius,\n \"--fh-font\": font,\n \"--fh-fs\": fs,\n \"--fh-bg\": dark ? \"#0F172A\" : \"#FFFFFF\",\n \"--fh-fg\": dark ? \"#F1F5F9\" : \"#0F172A\",\n \"--fh-muted\": dark ? \"#94A3B8\" : \"#64748B\",\n \"--fh-row\": dark ? \"#1E293B\" : \"#F8FAFC\",\n \"--fh-border\": dark ? \"#1E293B\" : \"#E2E8F0\",\n \"--fh-input-bg\": dark ? \"#0F172A\" : \"#FFFFFF\",\n \"--fh-input-border\": dark ? \"#334155\" : \"#CBD5E1\",\n };\n for (const [k, v] of Object.entries(vars)) root.style.setProperty(k, v);\n}\n\nfunction el<K extends keyof HTMLElementTagNameMap>(\n tag: K,\n attrs?: Record<string, string>,\n children?: (Node | string | null | undefined)[]\n): HTMLElementTagNameMap[K] {\n const node = document.createElement(tag);\n if (attrs) for (const [k, v] of Object.entries(attrs)) {\n if (k === \"class\") node.className = v;\n else node.setAttribute(k, v);\n }\n if (children) {\n for (const c of children) {\n if (c == null) continue;\n node.appendChild(typeof c === \"string\" ? document.createTextNode(c) : c);\n }\n }\n return node;\n}\n\n// ---------------------------------------------------------------------------\n// mount() — entry point\n// ---------------------------------------------------------------------------\n\nexport function mount(options: MountOptions): Widget {\n injectStyles();\n\n const container = options.container || document.body;\n const client = new HeedKitClient(options);\n\n // Silence init failures (bad project key, network down, API offline) so\n // they don't surface as unhandled promise rejections in the host page —\n // a marketing visitor should never see a Next.js error overlay because\n // our init 401'd. The launcher just doesn't show; open() no-ops.\n const initPromise: Promise<InitResult | null> = client.init(options.user || {}).catch((e) => {\n // eslint-disable-next-line no-console\n console.warn(\"[HeedKit] widget init failed; launcher disabled.\", e);\n return null;\n });\n\n let overlay: HTMLDivElement | null = null;\n let launcher: HTMLButtonElement | null = null;\n\n function close() {\n if (overlay) {\n overlay.remove();\n overlay = null;\n }\n }\n\n async function open() {\n const r = await initPromise;\n if (!r) return; // init failed; nothing to render\n if (overlay) return;\n overlay = renderPanel(client, client.getTheme(), close);\n container.appendChild(overlay);\n }\n\n if (!options.hideLauncher) {\n initPromise.then((r) => {\n if (!r) return; // init failed; skip the launcher entirely\n launcher = el(\"button\", { class: \"fk-launcher\", type: \"button\" }, [\n options.label || \"Feedback\",\n ]) as HTMLButtonElement;\n applyTheme(launcher, client.getTheme());\n launcher.addEventListener(\"click\", open);\n container.appendChild(launcher);\n });\n }\n\n return {\n client,\n open,\n close,\n destroy() {\n close();\n launcher?.remove();\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Panel rendering\n// ---------------------------------------------------------------------------\n\nfunction renderPanel(\n client: HeedKitClient,\n theme: Theme,\n onClose: () => void,\n): HTMLDivElement {\n const overlay = el(\"div\", { class: \"fk-overlay\", role: \"dialog\" }) as HTMLDivElement;\n applyTheme(overlay, theme);\n overlay.addEventListener(\"click\", (e) => {\n if (e.target === overlay) onClose();\n });\n\n const panel = el(\"div\", { class: \"fk-panel\" });\n overlay.appendChild(panel);\n\n // -- state -------------------------------------------------------------\n type Mode = \"browse\" | \"suggest\";\n const enabledKinds = client.getEnabledKinds();\n const groupMode = theme.group_mode || \"tabs\";\n // tabs mode: one tab per enabled kind, plus mixed \"All\". list mode: no kind tabs.\n let mode: Mode = \"browse\";\n let activeKind: FeatureKind | \"all\" = groupMode === \"tabs\" && enabledKinds.length > 0 ? enabledKinds[0] : \"all\";\n let features: Feature[] = [];\n\n // -- header -----------------------------------------------------------\n const head = el(\"div\", { class: \"fk-head\" });\n const titlerow = el(\"div\", { class: \"fk-titlerow\" });\n titlerow.appendChild(el(\"div\", { class: \"fk-title\" }, [client.getProjectName() || \"Feedback\"]));\n const closeBtn = el(\"button\", { class: \"fk-close\", type: \"button\", \"aria-label\": \"Close\" }, [\"×\"]);\n closeBtn.addEventListener(\"click\", onClose);\n titlerow.appendChild(closeBtn);\n head.appendChild(titlerow);\n\n const modes = el(\"div\", { class: \"fk-modes\" });\n const modeBrowse = el(\"button\", { class: \"fk-mode\", type: \"button\" }, [\"Browse\"]) as HTMLButtonElement;\n const modeSuggest = el(\"button\", { class: \"fk-mode\", type: \"button\" }, [\"Suggest\"]) as HTMLButtonElement;\n modes.append(modeBrowse, modeSuggest);\n head.appendChild(modes);\n panel.appendChild(head);\n\n // -- tabs row (tabs mode only) ----------------------------------------\n let tabsEl: HTMLElement | null = null;\n if (groupMode === \"tabs\" && enabledKinds.length > 0) {\n tabsEl = el(\"div\", { class: \"fk-tabs\" });\n const all = el(\"button\", { class: \"fk-tab\", type: \"button\" }, [\"All\"]) as HTMLButtonElement;\n all.dataset.kind = \"all\";\n tabsEl.appendChild(all);\n for (const k of enabledKinds) {\n const meta = KIND_OPTIONS[k];\n const tab = el(\"button\", { class: \"fk-tab\", type: \"button\" }, [\n el(\"span\", {}, [meta.tabIcon]),\n el(\"span\", {}, [meta.label]),\n ]) as HTMLButtonElement;\n tab.dataset.kind = k;\n tabsEl.appendChild(tab);\n }\n panel.appendChild(tabsEl);\n tabsEl.addEventListener(\"click\", (e) => {\n const target = (e.target as HTMLElement).closest(\"[data-kind]\") as HTMLElement | null;\n if (!target) return;\n activeKind = target.dataset.kind as FeatureKind | \"all\";\n paintTabs();\n refresh();\n });\n }\n\n // -- body -------------------------------------------------------------\n const body = el(\"div\", { class: \"fk-body\" });\n panel.appendChild(body);\n\n // -- helpers ----------------------------------------------------------\n\n function paintModes() {\n modeBrowse.setAttribute(\"data-active\", String(mode === \"browse\"));\n modeSuggest.setAttribute(\"data-active\", String(mode === \"suggest\"));\n if (tabsEl) tabsEl.style.display = mode === \"browse\" ? \"\" : \"none\";\n }\n\n function paintTabs() {\n if (!tabsEl) return;\n for (const t of Array.from(tabsEl.children)) {\n (t as HTMLElement).setAttribute(\n \"data-active\",\n String((t as HTMLElement).dataset.kind === String(activeKind)),\n );\n }\n }\n\n async function refresh() {\n body.replaceChildren(el(\"div\", { class: \"fk-loading\" }, [\"Loading…\"]));\n try {\n const opts: { sort: \"top\" | \"new\"; kind?: FeatureKind } = { sort: \"top\" };\n if (activeKind !== \"all\") opts.kind = activeKind;\n features = await client.list(opts);\n } catch (e) {\n body.replaceChildren(\n el(\"div\", { class: \"fk-empty\" }, [`Failed to load: ${(e as Error).message}`]),\n );\n return;\n }\n renderList();\n }\n\n // Toggle a single interaction. For upvote/downvote we mirror \"press one,\n // press it again to undo, press the other to flip\". For +1/like we just toggle.\n async function performAction(f: Feature, interaction: Interaction) {\n // The backend currently exposes a single /vote toggle endpoint regardless of\n // interaction type — all four collapse to the same row-count in this MVP.\n // (When a separate downvote endpoint is added we can branch here.)\n const r = await client.vote(f.id);\n f.voted = r.voted;\n f.vote_count = r.vote_count;\n renderList();\n }\n\n function renderActions(f: Feature): HTMLElement {\n const interactions = client.getInteractionsFor(f.kind);\n const showCount = (client.getTheme().show_counts || {})[f.kind] !== false;\n const wrap = el(\"div\", { class: \"fk-actions\" });\n\n if (interactions.length === 0) {\n // Read-only mode: just show the count (if visible).\n if (showCount) {\n const btn = el(\"button\", { class: \"fk-act\", type: \"button\", disabled: \"true\" }, [\n el(\"span\", {}, [String(f.vote_count)]),\n ]);\n wrap.appendChild(btn);\n }\n return wrap;\n }\n\n for (const i of interactions) {\n const meta = INTERACTION_META[i];\n const btn = el(\"button\", {\n class: \"fk-act\",\n type: \"button\",\n \"aria-label\": meta.label,\n }, [\n el(\"span\", { class: \"fk-glyph\" }, [meta.icon]),\n ...(showCount ? [el(\"span\", {}, [String(f.vote_count)])] : []),\n ]) as HTMLButtonElement;\n if (i === \"upvote\" || i === \"like\" || i === \"plus_one\") {\n btn.setAttribute(\"data-voted\", String(f.voted));\n }\n btn.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n performAction(f, i);\n });\n wrap.appendChild(btn);\n }\n return wrap;\n }\n\n function renderList() {\n body.innerHTML = \"\";\n if (features.length === 0) {\n body.appendChild(el(\"div\", { class: \"fk-empty\" }, [\"No items yet — be the first!\"]));\n return;\n }\n for (const f of features) {\n body.appendChild(renderRow(f));\n }\n }\n\n // A row collapses by default; clicking the meta column reveals comments.\n function renderRow(f: Feature): HTMLElement {\n const row = el(\"div\", { class: \"fk-row\" });\n row.appendChild(renderActions(f));\n\n const meta = el(\"div\", { class: \"fk-meta\" });\n meta.appendChild(el(\"div\", { class: \"fk-item-title\" }, [f.title]));\n if (f.description) meta.appendChild(el(\"div\", { class: \"fk-item-desc\" }, [f.description]));\n\n const badges = el(\"div\", { class: \"fk-item-badges\" });\n if (f.status && f.status !== \"open\") {\n const b = el(\"span\", { class: \"fk-badge\" }, [f.status.replace(\"_\", \" \")]);\n b.setAttribute(\"data-status\", f.status);\n badges.appendChild(b);\n }\n if (f.tag) badges.appendChild(el(\"span\", { class: \"fk-badge\" }, [f.tag]));\n if (badges.children.length) meta.appendChild(badges);\n\n let commentsLoaded = false;\n const commentsEl = el(\"div\", { class: \"fk-comments\" });\n commentsEl.style.display = \"none\";\n meta.appendChild(commentsEl);\n\n meta.addEventListener(\"click\", async () => {\n const opening = commentsEl.style.display === \"none\";\n commentsEl.style.display = opening ? \"\" : \"none\";\n if (opening && !commentsLoaded) {\n commentsLoaded = true;\n commentsEl.replaceChildren(el(\"div\", { class: \"fk-loading\" }, [\"Loading…\"]));\n try {\n const cs = await client.listComments(f.id);\n commentsEl.replaceChildren(...renderComments(f, cs));\n } catch (e) {\n commentsEl.replaceChildren(\n el(\"div\", { class: \"fk-error\" }, [(e as Error).message]),\n );\n }\n }\n });\n\n row.appendChild(meta);\n return row;\n }\n\n function renderComments(f: Feature, comments: Comment[]): HTMLElement[] {\n const nodes: HTMLElement[] = [];\n if (comments.length === 0) {\n nodes.push(el(\"div\", { class: \"fk-empty\" }, [\"No replies yet.\"]));\n } else {\n for (const c of comments) {\n nodes.push(el(\"div\", { class: \"fk-comment\" }, [\n el(\"span\", { class: \"fk-comment-author\" }, [c.author_name || \"Anonymous\"]),\n \" — \",\n c.body,\n ]));\n }\n }\n // Comment input\n const input = el(\"textarea\", {\n class: \"fk-textarea\",\n placeholder: \"Add a reply…\",\n rows: \"2\",\n }) as HTMLTextAreaElement;\n const send = el(\"button\", { class: \"fk-submit\", type: \"button\" }, [\"Reply\"]) as HTMLButtonElement;\n send.addEventListener(\"click\", async (e) => {\n e.stopPropagation();\n if (!input.value.trim()) return;\n send.disabled = true;\n try {\n const c = await client.comment(f.id, input.value);\n input.value = \"\";\n send.disabled = false;\n // Refresh inline.\n const refreshed = await client.listComments(f.id);\n // Replace the surrounding comments block. Find parent and re-render.\n const parent = send.parentElement?.parentElement;\n if (parent) parent.replaceChildren(...renderComments(f, refreshed));\n } catch (err) {\n send.disabled = false;\n alert((err as Error).message);\n }\n });\n nodes.push(el(\"div\", {}, [input, send]));\n return nodes;\n }\n\n // ---- Suggest form --------------------------------------------------\n\n function renderForm() {\n body.innerHTML = \"\";\n const enabled = client.getEnabledKinds();\n const enabledOptions = enabled.map((value) => ({ value, ...KIND_OPTIONS[value] }));\n const safeOptions = enabledOptions.length > 0 ? enabledOptions : [\n { value: \"other\" as FeatureKind, ...KIND_OPTIONS.other },\n ];\n let kind: FeatureKind = safeOptions[0].value;\n\n const form = el(\"form\", { class: \"fk-form\" }) as HTMLFormElement;\n\n const kindLabel = el(\"label\", { class: \"fk-label\" }, [\"What's this about?\"]);\n const segmented = el(\"div\", { class: \"fk-segmented\" });\n const segButtons: HTMLButtonElement[] = [];\n for (const opt of safeOptions) {\n const btn = el(\"button\", { class: \"fk-seg\", type: \"button\" }, [opt.label]) as HTMLButtonElement;\n btn.setAttribute(\"data-active\", String(opt.value === kind));\n btn.addEventListener(\"click\", () => {\n kind = opt.value;\n segButtons.forEach((b, i) =>\n b.setAttribute(\"data-active\", String(safeOptions[i].value === kind)),\n );\n titleInput.placeholder = safeOptions.find((o) => o.value === kind)!.placeholder;\n });\n segButtons.push(btn);\n segmented.appendChild(btn);\n }\n kindLabel.appendChild(segmented);\n\n const titleLabel = el(\"label\", { class: \"fk-label\" }, [\"Title\"]);\n const titleInput = el(\"input\", {\n class: \"fk-input\",\n type: \"text\",\n placeholder: safeOptions[0].placeholder,\n required: \"true\",\n }) as HTMLInputElement;\n titleLabel.appendChild(titleInput);\n\n const descLabel = el(\"label\", { class: \"fk-label\" }, [\"Description\"]);\n const descInput = el(\"textarea\", {\n class: \"fk-textarea\",\n placeholder: \"Any extra context helps.\",\n rows: \"4\",\n }) as HTMLTextAreaElement;\n descLabel.appendChild(descInput);\n\n const submit = el(\"button\", { class: \"fk-submit\", type: \"submit\" }, [\"Submit\"]) as HTMLButtonElement;\n\n form.append(kindLabel, titleLabel, descLabel, submit);\n body.appendChild(form);\n\n form.addEventListener(\"submit\", async (e) => {\n e.preventDefault();\n if (!titleInput.value.trim()) return;\n submit.disabled = true;\n submit.textContent = \"Submitting…\";\n try {\n await client.submit({\n title: titleInput.value,\n description: descInput.value,\n kind,\n });\n titleInput.value = \"\";\n descInput.value = \"\";\n setMode(\"browse\");\n // Land on the tab of what they just posted, so they see their submission.\n if (tabsEl) {\n activeKind = kind;\n paintTabs();\n }\n await refresh();\n } catch (err) {\n submit.disabled = false;\n submit.textContent = \"Submit\";\n alert((err as Error).message);\n }\n });\n }\n\n function setMode(m: Mode) {\n mode = m;\n paintModes();\n if (mode === \"browse\") refresh();\n else renderForm();\n }\n\n modeBrowse.addEventListener(\"click\", () => setMode(\"browse\"));\n modeSuggest.addEventListener(\"click\", () => setMode(\"suggest\"));\n\n paintModes();\n paintTabs();\n setMode(\"browse\");\n\n return overlay;\n}\n"],"mappings":"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","names":["src_exports","__export","HeedKitClient","mount","DEFAULT_API","DEVICE_ID_KEY","getOrCreateDeviceId","_a","_b","existing","next","e","normalizeFeature","f","_c","_d","_e","_f","_g","_h","normalizeComment","c","HeedKitClient","config","user","body","res","p","kind","row","i","opts","params","input","featureId","path","method","detail","j","KIND_OPTIONS","INTERACTION_META","FONT_SIZES","STYLE_ID","CSS","injectStyles","style","effectiveMode","theme","m","applyTheme","root","_a","_b","_c","primary","radius","dark","font","fs","vars","k","v","el","tag","attrs","children","node","c","mount","options","container","client","HeedKitClient","initPromise","e","overlay","launcher","close","open","renderPanel","r","onClose","panel","enabledKinds","groupMode","mode","activeKind","features","head","titlerow","closeBtn","modes","modeBrowse","modeSuggest","tabsEl","all","meta","tab","target","paintTabs","refresh","body","paintModes","t","opts","renderList","performAction","f","interaction","renderActions","interactions","showCount","wrap","btn","i","renderRow","row","badges","b","commentsLoaded","commentsEl","opening","cs","renderComments","comments","nodes","input","send","refreshed","parent","err","renderForm","enabledOptions","value","safeOptions","kind","form","kindLabel","segmented","segButtons","opt","titleInput","o","titleLabel","descLabel","descInput","submit","setMode"]}
|