@gjsify/gtk-host 0.43.0 → 0.45.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 (63) hide show
  1. package/README.md +86 -13
  2. package/lib/esm/adapters/react.js +1 -1
  3. package/lib/esm/adapters/solid.js +1 -1
  4. package/lib/esm/conformance/diagnostics.js +2 -2
  5. package/lib/esm/conformance/index.js +2 -2
  6. package/lib/esm/descriptors/adw.js +1 -1
  7. package/lib/esm/descriptors/gtk.js +1 -1
  8. package/lib/esm/errors.js +1 -1
  9. package/lib/esm/generated/widgets.js +1 -1
  10. package/lib/esm/host.js +1 -1
  11. package/lib/esm/index.js +1 -1
  12. package/lib/esm/list/controller.js +1 -0
  13. package/lib/esm/list/index.js +1 -0
  14. package/lib/esm/list/scroll.js +1 -0
  15. package/lib/esm/policies.js +1 -1
  16. package/lib/esm/probe.js +1 -1
  17. package/lib/esm/signals.js +1 -1
  18. package/lib/esm/style/errors.js +1 -0
  19. package/lib/esm/style/gtk-css.js +1 -0
  20. package/lib/esm/style/gtk-props.js +1 -0
  21. package/lib/esm/style/index.js +1 -0
  22. package/lib/esm/style/layout.js +1 -0
  23. package/lib/esm/style/paint.js +1 -0
  24. package/lib/esm/style/resolve.js +1 -0
  25. package/lib/esm/style/sheet.js +3 -0
  26. package/lib/esm/style/tokens.js +1 -0
  27. package/lib/types/adapters/react.d.ts +59 -10
  28. package/lib/types/adapters/solid.d.ts +35 -0
  29. package/lib/types/conformance/diagnostics.d.ts +13 -3
  30. package/lib/types/conformance/index.d.ts +1 -1
  31. package/lib/types/descriptors/index.d.ts +2 -2
  32. package/lib/types/errors.d.ts +10 -0
  33. package/lib/types/generated/props.d.ts +80 -1
  34. package/lib/types/generator/emit-types.d.mts +1 -1
  35. package/lib/types/generator/gir.d.mts +36 -2
  36. package/lib/types/host.d.ts +2 -2
  37. package/lib/types/index.d.ts +1 -1
  38. package/lib/types/list/controller.d.ts +112 -0
  39. package/lib/types/list/index.d.ts +2 -0
  40. package/lib/types/list/list.spec.d.ts +2 -0
  41. package/lib/types/list/scroll.d.ts +26 -0
  42. package/lib/types/policies.d.ts +11 -0
  43. package/lib/types/probe.d.ts +80 -2
  44. package/lib/types/probe.spec.d.ts +2 -0
  45. package/lib/types/props.d.ts +7 -4
  46. package/lib/types/signals.d.ts +3 -1
  47. package/lib/types/style/errors.d.ts +6 -0
  48. package/lib/types/style/gtk-css.d.ts +24 -0
  49. package/lib/types/style/gtk-css.spec.d.ts +2 -0
  50. package/lib/types/style/gtk-props.d.ts +27 -0
  51. package/lib/types/style/gtk-props.spec.d.ts +2 -0
  52. package/lib/types/style/index.d.ts +13 -0
  53. package/lib/types/style/layout.d.ts +163 -0
  54. package/lib/types/style/layout.spec.d.ts +2 -0
  55. package/lib/types/style/paint.d.ts +53 -0
  56. package/lib/types/style/paint.spec.d.ts +2 -0
  57. package/lib/types/style/resolve.d.ts +58 -0
  58. package/lib/types/style/sheet.d.ts +40 -0
  59. package/lib/types/style/sheet.spec.d.ts +2 -0
  60. package/lib/types/style/tokens.d.ts +58 -0
  61. package/lib/types/testing/gate.d.mts +23 -0
  62. package/lib/types/types.d.ts +21 -4
  63. package/package.json +26 -12
@@ -52,6 +52,17 @@ export declare const makeDetachedContainer: () => Gtk.Widget;
52
52
  */
53
53
  export declare function unhandledPolicy(policy: never): never;
