gap-inspector 0.1.0 → 0.2.0
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.
- package/dist/index.js +62 -5
- package/dist/measurement.js +7 -2
- package/dist/styles.d.ts +1 -1
- package/dist/styles.js +15 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useRef, useState } from "react";
|
|
2
|
+
import { useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
3
3
|
import { createPortal } from "react-dom";
|
|
4
4
|
import { inferAxis, inspectPoint, measureGap, resolveSelector } from "./measurement";
|
|
5
5
|
import { gapInspectorStyles } from "./styles";
|
|
@@ -22,6 +22,52 @@ export function GapInspector({ initiallyOpen = false, onMeasure }) {
|
|
|
22
22
|
useEffect(() => {
|
|
23
23
|
setHover(null);
|
|
24
24
|
}, [measurement]);
|
|
25
|
+
const panelHeightAnimRef = useRef(null);
|
|
26
|
+
const lastPanelHeightRef = useRef(null);
|
|
27
|
+
const closingSizeRef = useRef(null);
|
|
28
|
+
// The panel's height is auto, so CSS transitions can't animate content swaps
|
|
29
|
+
// (empty ↔ report ↔ point inspection). FLIP it instead: animate from the last
|
|
30
|
+
// rendered height (or the mid-flight height if interrupted) to the new one.
|
|
31
|
+
useLayoutEffect(() => {
|
|
32
|
+
const panel = panelRef.current;
|
|
33
|
+
if (!panel) {
|
|
34
|
+
panelHeightAnimRef.current = null;
|
|
35
|
+
lastPanelHeightRef.current = null;
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const previousAnim = panelHeightAnimRef.current;
|
|
39
|
+
const inFlight = previousAnim && previousAnim.playState === "running"
|
|
40
|
+
? panel.getBoundingClientRect().height
|
|
41
|
+
: null;
|
|
42
|
+
previousAnim?.cancel();
|
|
43
|
+
const natural = panel.offsetHeight;
|
|
44
|
+
const from = inFlight ?? lastPanelHeightRef.current;
|
|
45
|
+
lastPanelHeightRef.current = natural;
|
|
46
|
+
if (from === null ||
|
|
47
|
+
Math.abs(from - natural) < 1 ||
|
|
48
|
+
window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
panelHeightAnimRef.current = panel.animate([{ height: `${from}px` }, { height: `${natural}px` }], { duration: 260, easing: "cubic-bezier(0.32, 0.72, 0, 1)" });
|
|
52
|
+
}, [open, measurement, pointInspection]);
|
|
53
|
+
// Closing morph: the pill appears at the panel's anchor corner, so animate it
|
|
54
|
+
// from the panel's last size down to its own — one element shrinking into the
|
|
55
|
+
// pill, not two distinct elements swapping.
|
|
56
|
+
useLayoutEffect(() => {
|
|
57
|
+
const launcher = launcherRef.current;
|
|
58
|
+
const fromSize = closingSizeRef.current;
|
|
59
|
+
closingSizeRef.current = null;
|
|
60
|
+
if (open ||
|
|
61
|
+
!launcher ||
|
|
62
|
+
!fromSize ||
|
|
63
|
+
window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
launcher.animate([
|
|
67
|
+
{ width: `${fromSize.width}px`, height: `${fromSize.height}px`, borderRadius: "14px" },
|
|
68
|
+
{ width: `${launcher.offsetWidth}px`, height: `${launcher.offsetHeight}px`, borderRadius: "10px" }
|
|
69
|
+
], { duration: 240, easing: "cubic-bezier(0.32, 0.72, 0, 1)" });
|
|
70
|
+
}, [open]);
|
|
25
71
|
const activeAxis = drag ? inferAxis(drag.start, drag.end) : "horizontal";
|
|
26
72
|
// Computed in pointer handlers (not during render): measureGap reads layout,
|
|
27
73
|
// and the boundary-scan fallback is skipped so dragging stays cheap on big pages.
|
|
@@ -218,7 +264,13 @@ export function GapInspector({ initiallyOpen = false, onMeasure }) {
|
|
|
218
264
|
? null
|
|
219
265
|
: createPortal(_jsx(MeasurementOverlay, { drag: drag, axis: activeAxis, measurement: measurement, pointInspection: pointInspection, preview: preview, hover: hover }), document.body), _jsxs("section", { className: "gi-panel", "aria-label": "Gap Inspector", ref: panelRef, style: panelPosition
|
|
220
266
|
? { left: panelPosition.x, top: panelPosition.y, right: "auto", bottom: "auto" }
|
|
221
|
-
: undefined, children: [_jsxs("div", { className: "gi-body", children: [_jsxs("div", { className: "gi-header", onPointerDown: (event) => beginInspectorDrag(event, panelRef.current), onPointerMove: updateInspectorDrag, onPointerUp: endInspectorDrag, onPointerCancel: endInspectorDrag, children: [_jsx("div", { className: "gi-title", children: "Gap Inspector" }), _jsx("button", { className: "gi-close", type: "button", "aria-label": "Close Gap Inspector", onClick: () =>
|
|
267
|
+
: undefined, children: [_jsxs("div", { className: "gi-body", children: [_jsxs("div", { className: "gi-header", onPointerDown: (event) => beginInspectorDrag(event, panelRef.current), onPointerMove: updateInspectorDrag, onPointerUp: endInspectorDrag, onPointerCancel: endInspectorDrag, children: [_jsx("div", { className: "gi-title", children: "Gap Inspector" }), _jsx("button", { className: "gi-close", type: "button", "aria-label": "Close Gap Inspector", onClick: () => {
|
|
268
|
+
const panel = panelRef.current;
|
|
269
|
+
if (panel) {
|
|
270
|
+
closingSizeRef.current = { width: panel.offsetWidth, height: panel.offsetHeight };
|
|
271
|
+
}
|
|
272
|
+
setOpen(false);
|
|
273
|
+
}, children: _jsx("svg", { width: "12", height: "12", viewBox: "0 0 12 12", "aria-hidden": "true", children: _jsx("path", { d: "M3 3l6 6M9 3l-6 6", stroke: "currentColor", strokeWidth: "1.4", strokeLinecap: "round" }) }) })] }), _jsx("div", { className: "gi-content", children: measurement ? (_jsx(Report, { measurement: measurement, hover: hover, onHover: setHover })) : pointInspection ? (_jsx(PointReport, { inspection: pointInspection })) : (_jsxs("div", { className: "gi-empty", children: [_jsx("p", { children: "Draw a line between two rendered edges to measure the gap and see which CSS declarations produce it. Click once to inspect a point." }), _jsxs("div", { className: "gi-hint", children: [_jsx("span", { className: "gi-kbd", children: "\u2325" }), _jsx("span", { children: "Hold Alt to interact with the page underneath." })] })] })) })] }), measurement || pointInspection ? (_jsxs("div", { className: "gi-footer", children: [_jsx("button", { className: "gi-ghost", type: "button", onClick: () => {
|
|
222
274
|
setMeasurement(null);
|
|
223
275
|
setPointInspection(null);
|
|
224
276
|
}, children: "Clear" }), _jsx("button", { className: "gi-primary", "data-state": copyState, type: "button", onClick: copyMeasurement, children: copyState === "copied" ? "Copied" : copyState === "failed" ? "Failed" : "Copy report" })] })) : null] })] }));
|
|
@@ -869,10 +921,15 @@ function lineFromDrag(axis, drag) {
|
|
|
869
921
|
};
|
|
870
922
|
}
|
|
871
923
|
function formatPx(value) {
|
|
872
|
-
const rounded =
|
|
873
|
-
return `${Number.isInteger(rounded) ? rounded : rounded.toFixed(
|
|
924
|
+
const rounded = roundPx(value);
|
|
925
|
+
return `${Number.isInteger(rounded) ? rounded : rounded.toFixed(1)}px`;
|
|
874
926
|
}
|
|
875
927
|
function roundPx(value) {
|
|
876
|
-
|
|
928
|
+
const nearest = Math.round(value);
|
|
929
|
+
// Snap subpixel rendering noise (7.992px at fractional DPRs/zoom) to the integer.
|
|
930
|
+
if (Math.abs(value - nearest) < 0.15) {
|
|
931
|
+
return nearest;
|
|
932
|
+
}
|
|
933
|
+
return Math.round(value * 10) / 10;
|
|
877
934
|
}
|
|
878
935
|
export { inferAxis, measureGap };
|
package/dist/measurement.js
CHANGED
|
@@ -1192,11 +1192,16 @@ function positivePx(value) {
|
|
|
1192
1192
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
|
|
1193
1193
|
}
|
|
1194
1194
|
function roundPx(value) {
|
|
1195
|
-
|
|
1195
|
+
const nearest = Math.round(value);
|
|
1196
|
+
// Snap subpixel rendering noise (7.992px at fractional DPRs/zoom) to the integer.
|
|
1197
|
+
if (Math.abs(value - nearest) < 0.15) {
|
|
1198
|
+
return nearest;
|
|
1199
|
+
}
|
|
1200
|
+
return Math.round(value * 10) / 10;
|
|
1196
1201
|
}
|
|
1197
1202
|
function formatPx(value) {
|
|
1198
1203
|
const rounded = roundPx(value);
|
|
1199
|
-
return `${Number.isInteger(rounded) ? rounded : rounded.toFixed(
|
|
1204
|
+
return `${Number.isInteger(rounded) ? rounded : rounded.toFixed(1)}px`;
|
|
1200
1205
|
}
|
|
1201
1206
|
function cssPropertyName(property) {
|
|
1202
1207
|
return property.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
|
package/dist/styles.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const gapInspectorStyles = "\n.gi-root,\n.gi-svg {\n --gi-chrome: #131313;\n --gi-surface: #1a1a1a;\n --gi-well: #0d0d0d;\n --gi-text: #f7f7f7;\n --gi-text-secondary: #c2c6cc;\n --gi-text-muted: #8a9099;\n --gi-hairline: rgba(255, 255, 255, 0.09);\n --gi-hairline-soft: rgba(255, 255, 255, 0.05);\n --gi-accent: #12a0f0;\n --gi-danger: #f04438;\n --gi-amber: #f5a623;\n --gi-margin: #f5a623;\n --gi-padding: #4ade80;\n --gi-border-kind: #f87171;\n --gi-scrollbar: #2dd4bf;\n --gi-gap-kind: #a78bfa;\n --gi-layout: #9ba1a8;\n --gi-content: #12a0f0;\n --gi-unknown: #ec4899;\n --gi-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.06),\n 0 1px 2px rgba(0, 0, 0, 0.6),\n 0 32px 70px -16px rgba(0, 0, 0, 0.75);\n --gi-font: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Inter\", sans-serif;\n --gi-mono: ui-monospace, \"SF Mono\", \"JetBrains Mono\", Menlo, Consolas, monospace;\n}\n\n.gi-root {\n color: var(--gi-text);\n font-family: var(--gi-font);\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n font-synthesis: none;\n position: fixed;\n inset: 0;\n z-index: 2147483647;\n pointer-events: none;\n}\n\n.gi-button {\n align-items: center;\n background: var(--gi-chrome);\n border: 1px solid var(--gi-hairline);\n border-radius: 10px;\n bottom: 18px;\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.06),\n 0 1px 2px rgba(0, 0, 0, 0.6),\n 0 12px 32px -8px rgba(0, 0, 0, 0.6);\n color: var(--gi-text);\n cursor: pointer;\n display: inline-flex;\n font: inherit;\n font-size: 12.5px;\n font-weight: 500;\n gap: 8px;\n height: 34px;\n padding: 0 14px;\n pointer-events: auto;\n position: fixed;\n right: 18px;\n touch-action: none;\n transition: border-color 120ms ease, background-color 120ms ease;\n}\n\n.gi-button:hover {\n background: #181818;\n border-color: rgba(255, 255, 255, 0.16);\n}\n\n.gi-button-mark {\n background: var(--gi-accent);\n border-radius: 999px;\n box-shadow: 0 0 8px rgba(18, 160, 240, 0.8);\n display: inline-block;\n height: 6px;\n width: 6px;\n}\n\n.gi-panel {\n background: var(--gi-chrome);\n border-radius: 14px;\n bottom: 18px;\n box-shadow: var(--gi-shadow);\n display: flex;\n flex-direction: column;\n max-height: min(560px, calc(100vh - 36px));\n overflow: clip;\n padding: 4px;\n pointer-events: auto;\n position: fixed;\n right: 18px;\n width: min(400px, calc(100vw - 36px));\n}\n\n.gi-body {\n background: var(--gi-surface);\n border: 1px solid var(--gi-hairline);\n border-radius: 10px;\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow: clip;\n}\n\n.gi-header {\n align-items: center;\n border-bottom: 1px solid var(--gi-hairline-soft);\n cursor: grab;\n display: flex;\n flex-shrink: 0;\n justify-content: space-between;\n padding: 11px 11px 11px 14px;\n touch-action: none;\n user-select: none;\n}\n\n.gi-header:active {\n cursor: grabbing;\n}\n\n.gi-header .gi-close {\n cursor: pointer;\n}\n\n.gi-title {\n font-size: 13px;\n font-weight: 600;\n letter-spacing: -0.01em;\n line-height: 16px;\n}\n\n.gi-close {\n align-items: center;\n appearance: none;\n background: transparent;\n border: 1px solid transparent;\n border-radius: 7px;\n color: var(--gi-text-muted);\n cursor: pointer;\n display: inline-flex;\n height: 24px;\n justify-content: center;\n padding: 0;\n transition: background-color 120ms ease, color 120ms ease, border-color 120ms ease;\n width: 24px;\n}\n\n.gi-close:hover {\n background: rgba(255, 255, 255, 0.06);\n border-color: var(--gi-hairline);\n color: var(--gi-text-secondary);\n}\n\n.gi-content {\n display: flex;\n flex-direction: column;\n gap: 12px;\n min-height: 0;\n overflow-y: auto;\n padding: 14px;\n}\n\n.gi-content::-webkit-scrollbar {\n width: 8px;\n}\n\n.gi-content::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.12);\n background-clip: padding-box;\n border: 2px solid transparent;\n border-radius: 999px;\n}\n\n.gi-empty {\n color: var(--gi-text-muted);\n display: flex;\n flex-direction: column;\n font-size: 12.5px;\n gap: 12px;\n line-height: 1.55;\n}\n\n.gi-empty p {\n margin: 0;\n}\n\n.gi-hint {\n align-items: center;\n color: var(--gi-text-muted);\n display: flex;\n font-size: 12px;\n gap: 8px;\n}\n\n.gi-kbd {\n align-items: center;\n background: var(--gi-well);\n border: 1px solid var(--gi-hairline);\n border-radius: 5px;\n color: var(--gi-text-secondary);\n display: inline-flex;\n flex-shrink: 0;\n font-size: 11px;\n height: 18px;\n justify-content: center;\n line-height: 1;\n min-width: 18px;\n padding: 0 4px;\n}\n\n.gi-footer {\n align-items: center;\n display: flex;\n flex-shrink: 0;\n gap: 8px;\n justify-content: flex-end;\n padding: 8px 6px 4px;\n}\n\n.gi-ghost,\n.gi-primary {\n appearance: none;\n border: 0;\n border-radius: 8px;\n cursor: pointer;\n font: inherit;\n font-size: 12.5px;\n line-height: 16px;\n padding: 7px 12px;\n transition: background-color 120ms ease, filter 120ms ease;\n}\n\n.gi-ghost {\n background: transparent;\n color: var(--gi-text-secondary);\n font-weight: 500;\n}\n\n.gi-ghost:hover {\n background: rgba(255, 255, 255, 0.06);\n}\n\n.gi-primary {\n background: var(--gi-accent);\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.24),\n 0 1px 2px rgba(0, 0, 0, 0.45);\n color: #ffffff;\n font-weight: 600;\n}\n\n.gi-primary:hover {\n filter: brightness(1.08);\n}\n\n.gi-primary[data-state=\"failed\"] {\n background: var(--gi-danger);\n}\n\n.gi-report-title {\n align-items: baseline;\n display: flex;\n gap: 7px;\n}\n\n.gi-metric {\n color: var(--gi-kind-color, var(--gi-text));\n font-family: var(--gi-mono);\n font-size: 18px;\n font-variant-numeric: tabular-nums;\n font-weight: 600;\n letter-spacing: -0.02em;\n line-height: 22px;\n}\n\n.gi-metric-axis {\n color: var(--gi-text-muted);\n font-size: 12px;\n font-weight: 500;\n}\n\n.gi-bar {\n display: flex;\n gap: 2px;\n height: 14px;\n}\n\n.gi-bar-segment {\n background: var(--gi-kind-color, var(--gi-layout));\n background-clip: padding-box;\n border-block: 4px solid transparent;\n border-radius: 6px;\n box-sizing: border-box;\n flex-basis: 0;\n min-width: 3px;\n}\n\n.gi-bar-segment:hover {\n filter: brightness(1.25);\n}\n\n.gi-bar-unattributed {\n background: repeating-linear-gradient(\n 135deg,\n rgba(255, 255, 255, 0.28) 0 2px,\n rgba(255, 255, 255, 0.08) 2px 5px\n );\n}\n\n.gi-equation {\n background: var(--gi-well);\n border: 1px solid var(--gi-hairline);\n border-radius: 9px;\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.4);\n color: var(--gi-text);\n font-family: var(--gi-mono);\n font-size: 11.5px;\n font-variant-numeric: tabular-nums;\n line-height: 1.6;\n overflow-wrap: anywhere;\n padding: 9px 11px;\n}\n\n.gi-caps {\n color: var(--gi-text-muted);\n font-size: 10px;\n font-weight: 600;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n}\n\n.gi-contribs {\n display: flex;\n flex-direction: column;\n}\n\n.gi-contribs .gi-caps {\n margin-bottom: 2px;\n}\n\n.gi-contrib {\n display: flex;\n flex-direction: column;\n gap: 4px;\n padding: 9px 1px;\n}\n\n.gi-contrib + .gi-contrib {\n border-top: 1px solid var(--gi-hairline-soft);\n}\n\n.gi-contrib:hover {\n background: rgba(255, 255, 255, 0.03);\n}\n\n.gi-contrib-row {\n align-items: center;\n display: flex;\n gap: 8px;\n}\n\n.gi-kind-label {\n background: color-mix(in srgb, var(--gi-kind-color) 15%, transparent);\n border-radius: 5px;\n color: var(--gi-kind-color);\n flex-shrink: 0;\n font-size: 10px;\n font-weight: 600;\n letter-spacing: 0.04em;\n line-height: 1;\n padding: 4px 6px;\n text-transform: uppercase;\n}\n\n.gi-contrib-prop {\n color: var(--gi-text);\n flex: 1;\n font-size: 12px;\n font-weight: 500;\n min-width: 0;\n overflow-wrap: anywhere;\n}\n\n.gi-contrib-css {\n color: var(--gi-text-muted);\n font-family: var(--gi-mono);\n font-size: 11px;\n font-weight: 400;\n}\n\n.gi-contrib-value {\n color: var(--gi-text);\n flex-shrink: 0;\n font-family: var(--gi-mono);\n font-size: 12px;\n font-variant-numeric: tabular-nums;\n font-weight: 600;\n margin-left: auto;\n}\n\n.gi-contrib-note {\n color: var(--gi-text-muted);\n font-size: 11.5px;\n line-height: 1.5;\n}\n\n.gi-warning {\n background: color-mix(in srgb, var(--gi-amber) 9%, transparent);\n border: 1px solid color-mix(in srgb, var(--gi-amber) 28%, transparent);\n border-radius: 9px;\n color: #f2c069;\n font-size: 11.5px;\n line-height: 1.55;\n padding: 8px 11px;\n}\n\n.gi-hovercard {\n background: var(--gi-surface);\n border: 1px solid var(--gi-hairline);\n border-radius: 10px;\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.06),\n 0 8px 24px rgba(0, 0, 0, 0.55);\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 10px 11px;\n pointer-events: none;\n position: fixed;\n z-index: 10;\n}\n\n.gi-hovercard-row {\n align-items: center;\n display: flex;\n gap: 8px;\n}\n\n.gi-hovercard-prop {\n color: var(--gi-text);\n flex: 1;\n font-size: 12px;\n font-weight: 500;\n min-width: 0;\n overflow-wrap: anywhere;\n}\n\n.gi-hovercard-value {\n color: var(--gi-text);\n flex-shrink: 0;\n font-family: var(--gi-mono);\n font-size: 12px;\n font-variant-numeric: tabular-nums;\n font-weight: 600;\n}\n\n.gi-hovercard-selector {\n color: #dfe2e6;\n font-family: var(--gi-mono);\n font-size: 10.5px;\n line-height: 1.5;\n overflow-wrap: anywhere;\n}\n\n.gi-hovercard-meta {\n color: var(--gi-text-muted);\n font-family: var(--gi-mono);\n font-size: 10.5px;\n}\n\n.gi-hovercard-note {\n color: var(--gi-text-muted);\n font-size: 11px;\n line-height: 1.5;\n}\n\n.gi-canvas {\n cursor: crosshair;\n inset: 0;\n pointer-events: auto;\n position: fixed;\n touch-action: none;\n}\n\n.gi-canvas[data-passthrough=\"true\"] {\n pointer-events: none;\n}\n\n.gi-svg {\n left: 0;\n overflow: visible;\n pointer-events: none;\n position: absolute;\n top: 0;\n z-index: 2147483646;\n}\n\n.gi-line {\n stroke: var(--gi-accent);\n stroke-dasharray: 5 5;\n stroke-linecap: round;\n stroke-width: 1.5;\n}\n\n.gi-gap-band {\n fill: rgba(18, 160, 240, 0.16);\n stroke: rgba(18, 160, 240, 0.8);\n stroke-width: 1;\n}\n\n.gi-preview-gap {\n fill: rgba(18, 160, 240, 0.1);\n stroke-dasharray: 4 4;\n}\n\n.gi-element-box {\n fill: rgba(18, 160, 240, 0.06);\n stroke: rgba(18, 160, 240, 0.85);\n stroke-width: 1;\n}\n\n.gi-preview-box {\n fill: rgba(18, 160, 240, 0.03);\n stroke-dasharray: 7 4;\n}\n\n.gi-contributor-box {\n fill: color-mix(in srgb, var(--gi-kind-color) 38%, transparent);\n stroke: color-mix(in srgb, var(--gi-kind-color) 85%, transparent);\n stroke-width: 1;\n}\n\n.gi-preview-contributor {\n opacity: 0.62;\n}\n\n.gi-series-box {\n fill: color-mix(in srgb, var(--gi-kind-color) 5%, transparent);\n opacity: 0.34;\n stroke: var(--gi-kind-color);\n stroke-dasharray: 2 6;\n stroke-width: 1;\n}\n\n.gi-preview-series {\n opacity: 0.2;\n}\n\n.gi-edge-marker {\n fill: var(--gi-accent);\n stroke: none;\n}\n\n.gi-preview-edge {\n fill: rgba(18, 160, 240, 0.85);\n}\n\n.gi-from-edge {\n opacity: 0.92;\n}\n\n.gi-to-edge {\n opacity: 0.92;\n}\n\n.gi-kind-margin {\n --gi-kind-color: var(--gi-margin);\n}\n\n.gi-kind-padding {\n --gi-kind-color: var(--gi-padding);\n}\n\n.gi-kind-border {\n --gi-kind-color: var(--gi-border-kind);\n}\n\n.gi-kind-scrollbar {\n --gi-kind-color: var(--gi-scrollbar);\n}\n\n.gi-kind-gap {\n --gi-kind-color: var(--gi-gap-kind);\n}\n\n.gi-kind-layout {\n --gi-kind-color: var(--gi-layout);\n}\n\n.gi-kind-content {\n --gi-kind-color: var(--gi-content);\n}\n\n.gi-kind-unknown {\n --gi-kind-color: var(--gi-unknown);\n}\n\n.gi-hover-box {\n fill: color-mix(in srgb, var(--gi-kind-color) 35%, transparent);\n stroke: var(--gi-kind-color);\n stroke-width: 1.5;\n}\n\n.gi-point-region {\n fill: color-mix(in srgb, var(--gi-kind-color) 20%, transparent);\n stroke: var(--gi-kind-color);\n stroke-dasharray: 5 3;\n stroke-width: 1.5;\n}\n\n.gi-point-dot {\n fill: var(--gi-kind-color);\n stroke: #131313;\n stroke-width: 2;\n}\n";
|
|
1
|
+
export declare const gapInspectorStyles = "\n.gi-root,\n.gi-svg {\n --gi-chrome: #131313;\n --gi-surface: #1a1a1a;\n --gi-well: #0d0d0d;\n --gi-text: #f7f7f7;\n --gi-text-secondary: #c2c6cc;\n --gi-text-muted: #8a9099;\n --gi-hairline: rgba(255, 255, 255, 0.09);\n --gi-hairline-soft: rgba(255, 255, 255, 0.05);\n --gi-accent: #12a0f0;\n --gi-danger: #f04438;\n --gi-amber: #f5a623;\n --gi-margin: #f5a623;\n --gi-padding: #4ade80;\n --gi-border-kind: #f87171;\n --gi-scrollbar: #2dd4bf;\n --gi-gap-kind: #a78bfa;\n --gi-layout: #9ba1a8;\n --gi-content: #12a0f0;\n --gi-unknown: #ec4899;\n --gi-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.06),\n 0 1px 2px rgba(0, 0, 0, 0.6),\n 0 32px 70px -16px rgba(0, 0, 0, 0.75);\n --gi-font: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Inter\", sans-serif;\n --gi-mono: ui-monospace, \"SF Mono\", \"JetBrains Mono\", Menlo, Consolas, monospace;\n}\n\n.gi-root {\n color: var(--gi-text);\n font-family: var(--gi-font);\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n font-synthesis: none;\n position: fixed;\n inset: 0;\n z-index: 2147483647;\n pointer-events: none;\n}\n\n.gi-button {\n align-items: center;\n background: var(--gi-chrome);\n border: 1px solid var(--gi-hairline);\n border-radius: 10px;\n bottom: 18px;\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.06),\n 0 1px 2px rgba(0, 0, 0, 0.6),\n 0 12px 32px -8px rgba(0, 0, 0, 0.6);\n color: var(--gi-text);\n cursor: pointer;\n display: inline-flex;\n font: inherit;\n font-size: 12.5px;\n font-weight: 500;\n gap: 8px;\n height: 34px;\n overflow: clip;\n padding: 0 14px;\n pointer-events: auto;\n position: fixed;\n right: 18px;\n touch-action: none;\n transition: border-color 120ms ease, background-color 120ms ease;\n white-space: nowrap;\n}\n\n.gi-button:hover {\n background: #181818;\n border-color: rgba(255, 255, 255, 0.16);\n}\n\n.gi-button-mark {\n background: var(--gi-accent);\n border-radius: 999px;\n box-shadow: 0 0 8px rgba(18, 160, 240, 0.8);\n display: inline-block;\n height: 6px;\n width: 6px;\n}\n\n.gi-panel {\n background: var(--gi-chrome);\n border-radius: 14px;\n bottom: 18px;\n box-shadow: var(--gi-shadow);\n display: flex;\n flex-direction: column;\n max-height: min(560px, calc(100vh - 36px));\n overflow: clip;\n padding: 4px;\n pointer-events: auto;\n position: fixed;\n right: 18px;\n width: min(400px, calc(100vw - 36px));\n}\n\n@media (prefers-reduced-motion: no-preference) {\n .gi-panel {\n animation: gi-pop-in 170ms cubic-bezier(0.32, 0.72, 0, 1);\n }\n}\n\n@keyframes gi-pop-in {\n from {\n opacity: 0;\n transform: scale(0.96) translateY(6px);\n }\n}\n\n.gi-body {\n background: var(--gi-surface);\n border: 1px solid var(--gi-hairline);\n border-radius: 10px;\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow: clip;\n}\n\n.gi-header {\n align-items: center;\n border-bottom: 1px solid var(--gi-hairline-soft);\n cursor: grab;\n display: flex;\n flex-shrink: 0;\n justify-content: space-between;\n padding: 11px 11px 11px 14px;\n touch-action: none;\n user-select: none;\n}\n\n.gi-header:active {\n cursor: grabbing;\n}\n\n.gi-header .gi-close {\n cursor: pointer;\n}\n\n.gi-title {\n font-size: 13px;\n font-weight: 600;\n letter-spacing: -0.01em;\n line-height: 16px;\n}\n\n.gi-close {\n align-items: center;\n appearance: none;\n background: transparent;\n border: 1px solid transparent;\n border-radius: 7px;\n color: var(--gi-text-muted);\n cursor: pointer;\n display: inline-flex;\n height: 24px;\n justify-content: center;\n padding: 0;\n transition: background-color 120ms ease, color 120ms ease, border-color 120ms ease;\n width: 24px;\n}\n\n.gi-close:hover {\n background: rgba(255, 255, 255, 0.06);\n border-color: var(--gi-hairline);\n color: var(--gi-text-secondary);\n}\n\n.gi-content {\n display: flex;\n flex-direction: column;\n gap: 12px;\n min-height: 0;\n overflow-y: auto;\n padding: 14px;\n}\n\n.gi-content::-webkit-scrollbar {\n width: 8px;\n}\n\n.gi-content::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.12);\n background-clip: padding-box;\n border: 2px solid transparent;\n border-radius: 999px;\n}\n\n.gi-empty {\n color: var(--gi-text-muted);\n display: flex;\n flex-direction: column;\n font-size: 12.5px;\n gap: 12px;\n line-height: 1.55;\n}\n\n.gi-empty p {\n margin: 0;\n}\n\n.gi-hint {\n align-items: center;\n color: var(--gi-text-muted);\n display: flex;\n font-size: 12px;\n gap: 8px;\n}\n\n.gi-kbd {\n align-items: center;\n background: var(--gi-well);\n border: 1px solid var(--gi-hairline);\n border-radius: 5px;\n color: var(--gi-text-secondary);\n display: inline-flex;\n flex-shrink: 0;\n font-size: 11px;\n height: 18px;\n justify-content: center;\n line-height: 1;\n min-width: 18px;\n padding: 0 4px;\n}\n\n.gi-footer {\n align-items: center;\n display: flex;\n flex-shrink: 0;\n gap: 8px;\n justify-content: flex-end;\n padding: 8px 6px 4px;\n}\n\n.gi-ghost,\n.gi-primary {\n appearance: none;\n border: 0;\n border-radius: 8px;\n cursor: pointer;\n font: inherit;\n font-size: 12.5px;\n line-height: 16px;\n padding: 7px 12px;\n transition: background-color 120ms ease, filter 120ms ease;\n}\n\n.gi-ghost {\n background: transparent;\n color: var(--gi-text-secondary);\n font-weight: 500;\n}\n\n.gi-ghost:hover {\n background: rgba(255, 255, 255, 0.06);\n}\n\n.gi-primary {\n background: var(--gi-accent);\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.24),\n 0 1px 2px rgba(0, 0, 0, 0.45);\n color: #ffffff;\n font-weight: 600;\n}\n\n.gi-primary:hover {\n filter: brightness(1.08);\n}\n\n.gi-primary[data-state=\"failed\"] {\n background: var(--gi-danger);\n}\n\n.gi-report-title {\n align-items: baseline;\n display: flex;\n gap: 7px;\n}\n\n.gi-metric {\n color: var(--gi-kind-color, var(--gi-text));\n font-family: var(--gi-mono);\n font-size: 18px;\n font-variant-numeric: tabular-nums;\n font-weight: 600;\n letter-spacing: -0.02em;\n line-height: 22px;\n}\n\n.gi-metric-axis {\n color: var(--gi-text-muted);\n font-size: 12px;\n font-weight: 500;\n}\n\n.gi-bar {\n display: flex;\n gap: 2px;\n height: 14px;\n}\n\n.gi-bar-segment {\n background: var(--gi-kind-color, var(--gi-layout));\n background-clip: padding-box;\n border-block: 4px solid transparent;\n border-radius: 6px;\n box-sizing: border-box;\n flex-basis: 0;\n min-width: 3px;\n}\n\n.gi-bar-segment:hover {\n filter: brightness(1.25);\n}\n\n.gi-bar-unattributed {\n background: repeating-linear-gradient(\n 135deg,\n rgba(255, 255, 255, 0.28) 0 2px,\n rgba(255, 255, 255, 0.08) 2px 5px\n );\n}\n\n.gi-equation {\n background: var(--gi-well);\n border: 1px solid var(--gi-hairline);\n border-radius: 9px;\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.4);\n color: var(--gi-text);\n font-family: var(--gi-mono);\n font-size: 11.5px;\n font-variant-numeric: tabular-nums;\n line-height: 1.6;\n overflow-wrap: anywhere;\n padding: 9px 11px;\n}\n\n.gi-caps {\n color: var(--gi-text-muted);\n font-size: 10px;\n font-weight: 600;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n}\n\n.gi-contribs {\n display: flex;\n flex-direction: column;\n}\n\n.gi-contribs .gi-caps {\n margin-bottom: 2px;\n}\n\n.gi-contrib {\n display: flex;\n flex-direction: column;\n gap: 4px;\n padding: 9px 1px;\n}\n\n.gi-contrib + .gi-contrib {\n border-top: 1px solid var(--gi-hairline-soft);\n}\n\n.gi-contrib:hover {\n background: rgba(255, 255, 255, 0.03);\n}\n\n.gi-contrib-row {\n align-items: center;\n display: flex;\n gap: 8px;\n}\n\n.gi-kind-label {\n background: color-mix(in srgb, var(--gi-kind-color) 15%, transparent);\n border-radius: 5px;\n color: var(--gi-kind-color);\n flex-shrink: 0;\n font-size: 10px;\n font-weight: 600;\n letter-spacing: 0.04em;\n line-height: 1;\n padding: 4px 6px;\n text-transform: uppercase;\n}\n\n.gi-contrib-prop {\n color: var(--gi-text);\n flex: 1;\n font-size: 12px;\n font-weight: 500;\n min-width: 0;\n overflow-wrap: anywhere;\n}\n\n.gi-contrib-css {\n color: var(--gi-text-muted);\n font-family: var(--gi-mono);\n font-size: 11px;\n font-weight: 400;\n}\n\n.gi-contrib-value {\n color: var(--gi-text);\n flex-shrink: 0;\n font-family: var(--gi-mono);\n font-size: 12px;\n font-variant-numeric: tabular-nums;\n font-weight: 600;\n margin-left: auto;\n}\n\n.gi-contrib-note {\n color: var(--gi-text-muted);\n font-size: 11.5px;\n line-height: 1.5;\n}\n\n.gi-warning {\n background: color-mix(in srgb, var(--gi-amber) 9%, transparent);\n border: 1px solid color-mix(in srgb, var(--gi-amber) 28%, transparent);\n border-radius: 9px;\n color: #f2c069;\n font-size: 11.5px;\n line-height: 1.55;\n padding: 8px 11px;\n}\n\n.gi-hovercard {\n background: var(--gi-surface);\n border: 1px solid var(--gi-hairline);\n border-radius: 10px;\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.06),\n 0 8px 24px rgba(0, 0, 0, 0.55);\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 10px 11px;\n pointer-events: none;\n position: fixed;\n z-index: 10;\n}\n\n.gi-hovercard-row {\n align-items: center;\n display: flex;\n gap: 8px;\n}\n\n.gi-hovercard-prop {\n color: var(--gi-text);\n flex: 1;\n font-size: 12px;\n font-weight: 500;\n min-width: 0;\n overflow-wrap: anywhere;\n}\n\n.gi-hovercard-value {\n color: var(--gi-text);\n flex-shrink: 0;\n font-family: var(--gi-mono);\n font-size: 12px;\n font-variant-numeric: tabular-nums;\n font-weight: 600;\n}\n\n.gi-hovercard-selector {\n color: #dfe2e6;\n font-family: var(--gi-mono);\n font-size: 10.5px;\n line-height: 1.5;\n overflow-wrap: anywhere;\n}\n\n.gi-hovercard-meta {\n color: var(--gi-text-muted);\n font-family: var(--gi-mono);\n font-size: 10.5px;\n}\n\n.gi-hovercard-note {\n color: var(--gi-text-muted);\n font-size: 11px;\n line-height: 1.5;\n}\n\n.gi-canvas {\n cursor: crosshair;\n inset: 0;\n pointer-events: auto;\n position: fixed;\n touch-action: none;\n}\n\n.gi-canvas[data-passthrough=\"true\"] {\n pointer-events: none;\n}\n\n.gi-svg {\n left: 0;\n overflow: visible;\n pointer-events: none;\n position: absolute;\n top: 0;\n z-index: 2147483646;\n}\n\n.gi-line {\n stroke: var(--gi-accent);\n stroke-dasharray: 5 5;\n stroke-linecap: round;\n stroke-width: 1.5;\n}\n\n.gi-gap-band {\n fill: rgba(18, 160, 240, 0.16);\n stroke: rgba(18, 160, 240, 0.8);\n stroke-width: 1;\n}\n\n.gi-preview-gap {\n fill: rgba(18, 160, 240, 0.1);\n stroke-dasharray: 4 4;\n}\n\n.gi-element-box {\n fill: rgba(18, 160, 240, 0.06);\n stroke: rgba(18, 160, 240, 0.85);\n stroke-width: 1;\n}\n\n.gi-preview-box {\n fill: rgba(18, 160, 240, 0.03);\n stroke-dasharray: 7 4;\n}\n\n.gi-contributor-box {\n fill: color-mix(in srgb, var(--gi-kind-color) 38%, transparent);\n stroke: color-mix(in srgb, var(--gi-kind-color) 85%, transparent);\n stroke-width: 1;\n}\n\n.gi-preview-contributor {\n opacity: 0.62;\n}\n\n.gi-series-box {\n fill: color-mix(in srgb, var(--gi-kind-color) 5%, transparent);\n opacity: 0.34;\n stroke: var(--gi-kind-color);\n stroke-dasharray: 2 6;\n stroke-width: 1;\n}\n\n.gi-preview-series {\n opacity: 0.2;\n}\n\n.gi-edge-marker {\n fill: var(--gi-accent);\n stroke: none;\n}\n\n.gi-preview-edge {\n fill: rgba(18, 160, 240, 0.85);\n}\n\n.gi-from-edge {\n opacity: 0.92;\n}\n\n.gi-to-edge {\n opacity: 0.92;\n}\n\n.gi-kind-margin {\n --gi-kind-color: var(--gi-margin);\n}\n\n.gi-kind-padding {\n --gi-kind-color: var(--gi-padding);\n}\n\n.gi-kind-border {\n --gi-kind-color: var(--gi-border-kind);\n}\n\n.gi-kind-scrollbar {\n --gi-kind-color: var(--gi-scrollbar);\n}\n\n.gi-kind-gap {\n --gi-kind-color: var(--gi-gap-kind);\n}\n\n.gi-kind-layout {\n --gi-kind-color: var(--gi-layout);\n}\n\n.gi-kind-content {\n --gi-kind-color: var(--gi-content);\n}\n\n.gi-kind-unknown {\n --gi-kind-color: var(--gi-unknown);\n}\n\n.gi-hover-box {\n fill: color-mix(in srgb, var(--gi-kind-color) 35%, transparent);\n stroke: var(--gi-kind-color);\n stroke-width: 1.5;\n}\n\n.gi-point-region {\n fill: color-mix(in srgb, var(--gi-kind-color) 20%, transparent);\n stroke: var(--gi-kind-color);\n stroke-dasharray: 5 3;\n stroke-width: 1.5;\n}\n\n.gi-point-dot {\n fill: var(--gi-kind-color);\n stroke: #131313;\n stroke-width: 2;\n}\n";
|
package/dist/styles.js
CHANGED
|
@@ -58,12 +58,14 @@ export const gapInspectorStyles = `
|
|
|
58
58
|
font-weight: 500;
|
|
59
59
|
gap: 8px;
|
|
60
60
|
height: 34px;
|
|
61
|
+
overflow: clip;
|
|
61
62
|
padding: 0 14px;
|
|
62
63
|
pointer-events: auto;
|
|
63
64
|
position: fixed;
|
|
64
65
|
right: 18px;
|
|
65
66
|
touch-action: none;
|
|
66
67
|
transition: border-color 120ms ease, background-color 120ms ease;
|
|
68
|
+
white-space: nowrap;
|
|
67
69
|
}
|
|
68
70
|
|
|
69
71
|
.gi-button:hover {
|
|
@@ -96,6 +98,19 @@ export const gapInspectorStyles = `
|
|
|
96
98
|
width: min(400px, calc(100vw - 36px));
|
|
97
99
|
}
|
|
98
100
|
|
|
101
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
102
|
+
.gi-panel {
|
|
103
|
+
animation: gi-pop-in 170ms cubic-bezier(0.32, 0.72, 0, 1);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
@keyframes gi-pop-in {
|
|
108
|
+
from {
|
|
109
|
+
opacity: 0;
|
|
110
|
+
transform: scale(0.96) translateY(6px);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
99
114
|
.gi-body {
|
|
100
115
|
background: var(--gi-surface);
|
|
101
116
|
border: 1px solid var(--gi-hairline);
|
package/package.json
CHANGED