termcast 1.3.30 → 1.3.32

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 (294) hide show
  1. package/dist/apis/cache.d.ts.map +1 -1
  2. package/dist/apis/cache.js +4 -39
  3. package/dist/apis/cache.js.map +1 -1
  4. package/dist/apis/hud.d.ts.map +1 -1
  5. package/dist/apis/hud.js +13 -31
  6. package/dist/apis/hud.js.map +1 -1
  7. package/dist/apis/localstorage.d.ts.map +1 -1
  8. package/dist/apis/localstorage.js +3 -27
  9. package/dist/apis/localstorage.js.map +1 -1
  10. package/dist/apis/toast.d.ts +16 -43
  11. package/dist/apis/toast.d.ts.map +1 -1
  12. package/dist/apis/toast.js +78 -177
  13. package/dist/apis/toast.js.map +1 -1
  14. package/dist/build.d.ts +3 -1
  15. package/dist/build.d.ts.map +1 -1
  16. package/dist/build.js +52 -2
  17. package/dist/build.js.map +1 -1
  18. package/dist/cli.d.ts +1 -0
  19. package/dist/cli.d.ts.map +1 -1
  20. package/dist/cli.js +206 -25
  21. package/dist/cli.js.map +1 -1
  22. package/dist/colors.d.ts.map +1 -1
  23. package/dist/colors.js +1 -0
  24. package/dist/colors.js.map +1 -1
  25. package/dist/compile.d.ts +0 -1
  26. package/dist/compile.d.ts.map +1 -1
  27. package/dist/compile.js +18 -23
  28. package/dist/compile.js.map +1 -1
  29. package/dist/components/actions.d.ts.map +1 -1
  30. package/dist/components/actions.js +30 -15
  31. package/dist/components/actions.js.map +1 -1
  32. package/dist/components/animation-tick.d.ts +12 -0
  33. package/dist/components/animation-tick.d.ts.map +1 -0
  34. package/dist/components/animation-tick.js +63 -0
  35. package/dist/components/animation-tick.js.map +1 -0
  36. package/dist/components/detail.d.ts.map +1 -1
  37. package/dist/components/detail.js +10 -13
  38. package/dist/components/detail.js.map +1 -1
  39. package/dist/components/dropdown.d.ts +1 -0
  40. package/dist/components/dropdown.d.ts.map +1 -1
  41. package/dist/components/dropdown.js +27 -26
  42. package/dist/components/dropdown.js.map +1 -1
  43. package/dist/components/extension-preferences.d.ts.map +1 -1
  44. package/dist/components/extension-preferences.js +15 -10
  45. package/dist/components/extension-preferences.js.map +1 -1
  46. package/dist/components/footer.d.ts +13 -0
  47. package/dist/components/footer.d.ts.map +1 -0
  48. package/dist/components/footer.js +106 -0
  49. package/dist/components/footer.js.map +1 -0
  50. package/dist/components/form/file-autocomplete.d.ts +19 -4
  51. package/dist/components/form/file-autocomplete.d.ts.map +1 -1
  52. package/dist/components/form/file-autocomplete.js +56 -55
  53. package/dist/components/form/file-autocomplete.js.map +1 -1
  54. package/dist/components/form/file-picker.d.ts.map +1 -1
  55. package/dist/components/form/file-picker.js +26 -15
  56. package/dist/components/form/file-picker.js.map +1 -1
  57. package/dist/components/form/index.d.ts.map +1 -1
  58. package/dist/components/form/index.js +17 -15
  59. package/dist/components/form/index.js.map +1 -1
  60. package/dist/components/form/with-left-border.d.ts.map +1 -1
  61. package/dist/components/form/with-left-border.js +4 -12
  62. package/dist/components/form/with-left-border.js.map +1 -1
  63. package/dist/components/list.d.ts.map +1 -1
  64. package/dist/components/list.js +126 -86
  65. package/dist/components/list.js.map +1 -1
  66. package/dist/components/loading-bar.d.ts.map +1 -1
  67. package/dist/components/loading-bar.js +5 -22
  68. package/dist/components/loading-bar.js.map +1 -1
  69. package/dist/components/loading-text.d.ts.map +1 -1
  70. package/dist/components/loading-text.js +3 -22
  71. package/dist/components/loading-text.js.map +1 -1
  72. package/dist/components/theme-picker.d.ts +2 -0
  73. package/dist/components/theme-picker.d.ts.map +1 -0
  74. package/dist/components/theme-picker.js +37 -0
  75. package/dist/components/theme-picker.js.map +1 -0
  76. package/dist/descendants.d.ts +6 -0
  77. package/dist/descendants.d.ts.map +1 -1
  78. package/dist/descendants.js +74 -8
  79. package/dist/descendants.js.map +1 -1
  80. package/dist/examples/internal/descendants-rerender.d.ts +14 -0
  81. package/dist/examples/internal/descendants-rerender.d.ts.map +1 -0
  82. package/dist/examples/internal/descendants-rerender.js +145 -0
  83. package/dist/examples/internal/descendants-rerender.js.map +1 -0
  84. package/dist/examples/internal/simple-dialog.js +4 -1
  85. package/dist/examples/internal/simple-dialog.js.map +1 -1
  86. package/dist/examples/internal/simple-scrollbox.js +1 -1
  87. package/dist/examples/internal/simple-scrollbox.js.map +1 -1
  88. package/dist/examples/list-with-dropdown.js +1 -1
  89. package/dist/examples/list-with-dropdown.js.map +1 -1
  90. package/dist/examples/miscellaneous.js +1 -1
  91. package/dist/examples/miscellaneous.js.map +1 -1
  92. package/dist/examples/toast-action.d.ts +2 -0
  93. package/dist/examples/toast-action.d.ts.map +1 -0
  94. package/dist/examples/toast-action.js +76 -0
  95. package/dist/examples/toast-action.js.map +1 -0
  96. package/dist/examples/toast-variations.js +38 -36
  97. package/dist/examples/toast-variations.js.map +1 -1
  98. package/dist/extensions/dev.d.ts +1 -1
  99. package/dist/extensions/dev.d.ts.map +1 -1
  100. package/dist/extensions/dev.js +62 -30
  101. package/dist/extensions/dev.js.map +1 -1
  102. package/dist/extensions/home.d.ts.map +1 -1
  103. package/dist/extensions/home.js +4 -3
  104. package/dist/extensions/home.js.map +1 -1
  105. package/dist/extensions/react-refresh-init.d.ts +5 -0
  106. package/dist/extensions/react-refresh-init.d.ts.map +1 -0
  107. package/dist/extensions/react-refresh-init.js +52 -0
  108. package/dist/extensions/react-refresh-init.js.map +1 -0
  109. package/dist/internal/date-picker-widget.js +1 -1
  110. package/dist/internal/date-picker-widget.js.map +1 -1
  111. package/dist/internal/dialog.d.ts +8 -3
  112. package/dist/internal/dialog.d.ts.map +1 -1
  113. package/dist/internal/dialog.js +37 -53
  114. package/dist/internal/dialog.js.map +1 -1
  115. package/dist/internal/navigation.d.ts +1 -0
  116. package/dist/internal/navigation.d.ts.map +1 -1
  117. package/dist/internal/navigation.js +25 -1
  118. package/dist/internal/navigation.js.map +1 -1
  119. package/dist/internal/providers.d.ts.map +1 -1
  120. package/dist/internal/providers.js +9 -197
  121. package/dist/internal/providers.js.map +1 -1
  122. package/dist/internal/scrollbox.d.ts.map +1 -1
  123. package/dist/internal/scrollbox.js +1 -0
  124. package/dist/internal/scrollbox.js.map +1 -1
  125. package/dist/release.d.ts +1 -0
  126. package/dist/release.d.ts.map +1 -1
  127. package/dist/release.js +16 -9
  128. package/dist/release.js.map +1 -1
  129. package/dist/state.d.ts +27 -1
  130. package/dist/state.d.ts.map +1 -1
  131. package/dist/state.js +6 -0
  132. package/dist/state.js.map +1 -1
  133. package/dist/theme.d.ts +6 -19
  134. package/dist/theme.d.ts.map +1 -1
  135. package/dist/theme.js +76 -45
  136. package/dist/theme.js.map +1 -1
  137. package/dist/themes/aura.json +69 -0
  138. package/dist/themes/ayu.json +80 -0
  139. package/dist/themes/catppuccin-frappe.json +233 -0
  140. package/dist/themes/catppuccin-macchiato.json +233 -0
  141. package/dist/themes/catppuccin.json +112 -0
  142. package/dist/themes/cobalt2.json +228 -0
  143. package/dist/themes/cursor.json +249 -0
  144. package/dist/themes/dracula.json +219 -0
  145. package/dist/themes/everforest.json +241 -0
  146. package/dist/themes/flexoki.json +237 -0
  147. package/dist/themes/github-light.json +56 -0
  148. package/dist/themes/github.json +241 -0
  149. package/dist/themes/gruvbox.json +95 -0
  150. package/dist/themes/kanagawa.json +77 -0
  151. package/dist/themes/lucent-orng.json +227 -0
  152. package/dist/themes/material.json +235 -0
  153. package/dist/themes/matrix.json +77 -0
  154. package/dist/themes/mercury.json +245 -0
  155. package/dist/themes/monokai.json +221 -0
  156. package/dist/themes/nightowl.json +221 -0
  157. package/dist/themes/nord.json +223 -0
  158. package/dist/themes/one-dark.json +84 -0
  159. package/dist/themes/opencode-light.json +62 -0
  160. package/dist/themes/opencode.json +245 -0
  161. package/dist/themes/orng.json +245 -0
  162. package/dist/themes/palenight.json +222 -0
  163. package/dist/themes/rosepine.json +234 -0
  164. package/dist/themes/solarized.json +223 -0
  165. package/dist/themes/synthwave84.json +226 -0
  166. package/dist/themes/termcast.json +226 -0
  167. package/dist/themes/tokyonight.json +243 -0
  168. package/dist/themes/vercel.json +255 -0
  169. package/dist/themes/vesper.json +218 -0
  170. package/dist/themes/zenburn.json +223 -0
  171. package/dist/themes.d.ts +57 -0
  172. package/dist/themes.d.ts.map +1 -0
  173. package/dist/themes.js +181 -0
  174. package/dist/themes.js.map +1 -0
  175. package/dist/utils/run-command.d.ts +2 -1
  176. package/dist/utils/run-command.d.ts.map +1 -1
  177. package/dist/utils/run-command.js +20 -10
  178. package/dist/utils/run-command.js.map +1 -1
  179. package/dist/utils.d.ts +2 -1
  180. package/dist/utils.d.ts.map +1 -1
  181. package/dist/utils.js +90 -17
  182. package/dist/utils.js.map +1 -1
  183. package/dist/watcher.d.ts +3 -0
  184. package/dist/watcher.d.ts.map +1 -0
  185. package/dist/watcher.js +16 -0
  186. package/dist/watcher.js.map +1 -0
  187. package/package.json +16 -10
  188. package/src/apis/cache.tsx +5 -44
  189. package/src/apis/hud.tsx +17 -62
  190. package/src/apis/localstorage.tsx +3 -32
  191. package/src/apis/toast.tsx +91 -275
  192. package/src/build.test.tsx +10 -0
  193. package/src/build.tsx +61 -1
  194. package/src/cli.tsx +365 -103
  195. package/src/colors.tsx +1 -0
  196. package/src/compile.tsx +21 -29
  197. package/src/compile.vitest.tsx +300 -0
  198. package/src/components/actions.tsx +64 -45
  199. package/src/components/animation-tick.tsx +85 -0
  200. package/src/components/detail.tsx +31 -35
  201. package/src/components/dropdown.tsx +32 -21
  202. package/src/components/extension-preferences.tsx +14 -10
  203. package/src/components/footer.tsx +241 -0
  204. package/src/components/form/file-autocomplete.tsx +80 -60
  205. package/src/components/form/file-picker.tsx +37 -25
  206. package/src/components/form/index.tsx +45 -41
  207. package/src/components/form/with-left-border.tsx +4 -14
  208. package/src/components/list.tsx +181 -121
  209. package/src/components/loading-bar.tsx +5 -25
  210. package/src/components/loading-text.tsx +4 -23
  211. package/src/components/theme-picker.tsx +57 -0
  212. package/src/descendants.tsx +98 -9
  213. package/src/examples/actions-dialog-layout.vitest.tsx +112 -0
  214. package/src/examples/file-autocomplete.vitest.tsx +131 -122
  215. package/src/examples/form-basic.vitest.tsx +463 -644
  216. package/src/examples/form-dropdown.vitest.tsx +553 -571
  217. package/src/examples/form-scroll.vitest.tsx +112 -102
  218. package/src/examples/form-tagpicker.vitest.tsx +364 -338
  219. package/src/examples/internal/descendants-rerender.tsx +273 -0
  220. package/src/examples/internal/descendants-rerender.vitest.tsx +194 -0
  221. package/src/examples/internal/simple-dialog.tsx +4 -4
  222. package/src/examples/internal/simple-scrollbox.tsx +2 -2
  223. package/src/examples/internal/simple-scrollbox.vitest.tsx +43 -31
  224. package/src/examples/list-detail-metadata.vitest.tsx +34 -30
  225. package/src/examples/list-dropdown-default.vitest.tsx +84 -72
  226. package/src/examples/list-empty-view.vitest.tsx +93 -0
  227. package/src/examples/list-fetch-data.vitest.tsx +36 -30
  228. package/src/examples/list-scrollbox.vitest.tsx +59 -39
  229. package/src/examples/list-with-detail.vitest.tsx +339 -314
  230. package/src/examples/list-with-dropdown.tsx +1 -0
  231. package/src/examples/list-with-dropdown.vitest.tsx +176 -150
  232. package/src/examples/list-with-sections.vitest.tsx +289 -270
  233. package/src/examples/list-with-toast.vitest.tsx +44 -44
  234. package/src/examples/miscellaneous.tsx +10 -0
  235. package/src/examples/simple-file-picker.vitest.tsx +90 -86
  236. package/src/examples/simple-grid.vitest.tsx +275 -249
  237. package/src/examples/simple-navigation.vitest.tsx +192 -168
  238. package/src/examples/store.vitest.tsx +6 -4
  239. package/src/examples/swift-extension.vitest.tsx +31 -19
  240. package/src/examples/synonyms.vitest.tsx +93 -83
  241. package/src/examples/toast-action.tsx +160 -0
  242. package/src/examples/toast-action.vitest.tsx +404 -0
  243. package/src/examples/toast-variations.tsx +58 -57
  244. package/src/examples/toast-variations.vitest.tsx +186 -166
  245. package/src/extensions/dev.tsx +74 -33
  246. package/src/extensions/dev.vitest.tsx +162 -69
  247. package/src/extensions/home.tsx +5 -6
  248. package/src/extensions/react-refresh-init.tsx +59 -0
  249. package/src/internal/date-picker-widget.tsx +1 -1
  250. package/src/internal/dialog.tsx +59 -83
  251. package/src/internal/navigation.tsx +37 -4
  252. package/src/internal/providers.tsx +27 -315
  253. package/src/internal/scrollbox.tsx +1 -0
  254. package/src/release.tsx +16 -10
  255. package/src/state.tsx +36 -3
  256. package/src/theme.tsx +82 -51
  257. package/src/themes/aura.json +69 -0
  258. package/src/themes/ayu.json +80 -0
  259. package/src/themes/catppuccin-frappe.json +233 -0
  260. package/src/themes/catppuccin-macchiato.json +233 -0
  261. package/src/themes/catppuccin.json +112 -0
  262. package/src/themes/cobalt2.json +228 -0
  263. package/src/themes/cursor.json +249 -0
  264. package/src/themes/dracula.json +219 -0
  265. package/src/themes/everforest.json +241 -0
  266. package/src/themes/flexoki.json +237 -0
  267. package/src/themes/github-light.json +56 -0
  268. package/src/themes/github.json +241 -0
  269. package/src/themes/gruvbox.json +95 -0
  270. package/src/themes/kanagawa.json +77 -0
  271. package/src/themes/lucent-orng.json +227 -0
  272. package/src/themes/material.json +235 -0
  273. package/src/themes/matrix.json +77 -0
  274. package/src/themes/mercury.json +252 -0
  275. package/src/themes/monokai.json +221 -0
  276. package/src/themes/nightowl.json +221 -0
  277. package/src/themes/nord.json +223 -0
  278. package/src/themes/one-dark.json +84 -0
  279. package/src/themes/opencode-light.json +62 -0
  280. package/src/themes/opencode.json +245 -0
  281. package/src/themes/orng.json +245 -0
  282. package/src/themes/palenight.json +222 -0
  283. package/src/themes/rosepine.json +234 -0
  284. package/src/themes/solarized.json +223 -0
  285. package/src/themes/synthwave84.json +226 -0
  286. package/src/themes/termcast.json +227 -0
  287. package/src/themes/tokyonight.json +243 -0
  288. package/src/themes/vercel.json +255 -0
  289. package/src/themes/vesper.json +218 -0
  290. package/src/themes/zenburn.json +223 -0
  291. package/src/themes.ts +291 -0
  292. package/src/utils/run-command.tsx +23 -12
  293. package/src/utils.tsx +115 -18
  294. package/src/watcher.tsx +19 -0
