@gtkx/cli 0.20.0 → 1.0.0-rc.1

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 (341) hide show
  1. package/README.md +173 -0
  2. package/bin/gtkx-dev-runner.js +9 -0
  3. package/dist/builder.d.ts +2 -50
  4. package/dist/builder.d.ts.map +1 -1
  5. package/dist/builder.js +22 -48
  6. package/dist/builder.js.map +1 -1
  7. package/dist/cli.d.ts +1 -2
  8. package/dist/cli.d.ts.map +1 -1
  9. package/dist/cli.js +11 -124
  10. package/dist/cli.js.map +1 -1
  11. package/dist/codegen/freshness.d.ts +11 -0
  12. package/dist/codegen/freshness.d.ts.map +1 -0
  13. package/dist/codegen/freshness.js +42 -0
  14. package/dist/codegen/freshness.js.map +1 -0
  15. package/dist/codegen/report.d.ts +3 -0
  16. package/dist/codegen/report.d.ts.map +1 -0
  17. package/dist/codegen/report.js +16 -0
  18. package/dist/codegen/report.js.map +1 -0
  19. package/dist/codegen/run-codegen.d.ts +35 -0
  20. package/dist/codegen/run-codegen.d.ts.map +1 -0
  21. package/dist/codegen/run-codegen.js +133 -0
  22. package/dist/codegen/run-codegen.js.map +1 -0
  23. package/dist/codegen/store-resolver.d.ts +21 -0
  24. package/dist/codegen/store-resolver.d.ts.map +1 -0
  25. package/dist/codegen/store-resolver.js +52 -0
  26. package/dist/codegen/store-resolver.js.map +1 -0
  27. package/dist/commands/build.d.ts +9 -0
  28. package/dist/commands/build.d.ts.map +1 -0
  29. package/dist/commands/build.js +33 -0
  30. package/dist/commands/build.js.map +1 -0
  31. package/dist/commands/codegen.d.ts +9 -0
  32. package/dist/commands/codegen.d.ts.map +1 -0
  33. package/dist/commands/codegen.js +40 -0
  34. package/dist/commands/codegen.js.map +1 -0
  35. package/dist/commands/dev.d.ts +5 -0
  36. package/dist/commands/dev.d.ts.map +1 -0
  37. package/dist/commands/dev.js +21 -0
  38. package/dist/commands/dev.js.map +1 -0
  39. package/dist/commands/docs.d.ts +19 -0
  40. package/dist/commands/docs.d.ts.map +1 -0
  41. package/dist/commands/docs.js +59 -0
  42. package/dist/commands/docs.js.map +1 -0
  43. package/dist/dev/icon-dir.d.ts +2 -0
  44. package/dist/dev/icon-dir.d.ts.map +1 -0
  45. package/dist/dev/icon-dir.js +13 -0
  46. package/dist/dev/icon-dir.js.map +1 -0
  47. package/dist/dev/refresh-tracker.d.ts +6 -0
  48. package/dist/dev/refresh-tracker.d.ts.map +1 -0
  49. package/dist/dev/refresh-tracker.js +18 -0
  50. package/dist/dev/refresh-tracker.js.map +1 -0
  51. package/dist/dev/runner-deps.d.ts +3 -0
  52. package/dist/dev/runner-deps.d.ts.map +1 -0
  53. package/dist/dev/runner-deps.js +39 -0
  54. package/dist/dev/runner-deps.js.map +1 -0
  55. package/dist/dev/runner-main.d.ts +2 -0
  56. package/dist/dev/runner-main.d.ts.map +1 -0
  57. package/dist/dev/runner-main.js +28 -0
  58. package/dist/dev/runner-main.js.map +1 -0
  59. package/dist/dev/runner.d.ts +23 -0
  60. package/dist/dev/runner.d.ts.map +1 -0
  61. package/dist/dev/runner.js +88 -0
  62. package/dist/dev/runner.js.map +1 -0
  63. package/dist/dev/schema-dir.d.ts +2 -0
  64. package/dist/dev/schema-dir.d.ts.map +1 -0
  65. package/dist/dev/schema-dir.js +10 -0
  66. package/dist/dev/schema-dir.js.map +1 -0
  67. package/dist/dev/supervisor.d.ts +17 -0
  68. package/dist/dev/supervisor.d.ts.map +1 -0
  69. package/dist/dev/supervisor.js +142 -0
  70. package/dist/dev/supervisor.js.map +1 -0
  71. package/dist/dev/vite-dev-server.d.ts +21 -0
  72. package/dist/dev/vite-dev-server.d.ts.map +1 -0
  73. package/dist/dev/vite-dev-server.js +12 -0
  74. package/dist/dev/vite-dev-server.js.map +1 -0
  75. package/dist/internal/banner.d.ts +3 -0
  76. package/dist/internal/banner.d.ts.map +1 -0
  77. package/dist/internal/banner.js +8 -0
  78. package/dist/internal/banner.js.map +1 -0
  79. package/dist/internal/data-dir.d.ts +3 -0
  80. package/dist/internal/data-dir.d.ts.map +1 -0
  81. package/dist/internal/data-dir.js +37 -0
  82. package/dist/internal/data-dir.js.map +1 -0
  83. package/dist/internal/entry-arg.d.ts +19 -0
  84. package/dist/internal/entry-arg.d.ts.map +1 -0
  85. package/dist/internal/entry-arg.js +33 -0
  86. package/dist/internal/entry-arg.js.map +1 -0
  87. package/dist/internal/errors.d.ts +4 -0
  88. package/dist/internal/errors.d.ts.map +1 -0
  89. package/dist/internal/errors.js +27 -0
  90. package/dist/internal/errors.js.map +1 -0
  91. package/dist/internal/list-files.d.ts +6 -0
  92. package/dist/internal/list-files.d.ts.map +1 -0
  93. package/dist/internal/list-files.js +13 -0
  94. package/dist/internal/list-files.js.map +1 -0
  95. package/dist/internal/resolve-cli-tool.d.ts +2 -0
  96. package/dist/internal/resolve-cli-tool.d.ts.map +1 -0
  97. package/dist/internal/resolve-cli-tool.js +20 -0
  98. package/dist/internal/resolve-cli-tool.js.map +1 -0
  99. package/dist/internal/staging-dir.d.ts +3 -0
  100. package/dist/internal/staging-dir.d.ts.map +1 -0
  101. package/dist/internal/staging-dir.js +16 -0
  102. package/dist/internal/staging-dir.js.map +1 -0
  103. package/dist/internal/xdg-data-dirs.d.ts +2 -0
  104. package/dist/internal/xdg-data-dirs.d.ts.map +1 -0
  105. package/dist/internal/xdg-data-dirs.js +8 -0
  106. package/dist/internal/xdg-data-dirs.js.map +1 -0
  107. package/dist/mcp/client.d.ts +23 -0
  108. package/dist/mcp/client.d.ts.map +1 -0
  109. package/dist/mcp/client.js +157 -0
  110. package/dist/mcp/client.js.map +1 -0
  111. package/dist/mcp/handlers.d.ts +8 -0
  112. package/dist/mcp/handlers.d.ts.map +1 -0
  113. package/dist/mcp/handlers.js +119 -0
  114. package/dist/mcp/handlers.js.map +1 -0
  115. package/dist/mcp/index.d.ts +4 -0
  116. package/dist/mcp/index.d.ts.map +1 -0
  117. package/dist/mcp/index.js +17 -0
  118. package/dist/mcp/index.js.map +1 -0
  119. package/dist/mcp/serialize-widget.d.ts +10 -0
  120. package/dist/mcp/serialize-widget.d.ts.map +1 -0
  121. package/dist/mcp/serialize-widget.js +20 -0
  122. package/dist/mcp/serialize-widget.js.map +1 -0
  123. package/dist/mcp/testing-loader.d.ts +6 -0
  124. package/dist/mcp/testing-loader.d.ts.map +1 -0
  125. package/dist/mcp/testing-loader.js +25 -0
  126. package/dist/mcp/testing-loader.js.map +1 -0
  127. package/dist/mcp/widget-registry.d.ts +13 -0
  128. package/dist/mcp/widget-registry.d.ts.map +1 -0
  129. package/dist/mcp/widget-registry.js +38 -0
  130. package/dist/mcp/widget-registry.js.map +1 -0
  131. package/dist/refresh-runtime.d.ts +10 -20
  132. package/dist/refresh-runtime.d.ts.map +1 -1
  133. package/dist/refresh-runtime.js +12 -36
  134. package/dist/refresh-runtime.js.map +1 -1
  135. package/dist/settings/compile.d.ts +2 -0
  136. package/dist/settings/compile.d.ts.map +1 -0
  137. package/dist/settings/compile.js +19 -0
  138. package/dist/settings/compile.js.map +1 -0
  139. package/dist/settings/parser.d.ts +23 -0
  140. package/dist/settings/parser.d.ts.map +1 -0
  141. package/dist/settings/parser.js +117 -0
  142. package/dist/settings/parser.js.map +1 -0
  143. package/dist/settings/render.d.ts +4 -0
  144. package/dist/settings/render.d.ts.map +1 -0
  145. package/dist/settings/render.js +148 -0
  146. package/dist/settings/render.js.map +1 -0
  147. package/dist/settings/schema.d.ts +13 -0
  148. package/dist/settings/schema.d.ts.map +1 -0
  149. package/dist/settings/schema.js +103 -0
  150. package/dist/settings/schema.js.map +1 -0
  151. package/dist/vite-plugins/asset-extensions.d.ts +4 -0
  152. package/dist/vite-plugins/asset-extensions.d.ts.map +1 -0
  153. package/dist/vite-plugins/asset-extensions.js +27 -0
  154. package/dist/vite-plugins/asset-extensions.js.map +1 -0
  155. package/dist/vite-plugins/built-url.d.ts +3 -0
  156. package/dist/vite-plugins/built-url.d.ts.map +1 -0
  157. package/dist/{vite-plugin-gtkx-built-url.js → vite-plugins/built-url.js} +4 -17
  158. package/dist/vite-plugins/built-url.js.map +1 -0
  159. package/dist/vite-plugins/css.d.ts +3 -0
  160. package/dist/vite-plugins/css.d.ts.map +1 -0
  161. package/dist/vite-plugins/css.js +30 -0
  162. package/dist/vite-plugins/css.js.map +1 -0
  163. package/dist/vite-plugins/fast-refresh/refresh-filter.d.ts +7 -0
  164. package/dist/vite-plugins/fast-refresh/refresh-filter.d.ts.map +1 -0
  165. package/dist/vite-plugins/fast-refresh/refresh-filter.js +15 -0
  166. package/dist/vite-plugins/fast-refresh/refresh-filter.js.map +1 -0
  167. package/dist/vite-plugins/fast-refresh/swc-refresh.d.ts +5 -0
  168. package/dist/vite-plugins/fast-refresh/swc-refresh.d.ts.map +1 -0
  169. package/dist/vite-plugins/fast-refresh/swc-refresh.js +66 -0
  170. package/dist/vite-plugins/fast-refresh/swc-refresh.js.map +1 -0
  171. package/dist/vite-plugins/icons.d.ts +3 -0
  172. package/dist/vite-plugins/icons.d.ts.map +1 -0
  173. package/dist/vite-plugins/icons.js +47 -0
  174. package/dist/vite-plugins/icons.js.map +1 -0
  175. package/dist/vite-plugins/index.d.ts +3 -0
  176. package/dist/vite-plugins/index.d.ts.map +1 -0
  177. package/dist/vite-plugins/index.js +21 -0
  178. package/dist/vite-plugins/index.js.map +1 -0
  179. package/dist/vite-plugins/native.d.ts +3 -0
  180. package/dist/vite-plugins/native.d.ts.map +1 -0
  181. package/dist/vite-plugins/native.js +60 -0
  182. package/dist/vite-plugins/native.js.map +1 -0
  183. package/dist/vite-plugins/react-compiler.d.ts +4 -0
  184. package/dist/vite-plugins/react-compiler.d.ts.map +1 -0
  185. package/dist/vite-plugins/react-compiler.js +56 -0
  186. package/dist/vite-plugins/react-compiler.js.map +1 -0
  187. package/dist/vite-plugins/react-dom-prebundle.d.ts +3 -0
  188. package/dist/vite-plugins/react-dom-prebundle.d.ts.map +1 -0
  189. package/dist/vite-plugins/react-dom-prebundle.js +11 -0
  190. package/dist/vite-plugins/react-dom-prebundle.js.map +1 -0
  191. package/dist/vite-plugins/resource-init-module.d.ts +5 -0
  192. package/dist/vite-plugins/resource-init-module.d.ts.map +1 -0
  193. package/dist/vite-plugins/resource-init-module.js +50 -0
  194. package/dist/vite-plugins/resource-init-module.js.map +1 -0
  195. package/dist/vite-plugins/resource-shared.d.ts +6 -0
  196. package/dist/vite-plugins/resource-shared.d.ts.map +1 -0
  197. package/dist/vite-plugins/resource-shared.js +21 -0
  198. package/dist/vite-plugins/resource-shared.js.map +1 -0
  199. package/dist/vite-plugins/resources.d.ts +4 -0
  200. package/dist/vite-plugins/resources.d.ts.map +1 -0
  201. package/dist/vite-plugins/resources.js +220 -0
  202. package/dist/vite-plugins/resources.js.map +1 -0
  203. package/dist/vite-plugins/settings-worker-env.d.ts +3 -0
  204. package/dist/vite-plugins/settings-worker-env.d.ts.map +1 -0
  205. package/dist/vite-plugins/settings-worker-env.js +21 -0
  206. package/dist/vite-plugins/settings-worker-env.js.map +1 -0
  207. package/dist/vite-plugins/settings.d.ts +3 -0
  208. package/dist/vite-plugins/settings.d.ts.map +1 -0
  209. package/dist/vite-plugins/settings.js +190 -0
  210. package/dist/vite-plugins/settings.js.map +1 -0
  211. package/dist/vite-plugins/undeclared-library.d.ts +3 -0
  212. package/dist/vite-plugins/undeclared-library.d.ts.map +1 -0
  213. package/dist/vite-plugins/undeclared-library.js +47 -0
  214. package/dist/vite-plugins/undeclared-library.js.map +1 -0
  215. package/dist/vite-plugins/virtual-module.d.ts +22 -0
  216. package/dist/vite-plugins/virtual-module.d.ts.map +1 -0
  217. package/dist/vite-plugins/virtual-module.js +18 -0
  218. package/dist/vite-plugins/virtual-module.js.map +1 -0
  219. package/dist/vitest-plugin.d.ts +10 -0
  220. package/dist/vitest-plugin.d.ts.map +1 -0
  221. package/dist/vitest-plugin.js +12 -0
  222. package/dist/vitest-plugin.js.map +1 -0
  223. package/env.d.ts +131 -3
  224. package/package.json +32 -38
  225. package/src/babel-modules.d.ts +13 -0
  226. package/src/builder.ts +28 -76
  227. package/src/cli.ts +22 -0
  228. package/src/codegen/freshness.ts +52 -0
  229. package/src/codegen/report.ts +20 -0
  230. package/src/codegen/run-codegen.ts +185 -0
  231. package/src/codegen/store-resolver.ts +75 -0
  232. package/src/commands/build.ts +37 -0
  233. package/src/commands/codegen.ts +44 -0
  234. package/src/commands/dev.ts +25 -0
  235. package/src/commands/docs.ts +66 -0
  236. package/src/dev/icon-dir.ts +11 -0
  237. package/src/dev/refresh-tracker.ts +21 -0
  238. package/src/dev/runner-deps.ts +42 -0
  239. package/src/dev/runner-main.ts +33 -0
  240. package/src/dev/runner.ts +126 -0
  241. package/src/dev/schema-dir.ts +11 -0
  242. package/src/dev/supervisor.ts +178 -0
  243. package/src/dev/vite-dev-server.ts +34 -0
  244. package/src/internal/banner.ts +9 -0
  245. package/src/internal/data-dir.ts +39 -0
  246. package/src/internal/entry-arg.ts +38 -0
  247. package/src/internal/errors.ts +28 -0
  248. package/src/internal/list-files.ts +17 -0
  249. package/src/internal/resolve-cli-tool.ts +21 -0
  250. package/src/internal/staging-dir.ts +16 -0
  251. package/src/internal/xdg-data-dirs.ts +7 -0
  252. package/src/mcp/client.ts +177 -0
  253. package/src/mcp/handlers.ts +156 -0
  254. package/src/mcp/index.ts +22 -0
  255. package/src/mcp/serialize-widget.ts +34 -0
  256. package/src/mcp/testing-loader.ts +32 -0
  257. package/src/mcp/widget-registry.ts +43 -0
  258. package/src/refresh-runtime.ts +12 -41
  259. package/src/settings/compile.ts +19 -0
  260. package/src/settings/parser.ts +154 -0
  261. package/src/settings/render.ts +167 -0
  262. package/src/settings/schema.ts +115 -0
  263. package/src/vite-plugins/asset-extensions.ts +28 -0
  264. package/src/{vite-plugin-gtkx-built-url.ts → vite-plugins/built-url.ts} +3 -16
  265. package/src/vite-plugins/css.ts +38 -0
  266. package/src/vite-plugins/fast-refresh/refresh-filter.ts +18 -0
  267. package/src/vite-plugins/fast-refresh/swc-refresh.ts +79 -0
  268. package/src/vite-plugins/icons.ts +58 -0
  269. package/src/vite-plugins/index.ts +22 -0
  270. package/src/vite-plugins/native.ts +74 -0
  271. package/src/vite-plugins/react-compiler.ts +70 -0
  272. package/src/vite-plugins/react-dom-prebundle.ts +14 -0
  273. package/src/vite-plugins/resource-init-module.ts +54 -0
  274. package/src/vite-plugins/resource-shared.ts +27 -0
  275. package/src/vite-plugins/resources.ts +272 -0
  276. package/src/vite-plugins/settings-worker-env.ts +25 -0
  277. package/src/vite-plugins/settings.ts +221 -0
  278. package/src/vite-plugins/undeclared-library.ts +69 -0
  279. package/src/vite-plugins/virtual-module.ts +37 -0
  280. package/src/vitest-plugin.ts +14 -0
  281. package/dist/create.d.ts +0 -54
  282. package/dist/create.d.ts.map +0 -1
  283. package/dist/create.js +0 -221
  284. package/dist/create.js.map +0 -1
  285. package/dist/dev-server.d.ts +0 -38
  286. package/dist/dev-server.d.ts.map +0 -1
  287. package/dist/dev-server.js +0 -128
  288. package/dist/dev-server.js.map +0 -1
  289. package/dist/index.d.ts +0 -4
  290. package/dist/index.d.ts.map +0 -1
  291. package/dist/index.js +0 -4
  292. package/dist/index.js.map +0 -1
  293. package/dist/mcp-client.d.ts +0 -31
  294. package/dist/mcp-client.d.ts.map +0 -1
  295. package/dist/mcp-client.js +0 -430
  296. package/dist/mcp-client.js.map +0 -1
  297. package/dist/templates.d.ts +0 -9
  298. package/dist/templates.d.ts.map +0 -1
  299. package/dist/templates.js +0 -16
  300. package/dist/templates.js.map +0 -1
  301. package/dist/vite-plugin-gtkx-assets.d.ts +0 -20
  302. package/dist/vite-plugin-gtkx-assets.d.ts.map +0 -1
  303. package/dist/vite-plugin-gtkx-assets.js +0 -57
  304. package/dist/vite-plugin-gtkx-assets.js.map +0 -1
  305. package/dist/vite-plugin-gtkx-built-url.d.ts +0 -18
  306. package/dist/vite-plugin-gtkx-built-url.d.ts.map +0 -1
  307. package/dist/vite-plugin-gtkx-built-url.js.map +0 -1
  308. package/dist/vite-plugin-gtkx-native.d.ts +0 -14
  309. package/dist/vite-plugin-gtkx-native.d.ts.map +0 -1
  310. package/dist/vite-plugin-gtkx-native.js +0 -53
  311. package/dist/vite-plugin-gtkx-native.js.map +0 -1
  312. package/dist/vite-plugin-gtkx-refresh.d.ts +0 -8
  313. package/dist/vite-plugin-gtkx-refresh.d.ts.map +0 -1
  314. package/dist/vite-plugin-gtkx-refresh.js +0 -37
  315. package/dist/vite-plugin-gtkx-refresh.js.map +0 -1
  316. package/dist/vite-plugin-swc-ssr-refresh.d.ts +0 -8
  317. package/dist/vite-plugin-swc-ssr-refresh.d.ts.map +0 -1
  318. package/dist/vite-plugin-swc-ssr-refresh.js +0 -46
  319. package/dist/vite-plugin-swc-ssr-refresh.js.map +0 -1
  320. package/src/cli.tsx +0 -154
  321. package/src/create.ts +0 -310
  322. package/src/dev-server.tsx +0 -162
  323. package/src/index.ts +0 -3
  324. package/src/mcp-client.ts +0 -518
  325. package/src/templates.ts +0 -26
  326. package/src/vite-plugin-gtkx-assets.ts +0 -69
  327. package/src/vite-plugin-gtkx-native.ts +0 -64
  328. package/src/vite-plugin-gtkx-refresh.ts +0 -54
  329. package/src/vite-plugin-swc-ssr-refresh.ts +0 -61
  330. package/templates/claude/EXAMPLES.md.ejs +0 -744
  331. package/templates/claude/SKILL.md.ejs +0 -93
  332. package/templates/claude/WIDGETS.md.ejs +0 -820
  333. package/templates/config/vitest.config.ts.ejs +0 -11
  334. package/templates/gitignore.ejs +0 -4
  335. package/templates/package.json.ejs +0 -16
  336. package/templates/src/app.tsx.ejs +0 -32
  337. package/templates/src/dev.tsx.ejs +0 -5
  338. package/templates/src/gtkx-env.d.ts.ejs +0 -1
  339. package/templates/src/index.tsx.ejs +0 -5
  340. package/templates/tests/app.test.tsx.ejs +0 -16
  341. package/templates/tsconfig.json.ejs +0 -14
