@gtkx/react 0.1.50 → 0.1.52

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.
package/dist/batch.js CHANGED
@@ -5,10 +5,15 @@ export const beginCommit = () => {
5
5
  };
6
6
  export const endCommit = () => {
7
7
  inCommit = false;
8
- for (const callback of pendingFlushes) {
9
- callback();
8
+ if (pendingFlushes.size > 0) {
9
+ const callbacks = [...pendingFlushes];
10
+ pendingFlushes.clear();
11
+ queueMicrotask(() => {
12
+ for (const callback of callbacks) {
13
+ callback();
14
+ }
15
+ });
10
16
  }
11
- pendingFlushes.clear();
12
17
  };
13
18
  export const scheduleFlush = (callback) => {
14
19
  if (inCommit) {
@@ -5,6 +5,8 @@ const COLUMN_VIEW_WIDGET = "ColumnView";
5
5
  const DROPDOWN_WIDGETS = new Set(["DropDown"]);
6
6
  const GRID_WIDGETS = new Set(["Grid"]);
7
7
  const NOTEBOOK_WIDGET = "Notebook";
8
+ const STACK_WIDGET = "Stack";
9
+ const POPOVER_MENU_WIDGET = "PopoverMenu";
8
10
  const INTERNALLY_PROVIDED_PARAMS = {
9
11
  ApplicationWindow: new Set(["application"]),
10
12
  };
@@ -33,6 +35,8 @@ const isColumnViewWidget = (widgetName) => widgetName === COLUMN_VIEW_WIDGET;
33
35
  const isDropDownWidget = (widgetName) => DROPDOWN_WIDGETS.has(widgetName);
34
36
  const isGridWidget = (widgetName) => GRID_WIDGETS.has(widgetName);
35
37
  const isNotebookWidget = (widgetName) => widgetName === NOTEBOOK_WIDGET;
38
+ const isStackWidget = (widgetName) => widgetName === STACK_WIDGET;
39
+ const isPopoverMenuWidget = (widgetName) => widgetName === POPOVER_MENU_WIDGET;
36
40
  const sanitizeDoc = (doc) => {
37
41
  let result = doc;
38
42
  result = result.replace(/<picture>[\s\S]*?<\/picture>/gi, "");
@@ -140,7 +144,7 @@ export class JsxGenerator {
140
144
  `import type { ReactNode, Ref } from "react";`,
141
145
  ...externalImports,
142
146
  `import type * as Gtk from "@gtkx/ffi/gtk";`,
143
- `import type { ColumnViewColumnProps, ColumnViewRootProps, GridChildProps, ListItemProps, ListViewRenderProps, NotebookPageProps, SlotProps } from "../types.js";`,
147
+ `import type { ColumnViewColumnProps, ColumnViewRootProps, GridChildProps, ListItemProps, ListViewRenderProps, MenuItemProps, MenuRootProps, MenuSectionProps, MenuSubmenuProps, NotebookPageProps, SlotProps, StackPageProps, StackRootProps } from "../types.js";`,
144
148
  "",
145
149
  ].join("\n");
146
150
  }
@@ -150,7 +154,7 @@ export class JsxGenerator {
150
154
  generateCommonTypes(widgetClass) {
151
155
  const widgetPropsContent = this.generateWidgetPropsContent(widgetClass);
152
156
  return `
153
- export { ColumnViewColumnProps, ColumnViewRootProps, GridChildProps, ListItemProps, ListViewRenderProps, NotebookPageProps, SlotProps };
157
+ export { ColumnViewColumnProps, ColumnViewRootProps, GridChildProps, ListItemProps, ListViewRenderProps, MenuItemProps, MenuRootProps, MenuSectionProps, MenuSubmenuProps, NotebookPageProps, SlotProps, StackPageProps, StackRootProps };
154
158
 
155
159
  ${widgetPropsContent}
156
160
  `;
@@ -581,11 +585,17 @@ ${widgetPropsContent}
581
585
  isColumnViewWidget(widget.name) ||
582
586
  isDropDownWidget(widget.name) ||
583
587
  isGridWidget(widget.name) ||
584
- isNotebookWidget(widget.name);
588
+ isNotebookWidget(widget.name) ||
589
+ isStackWidget(widget.name) ||
590
+ isPopoverMenuWidget(widget.name);
585
591
  const docComment = widget.doc ? formatDoc(widget.doc).trimEnd() : "";
586
592
  if (hasMeaningfulSlots) {
587
593
  // For list widgets, generate wrapper components with proper generics
588
- if (isListWidget(widget.name) || isColumnViewWidget(widget.name) || isDropDownWidget(widget.name)) {
594
+ if (isListWidget(widget.name) ||
595
+ isColumnViewWidget(widget.name) ||
596
+ isDropDownWidget(widget.name) ||
597
+ isStackWidget(widget.name) ||
598
+ isPopoverMenuWidget(widget.name)) {
589
599
  const wrapperComponents = this.generateGenericWrapperComponents(widget.name, metadata);
590
600
  const exportMembers = this.getWrapperExportMembers(widget.name, metadata);
591
601
  if (docComment) {
@@ -619,6 +629,38 @@ ${widgetPropsContent}
619
629
  }
620
630
  }
621
631
  }
632
+ // Add ApplicationMenu and Menu namespace components
633
+ lines.push(`/**
634
+ * Sets the application-wide menu bar.
635
+ * The menu will appear in the window's title bar on supported platforms.
636
+ * Use Menu.Item, Menu.Section, and Menu.Submenu as children.
637
+ */
638
+ export function ApplicationMenu(props: MenuRootProps): import("react").ReactElement {
639
+ \treturn createElement("ApplicationMenu", props);
640
+ }
641
+
642
+ function MenuItem(props: MenuItemProps): import("react").ReactElement {
643
+ \treturn createElement("Menu.Item", props);
644
+ }
645
+
646
+ function MenuSection(props: MenuSectionProps): import("react").ReactElement {
647
+ \treturn createElement("Menu.Section", props);
648
+ }
649
+
650
+ function MenuSubmenu(props: MenuSubmenuProps): import("react").ReactElement {
651
+ \treturn createElement("Menu.Submenu", props);
652
+ }
653
+
654
+ /**
655
+ * Declarative menu builder for use with PopoverMenu and ApplicationMenu.
656
+ * Use Menu.Item for action items, Menu.Section for groups, Menu.Submenu for nested menus.
657
+ */
658
+ export const Menu = {
659
+ \tItem: MenuItem,
660
+ \tSection: MenuSection,
661
+ \tSubmenu: MenuSubmenu,
662
+ };
663
+ `);
622
664
  return `${lines.join("\n")}\n`;
623
665
  }
624
666
  getWrapperExportMembers(widgetName, metadata) {
@@ -634,6 +676,14 @@ ${widgetPropsContent}
634
676
  else if (isDropDownWidget(widgetName)) {
635
677
  members.push(`Item: ${name}Item`);
636
678
  }
679
+ else if (isStackWidget(widgetName)) {
680
+ members.push(`Page: ${name}Page`);
681
+ }
682
+ else if (isPopoverMenuWidget(widgetName)) {
683
+ members.push(`Item: ${name}Item`);
684
+ members.push(`Section: ${name}Section`);
685
+ members.push(`Submenu: ${name}Submenu`);
686
+ }
637
687
  // Add named child slots
638
688
  for (const slot of metadata.namedChildSlots) {
639
689
  members.push(`${slot.slotName}: ${name}${slot.slotName}`);
@@ -710,6 +760,32 @@ ${widgetPropsContent}
710
760
  lines.push(`\treturn createElement("${name}.Item", props);`);
711
761
  lines.push(`}`);
712
762
  }
763
+ else if (isStackWidget(widgetName)) {
764
+ lines.push(`function ${name}Root(props: StackRootProps & ${name}Props): import("react").ReactElement {`);
765
+ lines.push(`\treturn createElement("${name}.Root", props);`);
766
+ lines.push(`}`);
767
+ lines.push(``);
768
+ lines.push(`function ${name}Page(props: StackPageProps): import("react").ReactElement {`);
769
+ lines.push(`\treturn createElement("${name}.Page", props);`);
770
+ lines.push(`}`);
771
+ }
772
+ else if (isPopoverMenuWidget(widgetName)) {
773
+ lines.push(`function ${name}Root(props: MenuRootProps & ${name}Props): import("react").ReactElement {`);
774
+ lines.push(`\treturn createElement("${name}.Root", props);`);
775
+ lines.push(`}`);
776
+ lines.push(``);
777
+ lines.push(`function ${name}Item(props: MenuItemProps): import("react").ReactElement {`);
778
+ lines.push(`\treturn createElement("Menu.Item", props);`);
779
+ lines.push(`}`);
780
+ lines.push(``);
781
+ lines.push(`function ${name}Section(props: MenuSectionProps): import("react").ReactElement {`);
782
+ lines.push(`\treturn createElement("Menu.Section", props);`);
783
+ lines.push(`}`);
784
+ lines.push(``);
785
+ lines.push(`function ${name}Submenu(props: MenuSubmenuProps): import("react").ReactElement {`);
786
+ lines.push(`\treturn createElement("Menu.Submenu", props);`);
787
+ lines.push(`}`);
788
+ }
713
789
  for (const slot of metadata.namedChildSlots) {
714
790
  lines.push(``);
715
791
  lines.push(`function ${name}${slot.slotName}(props: SlotProps): import("react").ReactElement {`);
@@ -734,7 +810,9 @@ ${widgetPropsContent}
734
810
  isColumnViewWidget(widget.name) ||
735
811
  isDropDownWidget(widget.name) ||
736
812
  isGridWidget(widget.name) ||
737
- isNotebookWidget(widget.name);
813
+ isNotebookWidget(widget.name) ||
814
+ isStackWidget(widget.name) ||
815
+ isPopoverMenuWidget(widget.name);
738
816
  if (hasMeaningfulSlots) {
739
817
  elements.push(`"${widgetName}.Root": ${propsName};`);
740
818
  }
@@ -760,7 +838,16 @@ ${widgetPropsContent}
760
838
  if (isNotebookWidget(widget.name)) {
761
839
  elements.push(`"${widgetName}.Page": NotebookPageProps;`);
762
840
  }
841
+ if (isStackWidget(widget.name)) {
842
+ elements.push(`"${widgetName}.Page": StackPageProps;`);
843
+ }
763
844
  }
845
+ // Add shared Menu elements (used by PopoverMenu, PopoverMenuBar, and ApplicationMenu)
846
+ elements.push(`"Menu.Item": MenuItemProps;`);
847
+ elements.push(`"Menu.Section": MenuSectionProps;`);
848
+ elements.push(`"Menu.Submenu": MenuSubmenuProps;`);
849
+ // Add ApplicationMenu element
850
+ elements.push(`ApplicationMenu: MenuRootProps;`);
764
851
  return `
765
852
  declare global {
766
853
  \tnamespace React {
@@ -18,6 +18,26 @@ export interface PageContainer {
18
18
  removePage(child: Gtk.Widget): void;
19
19
  updatePageLabel(child: Gtk.Widget, label: string): void;
20
20
  }
21
+ /**
22
+ * Props for Stack pages.
23
+ */
24
+ export interface StackPageProps {
25
+ name?: string;
26
+ title?: string;
27
+ iconName?: string;
28
+ needsAttention?: boolean;
29
+ visible?: boolean;
30
+ useUnderline?: boolean;
31
+ }
32
+ /**
33
+ * Interface for Stack containers.
34
+ */
35
+ export interface StackPageContainer {
36
+ addStackPage(child: Gtk.Widget, props: StackPageProps): void;
37
+ insertStackPageBefore(child: Gtk.Widget, props: StackPageProps, beforeChild: Gtk.Widget): void;
38
+ removeStackPage(child: Gtk.Widget): void;
39
+ updateStackPageProps(child: Gtk.Widget, props: StackPageProps): void;
40
+ }
21
41
  /**
22
42
  * Interface for grid-based containers.
23
43
  */
@@ -46,6 +66,7 @@ export interface ColumnContainer {
46
66
  }
47
67
  export declare const isChildContainer: (node: Node) => node is Node & ChildContainer;
48
68
  export declare const isPageContainer: (node: Node) => node is Node & PageContainer;
69
+ export declare const isStackPageContainer: (node: Node) => node is Node & StackPageContainer;
49
70
  export declare const isGridContainer: (node: Node) => node is Node & GridContainer;
50
71
  export declare const isItemContainer: <T>(node: Node) => node is Node & ItemContainer<T>;
51
72
  export declare const isColumnContainer: (node: Node) => node is Node & ColumnContainer;
@@ -1,5 +1,6 @@
1
1
  export const isChildContainer = (node) => "attachChild" in node && "detachChild" in node && "insertChildBefore" in node;
2
2
  export const isPageContainer = (node) => "addPage" in node && "removePage" in node && "insertPageBefore" in node && "updatePageLabel" in node;
3
+ export const isStackPageContainer = (node) => "addStackPage" in node && "removeStackPage" in node && "updateStackPageProps" in node;
3
4
  export const isGridContainer = (node) => "attachToGrid" in node && "removeFromGrid" in node;
4
5
  export const isItemContainer = (node) => "addItem" in node && "insertItemBefore" in node && "removeItem" in node;
5
6
  export const isColumnContainer = (node) => "addColumn" in node && "removeColumn" in node && "getSortFn" in node;
package/dist/factory.js CHANGED
@@ -6,10 +6,12 @@ import { FlowBoxNode } from "./nodes/flow-box.js";
6
6
  import { GridChildNode, GridNode } from "./nodes/grid.js";
7
7
  import { ListItemNode, ListViewNode } from "./nodes/list.js";
8
8
  import { ListBoxNode } from "./nodes/list-box.js";
9
+ import { ApplicationMenuNode, MenuItemNode, MenuSectionNode, MenuSubmenuNode, PopoverMenuBarNode, PopoverMenuRootNode, } from "./nodes/menu.js";
9
10
  import { NotebookNode, NotebookPageNode } from "./nodes/notebook.js";
10
11
  import { OverlayNode } from "./nodes/overlay.js";
11
12
  import { RootNode } from "./nodes/root.js";
12
13
  import { SlotNode } from "./nodes/slot.js";
14
+ import { StackNode, StackPageNode } from "./nodes/stack.js";
13
15
  import { TextViewNode } from "./nodes/text-view.js";
14
16
  import { WidgetNode } from "./nodes/widget.js";
15
17
  import { WindowNode } from "./nodes/window.js";
@@ -23,11 +25,18 @@ const NODE_CLASSES = [
23
25
  DropDownItemNode,
24
26
  GridChildNode,
25
27
  NotebookPageNode,
28
+ StackPageNode,
29
+ MenuItemNode,
30
+ MenuSectionNode,
31
+ MenuSubmenuNode,
26
32
  SlotNode,
27
33
  // Specialized widget nodes
28
34
  WindowNode,
29
35
  AboutDialogNode,
30
36
  TextViewNode,
37
+ ApplicationMenuNode,
38
+ PopoverMenuRootNode,
39
+ PopoverMenuBarNode,
31
40
  // Container nodes
32
41
  ActionBarNode,
33
42
  FlowBoxNode,
@@ -38,13 +47,16 @@ const NODE_CLASSES = [
38
47
  ColumnViewNode,
39
48
  ListViewNode,
40
49
  NotebookNode,
50
+ StackNode,
41
51
  // Catch-all (must be last)
42
52
  WidgetNode,
43
53
  ];
44
54
  export const createNode = (type, props, existingWidget) => {
45
55
  for (const NodeClass of NODE_CLASSES) {
46
56
  if (NodeClass.matches(type, existingWidget)) {
47
- return new NodeClass(type, props, existingWidget);
57
+ const node = new NodeClass(type, existingWidget);
58
+ node.initialize(props);
59
+ return node;
48
60
  }
49
61
  }
50
62
  throw new Error(`No matching node class for type: ${type}`);
@@ -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 { ColumnViewColumnProps, ColumnViewRootProps, GridChildProps, ListItemProps, ListViewRenderProps, NotebookPageProps, SlotProps } from "../types.js";
7
- export { ColumnViewColumnProps, ColumnViewRootProps, GridChildProps, ListItemProps, ListViewRenderProps, NotebookPageProps, SlotProps, };
6
+ import type { ColumnViewColumnProps, ColumnViewRootProps, GridChildProps, ListItemProps, ListViewRenderProps, MenuItemProps, MenuRootProps, MenuSectionProps, MenuSubmenuProps, NotebookPageProps, SlotProps, StackPageProps, StackRootProps } from "../types.js";
7
+ export { ColumnViewColumnProps, ColumnViewRootProps, GridChildProps, ListItemProps, ListViewRenderProps, MenuItemProps, MenuRootProps, MenuSectionProps, MenuSubmenuProps, NotebookPageProps, SlotProps, StackPageProps, StackRootProps, };
8
8
  /**
9
9
  * The base class for all widgets.
10
10
  *
@@ -10043,6 +10043,10 @@ export declare const Popover: {
10043
10043
  Child: "Popover.Child";
10044
10044
  DefaultWidget: "Popover.DefaultWidget";
10045
10045
  };
10046
+ declare function PopoverMenuRoot(props: MenuRootProps & PopoverMenuProps): import("react").ReactElement;
10047
+ declare function PopoverMenuItem(props: MenuItemProps): import("react").ReactElement;
10048
+ declare function PopoverMenuSection(props: MenuSectionProps): import("react").ReactElement;
10049
+ declare function PopoverMenuSubmenu(props: MenuSubmenuProps): import("react").ReactElement;
10046
10050
  /**
10047
10051
  * A subclass of `GtkPopover` that implements menu behavior.
10048
10052
  *
@@ -10161,7 +10165,12 @@ export declare const Popover: {
10161
10165
  * [enum@Gtk.AccessibleRole.checkbox] or [enum@Gtk.AccessibleRole.menu_item_radio]
10162
10166
  * roles, depending on the action they are connected to.
10163
10167
  */
10164
- export declare const PopoverMenu: "PopoverMenu";
10168
+ export declare const PopoverMenu: {
10169
+ Root: typeof PopoverMenuRoot;
10170
+ Item: typeof PopoverMenuItem;
10171
+ Section: typeof PopoverMenuSection;
10172
+ Submenu: typeof PopoverMenuSubmenu;
10173
+ };
10165
10174
  /**
10166
10175
  * Presents a horizontal bar of items that pop up menus when clicked.
10167
10176
  *
@@ -10984,6 +10993,9 @@ export declare const SpinButton: "SpinButton";
10984
10993
  * `GtkSpinner` uses the [enum@Gtk.AccessibleRole.progress_bar] role.
10985
10994
  */
10986
10995
  export declare const Spinner: "Spinner";
10996
+ declare function StackRoot(props: StackRootProps & StackProps): import("react").ReactElement;
10997
+ declare function StackPage(props: StackPageProps): import("react").ReactElement;
10998
+ declare function StackVisibleChild(props: SlotProps): import("react").ReactElement;
10987
10999
  /**
10988
11000
  * Shows one of its children at a time.
10989
11001
  *
@@ -11035,8 +11047,9 @@ export declare const Spinner: "Spinner";
11035
11047
  * pages, which are the accessible parent objects of the child widgets.
11036
11048
  */
11037
11049
  export declare const Stack: {
11038
- Root: "Stack.Root";
11039
- VisibleChild: "Stack.VisibleChild";
11050
+ Root: typeof StackRoot;
11051
+ Page: typeof StackPage;
11052
+ VisibleChild: typeof StackVisibleChild;
11040
11053
  };
11041
11054
  /**
11042
11055
  * Uses a sidebar to switch between `GtkStack` pages.
@@ -11731,6 +11744,24 @@ export declare const WindowControls: "WindowControls";
11731
11744
  * role.
11732
11745
  */
11733
11746
  export declare const WindowHandle: "WindowHandle";
11747
+ /**
11748
+ * Sets the application-wide menu bar.
11749
+ * The menu will appear in the window's title bar on supported platforms.
11750
+ * Use Menu.Item, Menu.Section, and Menu.Submenu as children.
11751
+ */
11752
+ export declare function ApplicationMenu(props: MenuRootProps): import("react").ReactElement;
11753
+ declare function MenuItem(props: MenuItemProps): import("react").ReactElement;
11754
+ declare function MenuSection(props: MenuSectionProps): import("react").ReactElement;
11755
+ declare function MenuSubmenu(props: MenuSubmenuProps): import("react").ReactElement;
11756
+ /**
11757
+ * Declarative menu builder for use with PopoverMenu and ApplicationMenu.
11758
+ * Use Menu.Item for action items, Menu.Section for groups, Menu.Submenu for nested menus.
11759
+ */
11760
+ export declare const Menu: {
11761
+ Item: typeof MenuItem;
11762
+ Section: typeof MenuSection;
11763
+ Submenu: typeof MenuSubmenu;
11764
+ };
11734
11765
  declare global {
11735
11766
  namespace React {
11736
11767
  namespace JSX {
@@ -11839,7 +11870,7 @@ declare global {
11839
11870
  "Popover.Root": PopoverProps;
11840
11871
  "Popover.Child": SlotProps;
11841
11872
  "Popover.DefaultWidget": SlotProps;
11842
- PopoverMenu: PopoverMenuProps;
11873
+ "PopoverMenu.Root": PopoverMenuProps;
11843
11874
  PopoverMenuBar: PopoverMenuBarProps;
11844
11875
  PrintUnixDialog: PrintUnixDialogProps;
11845
11876
  ProgressBar: ProgressBarProps;
@@ -11865,6 +11896,7 @@ declare global {
11865
11896
  Spinner: SpinnerProps;
11866
11897
  "Stack.Root": StackProps;
11867
11898
  "Stack.VisibleChild": SlotProps;
11899
+ "Stack.Page": StackPageProps;
11868
11900
  "StackSidebar.Root": StackSidebarProps;
11869
11901
  "StackSidebar.Stack": SlotProps;
11870
11902
  "StackSwitcher.Root": StackSwitcherProps;
@@ -11885,6 +11917,10 @@ declare global {
11885
11917
  WindowControls: WindowControlsProps;
11886
11918
  WindowHandle: WindowHandleProps;
11887
11919
  "WindowHandle.Child": SlotProps;
11920
+ "Menu.Item": MenuItemProps;
11921
+ "Menu.Section": MenuSectionProps;
11922
+ "Menu.Submenu": MenuSubmenuProps;
11923
+ ApplicationMenu: MenuRootProps;
11888
11924
  }
11889
11925
  }
11890
11926
  }
@@ -4095,6 +4095,18 @@ export const Popover = {
4095
4095
  Child: "Popover.Child",
4096
4096
  DefaultWidget: "Popover.DefaultWidget",
4097
4097
  };
4098
+ function PopoverMenuRoot(props) {
4099
+ return createElement("PopoverMenu.Root", props);
4100
+ }
4101
+ function PopoverMenuItem(props) {
4102
+ return createElement("Menu.Item", props);
4103
+ }
4104
+ function PopoverMenuSection(props) {
4105
+ return createElement("Menu.Section", props);
4106
+ }
4107
+ function PopoverMenuSubmenu(props) {
4108
+ return createElement("Menu.Submenu", props);
4109
+ }
4098
4110
  /**
4099
4111
  * A subclass of `GtkPopover` that implements menu behavior.
4100
4112
  *
@@ -4213,7 +4225,12 @@ export const Popover = {
4213
4225
  * [enum@Gtk.AccessibleRole.checkbox] or [enum@Gtk.AccessibleRole.menu_item_radio]
4214
4226
  * roles, depending on the action they are connected to.
4215
4227
  */
4216
- export const PopoverMenu = "PopoverMenu";
4228
+ export const PopoverMenu = {
4229
+ Root: PopoverMenuRoot,
4230
+ Item: PopoverMenuItem,
4231
+ Section: PopoverMenuSection,
4232
+ Submenu: PopoverMenuSubmenu,
4233
+ };
4217
4234
  /**
4218
4235
  * Presents a horizontal bar of items that pop up menus when clicked.
4219
4236
  *
@@ -5036,6 +5053,15 @@ export const SpinButton = "SpinButton";
5036
5053
  * `GtkSpinner` uses the [enum@Gtk.AccessibleRole.progress_bar] role.
5037
5054
  */
5038
5055
  export const Spinner = "Spinner";
5056
+ function StackRoot(props) {
5057
+ return createElement("Stack.Root", props);
5058
+ }
5059
+ function StackPage(props) {
5060
+ return createElement("Stack.Page", props);
5061
+ }
5062
+ function StackVisibleChild(props) {
5063
+ return createElement("Stack.VisibleChild", props);
5064
+ }
5039
5065
  /**
5040
5066
  * Shows one of its children at a time.
5041
5067
  *
@@ -5087,8 +5113,9 @@ export const Spinner = "Spinner";
5087
5113
  * pages, which are the accessible parent objects of the child widgets.
5088
5114
  */
5089
5115
  export const Stack = {
5090
- Root: "Stack.Root",
5091
- VisibleChild: "Stack.VisibleChild",
5116
+ Root: StackRoot,
5117
+ Page: StackPage,
5118
+ VisibleChild: StackVisibleChild,
5092
5119
  };
5093
5120
  /**
5094
5121
  * Uses a sidebar to switch between `GtkStack` pages.
@@ -5783,3 +5810,29 @@ export const WindowControls = "WindowControls";
5783
5810
  * role.
5784
5811
  */
5785
5812
  export const WindowHandle = "WindowHandle";
5813
+ /**
5814
+ * Sets the application-wide menu bar.
5815
+ * The menu will appear in the window's title bar on supported platforms.
5816
+ * Use Menu.Item, Menu.Section, and Menu.Submenu as children.
5817
+ */
5818
+ export function ApplicationMenu(props) {
5819
+ return createElement("ApplicationMenu", props);
5820
+ }
5821
+ function MenuItem(props) {
5822
+ return createElement("Menu.Item", props);
5823
+ }
5824
+ function MenuSection(props) {
5825
+ return createElement("Menu.Section", props);
5826
+ }
5827
+ function MenuSubmenu(props) {
5828
+ return createElement("Menu.Submenu", props);
5829
+ }
5830
+ /**
5831
+ * Declarative menu builder for use with PopoverMenu and ApplicationMenu.
5832
+ * Use Menu.Item for action items, Menu.Section for groups, Menu.Submenu for nested menus.
5833
+ */
5834
+ export const Menu = {
5835
+ Item: MenuItem,
5836
+ Section: MenuSection,
5837
+ Submenu: MenuSubmenu,
5838
+ };
package/dist/node.d.ts CHANGED
@@ -1,12 +1,21 @@
1
1
  import * as Gtk from "@gtkx/ffi/gtk";
2
2
  import type { Props, ROOT_NODE_CONTAINER } from "./factory.js";
3
- export declare abstract class Node<T extends Gtk.Widget | undefined = Gtk.Widget | undefined> {
3
+ export declare abstract class Node<T extends Gtk.Widget | undefined = Gtk.Widget | undefined, S extends object | undefined = object | undefined> {
4
4
  static matches(_type: string, _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;
8
+ protected nodeType: string;
9
+ private _state;
10
+ protected get state(): S;
11
+ protected set state(value: S);
8
12
  protected isVirtual(): boolean;
9
- constructor(type: string, props: Props, existingWidget?: Gtk.Widget);
13
+ constructor(type: string, existingWidget?: Gtk.Widget);
14
+ /**
15
+ * Initializes the node with props. Called by the reconciler after construction.
16
+ * Subclasses can override to perform custom initialization.
17
+ */
18
+ initialize(props: Props): void;
10
19
  protected createWidget(type: string, props: Props): T;
11
20
  getWidget(): T;
12
21
  appendChild(child: Node): void;
package/dist/node.js CHANGED
@@ -14,18 +14,37 @@ export class Node {
14
14
  return false;
15
15
  }
16
16
  signalHandlers = new Map();
17
- widget;
17
+ widget = undefined;
18
18
  widgetType;
19
+ nodeType;
20
+ _state = null;
21
+ get state() {
22
+ if (this._state === null) {
23
+ throw new Error(`${this.constructor.name} not initialized`);
24
+ }
25
+ return this._state;
26
+ }
27
+ set state(value) {
28
+ this._state = value;
29
+ }
19
30
  isVirtual() {
20
31
  return false;
21
32
  }
22
- constructor(type, props, existingWidget) {
33
+ constructor(type, existingWidget) {
34
+ this.nodeType = type;
23
35
  this.widgetType = type.split(".")[0] || type;
24
36
  if (existingWidget) {
25
37
  this.widget = existingWidget;
26
- return;
27
38
  }
28
- this.widget = (this.isVirtual() ? undefined : this.createWidget(type, props));
39
+ }
40
+ /**
41
+ * Initializes the node with props. Called by the reconciler after construction.
42
+ * Subclasses can override to perform custom initialization.
43
+ */
44
+ initialize(props) {
45
+ if (!this.widget && !this.isVirtual()) {
46
+ this.widget = this.createWidget(this.nodeType, props);
47
+ }
29
48
  this.updateProps({}, props);
30
49
  }
31
50
  createWidget(type, props) {
@@ -1,25 +1,28 @@
1
1
  import * as Gtk from "@gtkx/ffi/gtk";
2
+ import type Reconciler from "react-reconciler";
2
3
  import { type ColumnContainer, type ItemContainer } from "../container-interfaces.js";
3
4
  import type { Props } from "../factory.js";
4
5
  import { Node } from "../node.js";
5
- import type { ColumnSortFn } from "../types.js";
6
- export declare class ColumnViewNode extends Node<Gtk.ColumnView> implements ItemContainer<unknown>, ColumnContainer {
6
+ import type { ColumnSortFn, RenderItemFn } from "../types.js";
7
+ interface ColumnViewState {
8
+ stringList: Gtk.StringList;
9
+ selectionModel: Gtk.SingleSelection;
10
+ sortListModel: Gtk.SortListModel;
11
+ items: unknown[];
12
+ columns: ColumnViewColumnNode[];
13
+ committedLength: number;
14
+ sortColumn: string | null;
15
+ sortOrder: Gtk.SortType;
16
+ sortFn: ColumnSortFn<unknown, string> | null;
17
+ isSorting: boolean;
18
+ onSortChange: ((column: string | null, order: Gtk.SortType) => void) | null;
19
+ sorterChangedHandlerId: number | null;
20
+ lastNotifiedColumn: string | null;
21
+ lastNotifiedOrder: Gtk.SortType;
22
+ }
23
+ export declare class ColumnViewNode extends Node<Gtk.ColumnView, ColumnViewState> implements ItemContainer<unknown>, ColumnContainer {
7
24
  static matches(type: string): boolean;
8
- private stringList;
9
- private selectionModel;
10
- private sortListModel;
11
- private items;
12
- private columns;
13
- private committedLength;
14
- private sortColumn;
15
- private sortOrder;
16
- private sortFn;
17
- private isSorting;
18
- private onSortChange;
19
- private sorterChangedHandlerId;
20
- private lastNotifiedColumn;
21
- private lastNotifiedOrder;
22
- constructor(type: string, props: Props);
25
+ initialize(props: Props): void;
23
26
  private connectSorterChangedSignal;
24
27
  private waitForSortComplete;
25
28
  private disconnectSorterChangedSignal;
@@ -39,17 +42,23 @@ export declare class ColumnViewNode extends Node<Gtk.ColumnView> implements Item
39
42
  protected consumedProps(): Set<string>;
40
43
  updateProps(oldProps: Props, newProps: Props): void;
41
44
  }
42
- export declare class ColumnViewColumnNode extends Node {
45
+ interface ListItemInfo {
46
+ box: Gtk.Box;
47
+ fiberRoot: Reconciler.FiberRoot;
48
+ }
49
+ interface ColumnViewColumnState {
50
+ column: Gtk.ColumnViewColumn;
51
+ factory: Gtk.SignalListItemFactory;
52
+ renderCell: RenderItemFn<unknown>;
53
+ columnId: string | null;
54
+ sorter: Gtk.CustomSorter | null;
55
+ listItemCache: Map<number, ListItemInfo>;
56
+ }
57
+ export declare class ColumnViewColumnNode extends Node<never, ColumnViewColumnState> {
43
58
  static matches(type: string): boolean;
44
59
  protected isVirtual(): boolean;
45
- private column;
46
- private factory;
47
- private renderCell;
48
60
  private columnView;
49
- private listItemCache;
50
- private columnId;
51
- private sorter;
52
- constructor(type: string, props: Props);
61
+ initialize(props: Props): void;
53
62
  getColumn(): Gtk.ColumnViewColumn;
54
63
  getId(): string | null;
55
64
  setColumnView(columnView: ColumnViewNode | null): void;
@@ -64,9 +73,10 @@ export declare class ColumnViewItemNode extends Node {
64
73
  static matches(type: string): boolean;
65
74
  protected isVirtual(): boolean;
66
75
  private item;
67
- constructor(type: string, props: Props);
76
+ initialize(props: Props): void;
68
77
  getItem(): unknown;
69
78
  attachToParent(parent: Node): void;
70
79
  attachToParentBefore(parent: Node, before: Node): void;
71
80
  detachFromParent(parent: Node): void;
72
81
  }
82
+ export {};