@gtkx/react 0.6.1 → 0.8.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 (84) hide show
  1. package/dist/batch.d.ts +4 -1
  2. package/dist/batch.js +19 -10
  3. package/dist/codegen/jsx-generator.d.ts +4 -4
  4. package/dist/codegen/jsx-generator.js +24 -27
  5. package/dist/container-interfaces.d.ts +19 -6
  6. package/dist/container-interfaces.js +26 -6
  7. package/dist/errors.d.ts +8 -0
  8. package/dist/errors.js +38 -0
  9. package/dist/factory.js +9 -3
  10. package/dist/generated/jsx.d.ts +38 -26
  11. package/dist/generated/jsx.js +12 -2
  12. package/dist/index.js +3 -1
  13. package/dist/node.d.ts +5 -0
  14. package/dist/node.js +62 -6
  15. package/dist/nodes/action-bar.d.ts +2 -6
  16. package/dist/nodes/action-bar.js +3 -12
  17. package/dist/nodes/column-view.d.ts +19 -44
  18. package/dist/nodes/column-view.js +70 -243
  19. package/dist/nodes/combo-row.d.ts +5 -0
  20. package/dist/nodes/combo-row.js +6 -0
  21. package/dist/nodes/drop-down.d.ts +9 -0
  22. package/dist/nodes/drop-down.js +12 -0
  23. package/dist/nodes/flow-box.d.ts +4 -3
  24. package/dist/nodes/flow-box.js +26 -10
  25. package/dist/nodes/grid.d.ts +15 -15
  26. package/dist/nodes/grid.js +21 -64
  27. package/dist/nodes/header-bar.d.ts +34 -11
  28. package/dist/nodes/header-bar.js +55 -24
  29. package/dist/nodes/indexed-child-container.d.ts +16 -0
  30. package/dist/nodes/indexed-child-container.js +22 -0
  31. package/dist/nodes/list-box.d.ts +4 -3
  32. package/dist/nodes/list-box.js +33 -6
  33. package/dist/nodes/list-item-factory.d.ts +19 -0
  34. package/dist/nodes/list-item-factory.js +58 -0
  35. package/dist/nodes/list-view.d.ts +24 -0
  36. package/dist/nodes/list-view.js +46 -0
  37. package/dist/nodes/menu.d.ts +25 -19
  38. package/dist/nodes/menu.js +30 -59
  39. package/dist/nodes/notebook.d.ts +13 -14
  40. package/dist/nodes/notebook.js +18 -56
  41. package/dist/nodes/paged-stack.d.ts +39 -0
  42. package/dist/nodes/paged-stack.js +54 -0
  43. package/dist/nodes/selectable-list.d.ts +41 -0
  44. package/dist/nodes/selectable-list.js +228 -0
  45. package/dist/nodes/stack-page-props.d.ts +11 -0
  46. package/dist/nodes/stack-page-props.js +23 -0
  47. package/dist/nodes/stack.d.ts +14 -28
  48. package/dist/nodes/stack.js +30 -142
  49. package/dist/nodes/string-list-container.d.ts +41 -0
  50. package/dist/nodes/string-list-container.js +90 -0
  51. package/dist/nodes/string-list-item.d.ts +15 -0
  52. package/dist/nodes/string-list-item.js +48 -0
  53. package/dist/nodes/string-list-store.d.ts +13 -0
  54. package/dist/nodes/string-list-store.js +44 -0
  55. package/dist/nodes/text-view.d.ts +1 -1
  56. package/dist/nodes/text-view.js +1 -5
  57. package/dist/nodes/toggle-button.d.ts +1 -1
  58. package/dist/nodes/toggle-button.js +1 -3
  59. package/dist/nodes/view-stack.d.ts +9 -0
  60. package/dist/nodes/view-stack.js +28 -0
  61. package/dist/nodes/virtual-item.d.ts +20 -0
  62. package/dist/nodes/virtual-item.js +57 -0
  63. package/dist/nodes/virtual-slot.d.ts +25 -0
  64. package/dist/nodes/virtual-slot.js +71 -0
  65. package/dist/nodes/widget.d.ts +0 -3
  66. package/dist/nodes/widget.js +0 -28
  67. package/dist/nodes/window.d.ts +1 -1
  68. package/dist/nodes/window.js +9 -15
  69. package/dist/predicates.d.ts +8 -0
  70. package/dist/predicates.js +8 -0
  71. package/dist/props.d.ts +7 -5
  72. package/dist/props.js +11 -9
  73. package/dist/reconciler/host-config.d.ts +19 -0
  74. package/dist/reconciler/host-config.js +89 -0
  75. package/dist/reconciler.d.ts +2 -26
  76. package/dist/reconciler.js +15 -106
  77. package/dist/render.d.ts +3 -4
  78. package/dist/render.js +6 -4
  79. package/dist/types.d.ts +22 -19
  80. package/package.json +6 -5
  81. package/dist/nodes/dropdown.d.ts +0 -39
  82. package/dist/nodes/dropdown.js +0 -103
  83. package/dist/nodes/list.d.ts +0 -43
  84. package/dist/nodes/list.js +0 -153
