@gtkx/react 0.9.3 → 0.10.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 (182) hide show
  1. package/README.md +55 -67
  2. package/dist/errors.d.ts +3 -3
  3. package/dist/errors.js +8 -8
  4. package/dist/factory.d.ts +3 -5
  5. package/dist/factory.js +18 -71
  6. package/dist/fiber-root.d.ts +1 -1
  7. package/dist/fiber-root.js +1 -2
  8. package/dist/generated/internal.d.ts +3 -6
  9. package/dist/generated/internal.js +10386 -13577
  10. package/dist/generated/jsx.d.ts +2325 -2219
  11. package/dist/generated/jsx.js +1339 -1574
  12. package/dist/generated/registry.d.ts +4 -0
  13. package/dist/generated/registry.js +13 -0
  14. package/dist/host-config.d.ts +7 -4
  15. package/dist/host-config.js +53 -18
  16. package/dist/index.d.ts +2 -22
  17. package/dist/index.js +2 -40
  18. package/dist/jsx.d.ts +719 -0
  19. package/dist/jsx.js +392 -0
  20. package/dist/node.d.ts +15 -32
  21. package/dist/node.js +20 -240
  22. package/dist/nodes/action-row-child.d.ts +21 -0
  23. package/dist/nodes/action-row-child.js +69 -0
  24. package/dist/nodes/action-row.js +33 -0
  25. package/dist/nodes/application.d.ts +1 -0
  26. package/dist/nodes/application.js +38 -0
  27. package/dist/nodes/autowrapped.d.ts +1 -0
  28. package/dist/nodes/autowrapped.js +109 -0
  29. package/dist/nodes/column-view-column.d.ts +16 -0
  30. package/dist/nodes/column-view-column.js +54 -0
  31. package/dist/nodes/column-view.d.ts +0 -59
  32. package/dist/nodes/column-view.js +107 -226
  33. package/dist/nodes/fixed-child.d.ts +1 -0
  34. package/dist/nodes/fixed-child.js +45 -0
  35. package/dist/nodes/grid-child.d.ts +1 -0
  36. package/dist/nodes/grid-child.js +54 -0
  37. package/dist/nodes/index.d.ts +34 -0
  38. package/dist/nodes/index.js +34 -0
  39. package/dist/nodes/internal/list-item-renderer.d.ts +18 -0
  40. package/dist/nodes/internal/list-item-renderer.js +67 -0
  41. package/dist/nodes/internal/list-store.d.ts +16 -0
  42. package/dist/nodes/internal/list-store.js +69 -0
  43. package/dist/nodes/internal/predicates.d.ts +26 -0
  44. package/dist/nodes/internal/predicates.js +36 -0
  45. package/dist/nodes/internal/signal-store.d.ts +9 -0
  46. package/dist/nodes/internal/signal-store.js +54 -0
  47. package/dist/nodes/internal/simple-list-store.d.ts +14 -0
  48. package/dist/nodes/internal/simple-list-store.js +60 -0
  49. package/dist/nodes/internal/tree-list-item-renderer.d.ts +18 -0
  50. package/dist/nodes/internal/tree-list-item-renderer.js +90 -0
  51. package/dist/nodes/internal/tree-store.d.ts +28 -0
  52. package/dist/nodes/internal/tree-store.js +153 -0
  53. package/dist/nodes/internal/utils.d.ts +3 -0
  54. package/dist/nodes/internal/utils.js +20 -0
  55. package/dist/nodes/list-item.d.ts +12 -0
  56. package/dist/nodes/list-item.js +24 -0
  57. package/dist/nodes/list-view.d.ts +0 -22
  58. package/dist/nodes/list-view.js +45 -38
  59. package/dist/nodes/menu.d.ts +6 -106
  60. package/dist/nodes/menu.js +16 -268
  61. package/dist/nodes/models/list.d.ts +24 -0
  62. package/dist/nodes/models/list.js +102 -0
  63. package/dist/nodes/models/menu.d.ts +45 -0
  64. package/dist/nodes/models/menu.js +265 -0
  65. package/dist/nodes/models/tree-list.d.ts +28 -0
  66. package/dist/nodes/models/tree-list.js +141 -0
  67. package/dist/nodes/navigation-page.d.ts +21 -0
  68. package/dist/nodes/navigation-page.js +95 -0
  69. package/dist/nodes/navigation-view.d.ts +1 -0
  70. package/dist/nodes/navigation-view.js +29 -0
  71. package/dist/nodes/notebook-page-tab.d.ts +15 -0
  72. package/dist/nodes/notebook-page-tab.js +42 -0
  73. package/dist/nodes/notebook-page.d.ts +23 -0
  74. package/dist/nodes/notebook-page.js +106 -0
  75. package/dist/nodes/notebook.d.ts +0 -32
  76. package/dist/nodes/notebook.js +20 -113
  77. package/dist/nodes/overlay-child.d.ts +1 -0
  78. package/dist/nodes/overlay-child.js +30 -0
  79. package/dist/nodes/pack-child.d.ts +21 -0
  80. package/dist/nodes/pack-child.js +68 -0
  81. package/dist/nodes/pack.d.ts +1 -0
  82. package/dist/nodes/pack.js +33 -0
  83. package/dist/nodes/popover-menu.d.ts +1 -0
  84. package/dist/nodes/popover-menu.js +58 -0
  85. package/dist/nodes/simple-list-item.d.ts +9 -0
  86. package/dist/nodes/simple-list-item.js +9 -0
  87. package/dist/nodes/simple-list-view.d.ts +1 -0
  88. package/dist/nodes/simple-list-view.js +75 -0
  89. package/dist/nodes/slot.d.ts +18 -10
  90. package/dist/nodes/slot.js +83 -51
  91. package/dist/nodes/stack-page.d.ts +1 -0
  92. package/dist/nodes/stack-page.js +80 -0
  93. package/dist/nodes/stack.d.ts +1 -22
  94. package/dist/nodes/stack.js +21 -60
  95. package/dist/nodes/toast-overlay.d.ts +1 -0
  96. package/dist/nodes/toast-overlay.js +35 -0
  97. package/dist/nodes/toast.d.ts +17 -0
  98. package/dist/nodes/toast.js +77 -0
  99. package/dist/nodes/toolbar-child.d.ts +9 -0
  100. package/dist/nodes/toolbar-child.js +33 -0
  101. package/dist/nodes/toolbar.d.ts +1 -0
  102. package/dist/nodes/toolbar.js +42 -0
  103. package/dist/nodes/tree-list-item.d.ts +20 -0
  104. package/dist/nodes/tree-list-item.js +102 -0
  105. package/dist/nodes/tree-list-view.d.ts +1 -0
  106. package/dist/nodes/tree-list-view.js +57 -0
  107. package/dist/nodes/virtual.d.ts +13 -0
  108. package/dist/nodes/virtual.js +21 -0
  109. package/dist/nodes/widget.d.ts +17 -3
  110. package/dist/nodes/widget.js +258 -2
  111. package/dist/nodes/window.d.ts +1 -12
  112. package/dist/nodes/window.js +66 -27
  113. package/dist/portal.d.ts +18 -13
  114. package/dist/portal.js +17 -14
  115. package/dist/reconciler.d.ts +0 -4
  116. package/dist/reconciler.js +1 -9
  117. package/dist/registry.d.ts +8 -0
  118. package/dist/registry.js +5 -0
  119. package/dist/render.d.ts +108 -12
  120. package/dist/render.js +140 -16
  121. package/dist/scheduler.d.ts +4 -0
  122. package/dist/scheduler.js +10 -0
  123. package/dist/types.d.ts +3 -136
  124. package/package.json +6 -6
  125. package/dist/batch.d.ts +0 -5
  126. package/dist/batch.js +0 -31
  127. package/dist/codegen/jsx-generator.d.ts +0 -56
  128. package/dist/codegen/jsx-generator.js +0 -959
  129. package/dist/containers.d.ts +0 -58
  130. package/dist/nodes/about-dialog.d.ts +0 -8
  131. package/dist/nodes/about-dialog.js +0 -16
  132. package/dist/nodes/action-bar.d.ts +0 -5
  133. package/dist/nodes/action-bar.js +0 -6
  134. package/dist/nodes/combo-row.d.ts +0 -5
  135. package/dist/nodes/combo-row.js +0 -6
  136. package/dist/nodes/drop-down.d.ts +0 -9
  137. package/dist/nodes/drop-down.js +0 -12
  138. package/dist/nodes/flow-box.d.ts +0 -10
  139. package/dist/nodes/flow-box.js +0 -41
  140. package/dist/nodes/grid.d.ts +0 -30
  141. package/dist/nodes/grid.js +0 -84
  142. package/dist/nodes/header-bar.d.ts +0 -43
  143. package/dist/nodes/header-bar.js +0 -116
  144. package/dist/nodes/indexed-child-container.d.ts +0 -16
  145. package/dist/nodes/indexed-child-container.js +0 -22
  146. package/dist/nodes/list-box.d.ts +0 -10
  147. package/dist/nodes/list-box.js +0 -48
  148. package/dist/nodes/list-item-factory.d.ts +0 -19
  149. package/dist/nodes/list-item-factory.js +0 -58
  150. package/dist/nodes/overlay.d.ts +0 -11
  151. package/dist/nodes/overlay.js +0 -50
  152. package/dist/nodes/paged-stack.d.ts +0 -31
  153. package/dist/nodes/paged-stack.js +0 -95
  154. package/dist/nodes/root.d.ts +0 -8
  155. package/dist/nodes/root.js +0 -13
  156. package/dist/nodes/selectable-list.d.ts +0 -45
  157. package/dist/nodes/selectable-list.js +0 -260
  158. package/dist/nodes/stack-page-props.d.ts +0 -11
  159. package/dist/nodes/stack-page-props.js +0 -23
  160. package/dist/nodes/string-list-container.d.ts +0 -34
  161. package/dist/nodes/string-list-container.js +0 -118
  162. package/dist/nodes/string-list-item.d.ts +0 -19
  163. package/dist/nodes/string-list-item.js +0 -50
  164. package/dist/nodes/string-list-store.d.ts +0 -13
  165. package/dist/nodes/string-list-store.js +0 -44
  166. package/dist/nodes/text-view.d.ts +0 -8
  167. package/dist/nodes/text-view.js +0 -16
  168. package/dist/nodes/toggle-button.d.ts +0 -14
  169. package/dist/nodes/toggle-button.js +0 -39
  170. package/dist/nodes/toolbar-view.d.ts +0 -14
  171. package/dist/nodes/toolbar-view.js +0 -78
  172. package/dist/nodes/view-stack.d.ts +0 -9
  173. package/dist/nodes/view-stack.js +0 -28
  174. package/dist/nodes/virtual-item.d.ts +0 -19
  175. package/dist/nodes/virtual-item.js +0 -48
  176. package/dist/nodes/virtual-slot.d.ts +0 -25
  177. package/dist/nodes/virtual-slot.js +0 -57
  178. package/dist/predicates.d.ts +0 -29
  179. package/dist/predicates.js +0 -37
  180. package/dist/props.d.ts +0 -7
  181. package/dist/props.js +0 -12
  182. /package/dist/{containers.js → nodes/action-row.d.ts} +0 -0
