@gtkx/native 0.3.2 → 0.3.4
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 +53 -154
- package/dist/index.node +0 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,239 +5,138 @@
|
|
|
5
5
|
<h1 align="center">GTKX</h1>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
|
-
<strong>Build native GTK4 desktop
|
|
8
|
+
<strong>Build native GTK4 desktop apps with React</strong>
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
12
|
<a href="https://eugeniodepalo.github.io/gtkx">Documentation</a> ·
|
|
13
13
|
<a href="#quick-start">Quick Start</a> ·
|
|
14
|
-
<a href="#examples">Examples</a>
|
|
14
|
+
<a href="#examples">Examples</a> ·
|
|
15
|
+
<a href="#contributing">Contributing</a>
|
|
15
16
|
</p>
|
|
16
17
|
|
|
17
18
|
---
|
|
18
19
|
|
|
19
|
-
GTKX
|
|
20
|
+
GTKX lets you build native Linux desktop applications using React and TypeScript. Write familiar React code that renders as native GTK4 widgets—no Electron, no web views.
|
|
20
21
|
|
|
21
22
|
## Features
|
|
22
23
|
|
|
23
|
-
- **React
|
|
24
|
-
- **Hot
|
|
25
|
-
- **Native
|
|
26
|
-
- **CLI
|
|
27
|
-
- **CSS-in-JS
|
|
28
|
-
- **Testing
|
|
24
|
+
- **React** — Hooks, state, props, and components you already know
|
|
25
|
+
- **Hot Reload** — Edit code and see changes instantly via Vite
|
|
26
|
+
- **Native** — Direct FFI bindings to GTK4 via Rust and libffi
|
|
27
|
+
- **CLI** — `npx @gtkx/cli@latest create` scaffolds a ready-to-go project
|
|
28
|
+
- **CSS-in-JS** — Emotion-style `css` template literals for GTK styling
|
|
29
|
+
- **Testing** — Testing Library-style `screen`, `userEvent`, and queries
|
|
29
30
|
|
|
30
31
|
## Quick Start
|
|
31
32
|
|
|
32
|
-
Create a new GTKX app with a single command:
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
npx @gtkx/cli@latest create
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
This launches an interactive wizard that sets up your project with TypeScript, your preferred package manager, and optional testing support.
|
|
39
|
-
|
|
40
|
-
You can also pass options directly:
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
npx @gtkx/cli@latest create my-app --app-id com.example.myapp --pm pnpm --testing vitest
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Then start developing with HMR:
|
|
47
|
-
|
|
48
33
|
```bash
|
|
34
|
+
npx @gtkx/cli@latest create my-app
|
|
49
35
|
cd my-app
|
|
50
36
|
npm run dev
|
|
51
37
|
```
|
|
52
38
|
|
|
53
|
-
Edit your code and see changes instantly
|
|
54
|
-
|
|
55
|
-
### Manual Setup
|
|
39
|
+
Edit your code and see changes instantly—no restart needed.
|
|
56
40
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
```bash
|
|
60
|
-
npm install @gtkx/cli @gtkx/react @gtkx/ffi react
|
|
61
|
-
npm install -D @types/react typescript
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
Create your first app:
|
|
41
|
+
### Example
|
|
65
42
|
|
|
66
43
|
```tsx
|
|
44
|
+
import { render, ApplicationWindow, Box, Button, Label, quit } from "@gtkx/react";
|
|
45
|
+
import { Orientation } from "@gtkx/ffi/gtk";
|
|
67
46
|
import { useState } from "react";
|
|
68
|
-
import * as Gtk from "@gtkx/ffi/gtk";
|
|
69
|
-
import { ApplicationWindow, Box, Button, Label, quit } from "@gtkx/react";
|
|
70
47
|
|
|
71
|
-
|
|
48
|
+
const App = () => {
|
|
72
49
|
const [count, setCount] = useState(0);
|
|
73
50
|
|
|
74
51
|
return (
|
|
75
|
-
<ApplicationWindow
|
|
76
|
-
|
|
77
|
-
defaultWidth={400}
|
|
78
|
-
defaultHeight={300}
|
|
79
|
-
onCloseRequest={quit}
|
|
80
|
-
>
|
|
81
|
-
<Box
|
|
82
|
-
orientation={Gtk.Orientation.VERTICAL}
|
|
83
|
-
spacing={12}
|
|
84
|
-
marginStart={20}
|
|
85
|
-
marginEnd={20}
|
|
86
|
-
marginTop={20}
|
|
87
|
-
marginBottom={20}
|
|
88
|
-
>
|
|
52
|
+
<ApplicationWindow title="Counter" onCloseRequest={quit}>
|
|
53
|
+
<Box orientation={Orientation.VERTICAL} spacing={12} margin={20}>
|
|
89
54
|
<Label.Root label={`Count: ${count}`} />
|
|
90
55
|
<Button label="Increment" onClicked={() => setCount((c) => c + 1)} />
|
|
91
56
|
</Box>
|
|
92
57
|
</ApplicationWindow>
|
|
93
58
|
);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export const appId = "org.example.MyApp";
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
```tsx
|
|
100
|
-
import { render } from "@gtkx/react";
|
|
101
|
-
import App, { appId } from "./app.js";
|
|
102
|
-
|
|
103
|
-
render(<App />, appId);
|
|
104
|
-
```
|
|
59
|
+
};
|
|
105
60
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
```bash
|
|
109
|
-
npx gtkx dev src/app.tsx
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
Or without HMR (production):
|
|
113
|
-
|
|
114
|
-
```bash
|
|
115
|
-
npx tsc -b && node dist/index.js
|
|
61
|
+
render(<App />, "org.example.Counter");
|
|
116
62
|
```
|
|
117
63
|
|
|
118
64
|
## Styling
|
|
119
65
|
|
|
120
|
-
Use `@gtkx/css` for CSS-in-JS styling:
|
|
121
|
-
|
|
122
66
|
```tsx
|
|
123
67
|
import { css } from "@gtkx/css";
|
|
124
68
|
import { Button } from "@gtkx/react";
|
|
125
69
|
|
|
126
|
-
const
|
|
70
|
+
const primary = css`
|
|
127
71
|
padding: 16px 32px;
|
|
128
72
|
border-radius: 24px;
|
|
129
73
|
background: linear-gradient(135deg, #3584e4, #9141ac);
|
|
130
74
|
color: white;
|
|
131
|
-
font-weight: bold;
|
|
132
75
|
`;
|
|
133
76
|
|
|
134
|
-
|
|
77
|
+
<Button label="Click me" cssClasses={[primary]} />
|
|
135
78
|
```
|
|
136
79
|
|
|
137
|
-
GTK also provides built-in
|
|
80
|
+
GTK also provides built-in classes like `suggested-action`, `destructive-action`, `card`, and `heading`.
|
|
138
81
|
|
|
139
82
|
## Testing
|
|
140
83
|
|
|
141
|
-
Use `@gtkx/testing` for Testing Library-style component tests:
|
|
142
|
-
|
|
143
84
|
```tsx
|
|
144
|
-
import { cleanup, render, screen, userEvent
|
|
85
|
+
import { cleanup, render, screen, userEvent } from "@gtkx/testing";
|
|
145
86
|
import { AccessibleRole } from "@gtkx/ffi/gtk";
|
|
146
|
-
import { App } from "./app.js";
|
|
147
87
|
|
|
148
|
-
afterEach(
|
|
149
|
-
await cleanup();
|
|
150
|
-
});
|
|
88
|
+
afterEach(() => cleanup());
|
|
151
89
|
|
|
152
|
-
test("increments count
|
|
90
|
+
test("increments count", async () => {
|
|
153
91
|
await render(<App />);
|
|
154
92
|
|
|
155
|
-
const button = await screen.findByRole(AccessibleRole.BUTTON, {
|
|
156
|
-
name: "Increment",
|
|
157
|
-
});
|
|
93
|
+
const button = await screen.findByRole(AccessibleRole.BUTTON, { name: "Increment" });
|
|
158
94
|
await userEvent.click(button);
|
|
159
95
|
|
|
160
96
|
await screen.findByText("Count: 1");
|
|
161
97
|
});
|
|
162
|
-
|
|
163
|
-
test("can also use fireEvent for low-level signals", async () => {
|
|
164
|
-
await render(<App />);
|
|
165
|
-
|
|
166
|
-
const button = await screen.findByRole(AccessibleRole.BUTTON, {
|
|
167
|
-
name: "Increment",
|
|
168
|
-
});
|
|
169
|
-
fireEvent(button, "clicked");
|
|
170
|
-
|
|
171
|
-
await screen.findByText("Count: 1");
|
|
172
|
-
});
|
|
173
98
|
```
|
|
174
99
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
**Queries** - Find elements in the rendered tree (all async):
|
|
178
|
-
|
|
179
|
-
- `findBy*` / `findAllBy*` - Waits for element to appear
|
|
180
|
-
|
|
181
|
-
Query types: `ByRole`, `ByText`, `ByLabelText`, `ByTestId`
|
|
182
|
-
|
|
183
|
-
**User Interactions**:
|
|
100
|
+
Queries: `findByRole`, `findByText`, `findByLabelText`, `findByTestId`
|
|
184
101
|
|
|
185
|
-
|
|
186
|
-
- `userEvent.dblClick(element)` - Simulate double click
|
|
187
|
-
- `userEvent.activate(element)` - Activate element (e.g., press Enter in input)
|
|
188
|
-
- `userEvent.type(element, text)` - Type text into input
|
|
189
|
-
- `userEvent.clear(element)` - Clear input text
|
|
190
|
-
- `userEvent.tab(element, options?)` - Simulate Tab navigation
|
|
191
|
-
- `userEvent.selectOptions(element, values)` - Select options in ComboBox/ListBox
|
|
192
|
-
- `userEvent.deselectOptions(element, values)` - Deselect options in ListBox
|
|
193
|
-
|
|
194
|
-
**Low-level Events**:
|
|
195
|
-
|
|
196
|
-
- `fireEvent(element, signalName, ...args)` - Emit any GTK signal with optional arguments
|
|
197
|
-
|
|
198
|
-
**Utilities**:
|
|
199
|
-
|
|
200
|
-
- `waitFor(callback)` - Wait for condition
|
|
201
|
-
- `waitForElementToBeRemoved(element)` - Wait for element removal
|
|
102
|
+
User events: `click`, `dblClick`, `type`, `clear`, `tab`, `selectOptions`
|
|
202
103
|
|
|
203
104
|
## Examples
|
|
204
105
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
106
|
+
| Example | Description |
|
|
107
|
+
| ------- | ----------- |
|
|
108
|
+
| [gtk4-demo](examples/gtk4-demo) | Widget showcase |
|
|
109
|
+
| [todo](examples/todo) | Todo app with tests |
|
|
208
110
|
|
|
209
111
|
```bash
|
|
210
|
-
cd examples/gtk4-demo
|
|
211
|
-
pnpm dev
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
### Todo App
|
|
215
|
-
|
|
216
|
-
A todo app demonstrating `@gtkx/testing` with realistic component tests:
|
|
217
|
-
|
|
218
|
-
```bash
|
|
219
|
-
cd examples/todo
|
|
220
|
-
pnpm dev
|
|
221
|
-
pnpm test
|
|
112
|
+
cd examples/gtk4-demo && pnpm dev
|
|
222
113
|
```
|
|
223
114
|
|
|
224
115
|
## Packages
|
|
225
116
|
|
|
226
|
-
| Package
|
|
227
|
-
|
|
|
228
|
-
| [@gtkx/cli](packages/cli)
|
|
229
|
-
| [@gtkx/react](packages/react)
|
|
230
|
-
| [@gtkx/ffi](packages/ffi)
|
|
231
|
-
| [@gtkx/native](packages/native)
|
|
232
|
-
| [@gtkx/css](packages/css)
|
|
233
|
-
| [@gtkx/testing](packages/testing) | Testing utilities
|
|
234
|
-
| [@gtkx/gir](packages/gir)
|
|
117
|
+
| Package | Description |
|
|
118
|
+
| ------- | ----------- |
|
|
119
|
+
| [@gtkx/cli](packages/cli) | CLI with HMR dev server |
|
|
120
|
+
| [@gtkx/react](packages/react) | React reconciler and JSX components |
|
|
121
|
+
| [@gtkx/ffi](packages/ffi) | TypeScript bindings for GTK4/GLib/GIO |
|
|
122
|
+
| [@gtkx/native](packages/native) | Rust native module (libffi bridge) |
|
|
123
|
+
| [@gtkx/css](packages/css) | CSS-in-JS styling |
|
|
124
|
+
| [@gtkx/testing](packages/testing) | Testing utilities |
|
|
125
|
+
| [@gtkx/gir](packages/gir) | GObject Introspection parser |
|
|
235
126
|
|
|
236
127
|
## Requirements
|
|
237
128
|
|
|
238
129
|
- Node.js 20+
|
|
239
|
-
- GTK4
|
|
240
|
-
- Linux
|
|
130
|
+
- GTK4 (`gtk4-devel` on Fedora, `libgtk-4-dev` on Ubuntu)
|
|
131
|
+
- Linux
|
|
132
|
+
|
|
133
|
+
## Contributing
|
|
134
|
+
|
|
135
|
+
We welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
136
|
+
|
|
137
|
+
- [Report a bug](https://github.com/eugeniodepalo/gtkx/issues/new?template=bug_report.md)
|
|
138
|
+
- [Request a feature](https://github.com/eugeniodepalo/gtkx/issues/new?template=feature_request.md)
|
|
139
|
+
- [Read the Code of Conduct](CODE_OF_CONDUCT.md)
|
|
241
140
|
|
|
242
141
|
## License
|
|
243
142
|
|
package/dist/index.node
CHANGED
|
Binary file
|