@gtkx/react 0.10.4 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/README.md +103 -0
  2. package/dist/factory.js +1 -0
  3. package/dist/fiber-root.js +1 -1
  4. package/dist/generated/internal.d.ts +27 -1
  5. package/dist/generated/internal.js +920 -9714
  6. package/dist/generated/jsx.d.ts +8029 -17908
  7. package/dist/generated/jsx.js +70 -9013
  8. package/dist/generated/registry.d.ts +0 -1
  9. package/dist/node.d.ts +1 -1
  10. package/dist/nodes/action-row-child.js +3 -2
  11. package/dist/nodes/action-row.js +3 -7
  12. package/dist/nodes/application.js +1 -1
  13. package/dist/nodes/autowrapped.js +7 -5
  14. package/dist/nodes/column-view-column.js +1 -1
  15. package/dist/nodes/column-view.js +4 -3
  16. package/dist/nodes/fixed-child.js +3 -3
  17. package/dist/nodes/grid-child.js +4 -4
  18. package/dist/nodes/internal/constants.d.ts +1 -0
  19. package/dist/nodes/internal/constants.js +10 -0
  20. package/dist/nodes/internal/list-item-renderer.d.ts +1 -1
  21. package/dist/nodes/internal/list-item-renderer.js +4 -2
  22. package/dist/nodes/internal/predicates.d.ts +18 -9
  23. package/dist/nodes/internal/signal-store.d.ts +1 -1
  24. package/dist/nodes/internal/simple-list-store.d.ts +2 -2
  25. package/dist/nodes/internal/simple-list-store.js +2 -2
  26. package/dist/nodes/internal/tree-list-item-renderer.d.ts +1 -1
  27. package/dist/nodes/internal/tree-list-item-renderer.js +7 -3
  28. package/dist/nodes/internal/tree-store.d.ts +1 -1
  29. package/dist/nodes/internal/tree-store.js +1 -1
  30. package/dist/nodes/internal/utils.d.ts +7 -1
  31. package/dist/nodes/internal/utils.js +33 -6
  32. package/dist/nodes/list-item.d.ts +1 -1
  33. package/dist/nodes/list-view.js +3 -3
  34. package/dist/nodes/models/list.js +3 -3
  35. package/dist/nodes/models/menu.js +2 -2
  36. package/dist/nodes/models/tree-list.js +11 -10
  37. package/dist/nodes/notebook-page-tab.d.ts +1 -1
  38. package/dist/nodes/notebook-page.d.ts +3 -3
  39. package/dist/nodes/notebook-page.js +2 -2
  40. package/dist/nodes/notebook.js +4 -4
  41. package/dist/nodes/overlay-child.js +2 -1
  42. package/dist/nodes/pack-child.js +3 -2
  43. package/dist/nodes/pack.js +3 -7
  44. package/dist/nodes/popover-menu.js +3 -4
  45. package/dist/nodes/simple-list-view.js +6 -7
  46. package/dist/nodes/slot.d.ts +1 -1
  47. package/dist/nodes/slot.js +9 -7
  48. package/dist/nodes/stack-page.js +2 -1
  49. package/dist/nodes/stack.js +3 -4
  50. package/dist/nodes/toolbar-child.js +2 -1
  51. package/dist/nodes/tree-list-item.d.ts +3 -3
  52. package/dist/nodes/tree-list-item.js +3 -3
  53. package/dist/nodes/widget.d.ts +10 -2
  54. package/dist/nodes/widget.js +112 -111
  55. package/dist/nodes/window.js +1 -1
  56. package/dist/render.js +1 -1
  57. package/package.json +5 -7
@@ -1,4 +1,3 @@
1
- /** Generated namespace registry for widget class resolution. */
2
1
  type Namespace = Record<string, unknown>;
3
2
  export declare const NAMESPACE_REGISTRY: [string, Namespace][];
4
3
  export {};
