@industry-theme/xterm-terminal-panel 0.2.3 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -800,10 +800,268 @@ function useThemedTerminal() {
800
800
  getCSSVariables
801
801
  };
802
802
  }
803
- // src/panels/TerminalPanel.tsx
803
+ // src/components/TabBar/TabBar.tsx
804
+ import { useTheme as useTheme4 } from "@principal-ade/industry-theme";
805
+ import { Plus } from "lucide-react";
806
+ import { useState as useState2 } from "react";
807
+
808
+ // src/components/TabBar/TabButton.tsx
804
809
  import { useTheme as useTheme3 } from "@principal-ade/industry-theme";
810
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
811
+ var TabButton = ({
812
+ tab,
813
+ isActive,
814
+ isHovered,
815
+ onMouseEnter,
816
+ onMouseLeave,
817
+ onClick,
818
+ onClose,
819
+ keyboardHint,
820
+ renderAccessory
821
+ }) => {
822
+ const { theme } = useTheme3();
823
+ const showCloseButton = isHovered || isActive;
824
+ const closable = tab.closable !== false;
825
+ return /* @__PURE__ */ jsxs2("div", {
826
+ onMouseEnter,
827
+ onMouseLeave,
828
+ onClick,
829
+ style: {
830
+ display: "flex",
831
+ alignItems: "center",
832
+ justifyContent: "center",
833
+ gap: "6px",
834
+ padding: "6px 8px",
835
+ backgroundColor: isActive ? theme.colors.background : theme.colors.backgroundSecondary,
836
+ cursor: "pointer",
837
+ fontSize: theme.fontSizes[1],
838
+ fontWeight: isActive ? theme.fontWeights.semibold : theme.fontWeights.body,
839
+ fontFamily: theme.fonts.body,
840
+ color: isActive ? theme.colors.text : theme.colors.textSecondary,
841
+ whiteSpace: "nowrap",
842
+ transition: "all 0.2s",
843
+ flex: 1,
844
+ minWidth: 0,
845
+ height: "100%",
846
+ position: "relative",
847
+ boxSizing: "border-box"
848
+ },
849
+ children: [
850
+ closable && showCloseButton && /* @__PURE__ */ jsx3("button", {
851
+ onClick: (e) => {
852
+ e.stopPropagation();
853
+ onClose();
854
+ },
855
+ style: {
856
+ display: "flex",
857
+ alignItems: "center",
858
+ justifyContent: "center",
859
+ width: "16px",
860
+ height: "16px",
861
+ borderRadius: "3px",
862
+ border: "none",
863
+ backgroundColor: "transparent",
864
+ cursor: "pointer",
865
+ color: theme.colors.textSecondary,
866
+ padding: 0,
867
+ position: "absolute",
868
+ left: "8px"
869
+ },
870
+ onMouseEnter: (e) => {
871
+ e.currentTarget.style.backgroundColor = theme.colors.backgroundTertiary;
872
+ },
873
+ onMouseLeave: (e) => {
874
+ e.currentTarget.style.backgroundColor = "transparent";
875
+ },
876
+ title: "Close (⌘W)",
877
+ children: "×"
878
+ }),
879
+ tab.icon && /* @__PURE__ */ jsx3("div", {
880
+ style: { flexShrink: 0, display: "flex", alignItems: "center" },
881
+ children: tab.icon
882
+ }),
883
+ /* @__PURE__ */ jsx3("span", {
884
+ style: {
885
+ overflow: "hidden",
886
+ textOverflow: "ellipsis",
887
+ whiteSpace: "nowrap"
888
+ },
889
+ title: tab.label,
890
+ children: tab.label
891
+ }),
892
+ renderAccessory ? renderAccessory(tab) : keyboardHint && /* @__PURE__ */ jsx3("span", {
893
+ style: {
894
+ fontSize: theme.fontSizes[0],
895
+ color: theme.colors.textSecondary,
896
+ opacity: 0.6,
897
+ flexShrink: 0
898
+ },
899
+ children: keyboardHint
900
+ })
901
+ ]
902
+ });
903
+ };
904
+ TabButton.displayName = "TabButton";
905
+
906
+ // src/components/TabBar/TabBar.tsx
907
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
908
+ var TabBar = ({
909
+ tabs,
910
+ activeTabId,
911
+ onTabClick,
912
+ onTabClose,
913
+ onNewTab,
914
+ leftSection,
915
+ rightSection,
916
+ renderTabAccessory,
917
+ className,
918
+ showKeyboardHints = true
919
+ }) => {
920
+ const { theme } = useTheme4();
921
+ const [hoveredTabId, setHoveredTabId] = useState2(null);
922
+ return /* @__PURE__ */ jsxs3("div", {
923
+ className,
924
+ style: {
925
+ display: "flex",
926
+ alignItems: "stretch",
927
+ height: "40px",
928
+ flexShrink: 0,
929
+ boxSizing: "border-box"
930
+ },
931
+ children: [
932
+ leftSection && /* @__PURE__ */ jsx4("div", {
933
+ style: {
934
+ display: "flex",
935
+ alignItems: "center",
936
+ gap: "4px",
937
+ padding: "0 8px",
938
+ backgroundColor: theme.colors.backgroundSecondary,
939
+ borderRight: `1px solid ${theme.colors.border}`,
940
+ borderBottom: `1px solid ${theme.colors.border}`,
941
+ boxSizing: "border-box"
942
+ },
943
+ children: leftSection
944
+ }),
945
+ /* @__PURE__ */ jsx4("div", {
946
+ style: {
947
+ display: "flex",
948
+ alignItems: "center",
949
+ flex: 1,
950
+ overflow: "hidden",
951
+ backgroundColor: theme.colors.backgroundSecondary,
952
+ borderBottom: `1px solid ${theme.colors.border}`,
953
+ boxSizing: "border-box"
954
+ },
955
+ children: tabs.map((tab, index) => /* @__PURE__ */ jsx4(TabButton, {
956
+ tab,
957
+ isActive: tab.id === activeTabId,
958
+ isHovered: tab.id === hoveredTabId,
959
+ onMouseEnter: () => setHoveredTabId(tab.id),
960
+ onMouseLeave: () => setHoveredTabId(null),
961
+ onClick: () => onTabClick(tab.id),
962
+ onClose: () => onTabClose(tab.id),
963
+ keyboardHint: showKeyboardHints && index < 9 ? `⌘ ${index + 1}` : undefined,
964
+ renderAccessory: renderTabAccessory
965
+ }, tab.id))
966
+ }),
967
+ rightSection !== undefined ? rightSection && /* @__PURE__ */ jsx4("div", {
968
+ style: {
969
+ display: "flex",
970
+ alignItems: "center",
971
+ gap: "4px",
972
+ padding: "0 8px",
973
+ backgroundColor: theme.colors.backgroundSecondary,
974
+ borderLeft: `1px solid ${theme.colors.border}`,
975
+ borderBottom: `1px solid ${theme.colors.border}`,
976
+ boxSizing: "border-box"
977
+ },
978
+ children: rightSection
979
+ }) : onNewTab && /* @__PURE__ */ jsx4("div", {
980
+ style: {
981
+ display: "flex",
982
+ alignItems: "center",
983
+ gap: "4px",
984
+ padding: "0 8px",
985
+ backgroundColor: theme.colors.backgroundSecondary,
986
+ borderLeft: `1px solid ${theme.colors.border}`,
987
+ borderBottom: `1px solid ${theme.colors.border}`,
988
+ boxSizing: "border-box"
989
+ },
990
+ children: /* @__PURE__ */ jsx4("button", {
991
+ onClick: onNewTab,
992
+ style: {
993
+ display: "flex",
994
+ alignItems: "center",
995
+ justifyContent: "center",
996
+ width: "28px",
997
+ height: "28px",
998
+ border: "none",
999
+ borderRadius: "4px",
1000
+ backgroundColor: "transparent",
1001
+ cursor: "pointer",
1002
+ color: theme.colors.textSecondary
1003
+ },
1004
+ onMouseEnter: (e) => {
1005
+ e.currentTarget.style.backgroundColor = theme.colors.backgroundTertiary;
1006
+ },
1007
+ onMouseLeave: (e) => {
1008
+ e.currentTarget.style.backgroundColor = "transparent";
1009
+ },
1010
+ title: "New Tab (⌘T)",
1011
+ children: /* @__PURE__ */ jsx4(Plus, {
1012
+ size: 14
1013
+ })
1014
+ })
1015
+ })
1016
+ ]
1017
+ });
1018
+ };
1019
+ TabBar.displayName = "TabBar";
1020
+ // src/types/mixed-tab.ts
1021
+ function isTabOfType(tab, contentType) {
1022
+ return tab.contentType === contentType;
1023
+ }
1024
+ // src/hooks/useTabKeyboardShortcuts.ts
1025
+ import { useEffect as useEffect2 } from "react";
1026
+ var useTabKeyboardShortcuts = ({
1027
+ onNewTab,
1028
+ onCloseTab,
1029
+ onSwitchToTab,
1030
+ enabled = true
1031
+ }) => {
1032
+ useEffect2(() => {
1033
+ if (!enabled)
1034
+ return;
1035
+ const handleKeyDown = (e) => {
1036
+ const isCmdOrCtrl = e.metaKey || e.ctrlKey;
1037
+ if (isCmdOrCtrl && e.key === "t" && onNewTab) {
1038
+ e.preventDefault();
1039
+ e.stopPropagation();
1040
+ onNewTab();
1041
+ return;
1042
+ }
1043
+ if (isCmdOrCtrl && e.key === "w" && onCloseTab) {
1044
+ e.preventDefault();
1045
+ e.stopPropagation();
1046
+ onCloseTab();
1047
+ return;
1048
+ }
1049
+ if (isCmdOrCtrl && /^[1-9]$/.test(e.key) && onSwitchToTab) {
1050
+ e.preventDefault();
1051
+ e.stopPropagation();
1052
+ const index = parseInt(e.key, 10) - 1;
1053
+ onSwitchToTab(index);
1054
+ return;
1055
+ }
1056
+ };
1057
+ window.addEventListener("keydown", handleKeyDown);
1058
+ return () => window.removeEventListener("keydown", handleKeyDown);
1059
+ }, [enabled, onNewTab, onCloseTab, onSwitchToTab]);
1060
+ };
1061
+ // src/panels/TerminalPanel.tsx
1062
+ import { useTheme as useTheme5 } from "@principal-ade/industry-theme";
805
1063
  import { Lock, Unlock, ArrowDown } from "lucide-react";
