@gjsify/gtk-host 0.41.0 → 0.44.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 +481 -6
- package/lib/esm/adapters/react.js +1 -0
- package/lib/esm/adapters/solid.js +1 -0
- package/lib/esm/adapters/vue.js +1 -0
- package/lib/esm/attrs.js +0 -0
- package/lib/esm/conformance/diagnostics.js +2 -2
- 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/descriptors/index.js +1 -1
- package/lib/esm/errors.js +1 -1
- package/lib/esm/generated/props.js +0 -0
- package/lib/esm/generated/widgets.js +1 -0
- package/lib/esm/host.js +1 -1
- package/lib/esm/index.js +1 -1
- package/lib/esm/jsx-runtime.js +1 -0
- package/lib/esm/policies.js +1 -1
- package/lib/esm/probe.js +1 -0
- package/lib/esm/props.js +1 -1
- package/lib/esm/react-jsx-runtime.js +1 -0
- package/lib/esm/registry.js +1 -1
- package/lib/esm/signals.js +1 -1
- package/lib/esm/style/errors.js +1 -0
- package/lib/esm/style/gtk-css.js +1 -0
- package/lib/esm/style/gtk-props.js +1 -0
- package/lib/esm/style/index.js +1 -0
- package/lib/esm/style/layout.js +1 -0
- package/lib/esm/style/paint.js +1 -0
- package/lib/esm/style/resolve.js +1 -0
- package/lib/esm/style/sheet.js +3 -0
- package/lib/esm/style/tokens.js +1 -0
- package/lib/esm/tags.js +2 -0
- package/lib/esm/vue-components.js +0 -0
- package/lib/types/adapters/react.d.ts +224 -0
- package/lib/types/adapters/react.spec.d.ts +2 -0
- package/lib/types/adapters/solid.d.ts +78 -0
- package/lib/types/adapters/solid.spec.d.ts +2 -0
- package/lib/types/adapters/vue.d.ts +24 -0
- package/lib/types/adapters/vue.spec.d.ts +2 -0
- package/lib/types/attrs.d.ts +102 -0
- package/lib/types/buildable.spec.d.ts +2 -0
- package/lib/types/conformance/diagnostics.d.ts +26 -2
- package/lib/types/conformance/index.d.ts +24 -1
- package/lib/types/conformance/vectors.d.mts +34 -0
- package/lib/types/descriptors/index.d.ts +52 -1
- package/lib/types/errors.d.ts +21 -0
- package/lib/types/generated/props.d.ts +5505 -0
- package/lib/types/generated/surface-data.d.mts +22 -0
- package/lib/types/generated/widgets.d.ts +3 -0
- package/lib/types/generated.spec.d.ts +4 -0
- package/lib/types/generator/emit-types.d.mts +54 -0
- package/lib/types/generator/emit.d.mts +50 -0
- package/lib/types/generator/gir.d.mts +164 -0
- package/lib/types/generator/main.d.mts +23 -0
- package/lib/types/generator/mini.fixture.d.mts +30 -0
- package/lib/types/generator/surface.d.mts +62 -0
- package/lib/types/generator/tsmap.d.mts +73 -0
- package/lib/types/generator.spec.d.ts +2 -0
- package/lib/types/host.d.ts +102 -1
- package/lib/types/index.d.ts +6 -3
- package/lib/types/jsx-runtime.d.ts +70 -0
- package/lib/types/policies.d.ts +58 -0
- package/lib/types/probe.d.ts +87 -0
- package/lib/types/props.d.ts +52 -2
- package/lib/types/react-jsx-runtime.d.ts +108 -0
- package/lib/types/registry.d.ts +1 -1
- package/lib/types/signals.d.ts +16 -1
- package/lib/types/style/errors.d.ts +6 -0
- package/lib/types/style/gtk-css.d.ts +24 -0
- package/lib/types/style/gtk-css.spec.d.ts +2 -0
- package/lib/types/style/gtk-props.d.ts +27 -0
- package/lib/types/style/gtk-props.spec.d.ts +2 -0
- package/lib/types/style/index.d.ts +13 -0
- package/lib/types/style/layout.d.ts +163 -0
- package/lib/types/style/layout.spec.d.ts +2 -0
- package/lib/types/style/paint.d.ts +53 -0
- package/lib/types/style/paint.spec.d.ts +2 -0
- package/lib/types/style/resolve.d.ts +58 -0
- package/lib/types/style/sheet.d.ts +40 -0
- package/lib/types/style/sheet.spec.d.ts +2 -0
- package/lib/types/style/tokens.d.ts +58 -0
- package/lib/types/tags.d.ts +25 -0
- package/lib/types/testing/gate.d.mts +25 -0
- package/lib/types/types.d.ts +56 -3
- package/lib/types/vue-components.d.ts +46 -0
- package/package.json +85 -8
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The JSX surface — our OWN jsx-runtime, and the measurement that made that the
|
|
3
|
+
* only option.
|
|
4
|
+
*
|
|
5
|
+
* The obvious alternative is to augment Solid's namespace:
|
|
6
|
+
* `declare module 'solid-js' { namespace JSX { interface IntrinsicElements … } }`.
|
|
7
|
+
* Measured, that leaves all 208 tags Solid pre-declares (113 HTML + 4 deprecated
|
|
8
|
+
* HTML + 59 SVG + 32 MathML) valid on a GTK renderer: `<div/>` and `<circle/>`
|
|
9
|
+
* type-check clean and then render NOTHING, silently. Closing them needs 208
|
|
10
|
+
* `never` overrides and produces `Type '{}' is not assignable to type 'never'`
|
|
11
|
+
* instead of "no such element". With our own runtime, `<div/>` is
|
|
12
|
+
* `TS2339: Property 'div' does not exist on type 'JSX.IntrinsicElements'`.
|
|
13
|
+
*
|
|
14
|
+
* TWO CONFIGURATION FACTS A CONSUMER MUST KNOW, both measured:
|
|
15
|
+
*
|
|
16
|
+
* - `jsxImportSource` must point here, and `noImplicitAny` must be ON. With
|
|
17
|
+
* `jsx: "preserve"`, no `jsxImportSource` and `noImplicitAny` off, every JSX
|
|
18
|
+
* element is implicitly `any` and `tsc` exits 0 having checked NOTHING — the one
|
|
19
|
+
* configuration in which this whole surface evaporates in silence.
|
|
20
|
+
* - `jsx: "react"` is refused outright (TS5089); `preserve` (what
|
|
21
|
+
* babel-preset-solid needs) and `react-jsx` both work.
|
|
22
|
+
*
|
|
23
|
+
* AND ONE HOLE THAT CANNOT BE CLOSED: TypeScript exempts every HYPHENATED JSX
|
|
24
|
+
* attribute from excess-property checking, so `<gtk-box no-such={1}/>` is accepted
|
|
25
|
+
* — on intrinsics and on components alike. Three index-signature shapes were tried
|
|
26
|
+
* (`\`${string}-${string}\`` mapped to `unknown`, to `never`, and to a subtracted
|
|
27
|
+
* union); all three either changed nothing or collided with the declared kebab
|
|
28
|
+
* keys (TS2411). The camelCase spelling of every property IS checked, which is why
|
|
29
|
+
* both spellings are generated and camelCase is the one to prefer.
|
|
30
|
+
*/
|
|
31
|
+
import type { JsxAttributes, WithOnce } from './attrs.js';
|
|
32
|
+
import type { HostNode } from './types.js';
|
|
33
|
+
import type { WidgetClassByTag, WidgetPropsByTag } from './generated/props.js';
|
|
34
|
+
/** Every GTK/Adwaita tag, with its properties, its handlers and its `ref`. */
|
|
35
|
+
export type GtkIntrinsicElements = {
|
|
36
|
+
[K in keyof WidgetPropsByTag]: WithOnce<WidgetPropsByTag[K]> & JsxAttributes<WidgetClassByTag[K]>;
|
|
37
|
+
};
|
|
38
|
+
export declare namespace JSX {
|
|
39
|
+
/**
|
|
40
|
+
* The type of a JSX EXPRESSION — a host node, not `ElementChild`.
|
|
41
|
+
*
|
|
42
|
+
* It was `ElementChild` (`HostNode | ElementChildren | string | number |
|
|
43
|
+
* boolean | null | undefined`), which reads like the right answer because that
|
|
44
|
+
* is what may be PASSED as a child. It is not what a JSX element evaluates
|
|
45
|
+
* TO: the compiler's `createElement` returns a node, always.
|
|
46
|
+
*
|
|
47
|
+
* The imprecision was not cosmetic. `<For>`, `<Index>` and `<Show>` are typed
|
|
48
|
+
* in `adapters/solid.ts` against `HostNode` — deliberately, because Solid's own
|
|
49
|
+
* signatures pin `JSX.Element` to the DOM's `Element` — so with `Element` this
|
|
50
|
+
* wide the FIRST `<For>` in any application failed with
|
|
51
|
+
* `Type 'ElementChild' is not assignable to type 'HostNode'`, and the whole
|
|
52
|
+
* control-flow surface was untypeable. Found by the first real JSX app
|
|
53
|
+
* (`showcases/gtk/solid-host-counter`); the fixtures in `type-tests/jsx/` had
|
|
54
|
+
* never used a control-flow component, which is why they went green over it.
|
|
55
|
+
* `type-tests/jsx/positive-element-is-a-node.tsx` is that gap closed.
|
|
56
|
+
*
|
|
57
|
+
* Children stay wide: they are typed by `JsxAttributes.children`, not by this.
|
|
58
|
+
*/
|
|
59
|
+
type Element = HostNode;
|
|
60
|
+
/** Names the prop children arrive on — without it, nesting is an error. */
|
|
61
|
+
interface ElementChildrenAttribute {
|
|
62
|
+
children: Record<never, never>;
|
|
63
|
+
}
|
|
64
|
+
interface IntrinsicElements extends GtkIntrinsicElements {
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export declare function jsx(): never;
|
|
68
|
+
export declare function jsxs(): never;
|
|
69
|
+
export declare function jsxDEV(): never;
|
|
70
|
+
export declare function Fragment(): never;
|
package/lib/types/policies.d.ts
CHANGED
|
@@ -11,6 +11,64 @@ export declare function addressOf(el: HostElement): Gtk.Widget;
|
|
|
11
11
|
* activation from the one the author configured.
|
|
12
12
|
*/
|
|
13
13
|
export declare function makeWrapper(policy: ChildPolicy, child: Gtk.Widget): Gtk.Widget | null;
|
|
14
|
+
/**
|
|
15
|
+
* A container the host owns that no window shows — the DOM's detached `<div>`.
|
|
16
|
+
*
|
|
17
|
+
* `<KeepAlive>` and `<Suspense>` ask a renderer for off-screen storage:
|
|
18
|
+
* `KeepAliveImpl.setup` opens with `createElement("div")` and `SuspenseImpl` does
|
|
19
|
+
* the same for its `hiddenContainer`. The Vue adapter answered that with its own
|
|
20
|
+
* `gi://Gtk` import and a literal `new Gtk.Box()` — the ONE runtime toolkit import
|
|
21
|
+
* and the ONE concrete widget class in any adapter, i.e. exactly the widget
|
|
22
|
+
* knowledge ADR 0027 § 7 forbids one. It lives here because this is already the
|
|
23
|
+
* file that builds widgets the author did not write (see `makeWrapper`), and it is
|
|
24
|
+
* the only one with a runtime `gi://Gtk` import.
|
|
25
|
+
*
|
|
26
|
+
* A `Gtk.Box` and not an `Adw.Bin`: the deactivated subtree may hold SEVERAL
|
|
27
|
+
* children, and a one-child container would silently keep the last.
|
|
28
|
+
*/
|
|
29
|
+
export declare const makeDetachedContainer: () => Gtk.Widget;
|
|
30
|
+
/**
|
|
31
|
+
* The ONE-CHILD setter this child's placement goes through, or null.
|
|
32
|
+
*
|
|
33
|
+
* `single` always is one (`set_child`, `set_content`); a `slotted` slot is one
|
|
34
|
+
* when its method is a setter (`set_content`, `set_title_widget`) rather than an
|
|
35
|
+
* adder. Such a slot REPLACES — and it does so silently, which is why four call
|
|
36
|
+
* sites need the same question answered. Two of them are about an ELEMENT
|
|
37
|
+
* arriving; the other two are about TEXT, because GTK's text sink is the SAME
|
|
38
|
+
* slot: measured on gtk 4.22, `button.set_child(w)` followed by
|
|
39
|
+
* `set_property('label', …)` leaves `w.get_parent() === null`, and `set_child`
|
|
40
|
+
* after a `label` write leaves `label === null`. One widget, one slot, two APIs.
|
|
41
|
+
*/
|
|
42
|
+
/**
|
|
43
|
+
* Compile-time exhaustiveness, which this package does NOT get for free.
|
|
44
|
+
*
|
|
45
|
+
* `tsconfig.json` sets `strict: false`, so a switch that stops covering its union
|
|
46
|
+
* simply falls through and returns `undefined` — no error. Adding the `uncurated`
|
|
47
|
+
* policy kind passed `tsc` cleanly while five switches silently ignored it, which
|
|
48
|
+
* is exactly the class of green-and-wrong this package exists to prevent
|
|
49
|
+
* elsewhere. Assignability to `never` is not a strictness option, so a `default`
|
|
50
|
+
* arm calling this DOES fail the build (measured) and is the only mechanism that
|
|
51
|
+
* makes the next union member impossible to forget.
|
|
52
|
+
*/
|
|
53
|
+
export declare function unhandledPolicy(policy: never): never;
|
|
54
|
+
export declare function setterSlotOf(parent: HostElement, child: HostElement): string | null;
|
|
55
|
+
/** Every one-child slot this policy has, by setter name — `single` has exactly one. */
|
|
56
|
+
export declare function setterSlots(policy: ChildPolicy): string[];
|
|
57
|
+
/**
|
|
58
|
+
* Who GTK says is in a one-child slot. `undefined` means there is no getter to ask.
|
|
59
|
+
*
|
|
60
|
+
* The slot's own getter is the ONLY honest reader of this, and a child-list walk
|
|
61
|
+
* is not a substitute: measured on gtk 4.22.4 / libadwaita 1.9.3, a FRESH widget
|
|
62
|
+
* already has direct children the application never put there —
|
|
63
|
+
* `Gtk.ScrolledWindow` two `GtkScrollbar`s, `Adw.ToolbarView` two
|
|
64
|
+
* `GtkRevealer`s, `Adw.Window` an `AdwDialogHost` + an `AdwGizmo`,
|
|
65
|
+
* `Adw.StatusPage` a `GtkScrolledWindow` — while every one of those widgets
|
|
66
|
+
* answers `null` from its getter. The getter also survives GTK wrapping the
|
|
67
|
+
* child: `Gtk.ScrolledWindow.set_child(label)` reports a `GtkViewport`, not the
|
|
68
|
+
* label, so callers may compare occupants for IDENTITY but never assume the
|
|
69
|
+
* occupant is the widget they handed over.
|
|
70
|
+
*/
|
|
71
|
+
export declare function slotOccupant(widget: Gtk.Widget, setter: string): Gtk.Widget | null | undefined;
|
|
14
72
|
export interface Placement {
|
|
15
73
|
parent: HostElement;
|
|
16
74
|
child: HostElement;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import Adw from 'gi://Adw?version=1';
|
|
2
|
+
/** Record one assertion. A `false` is a finding; nothing else is. */
|
|
3
|
+
export type ProbeCheck = (what: string, ok: boolean) => void;
|
|
4
|
+
/** What a showcase gives the harness. */
|
|
5
|
+
export interface HostProbe<T> {
|
|
6
|
+
/**
|
|
7
|
+
* Build the UI. `app` is `null` on the headless path, where there is no
|
|
8
|
+
* `GApplication` and the window is never presented.
|
|
9
|
+
*/
|
|
10
|
+
build(app: Adw.Application | null): T;
|
|
11
|
+
/**
|
|
12
|
+
* Assert against the REAL widget tree — `get_first_child()`/`get_next_sibling()`
|
|
13
|
+
* and the exact getters, never the host's own bookkeeping, which would agree
|
|
14
|
+
* with itself while the window is wrong. Return whatever belongs in the result
|
|
15
|
+
* line; the harness adds the failure list and the diagnostic count.
|
|
16
|
+
*
|
|
17
|
+
* MAY BE ASYNC, and one adapter forces it: Vue flushes render jobs on a
|
|
18
|
+
* microtask, so an assertion after a click has to `await nextTick()` or it reads
|
|
19
|
+
* the pre-patch tree. Without this the Vue showcase hand-rolled the whole
|
|
20
|
+
* harness, and the copy carried the pre-`describeLogRecord` collector bug with
|
|
21
|
+
* it — a log record with no `MESSAGE` counted as a diagnostic and then described
|
|
22
|
+
* as the empty string.
|
|
23
|
+
*/
|
|
24
|
+
assert(ui: T, check: ProbeCheck): Record<string, unknown> | Promise<Record<string, unknown>>;
|
|
25
|
+
/**
|
|
26
|
+
* Release what the assertions built, before the diagnostics are counted.
|
|
27
|
+
*
|
|
28
|
+
* ORDER IS THE POINT. Teardown is exactly where GTK reports a mis-parented tree
|
|
29
|
+
* — `Finalizing GtkLabel …, but it still has children left` arrives at finalize,
|
|
30
|
+
* at exit 0 (ADR 0027 § Context). A probe that counts diagnostics and THEN tears
|
|
31
|
+
* down cannot see the one class of defect that only surfaces there, which is
|
|
32
|
+
* what both hand-written probes did.
|
|
33
|
+
*
|
|
34
|
+
* Optional because a probe that owns nothing has nothing to release; the
|
|
35
|
+
* harness's own `build` result is reachable only from here.
|
|
36
|
+
*/
|
|
37
|
+
teardown?(ui: T): void;
|
|
38
|
+
/** Prefix of the machine-readable result line. Default `PROBE`. */
|
|
39
|
+
label?: string;
|
|
40
|
+
}
|
|
41
|
+
/** A showcase that also has a GUI path — i.e. every one of them. */
|
|
42
|
+
export interface HostProbeApp<T> extends HostProbe<T> {
|
|
43
|
+
/** GApplication id for the GUI path. */
|
|
44
|
+
applicationId: string;
|
|
45
|
+
/** Present the toplevel. Reached only after the assertions have passed. */
|
|
46
|
+
present(ui: T): void;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Truthy-env check, matching `@gjsify/devtools`' `GJSIFY_DEVTOOLS` gate semantics
|
|
50
|
+
* and `@gjsify/storybook`'s `probeEnabled` — one spelling of "opt in" across the
|
|
51
|
+
* repo, so `=0` and `=false` mean off rather than "any value is on".
|
|
52
|
+
*/
|
|
53
|
+
export declare function probeEnabled(): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Run the showcase's assertions once and return the process exit code.
|
|
56
|
+
*
|
|
57
|
+
* **The probe always builds HEADLESS, in both paths.** It is handed `null` rather
|
|
58
|
+
* than the `GApplication`, for two reasons that point the same way. It makes the two
|
|
59
|
+
* paths return the same verdict about the same tree — a probe whose GUI run differs
|
|
60
|
+
* from its headless run is two probes. And it keeps the GUI path from constructing
|
|
61
|
+
* and (now that `teardown` exists) destroying an `Adw.ApplicationWindow` INSIDE
|
|
62
|
+
* `activate`, which is the exact neighbourhood of the segfault recorded on
|
|
63
|
+
* `runHostProbeApp` below. Nothing a probe asserts needs an application; `present`
|
|
64
|
+
* gets the real one.
|
|
65
|
+
*
|
|
66
|
+
* The diagnostics gate is reset first and asserted last, and both halves are the
|
|
67
|
+
* harness's rather than the showcase's. Reset, because in the GUI path this runs
|
|
68
|
+
* from `activate` — AFTER Adw startup, where a session-bus, portal, theme or a11y
|
|
69
|
+
* warning is routine in a container, and counting those would fail the showcase
|
|
70
|
+
* with the host's name on a diagnostic it did not cause. Asserted, because GTK's
|
|
71
|
+
* failure mode is exit 0: a mis-parented widget floods `Gtk-WARNING` and the
|
|
72
|
+
* process still succeeds.
|
|
73
|
+
*/
|
|
74
|
+
export declare function runHostProbe<T>(probe: HostProbe<T>): Promise<number>;
|
|
75
|
+
/**
|
|
76
|
+
* The whole `main` of a gtk-host showcase.
|
|
77
|
+
*
|
|
78
|
+
* `GJSIFY_HOST_PROBE` truthy: assert headlessly and exit, no window and no main
|
|
79
|
+
* loop. Otherwise: run the SAME assertions from `activate` before the window is
|
|
80
|
+
* shown, exit non-zero if any of them failed, then present. The GUI path carrying
|
|
81
|
+
* the assertions is the load-bearing half — `scripts/showcase-smoke.mjs` launches
|
|
82
|
+
* the app and waits, so without it the CI leg proves only that the process started.
|
|
83
|
+
*
|
|
84
|
+
* `runAsync`, never the sync `run()`: a sync `run()` leaves promise jobs undrained
|
|
85
|
+
* and hangs a view load on its spinner (the class `@gjsify/adwaita-app` documents).
|
|
86
|
+
*/
|
|
87
|
+
export declare function runHostProbeApp<T>(probe: HostProbeApp<T>): Promise<void>;
|
package/lib/types/props.d.ts
CHANGED
|
@@ -1,12 +1,38 @@
|
|
|
1
1
|
import GObject from 'gi://GObject';
|
|
2
|
+
import type { WidgetDescriptor } from './types.js';
|
|
2
3
|
/** `backgroundColor` and `background-color` both name the GObject property `background-color`. */
|
|
3
4
|
export declare function toPropertyName(name: string): string;
|
|
5
|
+
/**
|
|
6
|
+
* A props object without the keys a framework reserves for itself.
|
|
7
|
+
*
|
|
8
|
+
* The SET is per-framework and stays with the adapter that owns it — Vue's is
|
|
9
|
+
* `@vue/shared`'s `isReservedProp`, React's is `children` — but the LOOP was
|
|
10
|
+
* written twice, byte-for-byte apart from the identifier names. That is the second
|
|
11
|
+
* copy this repo lifts on: the two would drift, and the drifted one fails in a
|
|
12
|
+
* consumer while the host stays green.
|
|
13
|
+
*
|
|
14
|
+
* `undefined` rather than `{}` for an empty result, and that is load-bearing:
|
|
15
|
+
* `createElement(tag, undefined)` skips the property loop entirely, so a vnode
|
|
16
|
+
* whose props are ALL reserved must not look like a vnode with one unknown
|
|
17
|
+
* property.
|
|
18
|
+
*/
|
|
19
|
+
export declare function withoutKeys(props: Record<string, unknown> | null | undefined, skip: ReadonlySet<string>): Record<string, unknown> | undefined;
|
|
4
20
|
/** All ParamSpecs of a class, by kebab name. Cached per GType — `list_properties()` is not cheap. */
|
|
5
21
|
export declare function paramSpecs(klass: GObject.ObjectClass, gtypeName: string): Map<string, GObject.ParamSpec>;
|
|
6
22
|
export declare const isWritable: (spec: GObject.ParamSpec) => boolean;
|
|
7
23
|
export declare const isConstructOnly: (spec: GObject.ParamSpec) => boolean;
|
|
8
24
|
/** Construct-only property names of a class, in declaration order. */
|
|
9
25
|
export declare function constructOnlyNames(klass: GObject.ObjectClass, gtypeName: string): string[];
|
|
26
|
+
/**
|
|
27
|
+
* The value a nick names on an enum GType, or undefined if it names none.
|
|
28
|
+
*
|
|
29
|
+
* Exported for the generated surface's own check: the type surface offers a union
|
|
30
|
+
* of nicks per enum, and a nick this host cannot resolve would type-check and then
|
|
31
|
+
* be refused at runtime. `generated.spec.ts` resolves every emitted nick through
|
|
32
|
+
* this function, so the GIR-member-to-nick spelling is measured rather than
|
|
33
|
+
* assumed. Also the primitive a renderer needs for a "did you mean" diagnostic.
|
|
34
|
+
*/
|
|
35
|
+
export declare const lookupEnumNick: (gtypeName: string, nick: string) => number | undefined;
|
|
10
36
|
/**
|
|
11
37
|
* Turn an authored value into one GObject will actually store.
|
|
12
38
|
*
|
|
@@ -22,8 +48,32 @@ export declare function coerce(spec: GObject.ParamSpec, value: unknown, tag: str
|
|
|
22
48
|
*
|
|
23
49
|
* React hands `undefined` for a prop that disappeared, and GObject cannot store
|
|
24
50
|
* that: `set_property(name, undefined)` throws "Could not guess unspecified
|
|
25
|
-
* GValue type" (measured).
|
|
51
|
+
* GValue type" (measured). What "removed" means is the value the widget would
|
|
52
|
+
* have carried had the prop never been authored — and that is what CONSTRUCTION
|
|
53
|
+
* leaves behind, not what the ParamSpec declares.
|
|
54
|
+
*
|
|
55
|
+
* The two disagree far too often to treat the ParamSpec as an approximation.
|
|
56
|
+
* Measured on gjs 1.88.1 / GTK 4.22.4 / libadwaita 1.9.3, one probe per row, over
|
|
57
|
+
* the curated descriptors as this table ships them — 27 of them at the time of the
|
|
58
|
+
* measurement, so the totals move when a row joins: 981 scalar properties are both
|
|
59
|
+
* readable and writable, and **107 of them disagree** — 80 once construct-only
|
|
60
|
+
* `css-name` is set aside. Twelve property names carry it, four of them
|
|
61
|
+
* behavioural, and those four are pinned BY NAME in `props.spec.ts` because a name
|
|
62
|
+
* is what survives a re-count:
|
|
63
|
+
*
|
|
64
|
+
* GtkWindow.visible spec=true constructed=false
|
|
65
|
+
* AdwActionRow.activatable spec=true constructed=false
|
|
66
|
+
* GtkToggleButton.receives-default spec=false constructed=true
|
|
67
|
+
* GtkListBox.focusable spec=false constructed=true (7 types)
|
|
68
|
+
*
|
|
69
|
+
* So `<AdwActionRow activatable={cond}>` with `cond` going `undefined` made a
|
|
70
|
+
* non-activatable row activatable, and removing `visible` SHOWED a window —
|
|
71
|
+
* silently, at exit 0, in the package that exists to refuse exactly that.
|
|
72
|
+
*
|
|
73
|
+
* `name` is kept as the probe reports it rather than as the ParamSpec's `null`:
|
|
74
|
+
* `gtk_widget_get_name` falls back to the type name when none was set, so the
|
|
75
|
+
* probe's answer is the one CSS `#id` matching already sees.
|
|
26
76
|
*/
|
|
27
|
-
export declare function
|
|
77
|
+
export declare function removedValue(descriptor: WidgetDescriptor, spec: GObject.ParamSpec): unknown;
|
|
28
78
|
/** Look a property up, refusing the two silent failures: unknown and read-only. */
|
|
29
79
|
export declare function requireSpec(specs: Map<string, GObject.ParamSpec>, tag: string, name: string): GObject.ParamSpec;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The React JSX surface: React's OWN automatic runtime, our OWN element list.
|
|
3
|
+
*
|
|
4
|
+
* `./jsx-runtime` in this package deliberately THROWS from `jsx()`/`jsxs()`, and
|
|
5
|
+
* that refusal is correct for the dialects it serves — Solid's reactivity lives in
|
|
6
|
+
* what `babel-preset-solid` emits from `jsx: "preserve"`, and Vue's in its SFC
|
|
7
|
+
* compiler, so an automatic runtime reaching those functions means the pipeline was
|
|
8
|
+
* misconfigured and nothing would render. React is the opposite case and the
|
|
9
|
+
* difference is structural rather than a matter of taste: React's `jsx()` builds a
|
|
10
|
+
* plain, renderer-agnostic React ELEMENT (a `{type, props, key}` record), and the
|
|
11
|
+
* host mapping happens later, in `react-reconciler`. So the automatic runtime is
|
|
12
|
+
* exactly the right thing here, and it is React's own — reimplementing it would be
|
|
13
|
+
* a second `createElement` to keep in step with React's element format.
|
|
14
|
+
*
|
|
15
|
+
* That is why this is a SEPARATE subpath instead of a change to `./jsx-runtime`:
|
|
16
|
+
* one module cannot both refuse the automatic runtime (for Solid) and provide it
|
|
17
|
+
* (for React). A consumer picks by pointing `jsxImportSource` at one or the other,
|
|
18
|
+
* and TypeScript appends `/jsx-runtime` (`/jsx-dev-runtime` under
|
|
19
|
+
* `jsx: "react-jsxdev"`) — hence two export keys beside `./react`. The tsconfig
|
|
20
|
+
* recipe is in the package README.
|
|
21
|
+
*
|
|
22
|
+
* WHY NOT just `jsxImportSource: "react"`. Then the element list comes from
|
|
23
|
+
* `@types/react`'s own `JSX.IntrinsicElements`, which is the 208-tag problem ADR
|
|
24
|
+
* 0028 § 8 measured on Solid, one package over: every HTML, SVG and MathML tag
|
|
25
|
+
* type-checks clean on a GTK renderer and then renders NOTHING. Declaring the
|
|
26
|
+
* namespace here is what makes `<div/>` a `TS2339` naming the element.
|
|
27
|
+
*
|
|
28
|
+
* The element list itself is the generated `WidgetPropsByTag`/`WidgetClassByTag`,
|
|
29
|
+
* which `scripts/check-type-surfaces.mjs` already holds negative-first through its
|
|
30
|
+
* `jsx` half. The React-specific plumbing below has no half yet — that gap, and
|
|
31
|
+
* why adding one is not a one-liner, is in `status/open-todos.md`. Its RUNTIME
|
|
32
|
+
* half is `adapters/react.spec.ts`.
|
|
33
|
+
*/
|
|
34
|
+
import type { Key, ReactElement, ReactNode, Ref } from 'react';
|
|
35
|
+
import type { WidgetClassByTag, WidgetPropsByTag } from './generated/props.js';
|
|
36
|
+
import type { RawSignalAttributes, SlotAttribute, WithOnce } from './attrs.js';
|
|
37
|
+
export { Fragment } from 'react/jsx-runtime';
|
|
38
|
+
/**
|
|
39
|
+
* React's own factories, RE-TYPED over this package's element list.
|
|
40
|
+
*
|
|
41
|
+
* The functions are React's — identity matters, because they build React's
|
|
42
|
+
* element format and a reimplementation would be a second one to keep in step.
|
|
43
|
+
* Only the SIGNATURE is ours: `@types/react` types `type` as React's
|
|
44
|
+
* `ElementType`, i.e. every HTML/SVG/MathML tag, so a direct call with a GTK tag
|
|
45
|
+
* would be a type error while a JSX tag (checked against `JSX.IntrinsicElements`
|
|
46
|
+
* below) would not. The cast is what makes the two agree.
|
|
47
|
+
*/
|
|
48
|
+
export declare const jsx: GtkJsxFactory;
|
|
49
|
+
export declare const jsxs: GtkJsxFactory;
|
|
50
|
+
export declare const jsxDEV: GtkJsxDevFactory;
|
|
51
|
+
/** What may stand in a JSX tag position here: a GTK tag or a component. */
|
|
52
|
+
export type GtkElementType = keyof GtkReactIntrinsicElements | ((props: never) => ReactNode);
|
|
53
|
+
type GtkJsxFactory = (type: GtkElementType, props: unknown, key?: Key) => ReactElement;
|
|
54
|
+
type GtkJsxDevFactory = (type: GtkElementType, props: unknown, key: Key | undefined, isStatic: boolean, source?: unknown, self?: unknown) => ReactElement;
|
|
55
|
+
/**
|
|
56
|
+
* Per-element attributes React needs on top of the GObject properties.
|
|
57
|
+
*
|
|
58
|
+
* Deliberately not `JsxAttributes` from `./attrs.js`: that one types `ref` as
|
|
59
|
+
* `T | ((el: T) => void)`, which is Solid's spelling. React's `ref` additionally
|
|
60
|
+
* accepts a `useRef` object, so a shared type would reject the single most common
|
|
61
|
+
* way a React author holds a widget.
|
|
62
|
+
*
|
|
63
|
+
* `ref`, `children` and `key` are declared per element rather than left to
|
|
64
|
+
* `JSX.IntrinsicAttributes`, which TypeScript unions into the attributes of a
|
|
65
|
+
* COMPONENT and not of an intrinsic element — measured in ADR 0028 § 8: an
|
|
66
|
+
* undeclared `ref` is TS2322 and an undeclared `children` makes every nested
|
|
67
|
+
* element TS2559. `children` must also be optional, or a self-closing tag is
|
|
68
|
+
* TS2741.
|
|
69
|
+
*/
|
|
70
|
+
export interface ReactWidgetAttributes<T> extends SlotAttribute, RawSignalAttributes {
|
|
71
|
+
children?: ReactNode;
|
|
72
|
+
ref?: Ref<T> | undefined;
|
|
73
|
+
key?: Key | null | undefined;
|
|
74
|
+
}
|
|
75
|
+
/** Every GTK/Adwaita tag, with its properties, its handlers, its `ref` and its `key`. */
|
|
76
|
+
export type GtkReactIntrinsicElements = {
|
|
77
|
+
[K in keyof WidgetPropsByTag]: WithOnce<WidgetPropsByTag[K]> & ReactWidgetAttributes<WidgetClassByTag[K]>;
|
|
78
|
+
};
|
|
79
|
+
export declare namespace JSX {
|
|
80
|
+
/**
|
|
81
|
+
* DELIBERATELY NOT `HostNode`, and not to be made "consistent" with the Solid
|
|
82
|
+
* surface next door.
|
|
83
|
+
*
|
|
84
|
+
* `jsx-runtime.ts` declares `Element = HostNode`, because Solid's control-flow
|
|
85
|
+
* components (`<For>`, `<Index>`, `<Show>`) are typed against host nodes and the
|
|
86
|
+
* first `<For>` in an application was otherwise a type error. React's is
|
|
87
|
+
* `ReactElement` because that is what a React JSX expression evaluates to: `jsx()`
|
|
88
|
+
* builds a renderer-agnostic element record and the host mapping happens later, in
|
|
89
|
+
* the reconciler. React's control flow is plain JavaScript, not typed components,
|
|
90
|
+
* so nothing here needs a host node in that position.
|
|
91
|
+
*
|
|
92
|
+
* The two files therefore answer two different questions and will keep disagreeing
|
|
93
|
+
* on this line. That is the design, which is why it is written down at the line
|
|
94
|
+
* rather than left to be rediscovered by whoever reaches for the one-line fix.
|
|
95
|
+
*/
|
|
96
|
+
type Element = ReactElement;
|
|
97
|
+
type ElementType = GtkElementType;
|
|
98
|
+
/** Names the prop children arrive on — without it, nesting is an error. */
|
|
99
|
+
interface ElementChildrenAttribute {
|
|
100
|
+
children: Record<never, never>;
|
|
101
|
+
}
|
|
102
|
+
/** What React itself adds to every element, intrinsic or component. */
|
|
103
|
+
interface IntrinsicAttributes {
|
|
104
|
+
key?: Key | null | undefined;
|
|
105
|
+
}
|
|
106
|
+
interface IntrinsicElements extends GtkReactIntrinsicElements {
|
|
107
|
+
}
|
|
108
|
+
}
|
package/lib/types/registry.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export declare function registerWidget(descriptor: WidgetDescriptor): void;
|
|
|
4
4
|
export declare function registerWidgets(descriptors: readonly WidgetDescriptor[]): void;
|
|
5
5
|
export declare function lookupWidget(tag: string): WidgetDescriptor;
|
|
6
6
|
export declare const hasWidget: (tag: string) => boolean;
|
|
7
|
-
/** Every registered
|
|
7
|
+
/** Every registered GType name — the conformance suite walks this, so coverage is data. */
|
|
8
8
|
export declare const registeredTags: () => string[];
|
|
9
9
|
/**
|
|
10
10
|
* The nearest registered ancestor of a GType, most specific first.
|
package/lib/types/signals.d.ts
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
import type { HostElement } from './types.js';
|
|
2
|
+
export interface EventBinding {
|
|
3
|
+
/** The GObject signal name, modifiers removed. */
|
|
4
|
+
signal: string;
|
|
5
|
+
/** `.once`: disconnect after the first emission that actually reaches the callback. */
|
|
6
|
+
once: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Split an event prop into the signal GObject knows and the options it does not.
|
|
10
|
+
*
|
|
11
|
+
* Both escape hatches come FIRST and are verbatim: an `eventAliases` entry and
|
|
12
|
+
* the `on:<raw-signal-name>` spelling are the way to bind a signal that really
|
|
13
|
+
* does end in `-once` or `-capture`, exactly as they are the way to bind any
|
|
14
|
+
* other irregular name.
|
|
15
|
+
*/
|
|
16
|
+
export declare function parseEventProp(prop: string, aliases?: Readonly<Record<string, string>>): EventBinding;
|
|
2
17
|
/** `onRowActivated` -> `row-activated`; `onNotifyVisible` -> `notify::visible`. */
|
|
3
|
-
export declare
|
|
18
|
+
export declare const toSignalName: (prop: string, aliases?: Readonly<Record<string, string>>) => string;
|
|
4
19
|
/** An event prop is `on:` + a raw signal name, or `on` + an uppercase letter. */
|
|
5
20
|
export declare function isEventProp(prop: string): boolean;
|
|
6
21
|
export declare const beginHostWrite: () => void;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** A utility class, property or combination this vocabulary cannot answer for, and why. */
|
|
2
|
+
export declare class UnknownUtilityError extends Error {
|
|
3
|
+
readonly name = "UnknownUtilityError";
|
|
4
|
+
readonly utility: string;
|
|
5
|
+
constructor(utility: string, detail: string);
|
|
6
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Property names GTK4 accepts in a stylesheet, with a value that parses.
|
|
3
|
+
*
|
|
4
|
+
* The value matters: `border-radius: 8px` and `border-radius: 9999px` both parse,
|
|
5
|
+
* but a property is only provably present when some value for it is accepted.
|
|
6
|
+
*/
|
|
7
|
+
export declare const GTK_CSS_PROBES: ReadonlyArray<readonly [property: string, value: string]>;
|
|
8
|
+
/**
|
|
9
|
+
* Property names GTK4 REFUSES, and the reason each one is here.
|
|
10
|
+
*
|
|
11
|
+
* Most of them are the layout model the web has and GTK does not — there is no
|
|
12
|
+
* `display: flex`, no absolute positioning, no intrinsic `width`. They must become
|
|
13
|
+
* widget selection and widget properties, which is the layout half.
|
|
14
|
+
*
|
|
15
|
+
* Two groups are not that, and both are here because a reader would assume the
|
|
16
|
+
* opposite. `text-align` is not about layout at all: it is the property most likely
|
|
17
|
+
* to be grouped with `color` and `font-size` by anyone reading a Tailwind `text-*`
|
|
18
|
+
* vocabulary, and GTK drops it in silence. The four logical spacings ARE spacing,
|
|
19
|
+
* whose physical spellings sit in the accepted table three lines up — the refusal
|
|
20
|
+
* is per NAME, not per concept, and that is the asymmetry `layout.ts` is built on.
|
|
21
|
+
*/
|
|
22
|
+
export declare const NOT_GTK_CSS: ReadonlyArray<readonly [property: string, value: string]>;
|
|
23
|
+
/** The property names of {@link GTK_CSS_PROBES}, for a membership test. */
|
|
24
|
+
export declare const GTK_CSS_PROPERTIES: ReadonlySet<string>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Properties GTK installs, with the GType of their value.
|
|
3
|
+
*
|
|
4
|
+
* `GtkWidget` rows are the universal set — every widget in the table inherits
|
|
5
|
+
* them, which is what lets `layout.ts` emit them without knowing the tag.
|
|
6
|
+
*/
|
|
7
|
+
export declare const GTK_WIDGET_PROPERTY_PROBES: ReadonlyArray<readonly [gtype: string, property: string, valueType: string]>;
|
|
8
|
+
/**
|
|
9
|
+
* Properties the class does NOT install, and the claim each one carries.
|
|
10
|
+
*
|
|
11
|
+
* Without this direction the table above could name every property in GTK and
|
|
12
|
+
* still pass — and every routing decision in `layout.ts` rests on an absence
|
|
13
|
+
* rather than on a presence.
|
|
14
|
+
*/
|
|
15
|
+
export declare const NOT_GTK_WIDGET_PROPERTIES: ReadonlyArray<readonly [gtype: string, property: string]>;
|
|
16
|
+
/**
|
|
17
|
+
* The property NAMES of {@link GTK_WIDGET_PROPERTY_PROBES}, for a membership test.
|
|
18
|
+
*
|
|
19
|
+
* NAMES ONLY, deliberately weaker than the table: L1 does not know which widget a
|
|
20
|
+
* class list will land on, so the strongest guard it can run is "GTK installs a
|
|
21
|
+
* property by this name SOMEWHERE in the vocabulary". `orientation` passes it on
|
|
22
|
+
* an element that turns out to be a `Gtk.Label`, and refusing that is L2's job,
|
|
23
|
+
* with the tag in hand. Reading this set as "every widget has these" is the one
|
|
24
|
+
* mistake it invites, and `GTK_WIDGET_PROPERTY_PROBES` is the table that answers
|
|
25
|
+
* the per-class question.
|
|
26
|
+
*/
|
|
27
|
+
export declare const GTK_WIDGET_PROPERTIES: ReadonlySet<string>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { GTK_CSS_PROBES, GTK_CSS_PROPERTIES, NOT_GTK_CSS } from './gtk-css.js';
|
|
2
|
+
export { GTK_WIDGET_PROPERTIES, GTK_WIDGET_PROPERTY_PROBES, NOT_GTK_WIDGET_PROPERTIES } from './gtk-props.js';
|
|
3
|
+
export { MINIMAL_TOKENS, lookupToken, requireToken } from './tokens.js';
|
|
4
|
+
export type { Scale, StyleTokens } from './tokens.js';
|
|
5
|
+
export { UnknownUtilityError } from './errors.js';
|
|
6
|
+
export { PAINT_PROPERTIES, partitionPaint, resolvePaintUtility } from './paint.js';
|
|
7
|
+
export type { PaintProps } from './paint.js';
|
|
8
|
+
export { LAYOUT_PROPERTIES, partitionLayout, resolveLayoutUtility } from './layout.js';
|
|
9
|
+
export type { AlignValue, Edge, JustifyValue, LayoutIntent, LayoutPartition, LayoutProps, OverlayIntent, } from './layout.js';
|
|
10
|
+
export { partition, resolveUtilities, resolveUtility } from './resolve.js';
|
|
11
|
+
export type { Partitioned, StyleProps } from './resolve.js';
|
|
12
|
+
export { StyleSheet, StyleSheetError, VARIANT_PSEUDO } from './sheet.js';
|
|
13
|
+
export type { StyleSheetOptions } from './sheet.js';
|