├── .gitattributes ├── src ├── store.ts ├── web-ponyfill.ts ├── gobject.ts ├── gtk4 │ ├── displays.tsx │ ├── entries.tsx │ ├── buttons.tsx │ ├── index.ts │ ├── windows.tsx │ ├── containers.tsx │ └── common.ts ├── index.ts ├── storage.ts ├── jsx-runtime.ts ├── widget.tsx ├── reactive.ts └── fetch.ts ├── .gitignore ├── bun.lockb ├── .editorconfig ├── typedoc.json ├── docs ├── typescript.md ├── build-app.md └── jsx.md ├── tsconfig.json ├── README.md ├── package.json └── LICENSE /.gitattributes: -------------------------------------------------------------------------------- 1 | *.lockb binary diff=lockb -------------------------------------------------------------------------------- /src/store.ts: -------------------------------------------------------------------------------- 1 | export * from "solid-js/store"; 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | types/ 3 | docs-dist/ 4 | node_modules -------------------------------------------------------------------------------- /bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thislight/gsolid/HEAD/bun.lockb -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 4 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = false 12 | insert_final_newline = false 13 | 14 | [*.ts,*.js,*.tsx,*.jsx] 15 | indent_size = 2 -------------------------------------------------------------------------------- /src/web-ponyfill.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This module includes some API implementations, which is not exists in gjs, for solid js. 3 | * 4 | * This module injects into solid js by a bundler, and is not intended to be used by user code. 5 | * 6 | * @license Apache-2.0 7 | * @module 8 | */ 9 | import GLib from "gi://GLib"; 10 | 11 | export function queueMicrotask(fn: () => void) { 12 | GLib.timeout_add(GLib.PRIORITY_LOW, 0, () => { 13 | fn(); 14 | return false; 15 | }); 16 | } 17 | -------------------------------------------------------------------------------- /typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://typedoc.org/schema.json", 3 | "entryPoints": [ 4 | "src/index.ts", 5 | "src/jsx-runtime.ts", 6 | "src/widget.tsx", 7 | "src/gtk4/", 8 | "src/fetch.ts", 9 | "src/store.ts", 10 | "src/web-ponyfill.ts", 11 | "src/storage.ts" 12 | ], 13 | "out": "./docs-dist", 14 | "includeVersion": true, 15 | "visibilityFilters": { 16 | "protected": false, 17 | "private": false, 18 | "inherited": true, 19 | "external": true 20 | }, 21 | "highlightLanguages": [ 22 | "js", 23 | "ts", 24 | "jsx", 25 | "tsx", 26 | "c" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /docs/typescript.md: -------------------------------------------------------------------------------- 1 | # GSolid and TypeScript 2 | 3 | You can use GSolid with TypeScript (.ts/.tsx). There is the recommended configuration: 4 | 5 | This configuration uses packages `@girs/gjs` and `@girs/gtk-4.0`. 6 | 7 | ```json5 8 | { 9 | compilerOptions: { 10 | types: ["@girs/gjs", "@girs/gjs/dom", "@girs/gtk-4.0"], // GI type decralations 11 | isolatedModules: true, 12 | esModuleInterop: true, 13 | jsx: "preserve", 14 | jsxImportSource: "gsolid", 15 | lib: [ 16 | "ES2015", 17 | "ES2016", 18 | "ES2017", 19 | "ES2018", 20 | "ES2019", 21 | "ES2020", 22 | "ES2021", 23 | "ES2022", 24 | "ESNext", 25 | ] 26 | }, 27 | } 28 | ``` 29 | 30 | It's also recommended to use the components in `gsolid/gtk4`. 31 | -------------------------------------------------------------------------------- /src/gobject.ts: -------------------------------------------------------------------------------- 1 | import GObject from "gi://GObject?version=2.0"; 2 | import { onCleanup } from "./index.js"; 3 | 4 | export function registeredGClass< 5 | T extends typeof GObject.Object, 6 | Props extends { [key: string]: GObject.ParamSpec }, 7 | Interfaces extends { $gtype: GObject.GType }[], 8 | Sigs extends { 9 | [key: string]: { 10 | param_types?: readonly GObject.GType[]; 11 | [key: string]: any; 12 | }; 13 | } 14 | >(metadata: GObject.MetaInfo) { 15 | return (originalClass: T) => { 16 | return /* @__PURE__ */ GObject.registerClass(metadata, originalClass); 17 | }; 18 | } 19 | 20 | export interface Disconnectable { 21 | disconnect(id: number): void 22 | } 23 | 24 | /** 25 | * Disconnect signals on cleanning up. 26 | * @param signals 27 | */ 28 | export function disconnectOnCleanup(signals: [Disconnectable, number][]) { 29 | onCleanup(() => { 30 | for (const [object, id] of signals) { 31 | object.disconnect(id) 32 | } 33 | }) 34 | return (object: Disconnectable, id: number) => { 35 | signals.push([object, id]) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /docs/build-app.md: -------------------------------------------------------------------------------- 1 | # Notes to build Applications 2 | 3 | This document is for the bundler developers and describes some requirements to correctly bundle gsolid application. 4 | 5 | You can also check out the [esbuild-plugin-gsolid](https://github.com/thislight/esbuild-plugin-gsolid). 6 | 7 | ## Translate JSX files using [babel-preset-solid](https://github.com/solidjs/solid/tree/main/packages/babel-preset-solid) 8 | 9 | Sample babel config: 10 | 11 | ```js 12 | presets: [ 13 | [ 14 | "babel-preset-solid", 15 | { 16 | moduleName: "gsolid/jsx-runtime", 17 | generate: "universal", 18 | }, 19 | ], 20 | ], 21 | ``` 22 | 23 | The preset does not support TSX files, so they must be translated to JSXs before feeding babel-preset-solid. 24 | 25 | ## Inject `gsolid/web-ponyfill` 26 | 27 | `gsolid/web-ponyfill` is a ESM ponyfill. Every export must be imported in `solid-js`'s files. For example, such content will be injected into the start of the every files: 28 | 29 | ````js 30 | import {queueMicrotask} from "gsolid/web-ponyfill" 31 | ```` 32 | 33 | Since the `solid-js` does not have dependency to `gsolid`, the bundler must resolve the `gsolid/web-ponyfill` to a nearest package. 34 | 35 | Currently, copying the file content into the files works. The file SHOULD be no side effect. 36 | 37 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "src/index.ts", 4 | "src/jsx-runtime.ts", 5 | "src/widget.tsx", 6 | "src/fetch.ts", 7 | "src/web-ponyfill.ts", 8 | "src/reactive.ts", 9 | "src/store.ts", 10 | "src/storage.ts", 11 | "src/gobject.ts" 12 | ], 13 | "include": ["src/gtk4/*.tsx", "src/gtk4/*.ts"], 14 | "exclude": ["node_modules/"], 15 | "compilerOptions": { 16 | "emitDeclarationOnly": true, 17 | "declaration": true, 18 | "target": "esnext", 19 | "newLine": "LF", 20 | "module": "ES2022", 21 | "moduleResolution": "Bundler", 22 | "strict": true, 23 | "jsx": "preserve", 24 | "outDir": "types", 25 | "isolatedModules": true, 26 | "experimentalDecorators": true, 27 | "skipLibCheck": true, 28 | "lib": [ 29 | "ES2015", 30 | "ES2016", 31 | "ES2017", 32 | "ES2018", 33 | "ES2019", 34 | "ES2020", 35 | "ES2021", 36 | "ES2022", 37 | "ESNext", 38 | "DOM", // This type lib is required to build, part of solid-js includes links to dom.d.ts 39 | ], 40 | "types": [ 41 | "@girs/gjs", 42 | "@girs/gtk-4.0", 43 | "@girs/soup-3.0", 44 | "@girs/girepository-2.0", 45 | ], 46 | "jsxImportSource": "gsolid", 47 | "esModuleInterop": true, 48 | "rootDir": "./src" 49 | }, 50 | } 51 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GSolid 2 | 3 | Simple and performant reactivity for building user interfaces, with GTK 4. GSolid is a universal GTK renderer for [solid-js](https://www.solidjs.com). 4 | 5 | - Performant: Working with native `Gtk.Widget` without heavy middleware. No Tick, No Late. 6 | - Powerful: Composable reactive primitives plus the flexibility of JSX. 7 | - Productive: Ergonomics and familiarity that make building simple or complex frontends a breeze. 8 | 9 | GSolid supports [Gjs](https://gitlab.gnome.org/GNOME/gjs/). 10 | 11 | Launch your project in seconds with [gsolid-app-starter](https://github.com/thislight/gsolid-app-starter)! 12 | 13 | ```jsx 14 | import Gtk from "gi://Gtk?version=4.0"; 15 | import { createSignal } from "gsolid"; 16 | import { Box, Button, Label, ReactiveWindow, createApp } from "gsolid/gtk4"; 17 | 18 | createApp((app) => { 19 | const [counter, setCounter] = createSignal(0); 20 | app.add_window( 21 | false} 24 | title="Hello World!" 25 | defaultWidth={300} 26 | defaultHeight={250} 27 | > 28 | 29 |