@malto/sdk 0.1.2 → 0.1.3

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/malto.umd.js CHANGED
@@ -1,39 +1,39 @@
1
- var Malto=(function(exports){'use strict';var F="https://malto-api-production.up.railway.app",h=class{constructor(t){this.apiKey=t.apiKey,this.apiUrl=(t.apiUrl??F).replace(/\/$/,""),this.getSessionToken=t.getSessionToken;}async request(t,e={}){let a={"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`};if(e.headers){let s=e.headers;for(let[d,l]of Object.entries(s))a[d]=l;}if(e.auth){let s=this.getSessionToken();s&&(a["X-Malto-Session"]=s);}let r=await fetch(`${this.apiUrl}${t}`,{...e,headers:a}),o=await r.text(),n=o?A(o):null;if(!r.ok){let s=n&&(n.message||n.error)||`Request failed (${r.status})`;throw new b(Array.isArray(s)?s.join(", "):String(s),r.status)}return n}board(){return this.request("/v1/sdk/board")}listFeedbacks(){return this.request("/v1/sdk/feedbacks",{auth:true})}feedback(t){return this.request(`/v1/sdk/feedbacks/${t}`,{auth:true})}createFeedback(t){return this.request("/v1/sdk/feedbacks",{method:"POST",auth:true,body:JSON.stringify(t)})}vote(t){return this.request(`/v1/sdk/feedbacks/${t}/vote`,{method:"POST",auth:true})}comments(t){return this.request(`/v1/sdk/feedbacks/${t}/comments`,{auth:true})}addComment(t,e,a){return this.request(`/v1/sdk/feedbacks/${t}/comments`,{method:"POST",auth:true,body:JSON.stringify({body:e,parentId:a})})}roadmap(){return this.request("/v1/sdk/roadmap")}releases(){return this.request("/v1/sdk/releases")}startMagicLink(t){return this.request("/v1/sdk/auth/magic-link",{method:"POST",body:JSON.stringify(t)})}verifyMagicLink(t){return this.request("/v1/sdk/auth/verify",{method:"POST",body:JSON.stringify({token:t})})}identify(t){return this.request("/v1/sdk/auth/identify",{method:"POST",body:JSON.stringify(t)})}},b=class extends Error{constructor(e,a){super(e);this.status=a;this.name="MaltoApiError";}};function A(i){try{return JSON.parse(i)}catch{return null}}var x="malto:session:";function E(i){if(typeof window>"u")return null;try{let t=window.localStorage.getItem(x+i);if(!t)return null;let e=JSON.parse(t);return !e?.token||!e?.expiresAt?null:new Date(e.expiresAt).getTime()<Date.now()?(window.localStorage.removeItem(x+i),null):e}catch{return null}}function S(i,t){if(!(typeof window>"u"))try{window.localStorage.setItem(x+i,JSON.stringify(t));}catch{}}function g(i){if(!(typeof window>"u"))try{window.localStorage.removeItem(x+i);}catch{}}var H="malto-sdk-styles",P="malto-sdk-styles-custom";function z(i){if(typeof document>"u")return;let t=B(i);I(H,t),i.customCss?I(P,O(i.customCss)):document.getElementById(P)?.remove();}function O(i){return i.replace(/<\/style/gi,"<\\/style").replace(/<\/script/gi,"<\\/script").replace(/expression\s*\(/gi,"expr\\(").replace(/javascript\s*:/gi,"javascript\\:")}function I(i,t){let e=document.getElementById(i);if(e){e.textContent=t;return}let a=document.createElement("style");a.id=i,a.textContent=t,document.head.appendChild(a);}function B(i){let t=i.primary,e=D(t),a=i.radius==="sm"?"12px":i.radius==="lg"?"24px":"20px",r=i.appearance??"auto",o=i.cssVars??{};return `
1
+ var Malto=(function(exports){'use strict';var $="https://malto-api-production.up.railway.app",v=class{constructor(t){this.apiKey=t.apiKey,this.apiUrl=(t.apiUrl??$).replace(/\/$/,""),this.getSessionToken=t.getSessionToken;}async request(t,e={}){let a={"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`};if(e.headers){let s=e.headers;for(let[l,d]of Object.entries(s))a[l]=d;}if(e.auth){let s=this.getSessionToken();s&&(a["X-Malto-Session"]=s);}let o=await fetch(`${this.apiUrl}${t}`,{...e,headers:a}),r=await o.text(),n=r?O(r):null;if(!o.ok){let s=n&&(n.message||n.error)||`Request failed (${o.status})`;throw new k(Array.isArray(s)?s.join(", "):String(s),o.status)}return n}board(){return this.request("/v1/sdk/board")}listFeedbacks(){return this.request("/v1/sdk/feedbacks",{auth:true})}feedback(t){return this.request(`/v1/sdk/feedbacks/${t}`,{auth:true})}createFeedback(t){return this.request("/v1/sdk/feedbacks",{method:"POST",auth:true,body:JSON.stringify(t)})}vote(t){return this.request(`/v1/sdk/feedbacks/${t}/vote`,{method:"POST",auth:true})}comments(t){return this.request(`/v1/sdk/feedbacks/${t}/comments`,{auth:true})}addComment(t,e,a){return this.request(`/v1/sdk/feedbacks/${t}/comments`,{method:"POST",auth:true,body:JSON.stringify({body:e,parentId:a})})}roadmap(){return this.request("/v1/sdk/roadmap")}releases(){return this.request("/v1/sdk/releases")}startMagicLink(t){return this.request("/v1/sdk/auth/magic-link",{method:"POST",body:JSON.stringify(t)})}verifyMagicLink(t){return this.request("/v1/sdk/auth/verify",{method:"POST",body:JSON.stringify({token:t})})}identify(t){return this.request("/v1/sdk/auth/identify",{method:"POST",body:JSON.stringify(t)})}},k=class extends Error{constructor(e,a){super(e);this.status=a;this.name="MaltoApiError";}};function O(i){try{return JSON.parse(i)}catch{return null}}var w="malto:session:";function N(i){if(typeof window>"u")return null;try{let t=window.localStorage.getItem(w+i);if(!t)return null;let e=JSON.parse(t);return !e?.token||!e?.expiresAt?null:new Date(e.expiresAt).getTime()<Date.now()?(window.localStorage.removeItem(w+i),null):e}catch{return null}}function S(i,t){if(!(typeof window>"u"))try{window.localStorage.setItem(w+i,JSON.stringify(t));}catch{}}function y(i){if(!(typeof window>"u"))try{window.localStorage.removeItem(w+i);}catch{}}var B="malto-sdk-styles",P="malto-sdk-styles-custom";function H(i){if(typeof document>"u")return;let t=j(i);z(B,t),i.customCss?z(P,F(i.customCss)):document.getElementById(P)?.remove();}function F(i){return i.replace(/<\/style/gi,"<\\/style").replace(/<\/script/gi,"<\\/script").replace(/expression\s*\(/gi,"expr\\(").replace(/javascript\s*:/gi,"javascript\\:")}function z(i,t){let e=document.getElementById(i);if(e){e.textContent=t;return}let a=document.createElement("style");a.id=i,a.textContent=t,document.head.appendChild(a);}function j(i){let t=i.primary,e=U(t),a=i.radius==="sm"?"12px":i.radius==="lg"?"24px":"20px",o=i.appearance??"light",r=i.cssVars??{};return `
2
2
  @import url('https://fonts.googleapis.com/css2?family=Google+Sans:ital,opsz,wght@0,17..18,400..700;1,17..18,400..700&display=swap');
3
3
 
4
4
  :where(.malto-root, .malto-root *) {
5
5
  box-sizing: border-box;
6
6
  }
7
7
  .malto-root {
8
- --malto-primary: ${o.primary??t};
9
- --malto-primary-contrast: ${o.primaryContrast??e.contrast};
8
+ --malto-primary: ${r.primary??t};
9
+ --malto-primary-contrast: ${r.primaryContrast??e.contrast};
10
10
  --malto-primary-50: ${e.tint50};
11
11
  --malto-primary-100: ${e.tint100};
12
12
  --malto-primary-200: ${e.tint200};
13
13
  --malto-primary-600: ${e.shade600};
14
14
  --malto-primary-rgb: ${e.rgb};
15
- --malto-surface: ${o.surface??"#ffffff"};
16
- --malto-surface-muted: ${o.surfaceMuted??"#f2eeff"};
15
+ --malto-surface: ${r.surface??"#ffffff"};
16
+ --malto-surface-muted: ${r.surfaceMuted??"#f2eeff"};
17
17
  --malto-surface-elevated: rgba(255,255,255,0.92);
18
- --malto-border: ${o.border??"#e2e8f0"};
18
+ --malto-border: ${r.border??"#e2e8f0"};
19
19
  --malto-border-strong: #cbd1de;
20
- --malto-text: ${o.text??"#0a0a0a"};
21
- --malto-text-muted: ${o.textMuted??"#5b5871"};
20
+ --malto-text: ${r.text??"#0a0a0a"};
21
+ --malto-text-muted: ${r.textMuted??"#5b5871"};
22
22
  --malto-text-subtle: rgba(10, 10, 10, 0.5);
23
- --malto-radius: ${o.radius??a};
23
+ --malto-radius: ${r.radius??a};
24
24
  --malto-radius-sm: 12px;
25
25
  --malto-radius-pill: 999px;
26
- --malto-shadow-sm: ${o.shadow??"0 4px 12px -6px rgba(25, 24, 56, 0.12)"};
26
+ --malto-shadow-sm: ${r.shadow??"0 4px 12px -6px rgba(25, 24, 56, 0.12)"};
27
27
  --malto-shadow-md: 0 10px 30px -10px rgba(25, 24, 56, 0.15);
28
28
  --malto-shadow-lg: 0 30px 60px -20px rgba(25, 24, 56, 0.25);
29
29
  --malto-shadow-glow: 0 8px 20px -6px rgba(var(--malto-primary-rgb), 0.45);
30
- --malto-font: ${o.font??"'Google Sans', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, sans-serif"};
30
+ --malto-font: ${r.font??"'Google Sans', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, sans-serif"};
31
31
  --malto-ease-spring: cubic-bezier(0.34, 1.4, 0.5, 1);
32
32
  --malto-ease-smooth: cubic-bezier(0.32, 0.72, 0, 1);
33
33
  }
34
34
 
35
- ${r==="dark"?T():""}
36
- ${r==="auto"?`@media (prefers-color-scheme: dark) { ${T()} }`:""}
35
+ ${o==="dark"?R():""}
36
+ ${o==="auto"?`@media (prefers-color-scheme: dark) { ${R()} }`:""}
37
37
 
38
38
  .malto-root, .malto-root *, .malto-root *::before, .malto-root *::after {
39
39
  font-family: var(--malto-font);
@@ -119,7 +119,8 @@ var Malto=(function(exports){'use strict';var F="https://malto-api-production.up
119
119
  .malto-modal {
120
120
  background: var(--malto-surface);
121
121
  width: 100%;
122
- max-width: 460px;
122
+ max-width: 1152px;
123
+ height: 720px;
123
124
  max-height: 92vh;
124
125
  border-radius: var(--malto-radius) var(--malto-radius) 0 0;
125
126
  box-shadow: var(--malto-shadow-lg);
@@ -570,6 +571,206 @@ var Malto=(function(exports){'use strict';var F="https://malto-api-production.up
570
571
  background: var(--malto-surface-muted);
571
572
  }
572
573
 
574
+ /* \u2500\u2500\u2500\u2500\u2500\u2500 Kanban (roadmap) \u2500\u2500\u2500\u2500\u2500\u2500 */
575
+ .malto-kanban {
576
+ display: grid;
577
+ grid-template-columns: repeat(4, minmax(0, 1fr));
578
+ gap: 16px;
579
+ align-items: start;
580
+ }
581
+ @media (max-width: 960px) {
582
+ .malto-kanban { grid-template-columns: repeat(2, minmax(0, 1fr)); }
583
+ }
584
+ @media (max-width: 560px) {
585
+ .malto-kanban { grid-template-columns: 1fr; }
586
+ }
587
+ .malto-kanban-col {
588
+ display: flex; flex-direction: column;
589
+ gap: 12px;
590
+ min-width: 0;
591
+ }
592
+ .malto-kanban-head {
593
+ display: flex; align-items: center; justify-content: space-between;
594
+ padding: 0 4px;
595
+ }
596
+ .malto-kanban-title {
597
+ margin: 0;
598
+ font-size: 11px;
599
+ font-weight: 600;
600
+ text-transform: uppercase;
601
+ letter-spacing: 0.06em;
602
+ color: var(--malto-text-muted);
603
+ }
604
+ .malto-kanban-count {
605
+ font-size: 11px;
606
+ font-weight: 700;
607
+ color: var(--malto-text-subtle);
608
+ letter-spacing: 0.04em;
609
+ }
610
+ .malto-kanban-list {
611
+ display: flex; flex-direction: column;
612
+ gap: 12px;
613
+ }
614
+ .malto-kanban-empty {
615
+ padding: 14px 12px;
616
+ font-size: 12px;
617
+ color: var(--malto-text-subtle);
618
+ border: 1px dashed var(--malto-border);
619
+ border-radius: 12px;
620
+ text-align: center;
621
+ background: var(--malto-surface-muted);
622
+ }
623
+
624
+ /* Card \u2014 mirrors malto-web FeedbackCard */
625
+ .malto-card {
626
+ display: block;
627
+ text-decoration: none;
628
+ color: inherit;
629
+ position: relative;
630
+ padding: 16px;
631
+ background: var(--malto-surface);
632
+ border: 1px solid rgba(200, 196, 216, 0.18);
633
+ border-radius: 12px;
634
+ box-shadow: 0 0 40px rgba(var(--malto-primary-rgb), 0.06),
635
+ 0 0 80px rgba(var(--malto-primary-rgb), 0.02);
636
+ transition: transform .2s var(--malto-ease-spring),
637
+ box-shadow .2s ease, border-color .2s ease;
638
+ cursor: pointer;
639
+ }
640
+ .malto-card:hover {
641
+ transform: translateY(-2px);
642
+ box-shadow: 0 0 50px rgba(var(--malto-primary-rgb), 0.14),
643
+ 0 0 90px rgba(var(--malto-primary-rgb), 0.04);
644
+ border-color: rgba(var(--malto-primary-rgb), 0.2);
645
+ }
646
+ .malto-card-top {
647
+ display: flex; align-items: flex-start; justify-content: space-between;
648
+ gap: 8px;
649
+ }
650
+ .malto-card-cat {
651
+ display: inline-flex; align-items: center;
652
+ padding: 3px 9px;
653
+ border-radius: 999px;
654
+ background: rgba(var(--malto-primary-rgb), 0.1);
655
+ color: var(--malto-primary-600);
656
+ font-size: 10px;
657
+ font-weight: 600;
658
+ text-transform: uppercase;
659
+ letter-spacing: 0.05em;
660
+ line-height: 1.4;
661
+ }
662
+ .malto-card-votes {
663
+ display: inline-flex; flex-direction: column;
664
+ align-items: center;
665
+ padding: 4px 8px;
666
+ border: 1px solid var(--malto-border);
667
+ border-radius: 8px;
668
+ background: var(--malto-surface);
669
+ color: var(--malto-text);
670
+ font-size: 12px;
671
+ font-weight: 700;
672
+ line-height: 1;
673
+ transition: border-color .2s ease, background .2s ease;
674
+ }
675
+ .malto-card:hover .malto-card-votes {
676
+ border-color: rgba(var(--malto-primary-rgb), 0.3);
677
+ background: rgba(var(--malto-primary-rgb), 0.05);
678
+ }
679
+ .malto-card-votes svg {
680
+ color: var(--malto-text-muted);
681
+ margin-bottom: 2px;
682
+ }
683
+ .malto-card-title {
684
+ margin: 12px 0 0;
685
+ font-size: 14.5px;
686
+ font-weight: 600;
687
+ letter-spacing: -0.01em;
688
+ line-height: 1.35;
689
+ color: var(--malto-text);
690
+ display: -webkit-box;
691
+ -webkit-line-clamp: 2;
692
+ -webkit-box-orient: vertical;
693
+ overflow: hidden;
694
+ }
695
+ .malto-card-desc {
696
+ margin: 6px 0 0;
697
+ font-size: 12.5px;
698
+ line-height: 1.45;
699
+ color: var(--malto-text-muted);
700
+ display: -webkit-box;
701
+ -webkit-line-clamp: 2;
702
+ -webkit-box-orient: vertical;
703
+ overflow: hidden;
704
+ }
705
+ .malto-card-foot {
706
+ display: flex; align-items: center; justify-content: space-between;
707
+ gap: 8px;
708
+ margin-top: 14px;
709
+ padding-top: 12px;
710
+ border-top: 1px solid rgba(var(--malto-primary-rgb), 0.08);
711
+ font-size: 11px;
712
+ color: var(--malto-text-subtle);
713
+ }
714
+ .malto-card-who {
715
+ display: flex; align-items: center; gap: 6px;
716
+ min-width: 0;
717
+ flex: 1;
718
+ }
719
+ .malto-card-avatar {
720
+ flex: none;
721
+ width: 20px; height: 20px;
722
+ border-radius: 999px;
723
+ display: flex; align-items: center; justify-content: center;
724
+ color: #ffffff;
725
+ font-size: 9px;
726
+ font-weight: 700;
727
+ overflow: hidden;
728
+ }
729
+ .malto-card-avatar img {
730
+ width: 100%; height: 100%;
731
+ object-fit: cover;
732
+ }
733
+ .malto-avatar-bg-0 { background: #5f4ff8; }
734
+ .malto-avatar-bg-1 { background: #ec4899; }
735
+ .malto-avatar-bg-2 { background: #0ea5e9; }
736
+ .malto-avatar-bg-3 { background: #10b981; }
737
+ .malto-avatar-bg-4 { background: #f59e0b; }
738
+ .malto-avatar-bg-5 { background: #7e2eaa; }
739
+ .malto-avatar-bg-6 { background: #ef4444; }
740
+ .malto-avatar-bg-7 { background: #06b6d4; }
741
+ .malto-card-author {
742
+ font-size: 11px;
743
+ font-weight: 500;
744
+ color: var(--malto-text-muted);
745
+ min-width: 0;
746
+ overflow: hidden;
747
+ text-overflow: ellipsis;
748
+ white-space: nowrap;
749
+ }
750
+ .malto-card-dot {
751
+ color: var(--malto-border-strong);
752
+ flex: none;
753
+ }
754
+ .malto-card-time {
755
+ color: var(--malto-text-muted);
756
+ flex: none;
757
+ }
758
+ .malto-card-comments {
759
+ display: inline-flex; align-items: center; gap: 4px;
760
+ color: var(--malto-text-muted);
761
+ font-weight: 500;
762
+ flex: none;
763
+ }
764
+ .malto-card-skeleton {
765
+ cursor: default;
766
+ box-shadow: none;
767
+ }
768
+ .malto-card-skeleton:hover {
769
+ transform: none;
770
+ box-shadow: none;
771
+ border-color: rgba(200, 196, 216, 0.18);
772
+ }
773
+
573
774
  /* \u2500\u2500\u2500\u2500\u2500\u2500 Animations \u2500\u2500\u2500\u2500\u2500\u2500 */
574
775
  @keyframes malto-overlay-in {
575
776
  from { opacity: 0; backdrop-filter: blur(0); }
@@ -595,7 +796,7 @@ var Malto=(function(exports){'use strict';var F="https://malto-api-production.up
595
796
  transition-duration: 0.01ms !important;
596
797
  }
597
798
  }
598
- `}function T(){return `
799
+ `}function R(){return `
599
800
  .malto-root {
600
801
  --malto-surface: #131127;
601
802
  --malto-surface-muted: #1a1834;
@@ -605,5 +806,5 @@ var Malto=(function(exports){'use strict';var F="https://malto-api-production.up
605
806
  --malto-text-muted: #a09cc7;
606
807
  --malto-text-subtle: rgba(230, 227, 245, 0.5);
607
808
  }
608
- `}function D(i){let{r:t,g:e,b:a}=j(i);return {rgb:`${t}, ${e}, ${a}`,contrast:U(t,e,a),tint50:N(t,e,a,.06),tint100:N(t,e,a,.12),tint200:N(t,e,a,.18),shade600:V(t,e,a,-0.18)}}function j(i){let t=i.trim().replace(/^#/,"");return t.length===3&&(t=t.split("").map(e=>e+e).join("")),/^[0-9a-fA-F]{6}$/.test(t)?{r:parseInt(t.slice(0,2),16),g:parseInt(t.slice(2,4),16),b:parseInt(t.slice(4,6),16)}:{r:69,g:47,b:223}}function U(i,t,e){return (.2126*i+.7152*t+.0722*e)/255>.65?"#0f0d23":"#ffffff"}function N(i,t,e,a,r){return `rgba(${i}, ${t}, ${e}, ${a})`}function V(i,t,e,a){let r=n=>Math.max(0,Math.min(255,Math.round(n+255*a))),o=n=>r(n).toString(16).padStart(2,"0");return `#${o(i)}${o(t)}${o(e)}`}var q={"bottom-right":{right:"24px",bottom:"24px"},"bottom-left":{left:"24px",bottom:"24px"},"top-right":{right:"24px",top:"24px"},"top-left":{left:"24px",top:"24px"}},v=class{constructor(t){this.resolvedMode="bubble";this.root=null;this.container=null;this.trigger=null;this.board=null;if(!t.apiKey)throw new Error("Malto: apiKey is required");this.apiKeyPrefix=t.apiKey.slice(0,16),this.config={apiKey:t.apiKey,apiUrl:t.apiUrl??"https://malto-api-production.up.railway.app",mode:t.mode??"auto",position:t.position??"bottom-right",triggerLabel:t.triggerLabel??"Feedback",primaryColor:t.primaryColor,cssVars:t.cssVars,customCss:t.customCss,radius:t.radius??"md",appearance:t.appearance??"auto",zIndex:t.zIndex??2147483600,views:t.views,identify:t.identify,target:t.target,onReady:t.onReady,onError:t.onError};let e=E(this.apiKeyPrefix);this.state={open:false,view:"list",loading:false,error:null,feedbacks:[],roadmap:{},releases:[],selectedFeedback:null,comments:[],authEmail:"",authStatus:"idle",email:e?.email??null,name:e?.name??null},this.client=new h({apiKey:this.config.apiKey,apiUrl:this.config.apiUrl,getSessionToken:()=>E(this.apiKeyPrefix)?.token??null});}async mount(){try{let t=await this.client.board();this.board=t;let e=this.config.primaryColor||t.widget.primaryColor||t.board.boardThemeColor||"#452fdf";z({primary:e,cssVars:this.config.cssVars,customCss:this.config.customCss,radius:this.config.radius,appearance:this.config.appearance}),this.resolvedMode=this.config.mode==="auto"?t.widget.defaultMode:this.config.mode,this.config.identify&&await this.runIdentify(this.config.identify),this.renderHost(this.resolvedMode),this.config.onReady?.();}catch(t){this.config.onError?.(t);}}unmount(){this.root?.parentElement?.removeChild(this.root),this.trigger?.parentElement?.removeChild(this.trigger),this.root=null,this.trigger=null,this.container=null;}open(){this.state.open=true,this.render();}close(){this.state.open=false,this.render();}setIdentify(t){if(!t){g(this.apiKeyPrefix),this.state.email=null,this.state.name=null,this.render();return}this.runIdentify(t);}async runIdentify(t){try{let e=await this.client.identify(t);S(this.apiKeyPrefix,{token:e.sessionToken,expiresAt:e.expiresAt,email:e.user.email,name:e.user.name}),this.state.email=e.user.email,this.state.name=e.user.name,this.render();}catch(e){this.config.onError?.(e);}}renderHost(t){let e=document.createElement("div");if(e.className="malto-root",e.style.setProperty("--malto-z",String(this.config.zIndex)),document.body.appendChild(e),this.root=e,t==="inline"){let a=this.resolveTarget();if(!a){this.config.onError?.(new Error("Malto: inline target not found"));return}let r=document.createElement("div");r.className="malto-root malto-inline",r.style.setProperty("--malto-z",String(this.config.zIndex)),a.appendChild(r),this.container=r,this.state.open=true,this.render();return}if(t==="bubble"){let a=this.buildBubble(),r=q[this.config.position];Object.assign(a.style,r);let o=document.createElement("div");o.className="malto-root",o.style.setProperty("--malto-z",String(this.config.zIndex)),o.appendChild(a),document.body.appendChild(o),this.trigger=o;}else if(t==="trigger"){let a=this.resolveTarget();if(!a){this.config.onError?.(new Error("Malto: trigger target not found"));return}let r=document.createElement("span");r.className="malto-root",r.style.setProperty("--malto-z",String(this.config.zIndex));let o=document.createElement("button");o.className="malto-trigger",o.innerHTML=`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg><span>${L(this.config.triggerLabel)}</span>`,o.addEventListener("click",()=>this.open()),r.appendChild(o),a.appendChild(r),this.trigger=r;}else t==="modal"&&(this.state.open=true);this.render();}buildBubble(){let t=document.createElement("button");return t.className="malto-bubble",t.setAttribute("aria-label",this.config.triggerLabel),t.innerHTML='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>',t.addEventListener("click",()=>{this.state.open?this.close():this.open();}),t}resolveTarget(){return this.config.target?typeof this.config.target=="string"?document.querySelector(this.config.target):this.config.target:null}render(){if(!this.root)return;if(this.resolvedMode==="inline"){if(!this.container)return;this.container.innerHTML="",this.container.appendChild(this.buildPanelBody());return}if(this.root.innerHTML="",!this.state.open)return;let t=document.createElement("div");t.className="malto-overlay",t.addEventListener("click",a=>{a.target===t&&this.close();});let e=document.createElement("div");e.className="malto-modal",e.appendChild(this.buildPanelBody()),t.appendChild(e),this.root.appendChild(t);}buildPanelBody(){let t=document.createElement("div");t.style.display="flex",t.style.flexDirection="column",t.style.height="100%",t.style.minHeight="0",t.appendChild(this.buildHeader()),t.appendChild(this.buildTabs());let e=document.createElement("div");if(e.className="malto-body",e.appendChild(this.buildView()),t.appendChild(e),this.state.view!=="auth"&&!this.state.email){let a=document.createElement("div");a.className="malto-footer-banner";let r=document.createElement("span");r.innerHTML="Sign in to vote, comment, or submit ideas.";let o=document.createElement("button");o.className="malto-link",o.textContent="Sign in",o.addEventListener("click",()=>this.go("auth")),a.appendChild(r),a.appendChild(o),t.appendChild(a);}return t}buildHeader(){let t=document.createElement("div");t.className="malto-header";let e=document.createElement("div");e.className="malto-header-meta";let a=document.createElement("div");a.className="malto-board-logo";let r=$(this.board?.board.companyLogoUrl);if(r){let n=document.createElement("img");n.src=r,n.alt="",n.referrerPolicy="no-referrer",n.crossOrigin="anonymous",a.appendChild(n);}else a.textContent=(this.board?.board.companyName??this.board?.board.boardName??"M").charAt(0).toUpperCase();let o=document.createElement("h3");if(o.textContent=this.board?.board.boardName??this.board?.board.companyName??"Feedback",e.appendChild(a),e.appendChild(o),t.appendChild(e),this.resolvedMode!=="inline"){let n=document.createElement("button");n.className="malto-close",n.setAttribute("aria-label","Close"),n.innerHTML='<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>',n.addEventListener("click",()=>this.close()),t.appendChild(n);}return t}buildTabs(){let t=document.createElement("div");t.className="malto-tabs";let e=this.allowedViews();return e.includes("list")&&t.appendChild(this.tabBtn("Feed","list")),e.includes("submit")&&t.appendChild(this.tabBtn("New","submit")),e.includes("roadmap")&&t.appendChild(this.tabBtn("Roadmap","roadmap")),e.includes("changelog")&&t.appendChild(this.tabBtn("Updates","changelog")),t}tabBtn(t,e){let a=document.createElement("button");return a.className="malto-tab",a.setAttribute("aria-selected",this.state.view===e?"true":"false"),a.textContent=t,a.addEventListener("click",()=>this.go(e)),a}go(t){this.state.view=t,this.state.error=null,this.render(),t==="list"&&this.loadFeedbacks(),t==="roadmap"&&this.loadRoadmap(),t==="changelog"&&this.loadReleases(),t==="detail"&&this.state.selectedFeedback&&this.loadComments(this.state.selectedFeedback.id);}allowedViews(){let t=this.board?.widget.enabledFeatures??["list","submit","vote","comment","roadmap","changelog"];return (this.config.views??["list","submit","roadmap","changelog"]).filter(a=>t.includes(a))}buildView(){let t=document.createElement("div");if(this.state.error){let e=document.createElement("div");e.className="malto-error",e.textContent=this.state.error,t.appendChild(e);}switch(this.state.view){case "list":t.appendChild(this.viewList()),this.state.feedbacks.length===0&&!this.state.loading&&this.loadFeedbacks();break;case "submit":t.appendChild(this.viewSubmit());break;case "auth":t.appendChild(this.viewAuth());break;case "roadmap":t.appendChild(this.viewRoadmap()),Object.keys(this.state.roadmap).length===0&&!this.state.loading&&this.loadRoadmap();break;case "changelog":t.appendChild(this.viewChangelog()),this.state.releases.length===0&&!this.state.loading&&this.loadReleases();break;case "detail":t.appendChild(this.viewDetail());break}return t}viewList(){let t=document.createElement("div");if(this.state.loading)return t.appendChild(this.skeletonList(4)),t;if(this.state.feedbacks.length===0)return t.appendChild(this.emptyState("\u{1F4A1}","No requests yet","Be the first to share an idea or report something.")),t;let e=document.createElement("div");e.className="malto-list";for(let a of this.state.feedbacks)e.appendChild(this.feedbackRow(a));return t.appendChild(e),t}feedbackRow(t){let e=document.createElement("div");e.className="malto-item";let a=document.createElement("button");a.className="malto-vote",a.setAttribute("aria-pressed",t.hasVoted?"true":"false");let r=document.createElement("span");r.className="malto-vote-arrow",r.textContent="\u25B2";let o=document.createElement("span");o.className="malto-vote-count",o.textContent=_(t.votes??0),a.appendChild(r),a.appendChild(o),a.addEventListener("click",m=>{m.stopPropagation(),this.handleVote(t);});let n=document.createElement("div");n.className="malto-item-content";let s=document.createElement("h4");if(s.textContent=t.title,n.appendChild(s),t.description){let m=document.createElement("p");m.textContent=t.description,n.appendChild(m);}let d=document.createElement("div");if(d.className="malto-item-meta",t.status&&t.status!=="BACKLOG"){let m=K(t.status);d.appendChild(m);}let l=document.createElement("span");return l.textContent=R(t.createdAt),d.appendChild(l),n.appendChild(d),e.appendChild(a),e.appendChild(n),e.addEventListener("click",()=>{this.state.selectedFeedback=t,this.go("detail");}),e}viewSubmit(){let t=document.createElement("form");t.className="malto-form";let e=document.createElement("input");e.className="malto-input",e.required=true,e.maxLength=200,e.placeholder="What would you like?";let a=document.createElement("textarea");a.className="malto-textarea",a.maxLength=5e3,a.placeholder="Add some context (optional)";let r=document.createElement("button");return r.className="malto-button",r.textContent="Submit feedback",r.type="submit",t.appendChild(e),t.appendChild(a),t.appendChild(r),t.addEventListener("submit",async o=>{if(o.preventDefault(),!this.state.email){this.go("auth");return}r.setAttribute("disabled","true");try{await this.client.createFeedback({title:e.value.trim(),description:a.value.trim()||void 0}),e.value="",a.value="",await this.loadFeedbacks(),this.go("list");}catch(n){this.state.error=n.message,r.removeAttribute("disabled"),this.render();}}),t}viewAuth(){let t=document.createElement("div");if(this.state.email){let n=document.createElement("p");n.style.fontSize="13px",n.style.color="var(--malto-text)",n.style.marginBottom="10px",n.innerHTML=`Signed in as <strong>${L(this.state.email)}</strong>`;let s=document.createElement("button");return s.className="malto-secondary",s.textContent="Sign out",s.addEventListener("click",()=>{g(this.apiKeyPrefix),this.state.email=null,this.state.name=null,this.go("list");}),t.appendChild(n),t.appendChild(s),t}if(this.state.authStatus==="sent"){let n=document.createElement("p");n.style.fontSize="13px",n.style.color="var(--malto-text)",n.style.marginBottom="12px",n.style.lineHeight="1.5",n.innerHTML=`We sent a sign-in link to <strong>${L(this.state.authEmail)}</strong>. Open the email and paste the token below.`;let s=document.createElement("input");s.className="malto-input",s.placeholder="Paste token from email";let d=document.createElement("button");d.className="malto-button",d.style.marginTop="8px",d.textContent="Verify",d.addEventListener("click",async()=>{d.setAttribute("disabled","true");try{let m=await this.client.verifyMagicLink(s.value.trim());S(this.apiKeyPrefix,{token:m.sessionToken,expiresAt:m.expiresAt,email:m.user.email,name:m.user.name}),this.state.email=m.user.email,this.state.name=m.user.name,this.state.authStatus="idle",this.go("list");}catch(m){this.state.error=m.message,d.removeAttribute("disabled"),this.render();}});let l=document.createElement("button");return l.className="malto-link",l.style.marginTop="12px",l.style.display="block",l.textContent="Use a different email",l.addEventListener("click",()=>{this.state.authStatus="idle",this.render();}),t.appendChild(n),t.appendChild(s),t.appendChild(d),t.appendChild(l),t}let e=document.createElement("form");e.className="malto-form";let a=document.createElement("p");a.style.fontSize="13px",a.style.color="var(--malto-text-muted)",a.style.marginBottom="4px",a.style.lineHeight="1.5",a.textContent="Enter your email to receive a one-click sign-in link.";let r=document.createElement("input");r.className="malto-input",r.type="email",r.required=true,r.placeholder="you@company.com",r.value=this.state.authEmail;let o=document.createElement("button");return o.className="malto-button",o.type="submit",o.textContent="Send sign-in link",e.appendChild(a),e.appendChild(r),e.appendChild(o),e.addEventListener("submit",async n=>{n.preventDefault(),o.setAttribute("disabled","true");try{await this.client.startMagicLink({email:r.value.trim()}),this.state.authEmail=r.value.trim(),this.state.authStatus="sent",this.render();}catch(s){this.state.error=s.message,o.removeAttribute("disabled"),this.render();}}),e}viewRoadmap(){let t=document.createElement("div");if(this.state.loading)return t.appendChild(this.skeletonList(3)),t;let e={PLANNED:"Planned",IN_PROGRESS:"In Progress",COMPLETED:"Done"},a=false;for(let r of ["PLANNED","IN_PROGRESS","COMPLETED"]){let o=this.state.roadmap[r]??[],n=document.createElement("div");n.className="malto-roadmap-col";let s=document.createElement("h5");s.textContent=e[r]??r;let d=document.createElement("span");if(d.className="malto-roadmap-count",d.textContent=String(o.length),s.appendChild(d),n.appendChild(s),o.length===0){let l=document.createElement("div");l.className="malto-empty-desc",l.style.padding="8px 0 12px",l.textContent="Nothing here yet.",n.appendChild(l);}else {a=true;for(let l of o)n.appendChild(this.feedbackRow(l));}t.appendChild(n);}return !a&&Object.keys(this.state.roadmap).length===0&&(t.innerHTML="",t.appendChild(this.emptyState("\u{1F5FA}\uFE0F","Empty roadmap","Once admins move items into Planned, In Progress or Done, you'll see them here."))),t}viewChangelog(){let t=document.createElement("div");if(this.state.loading)return t.appendChild(this.skeletonList(2)),t;if(this.state.releases.length===0)return t.appendChild(this.emptyState("\u2728","No updates yet","Check back soon.")),t;for(let e of this.state.releases){let a=document.createElement("div");if(a.className="malto-release",e.publishedAt){let n=document.createElement("span");n.className="malto-release-date",n.textContent=Y(e.publishedAt),a.appendChild(n);}let r=document.createElement("h4");r.textContent=e.title;let o=document.createElement("p");o.textContent=e.body,a.appendChild(r),a.appendChild(o),t.appendChild(a);}return t}viewDetail(){let t=document.createElement("div"),e=this.state.selectedFeedback;if(!e)return t.appendChild(this.emptyState("\u{1F4ED}","Nothing selected","Pick a request from Feed.")),t;let a=document.createElement("button");if(a.className="malto-back",a.innerHTML='<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg> Back',a.addEventListener("click",()=>this.go("list")),t.appendChild(a),t.appendChild(this.feedbackRow(e)),this.allowedViews().includes("comment")){let o=document.createElement("h5");if(o.textContent="Comments",o.style.cssText="margin: 16px 0 8px; font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--malto-text-muted); font-weight: 600;",t.appendChild(o),this.state.loading)t.appendChild(this.skeletonList(2));else if(this.state.comments.length===0){let l=document.createElement("div");l.className="malto-empty-desc",l.style.padding="8px 0 12px",l.textContent="No comments yet \u2014 start the conversation.",t.appendChild(l);}else for(let l of this.state.comments){let m=document.createElement("div");m.className="malto-comment";let f=document.createElement("div");f.className="malto-avatar";let M=$(l.author?.avatarUrl);if(M){let u=document.createElement("img");u.src=M,u.alt="",u.referrerPolicy="no-referrer",u.crossOrigin="anonymous",f.appendChild(u);}else f.textContent=(l.author?.name??"?").charAt(0).toUpperCase();let p=document.createElement("div");p.style.flex="1",p.style.minWidth="0";let y=document.createElement("div"),k=document.createElement("span");k.className="malto-comment-author",k.textContent=l.author?.name??"User";let w=document.createElement("span");w.className="malto-comment-time",w.textContent=R(l.createdAt),y.appendChild(k),y.appendChild(w);let C=document.createElement("div");C.className="malto-comment-body",C.textContent=l.body,p.appendChild(y),p.appendChild(C),m.appendChild(f),m.appendChild(p),t.appendChild(m);}let n=document.createElement("form");n.className="malto-form",n.style.marginTop="12px";let s=document.createElement("textarea");s.className="malto-textarea",s.placeholder="Write a comment",s.required=true;let d=document.createElement("button");d.className="malto-button",d.type="submit",d.textContent="Post comment",n.appendChild(s),n.appendChild(d),n.addEventListener("submit",async l=>{if(l.preventDefault(),!this.state.email){this.go("auth");return}d.setAttribute("disabled","true");try{await this.client.addComment(e.id,s.value.trim()),s.value="",await this.loadComments(e.id);}catch(m){this.state.error=m.message;}finally{d.removeAttribute("disabled"),this.render();}}),t.appendChild(n);}return t}skeletonList(t){let e=document.createElement("div");for(let a=0;a<t;a++){let r=document.createElement("div");r.className="malto-skeleton-row";let o=document.createElement("div");o.className="malto-skeleton",o.style.width="44px",o.style.height="48px",o.style.flex="none";let n=document.createElement("div");n.style.flex="1";let s=document.createElement("div");s.className="malto-skeleton",s.style.height="12px",s.style.width="70%",s.style.marginBottom="6px";let d=document.createElement("div");d.className="malto-skeleton",d.style.height="10px",d.style.width="90%",n.appendChild(s),n.appendChild(d),r.appendChild(o),r.appendChild(n),e.appendChild(r);}return e}emptyState(t,e,a){let r=document.createElement("div");r.className="malto-empty";let o=document.createElement("div");o.className="malto-empty-icon",o.style.fontSize="20px",o.textContent=t;let n=document.createElement("div");n.className="malto-empty-title",n.textContent=e;let s=document.createElement("div");return s.className="malto-empty-desc",s.textContent=a,r.appendChild(o),r.appendChild(n),r.appendChild(s),r}async loadFeedbacks(){this.state.loading=true,this.render();try{this.state.feedbacks=await this.client.listFeedbacks();}catch(t){this.state.error=t.message;}finally{this.state.loading=false,this.render();}}async loadRoadmap(){this.state.loading=true,this.render();try{this.state.roadmap=await this.client.roadmap();}catch(t){this.state.error=t.message;}finally{this.state.loading=false,this.render();}}async loadReleases(){this.state.loading=true,this.render();try{this.state.releases=await this.client.releases();}catch(t){this.state.error=t.message;}finally{this.state.loading=false,this.render();}}async loadComments(t){this.state.loading=true,this.render();try{this.state.comments=await this.client.comments(t);}catch(e){this.state.error=e.message;}finally{this.state.loading=false,this.render();}}async handleVote(t){if(!this.state.email){this.go("auth");return}try{let e=await this.client.vote(t.id);t.hasVoted=e.voted,t.votes=e.votes,this.render();}catch(e){this.state.error=e.message,this.render();}}};function K(i){let t=document.createElement("span");t.className=`malto-status malto-status-${i}`;let e=document.createElement("span");e.className="malto-status-dot",t.appendChild(e);let a=document.createElement("span"),r={PLANNED:"Planned",IN_PROGRESS:"In progress",COMPLETED:"Done",DECLINED:"Declined",UNDER_REVIEW:"Under review",BACKLOG:"Backlog"};return a.textContent=r[i]??i,t.appendChild(a),t}function _(i){return i<1e3?String(i):i<1e4?(i/1e3).toFixed(1).replace(/\.0$/,"")+"k":Math.floor(i/1e3)+"k"}function R(i){let t=Date.now()-new Date(i).getTime(),e=Math.floor(t/1e3);if(e<60)return "just now";let a=Math.floor(e/60);if(a<60)return `${a}m`;let r=Math.floor(a/60);if(r<24)return `${r}h`;let o=Math.floor(r/24);if(o<30)return `${o}d`;let n=Math.floor(o/30);return n<12?`${n}mo`:`${Math.floor(n/12)}y`}function Y(i){try{return new Date(i).toLocaleDateString(void 0,{day:"numeric",month:"short",year:"numeric"})}catch{return i}}function L(i){return i.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function $(i){if(!i||typeof i!="string")return null;let t;try{t=new URL(i,typeof location<"u"?location.href:"https://x");}catch{return null}return t.protocol!=="https:"&&t.protocol!=="http:"?null:t.toString()}var c=null;function rt(i){c&&c.unmount();let t=new v(i);return c=t,t.mount(),t}function nt(){c?.open();}function it(){c?.close();}function st(i){c?.setIdentify(i);}function lt(i){g(i.slice(0,16)),c?.setIdentify(null);}function dt(){c?.unmount(),c=null;}
609
- exports.MaltoApiError=b;exports.MaltoClient=h;exports.MaltoWidget=v;exports.close=it;exports.destroy=dt;exports.identify=st;exports.init=rt;exports.open=nt;exports.reset=lt;return exports;})({});
809
+ `}function U(i){let{r:t,g:e,b:a}=D(i);return {rgb:`${t}, ${e}, ${a}`,contrast:V(t,e,a),tint50:L(t,e,a,.06),tint100:L(t,e,a,.12),tint200:L(t,e,a,.18),shade600:K(t,e,a,-0.18)}}function D(i){let t=i.trim().replace(/^#/,"");return t.length===3&&(t=t.split("").map(e=>e+e).join("")),/^[0-9a-fA-F]{6}$/.test(t)?{r:parseInt(t.slice(0,2),16),g:parseInt(t.slice(2,4),16),b:parseInt(t.slice(4,6),16)}:{r:69,g:47,b:223}}function V(i,t,e){return (.2126*i+.7152*t+.0722*e)/255>.65?"#0f0d23":"#ffffff"}function L(i,t,e,a,o){return `rgba(${i}, ${t}, ${e}, ${a})`}function K(i,t,e,a){let o=n=>Math.max(0,Math.min(255,Math.round(n+255*a))),r=n=>o(n).toString(16).padStart(2,"0");return `#${r(i)}${r(t)}${r(e)}`}var q={"bottom-right":{right:"24px",bottom:"24px"},"bottom-left":{left:"24px",bottom:"24px"},"top-right":{right:"24px",top:"24px"},"top-left":{left:"24px",top:"24px"}},E=class{constructor(t){this.resolvedMode="bubble";this.root=null;this.container=null;this.trigger=null;this.board=null;this.shellEl=null;this.bodyEl=null;this.tabRefs={};this.bannerEl=null;this.initialLoaded=false;if(!t.apiKey)throw new Error("Malto: apiKey is required");this.apiKeyPrefix=t.apiKey.slice(0,16),this.config={apiKey:t.apiKey,apiUrl:t.apiUrl??"https://malto-api-production.up.railway.app",mode:t.mode??"auto",position:t.position??"bottom-right",triggerLabel:t.triggerLabel??"Feedback",primaryColor:t.primaryColor,cssVars:t.cssVars,customCss:t.customCss,radius:t.radius??"md",appearance:t.appearance??"light",zIndex:t.zIndex??2147483600,views:t.views,identify:t.identify,target:t.target,onReady:t.onReady,onError:t.onError};let e=N(this.apiKeyPrefix);this.state={open:false,view:"roadmap",loading:true,error:null,roadmap:{},releases:[],selectedFeedback:null,comments:[],authEmail:"",authStatus:"idle",email:e?.email??null,name:e?.name??null},this.client=new v({apiKey:this.config.apiKey,apiUrl:this.config.apiUrl,getSessionToken:()=>N(this.apiKeyPrefix)?.token??null});}async mount(){try{let t=await this.client.board();this.board=t;let e=this.config.primaryColor||t.widget.primaryColor||t.board.boardThemeColor||"#452fdf";H({primary:e,cssVars:this.config.cssVars,customCss:this.config.customCss,radius:this.config.radius,appearance:this.config.appearance}),this.resolvedMode=this.config.mode==="auto"?t.widget.defaultMode:this.config.mode,this.config.identify&&await this.runIdentify(this.config.identify),this.renderHost(this.resolvedMode),this.ensureInitialLoad(),this.config.onReady?.();}catch(t){this.config.onError?.(t);}}ensureInitialLoad(){this.initialLoaded||(this.initialLoaded=true,this.state.view==="roadmap"?this.loadRoadmap():this.state.view==="changelog"&&this.loadReleases());}unmount(){this.root?.parentElement?.removeChild(this.root),this.trigger?.parentElement?.removeChild(this.trigger),this.root=null,this.trigger=null,this.container=null,this.shellEl=null,this.bodyEl=null,this.tabRefs={},this.bannerEl=null;}open(){this.state.open=true,this.render();}close(){this.state.open=false,this.render();}setIdentify(t){if(!t){y(this.apiKeyPrefix),this.state.email=null,this.state.name=null,this.render();return}this.runIdentify(t);}async runIdentify(t){try{let e=await this.client.identify(t);S(this.apiKeyPrefix,{token:e.sessionToken,expiresAt:e.expiresAt,email:e.user.email,name:e.user.name}),this.state.email=e.user.email,this.state.name=e.user.name,this.render();}catch(e){this.config.onError?.(e);}}renderHost(t){let e=document.createElement("div");if(e.className="malto-root",e.style.setProperty("--malto-z",String(this.config.zIndex)),document.body.appendChild(e),this.root=e,t==="inline"){let a=this.resolveTarget();if(!a){this.config.onError?.(new Error("Malto: inline target not found"));return}let o=document.createElement("div");o.className="malto-root malto-inline",o.style.setProperty("--malto-z",String(this.config.zIndex)),a.appendChild(o),this.container=o,this.state.open=true,this.render();return}if(t==="bubble"){let a=this.buildBubble(),o=q[this.config.position];Object.assign(a.style,o);let r=document.createElement("div");r.className="malto-root",r.style.setProperty("--malto-z",String(this.config.zIndex)),r.appendChild(a),document.body.appendChild(r),this.trigger=r;}else if(t==="trigger"){let a=this.resolveTarget();if(!a){this.config.onError?.(new Error("Malto: trigger target not found"));return}let o=document.createElement("span");o.className="malto-root",o.style.setProperty("--malto-z",String(this.config.zIndex));let r=document.createElement("button");r.className="malto-trigger",r.innerHTML=`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg><span>${T(this.config.triggerLabel)}</span>`,r.addEventListener("click",()=>this.open()),o.appendChild(r),a.appendChild(o),this.trigger=o;}else t==="modal"&&(this.state.open=true);this.render();}buildBubble(){let t=document.createElement("button");return t.className="malto-bubble",t.setAttribute("aria-label",this.config.triggerLabel),t.innerHTML='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>',t.addEventListener("click",()=>{this.state.open?this.close():this.open();}),t}resolveTarget(){return this.config.target?typeof this.config.target=="string"?document.querySelector(this.config.target):this.config.target:null}render(){if(this.root){if(this.resolvedMode==="inline"){if(!this.container)return;(!this.shellEl||this.shellEl.parentElement!==this.container)&&(this.container.innerHTML="",this.shellEl=this.buildShell(),this.container.appendChild(this.shellEl)),this.refreshShell();return}if(!this.state.open){this.root.innerHTML="",this.shellEl=null,this.bodyEl=null,this.tabRefs={},this.bannerEl=null;return}if(!this.shellEl||this.shellEl.parentElement===null){this.root.innerHTML="";let t=document.createElement("div");t.className="malto-overlay",t.addEventListener("click",a=>{a.target===t&&this.close();});let e=document.createElement("div");e.className="malto-modal",this.shellEl=this.buildShell(),e.appendChild(this.shellEl),t.appendChild(e),this.root.appendChild(t);}this.refreshShell();}}buildShell(){let t=document.createElement("div");t.style.display="flex",t.style.flexDirection="column",t.style.height="100%",t.style.minHeight="0",t.appendChild(this.buildHeader()),t.appendChild(this.buildTabs());let e=document.createElement("div");e.className="malto-body",this.bodyEl=e,t.appendChild(e);let a=document.createElement("div");a.className="malto-footer-banner",a.style.display="none";let o=document.createElement("span");o.innerHTML="Sign in to vote, comment, or submit ideas.";let r=document.createElement("button");return r.className="malto-link",r.textContent="Sign in",r.addEventListener("click",()=>this.go("auth")),a.appendChild(o),a.appendChild(r),this.bannerEl=a,t.appendChild(a),t}refreshShell(){for(let[t,e]of Object.entries(this.tabRefs))e?.setAttribute("aria-selected",t===this.state.view?"true":"false");if(this.bodyEl&&(this.bodyEl.innerHTML="",this.bodyEl.appendChild(this.buildView())),this.bannerEl){let t=this.state.view!=="auth"&&!this.state.email;this.bannerEl.style.display=t?"":"none";}}buildHeader(){let t=document.createElement("div");t.className="malto-header";let e=document.createElement("div");e.className="malto-header-meta";let a=document.createElement("div");a.className="malto-board-logo";let o=I(this.board?.board.companyLogoUrl);if(o){let n=document.createElement("img");n.src=o,n.alt="",n.referrerPolicy="no-referrer",n.crossOrigin="anonymous",a.appendChild(n);}else a.textContent=(this.board?.board.companyName??this.board?.board.boardName??"M").charAt(0).toUpperCase();let r=document.createElement("h3");if(r.textContent=this.board?.board.boardName??this.board?.board.companyName??"Feedback",e.appendChild(a),e.appendChild(r),t.appendChild(e),this.resolvedMode!=="inline"){let n=document.createElement("button");n.className="malto-close",n.setAttribute("aria-label","Close"),n.innerHTML='<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>',n.addEventListener("click",()=>this.close()),t.appendChild(n);}return t}buildTabs(){let t=document.createElement("div");t.className="malto-tabs",this.tabRefs={};let e=this.allowedViews();return e.includes("roadmap")&&t.appendChild(this.tabBtn("Roadmap","roadmap")),e.includes("changelog")&&t.appendChild(this.tabBtn("Updates","changelog")),e.includes("submit")&&t.appendChild(this.tabBtn("New","submit")),t}tabBtn(t,e){let a=document.createElement("button");return a.className="malto-tab",a.setAttribute("aria-selected",this.state.view===e?"true":"false"),a.textContent=t,a.addEventListener("click",()=>this.go(e)),this.tabRefs[e]=a,a}go(t){this.state.view=t,this.state.error=null,(t==="roadmap"||t==="changelog"||t==="detail"&&this.state.selectedFeedback)&&(this.state.loading=true),this.render(),t==="roadmap"&&this.loadRoadmap(),t==="changelog"&&this.loadReleases(),t==="detail"&&this.state.selectedFeedback&&this.loadComments(this.state.selectedFeedback.id);}allowedViews(){let t=["roadmap","submit","changelog"],e=this.board?.widget.enabledFeatures??t,a=this.config.views??t;return t.filter(o=>e.includes(o)&&a.includes(o))}buildView(){let t=document.createElement("div");if(this.state.error){let e=document.createElement("div");e.className="malto-error",e.textContent=this.state.error,t.appendChild(e);}switch(this.state.view){case "submit":t.appendChild(this.viewSubmit());break;case "auth":t.appendChild(this.viewAuth());break;case "roadmap":t.appendChild(this.viewRoadmap());break;case "changelog":t.appendChild(this.viewChangelog());break;case "detail":t.appendChild(this.viewDetail());break}return t}feedbackRow(t){let e=document.createElement("div");e.className="malto-item";let a=document.createElement("button");a.className="malto-vote",a.setAttribute("aria-pressed",t.hasVoted?"true":"false");let o=document.createElement("span");o.className="malto-vote-arrow",o.textContent="\u25B2";let r=document.createElement("span");r.className="malto-vote-count",r.textContent=A(t.votes??0),a.appendChild(o),a.appendChild(r),a.addEventListener("click",m=>{m.stopPropagation(),this.handleVote(t);});let n=document.createElement("div");n.className="malto-item-content";let s=document.createElement("h4");if(s.textContent=t.title,n.appendChild(s),t.description){let m=document.createElement("p");m.textContent=t.description,n.appendChild(m);}let l=document.createElement("div");if(l.className="malto-item-meta",t.status&&t.status!=="BACKLOG"){let m=_(t.status);l.appendChild(m);}let d=document.createElement("span");return d.textContent=M(t.createdAt),l.appendChild(d),n.appendChild(l),e.appendChild(a),e.appendChild(n),e.addEventListener("click",()=>{this.state.selectedFeedback=t,this.go("detail");}),e}viewSubmit(){let t=document.createElement("form");t.className="malto-form";let e=document.createElement("input");e.className="malto-input",e.required=true,e.maxLength=200,e.placeholder="What would you like?";let a=document.createElement("textarea");a.className="malto-textarea",a.maxLength=5e3,a.placeholder="Add some context (optional)";let o=document.createElement("button");return o.className="malto-button",o.textContent="Submit feedback",o.type="submit",t.appendChild(e),t.appendChild(a),t.appendChild(o),t.addEventListener("submit",async r=>{if(r.preventDefault(),!this.state.email){this.go("auth");return}o.setAttribute("disabled","true");try{await this.client.createFeedback({title:e.value.trim(),description:a.value.trim()||void 0}),e.value="",a.value="",this.go("roadmap");}catch(n){this.state.error=n.message,o.removeAttribute("disabled"),this.render();}}),t}viewAuth(){let t=document.createElement("div");if(this.state.email){let n=document.createElement("p");n.style.fontSize="13px",n.style.color="var(--malto-text)",n.style.marginBottom="10px",n.innerHTML=`Signed in as <strong>${T(this.state.email)}</strong>`;let s=document.createElement("button");return s.className="malto-secondary",s.textContent="Sign out",s.addEventListener("click",()=>{y(this.apiKeyPrefix),this.state.email=null,this.state.name=null,this.go("roadmap");}),t.appendChild(n),t.appendChild(s),t}if(this.state.authStatus==="sent"){let n=document.createElement("p");n.style.fontSize="13px",n.style.color="var(--malto-text)",n.style.marginBottom="12px",n.style.lineHeight="1.5",n.innerHTML=`We sent a sign-in link to <strong>${T(this.state.authEmail)}</strong>. Open the email and paste the token below.`;let s=document.createElement("input");s.className="malto-input",s.placeholder="Paste token from email";let l=document.createElement("button");l.className="malto-button",l.style.marginTop="8px",l.textContent="Verify",l.addEventListener("click",async()=>{l.setAttribute("disabled","true");try{let m=await this.client.verifyMagicLink(s.value.trim());S(this.apiKeyPrefix,{token:m.sessionToken,expiresAt:m.expiresAt,email:m.user.email,name:m.user.name}),this.state.email=m.user.email,this.state.name=m.user.name,this.state.authStatus="idle",this.go("roadmap");}catch(m){this.state.error=m.message,l.removeAttribute("disabled"),this.render();}});let d=document.createElement("button");return d.className="malto-link",d.style.marginTop="12px",d.style.display="block",d.textContent="Use a different email",d.addEventListener("click",()=>{this.state.authStatus="idle",this.render();}),t.appendChild(n),t.appendChild(s),t.appendChild(l),t.appendChild(d),t}let e=document.createElement("form");e.className="malto-form";let a=document.createElement("p");a.style.fontSize="13px",a.style.color="var(--malto-text-muted)",a.style.marginBottom="4px",a.style.lineHeight="1.5",a.textContent="Enter your email to receive a one-click sign-in link.";let o=document.createElement("input");o.className="malto-input",o.type="email",o.required=true,o.placeholder="you@company.com",o.value=this.state.authEmail;let r=document.createElement("button");return r.className="malto-button",r.type="submit",r.textContent="Send sign-in link",e.appendChild(a),e.appendChild(o),e.appendChild(r),e.addEventListener("submit",async n=>{n.preventDefault(),r.setAttribute("disabled","true");try{await this.client.startMagicLink({email:o.value.trim()}),this.state.authEmail=o.value.trim(),this.state.authStatus="sent",this.render();}catch(s){this.state.error=s.message,r.removeAttribute("disabled"),this.render();}}),e}viewRoadmap(){let t=document.createElement("div");if(t.className="malto-kanban",this.state.loading){for(let o=0;o<4;o++){let r=document.createElement("div");r.className="malto-kanban-col";let n=document.createElement("h5");n.className="malto-kanban-title",n.textContent="Loading",r.appendChild(n),r.appendChild(this.skeletonCards(2)),t.appendChild(r);}return t}let e=[{status:"BACKLOG",title:"Backlog"},{status:"PLANNED",title:"Planned"},{status:"IN_PROGRESS",title:"In Progress"},{status:"UNDER_REVIEW",title:"Under Review"}],a=false;for(let{status:o,title:r}of e){let n=this.state.roadmap[o]??[];n.length>0&&(a=true);let s=document.createElement("div");s.className="malto-kanban-col";let l=document.createElement("div");l.className="malto-kanban-head";let d=document.createElement("h5");d.className="malto-kanban-title",d.textContent=r;let m=document.createElement("span");m.className="malto-kanban-count",m.textContent=G(n.length),l.appendChild(d),l.appendChild(m),s.appendChild(l);let c=document.createElement("div");if(c.className="malto-kanban-list",n.length===0){let u=document.createElement("div");u.className="malto-kanban-empty",u.textContent="Nothing here.",c.appendChild(u);}else for(let u of n)c.appendChild(this.feedbackCard(u));s.appendChild(c),t.appendChild(s);}return a||(t.innerHTML="",t.appendChild(this.emptyState("\u{1F5FA}\uFE0F","Empty roadmap","Once admins move items into Planned, In Progress or Done, you'll see them here."))),t}feedbackCard(t){let e=t.url??"",a=document.createElement(e?"a":"div");a.className="malto-card",e&&(a.href=e,a.target="_blank",a.rel="noopener noreferrer");let o=document.createElement("div");o.className="malto-card-top";let r=document.createElement("span");r.className="malto-card-cat",r.textContent=t.category??"General";let n=document.createElement("span");n.className="malto-card-votes",n.innerHTML=`<svg viewBox="0 0 12 12" width="10" height="10" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 7 6 4 9 7"/></svg><span>${A(t.votes??0)}</span>`,o.appendChild(r),o.appendChild(n),a.appendChild(o);let s=document.createElement("h4");if(s.className="malto-card-title",s.textContent=t.title,a.appendChild(s),t.description){let p=document.createElement("p");p.className="malto-card-desc",p.textContent=t.description,a.appendChild(p);}let l=document.createElement("div");l.className="malto-card-foot";let d=document.createElement("div");d.className="malto-card-who";let m=I(t.author?.avatarUrl),c=document.createElement("span");if(c.className="malto-card-avatar",m){let p=document.createElement("img");p.src=m,p.alt="",p.referrerPolicy="no-referrer",p.crossOrigin="anonymous",c.appendChild(p);}else c.classList.add(`malto-avatar-bg-${W(t.author?.name??t.title)}`),c.textContent=Y(t.author?.name);d.appendChild(c);let u=document.createElement("span");u.className="malto-card-author",u.textContent=t.author?.name??"Anon",d.appendChild(u);let h=document.createElement("span");h.className="malto-card-dot",h.textContent="\xB7",d.appendChild(h);let b=document.createElement("span");b.className="malto-card-time",b.textContent=M(t.createdAt),d.appendChild(b);let f=document.createElement("span");return f.className="malto-card-comments",f.innerHTML=`<svg viewBox="0 0 14 14" width="11" height="11" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 9a1.5 1.5 0 0 1-1.5 1.5H5l-3 3v-9A1.5 1.5 0 0 1 3.5 3h7A1.5 1.5 0 0 1 12 4.5z"/></svg><span>${t.commentCount??0}</span>`,l.appendChild(d),l.appendChild(f),a.appendChild(l),a}skeletonCards(t){let e=document.createElement("div");e.className="malto-kanban-list";for(let a=0;a<t;a++){let o=document.createElement("div");o.className="malto-card malto-card-skeleton";let r=document.createElement("div");r.className="malto-skeleton",r.style.height="14px",r.style.width="60px";let n=document.createElement("div");n.className="malto-skeleton",n.style.height="12px",n.style.width="85%",n.style.marginTop="10px";let s=document.createElement("div");s.className="malto-skeleton",s.style.height="10px",s.style.width="70%",s.style.marginTop="6px",o.appendChild(r),o.appendChild(n),o.appendChild(s),e.appendChild(o);}return e}viewChangelog(){let t=document.createElement("div");if(this.state.loading)return t.appendChild(this.skeletonList(2)),t;if(this.state.releases.length===0)return t.appendChild(this.emptyState("\u2728","No updates yet","Check back soon.")),t;for(let e of this.state.releases){let a=document.createElement("div");if(a.className="malto-release",e.publishedAt){let n=document.createElement("span");n.className="malto-release-date",n.textContent=J(e.publishedAt),a.appendChild(n);}let o=document.createElement("h4");o.textContent=e.title;let r=document.createElement("p");r.textContent=e.body,a.appendChild(o),a.appendChild(r),t.appendChild(a);}return t}viewDetail(){let t=document.createElement("div"),e=this.state.selectedFeedback;if(!e)return t.appendChild(this.emptyState("\u{1F4ED}","Nothing selected","Pick a request from the roadmap.")),t;let a=document.createElement("button");if(a.className="malto-back",a.innerHTML='<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg> Back',a.addEventListener("click",()=>this.go("roadmap")),t.appendChild(a),t.appendChild(this.feedbackRow(e)),this.board?.widget.enabledFeatures.includes("comment")??true){let r=document.createElement("h5");if(r.textContent="Comments",r.style.cssText="margin: 16px 0 8px; font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--malto-text-muted); font-weight: 600;",t.appendChild(r),this.state.loading)t.appendChild(this.skeletonList(2));else if(this.state.comments.length===0){let d=document.createElement("div");d.className="malto-empty-desc",d.style.padding="8px 0 12px",d.textContent="No comments yet \u2014 start the conversation.",t.appendChild(d);}else for(let d of this.state.comments){let m=document.createElement("div");m.className="malto-comment";let c=document.createElement("div");c.className="malto-avatar";let u=I(d.author?.avatarUrl);if(u){let x=document.createElement("img");x.src=u,x.alt="",x.referrerPolicy="no-referrer",x.crossOrigin="anonymous",c.appendChild(x);}else c.textContent=(d.author?.name??"?").charAt(0).toUpperCase();let h=document.createElement("div");h.style.flex="1",h.style.minWidth="0";let b=document.createElement("div"),f=document.createElement("span");f.className="malto-comment-author",f.textContent=d.author?.name??"User";let p=document.createElement("span");p.className="malto-comment-time",p.textContent=M(d.createdAt),b.appendChild(f),b.appendChild(p);let C=document.createElement("div");C.className="malto-comment-body",C.textContent=d.body,h.appendChild(b),h.appendChild(C),m.appendChild(c),m.appendChild(h),t.appendChild(m);}let n=document.createElement("form");n.className="malto-form",n.style.marginTop="12px";let s=document.createElement("textarea");s.className="malto-textarea",s.placeholder="Write a comment",s.required=true;let l=document.createElement("button");l.className="malto-button",l.type="submit",l.textContent="Post comment",n.appendChild(s),n.appendChild(l),n.addEventListener("submit",async d=>{if(d.preventDefault(),!this.state.email){this.go("auth");return}l.setAttribute("disabled","true");try{await this.client.addComment(e.id,s.value.trim()),s.value="",await this.loadComments(e.id);}catch(m){this.state.error=m.message;}finally{l.removeAttribute("disabled"),this.render();}}),t.appendChild(n);}return t}skeletonList(t){let e=document.createElement("div");for(let a=0;a<t;a++){let o=document.createElement("div");o.className="malto-skeleton-row";let r=document.createElement("div");r.className="malto-skeleton",r.style.width="44px",r.style.height="48px",r.style.flex="none";let n=document.createElement("div");n.style.flex="1";let s=document.createElement("div");s.className="malto-skeleton",s.style.height="12px",s.style.width="70%",s.style.marginBottom="6px";let l=document.createElement("div");l.className="malto-skeleton",l.style.height="10px",l.style.width="90%",n.appendChild(s),n.appendChild(l),o.appendChild(r),o.appendChild(n),e.appendChild(o);}return e}emptyState(t,e,a){let o=document.createElement("div");o.className="malto-empty";let r=document.createElement("div");r.className="malto-empty-icon",r.style.fontSize="20px",r.textContent=t;let n=document.createElement("div");n.className="malto-empty-title",n.textContent=e;let s=document.createElement("div");return s.className="malto-empty-desc",s.textContent=a,o.appendChild(r),o.appendChild(n),o.appendChild(s),o}async loadRoadmap(){this.state.loading=true,this.render();try{this.state.roadmap=await this.client.roadmap();}catch(t){this.state.error=t.message;}finally{this.state.loading=false,this.render();}}async loadReleases(){this.state.loading=true,this.render();try{this.state.releases=await this.client.releases();}catch(t){this.state.error=t.message;}finally{this.state.loading=false,this.render();}}async loadComments(t){this.state.loading=true,this.render();try{this.state.comments=await this.client.comments(t);}catch(e){this.state.error=e.message;}finally{this.state.loading=false,this.render();}}async handleVote(t){if(!this.state.email){this.go("auth");return}try{let e=await this.client.vote(t.id);t.hasVoted=e.voted,t.votes=e.votes,this.render();}catch(e){this.state.error=e.message,this.render();}}};function _(i){let t=document.createElement("span");t.className=`malto-status malto-status-${i}`;let e=document.createElement("span");e.className="malto-status-dot",t.appendChild(e);let a=document.createElement("span"),o={PLANNED:"Planned",IN_PROGRESS:"In progress",COMPLETED:"Done",DECLINED:"Declined",UNDER_REVIEW:"Under review",BACKLOG:"Backlog"};return a.textContent=o[i]??i,t.appendChild(a),t}function Y(i){if(!i)return "?";let t=i.trim().split(/\s+/).filter(Boolean);if(t.length===0)return "?";let e=t[0]?.[0]??"",a=t.length>1?t[t.length-1]?.[0]??"":"";return (e+a).toUpperCase()||"?"}function W(i){let t=0;for(let e=0;e<i.length;e++)t=t*31+i.charCodeAt(e)>>>0;return t%8}function G(i){return i<10?`0${i}`:String(i)}function A(i){return i<1e3?String(i):i<1e4?(i/1e3).toFixed(1).replace(/\.0$/,"")+"k":Math.floor(i/1e3)+"k"}function M(i){let t=Date.now()-new Date(i).getTime(),e=Math.floor(t/1e3);if(e<60)return "just now";let a=Math.floor(e/60);if(a<60)return `${a}m`;let o=Math.floor(a/60);if(o<24)return `${o}h`;let r=Math.floor(o/24);if(r<30)return `${r}d`;let n=Math.floor(r/30);return n<12?`${n}mo`:`${Math.floor(n/12)}y`}function J(i){try{return new Date(i).toLocaleDateString(void 0,{day:"numeric",month:"short",year:"numeric"})}catch{return i}}function T(i){return i.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function I(i){if(!i||typeof i!="string")return null;let t;try{t=new URL(i,typeof location<"u"?location.href:"https://x");}catch{return null}return t.protocol!=="https:"&&t.protocol!=="http:"?null:t.toString()}var g=null;function st(i){g&&g.unmount();let t=new E(i);return g=t,t.mount(),t}function lt(){g?.open();}function dt(){g?.close();}function mt(i){g?.setIdentify(i);}function ct(i){y(i.slice(0,16)),g?.setIdentify(null);}function pt(){g?.unmount(),g=null;}
810
+ exports.MaltoApiError=k;exports.MaltoClient=v;exports.MaltoWidget=E;exports.close=dt;exports.destroy=pt;exports.identify=mt;exports.init=st;exports.open=lt;exports.reset=ct;return exports;})({});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@malto/sdk",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Embeddable feedback widget for Malto.io — vanilla JavaScript SDK with zero runtime dependencies.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/malto-io/malto-sdk",