@gtkx/react 0.4.0 → 0.4.3
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/README.md +2 -6
- package/dist/codegen/jsx-generator.d.ts +2 -0
- package/dist/codegen/jsx-generator.js +12 -11
- package/dist/container-interfaces.d.ts +20 -20
- package/dist/nodes/column-view.d.ts +2 -0
- package/dist/nodes/column-view.js +8 -7
- package/dist/nodes/list.d.ts +3 -0
- package/dist/nodes/list.js +13 -6
- package/dist/nodes/menu.d.ts +2 -0
- package/dist/nodes/menu.js +10 -14
- package/dist/nodes/stack.d.ts +1 -0
- package/dist/nodes/stack.js +11 -13
- package/dist/portal.d.ts +3 -0
- package/dist/portal.js +3 -2
- package/dist/types.d.ts +26 -26
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -57,7 +57,7 @@ const App = () => {
|
|
|
57
57
|
|
|
58
58
|
return (
|
|
59
59
|
<ApplicationWindow title="Counter" onCloseRequest={quit}>
|
|
60
|
-
<Box orientation={Orientation.VERTICAL} spacing={12}
|
|
60
|
+
<Box orientation={Orientation.VERTICAL} spacing={12}>
|
|
61
61
|
<Label.Root label={`Count: ${count}`} />
|
|
62
62
|
<Button label="Increment" onClicked={() => setCount((c) => c + 1)} />
|
|
63
63
|
</Box>
|
|
@@ -117,10 +117,6 @@ User events: `click`, `dblClick`, `type`, `clear`, `tab`, `selectOptions`
|
|
|
117
117
|
| [gtk4-demo](examples/gtk4-demo) | Widget showcase |
|
|
118
118
|
| [todo](examples/todo) | Todo app with tests |
|
|
119
119
|
|
|
120
|
-
```bash
|
|
121
|
-
cd examples/gtk4-demo && pnpm dev
|
|
122
|
-
```
|
|
123
|
-
|
|
124
120
|
## Packages
|
|
125
121
|
|
|
126
122
|
| Package | Description |
|
|
@@ -136,7 +132,7 @@ cd examples/gtk4-demo && pnpm dev
|
|
|
136
132
|
## Requirements
|
|
137
133
|
|
|
138
134
|
- Node.js 20+
|
|
139
|
-
- GTK4 (`gtk4
|
|
135
|
+
- GTK4 Runtime (`gtk4` on Fedora, `libgtk-4-1` on Ubuntu)
|
|
140
136
|
- Linux
|
|
141
137
|
|
|
142
138
|
## Contributing
|
|
@@ -64,9 +64,11 @@ export declare class JsxGenerator {
|
|
|
64
64
|
private addNamespacePrefix;
|
|
65
65
|
private buildSignalHandlerType;
|
|
66
66
|
private generateExports;
|
|
67
|
+
private generateApplicationMenuComponents;
|
|
67
68
|
private getWrapperExportMembers;
|
|
68
69
|
private generateGenericWrapperComponents;
|
|
69
70
|
private generateJsxNamespace;
|
|
71
|
+
private addMenuIntrinsicElements;
|
|
70
72
|
private formatCode;
|
|
71
73
|
}
|
|
72
74
|
export {};
|
|
@@ -590,7 +590,6 @@ ${widgetPropsContent}
|
|
|
590
590
|
isPopoverMenuWidget(widget.name);
|
|
591
591
|
const docComment = widget.doc ? formatDoc(widget.doc).trimEnd() : "";
|
|
592
592
|
if (hasMeaningfulSlots) {
|
|
593
|
-
// For list widgets, generate wrapper components with proper generics
|
|
594
593
|
if (isListWidget(widget.name) ||
|
|
595
594
|
isColumnViewWidget(widget.name) ||
|
|
596
595
|
isDropDownWidget(widget.name) ||
|
|
@@ -629,8 +628,11 @@ ${widgetPropsContent}
|
|
|
629
628
|
}
|
|
630
629
|
}
|
|
631
630
|
}
|
|
632
|
-
|
|
633
|
-
lines.
|
|
631
|
+
lines.push(this.generateApplicationMenuComponents());
|
|
632
|
+
return `${lines.join("\n")}\n`;
|
|
633
|
+
}
|
|
634
|
+
generateApplicationMenuComponents() {
|
|
635
|
+
return `/**
|
|
634
636
|
* Sets the application-wide menu bar.
|
|
635
637
|
* The menu will appear in the window's title bar on supported platforms.
|
|
636
638
|
* Use Menu.Item, Menu.Section, and Menu.Submenu as children.
|
|
@@ -658,8 +660,7 @@ export const Menu = {
|
|
|
658
660
|
\tSection: MenuSection,
|
|
659
661
|
\tSubmenu: MenuSubmenu,
|
|
660
662
|
};
|
|
661
|
-
|
|
662
|
-
return `${lines.join("\n")}\n`;
|
|
663
|
+
`;
|
|
663
664
|
}
|
|
664
665
|
getWrapperExportMembers(widgetName, metadata) {
|
|
665
666
|
const name = toPascalCase(widgetName);
|
|
@@ -682,7 +683,6 @@ export const Menu = {
|
|
|
682
683
|
members.push(`Section: ${name}Section`);
|
|
683
684
|
members.push(`Submenu: ${name}Submenu`);
|
|
684
685
|
}
|
|
685
|
-
// Add named child slots
|
|
686
686
|
for (const slot of metadata.namedChildSlots) {
|
|
687
687
|
members.push(`${slot.slotName}: ${name}${slot.slotName}`);
|
|
688
688
|
}
|
|
@@ -840,11 +840,7 @@ export const Menu = {
|
|
|
840
840
|
elements.push(`"${widgetName}.Page": StackPageProps;`);
|
|
841
841
|
}
|
|
842
842
|
}
|
|
843
|
-
|
|
844
|
-
elements.push(`"Menu.Item": MenuItemProps;`);
|
|
845
|
-
elements.push(`"Menu.Section": MenuSectionProps;`);
|
|
846
|
-
elements.push(`"Menu.Submenu": MenuSubmenuProps;`);
|
|
847
|
-
// Add ApplicationMenu element
|
|
843
|
+
this.addMenuIntrinsicElements(elements);
|
|
848
844
|
elements.push(`ApplicationMenu: MenuRootProps;`);
|
|
849
845
|
return `
|
|
850
846
|
declare global {
|
|
@@ -858,6 +854,11 @@ declare global {
|
|
|
858
854
|
}
|
|
859
855
|
`;
|
|
860
856
|
}
|
|
857
|
+
addMenuIntrinsicElements(elements) {
|
|
858
|
+
elements.push(`"Menu.Item": MenuItemProps;`);
|
|
859
|
+
elements.push(`"Menu.Section": MenuSectionProps;`);
|
|
860
|
+
elements.push(`"Menu.Submenu": MenuSubmenuProps;`);
|
|
861
|
+
}
|
|
861
862
|
async formatCode(code) {
|
|
862
863
|
try {
|
|
863
864
|
return await format(code, {
|
|
@@ -1,69 +1,69 @@
|
|
|
1
1
|
import type * as Gtk from "@gtkx/ffi/gtk";
|
|
2
2
|
import type { Node } from "./node.js";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Type for containers that manage child widgets with attach/detach semantics.
|
|
5
5
|
* Used by ActionBar, FlowBox, ListBox, Overlay.
|
|
6
6
|
*/
|
|
7
|
-
export
|
|
7
|
+
export type ChildContainer = {
|
|
8
8
|
attachChild(child: Gtk.Widget): void;
|
|
9
9
|
insertChildBefore(child: Gtk.Widget, before: Gtk.Widget): void;
|
|
10
10
|
detachChild(child: Gtk.Widget): void;
|
|
11
|
-
}
|
|
11
|
+
};
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
13
|
+
* Type for page-based containers like Notebook.
|
|
14
14
|
*/
|
|
15
|
-
export
|
|
15
|
+
export type PageContainer = {
|
|
16
16
|
addPage(child: Gtk.Widget, label: string): void;
|
|
17
17
|
insertPageBefore(child: Gtk.Widget, label: string, beforeChild: Gtk.Widget): void;
|
|
18
18
|
removePage(child: Gtk.Widget): void;
|
|
19
19
|
updatePageLabel(child: Gtk.Widget, label: string): void;
|
|
20
|
-
}
|
|
20
|
+
};
|
|
21
21
|
/**
|
|
22
22
|
* Props for Stack pages.
|
|
23
23
|
*/
|
|
24
|
-
export
|
|
24
|
+
export type StackPageProps = {
|
|
25
25
|
name?: string;
|
|
26
26
|
title?: string;
|
|
27
27
|
iconName?: string;
|
|
28
28
|
needsAttention?: boolean;
|
|
29
29
|
visible?: boolean;
|
|
30
30
|
useUnderline?: boolean;
|
|
31
|
-
}
|
|
31
|
+
};
|
|
32
32
|
/**
|
|
33
|
-
*
|
|
33
|
+
* Type for Stack containers.
|
|
34
34
|
*/
|
|
35
|
-
export
|
|
35
|
+
export type StackPageContainer = {
|
|
36
36
|
addStackPage(child: Gtk.Widget, props: StackPageProps): void;
|
|
37
37
|
insertStackPageBefore(child: Gtk.Widget, props: StackPageProps, beforeChild: Gtk.Widget): void;
|
|
38
38
|
removeStackPage(child: Gtk.Widget): void;
|
|
39
39
|
updateStackPageProps(child: Gtk.Widget, props: StackPageProps): void;
|
|
40
|
-
}
|
|
40
|
+
};
|
|
41
41
|
/**
|
|
42
|
-
*
|
|
42
|
+
* Type for grid-based containers.
|
|
43
43
|
*/
|
|
44
|
-
export
|
|
44
|
+
export type GridContainer = {
|
|
45
45
|
attachToGrid(child: Gtk.Widget, column: number, row: number, colSpan: number, rowSpan: number): void;
|
|
46
46
|
removeFromGrid(child: Gtk.Widget): void;
|
|
47
|
-
}
|
|
47
|
+
};
|
|
48
48
|
/**
|
|
49
|
-
*
|
|
49
|
+
* Type for item-based containers like ListView, ColumnView, DropDown.
|
|
50
50
|
*/
|
|
51
|
-
export
|
|
51
|
+
export type ItemContainer<T> = {
|
|
52
52
|
addItem(item: T): void;
|
|
53
53
|
insertItemBefore(item: T, beforeItem: T): void;
|
|
54
54
|
removeItem(item: T): void;
|
|
55
|
-
}
|
|
55
|
+
};
|
|
56
56
|
/**
|
|
57
|
-
*
|
|
57
|
+
* Type for column-based containers like ColumnView.
|
|
58
58
|
* Note: Column type is generic to support both raw Gtk.ColumnViewColumn and wrapper nodes.
|
|
59
59
|
*/
|
|
60
|
-
export
|
|
60
|
+
export type ColumnContainer = {
|
|
61
61
|
addColumn(column: unknown): void;
|
|
62
62
|
insertColumnBefore(column: unknown, beforeColumn: unknown): void;
|
|
63
63
|
removeColumn(column: unknown): void;
|
|
64
64
|
getItems(): unknown[];
|
|
65
65
|
getSortFn(): ((a: unknown, b: unknown, columnId: string) => number) | null;
|
|
66
|
-
}
|
|
66
|
+
};
|
|
67
67
|
export declare const isChildContainer: (node: Node) => node is Node & ChildContainer;
|
|
68
68
|
export declare const isPageContainer: (node: Node) => node is Node & PageContainer;
|
|
69
69
|
export declare const isStackPageContainer: (node: Node) => node is Node & StackPageContainer;
|
|
@@ -23,6 +23,8 @@ interface ColumnViewState {
|
|
|
23
23
|
export declare class ColumnViewNode extends Node<Gtk.ColumnView, ColumnViewState> implements ItemContainer<unknown>, ColumnContainer {
|
|
24
24
|
static matches(type: string): boolean;
|
|
25
25
|
initialize(props: Props): void;
|
|
26
|
+
private initializeStateWithPlaceholders;
|
|
27
|
+
private createGtkModels;
|
|
26
28
|
private connectSorterChangedSignal;
|
|
27
29
|
private waitForSortComplete;
|
|
28
30
|
private disconnectSorterChangedSignal;
|
|
@@ -12,9 +12,12 @@ export class ColumnViewNode extends Node {
|
|
|
12
12
|
return type === "ColumnView.Root";
|
|
13
13
|
}
|
|
14
14
|
initialize(props) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
this.initializeStateWithPlaceholders(props);
|
|
16
|
+
super.initialize(props);
|
|
17
|
+
this.createGtkModels();
|
|
18
|
+
this.connectSorterChangedSignal();
|
|
19
|
+
}
|
|
20
|
+
initializeStateWithPlaceholders(props) {
|
|
18
21
|
this.state = {
|
|
19
22
|
stringList: null,
|
|
20
23
|
selectionModel: null,
|
|
@@ -31,7 +34,8 @@ export class ColumnViewNode extends Node {
|
|
|
31
34
|
lastNotifiedColumn: null,
|
|
32
35
|
lastNotifiedOrder: Gtk.SortType.ASCENDING,
|
|
33
36
|
};
|
|
34
|
-
|
|
37
|
+
}
|
|
38
|
+
createGtkModels() {
|
|
35
39
|
const stringList = new Gtk.StringList([]);
|
|
36
40
|
const sortListModel = new Gtk.SortListModel(getInterface(stringList, Gio.ListModel), this.widget.getSorter());
|
|
37
41
|
sortListModel.setIncremental(true);
|
|
@@ -40,7 +44,6 @@ export class ColumnViewNode extends Node {
|
|
|
40
44
|
this.state.stringList = stringList;
|
|
41
45
|
this.state.sortListModel = sortListModel;
|
|
42
46
|
this.state.selectionModel = selectionModel;
|
|
43
|
-
this.connectSorterChangedSignal();
|
|
44
47
|
}
|
|
45
48
|
connectSorterChangedSignal() {
|
|
46
49
|
const sorter = this.widget.getSorter();
|
|
@@ -221,8 +224,6 @@ export class ColumnViewColumnNode extends Node {
|
|
|
221
224
|
}
|
|
222
225
|
columnView = null;
|
|
223
226
|
initialize(props) {
|
|
224
|
-
// Unlike ColumnViewNode, we can create GTK objects before super.initialize() here
|
|
225
|
-
// since this is a virtual node (no widget created by parent class).
|
|
226
227
|
const factory = new Gtk.SignalListItemFactory();
|
|
227
228
|
const column = new Gtk.ColumnViewColumn(props.title, factory);
|
|
228
229
|
const columnId = props.id ?? null;
|
package/dist/nodes/list.d.ts
CHANGED
|
@@ -20,6 +20,9 @@ interface ListViewState {
|
|
|
20
20
|
export declare class ListViewNode extends Node<Gtk.ListView | Gtk.GridView, ListViewState> implements ItemContainer<unknown> {
|
|
21
21
|
static matches(type: string): boolean;
|
|
22
22
|
initialize(props: Props): void;
|
|
23
|
+
private initializeStateWithPlaceholders;
|
|
24
|
+
private createGtkModels;
|
|
25
|
+
private connectFactorySignals;
|
|
23
26
|
private syncStringList;
|
|
24
27
|
addItem(item: unknown): void;
|
|
25
28
|
insertItemBefore(item: unknown, beforeItem: unknown): void;
|
package/dist/nodes/list.js
CHANGED
|
@@ -11,9 +11,14 @@ export class ListViewNode extends Node {
|
|
|
11
11
|
return type === "ListView.Root" || type === "GridView.Root";
|
|
12
12
|
}
|
|
13
13
|
initialize(props) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
this.initializeStateWithPlaceholders(props);
|
|
15
|
+
super.initialize(props);
|
|
16
|
+
this.createGtkModels();
|
|
17
|
+
this.connectFactorySignals();
|
|
18
|
+
this.widget.setModel(this.state.selectionModel);
|
|
19
|
+
this.widget.setFactory(this.state.factory);
|
|
20
|
+
}
|
|
21
|
+
initializeStateWithPlaceholders(props) {
|
|
17
22
|
this.state = {
|
|
18
23
|
stringList: null,
|
|
19
24
|
selectionModel: null,
|
|
@@ -23,13 +28,17 @@ export class ListViewNode extends Node {
|
|
|
23
28
|
items: [],
|
|
24
29
|
committedLength: 0,
|
|
25
30
|
};
|
|
26
|
-
|
|
31
|
+
}
|
|
32
|
+
createGtkModels() {
|
|
27
33
|
const stringList = new Gtk.StringList([]);
|
|
28
34
|
const selectionModel = new Gtk.SingleSelection(getInterface(stringList, Gio.ListModel));
|
|
29
35
|
const factory = new Gtk.SignalListItemFactory();
|
|
30
36
|
this.state.stringList = stringList;
|
|
31
37
|
this.state.selectionModel = selectionModel;
|
|
32
38
|
this.state.factory = factory;
|
|
39
|
+
}
|
|
40
|
+
connectFactorySignals() {
|
|
41
|
+
const factory = this.state.factory;
|
|
33
42
|
factory.connect("setup", (_self, listItemObj) => {
|
|
34
43
|
const listItem = getObject(listItemObj.id);
|
|
35
44
|
const id = getObjectId(listItemObj.id);
|
|
@@ -66,8 +75,6 @@ export class ListViewNode extends Node {
|
|
|
66
75
|
this.state.listItemCache.delete(id);
|
|
67
76
|
}
|
|
68
77
|
});
|
|
69
|
-
this.widget.setModel(selectionModel);
|
|
70
|
-
this.widget.setFactory(factory);
|
|
71
78
|
}
|
|
72
79
|
syncStringList = () => {
|
|
73
80
|
const newLength = this.state.items.length;
|
package/dist/nodes/menu.d.ts
CHANGED
|
@@ -56,7 +56,9 @@ export declare class MenuItemNode extends Node<never> {
|
|
|
56
56
|
attachToParent(parent: Node): void;
|
|
57
57
|
detachFromParent(parent: Node): void;
|
|
58
58
|
protected consumedProps(): Set<string>;
|
|
59
|
+
private isFieldInitializationIncomplete;
|
|
59
60
|
updateProps(oldProps: Props, newProps: Props): void;
|
|
61
|
+
private invokeCurrentCallback;
|
|
60
62
|
private setupAction;
|
|
61
63
|
private cleanupAction;
|
|
62
64
|
private updateAccels;
|
package/dist/nodes/menu.js
CHANGED
|
@@ -138,27 +138,23 @@ export class MenuItemNode extends Node {
|
|
|
138
138
|
consumed.add("accels");
|
|
139
139
|
return consumed;
|
|
140
140
|
}
|
|
141
|
+
isFieldInitializationIncomplete() {
|
|
142
|
+
return !this.entry;
|
|
143
|
+
}
|
|
141
144
|
updateProps(oldProps, newProps) {
|
|
142
|
-
|
|
143
|
-
// This happens when base class constructor calls updateProps
|
|
144
|
-
// before derived class field initializers run - skip in that case
|
|
145
|
-
if (!this.entry) {
|
|
145
|
+
if (this.isFieldInitializationIncomplete()) {
|
|
146
146
|
super.updateProps(oldProps, newProps);
|
|
147
147
|
return;
|
|
148
148
|
}
|
|
149
149
|
const labelChanged = oldProps.label !== newProps.label;
|
|
150
|
-
const
|
|
151
|
-
const hasCallback = newProps.onActivate !== undefined;
|
|
150
|
+
const callbackPresenceChanged = (oldProps.onActivate !== undefined) !== (newProps.onActivate !== undefined);
|
|
152
151
|
const accelsChanged = oldProps.accels !== newProps.accels;
|
|
153
|
-
// Always update the callback reference - the signal handler uses this
|
|
154
152
|
this.onActivateCallback = newProps.onActivate;
|
|
155
153
|
this.currentAccels = newProps.accels;
|
|
156
154
|
if (labelChanged) {
|
|
157
155
|
this.entry.label = newProps.label;
|
|
158
156
|
}
|
|
159
|
-
|
|
160
|
-
// (not when the callback reference changes - we store the ref and call it)
|
|
161
|
-
if (this.isAttached && hadCallback !== hasCallback) {
|
|
157
|
+
if (this.isAttached && callbackPresenceChanged) {
|
|
162
158
|
this.cleanupAction();
|
|
163
159
|
this.setupAction();
|
|
164
160
|
}
|
|
@@ -167,15 +163,15 @@ export class MenuItemNode extends Node {
|
|
|
167
163
|
}
|
|
168
164
|
super.updateProps(oldProps, newProps);
|
|
169
165
|
}
|
|
166
|
+
invokeCurrentCallback() {
|
|
167
|
+
this.onActivateCallback?.();
|
|
168
|
+
}
|
|
170
169
|
setupAction() {
|
|
171
170
|
if (!this.onActivateCallback)
|
|
172
171
|
return;
|
|
173
172
|
this.actionName = generateActionName();
|
|
174
173
|
this.action = new Gio.SimpleAction(this.actionName);
|
|
175
|
-
this.signalHandlerId = this.action.connect("activate", () =>
|
|
176
|
-
// Call the current callback (may have been updated via updateProps)
|
|
177
|
-
this.onActivateCallback?.();
|
|
178
|
-
});
|
|
174
|
+
this.signalHandlerId = this.action.connect("activate", () => this.invokeCurrentCallback());
|
|
179
175
|
const app = getCurrentApp();
|
|
180
176
|
const action = getInterface(this.action, Gio.Action);
|
|
181
177
|
if (!action) {
|
package/dist/nodes/stack.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export declare class StackNode extends Node<Gtk.Stack> implements StackPageConta
|
|
|
15
15
|
insertChildBefore(child: Gtk.Widget, _before: Gtk.Widget): void;
|
|
16
16
|
detachChild(child: Gtk.Widget): void;
|
|
17
17
|
protected consumedProps(): Set<string>;
|
|
18
|
+
private setVisibleChildOrDefer;
|
|
18
19
|
updateProps(oldProps: Props, newProps: Props): void;
|
|
19
20
|
}
|
|
20
21
|
export declare class StackPageNode extends Node {
|
package/dist/nodes/stack.js
CHANGED
|
@@ -30,8 +30,6 @@ export class StackNode extends Node {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
insertStackPageBefore(child, props, _beforeChild) {
|
|
33
|
-
// Stack doesn't have insertBefore, so we add and rely on order
|
|
34
|
-
// For now, just add at the end - GTK Stack doesn't support insertion at position
|
|
35
33
|
this.addStackPage(child, props);
|
|
36
34
|
}
|
|
37
35
|
removeStackPage(child) {
|
|
@@ -65,7 +63,6 @@ export class StackNode extends Node {
|
|
|
65
63
|
this.widget.addChild(child);
|
|
66
64
|
}
|
|
67
65
|
insertChildBefore(child, _before) {
|
|
68
|
-
// Stack doesn't support insertion at position
|
|
69
66
|
this.widget.addChild(child);
|
|
70
67
|
}
|
|
71
68
|
detachChild(child) {
|
|
@@ -76,18 +73,19 @@ export class StackNode extends Node {
|
|
|
76
73
|
consumed.add("visibleChildName");
|
|
77
74
|
return consumed;
|
|
78
75
|
}
|
|
76
|
+
setVisibleChildOrDefer(name) {
|
|
77
|
+
const child = this.widget.getChildByName(name);
|
|
78
|
+
if (child) {
|
|
79
|
+
this.widget.setVisibleChild(child);
|
|
80
|
+
this.pendingVisibleChildName = null;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
this.pendingVisibleChildName = name;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
79
86
|
updateProps(oldProps, newProps) {
|
|
80
87
|
if (newProps.visibleChildName !== undefined) {
|
|
81
|
-
|
|
82
|
-
const child = this.widget.getChildByName(name);
|
|
83
|
-
if (child) {
|
|
84
|
-
this.widget.setVisibleChild(child);
|
|
85
|
-
this.pendingVisibleChildName = null;
|
|
86
|
-
}
|
|
87
|
-
else {
|
|
88
|
-
// Child not yet added, defer until it's added
|
|
89
|
-
this.pendingVisibleChildName = name;
|
|
90
|
-
}
|
|
88
|
+
this.setVisibleChildOrDefer(newProps.visibleChildName);
|
|
91
89
|
}
|
|
92
90
|
super.updateProps(oldProps, newProps);
|
|
93
91
|
}
|
package/dist/portal.d.ts
CHANGED
|
@@ -8,6 +8,9 @@ import type { ReactNode, ReactPortal } from "react";
|
|
|
8
8
|
* When called without a container argument, the portal renders at the root level.
|
|
9
9
|
* This is useful for dialogs which don't need a parent container.
|
|
10
10
|
*
|
|
11
|
+
* Implementation note: ReactPortal is an opaque type, so we manually construct
|
|
12
|
+
* the internal representation required by custom reconcilers.
|
|
13
|
+
*
|
|
11
14
|
* @example
|
|
12
15
|
* ```tsx
|
|
13
16
|
* // Render dialog at root level (no container needed)
|
package/dist/portal.js
CHANGED
|
@@ -8,6 +8,9 @@ import { ROOT_NODE_CONTAINER } from "./factory.js";
|
|
|
8
8
|
* When called without a container argument, the portal renders at the root level.
|
|
9
9
|
* This is useful for dialogs which don't need a parent container.
|
|
10
10
|
*
|
|
11
|
+
* Implementation note: ReactPortal is an opaque type, so we manually construct
|
|
12
|
+
* the internal representation required by custom reconcilers.
|
|
13
|
+
*
|
|
11
14
|
* @example
|
|
12
15
|
* ```tsx
|
|
13
16
|
* // Render dialog at root level (no container needed)
|
|
@@ -18,8 +21,6 @@ import { ROOT_NODE_CONTAINER } from "./factory.js";
|
|
|
18
21
|
* ```
|
|
19
22
|
*/
|
|
20
23
|
export const createPortal = (children, container, key) => {
|
|
21
|
-
// ReactPortal is an opaque type but we need to construct it manually for custom reconcilers.
|
|
22
|
-
// The shape matches React's internal portal representation.
|
|
23
24
|
return {
|
|
24
25
|
$$typeof: Symbol.for("react.portal"),
|
|
25
26
|
key: key ?? null,
|
package/dist/types.d.ts
CHANGED
|
@@ -4,23 +4,23 @@ import type { ReactElement, ReactNode } from "react";
|
|
|
4
4
|
* Props for slot components that accept children.
|
|
5
5
|
* Used by container widgets that render child elements in designated slots.
|
|
6
6
|
*/
|
|
7
|
-
export
|
|
7
|
+
export type SlotProps = {
|
|
8
8
|
children?: ReactNode;
|
|
9
|
-
}
|
|
9
|
+
};
|
|
10
10
|
/**
|
|
11
11
|
* Props passed to list item components.
|
|
12
12
|
* @typeParam I - The type of the data item
|
|
13
13
|
*/
|
|
14
|
-
export
|
|
14
|
+
export type ListItemProps<I = unknown> = {
|
|
15
15
|
/** The data item to render. */
|
|
16
16
|
item: I;
|
|
17
|
-
}
|
|
18
|
-
export
|
|
17
|
+
};
|
|
18
|
+
export type GridChildProps = SlotProps & {
|
|
19
19
|
column?: number;
|
|
20
20
|
row?: number;
|
|
21
21
|
columnSpan?: number;
|
|
22
22
|
rowSpan?: number;
|
|
23
|
-
}
|
|
23
|
+
};
|
|
24
24
|
/**
|
|
25
25
|
* Render function for ListView/GridView items.
|
|
26
26
|
* Called with null during setup (for loading state) and with the actual item during bind.
|
|
@@ -30,10 +30,10 @@ export type RenderItemFn<T> = (item: T | null) => ReactElement;
|
|
|
30
30
|
* Props for ListView and GridView components.
|
|
31
31
|
* @typeParam T - The type of the data items in the list
|
|
32
32
|
*/
|
|
33
|
-
export
|
|
33
|
+
export type ListViewRenderProps<T = unknown> = {
|
|
34
34
|
/** Render function called for each item in the list. */
|
|
35
35
|
renderItem: RenderItemFn<T>;
|
|
36
|
-
}
|
|
36
|
+
};
|
|
37
37
|
/**
|
|
38
38
|
* Comparison function for sorting items by column.
|
|
39
39
|
* Returns negative if a < b, 0 if a === b, positive if a > b.
|
|
@@ -46,7 +46,7 @@ export type ColumnSortFn<T, C extends string = string> = (a: T, b: T, columnId:
|
|
|
46
46
|
* Props for individual columns in a ColumnView.
|
|
47
47
|
* @typeParam T - The type of the data items displayed in the column
|
|
48
48
|
*/
|
|
49
|
-
export
|
|
49
|
+
export type ColumnViewColumnProps<T = unknown> = {
|
|
50
50
|
/** The column header title. */
|
|
51
51
|
title?: string;
|
|
52
52
|
/** Whether the column should expand to fill available space. */
|
|
@@ -63,13 +63,13 @@ export interface ColumnViewColumnProps<T = unknown> {
|
|
|
63
63
|
* Always annotate your callback parameter type to include null, e.g.: `(item: MyItem | null) => ...`
|
|
64
64
|
*/
|
|
65
65
|
renderCell: (item: T | null) => ReactElement;
|
|
66
|
-
}
|
|
66
|
+
};
|
|
67
67
|
/**
|
|
68
68
|
* Props for the ColumnView root component.
|
|
69
69
|
* @typeParam T - The type of the data items in the view
|
|
70
70
|
* @typeParam C - The union type of column IDs
|
|
71
71
|
*/
|
|
72
|
-
export
|
|
72
|
+
export type ColumnViewRootProps<T = unknown, C extends string = string> = {
|
|
73
73
|
/** The ID of the currently sorted column, or null if unsorted. */
|
|
74
74
|
sortColumn?: C | null;
|
|
75
75
|
/** The current sort direction. */
|
|
@@ -78,55 +78,55 @@ export interface ColumnViewRootProps<T = unknown, C extends string = string> {
|
|
|
78
78
|
onSortChange?: (column: C | null, order: SortType) => void;
|
|
79
79
|
/** Custom comparison function for sorting items. */
|
|
80
80
|
sortFn?: ColumnSortFn<T, C>;
|
|
81
|
-
}
|
|
82
|
-
export
|
|
81
|
+
};
|
|
82
|
+
export type NotebookPageProps = SlotProps & {
|
|
83
83
|
label: string;
|
|
84
|
-
}
|
|
85
|
-
export
|
|
84
|
+
};
|
|
85
|
+
export type StackRootProps = SlotProps & {
|
|
86
86
|
visibleChildName?: string;
|
|
87
|
-
}
|
|
88
|
-
export
|
|
87
|
+
};
|
|
88
|
+
export type StackPageProps = SlotProps & {
|
|
89
89
|
name?: string;
|
|
90
90
|
title?: string;
|
|
91
91
|
iconName?: string;
|
|
92
92
|
needsAttention?: boolean;
|
|
93
93
|
visible?: boolean;
|
|
94
94
|
useUnderline?: boolean;
|
|
95
|
-
}
|
|
95
|
+
};
|
|
96
96
|
/**
|
|
97
97
|
* Props for the Menu.Root component.
|
|
98
98
|
* Root container for declarative menu structures.
|
|
99
99
|
*/
|
|
100
|
-
export
|
|
100
|
+
export type MenuRootProps = {
|
|
101
101
|
children?: ReactNode;
|
|
102
|
-
}
|
|
102
|
+
};
|
|
103
103
|
/**
|
|
104
104
|
* Props for Menu.Item components.
|
|
105
105
|
* Represents a single menu item with an action.
|
|
106
106
|
*/
|
|
107
|
-
export
|
|
107
|
+
export type MenuItemProps = {
|
|
108
108
|
/** The visible label for the menu item. */
|
|
109
109
|
label: string;
|
|
110
110
|
/** Callback invoked when the menu item is activated. */
|
|
111
111
|
onActivate?: () => void;
|
|
112
112
|
/** Keyboard accelerators for this menu item (e.g., `"<Control>q"` or `["<Control>q", "<Control>w"]`). */
|
|
113
113
|
accels?: string | string[];
|
|
114
|
-
}
|
|
114
|
+
};
|
|
115
115
|
/**
|
|
116
116
|
* Props for Menu.Section components.
|
|
117
117
|
* Groups related menu items with optional label.
|
|
118
118
|
*/
|
|
119
|
-
export
|
|
119
|
+
export type MenuSectionProps = {
|
|
120
120
|
/** Optional section label displayed as a header. */
|
|
121
121
|
label?: string;
|
|
122
122
|
children?: ReactNode;
|
|
123
|
-
}
|
|
123
|
+
};
|
|
124
124
|
/**
|
|
125
125
|
* Props for Menu.Submenu components.
|
|
126
126
|
* Creates a nested submenu with its own items.
|
|
127
127
|
*/
|
|
128
|
-
export
|
|
128
|
+
export type MenuSubmenuProps = {
|
|
129
129
|
/** The submenu label shown in parent menu. */
|
|
130
130
|
label: string;
|
|
131
131
|
children?: ReactNode;
|
|
132
|
-
}
|
|
132
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gtkx/react",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"description": "Build GTK4 desktop applications with React and TypeScript",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"gtk",
|
|
@@ -36,10 +36,10 @@
|
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"react-reconciler": "0.33.0",
|
|
39
|
-
"@gtkx/ffi": "0.4.
|
|
39
|
+
"@gtkx/ffi": "0.4.3"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@gtkx/gir": "0.4.
|
|
42
|
+
"@gtkx/gir": "0.4.3"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
45
|
"react": "^19"
|