package/dist/node.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { Container, ContainerClass, Props } from "./types.js";
2
2
  export declare class Node<T = unknown, P = Props> {
3
3
  static priority: number;
4
- static matches(_type: string, _containerOrClass?: Container | ContainerClass): boolean;
4
+ static matches(_type: string, _containerOrClass?: Container | ContainerClass | null): boolean;
5
5
  static createContainer(_props: Props, _containerClass: ContainerClass, _rootContainer?: Container): unknown;
6
6
  container: T;
7
7
  typeName: string;
@@ -1,3 +1,4 @@
1
+ import { isObjectEqual } from "@gtkx/ffi";
1
2
  import { registerNodeClass } from "../registry.js";
2
3
  import { scheduleAfterCommit } from "../scheduler.js";
3
4
  import { VirtualNode } from "./virtual.js";
@@ -48,7 +49,7 @@ export class ActionRowChild extends VirtualNode {
48
49
  scheduleAfterCommit(() => {
49
50
  if (parent) {
50
51
  const currentParent = widget.getParent();
51
- if (currentParent?.equals(parent)) {
52
+ if (currentParent && isObjectEqual(currentParent, parent)) {
52
53
  parent.remove(widget);
53
54
  }
54
55
  }
@@ -61,7 +62,7 @@ export class ActionRowChild extends VirtualNode {
61
62
  scheduleAfterCommit(() => {
62
63
  for (const widget of childrenToRemove) {
63
64
  const currentParent = widget.getParent();
64
- if (currentParent?.equals(parent)) {
65
+ if (currentParent && isObjectEqual(currentParent, parent)) {
65
66
  parent.remove(widget);
66
67
  }
67
68
  }
@@ -1,16 +1,12 @@
1
- import * as Gtk from "@gtkx/ffi/gtk";
1
+ import { PREFIX_SUFFIX_INTERFACE_METHODS } from "../generated/internal.js";
2
2
  import { registerNodeClass } from "../registry.js";
3
3
  import { ActionRowChild } from "./action-row-child.js";
4
+ import { matchesInterface } from "./internal/utils.js";
4
5
  import { WidgetNode } from "./widget.js";
5
6
  class ActionRowNode extends WidgetNode {
6
7
  static priority = 0;
7
8
  static matches(_type, containerOrClass) {
8
- if (!containerOrClass ||
9
- (typeof containerOrClass !== "function" && !(containerOrClass instanceof Gtk.Widget))) {
10
- return false;
11
- }
12
- const protoOrInstance = typeof containerOrClass === "function" ? containerOrClass.prototype : containerOrClass;
13
- return "addPrefix" in protoOrInstance && "addSuffix" in protoOrInstance && "remove" in protoOrInstance;
9
+ return matchesInterface(PREFIX_SUFFIX_INTERFACE_METHODS, containerOrClass);
14
10
  }
15
11
  appendChild(child) {
16
12
  if (child instanceof ActionRowChild) {
@@ -30,7 +30,7 @@ class ApplicationNode extends Node {
30
30
  if (child instanceof MenuNode) {
31
31
  this.menu.removeChild(child);
32
32
  if (this.menu.getMenu().getNItems() === 0) {
33
- this.container.setMenubar(undefined);
33
+ this.container.setMenubar(null);
34
34
  }
35
35
  }
36
36
  }
@@ -1,8 +1,9 @@
1
- import { batch } from "@gtkx/ffi";
1
+ import { batch, isObjectEqual } from "@gtkx/ffi";
2
2
  import * as Gtk from "@gtkx/ffi/gtk";
3
+ import { AUTOWRAP_CLASSES } from "../generated/internal.js";
3
4
  import { registerNodeClass } from "../registry.js";
4
5
  import { isRemovable, isSingleChild } from "./internal/predicates.js";
5
- import { isContainerType } from "./internal/utils.js";
6
+ import { matchesAnyClass } from "./internal/utils.js";
6
7
  import { WidgetNode } from "./widget.js";
7
8
  const isAutowrappedChild = (obj) => {
8
9
  return obj instanceof Gtk.ListBoxRow || obj instanceof Gtk.FlowBoxChild;
@@ -10,7 +11,7 @@ const isAutowrappedChild = (obj) => {
10
11
  class AutowrappedNode extends WidgetNode {
11
12
  static priority = 2;
12
13
  static matches(_type, containerOrClass) {
13
- return isContainerType(Gtk.ListBox, containerOrClass) || isContainerType(Gtk.FlowBox, containerOrClass);
14
+ return matchesAnyClass(AUTOWRAP_CLASSES, containerOrClass);
14
15
  }
15
16
  appendChild(child) {
16
17
  if (!(child instanceof WidgetNode)) {
@@ -68,7 +69,7 @@ class AutowrappedNode extends WidgetNode {
68
69
  this.removeExistingWrapper(child.container);
69
70
  }
70
71
  const position = this.findChildPosition(before);
71
- if (position !== undefined) {
72
+ if (position !== null) {
72
73
  this.container.insert(child.container, position);
73
74
  }
74
75
  else {
@@ -92,12 +93,13 @@ class AutowrappedNode extends WidgetNode {
92
93
  const beforeIsWrapper = isAutowrappedChild(before.container);
93
94
  while (currentChild) {
94
95
  const widgetToCompare = beforeIsWrapper ? currentChild : this.unwrapChild(currentChild);
95
- if (widgetToCompare?.equals(before.container)) {
96
+ if (widgetToCompare && isObjectEqual(widgetToCompare, before.container)) {
96
97
  return position;
97
98
  }
98
99
  position++;
99
100
  currentChild = currentChild.getNextSibling();
100
101
  }
102
+ return null;
101
103
  }
102
104
  unwrapChild(child) {
103
105
  if ("getChild" in child && typeof child.getChild === "function") {
@@ -46,7 +46,7 @@ export class ColumnViewColumnNode extends VirtualNode {
46
46
  this.column.setSorter(new Gtk.StringSorter());
47
47
  }
48
48
  else {
49
- this.column.setSorter(undefined);
49
+ this.column.setSorter(null);
50
50
  }
51
51
  }
52
52
  }
@@ -1,8 +1,9 @@
1
1
  import * as Gtk from "@gtkx/ffi/gtk";
2
+ import { COLUMN_VIEW_CLASSES } from "../generated/internal.js";
2
3
  import { registerNodeClass } from "../registry.js";
3
4
  import { ColumnViewColumnNode } from "./column-view-column.js";
4
5
  import { signalStore } from "./internal/signal-store.js";
5
- import { filterProps, isContainerType } from "./internal/utils.js";
6
+ import { filterProps, matchesAnyClass } from "./internal/utils.js";
6
7
  import { ListItemNode } from "./list-item.js";
7
8
  import { List } from "./models/list.js";
8
9
  import { WidgetNode } from "./widget.js";
@@ -12,7 +13,7 @@ class ColumnViewNode extends WidgetNode {
12
13
  handleSortChange;
13
14
  list;
14
15
  static matches(_type, containerOrClass) {
15
- return isContainerType(Gtk.ColumnView, containerOrClass);
16
+ return matchesAnyClass(COLUMN_VIEW_CLASSES, containerOrClass);
16
17
  }
17
18
  constructor(typeName, props, container, rootContainer) {
18
19
  super(typeName, props, container, rootContainer);
@@ -87,7 +88,7 @@ class ColumnViewNode extends WidgetNode {
87
88
  const sortColumn = newProps.sortColumn;
88
89
  const sortOrder = newProps.sortOrder ?? Gtk.SortType.ASCENDING;
89
90
  if (!sortColumn) {
90
- this.container.sortByColumn(sortOrder);
91
+ this.container.sortByColumn(sortOrder, undefined);
91
92
  }
92
93
  else {
93
94
  this.container.sortByColumn(sortOrder, this.getColumn(sortColumn));
@@ -1,4 +1,4 @@
1
- import { batch } from "@gtkx/ffi";
1
+ import { batch, isObjectEqual } from "@gtkx/ffi";
2
2
  import { registerNodeClass } from "../registry.js";
3
3
  import { SlotNode } from "./slot.js";
4
4
  class FixedChildNode extends SlotNode {
@@ -28,7 +28,7 @@ class FixedChildNode extends SlotNode {
28
28
  const child = this.child;
29
29
  batch(() => {
30
30
  const currentParent = child.getParent();
31
- if (currentParent?.equals(fixed)) {
31
+ if (currentParent && isObjectEqual(currentParent, fixed)) {
32
32
  fixed.remove(child);
33
33
  }
34
34
  fixed.put(child, x, y);
@@ -39,7 +39,7 @@ class FixedChildNode extends SlotNode {
39
39
  const fixed = this.getFixed();
40
40
  if (oldChild) {
41
41
  const parent = oldChild.getParent();
42
- if (parent?.equals(fixed)) {
42
+ if (parent && isObjectEqual(parent, fixed)) {
43
43
  fixed.remove(oldChild);
44
44
  }
45
45
  }
@@ -1,4 +1,4 @@
1
- import { batch } from "@gtkx/ffi";
1
+ import { batch, isObjectEqual } from "@gtkx/ffi";
2
2
  import { registerNodeClass } from "../registry.js";
3
3
  import { SlotNode } from "./slot.js";
4
4
  class GridChildNode extends SlotNode {
@@ -32,12 +32,12 @@ class GridChildNode extends SlotNode {
32
32
  const rowSpan = this.props.rowSpan ?? 1;
33
33
  batch(() => {
34
34
  const existingChild = grid.getChildAt(column, row);
35
- if (existingChild && !existingChild.equals(this.child)) {
35
+ if (existingChild && this.child && !isObjectEqual(existingChild, this.child)) {
36
36
  grid.remove(existingChild);
37
37
  }
38
38
  if (this.child) {
39
39
  const currentParent = this.child.getParent();
40
- if (currentParent?.equals(grid)) {
40
+ if (currentParent && isObjectEqual(currentParent, grid)) {
41
41
  grid.remove(this.child);
42
42
  }
43
43
  grid.attach(this.child, column, row, columnSpan, rowSpan);
@@ -48,7 +48,7 @@ class GridChildNode extends SlotNode {
48
48
  const grid = this.getGrid();
49
49
  if (oldChild) {
50
50
  const parent = oldChild.getParent();
51
- if (parent?.equals(grid)) {
51
+ if (parent && isObjectEqual(parent, grid)) {
52
52
  grid.remove(oldChild);
53
53
  }
54
54
  }
@@ -0,0 +1 @@
1
+ export declare const EVENT_CONTROLLER_PROPS: Set<string>;
@@ -0,0 +1,10 @@
1
+ export const EVENT_CONTROLLER_PROPS = new Set([
2
+ "onEnter",
3
+ "onLeave",
4
+ "onMotion",
5
+ "onPressed",
6
+ "onReleased",
7
+ "onKeyPressed",
8
+ "onKeyReleased",
9
+ "onScroll",
10
+ ]);
@@ -10,7 +10,7 @@ export declare class ListItemRenderer {
10
10
  constructor();
11
11
  getFactory(): Gtk.SignalListItemFactory;
12
12
  setRenderFn(renderFn?: RenderItemFn<unknown>): void;
13
- setStore(store?: ListStore): void;
13
+ setStore(store?: ListStore | null): void;
14
14
  private getStore;
15
15
  private initialize;
16
16
  }
@@ -42,8 +42,10 @@ export class ListItemRenderer {
42
42
  const fiberRoot = this.fiberRoots.get(ptr);
43
43
  if (!fiberRoot)
44
44
  return;
45
- const id = listItem.getItem();
46
- const item = this.getStore().getItem(id.getString());
45
+ const stringObject = listItem.getItem();
46
+ if (!(stringObject instanceof Gtk.StringObject))
47
+ return;
48
+ const item = this.getStore().getItem(stringObject.getString());
47
49
  const element = this.renderFn?.(item);
48
50
  reconciler.getInstance().updateContainer(element, fiberRoot, null, () => { });
49
51
  });
@@ -1,29 +1,38 @@
1
1
  import * as Gtk from "@gtkx/ffi/gtk";
2
- export declare const isAppendable: (obj: unknown) => obj is Gtk.Widget & {
2
+ type AppendableWidget = Gtk.Widget & {
3
3
  append: (child: Gtk.Widget) => void;
4
4
  };
5
- export declare const isAddable: (obj: unknown) => obj is Gtk.Widget & {
5
+ type AddableWidget = Gtk.Widget & {
6
6
  add: (child: Gtk.Widget) => void;
7
7
  };
8
- export declare const hasSingleContent: (obj: unknown) => obj is Gtk.Widget & {
9
- setContent: (content: Gtk.Widget | undefined) => void;
8
+ type ContentWidget = Gtk.Widget & {
9
+ setContent: (content?: Gtk.Widget | null) => void;
10
10
  };
11
- export declare const isSingleChild: (obj: unknown) => obj is Gtk.Widget & {
11
+ type SingleChildWidget = Gtk.Widget & {
12
12
  setChild: (child: Gtk.Widget | null) => void;
13
13
  };
14
- export declare const isRemovable: (obj: unknown) => obj is Gtk.Widget & {
14
+ type RemovableWidget = Gtk.Widget & {
15
15
  remove: (child: Gtk.Widget) => void;
16
16
  };
17
- export declare const isReorderable: (obj: unknown) => obj is Gtk.Widget & {
17
+ export type ReorderableWidget = Gtk.Widget & {
18
18
  reorderChildAfter: (child: Gtk.Widget, sibling?: Gtk.Widget) => void;
19
19
  insertChildAfter: (child: Gtk.Widget, sibling?: Gtk.Widget) => void;
20
20
  };
21
- export declare const isInsertable: (obj: unknown) => obj is Gtk.Widget & {
21
+ export type InsertableWidget = Gtk.Widget & {
22
22
  insert: (child: Gtk.Widget, position: number) => void;
23
23
  getFirstChild: () => Gtk.Widget | null;
24
24
  };
25
- export declare const isEditable: (obj: unknown) => obj is Gtk.Widget & {
25
+ type EditableWidget = Gtk.Widget & {
26
26
  getPosition: () => number;
27
27
  setPosition: (position: number) => void;
28
28
  getText: () => string;
29
29
  };
30
+ export declare const isAppendable: (obj: unknown) => obj is AppendableWidget;
31
+ export declare const isAddable: (obj: unknown) => obj is AddableWidget;
32
+ export declare const hasSingleContent: (obj: unknown) => obj is ContentWidget;
33
+ export declare const isSingleChild: (obj: unknown) => obj is SingleChildWidget;
34
+ export declare const isRemovable: (obj: unknown) => obj is RemovableWidget;
35
+ export declare const isReorderable: (obj: unknown) => obj is ReorderableWidget;
36
+ export declare const isInsertable: (obj: unknown) => obj is InsertableWidget;
37
+ export declare const isEditable: (obj: unknown) => obj is EditableWidget;
38
+ export {};
@@ -7,7 +7,7 @@ declare class SignalStore {
7
7
  private getOwnerMap;
8
8
  private disconnect;
9
9
  private connect;
10
- set(owner: SignalOwner, obj: GObject.GObject, signal: string, handler?: SignalHandler): void;
10
+ set(owner: SignalOwner, obj: GObject.GObject, signal: string, handler?: SignalHandler | null): void;
11
11
  clear(owner: SignalOwner): void;
12
12
  blockAll(): void;
13
13
  unblockAll(): void;
@@ -8,7 +8,7 @@ export declare class SimpleListStore {
8
8
  insertItemBefore(id: string, beforeId: string, label: string): void;
9
9
  updateItem(id: string, label: string): void;
10
10
  getItem(id: string): string | null;
11
- getIdAtIndex(index: number): string | undefined;
12
- getIndexById(id: string): number | undefined;
11
+ getIdAtIndex(index: number): string | null;
12
+ getIndexById(id: string): number | null;
13
13
  getModel(): Gtk.StringList;
14
14
  }
@@ -48,11 +48,11 @@ export class SimpleListStore {
48
48
  return this.model.getString(this.ids.indexOf(id));
49
49
  }
50
50
  getIdAtIndex(index) {
51
- return this.ids[index];
51
+ return this.ids[index] ?? null;
52
52
  }
53
53
  getIndexById(id) {
54
54
  const index = this.ids.indexOf(id);
55
- return index >= 0 ? index : undefined;
55
+ return index >= 0 ? index : null;
56
56
  }
57
57
  getModel() {
58
58
  return this.model;
@@ -10,7 +10,7 @@ export declare class TreeListItemRenderer {
10
10
  constructor();
11
11
  getFactory(): Gtk.SignalListItemFactory;
12
12
  setRenderFn(renderFn?: TreeRenderItemFn<unknown>): void;
13
- setStore(store?: TreeStore): void;
13
+ setStore(store?: TreeStore | null): void;
14
14
  private getStore;
15
15
  private initialize;
16
16
  }
@@ -45,12 +45,14 @@ export class TreeListItemRenderer {
45
45
  if (!fiberRoot)
46
46
  return;
47
47
  const treeListRow = listItem.getItem();
48
- if (!treeListRow)
48
+ if (!(treeListRow instanceof Gtk.TreeListRow))
49
49
  return;
50
50
  const expander = listItem.getChild();
51
+ if (!(expander instanceof Gtk.TreeExpander))
52
+ return;
51
53
  expander.setListRow(treeListRow);
52
54
  const stringObject = treeListRow.getItem();
53
- if (!stringObject)
55
+ if (!(stringObject instanceof Gtk.StringObject))
54
56
  return;
55
57
  const id = stringObject.getString();
56
58
  const itemData = this.getStore().getItem(id);
@@ -74,7 +76,9 @@ export class TreeListItemRenderer {
74
76
  if (!fiberRoot)
75
77
  return;
76
78
  const expander = listItem.getChild();
77
- expander.setListRow(undefined);
79
+ if (expander instanceof Gtk.TreeExpander) {
80
+ expander.setListRow(null);
81
+ }
78
82
  reconciler.getInstance().updateContainer(null, fiberRoot, null, () => { });
79
83
  });
80
84
  signalStore.set(this, this.factory, "teardown", (_self, listItem) => {
@@ -19,7 +19,7 @@ export declare class TreeStore {
19
19
  removeItem(id: string, parentId?: string): void;
20
20
  insertItemBefore(id: string, beforeId: string, data: TreeItemData, parentId?: string): void;
21
21
  updateItem(id: string, data: TreeItemData): void;
22
- getItem(id: string): TreeItemData | undefined;
22
+ getItem(id: string): TreeItemData | null;
23
23
  getRootModel(): Gtk.StringList;
24
24
  getChildrenModel(parentId: string): Gtk.StringList | null;
25
25
  hasChildren(parentId: string): boolean;
@@ -100,7 +100,7 @@ export class TreeStore {
100
100
  }
101
101
  }
102
102
  getItem(id) {
103
- return this.items.get(id);
103
+ return this.items.get(id) ?? null;
104
104
  }
105
105
  getRootModel() {
106
106
  return this.rootModel;
@@ -1,3 +1,9 @@
1
1
  import type { Container, ContainerClass, Props } from "../../types.js";
2
- export declare const isContainerType: (cls: new (...args: any[]) => Container, containerOrClass?: Container | ContainerClass) => boolean;
2
+ type AnyClass = new (...args: any[]) => any;
3
+ export declare const matchesAnyClass: (classes: readonly AnyClass[], containerOrClass?: Container | ContainerClass | null) => boolean;
4
+ export declare const isContainerType: (cls: AnyClass, containerOrClass?: Container | ContainerClass | null) => boolean;
5
+ export declare const matchesInterface: (methods: readonly string[], containerOrClass?: Container | ContainerClass | null) => boolean;
3
6
  export declare const filterProps: (props: Props, excludeKeys: string[]) => Props;
7
+ export declare const resolvePropMeta: (container: Container, key: string) => [string | null, string] | null;
8
+ export declare const resolveSignal: (container: Container, signalName: string) => boolean;
9
+ export {};
@@ -1,13 +1,19 @@
1
- export const isContainerType = (
2
- // biome-ignore lint/suspicious/noExplicitAny: Required for contravariant behavior
3
- cls, containerOrClass) => {
1
+ import { PROPS, SIGNALS } from "../../generated/internal.js";
2
+ export const matchesAnyClass = (classes, containerOrClass) => {
4
3
  if (!containerOrClass) {
5
4
  return false;
6
5
  }
7
- if (containerOrClass instanceof cls) {
8
- return true;
6
+ return classes.some((cls) => containerOrClass instanceof cls ||
7
+ containerOrClass === cls ||
8
+ Object.prototype.isPrototypeOf.call(cls, containerOrClass));
9
+ };
10
+ export const isContainerType = (cls, containerOrClass) => matchesAnyClass([cls], containerOrClass);
11
+ export const matchesInterface = (methods, containerOrClass) => {
12
+ if (!containerOrClass) {
13
+ return false;
9
14
  }
10
- return containerOrClass === cls || Object.prototype.isPrototypeOf.call(cls, containerOrClass);
15
+ const proto = typeof containerOrClass === "function" ? containerOrClass.prototype : containerOrClass;
16
+ return methods.every((method) => method in proto);
11
17
  };
12
18
  export const filterProps = (props, excludeKeys) => {
13
19
  const result = {};
@@ -18,3 +24,24 @@ export const filterProps = (props, excludeKeys) => {
18
24
  }
19
25
  return result;
20
26
  };
27
+ const walkPrototypeChain = (container, lookup) => {
28
+ // biome-ignore lint/complexity/noBannedTypes: Walking prototype chain requires Function type
29
+ let current = container.constructor;
30
+ while (current) {
31
+ const typeName = current.glibTypeName;
32
+ if (typeName) {
33
+ const result = lookup(typeName);
34
+ if (result !== null) {
35
+ return result;
36
+ }
37
+ }
38
+ const prototype = Object.getPrototypeOf(current.prototype);
39
+ current = prototype?.constructor ?? null;
40
+ if (current === Object || current === Function) {
41
+ break;
42
+ }
43
+ }
44
+ return null;
45
+ };
46
+ export const resolvePropMeta = (container, key) => walkPrototypeChain(container, (typeName) => PROPS[typeName]?.[key] ?? null);
47
+ export const resolveSignal = (container, signalName) => walkPrototypeChain(container, (typeName) => (SIGNALS[typeName]?.has(signalName) ? true : null)) ?? false;
@@ -6,7 +6,7 @@ export declare class ListItemNode<T extends Omit<ListStore, "items" | "model"> =
6
6
  static priority: number;
7
7
  private store?;
8
8
  static matches(type: string): boolean;
9
- setStore(store?: T): void;
9
+ setStore(store?: T | null): void;
10
10
  updateProps(oldProps: P | null, newProps: P): void;
11
11
  }
12
12
  export {};
@@ -1,7 +1,7 @@
1
- import * as Gtk from "@gtkx/ffi/gtk";
1
+ import { LIST_WIDGET_CLASSES } from "../generated/internal.js";
2
2
  import { registerNodeClass } from "../registry.js";
3
3
  import { ListItemRenderer } from "./internal/list-item-renderer.js";
4
- import { filterProps, isContainerType } from "./internal/utils.js";
4
+ import { filterProps, matchesAnyClass } from "./internal/utils.js";
5
5
  import { ListItemNode } from "./list-item.js";
6
6
  import { List } from "./models/list.js";
7
7
  import { WidgetNode } from "./widget.js";
@@ -11,7 +11,7 @@ class ListViewNode extends WidgetNode {
11
11
  itemRenderer;
12
12
  list;
13
13
  static matches(_type, containerOrClass) {
14
- return isContainerType(Gtk.ListView, containerOrClass) || isContainerType(Gtk.GridView, containerOrClass);
14
+ return matchesAnyClass(LIST_WIDGET_CLASSES, containerOrClass);
15
15
  }
16
16
  constructor(typeName, props, container, rootContainer) {
17
17
  super(typeName, props, container, rootContainer);
@@ -38,12 +38,12 @@ export class List extends VirtualNode {
38
38
  return;
39
39
  }
40
40
  this.store.removeItem(child.props.id);
41
- child.setStore(undefined);
41
+ child.setStore(null);
42
42
  }
43
43
  updateProps(oldProps, newProps) {
44
44
  super.updateProps(oldProps, newProps);
45
45
  if (!oldProps || oldProps.selectionMode !== newProps.selectionMode) {
46
- signalStore.set(this, this.selectionModel, "selection-changed", undefined);
46
+ signalStore.set(this, this.selectionModel, "selection-changed", null);
47
47
  this.selectionModel = this.createSelectionModel(newProps.selectionMode);
48
48
  }
49
49
  if (!oldProps ||
@@ -53,7 +53,7 @@ export class List extends VirtualNode {
53
53
  this.handleSelectionChange = () => {
54
54
  onSelectionChanged?.(this.getSelection());
55
55
  };
56
- signalStore.set(this, this.selectionModel, "selection-changed", newProps.onSelectionChanged ? this.handleSelectionChange : undefined);
56
+ signalStore.set(this, this.selectionModel, "selection-changed", newProps.onSelectionChanged ? this.handleSelectionChange : null);
57
57
  }
58
58
  if (!oldProps || oldProps.selected !== newProps.selected || oldProps.selectionMode !== newProps.selectionMode) {
59
59
  this.setSelection(newProps.selected);
@@ -1,4 +1,4 @@
1
- import { batch } from "@gtkx/ffi";
1
+ import { batch, isObjectEqual } from "@gtkx/ffi";
2
2
  import * as Gio from "@gtkx/ffi/gio";
3
3
  import { scheduleAfterCommit } from "../../scheduler.js";
4
4
  import { signalStore } from "../internal/signal-store.js";
@@ -100,7 +100,7 @@ export class Menu extends VirtualNode {
100
100
  }
101
101
  else {
102
102
  const link = parent.getItemLink(i, this.type);
103
- if (link?.equals(this.menu)) {
103
+ if (link && isObjectEqual(link, this.menu)) {
104
104
  return i;
105
105
  }
106
106
  }
@@ -16,8 +16,9 @@ export class TreeList extends VirtualNode {
16
16
  this.selectionModel.setModel(this.treeListModel);
17
17
  }
18
18
  createChildModel(item) {
19
- const stringObject = item;
20
- const parentId = stringObject.getString();
19
+ if (!(item instanceof Gtk.StringObject))
20
+ return null;
21
+ const parentId = item.getString();
21
22
  return this.store.getChildrenModel(parentId);
22
23
  }
23
24
  getStore() {
@@ -70,7 +71,7 @@ export class TreeList extends VirtualNode {
70
71
  throw new Error("Cannot remove 'TreeListItem' from 'TreeList': missing required 'id' prop");
71
72
  }
72
73
  this.store.removeItem(child.props.id);
73
- child.setStore(undefined);
74
+ child.setStore(null);
74
75
  }
75
76
  updateProps(oldProps, newProps) {
76
77
  super.updateProps(oldProps, newProps);
@@ -78,7 +79,7 @@ export class TreeList extends VirtualNode {
78
79
  this.treeListModel.setAutoexpand(newProps.autoexpand ?? false);
79
80
  }
80
81
  if (!oldProps || oldProps.selectionMode !== newProps.selectionMode) {
81
- signalStore.set(this, this.selectionModel, "selection-changed", undefined);
82
+ signalStore.set(this, this.selectionModel, "selection-changed", null);
82
83
  this.selectionModel = this.createSelectionModel(newProps.selectionMode);
83
84
  this.selectionModel.setModel(this.treeListModel);
84
85
  }
@@ -89,7 +90,7 @@ export class TreeList extends VirtualNode {
89
90
  this.handleSelectionChange = () => {
90
91
  onSelectionChanged?.(this.getSelection());
91
92
  };
92
- signalStore.set(this, this.selectionModel, "selection-changed", newProps.onSelectionChanged ? this.handleSelectionChange : undefined);
93
+ signalStore.set(this, this.selectionModel, "selection-changed", newProps.onSelectionChanged ? this.handleSelectionChange : null);
93
94
  }
94
95
  if (!oldProps || oldProps.selected !== newProps.selected || oldProps.selectionMode !== newProps.selectionMode) {
95
96
  this.setSelection(newProps.selected);
@@ -115,9 +116,9 @@ export class TreeList extends VirtualNode {
115
116
  const row = this.treeListModel.getRow(index);
116
117
  if (!row)
117
118
  continue;
118
- const stringObject = row.getItem();
119
- if (stringObject) {
120
- ids.push(stringObject.getString());
119
+ const item = row.getItem();
120
+ if (item instanceof Gtk.StringObject) {
121
+ ids.push(item.getString());
121
122
  }
122
123
  }
123
124
  return ids;
@@ -131,8 +132,8 @@ export class TreeList extends VirtualNode {
131
132
  const row = this.treeListModel.getRow(i);
132
133
  if (!row)
133
134
  continue;
134
- const stringObject = row.getItem();
135
- if (stringObject && ids.includes(stringObject.getString())) {
135
+ const item = row.getItem();
136
+ if (item instanceof Gtk.StringObject && ids.includes(item.getString())) {
136
137
  selected.add(i);
137
138
  }
138
139
  }
@@ -10,6 +10,6 @@ export declare class NotebookPageTabNode extends SlotNode<Props> {
10
10
  setPage(notebook?: Gtk.Notebook, page?: Gtk.Widget): void;
11
11
  private getNotebook;
12
12
  private getPage;
13
- protected onChildChange(_oldChild: Gtk.Widget | undefined): void;
13
+ protected onChildChange(_oldChild: Gtk.Widget | null): void;
14
14
  }
15
15
  export {};
@@ -5,11 +5,11 @@ import { SlotNode } from "./slot.js";
5
5
  type Props = Partial<NotebookPageProps>;
6
6
  export declare class NotebookPageNode extends SlotNode<Props> {
7
7
  static priority: number;
8
- position?: number;
8
+ position?: number | null;
9
9
  private tabNode?;
10
10
  static matches(type: string): boolean;
11
11
  setNotebook(notebook?: Gtk.Notebook): void;
12
- setPosition(position?: number): void;
12
+ setPosition(position?: number | null): void;
13
13
  private getNotebook;
14
14
  private updateTabNode;
15
15
  appendChild(child: Node): void;
@@ -18,6 +18,6 @@ export declare class NotebookPageNode extends SlotNode<Props> {
18
18
  updateProps(oldProps: Props | null, newProps: Props): void;
19
19
  private attachPage;
20
20
  private detachPage;
21
- protected onChildChange(oldChild: Gtk.Widget | undefined): void;
21
+ protected onChildChange(oldChild: Gtk.Widget | null): void;
22
22
  }
23
23
  export {};
@@ -44,7 +44,7 @@ export class NotebookPageNode extends SlotNode {
44
44
  this.child = child.container;
45
45
  scheduleAfterCommit(() => {
46
46
  if (this.parent) {
47
- this.onChildChange(oldChild);
47
+ this.onChildChange(oldChild ?? null);
48
48
  }
49
49
  this.updateTabNode();
50
50
  });
@@ -80,7 +80,7 @@ export class NotebookPageNode extends SlotNode {
80
80
  label.setLabel(this.props.label ?? "");
81
81
  tabLabel = label;
82
82
  }
83
- if (this.position !== undefined) {
83
+ if (this.position != null) {
84
84
  notebook.insertPage(child, this.position, tabLabel);
85
85
  return;
86
86
  }