@inkindcards/semantic-layer 2.2.1 → 2.2.3

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.
@@ -61,9 +61,10 @@ interface InspectableProps {
61
61
  }
62
62
  /**
63
63
  * Wraps a data-bound component and registers it with the DataInspector overlay.
64
- * When inspect mode is off or no DataInspector ancestor exists, renders children
65
- * with zero layout impact (no wrapper div). Only adds a positioned wrapper
66
- * with a click-capture overlay when inspect mode is active.
64
+ * Uses `display: contents` so the wrapper is invisible to CSS layout charts,
65
+ * grids, and flex items render exactly as if Inspectable were not there.
66
+ * The inspect-mode highlight is rendered via a React portal into document.body,
67
+ * positioned with getBoundingClientRect().
67
68
  */
68
69
  declare function Inspectable({ label, currentSource, data, columns, children, }: InspectableProps): react_jsx_runtime.JSX.Element;
69
70
 
@@ -61,9 +61,10 @@ interface InspectableProps {
61
61
  }
62
62
  /**
63
63
  * Wraps a data-bound component and registers it with the DataInspector overlay.
64
- * When inspect mode is off or no DataInspector ancestor exists, renders children
65
- * with zero layout impact (no wrapper div). Only adds a positioned wrapper
66
- * with a click-capture overlay when inspect mode is active.
64
+ * Uses `display: contents` so the wrapper is invisible to CSS layout charts,
65
+ * grids, and flex items render exactly as if Inspectable were not there.
66
+ * The inspect-mode highlight is rendered via a React portal into document.body,
67
+ * positioned with getBoundingClientRect().
67
68
  */
68
69
  declare function Inspectable({ label, currentSource, data, columns, children, }: InspectableProps): react_jsx_runtime.JSX.Element;
69
70
 
@@ -1,6 +1,7 @@
1
1
  import { useMetrics, useAuth, useAdminFields, useAdminRoles, useAdminUsers } from './chunk-3OR3QCN6.js';
2
2
  import { createContext, useState, useMemo, useCallback, useContext, useId, useRef, useEffect } from 'react';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
+ import { createPortal } from 'react-dom';
4
5
 
5
6
  var containerStyle = {
6
7
  fontFamily: "system-ui, -apple-system, sans-serif",
@@ -834,6 +835,21 @@ function InspectableRegistry({ children }) {
834
835
  };
835
836
  return /* @__PURE__ */ jsx(InspectableRegistryContext.Provider, { value, children });
836
837
  }
