UNPKG

on-codemerge

Version:

A WYSIWYG editor for on-codemerge is a user-friendly interface that allows users to edit and view their code in real time, exactly as it will appear in the final product

3 lines (2 loc) 9.21 kB
/*! on-codemerge v1.3.1 @author Pavel Kuzmin @license MIT @homepage https://s00d.github.io/on-codemerge/ @repository git+https://github.com/s00d/on-codemerge.git Copyright (c) 2026 Pavel Kuzmin - Built on 2026-07-02T13:39:17.947Z */ "use strict";var y=Object.defineProperty;var L=(p,e,t)=>e in p?y(p,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):p[e]=t;var s=(p,e,t)=>L(p,typeof e!="symbol"?e+"":e,t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class M{constructor(e,t,i={}){s(this,"menu");s(this,"editor");s(this,"activeElement",null);s(this,"subMenus",[]);s(this,"orientation");s(this,"buttons",[]);s(this,"options");s(this,"isVisible",!1);s(this,"longPressTimer",null);s(this,"longPressDelay",500);s(this,"touchStartX",0);s(this,"touchStartY",0);s(this,"handleTouchStart",e=>{e.preventDefault(),this.touchStartX=e.touches[0].clientX,this.touchStartY=e.touches[0].clientY,this.longPressTimer=window.setTimeout(()=>{this.showContextMenu(e.touches[0].clientX,e.touches[0].clientY)},this.longPressDelay)});s(this,"handleTouchMove",e=>{const t=e.touches[0].clientX,i=e.touches[0].clientY,a=Math.abs(t-this.touchStartX),c=Math.abs(i-this.touchStartY);(a>10||c>10)&&this.cancelLongPress()});s(this,"handleTouchEnd",e=>{this.cancelLongPress()});s(this,"handleTouchCancel",e=>{this.cancelLongPress()});s(this,"handleClickOutside",e=>{this.menu.contains(e.target)||this.hide()});s(this,"handleEscapeKey",e=>{e.key==="Escape"&&this.hide()});this.orientation=i.orientation||"vertical",this.buttons=t,this.editor=e,this.options={closeOnClickOutside:!0,closeOnEscape:!0,animation:!0,maxHeight:400,maxWidth:300,...i},this.menu=this.createMenu(),this.editor.getDOMContext().appendChild(this.menu),this.setupEventListeners()}createMenu(){const e=document.createElement("div");return e.className=`context-menu ${this.orientation==="horizontal"?"horizontal":""}`,this.options.maxHeight&&(e.style.maxHeight=`${this.options.maxHeight}px`),this.options.maxWidth&&(e.style.maxWidth=`${this.options.maxWidth}px`),this.buttons.forEach(t=>{if(t.type==="divider"){const i=document.createElement("div");i.className=`menu-divider ${this.orientation==="horizontal"?"horizontal":""}`,e.appendChild(i)}else if(t.type==="group"&&t.groupTitle){const i=document.createElement("div");i.className="menu-group";const a=document.createElement("div");a.className="menu-group-title",a.textContent=t.groupTitle,i.appendChild(a),t.subMenu&&t.subMenu.forEach(c=>{const h=this.createMenuItem(c);h&&i.appendChild(h)}),e.appendChild(i)}else if(t.type==="custom"&&t.customHTML){const i=document.createElement("div");i.className="menu-custom",i.innerHTML=t.customHTML,e.appendChild(i)}else{const i=this.createMenuItem(t);i&&e.appendChild(i)}}),e}createMenuItem(e){const t=document.createElement("button");t.className=`menu-item ${e.className||""}`,t.dataset.action=e.action||"",t.dataset.type=e.type||"button",e.variant&&(t.dataset.type=e.variant),e.title&&(t.title=e.title);const i=e.icon?`<span class="menu-icon">${e.icon}</span>`:"",a=e.label||e.title||"",c=a?`<span class="menu-label">${a}</span>`:"",h=e.hotkey?`<span class="menu-hotkey">${e.hotkey}</span>`:"",d=e.subMenu?'<span class="menu-submenu-indicator">▶</span>':"";if(e.type==="checkbox"||e.type==="radio"){const o=`<span class="menu-${e.type}"></span>`;t.innerHTML=`${o}${i}${c}${h}`,e.checked&&(t.dataset.checked="true")}else t.innerHTML=e.iconPosition==="right"?`${c}${i}${h}${d}`:`${i}${c}${h}${d}`;if(typeof e.disabled=="function"?t.disabled=e.disabled():t.disabled=e.disabled||!1,e.onClick&&t.addEventListener("click",o=>{var n;o.preventDefault(),o.stopPropagation(),(n=e.onClick)==null||n.call(e,this.activeElement),e.closeOnClick!==!1&&this.hide()}),e.subMenu){const o=new M(this.editor,e.subMenu,{...this.options,maxHeight:Math.min(this.options.maxHeight||400,300)});this.subMenus.push(o),t.addEventListener("mouseenter",()=>{this.subMenus.forEach(u=>{u!==o&&u.hide()});const n=t.getBoundingClientRect(),v=n.right+5,f=n.top;o.show(t,v,f)}),t.addEventListener("mouseleave",n=>{setTimeout(()=>{const v=document.elementFromPoint(n.clientX,n.clientY),f=o.menu.contains(v),u=o.menu.contains(n.relatedTarget),l=o.menu.getBoundingClientRect(),r=t.getBoundingClientRect(),m={left:Math.min(r.right,l.left)-10,right:Math.max(r.right,l.left)+10,top:Math.min(r.top,l.top)-10,bottom:Math.max(r.bottom,l.bottom)+10},E=n.clientX>=m.left&&n.clientX<=m.right&&n.clientY>=m.top&&n.clientY<=m.bottom,g=n.clientY>=Math.min(r.top,l.top)-20&&n.clientY<=Math.max(r.bottom,l.bottom)+20;!f&&!u&&!E&&!g&&o.hide()},50)}),o.menu.addEventListener("mouseenter",()=>{}),o.menu.addEventListener("mouseleave",n=>{setTimeout(()=>{const v=document.elementFromPoint(n.clientX,n.clientY),f=t.contains(v),u=t.contains(n.relatedTarget),l=o.menu.getBoundingClientRect(),r=t.getBoundingClientRect(),m={left:Math.min(r.right,l.left)-10,right:Math.max(r.right,l.left)+10,top:Math.min(r.top,l.top)-10,bottom:Math.max(r.bottom,l.bottom)+10},E=n.clientX>=m.left&&n.clientX<=m.right&&n.clientY>=m.top&&n.clientY<=m.bottom,g=n.clientY>=Math.min(r.top,l.top)-20&&n.clientY<=Math.max(r.bottom,l.bottom)+20;!f&&!u&&!E&&!g&&o.hide()},50)})}return t}setupEventListeners(){this.options.closeOnClickOutside&&this.editor.getDOMContext().addEventListener("click",this.handleClickOutside),this.options.closeOnEscape&&this.editor.getDOMContext().addEventListener("keydown",this.handleEscapeKey);let e=0,t=0;this.menu.addEventListener("touchstart",i=>{e=i.touches[0].clientY,t=i.touches[0].clientX}),this.menu.addEventListener("touchmove",i=>{i.preventDefault()}),this.menu.addEventListener("touchend",i=>{const a=i.changedTouches[0].clientY,c=i.changedTouches[0].clientX,h=Math.abs(a-e),d=Math.abs(c-t);(h>50||d>50)&&this.hide()})}setupLongPressListeners(){this.activeElement&&(this.activeElement.removeEventListener("touchstart",this.handleTouchStart),this.activeElement.removeEventListener("touchmove",this.handleTouchMove),this.activeElement.removeEventListener("touchend",this.handleTouchEnd),this.activeElement.removeEventListener("touchcancel",this.handleTouchCancel)),this.activeElement&&(this.activeElement.addEventListener("touchstart",this.handleTouchStart),this.activeElement.addEventListener("touchmove",this.handleTouchMove),this.activeElement.addEventListener("touchend",this.handleTouchEnd),this.activeElement.addEventListener("touchcancel",this.handleTouchCancel))}cancelLongPress(){this.longPressTimer&&(clearTimeout(this.longPressTimer),this.longPressTimer=null)}showContextMenu(e,t){this.activeElement&&this.show(this.activeElement,e,t)}show(e,t,i){this.activeElement=e,this.isVisible=!0,this.setupLongPressListeners(),this.menu.style.display="flex",this.menu.style.flexDirection=this.orientation==="horizontal"?"row":"column",this.options.animation&&(this.menu.style.opacity="0",this.menu.style.transform="translateY(-10px) scale(0.95)"),this.menu.style.left=`${t}px`,this.menu.style.top=`${i}px`,this.options.animation&&requestAnimationFrame(()=>{this.menu.style.opacity="1",this.menu.style.transform="translateY(0) scale(1)"}),requestAnimationFrame(()=>{this.adjustPosition()})}adjustPosition(){const e=this.menu.getBoundingClientRect(),t=window.innerWidth,i=window.innerHeight,a=parseInt(this.menu.style.left),c=parseInt(this.menu.style.top);let h=a,d=c;e.right>t&&(h=a-(e.right-t)-10),e.left<0&&(h=10),e.bottom>i&&(d=c-(e.bottom-i)-10),e.top<0&&(d=10),(h!==a||d!==c)&&(this.menu.style.left=`${h}px`,this.menu.style.top=`${d}px`)}hide(){this.isVisible&&(this.isVisible=!1,this.cancelLongPress(),this.activeElement&&(this.activeElement.removeEventListener("touchstart",this.handleTouchStart),this.activeElement.removeEventListener("touchmove",this.handleTouchMove),this.activeElement.removeEventListener("touchend",this.handleTouchEnd),this.activeElement.removeEventListener("touchcancel",this.handleTouchCancel)),this.subMenus.forEach(e=>e.hide()),this.options.animation?(this.menu.style.opacity="0",this.menu.style.transform="translateY(-10px) scale(0.95)",setTimeout(()=>{this.menu.style.display="none",this.activeElement=null},200)):(this.menu.style.display="none",this.activeElement=null))}updateButtons(e){this.menu.innerHTML="",this.buttons=e,this.menu.appendChild(this.createMenu())}updateButtonState(e,t){const i=this.menu.querySelector(`[data-action="${e}"]`);i&&(Object.assign(i.dataset,t),t.disabled!==void 0&&(i.disabled=typeof t.disabled=="function"?t.disabled():t.disabled),t.checked!==void 0&&(i.dataset.checked=t.checked.toString()))}getElement(){return this.menu}destroy(){this.cancelLongPress(),this.activeElement&&(this.activeElement.removeEventListener("touchstart",this.handleTouchStart),this.activeElement.removeEventListener("touchmove",this.handleTouchMove),this.activeElement.removeEventListener("touchend",this.handleTouchEnd),this.activeElement.removeEventListener("touchcancel",this.handleTouchCancel)),this.options.closeOnClickOutside&&this.editor.getDOMContext().removeEventListener("click",this.handleClickOutside),this.options.closeOnEscape&&this.editor.getDOMContext().removeEventListener("keydown",this.handleEscapeKey),this.subMenus.forEach(e=>e.destroy()),this.menu.parentNode&&this.menu.parentNode.removeChild(this.menu)}}exports.ContextMenu=M;