@hazem3500/komo 0.0.0-stage → 0.9.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 (126) hide show
  1. package/LICENSE +21 -0
  2. package/NODE.md +80 -0
  3. package/NOTICE.md +45 -0
  4. package/README.md +411 -2
  5. package/cli/agent.mjs +615 -0
  6. package/cli/config.mjs +34 -0
  7. package/cli/index.mjs +405 -0
  8. package/cli/project.mjs +136 -0
  9. package/cli/workflow.mjs +42 -0
  10. package/dist/MorphingMenu.d.ts +30 -0
  11. package/dist/PointerIcon.d.ts +2 -0
  12. package/dist/SmileIcon.d.ts +2 -0
  13. package/dist/THIRD_PARTY_NOTICES.txt +387 -0
  14. package/dist/accent-picker-F5UI2NP7.js +1 -0
  15. package/dist/accent-picker.d.ts +4 -0
  16. package/dist/accent.d.ts +2 -0
  17. package/dist/account-usage.d.ts +2 -0
  18. package/dist/action-menu.d.ts +10 -0
  19. package/dist/agent-prompt.d.ts +6 -0
  20. package/dist/agent-prompt.js +1 -0
  21. package/dist/anchors.d.ts +48 -0
  22. package/dist/api.d.ts +39 -0
  23. package/dist/approved-sites.d.ts +9 -0
  24. package/dist/card-motion.d.ts +8 -0
  25. package/dist/chunk-7YUXYVQA.js +1 -0
  26. package/dist/chunk-I7AUKTXE.js +1 -0
  27. package/dist/chunk-JQVBZ2BB.js +1 -0
  28. package/dist/chunk-Q7WSWLMV.js +1 -0
  29. package/dist/chunk-Y2GRLW4Q.js +1 -0
  30. package/dist/chunk-YZP3KX4Y.js +1 -0
  31. package/dist/chunk-Z2ABBESO.js +1 -0
  32. package/dist/config.d.ts +11 -0
  33. package/dist/connect-project.d.ts +14 -0
  34. package/dist/connection-issue.d.ts +7 -0
  35. package/dist/design-comment-QPTW66JO.js +1 -0
  36. package/dist/design-comment.d.ts +42 -0
  37. package/dist/design-export-BRBI7S3V.js +1 -0
  38. package/dist/design-export.d.ts +8 -0
  39. package/dist/design-mode-styles.d.ts +1 -0
  40. package/dist/design-mode.d.ts +19 -0
  41. package/dist/design-mode.js +1 -0
  42. package/dist/design-panel-BPVXFERR.js +1 -0
  43. package/dist/design-panel-styles.d.ts +1 -0
  44. package/dist/design-panel.d.ts +33 -0
  45. package/dist/design-tokens.d.ts +76 -0
  46. package/dist/dom.d.ts +20 -0
  47. package/dist/drawer-expand-motion.d.ts +46 -0
  48. package/dist/drawer-presence.d.ts +4 -0
  49. package/dist/edge-sidebar.d.ts +39 -0
  50. package/dist/emoji-history.d.ts +8 -0
  51. package/dist/emoji.d.ts +1 -0
  52. package/dist/floating-drag.d.ts +9 -0
  53. package/dist/icon-markup.d.ts +4 -0
  54. package/dist/index.d.ts +8 -0
  55. package/dist/index.js +1 -0
  56. package/dist/inline-text-editor-F7B6FQQ3.js +1 -0
  57. package/dist/inline-text-editor.d.ts +70 -0
  58. package/dist/lazy-accent-picker.d.ts +4 -0
  59. package/dist/lazy-toolbar.d.ts +19 -0
  60. package/dist/message-links.d.ts +2 -0
  61. package/dist/morphing-menu-styles.d.ts +1 -0
  62. package/dist/node.mjs +2607 -0
  63. package/dist/onboarding-NO3RQWR7.js +1 -0
  64. package/dist/onboarding.d.ts +6 -0
  65. package/dist/optimistic.d.ts +26 -0
  66. package/dist/page.d.ts +2 -0
  67. package/dist/picker-WQN53YJ5.js +1 -0
  68. package/dist/pin-direction.d.ts +12 -0
  69. package/dist/pin-stacks.d.ts +3 -0
  70. package/dist/polling.d.ts +10 -0
  71. package/dist/postgres/001_initial.sql +128 -0
  72. package/dist/postgres/002_thread_tags.sql +1 -0
  73. package/dist/postgres/003_project_webhooks.sql +4 -0
  74. package/dist/project-management.d.ts +2 -0
  75. package/dist/react-inspector.d.ts +43 -0
  76. package/dist/react-props-panel-XSMDR2CY.js +1 -0
  77. package/dist/react-props-panel.d.ts +39 -0
  78. package/dist/react.d.ts +38 -0
  79. package/dist/react.js +1 -0
  80. package/dist/reaction-picker.d.ts +1 -0
  81. package/dist/review-layout.d.ts +23 -0
  82. package/dist/setup-browser.d.ts +1 -0
  83. package/dist/setup.d.ts +4 -0
  84. package/dist/setup.js +1 -0
  85. package/dist/shortcuts.d.ts +15 -0
  86. package/dist/static-svg.d.ts +3 -0
  87. package/dist/styles.d.ts +1 -0
  88. package/dist/tag-editor-VDPZ6CO3.js +1 -0
  89. package/dist/tag-editor.d.ts +12 -0
  90. package/dist/toolbar-runtime-2SIUE6SQ.js +1 -0
  91. package/dist/toolbar-runtime.d.ts +5 -0
  92. package/dist/types.d.ts +163 -0
  93. package/package.json +114 -4
  94. package/server/digest.ts +8 -0
  95. package/server/import-project.ts +164 -0
  96. package/server/index.ts +1656 -0
  97. package/server/migrations/0001_comments.sql +54 -0
  98. package/server/migrations/0002_identity.sql +2 -0
  99. package/server/migrations/0003_accent_color.sql +1 -0
  100. package/server/migrations/0004_workspaces.sql +46 -0
  101. package/server/migrations/0005_domains.sql +6 -0
  102. package/server/migrations/0006_member_budget.sql +16 -0
  103. package/server/migrations/0007_revisions.sql +17 -0
  104. package/server/migrations/0008_starter_comments.sql +1 -0
  105. package/server/migrations/0009_retention.sql +19 -0
  106. package/server/migrations/0010_reviewer_history.sql +1 -0
  107. package/server/migrations/0011_project_management.sql +52 -0
  108. package/server/migrations/0012_setup_sites.sql +3 -0
  109. package/server/migrations/0013_project_sites.sql +8 -0
  110. package/server/migrations/0014_project_site_removals.sql +3 -0
  111. package/server/migrations/0015_query_efficiency.sql +6 -0
  112. package/server/migrations/0016_thread_tags.sql +1 -0
  113. package/server/migrations/0017_project_webhooks.sql +4 -0
  114. package/server/node-webhooks.ts +126 -0
  115. package/server/project-management.ts +387 -0
  116. package/server/project-sites.ts +117 -0
  117. package/server/secrets.d.ts +24 -0
  118. package/server/setup-client.txt +2932 -0
  119. package/server/setup-page.ts +14 -0
  120. package/server/tsconfig.json +12 -0
  121. package/server/validation.ts +220 -0
  122. package/server/webhooks.ts +206 -0
  123. package/server/workspaces.ts +168 -0
  124. package/src/emoji.ts +7 -0
  125. package/src/page.ts +4 -0
  126. package/src/types.ts +166 -0
