@gjsify/gtk-host 0.44.0 → 0.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -4
- package/lib/esm/adapters/solid.js +1 -1
- package/lib/esm/conformance/diagnostics.js +1 -1
- package/lib/esm/conformance/index.js +2 -2
- package/lib/esm/descriptors/adw.js +1 -1
- package/lib/esm/descriptors/gtk.js +1 -1
- package/lib/esm/errors.js +1 -1
- package/lib/esm/generated/widgets.js +1 -1
- package/lib/esm/host.js +1 -1
- package/lib/esm/index.js +1 -1
- package/lib/esm/list/controller.js +1 -0
- package/lib/esm/list/index.js +1 -0
- package/lib/esm/list/scroll.js +1 -0
- package/lib/esm/policies.js +1 -1
- package/lib/esm/probe.js +1 -1
- package/lib/esm/props.js +1 -1
- package/lib/esm/registry.js +1 -1
- package/lib/esm/signals.js +1 -1
- package/lib/esm/style/document.js +1 -0
- package/lib/esm/style/gtk-props.js +1 -1
- package/lib/esm/style/index.js +1 -1
- package/lib/esm/style/layout.js +1 -1
- package/lib/esm/style/paint.js +1 -1
- package/lib/esm/style/sheet.js +3 -3
- package/lib/esm/style/theme.js +3 -0
- package/lib/esm/style/tokens.js +1 -1
- package/lib/types/adapters/solid.d.ts +35 -0
- package/lib/types/conformance/diagnostics.d.ts +1 -1
- package/lib/types/descriptors/index.d.ts +3 -3
- package/lib/types/errors.d.ts +10 -0
- package/lib/types/generated/props.d.ts +684 -816
- package/lib/types/generated/widgets.d.ts +1 -1
- package/lib/types/generator/emit-types.d.mts +2 -2
- package/lib/types/generator/emit.d.mts +16 -6
- package/lib/types/generator/girs-vocabulary.d.mts +45 -0
- package/lib/types/generator/main.d.mts +16 -8
- package/lib/types/generator/model.d.mts +95 -0
- package/lib/types/generator/names.d.mts +19 -0
- package/lib/types/generator/vocabulary-dts.d.mts +47 -0
- package/lib/types/host.d.ts +3 -3
- package/lib/types/index.d.ts +1 -1
- package/lib/types/list/controller.d.ts +112 -0
- package/lib/types/list/index.d.ts +2 -0
- package/lib/types/list/list.spec.d.ts +2 -0
- package/lib/types/list/scroll.d.ts +26 -0
- package/lib/types/policies.d.ts +18 -1
- package/lib/types/probe.d.ts +49 -0
- package/lib/types/probe.spec.d.ts +2 -0
- package/lib/types/props.d.ts +13 -1
- package/lib/types/registry.d.ts +1 -1
- package/lib/types/signals.d.ts +3 -1
- package/lib/types/style/document.d.ts +22 -0
- package/lib/types/style/index.d.ts +6 -3
- package/lib/types/style/layout.d.ts +34 -0
- package/lib/types/style/sheet.d.ts +0 -5
- package/lib/types/style/theme.d.ts +158 -0
- package/lib/types/style/theme.spec.d.ts +2 -0
- package/lib/types/style/tokens.d.ts +76 -0
- package/lib/types/style/tokens.spec.d.ts +2 -0
- package/lib/types/types.d.ts +84 -4
- package/package.json +22 -16
- package/lib/types/generator/gir.d.mts +0 -164
- package/lib/types/generator/mini.fixture.d.mts +0 -30
- package/lib/types/generator/surface.d.mts +0 -62
- package/lib/types/generator/tsmap.d.mts +0 -73
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Emit the TYPE surfaces: one interface per GIR declaration,
|
|
2
|
+
* Emit the TYPE surfaces: one interface per GIR declaration, four tag maps.
|
|
3
3
|
*
|
|
4
4
|
* WHAT THE DIALECTS FORCED, all of it measured rather than assumed (ADR 0028 § 7,
|
|
5
5
|
* and the numbers live there):
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* arrives as `unknown` so using it fails (TS2345). A generated surface that
|
|
24
24
|
* typed handlers loosely would break every handler that names its parameter.
|
|
25
25
|
*/
|
|
26
|
-
import type { SurfaceModel } from './
|
|
26
|
+
import type { SurfaceModel } from './model.mjs';
|
|
27
27
|
/**
|
|
28
28
|
* Volar's own resolution rule, reproduced so the generator can SEE the gap.
|
|
29
29
|
*
|
|
@@ -17,8 +17,7 @@
|
|
|
17
17
|
* answer. The machine-INDEPENDENT check is the runtime one that already exists —
|
|
18
18
|
* `descriptorProblems()` against the installed typelib.
|
|
19
19
|
*/
|
|
20
|
-
import type {
|
|
21
|
-
import type { GirClass, GirNamespace } from './gir.mjs';
|
|
20
|
+
import type { WidgetDescriptor } from '../types.js';
|
|
22
21
|
/**
|
|
23
22
|
* The `gi://` import a generated table needs, per GIR namespace.
|
|
24
23
|
*
|
|
@@ -29,12 +28,23 @@ import type { GirClass, GirNamespace } from './gir.mjs';
|
|
|
29
28
|
* trust.
|
|
30
29
|
*/
|
|
31
30
|
export declare const GJS_MODULES: Readonly<Record<string, string>>;
|
|
31
|
+
/** What a widget row needs. Three fields, not a GIR class — see `girs-vocabulary.mts`. */
|
|
32
|
+
export interface WidgetRow {
|
|
33
|
+
readonly gtype: string;
|
|
34
|
+
readonly namespace: string;
|
|
35
|
+
readonly name: string;
|
|
36
|
+
}
|
|
32
37
|
export interface EmitInput {
|
|
33
|
-
|
|
34
|
-
readonly
|
|
38
|
+
/** The provenance line, verbatim: `Gtk-4.0/4.23.3 Adw-1/1.8.0`. */
|
|
39
|
+
readonly provenance: string;
|
|
40
|
+
readonly widgets: readonly WidgetRow[];
|
|
41
|
+
/**
|
|
42
|
+
* Every GType the vocabulary knows, widgets and bases alike. G1 asks whether a curated
|
|
43
|
+
* row names something that exists, and a widget-only set would report every curated
|
|
44
|
+
* base as missing.
|
|
45
|
+
*/
|
|
46
|
+
readonly knownGTypes: ReadonlySet<string>;
|
|
35
47
|
readonly curated: readonly WidgetDescriptor[];
|
|
36
|
-
/** `methodsOf` from the conformance module — one extractor, not a second copy. */
|
|
37
|
-
readonly methodsOf: (policy: ChildPolicy) => string[];
|
|
38
48
|
/** GIR namespace -> `gi://` import. Defaults to the GTK/Adwaita pair. */
|
|
39
49
|
readonly modules?: Readonly<Record<string, string>>;
|
|
40
50
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read the widget vocabulary from `@girs/<ns>/vocabulary` and build the emitter's model.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS REPLACED A GIR READER. This package used to parse the `.gir` XML itself, which
|
|
5
|
+
* made it the SECOND reader of a format ts-for-gir already reads — and two readers of one
|
|
6
|
+
* format are two truths that drift apart silently. ADR 0029 moved the vocabulary into
|
|
7
|
+
* `@girs/*` so there is one. What stays here is the DIALECT: kebab tags, the camelCase
|
|
8
|
+
* second spelling, `on<Signal>` prop names, Vue's Volar aliases. None of that is in the
|
|
9
|
+
* vocabulary and none of it belongs there, as its own header says.
|
|
10
|
+
*
|
|
11
|
+
* WHY IT READS BOTH HALVES. The runtime `.js` carries the facts as values (`OWN_PROPS`,
|
|
12
|
+
* `DECLS`, `OWN_SIGNALS`, `ENUM_NICKS`), which is what a check can compare against a live
|
|
13
|
+
* typelib. The `.d.ts` carries the rendered TypeScript for each property, which no amount
|
|
14
|
+
* of runtime data can reconstruct: `GtkBaselinePositionNick | Gtk.BaselinePosition`
|
|
15
|
+
* depends on that file's own imports. So the types come from the declarations and the
|
|
16
|
+
* facts come from the values, and neither is re-derived from the other.
|
|
17
|
+
*
|
|
18
|
+
* The `.d.ts` half is READ in `vocabulary-dts.mts`, which touches no file and so
|
|
19
|
+
* imports no `gi://` — that is what lets `generator.spec.ts` pin its regexes against
|
|
20
|
+
* literal fixtures instead of against whichever `@girs` happens to be installed.
|
|
21
|
+
*/
|
|
22
|
+
import type { SurfaceModel } from './model.mjs';
|
|
23
|
+
/** The three fields `emit-types.mts` reads off a widget. Not a GIR class any more. */
|
|
24
|
+
export interface WidgetRef {
|
|
25
|
+
readonly gtype: string;
|
|
26
|
+
readonly namespace: string;
|
|
27
|
+
readonly name: string;
|
|
28
|
+
}
|
|
29
|
+
export interface VocabularySource {
|
|
30
|
+
/** Import name, e.g. `gtk-4.0`. */
|
|
31
|
+
readonly pkg: string;
|
|
32
|
+
/** GType prefix, e.g. `Gtk`. */
|
|
33
|
+
readonly prefix: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Load the vocabulary packages and build the model the emitters already consume.
|
|
37
|
+
*
|
|
38
|
+
* `dir` is the `node_modules/@girs` root; the caller resolves it, because a generator
|
|
39
|
+
* should not guess where its own dependencies live.
|
|
40
|
+
*/
|
|
41
|
+
export declare function buildFromVocabulary(dir: string, sources: readonly VocabularySource[]): Promise<{
|
|
42
|
+
model: SurfaceModel;
|
|
43
|
+
widgets: WidgetRef[];
|
|
44
|
+
provenance: string;
|
|
45
|
+
}>;
|
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The generator CLI.
|
|
3
3
|
*
|
|
4
|
-
* gjsify run generate -- [--
|
|
4
|
+
* gjsify run generate -- [--girs-dir DIR] [--out DIR]
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* this repository
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
6
|
+
* WHERE THE VOCABULARY COMES FROM. The input used to be GIR XML: distro artefacts
|
|
7
|
+
* that are not in this repository, 6.2 MB for `Gtk-4.0.gir` alone, with four GTK
|
|
8
|
+
* versions on the maintainer workstation and no way to know which one a build saw.
|
|
9
|
+
* It is now the `@girs/<ns>/vocabulary` subpath (ADR 0029), which is an ordinary
|
|
10
|
+
* dependency, resolved like any other. That closes the provenance question the old
|
|
11
|
+
* route could only answer by convention: each vocabulary states the namespace,
|
|
12
|
+
* version and library version it was generated from, and this generator copies that
|
|
13
|
+
* into the artefact header instead of naming the files it happened to read.
|
|
14
|
+
*
|
|
15
|
+
* `--girs-dir` stays an argument so a locally built `@girs` can be generated against
|
|
16
|
+
* before it is published. Without it the directory is found by walking up from the
|
|
17
|
+
* working directory, which is what makes `npm run generate` work from the package.
|
|
18
|
+
*
|
|
19
|
+
* The ARTEFACT remains committed (ADR 0028 § Implementation): a fresh clone builds,
|
|
20
|
+
* checks, packs and tests without regenerating anything.
|
|
13
21
|
*
|
|
14
22
|
* THERE IS NO `--check` MODE, and the attempt to add one is worth recording: the
|
|
15
23
|
* `generate` script pipes the output through `gjsify format`, which reflows it
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The declaration graph the type surfaces are emitted from — the shape only.
|
|
3
|
+
*
|
|
4
|
+
* ONE INTERFACE PER DECLARATION, carrying its OWN members and extending its bases —
|
|
5
|
+
* not one flat interface per widget. The measurement decides it: the concrete widgets
|
|
6
|
+
* have thousands of writable property slots between them and a few hundred distinct
|
|
7
|
+
* property names. Flattening would emit the same `visible?: boolean` once per widget;
|
|
8
|
+
* mirroring the inheritance the vocabulary reports emits it once, on `GtkWidgetProps`,
|
|
9
|
+
* and the diff of a GTK update then shows what actually changed.
|
|
10
|
+
*
|
|
11
|
+
* WHO FILLS IT. `girs-vocabulary.mts`, from `@girs/<ns>/vocabulary`. This module used
|
|
12
|
+
* to hold a `buildSurface()` that filled the same shape from GIR XML this package
|
|
13
|
+
* parsed itself; ADR 0029 moved the vocabulary into `@girs/*` so there is one reader
|
|
14
|
+
* of that format instead of two. Only the shape survived, which is why the file is
|
|
15
|
+
* `model.mts` and no longer `surface.mts`: `surface` now names the `@girs` subpath.
|
|
16
|
+
*/
|
|
17
|
+
import type { WidgetRow } from './emit.mjs';
|
|
18
|
+
export interface PropMember {
|
|
19
|
+
readonly kebab: string;
|
|
20
|
+
readonly camel: string;
|
|
21
|
+
readonly ts: string;
|
|
22
|
+
/**
|
|
23
|
+
* The hover blurb, from the JSDoc above the property in the vocabulary's `.d.ts`.
|
|
24
|
+
*
|
|
25
|
+
* The typelib strips documentation by design — which is why gi-docgen reads the
|
|
26
|
+
* GIR — and hover text is what a published type surface is FOR (ADR 0028 § 6). So
|
|
27
|
+
* the doc travels with the rendered type, out of the half of the vocabulary that
|
|
28
|
+
* can carry it; the runtime half is values, and a value cannot hold a comment.
|
|
29
|
+
*/
|
|
30
|
+
readonly doc?: string;
|
|
31
|
+
readonly deprecated: boolean;
|
|
32
|
+
readonly since?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface SignalMember {
|
|
35
|
+
readonly signal: string;
|
|
36
|
+
readonly prop: string;
|
|
37
|
+
/** Already rendered — `Gtk.ListBox.SignalSignatures['row-activated']`. */
|
|
38
|
+
readonly ts: string;
|
|
39
|
+
readonly doc?: string;
|
|
40
|
+
readonly deprecated: boolean;
|
|
41
|
+
readonly since?: string;
|
|
42
|
+
}
|
|
43
|
+
export interface Declaration {
|
|
44
|
+
/** Namespace-qualified — `Gtk.Box`. The graph is keyed on this, the way GIR references. */
|
|
45
|
+
readonly key: string;
|
|
46
|
+
readonly gtype: string;
|
|
47
|
+
readonly kind: 'class' | 'interface';
|
|
48
|
+
/** `GtkBoxProps`. */
|
|
49
|
+
readonly iface: string;
|
|
50
|
+
readonly bases: readonly string[];
|
|
51
|
+
readonly props: readonly PropMember[];
|
|
52
|
+
readonly signals: readonly SignalMember[];
|
|
53
|
+
readonly doc?: string;
|
|
54
|
+
/**
|
|
55
|
+
* The library release this TYPE arrived in, where GIR states one.
|
|
56
|
+
*
|
|
57
|
+
* Distinct from a member's `since`: it answers "does the installed library have
|
|
58
|
+
* this class at all", which is the question a bare `ctor()` returning `undefined`
|
|
59
|
+
* used to ask by crashing. Only about 11% of GIR classes carry a `version`, so an
|
|
60
|
+
* absent value means "not stated", never "has always existed".
|
|
61
|
+
*/
|
|
62
|
+
readonly since?: string;
|
|
63
|
+
}
|
|
64
|
+
export interface SurfaceModel {
|
|
65
|
+
/**
|
|
66
|
+
* The widget rows, sorted by GType name.
|
|
67
|
+
*
|
|
68
|
+
* The same three fields the table emitter takes, so the type comes from there
|
|
69
|
+
* rather than being restated — a second spelling of a row is a second thing to
|
|
70
|
+
* keep in step with `girs-vocabulary.mts`, which fills both.
|
|
71
|
+
*/
|
|
72
|
+
readonly widgets: readonly WidgetRow[];
|
|
73
|
+
readonly declarations: ReadonlyMap<string, Declaration>;
|
|
74
|
+
/** Widget GType -> the GTypes of every declaration its members come from, self first. */
|
|
75
|
+
readonly closure: ReadonlyMap<string, readonly string[]>;
|
|
76
|
+
/** Enum GType -> nicks, for the emitted aliases and for the runtime nick check. */
|
|
77
|
+
readonly enumNicks: ReadonlyMap<string, readonly string[]>;
|
|
78
|
+
readonly namespacesUsed: ReadonlySet<string>;
|
|
79
|
+
/** Namespace -> the `@girs` package that types it, so the emitter needs no second source. */
|
|
80
|
+
readonly packages: Readonly<Record<string, string>>;
|
|
81
|
+
/**
|
|
82
|
+
* Base -> members it must not contribute, because a nearer declaration disagrees.
|
|
83
|
+
*
|
|
84
|
+
* EMPTY TODAY, AND NOT DEFENSIVE MACHINERY. TypeScript requires a multiply
|
|
85
|
+
* inherited member to be IDENTICAL in every base — `string` and `string | null`
|
|
86
|
+
* are not — and GTK's interfaces do redeclare class properties, so a base that
|
|
87
|
+
* loses a member has to be emitted as `Omit<Base, 'name'>`: a local redeclaration
|
|
88
|
+
* does NOT repair incompatible bases, it turns one error into another. The GIR
|
|
89
|
+
* route computed those conflicts here; the published vocabulary resolves them
|
|
90
|
+
* upstream, so the map now arrives empty. It stays because `emit-types.mts`
|
|
91
|
+
* renders `Omit<>` from it, and a vocabulary that reintroduces a conflict needs a
|
|
92
|
+
* way to say so — the alternative is a surface that does not compile.
|
|
93
|
+
*/
|
|
94
|
+
readonly omissions: ReadonlyMap<string, ReadonlyMap<string, readonly string[]>>;
|
|
95
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two name transforms this package's DIALECT owns.
|
|
3
|
+
*
|
|
4
|
+
* Everything else that used to live here — the GIR-type-to-TypeScript mapper, the
|
|
5
|
+
* enum-nick unions, the `@girs` package map — moved into `@girs/<ns>/vocabulary`
|
|
6
|
+
* with ADR 0029, which renders each property's type in its own `.d.ts` and ships
|
|
7
|
+
* the nicks as data. What no vocabulary can answer is how a FRAMEWORK spells a
|
|
8
|
+
* member, because every framework spells it differently; that is dialect, it stays
|
|
9
|
+
* here, and it is why this file is `names.mts` and no longer `tsmap.mts`.
|
|
10
|
+
*
|
|
11
|
+
* Both are also read by `generated.spec.ts`, which runs them against the host's own
|
|
12
|
+
* inverse (`toSignalName`) over every generated name. Two independent
|
|
13
|
+
* implementations checked against each other is the point: nothing made them agree,
|
|
14
|
+
* and the first run of that check found that they did not.
|
|
15
|
+
*/
|
|
16
|
+
/** `row-activated` -> `onRowActivated`; `notify` handled by the caller. */
|
|
17
|
+
export declare const eventPropOf: (signal: string) => string;
|
|
18
|
+
/** `can-focus` -> `canFocus`. The inverse of the host's `toPropertyName`. */
|
|
19
|
+
export declare const camelOf: (kebab: string) => string;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** One member, as the `.d.ts` renders it: the TS text plus whatever JSDoc sits above. */
|
|
2
|
+
export interface DeclaredProp {
|
|
3
|
+
readonly ts: string;
|
|
4
|
+
readonly doc?: string;
|
|
5
|
+
readonly since?: string;
|
|
6
|
+
readonly deprecated: boolean;
|
|
7
|
+
}
|
|
8
|
+
/** One `export interface <GType>Props` — its own JSDoc, and its own members. */
|
|
9
|
+
export interface DeclaredInterface {
|
|
10
|
+
readonly doc?: string;
|
|
11
|
+
readonly props: Map<string, DeclaredProp>;
|
|
12
|
+
}
|
|
13
|
+
interface DocBlock {
|
|
14
|
+
readonly doc?: string;
|
|
15
|
+
readonly since?: string;
|
|
16
|
+
readonly deprecated: boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The JSDoc block directly above a declaration, or nothing.
|
|
20
|
+
*
|
|
21
|
+
* ADJACENCY IS THE WHOLE RULE. `text` is everything preceding the declaration, so the
|
|
22
|
+
* nearest block above it may belong to a sibling several members up. Requiring
|
|
23
|
+
* whitespace only between that block's terminator and the declaration is what
|
|
24
|
+
* separates "this member is documented" from "some earlier member was".
|
|
25
|
+
*/
|
|
26
|
+
export declare function readDocBlock(text: string): DocBlock;
|
|
27
|
+
/**
|
|
28
|
+
* Read the namespace imports a vocabulary declares: `import type Gdk from
|
|
29
|
+
* '@girs/gdk-4.0'`.
|
|
30
|
+
*
|
|
31
|
+
* These are the only honest answer to "which namespaces do the rendered types reach
|
|
32
|
+
* into". Deriving it from the source list instead emitted `Gdk.RGBA` with no Gdk
|
|
33
|
+
* import — TS2503, in a file nobody edits by hand.
|
|
34
|
+
*/
|
|
35
|
+
export declare function readNamespaceImports(text: string, ownPkg: string): Map<string, string>;
|
|
36
|
+
/**
|
|
37
|
+
* The interfaces a vocabulary `.d.ts` declares, with each property's rendered type.
|
|
38
|
+
*
|
|
39
|
+
* Brace-matched rather than terminated on a closing brace at column 0: an interface
|
|
40
|
+
* body can contain a nested object type, and a reader that stops at the first one
|
|
41
|
+
* silently truncates it. That exact shortcut is already recorded as a defect in two
|
|
42
|
+
* sibling scripts.
|
|
43
|
+
*/
|
|
44
|
+
export declare function readDeclaredInterfaces(text: string): Map<string, DeclaredInterface>;
|
|
45
|
+
/** Property lines plus the JSDoc block immediately above each one. */
|
|
46
|
+
export declare function readProps(body: string): Map<string, DeclaredProp>;
|
|
47
|
+
export {};
|
package/lib/types/host.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import GObject from 'gi://GObject';
|
|
1
|
+
import GObject from 'gi://GObject?version=2.0';
|
|
2
2
|
import type Gtk from '@girs/gtk-4.0';
|
|
3
3
|
import type { HostAnchor, HostElement, HostNode, HostText, WidgetDescriptor } from './types.js';
|
|
4
4
|
export declare function createElement(tag: string, props?: Record<string, unknown>): HostElement;
|
|
@@ -107,7 +107,7 @@ export declare function destroy(node: HostNode): void;
|
|
|
107
107
|
* `GObject.registerClass` subclass inherits its ancestor's policy. Guessing a
|
|
108
108
|
* method name here would be the generic `add` that GTK4 deliberately removed.
|
|
109
109
|
*/
|
|
110
|
-
export declare function mountRoot(el: HostElement, container:
|
|
110
|
+
export declare function mountRoot(el: HostElement, container: GObject.Object): void;
|
|
111
111
|
/**
|
|
112
112
|
* The materialised widget of a host node — for a `ref`, or for a test.
|
|
113
113
|
*
|
|
@@ -149,7 +149,7 @@ export declare const createDetachedContainer: () => HostElement;
|
|
|
149
149
|
* through `nearestRegistered`, so an application's own `GObject.registerClass`
|
|
150
150
|
* subclass inherits its ancestor's placement rules instead of failing.
|
|
151
151
|
*/
|
|
152
|
-
export declare function adopt(container:
|
|
152
|
+
export declare function adopt(container: GObject.Object): HostElement;
|
|
153
153
|
export declare const parentNode: (node: HostNode) => HostElement | null;
|
|
154
154
|
export declare const firstChild: (el: HostElement) => HostNode | null;
|
|
155
155
|
export declare const nextSibling: (node: HostNode) => HostNode | null;
|
package/lib/types/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { addressOf, reorderMode } from './policies.js';
|
|
|
5
5
|
export { toSignalName, isEventProp } from './signals.js';
|
|
6
6
|
export { constructOnlyNames, isConstructOnly, isWritable, lookupEnumNick, paramSpecs, toPropertyName, } from './props.js';
|
|
7
7
|
export { assertInjective, tagOf } from './tags.js';
|
|
8
|
-
export { probeEnabled, runHostProbe, runHostProbeApp, type HostProbe, type HostProbeApp, type ProbeCheck, } from './probe.js';
|
|
8
|
+
export { blankReason, checkRendered, probeEnabled, runHostProbe, runHostProbeApp, shotEvidence, type CaptureWidget, type HostProbe, type HostProbeApp, type ProbeCheck, type ShotEvidence, } from './probe.js';
|
|
9
9
|
export type { ElementChild, ElementChildren, JsxAttributes, RawSignalAttributes, SlotAttribute, VueAttributes, WithOnce, } from './attrs.js';
|
|
10
10
|
export { clearRegistry, hasWidget, lookupWidget, nearestRegistered, registerWidget, registerWidgets, registeredTags, } from './registry.js';
|
|
11
11
|
export { ADW_DESCRIPTORS, BUILTIN_DESCRIPTORS, CURATED_DESCRIPTORS, GENERATED_PROVENANCE, GENERATED_WIDGETS, GTK_DESCRIPTORS, mergeGenerated, registerBuiltinWidgets, tableProvenance, } from './descriptors/index.js';
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import Gtk from 'gi://Gtk?version=4.0';
|
|
2
|
+
/**
|
|
3
|
+
* A row's identity, and the only thing this layer reads off a row.
|
|
4
|
+
*
|
|
5
|
+
* `key` decides whether the model has to be rebuilt at all. Everything else a dialect
|
|
6
|
+
* wants to carry — a render function, a component, a plain record — rides along in the
|
|
7
|
+
* type parameter and is handed straight back to `showRow`.
|
|
8
|
+
*/
|
|
9
|
+
export interface ListRowKey {
|
|
10
|
+
readonly key: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The dialect's half of a list — three callbacks, one per factory phase that needs one.
|
|
14
|
+
*
|
|
15
|
+
* `Handle` is whatever the dialect needs to keep per ROW WIDGET: a React root, a Solid
|
|
16
|
+
* disposer plus a setter, a Vue app instance. The controller stores it, hands it back,
|
|
17
|
+
* and never looks inside it.
|
|
18
|
+
*/
|
|
19
|
+
export interface ListRowSink<Row extends ListRowKey, Handle> {
|
|
20
|
+
/**
|
|
21
|
+
* GTK made a row widget's carrier; put something in it and keep what you need.
|
|
22
|
+
*
|
|
23
|
+
* Called from `setup`, ONCE per row widget, and that is not a convenience: `adopt`'s
|
|
24
|
+
* `foreign` snapshot cannot tell the host's own previous child from application
|
|
25
|
+
* chrome, so taking the carrier a SECOND time reads our own row as someone else's
|
|
26
|
+
* and refuses with `occupied-slot`. `host.spec.ts` pins that refusal.
|
|
27
|
+
*
|
|
28
|
+
* TWO routes reach it, and the nearer one is not the obvious one. GTK reusing a
|
|
29
|
+
* carrier across `bind`/`unbind` is the route people expect, and it needs scrolling
|
|
30
|
+
* or recycling to happen at all. The route that fires FIRST is `setRows` over
|
|
31
|
+
* unchanged keys: it shows every live row again through the same handle, with no
|
|
32
|
+
* GTK involvement, so a dialect that adopts per show meets the refusal on its first
|
|
33
|
+
* content change — measured, and it is what `list.spec.ts`'s in-place vector
|
|
34
|
+
* exercises. Adopt here, keep the element in the handle.
|
|
35
|
+
*/
|
|
36
|
+
mountRow(item: Gtk.ListItem): Handle;
|
|
37
|
+
/**
|
|
38
|
+
* Show `row` in the widget behind `handle`, or empty it when `row` is `null`.
|
|
39
|
+
*
|
|
40
|
+
* Called from `bind`, from `unbind` with `null`, and again for every live row when
|
|
41
|
+
* `setRows` sees unchanged keys over changed content — which GTK does not re-bind
|
|
42
|
+
* for us (the splice measurement in the header says why).
|
|
43
|
+
*/
|
|
44
|
+
showRow(handle: Handle, row: Row | null, index: number): void;
|
|
45
|
+
/** GTK is done with this row widget, or the controller is. Let go of everything. */
|
|
46
|
+
disposeRow(handle: Handle): void;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* WHERE A SINK'S OWN THROW GOES, because there are TWO paths and they differ.
|
|
50
|
+
*
|
|
51
|
+
* `setRows` over unchanged keys calls `showRow` DIRECTLY — no GTK in between — so a
|
|
52
|
+
* throw there propagates out of `setRows` to whoever called it, and a dialect can catch
|
|
53
|
+
* it. Every other call (`setup`, `bind`, `unbind`, `teardown`) runs inside a GObject
|
|
54
|
+
* signal callback, where GJS does not let an exception cross the C frame: it is swallowed
|
|
55
|
+
* and logged as `Gjs-CRITICAL … JS ERROR`, the emission continues, and the controller
|
|
56
|
+
* carries on with a row that never rendered. A diagnostics gate sees that; nothing else
|
|
57
|
+
* does.
|
|
58
|
+
*
|
|
59
|
+
* The asymmetry is not fixable from here — it is GJS's signal boundary — so it is
|
|
60
|
+
* DECLARED instead, and it decides where a sink should put its own error handling. It
|
|
61
|
+
* bites unevenly: React Native's sink only fills a Map on this path and cannot really
|
|
62
|
+
* throw, while Solid's `show()` runs the row's reactive updates synchronously inside
|
|
63
|
+
* `batch()`, so an error in application code lands here.
|
|
64
|
+
*
|
|
65
|
+
* Note what is NOT the answer: `@gjsify/react-native`'s `onRowError` is React's own root
|
|
66
|
+
* error channel, not this seam's. A sink that needs one owns it, because only the
|
|
67
|
+
* dialect knows what a row's error means — a controller-level hook would have to decide
|
|
68
|
+
* whether to keep binding, and neither answer is right for every renderer.
|
|
69
|
+
*/
|
|
70
|
+
/**
|
|
71
|
+
* A `Gtk.ListView`'s model, factory and per-row handles.
|
|
72
|
+
*
|
|
73
|
+
* Constructed by a dialect with its `ListRowSink`, attached to a view someone else
|
|
74
|
+
* created, disposed from that someone's own cleanup. Nothing here is reactive:
|
|
75
|
+
* `setRows` is called with the current rows and works out whether GTK has to hear
|
|
76
|
+
* about it.
|
|
77
|
+
*/
|
|
78
|
+
export declare class ListController<Row extends ListRowKey, Handle> {
|
|
79
|
+
#private;
|
|
80
|
+
constructor(sink: ListRowSink<Row, Handle>);
|
|
81
|
+
/**
|
|
82
|
+
* Give the view its model and factory.
|
|
83
|
+
*
|
|
84
|
+
* `Gtk.NoSelection` and not the store directly: `Gtk.ListView:model` is a
|
|
85
|
+
* `Gtk.SelectionModel`, and a plain `Gio.ListModel` is not one. `NoSelection` is the
|
|
86
|
+
* wrapper that says "no selection", and it is what this controller installs because
|
|
87
|
+
* a `Gtk.SingleSelection` would give rows a selected state nothing here would ever
|
|
88
|
+
* clear. Selection is a dialect-level feature nobody has asked for yet; adding it
|
|
89
|
+
* means widening `attach`, not reaching around it.
|
|
90
|
+
*/
|
|
91
|
+
attach(view: Gtk.ListView): void;
|
|
92
|
+
/**
|
|
93
|
+
* The rows GTK should be showing.
|
|
94
|
+
*
|
|
95
|
+
* The model is only touched when the KEYS changed. When they did not, every row's
|
|
96
|
+
* subtree is shown again instead — a row whose key is the same but whose data
|
|
97
|
+
* changed has to repaint, and the splice measurement says GTK will not re-bind it
|
|
98
|
+
* for us. That is strictly cheaper than a splice, which tears down every row.
|
|
99
|
+
*/
|
|
100
|
+
setRows(rows: readonly Row[]): void;
|
|
101
|
+
/** How many rows GTK is currently holding a widget for. A spec seam and a leak detector. */
|
|
102
|
+
get liveRows(): number;
|
|
103
|
+
/**
|
|
104
|
+
* Release every row, disconnect every handler, and let go of the view.
|
|
105
|
+
*
|
|
106
|
+
* Called from the owner's cleanup, which runs while JS callbacks still work —
|
|
107
|
+
* unlike GTK's own `teardown`, which fires during GC sweeping when the view is
|
|
108
|
+
* collected and is BLOCKED there (measured, see the header). Idempotent, because an
|
|
109
|
+
* owner's cleanup and an explicit dispose both reach it.
|
|
110
|
+
*/
|
|
111
|
+
dispose(): void;
|
|
112
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type Gtk from '@girs/gtk-4.0';
|
|
2
|
+
/**
|
|
3
|
+
* Call `listener` when the scroller gets within `threshold` page-lengths of the end.
|
|
4
|
+
*
|
|
5
|
+
* `Gtk.Adjustment`, because that is where GTK keeps a scroll position: the scrolled
|
|
6
|
+
* window has no scroll signal of its own, and `notify::value` on the adjustment behind
|
|
7
|
+
* `hadjustment`/`vadjustment` is the only place the position is observable. MEASURED: a
|
|
8
|
+
* `Gtk.ScrolledWindow` hands out its adjustments with no window anywhere, and
|
|
9
|
+
* `set_value` on one raised `notify::value` — so this is drivable, and asserted, in a
|
|
10
|
+
* spec that presents nothing.
|
|
11
|
+
*
|
|
12
|
+
* `upper` and `page-size` are subscribed too, and not for completeness: `upper` grows
|
|
13
|
+
* when rows are added, which is the event that ARMS the next call — a list that grew has
|
|
14
|
+
* a new end.
|
|
15
|
+
*
|
|
16
|
+
* A list with nothing to scroll (`upper <= page-size`) never fires. That is the state
|
|
17
|
+
* every list is in before it has been allocated, and firing there would call the
|
|
18
|
+
* listener on mount for every list in the application.
|
|
19
|
+
*
|
|
20
|
+
* ONCE PER ARRIVAL, and this is the one policy here that came from a framework: it is
|
|
21
|
+
* React Native's `onEndReached` semantics. It is the core's behaviour anyway because
|
|
22
|
+
* every "load more" caller wants it — firing on every frame while the user rests at the
|
|
23
|
+
* bottom would issue a page request per frame. A dialect that wants the raw stream has
|
|
24
|
+
* the adjustment and can subscribe to it directly; this function is the debounced edge.
|
|
25
|
+
*/
|
|
26
|
+
export declare function onScrollNearEnd(scroller: Gtk.ScrolledWindow, axis: 'horizontal' | 'vertical', threshold: number, listener: (distanceFromEnd: number) => void): () => void;
|
package/lib/types/policies.d.ts
CHANGED
|
@@ -9,8 +9,14 @@ export declare function addressOf(el: HostElement): Gtk.Widget;
|
|
|
9
9
|
* is the spelling anyone reaching for `activatable` or `selectable` uses, and
|
|
10
10
|
* wrapping a row inside a second row nests two selectable widgets and detaches
|
|
11
11
|
* activation from the one the author configured.
|
|
12
|
+
*
|
|
13
|
+
* A `slotted` policy reaches this too, per SLOT: an adder that hands the child to an
|
|
14
|
+
* inner `Gtk.ListBox` needs exactly the same wrap, and `Adw.ExpanderRow`'s `add_row` is
|
|
15
|
+
* one. The measurement behind that is on `ChildPolicy`'s `wrapSlots`; the short version
|
|
16
|
+
* is that `gtk_list_box_remove` does not unwrap, so without this the child leaks behind
|
|
17
|
+
* one `Gtk-WARNING` at unmount.
|
|
12
18
|
*/
|
|
13
|
-
export declare function makeWrapper(policy: ChildPolicy, child: Gtk.Widget): Gtk.Widget | null;
|
|
19
|
+
export declare function makeWrapper(policy: ChildPolicy, child: Gtk.Widget, slot: string | null): Gtk.Widget | null;
|
|
14
20
|
/**
|
|
15
21
|
* A container the host owns that no window shows — the DOM's detached `<div>`.
|
|
16
22
|
*
|
|
@@ -52,6 +58,17 @@ export declare const makeDetachedContainer: () => Gtk.Widget;
|
|
|
52
58
|
*/
|
|
53
59
|
export declare function unhandledPolicy(policy: never): never;
|
|
54
60
|
export declare function setterSlotOf(parent: HostElement, child: HostElement): string | null;
|
|
61
|
+
/**
|
|
62
|
+
* The slots this policy fills with an ADDER, by slot name.
|
|
63
|
+
*
|
|
64
|
+
* `set_`-prefixed or not is the whole distinction, and TWO decisions turn on it,
|
|
65
|
+
* which is why the predicate is here once rather than spelled out at each. A
|
|
66
|
+
* setter-backed slot is emptied by writing `null` back through itself, so
|
|
67
|
+
* `policyProblems()` lets such a policy name no `remove`; and it holds one child,
|
|
68
|
+
* so `rotateTail` returns before touching it — a policy with no adder slot at all
|
|
69
|
+
* has no order to pay for, which is what `reorderMode()` reports.
|
|
70
|
+
*/
|
|
71
|
+
export declare function adderSlots(policy: ChildPolicy): string[];
|
|
55
72
|
/** Every one-child slot this policy has, by setter name — `single` has exactly one. */
|
|
56
73
|
export declare function setterSlots(policy: ChildPolicy): string[];
|
|
57
74
|
/**
|
package/lib/types/probe.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Adw from 'gi://Adw?version=1';
|
|
2
|
+
import Gtk from 'gi://Gtk?version=4.0';
|
|
2
3
|
/** Record one assertion. A `false` is a finding; nothing else is. */
|
|
3
4
|
export type ProbeCheck = (what: string, ok: boolean) => void;
|
|
4
5
|
/** What a showcase gives the harness. */
|
|
@@ -85,3 +86,51 @@ export declare function runHostProbe<T>(probe: HostProbe<T>): Promise<number>;
|
|
|
85
86
|
* and hangs a view load on its spinner (the class `@gjsify/adwaita-app` documents).
|
|
86
87
|
*/
|
|
87
88
|
export declare function runHostProbeApp<T>(probe: HostProbeApp<T>): Promise<void>;
|
|
89
|
+
/**
|
|
90
|
+
* Rasterise one widget. `@gjsify/devtools`' `captureWidgetPng` has this shape;
|
|
91
|
+
* `null` means the widget has no renderer or no size yet, never "the image is empty".
|
|
92
|
+
*/
|
|
93
|
+
export type CaptureWidget = (widget: Gtk.Widget) => Uint8Array | null;
|
|
94
|
+
/** What a picture of a subtree is worth, in numbers a `check` can read. */
|
|
95
|
+
export interface ShotEvidence {
|
|
96
|
+
/**
|
|
97
|
+
* STRICT descendants of the container in the REAL GTK tree.
|
|
98
|
+
*
|
|
99
|
+
* The decisive number, and the cheapest. `0` is not "a small tree": it is a
|
|
100
|
+
* container nothing was rendered into, which is what a refused render, an
|
|
101
|
+
* unmounted root and a component that returned `null` all look like from here.
|
|
102
|
+
*/
|
|
103
|
+
widgets: number;
|
|
104
|
+
width: number;
|
|
105
|
+
height: number;
|
|
106
|
+
/** PNG byte count, `0` when `capture` produced none. */
|
|
107
|
+
bytes: number;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Count what a shot of `container` would be a picture OF.
|
|
111
|
+
*
|
|
112
|
+
* Reads the real GTK tree (`get_first_child`/`get_next_sibling`) rather than any
|
|
113
|
+
* host bookkeeping — the shadow tree would agree with itself here, which is the
|
|
114
|
+
* whole reason `conformance/` exists.
|
|
115
|
+
*/
|
|
116
|
+
export declare function shotEvidence(container: Gtk.Widget, capture: CaptureWidget): ShotEvidence;
|
|
117
|
+
/**
|
|
118
|
+
* Why a shot of this evidence would be blank — or `null` when it would not.
|
|
119
|
+
*
|
|
120
|
+
* Ordered by what a reader can act on. "Nothing was rendered" and "the renderer had
|
|
121
|
+
* no surface yet" are different bugs with the same photograph, and a message that
|
|
122
|
+
* cannot tell them apart sends the reader back to guessing — the state
|
|
123
|
+
* `describeLogRecord` exists to end one layer down.
|
|
124
|
+
*
|
|
125
|
+
* A NON-EMPTY PNG IS NOT PROOF, which is why byte count is the LAST question rather
|
|
126
|
+
* than the only one: a window with a refused tree still rasterises to several KB of
|
|
127
|
+
* perfectly valid background.
|
|
128
|
+
*/
|
|
129
|
+
export declare function blankReason(evidence: ShotEvidence): string | null;
|
|
130
|
+
/**
|
|
131
|
+
* Record "this actually rendered" as a probe check, named.
|
|
132
|
+
*
|
|
133
|
+
* Takes the evidence rather than the widget so a caller that already shot it does
|
|
134
|
+
* not rasterise twice, and so the reason lands in the failure list verbatim.
|
|
135
|
+
*/
|
|
136
|
+
export declare function checkRendered(check: ProbeCheck, what: string, evidence: ShotEvidence): void;
|
package/lib/types/props.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import GObject from 'gi://GObject';
|
|
1
|
+
import GObject from 'gi://GObject?version=2.0';
|
|
2
2
|
import type { WidgetDescriptor } from './types.js';
|
|
3
3
|
/** `backgroundColor` and `background-color` both name the GObject property `background-color`. */
|
|
4
4
|
export declare function toPropertyName(name: string): string;
|
|
@@ -33,6 +33,18 @@ export declare function constructOnlyNames(klass: GObject.ObjectClass, gtypeName
|
|
|
33
33
|
* assumed. Also the primitive a renderer needs for a "did you mean" diagnostic.
|
|
34
34
|
*/
|
|
35
35
|
export declare const lookupEnumNick: (gtypeName: string, nick: string) => number | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* The member names an installed enum registers, or `undefined` if this host has none.
|
|
38
|
+
*
|
|
39
|
+
* The INVERSE of {@link lookupEnumNick}, and it exists for the one question that
|
|
40
|
+
* function cannot answer: a nick the vocabulary never emitted is absent from every
|
|
41
|
+
* list a check could iterate, so only the host's own members can reveal it. Read off
|
|
42
|
+
* the same `ENUM_NAMESPACES` table, so the two cannot disagree about where an enum
|
|
43
|
+
* lives — a second copy of that list is what made `Pango` missing once already.
|
|
44
|
+
*
|
|
45
|
+
* `$gtype` and anything non-numeric are not members; GJS puts both on the same object.
|
|
46
|
+
*/
|
|
47
|
+
export declare function enumMembers(gtypeName: string): string[] | undefined;
|
|
36
48
|
/**
|
|
37
49
|
* Turn an authored value into one GObject will actually store.
|
|
38
50
|
*
|
package/lib/types/registry.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import GObject from 'gi://GObject';
|
|
1
|
+
import GObject from 'gi://GObject?version=2.0';
|
|
2
2
|
import type { WidgetDescriptor } from './types.js';
|
|
3
3
|
export declare function registerWidget(descriptor: WidgetDescriptor): void;
|
|
4
4
|
export declare function registerWidgets(descriptors: readonly WidgetDescriptor[]): void;
|
package/lib/types/signals.d.ts
CHANGED
|
@@ -18,9 +18,11 @@ export declare function parseEventProp(prop: string, aliases?: Readonly<Record<s
|
|
|
18
18
|
export declare const toSignalName: (prop: string, aliases?: Readonly<Record<string, string>>) => string;
|
|
19
19
|
/** An event prop is `on:` + a raw signal name, or `on` + an uppercase letter. */
|
|
20
20
|
export declare function isEventProp(prop: string): boolean;
|
|
21
|
-
export declare const beginHostWrite: () => void;
|
|
21
|
+
export declare const beginHostWrite: (target?: object | null) => void;
|
|
22
22
|
export declare const endHostWrite: () => void;
|
|
23
23
|
export declare const inHostWrite: () => boolean;
|
|
24
|
+
/** Is this object one whose property the host is writing at this instant? */
|
|
25
|
+
export declare const isHostWriteTarget: (o: object) => boolean;
|
|
24
26
|
export declare function setHandler(el: HostElement, prop: string, next: ((...args: unknown[]) => unknown) | null): void;
|
|
25
27
|
/** Disconnect every handler on a node. The only place a handler dies. */
|
|
26
28
|
export declare function clearHandlers(el: HostElement): void;
|