@gjsify/gtk-host 0.45.0 → 0.47.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 (53) hide show
  1. package/lib/esm/conformance/diagnostics.js +1 -1
  2. package/lib/esm/conformance/index.js +1 -1
  3. package/lib/esm/descriptors/adw.js +1 -1
  4. package/lib/esm/font-dir.js +1 -0
  5. package/lib/esm/fonts.js +1 -0
  6. package/lib/esm/generated/widgets.js +1 -1
  7. package/lib/esm/host.js +1 -1
  8. package/lib/esm/index.js +1 -1
  9. package/lib/esm/list/controller.js +1 -1
  10. package/lib/esm/policies.js +1 -1
  11. package/lib/esm/probe.js +1 -1
  12. package/lib/esm/props.js +1 -1
  13. package/lib/esm/registry.js +1 -1
  14. package/lib/esm/style/document.js +1 -0
  15. package/lib/esm/style/gtk-props.js +1 -1
  16. package/lib/esm/style/index.js +1 -1
  17. package/lib/esm/style/layout.js +1 -1
  18. package/lib/esm/style/paint.js +1 -1
  19. package/lib/esm/style/sheet.js +3 -3
  20. package/lib/esm/style/theme.js +3 -0
  21. package/lib/esm/style/tokens.js +1 -1
  22. package/lib/types/descriptors/index.d.ts +1 -1
  23. package/lib/types/font-dir.d.ts +42 -0
  24. package/lib/types/font-dir.spec.d.ts +2 -0
  25. package/lib/types/fonts.d.ts +64 -0
  26. package/lib/types/fonts.spec.d.ts +2 -0
  27. package/lib/types/generated/props.d.ts +611 -822
  28. package/lib/types/generated/widgets.d.ts +1 -1
  29. package/lib/types/generator/emit-types.d.mts +1 -1
  30. package/lib/types/generator/emit.d.mts +16 -6
  31. package/lib/types/generator/girs-vocabulary.d.mts +45 -0
  32. package/lib/types/generator/main.d.mts +16 -8
  33. package/lib/types/generator/model.d.mts +95 -0
  34. package/lib/types/generator/names.d.mts +19 -0
  35. package/lib/types/generator/vocabulary-dts.d.mts +47 -0
  36. package/lib/types/host.d.ts +1 -1
  37. package/lib/types/policies.d.ts +7 -1
  38. package/lib/types/props.d.ts +13 -1
  39. package/lib/types/registry.d.ts +1 -1
  40. package/lib/types/style/document.d.ts +22 -0
  41. package/lib/types/style/index.d.ts +6 -3
  42. package/lib/types/style/layout.d.ts +34 -0
  43. package/lib/types/style/sheet.d.ts +0 -5
  44. package/lib/types/style/theme.d.ts +158 -0
  45. package/lib/types/style/theme.spec.d.ts +2 -0
  46. package/lib/types/style/tokens.d.ts +76 -0
  47. package/lib/types/style/tokens.spec.d.ts +2 -0
  48. package/lib/types/types.d.ts +63 -0
  49. package/package.json +19 -15
  50. package/lib/types/generator/gir.d.mts +0 -190
  51. package/lib/types/generator/mini.fixture.d.mts +0 -30
  52. package/lib/types/generator/surface.d.mts +0 -62
  53. package/lib/types/generator/tsmap.d.mts +0 -73
@@ -1,3 +1,3 @@
1
1
  import type { GeneratedWidget } from '../types.js';
2
- export declare const GENERATED_PROVENANCE: "Gtk-4.0 Adw-1";
2
+ export declare const GENERATED_PROVENANCE: "Gtk-4.0/4.23.3 Adw-1/1.10.0";
3
3
  export declare const GENERATED_WIDGETS: readonly GeneratedWidget[];
@@ -23,7 +23,7 @@
23
23
  * arrives as `unknown` so using it fails (TS2345). A generated surface that
24
24
  * typed handlers loosely would break every handler that names its parameter.
25
25
  */
26
- import type { SurfaceModel } from './surface.mjs';
26
+ import type { SurfaceModel } from './model.mjs';
27
27
  /**
28
28
  * Volar's own resolution rule, reproduced so the generator can SEE the gap.
29
29
  *
@@ -17,8 +17,7 @@
17
17
  * answer. The machine-INDEPENDENT check is the runtime one that already exists —
18
18
  * `descriptorProblems()` against the installed typelib.
19
19
  */
20
- import type { ChildPolicy, WidgetDescriptor } from '../types.js';
21
- import type { GirClass, GirNamespace } from './gir.mjs';
20
+ import type { WidgetDescriptor } from '../types.js';
22
21
  /**
23
22
  * The `gi://` import a generated table needs, per GIR namespace.
24
23
  *
@@ -29,12 +28,23 @@ import type { GirClass, GirNamespace } from './gir.mjs';
29
28
  * trust.
30
29
  */
