@hazem3500/komo 0.8.0 → 0.9.1

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 (46) hide show
  1. package/NODE.md +20 -0
  2. package/README.md +64 -0
  3. package/dist/accent-picker-F5UI2NP7.js +1 -0
  4. package/dist/adapters/class-theme.d.ts +22 -0
  5. package/dist/adapters/class-theme.js +1 -0
  6. package/dist/adapters/tailwind.d.ts +62 -0
  7. package/dist/adapters/tailwind.js +1 -0
  8. package/dist/chunk-5LHGJFWQ.js +1 -0
  9. package/dist/chunk-JC6FXUNO.js +1 -0
  10. package/dist/{chunk-RPKLGTEU.js → chunk-Q7WSWLMV.js} +1 -1
  11. package/dist/{chunk-E5X4IQJ2.js → chunk-YZP3KX4Y.js} +1 -1
  12. package/dist/design-comment-RTVUFVDE.js +1 -0
  13. package/dist/design-comment.d.ts +50 -0
  14. package/dist/design-mode-styles.d.ts +1 -1
  15. package/dist/design-mode.d.ts +2 -0
  16. package/dist/design-mode.js +1 -1
  17. package/dist/design-system.d.ts +150 -0
  18. package/dist/design-tokens.d.ts +2 -0
  19. package/dist/dom.d.ts +10 -0
  20. package/dist/index.js +1 -1
  21. package/dist/inline-text-editor-SWPVB35B.js +1 -0
  22. package/dist/inline-text-editor.d.ts +3 -0
  23. package/dist/node.mjs +218 -65
  24. package/dist/{onboarding-YA63RUKK.js → onboarding-NO3RQWR7.js} +1 -1
  25. package/dist/react-inspector.d.ts +9 -1
  26. package/dist/react-props-panel-XQ4T3RLV.js +1 -0
  27. package/dist/react-props-panel.d.ts +3 -1
  28. package/dist/react.js +1 -1
  29. package/dist/review-layout.d.ts +3 -1
  30. package/dist/setup.js +1 -1
  31. package/dist/tag-editor-ZA7NLPOJ.js +1 -0
  32. package/dist/toolbar-runtime-2JO6YXD5.js +1 -0
  33. package/dist/types.d.ts +20 -0
  34. package/package.json +11 -2
  35. package/server/iap.ts +133 -0
  36. package/server/index.ts +108 -17
  37. package/server/secrets.d.ts +6 -0
  38. package/server/setup-client.txt +142 -70
  39. package/src/types.ts +21 -0
  40. package/dist/accent-picker-HSUCA4KE.js +0 -1
  41. package/dist/chunk-Z2ABBESO.js +0 -1
  42. package/dist/chunk-ZUNTYWJF.js +0 -1
  43. package/dist/inline-text-editor-F7B6FQQ3.js +0 -1
  44. package/dist/react-props-panel-XSMDR2CY.js +0 -1
  45. package/dist/tag-editor-VDPZ6CO3.js +0 -1
  46. package/dist/toolbar-runtime-MYOLQPTJ.js +0 -1
@@ -1 +1 @@
1
- import{b as e,c as t}from"./chunk-RPKLGTEU.js";import{d as a,e as n,f as s}from"./chunk-E5X4IQJ2.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};
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};
@@ -39,5 +39,13 @@ export declare function isEditablePropValue(prop: InspectableProp, value: unknow
39
39
  export declare function registerInspectableRoot(element: HTMLElement, definition: InspectableComponent, props: Record<string, unknown>, onChange: (next: Record<string, InspectableScalar>) => void): () => void;
40
40
  /** Refresh a registered root's latest state and callback without replacing its identity. */
41
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. */
42
+ /**
43
+ * The registered React component whose root is exactly this element. Descendants
44
+ * don't inherit the root's props, like layers inside a Figma instance.
45
+ */
43
46
  export declare function inspectableFor(target: Element | null): RegisteredInspectableComponent | null;
47
+ /** The nearest registered component root strictly above `target`, if any. */
48
+ export declare function inspectableAncestor(target: Element | null): {
49
+ root: HTMLElement;
50
+ component: RegisteredInspectableComponent;
51
+ } | null;
@@ -0,0 +1 @@
1
+ import{a as e,d as t,e as n,g as i,h as o,i as a,j as r,k as s,l as d,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,w as x,x as v}from"./chunk-JC6FXUNO.js";import"./chunk-I7AUKTXE.js";var y=new Map,w=new WeakMap,E=new WeakSet,C=new WeakMap;function $(e){return void 0===e?"unset":JSON.stringify(e)??"unset"}var S=new Map;function P(e){if(e)for(let[e,n]of y){let i=t(e);i&&(S.set(e,i.props),i.setProps({...i.props,...Object.fromEntries(n)}))}else for(let[e,n]of S)t(e)?.setProps(n);e||S.clear(),s(e)}function N(e){return!!y.get(e)?.size}function A(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=y.get(e);return r||y.set(e,r=new Map),r.has(i)||r.set(i,a),{propName:i,before:a}}function z(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 M(e,t,n,i){if(n===i){let i=y.get(e);return void(i?.get(t)===n&&!(w.get(e)??[]).some(e=>e.propName===t)&&(i.delete(t),i.size||y.delete(e)))}let o=w.get(e);o||w.set(e,o=[]),o.push({propName:t,before:n,after:i})}function L(e,t,n){z(e,t,n);let i=y.get(e);i?.get(t)===n&&!(w.get(e)??[]).some(e=>e.propName===t)&&(i.delete(t),i.size||y.delete(e))}function T(e){return!!e&&!!w.get(e)?.length}function R(e){let n=y.get(e),o=t(e);if(!n?.size||!o)return;let a=i(e),r=[...n].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}: ${$(t)} → ${$(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 q(e){return[R(e),v(e)].filter(e=>!!e).join("\n\n")||void 0}function D(e,n,i){C.get(e)?.abort();let o=new AbortController;C.set(e,o),e.addEventListener("click",e=>{let o=n();if(!o)return;let a=v(o);!t(o)&&!a||(e.stopImmediatePropagation(),i(o,q(o)))},{capture:!0,signal:o.signal})}function j(e){return b(e)}function O(e){return h(e)}function V(e){k(e)}function B(e){x(e)}function H(e){if(!e||E.has(e))return;let t=document.createElement("style");t.textContent=".design-react-source{display:block;padding:0 0 8px;color:#77736f;font-size:10px;overflow-wrap:anywhere}.design-react-inside{padding:10px 12px}.design-react-inside button{padding:0;border:0;background:none;color:#bda6ef;font:inherit;cursor:pointer}.design-react-inside button:hover{text-decoration:underline}.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}",e.append(t),E.add(e)}function F(e,t,n,a){let r=i(e);if(!r)return null;let s=m(r,t);if(!s.length)return null;H(a);let d=document.createElement("span");d.className="design-token-binding",d.setAttribute("data-mode","custom");let c=document.createElement("span");c.className="design-token-icon",c.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 s){let t=document.createElement("option"),n=o(r,e);t.value=e.path,t.textContent=n?`${e.path} · ${n}`:e.path,k.append(t)}let w=()=>{let n=u(r,e,t),i=n?null:g(r,e,t),o="token"===n?.mode?s.find(e=>e.path===n.tokenPath):void 0,a=o??i?.token;k.value=a?.path??"custom",h.textContent=a?.path??"";let l=n?.declaredPath,p=o?"token":i?"connected":l?"override":"custom";d.dataset.mode=p,d.parentElement?.setAttribute("data-token-mode",p),x.textContent="token"===p?l&&l!==o?.path?`Rebound from ${l} · preview`:`Linked to ${o?.path} · preview`:"connected"===p?"Connected "+("inline"===i?.origin?"inline":"from stylesheet"):"override"===p?`Custom override · was ${l}`:"",k.title=x.textContent||"Choose a token"},E=new MutationObserver(w);E.observe(e,{attributes:!0,attributeFilter:["style"]});let C=new MutationObserver(()=>{d.isConnected||(E.disconnect(),C.disconnect())});return C.observe(d.ownerDocument,{childList:!0,subtree:!0}),k.addEventListener("change",()=>{let i=e.style.getPropertyValue(t),o=s.find(e=>e.path===k.value),a=u(r,e,t);if(o&&a&&o.path===a.declaredPath)f(r,e,t),n(i,e.style.getPropertyValue(t),o.path);else if(o)(o.path!==g(r,e,t)?.token.path||a)&&l(r,e,o,t,{recordHistory:!1})&&n(i,e.style.getPropertyValue(t),o.path);else{let o=d.parentElement?.querySelector("[data-property]")?.value??getComputedStyle(e).getPropertyValue(t).trim(),a=/^-?[\d.]+$/.test(o.trim())&&!/weight|line/.test(t)?`${o.trim()}px`:o;p(r,e,t,a),e.style.setProperty(t,a),n(i,a)}w()}),b.addEventListener("click",()=>{let e=s.find(e=>e.path===k.value),t=d.parentElement?.querySelector("input[data-property]"),n=e&&o(r,e);t&&n&&(t.value="number"===t.type?String(parseFloat(n)):n),k.value="custom",k.dispatchEvent(new Event("change")),d.parentElement?.querySelector("[data-property]")?.focus()}),d.append(h,k,c,b,x),queueMicrotask(w),w(),d}function I(e){let t=i(e);return new Set(t?.elementBindings.get(e)?.keys()??[])}function U(e,t,n,i,o,a,r){for(let s of t){let t=[...n.querySelectorAll("[data-field-property]")].find(e=>e.dataset.fieldProperty===s.property);if(!t||t.querySelector(".design-token-binding"))continue;let d=t.querySelector("[data-property]");if(!d)continue;let l=F(e,s.property,n=>{i(s,d,n),a&&(d.value=a(s,e));let o=t.querySelector('input[type="range"],input[type="color"]');o&&(o.value="color"===s.kind&&r?r(d.value):d.value)},o);l&&t.append(l)}}var W=!1;function _(e,t,n,o){let a=i(e);if(!a||!a.tokens.length)return null;H(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 s=document.createElement("summary");s.textContent="Shared theme";let d=document.createElement("small");d.className="design-react-source",d.textContent="Changes every element using these tokens",r.append(s,d);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,i]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 i)r.append(K(a,o,t,n,e))}return r}function K(e,t,n,i,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} · ${a(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,o,a)=>{let s=null!==a&&r(e,t,a.trim(),g);n.setAttribute("aria-invalid",String(!s)),s&&(g=!0,k(),i())},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 i=o(e,t);m.value=i,h&&(h.value=n.toHex(i)),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",()=>{d(e,t),b(),i()}),b(),l.append(p,f,x),l}function J(e,t,n){let o=i(e);o&&p(o,e,t,n)}function X(e,t){let n=i(e);n&&c(n,e,t)}function G(e){let n=w.get(e)?.pop(),i=t(e);if(!n||!i)return;i.setProps({...i.props,[n.propName]:n.before});let o=y.get(e);if(o){let t=o.get(n.propName);Object.is(t,n.before)&&o.delete(n.propName),o.size||y.delete(e)}}function Q(e){let n=y.get(e),i=t(e);!n?.size||!i||(i.setProps({...i.props,...Object.fromEntries(n)}),y.delete(e),w.delete(e))}function Y(t,n,i,o,a,r){let s=n.definition.props.find(e=>e.name===i);if(!s||!e(s,o))return a.setAttribute("aria-invalid","true"),!1;a.removeAttribute("aria-invalid");let d=n.props[i];if(Object.is(d,o))return!0;let l=y.get(t);l||y.set(t,l=new Map);let p=l.has(i)?l.get(i):d;Object.is(p,o)?l.delete(i):l.set(i,p),l.size||y.delete(t);let c=w.get(t);return c||w.set(t,c=[]),c.push({propName:i,before:d,after:o}),n.setProps({...n.props,[i]:o}),r(),!0}function Z(e,o,a,r){let s=t(e);if(!s)return function(e,t,i){let o=n(e);if(!o)return null;H(i);let a=document.createElement("small");if(a.className="design-react-source design-react-group design-react-inside",a.append(`Inside ${o.component.definition.name}`),t){let e=document.createElement("button");e.type="button",e.textContent="Select component",e.addEventListener("click",()=>t(o.root)),a.append(" · ",e)}return a}(e,r,a);H(a);let d=document.createElement("details");d.className="design-group design-react-group",d.open=!0;let l=document.createElement("summary");l.textContent="Properties",d.append(l);let p=document.createElement("small");p.className="design-react-source",p.textContent=`${s.definition.name} · ${s.definition.source}:${s.definition.line}`,d.append(p);for(let t of s.definition.props){let n=t.styleProperty,a=document.createElement("label");a.className="design-field design-react-field";let r=document.createElement("span");r.textContent=t.name;let l,p=s.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",`${s.definition.name} ${t.name}`),"unsupported"===t.kind)l=document.createElement("input"),l.disabled=!0,l.value=`Read only · ${t.typeLabel}`,l.setAttribute("aria-label",`${s.definition.name} ${t.name}, read only`),a.title=`Komo does not edit ${t.typeLabel} props.`;else{let n=()=>{let n=l instanceof HTMLInputElement&&"checkbox"===l.type?l.checked:l.value,i=n;if("number"===t.kind)i=""===String(n).trim()?void 0:Number(n);else if("enum"===t.kind){let e=(t.values??[]).find(e=>String(e)===n);i=""!==n||t.required?e:void 0}else"boolean"===t.kind&&(i=!0===n);Y(e,s,t.name,i,l,o)};l.addEventListener("change",n)}a.append(r,l);let c=document.createElement("small");if(c.className="design-react-type",c.textContent=`${t.typeLabel}${t.required?" · required":" · optional"}`,a.append(c),a.title||=c.textContent,"string"===t.kind&&n){let r=i(e),d=r?m(r,n):[];if(d.length){let i=document.createElement("span");i.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 d){let t=document.createElement("option");t.value=e.path,t.textContent=e.path,p.append(t)}let u=()=>{let e=d.find(e=>s.props[t.name]===`var(${e.cssVariable})`);p.value=e?.path??"custom",i.dataset.mode=e?"token":"custom"};p.addEventListener("change",()=>{let i=d.find(e=>e.path===p.value),a=i?`var(${i.cssVariable})`:"string"==typeof s.props[t.name]&&String(s.props[t.name]).startsWith("var(")?e.ownerDocument.defaultView?.getComputedStyle(e).getPropertyValue(n).trim()??"":"string"==typeof s.props[t.name]?s.props[t.name]:"";Y(e,s,t.name,a,l,o)&&u()}),i.append(r,p),a.append(i),u()}}d.append(a)}return d}export{U as attachStyleTokenControls,A as beginReactTextEdit,j as canUndoDesignTokenEdit,T as canUndoReactProp,L as cancelReactTextEdit,_ as createDesignThemePanel,F as createElementTokenControl,Z as createReactPropsPanel,M as finishReactTextEdit,O as hasDesignTokenEdit,N as hasReactPropChanges,D as installCommentCapture,J as noteDesignTokenOverride,z as previewReactTextEdit,q as proposedDesignChanges,R as proposedReactChanges,B as resetDesignTokenEdits,Q as resetReactProps,P as showDesignBefore,X as syncDesignTokenBinding,I as tokenBoundProperties,V as undoDesignTokenEdit,G as undoReactProp};
@@ -1,3 +1,5 @@
1
+ /** Before/After for React prop previews and shared theme values. */
2
+ export declare function showDesignBefore(on: boolean): void;
1
3
  export declare function hasReactPropChanges(element: HTMLElement): boolean;
