@softwarity/geojson-editor 1.0.26 → 1.0.27
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/geojson-editor.js +2 -2
- package/package.json +1 -1
- package/src/geojson-editor.ts +219 -11
- package/src/internal-types.ts +2 -0
package/dist/geojson-editor.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @license MIT
|
|
3
3
|
* @name @softwarity/geojson-editor
|
|
4
|
-
* @version 1.0.
|
|
4
|
+
* @version 1.0.27
|
|
5
5
|
* @author Softwarity (https://www.softwarity.io/)
|
|
6
6
|
* @copyright 2025 Softwarity
|
|
7
7
|
* @see https://github.com/softwarity/geojson-editor
|
|
8
8
|
*/
|
|
9
|
-
const e=["type","geometry","properties","coordinates","id","features"],t=["Point","MultiPoint","LineString","MultiLineString","Polygon","MultiPolygon"],i=/"geometry"\s*:/,s=/"properties"\s*:/,n=/"features"\s*:/,o=/^(\s*"[^"]+"\s*:\s*)([{\[])/,r=/^(\s*)([{\[]),?\s*$/,l=/&/g,a=/</g,h=/>/g,c=/([{}[\],:])/g,d=/"([^"]+)"(<span class="json-punctuation">:<\/span>)/g,u=/<span class="geojson-key">"type"<\/span><span class="json-punctuation">:<\/span>(\s*)"([^"]*)"/g,p=/(<span class="json-punctuation">:<\/span>)(\s*)"([^"]*)"/g,g=/(<span class="json-punctuation">:<\/span>)(\s*)(-?\d+\.?\d*(?:e[+-]?\d+)?)/gi,f=/(<span class="json-punctuation">[\[,]<\/span>)(\s*)(-?\d+\.?\d*(?:e[+-]?\d+)?)/gi,m=/^(\s*)(-?\d+\.?\d*(?:e[+-]?\d+)?)/gim,_=/(<span class="json-punctuation">:<\/span>)(\s*)(true|false)/g,b=/(<span class="json-punctuation">:<\/span>)(\s*)(null)/g,v=/(<\/span>|^)([^<]+)(<span|$)/g,C=/^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/,L=/^#?([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])$/,y=/^\s*$/,x=/(\s+)/,k=/"([\w-]+)"\s*:\s*(?:"([^"]*)"|(\btrue\b|\bfalse\b))/g,w=/"([\w-]+)"\s*:\s*(?:"([^"]*)"|(\btrue\b|\bfalse\b))/,S=/"([\w-]+)"\s*:\s*(true|false)/,j=/"type"\s*:\s*"Feature"/,F=/^\s*"([^"]+)"\s*:\s*([{\[])/,E=/^\s*([{\[]),?\s*$/,I=/[{\[]/,T=/[\w-]/,N=/\{/g,R=/\}/g,A=/\[/g,$=/\]/g;function M(e,t){const i="{"===t?"}":"]";let s=0,n=0,o=!1,r=!1;for(const l of e)r?r=!1:"\\"===l&&o?r=!0:'"'!==l?o||(l===t&&s++,l===i&&n++):o=!o;return{open:s,close:n}}function B(e){if(!e||"object"!=typeof e)throw new Error("Feature must be an object");if("Feature"!==e.type)throw new Error('Feature type must be "Feature"');if(!("geometry"in e))throw new Error("Feature must have a geometry property");if(!("properties"in e))throw new Error("Feature must have a properties property");if(null!==e.geometry){if("object"!=typeof e.geometry)throw new Error("Feature geometry must be an object or null");if(!e.geometry.type)throw new Error("Feature geometry must have a type");if(!t.includes(e.geometry.type))throw new Error(`Invalid geometry type: "${e.geometry.type}"`);if(!("coordinates"in e.geometry))throw new Error("Feature geometry must have coordinates")}if(null!==e.properties&&"object"!=typeof e.properties)throw new Error("Feature properties must be an object or null")}function P(e){let t=[];if(Array.isArray(e))t=e;else{if(!e||"object"!=typeof e)throw new Error("Input must be a Feature, array of Features, or FeatureCollection");if("FeatureCollection"===e.type&&"features"in e&&Array.isArray(e.features))t=e.features;else{if("Feature"!==e.type)throw new Error("Input must be a Feature, array of Features, or FeatureCollection");t=[e]}}for(const i of t)B(i);return t}let K=null;function H(e){return",aliceblue,antiquewhite,aqua,aquamarine,azure,beige,bisque,black,blanchedalmond,blue,blueviolet,brown,burlywood,cadetblue,chartreuse,chocolate,coral,cornflowerblue,cornsilk,crimson,cyan,darkblue,darkcyan,darkgoldenrod,darkgray,darkgreen,darkgrey,darkkhaki,darkmagenta,darkolivegreen,darkorange,darkorchid,darkred,darksalmon,darkseagreen,darkslateblue,darkslategray,darkslategrey,darkturquoise,darkviolet,deeppink,deepskyblue,dimgray,dimgrey,dodgerblue,firebrick,floralwhite,forestgreen,fuchsia,gainsboro,ghostwhite,gold,goldenrod,gray,green,greenyellow,grey,honeydew,hotpink,indianred,indigo,ivory,khaki,lavender,lavenderblush,lawngreen,lemonchiffon,lightblue,lightcoral,lightcyan,lightgoldenrodyellow,lightgray,lightgreen,lightgrey,lightpink,lightsalmon,lightseagreen,lightskyblue,lightslategray,lightslategrey,lightsteelblue,lightyellow,lime,limegreen,linen,magenta,maroon,mediumaquamarine,mediumblue,mediumorchid,mediumpurple,mediumseagreen,mediumslateblue,mediumspringgreen,mediumturquoise,mediumvioletred,midnightblue,mintcream,mistyrose,moccasin,navajowhite,navy,oldlace,olive,olivedrab,orange,orangered,orchid,palegoldenrod,palegreen,paleturquoise,palevioletred,papayawhip,peachpuff,peru,pink,plum,powderblue,purple,rebeccapurple,red,rosybrown,royalblue,saddlebrown,salmon,sandybrown,seagreen,seashell,sienna,silver,skyblue,slateblue,slategray,slategrey,snow,springgreen,steelblue,tan,teal,thistle,tomato,turquoise,violet,wheat,white,whitesmoke,yellow,yellowgreen,".includes(","+e.toLowerCase()+",")}function O(i,s,n){if(!i)return"";let L=i,k=null;if(n?.collapseButton?.isCollapsed){const e=i.match(o),t=!e&&i.match(r);e?(L=e[1]+e[2],k=e[2]):t&&(L=t[1]+t[2],k=t[2])}let w=L.replace(l,"&").replace(a,"<").replace(h,">");if(w=w.replace(c,'<span class="json-punctuation">$1</span>'),d.lastIndex=0,w=w.replace(d,(t,i,n)=>"properties"!==s&&e.includes(i)?`<span class="geojson-key">"${i}"</span>${n}`:`<span class="json-key">"${i}"</span>${n}`),"properties"!==s&&(u.lastIndex=0,w=w.replace(u,(e,i,s)=>`<span class="geojson-key">"type"</span><span class="json-punctuation">:</span>${i}<span class="${"Feature"===s||"FeatureCollection"===s||t.includes(s)?"geojson-type":"geojson-type-invalid"}">"${s}"</span>`)),p.lastIndex=0,w=w.replace(p,(e,t,i,s)=>e.includes("geojson-type")||e.includes("json-string")?e:C.test(s)||H(s)?`${t}${i}<span class="json-string json-color" data-color="${s}" style="--swatch-color: ${s}">"${s}"</span>`:`${t}${i}<span class="json-string">"${s}"</span>`),g.lastIndex=0,w=w.replace(g,'$1$2<span class="json-number">$3</span>'),f.lastIndex=0,w=w.replace(f,'$1$2<span class="json-number">$3</span>'),m.lastIndex=0,w=w.replace(m,'$1<span class="json-number">$2</span>'),_.lastIndex=0,w=w.replace(_,(e,t,i,s)=>`${t}${i}<span class="json-boolean${"true"===s?" json-bool-true":" json-bool-false"}">${s}</span>`),b.lastIndex=0,w=w.replace(b,'$1$2<span class="json-null">$3</span>'),k){const e="["===k?"collapsed-bracket-array":"collapsed-bracket-object";w=w.replace(new RegExp(`<span class="json-punctuation">\\${k}<\\/span>$`),`<span class="${e}">${k}</span>`)}return v.lastIndex=0,w=w.replace(v,(e,t,i,s)=>{if(!i||y.test(i))return e;const n=i.split(x);let o=!1;const r=n.map(e=>y.test(e)?e:(o=!0,`<span class="json-error">${e}</span>`)).join("");return o?t+r+s:e}),w}const D=e=>document.createElement(e);class V extends HTMLElement{constructor(){super(),this.lines=[],this.collapsedNodes=/* @__PURE__ */new Set,this.hiddenFeatures=/* @__PURE__ */new Set,this._nodeIdCounter=0,this._lineToNodeId=/* @__PURE__ */new Map,this._nodeIdToLines=/* @__PURE__ */new Map,this._openedNodeKeys=/* @__PURE__ */new Set,this.visibleLines=[],this.lineMetadata=/* @__PURE__ */new Map,this.featureRanges=/* @__PURE__ */new Map,this.viewportHeight=0,this.lineHeight=19.5,this.bufferLines=5,this._lastStartIndex=-1,this._lastEndIndex=-1,this._lastTotalLines=-1,this._scrollRaf=null,this.cursorLine=0,this.cursorColumn=0,this.selectionStart=null,this.selectionEnd=null,this.renderTimer=void 0,this.inputTimer=void 0,this._undoStack=[],this._redoStack=[],this._maxHistorySize=100,this._lastActionTime=0,this._lastActionType=null,this._groupingDelay=500,this._isSelecting=!1,this._isComposing=!1,this._blockRender=!1,this._insertMode=!0,this._charWidth=null,this._contextMapCache=null,this._contextMapLinesLength=0,this._contextMapFirstLine=void 0,this._contextMapLastLine=void 0,this._errorLinesCache=null,this._lastCurrentFeatureIndices=null,this._viewport=null,this._linesContainer=null,this._scrollContent=null,this._hiddenTextarea=null,this._gutterContent=null,this._gutterScrollContent=null,this._gutterScroll=null,this._gutter=null,this._clearBtn=null,this._editorWrapper=null,this._placeholderLayer=null,this._editorPrefix=null,this._editorSuffix=null,this._errorNav=null,this._errorCount=null,this._prevErrorBtn=null,this._nextErrorBtn=null,this.attachShadow({mode:"open"})}_id(e){return this.shadowRoot.getElementById(e)}_invalidateRenderCache(){this._lastStartIndex=-1,this._lastEndIndex=-1,this._lastTotalLines=-1}_createSnapshot(){return{lines:[...this.lines],cursorLine:this.cursorLine,cursorColumn:this.cursorColumn,timestamp:Date.now()}}_restoreSnapshot(e){this.lines=[...e.lines],this.cursorLine=e.cursorLine,this.cursorColumn=e.cursorColumn,this.updateModel(),this._invalidateRenderCache(),this.scheduleRender(),this.updatePlaceholderVisibility(),this.emitChange()}_saveToHistory(e="edit"){const t=Date.now();if(!(e===this._lastActionType&&t-this._lastActionTime<this._groupingDelay)){const e=this._createSnapshot();this._undoStack.push(e),this._undoStack.length>this._maxHistorySize&&this._undoStack.shift(),this._redoStack=[]}this._lastActionTime=t,this._lastActionType=e}undo(){if(0===this._undoStack.length)return!1;this._redoStack.push(this._createSnapshot());const e=this._undoStack.pop();return e&&this._restoreSnapshot(e),this._lastActionType=null,this._lastActionTime=0,!0}redo(){if(0===this._redoStack.length)return!1;this._undoStack.push(this._createSnapshot());const e=this._redoStack.pop();return e&&this._restoreSnapshot(e),this._lastActionType=null,this._lastActionTime=0,!0}clearHistory(){this._undoStack=[],this._redoStack=[],this._lastActionType=null,this._lastActionTime=0}canUndo(){return this._undoStack.length>0}canRedo(){return this._redoStack.length>0}_generateNodeId(){return"node_"+ ++this._nodeIdCounter}_getCollapsedRangeForLine(e){for(const[t,i]of this._nodeIdToLines)if(this.collapsedNodes.has(t)&&e>i.startLine&&e<i.endLine)return{nodeId:t,...i};return null}_getCollapsedClosingLine(e){for(const[t,i]of this._nodeIdToLines)if(this.collapsedNodes.has(t)&&e===i.endLine)return{nodeId:t,...i};return null}_getClosingBracketPos(e){return Math.max(e.lastIndexOf("]"),e.lastIndexOf("}"))}_getCollapsedNodeAtLine(e){const t=this._lineToNodeId.get(e);if(t&&this.collapsedNodes.has(t)){const e=this._nodeIdToLines.get(t);if(e)return{nodeId:t,...e}}return null}_getContainingExpandedNode(e){let t=null;for(const[i,s]of this._nodeIdToLines)this.collapsedNodes.has(i)||e>=s.startLine&&e<=s.endLine&&(!t||s.endLine-s.startLine<t.endLine-t.startLine)&&(t={nodeId:i,...s});return t}_deleteCollapsedNode(e){this._saveToHistory("delete");const t=e.endLine-e.startLine+1;this.lines.splice(e.startLine,t),this.cursorLine=Math.min(e.startLine,this.lines.length-1),this.cursorColumn=0,this.formatAndUpdate()}_rebuildNodeIdMappings(){const e=/* @__PURE__ */new Set;for(const i of this.collapsedNodes){const t=this._nodeIdToLines.get(i);t?.uniqueKey&&e.add(t.uniqueKey)}this._nodeIdCounter=0,this._lineToNodeId.clear(),this._nodeIdToLines.clear(),this.collapsedNodes.clear();const t=/* @__PURE__ */new Map;for(let i=0;i<this.lines.length;i++){const s=this.lines[i],n=s.match(F),o=!n&&s.match(E);if(!n&&!o)continue;let r,l;if(n)r=n[1],l=n[2];else{if(!o)continue;l=o[1],r=`__root_${l}_${i}`}const a=M(s.substring(s.indexOf(l)+1),l);if(a.close>a.open)continue;const h=this._findClosingLine(i,l);if(-1===h||h===i)continue;const c=this._generateNodeId(),d=t.get(r)||0;t.set(r,d+1);const u=`${r}:${d}`;this._lineToNodeId.set(i,c),this._nodeIdToLines.set(c,{startLine:i,endLine:h,nodeKey:r,uniqueKey:u,isRootFeature:!!o}),e.has(u)&&!this._openedNodeKeys.has(u)&&this.collapsedNodes.add(c)}}static get observedAttributes(){return["readonly","value","placeholder","internal-add-shortcut"]}connectedCallback(){this.render(),this._cacheElements(),this.setupEventListeners(),this.updatePrefixSuffix(),this.value&&this.setValue(this.value),this.updatePlaceholderVisibility()}disconnectedCallback(){this.renderTimer&&clearTimeout(this.renderTimer),this.inputTimer&&clearTimeout(this.inputTimer);const e=document.querySelector(".geojson-color-picker-input");e&&(e._closeListener&&document.removeEventListener("click",e._closeListener,!0),e.remove())}attributeChangedCallback(e,t,i){if(t!==i)switch(e){case"value":this.setValue(i);break;case"readonly":this.updateReadonly();break;case"placeholder":this.updatePlaceholderContent()}}get readonly(){return this.hasAttribute("readonly")}get value(){return this.getAttribute("value")||""}get placeholder(){return this.getAttribute("placeholder")||""}get internalAddShortcut(){return this.hasAttribute("internal-add-shortcut")}get prefix(){return'{"type": "FeatureCollection", "features": ['}get suffix(){return"]}"}render(){const e=this.shadowRoot,t=D("style");t.textContent=':host *,:host *:before,:host *:after{box-sizing:border-box;font: 13px/1.5 Courier New,Courier,monospace;font-variant:normal;letter-spacing:0;word-spacing:0;text-transform:none;text-decoration:none;text-indent:0}:host{color-scheme:inherit;--line-height: 19.5px;--gutter-width: 50px;--editor-padding-y: 8px;--editor-padding-x: 12px;display:flex;flex-direction:column;position:relative;width:100%;height:400px;border-radius:4px;overflow:hidden}:host([readonly]) .editor-wrapper:after{content:"";position:absolute;inset:0;pointer-events:none;background:repeating-linear-gradient(-45deg,rgba(128,128,128,.08),rgba(128,128,128,.08) 3px,transparent 3px,transparent 12px);z-index:1}:host([readonly]) .hidden-textarea{cursor:text}.editor-wrapper{position:relative;width:100%;flex:1;background:var(--geojson-editor-bg-color, light-dark(#fff, #2b2b2b));display:flex;overflow:hidden}.gutter{width:var(--gutter-width);background:var(--geojson-editor-gutter-bg, light-dark(#f0f0f0, #313335));border-right:1px solid var(--geojson-editor-gutter-border, light-dark(#e0e0e0, #3c3f41));overflow:hidden;flex-shrink:0;position:relative}.gutter-scroll{position:absolute;inset:0;overflow:hidden;padding:8px 0}.gutter-scroll-content{position:relative;width:100%}.gutter-content{position:absolute;top:0;left:0;right:0;will-change:transform}.gutter-line{height:var(--line-height);display:flex;align-items:center;justify-content:flex-end;padding-right:4px;position:relative}.gutter-line.has-error:before{content:"";position:absolute;right:0;top:0;bottom:0;width:3px;background:var(--geojson-editor-error-color, light-dark(#dc3545, #ff6b68))}.line-number{font-size:11px;color:var(--geojson-editor-gutter-text, light-dark(#999, #606366));-webkit-user-select:none;user-select:none;min-width:20px;text-align:right}.collapse-column{width:16px;display:flex;align-items:center;justify-content:center;flex-shrink:0}.collapse-button{width:12px;height:12px;border-radius:2px;cursor:pointer;flex-shrink:0;background:transparent;border:none;color:var(--geojson-editor-json-punct, light-dark(#000, #a9b7c6));font-size:10px;display:flex;align-items:center;justify-content:center;-webkit-user-select:none;user-select:none;opacity:0;transition:transform .1s,opacity .15s}.collapse-button.collapsed,.gutter:hover .collapse-button{opacity:1}.collapse-button:hover{transform:scale(1.2)}@media(hover:none),(pointer:coarse){.collapse-button{opacity:1}}.editor-content{position:relative;flex:1;overflow:hidden}.hidden-textarea{position:absolute;top:0;left:0;width:100%;height:100%;opacity:0;padding:0;margin:0;border:none;outline:none;resize:none;overflow:hidden;z-index:-1;pointer-events:none;caret-color:transparent}.viewport{position:absolute;inset:0;overflow:auto;padding:var(--editor-padding-y) var(--editor-padding-x);overscroll-behavior:contain;scrollbar-width:thin;scrollbar-color:var(--geojson-editor-control-border, light-dark(#c0c0c0, #5a5a5a)) var(--geojson-editor-control-bg, light-dark(#e8e8e8, #3c3f41))}.scroll-content{position:relative;width:100%}.lines-container{position:absolute;top:0;left:0;right:0;will-change:transform}.line{height:var(--line-height);white-space:pre;display:block;position:relative}.cursor{position:absolute;width:2px;height:1em;background:var(--geojson-editor-caret-color, light-dark(#000, #bbb));top:.15em;pointer-events:none;animation:cursor-blink 1s step-end infinite}.cursor.cursor-block{width:.6em;opacity:.5;animation:cursor-blink-block 1s step-end infinite}@keyframes cursor-blink-block{0%,to{opacity:.5}50%{opacity:.2}}@keyframes cursor-blink{0%,to{opacity:1}50%{opacity:0}}.selection{position:absolute;height:100%;top:0;background:var(--geojson-editor-selection-color, light-dark(rgba(51, 153, 255, .3), rgba(51, 153, 255, .4)));pointer-events:none;z-index:0}.line-hidden>span{opacity:.35;filter:grayscale(50%)}.placeholder-layer{position:absolute;top:var(--editor-padding-y);left:var(--editor-padding-x);color:#6a6a6a;pointer-events:none;z-index:0;white-space:pre}.json-key{color:var(--geojson-editor-json-key, light-dark(#660e7a, #9876aa))}.json-string{color:var(--geojson-editor-json-string, light-dark(#008000, #6a8759))}.json-number{color:var(--geojson-editor-json-number, light-dark(#00f, #6897bb))}.json-boolean,.json-null{color:var(--geojson-editor-json-boolean, light-dark(#000080, #cc7832))}.json-punctuation{color:var(--geojson-editor-json-punct, light-dark(#000, #a9b7c6))}.json-error{color:var(--geojson-editor-json-error, light-dark(#f00, #ff6b68))}.geojson-key{color:var(--geojson-editor-geojson-key, light-dark(#660e7a, #9876aa));font-weight:600}.geojson-type{color:var(--geojson-editor-geojson-type, light-dark(#008000, #6a8759));font-weight:600}.geojson-type-invalid{color:var(--geojson-editor-geojson-type-invalid, light-dark(#f00, #ff6b68));font-weight:600}.collapsed-bracket-array,.collapsed-bracket-object{color:var(--geojson-editor-json-punct, light-dark(#000, #a9b7c6))}.collapsed-bracket-array:after,.collapsed-bracket-object:after{content:"…";color:var(--geojson-editor-json-punct, light-dark(#000, #a9b7c6))}.prefix-wrapper,.suffix-wrapper{display:flex;flex-shrink:0;background:var(--geojson-editor-bg-color, light-dark(#fff, #2b2b2b))}.prefix-gutter,.suffix-gutter{width:var(--gutter-width);background:var(--geojson-editor-gutter-bg, light-dark(#f0f0f0, #313335));border-right:1px solid var(--geojson-editor-gutter-border, light-dark(#e0e0e0, #3c3f41));flex-shrink:0}.editor-prefix,.editor-suffix{flex:1;padding:4px 12px;color:var(--geojson-editor-text-color, light-dark(#000, #a9b7c6));background:var(--geojson-editor-bg-color, light-dark(#fff, #2b2b2b));-webkit-user-select:none;user-select:none;white-space:pre-wrap;word-wrap:break-word;opacity:.6}.prefix-wrapper{border-bottom:1px solid rgba(255,255,255,.1);position:relative}.suffix-wrapper{border-top:1px solid rgba(255,255,255,.1);position:relative}.info-btn{position:absolute;right:.5rem;top:50%;transform:translateY(-50%);background:transparent;border:none;color:var(--geojson-editor-text-color, light-dark(#000, #a9b7c6));opacity:.15;cursor:pointer;font-size:.7rem;width:1rem;height:1rem;padding:0;border-radius:50%;display:flex;align-items:center;justify-content:center;transition:opacity .2s;font-family:sans-serif}.info-btn:hover{opacity:.5}.info-popup{display:none;position:absolute;top:2rem;right:.5rem;z-index:1000;background:var(--geojson-editor-bg-color, light-dark(#fff, #2b2b2b));border:1px solid var(--geojson-editor-gutter-border, light-dark(#e0e0e0, #3c3f41));border-radius:6px;box-shadow:0 4px 12px #00000026;padding:12px 16px;min-width:200px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}.info-popup.visible{display:block}.info-popup-content{text-align:center}.info-popup-title{font-weight:700;font-size:13px;color:var(--geojson-editor-text-color, light-dark(#000, #a9b7c6));margin-bottom:4px}.info-popup-version{display:block;font-size:11px;color:var(--geojson-editor-text-color, light-dark(#000, #a9b7c6));opacity:.6;margin-bottom:8px;text-decoration:none}.info-popup-version:hover{opacity:1;text-decoration:underline!important}.info-popup-copyright{font-size:10px;color:var(--geojson-editor-text-color, light-dark(#000, #a9b7c6));opacity:.5}.clear-btn{position:absolute;right:.5rem;top:50%;transform:translateY(-50%);background:transparent;border:none;color:var(--geojson-editor-text-color, light-dark(#000, #a9b7c6));opacity:.3;cursor:pointer;font-size:.65rem;width:1rem;height:1rem;padding:.15rem 0 0;border-radius:3px;display:flex;align-items:center;justify-content:center;transition:opacity .2s,background .2s}.clear-btn:hover{opacity:.7;background:#ffffff1a}.clear-btn[hidden]{display:none}.error-nav{display:none;align-items:center;gap:4px;margin-right:24px}.error-nav.visible{display:flex}.error-nav-btn{background:transparent;border:none;color:var(--geojson-editor-error-color, light-dark(#dc3545, #ff6b68));cursor:pointer;font-size:8px;width:16px;height:16px;padding:0;display:flex;align-items:center;justify-content:center;opacity:.7;transition:opacity .2s}.error-nav-btn:hover{opacity:1}.error-count{color:var(--geojson-editor-error-color, light-dark(#dc3545, #ff6b68));font-size:11px;min-width:20px;text-align:center}.viewport::-webkit-scrollbar{width:10px;height:10px}.viewport::-webkit-scrollbar-track{background:var(--geojson-editor-control-bg, light-dark(#e8e8e8, #3c3f41))}.viewport::-webkit-scrollbar-thumb{background:var(--geojson-editor-control-border, light-dark(#c0c0c0, #5a5a5a));border-radius:5px}.viewport::-webkit-scrollbar-thumb:hover{background:var(--geojson-editor-control-color, light-dark(#000080, #cc7832))}.json-color,.json-boolean{position:relative}.json-color:before,.json-boolean:before{content:"";position:absolute;left:-8px;top:50%;transform:translateY(-50%);margin-top:-1px;width:8px;height:8px;border-radius:2px;cursor:pointer}.json-color:hover:before,.json-boolean:hover:before{transform:translateY(-50%) scale(1.2);border-color:var(--geojson-editor-control-color, light-dark(#000080, #cc7832))}.json-color:before{background-color:var(--swatch-color);border:1px solid var(--geojson-editor-json-punct, light-dark(#000, #a9b7c6))}.json-boolean:before{border:1.5px solid var(--geojson-editor-control-border, light-dark(#c0c0c0, #5a5a5a));background:transparent}.json-bool-true:before{content:"✔";border-color:var(--geojson-editor-control-color, light-dark(#000080, #cc7832));color:var(--geojson-editor-control-color, light-dark(#000080, #cc7832));font-size:8px;display:flex;align-items:center;justify-content:center;line-height:8px}.line.has-visibility:before{content:"👁";position:absolute;left:0;top:3px;font-size:10px;color:var(--geojson-editor-control-color, light-dark(#000080, #cc7832));opacity:.6;cursor:pointer;z-index:1}.line.has-visibility:hover:before{opacity:1;transform:scale(1.15)}.line.has-visibility.feature-hidden:before{opacity:.5}';const i=D("div");for(i.innerHTML=function(e="",t=""){return`\n <div class="prefix-wrapper">\n <div class="prefix-gutter"></div>\n <div class="editor-prefix" id="editorPrefix"></div>\n <button class="info-btn" id="infoBtn" title="@softwarity/geojson-editor v${t}" aria-label="About">ⓘ</button>\n </div>\n <div class="editor-wrapper">\n <div class="gutter">\n <div class="gutter-scroll" id="gutterScroll">\n <div class="gutter-scroll-content" id="gutterScrollContent">\n <div class="gutter-content" id="gutterContent"></div>\n </div>\n </div>\n </div>\n <div class="editor-content">\n <div class="placeholder-layer" id="placeholderLayer">${i=e,i?i.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">"):""}</div>\n <textarea\n class="hidden-textarea"\n id="hiddenTextarea"\n spellcheck="false"\n autocomplete="off"\n autocorrect="off"\n autocapitalize="off"\n tabindex="0"\n ></textarea>\n <div class="viewport" id="viewport">\n <div class="scroll-content" id="scrollContent">\n <div class="lines-container" id="linesContainer"></div>\n </div>\n </div>\n </div>\n </div>\n <div class="suffix-wrapper">\n <div class="suffix-gutter"></div>\n <div class="editor-suffix" id="editorSuffix"></div>\n <div class="error-nav" id="errorNav">\n <button class="error-nav-btn" id="prevErrorBtn" title="Previous error">◀</button>\n <span class="error-count" id="errorCount"></span>\n <button class="error-nav-btn" id="nextErrorBtn" title="Next error">▶</button>\n </div>\n <button class="clear-btn" id="clearBtn" title="Clear editor">✕</button>\n </div>\n <div class="info-popup" id="infoPopup">\n <div class="info-popup-content">\n <div class="info-popup-title">GeoJSON Editor</div>\n <a class="info-popup-version" href="https://www.npmjs.com/package/@softwarity/geojson-editor/v/${t}" target="_blank" rel="noopener">v${t}</a>\n <div class="info-popup-copyright">© ${/* @__PURE__ */(new Date).getFullYear()} Softwarity</div>\n </div>\n </div>\n `;var i}(this.placeholder,"1.0.26"),e.innerHTML="",e.appendChild(t);i.firstChild;)e.appendChild(i.firstChild)}_cacheElements(){this._viewport=this._id("viewport"),this._linesContainer=this._id("linesContainer"),this._scrollContent=this._id("scrollContent"),this._hiddenTextarea=this._id("hiddenTextarea"),this._gutterContent=this._id("gutterContent"),this._gutterScrollContent=this._id("gutterScrollContent"),this._gutterScroll=this._id("gutterScroll"),this._gutter=this.shadowRoot.querySelector(".gutter"),this._clearBtn=this._id("clearBtn"),this._editorWrapper=this.shadowRoot.querySelector(".editor-wrapper"),this._placeholderLayer=this._id("placeholderLayer"),this._editorPrefix=this._id("editorPrefix"),this._editorSuffix=this._id("editorSuffix"),this._errorNav=this._id("errorNav"),this._errorCount=this._id("errorCount"),this._prevErrorBtn=this._id("prevErrorBtn"),this._nextErrorBtn=this._id("nextErrorBtn")}setupEventListeners(){const e=this._hiddenTextarea,t=this._viewport,i=this._gutterContent,s=this._gutter,n=this._clearBtn,o=this._editorWrapper;if(!(e&&t&&i&&s&&n&&o))return;this._isSelecting=!1,t.addEventListener("click",e=>{this.handleEditorClick(e)},!0),t.addEventListener("mousedown",t=>{const i=t.target,s=i.closest(".line.has-visibility");if(s){const e=s.getBoundingClientRect();if(t.clientX-e.left<14)return void(this._blockRender=!0)}if(i.classList.contains("json-color")||i.classList.contains("json-boolean")){const e=i.getBoundingClientRect(),s=t.clientX-e.left;if(s<0&&s>=-8)return void(this._blockRender=!0)}if(t.preventDefault(),2===t.detail){const i=this._getPositionFromClick(t);return this._selectWordAt(i.line,i.column),this._isSelecting=!1,e.focus(),this._invalidateRenderCache(),void this.scheduleRender()}const n=this._getPositionFromClick(t);t.shiftKey&&this.selectionStart?(this.selectionEnd=n,this.cursorLine=n.line,this.cursorColumn=n.column):(this.cursorLine=n.line,this.cursorColumn=n.column,this.selectionStart={line:n.line,column:n.column},this.selectionEnd=null,this._isSelecting=!0),e.focus(),this._invalidateRenderCache(),this.scheduleRender()});let r=null;const l=()=>{r&&(clearInterval(r),r=null)},a=e=>{l(),r=setInterval(()=>{this._isSelecting?("up"===e?t.scrollTop-=20:t.scrollTop+=20,this._updateSelectionFromScroll(e),this._invalidateRenderCache(),this.scheduleRender()):l()},50)};document.addEventListener("mousemove",e=>{if(!this._isSelecting)return;const i=t.getBoundingClientRect();if(e.clientY<i.top)a("up");else if(e.clientY>i.bottom)a("down");else{l();const s=this._getPositionFromClick(e);this.selectionEnd=s,this.cursorLine=s.line,this.cursorColumn=s.column,e.clientY<i.top+30?t.scrollTop-=20:e.clientY>i.bottom-30&&(t.scrollTop+=20),this._invalidateRenderCache(),this.scheduleRender()}}),document.addEventListener("mouseup",()=>{this._isSelecting=!1,l()}),e.addEventListener("focus",()=>{o.classList.add("focused"),this._invalidateRenderCache(),this.scheduleRender(),this._emitCurrentFeature(!0)}),e.addEventListener("blur",()=>{o.classList.remove("focused"),this._invalidateRenderCache(),this.scheduleRender(),this._emitCurrentFeatureNull()});let h=!1;t.addEventListener("scroll",()=>{h||(this.syncGutterScroll(),this._scrollRaf||(this._scrollRaf=requestAnimationFrame(()=>{this._scrollRaf=null,h=!0,this.renderViewport(),h=!1})))}),e.addEventListener("compositionstart",()=>{this._isComposing=!0}),e.addEventListener("compositionend",()=>{this._isComposing=!1,this.handleInput()}),e.addEventListener("input",()=>{this._isComposing||this.handleInput()}),e.addEventListener("keydown",e=>{this.handleKeydown(e)}),e.addEventListener("paste",e=>{this.handlePaste(e)}),e.addEventListener("copy",e=>{this.handleCopy(e)}),e.addEventListener("cut",e=>{this.handleCut(e)}),i.addEventListener("click",e=>{this.handleGutterClick(e)}),s.addEventListener("mousedown",e=>{e.preventDefault()}),s.addEventListener("wheel",e=>{e.preventDefault(),t.scrollTop+=e.deltaY}),n.addEventListener("click",()=>{this.removeAll()});const c=this._id("infoBtn"),d=this._id("infoPopup");c&&d&&(c.addEventListener("click",e=>{e.stopPropagation(),d.classList.toggle("visible")}),document.addEventListener("click",()=>{d.classList.remove("visible")})),this._prevErrorBtn?.addEventListener("click",()=>{this.goToPrevError()}),this._nextErrorBtn?.addEventListener("click",()=>{this.goToNextError()}),this.updateReadonly()}setValue(e,t=!0){if(this.lines.length>0&&this._saveToHistory("setValue"),e&&e.trim())try{const t="["+e+"]",i=JSON.parse(t),s=JSON.stringify(i,null,2).split("\n");this.lines=s.slice(1,-1)}catch(i){this.lines=e.split("\n")}else this.lines=[];this.collapsedNodes.clear(),this.hiddenFeatures.clear(),this._openedNodeKeys.clear(),this._lineToNodeId.clear(),this._nodeIdToLines.clear(),this.cursorLine=0,this.cursorColumn=0,this.updateModel(),this.scheduleRender(),this.updatePlaceholderVisibility(),t&&this.lines.length>0&&requestAnimationFrame(()=>{this.autoCollapseCoordinates()}),this.emitChange()}getContent(){return this.lines.join("\n")}updateModel(){this._contextMapCache=null,this._errorLinesCache=null,this._rebuildNodeIdMappings(),this.computeFeatureRanges(),this.computeLineMetadata(),this.computeVisibleLines()}updateView(){this.computeLineMetadata(),this.computeVisibleLines()}computeFeatureRanges(){this.featureRanges.clear();try{const e=this.lines.join("\n"),t=this.prefix+e+this.suffix;if(!JSON.parse(t).features)return;let i=0,s=0,n=!1,o=-1;for(let r=0;r<this.lines.length;r++){const e=this.lines[r];if(!n&&j.test(e)){let e=r;for(let t=r;t>=0;t--){const i=this.lines[t].trim();if("{"===i||"{,"===i){e=t;break}}o=e,n=!0,s=1;for(let t=e;t<=r;t++){const i=M(this.lines[t],"{");s+=t===e?i.open-1-i.close:i.open-i.close}}else if(n){const t=M(e,"{");s+=t.open-t.close,s<=0&&(this.featureRanges.set(i,{startLine:o,endLine:r,featureIndex:i}),i++,n=!1)}}}catch(e){}}computeLineMetadata(){this.lineMetadata.clear();const e=this._findCollapsibleRanges(),t=this._computeErrorLines();for(let i=0;i<this.lines.length;i++){const s=this.lines[i],n={colors:[],booleans:[],collapseButton:null,visibilityButton:null,isHidden:!1,isCollapsed:!1,featureIndex:null,hasError:t.has(i)};let o;for(k.lastIndex=0;null!==(o=k.exec(s));){const[,e,t,i]=o;i?n.booleans.push({attributeName:e,value:"true"===i}):t&&(C.test(t)||H(t))&&n.colors.push({attributeName:e,color:t})}const r=e.find(e=>e.startLine===i);r&&(n.collapseButton={nodeKey:r.nodeKey,nodeId:r.nodeId,isCollapsed:this.collapsedNodes.has(r.nodeId)}),e.find(e=>this.collapsedNodes.has(e.nodeId)&&i>e.startLine&&i<e.endLine)&&(n.isCollapsed=!0);for(const[e,t]of this.featureRanges)if(i>=t.startLine&&i<=t.endLine){n.featureIndex=e,this.hiddenFeatures.has(e)&&(n.isHidden=!0),i===t.startLine&&(n.visibilityButton={featureIndex:e,isHidden:this.hiddenFeatures.has(e)});break}this.lineMetadata.set(i,n)}}_computeErrorLines(){if(null!==this._errorLinesCache)return this._errorLinesCache;const e=/* @__PURE__ */new Set;for(let i=0;i<this.lines.length;i++)O(this.lines[i],"",void 0).includes("json-error")&&e.add(i);try{const e="["+this.lines.join("\n")+"]";JSON.parse(e)}catch(t){if(t instanceof Error){const i=t.message.match(/line (\d+)/);if(i){const t=Math.max(0,parseInt(i[1],10)-1);e.add(t)}}}return this._errorLinesCache=e,e}_getErrorLines(){const e=[];for(const[t,i]of this.lineMetadata)i.hasError&&e.push(t);return e.sort((e,t)=>e-t)}goToNextError(){const e=this._getErrorLines();if(0===e.length)return!1;const t=e.find(e=>e>this.cursorLine),i=void 0!==t?t:e[0];return this._goToErrorLine(i)}goToPrevError(){const e=this._getErrorLines();if(0===e.length)return!1;const t=e.filter(e=>e<this.cursorLine),i=t.length>0?t[t.length-1]:e[e.length-1];return this._goToErrorLine(i)}_expandNodesContainingLine(e){let t=!1;for(const[i,s]of this._nodeIdToLines)this.collapsedNodes.has(i)&&e>s.startLine&&e<=s.endLine&&(this.collapsedNodes.delete(i),s.uniqueKey&&this._openedNodeKeys.add(s.uniqueKey),t=!0);return t}_goToErrorLine(e){return this._expandNodesContainingLine(e)&&this.updateView(),this.cursorLine=e,this.cursorColumn=0,this._invalidateRenderCache(),this._scrollToCursor(!0),this.renderViewport(),this._updateErrorDisplay(),this._hiddenTextarea?.focus(),!0}_expandErrorNodes(){const e=this._getErrorLines();if(0===e.length)return;let t=!1;for(const i of e)this._expandNodesContainingLine(i)&&(t=!0);t&&this.updateView()}computeVisibleLines(){this.visibleLines=[];for(let e=0;e<this.lines.length;e++){const t=this.lineMetadata.get(e);t&&t.isCollapsed||this.visibleLines.push({index:e,content:this.lines[e],meta:t})}this._invalidateRenderCache()}scheduleRender(){this.renderTimer||(this.renderTimer=requestAnimationFrame(()=>{this.renderTimer=void 0,this.renderViewport()}))}renderViewport(){if(this._blockRender)return;const e=this._viewport,t=this._linesContainer,i=this._scrollContent;if(!e||!t)return;this.viewportHeight=e.clientHeight;const s=this.visibleLines.length,n=s*this.lineHeight;if(i){i.style.height=`${n}px`;const e=this._getCharWidth(),t=this.lines.reduce((e,t)=>Math.max(e,t.length),0)*e+20;i.style.minWidth=`${t}px`}const o=e.scrollTop,r=Math.floor(o/this.lineHeight),l=Math.ceil(this.viewportHeight/this.lineHeight),a=Math.max(0,r-this.bufferLines),h=Math.min(s,r+l+this.bufferLines);if(s>0&&this._lastStartIndex===a&&this._lastEndIndex===h&&this._lastTotalLines===s)return;this._lastStartIndex=a,this._lastEndIndex=h,this._lastTotalLines=s;const c=a*this.lineHeight;t.style.transform=`translateY(${c}px)`;const d=this._buildContextMap(),u=this._editorWrapper?.classList.contains("focused"),p=document.createDocumentFragment();if(0===s){const e=D("div");return e.className="line empty-line",e.dataset.lineIndex="0",u&&(e.innerHTML=this._insertCursor(0)),p.appendChild(e),t.innerHTML="",t.appendChild(p),void this.renderGutter(0,0)}for(let g=a;g<h;g++){const e=this.visibleLines[g];if(!e)continue;const t=D("div");t.className="line",t.dataset.lineIndex=String(e.index),e.meta?.visibilityButton&&(t.classList.add("has-visibility"),t.dataset.featureIndex=String(e.meta.visibilityButton.featureIndex),e.meta.visibilityButton.isHidden&&t.classList.add("feature-hidden")),e.meta?.isHidden&&t.classList.add("line-hidden");const i=d.get(e.index)||"Feature";let s=O(e.content,i,e.meta);u&&this._hasSelection()&&(s=this._addSelectionHighlight(s,e.index,e.content)),u&&e.index===this.cursorLine&&(s+=this._insertCursor(this.cursorColumn)),t.innerHTML=s,p.appendChild(t)}t.innerHTML="",t.appendChild(p),this.renderGutter(a,h),this._editorWrapper?.classList.contains("focused")&&this._emitCurrentFeature()}_insertCursor(e){const t=this._getCharWidth(),i=e*t;return this._insertMode?`<span class="cursor" style="left: ${i}px"></span>`:`<span class="cursor cursor-block" style="left: ${i}px; width: ${t}px"></span>`}_addSelectionHighlight(e,t,i){const s=this._normalizeSelection();if(!s)return e;const{start:n,end:o}=s;if(t<n.line||t>o.line)return e;const r=this._getCharWidth();let l,a;return t===n.line&&t===o.line?(l=n.column,a=o.column):t===n.line?(l=n.column,a=i.length):t===o.line?(l=0,a=o.column):(l=0,a=i.length),`<span class="selection" style="left: ${l*r}px; width: ${(a-l)*r}px"></span>`+e}_getCharWidth(){if(!this._charWidth){const e=D("canvas").getContext("2d");e?(e.font="13px 'Courier New', Courier, monospace",this._charWidth=e.measureText("M").width):this._charWidth=7.8}return this._charWidth}renderGutter(e,t){const i=this._gutterContent,s=this._gutterScrollContent;if(!i)return;const n=this.visibleLines.length*this.lineHeight;s&&(s.style.height=`${n}px`);const o=e*this.lineHeight;i.style.transform=`translateY(${o}px)`;const r=document.createDocumentFragment();for(let l=e;l<t;l++){const e=this.visibleLines[l];if(!e)continue;const t=D("div");t.className="gutter-line";const i=e.meta;i?.hasError&&t.classList.add("has-error");const s=D("span");s.className="line-number",s.textContent=String(e.index+1),t.appendChild(s);const n=D("div");if(n.className="collapse-column",i?.collapseButton){const t=D("div");t.className="collapse-button"+(i.collapseButton.isCollapsed?" collapsed":""),t.textContent=i.collapseButton.isCollapsed?"›":"⌄",t.dataset.line=String(e.index),t.dataset.nodeId=i.collapseButton.nodeId,t.title=i.collapseButton.isCollapsed?"Expand":"Collapse",n.appendChild(t)}t.appendChild(n),r.appendChild(t)}i.innerHTML="",i.appendChild(r)}syncGutterScroll(){this._gutterScroll&&this._viewport&&(this._gutterScroll.scrollTop=this._viewport.scrollTop)}handleInput(){const e=this._hiddenTextarea,t=e?.value;if(t)if(this._hasSelection()&&this._deleteSelection(),this._getCollapsedRangeForLine(this.cursorLine))e.value="";else{if(this._getCollapsedClosingLine(this.cursorLine)){const t=this.lines[this.cursorLine],i=this._getClosingBracketPos(t);if(this.cursorColumn<=i)return void(e.value="")}if(this._getCollapsedNodeAtLine(this.cursorLine)){const t=this.lines[this.cursorLine].search(I);if(this.cursorColumn>t)return void(e.value="")}if(this.cursorLine<this.lines.length){const e=this.lines[this.cursorLine],i=e.substring(0,this.cursorColumn),s=t.split("\n");if(1===s.length){if(this._insertMode){const s=e.substring(this.cursorColumn);this.lines[this.cursorLine]=i+t+s}else{const s=e.substring(this.cursorColumn+t.length);this.lines[this.cursorLine]=i+t+s}this.cursorColumn+=t.length}else{const t=e.substring(this.cursorColumn);this.lines[this.cursorLine]=i+s[0];for(let e=1;e<s.length-1;e++)this.lines.splice(this.cursorLine+e,0,s[e]);const n=s[s.length-1]+t;this.lines.splice(this.cursorLine+s.length-1,0,n),this.cursorLine+=s.length-1,this.cursorColumn=s[s.length-1].length}}else{const e=t.split("\n");this.lines.push(...e),this.cursorLine=this.lines.length-1,this.cursorColumn=this.lines[this.cursorLine].length}e.value="",clearTimeout(this.inputTimer),this.inputTimer=setTimeout(()=>{this.formatAndUpdate()},150)}}handleKeydown(e){const t={inCollapsedZone:this._getCollapsedRangeForLine(this.cursorLine),onCollapsedNode:this._getCollapsedNodeAtLine(this.cursorLine),onClosingLine:this._getCollapsedClosingLine(this.cursorLine)},i={Enter:()=>this._handleEnter(e.shiftKey,t),Backspace:()=>this._handleBackspace(t),Delete:()=>this._handleDelete(t),ArrowUp:()=>this._handleArrowKey(-1,0,e.shiftKey,e.ctrlKey||e.metaKey),ArrowDown:()=>this._handleArrowKey(1,0,e.shiftKey,e.ctrlKey||e.metaKey),ArrowLeft:()=>this._handleArrowKey(0,-1,e.shiftKey,e.ctrlKey||e.metaKey),ArrowRight:()=>this._handleArrowKey(0,1,e.shiftKey,e.ctrlKey||e.metaKey),Home:()=>this._handleHomeEnd("home",e.shiftKey,e.ctrlKey||e.metaKey,t.onClosingLine),End:()=>this._handleHomeEnd("end",e.shiftKey,e.ctrlKey||e.metaKey,t.onClosingLine),PageUp:()=>this._handlePageUpDown("up",e.shiftKey),PageDown:()=>this._handlePageUpDown("down",e.shiftKey),Tab:()=>this._handleTab(e.shiftKey,t),Insert:()=>{this._insertMode=!this._insertMode,this.scheduleRender()}},s={a:()=>this._selectAll(),z:()=>e.shiftKey?this.redo():this.undo(),y:()=>this.redo(),s:()=>this.save(),o:()=>!this.hasAttribute("readonly")&&this.open(),i:()=>this.internalAddShortcut&&!this.readonly&&this._handleAddFeaturePrompt()};if(i[e.key])return e.preventDefault(),e.stopPropagation(),void i[e.key]();(e.ctrlKey||e.metaKey)&&s[e.key]&&(e.preventDefault(),e.stopPropagation(),s[e.key]())}_handleEnter(e,t){if(e){const e=this._getContainingExpandedNode(this.cursorLine);if(e){const t=this.lines[e.startLine],i=t.search(I);this.toggleCollapse(e.nodeId),this.cursorLine=e.startLine,this.cursorColumn=i>=0?i+1:t.length,this._clearSelection(),this._scrollToCursor()}return}if(t.onCollapsedNode)this.toggleCollapse(t.onCollapsedNode.nodeId);else{if(t.onClosingLine){const e=this.lines[this.cursorLine],i=this._getClosingBracketPos(e);if(i>=0&&this.cursorColumn<=i)return void this.toggleCollapse(t.onClosingLine.nodeId)}t.inCollapsedZone}}_handleBackspace(e){if(this._hasSelection())return this._deleteSelection(),void this.formatAndUpdate();if(e.onClosingLine){const t=this.lines[this.cursorLine],i=this._getClosingBracketPos(t);return i>=0&&this.cursorColumn>i+1?void this.deleteBackward():void this._deleteCollapsedNode(e.onClosingLine)}if(e.onCollapsedNode&&0===this.cursorColumn)this._deleteCollapsedNode(e.onCollapsedNode);else if(!e.inCollapsedZone){if(e.onCollapsedNode){const t=this.lines[this.cursorLine].search(I);if(this.cursorColumn>t+1)return void this._deleteCollapsedNode(e.onCollapsedNode)}this.deleteBackward()}}_handleDelete(e){if(this._hasSelection())return this._deleteSelection(),void this.formatAndUpdate();if(e.onClosingLine){const t=this.lines[this.cursorLine],i=this._getClosingBracketPos(t);return i>=0&&this.cursorColumn>i?void this.deleteForward():void this._deleteCollapsedNode(e.onClosingLine)}if(e.onCollapsedNode){const t=this.lines[this.cursorLine].search(I);if(this.cursorColumn>t)return void this._deleteCollapsedNode(e.onCollapsedNode)}e.inCollapsedZone||this.deleteForward()}_handleTab(e,t){e?this._navigateToPrevAttribute():this._navigateToNextAttribute()}_navigateToNextAttribute(){const e=this.visibleLines.length;let t=this.visibleLines.findIndex(e=>e.index===this.cursorLine);t<0&&(t=0);for(let i=t;i<e;i++){const e=this.visibleLines[i],s=this.lines[e.index],n=i===t?this.cursorColumn:0,o=this._findNextAttributeOrBracket(s,n,e.index);if(null!==o)return this.cursorLine=e.index,this.cursorColumn=o.start,o.isBracket?this._clearSelection():(this.selectionStart={line:e.index,column:o.start},this.selectionEnd={line:e.index,column:o.end}),this._scrollToCursor(),this._invalidateRenderCache(),void this.scheduleRender()}for(let i=0;i<t;i++){const e=this.visibleLines[i],t=this.lines[e.index],s=this._findNextAttributeOrBracket(t,0,e.index);if(null!==s)return this.cursorLine=e.index,this.cursorColumn=s.start,s.isBracket?this._clearSelection():(this.selectionStart={line:e.index,column:s.start},this.selectionEnd={line:e.index,column:s.end}),this._scrollToCursor(),this._invalidateRenderCache(),void this.scheduleRender()}}_navigateToPrevAttribute(){const e=this.visibleLines.length;let t=this.visibleLines.findIndex(e=>e.index===this.cursorLine);t<0&&(t=e-1);for(let i=t;i>=0;i--){const e=this.visibleLines[i],s=this.lines[e.index],n=i===t?this.cursorColumn:s.length,o=this._findPrevAttributeOrBracket(s,n,e.index);if(null!==o)return this.cursorLine=e.index,this.cursorColumn=o.start,o.isBracket?this._clearSelection():(this.selectionStart={line:e.index,column:o.start},this.selectionEnd={line:e.index,column:o.end}),this._scrollToCursor(),this._invalidateRenderCache(),void this.scheduleRender()}for(let i=e-1;i>t;i--){const e=this.visibleLines[i],t=this.lines[e.index],s=this._findPrevAttributeOrBracket(t,t.length,e.index);if(null!==s)return this.cursorLine=e.index,this.cursorColumn=s.start,s.isBracket?this._clearSelection():(this.selectionStart={line:e.index,column:s.start},this.selectionEnd={line:e.index,column:s.end}),this._scrollToCursor(),this._invalidateRenderCache(),void this.scheduleRender()}}_findNextAttributeInLine(e,t){const i=[],s=/"([^"]+)"(?:\s*:\s*(?:"([^"]*)"|(-?\d+\.?\d*(?:e[+-]?\d+)?)|true|false|null))?/gi;let n;for(;null!==(n=s.exec(e));){const t=n.index+1,s=t+n[1].length;if(i.push({start:t,end:s}),void 0!==n[2]){const t=e.substring(n.index).match(/:\s*"([^"]*)"/);if(t){const e=n.index+(t.index||0)+t[0].indexOf('"')+1,s=e+n[2].length;i.push({start:e,end:s})}}else if(void 0!==n[3]){const t=e.substring(n.index).match(/:\s*(-?\d+\.?\d*(?:e[+-]?\d+)?)/i);if(t){const e=n.index+(t.index||0)+t[0].indexOf(t[1]),s=e+t[1].length;i.push({start:e,end:s})}}else{const t=e.substring(n.index).match(/:\s*(true|false|null)/);if(t){const e=n.index+(t.index||0)+t[0].indexOf(t[1]),s=e+t[1].length;i.push({start:e,end:s})}}}const o=/(?:^|[\[,\s])(-?\d+\.?\d*(?:e[+-]?\d+)?)\s*(?:[,\]]|$)/gi;for(;null!==(n=o.exec(e));){const e=n[1],t=n.index+n[0].indexOf(e),s=t+e.length;i.some(e=>e.start===t&&e.end===s)||i.push({start:t,end:s})}i.sort((e,t)=>e.start-t.start);for(const r of i)if(r.start>t)return r;return null}_findPrevAttributeInLine(e,t){const i=[],s=/"([^"]+)"(?:\s*:\s*(?:"([^"]*)"|(-?\d+\.?\d*(?:e[+-]?\d+)?)|true|false|null))?/gi;let n;for(;null!==(n=s.exec(e));){const t=n.index+1,s=t+n[1].length;if(i.push({start:t,end:s}),void 0!==n[2]){const t=e.substring(n.index).match(/:\s*"([^"]*)"/);if(t){const e=n.index+(t.index||0)+t[0].indexOf('"')+1,s=e+n[2].length;i.push({start:e,end:s})}}else if(void 0!==n[3]){const t=e.substring(n.index).match(/:\s*(-?\d+\.?\d*(?:e[+-]?\d+)?)/i);if(t){const e=n.index+(t.index||0)+t[0].indexOf(t[1]),s=e+t[1].length;i.push({start:e,end:s})}}else{const t=e.substring(n.index).match(/:\s*(true|false|null)/);if(t){const e=n.index+(t.index||0)+t[0].indexOf(t[1]),s=e+t[1].length;i.push({start:e,end:s})}}}const o=/(?:^|[\[,\s])(-?\d+\.?\d*(?:e[+-]?\d+)?)\s*(?:[,\]]|$)/gi;for(;null!==(n=o.exec(e));){const e=n[1],t=n.index+n[0].indexOf(e),s=t+e.length;i.some(e=>e.start===t&&e.end===s)||i.push({start:t,end:s})}i.sort((e,t)=>e.start-t.start);for(let r=i.length-1;r>=0;r--)if(i[r].end<t)return i[r];return null}_findBracketInLine(e){const t=e.match(/[\[{]\s*$/);return t&&void 0!==t.index?t.index+1:null}_findNextAttributeOrBracket(e,t,i){const s=this._findNextAttributeInLine(e,t),n=this._findBracketInLine(e);return null!==s&&null!==n?n>t&&n<s.start?{start:n,end:n,isBracket:!0}:{...s,isBracket:!1}:null!==s?{...s,isBracket:!1}:null!==n&&n>t?{start:n,end:n,isBracket:!0}:null}_findPrevAttributeOrBracket(e,t,i){const s=this._findPrevAttributeInLine(e,t),n=this._findBracketInLine(e);return null!==s&&null!==n?n<t&&n>s.end?{start:n,end:n,isBracket:!0}:{...s,isBracket:!1}:null!==s?{...s,isBracket:!1}:null!==n&&n<t?{start:n,end:n,isBracket:!0}:null}insertNewline(){if(this._saveToHistory("newline"),this.cursorLine<this.lines.length){const e=this.lines[this.cursorLine],t=e.substring(0,this.cursorColumn),i=e.substring(this.cursorColumn);this.lines[this.cursorLine]=t,this.lines.splice(this.cursorLine+1,0,i),this.cursorLine++,this.cursorColumn=0}else this.lines.push(""),this.cursorLine=this.lines.length-1,this.cursorColumn=0;this.formatAndUpdate()}deleteBackward(){if(this._saveToHistory("delete"),this.cursorColumn>0){const e=this.lines[this.cursorLine];this.lines[this.cursorLine]=e.substring(0,this.cursorColumn-1)+e.substring(this.cursorColumn),this.cursorColumn--}else if(this.cursorLine>0){const e=this.lines[this.cursorLine],t=this.lines[this.cursorLine-1];this.cursorColumn=t.length,this.lines[this.cursorLine-1]=t+e,this.lines.splice(this.cursorLine,1),this.cursorLine--}this.formatAndUpdate()}deleteForward(){if(this._saveToHistory("delete"),this.cursorLine<this.lines.length){const e=this.lines[this.cursorLine];this.cursorColumn<e.length?this.lines[this.cursorLine]=e.substring(0,this.cursorColumn)+e.substring(this.cursorColumn+1):this.cursorLine<this.lines.length-1&&(this.lines[this.cursorLine]=e+this.lines[this.cursorLine+1],this.lines.splice(this.cursorLine+1,1))}this.formatAndUpdate()}moveCursorSkipCollapsed(e){let t=this.cursorLine+e;for(;t>=0&&t<this.lines.length;){const i=this._getCollapsedRangeForLine(t);if(!i)break;t=e>0?i.endLine:i.startLine}this.cursorLine=Math.max(0,Math.min(this.lines.length-1,t));const i=this.lines[this.cursorLine]?.length||0;this.cursorColumn=Math.min(this.cursorColumn,i),this._invalidateRenderCache(),this._scrollToCursor(),this.scheduleRender()}moveCursorHorizontal(e){e>0?this._moveCursorRight():this._moveCursorLeft(),this._invalidateRenderCache(),this._scrollToCursor(),this.scheduleRender()}_moveCursorRight(){const e=this.lines[this.cursorLine],t=this._getCollapsedNodeAtLine(this.cursorLine);if(this._getCollapsedClosingLine(this.cursorLine)){const t=this._getClosingBracketPos(e);this.cursorColumn<t?this.cursorColumn=t:this.cursorColumn>=e.length?this.cursorLine<this.lines.length-1&&(this.cursorLine++,this.cursorColumn=0):this.cursorColumn++}else if(t){const i=e.search(I);this.cursorColumn<i?this.cursorColumn++:this.cursorColumn===i?this.cursorColumn=i+1:(this.cursorLine=t.endLine,this.cursorColumn=this._getClosingBracketPos(this.lines[this.cursorLine]))}else if(this.cursorColumn>=e.length){if(this.cursorLine<this.lines.length-1){this.cursorLine++,this.cursorColumn=0;const e=this._getCollapsedRangeForLine(this.cursorLine);e&&(this.cursorLine=e.endLine,this.cursorColumn=0)}}else this.cursorColumn++}_moveCursorLeft(){const e=this.lines[this.cursorLine],t=this._getCollapsedNodeAtLine(this.cursorLine),i=this._getCollapsedClosingLine(this.cursorLine);if(i){const t=this._getClosingBracketPos(e);if(this.cursorColumn>t+1)this.cursorColumn--;else{this.cursorLine=i.startLine;const e=this.lines[this.cursorLine];this.cursorColumn=e.search(I)+1}}else if(t){const t=e.search(I);this.cursorColumn>t+1?this.cursorColumn=t+1:this.cursorColumn===t+1?this.cursorColumn=t:this.cursorColumn>0?this.cursorColumn--:this.cursorLine>0&&(this.cursorLine--,this.cursorColumn=this.lines[this.cursorLine]?.length||0)}else if(this.cursorColumn>0)this.cursorColumn--;else if(this.cursorLine>0)if(this.cursorLine--,this._getCollapsedClosingLine(this.cursorLine))this.cursorColumn=this.lines[this.cursorLine]?.length||0;else{const e=this._getCollapsedRangeForLine(this.cursorLine);if(e){this.cursorLine=e.startLine;const t=this.lines[this.cursorLine];this.cursorColumn=t.search(I)+1}else this.cursorColumn=this.lines[this.cursorLine]?.length||0}}_scrollToCursor(e=!1){const t=this._viewport;if(!t)return;const i=this.visibleLines.findIndex(e=>e.index===this.cursorLine);if(-1===i)return;const s=i*this.lineHeight,n=t.clientHeight,o=2*this.lineHeight;if(e)t.scrollTop=Math.max(0,s-n/2+this.lineHeight/2);else{const e=t.scrollTop,i=e+n;s<e+o?t.scrollTop=Math.max(0,s-o):s+this.lineHeight>i-o&&(t.scrollTop=s+this.lineHeight+o-n)}}_handleArrowKey(e,t,i,s=!1){i&&!this.selectionStart&&(this.selectionStart={line:this.cursorLine,column:this.cursorColumn}),0!==e?this.moveCursorSkipCollapsed(e):0!==t&&(s?this._moveCursorByWord(t):this.moveCursorHorizontal(t)),i?this.selectionEnd={line:this.cursorLine,column:this.cursorColumn}:(this.selectionStart=null,this.selectionEnd=null)}_moveCursorByWord(e){const t=this.lines[this.cursorLine]||"",i=e=>T.test(e),s=this._getCollapsedNodeAtLine(this.cursorLine);if(e>0){let e=this.cursorColumn;if(s){const i=t.search(I);if(i>=0&&e>=i)return this.cursorLine=s.endLine,this.cursorColumn=(this.lines[this.cursorLine]||"").length,this._invalidateRenderCache(),this._scrollToCursor(),void this.scheduleRender()}if(e>=t.length){if(this.cursorLine<this.lines.length-1){let e=this.cursorLine+1;const t=this._getCollapsedRangeForLine(e);t&&(e=t.endLine),this.cursorLine=Math.min(e,this.lines.length-1),this.cursorColumn=0}}else if(i(t[e])){for(;e<t.length&&i(t[e]);)e++;this.cursorColumn=e}else{for(;e<t.length&&!i(t[e]);)e++;this.cursorColumn=e}}else{let e=this.cursorColumn;const s=this._getCollapsedClosingLine(this.cursorLine);if(s){const i=this._getClosingBracketPos(t);if(i>=0&&e<=i+1){this.cursorLine=s.startLine;const e=(this.lines[this.cursorLine]||"").search(I);return this.cursorColumn=e>=0?e:0,this._invalidateRenderCache(),this._scrollToCursor(),void this.scheduleRender()}}if(0===e){if(this.cursorLine>0){let e=this.cursorLine-1;const t=this._getCollapsedRangeForLine(e);t&&(e=t.startLine),this.cursorLine=Math.max(e,0),this.cursorColumn=this.lines[this.cursorLine].length}}else if(e>0&&i(t[e-1])){for(;e>0&&i(t[e-1]);)e--;this.cursorColumn=e}else{for(;e>0&&!i(t[e-1]);)e--;for(;e>0&&i(t[e-1]);)e--;this.cursorColumn=e}}this._invalidateRenderCache(),this._scrollToCursor(),this.scheduleRender()}_handleHomeEnd(e,t,i,s){if(t&&!this.selectionStart&&(this.selectionStart={line:this.cursorLine,column:this.cursorColumn}),"home"===e)i?(this.cursorLine=0,this.cursorColumn=0):s?(this.cursorLine=s.startLine,this.cursorColumn=0):this.cursorColumn=0;else if(i)this.cursorLine=this.lines.length-1,this.cursorColumn=this.lines[this.cursorLine]?.length||0;else{const e=this.lines[this.cursorLine]?.length||0;this.cursorColumn=e}t?this.selectionEnd={line:this.cursorLine,column:this.cursorColumn}:(this.selectionStart=null,this.selectionEnd=null),this._invalidateRenderCache(),this._scrollToCursor(),this.scheduleRender()}_handlePageUpDown(e,t){t&&!this.selectionStart&&(this.selectionStart={line:this.cursorLine,column:this.cursorColumn});const i=this._viewport;if(!i)return;const s=Math.floor(i.clientHeight/this.lineHeight);if("up"===e){const e=this.visibleLines.findIndex(e=>e.index===this.cursorLine),t=Math.max(0,e-s);this.cursorLine=this.visibleLines[t]?.index||0}else{const e=this.visibleLines.findIndex(e=>e.index===this.cursorLine),t=Math.min(this.visibleLines.length-1,e+s);this.cursorLine=this.visibleLines[t]?.index||this.lines.length-1}this.cursorColumn=Math.min(this.cursorColumn,this.lines[this.cursorLine]?.length||0),t?this.selectionEnd={line:this.cursorLine,column:this.cursorColumn}:(this.selectionStart=null,this.selectionEnd=null),this._invalidateRenderCache(),this._scrollToCursor(),this.scheduleRender()}_selectAll(){this.selectionStart={line:0,column:0};const e=this.lines.length-1;this.selectionEnd={line:e,column:this.lines[e]?.length||0},this.cursorLine=e,this.cursorColumn=this.lines[e]?.length||0,this._invalidateRenderCache(),this.scheduleRender()}_getSelectedText(){const e=this._normalizeSelection();if(!e)return"";const{start:t,end:i}=e;if(t.line===i.line)return this.lines[t.line].substring(t.column,i.column);let s=this.lines[t.line].substring(t.column)+"\n";for(let n=t.line+1;n<i.line;n++)s+=this.lines[n]+"\n";return s+=this.lines[i.line].substring(0,i.column),s}_normalizeSelection(){if(!this.selectionStart||!this.selectionEnd)return null;const e=this.selectionStart,t=this.selectionEnd;return e.line<t.line||e.line===t.line&&e.column<=t.column?{start:e,end:t}:{start:t,end:e}}_hasSelection(){return!(!this.selectionStart||!this.selectionEnd||this.selectionStart.line===this.selectionEnd.line&&this.selectionStart.column===this.selectionEnd.column)}_clearSelection(){this.selectionStart=null,this.selectionEnd=null}_selectWordAt(e,t){if(e<0||e>=this.lines.length)return;const i=this.lines[e];if(!i||t>i.length)return;const s=e=>/[\w\-]/.test(e);let n=!1,o=-1,r=-1,l=!1;for(let c=0;c<i.length;c++){const s=i[c];if(l)l=!1;else if("\\"!==s){if('"'===s)if(n){if(r=c,t>=o&&t<=r)return this.selectionStart={line:e,column:o+1},this.selectionEnd={line:e,column:r},this.cursorLine=e,void(this.cursorColumn=r);n=!1,o=-1,r=-1}else n=!0,o=c}else l=!0}let a=t,h=t;for(;a>0&&s(i[a-1]);)a--;for(;h<i.length&&s(i[h]);)h++;a<h&&(this.selectionStart={line:e,column:a},this.selectionEnd={line:e,column:h},this.cursorLine=e,this.cursorColumn=h)}_deleteSelection(){const e=this._normalizeSelection();if(!e)return!1;const{start:t,end:i}=e;if(this._saveToHistory("delete"),t.line===i.line){const e=this.lines[t.line];this.lines[t.line]=e.substring(0,t.column)+e.substring(i.column)}else{const e=this.lines[t.line].substring(0,t.column),s=this.lines[i.line].substring(i.column);this.lines[t.line]=e+s,this.lines.splice(t.line+1,i.line-t.line)}return this.cursorLine=t.line,this.cursorColumn=t.column,this.selectionStart=null,this.selectionEnd=null,!0}insertText(e){if(this._hasSelection()&&this._deleteSelection(),!this._getCollapsedRangeForLine(this.cursorLine)){if(this._getCollapsedClosingLine(this.cursorLine)){const e=this.lines[this.cursorLine],t=this._getClosingBracketPos(e);if(this.cursorColumn<=t)return}if(this._getCollapsedNodeAtLine(this.cursorLine)){const e=this.lines[this.cursorLine].search(I);if(this.cursorColumn>e)return}if(this._saveToHistory("insert"),0===this.lines.length){const t=e.split("\n");this.lines=t,this.cursorLine=t.length-1,this.cursorColumn=t[t.length-1].length}else if(this.cursorLine<this.lines.length){const t=e.split("\n"),i=this.lines[this.cursorLine],s=i.substring(0,this.cursorColumn),n=i.substring(this.cursorColumn);if(1===t.length)this.lines[this.cursorLine]=s+e+n,this.cursorColumn+=e.length;else{const e=s+t[0],i=t[t.length-1]+n,o=t.slice(1,-1);this.lines.splice(this.cursorLine,1,e,...o,i),this.cursorLine+=t.length-1,this.cursorColumn=t[t.length-1].length}}this.formatAndUpdate()}}handlePaste(e){e.preventDefault();const t=e.clipboardData?.getData("text/plain");if(!t)return;const i=/* @__PURE__ */new Set;for(const o of this.collapsedNodes){const e=this._nodeIdToLines.get(o);if(e?.nodeKey){const t=this._getFeatureIndexForLine(e.startLine);i.add(`${t}:${e.nodeKey}`)}}const s=this._parseFeatures().length;let n=0;try{let e;try{e=JSON.parse(t)}catch{e=JSON.parse("["+t+"]")}const i=P(e);n=i.length;const s=i.map(e=>JSON.stringify(e,null,2)).join(",\n");this.insertText(s)}catch{this.insertText(t)}if(this.renderTimer&&(cancelAnimationFrame(this.renderTimer),this.renderTimer=void 0),n>0){const e=this._findCollapsibleRanges();for(const t of e){const e=this._getFeatureIndexForLine(t.startLine);if(-1!==e)if(e<s){const s=`${e}:${t.nodeKey}`;i.has(s)&&this.collapsedNodes.add(t.nodeId)}else"coordinates"===t.nodeKey&&this.collapsedNodes.add(t.nodeId)}this.updateView()}this._expandErrorNodes(),this.renderViewport(),requestAnimationFrame(()=>{this._scrollToCursor()})}handleCopy(e){e.preventDefault(),e.clipboardData&&(this._hasSelection()?e.clipboardData.setData("text/plain",this._getSelectedText()):e.clipboardData.setData("text/plain",this.getContent()))}handleCut(e){e.preventDefault(),e.clipboardData&&(this._hasSelection()?(e.clipboardData.setData("text/plain",this._getSelectedText()),this._saveToHistory("cut"),this._deleteSelection(),this.formatAndUpdate()):(e.clipboardData.setData("text/plain",this.getContent()),this._saveToHistory("cut"),this.lines=[],this.cursorLine=0,this.cursorColumn=0,this.formatAndUpdate()))}_getPositionFromClick(e){const t=this._viewport,i=this._linesContainer;if(!t)return{line:0,column:0};const s=t.getBoundingClientRect(),n=e.clientY-s.top+t.scrollTop-8,o=Math.floor(n/this.lineHeight);let r=0,l=0;if(o>=0&&o<this.visibleLines.length){const n=this.visibleLines[o];r=n.index;const a=i?.querySelector(`.line[data-line-index="${n.index}"]`),h=this._getCharWidth();if(a){const t=a.getBoundingClientRect(),i=e.clientX-t.left,s=Math.round(i/h),o=n.content?.length||0;l=Math.max(0,Math.min(s,o))}else{const i=12,o=e.clientX-s.left+t.scrollLeft-i,r=Math.round(o/h),a=n.content?.length||0;l=Math.max(0,Math.min(r,a))}}return{line:r,column:l}}_updateSelectionFromScroll(e){if(this.visibleLines.length)if("up"===e){const e=this.visibleLines[0];this.selectionEnd={line:e.index,column:0},this.cursorLine=e.index,this.cursorColumn=0}else{const e=this.visibleLines[this.visibleLines.length-1],t=e.content?.length||0;this.selectionEnd={line:e.index,column:t},this.cursorLine=e.index,this.cursorColumn=t}}handleGutterClick(e){const t=e.target;if(!t)return;const i=t.closest(".visibility-button");if(i&&void 0!==i.dataset.featureIndex)this.toggleFeatureVisibility(parseInt(i.dataset.featureIndex,10));else if(t.classList.contains("collapse-button")){const e=t.dataset.nodeId;return void(e&&this.toggleCollapse(e))}}handleEditorClick(e){const t=e.target;if(!t)return;this._blockRender=!1;const i=t.closest(".line.has-visibility");if(i){const t=i.getBoundingClientRect();if(e.clientX-t.left<14){e.preventDefault(),e.stopPropagation();const t=i.dataset.featureIndex;return void(void 0!==t&&this.toggleFeatureVisibility(parseInt(t,10)))}}if(t.classList.contains("json-color")){const i=t.getBoundingClientRect(),s=e.clientX-i.left;if(s<0&&s>=-8){e.preventDefault(),e.stopPropagation();const i=t.dataset.color,s=t.closest(".line");if(s){const e=parseInt(s.dataset.lineIndex||"0"),n=this.lines[e].match(w);n&&n[1]&&i&&this.showColorPicker(t,e,i,n[1])}return}}if(t.classList.contains("json-boolean")){const i=t.getBoundingClientRect(),s=e.clientX-i.left;if(s<0&&s>=-8){e.preventDefault(),e.stopPropagation();const i=t.closest(".line");if(i){const e=parseInt(i.dataset.lineIndex||"0"),t=this.lines[e].match(S);if(t){const i="true"===t[2];this.updateBooleanValue(e,!i,t[1])}}return}}}toggleCollapse(e){const t=this._nodeIdToLines.get(e);this.collapsedNodes.has(e)?(this.collapsedNodes.delete(e),t?.uniqueKey&&this._openedNodeKeys.add(t.uniqueKey)):(this.collapsedNodes.add(e),t?.uniqueKey&&this._openedNodeKeys.delete(t.uniqueKey)),this.updateView(),this._invalidateRenderCache(),this.scheduleRender()}autoCollapseCoordinates(){this._hasErrors()||this._applyCollapsedOption(["coordinates"])}_hasErrors(){try{const e="["+this.lines.join("\n")+"]";JSON.parse(e)}catch{return!0}for(const e of this.lines)if(O(e,"",void 0).includes("json-error"))return!0;return!1}_applyCollapsedFromOptions(e,t){if(this._hasErrors())return;const i=void 0!==e.collapsed?e.collapsed:["coordinates"];i&&(!Array.isArray(i)||i.length>0)&&this._applyCollapsedOption(i,t)}_applyCollapsedOption(e,t=null){const i=this._findCollapsibleRanges();for(const s of i){let i=!1;if("function"==typeof e){const n=this._getFeatureIndexForLine(s.startLine);if(-1===n)continue;const o=e(t?.[n]||null,n);i=s.isRootFeature?o.includes("$root"):o.includes(s.nodeKey)}else Array.isArray(e)&&(i=s.isRootFeature?e.includes("$root"):e.includes(s.nodeKey));i&&this.collapsedNodes.add(s.nodeId)}this.updateModel(),this.scheduleRender()}toggleFeatureVisibility(e){void 0!==e&&(this.hiddenFeatures.has(e)?this.hiddenFeatures.delete(e):this.hiddenFeatures.add(e),this.updateView(),this.scheduleRender(),this.emitChange())}showColorPicker(e,t,i,s){const n=document.querySelector(".geojson-color-picker-anchor");n&&n.remove();const o=D("div");o.className="geojson-color-picker-anchor";const r=e.getBoundingClientRect();o.style.cssText=`\n position: fixed;\n left: ${r.left-8}px;\n top: ${r.top+r.height}px;\n width: 10px;\n height: 10px;\n z-index: 9998;\n `,document.body.appendChild(o);const l=D("input");l.type="color";let a=i;a=i.startsWith("#")?i.replace(L,"#$1$1$2$2$3$3"):function(e){const t=(K||(K=document.createElement("div"),K.style.display="none",document.body.appendChild(K)),K);t.style.color=e;const i=getComputedStyle(t).color;if(!i)return null;const s=i.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);if(!s)return null;const[,n,o,r]=s;return"#"+parseInt(n,10).toString(16).padStart(2,"0")+parseInt(o,10).toString(16).padStart(2,"0")+parseInt(r,10).toString(16).padStart(2,"0")}(i)||"#000000",l.value=a,l.className="geojson-color-picker-input",l.style.cssText="\n position: absolute;\n left: 0;\n top: 0;\n width: 10px;\n height: 10px;\n opacity: 0;\n border: none;\n padding: 0;\n cursor: pointer;\n ",o.appendChild(l),l.addEventListener("input",e=>{this.updateColorValue(t,e.target.value,s)});const h=e=>{e.target!==l&&(document.removeEventListener("click",h,!0),o.remove())};l._closeListener=h,setTimeout(()=>{document.addEventListener("click",h,!0)},100),l.focus(),l.click()}updateColorValue(e,t,i){const s=new RegExp(`"${i}"\\s*:\\s*"(?:#[0-9a-fA-F]{3,6}|[a-zA-Z]+)"`);this.lines[e]=this.lines[e].replace(s,`"${i}": "${t}"`),this.updateView(),this.scheduleRender(),this.emitChange()}updateBooleanValue(e,t,i){const s=new RegExp(`"${i}"\\s*:\\s*(true|false)`);this.lines[e]=this.lines[e].replace(s,`"${i}": ${t}`),this.updateView(),this.scheduleRender(),this.emitChange()}_bestEffortFormat(e,t){const i=e.split("\n");if(void 0!==t&&t>=0&&t<i.length){const e=i[t],s=i.slice(0,t).join("\n"),n=s.trim()?this._formatChunk(s):[],o=this._computeDepthAtEnd(n)+this._computeBracketDelta(e),r=i.slice(t+1).join("\n"),l=r.trim()?this._formatChunk(r,o):[];return[...n,e,...l]}return this._formatChunk(e)}_computeBracketDelta(e){let t=0,i=!1,s=!1;for(const n of e)s?s=!1:"\\"===n&&i?s=!0:'"'!==n?i||("{"===n||"["===n?t++:"}"!==n&&"]"!==n||t--):i=!i;return t}_computeDepthAtEnd(e){let t=1;for(const i of e)for(const e of i)"{"===e||"["===e?t++:"}"!==e&&"]"!==e||(t=Math.max(0,t-1));return t}_formatChunk(e,t=1){const i=[];let s="",n=t,o=!1,r=!1;for(let l=0;l<e.length;l++){const t=e[l];if(r)s+=t,r=!1;else if("\\"===t&&o)s+=t,r=!0;else if('"'!==t)if(o)s+=t;else if("{"===t||"["===t)s+=t,i.push(" ".repeat(n)+s.trim()),n++,s="";else if("}"===t||"]"===t)s.trim()&&i.push(" ".repeat(n)+s.trim()),n=Math.max(0,n-1),s=t;else if(","===t)s+=t,i.push(" ".repeat(n)+s.trim()),s="";else if(":"===t){if(s+=": ",l++," "===e[l])continue;l--}else{if("\n"===t||"\r"===t)continue;s+=t}else o=!o,s+=t}return s.trim()&&i.push(" ".repeat(n)+s.trim()),i}formatAndUpdate(){const e=this.cursorLine,t=this.cursorColumn,i=this.lines.join("\n"),s=this._countFeatures(i),n=this._getFeatureIndexForLine(e);try{const e="["+i+"]",t=JSON.parse(e),s=JSON.stringify(t,null,2).split("\n");this.lines=s.slice(1,-1)}catch{if(i.trim()){const t=(this.lines[e]||"").length<80?e:void 0,s=i.split("\n"),n=void 0!==t?this._formatChunk(s.slice(0,t).join("\n")).length:0;this.lines=this._bestEffortFormat(i,t),void 0!==t&&n>=0&&(this.cursorLine=n)}}if(this.lines.join("\n")===i)this.cursorLine=e,this.cursorColumn=t;else if(0===t)this.cursorColumn=0;else{const s=i.split("\n");let n=0;for(let t=0;t<e&&t<s.length;t++)n+=s[t].replace(/\s/g,"").length;n+=(s[e]||"").substring(0,t).replace(/\s/g,"").length;let o=0,r=0,l=0;for(let e=0;e<this.lines.length;e++){const t=this.lines[e];for(let i=0;i<=t.length;i++){if(o>=n){r=e,l=i;break}i<t.length&&!/\s/.test(t[i])&&o++}if(o>=n)break}this.cursorLine=r,this.cursorColumn=l}this.cursorLine=Math.min(this.cursorLine,Math.max(0,this.lines.length-1)),this.cursorColumn=Math.min(this.cursorColumn,this.lines[this.cursorLine]?.length||0);const o=this.lines.join("\n"),r=this._countFeatures(o);if(s>=0&&r>=0&&s!==r){const e=r-s,t=n>=0?n:0;this._adjustHiddenIndices(t,e)}this.updateModel(),this._expandErrorNodes(),this.scheduleRender(),this.updatePlaceholderVisibility(),this._updateErrorDisplay(),this.emitChange()}emitChange(){const e=this.getContent(),i=this.prefix+e+this.suffix;try{let s=JSON.parse(i);this.hiddenFeatures.size>0&&(s.features=s.features.filter((e,t)=>!this.hiddenFeatures.has(t)));const n=function(e){const i=[];return e.features?(e.features.forEach((e,s)=>{"Feature"!==e.type&&i.push(`features[${s}]: type must be "Feature"`),e.geometry&&e.geometry.type&&(t.includes(e.geometry.type)||i.push(`features[${s}].geometry: invalid type "${e.geometry.type}"`))}),i):i}(s);n.length>0?this.dispatchEvent(new CustomEvent("error",{detail:{error:n.join("; "),errors:n,content:e},bubbles:!0,composed:!0})):this.dispatchEvent(new CustomEvent("change",{detail:s,bubbles:!0,composed:!0}))}catch(s){this.dispatchEvent(new CustomEvent("error",{detail:{error:s instanceof Error?s.message:"Unknown error",content:e},bubbles:!0,composed:!0}))}}_emitCurrentFeature(e=!1){const t=this._getFeatureIndicesForCurrentSelection(),i=JSON.stringify(t);if(e||i!==this._lastCurrentFeatureIndices)if(this._lastCurrentFeatureIndices=i,0===t.length)this.dispatchEvent(new CustomEvent("current-features",{detail:{type:"FeatureCollection",features:[]},bubbles:!0,composed:!0}));else{const e=this._parseFeatures(),i={type:"FeatureCollection",features:t.map(t=>e[t]).filter(e=>null!=e)};this.dispatchEvent(new CustomEvent("current-features",{detail:i,bubbles:!0,composed:!0}))}}_getFeatureIndicesForCurrentSelection(){const e=/* @__PURE__ */new Set;let t,i;this.selectionStart&&this.selectionEnd?(t=Math.min(this.selectionStart.line,this.selectionEnd.line),i=Math.max(this.selectionStart.line,this.selectionEnd.line)):(t=this.cursorLine,i=this.cursorLine);for(const[,s]of this.featureRanges)s.startLine<=i&&s.endLine>=t&&e.add(s.featureIndex);return Array.from(e).sort((e,t)=>e-t)}_emitCurrentFeatureNull(){this._lastCurrentFeatureIndices=null,this.dispatchEvent(new CustomEvent("current-features",{detail:{type:"FeatureCollection",features:[]},bubbles:!0,composed:!0}))}updateReadonly(){this._hiddenTextarea&&(this._hiddenTextarea.readOnly=this.readonly),this._clearBtn&&(this._clearBtn.hidden=this.readonly)}updatePlaceholderVisibility(){this._placeholderLayer&&(this._placeholderLayer.style.display=this.lines.length>0?"none":"block")}_updateErrorDisplay(){const e=this._getErrorLines().length;this._errorNav&&this._errorNav.classList.toggle("visible",e>0),this._errorCount&&(this._errorCount.textContent=e>0?String(e):"")}updatePlaceholderContent(){this._placeholderLayer&&(this._placeholderLayer.textContent=this.placeholder),this.updatePlaceholderVisibility()}updatePrefixSuffix(){this._editorPrefix&&(this._editorPrefix.textContent=this.prefix),this._editorSuffix&&(this._editorSuffix.textContent=this.suffix)}_findCollapsibleRanges(){const e=[];for(const[t,i]of this._lineToNodeId){const s=this._nodeIdToLines.get(i);if(!s)continue;const n=this.lines[t];if(!n)continue;const o=n.match(F),r=!o&&n.match(E);if(!o&&!r)continue;const l=o?o[2]:r?r[1]:"{";e.push({startLine:s.startLine,endLine:s.endLine,nodeKey:s.nodeKey||(o?o[1]:`__root_${t}`),nodeId:i,openBracket:l,isRootFeature:!!r})}return e.sort((e,t)=>e.startLine-t.startLine),e}_findClosingLine(e,t){let i=1;const s=this.lines[e],n=s.indexOf(t);if(-1!==n){const o=M(s.substring(n+1),t);if(i+=o.open-o.close,0===i)return e}for(let o=e+1;o<this.lines.length;o++){const e=M(this.lines[o],t);if(i+=e.open-e.close,0===i)return o}return-1}_buildContextMap(){const e=this.lines.length;if(this._contextMapCache&&this._contextMapLinesLength===e&&this._contextMapFirstLine===this.lines[0]&&this._contextMapLastLine===this.lines[e-1])return this._contextMapCache;const t=/* @__PURE__ */new Map,o=[];let r=null;for(let l=0;l<e;l++){const e=this.lines[l],a=o[o.length-1]?.context||"Feature";t.set(l,a),i.test(e)?r="geometry":s.test(e)?r="properties":n.test(e)&&(r="Feature"),N.lastIndex=0,R.lastIndex=0,A.lastIndex=0,$.lastIndex=0;const h=(e.match(N)||[]).length,c=(e.match(R)||[]).length,d=(e.match(A)||[]).length,u=(e.match($)||[]).length;for(let t=0;t<h+d;t++)o.push({context:r||a,isArray:t>=h}),r=null;for(let t=0;t<c+u&&o.length>0;t++)o.pop()}return this._contextMapCache=t,this._contextMapLinesLength=e,this._contextMapFirstLine=this.lines[0],this._contextMapLastLine=this.lines[e-1],t}set(e,t={}){const i=P(e);this._setFeaturesInternal(i,t)}add(e,t={}){const i=P(e),s=this._parseFeatures().length,n=[...this._parseFeatures(),...i];this._setFeaturesInternalPreserving(n,t,s)}insertAt(e,t,i={}){const s=P(e),n=this._parseFeatures(),o=t<0?n.length+t:t,r=Math.max(0,Math.min(o,n.length));this._adjustHiddenIndices(r,s.length),n.splice(r,0,...s),this._setFeaturesInternalPreserving(n,i,r,s.length)}_setFeaturesInternal(e,t){const i=e.map(e=>JSON.stringify(e,null,2)).join(",\n");this.setValue(i,!1),this._applyCollapsedFromOptions(t,e)}_setFeaturesInternalPreserving(e,t,i,s){const n=/* @__PURE__ */new Set;for(const h of this.collapsedNodes){const e=this._nodeIdToLines.get(h);if(e?.nodeKey){const t=this._getFeatureIndexForLine(e.startLine);n.add(`${t}:${e.nodeKey}`)}}const o=new Set(this.hiddenFeatures),r=e.map(e=>JSON.stringify(e,null,2)).join(",\n");this.setValue(r,!1),this.hiddenFeatures=o;const l=this._findCollapsibleRanges(),a=void 0!==s?s:e.length-i;for(const h of l){const e=this._getFeatureIndexForLine(h.startLine);if(-1===e)continue;let t=e;if(e>=i&&e<i+a)continue;e>=i+a&&(t=e-a);const s=`${t}:${h.nodeKey}`;n.has(s)&&this.collapsedNodes.add(h.nodeId)}this._applyCollapsedToNewFeatures(t,e,i,a),this.updateView(),this.scheduleRender()}_applyCollapsedToNewFeatures(e,t,i,s){const n=void 0!==e.collapsed?e.collapsed:["coordinates"];if(!n||Array.isArray(n)&&0===n.length)return;const o=this._findCollapsibleRanges();for(const r of o){const e=this._getFeatureIndexForLine(r.startLine);if(-1===e)continue;if(e<i||e>=i+s)continue;let o=!1;if("function"==typeof n){const i=n(t[e],e);o=r.isRootFeature?i.includes("$root"):i.includes(r.nodeKey)}else Array.isArray(n)&&(o=r.isRootFeature?n.includes("$root"):n.includes(r.nodeKey));o&&this.collapsedNodes.add(r.nodeId)}}_countFeatures(e){try{const t="["+e+"]",i=JSON.parse(t);return Array.isArray(i)?i.length:-1}catch{return-1}}_adjustHiddenIndices(e,t){if(0===t||0===this.hiddenFeatures.size)return;const i=/* @__PURE__ */new Set;for(const s of this.hiddenFeatures)if(s<e)i.add(s);else{const e=s+t;e>=0&&i.add(e)}this.hiddenFeatures=i}_removeAndShiftHiddenIndex(e){if(0===this.hiddenFeatures.size)return;const t=/* @__PURE__ */new Set;for(const i of this.hiddenFeatures)i<e?t.add(i):i>e&&t.add(i-1);this.hiddenFeatures=t}_getFeatureIndexForLine(e){for(const[,t]of this.featureRanges)if(e>=t.startLine&&e<=t.endLine)return t.featureIndex;return-1}removeAt(e){const t=this._parseFeatures(),i=e<0?t.length+e:e;if(i>=0&&i<t.length){const e=/* @__PURE__ */new Set;for(const t of this.collapsedNodes){const s=this._nodeIdToLines.get(t);if(s?.nodeKey){const t=this._getFeatureIndexForLine(s.startLine);if(t===i)continue;const n=t>i?t-1:t;e.add(`${n}:${s.nodeKey}`)}}this._removeAndShiftHiddenIndex(i);const s=new Set(this.hiddenFeatures),n=t.splice(i,1)[0],o=t.map(e=>JSON.stringify(e,null,2)).join(",\n");this.setValue(o,!1),this.hiddenFeatures=s;const r=this._findCollapsibleRanges();for(const t of r){const i=this._getFeatureIndexForLine(t.startLine);if(-1===i)continue;const s=`${i}:${t.nodeKey}`;e.has(s)&&this.collapsedNodes.add(t.nodeId)}return this.updateView(),this.scheduleRender(),this.emitChange(),this._lastCurrentFeatureIndices=null,this._editorWrapper?.classList.contains("focused")&&this._emitCurrentFeature(!0),n}}removeAll(){this.lines.length>0&&this._saveToHistory("removeAll");const e=this._parseFeatures();return this.lines=[],this.collapsedNodes.clear(),this.hiddenFeatures.clear(),this.cursorLine=0,this.cursorColumn=0,this.selectionStart=null,this.selectionEnd=null,this.updateModel(),this.scheduleRender(),this.updatePlaceholderVisibility(),this.emitChange(),this._lastCurrentFeatureIndices=null,this._editorWrapper?.classList.contains("focused")&&this._emitCurrentFeature(!0),e}get(e){const t=this._parseFeatures();return t[e<0?t.length+e:e]}getAll(){return this._parseFeatures()}emit(){this.emitChange()}save(e="features.geojson"){try{const t={type:"FeatureCollection",features:this._parseFeatures()},i=JSON.stringify(t,null,2),s=new Blob([i],{type:"application/geo+json"}),n=URL.createObjectURL(s),o=D("a");return o.href=n,o.download=e,document.body.appendChild(o),o.click(),document.body.removeChild(o),URL.revokeObjectURL(n),!0}catch(t){return!1}}open(e={}){return new Promise(t=>{const i=D("input");i.type="file",i.accept=".geojson,.json,application/geo+json,application/json",i.style.display="none",i.addEventListener("change",s=>{const n=s.target.files?.[0];if(!n)return document.body.removeChild(i),void t(!1);const o=new FileReader;o.onload=s=>{try{const n=s.target?.result,o=P(JSON.parse(n));this._saveToHistory("open"),this.set(o,e),this.clearHistory(),document.body.removeChild(i),t(!0)}catch(n){document.body.removeChild(i),t(!1)}},o.onerror=()=>{document.body.removeChild(i),t(!1)},o.readAsText(n)}),i.addEventListener("cancel",()=>{document.body.removeChild(i),t(!1)}),document.body.appendChild(i),i.click()})}_handleAddFeaturePrompt(){const e=prompt("Enter GeoJSON (Feature, Feature[], or FeatureCollection):");if(e&&e.trim())try{const t=P(JSON.parse(e));t.length>0&&this.add(t)}catch{}}_parseFeatures(){try{const e=this.lines.join("\n");return e.trim()?JSON.parse("["+e+"]"):[]}catch(e){return[]}}}customElements.get("geojson-editor")||customElements.define("geojson-editor",V);export{V as default};
|
|
9
|
+
const e=["type","geometry","properties","coordinates","id","features"],t=["Point","MultiPoint","LineString","MultiLineString","Polygon","MultiPolygon"],i=/"geometry"\s*:/,s=/"properties"\s*:/,n=/"features"\s*:/,o=/^(\s*"[^"]+"\s*:\s*)([{\[])/,r=/^(\s*)([{\[]),?\s*$/,l=/&/g,a=/</g,h=/>/g,c=/([{}[\],:])/g,d=/"([^"]+)"(<span class="json-punctuation">:<\/span>)/g,u=/<span class="geojson-key">"type"<\/span><span class="json-punctuation">:<\/span>(\s*)"([^"]*)"/g,p=/(<span class="json-punctuation">:<\/span>)(\s*)"([^"]*)"/g,g=/(<span class="json-punctuation">:<\/span>)(\s*)(-?\d+\.?\d*(?:e[+-]?\d+)?)/gi,f=/(<span class="json-punctuation">[\[,]<\/span>)(\s*)(-?\d+\.?\d*(?:e[+-]?\d+)?)/gi,m=/^(\s*)(-?\d+\.?\d*(?:e[+-]?\d+)?)/gim,_=/(<span class="json-punctuation">:<\/span>)(\s*)(true|false)/g,b=/(<span class="json-punctuation">:<\/span>)(\s*)(null)/g,C=/(<\/span>|^)([^<]+)(<span|$)/g,v=/^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/,L=/^#?([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])$/,y=/^\s*$/,x=/(\s+)/,k=/"([\w-]+)"\s*:\s*(?:"([^"]*)"|(\btrue\b|\bfalse\b))/g,w=/"([\w-]+)"\s*:\s*(?:"([^"]*)"|(\btrue\b|\bfalse\b))/,S=/"([\w-]+)"\s*:\s*(true|false)/,F=/"type"\s*:\s*"Feature"/,j=/^\s*"([^"]+)"\s*:\s*([{\[])/,E=/^\s*([{\[]),?\s*$/,I=/[{\[]/,T=/[\w-]/,N=/\{/g,R=/\}/g,A=/\[/g,M=/\]/g;function $(e,t){const i="{"===t?"}":"]";let s=0,n=0,o=!1,r=!1;for(const l of e)r?r=!1:"\\"===l&&o?r=!0:'"'!==l?o||(l===t&&s++,l===i&&n++):o=!o;return{open:s,close:n}}function B(e){if(!e||"object"!=typeof e)throw new Error("Feature must be an object");if("Feature"!==e.type)throw new Error('Feature type must be "Feature"');if(!("geometry"in e))throw new Error("Feature must have a geometry property");if(!("properties"in e))throw new Error("Feature must have a properties property");if(null!==e.geometry){if("object"!=typeof e.geometry)throw new Error("Feature geometry must be an object or null");if(!e.geometry.type)throw new Error("Feature geometry must have a type");if(!t.includes(e.geometry.type))throw new Error(`Invalid geometry type: "${e.geometry.type}"`);if(!("coordinates"in e.geometry))throw new Error("Feature geometry must have coordinates")}if(null!==e.properties&&"object"!=typeof e.properties)throw new Error("Feature properties must be an object or null")}function K(e){let t=[];if(Array.isArray(e))t=e;else{if(!e||"object"!=typeof e)throw new Error("Input must be a Feature, array of Features, or FeatureCollection");if("FeatureCollection"===e.type&&"features"in e&&Array.isArray(e.features))t=e.features;else{if("Feature"!==e.type)throw new Error("Input must be a Feature, array of Features, or FeatureCollection");t=[e]}}for(const i of t)B(i);return t}let P=null;function H(e){return",aliceblue,antiquewhite,aqua,aquamarine,azure,beige,bisque,black,blanchedalmond,blue,blueviolet,brown,burlywood,cadetblue,chartreuse,chocolate,coral,cornflowerblue,cornsilk,crimson,cyan,darkblue,darkcyan,darkgoldenrod,darkgray,darkgreen,darkgrey,darkkhaki,darkmagenta,darkolivegreen,darkorange,darkorchid,darkred,darksalmon,darkseagreen,darkslateblue,darkslategray,darkslategrey,darkturquoise,darkviolet,deeppink,deepskyblue,dimgray,dimgrey,dodgerblue,firebrick,floralwhite,forestgreen,fuchsia,gainsboro,ghostwhite,gold,goldenrod,gray,green,greenyellow,grey,honeydew,hotpink,indianred,indigo,ivory,khaki,lavender,lavenderblush,lawngreen,lemonchiffon,lightblue,lightcoral,lightcyan,lightgoldenrodyellow,lightgray,lightgreen,lightgrey,lightpink,lightsalmon,lightseagreen,lightskyblue,lightslategray,lightslategrey,lightsteelblue,lightyellow,lime,limegreen,linen,magenta,maroon,mediumaquamarine,mediumblue,mediumorchid,mediumpurple,mediumseagreen,mediumslateblue,mediumspringgreen,mediumturquoise,mediumvioletred,midnightblue,mintcream,mistyrose,moccasin,navajowhite,navy,oldlace,olive,olivedrab,orange,orangered,orchid,palegoldenrod,palegreen,paleturquoise,palevioletred,papayawhip,peachpuff,peru,pink,plum,powderblue,purple,rebeccapurple,red,rosybrown,royalblue,saddlebrown,salmon,sandybrown,seagreen,seashell,sienna,silver,skyblue,slateblue,slategray,slategrey,snow,springgreen,steelblue,tan,teal,thistle,tomato,turquoise,violet,wheat,white,whitesmoke,yellow,yellowgreen,".includes(","+e.toLowerCase()+",")}function O(i,s,n){if(!i)return"";let L=i,k=null;if(n?.collapseButton?.isCollapsed){const e=i.match(o),t=!e&&i.match(r);e?(L=e[1]+e[2],k=e[2]):t&&(L=t[1]+t[2],k=t[2])}let w=L.replace(l,"&").replace(a,"<").replace(h,">");if(w=w.replace(c,'<span class="json-punctuation">$1</span>'),d.lastIndex=0,w=w.replace(d,(t,i,n)=>"properties"!==s&&e.includes(i)?`<span class="geojson-key">"${i}"</span>${n}`:`<span class="json-key">"${i}"</span>${n}`),"properties"!==s&&(u.lastIndex=0,w=w.replace(u,(e,i,s)=>`<span class="geojson-key">"type"</span><span class="json-punctuation">:</span>${i}<span class="${"Feature"===s||"FeatureCollection"===s||t.includes(s)?"geojson-type":"geojson-type-invalid"}">"${s}"</span>`)),p.lastIndex=0,w=w.replace(p,(e,t,i,s)=>e.includes("geojson-type")||e.includes("json-string")?e:v.test(s)||H(s)?`${t}${i}<span class="json-string json-color" data-color="${s}" style="--swatch-color: ${s}">"${s}"</span>`:`${t}${i}<span class="json-string">"${s}"</span>`),g.lastIndex=0,w=w.replace(g,'$1$2<span class="json-number">$3</span>'),f.lastIndex=0,w=w.replace(f,'$1$2<span class="json-number">$3</span>'),m.lastIndex=0,w=w.replace(m,'$1<span class="json-number">$2</span>'),_.lastIndex=0,w=w.replace(_,(e,t,i,s)=>`${t}${i}<span class="json-boolean${"true"===s?" json-bool-true":" json-bool-false"}">${s}</span>`),b.lastIndex=0,w=w.replace(b,'$1$2<span class="json-null">$3</span>'),k){const e="["===k?"collapsed-bracket-array":"collapsed-bracket-object";w=w.replace(new RegExp(`<span class="json-punctuation">\\${k}<\\/span>$`),`<span class="${e}">${k}</span>`)}return C.lastIndex=0,w=w.replace(C,(e,t,i,s)=>{if(!i||y.test(i))return e;const n=i.split(x);let o=!1;const r=n.map(e=>y.test(e)?e:(o=!0,`<span class="json-error">${e}</span>`)).join("");return o?t+r+s:e}),w}const D=e=>document.createElement(e);class V extends HTMLElement{constructor(){super(),this.lines=[],this.collapsedNodes=/* @__PURE__ */new Set,this.hiddenFeatures=/* @__PURE__ */new Set,this._nodeIdCounter=0,this._lineToNodeId=/* @__PURE__ */new Map,this._nodeIdToLines=/* @__PURE__ */new Map,this._openedNodeKeys=/* @__PURE__ */new Set,this.visibleLines=[],this.lineMetadata=/* @__PURE__ */new Map,this.featureRanges=/* @__PURE__ */new Map,this.viewportHeight=0,this.lineHeight=19.5,this.bufferLines=5,this._lastStartIndex=-1,this._lastEndIndex=-1,this._lastTotalLines=-1,this._scrollRaf=null,this.cursorLine=0,this.cursorColumn=0,this.selectionStart=null,this.selectionEnd=null,this.renderTimer=void 0,this.inputTimer=void 0,this._undoStack=[],this._redoStack=[],this._maxHistorySize=100,this._lastActionTime=0,this._lastActionType=null,this._groupingDelay=500,this._isSelecting=!1,this._isComposing=!1,this._blockRender=!1,this._insertMode=!0,this._charWidth=null,this._contextMapCache=null,this._contextMapLinesLength=0,this._contextMapFirstLine=void 0,this._contextMapLastLine=void 0,this._errorLinesCache=null,this._lastCurrentFeatureIndices=null,this._viewport=null,this._linesContainer=null,this._scrollContent=null,this._hiddenTextarea=null,this._gutterContent=null,this._gutterScrollContent=null,this._gutterScroll=null,this._gutter=null,this._clearBtn=null,this._editorWrapper=null,this._placeholderLayer=null,this._editorPrefix=null,this._editorSuffix=null,this._errorNav=null,this._errorCount=null,this._prevErrorBtn=null,this._nextErrorBtn=null,this.attachShadow({mode:"open"})}_id(e){return this.shadowRoot.getElementById(e)}_invalidateRenderCache(){this._lastStartIndex=-1,this._lastEndIndex=-1,this._lastTotalLines=-1}_createSnapshot(){const e=[];for(const t of this.collapsedNodes){const i=this._nodeIdToLines.get(t);i?.uniqueKey&&e.push(i.uniqueKey)}return{lines:[...this.lines],cursorLine:this.cursorLine,cursorColumn:this.cursorColumn,timestamp:Date.now(),collapsedUniqueKeys:e}}_restoreSnapshot(e){if(this.lines=[...e.lines],this.cursorLine=e.cursorLine,this.cursorColumn=e.cursorColumn,this.updateModel(),void 0!==e.collapsedUniqueKeys){this.collapsedNodes.clear();const t=new Set(e.collapsedUniqueKeys);for(const[e,i]of this._nodeIdToLines)i.uniqueKey&&t.has(i.uniqueKey)&&this.collapsedNodes.add(e)}else this.collapsedNodes.clear(),this._applyCollapsedOption(["coordinates"]);this._invalidateRenderCache(),this.scheduleRender(),this.updatePlaceholderVisibility(),this.emitChange()}_saveToHistory(e="edit"){const t=Date.now();if(!(e===this._lastActionType&&t-this._lastActionTime<this._groupingDelay)){const e=this._createSnapshot();this._undoStack.push(e),this._undoStack.length>this._maxHistorySize&&this._undoStack.shift(),this._redoStack=[]}this._lastActionTime=t,this._lastActionType=e}undo(){if(0===this._undoStack.length)return!1;this._redoStack.push(this._createSnapshot());const e=this._undoStack.pop();return e&&this._restoreSnapshot(e),this._lastActionType=null,this._lastActionTime=0,!0}redo(){if(0===this._redoStack.length)return!1;this._undoStack.push(this._createSnapshot());const e=this._redoStack.pop();return e&&this._restoreSnapshot(e),this._lastActionType=null,this._lastActionTime=0,!0}clearHistory(){this._undoStack=[],this._redoStack=[],this._lastActionType=null,this._lastActionTime=0}canUndo(){return this._undoStack.length>0}canRedo(){return this._redoStack.length>0}_generateNodeId(){return"node_"+ ++this._nodeIdCounter}_getCollapsedRangeForLine(e){for(const[t,i]of this._nodeIdToLines)if(this.collapsedNodes.has(t)&&e>i.startLine&&e<i.endLine)return{nodeId:t,...i};return null}_getCollapsedClosingLine(e){for(const[t,i]of this._nodeIdToLines)if(this.collapsedNodes.has(t)&&e===i.endLine)return{nodeId:t,...i};return null}_getClosingBracketPos(e){return Math.max(e.lastIndexOf("]"),e.lastIndexOf("}"))}_getCollapsedNodeAtLine(e){const t=this._lineToNodeId.get(e);if(t&&this.collapsedNodes.has(t)){const e=this._nodeIdToLines.get(t);if(e)return{nodeId:t,...e}}return null}_getContainingExpandedNode(e){let t=null;for(const[i,s]of this._nodeIdToLines)this.collapsedNodes.has(i)||e>=s.startLine&&e<=s.endLine&&(!t||s.endLine-s.startLine<t.endLine-t.startLine)&&(t={nodeId:i,...s});return t}_deleteCollapsedNode(e){this._saveToHistory("delete");const t=e.endLine-e.startLine+1;this.lines.splice(e.startLine,t),this.cursorLine=Math.min(e.startLine,this.lines.length-1),this.cursorColumn=0,this.formatAndUpdate()}_rebuildNodeIdMappings(){const e=/* @__PURE__ */new Set;for(const i of this.collapsedNodes){const t=this._nodeIdToLines.get(i);t?.uniqueKey&&e.add(t.uniqueKey)}this._nodeIdCounter=0,this._lineToNodeId.clear(),this._nodeIdToLines.clear(),this.collapsedNodes.clear();const t=/* @__PURE__ */new Map;for(let i=0;i<this.lines.length;i++){const s=this.lines[i],n=s.match(j),o=!n&&s.match(E);if(!n&&!o)continue;let r,l;if(n)r=n[1],l=n[2];else{if(!o)continue;l=o[1],r=`__root_${l}_${i}`}const a=$(s.substring(s.indexOf(l)+1),l);if(a.close>a.open)continue;const h=this._findClosingLine(i,l);if(-1===h||h===i)continue;const c=this._generateNodeId(),d=t.get(r)||0;t.set(r,d+1);const u=`${r}:${d}`;this._lineToNodeId.set(i,c),this._nodeIdToLines.set(c,{startLine:i,endLine:h,nodeKey:r,uniqueKey:u,isRootFeature:!!o}),e.has(u)&&!this._openedNodeKeys.has(u)&&this.collapsedNodes.add(c)}}static get observedAttributes(){return["readonly","value","placeholder","internal-add-shortcut"]}connectedCallback(){this.render(),this._cacheElements(),this.setupEventListeners(),this.updatePrefixSuffix(),this.value&&this.setValue(this.value),this.updatePlaceholderVisibility()}disconnectedCallback(){this.renderTimer&&clearTimeout(this.renderTimer),this.inputTimer&&clearTimeout(this.inputTimer);const e=document.querySelector(".geojson-color-picker-input");e&&(e._closeListener&&document.removeEventListener("click",e._closeListener,!0),e.remove())}attributeChangedCallback(e,t,i){if(t!==i)switch(e){case"value":this.setValue(i);break;case"readonly":this.updateReadonly();break;case"placeholder":this.updatePlaceholderContent()}}get readonly(){return this.hasAttribute("readonly")}get value(){return this.getAttribute("value")||""}get placeholder(){return this.getAttribute("placeholder")||""}get internalAddShortcut(){return this.hasAttribute("internal-add-shortcut")}get prefix(){return'{"type": "FeatureCollection", "features": ['}get suffix(){return"]}"}render(){const e=this.shadowRoot,t=D("style");t.textContent=':host *,:host *:before,:host *:after{box-sizing:border-box;font: 13px/1.5 Courier New,Courier,monospace;font-variant:normal;letter-spacing:0;word-spacing:0;text-transform:none;text-decoration:none;text-indent:0}:host{color-scheme:inherit;--line-height: 19.5px;--gutter-width: 50px;--editor-padding-y: 8px;--editor-padding-x: 12px;display:flex;flex-direction:column;position:relative;width:100%;height:400px;border-radius:4px;overflow:hidden}:host([readonly]) .editor-wrapper:after{content:"";position:absolute;inset:0;pointer-events:none;background:repeating-linear-gradient(-45deg,rgba(128,128,128,.08),rgba(128,128,128,.08) 3px,transparent 3px,transparent 12px);z-index:1}:host([readonly]) .hidden-textarea{cursor:text}.editor-wrapper{position:relative;width:100%;flex:1;background:var(--geojson-editor-bg-color, light-dark(#fff, #2b2b2b));display:flex;overflow:hidden}.gutter{width:var(--gutter-width);background:var(--geojson-editor-gutter-bg, light-dark(#f0f0f0, #313335));border-right:1px solid var(--geojson-editor-gutter-border, light-dark(#e0e0e0, #3c3f41));overflow:hidden;flex-shrink:0;position:relative}.gutter-scroll{position:absolute;inset:0;overflow:hidden;padding:8px 0}.gutter-scroll-content{position:relative;width:100%}.gutter-content{position:absolute;top:0;left:0;right:0;will-change:transform}.gutter-line{height:var(--line-height);display:flex;align-items:center;justify-content:flex-end;padding-right:4px;position:relative}.gutter-line.has-error:before{content:"";position:absolute;right:0;top:0;bottom:0;width:3px;background:var(--geojson-editor-error-color, light-dark(#dc3545, #ff6b68))}.line-number{font-size:11px;color:var(--geojson-editor-gutter-text, light-dark(#999, #606366));-webkit-user-select:none;user-select:none;min-width:20px;text-align:right}.collapse-column{width:16px;display:flex;align-items:center;justify-content:center;flex-shrink:0}.collapse-button{width:12px;height:12px;border-radius:2px;cursor:pointer;flex-shrink:0;background:transparent;border:none;color:var(--geojson-editor-json-punct, light-dark(#000, #a9b7c6));font-size:10px;display:flex;align-items:center;justify-content:center;-webkit-user-select:none;user-select:none;opacity:0;transition:transform .1s,opacity .15s}.collapse-button.collapsed,.gutter:hover .collapse-button{opacity:1}.collapse-button:hover{transform:scale(1.2)}@media(hover:none),(pointer:coarse){.collapse-button{opacity:1}}.editor-content{position:relative;flex:1;overflow:hidden}.hidden-textarea{position:absolute;top:0;left:0;width:100%;height:100%;opacity:0;padding:0;margin:0;border:none;outline:none;resize:none;overflow:hidden;z-index:-1;pointer-events:none;caret-color:transparent}.viewport{position:absolute;inset:0;overflow:auto;padding:var(--editor-padding-y) var(--editor-padding-x);overscroll-behavior:contain;scrollbar-width:thin;scrollbar-color:var(--geojson-editor-control-border, light-dark(#c0c0c0, #5a5a5a)) var(--geojson-editor-control-bg, light-dark(#e8e8e8, #3c3f41))}.scroll-content{position:relative;width:100%}.lines-container{position:absolute;top:0;left:0;right:0;will-change:transform}.line{height:var(--line-height);white-space:pre;display:block;position:relative}.cursor{position:absolute;width:2px;height:1em;background:var(--geojson-editor-caret-color, light-dark(#000, #bbb));top:.15em;pointer-events:none;animation:cursor-blink 1s step-end infinite}.cursor.cursor-block{width:.6em;opacity:.5;animation:cursor-blink-block 1s step-end infinite}@keyframes cursor-blink-block{0%,to{opacity:.5}50%{opacity:.2}}@keyframes cursor-blink{0%,to{opacity:1}50%{opacity:0}}.selection{position:absolute;height:100%;top:0;background:var(--geojson-editor-selection-color, light-dark(rgba(51, 153, 255, .3), rgba(51, 153, 255, .4)));pointer-events:none;z-index:0}.line-hidden>span{opacity:.35;filter:grayscale(50%)}.placeholder-layer{position:absolute;top:var(--editor-padding-y);left:var(--editor-padding-x);color:#6a6a6a;pointer-events:none;z-index:0;white-space:pre}.json-key{color:var(--geojson-editor-json-key, light-dark(#660e7a, #9876aa))}.json-string{color:var(--geojson-editor-json-string, light-dark(#008000, #6a8759))}.json-number{color:var(--geojson-editor-json-number, light-dark(#00f, #6897bb))}.json-boolean,.json-null{color:var(--geojson-editor-json-boolean, light-dark(#000080, #cc7832))}.json-punctuation{color:var(--geojson-editor-json-punct, light-dark(#000, #a9b7c6))}.json-error{color:var(--geojson-editor-json-error, light-dark(#f00, #ff6b68))}.geojson-key{color:var(--geojson-editor-geojson-key, light-dark(#660e7a, #9876aa));font-weight:600}.geojson-type{color:var(--geojson-editor-geojson-type, light-dark(#008000, #6a8759));font-weight:600}.geojson-type-invalid{color:var(--geojson-editor-geojson-type-invalid, light-dark(#f00, #ff6b68));font-weight:600}.collapsed-bracket-array,.collapsed-bracket-object{color:var(--geojson-editor-json-punct, light-dark(#000, #a9b7c6))}.collapsed-bracket-array:after,.collapsed-bracket-object:after{content:"…";color:var(--geojson-editor-json-punct, light-dark(#000, #a9b7c6))}.prefix-wrapper,.suffix-wrapper{display:flex;flex-shrink:0;background:var(--geojson-editor-bg-color, light-dark(#fff, #2b2b2b))}.prefix-gutter,.suffix-gutter{width:var(--gutter-width);background:var(--geojson-editor-gutter-bg, light-dark(#f0f0f0, #313335));border-right:1px solid var(--geojson-editor-gutter-border, light-dark(#e0e0e0, #3c3f41));flex-shrink:0}.editor-prefix,.editor-suffix{flex:1;padding:4px 12px;color:var(--geojson-editor-text-color, light-dark(#000, #a9b7c6));background:var(--geojson-editor-bg-color, light-dark(#fff, #2b2b2b));-webkit-user-select:none;user-select:none;white-space:pre-wrap;word-wrap:break-word;opacity:.6}.prefix-wrapper{border-bottom:1px solid rgba(255,255,255,.1);position:relative}.suffix-wrapper{border-top:1px solid rgba(255,255,255,.1);position:relative}.info-btn{position:absolute;right:.5rem;top:50%;transform:translateY(-50%);background:transparent;border:none;color:var(--geojson-editor-text-color, light-dark(#000, #a9b7c6));opacity:.15;cursor:pointer;font-size:.7rem;width:1rem;height:1rem;padding:0;border-radius:50%;display:flex;align-items:center;justify-content:center;transition:opacity .2s;font-family:sans-serif}.info-btn:hover{opacity:.5}.info-popup{display:none;position:absolute;top:2rem;right:.5rem;z-index:1000;background:var(--geojson-editor-bg-color, light-dark(#fff, #2b2b2b));border:1px solid var(--geojson-editor-gutter-border, light-dark(#e0e0e0, #3c3f41));border-radius:6px;box-shadow:0 4px 12px #00000026;padding:12px 16px;min-width:200px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}.info-popup.visible{display:block}.info-popup-content{text-align:center}.info-popup-title{font-weight:700;font-size:13px;color:var(--geojson-editor-text-color, light-dark(#000, #a9b7c6));margin-bottom:4px}.info-popup-version{display:block;font-size:11px;color:var(--geojson-editor-text-color, light-dark(#000, #a9b7c6));opacity:.6;margin-bottom:8px;text-decoration:none}.info-popup-version:hover{opacity:1;text-decoration:underline!important}.info-popup-copyright{font-size:10px;color:var(--geojson-editor-text-color, light-dark(#000, #a9b7c6));opacity:.5}.clear-btn{position:absolute;right:.5rem;top:50%;transform:translateY(-50%);background:transparent;border:none;color:var(--geojson-editor-text-color, light-dark(#000, #a9b7c6));opacity:.3;cursor:pointer;font-size:.65rem;width:1rem;height:1rem;padding:.15rem 0 0;border-radius:3px;display:flex;align-items:center;justify-content:center;transition:opacity .2s,background .2s}.clear-btn:hover{opacity:.7;background:#ffffff1a}.clear-btn[hidden]{display:none}.error-nav{display:none;align-items:center;gap:4px;margin-right:24px}.error-nav.visible{display:flex}.error-nav-btn{background:transparent;border:none;color:var(--geojson-editor-error-color, light-dark(#dc3545, #ff6b68));cursor:pointer;font-size:8px;width:16px;height:16px;padding:0;display:flex;align-items:center;justify-content:center;opacity:.7;transition:opacity .2s}.error-nav-btn:hover{opacity:1}.error-count{color:var(--geojson-editor-error-color, light-dark(#dc3545, #ff6b68));font-size:11px;min-width:20px;text-align:center}.viewport::-webkit-scrollbar{width:10px;height:10px}.viewport::-webkit-scrollbar-track{background:var(--geojson-editor-control-bg, light-dark(#e8e8e8, #3c3f41))}.viewport::-webkit-scrollbar-thumb{background:var(--geojson-editor-control-border, light-dark(#c0c0c0, #5a5a5a));border-radius:5px}.viewport::-webkit-scrollbar-thumb:hover{background:var(--geojson-editor-control-color, light-dark(#000080, #cc7832))}.json-color,.json-boolean{position:relative}.json-color:before,.json-boolean:before{content:"";position:absolute;left:-8px;top:50%;transform:translateY(-50%);margin-top:-1px;width:8px;height:8px;border-radius:2px;cursor:pointer}.json-color:hover:before,.json-boolean:hover:before{transform:translateY(-50%) scale(1.2);border-color:var(--geojson-editor-control-color, light-dark(#000080, #cc7832))}.json-color:before{background-color:var(--swatch-color);border:1px solid var(--geojson-editor-json-punct, light-dark(#000, #a9b7c6))}.json-boolean:before{border:1.5px solid var(--geojson-editor-control-border, light-dark(#c0c0c0, #5a5a5a));background:transparent}.json-bool-true:before{content:"✔";border-color:var(--geojson-editor-control-color, light-dark(#000080, #cc7832));color:var(--geojson-editor-control-color, light-dark(#000080, #cc7832));font-size:8px;display:flex;align-items:center;justify-content:center;line-height:8px}.line.has-visibility:before{content:"👁";position:absolute;left:0;top:3px;font-size:10px;color:var(--geojson-editor-control-color, light-dark(#000080, #cc7832));opacity:.6;cursor:pointer;z-index:1}.line.has-visibility:hover:before{opacity:1;transform:scale(1.15)}.line.has-visibility.feature-hidden:before{opacity:.5}';const i=D("div");for(i.innerHTML=function(e="",t=""){return`\n <div class="prefix-wrapper">\n <div class="prefix-gutter"></div>\n <div class="editor-prefix" id="editorPrefix"></div>\n <button class="info-btn" id="infoBtn" title="@softwarity/geojson-editor v${t}" aria-label="About">ⓘ</button>\n </div>\n <div class="editor-wrapper">\n <div class="gutter">\n <div class="gutter-scroll" id="gutterScroll">\n <div class="gutter-scroll-content" id="gutterScrollContent">\n <div class="gutter-content" id="gutterContent"></div>\n </div>\n </div>\n </div>\n <div class="editor-content">\n <div class="placeholder-layer" id="placeholderLayer">${i=e,i?i.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">"):""}</div>\n <textarea\n class="hidden-textarea"\n id="hiddenTextarea"\n spellcheck="false"\n autocomplete="off"\n autocorrect="off"\n autocapitalize="off"\n tabindex="0"\n ></textarea>\n <div class="viewport" id="viewport">\n <div class="scroll-content" id="scrollContent">\n <div class="lines-container" id="linesContainer"></div>\n </div>\n </div>\n </div>\n </div>\n <div class="suffix-wrapper">\n <div class="suffix-gutter"></div>\n <div class="editor-suffix" id="editorSuffix"></div>\n <div class="error-nav" id="errorNav">\n <button class="error-nav-btn" id="prevErrorBtn" title="Previous error">◀</button>\n <span class="error-count" id="errorCount"></span>\n <button class="error-nav-btn" id="nextErrorBtn" title="Next error">▶</button>\n </div>\n <button class="clear-btn" id="clearBtn" title="Clear editor">✕</button>\n </div>\n <div class="info-popup" id="infoPopup">\n <div class="info-popup-content">\n <div class="info-popup-title">GeoJSON Editor</div>\n <a class="info-popup-version" href="https://www.npmjs.com/package/@softwarity/geojson-editor/v/${t}" target="_blank" rel="noopener">v${t}</a>\n <div class="info-popup-copyright">© ${/* @__PURE__ */(new Date).getFullYear()} Softwarity</div>\n </div>\n </div>\n `;var i}(this.placeholder,"1.0.27"),e.innerHTML="",e.appendChild(t);i.firstChild;)e.appendChild(i.firstChild)}_cacheElements(){this._viewport=this._id("viewport"),this._linesContainer=this._id("linesContainer"),this._scrollContent=this._id("scrollContent"),this._hiddenTextarea=this._id("hiddenTextarea"),this._gutterContent=this._id("gutterContent"),this._gutterScrollContent=this._id("gutterScrollContent"),this._gutterScroll=this._id("gutterScroll"),this._gutter=this.shadowRoot.querySelector(".gutter"),this._clearBtn=this._id("clearBtn"),this._editorWrapper=this.shadowRoot.querySelector(".editor-wrapper"),this._placeholderLayer=this._id("placeholderLayer"),this._editorPrefix=this._id("editorPrefix"),this._editorSuffix=this._id("editorSuffix"),this._errorNav=this._id("errorNav"),this._errorCount=this._id("errorCount"),this._prevErrorBtn=this._id("prevErrorBtn"),this._nextErrorBtn=this._id("nextErrorBtn")}setupEventListeners(){const e=this._hiddenTextarea,t=this._viewport,i=this._gutterContent,s=this._gutter,n=this._clearBtn,o=this._editorWrapper;if(!(e&&t&&i&&s&&n&&o))return;this._isSelecting=!1,t.addEventListener("click",e=>{this.handleEditorClick(e)},!0),t.addEventListener("mousedown",t=>{const i=t.target,s=i.closest(".line.has-visibility");if(s){const e=s.getBoundingClientRect();if(t.clientX-e.left<14)return void(this._blockRender=!0)}if(i.classList.contains("json-color")||i.classList.contains("json-boolean")){const e=i.getBoundingClientRect(),s=t.clientX-e.left;if(s<0&&s>=-8)return void(this._blockRender=!0)}if(t.preventDefault(),2===t.detail){const i=this._getPositionFromClick(t);return this._selectWordAt(i.line,i.column),this._isSelecting=!1,e.focus(),this._invalidateRenderCache(),void this.scheduleRender()}const n=this._getPositionFromClick(t);t.shiftKey&&this.selectionStart?(this.selectionEnd=n,this.cursorLine=n.line,this.cursorColumn=n.column):(this.cursorLine=n.line,this.cursorColumn=n.column,this.selectionStart={line:n.line,column:n.column},this.selectionEnd=null,this._isSelecting=!0),e.focus(),this._invalidateRenderCache(),this.scheduleRender()});let r=null;const l=()=>{r&&(clearInterval(r),r=null)},a=e=>{l(),r=setInterval(()=>{this._isSelecting?("up"===e?t.scrollTop-=20:t.scrollTop+=20,this._updateSelectionFromScroll(e),this._invalidateRenderCache(),this.scheduleRender()):l()},50)};document.addEventListener("mousemove",e=>{if(!this._isSelecting)return;const i=t.getBoundingClientRect();if(e.clientY<i.top)a("up");else if(e.clientY>i.bottom)a("down");else{l();const s=this._getPositionFromClick(e);this.selectionEnd=s,this.cursorLine=s.line,this.cursorColumn=s.column,e.clientY<i.top+30?t.scrollTop-=20:e.clientY>i.bottom-30&&(t.scrollTop+=20),this._invalidateRenderCache(),this.scheduleRender()}}),document.addEventListener("mouseup",()=>{this._isSelecting=!1,l()}),e.addEventListener("focus",()=>{o.classList.add("focused"),this._invalidateRenderCache(),this.scheduleRender(),this._emitCurrentFeature(!0)}),e.addEventListener("blur",()=>{o.classList.remove("focused"),this._invalidateRenderCache(),this.scheduleRender(),this._emitCurrentFeatureNull()});let h=!1;t.addEventListener("scroll",()=>{h||(this.syncGutterScroll(),this._scrollRaf||(this._scrollRaf=requestAnimationFrame(()=>{this._scrollRaf=null,h=!0,this.renderViewport(),h=!1})))}),e.addEventListener("compositionstart",()=>{this._isComposing=!0}),e.addEventListener("compositionend",()=>{this._isComposing=!1,this.handleInput()}),e.addEventListener("input",()=>{this._isComposing||this.handleInput()}),e.addEventListener("keydown",e=>{this.handleKeydown(e)}),e.addEventListener("paste",e=>{this.handlePaste(e)}),e.addEventListener("copy",e=>{this.handleCopy(e)}),e.addEventListener("cut",e=>{this.handleCut(e)}),i.addEventListener("click",e=>{this.handleGutterClick(e)}),s.addEventListener("mousedown",e=>{e.preventDefault()}),s.addEventListener("wheel",e=>{e.preventDefault(),t.scrollTop+=e.deltaY}),n.addEventListener("click",()=>{this.removeAll()});const c=this._id("infoBtn"),d=this._id("infoPopup");c&&d&&(c.addEventListener("click",e=>{e.stopPropagation(),d.classList.toggle("visible")}),document.addEventListener("click",()=>{d.classList.remove("visible")})),this._prevErrorBtn?.addEventListener("click",()=>{this.goToPrevError()}),this._nextErrorBtn?.addEventListener("click",()=>{this.goToNextError()}),this.updateReadonly()}setValue(e,t=!0){if(this.lines.length>0&&this._saveToHistory("setValue"),e&&e.trim())try{const t="["+e+"]",i=JSON.parse(t),s=JSON.stringify(i,null,2).split("\n");this.lines=s.slice(1,-1)}catch(i){this.lines=e.split("\n")}else this.lines=[];this.collapsedNodes.clear(),this.hiddenFeatures.clear(),this._openedNodeKeys.clear(),this._lineToNodeId.clear(),this._nodeIdToLines.clear(),this.cursorLine=0,this.cursorColumn=0,this.updateModel(),this.scheduleRender(),this.updatePlaceholderVisibility(),t&&this.lines.length>0&&requestAnimationFrame(()=>{this.autoCollapseCoordinates()}),this.emitChange()}getContent(){return this.lines.join("\n")}updateModel(){this._contextMapCache=null,this._errorLinesCache=null,this._rebuildNodeIdMappings(),this.computeFeatureRanges(),this.computeLineMetadata(),this.computeVisibleLines()}updateView(){this.computeLineMetadata(),this.computeVisibleLines()}computeFeatureRanges(){this.featureRanges.clear();try{const e=this.lines.join("\n"),t=this.prefix+e+this.suffix;if(!JSON.parse(t).features)return;let i=0,s=0,n=!1,o=-1;for(let r=0;r<this.lines.length;r++){const e=this.lines[r];if(!n&&F.test(e)){let e=r;for(let t=r;t>=0;t--){const i=this.lines[t].trim();if("{"===i||"{,"===i){e=t;break}}o=e,n=!0,s=1;for(let t=e;t<=r;t++){const i=$(this.lines[t],"{");s+=t===e?i.open-1-i.close:i.open-i.close}}else if(n){const t=$(e,"{");s+=t.open-t.close,s<=0&&(this.featureRanges.set(i,{startLine:o,endLine:r,featureIndex:i}),i++,n=!1)}}}catch(e){}}computeLineMetadata(){this.lineMetadata.clear();const e=this._findCollapsibleRanges(),t=this._computeErrorLines();for(let i=0;i<this.lines.length;i++){const s=this.lines[i],n={colors:[],booleans:[],collapseButton:null,visibilityButton:null,isHidden:!1,isCollapsed:!1,featureIndex:null,hasError:t.has(i)};let o;for(k.lastIndex=0;null!==(o=k.exec(s));){const[,e,t,i]=o;i?n.booleans.push({attributeName:e,value:"true"===i}):t&&(v.test(t)||H(t))&&n.colors.push({attributeName:e,color:t})}const r=e.find(e=>e.startLine===i);r&&(n.collapseButton={nodeKey:r.nodeKey,nodeId:r.nodeId,isCollapsed:this.collapsedNodes.has(r.nodeId)}),e.find(e=>this.collapsedNodes.has(e.nodeId)&&i>e.startLine&&i<e.endLine)&&(n.isCollapsed=!0);for(const[e,t]of this.featureRanges)if(i>=t.startLine&&i<=t.endLine){n.featureIndex=e,this.hiddenFeatures.has(e)&&(n.isHidden=!0),i===t.startLine&&(n.visibilityButton={featureIndex:e,isHidden:this.hiddenFeatures.has(e)});break}this.lineMetadata.set(i,n)}}_computeErrorLines(){if(null!==this._errorLinesCache)return this._errorLinesCache;const e=/* @__PURE__ */new Set;for(let i=0;i<this.lines.length;i++)O(this.lines[i],"",void 0).includes("json-error")&&e.add(i);try{const e="["+this.lines.join("\n")+"]";JSON.parse(e)}catch(t){if(t instanceof Error){const i=t.message.match(/line (\d+)/);if(i){const t=Math.max(0,parseInt(i[1],10)-1);e.add(t)}}}return this._errorLinesCache=e,e}_getErrorLines(){const e=[];for(const[t,i]of this.lineMetadata)i.hasError&&e.push(t);return e.sort((e,t)=>e-t)}goToNextError(){const e=this._getErrorLines();if(0===e.length)return!1;const t=e.find(e=>e>this.cursorLine),i=void 0!==t?t:e[0];return this._goToErrorLine(i)}goToPrevError(){const e=this._getErrorLines();if(0===e.length)return!1;const t=e.filter(e=>e<this.cursorLine),i=t.length>0?t[t.length-1]:e[e.length-1];return this._goToErrorLine(i)}_expandNodesContainingLine(e){let t=!1;for(const[i,s]of this._nodeIdToLines)this.collapsedNodes.has(i)&&e>s.startLine&&e<=s.endLine&&(this.collapsedNodes.delete(i),s.uniqueKey&&this._openedNodeKeys.add(s.uniqueKey),t=!0);return t}_goToErrorLine(e){return this._expandNodesContainingLine(e)&&this.updateView(),this.cursorLine=e,this.cursorColumn=0,this._invalidateRenderCache(),this._scrollToCursor(!0),this.renderViewport(),this._updateErrorDisplay(),this._hiddenTextarea?.focus(),!0}_expandErrorNodes(){const e=this._getErrorLines();if(0===e.length)return;let t=!1;for(const i of e)this._expandNodesContainingLine(i)&&(t=!0);t&&this.updateView()}computeVisibleLines(){this.visibleLines=[];for(let e=0;e<this.lines.length;e++){const t=this.lineMetadata.get(e);t&&t.isCollapsed||this.visibleLines.push({index:e,content:this.lines[e],meta:t})}this._invalidateRenderCache()}scheduleRender(){this.renderTimer||(this.renderTimer=requestAnimationFrame(()=>{this.renderTimer=void 0,this.renderViewport()}))}renderViewport(){if(this._blockRender)return;const e=this._viewport,t=this._linesContainer,i=this._scrollContent;if(!e||!t)return;this.viewportHeight=e.clientHeight;const s=this.visibleLines.length,n=s*this.lineHeight;if(i){i.style.height=`${n}px`;const e=this._getCharWidth(),t=this.lines.reduce((e,t)=>Math.max(e,t.length),0)*e+20;i.style.minWidth=`${t}px`}const o=e.scrollTop,r=Math.floor(o/this.lineHeight),l=Math.ceil(this.viewportHeight/this.lineHeight),a=Math.max(0,r-this.bufferLines),h=Math.min(s,r+l+this.bufferLines);if(s>0&&this._lastStartIndex===a&&this._lastEndIndex===h&&this._lastTotalLines===s)return;this._lastStartIndex=a,this._lastEndIndex=h,this._lastTotalLines=s;const c=a*this.lineHeight;t.style.transform=`translateY(${c}px)`;const d=this._buildContextMap(),u=this._editorWrapper?.classList.contains("focused"),p=document.createDocumentFragment();if(0===s){const e=D("div");return e.className="line empty-line",e.dataset.lineIndex="0",u&&(e.innerHTML=this._insertCursor(0)),p.appendChild(e),t.innerHTML="",t.appendChild(p),void this.renderGutter(0,0)}for(let g=a;g<h;g++){const e=this.visibleLines[g];if(!e)continue;const t=D("div");t.className="line",t.dataset.lineIndex=String(e.index),e.meta?.visibilityButton&&(t.classList.add("has-visibility"),t.dataset.featureIndex=String(e.meta.visibilityButton.featureIndex),e.meta.visibilityButton.isHidden&&t.classList.add("feature-hidden")),e.meta?.isHidden&&t.classList.add("line-hidden");const i=d.get(e.index)||"Feature";let s=O(e.content,i,e.meta);u&&this._hasSelection()&&(s=this._addSelectionHighlight(s,e.index,e.content)),u&&e.index===this.cursorLine&&(s+=this._insertCursor(this.cursorColumn)),t.innerHTML=s,p.appendChild(t)}t.innerHTML="",t.appendChild(p),this.renderGutter(a,h),this._editorWrapper?.classList.contains("focused")&&this._emitCurrentFeature()}_insertCursor(e){const t=this._getCharWidth(),i=e*t;return this._insertMode?`<span class="cursor" style="left: ${i}px"></span>`:`<span class="cursor cursor-block" style="left: ${i}px; width: ${t}px"></span>`}_addSelectionHighlight(e,t,i){const s=this._normalizeSelection();if(!s)return e;const{start:n,end:o}=s;if(t<n.line||t>o.line)return e;const r=this._getCharWidth();let l,a;return t===n.line&&t===o.line?(l=n.column,a=o.column):t===n.line?(l=n.column,a=i.length):t===o.line?(l=0,a=o.column):(l=0,a=i.length),`<span class="selection" style="left: ${l*r}px; width: ${(a-l)*r}px"></span>`+e}_getCharWidth(){if(!this._charWidth){const e=D("canvas").getContext("2d");e?(e.font="13px 'Courier New', Courier, monospace",this._charWidth=e.measureText("M").width):this._charWidth=7.8}return this._charWidth}renderGutter(e,t){const i=this._gutterContent,s=this._gutterScrollContent;if(!i)return;const n=this.visibleLines.length*this.lineHeight;s&&(s.style.height=`${n}px`);const o=e*this.lineHeight;i.style.transform=`translateY(${o}px)`;const r=document.createDocumentFragment();for(let l=e;l<t;l++){const e=this.visibleLines[l];if(!e)continue;const t=D("div");t.className="gutter-line";const i=e.meta;i?.hasError&&t.classList.add("has-error");const s=D("span");s.className="line-number",s.textContent=String(e.index+1),t.appendChild(s);const n=D("div");if(n.className="collapse-column",i?.collapseButton){const t=D("div");t.className="collapse-button"+(i.collapseButton.isCollapsed?" collapsed":""),t.textContent=i.collapseButton.isCollapsed?"›":"⌄",t.dataset.line=String(e.index),t.dataset.nodeId=i.collapseButton.nodeId,t.title=i.collapseButton.isCollapsed?"Expand":"Collapse",n.appendChild(t)}t.appendChild(n),r.appendChild(t)}i.innerHTML="",i.appendChild(r)}syncGutterScroll(){this._gutterScroll&&this._viewport&&(this._gutterScroll.scrollTop=this._viewport.scrollTop)}handleInput(){const e=this._hiddenTextarea,t=e?.value;if(t)if(this._hasSelection()&&this._deleteSelection(),this._getCollapsedRangeForLine(this.cursorLine))e.value="";else{if(this._getCollapsedClosingLine(this.cursorLine)){const t=this.lines[this.cursorLine],i=this._getClosingBracketPos(t);if(this.cursorColumn<=i)return void(e.value="")}if(this._getCollapsedNodeAtLine(this.cursorLine)){const t=this.lines[this.cursorLine].search(I);if(this.cursorColumn>t)return void(e.value="")}if(this.cursorLine<this.lines.length){const e=this.lines[this.cursorLine],i=e.substring(0,this.cursorColumn),s=t.split("\n");if(1===s.length){if(this._insertMode){const s=e.substring(this.cursorColumn);this.lines[this.cursorLine]=i+t+s}else{const s=e.substring(this.cursorColumn+t.length);this.lines[this.cursorLine]=i+t+s}this.cursorColumn+=t.length}else{const t=e.substring(this.cursorColumn);this.lines[this.cursorLine]=i+s[0];for(let e=1;e<s.length-1;e++)this.lines.splice(this.cursorLine+e,0,s[e]);const n=s[s.length-1]+t;this.lines.splice(this.cursorLine+s.length-1,0,n),this.cursorLine+=s.length-1,this.cursorColumn=s[s.length-1].length}}else{const e=t.split("\n");this.lines.push(...e),this.cursorLine=this.lines.length-1,this.cursorColumn=this.lines[this.cursorLine].length}e.value="",clearTimeout(this.inputTimer),this.inputTimer=setTimeout(()=>{this.formatAndUpdate()},150)}}handleKeydown(e){const t={inCollapsedZone:this._getCollapsedRangeForLine(this.cursorLine),onCollapsedNode:this._getCollapsedNodeAtLine(this.cursorLine),onClosingLine:this._getCollapsedClosingLine(this.cursorLine)},i={Enter:()=>this._handleEnter(e.shiftKey,t),Backspace:()=>this._handleBackspace(t),Delete:()=>this._handleDelete(t),ArrowUp:()=>this._handleArrowKey(-1,0,e.shiftKey,e.ctrlKey||e.metaKey),ArrowDown:()=>this._handleArrowKey(1,0,e.shiftKey,e.ctrlKey||e.metaKey),ArrowLeft:()=>this._handleArrowKey(0,-1,e.shiftKey,e.ctrlKey||e.metaKey),ArrowRight:()=>this._handleArrowKey(0,1,e.shiftKey,e.ctrlKey||e.metaKey),Home:()=>this._handleHomeEnd("home",e.shiftKey,e.ctrlKey||e.metaKey,t.onClosingLine),End:()=>this._handleHomeEnd("end",e.shiftKey,e.ctrlKey||e.metaKey,t.onClosingLine),PageUp:()=>this._handlePageUpDown("up",e.shiftKey),PageDown:()=>this._handlePageUpDown("down",e.shiftKey),Tab:()=>this._handleTab(e.shiftKey,t),Insert:()=>{this._insertMode=!this._insertMode,this.scheduleRender()}},s={a:()=>this._selectAll(),z:()=>e.shiftKey?this.redo():this.undo(),y:()=>this.redo(),s:()=>this.save(),o:()=>!this.hasAttribute("readonly")&&this.open(),i:()=>this.internalAddShortcut&&!this.readonly&&this._handleAddFeaturePrompt()};if(i[e.key])return e.preventDefault(),e.stopPropagation(),void i[e.key]();(e.ctrlKey||e.metaKey)&&s[e.key]&&(e.preventDefault(),e.stopPropagation(),s[e.key]())}_handleEnter(e,t){if(e){const e=this._getContainingExpandedNode(this.cursorLine);if(e){const t=this.lines[e.startLine],i=t.search(I);this.toggleCollapse(e.nodeId),this.cursorLine=e.startLine,this.cursorColumn=i>=0?i+1:t.length,this._clearSelection(),this._scrollToCursor()}return}if(t.onCollapsedNode)this.toggleCollapse(t.onCollapsedNode.nodeId);else{if(t.onClosingLine){const e=this.lines[this.cursorLine],i=this._getClosingBracketPos(e);if(i>=0&&this.cursorColumn<=i)return void this.toggleCollapse(t.onClosingLine.nodeId)}t.inCollapsedZone}}_handleBackspace(e){if(this._hasSelection())return this._deleteSelection(),void this.formatAndUpdate();if(e.onClosingLine){const t=this.lines[this.cursorLine],i=this._getClosingBracketPos(t);return i>=0&&this.cursorColumn>i+1?void this.deleteBackward():void this._deleteCollapsedNode(e.onClosingLine)}if(e.onCollapsedNode&&0===this.cursorColumn)this._deleteCollapsedNode(e.onCollapsedNode);else if(!e.inCollapsedZone){if(e.onCollapsedNode){const t=this.lines[this.cursorLine].search(I);if(this.cursorColumn>t+1)return void this._deleteCollapsedNode(e.onCollapsedNode)}this.deleteBackward()}}_handleDelete(e){if(this._hasSelection())return this._deleteSelection(),void this.formatAndUpdate();if(e.onClosingLine){const t=this.lines[this.cursorLine],i=this._getClosingBracketPos(t);return i>=0&&this.cursorColumn>i?void this.deleteForward():void this._deleteCollapsedNode(e.onClosingLine)}if(e.onCollapsedNode){const t=this.lines[this.cursorLine].search(I);if(this.cursorColumn>t)return void this._deleteCollapsedNode(e.onCollapsedNode)}e.inCollapsedZone||this.deleteForward()}_handleTab(e,t){e?this._navigateToPrevAttribute():this._navigateToNextAttribute()}_navigateToNextAttribute(){const e=this.visibleLines.length;let t=this.visibleLines.findIndex(e=>e.index===this.cursorLine);t<0&&(t=0);for(let i=t;i<e;i++){const e=this.visibleLines[i],s=this.lines[e.index],n=i===t?this.cursorColumn:0,o=this._findNextAttributeOrBracket(s,n,e.index);if(null!==o)return this.cursorLine=e.index,this.cursorColumn=o.start,o.isBracket?this._clearSelection():(this.selectionStart={line:e.index,column:o.start},this.selectionEnd={line:e.index,column:o.end}),this._scrollToCursor(),this._invalidateRenderCache(),void this.scheduleRender()}for(let i=0;i<t;i++){const e=this.visibleLines[i],t=this.lines[e.index],s=this._findNextAttributeOrBracket(t,0,e.index);if(null!==s)return this.cursorLine=e.index,this.cursorColumn=s.start,s.isBracket?this._clearSelection():(this.selectionStart={line:e.index,column:s.start},this.selectionEnd={line:e.index,column:s.end}),this._scrollToCursor(),this._invalidateRenderCache(),void this.scheduleRender()}}_navigateToPrevAttribute(){const e=this.visibleLines.length;let t=this.visibleLines.findIndex(e=>e.index===this.cursorLine);t<0&&(t=e-1);for(let i=t;i>=0;i--){const e=this.visibleLines[i],s=this.lines[e.index],n=i===t?this.cursorColumn:s.length,o=this._findPrevAttributeOrBracket(s,n,e.index);if(null!==o)return this.cursorLine=e.index,this.cursorColumn=o.start,o.isBracket?this._clearSelection():(this.selectionStart={line:e.index,column:o.start},this.selectionEnd={line:e.index,column:o.end}),this._scrollToCursor(),this._invalidateRenderCache(),void this.scheduleRender()}for(let i=e-1;i>t;i--){const e=this.visibleLines[i],t=this.lines[e.index],s=this._findPrevAttributeOrBracket(t,t.length,e.index);if(null!==s)return this.cursorLine=e.index,this.cursorColumn=s.start,s.isBracket?this._clearSelection():(this.selectionStart={line:e.index,column:s.start},this.selectionEnd={line:e.index,column:s.end}),this._scrollToCursor(),this._invalidateRenderCache(),void this.scheduleRender()}}_findNextAttributeInLine(e,t){const i=[],s=/"([^"]+)"(?:\s*:\s*(?:"([^"]*)"|(-?\d+\.?\d*(?:e[+-]?\d+)?)|true|false|null))?/gi;let n;for(;null!==(n=s.exec(e));){const t=n.index+1,s=t+n[1].length;if(i.push({start:t,end:s}),void 0!==n[2]){const t=e.substring(n.index).match(/:\s*"([^"]*)"/);if(t){const e=n.index+(t.index||0)+t[0].indexOf('"')+1,s=e+n[2].length;i.push({start:e,end:s})}}else if(void 0!==n[3]){const t=e.substring(n.index).match(/:\s*(-?\d+\.?\d*(?:e[+-]?\d+)?)/i);if(t){const e=n.index+(t.index||0)+t[0].indexOf(t[1]),s=e+t[1].length;i.push({start:e,end:s})}}else{const t=e.substring(n.index).match(/:\s*(true|false|null)/);if(t){const e=n.index+(t.index||0)+t[0].indexOf(t[1]),s=e+t[1].length;i.push({start:e,end:s})}}}const o=/(?:^|[\[,\s])(-?\d+\.?\d*(?:e[+-]?\d+)?)\s*(?:[,\]]|$)/gi;for(;null!==(n=o.exec(e));){const e=n[1],t=n.index+n[0].indexOf(e),s=t+e.length;i.some(e=>e.start===t&&e.end===s)||i.push({start:t,end:s})}i.sort((e,t)=>e.start-t.start);for(const r of i)if(r.start>t)return r;return null}_findPrevAttributeInLine(e,t){const i=[],s=/"([^"]+)"(?:\s*:\s*(?:"([^"]*)"|(-?\d+\.?\d*(?:e[+-]?\d+)?)|true|false|null))?/gi;let n;for(;null!==(n=s.exec(e));){const t=n.index+1,s=t+n[1].length;if(i.push({start:t,end:s}),void 0!==n[2]){const t=e.substring(n.index).match(/:\s*"([^"]*)"/);if(t){const e=n.index+(t.index||0)+t[0].indexOf('"')+1,s=e+n[2].length;i.push({start:e,end:s})}}else if(void 0!==n[3]){const t=e.substring(n.index).match(/:\s*(-?\d+\.?\d*(?:e[+-]?\d+)?)/i);if(t){const e=n.index+(t.index||0)+t[0].indexOf(t[1]),s=e+t[1].length;i.push({start:e,end:s})}}else{const t=e.substring(n.index).match(/:\s*(true|false|null)/);if(t){const e=n.index+(t.index||0)+t[0].indexOf(t[1]),s=e+t[1].length;i.push({start:e,end:s})}}}const o=/(?:^|[\[,\s])(-?\d+\.?\d*(?:e[+-]?\d+)?)\s*(?:[,\]]|$)/gi;for(;null!==(n=o.exec(e));){const e=n[1],t=n.index+n[0].indexOf(e),s=t+e.length;i.some(e=>e.start===t&&e.end===s)||i.push({start:t,end:s})}i.sort((e,t)=>e.start-t.start);for(let r=i.length-1;r>=0;r--)if(i[r].end<t)return i[r];return null}_findBracketInLine(e){const t=e.match(/[\[{]\s*$/);return t&&void 0!==t.index?t.index+1:null}_findNextAttributeOrBracket(e,t,i){const s=this._findNextAttributeInLine(e,t),n=this._findBracketInLine(e);return null!==s&&null!==n?n>t&&n<s.start?{start:n,end:n,isBracket:!0}:{...s,isBracket:!1}:null!==s?{...s,isBracket:!1}:null!==n&&n>t?{start:n,end:n,isBracket:!0}:null}_findPrevAttributeOrBracket(e,t,i){const s=this._findPrevAttributeInLine(e,t),n=this._findBracketInLine(e);return null!==s&&null!==n?n<t&&n>s.end?{start:n,end:n,isBracket:!0}:{...s,isBracket:!1}:null!==s?{...s,isBracket:!1}:null!==n&&n<t?{start:n,end:n,isBracket:!0}:null}insertNewline(){if(this._saveToHistory("newline"),this.cursorLine<this.lines.length){const e=this.lines[this.cursorLine],t=e.substring(0,this.cursorColumn),i=e.substring(this.cursorColumn);this.lines[this.cursorLine]=t,this.lines.splice(this.cursorLine+1,0,i),this.cursorLine++,this.cursorColumn=0}else this.lines.push(""),this.cursorLine=this.lines.length-1,this.cursorColumn=0;this.formatAndUpdate()}deleteBackward(){if(this._saveToHistory("delete"),this.cursorColumn>0){const e=this.lines[this.cursorLine];this.lines[this.cursorLine]=e.substring(0,this.cursorColumn-1)+e.substring(this.cursorColumn),this.cursorColumn--}else if(this.cursorLine>0){const e=this.lines[this.cursorLine],t=this.lines[this.cursorLine-1];this.cursorColumn=t.length,this.lines[this.cursorLine-1]=t+e,this.lines.splice(this.cursorLine,1),this.cursorLine--}this.formatAndUpdate()}deleteForward(){if(this._saveToHistory("delete"),this.cursorLine<this.lines.length){const e=this.lines[this.cursorLine];this.cursorColumn<e.length?this.lines[this.cursorLine]=e.substring(0,this.cursorColumn)+e.substring(this.cursorColumn+1):this.cursorLine<this.lines.length-1&&(this.lines[this.cursorLine]=e+this.lines[this.cursorLine+1],this.lines.splice(this.cursorLine+1,1))}this.formatAndUpdate()}moveCursorSkipCollapsed(e){let t=this.cursorLine+e;for(;t>=0&&t<this.lines.length;){const i=this._getCollapsedRangeForLine(t);if(!i)break;t=e>0?i.endLine:i.startLine}this.cursorLine=Math.max(0,Math.min(this.lines.length-1,t));const i=this.lines[this.cursorLine]?.length||0;this.cursorColumn=Math.min(this.cursorColumn,i),this._invalidateRenderCache(),this._scrollToCursor(),this.scheduleRender()}moveCursorHorizontal(e){e>0?this._moveCursorRight():this._moveCursorLeft(),this._invalidateRenderCache(),this._scrollToCursor(),this.scheduleRender()}_moveCursorRight(){const e=this.lines[this.cursorLine],t=this._getCollapsedNodeAtLine(this.cursorLine);if(this._getCollapsedClosingLine(this.cursorLine)){const t=this._getClosingBracketPos(e);this.cursorColumn<t?this.cursorColumn=t:this.cursorColumn>=e.length?this.cursorLine<this.lines.length-1&&(this.cursorLine++,this.cursorColumn=0):this.cursorColumn++}else if(t){const i=e.search(I);this.cursorColumn<i?this.cursorColumn++:this.cursorColumn===i?this.cursorColumn=i+1:(this.cursorLine=t.endLine,this.cursorColumn=this._getClosingBracketPos(this.lines[this.cursorLine]))}else if(this.cursorColumn>=e.length){if(this.cursorLine<this.lines.length-1){this.cursorLine++,this.cursorColumn=0;const e=this._getCollapsedRangeForLine(this.cursorLine);e&&(this.cursorLine=e.endLine,this.cursorColumn=0)}}else this.cursorColumn++}_moveCursorLeft(){const e=this.lines[this.cursorLine],t=this._getCollapsedNodeAtLine(this.cursorLine),i=this._getCollapsedClosingLine(this.cursorLine);if(i){const t=this._getClosingBracketPos(e);if(this.cursorColumn>t+1)this.cursorColumn--;else{this.cursorLine=i.startLine;const e=this.lines[this.cursorLine];this.cursorColumn=e.search(I)+1}}else if(t){const t=e.search(I);this.cursorColumn>t+1?this.cursorColumn=t+1:this.cursorColumn===t+1?this.cursorColumn=t:this.cursorColumn>0?this.cursorColumn--:this.cursorLine>0&&(this.cursorLine--,this.cursorColumn=this.lines[this.cursorLine]?.length||0)}else if(this.cursorColumn>0)this.cursorColumn--;else if(this.cursorLine>0)if(this.cursorLine--,this._getCollapsedClosingLine(this.cursorLine))this.cursorColumn=this.lines[this.cursorLine]?.length||0;else{const e=this._getCollapsedRangeForLine(this.cursorLine);if(e){this.cursorLine=e.startLine;const t=this.lines[this.cursorLine];this.cursorColumn=t.search(I)+1}else this.cursorColumn=this.lines[this.cursorLine]?.length||0}}_scrollToCursor(e=!1){const t=this._viewport;if(!t)return;const i=this.visibleLines.findIndex(e=>e.index===this.cursorLine);if(-1===i)return;const s=i*this.lineHeight,n=t.clientHeight,o=2*this.lineHeight;if(e)t.scrollTop=Math.max(0,s-n/2+this.lineHeight/2);else{const e=t.scrollTop,i=e+n;s<e+o?t.scrollTop=Math.max(0,s-o):s+this.lineHeight>i-o&&(t.scrollTop=s+this.lineHeight+o-n)}}_handleArrowKey(e,t,i,s=!1){i&&!this.selectionStart&&(this.selectionStart={line:this.cursorLine,column:this.cursorColumn}),0!==e?this.moveCursorSkipCollapsed(e):0!==t&&(s?this._moveCursorByWord(t):this.moveCursorHorizontal(t)),i?this.selectionEnd={line:this.cursorLine,column:this.cursorColumn}:(this.selectionStart=null,this.selectionEnd=null)}_moveCursorByWord(e){const t=this.lines[this.cursorLine]||"",i=e=>T.test(e),s=this._getCollapsedNodeAtLine(this.cursorLine);if(e>0){let e=this.cursorColumn;if(s){const i=t.search(I);if(i>=0&&e>=i)return this.cursorLine=s.endLine,this.cursorColumn=(this.lines[this.cursorLine]||"").length,this._invalidateRenderCache(),this._scrollToCursor(),void this.scheduleRender()}if(e>=t.length){if(this.cursorLine<this.lines.length-1){let e=this.cursorLine+1;const t=this._getCollapsedRangeForLine(e);t&&(e=t.endLine),this.cursorLine=Math.min(e,this.lines.length-1),this.cursorColumn=0}}else if(i(t[e])){for(;e<t.length&&i(t[e]);)e++;this.cursorColumn=e}else{for(;e<t.length&&!i(t[e]);)e++;this.cursorColumn=e}}else{let e=this.cursorColumn;const s=this._getCollapsedClosingLine(this.cursorLine);if(s){const i=this._getClosingBracketPos(t);if(i>=0&&e<=i+1){this.cursorLine=s.startLine;const e=(this.lines[this.cursorLine]||"").search(I);return this.cursorColumn=e>=0?e:0,this._invalidateRenderCache(),this._scrollToCursor(),void this.scheduleRender()}}if(0===e){if(this.cursorLine>0){let e=this.cursorLine-1;const t=this._getCollapsedRangeForLine(e);t&&(e=t.startLine),this.cursorLine=Math.max(e,0),this.cursorColumn=this.lines[this.cursorLine].length}}else if(e>0&&i(t[e-1])){for(;e>0&&i(t[e-1]);)e--;this.cursorColumn=e}else{for(;e>0&&!i(t[e-1]);)e--;for(;e>0&&i(t[e-1]);)e--;this.cursorColumn=e}}this._invalidateRenderCache(),this._scrollToCursor(),this.scheduleRender()}_handleHomeEnd(e,t,i,s){if(t&&!this.selectionStart&&(this.selectionStart={line:this.cursorLine,column:this.cursorColumn}),"home"===e)i?(this.cursorLine=0,this.cursorColumn=0):s?(this.cursorLine=s.startLine,this.cursorColumn=0):this.cursorColumn=0;else if(i)this.cursorLine=this.lines.length-1,this.cursorColumn=this.lines[this.cursorLine]?.length||0;else{const e=this.lines[this.cursorLine]?.length||0;this.cursorColumn=e}t?this.selectionEnd={line:this.cursorLine,column:this.cursorColumn}:(this.selectionStart=null,this.selectionEnd=null),this._invalidateRenderCache(),this._scrollToCursor(),this.scheduleRender()}_handlePageUpDown(e,t){t&&!this.selectionStart&&(this.selectionStart={line:this.cursorLine,column:this.cursorColumn});const i=this._viewport;if(!i)return;const s=Math.floor(i.clientHeight/this.lineHeight);if("up"===e){const e=this.visibleLines.findIndex(e=>e.index===this.cursorLine),t=Math.max(0,e-s);this.cursorLine=this.visibleLines[t]?.index||0}else{const e=this.visibleLines.findIndex(e=>e.index===this.cursorLine),t=Math.min(this.visibleLines.length-1,e+s);this.cursorLine=this.visibleLines[t]?.index||this.lines.length-1}this.cursorColumn=Math.min(this.cursorColumn,this.lines[this.cursorLine]?.length||0),t?this.selectionEnd={line:this.cursorLine,column:this.cursorColumn}:(this.selectionStart=null,this.selectionEnd=null),this._invalidateRenderCache(),this._scrollToCursor(),this.scheduleRender()}_selectAll(){this.selectionStart={line:0,column:0};const e=this.lines.length-1;this.selectionEnd={line:e,column:this.lines[e]?.length||0},this.cursorLine=e,this.cursorColumn=this.lines[e]?.length||0,this._invalidateRenderCache(),this.scheduleRender()}_getSelectedText(){const e=this._normalizeSelection();if(!e)return"";const{start:t,end:i}=e;if(t.line===i.line)return this.lines[t.line].substring(t.column,i.column);let s=this.lines[t.line].substring(t.column)+"\n";for(let n=t.line+1;n<i.line;n++)s+=this.lines[n]+"\n";return s+=this.lines[i.line].substring(0,i.column),s}_normalizeSelection(){if(!this.selectionStart||!this.selectionEnd)return null;const e=this.selectionStart,t=this.selectionEnd;return e.line<t.line||e.line===t.line&&e.column<=t.column?{start:e,end:t}:{start:t,end:e}}_hasSelection(){return!(!this.selectionStart||!this.selectionEnd||this.selectionStart.line===this.selectionEnd.line&&this.selectionStart.column===this.selectionEnd.column)}_clearSelection(){this.selectionStart=null,this.selectionEnd=null}_selectWordAt(e,t){if(e<0||e>=this.lines.length)return;const i=this.lines[e];if(!i||t>i.length)return;const s=e=>/[\w\-]/.test(e);let n=!1,o=-1,r=-1,l=!1;for(let c=0;c<i.length;c++){const s=i[c];if(l)l=!1;else if("\\"!==s){if('"'===s)if(n){if(r=c,t>=o&&t<=r)return this.selectionStart={line:e,column:o+1},this.selectionEnd={line:e,column:r},this.cursorLine=e,void(this.cursorColumn=r);n=!1,o=-1,r=-1}else n=!0,o=c}else l=!0}let a=t,h=t;for(;a>0&&s(i[a-1]);)a--;for(;h<i.length&&s(i[h]);)h++;a<h&&(this.selectionStart={line:e,column:a},this.selectionEnd={line:e,column:h},this.cursorLine=e,this.cursorColumn=h)}_deleteSelection(){const e=this._normalizeSelection();if(!e)return!1;const{start:t,end:i}=e;if(this._saveToHistory("delete"),t.line===i.line){const e=this.lines[t.line];this.lines[t.line]=e.substring(0,t.column)+e.substring(i.column)}else{const e=this.lines[t.line].substring(0,t.column),s=this.lines[i.line].substring(i.column);this.lines[t.line]=e+s,this.lines.splice(t.line+1,i.line-t.line)}return this.cursorLine=t.line,this.cursorColumn=t.column,this.selectionStart=null,this.selectionEnd=null,!0}insertText(e){if(this._hasSelection()&&this._deleteSelection(),!this._getCollapsedRangeForLine(this.cursorLine)){if(this._getCollapsedClosingLine(this.cursorLine)){const e=this.lines[this.cursorLine],t=this._getClosingBracketPos(e);if(this.cursorColumn<=t)return}if(this._getCollapsedNodeAtLine(this.cursorLine)){const e=this.lines[this.cursorLine].search(I);if(this.cursorColumn>e)return}if(this._saveToHistory("insert"),0===this.lines.length){const t=e.split("\n");this.lines=t,this.cursorLine=t.length-1,this.cursorColumn=t[t.length-1].length}else if(this.cursorLine<this.lines.length){const t=e.split("\n"),i=this.lines[this.cursorLine],s=i.substring(0,this.cursorColumn),n=i.substring(this.cursorColumn);if(1===t.length)this.lines[this.cursorLine]=s+e+n,this.cursorColumn+=e.length;else{const e=s+t[0],i=t[t.length-1]+n,o=t.slice(1,-1);this.lines.splice(this.cursorLine,1,e,...o,i),this.cursorLine+=t.length-1,this.cursorColumn=t[t.length-1].length}}this.formatAndUpdate()}}handlePaste(e){e.preventDefault();const t=e.clipboardData?.getData("text/plain");if(!t)return;const i=/* @__PURE__ */new Set;for(const o of this.collapsedNodes){const e=this._nodeIdToLines.get(o);if(e?.nodeKey){const t=this._getFeatureIndexForLine(e.startLine);i.add(`${t}:${e.nodeKey}`)}}const s=this._parseFeatures().length;let n=0;try{let e;try{e=JSON.parse(t)}catch{e=JSON.parse("["+t+"]")}const i=K(e);n=i.length;const s=i.map(e=>JSON.stringify(e,null,2)).join(",\n");this.insertText(s)}catch{this.insertText(t)}if(this.renderTimer&&(cancelAnimationFrame(this.renderTimer),this.renderTimer=void 0),n>0){const e=this._findCollapsibleRanges();for(const t of e){const e=this._getFeatureIndexForLine(t.startLine);if(-1!==e)if(e<s){const s=`${e}:${t.nodeKey}`;i.has(s)&&this.collapsedNodes.add(t.nodeId)}else"coordinates"===t.nodeKey&&this.collapsedNodes.add(t.nodeId)}this.updateView()}this._expandErrorNodes(),this.renderViewport(),requestAnimationFrame(()=>{this._scrollToCursor()})}handleCopy(e){e.preventDefault(),e.clipboardData&&(this._hasSelection()?e.clipboardData.setData("text/plain",this._getSelectedText()):e.clipboardData.setData("text/plain",this.getContent()))}handleCut(e){e.preventDefault(),e.clipboardData&&(this._hasSelection()?(e.clipboardData.setData("text/plain",this._getSelectedText()),this._saveToHistory("cut"),this._deleteSelection(),this.formatAndUpdate()):(e.clipboardData.setData("text/plain",this.getContent()),this._saveToHistory("cut"),this.lines=[],this.cursorLine=0,this.cursorColumn=0,this.formatAndUpdate()))}_getPositionFromClick(e){const t=this._viewport,i=this._linesContainer;if(!t)return{line:0,column:0};const s=t.getBoundingClientRect(),n=e.clientY-s.top+t.scrollTop-8,o=Math.floor(n/this.lineHeight);let r=0,l=0;if(o>=0&&o<this.visibleLines.length){const n=this.visibleLines[o];r=n.index;const a=i?.querySelector(`.line[data-line-index="${n.index}"]`),h=this._getCharWidth();if(a){const t=a.getBoundingClientRect(),i=e.clientX-t.left,s=Math.round(i/h),o=n.content?.length||0;l=Math.max(0,Math.min(s,o))}else{const i=12,o=e.clientX-s.left+t.scrollLeft-i,r=Math.round(o/h),a=n.content?.length||0;l=Math.max(0,Math.min(r,a))}}return{line:r,column:l}}_updateSelectionFromScroll(e){if(this.visibleLines.length)if("up"===e){const e=this.visibleLines[0];this.selectionEnd={line:e.index,column:0},this.cursorLine=e.index,this.cursorColumn=0}else{const e=this.visibleLines[this.visibleLines.length-1],t=e.content?.length||0;this.selectionEnd={line:e.index,column:t},this.cursorLine=e.index,this.cursorColumn=t}}handleGutterClick(e){const t=e.target;if(!t)return;const i=t.closest(".visibility-button");if(i&&void 0!==i.dataset.featureIndex)this.toggleFeatureVisibility(parseInt(i.dataset.featureIndex,10));else if(t.classList.contains("collapse-button")){const e=t.dataset.nodeId;return void(e&&this.toggleCollapse(e))}}handleEditorClick(e){const t=e.target;if(!t)return;this._blockRender=!1;const i=t.closest(".line.has-visibility");if(i){const t=i.getBoundingClientRect();if(e.clientX-t.left<14){e.preventDefault(),e.stopPropagation();const t=i.dataset.featureIndex;return void(void 0!==t&&this.toggleFeatureVisibility(parseInt(t,10)))}}if(t.classList.contains("json-color")){const i=t.getBoundingClientRect(),s=e.clientX-i.left;if(s<0&&s>=-8){e.preventDefault(),e.stopPropagation();const i=t.dataset.color,s=t.closest(".line");if(s){const e=parseInt(s.dataset.lineIndex||"0"),n=this.lines[e].match(w);n&&n[1]&&i&&this.showColorPicker(t,e,i,n[1])}return}}if(t.classList.contains("json-boolean")){const i=t.getBoundingClientRect(),s=e.clientX-i.left;if(s<0&&s>=-8){e.preventDefault(),e.stopPropagation();const i=t.closest(".line");if(i){const e=parseInt(i.dataset.lineIndex||"0"),t=this.lines[e].match(S);if(t){const i="true"===t[2];this.updateBooleanValue(e,!i,t[1])}}return}}}toggleCollapse(e){const t=this._nodeIdToLines.get(e);this.collapsedNodes.has(e)?(this.collapsedNodes.delete(e),t?.uniqueKey&&this._openedNodeKeys.add(t.uniqueKey)):(this.collapsedNodes.add(e),t?.uniqueKey&&this._openedNodeKeys.delete(t.uniqueKey)),this.updateView(),this._invalidateRenderCache(),this.scheduleRender()}autoCollapseCoordinates(){this._hasErrors()||this._applyCollapsedOption(["coordinates"])}_hasErrors(){try{const e="["+this.lines.join("\n")+"]";JSON.parse(e)}catch{return!0}for(const e of this.lines)if(O(e,"",void 0).includes("json-error"))return!0;return!1}_applyCollapsedFromOptions(e,t){if(this._hasErrors())return;const i=void 0!==e.collapsed?e.collapsed:["coordinates"];i&&(!Array.isArray(i)||i.length>0)&&this._applyCollapsedOption(i,t)}_applyCollapsedOption(e,t=null){const i=this._findCollapsibleRanges();for(const s of i){let i=!1;if("function"==typeof e){const n=this._getFeatureIndexForLine(s.startLine);if(-1===n)continue;const o=e(t?.[n]||null,n);i=s.isRootFeature?o.includes("$root"):o.includes(s.nodeKey)}else Array.isArray(e)&&(i=s.isRootFeature?e.includes("$root"):e.includes(s.nodeKey));i&&this.collapsedNodes.add(s.nodeId)}this.updateModel(),this.scheduleRender()}toggleFeatureVisibility(e){void 0!==e&&(this.hiddenFeatures.has(e)?this.hiddenFeatures.delete(e):this.hiddenFeatures.add(e),this.updateView(),this.scheduleRender(),this.emitChange())}showColorPicker(e,t,i,s){const n=document.querySelector(".geojson-color-picker-anchor");n&&n.remove();const o=D("div");o.className="geojson-color-picker-anchor";const r=e.getBoundingClientRect();o.style.cssText=`\n position: fixed;\n left: ${r.left-8}px;\n top: ${r.top+r.height}px;\n width: 10px;\n height: 10px;\n z-index: 9998;\n `,document.body.appendChild(o);const l=D("input");l.type="color";let a=i;a=i.startsWith("#")?i.replace(L,"#$1$1$2$2$3$3"):function(e){const t=(P||(P=document.createElement("div"),P.style.display="none",document.body.appendChild(P)),P);t.style.color=e;const i=getComputedStyle(t).color;if(!i)return null;const s=i.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);if(!s)return null;const[,n,o,r]=s;return"#"+parseInt(n,10).toString(16).padStart(2,"0")+parseInt(o,10).toString(16).padStart(2,"0")+parseInt(r,10).toString(16).padStart(2,"0")}(i)||"#000000",l.value=a,l.className="geojson-color-picker-input",l.style.cssText="\n position: absolute;\n left: 0;\n top: 0;\n width: 10px;\n height: 10px;\n opacity: 0;\n border: none;\n padding: 0;\n cursor: pointer;\n ",o.appendChild(l),l.addEventListener("input",e=>{this.updateColorValue(t,e.target.value,s)});const h=e=>{e.target!==l&&(document.removeEventListener("click",h,!0),o.remove())};l._closeListener=h,setTimeout(()=>{document.addEventListener("click",h,!0)},100),l.focus(),l.click()}updateColorValue(e,t,i){const s=new RegExp(`"${i}"\\s*:\\s*"(?:#[0-9a-fA-F]{3,6}|[a-zA-Z]+)"`);this.lines[e]=this.lines[e].replace(s,`"${i}": "${t}"`),this.updateView(),this.scheduleRender(),this.emitChange()}updateBooleanValue(e,t,i){const s=new RegExp(`"${i}"\\s*:\\s*(true|false)`);this.lines[e]=this.lines[e].replace(s,`"${i}": ${t}`),this.updateView(),this.scheduleRender(),this.emitChange()}_bestEffortFormat(e,t){const i=e.split("\n");if(void 0!==t&&t>=0&&t<i.length){const e=i[t],s=i.slice(0,t).join("\n"),n=s.trim()?this._formatChunk(s):[],o=this._computeDepthAtEnd(n)+this._computeBracketDelta(e),r=i.slice(t+1).join("\n"),l=r.trim()?this._formatChunk(r,o):[];return[...n,e,...l]}return this._formatChunk(e)}_computeBracketDelta(e){let t=0,i=!1,s=!1;for(const n of e)s?s=!1:"\\"===n&&i?s=!0:'"'!==n?i||("{"===n||"["===n?t++:"}"!==n&&"]"!==n||t--):i=!i;return t}_computeDepthAtEnd(e){let t=1;for(const i of e)for(const e of i)"{"===e||"["===e?t++:"}"!==e&&"]"!==e||(t=Math.max(0,t-1));return t}_formatChunk(e,t=1){const i=[];let s="",n=t,o=!1,r=!1;for(let l=0;l<e.length;l++){const t=e[l];if(r)s+=t,r=!1;else if("\\"===t&&o)s+=t,r=!0;else if('"'!==t)if(o)s+=t;else if("{"===t||"["===t)s+=t,i.push(" ".repeat(n)+s.trim()),n++,s="";else if("}"===t||"]"===t)s.trim()&&i.push(" ".repeat(n)+s.trim()),n=Math.max(0,n-1),s=t;else if(","===t)s+=t,i.push(" ".repeat(n)+s.trim()),s="";else if(":"===t){if(s+=": ",l++," "===e[l])continue;l--}else{if("\n"===t||"\r"===t)continue;s+=t}else o=!o,s+=t}return s.trim()&&i.push(" ".repeat(n)+s.trim()),i}formatAndUpdate(){const e=this.cursorLine,t=this.cursorColumn,i=this.lines.join("\n"),s=this._countFeatures(i),n=this._getFeatureIndexForLine(e);try{const e="["+i+"]",t=JSON.parse(e),s=JSON.stringify(t,null,2).split("\n");this.lines=s.slice(1,-1)}catch{if(i.trim()){const t=(this.lines[e]||"").length<80?e:void 0,s=i.split("\n"),n=void 0!==t?this._formatChunk(s.slice(0,t).join("\n")).length:0;this.lines=this._bestEffortFormat(i,t),void 0!==t&&n>=0&&(this.cursorLine=n)}}if(this.lines.join("\n")===i)this.cursorLine=e,this.cursorColumn=t;else if(0===t)this.cursorColumn=0;else{const s=i.split("\n");let n=0;for(let t=0;t<e&&t<s.length;t++)n+=s[t].replace(/\s/g,"").length;n+=(s[e]||"").substring(0,t).replace(/\s/g,"").length;let o=0,r=0,l=0;for(let e=0;e<this.lines.length;e++){const t=this.lines[e];for(let i=0;i<=t.length;i++){if(o>=n){r=e,l=i;break}i<t.length&&!/\s/.test(t[i])&&o++}if(o>=n)break}this.cursorLine=r,this.cursorColumn=l}this.cursorLine=Math.min(this.cursorLine,Math.max(0,this.lines.length-1)),this.cursorColumn=Math.min(this.cursorColumn,this.lines[this.cursorLine]?.length||0);const o=this.lines.join("\n"),r=this._countFeatures(o);if(s>=0&&r>=0&&s!==r){const e=r-s,t=n>=0?n:0;this._adjustHiddenIndices(t,e)}this.updateModel(),this._expandErrorNodes(),this.scheduleRender(),this.updatePlaceholderVisibility(),this._updateErrorDisplay(),this.emitChange()}emitChange(){const e=this.getContent(),i=this.prefix+e+this.suffix;try{let s=JSON.parse(i);this.hiddenFeatures.size>0&&(s.features=s.features.filter((e,t)=>!this.hiddenFeatures.has(t)));const n=function(e){const i=[];return e.features?(e.features.forEach((e,s)=>{"Feature"!==e.type&&i.push(`features[${s}]: type must be "Feature"`),e.geometry&&e.geometry.type&&(t.includes(e.geometry.type)||i.push(`features[${s}].geometry: invalid type "${e.geometry.type}"`))}),i):i}(s);n.length>0?this.dispatchEvent(new CustomEvent("error",{detail:{error:n.join("; "),errors:n,content:e},bubbles:!0,composed:!0})):this.dispatchEvent(new CustomEvent("change",{detail:s,bubbles:!0,composed:!0}))}catch(s){this.dispatchEvent(new CustomEvent("error",{detail:{error:s instanceof Error?s.message:"Unknown error",content:e},bubbles:!0,composed:!0}))}}_emitCurrentFeature(e=!1){let t,i;this.selectionStart&&this.selectionEnd?(t=Math.min(this.selectionStart.line,this.selectionEnd.line),i=Math.max(this.selectionStart.line,this.selectionEnd.line)):(t=this.cursorLine,i=this.cursorLine);const s=this._getCoordinatePointsInRange(t,i);if(s.length>0){const t="coords:"+JSON.stringify(s);if(!e&&t===this._lastCurrentFeatureIndices)return;this._lastCurrentFeatureIndices=t;const i=s.map(e=>({type:"Feature",geometry:{type:"Point",coordinates:e},properties:{}}));return void this.dispatchEvent(new CustomEvent("current-features",{detail:{type:"FeatureCollection",features:i},bubbles:!0,composed:!0}))}const n=this._getFeatureIndicesForCurrentSelection(),o=JSON.stringify(n);if(e||o!==this._lastCurrentFeatureIndices)if(this._lastCurrentFeatureIndices=o,0===n.length)this.dispatchEvent(new CustomEvent("current-features",{detail:{type:"FeatureCollection",features:[]},bubbles:!0,composed:!0}));else{const e=this._parseFeatures(),t=n.map(t=>e[t]).filter(e=>null!=e);this.dispatchEvent(new CustomEvent("current-features",{detail:{type:"FeatureCollection",features:t},bubbles:!0,composed:!0}))}}_getCoordinatePointsInRange(e,t){const i=[],s=this._findCollapsibleRanges().filter(t=>"coordinates"===t.nodeKey&&!this.collapsedNodes.has(t.nodeId)&&e>=t.startLine&&e<=t.endLine);if(0===s.length)return i;const n=s[0],o=this.lines.slice(n.startLine,n.endLine+1).join("\n").match(/"coordinates"\s*:\s*(\[[\s\S]*)/);if(!o)return i;try{let s=0,r="",l=!1;for(const e of o[1])if("["===e&&(s++,l=!0),l&&(r+=e),"]"===e&&(s--,0===s))break;const a=JSON.parse(r),h=this._flattenCoordinates(a),c=this._findCoordinatesAtLines(n.startLine,n.endLine,e,t,h);for(const e of c)e.length>=2&&Math.abs(e[0])<=180&&Math.abs(e[1])<=90&&i.push(e)}catch{for(let s=e;s<=t;s++){const e=this.lines[s];if(!e)continue;const t=e.match(/\[\s*(-?\d+\.?\d*)\s*,\s*(-?\d+\.?\d*)(?:\s*,\s*(-?\d+\.?\d*))?\s*\]/);if(t){const e=[parseFloat(t[1]),parseFloat(t[2])];void 0!==t[3]&&e.push(parseFloat(t[3])),Math.abs(e[0])<=180&&Math.abs(e[1])<=90&&i.push(e)}}}return i}_flattenCoordinates(e){const t=[],i=e=>{if(Array.isArray(e))if(e.length>=2&&e.length<=3&&e.every(e=>"number"==typeof e))t.push(e);else for(const t of e)i(t)};return i(e),t}_findCoordinatesAtLines(e,t,i,s,n){if(0===n.length)return[];const o=t-e;if(o<=0)return 1===n.length?n:[];const r=o/n.length,l=[],a=i-e,h=s-e;for(let c=0;c<n.length;c++){const e=Math.floor(c*r),t=Math.floor((c+1)*r);e<=h&&t>=a&&l.push(n[c])}if(0===l.length&&n.length>0){const t=(i-e)/o,s=Math.min(Math.floor(t*n.length),n.length-1);l.push(n[Math.max(0,s)])}return l}_getFeatureIndicesForCurrentSelection(){const e=/* @__PURE__ */new Set;let t,i;this.selectionStart&&this.selectionEnd?(t=Math.min(this.selectionStart.line,this.selectionEnd.line),i=Math.max(this.selectionStart.line,this.selectionEnd.line)):(t=this.cursorLine,i=this.cursorLine);for(const[,s]of this.featureRanges)s.startLine<=i&&s.endLine>=t&&e.add(s.featureIndex);return Array.from(e).sort((e,t)=>e-t)}_emitCurrentFeatureNull(){this._lastCurrentFeatureIndices=null,this.dispatchEvent(new CustomEvent("current-features",{detail:{type:"FeatureCollection",features:[]},bubbles:!0,composed:!0}))}updateReadonly(){this._hiddenTextarea&&(this._hiddenTextarea.readOnly=this.readonly),this._clearBtn&&(this._clearBtn.hidden=this.readonly)}updatePlaceholderVisibility(){this._placeholderLayer&&(this._placeholderLayer.style.display=this.lines.length>0?"none":"block")}_updateErrorDisplay(){const e=this._getErrorLines().length;this._errorNav&&this._errorNav.classList.toggle("visible",e>0),this._errorCount&&(this._errorCount.textContent=e>0?String(e):"")}updatePlaceholderContent(){this._placeholderLayer&&(this._placeholderLayer.textContent=this.placeholder),this.updatePlaceholderVisibility()}updatePrefixSuffix(){this._editorPrefix&&(this._editorPrefix.textContent=this.prefix),this._editorSuffix&&(this._editorSuffix.textContent=this.suffix)}_findCollapsibleRanges(){const e=[];for(const[t,i]of this._lineToNodeId){const s=this._nodeIdToLines.get(i);if(!s)continue;const n=this.lines[t];if(!n)continue;const o=n.match(j),r=!o&&n.match(E);if(!o&&!r)continue;const l=o?o[2]:r?r[1]:"{";e.push({startLine:s.startLine,endLine:s.endLine,nodeKey:s.nodeKey||(o?o[1]:`__root_${t}`),nodeId:i,openBracket:l,isRootFeature:!!r})}return e.sort((e,t)=>e.startLine-t.startLine),e}_findClosingLine(e,t){let i=1;const s=this.lines[e],n=s.indexOf(t);if(-1!==n){const o=$(s.substring(n+1),t);if(i+=o.open-o.close,0===i)return e}for(let o=e+1;o<this.lines.length;o++){const e=$(this.lines[o],t);if(i+=e.open-e.close,0===i)return o}return-1}_buildContextMap(){const e=this.lines.length;if(this._contextMapCache&&this._contextMapLinesLength===e&&this._contextMapFirstLine===this.lines[0]&&this._contextMapLastLine===this.lines[e-1])return this._contextMapCache;const t=/* @__PURE__ */new Map,o=[];let r=null;for(let l=0;l<e;l++){const e=this.lines[l],a=o[o.length-1]?.context||"Feature";t.set(l,a),i.test(e)?r="geometry":s.test(e)?r="properties":n.test(e)&&(r="Feature"),N.lastIndex=0,R.lastIndex=0,A.lastIndex=0,M.lastIndex=0;const h=(e.match(N)||[]).length,c=(e.match(R)||[]).length,d=(e.match(A)||[]).length,u=(e.match(M)||[]).length;for(let t=0;t<h+d;t++)o.push({context:r||a,isArray:t>=h}),r=null;for(let t=0;t<c+u&&o.length>0;t++)o.pop()}return this._contextMapCache=t,this._contextMapLinesLength=e,this._contextMapFirstLine=this.lines[0],this._contextMapLastLine=this.lines[e-1],t}set(e,t={}){const i=K(e);this._setFeaturesInternal(i,t)}add(e,t={}){const i=K(e),s=this._parseFeatures().length,n=[...this._parseFeatures(),...i];this._setFeaturesInternalPreserving(n,t,s)}insertAt(e,t,i={}){const s=K(e),n=this._parseFeatures(),o=t<0?n.length+t:t,r=Math.max(0,Math.min(o,n.length));this._adjustHiddenIndices(r,s.length),n.splice(r,0,...s),this._setFeaturesInternalPreserving(n,i,r,s.length)}_setFeaturesInternal(e,t){const i=e.map(e=>JSON.stringify(e,null,2)).join(",\n");this.setValue(i,!1),this._applyCollapsedFromOptions(t,e)}_setFeaturesInternalPreserving(e,t,i,s){const n=/* @__PURE__ */new Set;for(const h of this.collapsedNodes){const e=this._nodeIdToLines.get(h);if(e?.nodeKey){const t=this._getFeatureIndexForLine(e.startLine);n.add(`${t}:${e.nodeKey}`)}}const o=new Set(this.hiddenFeatures),r=e.map(e=>JSON.stringify(e,null,2)).join(",\n");this.setValue(r,!1),this.hiddenFeatures=o;const l=this._findCollapsibleRanges(),a=void 0!==s?s:e.length-i;for(const h of l){const e=this._getFeatureIndexForLine(h.startLine);if(-1===e)continue;let t=e;if(e>=i&&e<i+a)continue;e>=i+a&&(t=e-a);const s=`${t}:${h.nodeKey}`;n.has(s)&&this.collapsedNodes.add(h.nodeId)}this._applyCollapsedToNewFeatures(t,e,i,a),this.updateView(),this.scheduleRender()}_applyCollapsedToNewFeatures(e,t,i,s){const n=void 0!==e.collapsed?e.collapsed:["coordinates"];if(!n||Array.isArray(n)&&0===n.length)return;const o=this._findCollapsibleRanges();for(const r of o){const e=this._getFeatureIndexForLine(r.startLine);if(-1===e)continue;if(e<i||e>=i+s)continue;let o=!1;if("function"==typeof n){const i=n(t[e],e);o=r.isRootFeature?i.includes("$root"):i.includes(r.nodeKey)}else Array.isArray(n)&&(o=r.isRootFeature?n.includes("$root"):n.includes(r.nodeKey));o&&this.collapsedNodes.add(r.nodeId)}}_countFeatures(e){try{const t="["+e+"]",i=JSON.parse(t);return Array.isArray(i)?i.length:-1}catch{return-1}}_adjustHiddenIndices(e,t){if(0===t||0===this.hiddenFeatures.size)return;const i=/* @__PURE__ */new Set;for(const s of this.hiddenFeatures)if(s<e)i.add(s);else{const e=s+t;e>=0&&i.add(e)}this.hiddenFeatures=i}_removeAndShiftHiddenIndex(e){if(0===this.hiddenFeatures.size)return;const t=/* @__PURE__ */new Set;for(const i of this.hiddenFeatures)i<e?t.add(i):i>e&&t.add(i-1);this.hiddenFeatures=t}_getFeatureIndexForLine(e){for(const[,t]of this.featureRanges)if(e>=t.startLine&&e<=t.endLine)return t.featureIndex;return-1}removeAt(e){const t=this._parseFeatures(),i=e<0?t.length+e:e;if(i>=0&&i<t.length){const e=/* @__PURE__ */new Set;for(const t of this.collapsedNodes){const s=this._nodeIdToLines.get(t);if(s?.nodeKey){const t=this._getFeatureIndexForLine(s.startLine);if(t===i)continue;const n=t>i?t-1:t;e.add(`${n}:${s.nodeKey}`)}}this._removeAndShiftHiddenIndex(i);const s=new Set(this.hiddenFeatures),n=t.splice(i,1)[0],o=t.map(e=>JSON.stringify(e,null,2)).join(",\n");this.setValue(o,!1),this.hiddenFeatures=s;const r=this._findCollapsibleRanges();for(const t of r){const i=this._getFeatureIndexForLine(t.startLine);if(-1===i)continue;const s=`${i}:${t.nodeKey}`;e.has(s)&&this.collapsedNodes.add(t.nodeId)}return this.updateView(),this.scheduleRender(),this.emitChange(),this._lastCurrentFeatureIndices=null,this._editorWrapper?.classList.contains("focused")&&this._emitCurrentFeature(!0),n}}removeAll(){this.lines.length>0&&this._saveToHistory("removeAll");const e=this._parseFeatures();return this.lines=[],this.collapsedNodes.clear(),this.hiddenFeatures.clear(),this.cursorLine=0,this.cursorColumn=0,this.selectionStart=null,this.selectionEnd=null,this.updateModel(),this.scheduleRender(),this.updatePlaceholderVisibility(),this.emitChange(),this._lastCurrentFeatureIndices=null,this._editorWrapper?.classList.contains("focused")&&this._emitCurrentFeature(!0),e}get(e){const t=this._parseFeatures();return t[e<0?t.length+e:e]}getAll(){return this._parseFeatures()}emit(){this.emitChange()}save(e="features.geojson"){try{const t={type:"FeatureCollection",features:this._parseFeatures()},i=JSON.stringify(t,null,2),s=new Blob([i],{type:"application/geo+json"}),n=URL.createObjectURL(s),o=D("a");return o.href=n,o.download=e,document.body.appendChild(o),o.click(),document.body.removeChild(o),URL.revokeObjectURL(n),!0}catch(t){return!1}}open(e={}){return new Promise(t=>{const i=D("input");i.type="file",i.accept=".geojson,.json,application/geo+json,application/json",i.style.display="none",i.addEventListener("change",s=>{const n=s.target.files?.[0];if(!n)return document.body.removeChild(i),void t(!1);const o=new FileReader;o.onload=s=>{try{const n=s.target?.result,o=K(JSON.parse(n));this._saveToHistory("open"),this.set(o,e),this.clearHistory(),document.body.removeChild(i),t(!0)}catch(n){document.body.removeChild(i),t(!1)}},o.onerror=()=>{document.body.removeChild(i),t(!1)},o.readAsText(n)}),i.addEventListener("cancel",()=>{document.body.removeChild(i),t(!1)}),document.body.appendChild(i),i.click()})}_handleAddFeaturePrompt(){const e=prompt("Enter GeoJSON (Feature, Feature[], or FeatureCollection):");if(e&&e.trim())try{const t=K(JSON.parse(e));t.length>0&&this.add(t)}catch{}}_parseFeatures(){try{const e=this.lines.join("\n");return e.trim()?JSON.parse("["+e+"]"):[]}catch(e){return[]}}}customElements.get("geojson-editor")||customElements.define("geojson-editor",V);export{V as default};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@softwarity/geojson-editor",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.27",
|
|
4
4
|
"description": "A feature-rich GeoJSON editor Web Component with syntax highlighting, collapsible nodes, and color picker",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/geojson-editor.js",
|
package/src/geojson-editor.ts
CHANGED
|
@@ -155,11 +155,19 @@ class GeoJsonEditor extends HTMLElement {
|
|
|
155
155
|
* @returns {Object} State snapshot
|
|
156
156
|
*/
|
|
157
157
|
private _createSnapshot() {
|
|
158
|
+
// Collect uniqueKeys of collapsed nodes
|
|
159
|
+
const collapsedUniqueKeys: string[] = [];
|
|
160
|
+
for (const nodeId of this.collapsedNodes) {
|
|
161
|
+
const info = this._nodeIdToLines.get(nodeId);
|
|
162
|
+
if (info?.uniqueKey) collapsedUniqueKeys.push(info.uniqueKey);
|
|
163
|
+
}
|
|
164
|
+
|
|
158
165
|
return {
|
|
159
166
|
lines: [...this.lines],
|
|
160
167
|
cursorLine: this.cursorLine,
|
|
161
168
|
cursorColumn: this.cursorColumn,
|
|
162
|
-
timestamp: Date.now()
|
|
169
|
+
timestamp: Date.now(),
|
|
170
|
+
collapsedUniqueKeys
|
|
163
171
|
};
|
|
164
172
|
}
|
|
165
173
|
|
|
@@ -171,6 +179,24 @@ class GeoJsonEditor extends HTMLElement {
|
|
|
171
179
|
this.cursorLine = snapshot.cursorLine;
|
|
172
180
|
this.cursorColumn = snapshot.cursorColumn;
|
|
173
181
|
this.updateModel();
|
|
182
|
+
|
|
183
|
+
// Restore collapsed state from snapshot
|
|
184
|
+
if (snapshot.collapsedUniqueKeys !== undefined) {
|
|
185
|
+
// Snapshot has collapsed state info - restore it (even if empty array = nothing collapsed)
|
|
186
|
+
this.collapsedNodes.clear();
|
|
187
|
+
const uniqueKeysToCollapse = new Set(snapshot.collapsedUniqueKeys);
|
|
188
|
+
|
|
189
|
+
for (const [nodeId, info] of this._nodeIdToLines) {
|
|
190
|
+
if (info.uniqueKey && uniqueKeysToCollapse.has(info.uniqueKey)) {
|
|
191
|
+
this.collapsedNodes.add(nodeId);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
} else {
|
|
195
|
+
// Old snapshot without collapsed state - apply default (collapse coordinates)
|
|
196
|
+
this.collapsedNodes.clear();
|
|
197
|
+
this._applyCollapsedOption(['coordinates']);
|
|
198
|
+
}
|
|
199
|
+
|
|
174
200
|
this._invalidateRenderCache();
|
|
175
201
|
this.scheduleRender();
|
|
176
202
|
this.updatePlaceholderVisibility();
|
|
@@ -3552,17 +3578,53 @@ class GeoJsonEditor extends HTMLElement {
|
|
|
3552
3578
|
/**
|
|
3553
3579
|
* Emit current-features event when cursor/selection changes
|
|
3554
3580
|
* Includes all features that overlap with the selection (or just cursor position if no selection)
|
|
3581
|
+
* If cursor is inside an expanded coordinates block, emits Point features for each coordinate line
|
|
3555
3582
|
* Only emits when the set of features changes (not on every cursor move)
|
|
3556
3583
|
* @param force - If true, emit even if features haven't changed (used on focus)
|
|
3557
3584
|
*/
|
|
3558
3585
|
private _emitCurrentFeature(force: boolean = false): void {
|
|
3559
|
-
//
|
|
3560
|
-
|
|
3586
|
+
// Determine the line range to check
|
|
3587
|
+
let startLine: number;
|
|
3588
|
+
let endLine: number;
|
|
3561
3589
|
|
|
3562
|
-
|
|
3590
|
+
if (this.selectionStart && this.selectionEnd) {
|
|
3591
|
+
startLine = Math.min(this.selectionStart.line, this.selectionEnd.line);
|
|
3592
|
+
endLine = Math.max(this.selectionStart.line, this.selectionEnd.line);
|
|
3593
|
+
} else {
|
|
3594
|
+
startLine = this.cursorLine;
|
|
3595
|
+
endLine = this.cursorLine;
|
|
3596
|
+
}
|
|
3597
|
+
|
|
3598
|
+
// Check if we're inside an expanded coordinates block
|
|
3599
|
+
const coordinatePoints = this._getCoordinatePointsInRange(startLine, endLine);
|
|
3600
|
+
|
|
3601
|
+
if (coordinatePoints.length > 0) {
|
|
3602
|
+
// We're inside coordinates - emit Points
|
|
3603
|
+
const pointsKey = 'coords:' + JSON.stringify(coordinatePoints);
|
|
3604
|
+
if (!force && pointsKey === this._lastCurrentFeatureIndices) return;
|
|
3605
|
+
this._lastCurrentFeatureIndices = pointsKey;
|
|
3606
|
+
|
|
3607
|
+
const features = coordinatePoints.map(coord => ({
|
|
3608
|
+
type: 'Feature' as const,
|
|
3609
|
+
geometry: {
|
|
3610
|
+
type: 'Point' as const,
|
|
3611
|
+
coordinates: coord
|
|
3612
|
+
},
|
|
3613
|
+
properties: {}
|
|
3614
|
+
}));
|
|
3615
|
+
|
|
3616
|
+
this.dispatchEvent(new CustomEvent('current-features', {
|
|
3617
|
+
detail: { type: 'FeatureCollection', features },
|
|
3618
|
+
bubbles: true,
|
|
3619
|
+
composed: true
|
|
3620
|
+
}));
|
|
3621
|
+
return;
|
|
3622
|
+
}
|
|
3623
|
+
|
|
3624
|
+
// Not in coordinates - use normal feature detection
|
|
3625
|
+
const featureIndices = this._getFeatureIndicesForCurrentSelection();
|
|
3563
3626
|
const indicesKey = JSON.stringify(featureIndices);
|
|
3564
3627
|
|
|
3565
|
-
// Only emit if features changed (unless forced)
|
|
3566
3628
|
if (!force && indicesKey === this._lastCurrentFeatureIndices) return;
|
|
3567
3629
|
this._lastCurrentFeatureIndices = indicesKey;
|
|
3568
3630
|
|
|
@@ -3580,19 +3642,165 @@ class GeoJsonEditor extends HTMLElement {
|
|
|
3580
3642
|
.map(idx => allFeatures[idx])
|
|
3581
3643
|
.filter(f => f != null);
|
|
3582
3644
|
|
|
3583
|
-
const featureCollection = {
|
|
3584
|
-
type: 'FeatureCollection',
|
|
3585
|
-
features: selectedFeatures
|
|
3586
|
-
};
|
|
3587
|
-
|
|
3588
3645
|
this.dispatchEvent(new CustomEvent('current-features', {
|
|
3589
|
-
detail:
|
|
3646
|
+
detail: { type: 'FeatureCollection', features: selectedFeatures },
|
|
3590
3647
|
bubbles: true,
|
|
3591
3648
|
composed: true
|
|
3592
3649
|
}));
|
|
3593
3650
|
}
|
|
3594
3651
|
}
|
|
3595
3652
|
|
|
3653
|
+
/**
|
|
3654
|
+
* Get coordinate points from lines in the given range if inside an expanded coordinates block
|
|
3655
|
+
* Returns array of [lng, lat] or [lng, lat, alt] coordinates
|
|
3656
|
+
* Handles both compact format ([lng, lat] on one line) and expanded format (multiline)
|
|
3657
|
+
*/
|
|
3658
|
+
private _getCoordinatePointsInRange(startLine: number, endLine: number): number[][] {
|
|
3659
|
+
const points: number[][] = [];
|
|
3660
|
+
const ranges = this._findCollapsibleRanges();
|
|
3661
|
+
|
|
3662
|
+
// Find coordinates blocks that contain our line range
|
|
3663
|
+
const coordsRanges = ranges.filter(r =>
|
|
3664
|
+
r.nodeKey === 'coordinates' &&
|
|
3665
|
+
!this.collapsedNodes.has(r.nodeId) && // Only if expanded
|
|
3666
|
+
startLine >= r.startLine &&
|
|
3667
|
+
startLine <= r.endLine
|
|
3668
|
+
);
|
|
3669
|
+
|
|
3670
|
+
if (coordsRanges.length === 0) return points;
|
|
3671
|
+
|
|
3672
|
+
// Get the coordinates block content and parse it
|
|
3673
|
+
const coordsRange = coordsRanges[0];
|
|
3674
|
+
const coordsContent = this.lines.slice(coordsRange.startLine, coordsRange.endLine + 1).join('\n');
|
|
3675
|
+
|
|
3676
|
+
// Extract the array part after "coordinates":
|
|
3677
|
+
const arrayMatch = coordsContent.match(/"coordinates"\s*:\s*(\[[\s\S]*)/);
|
|
3678
|
+
if (!arrayMatch) return points;
|
|
3679
|
+
|
|
3680
|
+
// Try to parse the coordinates array
|
|
3681
|
+
try {
|
|
3682
|
+
// Find the matching closing bracket for the coordinates array
|
|
3683
|
+
let depth = 0;
|
|
3684
|
+
let arrayStr = '';
|
|
3685
|
+
let started = false;
|
|
3686
|
+
for (const char of arrayMatch[1]) {
|
|
3687
|
+
if (char === '[') { depth++; started = true; }
|
|
3688
|
+
if (started) arrayStr += char;
|
|
3689
|
+
if (char === ']') { depth--; if (depth === 0) break; }
|
|
3690
|
+
}
|
|
3691
|
+
|
|
3692
|
+
const coordsArray = JSON.parse(arrayStr);
|
|
3693
|
+
|
|
3694
|
+
// Flatten to get all coordinate pairs (handles Point, LineString, Polygon, MultiPolygon)
|
|
3695
|
+
const flatCoords = this._flattenCoordinates(coordsArray);
|
|
3696
|
+
|
|
3697
|
+
// Map each coordinate to its approximate line range and check if cursor is in it
|
|
3698
|
+
// We'll compute which coordinates the cursor/selection overlaps with
|
|
3699
|
+
const selectedCoords = this._findCoordinatesAtLines(
|
|
3700
|
+
coordsRange.startLine,
|
|
3701
|
+
coordsRange.endLine,
|
|
3702
|
+
startLine,
|
|
3703
|
+
endLine,
|
|
3704
|
+
flatCoords
|
|
3705
|
+
);
|
|
3706
|
+
|
|
3707
|
+
for (const coord of selectedCoords) {
|
|
3708
|
+
// Validate it looks like a real coordinate (lng: -180 to 180, lat: -90 to 90)
|
|
3709
|
+
if (coord.length >= 2 && Math.abs(coord[0]) <= 180 && Math.abs(coord[1]) <= 90) {
|
|
3710
|
+
points.push(coord);
|
|
3711
|
+
}
|
|
3712
|
+
}
|
|
3713
|
+
} catch {
|
|
3714
|
+
// If parsing fails, fall back to simple line matching
|
|
3715
|
+
for (let i = startLine; i <= endLine; i++) {
|
|
3716
|
+
const line = this.lines[i];
|
|
3717
|
+
if (!line) continue;
|
|
3718
|
+
|
|
3719
|
+
// Match compact coordinate patterns: [lng, lat] or [lng, lat, alt]
|
|
3720
|
+
const coordMatch = line.match(/\[\s*(-?\d+\.?\d*)\s*,\s*(-?\d+\.?\d*)(?:\s*,\s*(-?\d+\.?\d*))?\s*\]/);
|
|
3721
|
+
if (coordMatch) {
|
|
3722
|
+
const coord = [parseFloat(coordMatch[1]), parseFloat(coordMatch[2])];
|
|
3723
|
+
if (coordMatch[3] !== undefined) {
|
|
3724
|
+
coord.push(parseFloat(coordMatch[3]));
|
|
3725
|
+
}
|
|
3726
|
+
if (Math.abs(coord[0]) <= 180 && Math.abs(coord[1]) <= 90) {
|
|
3727
|
+
points.push(coord);
|
|
3728
|
+
}
|
|
3729
|
+
}
|
|
3730
|
+
}
|
|
3731
|
+
}
|
|
3732
|
+
|
|
3733
|
+
return points;
|
|
3734
|
+
}
|
|
3735
|
+
|
|
3736
|
+
/**
|
|
3737
|
+
* Flatten nested coordinate arrays to get all [lng, lat] pairs
|
|
3738
|
+
*/
|
|
3739
|
+
private _flattenCoordinates(coords: unknown): number[][] {
|
|
3740
|
+
const result: number[][] = [];
|
|
3741
|
+
|
|
3742
|
+
const flatten = (arr: unknown): void => {
|
|
3743
|
+
if (!Array.isArray(arr)) return;
|
|
3744
|
+
// Check if this is a coordinate pair (array of 2-3 numbers)
|
|
3745
|
+
if (arr.length >= 2 && arr.length <= 3 && arr.every(n => typeof n === 'number')) {
|
|
3746
|
+
result.push(arr as number[]);
|
|
3747
|
+
} else {
|
|
3748
|
+
// Recurse into nested arrays
|
|
3749
|
+
for (const item of arr) {
|
|
3750
|
+
flatten(item);
|
|
3751
|
+
}
|
|
3752
|
+
}
|
|
3753
|
+
};
|
|
3754
|
+
|
|
3755
|
+
flatten(coords);
|
|
3756
|
+
return result;
|
|
3757
|
+
}
|
|
3758
|
+
|
|
3759
|
+
/**
|
|
3760
|
+
* Find which coordinates from flatCoords are at the given cursor/selection lines
|
|
3761
|
+
* Uses a simple heuristic based on line distribution
|
|
3762
|
+
*/
|
|
3763
|
+
private _findCoordinatesAtLines(
|
|
3764
|
+
blockStart: number,
|
|
3765
|
+
blockEnd: number,
|
|
3766
|
+
cursorStart: number,
|
|
3767
|
+
cursorEnd: number,
|
|
3768
|
+
flatCoords: number[][]
|
|
3769
|
+
): number[][] {
|
|
3770
|
+
if (flatCoords.length === 0) return [];
|
|
3771
|
+
|
|
3772
|
+
// Calculate total lines in the coordinates block (excluding the "coordinates": line itself)
|
|
3773
|
+
const totalLines = blockEnd - blockStart;
|
|
3774
|
+
if (totalLines <= 0) return flatCoords.length === 1 ? flatCoords : [];
|
|
3775
|
+
|
|
3776
|
+
// Estimate lines per coordinate (approximate)
|
|
3777
|
+
const linesPerCoord = totalLines / flatCoords.length;
|
|
3778
|
+
|
|
3779
|
+
// Find which coordinates the cursor/selection overlaps with
|
|
3780
|
+
const result: number[][] = [];
|
|
3781
|
+
const relativeStart = cursorStart - blockStart;
|
|
3782
|
+
const relativeEnd = cursorEnd - blockStart;
|
|
3783
|
+
|
|
3784
|
+
for (let i = 0; i < flatCoords.length; i++) {
|
|
3785
|
+
const coordLineStart = Math.floor(i * linesPerCoord);
|
|
3786
|
+
const coordLineEnd = Math.floor((i + 1) * linesPerCoord);
|
|
3787
|
+
|
|
3788
|
+
// Check if this coordinate's line range overlaps with cursor/selection
|
|
3789
|
+
if (coordLineStart <= relativeEnd && coordLineEnd >= relativeStart) {
|
|
3790
|
+
result.push(flatCoords[i]);
|
|
3791
|
+
}
|
|
3792
|
+
}
|
|
3793
|
+
|
|
3794
|
+
// If no match found but we're in the block, return the closest coordinate
|
|
3795
|
+
if (result.length === 0 && flatCoords.length > 0) {
|
|
3796
|
+
const relativePos = (cursorStart - blockStart) / totalLines;
|
|
3797
|
+
const coordIndex = Math.min(Math.floor(relativePos * flatCoords.length), flatCoords.length - 1);
|
|
3798
|
+
result.push(flatCoords[Math.max(0, coordIndex)]);
|
|
3799
|
+
}
|
|
3800
|
+
|
|
3801
|
+
return result;
|
|
3802
|
+
}
|
|
3803
|
+
|
|
3596
3804
|
/**
|
|
3597
3805
|
* Get all feature indices that overlap with the current cursor position or selection
|
|
3598
3806
|
* Returns sorted unique indices
|
package/src/internal-types.ts
CHANGED
|
@@ -79,6 +79,8 @@ export interface EditorSnapshot {
|
|
|
79
79
|
cursorLine: number;
|
|
80
80
|
cursorColumn: number;
|
|
81
81
|
timestamp: number;
|
|
82
|
+
/** Collapsed node unique keys (nodeKey:occurrence) for restoring collapsed state */
|
|
83
|
+
collapsedUniqueKeys?: string[];
|
|
82
84
|
}
|
|
83
85
|
|
|
84
86
|
/** Bracket count result */
|