@hazem3500/komo 0.0.0-stage → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/LICENSE +21 -0
  2. package/NODE.md +80 -0
  3. package/NOTICE.md +45 -0
  4. package/README.md +411 -2
  5. package/cli/agent.mjs +615 -0
  6. package/cli/config.mjs +34 -0
  7. package/cli/index.mjs +405 -0
  8. package/cli/project.mjs +136 -0
  9. package/cli/workflow.mjs +42 -0
  10. package/dist/MorphingMenu.d.ts +30 -0
  11. package/dist/PointerIcon.d.ts +2 -0
  12. package/dist/SmileIcon.d.ts +2 -0
  13. package/dist/THIRD_PARTY_NOTICES.txt +387 -0
  14. package/dist/accent-picker-F5UI2NP7.js +1 -0
  15. package/dist/accent-picker.d.ts +4 -0
  16. package/dist/accent.d.ts +2 -0
  17. package/dist/account-usage.d.ts +2 -0
  18. package/dist/action-menu.d.ts +10 -0
  19. package/dist/agent-prompt.d.ts +6 -0
  20. package/dist/agent-prompt.js +1 -0
  21. package/dist/anchors.d.ts +48 -0
  22. package/dist/api.d.ts +39 -0
  23. package/dist/approved-sites.d.ts +9 -0
  24. package/dist/card-motion.d.ts +8 -0
  25. package/dist/chunk-7YUXYVQA.js +1 -0
  26. package/dist/chunk-I7AUKTXE.js +1 -0
  27. package/dist/chunk-JQVBZ2BB.js +1 -0
  28. package/dist/chunk-Q7WSWLMV.js +1 -0
  29. package/dist/chunk-Y2GRLW4Q.js +1 -0
  30. package/dist/chunk-YZP3KX4Y.js +1 -0
  31. package/dist/chunk-Z2ABBESO.js +1 -0
  32. package/dist/config.d.ts +11 -0
  33. package/dist/connect-project.d.ts +14 -0
  34. package/dist/connection-issue.d.ts +7 -0
  35. package/dist/design-comment-QPTW66JO.js +1 -0
  36. package/dist/design-comment.d.ts +42 -0
  37. package/dist/design-export-BRBI7S3V.js +1 -0
  38. package/dist/design-export.d.ts +8 -0
  39. package/dist/design-mode-styles.d.ts +1 -0
  40. package/dist/design-mode.d.ts +19 -0
  41. package/dist/design-mode.js +1 -0
  42. package/dist/design-panel-BPVXFERR.js +1 -0
  43. package/dist/design-panel-styles.d.ts +1 -0
  44. package/dist/design-panel.d.ts +33 -0
  45. package/dist/design-tokens.d.ts +76 -0
  46. package/dist/dom.d.ts +20 -0
  47. package/dist/drawer-expand-motion.d.ts +46 -0
  48. package/dist/drawer-presence.d.ts +4 -0
  49. package/dist/edge-sidebar.d.ts +39 -0
  50. package/dist/emoji-history.d.ts +8 -0
  51. package/dist/emoji.d.ts +1 -0
  52. package/dist/floating-drag.d.ts +9 -0
  53. package/dist/icon-markup.d.ts +4 -0
  54. package/dist/index.d.ts +8 -0
  55. package/dist/index.js +1 -0
  56. package/dist/inline-text-editor-F7B6FQQ3.js +1 -0
  57. package/dist/inline-text-editor.d.ts +70 -0
  58. package/dist/lazy-accent-picker.d.ts +4 -0
  59. package/dist/lazy-toolbar.d.ts +19 -0
  60. package/dist/message-links.d.ts +2 -0
  61. package/dist/morphing-menu-styles.d.ts +1 -0
  62. package/dist/node.mjs +2607 -0
  63. package/dist/onboarding-NO3RQWR7.js +1 -0
  64. package/dist/onboarding.d.ts +6 -0
  65. package/dist/optimistic.d.ts +26 -0
  66. package/dist/page.d.ts +2 -0
  67. package/dist/picker-WQN53YJ5.js +1 -0
  68. package/dist/pin-direction.d.ts +12 -0
  69. package/dist/pin-stacks.d.ts +3 -0
  70. package/dist/polling.d.ts +10 -0
  71. package/dist/postgres/001_initial.sql +128 -0
  72. package/dist/postgres/002_thread_tags.sql +1 -0
  73. package/dist/postgres/003_project_webhooks.sql +4 -0
  74. package/dist/project-management.d.ts +2 -0
  75. package/dist/react-inspector.d.ts +43 -0
  76. package/dist/react-props-panel-XSMDR2CY.js +1 -0
  77. package/dist/react-props-panel.d.ts +39 -0
  78. package/dist/react.d.ts +38 -0
  79. package/dist/react.js +1 -0
  80. package/dist/reaction-picker.d.ts +1 -0
  81. package/dist/review-layout.d.ts +23 -0
  82. package/dist/setup-browser.d.ts +1 -0
  83. package/dist/setup.d.ts +4 -0
  84. package/dist/setup.js +1 -0
  85. package/dist/shortcuts.d.ts +15 -0
  86. package/dist/static-svg.d.ts +3 -0
  87. package/dist/styles.d.ts +1 -0
  88. package/dist/tag-editor-VDPZ6CO3.js +1 -0
  89. package/dist/tag-editor.d.ts +12 -0
  90. package/dist/toolbar-runtime-2SIUE6SQ.js +1 -0
  91. package/dist/toolbar-runtime.d.ts +5 -0
  92. package/dist/types.d.ts +163 -0
  93. package/package.json +114 -4
  94. package/server/digest.ts +8 -0
  95. package/server/import-project.ts +164 -0
  96. package/server/index.ts +1656 -0
  97. package/server/migrations/0001_comments.sql +54 -0
  98. package/server/migrations/0002_identity.sql +2 -0
  99. package/server/migrations/0003_accent_color.sql +1 -0
  100. package/server/migrations/0004_workspaces.sql +46 -0
  101. package/server/migrations/0005_domains.sql +6 -0
  102. package/server/migrations/0006_member_budget.sql +16 -0
  103. package/server/migrations/0007_revisions.sql +17 -0
  104. package/server/migrations/0008_starter_comments.sql +1 -0
  105. package/server/migrations/0009_retention.sql +19 -0
  106. package/server/migrations/0010_reviewer_history.sql +1 -0
  107. package/server/migrations/0011_project_management.sql +52 -0
  108. package/server/migrations/0012_setup_sites.sql +3 -0
  109. package/server/migrations/0013_project_sites.sql +8 -0
  110. package/server/migrations/0014_project_site_removals.sql +3 -0
  111. package/server/migrations/0015_query_efficiency.sql +6 -0
  112. package/server/migrations/0016_thread_tags.sql +1 -0
  113. package/server/migrations/0017_project_webhooks.sql +4 -0
  114. package/server/node-webhooks.ts +126 -0
  115. package/server/project-management.ts +387 -0
  116. package/server/project-sites.ts +117 -0
  117. package/server/secrets.d.ts +24 -0
  118. package/server/setup-client.txt +2932 -0
  119. package/server/setup-page.ts +14 -0
  120. package/server/tsconfig.json +12 -0
  121. package/server/validation.ts +220 -0
  122. package/server/webhooks.ts +206 -0
  123. package/server/workspaces.ts +168 -0
  124. package/src/emoji.ts +7 -0
  125. package/src/page.ts +4 -0
  126. package/src/types.ts +166 -0
