@gtkx/react 0.9.4 → 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 +914 -808
  11. package/dist/generated/jsx.js +123 -358
  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
package/dist/portal.js CHANGED
@@ -1,23 +1,26 @@
1
- import { ROOT_NODE_CONTAINER } from "./factory.js";
2
1
  /**
3
- * Creates a portal that renders children into a different GTK widget container.
2
+ * Creates a React portal for rendering children into a different part of the widget tree.
4
3
  *
5
- * Similar to ReactDOM.createPortal, this allows you to render a subtree into
6
- * a different part of the widget tree.
4
+ * Portals are useful for rendering dialogs, tooltips, or other floating content
5
+ * that should visually appear outside its parent component's boundaries.
7
6
  *
8
- * When called without a container argument, the portal renders at the root level.
9
- * This is useful for dialogs which don't need a parent container.
10
- *
11
- * Implementation note: ReactPortal is an opaque type, so we manually construct
12
- * the internal representation required by custom reconcilers.
7
+ * @param children - The React elements to render in the portal
8
+ * @param container - The target container widget to render into
9
+ * @param key - Optional key for the portal element
10
+ * @returns A ReactPortal element
13
11
  *
14
12
  * @example
15
13
  * ```tsx
16
- * // Render dialog at root level (no container needed)
17
- * {createPortal(<AboutDialog programName="My App" />)}
14
+ * import { createPortal } from "@gtkx/react";
18
15
  *
19
- * // Render into a specific container
20
- * {createPortal(<Label label="This is in the Box" />, boxRef.current)}
16
+ * const Modal = ({ container, children }) => {
17
+ * return createPortal(
18
+ * <GtkWindow modal>
19
+ * {children}
20
+ * </GtkWindow>,
21
+ * container
22
+ * );
23
+ * };
21
24
  * ```
22
25
  */
23
26
  export const createPortal = (children, container, key) => {
@@ -25,7 +28,7 @@ export const createPortal = (children, container, key) => {
25
28
  $$typeof: Symbol.for("react.portal"),
26
29
  key: key ?? null,
27
30
  children,
28
- containerInfo: container ?? ROOT_NODE_CONTAINER,
31
+ containerInfo: container,
29
32
  implementation: null,
30
33
  };
31
34
  };
@@ -5,9 +5,5 @@ declare class Reconciler {
5
5
  getInstance(): ReconcilerInstance;
6
6
  private injectDevTools;
7
7
  }
8
- /**
9
- * The singleton GTKX React reconciler instance.
10
- * @private This is an internal API used only by @gtkx/testing. Do not use directly.
11
- */
12
8
  export declare const reconciler: Reconciler;
13
9
  export {};
@@ -1,14 +1,10 @@
1
1
  import ReactReconciler from "react-reconciler";
2
2
  import packageJson from "../package.json" with { type: "json" };
3
- import { createNode } from "./factory.js";
4
3
  import { createHostConfig } from "./host-config.js";
5
4
  class Reconciler {
6
5
  instance;
7
6
  constructor() {
8
- const createNodeFromContainer = (container) => {
9
- return createNode(container.constructor.name, {}, container);
10
- };
11
- this.instance = ReactReconciler(createHostConfig(createNodeFromContainer));
7
+ this.instance = ReactReconciler(createHostConfig());
12
8
  this.injectDevTools();
13
9
  }
14
10
  getInstance() {
@@ -24,8 +20,4 @@ class Reconciler {
24
20
  });
25
21
  }
26
22
  }
27
- /**
28
- * The singleton GTKX React reconciler instance.
29
- * @private This is an internal API used only by @gtkx/testing. Do not use directly.
30
- */
31
23
  export const reconciler = new Reconciler();
