Skip to content

Commit 6021535

Browse files
matthttamclaude
andauthored
fix: address Obsidian community plugin review warnings (#4)
* chore: bump minAppVersion and replace flagged dependencies - Bump manifest minAppVersion to 1.6.6 so Vault.getAllFolders / Vault.getFileByPath are considered available. - Replace builtin-modules with node:module's builtinModules in the esbuild config. - Drop lint-staged in favour of running npm run lint from the husky pre-commit hook. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix: use activeWindow timer APIs for popout compatibility Replace setTimeout / clearTimeout calls in DataManager and MapRenderer with activeWindow.setTimeout / activeWindow.clearTimeout so debounced saves, hover previews, and resize/zoom handlers continue to work when the map renders inside a popout window. Store handle types as number to match the activeWindow return type. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix: use Obsidian DOM helpers for SVG and fragment creation Swap document.createElementNS('http://www.w3.org/2000/svg', ...), document.createDocumentFragment(), and document.createElement('div') calls in MapRenderer and MeasurementController for the Obsidian createSvg / createFragment / createDiv helpers. Also use createSpan for the layer range badge and register the Obsidian globals in the eslint config so no-undef does not flag them. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix: prefer Obsidian DOM helpers and tighten generated-icon types - Use createEl / createSvg / activeDocument across the remaining document.createElement* and document.fonts call sites (mapExport, mapImport, markerPin, mapIcon, renderTemplateManager, font availability check in types.ts). - Re-type imports from the gitignored src/generated/ icon modules so the community-plugin review bot, which sees those imports as any, no longer flags downstream member access as unsafe. Also type the dynamic gi-icons-embedded import and its DecompressionStream reader. - Underscore the unused previewContainer param in MarkerEditModal.buildSizeOverrides. - Polyfill createDiv / createEl / createSpan / createSvg / createFragment / activeWindow / activeDocument globals in the jsdom test setup so MapRenderer and related tests keep passing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix: bump version to 1.4.1 and use detached host in dom mocks - Pre-bump manifest.json + package.json + versions.json from 1.4.0 to 1.4.1 so the manifest's minAppVersion=1.6.6 matches a published-version mapping in versions.json. semantic-release will still treat this as the patch bump it computes from the fix: commits on this branch. - Rework the global createDiv / createEl / createSpan jsdom mocks to build a detached element instead of appending to document.body, matching Obsidian's actual global helpers and keeping test DOM isolated between cases. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 15c1338 commit 6021535

18 files changed

Lines changed: 185 additions & 118 deletions

.husky/pre-commit

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
npx lint-staged
1+
npm run lint

.lintstagedrc.json

Lines changed: 0 additions & 4 deletions
This file was deleted.

esbuild.config.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import esbuild from 'esbuild';
22
import process from 'process';
3-
import builtins from 'builtin-modules';
3+
import { builtinModules as builtins } from 'node:module';
44

55
const banner = `/*
66
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD

eslint.config.mjs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ export default tseslint.config(
1414
globals: {
1515
...globals.browser,
1616
activeWindow: 'readonly',
17+
activeDocument: 'readonly',
18+
createDiv: 'readonly',
19+
createEl: 'readonly',
20+
createSpan: 'readonly',
21+
createSvg: 'readonly',
22+
createFragment: 'readonly',
1723
},
1824
parserOptions: {
1925
projectService: true,

manifest.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"id": "ttrpg-maps",
33
"name": "TTRPG Maps",
4-
"version": "1.4.0",
5-
"minAppVersion": "1.5.0",
4+
"version": "1.4.1",
5+
"minAppVersion": "1.6.6",
66
"description": "Render interactive TTRPG maps from code blocks with markers, templates, and distance measurement tools.",
77
"author": "matthttam",
88
"authorUrl": "https://github.com/matthttam",

package.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "obsidian-ttrpg-maps",
3-
"version": "1.4.0",
3+
"version": "1.4.1",
44
"description": "Render interactive TTRPG maps from code blocks with markers, templates, and distance measurement tools.",
55
"main": "main.js",
66
"repository": {
@@ -40,14 +40,12 @@
4040
"@typescript-eslint/eslint-plugin": "^8.58.0",
4141
"@typescript-eslint/parser": "^8.58.0",
4242
"@vitest/coverage-v8": "^4.1.4",
43-
"builtin-modules": "^3.3.0",
4443
"esbuild": "^0.20.0",
4544
"eslint": "^9.39.4",
4645
"eslint-config-prettier": "^10.1.8",
4746
"eslint-plugin-obsidianmd": "^0.1.9",
4847
"husky": "^9.1.7",
4948
"jsdom": "^29.0.2",
50-
"lint-staged": "^16.4.0",
5149
"obsidian": "latest",
5250
"prettier": "^3.8.1",
5351
"semantic-release": "^25.0.3",

src/DataManager.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const TTRPGMAP_DIR = '.ttrpgmap';
88
export class DataManager {
99
private app: App;
1010
private plugin: TTRPGMapsPlugin;
11-
private saveTimeouts: Map<string, ReturnType<typeof setTimeout>> = new Map();
11+
private saveTimeouts: Map<string, number> = new Map();
1212
private pendingStates: Map<string, MapState> = new Map();
1313

1414
constructor(app: App, plugin: TTRPGMapsPlugin) {
@@ -141,11 +141,11 @@ export class DataManager {
141141
/** Save per-map state to sidecar file (debounced 300ms) */
142142
saveMapState(mapId: string, state: MapState): void {
143143
const existing = this.saveTimeouts.get(mapId);
144-
if (existing) clearTimeout(existing);
144+
if (existing) activeWindow.clearTimeout(existing);
145145

146146
this.pendingStates.set(mapId, state);
147147

148-
const timeout = setTimeout(() => {
148+
const timeout = activeWindow.setTimeout(() => {
149149
void (async () => {
150150
this.saveTimeouts.delete(mapId);
151151
this.pendingStates.delete(mapId);
@@ -161,7 +161,7 @@ export class DataManager {
161161
/** Flush any pending debounced saves immediately */
162162
async flushSaves(): Promise<void> {
163163
for (const [mapId, timeout] of this.saveTimeouts) {
164-
clearTimeout(timeout);
164+
activeWindow.clearTimeout(timeout);
165165
const state = this.pendingStates.get(mapId);
166166
if (state) {
167167
await this.ensureDir();
@@ -182,7 +182,7 @@ export class DataManager {
182182
const writes: Array<{ path: string; data: string }> = [];
183183
const flushedMapIds: string[] = [];
184184
for (const [mapId, timeout] of this.saveTimeouts) {
185-
clearTimeout(timeout);
185+
activeWindow.clearTimeout(timeout);
186186
const state = this.pendingStates.get(mapId);
187187
if (state) {
188188
flushedMapIds.push(mapId);

src/map/MapRenderer.ts

Lines changed: 27 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -92,15 +92,15 @@ export class MapRenderer extends MarkdownRenderChild {
9292
private resizeStartScale = 1;
9393
private resizeTarget: 'marker' | 'text' = 'marker';
9494
private resizeHandleSide: 'left' | 'right' = 'right';
95-
private _resizeSaveTimeout: ReturnType<typeof setTimeout> | null = null;
95+
private _resizeSaveTimeout: number | null = null;
9696

9797
// Copy-marker state
9898
private pendingCopy: MapMarker | null = null;
9999
private _cancelCopy: (() => void) | null = null;
100100

101101
// Container resize handling
102102
private resizeObserver: ResizeObserver | null = null;
103-
private _resizeDebounce: ReturnType<typeof setTimeout> | null = null;
103+
private _resizeDebounce: number | null = null;
104104

105105
// Layer panel state (non-persisted, session only)
106106
private layerVisibilityOverrides: Map<string, 'show' | 'hide' | 'always'> = new Map();
@@ -186,7 +186,7 @@ export class MapRenderer extends MarkdownRenderChild {
186186
this.resizeObserver = null;
187187
}
188188
if (this._resizeDebounce) {
189-
clearTimeout(this._resizeDebounce);
189+
activeWindow.clearTimeout(this._resizeDebounce);
190190
this._resizeDebounce = null;
191191
}
192192
}
@@ -207,8 +207,7 @@ export class MapRenderer extends MarkdownRenderChild {
207207
this.imageEl = this.mapContainer.createEl('img', { cls: 'ttrpgmap-image' });
208208
this.loadImage();
209209

210-
this.svgOverlay = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
211-
this.svgOverlay.addClass('ttrpgmap-svg-overlay');
210+
this.svgOverlay = createSvg('svg', { cls: 'ttrpgmap-svg-overlay' });
212211
this.mapContainer.appendChild(this.svgOverlay);
213212

214213
// Marker overlay sits outside the scaled container for crisp rendering
@@ -245,9 +244,9 @@ export class MapRenderer extends MarkdownRenderChild {
245244
this.svgOverlay.addClass('ttrpgmap-hidden');
246245
this.imageEl.addClass('ttrpgmap-pixelated');
247246
} else {
248-
clearTimeout(this._resizeDebounce);
247+
activeWindow.clearTimeout(this._resizeDebounce);
249248
}
250-
this._resizeDebounce = setTimeout(() => {
249+
this._resizeDebounce = activeWindow.setTimeout(() => {
251250
this._resizeDebounce = null;
252251
this.imageEl.removeClass('ttrpgmap-pixelated');
253252
this.svgOverlay.removeClass('ttrpgmap-hidden');
@@ -398,14 +397,14 @@ export class MapRenderer extends MarkdownRenderChild {
398397
}
399398

400399
// Auto-dismiss after 2s, but pause while hovering
401-
let timer = setTimeout(() => warning.remove(), 2000);
400+
let timer = activeWindow.setTimeout(() => warning.remove(), 2000);
402401
warning.addEventListener('mouseenter', () => {
403-
clearTimeout(timer);
402+
activeWindow.clearTimeout(timer);
404403
warning.addClass('ttrpgmap-lock-warning-paused');
405404
});
406405
warning.addEventListener('mouseleave', () => {
407406
warning.removeClass('ttrpgmap-lock-warning-paused');
408-
timer = setTimeout(() => warning.remove(), 1000);
407+
timer = activeWindow.setTimeout(() => warning.remove(), 1000);
409408
});
410409
}
411410

@@ -550,7 +549,7 @@ export class MapRenderer extends MarkdownRenderChild {
550549
const nameEl = row.createDiv({ cls: 'ttrpgmap-marker-list-name' });
551550
nameEl.setText(layer.name);
552551
const rangeText = this.formatZoomRangeShort(layer);
553-
if (rangeText) nameEl.createEl('span', { cls: 'ttrpgmap-layer-range-badge', text: ` ${rangeText}` });
552+
if (rangeText) nameEl.createSpan({ cls: 'ttrpgmap-layer-range-badge', text: ` ${rangeText}` });
554553

555554
// Actions
556555
const actionGroup = row.createDiv({ cls: 'ttrpgmap-layer-action-group' });
@@ -938,7 +937,7 @@ export class MapRenderer extends MarkdownRenderChild {
938937

939938
let prevWidth = rect.width;
940939
let prevHeight = rect.height;
941-
let resizeSyncTimeout: ReturnType<typeof setTimeout> | null = null;
940+
let resizeSyncTimeout: number | null = null;
942941
const onMove = (ev: MouseEvent) => {
943942
const delta = axis === 'width' ? ev.clientX - this.edgeResizeStartPos : ev.clientY - this.edgeResizeStartPos;
944943
const newSize = Math.max(50, Math.round(this.edgeResizeStartSize + delta));
@@ -963,7 +962,7 @@ export class MapRenderer extends MarkdownRenderChild {
963962

964963
// Throttled marker sync during drag (every 100ms)
965964
if (!resizeSyncTimeout) {
966-
resizeSyncTimeout = setTimeout(() => {
965+
resizeSyncTimeout = activeWindow.setTimeout(() => {
967966
resizeSyncTimeout = null;
968967
this.updateImageScaleCache();
969968
this.syncViewportMarkers(true);
@@ -975,7 +974,7 @@ export class MapRenderer extends MarkdownRenderChild {
975974
activeWindow.removeEventListener('mousemove', onMove);
976975
activeWindow.removeEventListener('mouseup', onUp);
977976
if (resizeSyncTimeout) {
978-
clearTimeout(resizeSyncTimeout);
977+
activeWindow.clearTimeout(resizeSyncTimeout);
979978
resizeSyncTimeout = null;
980979
}
981980
const finalRect = this.wrapper.getBoundingClientRect();
@@ -1095,8 +1094,8 @@ export class MapRenderer extends MarkdownRenderChild {
10951094

10961095
// ──────────────────── Pan / Zoom ────────────────────
10971096

1098-
private _zoomSettleTimeout: ReturnType<typeof setTimeout> | null = null;
1099-
private _cullTimeout: ReturnType<typeof setTimeout> | null = null;
1097+
private _zoomSettleTimeout: number | null = null;
1098+
private _cullTimeout: number | null = null;
11001099
private _lastSettledZoom = 100;
11011100

11021101
private applyTransform(): void {
@@ -1110,8 +1109,8 @@ export class MapRenderer extends MarkdownRenderChild {
11101109
this.markerOverlay.addClass('ttrpgmap-visibility-hidden');
11111110
}
11121111
if (isPanning) {
1113-
if (this._cullTimeout) clearTimeout(this._cullTimeout);
1114-
this._cullTimeout = setTimeout(() => {
1112+
if (this._cullTimeout) activeWindow.clearTimeout(this._cullTimeout);
1113+
this._cullTimeout = activeWindow.setTimeout(() => {
11151114
this._cullTimeout = null;
11161115
this.syncViewportMarkers(true);
11171116
this.markerOverlay.style.transform = `translate(${this.panX}px, ${this.panY}px)`;
@@ -1126,8 +1125,8 @@ export class MapRenderer extends MarkdownRenderChild {
11261125
// Zoom changed: hide markers during interactive zoom, rebuild when settled
11271126
this.markerOverlay.addClass('ttrpgmap-visibility-hidden');
11281127

1129-
if (this._zoomSettleTimeout) clearTimeout(this._zoomSettleTimeout);
1130-
this._zoomSettleTimeout = setTimeout(() => {
1128+
if (this._zoomSettleTimeout) activeWindow.clearTimeout(this._zoomSettleTimeout);
1129+
this._zoomSettleTimeout = activeWindow.setTimeout(() => {
11311130
this._zoomSettleTimeout = null;
11321131
this._lastSettledZoom = this.zoom;
11331132
this.markerOverlay.style.transform = `translate(${this.panX}px, ${this.panY}px)`;
@@ -1444,8 +1443,8 @@ export class MapRenderer extends MarkdownRenderChild {
14441443
}
14451444

14461445
markerEl.addClass('ttrpgmap-marker-resizing');
1447-
if (this._resizeSaveTimeout) clearTimeout(this._resizeSaveTimeout);
1448-
this._resizeSaveTimeout = setTimeout(() => {
1446+
if (this._resizeSaveTimeout) activeWindow.clearTimeout(this._resizeSaveTimeout);
1447+
this._resizeSaveTimeout = activeWindow.setTimeout(() => {
14491448
markerEl.removeClass('ttrpgmap-marker-resizing');
14501449
if (this.state) this.plugin.dataManager.saveMapState(this.config.id, this.state);
14511450
}, RESIZE_SAVE_DEBOUNCE_MS);
@@ -1765,7 +1764,7 @@ export class MapRenderer extends MarkdownRenderChild {
17651764

17661765
// Create markers newly entering visibility
17671766
if (visibleIds.size > 0) {
1768-
const fragment = document.createDocumentFragment();
1767+
const fragment = createFragment();
17691768
for (const marker of this.state.markers) {
17701769
if (!visibleIds.has(marker.id)) continue;
17711770
const markerEl = this.createMarkerElement(marker, mapScaleToZoom, mapTextScaleToZoom, isMeasuring, fragment);
@@ -1811,7 +1810,7 @@ export class MapRenderer extends MarkdownRenderChild {
18111810
visibleMarkers.length = maxMarkers;
18121811
}
18131812

1814-
const fragment = document.createDocumentFragment();
1813+
const fragment = createFragment();
18151814
for (const marker of visibleMarkers) {
18161815
const markerEl = this.createMarkerElement(marker, mapScaleToZoom, mapTextScaleToZoom, isMeasuring, fragment);
18171816
if (!isMeasuring) this.attachMarkerEvents(marker, markerEl);
@@ -1845,8 +1844,7 @@ export class MapRenderer extends MarkdownRenderChild {
18451844

18461845
const { sx, sy } = this.getImageScale();
18471846
const scale = this.zoom / 100;
1848-
const markerEl = document.createElement('div');
1849-
markerEl.addClass('ttrpgmap-marker');
1847+
const markerEl = createDiv({ cls: 'ttrpgmap-marker' });
18501848
(parent ?? this.markerOverlay).appendChild(markerEl);
18511849

18521850
markerEl.style.left = `${marker.x * sx * scale}px`;
@@ -1930,7 +1928,7 @@ export class MapRenderer extends MarkdownRenderChild {
19301928
}
19311929

19321930
private attachMarkerHoverPreview(marker: MapMarker, markerEl: HTMLElement): void {
1933-
let hoverTimeout: ReturnType<typeof setTimeout> | null = null;
1931+
let hoverTimeout: number | null = null;
19341932
let hoverSuppressed = false;
19351933
// Hover parent with intercepted setter: auto-hides popover if suppressed
19361934
let _popover: { hide: () => void } | null = null;
@@ -1950,7 +1948,7 @@ export class MapRenderer extends MarkdownRenderChild {
19501948

19511949
const clearHoverTimeout = () => {
19521950
if (hoverTimeout) {
1953-
clearTimeout(hoverTimeout);
1951+
activeWindow.clearTimeout(hoverTimeout);
19541952
hoverTimeout = null;
19551953
}
19561954
};
@@ -1988,7 +1986,7 @@ export class MapRenderer extends MarkdownRenderChild {
19881986
if (!previewPath && marker.note) previewPath = linkPath(marker.note);
19891987
if (!previewPath) return;
19901988

1991-
hoverTimeout = setTimeout(() => {
1989+
hoverTimeout = activeWindow.setTimeout(() => {
19921990
hoverTimeout = null;
19931991
if (this.draggingMarker || this.interaction.current === 'panning' || hoverSuppressed) return;
19941992
hoverParent.hoverPopover = null;

src/map/MeasurementController.ts

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -213,11 +213,9 @@ export class MeasurementController {
213213
const cursor: MapPoint = { x: (e.clientX - rect.left) / scale, y: (e.clientY - rect.top) / scale };
214214

215215
if (!this.measurePreviewLine) {
216-
this.measurePreviewLine = document.createElementNS('http://www.w3.org/2000/svg', 'line');
217-
this.measurePreviewLine.setAttribute(
218-
'class',
219-
'ttrpgmap-draw-line ttrpgmap-measure-line ttrpgmap-measure-preview',
220-
);
216+
this.measurePreviewLine = createSvg('line', {
217+
cls: 'ttrpgmap-draw-line ttrpgmap-measure-line ttrpgmap-measure-preview',
218+
});
221219
this.ctx.svgOverlay.appendChild(this.measurePreviewLine);
222220
}
223221
this.measurePreviewLine.setAttribute('x1', String(last.x));
@@ -226,9 +224,10 @@ export class MeasurementController {
226224
this.measurePreviewLine.setAttribute('y2', String(cursor.y));
227225

228226
if (!this.measurePreviewCircle) {
229-
this.measurePreviewCircle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
227+
this.measurePreviewCircle = createSvg('circle', {
228+
cls: 'ttrpgmap-draw-point ttrpgmap-measure-preview',
229+
});
230230
this.measurePreviewCircle.setAttribute('r', '4');
231-
this.measurePreviewCircle.setAttribute('class', 'ttrpgmap-draw-point ttrpgmap-measure-preview');
232231
this.ctx.svgOverlay.appendChild(this.measurePreviewCircle);
233232
}
234233
this.measurePreviewCircle.setAttribute('cx', String(cursor.x));
@@ -239,8 +238,9 @@ export class MeasurementController {
239238
if (segDist !== null) {
240239
const mid: MapPoint = { x: (last.x + cursor.x) / 2, y: (last.y + cursor.y) / 2 };
241240
if (!this.measurePreviewLabel) {
242-
this.measurePreviewLabel = document.createElementNS('http://www.w3.org/2000/svg', 'text');
243-
this.measurePreviewLabel.setAttribute('class', 'ttrpgmap-draw-label ttrpgmap-measure-preview');
241+
this.measurePreviewLabel = createSvg('text', {
242+
cls: 'ttrpgmap-draw-label ttrpgmap-measure-preview',
243+
});
244244
this.ctx.svgOverlay.appendChild(this.measurePreviewLabel);
245245
}
246246
this.measurePreviewLabel.setAttribute('x', String(mid.x));
@@ -272,8 +272,7 @@ export class MeasurementController {
272272
const stroke: MapPoint[] = [point];
273273
this.freehandStrokes.push(stroke);
274274

275-
const polyline = document.createElementNS('http://www.w3.org/2000/svg', 'polyline');
276-
polyline.setAttribute('class', 'ttrpgmap-draw-line ttrpgmap-freehand-line');
275+
const polyline = createSvg('polyline', { cls: 'ttrpgmap-draw-line ttrpgmap-freehand-line' });
277276
polyline.setAttribute('points', `${point.x},${point.y}`);
278277
polyline.setAttribute('fill', 'none');
279278
this.ctx.svgOverlay.appendChild(polyline);
@@ -500,33 +499,30 @@ export class MeasurementController {
500499
}
501500

502501
private drawSvgLine(a: MapPoint, b: MapPoint, cls: string): SVGLineElement {
503-
const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
502+
const line = createSvg('line', { cls });
504503
line.setAttribute('x1', String(a.x));
505504
line.setAttribute('y1', String(a.y));
506505
line.setAttribute('x2', String(b.x));
507506
line.setAttribute('y2', String(b.y));
508-
line.setAttribute('class', cls);
509507
this.ctx.svgOverlay.appendChild(line);
510508
this.activeSvgElements.push(line);
511509
return line;
512510
}
513511

514512
private drawSvgCircle(p: MapPoint, r: number, cls: string): SVGCircleElement {
515-
const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
513+
const circle = createSvg('circle', { cls });
516514
circle.setAttribute('cx', String(p.x));
517515
circle.setAttribute('cy', String(p.y));
518516
circle.setAttribute('r', String(r));
519-
circle.setAttribute('class', cls);
520517
this.ctx.svgOverlay.appendChild(circle);
521518
this.activeSvgElements.push(circle);
522519
return circle;
523520
}
524521

525522
private drawSvgText(p: MapPoint, text: string, cls: string): SVGTextElement {
526-
const el = document.createElementNS('http://www.w3.org/2000/svg', 'text');
523+
const el = createSvg('text', { cls });
527524
el.setAttribute('x', String(p.x));
528525
el.setAttribute('y', String(p.y - 10));
529-
el.setAttribute('class', cls);
530526
el.textContent = text;
531527
this.ctx.svgOverlay.appendChild(el);
532528
this.activeSvgElements.push(el);

0 commit comments

Comments
 (0)