31
30
  export declare const GJS_MODULES: Readonly<Record<string, string>>;
31
+ /** What a widget row needs. Three fields, not a GIR class — see `girs-vocabulary.mts`. */
32
+ export interface WidgetRow {
33
+ readonly gtype: string;
34
+ readonly namespace: string;
35
+ readonly name: string;
36
+ }
32
37
  export interface EmitInput {
33
- readonly namespaces: readonly GirNamespace[];
34
- readonly widgets: readonly GirClass[];
38
+ /** The provenance line, verbatim: `Gtk-4.0/4.23.3 Adw-1/1.8.0`. */
39
+ readonly provenance: string;
40
+ readonly widgets: readonly WidgetRow[];
41
+ /**
42
+ * Every GType the vocabulary knows, widgets and bases alike. G1 asks whether a curated
43
+ * row names something that exists, and a widget-only set would report every curated
44
+ * base as missing.
45
+ */
46
+ readonly knownGTypes: ReadonlySet<string>;
35
47
  readonly curated: readonly WidgetDescriptor[];
36
- /** `methodsOf` from the conformance module — one extractor, not a second copy. */
37
- readonly methodsOf: (policy: ChildPolicy) => string[];
38
48
  /** GIR namespace -> `gi://` import. Defaults to the GTK/Adwaita pair. */
39
49
  readonly modules?: Readonly<Record<string, string>>;
40
50
  }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Read the widget vocabulary from `@girs/<ns>/vocabulary` and build the emitter's model.