@@ -1,8 +1,9 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "@opentui/react/jsx-runtime";
2
2
  import { TextAttributes, } from '@opentui/core';
3
- import { useKeyboard } from '@opentui/react';
3
+ import { useKeyboard, flushSync } from '@opentui/react';
4
4
  import React, { createContext, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
5
5
  import { LoadingBar } from 'termcast/src/components/loading-bar';
6
+ import { Footer } from 'termcast/src/components/footer';
6
7
  import { createDescendants } from 'termcast/src/descendants';
7
8
  import { useStore } from 'termcast/src/state';
8
9
  import { useDialog } from 'termcast/src/internal/dialog';
@@ -12,6 +13,7 @@ import { Offscreen } from 'termcast/src/internal/offscreen';
12
13
  import { ScrollBox } from 'termcast/src/internal/scrollbox';
13
14
  import { Color, resolveColor } from 'termcast/src/colors';
14
15
  import { getIconEmoji } from 'termcast/src/components/icon';
16
+ import { ActionPanel } from 'termcast/src/components/actions';
15
17
  import { Theme, markdownSyntaxStyle } from 'termcast/src/theme';
16
18
  export { Color };
17
19
  function formatRelativeDate(date) {
@@ -47,15 +49,10 @@ function formatRelativeDate(date) {
47
49
  function ListFooter() {
48
50
  const firstActionTitle = useStore((s) => s.firstActionTitle);
49
51
  const hasToast = useStore((s) => s.toast !== null);
50
- const content = hasToast ? null : (_jsxs(_Fragment, { children: [firstActionTitle && (_jsxs(_Fragment, { children: [_jsx("text", { fg: Theme.text, attributes: TextAttributes.BOLD, children: "\u21B5" }), _jsxs("text", { fg: Theme.textMuted, children: [" ", firstActionTitle.toLowerCase()] })] })), _jsxs("text", { fg: Theme.text, attributes: TextAttributes.BOLD, children: [' ', "\u2191\u2193"] }), _jsx("text", { fg: Theme.textMuted, children: " navigate" }), _jsxs("text", { fg: Theme.text, attributes: TextAttributes.BOLD, children: [' ', "^k"] }), _jsx("text", { fg: Theme.textMuted, children: " actions" })] }));
51
- return (_jsx("box", { border: false, height: 1, style: {
52
- paddingLeft: 1,
53
- flexShrink: 0,
54
- paddingRight: 1,
55
- paddingTop: 1,
56
- marginTop: 1,
57
- flexDirection: 'row',
58
- }, children: content }));
52
+ const listContext = useContext(ListContext);
53
+ const isShowingDetail = listContext?.isShowingDetail ?? false;
54
+ const content = hasToast ? null : (_jsxs("box", { style: { flexDirection: 'row', gap: 3 }, children: [firstActionTitle && (_jsxs("box", { style: { flexDirection: 'row', gap: 1 }, children: [_jsx("text", { flexShrink: 0, fg: Theme.text, attributes: TextAttributes.BOLD, children: "\u21B5" }), _jsx("text", { flexShrink: 0, fg: Theme.textMuted, children: firstActionTitle.toLowerCase() })] })), _jsxs("box", { style: { flexDirection: 'row', gap: 1 }, children: [_jsx("text", { flexShrink: 0, fg: Theme.text, attributes: TextAttributes.BOLD, children: "\u2191\u2193" }), _jsx("text", { flexShrink: 0, fg: Theme.textMuted, children: "navigate" })] }), _jsxs("box", { style: { flexDirection: 'row', gap: 1 }, children: [_jsx("text", { flexShrink: 0, fg: Theme.text, attributes: TextAttributes.BOLD, children: "^k" }), _jsx("text", { flexShrink: 0, fg: Theme.textMuted, children: "actions" })] })] }));
55
+ return _jsx(Footer, { hidePoweredBy: isShowingDetail, children: content });
59
56
  }
60
57
  const ListContext = createContext(undefined);
61
58
  // Helper function to determine if an item should be visible based on search
@@ -74,7 +71,7 @@ function shouldItemBeVisible(searchQuery, props) {
74
71
  .toLowerCase();
75
72
  return searchableText.includes(needle);
76
73
  }
77
- const { DescendantsProvider: ListDescendantsProvider, useDescendants: useListDescendants, useDescendant: useListItemDescendant, } = createDescendants();
74
+ const { DescendantsProvider: ListDescendantsProvider, useDescendants: useListDescendants, useDescendant: useListItemDescendant, useDescendantsRerender: useListDescendantsRerender, useDescendantsMap: useListDescendantsMap, } = createDescendants();
78
75
  const { DescendantsProvider: DropdownDescendantsProvider, useDescendants: useDropdownDescendants, useDescendant: useDropdownItemDescendant, } = createDescendants();
79
76
  const DropdownContext = createContext(undefined);
80
77
  function ListDropdownDialog(props) {
@@ -84,8 +81,10 @@ function ListDropdownDialog(props) {
84
81
  const descendantsContext = useDropdownDescendants();
85
82
  // Wrapper function that updates search text
86
83
  const setSearchText = (value) => {
87
- setSearchTextRaw(value);
88
- // TODO: use flushSync when available to force descendants to update visibility
84
+ // Using flushSync to force descendants to update visibility before querying
85
+ flushSync(() => {
86
+ setSearchTextRaw(value);
87
+ });
89
88
  const items = Object.values(descendantsContext.map.current)
90
89
  .filter((item) => item.index !== -1 && item.props?.visible !== false)
91
90
  .sort((a, b) => a.index - b.index);
@@ -144,13 +143,13 @@ function ListDropdownDialog(props) {
144
143
  return (_jsx(DropdownDescendantsProvider, { value: descendantsContext, children: _jsxs("box", { children: [_jsxs("box", { style: { paddingLeft: 2, paddingRight: 2 }, children: [_jsxs("box", { style: { paddingLeft: 1, paddingRight: 1 }, children: [_jsxs("box", { style: {
145
144
  flexDirection: 'row',
146
145
  justifyContent: 'space-between',
147
- }, children: [_jsx("text", { attributes: TextAttributes.BOLD, children: props.tooltip }), _jsx("text", { fg: Theme.textMuted, children: "esc" })] }), _jsx("box", { style: { paddingTop: 1, paddingBottom: 1 }, children: _jsx("textarea", { ref: inputRef, height: 1, wrapMode: 'none', keyBindings: [
148
- { name: 'return', action: 'submit' },
149
- { name: 'linefeed', action: 'submit' },
150
- ], onContentChange: () => {
151
- const value = inputRef.current?.plainText || '';
152
- setSearchText(value);
153
- }, placeholder: props.placeholder || 'Search...', focused: inFocus, initialValue: searchText, focusedBackgroundColor: Theme.backgroundPanel, cursorColor: Theme.primary, focusedTextColor: Theme.textMuted }) })] }), _jsx("box", { style: { paddingBottom: 1 }, children: _jsx(DropdownContext.Provider, { value: {
146
+ }, children: [_jsx("text", { flexShrink: 0, fg: Theme.textMuted, children: props.tooltip }), _jsx("text", { flexShrink: 0, fg: Theme.textMuted, children: "esc" })] }), _jsxs("box", { style: { paddingTop: 1, paddingBottom: 1, flexDirection: 'row' }, children: [_jsx("text", { flexShrink: 0, fg: Theme.textMuted, children: "> " }), _jsx("textarea", { ref: inputRef, height: 1, flexGrow: 1, wrapMode: 'none', keyBindings: [
147
+ { name: 'return', action: 'submit' },
148
+ { name: 'linefeed', action: 'submit' },
149
+ ], onContentChange: () => {
150
+ const value = inputRef.current?.plainText || '';
151
+ setSearchText(value);
152
+ }, placeholder: props.placeholder || 'Search...', focused: inFocus, initialValue: searchText, focusedBackgroundColor: Theme.backgroundPanel, cursorColor: Theme.primary, focusedTextColor: Theme.textMuted })] })] }), _jsx("box", { style: { paddingBottom: 1 }, children: _jsx(DropdownContext.Provider, { value: {
154
153
  currentSection: undefined,
155
154
  selectedIndex,
156
155
  setSelectedIndex,
@@ -160,18 +159,12 @@ function ListDropdownDialog(props) {
160
159
  onChange: (value) => {
161
160
  props.onChange?.(value);
162
161
  },
163
- }, children: props.children }) }), props.isLoading && (_jsx("box", { style: { paddingLeft: 1 }, children: _jsx("text", { fg: Theme.textMuted, children: "Loading..." }) }))] }), _jsx(DropdownFooter, {})] }) }));
162
+ }, children: props.children }) }), props.isLoading && (_jsx("box", { style: { paddingLeft: 1 }, children: _jsx("text", { flexShrink: 0, fg: Theme.textMuted, children: "Loading..." }) }))] }), _jsx(DropdownFooter, {})] }) }));
164
163
  }
