@gtkx/react 0.1.35 → 0.1.36

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,8 +1,10 @@
1
1
  import { toCamelCase, toPascalCase } from "@gtkx/gir";
2
2
  import { format } from "prettier";
3
- const LIST_WIDGETS = new Set(["ListView", "ColumnView", "GridView"]);
3
+ const LIST_WIDGETS = new Set(["ListView", "GridView"]);
4
+ const COLUMN_VIEW_WIDGET = "ColumnView";
4
5
  const DROPDOWN_WIDGETS = new Set(["DropDown"]);
5
6
  const GRID_WIDGETS = new Set(["Grid"]);
7
+ const NOTEBOOK_WIDGET = "Notebook";
6
8
  const INTERNALLY_PROVIDED_PARAMS = {
7
9
  ApplicationWindow: new Set(["application"]),
8
10
  };
@@ -27,8 +29,10 @@ const toJsxPropertyType = (tsType) => {
27
29
  return `Gtk.${result}`;
28
30
  };
29
31
  const isListWidget = (widgetName) => LIST_WIDGETS.has(widgetName);
32
+ const isColumnViewWidget = (widgetName) => widgetName === COLUMN_VIEW_WIDGET;
30
33
  const isDropDownWidget = (widgetName) => DROPDOWN_WIDGETS.has(widgetName);
31
34
  const isGridWidget = (widgetName) => GRID_WIDGETS.has(widgetName);
35
+ const isNotebookWidget = (widgetName) => widgetName === NOTEBOOK_WIDGET;
32
36
  const sanitizeDoc = (doc) => {
33
37
  let result = doc;
34
38
  result = result.replace(/<picture>[\s\S]*?<\/picture>/gi, "");
@@ -113,14 +117,14 @@ export class JsxGenerator {
113
117
  `import type { ReactNode, Ref } from "react";`,
114
118
  ...externalImports,
115
119
  `import type * as Gtk from "@gtkx/ffi/gtk";`,
116
- `import type { GridChildProps, ListItemProps, SlotProps } from "../types.js";`,
120
+ `import type { ColumnViewColumnProps, GridChildProps, ListItemProps, ListViewRenderProps, NotebookPageProps, SlotProps } from "../types.js";`,
117
121
  "",
118
122
  ].join("\n");
119
123
  }
120
124
  generateCommonTypes(widgetClass) {
121
125
  const widgetPropsContent = this.generateWidgetPropsContent(widgetClass);
122
126
  return `
123
- export { SlotProps, GridChildProps, ListItemProps };
127
+ export { ColumnViewColumnProps, GridChildProps, ListItemProps, ListViewRenderProps, NotebookPageProps, SlotProps };
124
128
 
125
129
  ${widgetPropsContent}
126
130
  `;
@@ -309,8 +313,13 @@ ${widgetPropsContent}
309
313
  }
310
314
  if (isListWidget(widget.name)) {
311
315
  lines.push("");
312
- lines.push(`\t/** Function to render each item as a GTK widget */`);
313
- lines.push(`\trenderItem?: (item: any) => Gtk.Widget;`);
316
+ lines.push(`\t/**`);
317
+ lines.push(`\t * Render function for list items.`);
318
+ lines.push(`\t * Called with null during setup/unbind and with the actual item during bind.`);
319
+ lines.push(`\t * The ref callback must be attached to the root widget to set it as the list item's child.`);
320
+ lines.push(`\t */`);
321
+ lines.push(`\t// biome-ignore lint/suspicious/noExplicitAny: allows typed renderItem callbacks`);
322
+ lines.push(`\trenderItem: (item: any, ref: import("react").RefCallback<Gtk.Widget>) => import("react").ReactElement;`);
314
323
  }
