green-screen-react 1.1.2 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -118,8 +118,14 @@ interface GreenScreenTerminalProps {
118
118
  autoFocusDisabled?: boolean;
119
119
  /** Custom boot loader element, or false to disable */
120
120
  bootLoader?: React.ReactNode | false;
121
+ /** When true, dismiss the boot loader. If provided, overrides the default
122
+ * "dismiss when screen data arrives" behavior. Use to keep the boot loader
123
+ * visible during sign-in, startup command execution, etc. */
124
+ bootLoaderReady?: boolean;
121
125
  /** Content for the right side of the header */
122
126
  headerRight?: React.ReactNode;
127
+ /** Content rendered after the connection status groups (WiFi+host, Key+username) */
128
+ statusActions?: React.ReactNode;
123
129
  /** Overlay content (e.g. "Extracting..." state) */
124
130
  overlay?: React.ReactNode;
125
131
  /** Callback for notifications (replaces toast) */
@@ -146,7 +152,7 @@ interface GreenScreenTerminalProps {
146
152
  *
147
153
  * Supports: TN5250 (IBM i), TN3270 (z/OS), VT (OpenVMS/Pick), HP 6530 (NonStop)
148
154
  */
149
- declare function GreenScreenTerminal({ adapter: externalAdapter, baseUrl, workerUrl, protocol, protocolProfile: customProfile, screenData: externalScreenData, connectionStatus: externalStatus, readOnly, pollInterval, autoReconnect: autoReconnectEnabled, maxReconnectAttempts: maxAttempts, embedded, showHeader, typingAnimation, typingBudgetMs, inlineSignIn, defaultProtocol: signInDefaultProtocol, onSignIn, autoSignedIn, autoFocusDisabled, bootLoader, headerRight, overlay, onNotification, onScreenChange, onMinimize, className, style, }: GreenScreenTerminalProps): react_jsx_runtime.JSX.Element;
155
+ declare function GreenScreenTerminal({ adapter: externalAdapter, baseUrl, workerUrl, protocol, protocolProfile: customProfile, screenData: externalScreenData, connectionStatus: externalStatus, readOnly, pollInterval, autoReconnect: autoReconnectEnabled, maxReconnectAttempts: maxAttempts, embedded, showHeader, typingAnimation, typingBudgetMs, inlineSignIn, defaultProtocol: signInDefaultProtocol, onSignIn, autoSignedIn, autoFocusDisabled, bootLoader, bootLoaderReady, headerRight, statusActions, overlay, onNotification, onScreenChange, onMinimize, className, style, }: GreenScreenTerminalProps): react_jsx_runtime.JSX.Element;
150
156
 
151
157
  interface TerminalBootLoaderProps {
152
158
  /** Text to display during boot animation */
package/dist/index.d.ts CHANGED
@@ -118,8 +118,14 @@ interface GreenScreenTerminalProps {
118
118
  autoFocusDisabled?: boolean;
119
119
  /** Custom boot loader element, or false to disable */
120
120
  bootLoader?: React.ReactNode | false;
121
+ /** When true, dismiss the boot loader. If provided, overrides the default
122
+ * "dismiss when screen data arrives" behavior. Use to keep the boot loader
123
+ * visible during sign-in, startup command execution, etc. */
124
+ bootLoaderReady?: boolean;
121
125
  /** Content for the right side of the header */
122
126
  headerRight?: React.ReactNode;
127
+ /** Content rendered after the connection status groups (WiFi+host, Key+username) */
128
+ statusActions?: React.ReactNode;
123
129
  /** Overlay content (e.g. "Extracting..." state) */
124
130
  overlay?: React.ReactNode;
125
131
  /** Callback for notifications (replaces toast) */
@@ -146,7 +152,7 @@ interface GreenScreenTerminalProps {
146
152
  *
147
153
  * Supports: TN5250 (IBM i), TN3270 (z/OS), VT (OpenVMS/Pick), HP 6530 (NonStop)
148
154
  */
149
- declare function GreenScreenTerminal({ adapter: externalAdapter, baseUrl, workerUrl, protocol, protocolProfile: customProfile, screenData: externalScreenData, connectionStatus: externalStatus, readOnly, pollInterval, autoReconnect: autoReconnectEnabled, maxReconnectAttempts: maxAttempts, embedded, showHeader, typingAnimation, typingBudgetMs, inlineSignIn, defaultProtocol: signInDefaultProtocol, onSignIn, autoSignedIn, autoFocusDisabled, bootLoader, headerRight, overlay, onNotification, onScreenChange, onMinimize, className, style, }: GreenScreenTerminalProps): react_jsx_runtime.JSX.Element;
155
+ declare function GreenScreenTerminal({ adapter: externalAdapter, baseUrl, workerUrl, protocol, protocolProfile: customProfile, screenData: externalScreenData, connectionStatus: externalStatus, readOnly, pollInterval, autoReconnect: autoReconnectEnabled, maxReconnectAttempts: maxAttempts, embedded, showHeader, typingAnimation, typingBudgetMs, inlineSignIn, defaultProtocol: signInDefaultProtocol, onSignIn, autoSignedIn, autoFocusDisabled, bootLoader, bootLoaderReady, headerRight, statusActions, overlay, onNotification, onScreenChange, onMinimize, className, style, }: GreenScreenTerminalProps): react_jsx_runtime.JSX.Element;
150
156
 
151
157
  interface TerminalBootLoaderProps {
152
158
  /** Text to display during boot animation */
package/dist/index.js CHANGED
@@ -1120,7 +1120,9 @@ function GreenScreenTerminal({
1120
1120
  autoSignedIn,
1121
1121
  autoFocusDisabled = false,
1122
1122
  bootLoader,
1123
+ bootLoaderReady,
1123
1124
  headerRight,
1125
+ statusActions,
1124
1126
  overlay,
1125
1127
  onNotification,
1126
1128
  onScreenChange,
@@ -1169,13 +1171,14 @@ function GreenScreenTerminal({
1169
1171
  const sendText = (0, import_react5.useCallback)(async (text) => _sendText(text), [_sendText]);
1170
1172
  const sendKey = (0, import_react5.useCallback)(async (key) => _sendKey(key), [_sendKey]);
1171
1173
  const [optimisticEdits, setOptimisticEdits] = (0, import_react5.useState)([]);
1172
- const prevScreenSigForEdits = (0, import_react5.useRef)(void 0);
1174
+ const prevScreenContentForEdits = (0, import_react5.useRef)(void 0);
1173
1175
  (0, import_react5.useEffect)(() => {
1174
- if (rawScreenData?.screen_signature && rawScreenData.screen_signature !== prevScreenSigForEdits.current) {
1175
- prevScreenSigForEdits.current = rawScreenData.screen_signature;
1176
+ const content = rawScreenData?.content;
1177
+ if (content && content !== prevScreenContentForEdits.current) {
1178
+ prevScreenContentForEdits.current = content;
1176
1179
  setOptimisticEdits([]);
1177
1180
  }
1178
- }, [rawScreenData?.screen_signature]);
1181
+ }, [rawScreenData?.content]);
1179
1182
  const [inputText, setInputText] = (0, import_react5.useState)("");
1180
1183
  const [isFocused, setIsFocused] = (0, import_react5.useState)(false);
1181
1184
  const [showSignInHint, setShowSignInHint] = (0, import_react5.useState)(false);
@@ -1273,13 +1276,15 @@ function GreenScreenTerminal({
1273
1276
  const [showBootLoader, setShowBootLoader] = (0, import_react5.useState)(bootLoader !== false);
1274
1277
  const [bootFadingOut, setBootFadingOut] = (0, import_react5.useState)(false);
1275
1278
  (0, import_react5.useEffect)(() => {
1276
- if (screenData?.content && showBootLoader) {
1279
+ if (!showBootLoader) return;
1280
+ const shouldDismiss = bootLoaderReady !== void 0 ? bootLoaderReady : !!screenData?.content;
1281
+ if (shouldDismiss) {
1277
1282
  setBootFadingOut(true);
1278
1283
  setShowBootLoader(false);
1279
1284
  const timer = setTimeout(() => setBootFadingOut(false), 400);
1280
1285
  return () => clearTimeout(timer);
1281
1286
  }
1282
- }, [screenData?.content, showBootLoader]);
1287
+ }, [screenData?.content, showBootLoader, bootLoaderReady]);
1283
1288
  const FOCUS_STORAGE_KEY = "gs-terminal-focused";
1284
1289
  (0, import_react5.useEffect)(() => {
1285
1290
  if (!autoFocusDisabled && !readOnly) {
@@ -1514,7 +1519,7 @@ function GreenScreenTerminal({
1514
1519
  }
1515
1520
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { width: `${screenData?.cols || profile.defaultCols}ch`, height: `${(screenData?.rows || profile.defaultRows) * 21}px`, display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { textAlign: "center" }, children: [
1516
1521
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { color: "#808080", marginBottom: "12px" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TerminalIcon, { size: 40 }) }),
1517
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: { fontFamily: "var(--gs-font)", fontSize: "12px", color: "#808080" }, children: connStatus?.connected ? "Waiting for screen data..." : "Not connected" }),
1522
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: { fontFamily: "var(--gs-font)", fontSize: "12px", color: connStatus?.status === "connecting" ? "#f59e0b" : connStatus?.status === "loading" ? "#94a3b8" : "#808080" }, children: connStatus?.connected ? "Waiting for screen data..." : connStatus?.status === "connecting" ? "Connecting..." : connStatus?.status === "loading" ? "Loading..." : "Not connected" }),
1518
1523
  !connStatus?.connected && isUsingDefaultAdapter && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { style: { fontFamily: "var(--gs-font)", fontSize: "11px", color: "#606060", marginTop: "8px" }, children: [
1519
1524
  "Start the proxy: ",
1520
1525
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("code", { style: { color: "#10b981" }, children: "npx green-screen-proxy --mock" })
@@ -1535,7 +1540,7 @@ function GreenScreenTerminal({
1535
1540
  const cursor = getCursorPos();
1536
1541
  const hasCursor = screenData.cursor_row !== void 0 && screenData.cursor_col !== void 0;
1537
1542
  const cursorInInputField = hasCursor && fields.some(
1538
- (f) => f.is_input && f.row === cursor.row && cursor.col >= f.col && cursor.col < f.col + f.length
1543
+ (f) => f.is_input && !f.is_non_display && f.row === cursor.row && cursor.col >= f.col && cursor.col < f.col + f.length
1539
1544
  );
1540
1545
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { fontFamily: "var(--gs-font)", fontSize: "13px", position: "relative", width: `${cols}ch` }, children: [
1541
1546
  rows.map((line, index) => {
@@ -1597,8 +1602,9 @@ function GreenScreenTerminal({
1597
1602
  screenData?.insert_mode && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "gs-badge-ins", children: "INS" })
1598
1603
  ] }),
1599
1604
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "gs-header-right", children: [
1600
- connStatus?.status && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(KeyIcon, { size: 12, style: { color: getStatusColor(connStatus.status) } }),
1601
- connStatus && (connStatus.connected ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(WifiIcon, { size: 12, style: { color: "var(--gs-green, #10b981)" } }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(WifiOffIcon, { size: 12, style: { color: "#FF6B00" } })),
1605
+ connStatus?.status && connStatus.status !== "loading" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(KeyIcon, { size: 12, style: { color: getStatusColor(connStatus.status) } }),
1606
+ connStatus && connStatus.status !== "loading" && (connStatus.connected ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(WifiIcon, { size: 12, style: { color: "var(--gs-green, #10b981)" } }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(WifiOffIcon, { size: 12, style: { color: "#FF6B00" } })),
1607
+ statusActions,
1602
1608
  onMinimize && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { onClick: (e) => {
1603
1609
  e.stopPropagation();
1604
1610
  onMinimize();
@@ -1620,7 +1626,7 @@ function GreenScreenTerminal({
1620
1626
  screenData?.insert_mode && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "gs-badge-ins", children: "INS" })
1621
1627
  ] }),
1622
1628
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "gs-header-right", children: [
1623
- connStatus && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "gs-status-group", children: connStatus.connected ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
1629
+ connStatus && connStatus.status !== "loading" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "gs-status-group", children: connStatus.connected ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
1624
1630
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(WifiIcon, { size: 12, style: { color: "var(--gs-green, #10b981)" } }),
1625
1631
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "gs-host", children: connStatus.host })
1626
1632
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
@@ -1632,6 +1638,7 @@ function GreenScreenTerminal({
1632
1638
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(KeyIcon, { size: 12, style: { color: getStatusColor(connStatus.status) } }),
1633
1639
  connStatus.username && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "gs-host", children: connStatus.username })
1634
1640
  ] }),
1641
+ statusActions,
1635
1642
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { onClick: (e) => {
1636
1643
  e.stopPropagation();
1637
1644
  setShowShortcuts((s) => !s);
@@ -1691,7 +1698,8 @@ function GreenScreenTerminal({
1691
1698
  ] }),
1692
1699
  connStatus && !connStatus.connected && screenData && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "gs-overlay", children: [
1693
1700
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(WifiOffIcon, { size: 28 }),
1694
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: isAutoReconnecting || reconnecting ? "Reconnecting..." : "Disconnected" })
1701
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: isAutoReconnecting || reconnecting ? "Reconnecting..." : connStatus?.status === "connecting" ? "Connecting..." : "Disconnected" }),
1702
+ connStatus.error && !isAutoReconnecting && !reconnecting && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { fontSize: "0.75em", opacity: 0.7, maxWidth: "80%", textAlign: "center", wordBreak: "break-word" }, children: connStatus.error })
1695
1703
  ] }),
1696
1704
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1697
1705
  "input",