@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.
Files changed (86) hide show
  1. package/README.md +481 -6
  2. package/lib/esm/adapters/react.js +1 -0
  3. package/lib/esm/adapters/solid.js +1 -0
  4. package/lib/esm/adapters/vue.js +1 -0
  5. package/lib/esm/attrs.js +0 -0
  6. package/lib/esm/conformance/diagnostics.js +2 -2
  7. package/lib/esm/conformance/index.js +2 -2
  8. package/lib/esm/descriptors/adw.js +1 -1
  9. package/lib/esm/descriptors/gtk.js +1 -1
  10. package/lib/esm/descriptors/index.js +1 -1
  11. package/lib/esm/errors.js +1 -1
  12. package/lib/esm/generated/props.js +0 -0
  13. package/lib/esm/generated/widgets.js +1 -0
  14. package/lib/esm/host.js +1 -1
  15. package/lib/esm/index.js +1 -1
  16. package/lib/esm/jsx-runtime.js +1 -0
  17. package/lib/esm/policies.js +1 -1
  18. package/lib/esm/probe.js +1 -0
  19. package/lib/esm/props.js +1 -1
  20. package/lib/esm/react-jsx-runtime.js +1 -0
  21. package/lib/esm/registry.js +1 -1
  22. package/lib/esm/signals.js +1 -1
  23. package/lib/esm/style/errors.js +1 -0
  24. package/lib/esm/style/gtk-css.js +1 -0
  25. package/lib/esm/style/gtk-props.js +1 -0
  26. package/lib/esm/style/index.js +1 -0
  27. package/lib/esm/style/layout.js +1 -0
  28. package/lib/esm/style/paint.js +1 -0
  29. package/lib/esm/style/resolve.js +1 -0
  30. package/lib/esm/style/sheet.js +3 -0
  31. package/lib/esm/style/tokens.js +1 -0
  32. package/lib/esm/tags.js +2 -0
  33. package/lib/esm/vue-components.js +0 -0
  34. package/lib/types/adapters/react.d.ts +224 -0
  35. package/lib/types/adapters/react.spec.d.ts +2 -0
  36. package/lib/types/adapters/solid.d.ts +78 -0
  37. package/lib/types/adapters/solid.spec.d.ts +2 -0
  38. package/lib/types/adapters/vue.d.ts +24 -0
  39. package/lib/types/adapters/vue.spec.d.ts +2 -0
  40. package/lib/types/attrs.d.ts +102 -0
  41. package/lib/types/buildable.spec.d.ts +2 -0
  42. package/lib/types/conformance/diagnostics.d.ts +26 -2
  43. package/lib/types/conformance/index.d.ts +24 -1
  44. package/lib/types/conformance/vectors.d.mts +34 -0
  45. package/lib/types/descriptors/index.d.ts +52 -1
  46. package/lib/types/errors.d.ts +21 -0
  47. package/lib/types/generated/props.d.ts +5505 -0
  48. package/lib/types/generated/surface-data.d.mts +22 -0
  49. package/lib/types/generated/widgets.d.ts +3 -0
  50. package/lib/types/generated.spec.d.ts +4 -0
  51. package/lib/types/generator/emit-types.d.mts +54 -0
  52. package/lib/types/generator/emit.d.mts +50 -0
  53. package/lib/types/generator/gir.d.mts +164 -0
  54. package/lib/types/generator/main.d.mts +23 -0
  55. package/lib/types/generator/mini.fixture.d.mts +30 -0
  56. package/lib/types/generator/surface.d.mts +62 -0
  57. package/lib/types/generator/tsmap.d.mts +73 -0
  58. package/lib/types/generator.spec.d.ts +2 -0
  59. package/lib/types/host.d.ts +102 -1
  60. package/lib/types/index.d.ts +6 -3
  61. package/lib/types/jsx-runtime.d.ts +70 -0
  62. package/lib/types/policies.d.ts +58 -0
  63. package/lib/types/probe.d.ts +87 -0
  64. package/lib/types/props.d.ts +52 -2
  65. package/lib/types/react-jsx-runtime.d.ts +108 -0
  66. package/lib/types/registry.d.ts +1 -1
  67. package/lib/types/signals.d.ts +16 -1
  68. package/lib/types/style/errors.d.ts +6 -0
  69. package/lib/types/style/gtk-css.d.ts +24 -0
  70. package/lib/types/style/gtk-css.spec.d.ts +2 -0
  71. package/lib/types/style/gtk-props.d.ts +27 -0
  72. package/lib/types/style/gtk-props.spec.d.ts +2 -0
  73. package/lib/types/style/index.d.ts +13 -0
  74. package/lib/types/style/layout.d.ts +163 -0
  75. package/lib/types/style/layout.spec.d.ts +2 -0
  76. package/lib/types/style/paint.d.ts +53 -0
  77. package/lib/types/style/paint.spec.d.ts +2 -0
  78. package/lib/types/style/resolve.d.ts +58 -0
  79. package/lib/types/style/sheet.d.ts +40 -0
  80. package/lib/types/style/sheet.spec.d.ts +2 -0
  81. package/lib/types/style/tokens.d.ts +58 -0
  82. package/lib/types/tags.d.ts +25 -0
  83. package/lib/types/testing/gate.d.mts +25 -0
  84. package/lib/types/types.d.ts +56 -3
  85. package/lib/types/vue-components.d.ts +46 -0
  86. 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;
@@ -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>;
@@ -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). The ParamSpec knows the right answer.
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 defaultValue(spec: GObject.ParamSpec): unknown;
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
+ }
@@ -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 tag — the conformance suite walks this, so coverage is data. */
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.
@@ -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 function toSignalName(prop: string, aliases?: Readonly<Record<string, string>>): string;
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,2 @@
1
+ declare const _default: () => Promise<void>;
2
+ export default _default;
@@ -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,2 @@
1
+ declare const _default: () => Promise<void>;
2
+ export default _default;
@@ -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';