gloomberb 0.9.4 → 0.9.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.
Files changed (56) hide show
  1. package/package.json +3 -2
  2. package/patches/@opentui%2Fcore@0.3.2.patch +231 -29
  3. package/patches/react-reconciler@0.33.0.patch +10 -0
  4. package/src/cli/entry.ts +8 -1
  5. package/src/cli/native-smoke.ts +5 -0
  6. package/src/components/chart/native/bitmap-support.test.ts +27 -0
  7. package/src/components/chart/native/bitmap-support.ts +55 -0
  8. package/src/components/chart/native/kitty/index.test.ts +47 -0
  9. package/src/components/chart/native/surface/visibility.ts +8 -1
  10. package/src/components/chart/static/chart/bitmap.ts +16 -9
  11. package/src/components/command-bar/list/view.tsx +1 -1
  12. package/src/components/command-bar/theme-picker.tsx +1 -1
  13. package/src/components/data-table/view.tsx +0 -12
  14. package/src/components/layout/floating-pane.tsx +3 -3
  15. package/src/components/layout/pane/header.tsx +5 -0
  16. package/src/components/layout/pane/index.tsx +3 -3
  17. package/src/components/layout/shell/action-menu-overlay.tsx +1 -1
  18. package/src/components/layout/shell/cursor-occlusion.ts +9 -1
  19. package/src/components/layout/shell/index.tsx +8 -1
  20. package/src/components/layout/shell/pane/layers.tsx +2 -2
  21. package/src/components/layout/status-bar.tsx +5 -5
  22. package/src/components/pane-settings-dialog/desktop.tsx +1 -1
  23. package/src/components/price-performance.tsx +1 -1
  24. package/src/components/price-sparkline/view.tsx +15 -14
  25. package/src/components/speedometer-gauge/terminal.tsx +18 -15
  26. package/src/components/table-view-shared.tsx +0 -10
  27. package/src/components/ticker/list-table-view.tsx +1 -7
  28. package/src/components/ticker/list-table.test.tsx +0 -4
  29. package/src/components/ui/data-table/opentui/index.tsx +4 -10
  30. package/src/components/ui/data-table/types.ts +6 -4
  31. package/src/components/ui/list-view.tsx +1 -1
  32. package/src/components/ui/tabs.tsx +1 -2
  33. package/src/components/ui/ui.test.tsx +0 -9
  34. package/src/plugins/builtin/account-management/form-components.tsx +2 -2
  35. package/src/plugins/builtin/alerts/pane.tsx +1 -1
  36. package/src/plugins/builtin/buildout/cells.tsx +1 -1
  37. package/src/plugins/builtin/buildout/pane/index.tsx +1 -1
  38. package/src/plugins/builtin/chat/message/desktop.tsx +1 -1
  39. package/src/plugins/builtin/chat/message/inline-tokens.tsx +1 -1
  40. package/src/plugins/builtin/chat/message/terminal.tsx +2 -2
  41. package/src/plugins/builtin/chat/sidebar.tsx +1 -1
  42. package/src/plugins/builtin/chat/status-widget.tsx +1 -1
  43. package/src/plugins/builtin/cloud/auth-actions.tsx +2 -2
  44. package/src/plugins/builtin/correlation/matrix/symbol-cell.tsx +1 -1
  45. package/src/plugins/builtin/debug/index.tsx +3 -4
  46. package/src/plugins/builtin/help/components.tsx +1 -1
  47. package/src/plugins/builtin/holders/treemap.tsx +1 -1
  48. package/src/plugins/builtin/options/table.ts +5 -5
  49. package/src/plugins/ibkr/trade/ticket-panel.tsx +1 -1
  50. package/src/renderers/electrobun/view/data-table/index.tsx +0 -8
  51. package/src/renderers/electrobun/view/data-table/row.tsx +2 -12
  52. package/src/renderers/electrobun/view/host/box.tsx +6 -1
  53. package/src/renderers/electrobun/view/host/style.ts +1 -0
  54. package/src/renderers/electrobun/view/styles.css +7 -0
  55. package/src/renderers/opentui/native-smoke.ts +1 -0
  56. package/src/version.ts +1 -1