165
164
  function DropdownFooter() {
166
165
  const hasToast = useStore((s) => s.toast !== null);
167
- const content = hasToast ? null : (_jsxs(_Fragment, { children: [_jsx("text", { fg: Theme.text, attributes: TextAttributes.BOLD, children: "\u21B5" }), _jsx("text", { fg: Theme.textMuted, children: " select" }), _jsxs("text", { fg: Theme.text, attributes: TextAttributes.BOLD, children: [' ', "\u2191\u2193"] }), _jsx("text", { fg: Theme.textMuted, children: " navigate" })] }));
168
- return (_jsx("box", { border: false, height: 1, style: {
169
- paddingRight: 2,
170
- paddingLeft: 3,
171
- paddingBottom: 1,
172
- paddingTop: 1,
173
- flexDirection: 'row',
174
- }, children: content }));
166
+ const content = hasToast ? null : (_jsxs("box", { style: { flexDirection: 'row', gap: 3 }, children: [_jsxs("box", { style: { flexDirection: 'row', gap: 1 }, children: [_jsx("text", { flexShrink: 0, fg: Theme.text, attributes: TextAttributes.BOLD, children: "\u21B5" }), _jsx("text", { flexShrink: 0, fg: Theme.textMuted, children: "select" })] }), _jsxs("box", { style: { flexDirection: 'row', gap: 1 }, children: [_jsx("text", { flexShrink: 0, fg: Theme.text, attributes: TextAttributes.BOLD, children: "\u2191\u2193" }), _jsx("text", { flexShrink: 0, fg: Theme.textMuted, children: "navigate" })] })] }));
167
+ return (_jsx(Footer, { paddingLeft: 3, paddingRight: 2, paddingBottom: 1, marginTop: 0, children: content }));
175
168
  }
