uilint-react 0.1.45 → 0.1.47

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.
@@ -1,16 +1,18 @@
1
1
  "use client";
2
2
  import {
3
3
  BADGE_COLORS,
4
- Badge
5
- } from "./chunk-W42PI2OF.js";
4
+ Badge,
5
+ fetchSource,
6
+ getCachedSource
7
+ } from "./chunk-S4IWHBOQ.js";
6
8
  import {
7
9
  groupBySourceFile,
8
10
  useUILintContext,
9
11
  useUILintStore
10
- } from "./chunk-BJD2V2LF.js";
12
+ } from "./chunk-RAPUZC5J.js";
11
13
 
12
14
  // src/components/ui-lint/UILintToolbar.tsx
13
- import { useState as useState2, useRef as useRef2, useEffect as useEffect2, useCallback as useCallback2 } from "react";
15
+ import React3, { useState as useState2, useRef as useRef2, useEffect as useEffect3, useCallback as useCallback2 } from "react";
14
16
  import { createPortal } from "react-dom";
15
17
 
16
18
  // src/components/ui-lint/toolbar-styles.ts
@@ -228,10 +230,10 @@ function SettingsPopover({ settings }) {
228
230
  }
229
231
 
230
232
  // src/components/ui-lint/ScanPanelStack.tsx
231
- import { useRef, useEffect } from "react";
233
+ import { useRef, useEffect as useEffect2 } from "react";
232
234
 
233
235
  // src/components/ui-lint/ScanResultsPopover.tsx
234
- import { useState, useCallback, useMemo } from "react";
236
+ import { useState, useCallback, useMemo, useEffect } from "react";
235
237
 
236
238
  // src/components/ui-lint/toolbar-icons.tsx
237
239
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
@@ -860,12 +862,65 @@ function ElementRow({ item, onHover, onClick }) {
860
862
  }
861
863
  );
862
864
  }
