inspector-ng 0.0.5 → 0.0.6

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.
@@ -277,14 +277,14 @@ class inspectorComponent {
277
277
  this.Math = Math;
278
278
  this.formatValue = formatValue;
279
279
  this.guideHitboxSize = GUIDE_HITBOX_SIZE;
280
- this.overlayRoot = viewChild("overlayRoot");
281
- this.highlightColor = "#4f8cff";
282
- this.guideColor = "#ff7a00";
280
+ this.overlayRoot = viewChild('overlayRoot');
281
+ this.highlightColor = '#4f8cff';
282
+ this.guideColor = '#ff7a00';
283
283
  this.hoverHighlightEnabled = true;
284
284
  this.persistOnReload = false;
285
285
  this.enabled = signal(false);
286
- this.toolMode = signal("none");
287
- this.guideOrientation = signal("vertical");
286
+ this.toolMode = signal('none');
287
+ this.guideOrientation = signal('vertical');
288
288
  this.guides = signal([]);
289
289
  this.hoverRect = signal(null);
290
290
  this.selectedGuideId = signal(null);
@@ -298,13 +298,23 @@ class inspectorComponent {
298
298
  this.selectedMetaLine = computed(() => {
299
299
  const selected = this.selectedMeasurement();
300
300
  if (!selected) {
301
- return "";
301
+ return '';
302
302
  }
303
303
  return `${selected.label} · ${formatValue(selected.rect.width)} x ${formatValue(selected.rect.height)} · ${selected.styles.fontSize} / ${selected.styles.lineHeight} / ${selected.styles.color}`;
304
304
  });
305
305
  this.hydrated = signal(false);
306
306
  this.history = signal([]);
307
307
  this.historyIndex = signal(-1);
308
+ this.handleCapturedClick = (event) => {
309
+ if (!event.shiftKey ||
310
+ !this.canInspectClick(event) ||
311
+ !this.selectElementAtPoint(event)) {
312
+ return;
313
+ }
314
+ event.preventDefault();
315
+ event.stopPropagation();
316
+ event.stopImmediatePropagation();
317
+ };
308
318
  this.draggingGuideId = null;
309
319
  this.selectedElement = null;
310
320
  this.hoverElement = null;
@@ -331,7 +341,14 @@ class inspectorComponent {
331
341
  });
332
342
  }
