From ede8890a08b3fbbb1f6df3b8c277ab6424d1befd Mon Sep 17 00:00:00 2001 From: Aylur Date: Tue, 15 Oct 2024 01:22:24 +0000 Subject: docs: better explain ags --- docs/guide/typescript/binding.md | 235 +++++++++++++++++++ docs/guide/typescript/cli-app.md | 174 ++++++++++++++ docs/guide/typescript/faq.md | 266 +++++++++++++++++++++ docs/guide/typescript/first-widgets.md | 412 +++++++++++++++++++++++++++++++++ docs/guide/typescript/gobject.md | 165 +++++++++++++ docs/guide/typescript/installation.md | 89 +++++++ docs/guide/typescript/theming.md | 179 ++++++++++++++ docs/guide/typescript/utilities.md | 168 ++++++++++++++ docs/guide/typescript/variable.md | 153 ++++++++++++ docs/guide/typescript/widget.md | 214 +++++++++++++++++ 10 files changed, 2055 insertions(+) create mode 100644 docs/guide/typescript/binding.md create mode 100644 docs/guide/typescript/cli-app.md create mode 100644 docs/guide/typescript/faq.md create mode 100644 docs/guide/typescript/first-widgets.md create mode 100644 docs/guide/typescript/gobject.md create mode 100644 docs/guide/typescript/installation.md create mode 100644 docs/guide/typescript/theming.md create mode 100644 docs/guide/typescript/utilities.md create mode 100644 docs/guide/typescript/variable.md create mode 100644 docs/guide/typescript/widget.md (limited to 'docs/guide/typescript') diff --git a/docs/guide/typescript/binding.md b/docs/guide/typescript/binding.md new file mode 100644 index 0000000..05645ab --- /dev/null +++ b/docs/guide/typescript/binding.md @@ -0,0 +1,235 @@ +# Binding + +As mentioned before binding an object's state to another - +so in most cases a `Variable` or a `GObject.Object` property to a widget's property - +is done through the `bind` function which returns a `Binding` object. + +`Binding` objects simply hold information about the source and how it should be transformed +which Widget constructors can use to setup a connection between themselves and the source. + +```ts +class Binding { + private transformFn: (v: any) => unknown + private emitter: Subscribable | Connectable + private prop?: string + + as(fn: (v: Value) => T): Binding + get(): Value + subscribe(callback: (value: Value) => void): () => void +} +``` + +A `Binding` can be constructed from an object implementing +the `Subscribable` interface (usually a `Variable`) +or an object implementing the `Connectable` interface and one of its properties +(usually a `GObject.Object` instance). + +```ts +function bind(obj: Subscribable): Binding + +function bind< + Obj extends Connectable, + Prop extends keyof Obj, +>(obj: Obj, prop: Prop): Binding +``` + +## Subscribable and Connectable interface + +Any object implementing one of these interfaces can be used with `bind`. + +```ts +interface Subscribable { + subscribe(callback: (value: T) => void): () => void + get(): T +} + +interface Connectable { + connect(signal: string, callback: (...args: any[]) => unknown): number + disconnect(id: number): void +} +``` + +## Example Custom Subscribable + +When binding the children of a box from an array, usually not all elements +of the array changes each time, so it would make sense to not destroy +the widget which represents the element. + +::: code-group + +```ts :line-numbers [varmap.ts] +import { type Subscribable } from "astal/binding" +import { Gtk } from "astal" + +export class VarMap implements Subscribable { + #subs = new Set<(v: Array<[K, T]>) => void>() + #map: Map + + #notifiy() { + const value = this.get() + for (const sub of this.#subs) { + sub(value) + } + } + + #delete(key: K) { + const v = this.#map.get(key) + + if (v instanceof Gtk.Widget) { + v.destroy() + } + + this.#map.delete(key) + } + + constructor(initial?: Iterable<[K, T]>) { + this.#map = new Map(initial) + } + + set(key: K, value: T) { + this.#delete(key) + this.#map.set(key, value) + this.#notifiy() + } + + delete(key: K) { + this.#delete(key) + this.#notifiy() + } + + get() { + return [...this.#map.entries()] + } + + subscribe(callback: (v: Array<[K, T]>) => void) { + this.#subs.add(callback) + return () => this.#subs.delete(callback) + } +} +``` + +::: + +And this `VarMap` can be used as an alternative to `Variable>`. + +```tsx +function MappedBox() { + const map = new VarMap([ + [1, ] + [2, ] + ]) + + const conns = [ + gobject.connect("added", (_, id) => map.set(id, MyWidget({ id }))), + gobject.connect("removed", (_, id) => map.delete(id, MyWidget({ id }))), + ] + + return conns.map(id => gobject.disconnect(id))}> + {bind(map).as(arr => arr.sort(([a], [b]) => a - b).map(([,w]) => w))} + +} +``` + +## Example Custom Connectable + +Astal provides [decorator functions](./gobject#example-usage) +that make it easy to subclass gobjects, however +you can read more about GObjects and subclassing +on [gjs.guide](https://gjs.guide/guides/gobject/subclassing.html#gobject-subclassing). + +Objects coming from [libraries](../libraries/references#astal-libraries) +usually have a singleton gobject you can access with `.get_default()`. + +Here is an example of a Brightness library by wrapping the `brightnessctl` cli utility +and by monitoring `/sys/class/backlight` + +::: code-group + +```ts :line-numbers [brightness.ts] +import GObject, { register, property } from "astal/gobject" +import { monitorFile, readFileAsync } from "astal/file" +import { exec, execAsync } from "astal/process" + +const get = (args: string) => Number(exec(`brightnessctl ${args}`)) +const screen = exec(`bash -c "ls -w1 /sys/class/backlight | head -1"`) +const kbd = exec(`bash -c "ls -w1 /sys/class/leds | head -1"`) + +@register({ GTypeName: "Brightness" }) +export default class Brightness extends GObject.Object { + static instance: Brightness + static get_default() { + if (!this.instance) + this.instance = new Brightness() + + return this.instance + } + + #kbdMax = get(`--device ${kbd} max`) + #kbd = get(`--device ${kbd} get`) + #screenMax = get("max") + #screen = get("get") / (get("max") || 1) + + @property(Number) + get kbd() { return this.#kbd } + + set kbd(value) { + if (value < 0 || value > this.#kbdMax) + return + + execAsync(`brightnessctl -d ${kbd} s ${value} -q`).then(() => { + this.#kbd = value + this.notify("kbd") + }) + } + + @property(Number) + get screen() { return this.#screen } + + set screen(percent) { + if (percent < 0) + percent = 0 + + if (percent > 1) + percent = 1 + + execAsync(`brightnessctl set ${Math.floor(percent * 100)}% -q`).then(() => { + this.#screen = percent + this.notify("screen") + }) + } + + constructor() { + super() + + const screenPath = `/sys/class/backlight/${screen}/brightness` + const kbdPath = `/sys/class/leds/${kbd}/brightness` + + monitorFile(screenPath, async f => { + const v = await readFileAsync(f) + this.#screen = Number(v) / this.#screenMax + this.notify("screen") + }) + + monitorFile(kbdPath, async f => { + const v = await readFileAsync(f) + this.#kbd = Number(v) / this.#kbdMax + this.notify("kbd") + }) + } +} +``` + +::: + +And it can be used like any other library object. + +```tsx +function BrightnessSlider() { + const brightness = Brightness.get_default() + + return brightness.screen = value} + /> +} +``` diff --git a/docs/guide/typescript/cli-app.md b/docs/guide/typescript/cli-app.md new file mode 100644 index 0000000..3407e06 --- /dev/null +++ b/docs/guide/typescript/cli-app.md @@ -0,0 +1,174 @@ +# CLI and App + +`App` is a singleton **instance** of an [Astal.Application](https://aylur.github.io/libastal/class.Application.html). + +Depending on gtk version import paths will differ + +```ts +import { App } from "astal/gtk3" + +import { App } from "astal/gtk4" +``` + +## Entry point + +:::code-group + +```ts [app.ts] +App.start({ + main() { + // setup anything + // instantiate widgets + }, +}) +``` + +::: + +## Instance identifier + +You can run multiple instance by defining a unique instance name. + +```ts +App.start({ + instanceName: "my-instance", // defaults to "astal" + main() { }, +}) +``` + +## Messaging from CLI + +If you want to interact with an instance from the CLI, +you can do so by sending a message. + +```ts +App.start({ + requestHandler(request: string, res: (response: any) => void) { + if (request == "say hi") { + res("hi cli") + } + res("unknown command") + }, + main() { }, +}) +``` + +:::code-group + +```sh [astal] +astal say hi +# hi cli +``` + +```sh [ags] +ags -m "say hi" +# hi cli +``` + +::: + +If you want to run arbitrary JavaScript from CLI, you can use `App.eval` +which will evaluate the passed string as the body of an `async` function. + +```ts +App.start({ + main() {}, + requestHandler(js, res) { + App.eval(js).then(res).catch(res) + }, +}) +``` + +If the string does not contain a semicolon, a single expression is assumed and returned implicity. + +```sh +astal "'hello'" +# hello +``` + +If the string contains a semicolon, you have to return explicitly + +```sh +astal "'hello';" +# undefined + +astal "return 'hello';" +# hello +``` + +## Toggling Windows by their name + +In order for Astal to know about your windows, you have to register them. +You can do this by specifying a **unique** `name` and calling `App.add_window` + +```tsx {4} +import { App } from "astal" + +function Bar() { + return App.add_window(self)}> + + +} +``` + +You can also invoke `App.add_window` by simply passing the `App` to the `application` prop. + +```tsx {4} +import { App } from "astal" + +function Bar() { + return + + +} +``` + +:::warning +When assigning the `application` prop make sure `name` comes before. +Props are set sequentially and if name is applied after application it won't work. +::: + +:::code-group + +```sh [astal] +astal -t Bar +``` + +```sh [ags] +ags -t Bar +``` + +::: + +## Bundled scripts + +The produced scripts when bundling can run as the main instance +and a "client" instance. + +The first time you execute your bundled script the `main` function gets called. +While that instance is running any subsequent execution of the script will call +the `client` function. + +:::code-group + +```ts [main.ts] +App.start({ + // main instance + main(...args: Array) { + print(...args) + }, + + // every subsequent calls + client(message: (msg: string) => string, ...args: Array) { + const res = message("you can message the main instance") + console.log(res) + }, + + // this runs in the main instance + requestHandler(request: string, res: (response: any) => void) { + res("response from main") + }, +}) +``` + +::: diff --git a/docs/guide/typescript/faq.md b/docs/guide/typescript/faq.md new file mode 100644 index 0000000..76d8e72 --- /dev/null +++ b/docs/guide/typescript/faq.md @@ -0,0 +1,266 @@ +# Frequently asked question, common issues, tips and tricks + +## Monitor id does not match compositor + +The monitor id property that windows expect is mapped by Gdk, which is not always +the same as the compositor. Instead use the `gdkmonitor` property which expects +a `Gdk.Monitor` object. + +```tsx +import { App } from "astal" + +function Bar(gdkmonitor) { + return +} + +function main() { + for (const monitor of App.get_monitors()) { + if (monitor.model == "your-desired-model") { + Bar(monitor) + } + } +} + +App.start({ main }) +``` + +## Environment variables + +JavaScript is **not** an bash. + +```ts +const HOME = exec("echo $HOME") // does not work +``` + +`exec` and `execAsync` runs the passed program as is, its **not** run in a +shell environment, so the above example just passes `$HOME` as a string literal +to the `echo` program. + +:::danger Please don't do this +You could pass it to bash, but that is a horrible approach. + +```ts +const HOME = exec("bash -c 'echo $HOME'") +``` + +::: + +You can read environment variables with [GLib.getenv](https://gjs-docs.gnome.org/glib20~2.0/glib.getenv). + +```ts +import GLib from "gi://GLib" + +const HOME = GLib.getenv("HOME") +``` + +## Custom SVG symbolic icons + +Put the svgs in a directory, named `-symbolic.svg` +and use `App.add_icons` or `icons` parameter in `App.start` + +:::code-group + +```ts [app.ts] +App.start({ + icons: `${SRC}/icons`, + main() { + Widget.Icon({ + icon: "custom-symbolic", // custom-symbolic.svg + css: "color: green;", // can be colored, like other named icons + }) + }, +}) +``` + +::: + +:::info +If there is a name clash with an icon from your current icon pack +the icon pack will take precedence +::: + +## Logging + +The `console` API in gjs uses glib logging functions. +If you just want to print some text as is to stdout +use the globally available `print` function or `printerr` for stderr. + +```ts +print("print this line to stdout") +printerr("print this line to stderr") +``` + +## Populate the global scope with frequently accessed variables + +It might be annoying to always import Gtk only for `Gtk.Align` enums. + +:::code-group + +```ts [globals.ts] +import Gtk from "gi://Gtk" + +declare global { + const START: number + const CENTER: number + const END: number + const FILL: number +} + +Object.assign(globalThis, { + START: Gtk.Align.START, + CENTER: Gtk.Align.CENTER, + END: Gtk.Align.END, + FILL: Gtk.Align.FILL, +}) +``` + +::: + +:::code-group + +```tsx [Bar.tsx] +export default function Bar() { + return + + +} +``` + +::: + +:::code-group + +```ts [app.ts] +import "./globals" +import Bar from "./Bar" + +App.start({ + main: Bar +}) +``` + +::: + +:::info +It is considered bad practice to populate the global scope, but its your code, not a public library. +::: + +## Auto create Window for each Monitor + +To have Window widgets appear on a monitor when its plugged in, listen to `App.monitor_added`. + +:::code-group + +```tsx [Bar.tsx] +export default function Bar(gdkmonitor: Gdk.Monitor) { + return +} +``` + +::: + +:::code-group + +```ts [app.ts] +import { Gdk, Gtk } from "astal" +import Bar from "./Bar" + +function main() { + const bars = new Map() + + // initialize + for (const gdkmonitor of App.get_monitors()) { + bars.set(gdkmonitor, Bar(gdkmonitor)) + } + + App.connect("monitor-added", (_, gdkmonitor) => { + bars.set(gdkmonitor, Bar(gdkmonitor)) + }) + + App.connect("monitor-removed", (_, gdkmonitor) => { + bars.get(gdkmonitor)?.destroy() + bars.delete(gdkmonitor) + }) +} + +App.start({ main }) +``` + +::: + +## Error: Can't convert non-null pointer to JS value + +These happen when accessing list type properties. Gjs fails to correctly bind +`List` and other array like types of Vala as a property. + +```ts +import Notifd from "gi://AstalNotifd" +const notifd = Notifd.get_default() + +notifd.notifications // ❌ // [!code error] + +notifd.get_notifications() // βœ… +``` + +## How to create regular floating windows + +Use `Gtk.Window` with [Widget.astalify](/guide/ags/widget#how-to-use-non-builtin-gtk-widgets). + +By default `Gtk.Window` is destroyed on close. To prevent this add a handler for `delete-event`. + +```tsx {4-7} +const RegularWindow = Widget.astalify(Gtk.Window) + +return { + self.hide() + return true + }} +> + {child} + +``` + +## Is there a way to limit the width/height of a widget? + +Unfortunately not. You can set a minimum size with `min-width` and `min-heigth` css attributes, +but you can not set max size. + +## Custom widgets with bindable properties + +In function components you can wrap any primitive to handle both +binding and value cases as one. + +```tsx +function MyWidget(props: { prop: string | Binding }) { + const prop = props.prop instanceof Binding + ? props.prop + : bind({ get: () => props.prop, subscribe: () => () => {} }) + + function setup(self: Widget.Box) { + self.hook(prop, () => { + const value = prop.get() + // handler + }) + } + + return + +} +``` + +You can pass the prop the super constructor in subclasses + +```tsx +@register() +class MyWidget extends Widget.Box { + @property(String) + set prop(v: string) { + // handler + } + + constructor(props: { prop: string | Binding }) { + super(props) + } +} +``` diff --git a/docs/guide/typescript/first-widgets.md b/docs/guide/typescript/first-widgets.md new file mode 100644 index 0000000..3664bfa --- /dev/null +++ b/docs/guide/typescript/first-widgets.md @@ -0,0 +1,412 @@ +# First Widgets + +## Getting Started + +Start by initializing a project + +```sh +ags --init +``` + +then run `ags` in the terminal + +```sh +ags +``` + +:::details Usage without AGS +🚧 Not yet documented. 🚧 +::: + +That's it! You have now a custom written bar using Gtk. + +:::tip +AGS will transpile every `.ts`, `.jsx` and `.tsx` files into regular JavaScript, then +it will bundle everything into a single JavaScript file which then GJS can execute. +::: + +The AGS init command will generate the following files + +```txt +. +β”œβ”€β”€ @girs/ # generated types +β”œβ”€β”€ widget/ +β”‚ └── Bar.tsx +β”œβ”€β”€ app.ts # entry proint +β”œβ”€β”€ env.d.ts # additional types +β”œβ”€β”€ style.css +└── tsconfig.json # needed by LSPs +``` + +## Root of every shell component: Window + +Astal apps are composed of widgets. A widget is a piece of UI that has its own logic and style. +A widget can be as small as a button or an entire bar. +The top level widget is always a [Window](https://aylur.github.io/libastal/class.Window.html) which will hold all widgets. + +::: code-group + +```tsx [widget/Bar.tsx] +function Bar(monitor = 0) { + return + Content of the widget + +} +``` + +::: + +::: code-group + +```ts [app.ts] +import Bar from "./widget/Bar" + +App.start({ + main() { + Bar(0) + Bar(1) // instantiate for each monitor + }, +}) +``` + +::: + +## Creating and nesting widgets + +Widgets are JavaScript functions which return Gtk widgets, +either by using JSX or using a widget constructor. + +:::code-group + +```tsx [MyButton.tsx] +function MyButton(): JSX.Element { + return +} +``` + +```ts [MyButton.ts] +import { Widget } from "astal/gtk3" + +function MyButton(): Widget.Button { + return new Widget.Button( + { onClicked: "echo hello" }, + new Widget.Label({ label: "Click me!" }), + ) +} +``` + +::: + +:::info +The only difference between the two is the return type. +Using markup the return type is always `Gtk.Widget` (globally available as `JSX.Element`), +while using constructors the return type is the actual type of the widget. +It is rare to need the actual return type, so most if not all of the time, you can use markup. +::: + +Now that you have declared `MyButton`, you can nest it into another component. + +```tsx +function MyBar() { + return + + Click The button + + + +} +``` + +Notice that widgets you defined start with a capital letter ``. +Lowercase tags are builtin widgets, while capital letter is for custom widgets. + +## Displaying Data + +JSX lets you put markup into JavaScript. +Curly braces let you β€œescape back” into JavaScript so that you can embed some variable +from your code and display it. + +```tsx +function MyWidget() { + const label = "hello" + + return +} +``` + +You can also pass JavaScript to markup attributes + +```tsx +function MyWidget() { + const label = "hello" + + return +} +``` + +### Builtin Widgets + +You can check the [source code](https://github.com/aylur/astal/blob/main/lang/gjs/src/gtk3/index.ts) to have a full list of builtin widgets. + +These widgets are available by default in JSX. + +- box: [Astal.Box](https://aylur.github.io/libastal/class.Box.html) +- button: [Astal.Button](https://aylur.github.io/libastal/class.Button.html) +- centerbox: [Astal.CenterBox](https://aylur.github.io/libastal/class.CenterBox.html) +- circularprogress: [Astal.CircularProgress](https://aylur.github.io/libastal/class.CircularProgress.html) +- drawingarea: [Gtk.DrawingArea](https://docs.gtk.org/gtk3/class.DrawingArea.html) +- entry: [Gtk.Entry](https://docs.gtk.org/gtk3/class.Entry.html) +- eventbox: [Astal.EventBox](https://aylur.github.io/libastal/class.EventBox.html) +- icon: [Astal.Icon](https://aylur.github.io/libastal/class.Icon.html) +- label: [Astal.Label](https://aylur.github.io/libastal/class.Label.html) +- levelbar: [Astal.LevelBar](https://aylur.github.io/libastal/class.LevelBar.html) +- overlay: [Astal.Overlay](https://aylur.github.io/libastal/class.Overlay.html) +- revealer: [Gtk.Revealer](https://docs.gtk.org/gtk3/class.Revealer.html) +- scrollable: [Astal.Scrollable](https://aylur.github.io/libastal/class.Scrollable.html) +- slider: [Astal.Slider](https://aylur.github.io/libastal/class.Slider.html) +- stack: [Astal.Stack](https://aylur.github.io/libastal/class.Stack.html) +- switch: [Gtk.Switch](https://docs.gtk.org/gtk3/class.Switch.html) +- window: [Astal.Window](https://aylur.github.io/libastal/class.Window.html) + +## Gtk4 + +🚧 Work in Progress 🚧 -- cgit v1.2.3 From fe11c037bad45697451b7264ff93fa37f1fac78f Mon Sep 17 00:00:00 2001 From: Aylur Date: Tue, 15 Oct 2024 11:55:53 +0000 Subject: docs: recommend /usr prefix by default --- docs/guide/typescript/installation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'docs/guide/typescript') diff --git a/docs/guide/typescript/installation.md b/docs/guide/typescript/installation.md index 4c31b6e..f085194 100644 --- a/docs/guide/typescript/installation.md +++ b/docs/guide/typescript/installation.md @@ -9,7 +9,7 @@ It lets you - generate a tsconfig which is used by LSPs - bundle your TypeScript and JavaScript code using [esbuild](https://esbuild.github.io/). -::: details Trivia +:::details Trivia AGS is the predecessor of Astal, which was written purely in TypeScript and so only supported JavaScript/TypeScript. Now it serves as a scaffolding tool for Astal+TypeScript+JSX projects. ::: @@ -43,7 +43,7 @@ meson install -C build :::tip You might be wondering why it is recommended to install a JavaScript package on the system instead of installing it as a node module. -It is solely to keep it in **sync** with the core `astal-sh` and `astal3`/`astal4` package. +It is solely to keep it in **sync** with the core `astal-io` and `astal3`/`astal4` package. ::: 3. Install the following dependencies -- cgit v1.2.3 From b33c3bf91dbbea13b1a2c8603e00809b22cd42c8 Mon Sep 17 00:00:00 2001 From: Aylur Date: Tue, 15 Oct 2024 13:36:16 +0000 Subject: docs: fix links --- docs/guide/typescript/cli-app.md | 2 +- docs/guide/typescript/faq.md | 2 +- docs/guide/typescript/first-widgets.md | 4 ++-- docs/guide/typescript/utilities.md | 4 ++-- docs/guide/typescript/variable.md | 4 ++-- docs/guide/typescript/widget.md | 34 +++++++++++++++++----------------- 6 files changed, 25 insertions(+), 25 deletions(-) (limited to 'docs/guide/typescript') diff --git a/docs/guide/typescript/cli-app.md b/docs/guide/typescript/cli-app.md index 3407e06..f409176 100644 --- a/docs/guide/typescript/cli-app.md +++ b/docs/guide/typescript/cli-app.md @@ -1,6 +1,6 @@ # CLI and App -`App` is a singleton **instance** of an [Astal.Application](https://aylur.github.io/libastal/class.Application.html). +`App` is a singleton **instance** of an [Astal.Application](https://aylur.github.io/libastal/astal3/class.Application.html). Depending on gtk version import paths will differ diff --git a/docs/guide/typescript/faq.md b/docs/guide/typescript/faq.md index 76d8e72..48c802c 100644 --- a/docs/guide/typescript/faq.md +++ b/docs/guide/typescript/faq.md @@ -204,7 +204,7 @@ notifd.get_notifications() // βœ… ## How to create regular floating windows -Use `Gtk.Window` with [Widget.astalify](/guide/ags/widget#how-to-use-non-builtin-gtk-widgets). +Use `Gtk.Window` with [Widget.astalify](/guide/typescript/widget#how-to-use-non-builtin-gtk-widgets). By default `Gtk.Window` is destroyed on close. To prevent this add a handler for `delete-event`. diff --git a/docs/guide/typescript/first-widgets.md b/docs/guide/typescript/first-widgets.md index 3664bfa..a7372a8 100644 --- a/docs/guide/typescript/first-widgets.md +++ b/docs/guide/typescript/first-widgets.md @@ -42,7 +42,7 @@ The AGS init command will generate the following files Astal apps are composed of widgets. A widget is a piece of UI that has its own logic and style. A widget can be as small as a button or an entire bar. -The top level widget is always a [Window](https://aylur.github.io/libastal/class.Window.html) which will hold all widgets. +The top level widget is always a [Window](https://aylur.github.io/libastal/astal3/class.Window.html) which will hold all widgets. ::: code-group @@ -363,7 +363,7 @@ by setting `noImplicityDestroy` property on the container widget. :::info The above example destroys and recreates every widget in the list **every time** the value of the `Variable` changes. There might be cases where you would -want to [handle child creation and deletion](/guide/ags/faq#avoiding-unnecessary-re-rendering) +want to [handle child creation and deletion](/guide/typescript/faq#avoiding-unnecessary-re-rendering) yourself, because you don't want to lose the inner state of widgets that does not need to be recreated. In this case you can create a [custom reactive structure](./binding#example-custom-subscribable) diff --git a/docs/guide/typescript/utilities.md b/docs/guide/typescript/utilities.md index 9bc56b2..f808044 100644 --- a/docs/guide/typescript/utilities.md +++ b/docs/guide/typescript/utilities.md @@ -44,7 +44,7 @@ import { interval, timeout, idle } from "astal" You can use javascript native `setTimeout` or `setInterval` they return a [GLib.Source](https://docs.gtk.org/glib/struct.Source.html) instance. Alternatively you can use these functions provided by Astal, -which return an [Astal.Time](https://aylur.github.io/libastal/class.Time.html) instance. +which return an [Astal.Time](https://aylur.github.io/libastal/io/class.Time.html) instance. `Astal.Time` has a `now` signal and a `cancelled` signal. @@ -99,7 +99,7 @@ import { subprocess, exec, execAsync } from "astal" ### Subprocess You can start a subprocess and run callback functions whenever it outputs to -stdout or stderr. [Astal.Process](https://aylur.github.io/libastal/class.Process.html) has a `stdout` and `stderr` signal. +stdout or stderr. [Astal.Process](https://aylur.github.io/libastal/io/class.Process.html) has a `stdout` and `stderr` signal. ```ts function subprocess(args: { diff --git a/docs/guide/typescript/variable.md b/docs/guide/typescript/variable.md index 4207f61..2abacbd 100644 --- a/docs/guide/typescript/variable.md +++ b/docs/guide/typescript/variable.md @@ -8,7 +8,7 @@ Variable is just a simple object which holds a single value. It also has some shortcuts for hooking up subprocesses, intervals and other gobjects. :::info -The `Variable` object imported from the `"astal"` package is **not** [Astal.Variable](https://aylur.github.io/libastal/class.Variable.html). +The `Variable` object imported from the `"astal"` package is **not** [Astal.Variable](https://aylur.github.io/libastal/io/class.Variable.html). ::: ## Example Usage @@ -75,7 +75,7 @@ output. They can poll and watch at the same time, but they can only poll/watch once. :::warning -The command parameter is passed to [execAsync](/guide/ags/utilities#executing-external-commands-and-scripts) +The command parameter is passed to [execAsync](/guide/typescript/utilities#executing-external-commands-and-scripts) which means they are **not** executed in a shell environment, they do **not** expand ENV variables like `$HOME`, and they do **not** handle logical operators like `&&` and `||`. diff --git a/docs/guide/typescript/widget.md b/docs/guide/typescript/widget.md index 03ba9ea..d16d194 100644 --- a/docs/guide/typescript/widget.md +++ b/docs/guide/typescript/widget.md @@ -191,23 +191,23 @@ You can check the [source code](https://github.com/aylur/astal/blob/main/lang/gj These widgets are available by default in JSX. -- box: [Astal.Box](https://aylur.github.io/libastal/class.Box.html) -- button: [Astal.Button](https://aylur.github.io/libastal/class.Button.html) -- centerbox: [Astal.CenterBox](https://aylur.github.io/libastal/class.CenterBox.html) -- circularprogress: [Astal.CircularProgress](https://aylur.github.io/libastal/class.CircularProgress.html) -- drawingarea: [Gtk.DrawingArea](https://docs.gtk.org/gtk3/class.DrawingArea.html) -- entry: [Gtk.Entry](https://docs.gtk.org/gtk3/class.Entry.html) -- eventbox: [Astal.EventBox](https://aylur.github.io/libastal/class.EventBox.html) -- icon: [Astal.Icon](https://aylur.github.io/libastal/class.Icon.html) -- label: [Astal.Label](https://aylur.github.io/libastal/class.Label.html) -- levelbar: [Astal.LevelBar](https://aylur.github.io/libastal/class.LevelBar.html) -- overlay: [Astal.Overlay](https://aylur.github.io/libastal/class.Overlay.html) -- revealer: [Gtk.Revealer](https://docs.gtk.org/gtk3/class.Revealer.html) -- scrollable: [Astal.Scrollable](https://aylur.github.io/libastal/class.Scrollable.html) -- slider: [Astal.Slider](https://aylur.github.io/libastal/class.Slider.html) -- stack: [Astal.Stack](https://aylur.github.io/libastal/class.Stack.html) -- switch: [Gtk.Switch](https://docs.gtk.org/gtk3/class.Switch.html) -- window: [Astal.Window](https://aylur.github.io/libastal/class.Window.html) +- box: [Astal.Box](https://aylur.github.io/libastal/astal3/class.Box.html) +- button: [Astal.Button](https://aylur.github.io/libastal/astal3/class.Button.html) +- centerbox: [Astal.CenterBox](https://aylur.github.io/libastal/astal3/class.CenterBox.html) +- circularprogress: [Astal.CircularProgress](https://aylur.github.io/libastal/astal3/class.CircularProgress.html) +- drawingarea: [Gtk.DrawingArea](https://docs.gtk.org/gtk3/astal3/class.DrawingArea.html) +- entry: [Gtk.Entry](https://docs.gtk.org/gtk3/astal3/class.Entry.html) +- eventbox: [Astal.EventBox](https://aylur.github.io/libastal/astal3/class.EventBox.html) +- icon: [Astal.Icon](https://aylur.github.io/libastal/astal3/class.Icon.html) +- label: [Astal.Label](https://aylur.github.io/libastal/astal3/class.Label.html) +- levelbar: [Astal.LevelBar](https://aylur.github.io/libastal/astal3/class.LevelBar.html) +- overlay: [Astal.Overlay](https://aylur.github.io/libastal/astal3/class.Overlay.html) +- revealer: [Gtk.Revealer](https://docs.gtk.org/gtk3/astal3/class.Revealer.html) +- scrollable: [Astal.Scrollable](https://aylur.github.io/libastal/astal3/class.Scrollable.html) +- slider: [Astal.Slider](https://aylur.github.io/libastal/astal3/class.Slider.html) +- stack: [Astal.Stack](https://aylur.github.io/libastal/astal3/class.Stack.html) +- switch: [Gtk.Switch](https://docs.gtk.org/gtk3/astal3/class.Switch.html) +- window: [Astal.Window](https://aylur.github.io/libastal/astal3/class.Window.html) ## Gtk4 -- cgit v1.2.3