@softwarity/geojson-editor 1.0.16 → 1.0.18

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.
@@ -1,497 +1,155 @@
1
1
  import type { Feature, FeatureCollection } from 'geojson';
2
- /** Geometry type names */
3
- export type GeometryType = 'Point' | 'MultiPoint' | 'LineString' | 'MultiLineString' | 'Polygon' | 'MultiPolygon';
4
- /** Position in the editor (line and column) */
5
- export interface CursorPosition {
6
- line: number;
7
- column: number;
8
- }
9
- /** Options for set/add/insertAt/open methods */
10
- export interface SetOptions {
11
- /**
12
- * Attributes to collapse after loading.
13
- * - string[]: List of attribute names (e.g., ['coordinates', 'geometry'])
14
- * - function: Dynamic function (feature, index) => string[]
15
- * - '$root': Special keyword to collapse entire features
16
- * - Empty array: No auto-collapse
17
- * @default ['coordinates']
18
- */
19
- collapsed?: string[] | ((feature: Feature, index: number) => string[]);
20
- }
21
- /** Theme configuration */
22
- export interface ThemeConfig {
23
- bgColor?: string;
24
- textColor?: string;
25
- caretColor?: string;
26
- gutterBg?: string;
27
- gutterBorder?: string;
28
- gutterText?: string;
29
- jsonKey?: string;
30
- jsonString?: string;
31
- jsonNumber?: string;
32
- jsonBoolean?: string;
33
- jsonNull?: string;
34
- jsonPunct?: string;
35
- jsonError?: string;
36
- controlColor?: string;
37
- controlBg?: string;
38
- controlBorder?: string;
39
- geojsonKey?: string;
40
- geojsonType?: string;
41
- geojsonTypeInvalid?: string;
42
- jsonKeyInvalid?: string;
43
- }
44
- /** Theme settings for dark and light modes */
45
- export interface ThemeSettings {
46
- dark?: ThemeConfig;
47
- light?: ThemeConfig;
48
- }
49
- /** Color metadata for a line */
50
- interface ColorMeta {
51
- attributeName: string;
52
- color: string;
53
- }
54
- /** Boolean metadata for a line */
55
- interface BooleanMeta {
56
- attributeName: string;
57
- value: boolean;
58
- }
59
- /** Collapse button metadata */
60
- interface CollapseButtonMeta {
61
- nodeKey: string;
62
- nodeId: string;
63
- isCollapsed: boolean;
64
- }
65
- /** Visibility button metadata */
66
- interface VisibilityButtonMeta {
67
- featureKey: string;
68
- isHidden: boolean;
69
- }
70
- /** Line metadata */
71
- interface LineMeta {
72
- colors: ColorMeta[];
73
- booleans: BooleanMeta[];
74
- collapseButton: CollapseButtonMeta | null;
75
- visibilityButton: VisibilityButtonMeta | null;
76
- isHidden: boolean;
77
- isCollapsed: boolean;
78
- featureKey: string | null;
79
- }
80
- /** Visible line data */
81
- interface VisibleLine {
82
- index: number;
83
- content: string;
84
- meta: LineMeta | undefined;
85
- }
86
- /** Feature range in the editor */
87
- interface FeatureRange {
88
- startLine: number;
89
- endLine: number;
90
- featureIndex: number;
91
- }
2
+ import type { SetOptions, ThemeSettings } from './types.js';
3
+
4
+ export type { SetOptions, ThemeConfig, ThemeSettings } from './types.js';
5
+
92
6
  /** Input types accepted by API methods */
93
7
  export type FeatureInput = Feature | Feature[] | FeatureCollection;
8
+
94
9
  /**
95
10
  * GeoJSON Editor Web Component
96
- * Monaco-like architecture with virtualized line rendering
11
+ * A feature-rich GeoJSON editor with syntax highlighting, collapsible nodes, and inline controls.
97
12
  */