3
+ *
4
+ * WHY THIS REPLACED A GIR READER. This package used to parse the `.gir` XML itself, which
5
+ * made it the SECOND reader of a format ts-for-gir already reads — and two readers of one
6
+ * format are two truths that drift apart silently. ADR 0029 moved the vocabulary into
7
+ * `@girs/*` so there is one. What stays here is the DIALECT: kebab tags, the camelCase
8
+ * second spelling, `on<Signal>` prop names, Vue's Volar aliases. None of that is in the
9
+ * vocabulary and none of it belongs there, as its own header says.
10
+ *
11
+ * WHY IT READS BOTH HALVES. The runtime `.js` carries the facts as values (`OWN_PROPS`,
12
+ * `DECLS`, `OWN_SIGNALS`, `ENUM_NICKS`), which is what a check can compare against a live
13
+ * typelib. The `.d.ts` carries the rendered TypeScript for each property, which no amount
14
+ * of runtime data can reconstruct: `GtkBaselinePositionNick | Gtk.BaselinePosition`
15
+ * depends on that file's own imports. So the types come from the declarations and the
16
+ * facts come from the values, and neither is re-derived from the other.
17
+ *
18
+ * The `.d.ts` half is READ in `vocabulary-dts.mts`, which touches no file and so
19
+ * imports no `gi://` — that is what lets `generator.spec.ts` pin its regexes against
20
+ * literal fixtures instead of against whichever `@girs` happens to be installed.
21
+ */
22
+ import type { SurfaceModel } from './model.mjs';
23
+ /** The three fields `emit-types.mts` reads off a widget. Not a GIR class any more. */
24
+ export interface WidgetRef {
25
+ readonly gtype: string;
26
+ readonly namespace: string;
27
+ readonly name: string;
28
+ }
29
+ export interface VocabularySource {
30
+ /** Import name, e.g. `gtk-4.0`. */
31
+ readonly pkg: string;
32
+ /** GType prefix, e.g. `Gtk`. */
33
+ readonly prefix: string;
34
+ }
35
+ /**
36
+ * Load the vocabulary packages and build the model the emitters already consume.
37
+ *
38
+ * `dir` is the `node_modules/@girs` root; the caller resolves it, because a generator
39
+ * should not guess where its own dependencies live.
40
+ */
41
+ export declare function buildFromVocabulary(dir: string, sources: readonly VocabularySource[]): Promise<{
42
+ model: SurfaceModel;
43
+ widgets: WidgetRef[];
44
+ provenance: string;
45
+ }>;
@@ -1,15 +1,23 @@
1
1
  /**
2
2
  * The generator CLI.
3
3
  *
4
- * gjsify run generate -- [--gir-dir DIR]... [--out DIR]
4
+ * gjsify run generate -- [--girs-dir DIR] [--out DIR]
5
5
  *
6
- * WHY THE GIR PATH IS AN ARGUMENT AND NOT A DEPENDENCY. The GIR files are not in
7
- * this repository and should not be: `Gtk-4.0.gir` alone is 6.2 MB, they are
8
- * distro artefacts, and four different GTK versions sit on the maintainer
9
- * workstation. So the ARTEFACT is committed (ADR 0028 § Implementation) and the
10
- * input is located at generation time — from `--gir-dir`, from `GJSIFY_GIR_DIR`,
11
- * or from the search list below. A fresh clone builds, checks, packs and tests
12
- * with no GIR present at all; only regenerating needs one.
6
+ * WHERE THE VOCABULARY COMES FROM. The input used to be GIR XML: distro artefacts
7
+ * that are not in this repository, 6.2 MB for `Gtk-4.0.gir` alone, with four GTK
8
+ * versions on the maintainer workstation and no way to know which one a build saw.
9
+ * It is now the `@girs/<ns>/vocabulary` subpath (ADR 0029), which is an ordinary
10
+ * dependency, resolved like any other. That closes the provenance question the old
11
+ * route could only answer by convention: each vocabulary states the namespace,
12
+ * version and library version it was generated from, and this generator copies that
13
+ * into the artefact header instead of naming the files it happened to read.
14
+ *
15
+ * `--girs-dir` stays an argument so a locally built `@girs` can be generated against
16
+ * before it is published. Without it the directory is found by walking up from the
17
+ * working directory, which is what makes `npm run generate` work from the package.
18
+ *
19
+ * The ARTEFACT remains committed (ADR 0028 § Implementation): a fresh clone builds,
20
+ * checks, packs and tests without regenerating anything.
13
21
  *
14
22
  * THERE IS NO `--check` MODE, and the attempt to add one is worth recording: the
15
23
  * `generate` script pipes the output through `gjsify format`, which reflows it
@@ -0,0 +1,95 @@
1
+ /**
2
+ * The declaration graph the type surfaces are emitted from — the shape only.
3
+ *
4
+ * ONE INTERFACE PER DECLARATION, carrying its OWN members and extending its bases —
5
+ * not one flat interface per widget. The measurement decides it: the concrete widgets
6
+ * have thousands of writable property slots between them and a few hundred distinct
7
+ * property names. Flattening would emit the same `visible?: boolean` once per widget;
8
+ * mirroring the inheritance the vocabulary reports emits it once, on `GtkWidgetProps`,
9
+ * and the diff of a GTK update then shows what actually changed.
10
+ *
11
+ * WHO FILLS IT. `girs-vocabulary.mts`, from `@girs/<ns>/vocabulary`. This module used
12
+ * to hold a `buildSurface()` that filled the same shape from GIR XML this package
13
+ * parsed itself; ADR 0029 moved the vocabulary into `@girs/*` so there is one reader
14
+ * of that format instead of two. Only the shape survived, which is why the file is
15
+ * `model.mts` and no longer `surface.mts`: `surface` now names the `@girs` subpath.
16
+ */
17
+ import type { WidgetRow } from './emit.mjs';
18
+ export interface PropMember {
19
+ readonly kebab: string;
20
+ readonly camel: string;
21
+ readonly ts: string;
22
+ /**
23
+ * The hover blurb, from the JSDoc above the property in the vocabulary's `.d.ts`.
24
+ *
25
+ * The typelib strips documentation by design — which is why gi-docgen reads the
26
+ * GIR — and hover text is what a published type surface is FOR (ADR 0028 § 6). So
27
+ * the doc travels with the rendered type, out of the half of the vocabulary that
28
+ * can carry it; the runtime half is values, and a value cannot hold a comment.
29
+ */
30
+ readonly doc?: string;
31
+ readonly deprecated: boolean;
32
+ readonly since?: string;
33
+ }
34
+ export interface SignalMember {
35
+ readonly signal: string;
36
+ readonly prop: string;
37
+ /** Already rendered — `Gtk.ListBox.SignalSignatures['row-activated']`. */
38
+ readonly ts: string;
39
+ readonly doc?: string;
40
+ readonly deprecated: boolean;
41
+ readonly since?: string;
42
+ }
43
+ export interface Declaration {
44
+ /** Namespace-qualified — `Gtk.Box`. The graph is keyed on this, the way GIR references. */
45
+ readonly key: string;
46
+ readonly gtype: string;
47
+ readonly kind: 'class' | 'interface';
48
+ /** `GtkBoxProps`. */
49
+ readonly iface: string;
50
+ readonly bases: readonly string[];
51
+ readonly props: readonly PropMember[];
52
+ readonly signals: readonly SignalMember[];
53
+ readonly doc?: string;
54
+ /**
55
+ * The library release this TYPE arrived in, where GIR states one.
56
+ *
57
+ * Distinct from a member's `since`: it answers "does the installed library have
58
+ * this class at all", which is the question a bare `ctor()` returning `undefined`
59
+ * used to ask by crashing. Only about 11% of GIR classes carry a `version`, so an
60
+ * absent value means "not stated", never "has always existed".
61
+ */
62
+ readonly since?: string;
63
+ }
64
+ export interface SurfaceModel {
65
+ /**
66
+ * The widget rows, sorted by GType name.
67
+ *
68
+ * The same three fields the table emitter takes, so the type comes from there
69
+ * rather than being restated — a second spelling of a row is a second thing to
70
+ * keep in step with `girs-vocabulary.mts`, which fills both.
71
+ */
72
+ readonly widgets: readonly WidgetRow[];
73
+ readonly declarations: ReadonlyMap<string, Declaration>;
74
+ /** Widget GType -> the GTypes of every declaration its members come from, self first. */
75
+ readonly closure: ReadonlyMap<string, readonly string[]>;
76
+ /** Enum GType -> nicks, for the emitted aliases and for the runtime nick check. */
77
+ readonly enumNicks: ReadonlyMap<string, readonly string[]>;
78
+ readonly namespacesUsed: ReadonlySet<string>;
79
+ /** Namespace -> the `@girs` package that types it, so the emitter needs no second source. */
80
+ readonly packages: Readonly<Record<string, string>>;
81
+ /**
82
+ * Base -> members it must not contribute, because a nearer declaration disagrees.
83
+ *
84
+ * EMPTY TODAY, AND NOT DEFENSIVE MACHINERY. TypeScript requires a multiply
85
+ * inherited member to be IDENTICAL in every base — `string` and `string | null`
86
+ * are not — and GTK's interfaces do redeclare class properties, so a base that
87
+ * loses a member has to be emitted as `Omit<Base, 'name'>`: a local redeclaration
88
+ * does NOT repair incompatible bases, it turns one error into another. The GIR
89
+ * route computed those conflicts here; the published vocabulary resolves them
90
+ * upstream, so the map now arrives empty. It stays because `emit-types.mts`
91
+ * renders `Omit<>` from it, and a vocabulary that reintroduces a conflict needs a
92
+ * way to say so — the alternative is a surface that does not compile.
93
+ */
94
+ readonly omissions: ReadonlyMap<string, ReadonlyMap<string, readonly string[]>>;
95
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The two name transforms this package's DIALECT owns.
3
+ *
4
+ * Everything else that used to live here — the GIR-type-to-TypeScript mapper, the
5
+ * enum-nick unions, the `@girs` package map — moved into `@girs/<ns>/vocabulary`
6
+ * with ADR 0029, which renders each property's type in its own `.d.ts` and ships
7
+ * the nicks as data. What no vocabulary can answer is how a FRAMEWORK spells a
8
+ * member, because every framework spells it differently; that is dialect, it stays
9
+ * here, and it is why this file is `names.mts` and no longer `tsmap.mts`.
10
+ *
11
+ * Both are also read by `generated.spec.ts`, which runs them against the host's own
12
+ * inverse (`toSignalName`) over every generated name. Two independent
13
+ * implementations checked against each other is the point: nothing made them agree,
14
+ * and the first run of that check found that they did not.
15
+ */
16
+ /** `row-activated` -> `onRowActivated`; `notify` handled by the caller. */
17
+ export declare const eventPropOf: (signal: string) => string;
18
+ /** `can-focus` -> `canFocus`. The inverse of the host's `toPropertyName`. */
19
+ export declare const camelOf: (kebab: string) => string;
@@ -0,0 +1,47 @@
1
+ /** One member, as the `.d.ts` renders it: the TS text plus whatever JSDoc sits above. */
2
+ export interface DeclaredProp {
3
+ readonly ts: string;
4
+ readonly doc?: string;
5
+ readonly since?: string;
6
+ readonly deprecated: boolean;
7
+ }
8
+ /** One `export interface <GType>Props` — its own JSDoc, and its own members. */
9
+ export interface DeclaredInterface {
10
+ readonly doc?: string;
11
+ readonly props: Map<string, DeclaredProp>;
12
+ }
13
+ interface DocBlock {
14
+ readonly doc?: string;
15
+ readonly since?: string;
16
+ readonly deprecated: boolean;
17
+ }
18
+ /**
19
+ * The JSDoc block directly above a declaration, or nothing.
20
+ *
21
+ * ADJACENCY IS THE WHOLE RULE. `text` is everything preceding the declaration, so the
22
+ * nearest block above it may belong to a sibling several members up. Requiring
23
+ * whitespace only between that block's terminator and the declaration is what
24
+ * separates "this member is documented" from "some earlier member was".
25
+ */
26
+ export declare function readDocBlock(text: string): DocBlock;
27
+ /**
28
+ * Read the namespace imports a vocabulary declares: `import type Gdk from
29
+ * '@girs/gdk-4.0'`.
30
+ *
31
+ * These are the only honest answer to "which namespaces do the rendered types reach
32
+ * into". Deriving it from the source list instead emitted `Gdk.RGBA` with no Gdk
33
+ * import — TS2503, in a file nobody edits by hand.
34
+ */
35
+ export declare function readNamespaceImports(text: string, ownPkg: string): Map<string, string>;
36
+ /**
37
+ * The interfaces a vocabulary `.d.ts` declares, with each property's rendered type.
38
+ *
39
+ * Brace-matched rather than terminated on a closing brace at column 0: an interface
40
+ * body can contain a nested object type, and a reader that stops at the first one
41
+ * silently truncates it. That exact shortcut is already recorded as a defect in two
42
+ * sibling scripts.
43
+ */
44
+ export declare function readDeclaredInterfaces(text: string): Map<string, DeclaredInterface>;
45
+ /** Property lines plus the JSDoc block immediately above each one. */
46
+ export declare function readProps(body: string): Map<string, DeclaredProp>;
47
+ export {};
@@ -1,4 +1,4 @@
1
- import GObject from 'gi://GObject';
1
+ import GObject from 'gi://GObject?version=2.0';
2
2
  import type Gtk from '@girs/gtk-4.0';
3
3
  import type { HostAnchor, HostElement, HostNode, HostText, WidgetDescriptor } from './types.js';
4
4
  export declare function createElement(tag: string, props?: Record<string, unknown>): HostElement;
@@ -9,8 +9,14 @@ export declare function addressOf(el: HostElement): Gtk.Widget;
9
9
  * is the spelling anyone reaching for `activatable` or `selectable` uses, and
10
10
  * wrapping a row inside a second row nests two selectable widgets and detaches
11
11
  * activation from the one the author configured.
12
+ *
13
+ * A `slotted` policy reaches this too, per SLOT: an adder that hands the child to an
14
+ * inner `Gtk.ListBox` needs exactly the same wrap, and `Adw.ExpanderRow`'s `add_row` is
15
+ * one. The measurement behind that is on `ChildPolicy`'s `wrapSlots`; the short version
16
+ * is that `gtk_list_box_remove` does not unwrap, so without this the child leaks behind
17
+ * one `Gtk-WARNING` at unmount.
12
18
  */
13
- export declare function makeWrapper(policy: ChildPolicy, child: Gtk.Widget): Gtk.Widget | null;
19
+ export declare function makeWrapper(policy: ChildPolicy, child: Gtk.Widget, slot: string | null): Gtk.Widget | null;
14
20
  /**
15
21
  * A container the host owns that no window shows — the DOM's detached `<div>`.
16
22
  *
@@ -1,4 +1,4 @@
1
- import GObject from 'gi://GObject';
1
+ import GObject from 'gi://GObject?version=2.0';
2
2
  import type { WidgetDescriptor } from './types.js';
3
3
  /** `backgroundColor` and `background-color` both name the GObject property `background-color`. */
4
4
  export declare function toPropertyName(name: string): string;
@@ -33,6 +33,18 @@ export declare function constructOnlyNames(klass: GObject.ObjectClass, gtypeName
33
33
  * assumed. Also the primitive a renderer needs for a "did you mean" diagnostic.
34
34
  */
35
35
  export declare const lookupEnumNick: (gtypeName: string, nick: string) => number | undefined;
36
+ /**
37
+ * The member names an installed enum registers, or `undefined` if this host has none.
38
+ *
39
+ * The INVERSE of {@link lookupEnumNick}, and it exists for the one question that
40
+ * function cannot answer: a nick the vocabulary never emitted is absent from every
41
+ * list a check could iterate, so only the host's own members can reveal it. Read off
42
+ * the same `ENUM_NAMESPACES` table, so the two cannot disagree about where an enum
43
+ * lives — a second copy of that list is what made `Pango` missing once already.
44
+ *
45
+ * `$gtype` and anything non-numeric are not members; GJS puts both on the same object.
46
+ */
47
+ export declare function enumMembers(gtypeName: string): string[] | undefined;
36
48
  /**
37
49
  * Turn an authored value into one GObject will actually store.
38
50
  *
@@ -1,4 +1,4 @@
1
- import GObject from 'gi://GObject';
1
+ import GObject from 'gi://GObject?version=2.0';
2
2
  import type { WidgetDescriptor } from './types.js';
3
3
  export declare function registerWidget(descriptor: WidgetDescriptor): void;
4
4
  export declare function registerWidgets(descriptors: readonly WidgetDescriptor[]): void;
@@ -0,0 +1,22 @@
1
+ import Gdk from 'gi://Gdk?version=4.0';
2
+ import Gtk from 'gi://Gtk?version=4.0';
3
+ /** A document GTK refused, or one that would have discarded what follows it. */
4
+ export declare class StyleSheetError extends Error {
5
+ readonly name = "StyleSheetError";
6
+ constructor(message: string);
7
+ }
8
+ /**
9
+ * Refuse a document that would take everything after it with it.
10
+ *
11
+ * `subject` names what is being loaded, because the two callers have very different
12
+ * readers: a generated rule is this package's bug, and an application's theme
13
+ * document is the application's.
14
+ */
15
+ export declare function assertContained(document: string, subject: string): void;
16
+ /**
17
+ * Put a provider on a display at `priority`, and say which display that was.
18
+ *
19
+ * `subject` names what is being installed, because the failure a caller has to act
20
+ * on is "there is no display yet" and the fix depends on which document it is.
21
+ */
22
+ export declare function installProvider(provider: Gtk.CssProvider, subject: string, display: Gdk.Display | null | undefined, priority: number): Gdk.Display;
@@ -1,13 +1,16 @@
1
1
  export { GTK_CSS_PROBES, GTK_CSS_PROPERTIES, NOT_GTK_CSS } from './gtk-css.js';
2
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';
3
+ export { MINIMAL_TOKENS, TAILWIND_DEFAULT_TOKENS, lookupToken, mergeTokens, requireToken, tailwindDefaultHint, } from './tokens.js';
4
4
  export type { Scale, StyleTokens } from './tokens.js';
5
5
  export { UnknownUtilityError } from './errors.js';
6
6
  export { PAINT_PROPERTIES, partitionPaint, resolvePaintUtility } from './paint.js';
7
7
  export type { PaintProps } from './paint.js';
8
8
  export { LAYOUT_PROPERTIES, partitionLayout, resolveLayoutUtility } from './layout.js';
9
- export type { AlignValue, Edge, JustifyValue, LayoutIntent, LayoutPartition, LayoutProps, OverlayIntent, } from './layout.js';
9
+ export type { AlignValue, Edge, JustifyValue, LayoutIntent, LayoutPartition, LayoutProps, OverlayIntent, WrapIntent, } from './layout.js';
10
10
  export { partition, resolveUtilities, resolveUtility } from './resolve.js';
11
11
  export type { Partitioned, StyleProps } from './resolve.js';
12
- export { StyleSheet, StyleSheetError, VARIANT_PSEUDO } from './sheet.js';
12
+ export { StyleSheet, VARIANT_PSEUDO } from './sheet.js';
13
13
  export type { StyleSheetOptions } from './sheet.js';
14
+ export { assertContained, StyleSheetError } from './document.js';
15
+ export { ADWAITA_NAMED_COLORS, NEUTRAL_THEME, NOT_ADWAITA_NAMED_COLORS, THEME_PROVIDER_PRIORITY, ThemeRegistry, } from './theme.js';
16
+ export type { Theme, ThemeRegistryOptions } from './theme.js';
@@ -27,6 +27,7 @@ export interface LayoutProps {
27
27
  paddingBottom?: string;
28
28
  paddingLeft?: string;
29
29
  flexDirection?: 'row' | 'column';
30
+ flexWrap?: 'nowrap' | 'wrap';
30
31
  flexGrow?: string;
31
32
  alignItems?: AlignValue;
32
33
  justifyContent?: JustifyValue;
@@ -114,6 +115,25 @@ export interface LayoutIntent {
114
115
  * `relative` would make it undetectable.
115
116
  */
116
117
  readonly overlay?: OverlayIntent;
118
+ /**
119
+ * `flex-wrap` — the element becomes a DIFFERENT WIDGET.
120
+ *
121
+ * A `Gtk.Box` lays its children on one line and has no second line to put
122
+ * anything on. Wrapping on GTK is `Gtk.FlowBox`, which is not another property
123
+ * on the box but another class — so this is the same shape as
124
+ * {@link LayoutIntent.distribute}'s `space-between`: L1 names the widget the
125
+ * answer needs and L2 swaps it, because L1 resolves properties for an element
126
+ * and has no say in what the element becomes.
127
+ *
128
+ * The SPACINGS travel with it, and that is the reason this field carries values
129
+ * at all rather than being a flag. `Gtk.FlowBox` has NO `spacing` (measured,
130
+ * `gtk-props.ts`) — it has `row-spacing` and `column-spacing`, both real at once
131
+ * — so a gap on a wrapping element cannot take the `Gtk.Box:spacing` route the
132
+ * gap routes below use, and the axis-qualified spellings stop being an
133
+ * orientation question. Routing them here is what keeps `gap-*` from emitting a
134
+ * property the widget does not install.
135
+ */
136
+ readonly wrap?: WrapIntent;
117
137
  /**
118
138
  * `text-*` — only a text widget aligns text.
119
139
  *
@@ -124,6 +144,20 @@ export interface LayoutIntent {
124
144
  */
125
145
  readonly textAlign?: 'left' | 'center' | 'right' | 'justify';
126
146
  }
147
+ /**
148
+ * `flex-nowrap` / `flex-wrap`, with the spacings a wrapping widget needs.
149
+ *
150
+ * `single` is carried rather than dropped for the reason `relative` is: it is the
151
+ * half L2 can hold the other half against, and a resolution that never sees it
152
+ * cannot tell "this element does not wrap" from "nobody asked".
153
+ */
154
+ export type WrapIntent = {
155
+ readonly lines: 'single';
156
+ } | {
157
+ readonly lines: 'multi';
158
+ readonly rowSpacing?: number;
159
+ readonly columnSpacing?: number;
160
+ };
127
161
  export type OverlayIntent = {
128
162
  readonly role: 'context';
129
163
  } | {
@@ -1,11 +1,6 @@
1
1
  import Gdk from 'gi://Gdk?version=4.0';
2
2
  /** A variant this sheet knows how to express, and the pseudo-class it becomes. */
3
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
4
  export interface StyleSheetOptions {
10
5
  /**
11
6
  * Where the provider is installed. Omitted means the default display — the
@@ -0,0 +1,158 @@
1
+ import Gdk from 'gi://Gdk?version=4.0';
2
+ /**
3
+ * Where a theme document is installed. See decision 2 for why it is this number.
4
+ *
5
+ * Exported because it is the fact a reader has to check against their own providers,
6
+ * and because a consumer installing a fourth document needs to know what it has to
7
+ * sit between.
8
+ */
9
+ export declare const THEME_PROVIDER_PRIORITY: number;
10
+ /**
11
+ * The named colours libadwaita defines, measured rather than read.
12
+ *
13
+ * MEASURED on libadwaita 1.9.3 by resolving `var(--<name>, <sentinel>)` on a real
14
+ * widget and checking the sentinel did NOT come back — the only test that
15
+ * distinguishes "the name exists" from "the name is a typo that defines nothing".
16
+ * `theme.spec.ts` re-measures both directions against the libadwaita that is
17
+ * running, so a release that renames one goes red here rather than in a window.
18
+ *
19
+ * The list is what a theme may OVERRIDE, and overriding a name libadwaita does not
20
+ * define is the exact silent failure this set exists to catch: `--acccent-bg-color`
21
+ * is a perfectly valid custom property that nothing ever reads.
22
+ */
23
+ export declare const ADWAITA_NAMED_COLORS: readonly string[];
24
+ /**
25
+ * Names that are NOT custom properties, and the claim each one carries.
26
+ *
27
+ * Without this direction the set above could name every string in GTK and still
28
+ * pass. `borders` is the interesting row: it is a real Adwaita colour under the
29
+ * LEGACY `@define-color` mechanism and is not a CSS variable, which is exactly the
30
+ * confusion decision 1 is about. `accent_bg_color` is the same point in the other
31
+ * spelling — the underscored legacy name of a variable that does exist.
32
+ */
33
+ export declare const NOT_ADWAITA_NAMED_COLORS: readonly string[];
34
+ /** One named look: a GTK CSS document, a palette, and which desktops default to it. */
35
+ export interface Theme {
36
+ /** How the application asks for it. Also what a refusal names. */
37
+ readonly name: string;
38
+ /**
39
+ * The application's own GTK CSS document.
40
+ *
41
+ * Goes through the same containment probe as a generated rule, and for a
42
+ * stronger reason: this is the document this package did not write.
43
+ */
44
+ readonly css?: string;
45
+ /**
46
+ * Adwaita named colours to redefine, WITHOUT the `--` prefix.
47
+ *
48
+ * `{ 'accent-bg-color': 'rgb(53 132 228)' }`. Emitted as a `:root` block ahead of
49
+ * {@link Theme.css}, so a rule in {@link Theme.css} redefining one of these names
50
+ * WINS — the last definition in a document is the one that applies.
51
+ */
52
+ readonly namedColors?: Readonly<Record<string, string>>;
53
+ /**
54
+ * The `process.platform` values this theme is the default for, or `'*'` for any.
55
+ *
56
+ * Data on the theme rather than a table in the registry, because "this look
57
+ * belongs on macOS" is a fact about the look.
58
+ *
59
+ * `'*'` exists because `process.platform` has more values than the three desktops
60
+ * this project targets — `freebsd`, `openbsd`, `android`, `sunos`, … — and GTK
61
+ * runs on several of them. A registry that only knew `linux`/`darwin`/`win32`
62
+ * would make `selectDefault(process.platform)`, the call this seam is documented
63
+ * with, THROW on a platform where nothing is wrong. A fallback theme says so once
64
+ * instead, and a named theme still wins over it by being registered later.
65
+ */
66
+ readonly defaultOn?: readonly string[];
67
+ }
68
+ /**
69
+ * The one theme shipped now, and it deliberately changes nothing.
70
+ *
71
+ * A GTK application should look like the desktop it is running on, and the accent is
72
+ * the user's — they picked it in Settings and expect their applications to use it.
73
+ * So the neutral theme is an EMPTY document, and that is a statement rather than a
74
+ * placeholder: selecting it is how an application returns to Adwaita exactly, which
75
+ * is measurably true because reloading the provider to the empty string restores
76
+ * every named colour to libadwaita's own value.
77
+ *
78
+ * It is also what makes the registry useful with one theme registered: there is
79
+ * always something to switch back TO.
80
+ */
81
+ export declare const NEUTRAL_THEME: Theme;
82
+ export interface ThemeRegistryOptions {
83
+ /**
84
+ * Where the provider is installed. Omitted means the default display — the right
85
+ * answer for an application and the wrong one for a test, which is why it is
86
+ * injectable at all.
87
+ */
88
+ readonly display?: Gdk.Display | null;
89
+ /** Provider priority. Defaults to {@link THEME_PROVIDER_PRIORITY}; see decision 2. */
90
+ readonly priority?: number;
91
+ }
92
+ /**
93
+ * Named themes, one selected, swapped on a single provider.
94
+ *
95
+ * NOT a module-level singleton, unlike the token configuration one layer up. A
96
+ * registry holds a `Gdk.Display` and a `Gtk.CssProvider`, so a test that could not
97
+ * make its own would have to share the session's — and the registry is exactly the
98
+ * object whose whole behaviour is "what is installed on the display right now".
99
+ */
100
+ export declare class ThemeRegistry {
101
+ #private;
102
+ constructor(options?: ThemeRegistryOptions);
103
+ /**
104
+ * Add a theme, refusing anything that would be a silent no-op.
105
+ *
106
+ * The document is PROBED here rather than at selection, so the error names the
107
+ * line that declared the theme instead of the line that switched to it — which
108
+ * may be a user clicking a row in the application's settings, hours later.
109
+ */
110
+ register(theme: Theme): this;
111
+ /** The registered names, in registration order. */
112
+ get names(): readonly string[];
113
+ /** The selected theme's name, or null before anything is selected. */
114
+ get current(): string | null;
115
+ /** The document a theme produces. Exposed because a test that cannot read it proves nothing. */
116
+ documentOf(theme: Theme): string;
117
+ /**
118
+ * Switch to a registered theme, replacing whatever was loaded.
119
+ *
120
+ * Idempotent, and cheap enough to call from a settings row's handler: the
121
+ * document was probed at registration, so this is one `load_from_string` plus, on
122
+ * the first call only, one `add_provider_for_display`.
123
+ */
124
+ select(name: string): void;
125
+ /**
126
+ * Select the theme that declares itself the default for `platform`.
127
+ *
128
+ * The platform is a PARAMETER and this module never reads `process.platform`
129
+ * itself — the same discipline the intent seam one layer up argues for. It keeps
130
+ * a `process` read (and the OS declaration that comes with one) out of a package
131
+ * whose job is GTK, and it lets a settings screen preview another desktop's look
132
+ * by passing that desktop's name.
133
+ *
134
+ * The last registered match wins, so an application registering its own theme
135
+ * after the neutral one gets its own — including over a theme that declares
136
+ * `'*'`, which is how the shipped neutral default stays a fallback rather than a
137
+ * ceiling.
138
+ */
139
+ selectDefault(platform: string): void;
140
+ /**
141
+ * Take the theme document off the display, leaving nothing behind.
142
+ *
143
+ * Selecting the neutral theme reloads the document to empty, which is all an
144
+ * application needs. It is NOT all a TEST needs, and the difference was measured
145
+ * in this file's own spec: a vector that read "libadwaita's own accent" read the
146
+ * PREVIOUS vector's green instead, because that registry's provider was still on
147
+ * the shared display with a `--accent-bg-color` in it — and the assertion named
148
+ * "back to Adwaita exactly" then passed against the green. Ownership belongs with
149
+ * whoever created the registry, so there has to be a way to give it up.
150
+ *
151
+ * The provider is removed from the display it was INSTALLED on rather than from
152
+ * whatever `Gdk.Display.get_default()` answers now. A later `select()` installs
153
+ * again: position relative to the generated sheet is decided by the priority
154
+ * numbers, not by insertion order, so re-installing cannot land in the wrong
155
+ * place (decision 2).
156
+ */
157
+ dispose(): void;
158
+ }
@@ -0,0 +1,2 @@
1
+ declare const _default: () => Promise<void>;
2
+ export default _default;