@gjsify/gtk-host 0.46.0 → 0.48.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 (40) hide show
  1. package/README.md +55 -1
  2. package/lib/esm/conformance/index.js +1 -2
  3. package/lib/esm/conformance/tree.js +2 -0
  4. package/lib/esm/conformance/window-chrome.js +1 -0
  5. package/lib/esm/descriptors/adw.js +1 -1
  6. package/lib/esm/errors.js +1 -1
  7. package/lib/esm/font-dir.js +1 -0
  8. package/lib/esm/fonts.js +1 -0
  9. package/lib/esm/host.js +1 -1
  10. package/lib/esm/index.js +1 -1
  11. package/lib/esm/menu.js +1 -0
  12. package/lib/esm/policies.js +1 -1
  13. package/lib/esm/probe.js +1 -1
  14. package/lib/esm/props.js +1 -1
  15. package/lib/esm/style/font-family.js +3 -0
  16. package/lib/esm/style/index.js +1 -1
  17. package/lib/esm/style/paint.js +1 -1
  18. package/lib/types/attrs.d.ts +31 -0
  19. package/lib/types/conformance/index.d.ts +18 -29
  20. package/lib/types/conformance/tree.d.ts +30 -0
  21. package/lib/types/conformance/vectors.d.mts +6 -0
  22. package/lib/types/conformance/window-chrome.d.ts +29 -0
  23. package/lib/types/errors.d.ts +11 -0
  24. package/lib/types/font-dir.d.ts +42 -0
  25. package/lib/types/font-dir.spec.d.ts +2 -0
  26. package/lib/types/fonts.d.ts +64 -0
  27. package/lib/types/fonts.spec.d.ts +2 -0
  28. package/lib/types/index.d.ts +1 -1
  29. package/lib/types/jsx-runtime.d.ts +2 -2
  30. package/lib/types/menu.d.ts +43 -0
  31. package/lib/types/menu.spec.d.ts +2 -0
  32. package/lib/types/policies.d.ts +65 -1
  33. package/lib/types/portal.spec.d.ts +2 -0
  34. package/lib/types/react-jsx-runtime.d.ts +2 -2
  35. package/lib/types/style/font-family.d.ts +64 -0
  36. package/lib/types/style/index.d.ts +3 -1
  37. package/lib/types/style/paint.d.ts +37 -0
  38. package/lib/types/types.d.ts +79 -0
  39. package/lib/types/vue-components.d.ts +2 -2
  40. package/package.json +10 -4
package/README.md CHANGED
@@ -77,7 +77,8 @@ already-parented ones, at exit 0.
77
77
  ## Child placement
78
78
 
79
79
  Seven policy kinds, declared per widget as data and dispatched on the policy's
80
- own `kind`. Descriptor lookup is by exact GType name; `mountRoot` is the one path
80
+ own `kind` — and one widget family that takes none of them, § *Node placement*
81
+ below. Descriptor lookup is by exact GType name; `mountRoot` is the one path
81
82
  that walks the type hierarchy (`GObject.type_is_a`, via `nearestRegistered`), so
82
83
  an application's own subclass resolves to its ancestor's rules:
83
84
 
@@ -117,6 +118,59 @@ attachment point, `layout={{ column, row, columnSpan, rowSpan }}` a `coords` cel
117
118
  `layout={{ name, title }}` a `keyed` page. Both are read at placement time, so
118
119
  changing either RE-PLACES the child rather than doing nothing.
119
120
 
121
+ ## Node placement — a portal
122
+
123
+ Every policy above ends in a call on the PARENT, which presumes an answer to a
124
+ question one widget family answers differently: **does this node go into its parent
125
+ at all?** An `Adw.Dialog` does not. It is *presented against* a parent and never
126
+ parented by it, so its position in the authored tree and its position in the GTK
127
+ tree are different places — a portal.
128
+
129
+ Descriptors therefore carry a second, orthogonal declaration
130
+ ([ADR 0045](../../../docs/adr/0045-portal-placement-in-the-gtk-host.md)). `children`
131
+ says how a parent adopts a child; `placement` says whether it adopts one at all.
132
+
133
+ ```ts
134
+ { gtype: 'AdwDialog', ctor: () => Adw.Dialog,
135
+ children: { kind: 'single', set: 'set_child' },
136
+ placement: { kind: 'portal', present: 'present', close: 'force_close' } }
137
+ ```
138
+
139
+ MEASURED on libadwaita 1.9.3 / GTK 4.22.4 / gjs 1.88.1, and every line of the seam
140
+ is one of these:
141
+
142
+ | case | result |
143
+ |---|---|
144
+ | `box.append(dialog)`, box **rooted in a window** | `Adwaita-ERROR`, **SIGABRT, exit 134**, core dump |
145
+ | `box.append(dialog)`, box **detached** | **exit 0, silent** — which is how a bare-box re-test "disproves" the row above |
146
+ | `dialog.present(box)`, box **not** in a window | opens a **separate `GtkWindow`**, exit 0, `visibleDialog` false |
147
+ | `dialog.close()` with `can-close: false` | returns **false**, emits `close-attempt`, **stays up** |
148
+ | `dialog.close()` never presented | `Adwaita-CRITICAL … that's not presented` |
149
+ | `dialog.force_close()` never presented | **silent** |
150
+ | re-`present()` for a second host | `Adwaita-CRITICAL` + `Gtk-WARNING`, **and it does not move** |
151
+ | `notify::root` on a grandchild box | fires on root and again on unroot |
152
+
153
+ So: the declared close is the **forced** one (an unmount is not a user request, and
154
+ it needs no "is it up?" probe); presenting **waits** on the parent's `notify::root`,
155
+ because every framework builds bottom-up and a `<Modal>` inserted before its tree is
156
+ rooted would otherwise float out of the application; the subscription is kept, so a
157
+ subtree moved to another toplevel is re-hosted with a close-then-present rather than
158
+ the critical; and a portal counts for nothing in the sibling index, the tail rotation,
159
+ either slot reader or `addressesOf`.
160
+
161
+ `attached` — "GTK has taken this node" — is written by the present, not by the
162
+ insert. A deferred portal is claimed by the host and not yet taken by GTK, which is
163
+ exactly the distinction that flag exists to keep.
164
+
165
+ Membership is the `Adw.Dialog` family and nothing else: `AdwDialog` plus
166
+ `AdwAboutDialog`, `AdwAlertDialog`, `AdwPreferencesDialog` and `AdwShortcutsDialog`,
167
+ each **named** rather than inherited because descriptor lookup is exact — and
168
+ `portal.spec.ts` walks `GObject.type_is_a(…, Adw.Dialog)` over the registered table,
169
+ so libadwaita's next dialog subclass fails the suite instead of aborting somebody's
170
+ application. A `Gtk.Window` is deliberately not one: `gtk_window_present()` takes no
171
+ argument, so there is nothing to present it *against*, and `descriptorProblems()`
172
+ refuses a zero-argument `present` as a portal.
173
+
120
174
  ## Lists — `@gjsify/gtk-host/list`
121
175
 
122
176
  A `Gtk.ListView` is the one thing in GTK4 that cannot be an element: it installs no
