nostr-components 0.2.6 → 0.3.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.
Files changed (138) hide show
  1. package/README.md +105 -185
  2. package/dist/assets/{base-styles-CBypR3FR.js → base-styles-DC0ilu4S.js} +2 -2
  3. package/dist/assets/{base-styles-CBypR3FR.js.map → base-styles-DC0ilu4S.js.map} +1 -1
  4. package/dist/assets/{copy-delegation-C4uvRTVM.js → copy-delegation-CcagQMIW.js} +2 -2
  5. package/dist/assets/{copy-delegation-C4uvRTVM.js.map → copy-delegation-CcagQMIW.js.map} +1 -1
  6. package/dist/assets/{dialog-component-Da1ZIYh9.js → dialog-component-Dqg0QU9I.js} +2 -7
  7. package/dist/assets/dialog-component-Dqg0QU9I.js.map +1 -0
  8. package/dist/assets/{dialog-likers-BjiCHFan.js → dialog-likers-D3c7WIMp.js} +5 -5
  9. package/dist/assets/dialog-likers-D3c7WIMp.js.map +1 -0
  10. package/dist/assets/index.esm-ByUtE_cm.js +2159 -0
  11. package/dist/assets/index.esm-ByUtE_cm.js.map +1 -0
  12. package/dist/assets/nip05-utils-BNBHUmkr.js.map +1 -1
  13. package/dist/assets/nostr-login-service-D2FmscPI.js +2 -0
  14. package/dist/assets/nostr-login-service-D2FmscPI.js.map +1 -0
  15. package/dist/assets/nostr-service-m3Hgc5Xx.js +266 -0
  16. package/dist/assets/nostr-service-m3Hgc5Xx.js.map +1 -0
  17. package/dist/assets/nostr-user-component-XEnanH-d.js +2 -0
  18. package/dist/assets/nostr-user-component-XEnanH-d.js.map +1 -0
  19. package/dist/assets/{pure-jrVhRVpB.js → pure-laCRX9eG.js} +2 -2
  20. package/dist/assets/pure-laCRX9eG.js.map +1 -0
  21. package/dist/assets/theme-C1r1Zw8r.js.map +1 -1
  22. package/dist/assets/{user-resolver-C-E6KdwY.js → user-resolver-DqI5KGh6.js} +2 -2
  23. package/dist/assets/{user-resolver-C-E6KdwY.js.map → user-resolver-DqI5KGh6.js.map} +1 -1
  24. package/dist/assets/utils--bxLbhGF.js.map +1 -1
  25. package/dist/assets/zap-utils-BZcaCsT_.js +2 -0
  26. package/dist/assets/zap-utils-BZcaCsT_.js.map +1 -0
  27. package/dist/components/nostr-comment.es.js +26 -26
  28. package/dist/components/nostr-comment.es.js.map +1 -1
  29. package/dist/components/nostr-dm.es.js +2 -2
  30. package/dist/components/nostr-dm.es.js.map +1 -1
  31. package/dist/components/nostr-follow-button.es.js +6 -7
  32. package/dist/components/nostr-follow-button.es.js.map +1 -1
  33. package/dist/components/nostr-like.es.js +16 -16
  34. package/dist/components/nostr-like.es.js.map +1 -1
  35. package/dist/components/nostr-live-chat.es.js +2 -2
  36. package/dist/components/nostr-live-chat.es.js.map +1 -1
  37. package/dist/components/nostr-post.es.js +19 -19
  38. package/dist/components/nostr-post.es.js.map +1 -1
  39. package/dist/components/nostr-profile-badge.es.js +1 -1
  40. package/dist/components/nostr-profile-badge.es.js.map +1 -1
  41. package/dist/components/nostr-profile.es.js +1 -1
  42. package/dist/components/nostr-profile.es.js.map +1 -1
  43. package/dist/components/nostr-zap.es.js +24 -24
  44. package/dist/components/nostr-zap.es.js.map +1 -1
  45. package/dist/nostr-components.es.js +1 -1
  46. package/dist/nostr-components.umd.js +2644 -305
  47. package/dist/nostr-components.umd.js.map +1 -1
  48. package/package.json +5 -2
  49. package/dist/assets/dark-nostrich-running.gif +0 -0
  50. package/dist/assets/default_dp-NQ3TGrtT.png +0 -0
  51. package/dist/assets/default_dp.png +0 -0
  52. package/dist/assets/default_dp_32.png +0 -0
  53. package/dist/assets/dialog-component-Da1ZIYh9.js.map +0 -1
  54. package/dist/assets/dialog-likers-BjiCHFan.js.map +0 -1
  55. package/dist/assets/light-nostrich-running.gif +0 -0
  56. package/dist/assets/nostr-service-pr_crY62.js +0 -78
  57. package/dist/assets/nostr-service-pr_crY62.js.map +0 -1
  58. package/dist/assets/nostr-user-component-BOdux8_6.js +0 -2
  59. package/dist/assets/nostr-user-component-BOdux8_6.js.map +0 -1
  60. package/dist/assets/pure-jrVhRVpB.js.map +0 -1
  61. package/dist/assets/zap-utils-B1sz0Abx.js +0 -2
  62. package/dist/assets/zap-utils-B1sz0Abx.js.map +0 -1
  63. package/dist/index.d.ts +0 -6
  64. package/dist/nostr-comment.d.ts +0 -4
  65. package/dist/nostr-dm.d.ts +0 -4
  66. package/dist/nostr-follow-button.d.ts +0 -4
  67. package/dist/nostr-like.d.ts +0 -4
  68. package/dist/nostr-live-chat.d.ts +0 -4
  69. package/dist/nostr-post.d.ts +0 -4
  70. package/dist/nostr-profile-badge.d.ts +0 -4
  71. package/dist/nostr-profile.d.ts +0 -4
  72. package/dist/nostr-zap.d.ts +0 -4
  73. package/dist/src/base/base-component/nostr-base-component.d.ts +0 -116
  74. package/dist/src/base/copy-delegation.d.ts +0 -5
  75. package/dist/src/base/dialog-component/dialog-component.d.ts +0 -67
  76. package/dist/src/base/dialog-component/style.d.ts +0 -5
  77. package/dist/src/base/event-component/nostr-event-component.d.ts +0 -53
  78. package/dist/src/base/render-options.d.ts +0 -5
  79. package/dist/src/base/resolvers/event-resolver.d.ts +0 -20
  80. package/dist/src/base/resolvers/user-resolver.d.ts +0 -19
  81. package/dist/src/base/text-row/render-name.d.ts +0 -7
  82. package/dist/src/base/text-row/render-nip05.d.ts +0 -1
  83. package/dist/src/base/text-row/render-npub.d.ts +0 -1
  84. package/dist/src/base/text-row/render-text-row.d.ts +0 -9
  85. package/dist/src/base/user-component/nostr-user-component.d.ts +0 -43
  86. package/dist/src/common/base-styles.d.ts +0 -44
  87. package/dist/src/common/constants.d.ts +0 -4
  88. package/dist/src/common/date-utils.d.ts +0 -9
  89. package/dist/src/common/icons.d.ts +0 -7
  90. package/dist/src/common/nip05-utils.d.ts +0 -13
  91. package/dist/src/common/nostr-service.d.ts +0 -40
  92. package/dist/src/common/theme.d.ts +0 -4
  93. package/dist/src/common/types.d.ts +0 -1
  94. package/dist/src/common/utils.d.ts +0 -34
  95. package/dist/src/index.d.ts +0 -32
  96. package/dist/src/nostr-comment/nostr-comment.d.ts +0 -60
  97. package/dist/src/nostr-comment/render.d.ts +0 -15
  98. package/dist/src/nostr-comment/utils.d.ts +0 -81
  99. package/dist/src/nostr-dm/nostr-dm.d.ts +0 -34
  100. package/dist/src/nostr-dm/render.d.ts +0 -15
  101. package/dist/src/nostr-follow-button/nostr-follow-button.d.ts +0 -24
  102. package/dist/src/nostr-follow-button/render.d.ts +0 -11
  103. package/dist/src/nostr-follow-button/style.d.ts +0 -1
  104. package/dist/src/nostr-like/dialog-help-style.d.ts +0 -1
  105. package/dist/src/nostr-like/dialog-help.d.ts +0 -2
  106. package/dist/src/nostr-like/dialog-likers-style.d.ts +0 -1
  107. package/dist/src/nostr-like/dialog-likers.d.ts +0 -24
  108. package/dist/src/nostr-like/like-utils.d.ts +0 -52
  109. package/dist/src/nostr-like/nostr-like.d.ts +0 -49
  110. package/dist/src/nostr-like/render.d.ts +0 -10
  111. package/dist/src/nostr-like/style.d.ts +0 -1
  112. package/dist/src/nostr-live-chat/nostr-live-chat.d.ts +0 -65
  113. package/dist/src/nostr-live-chat/render.d.ts +0 -31
  114. package/dist/src/nostr-post/nostr-post.d.ts +0 -25
  115. package/dist/src/nostr-post/parse-text.d.ts +0 -8
  116. package/dist/src/nostr-post/render-content.d.ts +0 -5
  117. package/dist/src/nostr-post/render.d.ts +0 -19
  118. package/dist/src/nostr-post/style.d.ts +0 -1
  119. package/dist/src/nostr-profile/nostr-profile.d.ts +0 -24
  120. package/dist/src/nostr-profile/render-stats.d.ts +0 -1
  121. package/dist/src/nostr-profile/render.d.ts +0 -22
  122. package/dist/src/nostr-profile/style.d.ts +0 -1
  123. package/dist/src/nostr-profile-badge/nostr-profile-badge.d.ts +0 -34
  124. package/dist/src/nostr-profile-badge/render.d.ts +0 -11
  125. package/dist/src/nostr-profile-badge/style.d.ts +0 -1
  126. package/dist/src/nostr-zap/dialog-help-style.d.ts +0 -5
  127. package/dist/src/nostr-zap/dialog-help.d.ts +0 -2
  128. package/dist/src/nostr-zap/dialog-zap-style.d.ts +0 -6
  129. package/dist/src/nostr-zap/dialog-zap.d.ts +0 -31
  130. package/dist/src/nostr-zap/dialog-zappers-style.d.ts +0 -1
  131. package/dist/src/nostr-zap/dialog-zappers.d.ts +0 -25
  132. package/dist/src/nostr-zap/nostr-zap.d.ts +0 -45
  133. package/dist/src/nostr-zap/render.d.ts +0 -9
  134. package/dist/src/nostr-zap/style.d.ts +0 -1
  135. package/dist/src/nostr-zap/zap-utils.d.ts +0 -53
  136. package/dist/vite.config.d.ts +0 -2
  137. package/dist/vite.config.esm.d.ts +0 -2
  138. package/dist/vite.config.umd.d.ts +0 -2