838
+ function getChildrenBounds(el) {
839
+ const children = el.children;
840
+ if (children.length === 0) return null;
841
+ let top = Infinity, left = Infinity, bottom = -Infinity, right = -Infinity;
842
+ for (let i = 0; i < children.length; i++) {
843
+ const r = children[i].getBoundingClientRect();
844
+ if (r.width === 0 && r.height === 0) continue;
845
+ top = Math.min(top, r.top);
846
+ left = Math.min(left, r.left);
847
+ bottom = Math.max(bottom, r.bottom);
848
+ right = Math.max(right, r.right);
849
+ }
850
+ if (top === Infinity) return null;
851
+ return new DOMRect(left, top, right - left, bottom - top);
852
+ }
837
853
  function Inspectable({
838
854
  label,
839
855
  currentSource = "unknown",
@@ -843,81 +859,103 @@ function Inspectable({
843
859
  }) {
844
860
  const registry = useContext(InspectableRegistryContext);
845
861
  const id = useId();
846
- const ref = useRef(null);
862
+ const wrapperRef = useRef(null);
863
+ const [rect, setRect] = useState(null);
864
+ const registryRef = useRef(registry);
865
+ registryRef.current = registry;
847
866
  const inferredColumns = columns ?? (data?.[0] ? Object.keys(data[0]) : []);
848
867
  const sampleValues = data?.slice(0, 3) ?? [];
868
+ const columnsKey = inferredColumns.join(",");
849
869
  useEffect(() => {
850
- if (!registry) return;
851
- registry.register({
870
+ const reg = registryRef.current;
871
+ if (!reg) return;
872
+ reg.register({
852
873
  id,
853
874
  label,
854
875
  currentSource,
855
- columns: inferredColumns,
876
+ columns: columnsKey.split(",").filter(Boolean),
856
877
  sampleValues,
857
- element: ref.current
878
+ element: wrapperRef.current
858
879
  });
859
- return () => registry.unregister(id);
860
- }, [id, label, currentSource, inferredColumns.join(","), registry]);
880
+ return () => reg.unregister(id);
881
+ }, [id, label, currentSource, columnsKey]);
882
+ const inspectActive = registry?.inspectActive ?? false;
883
+ useEffect(() => {
884
+ if (!inspectActive || !wrapperRef.current) {
885
+ setRect(null);
886
+ return;
887
+ }
888
+ const measure = () => {
889
+ if (wrapperRef.current) {
890
+ setRect(getChildrenBounds(wrapperRef.current));
891
+ }
892
+ };
893
+ measure();
894
+ window.addEventListener("scroll", measure, true);
895
+ window.addEventListener("resize", measure);
896
+ const interval = setInterval(measure, 300);
897
+ return () => {
898
+ window.removeEventListener("scroll", measure, true);
899
+ window.removeEventListener("resize", measure);
900
+ clearInterval(interval);
901
+ };
902
+ }, [inspectActive]);
861
903
  if (!registry) {
862
904
  return /* @__PURE__ */ jsx(Fragment, { children });
863
905
  }
864
906
  const isSelected = registry.selectedId === id;
865
- const inspecting = registry.inspectActive;
866
907
  const handleClick = (e) => {
867
908
  e.stopPropagation();
868
909
  e.preventDefault();
869
910
  registry.setSelectedId(isSelected ? null : id);
870
911
  };
871
- if (!inspecting) {
872
- return /* @__PURE__ */ jsx("div", { ref, children });
873
- }
874
- return /* @__PURE__ */ jsxs(
875
- "div",
876
- {
877
- ref,
878
- style: { position: "relative" },
879
- children: [
880
- children,
881
- /* @__PURE__ */ jsx(
882
- "div",
883
- {
884
- onClick: handleClick,
885
- style: {
886
- position: "absolute",
887
- inset: 0,
888
- zIndex: 9999,
889
- cursor: "pointer",
890
- outline: isSelected ? "2px solid #3b82f6" : "2px dashed #93c5fd",
891
- outlineOffset: 2,
892
- borderRadius: 4,
893
- transition: "outline 0.15s ease",
894
- background: isSelected ? "rgba(59,130,246,0.05)" : "transparent"
895
- },
896
- children: /* @__PURE__ */ jsx(
897
- "div",
898
- {
899
- style: {
900
- position: "absolute",
901
- top: -10,
902
- left: 4,
903
- fontSize: 10,
904
- fontWeight: 600,
905
- fontFamily: "system-ui, -apple-system, sans-serif",
906
- color: "#fff",
907
- backgroundColor: isSelected ? "#3b82f6" : "#93c5fd",
908
- padding: "1px 6px",
909
- borderRadius: 3,
910
- pointerEvents: "none",
911
- whiteSpace: "nowrap"
912
- },
913
- children: label
914
- }
915
- )
916
- }
917
- )
918
- ]
919
- }
920
- );
912
+ return /* @__PURE__ */ jsxs("div", { ref: wrapperRef, style: { display: "contents" }, children: [
913
+ children,
914
+ registry.inspectActive && rect && createPortal(
915
+ /* @__PURE__ */ jsx(
916
+ "div",
917
+ {
918
+ onClick: handleClick,
919
+ style: {
920
+ position: "fixed",
921
+ top: rect.top,
922
+ left: rect.left,
923
+ width: rect.width,
924
+ height: rect.height,
925
+ zIndex: 9999,
926
+ cursor: "pointer",
927
+ outline: isSelected ? "2px solid #3b82f6" : "2px dashed #93c5fd",
928
+ outlineOffset: 2,
929
+ borderRadius: 4,
930
+ transition: "outline 0.15s ease",
931
+ background: isSelected ? "rgba(59,130,246,0.05)" : "transparent",
932
+ pointerEvents: "auto"
933
+ },
934
+ children: /* @__PURE__ */ jsx(
935
+ "div",
936
+ {
937
+ style: {
938
+ position: "absolute",
939
+ top: -10,
940
+ left: 4,
941
+ fontSize: 10,
942
+ fontWeight: 600,
943
+ fontFamily: "system-ui, -apple-system, sans-serif",
944
+ color: "#fff",
945
+ backgroundColor: isSelected ? "#3b82f6" : "#93c5fd",
946
+ padding: "1px 6px",
947
+ borderRadius: 3,
948
+ pointerEvents: "none",
949
+ whiteSpace: "nowrap"
950
+ },
951
+ children: label
952
+ }
953
+ )
954
+ }
955
+ ),
956
+ document.body
957
+ )
958
+ ] });
921
959
  }
922
960
 
923
961
  // src/components/field-matcher.ts