sonance-brand-mcp 1.3.78 → 1.3.79

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.
@@ -64,6 +64,7 @@ import {
64
64
  removePreviewStyles,
65
65
  injectPreviewStyles,
66
66
  extractPreviewCSSFromCode,
67
+ getActiveModalContent,
67
68
  } from "./utils";
68
69
  import { Section, ColorSwatch, SelectField } from "./components/common";
69
70
  import { InspectorOverlay } from "./components/InspectorOverlay";
@@ -795,14 +796,28 @@ export function SonanceDevTools() {
795
796
  return rect; // No scroll parent, use original rect
796
797
  };
797
798
 
799
+ // Helper: Detect active modal and filter elements to only those in the topmost layer
800
+ const activeModalContent = getActiveModalContent();
801
+ const isInActiveLayer = (el: Element): boolean => {
802
+ // Always exclude DevTools panel
803
+ if (el.closest("[data-sonance-devtools]")) return false;
804
+
805
+ // If a modal is active, only include elements inside the modal content
806
+ if (activeModalContent) {
807
+ return activeModalContent.contains(el) || el === activeModalContent;
808
+ }
809
+
810
+ return true;
811
+ };
812
+
798
813
  // Scan for tagged components
799
814
  if (inspectorEnabled || activeTab === "components") {
800
815
  // 1. Scan for explicitly tagged components
801
816
  const taggedComponents = document.querySelectorAll("[data-sonance-name]");
802
817
  taggedComponents.forEach((el) => {
803
- // Skip DevTools elements
804
- if (el.closest("[data-sonance-devtools]")) return;
805
-
818
+ // Skip elements outside the active layer (DevTools, behind modals)
819
+ if (!isInActiveLayer(el)) return;
820
+
806
821
  const name = el.getAttribute("data-sonance-name");
807
822
  if (name) {
808
823
  const rawRect = el.getBoundingClientRect();
@@ -848,9 +863,9 @@ export function SonanceDevTools() {
848
863
  Object.entries(genericSelectors).forEach(([genericName, selector]) => {
849
864
  const elements = document.querySelectorAll(selector);
850
865
  elements.forEach((el) => {
851
- // Skip DevTools elements
852
- if (el.closest("[data-sonance-devtools]")) return;
853
-
866
+ // Skip elements outside the active layer (DevTools, behind modals)
867
+ if (!isInActiveLayer(el)) return;
868
+
854
869
  const rawRect = el.getBoundingClientRect();
855
870
  const rect = getVisibleRect(el, rawRect);
856
871
  if (rect && rect.width > 0 && rect.height > 0) {
@@ -890,6 +905,9 @@ export function SonanceDevTools() {
890
905
  if (activeTab === "logos") {
891
906
  const images = document.querySelectorAll("img");
892
907
  images.forEach((img) => {
908
+ // Skip elements outside the active layer (DevTools, behind modals)
909
+ if (!isInActiveLayer(img)) return;
910
+
893
911
  const src = img.src || img.getAttribute("src") || "";
894
912
  const alt = img.alt || "";
895
913
 
@@ -944,9 +962,9 @@ export function SonanceDevTools() {
944
962
  const addedElements = new Set<Element>();
945
963
 
946
964
  textElements.forEach((el) => {
947
- // Skip elements that are part of the DevTools UI
948
- if (el.closest("[data-sonance-devtools]")) return;
949
-
965
+ // Skip elements outside the active layer (DevTools, behind modals)
966
+ if (!isInActiveLayer(el)) return;
967
+
950
968
  // Skip if this element is inside another text element we're already tracking
951
969
  // This prevents duplicate labels for nested structures
952
970
  const parentTextEl = el.parentElement?.closest("h1, h2, h3, h4, h5, h6, p, a, label, blockquote, figcaption, li");
@@ -329,6 +329,55 @@ export function extractPreviewCSSFromCode(
329
329
  return rules.join("\n");
330
330
  }
331
331
 
332
+ /**
333
+ * Finds the topmost modal/dialog content container if one is open.
334
+ * Returns the content element (not the backdrop) or null if no modal is active.
335
+ *
336
+ * Detection strategy:
337
+ * 1. Look for Radix UI dialogs with [data-state="open"]
338
+ * 2. Look for role="dialog" elements
339
+ * 3. Look for native <dialog open> elements
340
+ * 4. Look for custom Dialog with z-50 fixed positioning
341
+ * 5. Look for Drawer/Sheet overlays
342
+ */
343
+ export function getActiveModalContent(): Element | null {
344
+ if (typeof document === "undefined") return null;
345
+
346
+ // Priority-ordered list of modal content selectors
347
+ const contentSelectors = [
348
+ // Radix UI Dialog content
349
+ '[data-state="open"][role="dialog"]',
350
+ // Custom Dialog content (has data-sonance-name="dialog")
351
+ '.fixed.inset-0.z-50 [data-sonance-name="dialog"]',
352
+ '.fixed.inset-0.z-50 > .relative.z-10',
353
+ // Native dialog
354
+ 'dialog[open]',
355
+ // aria-modal content
356
+ '[aria-modal="true"]',
357
+ // Sheet/Drawer content
358
+ '[data-state="open"][data-sheet-content]',
359
+ '[data-state="open"][role="complementary"]',
360
+ ];
361
+
362
+ for (const selector of contentSelectors) {
363
+ const modal = document.querySelector(selector);
364
+ if (modal) {
365
+ // Return innermost dialog content, not the wrapper
366
+ return modal;
367
+ }
368
+ }
369
+
370
+ // Fallback: check for z-50 fixed full-screen overlays
371
+ const fixedOverlays = document.querySelectorAll('.fixed.inset-0.z-50');
372
+ for (const overlay of fixedOverlays) {
373
+ // Find the content within (skip if it's just a backdrop)
374
+ const content = overlay.querySelector('.relative.z-10, [data-sonance-name]');
375
+ if (content) return content;
376
+ }
377
+
378
+ return null;
379
+ }
380
+
332
381
  // Helper to check if a category should show scope options
333
382
  export function shouldShowScopeOptions(category: string): boolean {
334
383
  if (category === "all") return true; // Show for "all" selection
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sonance-brand-mcp",
3
- "version": "1.3.78",
3
+ "version": "1.3.79",
4
4
  "description": "MCP Server for Sonance Brand Guidelines and Component Library - gives Claude instant access to brand colors, typography, and UI components.",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",