handlebars-editor-react 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,4 +1,3 @@
1
- 'use strict';Object.defineProperty(exports,'__esModule',{value:true});var react=require('react'),ne=require('handlebars'),jsxRuntime=require('react/jsx-runtime');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var ne__default=/*#__PURE__*/_interopDefault(ne);var ue=ne__default.default.Parser,M=ue.lexer,Re=ue.terminals_,we=new Set(["OPEN_BLOCK","OPEN_INVERSE","OPEN_INVERSE_CHAIN","OPEN_ENDBLOCK"]),ve=new Set(["OPEN","OPEN_UNESCAPED"]),Be=new Set(["OPEN_PARTIAL","OPEN_PARTIAL_BLOCK"]),De=new Set(["OPEN","OPEN_UNESCAPED","OPEN_BLOCK","OPEN_INVERSE","OPEN_INVERSE_CHAIN","OPEN_ENDBLOCK","OPEN_PARTIAL","OPEN_PARTIAL_BLOCK"]),He=new Set(["CLOSE","CLOSE_UNESCAPED","CLOSE_RAW_BLOCK","END_RAW_BLOCK"]),Me=new Set(["ID","STRING","NUMBER","BOOLEAN","DATA","OPEN_SEXPR","UNDEFINED","NULL"]),fe=t=>we.has(t),he=t=>ve.has(t),de=t=>Be.has(t),Ke=t=>De.has(t),Ve=t=>He.has(t),Ue=t=>Me.has(t),Fe={CONTENT:"text",COMMENT:"comment",OPEN:"brace",CLOSE:"brace",OPEN_UNESCAPED:"brace",CLOSE_UNESCAPED:"brace",OPEN_RAW_BLOCK:"brace",CLOSE_RAW_BLOCK:"brace",END_RAW_BLOCK:"brace",OPEN_BLOCK:"brace",OPEN_INVERSE:"brace",OPEN_INVERSE_CHAIN:"brace",OPEN_ENDBLOCK:"brace",OPEN_PARTIAL:"brace",OPEN_PARTIAL_BLOCK:"brace",OPEN_SEXPR:"subexpr-paren",CLOSE_SEXPR:"subexpr-paren",OPEN_BLOCK_PARAMS:"block-keyword",CLOSE_BLOCK_PARAMS:"block-keyword",INVERSE:"block-keyword",ID:"variable",STRING:"literal",NUMBER:"literal",BOOLEAN:"literal",UNDEFINED:"literal",NULL:"literal",DATA:"data-var",SEP:"brace",EQUALS:"brace"};function pe(t,n,r){let e=0;for(let s=0;s<n-1&&s<t.length;s++)e+=t[s].length+1;return e+r}function We(t){let n=[],r=t.split(`
2
- `);M.setInput(t);try{for(let e=M.lex();e!==M.EOF;e=M.lex()){let s=Re[e]||"UNKNOWN",o=M.yylloc;n.push({type:s,text:M.yytext,start:pe(r,o.first_line,o.first_column),end:pe(r,o.last_line,o.last_column)});}}catch{}return n}function $e(t){return t.map(n=>n.type==="ID"&&n.text==="."?{...n,type:"SEP"}:n.type==="ID"&&n.text==="="?{...n,type:"EQUALS"}:n)}function ze(t){let n=[],r=null,e=false,s=false,o=0;for(let c=0;c<t.length;c++){let i=t[c],E=t[c-1];Ke(i.type)?(fe(i.type)?r=i.type==="OPEN_ENDBLOCK"?"block-close":"block-open":de(i.type)?r="partial":he(i.type)&&(r="mustache"),s=false,o=0):Ve(i.type)&&(r=null,s=false,o=0),i.type==="OPEN_BLOCK_PARAMS"?e=true:i.type==="CLOSE_BLOCK_PARAMS"&&(e=false),i.type==="SEP"?o++:i.type==="ID"&&E?.type!=="SEP"&&E?.type!=="DATA"&&(o=0);let A=false;if(i.type==="ID"){if(o===0)A=s;else for(let P=c-1;P>=0;P--)if(t[P].type==="ID"&&n[P]?.context.pathRootAfterHelper!==void 0){let g=t[P-1];if(g?.type!=="SEP"&&g?.type!=="DATA"){A=n[P].context.pathRootAfterHelper;break}}}n.push({...i,context:{type:r,isInBlockParams:e,pathRootAfterHelper:A}}),i.type==="ID"&&o===0&&!e&&E?.type!=="EQUALS"&&E?.type!=="DATA"&&(s=true);}return n}function Xe(t,n,r){let{context:e}=t;return t.text==="this"?"data-var":e.isInBlockParams?"block-param":r?.type==="EQUALS"?"hash-key":n?.type==="EQUALS"?"hash-value":n?.type==="DATA"?"data-var":n?.type==="SEP"?e.pathRootAfterHelper?"helper-arg":"variable-path":Qe(t,n,r)}function Qe(t,n,r){let{context:e}=t;return e.type==="block-open"||e.type==="block-close"?fe(n?.type??"")?"block-keyword":"helper-arg":e.type==="partial"?de(n?.type??"")?"helper":"helper-arg":n?.type==="OPEN_SEXPR"?"helper":e.type==="mustache"?he(n?.type??"")?r?.type==="SEP"?"variable":r&&Ue(r.type)?"helper":"variable":"helper-arg":"variable"}function Ge(t){return t.map((n,r)=>{let e=t[r-1],s=t[r+1],o;return n.type==="ID"?o=Xe(n,e,s):o=Fe[n.type]||"text",{token:n,highlightType:o}})}function je(t,n){let r=[],e=0;for(let s=0;s<n.length;s++){let{token:o,highlightType:c}=n[s];if(o.start>e&&r.push({type:"text",value:t.slice(e,o.start),start:e,end:o.start}),o.type==="DATA"){let i=n[s+1];if(i?.token.type==="ID"&&i.token.start===o.end){r.push({type:"data-var",value:t.slice(o.start,i.token.end),start:o.start,end:i.token.end}),e=i.token.end,s++;continue}}r.push({type:c,value:t.slice(o.start,o.end),start:o.start,end:o.end}),e=o.end;}return e<t.length&&r.push({type:"text",value:t.slice(e),start:e,end:t.length}),r}function K(t){if(!t)return [];let n=We(t),r=$e(n),e=ze(r),s=Ge(e);return je(t,s).filter(c=>c.value.length>0)}var G=["if","unless","each","with"],me=new Set([...G,"lookup","log","this","else"]),xe=new Set(["each","with"]),qe=new Set(["ID","STRING","NUMBER","BOOLEAN","DATA","OPEN_SEXPR"]),Ee=ne__default.default.Parser,D=Ee.lexer,Ye=Ee.terminals_;function z(t){return me.has(t)||t.startsWith("@")}function Je(t){return qe.has(t.name)}function X(t,n){let r=[],e=true;for(let s=n;s<t.length;s++){let o=t[s];if(o.name==="EQUALS")break;if(o.name==="ID"){if(!e||t[s+1]?.name==="EQUALS")break;r.push(o.text),e=false;}else if(o.name==="SEP")e=true;else break}return r}function Ze(t,n,r,e){return {name:t,path:n,type:r?"block":n.includes(".")||e?"nested":"simple",blockType:r,context:e}}function et(t){let n=[],r=null;for(let e of t)xe.has(e.helper)&&e.context&&(r||(r=e.context),n.push(e.helper==="each"?`${e.context}[]`:e.context));return n.length===0||!r?null:{root:r,prefix:`${n.join(".")}.`}}function tt(t){let n=[],r=t;for(;r.length>0;){let e=nt(r);if(n.push(...e.expressions),e.consumed===r.length)break;let s=r.slice(e.consumed),o=s.search(/\{\{/);if(o===-1)break;r=s.slice(o);}return {expressions:n}}function nt(t){D.setInput(t),D.conditionStack=["INITIAL"];let n=[],r=0,e=false,s=null,o=[];try{for(let c=D.lex();c!==D.EOF;c=D.lex()){let i=Ye[c],E=D.yytext;if(r=D.yylloc?.last_column??r,!(i==="OPEN_RAW_BLOCK"||i==="CLOSE_RAW_BLOCK"||i==="END_RAW_BLOCK")){if(i==="OPEN"||i==="OPEN_UNESCAPED"){e=!0,s="mustache",o=[];continue}if(i==="OPEN_PARTIAL"||i==="OPEN_PARTIAL_BLOCK"){e=!0,s="partial",o=[];continue}if(i==="OPEN_BLOCK"||i==="OPEN_INVERSE"||i==="OPEN_INVERSE_CHAIN"){e=!0,s="block",o=[];continue}if(i==="OPEN_ENDBLOCK"){e=!0,s="endblock",o=[];continue}if(i==="CLOSE"||i==="CLOSE_UNESCAPED"){if(s){let A=o[0]?.text??null;n.push({type:s,tokens:[...o],helperName:A});}e=!1,o=[];continue}e&&o.push({name:i,text:E});}}return {expressions:n,consumed:t.length}}catch{return {expressions:n,consumed:r}}}function rt(t,n,r){let e=t.tokens;if(e.length===0||e[0]?.name==="DATA")return;let s=e[0]?.text;if(z(s))W(e,1,n,r);else {let o=X(e,0);if(o.length>0){let i=o.length*2-1,E=e[i];E&&Je(E)?W(e,i,n,r):Q(o,n,r);}}}function ot(t,n,r){let e=t.tokens,s=e[0]?.text;if(xe.has(s)){if(e[1]?.name==="OPEN_SEXPR")return W(e,1,n,r),{helper:s,context:""};{let o=1;for(;o<e.length&&e[o].name!=="ID";)o++;if(o<e.length){let c=X(e,o);return c.length>0&&!z(c[0])&&Q(c,n,r,s),{helper:s,context:c[0]||""}}return {helper:s,context:""}}}else if(me.has(s)){if(e[1]?.name==="OPEN_SEXPR")W(e,1,n,r);else {let o=1;for(;o<e.length&&e[o].name!=="ID";)o++;if(o<e.length){let c=X(e,o);c.length>0&&!z(c[0])&&Q(c,n,r,s);}}return {helper:s,context:""}}return {helper:s,context:""}}function st(t,n,r){let e=t.tokens,s=1;for(;s<e.length&&(e[s].name==="SEP"||e[s].name==="ID")&&!(e[s].name==="ID"&&e[s-1]?.name!=="SEP");)s++;W(e,s,n,r);}function W(t,n,r,e){for(let s=n;s<t.length;s++){let o=t[s];if(!(o.name==="OPEN_SEXPR"||o.name==="CLOSE_SEXPR")&&o.name!=="DATA"&&t[s-1]?.name!=="DATA"&&o.name!=="EQUALS"&&!(o.name==="ID"&&t[s+1]?.name==="EQUALS")&&o.name==="ID"&&!z(o.text)){if(t[s-1]?.name==="OPEN_SEXPR")continue;let i=X(t,s);i.length>0&&(Q(i,r,e),s+=i.length*2-2);}}}function Q(t,n,r,e){let s=t[0],o=n.contextPrefix&&n.rootContext?{prefix:n.contextPrefix,root:n.rootContext}:null,c,i;o?(c=o.prefix+t.join("."),i=o.root):(c=t.join("."),i=void 0),r.has(c)||r.set(c,Ze(s,c,e,i));}function at(t,n){return n.type==="endblock"&&t.length>0?t.slice(0,-1):t}function it(t){let n=new Map,r=[];for(let e of t){let s=et(r),o={contextPrefix:s?.prefix??null,rootContext:s?.root??null};if(e.type==="mustache")rt(e,o,n);else if(e.type==="block"){let c=ot(e,o,n);r=[...r,c];}else e.type==="partial"?st(e,o,n):e.type==="endblock"&&(r=at(r,e));}return Array.from(n.values())}function re(t){let{expressions:n}=tt(t),r=it(n),e=[...new Set(r.filter(s=>!s.context).map(s=>s.name))];return {variables:r,rootVariables:e}}function lt(t,n,r){if(!n)return t;let e=r?.helpers?ne__default.default.create():ne__default.default;if(r?.helpers)for(let[s,o]of Object.entries(r.helpers))e.registerHelper(s,o);return e.compile(t)(n)}var pt=["this","@index","@first","@last","@key"],ut=["@root"];function ft(t,n){if(!n)return "prefix";let r=t.toLowerCase(),e=n.toLowerCase();return r===e?"exact":r.startsWith(e)?"prefix":r.includes(e)?"partial":"none"}function ht(t,n,r,e,s){let o=[],c=new Set,i=s.lastIndexOf("."),E=i!==-1;E?s.slice(0,i+1):"";let P=E?s.slice(i+1):s,g=(m,l)=>{if(c.has(m))return;let b=ft(m,P);b!=="none"&&(c.add(m),o.push({option:{value:m,type:l},matchType:b}));};if(E){let m=s.slice(0,i).replace(/\[\]$/,"");n.forEach(l=>{let b=l.path.replace(/\[\]/g,"");if(b.startsWith(`${m}.`)){let q=b.slice(m.length+1).split(".")[0];g(q,"variable");}});}else {if(!r){for(let l of G)g(`#${l}`,"block-open");for(let l of G)g(`/${l}`,"block-close");g("else","block-close");}for(let l of t)g(l,"helper");if(e){if(e.isEach)for(let l of pt)g(l,"data-var");for(let l of e.blockParams)g(l,"variable");for(let l of ut)g(l,"data-var");}let m=new Set;for(let l of n){let b=l.path.split(".")[0].replace("[]","");m.add(b);}for(let l of m)g(l,"variable");}let v={"data-var":0,variable:1,helper:2,"block-open":3,"block-close":4},_={exact:0,prefix:1,partial:2,none:3};return o.sort((m,l)=>{let b=_[m.matchType]-_[l.matchType];if(b!==0)return b;let B=v[m.option.type]-v[l.option.type];return B!==0?B:m.option.value.localeCompare(l.option.value)}),o.map(m=>m.option)}function dt(t,n){let r=t.slice(0,n),e=[],s=/\{\{#(each|with)\s+([^\s}]+)(?:\s+as\s*\|([^|]+)\|)?|\{\{\/(each|with)\}\}/g;for(let o of r.matchAll(s))if(o[1]){let c=o[1],i=o[2],A=(o[3]||"").split(/\s+/).filter(Boolean);e.push({type:c,variable:i,blockParams:A,isEach:c==="each"});}else if(o[4]){let c=o[4];for(let i=e.length-1;i>=0;i--)if(e[i].type===c){e.splice(i,1);break}}return e.length>0?e[e.length-1]:null}function mt(t,n){let r=t.slice(0,n),e=r.lastIndexOf("{{!--");if(e!==-1&&r.slice(e).indexOf("--}}")===-1)return true;let s=r.lastIndexOf("{{!");if(s!==-1){let o=r.slice(s);if(!o.startsWith("{{!--")&&o.indexOf("}}")===-1)return true}return false}function xt(t,n){let r=t.slice(0,n),e=t.slice(n),s=r.lastIndexOf("{{");if(s===-1||r.slice(s).includes("}}"))return false;let c=e.indexOf("}}");return c===-1?false:!e.slice(0,c).includes("{{")}function ye({value:t,onChange:n,placeholder:r="Enter template...",readOnly:e=false,className:s="",style:o,theme:c,customHelpers:i=[],autocomplete:E=true,minHeight:A=100}){let P=react.useRef(null),g=react.useRef(null),v=react.useRef(null),_=react.useRef(null),m=react.useId(),[l,b]=react.useState({isOpen:false,options:[],selectedIndex:0,triggerStart:0,filterText:"",isRaw:false,contextPath:null}),[B,q]=react.useState({top:0,left:0}),se=react.useMemo(()=>re(t).variables.map(p=>({path:p.path,context:p.context})),[t]),ae=react.useMemo(()=>K(t),[t]),Oe=react.useMemo(()=>t?ae.map(a=>a.type==="text"?a.value:jsxRuntime.jsx("span",{className:`hbs-token-${a.type}`,children:a.value},a.start)):jsxRuntime.jsx("span",{className:"hbs-editor-placeholder",children:r}),[ae,t,r]),k=react.useCallback(()=>{b(a=>({...a,isOpen:false}));},[]),ie=react.useCallback((a,p)=>{if(!E||e){k();return}if(mt(a,p)||xt(a,p)){k();return}let d=a.slice(0,p).match(/(\{\{\{?)([#/]?[\w.@]*)$/);if(!d){k();return}let x=d[1],f=d[2]||"",T=p-f.length,h=x==="{{{";if(f.includes("}")){k();return}let y=dt(a,p),O=ht(i,se,h,y,f);if(O.length===0){k();return}b({isOpen:true,options:O,selectedIndex:0,triggerStart:T,filterText:f,isRaw:h,contextPath:y});},[E,e,i,se,k]),Ae=react.useCallback(a=>{let p=a.target.value;n?.(p),ie(p,a.target.selectionStart);},[n,ie]),U=react.useCallback(a=>{let p=g.current;if(!p)return;let{triggerStart:u,filterText:d,isRaw:x}=l,f=x?"}}}":"}}",T=d.lastIndexOf("."),h=T!==-1?d.slice(0,T+1):"",y,O;if(a.type==="block-open"&&!x){let N=a.value.slice(1);y=`${a.value} }}{{/${N}}}`,O=a.value.length+1;}else a.type!=="block-close"&&a.value!=="else"?(y=`${h}${a.value}${f}`,O=y.length):(y=`${a.value}${f}`,O=y.length);p.focus(),p.setSelectionRange(u,p.selectionStart),document.execCommand("insertText",false,y);let I=u+O;p.setSelectionRange(I,I),n?.(p.value),k();},[l,n,k]),Te=react.useCallback(a=>{let{scrollTop:p,scrollLeft:u}=a.currentTarget;v.current&&(v.current.scrollTop=p,v.current.scrollLeft=u),q({top:p,left:u});},[]),Pe=react.useCallback(a=>{_.current?.contains(a.relatedTarget)||k();},[k]),Y=react.useCallback(()=>{let a=g.current;if(!a||!l.isOpen)return;let p=a.selectionStart;t.slice(0,p).match(/(\{\{\{?)([#/]?[\w.@]*)$/)||k();},[l.isOpen,t,k]),Ne=react.useCallback(a=>{let p=a.currentTarget;if(a.key==="Tab"){if(l.isOpen){a.preventDefault();let T=l.options[l.selectedIndex];T&&U(T);return}a.preventDefault();let{selectionStart:f}=p;if(a.shiftKey){let h=t.slice(0,f).lastIndexOf(`
3
- `)+1,O=t.slice(h,f).match(/^(\t| {2})/);if(O){let I=O[1].length,N=t.slice(0,h)+t.slice(h+I);n?.(N);let S=Math.max(h,f-I);setTimeout(()=>p.setSelectionRange(S,S),0);}}else document.execCommand("insertText",false," "),n?.(p.value);return}if((a.metaKey||a.ctrlKey)&&(a.key==="z"||a.key==="y")||!l.isOpen)return;let{options:u,selectedIndex:d}=l,x=8;switch(a.key){case "ArrowDown":a.preventDefault(),b(f=>({...f,selectedIndex:Math.min(d+1,u.length-1)}));break;case "ArrowUp":a.preventDefault(),b(f=>({...f,selectedIndex:Math.max(d-1,0)}));break;case "Home":a.preventDefault(),b(f=>({...f,selectedIndex:0}));break;case "End":a.preventDefault(),b(f=>({...f,selectedIndex:u.length-1}));break;case "PageDown":a.preventDefault(),b(f=>({...f,selectedIndex:Math.min(d+x,u.length-1)}));break;case "PageUp":a.preventDefault(),b(f=>({...f,selectedIndex:Math.max(d-x,0)}));break;case "Enter":a.preventDefault(),u[d]&&U(u[d]);break;case "Escape":a.preventDefault(),k();break;case "ArrowLeft":case "ArrowRight":setTimeout(()=>Y(),0);break}},[l,U,k,Y,t,n]),J=react.useMemo(()=>{if(!l.isOpen||!g.current)return null;let a=g.current,p=getComputedStyle(a),u=getComputedStyle(a.parentElement||a);return {lineHeight:parseFloat(p.lineHeight)||20,paddingTop:parseFloat(p.paddingTop)||0,paddingLeft:parseFloat(p.paddingLeft)||0,charWidth:(parseFloat(p.fontSize)||14)*.6,dropdownWidth:parseInt(u.getPropertyValue("--hbs-autocomplete-min-width"),10)||180,dropdownMaxHeight:parseInt(u.getPropertyValue("--hbs-autocomplete-max-height"),10)||200,clientWidth:a.clientWidth,clientHeight:a.clientHeight}},[l.isOpen]),H=react.useMemo(()=>{if(!l.isOpen||!J)return {top:void 0,bottom:void 0,left:0,maxHeight:200,openUpward:false,visible:false};let{triggerStart:a}=l,{lineHeight:p,paddingTop:u,paddingLeft:d,charWidth:x,dropdownWidth:f,dropdownMaxHeight:T,clientWidth:h,clientHeight:y}=J,I=t.slice(0,a).split(`
4
- `),N=I.length,S=I[I.length-1]?.length||0,R=u+N*p-B.top,C=d+S*x-B.left,$=h-f-10;C>$&&(C=Math.max(10,$));let F=y-R-10,le=R-p-10,ce=F<120&&le>F,Z,ee,te;ce?(te=Math.min(T,Math.max(80,le)),ee=y-R+p,Z=void 0):(te=Math.min(T,Math.max(80,F)),Z=R,ee=void 0);let Le=R>=0&&R<y&&C>=0&&C<h;return {top:Z,bottom:ee,left:C,maxHeight:te,openUpward:ce,visible:Le}},[l,t,B,J]),Se=react.useMemo(()=>{if(!c)return {};let a={},p={variable:"--hbs-color-variable",variablePath:"--hbs-color-variable-path",blockKeyword:"--hbs-color-block-keyword",blockParam:"--hbs-color-block-param",helper:"--hbs-color-helper",helperArg:"--hbs-color-helper-arg",hashKey:"--hbs-color-hash-key",hashValue:"--hbs-color-hash-value",literal:"--hbs-color-literal",dataVar:"--hbs-color-data-var",subexprParen:"--hbs-color-subexpr-paren",comment:"--hbs-color-comment",raw:"--hbs-color-raw",brace:"--hbs-color-brace",text:"--hbs-color-text",background:"--hbs-color-background",caret:"--hbs-color-caret",border:"--hbs-color-border",placeholder:"--hbs-color-placeholder"};for(let[u,d]of Object.entries(p)){let x=c[u];x&&(a[d]=x);}return a},[c]);react.useEffect(()=>{if(!l.isOpen||!_.current)return;let u=_.current.querySelectorAll(".hbs-autocomplete-item")[l.selectedIndex];u&&u.scrollIntoView({block:"nearest"});},[l.selectedIndex,l.isOpen]),react.useEffect(()=>{if(!l.isOpen)return;let a=P.current,p=d=>{let x=d.target;a&&!a.contains(x)&&k();},u=d=>{let x=d.target;a?.contains(x)&&!_.current?.contains(x)&&x!==g.current&&k();};return document.addEventListener("mousedown",p),a?.addEventListener("mousedown",u),()=>{document.removeEventListener("mousedown",p),a?.removeEventListener("mousedown",u);}},[l.isOpen,k]);let Ce=react.useCallback((a,p)=>{let{filterText:u,selectedIndex:d}=l,x=p===d,f=u.lastIndexOf("."),T=f!==-1?u.slice(f+1):u,h=a.value;(a.type==="block-open"&&h.startsWith("#")||a.type==="block-close"&&h.startsWith("/")||a.type==="data-var"&&h.startsWith("@"))&&(h=h.slice(1));let y,O=T.toLowerCase().replace(/^[#/@]/,""),N=h.toLowerCase().indexOf(O);if(O.length>0&&N!==-1){let C=h.slice(0,N),$=h.slice(N,N+O.length),F=h.slice(N+O.length);y=jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[C,jsxRuntime.jsx("span",{className:"hbs-autocomplete-match",children:$}),F]});}else y=h;let S="";switch(a.type){case "block-open":S="#";break;case "block-close":S="/";break;case "data-var":S="@";break;case "helper":S="\u0192";break;case "variable":S="\xB7";break}let R=jsxRuntime.jsx("span",{className:"hbs-autocomplete-type",children:S});return jsxRuntime.jsxs("button",{id:`${m}-option-${p}`,type:"button",role:"option","aria-selected":x,className:`hbs-autocomplete-item hbs-autocomplete-${a.type} ${x?"hbs-selected":""}`,onMouseDown:C=>{C.preventDefault(),U(a);},onMouseEnter:()=>b(C=>({...C,selectedIndex:p})),children:[R,jsxRuntime.jsx("span",{className:"hbs-autocomplete-value",children:y})]},a.value)},[l,U,m]),Ie=["hbs-editor",e?"hbs-readonly":"",s].filter(Boolean).join(" ");return jsxRuntime.jsxs("div",{ref:P,className:Ie,style:{...Se,minHeight:typeof A=="number"?`${A}px`:A,...o},children:[jsxRuntime.jsx("div",{ref:v,className:"hbs-editor-highlight",children:Oe}),jsxRuntime.jsx("textarea",{ref:g,className:"hbs-editor-textarea",value:t,onChange:Ae,onKeyDown:Ne,onScroll:Te,onBlur:Pe,onSelect:Y,placeholder:"",readOnly:e,spellCheck:false,autoCapitalize:"off",autoComplete:"off",autoCorrect:"off",role:"combobox","aria-haspopup":"listbox","aria-expanded":E&&l.isOpen&&H.visible,"aria-controls":m,"aria-activedescendant":E&&l.isOpen&&l.options[l.selectedIndex]?`${m}-option-${l.selectedIndex}`:void 0}),E&&l.isOpen&&H.visible&&jsxRuntime.jsx("div",{ref:_,id:m,role:"listbox","aria-label":"Autocomplete suggestions",className:"hbs-autocomplete",style:{top:H.top,bottom:H.bottom,left:H.left,maxHeight:H.maxHeight},children:l.options.map((a,p)=>Ce(a,p))})]})}function bt({content:t,className:n}){if(!t)return null;let r=K(t);return jsxRuntime.jsx("span",{className:n,children:r.map(e=>jsxRuntime.jsx("span",{className:`hbs-token-${e.type}`,children:e.value},e.start))})}exports.HandlebarsEditor=ye;exports.HandlebarsHighlight=bt;exports.default=ye;exports.extract=re;exports.interpolate=lt;exports.tokenize=K;
1
+ 'use strict';Object.defineProperty(exports,'__esModule',{value:true});var react=require('react'),ne=require('handlebars'),reactDom=require('react-dom'),jsxRuntime=require('react/jsx-runtime');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var ne__default=/*#__PURE__*/_interopDefault(ne);var pe=ne__default.default.Parser,H=pe.lexer,Pe=pe.terminals_,Ne=new Set(["OPEN_BLOCK","OPEN_INVERSE","OPEN_INVERSE_CHAIN","OPEN_ENDBLOCK"]),Ce=new Set(["OPEN","OPEN_UNESCAPED"]),Re=new Set(["OPEN_PARTIAL","OPEN_PARTIAL_BLOCK"]),Le=new Set(["OPEN","OPEN_UNESCAPED","OPEN_BLOCK","OPEN_INVERSE","OPEN_INVERSE_CHAIN","OPEN_ENDBLOCK","OPEN_PARTIAL","OPEN_PARTIAL_BLOCK"]),Ie=new Set(["CLOSE","CLOSE_UNESCAPED","CLOSE_RAW_BLOCK","END_RAW_BLOCK"]),_e=new Set(["ID","STRING","NUMBER","BOOLEAN","DATA","OPEN_SEXPR","UNDEFINED","NULL"]),ue=t=>Ne.has(t),fe=t=>Ce.has(t),de=t=>Re.has(t),ve=t=>Le.has(t),we=t=>Ie.has(t),De=t=>_e.has(t),Be={CONTENT:"text",COMMENT:"comment",OPEN:"brace",CLOSE:"brace",OPEN_UNESCAPED:"brace",CLOSE_UNESCAPED:"brace",OPEN_RAW_BLOCK:"brace",CLOSE_RAW_BLOCK:"brace",END_RAW_BLOCK:"brace",OPEN_BLOCK:"brace",OPEN_INVERSE:"brace",OPEN_INVERSE_CHAIN:"brace",OPEN_ENDBLOCK:"brace",OPEN_PARTIAL:"brace",OPEN_PARTIAL_BLOCK:"brace",OPEN_SEXPR:"subexpr-paren",CLOSE_SEXPR:"subexpr-paren",OPEN_BLOCK_PARAMS:"block-keyword",CLOSE_BLOCK_PARAMS:"block-keyword",INVERSE:"block-keyword",ID:"variable",STRING:"literal",NUMBER:"literal",BOOLEAN:"literal",UNDEFINED:"literal",NULL:"literal",DATA:"data-var",SEP:"brace",EQUALS:"brace"};function ce(t,n,r){let e=0;for(let o=0;o<n-1&&o<t.length;o++)e+=t[o].length+1;return e+r}function He(t){let n=[],r=t.split(`
2
+ `);H.setInput(t);try{for(let e=H.lex();e!==H.EOF;e=H.lex()){let o=Pe[e]||"UNKNOWN",s=H.yylloc;n.push({type:o,text:H.yytext,start:ce(r,s.first_line,s.first_column),end:ce(r,s.last_line,s.last_column)});}}catch{}return n}function Me(t){return t.map(n=>n.type==="ID"&&n.text==="."?{...n,type:"SEP"}:n.type==="ID"&&n.text==="="?{...n,type:"EQUALS"}:n)}function Ve(t){let n=[],r=null,e=false,o=false,s=0;for(let l=0;l<t.length;l++){let i=t[l],h=t[l-1];ve(i.type)?(ue(i.type)?r=i.type==="OPEN_ENDBLOCK"?"block-close":"block-open":de(i.type)?r="partial":fe(i.type)&&(r="mustache"),o=false,s=0):we(i.type)&&(r=null,o=false,s=0),i.type==="OPEN_BLOCK_PARAMS"?e=true:i.type==="CLOSE_BLOCK_PARAMS"&&(e=false),i.type==="SEP"?s++:i.type==="ID"&&h?.type!=="SEP"&&h?.type!=="DATA"&&(s=0);let O=false;if(i.type==="ID"){if(s===0)O=o;else for(let k=l-1;k>=0;k--)if(t[k].type==="ID"&&n[k]?.context.pathRootAfterHelper!==void 0){let b=t[k-1];if(b?.type!=="SEP"&&b?.type!=="DATA"){O=n[k].context.pathRootAfterHelper;break}}}n.push({...i,context:{type:r,isInBlockParams:e,pathRootAfterHelper:O}}),i.type==="ID"&&s===0&&!e&&h?.type!=="EQUALS"&&h?.type!=="DATA"&&(o=true);}return n}function Ke(t,n,r){let{context:e}=t;return t.text==="this"?"data-var":e.isInBlockParams?"block-param":r?.type==="EQUALS"?"hash-key":n?.type==="EQUALS"?"hash-value":n?.type==="DATA"?"data-var":n?.type==="SEP"?e.pathRootAfterHelper?"helper-arg":"variable-path":Ue(t,n,r)}function Ue(t,n,r){let{context:e}=t;return e.type==="block-open"||e.type==="block-close"?ue(n?.type??"")?"block-keyword":"helper-arg":e.type==="partial"?de(n?.type??"")?"helper":"helper-arg":n?.type==="OPEN_SEXPR"?"helper":e.type==="mustache"?fe(n?.type??"")?r?.type==="SEP"?"variable":r&&De(r.type)?"helper":"variable":"helper-arg":"variable"}function We(t){return t.map((n,r)=>{let e=t[r-1],o=t[r+1],s;return n.type==="ID"?s=Ke(n,e,o):s=Be[n.type]||"text",{token:n,highlightType:s}})}function ze(t,n){let r=[],e=0;for(let o=0;o<n.length;o++){let{token:s,highlightType:l}=n[o];if(s.start>e&&r.push({type:"text",value:t.slice(e,s.start),start:e,end:s.start}),s.type==="DATA"){let i=n[o+1];if(i?.token.type==="ID"&&i.token.start===s.end){r.push({type:"data-var",value:t.slice(s.start,i.token.end),start:s.start,end:i.token.end}),e=i.token.end,o++;continue}}r.push({type:l,value:t.slice(s.start,s.end),start:s.start,end:s.end}),e=s.end;}return e<t.length&&r.push({type:"text",value:t.slice(e),start:e,end:t.length}),r}function M(t){if(!t)return [];let n=He(t),r=Me(n),e=Ve(r),o=We(e);return ze(t,o).filter(l=>l.value.length>0)}var J=["if","unless","each","with"],he=new Set([...J,"lookup","log","this","else"]),me=new Set(["each","with"]),$e=new Set(["ID","STRING","NUMBER","BOOLEAN","DATA","OPEN_SEXPR"]),be=ne__default.default.Parser,D=be.lexer,Fe=be.terminals_;function j(t){return he.has(t)||t.startsWith("@")}function Xe(t){return $e.has(t.name)}function q(t,n){let r=[],e=true;for(let o=n;o<t.length;o++){let s=t[o];if(s.name==="EQUALS")break;if(s.name==="ID"){if(!e||t[o+1]?.name==="EQUALS")break;r.push(s.text),e=false;}else if(s.name==="SEP")e=true;else break}return r}function Qe(t,n,r,e){return {name:t,path:n,type:r?"block":n.includes(".")||e?"nested":"simple",blockType:r,context:e}}function Ge(t){let n=[],r=null;for(let e of t)me.has(e.helper)&&e.context&&(r||(r=e.context),n.push(e.helper==="each"?`${e.context}[]`:e.context));return n.length===0||!r?null:{root:r,prefix:`${n.join(".")}.`}}function je(t){let n=[],r=t;for(;r.length>0;){let e=qe(r);if(n.push(...e.expressions),e.consumed===r.length)break;let o=r.slice(e.consumed),s=o.search(/\{\{/);if(s===-1)break;r=o.slice(s);}return {expressions:n}}function qe(t){D.setInput(t),D.conditionStack=["INITIAL"];let n=[],r=0,e=false,o=null,s=[];try{for(let l=D.lex();l!==D.EOF;l=D.lex()){let i=Fe[l],h=D.yytext;if(r=D.yylloc?.last_column??r,!(i==="OPEN_RAW_BLOCK"||i==="CLOSE_RAW_BLOCK"||i==="END_RAW_BLOCK")){if(i==="OPEN"||i==="OPEN_UNESCAPED"){e=!0,o="mustache",s=[];continue}if(i==="OPEN_PARTIAL"||i==="OPEN_PARTIAL_BLOCK"){e=!0,o="partial",s=[];continue}if(i==="OPEN_BLOCK"||i==="OPEN_INVERSE"||i==="OPEN_INVERSE_CHAIN"){e=!0,o="block",s=[];continue}if(i==="OPEN_ENDBLOCK"){e=!0,o="endblock",s=[];continue}if(i==="CLOSE"||i==="CLOSE_UNESCAPED"){if(o){let O=s[0]?.text??null;n.push({type:o,tokens:[...s],helperName:O});}e=!1,s=[];continue}e&&s.push({name:i,text:h});}}return {expressions:n,consumed:t.length}}catch{return {expressions:n,consumed:r}}}function Ye(t,n,r){let e=t.tokens;if(e.length===0||e[0]?.name==="DATA")return;let o=e[0]?.text;if(j(o))F(e,1,n,r);else {let s=q(e,0);if(s.length>0){let i=s.length*2-1,h=e[i];h&&Xe(h)?F(e,i,n,r):Y(s,n,r);}}}function Je(t,n,r){let e=t.tokens,o=e[0]?.text;if(me.has(o)){if(e[1]?.name==="OPEN_SEXPR")return F(e,1,n,r),{helper:o,context:""};{let s=1;for(;s<e.length&&e[s].name!=="ID";)s++;if(s<e.length){let l=q(e,s);return l.length>0&&!j(l[0])&&Y(l,n,r,o),{helper:o,context:l[0]||""}}return {helper:o,context:""}}}else if(he.has(o)){if(e[1]?.name==="OPEN_SEXPR")F(e,1,n,r);else {let s=1;for(;s<e.length&&e[s].name!=="ID";)s++;if(s<e.length){let l=q(e,s);l.length>0&&!j(l[0])&&Y(l,n,r,o);}}return {helper:o,context:""}}return {helper:o,context:""}}function Ze(t,n,r){let e=t.tokens,o=1;for(;o<e.length&&(e[o].name==="SEP"||e[o].name==="ID")&&!(e[o].name==="ID"&&e[o-1]?.name!=="SEP");)o++;F(e,o,n,r);}function F(t,n,r,e){for(let o=n;o<t.length;o++){let s=t[o];if(!(s.name==="OPEN_SEXPR"||s.name==="CLOSE_SEXPR")&&s.name!=="DATA"&&t[o-1]?.name!=="DATA"&&s.name!=="EQUALS"&&!(s.name==="ID"&&t[o+1]?.name==="EQUALS")&&s.name==="ID"&&!j(s.text)){if(t[o-1]?.name==="OPEN_SEXPR")continue;let i=q(t,o);i.length>0&&(Y(i,r,e),o+=i.length*2-2);}}}function Y(t,n,r,e){let o=t[0],s=n.contextPrefix&&n.rootContext?{prefix:n.contextPrefix,root:n.rootContext}:null,l,i;s?(l=s.prefix+t.join("."),i=s.root):(l=t.join("."),i=void 0),r.has(l)||r.set(l,Qe(o,l,e,i));}function et(t,n){return n.type==="endblock"&&t.length>0?t.slice(0,-1):t}function tt(t){let n=new Map,r=[];for(let e of t){let o=Ge(r),s={contextPrefix:o?.prefix??null,rootContext:o?.root??null};if(e.type==="mustache")Ye(e,s,n);else if(e.type==="block"){let l=Je(e,s,n);r=[...r,l];}else e.type==="partial"?Ze(e,s,n):e.type==="endblock"&&(r=et(r,e));}return Array.from(n.values())}function re(t){let{expressions:n}=je(t),r=tt(n),e=[...new Set(r.filter(o=>!o.context).map(o=>o.name))];return {variables:r,rootVariables:e}}function nt(t,n,r){if(!n)return t;let e=r?.helpers?ne__default.default.create():ne__default.default;if(r?.helpers)for(let[o,s]of Object.entries(r.helpers))e.registerHelper(o,s);return e.compile(t)(n)}var rt=["direction","boxSizing","width","height","overflowX","overflowY","borderTopWidth","borderRightWidth","borderBottomWidth","borderLeftWidth","borderStyle","paddingTop","paddingRight","paddingBottom","paddingLeft","fontStyle","fontVariant","fontWeight","fontStretch","fontSize","fontSizeAdjust","lineHeight","fontFamily","textAlign","textTransform","textIndent","textDecoration","letterSpacing","wordSpacing","tabSize","MozTabSize","whiteSpace","wordWrap","wordBreak","overflowWrap"];function xe(t,n){let r=getComputedStyle(t),e=document.createElement("div");e.id="hbs-caret-mirror",document.body.appendChild(e);let o=e.style;o.position="absolute",o.visibility="hidden",o.whiteSpace="pre-wrap",o.wordWrap="break-word";for(let b of rt)o[b]=r[b];o.width=`${t.clientWidth}px`,o.height="auto",o.overflow="hidden";let s=t.value.substring(0,n);e.textContent=s;let l=document.createElement("span");l.textContent="\u200B",e.appendChild(l);let i=t.value.substring(n);i&&e.appendChild(document.createTextNode(i));let h=l.getBoundingClientRect(),O=e.getBoundingClientRect(),k={top:h.top-O.top,left:h.left-O.left,height:parseFloat(r.lineHeight)||parseFloat(r.fontSize)*1.2};return document.body.removeChild(e),k}var at=160,se=200,X=10,it=["--hbs-color-text","--hbs-color-border","--hbs-color-placeholder","--hbs-color-focus-ring","--hbs-color-autocomplete-bg","--hbs-color-autocomplete-selected"];function ge({textareaRef:t,containerRef:n,triggerPosition:r,isOpen:e,children:o,listboxId:s}){let[l,i]=react.useState({top:void 0,bottom:void 0,left:0,maxHeight:se,visible:false}),[h,O]=react.useState({});react.useEffect(()=>{if(!e||!n.current)return;let d=getComputedStyle(n.current),A={};for(let c of it){let u=d.getPropertyValue(c).trim();u&&(A[c]=u);}O(A);},[e,n]);let k=react.useCallback(()=>{let d=t.current;if(!d||!e){i(x=>({...x,visible:false}));return}let A=d.getBoundingClientRect(),c=xe(d,r),u=d.scrollTop,S=d.scrollLeft,N=A.top+c.top-u,V=A.left+c.left-S,g=c.height,K=window.innerHeight,ee=window.innerWidth,R=K-N-g-X,Q=N-X,te=R<120&&Q>R,w,U,W;te?(W=Math.min(se,Math.max(80,Q)),U=K-N+X,w=void 0):(W=Math.min(se,Math.max(80,R)),w=N+g,U=void 0);let z=V,G=ee-at-X;z>G&&(z=Math.max(X,G));let a=c.top-u>=0&&c.top-u<d.clientHeight,p=c.left-S>=0&&c.left-S<d.clientWidth;i({top:w,bottom:U,left:z,maxHeight:W,visible:a&&p});},[t,r,e]);if(react.useEffect(()=>{k();},[k]),react.useEffect(()=>{if(!e)return;let d=()=>{k();};return window.addEventListener("scroll",d,true),window.addEventListener("resize",d),()=>{window.removeEventListener("scroll",d,true),window.removeEventListener("resize",d);}},[e,k]),!e||!l.visible)return null;let b={top:l.top,bottom:l.bottom,left:l.left,maxHeight:l.maxHeight,...h};return reactDom.createPortal(jsxRuntime.jsx("div",{id:s,role:"listbox","aria-label":"Autocomplete suggestions",className:"hbs-autocomplete-portal",style:b,children:o}),document.body)}var ut=["this","@index","@first","@last","@key"],ft=["@root"];function dt(t,n){if(!n)return "prefix";let r=t.toLowerCase(),e=n.toLowerCase();return r===e?"exact":r.startsWith(e)?"prefix":r.includes(e)?"partial":"none"}function ht(t,n,r,e,o){let s=[],l=new Set,i=o.lastIndexOf("."),h=i!==-1;h?o.slice(0,i+1):"";let k=h?o.slice(i+1):o,b=(c,u)=>{if(l.has(c))return;let S=dt(c,k);S!=="none"&&(l.add(c),s.push({option:{value:c,type:u},matchType:S}));};if(h){let c=o.slice(0,i).replace(/\[\]$/,"");n.forEach(u=>{let S=u.path.replace(/\[\]/g,"");if(S.startsWith(`${c}.`)){let V=S.slice(c.length+1).split(".")[0];b(V,"variable");}});}else {if(!r){for(let u of J)b(`#${u}`,"block-open");for(let u of J)b(`/${u}`,"block-close");b("else","block-close");}for(let u of t)b(u,"helper");if(e){if(e.isEach)for(let u of ut)b(u,"data-var");for(let u of e.blockParams)b(u,"variable");for(let u of ft)b(u,"data-var");}let c=new Set;for(let u of n){let S=u.path.split(".")[0].replace("[]","");c.add(S);}for(let u of c)b(u,"variable");}let d={"data-var":0,variable:1,helper:2,"block-open":3,"block-close":4},A={exact:0,prefix:1,partial:2,none:3};return s.sort((c,u)=>{let S=A[c.matchType]-A[u.matchType];if(S!==0)return S;let N=d[c.option.type]-d[u.option.type];return N!==0?N:c.option.value.localeCompare(u.option.value)}),s.map(c=>c.option)}function mt(t,n){let r=t.slice(0,n),e=[],o=/\{\{#(each|with)\s+([^\s}]+)(?:\s+as\s*\|([^|]+)\|)?|\{\{\/(each|with)\}\}/g;for(let s of r.matchAll(o))if(s[1]){let l=s[1],i=s[2],O=(s[3]||"").split(/\s+/).filter(Boolean);e.push({type:l,variable:i,blockParams:O,isEach:l==="each"});}else if(s[4]){let l=s[4];for(let i=e.length-1;i>=0;i--)if(e[i].type===l){e.splice(i,1);break}}return e.length>0?e[e.length-1]:null}function bt(t,n){let r=t.slice(0,n),e=r.lastIndexOf("{{!--");if(e!==-1&&r.slice(e).indexOf("--}}")===-1)return true;let o=r.lastIndexOf("{{!");if(o!==-1){let s=r.slice(o);if(!s.startsWith("{{!--")&&s.indexOf("}}")===-1)return true}return false}function xt(t,n){let r=t.slice(0,n),e=t.slice(n),o=r.lastIndexOf("{{");if(o===-1||r.slice(o).includes("}}"))return false;let l=e.indexOf("}}");return l===-1?false:!e.slice(0,l).includes("{{")}function ye({value:t,onChange:n,placeholder:r="Enter template...",readOnly:e=false,className:o="",style:s,theme:l,customHelpers:i=[],autocomplete:h=true,minHeight:O=100}){let k=react.useRef(null),b=react.useRef(null),d=react.useRef(null),A=react.useId(),[c,u]=react.useState({isOpen:false,options:[],selectedIndex:0,triggerStart:0,filterText:"",isRaw:false,contextPath:null}),S=react.useMemo(()=>re(t).variables.map(p=>({path:p.path,context:p.context})),[t]),N=react.useMemo(()=>M(t),[t]),V=react.useMemo(()=>t?N.map(a=>a.type==="text"?a.value:jsxRuntime.jsx("span",{className:`hbs-token-${a.type}`,children:a.value},a.start)):jsxRuntime.jsx("span",{className:"hbs-editor-placeholder",children:r}),[N,t,r]),g=react.useCallback(()=>{u(a=>({...a,isOpen:false}));},[]),K=react.useCallback((a,p)=>{if(!h||e){g();return}if(bt(a,p)||xt(a,p)){g();return}let x=a.slice(0,p).match(/(\{\{\{?)([#/]?[\w.@]*)$/);if(!x){g();return}let y=x[1],f=x[2]||"",C=p-f.length,E=y==="{{{";if(f.includes("}")){g();return}let P=mt(a,p),T=ht(i,S,E,P,f);if(T.length===0){g();return}u({isOpen:true,options:T,selectedIndex:0,triggerStart:C,filterText:f,isRaw:E,contextPath:P});},[h,e,i,S,g]),ee=react.useCallback(a=>{let p=a.target.value;n?.(p),K(p,a.target.selectionStart),d.current&&(d.current.scrollTop=a.target.scrollTop,d.current.scrollLeft=a.target.scrollLeft);},[n,K]),R=react.useCallback(a=>{let p=b.current;if(!p)return;let{triggerStart:m,filterText:x,isRaw:y}=c,f=y?"}}}":"}}",C=x.lastIndexOf("."),E=C!==-1?x.slice(0,C+1):"",P,T;if(a.type==="block-open"&&!y){let L=a.value.slice(1);P=`${a.value} }}{{/${L}}}`,T=a.value.length+1;}else a.type!=="block-close"&&a.value!=="else"?(P=`${E}${a.value}${f}`,T=P.length):(P=`${a.value}${f}`,T=P.length);p.focus(),p.setSelectionRange(m,p.selectionStart),document.execCommand("insertText",false,P);let B=m+T;p.setSelectionRange(B,B),n?.(p.value),g();},[c,n,g]),Q=react.useCallback(a=>{let{scrollTop:p,scrollLeft:m}=a.currentTarget;d.current&&(d.current.scrollTop=p,d.current.scrollLeft=m);},[]),te=react.useCallback(a=>{document.querySelector(".hbs-autocomplete-portal")?.contains(a.relatedTarget)||g();},[g]),w=react.useCallback(()=>{let a=b.current;if(!a||!c.isOpen)return;let p=a.selectionStart;t.slice(0,p).match(/(\{\{\{?)([#/]?[\w.@]*)$/)||g();},[c.isOpen,t,g]),U=react.useCallback(a=>{let p=a.currentTarget;if(a.key==="Tab"){if(c.isOpen){a.preventDefault();let C=c.options[c.selectedIndex];C&&R(C);return}a.preventDefault();let{selectionStart:f}=p;if(a.shiftKey){let E=t.slice(0,f).lastIndexOf(`
3
+ `)+1,T=t.slice(E,f).match(/^(\t| {2})/);if(T){let B=T[1].length,L=t.slice(0,E)+t.slice(E+B);n?.(L);let I=Math.max(E,f-B);setTimeout(()=>p.setSelectionRange(I,I),0);}}else document.execCommand("insertText",false," "),n?.(p.value);return}if((a.metaKey||a.ctrlKey)&&(a.key==="z"||a.key==="y")||!c.isOpen)return;let{options:m,selectedIndex:x}=c,y=8;switch(a.key){case "ArrowDown":a.preventDefault(),u(f=>({...f,selectedIndex:Math.min(x+1,m.length-1)}));break;case "ArrowUp":a.preventDefault(),u(f=>({...f,selectedIndex:Math.max(x-1,0)}));break;case "Home":a.preventDefault(),u(f=>({...f,selectedIndex:0}));break;case "End":a.preventDefault(),u(f=>({...f,selectedIndex:m.length-1}));break;case "PageDown":a.preventDefault(),u(f=>({...f,selectedIndex:Math.min(x+y,m.length-1)}));break;case "PageUp":a.preventDefault(),u(f=>({...f,selectedIndex:Math.max(x-y,0)}));break;case "Enter":a.preventDefault(),m[x]&&R(m[x]);break;case "Escape":a.preventDefault(),g();break;case "ArrowLeft":case "ArrowRight":setTimeout(()=>w(),0);break}},[c,R,g,w,t,n]),W=react.useMemo(()=>{if(!l)return {};let a={},p={variable:"--hbs-color-variable",variablePath:"--hbs-color-variable-path",blockKeyword:"--hbs-color-block-keyword",blockParam:"--hbs-color-block-param",helper:"--hbs-color-helper",helperArg:"--hbs-color-helper-arg",hashKey:"--hbs-color-hash-key",hashValue:"--hbs-color-hash-value",literal:"--hbs-color-literal",dataVar:"--hbs-color-data-var",subexprParen:"--hbs-color-subexpr-paren",comment:"--hbs-color-comment",raw:"--hbs-color-raw",brace:"--hbs-color-brace",text:"--hbs-color-text",background:"--hbs-color-background",caret:"--hbs-color-caret",border:"--hbs-color-border",placeholder:"--hbs-color-placeholder"};for(let[m,x]of Object.entries(p)){let y=l[m];y&&(a[x]=y);}return a},[l]);react.useEffect(()=>{let a=b.current,p=d.current;!a||!p||requestAnimationFrame(()=>{p.scrollTop=a.scrollTop,p.scrollLeft=a.scrollLeft;});},[t]),react.useEffect(()=>{if(!c.isOpen)return;let a=document.querySelector(".hbs-autocomplete-portal");if(!a)return;let m=a.querySelectorAll(".hbs-autocomplete-item")[c.selectedIndex];m&&m.scrollIntoView({block:"nearest"});},[c.selectedIndex,c.isOpen]),react.useEffect(()=>{if(!c.isOpen)return;let a=k.current,p=x=>{let y=x.target;document.querySelector(".hbs-autocomplete-portal")?.contains(y)||a&&!a.contains(y)&&g();},m=x=>{let y=x.target;document.querySelector(".hbs-autocomplete-portal")?.contains(y)||a?.contains(y)&&y!==b.current&&g();};return document.addEventListener("mousedown",p),a?.addEventListener("mousedown",m),()=>{document.removeEventListener("mousedown",p),a?.removeEventListener("mousedown",m);}},[c.isOpen,g]);let z=react.useCallback((a,p)=>{let{filterText:m,selectedIndex:x}=c,y=p===x,f=m.lastIndexOf("."),C=f!==-1?m.slice(f+1):m,E=a.value;(a.type==="block-open"&&E.startsWith("#")||a.type==="block-close"&&E.startsWith("/")||a.type==="data-var"&&E.startsWith("@"))&&(E=E.slice(1));let P,T=C.toLowerCase().replace(/^[#/@]/,""),L=E.toLowerCase().indexOf(T);if(T.length>0&&L!==-1){let $=E.slice(0,L),Se=E.slice(L,L+T.length),Te=E.slice(L+T.length);P=jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[$,jsxRuntime.jsx("span",{className:"hbs-autocomplete-match",children:Se}),Te]});}else P=E;let I="";switch(a.type){case "block-open":I="#";break;case "block-close":I="/";break;case "data-var":I="@";break;case "helper":I="\u0192";break;case "variable":I="\xB7";break}let Oe=jsxRuntime.jsx("span",{className:"hbs-autocomplete-type",children:I});return jsxRuntime.jsxs("button",{id:`${A}-option-${p}`,type:"button",role:"option","aria-selected":y,className:`hbs-autocomplete-item hbs-autocomplete-${a.type} ${y?"hbs-selected":""}`,onMouseDown:$=>{$.preventDefault(),R(a);},onMouseEnter:()=>u($=>({...$,selectedIndex:p})),children:[Oe,jsxRuntime.jsx("span",{className:"hbs-autocomplete-value",children:P})]},a.value)},[c,R,A]),G=["hbs-editor",e?"hbs-readonly":"",o].filter(Boolean).join(" ");return jsxRuntime.jsxs("div",{ref:k,className:G,style:{...W,minHeight:typeof O=="number"?`${O}px`:O,...s},children:[jsxRuntime.jsx("div",{ref:d,className:"hbs-editor-highlight",children:V}),jsxRuntime.jsx("textarea",{ref:b,className:"hbs-editor-textarea",value:t,onChange:ee,onKeyDown:U,onScroll:Q,onBlur:te,onSelect:w,placeholder:"",readOnly:e,spellCheck:false,autoCapitalize:"off",autoComplete:"off",autoCorrect:"off",role:"combobox","aria-haspopup":"listbox","aria-expanded":h&&c.isOpen,"aria-controls":A,"aria-activedescendant":h&&c.isOpen&&c.options[c.selectedIndex]?`${A}-option-${c.selectedIndex}`:void 0}),h&&jsxRuntime.jsx(ge,{textareaRef:b,containerRef:k,triggerPosition:c.triggerStart,isOpen:c.isOpen,listboxId:A,children:c.options.map((a,p)=>z(a,p))})]})}function gt({content:t,className:n}){if(!t)return null;let r=M(t);return jsxRuntime.jsx("span",{className:n,children:r.map(e=>jsxRuntime.jsx("span",{className:`hbs-token-${e.type}`,children:e.value},e.start))})}exports.HandlebarsEditor=ye;exports.HandlebarsHighlight=gt;exports.default=ye;exports.extract=re;exports.interpolate=nt;exports.tokenize=M;
package/dist/index.js CHANGED
@@ -1,4 +1,3 @@
1
- import {useRef,useId,useState,useMemo,useCallback,useEffect}from'react';import ne from'handlebars';import {jsx,jsxs,Fragment}from'react/jsx-runtime';var ue=ne.Parser,M=ue.lexer,Re=ue.terminals_,we=new Set(["OPEN_BLOCK","OPEN_INVERSE","OPEN_INVERSE_CHAIN","OPEN_ENDBLOCK"]),ve=new Set(["OPEN","OPEN_UNESCAPED"]),Be=new Set(["OPEN_PARTIAL","OPEN_PARTIAL_BLOCK"]),De=new Set(["OPEN","OPEN_UNESCAPED","OPEN_BLOCK","OPEN_INVERSE","OPEN_INVERSE_CHAIN","OPEN_ENDBLOCK","OPEN_PARTIAL","OPEN_PARTIAL_BLOCK"]),He=new Set(["CLOSE","CLOSE_UNESCAPED","CLOSE_RAW_BLOCK","END_RAW_BLOCK"]),Me=new Set(["ID","STRING","NUMBER","BOOLEAN","DATA","OPEN_SEXPR","UNDEFINED","NULL"]),fe=t=>we.has(t),he=t=>ve.has(t),de=t=>Be.has(t),Ke=t=>De.has(t),Ve=t=>He.has(t),Ue=t=>Me.has(t),Fe={CONTENT:"text",COMMENT:"comment",OPEN:"brace",CLOSE:"brace",OPEN_UNESCAPED:"brace",CLOSE_UNESCAPED:"brace",OPEN_RAW_BLOCK:"brace",CLOSE_RAW_BLOCK:"brace",END_RAW_BLOCK:"brace",OPEN_BLOCK:"brace",OPEN_INVERSE:"brace",OPEN_INVERSE_CHAIN:"brace",OPEN_ENDBLOCK:"brace",OPEN_PARTIAL:"brace",OPEN_PARTIAL_BLOCK:"brace",OPEN_SEXPR:"subexpr-paren",CLOSE_SEXPR:"subexpr-paren",OPEN_BLOCK_PARAMS:"block-keyword",CLOSE_BLOCK_PARAMS:"block-keyword",INVERSE:"block-keyword",ID:"variable",STRING:"literal",NUMBER:"literal",BOOLEAN:"literal",UNDEFINED:"literal",NULL:"literal",DATA:"data-var",SEP:"brace",EQUALS:"brace"};function pe(t,n,r){let e=0;for(let s=0;s<n-1&&s<t.length;s++)e+=t[s].length+1;return e+r}function We(t){let n=[],r=t.split(`
2
- `);M.setInput(t);try{for(let e=M.lex();e!==M.EOF;e=M.lex()){let s=Re[e]||"UNKNOWN",o=M.yylloc;n.push({type:s,text:M.yytext,start:pe(r,o.first_line,o.first_column),end:pe(r,o.last_line,o.last_column)});}}catch{}return n}function $e(t){return t.map(n=>n.type==="ID"&&n.text==="."?{...n,type:"SEP"}:n.type==="ID"&&n.text==="="?{...n,type:"EQUALS"}:n)}function ze(t){let n=[],r=null,e=false,s=false,o=0;for(let c=0;c<t.length;c++){let i=t[c],E=t[c-1];Ke(i.type)?(fe(i.type)?r=i.type==="OPEN_ENDBLOCK"?"block-close":"block-open":de(i.type)?r="partial":he(i.type)&&(r="mustache"),s=false,o=0):Ve(i.type)&&(r=null,s=false,o=0),i.type==="OPEN_BLOCK_PARAMS"?e=true:i.type==="CLOSE_BLOCK_PARAMS"&&(e=false),i.type==="SEP"?o++:i.type==="ID"&&E?.type!=="SEP"&&E?.type!=="DATA"&&(o=0);let A=false;if(i.type==="ID"){if(o===0)A=s;else for(let P=c-1;P>=0;P--)if(t[P].type==="ID"&&n[P]?.context.pathRootAfterHelper!==void 0){let g=t[P-1];if(g?.type!=="SEP"&&g?.type!=="DATA"){A=n[P].context.pathRootAfterHelper;break}}}n.push({...i,context:{type:r,isInBlockParams:e,pathRootAfterHelper:A}}),i.type==="ID"&&o===0&&!e&&E?.type!=="EQUALS"&&E?.type!=="DATA"&&(s=true);}return n}function Xe(t,n,r){let{context:e}=t;return t.text==="this"?"data-var":e.isInBlockParams?"block-param":r?.type==="EQUALS"?"hash-key":n?.type==="EQUALS"?"hash-value":n?.type==="DATA"?"data-var":n?.type==="SEP"?e.pathRootAfterHelper?"helper-arg":"variable-path":Qe(t,n,r)}function Qe(t,n,r){let{context:e}=t;return e.type==="block-open"||e.type==="block-close"?fe(n?.type??"")?"block-keyword":"helper-arg":e.type==="partial"?de(n?.type??"")?"helper":"helper-arg":n?.type==="OPEN_SEXPR"?"helper":e.type==="mustache"?he(n?.type??"")?r?.type==="SEP"?"variable":r&&Ue(r.type)?"helper":"variable":"helper-arg":"variable"}function Ge(t){return t.map((n,r)=>{let e=t[r-1],s=t[r+1],o;return n.type==="ID"?o=Xe(n,e,s):o=Fe[n.type]||"text",{token:n,highlightType:o}})}function je(t,n){let r=[],e=0;for(let s=0;s<n.length;s++){let{token:o,highlightType:c}=n[s];if(o.start>e&&r.push({type:"text",value:t.slice(e,o.start),start:e,end:o.start}),o.type==="DATA"){let i=n[s+1];if(i?.token.type==="ID"&&i.token.start===o.end){r.push({type:"data-var",value:t.slice(o.start,i.token.end),start:o.start,end:i.token.end}),e=i.token.end,s++;continue}}r.push({type:c,value:t.slice(o.start,o.end),start:o.start,end:o.end}),e=o.end;}return e<t.length&&r.push({type:"text",value:t.slice(e),start:e,end:t.length}),r}function K(t){if(!t)return [];let n=We(t),r=$e(n),e=ze(r),s=Ge(e);return je(t,s).filter(c=>c.value.length>0)}var G=["if","unless","each","with"],me=new Set([...G,"lookup","log","this","else"]),xe=new Set(["each","with"]),qe=new Set(["ID","STRING","NUMBER","BOOLEAN","DATA","OPEN_SEXPR"]),Ee=ne.Parser,D=Ee.lexer,Ye=Ee.terminals_;function z(t){return me.has(t)||t.startsWith("@")}function Je(t){return qe.has(t.name)}function X(t,n){let r=[],e=true;for(let s=n;s<t.length;s++){let o=t[s];if(o.name==="EQUALS")break;if(o.name==="ID"){if(!e||t[s+1]?.name==="EQUALS")break;r.push(o.text),e=false;}else if(o.name==="SEP")e=true;else break}return r}function Ze(t,n,r,e){return {name:t,path:n,type:r?"block":n.includes(".")||e?"nested":"simple",blockType:r,context:e}}function et(t){let n=[],r=null;for(let e of t)xe.has(e.helper)&&e.context&&(r||(r=e.context),n.push(e.helper==="each"?`${e.context}[]`:e.context));return n.length===0||!r?null:{root:r,prefix:`${n.join(".")}.`}}function tt(t){let n=[],r=t;for(;r.length>0;){let e=nt(r);if(n.push(...e.expressions),e.consumed===r.length)break;let s=r.slice(e.consumed),o=s.search(/\{\{/);if(o===-1)break;r=s.slice(o);}return {expressions:n}}function nt(t){D.setInput(t),D.conditionStack=["INITIAL"];let n=[],r=0,e=false,s=null,o=[];try{for(let c=D.lex();c!==D.EOF;c=D.lex()){let i=Ye[c],E=D.yytext;if(r=D.yylloc?.last_column??r,!(i==="OPEN_RAW_BLOCK"||i==="CLOSE_RAW_BLOCK"||i==="END_RAW_BLOCK")){if(i==="OPEN"||i==="OPEN_UNESCAPED"){e=!0,s="mustache",o=[];continue}if(i==="OPEN_PARTIAL"||i==="OPEN_PARTIAL_BLOCK"){e=!0,s="partial",o=[];continue}if(i==="OPEN_BLOCK"||i==="OPEN_INVERSE"||i==="OPEN_INVERSE_CHAIN"){e=!0,s="block",o=[];continue}if(i==="OPEN_ENDBLOCK"){e=!0,s="endblock",o=[];continue}if(i==="CLOSE"||i==="CLOSE_UNESCAPED"){if(s){let A=o[0]?.text??null;n.push({type:s,tokens:[...o],helperName:A});}e=!1,o=[];continue}e&&o.push({name:i,text:E});}}return {expressions:n,consumed:t.length}}catch{return {expressions:n,consumed:r}}}function rt(t,n,r){let e=t.tokens;if(e.length===0||e[0]?.name==="DATA")return;let s=e[0]?.text;if(z(s))W(e,1,n,r);else {let o=X(e,0);if(o.length>0){let i=o.length*2-1,E=e[i];E&&Je(E)?W(e,i,n,r):Q(o,n,r);}}}function ot(t,n,r){let e=t.tokens,s=e[0]?.text;if(xe.has(s)){if(e[1]?.name==="OPEN_SEXPR")return W(e,1,n,r),{helper:s,context:""};{let o=1;for(;o<e.length&&e[o].name!=="ID";)o++;if(o<e.length){let c=X(e,o);return c.length>0&&!z(c[0])&&Q(c,n,r,s),{helper:s,context:c[0]||""}}return {helper:s,context:""}}}else if(me.has(s)){if(e[1]?.name==="OPEN_SEXPR")W(e,1,n,r);else {let o=1;for(;o<e.length&&e[o].name!=="ID";)o++;if(o<e.length){let c=X(e,o);c.length>0&&!z(c[0])&&Q(c,n,r,s);}}return {helper:s,context:""}}return {helper:s,context:""}}function st(t,n,r){let e=t.tokens,s=1;for(;s<e.length&&(e[s].name==="SEP"||e[s].name==="ID")&&!(e[s].name==="ID"&&e[s-1]?.name!=="SEP");)s++;W(e,s,n,r);}function W(t,n,r,e){for(let s=n;s<t.length;s++){let o=t[s];if(!(o.name==="OPEN_SEXPR"||o.name==="CLOSE_SEXPR")&&o.name!=="DATA"&&t[s-1]?.name!=="DATA"&&o.name!=="EQUALS"&&!(o.name==="ID"&&t[s+1]?.name==="EQUALS")&&o.name==="ID"&&!z(o.text)){if(t[s-1]?.name==="OPEN_SEXPR")continue;let i=X(t,s);i.length>0&&(Q(i,r,e),s+=i.length*2-2);}}}function Q(t,n,r,e){let s=t[0],o=n.contextPrefix&&n.rootContext?{prefix:n.contextPrefix,root:n.rootContext}:null,c,i;o?(c=o.prefix+t.join("."),i=o.root):(c=t.join("."),i=void 0),r.has(c)||r.set(c,Ze(s,c,e,i));}function at(t,n){return n.type==="endblock"&&t.length>0?t.slice(0,-1):t}function it(t){let n=new Map,r=[];for(let e of t){let s=et(r),o={contextPrefix:s?.prefix??null,rootContext:s?.root??null};if(e.type==="mustache")rt(e,o,n);else if(e.type==="block"){let c=ot(e,o,n);r=[...r,c];}else e.type==="partial"?st(e,o,n):e.type==="endblock"&&(r=at(r,e));}return Array.from(n.values())}function re(t){let{expressions:n}=tt(t),r=it(n),e=[...new Set(r.filter(s=>!s.context).map(s=>s.name))];return {variables:r,rootVariables:e}}function lt(t,n,r){if(!n)return t;let e=r?.helpers?ne.create():ne;if(r?.helpers)for(let[s,o]of Object.entries(r.helpers))e.registerHelper(s,o);return e.compile(t)(n)}var pt=["this","@index","@first","@last","@key"],ut=["@root"];function ft(t,n){if(!n)return "prefix";let r=t.toLowerCase(),e=n.toLowerCase();return r===e?"exact":r.startsWith(e)?"prefix":r.includes(e)?"partial":"none"}function ht(t,n,r,e,s){let o=[],c=new Set,i=s.lastIndexOf("."),E=i!==-1;E?s.slice(0,i+1):"";let P=E?s.slice(i+1):s,g=(m,l)=>{if(c.has(m))return;let b=ft(m,P);b!=="none"&&(c.add(m),o.push({option:{value:m,type:l},matchType:b}));};if(E){let m=s.slice(0,i).replace(/\[\]$/,"");n.forEach(l=>{let b=l.path.replace(/\[\]/g,"");if(b.startsWith(`${m}.`)){let q=b.slice(m.length+1).split(".")[0];g(q,"variable");}});}else {if(!r){for(let l of G)g(`#${l}`,"block-open");for(let l of G)g(`/${l}`,"block-close");g("else","block-close");}for(let l of t)g(l,"helper");if(e){if(e.isEach)for(let l of pt)g(l,"data-var");for(let l of e.blockParams)g(l,"variable");for(let l of ut)g(l,"data-var");}let m=new Set;for(let l of n){let b=l.path.split(".")[0].replace("[]","");m.add(b);}for(let l of m)g(l,"variable");}let v={"data-var":0,variable:1,helper:2,"block-open":3,"block-close":4},_={exact:0,prefix:1,partial:2,none:3};return o.sort((m,l)=>{let b=_[m.matchType]-_[l.matchType];if(b!==0)return b;let B=v[m.option.type]-v[l.option.type];return B!==0?B:m.option.value.localeCompare(l.option.value)}),o.map(m=>m.option)}function dt(t,n){let r=t.slice(0,n),e=[],s=/\{\{#(each|with)\s+([^\s}]+)(?:\s+as\s*\|([^|]+)\|)?|\{\{\/(each|with)\}\}/g;for(let o of r.matchAll(s))if(o[1]){let c=o[1],i=o[2],A=(o[3]||"").split(/\s+/).filter(Boolean);e.push({type:c,variable:i,blockParams:A,isEach:c==="each"});}else if(o[4]){let c=o[4];for(let i=e.length-1;i>=0;i--)if(e[i].type===c){e.splice(i,1);break}}return e.length>0?e[e.length-1]:null}function mt(t,n){let r=t.slice(0,n),e=r.lastIndexOf("{{!--");if(e!==-1&&r.slice(e).indexOf("--}}")===-1)return true;let s=r.lastIndexOf("{{!");if(s!==-1){let o=r.slice(s);if(!o.startsWith("{{!--")&&o.indexOf("}}")===-1)return true}return false}function xt(t,n){let r=t.slice(0,n),e=t.slice(n),s=r.lastIndexOf("{{");if(s===-1||r.slice(s).includes("}}"))return false;let c=e.indexOf("}}");return c===-1?false:!e.slice(0,c).includes("{{")}function ye({value:t,onChange:n,placeholder:r="Enter template...",readOnly:e=false,className:s="",style:o,theme:c,customHelpers:i=[],autocomplete:E=true,minHeight:A=100}){let P=useRef(null),g=useRef(null),v=useRef(null),_=useRef(null),m=useId(),[l,b]=useState({isOpen:false,options:[],selectedIndex:0,triggerStart:0,filterText:"",isRaw:false,contextPath:null}),[B,q]=useState({top:0,left:0}),se=useMemo(()=>re(t).variables.map(p=>({path:p.path,context:p.context})),[t]),ae=useMemo(()=>K(t),[t]),Oe=useMemo(()=>t?ae.map(a=>a.type==="text"?a.value:jsx("span",{className:`hbs-token-${a.type}`,children:a.value},a.start)):jsx("span",{className:"hbs-editor-placeholder",children:r}),[ae,t,r]),k=useCallback(()=>{b(a=>({...a,isOpen:false}));},[]),ie=useCallback((a,p)=>{if(!E||e){k();return}if(mt(a,p)||xt(a,p)){k();return}let d=a.slice(0,p).match(/(\{\{\{?)([#/]?[\w.@]*)$/);if(!d){k();return}let x=d[1],f=d[2]||"",T=p-f.length,h=x==="{{{";if(f.includes("}")){k();return}let y=dt(a,p),O=ht(i,se,h,y,f);if(O.length===0){k();return}b({isOpen:true,options:O,selectedIndex:0,triggerStart:T,filterText:f,isRaw:h,contextPath:y});},[E,e,i,se,k]),Ae=useCallback(a=>{let p=a.target.value;n?.(p),ie(p,a.target.selectionStart);},[n,ie]),U=useCallback(a=>{let p=g.current;if(!p)return;let{triggerStart:u,filterText:d,isRaw:x}=l,f=x?"}}}":"}}",T=d.lastIndexOf("."),h=T!==-1?d.slice(0,T+1):"",y,O;if(a.type==="block-open"&&!x){let N=a.value.slice(1);y=`${a.value} }}{{/${N}}}`,O=a.value.length+1;}else a.type!=="block-close"&&a.value!=="else"?(y=`${h}${a.value}${f}`,O=y.length):(y=`${a.value}${f}`,O=y.length);p.focus(),p.setSelectionRange(u,p.selectionStart),document.execCommand("insertText",false,y);let I=u+O;p.setSelectionRange(I,I),n?.(p.value),k();},[l,n,k]),Te=useCallback(a=>{let{scrollTop:p,scrollLeft:u}=a.currentTarget;v.current&&(v.current.scrollTop=p,v.current.scrollLeft=u),q({top:p,left:u});},[]),Pe=useCallback(a=>{_.current?.contains(a.relatedTarget)||k();},[k]),Y=useCallback(()=>{let a=g.current;if(!a||!l.isOpen)return;let p=a.selectionStart;t.slice(0,p).match(/(\{\{\{?)([#/]?[\w.@]*)$/)||k();},[l.isOpen,t,k]),Ne=useCallback(a=>{let p=a.currentTarget;if(a.key==="Tab"){if(l.isOpen){a.preventDefault();let T=l.options[l.selectedIndex];T&&U(T);return}a.preventDefault();let{selectionStart:f}=p;if(a.shiftKey){let h=t.slice(0,f).lastIndexOf(`
3
- `)+1,O=t.slice(h,f).match(/^(\t| {2})/);if(O){let I=O[1].length,N=t.slice(0,h)+t.slice(h+I);n?.(N);let S=Math.max(h,f-I);setTimeout(()=>p.setSelectionRange(S,S),0);}}else document.execCommand("insertText",false," "),n?.(p.value);return}if((a.metaKey||a.ctrlKey)&&(a.key==="z"||a.key==="y")||!l.isOpen)return;let{options:u,selectedIndex:d}=l,x=8;switch(a.key){case "ArrowDown":a.preventDefault(),b(f=>({...f,selectedIndex:Math.min(d+1,u.length-1)}));break;case "ArrowUp":a.preventDefault(),b(f=>({...f,selectedIndex:Math.max(d-1,0)}));break;case "Home":a.preventDefault(),b(f=>({...f,selectedIndex:0}));break;case "End":a.preventDefault(),b(f=>({...f,selectedIndex:u.length-1}));break;case "PageDown":a.preventDefault(),b(f=>({...f,selectedIndex:Math.min(d+x,u.length-1)}));break;case "PageUp":a.preventDefault(),b(f=>({...f,selectedIndex:Math.max(d-x,0)}));break;case "Enter":a.preventDefault(),u[d]&&U(u[d]);break;case "Escape":a.preventDefault(),k();break;case "ArrowLeft":case "ArrowRight":setTimeout(()=>Y(),0);break}},[l,U,k,Y,t,n]),J=useMemo(()=>{if(!l.isOpen||!g.current)return null;let a=g.current,p=getComputedStyle(a),u=getComputedStyle(a.parentElement||a);return {lineHeight:parseFloat(p.lineHeight)||20,paddingTop:parseFloat(p.paddingTop)||0,paddingLeft:parseFloat(p.paddingLeft)||0,charWidth:(parseFloat(p.fontSize)||14)*.6,dropdownWidth:parseInt(u.getPropertyValue("--hbs-autocomplete-min-width"),10)||180,dropdownMaxHeight:parseInt(u.getPropertyValue("--hbs-autocomplete-max-height"),10)||200,clientWidth:a.clientWidth,clientHeight:a.clientHeight}},[l.isOpen]),H=useMemo(()=>{if(!l.isOpen||!J)return {top:void 0,bottom:void 0,left:0,maxHeight:200,openUpward:false,visible:false};let{triggerStart:a}=l,{lineHeight:p,paddingTop:u,paddingLeft:d,charWidth:x,dropdownWidth:f,dropdownMaxHeight:T,clientWidth:h,clientHeight:y}=J,I=t.slice(0,a).split(`
4
- `),N=I.length,S=I[I.length-1]?.length||0,R=u+N*p-B.top,C=d+S*x-B.left,$=h-f-10;C>$&&(C=Math.max(10,$));let F=y-R-10,le=R-p-10,ce=F<120&&le>F,Z,ee,te;ce?(te=Math.min(T,Math.max(80,le)),ee=y-R+p,Z=void 0):(te=Math.min(T,Math.max(80,F)),Z=R,ee=void 0);let Le=R>=0&&R<y&&C>=0&&C<h;return {top:Z,bottom:ee,left:C,maxHeight:te,openUpward:ce,visible:Le}},[l,t,B,J]),Se=useMemo(()=>{if(!c)return {};let a={},p={variable:"--hbs-color-variable",variablePath:"--hbs-color-variable-path",blockKeyword:"--hbs-color-block-keyword",blockParam:"--hbs-color-block-param",helper:"--hbs-color-helper",helperArg:"--hbs-color-helper-arg",hashKey:"--hbs-color-hash-key",hashValue:"--hbs-color-hash-value",literal:"--hbs-color-literal",dataVar:"--hbs-color-data-var",subexprParen:"--hbs-color-subexpr-paren",comment:"--hbs-color-comment",raw:"--hbs-color-raw",brace:"--hbs-color-brace",text:"--hbs-color-text",background:"--hbs-color-background",caret:"--hbs-color-caret",border:"--hbs-color-border",placeholder:"--hbs-color-placeholder"};for(let[u,d]of Object.entries(p)){let x=c[u];x&&(a[d]=x);}return a},[c]);useEffect(()=>{if(!l.isOpen||!_.current)return;let u=_.current.querySelectorAll(".hbs-autocomplete-item")[l.selectedIndex];u&&u.scrollIntoView({block:"nearest"});},[l.selectedIndex,l.isOpen]),useEffect(()=>{if(!l.isOpen)return;let a=P.current,p=d=>{let x=d.target;a&&!a.contains(x)&&k();},u=d=>{let x=d.target;a?.contains(x)&&!_.current?.contains(x)&&x!==g.current&&k();};return document.addEventListener("mousedown",p),a?.addEventListener("mousedown",u),()=>{document.removeEventListener("mousedown",p),a?.removeEventListener("mousedown",u);}},[l.isOpen,k]);let Ce=useCallback((a,p)=>{let{filterText:u,selectedIndex:d}=l,x=p===d,f=u.lastIndexOf("."),T=f!==-1?u.slice(f+1):u,h=a.value;(a.type==="block-open"&&h.startsWith("#")||a.type==="block-close"&&h.startsWith("/")||a.type==="data-var"&&h.startsWith("@"))&&(h=h.slice(1));let y,O=T.toLowerCase().replace(/^[#/@]/,""),N=h.toLowerCase().indexOf(O);if(O.length>0&&N!==-1){let C=h.slice(0,N),$=h.slice(N,N+O.length),F=h.slice(N+O.length);y=jsxs(Fragment,{children:[C,jsx("span",{className:"hbs-autocomplete-match",children:$}),F]});}else y=h;let S="";switch(a.type){case "block-open":S="#";break;case "block-close":S="/";break;case "data-var":S="@";break;case "helper":S="\u0192";break;case "variable":S="\xB7";break}let R=jsx("span",{className:"hbs-autocomplete-type",children:S});return jsxs("button",{id:`${m}-option-${p}`,type:"button",role:"option","aria-selected":x,className:`hbs-autocomplete-item hbs-autocomplete-${a.type} ${x?"hbs-selected":""}`,onMouseDown:C=>{C.preventDefault(),U(a);},onMouseEnter:()=>b(C=>({...C,selectedIndex:p})),children:[R,jsx("span",{className:"hbs-autocomplete-value",children:y})]},a.value)},[l,U,m]),Ie=["hbs-editor",e?"hbs-readonly":"",s].filter(Boolean).join(" ");return jsxs("div",{ref:P,className:Ie,style:{...Se,minHeight:typeof A=="number"?`${A}px`:A,...o},children:[jsx("div",{ref:v,className:"hbs-editor-highlight",children:Oe}),jsx("textarea",{ref:g,className:"hbs-editor-textarea",value:t,onChange:Ae,onKeyDown:Ne,onScroll:Te,onBlur:Pe,onSelect:Y,placeholder:"",readOnly:e,spellCheck:false,autoCapitalize:"off",autoComplete:"off",autoCorrect:"off",role:"combobox","aria-haspopup":"listbox","aria-expanded":E&&l.isOpen&&H.visible,"aria-controls":m,"aria-activedescendant":E&&l.isOpen&&l.options[l.selectedIndex]?`${m}-option-${l.selectedIndex}`:void 0}),E&&l.isOpen&&H.visible&&jsx("div",{ref:_,id:m,role:"listbox","aria-label":"Autocomplete suggestions",className:"hbs-autocomplete",style:{top:H.top,bottom:H.bottom,left:H.left,maxHeight:H.maxHeight},children:l.options.map((a,p)=>Ce(a,p))})]})}function bt({content:t,className:n}){if(!t)return null;let r=K(t);return jsx("span",{className:n,children:r.map(e=>jsx("span",{className:`hbs-token-${e.type}`,children:e.value},e.start))})}export{ye as HandlebarsEditor,bt as HandlebarsHighlight,ye as default,re as extract,lt as interpolate,K as tokenize};
1
+ import {useRef,useId,useState,useMemo,useCallback,useEffect}from'react';import ne from'handlebars';import {createPortal}from'react-dom';import {jsx,jsxs,Fragment}from'react/jsx-runtime';var pe=ne.Parser,H=pe.lexer,Pe=pe.terminals_,Ne=new Set(["OPEN_BLOCK","OPEN_INVERSE","OPEN_INVERSE_CHAIN","OPEN_ENDBLOCK"]),Ce=new Set(["OPEN","OPEN_UNESCAPED"]),Re=new Set(["OPEN_PARTIAL","OPEN_PARTIAL_BLOCK"]),Le=new Set(["OPEN","OPEN_UNESCAPED","OPEN_BLOCK","OPEN_INVERSE","OPEN_INVERSE_CHAIN","OPEN_ENDBLOCK","OPEN_PARTIAL","OPEN_PARTIAL_BLOCK"]),Ie=new Set(["CLOSE","CLOSE_UNESCAPED","CLOSE_RAW_BLOCK","END_RAW_BLOCK"]),_e=new Set(["ID","STRING","NUMBER","BOOLEAN","DATA","OPEN_SEXPR","UNDEFINED","NULL"]),ue=t=>Ne.has(t),fe=t=>Ce.has(t),de=t=>Re.has(t),ve=t=>Le.has(t),we=t=>Ie.has(t),De=t=>_e.has(t),Be={CONTENT:"text",COMMENT:"comment",OPEN:"brace",CLOSE:"brace",OPEN_UNESCAPED:"brace",CLOSE_UNESCAPED:"brace",OPEN_RAW_BLOCK:"brace",CLOSE_RAW_BLOCK:"brace",END_RAW_BLOCK:"brace",OPEN_BLOCK:"brace",OPEN_INVERSE:"brace",OPEN_INVERSE_CHAIN:"brace",OPEN_ENDBLOCK:"brace",OPEN_PARTIAL:"brace",OPEN_PARTIAL_BLOCK:"brace",OPEN_SEXPR:"subexpr-paren",CLOSE_SEXPR:"subexpr-paren",OPEN_BLOCK_PARAMS:"block-keyword",CLOSE_BLOCK_PARAMS:"block-keyword",INVERSE:"block-keyword",ID:"variable",STRING:"literal",NUMBER:"literal",BOOLEAN:"literal",UNDEFINED:"literal",NULL:"literal",DATA:"data-var",SEP:"brace",EQUALS:"brace"};function ce(t,n,r){let e=0;for(let o=0;o<n-1&&o<t.length;o++)e+=t[o].length+1;return e+r}function He(t){let n=[],r=t.split(`
2
+ `);H.setInput(t);try{for(let e=H.lex();e!==H.EOF;e=H.lex()){let o=Pe[e]||"UNKNOWN",s=H.yylloc;n.push({type:o,text:H.yytext,start:ce(r,s.first_line,s.first_column),end:ce(r,s.last_line,s.last_column)});}}catch{}return n}function Me(t){return t.map(n=>n.type==="ID"&&n.text==="."?{...n,type:"SEP"}:n.type==="ID"&&n.text==="="?{...n,type:"EQUALS"}:n)}function Ve(t){let n=[],r=null,e=false,o=false,s=0;for(let l=0;l<t.length;l++){let i=t[l],h=t[l-1];ve(i.type)?(ue(i.type)?r=i.type==="OPEN_ENDBLOCK"?"block-close":"block-open":de(i.type)?r="partial":fe(i.type)&&(r="mustache"),o=false,s=0):we(i.type)&&(r=null,o=false,s=0),i.type==="OPEN_BLOCK_PARAMS"?e=true:i.type==="CLOSE_BLOCK_PARAMS"&&(e=false),i.type==="SEP"?s++:i.type==="ID"&&h?.type!=="SEP"&&h?.type!=="DATA"&&(s=0);let O=false;if(i.type==="ID"){if(s===0)O=o;else for(let k=l-1;k>=0;k--)if(t[k].type==="ID"&&n[k]?.context.pathRootAfterHelper!==void 0){let b=t[k-1];if(b?.type!=="SEP"&&b?.type!=="DATA"){O=n[k].context.pathRootAfterHelper;break}}}n.push({...i,context:{type:r,isInBlockParams:e,pathRootAfterHelper:O}}),i.type==="ID"&&s===0&&!e&&h?.type!=="EQUALS"&&h?.type!=="DATA"&&(o=true);}return n}function Ke(t,n,r){let{context:e}=t;return t.text==="this"?"data-var":e.isInBlockParams?"block-param":r?.type==="EQUALS"?"hash-key":n?.type==="EQUALS"?"hash-value":n?.type==="DATA"?"data-var":n?.type==="SEP"?e.pathRootAfterHelper?"helper-arg":"variable-path":Ue(t,n,r)}function Ue(t,n,r){let{context:e}=t;return e.type==="block-open"||e.type==="block-close"?ue(n?.type??"")?"block-keyword":"helper-arg":e.type==="partial"?de(n?.type??"")?"helper":"helper-arg":n?.type==="OPEN_SEXPR"?"helper":e.type==="mustache"?fe(n?.type??"")?r?.type==="SEP"?"variable":r&&De(r.type)?"helper":"variable":"helper-arg":"variable"}function We(t){return t.map((n,r)=>{let e=t[r-1],o=t[r+1],s;return n.type==="ID"?s=Ke(n,e,o):s=Be[n.type]||"text",{token:n,highlightType:s}})}function ze(t,n){let r=[],e=0;for(let o=0;o<n.length;o++){let{token:s,highlightType:l}=n[o];if(s.start>e&&r.push({type:"text",value:t.slice(e,s.start),start:e,end:s.start}),s.type==="DATA"){let i=n[o+1];if(i?.token.type==="ID"&&i.token.start===s.end){r.push({type:"data-var",value:t.slice(s.start,i.token.end),start:s.start,end:i.token.end}),e=i.token.end,o++;continue}}r.push({type:l,value:t.slice(s.start,s.end),start:s.start,end:s.end}),e=s.end;}return e<t.length&&r.push({type:"text",value:t.slice(e),start:e,end:t.length}),r}function M(t){if(!t)return [];let n=He(t),r=Me(n),e=Ve(r),o=We(e);return ze(t,o).filter(l=>l.value.length>0)}var J=["if","unless","each","with"],he=new Set([...J,"lookup","log","this","else"]),me=new Set(["each","with"]),$e=new Set(["ID","STRING","NUMBER","BOOLEAN","DATA","OPEN_SEXPR"]),be=ne.Parser,D=be.lexer,Fe=be.terminals_;function j(t){return he.has(t)||t.startsWith("@")}function Xe(t){return $e.has(t.name)}function q(t,n){let r=[],e=true;for(let o=n;o<t.length;o++){let s=t[o];if(s.name==="EQUALS")break;if(s.name==="ID"){if(!e||t[o+1]?.name==="EQUALS")break;r.push(s.text),e=false;}else if(s.name==="SEP")e=true;else break}return r}function Qe(t,n,r,e){return {name:t,path:n,type:r?"block":n.includes(".")||e?"nested":"simple",blockType:r,context:e}}function Ge(t){let n=[],r=null;for(let e of t)me.has(e.helper)&&e.context&&(r||(r=e.context),n.push(e.helper==="each"?`${e.context}[]`:e.context));return n.length===0||!r?null:{root:r,prefix:`${n.join(".")}.`}}function je(t){let n=[],r=t;for(;r.length>0;){let e=qe(r);if(n.push(...e.expressions),e.consumed===r.length)break;let o=r.slice(e.consumed),s=o.search(/\{\{/);if(s===-1)break;r=o.slice(s);}return {expressions:n}}function qe(t){D.setInput(t),D.conditionStack=["INITIAL"];let n=[],r=0,e=false,o=null,s=[];try{for(let l=D.lex();l!==D.EOF;l=D.lex()){let i=Fe[l],h=D.yytext;if(r=D.yylloc?.last_column??r,!(i==="OPEN_RAW_BLOCK"||i==="CLOSE_RAW_BLOCK"||i==="END_RAW_BLOCK")){if(i==="OPEN"||i==="OPEN_UNESCAPED"){e=!0,o="mustache",s=[];continue}if(i==="OPEN_PARTIAL"||i==="OPEN_PARTIAL_BLOCK"){e=!0,o="partial",s=[];continue}if(i==="OPEN_BLOCK"||i==="OPEN_INVERSE"||i==="OPEN_INVERSE_CHAIN"){e=!0,o="block",s=[];continue}if(i==="OPEN_ENDBLOCK"){e=!0,o="endblock",s=[];continue}if(i==="CLOSE"||i==="CLOSE_UNESCAPED"){if(o){let O=s[0]?.text??null;n.push({type:o,tokens:[...s],helperName:O});}e=!1,s=[];continue}e&&s.push({name:i,text:h});}}return {expressions:n,consumed:t.length}}catch{return {expressions:n,consumed:r}}}function Ye(t,n,r){let e=t.tokens;if(e.length===0||e[0]?.name==="DATA")return;let o=e[0]?.text;if(j(o))F(e,1,n,r);else {let s=q(e,0);if(s.length>0){let i=s.length*2-1,h=e[i];h&&Xe(h)?F(e,i,n,r):Y(s,n,r);}}}function Je(t,n,r){let e=t.tokens,o=e[0]?.text;if(me.has(o)){if(e[1]?.name==="OPEN_SEXPR")return F(e,1,n,r),{helper:o,context:""};{let s=1;for(;s<e.length&&e[s].name!=="ID";)s++;if(s<e.length){let l=q(e,s);return l.length>0&&!j(l[0])&&Y(l,n,r,o),{helper:o,context:l[0]||""}}return {helper:o,context:""}}}else if(he.has(o)){if(e[1]?.name==="OPEN_SEXPR")F(e,1,n,r);else {let s=1;for(;s<e.length&&e[s].name!=="ID";)s++;if(s<e.length){let l=q(e,s);l.length>0&&!j(l[0])&&Y(l,n,r,o);}}return {helper:o,context:""}}return {helper:o,context:""}}function Ze(t,n,r){let e=t.tokens,o=1;for(;o<e.length&&(e[o].name==="SEP"||e[o].name==="ID")&&!(e[o].name==="ID"&&e[o-1]?.name!=="SEP");)o++;F(e,o,n,r);}function F(t,n,r,e){for(let o=n;o<t.length;o++){let s=t[o];if(!(s.name==="OPEN_SEXPR"||s.name==="CLOSE_SEXPR")&&s.name!=="DATA"&&t[o-1]?.name!=="DATA"&&s.name!=="EQUALS"&&!(s.name==="ID"&&t[o+1]?.name==="EQUALS")&&s.name==="ID"&&!j(s.text)){if(t[o-1]?.name==="OPEN_SEXPR")continue;let i=q(t,o);i.length>0&&(Y(i,r,e),o+=i.length*2-2);}}}function Y(t,n,r,e){let o=t[0],s=n.contextPrefix&&n.rootContext?{prefix:n.contextPrefix,root:n.rootContext}:null,l,i;s?(l=s.prefix+t.join("."),i=s.root):(l=t.join("."),i=void 0),r.has(l)||r.set(l,Qe(o,l,e,i));}function et(t,n){return n.type==="endblock"&&t.length>0?t.slice(0,-1):t}function tt(t){let n=new Map,r=[];for(let e of t){let o=Ge(r),s={contextPrefix:o?.prefix??null,rootContext:o?.root??null};if(e.type==="mustache")Ye(e,s,n);else if(e.type==="block"){let l=Je(e,s,n);r=[...r,l];}else e.type==="partial"?Ze(e,s,n):e.type==="endblock"&&(r=et(r,e));}return Array.from(n.values())}function re(t){let{expressions:n}=je(t),r=tt(n),e=[...new Set(r.filter(o=>!o.context).map(o=>o.name))];return {variables:r,rootVariables:e}}function nt(t,n,r){if(!n)return t;let e=r?.helpers?ne.create():ne;if(r?.helpers)for(let[o,s]of Object.entries(r.helpers))e.registerHelper(o,s);return e.compile(t)(n)}var rt=["direction","boxSizing","width","height","overflowX","overflowY","borderTopWidth","borderRightWidth","borderBottomWidth","borderLeftWidth","borderStyle","paddingTop","paddingRight","paddingBottom","paddingLeft","fontStyle","fontVariant","fontWeight","fontStretch","fontSize","fontSizeAdjust","lineHeight","fontFamily","textAlign","textTransform","textIndent","textDecoration","letterSpacing","wordSpacing","tabSize","MozTabSize","whiteSpace","wordWrap","wordBreak","overflowWrap"];function xe(t,n){let r=getComputedStyle(t),e=document.createElement("div");e.id="hbs-caret-mirror",document.body.appendChild(e);let o=e.style;o.position="absolute",o.visibility="hidden",o.whiteSpace="pre-wrap",o.wordWrap="break-word";for(let b of rt)o[b]=r[b];o.width=`${t.clientWidth}px`,o.height="auto",o.overflow="hidden";let s=t.value.substring(0,n);e.textContent=s;let l=document.createElement("span");l.textContent="\u200B",e.appendChild(l);let i=t.value.substring(n);i&&e.appendChild(document.createTextNode(i));let h=l.getBoundingClientRect(),O=e.getBoundingClientRect(),k={top:h.top-O.top,left:h.left-O.left,height:parseFloat(r.lineHeight)||parseFloat(r.fontSize)*1.2};return document.body.removeChild(e),k}var at=160,se=200,X=10,it=["--hbs-color-text","--hbs-color-border","--hbs-color-placeholder","--hbs-color-focus-ring","--hbs-color-autocomplete-bg","--hbs-color-autocomplete-selected"];function ge({textareaRef:t,containerRef:n,triggerPosition:r,isOpen:e,children:o,listboxId:s}){let[l,i]=useState({top:void 0,bottom:void 0,left:0,maxHeight:se,visible:false}),[h,O]=useState({});useEffect(()=>{if(!e||!n.current)return;let d=getComputedStyle(n.current),A={};for(let c of it){let u=d.getPropertyValue(c).trim();u&&(A[c]=u);}O(A);},[e,n]);let k=useCallback(()=>{let d=t.current;if(!d||!e){i(x=>({...x,visible:false}));return}let A=d.getBoundingClientRect(),c=xe(d,r),u=d.scrollTop,S=d.scrollLeft,N=A.top+c.top-u,V=A.left+c.left-S,g=c.height,K=window.innerHeight,ee=window.innerWidth,R=K-N-g-X,Q=N-X,te=R<120&&Q>R,w,U,W;te?(W=Math.min(se,Math.max(80,Q)),U=K-N+X,w=void 0):(W=Math.min(se,Math.max(80,R)),w=N+g,U=void 0);let z=V,G=ee-at-X;z>G&&(z=Math.max(X,G));let a=c.top-u>=0&&c.top-u<d.clientHeight,p=c.left-S>=0&&c.left-S<d.clientWidth;i({top:w,bottom:U,left:z,maxHeight:W,visible:a&&p});},[t,r,e]);if(useEffect(()=>{k();},[k]),useEffect(()=>{if(!e)return;let d=()=>{k();};return window.addEventListener("scroll",d,true),window.addEventListener("resize",d),()=>{window.removeEventListener("scroll",d,true),window.removeEventListener("resize",d);}},[e,k]),!e||!l.visible)return null;let b={top:l.top,bottom:l.bottom,left:l.left,maxHeight:l.maxHeight,...h};return createPortal(jsx("div",{id:s,role:"listbox","aria-label":"Autocomplete suggestions",className:"hbs-autocomplete-portal",style:b,children:o}),document.body)}var ut=["this","@index","@first","@last","@key"],ft=["@root"];function dt(t,n){if(!n)return "prefix";let r=t.toLowerCase(),e=n.toLowerCase();return r===e?"exact":r.startsWith(e)?"prefix":r.includes(e)?"partial":"none"}function ht(t,n,r,e,o){let s=[],l=new Set,i=o.lastIndexOf("."),h=i!==-1;h?o.slice(0,i+1):"";let k=h?o.slice(i+1):o,b=(c,u)=>{if(l.has(c))return;let S=dt(c,k);S!=="none"&&(l.add(c),s.push({option:{value:c,type:u},matchType:S}));};if(h){let c=o.slice(0,i).replace(/\[\]$/,"");n.forEach(u=>{let S=u.path.replace(/\[\]/g,"");if(S.startsWith(`${c}.`)){let V=S.slice(c.length+1).split(".")[0];b(V,"variable");}});}else {if(!r){for(let u of J)b(`#${u}`,"block-open");for(let u of J)b(`/${u}`,"block-close");b("else","block-close");}for(let u of t)b(u,"helper");if(e){if(e.isEach)for(let u of ut)b(u,"data-var");for(let u of e.blockParams)b(u,"variable");for(let u of ft)b(u,"data-var");}let c=new Set;for(let u of n){let S=u.path.split(".")[0].replace("[]","");c.add(S);}for(let u of c)b(u,"variable");}let d={"data-var":0,variable:1,helper:2,"block-open":3,"block-close":4},A={exact:0,prefix:1,partial:2,none:3};return s.sort((c,u)=>{let S=A[c.matchType]-A[u.matchType];if(S!==0)return S;let N=d[c.option.type]-d[u.option.type];return N!==0?N:c.option.value.localeCompare(u.option.value)}),s.map(c=>c.option)}function mt(t,n){let r=t.slice(0,n),e=[],o=/\{\{#(each|with)\s+([^\s}]+)(?:\s+as\s*\|([^|]+)\|)?|\{\{\/(each|with)\}\}/g;for(let s of r.matchAll(o))if(s[1]){let l=s[1],i=s[2],O=(s[3]||"").split(/\s+/).filter(Boolean);e.push({type:l,variable:i,blockParams:O,isEach:l==="each"});}else if(s[4]){let l=s[4];for(let i=e.length-1;i>=0;i--)if(e[i].type===l){e.splice(i,1);break}}return e.length>0?e[e.length-1]:null}function bt(t,n){let r=t.slice(0,n),e=r.lastIndexOf("{{!--");if(e!==-1&&r.slice(e).indexOf("--}}")===-1)return true;let o=r.lastIndexOf("{{!");if(o!==-1){let s=r.slice(o);if(!s.startsWith("{{!--")&&s.indexOf("}}")===-1)return true}return false}function xt(t,n){let r=t.slice(0,n),e=t.slice(n),o=r.lastIndexOf("{{");if(o===-1||r.slice(o).includes("}}"))return false;let l=e.indexOf("}}");return l===-1?false:!e.slice(0,l).includes("{{")}function ye({value:t,onChange:n,placeholder:r="Enter template...",readOnly:e=false,className:o="",style:s,theme:l,customHelpers:i=[],autocomplete:h=true,minHeight:O=100}){let k=useRef(null),b=useRef(null),d=useRef(null),A=useId(),[c,u]=useState({isOpen:false,options:[],selectedIndex:0,triggerStart:0,filterText:"",isRaw:false,contextPath:null}),S=useMemo(()=>re(t).variables.map(p=>({path:p.path,context:p.context})),[t]),N=useMemo(()=>M(t),[t]),V=useMemo(()=>t?N.map(a=>a.type==="text"?a.value:jsx("span",{className:`hbs-token-${a.type}`,children:a.value},a.start)):jsx("span",{className:"hbs-editor-placeholder",children:r}),[N,t,r]),g=useCallback(()=>{u(a=>({...a,isOpen:false}));},[]),K=useCallback((a,p)=>{if(!h||e){g();return}if(bt(a,p)||xt(a,p)){g();return}let x=a.slice(0,p).match(/(\{\{\{?)([#/]?[\w.@]*)$/);if(!x){g();return}let y=x[1],f=x[2]||"",C=p-f.length,E=y==="{{{";if(f.includes("}")){g();return}let P=mt(a,p),T=ht(i,S,E,P,f);if(T.length===0){g();return}u({isOpen:true,options:T,selectedIndex:0,triggerStart:C,filterText:f,isRaw:E,contextPath:P});},[h,e,i,S,g]),ee=useCallback(a=>{let p=a.target.value;n?.(p),K(p,a.target.selectionStart),d.current&&(d.current.scrollTop=a.target.scrollTop,d.current.scrollLeft=a.target.scrollLeft);},[n,K]),R=useCallback(a=>{let p=b.current;if(!p)return;let{triggerStart:m,filterText:x,isRaw:y}=c,f=y?"}}}":"}}",C=x.lastIndexOf("."),E=C!==-1?x.slice(0,C+1):"",P,T;if(a.type==="block-open"&&!y){let L=a.value.slice(1);P=`${a.value} }}{{/${L}}}`,T=a.value.length+1;}else a.type!=="block-close"&&a.value!=="else"?(P=`${E}${a.value}${f}`,T=P.length):(P=`${a.value}${f}`,T=P.length);p.focus(),p.setSelectionRange(m,p.selectionStart),document.execCommand("insertText",false,P);let B=m+T;p.setSelectionRange(B,B),n?.(p.value),g();},[c,n,g]),Q=useCallback(a=>{let{scrollTop:p,scrollLeft:m}=a.currentTarget;d.current&&(d.current.scrollTop=p,d.current.scrollLeft=m);},[]),te=useCallback(a=>{document.querySelector(".hbs-autocomplete-portal")?.contains(a.relatedTarget)||g();},[g]),w=useCallback(()=>{let a=b.current;if(!a||!c.isOpen)return;let p=a.selectionStart;t.slice(0,p).match(/(\{\{\{?)([#/]?[\w.@]*)$/)||g();},[c.isOpen,t,g]),U=useCallback(a=>{let p=a.currentTarget;if(a.key==="Tab"){if(c.isOpen){a.preventDefault();let C=c.options[c.selectedIndex];C&&R(C);return}a.preventDefault();let{selectionStart:f}=p;if(a.shiftKey){let E=t.slice(0,f).lastIndexOf(`
3
+ `)+1,T=t.slice(E,f).match(/^(\t| {2})/);if(T){let B=T[1].length,L=t.slice(0,E)+t.slice(E+B);n?.(L);let I=Math.max(E,f-B);setTimeout(()=>p.setSelectionRange(I,I),0);}}else document.execCommand("insertText",false," "),n?.(p.value);return}if((a.metaKey||a.ctrlKey)&&(a.key==="z"||a.key==="y")||!c.isOpen)return;let{options:m,selectedIndex:x}=c,y=8;switch(a.key){case "ArrowDown":a.preventDefault(),u(f=>({...f,selectedIndex:Math.min(x+1,m.length-1)}));break;case "ArrowUp":a.preventDefault(),u(f=>({...f,selectedIndex:Math.max(x-1,0)}));break;case "Home":a.preventDefault(),u(f=>({...f,selectedIndex:0}));break;case "End":a.preventDefault(),u(f=>({...f,selectedIndex:m.length-1}));break;case "PageDown":a.preventDefault(),u(f=>({...f,selectedIndex:Math.min(x+y,m.length-1)}));break;case "PageUp":a.preventDefault(),u(f=>({...f,selectedIndex:Math.max(x-y,0)}));break;case "Enter":a.preventDefault(),m[x]&&R(m[x]);break;case "Escape":a.preventDefault(),g();break;case "ArrowLeft":case "ArrowRight":setTimeout(()=>w(),0);break}},[c,R,g,w,t,n]),W=useMemo(()=>{if(!l)return {};let a={},p={variable:"--hbs-color-variable",variablePath:"--hbs-color-variable-path",blockKeyword:"--hbs-color-block-keyword",blockParam:"--hbs-color-block-param",helper:"--hbs-color-helper",helperArg:"--hbs-color-helper-arg",hashKey:"--hbs-color-hash-key",hashValue:"--hbs-color-hash-value",literal:"--hbs-color-literal",dataVar:"--hbs-color-data-var",subexprParen:"--hbs-color-subexpr-paren",comment:"--hbs-color-comment",raw:"--hbs-color-raw",brace:"--hbs-color-brace",text:"--hbs-color-text",background:"--hbs-color-background",caret:"--hbs-color-caret",border:"--hbs-color-border",placeholder:"--hbs-color-placeholder"};for(let[m,x]of Object.entries(p)){let y=l[m];y&&(a[x]=y);}return a},[l]);useEffect(()=>{let a=b.current,p=d.current;!a||!p||requestAnimationFrame(()=>{p.scrollTop=a.scrollTop,p.scrollLeft=a.scrollLeft;});},[t]),useEffect(()=>{if(!c.isOpen)return;let a=document.querySelector(".hbs-autocomplete-portal");if(!a)return;let m=a.querySelectorAll(".hbs-autocomplete-item")[c.selectedIndex];m&&m.scrollIntoView({block:"nearest"});},[c.selectedIndex,c.isOpen]),useEffect(()=>{if(!c.isOpen)return;let a=k.current,p=x=>{let y=x.target;document.querySelector(".hbs-autocomplete-portal")?.contains(y)||a&&!a.contains(y)&&g();},m=x=>{let y=x.target;document.querySelector(".hbs-autocomplete-portal")?.contains(y)||a?.contains(y)&&y!==b.current&&g();};return document.addEventListener("mousedown",p),a?.addEventListener("mousedown",m),()=>{document.removeEventListener("mousedown",p),a?.removeEventListener("mousedown",m);}},[c.isOpen,g]);let z=useCallback((a,p)=>{let{filterText:m,selectedIndex:x}=c,y=p===x,f=m.lastIndexOf("."),C=f!==-1?m.slice(f+1):m,E=a.value;(a.type==="block-open"&&E.startsWith("#")||a.type==="block-close"&&E.startsWith("/")||a.type==="data-var"&&E.startsWith("@"))&&(E=E.slice(1));let P,T=C.toLowerCase().replace(/^[#/@]/,""),L=E.toLowerCase().indexOf(T);if(T.length>0&&L!==-1){let $=E.slice(0,L),Se=E.slice(L,L+T.length),Te=E.slice(L+T.length);P=jsxs(Fragment,{children:[$,jsx("span",{className:"hbs-autocomplete-match",children:Se}),Te]});}else P=E;let I="";switch(a.type){case "block-open":I="#";break;case "block-close":I="/";break;case "data-var":I="@";break;case "helper":I="\u0192";break;case "variable":I="\xB7";break}let Oe=jsx("span",{className:"hbs-autocomplete-type",children:I});return jsxs("button",{id:`${A}-option-${p}`,type:"button",role:"option","aria-selected":y,className:`hbs-autocomplete-item hbs-autocomplete-${a.type} ${y?"hbs-selected":""}`,onMouseDown:$=>{$.preventDefault(),R(a);},onMouseEnter:()=>u($=>({...$,selectedIndex:p})),children:[Oe,jsx("span",{className:"hbs-autocomplete-value",children:P})]},a.value)},[c,R,A]),G=["hbs-editor",e?"hbs-readonly":"",o].filter(Boolean).join(" ");return jsxs("div",{ref:k,className:G,style:{...W,minHeight:typeof O=="number"?`${O}px`:O,...s},children:[jsx("div",{ref:d,className:"hbs-editor-highlight",children:V}),jsx("textarea",{ref:b,className:"hbs-editor-textarea",value:t,onChange:ee,onKeyDown:U,onScroll:Q,onBlur:te,onSelect:w,placeholder:"",readOnly:e,spellCheck:false,autoCapitalize:"off",autoComplete:"off",autoCorrect:"off",role:"combobox","aria-haspopup":"listbox","aria-expanded":h&&c.isOpen,"aria-controls":A,"aria-activedescendant":h&&c.isOpen&&c.options[c.selectedIndex]?`${A}-option-${c.selectedIndex}`:void 0}),h&&jsx(ge,{textareaRef:b,containerRef:k,triggerPosition:c.triggerStart,isOpen:c.isOpen,listboxId:A,children:c.options.map((a,p)=>z(a,p))})]})}function gt({content:t,className:n}){if(!t)return null;let r=M(t);return jsx("span",{className:n,children:r.map(e=>jsx("span",{className:`hbs-token-${e.type}`,children:e.value},e.start))})}export{ye as HandlebarsEditor,gt as HandlebarsHighlight,ye as default,re as extract,nt as interpolate,M as tokenize};
package/dist/styles.css CHANGED
@@ -98,14 +98,33 @@
98
98
  padding: var(--hbs-padding);
99
99
  pointer-events: none;
100
100
  color: var(--hbs-color-text);
101
+ /* Explicit font properties to match textarea exactly */
102
+ font-family: inherit;
103
+ font-size: inherit;
104
+ line-height: inherit;
101
105
  tab-size: var(--hbs-tab-size);
102
106
  -moz-tab-size: var(--hbs-tab-size);
103
- scrollbar-width: none;
104
- -ms-overflow-style: none;
107
+ /* Match textarea scrollbar to ensure same content width */
108
+ scrollbar-width: thin;
109
+ scrollbar-color: transparent transparent;
105
110
  }
106
111
 
112
+ /* Match textarea's trailing line space (textareas reserve space for cursor) */
113
+ .hbs-editor-highlight::after {
114
+ content: '\200b';
115
+ display: inline;
116
+ }
117
+
118
+ /* Invisible scrollbar that takes up same space as textarea's */
107
119
  .hbs-editor-highlight::-webkit-scrollbar {
108
- display: none;
120
+ width: 10px;
121
+ height: 10px;
122
+ }
123
+
124
+ .hbs-editor-highlight::-webkit-scrollbar-track,
125
+ .hbs-editor-highlight::-webkit-scrollbar-thumb,
126
+ .hbs-editor-highlight::-webkit-scrollbar-corner {
127
+ background: transparent;
109
128
  }
110
129
 
111
130
  .hbs-editor-highlight code {
@@ -247,23 +266,30 @@
247
266
  text-decoration: wavy underline var(--hbs-color-error);
248
267
  }
249
268
 
250
- /* Autocomplete dropdown */
251
- .hbs-autocomplete {
252
- position: absolute;
253
- z-index: 50;
254
- min-width: var(--hbs-autocomplete-min-width);
269
+ /* Autocomplete dropdown (portal-based, rendered to document.body) */
270
+ .hbs-autocomplete-portal {
271
+ position: fixed;
272
+ z-index: 9999;
273
+ min-width: 160px;
255
274
  max-width: 240px;
256
- max-height: var(--hbs-autocomplete-max-height);
257
275
  overflow: auto;
258
276
  border-radius: 8px;
259
- border: 1px solid var(--hbs-color-border);
260
- background: var(--hbs-color-autocomplete-bg);
261
277
  padding: 4px;
262
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
263
- }
278
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
264
279
 
265
- .hbs-editor.hbs-theme-dark .hbs-autocomplete {
266
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
280
+ /* Default theme values (can be overridden via inline styles) */
281
+ --hbs-color-text: #24292f;
282
+ --hbs-color-border: #d1d5db;
283
+ --hbs-color-placeholder: #6b7280;
284
+ --hbs-color-focus-ring: #2563eb;
285
+ --hbs-color-autocomplete-bg: #ffffff;
286
+ --hbs-color-autocomplete-selected: #f3f4f6;
287
+ --hbs-font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
288
+
289
+ border: 1px solid var(--hbs-color-border);
290
+ background: var(--hbs-color-autocomplete-bg);
291
+ font-family: var(--hbs-font-family);
292
+ color: var(--hbs-color-text);
267
293
  }
268
294
 
269
295
  .hbs-autocomplete-item {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "handlebars-editor-react",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "A React component for editing Handlebars templates with syntax highlighting and autocomplete",
5
5
  "author": "Dogukan Incesu",
6
6
  "license": "MIT",