@gjsify/adwaita-core 0.64.12-next.280 → 0.64.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/esm/list.js CHANGED
@@ -1 +1 @@
1
- import"./_virtual/_rolldown/runtime.js";function normalizeComboOptions(e){return Array.isArray(e)?e.map(e=>{if(typeof e==`string`)return{value:e,label:e};let t=e?.value===void 0?String(e?.label??``):String(e.value);return{value:t,label:e?.label===void 0?t:String(e.label)}}):[]}function parseListModel(e){if(!e)return[];try{return normalizeComboOptions(JSON.parse(e))}catch{return[]}}const e=-1;function clampListSelection(e,t){return Number.isFinite(e)&&e>=0&&e<t?e:t===0?-1:0}function sameItem(e,t){return e!==void 0&&t!==void 0&&e.value===t.value&&e.label===t.label}function listItemsChanged(e,t){let n=e??[],r=t??[],i=Math.min(n.length,r.length),a=0;for(;a<i&&sameItem(n[a],r[a]);)a++;let o=0;for(;o<i-a&&sameItem(n[n.length-1-o],r[r.length-1-o]);)o++;let s=n.length-a-o,c=r.length-a-o;return s===0&&c===0?null:{position:a,removed:s,added:c}}export{e as ADW_COMBO_NO_SELECTION,clampListSelection,listItemsChanged,normalizeComboOptions,parseListModel};
1
+ import"./_virtual/_rolldown/runtime.js";function readListModel(e){let t=e;if(typeof t?.get_n_items!=`function`||typeof t.get_item!=`function`)return[];let n=[],r=t.get_n_items();for(let e=0;e<r;e++){let r=t.get_item(e);n.push(typeof r?.string==`string`?r.string:r??{})}return n}function normalizeComboOptions(e){return(Array.isArray(e)?e:readListModel(e)).map(e=>{if(typeof e==`string`)return{value:e,label:e};let t=e?.value===void 0?String(e?.label??``):String(e.value);return{value:t,label:e?.label===void 0?t:String(e.label)}})}function parseListModel(e){if(!e)return[];try{return normalizeComboOptions(JSON.parse(e))}catch{return[]}}const e=-1;function sameItem(e,t){return e!==void 0&&t!==void 0&&e.value===t.value&&e.label===t.label}function listItemsChanged(e,t){let n=e??[],r=t??[],i=Math.min(n.length,r.length),a=0;for(;a<i&&sameItem(n[a],r[a]);)a++;let o=0;for(;o<i-a&&sameItem(n[n.length-1-o],r[r.length-1-o]);)o++;let s=n.length-a-o,c=r.length-a-o;return s===0&&c===0?null:{position:a,removed:s,added:c}}export{e as ADW_COMBO_NO_SELECTION,listItemsChanged,normalizeComboOptions,parseListModel};
package/lib/esm/markup.js CHANGED
@@ -1,4 +1,4 @@
1
1
  import"./_virtual/_rolldown/runtime.js";import{GTK_WIDGET_EXPAND as e,attributeOf as t,hostTagOf as n,isValueBasedBooleanAttr as r,propertyOf as i,widgetLengthStyle as a}from"./tags.js";function element(e,t,n,r,i,a){let o=` `.repeat(e),s=n.map(([e,t])=>t===null?e:`${e}=${r(t)}`),c=i.length===0,l=c?a?` />`:`></${t}>`:`>`,u=`${o}<${[t,...s].join(` `)}${l}`,d=u.length<=80||s.length===0?u:[`${o}<${t}`,...s.map(e=>`${o} ${e}`),`${o}${c?a?`/>`:`></${t}>`:`>`}`].join(`
2
2
  `);return c?d:[d,...i,`${o}</${t}>`].join(`
3
- `)}const htmlText=e=>e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`),htmlQuote=e=>{let t=e.includes(`"`)&&!e.includes(`'`)?`'`:`"`;return`${t}${e.replace(/&/g,`&amp;`).replace(t===`"`?/"/g:/'/g,t===`"`?`&quot;`:`&#39;`)}${t}`};function refuseBehaviour(e,t=`sharedTreeHtml`){let n=[e.bindings&&`bindings`,e.breakpoints&&`breakpoints`].filter(Boolean);if(n.length>0)throw Error(`${t} has no markup for \`${e.tag}\`'s ${n.join(` and `)} (ADR 0093); a bound property and a breakpoint are behaviour, and a renderer has to observe them.`)}function htmlElement(i,o){refuseBehaviour(i);let s=[];i.id!==void 0&&s.push([`id`,i.id]);let c=[],l=n(i.tag);for(let[n,o]of Object.entries(i.props??{})){let i=t(n);typeof o==`boolean`?r(l,i)?s.push([i,o?`true`:`false`]):o?s.push([i,null]):e.some(e=>e===i)&&s.push([i,`false`]):s.push([i,String(o)]);let u=a(i,o);u!==void 0&&u[1]!==null&&c.push(`${u[0]}: ${u[1]};`)}c.length>0&&s.push([`style`,c.join(` `)]),i.styleClasses!==void 0&&i.styleClasses.length>0&&s.push([`class`,i.styleClasses.join(` `)]);let u=i.extensions?.strings;u!==void 0&&s.push([`strings`,JSON.stringify(u.map(e=>e.value))]),i.slot!==void 0&&s.push([`slot`,i.slot]);let d=[...(i.extensions?.responses??[]).map(e=>{let t=[`id=${htmlQuote(e.id)}`];e.appearance!==void 0&&t.push(`appearance=${htmlQuote(e.appearance)}`),e.enabled===!1&&t.push(`enabled="false"`);let n=htmlText(e.label);return`${` `.repeat(o+1)}<adw-alert-response ${t.join(` `)}>${n}</adw-alert-response>`}),...(i.children??[]).map(e=>htmlElement(e,o+1))];return element(o,n(i.tag),s,htmlQuote,d,!1)}function sharedTreeHtml(e){return htmlElement(e,0)}function xmlNameOf(e){let t=/^(Adw|Gtk)([A-Z]\w*)$/.exec(e);if(t===null)throw Error(`sharedTreeNativeScriptXml: ${e} is not an Adw or Gtk class name`);return{prefix:t[1].toLowerCase(),member:t[2]}}const xmlQuote=e=>{let t=e.includes(`"`)?`'`:`"`;return`${t}${e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(t===`"`?/"/g:/'/g,t===`"`?`&quot;`:`&apos;`)}${t}`};function prefixesOf(e,t){t.add(xmlNameOf(e.tag).prefix);for(let n of e.children??[])prefixesOf(n,t);return t}const o=[`columns`,`cssClasses`,`direction`,`modal`,`rows`,`visibility`];function xmlElement(e,t,n){refuseBehaviour(e,`sharedTreeNativeScriptXml`);let{prefix:r,member:a}=xmlNameOf(e.tag),s=`${r}:${a}`,c=[...n];e.id!==void 0&&c.push([`id`,e.id]);for(let[t,n]of Object.entries(e.props??{})){let r=i(t);if(o.includes(r))throw Error(`sharedTreeNativeScriptXml: \`${e.tag}\`'s '${t}' has no XML spelling — the attribute would reach NativeScript's own \`${r}\` (ADR 0112). Set it from Blueprint, a .ui file or \`set_${t.replace(/-/g,`_`)}()\`.`);c.push([r,String(n)])}e.styleClasses!==void 0&&e.styleClasses.length>0&&c.push([`styleClasses`,e.styleClasses.join(` `)]);let l=e.extensions?.strings;l!==void 0&&c.push([`strings`,JSON.stringify(l.map(e=>e.value))]);let u=(e.children??[]).map(e=>{if(e.slot===void 0)return xmlElement(e,t+1,[]);let n=` `.repeat(t+1),r=`${s}.${e.slot}`;return[`${n}<${r}>`,xmlElement(e,t+2,[]),`${n}</${r}>`].join(`
3
+ `)}const htmlText=e=>e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`),htmlQuote=e=>{let t=e.includes(`"`)&&!e.includes(`'`)?`'`:`"`;return`${t}${e.replace(/&/g,`&amp;`).replace(t===`"`?/"/g:/'/g,t===`"`?`&quot;`:`&#39;`)}${t}`};function refuseBehaviour(e,t=`sharedTreeHtml`){let n=[e.bindings&&`bindings`,e.breakpoints&&`breakpoints`].filter(Boolean);if(n.length>0)throw Error(`${t} has no markup for \`${e.tag}\`'s ${n.join(` and `)} (ADR 0093); a bound property and a breakpoint are behaviour, and a renderer has to observe them.`)}function htmlElement(i,o){refuseBehaviour(i);let s=[];i.id!==void 0&&s.push([`id`,i.id]);let c=[],l=n(i.tag);for(let[n,o]of Object.entries(i.props??{})){let i=t(n);typeof o==`boolean`?r(l,i)?s.push([i,o?`true`:`false`]):o?s.push([i,null]):e.some(e=>e===i)&&s.push([i,`false`]):s.push([i,String(o)]);let u=a(i,o);u!==void 0&&u[1]!==null&&c.push(`${u[0]}: ${u[1]};`)}c.length>0&&s.push([`style`,c.join(` `)]),i.styleClasses!==void 0&&i.styleClasses.length>0&&s.push([`class`,i.styleClasses.join(` `)]);let u=i.extensions?.strings;u!==void 0&&s.push([`strings`,JSON.stringify(u.map(e=>e.value))]),i.slot!==void 0&&s.push([`slot`,i.slot]);let d=[...(i.extensions?.responses??[]).map(e=>{let t=[`id=${htmlQuote(e.id)}`];e.appearance!==void 0&&t.push(`appearance=${htmlQuote(e.appearance)}`),e.enabled===!1&&t.push(`enabled="false"`);let n=htmlText(e.label);return`${` `.repeat(o+1)}<adw-alert-response ${t.join(` `)}>${n}</adw-alert-response>`}),...(i.children??[]).map(e=>htmlElement(e,o+1))];return element(o,n(i.tag),s,htmlQuote,d,!1)}function sharedTreeHtml(e){return htmlElement(e,0)}function xmlNameOf(e){let t=/^(Adw|Gtk)([A-Z]\w*)$/.exec(e);if(t===null)throw Error(`sharedTreeNativeScriptXml: ${e} is not an Adw or Gtk class name`);return{prefix:t[1].toLowerCase(),member:t[2]}}const xmlQuote=e=>{let t=e.includes(`"`)?`'`:`"`;return`${t}${e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(t===`"`?/"/g:/'/g,t===`"`?`&quot;`:`&apos;`)}${t}`};function isModelAttribute(e){return e.tag===`GtkStringList`&&e.slot===`model`&&e.id===void 0&&e.extensions?.strings!==void 0}function prefixesOf(e,t){t.add(xmlNameOf(e.tag).prefix);for(let n of e.children??[])isModelAttribute(n)||prefixesOf(n,t);return t}const o=[`columns`,`cssClasses`,`direction`,`modal`,`rows`,`visibility`];function xmlElement(e,t,n){refuseBehaviour(e,`sharedTreeNativeScriptXml`);let{prefix:r,member:a}=xmlNameOf(e.tag),s=`${r}:${a}`,c=[...n];e.id!==void 0&&c.push([`id`,e.id]);for(let[t,n]of Object.entries(e.props??{})){let r=i(t);if(o.includes(r))throw Error(`sharedTreeNativeScriptXml: \`${e.tag}\`'s '${t}' has no XML spelling — the attribute would reach NativeScript's own \`${r}\` (ADR 0112). Set it from Blueprint, a .ui file or \`set_${t.replace(/-/g,`_`)}()\`.`);c.push([r,String(n)])}e.styleClasses!==void 0&&e.styleClasses.length>0&&c.push([`styleClasses`,e.styleClasses.join(` `)]);let l=[];for(let t of e.children??[]){let e=t.extensions?.strings;if(e===void 0){l.push(t);continue}if(!isModelAttribute(t))throw Error(`sharedTreeNativeScriptXml: \`${t.tag}\`'s strings have no XML spelling — \`strings\` is construct-only (ADR 0122); only a \`GtkStringList\` without an id at a \`model\` slot is written, as the parent's \`model\` attribute.`);c.push([`model`,JSON.stringify(e.map(e=>e.value))])}if(e.extensions?.strings!==void 0)throw Error(`sharedTreeNativeScriptXml: \`${e.tag}\`'s strings have no XML spelling — \`strings\` is construct-only (ADR 0122), so a list is written as its parent's \`model\` attribute.`);let u=l.map(e=>{if(e.slot===void 0)return xmlElement(e,t+1,[]);let n=` `.repeat(t+1),r=`${s}.${e.slot}`;return[`${n}<${r}>`,xmlElement(e,t+2,[]),`${n}</${r}>`].join(`
4
4
  `)});return element(t,s,c,xmlQuote,u,!0)}function sharedTreeNativeScriptXml(e){return xmlElement(e,0,[[`xmlns`,`http://schemas.nativescript.org/tns.xsd`],...[...prefixesOf(e,new Set)].sort().map(e=>[`xmlns:${e}`,`~/${e}`])])}export{o as NATIVESCRIPT_HOST_MEMBERS,sharedTreeHtml,sharedTreeNativeScriptXml};
@@ -0,0 +1 @@
1
+ import"./_virtual/_rolldown/runtime.js";import{GObjectObject as e,ListModel as t,ParamFlags as n,ParamSpec as r,checkPropertyValue as i,registerBaseClass as a}from"./gobject.js";import{MAXUINT32 as o}from"./glib-paths.js";import{INVALID_LIST_POSITION as s}from"./gtk-string-list.js";import{listItemsChanged as c,normalizeComboOptions as l,parseListModel as u}from"./list.js";const d=new WeakMap,f=new WeakMap;function notWritable(e,t){throw Error(`Property ${e}.${t} is not writable`)}var p=class GjsifyOptionObject extends e{constructor(e){super(e??void 0),d.has(this)||d.set(this,{value:``,label:``})}static new(e,t){let n=new GjsifyOptionObject;return d.set(n,{value:String(e),label:String(t)}),n}static fromInput(e){let[t]=l([e]);return GjsifyOptionObject.new(t.value,t.label)}get value(){return d.get(this).value}set value(e){notWritable(`GjsifyOptionObject`,`value`)}get label(){return d.get(this).label}set label(e){notWritable(`GjsifyOptionObject`,`label`)}toOption(){let e=d.get(this);return{value:e.value,label:e.label}}};a(p,`GjsifyOptionObject`,{},[r.string(`value`,``,``,n.READABLE,``),r.string(`label`,``,``,n.READABLE,``)]);var m=class GjsifyOptionList extends e{constructor(e){let t={...e};delete t.options,super(t),f.set(this,(e?.options??[]).map(e=>p.fromInput(e)))}static new(e){return new GjsifyOptionList({options:e})}get item_type(){return p.$gtype}set item_type(e){notWritable(`GjsifyOptionList`,`item-type`)}get itemType(){return this.item_type}set itemType(e){notWritable(`GjsifyOptionList`,`item-type`)}get n_items(){return f.get(this).length}set n_items(e){notWritable(`GjsifyOptionList`,`n-items`)}vfunc_get_item_type(){return this.item_type}vfunc_get_n_items(){return this.n_items}vfunc_get_item(e){return f.get(this)[e]??null}toOptions(){return f.get(this).map(e=>e.toOption())}append(e){this.splice(this.n_items,0,[e])}remove(e){this.splice(e,1,[])}splice(e,t,n){this.spliceItems(e,t,(n??[]).map(e=>p.fromInput(e)))}find(e){let t=f.get(this).findIndex(t=>t.value===e);return t===-1?s:t}reconcile(e){let t=l(e??[]),n=c(this.toOptions(),t);n&&this.spliceItems(n.position,n.removed,t.slice(n.position,n.position+n.added).map(e=>p.new(e.value,e.label)))}spliceItems(e,t,n){let r=f.get(this);if(!Number.isFinite(e)||e<0||e+t>r.length){console.warn(`GLib-GIO-CRITICAL: g_list_store_splice: assertion 'position + n_removals <= n_items' failed`);return}t===0&&n.length===0||(r.splice(e,t,...n),this.items_changed(e,t,n.length),t!==n.length&&this.notify(`n-items`))}};a(m,`GjsifyOptionList`,{},[r.uint(`n-items`,``,``,n.READABLE,0,o,0)],[t]);const h=r.object(`model`,``,``,n.READWRITE,t);function readModelWrite(e,t){if(e==null)return null;if(typeof e==`string`)return t.reconcile(u(e)),t;let n=e;return(typeof n.get_n_items!=`function`||typeof n.get_item!=`function`)&&i(h,e),e}export{m as GjsifyOptionList,p as GjsifyOptionObject,readModelWrite};
package/lib/esm/rows.js CHANGED
@@ -1 +1 @@
1
- import"./_virtual/_rolldown/runtime.js";import{SpinState as e}from"./adjustment.js";import{ADW_COMBO_NO_SELECTION as t,clampListSelection as n,listItemsChanged as r,normalizeComboOptions as i}from"./list.js";var ExpanderState=class{constructor(){this._expanded=!1,this._listeners=new Set}subscribe(e){return this._listeners.add(e),()=>{this._listeners.delete(e)}}_emit(){for(let e of[...this._listeners])e(this._expanded)}get expanded(){return this._expanded}setExpanded(e){let t=!!e;return t===this._expanded?!1:(this._expanded=t,this._emit(),!0)}toggle(){return this.setExpanded(!this._expanded)}expand(){return this.setExpanded(!0)}collapse(){return this.setExpanded(!1)}},ComboState=class{constructor(){this._options=[],this._selected=0,this._listeners=new Set,this._itemListeners=new Set}subscribe(e){return this._listeners.add(e),()=>{this._listeners.delete(e)}}subscribeItems(e){return this._itemListeners.add(e),()=>{this._itemListeners.delete(e)}}_emit(e){let t={selected:this._selected,value:this.selectedValue,label:this.selectedLabel,interactive:e};for(let e of[...this._listeners])e(t)}_setIndex(e,t){return e===this._selected?!1:(this._selected=e,this._emit(t),!0)}get model(){return this._options.map(e=>({value:e.value,label:e.label}))}setModel(e){let t=this._options,i=Array.isArray(e)?e:[],a=r(t,i);if(this._options=i.map(e=>({value:e.value,label:e.label})),this._selected=n(this._selected,i.length),a)for(let e of[...this._itemListeners])e(a);this._emit(!1)}get selectedIndex(){return this._selected}get presentsChooser(){return this._options.length>1}setSelectedIndex(e){return this._setIndex(Number.isFinite(e)?e:0,!1)}get selectedValue(){return this._options[this._selected]?.value??``}get selectedLabel(){return this._options[this._selected]?.label??``}setSelectedValue(e){let t=this._options.findIndex(t=>t.value===e);return t>=0?this.setSelectedIndex(t):!1}hasIndex(e){return Number.isFinite(e)&&e>=0&&e<this._options.length}select(e){return!this.hasIndex(e)||e===this._selected?!1:this._setIndex(e,!0)}get count(){return this._options.length}},ToggleGroupState=class{constructor(){this._labels=[],this._selected=0,this._listeners=new Set}subscribe(e){return this._listeners.add(e),()=>{this._listeners.delete(e)}}_emit(){let e={selected:this._selected,value:this.selectedValue};for(let t of[...this._listeners])t(e)}get labels(){return this._labels}setLabels(e){this._labels=Array.isArray(e)?e:[],this._selected>=this._labels.length&&(this._selected=0)}get selected(){return this._selected}setSelected(e){let t=Number.isFinite(e)?e:0;return t===this._selected||t<0||t>=this._labels.length?!1:(this._selected=t,this._emit(),!0)}get selectedValue(){return this._labels[this._selected]??``}get count(){return this._labels.length}};function keptToggles(e){let t=new Set,n=[];for(let r of e){let e=r.name??null;e!==null&&t.has(e)||(e!==null&&t.add(e),n.push(r))}return n}function toggleIndexOfName(e,t){return e.indexOf(t)}export{t as ADW_COMBO_NO_SELECTION,ComboState,ExpanderState,e as SpinState,ToggleGroupState,keptToggles,i as normalizeComboOptions,toggleIndexOfName};
1
+ import"./_virtual/_rolldown/runtime.js";import{SpinState as e}from"./adjustment.js";import{ADW_COMBO_NO_SELECTION as t,listItemsChanged as n,normalizeComboOptions as r}from"./list.js";var ExpanderState=class{constructor(){this._expanded=!1,this._listeners=new Set}subscribe(e){return this._listeners.add(e),()=>{this._listeners.delete(e)}}_emit(){for(let e of[...this._listeners])e(this._expanded)}get expanded(){return this._expanded}setExpanded(e){let t=!!e;return t===this._expanded?!1:(this._expanded=t,this._emit(),!0)}toggle(){return this.setExpanded(!this._expanded)}expand(){return this.setExpanded(!0)}collapse(){return this.setExpanded(!1)}};function watchItemsChanged(e,t){if(typeof e.connect!=`function`||typeof e.disconnect!=`function`)return()=>{};let n=e.connect(`items-changed`,(...e)=>{let[n,r,i]=e.slice(1);t({position:n??0,removed:r??0,added:i??0})});return()=>void e.disconnect?.(n)}var ComboState=class{constructor(){this._model=null,this._options=[],this._selected=-1,this._unwatch=null,this._listeners=new Set,this._itemListeners=new Set,this._notifyListeners=new Set}subscribe(e){return this._listeners.add(e),()=>{this._listeners.delete(e)}}subscribeNotify(e){return this._notifyListeners.add(e),()=>{this._notifyListeners.delete(e)}}subscribeItems(e){return this._itemListeners.add(e),()=>{this._itemListeners.delete(e)}}_emit(e){let t={selected:this._selected,value:this.selectedValue,label:this.selectedLabel,interactive:e};for(let e of[...this._listeners])e(t)}_notify(e){for(let t of[...this._notifyListeners])t(e)}_emitItems(e){for(let t of[...this._itemListeners])t(e)}_setIndex(e,t){return e===this._selected?!1:(this._selected=e,this._emit(t),this._notify(`selected`),this._notify(`selected-item`),!0)}get model(){return this._model}get options(){return this._options.map(e=>({value:e.value,label:e.label}))}get selectedItem(){return!this._model||this._selected<0?null:this._model.get_item(this._selected)??null}setModel(e){if(e===this._model)return;this._unwatch?.(),this._unwatch=null;let t=this._options;this._model=e,this._options=e?r(e):[],this._selected=this._options.length===0?-1:0,e&&(this._unwatch=watchItemsChanged(e,e=>this._onItemsChanged(e)));let i=n(t,this._options);i&&this._emitItems(i),this._emit(!1),e&&(this._notify(`selected`),this._notify(`selected-item`)),this._notify(`model`)}_onItemsChanged(e){this._options=this._model?r(this._model):[],this._emitItems(e);let t=this._selected,n=this._options.length;if(t===-1){if(n===0)return;this._selected=0,this._emit(!1),this._notify(`selected-item`),this._notify(`selected`);return}if(!(t<e.position)){if(t>=e.position+e.removed){this._selected=t+e.added-e.removed,this._emit(!1),this._notify(`selected`);return}this._selected=n===0?-1:Math.min(e.position,n-1),this._emit(!1),this._notify(`selected-item`),this._selected!==t&&this._notify(`selected`)}}get selectedIndex(){return this._selected}get presentsChooser(){return this._options.length>1}setSelectedIndex(e){return this.hasIndex(e)?this._setIndex(e,!1):!1}get selectedValue(){return this._options[this._selected]?.value??``}get selectedLabel(){return this._options[this._selected]?.label??``}setSelectedValue(e){let t=this._options.findIndex(t=>t.value===e);return t>=0?this.setSelectedIndex(t):!1}hasIndex(e){return Number.isFinite(e)&&e>=0&&e<this._options.length}select(e){return!this.hasIndex(e)||e===this._selected?!1:this._setIndex(e,!0)}get count(){return this._options.length}},ToggleGroupState=class{constructor(){this._labels=[],this._selected=0,this._listeners=new Set}subscribe(e){return this._listeners.add(e),()=>{this._listeners.delete(e)}}_emit(){let e={selected:this._selected,value:this.selectedValue};for(let t of[...this._listeners])t(e)}get labels(){return this._labels}setLabels(e){this._labels=Array.isArray(e)?e:[],this._selected>=this._labels.length&&(this._selected=0)}get selected(){return this._selected}setSelected(e){let t=Number.isFinite(e)?e:0;return t===this._selected||t<0||t>=this._labels.length?!1:(this._selected=t,this._emit(),!0)}get selectedValue(){return this._labels[this._selected]??``}get count(){return this._labels.length}};function keptToggles(e){let t=new Set,n=[];for(let r of e){let e=r.name??null;e!==null&&t.has(e)||(e!==null&&t.add(e),n.push(r))}return n}function toggleIndexOfName(e,t){return e.indexOf(t)}export{t as ADW_COMBO_NO_SELECTION,ComboState,ExpanderState,e as SpinState,ToggleGroupState,keptToggles,r as normalizeComboOptions,toggleIndexOfName};
@@ -1,7 +1,7 @@
1
1
  import type { BindingFlag, BlueprintTemplate, GObjectConstructor, GObjectInstance, GObjectNamespace } from '../gobject.js';
2
2
  import type { ConstructHarness } from './constructs.js';
3
3
  /** The rows of ADR 0096 § 2 that carry a claim; every one needs a vector. */
4
- export declare const GOBJECT_ROWS: readonly ["registerClass", "field-form", "ParamSpec", "Signals", "instance API", "type_ensure", "vfunc", "binding engine", "template"];
4
+ export declare const GOBJECT_ROWS: readonly ["registerClass", "field-form", "ParamSpec", "Signals", "instance API", "type_ensure", "vfunc", "binding engine", "template", "interface", "object property"];
5
5
  export type GObjectRow = (typeof GOBJECT_ROWS)[number];
6
6
  /** A template, in both spellings: GtkBuilder XML for GJS, the projected tree for a port. */
7
7
  export interface GObjectTemplateSource {
@@ -19,6 +19,24 @@ export interface GObjectSubject {
19
19
  readonly Widget?: GObjectConstructor;
20
20
  /** The value to put in `Template`. */
21
21
  template(source: GObjectTemplateSource): unknown;
22
+ /**
23
+ * The `Gio.ListModel` token a vector puts in `Implements` — the real interface on an oracle,
24
+ * the core's token on the subset. Absent where no Gio is reachable, which skips those rows.
25
+ */
26
+ readonly ListModel?: unknown;
27
+ /**
28
+ * Something carrying a READ-WRITE object-kind property called `model` whose value type is
29
+ * `Gio.ListModel`, and a value that property accepts.
30
+ *
31
+ * A REAL C object (`Gtk.DropDown` + `Gtk.StringList`) on the oracles, because a JS-registered
32
+ * class is not one for this row: GJS's auto-accessors store without a GValue conversion, so a
33
+ * JS class would accept every value the C property refuses and the refusal vectors would
34
+ * measure nothing. It needs a display, so an oracle offers it only where Gtk initialised.
35
+ */
36
+ objectProperty?(): {
37
+ readonly instance: GObjectInstance;
38
+ readonly accepted: GObjectInstance;
39
+ };
22
40
  /** The binding engine; `bind_property` on GJS, which is not exported by the ports. */
23
41
  bind(source: GObjectInstance, sourceProperty: string, target: GObjectInstance, targetProperty: string, flags: readonly BindingFlag[]): void;
24
42
  }
@@ -27,6 +45,10 @@ export interface GObjectVector {
27
45
  readonly rule: string;
28
46
  readonly holds: 'oracle' | 'subset';
29
47
  readonly widget?: true;
48
+ /** Needs {@link GObjectSubject.ListModel}; skipped where the subject has no Gio. */
49
+ readonly iface?: true;
50
+ /** Needs {@link GObjectSubject.objectProperty}; skipped where the subject cannot build one. */
51
+ readonly objectProperty?: true;
30
52
  readonly observe: (subject: GObjectSubject) => unknown;
31
53
  readonly shows: unknown;
32
54
  }
@@ -16,8 +16,8 @@ export type { ComboRowLike, RowAccessorSubject, RowAccessorVector, StringListLik
16
16
  export type { RadioGroupStep, RadioGroupVector } from './checks.js';
17
17
  export { CHECK_GROUP_VECTORS, driveCheckGroupVectors } from './check-group.js';
18
18
  export type { CheckButtonLike, CheckGroupSubject, CheckGroupVector } from './check-group.js';
19
- export { COMBO_CHOOSER_VECTORS, COMBO_SELECTION_VECTORS, TOGGLE_ACTIVE_NAME_VECTORS } from './rows.js';
20
- export type { ComboChooserVector, ComboSelectionStep, ComboSelectionVector, ToggleActiveNameVector } from './rows.js';
19
+ export { COMBO_CHOOSER_VECTORS, COMBO_ITEMS_CHANGED_VECTORS, COMBO_SELECTION_VECTORS, TOGGLE_ACTIVE_NAME_VECTORS, } from './rows.js';
20
+ export type { ComboChooserVector, ComboItemsChangedVector, ComboSelectionStep, ComboSelectionVector, ComboSpliceStep, ToggleActiveNameVector, } from './rows.js';
21
21
  export { VIEW_STACK_ICON_NAME_VECTORS, VIEW_STACK_PAGE_VECTORS, VIEW_STACK_VECTORS } from './view-stack.js';
22
22
  export type { ViewStackIconNameVector, ViewStackPageDescriptorVector, ViewStackVector, ViewStackVectorChange, ViewStackVectorOp, ViewStackVectorPage, } from './view-stack.js';
23
23
  export { NAVIGATION_VIEW_VECTORS, collectNavigationState, navigationEventLog, runNavigationSteps, } from './navigation-view.js';
@@ -32,8 +32,8 @@ export { MENU_BUTTON_DIRECTION_VECTORS, SPLIT_BUTTON_CONTENT_VECTORS, SPLIT_BUTT
32
32
  export type { SplitButtonContentStep, SplitButtonContentVector, SplitButtonDirectionVector, SplitButtonDropdownVector, SplitButtonMenuActivationVector, SplitButtonRootStateVector, SplitButtonStyleClassVector, SplitButtonTooltipVector, } from './split-button.js';
33
33
  export { ADJUSTMENT_AUTHORED_VECTORS, ADJUSTMENT_PARSE_VECTORS, ADJUSTMENT_SNAP_VECTORS } from './adjustment.js';
34
34
  export type { AdjustmentAuthoredVector, AdjustmentParseVector, AdjustmentSnapVector } from './adjustment.js';
35
- export { LIST_ITEMS_CHANGED_VECTORS, LIST_MODEL_OWNERSHIP_VECTORS, LIST_NORMALIZE_VECTORS, LIST_PARSE_VECTORS, LIST_SELECTION_CLAMP_VECTORS, TAB_PAGES_ITEMS_CHANGED_VECTORS, applyListReadback, replayTabPagesAsSplices, } from './list.js';
36
- export type { ListItemsChangedVector, ListModelOwnershipVector, ListNormalizeVector, ListParseVector, ListReadbackOp, ListSelectionClampVector, TabPagesItemsChangedVector, } from './list.js';
35
+ export { LIST_ITEMS_CHANGED_VECTORS, LIST_MODEL_OWNERSHIP_VECTORS, LIST_NORMALIZE_VECTORS, LIST_PARSE_VECTORS, TAB_PAGES_ITEMS_CHANGED_VECTORS, applyListMutation, applyListReadback, listModelForInput, replayTabPagesAsSplices, } from './list.js';
36
+ export type { ListItemsChangedVector, ListModelOwnershipVector, ListNormalizeVector, ListParseVector, ListReadbackOp, TabPagesItemsChangedVector, } from './list.js';
37
37
  export { COLUMN_VIEW_SORT_VECTORS, GRID_VIEW_COLUMN_VECTORS, LIST_VIEW_SELECT_VECTORS } from './list-view.js';
38
38
  export type { ColumnViewSortVector, GridViewColumnVector, ListViewClick, ListViewSelectVector } from './list-view.js';
39
39
  export { TREE_EXPANDER_LAYOUT_VECTORS, TREE_EXPANDER_SHORTCUT_VECTORS } from './tree-expander.js';
@@ -1,4 +1,5 @@
1
- import type { AdwComboOption, AdwListItemsChanged, AdwListModel, AdwListModelInput } from '../list.js';
1
+ import type { AdwComboOption, AdwListItemsChanged, AdwListModel, AdwListModelInput, AdwListModelSource } from '../list.js';
2
+ import { GjsifyOptionList } from '../option-list.js';
2
3
  import type { TabViewPagesChange } from '../tab-view.js';
3
4
  /** One {@link normalizeComboOptions} expectation. */
4
5
  export interface ListNormalizeVector {
@@ -24,6 +25,19 @@ export interface ListNormalizeVector {
24
25
  * a citation, and that sentence named no table).
25
26
  */
26
27
  export declare const LIST_NORMALIZE_VECTORS: ReadonlyArray<ListNormalizeVector>;
28
+ /**
29
+ * A {@link LIST_NORMALIZE_VECTORS} row as the value a `model` PROPERTY write takes.
30
+ *
31
+ * ADR 0122 § 4 took the array arm off that property, so the ARRAY rows go in as a list built
32
+ * out of the array: the normaliser still runs on them, one step further in, as
33
+ * {@link GjsifyOptionList}'s own constructor. The model-source rows go STRAIGHT through —
34
+ * that is the shape the door now takes, and they are what proves a surface reads items by
35
+ * position rather than recognising one class.
36
+ *
37
+ * Lives here rather than in each driving suite because WHICH door a row reaches through is
38
+ * part of what the table claims, and two copies of that answer are two claims.
39
+ */
40
+ export declare function listModelForInput(input: AdwListModelInput): AdwListModelSource;
27
41
  /** One {@link parseListModel} expectation — the JSON attribute door. */
28
42
  export interface ListParseVector {
29
43
  /** The attribute value exactly as authored. */
@@ -65,20 +79,21 @@ export interface ListItemsChangedVector {
65
79
  * change, which is `g_list_store_splice`'s shape.
66
80
  */
67
81
  export declare const LIST_ITEMS_CHANGED_VECTORS: ReadonlyArray<ListItemsChangedVector>;
68
- /** What a caller does to the array it read back out of a `model` accessor. */
82
+ /** What a caller does to the options they hold, or to the model they were handed. */
69
83
  export type ListReadbackOp = 'append' | 'relabel-first' | 'remove-first';
70
- /** One read-mutate-assign expectation — see {@link LIST_MODEL_OWNERSHIP_VECTORS}. */
84
+ /** One ownership expectation — see {@link LIST_MODEL_OWNERSHIP_VECTORS}. */
71
85
  export interface ListModelOwnershipVector {
72
86
  initial: AdwListModel;
73
87
  /**
74
- * Which array the caller mutates: the one `model` handed BACK, or the one they
75
- * assigned and kept. Two doors into the same failure, and closing one leaves the other.
88
+ * WHAT the caller mutates. `input` is the array they authored and handed to
89
+ * `GjsifyOptionList.new`; `options` is the array read back out of `toOptions()`; `model`
90
+ * is the list itself, through its own `Gio.ListModel` API. The first two must move
91
+ * nothing and the third must move everything, and which of the three a surface gets
92
+ * wrong is the difference between a leak and a dropped redraw.
76
93
  */
77
- source: 'readback' | 'input';
94
+ source: 'options' | 'input' | 'model';
78
95
  op: ListReadbackOp;
79
- /** Whether the mutated array is assigned back to `model` afterwards. */
80
- assign: boolean;
81
- /** The model the surface holds when the row is done. */
96
+ /** The options the surface holds when the row is done. */
82
97
  model: AdwListModel;
83
98
  /** The splice the surface emits, or `null` where it emits none. */
84
99
  itemsChanged: AdwListItemsChanged | null;
@@ -87,50 +102,42 @@ export interface ListModelOwnershipVector {
87
102
  rule: string;
88
103
  }
89
104
  /**
90
- * WHO OWNS THE ARRAY a `model` accessor hands back — read, mutate, assign.
105
+ * WHO OWNS THE OPTIONS — the arrays a caller holds on either side of the model, and the
106
+ * model itself.
91
107
  *
92
108
  * The browser suite drives `LIST_MODEL_OWNERSHIP_VECTORS` through `<adw-combo-row>` and
93
- * `<gtk-drop-down>`, and core drives it through `ComboState` itself, which is the surface
94
- * where BOTH doors are reachable: the element setters run `normalizeComboOptions` and so
95
- * close the input door on their own, while `ComboState.setModel` takes a normalised model
96
- * straight from a caller.
109
+ * `<gtk-drop-down>`, and core drives it through `ComboState`.
97
110
  *
98
- * THE ROWS EXIST BECAUSE THE SPLICE MADE THIS A SILENT FAILURE. Under the full rebuild
99
- * every assignment redrew the list, so an aliased array was invisible; the splice decides
100
- * what to redraw by COMPARING the assignment against the stored model, and an alias makes
101
- * both sides read the new value — "nothing changed", nothing drawn, no error. `append`
102
- * with `assign` is the pattern that regressed, `relabel-first` is the same failure one
103
- * level down through a shared descriptor (which is why the copy is per ITEM and not just
104
- * per array), and the `assign: false` row is the invariant the other two rest on: what a
105
- * caller holds is THEIRS, so touching it moves nothing until they hand it back.
111
+ * READ, MUTATE, ASSIGN IS GONE AS A PATTERN, and that is what reshaped these rows. ADR 0122
112
+ * § 4 narrows `model` to a real `Gio.ListModel`, so there is no array to assign back: the
113
+ * only way to change a model in place is its own API, and handing over a DIFFERENT list is a
114
+ * replacement that resets the selection. What survives from the array era is the half that
115
+ * was never about assignment — an array a caller holds is THEIRS on both sides, going in
116
+ * (`GjsifyOptionList` copies each descriptor into an item) and coming out (`toOptions`
117
+ * copies each item back). `relabel-first` is why the copy is per ITEM rather than per array:
118
+ * a shared descriptor would let the text under a selection move with nothing emitted, which
119
+ * is the failure `GjsifyOptionObject`'s read-only `label` exists to prevent.
120
+ *
121
+ * The `model` rows are the other side of the same invariant: the ONE door that does move the
122
+ * list emits the one minimal splice for it, in each of the three directions a splice can go.
106
123
  */
107
124
  export declare const LIST_MODEL_OWNERSHIP_VECTORS: ReadonlyArray<ListModelOwnershipVector>;
108
125
  /**
109
- * The caller-side half of one {@link LIST_MODEL_OWNERSHIP_VECTORS} row: mutate the array a
110
- * `model` accessor handed back, IN PLACE, and hand the same array back.
126
+ * The caller-side half of an `options`/`input` row: mutate the array, IN PLACE, and hand the
127
+ * same array back.
111
128
  *
112
129
  * In place and returning its argument is the whole point — a helper that built a new array
113
130
  * would test the pattern that never broke.
114
131
  */
115
132
  export declare function applyListReadback(model: AdwComboOption[], op: ListReadbackOp): AdwComboOption[];
116
- /** One {@link clampListSelection} expectation. */
117
- export interface ListSelectionClampVector {
118
- selected: number;
119
- length: number;
120
- result: number;
121
- rule: string;
122
- }
123
133
  /**
124
- * Where a selection lands after the model under it was replaced.
134
+ * The model-side half: the same three ops through the list's own `Gio.ListModel` API.
125
135
  *
126
- * The browser suite drives `LIST_SELECTION_CLAMP_VECTORS` through `<adw-combo-row>` and
127
- * through that element only. `<gtk-drop-down>` REFUSES an out-of-range `selected` set
128
- * outright — its published contract, with `ComboState.hasIndex` as the shared bounds — so
129
- * the starting index these rows replace cannot be put on that element in the first place.
130
- * One row is narrower than the vector even on the row, and `adw-row-state.spec.ts` says
131
- * so in place.
136
+ * `relabel-first` is a splice rather than an assignment because {@link GjsifyOptionObject}
137
+ * is read-only — changing what an item says means putting a different item there, which is
138
+ * also how `Gio.ListStore` would have to spell it.
132
139
  */
133
- export declare const LIST_SELECTION_CLAMP_VECTORS: ReadonlyArray<ListSelectionClampVector>;
140
+ export declare function applyListMutation(model: GjsifyOptionList, op: ListReadbackOp): void;
134
141
  /** One {@link tabViewItemsChanged} expectation, with the order it replays. */
135
142
  export interface TabPagesItemsChangedVector {
136
143
  change: TabViewPagesChange;
@@ -1,12 +1,21 @@
1
- import type { AdwComboOption, ComboStateChange } from '../rows.js';
1
+ import type { AdwComboOption, ComboNotify, ComboStateChange } from '../rows.js';
2
2
  /**
3
3
  * One mutation in a combo scenario. DATA, not a closure: a renderer suite
4
4
  * replays these against a real widget (set the options, pick from the chooser)
5
5
  * and compares what the user would see.
6
+ *
7
+ * `setModel` carries the model's CONTENTS and not a model object, so the table stays
8
+ * portable: each renderer builds whatever model it holds — a `GjsifyOptionList` in the
9
+ * core and in both browser elements, the same on the NativeScript host — out of these
10
+ * descriptors. `setModelAgain` is the one step that is about the model's IDENTITY rather
11
+ * than its contents, and it is a step rather than a flag because that is the only way to
12
+ * spell "assign the object you are already holding" in data.
6
13
  */
7
14
  export type ComboSelectionStep = {
8
15
  op: 'setModel';
9
16
  model: ReadonlyArray<AdwComboOption>;
17
+ } | {
18
+ op: 'setModelAgain';
10
19
  } | {
11
20
  op: 'setSelectedIndex';
12
21
  index: number;
@@ -23,7 +32,7 @@ export interface ComboSelectionVector {
23
32
  steps: readonly ComboSelectionStep[];
24
33
  /** `selectedIndex` afterwards. */
25
34
  selected: number;
26
- /** `selectedValue` afterwards — `''` when the index sits outside the options. */
35
+ /** `selectedValue` afterwards — `''` when nothing is selected. */
27
36
  value: string;
28
37
  /** `selectedLabel` afterwards — the text the inline value / button shows. */
29
38
  label: string;
@@ -33,6 +42,12 @@ export interface ComboSelectionVector {
33
42
  * gated on `interactive`.
34
43
  */
35
44
  emitted: ReadonlyArray<ComboStateChange>;
45
+ /**
46
+ * Every `notify::` the scenario owes, flattened in EMISSION ORDER — see the module
47
+ * header. Driven by the surfaces that have real GObject properties; a DOM renderer
48
+ * skips it.
49
+ */
50
+ notified: ReadonlyArray<ComboNotify>;
36
51
  rule: string;
37
52
  }
38
53
  /**
@@ -46,6 +61,51 @@ export interface ComboSelectionVector {
46
61
  * replaced. That first change is in `emitted` for exactly that reason.
47
62
  */
48
63
  export declare const COMBO_SELECTION_VECTORS: ReadonlyArray<ComboSelectionVector>;
64
+ /** One splice applied to the model a combo state is HOLDING. */
65
+ export interface ComboSpliceStep {
66
+ position: number;
67
+ removed: number;
68
+ added: ReadonlyArray<AdwComboOption>;
69
+ }
70
+ /** One `items-changed` → selection scenario. */
71
+ export interface ComboItemsChangedVector {
72
+ name: string;
73
+ /** The model the state holds before the splice. */
74
+ initial: ReadonlyArray<AdwComboOption>;
75
+ /** Where the selection sits before the splice — `-1` leaves the sentinel in place. */
76
+ selected: number;
77
+ splice: ComboSpliceStep;
78
+ /** `selectedIndex` after the splice. */
79
+ result: number;
80
+ /** `selectedValue` after the splice. */
81
+ value: string;
82
+ /** The `notify::` the splice owes, in order — EMPTY where GTK emits none. */
83
+ notified: ReadonlyArray<ComboNotify>;
84
+ rule: string;
85
+ }
86
+ /**
87
+ * What a splice on the HELD model does to the selection — `GtkSingleSelection`'s
88
+ * `items-changed` handler, which `Adw.ComboRow` and `Gtk.DropDown` both sit on.
89
+ *
90
+ * NEW IN ADR 0122, and only reachable since it: while `model` was an Array the only way to
91
+ * change the list was to replace it, so this whole axis had no spelling. A live
92
+ * `Gio.ListModel` moves under the widget, and WHERE it moved decides whether the selection
93
+ * follows the item, shifts with it, or is clamped because the item is gone.
94
+ *
95
+ * Every row is MEASURED (`combo-probe2.js`), and the `notified` column is the point of the
96
+ * table: the order here is the INVERSE of a `selected` write — `selected-item` first,
97
+ * because what changed is the item and the index is downstream of it. The shift row
98
+ * notifies `selected` ALONE for the mirror-image reason (the item did not change, only its
99
+ * position), and the replace-in-place row notifies `selected-item` alone.
100
+ *
101
+ * `<adw-combo-row>` drives the table through its own DOM, which is where the splice has to
102
+ * land for a user to see it: the outcome columns, the rebuilt `<option>` list, and the
103
+ * SILENCE a DOM surface owes (a model moving underneath is not a user pick, so no
104
+ * `notify::selected` event). The `notified` column itself stays with the core suite — it is
105
+ * a GObject property feed, and no port publishes one for this path yet; `subscribeNotify`
106
+ * is the seam a host that owns real properties will re-emit from.
107
+ */
108
+ export declare const COMBO_ITEMS_CHANGED_VECTORS: ReadonlyArray<ComboItemsChangedVector>;
49
109
  /** One `presentsChooser` expectation. */
50
110
  export interface ComboChooserVector {
51
111
  count: number;
@@ -1,16 +1,50 @@
1
- import type { Binding, BindingFlag, ClassLike, GObjectInstance, ParamSpec, RegisteredClass, SignalHandler } from './gobject.js';
1
+ import type { Binding, BindingFlag, ClassLike, GInterface, GObjectInstance, GType, ParamSpec, RegisteredClass, SignalHandler } from './gobject.js';
2
+ /**
3
+ * The kinds that carry a VALUE a declaration can also spell as a default — the five the subset
4
+ * has had since ADR 0105, and the only ones a signal parameter may take.
5
+ */
6
+ export type ForeignScalarKind = 'string' | 'boolean' | 'int' | 'uint' | 'double';
2
7
  /** The property kinds the subset has, and the only ones a declared widget property may take. */
3
- export type ForeignPropertyKind = 'string' | 'boolean' | 'int' | 'uint' | 'double';
8
+ export type ForeignPropertyKind = ForeignScalarKind | 'object';
4
9
  /** One property a widget class declares at its `extends`. `default` is the unset value. */
5
- export interface ForeignProperty {
6
- readonly kind: ForeignPropertyKind;
10
+ export interface ForeignScalarProperty {
11
+ readonly kind: ForeignScalarKind;
7
12
  readonly default?: string | boolean | number | null;
8
13
  readonly nick?: string;
9
14
  readonly blurb?: string;
10
15
  }
11
- /** One signal a widget class declares at its `extends`, in the subset's parameter vocabulary. */
16
+ /**
17
+ * A property holding another GObject, or `null` — `Adw.ComboRow:model` (ADR 0122 § 6).
18
+ *
19
+ * `valueType` IS REQUIRED, and that is the whole reason this is a separate arm rather than an
20
+ * optional field on the one above. `g_param_spec_object` takes the object type as an argument and
21
+ * has no default for it, so a declaration that omitted it would leave the engine to guess between
22
+ * "any GObject" and the interface the widget actually means — and a `model` that accepted any
23
+ * GObject is the refusal ADR 0122 § 6 exists to make. It is the subset's own token (`TYPE_OBJECT`
24
+ * or an interface of the subset), NOT node-gi's: a port that named a real GType would have to
25
+ * import node-gi to describe its own properties, which is the dependency this vocabulary exists
26
+ * to keep out. The engine that has node-gi translates.
27
+ *
28
+ * There is no `default`. `g_param_spec_object`'s default is always `NULL`, so a declaration
29
+ * cannot carry another one.
30
+ */
31
+ export interface ForeignObjectProperty {
32
+ readonly kind: 'object';
33
+ readonly valueType: GType | GInterface;
34
+ readonly nick?: string;
35
+ readonly blurb?: string;
36
+ }
37
+ /** One property a widget class declares at its `extends`. */
38
+ export type ForeignProperty = ForeignScalarProperty | ForeignObjectProperty;
39
+ /**
40
+ * One signal a widget class declares at its `extends`, in the subset's parameter vocabulary.
41
+ *
42
+ * SCALARS ONLY. An object parameter would need its own type beside the kind, as the property arm
43
+ * does, and nothing declares one — `items-changed` is three `uint`s. Widening it to
44
+ * `ForeignPropertyKind` would make `{ kind: 'object' }` spellable with no type and no meaning.
45
+ */
12
46
  export interface ForeignSignal {
13
- readonly param_types?: readonly ForeignPropertyKind[];
47
+ readonly param_types?: readonly ForeignScalarKind[];
14
48
  }
15
49
  /**
16
50
  * What a widget class declares at its `extends` — GJS's `registerClass` meta, in the port's own
@@ -20,6 +54,16 @@ export interface ForeignClassMeta {
20
54
  readonly GTypeName: string;
21
55
  readonly Properties?: Readonly<Record<string, ForeignProperty>>;
22
56
  readonly Signals?: Readonly<Record<string, ForeignSignal>>;
57
+ /**
58
+ * REFUSED, by name, and declared here so the refusal is findable from the call site.
59
+ *
60
+ * `Implements` is the one meta key route D cannot carry (ADR 0122 § 4): a foreign-parent class
61
+ * is registered over a `@nativescript/core` base that is not a GObject, so there is no GType
62
+ * to add an interface to. A widget that needs `Gio.ListModel` holds one instead of being one —
63
+ * which is what `Adw.ComboRow:model` does. Ignoring the key would leave a class that says it
64
+ * implements the interface and does not, which is the silent outcome ADR 0105 refuses.
65
+ */
66
+ readonly Implements?: readonly unknown[];
23
67
  }
24
68
  export interface GObjectEngine {
25
69
  /** Names the engine in a diagnostic; `'pure-js'` for the default one. */
@@ -1,5 +1,5 @@
1
1
  import type { SharedTreeNode } from './conformance/shared-trees.js';
2
- import type { GObjectEngine } from './engine.js';
2
+ import type { ForeignClassMeta, GObjectEngine } from './engine.js';
3
3
  /** What `registerClass` accepts as `Template`: the projected tree of a `?template` import (ADR 0096 § 4). */
4
4
  export type BlueprintTemplate = SharedTreeNode;
5
5
  /** The subset asked for something it does not list. `feature` is the name that was refused. */
@@ -16,6 +16,44 @@ export declare const TYPE_BOOLEAN: GType;
16
16
  export declare const TYPE_INT: GType;
17
17
  export declare const TYPE_UINT: GType;
18
18
  export declare const TYPE_DOUBLE: GType;
19
+ /**
20
+ * `G_TYPE_OBJECT` — the value type of an object-kind property that takes ANY GObject
21
+ * ({@link ParamSpec.object}). A property that takes one interface names the interface instead.
22
+ */
23
+ export declare const TYPE_OBJECT: GType;
24
+ /** What an interface token carries; the token itself is {@link GInterface}. */
25
+ export interface GInterfaceInfo {
26
+ /** The GIR spelling, as it reads in a refusal and in `items_changed`'s arity message. */
27
+ readonly name: string;
28
+ readonly gtype: GType;
29
+ /** The `vfunc_*` an implementor MUST define. */
30
+ readonly vfuncs: readonly string[];
31
+ /** Instance method → the `vfunc_*` it calls through. */
32
+ readonly methods: Readonly<Record<string, string>>;
33
+ /** Instance method → the signal it emits, with that signal's arity enforced. */
34
+ readonly emitters: Readonly<Record<string, string>>;
35
+ /** The signals the interface brings into the implementor's own signal table. */
36
+ readonly signals: Readonly<Record<string, readonly GType[]>>;
37
+ }
38
+ /**
39
+ * One interface of the subset — the value a class puts in `Implements`, and the right-hand side
40
+ * of `instanceof`.
41
+ *
42
+ * It is callable-shaped so `x instanceof ListModel` type-checks like any other `instanceof`;
43
+ * calling or constructing it throws, because an interface is not a class.
44
+ */
45
+ export type GInterface = GInterfaceInfo & (abstract new (...args: never[]) => object);
46
+ /**
47
+ * `Gio.ListModel` — the portable list model's interface, and the whole of the subset's interface
48
+ * support (ADR 0122 § 2).
49
+ *
50
+ * `items-changed` is an ordinary declared signal of every implementor, so an engine that knows
51
+ * nothing about interfaces registers and emits it like any other; `items_changed()` is the
52
+ * emitter GIR gives it, down to the arity message real GJS produces for a short call.
53
+ */
54
+ export declare const ListModel: GInterface;
55
+ /** Whether `instance`'s class chain declares `iface` — what `instanceof ListModel` answers. */
56
+ export declare function implementsInterface(instance: object, iface: GInterface): boolean;
19
57
  /**
20
58
  * `GObject.Value`, string-only (ADR 0096 Amendment 2). `init` takes `TYPE_STRING`; any other type
21
59
  * is refused by name. Real GObject logs a CRITICAL for `get_*`/`set_*` on an uninitialised value and
@@ -38,7 +76,7 @@ export declare const ParamFlags: {
38
76
  readonly CONSTRUCT: 4;
39
77
  readonly CONSTRUCT_ONLY: 8;
40
78
  };
41
- export type ParamKind = 'boolean' | 'string' | 'int' | 'uint' | 'double';
79
+ export type ParamKind = 'boolean' | 'string' | 'int' | 'uint' | 'double' | 'object';
42
80
  export declare class ParamSpec {
43
81
  readonly kind: ParamKind;
44
82
  readonly name: string;
@@ -47,6 +85,8 @@ export declare class ParamSpec {
47
85
  readonly flags: number;
48
86
  readonly minimum?: number;
49
87
  readonly maximum?: number;
88
+ /** An object-kind property's value type: {@link TYPE_OBJECT} or the one interface it takes. */
89
+ readonly valueType?: GType | GInterface;
50
90
  private readonly defaultValue;
51
91
  private constructor();
52
92
  static boolean(name: string, nick: string, blurb: string, flags: number, defaultValue: boolean): ParamSpec;
@@ -54,8 +94,30 @@ export declare class ParamSpec {
54
94
  static int(name: string, nick: string, blurb: string, flags: number, minimum: number, maximum: number, defaultValue: number): ParamSpec;
55
95
  static uint(name: string, nick: string, blurb: string, flags: number, minimum: number, maximum: number, defaultValue: number): ParamSpec;
56
96
  static double(name: string, nick: string, blurb: string, flags: number, minimum: number, maximum: number, defaultValue: number): ParamSpec;
97
+ /**
98
+ * `GObject.ParamSpec.object` — a property that holds another GObject, or `null`.
99
+ *
100
+ * `valueType` is {@link TYPE_OBJECT} for "any GObject" or an interface token for a property
101
+ * that takes only implementors of it (`Adw.ComboRow:model`, which takes a `Gio.ListModel`).
102
+ * The default is ALWAYS `null`: `g_param_spec_object` has no other, and a write that does
103
+ * not satisfy `valueType` throws rather than being stored (ADR 0122 § 6).
104
+ */
105
+ static object(name: string, nick: string, blurb: string, flags: number, valueType: GType | GInterface): ParamSpec;
57
106
  get_default_value(): unknown;
58
107
  }
108
+ /**
109
+ * The type check `g_object_set_property` does before a value reaches the store — the ONE place a
110
+ * declared property refuses a value, so every object-kind property refuses the same way.
111
+ *
112
+ * Only object-kind specs have anything to check: the other five kinds take what GJS's generated
113
+ * accessors take, which is anything (`_generateAccessors` stores without converting, and the
114
+ * subset's vectors hold it to that). The messages are the ones real GJS produces for a C object
115
+ * property, measured on `Gtk.DropDown:model` under GJS 1.88.01 / GTK 4.22.5 — a JS-registered
116
+ * class is NOT an oracle for them, because GJS's auto-accessors skip the GValue conversion that
117
+ * raises them. The pointer GJS prints in the "not a subclass" message is left out; nothing can
118
+ * match it.
119
+ */
120
+ export declare function checkPropertyValue(spec: ParamSpec, value: unknown): void;
59
121
  /** GJS's own symbols, so a class written in the field form (`static [GObject.properties] = …`) registers. */
60
122
  export declare const META_SYMBOLS: {
61
123
  readonly GTypeName: symbol;
@@ -111,8 +173,10 @@ export interface RegisteredClass {
111
173
  readonly typeName: string;
112
174
  readonly gtype: GType;
113
175
  readonly properties: readonly ParamSpec[];
114
- /** Signal name → its parameter types. */
176
+ /** Signal name → its parameter types; an implemented interface's are merged in. */
115
177
  readonly signals: Readonly<Record<string, readonly GType[]>>;
178
+ /** The interfaces of `Implements`, each one of {@link ACCEPTED_INTERFACES}. */
179
+ readonly interfaces: readonly GInterface[];
116
180
  readonly template?: BlueprintTemplate;
117
181
  readonly internalChildren: readonly string[];
118
182
  readonly cssName?: string;
@@ -130,6 +194,12 @@ export interface GObjectInstance {
130
194
  disconnect(id: number): void;
131
195
  emit(signal: string, ...args: unknown[]): void;
132
196
  }
197
+ /**
198
+ * `Implements` on a foreign-parent class: refused by name, on EVERY engine (ADR 0122 § 4). It is
199
+ * the core's refusal rather than each engine's so that route D says the same thing on the engine
200
+ * that could never do it and on the one that merely does not.
201
+ */
202
+ export declare function refuseForeignInterfaces(meta: ForeignClassMeta): void;
133
203
  /**
134
204
  * The default {@link GObjectEngine}: per-instance `Map`s behind a `WeakMap`, the only one the
135
205
  * browser can have. Registration needs nothing of it — a `$gtype` here is a token, not a GType.
@@ -213,7 +283,7 @@ export declare const UNLOCKED_VFUNCS: Readonly<Record<string, readonly string[]>
213
283
  * resolve through the registry like a registered class's own. The door is one that names the
214
284
  * missing widget model: such a class has no event system to fall through to.
215
285
  */
216
- export declare function registerBaseClass(klass: ClassLike, typeName: string, signals: Readonly<Record<string, readonly GType[]>>, properties?: readonly ParamSpec[], engine?: GObjectEngine): void;
286
+ export declare function registerBaseClass(klass: ClassLike, typeName: string, signals: Readonly<Record<string, readonly GType[]>>, properties?: readonly ParamSpec[], interfaces?: readonly GInterface[], engine?: GObjectEngine): void;
217
287
  export type GObjectConstructor = new (params?: Record<string, unknown>) => GObjectInstance;
218
288
  /** `GObject.Object` for a registered class with no widget model beneath it. */
219
289
  export declare class GObjectObject {
@@ -241,6 +311,7 @@ export interface GObjectNamespace {
241
311
  readonly TYPE_INT: GType;
242
312
  readonly TYPE_UINT: GType;
243
313
  readonly TYPE_DOUBLE: GType;
314
+ readonly TYPE_OBJECT: GType;
244
315
  readonly GTypeName: symbol;
245
316
  readonly GTypeFlags: symbol;
246
317
  readonly interfaces: symbol;
@@ -42,6 +42,8 @@ export declare const GDK_KEYS: Readonly<{
42
42
  readonly KEY_Up: 65362;
43
43
  readonly KEY_Right: 65363;
44
44
  readonly KEY_Down: 65364;
45
+ /** XF86Back: the hardware / mouse back key, and what Android's back button is delivered as. */
46
+ readonly KEY_Back: 269025062;
45
47
  }>;
46
48
  /** A DOM `key` as the keysym GTK would deliver: a Latin-1 character is its own code point, lowercased. */
47
49
  export declare function keyvalOfKey(key: string): number;
@@ -109,6 +111,13 @@ export interface GtkPlatform {
109
111
  }
110
112
  /** A port is always on a display, so `Settings.get_default()` is never null (real GTK: null before `Gtk.init`). */
111
113
  export declare function createGtkPlatform(host: PlatformHost): GtkPlatform;
114
+ /**
115
+ * Runs `event` through the key controllers attached to `widget`, as GTK does for a key the widget's
116
+ * toplevel receives: the first controller whose `key-pressed` / `key-released` handler returns true
117
+ * takes it. For keys the platform delivers by another road than the widget's own key listener (the
118
+ * Android back button); the result is whether a controller handled it.
119
+ */
120
+ export declare function deliverKeyToControllers(widget: object, event: HostKeyEvent): boolean;
112
121
  /** `Gtk.Widget.add_controller` / `remove_controller` for the widgets of a port. */
113
122
  export declare function widgetControllerMembers(host: PlatformHost): {
114
123
  add_controller(this: object, controller: EventControllerKey): void;