@navios/commander-tui 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/tsconfig.tsbuildinfo +1 -1
  3. package/lib/index.cjs +19 -10
  4. package/lib/index.cjs.map +1 -1
  5. package/lib/index.d.cts +37 -28
  6. package/lib/index.d.cts.map +1 -1
  7. package/lib/index.d.mts +48 -39
  8. package/lib/index.d.mts.map +1 -1
  9. package/lib/index.mjs +19 -10
  10. package/lib/index.mjs.map +1 -1
  11. package/lib/{screen_manager_bridge-CkV7637i.cjs → screen_manager_bridge-Cp2p1Ix3.cjs} +1 -1
  12. package/lib/{screen_manager_bridge-Dfg4QUrl.mjs → screen_manager_bridge-D2BBwKcF.mjs} +13 -1
  13. package/lib/screen_manager_bridge-D2BBwKcF.mjs.map +1 -0
  14. package/lib/{screen_manager_bridge-DN2J6_k1.mjs → screen_manager_bridge-DT-l0rxa.mjs} +1 -1
  15. package/lib/{screen_manager_bridge-BpDgVu3e.cjs → screen_manager_bridge-hMUrLiBP.cjs} +13 -1
  16. package/lib/screen_manager_bridge-hMUrLiBP.cjs.map +1 -0
  17. package/package.json +1 -1
  18. package/src/__tests__/components/__snapshots__/filter_bar.spec.tsx.snap +48 -0
  19. package/src/__tests__/components/__snapshots__/loading_message.spec.tsx.snap +32 -0
  20. package/src/__tests__/components/__snapshots__/log_message.spec.tsx.snap +76 -0
  21. package/src/__tests__/components/__snapshots__/progress_message.spec.tsx.snap +40 -0
  22. package/src/__tests__/components/__snapshots__/prompt_renderer.spec.tsx.snap +68 -0
  23. package/src/__tests__/components/__snapshots__/sidebar.spec.tsx.snap +240 -0
  24. package/src/__tests__/components/sidebar.spec.tsx +17 -0
  25. package/src/overrides/console.logger.override.ts +8 -1
  26. package/src/schemas/screen-options.ts +2 -0
  27. package/src/services/screen.ts +3 -0
  28. package/src/services/screen_manager.tsx +15 -11
  29. package/src/themes/dark.ts +4 -0
  30. package/src/themes/high-contrast.ts +4 -0
  31. package/src/themes/light.ts +4 -0
  32. package/src/types/screen.types.ts +1 -1
  33. package/src/types/theme.types.ts +1 -0
  34. package/lib/screen_manager_bridge-BpDgVu3e.cjs.map +0 -1
  35. package/lib/screen_manager_bridge-Dfg4QUrl.mjs.map +0 -1
@@ -138,6 +138,10 @@ exports[`PromptRenderer > choice prompt > should render choice prompt with optio
138
138
  "color": "#F59E0B",
139
139
  "icon": "◐",
140
140
  },
141
+ "static": {
142
+ "color": "#3B82F6",
143
+ "icon": "●",
144
+ },
141
145
  "success": {
142
146
  "color": "#22C55E",
143
147
  "icon": "✓",
@@ -328,6 +332,10 @@ exports[`PromptRenderer > choice prompt > should render choice with input mode 1
328
332
  "color": "#F59E0B",
329
333
  "icon": "◐",
330
334
  },
335
+ "static": {
336
+ "color": "#3B82F6",
337
+ "icon": "●",
338
+ },
331
339
  "success": {
332
340
  "color": "#22C55E",
333
341
  "icon": "✓",
@@ -515,6 +523,10 @@ exports[`PromptRenderer > choice prompt > should render choice with timeout 1`]
515
523
  "color": "#F59E0B",
516
524
  "icon": "◐",
517
525
  },