@@ -1,46 +1,53 @@
1
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";
2
+ import { registerNodeClass } from "../registry.js";
3
+ import { ListItemRenderer } from "./internal/list-item-renderer.js";
4
+ import { filterProps, isContainerType } from "./internal/utils.js";
5
+ import { ListItemNode } from "./list-item.js";
6
+ import { List } from "./models/list.js";
7
+ import { WidgetNode } from "./widget.js";
8
+ const PROP_NAMES = ["renderItem"];
9
+ class ListViewNode extends WidgetNode {
10
+ static priority = 1;
11
+ itemRenderer;
12
+ list;
13
+ static matches(_type, containerOrClass) {
14
+ return isContainerType(Gtk.ListView, containerOrClass) || isContainerType(Gtk.GridView, containerOrClass);
9
15
  }
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);
16
+ constructor(typeName, props, container, rootContainer) {
17
+ super(typeName, props, container, rootContainer);
18
+ this.list = new List();
19
+ this.itemRenderer = new ListItemRenderer(this.signalStore);
20
+ this.itemRenderer.setStore(this.list.getStore());
21
+ this.container.setFactory(this.itemRenderer.getFactory());
28
22
  }
29
- unmount() {
30
- this.state.factoryHandlers?.disconnect();
31
- this.cleanupSelection();
32
- super.unmount();
23
+ mount() {
24
+ super.mount();
25
+ this.container.setModel(this.list.getSelectionModel());
33
26
  }
34
- updateProps(oldProps, newProps) {
35
- if (oldProps.renderItem !== newProps.renderItem) {
36
- this.state.renderItem = newProps.renderItem;
27
+ appendChild(child) {
28
+ if (!(child instanceof ListItemNode)) {
29
+ throw new Error(`Cannot append '${child.typeName}' to 'ListView': expected ListItem`);
37
30
  }
38
- this.updateSelectionProps(oldProps, newProps);
39
- super.updateProps(oldProps, newProps);
31
+ this.list.appendChild(child);
40
32
  }
41
- }
42
- export class ListItemNode extends VirtualItemNode {
43
- static matches(type) {
44
- return type === "ListView.Item" || type === "GridView.Item";
33
+ insertBefore(child, before) {
34
+ if (!(child instanceof ListItemNode) || !(before instanceof ListItemNode)) {
35
+ throw new Error(`Cannot insert '${child.typeName}' to 'ListView': expected ListItem`);
36
+ }
37
+ this.list.insertBefore(child, before);
38
+ }
39
+ removeChild(child) {
40
+ if (!(child instanceof ListItemNode)) {
41
+ throw new Error(`Cannot remove '${child.typeName}' from 'ListView': expected ListItem`);
42
+ }
43
+ this.list.removeChild(child);
44
+ }
45
+ updateProps(oldProps, newProps) {
46
+ if (!oldProps || oldProps.renderItem !== newProps.renderItem) {
47
+ this.itemRenderer.setRenderFn(newProps.renderItem);
48
+ }
49
+ this.list.updateProps(filterProps(oldProps ?? {}, PROP_NAMES), filterProps(newProps, PROP_NAMES));
50
+ super.updateProps(filterProps(oldProps ?? {}, PROP_NAMES), filterProps(newProps, PROP_NAMES));
45
51
  }
46
52
  }
53
+ registerNodeClass(ListViewNode);
@@ -1,108 +1,8 @@
1
- import * as Gio from "@gtkx/ffi/gio";
2
- import * as Gtk from "@gtkx/ffi/gtk";
3
- import type { Props } from "../factory.js";
4
- import type { Node } from "../node.js";
5
- import { Node as NodeClass } from "../node.js";
6
- type MenuEntry = {
7
- type: "item" | "section" | "submenu";
8
- label?: string;
9
- action?: string;
10
- menu?: Gio.Menu;
11
- };
12
- interface MenuContainer {
13
- getMenu(): Gio.Menu;
14
- addMenuEntry(entry: MenuEntry): void;
15
- removeMenuEntry(entry: MenuEntry): void;
16
- }
17
- interface MenuEntryNode {
18
- parent: Node | null;
19
- getMenuEntry(): MenuEntry;
20
- setParentContainer(container: Node & MenuContainer): void;
21
- onAttach(): void;
22
- onDetach(): void;
23
- unmount(): void;
24
- }
25
- declare abstract class MenuContainerNode<T extends Gtk.Widget | undefined> extends NodeClass<T> implements MenuContainer {
26
- protected menu: Gio.Menu;
27
- protected entries: MenuEntry[];
28
- private rebuildScheduled;
29
- getMenu(): Gio.Menu;
30
- addMenuEntry(entry: MenuEntry): void;
31
- removeMenuEntry(entry: MenuEntry): void;
32
- appendChild(child: Node): void;
33
- insertBefore(child: Node, before: Node): void;
34
- removeChild(child: Node): void;
35
- private scheduleRebuild;
36
- protected rebuildMenu(): void;
37
- protected onMenuRebuilt(): void;
38
- }
39
- type MenuWidget = Gtk.Widget & {
40
- setMenuModel(model?: Gio.MenuModel): void;
41
- };
42
- declare abstract class MenuWidgetNode<T extends MenuWidget> extends MenuContainerNode<T> {
43
- protected abstract createMenuWidget(menu: Gio.Menu): T;
44
- initialize(props: Props): void;
45
- protected onMenuRebuilt(): void;
46
- }
47
- export declare class PopoverMenuRootNode extends MenuWidgetNode<Gtk.PopoverMenu> {
48
- static matches(type: string): boolean;
49
- protected createMenuWidget(menu: Gio.Menu): Gtk.PopoverMenu;
50
- }
51
- export declare class PopoverMenuBarNode extends MenuWidgetNode<Gtk.PopoverMenuBar> {
52
- static matches(type: string): boolean;
53
- protected createMenuWidget(menu: Gio.Menu): Gtk.PopoverMenuBar;
54
- }
55
- export declare class ApplicationMenuNode extends MenuContainerNode<never> {
56
- static matches(type: string): boolean;
57
- protected isVirtual(): boolean;
58
- mount(): void;
59
- unmount(): void;
60
- protected onMenuRebuilt(): void;
61
- }
62
- export declare class MenuItemNode extends NodeClass<never> implements MenuEntryNode {
63
- static consumedPropNames: string[];
64
- static matches(type: string): boolean;
65
- protected isVirtual(): boolean;
66
- private entry;
67
- private action;
68
- private actionName;
69
- private signalHandlerId;
70
- private onActivateCallback;
71
- private currentAccels;
72
- private parentContainer;
73
- initialize(props: Props): void;
74
- getMenuEntry(): MenuEntry;
75
- setParentContainer(container: Node & MenuContainer): void;
76
- onAttach(): void;
77
- onDetach(): void;
78
- unmount(): void;
79
- private isFieldInitializationIncomplete;
80
- updateProps(oldProps: Props, newProps: Props): void;
81
- private invokeCurrentCallback;
82
- private setupAction;
83
- private cleanupAction;
84
- private updateAccels;
85
- }
86
- declare class MenuContainerItemNode extends MenuContainerNode<never> implements MenuEntryNode {
87
- static consumedPropNames: string[];
88
- protected entryType: "section" | "submenu";
89
- protected matchType: string;
90
- static matches(_type: string): boolean;
91
- protected isVirtual(): boolean;
92
- private entry;
93
- initialize(props: Props): void;
94
- getMenuEntry(): MenuEntry;
95
- setParentContainer(_container: Node & MenuContainer): void;
96
- onAttach(): void;
97
- onDetach(): void;
98
- updateProps(oldProps: Props, newProps: Props): void;
99
- }
100
- export declare class MenuSectionNode extends MenuContainerItemNode {
101
- protected entryType: "section" | "submenu";
102
- static matches(type: string): boolean;
103
- }
104
- export declare class MenuSubmenuNode extends MenuContainerItemNode {
105
- protected entryType: "section" | "submenu";
1
+ import type { Container } from "../types.js";
2
+ import { Menu, type MenuProps } from "./models/menu.js";
3
+ export declare class MenuNode extends Menu {
4
+ static priority: number;
106
5
  static matches(type: string): boolean;
6
+ private static getType;
7
+ constructor(typeName: string, props: MenuProps, _container: undefined, rootContainer?: Container);
107
8
  }
108
- export {};
@@ -1,277 +1,25 @@
1
- import { getApplication, getNativeObject } from "@gtkx/ffi";
2
- import * as Gio from "@gtkx/ffi/gio";
3
- import * as GObject from "@gtkx/ffi/gobject";
4
1
  import * as Gtk from "@gtkx/ffi/gtk";
5
- import { Node as NodeClass } from "../node.js";
6
- import { RootNode } from "./root.js";
7
- let actionCounter = 0;
8
- const generateActionName = () => `gtkx_menu_action_${actionCounter++}`;
9
- const isMenuEntryNode = (node) => "getMenuEntry" in node && "setParentContainer" in node;
10
- class MenuContainerNode extends NodeClass {
11
- menu = new Gio.Menu();
12
- entries = [];
13
- rebuildScheduled = false;
14
- getMenu() {
15
- return this.menu;
16
- }
17
- addMenuEntry(entry) {
18
- this.entries.push(entry);
19
- this.scheduleRebuild();
20
- }
21
- removeMenuEntry(entry) {
22
- const index = this.entries.indexOf(entry);
23
- if (index !== -1) {
24
- this.entries.splice(index, 1);
25
- this.scheduleRebuild();
26
- }
27
- }
28
- appendChild(child) {
29
- if (isMenuEntryNode(child)) {
30
- child.parent = this;
31
- child.onAttach();
32
- this.addMenuEntry(child.getMenuEntry());
33
- child.setParentContainer(this);
34
- return;
35
- }
36
- super.appendChild(child);
37
- }
38
- insertBefore(child, before) {
39
- if (isMenuEntryNode(child)) {
40
- child.parent = this;
41
- child.onAttach();
42
- this.addMenuEntry(child.getMenuEntry());
43
- child.setParentContainer(this);
44
- return;
45
- }
46
- super.insertBefore(child, before);
47
- }
48
- removeChild(child) {
49
- if (isMenuEntryNode(child)) {
50
- this.removeMenuEntry(child.getMenuEntry());
51
- child.unmount();
52
- child.parent = null;
53
- return;
54
- }
55
- super.removeChild(child);
56
- }
57
- scheduleRebuild() {
58
- if (this.rebuildScheduled)
59
- return;
60
- this.rebuildScheduled = true;
61
- queueMicrotask(() => {
62
- this.rebuildScheduled = false;
63
- this.rebuildMenu();
64
- });
65
- }
66
- rebuildMenu() {
67
- this.menu.removeAll();
68
- for (const entry of this.entries) {
69
- if (entry.type === "item") {
70
- this.menu.append(entry.label, entry.action);
71
- }
72
- else if (entry.type === "section" && entry.menu) {
73
- this.menu.appendSection(entry.menu, entry.label);
74
- }
75
- else if (entry.type === "submenu" && entry.menu) {
76
- this.menu.appendSubmenu(entry.menu, entry.label);
77
- }
78
- }
79
- this.onMenuRebuilt();
80
- }
81
- onMenuRebuilt() { }
82
- }
83
- class MenuWidgetNode extends MenuContainerNode {
84
- initialize(props) {
85
- this.widget = this.createMenuWidget(this.menu);
86
- super.initialize(props);
87
- }
88
- onMenuRebuilt() {
89
- this.widget.setMenuModel(this.menu);
90
- }
91
- }
92
- export class PopoverMenuRootNode extends MenuWidgetNode {
93
- static matches(type) {
94
- return type === "PopoverMenu.Root";
95
- }
96
- createMenuWidget(menu) {
97
- return new Gtk.PopoverMenu(menu);
98
- }
99
- }
100
- export class PopoverMenuBarNode extends MenuWidgetNode {
101
- static matches(type) {
102
- return type === "PopoverMenuBar";
103
- }
104
- createMenuWidget(menu) {
105
- return new Gtk.PopoverMenuBar(menu);
106
- }
107
- }
108
- export class ApplicationMenuNode extends MenuContainerNode {
109
- static matches(type) {
110
- return type === "ApplicationMenu";
111
- }
112
- isVirtual() {
113
- return true;
114
- }
115
- mount() {
116
- if (!(this.parent instanceof RootNode)) {
117
- throw new Error("ApplicationMenu must be a direct child of a fragment at the root level");
118
- }
119
- getApplication().setMenubar(this.menu);
120
- }
121
- unmount() {
122
- getApplication().setMenubar(undefined);
123
- super.unmount();
124
- }
125
- onMenuRebuilt() {
126
- getApplication().setMenubar(this.menu);
127
- }
128
- }
129
- export class MenuItemNode extends NodeClass {
130
- static consumedPropNames = ["label", "onActivate", "accels"];
2
+ import { registerNodeClass } from "../registry.js";
3
+ import { Menu } from "./models/menu.js";
4
+ export class MenuNode extends Menu {
5
+ static priority = 1;
131
6
  static matches(type) {
132
- return type === "Menu.Item";
133
- }
134
- isVirtual() {
135
- return true;
136
- }
137
- entry = { type: "item" };
138
- action = null;
139
- actionName = null;
140
- signalHandlerId = null;
141
- onActivateCallback;
142
- currentAccels;
143
- parentContainer = null;
144
- initialize(props) {
145
- this.onActivateCallback = props.onActivate;
146
- this.currentAccels = props.accels;
147
- this.entry.label = props.label;
148
- super.initialize(props);
149
- }
150
- getMenuEntry() {
151
- return this.entry;
152
- }
153
- setParentContainer(container) {
154
- this.parentContainer = container;
155
- }
156
- onAttach() {
157
- this.setupAction();
158
- }
159
- onDetach() {
160
- this.cleanupAction();
7
+ return type === "Menu.Item" || type === "Menu.Section" || type === "Menu.Submenu";
161
8
  }
162
- unmount() {
163
- this.cleanupAction();
164
- this.parentContainer = null;
165
- super.unmount();
166
- }
167
- isFieldInitializationIncomplete() {
168
- return !this.entry;
169
- }
170
- updateProps(oldProps, newProps) {
171
- if (this.isFieldInitializationIncomplete()) {
172
- super.updateProps(oldProps, newProps);
173
- return;
174
- }
175
- const labelChanged = oldProps.label !== newProps.label;
176
- const callbackPresenceChanged = (oldProps.onActivate !== undefined) !== (newProps.onActivate !== undefined);
177
- const accelsChanged = oldProps.accels !== newProps.accels;
178
- this.onActivateCallback = newProps.onActivate;
179
- this.currentAccels = newProps.accels;
180
- if (labelChanged) {
181
- this.entry.label = newProps.label;
182
- }
183
- if (this.parentContainer && callbackPresenceChanged) {
184
- this.cleanupAction();
185
- this.setupAction();
9
+ static getType(typeName) {
10
+ if (typeName === "Menu.Item") {
11
+ return "item";
186
12
  }
187
- if (accelsChanged && this.actionName) {
188
- this.updateAccels(this.currentAccels);
13
+ else if (typeName === "Menu.Section") {
14
+ return "section";
189
15
  }
190
- super.updateProps(oldProps, newProps);
191
- }
192
- invokeCurrentCallback() {
193
- this.onActivateCallback?.();
194
- }
195
- setupAction() {
196
- if (!this.onActivateCallback)
197
- return;
198
- this.actionName = generateActionName();
199
- this.action = new Gio.SimpleAction(this.actionName);
200
- this.signalHandlerId = this.action.connect("activate", () => this.invokeCurrentCallback());
201
- const app = getApplication();
202
- const action = getNativeObject(this.action.id, Gio.Action);
203
- if (!action) {
204
- throw new Error("Failed to get Gio.Action interface from SimpleAction");
205
- }
206
- app.addAction(action);
207
- this.entry.action = `app.${this.actionName}`;
208
- if (this.currentAccels) {
209
- this.updateAccels(this.currentAccels);
16
+ else if (typeName === "Menu.Submenu") {
17
+ return "submenu";
210
18
  }
19
+ throw new Error(`Unable to find menu type '${typeName}'`);
211
20
  }
212
- cleanupAction() {
213
- if (this.actionName) {
214
- const app = getApplication();
215
- app.removeAction(this.actionName);
216
- if (this.currentAccels) {
217
- app.setAccelsForAction(`app.${this.actionName}`, []);
218
- }
219
- }
220
- if (this.action && this.signalHandlerId !== null) {
221
- GObject.signalHandlerDisconnect(this.action, this.signalHandlerId);
222
- }
223
- this.action = null;
224
- this.actionName = null;
225
- this.signalHandlerId = null;
226
- this.entry.action = undefined;
227
- }
228
- updateAccels(accels) {
229
- if (!this.actionName)
230
- return;
231
- const app = getApplication();
232
- const accelArray = accels ? (Array.isArray(accels) ? accels : [accels]) : [];
233
- app.setAccelsForAction(`app.${this.actionName}`, accelArray);
234
- }
235
- }
236
- class MenuContainerItemNode extends MenuContainerNode {
237
- static consumedPropNames = ["label"];
238
- entryType = "section";
239
- matchType = "";
240
- static matches(_type) {
241
- return false;
242
- }
243
- isVirtual() {
244
- return true;
245
- }
246
- entry = { type: "section" };
247
- initialize(props) {
248
- this.entry = { type: this.entryType };
249
- this.entry.menu = this.menu;
250
- this.entry.label = props.label;
251
- super.initialize(props);
252
- }
253
- getMenuEntry() {
254
- return this.entry;
255
- }
256
- setParentContainer(_container) { }
257
- onAttach() { }
258
- onDetach() { }
259
- updateProps(oldProps, newProps) {
260
- if (oldProps.label !== newProps.label && this.entry) {
261
- this.entry.label = newProps.label;
262
- }
263
- super.updateProps(oldProps, newProps);
264
- }
265
- }
266
- export class MenuSectionNode extends MenuContainerItemNode {
267
- entryType = "section";
268
- static matches(type) {
269
- return type === "Menu.Section";
270
- }
271
- }
272
- export class MenuSubmenuNode extends MenuContainerItemNode {
273
- entryType = "submenu";
274
- static matches(type) {
275
- return type === "Menu.Submenu";
21
+ constructor(typeName, props, _container, rootContainer) {
22
+ super(MenuNode.getType(typeName), props, undefined, rootContainer instanceof Gtk.Application ? rootContainer : undefined);
276
23
  }
277
24
  }
25
+ registerNodeClass(MenuNode);
@@ -0,0 +1,24 @@
1
+ import * as Gtk from "@gtkx/ffi/gtk";
2
+ import type { Node } from "../../node.js";
3
+ import { ListStore } from "../internal/list-store.js";
4
+ import { VirtualNode } from "../virtual.js";
5
+ export type ListProps = {
6
+ selectionMode?: Gtk.SelectionMode;
7
+ selected?: string[];
8
+ onSelectionChanged?: (ids: string[]) => void;
9
+ };
10
+ export declare class List extends VirtualNode<ListProps> {
11
+ private store;
12
+ private selectionModel;
13
+ private handleSelectionChange?;
14
+ constructor(selectionMode?: Gtk.SelectionMode);
15
+ getStore(): ListStore;
16
+ getSelectionModel(): Gtk.SingleSelection | Gtk.MultiSelection;
17
+ appendChild(child: Node): void;
18
+ insertBefore(child: Node, before: Node): void;
19
+ removeChild(child: Node): void;
20
+ updateProps(oldProps: ListProps | null, newProps: ListProps): void;
21
+ private createSelectionModel;
22
+ private getSelection;
23
+ private setSelection;
24
+ }
@@ -0,0 +1,102 @@
1
+ import * as Gtk from "@gtkx/ffi/gtk";
2
+ import { ListStore } from "../internal/list-store.js";
3
+ import { ListItemNode } from "../list-item.js";
4
+ import { VirtualNode } from "../virtual.js";
5
+ export class List extends VirtualNode {
6
+ store;
7
+ selectionModel;
8
+ handleSelectionChange;
9
+ constructor(selectionMode) {
10
+ super("", {}, undefined);
11
+ this.store = new ListStore();
12
+ this.selectionModel = this.createSelectionModel(selectionMode);
13
+ this.selectionModel.setModel(this.store.getModel());
14
+ }
15
+ getStore() {
16
+ return this.store;
17
+ }
18
+ getSelectionModel() {
19
+ return this.selectionModel;
20
+ }
21
+ appendChild(child) {
22
+ if (!(child instanceof ListItemNode)) {
23
+ return;
24
+ }
25
+ child.setStore(this.store);
26
+ this.store.addItem(child.props.id, child.props.value);
27
+ }
28
+ insertBefore(child, before) {
29
+ if (!(child instanceof ListItemNode) || !(before instanceof ListItemNode)) {
30
+ return;
31
+ }
32
+ child.setStore(this.store);
33
+ this.store.insertItemBefore(child.props.id, before.props.id, child.props.value);
34
+ }
35
+ removeChild(child) {
36
+ if (!(child instanceof ListItemNode)) {
37
+ return;
38
+ }
39
+ this.store.removeItem(child.props.id);
40
+ child.setStore(undefined);
41
+ }
42
+ updateProps(oldProps, newProps) {
43
+ super.updateProps(oldProps, newProps);
44
+ if (!oldProps || oldProps.selectionMode !== newProps.selectionMode) {
45
+ this.signalStore.set(this.selectionModel, "selection-changed", undefined);
46
+ this.selectionModel = this.createSelectionModel(newProps.selectionMode);
47
+ }
48
+ if (!oldProps ||
49
+ oldProps.onSelectionChanged !== newProps.onSelectionChanged ||
50
+ oldProps.selectionMode !== newProps.selectionMode) {
51
+ const onSelectionChanged = newProps.onSelectionChanged;
52
+ this.handleSelectionChange = () => {
53
+ onSelectionChanged?.(this.getSelection());
54
+ };
55
+ this.signalStore.set(this.selectionModel, "selection-changed", newProps.onSelectionChanged ? this.handleSelectionChange : undefined);
56
+ }
57
+ if (!oldProps || oldProps.selected !== newProps.selected || oldProps.selectionMode !== newProps.selectionMode) {
58
+ this.setSelection(newProps.selected);
59
+ }
60
+ }
61
+ createSelectionModel(mode) {
62
+ const model = this.store.getModel();
63
+ const selectionMode = mode ?? Gtk.SelectionMode.SINGLE;
64
+ const selectionModel = selectionMode === Gtk.SelectionMode.MULTIPLE
65
+ ? new Gtk.MultiSelection(model)
66
+ : new Gtk.SingleSelection(model);
67
+ if (selectionModel instanceof Gtk.SingleSelection) {
68
+ selectionModel.setAutoselect(false);
69
+ selectionModel.setCanUnselect(true);
70
+ }
71
+ return selectionModel;
72
+ }
73
+ getSelection() {
74
+ const model = this.store.getModel();
75
+ const selection = this.selectionModel.getSelection();
76
+ const size = selection.getSize();
77
+ const ids = [];
78
+ for (let i = 0; i < size; i++) {
79
+ const index = selection.getNth(i);
80
+ const id = model.getString(index);
81
+ if (id !== null) {
82
+ ids.push(id);
83
+ }
84
+ }
85
+ return ids;
86
+ }
87
+ setSelection(ids) {
88
+ const model = this.store.getModel();
89
+ const nItems = model.getNItems();
90
+ const selected = new Gtk.Bitset();
91
+ const mask = Gtk.Bitset.newRange(0, nItems);
92
+ if (ids) {
93
+ for (const id of ids) {
94
+ const index = model.find(id);
95
+ if (index < nItems) {
96
+ selected.add(index);
97
+ }
98
+ }
99
+ }
100
+ this.selectionModel.setSelection(selected, mask);
101
+ }
102
+ }
@@ -0,0 +1,45 @@
1
+ import * as Gio from "@gtkx/ffi/gio";
2
+ import type * as Gtk from "@gtkx/ffi/gtk";
3
+ import type { Node } from "../../node.js";
4
+ import { VirtualNode } from "../virtual.js";
5
+ export type MenuType = "root" | "item" | "section" | "submenu";
6
+ export type MenuProps = {
7
+ id?: string;
8
+ label?: string;
9
+ accels?: string | string[];
10
+ onActivate?: () => void;
11
+ };
12
+ export declare class Menu extends VirtualNode<MenuProps> {
13
+ private actionMap?;
14
+ private actionPrefix;
15
+ private parent?;
16
+ private menu;
17
+ private type;
18
+ private application?;
19
+ private action?;
20
+ private children;
21
+ constructor(type: MenuType, props: MenuProps, actionMap?: Gio.ActionMap, application?: Gtk.Application);
22
+ setActionMap(actionMap: Gio.ActionMap, prefix: string): void;
23
+ private getAccels;
24
+ private getActionName;
25
+ private getOnActivate;
26
+ private getId;
27
+ private getParent;
28
+ private getActionMap;
29
+ createAction(): void;
30
+ private removeAction;
31
+ private getPosition;
32
+ private setParent;
33
+ getMenu(): Gio.Menu;
34
+ private getAction;
35
+ removeFromParent(): void;
36
+ insertInParentBefore(before: Menu): void;
37
+ appendToParent(): void;
38
+ appendChild(child: Node): void;
39
+ insertBefore(child: Node, before: Node): void;
40
+ removeChild(child: Node): void;
41
+ updateProps(oldProps: MenuProps | null, newProps: MenuProps): void;
42
+ private updateItemProps;
43
+ private updateContainerProps;
44
+ unmount(): void;
45
+ }