@@ -1,2 +1 @@
1
- import"../_virtual/_rolldown/runtime.js";import{adderSlots as e,addressOf as t,unhandledPolicy as n}from"../policies.js";import{describeLogRecord as r,installDiagnosticsGate as i,isEnvironmentDiagnostic as a}from"./diagnostics.js";import{BUILTIN_DESCRIPTORS as o}from"../descriptors/index.js";import s from"gi://GObject?version=2.0";function methodsOf(e){switch(e.kind){case`none`:case`uncurated`: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 e.remove?[...Object.values(e.slots),e.remove]:Object.values(e.slots);case`keyed`:return[e.add,e.remove];case`coords`:return[e.attach,e.remove];default:return n(e)}}function descriptorProblems(e=o){let t=[];for(let n of e){let e;try{e=n.ctor()}catch(e){t.push({gtype:n.gtype,problem:`ctor() threw: ${e.message}`});continue}if(!e)continue;let r=s.type_name(e.$gtype);r!==n.gtype&&t.push({gtype:n.gtype,problem:`ctor() is ${r}, not ${n.gtype}`});for(let i of methodsOf(n.children))typeof e.prototype[i]!=`function`&&t.push({gtype:n.gtype,problem:`declares children.${i}(), which ${r} does not have`});if(n.textSink){let i=e.list_properties().find(e=>e.get_name()===n.textSink);i?(i.flags&s.ParamFlags.WRITABLE)===0?t.push({gtype:n.gtype,problem:`declares a READ-ONLY textSink "${n.textSink}"`}):s.type_is_a(i.value_type,s.TYPE_STRING)||t.push({gtype:n.gtype,problem:`declares textSink "${n.textSink}", which is ${s.type_name(i.value_type)}, not a string`}):t.push({gtype:n.gtype,problem:`declares textSink "${n.textSink}", which ${r} does not have`})}t.push(...policyProblems(n,e,r))}return t}function policyProblems(t,n,r){let i=[],a=n.prototype,o=t.children,requireGetter=(e,n)=>{let o=e.replace(/^set_/,`get_`);typeof a[o]!=`function`&&i.push({gtype:t.gtype,problem:`${n} uses ${e}() but ${r} has no ${o}(), so removal cannot check whether this child is still the one in place`})};if(o.kind===`single`&&requireGetter(o.set,`children.set`),o.kind===`slotted`){for(let[e,t]of Object.entries(o.slots))t.startsWith(`set_`)&&requireGetter(t,`slot "${e}"`);for(let e of Object.keys(o.wrapSlots??{}))e in o.slots||i.push({gtype:t.gtype,problem:`wrapSlots names "${e}", which is not one of ${Object.keys(o.slots).join(`, `)}`});o.defaultSlot in o.slots||i.push({gtype:t.gtype,problem:`defaultSlot "${o.defaultSlot}" is not one of ${Object.keys(o.slots).join(`, `)}`});let n=e(o);n.length>0&&!o.remove&&i.push({gtype:t.gtype,problem:`slot(s) ${n.map(e=>`"${e}"`).join(`, `)} are adder-backed, so removal needs a "remove" method and this policy names none`})}if(o.kind===`ordered`&&o.reorder===`native`&&!o.after&&i.push({gtype:t.gtype,problem:`claims reorder: 'native' with no "after" method — reorderMode() would tell an adapter the wrong thing`}),o.kind===`keyed`){let e=a[o.add],n=o.titled?3:1;typeof e==`function`&&e.length!==n&&i.push({gtype:t.gtype,problem:`titled: ${o.titled} implies ${o.add}() takes ${n} argument(s), but ${r}'s takes ${e.length}`})}return i}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=>s.type_name(e.constructor.$gtype));function addressesOf(e){let n=[];for(let r=e.first;r;r=r.next)r.kind===`element`&&r.widget&&n.push(t(r));return n}function findDescendant(e,t){let n=[e];for(;n.length>0;){let r=n.shift();if(r!==e&&t(r))return r;n.push(...gtkChildren(r))}return null}function descendants(e){let t=[e];for(let n of gtkChildren(e))t.push(...descendants(n));return t}function dumpTree(e,t=0){let n=s.type_name(e.constructor.$gtype),r=[`${` `.repeat(t)}${n}`];for(let n of gtkChildren(e))r.push(dumpTree(n,t+1));return r.join(`
2
- `)}export{addressesOf,descendants,r as describeLogRecord,descriptorProblems,dumpTree,findDescendant,gtkChildTypes,gtkChildren,i as installDiagnosticsGate,a as isEnvironmentDiagnostic,methodsOf};
1
+ import"../_virtual/_rolldown/runtime.js";import{adderSlots as e,addressOf as t,isPortal as n,placementOf as r,unhandledPlacement as i,unhandledPolicy as a}from"../policies.js";import{describeLogRecord as o,installDiagnosticsGate as s,isEnvironmentDiagnostic as c}from"./diagnostics.js";import{descendants as l,dumpTree as u,findDescendant as d,gtkChildTypes as f,gtkChildren as p}from"./tree.js";import{windowChromeCensus as m,windowChromeProblems as h}from"./window-chrome.js";import{BUILTIN_DESCRIPTORS as g}from"../descriptors/index.js";import _ from"gi://GObject?version=2.0";function methodsOf(e){switch(e.kind){case`none`:case`uncurated`: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 e.remove?[...Object.values(e.slots),e.remove]:Object.values(e.slots);case`keyed`:return[e.add,e.remove];case`coords`:return[e.attach,e.remove];default:return a(e)}}function placementMethodsOf(e){switch(e.kind){case`parented`:return[];case`portal`:return[e.present,e.close];default:return i(e)}}function descriptorProblems(e=g){let t=[];for(let n of e){let e;try{e=n.ctor()}catch(e){t.push({gtype:n.gtype,problem:`ctor() threw: ${e.message}`});continue}if(!e)continue;let i=_.type_name(e.$gtype);i!==n.gtype&&t.push({gtype:n.gtype,problem:`ctor() is ${i}, not ${n.gtype}`});for(let r of methodsOf(n.children))typeof e.prototype[r]!=`function`&&t.push({gtype:n.gtype,problem:`declares children.${r}(), which ${i} does not have`});let a=r(n);for(let r of placementMethodsOf(a))typeof e.prototype[r]!=`function`&&t.push({gtype:n.gtype,problem:`declares placement.${r}(), which ${i} does not have`});if(a.kind===`portal`){let r=e.prototype[a.present];typeof r==`function`&&r.length!==1&&t.push({gtype:n.gtype,problem:`placement.${a.present}() takes ${r.length} argument(s) on ${i}, and a portal is presented AGAINST a parent, which is exactly one`})}if(n.textSink){let r=e.list_properties().find(e=>e.get_name()===n.textSink);r?(r.flags&_.ParamFlags.WRITABLE)===0?t.push({gtype:n.gtype,problem:`declares a READ-ONLY textSink "${n.textSink}"`}):_.type_is_a(r.value_type,_.TYPE_STRING)||t.push({gtype:n.gtype,problem:`declares textSink "${n.textSink}", which is ${_.type_name(r.value_type)}, not a string`}):t.push({gtype:n.gtype,problem:`declares textSink "${n.textSink}", which ${i} does not have`})}t.push(...policyProblems(n,e,i))}return t}function policyProblems(t,n,r){let i=[],a=n.prototype,o=t.children,requireGetter=(e,n)=>{let o=e.replace(/^set_/,`get_`);typeof a[o]!=`function`&&i.push({gtype:t.gtype,problem:`${n} uses ${e}() but ${r} has no ${o}(), so removal cannot check whether this child is still the one in place`})};if(o.kind===`single`&&requireGetter(o.set,`children.set`),o.kind===`slotted`){for(let[e,t]of Object.entries(o.slots))t.startsWith(`set_`)&&requireGetter(t,`slot "${e}"`);for(let e of Object.keys(o.wrapSlots??{}))e in o.slots||i.push({gtype:t.gtype,problem:`wrapSlots names "${e}", which is not one of ${Object.keys(o.slots).join(`, `)}`});o.defaultSlot in o.slots||i.push({gtype:t.gtype,problem:`defaultSlot "${o.defaultSlot}" is not one of ${Object.keys(o.slots).join(`, `)}`});let n=e(o);n.length>0&&!o.remove&&i.push({gtype:t.gtype,problem:`slot(s) ${n.map(e=>`"${e}"`).join(`, `)} are adder-backed, so removal needs a "remove" method and this policy names none`})}if(o.kind===`ordered`&&o.reorder===`native`&&!o.after&&i.push({gtype:t.gtype,problem:`claims reorder: 'native' with no "after" method — reorderMode() would tell an adapter the wrong thing`}),o.kind===`keyed`){let e=a[o.add],n=o.titled?3:1;typeof e==`function`&&e.length!==n&&i.push({gtype:t.gtype,problem:`titled: ${o.titled} implies ${o.add}() takes ${n} argument(s), but ${r}'s takes ${e.length}`})}return i}function addressesOf(e){let r=[];for(let i=e.first;i;i=i.next)i.kind===`element`&&i.widget&&!n(i)&&r.push(t(i));return r}export{addressesOf,l as descendants,o as describeLogRecord,descriptorProblems,u as dumpTree,d as findDescendant,f as gtkChildTypes,p as gtkChildren,s as installDiagnosticsGate,c as isEnvironmentDiagnostic,methodsOf,placementMethodsOf,m as windowChromeCensus,h as windowChromeProblems};
@@ -0,0 +1,2 @@
1
+ import"../_virtual/_rolldown/runtime.js";import e from"gi://GObject?version=2.0";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=t=>gtkChildren(t).map(t=>e.type_name(t.constructor.$gtype));function findDescendant(e,t){let n=[e];for(;n.length>0;){let r=n.shift();if(r!==e&&t(r))return r;n.push(...gtkChildren(r))}return null}function descendants(e){let t=[e];for(let n of gtkChildren(e))t.push(...descendants(n));return t}function dumpTree(t,n=0){let r=e.type_name(t.constructor.$gtype),i=[`${` `.repeat(n)}${r}`];for(let e of gtkChildren(t))i.push(dumpTree(e,n+1));return i.join(`
2
+ `)}export{descendants,dumpTree,findDescendant,gtkChildTypes,gtkChildren};
@@ -0,0 +1 @@
1
+ import"../_virtual/_rolldown/runtime.js";import{descendants as e}from"./tree.js";import t from"gi://GObject?version=2.0";import n from"gi://Gtk?version=4.0";const typeOf=e=>t.type_name(e.constructor.$gtype)??`(unregistered GType)`,isHeaderBar=e=>e===`AdwHeaderBar`||e===`GtkHeaderBar`;function windowChromeCensus(t){let r=0,i=0,a=0;for(let o of e(t)){let e=typeOf(o);if(isHeaderBar(e)){o.get_mapped()&&a++;continue}if(e!==`GtkWindowControls`)continue;let t=o;!t.get_mapped()||t.get_empty()||(t.get_side()===n.PackType.START?r++:i++)}return{start:r,end:i,headerBars:a,mapped:t.get_mapped()}}function windowChromeProblems(e){let t=windowChromeCensus(e),n=typeOf(e);if(!t.mapped)return[`${n} is not mapped, so nothing under it draws yet and every count is 0 — present() the window before asking, or this reads as green having measured nothing`];let r=[],i=`${t.headerBars} mapped header bar(s)`;for(let[e,a]of[[`start`,t.start],[`end`,t.end]])a<=1||r.push(`${a} sets of window controls draw at the ${e} of their header bar in this ${n}, and a window has one — ${a-1} of those close buttons close nothing the user is looking at (${i})`);return t.start+t.end===0&&r.push(`no window control draws anywhere in this ${n}, so its chrome offers no way to close or move it (${i}) — an Adwaita window carries no titlebar of its own, so a header bar has to`),r}export{windowChromeCensus,windowChromeProblems};
@@ -1 +1 @@
1
- import"../_virtual/_rolldown/runtime.js";import e from"gi://Adw?version=1";const t=[{gtype:`AdwToggle`,ctor:()=>e.Toggle,children:{kind:`single`,set:`set_child`}},{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:`AdwExpanderRow`,ctor:()=>e.ExpanderRow,children:{kind:`slotted`,slots:{prefix:`add_prefix`,suffix:`add_suffix`,row:`add_row`},defaultSlot:`row`,remove:`remove`,wrapSlots:{row:`list-box-row`}}},{gtype:`AdwStatusPage`,ctor:()=>e.StatusPage,children:{kind:`single`,set:`set_child`}},{gtype:`AdwNavigationView`,ctor:()=>e.NavigationView,children:{kind:`keyed`,add:`add`,remove:`remove`,nameFrom:`tag`,titled:!1}},{gtype:`AdwNavigationPage`,ctor:()=>e.NavigationPage,children:{kind:`single`,set:`set_child`}},{gtype:`AdwViewStack`,ctor:()=>e.ViewStack,children:{kind:`keyed`,add:`add_titled`,remove:`remove`,nameFrom:`name`,titled:!0,hideBeforeRemove:!0}},{gtype:`AdwClamp`,ctor:()=>e.Clamp,children:{kind:`single`,set:`set_child`}},{gtype:`AdwToastOverlay`,ctor:()=>e.ToastOverlay,children:{kind:`single`,set:`set_child`}},{gtype:`AdwClampScrollable`,ctor:()=>e.ClampScrollable,children:{kind:`single`,set:`set_child`}},{gtype:`AdwBreakpointBin`,ctor:()=>e.BreakpointBin,children:{kind:`single`,set:`set_child`}},{gtype:`AdwNavigationSplitView`,ctor:()=>e.NavigationSplitView,children:{kind:`slotted`,slots:{sidebar:`set_sidebar`,content:`set_content`},defaultSlot:`content`}},{gtype:`AdwOverlaySplitView`,ctor:()=>e.OverlaySplitView,children:{kind:`slotted`,slots:{sidebar:`set_sidebar`,content:`set_content`},defaultSlot:`content`}},{gtype:`AdwWrapBox`,ctor:()=>e.WrapBox,children:{kind:`ordered`,append:`append`,after:`insert_child_after`,remove:`remove`,reorder:`native`}}];export{t as ADW_DESCRIPTORS};
1
+ import"../_virtual/_rolldown/runtime.js";import e from"gi://Adw?version=1";const t={kind:`portal`,present:`present`,close:`force_close`},n=[{gtype:`AdwDialog`,ctor:()=>e.Dialog,children:{kind:`single`,set:`set_child`},placement:t},{gtype:`AdwAlertDialog`,ctor:()=>e.AlertDialog,children:{kind:`uncurated`},placement:t},{gtype:`AdwAboutDialog`,ctor:()=>e.AboutDialog,children:{kind:`uncurated`},placement:t},{gtype:`AdwPreferencesDialog`,ctor:()=>e.PreferencesDialog,children:{kind:`uncurated`},placement:t},{gtype:`AdwShortcutsDialog`,ctor:()=>e.ShortcutsDialog,children:{kind:`uncurated`},placement:t},{gtype:`AdwToggle`,ctor:()=>e.Toggle,children:{kind:`single`,set:`set_child`}},{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:`AdwExpanderRow`,ctor:()=>e.ExpanderRow,children:{kind:`slotted`,slots:{prefix:`add_prefix`,suffix:`add_suffix`,row:`add_row`},defaultSlot:`row`,remove:`remove`,wrapSlots:{row:`list-box-row`}}},{gtype:`AdwStatusPage`,ctor:()=>e.StatusPage,children:{kind:`single`,set:`set_child`}},{gtype:`AdwNavigationView`,ctor:()=>e.NavigationView,children:{kind:`keyed`,add:`add`,remove:`remove`,nameFrom:`tag`,titled:!1}},{gtype:`AdwNavigationPage`,ctor:()=>e.NavigationPage,children:{kind:`single`,set:`set_child`}},{gtype:`AdwViewStack`,ctor:()=>e.ViewStack,children:{kind:`keyed`,add:`add_titled`,remove:`remove`,nameFrom:`name`,titled:!0,hideBeforeRemove:!0}},{gtype:`AdwClamp`,ctor:()=>e.Clamp,children:{kind:`single`,set:`set_child`}},{gtype:`AdwToastOverlay`,ctor:()=>e.ToastOverlay,children:{kind:`single`,set:`set_child`}},{gtype:`AdwClampScrollable`,ctor:()=>e.ClampScrollable,children:{kind:`single`,set:`set_child`}},{gtype:`AdwBreakpointBin`,ctor:()=>e.BreakpointBin,children:{kind:`single`,set:`set_child`}},{gtype:`AdwNavigationSplitView`,ctor:()=>e.NavigationSplitView,children:{kind:`slotted`,slots:{sidebar:`set_sidebar`,content:`set_content`},defaultSlot:`content`}},{gtype:`AdwOverlaySplitView`,ctor:()=>e.OverlaySplitView,children:{kind:`slotted`,slots:{sidebar:`set_sidebar`,content:`set_content`},defaultSlot:`content`}},{gtype:`AdwWrapBox`,ctor:()=>e.WrapBox,children:{kind:`ordered`,append:`append`,after:`insert_child_after`,remove:`remove`,reorder:`native`}}];export{n as ADW_DESCRIPTORS};
package/lib/esm/errors.js CHANGED
@@ -1 +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}', … }). Being a real GType in the installed typelib is not enough on its own.`),missingConstructProp:(e,t)=>new GtkHostError(`missing-construct-prop`,`<${e}> cannot be constructed without ${t}. In the installed library this is not an exception but a g_error(): the process ABORTS (SIGABRT, exit 134, core dump) with no catch and no diagnostic, so the host refuses here while a refusal is still reportable. Author ${t} on the element.`),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.`),eventModifier:(e,t)=>new GtkHostError(`event-modifier`,`${e} carries the DOM listener modifier ".${t}", which has no GObject meaning: a signal is emitted on one object and does not propagate through a tree, so there is no capture phase and nothing to be passive about. Drop the modifier (${e.slice(0,e.length-t.length)}); for GTK4's own propagation phases set "propagation-phase" on a Gtk.EventController instead.`),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(`, `)}.`),slotNeedsRemove:(e,t,n)=>new GtkHostError(`slot-needs-remove`,`<${e}> puts children into slot "${t}" with ${n}() and its policy names no "remove" method, so this child cannot be taken out again. A set_-prefixed slot is emptied by writing null back through the setter and needs nothing; an adder-backed one needs children.remove. Add it to the descriptor.`),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.`),uncuratedPlacement:(e,t)=>new GtkHostError(`uncurated-placement`,`<${e}> comes from the GENERATED table, which knows the tag but not how the widget adopts a child, so it cannot take <${t}>. Guessing is the one thing that is not available here: \`add\`, \`append\` and \`set_child\` all exist somewhere in GTK and calling the wrong one is a warning at exit 0. Add a curated policy for ${e} in descriptors/, or mount into a container that has one.`),siblingCycle:e=>new GtkHostError(`sibling-cycle`,`The child list of <${e}> does not terminate. A renderer linked a node to itself or into a loop; the host refuses to walk it rather than spin. This is a host or adapter bug, not an application one — please report it with the reordering that produced it.`),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.`),occupiedSlot:(e,t,n)=>new GtkHostError(`occupied-slot`,`<${e}> already holds a child the application put there, and ${n}() takes only ONE — placing <${t}> would unparent it. GTK does that silently: no throw, no warning, exit 0, and the application's own widget is simply gone. Mount into a container of your own inside <${e}>, or clear the existing child first (${n}(null)) if replacing it is the intent.`),notAnElement:e=>new GtkHostError(`not-an-element`,`Only an element node owns a widget, and this node is a ${e}. A text node's content lives in its PARENT's text sink and an anchor owns nothing at all — neither has a widget to hand back. Ask the parent element instead.`),destroyedNode:e=>new GtkHostError(`destroyed-node`,`<${e}> was destroyed, so its widget is gone. Asking again would MATERIALISE a fresh, propertyless, unparented widget — \`destroy\` clears props and layout precisely so a destroyed element cannot look re-materialisable — and a caller holding that widget would be looking at nothing on screen.`),notAHostParent:e=>new GtkHostError(`not-a-host-parent`,`insert() needs a host element as the parent and got ${e}. A raw widget cannot be one: the shadow tree lives in the host's own fields, so writing them onto a GObject wrapper renders nothing and reports nothing — Vue's <Teleport to="someWidget"> hands the widget through verbatim and landed exactly here. Wrap it with adopt(widget) first, which is what mountRoot() does.`)};export{GtkHostError,e as err};
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}', … }). Being a real GType in the installed typelib is not enough on its own.`),missingConstructProp:(e,t)=>new GtkHostError(`missing-construct-prop`,`<${e}> cannot be constructed without ${t}. In the installed library this is not an exception but a g_error(): the process ABORTS (SIGABRT, exit 134, core dump) with no catch and no diagnostic, so the host refuses here while a refusal is still reportable. Author ${t} on the element.`),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.`),noAccessor:(e,t,n)=>new GtkHostError(`no-accessor`,`<${e}>.${t} has to be written through its JS accessor — a null or a list cannot be handed to set_property, which guesses a GType and finds none — and GJS installed no "${n}" on this object. Assigning it anyway would create a plain JS property: no GObject write, no error, and notify::${t} never fires.`),badDetailedAction:(e,t,n)=>new GtkHostError(`bad-detailed-action`,`The menu item "${e}" names the action ${JSON.stringify(t)}, which GIO cannot parse: ${n}. In the installed GIO this is not an exception but a g_error() inside g_menu_item_set_detailed_action: the process ABORTS (SIGABRT, exit 134) with no catch and no diagnostic, so the host refuses here while a refusal is still reportable. A detailed action name is "app.act", "app.act::target" or "app.act(variant)".`),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.`),eventModifier:(e,t)=>new GtkHostError(`event-modifier`,`${e} carries the DOM listener modifier ".${t}", which has no GObject meaning: a signal is emitted on one object and does not propagate through a tree, so there is no capture phase and nothing to be passive about. Drop the modifier (${e.slice(0,e.length-t.length)}); for GTK4's own propagation phases set "propagation-phase" on a Gtk.EventController instead.`),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(`, `)}.`),slotNeedsRemove:(e,t,n)=>new GtkHostError(`slot-needs-remove`,`<${e}> puts children into slot "${t}" with ${n}() and its policy names no "remove" method, so this child cannot be taken out again. A set_-prefixed slot is emptied by writing null back through the setter and needs nothing; an adder-backed one needs children.remove. Add it to the descriptor.`),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.`),uncuratedPlacement:(e,t)=>new GtkHostError(`uncurated-placement`,`<${e}> comes from the GENERATED table, which knows the tag but not how the widget adopts a child, so it cannot take <${t}>. Guessing is the one thing that is not available here: \`add\`, \`append\` and \`set_child\` all exist somewhere in GTK and calling the wrong one is a warning at exit 0. Add a curated policy for ${e} in descriptors/, or mount into a container that has one.`),siblingCycle:e=>new GtkHostError(`sibling-cycle`,`The child list of <${e}> does not terminate. A renderer linked a node to itself or into a loop; the host refuses to walk it rather than spin. This is a host or adapter bug, not an application one — please report it with the reordering that produced it.`),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.`),occupiedSlot:(e,t,n)=>new GtkHostError(`occupied-slot`,`<${e}> already holds a child the application put there, and ${n}() takes only ONE — placing <${t}> would unparent it. GTK does that silently: no throw, no warning, exit 0, and the application's own widget is simply gone. Mount into a container of your own inside <${e}>, or clear the existing child first (${n}(null)) if replacing it is the intent.`),portalMethodMissing:(e,t,n)=>new GtkHostError(`portal-method-missing`,`<${e}> declares placement: { kind: 'portal', ${n}: '${t}' } and the installed class has no ${t}(). A portal is placed by calling that method on the node itself — nothing goes into the parent — so without it the node can never reach the screen and never leave it. Fix the descriptor, or drop the portal placement and give the widget an ordinary child policy.`),notAnElement:e=>new GtkHostError(`not-an-element`,`Only an element node owns a widget, and this node is a ${e}. A text node's content lives in its PARENT's text sink and an anchor owns nothing at all — neither has a widget to hand back. Ask the parent element instead.`),destroyedNode:e=>new GtkHostError(`destroyed-node`,`<${e}> was destroyed, so its widget is gone. Asking again would MATERIALISE a fresh, propertyless, unparented widget — \`destroy\` clears props and layout precisely so a destroyed element cannot look re-materialisable — and a caller holding that widget would be looking at nothing on screen.`),notAHostParent:e=>new GtkHostError(`not-a-host-parent`,`insert() needs a host element as the parent and got ${e}. A raw widget cannot be one: the shadow tree lives in the host's own fields, so writing them onto a GObject wrapper renders nothing and reports nothing — Vue's <Teleport to="someWidget"> hands the widget through verbatim and landed exactly here. Wrap it with adopt(widget) first, which is what mountRoot() does.`)};export{GtkHostError,e as err};
@@ -0,0 +1 @@
1
+ import"./_virtual/_rolldown/runtime.js";const e=[`.ttf`,`.otf`,`.ttc`,`.otc`];function resolveFontDir(e={}){return nonEmpty(e.fontDir)??nonEmpty(e.env?.GJSIFY_FONT_DIR)}function isFontFace(t){let n=t.toLowerCase();return e.some(e=>n.endsWith(e))}function nonEmpty(e){if(e===void 0)return;let t=e.trim();return t===``?void 0:t}export{e as FONT_FACE_EXTENSIONS,isFontFace,resolveFontDir};
@@ -0,0 +1 @@
1
+ import"./_virtual/_rolldown/runtime.js";import{isFontFace as e,resolveFontDir as t}from"./font-dir.js";import n from"gi://Gio?version=2.0";import r from"gi://GLib?version=2.0";import i from"gi://PangoCairo?version=1.0";function isUnsupportedByFontMap(e){return e instanceof r.Error&&e.matches(n.io_error_quark(),n.IOErrorEnum.NOT_SUPPORTED)}function initFonts(e={}){let a=t({...e,env:{GJSIFY_FONT_DIR:r.getenv(`GJSIFY_FONT_DIR`)??void 0}}),o=[],s=[],c=[];if(a===void 0)return{dir:a,registered:o,declined:s,failed:c};let l=[];collectFaces(n.File.new_for_path(a),l,c);let u=i.FontMap.get_default();for(let e of l.sort())try{u.add_font_file(e),o.push(e)}catch(t){if(isUnsupportedByFontMap(t)){s.push(e);continue}c.push({path:e,message:messageOf(t)})}for(let e of c)console.warn(`initFonts: ${e.path} could not be read as an application font (${e.message}). Text asking for a family this application ships will render in a substituted one.`);return{dir:a,registered:o,declined:s,failed:c}}function collectFaces(t,r,i){try{let a=t.enumerate_children(`standard::name,standard::type`,n.FileQueryInfoFlags.NOFOLLOW_SYMLINKS,null);for(let t=a.next_file(null);t!==null;t=a.next_file(null)){let o=a.get_child(t),s=o.get_path();s!==null&&(t.get_file_type()===n.FileType.DIRECTORY?collectFaces(o,r,i):e(t.get_name())&&r.push(s))}}catch(e){i.push({path:t.get_path()??``,message:messageOf(e)})}}function messageOf(e){return e instanceof r.Error||e instanceof Error?e.message:String(e)}export{initFonts,isUnsupportedByFontMap};
package/lib/esm/host.js CHANGED
@@ -1 +1 @@
1
- import"./_virtual/_rolldown/runtime.js";import{GtkHostError as e,err as t}from"./errors.js";import{beginHostWrite as n,clearHandlers as r,endHostWrite as i,isEventProp as a,setHandler as o,toSignalName as s}from"./signals.js";import{addressOf as c,insertChild as l,makeDetachedContainer as u,makeWrapper as d,removeChild as f,setterSlotOf as p,setterSlots as m,slotOccupant as h}from"./policies.js";import{coerce as g,paramSpecs as _,removedValue as v,requireSpec as y,toPropertyName as b}from"./props.js";import{lookupWidget as x,nearestRegistered as S}from"./registry.js";import C from"gi://GObject?version=2.0";function createElement(e,t){let n={kind:`element`,descriptor:x(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,destroyed:!1,foreign:[]};if(t)for(let[e,r]of Object.entries(t))setProp(n,e,r);return n}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;for(let n of e.descriptor.requiresProps??[])if(!(n in e.props))throw t.missingConstructProp(e.descriptor.gtype,n);let a=e.descriptor.ctor(),o=_(a,e.descriptor.gtype),s={};for(let[t,n]of Object.entries(e.props))s[t]=g(y(o,e.descriptor.gtype,t),n,e.descriptor.gtype);n(null);try{e.widget=new a(s)}finally{i()}try{replayInto(e)}catch(t){r(e);for(let t of childSnapshot(e))t.kind===`element`&&t.attached&&(f(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)o(e,t,n);for(let t of siblingsFrom(e.first,e))t.kind===`element`&&attach(e,t);e.textFromChildren&&flushText(e)}function setProp(e,t,r,o){if(a(t))return setEventHandler(e,t,r);if(t===`slot`)return setSlot(e,r);if(t===`layout`){let t=r,n=e.parent;if(!n||!e.widget){e.layout=t;return}let i=e.layout;replaceAt(e,n,()=>{e.layout=t},()=>{e.layout=i});return}let s=b(t),c=y(_(e.descriptor.ctor(),e.descriptor.gtype),e.descriptor.gtype,s),l=r==null,u=l?v(e.descriptor,c):g(c,r,e.descriptor.gtype),d=s in e.props?e.props[s]:void 0;if(l?delete e.props[s]:e.props[s]=r,e.widget){if((c.flags&C.ParamFlags.CONSTRUCT_ONLY)!==0)return rebuild(e,s,d);n(e.widget);try{writeProperty(e.widget,s,u)}finally{i()}}}function writeProperty(e,t,n){if(!Array.isArray(n)){e.set_property(t,n);return}let r=t.replace(/-([a-z0-9])/g,(e,t)=>t.toUpperCase());e[r]=n}function setEventHandler(e,t,n){e.widget?o(e,t,n):n&&assertSignalExists(e,t),n?e.listeners.set(t,n):e.listeners.delete(t)}function assertSignalExists(e,n){let r=s(n,e.descriptor.eventAliases).split(`::`)[0],i=e.descriptor.ctor().$gtype;if(C.signal_lookup(r,i)===0)throw t.unknownSignal(e.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){f(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 i=e.parent;if(e.widget){r(e);for(let t of childSnapshot(e))t.kind===`element`&&(f(e,t),t.attached=!1);i&&f(i,e)}e.widget=null,e.wrapper=null,e.attached=!1;try{materialize(e)}catch(r){t!==void 0&&(n===void 0?delete e.props[t]:e.props[t]=n);try{materialize(e),i&&attach(i,e)}catch{}throw r}i&&attach(i,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,destroyChildren(e)}function flushText(e){let t=``,n=!1;for(let r of childNodes(e))r.kind===`text`&&(t+=r.data,n=!0);if(t===``&&!e.textFromChildren)return;let r=e.descriptor.textSink;if(t===``&&r&&holdsElementInSetterSlot(e)){e.textFromChildren=!1,delete e.props[r];return}writeTextSink(e,t),e.textFromChildren=n}function*setterSlotChildren(e){for(let t of siblingsFrom(e.first,e))t.kind===`element`&&t.attached&&p(e,t)&&(yield t)}const holdsElementInSetterSlot=e=>!setterSlotChildren(e).next().done;function writeTextSink(e,r){let a=e.descriptor.textSink;if(!a)throw t.textNotAccepted(e.descriptor.gtype,r);materialize(e);let o=e.descriptor.children,s=o.kind===`single`?o.set:null;if(s&&!holdsOursInSlot(e,null)&&appOccupant(e.widget,e.descriptor,s))throw t.occupiedSlot(e.descriptor.gtype,`text`,s);let c=y(_(e.descriptor.ctor(),e.descriptor.gtype),e.descriptor.gtype,a);n(e.widget);try{e.widget.set_property(a,g(c,r,e.descriptor.gtype))}finally{i()}e.props[a]=r;for(let t of setterSlotChildren(e))t.attached=!1}function*childNodes(e){yield*siblingsFrom(e.first,e)}function childSnapshot(e){let t=[];for(let n of siblingsFrom(e.first,e))t.push(n);return t}function*siblingsFrom(e,n){let r=0;for(let i=e;i;i=i.next){if(++r>1e5)throw t.siblingCycle(n.descriptor.gtype);yield i}}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),refuseOccupiedSlot(e,t);let n=e.foreign.length>0?e.foreign.filter(t=>t.get_parent()===e.widget):e.foreign,r=n.length>0?n[n.length-1]:null,i=n.length;for(let n of siblingsFrom(e.first,e)){if(n===t)break;n.kind!==`element`||!n.attached||(r=c(n),i+=1)}let a=[];for(let n of siblingsFrom(t.next,e))n.kind===`element`&&n.attached&&a.push(n);l({parent:e,child:t,prevWidget:r,index:i,following:a}),t.attached=!0}function refuseOccupiedSlot(e,n){let r=p(e,n);if(r&&!holdsOursInSlot(e,n.slot)&&appOccupant(e.widget,e.descriptor,r))throw t.occupiedSlot(e.descriptor.gtype,n.descriptor.gtype,r)}function holdsOursInSlot(e,t){for(let n of siblingsFrom(e.first,e))if(n.kind===`element`&&n.attached&&n.slot===t)return!0;return!1}function ensureWrapper(n,r){if(r.wrapper)return;let i;try{i=d(n.descriptor.children,r.widget,r.slot)}catch(i){throw i instanceof e?i:t.rejectedChild(n.descriptor.gtype,r.descriptor.gtype,i.message)}i&&(r.wrapper=i)}function insert(e,t,n=null){assertHostParent(t);let r=e.parent,i=e.next,a=n===e?i:n;e.parent&&remove(e),link(t,e,a);try{e.kind===`element`?attach(t,e):e.kind===`text`&&flushText(t)}catch(t){throw unlink(e),r&&restore(e,r,i),t}}function assertHostParent(e){if(!isHostElement(e))throw t.notAHostParent(describeValue(e))}function isHostElement(e){let t=e;return!!t&&t.kind===`element`&&typeof t.descriptor==`object`}function describeValue(e){if(e==null)return String(e);if(typeof e!=`object`)return`a ${typeof e}`;let t=e.tagName;if(typeof t==`string`)return`a DOM element <${t.toLowerCase()}>`;let n=e.constructor?.$gtype,r=n?C.type_name(n)??`an unnamed GType`:null;if(r!==null&&r!==`JSObject`)return r;let i=e.constructor?.name;return i&&i!==`Object`?`a ${i}`:`a plain object`}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 restoreTextSink(e){let t=e.descriptor.textSink;if(!t||e.destroyed||!e.widget)return;let r=e.descriptor.children;if(r.kind!==`single`||holdsOursInSlot(e,null)||h(e.widget,r.set))return;let a=t.replace(/-([a-z])/g,(e,t)=>t.toUpperCase()),o=e.props[t]??e.props[a];if(typeof o!=`string`||o===``)return;let s=y(_(e.descriptor.ctor(),e.descriptor.gtype),e.descriptor.gtype,t);n(e.widget);try{e.widget.set_property(t,g(s,o,e.descriptor.gtype))}finally{i()}}function remove(e){let t=e.parent;t&&e.kind===`element`&&(f(t,e),e.attached=!1,e.wrapper&&=(e.wrapper.set_child(null),null),restoreTextSink(t)),unlink(e),t&&e.kind===`text`&&flushText(t)}function destroyChildren(e){for(let t of childSnapshot(e))destroy(t)}function disconnectHandlers(e){r(e),e.listeners.clear()}function destroy(e){if(e.kind===`element`&&(destroyChildren(e),r(e),e.listeners.clear()),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,e.destroyed=!0}}function mountRoot(e,t){materialize(e),insert(e,adopt(t))}function widgetOf(e){if(e.kind!==`element`)throw t.notAnElement(e.kind);if(e.destroyed)throw t.destroyedNode(e.descriptor.gtype);return materialize(e)}const createDetachedContainer=()=>adopt(u());function adopt(e){let n=e.constructor.$gtype,r=S(n);if(!r)throw t.unknownTag(gtypeNameOf(e));return{kind:`element`,descriptor:r,widget:e,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,destroyed:!1,foreign:adoptedChildren(e,r)}}function adoptedChildren(e,t){let n=m(t.children);if(n.length===0)return directChildren(e);let r=[];for(let i of n){let n=appOccupant(e,t,i);n&&r.push(n)}return r}function appOccupant(e,t,n){let r=h(e,n);if(!r)return null;let i=t.textSink;if(!i)return r;let a=e[i.replace(/-([a-z])/g,(e,t)=>t.toUpperCase())];return typeof a==`string`&&a!==``?null:r}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=>C.type_name(e.constructor.$gtype),parentNode=e=>e.parent,firstChild=e=>e.first,nextSibling=e=>e.next,prevSibling=e=>e.prev;export{adopt,createAnchor,createDetachedContainer,createElement,createText,describeValue,destroy,destroyChildren,disconnectHandlers,firstChild,insert,isHostElement,isText,materialize,mountRoot,nextSibling,parentNode,prevSibling,remove,setElementText,setEventHandler,setProp,setSlot,setText,widgetOf};
1
+ import"./_virtual/_rolldown/runtime.js";import{GtkHostError as e,err as t}from"./errors.js";import{beginHostWrite as n,clearHandlers as r,endHostWrite as i,isEventProp as a,setHandler as o,toSignalName as s}from"./signals.js";import{addressOf as c,insertChild as l,isPortal as u,makeDetachedContainer as d,makeWrapper as f,portalOf as p,presentPortal as m,removeChild as h,setterSlotOf as g,setterSlots as _,slotOccupant as v}from"./policies.js";import{coerce as y,isConstructOnly as b,paramSpecs as x,removedValue as S,requireSpec as C,toPropertyName as w}from"./props.js";import{lookupWidget as T,nearestRegistered as E}from"./registry.js";import D from"gi://GObject?version=2.0";function createElement(e,t){let n={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,destroyed:!1,foreign:[],portalWatch:null};if(t)for(let[e,r]of Object.entries(t))setProp(n,e,r);return n}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;for(let n of e.descriptor.requiresProps??[])if(!(n in e.props))throw t.missingConstructProp(e.descriptor.gtype,n);let a=e.descriptor.ctor(),o=x(a,e.descriptor.gtype),s={};for(let[t,n]of Object.entries(e.props))s[t]=y(C(o,e.descriptor.gtype,t),n,e.descriptor.gtype);n(null);try{e.widget=new a(s)}finally{i()}try{replayInto(e)}catch(t){r(e);for(let t of childSnapshot(e))t.kind===`element`&&t.attached&&(h(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)o(e,t,n);for(let t of siblingsFrom(e.first,e))t.kind===`element`&&attach(e,t);e.textFromChildren&&flushText(e)}function setProp(e,t,r,o){if(a(t))return setEventHandler(e,t,r);if(t===`slot`)return setSlot(e,r);if(t===`layout`){let t=r,n=e.parent;if(!n||!e.widget){e.layout=t;return}let i=e.layout;replaceAt(e,n,()=>{e.layout=t},()=>{e.layout=i});return}let s=w(t),c=C(x(e.descriptor.ctor(),e.descriptor.gtype),e.descriptor.gtype,s),l=r==null,u=l?S(e.descriptor,c):y(c,r,e.descriptor.gtype);e.widget!==null&&takesAccessorRoute(u)&&!b(c)&&requireAccessor(e,e.widget,s);let d=s in e.props?e.props[s]:void 0;if(l?delete e.props[s]:e.props[s]=r,e.widget){if(b(c))return rebuild(e,s,d);n(e.widget);try{writeProperty(e.widget,s,u)}finally{i()}}}function writeProperty(e,t,n){if(!takesAccessorRoute(n)){e.set_property(t,n);return}let r=accessorName(t);e[r]=n}const accessorName=e=>e.replace(/-([a-z0-9])/g,(e,t)=>t.toUpperCase()),takesAccessorRoute=e=>e===null||Array.isArray(e);function requireAccessor(e,n,r){let i=accessorName(r);if(!(i in n))throw t.noAccessor(e.descriptor.gtype,r,i)}function setEventHandler(e,t,n){e.widget?o(e,t,n):n&&assertSignalExists(e,t),n?e.listeners.set(t,n):e.listeners.delete(t)}function assertSignalExists(e,n){let r=s(n,e.descriptor.eventAliases).split(`::`)[0],i=e.descriptor.ctor().$gtype;if(D.signal_lookup(r,i)===0)throw t.unknownSignal(e.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){h(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 i=e.parent;if(e.widget){r(e);for(let t of childSnapshot(e))t.kind===`element`&&(h(e,t),t.attached=!1);i&&h(i,e)}e.widget=null,e.wrapper=null,e.attached=!1;try{materialize(e)}catch(r){t!==void 0&&(n===void 0?delete e.props[t]:e.props[t]=n);try{materialize(e),i&&attach(i,e)}catch{}throw r}i&&attach(i,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,destroyChildren(e)}function flushText(e){let t=``,n=!1;for(let r of childNodes(e))r.kind===`text`&&(t+=r.data,n=!0);if(t===``&&!e.textFromChildren)return;let r=e.descriptor.textSink;if(t===``&&r&&holdsElementInSetterSlot(e)){e.textFromChildren=!1,delete e.props[r];return}writeTextSink(e,t),e.textFromChildren=n}function*setterSlotChildren(e){for(let t of siblingsFrom(e.first,e))t.kind===`element`&&t.attached&&!u(t)&&g(e,t)&&(yield t)}const holdsElementInSetterSlot=e=>!setterSlotChildren(e).next().done;function writeTextSink(e,r){let a=e.descriptor.textSink;if(!a)throw t.textNotAccepted(e.descriptor.gtype,r);materialize(e);let o=e.descriptor.children,s=o.kind===`single`?o.set:null;if(s&&!holdsOursInSlot(e,null)&&appOccupant(e.widget,e.descriptor,s))throw t.occupiedSlot(e.descriptor.gtype,`text`,s);let c=C(x(e.descriptor.ctor(),e.descriptor.gtype),e.descriptor.gtype,a);n(e.widget);try{e.widget.set_property(a,y(c,r,e.descriptor.gtype))}finally{i()}e.props[a]=r;for(let t of setterSlotChildren(e))t.attached=!1}function*childNodes(e){yield*siblingsFrom(e.first,e)}function childSnapshot(e){let t=[];for(let n of siblingsFrom(e.first,e))t.push(n);return t}function*siblingsFrom(e,n){let r=0;for(let i=e;i;i=i.next){if(++r>1e5)throw t.siblingCycle(n.descriptor.gtype);yield i}}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);let n=p(t.descriptor);if(n){t.attached=m(e,t,n);return}ensureWrapper(e,t),refuseOccupiedSlot(e,t);let r=e.foreign.length>0?e.foreign.filter(t=>t.get_parent()===e.widget):e.foreign,i=r.length>0?r[r.length-1]:null,a=r.length;for(let n of siblingsFrom(e.first,e)){if(n===t)break;n.kind!==`element`||!n.attached||u(n)||(i=c(n),a+=1)}let o=[];for(let n of siblingsFrom(t.next,e))n.kind===`element`&&n.attached&&!u(n)&&o.push(n);l({parent:e,child:t,prevWidget:i,index:a,following:o}),t.attached=!0}function refuseOccupiedSlot(e,n){let r=g(e,n);if(r&&!holdsOursInSlot(e,n.slot)&&appOccupant(e.widget,e.descriptor,r))throw t.occupiedSlot(e.descriptor.gtype,n.descriptor.gtype,r)}function holdsOursInSlot(e,t){for(let n of siblingsFrom(e.first,e))if(n.kind===`element`&&n.attached&&n.slot===t&&!u(n))return!0;return!1}function ensureWrapper(n,r){if(r.wrapper)return;let i;try{i=f(n.descriptor.children,r.widget,r.slot)}catch(i){throw i instanceof e?i:t.rejectedChild(n.descriptor.gtype,r.descriptor.gtype,i.message)}i&&(r.wrapper=i)}function insert(e,t,n=null){assertHostParent(t);let r=e.parent,i=e.next,a=n===e?i:n;e.parent&&remove(e),link(t,e,a);try{e.kind===`element`?attach(t,e):e.kind===`text`&&flushText(t)}catch(t){throw unlink(e),r&&restore(e,r,i),t}}function assertHostParent(e){if(!isHostElement(e))throw t.notAHostParent(describeValue(e))}function isHostElement(e){let t=e;return!!t&&t.kind===`element`&&typeof t.descriptor==`object`}function describeValue(e){if(e==null)return String(e);if(typeof e!=`object`)return`a ${typeof e}`;let t=e.tagName;if(typeof t==`string`)return`a DOM element <${t.toLowerCase()}>`;let n=e.constructor?.$gtype,r=n?D.type_name(n)??`an unnamed GType`:null;if(r!==null&&r!==`JSObject`)return r;let i=e.constructor?.name;return i&&i!==`Object`?`a ${i}`:`a plain object`}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 restoreTextSink(e){let t=e.descriptor.textSink;if(!t||e.destroyed||!e.widget)return;let r=e.descriptor.children;if(r.kind!==`single`||holdsOursInSlot(e,null)||v(e.widget,r.set))return;let a=t.replace(/-([a-z])/g,(e,t)=>t.toUpperCase()),o=e.props[t]??e.props[a];if(typeof o!=`string`||o===``)return;let s=C(x(e.descriptor.ctor(),e.descriptor.gtype),e.descriptor.gtype,t);n(e.widget);try{e.widget.set_property(t,y(s,o,e.descriptor.gtype))}finally{i()}}function remove(e){let t=e.parent;t&&e.kind===`element`&&(h(t,e),e.attached=!1,e.wrapper&&=(e.wrapper.set_child(null),null),restoreTextSink(t)),unlink(e),t&&e.kind===`text`&&flushText(t)}function destroyChildren(e){for(let t of childSnapshot(e))destroy(t)}function disconnectHandlers(e){r(e),e.listeners.clear()}function destroy(e){if(e.kind===`element`&&(destroyChildren(e),r(e),e.listeners.clear()),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,e.destroyed=!0}}function mountRoot(e,t){materialize(e),insert(e,adopt(t))}function widgetOf(e){if(e.kind!==`element`)throw t.notAnElement(e.kind);if(e.destroyed)throw t.destroyedNode(e.descriptor.gtype);return materialize(e)}const createDetachedContainer=()=>adopt(d());function adopt(e){let n=e.constructor.$gtype,r=E(n);if(!r)throw t.unknownTag(gtypeNameOf(e));return{kind:`element`,descriptor:r,widget:e,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,destroyed:!1,foreign:adoptedChildren(e,r),portalWatch:null}}function adoptedChildren(e,t){let n=_(t.children);if(n.length===0)return directChildren(e);let r=[];for(let i of n){let n=appOccupant(e,t,i);n&&r.push(n)}return r}function appOccupant(e,t,n){let r=v(e,n);if(!r)return null;let i=t.textSink;if(!i)return r;let a=e[i.replace(/-([a-z])/g,(e,t)=>t.toUpperCase())];return typeof a==`string`&&a!==``?null:r}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=>D.type_name(e.constructor.$gtype),parentNode=e=>e.parent,firstChild=e=>e.first,nextSibling=e=>e.next,prevSibling=e=>e.prev;export{adopt,createAnchor,createDetachedContainer,createElement,createText,describeValue,destroy,destroyChildren,disconnectHandlers,firstChild,insert,isHostElement,isText,materialize,mountRoot,nextSibling,parentNode,prevSibling,remove,setElementText,setEventHandler,setProp,setSlot,setText,widgetOf};
package/lib/esm/index.js CHANGED
@@ -1 +1 @@
1
- import{GtkHostError as e}from"./errors.js";import{isEventProp as t,toSignalName as n}from"./signals.js";import{addressOf as r,reorderMode as i}from"./policies.js";import{constructOnlyNames as a,isConstructOnly as o,isWritable as s,lookupEnumNick as c,paramSpecs as l,toPropertyName as u}from"./props.js";import{assertInjective as d,tagOf as f}from"./tags.js";import{clearRegistry as p,hasWidget as m,lookupWidget as h,nearestRegistered as g,registerWidget as _,registerWidgets as v,registeredTags as y}from"./registry.js";import{adopt as b,createAnchor as x,createDetachedContainer as S,createElement as C,createText as w,destroy as T,destroyChildren as E,disconnectHandlers as D,firstChild as O,insert as k,isHostElement as A,isText as j,materialize as M,mountRoot as N,nextSibling as P,parentNode as F,prevSibling as I,remove as L,setElementText as R,setEventHandler as z,setProp as B,setSlot as V,setText as H,widgetOf as U}from"./host.js";import{GENERATED_PROVENANCE as W,GENERATED_WIDGETS as G}from"./generated/widgets.js";import{ADW_DESCRIPTORS as K}from"./descriptors/adw.js";import{GTK_DESCRIPTORS as q}from"./descriptors/gtk.js";import{BUILTIN_DESCRIPTORS as J,CURATED_DESCRIPTORS as Y,mergeGenerated as X,registerBuiltinWidgets as Z,tableProvenance as Q}from"./descriptors/index.js";import"./types.js";import{blankReason as $,checkRendered as ee,probeEnabled as te,runHostProbe as ne,runHostProbeApp as re,shotEvidence as ie}from"./probe.js";export{K as ADW_DESCRIPTORS,J as BUILTIN_DESCRIPTORS,Y as CURATED_DESCRIPTORS,W as GENERATED_PROVENANCE,G as GENERATED_WIDGETS,q as GTK_DESCRIPTORS,e as GtkHostError,r as addressOf,b as adopt,d as assertInjective,$ as blankReason,ee as checkRendered,p as clearRegistry,a as constructOnlyNames,x as createAnchor,S as createDetachedContainer,C as createElement,w as createText,T as destroy,E as destroyChildren,D as disconnectHandlers,O as firstChild,m as hasWidget,k as insert,o as isConstructOnly,t as isEventProp,A as isHostElement,j as isText,s as isWritable,c as lookupEnumNick,h as lookupWidget,M as materialize,X as mergeGenerated,N as mountRoot,g as nearestRegistered,P as nextSibling,l as paramSpecs,F as parentNode,I as prevSibling,te as probeEnabled,Z as registerBuiltinWidgets,_ as registerWidget,v as registerWidgets,y as registeredTags,L as remove,i as reorderMode,ne as runHostProbe,re as runHostProbeApp,R as setElementText,z as setEventHandler,B as setProp,V as setSlot,H as setText,ie as shotEvidence,Q as tableProvenance,f as tagOf,u as toPropertyName,n as toSignalName,U as widgetOf};
1
+ import{GtkHostError as e}from"./errors.js";import{isEventProp as t,toSignalName as n}from"./signals.js";import{addressOf as r,isPortal as i,placementOf as a,portalOf as o,reorderMode as s}from"./policies.js";import{constructOnlyNames as c,isConstructOnly as l,isWritable as u,lookupEnumNick as d,paramSpecs as f,toPropertyName as p}from"./props.js";import{assertInjective as m,tagOf as h}from"./tags.js";import{clearRegistry as g,hasWidget as _,lookupWidget as v,nearestRegistered as y,registerWidget as b,registerWidgets as x,registeredTags as S}from"./registry.js";import{adopt as C,createAnchor as w,createDetachedContainer as T,createElement as E,createText as D,destroy as O,destroyChildren as k,disconnectHandlers as A,firstChild as j,insert as M,isHostElement as N,isText as P,materialize as F,mountRoot as I,nextSibling as L,parentNode as R,prevSibling as z,remove as B,setElementText as V,setEventHandler as H,setProp as U,setSlot as W,setText as G,widgetOf as K}from"./host.js";import{GENERATED_PROVENANCE as q,GENERATED_WIDGETS as J}from"./generated/widgets.js";import{ADW_DESCRIPTORS as Y}from"./descriptors/adw.js";import{GTK_DESCRIPTORS as X}from"./descriptors/gtk.js";import{BUILTIN_DESCRIPTORS as Z,CURATED_DESCRIPTORS as Q,mergeGenerated as $,registerBuiltinWidgets as ee,tableProvenance as te}from"./descriptors/index.js";import"./types.js";import{blankReason as ne,checkRendered as re,probeEnabled as ie,runHostProbe as ae,runHostProbeApp as oe,shotEvidence as se}from"./probe.js";export{Y as ADW_DESCRIPTORS,Z as BUILTIN_DESCRIPTORS,Q as CURATED_DESCRIPTORS,q as GENERATED_PROVENANCE,J as GENERATED_WIDGETS,X as GTK_DESCRIPTORS,e as GtkHostError,r as addressOf,C as adopt,m as assertInjective,ne as blankReason,re as checkRendered,g as clearRegistry,c as constructOnlyNames,w as createAnchor,T as createDetachedContainer,E as createElement,D as createText,O as destroy,k as destroyChildren,A as disconnectHandlers,j as firstChild,_ as hasWidget,M as insert,l as isConstructOnly,t as isEventProp,N as isHostElement,i as isPortal,P as isText,u as isWritable,d as lookupEnumNick,v as lookupWidget,F as materialize,$ as mergeGenerated,I as mountRoot,y as nearestRegistered,L as nextSibling,f as paramSpecs,R as parentNode,a as placementOf,o as portalOf,z as prevSibling,ie as probeEnabled,ee as registerBuiltinWidgets,b as registerWidget,x as registerWidgets,S as registeredTags,B as remove,s as reorderMode,ae as runHostProbe,oe as runHostProbeApp,V as setElementText,H as setEventHandler,U as setProp,W as setSlot,G as setText,se as shotEvidence,te as tableProvenance,h as tagOf,p as toPropertyName,n as toSignalName,K as widgetOf};
@@ -0,0 +1 @@
1
+ import"./_virtual/_rolldown/runtime.js";import{err as e}from"./errors.js";import t from"gi://Gio?version=2.0";import n from"gi://GLib?version=2.0";import{normalizeMenuModel as r}from"@gjsify/adwaita-core";const i={label:`label`,action:`action`,icon:`icon`,verbIcon:`verb-icon`,accel:`accel`,hiddenWhen:`hidden-when`,custom:`custom`,id:`id`};function requireDetailedAction(n,r){try{t.Action.parse_detailed_name(n)}catch(t){throw e.badDetailedAction(r,n,t instanceof Error?t.message:String(t))}}function itemOf(e){let r=new t.MenuItem;if(e.kind===`item`){e.action!==void 0&&(requireDetailedAction(e.action,e.label),r.set_detailed_action(e.action));for(let[t,a]of Object.entries(i)){let i=e[t];t===`action`||typeof i!=`string`||r.set_attribute_value(a,n.Variant.new_string(i))}return e.useMarkup===!0&&r.set_attribute_value(`use-markup`,n.Variant.new_string(`true`)),r}let a=buildGioMenu(e.items);return e.kind===`section`?(r.set_section(a),e.label!==void 0&&r.set_label(e.label),e.displayHint!==void 0&&r.set_attribute_value(`display-hint`,n.Variant.new_string(e.displayHint)),e.textDirection!==void 0&&r.set_attribute_value(`text-direction`,n.Variant.new_string(e.textDirection)),r):(r.set_submenu(a),r.set_label(e.label),e.icon!==void 0&&r.set_attribute_value(`icon`,n.Variant.new_string(e.icon)),e.submenuAction!==void 0&&r.set_attribute_value(`submenu-action`,n.Variant.new_string(e.submenuAction)),e.macosSpecial!==void 0&&r.set_attribute_value(`gtk-macos-special`,n.Variant.new_string(e.macosSpecial)),r)}function buildGioMenu(e){let n=new t.Menu;for(let t of r(e))n.append_item(itemOf(t));return n}const isPortableMenu=e=>Array.isArray(e);function attr(e,t,r){let i=e.get_item_attribute_value(t,r,n.VariantType.new(`s`));return i===null?void 0:i.get_string()[0]}function detailedAction(e,t){let n=attr(e,t,`action`);if(n===void 0)return;let r=e.get_item_attribute_value(t,`target`,null);return r===null?n:r.get_type_string()===`s`?`${n}::${r.get_string()[0]}`:`${n}(${r.print(!1)})`}function fromGioMenu(e){let n=[];for(let r=0;r<e.get_n_items();r+=1){let i=e.get_item_link(r,t.MENU_LINK_SECTION),a=e.get_item_link(r,t.MENU_LINK_SUBMENU),o=attr(e,r,`label`);if(i!==null){let t={kind:`section`,items:fromGioMenu(i)};o!==void 0&&(t.label=o);let a=attr(e,r,`display-hint`);a!==void 0&&(t.displayHint=a);let s=attr(e,r,`text-direction`);s!==void 0&&(t.textDirection=s),n.push(t);continue}if(a!==null){let t={kind:`submenu`,label:o??``,items:fromGioMenu(a)};for(let[n,i]of[[`icon`,`icon`],[`submenuAction`,`submenu-action`],[`macosSpecial`,`gtk-macos-special`]]){let a=attr(e,r,i);a!==void 0&&(t[n]=a)}n.push(t);continue}let s={kind:`item`,label:o??``},c=detailedAction(e,r);c!==void 0&&(s.action=c);for(let[t,n]of[[`icon`,`icon`],[`verbIcon`,`verb-icon`],[`accel`,`accel`],[`hiddenWhen`,`hidden-when`],[`custom`,`custom`],[`id`,`id`]]){let i=attr(e,r,n);i!==void 0&&(s[t]=i)}attr(e,r,`use-markup`)!==void 0&&(s.useMarkup=!0),n.push(s)}return n}export{buildGioMenu,fromGioMenu,isPortableMenu};
@@ -1 +1 @@
1
- import"./_virtual/_rolldown/runtime.js";import{GtkHostError as e,err as t}from"./errors.js";import{beginHostWrite as n,endHostWrite as r}from"./signals.js";import i 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,n){let r=e.kind===`indexed`?e.wrap:e.kind===`slotted`?e.wrapSlots?.[n??e.defaultSlot]??null:null;if(!r)return null;if(r===`list-box-row`){if(t instanceof i.ListBoxRow)return null;let e=new i.ListBoxRow;return e.set_child(t),e}if(t instanceof i.FlowBoxChild)return null;let a=new i.FlowBoxChild;return a.set_child(t),a}const makeDetachedContainer=()=>new i.Box;function unhandledPolicy(e){throw Error(`unhandled child policy: ${JSON.stringify(e)}`)}function setterSlotOf(e,t){let n=e.descriptor.children;if(n.kind===`single`)return n.set;if(n.kind!==`slotted`)return null;let r=n.slots[t.slot??n.defaultSlot];return r?.startsWith(`set_`)===!0?r:null}function adderSlots(e){return e.kind===`slotted`?Object.entries(e.slots).filter(([,e])=>!e.startsWith(`set_`)).map(([e])=>e):[]}function setterSlots(e){return e.kind===`single`?[e.set]:e.kind===`slotted`?Object.values(e.slots).filter(e=>e.startsWith(`set_`)):[]}function slotOccupant(e,t){let n=e,r=t.replace(/^set_/,`get_`);if(typeof n[r]==`function`)return n[r]()??null}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`uncurated`:throw t.uncuratedPlacement(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;default:return unhandledPolicy(i)}}function appendChild(e,n,r){let i=e.descriptor.children,a=addressOf(n);switch(i.kind){case`uncurated`:throw t.uncuratedPlacement(e.descriptor.gtype,n.descriptor.gtype);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`){if(setterSlotOf(e,t))return;let slotOf=e=>e.slot??i.defaultSlot,r=slotOf(t);a=n.filter(e=>slotOf(e)===r)}for(let t of a)detachChild(e,t,r);for(let t of a)appendChild(e,t,r)}function detachChild(e,n,r){let i=e.descriptor.children,a=n.wrapper??n.widget;if(a)switch(i.kind){case`none`:case`uncurated`:return;case`single`:clearIfCurrent(r,i.set,a);return;case`slotted`:{let o=setterSlotOf(e,n);if(o){clearIfCurrent(r,o,a);return}let s=n.slot??i.defaultSlot;if(!i.remove)throw t.slotNeedsRemove(e.descriptor.gtype,s,i.slots[s]??`?`);r[i.remove](a);return}case`keyed`:{let e=i.hideBeforeRemove===!0&&a.get_visible();e&&writeVisible(a,!1),r[i.remove](a),e&&writeVisible(a,!0);return}case`ordered`:case`indexed`:case`coords`:r[i.remove](a);return;default:return unhandledPolicy(i)}}function writeVisible(e,t){n(null);try{e.set_visible(t)}finally{r()}}function clearIfCurrent(e,t,n){let r=slotOccupant(e,t);(r===void 0||r===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`uncurated`:return`n/a`;case`ordered`:return e.reorder;case`indexed`:return`native`;case`slotted`:return adderSlots(e).length>0?`remove-all`:`n/a`;case`keyed`:return`remove-all`;case`coords`:case`single`:case`none`:return`n/a`;default:return unhandledPolicy(e)}}export{adderSlots,addressOf,insertChild,makeDetachedContainer,makeWrapper,removeChild,reorderMode,setterSlotOf,setterSlots,slotOccupant,unhandledPolicy};
1
+ import"./_virtual/_rolldown/runtime.js";import{GtkHostError as e,err as t}from"./errors.js";import{beginHostWrite as n,endHostWrite as r}from"./signals.js";import i 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,n){let r=e.kind===`indexed`?e.wrap:e.kind===`slotted`?e.wrapSlots?.[n??e.defaultSlot]??null:null;if(!r)return null;if(r===`list-box-row`){if(t instanceof i.ListBoxRow)return null;let e=new i.ListBoxRow;return e.set_child(t),e}if(t instanceof i.FlowBoxChild)return null;let a=new i.FlowBoxChild;return a.set_child(t),a}const makeDetachedContainer=()=>new i.Box;function unhandledPolicy(e){throw Error(`unhandled child policy: ${JSON.stringify(e)}`)}function setterSlotOf(e,t){let n=e.descriptor.children;if(n.kind===`single`)return n.set;if(n.kind!==`slotted`)return null;let r=n.slots[t.slot??n.defaultSlot];return r?.startsWith(`set_`)===!0?r:null}function adderSlots(e){return e.kind===`slotted`?Object.entries(e.slots).filter(([,e])=>!e.startsWith(`set_`)).map(([e])=>e):[]}function setterSlots(e){return e.kind===`single`?[e.set]:e.kind===`slotted`?Object.values(e.slots).filter(e=>e.startsWith(`set_`)):[]}function slotOccupant(e,t){let n=e,r=t.replace(/^set_/,`get_`);if(typeof n[r]==`function`)return n[r]()??null}const a={kind:`parented`},placementOf=e=>e.placement??a;function portalOf(e){let t=placementOf(e);switch(t.kind){case`parented`:return null;case`portal`:return t;default:return unhandledPlacement(t)}}function unhandledPlacement(e){throw Error(`unhandled node placement: ${JSON.stringify(e)}`)}const isPortal=e=>portalOf(e.descriptor)!==null;function portalMethod(e,n,r){let i=e.widget?.[n];if(typeof i!=`function`)throw t.portalMethodMissing(e.descriptor.gtype,n,r);return i}const toplevelOf=e=>{let t=e.get_root();return t instanceof i.Window?t:null};function presentPortal(e,t,n){let r=e.widget;return r?(portalMethod(t,n.present,`present`),portalMethod(t,n.close,`close`),watchPortalRoot(r,t,n),placeAgainst(r,t,n)):!1}function placeAgainst(e,t,n){let r=t.widget;if(!r)return!1;let i=toplevelOf(e);if(!i)return portalMethod(t,n.close,`close`).call(r),!1;if(r.get_parent()){if(toplevelOf(r)===i)return!0;portalMethod(t,n.close,`close`).call(r)}return portalMethod(t,n.present,`present`).call(r,e),!0}function watchPortalRoot(e,t,n){t.portalWatch?.widget!==e&&(t.portalWatch&&retractPortalWatch(t),t.portalWatch={widget:e,id:e.connect(`notify::root`,()=>{t.attached=placeAgainst(e,t,n)})})}function retractPortalWatch(e){let t=e.portalWatch;t&&(e.portalWatch=null,t.widget.disconnect(t.id))}function retractPortal(e,t){retractPortalWatch(e),e.widget&&portalMethod(e,t.close,`close`).call(e.widget)}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`uncurated`:throw t.uncuratedPlacement(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;default:return unhandledPolicy(i)}}function appendChild(e,n,r){let i=e.descriptor.children,a=addressOf(n);switch(i.kind){case`uncurated`:throw t.uncuratedPlacement(e.descriptor.gtype,n.descriptor.gtype);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`){if(setterSlotOf(e,t))return;let slotOf=e=>e.slot??i.defaultSlot,r=slotOf(t);a=n.filter(e=>slotOf(e)===r)}for(let t of a)detachChild(e,t,r);for(let t of a)appendChild(e,t,r)}function detachChild(e,n,r){let i=e.descriptor.children,a=n.wrapper??n.widget;if(a)switch(i.kind){case`none`:case`uncurated`:return;case`single`:clearIfCurrent(r,i.set,a);return;case`slotted`:{let o=setterSlotOf(e,n);if(o){clearIfCurrent(r,o,a);return}let s=n.slot??i.defaultSlot;if(!i.remove)throw t.slotNeedsRemove(e.descriptor.gtype,s,i.slots[s]??`?`);r[i.remove](a);return}case`keyed`:{let e=i.hideBeforeRemove===!0&&a.get_visible();e&&writeVisible(a,!1),r[i.remove](a),e&&writeVisible(a,!0);return}case`ordered`:case`indexed`:case`coords`:r[i.remove](a);return;default:return unhandledPolicy(i)}}function writeVisible(e,t){n(null);try{e.set_visible(t)}finally{r()}}function clearIfCurrent(e,t,n){let r=slotOccupant(e,t);(r===void 0||r===n)&&e[t](null)}function removeChild(e,t){let n=portalOf(t.descriptor);if(n)return retractPortal(t,n);let r=e.widget;r&&t.attached&&detachChild(e,t,r)}function reorderMode(e){switch(e.kind){case`uncurated`:return`n/a`;case`ordered`:return e.reorder;case`indexed`:return`native`;case`slotted`:return adderSlots(e).length>0?`remove-all`:`n/a`;case`keyed`:return`remove-all`;case`coords`:case`single`:case`none`:return`n/a`;default:return unhandledPolicy(e)}}export{adderSlots,addressOf,insertChild,isPortal,makeDetachedContainer,makeWrapper,placementOf,portalOf,presentPortal,removeChild,reorderMode,retractPortal,setterSlotOf,setterSlots,slotOccupant,unhandledPlacement,unhandledPolicy};
package/lib/esm/probe.js CHANGED
@@ -1 +1 @@
1
- import"./_virtual/_rolldown/runtime.js";import{installDiagnosticsGate as e}from"./conformance/diagnostics.js";import{descendants as t}from"./conformance/index.js";import n from"gi://Gtk?version=4.0";import r from"gi://Adw?version=1";import i from"gi://GLib?version=2.0";import a from"system";function probeEnabled(){let e=i.getenv(`GJSIFY_HOST_PROBE`);if(e===null)return!1;let t=e.toLowerCase();return t!==``&&t!==`0`&&t!==`false`}const o=`<gtk-host probe: recorder self-check>`;function recorderIsHonest(e,t){let n=t.length;e(o,!1);let r=t.length===n+1&&t[n]===o;t.length=n,e(o,!0);let i=t.length===n;return t.length=n,r&&i?null:r?`the probe recorder records a PASSING check as a failure, so every assertion below is a false alarm`:`the probe recorder did not record a failed check, so every assertion below is unverifiable`}async function runHostProbe(t){let n=t.label??`PROBE`,r=e();r.reset();let i=[],check=(e,t)=>{t||i.push(e)},a=recorderIsHonest(check,i);a!==null&&i.push(a);let o={};try{let e=t.build(null);o=await t.assert(e,check),t.teardown?.(e)}catch(e){i.push(`threw: ${e.message}`)}let s=r.seen.length;check(`no GTK diagnostics (saw ${s})`,s===0);let c=JSON.stringify({...i.length>0?{failures:i}:{},diagnostics:s,...o});return print(`${n}: ${i.length>0?`FAIL`:`PASS`} ${c}`),+(i.length>0)}async function runHostProbeApp(e){if(probeEnabled())return n.init(),a.exit(await runHostProbe(e));let t=new r.Application({application_id:e.applicationId});t.connect(`activate`,()=>{t.hold(),(async()=>{try{let n=await runHostProbe(e);if(n!==0)return a.exit(n);e.present(e.build(t))}catch(t){return printerr(`JS ERROR: ${e.applicationId} probe threw: ${String(t)}`),a.exit(1)}finally{t.release()}})()}),await t.runAsync([])}function shotEvidence(e,n){let r=n(e);return{widgets:t(e).length-1,width:e.get_width(),height:e.get_height(),bytes:r?r.length:0}}function blankReason(e){return e.widgets===0?`nothing was rendered into the container: it has no children at all, which is what a refused render, an unmounted root and a component returning null all look like from GTK`:e.width<=0||e.height<=0?`the container is allocated ${e.width}×${e.height}: its ${e.widgets} widget(s) exist and occupy nothing`:e.bytes===0?`the capture produced no PNG: the widget has no renderer yet, so it was measured before it was ever on screen`:null}function checkRendered(e,t,n){let r=blankReason(n);e(r===null?t:`${t} — ${r}`,r===null)}export{blankReason,checkRendered,probeEnabled,runHostProbe,runHostProbeApp,shotEvidence};
1
+ import"./_virtual/_rolldown/runtime.js";import{installDiagnosticsGate as e}from"./conformance/diagnostics.js";import{descendants as t}from"./conformance/tree.js";import"./conformance/index.js";import n from"gi://Gtk?version=4.0";import r from"gi://Adw?version=1";import i from"gi://GLib?version=2.0";import a from"system";function probeEnabled(){let e=i.getenv(`GJSIFY_HOST_PROBE`);if(e===null)return!1;let t=e.toLowerCase();return t!==``&&t!==`0`&&t!==`false`}const o=`<gtk-host probe: recorder self-check>`;function recorderIsHonest(e,t){let n=t.length;e(o,!1);let r=t.length===n+1&&t[n]===o;t.length=n,e(o,!0);let i=t.length===n;return t.length=n,r&&i?null:r?`the probe recorder records a PASSING check as a failure, so every assertion below is a false alarm`:`the probe recorder did not record a failed check, so every assertion below is unverifiable`}async function runHostProbe(t){let n=t.label??`PROBE`,r=e();r.reset();let i=[],check=(e,t)=>{t||i.push(e)},a=recorderIsHonest(check,i);a!==null&&i.push(a);let o={};try{let e=t.build(null);o=await t.assert(e,check),t.teardown?.(e)}catch(e){i.push(`threw: ${e.message}`)}let s=r.seen.length;check(`no GTK diagnostics (saw ${s})`,s===0);let c=JSON.stringify({...i.length>0?{failures:i}:{},diagnostics:s,...o});return print(`${n}: ${i.length>0?`FAIL`:`PASS`} ${c}`),+(i.length>0)}async function runHostProbeApp(e){if(probeEnabled())return n.init(),a.exit(await runHostProbe(e));let t=new r.Application({application_id:e.applicationId});t.connect(`activate`,()=>{t.hold(),(async()=>{try{let n=await runHostProbe(e);if(n!==0)return a.exit(n);e.present(e.build(t))}catch(t){return printerr(`JS ERROR: ${e.applicationId} probe threw: ${String(t)}`),a.exit(1)}finally{t.release()}})()}),await t.runAsync([])}function shotEvidence(e,n){let r=n(e);return{widgets:t(e).length-1,width:e.get_width(),height:e.get_height(),bytes:r?r.length:0}}function blankReason(e){return e.widgets===0?`nothing was rendered into the container: it has no children at all, which is what a refused render, an unmounted root and a component returning null all look like from GTK`:e.width<=0||e.height<=0?`the container is allocated ${e.width}×${e.height}: its ${e.widgets} widget(s) exist and occupy nothing`:e.bytes===0?`the capture produced no PNG: the widget has no renderer yet, so it was measured before it was ever on screen`:null}function checkRendered(e,t,n){let r=blankReason(n);e(r===null?t:`${t} — ${r}`,r===null)}export{blankReason,checkRendered,probeEnabled,runHostProbe,runHostProbeApp,shotEvidence};
package/lib/esm/props.js CHANGED
@@ -1 +1 @@
1
- import"./_virtual/_rolldown/runtime.js";import{err as e}from"./errors.js";import t from"gi://GObject?version=2.0";import n from"gi://Gtk?version=4.0";import r from"gi://Adw?version=1";import i from"gi://Gdk?version=4.0";import a from"gi://Pango?version=1.0";const o=[[`Gtk`,n],[`Adw`,r],[`Gdk`,i],[`Pango`,a],[`G`,t]];function toPropertyName(e){return e.includes(`-`)?e:e.replace(/([a-z0-9])([A-Z])/g,`$1-$2`).toLowerCase()}function withoutKeys(e,t){if(!e)return;let n;for(let r of Object.keys(e))t.has(r)||((n??={})[r]=e[r]);return n}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}}const lookupEnumNick=(e,t)=>resolveEnumValue(e,t).value;function enumMembers(e){for(let[t,n]of o){if(!e.startsWith(t))continue;let r=n[e.slice(t.length)];if(r)return Object.keys(r).filter(e=>e!==`$gtype`&&typeof r[e]==`number`)}}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}const c=[t.TYPE_BOOLEAN,t.TYPE_STRING,t.TYPE_INT,t.TYPE_UINT,t.TYPE_INT64,t.TYPE_UINT64,t.TYPE_DOUBLE,t.TYPE_FLOAT],isScalarSpec=e=>t.type_is_a(e.value_type,t.TYPE_ENUM)||c.some(n=>t.type_is_a(e.value_type,n)),toAccessorName=e=>e.replace(/-([a-z0-9])/g,(e,t)=>t.toUpperCase()),l=new Map;function constructedDefaults(e){let r=l.get(e.gtype);if(r)return r;let i=new Map;l.set(e.gtype,i);let a=e.ctor(),o;try{let t={};for(let n of e.requiresProps??[])t[n]=``;o=new a(t)}catch{return i}for(let[n,r]of paramSpecs(a,e.gtype)){if(!isWritable(r)||isConstructOnly(r)||!isFlag(r.flags,t.ParamFlags.READABLE)||isFlag(r.flags,t.ParamFlags.DEPRECATED)||!isScalarSpec(r))continue;let e=toAccessorName(n);e in o&&i.set(n,o[e])}return o instanceof n.Window&&o.destroy(),i}function removedValue(e,t){let n=constructedDefaults(e),r=t.get_name();return n.has(r)?n.get(r):t.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,enumMembers,isConstructOnly,isWritable,lookupEnumNick,paramSpecs,removedValue,requireSpec,toPropertyName,withoutKeys};
1
+ import"./_virtual/_rolldown/runtime.js";import{err as e}from"./errors.js";import{buildGioMenu as t,isPortableMenu as n}from"./menu.js";import r from"gi://GObject?version=2.0";import i from"gi://Gtk?version=4.0";import a from"gi://Adw?version=1";import o from"gi://Gdk?version=4.0";import s from"gi://Gio?version=2.0";import c from"gi://Pango?version=1.0";const l=[[`Gtk`,i],[`Adw`,a],[`Gdk`,o],[`Pango`,c],[`G`,r]];function toPropertyName(e){return e.includes(`-`)?e:e.replace(/([a-z0-9])([A-Z])/g,`$1-$2`).toLowerCase()}function withoutKeys(e,t){if(!e)return;let n;for(let r of Object.keys(e))t.has(r)||((n??={})[r]=e[r]);return n}const u=new Map;function paramSpecs(e,t){let n=u.get(t);if(n)return n;n=new Map;for(let t of e.list_properties())n.set(t.get_name(),t);return u.set(t,n),n}const isFlag=(e,t)=>(e&t)!==0,isWritable=e=>isFlag(e.flags,r.ParamFlags.WRITABLE),isConstructOnly=e=>isFlag(e.flags,r.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 l){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}}const lookupEnumNick=(e,t)=>resolveEnumValue(e,t).value;function enumMembers(e){for(let[t,n]of l){if(!e.startsWith(t))continue;let r=n[e.slice(t.length)];if(r)return Object.keys(r).filter(e=>e!==`$gtype`&&typeof r[e]==`number`)}}function coerce(i,a,o){if(a==null)return a;let c=i.value_type;if(r.type_is_a(c,s.MenuModel.$gtype)&&n(a))return t(a);if(r.type_is_a(c,r.TYPE_ENUM)&&typeof a==`string`){let t=r.type_name(c),n=resolveEnumValue(t,a);if(n.value!==void 0)return n.value;throw n.resolved?e.badEnum(o,i.get_name(),a,t):e.unresolvableEnum(t)}if(r.type_is_a(c,r.TYPE_FLAGS)&&typeof a==`string`)throw e.badFlags(o,i.get_name(),a,r.type_name(c));if(r.type_is_a(c,r.TYPE_BOOLEAN)){if(typeof a==`boolean`)return a;if(a===`true`)return!0;if(a===`false`)return!1;if(typeof a==`string`)throw e.badBoolean(o,i.get_name(),a);return!!a}if(r.type_is_a(c,r.TYPE_STRING)){if(typeof a==`string`)return a;if(typeof a==`number`||typeof a==`boolean`)return String(a);throw e.badString(o,i.get_name(),typeof a)}return(r.type_is_a(c,r.TYPE_INT)||r.type_is_a(c,r.TYPE_UINT)||r.type_is_a(c,r.TYPE_INT64)||r.type_is_a(c,r.TYPE_UINT64))&&typeof a==`number`?Math.trunc(a):a}const d=[r.TYPE_BOOLEAN,r.TYPE_STRING,r.TYPE_INT,r.TYPE_UINT,r.TYPE_INT64,r.TYPE_UINT64,r.TYPE_DOUBLE,r.TYPE_FLOAT],isScalarSpec=e=>r.type_is_a(e.value_type,r.TYPE_ENUM)||d.some(t=>r.type_is_a(e.value_type,t)),toAccessorName=e=>e.replace(/-([a-z0-9])/g,(e,t)=>t.toUpperCase()),f=new Map;function constructedDefaults(e){let t=f.get(e.gtype);if(t)return t;let n=new Map;f.set(e.gtype,n);let a=e.ctor(),o;try{let t={};for(let n of e.requiresProps??[])t[n]=``;o=new a(t)}catch{return n}for(let[t,i]of paramSpecs(a,e.gtype)){if(!isWritable(i)||isConstructOnly(i)||!isFlag(i.flags,r.ParamFlags.READABLE)||isFlag(i.flags,r.ParamFlags.DEPRECATED)||!isScalarSpec(i))continue;let e=toAccessorName(t);e in o&&n.set(t,o[e])}return o instanceof i.Window&&o.destroy(),n}function removedValue(e,t){let n=constructedDefaults(e),r=t.get_name();return n.has(r)?n.get(r):t.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,enumMembers,isConstructOnly,isWritable,lookupEnumNick,paramSpecs,removedValue,requireSpec,toPropertyName,withoutKeys};
@@ -0,0 +1,3 @@
1
+ import"../_virtual/_rolldown/runtime.js";import{UnknownUtilityError as e}from"./errors.js";const t=new Set([`serif`,`sans-serif`,`monospace`,`cursive`,`fantasy`,`system-ui`,`ui-serif`,`ui-sans-serif`,`ui-monospace`,`ui-rounded`,`math`,`fangsong`,`emoji`]),n=new Set([`inherit`,`initial`,`unset`,`revert`,`revert-layer`]),r=/^"(?:[^"\\\n\r\f]|\\[\s\S])*"$|^'(?:[^'\\\n\r\f]|\\[\s\S])*'$/,i=/^[a-zA-Z-][\w-]*\(/,a=new Set([` `,` `,`
2
+ `,`\r`,`\f`]);function quote(e){let t=`"`;for(let n of e){let e=n.codePointAt(0)??0;n===`"`||n===`\\`?t+=`\\${n}`:e<32||e===127?t+=`\\${e.toString(16)} `:t+=n}return`${t}"`}function members(e){let t=[],n=0,r=0,i=null,o=!0;for(let s=0;s<e.length;s++){let c=e[s];if(i!==null){c===`\\`?s++:c===i&&(i=null);continue}if((o||r>0)&&(c===`"`||c===`'`))i=c;else if(c===`(`)r++;else if(c===`)`&&r>0)r--;else if(c===`,`&&r===0){t.push(e.slice(n,s)),n=s+1,o=!0;continue}a.has(c)||(o=!1)}return t.push(e.slice(n)),t}function isCompleteCall(e){if(!i.test(e))return!1;let t=0,n=null;for(let r=0;r<e.length;r++){let i=e[r];if(n!==null){i===`\\`?r++:i===n&&(n=null);continue}if(i===`"`||i===`'`)n=i;else if(i===`(`)t++;else if(i===`)`){if(t--,t===0)return r===e.length-1;if(t<0)return!1}}return!1}function serialiseFontFamily(a){let o=members(a),s=o.length===1;return o.map(o=>{let c=o.trim();if(c===``)throw new e(a,`is a font-family list with an empty member. GTK answers a missing family with "Expected a string" and drops the whole declaration, so the list is refused here instead`);if(r.test(c))return c;if(i.test(c)){if(isCompleteCall(c))return c;throw new e(a,`opens a function the member never closes. A function is the one member handed to GTK verbatim, so an unclosed one emits declaration text this module did not write — measured, "var(--x); color: red" emits a second declaration with no parse error at all`)}let l=c.toLowerCase();return t.has(l)||s&&n.has(l)?c:quote(c)}).join(`, `)}const o=[{authored:`Source Sans 3`,emitted:`"Source Sans 3"`,bare:`refused`},{authored:`M PLUS 1p`,emitted:`"M PLUS 1p"`,bare:`refused`},{authored:`8514oem`,emitted:`"8514oem"`,bare:`refused`},{authored:`Foo.Bar`,emitted:`"Foo.Bar"`,bare:`refused`},{authored:`Cantarell`,emitted:`"Cantarell"`,bare:`accepted`},{authored:`Fira Code`,emitted:`"Fira Code"`,bare:`accepted`},{authored:`Liberation Serif`,emitted:`"Liberation Serif"`,bare:`accepted`},{authored:`sans-serif`,emitted:`sans-serif`,bare:`accepted`},{authored:`monospace`,emitted:`monospace`,bare:`accepted`},{authored:`system-ui`,emitted:`system-ui`,bare:`accepted`},{authored:`Sans-Serif`,emitted:`Sans-Serif`,bare:`accepted`},{authored:`inherit`,emitted:`inherit`,bare:`accepted`},{authored:`Source Sans 3, sans-serif`,emitted:`"Source Sans 3", sans-serif`,bare:`refused`},{authored:`'Source Sans 3', sans-serif`,emitted:`'Source Sans 3', sans-serif`,bare:`accepted`},{authored:`Fira Code, ui-monospace, monospace`,emitted:`"Fira Code", ui-monospace, monospace`,bare:`accepted`},{authored:`"Source Sans 3"`,emitted:`"Source Sans 3"`,bare:`accepted`},{authored:`'Noto Sans'`,emitted:`'Noto Sans'`,bare:`accepted`},{authored:`"Foo, Bar", sans-serif`,emitted:`"Foo, Bar", sans-serif`,bare:`accepted`},{authored:`Marion's Hand, sans-serif`,emitted:`"Marion's Hand", sans-serif`,bare:`refused`},{authored:`var(--font-sans)`,emitted:`var(--font-sans)`,bare:`accepted`},{authored:`var(--font-sans, sans-serif)`,emitted:`var(--font-sans, sans-serif)`,bare:`accepted`},{authored:`var(--a, var(--b, sans-serif))`,emitted:`var(--a, var(--b, sans-serif))`,bare:`accepted`},{authored:`Say "Ah"`,emitted:`"Say \\"Ah\\""`,bare:`refused`},{authored:`Back\\slash`,emitted:`"Back\\\\slash"`,bare:`misread`},{authored:`Two
3
+ Lines`,emitted:`"Two\\a Lines"`,bare:`misread`},{authored:`"Two\rLines"`,emitted:`"\\"Two\\d Lines\\""`,bare:`refused`}];export{o as FONT_FAMILY_VECTORS,serialiseFontFamily};
@@ -1 +1 @@
1
- import{StyleSheetError as e,assertContained as t}from"./document.js";import{UnknownUtilityError as n}from"./errors.js";import{GTK_CSS_PROBES as r,GTK_CSS_PROPERTIES as i,NOT_GTK_CSS as a}from"./gtk-css.js";import{GTK_WIDGET_PROPERTIES as o,GTK_WIDGET_PROPERTY_PROBES as s,NOT_GTK_WIDGET_PROPERTIES as c}from"./gtk-props.js";import{MINIMAL_TOKENS as l,TAILWIND_DEFAULT_TOKENS as u,lookupToken as d,mergeTokens as f,requireToken as p,tailwindDefaultHint as m}from"./tokens.js";import{PAINT_PROPERTIES as h,partitionPaint as g,resolvePaintUtility as _}from"./paint.js";import{LAYOUT_PROPERTIES as v,partitionLayout as y,resolveLayoutUtility as b}from"./layout.js";import{partition as x,resolveUtilities as S,resolveUtility as C}from"./resolve.js";import{StyleSheet as w,VARIANT_PSEUDO as T}from"./sheet.js";import{ADWAITA_NAMED_COLORS as E,NEUTRAL_THEME as D,NOT_ADWAITA_NAMED_COLORS as O,THEME_PROVIDER_PRIORITY as k,ThemeRegistry as A}from"./theme.js";export{E as ADWAITA_NAMED_COLORS,r as GTK_CSS_PROBES,i as GTK_CSS_PROPERTIES,o as GTK_WIDGET_PROPERTIES,s as GTK_WIDGET_PROPERTY_PROBES,v as LAYOUT_PROPERTIES,l as MINIMAL_TOKENS,D as NEUTRAL_THEME,O as NOT_ADWAITA_NAMED_COLORS,a as NOT_GTK_CSS,c as NOT_GTK_WIDGET_PROPERTIES,h as PAINT_PROPERTIES,w as StyleSheet,e as StyleSheetError,u as TAILWIND_DEFAULT_TOKENS,k as THEME_PROVIDER_PRIORITY,A as ThemeRegistry,n as UnknownUtilityError,T as VARIANT_PSEUDO,t as assertContained,d as lookupToken,f as mergeTokens,x as partition,y as partitionLayout,g as partitionPaint,p as requireToken,b as resolveLayoutUtility,_ as resolvePaintUtility,S as resolveUtilities,C as resolveUtility,m as tailwindDefaultHint};
1
+ import{StyleSheetError as e,assertContained as t}from"./document.js";import{UnknownUtilityError as n}from"./errors.js";import{FONT_FAMILY_VECTORS as r,serialiseFontFamily as i}from"./font-family.js";import{GTK_CSS_PROBES as a,GTK_CSS_PROPERTIES as o,NOT_GTK_CSS as s}from"./gtk-css.js";import{GTK_WIDGET_PROPERTIES as c,GTK_WIDGET_PROPERTY_PROBES as l,NOT_GTK_WIDGET_PROPERTIES as u}from"./gtk-props.js";import{MINIMAL_TOKENS as d,TAILWIND_DEFAULT_TOKENS as f,lookupToken as p,mergeTokens as m,requireToken as h,tailwindDefaultHint as g}from"./tokens.js";import{CSS_VALUE as _,CSS_VALUE_KIND as v,PAINT_PROPERTIES as y,partitionPaint as b,resolvePaintUtility as x}from"./paint.js";import{LAYOUT_PROPERTIES as S,partitionLayout as C,resolveLayoutUtility as w}from"./layout.js";import{partition as T,resolveUtilities as E,resolveUtility as D}from"./resolve.js";import{StyleSheet as O,VARIANT_PSEUDO as k}from"./sheet.js";import{ADWAITA_NAMED_COLORS as A,NEUTRAL_THEME as j,NOT_ADWAITA_NAMED_COLORS as M,THEME_PROVIDER_PRIORITY as N,ThemeRegistry as P}from"./theme.js";export{A as ADWAITA_NAMED_COLORS,_ as CSS_VALUE,v as CSS_VALUE_KIND,r as FONT_FAMILY_VECTORS,a as GTK_CSS_PROBES,o as GTK_CSS_PROPERTIES,c as GTK_WIDGET_PROPERTIES,l as GTK_WIDGET_PROPERTY_PROBES,S as LAYOUT_PROPERTIES,d as MINIMAL_TOKENS,j as NEUTRAL_THEME,M as NOT_ADWAITA_NAMED_COLORS,s as NOT_GTK_CSS,u as NOT_GTK_WIDGET_PROPERTIES,y as PAINT_PROPERTIES,O as StyleSheet,e as StyleSheetError,f as TAILWIND_DEFAULT_TOKENS,N as THEME_PROVIDER_PRIORITY,P as ThemeRegistry,n as UnknownUtilityError,k as VARIANT_PSEUDO,t as assertContained,p as lookupToken,m as mergeTokens,T as partition,C as partitionLayout,b as partitionPaint,h as requireToken,w as resolveLayoutUtility,x as resolvePaintUtility,E as resolveUtilities,D as resolveUtility,i as serialiseFontFamily,g as tailwindDefaultHint};
@@ -1 +1 @@
1
- import"../_virtual/_rolldown/runtime.js";import{UnknownUtilityError as e}from"./errors.js";import{GTK_CSS_PROPERTIES as t}from"./gtk-css.js";import{lookupToken as n,requireToken as r,tailwindDefaultHint as i}from"./tokens.js";const a={backgroundColor:`background-color`,color:`color`,opacity:`opacity`,borderRadius:`border-radius`,borderTopLeftRadius:`border-top-left-radius`,borderTopRightRadius:`border-top-right-radius`,borderBottomLeftRadius:`border-bottom-left-radius`,borderBottomRightRadius:`border-bottom-right-radius`,borderWidth:`border-width`,borderTopWidth:`border-top-width`,borderRightWidth:`border-right-width`,borderBottomWidth:`border-bottom-width`,borderLeftWidth:`border-left-width`,borderColor:`border-color`,fontSize:`font-size`,fontWeight:`font-weight`,fontFamily:`font-family`,fontStyle:`font-style`,letterSpacing:`letter-spacing`,lineHeight:`line-height`,textDecorationLine:`text-decoration-line`,textTransform:`text-transform`},withAlpha=(t,n)=>{let r=Number(n);if(!Number.isFinite(r)||r<0||r>100)throw new e(`${t}/${n}`,`the alpha modifier must be 0–100, got "${n}"`);return`alpha(${t}, ${r/100})`};function resolvePaintUtility(t,a){if(t.includes(`:`))throw new e(t,`strip the variant prefix before resolving; this resolves the utility itself`);let l=t.lastIndexOf(`/`),u=l===-1?void 0:t.slice(l+1),d=l===-1?t:t.slice(0,l),colour=e=>u===void 0?e:withAlpha(e,u),noAlpha=()=>{if(u!==void 0)throw new e(t,`an alpha modifier only applies to a colour utility`)};switch(d){case`underline`:return noAlpha(),{textDecorationLine:`underline`};case`line-through`:return noAlpha(),{textDecorationLine:`line-through`};case`no-underline`:return noAlpha(),{textDecorationLine:`none`};case`uppercase`:return noAlpha(),{textTransform:`uppercase`};case`lowercase`:return noAlpha(),{textTransform:`lowercase`};case`capitalize`:return noAlpha(),{textTransform:`capitalize`};case`normal-case`:return noAlpha(),{textTransform:`none`};case`italic`:return noAlpha(),{fontStyle:`italic`};case`not-italic`:return noAlpha(),{fontStyle:`normal`};case`rounded`:return noAlpha(),{borderRadius:r(a.borderRadius,`DEFAULT`,t,`borderRadius`)};case`border`:return noAlpha(),{borderWidth:r(a.borderWidth,`DEFAULT`,t,`borderWidth`)}}let f=d.indexOf(`-`),p=f===-1?d:d.slice(0,f),m=f===-1?``:d.slice(f+1);switch(p){case`bg`:return{backgroundColor:colour(r(a.colors,m,t,`colors`))};case`opacity`:return noAlpha(),{opacity:r(a.opacity,m,t,`opacity`)};case`rounded`:{noAlpha();let e=o[m];return e===void 0?{borderRadius:r(a.borderRadius,m,t,`borderRadius`)}:{[e]:r(a.borderRadius,`DEFAULT`,t,`borderRadius`)}}case`border`:{let o=s[m];if(o!==void 0)return noAlpha(),{[o]:r(a.borderWidth,`DEFAULT`,t,`borderWidth`)};let c=n(a.borderWidth,m),l=n(a.colors,m);if(c!==void 0&&l!==void 0)throw new e(t,`"${m}" is in both the borderWidth and colors scales, so this utility is ambiguous`);if(c!==void 0)return noAlpha(),{borderWidth:c};if(l!==void 0)return{borderColor:colour(l)};throw new e(t,`"${m}" is in neither the borderWidth nor the colors scale`+(i(`borderWidth`,m)||i(`colors`,m)))}case`text`:{if(c.has(m))return null;let r=n(a.fontSize,m),o=n(a.colors,m);if(r!==void 0&&o!==void 0)throw new e(t,`"${m}" is in both the fontSize and colors scales, so this utility is ambiguous`);if(r!==void 0)return noAlpha(),{fontSize:r};if(o!==void 0)return{color:colour(o)};throw new e(t,`"${m}" is in neither the fontSize nor the colors scale`+(i(`fontSize`,m)||i(`colors`,m)))}case`font`:{noAlpha();let r=n(a.fontWeight,m),i=n(a.fontFamily,m);if(r!==void 0&&i!==void 0)throw new e(t,`"${m}" is in both the fontWeight and fontFamily scales, so this utility is ambiguous`);if(r!==void 0)return{fontWeight:r};if(i!==void 0)return{fontFamily:i};throw new e(t,`"${m}" is in neither the fontWeight nor the fontFamily scale`)}case`tracking`:return noAlpha(),{letterSpacing:r(a.letterSpacing,m,t,`letterSpacing`)};case`leading`:return noAlpha(),{lineHeight:r(a.lineHeight,m,t,`lineHeight`)}}return null}const o={tl:`borderTopLeftRadius`,tr:`borderTopRightRadius`,bl:`borderBottomLeftRadius`,br:`borderBottomRightRadius`},s={t:`borderTopWidth`,r:`borderRightWidth`,b:`borderBottomWidth`,l:`borderLeftWidth`},c=new Set([`left`,`center`,`right`,`justify`,`start`,`end`]),l=new Set(Object.keys(a));function partitionPaint(n){let r=[];for(let[i,o]of Object.entries(n)){if(o===void 0)continue;let n=a[i];if(n===void 0)throw new e(i,`is not a property the paint partition routes`);if(!t.has(n))throw new e(i,`maps to "${n}", which GTK does not accept — see gtk-css.ts`);r.push(`${n}: ${o}`)}let i=r.some(e=>/^border(-(top|right|bottom|left))?-width:/.test(e)),o=r.some(e=>/^border(-(top|right|bottom|left))?-style:/.test(e));return i&&!o&&r.push(`border-style: solid`),r}export{a as CSS_NAME,l as PAINT_PROPERTIES,partitionPaint,resolvePaintUtility};
1
+ import"../_virtual/_rolldown/runtime.js";import{UnknownUtilityError as e}from"./errors.js";import{serialiseFontFamily as t}from"./font-family.js";import{GTK_CSS_PROPERTIES as n}from"./gtk-css.js";import{lookupToken as r,requireToken as i,tailwindDefaultHint as a}from"./tokens.js";const o={backgroundColor:`background-color`,color:`color`,opacity:`opacity`,borderRadius:`border-radius`,borderTopLeftRadius:`border-top-left-radius`,borderTopRightRadius:`border-top-right-radius`,borderBottomLeftRadius:`border-bottom-left-radius`,borderBottomRightRadius:`border-bottom-right-radius`,borderWidth:`border-width`,borderTopWidth:`border-top-width`,borderRightWidth:`border-right-width`,borderBottomWidth:`border-bottom-width`,borderLeftWidth:`border-left-width`,borderColor:`border-color`,fontSize:`font-size`,fontWeight:`font-weight`,fontFamily:`font-family`,fontStyle:`font-style`,letterSpacing:`letter-spacing`,lineHeight:`line-height`,textDecorationLine:`text-decoration-line`,textTransform:`text-transform`},s={backgroundColor:`colour`,color:`colour`,opacity:`number`,borderRadius:`length`,borderTopLeftRadius:`length`,borderTopRightRadius:`length`,borderBottomLeftRadius:`length`,borderBottomRightRadius:`length`,borderWidth:`length`,borderTopWidth:`length`,borderRightWidth:`length`,borderBottomWidth:`length`,borderLeftWidth:`length`,borderColor:`colour`,fontSize:`length`,fontWeight:`number`,fontFamily:`name`,fontStyle:`keyword`,letterSpacing:`length`,lineHeight:`number`,textDecorationLine:`keyword`,textTransform:`keyword`},c={fontFamily:t},withAlpha=(t,n)=>{let r=Number(n);if(!Number.isFinite(r)||r<0||r>100)throw new e(`${t}/${n}`,`the alpha modifier must be 0–100, got "${n}"`);return`alpha(${t}, ${r/100})`};function resolvePaintUtility(t,n){if(t.includes(`:`))throw new e(t,`strip the variant prefix before resolving; this resolves the utility itself`);let o=t.lastIndexOf(`/`),s=o===-1?void 0:t.slice(o+1),c=o===-1?t:t.slice(0,o),colour=e=>s===void 0?e:withAlpha(e,s),noAlpha=()=>{if(s!==void 0)throw new e(t,`an alpha modifier only applies to a colour utility`)};switch(c){case`underline`:return noAlpha(),{textDecorationLine:`underline`};case`line-through`:return noAlpha(),{textDecorationLine:`line-through`};case`no-underline`:return noAlpha(),{textDecorationLine:`none`};case`uppercase`:return noAlpha(),{textTransform:`uppercase`};case`lowercase`:return noAlpha(),{textTransform:`lowercase`};case`capitalize`:return noAlpha(),{textTransform:`capitalize`};case`normal-case`:return noAlpha(),{textTransform:`none`};case`italic`:return noAlpha(),{fontStyle:`italic`};case`not-italic`:return noAlpha(),{fontStyle:`normal`};case`rounded`:return noAlpha(),{borderRadius:i(n.borderRadius,`DEFAULT`,t,`borderRadius`)};case`border`:return noAlpha(),{borderWidth:i(n.borderWidth,`DEFAULT`,t,`borderWidth`)}}let f=c.indexOf(`-`),p=f===-1?c:c.slice(0,f),m=f===-1?``:c.slice(f+1);switch(p){case`bg`:return{backgroundColor:colour(i(n.colors,m,t,`colors`))};case`opacity`:return noAlpha(),{opacity:i(n.opacity,m,t,`opacity`)};case`rounded`:{noAlpha();let e=l[m];return e===void 0?{borderRadius:i(n.borderRadius,m,t,`borderRadius`)}:{[e]:i(n.borderRadius,`DEFAULT`,t,`borderRadius`)}}case`border`:{let o=u[m];if(o!==void 0)return noAlpha(),{[o]:i(n.borderWidth,`DEFAULT`,t,`borderWidth`)};let s=r(n.borderWidth,m),c=r(n.colors,m);if(s!==void 0&&c!==void 0)throw new e(t,`"${m}" is in both the borderWidth and colors scales, so this utility is ambiguous`);if(s!==void 0)return noAlpha(),{borderWidth:s};if(c!==void 0)return{borderColor:colour(c)};throw new e(t,`"${m}" is in neither the borderWidth nor the colors scale`+(a(`borderWidth`,m)||a(`colors`,m)))}case`text`:{if(d.has(m))return null;let i=r(n.fontSize,m),o=r(n.colors,m);if(i!==void 0&&o!==void 0)throw new e(t,`"${m}" is in both the fontSize and colors scales, so this utility is ambiguous`);if(i!==void 0)return noAlpha(),{fontSize:i};if(o!==void 0)return{color:colour(o)};throw new e(t,`"${m}" is in neither the fontSize nor the colors scale`+(a(`fontSize`,m)||a(`colors`,m)))}case`font`:{noAlpha();let i=r(n.fontWeight,m),a=r(n.fontFamily,m);if(i!==void 0&&a!==void 0)throw new e(t,`"${m}" is in both the fontWeight and fontFamily scales, so this utility is ambiguous`);if(i!==void 0)return{fontWeight:i};if(a!==void 0)return{fontFamily:a};throw new e(t,`"${m}" is in neither the fontWeight nor the fontFamily scale`)}case`tracking`:return noAlpha(),{letterSpacing:i(n.letterSpacing,m,t,`letterSpacing`)};case`leading`:return noAlpha(),{lineHeight:i(n.lineHeight,m,t,`lineHeight`)}}return null}const l={tl:`borderTopLeftRadius`,tr:`borderTopRightRadius`,bl:`borderBottomLeftRadius`,br:`borderBottomRightRadius`},u={t:`borderTopWidth`,r:`borderRightWidth`,b:`borderBottomWidth`,l:`borderLeftWidth`},d=new Set([`left`,`center`,`right`,`justify`,`start`,`end`]),f=new Set(Object.keys(o));function partitionPaint(t){let r=[];for(let[i,a]of Object.entries(t)){if(a===void 0)continue;let t=o[i];if(t===void 0)throw new e(i,`is not a property the paint partition routes`);if(!n.has(t))throw new e(i,`maps to "${t}", which GTK does not accept — see gtk-css.ts`);let s=c[i];r.push(`${t}: ${s===void 0?a:s(a)}`)}let i=r.some(e=>/^border(-(top|right|bottom|left))?-width:/.test(e)),a=r.some(e=>/^border(-(top|right|bottom|left))?-style:/.test(e));return i&&!a&&r.push(`border-style: solid`),r}export{o as CSS_NAME,c as CSS_VALUE,s as CSS_VALUE_KIND,f as PAINT_PROPERTIES,partitionPaint,resolvePaintUtility};
@@ -1,4 +1,5 @@
1
1
  import type GObject from '@girs/gobject-2.0';
2
+ import type { AdwMenuInput } from '@gjsify/adwaita-core';
2
3
  import type { HostNode } from './types.js';
3
4
  /**
4
5
  * A `notify::` handler.
@@ -99,4 +100,34 @@ export interface JsxAttributes<T> extends SlotAttribute, RawSignalAttributes {
99
100
  */
100
101
  export interface VueAttributes extends SlotAttribute, RawSignalAttributes {
101
102
  }
103
+ /**
104
+ * The properties whose GObject type is a `GMenuModel`, in both spellings.
105
+ *
106
+ * A NAME LIST, not a type test, and the reason is measured rather than stylistic: the
107
+ * obvious `Gio.MenuModel extends NonNullable<T[K]> ? …` also matches every property
108
+ * typed as a wider GObject — `Gio.MenuModel extends GObject.Object` is TRUE — so the
109
+ * widening would leak onto properties that take an entirely different object. The three
110
+ * names below are the whole set on the shipped table (`menu-model` on the two menu
111
+ * buttons, the popover menu and the menu bar; `extra-menu` on the text widgets;
112
+ * `secondary-menu` on `AdwToolbarView`'s header bar), and `type-tests/` holds the
113
+ * widening against real markup in both dialects.
114
+ */
115
+ type MenuModelProp = 'menuModel' | 'menu-model' | 'extraMenu' | 'extra-menu' | 'secondaryMenu' | 'secondary-menu';
116
+ /**
117
+ * A props interface with every `GMenuModel` property widened to accept the PORTABLE
118
+ * menu model as well (ADR 0042).
119
+ *
120
+ * `Gio.MenuModel` is a GObject with no literal spelling, so before this a declarative
121
+ * dialect could not express a menu at all — the website gallery refused a Solid, Vue and
122
+ * React snippet for `Adw.SplitButton`, `Gtk.MenuButton` and `Gtk.PopoverMenu` for
123
+ * exactly that reason. The runtime half is `coerce`'s `GMenuModel` branch, which turns
124
+ * an authored array into a real `Gio.Menu` at the ParamSpec seam; this is the type that
125
+ * lets the array be written.
126
+ *
127
+ * A widget with NO such property is returned unchanged: `Omit` over a key it has not got
128
+ * is a no-op, and `MenuModelProp & keyof T` is then empty, so nothing is added either.
129
+ */
130
+ export type WithPortableMenu<T> = Omit<T, MenuModelProp> & {
131
+ [K in MenuModelProp & keyof T]?: T[K] | AdwMenuInput;
132
+ };
102
133
  export {};
@@ -1,8 +1,18 @@
1
1
  export { describeLogRecord, installDiagnosticsGate, isEnvironmentDiagnostic, type DiagnosticsGate, } from './diagnostics.js';
2
+ export { windowChromeCensus, windowChromeProblems, type WindowChromeCensus } from './window-chrome.js';
2
3
  import type Gtk from '@girs/gtk-4.0';
3
- import type { ChildPolicy, HostElement, WidgetDescriptor } from '../types.js';
4
+ import type { ChildPolicy, HostElement, NodePlacement, WidgetDescriptor } from '../types.js';
4
5
  /** Every method name a policy names, so the check does not have to know the shapes. */
5
6
  export declare function methodsOf(policy: ChildPolicy): string[];
7
+ /**
8
+ * Every method a PLACEMENT names — the second axis's answer to `methodsOf`.
9
+ *
10
+ * Separate from `methodsOf` rather than folded into it, because the two are
11
+ * checked against different things: a child policy's methods are called on the
12
+ * PARENT and a placement's on the NODE ITSELF, so a single list would make the
13
+ * message name the wrong object.
14
+ */
15
+ export declare function placementMethodsOf(placement: NodePlacement): string[];
6
16
  export interface DescriptorProblem {
7
17
  gtype: string;
8
18
  problem: string;
@@ -16,34 +26,13 @@ export interface DescriptorProblem {
16
26
  * the check runs up front and names the widget.
17
27
  */
18
28
  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[];
29
+ export { descendants, dumpTree, findDescendant, gtkChildTypes, gtkChildren } from './tree.js';
25
30
  /**
26
- * First STRICT descendant matching `pred`, breadth-first over the REAL GTK tree.
27
- *
28
- * Both showcase probes wrote this, identically. It excludes the root on purpose:
29
- * every caller is asking "what did the renderer put INSIDE this", and a root that
30
- * matches its own predicate answers a different question.
31
+ * The addresses a host element's element-children occupy, in shadow order.
31
32
  *
32
- * Breadth-first is not incidental either — `findDescendant(root, w => w instanceof
33
- * Gtk.Box)` on an Adwaita window finds an INTERNAL box of the header bar before
34
- * anything the author wrote, which is why a probe that needs a specific widget
35
- * reaches it through a landmark (a button's `get_parent()`) rather than by type.
36
- * Measured: with a search-by-type version, authoring `orientation="horizontal"`
37
- * still printed PROBE: PASS with byte-identical output.
33
+ * A PORTAL child occupies none — it is presented against this element and lives
34
+ * under the toplevel's dialog host — so including it would make every vector that
35
+ * compares this against the real child list disagree by one node that is not
36
+ * there.
38
37
  */
39
- export declare function findDescendant(root: Gtk.Widget, pred: (widget: Gtk.Widget) => boolean): Gtk.Widget | null;
40
- /**
41
- * Every widget in a subtree, ROOT FIRST and depth-first — GTK's own document order.
42
- *
43
- * Depth-first and not breadth-first, because the callers that collect (rather than
44
- * search) are asserting on ORDER: "the rows land before the counter row" is only a
45
- * claim about the tree if the walk visits it the way the tree reads.
46
- */
47
- export declare function descendants(root: Gtk.Widget): Gtk.Widget[];
48
- /** Recursive GType dump — what a devtools tree walk would show. */
49
- export declare function dumpTree(widget: Gtk.Widget, depth?: number): string;
38
+ export declare function addressesOf(el: HostElement): Gtk.Widget[];
@@ -0,0 +1,30 @@
1
+ import type Gtk from '@girs/gtk-4.0';
2
+ /** Direct GTK children of a widget, in GTK's own order. */
3
+ export declare function gtkChildren(widget: Gtk.Widget): Gtk.Widget[];
4
+ /** GType names of a widget's direct children — the cheap shape assertion. */
5
+ export declare const gtkChildTypes: (widget: Gtk.Widget) => string[];
6
+ /**
7
+ * First STRICT descendant matching `pred`, breadth-first over the REAL GTK tree.
8
+ *
9
+ * Both showcase probes wrote this, identically. It excludes the root on purpose:
10
+ * every caller is asking "what did the renderer put INSIDE this", and a root that
11
+ * matches its own predicate answers a different question.
12
+ *
13
+ * Breadth-first is not incidental either — `findDescendant(root, w => w instanceof
14
+ * Gtk.Box)` on an Adwaita window finds an INTERNAL box of the header bar before
15
+ * anything the author wrote, which is why a probe that needs a specific widget
16
+ * reaches it through a landmark (a button's `get_parent()`) rather than by type.
17
+ * Measured: with a search-by-type version, authoring `orientation="horizontal"`
18
+ * still printed PROBE: PASS with byte-identical output.
19
+ */
20
+ export declare function findDescendant(root: Gtk.Widget, pred: (widget: Gtk.Widget) => boolean): Gtk.Widget | null;
21
+ /**
22
+ * Every widget in a subtree, ROOT FIRST and depth-first — GTK's own document order.
23
+ *
24
+ * Depth-first and not breadth-first, because the callers that collect (rather than
25
+ * search) are asserting on ORDER: "the rows land before the counter row" is only a
26
+ * claim about the tree if the walk visits it the way the tree reads.
27
+ */
28
+ export declare function descendants(root: Gtk.Widget): Gtk.Widget[];
29
+ /** Recursive GType dump — what a devtools tree walk would show. */
30
+ export declare function dumpTree(widget: Gtk.Widget, depth?: number): string;
@@ -30,5 +30,11 @@ export interface VectorHarness {
30
30
  * `gated` rather than a bare `describe`: `@gjsify/unit` keeps ONE
31
31
  * `beforeEach`/`afterEach` slot per module and nulls both when a describe returns,
32
32
  * so hooks registered outside the block cover exactly one sibling.
33
+ *
34
+ * CORRECTED 2026-09-04 (#1554): hooks are SCOPED now — one frame per `describe`,
35
+ * popped when it returns — so hooks registered outside the block cover every
36
+ * sibling, and two registrations in one scope both run. `gated` stays because it
37
+ * keeps one declaration of what a gated block means, not because the runner
38
+ * forgets.
33
39
  */
34
40
  export declare function runAdapterVectors(harness: VectorHarness, gate: DiagnosticsGate): Promise<void>;
@@ -0,0 +1,29 @@
1
+ import Gtk from 'gi://Gtk?version=4.0';
2
+ /** What a window's chrome actually draws, per side of the decoration layout. */
3
+ export interface WindowChromeCensus {
4
+ /** Mapped, non-empty `GtkWindowControls` packed at the start of their header bar. */
5
+ readonly start: number;
6
+ /** The same at the end. On a GNOME host with a `:close` layout this is the close button. */
7
+ readonly end: number;
8
+ /** Mapped header bars, for the report. NOT the invariant — see the header. */
9
+ readonly headerBars: number;
10
+ /** Whether the root is mapped at all, i.e. whether the three counts mean anything. */
11
+ readonly mapped: boolean;
12
+ }
13
+ /**
14
+ * Count what the window's chrome draws.
15
+ *
16
+ * `get_empty()` is asked as well as `get_mapped()` because a `GtkWindowControls` is
17
+ * mapped on both sides of every header bar and draws buttons only on the side the
18
+ * decoration layout puts them: measured, a GNOME `:close` layout leaves six of the
19
+ * eight controls in a three-bar window empty and invisible.
20
+ */
21
+ export declare function windowChromeCensus(root: Gtk.Widget): WindowChromeCensus;
22
+ /**
23
+ * Every way this window's chrome is wrong, in sentences.
24
+ *
25
+ * An empty array is the only clean answer, and it is not reachable by accident: an
26
+ * unmapped root and a window whose chrome draws nothing at all are both named, so
27
+ * "no duplicates" cannot be produced by a tree that draws no chrome to duplicate.
28
+ */
29
+ export declare function windowChromeProblems(root: Gtk.Widget): string[];
@@ -19,6 +19,8 @@ export declare const err: {
19
19
  missingConstructProp: (tag: string, prop: string) => GtkHostError;
20
20
  unknownProp: (tag: string, prop: string) => GtkHostError;
21
21
  readOnlyProp: (tag: string, prop: string) => GtkHostError;
22
+ noAccessor: (tag: string, prop: string, accessor: string) => GtkHostError;
23
+ badDetailedAction: (label: string, detailed: string, why: string) => GtkHostError;
22
24
  badEnum: (tag: string, prop: string, nick: string, gtypeName: string) => GtkHostError;
23
25
  unknownSignal: (tag: string, prop: string, signal: string) => GtkHostError;
24
26
  signalTaken: (tag: string, prop: string, other: string, signal: string) => GtkHostError;
@@ -58,6 +60,15 @@ export declare const err: {
58
60
  siblingCycle: (parentTag: string) => GtkHostError;
59
61
  notAWidget: (tag: string) => GtkHostError;
60
62
  occupiedSlot: (parentTag: string, childTag: string, setter: string) => GtkHostError;
63
+ /**
64
+ * A portal descriptor naming a method the installed class does not have.
65
+ *
66
+ * `descriptorProblems()` rejects this shape up front, so a BUILT-IN descriptor
67
+ * can never reach here — an application-registered one is checked by nobody,
68
+ * and the alternative is `TypeError: widget[placement.present] is not a
69
+ * function` thrown from inside an insert, naming neither the tag nor the axis.
70
+ */
71
+ portalMethodMissing: (tag: string, method: string, role: "present" | "close") => GtkHostError;
61
72
  notAnElement: (kind: string) => GtkHostError;
62
73
  destroyedNode: (tag: string) => GtkHostError;
63
74
  notAHostParent: (got: string) => GtkHostError;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * The desktop face extensions `gjsify ship` stages, lower-cased.
3
+ *
4
+ * The same four the writing half accepts (`discoverFonts`, ADR 0038), and deliberately not a
5
+ * shared constant: this package cannot depend on `@gjsify/cli` — wrong direction and wrong tier —
6
+ * so the pairing is a specification both ends implement rather than a value one imports.
7
+ *
8
+ * `.woff`/`.woff2`/`.eot` are absent from BOTH ends. The writer refuses them by name because
9
+ * whether FreeType opens one is `FT_CONFIG_OPTION_USE_BROTLI`, a build option of whichever
10
+ * FreeType the SHIPPED artifact loads rather than of the packaging host; a reader that accepted
11
+ * them would hand the font map a file it may decline on the target and nowhere else.
12
+ */
13
+ export declare const FONT_FACE_EXTENSIONS: readonly string[];
14
+ export interface ResolveFontDirOptions {
15
+ /** Wins over everything — a dev tree (`data/fonts`), or a test fixture. */
16
+ fontDir?: string;
17
+ /** Environment to read `GJSIFY_FONT_DIR` from. */
18
+ env?: Record<string, string | undefined>;
19
+ }
20
+ /**
21
+ * Resolve the directory holding the application's shipped faces, or `undefined` when none is named.
22
+ *
23
+ * Precedence: explicit option, then `GJSIFY_FONT_DIR` — exported by the `gjsify ship` launcher,
24
+ * which is the only party that knows whether the payload became `/usr`, a `--prefix` tree, `/app`,
25
+ * a bundle's `Contents/Resources` or a Windows program directory.
26
+ *
27
+ * There is NO system fallback, and that is the one place this parts company with
28
+ * `resolveLocaleDir`, whose `/usr/share/locale` default is both correct and free. The analogous
29
+ * `/usr/share/fonts` is neither: fontconfig has already scanned it, so walking it again would add
30
+ * hundreds of `add_font_file` calls to every startup to arrive at families the font map holds
31
+ * anyway. `undefined` therefore means "this application ships no faces of its own" — the ordinary
32
+ * case, and a quiet one, because the launcher exports the variable only when it staged a face.
33
+ */
34
+ export declare function resolveFontDir(options?: ResolveFontDirOptions): string | undefined;
35
+ /**
36
+ * Is `name` a face {@link FONT_FACE_EXTENSIONS} covers?
37
+ *
38
+ * Extension-only and case-insensitive: `BRAND.TTF` is an ordinary name on the case-preserving
39
+ * filesystems macOS and Windows have, and a lowercase-only test would drop it into exactly the
40
+ * substituted-family failure this mechanism exists to prevent.
41
+ */
42
+ export declare function isFontFace(name: string): boolean;
@@ -0,0 +1,2 @@
1
+ declare const _default: () => Promise<void>;
2
+ export default _default;
@@ -0,0 +1,64 @@
1
+ import { type ResolveFontDirOptions } from './font-dir.js';
2
+ /** Everything {@link resolveFontDir} takes except the environment, which {@link initFonts} reads. */
3
+ export type InitFontsOptions = Omit<ResolveFontDirOptions, 'env'>;
4
+ /** A face the font map would not take, and why. */
5
+ export interface FontFaceFailure {
6
+ readonly path: string;
7
+ readonly message: string;
8
+ }
9
+ /** What {@link initFonts} did, so a caller that cares can assert on it. */
10
+ export interface InitFontsResult {
11
+ /** The directory that was read, or `undefined` when nothing named one. */
12
+ readonly dir: string | undefined;
13
+ /** Faces now on the default font map. */
14
+ readonly registered: readonly string[];
15
+ /** Faces the font map declined as unsupported — see {@link isUnsupportedByFontMap}. */
16
+ readonly declined: readonly string[];
17
+ /** Faces that failed for any other reason. Each was warned about; none threw. */
18
+ readonly failed: readonly FontFaceFailure[];
19
+ }
20
+ /**
21
+ * Did the font map decline runtime registration outright?
22
+ *
23
+ * `pango_font_map_add_font_file()` is a vfunc, and the CoreText map implements none — so on macOS
24
+ * the call falls through to the base implementation, which answers `G_IO_ERROR_NOT_SUPPORTED`.
25
+ * That is not a failure to report: macOS is already correct declaratively, because the bundle's
26
+ * `ATSApplicationFontsPath` had the OS activate the staged directory before the process started,
27
+ * and the ordering makes the runtime call the wrong tool there rather than merely a redundant one
28
+ * — `pango_core_text_font_map_changed()` only bumps a serial, there is no
29
+ * `kCTFontManagerRegisteredFontsChangedNotification` observer and no re-scan path in
30
+ * `pangocoretext-fontmap.c`, so a face registered after the map initialises could not be recovered
31
+ * by poking it anyway.
32
+ *
33
+ * Keyed on the ERROR rather than on `process.platform`, which is the difference between a
34
+ * capability test and a guess about who is asking. It costs no `gjsify.os` declaration (this
35
+ * package makes no OS decision, and ADR 0018's candidate set is derived from the code that reads
36
+ * the host), it stays right if a fontconfig-backed Pango is ever selected on darwin — the backend
37
+ * is chosen by what is compiled in, not per platform, and `PANGOCAIRO_BACKEND=fc` selects one — and
38
+ * it stays right for any other map that declines. The OS name was never the thing being asked.
39
+ */
40
+ export declare function isUnsupportedByFontMap(error: unknown): boolean;
41
+ /**
42
+ * Register every face in the application's shipped font directory with the default font map.
43
+ *
44
+ * Call it once at startup, and BEFORE any text is laid out — that ordering is load-bearing on the
45
+ * fontconfig backend rather than tidiness: it caches the FONTSET resolved for a description and
46
+ * `add_font_file` does not invalidate it, so a `Pango.Layout` that measured the family first keeps
47
+ * measuring the fallback for the life of the process even though the family is then in
48
+ * `list_families()`. win32 clears its cache instead and recovers, so registering early is free
49
+ * there and unrecoverable-if-missed on Linux (measured both ways; `fonts.spec.ts`).
50
+ *
51
+ * Nothing here is eager: this
52
+ * package is the element model renderers bind to and owns no application lifecycle, and a
53
+ * module-load side effect would decide an application's initialisation order invisibly — the same
54
+ * reason `gjsify ship` stages the faces and names the directory instead of injecting the call.
55
+ *
56
+ * Total, like `installDevtools`: a face that will not open costs one stderr line and appears in
57
+ * {@link InitFontsResult.failed}, never an exception. Taking an application down over a decorative
58
+ * face would be worse than rendering it in a fallback — but doing so SILENTLY is the defect this
59
+ * exists against, so it is loud and it is reported.
60
+ *
61
+ * Safe to call when the application ships no faces: `GJSIFY_FONT_DIR` is exported only when
62
+ * `gjsify ship` staged one, so an unset variable is the ordinary case and does nothing quietly.
63
+ */
64
+ export declare function initFonts(options?: InitFontsOptions): InitFontsResult;
@@ -0,0 +1,2 @@
1
+ declare const _default: () => Promise<void>;
2
+ export default _default;
@@ -1,7 +1,7 @@
1
1
  export * from './types.js';
2
2
  export { GtkHostError } from './errors.js';
3
3
  export { adopt, createAnchor, createDetachedContainer, createElement, createText, destroyChildren, destroy, disconnectHandlers, firstChild, insert, isHostElement, isText, materialize, mountRoot, nextSibling, parentNode, prevSibling, remove, setElementText, setEventHandler, setProp, setSlot, setText, widgetOf, } from './host.js';
4
- export { addressOf, reorderMode } from './policies.js';
4
+ export { addressOf, isPortal, placementOf, portalOf, reorderMode } from './policies.js';
5
5
  export { toSignalName, isEventProp } from './signals.js';
6
6
  export { constructOnlyNames, isConstructOnly, isWritable, lookupEnumNick, paramSpecs, toPropertyName, } from './props.js';
7
7
  export { assertInjective, tagOf } from './tags.js';
@@ -28,12 +28,12 @@
28
28
  * keys (TS2411). The camelCase spelling of every property IS checked, which is why
29
29
  * both spellings are generated and camelCase is the one to prefer.
30
30
  */
31
- import type { JsxAttributes, WithOnce } from './attrs.js';
31
+ import type { JsxAttributes, WithOnce, WithPortableMenu } from './attrs.js';
32
32
  import type { HostNode } from './types.js';
33
33
  import type { WidgetClassByTag, WidgetPropsByTag } from './generated/props.js';
34
34
  /** Every GTK/Adwaita tag, with its properties, its handlers and its `ref`. */
35
35
  export type GtkIntrinsicElements = {
36
- [K in keyof WidgetPropsByTag]: WithOnce<WidgetPropsByTag[K]> & JsxAttributes<WidgetClassByTag[K]>;
36
+ [K in keyof WidgetPropsByTag]: WithOnce<WithPortableMenu<WidgetPropsByTag[K]>> & JsxAttributes<WidgetClassByTag[K]>;
37
37
  };
38
38
  export declare namespace JSX {
39
39
  /**
@@ -0,0 +1,43 @@
1
+ import Gio from 'gi://Gio?version=2.0';
2
+ import type { AdwMenuInput, AdwMenuModel } from '@gjsify/adwaita-core';
3
+ /**
4
+ * A portable menu model as a live `Gio.Menu`.
5
+ *
6
+ * Accepts the AUTHORED form as well as the normalised one, so a JSX attribute needs no
7
+ * conversion step of its own: `normalizeMenuModel` is idempotent, which is what makes
8
+ * the two safe to take through one door.
9
+ */
10
+ export declare function buildGioMenu(input: AdwMenuInput | AdwMenuModel): Gio.Menu;
11
+ /**
12
+ * Whether a value is a portable menu model rather than a `GMenuModel`.
13
+ *
14
+ * An ARRAY, and nothing else. `Gio.MenuModel` is a GObject and never an array, so the
15
+ * test cannot confuse the two — and a caller passing a real `Gio.Menu` (the imperative
16
+ * path every existing GJS application uses) keeps passing it straight through.
17
+ */
18
+ export declare const isPortableMenu: (value: unknown) => value is AdwMenuInput;
19
+ /**
20
+ * A `GMenuModel` back as a portable model — the inverse of {@link buildGioMenu}.
21
+ *
22
+ * IT EXISTS TO MAKE THE LOSSLESS CLAIM MEASURABLE. ADR 0042 says the model maps onto
23
+ * `Gio.Menu` with nothing left over; a builder alone cannot show that, because whatever
24
+ * it drops is dropped in silence. `conformance/menu.ts` drives every vector through
25
+ * `buildGioMenu` and back through this function and compares, so a forgotten attribute
26
+ * fails a test naming it instead of disappearing from a popup nobody re-opened.
27
+ *
28
+ * It reads what GTK reads plus `id`, so an application's OWN extra attributes do not
29
+ * survive the round trip — stated rather than implied: this is not a general
30
+ * `GMenuModel` serialiser, it is the inverse of the builder above.
31
+ *
32
+ * TWO EDGES A HAND-BUILT `Gio.Menu` CAN REACH AND THE MODEL CANNOT, both matching GTK
33
+ * rather than diverging from it:
34
+ *
35
+ * · an item carrying BOTH links reads as a SECTION and its submenu is not walked.
36
+ * `GtkMenuTracker` decides the same way (`gtkmenutracker.c:317-352`): it tests
37
+ * `G_MENU_LINK_SECTION` first and
38
+ * recurses, so the submenu link is unreachable there too.
39
+ * · a non-string `label` reads as `''`. `attr()` asks for type `s`; so does
40
+ * `g_menu_item_get_attribute (item, "label", "&s", …)`, which fails the same way and
41
+ * leaves GTK drawing an unlabelled row.
42
+ */
43
+ export declare function fromGioMenu(model: Gio.MenuModel): AdwMenuModel;
@@ -0,0 +1,2 @@
1
+ declare const _default: () => Promise<void>;
2
+ export default _default;
@@ -1,5 +1,5 @@
1
1
  import Gtk from 'gi://Gtk?version=4.0';
2
- import type { ChildPolicy, HostElement } from './types.js';
2
+ import type { ChildPolicy, HostElement, NodePlacement, WidgetDescriptor } from './types.js';
3
3
  /** The object the PARENT addresses: a wrapper row when the policy demands one. */
4
4
  export declare function addressOf(el: HostElement): Gtk.Widget;
5
5
  /**
@@ -86,6 +86,70 @@ export declare function setterSlots(policy: ChildPolicy): string[];
86
86
  * occupant is the widget they handed over.
87
87
  */
88
88
  export declare function slotOccupant(widget: Gtk.Widget, setter: string): Gtk.Widget | null | undefined;
89
+ /**
90
+ * The declared placement of a node. The ONE place absence is turned into a value.
91
+ *
92
+ * Everything downstream switches on the union rather than on `descriptor.placement
93
+ * !== undefined`, so the absent case is a member with a name instead of a
94
+ * falsiness test that a third kind would quietly join.
95
+ */
96
+ export declare const placementOf: (descriptor: WidgetDescriptor) => NodePlacement;
97
+ /** The portal arm, or null. The narrow question four call sites ask. */
98
+ export declare function portalOf(descriptor: WidgetDescriptor): Extract<NodePlacement, {
99
+ kind: 'portal';
100
+ }> | null;
101
+ /** `unhandledPolicy`'s twin for the placement axis, and it exists for the same reason. */
102
+ export declare function unhandledPlacement(placement: never): never;
103
+ /** Is this node placed against its parent rather than into it? */
104
+ export declare const isPortal: (el: HostElement) => boolean;
105
+ /**
106
+ * Show a portal node against its parent — or subscribe and wait, if it is too early.
107
+ *
108
+ * Returns whether GTK has actually taken the node, which is what `attached` means.
109
+ *
110
+ * WHY THE WAIT IS THE FEATURE. Every framework builds bottom-up: React creates the
111
+ * whole subtree, appends its children, and inserts the ROOT into the container
112
+ * last, so at the moment a `<Modal>` is inserted its parent is usually not in a
113
+ * window yet. MEASURED on libadwaita 1.9.3 / GTK 4.22.4, presenting against an
114
+ * unrooted box: `adw_dialog_present` finds no `AdwDialogHost` among the parent's
115
+ * ancestors and takes its documented other branch, `present_as_window` — the
116
+ * dialog opens as a SEPARATE `GtkWindow`, `win.visibleDialog` stays false, exit 0,
117
+ * no diagnostic. A modal that floats out of its own application is exactly the
118
+ * green-and-wrong this host exists to refuse, and nothing in the shadow tree can
119
+ * see it.
120
+ *
121
+ * `notify::root` is the instrument. MEASURED: it fires on a GRANDCHILD box when
122
+ * the toplevel takes the subtree (root -> AdwWindow), and again on unroot (root ->
123
+ * null). The subscription STAYS for the life of the attachment rather than being
124
+ * one-shot, because re-rooting is real: measured, unrooting the parent leaves an
125
+ * already-presented dialog in the OLD window's host — `w1.visibleDialog` still
126
+ * true after `w1.set_content(null)` — so a subtree moved to a second window would
127
+ * silently keep showing its modal in the first.
128
+ *
129
+ * SYMMETRIC, and the second direction is not free. GTK does not take the dialog
130
+ * down when the anchor loses its window, so losing a toplevel RETRACTS the node
131
+ * rather than merely failing to present it (see `placeAgainst`). Without that, a
132
+ * subtree that is detached and never re-rooted keeps its sheet on screen in the
133
+ * window it left, and only a re-root — which such a subtree never gets — repairs it.
134
+ */
135
+ export declare function presentPortal(parent: HostElement, child: HostElement, portal: Extract<NodePlacement, {
136
+ kind: 'portal';
137
+ }>): boolean;
138
+ /**
139
+ * Take a portal node back down, with no probe and no `attached` guard.
140
+ *
141
+ * UNCONDITIONALLY, twice over, and both halves are measured. The method the
142
+ * descriptor names is the FORCED close (`force_close`, not `close`): an unmount is
143
+ * not a user request, and `close()` on a dialog whose `can-close` is FALSE returns
144
+ * FALSE, emits `close-attempt` and leaves it on screen. And `force_close()` on a
145
+ * node that was never presented is silent, where `close()` is
146
+ * `Adwaita-CRITICAL **: Trying to close … that's not presented` at exit 0 — so the
147
+ * host needs no "is it up?" question, which is the one it could not answer without
148
+ * knowing what a dialog is.
149
+ */
150
+ export declare function retractPortal(child: HostElement, portal: Extract<NodePlacement, {
151
+ kind: 'portal';
152
+ }>): void;
89
153
  export interface Placement {
90
154
  parent: HostElement;
91
155
  child: HostElement;
@@ -0,0 +1,2 @@
1
+ declare const _default: () => Promise<void>;
2
+ export default _default;
@@ -33,7 +33,7 @@
33
33
  */
34
34
  import type { Key, ReactElement, ReactNode, Ref } from 'react';
35
35
  import type { WidgetClassByTag, WidgetPropsByTag } from './generated/props.js';
36
- import type { RawSignalAttributes, SlotAttribute, WithOnce } from './attrs.js';
36
+ import type { RawSignalAttributes, SlotAttribute, WithOnce, WithPortableMenu } from './attrs.js';
37
37
  export { Fragment } from 'react/jsx-runtime';
38
38
  /**
39
39
  * React's own factories, RE-TYPED over this package's element list.
@@ -74,7 +74,7 @@ export interface ReactWidgetAttributes<T> extends SlotAttribute, RawSignalAttrib
74
74
  }
75
75
  /** Every GTK/Adwaita tag, with its properties, its handlers, its `ref` and its `key`. */
76
76
  export type GtkReactIntrinsicElements = {
77
- [K in keyof WidgetPropsByTag]: WithOnce<WidgetPropsByTag[K]> & ReactWidgetAttributes<WidgetClassByTag[K]>;
77
+ [K in keyof WidgetPropsByTag]: WithOnce<WithPortableMenu<WidgetPropsByTag[K]>> & ReactWidgetAttributes<WidgetClassByTag[K]>;
78
78
  };
79
79
  export declare namespace JSX {
80
80
  /**
@@ -0,0 +1,64 @@
1
+ /**
2
+ * A `font-family` value → the text that goes into the declaration.
3
+ *
4
+ * Exported because a consumer that has been quoting defensively (see the incident in
5
+ * the header) can call this instead and stop, and because both routes into the
6
+ * partition — a `style={{ fontFamily }}` object and a `font-*` utility resolving
7
+ * against `tokens.fontFamily` — must go through exactly this one function.
8
+ */
9
+ export declare function serialiseFontFamily(value: string): string;
10
+ /**
11
+ * What GTK does with an authored value that was NOT serialised.
12
+ *
13
+ * Three states rather than a boolean, and the third one is why. `refused` is the
14
+ * loud bug — GTK rejects the declaration, the containment probe rejects the rule,
15
+ * and the screen is gone. `misread` is the QUIET one: GTK accepts the bare text and
16
+ * resolves a DIFFERENT family, so the application renders in a substituted font with
17
+ * no diagnostic anywhere. A boolean column would have merged `misread` into
18
+ * `accepted` and asserted that serialising changes nothing — which is false for
19
+ * exactly the vectors where changing something is the whole point.
20
+ */
21
+ export type BareReading = 'refused' | 'accepted' | 'misread';
22
+ /** One authored `font-family` value, what it must become, and what GTK does with it unserialised. */
23
+ export interface FontFamilyVector {
24
+ /** What a `tokens.fontFamily` entry or a `style={{ fontFamily }}` carries. */
25
+ readonly authored: string;
26
+ /** What {@link serialiseFontFamily} must emit for it. */
27
+ readonly emitted: string;
28
+ /**
29
+ * What GTK does with `authored` AS IT STANDS.
30
+ *
31
+ * The column that makes this table a test rather than a restatement, and every
32
+ * state of it is RE-MEASURED against the running GTK by `gtk-css.spec.ts`:
33
+ * `refused` must be rejected, `accepted` must parse to the same computed value
34
+ * as `emitted`, and `misread` must parse to a DIFFERENT one. So the state is a
35
+ * finding and not a claim, and a vector cannot quietly stop exercising the rule.
36
+ */
37
+ readonly bare: BareReading;
38
+ }
39
+ /**
40
+ * The conformance set for `font-family` values.
41
+ *
42
+ * WHY THIS TABLE EXISTS, and it is the whole finding behind #1539. `gtk-css.ts`
43
+ * probed `['font-family', 'Cantarell']` — ONE word, valid as a bare identifier, and
44
+ * therefore the single family for which the missing quoting is invisible. The suite
45
+ * asserted that `font-family` is emitted and never that it is emitted CORRECTLY, so
46
+ * it would have gone green against an implementation that quoted nothing. A vector
47
+ * whose value cannot exercise the rule reads exactly like a vector that passed.
48
+ *
49
+ * So the set carries, deliberately: a family that NEEDS quoting, a family that does
50
+ * not, a bare multi-identifier family GTK already accepted (the case a
51
+ * quote-on-space reading would call broken), a stack mixing a quoted family with a
52
+ * bare keyword, a value already quoted, a `var()` reference, and a value GTK MISREADS
53
+ * rather than refuses. `bare` is re-measured by `gtk-css.spec.ts`, which also refuses
54
+ * a table that has lost its refused or its misread vectors.
55
+ *
56
+ * The three added after the first review are the shapes the SPLIT and the two
57
+ * PASSTHROUGHS have to survive rather than the quoter: a bare name carrying an odd
58
+ * quote character in front of a fallback, a nested `var()`, and an already-quoted
59
+ * member holding a carriage return. Each was emitted as something GTK accepted and
60
+ * was wrong about — so `gtk-css.spec.ts` also holds the three CLASSES directly, by
61
+ * asking GTK where the fallback member ended up, whether the document survived, and
62
+ * whether a declaration appeared that nothing here wrote.
63
+ */
64
+ export declare const FONT_FAMILY_VECTORS: readonly FontFamilyVector[];
@@ -3,8 +3,10 @@ export { GTK_WIDGET_PROPERTIES, GTK_WIDGET_PROPERTY_PROBES, NOT_GTK_WIDGET_PROPE
3
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
- export { PAINT_PROPERTIES, partitionPaint, resolvePaintUtility } from './paint.js';
6
+ export { CSS_VALUE, CSS_VALUE_KIND, PAINT_PROPERTIES, partitionPaint, resolvePaintUtility } from './paint.js';
7
7
  export type { PaintProps } from './paint.js';
8
+ export { FONT_FAMILY_VECTORS, serialiseFontFamily } from './font-family.js';
9
+ export type { FontFamilyVector } from './font-family.js';
8
10
  export { LAYOUT_PROPERTIES, partitionLayout, resolveLayoutUtility } from './layout.js';
9
11
  export type { AlignValue, Edge, JustifyValue, LayoutIntent, LayoutPartition, LayoutProps, OverlayIntent, WrapIntent, } from './layout.js';
10
12
  export { partition, resolveUtilities, resolveUtility } from './resolve.js';
@@ -32,6 +32,38 @@ export interface PaintProps {
32
32
  * `partition`'s per-call guard, which no input can reach while the table is right.
33
33
  */
34
34
  export declare const CSS_NAME: Readonly<Record<keyof PaintProps, string>>;
35
+ /**
36
+ * What KIND of value each property carries — and therefore whether that value can
37
+ * end the declaration early.
38
+ *
39
+ * DECLARED, not derived, because it is a judgement about a vocabulary rather than
40
+ * something the code can compute. It is here so the judgement is machine-held: the
41
+ * key set is `keyof PaintProps`, so a new property cannot skip it, and
42
+ * `paint.spec.ts` asserts that the `name`-valued properties are EXACTLY the ones
43
+ * {@link CSS_VALUE} serialises. A colour, a length, a number and a keyword are all
44
+ * self-delimiting; a `name` is supplied verbatim by the project and is the only kind
45
+ * that can carry a space, a comma or a quote.
46
+ *
47
+ * The measured answer today is that `font-family` is the only one — checked against
48
+ * the layout half too, which emits margins and paddings and nothing else. The next
49
+ * candidate is not hypothetical: `background-image: url(…)` would be the second.
50
+ */
51
+ export declare const CSS_VALUE_KIND: Readonly<Record<keyof PaintProps, 'colour' | 'length' | 'number' | 'keyword' | 'name'>>;
52
+ /**
53
+ * The properties whose value is SERIALISED rather than interpolated.
54
+ *
55
+ * PER PROPERTY, and that is the design rather than an accident of there being one
56
+ * entry: a global rule would have to decide what a comma or a space means without
57
+ * knowing which property it is in, and it means something different in every one.
58
+ * The table is the seam a second such property joins at, and
59
+ * {@link CSS_VALUE_KIND} is what makes joining it compulsory.
60
+ *
61
+ * Both routes to a `font-family` — a `style={{ fontFamily }}` object and a `font-*`
62
+ * utility resolving against `tokens.fontFamily` — arrive at `partitionPaint`, so
63
+ * one entry here covers both. That is why the serialisation lives at the emitter
64
+ * and not at either front end.
65
+ */
66
+ export declare const CSS_VALUE: Readonly<Partial<Record<keyof PaintProps, (value: string) => string>>>;
35
67
  /**
36
68
  * One utility class → the paint properties it sets, or `null` for "not mine".
37
69
  *
@@ -49,5 +81,10 @@ export declare const PAINT_PROPERTIES: ReadonlySet<string>;
49
81
  * GTK's parser with no diagnostic, which is the exact silence the whole partition
50
82
  * exists to avoid. The check is cheap and it has caught the one property that looks
51
83
  * like paint and is not.
84
+ *
85
+ * The VALUE gets the same treatment, per property, through {@link CSS_VALUE}. A
86
+ * checked name with an unserialised value is only half the guard: GTK refused the
87
+ * whole rule for `font-family: Source Sans 3` while the property name was right
88
+ * (#1539), and the value is the half a project supplies verbatim.
52
89
  */
53
90
  export declare function partitionPaint(props: PaintProps): readonly string[];
@@ -74,8 +74,74 @@ export interface HostElement extends HostNodeBase {
74
74
  * computes "first" and the whole rendered tree lands ABOVE the app's own chrome.
75
75
  */
76
76
  foreign: readonly Gtk.Widget[];
77
+ /**
78
+ * A PORTAL node's subscription to its parent's `root`, or null.
79
+ *
80
+ * Only a `portal` placement ever has one, and it is per-attachment state
81
+ * exactly like `wrapper` — a side table keyed on the element would be a second
82
+ * tree that can disagree with this one. See {@link NodePlacement}'s portal arm
83
+ * for what the subscription is for and what it was measured against.
84
+ */
85
+ portalWatch: {
86
+ widget: Gtk.Widget;
87
+ id: number;
88
+ } | null;
77
89
  }
78
90
  export type HostNode = HostElement | HostText | HostAnchor;
91
+ /**
92
+ * The axis ABOVE `ChildPolicy`, and the two are orthogonal on purpose.
93
+ *
94
+ * `ChildPolicy` answers "how does this parent adopt a child". It presumes the
95
+ * answer to a question nobody had to ask until now: *does this node go into its
96
+ * parent at all?* For every widget in the table it does. For an `Adw.Dialog` it
97
+ * does not, and the difference is not a degradation the parent can absorb —
98
+ * MEASURED on libadwaita 1.9.3 / GTK 4.22.4 / gjs 1.88.1, `box.append(dialog)`
99
+ * with the box ROOTED IN A WINDOW reaches
100
+ *
101
+ * Adwaita-ERROR **: Trying to add AdwDialog 0x… to GtkBox 0x…. Use
102
+ * adw_dialog_present() to show dialogs.
103
+ *
104
+ * which is `g_error()`: SIGABRT, exit 134, a core dump. Not an exception a `try`
105
+ * in the reconciler can catch and not a warning a diagnostics gate can count.
106
+ * `adw_dialog_root()` raises it from the ROOT vfunc, which is why a DETACHED box
107
+ * accepts the very same append in silence at exit 0 — re-testing this on a bare
108
+ * box "disproves" it and puts the append back.
109
+ *
110
+ * So the descriptor declares the axis, and `policies.ts` is the only reader.
111
+ * `parented` is every other widget and is what an ABSENT `placement` means; the
112
+ * union still cannot be forgotten because there is exactly one normaliser
113
+ * (`placementOf`) and every switch over it ends in `unhandledPlacement`.
114
+ */
115
+ export type NodePlacement =
116
+ /** The parent's `ChildPolicy` places it. Every widget but the dialog family. */
117
+ {
118
+ readonly kind: 'parented';
119
+ }
120
+ /**
121
+ * The node places ITSELF against its parent: `present(parent)` / `close()`.
122
+ *
123
+ * Three measurements shape the two method names, all on libadwaita 1.9.3:
124
+ *
125
+ * - `present` TAKES THE PARENT WIDGET (`adw_dialog_present` arity 1, against
126
+ * `gtk_window_present`'s 0). That is what makes this a portal rather than a
127
+ * toplevel: the node has a place in the shadow tree and a different place in
128
+ * the GTK tree, and the parent is what joins them.
129
+ * - `close` IS THE UNCONDITIONAL ONE, `force_close` and not `close`. An
130
+ * unmount is not a user request: with `can-close: false` (which is how
131
+ * `onRequestClose` is honoured one layer up) `adw_dialog_close()` returns
132
+ * FALSE, emits `close-attempt` and LEAVES THE DIALOG ON SCREEN — measured.
133
+ * `force_close()` closes it and emits `closed`.
134
+ * - AND `force_close` IS SAFE ON A NODE THAT WAS NEVER PRESENTED, where
135
+ * `close` is not: measured, `close()` on an unpresented dialog answers
136
+ * `Adwaita-CRITICAL **: Trying to close AdwDialog 0x… that's not presented`
137
+ * at exit 0, and `force_close()` is silent. So the host needs no
138
+ * "is it up?" probe before retracting one.
139
+ */
140
+ | {
141
+ readonly kind: 'portal';
142
+ readonly present: string;
143
+ readonly close: string;
144
+ };
79
145
  export type PolicyKind = 'none' | 'single' | 'ordered' | 'indexed' | 'slotted' | 'keyed' | 'coords';
80
146
  /**
81
147
  * How a parent adopts children. GTK4 deleted `GtkContainer`, so there is no
@@ -261,6 +327,19 @@ export interface WidgetDescriptor {
261
327
  /** Lazy so `gi://` loads late and an unused descriptor costs nothing. */
262
328
  readonly ctor: () => GObject.ObjectClass & (new (props?: Record<string, unknown>) => GObject.Object);
263
329
  readonly children: ChildPolicy;
330
+ /**
331
+ * How this node reaches the screen. Absent means `{ kind: 'parented' }`.
332
+ *
333
+ * Optional rather than required, and the reason is the shape of the table
334
+ * rather than convenience: the generated half is the whole GIR widget set and
335
+ * not one row of it is a portal, so a required field would be ~900 identical
336
+ * lines. Nothing is left implicit by that — `placementOf()` normalises the
337
+ * absence in ONE place and every switch over the result has a `never` arm, so
338
+ * a third placement kind cannot be added without every reader failing to
339
+ * compile. `descriptorProblems()` holds the declared methods against the
340
+ * installed class, exactly as it does for `children`.
341
+ */
342
+ readonly placement?: NodePlacement;
264
343
  /**
265
344
  * Where a text child goes. Absent means text under this widget is an ERROR
266
345
  * that names the tag — never a silent drop.
@@ -33,11 +33,11 @@
33
33
  * resolve goes unchecked.
34
34
  */
35
35
  import type { DefineComponent } from '@vue/runtime-core';
36
- import type { VueAttributes, WithOnce } from './attrs.js';
36
+ import type { VueAttributes, WithOnce, WithPortableMenu } from './attrs.js';
37
37
  import type { WidgetPropsByGType, WidgetPropsVueAliases } from './generated/props.js';
38
38
  type VueWidgetProps = WidgetPropsByGType & WidgetPropsVueAliases;
39
39
  export type GtkGlobalComponents = {
40
- [K in keyof VueWidgetProps]: DefineComponent<WithOnce<VueWidgetProps[K]> & VueAttributes>;
40
+ [K in keyof VueWidgetProps]: DefineComponent<WithOnce<WithPortableMenu<VueWidgetProps[K]>> & VueAttributes>;
41
41
  };
42
42
  declare module '@vue/runtime-core' {
43
43
  interface GlobalComponents extends GtkGlobalComponents {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjsify/gtk-host",
3
- "version": "0.46.0",
3
+ "version": "0.48.0",
4
4
  "description": "Framework-agnostic GTK4/Adwaita host: the element model UI-framework renderers bind to",
5
5
  "type": "module",
6
6
  "module": "lib/esm/index.js",
@@ -18,6 +18,10 @@
18
18
  "types": "./lib/types/list/index.d.ts",
19
19
  "default": "./lib/esm/list/index.js"
20
20
  },
21
+ "./fonts": {
22
+ "types": "./lib/types/fonts.d.ts",
23
+ "default": "./lib/esm/fonts.js"
24
+ },
21
25
  "./vue": {
22
26
  "types": "./lib/types/adapters/vue.d.ts",
23
27
  "default": "./lib/esm/adapters/vue.js"
@@ -93,7 +97,9 @@
93
97
  "@girs/glib-2.0": "4.6.0",
94
98
  "@girs/gobject-2.0": "4.6.0",
95
99
  "@girs/gtk-4.0": "4.6.0",
96
- "@girs/pango-1.0": "4.6.0"
100
+ "@girs/pango-1.0": "4.6.0",
101
+ "@girs/pangocairo-1.0": "4.6.0",
102
+ "@gjsify/adwaita-core": "^0.48.0"
97
103
  },
98
104
  "peerDependencies": {
99
105
  "@vue/runtime-core": "^3.5.0",
@@ -116,10 +122,10 @@
116
122
  }
117
123
  },
118
124
  "devDependencies": {
119
- "@gjsify/cli": "^0.46.0",
125
+ "@gjsify/cli": "^0.48.0",
120
126
  "@vue/runtime-core": "^3.5.0",
121
127
  "solid-js": "^1.9.0",
122
- "@gjsify/unit": "^0.46.0",
128
+ "@gjsify/unit": "^0.48.0",
123
129
  "@types/node": "^25.9.2",
124
130
  "typescript": "^6.0.3",
125
131
  "@gjsify/node-gi": "file:../../node-gi/node-gi",