526
+ "static": {
527
+ "color": "#3B82F6",
528
+ "icon": "●",
529
+ },
518
530
  "success": {
519
531
  "color": "#22C55E",
520
532
  "icon": "✓",
@@ -699,6 +711,10 @@ exports[`PromptRenderer > choice prompt > should render resolved choice prompt 1
699
711
  "color": "#F59E0B",
700
712
  "icon": "◐",
701
713
  },
714
+ "static": {
715
+ "color": "#3B82F6",
716
+ "icon": "●",
717
+ },
702
718
  "success": {
703
719
  "color": "#22C55E",
704
720
  "icon": "✓",
@@ -886,6 +902,10 @@ exports[`PromptRenderer > choice prompt > should render selected option highligh
886
902
  "color": "#F59E0B",
887
903
  "icon": "◐",
888
904
  },
905
+ "static": {
906
+ "color": "#3B82F6",
907
+ "icon": "●",
908
+ },
889
909
  "success": {
890
910
  "color": "#22C55E",
891
911
  "icon": "✓",
@@ -1076,6 +1096,10 @@ exports[`PromptRenderer > confirm prompt > should render confirm prompt (Yes/No)
1076
1096
  "color": "#F59E0B",
1077
1097
  "icon": "◐",
1078
1098
  },
1099
+ "static": {
1100
+ "color": "#3B82F6",
1101
+ "icon": "●",
1102
+ },
1079
1103
  "success": {
1080
1104
  "color": "#22C55E",
1081
1105
  "icon": "✓",
@@ -1252,6 +1276,10 @@ exports[`PromptRenderer > confirm prompt > should render resolved confirm prompt
1252
1276
  "color": "#F59E0B",
1253
1277
  "icon": "◐",
1254
1278
  },
1279
+ "static": {
1280
+ "color": "#3B82F6",
1281
+ "icon": "●",
1282
+ },
1255
1283
  "success": {
1256
1284
  "color": "#22C55E",
1257
1285
  "icon": "✓",
@@ -1429,6 +1457,10 @@ exports[`PromptRenderer > confirm prompt > should render with No selected 1`] =
1429
1457
  "color": "#F59E0B",
1430
1458
  "icon": "◐",
1431
1459
  },
1460
+ "static": {
1461
+ "color": "#3B82F6",
1462
+ "icon": "●",
1463
+ },
1432
1464
  "success": {
1433
1465
  "color": "#22C55E",
1434
1466
  "icon": "✓",
@@ -1605,6 +1637,10 @@ exports[`PromptRenderer > confirm prompt > should render with custom button labe
1605
1637
  "color": "#F59E0B",
1606
1638
  "icon": "◐",
1607
1639
  },
1640
+ "static": {
1641
+ "color": "#3B82F6",
1642
+ "icon": "●",
1643
+ },
1608
1644
  "success": {
1609
1645
  "color": "#22C55E",
1610
1646
  "icon": "✓",
@@ -1781,6 +1817,10 @@ exports[`PromptRenderer > input prompt > should render input prompt with placeho
1781
1817
  "color": "#F59E0B",
1782
1818
  "icon": "◐",
1783
1819
  },
1820
+ "static": {
1821
+ "color": "#3B82F6",
1822
+ "icon": "●",
1823
+ },
1784
1824
  "success": {
1785
1825
  "color": "#22C55E",
1786
1826
  "icon": "✓",
@@ -1956,6 +1996,10 @@ exports[`PromptRenderer > input prompt > should render input with entered value
1956
1996
  "color": "#F59E0B",
1957
1997
  "icon": "◐",
1958
1998
  },
1999
+ "static": {
2000
+ "color": "#3B82F6",
2001
+ "icon": "●",
2002
+ },
1959
2003
  "success": {
1960
2004
  "color": "#22C55E",
1961
2005
  "icon": "✓",
@@ -2131,6 +2175,10 @@ exports[`PromptRenderer > input prompt > should render resolved input prompt 1`]
2131
2175
  "color": "#F59E0B",
2132
2176
  "icon": "◐",
2133
2177
  },
2178
+ "static": {
2179
+ "color": "#3B82F6",
2180
+ "icon": "●",
2181
+ },
2134
2182
  "success": {
2135
2183
  "color": "#22C55E",
2136
2184
  "icon": "✓",
@@ -2307,6 +2355,10 @@ exports[`PromptRenderer > multiChoice prompt > should render multiChoice with ch
2307
2355
  "color": "#F59E0B",
2308
2356
  "icon": "◐",
2309
2357
  },
2358
+ "static": {
2359
+ "color": "#3B82F6",
2360
+ "icon": "●",
2361
+ },
2310
2362
  "success": {
2311
2363
  "color": "#22C55E",
2312
2364
  "icon": "✓",
@@ -2497,6 +2549,10 @@ exports[`PromptRenderer > multiChoice prompt > should render resolved multiChoic
2497
2549
  "color": "#F59E0B",
2498
2550
  "icon": "◐",
2499
2551
  },
2552
+ "static": {
2553
+ "color": "#3B82F6",
2554
+ "icon": "●",
2555
+ },
2500
2556
  "success": {
2501
2557
  "color": "#22C55E",
2502
2558
  "icon": "✓",
@@ -2690,6 +2746,10 @@ exports[`PromptRenderer > multiChoice prompt > should render with some options s
2690
2746
  "color": "#F59E0B",
2691
2747
  "icon": "◐",
2692
2748
  },
2749
+ "static": {
2750
+ "color": "#3B82F6",
2751
+ "icon": "●",
2752
+ },
2693
2753
  "success": {
2694
2754
  "color": "#22C55E",
2695
2755
  "icon": "✓",
@@ -2883,6 +2943,10 @@ exports[`PromptRenderer > multiChoice prompt > should show minSelect warning whe
2883
2943
  "color": "#F59E0B",
2884
2944
  "icon": "◐",
2885
2945
  },
2946
+ "static": {
2947
+ "color": "#3B82F6",
2948
+ "icon": "●",
2949
+ },
2886
2950
  "success": {
2887
2951
  "color": "#22C55E",
2888
2952
  "icon": "✓",
@@ -3075,6 +3139,10 @@ exports[`PromptRenderer > multiChoice prompt > should show selection count 1`] =
3075
3139
  "color": "#F59E0B",
3076
3140
  "icon": "◐",
3077
3141
  },
3142
+ "static": {
3143
+ "color": "#3B82F6",
3144
+ "icon": "●",
3145
+ },
3078
3146
  "success": {
3079
3147
  "color": "#22C55E",
3080
3148
  "icon": "✓",
@@ -138,6 +138,10 @@ exports[`Sidebar > badge counts > should render badge counts 1`] = `
138
138
  "color": "#F59E0B",
139
139
  "icon": "◐",
140
140
  },
141
+ "static": {
142
+ "color": "#3B82F6",
143
+ "icon": "●",
144
+ },
141
145
  "success": {
142
146
  "color": "#22C55E",
143
147
  "icon": "✓",
@@ -334,6 +338,10 @@ exports[`Sidebar > focus state > should render focused state 1`] = `
334
338
  "color": "#F59E0B",
335
339
  "icon": "◐",
336
340
  },
341
+ "static": {
342
+ "color": "#3B82F6",
343
+ "icon": "●",
344
+ },
337
345
  "success": {
338
346
  "color": "#22C55E",
339
347
  "icon": "✓",
@@ -514,6 +522,10 @@ exports[`Sidebar > focus state > should render unfocused state 1`] = `
514
522
  "color": "#F59E0B",
515
523
  "icon": "◐",
516
524
  },
525
+ "static": {
526
+ "color": "#3B82F6",
527
+ "icon": "●",
528
+ },
517
529
  "success": {
518
530
  "color": "#22C55E",
519
531
  "icon": "✓",
@@ -694,6 +706,10 @@ exports[`Sidebar > icons > should render icons 1`] = `
694
706
  "color": "#F59E0B",
695
707
  "icon": "◐",
696
708
  },
709
+ "static": {
710
+ "color": "#3B82F6",
711
+ "icon": "●",
712
+ },
697
713
  "success": {
698
714
  "color": "#22C55E",
699
715
  "icon": "✓",
@@ -890,6 +906,10 @@ exports[`Sidebar > pending vs completed screens > should not show separator if n
890
906
  "color": "#F59E0B",
891
907
  "icon": "◐",
892
908
  },
909
+ "static": {
910
+ "color": "#3B82F6",
911
+ "icon": "●",
912
+ },
893
913
  "success": {
894
914
  "color": "#22C55E",
895
915
  "icon": "✓",
@@ -1078,6 +1098,10 @@ exports[`Sidebar > pending vs completed screens > should separate pending from o
1078
1098
  "color": "#F59E0B",
1079
1099
  "icon": "◐",
1080
1100
  },
1101
+ "static": {
1102
+ "color": "#3B82F6",
1103
+ "icon": "●",
1104
+ },
1081
1105
  "success": {
1082
1106
  "color": "#22C55E",
1083
1107
  "icon": "✓",
@@ -1282,6 +1306,10 @@ exports[`Sidebar > pending vs completed screens > should show separator between
1282
1306
  "color": "#F59E0B",
1283
1307
  "icon": "◐",
1284
1308
  },
1309
+ "static": {
1310
+ "color": "#3B82F6",
1311
+ "icon": "●",
1312
+ },
1285
1313
  "success": {
1286
1314
  "color": "#22C55E",
1287
1315
  "icon": "✓",
@@ -1470,6 +1498,10 @@ exports[`Sidebar > screen list > should render active screen highlighted 1`] = `
1470
1498
  "color": "#F59E0B",
1471
1499
  "icon": "◐",
1472
1500
  },
1501
+ "static": {
1502
+ "color": "#3B82F6",
1503
+ "icon": "●",
1504
+ },
1473
1505
  "success": {
1474
1506
  "color": "#22C55E",
1475
1507
  "icon": "✓",
@@ -1658,6 +1690,10 @@ exports[`Sidebar > screen list > should render screen list 1`] = `
1658
1690
  "color": "#F59E0B",
1659
1691
  "icon": "◐",
1660
1692
  },
1693
+ "static": {
1694
+ "color": "#3B82F6",
1695
+ "icon": "●",
1696
+ },
1661
1697
  "success": {
1662
1698
  "color": "#22C55E",
1663
1699
  "icon": "✓",
@@ -1854,6 +1890,10 @@ exports[`Sidebar > status indicators > should render fail status 1`] = `
1854
1890
  "color": "#F59E0B",
1855
1891
  "icon": "◐",
1856
1892
  },
1893
+ "static": {
1894
+ "color": "#3B82F6",
1895
+ "icon": "●",
1896
+ },
1857
1897
  "success": {
1858
1898
  "color": "#22C55E",
1859
1899
  "icon": "✓",
@@ -2034,6 +2074,194 @@ exports[`Sidebar > status indicators > should render pending status 1`] = `
2034
2074
  "color": "#F59E0B",
2035
2075
  "icon": "◐",
2036
2076
  },
2077
+ "static": {
2078
+ "color": "#3B82F6",
2079
+ "icon": "●",
2080
+ },
2081
+ "success": {
2082
+ "color": "#22C55E",
2083
+ "icon": "✓",
2084
+ },
2085
+ "waiting": {
2086
+ "color": "#6B7280",
2087
+ "icon": "○",
2088
+ },
2089
+ },
2090
+ "table": {
2091
+ "background": "#3B82F615",
2092
+ "border": "#3B82F6",
2093
+ "cellText": "#E5E7EB",
2094
+ "headerText": "#F9FAFB",
2095
+ "separator": "#3B82F650",
2096
+ "title": "#F9FAFB",
2097
+ },
2098
+ }
2099
+ }
2100
+ >
2101
+ <Sidebar
2102
+ activeScreenId="1"
2103
+ focused={true}
2104
+ screens={
2105
+ [
2106
+ {
2107
+ "getBadgeCount": [MockFunction],
2108
+ "getIcon": [MockFunction],
2109
+ "getId": [MockFunction],
2110
+ "getName": [MockFunction],
2111
+ "getStatus": [MockFunction],
2112
+ "isHidden": [MockFunction],
2113
+ },
2114
+ ]
2115
+ }
2116
+ selectedIndex={0}
2117
+ title="Screens"
2118
+ width={30}
2119
+ />
2120
+ </LoggerProvider>
2121
+ `;
2122
+
2123
+ exports[`Sidebar > status indicators > should render static status 1`] = `
2124
+ <LoggerProvider
2125
+ theme={
2126
+ {
2127
+ "colors": {
2128
+ "background": "#111827",
2129
+ "error": "#EF4444",
2130
+ "foreground": "#F9FAFB",
2131
+ "muted": "#6B7280",
2132
+ "primary": "#3B82F6",
2133
+ "secondary": "#8B5CF6",
2134
+ "success": "#22C55E",
2135
+ "warning": "#F59E0B",
2136
+ },
2137
+ "errorHighlight": {
2138
+ "background": "#EF444425",
2139
+ "border": "#EF4444",
2140
+ "gutterBackground": "#EF444440",
2141
+ },
2142
+ "file": {
2143
+ "background": "#3B82F615",
2144
+ "border": "#3B82F6",
2145
+ "headerBackground": "#3B82F625",
2146
+ "headerText": "#F9FAFB",
2147
+ },
2148
+ "filter": {
2149
+ "activeLevel": "#3B82F6",
2150
+ "background": "#1F293780",
2151
+ "border": "#3B82F6",
2152
+ "cursor": "#3B82F6",
2153
+ "inactiveLevel": "#4B5563",
2154
+ "inputBackground": "#1F2937",
2155
+ "inputPlaceholder": "#6B7280",
2156
+ "inputText": "#F9FAFB",
2157
+ "text": "#E5E7EB",
2158
+ "textDim": "#6B7280",
2159
+ },
2160
+ "group": {
2161
+ "background": "#6B728010",
2162
+ "border": "#6B7280",
2163
+ "headerText": "#E5E7EB",
2164
+ "icon": "#9CA3AF",
2165
+ },
2166
+ "header": {
2167
+ "background": undefined,
2168
+ "border": "#374151",
2169
+ "text": "#F9FAFB",
2170
+ },
2171
+ "help": {
2172
+ "background": "#1F2937",
2173
+ "border": "#3B82F6",
2174
+ "category": "#3B82F6",
2175
+ "description": "#E5E7EB",
2176
+ "hint": "#6B7280",
2177
+ "key": "#F59E0B",
2178
+ "title": "#F9FAFB",
2179
+ },
2180
+ "logLevels": {
2181
+ "debug": {
2182
+ "background": "#8B5CF615",
2183
+ "border": "#8B5CF6",
2184
+ },
2185
+ "error": {
2186
+ "background": "#EF444415",
2187
+ "border": "#EF4444",
2188
+ },
2189
+ "fatal": {
2190
+ "background": "#DC262625",
2191
+ "border": "#DC2626",
2192
+ "text": "#FCA5A5",
2193
+ },
2194
+ "log": {
2195
+ "background": "#3B82F615",
2196
+ "border": "#3B82F6",
2197
+ },
2198
+ "verbose": {
2199
+ "background": "#6B728015",
2200
+ "border": "#6B7280",
2201
+ },
2202
+ "warn": {
2203
+ "background": "#F59E0B15",
2204
+ "border": "#F59E0B",
2205
+ },
2206
+ },
2207
+ "name": "dark",
2208
+ "progress": {
2209
+ "background": "#3B82F615",
2210
+ "barEmpty": "#374151",
2211
+ "barFilled": "#3B82F6",
2212
+ "border": "#3B82F6",
2213
+ "complete": "#22C55E",
2214
+ "completeBackground": "#22C55E15",
2215
+ "failed": "#EF4444",
2216
+ "failedBackground": "#EF444415",
2217
+ "text": "#E5E7EB",
2218
+ "textDim": "#9CA3AF",
2219
+ },
2220
+ "prompt": {
2221
+ "border": "#374151",
2222
+ "buttonBackground": "#374151",
2223
+ "buttonSelectedBackground": "#1F2937",
2224
+ "cancelButton": "#EF4444",
2225
+ "confirmButton": "#22C55E",
2226
+ "focusBorder": "#3B82F6",
2227
+ "inputBackground": "#1F2937",
2228
+ "inputBorder": "#3B82F6",
2229
+ "inputCursor": "#3B82F6",
2230
+ "inputPlaceholder": "#6B7280",
2231
+ "inputText": "#F9FAFB",
2232
+ "optionSelected": "#3B82F6",
2233
+ "optionSelectedBackground": "#1E3A5F",
2234
+ "optionText": "#E5E7EB",
2235
+ "optionTextDim": "#9CA3AF",
2236
+ "question": "#F9FAFB",
2237
+ },
2238
+ "separator": {
2239
+ "line": "#374151",
2240
+ "text": "#6B7280",
2241
+ },
2242
+ "sidebar": {
2243
+ "background": undefined,
2244
+ "badge": "#3B82F6",
2245
+ "border": "#374151",
2246
+ "focusBorder": "#3B82F6",
2247
+ "hoverBackground": "#374151",
2248
+ "selectedBackground": "#1F293780",
2249
+ "text": "#E5E7EB",
2250
+ "textDim": "#6B7280",
2251
+ },
2252
+ "statusIndicators": {
2253
+ "fail": {
2254
+ "color": "#EF4444",
2255
+ "icon": "✗",
2256
+ },
2257
+ "pending": {
2258
+ "color": "#F59E0B",
2259
+ "icon": "◐",
2260
+ },
2261
+ "static": {
2262
+ "color": "#3B82F6",
2263
+ "icon": "●",
2264
+ },
2037
2265
  "success": {
2038
2266
  "color": "#22C55E",
2039
2267
  "icon": "✓",
@@ -2214,6 +2442,10 @@ exports[`Sidebar > status indicators > should render success status 1`] = `
2214
2442
  "color": "#F59E0B",
2215
2443
  "icon": "◐",
2216
2444
  },
2445
+ "static": {
2446
+ "color": "#3B82F6",
2447
+ "icon": "●",
2448
+ },
2217
2449
  "success": {
2218
2450
  "color": "#22C55E",
2219
2451
  "icon": "✓",
@@ -2394,6 +2626,10 @@ exports[`Sidebar > status indicators > should render waiting status 1`] = `
2394
2626
  "color": "#F59E0B",
2395
2627
  "icon": "◐",
2396
2628
  },
2629
+ "static": {
2630
+ "color": "#3B82F6",
2631
+ "icon": "●",
2632
+ },
2397
2633
  "success": {
2398
2634
  "color": "#22C55E",
2399
2635
  "icon": "✓",
@@ -2574,6 +2810,10 @@ exports[`Sidebar > title > should render custom title 1`] = `
2574
2810
  "color": "#F59E0B",
2575
2811
  "icon": "◐",
2576
2812
  },
2813
+ "static": {
2814
+ "color": "#3B82F6",
2815
+ "icon": "●",
2816
+ },
2577
2817
  "success": {
2578
2818
  "color": "#22C55E",
2579
2819
  "icon": "✓",
@@ -200,6 +200,23 @@ describe('Sidebar', () => {
200
200
 
201
201
  expect(component).toMatchSnapshot()
202
202
  })
203
+
204
+ it('should render static status', () => {
205
+ const screens = [createMockScreen({ id: '1', name: 'Static', status: 'static' })]
206
+
207
+ const component = wrapWithContext(
208
+ <Sidebar
209
+ screens={screens}
210
+ selectedIndex={0}
211
+ activeScreenId="1"
212
+ focused={true}
213
+ width={30}
214
+ title="Screens"
215
+ />,
216
+ )
217
+
218
+ expect(component).toMatchSnapshot()
219
+ })
203
220
  })
204
221
 
205
222
  describe('badge counts', () => {
@@ -3,11 +3,13 @@ import {
3
3
  Injectable,
4
4
  LoggerOutput,
5
5
  type ClassTypeWithInstance,
6
+ type LoggerOptions,
6
7
  type LoggerService,
7
8
  type LogLevel,
8
9
  } from '@navios/core'
9
10
 
10
11
  import { ScreenLogger } from '../tokens/index.ts'
12
+ import { ALL_LOG_LEVELS } from '../types/index.ts'
11
13
 
12
14
  export function overrideConsoleLogger(
13
15
  hidden: boolean = false,
@@ -22,12 +24,17 @@ export function overrideConsoleLogger(
22
24
  class ConsoleLoggerOverride implements LoggerService {
23
25
  protected readonly logger = inject(ScreenLogger, {
24
26
  screen: {
25
- name: 'default',
27
+ name: 'internal',
26
28
  icon: '💻',
27
29
  hidden,
30
+ static: true,
28
31
  },
29
32
  })
30
33
 
34
+ setup(options: LoggerOptions & { logLevels: LogLevel[] }): void {
35
+ this.logger.setLogLevels(options.logLevels ?? ALL_LOG_LEVELS)
36
+ }
37
+
31
38
  log(message: string): void {
32
39
  this.logger.log(message)
33
40
  }
@@ -9,6 +9,8 @@ export const ScreenOptionsSchema = z.object({
9
9
  badgeCount: z.number().optional(),
10
10
  /** Whether the screen is hidden */
11
11
  hidden: z.boolean().optional().default(false),
12
+ /** Whether the screen is static (ignored in auto-close calculations) */
13
+ static: z.boolean().optional().default(false),
12
14
  })
13
15
 
14
16
  export type ScreenOptions = z.infer<typeof ScreenOptionsSchema>
@@ -43,6 +43,9 @@ export class ScreenInstance {
43
43
  this.icon = options.icon
44
44
  this.badgeCount = options.badgeCount ?? 0
45
45
  this.hidden = options.hidden ?? false
46
+ if (options.static) {
47
+ this.status = 'static'
48
+ }
46
49
  }
47
50
 
48
51
  incrementVersion(): void {
@@ -244,33 +244,34 @@ export class ScreenManager {
244
244
  }
245
245
  }
246
246
 
247
- // Check for auto-close
248
- this.checkAutoClose()
249
-
250
247
  this.notifyChange()
251
248
  }
252
249
 
253
250
  /**
254
- * Check if all screens are successful and start auto-close timer if enabled
251
+ * Check if all screens are successful (or only static) and start auto-close timer if enabled.
252
+ * Static screens are ignored in this calculation.
253
+ * If there are only static screens, the timer will trigger after the delay with no new activity.
255
254
  */
256
255
  private checkAutoClose(): void {
257
256
  const autoClose = this.bindOptions.autoClose
258
257
  if (!autoClose || !this.isBound) return
259
258
 
260
- // Clear any existing timer
259
+ // Clear any existing timer (will be restarted if conditions are met)
261
260
  if (this.autoCloseTimer) {
262
261
  clearTimeout(this.autoCloseTimer)
263
262
  this.autoCloseTimer = null
264
263
  }
265
264
 
266
- // Check if all screens are successful
267
- const screens = this.getScreens()
268
- if (screens.length === 0) return
265
+ // Get non-static screens
266
+ const nonStaticScreens = this.getScreens().filter((s) => s.getStatus() !== 'static')
269
267
 
270
- const allSuccessful = screens.every((s) => s.getStatus() === 'success')
271
- if (!allSuccessful) return
268
+ // If there are non-static screens, check if all are successful
269
+ if (nonStaticScreens.length > 0) {
270
+ const allSuccessful = nonStaticScreens.every((s) => s.getStatus() === 'success')
271
+ if (!allSuccessful) return
272
+ }
272
273
 
273
- // Start auto-close timer
274
+ // Start auto-close timer (either all non-static screens succeeded, or only static screens exist)
274
275
  const delay = typeof autoClose === 'number' ? autoClose : 5000
275
276
  this.autoCloseTimer = setTimeout(() => {
276
277
  this.unbind()
@@ -376,6 +377,9 @@ export class ScreenManager {
376
377
  }
377
378
 
378
379
  private notifyChange(): void {
380
+ // Check auto-close on every change (resets timer if activity occurs)
381
+ this.checkAutoClose()
382
+
379
383
  // Notify listeners - React components will forceUpdate and re-render
380
384
  this.changeListeners.forEach((listener) => listener())
381
385
  }
@@ -69,6 +69,10 @@ export const darkTheme: Theme = {
69
69
  icon: '✗',
70
70
  color: '#EF4444', // Red-500
71
71
  },
72
+ static: {
73
+ icon: '●',
74
+ color: '#3B82F6', // Blue-500
75
+ },
72
76
  },
73
77
 
74
78
  separator: {
@@ -74,6 +74,10 @@ export const highContrastTheme: Theme = {
74
74
  icon: '✗',
75
75
  color: '#EF4444', // Red-500
76
76
  },
77
+ static: {
78
+ icon: '●',
79
+ color: '#00FFFF', // Cyan for high visibility
80
+ },
77
81
  },
78
82
 
79
83
  separator: {
@@ -68,6 +68,10 @@ export const lightTheme: Theme = {
68
68
  icon: '✗',
69
69
  color: '#DC2626', // Red-600
70
70
  },
71
+ static: {
72
+ icon: '●',
73
+ color: '#2563EB', // Blue-600
74
+ },
71
75
  },
72
76
 
73
77
  separator: {