98
13
  declare class GeoJsonEditor extends HTMLElement {
99
- lines: string[];
100
- collapsedNodes: Set<string>;
101
- hiddenFeatures: Set<string>;
102
- private _nodeIdCounter;
103
- private _lineToNodeId;
104
- private _nodeIdToLines;
105
- visibleLines: VisibleLine[];
106
- lineMetadata: Map<number, LineMeta>;
107
- featureRanges: Map<string, FeatureRange>;
108
- viewportHeight: number;
109
- lineHeight: number;
110
- bufferLines: number;
111
- private _lastStartIndex;
112
- private _lastEndIndex;
113
- private _lastTotalLines;
114
- private _scrollRaf;
115
- cursorLine: number;
116
- cursorColumn: number;
117
- selectionStart: CursorPosition | null;
118
- selectionEnd: CursorPosition | null;
119
- private renderTimer;
120
- private inputTimer;
121
- themes: ThemeSettings;
122
- private _undoStack;
123
- private _redoStack;
124
- private _maxHistorySize;
125
- private _lastActionTime;
126
- private _lastActionType;
127
- private _groupingDelay;
128
- private _isSelecting;
129
- private _isComposing;
130
- private _blockRender;
131
- private _charWidth;
132
- private _contextMapCache;
133
- private _contextMapLinesLength;
134
- private _contextMapFirstLine;
135
- private _contextMapLastLine;
136
- constructor();
137
- _invalidateRenderCache(): void;
138
- /**
139
- * Create a snapshot of current editor state
140
- * @returns {Object} State snapshot
141
- */
142
- _createSnapshot(): {
143
- lines: string[];
144
- cursorLine: number;
145
- cursorColumn: number;
146
- timestamp: number;
147
- };
148
- /**
149
- * Restore editor state from snapshot
150
- * @param {Object} snapshot - State to restore
151
- */
152
- _restoreSnapshot(snapshot: any): void;
153
- /**
154
- * Save current state to undo stack before making changes
155
- * @param {string} actionType - Type of action (insert, delete, paste, etc.)
156
- */
157
- _saveToHistory(actionType?: string): void;
158
- /**
159
- * Undo last action
160
- * @returns {boolean} True if undo was performed
161
- */
162
- undo(): boolean;
163
- /**
164
- * Redo previously undone action
165
- * @returns {boolean} True if redo was performed
166
- */
167
- redo(): boolean;
168
- /**
169
- * Clear undo/redo history
170
- */
171
- clearHistory(): void;
172
- /**
173
- * Check if undo is available
174
- * @returns {boolean}
175
- */
176
- canUndo(): boolean;
177
- /**
178
- * Check if redo is available
179
- * @returns {boolean}
180
- */
181
- canRedo(): boolean;
182
- _generateNodeId(): string;
183
- /**
184
- * Check if a line is inside a collapsed node (hidden lines between opening and closing)
185
- * @param {number} lineIndex - The line index to check
186
- * @returns {Object|null} - The collapsed range info or null
187
- */
188
- _getCollapsedRangeForLine(lineIndex: any): {
189
- startLine: number;
190
- endLine: number;
191
- nodeKey?: string;
192
- isRootFeature?: boolean;
193
- nodeId: string;
194
- };
195
- /**
196
- * Check if cursor is on the closing line of a collapsed node
197
- * @param {number} lineIndex - The line index to check
198
- * @returns {Object|null} - The collapsed range info or null
199
- */
200
- _getCollapsedClosingLine(lineIndex: any): {
201
- startLine: number;
202
- endLine: number;
203
- nodeKey?: string;
204
- isRootFeature?: boolean;
205
- nodeId: string;
206
- };
207
- /**
208
- * Get the position of the closing bracket on a line
209
- * @param {string} line - The line content
210
- * @returns {number} - Position of bracket or -1
211
- */
212
- _getClosingBracketPos(line: any): number;
213
- /**
214
- * Check if cursor is on the opening line of a collapsed node
215
- * @param {number} lineIndex - The line index to check
216
- * @returns {Object|null} - The collapsed range info or null
217
- */
218
- _getCollapsedNodeAtLine(lineIndex: any): {
219
- startLine: number;
220
- endLine: number;
221
- nodeKey?: string;
222
- isRootFeature?: boolean;
223
- nodeId: string;
224
- };
225
- /**
226
- * Check if cursor is on a line that has a collapsible node (expanded or collapsed)
227
- * @param {number} lineIndex - The line index to check
228
- * @returns {Object|null} - The node info with isCollapsed flag or null
229
- */
230
- _getCollapsibleNodeAtLine(lineIndex: any): {
231
- startLine: number;
232
- endLine: number;
233
- nodeKey?: string;
234
- isRootFeature?: boolean;
235
- nodeId: string;
236
- isCollapsed: boolean;
237
- };
238
- /**
239
- * Find the innermost expanded node that contains the given line
240
- * Used for Shift+Tab to collapse the parent node from anywhere inside it
241
- * @param {number} lineIndex - The line index to check
242
- * @returns {Object|null} - The containing node info or null
243
- */
244
- _getContainingExpandedNode(lineIndex: any): any;
245
- /**
246
- * Delete an entire collapsed node (opening line to closing line)
247
- * @param {Object} range - The range info {startLine, endLine}
248
- */
249
- _deleteCollapsedNode(range: any): void;
250
- /**
251
- * Rebuild nodeId mappings after content changes
252
- * Preserves collapsed state by matching nodeKey + sequential occurrence
253
- */
254
- _rebuildNodeIdMappings(): void;
255
- static get observedAttributes(): string[];
256
- connectedCallback(): void;
257
- disconnectedCallback(): void;
258
- attributeChangedCallback(name: any, oldValue: any, newValue: any): void;
259
- get readonly(): boolean;
260
- get value(): string;
261
- get placeholder(): string;
262
- get prefix(): string;
263
- get suffix(): string;
264
- render(): void;
265
- setupEventListeners(): void;
266
- /**
267
- * Set the editor content from a string value
268
- */
269
- setValue(value: any, autoCollapse?: boolean): void;
270
- /**
271
- * Get full content as string (expanded, no hidden markers)
272
- */
273
- getContent(): string;
274
- /**
275
- * Update derived state from model
276
- * Rebuilds line-to-nodeId mapping while preserving collapsed state
277
- */
278
- updateModel(): void;
279
- /**
280
- * Update view state without rebuilding nodeId mappings
281
- * Used for collapse/expand operations where content doesn't change
282
- */
283
- updateView(): void;
284
- /**
285
- * Compute feature ranges (which lines belong to which feature)
286
- */
287
- computeFeatureRanges(): void;
288
- /**
289
- * Compute metadata for each line (colors, booleans, collapse buttons, etc.)
290
- */
291
- computeLineMetadata(): void;
292
- /**
293
- * Compute which lines are visible (not inside collapsed nodes)
294
- */
295
- computeVisibleLines(): void;
296
- scheduleRender(): void;
297
- renderViewport(): void;
298
- /**
299
- * Insert cursor element at the specified column position
300
- * Uses absolute positioning to avoid affecting text layout
301
- */
302
- _insertCursor(column: any): string;
303
- /**
304
- * Add selection highlight to a line
305
- */
306
- _addSelectionHighlight(html: any, lineIndex: any, content: any): any;
307
- /**
308
- * Get character width for monospace font
309
- */
310
- _getCharWidth(): number;
311
- renderGutter(startIndex: any, endIndex: any): void;
312
- syncGutterScroll(): void;
313
- handleInput(): void;
314
- handleKeydown(e: any): void;
315
- _handleEnter(ctx: any): void;
316
- _handleBackspace(ctx: any): void;
317
- _handleDelete(ctx: any): void;
318
- _handleTab(isShiftKey: any, ctx: any): void;
319
- insertNewline(): void;
320
- deleteBackward(): void;
321
- deleteForward(): void;
322
- /**
323
- * Move cursor vertically, skipping hidden collapsed lines only
324
- */
325
- moveCursorSkipCollapsed(deltaLine: any): void;
326
- /**
327
- * Move cursor horizontally with smart navigation around collapsed nodes
328
- */
329
- moveCursorHorizontal(delta: any): void;
330
- _moveCursorRight(): void;
331
- _moveCursorLeft(): void;
332
- /**
333
- * Scroll viewport to ensure cursor is visible
334
- */
335
- _scrollToCursor(): void;
336
- /**
337
- * Handle arrow key with optional selection and word jump
338
- */
339
- _handleArrowKey(deltaLine: any, deltaCol: any, isShift: any, isCtrl?: boolean): void;
340
- /**
341
- * Move cursor by word (Ctrl+Arrow)
342
- * Behavior matches VSCode/Monaco:
343
- * - Ctrl+Right: move to end of current word, or start of next word
344
- * - Ctrl+Left: move to start of current word, or start of previous word
345
- */
346
- _moveCursorByWord(direction: any): void;
347
- /**
348
- * Handle Home/End with optional selection
349
- */
350
- _handleHomeEnd(key: any, isShift: any, onClosingLine: any): void;
351
- /**
352
- * Select all content
353
- */
354
- _selectAll(): void;
355
- /**
356
- * Get selected text
357
- */
358
- _getSelectedText(): string;
359
- /**
360
- * Normalize selection so start is before end
361
- */
362
- _normalizeSelection(): {
363
- start: CursorPosition;
364
- end: CursorPosition;
365
- };
366
- /**
367
- * Check if there is an active selection
368
- */
369
- _hasSelection(): boolean;
370
- /**
371
- * Clear the current selection
372
- */
373
- _clearSelection(): void;
374
- /**
375
- * Delete selected text
376
- */
377
- _deleteSelection(): boolean;
378
- insertText(text: any): void;
379
- handlePaste(e: any): void;
380
- handleCopy(e: any): void;
381
- handleCut(e: any): void;
382
- /**
383
- * Get line/column position from mouse event
384
- */
385
- _getPositionFromClick(e: any): {
386
- line: number;
387
- column: number;
388
- };
389
- handleGutterClick(e: any): void;
390
- handleEditorClick(e: any): void;
391
- toggleCollapse(nodeId: any): void;
392
- autoCollapseCoordinates(): void;
393
- /**
394
- * Helper to apply collapsed option from API methods
395
- * @param {object} options - Options object with optional collapsed property
396
- * @param {array} features - Features array for function mode
397
- */
398
- _applyCollapsedFromOptions(options: any, features: any): void;
399
- /**
400
- * Apply collapsed option to nodes
401
- * @param {string[]|function} collapsed - Attributes to collapse or function returning them
402
- * @param {array} features - Features array for function mode (optional)
403
- */
404
- _applyCollapsedOption(collapsed: any, features?: any): void;
405
- toggleFeatureVisibility(featureKey: any): void;
406
- showColorPicker(indicator: any, line: any, currentColor: any, attributeName: any): void;
407
- updateColorValue(line: any, newColor: any, attributeName: any): void;
408
- updateBooleanValue(line: any, newValue: any, attributeName: any): void;
409
- formatAndUpdate(): void;
410
- emitChange(): void;
411
- updateReadonly(): void;
412
- updatePlaceholderVisibility(): void;
413
- updatePlaceholderContent(): void;
414
- updatePrefixSuffix(): void;
415
- updateThemeCSS(): void;
416
- _parseSelectorToHostRule(selector: any): string;
417
- setTheme(theme: ThemeSettings): void;
418
- resetTheme(): void;
419
- _getFeatureKey(feature: any): string;
420
- _countBrackets(line: any, openBracket: any): {
421
- open: number;
422
- close: number;
423
- };
424
- /**
425
- * Find all collapsible ranges using the mappings built by _rebuildNodeIdMappings
426
- * This method only READS the existing mappings, it doesn't create new IDs
427
- */
428
- _findCollapsibleRanges(): any[];
429
- _findClosingLine(startLine: any, openBracket: any): any;
430
- _buildContextMap(): Map<any, any>;
431
- _highlightSyntax(text: any, context: any, meta: any): any;
432
- _validateGeoJSON(parsed: any): any[];
433
- /**
434
- * Validate a single feature object
435
- * @param {object} feature - The feature to validate
436
- * @throws {Error} If the feature is invalid
437
- */
438
- _validateFeature(feature: any): void;
439
- /**
440
- * Normalize input to an array of features
441
- * Accepts: FeatureCollection, Feature[], or single Feature
442
- * @param {object|array} input - Input to normalize
443
- * @returns {array} Array of features
444
- * @throws {Error} If input is invalid
445
- */
446
- _normalizeToFeatures(input: any): any[];
447
- /**
448
- * Replace all features in the editor
449
- * Accepts: FeatureCollection, Feature[], or single Feature
450
- * @param {object|array} input - Features to set
451
- * @param {object} options - Optional settings
452
- * @param {string[]|function} options.collapsed - Attributes to collapse (default: ['coordinates'])
453
- * - string[]: List of attributes to collapse (e.g., ['coordinates', 'geometry'])
454
- * - function(feature, index): Returns string[] of attributes to collapse per feature
455
- * - Use '$root' to collapse the entire feature
456
- * @throws {Error} If input is invalid
457
- */
458
- set(input: FeatureInput, options?: SetOptions): void;
459
- /**
460
- * Add features to the end of the editor
461
- * Accepts: FeatureCollection, Feature[], or single Feature
462
- * @param {object|array} input - Features to add
463
- * @param {object} options - Optional settings
464
- * @param {string[]|function} options.collapsed - Attributes to collapse (default: ['coordinates'])
465
- * @throws {Error} If input is invalid
466
- */
467
- add(input: FeatureInput, options?: SetOptions): void;
468
- /**
469
- * Insert features at a specific index
470
- * Accepts: FeatureCollection, Feature[], or single Feature
471
- * @param {object|array} input - Features to insert
472
- * @param {number} index - Index to insert at (negative = from end)
473
- * @param {object} options - Optional settings
474
- * @param {string[]|function} options.collapsed - Attributes to collapse (default: ['coordinates'])
475
- * @throws {Error} If input is invalid
476
- */
477
- insertAt(input: FeatureInput, index: number, options?: SetOptions): void;
478
- removeAt(index: number): Feature | undefined;
479
- removeAll(): Feature[];
480
- get(index: number): Feature | undefined;
481
- getAll(): Feature[];
482
- emit(): void;
483
- /**
484
- * Save GeoJSON to a file (triggers download)
485
- */
486
- save(filename?: string): boolean;
487
- /**
488
- * Open a GeoJSON file from the client filesystem
489
- * Note: Available even in readonly mode via API (only Ctrl+O shortcut is blocked)
490
- * @param {object} options - Optional settings
491
- * @param {string[]|function} options.collapsed - Attributes to collapse (default: ['coordinates'])
492
- * @returns {Promise<boolean>} Promise that resolves to true if file was loaded successfully
493
- */
494
- open(options?: SetOptions): Promise<boolean>;
495
- _parseFeatures(): any;
14
+ /** Current editor content as string */
15
+ get value(): string;
16
+
17
+ /** Placeholder text when editor is empty */
18
+ get placeholder(): string;
19
+
20
+ /** Prefix text displayed before editor content */
21
+ get prefix(): string;
22
+
23
+ /** Suffix text displayed after editor content */
24
+ get suffix(): string;
25
+
26
+ /** Whether the editor is in readonly mode */
27
+ get readonly(): boolean;
28
+
29
+ /**
30
+ * Set the editor content from a string value
31
+ * @param value - JSON string content
32
+ * @param autoCollapse - Whether to auto-collapse coordinates (default: true)
33
+ */
34
+ setValue(value: string | null, autoCollapse?: boolean): void;
35
+
36
+ /**
37
+ * Get full content as string (expanded, no hidden markers)
38
+ */
39
+ getContent(): string;
40
+
41
+ /**
42
+ * Replace all features in the editor
43
+ * @param input - FeatureCollection, Feature[], or single Feature
44
+ * @param options - Optional settings (collapsed attributes)
45
+ * @throws Error if input is invalid
46
+ */
47
+ set(input: FeatureInput, options?: SetOptions): void;
48
+
49
+ /**
50
+ * Add features to the end of the editor
51
+ * @param input - FeatureCollection, Feature[], or single Feature
52
+ * @param options - Optional settings (collapsed attributes)
53
+ * @throws Error if input is invalid
54
+ */
55
+ add(input: FeatureInput, options?: SetOptions): void;
56
+
57
+ /**
58
+ * Insert features at a specific index
59
+ * @param input - FeatureCollection, Feature[], or single Feature
60
+ * @param index - Index to insert at (negative = from end)
61
+ * @param options - Optional settings (collapsed attributes)
62
+ * @throws Error if input is invalid
63
+ */
64
+ insertAt(input: FeatureInput, index: number, options?: SetOptions): void;
65
+
66
+ /**
67
+ * Remove feature at index
68
+ * @param index - Index to remove (negative = from end)
69
+ * @returns The removed feature, or undefined if index is out of bounds
70
+ */
71
+ removeAt(index: number): Feature | undefined;
72
+
73
+ /**
74
+ * Remove all features
75
+ * @returns Array of all removed features
76
+ */
77
+ removeAll(): Feature[];
78
+
79
+ /**
80
+ * Get feature at index
81
+ * @param index - Index to get (negative = from end)
82
+ * @returns The feature, or undefined if index is out of bounds
83
+ */
84
+ get(index: number): Feature | undefined;
85
+
86
+ /**
87
+ * Get all features as an array
88
+ */
89
+ getAll(): Feature[];
90
+
91
+ /**
92
+ * Emit the current document on the change event
93
+ */
94
+ emit(): void;
95
+
96
+ /**
97
+ * Save GeoJSON to a file (triggers download)
98
+ * @param filename - Filename for download (default: 'features.geojson')
99
+ * @returns true if save was successful
100
+ */
101
+ save(filename?: string): boolean;
102
+
103
+ /**
104
+ * Open a GeoJSON file from the client filesystem
105
+ * @param options - Optional settings (collapsed attributes)
106
+ * @returns Promise that resolves to true if file was loaded successfully
107
+ */
108
+ open(options?: SetOptions): Promise<boolean>;
109
+
110
+ /**
111
+ * Undo last action
112
+ * @returns true if undo was performed
113
+ */
114
+ undo(): boolean;
115
+
116
+ /**
117
+ * Redo previously undone action
118
+ * @returns true if redo was performed
119
+ */
120
+ redo(): boolean;
121
+
122
+ /**
123
+ * Check if undo is available
124
+ */
125
+ canUndo(): boolean;
126
+
127
+ /**
128
+ * Check if redo is available
129
+ */
130
+ canRedo(): boolean;
131
+
132
+ /**
133
+ * Clear undo/redo history
134
+ */
135
+ clearHistory(): void;
136
+
137
+ /**
138
+ * Set custom theme colors
139
+ * @param theme - Theme settings for dark and light modes
140
+ */
141
+ setTheme(theme: ThemeSettings): void;
142
+
143
+ /**
144
+ * Reset theme to defaults
145
+ */
146
+ resetTheme(): void;
147
+
148
+ /**
149
+ * Get current theme settings
150
+ * @returns Copy of current theme settings
151
+ */
152
+ getTheme(): ThemeSettings;
496
153
  }