806
- import { useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
1064
+ import { useEffect as useEffect3, useRef as useRef2, useState as useState3 } from "react";
807
1065
 
808
1066
  // src/panel-types/index.ts
809
1067
  function getTerminalSessions(context) {
@@ -838,19 +1096,19 @@ function getTerminalSlice(context) {
838
1096
  }
839
1097
 
840
1098
  // src/panels/TerminalPanel.tsx
841
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
1099
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
842
1100
  var TerminalPanel = ({
843
1101
  context,
844
1102
  actions,
845
1103
  events: _events,
846
1104
  terminalScope = "repository"
847
1105
  }) => {
848
- const { theme } = useTheme3();
849
- const [sessionId, setSessionId] = useState2(null);
850
- const [error, setError] = useState2(null);
851
- const [isInitializing, setIsInitializing] = useState2(true);
852
- const [usingMessagePort, setUsingMessagePort] = useState2(false);
853
- const [scrollPosition, setScrollPosition] = useState2({
1106
+ const { theme } = useTheme5();
1107
+ const [sessionId, setSessionId] = useState3(null);
1108
+ const [error, setError] = useState3(null);
1109
+ const [isInitializing, setIsInitializing] = useState3(true);
1110
+ const [usingMessagePort, setUsingMessagePort] = useState3(false);
1111
+ const [scrollPosition, setScrollPosition] = useState3({
854
1112
  isAtTop: false,
855
1113
  isAtBottom: true,
856
1114
  isScrollLocked: false
@@ -859,7 +1117,7 @@ var TerminalPanel = ({
859
1117
  const dataPortRef = useRef2(null);
860
1118
  const terminalDirectory = getTerminalDirectory(context, terminalScope);
861
1119
  const pendingSessionIdRef = useRef2(null);
862
- useEffect2(() => {
1120
+ useEffect3(() => {
863
1121
  let mounted = true;
864
1122
  let unsubscribePortReady = null;
865
1123
  const initTerminal = async () => {
@@ -917,7 +1175,7 @@ var TerminalPanel = ({
917
1175
  }
918
1176
  };
919
1177
  }, []);
920
- useEffect2(() => {
1178
+ useEffect3(() => {
921
1179
  if (usingMessagePort)
922
1180
  return;
923
1181
  if (!sessionId)
@@ -930,7 +1188,7 @@ var TerminalPanel = ({
930
1188
  }, 5000);
931
1189
  return () => clearTimeout(timeout);
932
1190
  }, [sessionId, usingMessagePort]);
933
- useEffect2(() => {
1191
+ useEffect3(() => {
934
1192
  if (!usingMessagePort || !dataPortRef.current)
935
1193
  return;
936
1194
  const port = dataPortRef.current;
@@ -988,7 +1246,7 @@ var TerminalPanel = ({
988
1246
  hasNotifiedPtyRef.current = true;
989
1247
  }
990
1248
  };
991
- useEffect2(() => {
1249
+ useEffect3(() => {
992
1250
  hasNotifiedPtyRef.current = false;
993
1251
  }, [sessionId]);
994
1252
  const handleScrollPositionChange = (position) => {
@@ -996,7 +1254,7 @@ var TerminalPanel = ({
996
1254
  };
997
1255
  const sessionInfo = sessionId ? getTerminalSession(context, sessionId) : undefined;
998
1256
  if (error) {
999
- return /* @__PURE__ */ jsxs2("div", {
1257
+ return /* @__PURE__ */ jsxs4("div", {
1000
1258
  style: {
1001
1259
  padding: "20px",
1002
1260
  color: "#ef4444",
@@ -1009,11 +1267,11 @@ var TerminalPanel = ({
1009
1267
  gap: "10px"
1010
1268
  },
1011
1269
  children: [
1012
- /* @__PURE__ */ jsx3("div", {
1270
+ /* @__PURE__ */ jsx5("div", {
1013
1271
  style: { fontSize: "16px", fontWeight: "bold" },
1014
1272
  children: "Terminal Error"
1015
1273
  }),
1016
- /* @__PURE__ */ jsx3("div", {
1274
+ /* @__PURE__ */ jsx5("div", {
1017
1275
  style: { fontSize: "14px", opacity: 0.8 },
1018
1276
  children: error
1019
1277
  })
@@ -1021,7 +1279,7 @@ var TerminalPanel = ({
1021
1279
  });
1022
1280
  }
1023
1281
  if (isInitializing || !sessionId) {
1024
- return /* @__PURE__ */ jsx3("div", {
1282
+ return /* @__PURE__ */ jsx5("div", {
1025
1283
  style: {
1026
1284
  padding: "20px",
1027
1285
  color: "#a0a0a0",
@@ -1047,10 +1305,10 @@ var TerminalPanel = ({
1047
1305
  terminalRef.current?.scrollToBottom();
1048
1306
  }
1049
1307
  };
1050
- return /* @__PURE__ */ jsxs2("div", {
1308
+ return /* @__PURE__ */ jsxs4("div", {
1051
1309
  style: { height: "100%", width: "100%", display: "flex", flexDirection: "column" },
1052
1310
  children: [
1053
- /* @__PURE__ */ jsxs2("div", {
1311
+ /* @__PURE__ */ jsxs4("div", {
1054
1312
  style: {
1055
1313
  display: "flex",
1056
1314
  gap: "8px",
@@ -1060,7 +1318,7 @@ var TerminalPanel = ({
1060
1318
  alignItems: "center"
1061
1319
  },
1062
1320
  children: [
1063
- /* @__PURE__ */ jsxs2("span", {
1321
+ /* @__PURE__ */ jsxs4("span", {
1064
1322
  style: {
1065
1323
  fontSize: "12px",
1066
1324
  color: theme.colors.textSecondary,
@@ -1073,7 +1331,7 @@ var TerminalPanel = ({
1073
1331
  sessionInfo?.shell
1074
1332
  ]
1075
1333
  }),
1076
- /* @__PURE__ */ jsxs2("button", {
1334
+ /* @__PURE__ */ jsxs4("button", {
1077
1335
  onClick: handleToggleScrollLock,
1078
1336
  style: {
1079
1337
  display: "flex",
@@ -1092,17 +1350,17 @@ var TerminalPanel = ({
1092
1350
  onMouseLeave: (e) => e.currentTarget.style.opacity = "1",
1093
1351
  title: scrollPosition.isScrollLocked ? "Click to unlock scroll" : "Click to lock scroll to bottom",
1094
1352
  children: [
1095
- scrollPosition.isScrollLocked ? /* @__PURE__ */ jsx3(Lock, {
1353
+ scrollPosition.isScrollLocked ? /* @__PURE__ */ jsx5(Lock, {
1096
1354
  size: 12
1097
- }) : /* @__PURE__ */ jsx3(Unlock, {
1355
+ }) : /* @__PURE__ */ jsx5(Unlock, {
1098
1356
  size: 12
1099
1357
  }),
1100
- /* @__PURE__ */ jsx3("span", {
1358
+ /* @__PURE__ */ jsx5("span", {
1101
1359
  children: scrollPosition.isScrollLocked ? "Locked" : "Unlocked"
1102
1360
  })
1103
1361
  ]
1104
1362
  }),
1105
- /* @__PURE__ */ jsxs2("button", {
1363
+ /* @__PURE__ */ jsxs4("button", {
1106
1364
  onClick: handleScrollToBottom,
1107
1365
  disabled: scrollPosition.isAtBottom,
1108
1366
  style: {
@@ -1123,19 +1381,19 @@ var TerminalPanel = ({
1123
1381
  onMouseLeave: (e) => !scrollPosition.isAtBottom && (e.currentTarget.style.opacity = "1"),
1124
1382
  title: "Scroll to bottom and lock",
1125
1383
  children: [
1126
- /* @__PURE__ */ jsx3(ArrowDown, {
1384
+ /* @__PURE__ */ jsx5(ArrowDown, {
1127
1385
  size: 12
1128
1386
  }),
1129
- /* @__PURE__ */ jsx3("span", {
1387
+ /* @__PURE__ */ jsx5("span", {
1130
1388
  children: "Bottom"
1131
1389
  })
1132
1390
  ]
1133
1391
  })
1134
1392
  ]
1135
1393
  }),
1136
- /* @__PURE__ */ jsx3("div", {
1394
+ /* @__PURE__ */ jsx5("div", {
1137
1395
  style: { flex: 1 },
1138
- children: /* @__PURE__ */ jsx3(ThemedTerminalWithProvider, {
1396
+ children: /* @__PURE__ */ jsx5(ThemedTerminalWithProvider, {
1139
1397
  ref: terminalRef,
1140
1398
  onData: handleTerminalData,
1141
1399
  onResize: handleTerminalResize,
@@ -1153,28 +1411,28 @@ var TerminalPanel = ({
1153
1411
  });
1154
1412
  };
1155
1413
  // src/panels/TabbedTerminalPanel.tsx
1156
- import { useTheme as useTheme4 } from "@principal-ade/industry-theme";
1157
- import { Terminal as TerminalIcon2, X as X2, Plus, Lock as Lock2, Unlock as Unlock2, Box, Boxes } from "lucide-react";
1158
- import React, {
1159
- useState as useState3,
1414
+ import { useTheme as useTheme6 } from "@principal-ade/industry-theme";
1415
+ import { Terminal as TerminalIcon2, Lock as Lock2, Unlock as Unlock2, Box, Boxes } from "lucide-react";
1416
+ import React2, {
1417
+ useState as useState4,
1160
1418
  useCallback as useCallback2,
1161
- useEffect as useEffect3,
1419
+ useEffect as useEffect4,
1162
1420
  useRef as useRef3
1163
1421
  } from "react";
1164
- import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1422
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1165
1423
  function TerminalTabContentInner(props, ref) {
1166
1424
  const { tab, sessionId, isActive, isVisible, actions, events, terminalContext, onSessionCreated, onScrollPositionChange, isForeign = false } = props;
1167
1425
  const terminalRef = useRef3(null);
1168
- const [localSessionId, setLocalSessionId] = useState3(sessionId);
1169
- const [isInitialized, setIsInitialized] = useState3(false);
1426
+ const [localSessionId, setLocalSessionId] = useState4(sessionId);
1427
+ const [isInitialized, setIsInitialized] = useState4(false);
1170
1428
  const hasInitializedRef = useRef3(false);
1171
- const [scrollPosition, setScrollPosition] = useState3({
1429
+ const [scrollPosition, setScrollPosition] = useState4({
1172
1430
  isAtTop: false,
1173
1431
  isAtBottom: true,
1174
1432
  isScrollLocked: false
1175
1433
  });
1176
- const [shouldRenderTerminal, setShouldRenderTerminal] = useState3(true);
1177
- const [ownerWindowId, setOwnerWindowId] = useState3(null);
1434
+ const [shouldRenderTerminal, setShouldRenderTerminal] = useState4(true);
1435
+ const [ownerWindowId, setOwnerWindowId] = useState4(null);
1178
1436
  const needsRefreshOnResizeRef = useRef3(false);
1179
1437
  const claimAndConnect = useCallback2(async (targetSessionId, force = false) => {
1180
1438
  try {
@@ -1194,7 +1452,7 @@ function TerminalTabContentInner(props, ref) {
1194
1452
  throw error;
1195
1453
  }
1196
1454
  }, [actions]);
1197
- useEffect3(() => {
1455
+ useEffect4(() => {
1198
1456
  if (hasInitializedRef.current) {
1199
1457
  return;
1200
1458
  }
@@ -1239,7 +1497,7 @@ function TerminalTabContentInner(props, ref) {
1239
1497
  mounted = false;
1240
1498
  };
1241
1499
  }, []);
1242
- useEffect3(() => {
1500
+ useEffect4(() => {
1243
1501
  if (!localSessionId || !isInitialized || !shouldRenderTerminal) {
1244
1502
  return;
1245
1503
  }
@@ -1291,7 +1549,7 @@ function TerminalTabContentInner(props, ref) {
1291
1549
  });
1292
1550
  }
1293
1551
  }, [localSessionId, events]);
1294
- useEffect3(() => {
1552
+ useEffect4(() => {
1295
1553
  if (!localSessionId || !actions.onOwnershipLost) {
1296
1554
  return;
1297
1555
  }
@@ -1341,12 +1599,12 @@ function TerminalTabContentInner(props, ref) {
1341
1599
  terminalRef.current?.scrollToBottom();
1342
1600
  }
1343
1601
  }, [scrollPosition.isScrollLocked]);
1344
- React.useImperativeHandle(ref, () => ({
1602
+ React2.useImperativeHandle(ref, () => ({
1345
1603
  scrollToBottom: handleScrollToBottom,
1346
1604
  toggleScrollLock: handleToggleScrollLock
1347
1605
  }), [handleScrollToBottom, handleToggleScrollLock]);
1348
1606
  if (!isInitialized) {
1349
- return /* @__PURE__ */ jsx4("div", {
1607
+ return /* @__PURE__ */ jsx6("div", {
1350
1608
  style: {
1351
1609
  display: isActive ? "flex" : "none",
1352
1610
  height: "100%",
@@ -1369,14 +1627,14 @@ function TerminalTabContentInner(props, ref) {
1369
1627
  ],
1370
1628
  opacity: 1
1371
1629
  } : undefined;
1372
- return /* @__PURE__ */ jsx4("div", {
1630
+ return /* @__PURE__ */ jsx6("div", {
1373
1631
  style: {
1374
1632
  display: isActive ? "flex" : "none",
1375
1633
  flexDirection: "column",
1376
1634
  height: "100%",
1377
1635
  width: "100%"
1378
1636
  },
1379
- children: /* @__PURE__ */ jsx4(ThemedTerminalWithProvider, {
1637
+ children: /* @__PURE__ */ jsx6(ThemedTerminalWithProvider, {
1380
1638
  ref: terminalRef,
1381
1639
  onData: shouldRenderTerminal ? handleData : undefined,
1382
1640
  onResize: shouldRenderTerminal ? handleResize : undefined,
@@ -1397,7 +1655,7 @@ function TerminalTabContentInner(props, ref) {
1397
1655
  });
1398
1656
  }
1399
1657
  var areTerminalTabContentPropsEqual = (prevProps, nextProps) => {
1400
- const tabEqual = prevProps.tab.id === nextProps.tab.id && prevProps.tab.directory === nextProps.tab.directory && prevProps.tab.isActive === nextProps.tab.isActive && prevProps.tab.label === nextProps.tab.label;
1658
+ const tabEqual = prevProps.tab.id === nextProps.tab.id && prevProps.tab.directory === nextProps.tab.directory && prevProps.tab.label === nextProps.tab.label;
1401
1659
  const changes = [];
1402
1660
  if (!tabEqual)
1403
1661
  changes.push("tab");
@@ -1413,8 +1671,8 @@ var areTerminalTabContentPropsEqual = (prevProps, nextProps) => {
1413
1671
  changes.push("isForeign");
1414
1672
  return changes.length === 0;
1415
1673
  };
1416
- var TerminalTabContentForwarded = React.forwardRef(TerminalTabContentInner);
1417
- var TerminalTabContent = React.memo(TerminalTabContentForwarded, areTerminalTabContentPropsEqual);
1674
+ var TerminalTabContentForwarded = React2.forwardRef(TerminalTabContentInner);
1675
+ var TerminalTabContent = React2.memo(TerminalTabContentForwarded, areTerminalTabContentPropsEqual);
1418
1676
  TerminalTabContent.displayName = "TerminalTabContent";
1419
1677
  var TabbedTerminalPanelInner = ({
1420
1678
  context: _context,
@@ -1428,22 +1686,41 @@ var TabbedTerminalPanelInner = ({
1428
1686
  initialTabs = [],
1429
1687
  showAllTerminals = false,
1430
1688
  onShowAllTerminalsChange,
1431
- tabLabelPrefix
1689
+ tabLabelPrefix,
1690
+ renderTabContent
1432
1691
  }) => {
1433
- const { theme } = useTheme4();
1434
- const [ownedTabs, setOwnedTabs] = useState3(initialTabs);
1435
- const [foreignTabs, setForeignTabs] = useState3([]);
1436
- const [activeTabId, setActiveTabId] = useState3(null);
1437
- const [sessionIds, setSessionIds] = useState3(new Map);
1438
- const [hoveredTabId, setHoveredTabId] = useState3(null);
1439
- const [scrollPositions, setScrollPositions] = useState3(new Map);
1692
+ const { theme } = useTheme6();
1693
+ const [ownedTabs, setOwnedTabs] = useState4(initialTabs);
1694
+ const [foreignTabs, setForeignTabs] = useState4([]);
1695
+ const [activeTabId, setActiveTabId] = useState4(null);
1696
+ const [sessionIds, setSessionIds] = useState4(new Map);
1697
+ const [scrollPositions, setScrollPositions] = useState4(new Map);
1698
+ useEffect4(() => {
1699
+ const customTabsFromProp = initialTabs.filter((tab) => tab.contentType !== "terminal");
1700
+ setOwnedTabs((prevTabs) => {
1701
+ const existingTerminalTabs = prevTabs.filter((tab) => tab.contentType === "terminal");
1702
+ const customTabIds = new Set(customTabsFromProp.map((t) => t.id));
1703
+ const existingCustomTabs = prevTabs.filter((tab) => tab.contentType !== "terminal" && !customTabIds.has(tab.id));
1704
+ const mergedTabs = [
1705
+ ...existingTerminalTabs,
1706
+ ...existingCustomTabs,
1707
+ ...customTabsFromProp
1708
+ ];
1709
+ const prevCustomTabs = prevTabs.filter((tab) => tab.contentType !== "terminal");
1710
+ const customTabsChanged = prevCustomTabs.length !== customTabsFromProp.length || !customTabsFromProp.every((tab) => prevCustomTabs.some((prev) => prev.id === tab.id));
1711
+ if (!customTabsChanged) {
1712
+ return prevTabs;
1713
+ }
1714
+ return mergedTabs;
1715
+ });
1716
+ }, [initialTabs]);
1440
1717
  const getOwnedTabLabel = useCallback2((index, _directory) => {
1441
1718
  if (tabLabelPrefix) {
1442
1719
  return `${tabLabelPrefix} ${index + 1}`;
1443
1720
  }
1444
1721
  return `⌘ ${index + 1}`;
1445
1722
  }, [tabLabelPrefix]);
1446
- const tabs = React.useMemo(() => {
1723
+ const tabs = React2.useMemo(() => {
1447
1724
  const labeledOwnedTabs = ownedTabs.map((tab, index) => ({
1448
1725
  ...tab,
1449
1726
  label: getOwnedTabLabel(index, tab.directory)
@@ -1451,6 +1728,18 @@ var TabbedTerminalPanelInner = ({
1451
1728
  const sortedForeignTabs = [...foreignTabs].sort((a, b) => a.label.localeCompare(b.label));
1452
1729
  return [...labeledOwnedTabs, ...sortedForeignTabs];
1453
1730
  }, [ownedTabs, foreignTabs, getOwnedTabLabel]);
1731
+ const genericTabs = React2.useMemo(() => {
1732
+ return tabs.map((tab) => ({
1733
+ id: tab.id,
1734
+ label: tab.label,
1735
+ closable: true,
1736
+ contentType: tab.contentType,
1737
+ metadata: {
1738
+ ...tab.directory && { directory: tab.directory },
1739
+ ...tab.command && { command: tab.command }
1740
+ }
1741
+ }));
1742
+ }, [tabs]);
1454
1743
  const tabRefsMap = useRef3(new Map);
1455
1744
  const refCallbacksMap = useRef3(new Map);
1456
1745
  const getRefCallback = useCallback2((tabId) => {
@@ -1493,14 +1782,15 @@ var TabbedTerminalPanelInner = ({
1493
1782
  if (ownedSessions.length > 0 && initialTabs.length === 0) {
1494
1783
  const restoredTabs = [];
1495
1784
  const restoredSessionIds = new Map;
1496
- ownedSessions.forEach((session, index) => {
1785
+ ownedSessions.forEach((session) => {
1497
1786
  const tabId = `tab-restored-${session.id}`;
1498
1787
  const sessionCwd = session.cwd || directory;
1499
1788
  const tab = {
1500
1789
  id: tabId,
1501
1790
  label: sessionCwd.split("/").pop() || sessionCwd,
1791
+ contentType: "terminal",
1502
1792
  directory: sessionCwd,
1503
- isActive: index === 0
1793
+ closable: true
1504
1794
  };
1505
1795
  restoredTabs.push(tab);
1506
1796
  restoredSessionIds.set(tabId, session.id);
@@ -1511,7 +1801,7 @@ var TabbedTerminalPanelInner = ({
1511
1801
  onTabsChange?.(restoredTabs);
1512
1802
  } else if (initialTabs.length > 0) {
1513
1803
  setOwnedTabs(initialTabs);
1514
- setActiveTabId(initialTabs.find((t) => t.isActive)?.id || initialTabs[0]?.id || null);
1804
+ setActiveTabId(initialTabs[0]?.id || null);
1515
1805
  }
1516
1806
  } catch (err) {
1517
1807
  console.error("[TabbedTerminalPanel] Failed to restore owned sessions:", err);
@@ -1532,8 +1822,9 @@ var TabbedTerminalPanelInner = ({
1532
1822
  const tab = {
1533
1823
  id: tabId,
1534
1824
  label: sessionCwd.split("/").pop() || sessionCwd,
1825
+ contentType: "terminal",
1535
1826
  directory: sessionCwd,
1536
- isActive: false
1827
+ closable: true
1537
1828
  };
1538
1829
  foreignTabsList.push(tab);
1539
1830
  newSessionIds.set(tabId, session.id);
@@ -1559,13 +1850,13 @@ var TabbedTerminalPanelInner = ({
1559
1850
  return [];
1560
1851
  });
1561
1852
  }, []);
1562
- useEffect3(() => {
1853
+ useEffect4(() => {
1563
1854
  if (hasInitializedRef.current)
1564
1855
  return;
1565
1856
  hasInitializedRef.current = true;
1566
1857
  restoreOwnedSessions();
1567
1858
  }, []);
1568
- useEffect3(() => {
1859
+ useEffect4(() => {
1569
1860
  const handleSessionCreated2 = (event) => {
1570
1861
  const customEvent = event;
1571
1862
  const { context } = customEvent.detail || {};
@@ -1579,7 +1870,7 @@ var TabbedTerminalPanelInner = ({
1579
1870
  window.removeEventListener("terminal-session-created", handleSessionCreated2);
1580
1871
  };
1581
1872
  }, [terminalContext, restoreOwnedSessions]);
1582
- useEffect3(() => {
1873
+ useEffect4(() => {
1583
1874
  if (showAllTerminals) {
1584
1875
  fetchForeignSessions();
1585
1876
  } else {
@@ -1603,17 +1894,16 @@ var TabbedTerminalPanelInner = ({
1603
1894
  const newTab = {
1604
1895
  id: `tab-${Date.now()}`,
1605
1896
  label: label || directoryName,
1897
+ contentType: "terminal",
1606
1898
  directory: targetDir,
1607
1899
  command,
1608
- isActive: true
1900
+ closable: true
1609
1901
  };
1610
1902
  setOwnedTabs((prevTabs) => {
1611
- const updatedTabs = prevTabs.map((t) => ({ ...t, isActive: false }));
1612
- const newTabs = [...updatedTabs, newTab];
1903
+ const newTabs = [...prevTabs, newTab];
1613
1904
  onTabsChange?.(newTabs);
1614
1905
  return newTabs;
1615
1906
  });
1616
- setForeignTabs((prevTabs) => prevTabs.map((t) => ({ ...t, isActive: false })));
1617
1907
  setActiveTabId(newTab.id);
1618
1908
  }, [directory, onTabsChange]);
1619
1909
  const isForeignTab = useCallback2((tabId) => {
@@ -1648,11 +1938,8 @@ var TabbedTerminalPanelInner = ({
1648
1938
  const nextActiveId = findNextActiveTab([...ownedTabs, ...newTabs]);
1649
1939
  if (nextActiveId !== activeTabId) {
1650
1940
  setActiveTabId(nextActiveId);
1651
- if (nextActiveId) {
1652
- setOwnedTabs((owned) => owned.map((t) => ({ ...t, isActive: t.id === nextActiveId })));
1653
- }
1654
1941
  }
1655
- return newTabs.map((t) => ({ ...t, isActive: t.id === nextActiveId }));
1942
+ return newTabs;
1656
1943
  });
1657
1944
  } else {
1658
1945
  setOwnedTabs((prevTabs) => {
@@ -1660,71 +1947,74 @@ var TabbedTerminalPanelInner = ({
1660
1947
  const nextActiveId = findNextActiveTab([...newTabs, ...foreignTabs]);
1661
1948
  if (nextActiveId !== activeTabId) {
1662
1949
  setActiveTabId(nextActiveId);
1663
- if (nextActiveId) {
1664
- setForeignTabs((foreign) => foreign.map((t) => ({ ...t, isActive: t.id === nextActiveId })));
1665
- }
1666
1950
  }
1667
1951
  onTabsChange?.(newTabs);
1668
- return newTabs.map((t) => ({ ...t, isActive: t.id === nextActiveId }));
1952
+ return newTabs;
1669
1953
  });
1670
1954
  }
1671
1955
  }, [activeTabId, sessionIds, actions, onTabsChange, isForeignTab, ownedTabs, foreignTabs]);
1672
1956
  const handleSessionCreated = useCallback2((tabId, sessionId) => {
1673
1957
  setSessionIds((prev) => new Map(prev).set(tabId, sessionId));
1674
1958
  }, []);
1675
- const tabsRef = useRef3(tabs);
1676
- const activeTabIdRef = useRef3(activeTabId);
1677
- const addNewTabRef = useRef3(addNewTab);
1678
- const closeTabRef = useRef3(closeTab);
1679
- const switchTabRef = useRef3(switchTab);
1680
- useEffect3(() => {
1681
- tabsRef.current = tabs;
1682
- activeTabIdRef.current = activeTabId;
1683
- addNewTabRef.current = addNewTab;
1684
- closeTabRef.current = closeTab;
1685
- switchTabRef.current = switchTab;
1686
- }, [tabs, activeTabId, addNewTab, closeTab, switchTab]);
1687
- useEffect3(() => {
1688
- const handleKeyDown = (e) => {
1689
- if ((e.metaKey || e.ctrlKey) && e.key === "t") {
1690
- e.preventDefault();
1691
- e.stopPropagation();
1692
- if (isCreatingTabRef.current)
1693
- return;
1694
- isCreatingTabRef.current = true;
1695
- addNewTabRef.current?.();
1696
- setTimeout(() => {
1697
- isCreatingTabRef.current = false;
1698
- }, 500);
1699
- return;
1700
- }
1701
- if ((e.metaKey || e.ctrlKey) && e.key === "w") {
1702
- const currentActiveTabId = activeTabIdRef.current;
1703
- const currentTabs = tabsRef.current;
1704
- if (currentActiveTabId && currentTabs.length > 0) {
1705
- e.preventDefault();
1706
- e.stopPropagation();
1707
- closeTabRef.current?.(currentActiveTabId);
1708
- }
1959
+ useTabKeyboardShortcuts({
1960
+ onNewTab: () => {
1961
+ if (isCreatingTabRef.current)
1709
1962
  return;
1963
+ isCreatingTabRef.current = true;
1964
+ addNewTab();
1965
+ setTimeout(() => {
1966
+ isCreatingTabRef.current = false;
1967
+ }, 500);
1968
+ },
1969
+ onCloseTab: () => {
1970
+ if (activeTabId && tabs.length > 0) {
1971
+ closeTab(activeTabId);
1710
1972
  }
1711
- if ((e.metaKey || e.ctrlKey) && e.key >= "1" && e.key <= "9") {
1712
- e.preventDefault();
1713
- const currentTabs = tabsRef.current;
1714
- const keyNum = parseInt(e.key, 10);
1715
- const tabIndex = keyNum === 9 ? currentTabs.length - 1 : keyNum - 1;
1716
- if (tabIndex >= 0 && tabIndex < currentTabs.length) {
1717
- const targetTab = currentTabs[tabIndex];
1718
- if (targetTab) {
1719
- switchTabRef.current?.(targetTab.id);
1720
- }
1721
- }
1973
+ },
1974
+ onSwitchToTab: (index) => {
1975
+ const tabIndex = index === 8 && tabs.length > 9 ? tabs.length - 1 : index;
1976
+ if (tabIndex >= 0 && tabIndex < tabs.length) {
1977
+ switchTab(tabs[tabIndex].id);
1722
1978
  }
1723
- };
1724
- window.addEventListener("keydown", handleKeyDown);
1725
- return () => window.removeEventListener("keydown", handleKeyDown);
1726
- }, []);
1727
- return /* @__PURE__ */ jsxs3("div", {
1979
+ }
1980
+ });
1981
+ const renderTabAccessory = useCallback2((tab) => {
1982
+ if (tab.id !== activeTabId)
1983
+ return null;
1984
+ const scrollPosition = scrollPositions.get(tab.id) ?? defaultScrollPosition;
1985
+ return /* @__PURE__ */ jsx6("button", {
1986
+ onClick: (e) => {
1987
+ e.stopPropagation();
1988
+ handleToggleScrollLock();
1989
+ },
1990
+ style: {
1991
+ display: "flex",
1992
+ alignItems: "center",
1993
+ justifyContent: "center",
1994
+ width: "16px",
1995
+ height: "16px",
1996
+ borderRadius: "3px",
1997
+ border: "none",
1998
+ backgroundColor: "transparent",
1999
+ cursor: "pointer",
2000
+ color: scrollPosition.isScrollLocked ? theme.colors.success : theme.colors.warning,
2001
+ padding: 0
2002
+ },
2003
+ onMouseEnter: (e) => {
2004
+ e.currentTarget.style.backgroundColor = theme.colors.backgroundTertiary;
2005
+ },
2006
+ onMouseLeave: (e) => {
2007
+ e.currentTarget.style.backgroundColor = "transparent";
2008
+ },
2009
+ title: scrollPosition.isScrollLocked ? "Scroll locked" : "Scroll unlocked",
2010
+ children: scrollPosition.isScrollLocked ? /* @__PURE__ */ jsx6(Lock2, {
2011
+ size: 10
2012
+ }) : /* @__PURE__ */ jsx6(Unlock2, {
2013
+ size: 10
2014
+ })
2015
+ });
2016
+ }, [activeTabId, scrollPositions, defaultScrollPosition, handleToggleScrollLock, theme]);
2017
+ return /* @__PURE__ */ jsxs5("div", {
1728
2018
  style: {
1729
2019
  display: "flex",
1730
2020
  flexDirection: "column",
@@ -1732,205 +2022,50 @@ var TabbedTerminalPanelInner = ({
1732
2022
  backgroundColor: theme.colors.background
1733
2023
  },
1734
2024
  children: [
1735
- !hideHeader && /* @__PURE__ */ jsxs3("div", {
2025
+ !hideHeader && /* @__PURE__ */ jsx6("div", {
1736
2026
  ref: headerRef,
1737
- style: {
1738
- display: "flex",
1739
- alignItems: "stretch",
1740
- height: "40px",
1741
- flexShrink: 0,
1742
- boxSizing: "border-box"
1743
- },
1744
- children: [
1745
- /* @__PURE__ */ jsx4("div", {
2027
+ children: /* @__PURE__ */ jsx6(TabBar, {
2028
+ tabs: genericTabs,
2029
+ activeTabId,
2030
+ onTabClick: switchTab,
2031
+ onTabClose: closeTab,
2032
+ onNewTab: addNewTab,
2033
+ leftSection: /* @__PURE__ */ jsx6("button", {
2034
+ onClick: () => onShowAllTerminalsChange?.(!showAllTerminals),
1746
2035
  style: {
1747
2036
  display: "flex",
1748
2037
  alignItems: "center",
1749
- gap: "4px",
1750
- padding: "0 8px",
1751
- borderRight: `1px solid ${theme.colors.border}`,
1752
- borderBottom: `1px solid ${theme.colors.border}`,
1753
- boxSizing: "border-box"
1754
- },
1755
- children: /* @__PURE__ */ jsx4("button", {
1756
- onClick: () => onShowAllTerminalsChange?.(!showAllTerminals),
1757
- style: {
1758
- display: "flex",
1759
- alignItems: "center",
1760
- justifyContent: "center",
1761
- width: "28px",
1762
- height: "28px",
1763
- border: "none",
1764
- borderRadius: "4px",
1765
- backgroundColor: showAllTerminals ? `${theme.colors.primary}22` : "transparent",
1766
- cursor: "pointer",
1767
- color: showAllTerminals ? theme.colors.primary : theme.colors.textSecondary
1768
- },
1769
- onMouseEnter: (e) => {
1770
- if (!showAllTerminals) {
1771
- e.currentTarget.style.backgroundColor = theme.colors.backgroundTertiary;
1772
- }
1773
- },
1774
- onMouseLeave: (e) => {
1775
- if (!showAllTerminals) {
1776
- e.currentTarget.style.backgroundColor = "transparent";
1777
- }
1778
- },
1779
- title: showAllTerminals ? "Showing all terminals (click to filter by context)" : "Show all terminals",
1780
- children: showAllTerminals ? /* @__PURE__ */ jsx4(Boxes, {
1781
- size: 14
1782
- }) : /* @__PURE__ */ jsx4(Box, {
1783
- size: 14
1784
- })
1785
- })
1786
- }),
1787
- /* @__PURE__ */ jsx4("div", {
1788
- style: {
1789
- display: "flex",
1790
- alignItems: "center",
1791
- flex: 1,
1792
- overflow: "hidden",
1793
- borderBottom: `1px solid ${theme.colors.border}`,
1794
- boxSizing: "border-box"
1795
- },
1796
- children: tabs.map((tab) => /* @__PURE__ */ jsxs3("div", {
1797
- onClick: (e) => {
1798
- e.stopPropagation();
1799
- switchTab(tab.id);
1800
- },
1801
- onMouseEnter: () => setHoveredTabId(tab.id),
1802
- onMouseLeave: () => setHoveredTabId(null),
1803
- style: {
1804
- display: "flex",
1805
- alignItems: "center",
1806
- justifyContent: "center",
1807
- gap: "6px",
1808
- padding: "6px 8px",
1809
- backgroundColor: tab.isActive ? theme.colors.background : theme.colors.backgroundSecondary,
1810
- borderBottom: "none",
1811
- cursor: "pointer",
1812
- fontSize: theme.fontSizes[1],
1813
- fontWeight: tab.isActive ? theme.fontWeights.semibold : theme.fontWeights.body,
1814
- fontFamily: theme.fonts.body,
1815
- color: tab.isActive ? theme.colors.text : theme.colors.textSecondary,
1816
- whiteSpace: "nowrap",
1817
- transition: "all 0.2s",
1818
- flex: 1,
1819
- minWidth: 0,
1820
- height: "100%",
1821
- position: "relative",
1822
- boxSizing: "border-box"
1823
- },
1824
- children: [
1825
- hoveredTabId === tab.id && /* @__PURE__ */ jsx4("button", {
1826
- onClick: (e) => {
1827
- e.stopPropagation();
1828
- closeTab(tab.id);
1829
- },
1830
- style: {
1831
- display: "flex",
1832
- alignItems: "center",
1833
- justifyContent: "center",
1834
- width: "16px",
1835
- height: "16px",
1836
- borderRadius: "3px",
1837
- border: "none",
1838
- backgroundColor: "transparent",
1839
- cursor: "pointer",
1840
- color: theme.colors.textSecondary,
1841
- padding: 0,
1842
- position: "absolute",
1843
- left: "8px"
1844
- },
1845
- onMouseEnter: (e) => {
1846
- e.currentTarget.style.backgroundColor = theme.colors.backgroundTertiary;
1847
- },
1848
- onMouseLeave: (e) => {
1849
- e.currentTarget.style.backgroundColor = "transparent";
1850
- },
1851
- children: /* @__PURE__ */ jsx4(X2, {
1852
- size: 12
1853
- })
1854
- }),
1855
- /* @__PURE__ */ jsx4("span", {
1856
- title: tab.directory.split("/").pop() || tab.directory,
1857
- children: tab.label
1858
- }),
1859
- tab.isActive && /* @__PURE__ */ jsx4("button", {
1860
- onClick: (e) => {
1861
- e.stopPropagation();
1862
- handleToggleScrollLock();
1863
- },
1864
- style: {
1865
- display: "flex",
1866
- alignItems: "center",
1867
- justifyContent: "center",
1868
- width: "16px",
1869
- height: "16px",
1870
- borderRadius: "3px",
1871
- border: "none",
1872
- backgroundColor: "transparent",
1873
- cursor: "pointer",
1874
- color: (scrollPositions.get(tab.id) ?? defaultScrollPosition).isScrollLocked ? theme.colors.success : theme.colors.warning,
1875
- padding: 0,
1876
- position: "absolute",
1877
- right: "8px"
1878
- },
1879
- onMouseEnter: (e) => {
1880
- e.currentTarget.style.backgroundColor = theme.colors.backgroundTertiary;
1881
- },
1882
- onMouseLeave: (e) => {
1883
- e.currentTarget.style.backgroundColor = "transparent";
1884
- },
1885
- title: (scrollPositions.get(tab.id) ?? defaultScrollPosition).isScrollLocked ? "Scroll locked" : "Scroll unlocked",
1886
- children: (scrollPositions.get(tab.id) ?? defaultScrollPosition).isScrollLocked ? /* @__PURE__ */ jsx4(Lock2, {
1887
- size: 10
1888
- }) : /* @__PURE__ */ jsx4(Unlock2, {
1889
- size: 10
1890
- })
1891
- })
1892
- ]
1893
- }, tab.id))
1894
- }),
1895
- /* @__PURE__ */ jsx4("div", {
1896
- style: {
1897
- display: "flex",
1898
- alignItems: "center",
1899
- gap: "4px",
1900
- padding: "0 8px",
1901
- borderLeft: `1px solid ${theme.colors.border}`,
1902
- borderBottom: `1px solid ${theme.colors.border}`,
1903
- boxSizing: "border-box"
2038
+ justifyContent: "center",
2039
+ width: "28px",
2040
+ height: "28px",
2041
+ border: "none",
2042
+ borderRadius: "4px",
2043
+ backgroundColor: showAllTerminals ? `${theme.colors.primary}22` : "transparent",
2044
+ cursor: "pointer",
2045
+ color: showAllTerminals ? theme.colors.primary : theme.colors.textSecondary
1904
2046
  },
1905
- children: /* @__PURE__ */ jsx4("button", {
1906
- onClick: () => addNewTab(),
1907
- style: {
1908
- display: "flex",
1909
- alignItems: "center",
1910
- justifyContent: "center",
1911
- width: "28px",
1912
- height: "28px",
1913
- border: "none",
1914
- borderRadius: "4px",
1915
- backgroundColor: "transparent",
1916
- cursor: "pointer",
1917
- color: theme.colors.textSecondary
1918
- },
1919
- onMouseEnter: (e) => {
2047
+ onMouseEnter: (e) => {
2048
+ if (!showAllTerminals) {
1920
2049
  e.currentTarget.style.backgroundColor = theme.colors.backgroundTertiary;
1921
- },
1922
- onMouseLeave: (e) => {
2050
+ }
2051
+ },
2052
+ onMouseLeave: (e) => {
2053
+ if (!showAllTerminals) {
1923
2054
  e.currentTarget.style.backgroundColor = "transparent";
1924
- },
1925
- title: "New terminal (Cmd+T)",
1926
- children: /* @__PURE__ */ jsx4(Plus, {
1927
- size: 14
1928
- })
2055
+ }
2056
+ },
2057
+ title: showAllTerminals ? "Showing all terminals (click to filter by context)" : "Show all terminals",
2058
+ children: showAllTerminals ? /* @__PURE__ */ jsx6(Boxes, {
2059
+ size: 14
2060
+ }) : /* @__PURE__ */ jsx6(Box, {
2061
+ size: 14
1929
2062
  })
1930
- })
1931
- ]
2063
+ }),
2064
+ renderTabAccessory,
2065
+ showKeyboardHints: false
2066
+ })
1932
2067
  }),
1933
- /* @__PURE__ */ jsxs3("div", {
2068
+ /* @__PURE__ */ jsxs5("div", {
1934
2069
  style: {
1935
2070
  flex: 1,
1936
2071
  display: "flex",
@@ -1940,20 +2075,74 @@ var TabbedTerminalPanelInner = ({
1940
2075
  minHeight: 0
1941
2076
  },
1942
2077
  children: [
1943
- tabs.map((tab) => /* @__PURE__ */ jsx4(TerminalTabContent, {
1944
- ref: getRefCallback(tab.id),
1945
- tab,
1946
- sessionId: sessionIds.get(tab.id) || null,
1947
- isActive: tab.id === activeTabId,
1948
- isVisible,
1949
- actions,
1950
- events,
1951
- terminalContext,
1952
- onSessionCreated: handleSessionCreated,
1953
- onScrollPositionChange: handleTabScrollPositionChange,
1954
- isForeign: tab.id.startsWith("tab-foreign-")
1955
- }, tab.id)),
1956
- tabs.length === 0 && /* @__PURE__ */ jsxs3("div", {
2078
+ tabs.map((tab) => {
2079
+ const isActive = tab.id === activeTabId;
2080
+ const sessionId = sessionIds.get(tab.id) || null;
2081
+ if (renderTabContent) {
2082
+ const customContent = renderTabContent(tab, isActive, sessionId);
2083
+ if (customContent === null && tab.contentType === "terminal") {
2084
+ return /* @__PURE__ */ jsx6(TerminalTabContent, {
2085
+ ref: getRefCallback(tab.id),
2086
+ tab,
2087
+ sessionId,
2088
+ isActive,
2089
+ isVisible,
2090
+ actions,
2091
+ events,
2092
+ terminalContext,
2093
+ onSessionCreated: handleSessionCreated,
2094
+ onScrollPositionChange: handleTabScrollPositionChange,
2095
+ isForeign: tab.id.startsWith("tab-foreign-")
2096
+ }, tab.id);
2097
+ }
2098
+ return /* @__PURE__ */ jsx6("div", {
2099
+ style: {
2100
+ display: isActive ? "flex" : "none",
2101
+ flexDirection: "column",
2102
+ height: "100%",
2103
+ width: "100%"
2104
+ },
2105
+ children: customContent
2106
+ }, tab.id);
2107
+ }
2108
+ if (tab.contentType === "terminal") {
2109
+ return /* @__PURE__ */ jsx6(TerminalTabContent, {
2110
+ ref: getRefCallback(tab.id),
2111
+ tab,
2112
+ sessionId,
2113
+ isActive,
2114
+ isVisible,
2115
+ actions,
2116
+ events,
2117
+ terminalContext,
2118
+ onSessionCreated: handleSessionCreated,
2119
+ onScrollPositionChange: handleTabScrollPositionChange,
2120
+ isForeign: tab.id.startsWith("tab-foreign-")
2121
+ }, tab.id);
2122
+ }
2123
+ return /* @__PURE__ */ jsxs5("div", {
2124
+ style: {
2125
+ display: isActive ? "flex" : "none",
2126
+ alignItems: "center",
2127
+ justifyContent: "center",
2128
+ height: "100%",
2129
+ color: theme.colors.textSecondary
2130
+ },
2131
+ children: [
2132
+ /* @__PURE__ */ jsxs5("p", {
2133
+ children: [
2134
+ "Unknown content type: ",
2135
+ tab.contentType
2136
+ ]
2137
+ }),
2138
+ /* @__PURE__ */ jsx6("p", {
2139
+ style: { fontSize: theme.fontSizes[0], marginTop: "8px" },
2140
+ children: "Provide a renderTabContent prop to render custom tab types"
2141
+ })
2142
+ ]
2143
+ }, tab.id);
2144
+ }),
2145
+ tabs.length === 0 && /* @__PURE__ */ jsxs5("div", {
1957
2146
  style: {
1958
2147
  display: "flex",
1959
2148
  flexDirection: "column",
@@ -1963,14 +2152,14 @@ var TabbedTerminalPanelInner = ({
1963
2152
  color: theme.colors.textSecondary
1964
2153
  },
1965
2154
  children: [
1966
- /* @__PURE__ */ jsx4(TerminalIcon2, {
2155
+ /* @__PURE__ */ jsx6(TerminalIcon2, {
1967
2156
  size: 32,
1968
2157
  style: { opacity: 0.5, marginBottom: "16px" }
1969
2158
  }),
1970
- /* @__PURE__ */ jsx4("p", {
2159
+ /* @__PURE__ */ jsx6("p", {
1971
2160
  children: "No terminal sessions"
1972
2161
  }),
1973
- /* @__PURE__ */ jsx4("button", {
2162
+ /* @__PURE__ */ jsx6("button", {
1974
2163
  onClick: () => addNewTab(),
1975
2164
  style: {
1976
2165
  marginTop: "16px",
@@ -1993,7 +2182,7 @@ var TabbedTerminalPanelInner = ({
1993
2182
  });
1994
2183
  };
1995
2184
  TabbedTerminalPanelInner.displayName = "TabbedTerminalPanelInner";
1996
- var TabbedTerminalPanel = React.memo(TabbedTerminalPanelInner, (prevProps, nextProps) => {
2185
+ var TabbedTerminalPanelMemoized = React2.memo(TabbedTerminalPanelInner, (prevProps, nextProps) => {
1997
2186
  const changes = [];
1998
2187
  if (prevProps.terminalContext !== nextProps.terminalContext)
1999
2188
  changes.push("terminalContext");
@@ -2015,9 +2204,12 @@ var TabbedTerminalPanel = React.memo(TabbedTerminalPanelInner, (prevProps, nextP
2015
2204
  changes.push("onShowAllTerminalsChange");
2016
2205
  if (prevProps.initialTabs !== nextProps.initialTabs)
2017
2206
  changes.push("initialTabs");
2207
+ if (prevProps.renderTabContent !== nextProps.renderTabContent)
2208
+ changes.push("renderTabContent");
2018
2209
  return changes.length === 0;
2019
2210
  });
2020
- TabbedTerminalPanel.displayName = "TabbedTerminalPanel";
2211
+ TabbedTerminalPanelMemoized.displayName = "TabbedTerminalPanel";
2212
+ var TabbedTerminalPanel = TabbedTerminalPanelMemoized;
2021
2213
  // src/tools/index.ts
2022
2214
  var createTerminalSessionTool = {
2023
2215
  name: "create_terminal_session",
@@ -2200,12 +2392,14 @@ var onPackageUnload = async () => {
2200
2392
  export {
2201
2393
  writeToTerminalTool,
2202
2394
  useThemedTerminal,
2395
+ useTabKeyboardShortcuts,
2203
2396
  terminalPanelToolsMetadata,
2204
2397
  terminalPanelTools,
2205
2398
  panels,
2206
2399
  onPackageUnload,
2207
2400
  onPackageLoad,
2208
2401
  isTerminalLoading,
2402
+ isTabOfType,
2209
2403
  getWorkspacePath,
2210
2404
  getTerminalSlice,
2211
2405
  getTerminalSessions,
@@ -2221,5 +2415,7 @@ export {
2221
2415
  ThemedTerminalWithProvider,
2222
2416
  ThemedTerminal,
2223
2417
  TerminalPanel,
2224
- TabbedTerminalPanel
2418
+ TabbedTerminalPanel,
2419
+ TabButton,
2420
+ TabBar
2225
2421
  };