@gtkx/cli 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.
@@ -0,0 +1,372 @@
1
+ ---
2
+ name: developing-gtkx-apps
3
+ description: Build GTK4 desktop applications with GTKX React framework. Use when creating GTKX components, working with GTK widgets, handling signals, or building Linux desktop UIs with React.
4
+ ---
5
+
6
+ # Developing GTKX Applications
7
+
8
+ GTKX is a React framework for building native GTK4 desktop applications on Linux. It uses a custom React reconciler to render React components as native GTK widgets.
9
+
10
+ ## Quick Start
11
+
12
+ ```tsx
13
+ import { GtkApplicationWindow, GtkBox, GtkButton, GtkLabel, render, quit } from "@gtkx/react";
14
+ import * as Gtk from "@gtkx/ffi/gtk";
15
+
16
+ const App = () => (
17
+ <GtkApplicationWindow title="My App" defaultWidth={800} defaultHeight={600} onCloseRequest={quit}>
18
+ <GtkBox orientation={Gtk.Orientation.VERTICAL} spacing={12}>
19
+ Hello, GTKX!
20
+ <GtkButton label="Quit" onClicked={quit} />
21
+ </GtkBox>
22
+ </GtkApplicationWindow>
23
+ );
24
+
25
+ render(<App />, "com.example.myapp");
26
+ ```
27
+
28
+ ## Widget Patterns
29
+
30
+ ### Container Widgets
31
+
32
+ **GtkBox** - Linear layout:
33
+ ```tsx
34
+ <GtkBox orientation={Gtk.Orientation.VERTICAL} spacing={12}>
35
+ First
36
+ Second
37
+ </GtkBox>
38
+ ```
39
+
40
+ **GtkGrid** - 2D positioning:
41
+ ```tsx
42
+ <GtkGrid rowSpacing={10} columnSpacing={10}>
43
+ <GridChild column={0} row={0}>Top-left</GridChild>
44
+ <GridChild column={1} row={0} columnSpan={2}>Spans 2 columns</GridChild>
45
+ </GtkGrid>
46
+ ```
47
+
48
+ **GtkStack** - Page-based container:
49
+ ```tsx
50
+ <GtkStack visibleChildName="page1">
51
+ <StackPage name="page1" title="Page 1">Content 1</StackPage>
52
+ <StackPage name="page2" title="Page 2">Content 2</StackPage>
53
+ </GtkStack>
54
+ ```
55
+
56
+ **GtkNotebook** - Tabbed container:
57
+ ```tsx
58
+ <GtkNotebook>
59
+ <Notebook.Page label="Tab 1">
60
+ <Content1 />
61
+ </Notebook.Page>
62
+ <Notebook.Page label="Tab 2">
63
+ <Content2 />
64
+ </Notebook.Page>
65
+ </GtkNotebook>
66
+ ```
67
+
68
+ **GtkPaned** - Resizable split:
69
+ ```tsx
70
+ <GtkPaned orientation={Gtk.Orientation.HORIZONTAL} position={280}>
71
+ <Slot for={GtkPaned} id="startChild">
72
+ <SideBar />
73
+ </Slot>
74
+ <Slot for={GtkPaned} id="endChild">
75
+ <MainContent />
76
+ </Slot>
77
+ </GtkPaned>
78
+ ```
79
+
80
+ ### Virtual Scrolling Lists
81
+
82
+ **ListView** - High-performance scrollable list with selection:
83
+ ```tsx
84
+ <ListView<Item>
85
+ vexpand
86
+ selected={[selectedId]}
87
+ selectionMode={Gtk.SelectionMode.SINGLE}
88
+ onSelectionChanged={(ids) => setSelectedId(ids[0])}
89
+ renderItem={(item) => (
90
+ <GtkLabel label={item?.text ?? ""} />
91
+ )}
92
+ >
93
+ {items.map(item => (
94
+ <ListItem key={item.id} id={item.id} value={item} />
95
+ ))}
96
+ </ListView>
97
+ ```
98
+
99
+ **GridView** - Grid-based virtual scrolling:
100
+ ```tsx
101
+ <GridView<Item>
102
+ vexpand
103
+ minColumns={2}
104
+ maxColumns={4}
105
+ renderItem={(item) => (
106
+ <GtkBox orientation={Gtk.Orientation.VERTICAL}>
107
+ <GtkImage iconName={item?.icon ?? "image-missing"} />
108
+ <GtkLabel label={item?.name ?? ""} />
109
+ </GtkBox>
110
+ )}
111
+ >
112
+ {items.map(item => (
113
+ <ListItem key={item.id} id={item.id} value={item} />
114
+ ))}
115
+ </GridView>
116
+ ```
117
+
118
+ **GtkColumnView** - Table with sortable columns:
119
+ ```tsx
120
+ <GtkColumnView
121
+ sortColumn="name"
122
+ sortOrder={Gtk.SortType.ASCENDING}
123
+ onSortChange={handleSort}
124
+ >
125
+ <ColumnViewColumn<Item>
126
+ title="Name"
127
+ id="name"
128
+ expand
129
+ sortable
130
+ renderCell={(item) => (
131
+ <GtkLabel label={item?.name ?? ""} />
132
+ )}
133
+ />
134
+ {items.map(item => (
135
+ <ListItem key={item.id} id={item.id} value={item} />
136
+ ))}
137
+ </GtkColumnView>
138
+ ```
139
+
140
+ **GtkDropDown** - String selection dropdown with controlled state:
141
+ ```tsx
142
+ <GtkDropDown selectedId={selectedId} onSelectionChanged={setSelectedId}>
143
+ {options.map(opt => (
144
+ <SimpleListItem key={opt.id} id={opt.id} value={opt.label} />
145
+ ))}
146
+ </GtkDropDown>
147
+ ```
148
+
149
+ **GtkOverlay** - Stack widgets on top of each other (first child is base):
150
+ ```tsx
151
+ <GtkOverlay>
152
+ <GtkButton label="Notifications" />
153
+ <GtkLabel
154
+ label="3"
155
+ cssClasses={["badge"]}
156
+ halign={Gtk.Align.END}
157
+ valign={Gtk.Align.START}
158
+ />
159
+ </GtkOverlay>
160
+ ```
161
+
162
+ ### GtkHeaderBar
163
+
164
+ Pack widgets at start and end of the title bar using Slot or Pack components:
165
+ ```tsx
166
+ <GtkHeaderBar>
167
+ <Pack.Start>
168
+ <GtkButton iconName="go-previous-symbolic" />
169
+ </Pack.Start>
170
+ <Slot for={GtkHeaderBar} id="titleWidget">
171
+ <GtkLabel label="My App" cssClasses={["title"]} />
172
+ </Slot>
173
+ <Pack.End>
174
+ <GtkMenuButton iconName="open-menu-symbolic" />
175
+ </Pack.End>
176
+ </GtkHeaderBar>
177
+ ```
178
+
179
+ ### GtkActionBar
180
+
181
+ Bottom bar with packed widgets:
182
+ ```tsx
183
+ <GtkActionBar>
184
+ <Pack.Start>
185
+ <GtkButton label="Cancel" />
186
+ </Pack.Start>
187
+ <Pack.End>
188
+ <GtkButton label="Save" cssClasses={["suggested-action"]} />
189
+ </Pack.End>
190
+ </GtkActionBar>
191
+ ```
192
+
193
+ ### Controlled Input
194
+
195
+ GtkEntry requires two-way binding:
196
+ ```tsx
197
+ const [text, setText] = useState("");
198
+
199
+ <GtkEntry
200
+ text={text}
201
+ onChanged={(entry) => setText(entry.getText())}
202
+ placeholderText="Type here..."
203
+ />
204
+ ```
205
+
206
+ ### Declarative Menus
207
+
208
+ ```tsx
209
+ <GtkPopoverMenu>
210
+ <Menu.Section>
211
+ <Menu.Item
212
+ id="new"
213
+ label="New"
214
+ onActivate={handleNew}
215
+ accels="<Control>n"
216
+ />
217
+ </Menu.Section>
218
+ <Menu.Section>
219
+ <Menu.Submenu label="Export">
220
+ <Menu.Item id="pdf" label="PDF" onActivate={handleExportPdf} />
221
+ <Menu.Item id="csv" label="CSV" onActivate={handleExportCsv} />
222
+ </Menu.Submenu>
223
+ </Menu.Section>
224
+ <Menu.Section>
225
+ <Menu.Item id="quit" label="Quit" onActivate={quit} accels="<Control>q" />
226
+ </Menu.Section>
227
+ </GtkPopoverMenu>
228
+ ```
229
+
230
+ ## Signal Handling
231
+
232
+ GTK signals map to `on<SignalName>` props:
233
+ - `clicked` → `onClicked`
234
+ - `toggled` → `onToggled`
235
+ - `changed` → `onChanged`
236
+ - `notify::selected` → `onNotify` (with property name arg)
237
+
238
+ ## Widget References
239
+
240
+ ```tsx
241
+ import { useRef } from "react";
242
+
243
+ const entryRef = useRef<Gtk.Entry | null>(null);
244
+ <GtkEntry ref={entryRef} />
245
+ ```
246
+
247
+ ## Portals
248
+
249
+ ```tsx
250
+ import { createPortal } from "@gtkx/react";
251
+
252
+ {createPortal(<GtkAboutDialog programName="My App" />)}
253
+ ```
254
+
255
+ ## Adwaita (Libadwaita) Widgets
256
+
257
+ Import Adwaita widgets and enums:
258
+ ```tsx
259
+ import * as Adw from "@gtkx/ffi/adw";
260
+ import { AdwApplicationWindow, AdwHeaderBar, AdwToolbarView, Toolbar } from "@gtkx/react";
261
+ ```
262
+
263
+ ### AdwToolbarView
264
+ Modern app layout with top/bottom bars:
265
+ ```tsx
266
+ <AdwToolbarView>
267
+ <Toolbar.Top>
268
+ <AdwHeaderBar>
269
+ <Slot for={AdwHeaderBar} id="titleWidget">
270
+ <AdwWindowTitle title="App" subtitle="Description" />
271
+ </Slot>
272
+ </AdwHeaderBar>
273
+ </Toolbar.Top>
274
+ <MainContent />
275
+ <Toolbar.Bottom>
276
+ <GtkActionBar>...</GtkActionBar>
277
+ </Toolbar.Bottom>
278
+ </AdwToolbarView>
279
+ ```
280
+
281
+ ### AdwApplicationWindow
282
+ Modern window requiring content slot:
283
+ ```tsx
284
+ <AdwApplicationWindow title="My App" defaultWidth={800} defaultHeight={600} onCloseRequest={quit}>
285
+ <Slot for={AdwApplicationWindow} id="content">
286
+ <AdwToolbarView>...</AdwToolbarView>
287
+ </Slot>
288
+ </AdwApplicationWindow>
289
+ ```
290
+
291
+ ### AdwStatusPage
292
+ Welcome or empty state pages:
293
+ ```tsx
294
+ <AdwStatusPage
295
+ iconName="applications-system-symbolic"
296
+ title="Welcome"
297
+ description="Get started with your app"
298
+ vexpand
299
+ />
300
+ ```
301
+
302
+ ### AdwBanner
303
+ Dismissable notification banner:
304
+ ```tsx
305
+ <AdwBanner
306
+ title="Update available!"
307
+ buttonLabel="Dismiss"
308
+ revealed={showBanner}
309
+ onButtonClicked={() => setShowBanner(false)}
310
+ />
311
+ ```
312
+
313
+ ### AdwPreferencesPage / AdwPreferencesGroup
314
+ Settings UI layout:
315
+ ```tsx
316
+ <AdwPreferencesPage title="Settings">
317
+ <AdwPreferencesGroup title="Appearance" description="Customize the look">
318
+ <AdwSwitchRow title="Dark Mode" active={dark} onActivate={() => setDark(!dark)} />
319
+ <AdwActionRow title="Theme" subtitle="Select color theme">
320
+ <Slot for={AdwActionRow} id="activatableWidget">
321
+ <GtkImage iconName="go-next-symbolic" />
322
+ </Slot>
323
+ </AdwActionRow>
324
+ </AdwPreferencesGroup>
325
+ </AdwPreferencesPage>
326
+ ```
327
+
328
+ ### AdwExpanderRow
329
+ Expandable row with nested content:
330
+ ```tsx
331
+ <AdwExpanderRow title="Advanced" subtitle="More options">
332
+ <AdwSwitchRow title="Option 1" active />
333
+ <AdwSwitchRow title="Option 2" active={false} />
334
+ </AdwExpanderRow>
335
+ ```
336
+
337
+ ### AdwEntryRow / AdwPasswordEntryRow
338
+ Input fields in list rows:
339
+ ```tsx
340
+ <AdwEntryRow title="Username" text={username} onChanged={(e) => setUsername(e.getText())} />
341
+ <AdwPasswordEntryRow title="Password" />
342
+ ```
343
+
344
+ ### AdwClamp
345
+ Limit content width for readability:
346
+ ```tsx
347
+ <AdwClamp maximumSize={600}>
348
+ <GtkBox>...</GtkBox>
349
+ </AdwClamp>
350
+ ```
351
+
352
+ ### AdwAvatar
353
+ User avatar with initials fallback:
354
+ ```tsx
355
+ <AdwAvatar size={48} text="John Doe" showInitials />
356
+ ```
357
+
358
+ ### AdwSpinner
359
+ Loading indicator:
360
+ ```tsx
361
+ {isLoading && <AdwSpinner widthRequest={32} heightRequest={32} />}
362
+ ```
363
+
364
+ ## Constraints
365
+
366
+ - **GTK is single-threaded**: All widget operations on main thread
367
+ - **Virtual lists need immutable data**: Use stable object references
368
+ - **GtkToggleButton auto-prevents feedback loops**: Safe for controlled state
369
+ - **GtkEntry needs two-way binding**: Use `onChanged` to sync state
370
+
371
+ For detailed widget reference, see [WIDGETS.md](WIDGETS.md).
372
+ For code examples, see [EXAMPLES.md](EXAMPLES.md).