315
324
  if (isDropDownWidget(widget.name)) {
316
325
  lines.push("");
@@ -523,16 +532,22 @@ ${widgetPropsContent}
523
532
  const nonChildSlots = metadata.namedChildSlots.filter((slot) => slot.slotName !== "Child");
524
533
  const hasMeaningfulSlots = nonChildSlots.length > 0 ||
525
534
  isListWidget(widget.name) ||
535
+ isColumnViewWidget(widget.name) ||
526
536
  isDropDownWidget(widget.name) ||
527
- isGridWidget(widget.name);
537
+ isGridWidget(widget.name) ||
538
+ isNotebookWidget(widget.name);
528
539
  const docComment = widget.doc ? formatDoc(widget.doc).trimEnd() : "";
529
540
  if (hasMeaningfulSlots) {
530
541
  const valueMembers = [
531
542
  `Root: "${widgetName}.Root" as const`,
532
543
  ...metadata.namedChildSlots.map((slot) => `${slot.slotName}: "${widgetName}.${slot.slotName}" as const`),
533
544
  ...(isListWidget(widget.name) ? [`Item: "${widgetName}.Item" as const`] : []),
545
+ ...(isColumnViewWidget(widget.name)
546
+ ? [`Column: "${widgetName}.Column" as const`, `Item: "${widgetName}.Item" as const`]
547
+ : []),
534
548
  ...(isDropDownWidget(widget.name) ? [`Item: "${widgetName}.Item" as const`] : []),
535
549
  ...(isGridWidget(widget.name) ? [`Child: "${widgetName}.Child" as const`] : []),
550
+ ...(isNotebookWidget(widget.name) ? [`Page: "${widgetName}.Page" as const`] : []),
536
551
  ];
537
552
  if (docComment) {
538
553
  lines.push(`${docComment}\nexport const ${widgetName} = {\n\t${valueMembers.join(",\n\t")},\n};`);
@@ -565,8 +580,10 @@ ${widgetPropsContent}
565
580
  const nonChildSlots = metadata.namedChildSlots.filter((slot) => slot.slotName !== "Child");
566
581
  const hasMeaningfulSlots = nonChildSlots.length > 0 ||
567
582
  isListWidget(widget.name) ||
583
+ isColumnViewWidget(widget.name) ||
568
584
  isDropDownWidget(widget.name) ||
569
- isGridWidget(widget.name);
585
+ isGridWidget(widget.name) ||
586
+ isNotebookWidget(widget.name);
570
587
  if (hasMeaningfulSlots) {
571
588
  elements.push(`"${widgetName}.Root": ${propsName};`);
572
589
  }
@@ -579,12 +596,19 @@ ${widgetPropsContent}
579
596
  if (isListWidget(widget.name)) {
580
597
  elements.push(`"${widgetName}.Item": ListItemProps;`);
581
598
  }
599
+ if (isColumnViewWidget(widget.name)) {
600
+ elements.push(`"${widgetName}.Column": ColumnViewColumnProps;`);
601
+ elements.push(`"${widgetName}.Item": ListItemProps;`);
602
+ }
582
603
  if (isDropDownWidget(widget.name)) {
583
604
  elements.push(`"${widgetName}.Item": ListItemProps;`);
584
605
  }
585
606
  if (isGridWidget(widget.name)) {
586
607
  elements.push(`"${widgetName}.Child": GridChildProps;`);
587
608
  }
609
+ if (isNotebookWidget(widget.name)) {
610
+ elements.push(`"${widgetName}.Page": NotebookPageProps;`);
611
+ }
588
612
  }
589
613
  return `
590
614
  declare global {
package/dist/factory.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  import type * as Gtk from "@gtkx/ffi/gtk";
2
2
  import type { Node } from "./node.js";
3
+ import { type ROOT_NODE_CONTAINER } from "./nodes/root.js";
3
4
  export type Props = Record<string, unknown>;
4
- export declare const createNode: (type: string, props: Props, app: Gtk.Application, existingWidget?: Gtk.Widget) => Node;
5
+ export { ROOT_NODE_CONTAINER } from "./nodes/root.js";
6
+ export declare const createNode: (type: string, props: Props, app: Gtk.Application, existingWidget?: Gtk.Widget | typeof ROOT_NODE_CONTAINER) => Node;
package/dist/factory.js CHANGED
@@ -1,23 +1,33 @@
1
+ import { ColumnViewColumnNode, ColumnViewItemNode, ColumnViewNode } from "./nodes/column-view.js";
1
2
  import { DropDownItemNode, DropDownNode } from "./nodes/dropdown.js";
2
3
  import { GridChildNode, GridNode } from "./nodes/grid.js";
3
4
  import { ListItemNode, ListViewNode } from "./nodes/list.js";
5
+ import { NotebookNode, NotebookPageNode } from "./nodes/notebook.js";
4
6
  import { OverlayNode } from "./nodes/overlay.js";
7
+ import { RootNode } from "./nodes/root.js";
5
8
  import { SlotNode } from "./nodes/slot.js";
6
9
  import { WidgetNode } from "./nodes/widget.js";
10
+ export { ROOT_NODE_CONTAINER } from "./nodes/root.js";
7
11
  const NODE_CLASSES = [
12
+ RootNode,
13
+ ColumnViewColumnNode,
14
+ ColumnViewItemNode,
8
15
  ListItemNode,
9
16
  DropDownItemNode,
10
17
  GridChildNode,
18
+ NotebookPageNode,
11
19
  SlotNode,
12
20
  DropDownNode,
13
21
  GridNode,
14
22
  OverlayNode,
23
+ ColumnViewNode,
15
24
  ListViewNode,
25
+ NotebookNode,
16
26
  WidgetNode,
17
27
  ];
18
28
  export const createNode = (type, props, app, existingWidget) => {
19
29
  for (const NodeClass of NODE_CLASSES) {
20
- if (NodeClass.matches(type)) {
30
+ if (NodeClass.matches(type, props, existingWidget)) {
21
31
  return new NodeClass(type, props, app, existingWidget);
22
32
  }
23
33
  }
@@ -0,0 +1,4 @@
1
+ import type { ReactNode } from "react";
2
+ import type Reconciler from "react-reconciler";
3
+ export declare const updateSync: (element: ReactNode, fiberRoot: Reconciler.FiberRoot) => void;
4
+ export declare const createFiberRoot: () => Reconciler.FiberRoot;
@@ -0,0 +1,27 @@
1
+ import { ROOT_NODE_CONTAINER } from "./factory.js";
2
+ import { reconciler } from "./reconciler.js";
3
+ export const updateSync = (element, fiberRoot) => {
4
+ const instance = reconciler.getInstance();
5
+ const instanceAny = instance;
6
+ if (typeof instanceAny.flushSync === "function") {
7
+ instanceAny.flushSync(() => {
8
+ instance.updateContainer(element, fiberRoot, null, () => { });
9
+ });
10
+ }
11
+ else {
12
+ if (typeof instanceAny.updateContainerSync === "function") {
13
+ instanceAny.updateContainerSync(element, fiberRoot, null, () => { });
14
+ }
15
+ else {
16
+ instance.updateContainer(element, fiberRoot, null, () => { });
17
+ }
18
+ if (typeof instanceAny.flushSyncWork === "function") {
19
+ instanceAny.flushSyncWork();
20
+ }
21
+ }
22
+ instance.flushPassiveEffects();
23
+ };
24
+ export const createFiberRoot = () => {
25
+ const instance = reconciler.getInstance();
26
+ return instance.createContainer(ROOT_NODE_CONTAINER, 0, null, false, null, "", (error) => console.error("List item render error:", error), () => { }, () => { }, () => { }, null);
27
+ };
@@ -3,8 +3,8 @@ import type { ReactNode, Ref } from "react";
3
3
  import type * as Gdk from "@gtkx/ffi/gdk";
4
4
  import type * as Gio from "@gtkx/ffi/gio";
5
5
  import type * as Gtk from "@gtkx/ffi/gtk";
6
- import type { GridChildProps, ListItemProps, SlotProps } from "../types.js";
7
- export { SlotProps, GridChildProps, ListItemProps };
6
+ import type { ColumnViewColumnProps, GridChildProps, ListItemProps, ListViewRenderProps, NotebookPageProps, SlotProps } from "../types.js";
7
+ export { ColumnViewColumnProps, GridChildProps, ListItemProps, ListViewRenderProps, NotebookPageProps, SlotProps, };
8
8
  export interface WidgetProps {
9
9
  canFocus?: boolean;
10
10
  canTarget?: boolean;
@@ -268,7 +268,6 @@ export interface ColumnViewProps extends WidgetProps {
268
268
  vadjustment?: Gtk.Adjustment;
269
269
  vscrollPolicy?: Gtk.ScrollablePolicy;
270
270
  onActivate?: (self: Gtk.ColumnView, position: number) => void;
271
- renderItem?: (item: any) => Gtk.Widget;
272
271
  ref?: Ref<Gtk.ColumnView>;
273
272
  }
274
273
  export interface ComboBoxProps extends WidgetProps {
@@ -567,7 +566,7 @@ export interface GridViewProps extends ListBaseProps {
567
566
  singleClickActivate?: boolean;
568
567
  tabBehavior?: Gtk.ListTabBehavior;
569
568
  onActivate?: (self: Gtk.GridView, position: number) => void;
570
- renderItem?: (item: any) => Gtk.Widget;
569
+ renderItem: (item: any, ref: import("react").RefCallback<Gtk.Widget>) => import("react").ReactElement;
571
570
  ref?: Ref<Gtk.GridView>;
572
571
  }
573
572
  export interface HeaderBarProps extends WidgetProps {
@@ -725,7 +724,7 @@ export interface ListViewProps extends ListBaseProps {
725
724
  singleClickActivate?: boolean;
726
725
  tabBehavior?: Gtk.ListTabBehavior;
727
726
  onActivate?: (self: Gtk.ListView, position: number) => void;
728
- renderItem?: (item: any) => Gtk.Widget;
727
+ renderItem: (item: any, ref: import("react").RefCallback<Gtk.Widget>) => import("react").ReactElement;
729
728
  ref?: Ref<Gtk.ListView>;
730
729
  }
731
730
  export interface LockButtonProps extends ButtonProps {
@@ -1305,6 +1304,7 @@ export declare const ColorChooserWidget: "ColorChooserWidget";
1305
1304
  export declare const ColorDialogButton: "ColorDialogButton";
1306
1305
  export declare const ColumnView: {
1307
1306
  Root: "ColumnView.Root";
1307
+ Column: "ColumnView.Column";
1308
1308
  Item: "ColumnView.Item";
1309
1309
  };
1310
1310
  export declare const ComboBox: "ComboBox";
@@ -1377,7 +1377,10 @@ export declare const MenuButton: {
1377
1377
  Popover: "MenuButton.Popover";
1378
1378
  };
1379
1379
  export declare const MessageDialog: "MessageDialog";
1380
- export declare const Notebook: "Notebook";
1380
+ export declare const Notebook: {
1381
+ Root: "Notebook.Root";
1382
+ Page: "Notebook.Page";
1383
+ };
1381
1384
  export declare const Overlay: "Overlay";
1382
1385
  export declare const PageSetupUnixDialog: "PageSetupUnixDialog";
1383
1386
  export declare const Paned: {
@@ -1479,6 +1482,7 @@ declare global {
1479
1482
  ColorChooserWidget: ColorChooserWidgetProps;
1480
1483
  ColorDialogButton: ColorDialogButtonProps;
1481
1484
  "ColumnView.Root": ColumnViewProps;
1485
+ "ColumnView.Column": ColumnViewColumnProps;
1482
1486
  "ColumnView.Item": ListItemProps;
1483
1487
  ComboBox: ComboBoxProps;
1484
1488
  "ComboBox.Child": SlotProps;
@@ -1537,7 +1541,8 @@ declare global {
1537
1541
  "MenuButton.Child": SlotProps;
1538
1542
  "MenuButton.Popover": SlotProps;
1539
1543
  MessageDialog: MessageDialogProps;
1540
- Notebook: NotebookProps;
1544
+ "Notebook.Root": NotebookProps;
1545
+ "Notebook.Page": NotebookPageProps;
1541
1546
  Overlay: OverlayProps;
1542
1547
  "Overlay.Child": SlotProps;
1543
1548
  PageSetupUnixDialog: PageSetupUnixDialogProps;
@@ -3969,6 +3969,7 @@ export const ColorChooserWidget = "ColorChooserWidget";
3969
3969
  export const ColorDialogButton = "ColorDialogButton";
3970
3970
  export const ColumnView = {
3971
3971
  Root: "ColumnView.Root",
3972
+ Column: "ColumnView.Column",
3972
3973
  Item: "ColumnView.Item",
3973
3974
  };
3974
3975
  export const ComboBox = "ComboBox";
@@ -4041,7 +4042,10 @@ export const MenuButton = {
4041
4042
  Popover: "MenuButton.Popover",
4042
4043
  };
4043
4044
  export const MessageDialog = "MessageDialog";
4044
- export const Notebook = "Notebook";
4045
+ export const Notebook = {
4046
+ Root: "Notebook.Root",
4047
+ Page: "Notebook.Page",
4048
+ };
4045
4049
  export const Overlay = "Overlay";
4046
4050
  export const PageSetupUnixDialog = "PageSetupUnixDialog";
4047
4051
  export const Paned = {
package/dist/index.js CHANGED
@@ -9,7 +9,9 @@ import { container } from "./render.js";
9
9
  export const quit = () => {
10
10
  if (container) {
11
11
  reconciler.getInstance().updateContainer(null, container, null, () => {
12
- stop();
12
+ setTimeout(() => {
13
+ stop();
14
+ }, 0);
13
15
  });
14
16
  }
15
17
  return true;
package/dist/node.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as Gtk from "@gtkx/ffi/gtk";
2
- import type { Props } from "./factory.js";
2
+ import type { Props, ROOT_NODE_CONTAINER } from "./factory.js";
3
3
  export declare abstract class Node<T extends Gtk.Widget | undefined = Gtk.Widget | undefined> {
4
- static matches(_type: string): boolean;
4
+ static matches(_type: string, _props: Props, _existingWidget?: Gtk.Widget | typeof ROOT_NODE_CONTAINER): boolean;
5
5
  protected signalHandlers: Map<string, number>;
6
6
  protected widget: T;
7
7
  protected widgetType: string;
@@ -22,5 +22,4 @@ export declare abstract class Node<T extends Gtk.Widget | undefined = Gtk.Widget
22
22
  protected connectSignal(widget: Gtk.Widget, eventName: string, handler: (...args: unknown[]) => unknown): void;
23
23
  protected setProperty(widget: Gtk.Widget, key: string, value: unknown): void;
24
24
  mount(_app: Gtk.Application): void;
25
- dispose(_app: Gtk.Application): void;
26
25
  }
package/dist/node.js CHANGED
@@ -9,7 +9,7 @@ const extractConstructorArgs = (type, props) => {
9
9
  return params.map((p) => props[p.name]);
10
10
  };
11
11
  export class Node {
12
- static matches(_type) {
12
+ static matches(_type, _props, _existingWidget) {
13
13
  return false;
14
14
  }
15
15
  signalHandlers = new Map();
@@ -162,5 +162,4 @@ export class Node {
162
162
  setter.call(widget, value);
163
163
  }
164
164
  mount(_app) { }
165
- dispose(_app) { }
166
165
  }
@@ -0,0 +1,45 @@
1
+ import * as Gtk from "@gtkx/ffi/gtk";
2
+ import type { Props } from "../factory.js";
3
+ import { Node } from "../node.js";
4
+ export declare class ColumnViewNode extends Node<Gtk.ColumnView> {
5
+ static matches(type: string): boolean;
6
+ private stringList;
7
+ private selectionModel;
8
+ private items;
9
+ private columns;
10
+ constructor(type: string, props: Props, app: Gtk.Application);
11
+ getItems(): unknown[];
12
+ addColumn(column: ColumnViewColumnNode): void;
13
+ removeColumn(column: ColumnViewColumnNode): void;
14
+ insertColumnBefore(column: ColumnViewColumnNode, before: ColumnViewColumnNode): void;
15
+ addItem(item: unknown): void;
16
+ insertItemBefore(item: unknown, beforeItem: unknown): void;
17
+ removeItem(item: unknown): void;
18
+ }
19
+ export declare class ColumnViewColumnNode extends Node {
20
+ static matches(type: string): boolean;
21
+ protected isVirtual(): boolean;
22
+ private gtkColumn;
23
+ private factory;
24
+ private renderCell;
25
+ private columnView;
26
+ private fiberRoots;
27
+ constructor(type: string, props: Props, app: Gtk.Application);
28
+ getGtkColumn(): Gtk.ColumnViewColumn;
29
+ setColumnView(columnView: ColumnViewNode | null): void;
30
+ attachToParent(parent: Node): void;
31
+ attachToParentBefore(parent: Node, before: Node): void;
32
+ detachFromParent(parent: Node): void;
33
+ protected consumedProps(): Set<string>;
34
+ updateProps(oldProps: Props, newProps: Props): void;
35
+ }
36
+ export declare class ColumnViewItemNode extends Node {
37
+ static matches(type: string): boolean;
38
+ protected isVirtual(): boolean;
39
+ private item;
40
+ constructor(type: string, props: Props, app: Gtk.Application);
41
+ getItem(): unknown;
42
+ attachToParent(parent: Node): void;
43
+ attachToParentBefore(parent: Node, before: Node): void;
44
+ detachFromParent(parent: Node): void;
45
+ }
@@ -0,0 +1,227 @@
1
+ import { getObject, getObjectId } from "@gtkx/ffi";
2
+ import * as Gtk from "@gtkx/ffi/gtk";
3
+ import { createFiberRoot, updateSync } from "../flush-sync.js";
4
+ import { Node } from "../node.js";
5
+ export class ColumnViewNode extends Node {
6
+ static matches(type) {
7
+ return type === "ColumnView.Root";
8
+ }
9
+ stringList;
10
+ selectionModel;
11
+ items = [];
12
+ columns = [];
13
+ constructor(type, props, app) {
14
+ super(type, props, app);
15
+ this.stringList = new Gtk.StringList([]);
16
+ this.selectionModel = new Gtk.SingleSelection(this.stringList);
17
+ this.widget.setModel(this.selectionModel);
18
+ }
19
+ getItems() {
20
+ return this.items;
21
+ }
22
+ addColumn(column) {
23
+ this.columns.push(column);
24
+ const gtkColumn = column.getGtkColumn();
25
+ this.widget.appendColumn(gtkColumn);
26
+ column.setColumnView(this);
27
+ }
28
+ removeColumn(column) {
29
+ const index = this.columns.indexOf(column);
30
+ if (index !== -1) {
31
+ this.columns.splice(index, 1);
32
+ this.widget.removeColumn(column.getGtkColumn());
33
+ column.setColumnView(null);
34
+ }
35
+ }
36
+ insertColumnBefore(column, before) {
37
+ const beforeIndex = this.columns.indexOf(before);
38
+ if (beforeIndex === -1) {
39
+ this.addColumn(column);
40
+ return;
41
+ }
42
+ this.columns.splice(beforeIndex, 0, column);
43
+ this.widget.insertColumn(beforeIndex, column.getGtkColumn());
44
+ column.setColumnView(this);
45
+ }
46
+ addItem(item) {
47
+ this.items.push(item);
48
+ this.stringList.append("");
49
+ }
50
+ insertItemBefore(item, beforeItem) {
51
+ const beforeIndex = this.items.indexOf(beforeItem);
52
+ if (beforeIndex === -1) {
53
+ this.addItem(item);
54
+ return;
55
+ }
56
+ this.items.splice(beforeIndex, 0, item);
57
+ this.stringList.splice(beforeIndex, 0, [""]);
58
+ }
59
+ removeItem(item) {
60
+ const index = this.items.indexOf(item);
61
+ if (index !== -1) {
62
+ this.items.splice(index, 1);
63
+ this.stringList.remove(index);
64
+ }
65
+ }
66
+ }
67
+ export class ColumnViewColumnNode extends Node {
68
+ static matches(type) {
69
+ return type === "ColumnView.Column";
70
+ }
71
+ isVirtual() {
72
+ return true;
73
+ }
74
+ gtkColumn;
75
+ factory;
76
+ renderCell;
77
+ columnView = null;
78
+ fiberRoots = new Map();
79
+ constructor(type, props, app) {
80
+ super(type, props, app);
81
+ this.factory = new Gtk.SignalListItemFactory();
82
+ this.gtkColumn = new Gtk.ColumnViewColumn(props.title, this.factory);
83
+ this.renderCell = props.renderCell;
84
+ if (props.expand !== undefined) {
85
+ this.gtkColumn.setExpand(props.expand);
86
+ }
87
+ if (props.resizable !== undefined) {
88
+ this.gtkColumn.setResizable(props.resizable);
89
+ }
90
+ if (props.fixedWidth !== undefined) {
91
+ this.gtkColumn.setFixedWidth(props.fixedWidth);
92
+ }
93
+ this.factory.connect("setup", (_self, listItemObj) => {
94
+ const listItem = getObject(listItemObj, Gtk.ListItem);
95
+ const id = getObjectId(listItemObj);
96
+ const fiberRoot = createFiberRoot();
97
+ this.fiberRoots.set(id, fiberRoot);
98
+ let rootWidget = null;
99
+ const ref = (widget) => {
100
+ if (widget && !rootWidget) {
101
+ rootWidget = widget;
102
+ listItem.setChild(widget);
103
+ }
104
+ };
105
+ const element = this.renderCell(null, ref);
106
+ updateSync(element, fiberRoot);
107
+ });
108
+ this.factory.connect("bind", (_self, listItemObj) => {
109
+ const listItem = getObject(listItemObj, Gtk.ListItem);
110
+ const id = getObjectId(listItemObj);
111
+ const fiberRoot = this.fiberRoots.get(id);
112
+ if (!fiberRoot)
113
+ return;
114
+ const position = listItem.getPosition();
115
+ if (this.columnView) {
116
+ const items = this.columnView.getItems();
117
+ const item = items[position];
118
+ const ref = () => { };
119
+ const element = this.renderCell(item ?? null, ref);
120
+ updateSync(element, fiberRoot);
121
+ }
122
+ });
123
+ this.factory.connect("unbind", (_self, listItemObj) => {
124
+ const id = getObjectId(listItemObj);
125
+ const fiberRoot = this.fiberRoots.get(id);
126
+ if (!fiberRoot)
127
+ return;
128
+ const ref = () => { };
129
+ const element = this.renderCell(null, ref);
130
+ updateSync(element, fiberRoot);
131
+ });
132
+ this.factory.connect("teardown", (_self, listItemObj) => {
133
+ const id = getObjectId(listItemObj);
134
+ const fiberRoot = this.fiberRoots.get(id);
135
+ if (!fiberRoot)
136
+ return;
137
+ updateSync(null, fiberRoot);
138
+ this.fiberRoots.delete(id);
139
+ });
140
+ }
141
+ getGtkColumn() {
142
+ return this.gtkColumn;
143
+ }
144
+ setColumnView(columnView) {
145
+ this.columnView = columnView;
146
+ }
147
+ attachToParent(parent) {
148
+ if (parent instanceof ColumnViewNode) {
149
+ parent.addColumn(this);
150
+ }
151
+ }
152
+ attachToParentBefore(parent, before) {
153
+ if (parent instanceof ColumnViewNode && before instanceof ColumnViewColumnNode) {
154
+ parent.insertColumnBefore(this, before);
155
+ }
156
+ else {
157
+ this.attachToParent(parent);
158
+ }
159
+ }
160
+ detachFromParent(parent) {
161
+ if (parent instanceof ColumnViewNode) {
162
+ parent.removeColumn(this);
163
+ }
164
+ }
165
+ consumedProps() {
166
+ const consumed = super.consumedProps();
167
+ consumed.add("renderCell");
168
+ consumed.add("title");
169
+ consumed.add("expand");
170
+ consumed.add("resizable");
171
+ consumed.add("fixedWidth");
172
+ return consumed;
173
+ }
174
+ updateProps(oldProps, newProps) {
175
+ if (oldProps.renderCell !== newProps.renderCell) {
176
+ this.renderCell = newProps.renderCell;
177
+ }
178
+ if (!this.gtkColumn)
179
+ return;
180
+ if (oldProps.title !== newProps.title) {
181
+ this.gtkColumn.setTitle(newProps.title);
182
+ }
183
+ if (oldProps.expand !== newProps.expand) {
184
+ this.gtkColumn.setExpand(newProps.expand);
185
+ }
186
+ if (oldProps.resizable !== newProps.resizable) {
187
+ this.gtkColumn.setResizable(newProps.resizable);
188
+ }
189
+ if (oldProps.fixedWidth !== newProps.fixedWidth) {
190
+ this.gtkColumn.setFixedWidth(newProps.fixedWidth);
191
+ }
192
+ }
193
+ }
194
+ export class ColumnViewItemNode extends Node {
195
+ static matches(type) {
196
+ return type === "ColumnView.Item";
197
+ }
198
+ isVirtual() {
199
+ return true;
200
+ }
201
+ item;
202
+ constructor(type, props, app) {
203
+ super(type, props, app);
204
+ this.item = props.item;
205
+ }
206
+ getItem() {
207
+ return this.item;
208
+ }
209
+ attachToParent(parent) {
210
+ if (parent instanceof ColumnViewNode) {
211
+ parent.addItem(this.item);
212
+ }
213
+ }
214
+ attachToParentBefore(parent, before) {
215
+ if (parent instanceof ColumnViewNode && before instanceof ColumnViewItemNode) {
216
+ parent.insertItemBefore(this.item, before.getItem());
217
+ }
218
+ else {
219
+ this.attachToParent(parent);
220
+ }
221
+ }
222
+ detachFromParent(parent) {
223
+ if (parent instanceof ColumnViewNode) {
224
+ parent.removeItem(this.item);
225
+ }
226
+ }
227
+ }
@@ -1,21 +1,20 @@
1
1
  import * as Gtk from "@gtkx/ffi/gtk";
2
2
  import type { Props } from "../factory.js";
3
3
  import { Node } from "../node.js";
4
- export declare class ListViewNode extends Node<Gtk.ListView> {
4
+ export declare class ListViewNode extends Node<Gtk.ListView | Gtk.GridView> {
5
5
  static matches(type: string): boolean;
6
6
  private stringList;
7
7
  private selectionModel;
8
8
  private factory;
9
9
  private items;
10
10
  private renderItem;
11
- private factorySignalHandlers;
11
+ private fiberRoots;
12
12
  constructor(type: string, props: Props, app: Gtk.Application);
13
13
  addItem(item: unknown): void;
14
14
  insertItemBefore(item: unknown, beforeItem: unknown): void;
15
15
  removeItem(item: unknown): void;
16
16
  protected consumedProps(): Set<string>;
17
17
  updateProps(oldProps: Props, newProps: Props): void;
18
- dispose(app: Gtk.Application): void;
19
18
  }
20
19
  export declare class ListItemNode extends Node {
21
20
  static matches(type: string): boolean;
@@ -1,41 +1,67 @@
1
- import { wrapPtr } from "@gtkx/ffi";
1
+ import { getObject, getObjectId } from "@gtkx/ffi";
2
2
  import * as Gtk from "@gtkx/ffi/gtk";
3
+ import { createFiberRoot, updateSync } from "../flush-sync.js";
3
4
  import { Node } from "../node.js";
4
- const LIST_WIDGETS = ["ListView", "ColumnView", "GridView"];
5
5
  export class ListViewNode extends Node {
6
6
  static matches(type) {
7
- return LIST_WIDGETS.map((w) => `${w}.Root`).includes(type);
7
+ return type === "ListView.Root" || type === "GridView.Root";
8
8
  }
9
9
  stringList;
10
10
  selectionModel;
11
11
  factory;
12
12
  items = [];
13
- renderItem = null;
14
- factorySignalHandlers = new Map();
13
+ renderItem;
14
+ fiberRoots = new Map();
15
15
  constructor(type, props, app) {
16
16
  super(type, props, app);
17
17
  this.stringList = new Gtk.StringList([]);
18
18
  this.selectionModel = new Gtk.SingleSelection(this.stringList);
19
19
  this.factory = new Gtk.SignalListItemFactory();
20
20
  this.renderItem = props.renderItem;
21
- const setupHandlerId = this.factory.connect("setup", (_self, listItemObj) => {
22
- const listItem = wrapPtr(listItemObj, Gtk.ListItem);
23
- if (this.renderItem) {
24
- const widget = this.renderItem(null);
25
- listItem.setChild(widget);
26
- }
21
+ this.factory.connect("setup", (_self, listItemObj) => {
22
+ const listItem = getObject(listItemObj, Gtk.ListItem);
23
+ const id = getObjectId(listItemObj);
24
+ const fiberRoot = createFiberRoot();
25
+ this.fiberRoots.set(id, fiberRoot);
26
+ let rootWidget = null;
27
+ const ref = (widget) => {
28
+ if (widget && !rootWidget) {
29
+ rootWidget = widget;
30
+ listItem.setChild(widget);
31
+ }
32
+ };
33
+ const element = this.renderItem(null, ref);
34
+ updateSync(element, fiberRoot);
27
35
  });
28
- this.factorySignalHandlers.set("setup", setupHandlerId);
29
- const bindHandlerId = this.factory.connect("bind", (_self, listItemObj) => {
30
- const listItem = wrapPtr(listItemObj, Gtk.ListItem);
36
+ this.factory.connect("bind", (_self, listItemObj) => {
37
+ const listItem = getObject(listItemObj, Gtk.ListItem);
38
+ const id = getObjectId(listItemObj);
39
+ const fiberRoot = this.fiberRoots.get(id);
40
+ if (!fiberRoot)
41
+ return;
31
42
  const position = listItem.getPosition();
32
43
  const item = this.items[position];
33
- if (this.renderItem && item !== undefined) {
34
- const widget = this.renderItem(item);
35
- listItem.setChild(widget);
36
- }
44
+ const ref = () => { };
45
+ const element = this.renderItem(item ?? null, ref);
46
+ updateSync(element, fiberRoot);
47
+ });
48
+ this.factory.connect("unbind", (_self, listItemObj) => {
49
+ const id = getObjectId(listItemObj);
50
+ const fiberRoot = this.fiberRoots.get(id);
51
+ if (!fiberRoot)
52
+ return;
53
+ const ref = () => { };
54
+ const element = this.renderItem(null, ref);
55
+ updateSync(element, fiberRoot);
56
+ });
57
+ this.factory.connect("teardown", (_self, listItemObj) => {
58
+ const id = getObjectId(listItemObj);
59
+ const fiberRoot = this.fiberRoots.get(id);
60
+ if (!fiberRoot)
61
+ return;
62
+ updateSync(null, fiberRoot);
63
+ this.fiberRoots.delete(id);
37
64
  });
38
- this.factorySignalHandlers.set("bind", bindHandlerId);
39
65
  this.widget.setModel(this.selectionModel);
40
66
  this.widget.setFactory(this.factory);
41
67
  }
@@ -70,20 +96,10 @@ export class ListViewNode extends Node {
70
96
  }
71
97
  super.updateProps(oldProps, newProps);
72
98
  }
73
- dispose(app) {
74
- super.dispose(app);
75
- this.widget.setModel(undefined);
76
- this.widget.setFactory(undefined);
77
- }
78
99
  }
79
100
  export class ListItemNode extends Node {
80
101
  static matches(type) {
81
- const dotIndex = type.indexOf(".");
82
- if (dotIndex === -1)
83
- return false;
84
- const widgetType = type.slice(0, dotIndex);
85
- const suffix = type.slice(dotIndex + 1);
86
- return suffix === "Item" && LIST_WIDGETS.includes(widgetType);
102
+ return type === "ListView.Item" || type === "GridView.Item";
87
103
  }
88
104
  isVirtual() {
89
105
  return true;
@@ -0,0 +1,27 @@
1
+ import * as Gtk from "@gtkx/ffi/gtk";
2
+ import type { Props } from "../factory.js";
3
+ import { Node } from "../node.js";
4
+ export declare class NotebookNode extends Node<Gtk.Notebook> {
5
+ static matches(type: string): boolean;
6
+ addPage(child: Gtk.Widget, label: string): void;
7
+ insertPageBefore(child: Gtk.Widget, label: string, beforeChild: Gtk.Widget): void;
8
+ removePage(child: Gtk.Widget): void;
9
+ updatePageLabel(child: Gtk.Widget, label: string): void;
10
+ }
11
+ export declare class NotebookPageNode extends Node {
12
+ static matches(type: string): boolean;
13
+ protected isVirtual(): boolean;
14
+ private label;
15
+ private childWidget;
16
+ private parentNotebook;
17
+ constructor(type: string, props: Props, app: Gtk.Application);
18
+ getLabel(): string;
19
+ setChildWidget(widget: Gtk.Widget): void;
20
+ getChildWidget(): Gtk.Widget | null;
21
+ appendChild(child: Node): void;
22
+ attachToParent(parent: Node): void;
23
+ attachToParentBefore(parent: Node, before: Node): void;
24
+ detachFromParent(parent: Node): void;
25
+ protected consumedProps(): Set<string>;
26
+ updateProps(oldProps: Props, newProps: Props): void;
27
+ }
@@ -0,0 +1,102 @@
1
+ import * as Gtk from "@gtkx/ffi/gtk";
2
+ import { Node } from "../node.js";
3
+ export class NotebookNode extends Node {
4
+ static matches(type) {
5
+ return type === "Notebook.Root";
6
+ }
7
+ addPage(child, label) {
8
+ const tabLabel = new Gtk.Label();
9
+ tabLabel.setLabel(label);
10
+ this.widget.appendPage(child, tabLabel);
11
+ }
12
+ insertPageBefore(child, label, beforeChild) {
13
+ const beforePageNum = this.widget.pageNum(beforeChild);
14
+ const tabLabel = new Gtk.Label();
15
+ tabLabel.setLabel(label);
16
+ if (beforePageNum >= 0) {
17
+ this.widget.insertPage(child, beforePageNum, tabLabel);
18
+ }
19
+ else {
20
+ this.widget.appendPage(child, tabLabel);
21
+ }
22
+ }
23
+ removePage(child) {
24
+ const pageNum = this.widget.pageNum(child);
25
+ if (pageNum >= 0) {
26
+ this.widget.removePage(pageNum);
27
+ }
28
+ }
29
+ updatePageLabel(child, label) {
30
+ const tabLabel = new Gtk.Label();
31
+ tabLabel.setLabel(label);
32
+ this.widget.setTabLabel(child, tabLabel);
33
+ }
34
+ }
35
+ export class NotebookPageNode extends Node {
36
+ static matches(type) {
37
+ return type === "Notebook.Page";
38
+ }
39
+ isVirtual() {
40
+ return true;
41
+ }
42
+ label;
43
+ childWidget = null;
44
+ parentNotebook = null;
45
+ constructor(type, props, app) {
46
+ super(type, props, app);
47
+ this.label = props.label ?? "";
48
+ }
49
+ getLabel() {
50
+ return this.label;
51
+ }
52
+ setChildWidget(widget) {
53
+ this.childWidget = widget;
54
+ }
55
+ getChildWidget() {
56
+ return this.childWidget;
57
+ }
58
+ appendChild(child) {
59
+ const childWidget = child.getWidget();
60
+ if (childWidget) {
61
+ this.childWidget = childWidget;
62
+ }
63
+ }
64
+ attachToParent(parent) {
65
+ if (parent instanceof NotebookNode && this.childWidget) {
66
+ this.parentNotebook = parent;
67
+ parent.addPage(this.childWidget, this.label);
68
+ }
69
+ }
70
+ attachToParentBefore(parent, before) {
71
+ if (parent instanceof NotebookNode && this.childWidget) {
72
+ this.parentNotebook = parent;
73
+ const beforePage = before instanceof NotebookPageNode ? before.getChildWidget() : before.getWidget();
74
+ if (beforePage) {
75
+ parent.insertPageBefore(this.childWidget, this.label, beforePage);
76
+ }
77
+ else {
78
+ parent.addPage(this.childWidget, this.label);
79
+ }
80
+ }
81
+ }
82
+ detachFromParent(parent) {
83
+ if (parent instanceof NotebookNode && this.childWidget) {
84
+ parent.removePage(this.childWidget);
85
+ this.parentNotebook = null;
86
+ }
87
+ }
88
+ consumedProps() {
89
+ const consumed = super.consumedProps();
90
+ consumed.add("label");
91
+ return consumed;
92
+ }
93
+ updateProps(oldProps, newProps) {
94
+ if (oldProps.label !== newProps.label) {
95
+ this.label = newProps.label ?? "";
96
+ if (this.parentNotebook && this.childWidget) {
97
+ this.parentNotebook.updatePageLabel(this.childWidget, this.label);
98
+ }
99
+ }
100
+ super.updateProps(oldProps, newProps);
101
+ }
102
+ }
@@ -0,0 +1,9 @@
1
+ import type * as Gtk from "@gtkx/ffi/gtk";
2
+ import type { Props } from "../factory.js";
3
+ import { Node } from "../node.js";
4
+ export declare const ROOT_NODE_CONTAINER: unique symbol;
5
+ export declare class RootNode extends Node<never> {
6
+ static matches(_type: string, _props: Props, existingWidget?: Gtk.Widget | typeof ROOT_NODE_CONTAINER): boolean;
7
+ protected isVirtual(): boolean;
8
+ constructor(app: Gtk.Application);
9
+ }
@@ -0,0 +1,13 @@
1
+ import { Node } from "../node.js";
2
+ export const ROOT_NODE_CONTAINER = Symbol.for("ROOT_NODE_CONTAINER");
3
+ export class RootNode extends Node {
4
+ static matches(_type, _props, existingWidget) {
5
+ return existingWidget === ROOT_NODE_CONTAINER;
6
+ }
7
+ isVirtual() {
8
+ return true;
9
+ }
10
+ constructor(app) {
11
+ super("", {}, app);
12
+ }
13
+ }
@@ -9,5 +9,4 @@ export declare class WidgetNode extends Node<Gtk.Widget> {
9
9
  protected consumedProps(): Set<string>;
10
10
  updateProps(oldProps: Props, newProps: Props): void;
11
11
  mount(_app: Gtk.Application): void;
12
- dispose(_app: Gtk.Application): void;
13
12
  }
@@ -1,6 +1,12 @@
1
+ import { getObjectId } from "@gtkx/ffi";
2
+ import * as GObject from "@gtkx/ffi/gobject";
1
3
  import * as Gtk from "@gtkx/ffi/gtk";
2
4
  import { Node } from "../node.js";
3
5
  import { OverlayNode } from "./overlay.js";
6
+ const isFlowBox = (widget) => widget instanceof Gtk.FlowBox;
7
+ const isFlowBoxChild = (widget) => GObject.typeNameFromInstance(getObjectId(widget.ptr)) === "GtkFlowBoxChild";
8
+ const isListBox = (widget) => widget instanceof Gtk.ListBox;
9
+ const isListBoxRow = (widget) => GObject.typeNameFromInstance(getObjectId(widget.ptr)) === "GtkListBoxRow";
4
10
  const COMBINED_PROPS = [
5
11
  {
6
12
  props: ["defaultWidth", "defaultHeight"],
@@ -36,6 +42,14 @@ export class WidgetNode extends Node {
36
42
  parentWidget.appendPage(this.widget);
37
43
  return;
38
44
  }
45
+ if (isFlowBox(parentWidget)) {
46
+ parentWidget.append(this.widget);
47
+ return;
48
+ }
49
+ if (isListBox(parentWidget)) {
50
+ parentWidget.append(this.widget);
51
+ return;
52
+ }
39
53
  super.attachToParent(parent);
40
54
  }
41
55
  attachToParentBefore(parent, before) {
@@ -70,9 +84,37 @@ export class WidgetNode extends Node {
70
84
  }
71
85
  return;
72
86
  }
87
+ if (isFlowBox(parentWidget)) {
88
+ if (beforeWidget) {
89
+ const beforeChild = beforeWidget.getParent();
90
+ if (beforeChild && isFlowBoxChild(beforeChild)) {
91
+ parentWidget.insert(this.widget, beforeChild.getIndex());
92
+ }
93
+ else {
94
+ parentWidget.append(this.widget);
95
+ }
96
+ }
97
+ else {
98
+ parentWidget.append(this.widget);
99
+ }
100
+ return;
101
+ }
102
+ if (isListBox(parentWidget)) {
103
+ if (beforeWidget && isListBoxRow(beforeWidget)) {
104
+ parentWidget.insert(this.widget, beforeWidget.getIndex());
105
+ }
106
+ else {
107
+ parentWidget.append(this.widget);
108
+ }
109
+ return;
110
+ }
73
111
  super.attachToParentBefore(parent, before);
74
112
  }
75
113
  detachFromParent(parent) {
114
+ if (this.widget instanceof Gtk.Window) {
115
+ this.widget.destroy();
116
+ return;
117
+ }
76
118
  if (this.widget instanceof Gtk.AboutDialog) {
77
119
  return;
78
120
  }
@@ -94,6 +136,17 @@ export class WidgetNode extends Node {
94
136
  }
95
137
  return;
96
138
  }
139
+ if (isFlowBox(parentWidget)) {
140
+ const flowBoxChild = this.widget.getParent();
141
+ if (flowBoxChild) {
142
+ parentWidget.remove(flowBoxChild);
143
+ }
144
+ return;
145
+ }
146
+ if (isListBox(parentWidget)) {
147
+ parentWidget.remove(this.widget);
148
+ return;
149
+ }
97
150
  super.detachFromParent(parent);
98
151
  }
99
152
  consumedProps() {
@@ -123,9 +176,4 @@ export class WidgetNode extends Node {
123
176
  this.widget.present();
124
177
  }
125
178
  }
126
- dispose(_app) {
127
- if (this.widget instanceof Gtk.Window) {
128
- this.widget.destroy();
129
- }
130
- }
131
179
  }
package/dist/portal.js CHANGED
@@ -1,10 +1,10 @@
1
- import * as Gtk from "@gtkx/ffi/gtk";
1
+ import { ROOT_NODE_CONTAINER } from "./factory.js";
2
2
  export const createPortal = (children, container, key) => {
3
3
  return {
4
4
  $$typeof: Symbol.for("react.portal"),
5
5
  key: key ?? null,
6
6
  children,
7
- containerInfo: container ?? Gtk.Application.getDefault(),
7
+ containerInfo: container ?? ROOT_NODE_CONTAINER,
8
8
  implementation: null,
9
9
  };
10
10
  };
@@ -1,7 +1,8 @@
1
- import * as Gtk from "@gtkx/ffi/gtk";
1
+ import type * as Gtk from "@gtkx/ffi/gtk";
2
2
  import ReactReconciler from "react-reconciler";
3
+ import { type ROOT_NODE_CONTAINER } from "./factory.js";
3
4
  import type { Node } from "./node.js";
4
- type Container = Gtk.Application | Gtk.Widget;
5
+ type Container = Gtk.Widget | typeof ROOT_NODE_CONTAINER;
5
6
  type TextInstance = Node;
6
7
  type SuspenseInstance = never;
7
8
  type PublicInstance = Gtk.Widget;
@@ -1,5 +1,4 @@
1
1
  import { getCurrentApp } from "@gtkx/ffi";
2
- import * as Gtk from "@gtkx/ffi/gtk";
3
2
  import React from "react";
4
3
  import ReactReconciler from "react-reconciler";
5
4
  import { createNode } from "./factory.js";
@@ -71,9 +70,7 @@ class Reconciler {
71
70
  afterActiveInstanceBlur: () => { },
72
71
  prepareScopeUpdate: () => { },
73
72
  getInstanceFromScope: () => null,
74
- detachDeletedInstance: (instance) => {
75
- instance.dispose(getCurrentApp());
76
- },
73
+ detachDeletedInstance: () => { },
77
74
  resetFormInstance: () => { },
78
75
  requestPostPaintCallback: () => { },
79
76
  shouldAttemptEagerTransition: () => false,
@@ -92,10 +89,7 @@ class Reconciler {
92
89
  return context;
93
90
  }
94
91
  createNodeFromContainer(container) {
95
- if (container instanceof Gtk.Widget) {
96
- return createNode(container.constructor.name, {}, getCurrentApp(), container);
97
- }
98
- return createNode("Application", {}, getCurrentApp(), container);
92
+ return createNode(container.constructor.name, {}, getCurrentApp(), container);
99
93
  }
100
94
  }
101
95
  export const reconciler = new Reconciler();
package/dist/render.js CHANGED
@@ -1,10 +1,11 @@
1
1
  import { start } from "@gtkx/ffi";
2
+ import { ROOT_NODE_CONTAINER } from "./factory.js";
2
3
  import { reconciler } from "./reconciler.js";
3
4
  export let container = null;
4
5
  export const render = (element, appId, flags) => {
5
- const app = start(appId, flags);
6
+ start(appId, flags);
6
7
  const instance = reconciler.getInstance();
7
- container = instance.createContainer(app, 0, null, false, null, "", (error, info) => {
8
+ container = instance.createContainer(ROOT_NODE_CONTAINER, 0, null, false, null, "", (error, info) => {
8
9
  console.error("Uncaught error in GTKX application:", error, info);
9
10
  }, (_error, _info) => { }, (_error, _info) => { }, () => { }, null);
10
11
  instance.updateContainer(element, container, null, () => { });
package/dist/types.d.ts CHANGED
@@ -1,9 +1,10 @@
1
- import type { ReactNode } from "react";
1
+ import type * as Gtk from "@gtkx/ffi/gtk";
2
+ import type { ReactElement, ReactNode, RefCallback } from "react";
2
3
  export interface SlotProps {
3
4
  children?: ReactNode;
4
5
  }
5
- export interface ListItemProps {
6
- item: any;
6
+ export interface ListItemProps<I = unknown> {
7
+ item: I;
7
8
  }
8
9
  export interface GridChildProps extends SlotProps {
9
10
  column?: number;
@@ -11,3 +12,18 @@ export interface GridChildProps extends SlotProps {
11
12
  columnSpan?: number;
12
13
  rowSpan?: number;
13
14
  }
15
+ export type RenderItemFn<T> = (item: T | null, ref: RefCallback<Gtk.Widget>) => ReactElement;
16
+ export interface ListViewRenderProps<T = unknown> {
17
+ renderItem: RenderItemFn<T>;
18
+ }
19
+ export type RenderCellFn<T> = (item: T | null, ref: RefCallback<Gtk.Widget>) => ReactElement;
20
+ export interface ColumnViewColumnProps {
21
+ title?: string;
22
+ expand?: boolean;
23
+ resizable?: boolean;
24
+ fixedWidth?: number;
25
+ renderCell: (item: any, ref: RefCallback<Gtk.Widget>) => ReactElement;
26
+ }
27
+ export interface NotebookPageProps extends SlotProps {
28
+ label: string;
29
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gtkx/react",
3
- "version": "0.1.35",
3
+ "version": "0.1.36",
4
4
  "description": "Build GTK4 desktop applications with React and TypeScript",
5
5
  "keywords": [
6
6
  "gtk",
@@ -36,10 +36,10 @@
36
36
  ],
37
37
  "dependencies": {
38
38
  "react-reconciler": "0.33.0",
39
- "@gtkx/ffi": "0.1.35"
39
+ "@gtkx/ffi": "0.1.36"
40
40
  },
41
41
  "devDependencies": {
42
- "@gtkx/gir": "0.1.35"
42
+ "@gtkx/gir": "0.1.36"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "react": "^19"