@@ -0,0 +1 @@
1
+ import{b as e,c as t}from"./chunk-Q7WSWLMV.js";import{h as a,i as n,j as s}from"./chunk-YZP3KX4Y.js";import"./chunk-I7AUKTXE.js";async function r(e,t=""){let r;try{let a=await e.request(`project/sites${t}`);r=[...a.fixed,...a.sites]}catch{return null}let i=a("div","approved-sites-editor");i.dataset.open="false";let o=a("span","approved-sites-count"),l=s("Sites with comments",()=>{let e="true"!==i.dataset.open;i.dataset.open=String(e),l.setAttribute("aria-expanded",String(e)),c.inert=!e},"approved-sites-toggle");l.replaceChildren(a("span","","Sites with comments"),o,n("chevron")),l.setAttribute("aria-expanded","false");let c=a("div","approved-sites-reveal");c.id=`approved-sites-${crypto.randomUUID()}`,c.inert=!0,l.setAttribute("aria-controls",c.id);let p=a("div","approved-sites-body"),d=a("ul","approved-site-list"),u=a("p","account-usage-status");u.setAttribute("role","status");let v=a("div","approved-site-add"),m=a("input");m.type="text",m.inputMode="url",m.spellcheck=!1,m.placeholder="your-site.com",m.setAttribute("aria-label","Site to approve"),m.setAttribute("autocomplete","off");let b=a("div","account-usage-note account-sites-note");b.append(n("info"),a("span","","Only these sites can show comments. Add * to cover preview links."));let h=async a=>{let n=r;r=a,f(),u.textContent="";try{let n=await e.request(`project/sites${t}`,"PATCH",{sites:a});return r=[...n.fixed,...n.sites],f(),!0}catch(e){return r=n,f(),u.textContent=e instanceof Error?e.message:"Try again.",!1}},y=s("Add",async()=>{let e;try{e=function(e){let t=e.trim().replace(/\/$/,"").toLowerCase();if(/^http:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/.test(t))return t;let a=/^https:\/\/([^/?#@\s]+)$/.exec(t.includes("://")?t:`https://${t}`),[n="",...s]=(a?.[1]??"").split(".");if(!a||s.length<1||s.join(".").includes("*")||n.split("*").length>2||n.includes("*")&&s.length<2)throw new Error("That doesn’t look like a site. Try your-site.com or *-preview.your-site.com.");return`https://${a[1]}`}(m.value)}catch(e){return void(u.textContent=e.message)}if(r.includes(e))return m.value="",void(u.textContent="Already on the list.");let t=m.value;m.value="",y.disabled=!0,await h([...r,e])||(m.value||=t),y.disabled=!1,m.focus()},"secondary");m.addEventListener("keydown",e=>{"Enter"===e.key&&(e.preventDefault(),y.click())}),v.append(m,y);let g=e=>{let t=a("li","approved-site"),n=a("span","",e.replace(/^https:\/\//,""));return n.title=e,t.append(n,s(`Remove ${e}`,()=>{h(r.filter(t=>t!==e))},"icon","close")),t},f=()=>{o.textContent=String(r.length),d.replaceChildren(...r.map(g))};return f(),p.append(d,v,b,u),c.append(p),i.append(l,c),i}var i=new WeakMap;function o(e,n="usage",o=!0,l=!1){let c=a("section","account-usage");c.setAttribute("aria-label","Account usage");let p=(e="")=>{let t=a("span",`usage-skeleton ${e}`);return t.setAttribute("aria-hidden","true"),t},d=e.user?.id,u=e.token,v=()=>e.user?.id===d&&e.token===u,m=i.get(e);m||i.set(e,m=new Map);let b=JSON.stringify([d,u,n]),h=m.get(b);h||m.set(b,h={});let y=e=>{c.setAttribute("aria-busy","false"),c.replaceChildren(a("h3","",`${e.hosted?"Starter plan":"Self-hosted"}${l?" · Local":""}`));let{used:t,limit:n}=e.comments,s=a("div","account-usage-label account-comments"),r=a("span","account-comment-count");if(r.append(a("span","",null===n?`${t.toLocaleString()} / Unlimited`:`${t.toLocaleString()} / ${n.toLocaleString()}`)),s.title="Includes replies and deleted comments.",null!==n){let e=a("span","account-usage-ring");e.setAttribute("role","meter"),e.setAttribute("aria-label","Project comments"),e.setAttribute("aria-valuemin","0"),e.setAttribute("aria-valuemax",String(n)),e.setAttribute("aria-valuenow",String(Math.min(t,n))),e.setAttribute("aria-valuetext",`${t} of ${n} comments used, including replies and deleted comments`),e.style.setProperty("--usage",(n>0?100*Math.min(t/n,1):0)+"%"),e.dataset.full=String(t>=n),r.append(e)}if(s.append(a("span","","Project comments"),r),c.append(s),e.projects){let{used:t,limit:n}=e.projects;if(null===n){let e=a("div","account-usage-label");return e.append(a("span","","Projects"),a("span","",`${t.toLocaleString()} / Unlimited`)),void c.append(e)}let s=a("div","account-projects"),r=a("div","account-usage-label"),i=a("span","account-project-count");i.append(a("strong","",String(t)),a("span","",`of ${n}`)),r.append(a("span","","Projects"),i);let o=a("div","account-project-slots");o.setAttribute("role","meter"),o.setAttribute("aria-label","Projects"),o.setAttribute("aria-valuemin","0"),o.setAttribute("aria-valuemax",String(n)),o.setAttribute("aria-valuenow",String(t)),o.setAttribute("aria-valuetext",`${t} of ${n} projects used`);for(let e=0;e<n;e++){let n=a("span");n.dataset.used=String(e<t),o.append(n)}s.append(r,o),c.append(s)}},g=async()=>{if(!v())return c.replaceChildren(),void c.setAttribute("aria-busy","false");h.value?y(h.value):(()=>{let e=a("div","usage-skeleton-heading");e.append(p("usage-skeleton-title"));let t=a("div","account-usage-label account-comments"),n=a("span","account-comment-count");n.append(p("usage-skeleton-count"),p("usage-skeleton-ring")),t.append(p("usage-skeleton-label"),n);let s=a("div","account-projects"),r=a("div","account-usage-label");r.append(p("usage-skeleton-label"),p("usage-skeleton-count"));let i=a("div","account-project-slots");i.setAttribute("aria-hidden","true"),i.append(a("span"),a("span"),a("span")),s.append(r,i);let o=a("span","sr-only","Loading account usage");o.setAttribute("role","status"),c.setAttribute("aria-busy","true"),c.replaceChildren(e,t,s,o)})(),c.setAttribute("aria-busy","true");try{let t,a=h.pending??=e.request(n);try{t=await a}finally{h.pending===a&&(h.pending=void 0)}if(!v())return delete h.value,c.replaceChildren(),void c.setAttribute("aria-busy","false");if(h.value=t,!c.isConnected)return;y(t),o&&e.user?.verified&&(async()=>{let t=n.includes("?")?n.slice(n.indexOf("?")):"",a=await r(e,t);a&&h.value&&c.isConnected&&v()&&c.append(a)})().catch(()=>{})}catch(e){if(e instanceof t&&(401===e.status||403===e.status)&&delete h.value,!v())return delete h.value,c.replaceChildren(),void c.setAttribute("aria-busy","false");if(!c.isConnected)return;h.value?y(h.value):c.replaceChildren(),c.setAttribute("aria-busy","false");let n=a("span","account-usage-status",h.value?"Couldn’t refresh usage":"Usage unavailable");n.setAttribute("role","status"),c.append(n,s("Retry",()=>{g()},"secondary"))}};return g(),c}function l(t,r,i){let o=a("section","account-sites project-management");o.dataset.open="false";let l=s("Project settings",()=>{let e="true"!==o.dataset.open;o.dataset.open=String(e),l.setAttribute("aria-expanded",String(e)),c.inert=!e,c.setAttribute("aria-hidden",String(!e))},"account-sites-summary");l.append(n("chevron")),l.setAttribute("aria-expanded","false");let c=a("div","account-sites-reveal");c.id=`project-settings-${crypto.randomUUID()}`,l.setAttribute("aria-controls",c.id),c.inert=!0,c.setAttribute("aria-hidden","true");let p=a("div","account-sites-clip");c.append(p);let d=a("div","account-sites-content"),u=a("p","account-usage-status");u.setAttribute("role","status");let v=r?`?workspace=${encodeURIComponent(r)}`:"",m=(e,a="GET",n)=>t.request(`project${e}${v}`,a,n);o.hidden=!0,p.append(d,u),o.append(l,c);let b,h=async e=>{let t=Array.from(o.querySelectorAll("button"));t.forEach(e=>e.disabled=!0),u.textContent="";try{await e()}catch(e){u.textContent=e instanceof Error?e.message:"Try again."}finally{t.forEach(e=>e.disabled=!1)}},y=async()=>{let e,n={format:"komo-export",version:1,project:b.project,exportedAt:(new Date).toISOString(),tables:{}};for(let a of["threads","comments","reactions","users"]){n.tables[a]=[];let s=0;for(;null!==s;){let i=await t.request(`project/export?table=${a}&offset=${s}${void 0===e?"":`&revision=${e}`}${r?`&workspace=${encodeURIComponent(r)}`:""}`);e=i.revision,n.tables[a].push(...i.rows),s=i.next}}let s=URL.createObjectURL(new Blob([JSON.stringify(n,null,2)],{type:"application/json"})),i=a("a");i.href=s,i.download=`${b.project}-comments.json`,i.click(),setTimeout(()=>URL.revokeObjectURL(s),1e3),u.textContent="Export downloaded."},g=async()=>{b=await m(""),o.hidden=!1,d.replaceChildren();let t=a("div","account-name-label");t.append(a("span","","Access"));let n,r=[["public","Anyone with the link"],["private","Invited Google accounts"]],l=()=>{let a=e("Project access",r,b.access,e=>{h(async()=>{let t=b.access;b.access=e,l();try{await m("","PATCH",{access:e}),u.textContent="Access updated."}catch(e){throw b.access=t,l(),e}})});n?n.replaceWith(a):t.append(a),n=a};l(),d.append(t);let c=await m("/webhook"),p=a("details","project-webhook");p.append(a("summary","","Comment webhooks"));let v=a("p","project-help","Send signed events to your HTTPS endpoint. Signing secrets are encrypted and shown only when entered.");p.append(v),c.deliveryAvailable||(v.textContent="Secure webhook delivery is not available on this server yet.");let f=a("label","account-name-label","HTTPS endpoint"),w=a("input");w.type="url",w.autocomplete="off",w.placeholder="https://example.com/komo-webhook",w.value=c.url,f.append(w),p.append(f);let A=a("label","account-name-label",c.secretConfigured?"Replace signing secret":"Signing secret"),k=a("input");k.type="password",k.autocomplete="new-password",k.minLength=32,k.maxLength=256,A.append(k),p.append(A);let C=new Map;for(let e of c.supportedEvents){let t=a("label","account-name-label",e),n=a("input");n.type="checkbox",n.checked=c.events.includes(e),C.set(e,n),t.prepend(n),p.append(t)}let x=a("label","account-name-label","Enable delivery"),j=a("input");j.type="checkbox",j.checked=c.enabled,j.disabled=!c.deliveryAvailable&&!c.enabled,x.prepend(j),p.append(x),p.append(s("Save webhook settings",()=>{h(async()=>{await m("/webhook","PATCH",{url:w.value,secret:k.value,events:[...C].filter(([,e])=>e.checked).map(([e])=>e),enabled:j.checked}),k.value="",u.textContent="Webhook settings saved."})},"secondary")),d.append(p);let S=a("label","account-name-label","Invite someone"),$=a("input");$.type="email",$.placeholder="name@example.com",$.autocomplete="email",S.append($);let E=a("input");E.readOnly=!0,E.hidden=!0,E.setAttribute("aria-label","Invitation link");let T=s("Create invitation",()=>{h(async()=>{if(!$.checkValidity()||!$.value)throw Error("Enter an email address.");let e=await m("/invites","POST",{email:$.value});E.value=e.url,E.hidden=!1,P.hidden=!1,u.textContent="Share this link. It expires in 7 days."})},"secondary"),P=s("Copy invitation",()=>{h(async()=>{await navigator.clipboard.writeText(E.value),u.textContent="Invitation copied."})},"secondary");P.hidden=!0,d.append(S,T,E,P);for(let e of b.members){let t=a("div","project-member");t.append(a("span","",e.name),s(`Remove ${e.name}`,()=>{h(async()=>{await m("/members","DELETE",{user:e.id}),await g(),u.textContent="Member removed."})},"secondary")),d.append(t)}for(let e of b.invites){let t=a("div","project-member");t.append(a("span","",e.email),s("Revoke invitation",()=>{h(async()=>{await m("/invites","DELETE",{email:e.email}),await g(),u.textContent="Invitation revoked."})},"secondary")),d.append(t)}d.append(s("Download comments",()=>{h(y)},"secondary"));let L=a("a","project-help","Move to self-hosting");L.href="https://komo.offbr.co/hosting/#migration",L.target="_blank",L.rel="noopener noreferrer",d.append(L);let U=a("details","project-danger");U.append(a("summary","","Free space or delete project")),U.append(a("p","",`Export first. These actions permanently remove comments. Type ${b.project} to confirm.`));let R=a("input");R.placeholder=b.project,R.setAttribute("aria-label","Confirm project key"),U.append(R),U.append(s("Delete resolved threads",()=>{h(async()=>{await m("/clear-resolved","POST",{confirm:R.value}),i?.(!1),u.textContent="Resolved threads deleted.",R.value=""})},"secondary destructive")),b.hosted&&U.append(s("Delete project",()=>{h(async()=>{await m("","DELETE",{confirm:R.value}),i?.(!0),d.replaceChildren(),u.textContent="Project deleted. Its project slot is available again."})},"secondary destructive")),d.append(U)};return g().catch(e=>{403!==e?.status&&(o.hidden=!1,u.textContent="Project settings unavailable.",d.append(s("Retry",()=>{h(g)},"secondary")))}),o}function c(e,t){let r=a("section","onboarding-panel"),i=a("p","account-usage-status");i.setAttribute("role","status");let l=e=>{i.textContent=e instanceof Error?e.message:"Try again."},c=async()=>{let p=encodeURIComponent(t.workspace),d=a("div","account-sites"),u=a("div","account-sites-summary");u.append(a("span","","Approved sites"),n("chevron")),d.append(u),d.setAttribute("aria-busy","true"),i.textContent="",r.replaceChildren(o(e,`usage?workspace=${p}`,!1),d,i);try{let o=await e.request(`workspace?workspace=${p}`);if(!r.isConnected)return;i.textContent="";let c=a("section","account-sites");c.dataset.open="false";let u=s("",()=>{let e="true"!==c.dataset.open;c.dataset.open=String(e),u.setAttribute("aria-expanded",String(e)),v.inert=!e,v.setAttribute("aria-hidden",String(!e))},"account-sites-summary");u.setAttribute("aria-expanded","false");let v=a("div","account-sites-reveal");v.id=`approved-sites-${crypto.randomUUID()}`,v.inert=!0,v.setAttribute("aria-hidden","true"),u.setAttribute("aria-controls",v.id);let m=a("div","account-sites-clip"),b=a("span","account-sites-count");u.append(a("span","","Approved sites"),b,n("chevron"));let h=a("div","account-sites-content"),y=a("div","approved-sites"),g=()=>{b.textContent=String(o.sites.length),y.replaceChildren(...o.sites.map(e=>a("span","",new URL(e).host)))};g();let f=a("label","account-name-label","Website"),w=a("input");w.type="url",w.placeholder="https://your-site.com",w.setAttribute("autocomplete","url"),w.value=t.site||o.suggested.find(e=>!o.sites.includes(e))||"",f.append(w);let A=s("Approve site",async()=>{let a;try{let e=new URL(w.value.trim());if("https:"!==e.protocol||e.username||e.password)throw Error("Enter an HTTPS website address.");a=e.origin}catch(e){return void l(e)}let n=[...o.sites],s=w.value;o.sites.includes(a)||o.sites.push(a),g(),w.value="",A.disabled=!0;try{await e.request("workspace/sites","POST",{project:t.workspace,origin:a}),t.site=void 0,i.textContent="Site approved"}catch(e){o.sites=n,g(),w.value||(w.value=s),l(e)}finally{A.disabled=!1}},"secondary");w.addEventListener("keydown",e=>{"Enter"===e.key&&(e.preventDefault(),A.click())});let k=a("div","account-usage-note account-sites-note");k.append(n("info"),a("span","","Approved sites can show and share comments. Localhost comments are visible by default.")),h.append(y,f,A,k),m.append(h),v.append(m),c.append(u,v),d.replaceWith(c)}catch(e){l(e),r.append(s("Retry",()=>{c()},"secondary"))}};if(t.invite){let n=s("Accept invitation",async()=>{n.disabled=!0;try{await e.request("project/join","POST",{invite:t.invite}),t.invite=void 0,r.replaceChildren(a("p","","You’re in. Return to the website to leave comments."))}catch(e){l(e),n.disabled=!1}},"primary");r.append(n,i)}else if(t.workspace)c();else if(t.code||t.claimKey){let a=s(t.code?"Create project":"Enable comments",async()=>{a.disabled=!0;let n=a.textContent;a.textContent=t.code?"Creating project…":"Enabling comments…";try{if(t.code){let a=await e.request("setup/complete","POST",{code:t.code});t.workspace=a.project,t.code=void 0,history.replaceState(null,"",`/setup?workspace=${encodeURIComponent(a.project)}`),await c(),i.textContent="Project ready. Return to your terminal."}else await e.request("owner/claim","POST",{key:t.claimKey}),t.claimKey=void 0,r.replaceChildren(o(e),i),i.textContent="Comments are ready."}catch(e){l(e),a.disabled=!1,a.textContent=n}},"primary");r.append(a,i)}else r.append(o(e));return r}export{o as accountUsage,c as onboardingPanel,l as projectManagement};
@@ -0,0 +1,6 @@
1
+ import type { CommentsApi } from "./api.js";
2
+ import type { OnboardingOptions } from "./types.js";
3
+ import { accountUsage } from "./account-usage.js";
4
+ export { accountUsage };
5
+ export { projectManagement } from "./project-management.js";
6
+ export declare function onboardingPanel(api: CommentsApi, options: OnboardingOptions): HTMLElement;
@@ -0,0 +1,26 @@
1
+ type ResolveId = (id: string) => string;
2
+ type Change<T> = (state: T, resolve: ResolveId) => T;
3
+ type Job<T> = {
4
+ change: Change<T>;
5
+ save: (resolve: ResolveId) => Promise<Record<string, string> | void>;
6
+ resolve: () => void;
7
+ reject: (error: unknown) => void;
8
+ };
9
+ /** Rebase outstanding edits on confirmed state; failed writes remove only their own edit. */
10
+ export declare class OptimisticQueue<T> {
11
+ private confirmed;
12
+ private changed;
13
+ private normalize;
14
+ private jobs;
15
+ private aliases;
16
+ revision: number;
17
+ constructor(confirmed: T, changed: (state: T) => void, normalize?: (state: T, resolve: ResolveId) => T);
18
+ get busy(): boolean;
19
+ id: (id: string) => string;
20
+ get value(): T;
21
+ replace(state: T, revision?: number): boolean;
22
+ reset(state: T): void;
23
+ submit(change: Change<T>, save: Job<T>["save"]): Promise<void>;
24
+ private drain;
25
+ }
26
+ export {};
package/dist/page.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ /** Static hosts may add a trailing slash to the same page. */
2
+ export declare function canonicalPage(pathname: string): string;
@@ -0,0 +1 @@
1
+ import"./chunk-I7AUKTXE.js";function e(e){if("string"!=typeof e||!e)throw new Error("expected a non-empty string, got: "+e)}function t(e){if("number"!=typeof e)throw new Error("expected a number, got: "+e)}var n="emoji",o="keyvalue",i="favorites",r="tokens",a="count",s="group-order",c="eTag",l="url",d="skinTone",u="readonly",m="readwrite",f="skinUnicodes";function h(e){return function(e,t){let n=new Set,o=[];for(let i of e){let e=t(i);n.has(e)||(n.add(e),o.push(i))}return o}(e,e=>e.unicode)}var p={},g={},b={};function v(e,t,n){n.onerror=()=>t(n.error),n.onblocked=()=>t(new Error("IDB blocked")),n.onsuccess=()=>e(n.result)}async function y(e){let t=await new Promise((t,c)=>{let l=indexedDB.open(e,1);p[e]=l,l.onupgradeneeded=e=>{e.oldVersion<1&&function(e){function t(t,n,o){let i=n?e.createObjectStore(t,{keyPath:n}):e.createObjectStore(t);if(o)for(let[e,[t,n]]of Object.entries(o))i.createIndex(e,t,{multiEntry:n});return i}t(o),t(n,"unicode",{[r]:["tokens",!0],[s]:[["group","order"]],[f]:["skinUnicodes",!0]}),t(i,void 0,{[a]:[""]})}(l.result)},v(t,c,l)});return t.onclose=()=>w(e),t}function k(e,t,n,o){return new Promise((i,r)=>{let a,s=e.transaction(t,n,{durability:"relaxed"}),c="string"==typeof t?s.objectStore(t):t.map(e=>s.objectStore(e));o(c,s,e=>{a=e}),s.oncomplete=()=>i(a),s.onerror=()=>r(s.error)})}function w(e){let t=p[e],n=t&&t.result;if(n){n.close();let t=b[e];if(t)for(let e of t)e()}delete p[e],delete g[e],delete b[e]}var j=new Set([":D","XD",":'D","O:)",":X",":P",";P","XP",":L",":Z",":j","8D","XO","8)",":B",":O",":S",":'o","Dx","X(","D:",":C",">0)",":3","</3","<3","\\M/",":E","8#"]);function E(e){return e.split(/[\s_]+/).map(e=>!e.match(/\w/)||j.has(e)?e.toLowerCase():e.replace(/[)(:,]/g,"").replace(/’/g,"'").toLowerCase()).filter(Boolean)}function S(e){return e.filter(Boolean).map(e=>e.toLowerCase()).filter(e=>e.length>=2)}function T(e,t,n,o){e[t](n).onsuccess=e=>o&&o(e.target.result)}function x(e,t,n){T(e,"get",t,n)}function C(e,t,n){T(e,"getAll",t,n)}function $(e){e.commit&&e.commit()}function _(e,t){let n=function(e,t){let n=e[0];for(let o=1;o<e.length;o++){let i=e[o];t(n)>t(i)&&(n=i)}return n}(e,e=>e.length),o=[];for(let i of n)e.some(e=>-1===e.findIndex(e=>t(e)===t(i)))||o.push(i);return o}async function L(e,t,i,r){{let a=function(e){return e.map(({annotation:e,emoticon:t,group:n,order:o,shortcodes:i,skins:r,tags:a,emoji:s,version:c})=>{let l={annotation:e,group:n,order:o,tags:a,tokens:[...new Set(S([...(i||[]).map(E).flat(),...(a||[]).map(E).flat(),...E(e),t]))].sort(),unicode:s,version:c};if(t&&(l.emoticon=t),i&&(l.shortcodes=i),r){l.skinTones=[],l.skinUnicodes=[],l.skinVersions=[];for(let{tone:e,emoji:t,version:n}of r)l.skinTones.push(e),l.skinUnicodes.push(t),l.skinVersions.push(n)}return l})}(t);await k(e,[n,o],m,([e,t],n)=>{let o,s,d=0;function u(){2===++d&&function(){if(o!==r||s!==i){e.clear();for(let t of a)e.put(t);t.put(r,c),t.put(i,l),$(n)}}()}x(t,c,e=>{o=e,u()}),x(t,l,e=>{s=e,u()})})}}async function I(e,t){let o=S(E(t));return o.length?k(e,n,u,(e,t,n)=>{let i=[],a=()=>{let e=_(i,e=>e.unicode);n(e.sort((e,t)=>e.order<t.order?-1:1))};for(let t=0;t<o.length;t++){let n=o[t],s=t===o.length-1?IDBKeyRange.bound(n,n+"￿",!1,!0):IDBKeyRange.only(n);C(e.index(r),s,e=>{i.push(e),i.length===o.length&&a()})}}):[]}async function z(e,t){let o=await I(e,t);return o.length?o.filter(e=>(e.shortcodes||[]).map(e=>e.toLowerCase()).includes(t.toLowerCase()))[0]||null:await async function(e,t){return k(e,n,u,(e,n,o)=>{let i,r=()=>{e.getAll(i&&IDBKeyRange.lowerBound(i,!0),50).onsuccess=e=>{let n=e.target.result;for(let e of n)if(i=e.unicode,t(e))return o(e);if(n.length<50)return o();r()}};r()})}(e,e=>(e.shortcodes||[]).includes(t.toLowerCase()))||null}function P(e,t,n){return k(e,t,u,(e,t,o)=>x(e,n,o))}var M=["name","url"];function A(e){!function(e){let t=e&&Array.isArray(e),n=t&&e.length&&(!e[0]||M.some(t=>!(t in e[0])));if(!t||n)throw new Error("Custom emojis are in the wrong format")}(e);let t=(e,t)=>e.name.toLowerCase()<t.name.toLowerCase()?-1:1,n=e.sort(t),o=function(e,t){let n=new Map;for(let o of e){let e=t(o);for(let t of e){let e=n;for(let n=0;n<t.length;n++){let o=t.charAt(n),i=e.get(o);i||(i=new Map,e.set(o,i)),e=i}let i=e.get("");i||(i=[],e.set("",i)),i.push(o)}}return(e,t)=>{let o=n;for(let t=0;t<e.length;t++){let n=e.charAt(t),i=o.get(n);if(!i)return[];o=i}if(t)return o.get("")||[];let i=[],r=[o];for(;r.length;){let e=[...r.shift().entries()].sort((e,t)=>e[0]<t[0]?-1:1);for(let[t,n]of e)""===t?i.push(...n):r.push(n)}return i}}(e,e=>{let t=new Set;if(e.shortcodes)for(let n of e.shortcodes)for(let e of E(n))t.add(e);return t}),i=e=>o(e,!0),r=e=>o(e,!1),a=new Map,s=new Map;for(let t of e){s.set(t.name.toLowerCase(),t);for(let e of t.shortcodes||[])a.set(e.toLowerCase(),t)}return{all:n,search:e=>{let n=E(e);return _(n.map((e,t)=>(t<n.length-1?i:r)(e)),e=>e.name).sort(t)},byShortcode:e=>a.get(e.toLowerCase()),byName:e=>s.get(e.toLowerCase())}}var O=typeof wrappedJSObject<"u";function B(e){if(!e)return e;if(O&&(e=structuredClone(e)),delete e.tokens,e.skinTones){let t=e.skinTones.length;e.skins=Array(t);for(let n=0;n<t;n++)e.skins[n]={tone:e.skinTones[n],unicode:e.skinUnicodes[n],version:e.skinVersions[n]};delete e.skinTones,delete e.skinUnicodes,delete e.skinVersions}return e}function N(e){e||console.warn("emoji-picker-element is more efficient if the dataSource server exposes an ETag header.")}var D=["annotation","emoji","group","order","version"];function F(e,t){if(2!==Math.floor(e.status/100))throw new Error("Failed to fetch: "+t+": "+e.status)}async function U(e){let t=await fetch(e);F(t,e);let n=t.headers.get("etag");N(n);let o=await t.json();return function(e){if(!e||!Array.isArray(e)||!e[0]||"object"!=typeof e[0]||D.some(t=>!(t in e[0])))throw new Error("Emoji data is in the wrong format")}(o),[n,o]}async function W(e){let t=function(e){for(var t=e.length,n=new ArrayBuffer(t),o=new Uint8Array(n),i=-1;++i<t;)o[i]=e.charCodeAt(i);return n}(JSON.stringify(e)),n=function(e){for(var t="",n=new Uint8Array(e),o=n.byteLength,i=-1;++i<o;)t+=String.fromCharCode(n[i]);return t}(await crypto.subtle.digest("SHA-1",t));return btoa(n)}async function V(e,t){let n,i=await async function(e){let t=await fetch(e,{method:"HEAD"});F(t,e);let n=t.headers.get("etag");return N(n),n}(t);if(!i){let e=await U(t);i=e[0],n=e[1],i||(i=await W(n))}await async function(e,t,n){let[i,r]=await Promise.all([c,l].map(t=>P(e,o,t)));return i===n&&r===t}(e,t,i)||(n||(n=(await U(t))[1]),await L(e,n,t,i))}var G=class{constructor({dataSource:e="https://cdn.jsdelivr.net/npm/emoji-picker-element-data@^1/en/emojibase/data.json",locale:t="en",customEmoji:n=[]}={}){this.dataSource=e,this.locale=t,this._dbName=`emoji-picker-element-${this.locale}`,this._db=void 0,this._lazyUpdate=void 0,this._custom=A(n),this._clear=this._clear.bind(this),this._ready=this._init()}async _init(){let e=this._db=await(t=this._dbName,g[t]||(g[t]=y(t)),g[t]);var t;!function(e,t){let n=b[e];n||(n=b[e]=[]),n.push(t)}(this._dbName,this._clear);let n=this.dataSource;await async function(e){return!await P(e,o,l)}(e)?await async function(e,t){let[n,o]=await U(t);n||(n=await W(o)),await L(e,o,t,n)}(e,n):this._lazyUpdate=async function(e,t){try{await V(e,t)}catch(e){if("InvalidStateError"!==e.name)throw e}}(e,n)}async ready(){let e=async()=>(this._ready||(this._ready=this._init()),this._ready);await e(),this._db||await e()}async getEmojiByGroup(e){return t(e),await this.ready(),h(await async function(e,t){return k(e,n,u,(e,n,o)=>{let i=IDBKeyRange.bound([t,0],[t+1,0],!1,!0);C(e.index(s),i,o)})}(this._db,e)).map(B)}async getEmojiBySearchQuery(t){return e(t),await this.ready(),[...this._custom.search(t),...h(await I(this._db,t)).map(B)]}async getEmojiByShortcode(t){return e(t),await this.ready(),this._custom.byShortcode(t)||B(await z(this._db,t))}async getEmojiByUnicodeOrName(t){return e(t),await this.ready(),this._custom.byName(t)||B(await async function(e,t){return k(e,n,u,(e,n,o)=>x(e,t,n=>{if(n)return o(n);x(e.index(f),t,e=>o(e||null))}))}(this._db,t))}async getPreferredSkinTone(){return await this.ready(),await P(this._db,o,d)||0}async setPreferredSkinTone(e){return t(e),await this.ready(),function(e,t,n,o){return k(e,t,m,(e,t)=>{e.put(o,n),$(t)})}(this._db,o,d,e)}async incrementFavoriteEmojiCount(t){return e(t),await this.ready(),function(e,t){return k(e,i,m,(e,n)=>x(e,t,o=>{e.put((o||0)+1,t),$(n)}))}(this._db,t)}async getTopFavoriteEmoji(e){return t(e),await this.ready(),(await function(e,t,o){return 0===o?[]:k(e,[i,n],u,([e,n],i,r)=>{let s=[];e.index(a).openCursor(void 0,"prev").onsuccess=e=>{let i=e.target.result;if(!i)return r(s);function a(e){if(s.push(e),s.length===o)return r(s);i.continue()}let c=i.primaryKey,l=t.byName(c);if(l)return a(l);x(n,c,e=>{if(e)return a(e);i.continue()})}})}(this._db,this._custom,e)).map(B)}set customEmoji(e){this._custom=A(e)}get customEmoji(){return this._custom.all}async _shutdown(){await this.ready();try{await this._lazyUpdate}catch{}}_clear(){this._db=this._ready=this._lazyUpdate=void 0}async close(){await this._shutdown(),await w(this._dbName)}async delete(){var e;await this._shutdown(),await(e=this._dbName,new Promise((t,n)=>{w(e),v(t,n,indexedDB.deleteDatabase(e))}))}},R=[[-1,"✨","custom"],[0,"😀","smileys-emotion"],[1,"👋","people-body"],[3,"🐱","animals-nature"],[4,"🍎","food-drink"],[5,"🏠️","travel-places"],[6,"⚽","activities"],[7,"📝","objects"],[8,"⛔️","symbols"],[9,"🏁","flags"]].map(([e,t,n])=>({id:e,emoji:t,name:n})),K=R.slice(1),H="function"==typeof requestIdleCallback?requestIdleCallback:setTimeout;function q(e){return e.unicode.includes("‍")}var X={"🫪":17,"🫩":16,"🫨":15.1,"🫠":14,"🥲":13.1,"🥻":12.1,"🥰":11,"🤩":5,"👱‍♀️":4,"🤣":3,"👁️‍🗨️":2,"😀":1,"😐️":.7,"😃":.6},J=["😊","😒","❤️","👍️","😍","😂","😭","☺️","😔","😩","😏","💕","🙌","😘"],Q='"Twemoji Mozilla","Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji","EmojiOne Color","Android Emoji",sans-serif',Y=(e,t)=>e<t?-1:e>t?1:0,Z=(e,t)=>{let n=document.createElement("canvas");n.width=n.height=1;let o=n.getContext("2d",{willReadFrequently:!0});return o.textBaseline="top",o.font=`100px ${Q}`,o.fillStyle=t,o.scale(.01,.01),o.fillText(e,0,0),o.getImageData(0,0,1,1).data};function ee(e){let t=Z(e,"#000"),n=Z(e,"#fff");return t&&n&&((e,t)=>{let n=[...e].join(",");return n===[...t].join(",")&&!n.startsWith("0,0,0,")})(t,n)}var te,ne=()=>(te||(te=new Promise(e=>H(()=>e(function(){let e=Object.entries(X);try{for(let[t,n]of e)if(ee(t))return n}catch{}return e[0][1]}())))),te),oe=new Map;function ie(e){e.preventDefault(),e.stopPropagation()}function re(e,t,n){return(t+=e?-1:1)<0?t=n.length-1:t>=n.length&&(t=0),t}function ae(e,t){let n=new Set,o=[];for(let i of e){let e=t(i);n.has(e)||(n.add(e),o.push(i))}return o}var se=requestAnimationFrame,ce="function"==typeof ResizeObserver;function le(e){{let t=document.createRange();return t.selectNode(e.firstChild),t.getBoundingClientRect().width}}var de,ue;function me(e,t,n){let o=le(t);if(!o){if(!ue){ue=n.cloneNode(!0);let e=getComputedStyle(n);for(let t of["font-family","line-height","width","height","font-size","display","align-items","justify-content"])ue.style.setProperty(t,e.getPropertyValue(t),"important")}try{return document.body.appendChild(ue),ue.firstChild.nodeValue=e,le(ue)}finally{ue.remove()}}return o}function fe(e,t,n){let o=e.get(t);return o||(o=n(),e.set(t,o)),o}function he(e){return""+e}function pe(e){let t=document.createElement("template");return t.innerHTML=e,t}var ge=new WeakMap,be=new WeakMap,ve=Symbol("un-keyed"),ye="replaceChildren"in Element.prototype;function ke(e,t){let{targetNode:n}=t,{targetParentNode:o}=t,i=!1;o?i=function(e,t){let n=e.firstChild,o=0;for(;n;){if(t[o]!==n)return!0;n=n.nextSibling,o++}return o!==t.length}(o,e):(i=!0,t.targetNode=void 0,t.targetParentNode=o=n.parentNode),i&&function(e,t){ye?e.replaceChildren(...t):(e.innerHTML="",e.append(...t))}(o,e)}function we(e,t,n){for(let o=0;o<e.length;o++){let i=e[o],r={binding:i,targetNode:i.attributeName?t:t.firstChild,targetParentNode:void 0,currentExpression:void 0};n.push(r)}}function je(e){let{template:t,elementsToBindings:n}=fe(ge,e,()=>function(e){let t="",n=!1,o=!1,i=-1,r=new Map,a=[],s=0;for(let c=0,l=e.length;c<l;c++){let d=e[c];if(t+=d.slice(s),c===l-1)break;for(let e=0;e<d.length;e++)switch(d.charAt(e)){case"<":"/"===d.charAt(e+1)?a.pop():(n=!0,a.push(++i));break;case">":n=!1,o=!1;break;case"=":o=!0}let u,m,f,h=fe(r,a[a.length-1],()=>[]);if(o){let n=/(\S+)="?([^"=]*)$/.exec(d);u=n[1],m=n[2];let o=/^([^">]*)("?)/.exec(e[c+1]);f=o[1],t=t.slice(0,-1*n[0].length),s=o[0].length}else s=0;let p={attributeName:u,attributeValuePre:m,attributeValuePost:f,expressionIndex:c};h.push(p),!n&&!o&&(t+=" ")}return{template:pe(t),elementsToBindings:r}}(e)),o=t.cloneNode(!0).content.firstElementChild,i=function(e,t){let n,o=[];if(1===t.size&&(n=t.get(0)))we(n,e,o);else{let n=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT),i=e,r=-1;do{let e=t.get(++r);e&&we(e,i,o)}while(i=n.nextNode())}return o}(o,n);return function(e){return function(e,t){for(let n of t){let{targetNode:t,currentExpression:o,binding:{expressionIndex:i,attributeName:r,attributeValuePre:a,attributeValuePost:s}}=n,c=e[i];if(o!==c)if(n.currentExpression=c,r)if(null===c)t.removeAttribute(r);else{let e=a+he(c)+s;t.setAttribute(r,e)}else{let e;Array.isArray(c)?ke(c,n):c instanceof Element?(e=c,t.replaceWith(e)):t.nodeValue=he(c),e&&(n.targetNode=e)}}}(e,i),o}}function Ee(e,t,n,o,i,r,a,s,c){let{labelWithSkin:l,titleForEmoji:d,unicodeWithSkin:u}=n,{html:m,map:f}=function(e){let t=fe(be,e,()=>new Map),n=ve;return{map:function(e,t,o){return e.map((e,i)=>{let r=n;n=o(e);try{return t(e,i)}finally{n=r}})},html:function(e,...o){let i=fe(t,e,()=>new Map);return fe(i,n,()=>je(e))(o)}}}(t);function h(e,n,o){return f(e,(e,i)=>m`<button role="${n?"option":"menuitem"}" aria-selected="${n?i===t.activeSearchItem:null}" aria-label="${l(e,t.currentSkinTone)}" title="${d(e)}" class="${"emoji"+(n&&i===t.activeSearchItem?" active":"")+(e.unicode?"":" custom-emoji")}" id="${`${o}-${e.id}`}" style="${e.unicode?null:`--custom-emoji-background: url(${JSON.stringify(e.url)})`}">${e.unicode?u(e,t.currentSkinTone):""}</button>`,e=>`${o}-${e.id}`)}let p=m`<section data-ref="rootElement" class="picker" aria-label="${t.i18n.regionLabel}" style="${t.pickerStyle||""}"><div class="pad-top"></div><div class="search-row"><div class="search-wrapper"><input id="search" class="search" type="search" role="combobox" enterkeyhint="search" placeholder="${t.i18n.searchLabel}" autocapitalize="none" autocomplete="off" spellcheck="true" aria-expanded="${!(!t.searchMode||!t.currentEmojis.length)}" aria-controls="search-results" aria-describedby="search-description" aria-autocomplete="list" aria-activedescendant="${t.activeSearchItemId?`emo-${t.activeSearchItemId}`:null}" data-ref="searchElement" data-on-input="onSearchInput" data-on-keydown="onSearchKeydown"><label class="sr-only" for="search">${t.i18n.searchLabel}</label> <span id="search-description" class="sr-only">${t.i18n.searchDescription}</span></div><div class="skintone-button-wrapper ${t.skinTonePickerExpandedAfterAnimation?"expanded":""}"><button id="skintone-button" class="emoji ${t.skinTonePickerExpanded?"hide-focus":""}" aria-label="${t.skinToneButtonLabel}" title="${t.skinToneButtonLabel}" aria-describedby="skintone-description" aria-haspopup="listbox" aria-expanded="${t.skinTonePickerExpanded}" aria-controls="skintone-list" data-on-click="onClickSkinToneButton">${t.skinToneButtonText||""}</button></div><span id="skintone-description" class="sr-only">${t.i18n.skinToneDescription}</span><div data-ref="skinToneDropdown" id="skintone-list" class="skintone-list hide-focus ${t.skinTonePickerExpanded?"":"hidden no-animate"}" style="transform:translateY(${t.skinTonePickerExpanded?0:"calc(-1 * var(--num-skintones) * var(--total-emoji-size))"})" role="listbox" aria-label="${t.i18n.skinTonesLabel}" aria-activedescendant="skintone-${t.activeSkinTone}" aria-hidden="${!t.skinTonePickerExpanded}" tabIndex="-1" data-on-focusout="onSkinToneOptionsFocusOut" data-on-click="onSkinToneOptionsClick" data-on-keydown="onSkinToneOptionsKeydown" data-on-keyup="onSkinToneOptionsKeyup">${f(t.skinTones,(e,n)=>m`<div id="skintone-${n}" class="emoji ${n===t.activeSkinTone?"active":""}" aria-selected="${n===t.activeSkinTone}" role="option" title="${t.i18n.skinTones[n]}" aria-label="${t.i18n.skinTones[n]}">${e}</div>`,e=>e)}</div></div><div class="nav" role="tablist" style="grid-template-columns:repeat(${t.groups.length},1fr)" aria-label="${t.i18n.categoriesLabel}" data-on-keydown="onNavKeydown" data-on-click="onNavClick">${f(t.groups,e=>m`<button role="tab" class="nav-button" aria-controls="tab-${e.id}" aria-label="${t.i18n.categories[e.name]}" aria-selected="${!t.searchMode&&t.currentGroup.id===e.id}" title="${t.i18n.categories[e.name]}" data-group-id="${e.id}"><div class="nav-emoji emoji">${e.emoji}</div></button>`,e=>e.id)}</div><div class="indicator-wrapper"><div class="indicator" style="transform:translateX(${(t.isRtl?-1:1)*t.currentGroupIndex*100}%)"></div></div><div class="message ${t.message?"":"gone"}" role="alert" aria-live="polite">${t.message||""}</div><div data-ref="tabpanelElement" class="tabpanel ${!t.databaseLoaded||t.message?"gone":""}" role="${t.searchMode?"region":"tabpanel"}" aria-label="${t.searchMode?t.i18n.searchResultsLabel:t.i18n.categories[t.currentGroup.name]}" id="${t.searchMode?null:`tab-${t.currentGroup.id}`}" tabIndex="0" data-on-click="onEmojiClick"><div data-action="calculateEmojiGridStyle">${f(t.currentEmojisWithCategories,(e,n)=>m`<div><div id="menu-label-${n}" class="category ${1===t.currentEmojisWithCategories.length&&""===t.currentEmojisWithCategories[0].category?"gone":""}" aria-hidden="true">${t.searchMode?t.i18n.searchResultsLabel:e.category?e.category:t.currentEmojisWithCategories.length>1?t.i18n.categories.custom:t.i18n.categories[t.currentGroup.name]}</div><div class="emoji-menu ${0===n||t.searchMode||-1!==t.currentGroup.id?"":"visibility-auto"}" style="${`--num-rows: ${Math.ceil(e.emojis.length/t.numColumns)}`}" data-action="updateOnIntersection" role="${t.searchMode?"listbox":"menu"}" aria-labelledby="menu-label-${n}" id="${t.searchMode?"search-results":null}">${h(e.emojis,t.searchMode,"emo")}</div></div>`,e=>e.category)}</div></div><div class="favorites onscreen emoji-menu ${t.message?"gone":""}" role="menu" aria-label="${t.i18n.favoritesLabel}" data-on-click="onEmojiClick">${h(t.currentFavorites,!1,"fav")}</div><button data-ref="baselineEmoji" aria-hidden="true" tabindex="-1" class="abs-pos hidden emoji baseline-emoji">😀</button></section>`,g=(t,n)=>{for(let o of e.querySelectorAll(`[${t}]`))n(o,o.getAttribute(t))};if(c){e.appendChild(p);for(let e of["click","focusout","input","keydown","keyup"])g(`data-on-${e}`,(t,n)=>{t.addEventListener(e,o[n])});g("data-ref",(e,t)=>{r[t]=e}),a.addEventListener("abort",()=>{e.removeChild(p)})}g("data-action",(e,t)=>{let n=s.get(t);n||s.set(t,n=new WeakSet),n.has(e)||(n.add(e),i[t](e))})}var Se="function"==typeof queueMicrotask?queueMicrotask:e=>Promise.resolve().then(e);function Te(e,t,n){if(e.length!==t.length)return!1;for(let o=0;o<e.length;o++)if(!n(e[o],t[o]))return!1;return!0}var xe=new WeakMap;var Ce=[],{assign:$e}=Object;function _e(e,t){let n={},o=new AbortController,i=o.signal,{state:r,createEffect:a}=function(e){let t,n,o=!1,i=new Map,r=new Set,a=()=>{if(o)return;let e=[...r];r.clear();try{for(let t of e)t()}finally{n=!1,r.size&&(n=!0,Se(a))}},s=new Proxy({},{get(e,n){if(t){let e=i.get(n);e||(e=new Set,i.set(n,e)),e.add(t)}return e[n]},set(e,t,o){if(e[t]!==o){e[t]=o;let s=i.get(t);if(s){for(let e of s)r.add(e);n||(n=!0,Se(a))}}return!0}});return e.addEventListener("abort",()=>{o=!0}),{state:s,createEffect:e=>{let n=()=>{let o=t;t=n;try{return e()}finally{t=o}};return n()}}}(i),s=new Map;$e(r,{skinToneEmoji:void 0,i18n:void 0,database:void 0,customEmoji:void 0,customCategorySorting:void 0,emojiVersion:void 0}),$e(r,t),$e(r,{initialLoad:!0,currentEmojis:[],currentEmojisWithCategories:[],rawSearchText:"",searchText:"",searchMode:!1,activeSearchItem:-1,message:void 0,skinTonePickerExpanded:!1,skinTonePickerExpandedAfterAnimation:!1,currentSkinTone:0,activeSkinTone:0,skinToneButtonText:void 0,pickerStyle:void 0,skinToneButtonLabel:"",skinTones:[],currentFavorites:[],defaultFavoriteEmojis:void 0,numColumns:8,isRtl:!1,currentGroupIndex:0,groups:K,databaseLoaded:!1,activeSearchItemId:void 0}),a(()=>{r.currentGroup!==r.groups[r.currentGroupIndex]&&(r.currentGroup=r.groups[r.currentGroupIndex])});let c=t=>{e.getElementById(t).focus()},l=t=>e.getElementById(`emo-${t.id}`),d=(e,t)=>{n.rootElement.dispatchEvent(new CustomEvent(e,{detail:t,bubbles:!0,composed:!0}))},u=(e,t)=>e.id===t.id,m=(e,t)=>{let{category:n,emojis:o}=e,{category:i,emojis:r}=t;return n===i&&Te(o,r,u)},f=e=>{Te(r.currentEmojis,e,u)||(r.currentEmojis=e)},h=e=>{r.searchMode!==e&&(r.searchMode=e)},p=(e,t)=>t&&e.skins&&e.skins[t]||e.unicode,g={labelWithSkin:(e,t)=>function(e){return ae(e,e=>e)}([e.name||p(e,t),e.annotation,...e.shortcodes||Ce].filter(Boolean)).join(", "),titleForEmoji:e=>e.annotation||(e.shortcodes||Ce).join(", "),unicodeWithSkin:p},b={onClickSkinToneButton:function(e){r.skinTonePickerExpanded=!r.skinTonePickerExpanded,r.activeSkinTone=r.currentSkinTone,r.skinTonePickerExpanded&&(ie(e),se(()=>c("skintone-list")))},onEmojiClick:function(e){let{target:t}=e;if(!t.classList.contains("emoji"))return;ie(e),T(t.id.substring(4))},onNavClick:function(e){let{target:t}=e,o=t.closest(".nav-button");if(!o)return;let i=parseInt(o.dataset.groupId,10);n.searchElement.value="",r.rawSearchText="",r.searchText="",r.activeSearchItem=-1,r.currentGroupIndex=r.groups.findIndex(e=>e.id===i)},onNavKeydown:function(e){let{target:t,key:n}=e,o=t=>{t&&(ie(e),t.focus())};switch(n){case"ArrowLeft":return o(t.previousElementSibling);case"ArrowRight":return o(t.nextElementSibling);case"Home":return o(t.parentElement.firstElementChild);case"End":return o(t.parentElement.lastElementChild)}},onSearchKeydown:function(e){if(!r.searchMode||!r.currentEmojis.length)return;let t=t=>{ie(e),r.activeSearchItem=re(t,r.activeSearchItem,r.currentEmojis)};switch(e.key){case"ArrowDown":return t(!1);case"ArrowUp":return t(!0);case"Enter":if(-1!==r.activeSearchItem)return ie(e),T(r.currentEmojis[r.activeSearchItem].id);r.activeSearchItem=0}},onSkinToneOptionsClick:function(e){let{target:{id:t}}=e,n=t&&t.match(/^skintone-(\d)/);if(!n)return;ie(e),x(parseInt(n[1],10))},onSkinToneOptionsFocusOut:async function(e){let{relatedTarget:t}=e;(!t||"skintone-list"!==t.id)&&(r.skinTonePickerExpanded=!1)},onSkinToneOptionsKeydown:function(e){if(!r.skinTonePickerExpanded)return;let t=async t=>{ie(e),r.activeSkinTone=t};switch(e.key){case"ArrowUp":return t(re(!0,r.activeSkinTone,r.skinTones));case"ArrowDown":return t(re(!1,r.activeSkinTone,r.skinTones));case"Home":return t(0);case"End":return t(r.skinTones.length-1);case"Enter":return ie(e),x(r.activeSkinTone);case"Escape":return ie(e),r.skinTonePickerExpanded=!1,c("skintone-button")}},onSkinToneOptionsKeyup:function(e){if(r.skinTonePickerExpanded&&" "===e.key)return ie(e),x(r.activeSkinTone)},onSearchInput:function(e){r.rawSearchText=e.target.value}},v={calculateEmojiGridStyle:function(e){!function(e,t,n){let o;ce?(o=new ResizeObserver(n),o.observe(e)):se(n),t.addEventListener("abort",()=>{o&&o.disconnect()})}(e,i,()=>{{let e=getComputedStyle(n.rootElement),t=parseInt(e.getPropertyValue("--num-columns"),10),o="rtl"===e.getPropertyValue("direction");r.numColumns=t,r.isRtl=o}})},updateOnIntersection:function(e){!function(e,t,n){{let o=e.closest(".tabpanel"),i=xe.get(o);i||(i=new IntersectionObserver(n,{root:o,rootMargin:"50% 0px 50% 0px",threshold:0}),xe.set(o,i),t.addEventListener("abort",()=>{i.disconnect()})),i.observe(e)}}(e,i,e=>{for(let{target:t,isIntersecting:n}of e)t.classList.toggle("onscreen",n)})}},y=!0;function k(){let{customEmoji:e,database:t}=r,n=e||Ce;t.customEmoji!==n&&(t.customEmoji=n)}a(()=>{Ee(e,r,g,b,v,n,i,s,y),y=!1}),r.emojiVersion||ne().then(e=>{e||(r.message=r.i18n.emojiUnsupportedMessage)}),a(()=>{r.database&&async function(){let e=!1,t=setTimeout(()=>{e=!0,r.message=r.i18n.loadingMessage},1e3);try{await r.database.ready(),r.databaseLoaded=!0}catch(e){console.error(e),r.message=r.i18n.networkErrorMessage}finally{clearTimeout(t),e&&(e=!1,r.message="")}}()}),a(()=>{r.pickerStyle=`\n --num-groups: ${r.groups.length}; \n --indicator-opacity: ${r.searchMode?0:1}; \n --num-skintones: 6;`}),a(()=>{r.customEmoji&&r.database&&k()}),a(()=>{r.customEmoji&&r.customEmoji.length?r.groups!==R&&(r.groups=R):r.groups!==K&&(r.currentGroupIndex&&r.currentGroupIndex--,r.groups=K)}),a(()=>{!async function(){r.databaseLoaded&&(r.currentSkinTone=await r.database.getPreferredSkinTone())}()}),a(()=>{r.skinTones=Array(6).fill().map((e,t)=>function(e,t){if(0===t)return e;let n=e.indexOf("‍");return-1!==n?e.substring(0,n)+String.fromCodePoint(127995+t-1)+e.substring(n):(e.endsWith("️")&&(e=e.substring(0,e.length-1)),e+"\ud83c"+String.fromCodePoint(57339+t-1))}(r.skinToneEmoji,t))}),a(()=>{r.skinToneButtonText=r.skinTones[r.currentSkinTone]}),a(()=>{r.skinToneButtonLabel=r.i18n.skinToneLabel.replace("{skinTone}",r.i18n.skinTones[r.currentSkinTone])}),a(()=>{r.databaseLoaded&&async function(){let{database:e}=r,t=(await Promise.all(J.map(t=>e.getEmojiByUnicodeOrName(t)))).filter(Boolean);r.defaultFavoriteEmojis=t}()}),a(()=>{r.databaseLoaded&&r.defaultFavoriteEmojis&&async function(){k();let{database:e,defaultFavoriteEmojis:t,numColumns:n}=r,o=await e.getTopFavoriteEmoji(n),i=await S(ae([...o,...t],e=>e.unicode||e.name).slice(0,n));r.currentFavorites=i}()}),a(()=>{!async function(){let{searchText:e,currentGroup:t,databaseLoaded:n,customEmoji:o}=r;if(n)if(e.length>=2){let t=await async function(e){return S(await E(await r.database.getEmojiBySearchQuery(e)))}(e);r.searchText===e&&(f(t),h(!0))}else{let{id:e}=t;if(-1!==e||o&&o.length){let t=await async function(e){let t=-1===e?r.customEmoji:await r.database.getEmojiByGroup(e);return S(await E(t))}(e);r.currentGroup.id===e&&(f(t),h(!1))}}else r.currentEmojis=[],r.searchMode=!1}()});let w=()=>{se(()=>function(e){e&&(e.scrollTop=0)}(n.tabpanelElement))};function j(e){return!e.unicode||!q(e)||oe.get(e.unicode)}async function E(e){let t=r.emojiVersion||await ne();return e.filter(({version:e})=>!e||e<=t)}async function S(e){return function(e,t){let n=e=>{let n={};for(let o of e)"number"==typeof o.tone&&o.version<=t&&(n[o.tone]=o.unicode);return n};return e.map(({unicode:e,skins:t,shortcodes:o,url:i,name:r,category:a,annotation:s})=>({unicode:e,name:r,shortcodes:o,url:i,category:a,annotation:s,id:e||r,skins:t&&n(t)}))}(e,r.emojiVersion||await ne())}async function T(e){let t=async function(e){let t=await r.database.getEmojiByUnicodeOrName(e),n=[...r.currentEmojis,...r.currentFavorites].find(t=>t.id===e),o=n.unicode&&p(n,r.currentSkinTone);return await r.database.incrementFavoriteEmojiCount(e),{emoji:t,skinTone:r.currentSkinTone,...o&&{unicode:o},...n.name&&{name:n.name}}}(e);d("emoji-click-sync",t),d("emoji-click",await t)}function x(e){r.currentSkinTone=e,r.skinTonePickerExpanded=!1,c("skintone-button"),d("skin-tone-change",{skinTone:e}),r.database.setPreferredSkinTone(e)}return a(()=>{let{currentEmojis:e,emojiVersion:t}=r,o=e.filter(e=>e.unicode).filter(e=>q(e)&&!oe.has(e.unicode));if(!t&&o.length)f(e),se(()=>function(e){!function(e,t,n){let o=!0;for(let i of e){let e=n(i);if(!e)continue;typeof de>"u"&&(de=me("😀",t,t));let r=me(i.unicode,e,t)/1.8<de;oe.set(i.unicode,r),r||(o=!1)}return o}(e,n.baselineEmoji,l)?r.currentEmojis=[...r.currentEmojis]:w()}(o));else{let n=t?e:e.filter(j);f(n),w()}}),a(()=>{}),a(()=>{(e=>{Te(r.currentEmojisWithCategories,e,m)||(r.currentEmojisWithCategories=e)})(function(){let{searchMode:e,currentEmojis:t}=r;if(e)return[{category:"",emojis:t}];let n=new Map;for(let e of t){let t=e.category||"",o=n.get(t);o||(o=[],n.set(t,o)),o.push(e)}return[...n.entries()].map(([e,t])=>({category:e,emojis:t})).sort((e,t)=>r.customCategorySorting(e.category,t.category))}())}),a(()=>{r.activeSearchItemId=-1!==r.activeSearchItem&&r.currentEmojis[r.activeSearchItem].id}),a(()=>{let{rawSearchText:e}=r;H(()=>{r.searchText=(e||"").trim(),r.activeSearchItem=-1})}),a(()=>{r.skinTonePickerExpanded?n.skinToneDropdown.addEventListener("transitionend",()=>{r.skinTonePickerExpandedAfterAnimation=!0},{once:!0}):r.skinTonePickerExpandedAfterAnimation=!1}),{$set(e){$e(r,e)},$destroy(){o.abort()}}}var Le={categoriesLabel:"Categories",emojiUnsupportedMessage:"Your browser does not support color emoji.",favoritesLabel:"Favorites",loadingMessage:"Loading…",networkErrorMessage:"Could not load emoji.",regionLabel:"Emoji picker",searchDescription:"When search results are available, press up or down to select and enter to choose.",searchLabel:"Search",searchResultsLabel:"Search results",skinToneDescription:"When expanded, press up or down to select and enter to choose.",skinToneLabel:"Choose a skin tone (currently {skinTone})",skinTonesLabel:"Skin tones",skinTones:["Default","Light","Medium-Light","Medium","Medium-Dark","Dark"],categories:{custom:"Custom","smileys-emotion":"Smileys and emoticons","people-body":"People and body","animals-nature":"Animals and nature","food-drink":"Food and drink","travel-places":"Travel and places",activities:"Activities",objects:"Objects",symbols:"Symbols",flags:"Flags"}},Ie=["customEmoji","customCategorySorting","database","dataSource","i18n","locale","skinToneEmoji","emojiVersion"],ze=`:host{--emoji-font-family:${Q}}`,Pe=class extends HTMLElement{constructor(e){super(),this.attachShadow({mode:"open"});let t=document.createElement("style");t.textContent=':host{--emoji-size:1.375rem;--emoji-padding:0.5rem;--category-emoji-size:var(--emoji-size);--category-emoji-padding:var(--emoji-padding);--indicator-height:3px;--input-border-radius:0.5rem;--input-border-size:1px;--input-font-size:1rem;--input-line-height:1.5;--input-padding:0.25rem;--num-columns:8;--outline-size:2px;--border-size:1px;--border-radius:0;--skintone-border-radius:1rem;--category-font-size:1rem;display:flex;width:min-content;height:400px}:host,:host(.light){color-scheme:light;--background:#fff;--border-color:#e0e0e0;--indicator-color:#385ac1;--input-border-color:#999;--input-font-color:#111;--input-placeholder-color:#999;--outline-color:#999;--category-font-color:#111;--button-active-background:#e6e6e6;--button-hover-background:#d9d9d9}:host(.dark){color-scheme:dark;--background:#222;--border-color:#444;--indicator-color:#5373ec;--input-border-color:#ccc;--input-font-color:#efefef;--input-placeholder-color:#ccc;--outline-color:#fff;--category-font-color:#efefef;--button-active-background:#555555;--button-hover-background:#484848}@media (prefers-color-scheme:dark){:host{color-scheme:dark;--background:#222;--border-color:#444;--indicator-color:#5373ec;--input-border-color:#ccc;--input-font-color:#efefef;--input-placeholder-color:#ccc;--outline-color:#fff;--category-font-color:#efefef;--button-active-background:#555555;--button-hover-background:#484848}}:host([hidden]){display:none}button{margin:0;padding:0;border:0;background:0 0;box-shadow:none;-webkit-tap-highlight-color:transparent}button::-moz-focus-inner{border:0}input{padding:0;margin:0;line-height:1.15;font-family:inherit}input[type=search]{-webkit-appearance:none}:focus{outline:var(--outline-color) solid var(--outline-size);outline-offset:calc(-1*var(--outline-size))}:host([data-js-focus-visible]) :focus:not([data-focus-visible-added]){outline:0}:focus:not(:focus-visible){outline:0}.hide-focus{outline:0}*{box-sizing:border-box}.picker{contain:content;display:flex;flex-direction:column;background:var(--background);border:var(--border-size) solid var(--border-color);border-radius:var(--border-radius);width:100%;height:100%;overflow:hidden;--total-emoji-size:calc(var(--emoji-size) + (2 * var(--emoji-padding)));--total-category-emoji-size:calc(var(--category-emoji-size) + (2 * var(--category-emoji-padding)))}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.hidden{opacity:0;pointer-events:none}.abs-pos{position:absolute;left:0;top:0}.gone{display:none!important}.skintone-button-wrapper,.skintone-list{background:var(--background);z-index:3}.skintone-button-wrapper.expanded{z-index:1}.skintone-list{position:absolute;inset-inline-end:0;top:0;z-index:2;overflow:visible;border-bottom:var(--border-size) solid var(--border-color);border-radius:0 0 var(--skintone-border-radius) var(--skintone-border-radius);will-change:transform;transition:transform .2s ease-in-out;transform-origin:center 0}@media (prefers-reduced-motion:reduce){.skintone-list{transition-duration:.001s}}@supports not (inset-inline-end:0){.skintone-list{right:0}}.skintone-list.no-animate{transition:none}.tabpanel{overflow-y:auto;scrollbar-gutter:stable;-webkit-overflow-scrolling:touch;will-change:transform;min-height:0;flex:1;contain:content}.emoji-menu{display:grid;grid-template-columns:repeat(var(--num-columns),var(--total-emoji-size));justify-content:space-around;align-items:flex-start;width:100%}.emoji-menu.visibility-auto{content-visibility:auto;contain-intrinsic-size:calc(var(--num-columns)*var(--total-emoji-size)) calc(var(--num-rows)*var(--total-emoji-size))}.category{padding:var(--emoji-padding);font-size:var(--category-font-size);color:var(--category-font-color)}.emoji,button.emoji{font-size:var(--emoji-size);display:flex;align-items:center;justify-content:center;border-radius:100%;height:var(--total-emoji-size);width:var(--total-emoji-size);line-height:1;overflow:hidden;font-family:var(--emoji-font-family);cursor:pointer}@media (hover:hover) and (pointer:fine){.emoji:hover,button.emoji:hover{background:var(--button-hover-background)}}.emoji.active,.emoji:active,button.emoji.active,button.emoji:active{background:var(--button-active-background)}.onscreen .custom-emoji::after{content:"";width:var(--emoji-size);height:var(--emoji-size);background-repeat:no-repeat;background-position:center center;background-size:contain;background-image:var(--custom-emoji-background)}.nav,.nav-button{align-items:center}.nav{display:grid;justify-content:space-between;contain:content}.nav-button{display:flex;justify-content:center}.nav-emoji{font-size:var(--category-emoji-size);width:var(--total-category-emoji-size);height:var(--total-category-emoji-size)}.indicator-wrapper{display:flex;border-bottom:1px solid var(--border-color)}.indicator{width:calc(100%/var(--num-groups));height:var(--indicator-height);opacity:var(--indicator-opacity);background-color:var(--indicator-color);will-change:transform,opacity;transition:opacity .1s linear,transform .25s ease-in-out}@media (prefers-reduced-motion:reduce){.indicator{will-change:opacity;transition:opacity .1s linear}}.pad-top,input.search{background:var(--background);width:100%}.pad-top{height:var(--emoji-padding);z-index:3}.search-row{display:flex;align-items:center;position:relative;padding-inline-start:var(--emoji-padding);padding-bottom:var(--emoji-padding)}.search-wrapper{flex:1;min-width:0}input.search{padding:var(--input-padding);border-radius:var(--input-border-radius);border:var(--input-border-size) solid var(--input-border-color);color:var(--input-font-color);font-size:var(--input-font-size);line-height:var(--input-line-height)}input.search::placeholder{color:var(--input-placeholder-color)}.favorites{overflow-y:auto;scrollbar-gutter:stable;display:flex;flex-direction:row;border-top:var(--border-size) solid var(--border-color);contain:content}.message{padding:var(--emoji-padding)}'+ze,this.shadowRoot.appendChild(t),this._ctx={locale:"en",dataSource:"https://cdn.jsdelivr.net/npm/emoji-picker-element-data@^1/en/emojibase/data.json",skinToneEmoji:"🖐️",customCategorySorting:Y,customEmoji:null,i18n:Le,emojiVersion:null,...e};for(let e of Ie)"database"!==e&&Object.prototype.hasOwnProperty.call(this,e)&&(this._ctx[e]=this[e],delete this[e]);this._dbFlush()}connectedCallback(){Ae(this),this._cmp||(this._cmp=_e(this.shadowRoot,this._ctx))}disconnectedCallback(){Ae(this),Se(()=>{if(!this.isConnected&&this._cmp){this._cmp.$destroy(),this._cmp=void 0;let{database:e}=this._ctx;e.close().catch(e=>console.error(e))}})}static get observedAttributes(){return["locale","data-source","skin-tone-emoji","emoji-version"]}attributeChangedCallback(e,t,n){this._set(e.replace(/-([a-z])/g,(e,t)=>t.toUpperCase()),"emoji-version"===e?parseFloat(n):n)}_set(e,t){this._ctx[e]=t,this._cmp&&this._cmp.$set({[e]:t}),["locale","dataSource"].includes(e)&&this._dbFlush()}_dbCreate(){let{locale:e,dataSource:t,database:n}=this._ctx;(!n||n.locale!==e||n.dataSource!==t)&&this._set("database",new G({locale:e,dataSource:t}))}_dbFlush(){Se(()=>this._dbCreate())}},Me={};for(let e of Ie)Me[e]={get(){return"database"===e&&this._dbCreate(),this._ctx[e]},set(t){if("database"===e)throw new Error("database is read-only");this._set(e,t)}};function Ae(e){e instanceof Pe||Object.setPrototypeOf(e,customElements.get(e.tagName.toLowerCase()).prototype)}Object.defineProperties(Pe.prototype,Me),customElements.get("emoji-picker")||customElements.define("emoji-picker",Pe);export{Pe as default,Ae as rescueElementPrototype};
@@ -0,0 +1,12 @@
1
+ type Bounds = {
2
+ left: number;
3
+ top: number;
4
+ right: number;
5
+ bottom: number;
6
+ };
7
+ export declare function pinDirection(point: {
8
+ x: number;
9
+ y: number;
10
+ component?: Bounds;
11
+ }, viewportWidth: number): "left" | "right";
12
+ export {};
@@ -0,0 +1,3 @@
1
+ import type { Thread } from "./types.js";
2
+ /** Stable membership: moving a pin opts it out until its anchor is replaced. */
3
+ export declare function pinStacks<T>(threads: Thread[], target: (thread: Thread) => T | null): Map<string, Thread[]>;
@@ -0,0 +1,10 @@
1
+ /** One read at a time; quiet widgets and unchanged projects spend less time polling. */
2
+ export declare function adaptivePolling(options: {
3
+ read: () => Promise<boolean | void>;
4
+ active: () => boolean;
5
+ enabled: () => boolean;
6
+ interval: number;
7
+ }): {
8
+ wake: (immediate?: boolean) => void;
9
+ stop(): void;
10
+ };
@@ -0,0 +1,128 @@
1
+ -- PostgreSQL schema for the Node runtime. Mirrors SQLite migrations 0001-0015.
2
+ CREATE TABLE users (id text PRIMARY KEY, name text NOT NULL, verified integer NOT NULL DEFAULT 0, avatar_url text, accent_color text, email text);
3
+ CREATE TABLE sessions (token_hash text PRIMARY KEY, user_id text NOT NULL REFERENCES users(id), project text NOT NULL, expires_at bigint NOT NULL);
4
+ CREATE INDEX session_expiry ON sessions(expires_at);
5
+ CREATE TABLE threads (id text PRIMARY KEY, project text NOT NULL, repo text NOT NULL, branch text NOT NULL, page text NOT NULL, anchor text NOT NULL, resolved integer NOT NULL DEFAULT 0, resolved_by text REFERENCES users(id), created_at bigint NOT NULL, updated_at bigint NOT NULL);
6
+ CREATE INDEX thread_scope ON threads(project,repo,branch,updated_at);
7
+ CREATE INDEX thread_created_scope ON threads(project,repo,branch,created_at,id);
8
+ CREATE TABLE comments (seq bigint GENERATED ALWAYS AS IDENTITY, id text PRIMARY KEY, thread_id text NOT NULL REFERENCES threads(id) ON DELETE CASCADE, user_id text NOT NULL REFERENCES users(id), body text NOT NULL, created_at bigint NOT NULL, edited_at bigint);
9
+ CREATE INDEX comment_thread ON comments(thread_id,created_at);
10
+ CREATE INDEX comments_reviewer_history ON comments(user_id,created_at DESC);
11
+ CREATE TABLE reactions (comment_id text NOT NULL REFERENCES comments(id) ON DELETE CASCADE, user_id text NOT NULL REFERENCES users(id), emoji text NOT NULL, PRIMARY KEY(comment_id,user_id,emoji));
12
+ CREATE TABLE oauth_states (state_hash text PRIMARY KEY, verifier text NOT NULL, project text NOT NULL, origin text NOT NULL, expires_at bigint NOT NULL, exchange_hash text NOT NULL, session_token text, provider text NOT NULL DEFAULT 'github', approved_origins text);
13
+ CREATE INDEX oauth_state_expiry ON oauth_states(expires_at);
14
+ CREATE TABLE rate_limits (key text PRIMARY KEY, count integer NOT NULL, expires_at bigint NOT NULL);
15
+ CREATE INDEX rate_limit_expiry ON rate_limits(expires_at);
16
+ CREATE TABLE workspaces (id text PRIMARY KEY, owner_id text NOT NULL REFERENCES users(id), repo text NOT NULL, origins text NOT NULL, suspended integer NOT NULL DEFAULT 0, created_at bigint NOT NULL, CHECK(owner_id LIKE 'google:%'));
17
+ CREATE INDEX workspace_owner ON workspaces(owner_id);
18
+ CREATE TABLE project_owners (project text PRIMARY KEY, user_id text NOT NULL REFERENCES users(id), CHECK(user_id LIKE 'google:%'));
19
+ CREATE TABLE project_quotas (project text PRIMARY KEY, max_comments integer NOT NULL, max_bytes bigint NOT NULL, comments integer NOT NULL DEFAULT 0, bytes bigint NOT NULL DEFAULT 0);
20
+ CREATE TABLE setup_requests (id text PRIMARY KEY, poll_hash text NOT NULL, config text NOT NULL, project text, expires_at bigint NOT NULL);
21
+ CREATE INDEX setup_request_expiry ON setup_requests(expires_at);
22
+ CREATE TABLE workspace_domains (project text NOT NULL REFERENCES workspaces(id), origin text NOT NULL, verified_at bigint NOT NULL, PRIMARY KEY(project,origin));
23
+ CREATE TABLE project_members (project text NOT NULL, user_id text NOT NULL REFERENCES users(id), PRIMARY KEY(project,user_id));
24
+ CREATE TABLE scope_revisions (project text NOT NULL, repo text NOT NULL, branch text NOT NULL, version bigint NOT NULL DEFAULT 0, PRIMARY KEY(project,repo,branch));
25
+ CREATE TABLE project_settings (project text PRIMARY KEY, access text NOT NULL DEFAULT 'public' CHECK(access IN ('public','private')));
26
+ CREATE TABLE project_access (project text NOT NULL, user_id text NOT NULL REFERENCES users(id), PRIMARY KEY(project,user_id));
27
+ CREATE TABLE project_invites (token_hash text PRIMARY KEY, project text NOT NULL, email text NOT NULL, expires_at bigint NOT NULL);
28
+ CREATE INDEX invite_project ON project_invites(project,expires_at);
29
+ CREATE INDEX invite_expiry ON project_invites(expires_at);
30
+ CREATE TABLE export_revisions (project text PRIMARY KEY, version bigint NOT NULL DEFAULT 0);
31
+ CREATE TABLE project_sites (project text NOT NULL, origin text NOT NULL, added_at bigint NOT NULL, removed integer NOT NULL DEFAULT 0, PRIMARY KEY(project,origin));
32
+
33
+ CREATE FUNCTION komo_quota(p_project text, p_comments integer, p_bytes bigint) RETURNS void LANGUAGE plpgsql AS $$
34
+ BEGIN
35
+ UPDATE project_quotas SET comments=GREATEST(0,comments+p_comments), bytes=GREATEST(0,bytes+p_bytes) WHERE project=p_project;
36
+ IF EXISTS(SELECT 1 FROM project_quotas WHERE project=p_project AND (comments>max_comments OR bytes>max_bytes)) THEN
37
+ RAISE EXCEPTION 'komo_quota_exceeded';
38
+ END IF;
39
+ END $$;
40
+ CREATE FUNCTION komo_scope(p_project text,p_repo text,p_branch text) RETURNS void LANGUAGE plpgsql AS $$
41
+ BEGIN
42
+ INSERT INTO scope_revisions(project,repo,branch,version) VALUES(p_project,p_repo,p_branch,1)
43
+ ON CONFLICT(project,repo,branch) DO UPDATE SET version=scope_revisions.version+1;
44
+ END $$;
45
+ CREATE FUNCTION komo_export(p_project text) RETURNS void LANGUAGE plpgsql AS $$
46
+ BEGIN
47
+ IF p_project IS NOT NULL THEN
48
+ INSERT INTO export_revisions(project,version) VALUES(p_project,1)
49
+ ON CONFLICT(project) DO UPDATE SET version=export_revisions.version+1;
50
+ END IF;
51
+ END $$;
52
+ CREATE FUNCTION komo_thread_change() RETURNS trigger LANGUAGE plpgsql AS $$
53
+ BEGIN
54
+ IF TG_OP='DELETE' THEN
55
+ PERFORM komo_quota(OLD.project,0,-(octet_length(OLD.anchor)+octet_length(OLD.page)+octet_length(OLD.branch)+512));
56
+ PERFORM komo_scope(OLD.project,OLD.repo,OLD.branch);
57
+ PERFORM komo_export(OLD.project);
58
+ RETURN OLD;
59
+ END IF;
60
+ IF TG_OP='INSERT' THEN
61
+ PERFORM komo_quota(NEW.project,0,octet_length(NEW.anchor)+octet_length(NEW.page)+octet_length(NEW.branch)+512);
62
+ ELSE
63
+ PERFORM komo_quota(NEW.project,0,octet_length(NEW.anchor)-octet_length(OLD.anchor));
64
+ END IF;
65
+ PERFORM komo_scope(NEW.project,NEW.repo,NEW.branch);
66
+ PERFORM komo_export(NEW.project);
67
+ RETURN NEW;
68
+ END $$;
69
+ CREATE FUNCTION komo_thread_children() RETURNS trigger LANGUAGE plpgsql AS $$
70
+ BEGIN
71
+ PERFORM set_config('komo.deleting_thread',OLD.id,true);
72
+ DELETE FROM comments WHERE thread_id=OLD.id;
73
+ PERFORM set_config('komo.deleting_thread','',true);
74
+ RETURN OLD;
75
+ END $$;
76
+ CREATE TRIGGER thread_children BEFORE DELETE ON threads FOR EACH ROW EXECUTE FUNCTION komo_thread_children();
77
+ CREATE TRIGGER thread_change AFTER INSERT OR UPDATE OR DELETE ON threads FOR EACH ROW EXECUTE FUNCTION komo_thread_change();
78
+ CREATE FUNCTION komo_comment_change() RETURNS trigger LANGUAGE plpgsql AS $$
79
+ DECLARE p text;
80
+ BEGIN
81
+ SELECT project INTO p FROM threads WHERE id=COALESCE(NEW.thread_id,OLD.thread_id);
82
+ IF TG_OP='INSERT' THEN
83
+ PERFORM komo_quota(p,1,octet_length(NEW.body)+256);
84
+ ELSIF TG_OP='UPDATE' THEN
85
+ PERFORM komo_quota(p,0,octet_length(NEW.body)-octet_length(OLD.body));
86
+ ELSE
87
+ PERFORM komo_quota(p,-1,-(octet_length(OLD.body)+256));
88
+ IF current_setting('komo.deleting_thread',true) IS DISTINCT FROM OLD.thread_id THEN
89
+ UPDATE threads SET updated_at=GREATEST(updated_at+1,(extract(epoch FROM clock_timestamp())*1000)::bigint) WHERE id=OLD.thread_id;
90
+ END IF;
91
+ END IF;
92
+ PERFORM komo_export(p);
93
+ RETURN COALESCE(NEW,OLD);
94
+ END $$;
95
+ CREATE FUNCTION komo_comment_children() RETURNS trigger LANGUAGE plpgsql AS $$
96
+ BEGIN
97
+ DELETE FROM reactions WHERE comment_id=OLD.id;
98
+ RETURN OLD;
99
+ END $$;
100
+ CREATE TRIGGER comment_children BEFORE DELETE ON comments FOR EACH ROW EXECUTE FUNCTION komo_comment_children();
101
+ CREATE TRIGGER comment_change AFTER INSERT OR UPDATE OR DELETE ON comments FOR EACH ROW EXECUTE FUNCTION komo_comment_change();
102
+ CREATE FUNCTION komo_reaction_change() RETURNS trigger LANGUAGE plpgsql AS $$
103
+ DECLARE p text;
104
+ BEGIN
105
+ SELECT t.project INTO p FROM comments c JOIN threads t ON t.id=c.thread_id WHERE c.id=COALESCE(NEW.comment_id,OLD.comment_id);
106
+ IF TG_OP='INSERT' THEN PERFORM komo_quota(p,0,256);
107
+ ELSIF TG_OP='DELETE' THEN PERFORM komo_quota(p,0,-256);
108
+ END IF;
109
+ PERFORM komo_export(p);
110
+ RETURN COALESCE(NEW,OLD);
111
+ END $$;
112
+ CREATE TRIGGER reaction_change AFTER INSERT OR UPDATE OR DELETE ON reactions FOR EACH ROW EXECUTE FUNCTION komo_reaction_change();
113
+ CREATE FUNCTION komo_member_change() RETURNS trigger LANGUAGE plpgsql AS $$
114
+ BEGIN
115
+ IF TG_OP='INSERT' THEN PERFORM komo_quota(NEW.project,0,13312);
116
+ ELSE PERFORM komo_quota(OLD.project,0,-13312);
117
+ END IF;
118
+ RETURN COALESCE(NEW,OLD);
119
+ END $$;
120
+ CREATE TRIGGER member_change AFTER INSERT OR DELETE ON project_members FOR EACH ROW EXECUTE FUNCTION komo_member_change();
121
+ CREATE FUNCTION komo_profile_change() RETURNS trigger LANGUAGE plpgsql AS $$
122
+ BEGIN
123
+ UPDATE scope_revisions SET version=version+1 WHERE (project,repo,branch) IN
124
+ (SELECT t.project,t.repo,t.branch FROM threads t JOIN comments c ON c.thread_id=t.id WHERE c.user_id=NEW.id);
125
+ UPDATE export_revisions SET version=version+1 WHERE project IN (SELECT project FROM project_members WHERE user_id=NEW.id);
126
+ RETURN NEW;
127
+ END $$;
128
+ CREATE TRIGGER profile_change AFTER UPDATE ON users FOR EACH ROW EXECUTE FUNCTION komo_profile_change();
@@ -0,0 +1 @@
1
+ ALTER TABLE threads ADD COLUMN tags text NOT NULL DEFAULT '[]';
@@ -0,0 +1,4 @@
1
+ ALTER TABLE project_settings ADD COLUMN webhook_url text;
2
+ ALTER TABLE project_settings ADD COLUMN webhook_secret text;
3
+ ALTER TABLE project_settings ADD COLUMN webhook_events text;
4
+ ALTER TABLE project_settings ADD COLUMN webhook_enabled integer NOT NULL DEFAULT 0;
@@ -0,0 +1,2 @@
1
+ import type { CommentsApi } from "./api.js";
2
+ export declare function projectManagement(api: CommentsApi, workspace?: string, onChange?: (deleted: boolean) => void): HTMLElement;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Runtime bridge for explicitly registered React roots.
3
+ *
4
+ * TypeScript types do not exist at runtime. A build-time manifest supplies the
5
+ * small, safe subset that can be edited; the consuming React app supplies a
6
+ * state callback so preview changes go through React's normal render cycle.
7
+ */
8
+ export type InspectableScalar = string | number | boolean | undefined;
9
+ export interface InspectableProp {
10
+ name: string;
11
+ kind: "string" | "number" | "boolean" | "enum" | "unsupported";
12
+ required: boolean;
13
+ values?: Array<string | number | boolean>;
14
+ typeLabel: string;
15
+ }
16
+ export interface InspectableComponent {
17
+ id: string;
18
+ name: string;
19
+ source: string;
20
+ line: number;
21
+ props: InspectableProp[];
22
+ /** Explicitly map a leaf text rendering to one editable string prop. */
23
+ textProp?: string;
24
+ }
25
+ export interface RegisteredInspectableComponent {
26
+ definition: InspectableComponent;
27
+ props: Record<string, InspectableScalar>;
28
+ onChange(next: Record<string, InspectableScalar>): void;
29
+ setProps(next: Record<string, InspectableScalar>): void;
30
+ }
31
+ export interface ReactPropEdit {
32
+ element: HTMLElement;
33
+ propName: string;
34
+ before: InspectableScalar;
35
+ after: InspectableScalar;
36
+ }
37
+ export declare function isEditablePropValue(prop: InspectableProp, value: unknown): value is InspectableScalar;
38
+ /** Register one opt-in root. Never infers ownership from React private internals. */
39
+ export declare function registerInspectableRoot(element: HTMLElement, definition: InspectableComponent, props: Record<string, unknown>, onChange: (next: Record<string, InspectableScalar>) => void): () => void;
40
+ /** Refresh a registered root's latest state and callback without replacing its identity. */
41
+ export declare function updateInspectableRoot(element: HTMLElement | null, definition: InspectableComponent, props: Record<string, unknown>, onChange: (next: Record<string, InspectableScalar>) => void): void;
42
+ /** Find the nearest explicitly registered React component root for a DOM target. */
43
+ export declare function inspectableFor(target: Element | null): RegisteredInspectableComponent | null;
@@ -0,0 +1 @@
1
+ import{a as e,d as t,f as n,g as i,h as o,i as a,j as r,k as d,l as s,m as l,n as p,o as c,p as u,q as g,r as f,s as m,t as h,u as b,v as k}from"./chunk-Z2ABBESO.js";import"./chunk-I7AUKTXE.js";var x=new Map,v=new WeakMap,y=new WeakSet,w=new WeakMap,E=".design-react-source{display:block;padding:0 0 8px;color:#77736f;font-size:10px;overflow-wrap:anywhere}.design-react-field.design-field{display:grid;grid-template-columns:76px minmax(0,1fr);gap:0 8px;height:auto;min-height:28px;margin-top:4px;background:none;box-shadow:none;color:#898680;font-size:11px}.design-react-field>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.design-react-field.design-field>:is(input,select){box-sizing:border-box;width:100%;min-width:0;height:28px;padding:0 8px;border:0;border-radius:6px;background:#ffffff0a;color:#f1efeb;font:inherit;font-size:11px}.design-react-field.design-field>:is(input,select):focus-visible{outline:1px solid #bda6ef;outline-offset:-1px}.design-react-field input[type=checkbox]{justify-self:end;width:14px;height:14px;accent-color:#bda6ef}.design-react-field input:disabled{opacity:.55;cursor:not-allowed}.design-react-type{display:none}.design-react-field .design-token-binding{grid-column:2;display:grid;grid-template-columns:auto minmax(0,1fr);align-items:center;gap:6px;margin-top:4px;color:#77736f;font-size:10px}.design-react-field .design-token-binding select{min-width:0;height:24px;border:0;border-radius:6px;background:#ffffff0a;color:#e9e6e1;padding:0 6px;font:inherit;font-size:10px}.design-react-field .design-token-binding[data-mode=token] select{background:#bda6ef24;color:#e6dcfb}.design-token-binding__state{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.design-field>.design-token-binding{display:contents}.design-field:has(>.design-token-binding)>input[data-property]{padding-right:28px}.design-token-icon,.design-token-detach,.design-field>.design-token-binding select{position:absolute;top:4px;right:4px;width:20px;height:20px;box-sizing:border-box;border-radius:5px}.design-token-icon{display:grid;place-items:center;color:#77736f;opacity:0;pointer-events:none;transition:opacity .12s}.design-token-icon::before{content:'';width:6px;height:6px;border:1.2px solid currentColor;border-radius:1.5px;rotate:45deg}.design-field:is(:hover,:focus-within) .design-token-icon{opacity:1}.design-field>.design-token-binding select{margin:0;padding:0;border:0;opacity:0;cursor:pointer;appearance:none}.design-field>.design-token-binding select:hover+.design-token-icon,.design-field:has(.design-token-binding select:hover) .design-token-icon{background:#ffffff14;color:#e9e6e1}.design-field:has(.design-token-binding select:focus-visible) :is(.design-token-icon,.design-token-chip){outline:2px solid #bda6ef;outline-offset:1px;opacity:1}.design-field[data-token-mode=override] .design-token-icon{opacity:1;color:#e7c27d}.design-token-chip,.design-token-detach{display:none}.design-field:is([data-token-mode=token],[data-token-mode=connected])>input[data-property]{visibility:hidden}.design-field:is([data-token-mode=token],[data-token-mode=connected]) .design-token-chip{position:absolute;inset:4px 28px 4px var(--lead,4px);display:flex;align-items:center;gap:5px;padding:0 6px;border-radius:4px;background:#bda6ef1f;color:#e6dcfb;font-size:11px;white-space:nowrap;overflow:hidden;pointer-events:none}.design-token-chip::before{content:'';flex:none;width:5px;height:5px;border:1.2px solid #c8b5f4;border-radius:1px;rotate:45deg}.design-field:is([data-token-mode=token],[data-token-mode=connected]) .design-token-binding select{left:var(--lead,4px);right:28px;width:auto}.design-field:is([data-token-mode=token],[data-token-mode=connected]) .design-token-icon{display:none}.design-field:is([data-token-mode=token],[data-token-mode=connected]) .design-token-detach{display:grid;place-items:center;color:#898680}.design-token-detach:hover{background:#ffffff14;color:#f1efeb}.design-token-detach svg{width:12px;height:12px;fill:none;stroke:currentColor;stroke-width:1.2;stroke-linecap:round}.design-theme-group .design-react-source{padding:0 0 6px}.design-theme-heading{display:block;padding:8px 0 2px;color:#77736f;font-size:10px;text-transform:capitalize}.design-theme-token{position:relative;display:grid;grid-template-columns:96px minmax(0,1fr) 20px;align-items:center;gap:6px;margin-top:4px}.design-theme-token>span{overflow:hidden;color:#898680;font-size:11px;text-overflow:ellipsis;white-space:nowrap}.design-theme-token[data-changed]>span{color:#e6dcfb}.design-theme-token[data-changed]::before{content:'';position:absolute;top:calc(50% - 2px);left:-8px;width:4px;height:4px;border-radius:50%;background:#bda6ef}.design-theme-reset{display:grid;place-items:center;width:20px;height:20px;padding:0;border:0;border-radius:5px;background:none;color:#77736f;cursor:pointer}.design-theme-reset:disabled{visibility:hidden}.design-theme-reset:hover{background:#ffffff14;color:#f1efeb}.design-theme-reset svg{width:12px;height:12px;fill:none;stroke:currentColor;stroke-width:1.4;stroke-linecap:round;stroke-linejoin:round}";function C(e){return void 0===e?"unset":JSON.stringify(e)??"unset"}function $(e){return!!x.get(e)?.size}function S(e){let n=t(e),i=n?.definition.textProp,o=n?.definition.props.find(e=>e.name===i);if(!n||!i||"string"!==o?.kind)return null;let a=n.props[i];if("string"!=typeof a||a.length>500)return null;let r=x.get(e);return r||x.set(e,r=new Map),r.has(i)||r.set(i,a),{propName:i,before:a}}function P(n,i,o){let a=t(n),r=a?.definition.props.find(e=>e.name===i);return!(!a||a.definition.textProp!==i||"string"!==r?.kind||o.length>500||!e(r,o))&&(a.setProps({...a.props,[i]:o}),!0)}function N(e,t,n,i){if(n===i){let i=x.get(e);return void(i?.get(t)===n&&!(v.get(e)??[]).some(e=>e.propName===t)&&(i.delete(t),i.size||x.delete(e)))}let o=v.get(e);o||v.set(e,o=[]),o.push({propName:t,before:n,after:i})}function A(e,t,n){P(e,t,n);let i=x.get(e);i?.get(t)===n&&!(v.get(e)??[]).some(e=>e.propName===t)&&(i.delete(t),i.size||x.delete(e))}function z(e){return!!e&&!!v.get(e)?.length}function M(e){let i=x.get(e),o=t(e);if(!i?.size||!o)return;let a=n(e),r=[...i].map(([e,t])=>{let n=o.definition.props.find(t=>t.name===e)?.styleProperty,i=o.props[e],r=n&&"string"==typeof i?a?.tokens.find(e=>e.properties.includes(n)&&i===`var(${e.cssVariable})`):void 0;return`- ${e}: ${C(t)} → ${C(i)}${r?` [${r.path}]`:" [custom value]"}`});return["Proposed React prop changes (preview only)",`Component: ${o.definition.name}`,`Source: ${o.definition.source}:${o.definition.line}`,...r,"Preview values use the app's React state callback; Komo does not write source files."].join("\n")}function L(e){return[M(e),k(e)].filter(e=>!!e).join("\n\n")||void 0}function R(e,n,i){w.get(e)?.abort();let o=new AbortController;w.set(e,o),e.addEventListener("click",e=>{let o=n();if(!o)return;let a=k(o);!t(o)&&!a||(e.stopImmediatePropagation(),i(o,L(o)))},{capture:!0,signal:o.signal})}function T(e){return m(e)}function q(e){return f(e)}function D(e){h(e)}function j(e){b(e)}function V(e){if(!e||y.has(e))return;let t=document.createElement("style");t.textContent=E,e.append(t),y.add(e)}function O(e,t,o,a){let r=n(e);if(!r)return null;let l=g(r,t);if(!l.length)return null;V(a);let f=document.createElement("span");f.className="design-token-binding",f.setAttribute("data-mode","custom");let m=document.createElement("span");m.className="design-token-icon",m.setAttribute("aria-hidden","true");let h=document.createElement("span");h.className="design-token-chip",h.setAttribute("aria-hidden","true");let b=document.createElement("button");b.type="button",b.className="design-token-detach",b.title="Detach token",b.setAttribute("aria-label",`Detach token from ${t}`),b.innerHTML='<svg viewBox="0 0 12 12"><path d="M5 3.5 6.5 2a2.1 2.1 0 0 1 3 3L8 6.5M7 8.5 5.5 10a2.1 2.1 0 0 1-3-3L4 5.5M2 2l8 8"/></svg>';let k=document.createElement("select");k.setAttribute("aria-label",`Style token for ${t}`);let x=document.createElement("small");x.className="design-token-binding__state",x.setAttribute("aria-live","polite");let v=`komo-token-${t}-${Math.random().toString(36).slice(2,8)}`;x.id=v,k.setAttribute("aria-describedby",v);let y=document.createElement("option");y.value="custom",y.textContent="Custom value",k.append(y);for(let e of l){let t=document.createElement("option"),n=i(r,e);t.value=e.path,t.textContent=n?`${e.path} · ${n}`:e.path,k.append(t)}let w=()=>{let n=p(r,e,t),i=n?null:c(r,e,t),o="token"===n?.mode?l.find(e=>e.path===n.tokenPath):void 0,a=o??i?.token;k.value=a?.path??"custom",h.textContent=a?.path??"";let d=n?.declaredPath,s=o?"token":i?"connected":d?"override":"custom";f.dataset.mode=s,f.parentElement?.setAttribute("data-token-mode",s),x.textContent="token"===s?d&&d!==o?.path?`Rebound from ${d} · preview`:`Linked to ${o?.path} · preview`:"connected"===s?"Connected "+("inline"===i?.origin?"inline":"from stylesheet"):"override"===s?`Custom override · was ${d}`:"",k.title=x.textContent||"Choose a token"},E=new MutationObserver(w);E.observe(e,{attributes:!0,attributeFilter:["style"]});let C=new MutationObserver(()=>{f.isConnected||(E.disconnect(),C.disconnect())});return C.observe(f.ownerDocument,{childList:!0,subtree:!0}),k.addEventListener("change",()=>{let n=e.style.getPropertyValue(t),i=l.find(e=>e.path===k.value),a=p(r,e,t);if(i&&a&&i.path===a.declaredPath)u(r,e,t),o(n,e.style.getPropertyValue(t),i.path);else if(i)(i.path!==c(r,e,t)?.token.path||a)&&d(r,e,i,t,{recordHistory:!1})&&o(n,e.style.getPropertyValue(t),i.path);else{let i=f.parentElement?.querySelector("[data-property]")?.value??getComputedStyle(e).getPropertyValue(t).trim(),a=/^-?[\d.]+$/.test(i.trim())&&!/weight|line/.test(t)?`${i.trim()}px`:i;s(r,e,t,a),e.style.setProperty(t,a),o(n,a)}w()}),b.addEventListener("click",()=>{let e=l.find(e=>e.path===k.value),t=f.parentElement?.querySelector("input[data-property]"),n=e&&i(r,e);t&&n&&(t.value="number"===t.type?String(parseFloat(n)):n),k.value="custom",k.dispatchEvent(new Event("change")),f.parentElement?.querySelector("[data-property]")?.focus()}),f.append(h,k,m,b,x),queueMicrotask(w),w(),f}function B(e){let t=n(e);return new Set(t?.elementBindings.get(e)?.keys()??[])}function H(e,t,n,i,o,a,r){for(let d of t){let t=[...n.querySelectorAll("[data-field-property]")].find(e=>e.dataset.fieldProperty===d.property);if(!t||t.querySelector(".design-token-binding"))continue;let s=t.querySelector("[data-property]");if(!s)continue;let l=O(e,d.property,n=>{i(d,s,n),a&&(s.value=a(d,e));let o=t.querySelector('input[type="range"],input[type="color"]');o&&(o.value="color"===d.kind&&r?r(s.value):s.value)},o);l&&t.append(l)}}var W=!1;function _(e,t,i,o){let a=n(e);if(!a||!a.tokens.length)return null;V(o);let r=document.createElement("details");r.className="design-group design-theme-group",r.open=W,r.addEventListener("toggle",()=>{r.isConnected&&(W=r.open)});let d=document.createElement("summary");d.textContent="Shared theme";let s=document.createElement("small");s.className="design-react-source",s.textContent="Changes every element using these tokens",r.append(d,s);let l=new Map;for(let e of a.tokens){let t=e.path.split(".")[0];l.set(t,[...l.get(t)??[],e])}let p=a.tokens.length>6&&l.size>1;for(let[e,n]of p?l:new Map([["",a.tokens]])){if(e){let t=document.createElement("small");t.className="design-theme-heading",t.textContent=e,r.append(t)}for(let o of n)r.append(F(a,o,t,i,e))}return r}function F(e,t,n,d,s){let l=document.createElement("div");l.className="design-theme-token";let p=document.createElement("span");p.textContent=s&&t.path.slice(s.length+1)||t.path,p.title=`${t.path} · ${o(e,t)} matching · ${t.impactSelector}`;let c=n.fields.find(e=>t.properties.includes(e.property)),u={property:t.cssVariable,label:`Shared theme value for ${t.path}`,kind:"dimension"===t.type?"size":c?.kind??"text",glyph:"color"===t.type?void 0:c?.glyph,values:c?.values},g=!1,f=n.fieldControl(u,{element:e.root,begin:()=>{g=!1},apply:(n,i,o)=>{let r=null!==o&&a(e,t,o.trim(),g);n.setAttribute("aria-invalid",String(!r)),r&&(g=!0,k(),d())},commit:(e,t,n)=>{!1!==n&&(g=!1,"true"===e.getAttribute("aria-invalid")&&b())}}),m=f.querySelector("[data-property]"),h=f.querySelector('input[type="color"]'),b=()=>{let o=i(e,t);m.value=o,h&&(h.value=n.toHex(o)),m.removeAttribute("aria-invalid"),k()},k=()=>{x.disabled=!l.toggleAttribute("data-changed",e.themeEdits.has(t.path)),"fontFamily"===t.type&&(m.title=m.value)},x=document.createElement("button");return x.type="button",x.className="design-theme-reset",x.title="Reset to page value",x.setAttribute("aria-label",`Reset ${t.path}`),x.innerHTML='<svg viewBox="0 0 16 16"><path d="M2.5 2.5v3h3M3 5.5a5.5 5.5 0 1 1-.5 2.5"/></svg>',x.addEventListener("click",()=>{r(e,t),b(),d()}),b(),l.append(p,f,x),l}function I(e,t,i){let o=n(e);o&&s(o,e,t,i)}function K(e,t){let i=n(e);i&&l(i,e,t)}function U(e){let n=v.get(e)?.pop(),i=t(e);if(!n||!i)return;i.setProps({...i.props,[n.propName]:n.before});let o=x.get(e);if(o){let t=o.get(n.propName);Object.is(t,n.before)&&o.delete(n.propName),o.size||x.delete(e)}}function J(e){let n=x.get(e),i=t(e);!n?.size||!i||(i.setProps({...i.props,...Object.fromEntries(n)}),x.delete(e),v.delete(e))}function X(t,n,i,o,a,r){let d=n.definition.props.find(e=>e.name===i);if(!d||!e(d,o))return a.setAttribute("aria-invalid","true"),!1;a.removeAttribute("aria-invalid");let s=n.props[i];if(Object.is(s,o))return!0;let l=x.get(t);l||x.set(t,l=new Map);let p=l.has(i)?l.get(i):s;Object.is(p,o)?l.delete(i):l.set(i,p),l.size||x.delete(t);let c=v.get(t);return c||v.set(t,c=[]),c.push({propName:i,before:s,after:o}),n.setProps({...n.props,[i]:o}),r(),!0}function Z(e,i,o){let a=t(e);if(!a)return null;if(o&&!y.has(o)){let e=document.createElement("style");e.textContent=E,o.append(e),y.add(o)}let r=document.createElement("details");r.className="design-group design-react-group",r.open=!0;let d=document.createElement("summary");d.textContent="React props",r.append(d);let s=document.createElement("small");s.className="design-react-source",s.textContent=`${a.definition.name} · ${a.definition.source}:${a.definition.line}`,r.append(s);for(let t of a.definition.props){let o=t.styleProperty,d=document.createElement("label");d.className="design-field design-react-field";let s=document.createElement("span");s.textContent=t.name;let l,p=a.props[t.name];if("enum"===t.kind){let e=document.createElement("select");for(let n of t.values??[]){let t=document.createElement("option");t.value=String(n),t.textContent=String(n),e.append(t)}if(void 0===p&&!t.required){let t=document.createElement("option");t.value="",t.textContent="unset",e.prepend(t)}e.value=void 0===p?"":String(p),l=e}else{let e=document.createElement("input");"boolean"===t.kind?(e.type="checkbox",e.checked=!0===p):"number"===t.kind?(e.type="number",e.step="any",e.value="number"==typeof p?String(p):""):(e.type="text",e.maxLength=500,e.autocomplete="off",e.value="string"==typeof p?p:""),l=e}if(l.setAttribute("aria-label",`${a.definition.name} ${t.name}`),"unsupported"===t.kind)l=document.createElement("input"),l.disabled=!0,l.value=`Read only · ${t.typeLabel}`,l.setAttribute("aria-label",`${a.definition.name} ${t.name}, read only`),d.title=`Komo does not edit ${t.typeLabel} props.`;else{let n=()=>{let n=l instanceof HTMLInputElement&&"checkbox"===l.type?l.checked:l.value,o=n;if("number"===t.kind)o=""===String(n).trim()?void 0:Number(n);else if("enum"===t.kind){let e=(t.values??[]).find(e=>String(e)===n);o=""!==n||t.required?e:void 0}else"boolean"===t.kind&&(o=!0===n);X(e,a,t.name,o,l,i)};l.addEventListener("change",n)}d.append(s,l);let c=document.createElement("small");if(c.className="design-react-type",c.textContent=`${t.typeLabel}${t.required?" · required":" · optional"}`,d.append(c),d.title||=c.textContent,"string"===t.kind&&o){let r=n(e),s=r?g(r,o):[];if(s.length){let n=document.createElement("span");n.className="design-token-binding";let r=document.createElement("span");r.textContent="Style token";let p=document.createElement("select");p.setAttribute("aria-label",`Style token for ${t.name}`);let c=document.createElement("option");c.value="custom",c.textContent="Custom value",p.append(c);for(let e of s){let t=document.createElement("option");t.value=e.path,t.textContent=e.path,p.append(t)}let u=()=>{let e=s.find(e=>a.props[t.name]===`var(${e.cssVariable})`);p.value=e?.path??"custom",n.dataset.mode=e?"token":"custom"};p.addEventListener("change",()=>{let n=s.find(e=>e.path===p.value),r=n?`var(${n.cssVariable})`:"string"==typeof a.props[t.name]&&String(a.props[t.name]).startsWith("var(")?e.ownerDocument.defaultView?.getComputedStyle(e).getPropertyValue(o).trim()??"":"string"==typeof a.props[t.name]?a.props[t.name]:"";X(e,a,t.name,r,l,i)&&u()}),n.append(r,p),d.append(n),u()}}r.append(d)}return r}export{H as attachStyleTokenControls,S as beginReactTextEdit,T as canUndoDesignTokenEdit,z as canUndoReactProp,A as cancelReactTextEdit,_ as createDesignThemePanel,O as createElementTokenControl,Z as createReactPropsPanel,N as finishReactTextEdit,q as hasDesignTokenEdit,$ as hasReactPropChanges,R as installCommentCapture,I as noteDesignTokenOverride,P as previewReactTextEdit,L as proposedDesignChanges,M as proposedReactChanges,j as resetDesignTokenEdits,J as resetReactProps,K as syncDesignTokenBinding,B as tokenBoundProperties,D as undoDesignTokenEdit,U as undoReactProp};
@@ -0,0 +1,39 @@
1
+ export declare function hasReactPropChanges(element: HTMLElement): boolean;
2
+ export interface ReactTextEditStart {
3
+ propName: string;
4
+ before: string;
5
+ }
6
+ /** Only an explicit registered textProp can drive a React-rendered inline edit. */
7
+ export declare function beginReactTextEdit(element: HTMLElement): ReactTextEditStart | null;
8
+ /** Preview through the registered React state callback; never mutate React's DOM. */
9
+ export declare function previewReactTextEdit(element: HTMLElement, propName: string, value: string): boolean;
10
+ export declare function finishReactTextEdit(element: HTMLElement, propName: string, before: string, after: string): void;
11
+ export declare function cancelReactTextEdit(element: HTMLElement, propName: string, before: string): void;
12
+ export declare function canUndoReactProp(element: HTMLElement | null): boolean;
13
+ export declare function proposedReactChanges(element: HTMLElement): string | undefined;
14
+ export declare function proposedDesignChanges(element: HTMLElement): string | undefined;
15
+ export declare function installCommentCapture(button: HTMLButtonElement, selected: () => HTMLElement | null, onComment: (element: Element, proposal?: string) => void): void;
16
+ export declare function canUndoDesignTokenEdit(element: HTMLElement | null): boolean;
17
+ export declare function hasDesignTokenEdit(element: HTMLElement): boolean;
18
+ export declare function undoDesignTokenEdit(element: HTMLElement): void;
19
+ export declare function resetDesignTokenEdits(element: HTMLElement): void;
20
+ /** Add token references directly to the existing style-property row. */
21
+ export declare function createElementTokenControl(element: HTMLElement, property: string, onEdit: (before: string, after: string, tokenPath?: string) => void, styleRoot?: ShadowRoot): HTMLElement | null;
22
+ /** Properties whose before/after is described by token provenance instead of raw CSS. */
23
+ export declare function tokenBoundProperties(element: HTMLElement): Set<string>;
24
+ export declare function attachStyleTokenControls<T extends {
25
+ property: string;
26
+ kind?: string;
27
+ }>(element: HTMLElement, fields: readonly T[], container: HTMLElement, onEdit: (field: T, input: HTMLInputElement | HTMLSelectElement, before: string) => void, styleRoot?: ShadowRoot, valueFor?: (field: T, element: HTMLElement) => string, toHex?: (value: string) => string): void;
28
+ type ThemeFields = Pick<typeof import("./design-panel.js"), "fieldControl" | "fields" | "toHex">;
29
+ /**
30
+ * Shared theme editing stays secondary; per-element token choice lives on each knob.
31
+ * Token rows reuse the panel's own fields and preview live, like every other field.
32
+ */
33
+ export declare function createDesignThemePanel(element: HTMLElement, panel: ThemeFields, onEdit: () => void, styleRoot?: ShadowRoot): HTMLElement | null;
34
+ export declare function noteDesignTokenOverride(element: HTMLElement, property: string, value: string): void;
35
+ export declare function syncDesignTokenBinding(element: HTMLElement, property: string): void;
36
+ export declare function undoReactProp(element: HTMLElement): void;
37
+ export declare function resetReactProps(element: HTMLElement): void;
38
+ export declare function createReactPropsPanel(element: HTMLElement, onEdit: () => void, styleRoot?: ShadowRoot): HTMLElement | null;
39
+ export {};
@@ -0,0 +1,38 @@
1
+ import { type RefCallback } from "react";
2
+ import { type InspectableComponent, type InspectableScalar } from "./react-inspector.js";
3
+ import { type KomoDesignToken } from "./design-tokens.js";
4
+ import type { KomoConfig } from "./config.js";
5
+ export type { KomoConfig } from "./config.js";
6
+ export type { InspectableComponent, InspectableProp, InspectableScalar, } from "./react-inspector.js";
7
+ export type { KomoDesignToken, KomoDesignTokenType } from "./design-tokens.js";
8
+ /** Mount once near the React app root. Memoize callback options with useCallback. */
9
+ export declare function useKomo(config: KomoConfig): void;
10
+ export interface UseKomoInspectableOptions {
11
+ /** A build-generated manifest entry for this component. */
12
+ component: InspectableComponent;
13
+ /** Only the scalar props listed by the manifest are exposed to the inspector. */
14
+ props: Record<string, InspectableScalar>;
15
+ /** Feed proposed preview values back through the component's React state. */
16
+ onChange(next: Record<string, InspectableScalar>): void;
17
+ /** Keep disabled outside an explicitly enabled development/demo environment. */
18
+ enabled?: boolean;
19
+ }
20
+ /**
21
+ * Opt one React DOM root into the Design mode prop inspector. The component
22
+ * must provide its own state update callback; Komo never reads Fiber internals
23
+ * or writes the host application's source files.
24
+ */
25
+ export declare function useKomoInspectable(options: UseKomoInspectableOptions): {
26
+ ref: RefCallback<HTMLElement>;
27
+ "data-komo-inspectable": string;
28
+ };
29
+ export interface UseKomoDesignTokensOptions {
30
+ /** Element that owns the explicitly listed CSS custom properties; defaults to document.documentElement after hydration. */
31
+ root?: HTMLElement;
32
+ /** Allowlisted token metadata; Komo never scans arbitrary custom properties. */
33
+ tokens: readonly KomoDesignToken[];
34
+ /** Keep disabled outside an explicitly enabled development/demo environment. */
35
+ enabled?: boolean;
36
+ }
37
+ /** Register named CSS-variable tokens for temporary Design mode previews. */
38
+ export declare function useKomoDesignTokens(options: UseKomoDesignTokensOptions): void;
package/dist/react.js ADDED
@@ -0,0 +1 @@
1
+ "use client";import{b as e,c as n,e as r}from"./chunk-Z2ABBESO.js";import{b as t}from"./chunk-JQVBZ2BB.js";import"./chunk-Q7WSWLMV.js";import"./chunk-Y2GRLW4Q.js";import"./chunk-7YUXYVQA.js";import"./chunk-YZP3KX4Y.js";import"./chunk-I7AUKTXE.js";import{useEffect as o,useRef as s}from"react";function c(e){let n=s(null);o(()=>{if(n.current&&function(e,n){return[...new Set([...Object.keys(e),...Object.keys(n)])].every(r=>{if("shortcuts"===r||"features"===r){let t=e[r]??{},o=n[r]??{};return Object.keys({...t,...o}).every(e=>Object.is(t[e],o[e]))}if("onboarding"!==r)return Object.is(e[r],n[r]);let t=e.onboarding,o=n.onboarding;return t&&o?Object.keys({...t,...o}).every(e=>"sites"===e?t.sites?.length===o.sites?.length&&(t.sites??[]).every((e,n)=>e===o.sites?.[n]):Object.is(t[e],o[e])):t===o})}(n.current.config,e)||(n.current?.controller.destroy(),n.current=null,!1===e.enabled))return;let r={...e,...e.onboarding?{onboarding:{...e.onboarding,...e.onboarding.sites?{sites:[...e.onboarding.sites]}:{}}}:{}};n.current={config:r,controller:t(r)}}),o(()=>()=>{n.current?.controller.destroy(),n.current=null},[])}function u(r){let t=s(null),c=s(null);return c.current||(c.current=e=>{t.current=e}),o(()=>{if(!0===r.enabled&&t.current)return e(t.current,r.component,r.props,r.onChange)},[r.enabled,r.component]),o(()=>{!0===r.enabled&&n(t.current,r.component,r.props,r.onChange)},[r.enabled,r.component,r.props,r.onChange]),{ref:c.current,"data-komo-inspectable":r.component.id}}function i(e){o(()=>{if(!0!==e.enabled)return;let n=e.root??document.documentElement;return r(n,e.tokens)},[e.root,e.tokens,e.enabled])}export{c as useKomo,i as useKomoDesignTokens,u as useKomoInspectable};
@@ -0,0 +1 @@
1
+ export declare function reactionPicker(root: ShadowRoot, trigger: HTMLButtonElement, onSelect: (emoji: string) => void, selected?: string, historyKey?: string, emojiDataSource?: string): (immediate?: boolean) => void;
@@ -0,0 +1,23 @@
1
+ export declare const REVIEW_BREAKPOINT = 760;
2
+ export declare const isCompactReview: (width: number, height: number) => boolean;
3
+ export declare function reviewLayout(width: number, height: number, expanded: boolean, pageHeight?: number, account?: boolean): {
4
+ desktop: boolean;
5
+ mobile: boolean;
6
+ framed: boolean;
7
+ sheetTop: number;
8
+ bottom: number;
9
+ scale: number;
10
+ left: number;
11
+ top: number;
12
+ right: number;
13
+ visibleTop: number;
14
+ visibleHeight: number;
15
+ visibleLeft: number;
16
+ visibleWidth: number;
17
+ height: number;
18
+ dockCenter: number;
19
+ };
20
+ export declare function mobileComposerPosition(width: number, height: number, top: number, cardWidth: number, cardHeight: number): {
21
+ x: number;
22
+ y: number;
23
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ import { type KomoConfig } from "./config.js";
2
+ export type { KomoConfig } from "./config.js";
3
+ /** Bind generated public settings once; mount with optional per-site overrides. */
4
+ export declare function defineKomo(config: KomoConfig): (overrides?: Partial<KomoConfig>) => import("./types.js").CommentsController;
package/dist/setup.js ADDED
@@ -0,0 +1 @@
1
+ import{a as o,c as n}from"./chunk-JQVBZ2BB.js";import"./chunk-Q7WSWLMV.js";import"./chunk-Y2GRLW4Q.js";import"./chunk-7YUXYVQA.js";import"./chunk-YZP3KX4Y.js";import"./chunk-I7AUKTXE.js";function r(r){return(s={})=>n(o({...r,...s}))}export{r as defineKomo};
@@ -0,0 +1,15 @@
1
+ import type { KomoShortcuts } from "./types.js";
2
+ export type ShortcutAction = keyof KomoShortcuts;
3
+ export interface Shortcut {
4
+ key: string;
5
+ shift: boolean;
6
+ alt: boolean;
7
+ ctrl: boolean;
8
+ meta: boolean;
9
+ /** Display form, e.g. "Shift+K". */
10
+ label: string;
11
+ }
12
+ /** Resolve configured shortcuts; false disables one. Throws on invalid or duplicate keys. */
13
+ export declare function resolveShortcuts(config?: KomoShortcuts): Record<ShortcutAction, Shortcut | null>;
14
+ export declare function matchesShortcut(event: KeyboardEvent, shortcut: Shortcut | null): boolean;
15
+ export declare function withShortcut(label: string, shortcut: Shortcut | null): string;
@@ -0,0 +1,3 @@
1
+ import { type ReactNode } from "react";
2
+ /** Serialize the pinned, hook-free icon components without mounting React roots. */
3
+ export declare function staticSvg(node: ReactNode): string;
@@ -0,0 +1 @@
1
+ export declare const styles: string;