54
54
  export declare function setterSlotOf(parent: HostElement, child: HostElement): string | null;
55
+ /**
56
+ * The slots this policy fills with an ADDER, by slot name.
57
+ *
58
+ * `set_`-prefixed or not is the whole distinction, and TWO decisions turn on it,
59
+ * which is why the predicate is here once rather than spelled out at each. A
60
+ * setter-backed slot is emptied by writing `null` back through itself, so
61
+ * `policyProblems()` lets such a policy name no `remove`; and it holds one child,
62
+ * so `rotateTail` returns before touching it — a policy with no adder slot at all
63
+ * has no order to pay for, which is what `reorderMode()` reports.
64
+ */
65
+ export declare function adderSlots(policy: ChildPolicy): string[];
55
66
  /** Every one-child slot this policy has, by setter name — `single` has exactly one. */
56
67
  export declare function setterSlots(policy: ChildPolicy): string[];
57
68
  /**
@@ -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. */
@@ -13,8 +14,28 @@ export interface HostProbe<T> {
13
14
  * and the exact getters, never the host's own bookkeeping, which would agree
14
15
  * with itself while the window is wrong. Return whatever belongs in the result
15
16
  * line; the harness adds the failure list and the diagnostic count.
17
+ *
18
+ * MAY BE ASYNC, and one adapter forces it: Vue flushes render jobs on a
19
+ * microtask, so an assertion after a click has to `await nextTick()` or it reads
20
+ * the pre-patch tree. Without this the Vue showcase hand-rolled the whole
21
+ * harness, and the copy carried the pre-`describeLogRecord` collector bug with
22
+ * it — a log record with no `MESSAGE` counted as a diagnostic and then described
23
+ * as the empty string.
16
24
  */
17
- assert(ui: T, check: ProbeCheck): Record<string, unknown>;
25
+ assert(ui: T, check: ProbeCheck): Record<string, unknown> | Promise<Record<string, unknown>>;
26
+ /**
27
+ * Release what the assertions built, before the diagnostics are counted.
28
+ *
29
+ * ORDER IS THE POINT. Teardown is exactly where GTK reports a mis-parented tree
30
+ * — `Finalizing GtkLabel …, but it still has children left` arrives at finalize,
31
+ * at exit 0 (ADR 0027 § Context). A probe that counts diagnostics and THEN tears
32
+ * down cannot see the one class of defect that only surfaces there, which is
33
+ * what both hand-written probes did.
34
+ *
35
+ * Optional because a probe that owns nothing has nothing to release; the
36
+ * harness's own `build` result is reachable only from here.
37
+ */
38
+ teardown?(ui: T): void;
18
39
  /** Prefix of the machine-readable result line. Default `PROBE`. */
19
40
  label?: string;
20
41
  }
@@ -34,6 +55,15 @@ export declare function probeEnabled(): boolean;
34
55
  /**
35
56
  * Run the showcase's assertions once and return the process exit code.
36
57
  *
58
+ * **The probe always builds HEADLESS, in both paths.** It is handed `null` rather
59
+ * than the `GApplication`, for two reasons that point the same way. It makes the two
60
+ * paths return the same verdict about the same tree — a probe whose GUI run differs
61
+ * from its headless run is two probes. And it keeps the GUI path from constructing
62
+ * and (now that `teardown` exists) destroying an `Adw.ApplicationWindow` INSIDE
63
+ * `activate`, which is the exact neighbourhood of the segfault recorded on
64
+ * `runHostProbeApp` below. Nothing a probe asserts needs an application; `present`
65
+ * gets the real one.
66
+ *
37
67
  * The diagnostics gate is reset first and asserted last, and both halves are the
38
68
  * harness's rather than the showcase's. Reset, because in the GUI path this runs
39
69
  * from `activate` — AFTER Adw startup, where a session-bus, portal, theme or a11y
@@ -42,7 +72,7 @@ export declare function probeEnabled(): boolean;
42
72
  * failure mode is exit 0: a mis-parented widget floods `Gtk-WARNING` and the
43
73
  * process still succeeds.
44
74
  */