@@ -0,0 +1 @@
1
+ import"./chunk-I7AUKTXE.js";var t=12,e=/^[\p{L}\p{N}][\p{L}\p{N} ._-]{0,31}$/u;function a(t){let a=t.trim().replace(/^#/,"").toLocaleLowerCase("en-US");return e.test(a)?a:null}function n(t,e){let n=[...e.tags],r=!1,o=!1,i=(...e)=>{o=!0,t.replaceChildren(...e),o=!1},l=`komo-tags-${Math.random().toString(36).slice(2)}`;!function t(d=!1){let p=document.createElement("style");p.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.tag-row .tag-options {\n flex-basis: 100%; display: grid; gap: 1px; max-height: 172px; overflow: auto; padding: 4px; border-radius: 8px;\n background: #ffffff07; box-shadow: inset 0 0 0 1px #ffffff0a;\n}\n.tag-row .tag-options:empty { display: none; }\n.tag-row .tag-option {\n display: flex; align-items: center; gap: 6px; min-height: 26px; padding: 0 8px; border-radius: 5px;\n color: #ddd; cursor: pointer; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;\n}\n.tag-row .tag-option[aria-selected="true"] { background: #ffffff12; color: #fff; }\n.tag-row .tag-option-hint, .tag-row .tag-option-empty { color: #858585; }\n.tag-row .tag-option-empty { padding: 5px 8px; }\n.new-comment-composer .draft-body .tag-slot { grid-row: 2; grid-column: 2; align-self: center; min-width: 0; }\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: 0 16px 12px 48px; margin-top: -6px; }\n';let s=document.createElement("div");s.className="tag-row",s.setAttribute("role","group"),s.setAttribute("aria-label","Tags");for(let a of n){let r=document.createElement("span");r.className="tag-chip";let o=document.createElement("span");o.textContent=`#${a}`;let i=document.createElement("button");i.type="button",i.textContent="×",i.setAttribute("aria-label",`Remove tag ${a}`),i.addEventListener("click",()=>{n=n.filter(t=>t!==a),e.onRemove(a),t()}),r.append(o,i),s.append(r)}if(r){let c=document.createElement("input");c.className="tag-input",c.placeholder="Add tag…",c.maxLength=33,c.autocomplete="off",c.setAttribute("role","combobox"),c.setAttribute("aria-label","Add tag"),c.setAttribute("aria-autocomplete","list"),c.setAttribute("aria-controls",l);let g=document.createElement("div");g.className="tag-options",g.id=l,g.setAttribute("role","listbox"),g.setAttribute("aria-label","Tags");let u=[],f=-1,m=a=>{!n.includes(a)&&n.length<12&&(n=[...n,a].sort(),e.onAdd(a)),r=n.length<12,t(r)},x=t=>{f=t,g.querySelectorAll("[role=option]").forEach((e,a)=>{e.setAttribute("aria-selected",String(a===t)),a===t&&e.scrollIntoView?.({block:"nearest"})}),t>=0?c.setAttribute("aria-activedescendant",`${l}-${t}`):c.removeAttribute("aria-activedescendant")},b=()=>{let t=c.value.trim().replace(/^#/,"").toLocaleLowerCase("en-US"),r=a(c.value),o=e.suggestions.filter(t=>!n.includes(t));u=(t?[...o.filter(e=>e.startsWith(t)),...o.filter(e=>!e.startsWith(t)&&e.includes(t))]:o).map(t=>({tag:t,create:!1})),r&&!n.includes(r)&&!o.includes(r)&&u.push({tag:r,create:!0}),g.replaceChildren(...u.map(({tag:t,create:e},a)=>{let n=document.createElement("div");return n.id=`${l}-${a}`,n.className="tag-option",n.setAttribute("role","option"),e&&n.append(Object.assign(document.createElement("span"),{className:"tag-option-hint",textContent:"Create"})),n.append(Object.assign(document.createElement("span"),{textContent:`#${t}`})),n.addEventListener("pointerdown",t=>t.preventDefault()),n.addEventListener("click",()=>m(t)),n.addEventListener("pointermove",()=>x(a)),n})),u.length||g.append(Object.assign(document.createElement("div"),{className:"tag-option-empty",textContent:t?n.includes(r??"")?"Already added":"Use letters, numbers, spaces, . _ or -":"Type to create a tag"})),c.setAttribute("aria-expanded",String(u.length>0)),x(t&&u.length?0:-1)};return c.addEventListener("input",b),c.addEventListener("keydown",o=>{if(o.stopPropagation(),!o.isComposing)if("ArrowDown"===o.key||"ArrowUp"===o.key){if(o.preventDefault(),!u.length)return;let t=u.length-1;x("ArrowDown"===o.key?f>=t?0:f+1:f<=0?t:f-1)}else if("Enter"===o.key||","===o.key)if(o.preventDefault(),f>=0&&u[f])m(u[f].tag);else if(c.value.trim()){let t=a(c.value);t?m(t):c.setAttribute("aria-invalid","true")}else r=!1,t();else if("Escape"===o.key)o.preventDefault(),r=!1,t();else if("Backspace"===o.key&&!c.value&&n.length){let a=n.at(-1);n=n.slice(0,-1),e.onRemove(a),t(!0)}}),c.addEventListener("input",()=>c.removeAttribute("aria-invalid")),c.addEventListener("blur",()=>{o||!c.isConnected||!r||(r=!1,t())}),s.append(c,g),i(p,s),b(),void((d||r)&&c.focus({preventScroll:!0}))}if(n.length<12){let e=document.createElement("button");e.type="button",e.className="tag-add",e.textContent=n.length?"+":"+ Add tag",e.setAttribute("aria-label","Add tag"),e.addEventListener("click",()=>{r=!0,t(!0)}),s.append(e)}i(p,s)}()}export{t as MAX_TAGS,a as normalizeTag,n as tagEditor};
@@ -0,0 +1,12 @@
1
+ export declare const MAX_TAGS = 12;
2
+ export interface TagEditorOptions {
3
+ tags: readonly string[];
4
+ /** Tags already used in this project, offered while typing. */
5
+ suggestions: readonly string[];
6
+ onAdd(tag: string): void;
7
+ onRemove(tag: string): void;
8
+ }
9
+ /** Lowercase and validate a typed tag; returns null when it isn't a valid tag. */
10
+ export declare function normalizeTag(value: string): string | null;
11
+ /** Render removable tag chips and an inline "Tag" input into `slot`. */
12
+ export declare function tagEditor(slot: HTMLElement, options: TagEditorOptions): void;
@@ -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 w,T as x,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 _,fa as O,ga as R,ha as W,ia as N,j as B,ja as F,k as H,ka as U,l as G,m as Y,n as $,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 wt=({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"}));wt.displayName="ChevronRight";import{useEffect as xt,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 _t,useId as Ot,useEffect as Rt,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 Gt=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 Yt(t){return t.startsWith("while")||t.startsWith("drag")&&"draggable"!==t||t.startsWith("layout")||t.startsWith("onTap")||t.startsWith("onPan")||t.startsWith("onLayout")||Gt.has(t)}var $t,Xt=t=>!Yt(t);try{"function"==typeof($t=lt("@emotion/is-prop-valid").default)&&(Xt=t=>t.startsWith("on")?!Yt(t):$t(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&&Yt(i)||!e&&!Yt(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 we(t,e,n,r){let i={},o=r(t,{});for(let t in o)i[t]=R(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 xe=t=>(e,n)=>{let r=ye(Qt),i=ye(It),o=()=>function({scrapeMotionValuesFromProps:t,createRenderState:e},n,r,i){return{latestValues:we(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=xe({scrapeMotionValuesFromProps:C,createRenderState:le}),Pe=xe({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 _e(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:Oe(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],w=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(),w.current&&f.animationState&&f.animationState.animateChanges())}),De(()=>{f&&(!w.current&&f.animationState&&f.animationState.animateChanges(),w.current&&(queueMicrotask(()=>{window.MotionHandoffMarkAsComplete?.(y)}),w.current=!1),f.enteringChildren=void 0)}),f}function Oe(t){if(t)return!1!==t.options.allowProjection?t.projection:Oe(t.parent)}function Re(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=_e(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 w{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 w{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 O(t,e,(t=>e=>o(e)&&t(e,He(e)))(n),r)}var Ge=({current:t})=>t?t.ownerDocument.defaultView:null,Ye=new Set(["auto","scroll"]),$e=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=Y(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);(Ye.has(t.overflowX)||Ye.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 $e(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),_(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:Ge(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&&_(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=x(t))}return o}startAnimation(t){let{drag:e,dragMomentum:n,dragElastic:r,dragTransition:i,dragSnapToOrigin:o,onDragTransitionEnd:s}=this.getProps(),a=this.constraints||{},l=_(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(){_(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){_(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};_(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=$(e.min,e.max-r,t.min):r>i&&(n=$(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(),_(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=O(window,"resize",()=>this.scalePositionWithinConstraints()),u=i.addEventListener("didUpdate",({delta:t,hasLayoutChanged:e})=>{this.isDragging&&e&&(_(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=_t(It);if(null===e)return[!0,null];let{isPresent:n,onExitComplete:r,register:i}=e,o=Ot();Rt(()=>{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 w{constructor(){super(...arguments),this.removePointerDownListener=G}onPointerDown(t){this.session=new $e(t,this.createPanHandlers(),{transformPagePoint:this.node.getTransformPagePoint(),contextWindow:Ge(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 w{constructor(t){super(t),this.removeGroupControls=G,this.removeListeners=G,this.controls=new sn(t)}mount(){let{dragControls:t}=this.node.getProps();t&&(this.removeGroupControls=t.subscribe(this.controls)),this.removeListeners=this.controls.addListeners()||G}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 wn=new WeakMap,xn=new WeakMap,En=t=>{let e=wn.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;xn.has(n)||xn.set(n,{});let r=xn.get(n),i=JSON.stringify(e);return r[i]||(r[i]=new IntersectionObserver(Pn,{root:t,...e})),r[i]}(e);return wn.set(t,n),r.observe(t),()=>{wn.delete(t),r.unobserve(t)}}var bn={some:0,all:1};var Cn={inView:{Feature:class extends w{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 w{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 w{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=Y(O(this.node.current,"focus",()=>this.onFocus()),O(this.node.current,"blur",()=>this.onBlur()))}unmount(){}}},hover:{Feature:class extends w{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 Re;let n=new Map,r=(n,r)=>Re(n,r,t,e);return new Proxy((t,e)=>r(t,e),{get:(i,o)=>"create"===o?r:(n.has(o)||n.set(o,Re(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),[w,x]=bt(null),E=St(null),P=St(null),S=St(r),b="left"===r||"right"===r;Pt(()=>{let t=P.current;if(!t||!w)return;let e=t.getBoundingClientRect(),n=Math.max(8-e.left,Math.min(0,window.innerWidth-8-e.right)),r=Math.max(8-e.top,Math.min(0,window.innerHeight-8-e.bottom));t.style.left=`${w.x+n}px`,t.style.top=`${w.y+r}px`},[w]);let C=St(null),M=St(null),k=St(h),A=St("more"),D=St(!1),j=St(!1),V=St(!1),_=St(null),O=St(void 0),R=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,G=t.filter(t=>!1!==t.showInBar),Y=G.find(t=>"dismiss"===t.id),$=G.filter(t=>"dismiss"!==t.id),X=t.filter(t=>t.children?.length);function z(){clearTimeout(O.current),x(null)}function q(){z(),clearTimeout(R.current),W.current=!1}function K(t,e,n=!1){clearTimeout(O.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(R.current);let u=()=>{W.current=!0,x(l)};n||W.current?u():O.current=setTimeout(u,400)}function Z(t,e,n){q(),U||(A.current=e,D.current=n),_.current="first",m(t)}function J(t=!0,e=A.current){q(),V.current=!0,_.current=t&&D.current?e:null,m({kind:"collapsed"})}function Q(){"group"===h.kind&&(_.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=_.current;_.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 w=()=>m(t=>({...t}));return window.addEventListener("resize",w),()=>{u=!0,l.forEach(t=>t.stop()),window.removeEventListener("resize",w)}},[h,B,r,t.length,G.length]),xt(()=>{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]),xt(()=>()=>{clearTimeout(O.current),clearTimeout(R.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":G.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(R.current))},onPointerLeave:t=>{"mouse"===t.pointerType&&(N.current=!1,z(),clearTimeout(R.current),R.current=setTimeout(()=>{W.current=!1},300))},children:[$.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"})}),Y&&tt(Y,!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)})]}),w&&!U&&Ln("div",{ref:P,className:"morphing-menu__tooltip","aria-hidden":"true",style:{left:w.x,top:w.y},children:w.label})]})}function jn(){return Ln(wt,{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 _n(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):_n({glyph:"person"}))}var On=t=>dt(In,{...t,items:t.items.map(t=>({...t,icon:_n(t.icon)}))});function Rn(t,e){t.replaceChildren();let n=ut(t);return ct(()=>n.render(On(e))),{render:t=>n.render(On(t)),unmount:()=>n.unmount()}}export{Rn as mountToolbar};
@@ -0,0 +1,5 @@
1
+ import type { ToolbarProps } from "./lazy-toolbar.js";
2
+ export declare function mountToolbar(element: HTMLElement, props: ToolbarProps): {
3
+ render: (next: ToolbarProps) => void;
4
+ unmount: () => void;
5
+ };
@@ -0,0 +1,163 @@
1
+ export interface Identity {
2
+ id: string;
3
+ name: string;
4
+ verified: boolean;
5
+ avatarUrl?: string;
6
+ accentColor?: string;
7
+ }
8
+ export interface Anchor {
9
+ /** A manually moved indicator keeps its own position instead of joining a stack. */
10
+ unstacked?: boolean;
11
+ selector: string;
12
+ text: string;
13
+ x: number;
14
+ y: number;
15
+ width: number;
16
+ height: number;
17
+ pageX: number;
18
+ pageY: number;
19
+ viewportWidth: number;
20
+ source?: string;
21
+ /** Optional public target details; old anchors remain valid without them. */
22
+ context?: {
23
+ tag?: string;
24
+ role?: string;
25
+ label?: string;
26
+ nearby?: string;
27
+ classes?: string;
28
+ selectedText?: string;
29
+ styles?: string;
30
+ scope?: string;
31
+ };
32
+ }
33
+ export interface Comment {
34
+ id: string;
35
+ body: string;
36
+ author: Identity;
37
+ createdAt: number;
38
+ editedAt: number | null;
39
+ reactions: Record<string, string[]>;
40
+ }
41
+ export interface Thread {
42
+ id: string;
43
+ page: string;
44
+ anchor: Anchor;
45
+ resolved: boolean;
46
+ resolvedBy: Identity | null;
47
+ createdAt: number;
48
+ updatedAt: number;
49
+ /** Reviewer-defined labels used to group related feedback. */
50
+ tags?: string[];
51
+ comments: Comment[];
52
+ }
53
+ export interface OnboardingOptions {
54
+ /** Temporary first-run setup inside the consuming site. Generated by the CLI. */
55
+ inProject?: boolean;
56
+ /** Suggested deployed sites shown for owner approval during first-run setup. */
57
+ sites?: string[];
58
+ invite?: string;
59
+ code?: string;
60
+ workspace?: string;
61
+ claimKey?: string;
62
+ site?: string;
63
+ }
64
+ /**
65
+ * Keyboard shortcuts as a key with optional Ctrl, Alt, Shift, or Meta
66
+ * modifiers, e.g. "M" or "Shift+J". Set false to disable one. Escape and Tab
67
+ * are reserved.
68
+ */
69
+ export interface KomoShortcuts {
70
+ /** Toggle comment mode. Defaults to "C". */
71
+ comment?: string | false;
72
+ /** Return to browsing. Defaults to "V". */
73
+ browse?: string | false;
74
+ /** Toggle Design mode. Defaults to "D". Has no effect when features.designMode is false. */
75
+ design?: string | false;
76
+ /** Restore a dismissed toolbar. Defaults to "Shift+K". */
77
+ restore?: string | false;
78
+ }
79
+ /** Optional review features. Each defaults to true; false removes it from the UI. */
80
+ export interface KomoFeatures {
81
+ /** Design mode inspector, style previews, and design proposals. */
82
+ designMode?: boolean;
83
+ /** Thread group tags: add them while writing a comment or on an open thread; shown in the sidebar. */
84
+ tags?: boolean;
85
+ }
86
+ export interface CommentsOptions {
87
+ /** Used by the hosted setup screen to reuse the sidebar account UI. */
88
+ onboarding?: OnboardingOptions;
89
+ /** Shared API URL. Never put a private credential here. */
90
+ endpoint: string;
91
+ /** Repository identifier, normally owner/repository. */
92
+ repo: string;
93
+ branch: string;
94
+ /** Public project key registered in the API configuration. */
95
+ project: string;
96
+ enabled?: boolean;
97
+ /** Hide the toolbar until controller.open() or the restore shortcut is used. Defaults to true. */
98
+ showToolbar?: boolean;
99
+ /** Override or disable the review keyboard shortcuts. */
100
+ shortcuts?: KomoShortcuts;
101
+ /** Turn optional features off, e.g. { designMode: false, tags: false }. */
102
+ features?: KomoFeatures;
103
+ /**
104
+ * Sidebar presentation when the review opens. "edge" (default) is a floating,
105
+ * draggable sidebar that parks off and peeks from the viewport edge while
106
+ * closed. "background" frames the site and shows the sidebar in the scaled
107
+ * review sheet. Users can switch Floating and Frame from the Account panel;
108
+ * that choice is remembered per project. Compact viewports always use a bottom
109
+ * Drawer, retaining the desktop preference when the viewport grows.
110
+ */
111
+ sidebar?: "background" | "edge";
112
+ /** Hide the drawer away from the pointer. Defaults to true. */
113
+ autoHideDrawer?: boolean;
114
+ /** Center the default drawer position within this element. */
115
+ drawerContainer?: HTMLElement;
116
+ /** Mounted content root for Frame. Defaults to a sole body content element; otherwise Floating only. */
117
+ pageRoot?: HTMLElement;
118
+ /**
119
+ * Roots, besides pageRoot, whose elements can be picked for comments and
120
+ * Design mode, such as a portal container. Defaults to all of body except
121
+ * komo, so body-level dialogs and popovers are pickable. Return [] to limit
122
+ * picking to pageRoot. Called on every pick; keep it cheap.
123
+ */
124
+ pickRoots?: () => Element[];
125
+ /**
126
+ * Stop komo's own pointer, focus, wheel and typing events at its host
127
+ * element, so page shortcuts and open modals don't react to komo's UI.
128
+ * Defaults to true; set false if the host needs to observe them.
129
+ */
130
+ isolateEvents?: boolean;
131
+ /** Resolve an anchor to a repository-relative source path. */
132
+ source?: (element: Element) => string | undefined;
133
+ /** Defaults to GitHub's source viewer. */
134
+ sourceUrl?: (source: string, branch: string) => string;
135
+ /** Defaults to location.pathname; query strings are not stored. */
136
+ page?: () => string;
137
+ pollInterval?: number;
138
+ /** Full emoji JSON URL; fetched only when choosing another emoji. */
139
+ emojiDataSource?: string;
140
+ /** Opt-in trusted parent domain. Every sibling host can receive the session. */
141
+ sessionDomain?: string;
142
+ /** Canonical API identity for trusted gateways to the same service. Defaults to endpoint. */
143
+ sessionEndpoint?: string;
144
+ }
145
+ export interface CommentsController {
146
+ /** Open a new comment anchored to an element. */
147
+ comment(element: Element): void;
148
+ destroy(): void;
149
+ open(): void;
150
+ close(): void;
151
+ refresh(): Promise<void>;
152
+ }
153
+ export interface AccountUsage {
154
+ hosted: boolean;
155
+ projects: {
156
+ used: number;
157
+ limit: number | null;
158
+ } | null;
159
+ comments: {
160
+ used: number;
161
+ limit: number | null;
162
+ };
163
+ }
package/package.json CHANGED
@@ -1,6 +1,116 @@
1
1
  {
2
2
  "name": "@hazem3500/komo",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.9.0",
4
+ "description": "Point, area, and threaded comments for website branches.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "files": [
8
+ "dist",
9
+ "server/index.ts",
10
+ "server/validation.ts",
11
+ "server/migrations",
12
+ "server/tsconfig.json",
13
+ "server/secrets.d.ts",
14
+ "src/types.ts",
15
+ "src/emoji.ts",
16
+ "README.md",
17
+ "NODE.md",
18
+ "LICENSE",
19
+ "src/page.ts",
20
+ "NOTICE.md",
21
+ "cli",
22
+ "server/workspaces.ts",
23
+ "server/setup-page.ts",
24
+ "server/setup-client.txt",
25
+ "server/project-management.ts",
26
+ "server/webhooks.ts",
27
+ "server/node-webhooks.ts",
28
+ "server/import-project.ts",
29
+ "server/digest.ts",
30
+ "server/project-sites.ts"
31
+ ],
32
+ "main": "./dist/index.js",
33
+ "types": "./dist/index.d.ts",
34
+ "exports": {
35
+ ".": {
36
+ "types": "./dist/index.d.ts",
37
+ "import": "./dist/index.js"
38
+ },
39
+ "./setup": {
40
+ "types": "./dist/setup.d.ts",
41
+ "import": "./dist/setup.js"
42
+ },
43
+ "./server": "./server/index.ts",
44
+ "./react": {
45
+ "types": "./dist/react.d.ts",
46
+ "import": "./dist/react.js"
47
+ },
48
+ "./node": {
49
+ "import": "./dist/node.mjs"
50
+ }
51
+ },
52
+ "sideEffects": [
53
+ "./dist/chunk-*.js",
54
+ "./dist/picker-*.js"
55
+ ],
56
+ "scripts": {
57
+ "build": "node scripts/build.mjs && pnpm run build:setup && pnpm run build:node",
58
+ "prepack": "pnpm run build",
59
+ "typecheck": "wrangler types --config server/wrangler.jsonc server/worker-configuration.d.ts && tsc -p tsconfig.json --noEmit && tsc -p server/tsconfig.json",
60
+ "test": "pnpm run build:setup && vitest run --config vitest.config.ts",
61
+ "dev:api": "wrangler dev --config server/wrangler.jsonc --port 8788",
62
+ "migrate:local": "wrangler d1 migrations apply DB --local --config server/wrangler.jsonc",
63
+ "migrate:remote": "wrangler d1 migrations apply DB --remote --config server/wrangler.jsonc",
64
+ "deploy:api": "pnpm run build:setup && wrangler deploy --config server/wrangler.jsonc",
65
+ "build:setup": "esbuild src/setup-browser.ts --bundle --format=esm --minify --outfile=server/setup-client.txt",
66
+ "size": "node scripts/measure.mjs",
67
+ "bench": "node scripts/bench.mjs",
68
+ "demo:react-props": "node examples/react-props/build.mjs",
69
+ "test:package": "pnpm run build && node scripts/check-package.mjs",
70
+ "build:node": "esbuild server/node.ts --bundle --platform=node --format=esm --packages=external --loader:.txt=text --outfile=dist/node.mjs && mkdir -p dist/postgres && cp server/postgres/*.sql dist/postgres/"
71
+ },
72
+ "repository": {
73
+ "type": "git",
74
+ "url": "git+https://github.com/hazem3500/komo.git",
75
+ "directory": "packages/komo"
76
+ },
77
+ "publishConfig": {
78
+ "access": "public"
79
+ },
80
+ "devDependencies": {
81
+ "@types/node": "^26",
82
+ "@types/pg": "^8.23.1",
83
+ "@types/react": "^19",
84
+ "@types/react-dom": "^19",
85
+ "@untitledui/icons": "0.0.22",
86
+ "emoji-picker-element": "^1.29.1",
87
+ "esbuild": "^0.25.0",
88
+ "jsdom": "^30.1.0",
89
+ "motion": "^12.43.0",
90
+ "react": "19.2.7",
91
+ "react-colorful": "^5.8.1",
92
+ "react-dom": "19.2.7",
93
+ "terser": "5.44.0",
94
+ "typescript": "^6.0.0",
95
+ "vitest": "4.1.11",
96
+ "wrangler": "4.136.3"
97
+ },
98
+ "dependencies": {
99
+ "emoji-regex": "^10.6.0",
100
+ "pg": "^8.23.0"
101
+ },
102
+ "bin": {
103
+ "komo": "./cli/index.mjs"
104
+ },
105
+ "engines": {
106
+ "node": ">=22.12"
107
+ },
108
+ "homepage": "https://github.com/hazem3500/komo#readme",
109
+ "bugs": {
110
+ "url": "https://github.com/hazem3500/komo/issues"
111
+ },
112
+ "peerDependencies": {
113
+ "react": "^18.2.0 || ^19.0.0",
114
+ "react-dom": "^18.2.0 || ^19.0.0"
115
+ }
116
+ }
@@ -0,0 +1,8 @@
1
+ export async function digest(value: string) {
2
+ return Array.from(
3
+ new Uint8Array(
4
+ await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value))
5
+ ),
6
+ (b) => b.toString(16).padStart(2, "0")
7
+ ).join("");
8
+ }
@@ -0,0 +1,164 @@
1
+ import { check, string, pagePath, anchorValue } from "./validation";
2
+ import { digest } from "./digest";
3
+ import { isEmoji } from "../src/emoji";
4
+
5
+ export async function importProject(
6
+ env: Env,
7
+ project: string,
8
+ data: Record<string, unknown>
9
+ ) {
10
+ const source = string(data.source, 100, "source project");
11
+ const kind = string(data.kind, 20, "table");
12
+ check(
13
+ Array.isArray(data.records) &&
14
+ data.records.length > 0 &&
15
+ data.records.length <= 50,
16
+ 400,
17
+ "Import 1–50 records at a time."
18
+ );
19
+ const repo =
20
+ (
21
+ await env.DB.prepare("SELECT repo FROM workspaces WHERE id=?")
22
+ .bind(project)
23
+ .first<{ repo: string }>()
24
+ )?.repo ?? JSON.parse(env.PROJECTS)[project]?.repo;
25
+ check(repo, 404, "Unknown destination project.");
26
+ const id = async (value: unknown, identity = false) =>
27
+ (identity ? "guest:import:" : "import:") +
28
+ (await digest(`${project}\n${source}\n${string(value, 200, "source ID")}`));
29
+ const time = (value: unknown) => {
30
+ check(
31
+ typeof value === "number" && Number.isSafeInteger(value) && value >= 0,
32
+ 400,
33
+ "Invalid timestamp."
34
+ );
35
+ return value;
36
+ };
37
+ const statements: D1PreparedStatement[] = [];
38
+ for (const value of data.records) {
39
+ check(
40
+ value && typeof value === "object" && !Array.isArray(value),
41
+ 400,
42
+ "Invalid record."
43
+ );
44
+ const row = value as Record<string, unknown>;
45
+ if (kind === "users") {
46
+ const accent = row.accent_color;
47
+ check(
48
+ accent === undefined ||
49
+ accent === null ||
50
+ (typeof accent === "string" && /^#[a-f0-9]{6}$/i.test(accent)),
51
+ 400,
52
+ "Invalid accent color."
53
+ );
54
+ const photo = row.avatar_url;
55
+ check(
56
+ photo === undefined ||
57
+ photo === null ||
58
+ (typeof photo === "string" &&
59
+ photo.length <= 12000 &&
60
+ (/^(https:\/\/|data:image\/jpeg;base64,)/.test(photo) ||
61
+ photo === "")),
62
+ 400,
63
+ "Invalid avatar."
64
+ );
65
+ const authorId = await id(row.id, true);
66
+ statements.push(
67
+ env.DB.prepare(
68
+ "INSERT OR IGNORE INTO users(id,name,verified,avatar_url,accent_color) VALUES(?,?,0,?,?) RETURNING id"
69
+ ).bind(
70
+ authorId,
71
+ string(row.name, 60, "author name"),
72
+ photo ?? null,
73
+ accent ?? null
74
+ ),
75
+ env.DB.prepare(
76
+ "INSERT OR IGNORE INTO project_members(project,user_id) VALUES(?,?)"
77
+ ).bind(project, authorId)
78
+ );
79
+ } else if (kind === "threads") {
80
+ let rawAnchor = row.anchor;
81
+ if (typeof rawAnchor === "string") {
82
+ try {
83
+ rawAnchor = JSON.parse(rawAnchor);
84
+ } catch {
85
+ check(false, 400, "Invalid imported anchor.");
86
+ }
87
+ }
88
+ const anchor = anchorValue(rawAnchor);
89
+ check(
90
+ row.resolved === 0 || row.resolved === 1,
91
+ 400,
92
+ "Invalid resolved state."
93
+ );
94
+ statements.push(
95
+ env.DB.prepare(
96
+ "INSERT OR IGNORE INTO threads(id,project,repo,branch,page,anchor,resolved,resolved_by,created_at,updated_at) VALUES(?,?,?,?,?,?,?,?,?,?) RETURNING id"
97
+ ).bind(
98
+ await id(row.id),
99
+ project,
100
+ repo,
101
+ string(row.branch, 250, "branch"),
102
+ pagePath(row.page),
103
+ JSON.stringify(anchor),
104
+ row.resolved,
105
+ row.resolved_by ? await id(row.resolved_by, true) : null,
106
+ time(row.created_at),
107
+ time(row.updated_at)
108
+ )
109
+ );
110
+ } else if (kind === "comments") {
111
+ const thread = await id(row.thread_id),
112
+ author = await id(row.user_id, true);
113
+ check(
114
+ await env.DB.prepare("SELECT id FROM threads WHERE id=? AND project=?")
115
+ .bind(thread, project)
116
+ .first(),
117
+ 400,
118
+ "Import the parent thread first."
119
+ );
120
+ statements.push(
121
+ env.DB.prepare(
122
+ "INSERT OR IGNORE INTO comments(id,thread_id,user_id,body,created_at,edited_at) VALUES(?,?,?,?,?,?) RETURNING id"
123
+ ).bind(
124
+ await id(row.id),
125
+ thread,
126
+ author,
127
+ string(row.body, 4000, "comment"),
128
+ time(row.created_at),
129
+ row.edited_at == null ? null : time(row.edited_at)
130
+ )
131
+ );
132
+ } else if (kind === "reactions") {
133
+ const comment = await id(row.comment_id);
134
+ check(
135
+ await env.DB.prepare(
136
+ "SELECT c.id FROM comments c JOIN threads t ON t.id=c.thread_id WHERE c.id=? AND t.project=?"
137
+ )
138
+ .bind(comment, project)
139
+ .first(),
140
+ 400,
141
+ "Import the comment first."
142
+ );
143
+ check(
144
+ typeof row.emoji === "string" && isEmoji(row.emoji),
145
+ 400,
146
+ "Invalid reaction."
147
+ );
148
+ statements.push(
149
+ env.DB.prepare(
150
+ "INSERT OR IGNORE INTO reactions(comment_id,user_id,emoji) VALUES(?,?,?) RETURNING comment_id"
151
+ ).bind(comment, await id(row.user_id, true), row.emoji)
152
+ );
153
+ } else check(false, 400, "Unknown import table.");
154
+ }
155
+ const results = await env.DB.batch(statements);
156
+ return Response.json({
157
+ ok: true,
158
+ imported: results.reduce(
159
+ (total, result, index) =>
160
+ total + (kind === "users" && index % 2 ? 0 : result.results.length),
161
+ 0
162
+ ),
163
+ });
164
+ }