176
169
  // Render a single list item row
177
170
  function ListItemRow(props) {
@@ -186,7 +179,7 @@ function ListItemRow(props) {
186
179
  : accessory.text?.value;
187
180
  const textColor = typeof accessory.text === 'object' ? accessory.text?.color : undefined;
188
181
  if (textValue) {
189
- accessoryElements.push(_jsx("text", { fg: active ? Theme.background : resolveColor(textColor) || Theme.info, wrapMode: "none", children: textValue }, `text-${textValue}`));
182
+ accessoryElements.push(_jsx("text", { flexShrink: 0, fg: active ? Theme.background : resolveColor(textColor) || Theme.info, wrapMode: "none", children: textValue }, `text-${textValue}`));
190
183
  }
191
184
  }
192
185
  if ('tag' in accessory && accessory.tag) {
@@ -195,7 +188,7 @@ function ListItemRow(props) {
195
188
  : accessory.tag?.value;
196
189
  const tagColor = typeof accessory.tag === 'object' ? accessory.tag?.color : undefined;
197
190
  if (tagValue) {
198
- accessoryElements.push(_jsxs("text", { fg: active ? Theme.background : resolveColor(tagColor) || Theme.warning, wrapMode: "none", children: ["[", tagValue, "]"] }, `tag-${tagValue}`));
191
+ accessoryElements.push(_jsxs("text", { flexShrink: 0, fg: active ? Theme.background : resolveColor(tagColor) || Theme.warning, wrapMode: "none", children: ["[", tagValue, "]"] }, `tag-${tagValue}`));
199
192
  }
200
193
  }
201
194
  if ('date' in accessory && accessory.date) {
@@ -207,7 +200,7 @@ function ListItemRow(props) {
207
200
  : undefined;
208
201
  if (dateValue) {
209
202
  const formatted = formatRelativeDate(dateValue);
210
- accessoryElements.push(_jsx("text", { fg: active ? Theme.background : resolveColor(dateColor) || Theme.success, wrapMode: "none", children: formatted }, `date-${dateValue.getTime()}`));
203
+ accessoryElements.push(_jsx("text", { flexShrink: 0, fg: active ? Theme.background : resolveColor(dateColor) || Theme.success, wrapMode: "none", children: formatted }, `date-${dateValue.getTime()}`));
211
204
  }
212
205
  }
213
206
  });
@@ -227,7 +220,7 @@ function ListItemRow(props) {
227
220
  setIsHovered(true);
228
221
  }, onMouseOut: () => {
229
222
  setIsHovered(false);
230
- }, onMouseDown: props.onMouseDown, children: [_jsxs("box", { style: { flexDirection: 'row', flexGrow: 1, flexShrink: 1, overflow: 'hidden', gap: 1 }, children: [_jsxs("box", { style: { flexDirection: 'row', flexShrink: 0 }, children: [_jsx("text", { fg: active ? Theme.background : Theme.text, attributes: active ? TextAttributes.BOLD : undefined, selectable: false, wrapMode: "none", children: active ? '›' : ' ' }), icon && _jsxs("text", { fg: active ? Theme.background : iconColor || Theme.text, selectable: false, wrapMode: "none", children: [getIconEmoji(icon), " "] }), _jsx("text", { fg: active ? Theme.background : Theme.text, attributes: active ? TextAttributes.BOLD : undefined, selectable: false, wrapMode: "none", children: title })] }), subtitle && (_jsx("text", { fg: active ? Theme.background : Theme.textMuted, selectable: false, wrapMode: "none", children: subtitle }))] }), accessoryElements.length > 0 && (_jsx("box", { style: { flexDirection: 'row', flexShrink: 0 }, children: accessoryElements.map((elem, i) => (_jsxs("box", { style: { flexDirection: 'row' }, children: [i > 0 && _jsx("text", { children: " " }), elem] }, i))) }))] }));
223
+ }, onMouseDown: props.onMouseDown, children: [_jsxs("box", { style: { flexDirection: 'row', flexGrow: 1, flexShrink: 1, overflow: 'hidden', gap: 1 }, children: [_jsxs("box", { style: { flexDirection: 'row', flexShrink: 0 }, children: [_jsx("text", { flexShrink: 0, fg: active ? Theme.background : Theme.text, attributes: active ? TextAttributes.BOLD : undefined, selectable: false, wrapMode: "none", children: active ? '›' : ' ' }), icon && _jsxs("text", { flexShrink: 0, fg: active ? Theme.background : iconColor || Theme.text, selectable: false, wrapMode: "none", children: [getIconEmoji(icon), " "] }), _jsx("text", { flexShrink: 0, fg: active ? Theme.background : Theme.text, attributes: active ? TextAttributes.BOLD : undefined, selectable: false, wrapMode: "none", children: title })] }), subtitle && (_jsx("text", { flexShrink: 0, fg: active ? Theme.background : Theme.textMuted, selectable: false, wrapMode: "none", children: subtitle }))] }), accessoryElements.length > 0 && (_jsx("box", { style: { flexDirection: 'row', flexShrink: 0 }, children: accessoryElements.map((elem, i) => (_jsxs("box", { style: { flexDirection: 'row' }, children: [i > 0 && _jsx("text", { flexShrink: 0, children: " " }), elem] }, i))) }))] }));
231
224
  }
