@toolr/ui-design 0.1.7 → 0.1.8
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/components/hooks/use-modal-behavior.ts +32 -3
- package/components/sections/golden-snapshots/file-diff-viewer.tsx +1 -1
- package/components/sections/golden-snapshots/status-overview.tsx +1 -1
- package/components/ui/action-dialog.tsx +14 -6
- package/components/ui/ai-action-button.tsx +2 -4
- package/components/ui/badge.tsx +12 -4
- package/components/ui/breadcrumb.tsx +5 -5
- package/components/ui/checkbox.tsx +17 -11
- package/components/ui/collapsible-section.tsx +1 -0
- package/components/ui/confirm-badge.tsx +12 -4
- package/components/ui/cookie-consent.tsx +1 -1
- package/components/ui/extension-list-card.tsx +1 -1
- package/components/ui/file-tree.tsx +4 -4
- package/components/ui/filter-dropdown.tsx +5 -2
- package/components/ui/form-actions.tsx +7 -5
- package/components/ui/icon-button.tsx +5 -5
- package/components/ui/input.tsx +8 -3
- package/components/ui/label.tsx +4 -0
- package/components/ui/layout-tab-bar.tsx +5 -5
- package/components/ui/modal.tsx +9 -5
- package/components/ui/nav-card.tsx +1 -1
- package/components/ui/navigation-bar.tsx +4 -4
- package/components/ui/number-input.tsx +6 -0
- package/components/ui/segmented-toggle.tsx +2 -0
- package/components/ui/select.tsx +6 -3
- package/components/ui/selection-grid.tsx +4 -0
- package/components/ui/setting-row.tsx +4 -2
- package/components/ui/settings-card.tsx +2 -2
- package/components/ui/settings-info-box.tsx +1 -2
- package/components/ui/sort-dropdown.tsx +8 -5
- package/components/ui/tab-bar.tsx +14 -4
- package/components/ui/toggle.tsx +19 -11
- package/components/ui/tooltip.tsx +5 -5
- package/dist/index.d.ts +13 -7
- package/dist/index.js +258 -156
- package/package.json +9 -1
package/dist/index.js
CHANGED
|
@@ -461,15 +461,14 @@ function Tooltip({
|
|
|
461
461
|
if (!triggerRef.current) return;
|
|
462
462
|
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
463
463
|
const tooltipEl = tooltipRef.current;
|
|
464
|
+
const tooltipRect = tooltipEl?.getBoundingClientRect();
|
|
464
465
|
let resolvedPosition = position === "auto" ? "top" : position;
|
|
465
|
-
if (position === "auto" &&
|
|
466
|
-
const tooltipRect = tooltipEl.getBoundingClientRect();
|
|
466
|
+
if (position === "auto" && tooltipRect) {
|
|
467
467
|
resolvedPosition = resolveAutoPosition(triggerRect, tooltipRect);
|
|
468
468
|
setActualPosition(resolvedPosition);
|
|
469
469
|
}
|
|
470
470
|
let newCoords = calculateBasePosition(triggerRect, resolvedPosition, align);
|
|
471
|
-
if (
|
|
472
|
-
const tooltipRect = tooltipEl.getBoundingClientRect();
|
|
471
|
+
if (tooltipRect) {
|
|
473
472
|
newCoords = adjustForTooltipSize(newCoords, tooltipRect, resolvedPosition, align);
|
|
474
473
|
newCoords = clampToViewport(newCoords, tooltipRect);
|
|
475
474
|
}
|
|
@@ -491,7 +490,8 @@ function Tooltip({
|
|
|
491
490
|
"div",
|
|
492
491
|
{
|
|
493
492
|
ref: tooltipRef,
|
|
494
|
-
|
|
493
|
+
role: "tooltip",
|
|
494
|
+
className: `fixed px-3 py-1.5 bg-[var(--popover)] border border-neutral-600 rounded-lg shadow-lg z-[9999] ${interactive || trigger === "click" ? "" : "pointer-events-none"} ${multiline ? "whitespace-pre-line" : "whitespace-nowrap"}`,
|
|
495
495
|
style: {
|
|
496
496
|
top: coords.top,
|
|
497
497
|
left: coords.left,
|
|
@@ -708,9 +708,9 @@ var statusIcons = {
|
|
|
708
708
|
};
|
|
709
709
|
var statusConfig = {
|
|
710
710
|
loading: { color: void 0, active: true, animation: "animate-spin" },
|
|
711
|
-
success: { color: "green", active: true, animation: "
|
|
712
|
-
warning: { color: "amber", active: true, animation: "
|
|
713
|
-
error: { color: "red", active: true, animation: "
|
|
711
|
+
success: { color: "green", active: true, animation: "" },
|
|
712
|
+
warning: { color: "amber", active: true, animation: "" },
|
|
713
|
+
error: { color: "red", active: true, animation: "" }
|
|
714
714
|
};
|
|
715
715
|
function resolveIcon(icon, status) {
|
|
716
716
|
if (status) return statusIcons[status];
|
|
@@ -772,7 +772,7 @@ function IconButton({
|
|
|
772
772
|
href,
|
|
773
773
|
target: "_blank",
|
|
774
774
|
rel: "noopener noreferrer",
|
|
775
|
-
"aria-label": tooltip?.title,
|
|
775
|
+
"aria-label": tooltip?.title || (typeof tooltip?.description === "string" ? tooltip.description : void 0),
|
|
776
776
|
"data-testid": testId,
|
|
777
777
|
className: `${sharedClassName} cursor-pointer no-underline`,
|
|
778
778
|
children: inner
|
|
@@ -783,7 +783,7 @@ function IconButton({
|
|
|
783
783
|
type: "button",
|
|
784
784
|
onClick,
|
|
785
785
|
disabled,
|
|
786
|
-
"aria-label": tooltip?.title,
|
|
786
|
+
"aria-label": tooltip?.title || (typeof tooltip?.description === "string" ? tooltip.description : void 0),
|
|
787
787
|
"data-testid": testId,
|
|
788
788
|
className: `${sharedClassName} cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed`,
|
|
789
789
|
children: inner
|
|
@@ -892,6 +892,10 @@ function Label({
|
|
|
892
892
|
hasProgress && /* @__PURE__ */ jsx5(
|
|
893
893
|
"span",
|
|
894
894
|
{
|
|
895
|
+
role: "progressbar",
|
|
896
|
+
"aria-valuenow": Math.min(progress, 100),
|
|
897
|
+
"aria-valuemin": 0,
|
|
898
|
+
"aria-valuemax": 100,
|
|
895
899
|
className: `absolute inset-y-0 left-0 ${progressFillColors[color]} rounded-[inherit]`,
|
|
896
900
|
style: { width: `${Math.min(progress, 100)}%` }
|
|
897
901
|
}
|
|
@@ -936,6 +940,16 @@ function Label({
|
|
|
936
940
|
);
|
|
937
941
|
}
|
|
938
942
|
|
|
943
|
+
// components/ui/badge.tsx
|
|
944
|
+
import { memo } from "react";
|
|
945
|
+
|
|
946
|
+
// components/lib/cn.ts
|
|
947
|
+
import { clsx } from "clsx";
|
|
948
|
+
import { twMerge } from "tailwind-merge";
|
|
949
|
+
function cn(...inputs) {
|
|
950
|
+
return twMerge(clsx(inputs));
|
|
951
|
+
}
|
|
952
|
+
|
|
939
953
|
// components/ui/badge.tsx
|
|
940
954
|
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
941
955
|
var sizeClasses2 = {
|
|
@@ -945,11 +959,11 @@ var sizeClasses2 = {
|
|
|
945
959
|
md: "min-w-[20px] h-[20px] px-1.5 text-xs",
|
|
946
960
|
lg: "min-w-[22px] h-[22px] px-1.5 text-sm"
|
|
947
961
|
};
|
|
948
|
-
|
|
962
|
+
var Badge = memo(function Badge2({
|
|
949
963
|
value,
|
|
950
964
|
color = "neutral",
|
|
951
965
|
size = "sm",
|
|
952
|
-
className
|
|
966
|
+
className,
|
|
953
967
|
testId
|
|
954
968
|
}) {
|
|
955
969
|
const display = typeof value === "number" && value > 99 ? "99+" : value;
|
|
@@ -957,13 +971,20 @@ function Badge({
|
|
|
957
971
|
"span",
|
|
958
972
|
{
|
|
959
973
|
"data-testid": testId,
|
|
960
|
-
className:
|
|
974
|
+
className: cn(
|
|
975
|
+
"inline-flex items-center justify-center border rounded-full font-medium leading-none tabular-nums",
|
|
976
|
+
FORM_COLORS[color].border,
|
|
977
|
+
FORM_COLORS[color].accent,
|
|
978
|
+
sizeClasses2[size],
|
|
979
|
+
className
|
|
980
|
+
),
|
|
961
981
|
children: display
|
|
962
982
|
}
|
|
963
983
|
);
|
|
964
|
-
}
|
|
984
|
+
});
|
|
965
985
|
|
|
966
986
|
// components/ui/confirm-badge.tsx
|
|
987
|
+
import { memo as memo2 } from "react";
|
|
967
988
|
import { Check as Check2 } from "lucide-react";
|
|
968
989
|
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
969
990
|
var sizeClasses3 = {
|
|
@@ -980,21 +1001,27 @@ var iconSizeClasses2 = {
|
|
|
980
1001
|
md: "w-3.5 h-3.5",
|
|
981
1002
|
lg: "w-4 h-4"
|
|
982
1003
|
};
|
|
983
|
-
|
|
1004
|
+
var ConfirmBadge = memo2(function ConfirmBadge2({
|
|
984
1005
|
color = "neutral",
|
|
985
1006
|
size = "sm",
|
|
986
|
-
className
|
|
1007
|
+
className,
|
|
987
1008
|
testId
|
|
988
1009
|
}) {
|
|
989
1010
|
return /* @__PURE__ */ jsx7(
|
|
990
1011
|
"span",
|
|
991
1012
|
{
|
|
992
1013
|
"data-testid": testId,
|
|
993
|
-
className:
|
|
1014
|
+
className: cn(
|
|
1015
|
+
"inline-flex items-center justify-center border",
|
|
1016
|
+
FORM_COLORS[color].border,
|
|
1017
|
+
FORM_COLORS[color].accent,
|
|
1018
|
+
sizeClasses3[size],
|
|
1019
|
+
className
|
|
1020
|
+
),
|
|
994
1021
|
children: /* @__PURE__ */ jsx7(Check2, { className: iconSizeClasses2[size] })
|
|
995
1022
|
}
|
|
996
1023
|
);
|
|
997
|
-
}
|
|
1024
|
+
});
|
|
998
1025
|
|
|
999
1026
|
// components/ui/checkbox.tsx
|
|
1000
1027
|
import { Check as Check3 } from "lucide-react";
|
|
@@ -1030,26 +1057,29 @@ function Checkbox({
|
|
|
1030
1057
|
size = "sm",
|
|
1031
1058
|
color = "blue",
|
|
1032
1059
|
variant = "outline",
|
|
1033
|
-
className
|
|
1060
|
+
className,
|
|
1061
|
+
"aria-label": ariaLabel,
|
|
1034
1062
|
testId
|
|
1035
1063
|
}) {
|
|
1036
1064
|
const s = CHECKBOX_SIZES[size];
|
|
1037
1065
|
const c = CHECKBOX_COLORS[color];
|
|
1038
|
-
const uncheckedStyle = variant === "outline" ? `${c.border} ${c.hover}` : `bg-neutral-700 ${c.border} ${c.hover}`;
|
|
1039
1066
|
return /* @__PURE__ */ jsx8(
|
|
1040
1067
|
"button",
|
|
1041
1068
|
{
|
|
1042
1069
|
type: "button",
|
|
1070
|
+
role: "checkbox",
|
|
1071
|
+
"aria-checked": checked,
|
|
1072
|
+
"aria-label": ariaLabel,
|
|
1043
1073
|
onClick: () => !disabled && onChange(!checked),
|
|
1044
1074
|
disabled,
|
|
1045
1075
|
"data-testid": testId,
|
|
1046
|
-
className:
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
children: checked && /* @__PURE__ */ jsx8(Check3, { className:
|
|
1076
|
+
className: cn(
|
|
1077
|
+
"rounded border flex items-center justify-center transition-colors flex-shrink-0 cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed",
|
|
1078
|
+
s.box,
|
|
1079
|
+
checked ? cn(c.bg, c.border) : cn(variant === "filled" && "bg-neutral-700", c.border, c.hover),
|
|
1080
|
+
className
|
|
1081
|
+
),
|
|
1082
|
+
children: checked && /* @__PURE__ */ jsx8(Check3, { className: cn(s.icon, c.icon) })
|
|
1053
1083
|
}
|
|
1054
1084
|
);
|
|
1055
1085
|
}
|
|
@@ -1136,8 +1166,9 @@ function Toggle({
|
|
|
1136
1166
|
onChange,
|
|
1137
1167
|
disabled = false,
|
|
1138
1168
|
size = "sm",
|
|
1139
|
-
className
|
|
1169
|
+
className,
|
|
1140
1170
|
color = "blue",
|
|
1171
|
+
"aria-label": ariaLabel,
|
|
1141
1172
|
testId
|
|
1142
1173
|
}) {
|
|
1143
1174
|
const s = TOGGLE_SIZES[size];
|
|
@@ -1147,24 +1178,28 @@ function Toggle({
|
|
|
1147
1178
|
"button",
|
|
1148
1179
|
{
|
|
1149
1180
|
type: "button",
|
|
1181
|
+
role: "switch",
|
|
1182
|
+
"aria-checked": checked,
|
|
1183
|
+
"aria-label": ariaLabel,
|
|
1150
1184
|
onClick: () => !disabled && onChange(!checked),
|
|
1151
1185
|
disabled,
|
|
1152
1186
|
"data-testid": testId,
|
|
1153
1187
|
style: { boxShadow: `inset 0 0 0 1px ${checked ? bc.active : bc.idle}` },
|
|
1154
|
-
className:
|
|
1155
|
-
relative
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1188
|
+
className: cn(
|
|
1189
|
+
"relative rounded-full transition-all flex-shrink-0 cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed",
|
|
1190
|
+
s.track,
|
|
1191
|
+
checked ? TOGGLE_CHECKED_TRACK[color] : TOGGLE_UNCHECKED_TRACK[color],
|
|
1192
|
+
className
|
|
1193
|
+
),
|
|
1160
1194
|
children: /* @__PURE__ */ jsx9(
|
|
1161
1195
|
"span",
|
|
1162
1196
|
{
|
|
1163
1197
|
style: { backgroundColor: checked ? kc.on : kc.off },
|
|
1164
|
-
className:
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1198
|
+
className: cn(
|
|
1199
|
+
"block absolute top-0.5 left-0.5 rounded-full transition-transform",
|
|
1200
|
+
s.knob,
|
|
1201
|
+
checked ? s.translate : "translate-x-0"
|
|
1202
|
+
)
|
|
1168
1203
|
}
|
|
1169
1204
|
)
|
|
1170
1205
|
}
|
|
@@ -1172,7 +1207,7 @@ function Toggle({
|
|
|
1172
1207
|
}
|
|
1173
1208
|
|
|
1174
1209
|
// components/ui/input.tsx
|
|
1175
|
-
import { forwardRef, useEffect as useEffect3, useRef as useRef2, useState as useState2 } from "react";
|
|
1210
|
+
import { forwardRef, useEffect as useEffect3, useId, useRef as useRef2, useState as useState2 } from "react";
|
|
1176
1211
|
import { Search as Search2, X as X2, Eye as Eye2, EyeOff as EyeOff2 } from "lucide-react";
|
|
1177
1212
|
|
|
1178
1213
|
// components/ui/debounce-border-overlay.tsx
|
|
@@ -1254,6 +1289,7 @@ var Input = forwardRef(function Input2({
|
|
|
1254
1289
|
const isSearch = type === "search";
|
|
1255
1290
|
const isPassword = type === "password";
|
|
1256
1291
|
const [isPasswordVisible, setIsPasswordVisible] = useState2(false);
|
|
1292
|
+
const errorId = useId();
|
|
1257
1293
|
const [internalValue, setInternalValue] = useState2(value);
|
|
1258
1294
|
const [debounceKey, setDebounceKey] = useState2(0);
|
|
1259
1295
|
const timerRef = useRef2(void 0);
|
|
@@ -1311,6 +1347,9 @@ var Input = forwardRef(function Input2({
|
|
|
1311
1347
|
},
|
|
1312
1348
|
disabled,
|
|
1313
1349
|
"data-testid": testId,
|
|
1350
|
+
"aria-invalid": hasError || void 0,
|
|
1351
|
+
"aria-describedby": typeof error === "string" && error ? errorId : void 0,
|
|
1352
|
+
...isSearch && !props["aria-label"] ? { "aria-label": props.placeholder || "Search" } : {},
|
|
1314
1353
|
...searchAutoProps,
|
|
1315
1354
|
className: `
|
|
1316
1355
|
w-full border rounded-lg text-neutral-200 placeholder-neutral-500
|
|
@@ -1329,6 +1368,7 @@ var Input = forwardRef(function Input2({
|
|
|
1329
1368
|
"button",
|
|
1330
1369
|
{
|
|
1331
1370
|
type: "button",
|
|
1371
|
+
"aria-label": "Clear search",
|
|
1332
1372
|
onClick: handleClear,
|
|
1333
1373
|
className: "absolute right-2 top-1/2 -translate-y-1/2 w-[18px] h-[18px] flex items-center justify-center rounded-md text-neutral-400 hover:text-neutral-300 hover:bg-neutral-500/20 transition-colors z-10 cursor-pointer",
|
|
1334
1374
|
children: /* @__PURE__ */ jsx11(X2, { className: "w-2.5 h-2.5" })
|
|
@@ -1340,14 +1380,14 @@ var Input = forwardRef(function Input2({
|
|
|
1340
1380
|
{
|
|
1341
1381
|
type: "button",
|
|
1342
1382
|
onClick: () => setIsPasswordVisible(!isPasswordVisible),
|
|
1343
|
-
|
|
1383
|
+
"aria-label": isPasswordVisible ? "Hide password" : "Show password",
|
|
1344
1384
|
className: "absolute right-2 top-1/2 -translate-y-1/2 w-[18px] h-[18px] flex items-center justify-center rounded-md text-neutral-400 hover:text-neutral-300 hover:bg-neutral-500/20 transition-colors z-10 cursor-pointer",
|
|
1345
1385
|
children: isPasswordVisible ? /* @__PURE__ */ jsx11(EyeOff2, { className: "w-2.5 h-2.5" }) : /* @__PURE__ */ jsx11(Eye2, { className: "w-2.5 h-2.5" })
|
|
1346
1386
|
}
|
|
1347
1387
|
),
|
|
1348
1388
|
debounceMs > 0 && debounceKey > 0 && /* @__PURE__ */ jsx11(DebounceBorderOverlay, { debounceKey, durationMs: debounceMs })
|
|
1349
1389
|
] }),
|
|
1350
|
-
typeof error === "string" && error && /* @__PURE__ */ jsx11("p", { className: "text-sm text-red-400 mt-1 text-right", children: error })
|
|
1390
|
+
typeof error === "string" && error && /* @__PURE__ */ jsx11("p", { id: errorId, className: "text-sm text-red-400 mt-1 text-right", role: "alert", children: error })
|
|
1351
1391
|
]
|
|
1352
1392
|
}
|
|
1353
1393
|
);
|
|
@@ -1378,7 +1418,8 @@ function NumberInput({
|
|
|
1378
1418
|
color = "blue",
|
|
1379
1419
|
size = "sm",
|
|
1380
1420
|
disabled = false,
|
|
1381
|
-
className = ""
|
|
1421
|
+
className = "",
|
|
1422
|
+
"aria-label": ariaLabel
|
|
1382
1423
|
}) {
|
|
1383
1424
|
const [focused, setFocused] = useState3(false);
|
|
1384
1425
|
const [editText, setEditText] = useState3(null);
|
|
@@ -1429,6 +1470,7 @@ function NumberInput({
|
|
|
1429
1470
|
ref: inputRef,
|
|
1430
1471
|
type: "text",
|
|
1431
1472
|
inputMode: "numeric",
|
|
1473
|
+
"aria-label": ariaLabel,
|
|
1432
1474
|
value: editText ?? value,
|
|
1433
1475
|
onChange: (e) => setEditText(e.target.value),
|
|
1434
1476
|
onFocus: () => {
|
|
@@ -1470,6 +1512,7 @@ function NumberInput({
|
|
|
1470
1512
|
"button",
|
|
1471
1513
|
{
|
|
1472
1514
|
type: "button",
|
|
1515
|
+
"aria-label": "Increase value",
|
|
1473
1516
|
tabIndex: -1,
|
|
1474
1517
|
onMouseDown: (e) => e.preventDefault(),
|
|
1475
1518
|
onClick: () => nudge(1),
|
|
@@ -1489,6 +1532,7 @@ function NumberInput({
|
|
|
1489
1532
|
"button",
|
|
1490
1533
|
{
|
|
1491
1534
|
type: "button",
|
|
1535
|
+
"aria-label": "Decrease value",
|
|
1492
1536
|
tabIndex: -1,
|
|
1493
1537
|
onMouseDown: (e) => e.preventDefault(),
|
|
1494
1538
|
onClick: () => nudge(-1),
|
|
@@ -1665,6 +1709,8 @@ function SegmentedToggle({
|
|
|
1665
1709
|
return /* @__PURE__ */ jsx14(Tooltip, { content: option.tooltip, position: tooltipPosition, children: /* @__PURE__ */ jsxs8(
|
|
1666
1710
|
"button",
|
|
1667
1711
|
{
|
|
1712
|
+
"aria-pressed": isActive,
|
|
1713
|
+
"aria-label": option.label || (typeof option.tooltip.description === "string" ? option.tooltip.description : void 0),
|
|
1668
1714
|
onClick: () => onChange(option.value),
|
|
1669
1715
|
disabled,
|
|
1670
1716
|
className: `flex items-center justify-center ${sizeClass} ${rounding} font-medium transition-all cursor-pointer ${isActive ? ACTIVE_COLORS[accentColor] || ACTIVE_COLORS.blue : `text-neutral-400 ${HOVER_COLORS[accentColor] || HOVER_COLORS.blue}`}`,
|
|
@@ -1980,12 +2026,14 @@ function Select({
|
|
|
1980
2026
|
{
|
|
1981
2027
|
ref: buttonRef,
|
|
1982
2028
|
type: "button",
|
|
2029
|
+
"aria-expanded": isOpen,
|
|
2030
|
+
"aria-haspopup": "listbox",
|
|
1983
2031
|
onClick: () => !disabled && (isOpen ? close() : open()),
|
|
1984
2032
|
disabled,
|
|
1985
2033
|
className: `flex items-center gap-1.5 min-w-0 rounded-lg border ${v.bg} ${FORM_COLORS[color].border} text-neutral-200 focus:outline-none ${FORM_COLORS[color].focus} transition-colors ${disabled ? "opacity-50 cursor-not-allowed" : `cursor-pointer ${FORM_COLORS[color].hover}`} ${s}`,
|
|
1986
2034
|
children: [
|
|
1987
2035
|
selectedOption?.icon,
|
|
1988
|
-
/* @__PURE__ */ jsx16("span", { className: `
|
|
2036
|
+
/* @__PURE__ */ jsx16("span", { className: `truncate ${selectedOption ? "" : "text-neutral-500"}`, children: selectedOption?.label ?? placeholder }),
|
|
1989
2037
|
/* @__PURE__ */ jsx16(ChevronDown3, { className: `w-3 h-3 ml-auto text-neutral-500 transition-transform shrink-0 ${isOpen ? "rotate-180" : ""}` })
|
|
1990
2038
|
]
|
|
1991
2039
|
}
|
|
@@ -1995,7 +2043,8 @@ function Select({
|
|
|
1995
2043
|
"div",
|
|
1996
2044
|
{
|
|
1997
2045
|
ref: menuRef,
|
|
1998
|
-
|
|
2046
|
+
role: "listbox",
|
|
2047
|
+
className: `fixed z-[9999] whitespace-nowrap ${v.menuBg} border ${FORM_COLORS[color].border} rounded-lg shadow-lg overflow-hidden`,
|
|
1999
2048
|
style: {
|
|
2000
2049
|
top: menuPos.top,
|
|
2001
2050
|
left: align === "right" ? void 0 : menuPos.left,
|
|
@@ -2019,7 +2068,7 @@ function Select({
|
|
|
2019
2068
|
children: [
|
|
2020
2069
|
/* @__PURE__ */ jsx16(Check4, { className: `w-3 h-3 shrink-0 ${isSelected ? FORM_COLORS[color].accent : "invisible"}` }),
|
|
2021
2070
|
opt.icon,
|
|
2022
|
-
/* @__PURE__ */ jsx16("span", { children: opt.label })
|
|
2071
|
+
/* @__PURE__ */ jsx16("span", { className: "truncate", children: opt.label })
|
|
2023
2072
|
]
|
|
2024
2073
|
},
|
|
2025
2074
|
String(opt.value)
|
|
@@ -2104,12 +2153,14 @@ function FilterDropdown({
|
|
|
2104
2153
|
/* @__PURE__ */ jsxs11(
|
|
2105
2154
|
"button",
|
|
2106
2155
|
{
|
|
2156
|
+
"aria-expanded": isOpen,
|
|
2157
|
+
"aria-haspopup": "listbox",
|
|
2107
2158
|
onClick: () => setIsOpen(!isOpen),
|
|
2108
2159
|
className: `flex items-center gap-1.5 h-7 px-2 rounded-md border ${v.bg} text-sm transition-colors cursor-pointer ${isActive ? `${clearable ? "rounded-r-none border-r-0" : ""} ${FORM_COLORS[color].border} text-neutral-200 ${FORM_COLORS[color].hover}` : isOpen ? `${FORM_COLORS[color].border} text-neutral-200` : `${FORM_COLORS[color].border} text-neutral-400 ${FORM_COLORS[color].hover} hover:text-neutral-200`}`,
|
|
2109
2160
|
children: [
|
|
2110
2161
|
/* @__PURE__ */ jsx17(Filter2, { className: `w-3 h-3 ${isActive ? FORM_COLORS[color].accent : ""}` }),
|
|
2111
2162
|
labelExtra,
|
|
2112
|
-
/* @__PURE__ */ jsx17("span", { className: "
|
|
2163
|
+
/* @__PURE__ */ jsx17("span", { className: "truncate", children: selectedLabel }),
|
|
2113
2164
|
/* @__PURE__ */ jsx17(ChevronDown4, { className: `w-3 h-3 transition-transform ${isOpen ? "rotate-180" : ""}` })
|
|
2114
2165
|
]
|
|
2115
2166
|
}
|
|
@@ -2117,12 +2168,13 @@ function FilterDropdown({
|
|
|
2117
2168
|
isActive && clearable && /* @__PURE__ */ jsx17(
|
|
2118
2169
|
"button",
|
|
2119
2170
|
{
|
|
2171
|
+
"aria-label": "Clear filter",
|
|
2120
2172
|
onClick: () => onChange("all"),
|
|
2121
2173
|
className: `flex items-center justify-center h-7 px-1.5 rounded-r-md border border-l-0 ${FORM_COLORS[color].border} ${v.bg} text-neutral-400 ${FORM_COLORS[color].hover} hover:text-neutral-200 transition-colors cursor-pointer`,
|
|
2122
2174
|
children: /* @__PURE__ */ jsx17(X3, { className: "w-3 h-3" })
|
|
2123
2175
|
}
|
|
2124
2176
|
),
|
|
2125
|
-
isOpen && /* @__PURE__ */ jsxs11("div", { ref: menuRef, className: `absolute right-0 top-full z-50 mt-1 min-w-[140px] whitespace-nowrap bg-[var(--popover)] border ${FORM_COLORS[color].border} rounded-lg shadow-
|
|
2177
|
+
isOpen && /* @__PURE__ */ jsxs11("div", { ref: menuRef, role: "listbox", className: `absolute right-0 top-full z-50 mt-1 min-w-[140px] whitespace-nowrap bg-[var(--popover)] border ${FORM_COLORS[color].border} rounded-lg shadow-lg overflow-hidden`, children: [
|
|
2126
2178
|
showSearch && /* @__PURE__ */ jsx17("div", { className: `sticky top-0 p-1.5 bg-[var(--popover)] border-b ${FORM_COLORS[color].border} z-10`, children: /* @__PURE__ */ jsxs11("div", { className: "relative", children: [
|
|
2127
2179
|
/* @__PURE__ */ jsx17(Search3, { className: "absolute left-2 top-1/2 -translate-y-1/2 w-3 h-3 text-neutral-500" }),
|
|
2128
2180
|
/* @__PURE__ */ jsx17(
|
|
@@ -2222,18 +2274,21 @@ function SortDropdown({
|
|
|
2222
2274
|
/* @__PURE__ */ jsxs12(
|
|
2223
2275
|
"button",
|
|
2224
2276
|
{
|
|
2277
|
+
"aria-expanded": isOpen,
|
|
2278
|
+
"aria-haspopup": "listbox",
|
|
2225
2279
|
onClick: () => setIsOpen(!isOpen),
|
|
2226
2280
|
className: `flex items-center gap-1.5 h-7 px-2 rounded-md border ${v.bg} text-sm transition-colors cursor-pointer ${FORM_COLORS[color].border} text-neutral-200 ${FORM_COLORS[color].hover}`,
|
|
2227
2281
|
children: [
|
|
2228
2282
|
/* @__PURE__ */ jsx18(
|
|
2229
|
-
"
|
|
2283
|
+
"button",
|
|
2230
2284
|
{
|
|
2231
|
-
|
|
2285
|
+
type: "button",
|
|
2286
|
+
"aria-label": ascending ? "Sort descending" : "Sort ascending",
|
|
2287
|
+
className: `${FORM_COLORS[color].accent} hover:brightness-125 transition-colors cursor-pointer`,
|
|
2232
2288
|
onClick: (e) => {
|
|
2233
2289
|
e.stopPropagation();
|
|
2234
2290
|
onToggleDirection();
|
|
2235
2291
|
},
|
|
2236
|
-
role: "button",
|
|
2237
2292
|
children: /* @__PURE__ */ jsx18(DirIcon, { className: "w-3 h-3" })
|
|
2238
2293
|
}
|
|
2239
2294
|
),
|
|
@@ -2242,7 +2297,7 @@ function SortDropdown({
|
|
|
2242
2297
|
]
|
|
2243
2298
|
}
|
|
2244
2299
|
),
|
|
2245
|
-
isOpen && /* @__PURE__ */ jsx18("div", { ref: menuRef, className: `absolute right-0 top-full z-50 mt-1 min-w-[140px] bg-[var(--popover)] border ${FORM_COLORS[color].border} rounded-lg shadow-
|
|
2300
|
+
isOpen && /* @__PURE__ */ jsx18("div", { ref: menuRef, role: "listbox", className: `absolute right-0 top-full z-50 mt-1 min-w-[140px] bg-[var(--popover)] border ${FORM_COLORS[color].border} rounded-lg shadow-lg overflow-hidden`, children: fields.map((f, idx) => /* @__PURE__ */ jsxs12(
|
|
2246
2301
|
"button",
|
|
2247
2302
|
{
|
|
2248
2303
|
onClick: () => {
|
|
@@ -2294,9 +2349,13 @@ function FormActions({
|
|
|
2294
2349
|
padding = "normal"
|
|
2295
2350
|
}) {
|
|
2296
2351
|
const showBorder = border ?? DEFAULT_BORDER[padding];
|
|
2297
|
-
const paddingClass = showBorder ? `${PADDING_CLASSES[padding]} ${BORDER_CLASS}` : PADDING_CLASSES[padding];
|
|
2298
2352
|
const hasLeft = onBack || statusText;
|
|
2299
|
-
return /* @__PURE__ */ jsxs13("div", { className:
|
|
2353
|
+
return /* @__PURE__ */ jsxs13("div", { className: cn(
|
|
2354
|
+
"flex items-center gap-2",
|
|
2355
|
+
hasLeft ? "justify-between" : "justify-end",
|
|
2356
|
+
PADDING_CLASSES[padding],
|
|
2357
|
+
showBorder && BORDER_CLASS
|
|
2358
|
+
), children: [
|
|
2300
2359
|
hasLeft && /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-2", children: [
|
|
2301
2360
|
onBack && /* @__PURE__ */ jsx19(
|
|
2302
2361
|
IconButton,
|
|
@@ -2353,13 +2412,13 @@ function FormActions({
|
|
|
2353
2412
|
}
|
|
2354
2413
|
|
|
2355
2414
|
// components/ui/modal.tsx
|
|
2356
|
-
import { useRef as useRef9, useState as useState8 } from "react";
|
|
2415
|
+
import { useId as useId2, useRef as useRef9, useState as useState8 } from "react";
|
|
2357
2416
|
import { createPortal as createPortal3 } from "react-dom";
|
|
2358
2417
|
import { Info as Info2, AlertTriangle as AlertTriangle2, AlertCircle as AlertCircle2, Check as Check7 } from "lucide-react";
|
|
2359
2418
|
|
|
2360
2419
|
// components/hooks/use-modal-behavior.ts
|
|
2361
2420
|
import { useEffect as useEffect7 } from "react";
|
|
2362
|
-
function useModalBehavior(isOpen, onClose) {
|
|
2421
|
+
function useModalBehavior(isOpen, onClose, containerRef) {
|
|
2363
2422
|
useEffect7(() => {
|
|
2364
2423
|
if (!isOpen) return;
|
|
2365
2424
|
const handler = (e) => {
|
|
@@ -2376,6 +2435,36 @@ function useModalBehavior(isOpen, onClose) {
|
|
|
2376
2435
|
document.body.style.overflow = prev;
|
|
2377
2436
|
};
|
|
2378
2437
|
}, [isOpen]);
|
|
2438
|
+
useEffect7(() => {
|
|
2439
|
+
if (!isOpen || !containerRef?.current) return;
|
|
2440
|
+
const container = containerRef.current;
|
|
2441
|
+
const focusable = container.querySelectorAll(
|
|
2442
|
+
'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'
|
|
2443
|
+
);
|
|
2444
|
+
if (focusable.length > 0) focusable[0].focus();
|
|
2445
|
+
const handler = (e) => {
|
|
2446
|
+
if (e.key !== "Tab") return;
|
|
2447
|
+
const nodes = container.querySelectorAll(
|
|
2448
|
+
'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'
|
|
2449
|
+
);
|
|
2450
|
+
if (nodes.length === 0) return;
|
|
2451
|
+
const first = nodes[0];
|
|
2452
|
+
const last = nodes[nodes.length - 1];
|
|
2453
|
+
if (e.shiftKey) {
|
|
2454
|
+
if (document.activeElement === first) {
|
|
2455
|
+
e.preventDefault();
|
|
2456
|
+
last.focus();
|
|
2457
|
+
}
|
|
2458
|
+
} else {
|
|
2459
|
+
if (document.activeElement === last) {
|
|
2460
|
+
e.preventDefault();
|
|
2461
|
+
first.focus();
|
|
2462
|
+
}
|
|
2463
|
+
}
|
|
2464
|
+
};
|
|
2465
|
+
document.addEventListener("keydown", handler);
|
|
2466
|
+
return () => document.removeEventListener("keydown", handler);
|
|
2467
|
+
}, [isOpen, containerRef]);
|
|
2379
2468
|
}
|
|
2380
2469
|
|
|
2381
2470
|
// components/ui/modal.tsx
|
|
@@ -2395,21 +2484,25 @@ var KIND_ICON = {
|
|
|
2395
2484
|
};
|
|
2396
2485
|
function Modal({ isOpen, onClose, title, children, kind = "info", size = "md", hideCloseButton = false, headerActions, testId }) {
|
|
2397
2486
|
const modalRef = useRef9(null);
|
|
2398
|
-
|
|
2487
|
+
const titleId = useId2();
|
|
2488
|
+
useModalBehavior(isOpen, onClose, modalRef);
|
|
2399
2489
|
if (!isOpen) return null;
|
|
2400
2490
|
return createPortal3(
|
|
2401
2491
|
/* @__PURE__ */ jsxs14("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
|
|
2402
|
-
/* @__PURE__ */ jsx20("div", { className: "absolute inset-0 bg-[var(--dialog-backdrop)]
|
|
2492
|
+
/* @__PURE__ */ jsx20("div", { className: "absolute inset-0 bg-[var(--dialog-backdrop)]", onClick: onClose, "aria-hidden": "true" }),
|
|
2403
2493
|
/* @__PURE__ */ jsxs14(
|
|
2404
2494
|
"div",
|
|
2405
2495
|
{
|
|
2406
2496
|
ref: modalRef,
|
|
2497
|
+
role: "dialog",
|
|
2498
|
+
"aria-modal": "true",
|
|
2499
|
+
"aria-labelledby": titleId,
|
|
2407
2500
|
"data-testid": testId,
|
|
2408
|
-
className: `relative bg-neutral-900 border border-neutral-700 rounded-xl shadow-
|
|
2501
|
+
className: `relative bg-neutral-900 border border-neutral-700 rounded-xl shadow-lg ${SIZE_CLASSES2[size]} w-full mx-4 overflow-hidden`,
|
|
2409
2502
|
children: [
|
|
2410
2503
|
/* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-3 px-5 py-4 border-b border-neutral-800", children: [
|
|
2411
2504
|
KIND_ICON[kind],
|
|
2412
|
-
/* @__PURE__ */ jsx20("h3", { className: "text-lg font-semibold text-white flex-1", children: title }),
|
|
2505
|
+
/* @__PURE__ */ jsx20("h3", { id: titleId, className: "text-lg font-semibold text-white flex-1 min-w-0 truncate", children: title }),
|
|
2413
2506
|
headerActions?.map((a, i) => /* @__PURE__ */ jsx20(IconButton, { ...a }, i)),
|
|
2414
2507
|
!hideCloseButton && /* @__PURE__ */ jsx20(
|
|
2415
2508
|
IconButton,
|
|
@@ -2504,15 +2597,9 @@ function AlertModal({
|
|
|
2504
2597
|
}
|
|
2505
2598
|
|
|
2506
2599
|
// components/ui/action-dialog.tsx
|
|
2600
|
+
import { useId as useId3, useRef as useRef10 } from "react";
|
|
2507
2601
|
import { createPortal as createPortal4 } from "react-dom";
|
|
2508
2602
|
|
|
2509
|
-
// components/lib/cn.ts
|
|
2510
|
-
import { clsx } from "clsx";
|
|
2511
|
-
import { twMerge } from "tailwind-merge";
|
|
2512
|
-
function cn(...inputs) {
|
|
2513
|
-
return twMerge(clsx(inputs));
|
|
2514
|
-
}
|
|
2515
|
-
|
|
2516
2603
|
// components/ui/selection-grid.tsx
|
|
2517
2604
|
import { jsx as jsx21, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2518
2605
|
function makeToolLogo(toolKey) {
|
|
@@ -2623,6 +2710,8 @@ function GridCard({ item, selected, onClick }) {
|
|
|
2623
2710
|
"button",
|
|
2624
2711
|
{
|
|
2625
2712
|
type: "button",
|
|
2713
|
+
"aria-pressed": selected,
|
|
2714
|
+
"aria-label": item.name,
|
|
2626
2715
|
onClick,
|
|
2627
2716
|
disabled: item.disabled,
|
|
2628
2717
|
className: cn(
|
|
@@ -2651,6 +2740,8 @@ function ListCard({ item, selected, onClick }) {
|
|
|
2651
2740
|
"button",
|
|
2652
2741
|
{
|
|
2653
2742
|
type: "button",
|
|
2743
|
+
"aria-pressed": selected,
|
|
2744
|
+
"aria-label": item.name,
|
|
2654
2745
|
onClick,
|
|
2655
2746
|
disabled: item.disabled,
|
|
2656
2747
|
className: cn(
|
|
@@ -2762,7 +2853,9 @@ function ActionDialog({
|
|
|
2762
2853
|
children,
|
|
2763
2854
|
className
|
|
2764
2855
|
}) {
|
|
2765
|
-
|
|
2856
|
+
const dialogRef = useRef10(null);
|
|
2857
|
+
const titleId = useId3();
|
|
2858
|
+
useModalBehavior(true, () => onCancel?.(), dialogRef);
|
|
2766
2859
|
const Icon = icon ? iconMap[icon] : null;
|
|
2767
2860
|
const hasSelection = (items && items.length > 0 || presets && presets.length > 0) && selectedIds && onSelect;
|
|
2768
2861
|
const hasScenarios = scenarios && scenarios.length > 0 && selectedScenarioIds && onSelectScenarios;
|
|
@@ -2778,12 +2871,16 @@ function ActionDialog({
|
|
|
2778
2871
|
}
|
|
2779
2872
|
return createPortal4(
|
|
2780
2873
|
/* @__PURE__ */ jsxs17("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
|
|
2781
|
-
/* @__PURE__ */ jsx23("div", { className: "absolute inset-0 bg-[var(--dialog-backdrop)]
|
|
2874
|
+
/* @__PURE__ */ jsx23("div", { className: "absolute inset-0 bg-[var(--dialog-backdrop)]", onClick: onCancel, "aria-hidden": "true" }),
|
|
2782
2875
|
/* @__PURE__ */ jsxs17(
|
|
2783
2876
|
"div",
|
|
2784
2877
|
{
|
|
2878
|
+
ref: dialogRef,
|
|
2879
|
+
role: "dialog",
|
|
2880
|
+
"aria-modal": "true",
|
|
2881
|
+
"aria-labelledby": titleId,
|
|
2785
2882
|
className: cn(
|
|
2786
|
-
"relative bg-neutral-950 border border-neutral-700 rounded-xl shadow-
|
|
2883
|
+
"relative bg-neutral-950 border border-neutral-700 rounded-xl shadow-lg w-full max-w-[800px] mx-4 flex flex-col",
|
|
2787
2884
|
"max-h-[80vh]",
|
|
2788
2885
|
className
|
|
2789
2886
|
),
|
|
@@ -2796,9 +2893,9 @@ function ActionDialog({
|
|
|
2796
2893
|
style: iconColor ? { color: iconColor } : void 0
|
|
2797
2894
|
}
|
|
2798
2895
|
),
|
|
2799
|
-
/* @__PURE__ */ jsxs17("div", { className: "flex flex-col", children: [
|
|
2800
|
-
/* @__PURE__ */ jsx23("span", { className: "text-md font-semibold text-neutral-200", children: title }),
|
|
2801
|
-
subtitle && /* @__PURE__ */ jsx23("span", { className: "text-sm text-neutral-500", children: subtitle })
|
|
2896
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex flex-col min-w-0", children: [
|
|
2897
|
+
/* @__PURE__ */ jsx23("span", { id: titleId, className: "text-md font-semibold text-neutral-200 truncate", children: title }),
|
|
2898
|
+
subtitle && /* @__PURE__ */ jsx23("span", { className: "text-sm text-neutral-500 truncate", children: subtitle })
|
|
2802
2899
|
] }),
|
|
2803
2900
|
/* @__PURE__ */ jsx23("div", { className: "flex-1" }),
|
|
2804
2901
|
onSettings && /* @__PURE__ */ jsx23(
|
|
@@ -2927,7 +3024,7 @@ function collectDirPaths(nodes, rootName, prefix = "") {
|
|
|
2927
3024
|
function FileTree({ nodes, rootName, selectedPath, onSelectFile, prefix = "", expandedPaths, onTogglePath, accentColor = "blue" }) {
|
|
2928
3025
|
if (rootName) {
|
|
2929
3026
|
const rootNode = { name: rootName, type: "directory", children: nodes };
|
|
2930
|
-
return /* @__PURE__ */ jsx24("ul", { className: "space-y-0.5", children: /* @__PURE__ */ jsx24(
|
|
3027
|
+
return /* @__PURE__ */ jsx24("ul", { role: "tree", className: "space-y-0.5", children: /* @__PURE__ */ jsx24(
|
|
2931
3028
|
FileTreeNodeItem,
|
|
2932
3029
|
{
|
|
2933
3030
|
node: rootNode,
|
|
@@ -2940,7 +3037,7 @@ function FileTree({ nodes, rootName, selectedPath, onSelectFile, prefix = "", ex
|
|
|
2940
3037
|
}
|
|
2941
3038
|
) });
|
|
2942
3039
|
}
|
|
2943
|
-
return /* @__PURE__ */ jsx24("ul", { className: "space-y-0.5", children: nodes.filter(nodeHasFiles).map((node) => {
|
|
3040
|
+
return /* @__PURE__ */ jsx24("ul", { role: "tree", className: "space-y-0.5", children: nodes.filter(nodeHasFiles).map((node) => {
|
|
2944
3041
|
const fullPath = prefix ? `${prefix}/${node.name}` : node.name;
|
|
2945
3042
|
return /* @__PURE__ */ jsx24(
|
|
2946
3043
|
FileTreeNodeItem,
|
|
@@ -2965,7 +3062,7 @@ function FileTreeNodeItem({ node, path, selectedPath, onSelectFile, expandedPath
|
|
|
2965
3062
|
const selectedClass = ACCENT_SELECTED[accentColor] ?? ACCENT_SELECTED.blue;
|
|
2966
3063
|
const iconColorClass = ACCENT_ICON[accentColor] ?? ACCENT_ICON.blue;
|
|
2967
3064
|
const rowClass = isSelected ? `${base} ${selectedClass}` : isDir ? `${base} cursor-pointer text-white hover:text-neutral-200` : `${base} cursor-pointer text-white hover:bg-neutral-700/50 hover:text-neutral-200`;
|
|
2968
|
-
return /* @__PURE__ */ jsxs18("li", { children: [
|
|
3065
|
+
return /* @__PURE__ */ jsxs18("li", { role: "treeitem", "aria-expanded": isDir ? expanded : void 0, "aria-selected": isSelected, children: [
|
|
2969
3066
|
/* @__PURE__ */ jsxs18(
|
|
2970
3067
|
"button",
|
|
2971
3068
|
{
|
|
@@ -2978,7 +3075,7 @@ function FileTreeNodeItem({ node, path, selectedPath, onSelectFile, expandedPath
|
|
|
2978
3075
|
]
|
|
2979
3076
|
}
|
|
2980
3077
|
),
|
|
2981
|
-
isDir && expanded && node.children && /* @__PURE__ */ jsx24("ul", { className: "ml-4 space-y-0.5", children: node.children.filter(nodeHasFiles).map((child) => {
|
|
3078
|
+
isDir && expanded && node.children && /* @__PURE__ */ jsx24("ul", { role: "group", className: "ml-4 space-y-0.5", children: node.children.filter(nodeHasFiles).map((child) => {
|
|
2982
3079
|
const childPath = `${path}/${child.name}`;
|
|
2983
3080
|
return /* @__PURE__ */ jsx24(
|
|
2984
3081
|
FileTreeNodeItem,
|
|
@@ -3090,7 +3187,7 @@ function EditorToolbar({
|
|
|
3090
3187
|
}
|
|
3091
3188
|
|
|
3092
3189
|
// components/ui/bottom-panel-header.tsx
|
|
3093
|
-
import { useState as useState10, useRef as
|
|
3190
|
+
import { useState as useState10, useRef as useRef11, useEffect as useEffect8, useCallback as useCallback5 } from "react";
|
|
3094
3191
|
import { RefreshCw as RefreshCw2 } from "lucide-react";
|
|
3095
3192
|
import { Fragment as Fragment6, jsx as jsx26, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
3096
3193
|
var DEFAULT_ACTIVE_TEXT = "text-neutral-300";
|
|
@@ -3118,8 +3215,8 @@ function BottomPanelHeader({
|
|
|
3118
3215
|
statusBanner,
|
|
3119
3216
|
onCollapse
|
|
3120
3217
|
}) {
|
|
3121
|
-
const containerRef =
|
|
3122
|
-
const actionsRef =
|
|
3218
|
+
const containerRef = useRef11(null);
|
|
3219
|
+
const actionsRef = useRef11(null);
|
|
3123
3220
|
const [layoutMode, setLayoutMode] = useState10("full");
|
|
3124
3221
|
const computeLayout = useCallback5(() => {
|
|
3125
3222
|
const container = containerRef.current;
|
|
@@ -3264,7 +3361,7 @@ function FrontmatterFormHeader({
|
|
|
3264
3361
|
}
|
|
3265
3362
|
|
|
3266
3363
|
// components/ui/editor-placeholder-card.tsx
|
|
3267
|
-
import { useState as useState11, useRef as
|
|
3364
|
+
import { useState as useState11, useRef as useRef12, useLayoutEffect as useLayoutEffect3 } from "react";
|
|
3268
3365
|
import { Fragment as Fragment7, jsx as jsx28, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
3269
3366
|
var COLORS = {
|
|
3270
3367
|
purple: {
|
|
@@ -3301,7 +3398,7 @@ function EditorPlaceholderCard({
|
|
|
3301
3398
|
const [isPlaceholderCopied, setIsPlaceholderCopied] = useState11(false);
|
|
3302
3399
|
const [isValueCopied, setIsValueCopied] = useState11(false);
|
|
3303
3400
|
const [isOverflowing, setIsOverflowing] = useState11(false);
|
|
3304
|
-
const valueRef =
|
|
3401
|
+
const valueRef = useRef12(null);
|
|
3305
3402
|
const colors = COLORS[accentColor];
|
|
3306
3403
|
const hasValue = !!value;
|
|
3307
3404
|
useLayoutEffect3(() => {
|
|
@@ -3927,11 +4024,11 @@ function RegistryCard(props) {
|
|
|
3927
4024
|
}
|
|
3928
4025
|
|
|
3929
4026
|
// components/ui/registry-detail.tsx
|
|
3930
|
-
import { useState as useState14, useRef as
|
|
4027
|
+
import { useState as useState14, useRef as useRef14, useEffect as useEffect10, useCallback as useCallback7 } from "react";
|
|
3931
4028
|
import { ChevronsUpDown as ChevronsUpDown2, ChevronsDownUp as ChevronsDownUp2 } from "lucide-react";
|
|
3932
4029
|
|
|
3933
4030
|
// components/ui/file-structure-section.tsx
|
|
3934
|
-
import { useState as useState13, useEffect as useEffect9, useCallback as useCallback6, useRef as
|
|
4031
|
+
import { useState as useState13, useEffect as useEffect9, useCallback as useCallback6, useRef as useRef13, useMemo } from "react";
|
|
3935
4032
|
import { FileCode as FileCode3, FolderTree, Loader2 as Loader23, AlertCircle as AlertCircle3, AlignLeft, Code2, Type } from "lucide-react";
|
|
3936
4033
|
import { jsx as jsx31, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
3937
4034
|
var ACCENT_BORDER = {
|
|
@@ -4102,10 +4199,10 @@ function FileStructureSection({
|
|
|
4102
4199
|
}, []);
|
|
4103
4200
|
const allCollapsed = expandedPaths.size === 0;
|
|
4104
4201
|
const [treeHeight, setTreeHeight] = useState13(null);
|
|
4105
|
-
const sectionRef =
|
|
4106
|
-
const resizing =
|
|
4107
|
-
const startY =
|
|
4108
|
-
const startHeight =
|
|
4202
|
+
const sectionRef = useRef13(null);
|
|
4203
|
+
const resizing = useRef13(false);
|
|
4204
|
+
const startY = useRef13(0);
|
|
4205
|
+
const startHeight = useRef13(0);
|
|
4109
4206
|
useEffect9(() => {
|
|
4110
4207
|
if (variant === "list" || treeHeight !== null || !sectionRef.current) return;
|
|
4111
4208
|
const el = sectionRef.current;
|
|
@@ -4299,7 +4396,7 @@ import { jsx as jsx32, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
|
4299
4396
|
var MARKDOWN_CLASSES = "text-md text-neutral-400 leading-relaxed [&_strong]:text-neutral-200 [&_code]:px-1.5 [&_code]:py-0.5 [&_code]:rounded [&_code]:bg-neutral-700/40 [&_code]:border [&_code]:border-neutral-500/40 [&_code]:text-neutral-200 [&_code]:font-mono [&_code]:text-sm [&_h1]:text-lg [&_h1]:font-semibold [&_h1]:text-neutral-200 [&_h1]:mb-2 [&_h2]:text-base [&_h2]:font-semibold [&_h2]:text-neutral-200 [&_h2]:mb-2 [&_h3]:text-md [&_h3]:font-medium [&_h3]:text-neutral-200 [&_h3]:mb-1 [&_ul]:list-disc [&_ul]:pl-4 [&_ol]:list-decimal [&_ol]:pl-4 [&_li]:mb-1 [&_p]:mb-2 [&_pre]:bg-neutral-900 [&_pre]:rounded [&_pre]:p-3 [&_pre]:overflow-x-auto [&_pre]:text-sm";
|
|
4300
4397
|
var COLLAPSED_MAX_HEIGHT = 240;
|
|
4301
4398
|
function CollapsibleTextSection({ children, header }) {
|
|
4302
|
-
const contentRef =
|
|
4399
|
+
const contentRef = useRef14(null);
|
|
4303
4400
|
const [overflows, setOverflows] = useState14(false);
|
|
4304
4401
|
const [expanded, setExpanded] = useState14(false);
|
|
4305
4402
|
const measure = useCallback7(() => {
|
|
@@ -4416,7 +4513,7 @@ function RegistryDetail({
|
|
|
4416
4513
|
}
|
|
4417
4514
|
|
|
4418
4515
|
// components/ui/registry-browser.tsx
|
|
4419
|
-
import { useState as useState15, useEffect as useEffect11, useRef as
|
|
4516
|
+
import { useState as useState15, useEffect as useEffect11, useRef as useRef15, useCallback as useCallback8 } from "react";
|
|
4420
4517
|
import { Search as Search4, ArrowRight as ArrowRight2, RefreshCw as RefreshCw3, Loader2 as Loader24, X as X4, AlertTriangle as AlertTriangle4 } from "lucide-react";
|
|
4421
4518
|
import { jsx as jsx33, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
4422
4519
|
var PAGE_SIZE = 60;
|
|
@@ -4448,10 +4545,10 @@ function RegistryBrowser({
|
|
|
4448
4545
|
const totalCount = items.length;
|
|
4449
4546
|
const needsPaging = totalCount > PAGE_SIZE;
|
|
4450
4547
|
const [visibleCount, setVisibleCount] = useState15(PAGE_SIZE);
|
|
4451
|
-
const scrollRef =
|
|
4452
|
-
const sentinelRef =
|
|
4453
|
-
const isFirstRender =
|
|
4454
|
-
const prevTotalCount =
|
|
4548
|
+
const scrollRef = useRef15(null);
|
|
4549
|
+
const sentinelRef = useRef15(null);
|
|
4550
|
+
const isFirstRender = useRef15(true);
|
|
4551
|
+
const prevTotalCount = useRef15(totalCount);
|
|
4455
4552
|
useEffect11(() => {
|
|
4456
4553
|
setVisibleCount(PAGE_SIZE);
|
|
4457
4554
|
}, [totalCount]);
|
|
@@ -4471,7 +4568,7 @@ function RegistryBrowser({
|
|
|
4471
4568
|
prevTotalCount.current = totalCount;
|
|
4472
4569
|
}
|
|
4473
4570
|
}, [totalCount, initialScrollTop]);
|
|
4474
|
-
const scrollTimerRef =
|
|
4571
|
+
const scrollTimerRef = useRef15(void 0);
|
|
4475
4572
|
const handleScroll = useCallback8(() => {
|
|
4476
4573
|
if (!onScrollChange) return;
|
|
4477
4574
|
clearTimeout(scrollTimerRef.current);
|
|
@@ -4639,7 +4736,6 @@ function AiActionButton({
|
|
|
4639
4736
|
return tooltip;
|
|
4640
4737
|
}, [tooltip, forceDisabled, disabledReason, isRunning, isCompleted, runningTooltipTitle, completedTooltipTitle]);
|
|
4641
4738
|
const isDisabled = forceDisabled;
|
|
4642
|
-
const blinkClass = isCompleted ? "animate-pulse" : "";
|
|
4643
4739
|
return /* @__PURE__ */ jsx34(
|
|
4644
4740
|
IconButton,
|
|
4645
4741
|
{
|
|
@@ -4650,8 +4746,8 @@ function AiActionButton({
|
|
|
4650
4746
|
onClick: isDisabled ? () => {
|
|
4651
4747
|
} : onClick,
|
|
4652
4748
|
tooltip: resolvedTooltip,
|
|
4653
|
-
active: isRunning,
|
|
4654
|
-
className
|
|
4749
|
+
active: isRunning || isCompleted,
|
|
4750
|
+
className,
|
|
4655
4751
|
testId
|
|
4656
4752
|
}
|
|
4657
4753
|
);
|
|
@@ -4745,7 +4841,7 @@ function AiExecutionActionButtons({
|
|
|
4745
4841
|
import { Loader2 as Loader25, Send as Send2 } from "lucide-react";
|
|
4746
4842
|
|
|
4747
4843
|
// components/sections/report-bug/screenshot-uploader.tsx
|
|
4748
|
-
import { useCallback as useCallback9, useRef as
|
|
4844
|
+
import { useCallback as useCallback9, useRef as useRef16, useState as useState16 } from "react";
|
|
4749
4845
|
import { ImagePlus, X as X5, AlertCircle as AlertCircle4 } from "lucide-react";
|
|
4750
4846
|
import { jsx as jsx36, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
4751
4847
|
var DEFAULT_MAX_SIZE = 20 * 1024 * 1024;
|
|
@@ -4761,7 +4857,7 @@ function ScreenshotUploader({
|
|
|
4761
4857
|
disabled = false,
|
|
4762
4858
|
className
|
|
4763
4859
|
}) {
|
|
4764
|
-
const fileInputRef =
|
|
4860
|
+
const fileInputRef = useRef16(null);
|
|
4765
4861
|
const [isDragging, setIsDragging] = useState16(false);
|
|
4766
4862
|
const [error, setError] = useState16(null);
|
|
4767
4863
|
const totalSize = screenshots.reduce((sum, s) => sum + s.size, 0);
|
|
@@ -5901,7 +5997,7 @@ import { useState as useState22, useEffect as useEffect13 } from "react";
|
|
|
5901
5997
|
import { RefreshCw as RefreshCw4, AlertCircle as AlertCircle5, Check as Check9, Activity, GitCompareArrows, Archive as Archive3, Tag as Tag3 } from "lucide-react";
|
|
5902
5998
|
|
|
5903
5999
|
// components/sections/golden-snapshots/status-overview.tsx
|
|
5904
|
-
import { useState as useState19, useRef as
|
|
6000
|
+
import { useState as useState19, useRef as useRef17 } from "react";
|
|
5905
6001
|
import { Archive, Check as Check8, AlertTriangle as AlertTriangle5, RotateCcw as RotateCcw2 } from "lucide-react";
|
|
5906
6002
|
import { jsx as jsx38, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
5907
6003
|
function getComponentVersion(meta, component) {
|
|
@@ -5952,7 +6048,7 @@ function StatusOverview({
|
|
|
5952
6048
|
}) {
|
|
5953
6049
|
const anyResetting = resettingComponent !== null || resettingAll;
|
|
5954
6050
|
const [showResetMenu, setShowResetMenu] = useState19(false);
|
|
5955
|
-
const resetMenuRef =
|
|
6051
|
+
const resetMenuRef = useRef17(null);
|
|
5956
6052
|
const resetMenuDropdownRef = useDropdownMaxHeight(showResetMenu);
|
|
5957
6053
|
useClickOutside(resetMenuRef, showResetMenu, () => setShowResetMenu(false));
|
|
5958
6054
|
const getLabel = (comp) => componentLabels?.[comp] ?? comp.charAt(0).toUpperCase() + comp.slice(1);
|
|
@@ -6023,7 +6119,7 @@ function StatusOverview({
|
|
|
6023
6119
|
tooltip: { title: "Reset options", description: "Reset live files to golden" }
|
|
6024
6120
|
}
|
|
6025
6121
|
),
|
|
6026
|
-
showResetMenu && /* @__PURE__ */ jsxs31("div", { ref: resetMenuDropdownRef, className: "absolute right-0 top-full mt-1 w-56 bg-neutral-850 border border-neutral-700 rounded-lg shadow-
|
|
6122
|
+
showResetMenu && /* @__PURE__ */ jsxs31("div", { ref: resetMenuDropdownRef, className: "absolute right-0 top-full mt-1 w-56 bg-neutral-850 border border-neutral-700 rounded-lg shadow-lg z-50 py-1 overflow-hidden", children: [
|
|
6027
6123
|
/* @__PURE__ */ jsx38(
|
|
6028
6124
|
"button",
|
|
6029
6125
|
{
|
|
@@ -6409,7 +6505,7 @@ function FileDiffViewer({ sync, componentLabels, monacoTheme, renderFileIcon })
|
|
|
6409
6505
|
devtools && hasUnsavedChanges && /* @__PURE__ */ jsx39(
|
|
6410
6506
|
IconButton,
|
|
6411
6507
|
{
|
|
6412
|
-
icon: /* @__PURE__ */ jsx39(Save2, { className: saving ? "animate-
|
|
6508
|
+
icon: /* @__PURE__ */ jsx39(Save2, { className: saving ? "animate-spin" : "" }),
|
|
6413
6509
|
onClick: handleSaveLiveFile,
|
|
6414
6510
|
disabled: saving,
|
|
6415
6511
|
color: "amber",
|
|
@@ -6943,13 +7039,13 @@ function GoldenSyncPanel({
|
|
|
6943
7039
|
import { Check as Check10, X as X6, RefreshCw as RefreshCw5, Terminal as Terminal3 } from "lucide-react";
|
|
6944
7040
|
|
|
6945
7041
|
// components/sections/ai-tools-paths/use-tools-paths.ts
|
|
6946
|
-
import { useState as useState23, useCallback as useCallback12, useRef as
|
|
7042
|
+
import { useState as useState23, useCallback as useCallback12, useRef as useRef18, useEffect as useEffect14 } from "react";
|
|
6947
7043
|
function useToolsPaths({ api, tools, onToolConfigChange }) {
|
|
6948
7044
|
const [isDetecting, setIsDetecting] = useState23(false);
|
|
6949
7045
|
const [hasScanned, setHasScanned] = useState23(false);
|
|
6950
7046
|
const [refreshingTools, setRefreshingTools] = useState23(/* @__PURE__ */ new Set());
|
|
6951
7047
|
const [scannedTools, setScannedTools] = useState23(/* @__PURE__ */ new Set());
|
|
6952
|
-
const wasDetectingRef =
|
|
7048
|
+
const wasDetectingRef = useRef18(false);
|
|
6953
7049
|
useEffect14(() => {
|
|
6954
7050
|
if (wasDetectingRef.current && !isDetecting) {
|
|
6955
7051
|
setHasScanned(true);
|
|
@@ -7734,7 +7830,7 @@ function SnapshotTree({
|
|
|
7734
7830
|
}
|
|
7735
7831
|
|
|
7736
7832
|
// components/sections/snapshot-browser/use-snapshot-browser.ts
|
|
7737
|
-
import { useState as useState25, useMemo as useMemo6, useEffect as useEffect16, useRef as
|
|
7833
|
+
import { useState as useState25, useMemo as useMemo6, useEffect as useEffect16, useRef as useRef19, useCallback as useCallback14 } from "react";
|
|
7738
7834
|
function collectExpandablePaths(scopes) {
|
|
7739
7835
|
const paths = [];
|
|
7740
7836
|
for (const scope of scopes) {
|
|
@@ -7765,7 +7861,7 @@ function useSnapshotBrowser({ scopes, api }) {
|
|
|
7765
7861
|
const [searchQuery, setSearchQuery] = useState25("");
|
|
7766
7862
|
const [expandedPaths, setExpandedPaths] = useState25(() => /* @__PURE__ */ new Set());
|
|
7767
7863
|
const [deletingSnapshotId, setDeletingSnapshotId] = useState25(null);
|
|
7768
|
-
const prevSearchRef =
|
|
7864
|
+
const prevSearchRef = useRef19("");
|
|
7769
7865
|
const allExpandablePaths = useMemo6(() => collectExpandablePaths(scopes), [scopes]);
|
|
7770
7866
|
const totalSnapshotCount = useMemo6(() => countSnapshots(scopes), [scopes]);
|
|
7771
7867
|
const allExpanded = allExpandablePaths.length > 0 && allExpandablePaths.every((p) => expandedPaths.has(p));
|
|
@@ -7911,10 +8007,10 @@ function SnapshotBrowserPanel({
|
|
|
7911
8007
|
}
|
|
7912
8008
|
|
|
7913
8009
|
// components/hooks/use-resizable-sidebar.ts
|
|
7914
|
-
import { useState as useState26, useCallback as useCallback15, useRef as
|
|
8010
|
+
import { useState as useState26, useCallback as useCallback15, useRef as useRef20 } from "react";
|
|
7915
8011
|
function useResizableSidebar({ min, max, defaultWidth, direction = "right" }) {
|
|
7916
8012
|
const [width, setWidth] = useState26(defaultWidth);
|
|
7917
|
-
const widthRef =
|
|
8013
|
+
const widthRef = useRef20(defaultWidth);
|
|
7918
8014
|
const onPointerDown = useCallback15((e) => {
|
|
7919
8015
|
e.preventDefault();
|
|
7920
8016
|
const el = e.currentTarget;
|
|
@@ -8402,7 +8498,7 @@ function SnippetForm({
|
|
|
8402
8498
|
}
|
|
8403
8499
|
|
|
8404
8500
|
// components/sections/prompt-editor/tabbed-prompt-editor.tsx
|
|
8405
|
-
import { useState as useState28, useRef as
|
|
8501
|
+
import { useState as useState28, useRef as useRef21, useCallback as useCallback17, useEffect as useEffect17, useMemo as useMemo8 } from "react";
|
|
8406
8502
|
import Editor2 from "@monaco-editor/react";
|
|
8407
8503
|
import { Variable, Info as Info4, Search as Search6, X as X10, AlertTriangle as AlertTriangle7 } from "lucide-react";
|
|
8408
8504
|
import { jsx as jsx48, jsxs as jsxs41 } from "react/jsx-runtime";
|
|
@@ -8426,10 +8522,10 @@ function TabbedPromptEditor({
|
|
|
8426
8522
|
const [variableSearch, setVariableSearch] = useState28("");
|
|
8427
8523
|
const [localContent, setLocalContent] = useState28(prompts);
|
|
8428
8524
|
const [isDirty, setIsDirty] = useState28(false);
|
|
8429
|
-
const editorRef =
|
|
8430
|
-
const monacoRef =
|
|
8431
|
-
const decorationsRef =
|
|
8432
|
-
const completionProviderRef =
|
|
8525
|
+
const editorRef = useRef21(null);
|
|
8526
|
+
const monacoRef = useRef21(null);
|
|
8527
|
+
const decorationsRef = useRef21([]);
|
|
8528
|
+
const completionProviderRef = useRef21(null);
|
|
8433
8529
|
useEffect17(() => {
|
|
8434
8530
|
setLocalContent(prompts);
|
|
8435
8531
|
setIsDirty(false);
|
|
@@ -9004,6 +9100,7 @@ function CollapsibleSection({
|
|
|
9004
9100
|
"button",
|
|
9005
9101
|
{
|
|
9006
9102
|
type: "button",
|
|
9103
|
+
"aria-expanded": open,
|
|
9007
9104
|
onClick: () => setOpen(!open),
|
|
9008
9105
|
className: "flex w-full items-center gap-2 py-2.5 px-1 text-left hover:bg-neutral-700/30 transition-colors cursor-pointer",
|
|
9009
9106
|
children: [
|
|
@@ -9398,7 +9495,7 @@ function Breadcrumb({
|
|
|
9398
9495
|
}) {
|
|
9399
9496
|
const s = sizeConfig2[size];
|
|
9400
9497
|
const isBox = variant === "box";
|
|
9401
|
-
return /* @__PURE__ */ jsx54("nav", { className: cn("flex items-center", className), children: /* @__PURE__ */ jsx54("div", { className: cn(
|
|
9498
|
+
return /* @__PURE__ */ jsx54("nav", { className: cn("flex items-center min-w-0", className), children: /* @__PURE__ */ jsx54("div", { className: cn(
|
|
9402
9499
|
"flex items-center gap-1",
|
|
9403
9500
|
isBox && [s.px, s.py, "bg-neutral-800/50 border border-neutral-700/50 rounded-lg"]
|
|
9404
9501
|
), children: segments.map((segment, index) => {
|
|
@@ -9406,7 +9503,7 @@ function Breadcrumb({
|
|
|
9406
9503
|
const isClickable = !isLast && !!segment.onClick;
|
|
9407
9504
|
const colors = segment.color && ACCENT_NAV[segment.color] ? ACCENT_NAV[segment.color] : null;
|
|
9408
9505
|
const isFirstPlain = !isBox && index === 0;
|
|
9409
|
-
return /* @__PURE__ */ jsxs47("div", { className: "flex items-center gap-1", children: [
|
|
9506
|
+
return /* @__PURE__ */ jsxs47("div", { className: "flex items-center gap-1 min-w-0", children: [
|
|
9410
9507
|
index > 0 && /* @__PURE__ */ jsx54(Separator, { type: separator, size }),
|
|
9411
9508
|
isClickable ? /* @__PURE__ */ jsxs47(
|
|
9412
9509
|
"button",
|
|
@@ -9414,7 +9511,7 @@ function Breadcrumb({
|
|
|
9414
9511
|
type: "button",
|
|
9415
9512
|
onClick: segment.onClick,
|
|
9416
9513
|
className: cn(
|
|
9417
|
-
"flex items-center gap-1.5 pr-2 py-0.5 rounded-md transition-colors cursor-pointer",
|
|
9514
|
+
"flex items-center gap-1.5 pr-2 py-0.5 rounded-md transition-colors cursor-pointer min-w-0",
|
|
9418
9515
|
isFirstPlain ? "pl-0" : "pl-2",
|
|
9419
9516
|
s.text,
|
|
9420
9517
|
"font-medium hover:text-white",
|
|
@@ -9422,14 +9519,14 @@ function Breadcrumb({
|
|
|
9422
9519
|
),
|
|
9423
9520
|
children: [
|
|
9424
9521
|
segment.icon && /* @__PURE__ */ jsx54(SegmentIcon, { icon: segment.icon, color: segment.color, size }),
|
|
9425
|
-
/* @__PURE__ */ jsx54("span", { children: segment.label })
|
|
9522
|
+
/* @__PURE__ */ jsx54("span", { className: "truncate max-w-[200px]", children: segment.label })
|
|
9426
9523
|
]
|
|
9427
9524
|
}
|
|
9428
9525
|
) : /* @__PURE__ */ jsxs47(
|
|
9429
9526
|
"div",
|
|
9430
9527
|
{
|
|
9431
9528
|
className: cn(
|
|
9432
|
-
"flex items-center gap-1.5 pr-2 py-0.5 rounded-md",
|
|
9529
|
+
"flex items-center gap-1.5 pr-2 py-0.5 rounded-md min-w-0",
|
|
9433
9530
|
isFirstPlain ? "pl-0" : "pl-2",
|
|
9434
9531
|
s.text,
|
|
9435
9532
|
isLast ? ["font-medium bg-neutral-700/50", colors ? colors.text : "text-white"] : ["font-medium", colors ? colors.text : "text-neutral-300"]
|
|
@@ -9445,7 +9542,7 @@ function Breadcrumb({
|
|
|
9445
9542
|
}
|
|
9446
9543
|
|
|
9447
9544
|
// components/ui/navigation-bar.tsx
|
|
9448
|
-
import { useState as useState34, useRef as
|
|
9545
|
+
import { useState as useState34, useRef as useRef22, useCallback as useCallback20 } from "react";
|
|
9449
9546
|
import { ChevronLeft as ChevronLeft2, ChevronRight as ChevronRight10, History as History2 } from "lucide-react";
|
|
9450
9547
|
import { Fragment as Fragment12, jsx as jsx55, jsxs as jsxs48 } from "react/jsx-runtime";
|
|
9451
9548
|
var sizeConfig3 = {
|
|
@@ -9505,7 +9602,7 @@ function NavigationBar({
|
|
|
9505
9602
|
const hasNav = !!(onBack || onForward);
|
|
9506
9603
|
const LeadIcon = leadingAction ? iconMap[leadingAction.icon] : null;
|
|
9507
9604
|
const [historyOpen, setHistoryOpen] = useState34(false);
|
|
9508
|
-
const historyRef =
|
|
9605
|
+
const historyRef = useRef22(null);
|
|
9509
9606
|
const closeHistory = useCallback20(() => setHistoryOpen(false), []);
|
|
9510
9607
|
useClickOutside(historyRef, historyOpen, closeHistory);
|
|
9511
9608
|
const hasHistoryEntries = historyEntries && historyEntries.length > 0;
|
|
@@ -9533,7 +9630,7 @@ function NavigationBar({
|
|
|
9533
9630
|
active: historyOpen
|
|
9534
9631
|
}
|
|
9535
9632
|
),
|
|
9536
|
-
historyOpen && hasHistoryEntries && /* @__PURE__ */ jsxs48("div", { className: "absolute left-0 top-full mt-1 w-max min-w-[200px] max-w-[420px] bg-neutral-800 border border-neutral-700 rounded-lg shadow-
|
|
9633
|
+
historyOpen && hasHistoryEntries && /* @__PURE__ */ jsxs48("div", { className: "absolute left-0 top-full mt-1 w-max min-w-[200px] max-w-[420px] bg-neutral-800 border border-neutral-700 rounded-lg shadow-lg z-50", children: [
|
|
9537
9634
|
/* @__PURE__ */ jsx55("div", { className: "px-3 py-1.5 border-b border-neutral-700/50", children: /* @__PURE__ */ jsx55("p", { className: "text-sm font-medium text-neutral-500", children: "History" }) }),
|
|
9538
9635
|
/* @__PURE__ */ jsx55("div", { className: "max-h-[300px] overflow-y-auto py-1", children: historyEntries.map((entry, i) => /* @__PURE__ */ jsx55(
|
|
9539
9636
|
"button",
|
|
@@ -9564,7 +9661,7 @@ function NavigationBar({
|
|
|
9564
9661
|
const isLast = index === segments.length - 1;
|
|
9565
9662
|
const isClickable = !isLast && !!segment.onClick;
|
|
9566
9663
|
const colors = segment.color && ACCENT_NAV[segment.color] ? ACCENT_NAV[segment.color] : null;
|
|
9567
|
-
return /* @__PURE__ */ jsxs48("div", { className: "flex items-center gap-1", children: [
|
|
9664
|
+
return /* @__PURE__ */ jsxs48("div", { className: "flex items-center gap-1 min-w-0", children: [
|
|
9568
9665
|
index > 0 && /* @__PURE__ */ jsx55(SegmentSeparator, { type: separator, size }),
|
|
9569
9666
|
isClickable ? /* @__PURE__ */ jsxs48(
|
|
9570
9667
|
"button",
|
|
@@ -9572,7 +9669,7 @@ function NavigationBar({
|
|
|
9572
9669
|
type: "button",
|
|
9573
9670
|
onClick: segment.onClick,
|
|
9574
9671
|
className: cn(
|
|
9575
|
-
"flex items-center gap-1.5 px-2 py-0.5 rounded-md transition-colors cursor-pointer",
|
|
9672
|
+
"flex items-center gap-1.5 px-2 py-0.5 rounded-md transition-colors cursor-pointer min-w-0",
|
|
9576
9673
|
s.text,
|
|
9577
9674
|
"font-medium hover:text-white",
|
|
9578
9675
|
colors ? [colors.text, `hover:${colors.bg}`] : ["text-neutral-300", "hover:bg-neutral-700/50"]
|
|
@@ -9586,7 +9683,7 @@ function NavigationBar({
|
|
|
9586
9683
|
"div",
|
|
9587
9684
|
{
|
|
9588
9685
|
className: cn(
|
|
9589
|
-
"flex items-center gap-1.5 px-2 py-0.5 rounded-md",
|
|
9686
|
+
"flex items-center gap-1.5 px-2 py-0.5 rounded-md min-w-0",
|
|
9590
9687
|
s.text,
|
|
9591
9688
|
isLast ? ["font-medium bg-neutral-700/50", colors ? colors.text : "text-white"] : ["font-medium", colors ? colors.text : "text-neutral-300"]
|
|
9592
9689
|
),
|
|
@@ -9602,7 +9699,7 @@ function NavigationBar({
|
|
|
9602
9699
|
}
|
|
9603
9700
|
|
|
9604
9701
|
// components/ui/tab-bar.tsx
|
|
9605
|
-
import { useRef as
|
|
9702
|
+
import { useRef as useRef23, useState as useState35, useEffect as useEffect18, useCallback as useCallback21 } from "react";
|
|
9606
9703
|
import { X as X11 } from "lucide-react";
|
|
9607
9704
|
import { jsx as jsx56, jsxs as jsxs49 } from "react/jsx-runtime";
|
|
9608
9705
|
var sizeConfig4 = {
|
|
@@ -9658,12 +9755,13 @@ function TabBadge({ badge, size, badgeColor }) {
|
|
|
9658
9755
|
const s = sizeConfig4[size];
|
|
9659
9756
|
return /* @__PURE__ */ jsx56(Badge, { value: badge, color: badgeColor, size: s.badgeSize, className: "flex-shrink-0" });
|
|
9660
9757
|
}
|
|
9661
|
-
function CloseButton({ size, onClick }) {
|
|
9758
|
+
function CloseButton({ size, onClick, tabLabel }) {
|
|
9662
9759
|
const s = sizeConfig4[size];
|
|
9663
9760
|
return /* @__PURE__ */ jsx56(
|
|
9664
9761
|
"button",
|
|
9665
9762
|
{
|
|
9666
9763
|
type: "button",
|
|
9764
|
+
"aria-label": `Close ${tabLabel}`,
|
|
9667
9765
|
onClick: (e) => {
|
|
9668
9766
|
e.stopPropagation();
|
|
9669
9767
|
onClick();
|
|
@@ -9691,6 +9789,8 @@ function CompactTab({
|
|
|
9691
9789
|
"button",
|
|
9692
9790
|
{
|
|
9693
9791
|
type: "button",
|
|
9792
|
+
role: "tab",
|
|
9793
|
+
"aria-selected": isActive,
|
|
9694
9794
|
onClick: onSelect,
|
|
9695
9795
|
className: cn(
|
|
9696
9796
|
"relative flex items-center justify-center transition-colors cursor-pointer",
|
|
@@ -9725,6 +9825,8 @@ function UnderlineTab({
|
|
|
9725
9825
|
"button",
|
|
9726
9826
|
{
|
|
9727
9827
|
type: "button",
|
|
9828
|
+
role: "tab",
|
|
9829
|
+
"aria-selected": isActive,
|
|
9728
9830
|
onClick: onSelect,
|
|
9729
9831
|
className: cn(
|
|
9730
9832
|
"group relative flex items-center whitespace-nowrap transition-colors cursor-pointer",
|
|
@@ -9739,7 +9841,7 @@ function UnderlineTab({
|
|
|
9739
9841
|
tab.icon && /* @__PURE__ */ jsx56(TabIcon, { icon: tab.icon, size, color: isActive ? tab.color : void 0 }),
|
|
9740
9842
|
/* @__PURE__ */ jsx56("span", { children: tab.label }),
|
|
9741
9843
|
tab.badge !== void 0 && /* @__PURE__ */ jsx56(TabBadge, { badge: tab.badge, size, badgeColor: tab.badgeColor }),
|
|
9742
|
-
showClose && /* @__PURE__ */ jsx56(CloseButton, { size, onClick: onClose }),
|
|
9844
|
+
showClose && /* @__PURE__ */ jsx56(CloseButton, { size, onClick: onClose, tabLabel: tab.label }),
|
|
9743
9845
|
isActive && /* @__PURE__ */ jsx56("span", { className: cn("absolute bottom-0 left-0 right-0 h-0.5 rounded-full", c.indicator) })
|
|
9744
9846
|
]
|
|
9745
9847
|
}
|
|
@@ -9759,6 +9861,8 @@ function PillTab({
|
|
|
9759
9861
|
"button",
|
|
9760
9862
|
{
|
|
9761
9863
|
type: "button",
|
|
9864
|
+
role: "tab",
|
|
9865
|
+
"aria-selected": isActive,
|
|
9762
9866
|
onClick: onSelect,
|
|
9763
9867
|
className: cn(
|
|
9764
9868
|
"group flex items-center whitespace-nowrap rounded-md transition-colors cursor-pointer",
|
|
@@ -9773,7 +9877,7 @@ function PillTab({
|
|
|
9773
9877
|
tab.icon && /* @__PURE__ */ jsx56(TabIcon, { icon: tab.icon, size, color: isActive ? tab.color : void 0 }),
|
|
9774
9878
|
/* @__PURE__ */ jsx56("span", { children: tab.label }),
|
|
9775
9879
|
tab.badge !== void 0 && /* @__PURE__ */ jsx56(TabBadge, { badge: tab.badge, size, badgeColor: tab.badgeColor }),
|
|
9776
|
-
showClose && /* @__PURE__ */ jsx56(CloseButton, { size, onClick: onClose })
|
|
9880
|
+
showClose && /* @__PURE__ */ jsx56(CloseButton, { size, onClick: onClose, tabLabel: tab.label })
|
|
9777
9881
|
]
|
|
9778
9882
|
}
|
|
9779
9883
|
);
|
|
@@ -9792,6 +9896,8 @@ function CardTab({
|
|
|
9792
9896
|
"button",
|
|
9793
9897
|
{
|
|
9794
9898
|
type: "button",
|
|
9899
|
+
role: "tab",
|
|
9900
|
+
"aria-selected": isActive,
|
|
9795
9901
|
onClick: onSelect,
|
|
9796
9902
|
className: cn(
|
|
9797
9903
|
"group relative flex items-center whitespace-nowrap transition-colors cursor-pointer rounded-t-lg border border-b-0",
|
|
@@ -9806,7 +9912,7 @@ function CardTab({
|
|
|
9806
9912
|
tab.icon && /* @__PURE__ */ jsx56(TabIcon, { icon: tab.icon, size, color: isActive ? tab.color : void 0 }),
|
|
9807
9913
|
/* @__PURE__ */ jsx56("span", { children: tab.label }),
|
|
9808
9914
|
tab.badge !== void 0 && /* @__PURE__ */ jsx56(TabBadge, { badge: tab.badge, size, badgeColor: tab.badgeColor }),
|
|
9809
|
-
showClose && /* @__PURE__ */ jsx56(CloseButton, { size, onClick: onClose }),
|
|
9915
|
+
showClose && /* @__PURE__ */ jsx56(CloseButton, { size, onClick: onClose, tabLabel: tab.label }),
|
|
9810
9916
|
isActive && /* @__PURE__ */ jsx56("span", { className: "absolute -bottom-px left-0 right-0 h-px bg-neutral-800" })
|
|
9811
9917
|
]
|
|
9812
9918
|
}
|
|
@@ -9826,7 +9932,7 @@ function TabBar({
|
|
|
9826
9932
|
size = "sm",
|
|
9827
9933
|
className
|
|
9828
9934
|
}) {
|
|
9829
|
-
const containerRef =
|
|
9935
|
+
const containerRef = useRef23(null);
|
|
9830
9936
|
const [compact, setCompact] = useState35(false);
|
|
9831
9937
|
const TabComponent = tabComponents[variant];
|
|
9832
9938
|
const computeLayout = useCallback21(() => {
|
|
@@ -9848,6 +9954,7 @@ function TabBar({
|
|
|
9848
9954
|
"div",
|
|
9849
9955
|
{
|
|
9850
9956
|
ref: containerRef,
|
|
9957
|
+
role: "tablist",
|
|
9851
9958
|
className: cn(
|
|
9852
9959
|
"flex items-end",
|
|
9853
9960
|
variant === "underline" && "border-b border-neutral-700",
|
|
@@ -9884,7 +9991,7 @@ function TabBar({
|
|
|
9884
9991
|
}
|
|
9885
9992
|
|
|
9886
9993
|
// components/ui/layout-tab-bar.tsx
|
|
9887
|
-
import { useState as useState36, useRef as
|
|
9994
|
+
import { useState as useState36, useRef as useRef24, useCallback as useCallback22, useEffect as useEffect19 } from "react";
|
|
9888
9995
|
import { ChevronLeft as ChevronLeft3, ChevronRight as ChevronRight11, X as X12 } from "lucide-react";
|
|
9889
9996
|
import { jsx as jsx57, jsxs as jsxs50 } from "react/jsx-runtime";
|
|
9890
9997
|
var COLORS2 = {
|
|
@@ -9929,11 +10036,11 @@ function getGradient(color, isActive) {
|
|
|
9929
10036
|
return isActive ? `linear-gradient(135deg, rgba(${rgb}, 0.54) 0%, rgba(${rgb}, 0.10) 100%)` : `linear-gradient(135deg, rgba(${rgb}, 0.36) 0%, rgba(${rgb}, 0.06) 100%)`;
|
|
9930
10037
|
}
|
|
9931
10038
|
function LayoutTabBar({ tabs, activeId, onSelect, onClose, onReorder, className }) {
|
|
9932
|
-
const scrollRef =
|
|
10039
|
+
const scrollRef = useRef24(null);
|
|
9933
10040
|
const [showLeft, setShowLeft] = useState36(false);
|
|
9934
10041
|
const [showRight, setShowRight] = useState36(false);
|
|
9935
10042
|
const [drag, setDrag] = useState36(null);
|
|
9936
|
-
const skipClickRef =
|
|
10043
|
+
const skipClickRef = useRef24(false);
|
|
9937
10044
|
const updateArrows = useCallback22(() => {
|
|
9938
10045
|
const el = scrollRef.current;
|
|
9939
10046
|
if (!el) return;
|
|
@@ -10056,20 +10163,15 @@ function LayoutTabBar({ tabs, activeId, onSelect, onClose, onReorder, className
|
|
|
10056
10163
|
/* @__PURE__ */ jsx57("span", { className: cn("truncate text-sm", isActive ? subC : "text-neutral-500"), children: tab.subtitle })
|
|
10057
10164
|
] }),
|
|
10058
10165
|
tab.closable && onClose && /* @__PURE__ */ jsx57(
|
|
10059
|
-
"
|
|
10166
|
+
"button",
|
|
10060
10167
|
{
|
|
10061
|
-
|
|
10168
|
+
type: "button",
|
|
10169
|
+
"aria-label": `Close ${tab.title}`,
|
|
10062
10170
|
tabIndex: -1,
|
|
10063
10171
|
onClick: (e) => {
|
|
10064
10172
|
e.stopPropagation();
|
|
10065
10173
|
onClose(tab.id);
|
|
10066
10174
|
},
|
|
10067
|
-
onKeyDown: (e) => {
|
|
10068
|
-
if (e.key === "Enter") {
|
|
10069
|
-
e.stopPropagation();
|
|
10070
|
-
onClose(tab.id);
|
|
10071
|
-
}
|
|
10072
|
-
},
|
|
10073
10175
|
className: "absolute right-1.5 top-1/2 -translate-y-1/2 opacity-0 group-hover:opacity-100 hover:bg-neutral-700 rounded p-0.5 transition-opacity cursor-pointer",
|
|
10074
10176
|
children: /* @__PURE__ */ jsx57(X12, { className: "w-3 h-3" })
|
|
10075
10177
|
}
|
|
@@ -10088,7 +10190,7 @@ function LayoutTabBar({ tabs, activeId, onSelect, onClose, onReorder, className
|
|
|
10088
10190
|
const ghostIconC = getTextClass(t.iconColor || t.titleColor || "white");
|
|
10089
10191
|
const ghostSubC = getTextClass(t.subtitleColor || t.selectedColor || t.color);
|
|
10090
10192
|
const ghostSubIconC = getTextClass(t.subtitleIconColor || t.subtitleColor || t.selectedColor || t.color);
|
|
10091
|
-
return /* @__PURE__ */ jsx57("div", { className: "fixed z-50 pointer-events-none opacity-90", style: { left: drag.x + 12, top: drag.y - 20 }, children: /* @__PURE__ */ jsxs50("div", { className: cn("flex flex-col gap-0.5 px-2.5 py-1.5 rounded-t-lg border-t-2 shadow-
|
|
10193
|
+
return /* @__PURE__ */ jsx57("div", { className: "fixed z-50 pointer-events-none opacity-90", style: { left: drag.x + 12, top: drag.y - 20 }, children: /* @__PURE__ */ jsxs50("div", { className: cn("flex flex-col gap-0.5 px-2.5 py-1.5 rounded-t-lg border-t-2 shadow-lg bg-neutral-800", ghostBorder), children: [
|
|
10092
10194
|
/* @__PURE__ */ jsxs50("div", { className: "flex items-center gap-1.5", children: [
|
|
10093
10195
|
t.icon && /* @__PURE__ */ jsx57("span", { className: cn("shrink-0 inline-flex", ghostIconC), style: { width: 14, height: 14 }, children: t.icon }),
|
|
10094
10196
|
/* @__PURE__ */ jsx57("span", { className: cn("text-md font-medium", ghostTitleC), children: t.title })
|
|
@@ -10139,7 +10241,7 @@ function NavCard({
|
|
|
10139
10241
|
children: /* @__PURE__ */ jsx58(Icon, { className: "w-4.5 h-4.5", style: { color: iconColor } })
|
|
10140
10242
|
}
|
|
10141
10243
|
),
|
|
10142
|
-
/* @__PURE__ */ jsx58("h3", { className: "text-md font-medium text-neutral-200", children: title }),
|
|
10244
|
+
/* @__PURE__ */ jsx58("h3", { className: "text-md font-medium text-neutral-200 truncate", children: title }),
|
|
10143
10245
|
description && /* @__PURE__ */ jsx58("p", { className: "mt-1 text-sm text-neutral-500 leading-relaxed line-clamp-2", children: description }),
|
|
10144
10246
|
stats && /* @__PURE__ */ jsx58("p", { className: "mt-2 text-sm text-neutral-600", children: stats })
|
|
10145
10247
|
]
|
|
@@ -10148,9 +10250,9 @@ function NavCard({
|
|
|
10148
10250
|
}
|
|
10149
10251
|
|
|
10150
10252
|
// components/ui/extension-list-card.tsx
|
|
10151
|
-
import { memo, useState as useState37, useRef as
|
|
10253
|
+
import { memo as memo3, useState as useState37, useRef as useRef25, useCallback as useCallback23, useEffect as useEffect20 } from "react";
|
|
10152
10254
|
import { jsx as jsx59, jsxs as jsxs52 } from "react/jsx-runtime";
|
|
10153
|
-
var ExtensionListCard =
|
|
10255
|
+
var ExtensionListCard = memo3(function ExtensionListCard2({
|
|
10154
10256
|
icon: Icon,
|
|
10155
10257
|
iconColor,
|
|
10156
10258
|
borderColor,
|
|
@@ -10164,7 +10266,7 @@ var ExtensionListCard = memo(function ExtensionListCard2({
|
|
|
10164
10266
|
testId
|
|
10165
10267
|
}) {
|
|
10166
10268
|
const [isHovered, setIsHovered] = useState37(false);
|
|
10167
|
-
const hoverTimerRef =
|
|
10269
|
+
const hoverTimerRef = useRef25(void 0);
|
|
10168
10270
|
useEffect20(() => () => clearTimeout(hoverTimerRef.current), []);
|
|
10169
10271
|
const handleMouseEnter = useCallback23(() => {
|
|
10170
10272
|
hoverTimerRef.current = setTimeout(() => setIsHovered(true), 300);
|
|
@@ -10191,7 +10293,7 @@ var ExtensionListCard = memo(function ExtensionListCard2({
|
|
|
10191
10293
|
/* @__PURE__ */ jsx59(Icon, { className: cn("w-5 h-5 shrink-0", iconColor) }),
|
|
10192
10294
|
/* @__PURE__ */ jsxs52("div", { className: "min-w-0 flex-1", children: [
|
|
10193
10295
|
/* @__PURE__ */ jsxs52("div", { className: "flex items-center gap-2 flex-wrap", children: [
|
|
10194
|
-
/* @__PURE__ */ jsx59("span", { className: cn("text-md font-medium", titleClassName), children: title }),
|
|
10296
|
+
/* @__PURE__ */ jsx59("span", { className: cn("text-md font-medium truncate", titleClassName), children: title }),
|
|
10195
10297
|
badges
|
|
10196
10298
|
] }),
|
|
10197
10299
|
description && /* @__PURE__ */ jsx59("div", { className: cn("text-sm text-neutral-500 mt-1", !isHovered && "line-clamp-2"), children: description })
|
|
@@ -10386,7 +10488,7 @@ function CookieConsent({
|
|
|
10386
10488
|
onConsent?.(choice);
|
|
10387
10489
|
};
|
|
10388
10490
|
if (!isVisible) return null;
|
|
10389
|
-
return /* @__PURE__ */ jsx63("div", { className: "fixed bottom-0 left-0 right-0 z-50 p-4 bg-neutral-900
|
|
10491
|
+
return /* @__PURE__ */ jsx63("div", { className: "fixed bottom-0 left-0 right-0 z-50 p-4 bg-neutral-900 border-t border-neutral-700/50", children: /* @__PURE__ */ jsxs56("div", { className: "max-w-6xl mx-auto flex flex-col sm:flex-row items-start sm:items-center gap-4", children: [
|
|
10390
10492
|
/* @__PURE__ */ jsxs56("div", { className: "flex-grow", children: [
|
|
10391
10493
|
/* @__PURE__ */ jsx63("p", { className: "text-md text-neutral-200 mb-1", children: heading }),
|
|
10392
10494
|
/* @__PURE__ */ jsx63("p", { className: "text-sm text-neutral-400", children: description })
|
|
@@ -10500,8 +10602,8 @@ function useNavigationHistory(initial, maxEntries = 50) {
|
|
|
10500
10602
|
// components/ui/setting-row.tsx
|
|
10501
10603
|
import { jsx as jsx64, jsxs as jsxs57 } from "react/jsx-runtime";
|
|
10502
10604
|
function SettingRow(props) {
|
|
10503
|
-
const { label, description, disabled, className
|
|
10504
|
-
return /* @__PURE__ */ jsxs57("div", { className:
|
|
10605
|
+
const { label, description, disabled, className } = props;
|
|
10606
|
+
return /* @__PURE__ */ jsxs57("div", { className: cn("flex items-start justify-between gap-4", className), children: [
|
|
10505
10607
|
/* @__PURE__ */ jsxs57("div", { children: [
|
|
10506
10608
|
/* @__PURE__ */ jsx64("label", { className: "text-neutral-200 leading-7", children: label }),
|
|
10507
10609
|
description && /* @__PURE__ */ jsx64("p", { className: "text-md text-neutral-500", children: description })
|
|
@@ -10513,7 +10615,8 @@ function SettingRow(props) {
|
|
|
10513
10615
|
onChange: props.onChange,
|
|
10514
10616
|
disabled,
|
|
10515
10617
|
color: props.color,
|
|
10516
|
-
size: props.size
|
|
10618
|
+
size: props.size,
|
|
10619
|
+
"aria-label": label
|
|
10517
10620
|
}
|
|
10518
10621
|
),
|
|
10519
10622
|
props.type === "select" && /* @__PURE__ */ jsx64(
|
|
@@ -10551,8 +10654,8 @@ function SettingsCard({ children, className, title, description, testId }) {
|
|
|
10551
10654
|
"data-testid": testId,
|
|
10552
10655
|
children: [
|
|
10553
10656
|
title && /* @__PURE__ */ jsxs58("div", { children: [
|
|
10554
|
-
/* @__PURE__ */ jsx65("h3", { className: "text-md font-medium text-neutral-200", children: title }),
|
|
10555
|
-
description && /* @__PURE__ */ jsx65("p", { className: "text-md text-neutral-500 mt-1", children: description })
|
|
10657
|
+
/* @__PURE__ */ jsx65("h3", { className: "text-md font-medium text-neutral-200 truncate", children: title }),
|
|
10658
|
+
description && /* @__PURE__ */ jsx65("p", { className: "text-md text-neutral-500 mt-1 line-clamp-2", children: description })
|
|
10556
10659
|
] }),
|
|
10557
10660
|
!title && description && /* @__PURE__ */ jsx65("p", { className: "text-md text-neutral-500", children: description }),
|
|
10558
10661
|
children
|
|
@@ -10603,8 +10706,7 @@ function SettingsInfoBox({ children, color = "neutral", className, testId }) {
|
|
|
10603
10706
|
return /* @__PURE__ */ jsxs59(
|
|
10604
10707
|
"div",
|
|
10605
10708
|
{
|
|
10606
|
-
className: cn("flex items-start gap-3 border-l-2", borderColorMap[color], className),
|
|
10607
|
-
style: { paddingLeft: 10 },
|
|
10709
|
+
className: cn("flex items-start gap-3 border-l-2 pl-2.5", borderColorMap[color], className),
|
|
10608
10710
|
"data-testid": testId,
|
|
10609
10711
|
children: [
|
|
10610
10712
|
/* @__PURE__ */ jsx66(Icon, { className: cn("w-4 h-4 mt-0.5 shrink-0", ACCENT_TEXT[color]) }),
|