@@ -1,6 +1,6 @@
1
1
  import { isGridContainer } from "../container-interfaces.js";
2
2
  import { Node } from "../node.js";
3
- import { getNumberProp } from "../props.js";
3
+ import { VirtualSlotNode } from "./virtual-slot.js";
4
4
  export class GridNode extends Node {
5
5
  static matches(type) {
6
6
  return type === "Grid.Root";
@@ -12,78 +12,35 @@ export class GridNode extends Node {
12
12
  this.widget.remove(child);
13
13
  }
14
14
  }
15
- export class GridChildNode extends Node {
15
+ export class GridChildNode extends VirtualSlotNode {
16
16
  static matches(type) {
17
17
  return type === "Grid.Child";
18
18
  }
19
- isVirtual() {
20
- return true;
19
+ isValidContainer(parent) {
20
+ return isGridContainer(parent);
21
21
  }
22
- column = 0;
23
- row = 0;
24
- columnSpan = 1;
25
- rowSpan = 1;
26
- childWidget = null;
27
- parentContainer = null;
28
- initialize(props) {
29
- this.column = getNumberProp(props, "column", 0);
30
- this.row = getNumberProp(props, "row", 0);
31
- this.columnSpan = getNumberProp(props, "columnSpan", 1);
32
- this.rowSpan = getNumberProp(props, "rowSpan", 1);
33
- super.initialize(props);
22
+ extractSlotProps(props) {
23
+ return {
24
+ column: props.column ?? 0,
25
+ row: props.row ?? 0,
26
+ columnSpan: props.columnSpan ?? 1,
27
+ rowSpan: props.rowSpan ?? 1,
28
+ };
34
29
  }
35
- appendChild(child) {
36
- const widget = child.getWidget();
37
- if (widget) {
38
- this.childWidget = widget;
39
- if (this.parentContainer) {
40
- this.attachChildToGrid();
41
- }
42
- }
30
+ addToContainer(container, child, props) {
31
+ container.attachToGrid(child, props.column, props.row, props.columnSpan, props.rowSpan);
43
32
  }
44
- removeChild(child) {
45
- const widget = child.getWidget();
46
- if (widget && this.childWidget === widget) {
47
- this.detachChildFromGrid();
48
- this.childWidget = null;
49
- }
33
+ insertBeforeInContainer(container, child, props, _before) {
34
+ this.addToContainer(container, child, props);
50
35
  }
51
- attachChildToGrid() {
52
- if (!this.parentContainer || !this.childWidget)
53
- return;
54
- this.parentContainer.attachToGrid(this.childWidget, this.column, this.row, this.columnSpan, this.rowSpan);
36
+ removeFromContainer(container, child) {
37
+ container.removeFromGrid(child);
55
38
  }
56
- detachChildFromGrid() {
57
- if (!this.parentContainer || !this.childWidget)
58
- return;
59
- this.parentContainer.removeFromGrid(this.childWidget);
60
- }
61
- attachToParent(parent) {
62
- if (isGridContainer(parent)) {
63
- this.parentContainer = parent;
64
- if (this.childWidget) {
65
- this.attachChildToGrid();
66
- }
67
- }
68
- }
69
- detachFromParent(parent) {
70
- if (isGridContainer(parent)) {
71
- this.detachChildFromGrid();
72
- this.parentContainer = null;
73
- }
39
+ updateInContainer(container, child, props) {
40
+ container.removeFromGrid(child);
41
+ container.attachToGrid(child, props.column, props.row, props.columnSpan, props.rowSpan);
74
42
  }
75
43
  updateProps(oldProps, newProps) {
76
- const positionChanged = oldProps.column !== newProps.column ||
77
- oldProps.row !== newProps.row ||
78
- oldProps.columnSpan !== newProps.columnSpan ||
79
- oldProps.rowSpan !== newProps.rowSpan;
80
- if (positionChanged) {
81
- this.detachChildFromGrid();
82
- this.column = getNumberProp(newProps, "column", 0);
83
- this.row = getNumberProp(newProps, "row", 0);
84
- this.columnSpan = getNumberProp(newProps, "columnSpan", 1);
85
- this.rowSpan = getNumberProp(newProps, "rowSpan", 1);
86
- this.attachChildToGrid();
87
- }
44
+ this.updateSlotPropsIfChanged(oldProps, newProps, ["column", "row", "columnSpan", "rowSpan"]);
88
45
  }
89
46
  }
@@ -1,19 +1,42 @@
1
1
  import type * as Adw from "@gtkx/ffi/adw";
2
2
  import type * as Gtk from "@gtkx/ffi/gtk";
3
+ import { type PackContainer } from "../container-interfaces.js";
4
+ import type { Props } from "../factory.js";
3
5
  import { Node } from "../node.js";
4
- /**
5
- * Node for AdwHeaderBar that uses packStart for non-slot children.
6
- */
7
- export declare class AdwHeaderBarNode extends Node<Adw.HeaderBar> {
8
- static matches(type: string): boolean;
6
+ import { VirtualSlotNode } from "./virtual-slot.js";
7
+ type HeaderBarWidget = Gtk.HeaderBar | Adw.HeaderBar | Gtk.ActionBar;
8
+ export declare class PackContainerNode<T extends HeaderBarWidget> extends Node<T> implements PackContainer {
9
+ packStart(child: Gtk.Widget): void;
10
+ packEnd(child: Gtk.Widget): void;
11
+ removeFromPack(child: Gtk.Widget): void;
9
12
  appendChild(child: Node): void;
10
13
  removeChild(child: Node): void;
11
14
  }
12
- /**
13
- * Node for Gtk.HeaderBar that uses packStart for children.
14
- */
15
- export declare class HeaderBarNode extends Node<Gtk.HeaderBar> {
15
+ export declare class AdwHeaderBarNode extends PackContainerNode<Adw.HeaderBar> {
16
+ static matches(type: string): boolean;
17
+ }
18
+ export declare class HeaderBarNode extends PackContainerNode<Gtk.HeaderBar> {
19
+ static matches(type: string): boolean;
20
+ }
21
+ type PackPosition = "start" | "end";
22
+ type PackSlotProps = {
23
+ position: PackPosition;
24
+ };
25
+ declare abstract class PackSlotNode extends VirtualSlotNode<PackContainer, PackSlotProps> {
26
+ protected abstract readonly position: PackPosition;
27
+ protected isValidContainer(parent: Node): parent is Node & PackContainer;
28
+ protected extractSlotProps(_props: Props): PackSlotProps;
29
+ protected addToContainer(container: PackContainer, child: Gtk.Widget, props: PackSlotProps): void;
30
+ protected insertBeforeInContainer(container: PackContainer, child: Gtk.Widget, props: PackSlotProps, _before: Gtk.Widget): void;
31
+ protected removeFromContainer(container: PackContainer, child: Gtk.Widget): void;
32
+ protected updateInContainer(): void;
33
+ }
34
+ export declare class PackStartNode extends PackSlotNode {
35
+ protected readonly position: PackPosition;
36
+ static matches(type: string): boolean;
37
+ }
38
+ export declare class PackEndNode extends PackSlotNode {
39
+ protected readonly position: PackPosition;
16
40
  static matches(type: string): boolean;
17
- appendChild(child: Node): void;
18
- removeChild(child: Node): void;
19
41
  }
42
+ export {};
@@ -1,10 +1,15 @@
1
+ import { isPackContainer } from "../container-interfaces.js";
1
2
  import { Node } from "../node.js";
2
- /**
3
- * Node for AdwHeaderBar that uses packStart for non-slot children.
4
- */
5
- export class AdwHeaderBarNode extends Node {
6
- static matches(type) {
7
- return type === "AdwHeaderBar" || type === "AdwHeaderBar.Root";
3
+ import { VirtualSlotNode } from "./virtual-slot.js";
4
+ export class PackContainerNode extends Node {
5
+ packStart(child) {
6
+ this.widget.packStart(child);
7
+ }
8
+ packEnd(child) {
9
+ this.widget.packEnd(child);
10
+ }
11
+ removeFromPack(child) {
12
+ this.widget.remove(child);
8
13
  }
9
14
  appendChild(child) {
10
15
  const childWidget = child.getWidget();
@@ -12,34 +17,60 @@ export class AdwHeaderBarNode extends Node {
12
17
  child.attachToParent(this);
13
18
  return;
14
19
  }
15
- this.widget.packStart(childWidget);
20
+ this.packStart(childWidget);
16
21
  }
17
22
  removeChild(child) {
18
23
  const childWidget = child.getWidget();
19
24
  if (childWidget) {
20
- this.widget.remove(childWidget);
25
+ this.removeFromPack(childWidget);
26
+ }
27
+ else {
28
+ child.detachFromParent(this);
21
29
  }
22
30
  }
23
31
  }
24
- /**
25
- * Node for Gtk.HeaderBar that uses packStart for children.
26
- */
27
- export class HeaderBarNode extends Node {
32
+ export class AdwHeaderBarNode extends PackContainerNode {
28
33
  static matches(type) {
29
- return type === "HeaderBar";
34
+ return type === "AdwHeaderBar" || type === "AdwHeaderBar.Root";
30
35
  }
31
- appendChild(child) {
32
- const childWidget = child.getWidget();
33
- if (!childWidget) {
34
- child.attachToParent(this);
35
- return;
36
- }
37
- this.widget.packStart(childWidget);
36
+ }
37
+ export class HeaderBarNode extends PackContainerNode {
38
+ static matches(type) {
39
+ return type === "HeaderBar" || type === "HeaderBar.Root";
38
40
  }
39
- removeChild(child) {
40
- const childWidget = child.getWidget();
41
- if (childWidget) {
42
- this.widget.remove(childWidget);
41
+ }
42
+ class PackSlotNode extends VirtualSlotNode {
43
+ isValidContainer(parent) {
44
+ return isPackContainer(parent);
45
+ }
46
+ extractSlotProps(_props) {
47
+ return { position: this.position };
48
+ }
49
+ addToContainer(container, child, props) {
50
+ if (props.position === "start") {
51
+ container.packStart(child);
52
+ }
53
+ else {
54
+ container.packEnd(child);
43
55
  }
44
56
  }
57
+ insertBeforeInContainer(container, child, props, _before) {
58
+ this.addToContainer(container, child, props);
59
+ }
60
+ removeFromContainer(container, child) {
61
+ container.removeFromPack(child);
62
+ }
63
+ updateInContainer() { }
64
+ }
65
+ export class PackStartNode extends PackSlotNode {
66
+ position = "start";
67
+ static matches(type) {
68
+ return type === "HeaderBar.Start" || type === "AdwHeaderBar.Start" || type === "ActionBar.Start";
69
+ }
70
+ }
71
+ export class PackEndNode extends PackSlotNode {
72
+ position = "end";
73
+ static matches(type) {
74
+ return type === "HeaderBar.End" || type === "AdwHeaderBar.End" || type === "ActionBar.End";
75
+ }
45
76
  }
@@ -0,0 +1,16 @@
1
+ import type * as Gtk from "@gtkx/ffi/gtk";
2
+ import type { ChildContainer } from "../container-interfaces.js";
3
+ import { Node } from "../node.js";
4
+ type IndexedWidget = Gtk.Widget & {
5
+ append(child: Gtk.Widget): void;
6
+ insert(child: Gtk.Widget, position: number): void;
7
+ remove(child: Gtk.Widget): void;
8
+ };
9
+ export declare abstract class IndexedChildContainerNode<T extends IndexedWidget> extends Node<T> implements ChildContainer {
10
+ protected abstract getInsertionIndex(before: Gtk.Widget): number;
11
+ protected getWidgetToRemove(child: Gtk.Widget): Gtk.Widget;
12
+ attachChild(child: Gtk.Widget): void;
13
+ insertChildBefore(child: Gtk.Widget, before: Gtk.Widget): void;
14
+ detachChild(child: Gtk.Widget): void;
15
+ }
16
+ export {};
@@ -0,0 +1,22 @@
1
+ import { Node } from "../node.js";
2
+ export class IndexedChildContainerNode extends Node {
3
+ getWidgetToRemove(child) {
4
+ return child;
5
+ }
6
+ attachChild(child) {
7
+ this.widget.append(child);
8
+ }
9
+ insertChildBefore(child, before) {
10
+ const index = this.getInsertionIndex(before);
11
+ if (index >= 0) {
12
+ this.widget.insert(child, index);
13
+ }
14
+ else {
15
+ this.widget.append(child);
16
+ }
17
+ }
18
+ detachChild(child) {
19
+ const toRemove = this.getWidgetToRemove(child);
20
+ this.widget.remove(toRemove);
21
+ }
22
+ }
@@ -1,8 +1,9 @@
1
1
  import type * as Gtk from "@gtkx/ffi/gtk";
2
- import type { ChildContainer } from "../container-interfaces.js";
3
- import { Node } from "../node.js";
4
- export declare class ListBoxNode extends Node<Gtk.ListBox> implements ChildContainer {
2
+ import { IndexedChildContainerNode } from "./indexed-child-container.js";
3
+ export declare class ListBoxNode extends IndexedChildContainerNode<Gtk.ListBox> {
5
4
  static matches(type: string): boolean;
5
+ protected getInsertionIndex(before: Gtk.Widget): number;
6
+ private unparentFromRow;
6
7
  attachChild(child: Gtk.Widget): void;
7
8
  insertChildBefore(child: Gtk.Widget, before: Gtk.Widget): void;
8
9
  detachChild(child: Gtk.Widget): void;
@@ -1,21 +1,48 @@
1
- import { Node } from "../node.js";
2
- const isListBoxRow = (widget) => "getIndex" in widget && "isSelected" in widget && typeof widget.getIndex === "function";
3
- export class ListBoxNode extends Node {
1
+ import { beginBatch, endBatch } from "@gtkx/ffi";
2
+ import { isListBoxRow } from "../predicates.js";
3
+ import { IndexedChildContainerNode } from "./indexed-child-container.js";
4
+ export class ListBoxNode extends IndexedChildContainerNode {
4
5
  static matches(type) {
5
6
  return type === "ListBox";
6
7
  }
8
+ getInsertionIndex(before) {
9
+ const beforeParent = before.getParent();
10
+ if (beforeParent && isListBoxRow(beforeParent)) {
11
+ return beforeParent.getIndex();
12
+ }
13
+ return -1;
14
+ }
15
+ unparentFromRow(child) {
16
+ const parent = child.getParent();
17
+ if (parent && isListBoxRow(parent)) {
18
+ beginBatch();
19
+ parent.setChild(null);
20
+ this.widget.remove(parent);
21
+ endBatch();
22
+ }
23
+ }
7
24
  attachChild(child) {
25
+ this.unparentFromRow(child);
8
26
  this.widget.append(child);
9
27
  }
10
28
  insertChildBefore(child, before) {
11
- if (isListBoxRow(before)) {
12
- this.widget.insert(child, before.getIndex());
29
+ this.unparentFromRow(child);
30
+ const index = this.getInsertionIndex(before);
31
+ if (index >= 0) {
32
+ this.widget.insert(child, index);
13
33
  }
14
34
  else {
15
35
  this.widget.append(child);
16
36
  }
17
37
  }
18
38
  detachChild(child) {
19
- this.widget.remove(child);
39
+ if (isListBoxRow(child)) {
40
+ beginBatch();
41
+ child.setChild(null);
42
+ this.widget.remove(child);
43
+ endBatch();
44
+ return;
45
+ }
46
+ this.unparentFromRow(child);
20
47
  }
21
48
  }
@@ -0,0 +1,19 @@
1
+ import * as Gtk from "@gtkx/ffi/gtk";
2
+ import type Reconciler from "react-reconciler";
3
+ import type { RenderItemFn } from "../types.js";
4
+ export type ListItemInfo = {
5
+ box: Gtk.Box;
6
+ fiberRoot: Reconciler.FiberRoot;
7
+ };
8
+ type ListItemFactoryConfig = {
9
+ factory: Gtk.SignalListItemFactory;
10
+ listItemCache: Map<number, ListItemInfo>;
11
+ getRenderFn: () => RenderItemFn<unknown>;
12
+ getItemAtPosition: (position: number) => unknown;
13
+ };
14
+ export type ListItemFactoryHandlers = {
15
+ handlerIds: number[];
16
+ disconnect: () => void;
17
+ };
18
+ export declare function connectListItemFactorySignals(config: ListItemFactoryConfig): ListItemFactoryHandlers;
19
+ export {};
@@ -0,0 +1,58 @@
1
+ import { getObject, getObjectId } from "@gtkx/ffi";
2
+ import * as GObject from "@gtkx/ffi/gobject";
3
+ import * as Gtk from "@gtkx/ffi/gtk";
4
+ import { createFiberRoot } from "../fiber-root.js";
5
+ import { reconciler } from "../reconciler.js";
6
+ export function connectListItemFactorySignals(config) {
7
+ const { factory, listItemCache, getRenderFn, getItemAtPosition } = config;
8
+ const handlerIds = [];
9
+ const setupId = factory.connect("setup", (_self, listItemObj) => {
10
+ const listItem = getObject(listItemObj.id);
11
+ const id = getObjectId(listItemObj.id);
12
+ const box = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
13
+ listItem.setChild(box);
14
+ const fiberRoot = createFiberRoot(box);
15
+ listItemCache.set(id, { box, fiberRoot });
16
+ const element = getRenderFn()(null);
17
+ reconciler.getInstance().updateContainer(element, fiberRoot, null, () => { });
18
+ });
19
+ handlerIds.push(setupId);
20
+ const bindId = factory.connect("bind", (_self, listItemObj) => {
21
+ const listItem = getObject(listItemObj.id);
22
+ const id = getObjectId(listItemObj.id);
23
+ const info = listItemCache.get(id);
24
+ if (!info)
25
+ return;
26
+ const position = listItem.getPosition();
27
+ const item = getItemAtPosition(position);
28
+ const element = getRenderFn()(item ?? null);
29
+ reconciler.getInstance().updateContainer(element, info.fiberRoot, null, () => { });
30
+ });
31
+ handlerIds.push(bindId);
32
+ const unbindId = factory.connect("unbind", (_self, listItemObj) => {
33
+ const id = getObjectId(listItemObj.id);
34
+ const info = listItemCache.get(id);
35
+ if (!info)
36
+ return;
37
+ reconciler.getInstance().updateContainer(null, info.fiberRoot, null, () => { });
38
+ });
39
+ handlerIds.push(unbindId);
40
+ const teardownId = factory.connect("teardown", (_self, listItemObj) => {
41
+ const id = getObjectId(listItemObj.id);
42
+ const info = listItemCache.get(id);
43
+ if (info) {
44
+ reconciler.getInstance().updateContainer(null, info.fiberRoot, null, () => { });
45
+ queueMicrotask(() => listItemCache.delete(id));
46
+ }
47
+ });
48
+ handlerIds.push(teardownId);
49
+ return {
50
+ handlerIds,
51
+ disconnect: () => {
52
+ for (const handlerId of handlerIds) {
53
+ GObject.signalHandlerDisconnect(factory, handlerId);
54
+ }
55
+ handlerIds.length = 0;
56
+ },
57
+ };
58
+ }
@@ -0,0 +1,24 @@
1
+ import * as Gtk from "@gtkx/ffi/gtk";
2
+ import type { Props } from "../factory.js";
3
+ import type { Node } from "../node.js";
4
+ import type { RenderItemFn } from "../types.js";
5
+ import { type ListItemFactoryHandlers, type ListItemInfo } from "./list-item-factory.js";
6
+ import { SelectableListNode, type SelectableListState } from "./selectable-list.js";
7
+ import { VirtualItemNode } from "./virtual-item.js";
8
+ type ListViewState = SelectableListState & {
9
+ factory: Gtk.SignalListItemFactory;
10
+ factoryHandlers: ListItemFactoryHandlers | null;
11
+ renderItem: RenderItemFn<unknown>;
12
+ listItemCache: Map<number, ListItemInfo>;
13
+ };
14
+ export declare class ListViewNode extends SelectableListNode<Gtk.ListView | Gtk.GridView, ListViewState> {
15
+ static consumedPropNames: string[];
16
+ static matches(type: string): boolean;
17
+ initialize(props: Props): void;
18
+ detachFromParent(parent: Node): void;
19
+ updateProps(oldProps: Props, newProps: Props): void;
20
+ }
21
+ export declare class ListItemNode extends VirtualItemNode {
22
+ static matches(type: string): boolean;
23
+ }
24
+ export {};
@@ -0,0 +1,46 @@
1
+ import * as Gtk from "@gtkx/ffi/gtk";
2
+ import { connectListItemFactorySignals } from "./list-item-factory.js";
3
+ import { SelectableListNode } from "./selectable-list.js";
4
+ import { VirtualItemNode } from "./virtual-item.js";
5
+ export class ListViewNode extends SelectableListNode {
6
+ static consumedPropNames = ["renderItem", "selected", "onSelectionChanged", "selectionMode"];
7
+ static matches(type) {
8
+ return type === "ListView.Root" || type === "GridView.Root";
9
+ }
10
+ initialize(props) {
11
+ const selectionState = this.initializeSelectionState(props);
12
+ this.state = {
13
+ ...selectionState,
14
+ factory: new Gtk.SignalListItemFactory(),
15
+ factoryHandlers: null,
16
+ renderItem: props.renderItem,
17
+ listItemCache: new Map(),
18
+ };
19
+ super.initialize(props);
20
+ this.state.factoryHandlers = connectListItemFactorySignals({
21
+ factory: this.state.factory,
22
+ listItemCache: this.state.listItemCache,
23
+ getRenderFn: () => this.state.renderItem,
24
+ getItemAtPosition: (position) => this.getItems()[position] ?? null,
25
+ });
26
+ this.applySelectionModel();
27
+ this.widget.setFactory(this.state.factory);
28
+ }
29
+ detachFromParent(parent) {
30
+ this.state.factoryHandlers?.disconnect();
31
+ this.cleanupSelection();
32
+ super.detachFromParent(parent);
33
+ }
34
+ updateProps(oldProps, newProps) {
35
+ if (oldProps.renderItem !== newProps.renderItem) {
36
+ this.state.renderItem = newProps.renderItem;
37
+ }
38
+ this.updateSelectionProps(oldProps, newProps);
39
+ super.updateProps(oldProps, newProps);
40
+ }
41
+ }
42
+ export class ListItemNode extends VirtualItemNode {
43
+ static matches(type) {
44
+ return type === "ListView.Item" || type === "GridView.Item";
45
+ }
46
+ }
@@ -2,12 +2,12 @@ import * as Gio from "@gtkx/ffi/gio";
2
2
  import * as Gtk from "@gtkx/ffi/gtk";
3
3
  import type { Props } from "../factory.js";
4
4
  import { Node } from "../node.js";
5
- interface MenuEntry {
5
+ type MenuEntry = {
6
6
  type: "item" | "section" | "submenu";
7
7
  label?: string;
8
8
  action?: string;
9
9
  menu?: Gio.Menu;
10
- }
10
+ };
11
11
  interface MenuContainer {
12
12
  getMenu(): Gio.Menu;
13
13
  addMenuEntry(entry: MenuEntry): void;
@@ -24,15 +24,21 @@ declare abstract class MenuContainerNode<T extends Gtk.Widget | undefined> exten
24
24
  protected rebuildMenu(): void;
25
25
  protected onMenuRebuilt(): void;
26
26
  }
27
- export declare class PopoverMenuRootNode extends MenuContainerNode<Gtk.PopoverMenu> {
28
- static matches(type: string): boolean;
27
+ type MenuWidget = Gtk.Widget & {
28
+ setMenuModel(model: Gio.MenuModel | null): void;
29
+ };
30
+ declare abstract class MenuWidgetNode<T extends MenuWidget> extends MenuContainerNode<T> {
31
+ protected abstract createMenuWidget(menu: Gio.Menu): T;
29
32
  initialize(props: Props): void;
30
33
  protected onMenuRebuilt(): void;
31
34
  }
32
- export declare class PopoverMenuBarNode extends MenuContainerNode<Gtk.PopoverMenuBar> {
35
+ export declare class PopoverMenuRootNode extends MenuWidgetNode<Gtk.PopoverMenu> {
33
36
  static matches(type: string): boolean;
34
- initialize(props: Props): void;
35
- protected onMenuRebuilt(): void;
37
+ protected createMenuWidget(menu: Gio.Menu): Gtk.PopoverMenu;
38
+ }
39
+ export declare class PopoverMenuBarNode extends MenuWidgetNode<Gtk.PopoverMenuBar> {
40
+ static matches(type: string): boolean;
41
+ protected createMenuWidget(menu: Gio.Menu): Gtk.PopoverMenuBar;
36
42
  }
37
43
  export declare class ApplicationMenuNode extends MenuContainerNode<never> {
38
44
  static matches(type: string): boolean;
@@ -43,6 +49,7 @@ export declare class ApplicationMenuNode extends MenuContainerNode<never> {
43
49
  protected onMenuRebuilt(): void;
44
50
  }
45
51
  export declare class MenuItemNode extends Node<never> {
52
+ static consumedPropNames: string[];
46
53
  static matches(type: string): boolean;
47
54
  protected isVirtual(): boolean;
48
55
  private entry;
@@ -55,7 +62,6 @@ export declare class MenuItemNode extends Node<never> {
55
62
  initialize(props: Props): void;
56
63
  attachToParent(parent: Node): void;
57
64
  detachFromParent(parent: Node): void;
58
- protected consumedProps(): Set<string>;
59
65
  private isFieldInitializationIncomplete;
60
66
  updateProps(oldProps: Props, newProps: Props): void;
61
67
  private invokeCurrentCallback;
@@ -63,24 +69,24 @@ export declare class MenuItemNode extends Node<never> {
63
69
  private cleanupAction;
64
70
  private updateAccels;
65
71
  }
66
- export declare class MenuSectionNode extends MenuContainerNode<never> {
67
- static matches(type: string): boolean;
72
+ declare class MenuContainerItemNode extends MenuContainerNode<never> {
73
+ static consumedPropNames: string[];
74
+ protected entryType: "section" | "submenu";
75
+ protected matchType: string;
76
+ static matches(_type: string): boolean;
68
77
  protected isVirtual(): boolean;
69
78
  private entry;
70
79
  initialize(props: Props): void;
71
80
  attachToParent(parent: Node): void;
72
81
  detachFromParent(parent: Node): void;
73
- protected consumedProps(): Set<string>;
74
82
  updateProps(oldProps: Props, newProps: Props): void;
75
83
  }
76
- export declare class MenuSubmenuNode extends MenuContainerNode<never> {
84
+ export declare class MenuSectionNode extends MenuContainerItemNode {
85
+ protected entryType: "section" | "submenu";
86
+ static matches(type: string): boolean;
87
+ }
88
+ export declare class MenuSubmenuNode extends MenuContainerItemNode {
89
+ protected entryType: "section" | "submenu";
77
90
  static matches(type: string): boolean;
78
- protected isVirtual(): boolean;
79
- private entry;
80
- initialize(props: Props): void;
81
- attachToParent(parent: Node): void;
82
- detachFromParent(parent: Node): void;
83
- protected consumedProps(): Set<string>;
84
- updateProps(oldProps: Props, newProps: Props): void;
85
91
  }
86
92
  export {};