333
343
  ngOnInit() {
334
- if (!this.isBrowser || !this.persistOnReload) {
344
+ if (!this.isBrowser) {
345
+ this.hydrated.set(true);
346
+ return;
347
+ }
348
+ window.addEventListener('click', this.handleCapturedClick, {
349
+ capture: true,
350
+ });
351
+ if (!this.persistOnReload) {
335
352
  this.hydrated.set(true);
336
353
  return;
337
354
  }
@@ -357,11 +374,19 @@ class inspectorComponent {
357
374
  this.hydrated.set(true);
358
375
  this.refreshTypographyBlocks();
359
376
  }
377
+ ngOnDestroy() {
378
+ if (!this.isBrowser) {
379
+ return;
380
+ }
381
+ window.removeEventListener('click', this.handleCapturedClick, {
382
+ capture: true,
383
+ });
384
+ }
360
385
  setToolMode(mode) {
361
386
  if (!this.enabled()) {
362
387
  this.enabled.set(true);
363
388
  }
364
- this.toolMode.set(this.toolMode() === mode ? "none" : mode);
389
+ this.toolMode.set(this.toolMode() === mode ? 'none' : mode);
365
390
  this.hoverRect.set(null);
366
391
  this.guidePreview.set(null);
367
392
  this.distanceOverlay.set(null);
@@ -397,11 +422,11 @@ class inspectorComponent {
397
422
  }
398
423
  handleKeydown(event) {
399
424
  const key = event.key.toLowerCase();
400
- if (key === "m") {
425
+ if (key === 'm') {
401
426
  event.preventDefault();
402
427
  this.enabled.update((value) => !value);
403
428
  if (!this.enabled()) {
404
- this.toolMode.set("none");
429
+ this.toolMode.set('none');
405
430
  this.hoverRect.set(null);
406
431
  this.selectedGuideId.set(null);
407
432
  this.distanceOverlay.set(null);
@@ -414,37 +439,37 @@ class inspectorComponent {
414
439
  if (!this.enabled()) {
415
440
  return;
416
441
  }
417
- if ((event.metaKey || event.ctrlKey) && key === "z") {
442
+ if ((event.metaKey || event.ctrlKey) && key === 'z') {
418
443
  event.preventDefault();
419
444
  event.shiftKey ? this.redo() : this.undo();
420
445
  return;
421
446
  }
422
- if (key === "s") {
447
+ if (key === 's') {
423
448
  event.preventDefault();
424
- this.setToolMode("select");
449
+ this.setToolMode('select');
425
450
  return;
426
451
  }
427
- if (key === "g") {
452
+ if (key === 'g') {
428
453
  event.preventDefault();
429
- this.setToolMode("guides");
454
+ this.setToolMode('guides');
430
455
  return;
431
456
  }
432
- if (key === "h") {
457
+ if (key === 'h') {
433
458
  event.preventDefault();
434
- this.setGuideOrientation("horizontal");
459
+ this.setGuideOrientation('horizontal');
435
460
  return;
436
461
  }
437
- if (key === "v") {
462
+ if (key === 'v') {
438
463
  event.preventDefault();
439
- this.setGuideOrientation("vertical");
464
+ this.setGuideOrientation('vertical');
440
465
  return;
441
466
  }
442
- if (event.key === "Alt") {
467
+ if (event.key === 'Alt') {
443
468
  this.altPressed.set(true);
444
469
  this.updateDistanceOverlay();
445
470
  return;
446
471
  }
447
- if (key === "escape") {
472
+ if (key === 'escape') {
448
473
  event.preventDefault();
449
474
  this.selectedMeasurement.set(null);
450
475
  this.selectedGuideId.set(null);
@@ -457,7 +482,7 @@ class inspectorComponent {
457
482
  this.refreshTypographyBlocks();
458
483
  return;
459
484
  }
460
- if ((key === "backspace" || key === "delete") && this.selectedGuideId()) {
485
+ if ((key === 'backspace' || key === 'delete') && this.selectedGuideId()) {
461
486
  event.preventDefault();
462
487
  const nextGuides = this.guides().filter((guide) => guide.id !== this.selectedGuideId());
463
488
  this.guides.set(nextGuides);
@@ -466,7 +491,7 @@ class inspectorComponent {
466
491
  }
467
492
  }
468
493
  handleKeyup(event) {
469
- if (event.key === "Alt") {
494
+ if (event.key === 'Alt') {
470
495
  this.altPressed.set(false);
471
496
  this.distanceOverlay.set(null);
472
497
  }
@@ -482,13 +507,13 @@ class inspectorComponent {
482
507
  if (guide.id !== this.draggingGuideId) {
483
508
  return guide;
484
509
  }
485
- const rawPosition = guide.orientation === "vertical" ? event.clientX : event.clientY;
486
- const max = guide.orientation === "vertical" ? viewport.width : viewport.height;
510
+ const rawPosition = guide.orientation === 'vertical' ? event.clientX : event.clientY;
511
+ const max = guide.orientation === 'vertical' ? viewport.width : viewport.height;
487
512
  return { ...guide, position: clamp(rawPosition, 0, max) };
488
513
  }));
489
514
  return;
490
515
  }
491
- if (this.toolMode() === "guides") {
516
+ if (this.toolMode() === 'guides') {
492
517
  this.hoverRect.set(null);
493
518
  this.hoverElement = null;
494
519
  this.distanceOverlay.set(null);
@@ -501,7 +526,7 @@ class inspectorComponent {
501
526
  return;
502
527
  }
503
528
  this.guidePreview.set(null);
504
- if (this.toolMode() !== "select" || !this.hoverHighlightEnabled) {
529
+ if (this.toolMode() !== 'select' || !this.hoverHighlightEnabled) {
505
530
  this.hoverRect.set(null);
506
531
  this.hoverElement = null;
507
532
  if (!this.altPressed()) {
@@ -535,7 +560,7 @@ class inspectorComponent {
535
560
  return;
536
561
  }
537
562
  const overlay = this.overlayRoot()?.nativeElement ?? null;
538
- if (this.toolMode() === "guides") {
563
+ if (this.toolMode() === 'guides') {
539
564
  if (overlay && overlay.contains(event.target)) {
540
565
  return;
541
566
  }
@@ -544,16 +569,34 @@ class inspectorComponent {
544
569
  this.guidePreview.set(guide);
545
570
  return;
546
571
  }
547
- if (this.toolMode() !== "select") {
572
+ if (!this.canInspectClick(event)) {
548
573
  return;
549
574
  }
575
+ this.selectElementAtPoint(event);
576
+ }
577
+ handleViewportChange() {
578
+ if (this.selectedElement && document.contains(this.selectedElement)) {
579
+ this.selectedMeasurement.set(getInspectMeasurement(this.selectedElement));
580
+ }
581
+ this.updateDistanceOverlay();
582
+ this.refreshTypographyBlocks();
583
+ }
584
+ canInspectClick(event) {
585
+ if (!this.enabled() || !this.isBrowser || this.toolMode() !== 'select') {
586
+ return false;
587
+ }
588
+ const overlay = this.overlayRoot()?.nativeElement ?? null;
589
+ return !(overlay && overlay.contains(event.target));
590
+ }
591
+ selectElementAtPoint(event) {
592
+ const overlay = this.overlayRoot()?.nativeElement ?? null;
550
593
  const target = getTargetElement({ x: event.clientX, y: event.clientY }, overlay);
551
594
  if (!target) {
552
595
  this.selectedMeasurement.set(null);
553
596
  this.selectedElement = null;
554
597
  this.distanceOverlay.set(null);
555
598
  this.refreshTypographyBlocks();
556
- return;
599
+ return false;
557
600
  }
558
601
  // Ctrl+click: select the minimum common parent of current selection and clicked element
559
602
  if ((event.ctrlKey || event.metaKey) && this.selectedElement) {
@@ -565,7 +608,7 @@ class inspectorComponent {
565
608
  this.selectedElement = commonParent;
566
609
  this.updateDistanceOverlay();
567
610
  this.refreshTypographyBlocks();
568
- return;
611
+ return true;
569
612
  }
570
613
  }
571
614
  this.selectedMeasurement.set(getInspectMeasurement(target));
@@ -573,13 +616,7 @@ class inspectorComponent {
573
616
  this.selectedGuideId.set(this.findGuideAtPoint(event.clientX, event.clientY));
574
617
  this.updateDistanceOverlay();
575
618
  this.refreshTypographyBlocks();
576
- }
577
- handleViewportChange() {
578
- if (this.selectedElement && document.contains(this.selectedElement)) {
579
- this.selectedMeasurement.set(getInspectMeasurement(this.selectedElement));
580
- }
581
- this.updateDistanceOverlay();
582
- this.refreshTypographyBlocks();
619
+ return true;
583
620
  }
584
621
  updateDistanceOverlay() {
585
622
  if (!this.altPressed() ||
@@ -622,10 +659,10 @@ class inspectorComponent {
622
659
  getGuidePreview(event) {
623
660
  const viewport = getViewportSize();
624
661
  const orientation = this.guideOrientation();
625
- const rawPosition = orientation === "vertical" ? event.clientX : event.clientY;
626
- const max = orientation === "vertical" ? viewport.width : viewport.height;
662
+ const rawPosition = orientation === 'vertical' ? event.clientX : event.clientY;
663
+ const max = orientation === 'vertical' ? viewport.width : viewport.height;
627
664
  return {
628
- id: "preview",
665
+ id: 'preview',
629
666
  orientation,
630
667
  position: this.snapGuide(clamp(rawPosition, 0, max)),
631
668
  };
@@ -640,11 +677,11 @@ class inspectorComponent {
640
677
  }
641
678
  findGuideAtPoint(x, y) {
642
679
  for (const guide of this.guides()) {
643
- if (guide.orientation === "vertical" &&
680
+ if (guide.orientation === 'vertical' &&
644
681
  Math.abs(guide.position - x) <= GUIDE_HITBOX_SIZE) {
645
682
  return guide.id;
646
683
  }
647
- if (guide.orientation === "horizontal" &&
684
+ if (guide.orientation === 'horizontal' &&
648
685
  Math.abs(guide.position - y) <= GUIDE_HITBOX_SIZE) {
649
686
  return guide.id;
650
687
  }
@@ -699,7 +736,7 @@ class inspectorComponent {
699
736
  }
700
737
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: inspectorComponent, decorators: [{
701
738
  type: Component,
702
- args: [{ selector: "inspector-overlay", standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"inspector-root\" #overlayRoot>\n <div class=\"inspector-toolbar\">\n <div class=\"inspector-toolbar__rail\">\n <button\n type=\"button\"\n class=\"inspector-icon-button\"\n [class.is-active]=\"toolMode() === 'select'\"\n (click)=\"setToolMode('select')\"\n title=\"Select mode\"\n >\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M3 2l8 8-3 .7L6.7 13 6 10 3 2z\" />\n </svg>\n </button>\n <button\n type=\"button\"\n class=\"inspector-icon-button\"\n [class.is-active]=\"showTypography()\"\n (click)=\"toggleTypography()\"\n title=\"Typography mode\"\n >\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M3 4V2h10v2h-4v10H7V4z\" />\n </svg>\n </button>\n <div class=\"inspector-guide-group\">\n <button\n type=\"button\"\n class=\"inspector-icon-button inspector-icon-button--guide-main\"\n [class.is-active]=\"toolMode() === 'guides'\"\n (click)=\"setToolMode('guides')\"\n title=\"Guides mode\"\n >\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M4 2h1v12H4zM11 2h1v12h-1zM2 4h12v1H2zM2 11h12v1H2z\" />\n </svg>\n </button>\n\n <button\n type=\"button\"\n class=\"inspector-icon-button inspector-icon-button--ghost inspector-icon-button--guide-menu\"\n [class.is-active]=\"guideMenuOpen()\"\n (click)=\"toggleGuideMenu()\"\n title=\"Guide options\"\n >\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M4.47 6.97L8 10.5l3.53-3.53-.94-.94L8 8.62 5.41 6.03z\" />\n </svg>\n </button>\n\n @if (guideMenuOpen()) {\n <div class=\"inspector-guide-menu\">\n <button\n type=\"button\"\n class=\"inspector-segment\"\n [class.is-active]=\"guideOrientation() === 'vertical'\"\n (click)=\"setGuideOrientation('vertical')\"\n >\n Vertical\n </button>\n <button\n type=\"button\"\n class=\"inspector-segment\"\n [class.is-active]=\"guideOrientation() === 'horizontal'\"\n (click)=\"setGuideOrientation('horizontal')\"\n >\n Horizontal\n </button>\n <button\n type=\"button\"\n class=\"inspector-segment inspector-segment--danger\"\n (click)=\"clearGuides()\"\n >\n Clear\n </button>\n </div>\n }\n </div>\n </div>\n </div>\n\n @if (enabled() && toolMode() === \"select\") {\n @if (hoverRect() && hoverHighlightEnabled) {\n <div\n class=\"inspector-box inspector-box--hover\"\n [style.left.px]=\"hoverRect()!.left\"\n [style.top.px]=\"hoverRect()!.top\"\n [style.width.px]=\"hoverRect()!.width\"\n [style.height.px]=\"hoverRect()!.height\"\n [style.--inspector-accent]=\"highlightColor\"\n ></div>\n }\n\n @if (selectedMeasurement(); as selected) {\n @if (selected.gap.active && selected.parentRect) {\n <div\n class=\"inspector-box inspector-box--gap\"\n [style.left.px]=\"selected.parentRect.left\"\n [style.top.px]=\"selected.parentRect.top\"\n [style.width.px]=\"selected.parentRect.width\"\n [style.height.px]=\"selected.parentRect.height\"\n ></div>\n <div\n class=\"inspector-box-tag inspector-box-tag--gap\"\n [style.left.px]=\"selected.parentRect.left\"\n [style.top.px]=\"selected.parentRect.top - 8\"\n >\n G {{ formatGap(selected) }}\n </div>\n }\n\n <div\n class=\"inspector-box inspector-box--margin\"\n [style.left.px]=\"selected.marginRect.left\"\n [style.top.px]=\"selected.marginRect.top\"\n [style.width.px]=\"selected.marginRect.width\"\n [style.height.px]=\"selected.marginRect.height\"\n ></div>\n <div\n class=\"inspector-box-tag inspector-box-tag--margin\"\n [style.left.px]=\"selected.marginRect.left\"\n [style.top.px]=\"selected.marginRect.top - 8\"\n >\n M {{ formatEdges(selected.margin) }}\n </div>\n\n <div\n class=\"inspector-box inspector-box--selected\"\n [style.left.px]=\"selected.rect.left\"\n [style.top.px]=\"selected.rect.top\"\n [style.width.px]=\"selected.rect.width\"\n [style.height.px]=\"selected.rect.height\"\n [style.--inspector-accent]=\"highlightColor\"\n >\n <div class=\"inspector-label\">{{ selectedMetaLine() }}</div>\n </div>\n\n <div\n class=\"inspector-box inspector-box--padding\"\n [style.left.px]=\"selected.paddingRect.left\"\n [style.top.px]=\"selected.paddingRect.top\"\n [style.width.px]=\"selected.paddingRect.width\"\n [style.height.px]=\"selected.paddingRect.height\"\n ></div>\n <div\n class=\"inspector-box-tag inspector-box-tag--padding\"\n [style.left.px]=\"selected.paddingRect.left\"\n [style.top.px]=\"\n selected.paddingRect.top + selected.paddingRect.height + 8\n \"\n >\n P {{ formatEdges(selected.padding) }}\n </div>\n }\n }\n\n @if (enabled() && showTypography()) {\n @for (block of textBlocks(); track block.id) {\n <div\n class=\"inspector-text-chip\"\n [style.left.px]=\"block.rect.left\"\n [style.top.px]=\"block.rect.top - 8\"\n >\n <span\n class=\"inspector-text-chip__swatch\"\n [style.background]=\"block.styles.color\"\n ></span>\n <span>{{ block.styles.fontSize }}</span>\n <span>{{ block.styles.lineHeight }}</span>\n <span>{{ block.styles.color }}</span>\n </div>\n }\n }\n\n @if (enabled() && altPressed() && distanceOverlay(); as distance) {\n <div\n class=\"inspector-box inspector-box--distance\"\n [style.left.px]=\"distance.rectA.left\"\n [style.top.px]=\"distance.rectA.top\"\n [style.width.px]=\"distance.rectA.width\"\n [style.height.px]=\"distance.rectA.height\"\n ></div>\n <div\n class=\"inspector-box inspector-box--distance\"\n [style.left.px]=\"distance.rectB.left\"\n [style.top.px]=\"distance.rectB.top\"\n [style.width.px]=\"distance.rectB.width\"\n [style.height.px]=\"distance.rectB.height\"\n ></div>\n\n @for (\n connector of distance.connectors;\n track trackConnector($index, connector)\n ) {\n <div\n class=\"inspector-connector\"\n [class.inspector-connector--vertical]=\"connector.x1 === connector.x2\"\n [class.inspector-connector--horizontal]=\"connector.y1 === connector.y2\"\n [style.left.px]=\"Math.min(connector.x1, connector.x2)\"\n [style.top.px]=\"Math.min(connector.y1, connector.y2)\"\n [style.width.px]=\"Math.max(1, Math.abs(connector.x2 - connector.x1))\"\n [style.height.px]=\"Math.max(1, Math.abs(connector.y2 - connector.y1))\"\n ></div>\n }\n\n @if (distance.horizontal && distance.horizontal.value > 0) {\n <div\n class=\"inspector-distance-line inspector-distance-line--horizontal\"\n [style.left.px]=\"\n Math.min(distance.horizontal.x1!, distance.horizontal.x2!)\n \"\n [style.top.px]=\"distance.horizontal.y!\"\n [style.width.px]=\"\n Math.abs(distance.horizontal.x2! - distance.horizontal.x1!)\n \"\n ></div>\n <div\n class=\"inspector-distance-tag\"\n [style.left.px]=\"\n (distance.horizontal.x1! + distance.horizontal.x2!) / 2\n \"\n [style.top.px]=\"distance.horizontal.y! + 10\"\n >\n {{ formatValue(distance.horizontal.value) }}\n </div>\n }\n\n @if (distance.vertical && distance.vertical.value > 0) {\n <div\n class=\"inspector-distance-line inspector-distance-line--vertical\"\n [style.left.px]=\"distance.vertical.x!\"\n [style.top.px]=\"Math.min(distance.vertical.y1!, distance.vertical.y2!)\"\n [style.height.px]=\"\n Math.abs(distance.vertical.y2! - distance.vertical.y1!)\n \"\n ></div>\n <div\n class=\"inspector-distance-tag inspector-distance-tag--vertical\"\n [style.left.px]=\"distance.vertical.x! + 10\"\n [style.top.px]=\"(distance.vertical.y1! + distance.vertical.y2!) / 2\"\n >\n {{ formatValue(distance.vertical.value) }}\n </div>\n }\n }\n\n @if (enabled()) {\n @if (toolMode() === \"guides\") {\n @if (guidePreview(); as preview) {\n <div\n class=\"inspector-guide inspector-guide--preview\"\n [class.inspector-guide--vertical]=\"preview.orientation === 'vertical'\"\n [class.inspector-guide--horizontal]=\"\n preview.orientation === 'horizontal'\n \"\n [style.left.px]=\"\n preview.orientation === 'vertical' ? preview.position : null\n \"\n [style.top.px]=\"\n preview.orientation === 'horizontal' ? preview.position : null\n \"\n [style.--inspector-guide]=\"guideColor\"\n >\n <span class=\"inspector-guide-line\"></span>\n </div>\n }\n }\n\n @for (guide of guides(); track guide.id) {\n <button\n type=\"button\"\n class=\"inspector-guide\"\n [class.inspector-guide--vertical]=\"guide.orientation === 'vertical'\"\n [class.inspector-guide--horizontal]=\"guide.orientation === 'horizontal'\"\n [class.inspector-guide--selected]=\"selectedGuideId() === guide.id\"\n [style.left.px]=\"\n guide.orientation === 'vertical' ? guide.position : null\n \"\n [style.top.px]=\"\n guide.orientation === 'horizontal' ? guide.position : null\n \"\n [style.--inspector-guide]=\"guideColor\"\n (pointerdown)=\"startGuideDrag($event, guide)\"\n >\n <span class=\"inspector-guide-line\"></span>\n </button>\n }\n }\n</div>\n", styles: [":host{--inspector-panel: rgba(27, 29, 36, .94);--inspector-panel-edge: rgba(255, 255, 255, .08);--inspector-text: #f3f4f6;--inspector-muted: #9ca3af;--inspector-blue: #4f8cff;--inspector-orange: #f59e0b;--inspector-green: #22c55e;--inspector-violet: #a855f7;position:fixed;inset:0;z-index:2147;pointer-events:none;font-family:SF Pro Display,Segoe UI,sans-serif}.inspector-root{position:fixed;inset:0;pointer-events:none}.inspector-toolbar{position:fixed;top:18px;right:18px;display:block;pointer-events:auto;z-index:10000}.inspector-toolbar__rail,.inspector-guide-menu{display:flex;gap:4px;padding:4px;border-radius:8px;border:1px solid var(--inspector-panel-edge);background:var(--inspector-panel);box-shadow:0 18px 40px #00000052;-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px)}.inspector-toolbar__rail{align-items:center}.inspector-guide-group{position:relative;display:flex;gap:0;align-items:center;border-radius:6px}.inspector-guide-menu{position:absolute;top:calc(100% + 8px);right:0;min-width:max-content;flex-direction:column;align-items:stretch}.inspector-guide-menu .inspector-segment{justify-content:flex-start;width:100%}.inspector-icon-button,.inspector-segment{display:inline-flex;align-items:center;justify-content:center;height:26px;border:0;border-radius:6px;background:transparent;color:var(--inspector-muted);cursor:pointer;transition:background .12s ease,color .12s ease;font:inherit;font-size:11px;letter-spacing:.02em}.inspector-icon-button{width:26px}.inspector-icon-button svg{width:14px;height:14px;fill:currentColor}.inspector-icon-button:hover,.inspector-segment:hover{background:#ffffff14;color:var(--inspector-text)}.inspector-icon-button.is-active,.inspector-segment.is-active{background:#4f8cff2e;color:#dbeafe}.inspector-icon-button--ghost.is-active{background:#ffffff14;color:var(--inspector-text)}.inspector-icon-button--guide-main{border-radius:6px 0 0 6px}.inspector-icon-button--guide-menu{width:20px;border-radius:0 6px 6px 0}.inspector-icon-button--guide-menu svg{width:12px;height:12px}.inspector-segment{padding:0 8px;white-space:nowrap}.inspector-segment--danger:hover{background:#ef444429;color:#fecaca}.inspector-box{position:fixed;box-sizing:border-box;pointer-events:none;border:1px solid var(--inspector-accent, var(--inspector-blue));background:color-mix(in srgb,var(--inspector-accent, var(--inspector-blue)) 8%,transparent)}.inspector-box--hover{opacity:.55}.inspector-box--selected{border-width:1.5px}.inspector-box--margin{border-color:#f59e0bd1;background:#f59e0b14}.inspector-box--padding{border-color:#22c55ed1;background:#22c55e14}.inspector-box--gap{border-color:#a855f7b8;background:#a855f70a}.inspector-box--distance{border-style:dashed;border-color:#4f8cffb3;background:transparent}.inspector-label,.inspector-box-tag,.inspector-text-chip,.inspector-distance-tag{font-variant-numeric:tabular-nums}.inspector-label{position:absolute;left:0;top:0;transform:translateY(calc(-100% - 8px));max-width:min(420px,calc(100vw - 24px));padding:6px 9px;border-radius:999px;border:1px solid var(--inspector-panel-edge);background:var(--inspector-panel);color:var(--inspector-text);box-shadow:0 18px 40px #00000042;font-size:11px;line-height:1;white-space:nowrap}.inspector-box-tag{position:fixed;transform:translateY(-100%);padding:4px 6px;border-radius:999px;border:1px solid var(--inspector-panel-edge);background:#111827f0;color:var(--inspector-text);box-shadow:0 12px 24px #0003;font-size:10px;line-height:1;pointer-events:none}.inspector-box-tag--margin{color:#fbbf24}.inspector-box-tag--padding{color:#86efac;transform:translateY(0)}.inspector-box-tag--gap{color:#d8b4fe}.inspector-text-chip{position:fixed;transform:translateY(-100%);display:inline-flex;gap:6px;align-items:center;padding:4px 6px;border-radius:999px;border:1px solid var(--inspector-panel-edge);background:#111827f0;color:#e5e7eb;box-shadow:0 12px 24px #00000038;font-size:10px;line-height:1;white-space:nowrap;pointer-events:none}.inspector-text-chip__swatch{width:8px;height:8px;border-radius:999px;border:1px solid rgba(255,255,255,.18);flex:0 0 auto}.inspector-connector{position:fixed;border-color:#4f8cffb8;border-style:dashed;pointer-events:none}.inspector-connector--vertical{border-left-width:1px;width:0}.inspector-connector--horizontal{border-top-width:1px;height:0}.inspector-distance-line{position:fixed;background:var(--inspector-blue);pointer-events:none}.inspector-distance-line--horizontal{height:1px}.inspector-distance-line--vertical{width:1px}.inspector-distance-tag{position:fixed;transform:translate(-50%);padding:5px 7px;border-radius:999px;border:1px solid var(--inspector-panel-edge);background:#111827f2;color:var(--inspector-text);font-size:10px;line-height:1;pointer-events:none}.inspector-distance-tag--vertical{transform:translateY(-50%)}.inspector-guide{position:fixed;margin:0;padding:0;border:0;background:transparent;pointer-events:auto;cursor:grab}.inspector-guide--vertical{top:0;width:14px;height:100vh;transform:translate(-50%)}.inspector-guide--horizontal{left:0;width:100vw;height:14px;transform:translateY(-50%)}.inspector-guide--preview{opacity:.55;pointer-events:none;cursor:default}.inspector-guide--preview .inspector-guide-line{background:color-mix(in srgb,var(--inspector-guide, #ff7a00) 72%,transparent)}.inspector-guide-line{position:absolute;inset:0;pointer-events:none}.inspector-guide--vertical .inspector-guide-line{left:calc(50% - .5px);width:1px;height:100%;background:var(--inspector-guide, #ff7a00)}.inspector-guide--horizontal .inspector-guide-line{top:calc(50% - .5px);width:100%;height:1px;background:var(--inspector-guide, #ff7a00)}.inspector-guide--selected .inspector-guide-line{box-shadow:0 0 0 1px #ffffff80}\n"] }]
739
+ args: [{ selector: 'inspector-overlay', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"inspector-root\" #overlayRoot>\n <div class=\"inspector-toolbar\">\n <div class=\"inspector-toolbar__rail\">\n <button\n type=\"button\"\n class=\"inspector-icon-button\"\n [class.is-active]=\"toolMode() === 'select'\"\n (click)=\"setToolMode('select')\"\n title=\"Select mode\"\n >\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M3 2l8 8-3 .7L6.7 13 6 10 3 2z\" />\n </svg>\n </button>\n <button\n type=\"button\"\n class=\"inspector-icon-button\"\n [class.is-active]=\"showTypography()\"\n (click)=\"toggleTypography()\"\n title=\"Typography mode\"\n >\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M3 4V2h10v2h-4v10H7V4z\" />\n </svg>\n </button>\n <div class=\"inspector-guide-group\">\n <button\n type=\"button\"\n class=\"inspector-icon-button inspector-icon-button--guide-main\"\n [class.is-active]=\"toolMode() === 'guides'\"\n (click)=\"setToolMode('guides')\"\n title=\"Guides mode\"\n >\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M4 2h1v12H4zM11 2h1v12h-1zM2 4h12v1H2zM2 11h12v1H2z\" />\n </svg>\n </button>\n\n <button\n type=\"button\"\n class=\"inspector-icon-button inspector-icon-button--ghost inspector-icon-button--guide-menu\"\n [class.is-active]=\"guideMenuOpen()\"\n (click)=\"toggleGuideMenu()\"\n title=\"Guide options\"\n >\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M4.47 6.97L8 10.5l3.53-3.53-.94-.94L8 8.62 5.41 6.03z\" />\n </svg>\n </button>\n\n @if (guideMenuOpen()) {\n <div class=\"inspector-guide-menu\">\n <button\n type=\"button\"\n class=\"inspector-segment\"\n [class.is-active]=\"guideOrientation() === 'vertical'\"\n (click)=\"setGuideOrientation('vertical')\"\n >\n Vertical\n </button>\n <button\n type=\"button\"\n class=\"inspector-segment\"\n [class.is-active]=\"guideOrientation() === 'horizontal'\"\n (click)=\"setGuideOrientation('horizontal')\"\n >\n Horizontal\n </button>\n <button\n type=\"button\"\n class=\"inspector-segment inspector-segment--danger\"\n (click)=\"clearGuides()\"\n >\n Clear\n </button>\n </div>\n }\n </div>\n </div>\n </div>\n\n @if (enabled() && toolMode() === \"select\") {\n @if (hoverRect() && hoverHighlightEnabled) {\n <div\n class=\"inspector-box inspector-box--hover\"\n [style.left.px]=\"hoverRect()!.left\"\n [style.top.px]=\"hoverRect()!.top\"\n [style.width.px]=\"hoverRect()!.width\"\n [style.height.px]=\"hoverRect()!.height\"\n [style.--inspector-accent]=\"highlightColor\"\n ></div>\n }\n\n @if (selectedMeasurement(); as selected) {\n @if (selected.gap.active && selected.parentRect) {\n <div\n class=\"inspector-box inspector-box--gap\"\n [style.left.px]=\"selected.parentRect.left\"\n [style.top.px]=\"selected.parentRect.top\"\n [style.width.px]=\"selected.parentRect.width\"\n [style.height.px]=\"selected.parentRect.height\"\n ></div>\n <div\n class=\"inspector-box-tag inspector-box-tag--gap\"\n [style.left.px]=\"selected.parentRect.left\"\n [style.top.px]=\"selected.parentRect.top - 8\"\n >\n G {{ formatGap(selected) }}\n </div>\n }\n\n <div\n class=\"inspector-box inspector-box--margin\"\n [style.left.px]=\"selected.marginRect.left\"\n [style.top.px]=\"selected.marginRect.top\"\n [style.width.px]=\"selected.marginRect.width\"\n [style.height.px]=\"selected.marginRect.height\"\n ></div>\n <div\n class=\"inspector-box-tag inspector-box-tag--margin\"\n [style.left.px]=\"selected.marginRect.left\"\n [style.top.px]=\"selected.marginRect.top - 8\"\n >\n M {{ formatEdges(selected.margin) }}\n </div>\n\n <div\n class=\"inspector-box inspector-box--selected\"\n [style.left.px]=\"selected.rect.left\"\n [style.top.px]=\"selected.rect.top\"\n [style.width.px]=\"selected.rect.width\"\n [style.height.px]=\"selected.rect.height\"\n [style.--inspector-accent]=\"highlightColor\"\n >\n <div class=\"inspector-label\">{{ selectedMetaLine() }}</div>\n </div>\n\n <div\n class=\"inspector-box inspector-box--padding\"\n [style.left.px]=\"selected.paddingRect.left\"\n [style.top.px]=\"selected.paddingRect.top\"\n [style.width.px]=\"selected.paddingRect.width\"\n [style.height.px]=\"selected.paddingRect.height\"\n ></div>\n <div\n class=\"inspector-box-tag inspector-box-tag--padding\"\n [style.left.px]=\"selected.paddingRect.left\"\n [style.top.px]=\"\n selected.paddingRect.top + selected.paddingRect.height + 8\n \"\n >\n P {{ formatEdges(selected.padding) }}\n </div>\n }\n }\n\n @if (enabled() && showTypography()) {\n @for (block of textBlocks(); track block.id) {\n <div\n class=\"inspector-text-chip\"\n [style.left.px]=\"block.rect.left\"\n [style.top.px]=\"block.rect.top - 8\"\n >\n <span\n class=\"inspector-text-chip__swatch\"\n [style.background]=\"block.styles.color\"\n ></span>\n <span>{{ block.styles.fontSize }}</span>\n <span>{{ block.styles.lineHeight }}</span>\n <span>{{ block.styles.color }}</span>\n </div>\n }\n }\n\n @if (enabled() && altPressed() && distanceOverlay(); as distance) {\n <div\n class=\"inspector-box inspector-box--distance\"\n [style.left.px]=\"distance.rectA.left\"\n [style.top.px]=\"distance.rectA.top\"\n [style.width.px]=\"distance.rectA.width\"\n [style.height.px]=\"distance.rectA.height\"\n ></div>\n <div\n class=\"inspector-box inspector-box--distance\"\n [style.left.px]=\"distance.rectB.left\"\n [style.top.px]=\"distance.rectB.top\"\n [style.width.px]=\"distance.rectB.width\"\n [style.height.px]=\"distance.rectB.height\"\n ></div>\n\n @for (\n connector of distance.connectors;\n track trackConnector($index, connector)\n ) {\n <div\n class=\"inspector-connector\"\n [class.inspector-connector--vertical]=\"connector.x1 === connector.x2\"\n [class.inspector-connector--horizontal]=\"connector.y1 === connector.y2\"\n [style.left.px]=\"Math.min(connector.x1, connector.x2)\"\n [style.top.px]=\"Math.min(connector.y1, connector.y2)\"\n [style.width.px]=\"Math.max(1, Math.abs(connector.x2 - connector.x1))\"\n [style.height.px]=\"Math.max(1, Math.abs(connector.y2 - connector.y1))\"\n ></div>\n }\n\n @if (distance.horizontal && distance.horizontal.value > 0) {\n <div\n class=\"inspector-distance-line inspector-distance-line--horizontal\"\n [style.left.px]=\"\n Math.min(distance.horizontal.x1!, distance.horizontal.x2!)\n \"\n [style.top.px]=\"distance.horizontal.y!\"\n [style.width.px]=\"\n Math.abs(distance.horizontal.x2! - distance.horizontal.x1!)\n \"\n ></div>\n <div\n class=\"inspector-distance-tag\"\n [style.left.px]=\"\n (distance.horizontal.x1! + distance.horizontal.x2!) / 2\n \"\n [style.top.px]=\"distance.horizontal.y! + 10\"\n >\n {{ formatValue(distance.horizontal.value) }}\n </div>\n }\n\n @if (distance.vertical && distance.vertical.value > 0) {\n <div\n class=\"inspector-distance-line inspector-distance-line--vertical\"\n [style.left.px]=\"distance.vertical.x!\"\n [style.top.px]=\"Math.min(distance.vertical.y1!, distance.vertical.y2!)\"\n [style.height.px]=\"\n Math.abs(distance.vertical.y2! - distance.vertical.y1!)\n \"\n ></div>\n <div\n class=\"inspector-distance-tag inspector-distance-tag--vertical\"\n [style.left.px]=\"distance.vertical.x! + 10\"\n [style.top.px]=\"(distance.vertical.y1! + distance.vertical.y2!) / 2\"\n >\n {{ formatValue(distance.vertical.value) }}\n </div>\n }\n }\n\n @if (enabled()) {\n @if (toolMode() === \"guides\") {\n @if (guidePreview(); as preview) {\n <div\n class=\"inspector-guide inspector-guide--preview\"\n [class.inspector-guide--vertical]=\"preview.orientation === 'vertical'\"\n [class.inspector-guide--horizontal]=\"\n preview.orientation === 'horizontal'\n \"\n [style.left.px]=\"\n preview.orientation === 'vertical' ? preview.position : null\n \"\n [style.top.px]=\"\n preview.orientation === 'horizontal' ? preview.position : null\n \"\n [style.--inspector-guide]=\"guideColor\"\n >\n <span class=\"inspector-guide-line\"></span>\n </div>\n }\n }\n\n @for (guide of guides(); track guide.id) {\n <button\n type=\"button\"\n class=\"inspector-guide\"\n [class.inspector-guide--vertical]=\"guide.orientation === 'vertical'\"\n [class.inspector-guide--horizontal]=\"guide.orientation === 'horizontal'\"\n [class.inspector-guide--selected]=\"selectedGuideId() === guide.id\"\n [style.left.px]=\"\n guide.orientation === 'vertical' ? guide.position : null\n \"\n [style.top.px]=\"\n guide.orientation === 'horizontal' ? guide.position : null\n \"\n [style.--inspector-guide]=\"guideColor\"\n (pointerdown)=\"startGuideDrag($event, guide)\"\n >\n <span class=\"inspector-guide-line\"></span>\n </button>\n }\n }\n</div>\n", styles: [":host{--inspector-panel: rgba(27, 29, 36, .94);--inspector-panel-edge: rgba(255, 255, 255, .08);--inspector-text: #f3f4f6;--inspector-muted: #9ca3af;--inspector-blue: #4f8cff;--inspector-orange: #f59e0b;--inspector-green: #22c55e;--inspector-violet: #a855f7;position:fixed;inset:0;z-index:2147;pointer-events:none;font-family:SF Pro Display,Segoe UI,sans-serif}.inspector-root{position:fixed;inset:0;pointer-events:none}.inspector-toolbar{position:fixed;top:18px;right:18px;display:block;pointer-events:auto;z-index:10000}.inspector-toolbar__rail,.inspector-guide-menu{display:flex;gap:4px;padding:4px;border-radius:8px;border:1px solid var(--inspector-panel-edge);background:var(--inspector-panel);box-shadow:0 18px 40px #00000052;-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px)}.inspector-toolbar__rail{align-items:center}.inspector-guide-group{position:relative;display:flex;gap:0;align-items:center;border-radius:6px}.inspector-guide-menu{position:absolute;top:calc(100% + 8px);right:0;min-width:max-content;flex-direction:column;align-items:stretch}.inspector-guide-menu .inspector-segment{justify-content:flex-start;width:100%}.inspector-icon-button,.inspector-segment{display:inline-flex;align-items:center;justify-content:center;height:26px;border:0;border-radius:6px;background:transparent;color:var(--inspector-muted);cursor:pointer;transition:background .12s ease,color .12s ease;font:inherit;font-size:11px;letter-spacing:.02em}.inspector-icon-button{width:26px}.inspector-icon-button svg{width:14px;height:14px;fill:currentColor}.inspector-icon-button:hover,.inspector-segment:hover{background:#ffffff14;color:var(--inspector-text)}.inspector-icon-button.is-active,.inspector-segment.is-active{background:#4f8cff2e;color:#dbeafe}.inspector-icon-button--ghost.is-active{background:#ffffff14;color:var(--inspector-text)}.inspector-icon-button--guide-main{border-radius:6px 0 0 6px}.inspector-icon-button--guide-menu{width:20px;border-radius:0 6px 6px 0}.inspector-icon-button--guide-menu svg{width:12px;height:12px}.inspector-segment{padding:0 8px;white-space:nowrap}.inspector-segment--danger:hover{background:#ef444429;color:#fecaca}.inspector-box{position:fixed;box-sizing:border-box;pointer-events:none;border:1px solid var(--inspector-accent, var(--inspector-blue));background:color-mix(in srgb,var(--inspector-accent, var(--inspector-blue)) 8%,transparent)}.inspector-box--hover{opacity:.55}.inspector-box--selected{border-width:1.5px}.inspector-box--margin{border-color:#f59e0bd1;background:#f59e0b14}.inspector-box--padding{border-color:#22c55ed1;background:#22c55e14}.inspector-box--gap{border-color:#a855f7b8;background:#a855f70a}.inspector-box--distance{border-style:dashed;border-color:#4f8cffb3;background:transparent}.inspector-label,.inspector-box-tag,.inspector-text-chip,.inspector-distance-tag{font-variant-numeric:tabular-nums}.inspector-label{position:absolute;left:0;top:0;transform:translateY(calc(-100% - 8px));max-width:min(420px,calc(100vw - 24px));padding:6px 9px;border-radius:999px;border:1px solid var(--inspector-panel-edge);background:var(--inspector-panel);color:var(--inspector-text);box-shadow:0 18px 40px #00000042;font-size:11px;line-height:1;white-space:nowrap}.inspector-box-tag{position:fixed;transform:translateY(-100%);padding:4px 6px;border-radius:999px;border:1px solid var(--inspector-panel-edge);background:#111827f0;color:var(--inspector-text);box-shadow:0 12px 24px #0003;font-size:10px;line-height:1;pointer-events:none}.inspector-box-tag--margin{color:#fbbf24}.inspector-box-tag--padding{color:#86efac;transform:translateY(0)}.inspector-box-tag--gap{color:#d8b4fe}.inspector-text-chip{position:fixed;transform:translateY(-100%);display:inline-flex;gap:6px;align-items:center;padding:4px 6px;border-radius:999px;border:1px solid var(--inspector-panel-edge);background:#111827f0;color:#e5e7eb;box-shadow:0 12px 24px #00000038;font-size:10px;line-height:1;white-space:nowrap;pointer-events:none}.inspector-text-chip__swatch{width:8px;height:8px;border-radius:999px;border:1px solid rgba(255,255,255,.18);flex:0 0 auto}.inspector-connector{position:fixed;border-color:#4f8cffb8;border-style:dashed;pointer-events:none}.inspector-connector--vertical{border-left-width:1px;width:0}.inspector-connector--horizontal{border-top-width:1px;height:0}.inspector-distance-line{position:fixed;background:var(--inspector-blue);pointer-events:none}.inspector-distance-line--horizontal{height:1px}.inspector-distance-line--vertical{width:1px}.inspector-distance-tag{position:fixed;transform:translate(-50%);padding:5px 7px;border-radius:999px;border:1px solid var(--inspector-panel-edge);background:#111827f2;color:var(--inspector-text);font-size:10px;line-height:1;pointer-events:none}.inspector-distance-tag--vertical{transform:translateY(-50%)}.inspector-guide{position:fixed;margin:0;padding:0;border:0;background:transparent;pointer-events:auto;cursor:grab}.inspector-guide--vertical{top:0;width:14px;height:100vh;transform:translate(-50%)}.inspector-guide--horizontal{left:0;width:100vw;height:14px;transform:translateY(-50%)}.inspector-guide--preview{opacity:.55;pointer-events:none;cursor:default}.inspector-guide--preview .inspector-guide-line{background:color-mix(in srgb,var(--inspector-guide, #ff7a00) 72%,transparent)}.inspector-guide-line{position:absolute;inset:0;pointer-events:none}.inspector-guide--vertical .inspector-guide-line{left:calc(50% - .5px);width:1px;height:100%;background:var(--inspector-guide, #ff7a00)}.inspector-guide--horizontal .inspector-guide-line{top:calc(50% - .5px);width:100%;height:1px;background:var(--inspector-guide, #ff7a00)}.inspector-guide--selected .inspector-guide-line{box-shadow:0 0 0 1px #ffffff80}\n"] }]
703
740
  }], ctorParameters: () => [{ type: undefined, decorators: [{
704
741
  type: Inject,
705
742
  args: [PLATFORM_ID]
@@ -713,25 +750,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
713
750
  type: Input
714
751
  }], handleKeydown: [{
715
752
  type: HostListener,
716
- args: ["window:keydown", ["$event"]]
753
+ args: ['window:keydown', ['$event']]
717
754
  }], handleKeyup: [{
718
755
  type: HostListener,
719
- args: ["window:keyup", ["$event"]]
756
+ args: ['window:keyup', ['$event']]
720
757
  }], handlePointerMove: [{
721
758
  type: HostListener,
722
- args: ["window:pointermove", ["$event"]]
759
+ args: ['window:pointermove', ['$event']]
723
760
  }], handlePointerUp: [{
724
761
  type: HostListener,
725
- args: ["window:pointerup"]
762
+ args: ['window:pointerup']
726
763
  }], handleClick: [{
727
764
  type: HostListener,
728
- args: ["window:click", ["$event"]]
765
+ args: ['window:click', ['$event']]
729
766
  }], handleViewportChange: [{
730
767
  type: HostListener,
731
- args: ["window:resize"]
768
+ args: ['window:resize']
732
769
  }, {
733
770
  type: HostListener,
734
- args: ["window:scroll"]
771
+ args: ['window:scroll']
735
772
  }] } });
736
773
 
737
774
  /**