@gjsify/adwaita-nativescript 0.64.12 → 0.64.13-next.283

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.
@@ -1 +1 @@
1
- import"../_virtual/_rolldown/runtime.js";import{capabilities as e}from"../capabilities.js";import{observeWindowSize as t}from"../widgets/breakpoint.js";import{gtypeNameOf as n,gtypeNameOfInstance as r}from"../widgets/gtype-name.js";import{declaredBuilderReferences as i,declaredBuilderSlots as a}from"../widgets/builder-slots.js";import{gtkPropertyRefusal as o,hasGtkProperty as s,readGtkProperty as c,writeGtkProperty as l}from"../widgets/shadowed-properties.js";import{emittedSignalsOf as u}from"../widgets/signals.js";import{authoredParamValue as d}from"./param-values.js";import{registerTemplateClass as f,templateClassFor as p}from"./template-classes.js";import{adw_exports as m}from"../namespace/adw.js";import{gtk_exports as h}from"../namespace/gtk.js";import{createBreakpointDriver as g,menuAssignments as _,parseBreakpointCondition as v}from"@gjsify/adwaita-core";import{assertTreeConstructs as y}from"@gjsify/adwaita-core/conformance";import{propertyOf as b}from"@gjsify/adwaita-core/tags";import{View as x}from"@nativescript/core";const S=[{prefix:`adw`,library:`Adw`,namespace:m},{prefix:`gtk`,library:`Gtk`,namespace:h}];function registerBarrel(e,t,n){let r=S.find(t=>t.prefix===e);if(r!==void 0&&r.library!==t)throw Error(`The prefix '${e}' already names \`${r.library}\`; it cannot also name \`${t}\`.`);r===void 0?S.push({prefix:e,library:t,namespace:n}):r.namespace=n}const C={GtkPopoverMenuBar:`Android has no menu-bar surface, and a row of PopupMenus would be a design choice, not GTK's widget (ADR 0097 § 2). Use a GtkMenuButton or a GtkPopoverMenu.`};function elementFor(e){let t=C[e];if(t!==void 0)throw Error(`\`${e}\` is refused on this port: ${t}`);let r=[...S].sort((e,t)=>t.library.length-e.library.length);for(let{prefix:t,library:i,namespace:a}of r){if(!e.startsWith(i))continue;let r=e.slice(i.length),o=a[r];if(typeof o!=`function`)throw Error(`Module '~/${t}' has no member for element '${t}:${r}' — the name \`${e}\` is authored in the shared corpus and this dialect cannot spell it. Give the widget a namespace member (ADR 0034 clause 2), or ledger the block as divergent.`);if(n(o)!==e)throw Error(`'${t}:${r}' resolves to class \`${n(o)}\`, not \`${e}\`. The corpus is authored in GIR class names and ADR 0034 clause 1 says a widget carries that name, so a barrel member bound to another class would build the wrong widget at exit 0.`);return{xmlName:`${t}:${r}`,ctor:o}}throw Error(`\`${e}\` starts with no library this dialect has a barrel for (${S.map(e=>e.prefix).join(`, `)}).`)}function elementOf(e){return e.extern===!0?{xmlName:`app:${e.tag}`,ctor:p(e.tag)}:elementFor(e.tag)}function translated(e,t,n){return n===void 0||e===void 0||typeof t!=`string`?t:e(t,n.context)}function build(e,t={}){refuseSiblings(e,`build`);let n=buildTree(e,t).root;if(!(n instanceof x))throw Error(`\`${e.tag}\` is not a widget, so a tree cannot root at it: there is nothing to show.`);return n}function buildDialog(e,t={}){refuseSiblings(e,`buildDialog`);let n=buildTree(e,t).root;if(n instanceof x||typeof n.present!=`function`)throw Error(`\`${e.tag}\` is not a dialog: it has no \`present()\`, so use \`build\` for it.`);return n}function buildWithSiblings(e,t={}){let n=buildTree(e,t,!0);if(!(n.root instanceof x))throw Error(`\`${e.tag}\` is not a widget, so a tree cannot root at it: there is nothing to show.`);return{root:n.root,siblings:n.siblings,objects:n.objects}}function buildInto(e,t,n={}){let r=elementOf(t);if(!(e instanceof r.ctor))throw Error(`\`buildInto\` was handed a ${e.constructor.name}, and the tree's root is \`${t.tag}\`: a template builds into an instance of the class it extends (<${r.xmlName}>).`);return buildTree(t,n,!0,e).objects}function refuseSiblings(e,t){if((e.siblings?.length??0)!==0)throw Error(`\`${e.tag}\` carries ${e.siblings.length} sibling object(s), and \`${t}\` returns one object so they would be built and lost. Use \`buildWithSiblings\`, which hands them back by id.`)}function buildTree(n,r,i=!1,a){y(`adwaita-nativescript`,e,n,Object.keys(T));let o={ids:new Map,pending:[],binds:[],breakpointHosts:[],observeSize:r.observeSize??t,menus:n.menus,scope:r.scope,template:r.template,translate:r.translate,values:i?new Map:void 0},s=buildNode(n,o,a),c=new Map;for(let e of n.siblings??[]){if(e.id===void 0)throw Error(`the sibling \`${e.tag}\` has no id, so nothing could ever ask for it: give it one in the .blp.`);c.set(e.id,buildNode(e,o))}for(let{view:e,element:t,prop:n,id:r}of o.pending){let i=o.ids.get(r);if(i===void 0)throw Error(`<${t.xmlName} ${n}="${r}"> names no object: nothing in this tree has the id '${r}', so \`${n}\` would be handed the string instead of the widget it refers to.`);l(e,n,i)}for(let e of o.binds)bindProperty(e,o);for(let e of o.breakpointHosts)bindBreakpoints(e,o);return{root:s,siblings:c,objects:new Map([...o.ids,...o.values??[]])}}function bindProperty(e,t){let{target:n,element:r,property:i,source:a,sourceProperty:d,flags:f}=e,p=`<${r.xmlName}> \`${i}: bind ${a}.${d}\``,m=t.template,h=a===`template`&&m!==void 0?m.instance:t.ids.get(a);if(h===void 0)throw Error(`${p} names no object: nothing in this tree has the id '${a}'.`);if(f.length>0&&m===void 0)throw Error(`${p} carries ${f.join(`, `)}: adwaita-nativescript binds the plain form only until each flag is verified against GObject.`);let g=b(d),_=b(i),v=u(h.constructor),y=`notify::${d}`;if(!s(h,g)||!v.includes(y))throw Error(`${p}: ${h.constructor.name} does not emit '${y}', so the target would follow the source once and never again. It emits: ${v.join(`, `)||`none`}.`);if(!s(n,_)){let e=o(n,_);throw Error(`${p}: the target has no property '${_}'.${e===null?``:` ${e}`}`)}if(m!==void 0){bindThroughEngine(m,{...e,from:h,where:p,notification:y});return}let follow=()=>l(n,_,c(h,g));follow(),h.connect(y,follow)}function engineFlags(e,t){for(let n of e)if(n!==`bidirectional`&&n!==`inverted`&&n!==`no-sync-create`)throw Error(`${t} carries the unknown flag '${n}'.`);let n=e.includes(`no-sync-create`)?[]:[`sync-create`];return e.includes(`bidirectional`)&&n.push(`bidirectional`),e.includes(`inverted`)&&n.push(`invert-boolean`),n}function viaProperties(e){let key=e=>typeof e==`string`?b(e):e;return new Proxy(e,{get(e,t){let n=typeof t==`string`&&s(e,key(t))?c(e,key(t)):Reflect.get(e,key(t));return typeof n==`function`?n.bind(e):n},set(e,t,n){return typeof t==`string`?(l(e,b(t),n),!0):Reflect.set(e,t,n)}})}function bindThroughEngine(e,t){let{target:n,from:r,property:i,sourceProperty:a,flags:o,where:s}=t,c=engineFlags(o,s),l=u(n.constructor);if(c.includes(`bidirectional`)&&!l.includes(`notify::${i}`))throw Error(`${s}: bidirectional, but ${n.constructor.name} does not emit 'notify::${i}', so the source would never follow the target back. It emits: ${l.join(`, `)||`none`}.`);e.bind(viaProperties(r),a,viaProperties(n),i,c)}function bindBreakpoints({view:e,element:t,node:n},r){if(!(e instanceof x))throw Error(`<${t.xmlName}> is not a view, so it has no size for a breakpoint to read.`);wireBreakpoints(t.xmlName,e,n.breakpoints??[],r.ids,r.observeSize,r.translate)}function applyBreakpoints(e,n,i,a={}){wireBreakpoints(r(e),e,n,new Map(Object.entries(i)),a.observeSize??t,a.translate)}function wireBreakpoints(e,t,n,r,i,a){let u=g(n.map(t=>{if(v(t.condition)===null)throw Error(`<${e}> \`condition ("${t.condition}")\` is not an Adwaita breakpoint condition.`);return{condition:t.condition,setters:t.setters.map(t=>{let n=r.get(t.object),i=`<${e}> breakpoint setter \`${t.object}.${t.property}\``;if(n===void 0)throw Error(`${i} names no object: nothing in this tree has the id '${t.object}'.`);if(!s(n,b(t.property))){let e=o(n,b(t.property));throw Error(`${i}: the target declares no '${b(t.property)}'.`+(e===null?``:` ${e}`))}let c=translated(a,t.value,t.translatable),l=d(n,b(t.property),c,i);return{object:n,property:t.property,value:{authored:l===null?String(c):l.value}}})}}),{read:(e,t)=>({original:c(e,b(t))}),write(e,t,n){let r=n;l(e,b(t),`authored`in r?r.authored:r.original)}});i(t,e=>u.evaluate(e))}function buildNode(e,t,n){let r=elementOf(e),i=n??new r.ctor,a=i instanceof x?buildView(e,r,i,t):buildValue(e,r,i,t);bindSignals(a,r,e,t);for(let[n,i]of Object.entries(e.bindings??{}))t.binds.push({target:a,element:r,property:n,source:i.source,sourceProperty:i.property,flags:i.flags??[]});e.breakpoints!==void 0&&t.breakpointHosts.push({view:a,element:r,node:e});for(let n of e.children??[]){let i=a;if(typeof i._addChildFromBuilder!=`function`)throw Error(`<${r.xmlName}> takes no XML child: \`${e.tag}\` has no \`_addChildFromBuilder\`, so the corpus nests a node this element cannot hold.`);let o=buildNode(n,t);applyLayout(n,o,r,e.tag),i._addChildFromBuilder(builderNameFor(r,e.tag,n),o)}return a}function bindSignals(e,t,n,r){if(n.signals===void 0)return;let i=u(t.ctor),a=e;for(let e of n.signals){let n=e.detail===void 0?e.name:`${e.name}::${e.detail}`;if(typeof a.connect!=`function`||!i.includes(n))throw Error(`<${t.xmlName}> declares no signal '${n}', so the handler '${e.handler}' would never run. It emits: ${i.join(`, `)||`none`}.`);let o=(e.flags??[]).filter(e=>r.template===void 0||e!==`swapped`);if(e.object!==void 0||o.length>0)throw Error(`the handler '${e.handler}' for '${n}' uses ${e.object===void 0?``:`an object `}${(e.flags??[]).join(`, `)}: adwaita-nativescript binds plain handlers only until each of those is verified against GTK.`);if(r.template!==void 0){a.connect(n,r.template.handler(e.handler,{flags:e.flags}));continue}let s=r.scope?.[e.handler];if(typeof s!=`function`)throw Error(`the tree binds the handler '${e.handler}' for '${n}', and the scope ${r.scope===void 0?"was not given (pass `scope`)":`has no such function`}.`);a.connect(n,(...e)=>s.apply(r.scope,e))}}const w={row:`row`,column:`column`,"row-span":`rowSpan`,"column-span":`columnSpan`};function applyLayout(e,t,n,r){if(e.layout!==void 0){if(typeof n.ctor.prototype.attach!=`function`)throw Error(`<${elementOf(e).xmlName}> authored layout (${Object.keys(e.layout).join(`, `)}) under \`${r}\`, which has no \`attach\`: this port's only layout manager is the grid, so the placement would be dropped.`);if(!(t instanceof x))throw Error(`\`${e.tag}\` is not a view, so it has no cell to place.`);for(let[n,r]of Object.entries(e.layout)){let i=w[n];if(i===void 0)throw Error(`layout \`${n}\` on \`${e.tag}\` reaches nothing: a grid child takes ${Object.keys(w).join(`, `)}.`);if(typeof r!=`number`||!Number.isInteger(r))throw Error(`layout \`${n}: ${String(r)}\` on \`${e.tag}\` is not a whole number.`);t[i]=r}}}function unknownProperty(e,t,n,r,i,a){let s=o(a,r);return Error(s===null?`<${e.xmlName} ${n}="${String(i)}"> reaches nothing: \`${t}\` declares no '${r}'. NativeScript's builder assigns it anyway, as a dead own-property at exit 0, so the attribute door cannot report this and the tree would render without it.`:`<${e.xmlName} ${n}="${String(i)}"> reaches nothing on \`${t}\`: ${s}`)}function buildView(e,t,n,r){if(e.page!==void 0)throw Error(`<${t.xmlName}> is a page (${JSON.stringify(e.page)}), and adwaita-nativescript builds no pages: there is no NS widget yet for Gtk.Notebook, and Gtk.StackPage is not on this branch.`);if(e.id!==void 0){if(r.ids.has(e.id)||r.values?.has(e.id))throw Error(`Two nodes of this tree carry the id '${e.id}'; GtkBuilder refuses a duplicate id.`);r.ids.set(e.id,n),n.id=e.id}let a=i(t.ctor);for(let[i,a]of _(e,r.menus)){let r=b(i);if(!s(n,r))throw unknownProperty(t,e.tag,i,r,i,n);l(n,r,a)}for(let[i,o]of Object.entries(e.props??{})){if(i===`menu-model`)continue;let c=b(i);if(!s(n,c))throw unknownProperty(t,e.tag,i,c,o,n);if(a.includes(c)){r.pending.push({view:n,element:t,prop:c,id:String(o)});continue}let u=translated(r.translate,o,e.translatable?.[i]),f=d(n,c,u,`<${t.xmlName} ${i}="${String(u)}">`);l(n,c,f===null?String(u):f.value)}if(e.styleClasses!==void 0&&e.styleClasses.length>0){if(!(`styleClasses`in n))throw Error(`<${t.xmlName}> takes no style classes: \`${e.tag}\` declares no 'styleClasses', so [${e.styleClasses.join(`, `)}] would be dropped.`);n.styleClasses=e.styleClasses.join(` `)}if(applyAccessibility(n,e,r),e.extensions?.strings!==void 0)throw Error(`<${t.xmlName}> takes no string-list items: \`${e.tag}\` is a widget, and only a list model holds them, so [${e.extensions.strings.map(e=>e.value).join(`, `)}] would be dropped.`);return applyResponses(n,t,e,r),n}const T={label:`accessibilityLabel`,description:`accessibilityHint`};function applyAccessibility(e,t,n){for(let[r,i]of Object.entries(t.accessibility??{}))e[T[r]]=String(translated(n.translate,i.value,i.translatable))}function buildValue(e,t,n,r){if(e.id!==void 0&&r.values===void 0)throw Error(`<${t.xmlName} id="${e.id}"> reaches nothing: \`${e.tag}\` is not a view, and \`getViewById\` walks views, so code beside the \`.blp\` could never look it up. \`buildWithSiblings\` hands every object back by id.`);if(e.styleClasses!==void 0&&e.styleClasses.length>0)throw Error(`<${t.xmlName}> takes no style classes: \`${e.tag}\` is not a widget, so [${e.styleClasses.join(`, `)}] would be dropped.`);if(e.accessibility!==void 0)throw Error(`<${t.xmlName}> takes no accessibility: \`${e.tag}\` is not a widget, so ${Object.keys(e.accessibility).join(`, `)} would be dropped.`);let i={};for(let[a,o]of _(e,r.menus)){let r=b(a);if(!s(n,r))throw unknownProperty(t,e.tag,a,r,a,n);i[r]=o}for(let[a,o]of Object.entries(e.props??{})){if(a===`menu-model`)continue;let c=b(a);if(!s(n,c))throw unknownProperty(t,e.tag,a,c,o,n);i[c]=translated(r.translate,o,e.translatable?.[a])}let a=e.extensions?.strings;if(a!==void 0){if(typeof n.append!=`function`)throw Error(`<${t.xmlName}> takes no string-list items: \`${e.tag}\` has no \`append\`, so [${a.map(e=>e.value).join(`, `)}] would be dropped.`);i.strings=a.map(e=>String(translated(r.translate,e.value,e.translatable)))}let o=new t.ctor(i);if(applyResponses(o,t,e,r),e.id!==void 0&&r.values!==void 0){if(r.values.has(e.id)||r.ids.has(e.id))throw Error(`Two nodes of this tree carry the id '${e.id}'; GtkBuilder refuses a duplicate id.`);r.values.set(e.id,o)}return o}function applyResponses(e,t,n,r){let i=e,a=n.extensions?.responses;if(a!==void 0){if(typeof i.add_response!=`function`)throw Error(`<${t.xmlName}> takes no responses: \`${n.tag}\` has no \`add_response\`, so [${a.map(e=>e.id).join(`, `)}] would be dropped.`);for(let{id:e,label:t,appearance:n,enabled:o,translatable:s}of a)i.add_response(e,String(translated(r.translate,t,s)),{...n===void 0?{}:{appearance:n},...o===void 0?{}:{enabled:o}})}}function builderNameFor(e,t,n){let r=elementOf(n);if(n.slot===void 0)return r.xmlName;let i=n.slot,o=a(e.ctor);if(o===null||!o.includes(i))throw Error(`<${e.xmlName}.${i}> reaches nothing: \`${t}\` declares no such builder slot, so NativeScript would hand <${r.xmlName}> to its fallback placement instead — at exit 0, in a cell the tree never asked for. Known slots: ${o===null||o.length===0?`none`:o.join(`, `)}.`);return i}export{applyBreakpoints,build,buildDialog,buildInto,buildWithSiblings,elementFor,registerBarrel,f as registerTemplateClass};
1
+ import"../_virtual/_rolldown/runtime.js";import{capabilities as e}from"../capabilities.js";import{observeWindowSize as t}from"../widgets/breakpoint.js";import{gtypeNameOf as n,gtypeNameOfInstance as r}from"../widgets/gtype-name.js";import{declaredBuilderReferences as i,declaredBuilderSlots as a}from"../widgets/builder-slots.js";import{gtkPropertyRefusal as o,hasGtkProperty as s,readGtkProperty as c,writeGtkProperty as l}from"../widgets/shadowed-properties.js";import{emittedSignalsOf as u}from"../widgets/signals.js";import{authoredParamValue as d}from"./param-values.js";import{registerTemplateClass as f,templateClassFor as p}from"./template-classes.js";import{adw_exports as m}from"../namespace/adw.js";import{gtk_exports as h}from"../namespace/gtk.js";import{createBreakpointDriver as g,menuAssignments as _,parseBreakpointCondition as v,registeredDefaultTranslate as y}from"@gjsify/adwaita-core";import{assertTreeConstructs as b}from"@gjsify/adwaita-core/conformance";import{propertyOf as x}from"@gjsify/adwaita-core/tags";import{View as S}from"@nativescript/core";const C=[{prefix:`adw`,library:`Adw`,namespace:m},{prefix:`gtk`,library:`Gtk`,namespace:h}];function registerBarrel(e,t,n){let r=C.find(t=>t.prefix===e);if(r!==void 0&&r.library!==t)throw Error(`The prefix '${e}' already names \`${r.library}\`; it cannot also name \`${t}\`.`);r===void 0?C.push({prefix:e,library:t,namespace:n}):r.namespace=n}const w={GtkPopoverMenuBar:`Android has no menu-bar surface, and a row of PopupMenus would be a design choice, not GTK's widget (ADR 0097 § 2). Use a GtkMenuButton or a GtkPopoverMenu.`};function elementFor(e){let t=w[e];if(t!==void 0)throw Error(`\`${e}\` is refused on this port: ${t}`);let r=[...C].sort((e,t)=>t.library.length-e.library.length);for(let{prefix:t,library:i,namespace:a}of r){if(!e.startsWith(i))continue;let r=e.slice(i.length),o=a[r];if(typeof o!=`function`)throw Error(`Module '~/${t}' has no member for element '${t}:${r}' — the name \`${e}\` is authored in the shared corpus and this dialect cannot spell it. Give the widget a namespace member (ADR 0034 clause 2), or ledger the block as divergent.`);if(n(o)!==e)throw Error(`'${t}:${r}' resolves to class \`${n(o)}\`, not \`${e}\`. The corpus is authored in GIR class names and ADR 0034 clause 1 says a widget carries that name, so a barrel member bound to another class would build the wrong widget at exit 0.`);return{xmlName:`${t}:${r}`,ctor:o}}throw Error(`\`${e}\` starts with no library this dialect has a barrel for (${C.map(e=>e.prefix).join(`, `)}).`)}function elementOf(e){return e.extern===!0?{xmlName:`app:${e.tag}`,ctor:p(e.tag)}:elementFor(e.tag)}function translated(e,t,n){return n===void 0||e===void 0||typeof t!=`string`?t:e(t,n.context)}function build(e,t={}){refuseSiblings(e,`build`);let n=buildTree(e,t).root;if(!(n instanceof S))throw Error(`\`${e.tag}\` is not a widget, so a tree cannot root at it: there is nothing to show.`);return n}function buildDialog(e,t={}){refuseSiblings(e,`buildDialog`);let n=buildTree(e,t).root;if(n instanceof S||typeof n.present!=`function`)throw Error(`\`${e.tag}\` is not a dialog: it has no \`present()\`, so use \`build\` for it.`);return n}function buildWithSiblings(e,t={}){let n=buildTree(e,t,!0);if(!(n.root instanceof S))throw Error(`\`${e.tag}\` is not a widget, so a tree cannot root at it: there is nothing to show.`);return{root:n.root,siblings:n.siblings,objects:n.objects}}function buildInto(e,t,n={}){let r=elementOf(t);if(!(e instanceof r.ctor))throw Error(`\`buildInto\` was handed a ${e.constructor.name}, and the tree's root is \`${t.tag}\`: a template builds into an instance of the class it extends (<${r.xmlName}>).`);return buildTree(t,n,!0,e).objects}function refuseSiblings(e,t){if((e.siblings?.length??0)!==0)throw Error(`\`${e.tag}\` carries ${e.siblings.length} sibling object(s), and \`${t}\` returns one object so they would be built and lost. Use \`buildWithSiblings\`, which hands them back by id.`)}function buildTree(n,r,i=!1,a){b(`adwaita-nativescript`,e,n,Object.keys(E));let o={ids:new Map,pending:[],binds:[],breakpointHosts:[],observeSize:r.observeSize??t,menus:n.menus,scope:r.scope,template:r.template,translate:r.translate??y(),values:i?new Map:void 0},s=buildNode(n,o,a),c=new Map;for(let e of n.siblings??[]){if(e.id===void 0)throw Error(`the sibling \`${e.tag}\` has no id, so nothing could ever ask for it: give it one in the .blp.`);c.set(e.id,buildNode(e,o))}for(let{view:e,element:t,prop:n,id:r}of o.pending){let i=o.ids.get(r);if(i===void 0)throw Error(`<${t.xmlName} ${n}="${r}"> names no object: nothing in this tree has the id '${r}', so \`${n}\` would be handed the string instead of the widget it refers to.`);l(e,n,i)}for(let e of o.binds)bindProperty(e,o);for(let e of o.breakpointHosts)bindBreakpoints(e,o);return{root:s,siblings:c,objects:new Map([...o.ids,...o.values??[]])}}function bindProperty(e,t){let{target:n,element:r,property:i,source:a,sourceProperty:d,flags:f}=e,p=`<${r.xmlName}> \`${i}: bind ${a}.${d}\``,m=t.template,h=a===`template`&&m!==void 0?m.instance:t.ids.get(a);if(h===void 0)throw Error(`${p} names no object: nothing in this tree has the id '${a}'.`);if(f.length>0&&m===void 0)throw Error(`${p} carries ${f.join(`, `)}: adwaita-nativescript binds the plain form only until each flag is verified against GObject.`);let g=x(d),_=x(i),v=u(h.constructor),y=`notify::${d}`;if(!s(h,g)||!v.includes(y))throw Error(`${p}: ${h.constructor.name} does not emit '${y}', so the target would follow the source once and never again. It emits: ${v.join(`, `)||`none`}.`);if(!s(n,_)){let e=o(n,_);throw Error(`${p}: the target has no property '${_}'.${e===null?``:` ${e}`}`)}if(m!==void 0){bindThroughEngine(m,{...e,from:h,where:p,notification:y});return}let follow=()=>l(n,_,c(h,g));follow(),h.connect(y,follow)}function engineFlags(e,t){for(let n of e)if(n!==`bidirectional`&&n!==`inverted`&&n!==`no-sync-create`)throw Error(`${t} carries the unknown flag '${n}'.`);let n=e.includes(`no-sync-create`)?[]:[`sync-create`];return e.includes(`bidirectional`)&&n.push(`bidirectional`),e.includes(`inverted`)&&n.push(`invert-boolean`),n}function viaProperties(e){let key=e=>typeof e==`string`?x(e):e;return new Proxy(e,{get(e,t){let n=typeof t==`string`&&s(e,key(t))?c(e,key(t)):Reflect.get(e,key(t));return typeof n==`function`?n.bind(e):n},set(e,t,n){return typeof t==`string`?(l(e,x(t),n),!0):Reflect.set(e,t,n)}})}function bindThroughEngine(e,t){let{target:n,from:r,property:i,sourceProperty:a,flags:o,where:s}=t,c=engineFlags(o,s),l=u(n.constructor);if(c.includes(`bidirectional`)&&!l.includes(`notify::${i}`))throw Error(`${s}: bidirectional, but ${n.constructor.name} does not emit 'notify::${i}', so the source would never follow the target back. It emits: ${l.join(`, `)||`none`}.`);e.bind(viaProperties(r),a,viaProperties(n),i,c)}function bindBreakpoints({view:e,element:t,node:n},r){if(!(e instanceof S))throw Error(`<${t.xmlName}> is not a view, so it has no size for a breakpoint to read.`);wireBreakpoints(t.xmlName,e,n.breakpoints??[],r.ids,r.observeSize,r.translate)}function applyBreakpoints(e,n,i,a={}){wireBreakpoints(r(e),e,n,new Map(Object.entries(i)),a.observeSize??t,a.translate??y())}function wireBreakpoints(e,t,n,r,i,a){let u=g(n.map(t=>{if(v(t.condition)===null)throw Error(`<${e}> \`condition ("${t.condition}")\` is not an Adwaita breakpoint condition.`);return{condition:t.condition,setters:t.setters.map(t=>{let n=r.get(t.object),i=`<${e}> breakpoint setter \`${t.object}.${t.property}\``;if(n===void 0)throw Error(`${i} names no object: nothing in this tree has the id '${t.object}'.`);if(!s(n,x(t.property))){let e=o(n,x(t.property));throw Error(`${i}: the target declares no '${x(t.property)}'.`+(e===null?``:` ${e}`))}let c=translated(a,t.value,t.translatable),l=d(n,x(t.property),c,i);return{object:n,property:t.property,value:{authored:l===null?String(c):l.value}}})}}),{read:(e,t)=>({original:c(e,x(t))}),write(e,t,n){let r=n;l(e,x(t),`authored`in r?r.authored:r.original)}});i(t,e=>u.evaluate(e))}function buildNode(e,t,n){let r=elementOf(e),i=n??new r.ctor,a=i instanceof S?buildView(e,r,i,t):buildValue(e,r,i,t);bindSignals(a,r,e,t);for(let[n,i]of Object.entries(e.bindings??{}))t.binds.push({target:a,element:r,property:n,source:i.source,sourceProperty:i.property,flags:i.flags??[]});e.breakpoints!==void 0&&t.breakpointHosts.push({view:a,element:r,node:e});for(let n of e.children??[]){let i=a;if(typeof i._addChildFromBuilder!=`function`)throw Error(`<${r.xmlName}> takes no XML child: \`${e.tag}\` has no \`_addChildFromBuilder\`, so the corpus nests a node this element cannot hold.`);let o=buildNode(n,t);applyLayout(n,o,r,e.tag),i._addChildFromBuilder(builderNameFor(r,e.tag,n),o)}return a}function bindSignals(e,t,n,r){if(n.signals===void 0)return;let i=u(t.ctor),a=e;for(let e of n.signals){let n=e.detail===void 0?e.name:`${e.name}::${e.detail}`;if(typeof a.connect!=`function`||!i.includes(n))throw Error(`<${t.xmlName}> declares no signal '${n}', so the handler '${e.handler}' would never run. It emits: ${i.join(`, `)||`none`}.`);let o=(e.flags??[]).filter(e=>r.template===void 0||e!==`swapped`);if(e.object!==void 0||o.length>0)throw Error(`the handler '${e.handler}' for '${n}' uses ${e.object===void 0?``:`an object `}${(e.flags??[]).join(`, `)}: adwaita-nativescript binds plain handlers only until each of those is verified against GTK.`);if(r.template!==void 0){a.connect(n,r.template.handler(e.handler,{flags:e.flags}));continue}let s=r.scope?.[e.handler];if(typeof s!=`function`)throw Error(`the tree binds the handler '${e.handler}' for '${n}', and the scope ${r.scope===void 0?"was not given (pass `scope`)":`has no such function`}.`);a.connect(n,(...e)=>s.apply(r.scope,e))}}const T={row:`row`,column:`column`,"row-span":`rowSpan`,"column-span":`columnSpan`};function applyLayout(e,t,n,r){if(e.layout!==void 0){if(typeof n.ctor.prototype.attach!=`function`)throw Error(`<${elementOf(e).xmlName}> authored layout (${Object.keys(e.layout).join(`, `)}) under \`${r}\`, which has no \`attach\`: this port's only layout manager is the grid, so the placement would be dropped.`);if(!(t instanceof S))throw Error(`\`${e.tag}\` is not a view, so it has no cell to place.`);for(let[n,r]of Object.entries(e.layout)){let i=T[n];if(i===void 0)throw Error(`layout \`${n}\` on \`${e.tag}\` reaches nothing: a grid child takes ${Object.keys(T).join(`, `)}.`);if(typeof r!=`number`||!Number.isInteger(r))throw Error(`layout \`${n}: ${String(r)}\` on \`${e.tag}\` is not a whole number.`);t[i]=r}}}function unknownProperty(e,t,n,r,i,a){let s=o(a,r);return Error(s===null?`<${e.xmlName} ${n}="${String(i)}"> reaches nothing: \`${t}\` declares no '${r}'. NativeScript's builder assigns it anyway, as a dead own-property at exit 0, so the attribute door cannot report this and the tree would render without it.`:`<${e.xmlName} ${n}="${String(i)}"> reaches nothing on \`${t}\`: ${s}`)}function buildView(e,t,n,r){if(e.page!==void 0)throw Error(`<${t.xmlName}> is a page (${JSON.stringify(e.page)}), and adwaita-nativescript builds no pages: there is no NS widget yet for Gtk.Notebook, and Gtk.StackPage is not on this branch.`);if(e.id!==void 0){if(r.ids.has(e.id)||r.values?.has(e.id))throw Error(`Two nodes of this tree carry the id '${e.id}'; GtkBuilder refuses a duplicate id.`);r.ids.set(e.id,n),n.id=e.id}let a=i(t.ctor);for(let[i,a]of _(e,r.menus)){let r=x(i);if(!s(n,r))throw unknownProperty(t,e.tag,i,r,i,n);l(n,r,a)}for(let[i,o]of Object.entries(e.props??{})){if(i===`menu-model`)continue;let c=x(i);if(!s(n,c))throw unknownProperty(t,e.tag,i,c,o,n);if(a.includes(c)){r.pending.push({view:n,element:t,prop:c,id:String(o)});continue}let u=translated(r.translate,o,e.translatable?.[i]),f=d(n,c,u,`<${t.xmlName} ${i}="${String(u)}">`);l(n,c,f===null?String(u):f.value)}if(e.styleClasses!==void 0&&e.styleClasses.length>0){if(!(`styleClasses`in n))throw Error(`<${t.xmlName}> takes no style classes: \`${e.tag}\` declares no 'styleClasses', so [${e.styleClasses.join(`, `)}] would be dropped.`);n.styleClasses=e.styleClasses.join(` `)}if(applyAccessibility(n,e,r),e.extensions?.strings!==void 0)throw Error(`<${t.xmlName}> takes no string-list items: \`${e.tag}\` is a widget, and only a list model holds them, so [${e.extensions.strings.map(e=>e.value).join(`, `)}] would be dropped.`);return applyResponses(n,t,e,r),n}const E={label:`accessibilityLabel`,description:`accessibilityHint`};function applyAccessibility(e,t,n){for(let[r,i]of Object.entries(t.accessibility??{}))e[E[r]]=String(translated(n.translate,i.value,i.translatable))}function buildValue(e,t,n,r){if(e.id!==void 0&&r.values===void 0)throw Error(`<${t.xmlName} id="${e.id}"> reaches nothing: \`${e.tag}\` is not a view, and \`getViewById\` walks views, so code beside the \`.blp\` could never look it up. \`buildWithSiblings\` hands every object back by id.`);if(e.styleClasses!==void 0&&e.styleClasses.length>0)throw Error(`<${t.xmlName}> takes no style classes: \`${e.tag}\` is not a widget, so [${e.styleClasses.join(`, `)}] would be dropped.`);if(e.accessibility!==void 0)throw Error(`<${t.xmlName}> takes no accessibility: \`${e.tag}\` is not a widget, so ${Object.keys(e.accessibility).join(`, `)} would be dropped.`);let i={};for(let[a,o]of _(e,r.menus)){let r=x(a);if(!s(n,r))throw unknownProperty(t,e.tag,a,r,a,n);i[r]=o}for(let[a,o]of Object.entries(e.props??{})){if(a===`menu-model`)continue;let c=x(a);if(!s(n,c))throw unknownProperty(t,e.tag,a,c,o,n);i[c]=translated(r.translate,o,e.translatable?.[a])}let a=e.extensions?.strings;if(a!==void 0){if(typeof n.append!=`function`)throw Error(`<${t.xmlName}> takes no string-list items: \`${e.tag}\` has no \`append\`, so [${a.map(e=>e.value).join(`, `)}] would be dropped.`);i.strings=a.map(e=>String(translated(r.translate,e.value,e.translatable)))}let o=new t.ctor(i);if(applyResponses(o,t,e,r),e.id!==void 0&&r.values!==void 0){if(r.values.has(e.id)||r.ids.has(e.id))throw Error(`Two nodes of this tree carry the id '${e.id}'; GtkBuilder refuses a duplicate id.`);r.values.set(e.id,o)}return o}function applyResponses(e,t,n,r){let i=e,a=n.extensions?.responses;if(a!==void 0){if(typeof i.add_response!=`function`)throw Error(`<${t.xmlName}> takes no responses: \`${n.tag}\` has no \`add_response\`, so [${a.map(e=>e.id).join(`, `)}] would be dropped.`);for(let{id:e,label:t,appearance:n,enabled:o,translatable:s}of a)i.add_response(e,String(translated(r.translate,t,s)),{...n===void 0?{}:{appearance:n},...o===void 0?{}:{enabled:o}})}}function builderNameFor(e,t,n){let r=elementOf(n);if(n.slot===void 0)return r.xmlName;let i=n.slot,o=a(e.ctor);if(o===null||!o.includes(i))throw Error(`<${e.xmlName}.${i}> reaches nothing: \`${t}\` declares no such builder slot, so NativeScript would hand <${r.xmlName}> to its fallback placement instead — at exit 0, in a cell the tree never asked for. Known slots: ${o===null||o.length===0?`none`:o.join(`, `)}.`);return i}export{applyBreakpoints,build,buildDialog,buildInto,buildWithSiblings,elementFor,registerBarrel,f as registerTemplateClass};
@@ -1 +1 @@
1
- import"../_virtual/_rolldown/runtime.js";import{builderSlotsOf as e,resolveBuilderSlot as t}from"./builder-slots.js";import{applyConstructProps as n}from"./construct-props.js";import{withSignals as r}from"./signals.js";import{GtkImage as i}from"./gtk-image.js";import{ActionRowState as a,isViewSensitive as o,rowLabelVisuals as s}from"./row-state.js";import{GridLayout as c,ItemSpec as l,Label as u,StackLayout as d}from"@nativescript/core";const f=`activated`,p=`notify::title`,m=`notify::subtitle`,h=`notify::icon-name`,g=`notify::activatable`,_=[`prefix`,`suffix`];var AdwActionRow=class extends r(c,{GTypeName:`AdwActionRow`,Properties:{title:{kind:`string`,default:``,blurb:`The title of the row`},subtitle:{kind:`string`,default:``,blurb:`The subtitle of the row`},"icon-name":{kind:`string`,default:``,blurb:`The icon name for this row`},activatable:{kind:`boolean`,default:!1,blurb:`Whether this row can be activated`}}}){static GTypeName=`AdwActionRow`;static builderSlots=e(_,`suffix`);isActionRow=!0;_textStack;_titleLabel;_subtitleLabel;_rowState=new a;_prefix=null;_iconImage=null;_suffix=null;constructor(e){super(),this.className=`adw-row adw-action-row`,this.addColumn(new l(1,`auto`)),this.addColumn(new l(1,`star`)),this.addColumn(new l(1,`auto`)),this.addRow(new l(1,`auto`));let t=new d;t.orientation=`vertical`,t.className=`adw-row-text`,c.setColumn(t,1);let r=new u;r.className=`adw-row-title`,r.textWrap=!0,t.addChild(r);let i=new u;i.className=`adw-row-subtitle`,i.textWrap=!0,t.addChild(i),this.addChild(t),this._textStack=t,this._titleLabel=r,this._subtitleLabel=i,this.connect(p,e=>e._applyLabels()),this.connect(m,e=>e._applyLabels()),this.connect(h,e=>e._applyIconName()),this.connect(g,e=>{e._rowState.setActivatable(e.activatable)}),this._applyLabels(),this.addEventListener(`tap`,()=>this.activate()),n(this,e)}add_prefix(e){this._prefix&&this.remove(this._prefix),e.className=`${e.className??``} adw-row-prefix`.trim(),c.setColumn(e,0),this.insertChild(e,0),this._prefix=e}get prefix(){return this._prefix}add_suffix(e){this._suffix&&this.remove(this._suffix),e.className=`${e.className??``} adw-row-suffix`.trim(),c.setColumn(e,2),this.addChild(e),this._suffix=e}remove(e){if(e===this._prefix)this._prefix=null;else if(e===this._suffix)this._suffix=null;else throw TypeError(`${this.constructor.name}.remove(): the view is neither this row's prefix nor its suffix. add_prefix()/add_suffix() are the only two slots remove() clears.`);this.removeChild(e),e===this._iconImage&&(this._iconImage=null,this.iconName=``)}get suffix(){return this._suffix}_addChildFromBuilder(e,n){t(e,_,`suffix`)===`prefix`?this.add_prefix(n):this.add_suffix(n)}get activatableWidget(){return this._rowState.activatableWidget}set activatableWidget(e){this._rowState.setActivatableWidget(e,o(e))&&e!==null&&(this.activatable=this._rowState.activatable)}syncActivatableWidgetSensitivity(){let e=this._rowState.activatableWidget;e&&this._rowState.setActivatableWidgetSensitive(o(e))&&(this.activatable=this._rowState.activatable)}activate(){if(!this.activatable)return;let e={eventName:f,object:this};this.notify(e)}_managesTitleVisibility=!0;_applyLabels(){let e=s({title:this.title,subtitle:this.subtitle});this._titleLabel.text=e.title,this._managesTitleVisibility&&(this._titleLabel.visibility=e.titleVisibility),this._subtitleLabel.text=e.subtitle,this._subtitleLabel.visibility=e.subtitleVisibility}_applyIconName(){let e=this.iconName;if(e===``){this._iconImage!==null&&this.remove(this._iconImage);return}this._iconImage===null&&(this._iconImage=new i,this.add_prefix(this._iconImage)),this._iconImage.iconName=e}};export{f as ACTIVATED,AdwActionRow,g as NOTIFY_ACTIVATABLE,h as NOTIFY_ICON_NAME,m as NOTIFY_SUBTITLE,p as NOTIFY_TITLE};
1
+ import"../_virtual/_rolldown/runtime.js";import{builderSlotsOf as e,resolveBuilderSlot as t}from"./builder-slots.js";import{applyConstructProps as n}from"./construct-props.js";import{withSignals as r}from"./signals.js";import{GtkImage as i}from"./gtk-image.js";import{ActionRowState as a,isViewSensitive as o,rowLabelVisuals as s}from"./row-state.js";import{adwSubtitleWriteNotifies as c}from"@gjsify/adwaita-core";import{GridLayout as l,ItemSpec as u,Label as d,StackLayout as f}from"@nativescript/core";const p=`activated`,m=`notify::title`,h=`notify::subtitle`,g=`notify::icon-name`,_=`notify::activatable`,v=[`prefix`,`suffix`];var AdwActionRow=class extends r(l,{GTypeName:`AdwActionRow`,Properties:{title:{kind:`string`,default:``,blurb:`The title of the row`},subtitle:{kind:`string`,default:``,blurb:`The subtitle of the row`,normalize:e=>e==null?``:String(e),changed:(e,t,n)=>c(String(t),n==null?null:String(e))},"icon-name":{kind:`string`,default:``,blurb:`The icon name for this row`},activatable:{kind:`boolean`,default:!1,blurb:`Whether this row can be activated`}}}){static GTypeName=`AdwActionRow`;static builderSlots=e(v,`suffix`);isActionRow=!0;_textStack;_titleLabel;_subtitleLabel;_rowState=new a;_prefix=null;_iconImage=null;_suffix=null;constructor(e){super(),this.className=`adw-row adw-action-row`,this.addColumn(new u(1,`auto`)),this.addColumn(new u(1,`star`)),this.addColumn(new u(1,`auto`)),this.addRow(new u(1,`auto`));let t=new f;t.orientation=`vertical`,t.className=`adw-row-text`,l.setColumn(t,1);let r=new d;r.className=`adw-row-title`,r.textWrap=!0,t.addChild(r);let i=new d;i.className=`adw-row-subtitle`,i.textWrap=!0,t.addChild(i),this.addChild(t),this._textStack=t,this._titleLabel=r,this._subtitleLabel=i,this.connect(m,e=>e._applyLabels()),this.connect(h,e=>e._applyLabels()),this.connect(g,e=>e._applyIconName()),this.connect(_,e=>{e._rowState.setActivatable(e.activatable)}),this._applyLabels(),this.addEventListener(`tap`,()=>this.activate()),n(this,e)}add_prefix(e){this._prefix&&this.remove(this._prefix),e.className=`${e.className??``} adw-row-prefix`.trim(),l.setColumn(e,0),this.insertChild(e,0),this._prefix=e}get prefix(){return this._prefix}add_suffix(e){this._suffix&&this.remove(this._suffix),e.className=`${e.className??``} adw-row-suffix`.trim(),l.setColumn(e,2),this.addChild(e),this._suffix=e}remove(e){if(e===this._prefix)this._prefix=null;else if(e===this._suffix)this._suffix=null;else throw TypeError(`${this.constructor.name}.remove(): the view is neither this row's prefix nor its suffix. add_prefix()/add_suffix() are the only two slots remove() clears.`);this.removeChild(e),e===this._iconImage&&(this._iconImage=null,this.iconName=``)}get suffix(){return this._suffix}_addChildFromBuilder(e,n){t(e,v,`suffix`)===`prefix`?this.add_prefix(n):this.add_suffix(n)}get activatableWidget(){return this._rowState.activatableWidget}set activatableWidget(e){this._rowState.setActivatableWidget(e,o(e))&&e!==null&&(this.activatable=this._rowState.activatable)}syncActivatableWidgetSensitivity(){let e=this._rowState.activatableWidget;e&&this._rowState.setActivatableWidgetSensitive(o(e))&&(this.activatable=this._rowState.activatable)}activate(){if(!this.activatable)return;let e={eventName:p,object:this};this.notify(e)}_managesTitleVisibility=!0;_applyLabels(){let e=s({title:this.title,subtitle:this.subtitle});this._titleLabel.text=e.title,this._managesTitleVisibility&&(this._titleLabel.visibility=e.titleVisibility),this._subtitleLabel.text=e.subtitle,this._subtitleLabel.visibility=e.subtitleVisibility}_applyIconName(){let e=this.iconName;if(e===``){this._iconImage!==null&&this.remove(this._iconImage);return}this._iconImage===null&&(this._iconImage=new i,this.add_prefix(this._iconImage)),this._iconImage.iconName=e}};export{p as ACTIVATED,AdwActionRow,_ as NOTIFY_ACTIVATABLE,g as NOTIFY_ICON_NAME,h as NOTIFY_SUBTITLE,m as NOTIFY_TITLE};
@@ -1 +1 @@
1
- import"../_virtual/_rolldown/runtime.js";import{applyConstructProps as e}from"./construct-props.js";import{xmlBoolean as t}from"./xml-values.js";import{withSignals as n}from"./signals.js";import{GtkImage as r}from"./gtk-image.js";import{attachRowPressFeedback as i}from"./row-press.js";import{buttonContentClassName as a,buttonContentLabelText as o}from"./button-content.js";import{assertPopupMenuAssignable as s,refuseMenuString as c}from"./popup-menu.js";import{showMenuPopup as l}from"./popup-menu-view.js";import{splitButtonArrowSvg as u}from"./split-button.js";import{ArrowType as d}from"./gtk-enums.js";import{SPLIT_BUTTON_DISABLED_OPACITY as f,SplitButtonState as p}from"@gjsify/adwaita-core";import{GridLayout as m,ItemSpec as h,Label as g,StackLayout as _}from"@nativescript/core";const v=`notify::direction`,y=`menuTapped`,clearingSlot=(e,t)=>{e._contentGate=!0;try{t()}finally{e._contentGate=!1}};var AdwSplitButton=class extends n(m,{GTypeName:`AdwSplitButton`,Signals:{clicked:{},activate:{}},Properties:{label:{kind:`string`,default:null,blurb:`The label to show in the button`,normalize:(e,t)=>{let n=t;if(n._contentGate)return null;if(e==null)return n.label;let r=String(e);return r!==n.label&&n.iconName!==null&&clearingSlot(n,()=>n.iconName=null),r}},"icon-name":{kind:`string`,default:null,blurb:`The name of the icon used to automatically populate the button`,normalize:(e,t)=>{let n=t;if(n._contentGate)return null;if(e==null)return n.iconName;let r=String(e)===``?null:String(e);return n.label!==null&&clearingSlot(n,()=>n.label=null),r}},"use-underline":{kind:`boolean`,default:!1,blurb:`Whether an underline in the text indicates a mnemonic`},"can-shrink":{kind:`boolean`,default:!1,blurb:`Whether the button can be smaller than the natural size of its contents`},"dropdown-tooltip":{kind:`string`,default:``,blurb:`The tooltip of the dropdown button`}}}){static GTypeName=`AdwSplitButton`;static emittedSignals=[v];_actionPart;_actionLabel;_actionIcon;_dropdownPart;_chevron;_state=new p;_actions=null;_showingIcon=!1;_sensitive=!0;_contentGate=!1;constructor(t){super(),this.className=`adw-split-button`,this.addColumn(new h(1,`auto`)),this.addColumn(new h(1,`auto`)),this.addRow(new h(1,`auto`));let n=new _;n.orientation=`horizontal`,n.className=`adw-split-button-action`,n.horizontalAlignment=`center`,m.setColumn(n,0);let o=new g;o.className=`adw-split-button-label`,o.verticalAlignment=`middle`,n.addChild(o);let s=new r;s.className=`${s.className} adw-split-button-action-icon`.trim(),s.verticalAlignment=`middle`,this.addChild(n),this._actionPart=n,this._actionLabel=o,this._actionIcon=s;let c=new m;c.className=`adw-split-button-dropdown`,c.addColumn(new h(1,`star`)),c.addRow(new h(1,`star`)),m.setColumn(c,1);let l=new r;l.className=`${l.className} adw-split-button-chevron`.trim(),l.iconName=u(this._state.direction),l.horizontalAlignment=`center`,l.verticalAlignment=`middle`,c.addChild(l),this.addChild(c),this._dropdownPart=c,this._chevron=l,n.addEventListener(`tap`,()=>this._click()),this.connect(`activate`,e=>e._click()),c.addEventListener(`tap`,()=>{this._openMenu()}),i(n),i(c),this.connect(`notify::label`,e=>e._renderContent()),this.connect(`notify::icon-name`,e=>e._renderContent()),this.connect(`notify::use-underline`,e=>e._renderContent()),this.connect(`notify::can-shrink`,e=>{e._actionLabel.className=a(e._actionLabel.className,e.canShrink)}),this._state.subscribe(()=>this._render()),this._render(),e(this,t)}_openMenu(){if(!(!this._sensitive||this._state.open||!this._state.dropdownEnabled)){this._state.toggleMenu();try{l(this._dropdownPart,{model:this._state.menuModel??[],actions:this._actions,onActivated:(e,t)=>{let n=this._state.activateMenuItem(t);if(n===null)return;let r={eventName:y,object:this,item:n.label,id:n.id??n.label,path:t,action:n.action};this.notify(r)},onDismiss:()=>this._state.closeMenu()})}catch(e){throw this._state.closeMenu(),e}}}_click(){this._sensitive&&this.emit(`clicked`)}_renderContent(){let e=this.iconName!==null;e?this._actionIcon.iconName=this.iconName??``:this._actionLabel.text=o(this.label??``,this.useUnderline),e!==this._showingIcon&&(this._actionPart.removeChild(this._showingIcon?this._actionIcon:this._actionLabel),this._actionPart.addChild(e?this._actionIcon:this._actionLabel),this._showingIcon=e)}_render(){let{direction:e,dropdownEnabled:t}=this._state;this._chevron.iconName=u(e),this._dropdownPart.opacity=t?1:f,this.opacity=this._sensitive?1:f}get menuModel(){return this._state.menuModel??[]}set menuModel(e){c(e,`AdwSplitButton`),this._state.setMenuModel(e),s(this._state.menuModel??[])}get actions(){return this._actions}set actions(e){this._actions=e??null}get_direction(){return d[this._state.direction.toUpperCase()]}set_direction(e){let t=e,n=typeof t==`number`?t:/^\d+$/.test(String(t))?Number(t):d[String(t).toUpperCase()],r=Object.keys(d).find(e=>d[e]===n)?.toLowerCase();if(r===void 0)throw TypeError(`${String(t)} is not a valid value for enum argument direction (Gtk.ArrowType)`);this._state.setDirection(r)&&this.notify({eventName:v,object:this,value:this.get_direction()})}get sensitive(){return this._sensitive}set sensitive(e){let n=!!t(e,this._sensitive);n!==this._sensitive&&(this._sensitive=n,this._render())}get actionButton(){return this._actionPart}};export{AdwSplitButton,y as MENU_TAPPED,v as NOTIFY_DIRECTION};
1
+ import"../_virtual/_rolldown/runtime.js";import{applyConstructProps as e}from"./construct-props.js";import{xmlBoolean as t}from"./xml-values.js";import{withSignals as n}from"./signals.js";import{GtkImage as r}from"./gtk-image.js";import{attachRowPressFeedback as i}from"./row-press.js";import{buttonContentClassName as a,buttonContentLabelText as o}from"./button-content.js";import{assertPopupMenuAssignable as s,refuseMenuString as c}from"./popup-menu.js";import{showMenuPopup as l}from"./popup-menu-view.js";import{splitButtonArrowSvg as u}from"./split-button.js";import{ArrowType as d}from"./gtk-enums.js";import{SPLIT_BUTTON_DISABLED_OPACITY as f,SplitButtonState as p}from"@gjsify/adwaita-core";import{GridLayout as m,ItemSpec as h,Label as g,StackLayout as _}from"@nativescript/core";const v=`notify::direction`,y=`menuTapped`,clearOtherSlot=(e,t)=>{if(!(e._contentGate||e[t]===null)){e._contentGate=!0;try{e[t]=null}finally{e._contentGate=!1}}};var AdwSplitButton=class extends n(m,{GTypeName:`AdwSplitButton`,Signals:{clicked:{},activate:{}},Properties:{label:{kind:`string`,default:null,blurb:`The label to show in the button`,normalize:(e,t)=>{let n=t;return n._contentGate?null:e==null?n.label:String(e)},afterNotify:e=>clearOtherSlot(e,`iconName`)},"icon-name":{kind:`string`,default:null,blurb:`The name of the icon used to automatically populate the button`,normalize:(e,t)=>{let n=t;return n._contentGate?null:e==null?n.iconName:String(e)===``?null:String(e)},changed:(e,t,n)=>e!==t||n===``,afterNotify:e=>clearOtherSlot(e,`label`)},"use-underline":{kind:`boolean`,default:!1,blurb:`Whether an underline in the text indicates a mnemonic`},"can-shrink":{kind:`boolean`,default:!1,blurb:`Whether the button can be smaller than the natural size of its contents`},"dropdown-tooltip":{kind:`string`,default:``,blurb:`The tooltip of the dropdown button`}}}){static GTypeName=`AdwSplitButton`;static emittedSignals=[v];_actionPart;_actionLabel;_actionIcon;_dropdownPart;_chevron;_state=new p;_actions=null;_showingIcon=!1;_sensitive=!0;_contentGate=!1;constructor(t){super(),this.className=`adw-split-button`,this.addColumn(new h(1,`auto`)),this.addColumn(new h(1,`auto`)),this.addRow(new h(1,`auto`));let n=new _;n.orientation=`horizontal`,n.className=`adw-split-button-action`,n.horizontalAlignment=`center`,m.setColumn(n,0);let o=new g;o.className=`adw-split-button-label`,o.verticalAlignment=`middle`,n.addChild(o);let s=new r;s.className=`${s.className} adw-split-button-action-icon`.trim(),s.verticalAlignment=`middle`,this.addChild(n),this._actionPart=n,this._actionLabel=o,this._actionIcon=s;let c=new m;c.className=`adw-split-button-dropdown`,c.addColumn(new h(1,`star`)),c.addRow(new h(1,`star`)),m.setColumn(c,1);let l=new r;l.className=`${l.className} adw-split-button-chevron`.trim(),l.iconName=u(this._state.direction),l.horizontalAlignment=`center`,l.verticalAlignment=`middle`,c.addChild(l),this.addChild(c),this._dropdownPart=c,this._chevron=l,n.addEventListener(`tap`,()=>this._click()),this.connect(`activate`,e=>e._click()),c.addEventListener(`tap`,()=>{this._openMenu()}),i(n),i(c),this.connect(`notify::label`,e=>e._renderContent()),this.connect(`notify::icon-name`,e=>e._renderContent()),this.connect(`notify::use-underline`,e=>e._renderContent()),this.connect(`notify::can-shrink`,e=>{e._actionLabel.className=a(e._actionLabel.className,e.canShrink)}),this._state.subscribe(()=>this._render()),this._render(),e(this,t)}_openMenu(){if(!(!this._sensitive||this._state.open||!this._state.dropdownEnabled)){this._state.toggleMenu();try{l(this._dropdownPart,{model:this._state.menuModel??[],actions:this._actions,onActivated:(e,t)=>{let n=this._state.activateMenuItem(t);if(n===null)return;let r={eventName:y,object:this,item:n.label,id:n.id??n.label,path:t,action:n.action};this.notify(r)},onDismiss:()=>this._state.closeMenu()})}catch(e){throw this._state.closeMenu(),e}}}_click(){this._sensitive&&this.emit(`clicked`)}_renderContent(){let e=this.iconName!==null;e?this._actionIcon.iconName=this.iconName??``:this._actionLabel.text=o(this.label??``,this.useUnderline),e!==this._showingIcon&&(this._actionPart.removeChild(this._showingIcon?this._actionIcon:this._actionLabel),this._actionPart.addChild(e?this._actionIcon:this._actionLabel),this._showingIcon=e)}_render(){let{direction:e,dropdownEnabled:t}=this._state;this._chevron.iconName=u(e),this._dropdownPart.opacity=t?1:f,this.opacity=this._sensitive?1:f}get menuModel(){return this._state.menuModel??[]}set menuModel(e){c(e,`AdwSplitButton`),this._state.setMenuModel(e),s(this._state.menuModel??[])}get actions(){return this._actions}set actions(e){this._actions=e??null}get_direction(){return d[this._state.direction.toUpperCase()]}set_direction(e){let t=e,n=typeof t==`number`?t:/^\d+$/.test(String(t))?Number(t):d[String(t).toUpperCase()],r=Object.keys(d).find(e=>d[e]===n)?.toLowerCase();if(r===void 0)throw TypeError(`${String(t)} is not a valid value for enum argument direction (Gtk.ArrowType)`);this._state.setDirection(r)&&this.notify({eventName:v,object:this,value:this.get_direction()})}get sensitive(){return this._sensitive}set sensitive(e){let n=!!t(e,this._sensitive);n!==this._sensitive&&(this._sensitive=n,this._render())}get actionButton(){return this._actionPart}};export{AdwSplitButton,y as MENU_TAPPED,v as NOTIFY_DIRECTION};
@@ -1,2 +1,2 @@
1
- import"../_virtual/_rolldown/runtime.js";import{applyConstructProps as e}from"./construct-props.js";import{xmlBoolean as t,xmlNumber as n}from"./xml-values.js";import{androidApiLevel as r}from"./native-tooltip.js";import{withSignals as i}from"./signals.js";import{classNameWith as a,normalizeStyleClasses as o,withCssClass as s,withoutCssClass as c}from"./style-classes.js";import{DEFAULT_LABEL_LINES as l,DEFAULT_LABEL_XALIGN as u,LABEL_JUSTIFICATIONS as d,labelDisplayText as f,labelEffectiveLines as p,labelEllipsizeOverflowValue as m,normalizeLabelEllipsize as h,normalizeLabelLines as g,normalizeLabelXalign as _}from"@gjsify/adwaita-core";import{Label as v}from"@nativescript/core";const y=new Map([[0,`start`],[.5,`center`],[1,`end`]]),b={left:`start`,right:`end`,center:`center`,fill:`start`};function physical(e,t){return e===`center`?`center`:e===`start`===t?`right`:`left`}var GtkLabel=class extends i(v){static GTypeName=`GtkLabel`;_label=``;_useMarkup=!1;_useUnderline=!1;_ellipsize=`none`;_lines=-1;_styleClasses=[];_xalign=u;_xalignWritten=!1;_justify=`left`;_selectable=!1;constructor(t){super(),this.addEventListener(`loaded`,()=>{this._applySelectable(),this._applyJustificationMode()}),e(this,t)}get label(){return this._label}set label(e){this._label=e??``,this._render()}get useMarkup(){return this._useMarkup}set useMarkup(e){this._useMarkup=t(e,this._useMarkup),this._render()}get useUnderline(){return this._useUnderline}set useUnderline(e){this._useUnderline=t(e,this._useUnderline),this._render()}get wrap(){return this.textWrap}set wrap(e){let n=t(e,this.textWrap);this._applyAlignment({wrap:n}),this.textWrap=n}get ellipsize(){return this._ellipsize}set ellipsize(e){this._ellipsize=h(e),this.textOverflow=m(this._ellipsize),this._applyLines()}get lines(){return this._lines}set lines(e){this._lines=g(n(e,l)),this._applyLines()}get selectable(){return this._selectable}set selectable(e){this._selectable=t(e,this._selectable),this._applySelectable()}_applySelectable(){this.nativeViewProtected?.setTextIsSelectable?.(this._selectable)}_applyLines(){this.maxLines=p(this._lines,this._ellipsize)??0}get justify(){return this._justify}set justify(e){let t=d.includes(e)?e:d[n(e,-1)];if(t===void 0)throw TypeError(`'${String(e)}' is not a Gtk.Justification, so it cannot be 'justify'. The members are ${d.join(`, `)}, or their values 0 to 3.`);this._applyAlignment({justify:t})}get xalign(){return this._xalign}set xalign(e){let t=_(n(e,u));if(!y.has(t))throw TypeError(`Gtk.Label xalign ${t} has no NativeScript counterpart: textAlignment places text at the start, the centre or the end, so only 0, 0.5 and 1 render as written. Snapping it would show a different label than GTK does with no sign of the difference.`);this._applyAlignment({xalign:t})}_applyAlignment(e){let t=e.xalign??(this._xalignWritten?this._xalign:null),n=e.justify??this._justify,r=e.text??this.text??``,i=(e.wrap??this.textWrap)||r.includes(`
2
- `),a=b[n],o=t===null?null:y.get(t),s;if(o===null)s=n===`left`?null:a;else if(o===a||!i||n===`left`)s=o;else throw TypeError(`Gtk.Label justify ${n} beside xalign ${t} has no NativeScript counterpart on a label that can show several lines: GTK places the text block at its ${o} and aligns the lines inside it to their ${a}, and textAlignment is one alignment for both. An xalign on the justify edge, or a label without wrap and newline, renders exactly.`);if(e.xalign!==void 0&&(this._xalign=e.xalign,this._xalignWritten=!0),e.justify!==void 0&&(this._justify=e.justify),s===null){(e.xalign!==void 0||e.justify!==void 0)&&(this.textAlignment=`initial`);return}let c=physical(s,this.style?.direction===`rtl`);this.textAlignment=n===`fill`&&c===`left`?`justify`:c,this._applyJustificationMode()}_applyJustificationMode(){this.textAlignment===`justify`||r()<26||this.nativeViewProtected?.setJustificationMode?.(+(this._justify===`fill`))}get styleClasses(){return[...this._styleClasses]}set styleClasses(e){this._setClasses(o(e))}get_label(){return this.label}set_label(e){this.label=e}set_markup(e){this._label=e??``,this._useMarkup=!0,this._render()}get_text(){return this.text??``}add_css_class(e){this._setClasses(s(this._styleClasses,e))}remove_css_class(e){this._setClasses(c(this._styleClasses,e))}has_css_class(e){return this._styleClasses.includes((e??``).trim())}get_css_classes(){return[...this._styleClasses]}set_css_classes(e){this._setClasses(o([...e].join(` `)))}_setClasses(e){this._styleClasses=[...e],this.className=a(``,this._styleClasses)}_render(){let e=f(this._label,this._useMarkup,this._useUnderline);this._applyAlignment({text:e}),this.text=e}};export{GtkLabel};
1
+ import"../_virtual/_rolldown/runtime.js";import{applyConstructProps as e}from"./construct-props.js";import{xmlBoolean as t,xmlNumber as n}from"./xml-values.js";import{androidApiLevel as r}from"./native-tooltip.js";import{withSignals as i}from"./signals.js";import{nativePlatformHost as a}from"../platform-host.js";import{classNameWith as o,normalizeStyleClasses as s,withCssClass as c,withoutCssClass as l}from"./style-classes.js";import{labelMarkupFormattedString as u,labelMarkupNeedsSpans as d}from"./label-markup.js";import{DEFAULT_LABEL_LINES as f,DEFAULT_LABEL_XALIGN as p,HandledAccumulator as m,LABEL_JUSTIFICATIONS as h,createAppInfo as g,labelActivateLink as _,labelDisplayText as v,labelEffectiveLines as y,labelEllipsizeOverflowValue as b,labelHasLinks as x,labelLinkVisited as S,labelMarkupRender as C,normalizeLabelEllipsize as w,normalizeLabelLines as T,normalizeLabelXalign as E}from"@gjsify/adwaita-core";import{Label as D}from"@nativescript/core";const O=`activate-link`,k=g(a),A=new Map([[0,`start`],[.5,`center`],[1,`end`]]),j={left:`start`,right:`end`,center:`center`,fill:`start`};function physical(e,t){return e===`center`?`center`:e===`start`===t?`right`:`left`}var GtkLabel=class extends i(D){static GTypeName=`GtkLabel`;_label=``;_useMarkup=!1;_useUnderline=!1;_ellipsize=`none`;_lines=-1;_styleClasses=[];_xalign=p;_xalignWritten=!1;_justify=`left`;_selectable=!1;_links=[];constructor(t){super(),this.addEventListener(`loaded`,()=>{this._applySelectable(),this._applyJustificationMode()}),e(this,t)}get label(){return this._label}set label(e){this._label=e??``,this._render()}get useMarkup(){return this._useMarkup}set useMarkup(e){this._useMarkup=t(e,this._useMarkup),this._render()}get useUnderline(){return this._useUnderline}set useUnderline(e){this._useUnderline=t(e,this._useUnderline),this._render()}get wrap(){return this.textWrap}set wrap(e){let n=t(e,this.textWrap);this._applyAlignment({wrap:n}),this.textWrap=n}get ellipsize(){return this._ellipsize}set ellipsize(e){this._ellipsize=w(e),this.textOverflow=b(this._ellipsize),this._applyLines()}get lines(){return this._lines}set lines(e){this._lines=T(n(e,f)),this._applyLines()}get selectable(){return this._selectable}set selectable(e){this._selectable=t(e,this._selectable),this._applySelectable()}_applySelectable(){this.nativeViewProtected?.setTextIsSelectable?.(this._selectable)}_applyLines(){this.maxLines=y(this._lines,this._ellipsize)??0}get justify(){return this._justify}set justify(e){let t=h.includes(e)?e:h[n(e,-1)];if(t===void 0)throw TypeError(`'${String(e)}' is not a Gtk.Justification, so it cannot be 'justify'. The members are ${h.join(`, `)}, or their values 0 to 3.`);this._applyAlignment({justify:t})}get xalign(){return this._xalign}set xalign(e){let t=E(n(e,p));if(!A.has(t))throw TypeError(`Gtk.Label xalign ${t} has no NativeScript counterpart: textAlignment places text at the start, the centre or the end, so only 0, 0.5 and 1 render as written. Snapping it would show a different label than GTK does with no sign of the difference.`);this._applyAlignment({xalign:t})}_applyAlignment(e){let t=e.xalign??(this._xalignWritten?this._xalign:null),n=e.justify??this._justify,r=e.text??this.text??``,i=(e.wrap??this.textWrap)||r.includes(`
2
+ `),a=j[n],o=t===null?null:A.get(t),s;if(o===null)s=n===`left`?null:a;else if(o===a||!i||n===`left`)s=o;else throw TypeError(`Gtk.Label justify ${n} beside xalign ${t} has no NativeScript counterpart on a label that can show several lines: GTK places the text block at its ${o} and aligns the lines inside it to their ${a}, and textAlignment is one alignment for both. An xalign on the justify edge, or a label without wrap and newline, renders exactly.`);if(e.xalign!==void 0&&(this._xalign=e.xalign,this._xalignWritten=!0),e.justify!==void 0&&(this._justify=e.justify),s===null){(e.xalign!==void 0||e.justify!==void 0)&&(this.textAlignment=`initial`);return}let c=physical(s,this.style?.direction===`rtl`);this.textAlignment=n===`fill`&&c===`left`?`justify`:c,this._applyJustificationMode()}_applyJustificationMode(){this.textAlignment===`justify`||r()<26||this.nativeViewProtected?.setJustificationMode?.(+(this._justify===`fill`))}get styleClasses(){return[...this._styleClasses]}set styleClasses(e){this._setClasses(s(e))}get_label(){return this.label}set_label(e){this.label=e}set_markup(e){this._label=e??``,this._useMarkup=!0,this._render()}get_text(){return this.text??``}add_css_class(e){this._setClasses(c(this._styleClasses,e))}remove_css_class(e){this._setClasses(l(this._styleClasses,e))}has_css_class(e){return this._styleClasses.includes((e??``).trim())}get_css_classes(){return[...this._styleClasses]}set_css_classes(e){this._setClasses(s([...e].join(` `)))}_setClasses(e){this._styleClasses=[...e],this.className=o(``,this._styleClasses)}_render(){let e=this._useMarkup?C(this._label,this._links):null;this._links=e?.links??[];let t=v(this._label,this._useMarkup,this._useUnderline);this._applyAlignment({text:t});let n=x(this._links);if(n!==this._styleClasses.includes(`link`)&&this._setClasses(n?c(this._styleClasses,`link`):l(this._styleClasses,`link`)),e!==null&&d(e)){this.text=t,this.formattedText=u(e,this._useUnderline,this.style.fontSize,e=>this._activateLink(e));return}this.formattedText!==null&&this.formattedText!==void 0&&(this.formattedText=null),this.text=t}_activateLink(e){let t=this._links[e];t!==void 0&&_(t.href,{rooted:this.isLoaded,emit:()=>{let e=new m;return this.notify({eventName:O,object:this,uri:t.href,accumulator:e}),e.stopped},launch:e=>this.launch(e)})&&(this._links=S(this._links,e))}launch(e){try{k.launch_default_for_uri(e,null)}catch{}}};export{O as ACTIVATE_LINK,GtkLabel};
@@ -0,0 +1 @@
1
+ import"../_virtual/_rolldown/runtime.js";import{stripMnemonic as e}from"@gjsify/adwaita-core";import{FormattedString as t,Span as n}from"@nativescript/core";function decoration(e,t){let n=e.underline||t;if(n&&e.strikethrough)return`underline line-through`;if(n)return`underline`;if(e.strikethrough)return`line-through`}const r={thin:`100`,ultralight:`200`,light:`300`,normal:`normal`,medium:`500`,semibold:`600`,bold:`bold`,ultrabold:`800`,heavy:`900`},i=new Set([`100`,`200`,`300`,`400`,`500`,`600`,`700`,`800`,`900`]);function applySpanAttributes(e,t){for(let[n,a]of Object.entries(t))switch(n){case`font_family`:case`family`:e.fontFamily=a;break;case`font_style`:case`style`:(a===`normal`||a===`italic`)&&(e.fontStyle=a);break;case`font_weight`:case`weight`:{let t=r[a]??(i.has(a)?a:void 0);t!==void 0&&(e.fontWeight=t);break}case`underline`:a!==`none`&&(e.textDecoration=`underline`);break;case`strikethrough`:a!==`false`&&a!==`none`&&(e.textDecoration=`line-through`);break;default:break}}function labelMarkupSpan(t,r,i){let a=new n;a.text=r?e(t.text):t.text;for(let e of t.style.spans)applySpanAttributes(a,e);t.style.monospace&&(a.fontFamily=`monospace`),t.style.bold&&(a.fontWeight=`bold`),t.style.italic&&(a.fontStyle=`italic`);let o=decoration(t.style,t.link!==null);o!==void 0&&(a.textDecoration=o),t.style.script!==null&&(a.style.verticalAlignment=t.style.script);let s=t.style.sizeSteps;return s!==0&&i!==void 0&&(a.fontSize=i*(s>0?1.2:.8333333333333)**Math.abs(s)),a}function labelMarkupNeedsSpans(e){return e.links.length>0?!0:e.runs.some(e=>e.link!==null||styled(e.style))}function styled(e){return e.bold||e.italic||e.underline||e.strikethrough||e.monospace||e.script!==null||e.sizeSteps!==0||e.spans.length>0}function labelMarkupFormattedString(e,r,i,a){let o=new t;for(let t of e.runs){let e=labelMarkupSpan(t,r,i);if(t.link!==null){let r=t.link;e.addEventListener(n.linkTapEvent,()=>a(r))}o.spans.push(e)}return o}export{labelMarkupFormattedString,labelMarkupNeedsSpans,labelMarkupSpan};
@@ -1 +1 @@
1
- import"../_virtual/_rolldown/runtime.js";import{ENGINE_TARGET as e}from"../engine-target.js";import{camelProperty as t,readGtkProperty as n,writeGtkProperty as r}from"./shadowed-properties.js";import{WIDGET_SIGNALS as i,watchMapping as a}from"./widget-mapping.js";import{withGtkWidgetLayout as o}from"./widget-layout.js";import{engineForTarget as s}from"@gjsify/adwaita-core";function coerceDeclared(e,t,n,r){return t.normalize===void 0?readDeclaredValue(e,t.kind,n):t.normalize(n,r)}function readDeclaredValue(e,t,n){if(typeof n!=`string`||t===`string`)return n;let r=n.trim();if(t===`object`)throw TypeError(`Property '${e}' holds an object; '${n}' is a string.`);if(t===`boolean`){let t=r.toLowerCase();if(t===`true`)return!0;if(t===`false`)return!1;throw TypeError(`Property '${e}' is a boolean; '${n}' is neither 'true' nor 'false'.`)}let i=r===``?NaN:Number(r);if(!Number.isFinite(i))throw TypeError(`Property '${e}' is a number; '${n}' is not one.`);return i}const c=new WeakMap;let l=1;const u=1073741824,d=new WeakMap,f=new WeakMap;function unknownHandler(e,t){return TypeError(`${e.constructor.name} has no handler with id ${t}. connect() hands out each id once and disconnect() takes it once; a second disconnect, or an id another widget returned, is refused here rather than left as a silent no-op.`)}const p=new WeakMap;function pureConnect(e,t,n){let r=l++,o=c.get(e);o===void 0&&(o=new Map,c.set(e,o));let s=i.includes(t)?a(e):void 0;return o.set(r,{eventName:t,listener:n,unwatch:s}),e.addEventListener(t,n),r}function pureDisconnect(e,t){let n=c.get(e)?.get(t);if(n===void 0)throw unknownHandler(e,t);e.removeEventListener(n.eventName,n.listener),n.unwatch?.(),c.get(e)?.delete(t)}function declaredConnect(e,t,n,r){let i=l++,a=p.get(e);return a===void 0&&p.set(e,a=new Map),a.set(i,{key:t,eventName:n,callback:r}),i}function declaredDisconnect(e,t){return p.get(e)?.delete(t)===!0}function emitDeclared(e,t,n){let r=p.get(e);if(r===void 0)return;let i=t.startsWith(`notify::`),a=[...r];for(let[o,s]of a){if(s.key!==t||r.get(o)!==s)continue;let a=i?{eventName:s.eventName,object:e}:{eventName:s.eventName,object:e,args:n};try{s.callback(e,a)}catch(t){console.error(`[${e.constructor.name}] unhandled exception in a '${s.eventName}' handler:`,t)}}}function refuseDeclaredEvent(e,t,n){let r=giKeyOf(resolvedFor(e.constructor),t);if(r===null)return;let i=r.startsWith(`notify::`),a=i?`a declared property's notification`:`a declared signal`,o=n===`notify`?i?`write the property, or emit it with notify('${r.slice(8)}')`:`emit it with emit('${r}', …)`:`subscribe with connect('${t}', (self, data) => …), whose id disconnect() takes`;throw TypeError(`${e.constructor.name}.${n}('${t}'): '${r}' is ${a} and GObject owns it — ${o}. On Android the emission belongs to the GObject and no NativeScript listener can see it, so ${n} would work off-device and be silent on it.`)}function spellingsOf(e){return[...new Set([e,e.replace(/-/g,`_`),t(e)])]}function emittedSignalsOf(e){let t=[];for(let n=e;typeof n==`function`;n=Object.getPrototypeOf(n))t.unshift(n);let n=new Set;for(let e of t)if(Object.hasOwn(e,`emittedSignals`))for(let t of e.emittedSignals)n.add(t);return[...n]}const m=new WeakMap,h=new WeakSet,g=new WeakSet,_=new WeakMap;function declarationsOf(e){let t=[];for(let n=e;typeof n==`function`;n=Object.getPrototypeOf(n)){let e=m.get(n);e!==void 0&&t.unshift(e)}return t}function resolvedFor(e){let t=_.get(e);if(t!==void 0)return t;let n=new Map,r=new Set,i={canonicalOf:n,declaredSignals:r,routeD:!1,giConnect:void 0,giDisconnect:void 0,giEmit:void 0},a=i;for(let t of declarationsOf(e)){for(let[e,r]of t.canonicalOf)n.set(e,r);for(let e of t.declaredSignals)r.add(e);t.routeD&&(a.routeD=!0),t.giConnect!==void 0&&(a.giConnect=t.giConnect),t.giDisconnect!==void 0&&(a.giDisconnect=t.giDisconnect),t.giEmit!==void 0&&(a.giEmit=t.giEmit)}return _.set(e,i),i}function giKeyOf(e,t){if(e.declaredSignals.has(t))return t;if(!t.startsWith(`notify::`))return null;let n=e.canonicalOf.get(t.slice(8));return n===void 0?null:`notify::${n}`}function declare(e,t,n){let r=new Map;for(let e of Object.keys(t?.Properties??{}))for(let t of spellingsOf(e))r.set(t,e);let i={meta:t,klass:e,prototype:e.prototype,canonicalOf:r,declaredSignals:new Set(Object.keys(t?.Signals??{})),routers:n,realized:!1,routeD:!1};return m.set(e,i),i}function declaredEmissionsOf(e){return[...Object.keys(e?.Signals??{}),...Object.keys(e?.Properties??{}).map(e=>`notify::${e}`)]}function realizeChain(e){if(!h.has(e)){h.add(e);for(let t of declarationsOf(e))realize(t)}}function realize(t){if(t.realized||(t.realized=!0,t.meta===void 0))return;let n=s(e);if(n?.supportsForeignParentClasses===!0){registerRouteD(t,n.registerForeignClass.bind(n));return}installPureJsProperties(t)}function registerRouteD(e,t){let{meta:n,prototype:r,routers:i}=e;if(i!==void 0&&(delete r.connect,delete r.disconnect,delete r.emit,delete r.notify),t(e.klass,n),wrapRouteDAccessors(e),i!==void 0){if(e.giConnect=r.connect,e.giDisconnect=r.disconnect,e.giEmit=r.emit,e.giConnect===void 0||e.giDisconnect===void 0||e.giEmit===void 0)throw Error(`Registering '${n.GTypeName}' over its NativeScript base installed no connect/disconnect/emit, so the widget would answer neither GObject nor this port. ADR 0105 refuses a silent fallback here: the subset is reachable only by calling usePureJsGObjectEngine() from '@gjsify/adwaita-core' before the port loads.`);for(let[e,t]of Object.entries(i))Object.defineProperty(r,e,{configurable:!0,writable:!0,enumerable:!1,value:t});refuseDeclaredNotifyPayload(r,r.notify)}e.routeD=!0}function refuseDeclaredNotifyPayload(e,t){let n=function notify(e,...n){if(typeof e==`object`&&e){let{eventName:t}=e;typeof t==`string`&&refuseDeclaredEvent(this,t,`notify`)}return t.call(this,e,...n)};g.add(n),Object.defineProperty(e,"notify",{configurable:!0,writable:!0,enumerable:!1,value:n})}function wrapRouteDAccessors(e){let{meta:t,prototype:n}=e;for(let[e,r]of Object.entries(t.Properties??{}))if(!(r.kind===`string`&&r.normalize===void 0))for(let i of spellingsOf(e)){let a=Object.getOwnPropertyDescriptor(n,i);if(a?.set===void 0)throw Error(`Registering '${t.GTypeName}' installed no setter for '${i}', so a string from XML would reach the GObject uncoerced. The host chain probably owns that name (see the class's \$foreignSkipped); rename the property.`);let o=a.set;Object.defineProperty(n,i,{...a,set(t){o.call(this,coerceDeclared(e,r,t,this))}})}}function installPureJsProperties(e){let{meta:t,prototype:n}=e;for(let[e,r]of Object.entries(t.Properties??{})){let t=defaultValueOf(r);for(let i of spellingsOf(e))i in n||Object.defineProperty(n,i,{configurable:!0,enumerable:!1,get(){let n=valuesOf(this);return n.has(e)||n.set(e,t),n.get(e)},set(t){let n=coerceDeclared(e,r,t,this),i=valuesOf(this);i.has(e)&&i.get(e)===n||(i.set(e,n),emitDeclared(this,`notify::${e}`,[]))}})}installPureNotify(e)}function installPureNotify(e){let{prototype:t}=e,n=t.notify;if(g.has(n))return;let r=function notify(e,...t){if(typeof e!=`string`){if(typeof e==`object`&&e){let{eventName:t}=e;typeof t==`string`&&refuseDeclaredEvent(this,t,`notify`)}return n.call(this,e,...t)}let{canonicalOf:r}=resolvedFor(this.constructor),i=r.get(e);if(i===void 0)throw TypeError(`${this.constructor.name} has no property '${e}' to notify. The declared ones are ${[...r.keys()].join(`, `)||`(none)`}; a NativeScript event is notified with its payload object, not with a name.`);emitDeclared(this,`notify::${i}`,[])};g.add(r),Object.defineProperty(t,"notify",{configurable:!0,writable:!0,enumerable:!1,value:r})}function withSignals(e,a){class WithSignals extends o(e){static emittedSignals=[...i,...declaredEmissionsOf(a)];constructor(...e){super(...e),realizeChain(new.target)}addEventListener(e,t,n,r){refuseDeclaredEvent(this,e,`addEventListener`),super.addEventListener(e,t,n,r)}removeEventListener(e,t,n){refuseDeclaredEvent(this,e,`removeEventListener`),super.removeEventListener(e,t,n)}connect(e,t){let n=resolvedFor(this.constructor),r=giKeyOf(n,e);if(n.routeD&&r!==null){let i=r.startsWith(`notify::`),a=n.giConnect.call(this,r,(n,...r)=>{let a=n;return t(n,i?{eventName:e,object:a}:{eventName:e,object:a,args:r})}),o=d.get(this);return o===void 0&&d.set(this,o=new Set),o.add(a),u+a}if(r!==null)return declaredConnect(this,r,e,t);let listener=e=>{let n=e.accumulator;if(n===void 0){t(this,e);return}n.stopped||n.collect(t(this,e))};return pureConnect(this,e,listener)}disconnect(e){if(e>=u){let t=e-u;if(d.get(this)?.delete(t)!==!0)throw unknownHandler(this,e);resolvedFor(this.constructor).giDisconnect.call(this,t);return}declaredDisconnect(this,e)||pureDisconnect(this,e)}emit(e,...t){let n=resolvedFor(this.constructor),r=giKeyOf(n,e);if(r!==null){n.routeD?n.giEmit.call(this,r,...t):emitDeclared(this,r,t);return}throw Error(`No signal '${e}' on object '${this.constructor.name}'. emit() is GObject's and takes a declared signal or a declared property's notify::<prop>; to dispatch a NativeScript event use notify({ eventName: '${e}', object: this }).`)}get_property(e){return n(this,t(e))}set_property(e,n){r(this,t(e),n)}}return declare(WithSignals,a,{connect:WithSignals.prototype.connect,disconnect:WithSignals.prototype.disconnect,emit:WithSignals.prototype.emit}),WithSignals}function withProperties(e,t){class WithProperties extends e{static emittedSignals=declaredEmissionsOf(t)}return declare(WithProperties,t,void 0),WithProperties}function valuesOf(e){let t=f.get(e);return t===void 0&&f.set(e,t=new Map),t}function defaultValueOf(e){return e.kind===`object`?null:e.default===void 0?e.kind===`string`?``:e.kind===`boolean`?!1:0:e.default}export{emittedSignalsOf,readDeclaredValue,withProperties,withSignals};
1
+ import"../_virtual/_rolldown/runtime.js";import{ENGINE_TARGET as e}from"../engine-target.js";import{camelProperty as t,readGtkProperty as n,writeGtkProperty as r}from"./shadowed-properties.js";import{WIDGET_SIGNALS as i,watchMapping as a}from"./widget-mapping.js";import{withGtkWidgetLayout as o}from"./widget-layout.js";import{engineForTarget as s}from"@gjsify/adwaita-core";function coerceDeclared(e,t,n,r){return t.normalize===void 0?readDeclaredValue(e,t.kind,n):t.normalize(n,r)}function isDeclaredChange(e,t,n,r,i){return e.changed===void 0?n!==t:e.changed(t,n,r,i)}function readDeclaredValue(e,t,n){if(typeof n!=`string`||t===`string`)return n;let r=n.trim();if(t===`object`)throw TypeError(`Property '${e}' holds an object; '${n}' is a string.`);if(t===`boolean`){let t=r.toLowerCase();if(t===`true`)return!0;if(t===`false`)return!1;throw TypeError(`Property '${e}' is a boolean; '${n}' is neither 'true' nor 'false'.`)}let i=r===``?NaN:Number(r);if(!Number.isFinite(i))throw TypeError(`Property '${e}' is a number; '${n}' is not one.`);return i}const c=new WeakMap;let l=1;const u=1073741824,d=new WeakMap,f=new WeakMap;function unknownHandler(e,t){return TypeError(`${e.constructor.name} has no handler with id ${t}. connect() hands out each id once and disconnect() takes it once; a second disconnect, or an id another widget returned, is refused here rather than left as a silent no-op.`)}const p=new WeakMap;function pureConnect(e,t,n){let r=l++,o=c.get(e);o===void 0&&(o=new Map,c.set(e,o));let s=i.includes(t)?a(e):void 0;return o.set(r,{eventName:t,listener:n,unwatch:s}),e.addEventListener(t,n),r}function pureDisconnect(e,t){let n=c.get(e)?.get(t);if(n===void 0)throw unknownHandler(e,t);e.removeEventListener(n.eventName,n.listener),n.unwatch?.(),c.get(e)?.delete(t)}function declaredConnect(e,t,n,r){let i=l++,a=p.get(e);return a===void 0&&p.set(e,a=new Map),a.set(i,{key:t,eventName:n,callback:r}),i}function declaredDisconnect(e,t){return p.get(e)?.delete(t)===!0}function emitDeclared(e,t,n){let r=p.get(e);if(r===void 0)return;let i=t.startsWith(`notify::`),a=[...r];for(let[o,s]of a){if(s.key!==t||r.get(o)!==s)continue;let a=i?{eventName:s.eventName,object:e}:{eventName:s.eventName,object:e,args:n};try{s.callback(e,a)}catch(t){console.error(`[${e.constructor.name}] unhandled exception in a '${s.eventName}' handler:`,t)}}}function refuseDeclaredEvent(e,t,n){let r=giKeyOf(resolvedFor(e.constructor),t);if(r===null)return;let i=r.startsWith(`notify::`),a=i?`a declared property's notification`:`a declared signal`,o=n===`notify`?i?`write the property, or emit it with notify('${r.slice(8)}')`:`emit it with emit('${r}', …)`:`subscribe with connect('${t}', (self, data) => …), whose id disconnect() takes`;throw TypeError(`${e.constructor.name}.${n}('${t}'): '${r}' is ${a} and GObject owns it — ${o}. On Android the emission belongs to the GObject and no NativeScript listener can see it, so ${n} would work off-device and be silent on it.`)}function spellingsOf(e){return[...new Set([e,e.replace(/-/g,`_`),t(e)])]}function emittedSignalsOf(e){let t=[];for(let n=e;typeof n==`function`;n=Object.getPrototypeOf(n))t.unshift(n);let n=new Set;for(let e of t)if(Object.hasOwn(e,`emittedSignals`))for(let t of e.emittedSignals)n.add(t);return[...n]}const m=new WeakMap,h=new WeakSet,g=new WeakSet,_=new WeakMap;function declarationsOf(e){let t=[];for(let n=e;typeof n==`function`;n=Object.getPrototypeOf(n)){let e=m.get(n);e!==void 0&&t.unshift(e)}return t}function resolvedFor(e){let t=_.get(e);if(t!==void 0)return t;let n=new Map,r=new Set,i={canonicalOf:n,declaredSignals:r,routeD:!1,giConnect:void 0,giDisconnect:void 0,giEmit:void 0},a=i;for(let t of declarationsOf(e)){for(let[e,r]of t.canonicalOf)n.set(e,r);for(let e of t.declaredSignals)r.add(e);t.routeD&&(a.routeD=!0),t.giConnect!==void 0&&(a.giConnect=t.giConnect),t.giDisconnect!==void 0&&(a.giDisconnect=t.giDisconnect),t.giEmit!==void 0&&(a.giEmit=t.giEmit)}return _.set(e,i),i}function giKeyOf(e,t){if(e.declaredSignals.has(t))return t;if(!t.startsWith(`notify::`))return null;let n=e.canonicalOf.get(t.slice(8));return n===void 0?null:`notify::${n}`}function declare(e,t,n){let r=new Map;for(let e of Object.keys(t?.Properties??{}))for(let t of spellingsOf(e))r.set(t,e);let i={meta:t,klass:e,prototype:e.prototype,canonicalOf:r,declaredSignals:new Set(Object.keys(t?.Signals??{})),routers:n,realized:!1,routeD:!1};return m.set(e,i),i}function declaredEmissionsOf(e){return[...Object.keys(e?.Signals??{}),...Object.keys(e?.Properties??{}).map(e=>`notify::${e}`)]}function realizeChain(e){if(!h.has(e)){h.add(e);for(let t of declarationsOf(e))realize(t)}}function realize(t){if(t.realized||(t.realized=!0,t.meta===void 0))return;let n=s(e);if(n?.supportsForeignParentClasses===!0){registerRouteD(t,n.registerForeignClass.bind(n));return}installPureJsProperties(t)}function registerRouteD(e,t){let{meta:n,prototype:r,routers:i}=e;if(i!==void 0&&(delete r.connect,delete r.disconnect,delete r.emit,delete r.notify),t(e.klass,n),wrapRouteDAccessors(e),i!==void 0){if(e.giConnect=r.connect,e.giDisconnect=r.disconnect,e.giEmit=r.emit,e.giConnect===void 0||e.giDisconnect===void 0||e.giEmit===void 0)throw Error(`Registering '${n.GTypeName}' over its NativeScript base installed no connect/disconnect/emit, so the widget would answer neither GObject nor this port. ADR 0105 refuses a silent fallback here: the subset is reachable only by calling usePureJsGObjectEngine() from '@gjsify/adwaita-core' before the port loads.`);for(let[e,t]of Object.entries(i))Object.defineProperty(r,e,{configurable:!0,writable:!0,enumerable:!1,value:t});refuseDeclaredNotifyPayload(r,r.notify)}e.routeD=!0}function refuseDeclaredNotifyPayload(e,t){let n=function notify(e,...n){if(typeof e==`object`&&e){let{eventName:t}=e;typeof t==`string`&&refuseDeclaredEvent(this,t,`notify`)}return t.call(this,e,...n)};g.add(n),Object.defineProperty(e,"notify",{configurable:!0,writable:!0,enumerable:!1,value:n})}function wrapRouteDAccessors(e){let{meta:t,prototype:n}=e;for(let[e,r]of Object.entries(t.Properties??{}))if(!(r.kind===`string`&&r.normalize===void 0))for(let i of spellingsOf(e)){let a=Object.getOwnPropertyDescriptor(n,i);if(a?.set===void 0)throw Error(`Registering '${t.GTypeName}' installed no setter for '${i}', so a string from XML would reach the GObject uncoerced. The host chain probably owns that name (see the class's \$foreignSkipped); rename the property.`);let o=a.set;Object.defineProperty(n,i,{...a,set(t){o.call(this,coerceDeclared(e,r,t,this))}})}}function installPureJsProperties(e){let{meta:t,prototype:n}=e;for(let[e,r]of Object.entries(t.Properties??{})){let t=defaultValueOf(r);for(let i of spellingsOf(e))i in n||Object.defineProperty(n,i,{configurable:!0,enumerable:!1,get(){let n=valuesOf(this);return n.has(e)||n.set(e,t),n.get(e)},set(t){let n=coerceDeclared(e,r,t,this),i=valuesOf(this);i.has(e)&&!isDeclaredChange(r,n,i.get(e),t,this)||(i.set(e,n),emitDeclared(this,`notify::${e}`,[]),r.afterNotify?.(this))}})}installPureNotify(e)}function installPureNotify(e){let{prototype:t}=e,n=t.notify;if(g.has(n))return;let r=function notify(e,...t){if(typeof e!=`string`){if(typeof e==`object`&&e){let{eventName:t}=e;typeof t==`string`&&refuseDeclaredEvent(this,t,`notify`)}return n.call(this,e,...t)}let{canonicalOf:r}=resolvedFor(this.constructor),i=r.get(e);if(i===void 0)throw TypeError(`${this.constructor.name} has no property '${e}' to notify. The declared ones are ${[...r.keys()].join(`, `)||`(none)`}; a NativeScript event is notified with its payload object, not with a name.`);emitDeclared(this,`notify::${i}`,[])};g.add(r),Object.defineProperty(t,"notify",{configurable:!0,writable:!0,enumerable:!1,value:r})}function withSignals(e,a){class WithSignals extends o(e){static emittedSignals=[...i,...declaredEmissionsOf(a)];constructor(...e){super(...e),realizeChain(new.target)}addEventListener(e,t,n,r){refuseDeclaredEvent(this,e,`addEventListener`),super.addEventListener(e,t,n,r)}removeEventListener(e,t,n){refuseDeclaredEvent(this,e,`removeEventListener`),super.removeEventListener(e,t,n)}connect(e,t){let n=resolvedFor(this.constructor),r=giKeyOf(n,e);if(n.routeD&&r!==null){let i=r.startsWith(`notify::`),a=n.giConnect.call(this,r,(n,...r)=>{let a=n;return t(n,i?{eventName:e,object:a}:{eventName:e,object:a,args:r})}),o=d.get(this);return o===void 0&&d.set(this,o=new Set),o.add(a),u+a}if(r!==null)return declaredConnect(this,r,e,t);let listener=e=>{let n=e.accumulator;if(n===void 0){t(this,e);return}n.stopped||n.collect(t(this,e))};return pureConnect(this,e,listener)}disconnect(e){if(e>=u){let t=e-u;if(d.get(this)?.delete(t)!==!0)throw unknownHandler(this,e);resolvedFor(this.constructor).giDisconnect.call(this,t);return}declaredDisconnect(this,e)||pureDisconnect(this,e)}emit(e,...t){let n=resolvedFor(this.constructor),r=giKeyOf(n,e);if(r!==null){n.routeD?n.giEmit.call(this,r,...t):emitDeclared(this,r,t);return}throw Error(`No signal '${e}' on object '${this.constructor.name}'. emit() is GObject's and takes a declared signal or a declared property's notify::<prop>; to dispatch a NativeScript event use notify({ eventName: '${e}', object: this }).`)}get_property(e){return n(this,t(e))}set_property(e,n){r(this,t(e),n)}}return declare(WithSignals,a,{connect:WithSignals.prototype.connect,disconnect:WithSignals.prototype.disconnect,emit:WithSignals.prototype.emit}),WithSignals}function withProperties(e,t){class WithProperties extends e{static emittedSignals=declaredEmissionsOf(t)}return declare(WithProperties,t,void 0),WithProperties}function valuesOf(e){let t=f.get(e);return t===void 0&&f.set(e,t=new Map),t}function defaultValueOf(e){return e.kind===`object`?null:e.default===void 0?e.kind===`string`?``:e.kind===`boolean`?!1:0:e.default}export{emittedSignalsOf,readDeclaredValue,withProperties,withSignals};
@@ -64,8 +64,10 @@ export interface BuildOptions {
64
64
  template?: TemplateScope;
65
65
  /**
66
66
  * Translates a string the `.blp` marked with `_()` or `C_()`, as GtkBuilder does with its
67
- * gettext domain. Called with the authored text and the `C_()` context, if any. Without it a
68
- * marked string stays as authored, which is English: the marking is carried, not acted on.
67
+ * gettext domain. Called with the authored text and the `C_()` context, if any. Without it the
68
+ * translator the platform registered answers (`registerDefaultTranslate` — on Android the real
69
+ * opt-in installs GLib's default-domain gettext, as GtkBuilder uses when no domain is set), and
70
+ * with neither a marked string stays as authored, which is English: carried, not acted on.
69
71
  * Covers properties, the labels of `responses`, `strings [ ]` items and breakpoint setters.
70
72
  */
71
73
  translate?: (text: string, context?: string) => string;
@@ -0,0 +1 @@
1
+ export declare const AdwDefaultTranslateNsTest: () => Promise<void>;
@@ -0,0 +1 @@
1
+ export declare const GtkLabelMarkupNsTest: () => Promise<void>;
@@ -53,6 +53,8 @@ export interface TouchGestureEventData extends EventData {
53
53
  export declare class Style extends Observable {
54
54
  #private;
55
55
  direction?: 'ltr' | 'rtl' | null;
56
+ /** In DIPs, and unset until written: `fontSizeProperty` carries no `defaultValue`. */
57
+ fontSize?: number;
56
58
  readonly viewRef: WeakRef<View>;
57
59
  constructor(view: View);
58
60
  get visibility(): string;
@@ -280,8 +282,96 @@ export declare class GridLayout extends LayoutBase {
280
282
  static setColumnSpan(view: View, value: number): void;
281
283
  static setRowSpan(view: View, value: number): void;
282
284
  }
285
+ /**
286
+ * A `Span`'s style — NOT a {@link View}'s {@link Style}.
287
+ *
288
+ * `Span extends ViewBase` upstream, so it has none of `View`'s shortcuts and carries only
289
+ * what a span can be given. Every member is unset until written, which is what the font
290
+ * properties answer on a device: `fontSizeProperty` and `fontFamilyProperty` are registered
291
+ * with no `defaultValue` (`ui/styling/style-properties.ts`).
292
+ */
293
+ export declare class SpanStyle extends Observable {
294
+ fontFamily: string | undefined;
295
+ fontSize: number | undefined;
296
+ fontStyle: string | undefined;
297
+ fontWeight: string | undefined;
298
+ textDecoration: string | undefined;
299
+ verticalAlignment: string | undefined;
300
+ }
301
+ /**
302
+ * One styled stretch of a {@link FormattedString}.
303
+ *
304
+ * The font and decoration members are ACCESSORS OVER `style`, as `ui/text-base/span.ts`
305
+ * has them — a double that made them own fields could not report a widget that wrote one
306
+ * and expected the other to see it.
307
+ */
308
+ export declare class Span extends Observable {
309
+ static readonly linkTapEvent = "linkTap";
310
+ readonly _style: SpanStyle;
311
+ get style(): SpanStyle;
312
+ /** NativeScript unescapes the two whitespace spellings a markup file can carry. */
313
+ private _text;
314
+ get text(): string;
315
+ set text(value: string);
316
+ get fontFamily(): string | undefined;
317
+ set fontFamily(value: string | undefined);
318
+ get fontSize(): number | undefined;
319
+ set fontSize(value: number | undefined);
320
+ get fontStyle(): string | undefined;
321
+ set fontStyle(value: string | undefined);
322
+ get fontWeight(): string | undefined;
323
+ set fontWeight(value: string | undefined);
324
+ get textDecoration(): string | undefined;
325
+ set textDecoration(value: string | undefined);
326
+ /**
327
+ * DERIVED, never written — upstream flips it from `addEventListener` /
328
+ * `removeEventListener` through `_setTappable(this.hasListeners(Span.linkTapEvent))`,
329
+ * and `setSpanModifiers` attaches the native `ClickableSpan` only for a tappable span.
330
+ * So subscribing IS what makes a span a link, and this reads the listeners rather than
331
+ * a flag a caller could set without one.
332
+ */
333
+ get tappable(): boolean;
334
+ }
335
+ /**
336
+ * The `ObservableArray<Span>` behind {@link FormattedString.spans}, as the four members
337
+ * that collection really offers.
338
+ *
339
+ * NOT A PLAIN ARRAY, and a double that used one would be the easier lie: `ObservableArray`
340
+ * reads by `getItem(pos)` and has no index access at all, so `spans[0]` is `undefined` on a
341
+ * device. A spec written against an array would pass here and read nothing there.
342
+ */
343
+ export declare class SpanList {
344
+ private readonly _items;
345
+ get length(): number;
346
+ push(span: Span): number;
347
+ /** A negative `pos` counts from the end, as upstream's does. */
348
+ getItem(pos: number): Span;
349
+ [Symbol.iterator](): Generator<Span, void, unknown>;
350
+ }
351
+ /** The rich-text value of a {@link Label} — a FLAT list of spans, no nesting. */
352
+ export declare class FormattedString extends Observable {
353
+ readonly spans: SpanList;
354
+ /** `formatted-string.ts`: the span texts concatenated, nothing between them. */
355
+ toString(): string;
356
+ }
283
357
  export declare class Label extends View {
284
- text: string;
358
+ private _text;
359
+ private _formattedText;
360
+ /**
361
+ * A write is a NO-OP while {@link formattedText} is set, as on a device:
362
+ * `[textProperty.setNative]` returns early when the label carries rich text
363
+ * (`ui/text-base/index.android.ts:192-195`), so the spans are what shows and this
364
+ * property is whatever the spans last said.
365
+ */
366
+ get text(): string;
367
+ set text(value: string);
368
+ /**
369
+ * Unset until something writes it — `formattedTextProperty` carries no `defaultValue`
370
+ * (`ui/text-base/text-base-common.ts:194`), so a label that was never given rich text
371
+ * reads `undefined`, not `null`.
372
+ */
373
+ get formattedText(): FormattedString | null | undefined;
374
+ set formattedText(value: FormattedString | null | undefined);
285
375
  textWrap: boolean;
286
376
  textAlignment: string;
287
377
  textOverflow: string;
@@ -84,8 +84,8 @@ export declare class AdwBanner extends AdwBanner_base {
84
84
  * Whether {@link title} is Pango markup. Defaults to TRUE, as in libadwaita
85
85
  * (:422-425).
86
86
  *
87
- * NS has no inline-markup layer, so markup is reduced to its plain text —
88
- * closer to what GTK paints than the raw tags would be.
87
+ * Markup is reduced to its plain text here — closer to what GTK paints than the raw
88
+ * tags would be, and deliberately not the drawn path `Gtk.Label` takes: see the header.
89
89
  */
90
90
  get useMarkup(): boolean;
91
91
  set useMarkup(value: boolean | string);
@@ -1,10 +1,12 @@
1
- import { Label } from '@nativescript/core';
1
+ import { Label, type EventData } from '@nativescript/core';
2
2
  import { type LabelEllipsizeMode, type LabelJustification } from '@gjsify/adwaita-core';
3
3
  import { type ConstructProps } from './construct-props.js';
4
+ /** Event name emitted when a link in the markup is tapped, before it is opened. */
5
+ export declare const ACTIVATE_LINK = "activate-link";
4
6
  declare const GtkLabel_base: ((abstract new (...args: any[]) => {
5
- addEventListener(eventName: string, callback: (data: import("@nativescript/core").EventData) => void, thisArg?: unknown, once?: boolean): void;
6
- removeEventListener(eventName: string, callback?: (data: import("@nativescript/core").EventData) => void, thisArg?: unknown): void;
7
- connect(eventName: string, callback: (self: /*elided*/ any, data: import("@nativescript/core").EventData) => unknown): number;
7
+ addEventListener(eventName: string, callback: (data: EventData) => void, thisArg?: unknown, once?: boolean): void;
8
+ removeEventListener(eventName: string, callback?: (data: EventData) => void, thisArg?: unknown): void;
9
+ connect(eventName: string, callback: (self: /*elided*/ any, data: EventData) => unknown): number;
8
10
  disconnect(handlerId: number): void;
9
11
  emit(eventName: string, ...args: unknown[]): void;
10
12
  get_property(name: string): unknown;
@@ -59,7 +61,7 @@ declare const GtkLabel_base: ((abstract new (...args: any[]) => {
59
61
  set_focus_on_click(focusOnClick: boolean): void;
60
62
  grab_focus(): boolean;
61
63
  _emit(eventName: string): void;
62
- notify<T extends import("@nativescript/core").EventData>(data: T): void;
64
+ notify<T extends EventData>(data: T): void;
63
65
  notifyPropertyChange(name: string, value: unknown, oldValue?: unknown): void;
64
66
  set(name: string, value: unknown): void;
65
67
  get(name: string): unknown;
@@ -78,6 +80,8 @@ export declare class GtkLabel extends GtkLabel_base {
78
80
  private _xalignWritten;
79
81
  private _justify;
80
82
  private _selectable;
83
+ /** The `<a href>` of the last render — kept so a re-parse inherits `visited` by URI. */
84
+ private _links;
81
85
  constructor(props?: ConstructProps<GtkLabel>);
82
86
  /**
83
87
  * `Gtk.Label:label` — the text, as written, before markup and the mnemonic marker are
@@ -88,9 +92,8 @@ export declare class GtkLabel extends GtkLabel_base {
88
92
  /**
89
93
  * `Gtk.Label:use-markup` — whether {@link label} is Pango markup.
90
94
  *
91
- * TRUE means the markup is REDUCED to its plain text here, not rendered: see the
92
- * header. FALSE, the default, shows the string literally, so a `<` in a sentence stays
93
- * a `<`.
95
+ * TRUE means the markup is DRAWN, as styled `Span`s: see the header. FALSE, the
96
+ * default, shows the string literally, so a `<` in a sentence stays a `<`.
94
97
  */
95
98
  get useMarkup(): boolean;
96
99
  set useMarkup(raw: boolean | string);
@@ -201,5 +204,23 @@ export declare class GtkLabel extends GtkLabel_base {
201
204
  set_css_classes(names: readonly string[]): void;
202
205
  private _setClasses;
203
206
  private _render;
207
+ /**
208
+ * `emit_activate_link` for the link at `index`: the user's handlers under GTK's handled
209
+ * accumulator, then — only if none handled it — the default launch.
210
+ *
211
+ * The link becomes VISITED whenever the emission was handled, INCLUDING by a handler
212
+ * that cancelled the launch (gtklabel.c:2053, `if (handled && !link->visited)`): GTK
213
+ * reads a TRUE as "this link has been followed, my way". `Gtk.LinkButton` differs — it
214
+ * sets `visited` inside its own default handler, which a cancelling handler skips — and
215
+ * the two are not the same rule.
216
+ */
217
+ private _activateLink;
218
+ /**
219
+ * The launcher call, on its own method so a caller (or a spec) can stand in for the
220
+ * app the host would have opened — the same door `Adw.AboutDialog` uses on this
221
+ * surface, because the two must not disagree about what following a link does. A URI
222
+ * the host cannot launch is dropped, as a failed launch is.
223
+ */
224
+ protected launch(uri: string): void;
204
225
  }
205
226
  export {};
@@ -0,0 +1,43 @@
1
+ import { FormattedString, Span } from '@nativescript/core';
2
+ import { type LabelMarkupRender, type LabelMarkupRun } from '@gjsify/adwaita-core';
3
+ /**
4
+ * One run as one `Span`.
5
+ *
6
+ * The `<span>` attributes are written FIRST and the pango tags after, so a tag wins a
7
+ * collision — the same declared order the web port states, for the same reason: the runs
8
+ * record the tags as booleans and the `<span>`s as a separate stack, so neither renderer can
9
+ * know which element was inner.
10
+ *
11
+ * `mnemonics` is `use-underline`, applied to the run's TEXT and not to the markup string:
12
+ * `gtk_label_set_markup_with_mnemonic` parses first and strips the marker out of the result,
13
+ * so an `_` inside a tag's attributes is not a mnemonic.
14
+ */
15
+ export declare function labelMarkupSpan(run: LabelMarkupRun, mnemonics: boolean, base?: number): Span;
16
+ /**
17
+ * Whether `render` needs the `FormattedString` path at all.
18
+ *
19
+ * A label whose markup is only `<markup>` around plain prose draws IDENTICALLY from
20
+ * `text`, and taking the rich path for it would move every such label onto a different
21
+ * native mechanism (an Android `SpannableStringBuilder` rather than a plain `CharSequence`)
22
+ * for no visible difference. So the predicate is "any run carries style, or there is a
23
+ * link", and a markup label that needs neither keeps the path it has always had.
24
+ *
25
+ * LOCAL TO THIS MODULE on purpose: it is a NativeScript write-path question, and a core
26
+ * helper for it would be a core function no renderer suite drives.
27
+ */
28
+ export declare function labelMarkupNeedsSpans(render: LabelMarkupRender): boolean;
29
+ /**
30
+ * `render` as a `FormattedString`, with every run inside an `<a href>` subscribed to
31
+ * `onLinkTap`.
32
+ *
33
+ * SUBSCRIBING IS WHAT MAKES A SPAN TAPPABLE: `tappable` is derived from
34
+ * `hasListeners(Span.linkTapEvent)` (`Span._setTappable`) and `setSpanModifiers` attaches
35
+ * the native `ClickableSpan` only for a tappable span, so the listener is not an extra on
36
+ * top of the link — it IS the link.
37
+ *
38
+ * A LINK WITH NO TEXT HAS NO SPAN, and cannot: `createSpannableStringBuilder` skips any
39
+ * span whose text is empty (`spanLength > 0`), so an empty `Span` would not reach the
40
+ * native text at all. The web port keeps the empty `<a>`; here the link survives only in
41
+ * the render's `links`, which is what answers `has-tooltip` and the `link` style class.
42
+ */
43
+ export declare function labelMarkupFormattedString(render: LabelMarkupRender, mnemonics: boolean, base: number | undefined, onLinkTap: (index: number) => void): FormattedString;
@@ -21,6 +21,35 @@ type Declared<P> = P & {
21
21
  * here, since a write that resolves to the value already held is not a change.
22
22
  */
23
23
  readonly normalize?: (value: unknown, self: object) => unknown;
24
+ /**
25
+ * Replaces the equal-write check for this property on the PURE leg: `written` is the value as
26
+ * the caller spelled it, `next` what {@link Declared.normalize} made of it, `held` what the
27
+ * store holds — and the answer decides whether the write notifies at all.
28
+ *
29
+ * WHY. A C setter guards on `g_strcmp0 (value, adw_…_get_…(self))`, against the GETTER
30
+ * READBACK rather than the stored field. Where storage normalises, the two differ and the
31
+ * guard can never fire: `GtkImage` turns an empty icon name into "no icon", so writing `''`
32
+ * to a button that already reads back `null` notifies EVERY time (measured on GJS 1.88.1 /
33
+ * libadwaita 1.9.4). Comparing the held value says the opposite, and only the property whose
34
+ * `normalize` collapses distinct writes onto one held value can tell the difference.
35
+ *
36
+ * The real leg has no use for it — there the guard IS the C one.
37
+ */
38
+ readonly changed?: (next: unknown, held: unknown, written: unknown, self: object) => boolean;
39
+ /**
40
+ * The rest of the C setter, on the PURE leg: runs once this property's own `notify::<name>`
41
+ * is out, so a setter that also drives OTHER properties emits in the order C does.
42
+ *
43
+ * WHY IT IS NOT `normalize`. A normalizer runs AHEAD of the store, so a cross-write made
44
+ * there notifies before the property that caused it. `Adw.SplitButton` measures the other way
45
+ * round — `label = 'Open'` on an icon button emits `label` first and the slots it clears
46
+ * after — and the two cannot both be one hook. The SHAPE of a value still belongs to
47
+ * `normalize`; what the write does to its siblings belongs here.
48
+ *
49
+ * Not run on the real leg, where the C setter does this itself: a second pass would write the
50
+ * cleared slot a second time, and C answers a redundant `null` with a CRITICAL.
51
+ */
52
+ readonly afterNotify?: (self: object) => void;
24
53
  };
25
54
  /** A declared property of any kind, with its optional {@link Declared.normalize}. */
26
55
  export type DeclaredProperty = Declared<ForeignScalarProperty> | Declared<ForeignObjectProperty>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjsify/adwaita-nativescript",
3
- "version": "0.64.12",
3
+ "version": "0.64.13-next.283",
4
4
  "description": "Native Adwaita widgets for the NativeScript runtime — real NativeScript components (StackLayout/GridLayout/Switch/Label) styled like Libadwaita, not a webview",
5
5
  "type": "module",
6
6
  "module": "lib/esm/index.js",
@@ -73,15 +73,15 @@
73
73
  "design-system"
74
74
  ],
75
75
  "dependencies": {
76
- "@gjsify/adwaita-core": "^0.64.12",
77
- "@gjsify/adwaita-fonts": "^0.64.12",
78
- "@gjsify/adwaita-icons": "^0.64.12",
79
- "@gjsify/canvas2d-core": "^0.64.12",
80
- "@gjsify/native-platform": "^0.64.12"
76
+ "@gjsify/adwaita-core": "0.64.13-next.283",
77
+ "@gjsify/adwaita-fonts": "0.64.13-next.283",
78
+ "@gjsify/adwaita-icons": "0.64.13-next.283",
79
+ "@gjsify/canvas2d-core": "0.64.13-next.283",
80
+ "@gjsify/native-platform": "0.64.13-next.283"
81
81
  },
82
82
  "peerDependencies": {
83
83
  "@nativescript/core": "*",
84
- "@gjsify/app-settings": "^0.64.12"
84
+ "@gjsify/app-settings": "0.64.13-next.283"
85
85
  },
86
86
  "peerDependenciesMeta": {
87
87
  "@nativescript/core": {
@@ -92,11 +92,11 @@
92
92
  }
93
93
  },
94
94
  "devDependencies": {
95
- "@gjsify/app-settings": "^0.64.12",
96
- "@gjsify/blueprint": "^0.64.12",
97
- "@gjsify/cli": "^0.64.12",
98
- "@gjsify/unit": "^0.64.12",
99
- "@gjsify/vite-plugin-blueprint": "^0.64.12",
95
+ "@gjsify/app-settings": "0.64.13-next.283",
96
+ "@gjsify/blueprint": "0.64.13-next.283",
97
+ "@gjsify/cli": "0.64.13-next.283",
98
+ "@gjsify/unit": "0.64.13-next.283",
99
+ "@gjsify/vite-plugin-blueprint": "0.64.13-next.283",
100
100
  "@types/node": "^25.9.2",
101
101
  "typescript": "^6.0.3"
102
102
  },
@@ -125,5 +125,6 @@
125
125
  "bugs": {
126
126
  "url": "https://github.com/gjsify/gjsify/issues"
127
127
  },
128
- "homepage": "https://github.com/gjsify/gjsify/tree/main/packages/nativescript-bridge/adwaita#readme"
128
+ "homepage": "https://github.com/gjsify/gjsify/tree/main/packages/nativescript-bridge/adwaita#readme",
129
+ "gitHead": "05fae97125a374e84bf57c2d2d086fb53523f205"
129
130
  }
@@ -173,6 +173,8 @@ function unloadView(view: View): void {
173
173
  */
174
174
  export class Style extends Observable {
175
175
  direction?: 'ltr' | 'rtl' | null = null;
176
+ /** In DIPs, and unset until written: `fontSizeProperty` carries no `defaultValue`. */
177
+ fontSize?: number;
176
178
  readonly viewRef: WeakRef<View>;
177
179
  #visibility = 'visible';
178
180
 
@@ -663,8 +665,181 @@ export class GridLayout extends LayoutBase {
663
665
  }
664
666
  }
665
667
 
668
+ /**
669
+ * A `Span`'s style — NOT a {@link View}'s {@link Style}.
670
+ *
671
+ * `Span extends ViewBase` upstream, so it has none of `View`'s shortcuts and carries only
672
+ * what a span can be given. Every member is unset until written, which is what the font
673
+ * properties answer on a device: `fontSizeProperty` and `fontFamilyProperty` are registered
674
+ * with no `defaultValue` (`ui/styling/style-properties.ts`).
675
+ */
676
+ export class SpanStyle extends Observable {
677
+ fontFamily: string | undefined;
678
+ fontSize: number | undefined;
679
+ fontStyle: string | undefined;
680
+ fontWeight: string | undefined;
681
+ textDecoration: string | undefined;
682
+ verticalAlignment: string | undefined;
683
+ }
684
+
685
+ /**
686
+ * One styled stretch of a {@link FormattedString}.
687
+ *
688
+ * The font and decoration members are ACCESSORS OVER `style`, as `ui/text-base/span.ts`
689
+ * has them — a double that made them own fields could not report a widget that wrote one
690
+ * and expected the other to see it.
691
+ */
692
+ export class Span extends Observable {
693
+ static readonly linkTapEvent = 'linkTap';
694
+
695
+ readonly _style: SpanStyle = new SpanStyle();
696
+
697
+ get style(): SpanStyle {
698
+ return this._style;
699
+ }
700
+
701
+ /** NativeScript unescapes the two whitespace spellings a markup file can carry. */
702
+ private _text = '';
703
+
704
+ get text(): string {
705
+ return this._text;
706
+ }
707
+
708
+ set text(value: string) {
709
+ this._text = String(value ?? '')
710
+ .replace(/\\n/g, '\n')
711
+ .replace(/\\t/g, '\t');
712
+ }
713
+
714
+ get fontFamily(): string | undefined {
715
+ return this._style.fontFamily;
716
+ }
717
+
718
+ set fontFamily(value: string | undefined) {
719
+ this._style.fontFamily = value;
720
+ }
721
+
722
+ get fontSize(): number | undefined {
723
+ return this._style.fontSize;
724
+ }
725
+
726
+ set fontSize(value: number | undefined) {
727
+ this._style.fontSize = value;
728
+ }
729
+
730
+ get fontStyle(): string | undefined {
731
+ return this._style.fontStyle;
732
+ }
733
+
734
+ set fontStyle(value: string | undefined) {
735
+ this._style.fontStyle = value;
736
+ }
737
+
738
+ get fontWeight(): string | undefined {
739
+ return this._style.fontWeight;
740
+ }
741
+
742
+ set fontWeight(value: string | undefined) {
743
+ this._style.fontWeight = value;
744
+ }
745
+
746
+ get textDecoration(): string | undefined {
747
+ return this._style.textDecoration;
748
+ }
749
+
750
+ set textDecoration(value: string | undefined) {
751
+ this._style.textDecoration = value;
752
+ }
753
+
754
+ /**
755
+ * DERIVED, never written — upstream flips it from `addEventListener` /
756
+ * `removeEventListener` through `_setTappable(this.hasListeners(Span.linkTapEvent))`,
757
+ * and `setSpanModifiers` attaches the native `ClickableSpan` only for a tappable span.
758
+ * So subscribing IS what makes a span a link, and this reads the listeners rather than
759
+ * a flag a caller could set without one.
760
+ */
761
+ get tappable(): boolean {
762
+ return (listenersOf(this).get(Span.linkTapEvent)?.length ?? 0) > 0;
763
+ }
764
+ }
765
+
766
+ /**
767
+ * The `ObservableArray<Span>` behind {@link FormattedString.spans}, as the four members
768
+ * that collection really offers.
769
+ *
770
+ * NOT A PLAIN ARRAY, and a double that used one would be the easier lie: `ObservableArray`
771
+ * reads by `getItem(pos)` and has no index access at all, so `spans[0]` is `undefined` on a
772
+ * device. A spec written against an array would pass here and read nothing there.
773
+ */
774
+ export class SpanList {
775
+ private readonly _items: Span[] = [];
776
+
777
+ get length(): number {
778
+ return this._items.length;
779
+ }
780
+
781
+ push(span: Span): number {
782
+ return this._items.push(span);
783
+ }
784
+
785
+ /** A negative `pos` counts from the end, as upstream's does. */
786
+ getItem(pos: number): Span {
787
+ return this._items[pos < 0 ? this._items.length + pos : pos]!;
788
+ }
789
+
790
+ *[Symbol.iterator](): Generator<Span, void, unknown> {
791
+ yield* this._items;
792
+ }
793
+ }
794
+
795
+ /** The rich-text value of a {@link Label} — a FLAT list of spans, no nesting. */
796
+ export class FormattedString extends Observable {
797
+ readonly spans: SpanList = new SpanList();
798
+
799
+ /** `formatted-string.ts`: the span texts concatenated, nothing between them. */
800
+ toString(): string {
801
+ let text = '';
802
+ for (const span of this.spans) text += span.text;
803
+ return text;
804
+ }
805
+ }
806
+
666
807
  export class Label extends View {
667
- text = '';
808
+ private _text = '';
809
+ private _formattedText: FormattedString | null | undefined;
810
+
811
+ /**
812
+ * A write is a NO-OP while {@link formattedText} is set, as on a device:
813
+ * `[textProperty.setNative]` returns early when the label carries rich text
814
+ * (`ui/text-base/index.android.ts:192-195`), so the spans are what shows and this
815
+ * property is whatever the spans last said.
816
+ */
817
+ get text(): string {
818
+ return this._text;
819
+ }
820
+
821
+ set text(value: string) {
822
+ if (this._formattedText === null || this._formattedText === undefined) this._text = value;
823
+ }
824
+
825
+ /**
826
+ * Unset until something writes it — `formattedTextProperty` carries no `defaultValue`
827
+ * (`ui/text-base/text-base-common.ts:194`), so a label that was never given rich text
828
+ * reads `undefined`, not `null`.
829
+ */
830
+ get formattedText(): FormattedString | null | undefined {
831
+ return this._formattedText;
832
+ }
833
+
834
+ set formattedText(value: FormattedString | null | undefined) {
835
+ this._formattedText = value;
836
+ // The device re-derives the plain text from the spans on BOTH legs:
837
+ // `[formattedTextProperty.setNative]` calls
838
+ // `textProperty.nativeValueChange(this, value?.toString() ?? '')`, which is why a
839
+ // `text` written BEFORE the clear would be wiped to the empty string.
840
+ this._text = value?.toString() ?? '';
841
+ }
842
+
668
843
  textWrap = false;
669
844
  textAlignment = 'initial';
670
845
  textOverflow = 'initial';