@@ -0,0 +1,8 @@
1
+ import type { Node } from "./node.js";
2
+ import type { Container, Props } from "./types.js";
3
+ type NodeClass<T = unknown, P = Props> = {
4
+ new (typeName: string, props: P, container: T, rootContainer?: Container): Node<T, P>;
5
+ } & Omit<typeof Node, "prototype">;
6
+ export declare const NODE_CLASSES: NodeClass[];
7
+ export declare const registerNodeClass: <T, P>(nodeClass: NodeClass<T, P>) => void;
8
+ export {};
@@ -0,0 +1,5 @@
1
+ export const NODE_CLASSES = [];
2
+ export const registerNodeClass = (nodeClass) => {
3
+ NODE_CLASSES.push(nodeClass);
4
+ NODE_CLASSES.sort((a, b) => a.priority - b.priority);
5
+ };
package/dist/render.d.ts CHANGED
@@ -1,22 +1,118 @@
1
1
  import type * as Gio from "@gtkx/ffi/gio";
2
- import type { ReactNode } from "react";
3
- export declare const getContainer: () => unknown;
2
+ import type * as Gtk from "@gtkx/ffi/gtk";
3
+ import { type ReactNode } from "react";
4
4
  /**
5
- * Renders a React element tree as a GTK application.
6
- * This is the main entry point for GTKX applications.
5
+ * React Context providing access to the GTK Application instance.
6
+ *
7
+ * Use {@link useApplication} to access the application in components.
7
8
  *
8
9
  * @example
9
10
  * ```tsx
10
- * render(
11
- * <ApplicationWindow title="My App">
12
- * Hello, GTKX!
13
- * </ApplicationWindow>,
14
- * "com.example.myapp"
15
- * );
11
+ * const App = () => {
12
+ * const app = useApplication();
13
+ * console.log(app.applicationId);
14
+ * return <GtkLabel label="Hello" />;
15
+ * };
16
+ * ```
17
+ */
18
+ export declare const ApplicationContext: React.Context<Gtk.Application | null>;
19
+ /**
20
+ * Hook to access the GTK Application instance.
21
+ *
22
+ * Must be called within a component rendered by {@link render}.
23
+ * Throws an error if called outside the application context.
24
+ *
25
+ * @returns The GTK Application instance
26
+ *
27
+ * @example
28
+ * ```tsx
29
+ * const MyComponent = () => {
30
+ * const app = useApplication();
31
+ * return <GtkLabel label={app.applicationId} />;
32
+ * };
16
33
  * ```
17
34
  *
35
+ * @see {@link ApplicationContext} for the underlying context
36
+ */
37
+ export declare const useApplication: () => Gtk.Application;
38
+ /**
39
+ * Sets the hot reloading state.
40
+ *
41
+ * Used internally by the dev server to prevent quit() from closing
42
+ * the application during HMR updates.
43
+ *
44
+ * @internal
45
+ */
46
+ export declare const setHotReloading: (value: boolean) => void;
47
+ /**
48
+ * Renders a React element tree into a GTK4 application window.
49
+ *
50
+ * This is the main entry point for GTKX applications. It initializes the GTK4
51
+ * runtime, creates an application container, and begins the React reconciliation
52
+ * process.
53
+ *
18
54
  * @param element - The root React element to render
19
- * @param appId - The application ID (e.g., "com.example.myapp")
20
- * @param flags - Optional GIO application flags
55
+ * @param appId - Application ID in reverse domain notation (e.g., "com.example.myapp")
56
+ * @param flags - Optional GIO application flags for customizing behavior
57
+ *
58
+ * @example
59
+ * ```tsx
60
+ * import { render, quit } from "@gtkx/react";
61
+ *
62
+ * const App = () => (
63
+ * <GtkApplicationWindow title="My App" onCloseRequest={quit}>
64
+ * <GtkLabel label="Hello, GTKX!" />
65
+ * </GtkApplicationWindow>
66
+ * );
67
+ *
68
+ * render(<App />, "com.example.myapp");
69
+ * ```
70
+ *
71
+ * @see {@link quit} for shutting down the application
72
+ * @see {@link update} for hot-reloading the rendered tree
21
73
  */
22
74
  export declare const render: (element: ReactNode, appId: string, flags?: Gio.ApplicationFlags) => void;
