@gjsify/adwaita-core 0.55.0 → 0.56.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
- import"../_virtual/_rolldown/runtime.js";import{authoredNodes as e}from"./shared-trees.js";const t=[`layout`,`strings`,`responses`,`page`,`extern`,`signal`,`bind`,`breakpoint`];function constructUsesOf(t){let n=[];for(let{node:r,path:i}of e(t))r.layout!==void 0&&n.push({kind:`layout`,path:i}),r.extensions?.strings!==void 0&&n.push({kind:`strings`,path:i}),r.extensions?.responses!==void 0&&n.push({kind:`responses`,path:i}),r.page!==void 0&&n.push({kind:`page`,path:i}),r.extern===!0&&n.push({kind:`extern`,path:i}),r.signals?.forEach(()=>n.push({kind:`signal`,path:i})),Object.keys(r.bindings??{}).forEach(()=>n.push({kind:`bind`,path:i})),r.breakpoints?.forEach(()=>n.push({kind:`breakpoint`,path:i}));return n}var UnsupportedConstructError=class extends Error{constructor(e,t){let n=t.map(e=>` ${e.kind} at ${e.path} — ${e.reason}`).join(`
2
- `);super(`this tree cannot be rendered by ${e}: ${t.length} construct(s) it refuses.\n${n}`),this.name=`UnsupportedConstructError`,this.renderer=e,this.refused=t}};function assertTreeConstructs(e,t,n){let r=[];for(let i of constructUsesOf(n)){let n=t[i.kind];if(n===void 0)throw Error(`${e}'s capabilities declare no row for the construct '${i.kind}'.`);n!==`implemented`&&r.push({...i,reason:n.refused})}if(r.length>0)throw new UnsupportedConstructError(e,r)}const n=[{kind:`layout`,rule:"`layout { }` places a grid child in its cell (ADR 0092); the spans default to one",tree:{tag:`GtkGrid`,children:[{tag:`GtkLabel`,id:`a`,layout:{row:0,column:0}},{tag:`GtkLabel`,id:`b`,layout:{row:1,column:1,"column-span":2}}]},shows:[{row:0,column:0,columnSpan:1},{row:1,column:1,columnSpan:2}]},{kind:`strings`,rule:"`strings [ ]` fills a combo row model in source order (ADR 0072)",tree:{tag:`AdwComboRow`,props:{title:`Colour`},children:[{tag:`GtkStringList`,slot:`model`,extensions:{strings:[{value:`Blue`},{value:`Teal`},{value:`Green`}]}}]},shows:[`Blue`,`Teal`,`Green`]},{kind:`responses`,rule:"`responses [ ]` registers each response with its appearance and enabled state (ADR 0072)",tree:{tag:`AdwAlertDialog`,props:{heading:`Delete?`},extensions:{responses:[{id:`cancel`,label:`Cancel`},{id:`delete`,label:`Delete`,appearance:`destructive`,enabled:!1}]}},shows:[{id:`cancel`,label:`Cancel`,appearance:`default`,enabled:!0},{id:`delete`,label:`Delete`,appearance:`destructive`,enabled:!1}]},{kind:`page`,rule:"a stack child with a `page` is a page with that name and title",tree:{tag:`GtkStack`,children:[{tag:`GtkLabel`,props:{label:`x`},page:{name:`first`,label:`First`}}]},shows:[{name:`first`,title:`First`}]},{kind:`extern`,rule:"an `extern` node is built by the class the application registered under its name (ADR 0093)",tree:{tag:`GtkBox`,children:[{tag:`CorpusExtern`,id:`registered`,extern:!0}]},shows:[{id:`registered`,builtByRegisteredClass:!0}]},{kind:`signal`,rule:"a handler bound with `clicked => $onClicked()` runs, from the scope the builder was handed, once per emission (ADR 0093)",tree:{tag:`GtkBox`,children:[{tag:`GtkButton`,id:`pressed`,signals:[{name:`clicked`,handler:`onClicked`}]}]},shows:[{handler:`onClicked`,calls:1}]},{kind:`bind`,rule:"a `bind` makes the target follow the source, once at creation and again on every change (ADR 0093)",tree:{tag:`GtkBox`,children:[{tag:`GtkToggleButton`,id:`source`},{tag:`GtkToggleButton`,id:`target`,bindings:{active:{source:`source`,property:`active`}}}]},shows:{afterBuild:!1,afterSourceOn:!0}},{kind:`breakpoint`,rule:"a `breakpoint` writes its setters while its condition holds for the parent, and restores them after (ADR 0093)",tree:{tag:`GtkBox`,children:[{tag:`GtkLabel`,id:`caption`,props:{label:`wide`}}],breakpoints:[{condition:`max-width: 400px`,setters:[{object:`caption`,property:`label`,value:`narrow`}]}]},shows:[`wide`,`narrow`,`wide`]}],r=[{width:800,height:600},{width:300,height:600},{width:800,height:600}],i=`CorpusExtern`;async function driveConstructVectors(e,n){let{describe:r,it:i,expect:a}=n;await r(`${e.name}: template constructs (ADR 0093)`,async()=>{await i(`declares a row for every construct kind, and no other`,()=>{a(Object.keys(e.capabilities).sort().join()).toBe([...t].sort().join())});for(let n of t){let t=e.capabilities[n],r=e.vectors.filter(e=>e.kind===n);if(t===`implemented`){await i(`${n}: a claim has at least one vector`,()=>{a(r.length>0).toBe(!0)});for(let t of r)await i(`${n} is built: ${t.rule}`,()=>{a(JSON.stringify(e.observe(t))).toBe(JSON.stringify(t.shows))});continue}for(let t of r)await i(`${n} is refused by name: ${t.rule}`,()=>{let r;try{e.observe(t)}catch(e){r=e}a(r instanceof UnsupportedConstructError).toBe(!0),a(r instanceof UnsupportedConstructError&&r.refused.some(e=>e.kind===n)).toBe(!0)})}})}export{r as BREAKPOINT_VECTOR_SIZES,t as CONSTRUCT_KINDS,n as CONSTRUCT_VECTORS,i as EXTERN_VECTOR_CLASS,UnsupportedConstructError,assertTreeConstructs,constructUsesOf,driveConstructVectors};
1
+ import"../_virtual/_rolldown/runtime.js";import{authoredNodes as e}from"./shared-trees.js";const t=[`layout`,`strings`,`responses`,`page`,`extern`,`signal`,`bind`,`breakpoint`,`sibling-object`];function constructUsesOf(e){let t=[];return[{tree:e,address:e.tag},...(e.siblings??[]).map((t,n)=>({tree:t,address:`${e.tag} > sibling[${n}] ${t.tag}`}))].forEach(({tree:e,address:n},r)=>{r>0&&t.push({kind:`sibling-object`,path:n}),collectUses(e,n,t)}),t}function collectUses(t,n,r){for(let{node:i,path:a}of e(t,n))i.layout!==void 0&&r.push({kind:`layout`,path:a}),i.extensions?.strings!==void 0&&r.push({kind:`strings`,path:a}),i.extensions?.responses!==void 0&&r.push({kind:`responses`,path:a}),i.page!==void 0&&r.push({kind:`page`,path:a}),i.extern===!0&&r.push({kind:`extern`,path:a}),i.signals?.forEach(()=>r.push({kind:`signal`,path:a})),Object.keys(i.bindings??{}).forEach(()=>r.push({kind:`bind`,path:a})),i.breakpoints?.forEach(()=>r.push({kind:`breakpoint`,path:a}))}var UnsupportedConstructError=class extends Error{constructor(e,t){let n=t.map(e=>` ${e.kind} at ${e.path} — ${e.reason}`).join(`
2
+ `);super(`this tree cannot be rendered by ${e}: ${t.length} construct(s) it refuses.\n${n}`),this.name=`UnsupportedConstructError`,this.renderer=e,this.refused=t}};function assertTreeConstructs(e,t,n){let r=[];for(let i of constructUsesOf(n)){let n=t[i.kind];if(n===void 0)throw Error(`${e}'s capabilities declare no row for the construct '${i.kind}'.`);n!==`implemented`&&r.push({...i,reason:n.refused})}if(r.length>0)throw new UnsupportedConstructError(e,r)}const n=[{kind:`layout`,rule:"`layout { }` places a grid child in its cell (ADR 0092); the spans default to one",tree:{tag:`GtkGrid`,children:[{tag:`GtkLabel`,id:`a`,layout:{row:0,column:0}},{tag:`GtkLabel`,id:`b`,layout:{row:1,column:1,"column-span":2}}]},shows:[{row:0,column:0,columnSpan:1},{row:1,column:1,columnSpan:2}]},{kind:`strings`,rule:"`strings [ ]` fills a combo row model in source order (ADR 0072)",tree:{tag:`AdwComboRow`,props:{title:`Colour`},children:[{tag:`GtkStringList`,slot:`model`,extensions:{strings:[{value:`Blue`},{value:`Teal`},{value:`Green`}]}}]},shows:[`Blue`,`Teal`,`Green`]},{kind:`responses`,rule:"`responses [ ]` registers each response with its appearance and enabled state (ADR 0072)",tree:{tag:`AdwAlertDialog`,props:{heading:`Delete?`},extensions:{responses:[{id:`cancel`,label:`Cancel`},{id:`delete`,label:`Delete`,appearance:`destructive`,enabled:!1}]}},shows:[{id:`cancel`,label:`Cancel`,appearance:`default`,enabled:!0},{id:`delete`,label:`Delete`,appearance:`destructive`,enabled:!1}]},{kind:`page`,rule:"a stack child with a `page` is a page with that name and title",tree:{tag:`GtkStack`,children:[{tag:`GtkLabel`,props:{label:`x`},page:{name:`first`,label:`First`}}]},shows:[{name:`first`,title:`First`}]},{kind:`extern`,rule:"an `extern` node is built by the class the application registered under its name (ADR 0093)",tree:{tag:`GtkBox`,children:[{tag:`CorpusExtern`,id:`registered`,extern:!0}]},shows:[{id:`registered`,builtByRegisteredClass:!0}]},{kind:`signal`,rule:"a handler bound with `clicked => $onClicked()` runs, from the scope the builder was handed, once per emission (ADR 0093)",tree:{tag:`GtkBox`,children:[{tag:`GtkButton`,id:`pressed`,signals:[{name:`clicked`,handler:`onClicked`}]}]},shows:[{handler:`onClicked`,calls:1}]},{kind:`bind`,rule:"a `bind` makes the target follow the source, once at creation and again on every change (ADR 0093)",tree:{tag:`GtkBox`,children:[{tag:`GtkToggleButton`,id:`source`},{tag:`GtkToggleButton`,id:`target`,bindings:{active:{source:`source`,property:`active`}}}]},shows:{afterBuild:!1,afterSourceOn:!0}},{kind:`breakpoint`,rule:"a `breakpoint` writes its setters while its condition holds for the parent, and restores them after (ADR 0093)",tree:{tag:`GtkBox`,children:[{tag:`GtkLabel`,id:`caption`,props:{label:`wide`}}],breakpoints:[{condition:`max-width: 400px`,setters:[{object:`caption`,property:`label`,value:`narrow`}]}]},shows:[`wide`,`narrow`,`wide`]},{kind:`sibling-object`,rule:"a `sibling` is built beside the root, outside its children, in the root's id scope, and handed back by its id (ADR 0093)",tree:{tag:`GtkBox`,children:[{tag:`GtkLabel`,id:`caption`,props:{label:`in the root`}}],siblings:[{tag:`GtkLabel`,id:`beside`,props:{label:`beside`}}],breakpoints:[{condition:`max-width: 400px`,setters:[{object:`beside`,property:`label`,value:`narrow`}]}]},shows:{insideRoot:!1,label:[`beside`,`narrow`,`beside`]}}],r=[{width:800,height:600},{width:300,height:600},{width:800,height:600}],i=`CorpusExtern`;async function driveConstructVectors(e,n){let{describe:r,it:i,expect:a}=n;await r(`${e.name}: template constructs (ADR 0093)`,async()=>{await i(`declares a row for every construct kind, and no other`,()=>{a(Object.keys(e.capabilities).sort().join()).toBe([...t].sort().join())});for(let n of t){let t=e.capabilities[n],r=e.vectors.filter(e=>e.kind===n);if(t===`implemented`){await i(`${n}: a claim has at least one vector`,()=>{a(r.length>0).toBe(!0)});for(let t of r)await i(`${n} is built: ${t.rule}`,()=>{a(JSON.stringify(e.observe(t))).toBe(JSON.stringify(t.shows))});continue}for(let t of r)await i(`${n} is refused by name: ${t.rule}`,()=>{let r;try{e.observe(t)}catch(e){r=e}a(r instanceof UnsupportedConstructError).toBe(!0),a(r instanceof UnsupportedConstructError&&r.refused.some(e=>e.kind===n)).toBe(!0)})}})}export{r as BREAKPOINT_VECTOR_SIZES,t as CONSTRUCT_KINDS,n as CONSTRUCT_VECTORS,i as EXTERN_VECTOR_CLASS,UnsupportedConstructError,assertTreeConstructs,constructUsesOf,driveConstructVectors};
@@ -1 +1 @@
1
- import"../_virtual/_rolldown/runtime.js";import{SWITCH_ROW_NOTIFY_VECTORS as e}from"./action-row.js";import{BANNER_BUTTON_TEXT_VECTORS as t,BANNER_BUTTON_VISIBLE_VECTORS as n}from"./banner.js";import{ENTRY_TEXT_LENGTH_VECTORS as r}from"./entry-row.js";const i=[`BANNER_BUTTON_TEXT_VECTORS`,`BANNER_BUTTON_VISIBLE_VECTORS`,`ENTRY_TEXT_LENGTH_VECTORS`,`SWITCH_ROW_NOTIFY_VECTORS`],a={"Adw.ShortcutLabel":"a CHOICE, not an impossibility: SHORTCUT_LABEL_VECTORS is deliberately off SHARED_TREE_TABLES, because the row this block would instantiate is unreadable on a translated host — see the header. What that costs is one-sided. `adwaita-web` drives the table from its own spec and would pass the row here too; `gtk-host` drives it from NO spec, so libadwaita's own keycap rendering is the one thing this declaration leaves unchecked. Joining it wants `it.failing(…, { when: <translated host> })` per tests/AGENTS.md rule 6 — a tolerated failure on a de_DE desk, a REAL assertion anywhere the host is untranslated, which no workflow here opts out of.","Adw.WindowTitle":`WINDOW_TITLE_VECTORS is a STEP table over a fresh widget and its rows spell their own titles; the authored "Inbox"/"3 unread messages" is no row's input, and LABEL_VISIBILITY_VECTORS keys on the label TEXT for the same reason.`},switchRowRowFor=t=>e.find(e=>t===void 0?e.steps.length===0:e.steps.length===1&&e.steps[0].op===`set-active`&&e.steps[0].active===t);function expectationsForNode(e,i){let a=e.props??{},o=[],at=(t,n,r,a)=>o.push({path:i,gtype:e.tag,table:t,observable:n,expected:r,rule:a});if(e.tag===`AdwEntryRow`){let e=typeof a.text==`string`?a.text:``,t=r.find(t=>t.text===e);t&&at(`ENTRY_TEXT_LENGTH_VECTORS`,`entry-text-length`,t.length,t.rule)}if(e.tag===`AdwSwitchRow`){let e=typeof a.active==`boolean`?a.active:void 0,t=switchRowRowFor(e);t&&at(`SWITCH_ROW_NOTIFY_VECTORS`,`switch-row-active`,t.active,t.rule)}if(e.tag===`AdwBanner`){let e=typeof a.buttonLabel==`string`?a.buttonLabel:void 0;if(e!==void 0){let r=n.find(t=>t.label===e);r&&at(`BANNER_BUTTON_VISIBLE_VECTORS`,`banner-button-visible`,r.visible,r.rule);let i=t.find(t=>t.label===e);i&&at(`BANNER_BUTTON_TEXT_VECTORS`,`banner-button-text`,i.text,i.rule)}}return o}function walk(e,t,n){n(e,t),(e.children??[]).forEach((e,r)=>walk(e,`${t} > ${e.tag}[${r}]`,n))}function authoredNodes(e){let t=[];return walk(e,e.tag,(e,n)=>t.push({node:e,path:n})),t}function authoredTags(e,t=e=>e){return authoredNodes(e).map(({node:e})=>t(e.tag))}function sharedTreePlacements(e){return authoredNodes(e).filter(({node:e})=>e.slot!==void 0).map(({node:e,path:t})=>({path:t,slot:e.slot}))}function withoutPlacements(e){let{slot:t,children:n,...r}=e;return{...r,...n===void 0?{}:{children:n.map(withoutPlacements)}}}function subjectIndexOf(e,t){return authoredNodes(e).findIndex(e=>e.path===t)}function sharedTreeExpectations(e){let t=[];return walk(e,e.tag,(e,n)=>t.push(...expectationsForNode(e,n))),t}function reachedTables(e){let t=new Set;for(let n of e)for(let e of sharedTreeExpectations(n))t.add(e.table);return[...t].sort()}export{a as SHARED_TREE_BLOCKS_WITHOUT_EXPECTATIONS,i as SHARED_TREE_TABLES,authoredNodes,authoredTags,reachedTables,sharedTreeExpectations,sharedTreePlacements,subjectIndexOf,withoutPlacements};
1
+ import"../_virtual/_rolldown/runtime.js";import{SWITCH_ROW_NOTIFY_VECTORS as e}from"./action-row.js";import{BANNER_BUTTON_TEXT_VECTORS as t,BANNER_BUTTON_VISIBLE_VECTORS as n}from"./banner.js";import{ENTRY_TEXT_LENGTH_VECTORS as r}from"./entry-row.js";const i=[`BANNER_BUTTON_TEXT_VECTORS`,`BANNER_BUTTON_VISIBLE_VECTORS`,`ENTRY_TEXT_LENGTH_VECTORS`,`SWITCH_ROW_NOTIFY_VECTORS`],a={"Adw.ShortcutLabel":"a CHOICE, not an impossibility: SHORTCUT_LABEL_VECTORS is deliberately off SHARED_TREE_TABLES, because the row this block would instantiate is unreadable on a translated host — see the header. What that costs is one-sided. `adwaita-web` drives the table from its own spec and would pass the row here too; `gtk-host` drives it from NO spec, so libadwaita's own keycap rendering is the one thing this declaration leaves unchecked. Joining it wants `it.failing(…, { when: <translated host> })` per tests/AGENTS.md rule 6 — a tolerated failure on a de_DE desk, a REAL assertion anywhere the host is untranslated, which no workflow here opts out of.","Adw.WindowTitle":`WINDOW_TITLE_VECTORS is a STEP table over a fresh widget and its rows spell their own titles; the authored "Inbox"/"3 unread messages" is no row's input, and LABEL_VISIBILITY_VECTORS keys on the label TEXT for the same reason.`},switchRowRowFor=t=>e.find(e=>t===void 0?e.steps.length===0:e.steps.length===1&&e.steps[0].op===`set-active`&&e.steps[0].active===t);function expectationsForNode(e,i){let a=e.props??{},o=[],at=(t,n,r,a)=>o.push({path:i,gtype:e.tag,table:t,observable:n,expected:r,rule:a});if(e.tag===`AdwEntryRow`){let e=typeof a.text==`string`?a.text:``,t=r.find(t=>t.text===e);t&&at(`ENTRY_TEXT_LENGTH_VECTORS`,`entry-text-length`,t.length,t.rule)}if(e.tag===`AdwSwitchRow`){let e=typeof a.active==`boolean`?a.active:void 0,t=switchRowRowFor(e);t&&at(`SWITCH_ROW_NOTIFY_VECTORS`,`switch-row-active`,t.active,t.rule)}if(e.tag===`AdwBanner`){let e=typeof a.buttonLabel==`string`?a.buttonLabel:void 0;if(e!==void 0){let r=n.find(t=>t.label===e);r&&at(`BANNER_BUTTON_VISIBLE_VECTORS`,`banner-button-visible`,r.visible,r.rule);let i=t.find(t=>t.label===e);i&&at(`BANNER_BUTTON_TEXT_VECTORS`,`banner-button-text`,i.text,i.rule)}}return o}function walk(e,t,n){n(e,t),(e.children??[]).forEach((e,r)=>walk(e,`${t} > ${e.tag}[${r}]`,n))}function authoredNodes(e,t=e.tag){let n=[];return walk(e,t,(e,t)=>n.push({node:e,path:t})),n}function authoredTags(e,t=e=>e){return authoredNodes(e).map(({node:e})=>t(e.tag))}function sharedTreePlacements(e){return authoredNodes(e).filter(({node:e})=>e.slot!==void 0).map(({node:e,path:t})=>({path:t,slot:e.slot}))}function withoutPlacements(e){let{slot:t,children:n,...r}=e;return{...r,...n===void 0?{}:{children:n.map(withoutPlacements)}}}function subjectIndexOf(e,t){return authoredNodes(e).findIndex(e=>e.path===t)}function sharedTreeExpectations(e){let t=[];return walk(e,e.tag,(e,n)=>t.push(...expectationsForNode(e,n))),t}function reachedTables(e){let t=new Set;for(let n of e)for(let e of sharedTreeExpectations(n))t.add(e.table);return[...t].sort()}export{a as SHARED_TREE_BLOCKS_WITHOUT_EXPECTATIONS,i as SHARED_TREE_TABLES,authoredNodes,authoredTags,reachedTables,sharedTreeExpectations,sharedTreePlacements,subjectIndexOf,withoutPlacements};
package/lib/esm/markup.js CHANGED
@@ -1,4 +1,4 @@
1
- import"./_virtual/_rolldown/runtime.js";import{GTK_WIDGET_MARGIN_CSS as e,attributeOf as t,hostTagOf as n,propertyOf as r}from"./tags.js";function element(e,t,n,r,i,a){let o=` `.repeat(e),s=n.map(([e,t])=>t===null?e:`${e}=${r(t)}`),c=i.length===0,l=c?a?` />`:`></${t}>`:`>`,u=`${o}<${[t,...s].join(` `)}${l}`,d=u.length<=80||s.length===0?u:[`${o}<${t}`,...s.map(e=>`${o} ${e}`),`${o}${c?a?`/>`:`></${t}>`:`>`}`].join(`
1
+ import"./_virtual/_rolldown/runtime.js";import{GTK_WIDGET_EXPAND as e,attributeOf as t,hostTagOf as n,isValueBasedBooleanAttr as r,propertyOf as i,widgetLengthStyle as a}from"./tags.js";function element(e,t,n,r,i,a){let o=` `.repeat(e),s=n.map(([e,t])=>t===null?e:`${e}=${r(t)}`),c=i.length===0,l=c?a?` />`:`></${t}>`:`>`,u=`${o}<${[t,...s].join(` `)}${l}`,d=u.length<=80||s.length===0?u:[`${o}<${t}`,...s.map(e=>`${o} ${e}`),`${o}${c?a?`/>`:`></${t}>`:`>`}`].join(`
2
2
  `);return c?d:[d,...i,`${o}</${t}>`].join(`
3
- `)}const htmlText=e=>e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`),htmlQuote=e=>{let t=e.includes(`"`)&&!e.includes(`'`)?`'`:`"`;return`${t}${e.replace(/&/g,`&amp;`).replace(t===`"`?/"/g:/'/g,t===`"`?`&quot;`:`&#39;`)}${t}`};function htmlElement(r,i){let a=[];r.id!==void 0&&a.push([`id`,r.id]);let o=[];for(let[n,i]of Object.entries(r.props??{})){typeof i==`boolean`?i&&a.push([t(n),null]):a.push([t(n),String(i)]);let r=e[t(n)];r!==void 0&&o.push(`${r}: ${Number(i)}px;`)}o.length>0&&a.push([`style`,o.join(` `)]),r.styleClasses!==void 0&&r.styleClasses.length>0&&a.push([`class`,r.styleClasses.join(` `)]);let s=r.extensions?.strings;s!==void 0&&a.push([`strings`,JSON.stringify(s.map(e=>e.value))]),r.slot!==void 0&&a.push([`slot`,r.slot]);let c=[...(r.extensions?.responses??[]).map(e=>{let t=[`id=${htmlQuote(e.id)}`];e.appearance!==void 0&&t.push(`appearance=${htmlQuote(e.appearance)}`),e.enabled===!1&&t.push(`enabled="false"`);let n=htmlText(e.label);return`${` `.repeat(i+1)}<adw-alert-response ${t.join(` `)}>${n}</adw-alert-response>`}),...(r.children??[]).map(e=>htmlElement(e,i+1))];return element(i,n(r.tag),a,htmlQuote,c,!1)}function sharedTreeHtml(e){return htmlElement(e,0)}function xmlNameOf(e){let t=/^(Adw|Gtk)([A-Z]\w*)$/.exec(e);if(t===null)throw Error(`sharedTreeNativeScriptXml: ${e} is not an Adw or Gtk class name`);return{prefix:t[1].toLowerCase(),member:t[2]}}const xmlQuote=e=>{let t=e.includes(`"`)?`'`:`"`;return`${t}${e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(t===`"`?/"/g:/'/g,t===`"`?`&quot;`:`&apos;`)}${t}`};function prefixesOf(e,t){t.add(xmlNameOf(e.tag).prefix);for(let n of e.children??[])prefixesOf(n,t);return t}function xmlElement(e,t,n){let{prefix:i,member:a}=xmlNameOf(e.tag),o=`${i}:${a}`,s=[...n];e.id!==void 0&&s.push([`id`,e.id]);for(let[t,n]of Object.entries(e.props??{}))s.push([r(t),String(n)]);e.styleClasses!==void 0&&e.styleClasses.length>0&&s.push([`styleClasses`,e.styleClasses.join(` `)]);let c=e.extensions?.strings;c!==void 0&&s.push([`strings`,JSON.stringify(c.map(e=>e.value))]);let l=(e.children??[]).map(e=>{if(e.slot===void 0)return xmlElement(e,t+1,[]);let n=` `.repeat(t+1),r=`${o}.${e.slot}`;return[`${n}<${r}>`,xmlElement(e,t+2,[]),`${n}</${r}>`].join(`
3
+ `)}const htmlText=e=>e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`),htmlQuote=e=>{let t=e.includes(`"`)&&!e.includes(`'`)?`'`:`"`;return`${t}${e.replace(/&/g,`&amp;`).replace(t===`"`?/"/g:/'/g,t===`"`?`&quot;`:`&#39;`)}${t}`};function refuseBehaviour(e,t=`sharedTreeHtml`){let n=[e.bindings&&`bindings`,e.breakpoints&&`breakpoints`].filter(Boolean);if(n.length>0)throw Error(`${t} has no markup for \`${e.tag}\`'s ${n.join(` and `)} (ADR 0093); a bound property and a breakpoint are behaviour, and a renderer has to observe them.`)}function htmlElement(i,o){refuseBehaviour(i);let s=[];i.id!==void 0&&s.push([`id`,i.id]);let c=[],l=n(i.tag);for(let[n,o]of Object.entries(i.props??{})){let i=t(n);typeof o==`boolean`?r(l,i)?s.push([i,o?`true`:`false`]):o?s.push([i,null]):e.some(e=>e===i)&&s.push([i,`false`]):s.push([i,String(o)]);let u=a(i,o);u!==void 0&&u[1]!==null&&c.push(`${u[0]}: ${u[1]};`)}c.length>0&&s.push([`style`,c.join(` `)]),i.styleClasses!==void 0&&i.styleClasses.length>0&&s.push([`class`,i.styleClasses.join(` `)]);let u=i.extensions?.strings;u!==void 0&&s.push([`strings`,JSON.stringify(u.map(e=>e.value))]),i.slot!==void 0&&s.push([`slot`,i.slot]);let d=[...(i.extensions?.responses??[]).map(e=>{let t=[`id=${htmlQuote(e.id)}`];e.appearance!==void 0&&t.push(`appearance=${htmlQuote(e.appearance)}`),e.enabled===!1&&t.push(`enabled="false"`);let n=htmlText(e.label);return`${` `.repeat(o+1)}<adw-alert-response ${t.join(` `)}>${n}</adw-alert-response>`}),...(i.children??[]).map(e=>htmlElement(e,o+1))];return element(o,n(i.tag),s,htmlQuote,d,!1)}function sharedTreeHtml(e){return htmlElement(e,0)}function xmlNameOf(e){let t=/^(Adw|Gtk)([A-Z]\w*)$/.exec(e);if(t===null)throw Error(`sharedTreeNativeScriptXml: ${e} is not an Adw or Gtk class name`);return{prefix:t[1].toLowerCase(),member:t[2]}}const xmlQuote=e=>{let t=e.includes(`"`)?`'`:`"`;return`${t}${e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(t===`"`?/"/g:/'/g,t===`"`?`&quot;`:`&apos;`)}${t}`};function prefixesOf(e,t){t.add(xmlNameOf(e.tag).prefix);for(let n of e.children??[])prefixesOf(n,t);return t}function xmlElement(e,t,n){refuseBehaviour(e,`sharedTreeNativeScriptXml`);let{prefix:r,member:a}=xmlNameOf(e.tag),o=`${r}:${a}`,s=[...n];e.id!==void 0&&s.push([`id`,e.id]);for(let[t,n]of Object.entries(e.props??{}))s.push([i(t),String(n)]);e.styleClasses!==void 0&&e.styleClasses.length>0&&s.push([`styleClasses`,e.styleClasses.join(` `)]);let c=e.extensions?.strings;c!==void 0&&s.push([`strings`,JSON.stringify(c.map(e=>e.value))]);let l=(e.children??[]).map(e=>{if(e.slot===void 0)return xmlElement(e,t+1,[]);let n=` `.repeat(t+1),r=`${o}.${e.slot}`;return[`${n}<${r}>`,xmlElement(e,t+2,[]),`${n}</${r}>`].join(`
4
4
  `)});return element(t,o,s,xmlQuote,l,!0)}function sharedTreeNativeScriptXml(e){return xmlElement(e,0,[[`xmlns`,`http://schemas.nativescript.org/tns.xsd`],...[...prefixesOf(e,new Set)].sort().map(e=>[`xmlns:${e}`,`~/${e}`])])}export{sharedTreeHtml,sharedTreeNativeScriptXml};
package/lib/esm/tags.js CHANGED
@@ -1 +1 @@
1
- import"./_virtual/_rolldown/runtime.js";const hostTagOf=e=>{if(!/^(?:Adw|Gtk)[A-Z]\w*$/.test(e))throw Error(`hostTagOf: ${e} is not a GIR class name`);let t=[];for(let n=0;n<e.length;n++){let r=e.charAt(n);if(r>=`A`&&r<=`Z`&&n>0){let r=e.charAt(n-1),i=e.charAt(n+1);(!(r>=`A`&&r<=`Z`)||i>=`a`&&i<=`z`)&&t.push(`-`)}t.push(r.toLowerCase())}return t.join(``)},attributeOf=e=>e.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`),propertyOf=e=>e.replace(/[-_]([a-z0-9])/g,(e,t)=>t.toUpperCase()),e={"margin-start":`margin-inline-start`,"margin-end":`margin-inline-end`,"margin-top":`margin-top`,"margin-bottom":`margin-bottom`};export{e as GTK_WIDGET_MARGIN_CSS,attributeOf,hostTagOf,propertyOf};
1
+ import"./_virtual/_rolldown/runtime.js";const hostTagOf=e=>{if(!/^(?:Adw|Gtk)[A-Z]\w*$/.test(e))throw Error(`hostTagOf: ${e} is not a GIR class name`);let t=[];for(let n=0;n<e.length;n++){let r=e.charAt(n);if(r>=`A`&&r<=`Z`&&n>0){let r=e.charAt(n-1),i=e.charAt(n+1);(!(r>=`A`&&r<=`Z`)||i>=`a`&&i<=`z`)&&t.push(`-`)}t.push(r.toLowerCase())}return t.join(``)},attributeOf=e=>e.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`),propertyOf=e=>e.replace(/[-_]([a-z0-9])/g,(e,t)=>t.toUpperCase()),e={"margin-start":`margin-inline-start`,"margin-end":`margin-inline-end`,"margin-top":`margin-top`,"margin-bottom":`margin-bottom`},t=[`hexpand`,`vexpand`],n={"width-request":`min-width`,"height-request":`min-height`};function widgetLengthStyle(t,r){let i=e[t];if(i!==void 0)return[i,`${Number(r)}px`];let a=n[t];if(a!==void 0)return[a,Number(r)<0?null:`${Number(r)}px`]}const r=new Set([`sensitive`,`enabled`,`editable`,`visible`,`can-pop`,`revealed`,`show-apply-button`]),i=new Map([[`adw-toggle-group`,new Set([`sensitive`])],[`adw-toggle`,new Set([`enabled`])],[`adw-alert-response`,new Set([`enabled`])],[`adw-sidebar-item`,new Set([`enabled`,`visible`])],[`gtk-editable-label`,new Set([`editable`])],[`adw-entry-row`,new Set([`editable`,`show-apply-button`])],[`gtk-text`,new Set([`editable`])],[`gtk-text-view`,new Set([`editable`])],[`adw-navigation-page`,new Set([`can-pop`])],[`gtk-action-bar`,new Set([`revealed`])],[`adw-password-entry-row`,new Set([`revealed`])]]);function isValueBasedBooleanAttr(e,t){let n=i.get(e);return n!==void 0&&n.has(t)}export{t as GTK_WIDGET_EXPAND,e as GTK_WIDGET_MARGIN_CSS,n as GTK_WIDGET_SIZE_CSS,r as VALUE_BASED_BOOLEAN_ATTRS,attributeOf,hostTagOf,isValueBasedBooleanAttr,propertyOf,widgetLengthStyle};
@@ -1,6 +1,6 @@
1
1
  import type { SharedTreeNode } from './shared-trees.js';
2
2
  /** The construct kinds, in the order the tables list them. */
3
- export declare const CONSTRUCT_KINDS: readonly ["layout", "strings", "responses", "page", "extern", "signal", "bind", "breakpoint"];
3
+ export declare const CONSTRUCT_KINDS: readonly ["layout", "strings", "responses", "page", "extern", "signal", "bind", "breakpoint", "sibling-object"];
4
4
  export type ConstructKind = (typeof CONSTRUCT_KINDS)[number];
5
5
  /** `implemented`, or the sentence a human can act on — it is the text the error prints. */
6
6
  export type ConstructCapability = 'implemented' | {
@@ -52,8 +52,9 @@ export interface ConstructVector {
52
52
  }
53
53
  export declare const CONSTRUCT_VECTORS: readonly ConstructVector[];
54
54
  /**
55
- * The sizes a renderer feeds the `breakpoint` vector through its own size source, in order, and
56
- * reads the caption after each: wide, then narrow enough for the condition, then wide again.
55
+ * The sizes a renderer feeds the `breakpoint` and `sibling-object` vectors through its own size
56
+ * source, in order, and reads the label after each: wide, then narrow enough for the condition,
57
+ * then wide again.
57
58
  */
58
59
  export declare const BREAKPOINT_VECTOR_SIZES: readonly {
59
60
  readonly width: number;
@@ -189,6 +189,13 @@ export interface SharedTreeNode {
189
189
  };
190
190
  }[];
191
191
  }[];
192
+ /**
193
+ * Root only: the OBJECT roots the file declares beside this one — `Adw.AlertDialog dialog { }`
194
+ * or `$Learn learn { }` after the template — each a tree of its own (ADR 0093). They share the
195
+ * root's id scope, so a setter or a reference may name one, and a renderer hands the built
196
+ * object back to the code beside the file; none of them is a child of the root.
197
+ */
198
+ siblings?: readonly SharedTreeNode[];
192
199
  children?: readonly SharedTreeNode[];
193
200
  }
194
201
  /**
@@ -242,7 +249,7 @@ export declare const SHARED_TREE_TABLES: readonly ["BANNER_BUTTON_TEXT_VECTORS",
242
249
  */
243
250
  export declare const SHARED_TREE_BLOCKS_WITHOUT_EXPECTATIONS: Readonly<Record<string, string>>;
244
251
  /** Every authored node of `root`, in pre-order — the sequence a realised tree must reproduce. */
245
- export declare function authoredNodes(root: SharedTreeNode): {
252
+ export declare function authoredNodes(root: SharedTreeNode, address?: string): {
246
253
  node: SharedTreeNode;
247
254
  path: string;
248
255
  }[];
@@ -37,7 +37,7 @@ export declare const attributeOf: (prop: string) => string;
37
37
  */
38
38
  export declare const propertyOf: (name: string) => string;
39
39
  /**
40
- * `GtkWidget`'s four margins, as the CSS property each one is — `start`/`end` the LOGICAL
40
+ * `GtkWidget`'s four margins, as the CSS property each is — `start`/`end` the LOGICAL
41
41
  * edges `gtk_widget_set_margin_start` documents, `top`/`bottom` physical as in GTK.
42
42
  *
43
43
  * A markup renderer writes them as inline style, because an attribute cannot carry a length
@@ -46,3 +46,45 @@ export declare const propertyOf: (name: string) => string;
46
46
  * `./markup.ts`, whose markup has to parse back to exactly what that builder made.
47
47
  */
48
48
  export declare const GTK_WIDGET_MARGIN_CSS: Readonly<Record<string, string>>;
49
+ /**
50
+ * `GtkWidget:hexpand` / `vexpand`, the two booleans whose `false` is an AUTHORED answer: the
51
+ * attribute's absence says "not written", and a widget that expands by default
52
+ * (`<gtk-scrolled-window>`) needs the author's `false` to stop. A renderer writes `true` as
53
+ * the bare attribute and `false` as `hexpand="false"`, which the stylesheet reads.
54
+ */
55
+ export declare const GTK_WIDGET_EXPAND: readonly ["hexpand", "vexpand"];
56
+ /**
57
+ * `GtkWidget:width-request` / `height-request`, as the CSS minimum each one is. A size request
58
+ * is a MINIMUM in GTK (`gtk_widget_set_size_request`: the widget is never measured below it,
59
+ * and its natural size still wins when larger), so `min-*` is the same sentence and `width`
60
+ * would claim an exactness GTK does not give. -1 is the pspec's "not set".
61
+ */
62
+ export declare const GTK_WIDGET_SIZE_CSS: Readonly<Record<string, string>>;
63
+ /**
64
+ * The inline-style declaration an authored GtkWidget length property stands for, or
65
+ * `undefined` when `attribute` is not one. `null` is a size request of -1: the author said
66
+ * "unset", so nothing is written (and an earlier value is to be cleared).
67
+ */
68
+ export declare function widgetLengthStyle(attribute: string, value: string | number | boolean): readonly [property: string, length: string | null] | undefined;
69
+ /**
70
+ * Kebab-case attribute names of GTK boolean properties that default to TRUE.
71
+ * These are VALUE-BASED: `attr="false"` means false, absent means true (the default).
72
+ * Style classes like `flat`/`round`/`compact` are PRESENCE-BASED and NOT in this set.
73
+ * ADR 0049, ADR 0034 own the presence vs. value split.
74
+ *
75
+ * @deprecated Use {@link isValueBasedBooleanAttr} instead. This flat set cannot express
76
+ * that the same attribute name (e.g. `revealed`) is value-based for one widget
77
+ * (`gtk-action-bar`) but presence-based for another (`adw-banner`).
78
+ */
79
+ export declare const VALUE_BASED_BOOLEAN_ATTRS: Set<string>;
80
+ /**
81
+ * Whether the given attribute on the given widget tag is VALUE-BASED.
82
+ *
83
+ * Value-based means: `attr="false"` spells false, absent spells the default (TRUE).
84
+ * Presence-based means: the attribute's PRESENCE spells true, absence spells false.
85
+ *
86
+ * @param tagName The element's tag name (e.g. `adw-banner`, `gtk-action-bar`).
87
+ * @param attrName The kebab-case attribute name (e.g. `revealed`, `can-pop`).
88
+ * @returns True if the attribute should be written as `attr="true"|"false"`.
89
+ */
90
+ export declare function isValueBasedBooleanAttr(tagName: string, attrName: string): boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjsify/adwaita-core",
3
- "version": "0.55.0",
3
+ "version": "0.56.0",
4
4
  "description": "Headless Adwaita widget behavior (breakpoint condition grammar + apply/unapply state machine, color-scheme observable, avatar derivation) shared by the web and NativeScript Adwaita renderers — pure TS, no platform imports",
5
5
  "type": "module",
6
6
  "module": "lib/esm/index.js",
@@ -58,8 +58,8 @@
58
58
  "headless"
59
59
  ],
60
60
  "devDependencies": {
61
- "@gjsify/cli": "^0.55.0",
62
- "@gjsify/unit": "^0.55.0",
61
+ "@gjsify/cli": "^0.56.0",
62
+ "@gjsify/unit": "^0.56.0",
63
63
  "@types/node": "^25.9.2",
64
64
  "typescript": "^6.0.3"
65
65
  },