232
225
  export const List = (props) => {
233
226
  const { children, onSelectionChange, filtering, searchText: controlledSearchText, onSearchTextChange, searchBarPlaceholder = 'Search...', isLoading, navigationTitle, isShowingDetail, selectedItemId, searchBarAccessory, ...otherProps } = props;
@@ -284,9 +277,10 @@ export const List = (props) => {
284
277
  };
285
278
  // Wrapper function that updates search text
286
279
  const setInternalSearchText = (value) => {
287
- setInternalSearchTextRaw(value);
288
- // TODO: use flushSync when available to force descendants to update visibility
289
- // before querying. For now, we compute visibility inline with the new search value.
280
+ // Using flushSync to force descendants to update visibility before querying
281
+ flushSync(() => {
282
+ setInternalSearchTextRaw(value);
283
+ });
290
284
  const items = Object.values(descendantsContext.map.current)
291
285
  .filter((item) => item.index !== -1 && item.props?.visible !== false)
292
286
  .sort((a, b) => a.index - b.index);
@@ -402,11 +396,15 @@ export const List = (props) => {
402
396
  if (evt.name === 'k' && evt.ctrl) {
403
397
  // Show current item's actions if available
404
398
  if (currentItem?.props?.actions) {
405
- dialog.push(currentItem.props.actions, 'bottom-right');
399
+ dialog.pushActions(currentItem.props.actions);
406
400
  }
407
401
  // Otherwise show List's own actions
408
402
  else if (props.actions) {
409
- dialog.push(props.actions, 'bottom-right');
403
+ dialog.pushActions(props.actions);
404
+ }
405
+ // Otherwise show empty ActionPanel (still has Settings section with Configure Extension, etc.)
406
+ else {
407
+ dialog.pushActions(_jsx(ActionPanel, {}));
410
408
  }
411
409
  return;
412
410
  }
@@ -420,7 +418,7 @@ export const List = (props) => {
420
418
  return;
421
419
  if (currentItem.props.actions) {
422
420
  useStore.setState({ shouldAutoExecuteFirstAction: true });
423
- dialog.push(currentItem.props.actions, 'bottom-right');
421
+ dialog.pushActions(currentItem.props.actions);
424
422
  }
425
423
  }
426
424
  });
@@ -449,17 +447,17 @@ export const List = (props) => {
449
447
  flexDirection: 'row',
450
448
  justifyContent: 'space-between',
451
449
  alignItems: 'center',
452
- }, children: [_jsx("box", { style: {
450
+ }, children: [_jsxs("box", { style: {
453
451
  flexGrow: 1,
454
- flexDirection: 'column',
452
+ flexDirection: 'row',
455
453
  flexShrink: 1,
456
- }, children: _jsx("textarea", { ref: inputRef, height: 1, wrapMode: 'none', keyBindings: [
457
- { name: 'return', action: 'submit' },
458
- { name: 'linefeed', action: 'submit' },
459
- ], placeholder: searchBarPlaceholder, focused: inFocus && !isDropdownOpen, initialValue: searchText, onContentChange: () => {
460
- const value = inputRef.current?.plainText || '';
461
- handleSearchChange(value);
462
- }, focusedBackgroundColor: Theme.backgroundPanel, cursorColor: Theme.primary, focusedTextColor: Theme.text }) }), searchBarAccessory] }) }), _jsxs("box", { style: { flexDirection: 'row', flexGrow: 1, flexShrink: 1 }, children: [_jsxs("box", { style: { width: isShowingDetail ? '50%' : '100%', flexGrow: isShowingDetail ? 0 : 1, flexShrink: 1, flexDirection: 'column' }, children: [_jsx(ScrollBox, { ref: scrollBoxRef, focused: false, flexGrow: 1, flexShrink: 1, style: {
454
+ }, children: [_jsx("text", { flexShrink: 0, fg: Theme.textMuted, children: "> " }), _jsx("textarea", { ref: inputRef, height: 1, flexGrow: 1, wrapMode: 'none', keyBindings: [
455
+ { name: 'return', action: 'submit' },
456
+ { name: 'linefeed', action: 'submit' },
457
+ ], placeholder: searchBarPlaceholder, focused: inFocus && !isDropdownOpen, initialValue: searchText, onContentChange: () => {
458
+ const value = inputRef.current?.plainText || '';
459
+ handleSearchChange(value);
460
+ }, focusedBackgroundColor: Theme.backgroundPanel, cursorColor: Theme.primary, focusedTextColor: Theme.text })] }), searchBarAccessory] }) }), _jsxs("box", { style: { flexDirection: 'row', flexGrow: 1, flexShrink: 1 }, children: [_jsxs("box", { style: { width: isShowingDetail ? '50%' : '100%', flexGrow: 1, flexShrink: 1, flexDirection: 'column' }, children: [_jsx(ScrollBox, { ref: scrollBoxRef, focused: false, flexGrow: 1, flexShrink: 1, style: {
463
461
  rootOptions: {
464
462
  backgroundColor: undefined,
465
463
  },
@@ -473,13 +471,42 @@ export const List = (props) => {
473
471
  paddingRight: 1,
474
472
  }, border: ['left'], borderStyle: 'single', borderColor: Theme.border, children: currentDetail }))] })] }) }) }));
