@gjsify/gtk-host 0.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +140 -0
- package/lib/esm/_virtual/_rolldown/runtime.js +1 -0
- package/lib/esm/conformance/diagnostics.js +2 -0
- package/lib/esm/conformance/index.js +2 -0
- package/lib/esm/descriptors/adw.js +1 -0
- package/lib/esm/descriptors/gtk.js +1 -0
- package/lib/esm/descriptors/index.js +1 -0
- package/lib/esm/errors.js +1 -0
- package/lib/esm/host.js +1 -0
- package/lib/esm/index.js +1 -0
- package/lib/esm/policies.js +1 -0
- package/lib/esm/props.js +1 -0
- package/lib/esm/registry.js +1 -0
- package/lib/esm/signals.js +1 -0
- package/lib/esm/types.js +0 -0
- package/lib/types/conformance/diagnostics.d.ts +17 -0
- package/lib/types/conformance/index.d.ts +26 -0
- package/lib/types/conformance.spec.d.ts +2 -0
- package/lib/types/descriptors/adw.d.ts +2 -0
- package/lib/types/descriptors/gtk.d.ts +2 -0
- package/lib/types/descriptors/index.d.ts +5 -0
- package/lib/types/errors.d.ts +33 -0
- package/lib/types/host.d.ts +56 -0
- package/lib/types/host.spec.d.ts +2 -0
- package/lib/types/index.d.ts +8 -0
- package/lib/types/policies.d.ts +33 -0
- package/lib/types/props.d.ts +29 -0
- package/lib/types/props.spec.d.ts +2 -0
- package/lib/types/registry.d.ts +25 -0
- package/lib/types/signals.d.ts +11 -0
- package/lib/types/types.d.ts +145 -0
- package/package.json +72 -0
package/README.md
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# @gjsify/gtk-host
|
|
2
|
+
|
|
3
|
+
The element model UI-framework renderers bind to, for GTK4 and libadwaita.
|
|
4
|
+
|
|
5
|
+
Vue, React, Solid and Angular each publish a contract for rendering into
|
|
6
|
+
something that is not the DOM. What none of them provides is the *something*:
|
|
7
|
+
an object model that can create a widget, set a property, adopt a child, and
|
|
8
|
+
navigate the result. That is this package.
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import type Adw from '@girs/adw-1';
|
|
12
|
+
import { createElement, insert, materialize, registerBuiltinWidgets } from '@gjsify/gtk-host';
|
|
13
|
+
|
|
14
|
+
registerBuiltinWidgets();
|
|
15
|
+
|
|
16
|
+
const window = createElement('AdwApplicationWindow', { title: 'Hello' });
|
|
17
|
+
const box = createElement('GtkBox', { orientation: 'vertical', spacing: 12 });
|
|
18
|
+
const button = createElement('GtkButton', { label: 'Press me' });
|
|
19
|
+
|
|
20
|
+
insert(box, window);
|
|
21
|
+
insert(button, box);
|
|
22
|
+
(materialize(window) as Adw.ApplicationWindow).present();
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Why a shared host
|
|
26
|
+
|
|
27
|
+
NativeScript carries five framework flavours over one host, and the adapters are
|
|
28
|
+
small because the host exists: its Solid adapter is **91 lines**, its React
|
|
29
|
+
adapter **505** — and both hold *zero* lines of widget knowledge. Under GTK4 the
|
|
30
|
+
shared share is larger still: GTK4 deleted `GtkContainer`, so there is no generic
|
|
31
|
+
`add`, and `Gtk.Buildable.add_child` is introspected as a vfunc only. Every
|
|
32
|
+
container's adoption rule has to be written down somewhere. Written once, it is a
|
|
33
|
+
table; written per adapter, it is the same table three times — which is what
|
|
34
|
+
stalled `react-gtk`, `react-native-gtk4` and `svelte-gjs`.
|
|
35
|
+
|
|
36
|
+
See [ADR 0027](../../../docs/adr/0027-gtk-host-layer.md) and
|
|
37
|
+
[ADR 0028](../../../docs/adr/0028-widget-table-provenance.md).
|
|
38
|
+
|
|
39
|
+
## What it refuses to do quietly
|
|
40
|
+
|
|
41
|
+
GTK's failure mode is exit 0, so this host is loud on purpose. Measured on
|
|
42
|
+
gjs 1.88.1:
|
|
43
|
+
|
|
44
|
+
| What you write | What GObject does | What this host does |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| `orientation: 'vertical'` | keeps `HORIZONTAL`; `set_property` logs `GLib-GObject-CRITICAL`, the JS setter says nothing at all | resolves the nick against the enum's GType |
|
|
47
|
+
| `orientation: 'sideways'` | same silence | throws, naming `GtkOrientation` |
|
|
48
|
+
| a read-only property | accepts the write, stores nothing | throws, naming the property |
|
|
49
|
+
| a misspelled property | nothing | throws, naming the widget |
|
|
50
|
+
| text inside `<GtkImage>` | nothing | throws, naming the tag and the fix |
|
|
51
|
+
| a child under a childless widget | `Gtk-WARNING` at exit 0 | throws, naming the three fixes |
|
|
52
|
+
| `selectable: 'false'` (a string) | JS truthiness makes it TRUE | honours `'true'`/`'false'`, throws on any other string |
|
|
53
|
+
| a string for a flags property | dropped silently | throws, naming the flags GType and asking for the numeric value |
|
|
54
|
+
|
|
55
|
+
## The node tree
|
|
56
|
+
|
|
57
|
+
Three node kinds — `element`, `text`, `anchor` — linked by the host's own
|
|
58
|
+
`parent`/`first`/`next`, never by `Gtk.Widget.get_parent()`. Text and anchors own
|
|
59
|
+
no widget, so GTK cannot answer navigation questions about them.
|
|
60
|
+
|
|
61
|
+
**Anchors never enter the GTK tree.** Vue's `createComment` and every
|
|
62
|
+
`v-if`/`<Show>` boundary becomes one, and insertion resolves forward past it to
|
|
63
|
+
the next node that owns a widget. An empty branch therefore cannot shift a
|
|
64
|
+
sibling's index.
|
|
65
|
+
|
|
66
|
+
**An element is `attached` only once GTK has taken it.** Owning a widget is not
|
|
67
|
+
the same fact: every framework materialises a subtree bottom-up, long before
|
|
68
|
+
inserting it. Placement reads `attached`, never `widget !== null` — deriving it
|
|
69
|
+
from the widget made the `remove-all` policy detach non-children and re-add
|
|
70
|
+
already-parented ones, at exit 0.
|
|
71
|
+
|
|
72
|
+
**Text has no node in GTK.** It goes to the owning widget's declared `textSink`
|
|
73
|
+
(`Gtk.Label:label`, `Gtk.Entry:text`, …). A widget without one rejects text by name.
|
|
74
|
+
|
|
75
|
+
## Child placement
|
|
76
|
+
|
|
77
|
+
Seven policy kinds, declared per widget as data and dispatched on the policy's
|
|
78
|
+
own `kind`. Descriptor lookup is by exact GType name; `mountRoot` is the one path
|
|
79
|
+
that walks the type hierarchy (`GObject.type_is_a`, via `nearestRegistered`), so
|
|
80
|
+
an application's own subclass resolves to its ancestor's rules:
|
|
81
|
+
|
|
82
|
+
| kind | example | how a child lands |
|
|
83
|
+
|---|---|---|
|
|
84
|
+
| `single` | `AdwBin`, `GtkWindow` | `set_child` / `set_content` |
|
|
85
|
+
| `ordered` | `GtkBox` | `append` + `insert_child_after` |
|
|
86
|
+
| `indexed` | `GtkListBox` | `insert(row, i)` — the parent addresses a **wrapper** row |
|
|
87
|
+
| `slotted` | `AdwHeaderBar` | `pack_start` / `pack_end` / `set_title_widget`, chosen by the child's `slot` |
|
|
88
|
+
| `keyed` | `GtkStack` | `add_titled(child, name, title)` |
|
|
89
|
+
| `coords` | `GtkGrid` | `attach(child, column, row, …)` |
|
|
90
|
+
| `none` | `GtkLabel` | rejected, with the three fixes named |
|
|
91
|
+
|
|
92
|
+
A container that cannot reorder in place declares it. `Adw.PreferencesGroup` has
|
|
93
|
+
`add` and `remove` and no `insert` — measured — so it declares
|
|
94
|
+
`reorder: 'remove-all'` and pays a tail re-append. The degradation is in the
|
|
95
|
+
table, not a surprise in an app. The re-append is ordered so a refusal costs
|
|
96
|
+
nothing: the new child is appended FIRST, then the tail is rotated — detaching the
|
|
97
|
+
tail first and failing on the append took already-rendered siblings with it.
|
|
98
|
+
|
|
99
|
+
Its sibling `Adw.PreferencesPage` looks identical and is not: `insert(group, i)`
|
|
100
|
+
exists there, so it uses `indexed` and reorders natively. Near-identical APIs with
|
|
101
|
+
opposite capabilities are exactly why the table is measured per widget rather than
|
|
102
|
+
inherited.
|
|
103
|
+
|
|
104
|
+
`slot` and `layout` are props the CHILD declares: `slot="end"` picks a `slotted`
|
|
105
|
+
attachment point, `layout={{ column, row, columnSpan, rowSpan }}` a `coords` cell,
|
|
106
|
+
`layout={{ name, title }}` a `keyed` page. Both are read at placement time, so
|
|
107
|
+
changing either RE-PLACES the child rather than doing nothing.
|
|
108
|
+
|
|
109
|
+
## Lifetime
|
|
110
|
+
|
|
111
|
+
`remove` detaches and is reversible, because frameworks move nodes. The wrapper
|
|
112
|
+
row an `indexed` parent demanded is handed back at the same time — it belongs to
|
|
113
|
+
that parent, and dragging a `GtkListBoxRow` into the next one would carry the
|
|
114
|
+
still-parented widget with it — so a re-insert gets a fresh row. Author your own
|
|
115
|
+
`<GtkListBoxRow>` when the row itself holds state. `destroy`
|
|
116
|
+
tears a subtree down: it disconnects every handler, unparents, drops the
|
|
117
|
+
reference, and closes a toplevel window (the one node unparenting cannot reach —
|
|
118
|
+
it has no parent and its `GtkApplication` still holds it). It is recursive, it is
|
|
119
|
+
eager, and it is the only place a handler is disconnected for good — a rebuild
|
|
120
|
+
disconnects and re-binds, a re-render replaces. GJS blocks JS callbacks during GC,
|
|
121
|
+
so **whatever is not disconnected here stays connected for the life of the
|
|
122
|
+
process**.
|
|
123
|
+
|
|
124
|
+
Construct-only properties cannot be patched; GObject accepts the write and keeps
|
|
125
|
+
the old value. Changing one **rebuilds** the widget in place, preserving position,
|
|
126
|
+
properties and listeners.
|
|
127
|
+
|
|
128
|
+
## Conformance
|
|
129
|
+
|
|
130
|
+
`@gjsify/gtk-host/conformance` exports the checks that keep the table honest and
|
|
131
|
+
the readers every vector asserts through:
|
|
132
|
+
|
|
133
|
+
- `descriptorProblems()` — every method and text sink a descriptor names must
|
|
134
|
+
exist on that GType in the *installed* GTK.
|
|
135
|
+
- `gtkChildren()` / `gtkChildTypes()` / `dumpTree()` — read the **real** widget
|
|
136
|
+
tree. A renderer that asserts against its own bookkeeping agrees with itself
|
|
137
|
+
while the window is wrong.
|
|
138
|
+
|
|
139
|
+
Adapters will run the same vectors, so "it works in Vue" and "it works in Solid"
|
|
140
|
+
will mean the same thing. None is written yet — see `status/open-todos.md`.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=Object.defineProperty,__name=(t,n)=>e(t,`name`,{value:n,configurable:!0});export{__name};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import"../_virtual/_rolldown/runtime.js";import e from"gi://GLib";let t=null;function installDiagnosticsGate(){if(t)return t;let n=[],r=new TextDecoder,i=e.getenv(`G_MESSAGES_DEBUG`)!==null;return e.log_set_writer_func((t,a)=>{try{let o=a?.MESSAGE,s=o instanceof Uint8Array?r.decode(o):String(o??``),c=t&e.LogLevelFlags.LEVEL_MASK;c<=e.LogLevelFlags.LEVEL_WARNING&&n.push(s),(i||c<=e.LogLevelFlags.LEVEL_MESSAGE)&&printerr(s)}catch{printerr(`<gtk-host: a log message could not be decoded>`)}return e.LogWriterOutput.HANDLED}),t={seen:n,reset(){n.length=0},assertQuiet(e){if(n.length===0)return;let t=n.length,r=n.join(`
|
|
2
|
+
`);throw n.length=0,Error(`${e?e+`: `:``}GTK reported ${t} diagnostic(s) that would have passed at exit 0:\n ${r}`)}},t}export{installDiagnosticsGate};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import"../_virtual/_rolldown/runtime.js";import{installDiagnosticsGate as e}from"./diagnostics.js";import{BUILTIN_DESCRIPTORS as t}from"../descriptors/index.js";import{addressOf as n}from"../policies.js";import r from"gi://GObject";function methodsOf(e){switch(e.kind){case`none`:return[];case`single`:return[e.set];case`ordered`:return e.after?[e.append,e.after,e.remove]:[e.append,e.remove];case`indexed`:return[e.insert,e.remove];case`slotted`:return[...Object.values(e.slots),e.remove];case`keyed`:return[e.add,e.remove];case`coords`:return[e.attach,e.remove]}}function descriptorProblems(e=t){let n=[];for(let t of e){let e;try{e=t.ctor()}catch(e){n.push({gtype:t.gtype,problem:`ctor() threw: ${e.message}`});continue}let i=r.type_name(e.$gtype);i!==t.gtype&&n.push({gtype:t.gtype,problem:`ctor() is ${i}, not ${t.gtype}`});for(let r of methodsOf(t.children))typeof e.prototype[r]!=`function`&&n.push({gtype:t.gtype,problem:`declares children.${r}(), which ${i} does not have`});if(t.textSink){let a=e.list_properties().find(e=>e.get_name()===t.textSink);a?(a.flags&r.ParamFlags.WRITABLE)===0?n.push({gtype:t.gtype,problem:`declares a READ-ONLY textSink "${t.textSink}"`}):r.type_is_a(a.value_type,r.TYPE_STRING)||n.push({gtype:t.gtype,problem:`declares textSink "${t.textSink}", which is ${r.type_name(a.value_type)}, not a string`}):n.push({gtype:t.gtype,problem:`declares textSink "${t.textSink}", which ${i} does not have`})}n.push(...policyProblems(t,e,i))}return n}function policyProblems(e,t,n){let r=[],i=t.prototype,a=e.children,requireGetter=(t,a)=>{let o=t.replace(/^set_/,`get_`);typeof i[o]!=`function`&&r.push({gtype:e.gtype,problem:`${a} uses ${t}() but ${n} has no ${o}(), so removal cannot check whether this child is still the one in place`})};if(a.kind===`single`&&requireGetter(a.set,`children.set`),a.kind===`slotted`){for(let[e,t]of Object.entries(a.slots))t.startsWith(`set_`)&&requireGetter(t,`slot "${e}"`);a.defaultSlot in a.slots||r.push({gtype:e.gtype,problem:`defaultSlot "${a.defaultSlot}" is not one of ${Object.keys(a.slots).join(`, `)}`})}if(a.kind===`ordered`&&a.reorder===`native`&&!a.after&&r.push({gtype:e.gtype,problem:`claims reorder: 'native' with no "after" method — reorderMode() would tell an adapter the wrong thing`}),a.kind===`keyed`){let t=i[a.add],o=a.titled?3:1;typeof t==`function`&&t.length!==o&&r.push({gtype:e.gtype,problem:`titled: ${a.titled} implies ${a.add}() takes ${o} argument(s), but ${n}'s takes ${t.length}`})}return r}function gtkChildren(e){let t=[],n=e;if(typeof n.get_first_child!=`function`)return t;for(let e=n.get_first_child();e;e=e.get_next_sibling())t.push(e);return t}const gtkChildTypes=e=>gtkChildren(e).map(e=>r.type_name(e.constructor.$gtype));function addressesOf(e){let t=[];for(let r=e.first;r;r=r.next)r.kind===`element`&&r.widget&&t.push(n(r));return t}function dumpTree(e,t=0){let n=r.type_name(e.constructor.$gtype),i=[`${` `.repeat(t)}${n}`];for(let n of gtkChildren(e))i.push(dumpTree(n,t+1));return i.join(`
|
|
2
|
+
`)}export{addressesOf,descriptorProblems,dumpTree,gtkChildTypes,gtkChildren,e as installDiagnosticsGate,methodsOf};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"../_virtual/_rolldown/runtime.js";import e from"gi://Adw?version=1";const t=[{gtype:`AdwApplicationWindow`,ctor:()=>e.ApplicationWindow,children:{kind:`single`,set:`set_content`}},{gtype:`AdwWindow`,ctor:()=>e.Window,children:{kind:`single`,set:`set_content`}},{gtype:`AdwBin`,ctor:()=>e.Bin,children:{kind:`single`,set:`set_child`}},{gtype:`AdwToolbarView`,ctor:()=>e.ToolbarView,children:{kind:`slotted`,slots:{top:`add_top_bar`,bottom:`add_bottom_bar`,content:`set_content`},defaultSlot:`content`,remove:`remove`}},{gtype:`AdwHeaderBar`,ctor:()=>e.HeaderBar,children:{kind:`slotted`,slots:{start:`pack_start`,end:`pack_end`,title:`set_title_widget`},defaultSlot:`start`,remove:`remove`}},{gtype:`AdwPreferencesGroup`,ctor:()=>e.PreferencesGroup,children:{kind:`ordered`,append:`add`,remove:`remove`,reorder:`remove-all`}},{gtype:`AdwPreferencesPage`,ctor:()=>e.PreferencesPage,children:{kind:`indexed`,insert:`insert`,remove:`remove`,wrap:null}},{gtype:`AdwActionRow`,ctor:()=>e.ActionRow,children:{kind:`slotted`,slots:{prefix:`add_prefix`,suffix:`add_suffix`},defaultSlot:`suffix`,remove:`remove`}},{gtype:`AdwStatusPage`,ctor:()=>e.StatusPage,children:{kind:`single`,set:`set_child`}}];export{t as ADW_DESCRIPTORS};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"../_virtual/_rolldown/runtime.js";import e from"gi://Gtk?version=4.0";const t=[{gtype:`GtkBox`,ctor:()=>e.Box,children:{kind:`ordered`,append:`append`,after:`insert_child_after`,remove:`remove`,reorder:`native`}},{gtype:`GtkWindow`,ctor:()=>e.Window,children:{kind:`single`,set:`set_child`}},{gtype:`GtkApplicationWindow`,ctor:()=>e.ApplicationWindow,children:{kind:`single`,set:`set_child`}},{gtype:`GtkScrolledWindow`,ctor:()=>e.ScrolledWindow,children:{kind:`single`,set:`set_child`}},{gtype:`GtkFrame`,ctor:()=>e.Frame,children:{kind:`single`,set:`set_child`}},{gtype:`GtkLabel`,ctor:()=>e.Label,children:{kind:`none`},textSink:`label`},{gtype:`GtkButton`,ctor:()=>e.Button,children:{kind:`single`,set:`set_child`},textSink:`label`},{gtype:`GtkToggleButton`,ctor:()=>e.ToggleButton,children:{kind:`single`,set:`set_child`},textSink:`label`},{gtype:`GtkImage`,ctor:()=>e.Image,children:{kind:`none`}},{gtype:`GtkSwitch`,ctor:()=>e.Switch,children:{kind:`none`}},{gtype:`GtkEntry`,ctor:()=>e.Entry,children:{kind:`none`},textSink:`text`},{gtype:`GtkListBox`,ctor:()=>e.ListBox,children:{kind:`indexed`,insert:`insert`,remove:`remove`,wrap:`list-box-row`}},{gtype:`GtkFlowBox`,ctor:()=>e.FlowBox,children:{kind:`indexed`,insert:`insert`,remove:`remove`,wrap:`flow-box-child`}},{gtype:`GtkListBoxRow`,ctor:()=>e.ListBoxRow,children:{kind:`single`,set:`set_child`}},{gtype:`GtkStack`,ctor:()=>e.Stack,children:{kind:`keyed`,add:`add_titled`,remove:`remove`,nameFrom:`name`,titled:!0}},{gtype:`GtkGrid`,ctor:()=>e.Grid,children:{kind:`coords`,attach:`attach`,remove:`remove`}},{gtype:`GtkHeaderBar`,ctor:()=>e.HeaderBar,children:{kind:`slotted`,slots:{start:`pack_start`,end:`pack_end`,title:`set_title_widget`},defaultSlot:`start`,remove:`remove`}}];export{t as GTK_DESCRIPTORS};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"../_virtual/_rolldown/runtime.js";import{registerWidgets as e}from"../registry.js";import{ADW_DESCRIPTORS as t}from"./adw.js";import{GTK_DESCRIPTORS as n}from"./gtk.js";const r=[...n,...t];function registerBuiltinWidgets(){e(r)}export{t as ADW_DESCRIPTORS,r as BUILTIN_DESCRIPTORS,n as GTK_DESCRIPTORS,registerBuiltinWidgets};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";var GtkHostError=class extends Error{constructor(e,t){super(t),this.code=e,this.name=`GtkHostError`}};const e={unknownTag:e=>new GtkHostError(`unknown-tag`,`No descriptor registered for <${e}>. Register one with registerWidget({ gtype: '${e}', … }) or use a raw GType tag that is present in the installed typelib.`),unknownProp:(e,t)=>new GtkHostError(`unknown-prop`,`<${e}> has no property "${t}". Check the spelling against the installed GTK (camelCase and kebab-case both resolve), or bind it as a signal with on${t[0]?.toUpperCase()}${t.slice(1)}.`),readOnlyProp:(e,t)=>new GtkHostError(`read-only-prop`,`<${e}>.${t} is read-only in the installed GTK. Writing it is a silent no-op in GObject, so this host refuses it instead of dropping the value.`),badEnum:(e,t,n,r)=>new GtkHostError(`bad-enum`,`<${e}>.${t} expects ${r}, and "${n}" is not one of its values. Note that GObject accepts the wrong string SILENTLY — the property would have kept its old value.`),unknownSignal:(e,t,n)=>new GtkHostError(`unknown-signal`,`<${e}> emits no signal "${n}" (bound as ${t}). Check the spelling against the installed GTK, or use the escape hatch on:<raw-signal-name> if the name is irregular.`),signalTaken:(e,t,n,r)=>new GtkHostError(`signal-taken`,`<${e}> already binds "${r}" through ${n}, so ${t} would silently replace it — GObject has one handler per connect, and this host keeps one per signal name. Use one spelling, or combine the two callbacks yourself.`),badString:(e,t,n)=>new GtkHostError(`bad-string`,`<${e}>.${t} is a string property and got a ${n}. Numbers and booleans are stringified; anything else has no unambiguous spelling, and GObject would have thrown from inside the next rebuild.`),badBoolean:(e,t,n)=>new GtkHostError(`bad-boolean`,`<${e}>.${t} is a boolean and got the string "${n}". JS truthiness would make "false" mean TRUE — the exact silent-wrong-value this host exists to refuse. Pass a real boolean.`),badFlags:(e,t,n,r)=>new GtkHostError(`bad-flags`,`<${e}>.${t} expects the flags type ${r}, and a string ("${n}") cannot be resolved to one. Pass the numeric value (bitwise-or the members). GObject would have dropped the string silently.`),unresolvableEnum:e=>new GtkHostError(`unresolvable-enum`,`Cannot resolve the enum type ${e} to a GI namespace. Pass the numeric value instead, or extend ENUM_NAMESPACES in props.ts.`),textNotAccepted:(e,t)=>new GtkHostError(`text-not-accepted`,`<${e}> has no text sink, so the text ${JSON.stringify(t.slice(0,32))} has nowhere to go. Wrap it in a widget that takes text (<GtkLabel>), or set the property directly.`),unclaimedChild:(e,t)=>new GtkHostError(`unclaimed-child`,`<${e}> declares children: { kind: 'none' }, so it cannot adopt <${t}>. Fix one of three things: give the parent a child policy, wrap the child in a container, or set the child on a property (e.g. a "child" or "content" property).`),unknownSlot:(e,t,n)=>new GtkHostError(`unknown-slot`,`<${e}> has no slot "${t}". Known slots: ${n.join(`, `)}.`),rejectedChild:(e,t,n)=>new GtkHostError(`rejected-child`,`<${e}> refused <${t}>: ${n}. The container accepts only certain child types (e.g. AdwPreferencesPage takes AdwPreferencesGroup); the descriptor cannot know that, GTK does.`),notAWidget:e=>new GtkHostError(`not-a-widget`,`<${e}> is not a Gtk.Widget, so it cannot be placed as a child. Non-widget GObjects (controllers, filters, models) attach to a property, not to a parent.`)};export{GtkHostError,e as err};
|
package/lib/esm/host.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import{err as e}from"./errors.js";import{lookupWidget as t,nearestRegistered as n}from"./registry.js";import{addressOf as r,insertChild as i,makeWrapper as a,removeChild as o}from"./policies.js";import{beginHostWrite as s,clearHandlers as c,endHostWrite as l,isEventProp as u,setHandler as d,toSignalName as f}from"./signals.js";import{coerce as p,defaultValue as m,paramSpecs as h,requireSpec as g,toPropertyName as _}from"./props.js";import v from"gi://GObject";function createElement(e,n){let r={kind:`element`,descriptor:t(e),widget:null,wrapper:null,slot:null,parent:null,prev:null,next:null,first:null,last:null,handlers:new Map,listeners:new Map,props:{},layout:null,textFromChildren:!1,attached:!1};if(n)for(let[e,t]of Object.entries(n))setProp(r,e,t);return r}const createText=e=>({kind:`text`,data:e,parent:null,prev:null,next:null}),createAnchor=(e=``)=>({kind:`anchor`,data:e,parent:null,prev:null,next:null}),isText=e=>e.kind===`text`;function materialize(e){if(e.widget)return e.widget;let t=e.descriptor.ctor(),n=h(t,e.descriptor.gtype),r={};for(let[t,i]of Object.entries(e.props))r[t]=p(g(n,e.descriptor.gtype,t),i,e.descriptor.gtype);s();try{e.widget=new t(r)}finally{l()}try{replayInto(e)}catch(t){c(e);for(let t of childSnapshot(e))t.kind===`element`&&t.attached&&(o(e,t),t.attached=!1);throw e.widget=null,e.wrapper=null,t}return e.widget}function replayInto(e){for(let[t,n]of e.listeners)d(e,t,n);for(let t=e.first;t;t=t.next)t.kind===`element`&&attach(e,t);e.textFromChildren&&flushText(e)}function setProp(e,t,n,r){if(u(t))return setEventHandler(e,t,n);if(t===`slot`)return setSlot(e,n);if(t===`layout`){let t=n,r=e.parent;if(!r||!e.widget){e.layout=t;return}let i=e.layout;replaceAt(e,r,()=>{e.layout=t},()=>{e.layout=i});return}let i=_(t),a=g(h(e.descriptor.ctor(),e.descriptor.gtype),e.descriptor.gtype,i),o=n===void 0?m(a):p(a,n,e.descriptor.gtype),c=i in e.props?e.props[i]:void 0;if(n===void 0?delete e.props[i]:e.props[i]=n,e.widget){if((a.flags&v.ParamFlags.CONSTRUCT_ONLY)!==0)return rebuild(e,i,c);s();try{e.widget.set_property(i,o)}finally{l()}}}function setEventHandler(e,t,n){e.widget?d(e,t,n):n&&assertSignalExists(e,t),n?e.listeners.set(t,n):e.listeners.delete(t)}function assertSignalExists(t,n){let r=f(n,t.descriptor.eventAliases).split(`::`)[0],i=t.descriptor.ctor().$gtype;if(v.signal_lookup(r,i)===0)throw e.unknownSignal(t.descriptor.gtype,n,r)}function setSlot(e,t){if(e.slot===t)return;let n=e.parent;if(!n||!e.widget){e.slot=t;return}let r=e.slot;replaceAt(e,n,()=>{e.slot=t},()=>{e.slot=r})}function replaceAt(e,t,n,r){o(t,e),e.attached=!1,n();try{attach(t,e)}catch(n){r();try{attach(t,e)}catch{}throw n}}function rebuild(e,t,n){let r=e.parent;if(e.widget){c(e);for(let t of childSnapshot(e))t.kind===`element`&&(o(e,t),t.attached=!1);r&&o(r,e)}e.widget=null,e.wrapper=null,e.attached=!1;try{materialize(e)}catch(i){t!==void 0&&(n===void 0?delete e.props[t]:e.props[t]=n);try{materialize(e),r&&attach(r,e)}catch{}throw i}r&&attach(r,e)}function setText(e,t){e.data=t,e.kind===`text`&&e.parent&&flushText(e.parent)}function setElementText(e,t){writeTextSink(e,t),e.textFromChildren=!1;for(let t of childSnapshot(e))destroy(t)}function flushText(e){let t=``,n=!1;for(let r of childNodes(e))r.kind===`text`&&(t+=r.data,n=!0);t===``&&!e.textFromChildren||(writeTextSink(e,t),e.textFromChildren=n)}function writeTextSink(t,n){let r=t.descriptor.textSink;if(!r)throw e.textNotAccepted(t.descriptor.gtype,n);materialize(t);let i=g(h(t.descriptor.ctor(),t.descriptor.gtype),t.descriptor.gtype,r);s();try{t.widget.set_property(r,p(i,n,t.descriptor.gtype))}finally{l()}t.props[r]=n}function*childNodes(e){for(let t=e.first;t;t=t.next)yield t}function childSnapshot(e){let t=[];for(let n=e.first;n;n=n.next)t.push(n);return t}function link(e,t,n){t.parent=e,n?(t.prev=n.prev,t.next=n,n.prev?n.prev.next=t:e.first=t,n.prev=t):(t.prev=e.last,t.next=null,e.last?e.last.next=t:e.first=t,e.last=t)}function unlink(e){let t=e.parent;t&&(e.prev?e.prev.next=e.next:t.first=e.next,e.next?e.next.prev=e.prev:t.last=e.prev,e.prev=null,e.next=null,e.parent=null)}function attach(e,t){if(!e.widget)return;materialize(t),ensureWrapper(e,t);let n=null,a=0;for(let i=e.first;i&&i!==t;i=i.next)i.kind!==`element`||!i.attached||(n=r(i),a+=1);let o=[];for(let e=t.next;e;e=e.next)e.kind===`element`&&e.attached&&o.push(e);i({parent:e,child:t,prevWidget:n,index:a,following:o}),t.attached=!0}function ensureWrapper(e,t){if(t.wrapper)return;let n=a(e.descriptor.children,t.widget);n&&(t.wrapper=n)}function insert(e,t,n=null){let r=e.parent,i=e.next;e.parent&&remove(e),link(t,e,n);try{e.kind===`element`?attach(t,e):e.kind===`text`&&flushText(t)}catch(t){throw unlink(e),r&&restore(e,r,i),t}}function restore(e,t,n){try{link(t,e,n),e.kind===`element`?attach(t,e):e.kind===`text`&&flushText(t)}catch{unlink(e)}}function remove(e){let t=e.parent;t&&e.kind===`element`&&(o(t,e),e.attached=!1,e.wrapper&&=(e.wrapper.set_child(null),null)),unlink(e),t&&e.kind===`text`&&flushText(t)}function clearContainer(e){for(;e.first;)remove(e.first)}function destroy(e){if(e.kind===`element`){for(let t of childSnapshot(e))destroy(t);c(e),e.listeners.clear()}if(remove(e),e.kind===`element`){let t=e.widget;t&&typeof t.destroy==`function`&&typeof t.get_parent==`function`&&t.get_parent()===null&&t.destroy(),e.widget=null,e.wrapper=null,e.props={},e.layout=null,e.textFromChildren=!1}}function mountRoot(t,r){materialize(t);let a=r.constructor.$gtype,o=n(a);if(!o)throw e.unknownTag(gtypeNameOf(r));let s={kind:`element`,descriptor:o,widget:r,wrapper:null,slot:null,parent:null,prev:null,next:null,first:null,last:null,handlers:new Map,listeners:new Map,props:{},layout:null,textFromChildren:!1,attached:!0},c=directChildren(r);link(s,t,null);try{ensureWrapper(s,t),i({parent:s,child:t,prevWidget:c.length>0?c[c.length-1]:null,index:c.length,following:[]}),t.attached=!0}catch(e){throw unlink(t),e}}function directChildren(e){let t=[],n=e;if(typeof n.get_first_child!=`function`)return t;for(let e=n.get_first_child();e;e=e.get_next_sibling())t.push(e);return t}const gtypeNameOf=e=>v.type_name(e.constructor.$gtype),parentNode=e=>e.parent,firstChild=e=>e.first,nextSibling=e=>e.next,prevSibling=e=>e.prev;export{clearContainer,createAnchor,createElement,createText,destroy,firstChild,insert,isText,materialize,mountRoot,nextSibling,parentNode,prevSibling,remove,setElementText,setEventHandler,setProp,setSlot,setText};
|
package/lib/esm/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{GtkHostError as e}from"./errors.js";import{clearRegistry as t,hasWidget as n,lookupWidget as r,nearestRegistered as i,registerWidget as a,registerWidgets as o,registeredTags as s}from"./registry.js";import{ADW_DESCRIPTORS as c}from"./descriptors/adw.js";import{GTK_DESCRIPTORS as l}from"./descriptors/gtk.js";import{BUILTIN_DESCRIPTORS as u,registerBuiltinWidgets as d}from"./descriptors/index.js";import{addressOf as f,reorderMode as p}from"./policies.js";import{isEventProp as m,toSignalName as h}from"./signals.js";import{constructOnlyNames as g,isConstructOnly as _,isWritable as v,paramSpecs as y,toPropertyName as b}from"./props.js";import{clearContainer as x,createAnchor as S,createElement as C,createText as w,destroy as T,firstChild as E,insert as D,isText as O,materialize as k,mountRoot as A,nextSibling as j,parentNode as M,prevSibling as N,remove as P,setElementText as F,setEventHandler as I,setProp as L,setSlot as R,setText as z}from"./host.js";import"./types.js";export{c as ADW_DESCRIPTORS,u as BUILTIN_DESCRIPTORS,l as GTK_DESCRIPTORS,e as GtkHostError,f as addressOf,x as clearContainer,t as clearRegistry,g as constructOnlyNames,S as createAnchor,C as createElement,w as createText,T as destroy,E as firstChild,n as hasWidget,D as insert,_ as isConstructOnly,m as isEventProp,O as isText,v as isWritable,r as lookupWidget,k as materialize,A as mountRoot,i as nearestRegistered,j as nextSibling,y as paramSpecs,M as parentNode,N as prevSibling,d as registerBuiltinWidgets,a as registerWidget,o as registerWidgets,s as registeredTags,P as remove,p as reorderMode,F as setElementText,I as setEventHandler,L as setProp,R as setSlot,z as setText,b as toPropertyName,h as toSignalName};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import{GtkHostError as e,err as t}from"./errors.js";import n from"gi://Gtk?version=4.0";function addressOf(e){let n=e.wrapper??e.widget;if(!n)throw t.notAWidget(e.descriptor.gtype);return n}function makeWrapper(e,t){if(e.kind!==`indexed`||!e.wrap)return null;if(e.wrap===`list-box-row`){if(t instanceof n.ListBoxRow)return null;let e=new n.ListBoxRow;return e.set_child(t),e}if(t instanceof n.FlowBoxChild)return null;let r=new n.FlowBoxChild;return r.set_child(t),r}function insertChild(n){try{placeChild(n)}catch(r){throw r instanceof e?r:t.rejectedChild(n.parent.descriptor.gtype,n.child.descriptor.gtype,r.message)}}function placeChild(e){let{parent:n,child:r}=e,i=n.descriptor.children,a=n.widget,o=addressOf(r);switch(i.kind){case`none`:throw t.unclaimedChild(n.descriptor.gtype,r.descriptor.gtype);case`single`:a[i.set](o);return;case`indexed`:a[i.insert](o,e.index);return;case`coords`:appendChild(n,r,a);return;case`ordered`:if(i.after){a[i.after](o,e.prevWidget??null);return}case`slotted`:case`keyed`:appendChild(n,r,a),rotateTail(n,r,e.following,a);return}}function appendChild(e,n,r){let i=e.descriptor.children,a=addressOf(n);switch(i.kind){case`ordered`:r[i.append](a);return;case`slotted`:{let o=n.slot??i.defaultSlot,s=i.slots[o];if(!s)throw t.unknownSlot(e.descriptor.gtype,o,Object.keys(i.slots));r[s](a);return}case`keyed`:{let e=n.layout?.[i.nameFrom]??n.slot,t=n.layout?.title;i.titled?r[i.add](a,e??null,t??e??``):r[i.add](a);return}case`coords`:{let e=n.layout??{};r[i.attach](a,e.column??0,e.row??0,e.columnSpan??1,e.rowSpan??1);return}default:throw t.unclaimedChild(e.descriptor.gtype,n.descriptor.gtype)}}function rotateTail(e,t,n,r){let i=e.descriptor.children,a=n;if(i.kind===`slotted`){let slotOf=e=>e.slot??i.defaultSlot,e=slotOf(t);if(i.slots[e]?.startsWith(`set_`))return;a=n.filter(t=>slotOf(t)===e)}for(let t of a)detachChild(e,t,r);for(let t of a)appendChild(e,t,r)}function detachChild(e,t,n){let r=e.descriptor.children,i=t.wrapper??t.widget;if(i)switch(r.kind){case`none`:return;case`single`:clearIfCurrent(n,r.set,i);return;case`slotted`:{let e=r.slots[t.slot??r.defaultSlot];if(e?.startsWith(`set_`)){clearIfCurrent(n,e,i);return}n[r.remove](i);return}case`ordered`:case`indexed`:case`keyed`:case`coords`:n[r.remove](i);return}}function clearIfCurrent(e,t,n){let r=t.replace(/^set_/,`get_`),i=typeof e[r]==`function`?e[r]():void 0;(i===void 0||i===n)&&e[t](null)}function removeChild(e,t){let n=e.widget;n&&t.attached&&detachChild(e,t,n)}function reorderMode(e){switch(e.kind){case`ordered`:return e.reorder;case`indexed`:return`native`;case`slotted`:case`keyed`:return`remove-all`;case`coords`:case`single`:case`none`:return`n/a`}}export{addressOf,insertChild,makeWrapper,removeChild,reorderMode};
|
package/lib/esm/props.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import{err as e}from"./errors.js";import t from"gi://GObject";import n from"gi://Adw?version=1";import r from"gi://Gtk?version=4.0";import i from"gi://Gdk?version=4.0";import a from"gi://Pango";const o=[[`Gtk`,r],[`Adw`,n],[`Gdk`,i],[`Pango`,a],[`G`,t]];function toPropertyName(e){return e.includes(`-`)?e:e.replace(/([a-z0-9])([A-Z])/g,`$1-$2`).toLowerCase()}const s=new Map;function paramSpecs(e,t){let n=s.get(t);if(n)return n;n=new Map;for(let t of e.list_properties())n.set(t.get_name(),t);return s.set(t,n),n}const isFlag=(e,t)=>(e&t)!==0,isWritable=e=>isFlag(e.flags,t.ParamFlags.WRITABLE),isConstructOnly=e=>isFlag(e.flags,t.ParamFlags.CONSTRUCT_ONLY);function constructOnlyNames(e,t){let n=[];for(let[r,i]of paramSpecs(e,t))isConstructOnly(i)&&isWritable(i)&&n.push(r);return n}function resolveEnumValue(e,t){for(let[n,r]of o){if(!e.startsWith(n))continue;let i=r[e.slice(n.length)];if(!i)continue;let a=i[t.toUpperCase().replace(/-/g,`_`)];return typeof a==`number`?{resolved:!0,value:a}:{resolved:!0}}return{resolved:!1}}function coerce(n,r,i){if(r==null)return r;let a=n.value_type;if(t.type_is_a(a,t.TYPE_ENUM)&&typeof r==`string`){let o=t.type_name(a),s=resolveEnumValue(o,r);if(s.value!==void 0)return s.value;throw s.resolved?e.badEnum(i,n.get_name(),r,o):e.unresolvableEnum(o)}if(t.type_is_a(a,t.TYPE_FLAGS)&&typeof r==`string`)throw e.badFlags(i,n.get_name(),r,t.type_name(a));if(t.type_is_a(a,t.TYPE_BOOLEAN)){if(typeof r==`boolean`)return r;if(r===`true`)return!0;if(r===`false`)return!1;if(typeof r==`string`)throw e.badBoolean(i,n.get_name(),r);return!!r}if(t.type_is_a(a,t.TYPE_STRING)){if(typeof r==`string`)return r;if(typeof r==`number`||typeof r==`boolean`)return String(r);throw e.badString(i,n.get_name(),typeof r)}return(t.type_is_a(a,t.TYPE_INT)||t.type_is_a(a,t.TYPE_UINT)||t.type_is_a(a,t.TYPE_INT64)||t.type_is_a(a,t.TYPE_UINT64))&&typeof r==`number`?Math.trunc(r):r}function defaultValue(e){return e.get_default_value()}function requireSpec(t,n,r){let i=t.get(r);if(!i)throw e.unknownProp(n,r);if(!isWritable(i))throw e.readOnlyProp(n,r);return i}export{coerce,constructOnlyNames,defaultValue,isConstructOnly,isWritable,paramSpecs,requireSpec,toPropertyName};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import{err as e}from"./errors.js";import t from"gi://GObject";const n=new Map;function registerWidget(e){n.set(e.gtype,e)}function registerWidgets(e){for(let t of e)registerWidget(t)}function lookupWidget(t){let r=n.get(t);if(!r)throw e.unknownTag(t);return r}const hasWidget=e=>n.has(e),registeredTags=()=>[...n.keys()].sort();function nearestRegistered(e){let r,i=-1;for(let a of n.values()){let n;try{n=a.ctor().$gtype}catch{continue}if(!t.type_is_a(e,n))continue;let o=depthOf(n);o>i&&(r=a,i=o)}return r}function depthOf(e){let n=0,r=e;for(;r;){let e=t.type_parent(r);if(!e)break;n+=1,r=e}return n}function clearRegistry(){n.clear()}export{clearRegistry,hasWidget,lookupWidget,nearestRegistered,registerWidget,registerWidgets,registeredTags};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import{err as e}from"./errors.js";function toSignalName(e,t){if(t?.[e])return t[e];if(e.startsWith(`on:`))return e.slice(3);let n=e.slice(2);return n.startsWith(`Notify`)?`notify::${kebab(n.slice(6))}`:kebab(n)}const kebab=e=>e.replace(/^./,e=>e.toLowerCase()).replace(/([a-z0-9])([A-Z])/g,`$1-$2`).toLowerCase();function isEventProp(e){return e.startsWith(`on:`)||e.length>2&&e.startsWith(`on`)&&e[2]===e[2].toUpperCase()&&e[2]!==e[2].toLowerCase()}let t=0;const beginHostWrite=()=>{t+=1},endHostWrite=()=>{--t},inHostWrite=()=>t>0;function setHandler(t,n,r){let i=toSignalName(n,t.descriptor.eventAliases),a=t.handlers.get(i),o=t.widget;if(a&&a.prop!==n&&r)throw e.signalTaken(t.descriptor.gtype,n,a.prop,i);if(a&&(o.disconnect(a.id),t.handlers.delete(i)),!r)return;let s=i.startsWith(`notify::`),c=o.connect(i,(...e)=>{if(!(s&&inHostWrite()))return r(...e.slice(1))});t.handlers.set(i,{id:c,prop:n})}function clearHandlers(e){if(!e.widget){e.handlers.clear();return}let t=e.widget;for(let{id:n}of e.handlers.values())t.disconnect(n);e.handlers.clear()}export{beginHostWrite,clearHandlers,endHostWrite,inHostWrite,isEventProp,setHandler,toSignalName};
|
package/lib/esm/types.js
ADDED
|
File without changes
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface DiagnosticsGate {
|
|
2
|
+
/** Warning-or-worse messages seen since the last `reset()`. */
|
|
3
|
+
readonly seen: readonly string[];
|
|
4
|
+
reset(): void;
|
|
5
|
+
/** Throw if anything was recorded, naming every message. */
|
|
6
|
+
assertQuiet(context?: string): void;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Install the writer func once per process and return the gate.
|
|
10
|
+
*
|
|
11
|
+
* `GLib.log_set_writer_func` is process-global and replaces GLib's own writer, so
|
|
12
|
+
* this forwards rather than swallows — a writer that ate its input would hide the
|
|
13
|
+
* messages it exists to detect, including its own. The forward threshold matches
|
|
14
|
+
* what GLib's default writer does with `G_MESSAGES_DEBUG` unset: message-and-above
|
|
15
|
+
* is printed, info/debug is not.
|
|
16
|
+
*/
|
|
17
|
+
export declare function installDiagnosticsGate(): DiagnosticsGate;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export { installDiagnosticsGate, type DiagnosticsGate } from './diagnostics.js';
|
|
2
|
+
import type Gtk from '@girs/gtk-4.0';
|
|
3
|
+
import type { ChildPolicy, HostElement, WidgetDescriptor } from '../types.js';
|
|
4
|
+
/** Every method name a policy names, so the check does not have to know the shapes. */
|
|
5
|
+
export declare function methodsOf(policy: ChildPolicy): string[];
|
|
6
|
+
export interface DescriptorProblem {
|
|
7
|
+
gtype: string;
|
|
8
|
+
problem: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Assert the table against the installed typelib.
|
|
12
|
+
*
|
|
13
|
+
* A descriptor may name a method that does not exist — libadwaita renames, a
|
|
14
|
+
* distro ships an older GTK, a copy/paste survives review. Calling it produces
|
|
15
|
+
* `TypeError: host[policy.append] is not a function` deep inside a render, so
|
|
16
|
+
* the check runs up front and names the widget.
|
|
17
|
+
*/
|
|
18
|
+
export declare function descriptorProblems(descriptors?: readonly WidgetDescriptor[]): DescriptorProblem[];
|
|
19
|
+
/** Direct GTK children of a widget, in GTK's own order. */
|
|
20
|
+
export declare function gtkChildren(widget: Gtk.Widget): Gtk.Widget[];
|
|
21
|
+
/** GType names of a widget's direct children — the cheap shape assertion. */
|
|
22
|
+
export declare const gtkChildTypes: (widget: Gtk.Widget) => string[];
|
|
23
|
+
/** The addresses a host element's element-children occupy, in shadow order. */
|
|
24
|
+
export declare function addressesOf(el: HostElement): Gtk.Widget[];
|
|
25
|
+
/** Recursive GType dump — what a devtools tree walk would show. */
|
|
26
|
+
export declare function dumpTree(widget: Gtk.Widget, depth?: number): string;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { GTK_DESCRIPTORS } from './gtk.js';
|
|
2
|
+
export { ADW_DESCRIPTORS } from './adw.js';
|
|
3
|
+
export declare const BUILTIN_DESCRIPTORS: import("../types.js").WidgetDescriptor[];
|
|
4
|
+
/** Install the built-in table. Idempotent — registration is keyed on the GType name. */
|
|
5
|
+
export declare function registerBuiltinWidgets(): void;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every failure this host reports names the tag, the property and the fix.
|
|
3
|
+
*
|
|
4
|
+
* The reason is measured, not stylistic: GTK's own failure mode is Exit 0.
|
|
5
|
+
* Writing a string nick to an enum property is a SILENT no-op through both
|
|
6
|
+
* `set_property()` and the JS setter (`box.orientation = 'vertical'` leaves it
|
|
7
|
+
* at `HORIZONTAL`, gjs 1.88.1); writing a read-only property does not throw; and
|
|
8
|
+
* a mis-parented widget floods stderr with `Gtk-WARNING` while the process still
|
|
9
|
+
* exits 0. A renderer that stays quiet here produces a wrong window and a green
|
|
10
|
+
* test run, so this host is loud on purpose.
|
|
11
|
+
*/
|
|
12
|
+
export declare class GtkHostError extends Error {
|
|
13
|
+
readonly code: string;
|
|
14
|
+
readonly name = "GtkHostError";
|
|
15
|
+
constructor(code: string, message: string);
|
|
16
|
+
}
|
|
17
|
+
export declare const err: {
|
|
18
|
+
unknownTag: (tag: string) => GtkHostError;
|
|
19
|
+
unknownProp: (tag: string, prop: string) => GtkHostError;
|
|
20
|
+
readOnlyProp: (tag: string, prop: string) => GtkHostError;
|
|
21
|
+
badEnum: (tag: string, prop: string, nick: string, gtypeName: string) => GtkHostError;
|
|
22
|
+
unknownSignal: (tag: string, prop: string, signal: string) => GtkHostError;
|
|
23
|
+
signalTaken: (tag: string, prop: string, other: string, signal: string) => GtkHostError;
|
|
24
|
+
badString: (tag: string, prop: string, got: string) => GtkHostError;
|
|
25
|
+
badBoolean: (tag: string, prop: string, value: string) => GtkHostError;
|
|
26
|
+
badFlags: (tag: string, prop: string, value: string, gtypeName: string) => GtkHostError;
|
|
27
|
+
unresolvableEnum: (gtypeName: string) => GtkHostError;
|
|
28
|
+
textNotAccepted: (tag: string, text: string) => GtkHostError;
|
|
29
|
+
unclaimedChild: (parentTag: string, childTag: string) => GtkHostError;
|
|
30
|
+
unknownSlot: (parentTag: string, slot: string, known: string[]) => GtkHostError;
|
|
31
|
+
rejectedChild: (parentTag: string, childTag: string, reason: string) => GtkHostError;
|
|
32
|
+
notAWidget: (tag: string) => GtkHostError;
|
|
33
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import GObject from 'gi://GObject';
|
|
2
|
+
import type Gtk from '@girs/gtk-4.0';
|
|
3
|
+
import type { HostAnchor, HostElement, HostNode, HostText, WidgetDescriptor } from './types.js';
|
|
4
|
+
export declare function createElement(tag: string, props?: Record<string, unknown>): HostElement;
|
|
5
|
+
export declare const createText: (data: string) => HostText;
|
|
6
|
+
/**
|
|
7
|
+
* A position marker with no widget. Vue's `createComment` lands here, and so
|
|
8
|
+
* does every `v-if`/`<Show>` boundary.
|
|
9
|
+
*
|
|
10
|
+
* Anchors never enter the GTK tree. Insertion resolves forward past them to the
|
|
11
|
+
* next node that owns a widget — which is why an empty branch cannot shift a
|
|
12
|
+
* sibling's index.
|
|
13
|
+
*/
|
|
14
|
+
export declare const createAnchor: (data?: string) => HostAnchor;
|
|
15
|
+
export declare const isText: (node: HostNode) => node is HostText;
|
|
16
|
+
/**
|
|
17
|
+
* Build the GObject. Deferred until the widget is actually needed, because
|
|
18
|
+
* construct-only properties must all be known at `g_object_new` time — and
|
|
19
|
+
* Solid's `createElement(tag)` contract hands over no properties at all.
|
|
20
|
+
*/
|
|
21
|
+
export declare function materialize(el: HostElement): GObject.Object;
|
|
22
|
+
export declare function setProp(el: HostElement, key: string, next: unknown, _prev?: unknown): void;
|
|
23
|
+
export declare function setEventHandler(el: HostElement, prop: string, next: ((...args: unknown[]) => unknown) | null): void;
|
|
24
|
+
export declare function setSlot(el: HostElement, slot: string | null): void;
|
|
25
|
+
export declare function setText(node: HostText | HostAnchor, data: string): void;
|
|
26
|
+
/** Vue's bulk path and React's `shouldSetTextContent`: drop children, set the sink. */
|
|
27
|
+
export declare function setElementText(el: HostElement, text: string): void;
|
|
28
|
+
export declare function insert(node: HostNode, parent: HostElement, anchor?: HostNode | null): void;
|
|
29
|
+
/** Detach only — reversible. Frameworks move nodes; `remove` must not destroy one. */
|
|
30
|
+
export declare function remove(node: HostNode): void;
|
|
31
|
+
export declare function clearContainer(parent: HostElement): void;
|
|
32
|
+
/**
|
|
33
|
+
* Tear a subtree down: disconnect every handler, unparent, drop the reference.
|
|
34
|
+
*
|
|
35
|
+
* It is eager and it is the only place a handler dies. GJS blocks JS callbacks
|
|
36
|
+
* during GC ("The offending callback was `dispose()`"), so whatever is not
|
|
37
|
+
* disconnected here stays connected for the life of the process.
|
|
38
|
+
*
|
|
39
|
+
* A toplevel window is the one node unparenting cannot reach — it has no parent
|
|
40
|
+
* and its `GtkApplication` still holds it — so it is closed explicitly.
|
|
41
|
+
*/
|
|
42
|
+
export declare function destroy(node: HostNode): void;
|
|
43
|
+
/**
|
|
44
|
+
* Put a host tree inside an existing GTK container the application owns.
|
|
45
|
+
*
|
|
46
|
+
* The container is resolved through the SAME table as every other parent —
|
|
47
|
+
* `nearestRegistered` walks the real type hierarchy, so an application's own
|
|
48
|
+
* `GObject.registerClass` subclass inherits its ancestor's policy. Guessing a
|
|
49
|
+
* method name here would be the generic `add` that GTK4 deliberately removed.
|
|
50
|
+
*/
|
|
51
|
+
export declare function mountRoot(el: HostElement, container: Gtk.Widget): void;
|
|
52
|
+
export declare const parentNode: (node: HostNode) => HostElement | null;
|
|
53
|
+
export declare const firstChild: (el: HostElement) => HostNode | null;
|
|
54
|
+
export declare const nextSibling: (node: HostNode) => HostNode | null;
|
|
55
|
+
export declare const prevSibling: (node: HostNode) => HostNode | null;
|
|
56
|
+
export type { WidgetDescriptor };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from './types.js';
|
|
2
|
+
export { GtkHostError } from './errors.js';
|
|
3
|
+
export { createAnchor, createElement, createText, clearContainer, destroy, firstChild, insert, isText, materialize, mountRoot, nextSibling, parentNode, prevSibling, remove, setElementText, setEventHandler, setProp, setSlot, setText, } from './host.js';
|
|
4
|
+
export { addressOf, reorderMode } from './policies.js';
|
|
5
|
+
export { toSignalName, isEventProp } from './signals.js';
|
|
6
|
+
export { constructOnlyNames, isConstructOnly, isWritable, paramSpecs, toPropertyName } from './props.js';
|
|
7
|
+
export { clearRegistry, hasWidget, lookupWidget, nearestRegistered, registerWidget, registerWidgets, registeredTags, } from './registry.js';
|
|
8
|
+
export { ADW_DESCRIPTORS, BUILTIN_DESCRIPTORS, GTK_DESCRIPTORS, registerBuiltinWidgets } from './descriptors/index.js';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import Gtk from 'gi://Gtk?version=4.0';
|
|
2
|
+
import type { ChildPolicy, HostElement } from './types.js';
|
|
3
|
+
/** The object the PARENT addresses: a wrapper row when the policy demands one. */
|
|
4
|
+
export declare function addressOf(el: HostElement): Gtk.Widget;
|
|
5
|
+
/**
|
|
6
|
+
* `Gtk.ListBox` and `Gtk.FlowBox` wrap arbitrary children; the wrap is the host's job.
|
|
7
|
+
*
|
|
8
|
+
* Unless the author already wrote the row themselves — `<GtkListBox><GtkListBoxRow>`
|
|
9
|
+
* is the spelling anyone reaching for `activatable` or `selectable` uses, and
|
|
10
|
+
* wrapping a row inside a second row nests two selectable widgets and detaches
|
|
11
|
+
* activation from the one the author configured.
|
|
12
|
+
*/
|
|
13
|
+
export declare function makeWrapper(policy: ChildPolicy, child: Gtk.Widget): Gtk.Widget | null;
|
|
14
|
+
export interface Placement {
|
|
15
|
+
parent: HostElement;
|
|
16
|
+
child: HostElement;
|
|
17
|
+
/** Address of the preceding element sibling, or null when the child goes first. */
|
|
18
|
+
prevWidget: Gtk.Widget | null;
|
|
19
|
+
/** Index among ELEMENT siblings — text and anchors do not count. */
|
|
20
|
+
index: number;
|
|
21
|
+
/**
|
|
22
|
+
* Element siblings after the insertion point, in order.
|
|
23
|
+
*
|
|
24
|
+
* ELEMENTS, not widgets: a container that cannot insert is re-placed by
|
|
25
|
+
* rotating its tail, and re-placing a child needs the child's own slot or
|
|
26
|
+
* page name, which a bare `Gtk.Widget` cannot answer.
|
|
27
|
+
*/
|
|
28
|
+
following: HostElement[];
|
|
29
|
+
}
|
|
30
|
+
export declare function insertChild(place: Placement): void;
|
|
31
|
+
export declare function removeChild(parent: HostElement, child: HostElement): void;
|
|
32
|
+
/** Does this parent reorder in place, or does it pay a full re-append? Declared, not guessed. */
|
|
33
|
+
export declare function reorderMode(policy: ChildPolicy): 'native' | 'remove-all' | 'n/a';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import GObject from 'gi://GObject';
|
|
2
|
+
/** `backgroundColor` and `background-color` both name the GObject property `background-color`. */
|
|
3
|
+
export declare function toPropertyName(name: string): string;
|
|
4
|
+
/** All ParamSpecs of a class, by kebab name. Cached per GType — `list_properties()` is not cheap. */
|
|
5
|
+
export declare function paramSpecs(klass: GObject.ObjectClass, gtypeName: string): Map<string, GObject.ParamSpec>;
|
|
6
|
+
export declare const isWritable: (spec: GObject.ParamSpec) => boolean;
|
|
7
|
+
export declare const isConstructOnly: (spec: GObject.ParamSpec) => boolean;
|
|
8
|
+
/** Construct-only property names of a class, in declaration order. */
|
|
9
|
+
export declare function constructOnlyNames(klass: GObject.ObjectClass, gtypeName: string): string[];
|
|
10
|
+
/**
|
|
11
|
+
* Turn an authored value into one GObject will actually store.
|
|
12
|
+
*
|
|
13
|
+
* The enum branch is the whole reason this function exists: GObject accepts a
|
|
14
|
+
* string for an enum property and silently keeps the old value. Measured on
|
|
15
|
+
* gjs 1.88.1 — `set_property('orientation', 'vertical')` emits
|
|
16
|
+
* `GLib-GObject-CRITICAL` and leaves HORIZONTAL, and the JS setter
|
|
17
|
+
* `box.orientation = 'vertical'` does the same without any diagnostic at all.
|
|
18
|
+
*/
|
|
19
|
+
export declare function coerce(spec: GObject.ParamSpec, value: unknown, tag: string): unknown;
|
|
20
|
+
/**
|
|
21
|
+
* The value a property falls back to when a renderer removes it.
|
|
22
|
+
*
|
|
23
|
+
* React hands `undefined` for a prop that disappeared, and GObject cannot store
|
|
24
|
+
* that: `set_property(name, undefined)` throws "Could not guess unspecified
|
|
25
|
+
* GValue type" (measured). The ParamSpec knows the right answer.
|
|
26
|
+
*/
|
|
27
|
+
export declare function defaultValue(spec: GObject.ParamSpec): unknown;
|
|
28
|
+
/** Look a property up, refusing the two silent failures: unknown and read-only. */
|
|
29
|
+
export declare function requireSpec(specs: Map<string, GObject.ParamSpec>, tag: string, name: string): GObject.ParamSpec;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import GObject from 'gi://GObject';
|
|
2
|
+
import type { WidgetDescriptor } from './types.js';
|
|
3
|
+
export declare function registerWidget(descriptor: WidgetDescriptor): void;
|
|
4
|
+
export declare function registerWidgets(descriptors: readonly WidgetDescriptor[]): void;
|
|
5
|
+
export declare function lookupWidget(tag: string): WidgetDescriptor;
|
|
6
|
+
export declare const hasWidget: (tag: string) => boolean;
|
|
7
|
+
/** Every registered tag — the conformance suite walks this, so coverage is data. */
|
|
8
|
+
export declare const registeredTags: () => string[];
|
|
9
|
+
/**
|
|
10
|
+
* The nearest registered ancestor of a GType, most specific first.
|
|
11
|
+
*
|
|
12
|
+
* Registration is exact, but a consumer may subclass (`GObject.registerClass`)
|
|
13
|
+
* and still want its parent's placement rules. Dispatch walks the real type
|
|
14
|
+
* hierarchy rather than a name prefix, which is why `Gtk.HeaderBar` and
|
|
15
|
+
* `Adw.HeaderBar` can never be confused for one another.
|
|
16
|
+
*/
|
|
17
|
+
export declare function nearestRegistered(gtype: GObject.GType): WidgetDescriptor | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Drop every registration.
|
|
20
|
+
*
|
|
21
|
+
* A seam for a consumer that wants a table of its own — nothing in this package
|
|
22
|
+
* calls it, and the specs deliberately share the module-global table because
|
|
23
|
+
* that is what an application sees.
|
|
24
|
+
*/
|
|
25
|
+
export declare function clearRegistry(): void;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { HostElement } from './types.js';
|
|
2
|
+
/** `onRowActivated` -> `row-activated`; `onNotifyVisible` -> `notify::visible`. */
|
|
3
|
+
export declare function toSignalName(prop: string, aliases?: Readonly<Record<string, string>>): string;
|
|
4
|
+
/** An event prop is `on:` + a raw signal name, or `on` + an uppercase letter. */
|
|
5
|
+
export declare function isEventProp(prop: string): boolean;
|
|
6
|
+
export declare const beginHostWrite: () => void;
|
|
7
|
+
export declare const endHostWrite: () => void;
|
|
8
|
+
export declare const inHostWrite: () => boolean;
|
|
9
|
+
export declare function setHandler(el: HostElement, prop: string, next: ((...args: unknown[]) => unknown) | null): void;
|
|
10
|
+
/** Disconnect every handler on a node. The only place a handler dies. */
|
|
11
|
+
export declare function clearHandlers(el: HostElement): void;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import type GObject from '@girs/gobject-2.0';
|
|
2
|
+
import type Gtk from '@girs/gtk-4.0';
|
|
3
|
+
export type NodeKind = 'element' | 'text' | 'anchor';
|
|
4
|
+
export interface HostNodeBase {
|
|
5
|
+
readonly kind: NodeKind;
|
|
6
|
+
parent: HostElement | null;
|
|
7
|
+
prev: HostNode | null;
|
|
8
|
+
next: HostNode | null;
|
|
9
|
+
}
|
|
10
|
+
/** A text run. GTK has no text node — the OWNING element writes it to its text sink. */
|
|
11
|
+
export interface HostText extends HostNodeBase {
|
|
12
|
+
readonly kind: 'text';
|
|
13
|
+
data: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* A position marker. Vue's `createComment` and Svelte's comment markers land here.
|
|
17
|
+
* An anchor NEVER enters the GTK tree; `insert` resolves forward past it to the
|
|
18
|
+
* next node that actually owns a widget.
|
|
19
|
+
*/
|
|
20
|
+
export interface HostAnchor extends HostNodeBase {
|
|
21
|
+
readonly kind: 'anchor';
|
|
22
|
+
data: string;
|
|
23
|
+
}
|
|
24
|
+
export interface HostElement extends HostNodeBase {
|
|
25
|
+
readonly kind: 'element';
|
|
26
|
+
readonly descriptor: WidgetDescriptor;
|
|
27
|
+
/** null until materialisation — construct-only properties must be known first. */
|
|
28
|
+
widget: GObject.Object | null;
|
|
29
|
+
/** `Gtk.ListBoxRow` & friends: the object the PARENT addresses, not the child itself. */
|
|
30
|
+
wrapper: Gtk.Widget | null;
|
|
31
|
+
/** Declared by the CHILD (`slot="end"`), not derived from its position. */
|
|
32
|
+
slot: string | null;
|
|
33
|
+
first: HostNode | null;
|
|
34
|
+
last: HostNode | null;
|
|
35
|
+
/**
|
|
36
|
+
* signal name -> the one native handler, and the prop that owns it.
|
|
37
|
+
*
|
|
38
|
+
* One handler per signal name, ever. The owner is recorded because two props
|
|
39
|
+
* can resolve to the same signal (`onClicked` and `on:clicked`), and the
|
|
40
|
+
* second used to disconnect the first without saying so.
|
|
41
|
+
*/
|
|
42
|
+
handlers: Map<string, {
|
|
43
|
+
id: number;
|
|
44
|
+
prop: string;
|
|
45
|
+
}>;
|
|
46
|
+
/** Authored property values, kebab-normalised. Kept after materialisation so a
|
|
47
|
+
* construct-only change can rebuild the widget from the same intent. */
|
|
48
|
+
props: Record<string, unknown>;
|
|
49
|
+
/** Authored signal callbacks by prop name — a rebuild has to re-bind them. */
|
|
50
|
+
listeners: Map<string, (...args: unknown[]) => unknown>;
|
|
51
|
+
/** Positional data for `coords` parents (`Gtk.Grid`), read off the child. */
|
|
52
|
+
layout: Record<string, unknown> | null;
|
|
53
|
+
/** True once text CHILDREN wrote the sink, so removing the last one clears it
|
|
54
|
+
* instead of leaving the stale string an authored prop never set. */
|
|
55
|
+
textFromChildren: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* True while this element is actually IN its parent's GTK tree.
|
|
58
|
+
*
|
|
59
|
+
* Owning a widget is not the same thing: every framework builds bottom-up,
|
|
60
|
+
* so a subtree is materialised long before it is inserted. Deriving "is my
|
|
61
|
+
* sibling in the tree" from `widget !== null` made the remove-all policy
|
|
62
|
+
* detach non-children and re-add already-parented ones — two Adwaita
|
|
63
|
+
* criticals per replay, at exit 0.
|
|
64
|
+
*/
|
|
65
|
+
attached: boolean;
|
|
66
|
+
}
|
|
67
|
+
export type HostNode = HostElement | HostText | HostAnchor;
|
|
68
|
+
export type PolicyKind = 'none' | 'single' | 'ordered' | 'indexed' | 'slotted' | 'keyed' | 'coords';
|
|
69
|
+
/**
|
|
70
|
+
* How a parent adopts children. GTK4 deleted `GtkContainer`, so there is no
|
|
71
|
+
* generic `add` — and `Gtk.Buildable.add_child` is introspected as a vfunc only
|
|
72
|
+
* (`typeof headerBar.add_child === 'undefined'`, measured on gjs 1.88.1), so it
|
|
73
|
+
* is not an escape hatch either. Every container states its own rules here.
|
|
74
|
+
*/
|
|
75
|
+
export type ChildPolicy = {
|
|
76
|
+
kind: 'none';
|
|
77
|
+
}
|
|
78
|
+
/** `set_child` / `set_content` / `set_titlebar`: at most one child. */
|
|
79
|
+
| {
|
|
80
|
+
kind: 'single';
|
|
81
|
+
set: string;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Sequential children. `after` is the O(1) reorder path
|
|
85
|
+
* (`Gtk.Box.insert_child_after`); a container without it — `Adw.PreferencesGroup`
|
|
86
|
+
* has `add`/`remove` but no `insert`, measured — declares `reorder: 'remove-all'`
|
|
87
|
+
* and pays a full re-append per reorder. That degradation is DECLARED, never silent.
|
|
88
|
+
*/
|
|
89
|
+
| {
|
|
90
|
+
kind: 'ordered';
|
|
91
|
+
append: string;
|
|
92
|
+
after?: string;
|
|
93
|
+
remove: string;
|
|
94
|
+
reorder: 'native' | 'remove-all';
|
|
95
|
+
}
|
|
96
|
+
/** `Gtk.ListBox`/`Gtk.FlowBox`: index-addressed, and the parent addresses a WRAPPER row. */
|
|
97
|
+
| {
|
|
98
|
+
kind: 'indexed';
|
|
99
|
+
insert: string;
|
|
100
|
+
remove: string;
|
|
101
|
+
wrap: 'list-box-row' | 'flow-box-child' | null;
|
|
102
|
+
}
|
|
103
|
+
/** `Adw.HeaderBar`, `Adw.ToolbarView`, `Adw.ActionRow`: named attachment points. */
|
|
104
|
+
| {
|
|
105
|
+
kind: 'slotted';
|
|
106
|
+
slots: Record<string, string>;
|
|
107
|
+
defaultSlot: string;
|
|
108
|
+
remove: string;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* `Gtk.Stack`, `Adw.NavigationView`: children addressed by name/tag.
|
|
112
|
+
*
|
|
113
|
+
* `titled` states the ARITY, because it differs and getting it wrong is not
|
|
114
|
+
* a type error: `gtk_stack_add_titled(child, name, title)` requires all
|
|
115
|
+
* three and GJS throws "At least 3 arguments required" (measured), while
|
|
116
|
+
* `adw_navigation_view_add(page)` takes one. `descriptorProblems()` checks
|
|
117
|
+
* that a method EXISTS, never how many arguments it wants.
|
|
118
|
+
*/
|
|
119
|
+
| {
|
|
120
|
+
kind: 'keyed';
|
|
121
|
+
add: string;
|
|
122
|
+
remove: string;
|
|
123
|
+
nameFrom: string;
|
|
124
|
+
titled: boolean;
|
|
125
|
+
}
|
|
126
|
+
/** `Gtk.Grid`: position is data on the child, so document order carries nothing. */
|
|
127
|
+
| {
|
|
128
|
+
kind: 'coords';
|
|
129
|
+
attach: string;
|
|
130
|
+
remove: string;
|
|
131
|
+
};
|
|
132
|
+
export interface WidgetDescriptor {
|
|
133
|
+
/** GType name — and the tag a renderer writes. `GtkButton`, `AdwActionRow`. */
|
|
134
|
+
readonly gtype: string;
|
|
135
|
+
/** Lazy so `gi://` loads late and an unused descriptor costs nothing. */
|
|
136
|
+
readonly ctor: () => GObject.ObjectClass & (new (props?: Record<string, unknown>) => GObject.Object);
|
|
137
|
+
readonly children: ChildPolicy;
|
|
138
|
+
/**
|
|
139
|
+
* Where a text child goes. Absent means text under this widget is an ERROR
|
|
140
|
+
* that names the tag — never a silent drop.
|
|
141
|
+
*/
|
|
142
|
+
readonly textSink?: string;
|
|
143
|
+
/** `onActivate` -> `activate` is derived; irregular pairs live here, in the TABLE. */
|
|
144
|
+
readonly eventAliases?: Readonly<Record<string, string>>;
|
|
145
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gjsify/gtk-host",
|
|
3
|
+
"version": "0.41.0",
|
|
4
|
+
"description": "Framework-agnostic GTK4/Adwaita host: the element model UI-framework renderers bind to",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"module": "lib/esm/index.js",
|
|
7
|
+
"types": "lib/types/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./lib/types/index.d.ts",
|
|
11
|
+
"default": "./lib/esm/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./conformance": {
|
|
14
|
+
"types": "./lib/types/conformance/index.d.ts",
|
|
15
|
+
"default": "./lib/esm/conformance/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"lib"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"clear": "gjsify clear lib tmp tsconfig.tsbuildinfo test.gjs.mjs",
|
|
23
|
+
"check": "gjsify tsc --noEmit",
|
|
24
|
+
"build": "gjsify run build:gjsify && gjsify run build:types",
|
|
25
|
+
"build:gjsify": "gjsify build --library 'src/**/*.{ts,js}' --exclude 'src/**/*.spec.{mts,ts}' 'src/test.{mts,ts}'",
|
|
26
|
+
"build:types": "gjsify tsc",
|
|
27
|
+
"build:test": "gjsify run build:test:gjs",
|
|
28
|
+
"build:test:gjs": "gjsify build src/test.mts --app gjs --outfile test.gjs.mjs",
|
|
29
|
+
"test": "gjsify run build:gjsify && gjsify run build:test && gjsify run test:gjs",
|
|
30
|
+
"test:gjs": "gjsify run test.gjs.mjs"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"gjs",
|
|
34
|
+
"gtk",
|
|
35
|
+
"adwaita",
|
|
36
|
+
"renderer",
|
|
37
|
+
"host"
|
|
38
|
+
],
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@girs/adw-1": "^4.1.0",
|
|
41
|
+
"@girs/gdk-4.0": "^4.1.0",
|
|
42
|
+
"@girs/gjs": "^4.1.0",
|
|
43
|
+
"@girs/gobject-2.0": "^4.1.0",
|
|
44
|
+
"@girs/gtk-4.0": "^4.1.0",
|
|
45
|
+
"@girs/pango-1.0": "^4.1.0"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@gjsify/cli": "^0.41.0",
|
|
49
|
+
"@gjsify/unit": "^0.41.0",
|
|
50
|
+
"@types/node": "^25.9.2",
|
|
51
|
+
"typescript": "^6.0.3"
|
|
52
|
+
},
|
|
53
|
+
"gjsify": {
|
|
54
|
+
"runtimes": {
|
|
55
|
+
"gjs": "polyfill",
|
|
56
|
+
"node": "none",
|
|
57
|
+
"browser": "none",
|
|
58
|
+
"nativescript": "none"
|
|
59
|
+
},
|
|
60
|
+
"tier": 3
|
|
61
|
+
},
|
|
62
|
+
"license": "MIT",
|
|
63
|
+
"repository": {
|
|
64
|
+
"type": "git",
|
|
65
|
+
"url": "git+https://github.com/gjsify/gjsify.git",
|
|
66
|
+
"directory": "packages/framework/gtk-host"
|
|
67
|
+
},
|
|
68
|
+
"bugs": {
|
|
69
|
+
"url": "https://github.com/gjsify/gjsify/issues"
|
|
70
|
+
},
|
|
71
|
+
"homepage": "https://github.com/gjsify/gjsify/tree/main/packages/framework/gtk-host#readme"
|
|
72
|
+
}
|