75
+ /**
76
+ * Updates the rendered React element tree.
77
+ *
78
+ * Used primarily for hot module replacement (HMR) during development.
79
+ * Replaces the current component tree with a new element without
80
+ * reinitializing the GTK application.
81
+ *
82
+ * @param element - The new root React element to render
83
+ *
84
+ * @example
85
+ * ```tsx
86
+ * // In HMR handler
87
+ * if (import.meta.hot) {
88
+ * import.meta.hot.accept(() => {
89
+ * update(<App />);
90
+ * });
91
+ * }
92
+ * ```
93
+ *
94
+ * @see {@link render} for initial rendering
95
+ */
96
+ export declare const update: (element: ReactNode) => Promise<void>;
97
+ /**
98
+ * Gracefully shuts down the GTK application.
99
+ *
100
+ * Unmounts the React component tree and stops the GTK main loop.
101
+ * Typically used as the `onCloseRequest` handler for the application window.
102
+ *
103
+ * @returns `false` to allow GTK to close the window
104
+ *
105
+ * @example
106
+ * ```tsx
107
+ * import { quit } from "@gtkx/react";
108
+ *
109
+ * const App = () => (
110
+ * <GtkApplicationWindow title="My App" onCloseRequest={quit}>
111
+ * <GtkButton label="Quit" onClicked={quit} />
112
+ * </GtkApplicationWindow>
113
+ * );
114
+ * ```
115
+ *
116
+ * @see {@link render} for starting the application
117
+ */
118
+ export declare const quit: () => boolean;
package/dist/render.js CHANGED
@@ -1,35 +1,159 @@
1
- import { start } from "@gtkx/ffi";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { discardAllBatches, start, stop } from "@gtkx/ffi";
3
+ import { createContext, useContext } from "react";
2
4
  import { formatBoundaryError, formatRenderError } from "./errors.js";
3
- import { ROOT_NODE_CONTAINER } from "./factory.js";
4
5
  import { reconciler } from "./reconciler.js";
6
+ /**
7
+ * React Context providing access to the GTK Application instance.
8
+ *
9
+ * Use {@link useApplication} to access the application in components.
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * const App = () => {
14
+ * const app = useApplication();
15
+ * console.log(app.applicationId);
16
+ * return <GtkLabel label="Hello" />;
17
+ * };
18
+ * ```
19
+ */
20
+ export const ApplicationContext = createContext(null);
21
+ /**
22
+ * Hook to access the GTK Application instance.
23
+ *
24
+ * Must be called within a component rendered by {@link render}.
25
+ * Throws an error if called outside the application context.
26
+ *
27
+ * @returns The GTK Application instance
28
+ *
29
+ * @example
30
+ * ```tsx
31
+ * const MyComponent = () => {
32
+ * const app = useApplication();
33
+ * return <GtkLabel label={app.applicationId} />;
34
+ * };
35
+ * ```
36
+ *
37
+ * @see {@link ApplicationContext} for the underlying context
38
+ */
39
+ export const useApplication = () => {
40
+ const context = useContext(ApplicationContext);
41
+ if (!context) {
42
+ throw new Error("Expected ApplicationContext: useApplication must be called within Application");
43
+ }
44
+ return context;
45
+ };
5
46
  let container = null;
6
- export const getContainer = () => container;
47
+ let app = null;
48
+ let isHotReloading = false;
49
+ /**
50
+ * Sets the hot reloading state.
51
+ *
52
+ * Used internally by the dev server to prevent quit() from closing
53
+ * the application during HMR updates.
54
+ *
55
+ * @internal
56
+ */
57
+ export const setHotReloading = (value) => {
58
+ isHotReloading = value;
59
+ };
7
60
  /**
8
- * Renders a React element tree as a GTK application.
9
- * This is the main entry point for GTKX applications.
61
+ * Renders a React element tree into a GTK4 application window.
62
+ *
63
+ * This is the main entry point for GTKX applications. It initializes the GTK4
64
+ * runtime, creates an application container, and begins the React reconciliation
65
+ * process.
66
+ *
67
+ * @param element - The root React element to render
68
+ * @param appId - Application ID in reverse domain notation (e.g., "com.example.myapp")
69
+ * @param flags - Optional GIO application flags for customizing behavior
10
70
  *
11
71
  * @example
12
72
  * ```tsx
13
- * render(
14
- * <ApplicationWindow title="My App">
15
- * Hello, GTKX!
16
- * </ApplicationWindow>,
17
- * "com.example.myapp"
73
+ * import { render, quit } from "@gtkx/react";
74
+ *
75
+ * const App = () => (
76
+ * <GtkApplicationWindow title="My App" onCloseRequest={quit}>
77
+ * <GtkLabel label="Hello, GTKX!" />
78
+ * </GtkApplicationWindow>
18
79
  * );
80
+ *
81
+ * render(<App />, "com.example.myapp");
19
82
  * ```
20
83
  *
21
- * @param element - The root React element to render
22
- * @param appId - The application ID (e.g., "com.example.myapp")
23
- * @param flags - Optional GIO application flags
84
+ * @see {@link quit} for shutting down the application
85
+ * @see {@link update} for hot-reloading the rendered tree
24
86
  */
