gpui-bridge-react 0.2.0 → 0.4.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.
@@ -1,5 +1,5 @@
1
1
  import type { ReactNode, Ref } from "react";
2
- import type { A11y, ButtonProps as WireButtonProps, DiffSelection, ImageProps as WireImageProps, Menu, MenuItem, NodeProps, NodeType, Option, RadioGroupProps as WireRadioGroupProps, TableCell, TableColumn, TableSort, TabsProps as WireTabsProps, UINode, WindowControl, WindowEventPayload } from "gpui-bridge";
2
+ import type { A11y, ButtonProps as WireButtonProps, DiffSelection, ImageProps as WireImageProps, Menu, MenuItem, NodeProps, NodeType, Option, QuestionnaireAnswer, RadioGroupProps as WireRadioGroupProps, SettingsChange, TableCell, TableColumn, TableSort, TabsProps as WireTabsProps, UINode, WindowControl, WindowEventPayload } from "gpui-bridge";
3
3
  /** A `ref` gets the node (`ref.current.focus()`). */
4
4
  type HostComponent<P> = (props: P & {
5
5
  ref?: Ref<UINode<NodeType>>;
@@ -22,6 +22,25 @@ export interface DivProps extends SharedProps {
22
22
  tooltip?: string;
23
23
  /** Files dropped on the div. */
24
24
  onDrop?: (paths: string[]) => void;
25
+ /** With the `absolute` class: the user moves it inside its parent; `dragEnd` gives where it was left (PROTOCOL.md section 8). */
26
+ drag?: boolean;
27
+ /** Snaps a `drag` div to its parent's edges and its `drag` siblings within this many px (`true` = 8). */
28
+ magnetic?: boolean | number;
29
+ /** The user can carry the div to a `dropTarget`, which gets this string in `dropNode`. */
30
+ dragData?: string;
31
+ /** Takes divs with `dragData`; its `drag-over:` classes apply while one is carried over it. */
32
+ dropTarget?: boolean;
33
+ /** Where the user left a `drag` div. */
34
+ onDragEnd?: (point: {
35
+ x: number;
36
+ y: number;
37
+ }) => void;
38
+ /** A `dragData` div left on this `dropTarget`. */
39
+ onDropNode?: (drop: {
40
+ data: string;
41
+ x: number;
42
+ y: number;
43
+ }) => void;
25
44
  /** Makes the div focusable; called with keys such as `escape` or `ctrl-enter`. */
26
45
  onKeyDown?: (key: string) => void;
27
46
  children?: ReactNode;
@@ -287,6 +306,7 @@ export type CollapsibleProps = NodeProps["Collapsible"] & {
287
306
  export declare const Collapsible: HostComponent<CollapsibleProps>;
288
307
  export type AccordionProps = NodeProps["Accordion"] & {
289
308
  onChange?: (id: string) => void;
309
+ children?: ReactNode;
290
310
  };
291
311
  export declare const Accordion: HostComponent<AccordionProps>;
292
312
  export type AvatarProps = NodeProps["Avatar"];
@@ -318,7 +338,9 @@ export type GroupBoxProps = NodeProps["GroupBox"] & {
318
338
  export declare const GroupBox: HostComponent<GroupBoxProps>;
319
339
  export type DescriptionListProps = NodeProps["DescriptionList"];
320
340
  export declare const DescriptionList: HostComponent<DescriptionListProps>;
321
- export type StatusBarProps = NodeProps["StatusBar"];
341
+ export type StatusBarProps = NodeProps["StatusBar"] & {
342
+ children?: ReactNode;
343
+ };
322
344
  export declare const StatusBar: HostComponent<StatusBarProps>;
323
345
  export type ToolbarProps = NodeProps["Toolbar"] & {
324
346
  children?: ReactNode;
@@ -357,4 +379,192 @@ export declare const Sidebar: HostComponent<SidebarProps>;
357
379
  /** A line, bar or pie chart of the points in `data`; it has no events of its own. */
358
380
  export type ChartProps = NodeProps["Chart"];
359
381
  export declare const Chart: HostComponent<ChartProps>;
382
+ /** Paints the drawing commands in `commands`; `onPointerDown` gets the local point. */
383
+ export type CanvasProps = NodeProps["Canvas"] & {
384
+ onPointerDown?: (point: {
385
+ x: number;
386
+ y: number;
387
+ }) => void;
388
+ };
389
+ export declare const Canvas: HostComponent<CanvasProps>;
390
+ /** A command palette over the sections in `items`; `onConfirm` gets the chosen entry's `id`. */
391
+ export type CommandProps = NodeProps["Command"] & {
392
+ onConfirm?: (id: string) => void;
393
+ };
394
+ export declare const Command: HostComponent<CommandProps>;
395
+ /** Settings pages of typed fields; `onChange` gets `{key, value}` of the field the user set. */
396
+ export type SettingsProps = NodeProps["Settings"] & {
397
+ onChange?: (change: SettingsChange) => void;
398
+ };
399
+ export declare const Settings: HostComponent<SettingsProps>;
400
+ /** A button that stays pressed; `onChange` gets the new `checked`. */
401
+ export type ToggleProps = NodeProps["Toggle"] & {
402
+ onChange?: (checked: boolean) => void;
403
+ };
404
+ export declare const Toggle: HostComponent<ToggleProps>;
405
+ /** An action with a menu: `onClick` is the left half, `onMenu` gets the chosen item's id. */
406
+ export type DropdownButtonProps = NodeProps["DropdownButton"] & {
407
+ onClick?: () => void;
408
+ onMenu?: (item: string) => void;
409
+ };
410
+ export declare const DropdownButton: HostComponent<DropdownButtonProps>;
411
+ export type LabelProps = NodeProps["Label"];
412
+ export declare const Label: HostComponent<LabelProps>;
413
+ /** A centered empty state; its children are the action under the header. */
414
+ export type EmptyProps = NodeProps["Empty"] & {
415
+ children?: ReactNode;
416
+ };
417
+ export declare const Empty: HostComponent<EmptyProps>;
418
+ export type ShimmerProps = NodeProps["Shimmer"];
419
+ export declare const Shimmer: HostComponent<ShimmerProps>;
420
+ /** A framed text field; `onChange` and `onSubmit` work as in an `Input`. */
421
+ export type InputGroupProps = NodeProps["InputGroup"] & {
422
+ onChange?: (value: string) => void;
423
+ onSubmit?: (value: string) => void;
424
+ };
425
+ export declare const InputGroup: HostComponent<InputGroupProps>;
426
+ /** Copies `value` on click; `onCopied` gets the text that was copied. */
427
+ export type ClipboardProps = NodeProps["Clipboard"] & {
428
+ onCopied?: (value: string) => void;
429
+ };
430
+ export declare const Clipboard: HostComponent<ClipboardProps>;
431
+ /** A confirmation; `onOk` and `onCancel` close it, as in a `Dialog`. */
432
+ export type AlertDialogProps = NodeProps["AlertDialog"] & {
433
+ onOk?: () => void;
434
+ onCancel?: () => void;
435
+ children?: ReactNode;
436
+ };
437
+ export declare const AlertDialog: HostComponent<AlertDialogProps>;
438
+ /** A panel that slides in from `side`; `onClose` is its X, Escape or a click on the overlay. */
439
+ export type SheetProps = NodeProps["Sheet"] & {
440
+ onClose?: () => void;
441
+ children?: ReactNode;
442
+ };
443
+ export declare const Sheet: HostComponent<SheetProps>;
444
+ /**
445
+ * A panel anchored to its first child (the trigger); the rest are the panel. `onChange` gets the
446
+ * new `open`: the host keeps it, as it keeps a `Checkbox`'s `checked`.
447
+ */
448
+ export type PopoverProps = NodeProps["Popover"] & {
449
+ onChange?: (checked: boolean) => void;
450
+ children?: ReactNode;
451
+ };
452
+ export declare const Popover: HostComponent<PopoverProps>;
453
+ /** A card on hover, opened by the mouse alone; `onChange` gets the new `open`. */
454
+ export type HoverCardProps = NodeProps["HoverCard"] & {
455
+ onChange?: (checked: boolean) => void;
456
+ children?: ReactNode;
457
+ };
458
+ export declare const HoverCard: HostComponent<HoverCardProps>;
459
+ /** A day picker; `onChange` gets the chosen day, `null` when cleared. */
460
+ export type DatePickerProps = NodeProps["DatePicker"] & {
461
+ onChange?: (value: string | null) => void;
462
+ };
463
+ export declare const DatePicker: HostComponent<DatePickerProps>;
464
+ /** A time typed by segments; `onChange` gets the time (`HH:MM[:SS]`). */
465
+ export type TimeFieldProps = NodeProps["TimeField"] & {
466
+ onChange?: (value: string) => void;
467
+ };
468
+ export declare const TimeField: HostComponent<TimeFieldProps>;
469
+ /** A color swatch and hex box; `onChange` gets the color, `null` when cleared. */
470
+ export type ColorPickerProps = NodeProps["ColorPicker"] & {
471
+ onChange?: (value: string | null) => void;
472
+ };
473
+ export declare const ColorPicker: HostComponent<ColorPickerProps>;
474
+ /** A list that picks several options; `onChange` gets the whole selection. */
475
+ export type ComboboxProps = NodeProps["Combobox"] & {
476
+ onChange?: (value: string[]) => void;
477
+ };
478
+ export declare const Combobox: HostComponent<ComboboxProps>;
479
+ /** A chat bubble; its children are the content. */
480
+ export type BubbleProps = NodeProps["Bubble"] & {
481
+ children?: ReactNode;
482
+ };
483
+ export declare const Bubble: HostComponent<BubbleProps>;
484
+ /** A message row: a `MessageHeader` and a `MessageFooter` child, the rest is the content. */
485
+ export type MessageProps = NodeProps["Message"] & {
486
+ children?: ReactNode;
487
+ };
488
+ export declare const Message: HostComponent<MessageProps>;
489
+ export type MessageHeaderProps = NodeProps["MessageHeader"] & {
490
+ children?: ReactNode;
491
+ };
492
+ export declare const MessageHeader: HostComponent<MessageHeaderProps>;
493
+ export type MessageFooterProps = NodeProps["MessageFooter"] & {
494
+ children?: ReactNode;
495
+ };
496
+ export declare const MessageFooter: HostComponent<MessageFooterProps>;
497
+ /** A compact status row; children go after the text. */
498
+ export type MarkerProps = NodeProps["Marker"] & {
499
+ children?: ReactNode;
500
+ };
501
+ export declare const Marker: HostComponent<MarkerProps>;
502
+ /** A file or picture card; each handler shows its control (`onRetry` only while `failed`). */
503
+ export type AttachmentProps = NodeProps["Attachment"] & {
504
+ onClick?: () => void;
505
+ onRemove?: () => void;
506
+ onRetry?: () => void;
507
+ children?: ReactNode;
508
+ };
509
+ export declare const Attachment: HostComponent<AttachmentProps>;
510
+ /** A virtual list of messages anchored at the end; each child is a row. */
511
+ export type MessageScrollerProps = NodeProps["MessageScroller"] & {
512
+ children?: ReactNode;
513
+ };
514
+ export declare const MessageScroller: HostComponent<MessageScrollerProps>;
515
+ /** Questions one at a time; `onChange` gets one answer, `onSubmit` all of them. */
516
+ export type QuestionnaireProps = NodeProps["Questionnaire"] & {
517
+ onChange?: (answer: QuestionnaireAnswer) => void;
518
+ onSubmit?: (answers: QuestionnaireAnswer[]) => void;
519
+ };
520
+ export declare const Questionnaire: HostComponent<QuestionnaireProps>;
521
+ /**
522
+ * A selectable list over its `ListItem` children. Passing `value` makes the selection controlled.
523
+ * `onQuery` gets the search text (render the matching rows); `onLoadMore` asks for more rows.
524
+ */
525
+ export type ListProps = NodeProps["List"] & {
526
+ value?: string | null;
527
+ onChange?: (value: string | null) => void;
528
+ onConfirm?: (value: string) => void;
529
+ onQuery?: (query: string) => void;
530
+ onLoadMore?: () => void;
531
+ children?: ReactNode;
532
+ };
533
+ export declare const List: HostComponent<ListProps>;
534
+ /** A `List` row: `value` is what the list reports; its children are the content. */
535
+ export type ListItemProps = NodeProps["ListItem"] & {
536
+ children?: ReactNode;
537
+ };
538
+ export declare const ListItem: HostComponent<ListItemProps>;
539
+ /** Panels the user rearranges: its `DockPanel` children. The host owns the layout. */
540
+ export type DockProps = NodeProps["Dock"] & {
541
+ children?: ReactNode;
542
+ };
543
+ export declare const Dock: HostComponent<DockProps>;
544
+ /** A `Dock` panel; `onClose` means the user closed it: stop rendering it. */
545
+ export type DockPanelProps = NodeProps["DockPanel"] & {
546
+ onClose?: () => void;
547
+ children?: ReactNode;
548
+ };
549
+ export declare const DockPanel: HostComponent<DockPanelProps>;
550
+ /** An `Accordion` section: `id` is what `onChange` reports; its children are the content. */
551
+ export type AccordionItemProps = NodeProps["AccordionItem"] & {
552
+ children?: ReactNode;
553
+ };
554
+ export declare const AccordionItem: HostComponent<AccordionItemProps>;
555
+ /** A `Dialog`'s or `AlertDialog`'s footer: its children (buttons) replace OK/Cancel. */
556
+ export type DialogFooterProps = NodeProps["DialogFooter"] & {
557
+ children?: ReactNode;
558
+ };
559
+ export declare const DialogFooter: HostComponent<DialogFooterProps>;
560
+ /** A `StatusBar`'s left side: its children replace the `left` text. */
561
+ export type StatusBarLeftProps = NodeProps["StatusBarLeft"] & {
562
+ children?: ReactNode;
563
+ };
564
+ export declare const StatusBarLeft: HostComponent<StatusBarLeftProps>;
565
+ /** A `StatusBar`'s right side: its children replace the `right` text. */
566
+ export type StatusBarRightProps = NodeProps["StatusBarRight"] & {
567
+ children?: ReactNode;
568
+ };
569
+ export declare const StatusBarRight: HostComponent<StatusBarRightProps>;
360
570
  export {};
@@ -58,3 +58,37 @@ export const Diff = "Diff";
58
58
  export const Carousel = "Carousel";
59
59
  export const Sidebar = "Sidebar";
60
60
  export const Chart = "Chart";
61
+ export const Canvas = "Canvas";
62
+ export const Command = "Command";
63
+ export const Settings = "Settings";
64
+ export const Toggle = "Toggle";
65
+ export const DropdownButton = "DropdownButton";
66
+ export const Label = "Label";
67
+ export const Empty = "Empty";
68
+ export const Shimmer = "Shimmer";
69
+ export const InputGroup = "InputGroup";
70
+ export const Clipboard = "Clipboard";
71
+ export const AlertDialog = "AlertDialog";
72
+ export const Sheet = "Sheet";
73
+ export const Popover = "Popover";
74
+ export const HoverCard = "HoverCard";
75
+ export const DatePicker = "DatePicker";
76
+ export const TimeField = "TimeField";
77
+ export const ColorPicker = "ColorPicker";
78
+ export const Combobox = "Combobox";
79
+ export const Bubble = "Bubble";
80
+ export const Message = "Message";
81
+ export const MessageHeader = "MessageHeader";
82
+ export const MessageFooter = "MessageFooter";
83
+ export const Marker = "Marker";
84
+ export const Attachment = "Attachment";
85
+ export const MessageScroller = "MessageScroller";
86
+ export const Questionnaire = "Questionnaire";
87
+ export const List = "List";
88
+ export const ListItem = "ListItem";
89
+ export const Dock = "Dock";
90
+ export const DockPanel = "DockPanel";
91
+ export const AccordionItem = "AccordionItem";
92
+ export const DialogFooter = "DialogFooter";
93
+ export const StatusBarLeft = "StatusBarLeft";
94
+ export const StatusBarRight = "StatusBarRight";
@@ -114,12 +114,21 @@ const EVENT_PROPS = {
114
114
  onMenu: "menu",
115
115
  onKeyDown: "keyDown",
116
116
  onDrop: "drop",
117
+ onDragEnd: "dragEnd",
118
+ onDropNode: "dropNode",
117
119
  onOk: "ok",
118
120
  onCancel: "cancel",
119
121
  onClose: "close",
120
122
  onSort: "sort",
121
123
  onExpand: "expand",
122
124
  onCollapse: "collapse",
125
+ onPointerDown: "pointerDown",
126
+ onConfirm: "confirm",
127
+ onCopied: "copied",
128
+ onRemove: "remove",
129
+ onRetry: "retry",
130
+ onQuery: "query",
131
+ onLoadMore: "loadMore",
123
132
  };
124
133
  function isTextChildren(children) {
125
134
  const items = Array.isArray(children) ? children : [children];
@@ -156,14 +165,16 @@ function split(type, props) {
156
165
  wire.controlled = props.value !== undefined;
157
166
  if (type === "Pagination")
158
167
  wire.controlled = props.page !== undefined;
159
- if (type === "NumberInput" || type === "OtpInput")
168
+ if (type === "NumberInput" || type === "OtpInput" || type === "InputGroup")
160
169
  wire.controlled = props.value !== undefined;
161
170
  if (type === "Table")
162
171
  wire.controlled = props.selected !== undefined;
163
- if (type === "Tree" || type === "Carousel" || type === "Sidebar")
172
+ if (type === "Tree" || type === "Carousel" || type === "Sidebar" || type === "List")
164
173
  wire.controlled = props.value !== undefined;
165
- if (type === "Checkbox" || type === "Switch")
174
+ if (type === "Checkbox" || type === "Switch" || type === "Toggle")
166
175
  wire.controlled = props.checked !== undefined;
176
+ if (type === "DatePicker" || type === "TimeField" || type === "ColorPicker" || type === "Combobox")
177
+ wire.controlled = props.value !== undefined;
167
178
  return { wire, handlers };
168
179
  }
169
180
  /** Host event payloads become plain handler arguments. */
@@ -173,7 +184,7 @@ function subscribe(instance, event) {
173
184
  const handler = instance.handlers.get(event);
174
185
  if (!handler)
175
186
  return;
176
- if (event === "click" || event === "ok" || event === "cancel" || event === "close")
187
+ if (event === "click" || event === "ok" || event === "cancel" || event === "close" || event === "loadMore")
177
188
  handler();
178
189
  // A Table's double click carries the row.
179
190
  else if (event === "doubleClick")
@@ -186,7 +197,9 @@ function subscribe(instance, event) {
186
197
  handler(payload.key);
187
198
  else if (event === "drop")
188
199
  handler(payload.paths);
189
- else if (instance.type === "Checkbox" || instance.type === "Switch")
200
+ else if (instance.type === "Checkbox" || instance.type === "Switch" || instance.type === "Toggle")
201
+ handler(payload.checked);
202
+ else if (instance.type === "Popover" || instance.type === "HoverCard")
190
203
  handler(payload.checked);
191
204
  else
192
205
  handler(payload.value);
@@ -286,6 +299,74 @@ function createNode(app, type, wire) {
286
299
  return app.sidebar(wire);
287
300
  case "Chart":
288
301
  return app.chart(wire);
302
+ case "Canvas":
303
+ return app.canvas(wire);
304
+ case "Command":
305
+ return app.command(wire);
306
+ case "Settings":
307
+ return app.settings(wire);
308
+ case "Toggle":
309
+ return app.toggle(wire);
310
+ case "DropdownButton":
311
+ return app.dropdownButton(wire);
312
+ case "Label":
313
+ return app.label(wire);
314
+ case "Empty":
315
+ return app.empty(wire);
316
+ case "Shimmer":
317
+ return app.shimmer(wire);
318
+ case "InputGroup":
319
+ return app.inputGroup(wire);
320
+ case "Clipboard":
321
+ return app.clipboard(wire);
322
+ case "AlertDialog":
323
+ return app.alertDialog(wire);
324
+ case "Sheet":
325
+ return app.sheet(wire);
326
+ case "Popover":
327
+ return app.popover(wire);
328
+ case "HoverCard":
329
+ return app.hoverCard(wire);
330
+ case "DatePicker":
331
+ return app.datePicker(wire);
332
+ case "TimeField":
333
+ return app.timeField(wire);
334
+ case "ColorPicker":
335
+ return app.colorPicker(wire);
336
+ case "Combobox":
337
+ return app.combobox(wire);
338
+ case "Bubble":
339
+ return app.bubble(wire);
340
+ case "Message":
341
+ return app.message(wire);
342
+ case "MessageHeader":
343
+ return app.messageHeader(wire);
344
+ case "MessageFooter":
345
+ return app.messageFooter(wire);
346
+ case "Marker":
347
+ return app.marker(wire);
348
+ case "Attachment":
349
+ return app.attachment(wire);
350
+ case "MessageScroller":
351
+ return app.messageScroller(wire);
352
+ case "Questionnaire":
353
+ return app.questionnaire(wire);
354
+ case "List":
355
+ return app.list(wire);
356
+ case "ListItem":
357
+ return app.listItem(wire);
358
+ case "Dock":
359
+ return app.dock(wire);
360
+ case "DockPanel":
361
+ return app.dockPanel(wire);
362
+ case "AccordionItem":
363
+ return app.accordionItem(wire);
364
+ case "DialogFooter":
365
+ return app.dialogFooter(wire);
366
+ case "StatusBarLeft":
367
+ return app.statusBarLeft(wire);
368
+ case "StatusBarRight":
369
+ return app.statusBarRight(wire);
289
370
  default:
290
371
  throw new Error(`gpui-bridge-react: unknown element type '${type}'`);
291
372
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gpui-bridge-react",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "React renderer for gpui-bridge native UIs",
5
5
  "license": "MIT",
6
6
  "author": "gpui-bridge contributors",
@@ -29,14 +29,14 @@
29
29
  "node": ">=22.6"
30
30
  },
31
31
  "peerDependencies": {
32
- "gpui-bridge": "^0.2.0",
32
+ "gpui-bridge": "^0.4.0",
33
33
  "react": "^19.3.0"
34
34
  },
35
35
  "dependencies": {
36
36
  "react-reconciler": "0.34.0"
37
37
  },
38
38
  "devDependencies": {
39
- "gpui-bridge": "0.2.0",
39
+ "gpui-bridge": "0.4.0",
40
40
  "@types/node": "^26.6.5",
41
41
  "@types/react": "19.3.0",
42
42
  "@types/react-reconciler": "^0.34.0",