2
4
  export interface ReactTextEditStart {
3
5
  propName: string;
@@ -35,5 +37,5 @@ export declare function noteDesignTokenOverride(element: HTMLElement, property:
35
37
  export declare function syncDesignTokenBinding(element: HTMLElement, property: string): void;
36
38
  export declare function undoReactProp(element: HTMLElement): void;
37
39
  export declare function resetReactProps(element: HTMLElement): void;
38
- export declare function createReactPropsPanel(element: HTMLElement, onEdit: () => void, styleRoot?: ShadowRoot): HTMLElement | null;
40
+ export declare function createReactPropsPanel(element: HTMLElement, onEdit: () => void, styleRoot?: ShadowRoot, select?: (root: HTMLElement) => void): HTMLElement | null;
39
41
  export {};
package/dist/react.js CHANGED
@@ -1 +1 @@
1
- "use client";import{b as e,c as n,e as r}from"./chunk-Z2ABBESO.js";import{b as t}from"./chunk-ZUNTYWJF.js";import"./chunk-RPKLGTEU.js";import"./chunk-Y2GRLW4Q.js";import"./chunk-7YUXYVQA.js";import"./chunk-E5X4IQJ2.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};
1
+ "use client";import{b as e,c as n,f as t}from"./chunk-JC6FXUNO.js";import{b as r}from"./chunk-5LHGJFWQ.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(t=>{if("shortcuts"===t||"features"===t){let r=e[t]??{},o=n[t]??{};return Object.keys({...r,...o}).every(e=>Object.is(r[e],o[e]))}if("design"===t){let t=e.design,r=n.design;if(!t||!r)return t===r;let o=t.themes??[],s=r.themes??[];return t.tokens===r.tokens&&t.components===r.components&&o.length===s.length&&o.every((e,n)=>e===s[n])}if("onboarding"!==t)return Object.is(e[t],n[t]);let r=e.onboarding,o=n.onboarding;return r&&o?Object.keys({...r,...o}).every(e=>"sites"===e?r.sites?.length===o.sites?.length&&(r.sites??[]).every((e,n)=>e===o.sites?.[n]):Object.is(r[e],o[e])):r===o})}(n.current.config,e)||(n.current?.controller.destroy(),n.current=null,!1===e.enabled))return;let t={...e,...e.onboarding?{onboarding:{...e.onboarding,...e.onboarding.sites?{sites:[...e.onboarding.sites]}:{}}}:{}};n.current={config:t,controller:r(t)}}),o(()=>()=>{n.current?.controller.destroy(),n.current=null},[])}function u(t){let r=s(null),c=s(null);return c.current||(c.current=e=>{r.current=e}),o(()=>{if(!0===t.enabled&&r.current)return e(r.current,t.component,t.props,t.onChange)},[t.enabled,t.component]),o(()=>{!0===t.enabled&&n(r.current,t.component,t.props,t.onChange)},[t.enabled,t.component,t.props,t.onChange]),{ref:c.current,"data-komo-inspectable":t.component.id}}function i(e){o(()=>{if(!0!==e.enabled)return;let n=e.root??document.documentElement;return t(n,e.tokens)},[e.root,e.tokens,e.enabled])}export{c as useKomo,i as useKomoDesignTokens,u as useKomoInspectable};
@@ -1,6 +1,8 @@
1
1
  export declare const REVIEW_BREAKPOINT = 760;
2
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): {
3
+ export declare function reviewLayout(width: number, height: number, expanded: boolean, pageHeight?: number, account?: boolean,
4
+ /** Fit the page's full width beside the sidebar instead of letting it run under the left edge. */
5
+ fit?: boolean): {
4
6
  desktop: boolean;
5
7
  mobile: boolean;
6
8
  framed: boolean;
package/dist/setup.js CHANGED
@@ -1 +1 @@
1
- import{a as o,c as n}from"./chunk-ZUNTYWJF.js";import"./chunk-RPKLGTEU.js";import"./chunk-Y2GRLW4Q.js";import"./chunk-7YUXYVQA.js";import"./chunk-E5X4IQJ2.js";import"./chunk-I7AUKTXE.js";function r(r){return(s={})=>n(o({...r,...s}))}export{r as defineKomo};
1
+ import{a as o,c as n}from"./chunk-5LHGJFWQ.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 @@
1
+ import"./chunk-I7AUKTXE.js";var t=12,e=/^[\p{L}\p{N}][\p{L}\p{N} ._-]{0,31}$/u;function n(t){let n=t.trim().replace(/^#/,"").toLocaleLowerCase("en-US");return e.test(n)?n:null}function a(t,e){let a=[...e.tags],o=!1,i=!1,r=(...e)=>{i=!0,t.replaceChildren(...e),i=!1},l=`komo-tags-${Math.random().toString(36).slice(2)}`,d=null,p=0,s=()=>{cancelAnimationFrame(p),d?.remove(),d=null};!function c(g=!1){s();let u=document.createElement("style");u.textContent='\n.tag-row { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; min-width: 0; min-height: 24px; font-size: 12px; }\n.tag-row .tag-chip {\n display: inline-flex; align-items: center; gap: 2px; max-width: 160px; height: 22px; padding: 0 2px 0 7px;\n border-radius: 6px; font-weight: 500; line-height: 1; color: var(--accent, #bda6ef);\n background: color-mix(in srgb, var(--accent, #bda6ef) 14%, transparent);\n}\n.tag-row .tag-chip span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.tag-row .tag-chip button, .tag-row .tag-add {\n display: inline-flex; align-items: center; border: 0; padding: 0; color: inherit; background: none; cursor: pointer; font-family: inherit;\n}\n.tag-row .tag-chip button { justify-content: center; width: 18px; height: 18px; border-radius: 4px; opacity: .6; }\n.tag-row .tag-chip button:hover, .tag-row .tag-chip button:focus-visible { opacity: 1; background: color-mix(in srgb, currentColor 16%, transparent); }\n.tag-row .tag-add {\n gap: 4px; height: 22px; padding: 0 6px; border-radius: 6px; font-size: 12px; color: #858585;\n transition: color var(--duration-quick, 150ms), background var(--duration-quick, 150ms);\n}\n.tag-row .tag-add:hover, .tag-row .tag-add:focus-visible { color: #eee; background: #ffffff0d; }\n.tag-row .tag-input {\n width: 96px; height: 24px; padding: 0 8px; border: 0; border-radius: 6px; outline: none;\n font-family: inherit; font-size: 12px; color: #eee; background: #ffffff07; box-shadow: inset 0 0 0 1px #ffffff05;\n}\n.tag-row .tag-input::placeholder { color: #858585; }\n.tag-row .tag-input:focus { box-shadow: inset 0 0 0 1px #ffffff20; }\n.tag-row .tag-input[aria-invalid="true"] { box-shadow: inset 0 0 0 1px #f28b8299; }\n/* A floating menu attached to komo\'s root, so no container can clip it. */\n.tag-options {\n position: fixed; z-index: 40; display: grid; gap: 1px; width: 220px; max-height: 220px; overflow: auto;\n padding: 4px; border-radius: 10px; background: #2a2a2a; box-shadow: 0 0 0 1px #ffffff14, 0 12px 32px #0007;\n font-size: 12px;\n}\n.tag-options:empty { display: none; }\n.tag-option {\n display: flex; align-items: center; gap: 6px; min-height: 28px; padding: 0 8px; border-radius: 6px;\n color: #ddd; cursor: pointer; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;\n}\n.tag-option[aria-selected="true"] { background: #ffffff14; color: #fff; }\n.tag-option-hint, .tag-option-empty { color: #858585; }\n.tag-option-empty { padding: 6px 8px; }\n/* The tag row grows when the picker opens, instead of spilling over the text above it. */\n.new-comment-composer .draft-body:has(.tag-slot) { grid-template-rows: minmax(28px, auto) minmax(28px, auto); }\n.new-comment-composer .draft-body .tag-slot { grid-row: 2; grid-column: 2; align-self: start; min-width: 0; padding-top: 2px; }\n.new-comment-composer .draft-body:has(.tag-slot) .send { align-self: start; }\n.new-comment-composer .draft-body:not(:has(.avatar)) .tag-slot { grid-column: 1; }\n/* Line up with message text: 16px gutter plus the 24px avatar and 8px gap. */\n.thread-tags { padding: 8px 16px 12px 48px; }\n';let f=document.createElement("div");f.className="tag-row",f.setAttribute("role","group"),f.setAttribute("aria-label","Tags");for(let t of a){let n=document.createElement("span");n.className="tag-chip";let o=document.createElement("span");o.textContent=`#${t}`;let i=document.createElement("button");i.type="button",i.textContent="×",i.setAttribute("aria-label",`Remove tag ${t}`),i.addEventListener("click",()=>{a=a.filter(e=>e!==t),e.onRemove(t),c()}),n.append(o,i),f.append(n)}if(o){let m=document.createElement("input");m.className="tag-input",m.placeholder="Add tag…",m.maxLength=33,m.autocomplete="off",m.setAttribute("role","combobox"),m.setAttribute("aria-label","Add tag"),m.setAttribute("aria-autocomplete","list"),m.setAttribute("aria-controls",l);let x=document.createElement("div");x.className="tag-options",x.id=l,x.setAttribute("role","listbox"),x.setAttribute("aria-label","Tags");let h=[],b=-1,w=t=>{!a.includes(t)&&a.length<12&&(a=[...a,t].sort(),e.onAdd(t)),o=a.length<12,c(o)},v=t=>{b=t,x.querySelectorAll("[role=option]").forEach((e,n)=>{e.setAttribute("aria-selected",String(n===t)),n===t&&e.scrollIntoView?.({block:"nearest"})}),t>=0?m.setAttribute("aria-activedescendant",`${l}-${t}`):m.removeAttribute("aria-activedescendant")},y=()=>{let t=m.value.trim().replace(/^#/,"").toLocaleLowerCase("en-US"),o=n(m.value),i=e.suggestions.filter(t=>!a.includes(t));h=(t?[...i.filter(e=>e.startsWith(t)),...i.filter(e=>!e.startsWith(t)&&e.includes(t))]:i).map(t=>({tag:t,create:!1})),o&&!a.includes(o)&&!i.includes(o)&&h.push({tag:o,create:!0}),x.replaceChildren(...h.map(({tag:t,create:e},n)=>{let a=document.createElement("div");return a.id=`${l}-${n}`,a.className="tag-option",a.setAttribute("role","option"),e&&a.append(Object.assign(document.createElement("span"),{className:"tag-option-hint",textContent:"Create"})),a.append(Object.assign(document.createElement("span"),{textContent:`#${t}`})),a.addEventListener("pointerdown",t=>t.preventDefault()),a.addEventListener("click",()=>w(t)),a.addEventListener("pointermove",()=>v(n)),a})),h.length||x.append(Object.assign(document.createElement("div"),{className:"tag-option-empty",textContent:t?a.includes(o??"")?"Already added":"Use letters, numbers, spaces, . _ or -":"Type to create a tag"})),m.setAttribute("aria-expanded",String(h.length>0)),v(t&&h.length?0:-1)};m.addEventListener("input",y),m.addEventListener("keydown",t=>{if(t.stopPropagation(),!t.isComposing)if("ArrowDown"===t.key||"ArrowUp"===t.key){if(t.preventDefault(),!h.length)return;let e=h.length-1;v("ArrowDown"===t.key?b>=e?0:b+1:b<=0?e:b-1)}else if("Enter"===t.key||","===t.key)if(t.preventDefault(),b>=0&&h[b])w(h[b].tag);else if(m.value.trim()){let t=n(m.value);t?w(t):m.setAttribute("aria-invalid","true")}else o=!1,c();else if("Escape"===t.key)t.preventDefault(),o=!1,c();else if("Backspace"===t.key&&!m.value&&a.length){let t=a.at(-1);a=a.slice(0,-1),e.onRemove(t),c(!0)}}),m.addEventListener("input",()=>m.removeAttribute("aria-invalid")),m.addEventListener("blur",()=>{i||!m.isConnected||!o||(o=!1,c())}),f.append(m),r(u,f);let A=t.getRootNode();(A instanceof ShadowRoot?A:document.body).append(x),d=x;let k=()=>{if(!m.isConnected)return s();let t=m.getBoundingClientRect(),e=x.offsetHeight,n=window.innerHeight-t.bottom-8,a=e+4<=n||t.top-8<n?t.bottom+4:t.top-4-e;x.style.top=`${Math.max(8,a)}px`,x.style.left=`${Math.max(8,Math.min(t.left,window.innerWidth-x.offsetWidth-8))}px`,p=requestAnimationFrame(k)};return y(),k(),void((g||o)&&m.focus({preventScroll:!0}))}if(a.length<12){let t=document.createElement("button");t.type="button",t.className="tag-add",t.textContent=a.length?"+":"+ Add tag",t.setAttribute("aria-label","Add tag"),t.addEventListener("click",()=>{o=!0,c(!0)}),f.append(t)}r(u,f)}()}export{t as MAX_TAGS,n as normalizeTag,a as tagEditor};
@@ -0,0 +1 @@
1
+ import{$ as t,A as e,B as n,C as r,D as i,E as o,F as s,G as a,H as l,I as u,J as c,K as d,L as h,M as m,N as p,O as f,P as g,Q as v,R as y,S as x,T as w,U as E,V as P,W as S,X as b,Y as C,Z as M,_ as k,a as T,aa as A,b as L,ba as D,c as I,ca as j,da as V,ea as R,fa as _,ga as O,ha as W,ia as N,j as B,ja as F,k as H,ka as U,l as $,m as G,n as Y,o as X,p as z,q,r as K,s as Z,t as J,u as Q,v as tt,w as et,x as nt,y as rt,z as it}from"./chunk-7YUXYVQA.js";import{c as ot,g as st,k as at}from"./chunk-YZP3KX4Y.js";import{a as lt}from"./chunk-I7AUKTXE.js";import{createRoot as ut}from"react-dom/client";import{flushSync as ct}from"react-dom";import{createElement as dt}from"react";import*as ht from"react";var mt=({size:t=24,color:e="currentColor",...n})=>ht.createElement("svg",{viewBox:"0 0 24 24",width:t,height:t,stroke:e,strokeWidth:"2",fill:"none",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",...n},ht.createElement("path",{d:"m7 15 5 5 5-5M7 9l5-5 5 5"}));mt.displayName="ChevronSelectorVertical";import*as pt from"react";var ft=({size:t=24,color:e="currentColor",...n})=>pt.createElement("svg",{viewBox:"0 0 24 24",width:t,height:t,stroke:e,strokeWidth:"2",fill:"none",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",...n},pt.createElement("path",{d:"M18 6 6 18M6 6l12 12"}));ft.displayName="XClose";import*as gt from"react";var vt=({size:t=24,color:e="currentColor",...n})=>gt.createElement("svg",{viewBox:"0 0 24 24",width:t,height:t,stroke:e,strokeWidth:"2",fill:"none",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",...n},gt.createElement("path",{d:"M19 12H5m0 0 7 7m-7-7 7-7"}));vt.displayName="ArrowLeft";import*as yt from"react";var xt=({size:t=24,color:e="currentColor",...n})=>yt.createElement("svg",{viewBox:"0 0 24 24",width:t,height:t,stroke:e,strokeWidth:"2",fill:"none",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",...n},yt.createElement("path",{d:"m9 18 6-6-6-6"}));xt.displayName="ChevronRight";import{useEffect as wt,useId as Et,useLayoutEffect as Pt,useRef as St,useState as bt}from"react";import{createContext as Ct}from"react";var Mt=Ct({});import{useRef as kt}from"react";import{useLayoutEffect as Tt,useEffect as At}from"react";var Lt=typeof window<"u"?Tt:At;import{createContext as Dt}from"react";var It=Dt(null);import{createContext as jt}from"react";var Vt=jt({transformPagePoint:t=>t,isStatic:!1,reducedMotion:"never"});import{useContext as Rt,useId as _t,useEffect as Ot,useCallback as Wt}from"react";import{createContext as Nt}from"react";var Bt=Nt({strict:!1}),Ft={animation:["animate","variants","whileHover","whileTap","exit","whileInView","whileFocus","whileDrag"],exit:["exit"],drag:["drag","dragControls"],focus:["whileFocus"],hover:["whileHover","onHoverStart","onHoverEnd"],tap:["whileTap","onTap","onTapStart","onTapCancel"],pan:["onPan","onPanStart","onPanSessionStart","onPanEnd"],inView:["whileInView","onViewportEnter","onViewportLeave"],layout:["layout","layoutId"]},Ht=!1;function Ut(){return function(){if(Ht)return;let t={};for(let e in Ft)t[e]={isEnabled:t=>Ft[e].some(e=>!!t[e])};v(t),Ht=!0}(),y()}var $t=new Set(["animate","exit","variants","initial","style","values","variants","transition","transformTemplate","custom","inherit","onBeforeLayoutMeasure","onAnimationStart","onAnimationComplete","onUpdate","onDragStart","onDrag","onDragEnd","onMeasureDragConstraints","onDirectionLock","onDragTransitionEnd","_dragX","_dragY","onHoverStart","onHoverEnd","onViewportEnter","onViewportLeave","globalTapTarget","propagate","ignoreStrict","viewport"]);function Gt(t){return t.startsWith("while")||t.startsWith("drag")&&"draggable"!==t||t.startsWith("layout")||t.startsWith("onTap")||t.startsWith("onPan")||t.startsWith("onLayout")||$t.has(t)}var Yt,Xt=t=>!Gt(t);try{"function"==typeof(Yt=lt("@emotion/is-prop-valid").default)&&(Xt=t=>t.startsWith("on")?!Gt(t):Yt(t))}catch{}import{jsxs as zt,jsx as qt}from"react/jsx-runtime";import{forwardRef as Kt,useContext as Zt}from"react";import{createContext as Jt}from"react";var Qt=Jt({});import{useContext as te,useMemo as ee}from"react";function ne(t){let{initial:e,animate:n}=function(t,e){if(h(t)){let{initial:e,animate:n}=t;return{initial:!1===e||d(e)?e:void 0,animate:d(n)?n:void 0}}return!1!==t.inherit?e:{}}(t,te(Qt));return ee(()=>({initial:e,animate:n}),[re(e),re(n)])}function re(t){return Array.isArray(t)?t.join(" "):t}import{Fragment as ie,useMemo as oe,createElement as se}from"react";import{useMemo as ae}from"react";var le=()=>({style:{},transform:{},transformOrigin:{},vars:{}});function ue(t,e,n){for(let r in e)!rt(e[r])&&!b(r,n)&&(t[r]=e[r])}function ce(t,e){let n={};return ue(n,t.style||{},t),Object.assign(n,function({transformTemplate:t},e){return ae(()=>{let n={style:{},transform:{},transformOrigin:{},vars:{}};return S(n,e,t),Object.assign({},n.vars,n.style)},[e])}(t,e)),n}function de(t,e){let n={},r=ce(t,e);return t.drag&&!1!==t.dragListener&&(n.draggable=!1,r.userSelect=r.WebkitUserSelect=r.WebkitTouchCallout="none",r.touchAction=!0===t.drag?"none":"pan-"+("x"===t.drag?"y":"x")),void 0===t.tabIndex&&(t.onTap||t.onTapStart||t.whileTap)&&(n.tabIndex=0),n.style=r,n}import{useMemo as he}from"react";var me=()=>({style:{},transform:{},transformOrigin:{},vars:{},attrs:{}});function pe(e,n,r,i){let o=he(()=>{let r={style:{},transform:{},transformOrigin:{},vars:{},attrs:{}};return k(r,n,t(i),e.transformTemplate,e.style),{...r.attrs,style:{...r.style}}},[n]);if(e.style){let t={};ue(t,e.style,e),o.style={...t,...o.style}}return o}var fe=["animate","circle","defs","desc","ellipse","g","image","line","filter","marker","mask","metadata","path","pattern","polygon","polyline","rect","stop","switch","symbol","svg","text","tspan","use","view"];function ge(t){return"string"==typeof t&&!t.includes("-")&&!!(fe.indexOf(t)>-1||/[A-Z]/u.test(t))}function ve(t,e,n,{latestValues:r},i,o=!1,s){let a=(s??ge(t)?pe:de)(e,r,i,t),l=function(t,e,n){let r={};for(let i in t)"values"===i&&"object"==typeof t.values||rt(t[i])||(Xt(i)||!0===n&&Gt(i)||!e&&!Gt(i)||t.draggable&&i.startsWith("onDrag"))&&(r[i]=t[i]);return r}(e,"string"==typeof t,o),u=t!==ie?{...l,...a,ref:n}:{},{children:c}=e,d=oe(()=>rt(c)?c.get():c,[c]);return se(t,{...u,children:d})}import{useContext as ye}from"react";function xe(t,e,n,r){let i={},o=r(t,{});for(let t in o)i[t]=O(o[t]);let{initial:s,animate:a}=t,l=h(t),u=m(t);e&&u&&!l&&!1!==t.inherit&&(void 0===s&&(s=e.initial),void 0===a&&(a=e.animate));let d=!!n&&!1===n.initial;d=d||!1===s;let p=d?a:s;if(p&&"boolean"!=typeof p&&!c(p)){let e=Array.isArray(p)?p:[p];for(let n=0;n<e.length;n++){let r=et(t,e[n]);if(r){let{transitionEnd:t,transition:e,...n}=r;for(let t in n){let e=n[t];if(Array.isArray(e)){e=e[d?e.length-1:0]}null!==e&&(i[t]=e)}for(let e in t)i[e]=t[e]}}}return i}var we=t=>(e,n)=>{let r=ye(Qt),i=ye(It),o=()=>function({scrapeMotionValuesFromProps:t,createRenderState:e},n,r,i){return{latestValues:xe(n,r,i,t),renderState:e()}}(t,e,r,i);return n?o():function(t){let e=kt(null);return null===e.current&&(e.current=t()),e.current}(o)},Ee=we({scrapeMotionValuesFromProps:C,createRenderState:le}),Pe=we({scrapeMotionValuesFromProps:A,createRenderState:me}),Se=Symbol.for("motionComponentSymbol");import{useRef as be,useInsertionEffect as Ce,useCallback as Me}from"react";function ke(t,e,n){let r=be(n);Ce(()=>{r.current=n});let i=be(null);return Me(n=>{n&&t.onMount?.(n),e&&(n?e.mount(n):e.unmount());let o=r.current;if("function"==typeof o)if(n){let t=o(n);"function"==typeof t&&(i.current=t)}else i.current?(i.current(),i.current=null):o(n);else o&&(o.current=n)},[e])}import{useContext as Te,useRef as Ae,useInsertionEffect as Le,useEffect as De}from"react";import{createContext as Ie}from"react";var je=Ie({});function Ve(t){return t&&"object"==typeof t&&Object.prototype.hasOwnProperty.call(t,"current")}function Re(t,n,r,i,o,s){let{visualElement:a}=Te(Qt),l=Te(Bt),u=Te(It),c=Te(Vt),d=c.reducedMotion,h=c.skipAnimations,m=Ae(null),p=Ae(!1);i=i||l.renderer,!m.current&&i&&(m.current=i(t,{visualState:n,parent:a,props:r,presenceContext:u,blockInitialAnimation:!!u&&!1===u.initial,reducedMotionConfig:d,skipAnimations:h,isSVG:s}),p.current&&m.current&&(m.current.manuallyAnimateOnMount=!0));let f=m.current,g=Te(je);f&&!f.projection&&o&&("html"===f.type||"svg"===f.type)&&function(t,e,n,r){let{layoutId:i,layout:o,drag:s,dragConstraints:a,layoutScroll:l,layoutRoot:u,layoutAnchor:c,layoutCrossfade:d}=e;t.projection=new n(t.latestValues,e["data-framer-portal-id"]?void 0:_e(t.parent)),t.projection.setOptions({layoutId:i,layout:o,alwaysMeasureLayout:!!s||a&&Ve(a),visualElement:t,animationType:"string"==typeof o?o:"both",initialPromotionConfig:r,crossfade:d,layoutScroll:l,layoutRoot:u,layoutAnchor:c})}(m.current,r,o,g);let v=Ae(!1);Le(()=>{f&&v.current&&f.update(r,u)});let y=r[e],x=Ae(!!y&&typeof window<"u"&&!window.MotionHandoffIsComplete?.(y)&&window.MotionHasOptimisedAnimation?.(y));return Lt(()=>{p.current=!0,f&&(v.current=!0,window.MotionIsMounted=!0,f.updateFeatures(),f.scheduleRenderMicrotask(),x.current&&f.animationState&&f.animationState.animateChanges())}),De(()=>{f&&(!x.current&&f.animationState&&f.animationState.animateChanges(),x.current&&(queueMicrotask(()=>{window.MotionHandoffMarkAsComplete?.(y)}),x.current=!1),f.enteringChildren=void 0)}),f}function _e(t){if(t)return!1!==t.options.allowProjection?t.projection:_e(t.parent)}function Oe(t,{forwardMotionProps:e=!1,type:n}={},r,i){r&&function(t){let e=Ut();for(let n in t)e[n]={...e[n],...t[n]};v(e)}(r);let o=n?"svg"===n:ge(t),s=o?Pe:Ee;function a(n,r){let a,l={...Zt(Vt),...n,layoutId:We(n)},{isStatic:u}=l,c=ne(n),d=s(n,u);if(!u&&typeof window<"u"){Zt(Bt).strict;let e=function(t){let e=Ut(),{drag:n,layout:r}=e;if(!n&&!r)return{};let i={...n,...r};return{MeasureLayout:n?.isEnabled(t)||r?.isEnabled(t)?i.MeasureLayout:void 0,ProjectionNode:i.ProjectionNode}}(l);a=e.MeasureLayout,c.visualElement=Re(t,d,l,i,e.ProjectionNode,o)}return zt(Qt.Provider,{value:c,children:[a&&c.visualElement?qt(a,{visualElement:c.visualElement,...l}):null,ve(t,n,ke(d,c.visualElement,r),d,u,e,o)]})}a.displayName=`motion.${"string"==typeof t?t:`create(${t.displayName??t.name??""})`}`;let l=Kt(a);return l[Se]=t,l}function We({layoutId:t}){let e=Zt(Mt).id;return e&&void 0!==t?e+"-"+t:t}import{Fragment as Ne}from"react";var Be=0,Fe={animation:{Feature:class extends x{constructor(t){super(t),t.animationState||(t.animationState=j(t))}updateAnimationControlsSubscription(){let{animate:t}=this.node.getProps();c(t)&&(this.unmountControls=t.subscribe(this.node))}mount(){this.updateAnimationControlsSubscription()}update(){let{animate:t}=this.node.getProps(),{animate:e}=this.node.prevProps||{};t!==e&&this.updateAnimationControlsSubscription()}unmount(){this.node.animationState.reset(),this.unmountControls?.()}}},exit:{Feature:class extends x{constructor(){super(...arguments),this.id=Be++,this.isExitComplete=!1}update(){if(!this.node.presenceContext)return;let{isPresent:t,onExitComplete:e}=this.node.presenceContext,{isPresent:n}=this.node.prevPresenceContext||{};if(!this.node.animationState||t===n)return;if(t&&!1===n){if(this.isExitComplete){let{initial:t,custom:e}=this.node.getProps();if("string"==typeof t||"object"==typeof t&&null!==t&&!Array.isArray(t)){let n=nt(this.node,t,e);if(n){let{transition:t,transitionEnd:e,...r}=n;for(let t in r)this.node.getValue(t)?.jump(r[t])}}this.node.animationState.reset(),this.node.animationState.animateChanges()}else this.node.animationState.setActive("exit",!1);return void(this.isExitComplete=!1)}let r=this.node.animationState.setActive("exit",!t);e&&!t&&r.then(()=>{this.isExitComplete=!0,e(this.id)})}mount(){let{register:t,onExitComplete:e}=this.node.presenceContext||{};e&&e(this.id),t&&(this.unmount=t(this.id))}unmount(){}}}};function He(t){return{point:{x:t.pageX,y:t.pageY}}}function Ue(t,e,n,r){return _(t,e,(t=>e=>o(e)&&t(e,He(e)))(n),r)}var $e=({current:t})=>t?t.ownerDocument.defaultView:null,Ge=new Set(["auto","scroll"]),Ye=class{constructor(t,e,{transformPagePoint:n,contextWindow:r=window,dragSnapToOrigin:i=!1,distanceThreshold:s=3,element:a}={}){if(this.startEvent=null,this.lastMoveEvent=null,this.lastMoveEventInfo=null,this.lastRawMoveEventInfo=null,this.handlers={},this.contextWindow=window,this.scrollPositions=new Map,this.removeScrollListeners=null,this.onElementScroll=t=>{this.handleScroll(t.target)},this.onWindowScroll=()=>{this.handleScroll(window)},this.updatePoint=()=>{if(!this.lastMoveEvent||!this.lastMoveEventInfo)return;this.lastRawMoveEventInfo&&(this.lastMoveEventInfo=Xe(this.lastRawMoveEventInfo,this.transformPagePoint));let t=qe(this.lastMoveEventInfo,this.history),e=null!==this.startEvent,n=U(t.offset,{x:0,y:0})>=this.distanceThreshold;if(!e&&!n)return;let{point:r}=t,{timestamp:i}=Z;this.history.push({...r,timestamp:i});let{onStart:o,onMove:s}=this.handlers;e||(o&&o(this.lastMoveEvent,t),this.startEvent=this.lastMoveEvent),s&&s(this.lastMoveEvent,t)},this.handlePointerMove=(t,e)=>{this.lastMoveEvent=t,this.lastRawMoveEventInfo=e,this.lastMoveEventInfo=Xe(e,this.transformPagePoint),q.update(this.updatePoint,!0)},this.handlePointerUp=(t,e)=>{this.end();let{onEnd:n,onSessionEnd:r,resumeAnimation:i}=this.handlers;if((this.dragSnapToOrigin||!this.startEvent)&&i&&i(),!this.lastMoveEvent||!this.lastMoveEventInfo)return;let o=qe("pointercancel"===t.type?this.lastMoveEventInfo:Xe(e,this.transformPagePoint),this.history);this.startEvent&&n&&n(t,o),r&&r(t,o)},!o(t))return;this.dragSnapToOrigin=i,this.handlers=e,this.transformPagePoint=n,this.distanceThreshold=s,this.contextWindow=r||window;let l=Xe(He(t),this.transformPagePoint),{point:u}=l,{timestamp:c}=Z;this.history=[{...u,timestamp:c}];let{onSessionStart:d}=e;d&&d(t,qe(l,this.history));let h={passive:!0,capture:!0};this.removeListeners=G(Ue(this.contextWindow,"pointermove",this.handlePointerMove,h),Ue(this.contextWindow,"pointerup",this.handlePointerUp,h),Ue(this.contextWindow,"pointercancel",this.handlePointerUp,h)),a&&this.startScrollTracking(a)}startScrollTracking(t){let e=t.parentElement;for(;e;){let t=getComputedStyle(e);(Ge.has(t.overflowX)||Ge.has(t.overflowY))&&this.scrollPositions.set(e,{x:e.scrollLeft,y:e.scrollTop}),e=e.parentElement}this.scrollPositions.set(window,{x:window.scrollX,y:window.scrollY}),window.addEventListener("scroll",this.onElementScroll,{capture:!0}),window.addEventListener("scroll",this.onWindowScroll),this.removeScrollListeners=()=>{window.removeEventListener("scroll",this.onElementScroll,{capture:!0}),window.removeEventListener("scroll",this.onWindowScroll)}}handleScroll(t){let e=this.scrollPositions.get(t);if(!e)return;let n=t===window,r=n?{x:window.scrollX,y:window.scrollY}:{x:t.scrollLeft,y:t.scrollTop},i=r.x-e.x,o=r.y-e.y;0===i&&0===o||(n?this.lastMoveEventInfo&&(this.lastMoveEventInfo.point.x+=i,this.lastMoveEventInfo.point.y+=o):this.history.length>0&&(this.history[0].x-=i,this.history[0].y-=o),this.scrollPositions.set(t,r),q.update(this.updatePoint,!0))}updateHandlers(t){this.handlers=t}end(){this.removeListeners&&this.removeListeners(),this.removeScrollListeners&&this.removeScrollListeners(),this.scrollPositions.clear(),K(this.updatePoint)}};function Xe(t,e){return e?{point:e(t.point)}:t}function ze(t,e){return{x:t.x-e.x,y:t.y-e.y}}function qe({point:t},e){return{point:t,delta:ze(t,Ze(e)),offset:ze(t,Ke(e)),velocity:Je(e,.1)}}function Ke(t){return t[0]}function Ze(t){return t[t.length-1]}function Je(t,e){if(t.length<2)return{x:0,y:0};let n=t.length-1,r=null,i=Ze(t);for(;n>=0&&(r=t[n],!(i.timestamp-r.timestamp>X(e)));)n--;if(!r)return{x:0,y:0};r===t[0]&&t.length>2&&i.timestamp-r.timestamp>2*X(e)&&(r=t[1]);let o=z(i.timestamp-r.timestamp);if(0===o)return{x:0,y:0};let s={x:(i.x-r.x)/o,y:(i.y-r.y)/o};return s.x===1/0&&(s.x=0),s.y===1/0&&(s.y=0),s}function Qe(t,e,n){return{min:void 0!==e?t.min+e:void 0,max:void 0!==n?t.max+n-(t.max-t.min):void 0}}function tn(t,e){let n=e.min-t.min,r=e.max-t.max;return e.max-e.min<t.max-t.min&&([n,r]=[r,n]),{min:n,max:r}}var en=.35;function nn(t,e,n){return{min:rn(t,e),max:rn(t,n)}}function rn(t,e){return"number"==typeof t?t:t[e]||0}var on=new WeakMap,sn=class{constructor(t){this.openDragLock=null,this.isDragging=!1,this.currentDirection=null,this.originPoint={x:0,y:0},this.constraints=!1,this.hasMutatedConstraints=!1,this.elastic=u(),this.latestPointerEvent=null,this.latestPanInfo=null,this.visualElement=t}start(t,{snapToCursor:e=!1,distanceThreshold:n}={}){let{presenceContext:i}=this.visualElement;if(i&&!1===i.isPresent)return;let{dragSnapToOrigin:o}=this.getProps();this.panSession=new Ye(t,{onSessionStart:t=>{e&&this.snapToCursor(He(t).point),this.stopAnimation()},onStart:(t,e)=>{let{drag:n,dragPropagation:i,onDragStart:o}=this.getProps();if(n&&!i&&(this.openDragLock&&this.openDragLock(),this.openDragLock=r(n),!this.openDragLock))return;this.latestPointerEvent=t,this.latestPanInfo=e,this.isDragging=!0,this.currentDirection=null,this.resolveConstraints(),this.visualElement.projection&&(this.visualElement.projection.isAnimationBlocked=!0,this.visualElement.projection.target=void 0),R(t=>{let e=this.getAxisMotionValue(t).get()||0;if(J.test(e)){let{projection:n}=this.visualElement;if(n&&n.layout){let r=n.layout.layoutBox[t];r&&(e=V(r)*(parseFloat(e)/100))}}this.originPoint[t]=e}),o&&q.update(()=>o(t,e),!1,!0),it(this.visualElement,"transform");let{animationState:s}=this.visualElement;s&&s.setActive("whileDrag",!0)},onMove:(t,e)=>{this.latestPointerEvent=t,this.latestPanInfo=e;let{dragPropagation:n,dragDirectionLock:r,onDirectionLock:i,onDrag:o}=this.getProps();if(!n&&!this.openDragLock)return;let{offset:s}=e;if(r&&null===this.currentDirection)return this.currentDirection=function(t,e=10){let n=null;return Math.abs(t.y)>e?n="y":Math.abs(t.x)>e&&(n="x"),n}(s),void(null!==this.currentDirection&&i&&i(this.currentDirection));this.updateAxis("x",e.point,s),this.updateAxis("y",e.point,s),this.visualElement.render(),o&&q.update(()=>o(t,e),!1,!0)},onSessionEnd:(t,e)=>{this.latestPointerEvent=t,this.latestPanInfo=e,this.stop(t,e),this.latestPointerEvent=null,this.latestPanInfo=null},resumeAnimation:()=>{let{dragSnapToOrigin:t}=this.getProps();(t||this.constraints)&&this.startAnimation({x:0,y:0})}},{transformPagePoint:this.visualElement.getTransformPagePoint(),dragSnapToOrigin:o,distanceThreshold:n,contextWindow:$e(this.visualElement),element:this.visualElement.current})}stop(t,e){let n=t||this.latestPointerEvent,r=e||this.latestPanInfo,i=this.isDragging;if(this.cancel(),!i||!r||!n)return;let{velocity:o}=r;this.startAnimation(o);let{onDragEnd:s}=this.getProps();s&&q.postRender(()=>s(n,r))}cancel(){this.isDragging=!1;let{projection:t,animationState:e}=this.visualElement;t&&(t.isAnimationBlocked=!1),this.endPanSession();let{dragPropagation:n}=this.getProps();!n&&this.openDragLock&&(this.openDragLock(),this.openDragLock=null),e&&e.setActive("whileDrag",!1)}endPanSession(){this.panSession&&this.panSession.end(),this.panSession=void 0}updateAxis(t,e,n){let{drag:r}=this.getProps();if(!n||!ln(t,r,this.currentDirection))return;let i=this.getAxisMotionValue(t),o=this.originPoint[t]+n[t];this.constraints&&this.constraints[t]&&(o=function(t,{min:e,max:n},r){return void 0!==e&&t<e?t=r?Q(e,t,r.min):Math.max(t,e):void 0!==n&&t>n&&(t=r?Q(n,t,r.max):Math.min(t,n)),t}(o,this.constraints[t],this.elastic[t])),i.set(o)}resolveConstraints(){let{dragConstraints:t,dragElastic:e}=this.getProps(),n=this.visualElement.projection&&!this.visualElement.projection.layout?this.visualElement.projection.measure(!1):this.visualElement.projection?.layout,r=this.constraints;t&&Ve(t)?this.constraints||(this.constraints=this.resolveRefConstraints()):this.constraints=!(!t||!n)&&function(t,{top:e,left:n,bottom:r,right:i}){return{x:Qe(t.x,n,i),y:Qe(t.y,e,r)}}(n.layoutBox,t),this.elastic=function(t=en){return!1===t?t=0:!0===t&&(t=en),{x:nn(t,"left","right"),y:nn(t,"top","bottom")}}(e),r!==this.constraints&&!Ve(t)&&n&&this.constraints&&!this.hasMutatedConstraints&&R(t=>{!1!==this.constraints&&this.getAxisMotionValue(t)&&(this.constraints[t]=function(t,e){let n={};return void 0!==e.min&&(n.min=e.min-t.min),void 0!==e.max&&(n.max=e.max-t.min),n}(n.layoutBox[t],this.constraints[t]))})}resolveRefConstraints(){let{dragConstraints:t,onMeasureDragConstraints:e}=this.getProps();if(!t||!Ve(t))return!1;let n=t.current;H(null!==n,"If `dragConstraints` is set as a React ref, that ref must be passed to another component's `ref` prop.","drag-constraints-ref");let{projection:r}=this.visualElement;if(!r||!r.layout)return!1;r.root&&(r.root.scroll=void 0,r.root.updateScroll());let i=P(n,r.root,this.visualElement.getTransformPagePoint()),o=function(t,e){return{x:tn(t.x,e.x),y:tn(t.y,e.y)}}(r.layout.layoutBox,i);if(e){let t=e(E(o));this.hasMutatedConstraints=!!t,t&&(o=w(t))}return o}startAnimation(t){let{drag:e,dragMomentum:n,dragElastic:r,dragTransition:i,dragSnapToOrigin:o,onDragTransitionEnd:s}=this.getProps(),a=this.constraints||{},l=R(s=>{if(!ln(s,e,this.currentDirection))return;let l=a&&a[s]||{};(!0===o||o===s)&&(l={min:0,max:0});let u=r?200:1e6,c=r?40:1e7,d={type:"inertia",velocity:n?t[s]:0,bounceStiffness:u,bounceDamping:c,timeConstant:750,restDelta:1,restSpeed:10,...i,...l};return this.startAxisValueAnimation(s,d)});return Promise.all(l).then(s)}startAxisValueAnimation(t,e){let n=this.getAxisMotionValue(t);return it(this.visualElement,t),n.start(tt(t,n,0,e,this.visualElement,!1))}stopAnimation(){R(t=>this.getAxisMotionValue(t).stop())}getAxisMotionValue(t){let e=`_drag${t.toUpperCase()}`;return this.visualElement.getProps()[e]||this.visualElement.getValue(t,this.visualElement.latestValues[t]??0)}snapToCursor(t){R(e=>{let{drag:n}=this.getProps();if(!ln(e,n,this.currentDirection))return;let{projection:r}=this.visualElement,i=this.getAxisMotionValue(e);if(r&&r.layout){let{min:n,max:o}=r.layout.layoutBox[e],s=i.get()||0;i.set(t[e]-Q(n,o,.5)+s)}})}scalePositionWithinConstraints(){if(!this.visualElement.current)return;let{drag:t,dragConstraints:e}=this.getProps(),{projection:n}=this.visualElement;if(!Ve(e)||!n||!this.constraints)return;this.stopAnimation();let r={x:0,y:0};R(t=>{let e=this.getAxisMotionValue(t);if(e&&!1!==this.constraints){let n=e.get();r[t]=function(t,e){let n=.5,r=V(t),i=V(e);return i>r?n=Y(e.min,e.max-r,t.min):r>i&&(n=Y(t.min,t.max-i,e.min)),B(0,1,n)}({min:n,max:n},this.constraints[t])}});let{transformTemplate:i}=this.visualElement.getProps();this.visualElement.current.style.transform=i?i({},""):"none",n.root&&n.root.updateScroll(),n.updateLayout(),this.constraints=!1,this.resolveConstraints(),R(e=>{if(!ln(e,t,null))return;let n=this.getAxisMotionValue(e),{min:i,max:o}=this.constraints[e];n.set(Q(i,o,r[e]))}),this.visualElement.render()}addListeners(){if(!this.visualElement.current)return;on.set(this.visualElement,this);let t,e=this.visualElement.current,n=Ue(e,"pointerdown",t=>{let{drag:n,dragListener:r=!0}=this.getProps(),i=t.target,o=i!==e&&s(i);n&&r&&!o&&this.start(t)}),r=()=>{let{dragConstraints:n}=this.getProps();Ve(n)&&n.current&&(this.constraints=this.resolveRefConstraints(),t||(t=function(t,e,n){let r=l(t,an(n)),i=l(e,an(n));return()=>{r(),i()}}(e,n.current,()=>this.scalePositionWithinConstraints())))},{projection:i}=this.visualElement,o=i.addEventListener("measure",r);i&&!i.layout&&(i.root&&i.root.updateScroll(),i.updateLayout()),q.read(r);let a=_(window,"resize",()=>this.scalePositionWithinConstraints()),u=i.addEventListener("didUpdate",({delta:t,hasLayoutChanged:e})=>{this.isDragging&&e&&(R(e=>{let n=this.getAxisMotionValue(e);n&&(this.originPoint[e]+=t[e].translate,n.set(n.get()+t[e].translate))}),this.visualElement.render())});return()=>{a(),n(),o(),u&&u(),t&&t()}}getProps(){let t=this.visualElement.getProps(),{drag:e=!1,dragDirectionLock:n=!1,dragPropagation:r=!1,dragConstraints:i=!1,dragElastic:o=en,dragMomentum:s=!0}=t;return{...t,drag:e,dragDirectionLock:n,dragPropagation:r,dragConstraints:i,dragElastic:o,dragMomentum:s}}};function an(t){let e=!0;return()=>{e?e=!1:t()}}function ln(t,e,n){return!(!0!==e&&e!==t||null!==n&&n!==t)}var un=t=>(e,n)=>{t&&q.update(()=>t(e,n),!1,!0)};import{jsx as cn}from"react/jsx-runtime";import{useContext as dn,Component as hn}from"react";var mn=!1,pn=class extends hn{componentDidMount(){let{visualElement:t,layoutGroup:e,switchLayoutGroup:n,layoutId:r}=this.props,{projection:i}=t;i&&(e.group&&e.group.add(i),n&&n.register&&r&&n.register(i),mn&&i.root.didUpdate(),i.addEventListener("animationComplete",()=>{this.safeToRemove()}),i.setOptions({...i.options,layoutDependency:this.props.layoutDependency,onExitComplete:()=>this.safeToRemove()})),W.hasEverUpdated=!0}getSnapshotBeforeUpdate(t){let{layoutDependency:e,visualElement:n,drag:r,isPresent:i}=this.props,{projection:o}=n;return o&&(o.isPresent=i,t.layoutDependency!==e&&o.setOptions({...o.options,layoutDependency:e}),mn=!0,r||t.layoutDependency!==e||void 0===e||t.isPresent!==i?o.willUpdate():this.safeToRemove(),t.isPresent!==i&&(i?o.promote():o.relegate()||q.postRender(()=>{let t=o.getStack();(!t||!t.members.length)&&this.safeToRemove()}))),null}componentDidUpdate(){let{visualElement:t,layoutAnchor:e}=this.props,{projection:r}=t;r&&(r.options.layoutAnchor=e,r.root.didUpdate(),n.postRender(()=>{!r.currentAnimation&&r.isLead()&&this.safeToRemove()}))}componentWillUnmount(){let{visualElement:t,layoutGroup:e,switchLayoutGroup:n}=this.props,{projection:r}=t;mn=!0,r&&(r.scheduleCheckAfterUnmount(),e&&e.group&&e.group.remove(r),n&&n.deregister&&n.deregister(r))}safeToRemove(){let{safeToRemove:t}=this.props;t&&t()}render(){return null}};function fn(t){let[e,n]=function(t=!0){let e=Rt(It);if(null===e)return[!0,null];let{isPresent:n,onExitComplete:r,register:i}=e,o=_t();Ot(()=>{if(t)return i(o)},[t]);let s=Wt(()=>t&&r&&r(o),[o,r,t]);return!n&&r?[!1,s]:[!0]}(),r=dn(Mt);return cn(pn,{...t,layoutGroup:r,switchLayoutGroup:dn(je),isPresent:e,safeToRemove:n})}var gn={pan:{Feature:class extends x{constructor(){super(...arguments),this.removePointerDownListener=$}onPointerDown(t){this.session=new Ye(t,this.createPanHandlers(),{transformPagePoint:this.node.getTransformPagePoint(),contextWindow:$e(this.node)})}createPanHandlers(){let{onPanSessionStart:t,onPanStart:e,onPan:n,onPanEnd:r}=this.node.getProps();return{onSessionStart:un(t),onStart:un(e),onMove:un(n),onEnd:(t,e)=>{delete this.session,r&&q.postRender(()=>r(t,e))}}}mount(){this.removePointerDownListener=Ue(this.node.current,"pointerdown",t=>this.onPointerDown(t))}update(){this.session&&this.session.updateHandlers(this.createPanHandlers())}unmount(){this.removePointerDownListener(),this.session&&this.session.end()}}},drag:{Feature:class extends x{constructor(t){super(t),this.removeGroupControls=$,this.removeListeners=$,this.controls=new sn(t)}mount(){let{dragControls:t}=this.node.getProps();t&&(this.removeGroupControls=t.subscribe(this.controls)),this.removeListeners=this.controls.addListeners()||$}update(){let{dragControls:t}=this.node.getProps(),{dragControls:e}=this.node.prevProps||{};t!==e&&(this.removeGroupControls(),t&&(this.removeGroupControls=t.subscribe(this.controls)))}unmount(){this.removeGroupControls(),this.removeListeners(),this.controls.isDragging||this.controls.endPanSession()}},ProjectionNode:N,MeasureLayout:fn}};function vn(t,e,n){let{props:r}=t;t.animationState&&r.whileHover&&t.animationState.setActive("whileHover","Start"===n);let i=r["onHover"+n];i&&q.postRender(()=>i(e,He(e)))}function yn(t,e,n){let{props:r}=t;if(t.current instanceof HTMLButtonElement&&t.current.disabled)return;t.animationState&&r.whileTap&&t.animationState.setActive("whileTap","Start"===n);let i=r["onTap"+("End"===n?"":n)];i&&q.postRender(()=>i(e,He(e)))}var xn=new WeakMap,wn=new WeakMap,En=t=>{let e=xn.get(t.target);e&&e(t)},Pn=t=>{t.forEach(En)};function Sn(t,e,n){let r=function({root:t,...e}){let n=t||document;wn.has(n)||wn.set(n,{});let r=wn.get(n),i=JSON.stringify(e);return r[i]||(r[i]=new IntersectionObserver(Pn,{root:t,...e})),r[i]}(e);return xn.set(t,n),r.observe(t),()=>{xn.delete(t),r.unobserve(t)}}var bn={some:0,all:1};var Cn={inView:{Feature:class extends x{constructor(){super(...arguments),this.hasEnteredView=!1,this.isInView=!1}startObserver(){this.stopObserver?.();let{viewport:t={}}=this.node.getProps(),{root:e,margin:n,amount:r="some",once:i}=t,o={root:e?e.current:void 0,rootMargin:n,threshold:"number"==typeof r?r:bn[r]};this.stopObserver=Sn(this.node.current,o,t=>{let{isIntersecting:e}=t;if(this.isInView===e||(this.isInView=e,i&&!e&&this.hasEnteredView))return;e&&(this.hasEnteredView=!0),this.node.animationState&&this.node.animationState.setActive("whileInView",e);let{onViewportEnter:n,onViewportLeave:r}=this.node.getProps(),o=e?n:r;o&&o(t)})}mount(){this.startObserver()}update(){if(typeof IntersectionObserver>"u")return;let{props:t,prevProps:e}=this.node;["amount","margin","root"].some(function({viewport:t={}},{viewport:e={}}={}){return n=>t[n]!==e[n]}(t,e))&&this.startObserver()}unmount(){this.stopObserver?.(),this.hasEnteredView=!1,this.isInView=!1}}},tap:{Feature:class extends x{mount(){let{current:t}=this.node;if(!t)return;let{globalTapTarget:e,propagate:n}=this.node.props;this.unmount=a(t,(t,e)=>(yn(this.node,e,"Start"),(t,{success:e})=>yn(this.node,t,e?"End":"Cancel")),{useGlobalTarget:e,stopPropagation:!1===n?.tap})}unmount(){}}},focus:{Feature:class extends x{constructor(){super(...arguments),this.isActive=!1}onFocus(){let t=!1;try{t=this.node.current.matches(":focus-visible")}catch{t=!0}!t||!this.node.animationState||(this.node.animationState.setActive("whileFocus",!0),this.isActive=!0)}onBlur(){!this.isActive||!this.node.animationState||(this.node.animationState.setActive("whileFocus",!1),this.isActive=!1)}mount(){this.unmount=G(_(this.node.current,"focus",()=>this.onFocus()),_(this.node.current,"blur",()=>this.onBlur()))}unmount(){}}},hover:{Feature:class extends x{mount(){let{current:t}=this.node;t&&(this.unmount=i(t,(t,e)=>(vn(this.node,e,"Start"),t=>vn(this.node,t,"End"))))}unmount(){}}}},Mn=function(t,e){if(typeof Proxy>"u")return Oe;let n=new Map,r=(n,r)=>Oe(n,r,t,e);return new Proxy((t,e)=>r(t,e),{get:(i,o)=>"create"===o?r:(n.has(o)||n.set(o,Oe(o,void 0,t,e)),n.get(o))})}({...Fe,...Cn,...gn,...{layout:{ProjectionNode:N,MeasureLayout:fn}}},(t,e)=>e.isSVG??ge(t)?new D(e):new M(e,{allowProjection:t!==Ne}));import{useState as kn}from"react";var Tn=Mn;import{Fragment as An,jsx as Ln,jsxs as Dn}from"react/jsx-runtime";function In({items:t,defaultActiveId:e,activeId:n,edge:r="bottom",alignEnd:i=!1,onActiveChange:o,label:s="App navigation",moreLabel:a="More",backLabel:l="Back",className:u="",style:c}){let d=Et(),[h,m]=bt({kind:"collapsed"}),[v,y]=bt(e??t[0]?.id),[x,w]=bt(null),E=St(null),P=St(null),S=St(r),b="left"===r||"right"===r;Pt(()=>{let t=P.current;if(!t||!x)return;let e=0,n=0,r=document.documentElement.clientWidth,i=window.innerHeight;for(let o=t.parentNode;o instanceof Element&&o!==document.body;o=o.parentNode instanceof ShadowRoot?o.parentNode.host:o.parentNode){let t=getComputedStyle(o),s=o.getBoundingClientRect();"visible"!==t.overflowX&&(e=Math.max(e,s.left),r=Math.min(r,s.right)),"visible"!==t.overflowY&&(n=Math.max(n,s.top),i=Math.min(i,s.bottom))}t.style.maxWidth=`${Math.max(0,r-e-16)}px`,t.style.left=`${x.x}px`,t.style.top=`${x.y}px`;let o=t.getBoundingClientRect(),s=Math.max(e+8-o.left,Math.min(0,r-8-o.right)),a=Math.max(n+8-o.top,Math.min(0,i-8-o.bottom));t.style.left=`${x.x+s}px`,t.style.top=`${x.y+a}px`},[x]);let C=St(null),M=St(null),k=St(h),A=St("more"),D=St(!1),j=St(!1),V=St(!1),R=St(null),_=St(void 0),O=St(void 0),W=St(!1),N=St(!1),B=function(){!f.current&&g();let[t]=kn(p.current);return t}(),H=n??v,U="collapsed"!==h.kind,$=t.filter(t=>!1!==t.showInBar),G=$.find(t=>"dismiss"===t.id),Y=$.filter(t=>"dismiss"!==t.id),X=t.filter(t=>t.children?.length);function z(){clearTimeout(_.current),w(null)}function q(){z(),clearTimeout(O.current),W.current=!1}function K(t,e,n=!1){clearTimeout(_.current);let i=E.current,o=M.current;if(!i||!o||U||j.current||V.current&&!n)return;let s=i.getBoundingClientRect(),a=t.getBoundingClientRect(),l={label:e,x:"left"===r?s.width+8:"right"===r?-8:a.left-s.left+a.width/2,y:"top"===r?s.height+8:"bottom"===r?-8:a.top-s.top+a.height/2};clearTimeout(O.current);let u=()=>{W.current=!0,w(l)};n||W.current?u():_.current=setTimeout(u,400)}function Z(t,e,n){q(),U||(A.current=e,D.current=n),R.current="first",m(t)}function J(t=!0,e=A.current){q(),V.current=!0,R.current=t&&D.current?e:null,m({kind:"collapsed"})}function Q(){"group"===h.kind&&(R.current=h.id,m({kind:"main"}))}function tt(t,e){let n=!!t.children?.length,r=H===t.id||!!t.children?.some(t=>t.id===H),i=!e&&t.keepOpenOnSelect,s=(e,n=!1)=>Ln(Vn,{label:t.label,icon:n,reduced:!!B,children:e}),a=r&&t.activeIcon?t.activeIcon:t.icon,l=Dn(An,{children:[Ln("span",{className:"morphing-menu__icon","aria-hidden":"true",style:i?{display:"grid"}:void 0,children:i?s(a,!0):a}),!e&&Ln("span",{className:"morphing-menu__label",style:i?{display:"grid"}:void 0,children:i?s(t.label):t.label}),!e&&n&&Ln(jn,{})]}),u={className:e?"morphing-menu__shortcut":"morphing-menu__row","data-menu-item":t.id,"aria-label":t.label,"aria-current":r?n?"true":"page":void 0,"aria-expanded":n?"group"===h.kind&&h.id===t.id:void 0,"aria-controls":n?`${d}-group-${t.id}`:void 0,onClick:e=>n?Z({kind:"group",id:t.id},t.id,0===e.detail):function(t){y(t.id),o?.(t.id),U&&!t.keepOpenOnSelect?J(!0,"group"===h.kind?h.id:t.id):q(),t.onSelect?.()}(t),onPointerEnter:n=>{e&&"mouse"===n.pointerType&&K(n.currentTarget,t.label)},onPointerLeave:z,onPointerDown:q,onFocus:n=>{e&&n.currentTarget.matches(":focus-visible")&&K(n.currentTarget,t.label,!0)},onBlur:z};return t.href&&!n?Ln("a",{href:t.href,...u,children:l},t.id):Ln(Tn.button,{layout:!!e&&"position",transition:B?{duration:0}:T,type:"button",...u,children:l},t.id)}Pt(()=>{let t=E.current,e=C.current,n=M.current;if(!t||!e||!n)return;let i=S.current!==r;S.current=r;let o=k.current;k.current=h;let s=[...t.querySelectorAll(".morphing-menu__panel")],a=s.find(t=>"false"===t.getAttribute("aria-hidden")),l=[],u=!1,c=t=>(l.push(t),t),d=()=>({width:a?.offsetWidth??n.offsetWidth,height:a?.offsetHeight??n.offsetHeight}),p=i||o.kind!==h.kind||"group"===o.kind&&"group"===h.kind&&o.id!==h.id,f="collapsed"===o.kind!=("collapsed"===h.kind),g=B||!p;if(g)(()=>{let t=d();e.style.width=`${t.width}px`,e.style.height=`${t.height}px`})();else if(f&&!U)c(F(e,d(),I));else if(f){let t=Math.min(n.offsetWidth,n.offsetWidth>250?280:200);c(F(e,{width:t,height:n.offsetHeight>52?32:28},L)).finished.then(()=>{u||c(F(e,d(),{...T,bounce:U?.24:.15}))}).catch(()=>{})}else c(F(e,d(),{...T,duration:.25,bounce:.1}));c(F(n,{opacity:U?0:1,scale:U&&!B?.8:1,filter:U&&!B?"blur(8px)":"blur(0px)"},{duration:g?0:U?.15:.22,delay:g||U?0:.08,...U?{}:{ease:"easeOut"}}));for(let t of s){let e=t===a;for(let[n,r]of[...t.querySelectorAll(".morphing-menu__row")].entries())e&&f&&!g&&Object.assign(r.style,{opacity:"0",transform:"translateY(48px)",filter:"blur(4px)"}),c(F(r,{opacity:e?1:0,y:e||B?0:16,filter:e||B?"blur(0px)":"blur(2px)"},{...T,duration:g?0:e?f?.4:.25:.12,bounce:f?.3:0,delay:!g&&e?(f?.2:0)+.02*n:0}))}let v=[...(U?a:n)?.querySelectorAll("[data-menu-item]")??[]],y=R.current;R.current=null,y&&(j.current=!0,(("first"===y?v[0]:v.find(t=>t.dataset.menuItem===y))??(U?void 0:v.find(t=>"more"===t.dataset.menuItem)))?.focus({preventScroll:!0}),j.current=!1);let x=()=>m(t=>({...t}));return window.addEventListener("resize",x),()=>{u=!0,l.forEach(t=>t.stop()),window.removeEventListener("resize",x)}},[h,B,r,t.length,$.length]),wt(()=>{if(!U)return;let t=new AbortController;return st(E.current,"pointerdown",t=>{t.target instanceof Node&&!t.composedPath().includes(E.current)&&J(!1)},{signal:t.signal}),()=>t.abort()},[U]),wt(()=>()=>{clearTimeout(_.current),clearTimeout(O.current)},[]);let et=Dn("button",{type:"button",className:"morphing-menu__row","data-menu-item":"close",onClick:()=>J(!0,"more"),children:[Ln(ft,{"aria-hidden":"true"}),Ln("span",{className:"morphing-menu__label",children:"Close drawer"})]});return Dn("nav",{ref:E,"aria-label":s,className:["morphing-menu",u].filter(Boolean).join(" "),"data-view":h.kind,"data-edge":r,"data-vertical":b,"data-align-end":i,style:{"--mm-count":$.length+1,...c},onPointerMove:t=>{if(!V.current||"mouse"!==t.pointerType||!t.movementX&&!t.movementY)return;V.current=!1;let e=t.target instanceof Element?t.target.closest(".morphing-menu__shortcut"):null;e&&K(e,e.getAttribute("aria-label")??"")},onKeyDown:t=>{"Escape"===t.key&&(V.current=!0,q(),U&&(t.preventDefault(),t.stopPropagation(),"group"===h.kind?Q():J()))},onBlur:t=>{t.relatedTarget instanceof Node&&t.currentTarget.contains(t.relatedTarget)||(U?t.relatedTarget instanceof Node&&J(!1):N.current||q())},children:[Dn("div",{ref:C,className:"morphing-menu__shell",children:[Dn("div",{ref:M,className:"morphing-menu__bar","aria-hidden":U,inert:U,onPointerEnter:t=>{"mouse"===t.pointerType&&(N.current=!0,clearTimeout(O.current))},onPointerLeave:t=>{"mouse"===t.pointerType&&(N.current=!1,z(),clearTimeout(O.current),O.current=setTimeout(()=>{W.current=!1},300))},children:[Y.map(t=>tt(t,!0)),Ln(Tn.button,{layout:"position",transition:B?{duration:0}:T,type:"button",className:"morphing-menu__shortcut","data-menu-item":"more","aria-label":a,"aria-expanded":U,"aria-controls":`${d}-main`,onClick:t=>Z({kind:"main"},"more",0===t.detail),onPointerEnter:t=>{"mouse"===t.pointerType&&K(t.currentTarget,a)},onPointerLeave:z,onPointerDown:q,onBlur:z,onFocus:t=>{t.currentTarget.matches(":focus-visible")&&K(t.currentTarget,a,!0)},children:Ln(mt,{"aria-hidden":"true"})}),G&&tt(G,!0)]}),Dn("div",{id:`${d}-main`,className:"morphing-menu__panel","aria-hidden":"main"!==h.kind,inert:"main"!==h.kind,children:[[...t].sort((t,e)=>(t.expandedOrder??0)-(e.expandedOrder??0)).map(t=>tt(t,!1)),et]}),X.map(t=>{let e="group"===h.kind&&h.id===t.id;return Dn("div",{id:`${d}-group-${t.id}`,className:"morphing-menu__panel","aria-label":t.label,"aria-hidden":!e,inert:!e,children:[Dn("button",{type:"button",className:"morphing-menu__row","data-menu-item":"back",onClick:Q,children:[Ln(vt,{"aria-hidden":"true"}),Ln("span",{children:l})]}),t.children.map(t=>tt(t,!1)),et]},t.id)})]}),x&&!U&&Ln("div",{ref:P,className:"morphing-menu__tooltip","aria-hidden":"true",style:{left:x.x,top:x.y},children:x.label})]})}function jn(){return Ln(xt,{className:"morphing-menu__chevron","aria-hidden":"true"})}function Vn({label:t,icon:e,reduced:n,children:r}){let i=St(null),o=St(null);return Pt(()=>{let r=i.current,s=o.current;if(o.current={label:t,node:r.cloneNode(!0)},!s||s.label===t||n)return;let a=s.node;a.setAttribute("aria-hidden","true"),r.parentElement.append(a);let l={duration:200,easing:"cubic-bezier(.22,1,.36,1)"},u=r.animate([{opacity:0,transform:e?"scale(.7)":"translateY(4px)",filter:"blur(2px)"},{opacity:1,transform:"none",filter:"blur(0px)"}],l),c=a.animate([{opacity:1,transform:"none",filter:"blur(0px)"},{opacity:0,transform:e?"scale(.7)":"translateY(-4px)",filter:"blur(2px)"}],l);return c.finished.then(()=>a.remove()).catch(()=>{}),()=>{u.cancel(),c.cancel(),a.remove()}},[t,e,n]),Ln("span",{ref:i,style:{gridArea:"1 / 1",display:"flex",alignItems:"center"},children:r})}function Rn(t){return"glyph"in t?dt("span",{style:{display:"contents"},dangerouslySetInnerHTML:{__html:ot[t.glyph]}}):dt("span",{className:"review-avatar"},t.user?.avatarUrl?dt("img",{src:t.user.avatarUrl,alt:"",referrerPolicy:"no-referrer"}):t.user?at(t.user.name):Rn({glyph:"person"}))}var _n=t=>dt(In,{...t,items:t.items.map(t=>({...t,icon:Rn(t.icon)}))});function On(t,e){t.replaceChildren();let n=ut(t);return ct(()=>n.render(_n(e))),{render:t=>n.render(_n(t)),unmount:()=>n.unmount()}}export{On as mountToolbar};
package/dist/types.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import type { DesignSystem } from "./design-system.js";
2
+ export type * from "./design-system.js";
1
3
  export interface Identity {
2
4
  id: string;
3
5
  name: string;
@@ -115,6 +117,24 @@ export interface CommentsOptions {
115
117
  drawerContainer?: HTMLElement;
116
118
  /** Mounted content root for Frame. Defaults to a sole body content element; otherwise Floating only. */
117
119
  pageRoot?: HTMLElement;
120
+ /**
121
+ * Roots, besides pageRoot, whose elements can be picked for comments and
122
+ * Design mode, such as a portal container. Defaults to all of body except
123
+ * komo, so body-level dialogs and popovers are pickable. Return [] to limit
124
+ * picking to pageRoot. Called on every pick; keep it cheap.
125
+ */
126
+ pickRoots?: () => Element[];
127
+ /**
128
+ * Stop komo's own pointer, focus, wheel and typing events at its host
129
+ * element, so page shortcuts and open modals don't react to komo's UI.
130
+ * Defaults to true; set false if the host needs to observe them.
131
+ */
132
+ isolateEvents?: boolean;
133
+ /**
134
+ * Design-system adapters for Design mode: tokens, theme axes, and component
135
+ * identity. All optional; see DesignSystem.
136
+ */
137
+ design?: DesignSystem;
118
138
  /** Resolve an anchor to a repository-relative source path. */
119
139
  source?: (element: Element) => string | undefined;
120
140
  /** Defaults to GitHub's source viewer. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hazem3500/komo",
3
- "version": "0.8.0",
3
+ "version": "0.9.1",
4
4
  "description": "Point, area, and threaded comments for website branches.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -27,7 +27,8 @@
27
27
  "server/node-webhooks.ts",
28
28
  "server/import-project.ts",
29
29
  "server/digest.ts",
30
- "server/project-sites.ts"
30
+ "server/project-sites.ts",
31
+ "server/iap.ts"
31
32
  ],
32
33
  "main": "./dist/index.js",
33
34
  "types": "./dist/index.d.ts",
@@ -45,6 +46,14 @@
45
46
  "types": "./dist/react.d.ts",
46
47
  "import": "./dist/react.js"
47
48
  },
49
+ "./adapters/tailwind": {
50
+ "types": "./dist/adapters/tailwind.d.ts",
51
+ "import": "./dist/adapters/tailwind.js"
52
+ },
53
+ "./adapters/class-theme": {
54
+ "types": "./dist/adapters/class-theme.d.ts",
55
+ "import": "./dist/adapters/class-theme.js"
56
+ },
48
57
  "./node": {
49
58
  "import": "./dist/node.mjs"
50
59
  }
package/server/iap.ts ADDED
@@ -0,0 +1,133 @@
1
+ // Google Cloud Identity-Aware Proxy (IAP) sign-in. When KOMO_IAP_AUDIENCE names
2
+ // the IAP-protected backend (/projects/<number>/global/backendServices/<id>),
3
+ // the load balancer routes the sign-in paths through IAP. Sessions are minted
4
+ // from IAP's signed identity instead of a Google OAuth client, and reading
5
+ // comments requires one of those sessions.
6
+ import { check, HttpError } from "./validation";
7
+
8
+ const KEYS_URL = "https://www.gstatic.com/iap/verify/public_key-jwk";
9
+ const ISSUER = "https://cloud.google.com/iap";
10
+ let cached: { keys: Map<string, CryptoKey>; expires: number } | undefined;
11
+
12
+ async function keys(refresh = false) {
13
+ if (!refresh && cached && cached.expires > Date.now()) return cached.keys;
14
+ const response = await fetch(KEYS_URL);
15
+ check(response.ok, 503, "Could not verify sign-in. Try again shortly.");
16
+ const { keys: list } = (await response.json()) as {
17
+ keys?: (JsonWebKey & { kid?: string })[];
18
+ };
19
+ const imported = new Map<string, CryptoKey>();
20
+ for (const { kid, ...key } of list ?? [])
21
+ if (kid && key.kty === "EC" && key.crv === "P-256")
22
+ imported.set(
23
+ kid,
24
+ await crypto.subtle.importKey(
25
+ "jwk",
26
+ key,
27
+ { name: "ECDSA", namedCurve: "P-256" },
28
+ false,
29
+ ["verify"],
30
+ ),
31
+ );
32
+ cached = { keys: imported, expires: Date.now() + 3600000 };
33
+ return imported;
34
+ }
35
+
36
+ const decode = (part: string) =>
37
+ Uint8Array.from(atob(part.replace(/-/g, "+").replace(/_/g, "/")), (c) =>
38
+ c.charCodeAt(0),
39
+ );
40
+
41
+ export type IapIdentity = { id: string; email: string };
42
+
43
+ /** Verify IAP's signed header and return the Google account it vouches for. */
44
+ export async function iapIdentity(
45
+ request: Request,
46
+ audience: string,
47
+ ): Promise<IapIdentity> {
48
+ const jwt = request.headers.get("x-goog-iap-jwt-assertion") ?? "";
49
+ const [head, payload, signature, extra] = jwt.split(".");
50
+ check(
51
+ head && payload && signature && extra === undefined,
52
+ 401,
53
+ "Sign in with your Google account.",
54
+ );
55
+ let header: { alg?: unknown; kid?: unknown };
56
+ let claims: Record<string, unknown>;
57
+ try {
58
+ header = JSON.parse(new TextDecoder().decode(decode(head)));
59
+ claims = JSON.parse(new TextDecoder().decode(decode(payload)));
60
+ } catch {
61
+ throw new HttpError(401, "Invalid sign-in.");
62
+ }
63
+ check(
64
+ header.alg === "ES256" && typeof header.kid === "string",
65
+ 401,
66
+ "Invalid sign-in.",
67
+ );
68
+ const kid = header.kid;
69
+ // IAP rotates keys; refetch once before rejecting an unknown key id.
70
+ const key = (await keys()).get(kid) ?? (await keys(true)).get(kid);
71
+ check(key, 401, "Invalid sign-in.");
72
+ const valid = await crypto.subtle.verify(
73
+ { name: "ECDSA", hash: "SHA-256" },
74
+ key,
75
+ decode(signature),
76
+ new TextEncoder().encode(`${head}.${payload}`),
77
+ );
78
+ const now = Date.now() / 1000;
79
+ check(
80
+ valid &&
81
+ claims.iss === ISSUER &&
82
+ claims.aud === audience &&
83
+ typeof claims.exp === "number" &&
84
+ claims.exp > now &&
85
+ typeof claims.iat === "number" &&
86
+ claims.iat < now + 60,
87
+ 401,
88
+ "Invalid sign-in.",
89
+ );
90
+ // IAP's subject is the same numeric Google account id the OAuth flow stores.
91
+ const sub =
92
+ typeof claims.sub === "string"
93
+ ? claims.sub.match(/^accounts\.google\.com:(\d{1,40})$/)?.[1]
94
+ : undefined;
95
+ check(
96
+ sub &&
97
+ typeof claims.email === "string" &&
98
+ claims.email.length <= 254 &&
99
+ claims.email.includes("@"),
100
+ 401,
101
+ "Invalid sign-in.",
102
+ );
103
+ return { id: `google:${sub}`, email: claims.email.toLowerCase() };
104
+ }
105
+
106
+ /** Path prefix for IAP sign-in handlers, e.g. "/backoffice"; "" when unset. */
107
+ export function authPrefix(value: string | undefined): string {
108
+ if (!value) return "";
109
+ const prefix = value.replace(/\/+$/, "");
110
+ if (!/^(\/[A-Za-z0-9._~-]+)+$/.test(prefix))
111
+ throw new Error("KOMO_AUTH_PREFIX must be a path such as /backoffice");
112
+ return prefix;
113
+ }
114
+
115
+ /** Split PUBLIC_URL into its origin and an optional path the app is served under. */
116
+ export function publicLocation(value: string): { origin: string; path: string } {
117
+ const url = new URL(value);
118
+ const path = url.pathname.replace(/\/+$/, "");
119
+ if (
120
+ url.search ||
121
+ url.hash ||
122
+ url.username ||
123
+ url.password ||
124
+ (path && !/^(\/[A-Za-z0-9._~-]+)+$/.test(path)) ||
125
+ `${url.origin}${path}` !== value.replace(/\/+$/, "") ||
126
+ (url.protocol !== "https:" &&
127
+ !["localhost", "127.0.0.1"].includes(url.hostname))
128
+ )
129
+ throw new Error(
130
+ "PUBLIC_URL must be an HTTPS origin, optionally with a path such as https://example.com/komo (localhost allowed for development)",
131
+ );
132
+ return { origin: url.origin, path };
133
+ }