865
+ function extractTagName(line, column) {
866
+ if (!line) return null;
867
+ if (column !== void 0) {
868
+ const searchStart = Math.max(0, column - 50);
869
+ const searchEnd = Math.min(line.length, column + 20);
870
+ const searchSlice = line.substring(searchStart, searchEnd);
871
+ const tagMatches = [
872
+ ...searchSlice.matchAll(/<([a-zA-Z][a-zA-Z0-9.-]*|Fragment)\b/g)
873
+ ];
874
+ for (const match of tagMatches) {
875
+ const tagStart = searchStart + match.index;
876
+ const tagEnd = tagStart + match[0].length;
877
+ if (column >= tagStart && column <= tagEnd + 30) {
878
+ return match[1];
879
+ }
880
+ }
881
+ }
882
+ const trimmed = line.trim();
883
+ const jsxTagMatch = trimmed.match(/^<([a-zA-Z][a-zA-Z0-9.-]*|Fragment)\b/);
884
+ if (jsxTagMatch) {
885
+ return jsxTagMatch[1];
886
+ }
887
+ return null;
888
+ }
863
889
  function FileLevelIssueRow({
864
890
  filePath,
865
891
  issue,
866
892
  onClick
867
893
  }) {
868
894
  const fileName = filePath.split("/").pop() || filePath;
895
+ const [tagName, setTagName] = useState(null);
896
+ useEffect(() => {
897
+ const cached = getCachedSource(filePath);
898
+ if (cached) {
899
+ const lines = cached.content.split("\n");
900
+ const lineIndex = issue.line - 1;
901
+ if (lineIndex >= 0 && lineIndex < lines.length) {
902
+ const line = lines[lineIndex];
903
+ const tag = extractTagName(line, issue.column);
904
+ if (tag) {
905
+ setTagName(tag);
906
+ return;
907
+ }
908
+ }
909
+ }
910
+ fetchSource(filePath).then((result) => {
911
+ if (result) {
912
+ const lines = result.content.split("\n");
913
+ const lineIndex = issue.line - 1;
914
+ if (lineIndex >= 0 && lineIndex < lines.length) {
915
+ const line = lines[lineIndex];
916
+ const tag = extractTagName(line, issue.column);
917
+ if (tag) {
918
+ setTagName(tag);
919
+ }
920
+ }
921
+ }
922
+ });
923
+ }, [filePath, issue.line, issue.column]);
869
924
  return /* @__PURE__ */ jsxs3(
870
925
  "div",
871
926
  {
@@ -896,7 +951,22 @@ function FileLevelIssueRow({
896
951
  marginRight: "12px"
897
952
  },
898
953
  children: [
899
- /* @__PURE__ */ jsx3(
954
+ tagName && /* @__PURE__ */ jsxs3(
955
+ "span",
956
+ {
957
+ style: {
958
+ fontSize: "11px",
959
+ fontFamily: STYLES.fontMono,
960
+ color: STYLES.accent
961
+ },
962
+ children: [
963
+ "<",
964
+ tagName,
965
+ ">"
966
+ ]
967
+ }
968
+ ),
969
+ !tagName && /* @__PURE__ */ jsx3(
900
970
  "span",
901
971
  {
902
972
  style: {
@@ -992,26 +1062,26 @@ function CloseIcon() {
992
1062
  import { jsx as jsx4 } from "react/jsx-runtime";
993
1063
  function ScanPanelStack({ show, onClose }) {
994
1064
  const containerRef = useRef(null);
995
- useEffect(() => {
1065
+ useEffect2(() => {
996
1066
  if (!show) return;
997
1067
  const handleClickOutside = (e) => {
998
1068
  const target = e.target;
1069
+ if (target?.closest?.("[data-ui-lint]")) {
1070
+ return;
1071
+ }
999
1072
  if (containerRef.current && !containerRef.current.contains(target)) {
1000
- const isUILintElement = target.closest?.("[data-ui-lint]");
1001
- if (!isUILintElement) {
1002
- onClose();
1003
- }
1073
+ onClose();
1004
1074
  }
1005
1075
  };
1006
1076
  const timeoutId = setTimeout(() => {
1007
- document.addEventListener("mousedown", handleClickOutside);
1077
+ document.addEventListener("mousedown", handleClickOutside, true);
1008
1078
  }, 100);
1009
1079
  return () => {
1010
1080
  clearTimeout(timeoutId);
1011
- document.removeEventListener("mousedown", handleClickOutside);
1081
+ document.removeEventListener("mousedown", handleClickOutside, true);
1012
1082
  };
1013
1083
  }, [show, onClose]);
1014
- useEffect(() => {
1084
+ useEffect2(() => {
1015
1085
  if (!show) return;
1016
1086
  const handleKeyDown = (e) => {
1017
1087
  if (e.key === "Escape") {
@@ -1021,16 +1091,25 @@ function ScanPanelStack({ show, onClose }) {
1021
1091
  window.addEventListener("keydown", handleKeyDown);
1022
1092
  return () => window.removeEventListener("keydown", handleKeyDown);
1023
1093
  }, [show, onClose]);
1094
+ const handleUILintInteraction = (e) => {
1095
+ e.stopPropagation();
1096
+ };
1024
1097
  if (!show) return null;
1025
1098
  return /* @__PURE__ */ jsx4(
1026
1099
  "div",
1027
1100
  {
1028
1101
  ref: containerRef,
1102
+ "data-ui-lint": true,
1103
+ onMouseDown: handleUILintInteraction,
1104
+ onClick: handleUILintInteraction,
1105
+ onKeyDown: handleUILintInteraction,
1029
1106
  style: {
1030
1107
  position: "absolute",
1031
1108
  bottom: "100%",
1032
1109
  left: 0,
1033
- marginBottom: "8px"
1110
+ marginBottom: "8px",
1111
+ pointerEvents: "auto"
1112
+ // Ensure panel is interactive
1034
1113
  },
1035
1114
  children: /* @__PURE__ */ jsx4(ScanResultsPopover, { onClose })
1036
1115
  }
@@ -1038,10 +1117,10 @@ function ScanPanelStack({ show, onClose }) {
1038
1117
  }
1039
1118
 
1040
1119
  // src/components/ui-lint/UILintToolbar.tsx
1041
- import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1120
+ import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1042
1121
  var TOKENS = {
1043
1122
  // Colors
1044
- bgBase: "rgba(15, 15, 15, 0.85)",
1123
+ bgBase: "rgba(15, 15, 15, 0.92)",
1045
1124
  bgElevated: "rgba(25, 25, 25, 0.95)",
1046
1125
  bgHover: "rgba(255, 255, 255, 0.08)",
1047
1126
  bgActive: "rgba(255, 255, 255, 0.12)",
@@ -1052,26 +1131,17 @@ var TOKENS = {
1052
1131
  textMuted: "rgba(255, 255, 255, 0.4)",
1053
1132
  textDisabled: "rgba(255, 255, 255, 0.25)",
1054
1133
  accent: "#63b3ed",
1055
- // Calm blue
1056
1134
  success: BADGE_COLORS.success,
1057
- // Soft green (shared with Badge)
1058
1135
  warning: BADGE_COLORS.warning,
1059
- // Warm orange (shared with Badge)
1060
- // Typography
1136
+ error: "#f56565",
1061
1137
  fontFamily: `-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif`,
1062
1138
  fontMono: `"SF Mono", Monaco, "Cascadia Code", monospace`,
1063
- // Sizing
1064
- pillHeight: "44px",
1065
- // Touch-friendly
1066
- pillRadius: "22px",
1067
- buttonMinWidth: "44px",
1068
- // Touch target minimum
1069
- // Effects
1070
- blur: "blur(20px)",
1071
- shadowSm: "0 2px 8px rgba(0, 0, 0, 0.3)",
1139
+ pillHeight: "40px",
1140
+ pillRadius: "20px",
1141
+ buttonMinWidth: "40px",
1142
+ blur: "blur(16px)",
1072
1143
  shadowMd: "0 4px 20px rgba(0, 0, 0, 0.4)",
1073
- shadowGlow: (color) => `0 0 20px ${color}`,
1074
- // Animation
1144
+ shadowGlow: (color) => `0 0 16px ${color}`,
1075
1145
  transitionFast: "150ms cubic-bezier(0.4, 0, 0.2, 1)",
1076
1146
  transitionBase: "200ms cubic-bezier(0.4, 0, 0.2, 1)",
1077
1147
  transitionSlow: "300ms cubic-bezier(0.4, 0, 0.2, 1)"
@@ -1080,8 +1150,8 @@ var Icons = {
1080
1150
  Eye: () => /* @__PURE__ */ jsxs4(
1081
1151
  "svg",
1082
1152
  {
1083
- width: "18",
1084
- height: "18",
1153
+ width: "16",
1154
+ height: "16",
1085
1155
  viewBox: "0 0 24 24",
1086
1156
  fill: "none",
1087
1157
  stroke: "currentColor",
@@ -1094,11 +1164,11 @@ var Icons = {
1094
1164
  ]
1095
1165
  }
1096
1166
  ),
1097
- EyeOff: () => /* @__PURE__ */ jsxs4(
1167
+ Settings: () => /* @__PURE__ */ jsxs4(
1098
1168
  "svg",
1099
1169
  {
1100
- width: "18",
1101
- height: "18",
1170
+ width: "15",
1171
+ height: "15",
1102
1172
  viewBox: "0 0 24 24",
1103
1173
  fill: "none",
1104
1174
  stroke: "currentColor",
@@ -1106,16 +1176,30 @@ var Icons = {
1106
1176
  strokeLinecap: "round",
1107
1177
  strokeLinejoin: "round",
1108
1178
  children: [
1109
- /* @__PURE__ */ jsx5("path", { d: "M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24" }),
1110
- /* @__PURE__ */ jsx5("line", { x1: "1", y1: "1", x2: "23", y2: "23" })
1179
+ /* @__PURE__ */ jsx5("circle", { cx: "12", cy: "12", r: "3" }),
1180
+ /* @__PURE__ */ jsx5("path", { d: "M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z" })
1111
1181
  ]
1112
1182
  }
1113
1183
  ),
1114
- Scan: () => /* @__PURE__ */ jsxs4(
1184
+ Check: () => /* @__PURE__ */ jsx5(
1115
1185
  "svg",
1116
1186
  {
1117
- width: "16",
1118
- height: "16",
1187
+ width: "12",
1188
+ height: "12",
1189
+ viewBox: "0 0 24 24",
1190
+ fill: "none",
1191
+ stroke: "currentColor",
1192
+ strokeWidth: "2.5",
1193
+ strokeLinecap: "round",
1194
+ strokeLinejoin: "round",
1195
+ children: /* @__PURE__ */ jsx5("polyline", { points: "20 6 9 17 4 12" })
1196
+ }
1197
+ ),
1198
+ AlertTriangle: () => /* @__PURE__ */ jsxs4(
1199
+ "svg",
1200
+ {
1201
+ width: "12",
1202
+ height: "12",
1119
1203
  viewBox: "0 0 24 24",
1120
1204
  fill: "none",
1121
1205
  stroke: "currentColor",
@@ -1123,29 +1207,27 @@ var Icons = {
1123
1207
  strokeLinecap: "round",
1124
1208
  strokeLinejoin: "round",
1125
1209
  children: [
1126
- /* @__PURE__ */ jsx5("path", { d: "M3 7V5a2 2 0 0 1 2-2h2" }),
1127
- /* @__PURE__ */ jsx5("path", { d: "M17 3h2a2 2 0 0 1 2 2v2" }),
1128
- /* @__PURE__ */ jsx5("path", { d: "M21 17v2a2 2 0 0 1-2 2h-2" }),
1129
- /* @__PURE__ */ jsx5("path", { d: "M7 21H5a2 2 0 0 1-2-2v-2" }),
1130
- /* @__PURE__ */ jsx5("line", { x1: "7", y1: "12", x2: "17", y2: "12" })
1210
+ /* @__PURE__ */ jsx5("path", { d: "M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" }),
1211
+ /* @__PURE__ */ jsx5("line", { x1: "12", y1: "9", x2: "12", y2: "13" }),
1212
+ /* @__PURE__ */ jsx5("line", { x1: "12", y1: "17", x2: "12.01", y2: "17" })
1131
1213
  ]
1132
1214
  }
1133
1215
  ),
1134
- Check: () => /* @__PURE__ */ jsx5(
1216
+ ChevronDown: () => /* @__PURE__ */ jsx5(
1135
1217
  "svg",
1136
1218
  {
1137
- width: "14",
1138
- height: "14",
1219
+ width: "12",
1220
+ height: "12",
1139
1221
  viewBox: "0 0 24 24",
1140
1222
  fill: "none",
1141
1223
  stroke: "currentColor",
1142
- strokeWidth: "2.5",
1224
+ strokeWidth: "2",
1143
1225
  strokeLinecap: "round",
1144
1226
  strokeLinejoin: "round",
1145
- children: /* @__PURE__ */ jsx5("polyline", { points: "20 6 9 17 4 12" })
1227
+ children: /* @__PURE__ */ jsx5("polyline", { points: "6 9 12 15 18 9" })
1146
1228
  }
1147
1229
  ),
1148
- AlertTriangle: () => /* @__PURE__ */ jsxs4(
1230
+ X: () => /* @__PURE__ */ jsxs4(
1149
1231
  "svg",
1150
1232
  {
1151
1233
  width: "14",
@@ -1157,17 +1239,16 @@ var Icons = {
1157
1239
  strokeLinecap: "round",
1158
1240
  strokeLinejoin: "round",
1159
1241
  children: [
1160
- /* @__PURE__ */ jsx5("path", { d: "M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" }),
1161
- /* @__PURE__ */ jsx5("line", { x1: "12", y1: "9", x2: "12", y2: "13" }),
1162
- /* @__PURE__ */ jsx5("line", { x1: "12", y1: "17", x2: "12.01", y2: "17" })
1242
+ /* @__PURE__ */ jsx5("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
1243
+ /* @__PURE__ */ jsx5("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
1163
1244
  ]
1164
1245
  }
1165
1246
  ),
1166
- Settings: () => /* @__PURE__ */ jsxs4(
1247
+ Unplug: () => /* @__PURE__ */ jsxs4(
1167
1248
  "svg",
1168
1249
  {
1169
- width: "16",
1170
- height: "16",
1250
+ width: "14",
1251
+ height: "14",
1171
1252
  viewBox: "0 0 24 24",
1172
1253
  fill: "none",
1173
1254
  stroke: "currentColor",
@@ -1175,12 +1256,15 @@ var Icons = {
1175
1256
  strokeLinecap: "round",
1176
1257
  strokeLinejoin: "round",
1177
1258
  children: [
1178
- /* @__PURE__ */ jsx5("circle", { cx: "12", cy: "12", r: "3" }),
1179
- /* @__PURE__ */ jsx5("path", { d: "M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z" })
1259
+ /* @__PURE__ */ jsx5("path", { d: "M19 5l3-3" }),
1260
+ /* @__PURE__ */ jsx5("path", { d: "M2 22l3-3" }),
1261
+ /* @__PURE__ */ jsx5("path", { d: "M6.3 6.3a10 10 0 0 1 13.4 1.3" }),
1262
+ /* @__PURE__ */ jsx5("path", { d: "M17.7 17.7a10 10 0 0 1-13.4-1.3" }),
1263
+ /* @__PURE__ */ jsx5("path", { d: "m8 15 8-8" })
1180
1264
  ]
1181
1265
  }
1182
1266
  ),
1183
- ChevronRight: () => /* @__PURE__ */ jsx5(
1267
+ Scan: () => /* @__PURE__ */ jsxs4(
1184
1268
  "svg",
1185
1269
  {
1186
1270
  width: "14",
@@ -1191,7 +1275,13 @@ var Icons = {
1191
1275
  strokeWidth: "2",
1192
1276
  strokeLinecap: "round",
1193
1277
  strokeLinejoin: "round",
1194
- children: /* @__PURE__ */ jsx5("polyline", { points: "9 18 15 12 9 6" })
1278
+ children: [
1279
+ /* @__PURE__ */ jsx5("path", { d: "M3 7V5a2 2 0 0 1 2-2h2" }),
1280
+ /* @__PURE__ */ jsx5("path", { d: "M17 3h2a2 2 0 0 1 2 2v2" }),
1281
+ /* @__PURE__ */ jsx5("path", { d: "M21 17v2a2 2 0 0 1-2 2h-2" }),
1282
+ /* @__PURE__ */ jsx5("path", { d: "M7 21H5a2 2 0 0 1-2-2v-2" }),
1283
+ /* @__PURE__ */ jsx5("line", { x1: "7", y1: "12", x2: "17", y2: "12" })
1284
+ ]
1195
1285
  }
1196
1286
  )
1197
1287
  };
@@ -1208,101 +1298,72 @@ var globalStyles = `
1208
1298
 
1209
1299
  @keyframes uilint-pulse {
1210
1300
  0%, 100% { opacity: 1; }
1211
- 50% { opacity: 0.5; }
1212
- }
1213
-
1214
- @keyframes uilint-scan-line {
1215
- 0% { transform: translateX(-100%); }
1216
- 100% { transform: translateX(100%); }
1301
+ 50% { opacity: 0.6; }
1217
1302
  }
1218
1303
 
1219
- @keyframes uilint-spin {
1220
- from { transform: rotate(0deg); }
1221
- to { transform: rotate(360deg); }
1304
+ @keyframes uilint-slide-up {
1305
+ from { opacity: 0; transform: translateY(12px); }
1306
+ to { opacity: 1; transform: translateY(0); }
1222
1307
  }
1223
1308
 
1224
- .uilint-toolbar-btn {
1309
+ .uilint-btn {
1225
1310
  display: flex;
1226
1311
  align-items: center;
1227
1312
  justify-content: center;
1313
+ gap: 6px;
1228
1314
  height: 100%;
1315
+ padding: 0 14px;
1229
1316
  border: none;
1230
1317
  background: transparent;
1231
1318
  color: ${TOKENS.textSecondary};
1319
+ font-family: ${TOKENS.fontFamily};
1320
+ font-size: 13px;
1321
+ font-weight: 500;
1232
1322
  cursor: pointer;
1233
1323
  transition:
1234
1324
  background-color ${TOKENS.transitionFast},
1235
- color ${TOKENS.transitionFast},
1236
- transform ${TOKENS.transitionFast};
1325
+ color ${TOKENS.transitionFast};
1237
1326
  outline: none;
1238
- position: relative;
1327
+ white-space: nowrap;
1239
1328
  }
1240
1329
 
1241
- .uilint-toolbar-btn:hover:not(:disabled) {
1330
+ .uilint-btn:hover:not(:disabled) {
1242
1331
  background: ${TOKENS.bgHover};
1243
1332
  color: ${TOKENS.textPrimary};
1244
1333
  }
1245
1334
 
1246
- .uilint-toolbar-btn:active:not(:disabled) {
1335
+ .uilint-btn:active:not(:disabled) {
1247
1336
  background: ${TOKENS.bgActive};
1248
- transform: scale(0.97);
1249
1337
  }
1250
1338
 
1251
- .uilint-toolbar-btn:focus-visible {
1339
+ .uilint-btn:focus-visible {
1252
1340
  box-shadow: inset 0 0 0 2px ${TOKENS.borderFocus};
1253
1341
  }
1254
1342
 
1255
- .uilint-toolbar-btn:disabled {
1343
+ .uilint-btn:disabled {
1256
1344
  cursor: not-allowed;
1257
1345
  color: ${TOKENS.textDisabled};
1258
1346
  }
1259
1347
 
1260
- .uilint-toolbar-btn--active {
1261
- background: ${TOKENS.bgActive} !important;
1262
- color: ${TOKENS.accent} !important;
1263
- }
1264
-
1265
- .uilint-toolbar-btn--warning {
1266
- color: ${TOKENS.warning} !important;
1348
+ .uilint-btn--icon {
1349
+ padding: 0;
1350
+ min-width: ${TOKENS.buttonMinWidth};
1267
1351
  }
1268
1352
 
1269
- .uilint-toolbar-btn--success {
1270
- color: ${TOKENS.success} !important;
1271
- }
1272
-
1273
- .uilint-hint {
1274
- opacity: 0;
1275
- transform: translateY(4px);
1276
- transition:
1277
- opacity ${TOKENS.transitionBase},
1278
- transform ${TOKENS.transitionBase};
1279
- pointer-events: none;
1353
+ .uilint-btn--primary {
1354
+ color: ${TOKENS.textPrimary};
1280
1355
  }
1281
1356
 
1282
- .uilint-hint--visible {
1283
- opacity: 1;
1284
- transform: translateY(0);
1357
+ .uilint-btn--accent {
1358
+ color: ${TOKENS.accent};
1285
1359
  }
1286
1360
 
1287
- .uilint-scanning-indicator {
1288
- position: relative;
1289
- overflow: hidden;
1361
+ .uilint-btn--warning {
1362
+ color: ${TOKENS.warning};
1290
1363
  }
1291
1364
 
1292
- .uilint-scanning-indicator::after {
1293
- content: '';
1294
- position: absolute;
1295
- top: 0;
1296
- left: 0;
1297
- right: 0;
1298
- bottom: 0;
1299
- background: linear-gradient(
1300
- 90deg,
1301
- transparent,
1302
- rgba(99, 179, 237, 0.3),
1303
- transparent
1304
- );
1305
- animation: uilint-scan-line 1.5s ease-in-out infinite;
1365
+ .uilint-btn--success {
1366
+ color: ${TOKENS.success};
1306
1367
  }
1307
1368
 
1308
1369
  .uilint-popover {
@@ -1313,80 +1374,65 @@ var globalStyles = `
1313
1374
  animation: uilint-fade-out ${TOKENS.transitionBase} forwards;
1314
1375
  }
1315
1376
 
1316
- /* Custom scrollbar styling for dark mode - scoped to uilint components */
1317
- [data-ui-lint] *,
1318
- [data-ui-lint] {
1319
- /* Firefox */
1377
+ .uilint-scanning-bar {
1378
+ animation: uilint-slide-up ${TOKENS.transitionSlow} forwards;
1379
+ }
1380
+
1381
+ .uilint-scanning-dot {
1382
+ width: 6px;
1383
+ height: 6px;
1384
+ border-radius: 50%;
1385
+ background: ${TOKENS.accent};
1386
+ animation: uilint-pulse 1.5s ease-in-out infinite;
1387
+ }
1388
+
1389
+ /* Scrollbar styling */
1390
+ [data-ui-lint] * {
1320
1391
  scrollbar-width: thin;
1321
1392
  scrollbar-color: rgba(255, 255, 255, 0.15) rgba(15, 15, 15, 0.3);
1322
1393
  }
1323
1394
 
1324
- /* WebKit browsers (Chrome, Safari, Edge) */
1325
- [data-ui-lint] *::-webkit-scrollbar,
1326
- [data-ui-lint]::-webkit-scrollbar {
1395
+ [data-ui-lint] *::-webkit-scrollbar {
1327
1396
  width: 8px;
1328
1397
  height: 8px;
1329
1398
  }
1330
1399
 
1331
- [data-ui-lint] *::-webkit-scrollbar-track,
1332
- [data-ui-lint]::-webkit-scrollbar-track {
1400
+ [data-ui-lint] *::-webkit-scrollbar-track {
1333
1401
  background: rgba(15, 15, 15, 0.3);
1334
1402
  border-radius: 4px;
1335
1403
  }
1336
1404
 
1337
- [data-ui-lint] *::-webkit-scrollbar-thumb,
1338
- [data-ui-lint]::-webkit-scrollbar-thumb {
1405
+ [data-ui-lint] *::-webkit-scrollbar-thumb {
1339
1406
  background: rgba(255, 255, 255, 0.15);
1340
1407
  border-radius: 4px;
1341
- border: 1px solid rgba(15, 15, 15, 0.2);
1342
- transition: background ${TOKENS.transitionFast};
1343
1408
  }
1344
1409
 
1345
- [data-ui-lint] *::-webkit-scrollbar-thumb:hover,
1346
- [data-ui-lint]::-webkit-scrollbar-thumb:hover {
1410
+ [data-ui-lint] *::-webkit-scrollbar-thumb:hover {
1347
1411
  background: rgba(255, 255, 255, 0.25);
1348
1412
  }
1349
-
1350
- [data-ui-lint] *::-webkit-scrollbar-thumb:active,
1351
- [data-ui-lint]::-webkit-scrollbar-thumb:active {
1352
- background: rgba(255, 255, 255, 0.35);
1353
- }
1354
-
1355
- [data-ui-lint] *::-webkit-scrollbar-corner,
1356
- [data-ui-lint]::-webkit-scrollbar-corner {
1357
- background: rgba(15, 15, 15, 0.3);
1358
- }
1359
1413
  `;
1360
- function ToolbarButton({
1361
- onClick,
1362
- disabled,
1363
- active,
1364
- variant = "default",
1365
- title,
1366
- ariaLabel,
1367
- width = TOKENS.buttonMinWidth,
1368
- children
1369
- }) {
1370
- const classes = [
1371
- "uilint-toolbar-btn",
1372
- active && "uilint-toolbar-btn--active",
1373
- variant === "warning" && "uilint-toolbar-btn--warning",
1374
- variant === "success" && "uilint-toolbar-btn--success"
1375
- ].filter(Boolean).join(" ");
1376
- return /* @__PURE__ */ jsx5(
1377
- "button",
1378
- {
1379
- className: classes,
1380
- onClick,
1381
- disabled,
1382
- title,
1383
- "aria-label": ariaLabel,
1384
- "aria-pressed": active,
1385
- style: { minWidth: width },
1386
- children
1387
- }
1388
- );
1389
- }
1414
+ var PillContainer = React3.forwardRef(({ children, glow, style }, ref) => /* @__PURE__ */ jsx5(
1415
+ "div",
1416
+ {
1417
+ ref,
1418
+ style: {
1419
+ display: "inline-flex",
1420
+ alignItems: "center",
1421
+ height: TOKENS.pillHeight,
1422
+ borderRadius: TOKENS.pillRadius,
1423
+ border: `1px solid ${TOKENS.border}`,
1424
+ backgroundColor: TOKENS.bgBase,
1425
+ backdropFilter: TOKENS.blur,
1426
+ WebkitBackdropFilter: TOKENS.blur,
1427
+ boxShadow: glow ? `${TOKENS.shadowMd}, ${TOKENS.shadowGlow(glow)}` : TOKENS.shadowMd,
1428
+ overflow: "hidden",
1429
+ transition: `box-shadow ${TOKENS.transitionBase}`,
1430
+ ...style
1431
+ },
1432
+ children
1433
+ }
1434
+ ));
1435
+ PillContainer.displayName = "PillContainer";
1390
1436
  function Divider() {
1391
1437
  return /* @__PURE__ */ jsx5(
1392
1438
  "div",
@@ -1401,98 +1447,112 @@ function Divider() {
1401
1447
  }
1402
1448
  );
1403
1449
  }
1404
- function ScanStatus({ status, issueCount, enabled }) {
1405
- if (!enabled) {
1406
- return /* @__PURE__ */ jsx5(
1407
- "span",
1408
- {
1409
- style: {
1410
- fontSize: "12px",
1411
- color: TOKENS.textDisabled,
1412
- fontStyle: "italic"
1413
- },
1414
- children: "Off"
1415
- }
1416
- );
1417
- }
1418
- if (status === "scanning" || status === "paused") {
1419
- return /* @__PURE__ */ jsxs4(
1420
- "span",
1450
+ function Kbd({ children }) {
1451
+ return /* @__PURE__ */ jsx5(
1452
+ "kbd",
1453
+ {
1454
+ style: {
1455
+ display: "inline-flex",
1456
+ alignItems: "center",
1457
+ padding: "2px 6px",
1458
+ borderRadius: "4px",
1459
+ backgroundColor: TOKENS.bgElevated,
1460
+ border: `1px solid ${TOKENS.border}`,
1461
+ fontSize: "11px",
1462
+ fontFamily: TOKENS.fontMono,
1463
+ color: TOKENS.textSecondary,
1464
+ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.4)"
1465
+ },
1466
+ children
1467
+ }
1468
+ );
1469
+ }
1470
+ function DisconnectedToolbar({
1471
+ onSettingsClick,
1472
+ showSettings
1473
+ }) {
1474
+ return /* @__PURE__ */ jsxs4(PillContainer, { children: [
1475
+ /* @__PURE__ */ jsxs4(
1476
+ "div",
1421
1477
  {
1422
- className: "uilint-scanning-indicator",
1423
1478
  style: {
1424
1479
  display: "flex",
1425
1480
  alignItems: "center",
1426
1481
  gap: "6px",
1427
- padding: "0 4px"
1482
+ padding: "0 12px",
1483
+ color: TOKENS.textMuted,
1484
+ fontSize: "12px"
1428
1485
  },
1429
1486
  children: [
1430
- /* @__PURE__ */ jsx5(Icons.Scan, {}),
1431
- /* @__PURE__ */ jsx5(
1432
- "span",
1433
- {
1434
- style: {
1435
- fontSize: "12px",
1436
- fontFamily: TOKENS.fontMono,
1437
- animation: `uilint-pulse 1s ease-in-out infinite`
1438
- },
1439
- children: "Scanning"
1440
- }
1441
- )
1487
+ /* @__PURE__ */ jsx5(Icons.Unplug, {}),
1488
+ /* @__PURE__ */ jsx5("span", { children: "Not connected" })
1442
1489
  ]
1443
1490
  }
1444
- );
1445
- }
1446
- if (issueCount === 0) {
1447
- return /* @__PURE__ */ jsxs4(
1448
- "span",
1491
+ ),
1492
+ /* @__PURE__ */ jsx5(Divider, {}),
1493
+ /* @__PURE__ */ jsx5(
1494
+ "button",
1449
1495
  {
1450
- style: {
1451
- display: "flex",
1452
- alignItems: "center",
1453
- gap: "5px"
1454
- },
1496
+ className: `uilint-btn uilint-btn--icon ${showSettings ? "uilint-btn--accent" : ""}`,
1497
+ onClick: onSettingsClick,
1498
+ title: "Settings",
1499
+ "aria-label": "Open settings",
1500
+ "aria-pressed": showSettings,
1501
+ children: /* @__PURE__ */ jsx5(Icons.Settings, {})
1502
+ }
1503
+ )
1504
+ ] });
1505
+ }
1506
+ function IdleToolbar({
1507
+ onStartScan,
1508
+ onSettingsClick,
1509
+ showSettings
1510
+ }) {
1511
+ return /* @__PURE__ */ jsxs4(PillContainer, { children: [
1512
+ /* @__PURE__ */ jsxs4(
1513
+ "button",
1514
+ {
1515
+ className: "uilint-btn uilint-btn--primary",
1516
+ onClick: onStartScan,
1517
+ title: "Start scanning (\u2325S)",
1518
+ "aria-label": "Start live scanning",
1455
1519
  children: [
1456
- /* @__PURE__ */ jsx5(
1457
- "span",
1458
- {
1459
- style: {
1460
- display: "flex",
1461
- alignItems: "center",
1462
- justifyContent: "center",
1463
- width: "18px",
1464
- height: "18px",
1465
- borderRadius: "50%",
1466
- backgroundColor: `${TOKENS.success}20`,
1467
- color: TOKENS.success
1468
- },
1469
- children: /* @__PURE__ */ jsx5(Icons.Check, {})
1470
- }
1471
- ),
1472
- /* @__PURE__ */ jsx5(
1473
- "span",
1474
- {
1475
- style: {
1476
- fontSize: "12px",
1477
- fontWeight: 500,
1478
- color: TOKENS.success
1479
- },
1480
- children: "Clear"
1481
- }
1482
- )
1520
+ /* @__PURE__ */ jsx5(Icons.Eye, {}),
1521
+ /* @__PURE__ */ jsx5("span", { children: "Start Scanning" })
1483
1522
  ]
1484
1523
  }
1485
- );
1486
- }
1487
- return /* @__PURE__ */ jsxs4(
1488
- "span",
1489
- {
1490
- style: {
1491
- display: "flex",
1492
- alignItems: "center",
1493
- gap: "5px"
1494
- },
1495
- children: [
1524
+ ),
1525
+ /* @__PURE__ */ jsx5(Divider, {}),
1526
+ /* @__PURE__ */ jsx5(
1527
+ "button",
1528
+ {
1529
+ className: `uilint-btn uilint-btn--icon ${showSettings ? "uilint-btn--accent" : ""}`,
1530
+ onClick: onSettingsClick,
1531
+ title: "Settings",
1532
+ "aria-label": "Open settings",
1533
+ "aria-pressed": showSettings,
1534
+ children: /* @__PURE__ */ jsx5(Icons.Settings, {})
1535
+ }
1536
+ )
1537
+ ] });
1538
+ }
1539
+ function ScanningToolbar({
1540
+ issueCount,
1541
+ isScanning,
1542
+ showResults,
1543
+ onToggleResults,
1544
+ onStopScan
1545
+ }) {
1546
+ const hasIssues = issueCount > 0;
1547
+ const getStatusContent = () => {
1548
+ if (isScanning) {
1549
+ return /* @__PURE__ */ jsxs4(Fragment2, { children: [
1550
+ /* @__PURE__ */ jsx5("div", { className: "uilint-scanning-dot" }),
1551
+ /* @__PURE__ */ jsx5("span", { style: { fontFamily: TOKENS.fontMono, fontSize: "12px" }, children: "Scanning..." })
1552
+ ] });
1553
+ }
1554
+ if (hasIssues) {
1555
+ return /* @__PURE__ */ jsxs4(Fragment2, { children: [
1496
1556
  /* @__PURE__ */ jsx5(
1497
1557
  "span",
1498
1558
  {
@@ -1500,8 +1560,8 @@ function ScanStatus({ status, issueCount, enabled }) {
1500
1560
  display: "flex",
1501
1561
  alignItems: "center",
1502
1562
  justifyContent: "center",
1503
- width: "18px",
1504
- height: "18px",
1563
+ width: "16px",
1564
+ height: "16px",
1505
1565
  borderRadius: "50%",
1506
1566
  backgroundColor: `${TOKENS.warning}20`,
1507
1567
  color: TOKENS.warning
@@ -1510,6 +1570,72 @@ function ScanStatus({ status, issueCount, enabled }) {
1510
1570
  }
1511
1571
  ),
1512
1572
  /* @__PURE__ */ jsx5(Badge, { count: issueCount })
1573
+ ] });
1574
+ }
1575
+ return /* @__PURE__ */ jsxs4(Fragment2, { children: [
1576
+ /* @__PURE__ */ jsx5(
1577
+ "span",
1578
+ {
1579
+ style: {
1580
+ display: "flex",
1581
+ alignItems: "center",
1582
+ justifyContent: "center",
1583
+ width: "16px",
1584
+ height: "16px",
1585
+ borderRadius: "50%",
1586
+ backgroundColor: `${TOKENS.success}20`,
1587
+ color: TOKENS.success
1588
+ },
1589
+ children: /* @__PURE__ */ jsx5(Icons.Check, {})
1590
+ }
1591
+ ),
1592
+ /* @__PURE__ */ jsx5(
1593
+ "span",
1594
+ {
1595
+ style: { fontSize: "12px", fontWeight: 500, color: TOKENS.success },
1596
+ children: "All clear"
1597
+ }
1598
+ )
1599
+ ] });
1600
+ };
1601
+ const statusVariant = hasIssues ? "warning" : isScanning ? "accent" : "success";
1602
+ const glowColor = hasIssues ? `${TOKENS.warning}25` : void 0;
1603
+ return /* @__PURE__ */ jsxs4(
1604
+ "div",
1605
+ {
1606
+ className: "uilint-scanning-bar",
1607
+ style: { display: "flex", alignItems: "center", gap: "10px" },
1608
+ children: [
1609
+ /* @__PURE__ */ jsxs4(PillContainer, { glow: glowColor, children: [
1610
+ /* @__PURE__ */ jsxs4(
1611
+ "button",
1612
+ {
1613
+ className: `uilint-btn uilint-btn--${statusVariant}`,
1614
+ onClick: onToggleResults,
1615
+ title: hasIssues ? `${issueCount} issue${issueCount !== 1 ? "s" : ""} found` : "View scan results",
1616
+ "aria-label": "Toggle scan results",
1617
+ "aria-expanded": showResults,
1618
+ style: { paddingRight: "10px" },
1619
+ children: [
1620
+ getStatusContent(),
1621
+ /* @__PURE__ */ jsx5(Icons.ChevronDown, {})
1622
+ ]
1623
+ }
1624
+ ),
1625
+ /* @__PURE__ */ jsx5(Divider, {}),
1626
+ /* @__PURE__ */ jsx5(
1627
+ "button",
1628
+ {
1629
+ className: "uilint-btn uilint-btn--icon",
1630
+ onClick: onStopScan,
1631
+ title: "Stop scanning (\u2325S)",
1632
+ "aria-label": "Stop scanning",
1633
+ children: /* @__PURE__ */ jsx5(Icons.X, {})
1634
+ }
1635
+ )
1636
+ ] }),
1637
+ /* @__PURE__ */ jsx5(Kbd, { children: "\u2325 + Click" }),
1638
+ /* @__PURE__ */ jsx5("span", { style: { fontSize: "12px", color: TOKENS.textMuted }, children: "to inspect" })
1513
1639
  ]
1514
1640
  }
1515
1641
  );
@@ -1526,6 +1652,7 @@ function UILintToolbar() {
1526
1652
  (s) => s.elementIssuesCache
1527
1653
  );
1528
1654
  const fileIssuesCache = useUILintStore((s) => s.fileIssuesCache);
1655
+ const wsConnected = useUILintStore((s) => s.wsConnected);
1529
1656
  const [showSettings, setShowSettings] = useState2(false);
1530
1657
  const [showResults, setShowResults] = useState2(false);
1531
1658
  const [mounted, setMounted] = useState2(false);
@@ -1533,7 +1660,17 @@ function UILintToolbar() {
1533
1660
  const [nextjsOverlayVisible, setNextjsOverlayVisible] = useState2(false);
1534
1661
  const toolbarRef = useRef2(null);
1535
1662
  const settingsRef = useRef2(null);
1536
- useEffect2(() => {
1663
+ const isScanning = autoScanState.status === "scanning" || autoScanState.status === "paused";
1664
+ let elementIssues = 0;
1665
+ elementIssuesCache.forEach((el) => {
1666
+ elementIssues += el.issues.length;
1667
+ });
1668
+ let fileLevelIssues = 0;
1669
+ fileIssuesCache.forEach((issues) => {
1670
+ fileLevelIssues += issues.length;
1671
+ });
1672
+ const totalIssues = elementIssues + fileLevelIssues;
1673
+ useEffect3(() => {
1537
1674
  const checkForNextOverlay = () => {
1538
1675
  const overlaySelectors = [
1539
1676
  "nextjs-portal",
@@ -1560,29 +1697,21 @@ function UILintToolbar() {
1560
1697
  });
1561
1698
  return () => observer.disconnect();
1562
1699
  }, []);
1563
- const isScanning = autoScanState.status === "scanning";
1564
- const isComplete = autoScanState.status === "complete";
1565
- let elementIssues = 0;
1566
- elementIssuesCache.forEach((el) => {
1567
- elementIssues += el.issues.length;
1568
- });
1569
- let fileLevelIssues = 0;
1570
- fileIssuesCache.forEach((issues) => {
1571
- fileLevelIssues += issues.length;
1572
- });
1573
- const totalIssues = elementIssues + fileLevelIssues;
1574
- const hasIssues = totalIssues > 0;
1575
- useEffect2(() => {
1700
+ useEffect3(() => {
1576
1701
  setMounted(true);
1577
1702
  }, []);
1578
- useEffect2(() => {
1703
+ useEffect3(() => {
1579
1704
  const handleClickOutside = (e) => {
1580
1705
  const target = e.target;
1706
+ if (target?.closest?.("[data-ui-lint]")) return;
1581
1707
  if (showSettings && settingsRef.current && toolbarRef.current) {
1582
1708
  if (!settingsRef.current.contains(target) && !toolbarRef.current.contains(target)) {
1583
1709
  handleCloseSettings();
1584
1710
  }
1585
1711
  }
1712
+ if (showResults) {
1713
+ setShowResults(false);
1714
+ }
1586
1715
  };
1587
1716
  const handleEscape = (e) => {
1588
1717
  if (e.key === "Escape") {
@@ -1590,35 +1719,26 @@ function UILintToolbar() {
1590
1719
  if (showResults) setShowResults(false);
1591
1720
  }
1592
1721
  };
1593
- document.addEventListener("mousedown", handleClickOutside);
1722
+ document.addEventListener("mousedown", handleClickOutside, true);
1594
1723
  document.addEventListener("keydown", handleEscape);
1595
1724
  return () => {
1596
- document.removeEventListener("mousedown", handleClickOutside);
1725
+ document.removeEventListener("mousedown", handleClickOutside, true);
1597
1726
  document.removeEventListener("keydown", handleEscape);
1598
1727
  };
1599
1728
  }, [showSettings, showResults]);
1600
- const handleToggleClick = useCallback2(() => {
1601
- if (liveScanEnabled) {
1602
- disableLiveScan();
1603
- setShowResults(false);
1604
- } else {
1605
- enableLiveScan();
1606
- }
1607
- if (showSettings) handleCloseSettings();
1608
- }, [liveScanEnabled, enableLiveScan, disableLiveScan, showSettings]);
1609
- const handleIssuesClick = useCallback2(() => {
1610
- if (!liveScanEnabled) {
1611
- enableLiveScan();
1612
- return;
1613
- }
1614
- setShowResults((prev) => !prev);
1615
- }, [liveScanEnabled, enableLiveScan]);
1729
+ const handleStartScan = useCallback2(() => {
1730
+ enableLiveScan();
1731
+ setShowSettings(false);
1732
+ }, [enableLiveScan]);
1733
+ const handleStopScan = useCallback2(() => {
1734
+ disableLiveScan();
1735
+ setShowResults(false);
1736
+ }, [disableLiveScan]);
1616
1737
  const handleSettingsClick = useCallback2(() => {
1617
1738
  if (showSettings) {
1618
1739
  handleCloseSettings();
1619
1740
  } else {
1620
1741
  setShowSettings(true);
1621
- setShowResults(false);
1622
1742
  }
1623
1743
  }, [showSettings]);
1624
1744
  const handleCloseSettings = useCallback2(() => {
@@ -1628,125 +1748,77 @@ function UILintToolbar() {
1628
1748
  setSettingsClosing(false);
1629
1749
  }, 150);
1630
1750
  }, []);
1751
+ const handleToggleResults = useCallback2(() => {
1752
+ setShowResults((prev) => !prev);
1753
+ }, []);
1754
+ const handleUILintInteraction = useCallback2(
1755
+ (e) => {
1756
+ e.stopPropagation();
1757
+ },
1758
+ []
1759
+ );
1631
1760
  if (!mounted) return null;
1632
- const issueVariant = !liveScanEnabled ? "default" : hasIssues ? "warning" : isComplete ? "success" : "default";
1633
1761
  const bottomPosition = nextjsOverlayVisible ? "80px" : "20px";
1762
+ const renderToolbar = () => {
1763
+ if (!wsConnected) {
1764
+ return /* @__PURE__ */ jsx5(
1765
+ DisconnectedToolbar,
1766
+ {
1767
+ onSettingsClick: handleSettingsClick,
1768
+ showSettings
1769
+ }
1770
+ );
1771
+ }
1772
+ if (!liveScanEnabled) {
1773
+ return /* @__PURE__ */ jsx5(
1774
+ IdleToolbar,
1775
+ {
1776
+ onStartScan: handleStartScan,
1777
+ onSettingsClick: handleSettingsClick,
1778
+ showSettings
1779
+ }
1780
+ );
1781
+ }
1782
+ return /* @__PURE__ */ jsx5(
1783
+ ScanningToolbar,
1784
+ {
1785
+ issueCount: totalIssues,
1786
+ isScanning,
1787
+ showResults,
1788
+ onToggleResults: handleToggleResults,
1789
+ onStopScan: handleStopScan
1790
+ }
1791
+ );
1792
+ };
1634
1793
  const content = /* @__PURE__ */ jsxs4(
1635
1794
  "div",
1636
1795
  {
1637
1796
  "data-ui-lint": true,
1797
+ onMouseDown: handleUILintInteraction,
1798
+ onClick: handleUILintInteraction,
1799
+ onKeyDown: handleUILintInteraction,
1638
1800
  style: {
1639
1801
  position: "fixed",
1640
1802
  bottom: bottomPosition,
1641
1803
  left: "20px",
1642
1804
  zIndex: 99999,
1643
1805
  fontFamily: TOKENS.fontFamily,
1644
- transition: `bottom ${TOKENS.transitionSlow}`
1806
+ transition: `bottom ${TOKENS.transitionSlow}`,
1807
+ pointerEvents: "none"
1645
1808
  },
1646
1809
  children: [
1647
1810
  /* @__PURE__ */ jsx5("style", { children: globalStyles }),
1648
1811
  /* @__PURE__ */ jsx5(
1649
- "div",
1650
- {
1651
- className: `uilint-hint ${liveScanEnabled ? "uilint-hint--visible" : ""}`,
1652
- style: {
1653
- textAlign: "center",
1654
- marginBottom: "10px",
1655
- fontSize: "11px",
1656
- color: TOKENS.textMuted,
1657
- letterSpacing: "0.02em"
1658
- },
1659
- "aria-hidden": !liveScanEnabled,
1660
- children: /* @__PURE__ */ jsx5(
1661
- "kbd",
1662
- {
1663
- style: {
1664
- display: "inline-block",
1665
- padding: "2px 5px",
1666
- marginRight: "4px",
1667
- borderRadius: "4px",
1668
- backgroundColor: TOKENS.bgElevated,
1669
- border: `1px solid ${TOKENS.border}`,
1670
- fontSize: "10px",
1671
- fontFamily: TOKENS.fontMono,
1672
- color: TOKENS.textSecondary,
1673
- boxShadow: `0 1px 3px rgba(0, 0, 0, 0.5)`
1674
- },
1675
- children: "\u2325 + Click to inspect element"
1676
- }
1677
- )
1678
- }
1679
- ),
1680
- /* @__PURE__ */ jsxs4(
1681
1812
  "div",
1682
1813
  {
1683
1814
  ref: toolbarRef,
1684
1815
  role: "toolbar",
1685
1816
  "aria-label": "UI Lint toolbar",
1686
- style: {
1687
- position: "relative",
1688
- display: "inline-flex",
1689
- alignItems: "center",
1690
- height: TOKENS.pillHeight,
1691
- borderRadius: TOKENS.pillRadius,
1692
- border: `1px solid ${TOKENS.border}`,
1693
- backgroundColor: TOKENS.bgBase,
1694
- backdropFilter: TOKENS.blur,
1695
- WebkitBackdropFilter: TOKENS.blur,
1696
- boxShadow: liveScanEnabled && hasIssues ? `${TOKENS.shadowMd}, ${TOKENS.shadowGlow(
1697
- `${TOKENS.warning}30`
1698
- )}` : TOKENS.shadowMd,
1699
- overflow: "hidden",
1700
- transition: `box-shadow ${TOKENS.transitionBase}`
1701
- },
1702
- children: [
1703
- /* @__PURE__ */ jsx5(
1704
- ToolbarButton,
1705
- {
1706
- onClick: handleToggleClick,
1707
- active: liveScanEnabled,
1708
- title: liveScanEnabled ? "Stop scanning (\u2325S)" : "Start scanning (\u2325S)",
1709
- ariaLabel: liveScanEnabled ? "Stop live scanning" : "Start live scanning",
1710
- width: "48px",
1711
- children: liveScanEnabled ? /* @__PURE__ */ jsx5(Icons.Eye, {}) : /* @__PURE__ */ jsx5(Icons.EyeOff, {})
1712
- }
1713
- ),
1714
- /* @__PURE__ */ jsx5(Divider, {}),
1715
- /* @__PURE__ */ jsx5(
1716
- ToolbarButton,
1717
- {
1718
- onClick: handleIssuesClick,
1719
- active: showResults && liveScanEnabled,
1720
- variant: issueVariant,
1721
- title: !liveScanEnabled ? "Click to enable scanning" : `${totalIssues} issue${totalIssues !== 1 ? "s" : ""} found`,
1722
- ariaLabel: !liveScanEnabled ? "Enable scanning to see issues" : `View ${totalIssues} issues`,
1723
- width: "auto",
1724
- children: /* @__PURE__ */ jsx5("span", { style: { padding: "0 12px" }, children: /* @__PURE__ */ jsx5(
1725
- ScanStatus,
1726
- {
1727
- status: autoScanState.status,
1728
- issueCount: totalIssues,
1729
- enabled: liveScanEnabled
1730
- }
1731
- ) })
1732
- }
1733
- ),
1734
- /* @__PURE__ */ jsx5(Divider, {}),
1735
- /* @__PURE__ */ jsx5(
1736
- ToolbarButton,
1737
- {
1738
- onClick: handleSettingsClick,
1739
- active: showSettings,
1740
- title: "Settings",
1741
- ariaLabel: "Open settings",
1742
- width: "44px",
1743
- children: /* @__PURE__ */ jsx5(Icons.Settings, {})
1744
- }
1745
- )
1746
- ]
1817
+ style: { pointerEvents: "auto" },
1818
+ children: renderToolbar()
1747
1819
  }
1748
1820
  ),
1749
- showSettings && /* @__PURE__ */ jsx5(
1821
+ showSettings && !liveScanEnabled && /* @__PURE__ */ jsx5(
1750
1822
  "div",
1751
1823
  {
1752
1824
  ref: settingsRef,
@@ -1755,7 +1827,8 @@ function UILintToolbar() {
1755
1827
  position: "absolute",
1756
1828
  bottom: "100%",
1757
1829
  left: 0,
1758
- marginBottom: "8px"
1830
+ marginBottom: "8px",
1831
+ pointerEvents: "auto"
1759
1832
  },
1760
1833
  children: /* @__PURE__ */ jsx5(SettingsPopover, { settings })
1761
1834
  }