475
473
  };
474
+ function DefaultEmptyView() {
475
+ // Subscribe to re-render when items are added/removed
476
+ void useListDescendantsRerender();
477
+ // Get live map ref for reading in useLayoutEffect
478
+ const map = useListDescendantsMap();
479
+ const [hasVisibleItems, setHasVisibleItems] = useState(true);
480
+ // We must check visibility in useLayoutEffect because:
481
+ // 1. map.current is cleared by reset() during render, so it's empty if read during render
482
+ // 2. committedMap is stale - it's a snapshot from the previous render cycle and doesn't
483
+ // reflect prop changes like 'visible' (only tracks which items exist, not their props)
484
+ // 3. Items register in their own useLayoutEffect, so map.current is only populated after
485
+ // all items' layout effects have run
486
+ useLayoutEffect(() => {
487
+ const items = Object.values(map.current)
488
+ .filter((item) => item.index !== -1 && item.props?.visible !== false);
489
+ setHasVisibleItems(items.length > 0);
490
+ });
491
+ if (hasVisibleItems)
492
+ return null;
493
+ return (_jsx("box", { style: {
494
+ flexDirection: 'column',
495
+ alignItems: 'center',
496
+ justifyContent: 'center',
497
+ paddingTop: 2,
498
+ paddingBottom: 2,
499
+ paddingLeft: 2,
500
+ paddingRight: 2,
501
+ }, children: _jsx("text", { flexShrink: 0, fg: Theme.textMuted, children: "No items found" }) }));
502
+ }
476
503
  // Component to render list items and sections
477
504
  function ListItemsRenderer(props) {
478
505
  const { children } = props;
479
506
  const listContext = useContext(ListContext);
480
507
  const searchText = listContext?.searchText || '';
481
508
  // Pass search text down via context
482
- return (_jsx(ListSectionContext.Provider, { value: { searchText }, children: children }));
509
+ return (_jsxs(ListSectionContext.Provider, { value: { searchText }, children: [children, _jsx(DefaultEmptyView, {})] }));
483
510
  }
484
511
  const ListSectionContext = createContext({});