45
- export declare function runHostProbe<T>(probe: HostProbe<T>, app?: Adw.Application | null): number;
75
+ export declare function runHostProbe<T>(probe: HostProbe<T>): Promise<number>;
46
76
  /**
47
77
  * The whole `main` of a gtk-host showcase.
48
78
  *
@@ -56,3 +86,51 @@ export declare function runHostProbe<T>(probe: HostProbe<T>, app?: Adw.Applicati
56
86
  * and hangs a view load on its spinner (the class `@gjsify/adwaita-app` documents).
57
87
  */
58
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;
@@ -0,0 +1,2 @@
1
+ declare const _default: () => Promise<void>;
2
+ export default _default;
@@ -53,10 +53,13 @@ export declare function coerce(spec: GObject.ParamSpec, value: unknown, tag: str
53
53
  * leaves behind, not what the ParamSpec declares.
54
54
  *
55
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 / Adw 1.10 across the 26 shipped
57
- * descriptors: 953 scalar properties are both readable and writable, and
58
- * **104 of them disagree** — 78 once construct-only `css-name` is set aside.
59
- * Twelve property names carry it, four of them behavioural:
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:
60
63
  *
61
64
  * GtkWindow.visible spec=true constructed=false
62
65
  * AdwActionRow.activatable spec=true constructed=false
@@ -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;
@@ -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';
@@ -0,0 +1,163 @@
1
+ import { type StyleTokens } from './tokens.js';
2
+ /** React Native's own `alignItems`/`alignSelf` vocabulary. */
3
+ export type AlignValue = 'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline';
4
+ /** React Native's own `justifyContent` vocabulary. */
5
+ export type JustifyValue = 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around' | 'space-evenly';
6
+ /** The four physical edges an absolutely positioned element offsets from. */
7
+ export type Edge = 'top' | 'right' | 'bottom' | 'left';
8
+ /**
9
+ * The properties the layout half understands, in React Native's spelling.
10
+ *
11
+ * The VALUES are React Native's too — `alignItems: 'flex-start'`, not `'start'` —
12
+ * and that is the point of ADR 0032 § 4 rather than a detail. A class list and a
13
+ * `style={{…}}` object are one information set arriving by two routes, and 48 of
14
+ * the measured application's 57 style objects carry exactly these names and values.
15
+ * Normalising the classes into a third spelling would put a translation table
16
+ * between the two front ends and give the partition two truths to keep in step.
17
+ */
18
+ export interface LayoutProps {
19
+ marginTop?: string;
20
+ marginRight?: string;
21
+ marginBottom?: string;
22
+ marginLeft?: string;
23
+ marginStart?: string;
24
+ marginEnd?: string;
25
+ paddingTop?: string;
26
+ paddingRight?: string;
27
+ paddingBottom?: string;
28
+ paddingLeft?: string;
29
+ flexDirection?: 'row' | 'column';
30
+ flexGrow?: string;
31
+ alignItems?: AlignValue;
32
+ justifyContent?: JustifyValue;
33
+ alignSelf?: AlignValue;
34
+ gap?: string;
35
+ columnGap?: string;
36
+ rowGap?: string;
37
+ width?: string;
38
+ height?: string;
39
+ overflow?: 'visible' | 'hidden' | 'scroll';
40
+ display?: 'flex' | 'none';
41
+ position?: 'relative' | 'absolute';
42
+ top?: string;
43
+ right?: string;
44
+ bottom?: string;
45
+ left?: string;
46
+ textAlign?: 'left' | 'center' | 'right' | 'justify';
47
+ }
48
+ /**
49
+ * What L1 could not answer, for L2 to resolve against the shadow tree.
50
+ *
51
+ * Every field here is a case where the same input compiles to DIFFERENT GTK
52
+ * depending on something no per-element function can see. Nothing is an intent for
53
+ * being hard: `overflow-hidden` needs the parent no more than `bg-red` does, and it
54
+ * is a widget property below rather than a field here.
55
+ */
56
+ export interface LayoutIntent {
57
+ /**
58
+ * `flex-1` — `hexpand` on a row, `vexpand` on a column.
59
+ *
60
+ * ADR 0032 § 6, and the reason the intent mechanism exists at all: the axis is
61
+ * the PARENT's orientation, which an element does not know about itself.
62
+ */
63
+ readonly expand?: 'main-axis';
64
+ /**
65
+ * `items-*` — the cross-axis alignment of every CHILD.
66
+ *
67
+ * Two things missing at once. GTK has no `align-items`: the alignment lives on
68
+ * each child as `halign`/`valign`, so L2 must walk children this function has
69
+ * never seen. And WHICH of the two it is depends on this element's own
70
+ * orientation, which is `Gtk.Box`'s default when no `flex-row`/`flex-col` says
71
+ * otherwise — and the defaults disagree (`Gtk.Box` is horizontal, a React
72
+ * Native `View` is a column), so there is not even a safe fallback to guess.
73
+ */
74
+ readonly alignChildren?: AlignValue;
75
+ /**
76
+ * `justify-*` — main-axis distribution.
77
+ *
78
+ * `space-between` is a WIDGET CHOICE, not a property: `Gtk.CenterBox` for two or
79
+ * three children and a named refusal beyond that (ADR 0032 § 6). The child count
80
+ * decides, and L1 has no children. The other three are the box's own
81
+ * `halign`/`valign`, which needs the orientation for the same reason
82
+ * {@link LayoutIntent.alignChildren} does.
83
+ */
84
+ readonly distribute?: JustifyValue;
85
+ /**
86
+ * `self-*` — this element's own cross-axis alignment.
87
+ *
88
+ * `halign` or `valign` by the PARENT's orientation. Same shape as
89
+ * {@link LayoutIntent.expand}, same reason, one axis over.
90
+ */
91
+ readonly alignSelf?: AlignValue;
92
+ /**
93
+ * `gap-x-*` / `gap-y-*` — a spacing that is only valid on one orientation.
94
+ *
95
+ * `Gtk.Box` has ONE `spacing` (measured), so an axis-qualified gap is either
96
+ * that spacing or nothing at all, and which it is depends on the orientation
97
+ * L1 cannot see. Refusing the spelling outright was the alternative and is
98
+ * worse: `gap-x-2` on a row is ordinary, unambiguous authoring, and L2 answers
99
+ * it exactly.
100
+ */
101
+ readonly axisSpacing?: {
102
+ readonly axis: 'horizontal' | 'vertical';
103
+ readonly pixels: number;
104
+ };
105
+ /**
106
+ * `absolute` / `relative` / `inset-*` / `top-*` — the parent must be a `Gtk.Overlay`.
107
+ *
108
+ * A widget cannot make its own parent a different class, so the child's
109
+ * `absolute` is a request L2 executes on the PARENT. The `context` role is
110
+ * `relative`'s: it sets nothing (an overlay establishes the context by being
111
+ * one) but it is carried rather than dropped, because it is the half of the
112
+ * pair L2 can hold the other half against — an `absolute` child under a parent
113
+ * that never declared `relative` is a real authoring bug, and a dropped
114
+ * `relative` would make it undetectable.
115
+ */
116
+ readonly overlay?: OverlayIntent;
117
+ /**
118
+ * `text-*` — only a text widget aligns text.
119
+ *
120
+ * `xalign` and `justify` are `Gtk.Label`'s; `Gtk.Box` has neither (measured).
121
+ * A `<View className="text-center">` wrapping a `<Text>` is ordinary React
122
+ * Native, and on GTK the property has to travel to the label, which is a tree
123
+ * walk and therefore L2's.
124
+ */
125
+ readonly textAlign?: 'left' | 'center' | 'right' | 'justify';
126
+ }
127
+ export type OverlayIntent = {
128
+ readonly role: 'context';
129
+ } | {
130
+ readonly role: 'child';
131
+ readonly edges: Readonly<Partial<Record<Edge, number>>>;
132
+ };
133
+ /** What {@link partitionLayout} contributes to the partition. */
134
+ export interface LayoutPartition {
135
+ readonly css: readonly string[];
136
+ readonly props: Readonly<Record<string, unknown>>;
137
+ readonly intent: LayoutIntent;
138
+ }
139
+ /**
140
+ * One utility class → the layout properties it sets, or `null` for "not mine".
141
+ *
142
+ * `null` rather than a throw is what lets `resolve.ts` try both halves without
143
+ * either of them knowing the other exists. A family this half DOES own with a bad
144
+ * token still throws, and that distinction is the whole point: `flex-2` is a
145
+ * refusal with a reason, `wibble-3` is an unknown name.
146
+ */
147
+ export declare function resolveLayoutUtility(utility: string, tokens: StyleTokens): LayoutProps | null;
148
+ /**
149
+ * The {@link LayoutProps} keys, for the dispatch's ownership test.
150
+ *
151
+ * DERIVED from the route table rather than listed: a second list is a second thing
152
+ * to keep true, and the one that drifts is the one that decides whether a property
153
+ * is routed at all.
154
+ */
155
+ export declare const LAYOUT_PROPERTIES: ReadonlySet<string>;
156
+ /**
157
+ * Layout properties → `{ css, props, intent }`.
158
+ *
159
+ * The two cross-key refusals run first, because both are cases where every
160
+ * individual property is fine and the COMBINATION is what GTK cannot express.
161
+ * They are the reason this is not a per-property `map`.
162
+ */
163
+ export declare function partitionLayout(props: LayoutProps): LayoutPartition;
@@ -0,0 +1,2 @@
1
+ declare const _default: () => Promise<void>;
2
+ export default _default;
@@ -0,0 +1,53 @@
1
+ import { type StyleTokens } from './tokens.js';
2
+ /** The properties the paint half understands, in React Native's spelling. */
3
+ export interface PaintProps {
4
+ backgroundColor?: string;
5
+ color?: string;
6
+ opacity?: string;
7
+ borderRadius?: string;
8
+ borderTopLeftRadius?: string;
9
+ borderTopRightRadius?: string;
10
+ borderBottomLeftRadius?: string;
11
+ borderBottomRightRadius?: string;
12
+ borderWidth?: string;
13
+ borderTopWidth?: string;
14
+ borderRightWidth?: string;
15
+ borderBottomWidth?: string;
16
+ borderLeftWidth?: string;
17
+ borderColor?: string;
18
+ fontSize?: string;
19
+ fontWeight?: string;
20
+ fontFamily?: string;
21
+ fontStyle?: string;
22
+ letterSpacing?: string;
23
+ lineHeight?: string;
24
+ textDecorationLine?: string;
25
+ textTransform?: string;
26
+ }
27
+ /**
28
+ * React Native property name → the GTK CSS property it becomes.
29
+ *
30
+ * Exported so `paint.spec.ts` can assert the invariant this table rests on — that
31
+ * every value is a property GTK measurably accepts — directly, rather than through
32
+ * `partition`'s per-call guard, which no input can reach while the table is right.
33
+ */
34
+ export declare const CSS_NAME: Readonly<Record<keyof PaintProps, string>>;
35
+ /**
36
+ * One utility class → the paint properties it sets, or `null` for "not mine".
37
+ *
38
+ * Returns a partial record rather than mutating, so a caller can see what a single
39
+ * class contributed — which is what makes the last-wins rule testable.
40
+ */
41
+ export declare function resolvePaintUtility(utility: string, tokens: StyleTokens): PaintProps | null;
42
+ /** The {@link PaintProps} keys, for the dispatch's ownership test. */
43
+ export declare const PAINT_PROPERTIES: ReadonlySet<string>;
44
+ /**
45
+ * Paint properties → GTK CSS declarations.
46
+ *
47
+ * Every emitted name is checked against the MEASURED accepted set rather than
48
+ * trusted: a property this table maps but GTK does not accept would be dropped by
49
+ * GTK's parser with no diagnostic, which is the exact silence the whole partition
50
+ * exists to avoid. The check is cheap and it has caught the one property that looks
51
+ * like paint and is not.
52
+ */
53
+ export declare function partitionPaint(props: PaintProps): readonly string[];
@@ -0,0 +1,2 @@
1
+ declare const _default: () => Promise<void>;
2
+ export default _default;
@@ -0,0 +1,58 @@
1
+ import { type LayoutIntent, type LayoutProps } from './layout.js';
2
+ import { type PaintProps } from './paint.js';
3
+ import type { StyleTokens } from './tokens.js';
4
+ /** One normalised property set, in React Native's spelling (ADR 0032 § 4). */
5
+ export type StyleProps = PaintProps & LayoutProps;
6
+ /** What the partition hands back — GTK's three destinations, all of them. */
7
+ export interface Partitioned {
8
+ /** GTK CSS declarations, `property: value`, without the braces. */
9
+ readonly css: readonly string[];
10
+ /**
11
+ * Widget properties in GTK's own spelling, with values the host will apply.
12
+ *
13
+ * The values are what `applyProps` coerces through the ParamSpec — a nick for
14
+ * an enum, a boolean for a boolean, an integer for a `gint`. NOT what a raw
15
+ * GJS setter accepts: `box.orientation = 'vertical'` keeps HORIZONTAL with no
16
+ * diagnostic at all (measured, gjs 1.88.1), which is the whole reason the host
17
+ * has a coercion step.
18
+ */
19
+ readonly props: Readonly<Record<string, unknown>>;
20
+ /** What only the shadow tree can answer, for L2 at attach time. */
21
+ readonly intent: LayoutIntent;
22
+ }
23
+ /**
24
+ * One utility class → the properties it sets.
25
+ *
26
+ * Paint runs first, and the order is not arbitrary: the paint families are closed
27
+ * sets of scale names, so its `null` is a cheap "no such family here", while the
28
+ * layout half owns the open-ended spellings (`gap-x-4`, `w-1/2`) whose parsing is
29
+ * where a wrong claim would be expensive.
30
+ */
31
+ export declare function resolveUtility(utility: string, tokens: StyleTokens): StyleProps;
32
+ /**
33
+ * A class list → the properties it sets, later classes winning.
34
+ *
35
+ * Last-wins is CSS's own rule for equal specificity and the one authors expect from
36
+ * a utility vocabulary. It is done HERE, on the property record, rather than by
37
+ * emitting two declarations and letting GTK resolve them — GTK resolves equal
38
+ * specificity by SHEET ORDER, not by the order of names in `css-classes`, so
39
+ * "the later class wins" would be false the moment two generated classes met.
40
+ *
41
+ * It is also why `m-*` puts its horizontal half in the same KEYS as `mx-*`: two
42
+ * spellings of one edge only resolve by last-wins while they are one key.
43
+ */
44
+ export declare function resolveUtilities(utilities: readonly string[], tokens: StyleTokens): StyleProps;
45
+ /**
46
+ * Properties → `{ css, props, intent }`.
47
+ *
48
+ * Splits the record by ownership and hands each half to its own partition, because
49
+ * the layout half's refusals are CROSS-KEY (a physical and a logical margin
50
+ * together, two gap spellings at once) and it can only see them with its whole
51
+ * share in hand.
52
+ *
53
+ * A property NEITHER half routes throws rather than being skipped. That is the same
54
+ * rule as an unknown utility, one layer down, and it is the one that catches a
55
+ * `style={{…}}` object carrying a React Native property nobody has mapped yet —
56
+ * the front end with no class name to check.
57
+ */
58
+ export declare function partition(props: StyleProps): Partitioned;
@@ -0,0 +1,40 @@
1
+ import Gdk from 'gi://Gdk?version=4.0';
2
+ /** A variant this sheet knows how to express, and the pseudo-class it becomes. */
3
+ export declare const VARIANT_PSEUDO: Readonly<Record<string, string>>;
4
+ /** A rule GTK refused, or one that would have poisoned the document. */
5
+ export declare class StyleSheetError extends Error {
6
+ readonly name = "StyleSheetError";
7
+ constructor(message: string);
8
+ }
9
+ export interface StyleSheetOptions {
10
+ /**
11
+ * Where the provider is installed. Omitted means the default display — the
12
+ * right answer for an application and the wrong one for a test, which is why
13
+ * it is injectable at all.
14
+ */
15
+ readonly display?: Gdk.Display | null;
16
+ /** Provider priority. Defaults to `STYLE_PROVIDER_PRIORITY_APPLICATION`. */
17
+ readonly priority?: number;
18
+ }
19
+ export declare class StyleSheet {
20
+ #private;
21
+ constructor(options?: StyleSheetOptions);
22
+ /**
23
+ * Register `declarations` (and optional variants) and return their class name.
24
+ *
25
+ * Idempotent: the same declarations always yield the same name and the document
26
+ * gains nothing the second time.
27
+ */
28
+ classFor(declarations: readonly string[], variants?: Readonly<Record<string, readonly string[]>>): string;
29
+ /** The document as GTK sees it. Exposed because a test that cannot read it proves nothing. */
30
+ toString(): string;
31
+ /** How many distinct rules the document holds. */
32
+ get size(): number;
33
+ /**
34
+ * Load the document now, rather than on the next microtask.
35
+ *
36
+ * A test has no microtask checkpoint it can rely on, and an application that is
37
+ * about to present a window wants the styles already in place.
38
+ */
39
+ flush(): void;
40
+ }
@@ -0,0 +1,2 @@
1
+ declare const _default: () => Promise<void>;
2
+ export default _default;
@@ -0,0 +1,58 @@
1
+ /** A scale: token name → the CSS value it stands for. */
2
+ export type Scale = Readonly<Record<string, string>>;
3
+ /**
4
+ * Every scale the partition consults.
5
+ *
6
+ * All optional: a project that has no `letterSpacing` scale simply has no
7
+ * `tracking-*` utilities, and asking for one is an error naming the empty scale
8
+ * rather than a silent no-op.
9
+ */
10
+ export interface StyleTokens {
11
+ /**
12
+ * The one scale `m-*`, `p-*`, `gap-*`, `inset-*` and the edge utilities read.
13
+ *
14
+ * ONE scale for all of them because that is what a token file actually holds —
15
+ * `mt-2xs` and `gap-2xs` name the same 2xs — and splitting it would ask a
16
+ * project to repeat itself once per family.
17
+ *
18
+ * A value only reaches the WIDGET-PROPERTY channel if it is a pixel length:
19
+ * `margin-top` is a `gint` of device pixels (measured, `gtk-props.ts`) and GTK
20
+ * exposes no unit conversion there. A scale spelled in `rem` therefore still
21
+ * works for padding, which is CSS-only, and is a named error on a margin rather
22
+ * than a silently rounded one.
23
+ */
24
+ readonly spacing?: Scale;
25
+ /** `w-<token>`, falling back to {@link StyleTokens.spacing} — Tailwind's own layering. */
26
+ readonly width?: Scale;
27
+ /** `h-<token>`, falling back to {@link StyleTokens.spacing}. */
28
+ readonly height?: Scale;
29
+ readonly colors?: Scale;
30
+ readonly borderRadius?: Scale;
31
+ readonly borderWidth?: Scale;
32
+ readonly fontSize?: Scale;
33
+ readonly fontWeight?: Scale;
34
+ readonly fontFamily?: Scale;
35
+ readonly letterSpacing?: Scale;
36
+ readonly lineHeight?: Scale;
37
+ readonly opacity?: Scale;
38
+ }
39
+ /**
40
+ * A minimal set, for tests and for a consumer who has no token file yet.
41
+ *
42
+ * Deliberately SMALL rather than a copy of Tailwind's defaults. A large default
43
+ * scale would let a project's typo resolve against a value nobody chose, which is
44
+ * the failure the declared-vocabulary rule exists to prevent — and it would make
45
+ * "the values come from the project" false in the common case.
46
+ */
47
+ export declare const MINIMAL_TOKENS: StyleTokens;
48
+ /** A token's value, or `undefined` when the scale is absent or does not carry it. */
49
+ export declare const lookupToken: (scale: Scale | undefined, token: string) => string | undefined;
50
+ /**
51
+ * A token's value, or a named error that lists what the scale DOES hold.
52
+ *
53
+ * Both halves of the partition read scales, so the reader lives with the scales
54
+ * rather than in whichever half needed it first. Listing the known keys is the
55
+ * whole value of the message: "not in the borderRadius scale" turns a typo into a
56
+ * search, "Known: full, lg, md, none, sm" turns it into a one-line fix.
57
+ */
58
+ export declare function requireToken(scale: Scale | undefined, token: string, utility: string, scaleName: string): string;