@@ -85,7 +85,7 @@ export function PickerRow({
85
85
  return (
86
86
  <Box
87
87
  flexDirection="column"
88
- onMouseMove={onFocus}
88
+ onMouseOver={onFocus}
89
89
  onMouseDown={(event?: { stopPropagation?: () => void; preventDefault?: () => void }) => {
90
90
  event?.stopPropagation?.();
91
91
  event?.preventDefault?.();
@@ -135,7 +135,7 @@ export function CheckboxRow({
135
135
  <Box
136
136
  flexDirection="column"
137
137
  backgroundColor={hovered ? hoverBg() : undefined}
138
- onMouseMove={() => {
138
+ onMouseOver={() => {
139
139
  setHovered(true);
140
140
  onFocus();
141
141
  }}
@@ -214,7 +214,7 @@ export function AlertsPane({ focused, width, height, close }: PaneProps) {
214
214
  alert: AlertRule,
215
215
  column: AlertColumn,
216
216
  _index: number,
217
- rowState: { selected: boolean; hovered: boolean },
217
+ rowState: { selected: boolean },
218
218
  ): DataTableCell => {
219
219
  const selectedColor = rowState.selected ? colors.selectedText : undefined;
220
220
  const actionMouseDown = (handler: () => void) => (
@@ -26,7 +26,7 @@ interface BuildoutCellContext {
26
26
  export function renderBuildoutCell(
27
27
  row: BuildoutRow,
28
28
  column: BuildoutColumn,
29
- rowState: { selected: boolean; hovered: boolean },
29
+ rowState: { selected: boolean },
30
30
  context: BuildoutCellContext,
31
31
  ): DataTableCell {
32
32
  const selectedColor = rowState.selected ? colors.selectedText : undefined;
@@ -314,7 +314,7 @@ export function BuildoutPane({ focused, width, height }: PaneProps) {
314
314
  row: BuildoutRow,
315
315
  column: BuildoutColumn,
316
316
  _index: number,
317
- rowState: { selected: boolean; hovered: boolean },
317
+ rowState: { selected: boolean },
318
318
  ) => renderBuildoutCell(row, column, rowState, {
319
319
  favoriteBusyKey,
320
320
  toggleFavorite,
@@ -97,7 +97,7 @@ export const DesktopChatMessage = memo(function DesktopChatMessage({
97
97
  <Text
98
98
  fg={state.authorColor}
99
99
  attributes={state.authorAttributes}
100
- onMouseMove={() => onUserHover(msg.user)}
100
+ onMouseOver={() => onUserHover(msg.user)}
101
101
  onMouseOut={onUserHoverEnd}
102
102
  style={{ cursor: "default" }}
103
103
  >
@@ -58,7 +58,7 @@ export function ResponsiveTickerBadgeText({
58
58
  height={1}
59
59
  flexDirection="row"
60
60
  backgroundColor={blendHex(colors.panel, colors.positive, 0.24)}
61
- onMouseMove={() => {
61
+ onMouseOver={() => {
62
62
  if (user) onUserHover?.(user);
63
63
  }}
64
64
  onMouseOut={() => {
@@ -44,7 +44,7 @@ export function TerminalChatMessage({
44
44
  const messageRowProps = {
45
45
  width: contentWidth,
46
46
  backgroundColor: state.bgColor,
47
- onMouseMove: setHovered,
47
+ onMouseOver: setHovered,
48
48
  onMouseOut: clearHovered,
49
49
  };
50
50
 
@@ -80,7 +80,7 @@ export function TerminalChatMessage({
80
80
  <Text
81
81
  fg={state.authorColor}
82
82
  attributes={state.authorAttributes}
83
- onMouseMove={() => onUserHover(msg.user)}
83
+ onMouseOver={() => onUserHover(msg.user)}
84
84
  onMouseOut={onUserHoverEnd}
85
85
  >
86
86
  {msg.user.username ?? "anon"}
@@ -239,7 +239,7 @@ export function ChannelSidebar({
239
239
  flexDirection="row"
240
240
  backgroundColor={bg}
241
241
  onMouseDown={selectChannel}
242
- onMouseMove={() => setHoveredChannelId((current) => (current === channel.id ? current : channel.id))}
242
+ onMouseOver={() => setHoveredChannelId((current) => (current === channel.id ? current : channel.id))}
243
243
  onMouseOut={() => setHoveredChannelId((current) => (current === channel.id ? null : current))}
244
244
  style={{ cursor: "pointer" }}
245
245
  >
@@ -98,7 +98,7 @@ export function ChatStatusWidget({ controller = chatController }: ChatStatusWidg
98
98
  <Box
99
99
  flexDirection="row"
100
100
  backgroundColor={hovered ? hoverBg() : undefined}
101
- onMouseMove={() => setHovered((current) => (current ? current : true))}
101
+ onMouseOver={() => setHovered((current) => (current ? current : true))}
102
102
  onMouseOut={() => setHovered((current) => (current ? false : current))}
103
103
  onMouseDown={openChat}
104
104
  >
@@ -22,7 +22,7 @@ export function InlineAuthActions({ showSignup = true }: { showSignup?: boolean
22
22
  <Box flexDirection="row">
23
23
  <Box
24
24
  backgroundColor={hoveredAction === "login" ? hoverBg() : undefined}
25
- onMouseMove={() => setHoveredAction((current) => (current === "login" ? current : "login"))}
25
+ onMouseOver={() => setHoveredAction((current) => (current === "login" ? current : "login"))}
26
26
  onMouseOut={() => setHoveredAction((current) => (current === "login" ? null : current))}
27
27
  onMouseDown={(event: any) => openAuthCommand(openCommandBar, "Log In", event)}
28
28
  >
@@ -33,7 +33,7 @@ export function InlineAuthActions({ showSignup = true }: { showSignup?: boolean
33
33
  <Text fg={colors.textDim}>/</Text>
34
34
  <Box
35
35
  backgroundColor={hoveredAction === "signup" ? hoverBg() : undefined}
36
- onMouseMove={() => setHoveredAction((current) => (current === "signup" ? current : "signup"))}
36
+ onMouseOver={() => setHoveredAction((current) => (current === "signup" ? current : "signup"))}
37
37
  onMouseOut={() => setHoveredAction((current) => (current === "signup" ? null : current))}
38
38
  onMouseDown={(event: any) => openAuthCommand(openCommandBar, "Sign Up", event)}
39
39
  >
@@ -41,7 +41,7 @@ export function SymbolLabelCell({
41
41
  overflow="hidden"
42
42
  backgroundColor={hovered ? hoverBg() : undefined}
43
43
  style={{ cursor: "pointer" }}
44
- onMouseMove={() => onHover(symbol)}
44
+ onMouseOver={() => onHover(symbol)}
45
45
  onMouseOut={() => onLeave(symbol)}
46
46
  onMouseDown={(event: any) => handleSymbolMouseDown(event, openSymbol)}
47
47
  >
@@ -64,7 +64,6 @@ function DebugPane({ focused, width, height }: PaneProps) {
64
64
  const [filterSource, setFilterSource] = useState<string | null>(null);
65
65
  const [autoScroll, setAutoScroll] = useState(true);
66
66
  const [selectedIdx, setSelectedIdx] = useState(-1);
67
- const [hoveredIdx, setHoveredIdx] = useState<number | null>(null);
68
67
  const [showDetail, setShowDetail] = useState(false);
69
68
  const sourcesRef = useRef<string[]>(debugLog.getSources());
70
69
 
@@ -261,8 +260,8 @@ function DebugPane({ focused, width, height }: PaneProps) {
261
260
  {visibleEntries.map((entry, i) => {
262
261
  const globalIdx = viewStart + i;
263
262
  const isSelected = globalIdx === selectedIdx;
264
- const isHovered = globalIdx === hoveredIdx && !isSelected;
265
- const bgColor = isSelected ? colors.selected : isHovered ? hoverBg() : undefined;
263
+ const bgColor = isSelected ? colors.selected : undefined;
264
+ const rowHoverBg = isSelected ? undefined : hoverBg();
266
265
  const ts = formatTimestamp(entry.timestamp);
267
266
  const lvl = LEVEL_LABELS[entry.level];
268
267
  const sourceTag = entry.source;
@@ -278,7 +277,7 @@ function DebugPane({ focused, width, height }: PaneProps) {
278
277
  width={contentWidth}
279
278
  flexDirection="row"
280
279
  backgroundColor={bgColor}
281
- onMouseMove={() => setHoveredIdx((current) => (current === globalIdx ? current : globalIdx))}
280
+ hoverBackgroundColor={rowHoverBg}
282
281
  onMouseDown={() => { setSelectedIdx(globalIdx); setAutoScroll(false); }}
283
282
  >
284
283
  <Text fg={colors.textMuted}> {ts} </Text>
@@ -63,7 +63,7 @@ export function ActionButton({
63
63
  return (
64
64
  <Box
65
65
  backgroundColor={hovered ? hoverBg() : colors.panel}
66
- onMouseMove={() => onHover(id)}
66
+ onMouseOver={() => onHover(id)}
67
67
  onMouseOut={() => onHover(null)}
68
68
  onMouseDown={(event: any) => {
69
69
  event.stopPropagation?.();
@@ -165,7 +165,7 @@ function DesktopTile({ tile, chartWidth, chartHeight, selected, hovered, currenc
165
165
  onSelect();
166
166
  }}
167
167
  onDoubleClick={onActivate}
168
- onMouseMove={() => onHover(true)}
168
+ onMouseOver={() => onHover(true)}
169
169
  onMouseOut={() => onHover(false)}
170
170
  >
171
171
  {canShowLabel && (
@@ -130,9 +130,9 @@ function optionMoneynessBackground(
130
130
  row: OptionTableRow,
131
131
  contract: OptionContract | undefined,
132
132
  columnId: OptionColumnId,
133
- rowState: { selected: boolean; hovered: boolean },
133
+ rowState: { selected: boolean },
134
134
  ): string | undefined {
135
- if (rowState.selected || rowState.hovered) return undefined;
135
+ if (rowState.selected) return undefined;
136
136
  const inTheMoney = inferColumnMoneyness(row, contract, columnId);
137
137
  const sideColor = columnId.startsWith("call") ? colors.positive : colors.negative;
138
138
  return inTheMoney
@@ -180,13 +180,13 @@ export function renderOptionCell(
180
180
  row: OptionTableRow,
181
181
  column: OptionColumn,
182
182
  _index: number,
183
- rowState: { selected: boolean; hovered: boolean },
183
+ rowState: { selected: boolean },
184
184
  ): DataTableCell {
185
185
  const selectedColor = rowState.selected ? colors.selectedText : undefined;
186
- const rowSurface = rowState.selected ? colors.selected : rowState.hovered ? hoverBg() : colors.bg;
186
+ const rowSurface = rowState.selected ? colors.selected : colors.bg;
187
187
 
188
188
  if (column.id === "strike") {
189
- const backgroundColor = rowState.selected || rowState.hovered
189
+ const backgroundColor = rowState.selected
190
190
  ? undefined
191
191
  : blendHex(colors.bg, row.isPositionStrike ? colors.borderFocused : colors.header, row.isPositionStrike ? 0.18 : 0.1);
192
192
  const surface = backgroundColor ?? rowSurface;
@@ -72,7 +72,7 @@ function TradeFieldPill({
72
72
  backgroundColor={backgroundColor}
73
73
  paddingX={1}
74
74
  marginRight={1}
75
- onMouseMove={() => {
75
+ onMouseOver={() => {
76
76
  if (!disabled) setHoveredField((current) => (current === id ? current : id));
77
77
  }}
78
78
  onMouseDown={disabled ? undefined : () => {
@@ -53,8 +53,6 @@ export function WebDataTable<T, C extends DataTableColumn = DataTableColumn>({
53
53
  scrollRef,
54
54
  syncHeaderScroll: _syncHeaderScroll,
55
55
  onBodyScrollActivity,
56
- hoveredIdx,
57
- setHoveredIdx,
58
56
  getItemKey,
59
57
  isSelected,
60
58
  onSelect,
@@ -257,9 +255,6 @@ export function WebDataTable<T, C extends DataTableColumn = DataTableColumn>({
257
255
  focusPane();
258
256
  onTableMouseDown?.({});
259
257
  }}
260
- onMouseLeave={() => {
261
- if (hoveredIdx !== null) setHoveredIdx(null);
262
- }}
263
258
  onScroll={() => {
264
259
  markScrollbarActive();
265
260
  scheduleBodyScrollActivity();
@@ -315,7 +310,6 @@ export function WebDataTable<T, C extends DataTableColumn = DataTableColumn>({
315
310
  const item = items[row.index];
316
311
  if (!item) return null;
317
312
  const selected = isSelected(item, row.index);
318
- const hovered = hoveredIdx === row.index && !selected;
319
313
  const itemKey = getItemKey(item, row.index);
320
314
  return (
321
315
  <WebDataTableRow<T, C>
@@ -335,13 +329,11 @@ export function WebDataTable<T, C extends DataTableColumn = DataTableColumn>({
335
329
  onRowContextMenu={onRowContextMenu}
336
330
  onRowMouseDown={onRowMouseDown}
337
331
  onSelectRow={selectRow}
338
- hovered={hovered}
339
332
  getRowBackgroundColor={getRowBackgroundColor}
340
333
  renderCell={renderCell}
341
334
  renderSectionHeader={renderSectionHeader}
342
335
  rowContextMenuSurface={rowContextMenuSurface}
343
336
  selected={selected}
344
- setHoveredIdx={setHoveredIdx}
345
337
  />
346
338
  );
347
339
  }),
@@ -12,7 +12,6 @@ import type {
12
12
  import { WEB_CELL_HEIGHT } from "../input-host";
13
13
  import {
14
14
  CSS_BG,
15
- CSS_HOVER_BG,
16
15
  CSS_PANEL,
17
16
  CSS_SELECTED,
18
17
  CSS_SELECTED_TEXT,
@@ -151,7 +150,6 @@ function WebDataTableRowInner<
151
150
  onRowContextMenu,
152
151
  onRowMouseDown,
153
152
  onSelectRow,
154
- hovered,
155
153
  index,
156
154
  item,
157
155
  itemKey,
@@ -163,7 +161,6 @@ function WebDataTableRowInner<
163
161
  rowStart,
164
162
  rowContextMenuSurface,
165
163
  selected,
166
- setHoveredIdx,
167
164
  }: {
168
165
  columns: C[];
169
166
  columnGap: number;
@@ -174,7 +171,6 @@ function WebDataTableRowInner<
174
171
  onRowContextMenu?: DataTableProps<T, C>["onRowContextMenu"];
175
172
  onRowMouseDown?: DataTableProps<T, C>["onRowMouseDown"];
176
173
  onSelectRow: (item: T, index: number) => void;
177
- hovered: boolean;
178
174
  index: number;
179
175
  item: T;
180
176
  itemKey: string;
@@ -186,7 +182,6 @@ function WebDataTableRowInner<
186
182
  rowStart: number;
187
183
  rowContextMenuSurface: boolean;
188
184
  selected: boolean;
189
- setHoveredIdx: (index: number | null) => void;
190
185
  }) {
191
186
  useThemeColors();
192
187
  const sectionHeader: DataTableSectionHeader | null =
@@ -242,13 +237,11 @@ function WebDataTableRowInner<
242
237
  );
243
238
  }
244
239
 
245
- const rowState = { selected, hovered };
240
+ const rowState = { selected };
246
241
  const rowBackgroundColor = getRowBackgroundColor?.(item, index, rowState);
247
242
  const rowBg = selected
248
243
  ? CSS_SELECTED
249
- : hovered
250
- ? CSS_HOVER_BG
251
- : rowBackgroundColor ?? CSS_BG;
244
+ : rowBackgroundColor ?? CSS_BG;
252
245
 
253
246
  return (
254
247
  <div
@@ -260,9 +253,6 @@ function WebDataTableRowInner<
260
253
  ...baseRowStyle,
261
254
  backgroundColor: rowBg,
262
255
  }}
263
- onMouseMove={() => {
264
- if (!hovered) setHoveredIdx(index);
265
- }}
266
256
  onMouseDown={(event) => {
267
257
  focusPane();
268
258
  onTableMouseDown?.(event);
@@ -33,6 +33,9 @@ export const WebBox = forwardRef<HTMLDivElement, Record<string, unknown> & { chi
33
33
  const pendingDragRef = useRef<CellMouseEvent | null>(null);
34
34
  const propsRef = useRef(props);
35
35
  propsRef.current = props;
36
+ const hoverBackgroundColor = typeof props.hoverBackgroundColor === "string"
37
+ ? props.hoverBackgroundColor
38
+ : undefined;
36
39
 
37
40
  useImperativeHandle(ref, () => cellBoundsForElement(() => elementRef.current, () => propsRef.current) as unknown as HTMLDivElement, []);
38
41
 
@@ -140,6 +143,7 @@ export const WebBox = forwardRef<HTMLDivElement, Record<string, unknown> & { chi
140
143
  return (
141
144
  <div
142
145
  {...cleanDomProps(props)}
146
+ data-gloom-hover-bg={hoverBackgroundColor ? "true" : undefined}
143
147
  data-gloom-interactive={hasDirectMouseHandler(props) ? "true" : undefined}
144
148
  ref={elementRef}
145
149
  onMouseDown={handleMouseDown}
@@ -149,9 +153,10 @@ export const WebBox = forwardRef<HTMLDivElement, Record<string, unknown> & { chi
149
153
  onWheel={typeof props.onMouseScroll === "function" ? handleWheel : undefined}
150
154
  style={{
151
155
  ...commonStyle(props),
156
+ "--gloom-box-hover-bg": hoverBackgroundColor,
152
157
  ...(props.style as CSSProperties | undefined),
153
158
  ...(props.visible === false ? { display: "none" } : undefined),
154
- }}
159
+ } as CSSProperties}
155
160
  >
156
161
  {children as ReactNode}
157
162
  </div>
@@ -104,6 +104,7 @@ export function cleanDomProps(props: Record<string, unknown>): Record<string, un
104
104
  "cursorColor", "selectionBg", "selectionFg", "showCursor", "keyBindings", "wrapText", "wrapMode",
105
105
  "initialValue", "value", "onInput", "onChange", "onSubmit", "onCursorChange", "onMouse",
106
106
  "scrollX", "scrollY", "focusable", "bitmap", "bitmaps", "crosshair", "text", "font",
107
+ "hoverBackgroundColor",
107
108
  ]) {
108
109
  delete next[key];
109
110
  }
@@ -20,6 +20,13 @@ body {
20
20
  input, textarea, button { font: inherit; }
21
21
  input, textarea { cursor: text; user-select: text; }
22
22
  button, [data-gloom-interactive="true"] { cursor: pointer; }
23
+ [data-gloom-hover-bg="true"]:hover {
24
+ background-color: var(--gloom-box-hover-bg) !important;
25
+ }
26
+ [data-gloom-role="data-table-row"]:not([data-selected="true"]):hover,
27
+ [data-gloom-role="data-table-row"]:not([data-selected="true"]):hover > [data-gloom-role="data-table-cell"] {
28
+ background-color: var(--gloom-hover-bg) !important;
29
+ }
23
30
  [data-gloom-role="pane-window"] {
24
31
  background-clip: padding-box;
25
32
  isolation: isolate;
@@ -0,0 +1 @@
1
+ import "@opentui/core";
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const VERSION = "0.9.4";
1
+ export const VERSION = "0.9.5";