154
+
497
155
  export default GeoJsonEditor;
@@ -0,0 +1,44 @@
1
+ import type { Feature } from 'geojson';
2
+ /**
3
+ * Public types - exported from the package
4
+ */
5
+ /** Options for set/add/insertAt/open methods */
6
+ export interface SetOptions {
7
+ /**
8
+ * Attributes to collapse after loading.
9
+ * - string[]: List of attribute names (e.g., ['coordinates', 'geometry'])
10
+ * - function: Dynamic function (feature, index) => string[]
11
+ * - '$root': Special keyword to collapse entire features
12
+ * - Empty array: No auto-collapse
13
+ * @default ['coordinates']
14
+ */
15
+ collapsed?: string[] | ((feature: Feature | null, index: number) => string[]);
16
+ }
17
+ /** Theme configuration */
18
+ export interface ThemeConfig {
19
+ bgColor?: string;
20
+ textColor?: string;
21
+ caretColor?: string;
22
+ gutterBg?: string;
23
+ gutterBorder?: string;
24
+ gutterText?: string;
25
+ jsonKey?: string;
26
+ jsonString?: string;
27
+ jsonNumber?: string;
28
+ jsonBoolean?: string;
29
+ jsonNull?: string;
30
+ jsonPunct?: string;
31
+ jsonError?: string;
32
+ controlColor?: string;
33
+ controlBg?: string;
34
+ controlBorder?: string;
35
+ geojsonKey?: string;
36
+ geojsonType?: string;
37
+ geojsonTypeInvalid?: string;
38
+ jsonKeyInvalid?: string;
39
+ }
40
+ /** Theme settings for dark and light modes */
41
+ export interface ThemeSettings {
42
+ dark?: ThemeConfig;
43
+ light?: ThemeConfig;
44
+ }