485
512
  const ListItem = (props) => {
@@ -531,8 +558,8 @@ const ListItem = (props) => {
531
558
  const handleMouseDown = () => {
532
559
  if (listContext && index !== -1) {
533
560
  // If clicking on already selected item, show actions (like pressing Enter)
534
- if (isActive && props.actions) {
535
- dialog.push(props.actions, 'bottom-right');
561
+ if (isActive) {
562
+ dialog.pushActions(props.actions || _jsx(ActionPanel, {}));
536
563
  }
537
564
  else if (listContext.setSelectedIndex) {
538
565
  // Otherwise just select the item
@@ -570,7 +597,9 @@ const ListItem = (props) => {
570
597
  };
571
598
  const ListItemDetail = (props) => {
572
599
  const { isLoading, markdown, metadata } = props;
573
- return (_jsxs("box", { style: { flexDirection: 'column', flexGrow: 1 }, children: [isLoading && (_jsx("box", { style: { paddingBottom: 1 }, children: _jsx("text", { fg: Theme.textMuted, children: "Loading..." }) })), _jsx(ScrollBox, { focused: false, flexGrow: 1, flexShrink: 1, style: {
600
+ return (_jsxs("box", { style: { flexDirection: 'column', flexGrow: 1 }, children: [isLoading && (_jsx("box", { style: { paddingBottom: 1 }, children: _jsx("text", { flexShrink: 0, fg: Theme.textMuted, children: "Loading..." }) })), _jsx(ScrollBox, { focused: false,
601
+ // flexGrow={1}
602
+ flexShrink: 1, style: {
574
603
  rootOptions: {
575
604
  backgroundColor: undefined,
576
605
  },
@@ -583,19 +612,19 @@ const ListItemDetailMetadata = (props) => {
583
612
  return (_jsx("box", { style: { flexDirection: 'column' }, children: props.children }));
584
613
  };
585
614
  const ListItemDetailMetadataLabel = (props) => {
586
- return (_jsxs("box", { style: { flexDirection: 'column', paddingBottom: 0.5 }, children: [_jsxs("text", { fg: Theme.textMuted, children: [props.title, ":"] }), props.text && _jsx("text", { fg: Theme.text, children: props.text })] }));
615
+ return (_jsxs("box", { style: { flexDirection: 'column', paddingBottom: 0.5 }, children: [_jsxs("text", { flexShrink: 0, fg: Theme.textMuted, children: [props.title, ":"] }), props.text && _jsx("text", { flexShrink: 0, fg: Theme.text, children: props.text })] }));
587
616
  };
588
617
  const ListItemDetailMetadataSeparator = () => {
589
- return (_jsx("box", { style: { paddingBottom: 0.5 }, children: _jsx("text", { fg: Theme.border, children: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }) }));
618
+ return (_jsx("box", { style: { paddingBottom: 0.5 }, children: _jsx("text", { flexShrink: 0, fg: Theme.border, children: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }) }));
590
619
  };
591
620
  const ListItemDetailMetadataLink = (props) => {
592
- return (_jsxs("box", { style: { flexDirection: 'column', paddingBottom: 0.5 }, children: [_jsxs("text", { fg: Theme.textMuted, children: [props.title, ":"] }), _jsx("text", { fg: Theme.link, children: props.text })] }));
621
+ return (_jsxs("box", { style: { flexDirection: 'column', paddingBottom: 0.5 }, children: [_jsxs("text", { flexShrink: 0, fg: Theme.textMuted, children: [props.title, ":"] }), _jsx("text", { flexShrink: 0, fg: Theme.markdownLink, children: props.text })] }));
593
622
  };
594
623
  const ListItemDetailMetadataTagList = (props) => {
595
- return (_jsxs("box", { style: { flexDirection: 'column', paddingBottom: 0.5 }, children: [_jsxs("text", { fg: Theme.textMuted, children: [props.title, ":"] }), _jsx("box", { style: { flexDirection: 'row', paddingLeft: 1 }, children: props.children })] }));
624
+ return (_jsxs("box", { style: { flexDirection: 'column', paddingBottom: 0.5 }, children: [_jsxs("text", { flexShrink: 0, fg: Theme.textMuted, children: [props.title, ":"] }), _jsx("box", { style: { flexDirection: 'row', paddingLeft: 1 }, children: props.children })] }));
596
625
  };
597
626
  const ListItemDetailMetadataTagListItem = (props) => {
598
- return (_jsx("box", { style: { paddingRight: 1 }, children: _jsxs("text", { fg: resolveColor(props.color) || Theme.accent, children: ["[", props.text, "]"] }) }));
627
+ return (_jsx("box", { style: { paddingRight: 1 }, children: _jsxs("text", { flexShrink: 0, fg: resolveColor(props.color) || Theme.accent, children: ["[", props.text, "]"] }) }));
599
628
  };
600
629
  ListItemDetail.Metadata = ListItemDetailMetadata;
601
630
  ListItemDetailMetadata.Label = ListItemDetailMetadataLabel;
@@ -604,6 +633,14 @@ ListItemDetailMetadata.Link = ListItemDetailMetadataLink;
604
633
  ListItemDetailMetadata.TagList = ListItemDetailMetadataTagList;
605
634
  ListItemDetailMetadataTagList.Item = ListItemDetailMetadataTagListItem;
606
635
  ListItem.Detail = ListItemDetail;
636
+ /**
637
+ * A dropdown menu shown in the right-hand-side of the search bar.
638
+ * Open it with Ctrl+P or by clicking on it.
639
+ *
640
+ * Note: There is no built-in "All" or reset option. If you want users to be
641
+ * able to reset the filter, add a `List.Dropdown.Item` with title="All" and
642
+ * value="" (or your preferred reset value) at the top of your dropdown items.
643
+ */
607
644
  const ListDropdown = (props) => {
608
645
  const listContext = useContext(ListContext);
609
646
  const [isHovered, setIsHovered] = useState(false);
@@ -657,27 +694,30 @@ const ListDropdown = (props) => {
657
694
  useEffect(() => {
658
695
  if (isDropdownOpen && !dialog.stack.length) {
659
696
  // Pass the children to the dialog to render them there
660
- dialog.push(_jsx(ListDropdownDialog, { ...props, value: dropdownState.value, onChange: (newValue) => {
661
- // Find the title for this value
662
- let title = newValue;
663
- for (const item of Object.values(descendantsContext.map.current)) {
664
- const itemProps = item.props;
665
- if (itemProps.value === newValue) {
666
- title = itemProps.title;
667
- break;
697
+ dialog.push({
698
+ element: (_jsx(ListDropdownDialog, { ...props, value: dropdownState.value, onChange: (newValue) => {
699
+ // Find the title for this value
700
+ let title = newValue;
701
+ for (const item of Object.values(descendantsContext.map.current)) {
702
+ const itemProps = item.props;
703
+ if (itemProps.value === newValue) {
704
+ title = itemProps.title;
705
+ break;
706
+ }
668
707
  }
669
- }
670
- setDropdownState({ value: newValue, title });
671
- setIsDropdownOpen(false);
672
- dialog.clear();
673
- if (props.onChange) {
674
- props.onChange(newValue);
675
- }
676
- // TODO: Handle storeValue to persist the value
677
- }, onCancel: () => {
678
- setIsDropdownOpen(false);
679
- dialog.clear();
680
- }, children: props.children }), 'top-right');
708
+ setDropdownState({ value: newValue, title });
709
+ setIsDropdownOpen(false);
710
+ dialog.clear();
711
+ if (props.onChange) {
712
+ props.onChange(newValue);
713
+ }
714
+ // TODO: Handle storeValue to persist the value
715
+ }, onCancel: () => {
716
+ setIsDropdownOpen(false);
717
+ dialog.clear();
718
+ }, children: props.children })),
719
+ position: 'center',
720
+ });
681
721
  }
682
722
  }, [isDropdownOpen, props.children]);
683
723
  // Display the title from our state
@@ -694,7 +734,7 @@ const ListDropdown = (props) => {
694
734
  if (!isDropdownOpen) {
695
735
  listContext.openDropdown();
696
736
  }
697
- }, children: [_jsx("text", { fg: isHovered ? Theme.text : Theme.textMuted, selectable: false, children: displayValue }), _jsxs("text", { fg: isHovered ? Theme.text : Theme.textMuted, selectable: false, children: [' ', "\u25BE"] })] }, dropdownState.value)] }) }));
737
+ }, children: [_jsx("text", { flexShrink: 0, fg: isHovered ? Theme.text : Theme.textMuted, selectable: false, children: displayValue }), _jsxs("text", { flexShrink: 0, fg: isHovered ? Theme.text : Theme.textMuted, selectable: false, children: [' ', "\u25BE"] })] }, dropdownState.value)] }) }));
698
738
  };
699
739
  ListDropdown.Item = (props) => {
700
740
  const dropdownContext = useContext(DropdownContext);
@@ -748,7 +788,7 @@ ListDropdown.Item = (props) => {
748
788
  paddingLeft: isActive ? 0 : 1,
749
789
  paddingRight: 1,
750
790
  justifyContent: 'space-between',
751
- }, border: false, onMouseMove: handleMouseMove, onMouseOut: () => setIsHovered(false), onMouseDown: handleMouseDown, children: _jsxs("box", { style: { flexDirection: 'row' }, children: [isActive && (_jsxs("text", { fg: Theme.background, selectable: false, children: ["\u203A", ''] })), _jsx("text", { fg: isActive
791
+ }, border: false, onMouseMove: handleMouseMove, onMouseOut: () => setIsHovered(false), onMouseDown: handleMouseDown, children: _jsxs("box", { style: { flexDirection: 'row' }, children: [isActive && (_jsxs("text", { flexShrink: 0, fg: Theme.background, selectable: false, children: ["\u203A", ''] })), _jsx("text", { flexShrink: 0, fg: isActive
752
792
  ? Theme.background
753
793
  : isCurrent
754
794
  ? Theme.primary
@@ -771,7 +811,7 @@ ListDropdown.Section = (props) => {
771
811
  const showTitle = parentContext.selectedIndex !== undefined &&
772
812
  props.title &&
773
813
  !parentContext.searchText?.trim();
774
- return (_jsxs(_Fragment, { children: [showTitle && (_jsx("box", { style: { paddingTop: 1, paddingLeft: 1 }, children: _jsx("text", { fg: Theme.accent, attributes: TextAttributes.BOLD, children: props.title }) })), _jsx(DropdownContext.Provider, { value: sectionContextValue, children: props.children })] }));
814
+ return (_jsxs(_Fragment, { children: [showTitle && (_jsx("box", { style: { paddingTop: 1, paddingLeft: 1 }, children: _jsx("text", { flexShrink: 0, fg: Theme.accent, attributes: TextAttributes.BOLD, children: props.title }) })), _jsx(DropdownContext.Provider, { value: sectionContextValue, children: props.children })] }));
775
815
  };
776
816
  List.Item = ListItem;
777
817
  const ListSection = (props) => {
@@ -795,7 +835,7 @@ const ListSection = (props) => {
795
835
  }
796
836
  return (_jsxs("box", { style: { marginBottom: 1 }, children: [props.title && (_jsx("box", { border: false, style: {
797
837
  paddingLeft: 1,
798
- }, children: _jsx("text", { fg: Theme.accent, attributes: TextAttributes.BOLD, children: props.title }) })), children] }));
838
+ }, children: _jsx("text", { flexShrink: 0, fg: Theme.accent, attributes: TextAttributes.BOLD, children: props.title }) })), children] }));
799
839
  };
800
840
  List.Section = ListSection;
801
841
  List.Dropdown = ListDropdown;
@@ -806,15 +846,15 @@ List.EmptyView = (props) => {
806
846
  useKeyboard((evt) => {
807
847
  if (!inFocus)
808
848
  return;
809
- // Handle Ctrl+K to show actions
810
- if (evt.name === 'k' && evt.ctrl && props.actions) {
811
- dialog.push(props.actions, 'bottom-right');
849
+ // Handle Ctrl+K to show actions (always show panel, even without actions)
850
+ if (evt.name === 'k' && evt.ctrl) {
851
+ dialog.pushActions(props.actions || _jsx(ActionPanel, {}));
812
852
  return;
813
853
  }
814
854
  // Handle Enter to execute first action
815
855
  if (evt.name === 'return' && props.actions) {
816
856
  useStore.setState({ shouldAutoExecuteFirstAction: true });
817
- dialog.push(props.actions, 'bottom-right');
857
+ dialog.pushActions(props.actions);
818
858
  }
819
859
  });
820
860
  // Get icon string from ImageLike
@@ -842,7 +882,7 @@ List.EmptyView = (props) => {
842
882
  paddingLeft: 2,
843
883
  paddingRight: 2,
844
884
  gap: 1,
845
- }, children: [iconEmoji && (_jsx("text", { fg: Theme.textMuted, style: { marginBottom: 1 }, children: iconEmoji })), props.title && (_jsx("text", { fg: Theme.text, attributes: TextAttributes.BOLD, children: props.title?.replace(/\bRaycast\b/g, 'Termcast').replace(/\braycast\b/g, 'termcast') || '' })), props.description && (_jsx("text", { fg: Theme.textMuted, wrapMode: 'word', children: props.description?.replace(/\bRaycast\b/g, 'Termcast').replace(/\braycast\b/g, 'termcast') || '' }))] }));
885
+ }, children: [iconEmoji && (_jsx("text", { flexShrink: 0, fg: Theme.textMuted, style: { marginBottom: 1 }, children: iconEmoji })), props.title && (_jsx("text", { flexShrink: 0, fg: Theme.text, attributes: TextAttributes.BOLD, children: props.title?.replace(/\bRaycast\b/g, 'Termcast').replace(/\braycast\b/g, 'termcast') || '' })), props.description && (_jsx("text", { flexShrink: 0, fg: Theme.textMuted, wrapMode: 'word', children: props.description?.replace(/\bRaycast\b/g, 'Termcast').replace(/\braycast\b/g, 'termcast') || '' }))] }));
846
886
  };
847
887
  export default List;
848
888
  // Grid uses List internally with a different visual representation