25
87
  export const render = (element, appId, flags) => {
26
- start(appId, flags);
88
+ app = start(appId, flags);
27
89
  const instance = reconciler.getInstance();
28
- container = instance.createContainer(ROOT_NODE_CONTAINER, 0, null, false, null, "", (error) => {
90
+ container = instance.createContainer(app, 0, null, false, null, "", (error) => {
91
+ discardAllBatches();
29
92
  throw formatRenderError(error);
30
93
  }, (error) => {
94
+ discardAllBatches();
31
95
  const formattedError = formatBoundaryError(error);
32
96
  console.error(formattedError.toString());
33
97
  }, () => { }, () => { }, null);
34
- instance.updateContainer(element, container, null, () => { });
98
+ instance.updateContainer(_jsx(ApplicationContext.Provider, { value: app, children: element }), container, null, () => { });
99
+ };
100
+ /**
101
+ * Updates the rendered React element tree.
102
+ *
103
+ * Used primarily for hot module replacement (HMR) during development.
104
+ * Replaces the current component tree with a new element without
105
+ * reinitializing the GTK application.
106
+ *
107
+ * @param element - The new root React element to render
108
+ *
109
+ * @example
110
+ * ```tsx
111
+ * // In HMR handler
112
+ * if (import.meta.hot) {
113
+ * import.meta.hot.accept(() => {
114
+ * update(<App />);
115
+ * });
116
+ * }
117
+ * ```
118
+ *
119
+ * @see {@link render} for initial rendering
120
+ */
121
+ export const update = (element) => {
122
+ return new Promise((resolve) => {
123
+ reconciler
124
+ .getInstance()
125
+ .updateContainer(_jsx(ApplicationContext.Provider, { value: app, children: element }), container, null, resolve);
126
+ });
127
+ };
128
+ /**
129
+ * Gracefully shuts down the GTK application.
130
+ *
131
+ * Unmounts the React component tree and stops the GTK main loop.
132
+ * Typically used as the `onCloseRequest` handler for the application window.
133
+ *
134
+ * @returns `false` to allow GTK to close the window
135
+ *
136
+ * @example
137
+ * ```tsx
138
+ * import { quit } from "@gtkx/react";
139
+ *
140
+ * const App = () => (
141
+ * <GtkApplicationWindow title="My App" onCloseRequest={quit}>
142
+ * <GtkButton label="Quit" onClicked={quit} />
143
+ * </GtkApplicationWindow>
144
+ * );
145
+ * ```
146
+ *
147
+ * @see {@link render} for starting the application
148
+ */
149
+ export const quit = () => {
150
+ if (isHotReloading) {
151
+ return true;
152
+ }
153
+ reconciler.getInstance().updateContainer(null, container, null, () => {
154
+ setTimeout(() => {
155
+ stop();
156
+ }, 0);
157
+ });
158
+ return true;
35
159
  };
@@ -0,0 +1,4 @@
1
+ type Callback = () => void;
2
+ export declare const scheduleAfterCommit: (callback: Callback) => void;
3
+ export declare const flushAfterCommit: () => void;
4
+ export {};
@@ -0,0 +1,10 @@
1
+ const pendingCallbacks = [];
2
+ export const scheduleAfterCommit = (callback) => {
3
+ pendingCallbacks.push(callback);
4
+ };
5
+ export const flushAfterCommit = () => {
6
+ const callbacks = pendingCallbacks.splice(0);
7
+ for (const callback of callbacks) {
8
+ callback();
9
+ }
10
+ };
package/dist/types.d.ts CHANGED
@@ -1,137 +1,4 @@
1
1
  import type * as Gtk from "@gtkx/ffi/gtk";
2
- import type { ReactElement, ReactNode } from "react";
3
- /**
4
- * Props for slot components that accept children.
5
- * Used by container widgets that render child elements in designated slots.
6
- */
7
- export type SlotProps = {
8
- children?: ReactNode;
9
- };
10
- /**
11
- * Props passed to list item components (ListView, GridView, ColumnView).
12
- * @typeParam I - The type of the data item
13
- */
14
- export type ListItemProps<I = unknown> = {
15
- /** Unique identifier for this item. Used for selection. */
16
- id: string;
17
- /** The data item to render. */
18
- item: I;
19
- };
20
- /**
21
- * Props for string list items (DropDown, ComboRow).
22
- * Similar to HTML select option elements.
23
- */
24
- export type StringListItemProps = {
25
- /** Unique identifier for this item. Used for selection. */
26
- id: string;
27
- /** Display text shown in the dropdown. */
28
- label: string;
29
- };
30
- export type GridChildProps = SlotProps & {
31
- column?: number;
32
- row?: number;
33
- columnSpan?: number;
34
- rowSpan?: number;
35
- };
36
- /**
37
- * Render function for ListView/GridView items.
38
- * Called with null during setup (for loading state) and with the actual item during bind.
39
- */
40
- export type RenderItemFn<T> = (item: T | null) => ReactElement;
41
- /**
42
- * Props for ListView and GridView components.
43
- * @typeParam T - The type of the data items in the list
44
- */
45
- export type ListViewRenderProps<T = unknown> = {
46
- /** Render function called for each item in the list. */
47
- renderItem: RenderItemFn<T>;
48
- };
49
- /**
50
- * Props for individual columns in a ColumnView.
51
- * @typeParam T - The type of the data items displayed in the column
52
- */
53
- export type ColumnViewColumnProps<T = unknown> = {
54
- /** The column header title. */
55
- title?: string;
56
- /** Whether the column should expand to fill available space. */
57
- expand?: boolean;
58
- /** Whether the column can be resized by the user. */
59
- resizable?: boolean;
60
- /** Fixed width in pixels. Overrides automatic sizing. */
61
- fixedWidth?: number;
62
- /** Unique identifier for the column. Used for sorting. */
63
- id?: string;
64
- /** Whether this column header can be clicked to trigger sorting. */
65
- sortable?: boolean;
66
- /**
67
- * Render function for column cells.
68
- * Called with null during setup (for loading state) and with the actual item during bind.
69
- * Always annotate your callback parameter type to include null, e.g.: `(item: MyItem | null) => ...`
70
- */
71
- renderCell: (item: T | null) => ReactElement;
72
- };
73
- /**
74
- * Props for the ColumnView root component.
75
- * Sorting is handled by the parent component - sort your items before rendering
76
- * and pass them as ColumnView.Item children in the desired order.
77
- * @typeParam C - The union type of column IDs
78
- */
79
- export type ColumnViewRootProps<C extends string = string> = {
80
- /** The ID of the currently sorted column, or null if unsorted. Controls the sort indicator UI. */
81
- sortColumn?: C | null;
82
- /** The current sort direction. Controls the sort indicator UI. */
83
- sortOrder?: Gtk.SortType;
84
- /** Callback fired when the user clicks a column header to change sort. */
85
- onSortChange?: (column: C | null, order: Gtk.SortType) => void;
86
- };
87
- export type NotebookPageProps = SlotProps & {
88
- label: string;
89
- };
90
- export type StackRootProps = SlotProps & {
91
- visibleChildName?: string;
92
- };
93
- export type StackPageProps = SlotProps & {
94
- name?: string;
95
- title?: string;
96
- iconName?: string;
97
- needsAttention?: boolean;
98
- visible?: boolean;
99
- useUnderline?: boolean;
100
- };
101
- /**
102
- * Props for the Menu.Root component.
103
- * Root container for declarative menu structures.
104
- */
105
- export type MenuRootProps = {
106
- children?: ReactNode;
107
- };
108
- /**
109
- * Props for Menu.Item components.
110
- * Represents a single menu item with an action.
111
- */
112
- export type MenuItemProps = {
113
- /** The visible label for the menu item. */
114
- label: string;
115
- /** Callback invoked when the menu item is activated. */
116
- onActivate?: () => void;
117
- /** Keyboard accelerators for this menu item (e.g., `"<Control>q"` or `["<Control>q", "<Control>w"]`). */
118
- accels?: string | string[];
119
- };
120
- /**
121
- * Props for Menu.Section components.
122
- * Groups related menu items with optional label.
123
- */
124
- export type MenuSectionProps = {
125
- /** Optional section label displayed as a header. */
126
- label?: string;
127
- children?: ReactNode;
128
- };
129
- /**
130
- * Props for Menu.Submenu components.
131
- * Creates a nested submenu with its own items.
132
- */
133
- export type MenuSubmenuProps = {
134
- /** The submenu label shown in parent menu. */
135
- label: string;
136
- children?: ReactNode;
137
- };
2
+ export type Container = Gtk.Widget | Gtk.Application;
3
+ export type Props = Record<string, unknown>;
4
+ export type ContainerClass = typeof Gtk.Widget | typeof Gtk.Application;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gtkx/react",
3
- "version": "0.9.4",
3
+ "version": "0.10.0",
4
4
  "description": "Build GTK4 desktop applications with React and TypeScript",
5
5
  "keywords": [
6
6
  "gtk",
@@ -36,18 +36,18 @@
36
36
  ],
37
37
  "dependencies": {
38
38
  "react-reconciler": "^0.33.0",
39
- "@gtkx/ffi": "0.9.4"
39
+ "@gtkx/ffi": "0.10.0",
40
+ "@gtkx/gir": "0.10.0"
40
41
  },
41
42
  "devDependencies": {
42
- "@gtkx/gir": "0.9.4",
43
- "@gtkx/native": "0.9.4"
43
+ "@types/react-reconciler": "^0.32.3",
44
+ "@gtkx/codegen": "0.0.0"
44
45
  },
45
46
  "peerDependencies": {
46
47
  "react": "^19"
47
48
  },
48
49
  "scripts": {
49
50
  "build": "tsc -b && cp ../../README.md .",
50
- "codegen": "tsx scripts/codegen.ts",
51
- "test": "../../scripts/run-tests.sh"
51
+ "codegen": "gtkx-codegen jsx --girs-dir ../../girs --output-dir src/generated"
52
52
  }
53
53
  }
package/dist/batch.d.ts DELETED
@@ -1,5 +0,0 @@
1
- type FlushCallback = () => void;
2
- export declare const beginCommit: () => void;
3
- export declare const endCommit: () => void;
4
- export declare const scheduleFlush: (callback: FlushCallback) => void;
5
- export {};
package/dist/batch.js DELETED
@@ -1,31 +0,0 @@
1
- const state = {
2
- depth: 0,
3
- pendingFlushes: new Set(),
4
- };
5
- export const beginCommit = () => {
6
- state.depth++;
7
- };
8
- export const endCommit = () => {
9
- if (state.depth <= 0) {
10
- state.depth = 0;
11
- return;
12
- }
13
- state.depth--;
14
- if (state.depth === 0 && state.pendingFlushes.size > 0) {
15
- const callbacks = [...state.pendingFlushes];
16
- state.pendingFlushes.clear();
17
- queueMicrotask(() => {
18
- for (const callback of callbacks) {
19
- callback();
20
- }
21
- });
22
- }
23
- };
24
- export const scheduleFlush = (callback) => {
25
- if (state.depth > 0) {
26
- state.pendingFlushes.add(callback);
27
- }
28
- else {
29
- callback();
30
- }
31
- };