@@ -1,4 +1,4 @@
1
- var v=Object.defineProperty;var x=(s,o,e)=>o in s?v(s,o,{enumerable:!0,configurable:!0,writable:!0,value:e}):s[o]=e;var i=(s,o,e)=>x(s,typeof o!="symbol"?o+"":o,e);import{_ as m}from"../assets/preload-helper-D7HrI6pR.js";import{N as y,D as k,c as w,d as F,e as S,g as E}from"../assets/nostr-service-pr_crY62.js";import{g as b,a as g}from"../assets/theme-C1r1Zw8r.js";import{r as N}from"../assets/nip05-utils-BNBHUmkr.js";import"../assets/icons-Dr_d9MII.js";function $({theme:s,recipientNpub:o,recipientName:e,recipientPicture:t,message:r,isLoading:n,isFinding:a,isError:d,errorMessage:h,isSent:p}){const c=n?"Sending...":"Send DM",u=24,f=o?"Type your message here...":"Enter recipient npub/nip05 address...";return`
1
+ var v=Object.defineProperty;var x=(s,o,e)=>o in s?v(s,o,{enumerable:!0,configurable:!0,writable:!0,value:e}):s[o]=e;var i=(s,o,e)=>x(s,typeof o!="symbol"?o+"":o,e);import{_ as m}from"../assets/preload-helper-D7HrI6pR.js";import{N as y,D as k,c as w,d as F,e as S,g as E}from"../assets/nostr-service-m3Hgc5Xx.js";import{g as b,a as g}from"../assets/theme-C1r1Zw8r.js";import{r as N}from"../assets/nip05-utils-BNBHUmkr.js";import"../assets/icons-Dr_d9MII.js";function $({theme:s,recipientNpub:o,recipientName:e,recipientPicture:t,message:r,isLoading:n,isFinding:a,isError:d,errorMessage:h,isSent:p}){const c=n?"Sending...":"Send DM",u=24,f=o?"Type your message here...":"Enter recipient npub/nip05 address...";return`
2
2
  ${D(s)}
3
3
  <div class="nostr-dm-container ${d?"nostr-dm-error":""}">
4
4
  <div class="nostr-dm-header">
@@ -213,5 +213,5 @@ var v=Object.defineProperty;var x=(s,o,e)=>o in s?v(s,o,{enumerable:!0,configura
213
213
  padding: 0 16px 16px;
214
214
  }
215
215
  </style>
216
- `}function l(s,o,e){s.getAttribute("debug")==="true"&&(e?console.log(`[NostrDm] ${o}`,e):console.log(`[NostrDm] ${o}`))}class R extends HTMLElement{constructor(){super();i(this,"rendered",!1);i(this,"nostrService",y.getInstance());i(this,"theme","light");i(this,"recipientNpub",null);i(this,"recipientNip05",null);i(this,"recipientName",null);i(this,"recipientPicture",null);i(this,"recipientPubkey",null);i(this,"message","");i(this,"isLoading",!1);i(this,"isFinding",!1);i(this,"isError",!1);i(this,"errorMessage","");i(this,"isSent",!1);i(this,"boundHandleFind",null);i(this,"boundHandleSend",null);i(this,"boundHandleTextareaChange",null);i(this,"getRelays",()=>{const e=this.getAttribute("relays");return e?e.split(","):k});i(this,"getTheme",async()=>{this.theme="light";const e=this.getAttribute("theme");if(e){if(!["light","dark"].includes(e))throw new Error(`Invalid theme '${e}'. Accepted values are 'light', 'dark'`);this.theme=e}});i(this,"getRecipient",()=>{const e=this.getAttribute("nip05");if(e){this.recipientNip05=e,this.lookupRecipientByNip05();return}const t=this.getAttribute("recipient-npub");t&&(this.recipientNpub=t,this.lookupRecipient())});this.attachShadow({mode:"open"})}connectedCallback(){this.rendered||(this.rendered=!0,this.getTheme(),this.getRecipient(),this.nostrService.connectToNostr(this.getRelays()),this.render())}static get observedAttributes(){return["relays","recipient-npub","nip05","theme","debug"]}attributeChangedCallback(e,t,r){e==="relays"&&this.nostrService.connectToNostr(this.getRelays()),e==="theme"&&this.getTheme(),e==="nip05"&&r&&(this.recipientNip05=r,this.lookupRecipientByNip05()),e==="recipient-npub"&&r&&(this.recipientNpub=r,this.lookupRecipient()),this.render()}async lookupRecipient(e){const t=e||this.recipientNpub;if(t){this.isFinding=!0,this.render();try{const n=this.nostrService.getNDK().getUser({npub:t});await n.fetchProfile(),n.profile?(this.recipientName=n.profile.displayName||n.profile.name||"Unknown",this.recipientPicture=n.profile.image||null,this.recipientPubkey=n.pubkey,this.recipientNpub=t):(this.recipientName="Unknown",this.recipientPicture=null,this.recipientPubkey=n.pubkey,this.recipientNpub=t)}catch(r){this.isError=!0,this.errorMessage=`Failed to find recipient: ${r.message}`}finally{this.isFinding=!1,this.render()}}}async lookupRecipientByNip05(e){const t=e||this.recipientNip05;if(t){this.isFinding=!0,this.render();try{const r=await N(t);if(!r)throw new Error("Failed to resolve nip05");const n=w.npubEncode(r);await this.lookupRecipient(n)}catch(r){this.isError=!0,this.errorMessage=`Failed to resolve nip05: ${r.message}`}finally{this.isFinding=!1,this.render()}}}async handleFindClick(){const e=this.shadowRoot.querySelector(".nostr-dm-npub-input");if(!e||!e.value){this.isError=!0,this.errorMessage="Please enter a valid npub",this.render();return}const t=e.value.trim();t.includes("@")?await this.lookupRecipientByNip05(t):await this.lookupRecipient(t)}async handleSendClick(){if(l(this,"Send button clicked!"),!this.recipientPubkey||!this.message.trim()){this.isError=!0,this.errorMessage=this.recipientPubkey?"Please enter a message":"Recipient not found",this.render();return}if(this.isError=!1,this.isSent=!1,this.isLoading=!0,this.render(),!this.nostrService.hasSigner()){this.isError=!0,this.errorMessage="No Nostr signer available. Please ensure your Nostr extension is installed or provide a private key.",this.isLoading=!1,this.render();return}let e=null;if(typeof window<"u"&&window.nostr)e=new F;else if(typeof localStorage<"u"){const t=localStorage.getItem("nostr_nsec");if(t){const{NDKPrivateKeySigner:r}=await m(async()=>{const{NDKPrivateKeySigner:n}=await import("../assets/nostr-service-pr_crY62.js").then(a=>a.k);return{NDKPrivateKeySigner:n}},[]);e=new r(t)}}if(!e){this.isError=!0,this.errorMessage="Failed to create signer. Please ensure your Nostr signer (extension or private key) is configured.",this.render();return}this.render();try{const t=this.nostrService.getNDK();t.signer=e;const{nip04:r}=await m(async()=>{const{nip04:d}=await import("../assets/nostr-service-pr_crY62.js").then(h=>h.j);return{nip04:d}},[]),n=new S(t,{kind:E.EncryptedDirectMessage,tags:[["p",this.recipientPubkey]],created_at:Math.floor(Date.now()/1e3)});if(typeof window<"u"&&window.nostr){const d=await window.nostr.nip04.encrypt(this.recipientPubkey,this.message.trim());n.content=d}else if(typeof localStorage<"u"){const d=localStorage.getItem("nostr_nsec");if(!d)throw new Error("No private key available");const{nip19:h}=await m(async()=>{const{nip19:c}=await import("../assets/nostr-service-pr_crY62.js").then(u=>u.j);return{nip19:c}},[]);let p=d;if(d.startsWith("nsec"))try{p=h.decode(d).data}catch(c){throw console.error("Failed to decode nsec:",c),new Error("Invalid private key format")}try{n.content=await r.encrypt(p,this.recipientPubkey,this.message.trim())}catch(c){throw console.error("Encryption error:",c),new Error(`Encryption failed: ${c.message}`)}}l(this,"Sending encrypted DM:",{to:this.recipientPubkey,encryptedContent:n.content}),await n.publish(),l(this,"DM sent with encrypted content:",n),this.isSent=!0,this.message="";const a=this.shadowRoot.querySelector(".nostr-dm-textarea");a&&(a.value="")}catch(t){this.isError=!0,this.errorMessage=`Failed to send message: ${t.message}`,this.isSent=!1}finally{this.isLoading=!1,this.isFinding=!1,this.render()}}handleTextareaChange(e){const t=e.target;this.message=t.value}attachEventListeners(){const e=this.shadowRoot.querySelector(".nostr-dm-find-btn");e?(this.boundHandleFind&&e.removeEventListener("click",this.boundHandleFind),this.boundHandleFind=this.handleFindClick.bind(this),e.addEventListener("click",this.boundHandleFind),l(this,"Find button event listener attached")):l(this,"Find button not found in DOM");const t=this.shadowRoot.querySelector(".nostr-dm-send-btn");t?(l(this,"Send button found, disabled:",t.hasAttribute("disabled")),this.boundHandleSend&&t.removeEventListener("click",this.boundHandleSend),this.boundHandleSend=this.handleSendClick.bind(this),t.addEventListener("click",this.boundHandleSend),this.recipientPubkey&&!this.isLoading&&t.removeAttribute("disabled"),l(this,"Send button event listener attached")):l(this,"Send button not found in DOM");const r=this.shadowRoot.querySelector(".nostr-dm-textarea");r&&(this.boundHandleTextareaChange&&r.removeEventListener("input",this.boundHandleTextareaChange),this.boundHandleTextareaChange=this.handleTextareaChange.bind(this),r.addEventListener("input",this.boundHandleTextareaChange));const n=this.shadowRoot.querySelector(".nostr-dm-npub-input");n&&n.addEventListener("keydown",a=>{a.key==="Enter"&&this.handleFindClick()})}disconnectedCallback(){var n,a,d;const e=(n=this.shadowRoot)==null?void 0:n.querySelector(".nostr-dm-find-btn");e&&this.boundHandleFind&&e.removeEventListener("click",this.boundHandleFind);const t=(a=this.shadowRoot)==null?void 0:a.querySelector(".nostr-dm-send-btn");t&&this.boundHandleSend&&t.removeEventListener("click",this.boundHandleSend);const r=(d=this.shadowRoot)==null?void 0:d.querySelector(".nostr-dm-textarea");r&&this.boundHandleTextareaChange&&r.removeEventListener("input",this.boundHandleTextareaChange)}render(){l(this,"Rendering with state:",{recipientNpub:this.recipientNpub,recipientPubkey:this.recipientPubkey,message:this.message?"[message content]":"[empty]",isLoading:this.isLoading,isFinding:this.isFinding,isError:this.isError,isSent:this.isSent});const e={theme:this.theme,recipientNpub:this.recipientNpub,recipientName:this.recipientName,recipientPicture:this.recipientPicture,message:this.message,isLoading:this.isLoading,isFinding:this.isFinding,isError:this.isError,errorMessage:this.errorMessage,isSent:this.isSent};this.shadowRoot.innerHTML=$(e),this.attachEventListeners()}}customElements.define("nostr-dm",R);
216
+ `}function l(s,o,e){s.getAttribute("debug")==="true"&&(e?console.log(`[NostrDm] ${o}`,e):console.log(`[NostrDm] ${o}`))}class R extends HTMLElement{constructor(){super();i(this,"rendered",!1);i(this,"nostrService",y.getInstance());i(this,"theme","light");i(this,"recipientNpub",null);i(this,"recipientNip05",null);i(this,"recipientName",null);i(this,"recipientPicture",null);i(this,"recipientPubkey",null);i(this,"message","");i(this,"isLoading",!1);i(this,"isFinding",!1);i(this,"isError",!1);i(this,"errorMessage","");i(this,"isSent",!1);i(this,"boundHandleFind",null);i(this,"boundHandleSend",null);i(this,"boundHandleTextareaChange",null);i(this,"getRelays",()=>{const e=this.getAttribute("relays");return e?e.split(","):k});i(this,"getTheme",async()=>{this.theme="light";const e=this.getAttribute("theme");if(e){if(!["light","dark"].includes(e))throw new Error(`Invalid theme '${e}'. Accepted values are 'light', 'dark'`);this.theme=e}});i(this,"getRecipient",()=>{const e=this.getAttribute("nip05");if(e){this.recipientNip05=e,this.lookupRecipientByNip05();return}const t=this.getAttribute("recipient-npub");t&&(this.recipientNpub=t,this.lookupRecipient())});this.attachShadow({mode:"open"})}connectedCallback(){this.rendered||(this.rendered=!0,this.getTheme(),this.getRecipient(),this.nostrService.connectToNostr(this.getRelays()),this.render())}static get observedAttributes(){return["relays","recipient-npub","nip05","theme","debug"]}attributeChangedCallback(e,t,r){e==="relays"&&this.nostrService.connectToNostr(this.getRelays()),e==="theme"&&this.getTheme(),e==="nip05"&&r&&(this.recipientNip05=r,this.lookupRecipientByNip05()),e==="recipient-npub"&&r&&(this.recipientNpub=r,this.lookupRecipient()),this.render()}async lookupRecipient(e){const t=e||this.recipientNpub;if(t){this.isFinding=!0,this.render();try{const n=this.nostrService.getNDK().getUser({npub:t});await n.fetchProfile(),n.profile?(this.recipientName=n.profile.displayName||n.profile.name||"Unknown",this.recipientPicture=n.profile.image||null,this.recipientPubkey=n.pubkey,this.recipientNpub=t):(this.recipientName="Unknown",this.recipientPicture=null,this.recipientPubkey=n.pubkey,this.recipientNpub=t)}catch(r){this.isError=!0,this.errorMessage=`Failed to find recipient: ${r.message}`}finally{this.isFinding=!1,this.render()}}}async lookupRecipientByNip05(e){const t=e||this.recipientNip05;if(t){this.isFinding=!0,this.render();try{const r=await N(t);if(!r)throw new Error("Failed to resolve nip05");const n=w.npubEncode(r);await this.lookupRecipient(n)}catch(r){this.isError=!0,this.errorMessage=`Failed to resolve nip05: ${r.message}`}finally{this.isFinding=!1,this.render()}}}async handleFindClick(){const e=this.shadowRoot.querySelector(".nostr-dm-npub-input");if(!e||!e.value){this.isError=!0,this.errorMessage="Please enter a valid npub",this.render();return}const t=e.value.trim();t.includes("@")?await this.lookupRecipientByNip05(t):await this.lookupRecipient(t)}async handleSendClick(){if(l(this,"Send button clicked!"),!this.recipientPubkey||!this.message.trim()){this.isError=!0,this.errorMessage=this.recipientPubkey?"Please enter a message":"Recipient not found",this.render();return}if(this.isError=!1,this.isSent=!1,this.isLoading=!0,this.render(),!this.nostrService.hasSigner()){this.isError=!0,this.errorMessage="No Nostr signer available. Please ensure your Nostr extension is installed or provide a private key.",this.isLoading=!1,this.render();return}let e=null;if(typeof window<"u"&&window.nostr)e=new F;else if(typeof localStorage<"u"){const t=localStorage.getItem("nostr_nsec");if(t){const{NDKPrivateKeySigner:r}=await m(async()=>{const{NDKPrivateKeySigner:n}=await import("../assets/nostr-service-m3Hgc5Xx.js").then(a=>a.k);return{NDKPrivateKeySigner:n}},[]);e=new r(t)}}if(!e){this.isError=!0,this.errorMessage="Failed to create signer. Please ensure your Nostr signer (extension or private key) is configured.",this.render();return}this.render();try{const t=this.nostrService.getNDK();t.signer=e;const{nip04:r}=await m(async()=>{const{nip04:d}=await import("../assets/nostr-service-m3Hgc5Xx.js").then(h=>h.j);return{nip04:d}},[]),n=new S(t,{kind:E.EncryptedDirectMessage,tags:[["p",this.recipientPubkey]],created_at:Math.floor(Date.now()/1e3)});if(typeof window<"u"&&window.nostr){const d=await window.nostr.nip04.encrypt(this.recipientPubkey,this.message.trim());n.content=d}else if(typeof localStorage<"u"){const d=localStorage.getItem("nostr_nsec");if(!d)throw new Error("No private key available");const{nip19:h}=await m(async()=>{const{nip19:c}=await import("../assets/nostr-service-m3Hgc5Xx.js").then(u=>u.j);return{nip19:c}},[]);let p=d;if(d.startsWith("nsec"))try{p=h.decode(d).data}catch(c){throw console.error("Failed to decode nsec:",c),new Error("Invalid private key format")}try{n.content=await r.encrypt(p,this.recipientPubkey,this.message.trim())}catch(c){throw console.error("Encryption error:",c),new Error(`Encryption failed: ${c.message}`)}}l(this,"Sending encrypted DM:",{to:this.recipientPubkey,encryptedContent:n.content}),await n.publish(),l(this,"DM sent with encrypted content:",n),this.isSent=!0,this.message="";const a=this.shadowRoot.querySelector(".nostr-dm-textarea");a&&(a.value="")}catch(t){this.isError=!0,this.errorMessage=`Failed to send message: ${t.message}`,this.isSent=!1}finally{this.isLoading=!1,this.isFinding=!1,this.render()}}handleTextareaChange(e){const t=e.target;this.message=t.value}attachEventListeners(){const e=this.shadowRoot.querySelector(".nostr-dm-find-btn");e?(this.boundHandleFind&&e.removeEventListener("click",this.boundHandleFind),this.boundHandleFind=this.handleFindClick.bind(this),e.addEventListener("click",this.boundHandleFind),l(this,"Find button event listener attached")):l(this,"Find button not found in DOM");const t=this.shadowRoot.querySelector(".nostr-dm-send-btn");t?(l(this,"Send button found, disabled:",t.hasAttribute("disabled")),this.boundHandleSend&&t.removeEventListener("click",this.boundHandleSend),this.boundHandleSend=this.handleSendClick.bind(this),t.addEventListener("click",this.boundHandleSend),this.recipientPubkey&&!this.isLoading&&t.removeAttribute("disabled"),l(this,"Send button event listener attached")):l(this,"Send button not found in DOM");const r=this.shadowRoot.querySelector(".nostr-dm-textarea");r&&(this.boundHandleTextareaChange&&r.removeEventListener("input",this.boundHandleTextareaChange),this.boundHandleTextareaChange=this.handleTextareaChange.bind(this),r.addEventListener("input",this.boundHandleTextareaChange));const n=this.shadowRoot.querySelector(".nostr-dm-npub-input");n&&n.addEventListener("keydown",a=>{a.key==="Enter"&&this.handleFindClick()})}disconnectedCallback(){var n,a,d;const e=(n=this.shadowRoot)==null?void 0:n.querySelector(".nostr-dm-find-btn");e&&this.boundHandleFind&&e.removeEventListener("click",this.boundHandleFind);const t=(a=this.shadowRoot)==null?void 0:a.querySelector(".nostr-dm-send-btn");t&&this.boundHandleSend&&t.removeEventListener("click",this.boundHandleSend);const r=(d=this.shadowRoot)==null?void 0:d.querySelector(".nostr-dm-textarea");r&&this.boundHandleTextareaChange&&r.removeEventListener("input",this.boundHandleTextareaChange)}render(){l(this,"Rendering with state:",{recipientNpub:this.recipientNpub,recipientPubkey:this.recipientPubkey,message:this.message?"[message content]":"[empty]",isLoading:this.isLoading,isFinding:this.isFinding,isError:this.isError,isSent:this.isSent});const e={theme:this.theme,recipientNpub:this.recipientNpub,recipientName:this.recipientName,recipientPicture:this.recipientPicture,message:this.message,isLoading:this.isLoading,isFinding:this.isFinding,isError:this.isError,errorMessage:this.errorMessage,isSent:this.isSent};this.shadowRoot.innerHTML=$(e),this.attachEventListeners()}}customElements.define("nostr-dm",R);
217
217
  //# sourceMappingURL=nostr-dm.es.js.map
@@ -1 +1 @@
1
- {"version":3,"mappings":"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","names":["renderDm","theme","recipientNpub","recipientName","recipientPicture","message","isLoading","isFinding","isError","errorMessage","isSent","buttonText","iconSize","placeholderText","getDmStyles","getNostrLogo","getLoadingNostrich","debug","component","data","NostrDm","__publicField","NostrService","userRelays","DEFAULT_RELAYS","userTheme","nip05Attr","name","_oldValue","newValue","npub","targetNpub","user","err","nip05","targetNip05","pubkeyHex","resolveNip05","nip19","npubInput","entered","signer","NDKNip07Signer","stored","NDKPrivateKeySigner","__vitePreload","n","ndk","nip04","event","NDKEvent","NDKKind","encryptedContent","privateKeyHex","nip192","privateKey","e","encErr","textarea","findButton","sendButton","_a","_b","_c","renderOptions"],"ignoreList":[],"sources":["../../src/nostr-dm/render.ts","../../src/nostr-dm/nostr-dm.ts"],"sourcesContent":["import { Theme } from \"../common/types\";\nimport { getLoadingNostrich, getNostrLogo } from \"../common/theme\";\n\nexport interface RenderDmOptions {\n theme: Theme;\n recipientNpub: string | null;\n recipientName: string | null;\n recipientPicture: string | null;\n message: string;\n isLoading: boolean;\n isFinding: boolean;\n isError: boolean;\n errorMessage: string;\n isSent: boolean;\n}\n\nexport function renderDm({\n theme,\n recipientNpub,\n recipientName,\n recipientPicture,\n message,\n isLoading,\n isFinding,\n isError,\n errorMessage,\n isSent,\n}: RenderDmOptions): string {\n const buttonText = isLoading ? \"Sending...\" : \"Send DM\";\n const iconSize = 24;\n const placeholderText = recipientNpub\n ? \"Type your message here...\"\n : \"Enter recipient npub/nip05 address...\";\n\n return `\n ${getDmStyles(theme)}\n <div class=\"nostr-dm-container ${isError ? \"nostr-dm-error\" : \"\"}\">\n <div class=\"nostr-dm-header\">\n ${\n recipientNpub && recipientName\n ? `\n <div class=\"nostr-dm-recipient\">\n <img \n src=\"${recipientPicture || \"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23ccc' d='M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z'/%3E%3C/svg%3E\"}\" \n alt=\"${recipientName}\" \n class=\"nostr-dm-recipient-avatar\"\n onerror=\"this.onerror=null; this.src='data:image/svg+xml,%3Csvg xmlns=\\'http://www.w3.org/2000/svg\\' viewBox=\\'0 0 24 24\\'%3E%3Cpath fill=\\'%23ccc\\' d=\\'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z\\'/%3E%3C/svg%3E';\"\n />\n <span class=\"nostr-dm-recipient-name\">${recipientName}</span>\n </div>\n `\n : `\n <div class=\"nostr-dm-recipient-placeholder\">\n ${getNostrLogo(iconSize, iconSize)}\n <span>Nostr Direct Message</span>\n </div>\n `\n }\n </div>\n\n <div class=\"nostr-dm-content\">\n ${\n !recipientNpub\n ? `\n <div class=\"nostr-dm-npub-input-container\">\n <input type=\"text\" class=\"nostr-dm-npub-input\" placeholder=\"Enter recipient's npub/nip05 address...\" />\n <button class=\"nostr-dm-find-btn\" ${isFinding ? \"disabled\" : \"\"}>\n ${\n isFinding\n ? `${getLoadingNostrich()} <span>Finding...</span>`\n : `${getNostrLogo(iconSize, iconSize)} <span>Find</span>`\n }\n </button>\n </div>\n `\n : \"\"\n }\n \n <textarea \n class=\"nostr-dm-textarea\" \n placeholder=\"${placeholderText}\"\n ${!recipientNpub ? \"disabled\" : \"\"}\n >${message}</textarea>\n \n <div class=\"nostr-dm-actions\">\n <button class=\"nostr-dm-send-btn\" ${!recipientNpub || isLoading ? \"disabled\" : \"\"}>\n ${\n isLoading\n ? `${getLoadingNostrich()} <span>Sending...</span>`\n : `${getNostrLogo(iconSize, iconSize)} <span>${buttonText}</span>`\n }\n </button>\n </div>\n </div>\n\n ${isError ? `<small class=\"nostr-dm-error-message\">${errorMessage}</small>` : \"\"}\n ${isSent ? `<small class=\"nostr-dm-success-message\">Message sent successfully!</small>` : \"\"}\n </div>\n `;\n}\n\nexport function getDmStyles(theme: Theme): string {\n return `\n <style>\n :host {\n --nstrc-dm-background-dark: #222222;\n --nstrc-dm-background-light: #FFFFFF;\n --nstrc-dm-text-color-dark: #FFFFFF;\n --nstrc-dm-text-color-light: #000000;\n --nstrc-dm-border-dark: 1px solid #444444;\n --nstrc-dm-border-light: 1px solid #DDDDDD;\n --nstrc-dm-input-background-dark: #333333;\n --nstrc-dm-input-background-light: #F9F9F9;\n --nstrc-dm-button-background-dark: #000000;\n --nstrc-dm-button-background-light: #FFFFFF;\n --nstrc-dm-button-hover-dark: #333333;\n --nstrc-dm-button-hover-light: #F0F0F0;\n --nstrc-dm-button-text-dark: #FFFFFF;\n --nstrc-dm-button-text-light: #000000;\n --nstrc-dm-error-color: #FF4D4F;\n --nstrc-dm-success-color: #52C41A;\n --nstrc-dm-border-radius: 8px;\n \n --nstrc-dm-background: var(--nstrc-dm-background-${theme});\n --nstrc-dm-text-color: var(--nstrc-dm-text-color-${theme});\n --nstrc-dm-border: var(--nstrc-dm-border-${theme});\n --nstrc-dm-input-background: var(--nstrc-dm-input-background-${theme});\n --nstrc-dm-button-background: var(--nstrc-dm-button-background-${theme});\n --nstrc-dm-button-hover: var(--nstrc-dm-button-hover-${theme});\n --nstrc-dm-button-text: var(--nstrc-dm-button-text-${theme});\n }\n\n .nostr-dm-container {\n display: flex;\n flex-direction: column;\n font-family: var(--nostrc-font-family-primary);\n max-width: 500px;\n width: 100%;\n box-sizing: border-box;\n border-radius: var(--nstrc-dm-border-radius);\n border: var(--nstrc-dm-border);\n background-color: var(--nstrc-dm-background);\n color: var(--nstrc-dm-text-color);\n overflow: hidden;\n }\n\n .nostr-dm-header {\n padding: 12px 16px;\n border-bottom: var(--nstrc-dm-border);\n display: flex;\n align-items: center;\n }\n\n .nostr-dm-recipient, .nostr-dm-recipient-placeholder {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .nostr-dm-recipient-avatar {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n object-fit: cover;\n }\n\n .nostr-dm-recipient-name {\n font-weight: 600;\n font-size: 16px;\n }\n\n .nostr-dm-content {\n padding: 16px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .nostr-dm-npub-input-container {\n display: flex;\n gap: 8px;\n }\n\n .nostr-dm-npub-input {\n flex: 1;\n padding: 10px;\n box-sizing: border-box;\n max-width: 100%;\n border-radius: 4px;\n border: var(--nstrc-dm-border);\n background-color: var(--nstrc-dm-input-background);\n color: var(--nstrc-dm-text-color);\n }\n\n .nostr-dm-find-btn {\n padding: 10px 16px;\n border-radius: 4px;\n border: var(--nstrc-dm-border);\n background-color: var(--nstrc-dm-button-background);\n color: var(--nstrc-dm-button-text);\n cursor: pointer;\n }\n\n .nostr-dm-find-btn:hover {\n background-color: var(--nstrc-dm-button-hover);\n }\n\n .nostr-dm-textarea {\n width: 100%;\n min-height: 100px;\n box-sizing: border-box;\n padding: 12px;\n border-radius: 4px;\n border: var(--nstrc-dm-border);\n background-color: var(--nstrc-dm-input-background);\n color: var(--nstrc-dm-text-color);\n font-family: var(--nostrc-font-family-primary);\n resize: vertical;\n }\n\n .nostr-dm-textarea:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .nostr-dm-actions {\n display: flex;\n justify-content: flex-end;\n }\n\n .nostr-dm-send-btn {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 16px;\n border-radius: 4px;\n border: var(--nstrc-dm-border);\n background-color: var(--nstrc-dm-button-background);\n color: var(--nstrc-dm-button-text);\n cursor: pointer;\n }\n\n .nostr-dm-send-btn:hover:not(:disabled) {\n background-color: var(--nstrc-dm-button-hover);\n }\n\n .nostr-dm-send-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .nostr-dm-send-btn svg {\n width: 24px;\n height: 24px;\n fill: currentColor;\n }\n\n .nostr-dm-error-message {\n color: var(--nstrc-dm-error-color);\n font-size: 14px;\n padding: 0 16px 16px;\n }\n\n .nostr-dm-success-message {\n color: var(--nstrc-dm-success-color);\n font-size: 14px;\n padding: 0 16px 16px;\n }\n </style>\n `;\n}\n","/**\n * <nostr-dm>\n * Attributes:\n * - recipient-npub (optional) : pre-set npub of recipient\n * - nip05 (optional) : user@domain nip-05 identifier (alternative to recipient-npub)\n * - relays (optional) : comma-separated relay URLs (defaults to common public set)\n * - theme (optional) : \"light\" | \"dark\" (default \"light\")\n * - debug (optional) : \"true\" | \"false\" - whether to log debug messages (default \"false\")\n *\n * Behaviour:\n * • If neither recipient-npub nor nip05 is supplied the component shows an input + Find button.\n * • Entering an npub then clicking Find performs profile lookup; during lookup the Find button shows\n * spinner/“Finding…”. On success the UI switches to DM compose view.\n * • If nip05 attribute is provided we first resolve it to a pubkey via nip05 well-known file then look\n * up the profile as usual.\n */\nimport { NDKNip07Signer, NDKEvent, NDKKind } from \"@nostr-dev-kit/ndk\";\nimport { DEFAULT_RELAYS } from \"../common/constants\";\nimport { Theme } from \"../common/types\";\nimport { renderDm, RenderDmOptions } from \"./render\";\nimport { nip19 } from \"nostr-tools\";\nimport { NostrService } from \"../common/nostr-service\";\n\n// ---------------------------------------------------------------------------\n// nip05 resolution helper – very lightweight fetch to /.well-known/nostr.json\n// ---------------------------------------------------------------------------\n// Import the resolveNip05 function from our common utils\nimport { resolveNip05 } from '../common/nip05-utils';\n\n/**\n * Debug utility that only logs in development mode or when debug attribute is set\n * @param message The message to log\n * @param data Additional data to log\n */\nfunction debug(component: NostrDm, message: string, data?: any) {\n // Check if we're in development environment or debug attribute is true\n const isDev = process.env.NODE_ENV === 'development';\n const isDebug = component.getAttribute('debug') === 'true';\n \n if (isDev || isDebug) {\n if (data) {\n console.log(`[NostrDm] ${message}`, data);\n } else {\n console.log(`[NostrDm] ${message}`);\n }\n }\n}\n\n\nexport default class NostrDm extends HTMLElement {\n private rendered: boolean = false;\n private nostrService: NostrService = NostrService.getInstance();\n\n private theme: Theme = \"light\";\n private recipientNpub: string | null = null;\n private recipientNip05: string | null = null;\n private recipientName: string | null = null;\n private recipientPicture: string | null = null;\n private recipientPubkey: string | null = null;\n private message: string = \"\";\n\n // isLoading -> sending DM, isFinding -> looking up recipient\n private isLoading: boolean = false;\n private isFinding: boolean = false;\n private isError: boolean = false;\n private errorMessage: string = \"\";\n private isSent: boolean = false;\n\n // Event handlers\n private boundHandleFind: (() => void) | null = null;\n private boundHandleSend: (() => void) | null = null;\n private boundHandleTextareaChange: ((e: Event) => void) | null = null;\n\n constructor() {\n super();\n this.attachShadow({ mode: \"open\" });\n }\n\n getRelays = () => {\n const userRelays = this.getAttribute(\"relays\");\n if (userRelays) {\n return userRelays.split(\",\");\n }\n return DEFAULT_RELAYS;\n };\n\n getTheme = async () => {\n this.theme = \"light\";\n\n const userTheme = this.getAttribute(\"theme\");\n\n if (userTheme) {\n const isValidTheme = [\"light\", \"dark\"].includes(userTheme);\n\n if (!isValidTheme) {\n throw new Error(\n `Invalid theme '${userTheme}'. Accepted values are 'light', 'dark'`\n );\n }\n\n this.theme = userTheme as Theme;\n }\n };\n\n getRecipient = () => {\n const nip05Attr = this.getAttribute(\"nip05\");\n if (nip05Attr) {\n this.recipientNip05 = nip05Attr;\n this.lookupRecipientByNip05();\n return;\n }\n\n const recipientNpub = this.getAttribute(\"recipient-npub\");\n if (recipientNpub) {\n this.recipientNpub = recipientNpub;\n this.lookupRecipient();\n }\n };\n\n connectedCallback() {\n if (!this.rendered) {\n this.rendered = true;\n \n // Initialize the component\n this.getTheme();\n this.getRecipient();\n this.nostrService.connectToNostr(this.getRelays());\n this.render();\n }\n }\n\n static get observedAttributes() {\n return [\"relays\", \"recipient-npub\", \"nip05\", \"theme\", \"debug\"];\n }\n\n attributeChangedCallback(\n name: string,\n _oldValue: string | null,\n newValue: string | null\n ) {\n if (name === \"relays\") {\n this.nostrService.connectToNostr(this.getRelays());\n }\n\n if (name === \"theme\") {\n this.getTheme();\n }\n\n if (name === \"nip05\" && newValue) {\n this.recipientNip05 = newValue;\n this.lookupRecipientByNip05();\n }\n\n if (name === \"recipient-npub\" && newValue) {\n this.recipientNpub = newValue;\n this.lookupRecipient();\n }\n\n this.render();\n }\n\n private async lookupRecipient(npub?: string) {\n const targetNpub = npub || this.recipientNpub;\n if (!targetNpub) return;\n\n this.isFinding = true;\n this.render();\n\n try {\n const ndk = this.nostrService.getNDK();\n const user = ndk.getUser({ npub: targetNpub });\n\n await user.fetchProfile();\n\n if (user.profile) {\n this.recipientName =\n user.profile.displayName || user.profile.name || \"Unknown\";\n this.recipientPicture = user.profile.image || null;\n this.recipientPubkey = user.pubkey;\n // set actual recipient npub only after successful lookup\n this.recipientNpub = targetNpub;\n } else {\n this.recipientName = \"Unknown\";\n this.recipientPicture = null;\n this.recipientPubkey = user.pubkey;\n this.recipientNpub = targetNpub;\n }\n } catch (err) {\n this.isError = true;\n this.errorMessage = `Failed to find recipient: ${(err as Error).message}`;\n } finally {\n this.isFinding = false;\n this.render();\n }\n }\n\n // Resolve nip05 -> pubkey -> npub then delegate to lookupRecipient\n private async lookupRecipientByNip05(nip05?: string) {\n const targetNip05 = nip05 || this.recipientNip05;\n if (!targetNip05) return;\n\n this.isFinding = true;\n this.render();\n\n try {\n const pubkeyHex = await resolveNip05(targetNip05);\n if (!pubkeyHex) throw new Error(\"Failed to resolve nip05\");\n const npub = nip19.npubEncode(pubkeyHex);\n await this.lookupRecipient(npub);\n } catch (err) {\n this.isError = true;\n this.errorMessage = `Failed to resolve nip05: ${(err as Error).message}`;\n } finally {\n this.isFinding = false;\n this.render();\n }\n }\n\n private async handleFindClick() {\n // Determine if user entered nip05 (has '@') or npub\n\n const npubInput = this.shadowRoot!.querySelector(\n \".nostr-dm-npub-input\"\n ) as HTMLInputElement;\n if (!npubInput || !npubInput.value) {\n this.isError = true;\n this.errorMessage = \"Please enter a valid npub\";\n this.render();\n return;\n }\n\n const entered = npubInput.value.trim();\n if (entered.includes(\"@\")) {\n await this.lookupRecipientByNip05(entered);\n } else {\n await this.lookupRecipient(entered);\n }\n }\n\n private async handleSendClick() {\n debug(this, \"Send button clicked!\");\n \n if (!this.recipientPubkey || !this.message.trim()) {\n this.isError = true;\n this.errorMessage = !this.recipientPubkey\n ? \"Recipient not found\"\n : \"Please enter a message\";\n this.render();\n return;\n }\n\n this.isError = false;\n this.isSent = false;\n this.isLoading = true;\n this.render();\n\n // Check for signer availability using NostrService's hasSigner method\n if (!this.nostrService.hasSigner()) {\n this.isError = true;\n this.errorMessage = \"No Nostr signer available. Please ensure your Nostr extension is installed or provide a private key.\";\n this.isLoading = false;\n this.render();\n return;\n }\n \n // Create appropriate signer based on what's available\n let signer = null;\n if (typeof window !== 'undefined' && (window as any).nostr) {\n signer = new NDKNip07Signer();\n } else if (typeof localStorage !== 'undefined') {\n const stored = localStorage.getItem(\"nostr_nsec\");\n if (stored) {\n const { NDKPrivateKeySigner } = await import(\"@nostr-dev-kit/ndk\");\n signer = new NDKPrivateKeySigner(stored);\n }\n }\n\n if (!signer) {\n this.isError = true;\n this.errorMessage = \"Failed to create signer. Please ensure your Nostr signer (extension or private key) is configured.\";\n this.render();\n return;\n }\n\n this.render();\n\n try {\n const ndk = this.nostrService.getNDK();\n ndk.signer = signer;\n\n // Important: Use nostr-tools directly for encryption to ensure compatibility\n const { nip04 } = await import(\"nostr-tools\");\n\n // Create a basic event with the correct kind and target pubkey\n const event = new NDKEvent(ndk, {\n kind: NDKKind.EncryptedDirectMessage,\n tags: [[\"p\", this.recipientPubkey!]],\n created_at: Math.floor(Date.now() / 1000),\n });\n\n // For extension-based signers (NIP-07), use the extension's encryption\n if (typeof window !== 'undefined' && (window as any).nostr) {\n // Here we encrypt through the extension using nip04\n const encryptedContent = await (window as any).nostr.nip04.encrypt(\n this.recipientPubkey!,\n this.message.trim()\n );\n event.content = encryptedContent;\n } else if (typeof localStorage !== 'undefined') {\n // For private key signers\n const privateKeyHex = localStorage.getItem(\"nostr_nsec\");\n if (!privateKeyHex) throw new Error(\"No private key available\");\n\n // Import the relevant libraries\n const { nip19 } = await import(\"nostr-tools\");\n\n // Handle both hex and bech32 formats\n let privateKey = privateKeyHex;\n if (privateKeyHex.startsWith(\"nsec\")) {\n try {\n const decoded = nip19.decode(privateKeyHex);\n privateKey = decoded.data as string;\n } catch (e) {\n console.error(\"Failed to decode nsec:\", e);\n throw new Error(\"Invalid private key format\");\n }\n }\n\n // Use nostr-tools to encrypt the message\n try {\n event.content = await nip04.encrypt(\n privateKey,\n this.recipientPubkey!,\n this.message.trim()\n );\n } catch (encErr) {\n console.error(\"Encryption error:\", encErr);\n throw new Error(`Encryption failed: ${(encErr as Error).message}`);\n }\n }\n\n debug(this, \"Sending encrypted DM:\", {\n to: this.recipientPubkey!,\n encryptedContent: event.content,\n });\n\n // Publish the event with the encrypted content\n await event.publish();\n debug(this, \"DM sent with encrypted content:\", event);\n\n this.isSent = true;\n this.message = \"\";\n\n // Clear textarea\n const textarea = this.shadowRoot!.querySelector(\n \".nostr-dm-textarea\"\n ) as HTMLTextAreaElement;\n if (textarea) {\n textarea.value = \"\";\n }\n } catch (err) {\n this.isError = true;\n this.errorMessage = `Failed to send message: ${(err as Error).message}`;\n this.isSent = false; // Reset sent state on error\n } finally {\n this.isLoading = false; // Reset loading state\n this.isFinding = false;\n this.render();\n }\n }\n\n private handleTextareaChange(e: Event) {\n const textarea = e.target as HTMLTextAreaElement;\n this.message = textarea.value;\n }\n\n attachEventListeners() {\n // Find button\n const findButton = this.shadowRoot!.querySelector(\".nostr-dm-find-btn\");\n if (findButton) {\n // Remove any existing listener\n if (this.boundHandleFind) {\n findButton.removeEventListener(\"click\", this.boundHandleFind);\n }\n\n // Create and store a new bound handler\n this.boundHandleFind = this.handleFindClick.bind(this);\n findButton.addEventListener(\"click\", this.boundHandleFind);\n debug(this, \"Find button event listener attached\");\n } else {\n debug(this, \"Find button not found in DOM\");\n }\n\n // Send button\n const sendButton = this.shadowRoot!.querySelector(\".nostr-dm-send-btn\");\n if (sendButton) {\n debug(this, \"Send button found, disabled:\", sendButton.hasAttribute(\"disabled\"));\n \n // Remove any existing listener\n if (this.boundHandleSend) {\n sendButton.removeEventListener(\"click\", this.boundHandleSend);\n }\n\n // Create and store a new bound handler\n this.boundHandleSend = this.handleSendClick.bind(this);\n sendButton.addEventListener(\"click\", this.boundHandleSend);\n \n // Force enable the button if we have a recipient and we're not loading\n if (this.recipientPubkey && !this.isLoading) {\n sendButton.removeAttribute(\"disabled\");\n }\n \n debug(this, \"Send button event listener attached\");\n } else {\n debug(this, \"Send button not found in DOM\");\n }\n\n // Textarea\n const textarea = this.shadowRoot!.querySelector(\".nostr-dm-textarea\");\n if (textarea) {\n // Remove any existing listener\n if (this.boundHandleTextareaChange) {\n textarea.removeEventListener(\"input\", this.boundHandleTextareaChange);\n }\n\n // Create and store a new bound handler\n this.boundHandleTextareaChange = this.handleTextareaChange.bind(this);\n textarea.addEventListener(\"input\", this.boundHandleTextareaChange);\n }\n\n // Npub input\n const npubInput = this.shadowRoot!.querySelector(\".nostr-dm-npub-input\");\n if (npubInput) {\n // Add keydown event listener for Enter key\n npubInput.addEventListener(\"keydown\", (e: Event) => {\n if ((e as KeyboardEvent).key === \"Enter\") {\n this.handleFindClick();\n }\n });\n }\n }\n\n disconnectedCallback() {\n // Clean up event listeners\n const findButton = this.shadowRoot?.querySelector(\".nostr-dm-find-btn\");\n if (findButton && this.boundHandleFind) {\n findButton.removeEventListener(\"click\", this.boundHandleFind);\n }\n\n const sendButton = this.shadowRoot?.querySelector(\".nostr-dm-send-btn\");\n if (sendButton && this.boundHandleSend) {\n sendButton.removeEventListener(\"click\", this.boundHandleSend);\n }\n\n const textarea = this.shadowRoot?.querySelector(\".nostr-dm-textarea\");\n if (textarea && this.boundHandleTextareaChange) {\n textarea.removeEventListener(\"input\", this.boundHandleTextareaChange);\n }\n }\n\n private render() {\n debug(this, \"Rendering with state:\", {\n recipientNpub: this.recipientNpub,\n recipientPubkey: this.recipientPubkey,\n message: this.message ? \"[message content]\" : \"[empty]\",\n isLoading: this.isLoading,\n isFinding: this.isFinding,\n isError: this.isError,\n isSent: this.isSent\n });\n \n const renderOptions: RenderDmOptions = {\n theme: this.theme,\n recipientNpub: this.recipientNpub,\n recipientName: this.recipientName,\n recipientPicture: this.recipientPicture,\n message: this.message,\n isLoading: this.isLoading,\n isFinding: this.isFinding,\n isError: this.isError,\n errorMessage: this.errorMessage,\n isSent: this.isSent,\n };\n\n this.shadowRoot!.innerHTML = renderDm(renderOptions);\n this.attachEventListeners();\n }\n}\n\ncustomElements.define(\"nostr-dm\", NostrDm);\n"],"file":"components/nostr-dm.es.js"}
1
+ {"version":3,"mappings":"ycAgBO,SAASA,EAAS,CACvB,MAAAC,EACA,cAAAC,EACA,cAAAC,EACA,iBAAAC,EACA,QAAAC,EACA,UAAAC,EACA,UAAAC,EACA,QAAAC,EACA,aAAAC,EACA,OAAAC,CACF,EAA4B,CAC1B,MAAMC,EAAaL,EAAY,aAAe,UACxCM,EAAW,GACXC,EAAkBX,EACpB,4BACA,wCAEJ,MAAO;AAAA,MACHY,EAAYb,CAAK,CAAC;AAAA,qCACaO,EAAU,iBAAmB,EAAE;AAAA;AAAA,UAG1DN,GAAiBC,EACb;AAAA;AAAA;AAAA,qBAGOC,GAAoB,gWAAgW;AAAA,qBACpXD,CAAa;AAAA;AAAA;AAAA;AAAA,oDAIkBA,CAAa;AAAA;AAAA,UAGnD;AAAA;AAAA,cAEAY,EAAaH,EAAUA,CAAQ,CAAC;AAAA;AAAA;AAAA,SAItC;AAAA;AAAA;AAAA;AAAA,UAKGV,EAaG,GAZA;AAAA;AAAA;AAAA,gDAGkCK,EAAY,WAAa,EAAE;AAAA,gBAE3DA,EACI,GAAGS,EAAA,CAAoB,2BACvB,GAAGD,EAAaH,EAAUA,CAAQ,CAAC,oBACzC;AAAA;AAAA;AAAA,SAKN;AAAA;AAAA;AAAA;AAAA,yBAIiBC,CAAe;AAAA,YAC3BX,EAA6B,GAAb,UAAe;AAAA,WACjCG,CAAO;AAAA;AAAA;AAAA,8CAG4B,CAACH,GAAiBI,EAAY,WAAa,EAAE;AAAA,cAE7EA,EACI,GAAGU,EAAA,CAAoB,2BACvB,GAAGD,EAAaH,EAAUA,CAAQ,CAAC,UAAUD,CAAU,SAC7D;AAAA;AAAA;AAAA;AAAA;AAAA,QAKJH,EAAU,yCAAyCC,CAAY,WAAa,EAAE;AAAA,QAC9EC,EAAS,6EAA+E,EAAE;AAAA;AAAA,GAGlG,CAEO,SAASI,EAAYb,EAAsB,CAChD,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2DAqBkDA,CAAK;AAAA,2DACLA,CAAK;AAAA,mDACbA,CAAK;AAAA,uEACeA,CAAK;AAAA,yEACHA,CAAK;AAAA,+DACfA,CAAK;AAAA,6DACPA,CAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GA6IlE,CC5OA,SAASgB,EAAMC,EAAoBb,EAAiBc,EAAY,CAG9CD,EAAU,aAAa,OAAO,IAAM,SAG9CC,EACF,QAAQ,IAAI,aAAad,CAAO,GAAIc,CAAI,EAExC,QAAQ,IAAI,aAAad,CAAO,EAAE,EAGxC,CAGA,MAAqBe,UAAgB,WAAY,CAwB/C,aAAc,CACZ,QAxBMC,EAAA,gBAAoB,IACpBA,EAAA,oBAA6BC,EAAa,eAE1CD,EAAA,aAAe,SACfA,EAAA,qBAA+B,MAC/BA,EAAA,sBAAgC,MAChCA,EAAA,qBAA+B,MAC/BA,EAAA,wBAAkC,MAClCA,EAAA,uBAAiC,MACjCA,EAAA,eAAkB,IAGlBA,EAAA,iBAAqB,IACrBA,EAAA,iBAAqB,IACrBA,EAAA,eAAmB,IACnBA,EAAA,oBAAuB,IACvBA,EAAA,cAAkB,IAGlBA,EAAA,uBAAuC,MACvCA,EAAA,uBAAuC,MACvCA,EAAA,iCAAyD,MAOjEA,EAAA,iBAAY,IAAM,CAChB,MAAME,EAAa,KAAK,aAAa,QAAQ,EAC7C,OAAIA,EACKA,EAAW,MAAM,GAAG,EAEtBC,CACT,GAEAH,EAAA,gBAAW,SAAY,CACrB,KAAK,MAAQ,QAEb,MAAMI,EAAY,KAAK,aAAa,OAAO,EAE3C,GAAIA,EAAW,CAGb,GAAI,CAFiB,CAAC,QAAS,MAAM,EAAE,SAASA,CAAS,EAGvD,MAAM,IAAI,MACR,kBAAkBA,CAAS,0CAI/B,KAAK,MAAQA,CACf,CACF,GAEAJ,EAAA,oBAAe,IAAM,CACnB,MAAMK,EAAY,KAAK,aAAa,OAAO,EAC3C,GAAIA,EAAW,CACb,KAAK,eAAiBA,EACtB,KAAK,yBACL,MACF,CAEA,MAAMxB,EAAgB,KAAK,aAAa,gBAAgB,EACpDA,IACF,KAAK,cAAgBA,EACrB,KAAK,kBAET,GA1CE,KAAK,aAAa,CAAE,KAAM,OAAQ,CACpC,CA2CA,mBAAoB,CACb,KAAK,WACR,KAAK,SAAW,GAGhB,KAAK,WACL,KAAK,eACL,KAAK,aAAa,eAAe,KAAK,WAAW,EACjD,KAAK,SAET,CAEA,WAAW,oBAAqB,CAC9B,MAAO,CAAC,SAAU,iBAAkB,QAAS,QAAS,OAAO,CAC/D,CAEA,yBACEyB,EACAC,EACAC,EACA,CACIF,IAAS,UACX,KAAK,aAAa,eAAe,KAAK,WAAW,EAG/CA,IAAS,SACX,KAAK,WAGHA,IAAS,SAAWE,IACtB,KAAK,eAAiBA,EACtB,KAAK,0BAGHF,IAAS,kBAAoBE,IAC/B,KAAK,cAAgBA,EACrB,KAAK,mBAGP,KAAK,QACP,CAEA,MAAc,gBAAgBC,EAAe,CAC3C,MAAMC,EAAaD,GAAQ,KAAK,cAChC,GAAKC,EAEL,MAAK,UAAY,GACjB,KAAK,SAEL,GAAI,CAEF,MAAMC,EADM,KAAK,aAAa,SACb,QAAQ,CAAE,KAAMD,EAAY,EAE7C,MAAMC,EAAK,eAEPA,EAAK,SACP,KAAK,cACHA,EAAK,QAAQ,aAAeA,EAAK,QAAQ,MAAQ,UACnD,KAAK,iBAAmBA,EAAK,QAAQ,OAAS,KAC9C,KAAK,gBAAkBA,EAAK,OAE5B,KAAK,cAAgBD,IAErB,KAAK,cAAgB,UACrB,KAAK,iBAAmB,KACxB,KAAK,gBAAkBC,EAAK,OAC5B,KAAK,cAAgBD,EAEzB,OAASE,EAAK,CACZ,KAAK,QAAU,GACf,KAAK,aAAe,6BAA8BA,EAAc,OAAO,EACzE,SACE,KAAK,UAAY,GACjB,KAAK,QACP,EACF,CAGA,MAAc,uBAAuBC,EAAgB,CACnD,MAAMC,EAAcD,GAAS,KAAK,eAClC,GAAKC,EAEL,MAAK,UAAY,GACjB,KAAK,SAEL,GAAI,CACF,MAAMC,EAAY,MAAMC,EAAaF,CAAW,EAChD,GAAI,CAACC,EAAW,MAAM,IAAI,MAAM,yBAAyB,EACzD,MAAMN,EAAOQ,EAAM,WAAWF,CAAS,EACvC,MAAM,KAAK,gBAAgBN,CAAI,CACjC,OAASG,EAAK,CACZ,KAAK,QAAU,GACf,KAAK,aAAe,4BAA6BA,EAAc,OAAO,EACxE,SACE,KAAK,UAAY,GACjB,KAAK,QACP,EACF,CAEA,MAAc,iBAAkB,CAG9B,MAAMM,EAAY,KAAK,WAAY,cACjC,wBAEF,GAAI,CAACA,GAAa,CAACA,EAAU,MAAO,CAClC,KAAK,QAAU,GACf,KAAK,aAAe,4BACpB,KAAK,SACL,MACF,CAEA,MAAMC,EAAUD,EAAU,MAAM,OAC5BC,EAAQ,SAAS,GAAG,EACtB,MAAM,KAAK,uBAAuBA,CAAO,EAEzC,MAAM,KAAK,gBAAgBA,CAAO,CAEtC,CAEA,MAAc,iBAAkB,CAG9B,GAFAvB,EAAM,KAAM,sBAAsB,EAE9B,CAAC,KAAK,iBAAmB,CAAC,KAAK,QAAQ,OAAQ,CACjD,KAAK,QAAU,GACf,KAAK,aAAgB,KAAK,gBAEtB,yBADA,sBAEJ,KAAK,SACL,MACF,CAQA,GANA,KAAK,QAAU,GACf,KAAK,OAAS,GACd,KAAK,UAAY,GACjB,KAAK,SAGD,CAAC,KAAK,aAAa,YAAa,CAClC,KAAK,QAAU,GACf,KAAK,aAAe,uGACpB,KAAK,UAAY,GACjB,KAAK,SACL,MACF,CAGA,IAAIwB,EAAS,KACb,GAAI,OAAO,OAAW,KAAgB,OAAe,MACnDA,EAAS,IAAIC,UACJ,OAAO,aAAiB,IAAa,CAC9C,MAAMC,EAAS,aAAa,QAAQ,YAAY,EAChD,GAAIA,EAAQ,CACV,KAAM,CAAE,oBAAAC,CAAA,EAAwB,MAAAC,EAAA,oCAAAD,CAAA,OAAM,QAAO,qCAAoB,OAAAE,KAAA,sCACjEL,EAAS,IAAIG,EAAoBD,CAAM,CACzC,CACF,CAEA,GAAI,CAACF,EAAQ,CACX,KAAK,QAAU,GACf,KAAK,aAAe,qGACpB,KAAK,SACL,MACF,CAEA,KAAK,SAEL,GAAI,CACF,MAAMM,EAAM,KAAK,aAAa,SAC9BA,EAAI,OAASN,EAGb,KAAM,CAAE,MAAAO,CAAA,EAAU,MAAAH,EAAA,sBAAAG,GAAA,KAAM,QAAO,qCAAa,OAAAF,KAAA,gBAAAE,CAAA,OAGtCC,EAAQ,IAAIC,EAASH,EAAK,CAC9B,KAAMI,EAAQ,uBACd,KAAM,CAAC,CAAC,IAAK,KAAK,eAAgB,CAAC,EACnC,WAAY,KAAK,MAAM,KAAK,MAAQ,GAAI,EACzC,EAGD,GAAI,OAAO,OAAW,KAAgB,OAAe,MAAO,CAE1D,MAAMC,EAAmB,MAAO,OAAe,MAAM,MAAM,QACzD,KAAK,gBACL,KAAK,QAAQ,MAAK,EAEpBH,EAAM,QAAUG,CAClB,SAAW,OAAO,aAAiB,IAAa,CAE9C,MAAMC,EAAgB,aAAa,QAAQ,YAAY,EACvD,GAAI,CAACA,EAAe,MAAM,IAAI,MAAM,0BAA0B,EAG9D,KAAM,CAAE,MAAAf,GAAU,MAAAO,EAAA,sBAAAS,CAAA,OAAM,QAAO,qCAAa,OAAAR,KAAA,wBAG5C,IAAIS,EAAaF,EACjB,GAAIA,EAAc,WAAW,MAAM,EACjC,GAAI,CAEFE,EADgBjB,EAAM,OAAOe,CAAa,EACrB,IACvB,OAASG,EAAG,CACV,cAAQ,MAAM,yBAA0BA,CAAC,EACnC,IAAI,MAAM,4BAA4B,CAC9C,CAIF,GAAI,CACFP,EAAM,QAAU,MAAMD,EAAM,QAC1BO,EACA,KAAK,gBACL,KAAK,QAAQ,MAAK,CAEtB,OAASE,EAAQ,CACf,cAAQ,MAAM,oBAAqBA,CAAM,EACnC,IAAI,MAAM,sBAAuBA,EAAiB,OAAO,EAAE,CACnE,CACF,CAEAxC,EAAM,KAAM,wBAAyB,CACnC,GAAI,KAAK,gBACT,iBAAkBgC,EAAM,QACzB,EAGD,MAAMA,EAAM,UACZhC,EAAM,KAAM,kCAAmCgC,CAAK,EAEpD,KAAK,OAAS,GACd,KAAK,QAAU,GAGf,MAAMS,EAAW,KAAK,WAAY,cAChC,sBAEEA,IACFA,EAAS,MAAQ,GAErB,OAASzB,EAAK,CACZ,KAAK,QAAU,GACf,KAAK,aAAe,2BAA4BA,EAAc,OAAO,GACrE,KAAK,OAAS,EAChB,SACE,KAAK,UAAY,GACjB,KAAK,UAAY,GACjB,KAAK,QACP,CACF,CAEQ,qBAAqB,EAAU,CACrC,MAAMyB,EAAW,EAAE,OACnB,KAAK,QAAUA,EAAS,KAC1B,CAEA,sBAAuB,CAErB,MAAMC,EAAa,KAAK,WAAY,cAAc,oBAAoB,EAClEA,GAEE,KAAK,iBACPA,EAAW,oBAAoB,QAAS,KAAK,eAAe,EAI9D,KAAK,gBAAkB,KAAK,gBAAgB,KAAK,IAAI,EACrDA,EAAW,iBAAiB,QAAS,KAAK,eAAe,EACzD1C,EAAM,KAAM,qCAAqC,GAEjDA,EAAM,KAAM,8BAA8B,EAI5C,MAAM2C,EAAa,KAAK,WAAY,cAAc,oBAAoB,EAClEA,GACF3C,EAAM,KAAM,+BAAgC2C,EAAW,aAAa,UAAU,CAAC,EAG3E,KAAK,iBACPA,EAAW,oBAAoB,QAAS,KAAK,eAAe,EAI9D,KAAK,gBAAkB,KAAK,gBAAgB,KAAK,IAAI,EACrDA,EAAW,iBAAiB,QAAS,KAAK,eAAe,EAGrD,KAAK,iBAAmB,CAAC,KAAK,WAChCA,EAAW,gBAAgB,UAAU,EAGvC3C,EAAM,KAAM,qCAAqC,GAEjDA,EAAM,KAAM,8BAA8B,EAI5C,MAAMyC,EAAW,KAAK,WAAY,cAAc,oBAAoB,EAChEA,IAEE,KAAK,2BACPA,EAAS,oBAAoB,QAAS,KAAK,yBAAyB,EAItE,KAAK,0BAA4B,KAAK,qBAAqB,KAAK,IAAI,EACpEA,EAAS,iBAAiB,QAAS,KAAK,yBAAyB,GAInE,MAAMnB,EAAY,KAAK,WAAY,cAAc,sBAAsB,EACnEA,GAEFA,EAAU,iBAAiB,UAAYiB,GAAa,CAC7CA,EAAoB,MAAQ,SAC/B,KAAK,iBAET,CAAC,CAEL,CAEA,sBAAuB,WAErB,MAAMG,GAAaE,EAAA,KAAK,aAAL,YAAAA,EAAiB,cAAc,sBAC9CF,GAAc,KAAK,iBACrBA,EAAW,oBAAoB,QAAS,KAAK,eAAe,EAG9D,MAAMC,GAAaE,EAAA,KAAK,aAAL,YAAAA,EAAiB,cAAc,sBAC9CF,GAAc,KAAK,iBACrBA,EAAW,oBAAoB,QAAS,KAAK,eAAe,EAG9D,MAAMF,GAAWK,EAAA,KAAK,aAAL,YAAAA,EAAiB,cAAc,sBAC5CL,GAAY,KAAK,2BACnBA,EAAS,oBAAoB,QAAS,KAAK,yBAAyB,CAExE,CAEQ,QAAS,CACfzC,EAAM,KAAM,wBAAyB,CACnC,cAAe,KAAK,cACpB,gBAAiB,KAAK,gBACtB,QAAS,KAAK,QAAU,oBAAsB,UAC9C,UAAW,KAAK,UAChB,UAAW,KAAK,UAChB,QAAS,KAAK,QACd,OAAQ,KAAK,OACd,EAED,MAAM+C,EAAiC,CACrC,MAAO,KAAK,MACZ,cAAe,KAAK,cACpB,cAAe,KAAK,cACpB,iBAAkB,KAAK,iBACvB,QAAS,KAAK,QACd,UAAW,KAAK,UAChB,UAAW,KAAK,UAChB,QAAS,KAAK,QACd,aAAc,KAAK,aACnB,OAAQ,KAAK,QAGf,KAAK,WAAY,UAAYhE,EAASgE,CAAa,EACnD,KAAK,sBACP,CACF,CAEA,eAAe,OAAO,WAAY5C,CAAO","names":["renderDm","theme","recipientNpub","recipientName","recipientPicture","message","isLoading","isFinding","isError","errorMessage","isSent","buttonText","iconSize","placeholderText","getDmStyles","getNostrLogo","getLoadingNostrich","debug","component","data","NostrDm","__publicField","NostrService","userRelays","DEFAULT_RELAYS","userTheme","nip05Attr","name","_oldValue","newValue","npub","targetNpub","user","err","nip05","targetNip05","pubkeyHex","resolveNip05","nip19","npubInput","entered","signer","NDKNip07Signer","stored","NDKPrivateKeySigner","__vitePreload","n","ndk","nip04","event","NDKEvent","NDKKind","encryptedContent","privateKeyHex","nip192","privateKey","e","encErr","textarea","findButton","sendButton","_a","_b","_c","renderOptions"],"ignoreList":[],"sources":["../../src/nostr-dm/render.ts","../../src/nostr-dm/nostr-dm.ts"],"sourcesContent":["import { Theme } from \"../common/types\";\nimport { getLoadingNostrich, getNostrLogo } from \"../common/theme\";\n\nexport interface RenderDmOptions {\n theme: Theme;\n recipientNpub: string | null;\n recipientName: string | null;\n recipientPicture: string | null;\n message: string;\n isLoading: boolean;\n isFinding: boolean;\n isError: boolean;\n errorMessage: string;\n isSent: boolean;\n}\n\nexport function renderDm({\n theme,\n recipientNpub,\n recipientName,\n recipientPicture,\n message,\n isLoading,\n isFinding,\n isError,\n errorMessage,\n isSent,\n}: RenderDmOptions): string {\n const buttonText = isLoading ? \"Sending...\" : \"Send DM\";\n const iconSize = 24;\n const placeholderText = recipientNpub\n ? \"Type your message here...\"\n : \"Enter recipient npub/nip05 address...\";\n\n return `\n ${getDmStyles(theme)}\n <div class=\"nostr-dm-container ${isError ? \"nostr-dm-error\" : \"\"}\">\n <div class=\"nostr-dm-header\">\n ${\n recipientNpub && recipientName\n ? `\n <div class=\"nostr-dm-recipient\">\n <img \n src=\"${recipientPicture || \"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23ccc' d='M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z'/%3E%3C/svg%3E\"}\" \n alt=\"${recipientName}\" \n class=\"nostr-dm-recipient-avatar\"\n onerror=\"this.onerror=null; this.src='data:image/svg+xml,%3Csvg xmlns=\\'http://www.w3.org/2000/svg\\' viewBox=\\'0 0 24 24\\'%3E%3Cpath fill=\\'%23ccc\\' d=\\'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z\\'/%3E%3C/svg%3E';\"\n />\n <span class=\"nostr-dm-recipient-name\">${recipientName}</span>\n </div>\n `\n : `\n <div class=\"nostr-dm-recipient-placeholder\">\n ${getNostrLogo(iconSize, iconSize)}\n <span>Nostr Direct Message</span>\n </div>\n `\n }\n </div>\n\n <div class=\"nostr-dm-content\">\n ${\n !recipientNpub\n ? `\n <div class=\"nostr-dm-npub-input-container\">\n <input type=\"text\" class=\"nostr-dm-npub-input\" placeholder=\"Enter recipient's npub/nip05 address...\" />\n <button class=\"nostr-dm-find-btn\" ${isFinding ? \"disabled\" : \"\"}>\n ${\n isFinding\n ? `${getLoadingNostrich()} <span>Finding...</span>`\n : `${getNostrLogo(iconSize, iconSize)} <span>Find</span>`\n }\n </button>\n </div>\n `\n : \"\"\n }\n \n <textarea \n class=\"nostr-dm-textarea\" \n placeholder=\"${placeholderText}\"\n ${!recipientNpub ? \"disabled\" : \"\"}\n >${message}</textarea>\n \n <div class=\"nostr-dm-actions\">\n <button class=\"nostr-dm-send-btn\" ${!recipientNpub || isLoading ? \"disabled\" : \"\"}>\n ${\n isLoading\n ? `${getLoadingNostrich()} <span>Sending...</span>`\n : `${getNostrLogo(iconSize, iconSize)} <span>${buttonText}</span>`\n }\n </button>\n </div>\n </div>\n\n ${isError ? `<small class=\"nostr-dm-error-message\">${errorMessage}</small>` : \"\"}\n ${isSent ? `<small class=\"nostr-dm-success-message\">Message sent successfully!</small>` : \"\"}\n </div>\n `;\n}\n\nexport function getDmStyles(theme: Theme): string {\n return `\n <style>\n :host {\n --nstrc-dm-background-dark: #222222;\n --nstrc-dm-background-light: #FFFFFF;\n --nstrc-dm-text-color-dark: #FFFFFF;\n --nstrc-dm-text-color-light: #000000;\n --nstrc-dm-border-dark: 1px solid #444444;\n --nstrc-dm-border-light: 1px solid #DDDDDD;\n --nstrc-dm-input-background-dark: #333333;\n --nstrc-dm-input-background-light: #F9F9F9;\n --nstrc-dm-button-background-dark: #000000;\n --nstrc-dm-button-background-light: #FFFFFF;\n --nstrc-dm-button-hover-dark: #333333;\n --nstrc-dm-button-hover-light: #F0F0F0;\n --nstrc-dm-button-text-dark: #FFFFFF;\n --nstrc-dm-button-text-light: #000000;\n --nstrc-dm-error-color: #FF4D4F;\n --nstrc-dm-success-color: #52C41A;\n --nstrc-dm-border-radius: 8px;\n \n --nstrc-dm-background: var(--nstrc-dm-background-${theme});\n --nstrc-dm-text-color: var(--nstrc-dm-text-color-${theme});\n --nstrc-dm-border: var(--nstrc-dm-border-${theme});\n --nstrc-dm-input-background: var(--nstrc-dm-input-background-${theme});\n --nstrc-dm-button-background: var(--nstrc-dm-button-background-${theme});\n --nstrc-dm-button-hover: var(--nstrc-dm-button-hover-${theme});\n --nstrc-dm-button-text: var(--nstrc-dm-button-text-${theme});\n }\n\n .nostr-dm-container {\n display: flex;\n flex-direction: column;\n font-family: var(--nostrc-font-family-primary);\n max-width: 500px;\n width: 100%;\n box-sizing: border-box;\n border-radius: var(--nstrc-dm-border-radius);\n border: var(--nstrc-dm-border);\n background-color: var(--nstrc-dm-background);\n color: var(--nstrc-dm-text-color);\n overflow: hidden;\n }\n\n .nostr-dm-header {\n padding: 12px 16px;\n border-bottom: var(--nstrc-dm-border);\n display: flex;\n align-items: center;\n }\n\n .nostr-dm-recipient, .nostr-dm-recipient-placeholder {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .nostr-dm-recipient-avatar {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n object-fit: cover;\n }\n\n .nostr-dm-recipient-name {\n font-weight: 600;\n font-size: 16px;\n }\n\n .nostr-dm-content {\n padding: 16px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .nostr-dm-npub-input-container {\n display: flex;\n gap: 8px;\n }\n\n .nostr-dm-npub-input {\n flex: 1;\n padding: 10px;\n box-sizing: border-box;\n max-width: 100%;\n border-radius: 4px;\n border: var(--nstrc-dm-border);\n background-color: var(--nstrc-dm-input-background);\n color: var(--nstrc-dm-text-color);\n }\n\n .nostr-dm-find-btn {\n padding: 10px 16px;\n border-radius: 4px;\n border: var(--nstrc-dm-border);\n background-color: var(--nstrc-dm-button-background);\n color: var(--nstrc-dm-button-text);\n cursor: pointer;\n }\n\n .nostr-dm-find-btn:hover {\n background-color: var(--nstrc-dm-button-hover);\n }\n\n .nostr-dm-textarea {\n width: 100%;\n min-height: 100px;\n box-sizing: border-box;\n padding: 12px;\n border-radius: 4px;\n border: var(--nstrc-dm-border);\n background-color: var(--nstrc-dm-input-background);\n color: var(--nstrc-dm-text-color);\n font-family: var(--nostrc-font-family-primary);\n resize: vertical;\n }\n\n .nostr-dm-textarea:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .nostr-dm-actions {\n display: flex;\n justify-content: flex-end;\n }\n\n .nostr-dm-send-btn {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 16px;\n border-radius: 4px;\n border: var(--nstrc-dm-border);\n background-color: var(--nstrc-dm-button-background);\n color: var(--nstrc-dm-button-text);\n cursor: pointer;\n }\n\n .nostr-dm-send-btn:hover:not(:disabled) {\n background-color: var(--nstrc-dm-button-hover);\n }\n\n .nostr-dm-send-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .nostr-dm-send-btn svg {\n width: 24px;\n height: 24px;\n fill: currentColor;\n }\n\n .nostr-dm-error-message {\n color: var(--nstrc-dm-error-color);\n font-size: 14px;\n padding: 0 16px 16px;\n }\n\n .nostr-dm-success-message {\n color: var(--nstrc-dm-success-color);\n font-size: 14px;\n padding: 0 16px 16px;\n }\n </style>\n `;\n}\n","/**\n * <nostr-dm>\n * Attributes:\n * - recipient-npub (optional) : pre-set npub of recipient\n * - nip05 (optional) : user@domain nip-05 identifier (alternative to recipient-npub)\n * - relays (optional) : comma-separated relay URLs (defaults to common public set)\n * - theme (optional) : \"light\" | \"dark\" (default \"light\")\n * - debug (optional) : \"true\" | \"false\" - whether to log debug messages (default \"false\")\n *\n * Behaviour:\n * • If neither recipient-npub nor nip05 is supplied the component shows an input + Find button.\n * • Entering an npub then clicking Find performs profile lookup; during lookup the Find button shows\n * spinner/“Finding…”. On success the UI switches to DM compose view.\n * • If nip05 attribute is provided we first resolve it to a pubkey via nip05 well-known file then look\n * up the profile as usual.\n */\nimport { NDKNip07Signer, NDKEvent, NDKKind } from \"@nostr-dev-kit/ndk\";\nimport { DEFAULT_RELAYS } from \"../common/constants\";\nimport { Theme } from \"../common/types\";\nimport { renderDm, RenderDmOptions } from \"./render\";\nimport { nip19 } from \"nostr-tools\";\nimport { NostrService } from \"../common/nostr-service\";\n\n// ---------------------------------------------------------------------------\n// nip05 resolution helper – very lightweight fetch to /.well-known/nostr.json\n// ---------------------------------------------------------------------------\n// Import the resolveNip05 function from our common utils\nimport { resolveNip05 } from '../common/nip05-utils';\n\n/**\n * Debug utility that only logs in development mode or when debug attribute is set\n * @param message The message to log\n * @param data Additional data to log\n */\nfunction debug(component: NostrDm, message: string, data?: any) {\n // Check if we're in development environment or debug attribute is true\n const isDev = process.env.NODE_ENV === 'development';\n const isDebug = component.getAttribute('debug') === 'true';\n \n if (isDev || isDebug) {\n if (data) {\n console.log(`[NostrDm] ${message}`, data);\n } else {\n console.log(`[NostrDm] ${message}`);\n }\n }\n}\n\n\nexport default class NostrDm extends HTMLElement {\n private rendered: boolean = false;\n private nostrService: NostrService = NostrService.getInstance();\n\n private theme: Theme = \"light\";\n private recipientNpub: string | null = null;\n private recipientNip05: string | null = null;\n private recipientName: string | null = null;\n private recipientPicture: string | null = null;\n private recipientPubkey: string | null = null;\n private message: string = \"\";\n\n // isLoading -> sending DM, isFinding -> looking up recipient\n private isLoading: boolean = false;\n private isFinding: boolean = false;\n private isError: boolean = false;\n private errorMessage: string = \"\";\n private isSent: boolean = false;\n\n // Event handlers\n private boundHandleFind: (() => void) | null = null;\n private boundHandleSend: (() => void) | null = null;\n private boundHandleTextareaChange: ((e: Event) => void) | null = null;\n\n constructor() {\n super();\n this.attachShadow({ mode: \"open\" });\n }\n\n getRelays = () => {\n const userRelays = this.getAttribute(\"relays\");\n if (userRelays) {\n return userRelays.split(\",\");\n }\n return DEFAULT_RELAYS;\n };\n\n getTheme = async () => {\n this.theme = \"light\";\n\n const userTheme = this.getAttribute(\"theme\");\n\n if (userTheme) {\n const isValidTheme = [\"light\", \"dark\"].includes(userTheme);\n\n if (!isValidTheme) {\n throw new Error(\n `Invalid theme '${userTheme}'. Accepted values are 'light', 'dark'`\n );\n }\n\n this.theme = userTheme as Theme;\n }\n };\n\n getRecipient = () => {\n const nip05Attr = this.getAttribute(\"nip05\");\n if (nip05Attr) {\n this.recipientNip05 = nip05Attr;\n this.lookupRecipientByNip05();\n return;\n }\n\n const recipientNpub = this.getAttribute(\"recipient-npub\");\n if (recipientNpub) {\n this.recipientNpub = recipientNpub;\n this.lookupRecipient();\n }\n };\n\n connectedCallback() {\n if (!this.rendered) {\n this.rendered = true;\n \n // Initialize the component\n this.getTheme();\n this.getRecipient();\n this.nostrService.connectToNostr(this.getRelays());\n this.render();\n }\n }\n\n static get observedAttributes() {\n return [\"relays\", \"recipient-npub\", \"nip05\", \"theme\", \"debug\"];\n }\n\n attributeChangedCallback(\n name: string,\n _oldValue: string | null,\n newValue: string | null\n ) {\n if (name === \"relays\") {\n this.nostrService.connectToNostr(this.getRelays());\n }\n\n if (name === \"theme\") {\n this.getTheme();\n }\n\n if (name === \"nip05\" && newValue) {\n this.recipientNip05 = newValue;\n this.lookupRecipientByNip05();\n }\n\n if (name === \"recipient-npub\" && newValue) {\n this.recipientNpub = newValue;\n this.lookupRecipient();\n }\n\n this.render();\n }\n\n private async lookupRecipient(npub?: string) {\n const targetNpub = npub || this.recipientNpub;\n if (!targetNpub) return;\n\n this.isFinding = true;\n this.render();\n\n try {\n const ndk = this.nostrService.getNDK();\n const user = ndk.getUser({ npub: targetNpub });\n\n await user.fetchProfile();\n\n if (user.profile) {\n this.recipientName =\n user.profile.displayName || user.profile.name || \"Unknown\";\n this.recipientPicture = user.profile.image || null;\n this.recipientPubkey = user.pubkey;\n // set actual recipient npub only after successful lookup\n this.recipientNpub = targetNpub;\n } else {\n this.recipientName = \"Unknown\";\n this.recipientPicture = null;\n this.recipientPubkey = user.pubkey;\n this.recipientNpub = targetNpub;\n }\n } catch (err) {\n this.isError = true;\n this.errorMessage = `Failed to find recipient: ${(err as Error).message}`;\n } finally {\n this.isFinding = false;\n this.render();\n }\n }\n\n // Resolve nip05 -> pubkey -> npub then delegate to lookupRecipient\n private async lookupRecipientByNip05(nip05?: string) {\n const targetNip05 = nip05 || this.recipientNip05;\n if (!targetNip05) return;\n\n this.isFinding = true;\n this.render();\n\n try {\n const pubkeyHex = await resolveNip05(targetNip05);\n if (!pubkeyHex) throw new Error(\"Failed to resolve nip05\");\n const npub = nip19.npubEncode(pubkeyHex);\n await this.lookupRecipient(npub);\n } catch (err) {\n this.isError = true;\n this.errorMessage = `Failed to resolve nip05: ${(err as Error).message}`;\n } finally {\n this.isFinding = false;\n this.render();\n }\n }\n\n private async handleFindClick() {\n // Determine if user entered nip05 (has '@') or npub\n\n const npubInput = this.shadowRoot!.querySelector(\n \".nostr-dm-npub-input\"\n ) as HTMLInputElement;\n if (!npubInput || !npubInput.value) {\n this.isError = true;\n this.errorMessage = \"Please enter a valid npub\";\n this.render();\n return;\n }\n\n const entered = npubInput.value.trim();\n if (entered.includes(\"@\")) {\n await this.lookupRecipientByNip05(entered);\n } else {\n await this.lookupRecipient(entered);\n }\n }\n\n private async handleSendClick() {\n debug(this, \"Send button clicked!\");\n \n if (!this.recipientPubkey || !this.message.trim()) {\n this.isError = true;\n this.errorMessage = !this.recipientPubkey\n ? \"Recipient not found\"\n : \"Please enter a message\";\n this.render();\n return;\n }\n\n this.isError = false;\n this.isSent = false;\n this.isLoading = true;\n this.render();\n\n // Check for signer availability using NostrService's hasSigner method\n if (!this.nostrService.hasSigner()) {\n this.isError = true;\n this.errorMessage = \"No Nostr signer available. Please ensure your Nostr extension is installed or provide a private key.\";\n this.isLoading = false;\n this.render();\n return;\n }\n \n // Create appropriate signer based on what's available\n let signer = null;\n if (typeof window !== 'undefined' && (window as any).nostr) {\n signer = new NDKNip07Signer();\n } else if (typeof localStorage !== 'undefined') {\n const stored = localStorage.getItem(\"nostr_nsec\");\n if (stored) {\n const { NDKPrivateKeySigner } = await import(\"@nostr-dev-kit/ndk\");\n signer = new NDKPrivateKeySigner(stored);\n }\n }\n\n if (!signer) {\n this.isError = true;\n this.errorMessage = \"Failed to create signer. Please ensure your Nostr signer (extension or private key) is configured.\";\n this.render();\n return;\n }\n\n this.render();\n\n try {\n const ndk = this.nostrService.getNDK();\n ndk.signer = signer;\n\n // Important: Use nostr-tools directly for encryption to ensure compatibility\n const { nip04 } = await import(\"nostr-tools\");\n\n // Create a basic event with the correct kind and target pubkey\n const event = new NDKEvent(ndk, {\n kind: NDKKind.EncryptedDirectMessage,\n tags: [[\"p\", this.recipientPubkey!]],\n created_at: Math.floor(Date.now() / 1000),\n });\n\n // For extension-based signers (NIP-07), use the extension's encryption\n if (typeof window !== 'undefined' && (window as any).nostr) {\n // Here we encrypt through the extension using nip04\n const encryptedContent = await (window as any).nostr.nip04.encrypt(\n this.recipientPubkey!,\n this.message.trim()\n );\n event.content = encryptedContent;\n } else if (typeof localStorage !== 'undefined') {\n // For private key signers\n const privateKeyHex = localStorage.getItem(\"nostr_nsec\");\n if (!privateKeyHex) throw new Error(\"No private key available\");\n\n // Import the relevant libraries\n const { nip19 } = await import(\"nostr-tools\");\n\n // Handle both hex and bech32 formats\n let privateKey = privateKeyHex;\n if (privateKeyHex.startsWith(\"nsec\")) {\n try {\n const decoded = nip19.decode(privateKeyHex);\n privateKey = decoded.data as string;\n } catch (e) {\n console.error(\"Failed to decode nsec:\", e);\n throw new Error(\"Invalid private key format\");\n }\n }\n\n // Use nostr-tools to encrypt the message\n try {\n event.content = await nip04.encrypt(\n privateKey,\n this.recipientPubkey!,\n this.message.trim()\n );\n } catch (encErr) {\n console.error(\"Encryption error:\", encErr);\n throw new Error(`Encryption failed: ${(encErr as Error).message}`);\n }\n }\n\n debug(this, \"Sending encrypted DM:\", {\n to: this.recipientPubkey!,\n encryptedContent: event.content,\n });\n\n // Publish the event with the encrypted content\n await event.publish();\n debug(this, \"DM sent with encrypted content:\", event);\n\n this.isSent = true;\n this.message = \"\";\n\n // Clear textarea\n const textarea = this.shadowRoot!.querySelector(\n \".nostr-dm-textarea\"\n ) as HTMLTextAreaElement;\n if (textarea) {\n textarea.value = \"\";\n }\n } catch (err) {\n this.isError = true;\n this.errorMessage = `Failed to send message: ${(err as Error).message}`;\n this.isSent = false; // Reset sent state on error\n } finally {\n this.isLoading = false; // Reset loading state\n this.isFinding = false;\n this.render();\n }\n }\n\n private handleTextareaChange(e: Event) {\n const textarea = e.target as HTMLTextAreaElement;\n this.message = textarea.value;\n }\n\n attachEventListeners() {\n // Find button\n const findButton = this.shadowRoot!.querySelector(\".nostr-dm-find-btn\");\n if (findButton) {\n // Remove any existing listener\n if (this.boundHandleFind) {\n findButton.removeEventListener(\"click\", this.boundHandleFind);\n }\n\n // Create and store a new bound handler\n this.boundHandleFind = this.handleFindClick.bind(this);\n findButton.addEventListener(\"click\", this.boundHandleFind);\n debug(this, \"Find button event listener attached\");\n } else {\n debug(this, \"Find button not found in DOM\");\n }\n\n // Send button\n const sendButton = this.shadowRoot!.querySelector(\".nostr-dm-send-btn\");\n if (sendButton) {\n debug(this, \"Send button found, disabled:\", sendButton.hasAttribute(\"disabled\"));\n \n // Remove any existing listener\n if (this.boundHandleSend) {\n sendButton.removeEventListener(\"click\", this.boundHandleSend);\n }\n\n // Create and store a new bound handler\n this.boundHandleSend = this.handleSendClick.bind(this);\n sendButton.addEventListener(\"click\", this.boundHandleSend);\n \n // Force enable the button if we have a recipient and we're not loading\n if (this.recipientPubkey && !this.isLoading) {\n sendButton.removeAttribute(\"disabled\");\n }\n \n debug(this, \"Send button event listener attached\");\n } else {\n debug(this, \"Send button not found in DOM\");\n }\n\n // Textarea\n const textarea = this.shadowRoot!.querySelector(\".nostr-dm-textarea\");\n if (textarea) {\n // Remove any existing listener\n if (this.boundHandleTextareaChange) {\n textarea.removeEventListener(\"input\", this.boundHandleTextareaChange);\n }\n\n // Create and store a new bound handler\n this.boundHandleTextareaChange = this.handleTextareaChange.bind(this);\n textarea.addEventListener(\"input\", this.boundHandleTextareaChange);\n }\n\n // Npub input\n const npubInput = this.shadowRoot!.querySelector(\".nostr-dm-npub-input\");\n if (npubInput) {\n // Add keydown event listener for Enter key\n npubInput.addEventListener(\"keydown\", (e: Event) => {\n if ((e as KeyboardEvent).key === \"Enter\") {\n this.handleFindClick();\n }\n });\n }\n }\n\n disconnectedCallback() {\n // Clean up event listeners\n const findButton = this.shadowRoot?.querySelector(\".nostr-dm-find-btn\");\n if (findButton && this.boundHandleFind) {\n findButton.removeEventListener(\"click\", this.boundHandleFind);\n }\n\n const sendButton = this.shadowRoot?.querySelector(\".nostr-dm-send-btn\");\n if (sendButton && this.boundHandleSend) {\n sendButton.removeEventListener(\"click\", this.boundHandleSend);\n }\n\n const textarea = this.shadowRoot?.querySelector(\".nostr-dm-textarea\");\n if (textarea && this.boundHandleTextareaChange) {\n textarea.removeEventListener(\"input\", this.boundHandleTextareaChange);\n }\n }\n\n private render() {\n debug(this, \"Rendering with state:\", {\n recipientNpub: this.recipientNpub,\n recipientPubkey: this.recipientPubkey,\n message: this.message ? \"[message content]\" : \"[empty]\",\n isLoading: this.isLoading,\n isFinding: this.isFinding,\n isError: this.isError,\n isSent: this.isSent\n });\n \n const renderOptions: RenderDmOptions = {\n theme: this.theme,\n recipientNpub: this.recipientNpub,\n recipientName: this.recipientName,\n recipientPicture: this.recipientPicture,\n message: this.message,\n isLoading: this.isLoading,\n isFinding: this.isFinding,\n isError: this.isError,\n errorMessage: this.errorMessage,\n isSent: this.isSent,\n };\n\n this.shadowRoot!.innerHTML = renderDm(renderOptions);\n this.attachEventListeners();\n }\n}\n\ncustomElements.define(\"nostr-dm\", NostrDm);\n"],"file":"components/nostr-dm.es.js"}
@@ -1,4 +1,4 @@
1
- var v=Object.defineProperty;var w=(n,e,o)=>e in n?v(n,e,{enumerable:!0,configurable:!0,writable:!0,value:o}):n[e]=o;var f=(n,e,o)=>w(n,typeof e!="symbol"?e+"":e,o);import{d as m}from"../assets/nostr-service-pr_crY62.js";import{N as p}from"../assets/nostr-user-component-BOdux8_6.js";import{b as y,g as k,a as b}from"../assets/theme-C1r1Zw8r.js";import{e as c,g as S,a as l}from"../assets/base-styles-CBypR3FR.js";import"../assets/user-resolver-C-E6KdwY.js";import"../assets/icons-Dr_d9MII.js";function C({isLoading:n,isError:e,errorMessage:o,isFollowed:t,isFollowing:r,showAvatar:i=!1,user:s,profile:a,customText:h="Follow me on nostr"}){if(r)return F();if(n)return x();if(e)return N(o||"");const u=t?y("light"):i&&s&&(a!=null&&a.image)?`<img src="${c(a.image)}" alt="${c(a.name||s.npub)}" class="user-avatar" />`:k(),g=t?"Followed":`<span>${c(h)}</span>`;return d(u,g)}function x(){return d(b(),"<span>Loading...</span>")}function F(){return d(b(),"<span>Following...</span>")}function N(n){return d('<div class="error-icon">&#9888;</div>',c(n))}function d(n,e){return`
1
+ var w=Object.defineProperty;var g=(n,e,o)=>e in n?w(n,e,{enumerable:!0,configurable:!0,writable:!0,value:o}):n[e]=o;var h=(n,e,o)=>g(n,typeof e!="symbol"?e+"":e,o);import{d as m}from"../assets/nostr-service-m3Hgc5Xx.js";import{N as p}from"../assets/nostr-user-component-XEnanH-d.js";import{b as y,g as S,a as b}from"../assets/theme-C1r1Zw8r.js";import{e as a,g as C,a as s}from"../assets/base-styles-DC0ilu4S.js";import{e as F}from"../assets/nostr-login-service-D2FmscPI.js";import"../assets/user-resolver-DqI5KGh6.js";import"../assets/icons-Dr_d9MII.js";import"../assets/preload-helper-D7HrI6pR.js";function k({isLoading:n,isError:e,errorMessage:o,isFollowed:t,isFollowing:r,showAvatar:d=!1,user:l,profile:i,customText:f="Follow me on nostr"}){if(r)return L();if(n)return x();if(e)return N(o||"");const u=t?y("light"):d&&l&&(i!=null&&i.image)?`<img src="${a(i.image)}" alt="${a(i.name||l.npub)}" class="user-avatar" />`:S(),v=t?"Followed":`<span>${a(f)}</span>`;return c(u,v)}function x(){return c(b(),"<span>Loading...</span>")}function L(){return c(b(),"<span>Following...</span>")}function N(n){return c('<div class="error-icon">&#9888;</div>',a(n))}function c(n,e){return`
2
2
  <div class='nostr-follow-button-container'>
3
3
  <div class='nostr-follow-button-left-container'>
4
4
  ${n}
@@ -7,7 +7,7 @@ var v=Object.defineProperty;var w=(n,e,o)=>e in n?v(n,e,{enumerable:!0,configura
7
7
  ${e}
8
8
  </div>
9
9
  </div>
10
- `}function L(){return S(`
10
+ `}function E(){return C(`
11
11
  /* === FOLLOW BUTTON CONTAINER PATTERN === */
12
12
  :host {
13
13
  /* Icon sizing (overridable) */
@@ -95,9 +95,8 @@ var v=Object.defineProperty;var w=(n,e,o)=>e in n?v(n,e,{enumerable:!0,configura
95
95
  display: inline-block;
96
96
  vertical-align: middle;
97
97
  }
98
- `)}class E extends p{constructor(){super(...arguments);f(this,"followStatus",this.channel("follow"));f(this,"isFollowed",!1)}static get observedAttributes(){return[...super.observedAttributes,"show-avatar","text"]}connectedCallback(){var o;(o=super.connectedCallback)==null||o.call(this),this.attachDelegatedListeners(),this.render()}attributeChangedCallback(o,t,r){t!==r&&(super.attributeChangedCallback(o,t,r),this.render())}onStatusChange(o){this.render()}onUserReady(o,t){this.render()}async handleFollowClick(){var t;if(this.computeOverall()!==l.Ready)return;const o=new m;this.followStatus.set(l.Loading),this.render();try{const r=this.nostrService.getNDK();if(r.signer=o,!this.user){this.followStatus.set(l.Error,"Could not resolve user to follow."),this.render();return}const i=r.signer;if(!i)throw new Error("No signer available");const s=await i.user();s&&await s.follow(this.user),this.isFollowed=!0,this.followStatus.set(l.Ready)}catch(r){const i=r;let s;(t=i.message)!=null&&t.includes("NIP-07")?s=`Looks like you don't have any nostr signing browser extension.
99
- Please checkout the following video to setup a signer extension - <a href="https://youtu.be/8thRYn14nB0?t=310" target="_blank">Video</a>`:s="Please authorize, click the button to try again!",this.followStatus.set(l.Error,s)}finally{this.render()}}attachDelegatedListeners(){this.delegateEvent("click",".nostr-follow-button-container",o=>{var t,r;(t=o.preventDefault)==null||t.call(o),(r=o.stopPropagation)==null||r.call(o),this.handleFollowClick()})}renderContent(){const o=this.computeOverall()==l.Loading,t=this.followStatus.get()==l.Loading,r=this.computeOverall()===l.Error,i=super.renderError(this.errorMessage),s=this.hasAttribute("show-avatar"),a=this.getAttribute("text")||"Follow me on nostr",h={isLoading:o,isError:r,errorMessage:i,isFollowed:this.isFollowed,isFollowing:t,showAvatar:s,user:this.user,profile:this.profile,customText:a};this.shadowRoot.innerHTML=`
100
- ${L()}
101
- ${C(h)}
102
- `}}customElements.define("nostr-follow-button",E);
98
+ `)}class z extends p{constructor(){super(...arguments);h(this,"followStatus",this.channel("follow"));h(this,"isFollowed",!1)}static get observedAttributes(){return[...super.observedAttributes,"show-avatar","text"]}connectedCallback(){var o;(o=super.connectedCallback)==null||o.call(this),this.attachDelegatedListeners(),this.render()}attributeChangedCallback(o,t,r){t!==r&&(super.attributeChangedCallback(o,t,r),this.render())}onStatusChange(o){this.render()}onUserReady(o,t){this.render()}async handleFollowClick(){if(this.computeOverall()===s.Ready){this.followStatus.set(s.Loading),this.render();try{await F();const o=new m,t=this.nostrService.getNDK();if(t.signer=o,!this.user){this.followStatus.set(s.Error,"Could not resolve user to follow."),this.render();return}const r=await o.user();r&&await r.follow(this.user),this.isFollowed=!0,this.followStatus.set(s.Ready)}catch(o){const r=o.message||"Please authorize, click the button to try again!";this.followStatus.set(s.Error,r)}finally{this.render()}}}attachDelegatedListeners(){this.delegateEvent("click",".nostr-follow-button-container",o=>{var t,r;(t=o.preventDefault)==null||t.call(o),(r=o.stopPropagation)==null||r.call(o),this.handleFollowClick()})}renderContent(){const o=this.computeOverall()==s.Loading,t=this.followStatus.get()==s.Loading,r=this.computeOverall()===s.Error,d=super.renderError(this.errorMessage),l=this.hasAttribute("show-avatar"),i=this.getAttribute("text")||"Follow me on nostr",f={isLoading:o,isError:r,errorMessage:d,isFollowed:this.isFollowed,isFollowing:t,showAvatar:l,user:this.user,profile:this.profile,customText:i};this.shadowRoot.innerHTML=`
99
+ ${E()}
100
+ ${k(f)}
101
+ `}}customElements.define("nostr-follow-button",z);
103
102
  //# sourceMappingURL=nostr-follow-button.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"nostr-follow-button.es.js","sources":["../../src/nostr-follow-button/render.ts","../../src/nostr-follow-button/style.ts","../../src/nostr-follow-button/nostr-follow-button.ts"],"sourcesContent":["// SPDX-License-Identifier: MIT\n\nimport {\n getLoadingNostrich,\n getNostrLogo,\n getSuccessAnimation,\n} from '../common/theme';\nimport { escapeHtml } from '../common/utils';\nimport { IRenderOptions } from '../base/render-options';\nimport { NDKUser, NDKUserProfile } from '@nostr-dev-kit/ndk';\n\nexport interface RenderFollowButtonOptions extends IRenderOptions {\n isFollowed: boolean;\n isFollowing: boolean;\n showAvatar?: boolean;\n user?: NDKUser | null;\n profile?: NDKUserProfile | null;\n customText?: string;\n}\n\nexport function renderFollowButton({\n isLoading,\n isError,\n errorMessage,\n isFollowed,\n isFollowing,\n showAvatar = false,\n user,\n profile,\n customText = 'Follow me on nostr',\n}: RenderFollowButtonOptions): string {\n\n if (isFollowing) {\n return renderFollowing();\n }\n\n if (isLoading) {\n return renderLoading();\n }\n\n if (isError) {\n return renderError(errorMessage || '');\n }\n\n const iconContent = isFollowed\n ? getSuccessAnimation('light')\n : showAvatar && user && profile?.image\n ? `<img src=\"${escapeHtml(profile.image)}\" alt=\"${escapeHtml(profile.name || user.npub)}\" class=\"user-avatar\" />`\n : getNostrLogo();\n const textContent = isFollowed\n ? 'Followed'\n : `<span>${escapeHtml(customText)}</span>`;\n\n return renderContainer(iconContent, textContent);\n}\n\nfunction renderLoading(): string {\n return renderContainer(\n getLoadingNostrich(), // Use default values\n '<span>Loading...</span>'\n );\n}\n\nfunction renderFollowing(): string {\n return renderContainer(\n getLoadingNostrich(), // Use default values\n '<span>Following...</span>'\n );\n}\n\nfunction renderError(errorMessage: string): string {\n return renderContainer(\n '<div class=\"error-icon\">&#9888;</div>',\n escapeHtml(errorMessage)\n );\n}\n\nfunction renderContainer(leftContent: string, rightContent: string): string {\n return `\n <div class='nostr-follow-button-container'>\n <div class='nostr-follow-button-left-container'>\n ${leftContent}\n </div>\n <div class='nostr-follow-button-right-container'>\n ${rightContent}\n </div>\n </div>\n `;\n}","// SPDX-License-Identifier: MIT\n\nimport { getComponentStyles } from \"../common/base-styles\";\n\nexport function getFollowButtonStyles(): string {\n const customStyles = `\n /* === FOLLOW BUTTON CONTAINER PATTERN === */\n :host {\n /* Icon sizing (overridable) */\n --nostrc-icon-height: 25px;\n --nostrc-icon-width: 25px;\n\n /* Follow button CSS variables (overridable by parent components) */\n --nostrc-follow-btn-padding: var(--nostrc-spacing-sm) var(--nostrc-spacing-md);\n --nostrc-follow-btn-border-radius: var(--nostrc-border-radius-md);\n --nostrc-follow-btn-border: var(--nostrc-border-width) solid var(--nostrc-color-border);\n --nostrc-follow-btn-min-height: auto;\n --nostrc-follow-btn-width: auto;\n --nostrc-follow-btn-horizontal-alignment: left;\n --nostrc-follow-btn-bg: var(--nostrc-theme-bg, #ffffff);\n --nostrc-follow-btn-color: var(--nostrc-theme-text-primary, #333333);\n --nostrc-follow-btn-font-family: var(--nostrc-font-family-primary);\n --nostrc-follow-btn-font-size: var(--nostrc-font-size-base);\n \n /* Hover state variables */\n --nostrc-follow-btn-hover-bg: var(--nostrc-theme-hover-bg, rgba(0, 0, 0, 0.05));\n --nostrc-follow-btn-hover-color: var(--nostrc-theme-text-primary, #333333);\n --nostrc-follow-btn-hover-border: var(--nostrc-border-width) solid var(--nostrc-theme-border, var(--nostrc-color-border));\n\n /* Make the host the visual button surface */\n display: inline-flex;\n align-items: center;\n justify-content: var(--nostrc-follow-btn-horizontal-alignment);\n gap: var(--nostrc-spacing-md);\n background: var(--nostrc-follow-btn-bg);\n color: var(--nostrc-follow-btn-color);\n border: var(--nostrc-follow-btn-border);\n border-radius: var(--nostrc-follow-btn-border-radius);\n font-family: var(--nostrc-follow-btn-font-family);\n font-size: var(--nostrc-follow-btn-font-size);\n min-height: var(--nostrc-follow-btn-min-height);\n width: var(--nostrc-follow-btn-width);\n cursor: pointer;\n transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;\n }\n\n /* Hover state */\n :host(.is-clickable:hover) {\n background: var(--nostrc-follow-btn-hover-bg);\n color: var(--nostrc-follow-btn-hover-color);\n border: var(--nostrc-follow-btn-hover-border);\n }\n\n /* Focus state for accessibility */\n :host(:focus-visible) {\n outline: 2px solid var(--nostrc-color-primary, #007bff);\n outline-offset: 2px;\n }\n\n :host(.is-error) .nostr-follow-button-container {\n color: var(--nostrc-color-error-text);\n border: var(--nostrc-border-width) solid var(--nostrc-color-error-text);\n }\n\n .nostr-follow-button-container {\n display: flex;\n gap: var(--nostrc-spacing-md);\n width: fit-content;\n padding: var(--nostrc-follow-btn-padding);\n }\n \n .nostr-follow-button-right-container {\n margin: auto;\n }\n \n /* SVG Icon Styles */\n .nostr-follow-button-left-container svg {\n fill: var(--nostrc-follow-btn-color);\n display: inline-block;\n vertical-align: middle;\n width: var(--nostrc-icon-width);\n height: var(--nostrc-icon-height);\n }\n\n /* User Avatar Styles */\n .nostr-follow-button-left-container .user-avatar {\n width: var(--nostrc-icon-width);\n height: var(--nostrc-icon-height);\n border-radius: 50%;\n object-fit: cover;\n display: inline-block;\n vertical-align: middle;\n }\n `;\n \n // Use simple component styles - includes design tokens + utilities + custom styles\n return getComponentStyles(customStyles);\n}\n","// SPDX-License-Identifier: MIT\n\nimport { NDKNip07Signer } from '@nostr-dev-kit/ndk';\nimport { NostrUserComponent } from '../base/user-component/nostr-user-component';\nimport { renderFollowButton, RenderFollowButtonOptions } from './render';\nimport { NCStatus } from '../base/base-component/nostr-base-component';\nimport { getFollowButtonStyles } from './style';\n\n/**\n * TODO:\n * 1. To have a text attribute. Default value being \"Follow me on Nostr\"\n * 2. show-avatar attribute to show the avatar of the user, instead of nostr logo.\n */\nexport default class NostrFollowButton extends NostrUserComponent {\n\n protected followStatus = this.channel('follow');\n private isFollowed: boolean = false;\n\n static get observedAttributes() {\n return [...super.observedAttributes, 'show-avatar', 'text'];\n }\n\n connectedCallback() {\n super.connectedCallback?.();\n this.attachDelegatedListeners();\n this.render();\n }\n\n attributeChangedCallback(\n name: string,\n oldValue: string | null,\n newValue: string | null\n ) {\n if (oldValue === newValue) return;\n super.attributeChangedCallback(name, oldValue, newValue);\n this.render();\n }\n\n /** Base class functions */\n protected onStatusChange(_status: NCStatus) {\n this.render();\n }\n\n protected onUserReady(_user: any, _profile: any) {\n this.render();\n }\n\n /** Private functions */\n private async handleFollowClick() {\n if (this.computeOverall() !== NCStatus.Ready) return;\n const nip07signer = new NDKNip07Signer();\n\n this.followStatus.set(NCStatus.Loading);\n this.render();\n\n try {\n const ndk = this.nostrService.getNDK();\n ndk.signer = nip07signer;\n\n if (!this.user) {\n this.followStatus.set(NCStatus.Error, \"Could not resolve user to follow.\");\n this.render();\n return;\n\n }\n\n const signer = ndk.signer;\n if (!signer) {\n throw new Error('No signer available');\n }\n const signedUser = await signer.user();\n if (signedUser) {\n await signedUser.follow(this.user);\n }\n\n this.isFollowed = true;\n this.followStatus.set(NCStatus.Ready);\n } catch (err) {\n\n const error = err as Error;\n let errorMessage;\n if (error.message?.includes('NIP-07')) {\n errorMessage = `Looks like you don't have any nostr signing browser extension.\n Please checkout the following video to setup a signer extension - <a href=\"https://youtu.be/8thRYn14nB0?t=310\" target=\"_blank\">Video</a>`;\n } else {\n errorMessage = 'Please authorize, click the button to try again!';\n }\n this.followStatus.set(NCStatus.Error, errorMessage);\n } finally {\n this.render();\n }\n }\n\n private attachDelegatedListeners() {\n this.delegateEvent('click', '.nostr-follow-button-container', (e) => {\n e.preventDefault?.();\n e.stopPropagation?.();\n void this.handleFollowClick();\n });\n }\n\n protected renderContent() {\n const isLoading = this.computeOverall() == NCStatus.Loading;\n const isFollowing = this.followStatus.get() == NCStatus.Loading;\n const isError = this.computeOverall() === NCStatus.Error;\n const errorMessage = super.renderError(this.errorMessage);\n const showAvatar = this.hasAttribute('show-avatar');\n const customText = this.getAttribute('text') || 'Follow me on nostr';\n\n const renderOptions: RenderFollowButtonOptions = {\n isLoading : isLoading,\n isError : isError,\n errorMessage: errorMessage,\n isFollowed : this.isFollowed,\n isFollowing : isFollowing,\n showAvatar : showAvatar,\n user : this.user,\n profile : this.profile,\n customText : customText,\n };\n\n this.shadowRoot!.innerHTML = `\n ${getFollowButtonStyles()}\n ${renderFollowButton(renderOptions)}\n `\n }\n}\n\ncustomElements.define('nostr-follow-button', NostrFollowButton);\n"],"names":["renderFollowButton","isLoading","isError","errorMessage","isFollowed","isFollowing","showAvatar","user","profile","customText","renderFollowing","renderLoading","renderError","iconContent","getSuccessAnimation","escapeHtml","getNostrLogo","textContent","renderContainer","getLoadingNostrich","leftContent","rightContent","getFollowButtonStyles","getComponentStyles","NostrFollowButton","NostrUserComponent","__publicField","_a","name","oldValue","newValue","_status","_user","_profile","NCStatus","nip07signer","NDKNip07Signer","ndk","signer","signedUser","err","error","e","_b","renderOptions"],"mappings":"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"}
1
+ {"version":3,"file":"nostr-follow-button.es.js","sources":["../../src/nostr-follow-button/render.ts","../../src/nostr-follow-button/style.ts","../../src/nostr-follow-button/nostr-follow-button.ts"],"sourcesContent":["// SPDX-License-Identifier: MIT\n\nimport {\n getLoadingNostrich,\n getNostrLogo,\n getSuccessAnimation,\n} from '../common/theme';\nimport { escapeHtml } from '../common/utils';\nimport { IRenderOptions } from '../base/render-options';\nimport { NDKUser, NDKUserProfile } from '@nostr-dev-kit/ndk';\n\nexport interface RenderFollowButtonOptions extends IRenderOptions {\n isFollowed: boolean;\n isFollowing: boolean;\n showAvatar?: boolean;\n user?: NDKUser | null;\n profile?: NDKUserProfile | null;\n customText?: string;\n}\n\nexport function renderFollowButton({\n isLoading,\n isError,\n errorMessage,\n isFollowed,\n isFollowing,\n showAvatar = false,\n user,\n profile,\n customText = 'Follow me on nostr',\n}: RenderFollowButtonOptions): string {\n\n if (isFollowing) {\n return renderFollowing();\n }\n\n if (isLoading) {\n return renderLoading();\n }\n\n if (isError) {\n return renderError(errorMessage || '');\n }\n\n const iconContent = isFollowed\n ? getSuccessAnimation('light')\n : showAvatar && user && profile?.image\n ? `<img src=\"${escapeHtml(profile.image)}\" alt=\"${escapeHtml(profile.name || user.npub)}\" class=\"user-avatar\" />`\n : getNostrLogo();\n const textContent = isFollowed\n ? 'Followed'\n : `<span>${escapeHtml(customText)}</span>`;\n\n return renderContainer(iconContent, textContent);\n}\n\nfunction renderLoading(): string {\n return renderContainer(\n getLoadingNostrich(), // Use default values\n '<span>Loading...</span>'\n );\n}\n\nfunction renderFollowing(): string {\n return renderContainer(\n getLoadingNostrich(), // Use default values\n '<span>Following...</span>'\n );\n}\n\nfunction renderError(errorMessage: string): string {\n return renderContainer(\n '<div class=\"error-icon\">&#9888;</div>',\n escapeHtml(errorMessage)\n );\n}\n\nfunction renderContainer(leftContent: string, rightContent: string): string {\n return `\n <div class='nostr-follow-button-container'>\n <div class='nostr-follow-button-left-container'>\n ${leftContent}\n </div>\n <div class='nostr-follow-button-right-container'>\n ${rightContent}\n </div>\n </div>\n `;\n}","// SPDX-License-Identifier: MIT\n\nimport { getComponentStyles } from \"../common/base-styles\";\n\nexport function getFollowButtonStyles(): string {\n const customStyles = `\n /* === FOLLOW BUTTON CONTAINER PATTERN === */\n :host {\n /* Icon sizing (overridable) */\n --nostrc-icon-height: 25px;\n --nostrc-icon-width: 25px;\n\n /* Follow button CSS variables (overridable by parent components) */\n --nostrc-follow-btn-padding: var(--nostrc-spacing-sm) var(--nostrc-spacing-md);\n --nostrc-follow-btn-border-radius: var(--nostrc-border-radius-md);\n --nostrc-follow-btn-border: var(--nostrc-border-width) solid var(--nostrc-color-border);\n --nostrc-follow-btn-min-height: auto;\n --nostrc-follow-btn-width: auto;\n --nostrc-follow-btn-horizontal-alignment: left;\n --nostrc-follow-btn-bg: var(--nostrc-theme-bg, #ffffff);\n --nostrc-follow-btn-color: var(--nostrc-theme-text-primary, #333333);\n --nostrc-follow-btn-font-family: var(--nostrc-font-family-primary);\n --nostrc-follow-btn-font-size: var(--nostrc-font-size-base);\n \n /* Hover state variables */\n --nostrc-follow-btn-hover-bg: var(--nostrc-theme-hover-bg, rgba(0, 0, 0, 0.05));\n --nostrc-follow-btn-hover-color: var(--nostrc-theme-text-primary, #333333);\n --nostrc-follow-btn-hover-border: var(--nostrc-border-width) solid var(--nostrc-theme-border, var(--nostrc-color-border));\n\n /* Make the host the visual button surface */\n display: inline-flex;\n align-items: center;\n justify-content: var(--nostrc-follow-btn-horizontal-alignment);\n gap: var(--nostrc-spacing-md);\n background: var(--nostrc-follow-btn-bg);\n color: var(--nostrc-follow-btn-color);\n border: var(--nostrc-follow-btn-border);\n border-radius: var(--nostrc-follow-btn-border-radius);\n font-family: var(--nostrc-follow-btn-font-family);\n font-size: var(--nostrc-follow-btn-font-size);\n min-height: var(--nostrc-follow-btn-min-height);\n width: var(--nostrc-follow-btn-width);\n cursor: pointer;\n transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;\n }\n\n /* Hover state */\n :host(.is-clickable:hover) {\n background: var(--nostrc-follow-btn-hover-bg);\n color: var(--nostrc-follow-btn-hover-color);\n border: var(--nostrc-follow-btn-hover-border);\n }\n\n /* Focus state for accessibility */\n :host(:focus-visible) {\n outline: 2px solid var(--nostrc-color-primary, #007bff);\n outline-offset: 2px;\n }\n\n :host(.is-error) .nostr-follow-button-container {\n color: var(--nostrc-color-error-text);\n border: var(--nostrc-border-width) solid var(--nostrc-color-error-text);\n }\n\n .nostr-follow-button-container {\n display: flex;\n gap: var(--nostrc-spacing-md);\n width: fit-content;\n padding: var(--nostrc-follow-btn-padding);\n }\n \n .nostr-follow-button-right-container {\n margin: auto;\n }\n \n /* SVG Icon Styles */\n .nostr-follow-button-left-container svg {\n fill: var(--nostrc-follow-btn-color);\n display: inline-block;\n vertical-align: middle;\n width: var(--nostrc-icon-width);\n height: var(--nostrc-icon-height);\n }\n\n /* User Avatar Styles */\n .nostr-follow-button-left-container .user-avatar {\n width: var(--nostrc-icon-width);\n height: var(--nostrc-icon-height);\n border-radius: 50%;\n object-fit: cover;\n display: inline-block;\n vertical-align: middle;\n }\n `;\n \n // Use simple component styles - includes design tokens + utilities + custom styles\n return getComponentStyles(customStyles);\n}\n","// SPDX-License-Identifier: MIT\n\nimport { NDKNip07Signer } from '@nostr-dev-kit/ndk';\nimport { NostrUserComponent } from '../base/user-component/nostr-user-component';\nimport { renderFollowButton, RenderFollowButtonOptions } from './render';\nimport { NCStatus } from '../base/base-component/nostr-base-component';\nimport { getFollowButtonStyles } from './style';\nimport { ensureInitialized } from '../common/nostr-login-service';\n\n/**\n * TODO:\n * 1. To have a text attribute. Default value being \"Follow me on Nostr\"\n * 2. show-avatar attribute to show the avatar of the user, instead of nostr logo.\n */\nexport default class NostrFollowButton extends NostrUserComponent {\n\n protected followStatus = this.channel('follow');\n private isFollowed: boolean = false;\n\n static get observedAttributes() {\n return [...super.observedAttributes, 'show-avatar', 'text'];\n }\n\n connectedCallback() {\n super.connectedCallback?.();\n this.attachDelegatedListeners();\n this.render();\n }\n\n attributeChangedCallback(\n name: string,\n oldValue: string | null,\n newValue: string | null\n ) {\n if (oldValue === newValue) return;\n super.attributeChangedCallback(name, oldValue, newValue);\n this.render();\n }\n\n /** Base class functions */\n protected onStatusChange(_status: NCStatus) {\n this.render();\n }\n\n protected onUserReady(_user: any, _profile: any) {\n this.render();\n }\n\n /** Private functions */\n private async handleFollowClick() {\n if (this.computeOverall() !== NCStatus.Ready) return;\n\n this.followStatus.set(NCStatus.Loading);\n this.render();\n\n try {\n // Ensure NostrLogin is initialized (sets up window.nostr)\n await ensureInitialized();\n\n // Use NDKNip07Signer which works with window.nostr from NostrLogin\n const signer = new NDKNip07Signer();\n const ndk = this.nostrService.getNDK();\n ndk.signer = signer;\n\n if (!this.user) {\n this.followStatus.set(NCStatus.Error, \"Could not resolve user to follow.\");\n this.render();\n return;\n }\n\n const signedUser = await signer.user();\n if (signedUser) {\n await signedUser.follow(this.user);\n }\n\n this.isFollowed = true;\n this.followStatus.set(NCStatus.Ready);\n } catch (err) {\n const error = err as Error;\n // Generic error message - NostrLogin handles its own UI/errors\n const errorMessage = error.message || 'Please authorize, click the button to try again!';\n this.followStatus.set(NCStatus.Error, errorMessage);\n } finally {\n this.render();\n }\n }\n\n private attachDelegatedListeners() {\n this.delegateEvent('click', '.nostr-follow-button-container', (e) => {\n e.preventDefault?.();\n e.stopPropagation?.();\n void this.handleFollowClick();\n });\n }\n\n protected renderContent() {\n const isLoading = this.computeOverall() == NCStatus.Loading;\n const isFollowing = this.followStatus.get() == NCStatus.Loading;\n const isError = this.computeOverall() === NCStatus.Error;\n const errorMessage = super.renderError(this.errorMessage);\n const showAvatar = this.hasAttribute('show-avatar');\n const customText = this.getAttribute('text') || 'Follow me on nostr';\n\n const renderOptions: RenderFollowButtonOptions = {\n isLoading : isLoading,\n isError : isError,\n errorMessage: errorMessage,\n isFollowed : this.isFollowed,\n isFollowing : isFollowing,\n showAvatar : showAvatar,\n user : this.user,\n profile : this.profile,\n customText : customText,\n };\n\n this.shadowRoot!.innerHTML = `\n ${getFollowButtonStyles()}\n ${renderFollowButton(renderOptions)}\n `\n }\n}\n\ncustomElements.define('nostr-follow-button', NostrFollowButton);\n"],"names":["renderFollowButton","isLoading","isError","errorMessage","isFollowed","isFollowing","showAvatar","user","profile","customText","renderFollowing","renderLoading","renderError","iconContent","getSuccessAnimation","escapeHtml","getNostrLogo","textContent","renderContainer","getLoadingNostrich","leftContent","rightContent","getFollowButtonStyles","getComponentStyles","NostrFollowButton","NostrUserComponent","__publicField","_a","name","oldValue","newValue","_status","_user","_profile","NCStatus","ensureInitialized","signer","NDKNip07Signer","ndk","signedUser","err","e","_b","renderOptions"],"mappings":"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"}
@@ -1,28 +1,28 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/dialog-likers-BjiCHFan.js","assets/preload-helper-D7HrI6pR.js","assets/dialog-component-Da1ZIYh9.js","assets/zap-utils-B1sz0Abx.js","assets/nostr-service-pr_crY62.js","assets/utils--bxLbhGF.js","assets/base-styles-CBypR3FR.js"])))=>i.map(i=>d[i]);
2
- var m=Object.defineProperty;var w=(r,e,t)=>e in r?m(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t;var d=(r,e,t)=>w(r,typeof e!="symbol"?e+"":e,t);import{_ as y}from"../assets/preload-helper-D7HrI6pR.js";import{e as b,g as L,N as x,a as i,c as C}from"../assets/base-styles-CBypR3FR.js";import{S as f,e as g}from"../assets/nostr-service-pr_crY62.js";import"../assets/dialog-component-Da1ZIYh9.js";function S({isLoading:r,isError:e,errorMessage:t,buttonText:n,isLiked:o,likeCount:s,hasLikes:a=!1,isCountLoading:l=!1,theme:u="light"}){if(e)return E(t||"");const c=N(o,u),h=o?"<span>Liked</span>":`<span>${b(n)}</span>`;return U(c,h,s,a,o,r,l)}function E(r){return A('<div class="error-icon">&#9888;</div>',b(r))}function A(r,e){return`
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/dialog-likers-D3c7WIMp.js","assets/preload-helper-D7HrI6pR.js","assets/dialog-component-Dqg0QU9I.js","assets/zap-utils-BZcaCsT_.js","assets/nostr-service-m3Hgc5Xx.js","assets/nostr-login-service-D2FmscPI.js","assets/utils--bxLbhGF.js","assets/base-styles-DC0ilu4S.js"])))=>i.map(i=>d[i]);
2
+ var y=Object.defineProperty;var w=(o,e,t)=>e in o?y(o,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):o[e]=t;var d=(o,e,t)=>w(o,typeof e!="symbol"?e+"":e,t);import{_ as L}from"../assets/preload-helper-D7HrI6pR.js";import{e as v,g as C,N as x,a as i,c as S}from"../assets/base-styles-DC0ilu4S.js";import{S as f,e as g}from"../assets/nostr-service-m3Hgc5Xx.js";import"../assets/dialog-component-Dqg0QU9I.js";import{e as p,g as E,s as A}from"../assets/nostr-login-service-D2FmscPI.js";function U({isLoading:o,isError:e,errorMessage:t,buttonText:r,isLiked:n,likeCount:s,hasLikes:a=!1,isCountLoading:l=!1,theme:u="light"}){if(e)return z(t||"");const c=$(n,u),h=n?"<span>Liked</span>":`<span>${v(r)}</span>`;return N(c,h,s,a,n,o,l)}function z(o){return D('<div class="error-icon">&#9888;</div>',v(o))}function D(o,e){return`
3
3
  <div class="nostr-like-button-container">
4
4
  <div class="nostr-like-button-left-container">
5
- ${r}
5
+ ${o}
6
6
  </div>
7
7
  <div class="nostr-like-button-right-container">
8
8
  ${e}
9
9
  </div>
10
10
  </div>
11
- `}function U(r,e,t,n=!1,o=!1,s=!1,a=!1){let l="";return a?l='<span class="like-count skeleton"></span>':t>0&&(l=`<span class="like-count${n?" clickable":""}">${t} ${t===1?"like":"likes"}</span>`),`
11
+ `}function N(o,e,t,r=!1,n=!1,s=!1,a=!1){let l="";return a?l='<span class="like-count skeleton"></span>':t>0&&(l=`<span class="like-count${r?" clickable":""}">${t} ${t===1?"like":"likes"}</span>`),`
12
12
  <div class="nostr-like-button-container">
13
- <button class="${o?"nostr-like-button liked":"nostr-like-button"}">
14
- ${r}
13
+ <button class="${n?"nostr-like-button liked":"nostr-like-button"}">
14
+ ${o}
15
15
  ${s?'<span class="button-text-skeleton"></span>':e}
16
16
  </button>
17
17
  ${l} <button class="help-icon" title="What is a like?">?</button>
18
18
  </div>
19
- `}function N(r,e="light"){const t=e==="dark"?"#8ab4f8":"#1877f2",n=e==="dark"?"#e0e7ff":"#0d46a1";return r?`<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 100 100" width="24" height="24">
19
+ `}function $(o,e="light"){const t=e==="dark"?"#8ab4f8":"#1877f2",r=e==="dark"?"#e0e7ff":"#0d46a1";return o?`<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 100 100" width="24" height="24">
20
20
  <path d="M93.6,53.1c2.6-1.5,4.2-4.4,3.8-7.6c-0.5-4-4.2-6.8-8.2-6.8l-25,0c0.2-0.5,0.5-1.2,0.7-1.8c1.5-3.8,4.3-10.8,4.3-18 c0-8.1-5.7-13-9.6-13.3C57.2,5.5,55.4,7,55,9.7c-0.7,5.1-4.1,12.6-5.5,15.5c-0.4,0.9-0.9,1.7-1.6,2.4c-2.3,2.6-8.1,9-13.6,12.8 c0,0.2,0.1,0.5,0.1,0.7v47.9c0,0.4-0.1,0.8-0.1,1.2c9.4,2.7,17.9,4,27.2,4l21.3,0c3.7,0,7.2-2.5,7.9-6.1c0.6-3-0.5-5.7-2.5-7.5 c3.4-0.8,6-3.9,6-7.5c0-2.3-1-4.4-2.7-5.8c3.4-0.8,6-3.9,6-7.5C97.5,57,96,54.5,93.6,53.1z" fill="${t}"/>
21
21
  <path d="M23.4,36.9H6.7c-2.3,0-4.2,1.9-4.2,4.2v47.9c0,2.3,1.9,4.2,4.2,4.2h16.7c2.3,0,4.2-1.9,4.2-4.2V41.2 C27.6,38.8,25.8,36.9,23.4,36.9z M15.1,85.9c-2.4,0-4.4-2-4.4-4.4s2-4.4,4.4-4.4c2.4,0,4.4,2,4.4,4.4S17.5,85.9,15.1,85.9z" fill="${t}"/>
22
22
  </svg>`:`<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 100 100" width="24" height="24">
23
- <path d="M93.6,53.1c2.6-1.5,4.2-4.4,3.8-7.6c-0.5-4-4.2-6.8-8.2-6.8l-25,0c0.2-0.5,0.5-1.2,0.7-1.8c1.5-3.8,4.3-10.8,4.3-18 c0-8.1-5.7-13-9.6-13.3C57.2,5.5,55.4,7,55,9.7c-0.7,5.1-4.1,12.6-5.5,15.5c-0.4,0.9-0.9,1.7-1.6,2.4c-2.3,2.6-8.1,9-13.6,12.8 c0,0.2,0.1,0.5,0.1,0.7v47.9c0,0.4-0.1,0.8-0.1,1.2c9.4,2.7,17.9,4,27.2,4l21.3,0c3.7,0,7.2-2.5,7.9-6.1c0.6-3-0.5-5.7-2.5-7.5 c3.4-0.8,6-3.9,6-7.5c0-2.3-1-4.4-2.7-5.8c3.4-0.8,6-3.9,6-7.5C97.5,57,96,54.5,93.6,53.1z" fill="none" stroke="${n}" stroke-width="2"/>
24
- <path d="M23.4,36.9H6.7c-2.3,0-4.2,1.9-4.2,4.2v47.9c0,2.3,1.9,4.2,4.2,4.2h16.7c2.3,0,4.2-1.9,4.2-4.2V41.2 C27.6,38.8,25.8,36.9,23.4,36.9z M15.1,85.9c-2.4,0-4.4-2-4.4-4.4s2-4.4,4.4-4.4c2.4,0,4.4,2,4.4,4.4S17.5,85.9,15.1,85.9z" fill="none" stroke="${n}" stroke-width="2"/>
25
- </svg>`}function z(){return L(`
23
+ <path d="M93.6,53.1c2.6-1.5,4.2-4.4,3.8-7.6c-0.5-4-4.2-6.8-8.2-6.8l-25,0c0.2-0.5,0.5-1.2,0.7-1.8c1.5-3.8,4.3-10.8,4.3-18 c0-8.1-5.7-13-9.6-13.3C57.2,5.5,55.4,7,55,9.7c-0.7,5.1-4.1,12.6-5.5,15.5c-0.4,0.9-0.9,1.7-1.6,2.4c-2.3,2.6-8.1,9-13.6,12.8 c0,0.2,0.1,0.5,0.1,0.7v47.9c0,0.4-0.1,0.8-0.1,1.2c9.4,2.7,17.9,4,27.2,4l21.3,0c3.7,0,7.2-2.5,7.9-6.1c0.6-3-0.5-5.7-2.5-7.5 c3.4-0.8,6-3.9,6-7.5c0-2.3-1-4.4-2.7-5.8c3.4-0.8,6-3.9,6-7.5C97.5,57,96,54.5,93.6,53.1z" fill="none" stroke="${r}" stroke-width="2"/>
24
+ <path d="M23.4,36.9H6.7c-2.3,0-4.2,1.9-4.2,4.2v47.9c0,2.3,1.9,4.2,4.2,4.2h16.7c2.3,0,4.2-1.9,4.2-4.2V41.2 C27.6,38.8,25.8,36.9,23.4,36.9z M15.1,85.9c-2.4,0-4.4-2-4.4-4.4s2-4.4,4.4-4.4c2.4,0,4.4,2,4.4,4.4S17.5,85.9,15.1,85.9z" fill="none" stroke="${r}" stroke-width="2"/>
25
+ </svg>`}function R(){return C(`
26
26
  /* === LIKE BUTTON CONTAINER PATTERN === */
27
27
  :host {
28
28
  /* Icon sizing (overridable via CSS variables) */
@@ -237,7 +237,7 @@ var m=Object.defineProperty;var w=(r,e,t)=>e in r?m(r,e,{enumerable:!0,configura
237
237
  max-width: 250px;
238
238
  white-space: pre-line;
239
239
  }
240
- `)}function D(){return`
240
+ `)}function M(){return`
241
241
  .help-content {
242
242
  padding: var(--nostrc-spacing-md, 12px);
243
243
  }
@@ -280,7 +280,7 @@ var m=Object.defineProperty;var w=(r,e,t)=>e in r?m(r,e,{enumerable:!0,configura
280
280
  .help-content a:hover {
281
281
  color: var(--nostrc-theme-primary-hover, #0052a3);
282
282
  }
283
- `}const R=()=>{if(document.querySelector("style[data-help-dialog-styles]"))return;const r=document.createElement("style");r.setAttribute("data-help-dialog-styles","true"),r.textContent=D(),document.head.appendChild(r)},$=async r=>{R(),customElements.get("dialog-component")||await customElements.whenDefined("dialog-component");const e=document.createElement("dialog-component");e.setAttribute("header","What is a Like?"),r&&e.setAttribute("data-theme",r),e.innerHTML=`
283
+ `}const I=()=>{if(document.querySelector("style[data-help-dialog-styles]"))return;const o=document.createElement("style");o.setAttribute("data-help-dialog-styles","true"),o.textContent=M(),document.head.appendChild(o)},H=async o=>{I(),customElements.get("dialog-component")||await customElements.whenDefined("dialog-component");const e=document.createElement("dialog-component");e.setAttribute("header","What is a Like?"),e.setAttribute("data-theme",o),e.innerHTML=`
284
284
  <div class="help-content">
285
285
  <p>Like any webpage to show your appreciation! Your likes are stored on Nostr, a decentralized network you control—no accounts needed.</p>
286
286
  <ul>
@@ -289,8 +289,8 @@ var m=Object.defineProperty;var w=(r,e,t)=>e in r?m(r,e,{enumerable:!0,configura
289
289
  <li>Works with a browser extension like <a href="https://getalby.com" target="_blank" rel="noopener noreferrer">Alby</a> or nos2x</li>
290
290
  </ul>
291
291
  </div>
292
- `,e.showModal()};new TextDecoder("utf-8");new TextEncoder;function k(r){r.indexOf("://")===-1&&(r="wss://"+r);let e=new URL(r);return e.pathname=e.pathname.replace(/\/+/g,"/"),e.pathname.endsWith("/")&&(e.pathname=e.pathname.slice(0,-1)),(e.port==="80"&&e.protocol==="ws:"||e.port==="443"&&e.protocol==="wss:")&&(e.port=""),e.searchParams.sort(),e.hash="",e.toString()}async function I(r,e){const t=k(r),n=new f;try{const o=await n.querySync(e,{kinds:[17],"#k":["web"],"#i":[t],limit:1e3}),s=[];let a=0,l=0;for(const c of o)s.push({authorPubkey:c.pubkey,date:new Date(c.created_at*1e3),content:c.content}),c.content==="-"?l++:a++;return s.sort((c,h)=>h.date.getTime()-c.date.getTime()),{totalCount:a-l,likeDetails:s,likedCount:a,dislikedCount:l}}catch(o){throw o instanceof Error?o:new Error(String(o))}finally{n.close(e)}}function v(r,e){return{kind:17,content:e,tags:[["k","web"],["i",r]],created_at:Math.floor(Date.now()/1e3)}}function M(r){return v(r,"+")}function H(r){return v(r,"-")}async function P(r,e,t){const n=new f,o=r;try{const s=await n.querySync(t,{kinds:[17],authors:[e],"#k":["web"],"#i":[o],limit:1});if(s.length===0)return!1;const a=s[0];return a.content==="+"||a.content===""}catch(s){return console.error("Nostr-Components: Like button: Error checking user like status",s),!1}finally{n.close(t)}}async function T(){try{if(typeof window<"u"&&window.nostr)return await window.nostr.getPublicKey()}catch(r){console.error("Nostr-Components: Like button: Error getting user pubkey",r)}return null}async function p(r){try{if(typeof window<"u"&&window.nostr)return await window.nostr.signEvent(r);throw new Error("NIP-07 extension not available")}catch(e){throw console.error("Nostr-Components: Like button: Error signing event",e),e}}function _(){return typeof window<"u"&&!!window.nostr}class F extends x{constructor(){super();d(this,"likeActionStatus",this.channel("likeAction"));d(this,"likeListStatus",this.channel("likeList"));d(this,"currentUrl","");d(this,"isLiked",!1);d(this,"likeCount",0);d(this,"cachedLikeDetails",null);d(this,"loadSeq",0)}connectedCallback(){var t;(t=super.connectedCallback)==null||t.call(this),this.likeListStatus.get()===i.Idle&&this.initChannelStatus("likeList",i.Loading,{reflectOverall:!1}),this.attachDelegatedListeners(),this.render()}static get observedAttributes(){return[...super.observedAttributes,"url","text"]}attributeChangedCallback(t,n,o){n!==o&&(super.attributeChangedCallback(t,n,o),(t==="url"||t==="text")&&(this.likeActionStatus.set(i.Ready),this.likeListStatus.set(i.Loading),this.isLiked=!1,this.errorMessage="",this.updateLikeCount(),this.render()))}validateInputs(){if(!super.validateInputs())return this.likeActionStatus.set(i.Idle),this.likeListStatus.set(i.Idle),!1;const t=this.getAttribute("url"),n=this.getAttribute("text"),o=this.tagName.toLowerCase();let s=null;return t&&(C(t)||(s="Invalid URL format")),n&&n.length>32&&(s="Max text length: 32 characters"),s?(this.likeActionStatus.set(i.Error,s),this.likeListStatus.set(i.Error,s),console.error(`Nostr-Components: ${o}: ${s}`),!1):!0}onStatusChange(t){this.render()}onNostrRelaysConnected(){this.updateLikeCount(),this.render()}ensureCurrentUrl(){this.currentUrl||(this.currentUrl=k(this.getAttribute("url")||window.location.href))}async updateLikeCount(){const t=++this.loadSeq;try{await this.ensureNostrConnected(),this.currentUrl=k(this.getAttribute("url")||window.location.href),this.likeListStatus.set(i.Loading),this.render();const n=await I(this.currentUrl,this.getRelays());if(t!==this.loadSeq)return;this.likeCount=n.totalCount,this.cachedLikeDetails=n,this.likeListStatus.set(i.Ready)}catch(n){console.error("[NostrLike] Failed to fetch like count:",n),this.likeListStatus.set(i.Error,"Failed to load likes")}finally{this.render()}}async handleLikeClick(){if(this.ensureCurrentUrl(),!this.currentUrl){this.likeActionStatus.set(i.Error,"Invalid URL"),this.render();return}if(this.likeActionStatus.set(i.Loading),!_()){this.likeActionStatus.set(i.Error,"Please install a Nostr browser extension (Alby, nos2x, etc.)"),this.render();return}try{const t=await T();t&&(this.isLiked=await P(this.currentUrl,t,this.getRelays()))}catch(t){console.error("[NostrLike] Failed to check user like status:",t),this.likeActionStatus.set(i.Error,"Failed to check user like status")}finally{this.render()}if(this.isLiked){if(!window.confirm("You have already liked this. Do you want to unlike it?")){this.likeActionStatus.set(i.Ready),this.render();return}await this.handleUnlike()}else await this.handleLike()}async handleLike(){if(this.ensureCurrentUrl(),!this.currentUrl){this.likeActionStatus.set(i.Error,"Invalid URL"),this.render();return}this.likeActionStatus.set(i.Loading),this.render();try{const t=M(this.currentUrl),n=await p(t);await new g(this.nostrService.getNDK(),n).publish(),this.isLiked=!0,this.likeCount++,this.likeActionStatus.set(i.Ready),await this.updateLikeCount()}catch(t){console.error("[NostrLike] Failed to like:",t),this.isLiked=!1,this.likeCount--;const n=t instanceof Error?t.message:"Failed to like";this.likeActionStatus.set(i.Error,n)}finally{this.render()}}async handleUnlike(){if(this.ensureCurrentUrl(),!this.currentUrl){this.likeActionStatus.set(i.Error,"Invalid URL"),this.render();return}this.likeActionStatus.set(i.Loading),this.render();try{const t=H(this.currentUrl),n=await p(t);await new g(this.nostrService.getNDK(),n).publish(),this.isLiked=!1,this.likeCount>0&&this.likeCount--,this.likeActionStatus.set(i.Ready),await this.updateLikeCount()}catch(t){console.error("[NostrLike] Failed to unlike:",t),this.isLiked=!0,this.likeCount++;const n=t instanceof Error?t.message:"Failed to unlike";this.likeActionStatus.set(i.Error,n)}finally{this.render()}}async handleCountClick(){if(!(this.likeCount===0||!this.cachedLikeDetails))try{const{openLikersDialog:t}=await y(async()=>{const{openLikersDialog:n}=await import("../assets/dialog-likers-BjiCHFan.js");return{openLikersDialog:n}},__vite__mapDeps([0,1,2,3,4,5,6]));await t({likeDetails:this.cachedLikeDetails.likeDetails,theme:this.theme==="dark"?"dark":"light"})}catch(t){console.error("[NostrLike] Error opening likers dialog:",t)}}async handleHelpClick(){try{await $(this.theme==="dark"?"dark":"light")}catch(t){console.error("[NostrLike] Error showing help dialog:",t)}}attachDelegatedListeners(){this.delegateEvent("click",".nostr-like-button",t=>{var n,o;(n=t.preventDefault)==null||n.call(t),(o=t.stopPropagation)==null||o.call(t),this.handleLikeClick()}),this.delegateEvent("click",".like-count",t=>{var n,o;(n=t.preventDefault)==null||n.call(t),(o=t.stopPropagation)==null||o.call(t),this.handleCountClick()}),this.delegateEvent("click",".help-icon",t=>{var n,o;(n=t.preventDefault)==null||n.call(t),(o=t.stopPropagation)==null||o.call(t),this.handleHelpClick()})}renderContent(){const t=this.likeActionStatus.get()===i.Loading||this.conn.get()===i.Loading,n=this.likeListStatus.get()===i.Loading,o=this.computeOverall()===i.Error,s=this.errorMessage,a=this.getAttribute("text")||"Like",l={isLoading:t,isError:o,errorMessage:s,buttonText:a,isLiked:this.isLiked,likeCount:this.likeCount,hasLikes:this.likeCount>0,isCountLoading:n,theme:this.theme};this.shadowRoot.innerHTML=`
293
- ${z()}
294
- ${S(l)}
295
- `}}customElements.define("nostr-like",F);
292
+ `,e.showModal()};new TextDecoder("utf-8");new TextEncoder;function k(o){try{o.indexOf("://")===-1&&(o="wss://"+o);let e=new URL(o);return e.protocol==="http:"?e.protocol="ws:":e.protocol==="https:"&&(e.protocol="wss:"),e.pathname=e.pathname.replace(/\/+/g,"/"),e.pathname.endsWith("/")&&(e.pathname=e.pathname.slice(0,-1)),(e.port==="80"&&e.protocol==="ws:"||e.port==="443"&&e.protocol==="wss:")&&(e.port=""),e.searchParams.sort(),e.hash="",e.toString()}catch{throw new Error(`Invalid URL: ${o}`)}}async function T(o,e){const t=k(o),r=new f;try{const n=await r.querySync(e,{kinds:[17],"#k":["web"],"#i":[t],limit:1e3}),s=[];let a=0,l=0;for(const c of n)s.push({authorPubkey:c.pubkey,date:new Date(c.created_at*1e3),content:c.content}),c.content==="-"?l++:a++;return s.sort((c,h)=>h.date.getTime()-c.date.getTime()),{totalCount:a-l,likeDetails:s,likedCount:a,dislikedCount:l}}catch(n){throw n instanceof Error?n:new Error(String(n))}finally{r.close(e)}}function m(o,e){return{kind:17,content:e,tags:[["k","web"],["i",o]],created_at:Math.floor(Date.now()/1e3)}}function P(o){return m(o,"+")}function _(o){return m(o,"-")}async function F(o,e,t){const r=new f,n=o;try{const s=await r.querySync(t,{kinds:[17],authors:[e],"#k":["web"],"#i":[n],limit:1});if(s.length===0)return!1;const a=s[0];return a.content==="+"||a.content===""}catch(s){return console.error("Nostr-Components: Like button: Error checking user like status",s),!1}finally{r.close(t)}}async function q(){try{return await p(),await E()}catch(o){return console.error("Nostr-Components: Like button: Error getting user pubkey",o),null}}async function b(o){try{return await p(),await A(o)}catch(e){throw console.error("Nostr-Components: Like button: Error signing event",e),e}}class B extends x{constructor(){super();d(this,"likeActionStatus",this.channel("likeAction"));d(this,"likeListStatus",this.channel("likeList"));d(this,"currentUrl","");d(this,"isLiked",!1);d(this,"likeCount",0);d(this,"cachedLikeDetails",null);d(this,"loadSeq",0);this.likeListStatus.set(i.Loading)}connectedCallback(){var t;(t=super.connectedCallback)==null||t.call(this),this.attachDelegatedListeners(),this.render()}static get observedAttributes(){return[...super.observedAttributes,"url","text"]}attributeChangedCallback(t,r,n){r!==n&&(super.attributeChangedCallback(t,r,n),(t==="url"||t==="text")&&(this.likeActionStatus.set(i.Ready),this.likeListStatus.set(i.Loading),this.isLiked=!1,this.errorMessage="",this.updateLikeCount(),this.render()))}validateInputs(){if(!super.validateInputs())return this.likeActionStatus.set(i.Idle),this.likeListStatus.set(i.Idle),!1;const t=this.getAttribute("url"),r=this.getAttribute("text"),n=this.tagName.toLowerCase();let s=null;return t&&(S(t)||(s="Invalid URL format")),r&&r.length>32&&(s="Max text length: 32 characters"),s?(this.likeActionStatus.set(i.Error,s),this.likeListStatus.set(i.Error,s),console.error(`Nostr-Components: ${n}: ${s}`),!1):!0}onStatusChange(t){this.render()}onNostrRelaysConnected(){this.updateLikeCount(),this.render()}ensureCurrentUrl(){this.currentUrl||(this.currentUrl=k(this.getAttribute("url")||window.location.href))}async updateLikeCount(){const t=++this.loadSeq;try{await this.ensureNostrConnected(),this.currentUrl=k(this.getAttribute("url")||window.location.href),this.likeListStatus.set(i.Loading),this.render();const r=await T(this.currentUrl,this.getRelays());if(t!==this.loadSeq)return;this.likeCount=r.totalCount,this.cachedLikeDetails=r,this.likeListStatus.set(i.Ready)}catch(r){console.error("[NostrLike] Failed to fetch like count:",r),this.likeListStatus.set(i.Error,"Failed to load likes")}finally{this.render()}}async handleLikeClick(){if(this.ensureCurrentUrl(),!this.currentUrl){this.likeActionStatus.set(i.Error,"Invalid URL"),this.render();return}this.likeActionStatus.set(i.Loading),this.render();try{await p();const t=await q();if(t&&(this.isLiked=await F(this.currentUrl,t,this.getRelays())),this.isLiked){if(!window.confirm("You have already liked this. Do you want to unlike it?")){this.likeActionStatus.set(i.Ready),this.render();return}await this.handleUnlike()}else await this.handleLike()}catch(t){console.error("[NostrLike] Failed to check user like status:",t);const r=t instanceof Error?t.message:"Failed to check user like status";this.likeActionStatus.set(i.Error,r),this.render()}}async handleLike(){if(this.ensureCurrentUrl(),!this.currentUrl){this.likeActionStatus.set(i.Error,"Invalid URL"),this.render();return}this.likeActionStatus.set(i.Loading),this.render();try{const t=P(this.currentUrl),r=await b(t);await new g(this.nostrService.getNDK(),r).publish(),this.isLiked=!0,this.likeCount++,this.likeActionStatus.set(i.Ready),await this.updateLikeCount()}catch(t){console.error("[NostrLike] Failed to like:",t),this.isLiked=!1,this.likeCount--;const r=t instanceof Error?t.message:"Failed to like";this.likeActionStatus.set(i.Error,r)}finally{this.render()}}async handleUnlike(){if(this.ensureCurrentUrl(),!this.currentUrl){this.likeActionStatus.set(i.Error,"Invalid URL"),this.render();return}this.likeActionStatus.set(i.Loading),this.render();try{const t=_(this.currentUrl),r=await b(t);await new g(this.nostrService.getNDK(),r).publish(),this.isLiked=!1,this.likeCount>0&&this.likeCount--,this.likeActionStatus.set(i.Ready),await this.updateLikeCount()}catch(t){console.error("[NostrLike] Failed to unlike:",t),this.isLiked=!0,this.likeCount++;const r=t instanceof Error?t.message:"Failed to unlike";this.likeActionStatus.set(i.Error,r)}finally{this.render()}}async handleCountClick(){if(!(this.likeCount===0||!this.cachedLikeDetails))try{const{openLikersDialog:t}=await L(async()=>{const{openLikersDialog:r}=await import("../assets/dialog-likers-D3c7WIMp.js");return{openLikersDialog:r}},__vite__mapDeps([0,1,2,3,4,5,6,7]));await t({likeDetails:this.cachedLikeDetails.likeDetails,theme:this.theme==="dark"?"dark":"light"})}catch(t){console.error("[NostrLike] Error opening likers dialog:",t)}}async handleHelpClick(){try{await H(this.theme==="dark"?"dark":"light")}catch(t){console.error("[NostrLike] Error showing help dialog:",t)}}attachDelegatedListeners(){this.delegateEvent("click",".nostr-like-button",t=>{var r,n;(r=t.preventDefault)==null||r.call(t),(n=t.stopPropagation)==null||n.call(t),this.handleLikeClick()}),this.delegateEvent("click",".like-count",t=>{var r,n;(r=t.preventDefault)==null||r.call(t),(n=t.stopPropagation)==null||n.call(t),this.handleCountClick()}),this.delegateEvent("click",".help-icon",t=>{var r,n;(r=t.preventDefault)==null||r.call(t),(n=t.stopPropagation)==null||n.call(t),this.handleHelpClick()})}renderContent(){const t=this.likeActionStatus.get()===i.Loading||this.conn.get()===i.Loading,r=this.likeListStatus.get()===i.Loading,n=this.computeOverall()===i.Error,s=this.errorMessage,a=this.getAttribute("text")||"Like",l={isLoading:t,isError:n,errorMessage:s,buttonText:a,isLiked:this.isLiked,likeCount:this.likeCount,hasLikes:this.likeCount>0,isCountLoading:r,theme:this.theme};this.shadowRoot.innerHTML=`
293
+ ${R()}
294
+ ${U(l)}
295
+ `}}customElements.define("nostr-like",B);
296
296
  //# sourceMappingURL=nostr-like.es.js.map