@@ -1,820 +0,0 @@
1
- # GTKX Widget Reference
2
-
3
- ## Common Props (All Widgets)
4
-
5
- | Prop | Type | Description |
6
- |------|------|-------------|
7
- | `hexpand` / `vexpand` | boolean | Expand to fill available space |
8
- | `halign` / `valign` | `Gtk.Align.START \| CENTER \| END \| FILL` | Alignment |
9
- | `marginStart/End/Top/Bottom` | number | Margins in pixels |
10
- | `sensitive` | boolean | Enabled/disabled state |
11
- | `visible` | boolean | Visibility |
12
- | `cssClasses` | string[] | CSS classes for styling |
13
- | `widthRequest` / `heightRequest` | number | Minimum size |
14
-
15
- ---
16
-
17
- ## Containers
18
-
19
- ### GtkBox
20
- Linear layout (horizontal or vertical).
21
-
22
- ```tsx
23
- <GtkBox orientation={Gtk.Orientation.VERTICAL} spacing={12}>
24
- {children}
25
- </GtkBox>
26
- ```
27
-
28
- ### GtkGrid
29
- 2D grid with explicit positioning using `GridChild`.
30
-
31
- ```tsx
32
- <GtkGrid rowSpacing={8} columnSpacing={12}>
33
- <x.GridChild column={0} row={0}><GtkLabel label="Name:" /></x.GridChild>
34
- <x.GridChild column={1} row={0}><GtkEntry hexpand /></x.GridChild>
35
- <x.GridChild column={0} row={1} columnSpan={2}><GtkButton label="Submit" /></x.GridChild>
36
- </GtkGrid>
37
- ```
38
-
39
- **GridChild props:** `column`, `row`, `columnSpan`, `rowSpan`
40
-
41
- ### GtkStack
42
- Page container, shows one child at a time.
43
-
44
- ```tsx
45
- <GtkStack page="page1" transitionType={Gtk.StackTransitionType.SLIDE_LEFT_RIGHT}>
46
- <x.StackPage id="page1" title="First" iconName="document-new">
47
- <Content1 />
48
- </x.StackPage>
49
- <x.StackPage id="page2" title="Second">
50
- <Content2 />
51
- </x.StackPage>
52
- </GtkStack>
53
- ```
54
-
55
- **StackPage props:** `id` (optional), `title`, `iconName`, `needsAttention`, `badgeNumber` (AdwViewStack only)
56
-
57
- ### GtkNotebook
58
- Tabbed container with visible tabs.
59
-
60
- ```tsx
61
- <GtkNotebook>
62
- <x.NotebookPage label="Tab 1"><Content1 /></x.NotebookPage>
63
- <x.NotebookPage label="Tab 2" tabExpand tabFill><Content2 /></x.NotebookPage>
64
- </GtkNotebook>
65
- ```
66
-
67
- Custom tab widget:
68
- ```tsx
69
- <x.NotebookPage>
70
- <x.NotebookPageTab>
71
- <GtkBox spacing={4}>
72
- <GtkImage iconName="folder-symbolic" />
73
- <GtkLabel label="Files" />
74
- </GtkBox>
75
- </x.NotebookPageTab>
76
- <Content />
77
- </x.NotebookPage>
78
- ```
79
-
80
- **NotebookPage props:** `label`, `tabExpand`, `tabFill`
81
-
82
- ### GtkPaned
83
- Resizable split with draggable divider. **Requires Slot components.**
84
-
85
- ```tsx
86
- <GtkPaned position={280} shrinkStartChild={false}>
87
- <x.Slot for={GtkPaned} id="startChild"><Sidebar /></x.Slot>
88
- <x.Slot for={GtkPaned} id="endChild"><MainContent /></x.Slot>
89
- </GtkPaned>
90
- ```
91
-
92
- ### GtkOverlay
93
- Stack widgets on top of each other. First child is base layer, additional children need `OverlayChild` wrapper. Multiple children supported per overlay.
94
-
95
- ```tsx
96
- <GtkOverlay>
97
- <GtkButton label="Notifications" />
98
- <x.OverlayChild>
99
- <GtkLabel label="3" cssClasses={["badge"]} halign={Gtk.Align.END} valign={Gtk.Align.START} />
100
- </x.OverlayChild>
101
- </GtkOverlay>
102
- ```
103
-
104
- ### GtkFixed
105
- Absolute positioning with optional 3D transforms. Use `x.FixedChild` wrapper for children.
106
-
107
- ```tsx
108
- <GtkFixed>
109
- <x.FixedChild x={20} y={30}>
110
- <GtkLabel label="Top Left" />
111
- </x.FixedChild>
112
- <x.FixedChild x={200} y={100} transform={someGskTransform}>
113
- <GtkLabel label="Transformed" />
114
- </x.FixedChild>
115
- </GtkFixed>
116
- ```
117
-
118
- **FixedChild props:** `x`, `y` (pixel coordinates), `transform` (optional `Gsk.Transform`)
119
-
120
- ### GtkScrolledWindow
121
- Scrollable container.
122
-
123
- ```tsx
124
- <GtkScrolledWindow vexpand hscrollbarPolicy={Gtk.PolicyType.NEVER}>
125
- <Content />
126
- </GtkScrolledWindow>
127
- ```
128
-
129
- ---
130
-
131
- ## Virtual Lists
132
-
133
- All virtual list widgets use an `items` data prop and a `renderItem` function. Items are `{ id: string, value: T }` objects.
134
-
135
- ### GtkListView
136
- High-performance scrollable list with selection.
137
-
138
- ```tsx
139
- <GtkListView
140
- estimatedItemHeight={48}
141
- vexpand
142
- selected={selectedId ? [selectedId] : []}
143
- selectionMode={Gtk.SelectionMode.SINGLE}
144
- onSelectionChanged={(ids) => setSelectedId(ids[0])}
145
- items={items.map(item => ({ id: item.id, value: item }))}
146
- renderItem={(item: Item) => <GtkLabel label={item.name} />}
147
- />
148
- ```
149
-
150
- ### GtkGridView
151
- Grid-based virtual scrolling.
152
-
153
- ```tsx
154
- <GtkGridView
155
- estimatedItemHeight={100}
156
- minColumns={2}
157
- maxColumns={4}
158
- items={items.map(item => ({ id: item.id, value: item }))}
159
- renderItem={(item: Item) => (
160
- <GtkBox orientation={Gtk.Orientation.VERTICAL}>
161
- <GtkImage iconName={item.icon} />
162
- <GtkLabel label={item.name} />
163
- </GtkBox>
164
- )}
165
- />
166
- ```
167
-
168
- ### GtkColumnView
169
- Table with sortable columns.
170
-
171
- ```tsx
172
- <GtkColumnView
173
- estimatedRowHeight={48}
174
- sortColumn="name"
175
- sortOrder={Gtk.SortType.ASCENDING}
176
- onSortChanged={handleSort}
177
- items={items.map(item => ({ id: item.id, value: item }))}
178
- >
179
- <x.ColumnViewColumn
180
- title="Name"
181
- id="name"
182
- expand
183
- resizable
184
- sortable
185
- renderCell={(item: Item) => <GtkLabel label={item.name} />}
186
- />
187
- <x.ColumnViewColumn
188
- title="Size"
189
- id="size"
190
- fixedWidth={100}
191
- renderCell={(item: Item) => <GtkLabel label={`${item.size} KB`} />}
192
- />
193
- </GtkColumnView>
194
- ```
195
-
196
- ### GtkDropDown
197
- Selection dropdown.
198
-
199
- ```tsx
200
- <GtkDropDown
201
- selectedId={selectedId}
202
- onSelectionChanged={setSelectedId}
203
- items={options.map(opt => ({ id: opt.id, value: opt.label }))}
204
- />
205
- ```
206
-
207
- ### GtkListView (tree mode)
208
- Hierarchical tree with expand/collapse. Items with nested `children` arrays trigger tree behavior.
209
-
210
- ```tsx
211
- <GtkListView
212
- estimatedItemHeight={48}
213
- vexpand
214
- autoexpand={false}
215
- selectionMode={Gtk.SelectionMode.SINGLE}
216
- selected={selectedId ? [selectedId] : []}
217
- onSelectionChanged={(ids) => setSelectedId(ids[0])}
218
- items={files.map(file => ({
219
- id: file.id,
220
- value: file,
221
- children: file.children?.map(child => ({ id: child.id, value: child })),
222
- }))}
223
- renderItem={(item: FileNode, row) => (
224
- <GtkBox spacing={8}>
225
- <GtkImage iconName={item.isDirectory ? "folder-symbolic" : "text-x-generic-symbolic"} />
226
- <GtkLabel label={item.name} />
227
- </GtkBox>
228
- )}
229
- />
230
- ```
231
-
232
- **ListItem data props:** `id`, `value`, `children` (nested items for tree mode), `hideExpander`, `indentForDepth`, `indentForIcon`, `section` (for sectioned lists)
233
-
234
- ---
235
-
236
- ## Inputs
237
-
238
- ### GtkEntry
239
- Single-line text input. **Requires two-way binding.**
240
-
241
- ```tsx
242
- const [text, setText] = useState("");
243
- <GtkEntry text={text} onChanged={(e) => setText(e.getText())} placeholderText="Enter text..." />
244
- ```
245
-
246
- ### GtkToggleButton
247
- Toggle button. Auto-prevents signal feedback loops.
248
-
249
- ```tsx
250
- <GtkToggleButton active={isActive} onToggled={() => setIsActive(!isActive)} label="Toggle" />
251
- ```
252
-
253
- ### GtkCheckButton
254
- Checkbox.
255
-
256
- ```tsx
257
- <GtkCheckButton active={checked} onToggled={() => setChecked(!checked)} label="Option" />
258
- ```
259
-
260
- ### GtkSwitch
261
- On/off switch.
262
-
263
- ```tsx
264
- <GtkSwitch active={enabled} onStateSet={() => { setEnabled(!enabled); return true; }} />
265
- ```
266
-
267
- ### GtkSpinButton
268
- Numeric input with increment/decrement. Adjustment props are set directly.
269
-
270
- ```tsx
271
- <GtkSpinButton
272
- value={count}
273
- lower={0}
274
- upper={100}
275
- stepIncrement={1}
276
- onValueChanged={setCount}
277
- />
278
- ```
279
-
280
- ### GtkScale
281
- Slider with adjustment props and optional marks.
282
-
283
- ```tsx
284
- <GtkScale
285
- drawValue
286
- valuePos={Gtk.PositionType.TOP}
287
- value={volume}
288
- lower={0}
289
- upper={100}
290
- stepIncrement={1}
291
- onValueChanged={setVolume}
292
- marks={[
293
- { value: 0, label: "Min", position: Gtk.PositionType.BOTTOM },
294
- { value: 50, position: Gtk.PositionType.BOTTOM },
295
- { value: 100, label: "Max", position: Gtk.PositionType.BOTTOM },
296
- ]}
297
- />
298
- ```
299
-
300
- **Adjustment props:** `value`, `lower`, `upper`, `stepIncrement`, `pageIncrement`, `pageSize`, `onValueChanged`
301
- **ScaleMark type:** `{ value: number, position?: Gtk.PositionType, label?: string }`
302
-
303
- ### GtkCalendar
304
- Date picker with markable days.
305
-
306
- ```tsx
307
- <GtkCalendar
308
- onDaySelected={(cal) => setDate(cal.getDate())}
309
- markedDays={[15, 20, 25]}
310
- />
311
- ```
312
-
313
- ### GtkLevelBar
314
- Progress/level indicator with customizable thresholds.
315
-
316
- ```tsx
317
- <GtkLevelBar
318
- value={0.6}
319
- offsets={[
320
- { id: "low", value: 0.25 },
321
- { id: "high", value: 0.75 },
322
- { id: "full", value: 1.0 },
323
- ]}
324
- />
325
- ```
326
-
327
- **LevelBarOffset type:** `{ id: string, value: number }`
328
-
329
- ---
330
-
331
- ## Display
332
-
333
- ### GtkLabel
334
- ```tsx
335
- <GtkLabel label="Text" halign={Gtk.Align.START} wrap useMarkup />
336
- ```
337
-
338
- ### GtkButton
339
- ```tsx
340
- <GtkButton label="Click" onClicked={handleClick} iconName="document-new-symbolic" />
341
- ```
342
-
343
- ### GtkImage
344
- ```tsx
345
- <GtkImage iconName="folder-symbolic" pixelSize={48} />
346
- ```
347
-
348
- ---
349
-
350
- ## Header & Action Bars
351
-
352
- ### GtkHeaderBar
353
- Title bar with packed widgets. Use `x.ContainerSlot` for packing and `x.Slot` for titleWidget.
354
-
355
- ```tsx
356
- <GtkHeaderBar>
357
- <x.ContainerSlot for={GtkHeaderBar} id="packStart"><GtkButton iconName="go-previous-symbolic" /></x.ContainerSlot>
358
- <x.Slot for={GtkHeaderBar} id="titleWidget">
359
- <GtkLabel label="Title" cssClasses={["title"]} />
360
- </x.Slot>
361
- <x.ContainerSlot for={GtkHeaderBar} id="packEnd"><GtkMenuButton iconName="open-menu-symbolic" /></x.ContainerSlot>
362
- </GtkHeaderBar>
363
- ```
364
-
365
- ### GtkActionBar
366
- Bottom action bar.
367
-
368
- ```tsx
369
- <GtkActionBar>
370
- <x.ContainerSlot for={GtkActionBar} id="packStart"><GtkButton label="Cancel" /></x.ContainerSlot>
371
- <x.ContainerSlot for={GtkActionBar} id="packEnd"><GtkButton label="Save" cssClasses={["suggested-action"]} /></x.ContainerSlot>
372
- </GtkActionBar>
373
- ```
374
-
375
- ---
376
-
377
- ## Menus
378
-
379
- ### GtkPopoverMenu with GtkMenuButton
380
-
381
- ```tsx
382
- <GtkMenuButton iconName="open-menu-symbolic">
383
- <x.Slot for={GtkMenuButton} id="popover">
384
- <GtkPopoverMenu>
385
- <x.MenuSection>
386
- <x.MenuItem id="new" label="New" onActivate={handleNew} accels="<Control>n" />
387
- <x.MenuItem id="open" label="Open" onActivate={handleOpen} />
388
- </x.MenuSection>
389
- <x.MenuSection>
390
- <x.MenuSubmenu label="Export">
391
- <x.MenuItem id="pdf" label="PDF" onActivate={exportPdf} />
392
- <x.MenuItem id="csv" label="CSV" onActivate={exportCsv} />
393
- </x.MenuSubmenu>
394
- </x.MenuSection>
395
- <x.MenuSection>
396
- <x.MenuItem id="quit" label="Quit" onActivate={quit} accels="<Control>q" />
397
- </x.MenuSection>
398
- </GtkPopoverMenu>
399
- </x.Slot>
400
- </GtkMenuButton>
401
- ```
402
-
403
- **Menu.Item props:** `id` (required), `label`, `onActivate`, `accels` (e.g., `"<Control>n"`)
404
-
405
- ---
406
-
407
- ## Windows
408
-
409
- ### GtkApplicationWindow
410
-
411
- ```tsx
412
- <GtkApplicationWindow
413
- title="App"
414
- defaultWidth={800}
415
- defaultHeight={600}
416
- onClose={quit}
417
- >
418
- <Content />
419
- </GtkApplicationWindow>
420
- ```
421
-
422
- Custom titlebar:
423
- ```tsx
424
- <GtkApplicationWindow ...>
425
- <x.Slot for={GtkWindow} id="titlebar">
426
- <GtkHeaderBar />
427
- </x.Slot>
428
- <Content />
429
- </GtkApplicationWindow>
430
- ```
431
-
432
- ---
433
-
434
- ## Adwaita (Libadwaita)
435
-
436
- Import: `import * as Adw from "@gtkx/ffi/adw";`
437
-
438
- ### AdwApplicationWindow + AdwToolbarView
439
- Modern app structure.
440
-
441
- ```tsx
442
- <AdwApplicationWindow title="App" defaultWidth={800} defaultHeight={600} onClose={quit}>
443
- <AdwToolbarView>
444
- <x.ContainerSlot for={AdwToolbarView} id="addTopBar">
445
- <AdwHeaderBar>
446
- <x.Slot for={AdwHeaderBar} id="titleWidget">
447
- <AdwWindowTitle title="App" subtitle="Description" />
448
- </x.Slot>
449
- </AdwHeaderBar>
450
- </x.ContainerSlot>
451
- <MainContent />
452
- <x.ContainerSlot for={AdwToolbarView} id="addBottomBar">
453
- <GtkActionBar />
454
- </x.ContainerSlot>
455
- </AdwToolbarView>
456
- </AdwApplicationWindow>
457
- ```
458
-
459
- ### AdwStatusPage
460
- Welcome, error, or empty state.
461
-
462
- ```tsx
463
- <AdwStatusPage iconName="applications-system-symbolic" title="Welcome" description="Get started" vexpand>
464
- <GtkButton label="Start" cssClasses={["suggested-action", "pill"]} halign={Gtk.Align.CENTER} />
465
- </AdwStatusPage>
466
- ```
467
-
468
- ### AdwBanner
469
- Dismissable notification.
470
-
471
- ```tsx
472
- <AdwBanner title="Update available" buttonLabel="Dismiss" revealed={show} onButtonClicked={() => setShow(false)} />
473
- ```
474
-
475
- ### AdwPreferencesPage / AdwPreferencesGroup
476
- Settings UI.
477
-
478
- ```tsx
479
- <AdwPreferencesPage title="Settings">
480
- <AdwPreferencesGroup title="Appearance" description="Customize look">
481
- <AdwSwitchRow title="Dark Mode" active={dark} onActivated={() => setDark(!dark)} />
482
- <AdwActionRow title="Theme" subtitle="Select color">
483
- <x.ContainerSlot for={AdwActionRow} id="addPrefix">
484
- <GtkImage iconName="preferences-color-symbolic" />
485
- </x.ContainerSlot>
486
- <x.ContainerSlot for={AdwActionRow} id="addSuffix">
487
- <GtkImage iconName="go-next-symbolic" valign={Gtk.Align.CENTER} />
488
- </x.ContainerSlot>
489
- </AdwActionRow>
490
- </AdwPreferencesGroup>
491
- </AdwPreferencesPage>
492
- ```
493
-
494
- **ActionRow children:** Use `x.ContainerSlot for={AdwActionRow} id="addPrefix"` for left widgets, `x.ContainerSlot for={AdwActionRow} id="addSuffix"` for right widgets, or `x.Slot for={AdwActionRow} id="activatableWidget"` for clickable suffix.
495
-
496
- ### AdwExpanderRow
497
- Expandable settings row with optional action widget.
498
-
499
- ```tsx
500
- <AdwExpanderRow title="Advanced" subtitle="More options">
501
- <x.ContainerSlot for={AdwExpanderRow} id="addAction">
502
- <GtkButton iconName="emblem-system-symbolic" cssClasses={["flat"]} />
503
- </x.ContainerSlot>
504
- <x.ContainerSlot for={AdwExpanderRow} id="addRow">
505
- <AdwSwitchRow title="Option 1" active />
506
- <AdwSwitchRow title="Option 2" />
507
- </x.ContainerSlot>
508
- </AdwExpanderRow>
509
- ```
510
-
511
- **ExpanderRow slots:** `x.ContainerSlot for={AdwExpanderRow} id="addRow"` for nested rows, `x.ContainerSlot for={AdwExpanderRow} id="addAction"` for header action widget. Direct children also work for simple cases.
512
-
513
- ### AdwEntryRow / AdwPasswordEntryRow
514
- Input in list row.
515
-
516
- ```tsx
517
- <AdwEntryRow title="Username" text={username} onChanged={(e) => setUsername(e.getText())} />
518
- <AdwPasswordEntryRow title="Password" />
519
- ```
520
-
521
- ### AdwToggleGroup
522
- Segmented button group for mutually exclusive options.
523
-
524
- ```tsx
525
- const [mode, setMode] = useState("list");
526
-
527
- <AdwToggleGroup activeName={mode} onActiveChanged={(_index, name) => setMode(name ?? "list")}>
528
- <x.Toggle id="list" iconName="view-list-symbolic" tooltip="List view" />
529
- <x.Toggle id="grid" iconName="view-grid-symbolic" tooltip="Grid view" />
530
- <x.Toggle id="flow" label="Flow" />
531
- </AdwToggleGroup>
532
- ```
533
-
534
- **ToggleGroup props:** `activeName`, `active` (index), `onActiveChanged` (callback with index and name)
535
-
536
- **Toggle props:** `id` (optional), `label`, `iconName`, `tooltip`, `enabled`
537
-
538
- ### AdwNavigationView
539
- Stack-based navigation with history.
540
-
541
- ```tsx
542
- const [history, setHistory] = useState(["home"]);
543
-
544
- <AdwNavigationView history={history} onHistoryChanged={setHistory}>
545
- <x.NavigationPage for={AdwNavigationView} id="home" title="Home">
546
- <GtkButton label="Go to Details" onClicked={() => setHistory([...history, "details"])} />
547
- </x.NavigationPage>
548
- <x.NavigationPage for={AdwNavigationView} id="details" title="Details" canPop>
549
- <GtkLabel label="Details content" />
550
- </x.NavigationPage>
551
- </AdwNavigationView>
552
- ```
553
-
554
- **NavigationPage props:** `for` (required, parent widget type), `id` (required), `title`, `canPop`. Control navigation via `history` array.
555
-
556
- ### AdwNavigationSplitView
557
- Sidebar/content split layout for master-detail interfaces.
558
-
559
- ```tsx
560
- const [selected, setSelected] = useState(items[0]);
561
-
562
- <AdwNavigationSplitView sidebarWidthFraction={0.33} minSidebarWidth={200} maxSidebarWidth={300}>
563
- <x.NavigationPage for={AdwNavigationSplitView} id="sidebar" title="Sidebar">
564
- <AdwToolbarView>
565
- <x.ContainerSlot for={AdwToolbarView} id="addTopBar"><AdwHeaderBar /></x.ContainerSlot>
566
- <GtkListBox cssClasses={["navigation-sidebar"]} onRowSelected={(row) => {
567
- if (!row) return;
568
- const item = items[row.getIndex()];
569
- if (item) setSelected(item);
570
- }}>
571
- {items.map((item) => <AdwActionRow key={item.id} title={item.title} />)}
572
- </GtkListBox>
573
- </AdwToolbarView>
574
- </x.NavigationPage>
575
-
576
- <x.NavigationPage for={AdwNavigationSplitView} id="content" title={selected?.title ?? ""}>
577
- <AdwToolbarView>
578
- <x.ContainerSlot for={AdwToolbarView} id="addTopBar"><AdwHeaderBar /></x.ContainerSlot>
579
- <GtkLabel label={selected?.title ?? ""} />
580
- </AdwToolbarView>
581
- </x.NavigationPage>
582
- </AdwNavigationSplitView>
583
- ```
584
-
585
- **Props:** `sidebarWidthFraction`, `minSidebarWidth`, `maxSidebarWidth`, `collapsed`, `showContent`.
586
- **NavigationPage:** Use `for={AdwNavigationSplitView}` with `id="sidebar"` for left pane, `id="content"` for right pane.
587
- **Selection:** Use `GtkListBox` with `onRowSelected` (single click) not `onRowActivated` (double click).
588
-
589
- ### AdwAlertDialog
590
- Modern modal alert dialogs with response buttons.
591
-
592
- ```tsx
593
- const [showDialog, setShowDialog] = useState(false);
594
-
595
- {showDialog && (
596
- <AdwAlertDialog
597
- heading="Delete File?"
598
- body="This action cannot be undone."
599
- onResponse={(id) => {
600
- if (id === "delete") handleDelete();
601
- setShowDialog(false);
602
- }}
603
- >
604
- <x.AlertDialogResponse id="cancel" label="Cancel" />
605
- <x.AlertDialogResponse id="delete" label="Delete" appearance={Adw.ResponseAppearance.DESTRUCTIVE} />
606
- </AdwAlertDialog>
607
- )}
608
- ```
609
-
610
- **AlertDialogResponse props:** `id`, `label`, `appearance` (SUGGESTED, DESTRUCTIVE), `enabled`
611
-
612
- ### GtkColorDialogButton / GtkFontDialogButton
613
- Color and font picker dialogs.
614
-
615
- ```tsx
616
- <GtkColorDialogButton rgba={color} onRgbaChanged={setColor} title="Select Color" modal withAlpha />
617
- <GtkFontDialogButton fontDesc={font} onFontDescChanged={setFont} title="Select Font" modal useFont useSize />
618
- ```
619
-
620
- ### Other Adwaita Widgets
621
-
622
- | Widget | Description |
623
- |--------|-------------|
624
- | `AdwClamp` | Limits content width (`maximumSize={600}`) |
625
- | `AdwAvatar` | User avatar (`size={48} text="Name" showInitials`) |
626
- | `AdwSpinner` | Loading indicator |
627
- | `AdwWindowTitle` | Title + subtitle for header bars |
628
- | `AdwButtonRow` | Button styled as list row |
629
-
630
- ---
631
-
632
- ## Animations
633
-
634
- Wrap widgets in `x.Animation` for declarative animations with spring or timed transitions:
635
-
636
- ```tsx
637
- <x.Animation
638
- initial={{ opacity: 0, scale: 0.8 }}
639
- animate={{ opacity: 1, scale: 1 }}
640
- transition={{ mode: "spring", damping: 0.8, stiffness: 200, mass: 1 }}
641
- animateOnMount
642
- onAnimationComplete={() => console.log("done")}
643
- >
644
- <GtkBox>...</GtkBox>
645
- </x.Animation>
646
- ```
647
-
648
- **Props:** `initial`, `animate`, `exit`, `transition` (`AnimationTransition` discriminated union), `animateOnMount`, `onAnimationStart`, `onAnimationComplete`
649
-
650
- **Spring transition:** `{ mode: "spring", damping, stiffness, mass, initialVelocity, clamp, delay }`
651
-
652
- **Timed transition:** `{ mode: "timed", duration, easing (from Adw.Easing), delay, repeat, reverse, alternate }`
653
-
654
- ---
655
-
656
- ## Drag and Drop
657
-
658
- All widgets support drag-and-drop through props. Use `onDragPrepare`, `onDragBegin`, and `onDragEnd` to make a widget draggable, and `dropTypes`, `onDrop`, `onDropEnter`, and `onDropLeave` to accept drops.
659
-
660
- ```tsx
661
- import * as Gdk from "@gtkx/ffi/gdk";
662
- import { Type, Value } from "@gtkx/ffi/gobject";
663
-
664
- const DraggableButton = ({ label }: { label: string }) => (
665
- <GtkButton
666
- label={label}
667
- onDragPrepare={() => Gdk.ContentProvider.newForValue(Value.newFromString(label))}
668
- dragIcon={someTexture}
669
- dragIconHotX={16}
670
- dragIconHotY={16}
671
- />
672
- );
673
-
674
- const DropZone = () => {
675
- const [dropped, setDropped] = useState<string | null>(null);
676
- return (
677
- <GtkBox
678
- dropTypes={[Type.STRING]}
679
- onDrop={(value: Value) => { setDropped(value.getString()); return true; }}
680
- >
681
- <GtkLabel label={dropped ?? "Drop here"} />
682
- </GtkBox>
683
- );
684
- };
685
- ```
686
-
687
- **Drag source props:** `dragIcon`, `dragIconHotX`, `dragIconHotY`
688
-
689
- ## GValue Factories
690
-
691
- Create typed values for drag-and-drop and signal emission:
692
-
693
- | Factory | Description |
694
- | ------------------------------ | ----------------------------- |
695
- | `Value.newFromString(str)` | String values |
696
- | `Value.newFromDouble(num)` | 64-bit floating point |
697
- | `Value.newFromInt(num)` | 32-bit signed integer |
698
- | `Value.newFromBoolean(bool)` | Boolean values |
699
- | `Value.newFromObject(obj)` | GObject instances |
700
- | `Value.newFromBoxed(boxed)` | Boxed types (Gdk.RGBA, etc.) |
701
- | `Value.newFromEnum(gtype, n)` | Enum values (requires GType) |
702
- | `Value.newFromFlags(gtype, n)` | Flags values (requires GType) |
703
-
704
- Type constants for `dropTypes`: `Type.STRING`, `Type.INT`, `Type.DOUBLE`, `Type.BOOLEAN`, `Type.OBJECT`.
705
-
706
- ## Custom Drawing
707
-
708
- Render custom graphics with `GtkDrawingArea` using the `onDraw` callback:
709
-
710
- ```tsx
711
- import type { Context } from "@gtkx/ffi/cairo";
712
-
713
- const Canvas = () => {
714
- const handleDraw = (self: Gtk.DrawingArea, cr: Context, width: number, height: number) => {
715
- cr.setSourceRgb(0.2, 0.4, 0.8);
716
- cr.rectangle(10, 10, width - 20, height - 20);
717
- cr.fill();
718
- };
719
-
720
- return <GtkDrawingArea contentWidth={400} contentHeight={300} onDraw={handleDraw} />;
721
- };
722
- ```
723
-
724
- Add a `GtkGestureDrag` child for interactive drawing. Call `widget.queueDraw()` to trigger redraws.
725
-
726
- ## Event Controllers
727
-
728
- Event controllers are added as children to any widget. They are auto-generated from GTK's introspection data.
729
-
730
- ```tsx
731
- <GtkBox focusable>
732
- <GtkEventControllerMotion
733
- onEnter={(x, y) => console.log("Entered at", x, y)}
734
- onMotion={(x, y) => setPosition({ x, y })}
735
- onLeave={() => console.log("Left")}
736
- />
737
- <GtkEventControllerKey
738
- onKeyPressed={(keyval, keycode, state) => {
739
- console.log("Key pressed:", keyval);
740
- return false;
741
- }}
742
- />
743
- <GtkGestureClick onPressed={(nPress, x, y) => console.log("Clicked")} />
744
- <GtkLabel label="Hover or type here" />
745
- </GtkBox>
746
- ```
747
-
748
- **Input controllers:** `GtkEventControllerMotion`, `GtkEventControllerKey`, `GtkEventControllerScroll`, `GtkEventControllerFocus`
749
-
750
- **Gesture controllers:** `GtkGestureClick`, `GtkGestureDrag`, `GtkGestureLongPress`, `GtkGestureZoom`, `GtkGestureRotate`, `GtkGestureSwipe`, `GtkGestureStylus`, `GtkGesturePan`
751
-
752
- **Drag-and-drop:** `GtkDragSource`, `GtkDropTarget`, `GtkDropControllerMotion`
753
-
754
- ## SearchBar
755
-
756
- ```tsx
757
- const [searchActive, setSearchActive] = useState(false);
758
-
759
- <GtkSearchBar searchModeEnabled={searchActive} onSearchModeChanged={setSearchActive}>
760
- <GtkSearchEntry text={query} onSearchChanged={(entry) => setQuery(entry.getText())} />
761
- </GtkSearchBar>
762
- ```
763
-
764
- The `onSearchModeChanged` callback fires when search mode changes (e.g., user presses Escape).
765
-
766
- ## TextView / SourceView
767
-
768
- Text content is provided as direct children. Use `x.TextTag` for formatting and `x.TextAnchor` for embedded widgets.
769
-
770
- ```tsx
771
- <GtkTextView enableUndo onBufferChanged={(text) => console.log(text)}>
772
- Normal text, <x.TextTag id="bold" weight={Pango.Weight.BOLD}>bold</x.TextTag>, and
773
- <x.TextAnchor><GtkButton label="Click" /></x.TextAnchor> inline.
774
- </GtkTextView>
775
- ```
776
-
777
- **TextView props:** `enableUndo`, `onBufferChanged`, `onTextInserted`, `onTextDeleted`, `onCanUndoChanged`, `onCanRedoChanged`
778
-
779
- **TextTag props:** `id` (required), `priority`, `foreground`, `background`, `weight`, `style`, `underline`, `strikethrough`, `family`, `size`, `sizePoints`, `scale`, `justification`, `leftMargin`, `rightMargin`, `indent`, `editable`, `invisible`
780
-
781
- **TextAnchor:** Embeds widgets inline with `children`
782
-
783
- **TextPaintable:** Embeds images inline with `paintable` prop
784
-
785
- ```tsx
786
- <GtkSourceView
787
- showLineNumbers
788
- highlightCurrentLine
789
- language="typescript"
790
- styleScheme="Adwaita-dark"
791
- highlightSyntax
792
- highlightMatchingBrackets
793
- enableUndo
794
- onBufferChanged={setCode}
795
- >
796
- {code}
797
- </GtkSourceView>
798
- ```
799
-
800
- **SourceView additional props:** `language`, `styleScheme`, `highlightSyntax`, `highlightMatchingBrackets`, `implicitTrailingNewline`, `onCursorMoved`, `onHighlightUpdated`
801
-
802
- ## Keyboard Shortcuts
803
-
804
- Attach shortcuts with `<GtkShortcutController>` and `x.Shortcut`:
805
-
806
- ```tsx
807
- <GtkBox orientation={Gtk.Orientation.VERTICAL} spacing={12} focusable>
808
- <GtkShortcutController scope={Gtk.ShortcutScope.LOCAL}>
809
- <x.Shortcut trigger="<Control>equal" onActivate={() => setCount((c) => c + 1)} />
810
- <x.Shortcut trigger="<Control>minus" onActivate={() => setCount((c) => c - 1)} />
811
- </GtkShortcutController>
812
- <GtkLabel label={`Count: ${count}`} />
813
- </GtkBox>
814
- ```
815
-
816
- **Scopes:** `LOCAL` (widget focus), `MANAGED` (parent managed), `GLOBAL` (window-wide)
817
-
818
- **Trigger syntax:** `<Control>s`, `<Control><Shift>s`, `<Alt>F4`, `<Primary>q`, `F5`
819
-
820
- **Multiple triggers:** `trigger={["F5", "<Control>r"]}`