@gridify/editors 0.0.0-stage → 1.0.0-rc.1

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.
@@ -0,0 +1,2332 @@
1
+ import*as w from"@angular/core";import{Directive as zs,signal as E,input as we,model as Ls,computed as M,effect as Q,untracked as ee,ChangeDetectionStrategy as fn,Component as me,inject as L,Injectable as Pn,isSignal as sc,DestroyRef as lt,linkedSignal as sf,viewChild as ct,ElementRef as jo,afterNextRender as ur,output as Rs,Injector as Fs,booleanAttribute as js,DOCUMENT as ac,reflectComponentType as af}from"@angular/core";import{injectGfyDialogRef as lc,GfyExplorer as cc,GfyInput as Ps,GfyDialog as Ws,GfyMessageBox as fr,GfyToast as Ks,GfyIcons as Po,gfyParseAccelerator as lf,GfyPopupMenu as Wo,GfyButton as ke,GfyRibbon as mr,GfyToggleGroup as St,GfyPropertyGrid as Tt,GfyCodeEditor as Wn,GfyExpander as Yt,GfyIcon as mt,GfyUiSettings as cf,GfyTree as Kn,GfyProblemList as _n,GfyAccordion as gr,gfyDisplayAccelerator as dc,GfyNavList as Ko,GfyCodeBlock as pc,GfyDockingEngine as Ie,GfyMenuBar as Gn,GfyPreferenceSelect as Bn,GfyStatusBar as Vn,GfyDropdownButton as mn,GfyEngineSettings as _s,gfyKeyboardMenuPlace as df,GfySpinner as Gs,gfyLoadFormLayout as pf,GfyGroupBox as hc,GfySlider as _o,GfyDigitalDisplay as hf,GfyPictureGallery as uf,GfyPicture as ff,GfyFileUpload as mf,GfyColorPicker as gf,GfyTags as bf,GfyMultiSelect as yf,GfyMaskInput as wf,GfyDateTimePicker as vf,GfyTimePicker as xf,GfySplitButton as kf,GfySwitch as Sf,GfyRadioGroup as Tf,GfyCheckbox as Bs,GfyCombobox as Mf,GfySelect as $f,GfyTextarea as Af,GfyDatePicker as Cf,GfyPassword as Of,GfyControlDefaults as uc,GFY_CONTROL_AREA as fc,GfyForm as mc,GfyFormAreaTemplate as gc,GfyLabel as bc,GfyRepeater as yc,GfyRepeaterItemTemplate as wc}from"@gridify/studio";import{NgComponentOutlet as vc}from"@angular/common";const Jt="$expr";const Go="$bind";const br=/^[A-Za-z_$][\w$]*$/;function Hn(n){if(typeof n!=="object"||n===null||Array.isArray(n))return void 0;const e=n[Go];return Object.keys(n).length===1&&typeof e==="string"&&e.trim()!==""?e:void 0}function zt(n){if(typeof n!=="object"||n===null||Array.isArray(n))return void 0;const e=Object.keys(n);const t=n[Jt];return e.length===1&&typeof t==="string"&&t.trim()!==""?t:void 0}const Nf=n=>zt(n)!==void 0;function Lt(n){const e=zt(n);if(e!==void 0)return e;const t=Hn(n);if(t!==void 0)return`@${t}`;if(typeof n!=="object"||n===null||Array.isArray(n))return void 0;const o=n["$fn"];return Object.keys(n).length===1&&typeof o==="string"&&o!==""?o:void 0}const B=n=>Lt(n)!==void 0;const qn=["t","tr","tx","tk"];const If=/* @__PURE__ */new Set([" ","\t","\n","\r"]);const xc={"(":")","[":"]","{":"}"};function Df(n,e){const t=n[e];for(let o=e+1;o<n.length;o++){const i=n[o];if(i==="\\")o++;else if(i===t)return o+1;else if(i==="\n")return-1}return-1}function Ef(n,e){for(let t=e+1;t<n.length;t++){const o=n[t];if(o==="\\")t++;else if(o==="`")return t+1;else if(o==="$"&&n[t+1]==="{"){const i=yr(n,t+2,"}");if(!i)return-1;t=i.end}}return-1}function yr(n,e,t="value"){const o=[];let i=e;let r=e;while(r<n.length){const s=n[r];if(If.has(s)){r++}else if(s==="/"&&n[r+1]==="/"){const a=n.indexOf("\n",r);r=a<0?n.length:a+1}else if(s==="/"&&n[r+1]==="*"){const a=n.indexOf("*/",r+2);if(a<0)return null;r=a+2}else if(s==="\""||s==="'"){const a=Df(n,r);if(a<0)return null;r=i=a}else if(s==="`"){const a=Ef(n,r);if(a<0)return null;r=i=a}else if(s in xc){o.push(xc[s]);r++;i=r}else if(s===")"||s==="]"||s==="}"){if(o.length===0){if(t==="value"||t===s)return{end:r,last:i};return null}if(o.pop()!==s)return null;r++;i=r}else if(o.length===0&&t==="value"&&(s===","||s===";")){return{end:r,last:i}}else{r++;i=r}}return t==="value"&&o.length===0?{end:n.length,last:i}:null}function Vs(n){const e=n.trim();const t=/^((?:this\s*\.\s*)?[A-Za-z_$][\w$]*(?:\s*\.\s*[A-Za-z_$][\w$]*)*)\s*\(/.exec(e);if(!t)return null;const o=t[0].length-1;const i=yr(e,o+1,")");if(!i||e.slice(i.end+1).trim()!=="")return null;const r=e.slice(o+1,i.end);const s=[];if(r.trim()!==""){let a=0;for(;;){const l=yr(r,a,"value");if(!l||l.end<r.length&&r[l.end]!==",")return null;s.push(r.slice(a,l.end).trim());if(l.end>=r.length)break;a=l.end+1}}return{callee:t[1].replace(/\s+/g,"").replace(/^this\./,""),args:s}}const zf={n:"\n",r:"\r",t:"\t",b:"\b",f:"\f",v:" ","0":"\0"};function Hs(n){const e=n.trim();if(e==="true")return true;if(e==="false")return false;if(/^-?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?$/.test(e))return Number(e);const t=e[0];if((t==="\""||t==="'"||t==="`")&&e.length>=2&&e[e.length-1]===t){const o=e.slice(1,-1);if(t==="`"&&o.includes("${"))return void 0;let i="";for(let r=0;r<o.length;r++){const s=o[r];if(s!=="\\"){if(s===t)return void 0;i+=s;continue}const a=o[++r];if(a==="u"&&/^[0-9a-fA-F]{4}$/.test(o.slice(r+1,r+5))){i+=String.fromCharCode(parseInt(o.slice(r+1,r+5),16));r+=4}else if(a==="x"&&/^[0-9a-fA-F]{2}$/.test(o.slice(r+1,r+3))){i+=String.fromCharCode(parseInt(o.slice(r+1,r+3),16));r+=2}else if(a==="u"&&o[r+1]==="{"){const l=/^\{([0-9a-fA-F]{1,6})\}/.exec(o.slice(r+1,r+9));if(l&&parseInt(l[1],16)<=1114111){i+=String.fromCodePoint(parseInt(l[1],16));r+=l[0].length}else i+=a}else if(a==="\n"||a==="\r"&&o[r+1]==="\n"){if(a==="\r")r++}else i+=a===void 0?"":zf[a]??a}return i}return void 0}function Lf(n){if(n.trim()==="null")return{value:null};const e=Hs(n);return e===void 0?void 0:{value:e}}function Bo(n,e=60){const t=n.replace(/\s+/g," ").trim();return`ƒ ${t.length>e?`${t.slice(0,e-1)}…`:t}`}const v=n=>typeof n==="object"&&n!==null&&!Array.isArray(n);const ek=n=>Array.isArray(n);const q=n=>JSON.stringify(n);function Un(n){try{const e=JSON.parse(n);return Array.isArray(e)?e:[]}catch{return[]}}const Fe=(n,e)=>n.length===e.length&&n.every((t,o)=>t===e[o]);const qs=(n,e)=>n.length>=e.length&&e.every((t,o)=>t===n[o]);const Rf=200;const kc=/* @__PURE__ */new Set([" ","\t","\n","\r"]);const Sc={"\"":"\"","\\":"\\","/":"/",b:"\b",f:"\f",n:"\n",r:"\r",t:"\t"};const Tc=/-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/y;const Yn=/[A-Za-z_$][\w$]*/y;const Ff=/^\s*(?:export\s+)?(?:(?:public|private|protected|readonly|static|declare|const|let|var)\s+)*[A-Za-z_$][\w$]*!?\s*(?::[^=]+)?=\s*/;class Ce{offset;template;params;constructor(e,t,o={}){this.offset=e;this.template=t;this.params=o}}function Jn(n,e,t){Object.defineProperty(n,e,{value:t,enumerable:true,writable:true,configurable:true})}function Xn(n,e={}){const t=e.lenient===true;const o=/* @__PURE__ */new Map;const i=/* @__PURE__ */new Map;const r=(g,y,b)=>{if(!i.has(g))i.set(g,{offset:y,template:b})};const s=[0];for(let g=0;g<n.length;g++)if(n[g]==="\n")s.push(g+1);const a=g=>{let y=0;let b=s.length-1;while(y<b){const x=y+b+1>>1;if(s[x]<=g)y=x;else b=x-1}return{line:y+1,column:g-s[y]+1,offset:g}};let l=0;let d=false;const c=()=>{while(l<n.length){const g=n[l];if(kc.has(g))l++;else if(g==="/"&&(n[l+1]==="/"||n[l+1]==="*")){if(!t)throw new Ce(l,"Comments are not allowed in JSON.");r("comment",l,"A comment is accepted here, but the result is JSON, which has none.");if(n[l+1]==="/"){const y=n.indexOf("\n",l);l=y<0?n.length:y+1}else{const y=n.indexOf("*/",l+2);if(y<0)throw new Ce(l,"The comment is not closed.");l=y+2}}else break}};const p=()=>{if(l>=n.length)return new Ce(n.length,"The text ends too early.");const g=n[l];if(g==="'")return new Ce(l,"Strings need double quotes, not single quotes.");for(const y of["NaN","Infinity","undefined"])if(n.startsWith(y,l))return new Ce(l,"{word} is not valid JSON. Leave the property out.",{word:y});return new Ce(l,"Unexpected character \"{char}\".",{char:g})};const h=()=>{const g=l;const y=n[l];l++;let b="";while(l<n.length){const x=n[l];if(x===y){l++;return b}if(x==="\\"){const T=n[l+1];if(T==="u"){const k=n.slice(l+2,l+6);if(!/^[0-9a-fA-F]{4}$/.test(k))throw new Ce(l,"A \\u escape needs four hexadecimal digits.");b+=String.fromCharCode(parseInt(k,16));l+=6}else if(T!==void 0&&T in Sc){b+=Sc[T];l+=2}else if(t&&T==="'"){b+="'";l+=2}else{throw new Ce(l,"Unknown escape \"\\{char}\".",{char:T??""})}}else if(x<" "){throw new Ce(l,"A line break or a control character in a string must be escaped.")}else{b+=x;l++}}throw new Ce(g,"The string is not closed.")};const u=(g,y)=>{if(y>Rf)throw new Ce(l,"The document is nested too deeply.");c();if(l>=n.length)throw p();const b=n[l];if(b==="{"){l++;const x={};c();if(n[l]==="}"){l++;return x}let T=-1;for(;;){c();if(n[l]==="}"){if(!t)throw new Ce(l,"A trailing comma is not allowed in JSON.");r("comma",T,"A trailing comma is accepted here, but the result is JSON, which has none.");l++;return x}const k=l;let S;if(n[l]==="\""||t&&n[l]==="'"){if(n[l]==="'")r("quote",l,"Single quotes are accepted here, but the result is JSON with double quotes.");S=h()}else if(t&&l<n.length&&/[A-Za-z_$]/.test(n[l])){Yn.lastIndex=l;S=Yn.exec(n)?.[0]??"";l+=S.length;r("name",k,"A name without quotes is accepted here, but the result is JSON with quotes.")}else{if(l<n.length&&/[A-Za-z_$]/.test(n[l]))throw new Ce(l,"Property names need double quotes.");throw p()}o.set(q([...g,S]),a(k));c();if(n[l]!==":")throw new Ce(l,"Expected \":\" after the property name.");l++;Jn(x,S,u([...g,S],y+1));c();if(n[l]===","){T=l;l++;continue}if(n[l]==="}"){l++;return x}throw l>=n.length?p():new Ce(l,"Expected \",\" or \"}\".")}}if(b==="["){l++;const x=[];c();if(n[l]==="]"){l++;return x}let T=-1;for(;;){c();if(n[l]==="]"){if(!t)throw new Ce(l,"A trailing comma is not allowed in JSON.");r("comma",T,"A trailing comma is accepted here, but the result is JSON, which has none.");l++;return x}o.set(q([...g,x.length]),a(l));x.push(u([...g,x.length],y+1));c();if(n[l]===","){T=l;l++;continue}if(n[l]==="]"){l++;return x}throw l>=n.length?p():new Ce(l,"Expected \",\" or \"]\".")}}if(b==="\""||t&&b==="'"){if(b==="'")r("quote",l,"Single quotes are accepted here, but the result is JSON with double quotes.");return h()}if(b==="-"||b>="0"&&b<="9"){Tc.lastIndex=l;const x=Tc.exec(n);if(!x)throw new Ce(l,"This is not a valid number.");l+=x[0].length;return Number(x[0])}for(const[x,T]of[["true",true],["false",false],["null",null]]){if(n.startsWith(x,l)&&!(t&&/[\w$]/.test(n[l+x.length]??""))){l+=x.length;return T}}if(t&&y>0&&/[A-Za-z_$]/.test(b)){const x=m();if(x!==null)return x}if(t&&y>0&&/[A-Za-z_$(`!]/.test(b)&&!/^(?:NaN|Infinity|undefined)(?![\w$])/.test(n.slice(l,l+10))){const x=f();if(x!==null)return x}throw p()};const f=()=>{const g=l;const y=yr(n,l,"value");if(!y)throw new Ce(g,"The expression is not closed.");const b=n.slice(g,y.last).trim();if(b==="")return null;l=y.end;r("expression",g,"An expression is kept as it is written, as {\"$expr\": \"...\"}: the editor does not run it.");const x={};Jn(x,Jt,b);return x};const m=()=>{const g=l;Yn.lastIndex=l;let y=Yn.exec(n)?.[0]??"";let b=l+y.length;if(y==="this"&&n[b]==="."){Yn.lastIndex=b+1;const k=Yn.exec(n)?.[0];if(k){y=k;b+=1+k.length}}if(y===""||y==="undefined"||y==="NaN"||y==="Infinity")return null;let x=b;while(x<n.length&&kc.has(n[x]))x++;if(x<n.length&&n[x]!==","&&n[x]!=="}"&&n[x]!=="]"&&n[x]!==";")return null;l=b;r("function",g,"A name is read as a reference to a function: {\"$fn\": \"name\"}.");const T={};Jn(T,"$fn",y);return T};try{if(t){c();const b=Ff.exec(n.slice(l));if(b){l+=b[0].length;d=true;r("declaration",0,"The code around the value is ignored, and the result is the JSON of the value.")}}c();if(l>=n.length)return{ok:false,error:{...a(0),template:"The text is empty.",params:{}}};o.set(q([]),a(l));const g=u([],0);c();if(d&&n[l]===";"){l++;c()}if(l<n.length)throw new Ce(l,"Unexpected character \"{char}\" after the end of the value.",{char:n[l]});const y=[...i.values()].map(b=>({...a(Math.max(0,b.offset)),template:b.template,params:{}}));return{ok:true,value:g,positions:o,notes:y}}catch(g){if(g instanceof Ce)return{ok:false,error:{...a(g.offset),template:g.template,params:g.params}};throw g}}function Us(n,e){const t=a=>e.special&&a!==null&&typeof a==="object"&&!Array.isArray(a)?e.special(a):null;const o=a=>{const l=t(a);if(l!==null)return l;if(Array.isArray(a))return a.length?`[${a.map(o).join(", ")}]`:"[]";if(a!==null&&typeof a==="object"){const d=Object.entries(a);return d.length?`{${d.map(([c,p])=>`${e.key(c)}: ${o(p)}`).join(", ")}}`:"{}"}return e.primitive(a)};const i=a=>{if(t(a)!==null)return 0;if(Array.isArray(a))return 1+a.reduce((l,d)=>Math.max(l,i(d)),0);if(a!==null&&typeof a==="object")return 1+Object.values(a).reduce((l,d)=>Math.max(l,i(d)),0);return 0};const r=e.trailingComma?",":"";const s=(a,l,d)=>{if(a===null||typeof a!=="object")return e.primitive(a);const c=t(a);if(c!==null)return c;const p=Array.isArray(a)?a.length===0:Object.keys(a).length===0;if(p)return Array.isArray(a)?"[]":"{}";const h=o(a);if(d+l*e.indent+h.length<=e.width&&i(a)<=2)return h;const u=" ".repeat((l+1)*e.indent);const f=" ".repeat(l*e.indent);if(Array.isArray(a))return`[
2
+ ${a.map(m=>u+s(m,l+1,0)).join(",\n")}${r}
3
+ ${f}]`;return`{
4
+ ${Object.entries(a).map(([m,g])=>{const y=`${e.key(m)}: `;return u+y+s(g,l+1,y.length)}).join(",\n")}${r}
5
+ ${f}}`};return s(n,0,0)}function Zn(n,e=2,t=110){return Us(n,{indent:e,width:t,key:o=>JSON.stringify(o),primitive:o=>JSON.stringify(o),trailingComma:false})}function O(n,e){let t=n;for(const o of e){if(typeof o==="number"){if(!Array.isArray(t))return void 0;t=t[o]}else{if(!v(t)||!Object.prototype.hasOwnProperty.call(t,o))return void 0;t=t[o]}}return t}function be(n,e,t){if(e.length===0)return t??null;const[o,...i]=e;if(typeof o==="number"){const a=Array.isArray(n)?n:[];const l=[...a];l[o]=be(a[o]??(typeof i[0]==="number"?[]:{}),i,t);return l}const r=v(n)?n:{};if(i.length===0&&t===void 0){if(!Object.prototype.hasOwnProperty.call(r,o))return r;const a={};for(const[l,d]of Object.entries(r))if(l!==o)Jn(a,l,d);return a}const s={};for(const[a,l]of Object.entries(r))Jn(s,a,l);Jn(s,o,be(r[o]??(typeof i[0]==="number"?[]:{}),i,t));return s}function Qn(n,e){if(e.length===0)return n;const t=e.slice(0,-1);const o=e[e.length-1];const i=O(n,t);if(typeof o==="number"){if(!Array.isArray(i))return n;return be(n,t,i.filter((r,s)=>s!==o))}return be(n,e,void 0)}function gt(n,e,t,o){const i=O(n,e);const r=Array.isArray(i)?[...i]:[];const s=t===void 0?r.length:Math.max(0,Math.min(t,r.length));r.splice(s,0,o);return be(n,e,r)}function Vo(n,e,t,o){const i=O(n,e);if(!Array.isArray(i)||t<0||t>=i.length)return n;const r=Math.max(0,Math.min(o,i.length-1));if(r===t)return n;const s=[...i];const[a]=s.splice(t,1);s.splice(r,0,a);return be(n,e,s)}function Ho(n,e){if(Object.is(n,e))return true;if(Array.isArray(n))return Array.isArray(e)&&n.length===e.length&&n.every((i,r)=>Ho(i,e[r]));if(!v(n)||!v(e))return false;const t=Object.keys(n);const o=Object.keys(e);return t.length===o.length&&t.every((i,r)=>i===o[r]&&Ho(n[i],e[i]))}const Ys=n=>JSON.parse(JSON.stringify(n));const Js=["start","center","end","stretch"];const Mc=["item","separator","header","source"];const qo=[{name:"gfy:documents",label:"Open documents",description:"The documents that are open, numbered; the active one is checked, and a press makes a document active."},{name:"gfy:tools",label:"Tool windows",description:"One entry for each panel of the docking engine, checked while it is open; a press shows or hides the panel."},{name:"gfy:restore-layout",label:"Restore layout",description:"The entry that puts the windows back to the layout they had at the start."},{name:"gfy:windows",label:"Windows",description:"The main window and the popout windows (only an engine with popout windows has them), and Return all windows."}];const $c="my-block";const Ac=[{id:"item",label:"Choice",description:"An entry of a menu, a list or a group of buttons.",kind:"item"},{id:"separator",label:"Separator",description:"A line between the entries of a menu.",kind:"separator"},{id:"header",label:"Heading",description:"The heading of a group of entries of a menu.",kind:"header"},...qo.map(n=>({id:n.name,label:n.label,description:n.description,kind:"source",source:n.name})),{id:"app-block",label:"Block of the application",description:"A block that the application registers under a name of its own (GfyMenuSources): write the name in the Inspector.",kind:"source",source:$c}];const jf="gfy:";const Pf=n=>qo.find(e=>e.name===n.replace(/@.*$/,""));const Xs="The windows it is shown in, as masks of their tags, separated by commas: gfy:main, gfy:popout, doc*, /^doc-[0-9]+$/, gfy:popout&doc*. Without them it is shown where its parent is. The editor shows it anyway.";const Uo=[{key:"id",kind:"text",category:"identity",description:"Identifies the tab. It has to be unique."},{key:"label",kind:"text",category:"content",description:"The text of the tab."},{key:"rows",kind:"integer",min:1,category:"layout",description:"The number of grid rows of all sections of the tab. Without it the highest row used by the items counts."},{key:"hidden",kind:"boolean",bind:true,category:"behavior",description:"Hides the tab. The application can switch it by a signal, which makes a contextual tab. The editor shows it anyway."},{key:"showForTags",kind:"tags",bind:true,category:"behavior",description:Xs},{key:"contextual",kind:"boolean",category:"behavior",description:"Colors the tab as a contextual one. It does not hide the tab: hide it by \"Hidden\", driven by a signal."},{key:"keytip",kind:"text",category:"keyboard",description:"The letters shown after Alt. Without it a free one is chosen."}];const Yo=[{key:"id",kind:"text",category:"identity",description:"Identifies the section in its tab. It has to be unique there."},{key:"title",kind:"text",category:"content",description:"The text under the section, and on the button when the section is collapsed."},{key:"icon",kind:"text",category:"content",description:"The icon of the collapsed section, used only while the ribbon is collapsible (Ribbon Options). Without it the first icon of the items, or of their choices, is used."},{key:"columns",kind:"columns",category:"layout",description:"A number of columns, or the tracks of a grid such as \"72px 140px 1fr\"."},{key:"compactColumns",kind:"columns",category:"layout",description:"The columns of the shrunk section, used only while the ribbon is collapsible (Ribbon Options). Without them the columns are used."},{key:"collapsePriority",kind:"integer",category:"behavior",description:"A lower number is shrunk first. Equal numbers go from right to left. Used only while the ribbon is collapsible (Ribbon Options)."},{key:"collapsible",kind:"boolean",default:true,category:"behavior",description:"On by default; off: the section never collapses into a button. Used only while the ribbon is collapsible (Ribbon Options)."},{key:"hidden",kind:"boolean",bind:true,category:"behavior",description:"Hides the section. The application can switch it by a signal. The editor shows it anyway."},{key:"showForTags",kind:"tags",bind:true,category:"behavior",description:Xs},{key:"launcher",kind:"text",category:"behavior",description:"Shows the launcher button next to the title. The text is the action that a click reports."}];const Xt=[{key:"id",kind:"text",category:"identity",description:"The handle of the application: it binds signals and handlers to the item by it. It has to be unique in the whole ribbon."},{key:"label",kind:"text",bind:true,category:"content",description:"The text of the item. A gallery, a select, a combo box, a toggle group and a color picker do not draw it: it is their name for a screen reader."},{key:"icon",kind:"text",bind:true,category:"content",description:"The key of an icon from the registry of the application (for example \"app:paste\")."},{key:"iconColor",kind:"text",color:true,bind:true,category:"content",description:"The color of the icon, chosen in the color picker (it is written as a code such as \"#2563eb\"). Without it the icon has the accent color of the ribbon."},{key:"tooltip",kind:"text",bind:true,category:"content",description:"The text of the tooltip, used instead of the label. The shortcut is added to it. A gallery and a color picker use it as their name for a screen reader only."},{key:"description",kind:"text",bind:true,category:"content",description:"A longer text for the rich tooltip, shown after a moment."},{key:"col",kind:"integer",min:1,category:"layout",description:"The column where the item starts (from 1). Without it the grid places the item."},{key:"row",kind:"integer",min:1,category:"layout",description:"The row where the item starts (from 1). Without it the grid places the item."},{key:"colSpan",kind:"span",category:"layout",description:"How many columns the item covers, or \"all\"."},{key:"rowSpan",kind:"span",category:"layout",description:"How many rows the item covers, or \"all\". Without it the control decides."},{key:"justify",kind:"choice",options:Js,category:"layout",description:"Across the cells. A button, a field, a progress bar and a gallery fill their cells, and justify aligns their content (stretch, the default: the alignment of the control). A check box, a radio, a label, a toggle group, a color picker, a progress ring and a control of the application are placed in their cells by it."},{key:"align",kind:"choice",options:Js,category:"layout",description:"The alignment in the cell down. Stretch for an item of several rows, otherwise center."},{key:"action",kind:"text",category:"behavior",description:"The text that arrives in the action event. The application reacts to it."},{key:"disabled",kind:"boolean",bind:true,category:"behavior",description:"The starting state. The application can drive it by a signal."},{key:"disabledReason",kind:"text",bind:true,category:"behavior",description:"Why the item is disabled. Shown as a tooltip while it is."},{key:"hidden",kind:"boolean",bind:true,category:"behavior",description:"Hides the item. The application can switch it by a signal. The editor shows it anyway."},{key:"showForTags",kind:"tags",bind:true,category:"behavior",description:Xs},{key:"value",kind:"value",bind:true,category:"behavior",description:"The starting value of the control."},{key:"checked",kind:"boolean",bind:true,category:"behavior",description:"The starting state of a check box, a radio button or a toggle button."},{key:"shortcut",kind:"text",category:"keyboard",description:"A keyboard shortcut such as \"Ctrl+B\". \"Mod\" is Ctrl, and Cmd on a Mac. A control with a value or a list (a field, a gallery, a menu) reports the action alone for it, without a value."},{key:"keytip",kind:"text",category:"keyboard",description:"The letters shown after Alt. Without it they come from the label."}];const Jo=[{key:"kind",kind:"choice",options:Mc,category:"identity",description:"An entry, a separator line, a heading of a group, or a block of entries that the application fills (the last three: the menu of a split button or a dropdown button only)."},{key:"source",kind:"text",category:"identity",description:"The name of a block of menu items: the menu shows its items in this place when it opens, for example the open documents or the tool windows. The items run their own commands."},{key:"label",kind:"text",category:"content",description:"The text of the choice."},{key:"value",kind:"text",category:"identity",description:"What is stored and reported. Without it the label is used, so give it when the label comes from a translation function. An empty text is a value too (the \"none\" entry of a list)."},{key:"icon",kind:"text",category:"content",description:"The key of an icon from the registry of the application."},{key:"preview",kind:"text",category:"content",description:"The text of a gallery tile. \"AaBbCc\" without it; an empty text gives an empty tile."},{key:"style",kind:"map",category:"content",description:"CSS properties of the preview of the choice in the tile of a gallery (for example a font preview). Nothing else draws it: not a menu, not a list."},{key:"shortcut",kind:"text",category:"keyboard",description:"A keyboard shortcut of the choice, such as \"Ctrl+Shift+V\"."},{key:"checked",kind:"boolean",bind:true,category:"behavior",description:"The state of a button of a toggle group."},{key:"disabled",kind:"boolean",bind:true,category:"behavior",description:"The choice cannot be used."}];const Cc=[...Uo.map(n=>n.key),"sections"];const Oc=[...Yo.map(n=>n.key),"items"];const Nc=[...Xt.map(n=>n.key),"type","choices","inputs","compact"];const Zs=[...Jo.map(n=>n.key),"choices"];const Qs=["type","inputs","col","row","colSpan","rowSpan","justify","align"];function Wf(n,e){const t=n.key;if(B(e))return null;switch(n.kind){case"text":return typeof e==="string"?null:{template:"The property \"{key}\" must be a text.",params:{key:t}};case"boolean":return typeof e==="boolean"?null:{template:"The property \"{key}\" must be true or false.",params:{key:t}};case"integer":return Number.isInteger(e)&&(n.min===void 0||e>=n.min)?null:n.min===void 0?{template:"The property \"{key}\" must be a whole number.",params:{key:t}}:{template:"The property \"{key}\" must be a whole number of {min} or more.",params:{key:t,min:n.min}};case"choice":return typeof e==="string"&&n.options?.includes(e)?null:{template:"The property \"{key}\" must be one of: {options}.",params:{key:t,options:(n.options??[]).join(", ")}};case"span":return e==="all"||Number.isInteger(e)&&e>=1?null:{template:"The property \"{key}\" must be a whole number of 1 or more, or \"all\".",params:{key:t}};case"columns":if(typeof e==="string"&&/^\s*\d+\s*$/.test(e))return{template:"The property \"{key}\" is a text of grid tracks, and \"{value}\" is not one. Write the number without quotes: {value}.",params:{key:t,value:e.trim()}};return Number.isInteger(e)&&e>=1||typeof e==="string"&&e.trim()!==""?null:{template:"The property \"{key}\" must be a number of columns, or a text of grid tracks.",params:{key:t}};case"value":return typeof e==="string"||typeof e==="number"||typeof e==="boolean"?null:{template:"The property \"{key}\" must be a text, a number or true or false.",params:{key:t}};case"map":return v(e)&&Object.values(e).every(o=>typeof o==="string"||B(o))?null:{template:"The property \"{key}\" must be an object whose values are texts.",params:{key:t}};case"tags":return Array.isArray(e)&&e.every(o=>typeof o==="string"||B(o))?null:{template:"The property \"{key}\" must be a list of texts.",params:{key:t}}}}const Kf={structure:true,icon:true,tile:true,checked:true,disabled:true,submenu:true};const We={structure:false,icon:false,tile:false,checked:false,disabled:false,submenu:false};const Ic={...We,structure:true,icon:true,disabled:true,submenu:true};const ea=["small","large"];const ta=n=>n["size"]==="large"?"all":1;const Dc={name:"iconOnly",kind:"boolean",fallback:false,description:"Hides the label. The tooltip still shows it."};const Ec={name:"size",kind:"choice",options:ea,fallback:"small",description:"Small: the icon beside the label. Large: the icon above the label, over all rows."};const zc=[Ec,{name:"iconOnly",kind:"boolean",fallback:false,dependsOn:{input:"size",not:"large"},description:"Hides the label of a small button. The tooltip still shows it. A large button always shows its label."},{name:"menuLayout",kind:"choice",options:["list","icons"],fallback:"list",description:"The menu is a list of entries, or a grid of icons."},{name:"iconColumns",kind:"integer",min:1,fallback:6,dependsOn:{input:"menuLayout",equals:"icons"},description:"The columns of the grid of icons. Used only when the menu layout is icons."}];const Lc=[{name:"min",kind:"number",fallback:0,description:"The value at the start of the range."},{name:"max",kind:"number",fallback:100,description:"The value at the end of the range."},{name:"indeterminate",kind:"boolean",fallback:false,description:"Moves without end although there is a value."},{name:"showValue",kind:"boolean",fallback:false,description:"Writes the value as a text. A small ring has no room for it."},{name:"variant",kind:"choice",options:["accent","success","warning","danger","neutral"],fallback:"accent",description:"The color of the filled part."},{name:"valueText",kind:"function",signature:"(value: number, percent: number) => string",description:"Makes the text of the value, from the value and the percent. It is a function of the application: write {\"$fn\": \"name\"} and register the function under that name."}];const et=(n,e)=>e===void 0?{label:n}:{label:n,value:e};const Xo=[{type:"large-button",label:"Large button",group:"buttons",description:"A big button with the icon above the label. It covers all rows.",inputs:[],choices:"none",choiceUse:We,value:"none",checked:false,icon:true,command:true,emits:"nothing",defaultRowSpan:()=>"all",create:(n,e)=>({type:"large-button",id:n,label:e("Large button"),action:n})},{type:"button",label:"Button",group:"buttons",description:"A small button, the icon beside the label.",inputs:[Dc],choices:"none",choiceUse:We,value:"none",checked:false,icon:true,command:true,emits:"nothing",defaultRowSpan:()=>1,create:(n,e)=>({type:"button",id:n,label:e("Button"),action:n})},{type:"styled-button",label:"Styled button",group:"buttons",description:"A colored button.",inputs:[{name:"variant",kind:"choice",options:["default","primary","success","warning","danger"],fallback:"default",description:"The color: primary, success, warning and danger are colors of the theme, default is the quiet button."}],choices:"none",choiceUse:We,value:"none",checked:false,icon:true,command:true,emits:"nothing",defaultRowSpan:()=>1,create:(n,e)=>({type:"styled-button",id:n,label:e("Styled button"),action:n,inputs:{variant:"primary"}})},{type:"split-button",label:"Split button",group:"menus",description:"A button with an arrow that opens a menu. The main part and the entries of the menu report separately.",inputs:zc,choices:"optional",choiceUse:Ic,value:"none",checked:false,icon:true,command:true,emits:"nothing for the button, the key of the choice for the menu",defaultRowSpan:ta,create:(n,e)=>({type:"split-button",id:n,label:e("Split button"),action:n,choices:[et(e("First option")),et(e("Second option"))]})},{type:"dropdown-button",label:"Dropdown button",group:"menus",description:"A button that only opens a menu. The chosen entry is stored in the value.",inputs:zc,choices:"required",choiceUse:Ic,value:"text",checked:false,icon:true,command:true,emits:"the key of the choice",defaultRowSpan:ta,create:(n,e)=>({type:"dropdown-button",id:n,label:e("Dropdown button"),action:n,value:e("First option"),choices:[et(e("First option")),et(e("Second option"))]})},{type:"gallery",label:"Gallery",group:"menus",description:"Tiles with a preview and paging, over all rows. The chosen tile is the value.",inputs:[{name:"pageSize",kind:"integer",min:1,fallback:4,description:"How many tiles one page shows."}],choices:"required",choiceUse:{...We,icon:true,tile:true,disabled:true},value:"text",checked:false,icon:false,command:true,emits:"the key of the choice",defaultRowSpan:()=>"all",create:(n,e)=>({type:"gallery",id:n,action:n,value:"a",choices:[et(e("Style A"),"a"),et(e("Style B"),"b"),et(e("Style C"),"c")]})},{type:"table-picker",label:"Table picker",group:"menus",description:"A grid for choosing the size of a table, like in Word.",inputs:[{name:"size",kind:"choice",options:ea,fallback:"large",description:"Small: one row. Large: the icon above the label, over all rows."},{name:"columns",kind:"integer",min:1,fallback:10,description:"The columns of the grid."},{name:"rows",kind:"integer",min:1,fallback:8,description:"The rows of the grid."}],choices:"optional",choiceUse:{...We,icon:true,disabled:true},value:"none",checked:false,icon:true,command:true,emits:"\"<columns>x<rows>\", for example \"4x3\", or the key of a choice under the grid",defaultRowSpan:n=>n["size"]==="small"?1:"all",create:(n,e)=>({type:"table-picker",id:n,label:e("Table"),action:n})},{type:"color-picker",label:"Color picker",group:"menus",description:"An icon with a colored strip and a palette. The color is the value.",inputs:[{name:"colors",kind:"list",description:"The palette: a list of CSS colors. The Office colors without it."},{name:"automatic",kind:"text",color:true,description:"Shows the entry \"Automatic\" with this color. Its value is \"auto\"."},{name:"allowNone",kind:"boolean",fallback:false,description:"Shows the entry \"No color\". Its value is \"none\"."},{name:"moreColors",kind:"boolean",fallback:false,description:"Shows the entry \"More colors\" that turns the popup into the full color panel of the library."}],choices:"none",choiceUse:We,value:"text",checked:false,icon:true,command:true,emits:"the color, \"auto\" or \"none\"",defaultRowSpan:()=>1,create:(n,e)=>({type:"color-picker",id:n,label:e("Color"),action:n,value:"#ff0000"})},{type:"toggle-button",label:"Toggle button",group:"toggles",description:"A button that stays pressed.",inputs:[Ec,{...Dc,dependsOn:{input:"size",not:"large"},description:"Hides the label of a small button. The tooltip still shows it. A large button always shows its label."}],choices:"none",choiceUse:We,value:"none",checked:true,icon:true,command:true,emits:"true or false",defaultRowSpan:ta,create:(n,e)=>({type:"toggle-button",id:n,label:e("Toggle button"),action:n,checked:false})},{type:"toggle-group",label:"Toggle group",group:"toggles",description:"A row of toggle buttons made from the choices. The state of each one is in its choice.",ignores:["keytip","tooltip"],inputs:[{name:"exclusive",kind:"boolean",fallback:false,description:"Only one button is on, like radio buttons."},{name:"showLabels",kind:"boolean",fallback:false,description:"Shows the labels also next to the icons."}],choices:"required",choiceUse:{...We,icon:true,checked:true,disabled:true},value:"none",checked:false,icon:false,command:true,emits:"true or false for the clicked button, the key of the choice when exclusive",defaultRowSpan:()=>1,create:(n,e)=>({type:"toggle-group",id:n,action:n,inputs:{exclusive:true},choices:[et(e("Left"),"left"),et(e("Center"),"center"),et(e("Right"),"right")]})},{type:"checkbox",label:"Check box",group:"toggles",description:"A check box.",inputs:[],choices:"none",choiceUse:We,value:"none",checked:true,icon:false,command:true,emits:"true or false",defaultRowSpan:()=>1,create:(n,e)=>({type:"checkbox",id:n,label:e("Check box"),action:n,checked:false})},{type:"radio",label:"Radio button",group:"toggles",description:"A radio button. Buttons with the same group work together.",inputs:[{name:"group",kind:"text",description:"The name of the group of radio buttons."}],choices:"none",choiceUse:We,value:"none",checked:true,icon:false,command:true,emits:"true",defaultRowSpan:()=>1,create:(n,e)=>({type:"radio",id:n,label:e("Radio button"),action:n,inputs:{group:"group"},checked:false})},{type:"spinner",label:"Spinner",group:"fields",description:"A number field with arrows.",inputs:[{name:"min",kind:"number",description:"The smallest value. Without it there is none."},{name:"max",kind:"number",description:"The biggest value. Without it there is none."},{name:"step",kind:"number",fallback:1,description:"What the arrows add."},{name:"unit",kind:"text",fallback:"",description:"A short text after the number, such as \"cm\"."}],choices:"none",choiceUse:We,value:"number",checked:false,icon:true,command:true,emits:"the number",defaultRowSpan:()=>1,create:(n,e)=>({type:"spinner",id:n,label:e("Size"),action:n,value:10,inputs:{min:0,max:100,step:1}})},{type:"combobox",label:"Combo box",group:"fields",description:"A field that allows typing and choosing from a list.",inputs:[{name:"numeric",kind:"boolean",fallback:false,description:"Accepts only numbers."},{name:"min",kind:"number",dependsOn:{input:"numeric",equals:true},description:"The smallest number. Used only when the field is numeric."},{name:"max",kind:"number",dependsOn:{input:"numeric",equals:true},description:"The biggest number. Used only when the field is numeric."},{name:"placeholder",kind:"text",fallback:"",description:"The text of the empty field."}],choices:"optional",choiceUse:We,value:"any",checked:false,icon:false,command:true,emits:"the text, or a number when it is numeric",defaultRowSpan:()=>1,create:(n,e)=>({type:"combobox",id:n,action:n,value:e("First option"),choices:[et(e("First option")),et(e("Second option"))]})},{type:"select",label:"Select",group:"fields",description:"A native list to choose from.",inputs:[],choices:"required",choiceUse:{...We,disabled:true},value:"text",checked:false,icon:false,command:true,emits:"the key of the choice",defaultRowSpan:()=>1,create:(n,e)=>({type:"select",id:n,action:n,value:"a",choices:[et(e("Option A"),"a"),et(e("Option B"),"b")]})},{type:"label",label:"Label",group:"display",description:"A plain text, such as the caption of a group.",ignores:["action","shortcut","keytip"],inputs:[],choices:"none",choiceUse:We,value:"none",checked:false,icon:false,command:false,emits:"nothing",defaultRowSpan:()=>1,create:(n,e)=>({type:"label",id:n,label:e("Label")})},{type:"progress-bar",label:"Progress bar",group:"display",description:"Shows how far some work is. The application owns the value.",ignores:["action","shortcut","keytip"],inputs:[...Lc,{name:"size",kind:"choice",options:["small","medium","large"],fallback:"medium",description:"The thickness of the bar: 4, 8 or 14 px."}],choices:"none",choiceUse:We,value:"number",checked:false,icon:false,command:false,emits:"nothing",defaultRowSpan:()=>1,create:(n,e)=>({type:"progress-bar",id:n,label:e("Progress"),value:40,inputs:{showValue:true}})},{type:"progress-ring",label:"Progress ring",group:"display",description:"Shows how far some work is as a ring. The application owns the value.",ignores:["action","shortcut","keytip"],inputs:[...Lc.map(n=>n.name==="showValue"?{...n,dependsOn:{input:"size",equals:"large"}}:n),{name:"size",kind:"choice",options:ea,fallback:"small",description:"Small: one row. Large: 40 px over all rows, with the value inside."}],choices:"none",choiceUse:We,value:"number",checked:false,icon:false,command:false,emits:"nothing",defaultRowSpan:n=>n["size"]==="large"?"all":1,create:(n,e)=>({type:"progress-ring",id:n,label:e("Progress"),value:40})}];const _f=["buttons","menus","toggles","fields","display"];const Gf=new Map(Xo.map(n=>[n.type,n]));const J=n=>typeof n==="string"?Gf.get(n):void 0;const eo=n=>n?.choiceUse??Kf;const Rc=n=>eo(n).structure?Ac:Ac.filter(e=>e.kind==="item");function Rt(n){const e=n["rowSpan"];if(e==="all"||typeof e==="number"&&Number.isInteger(e)&&e>=1)return e;const t=J(n["type"]);return t?t.defaultRowSpan(v(n["inputs"])?n["inputs"]:{}):1}function Me(n){const e=n["colSpan"];return e==="all"||typeof e==="number"&&Number.isInteger(e)&&e>=1?e:1}function Bf(n,e){const t=n.name;if(B(e))return null;switch(n.kind){case"boolean":return typeof e==="boolean"?null:{template:"The property \"{key}\" must be true or false.",params:{key:t}};case"integer":return Number.isInteger(e)&&(n.min===void 0||e>=n.min)?null:{template:"The property \"{key}\" must be a whole number of {min} or more.",params:{key:t,min:n.min??0}};case"number":return typeof e==="number"&&Number.isFinite(e)?null:{template:"The property \"{key}\" must be a number.",params:{key:t}};case"text":return typeof e==="string"?null:{template:"The property \"{key}\" must be a text.",params:{key:t}};case"choice":return typeof e==="string"&&n.options?.includes(e)?null:{template:"The property \"{key}\" must be one of: {options}.",params:{key:t,options:(n.options??[]).join(", ")}};case"list":return Array.isArray(e)&&e.every(o=>typeof o==="string"||B(o))?null:{template:"The property \"{key}\" must be a list of texts.",params:{key:t}};case"function":return null}}const tt=3;const gn=n=>typeof n==="number"&&Number.isInteger(n)&&n>=1?n:void 0;function Fc(n){let e=0;let t="";const o=[];for(const r of n){if(r==="(")e++;if(r===")")e=Math.max(0,e-1);if(/\s/.test(r)&&e===0){if(t)o.push(t);t=""}else{t+=r}}if(t)o.push(t);let i=0;for(const r of o){const s=/^repeat\(\s*(\d+)\s*,(.*)\)$/s.exec(r);i+=s?Number(s[1])*Math.max(1,Fc(s[2].trim())):1}return i}function na(n){if(typeof n==="number")return Number.isFinite(n)&&n>=1?Math.floor(n):1;if(typeof n==="string")return Math.max(1,Fc(n.trim()));return 1}function oa(n,e=tt){if(!v(n))return e;const t=gn(n["rows"]);if(t!==void 0)return Math.max(t,e);let o=e;const i=n["sections"];if(Array.isArray(i)){for(const r of i){const s=v(r)?r["items"]:void 0;if(!Array.isArray(s))continue;for(const a of s){if(!v(a))continue;o=Math.max(o,(gn(a["row"])??1)+(gn(a["rowSpan"])??1)-1)}}}return o}function jc(n,e=tt,t=false){const o=Array.isArray(n)?n:[];const i=o.map(s=>oa(s,e));if(!t)return i;const r=i.reduce((s,a)=>Math.max(s,a),e);return i.map(()=>r)}function $e(n,e){const t=v(n)&&Array.isArray(n["items"])?n["items"]:[];const o=na(v(n)?n["columns"]:void 0);const i=Math.max(1,Math.floor(e));const r=t.map(()=>null);const s=/* @__PURE__ */new Set;const a=(g,y,b,x)=>{for(let T=g;T<g+b;T++)for(let k=y;k<y+x;k++)if(s.has(`${T}:${k}`))return false;return true};const l=g=>{for(let y=g.col;y<g.col+g.colSpan;y++)for(let b=g.row;b<g.row+g.rowSpan;b++)s.add(`${y}:${b}`)};const d=[];t.forEach((g,y)=>{if(!v(g))return;const b=Me(g);const x=Rt(g);d.push({index:y,col:b==="all"?1:gn(g["col"]),row:x==="all"?1:gn(g["row"]),colSpan:b==="all"?o:b,rowSpan:x==="all"?i:x})});const c=g=>v(g)&&(Me(g)==="all"||gn(g["col"])!==void 0);const p=g=>v(g)&&(Rt(g)==="all"||gn(g["row"])!==void 0);const h=(g,y,b)=>{const x={col:y,row:b,colSpan:g.colSpan,rowSpan:g.rowSpan,colFixed:c(t[g.index]),rowFixed:p(t[g.index])};r[g.index]=x;l(x)};for(const g of d)if(g.col!==void 0&&g.row!==void 0)h(g,g.col,g.row);const u=/* @__PURE__ */new Map;for(const g of d){if(g.col===void 0||g.row!==void 0)continue;let y=u.get(g.col)??1;while(!a(g.col,y,g.colSpan,g.rowSpan))y++;u.set(g.col,y+g.rowSpan);h(g,g.col,y)}let f=1;let m=1;for(const g of d){if(g.col!==void 0)continue;if(g.row!==void 0){if(g.row<m)f++;m=g.row;while(!a(f,m,g.colSpan,g.rowSpan))f++}else{for(;;){const y=m+g.rowSpan-1<=i||m===1;if(y&&a(f,m,g.colSpan,g.rowSpan))break;if(y)m++;else{f++;m=1}}}h(g,f,m)}return r}function ia(n){const e=[];for(let t=1;t<n.length;t++){const o=n[t];if(!o)continue;for(let i=0;i<t;i++){const r=n[i];if(!r)continue;if(r.col<o.col+o.colSpan&&o.col<r.col+r.colSpan&&r.row<o.row+o.rowSpan&&o.row<r.row+r.rowSpan)e.push([i,t])}}return e}function ra(n,e){let t=na(v(n)?n["columns"]:void 0);for(const o of e)if(o)t=Math.max(t,o.col+o.colSpan-1);return t}function Vf(n,e,t,o,i,r){const s=v(n)&&Array.isArray(n["items"])?n["items"]:[];const a=Math.max(1,Math.floor(e));const l=/* @__PURE__ */new Set;$e(n,a).forEach((p,h)=>{if(!p||h===r)return;const u=s[h];const f=v(u)&&Me(u)==="all";if(!f&&!(p.col<t&&t<p.col+p.colSpan))return;for(let m=p.row;m<p.row+p.rowSpan;m++)l.add(m)});const d=Math.max(1,Math.min(Math.floor(o),a));let c=null;for(let p=1;p+d-1<=a;p++){let h=true;for(let u=p;u<p+d;u++)if(l.has(u))h=false;if(h&&(c===null||Math.abs(p-i)<Math.abs(c-i)))c=p}return c}function Pc(n,e,t=1,o=1){const i=Math.max(1,Math.floor(e));const r=$e(n,i);const s=ra(n,r);const a=Math.max(1,Math.floor(t));const l=o==="all"?i:Math.max(1,Math.min(Math.floor(o),i));const d=(c,p)=>r.some(h=>h!==null&&h.col<c+a&&c<h.col+h.colSpan&&h.row<p+l&&p<h.row+h.rowSpan);for(let c=1;c<=s;c++)for(let p=1;p+l-1<=i;p++)if(!d(c,p))return{col:c,row:p};return{col:s+1,row:1}}function Zo(n,e,t){const o={};const i={...n};delete i["rowSpan"];const r=Rt(i);let s=Rt(n);const a=Me(n);if(e.rowSpan!==null){s=e.rowSpan>=t?"all":Math.max(1,Math.floor(e.rowSpan));o.rowSpan=s===r?void 0:s}if(e.colSpan!==null)o.colSpan=Math.max(1,Math.floor(e.colSpan))<=1?void 0:Math.floor(e.colSpan);o.col=a==="all"&&e.colSpan===null?void 0:Math.max(1,Math.floor(e.col));o.row=s==="all"?void 0:Math.max(1,Math.floor(e.row));return o}function Hf(n,e){const t=Vs(n);if(!t)return{ok:false,reason:"call"};if(!e.has(t.callee))return{ok:false,reason:"function",callee:t.callee};const o=[];for(const i of t.args){const r=Lf(i);if(!r)return{ok:false,reason:"argument",callee:t.callee,argument:i};o.push(r.value)}return{ok:true,callee:t.callee,args:o}}const Wc=/^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*$/;const Kc=/^(?:this\.)?([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)(?::(\d+))?$/;const wr=qn.join(", ");function vr(n){const e=/* @__PURE__ */new Map;for(const t of n.split(/[\s,;]+/)){const o=Kc.exec(t);if(!o)continue;const i=o[2]===void 0?1:Number(o[2]);if(i>=1)e.set(o[1],i-1)}return e}function _c(n){const e=/* @__PURE__ */new Set;const t=[];for(const o of n.split(/[\s,;]+/)){const i=Kc.exec(o);if(!i||i[2]!==void 0&&Number(i[2])<1||e.has(i[1]))continue;e.add(i[1]);t.push(i[2]===void 0?i[1]:`${i[1]}:${i[2]}`)}return t}const xr=vr(wr);function sa(n){return _c(n).filter(e=>!xr.has(e.split(":")[0]))}function qf(n){return _c(n).map(e=>e.split(":")[0]).filter(e=>xr.has(e))}function Uf(n){return new Map([...vr(n),...xr])}const aa=xr;function Gc(n,e=aa){const t=Vs(n);if(!t)return void 0;const o=e.get(t.callee);return o===void 0||t.args[o]===void 0?void 0:Hs(t.args[o])}function bt(n,e=aa){if(typeof n==="string")return n;const t=Lt(n);if(t===void 0)return void 0;const o=Gc(t,e);return o===void 0?Bo(t):String(o)}function to(n,e=aa){for(const t of n)if(t!==void 0&&t!==null)return bt(t,e)??String(t);return""}function _(n){const e=n.length;if(e===0)return"root";if(typeof n[0]!=="number")return"property";if(e===1)return"tab";if(n[1]!=="sections")return"property";if(e===2)return"property";if(typeof n[2]!=="number")return"property";if(e===3)return"section";if(n[3]!=="items")return"property";if(e===4||typeof n[4]!=="number")return"property";if(e===5)return"item";if(e===6&&n[5]==="compact")return"compact";for(let t=5;t<e;t+=2){if(n[t]!=="choices"||t+1>=e||typeof n[t+1]!=="number")return"property"}return e%2===1?"choice":"property"}function bn(n){for(let e=n.length;e>=1;e--){const t=n.slice(0,e);const o=_(t);if(o==="tab"||o==="section"||o==="item"||o==="choice")return t}return[]}function no(n){const e=_(n);return e==="tab"||e==="section"||e==="item"||e==="choice"?n.slice(0,-1):null}const kr={tab:["id","label","rows","contextual","hidden","showForTags","keytip","sections"],section:["id","title","icon","columns","compactColumns","collapsePriority","collapsible","launcher","hidden","showForTags","items"],item:["type","id","label","icon","iconColor","tooltip","description","action","shortcut","keytip","col","row","colSpan","rowSpan","justify","align","value","checked","disabled","disabledReason","hidden","showForTags","inputs","choices","compact"],choice:["kind","label","source","value","icon","preview","style","shortcut","checked","disabled","choices"]};function Qo(n,e,t,o){const i={};if(Object.prototype.hasOwnProperty.call(n,e)){for(const[l,d]of Object.entries(n))Object.defineProperty(i,l,{value:l===e?t:d,enumerable:true,writable:true,configurable:true});return i}const r=o.indexOf(e);const s=Object.entries(n);let a=s.length;if(r>=0){a=0;s.forEach(([l],d)=>{const c=o.indexOf(l);if(c>=0&&c<r)a=d+1})}s.splice(a,0,[e,t]);for(const[l,d]of s)Object.defineProperty(i,l,{value:d,enumerable:true,writable:true,configurable:true});return i}function Yf(n){const e=_(n);return e==="tab"||e==="section"||e==="item"||e==="choice"?kr[e]:[]}const ne=(n,e=null)=>({root:n,selected:e});function Bc(n){const e=/* @__PURE__ */new Set;if(!Array.isArray(n))return e;for(const t of n){const o=v(t)&&Array.isArray(t["sections"])?t["sections"]:[];for(const i of o){const r=v(i)&&Array.isArray(i["items"])?i["items"]:[];for(const s of r)if(v(s)&&typeof s["id"]==="string")e.add(s["id"])}}return e}function Vc(n){const e=/* @__PURE__ */new Set;if(Array.isArray(n)){for(const t of n)if(v(t)&&typeof t["id"]==="string")e.add(t["id"])}return e}function la(n,e){const t=/* @__PURE__ */new Set;const o=O(n,[e,"sections"]);if(Array.isArray(o)){for(const i of o)if(v(i)&&typeof i["id"]==="string")t.add(i["id"])}return t}function yn(n,e){const t=e.trim()===""?"item":e.trim();if(!n.has(t))return t;const o=t.replace(/\d+$/,"")||t;for(let i=2;;i++)if(!n.has(`${o}${i}`))return`${o}${i}`}const Jf=n=>n.replace(/-([a-z])/g,(e,t)=>t.toUpperCase()).replace(/[^A-Za-z0-9_$]/g,"")||"item";function Hc(n){if(!Array.isArray(n)&&v(n)&&Array.isArray(n["tabs"]))return{value:n["tabs"],unwrapped:true};return{value:n,unwrapped:false}}const Xf=n=>Array.isArray(n)?n:[];function Sr(n,e,t){const o=Xf(n);const i=yn(Vc(o),"tab");const r={id:i,label:e("New tab"),sections:[{id:"section",title:e("New section"),items:[]}]};const s=t===void 0?o.length:Math.max(0,Math.min(t,o.length));return{root:gt(o,[],s,r),selected:[s]}}function qc(n,e,t,o){if(!v(O(n,[e])))return ne(n);const i=yn(la(n,e),"section");const r=O(n,[e,"sections"]);const s=Array.isArray(r)?r.length:0;const a=o===void 0?s:Math.max(0,Math.min(o,s));return{root:gt(n,[e,"sections"],a,{id:i,title:t("New section"),items:[]}),selected:[e,"sections",a]}}function Zf(n,e,t,o,i,r){if(_(e)!=="section"||!v(O(n,e)))return ne(n);const s=yn(Bc(n),Jf(t));const a=J(t);let l=a?a.create(s,o):{type:t,id:s,label:o("Item")};if(r){l=Qo(l,"col",Math.max(1,Math.floor(r.col)),kr.item);if(!a||a.defaultRowSpan(v(l["inputs"])?l["inputs"]:{})!=="all")l=Qo(l,"row",Math.max(1,Math.floor(r.row)),kr.item)}const d=O(n,[...e,"items"]);const c=Array.isArray(d)?d.length:0;const p=i===void 0?c:Math.max(0,Math.min(i,c));return{root:gt(n,[...e,"items"],p,l),selected:[...e,"items",p]}}function Uc(n,e){const t=O(n,e.slice(0,5));return eo(v(t)?J(t["type"]):void 0)}function Qf(n,e,t,o,i){const r=O(n,e);if(_(e)==="choice"&&v(r)&&(!Uc(n,e).submenu||(r["kind"]??"item")!=="item"))return ne(n);if(_(e)==="item"&&v(r)&&J(r["type"])?.choices==="none")return ne(n);return Yc(n,e,t,o,i)}function Yc(n,e,t,o,i){const r=_(e);const s=O(n,e);if(r!=="item"&&r!=="choice"||!v(s))return ne(n);if(i!==void 0&&i.kind!=="item"&&!Uc(n,e).structure)return ne(n);const a=[...e,"choices"];const l=O(n,a);if(l!==void 0&&!Array.isArray(l))return ne(n);const d=Array.isArray(l)?l:[];const c=o===void 0?d.length:Math.max(0,Math.min(o,d.length));return{root:gt(n,a,c,em(i,d,t)),selected:[...a,c]}}function em(n,e,t){switch(n?.kind){case"separator":return{kind:"separator"};case"header":return{kind:"header",label:t("Heading")};case"source":return{kind:"source",label:t(n.label),source:n.source??""}}const o=new Set(e.map(s=>v(s)?String(s["value"]??s["label"]??""):""));const i=t("Choice");let r=i;for(let s=2;o.has(r);s++)r=`${i} ${s}`;return{label:r}}function tm(n,e,t,o,i){const r=no(e);const s=e[e.length-1];if(_(e)!=="choice"||r===null||typeof s!=="number"||!v(O(n,e)))return ne(n);return Yc(n,bn(r),t,o==="before"?s:s+1,i)}function Jc(n,e){const t=no(e);const o=t?O(n,t):void 0;const i=e[e.length-1];if(!t||!Array.isArray(o)||typeof i!=="number"||o[i]===void 0)return ne(n);let r=Qn(n,e);if(o.length>1)return{root:r,selected:[...t,Math.min(i,o.length-2)]};if(_(e)==="choice")r=Qn(r,t);return{root:r,selected:t.length===0?null:bn(t)}}function nm(n,e,t){const o=_(e);const i=Ys(t);const r=Vc(n);const s=Bc(n);const a=l=>{if(!Array.isArray(l))return;for(const d of l){if(!v(d))continue;const c=d["id"];if(typeof c!=="string")continue;const p=yn(s,c);s.add(p);d["id"]=p;if(d["action"]===c)d["action"]=p}};if(o==="tab"){if(typeof i["id"]==="string")i["id"]=yn(r,i["id"]);if(Array.isArray(i["sections"])){for(const l of i["sections"])if(v(l))a(l["items"])}}else if(o==="section"){const l=la(n,e[0]);if(typeof i["id"]==="string")i["id"]=yn(l,i["id"]);a(i["items"])}else if(o==="item"){a([i])}else if(o==="choice"&&(i["kind"]??"item")==="item"){const l=O(n,e.slice(0,-1));const d=new Set((Array.isArray(l)?l:[]).map(h=>v(h)?String(h["value"]??h["label"]??""):""));const c=String(i["value"]??i["label"]??"");let p=c;for(let h=2;d.has(p);h++)p=/\d$/.test(c)?`${c}-${h}`:`${c}${h}`;if(p!==c){if(typeof i["value"]==="string")i["value"]=p;else if(typeof i["label"]==="string")i["label"]=p}}return i}const At=n=>typeof n==="number"&&Number.isInteger(n)&&n>=1;function om(n,e,t,o){const i=Me(t)==="all"||At(t["col"]);const r=Rt(t)==="all"||At(t["row"]);if(!i||!r)return true;const s=O(n,e.slice(0,-2));const a=$e(s,o);const l=a[e[e.length-1]];if(!l)return true;const d=v(s)&&Array.isArray(s["items"])?s["items"]:[];const c=ra(s,a);const p=a.filter((y,b)=>y!==null&&v(d[b])&&Me(d[b])==="all");const h=(y,b)=>a.some(x=>x!==null&&y>=x.col&&y<x.col+x.colSpan&&b>=x.row&&b<x.row+x.rowSpan)||y>c&&p.some(x=>b>=x.row&&b<x.row+x.rowSpan);const u=(y,b,x,T)=>{for(let k=y;k<y+x;k++)for(let S=b;S<b+T;S++)if(h(k,S))return false;return true};const{colSpan:f,rowSpan:m}=l;if(Me(t)==="all"){const y=Array.from({length:Math.max(0,o-m+1-(l.row+m)+1)},(x,T)=>l.row+m+T);const b=Array.from({length:Math.max(0,l.row-1)},(x,T)=>T+1);for(const x of[...y,...b]){if(!u(1,x,Math.max(c,f),m))continue;delete t["col"];t["row"]=x;return true}return false}const g=Rt(t)==="all";for(let y=l.col;y<=c+1;y++){for(let b=y===l.col?l.row+m:1;b+m-1<=o;b++){if(!u(y,b,f,m))continue;t["col"]=y;if(g)delete t["row"];else t["row"]=b;return true}}return false}function im(n,e,t=tt){const o=no(e);const i=O(n,e);if(!o||!v(i))return ne(n);const r=e[e.length-1]+1;const s=nm(n,e,i);if(_(e)==="item"){if(!om(n,e,s,oa(O(n,e.slice(0,1)),t)))return ne(n,e);return{root:Tr(gt(n,o,r,s),e.slice(0,3)),selected:[...o,r]}}const a=gt(n,o,r,s);if(_(e)==="choice"&&e.length===7)return{root:ha(a,e.slice(0,5),e[6]),selected:[...o,r]};return{root:a,selected:[...o,r]}}function ca(n,e,t,o,i){let r=n;const s=O(n,[...e,"items"]);if(Array.isArray(s)){s.forEach((l,d)=>{if(d===t||!v(l))return;const c=Me(l);const p=l["col"];if(c==="all"||!At(p))return;const h=[...e,"items",d];if(p>=o)r=Se(r,h,"col",p+i).root;else if(i>0&&p+c>o)r=Se(r,h,"colSpan",c+i).root})}const a=O(r,[...e,"columns"]);if(typeof a==="number"&&Number.isInteger(a))r=Se(r,e,"columns",Math.max(1,a+i)).root;return r}function rm(n,e,t,o){const i=O(n,[...e,"items"]);if(!Array.isArray(i))return false;return i.every((r,s)=>{if(s===t||!v(r))return true;const a=Me(r);if(a==="all")return true;const l=r["col"];return At(l)&&!(l<=o&&o<l+a)})}function da(n,e,t){const o=O(n,e);const i=v(o)&&Array.isArray(o["items"])?o["items"]:null;if(!i)return null;const r=$e(o,t);let s=n;i.forEach((a,l)=>{const d=r[l];if(!v(a)||!d||Me(a)==="all"||At(a["col"]))return;s=Se(s,[...e,"items",l],"col",d.col).root});if(s===n)return n;return Xc(r,$e(O(s,e),t))?s:null}function sm(n,e,t,o,i=tt){const r=Math.max(1,Math.floor(o));const s=e.slice(0,3);const a=Fe(s,t)?da(n,t,i)??n:n;const l=O(a,e);if(_(e)!=="item"||!v(l))return{column:r,opens:true};const d=l["col"];const c=Me(l);if(!Fe(s,t)||!At(d)||c==="all"||!Array.from({length:c},(p,h)=>d+h).every(p=>rm(a,s,e[4],p)))return{column:r,opens:true};if(r>=d&&r<=d+c)return{column:d,opens:false};return{column:r,opens:true}}function am(n,e,t,o,i,r){if(_(e)!=="item"||!v(O(n,e))||_([...t,"items",0])!=="item")return ne(n,e);const s=da(n,t,r);if(s===null)return ne(n,e);const a=O(s,e);if(!v(a))return ne(n,e);const l=e.slice(0,3);const d=Fe(l,t);const c=Math.max(1,Math.floor(o));const p=Me(a);let h=s;let u=e;if(!d){const g=O(h,[...t,"items"]);const y=Zc(h,e,[...t,"items"],Array.isArray(g)?g.length:0);if(y.selected===null||y.root===h)return ne(n,e);h=y.root;u=y.selected}h=ca(h,t,u[4],c,p==="all"?1:p);const f=O(h,u);if(!v(f))return ne(n,e);const m=oo(h,u,Zo(f,{col:c,row:i,colSpan:null,rowSpan:null},r));return{root:m.root,selected:u}}function Xc(n,e){return n.every((t,o)=>{const i=e[o];if(t===null)return i===null;return i!==null&&i!==void 0&&i.col===t.col&&i.row===t.row&&i.colSpan===t.colSpan&&i.rowSpan===t.rowSpan})}function Ft(n,e,t){const o=O(n,e);const i=_(e)==="section"&&v(o)&&Array.isArray(o["items"])?o["items"]:null;if(!i)return n;const r=$e(o,t);let s=n;i.forEach((a,l)=>{const d=r[l];if(!v(a)||!d)return;const c=Zo(a,{col:d.col,row:d.row,colSpan:null,rowSpan:null},t);for(const p of["col","row"]){const h=c[p];if(h!==void 0&&!At(a[p]))s=Se(s,[...e,"items",l],p,h).root}});return s===n||Xc(r,$e(O(s,e),t))?s:n}function lm(n,e){if(!Array.isArray(n))return n;let t=n;n.forEach((o,i)=>{const r=v(o)?o["sections"]:void 0;if(!Array.isArray(r))return;r.forEach((s,a)=>{const l=[i,"sections",a];t=Ft(t,l,e(l))})});return t}function cm(n){if(!v(n))return[];const e=Me(n);const t=n["col"];if(e==="all"||!At(t))return[];return Array.from({length:e},(o,i)=>t+i)}function dm(n,e,t){const o=O(n,[...e,"items"]);if(_(e)!=="section"||!Array.isArray(o))return n;if(typeof O(n,[...e,"columns"])==="string")return n;const i=da(n,e,t);if(i===null)return n;let r=Infinity;let s=0;for(const p of O(i,[...e,"items"])){if(!v(p))continue;const h=Me(p);const u=p["col"];if(h==="all"||!At(u))continue;r=Math.min(r,u);s=Math.max(s,u+h-1)}if(!Number.isFinite(r))return n;const a=r-1;const l=O(i,[...e,"columns"]);const d=typeof l==="number"&&Number.isInteger(l);if(a===0&&!(d&&l>s))return n;let c=i;if(a>0){O(i,[...e,"items"]).forEach((p,h)=>{if(!v(p)||Me(p)==="all"||!At(p["col"]))return;c=Se(c,[...e,"items",h],"col",p["col"]-a).root})}return d?Se(c,e,"columns",s-a).root:c}function Tr(n,e){const t=O(n,[...e,"columns"]);const o=O(n,[...e,"items"]);if(typeof t!=="number"||!Number.isInteger(t)||!Array.isArray(o))return n;const i=Math.max(0,...o.flatMap(r=>cm(r)));return i>t?Se(n,e,"columns",i).root:n}function pa(n,e,t,o){if(_(e)!=="item"||!v(O(n,e)))return null;const i=e.slice(0,3);const r=e[4];let s=Ft(n,i,o);const a=$e(O(s,i),o)[r];if(!a)return null;const l=(S,$)=>Math.max(1,Math.floor(S??$));const d=l(t.col,a.col);const c=l(t.row,a.row);const p=l(t.colSpan,a.colSpan);const h=l(t.rowSpan,a.rowSpan);if(c+h-1>o)return null;const u=d+p-1;const f=a.col+a.colSpan-1;const m=(S,$)=>$e(O(s,i),o).some((A,R)=>R!==r&&A!==null&&S>=A.col&&S<A.col+A.colSpan&&$>=A.row&&$<A.row+A.rowSpan);const g=S=>{for(let $=c;$<c+h;$++)if(m(S,$))return true;return false};for(let S=f+1;S<=u;S++)if(g(S))s=ca(s,i,r,S,1);let y=a.col;let b=0;for(let S=a.col-d;S>0;S--){if(y>1&&!g(y-1)){y-=1}else{s=ca(s,i,null,y,1);b+=1}}if(d>a.col)y=d+b;for(let S=c;S<c+h;S++)for(let $=y;$<y+p;$++)if(m($,S))return null;const x=O(s,e);if(!v(x))return null;const T={col:y,row:c,colSpan:p!==a.colSpan?p:null,rowSpan:h!==a.rowSpan?h:null};const k=oo(s,e,Zo(x,T,o));return{root:Tr(k.root,i),selected:k.selected}}function pm(n,e,t,o){const i=O(n,[...e,"items"]);if(_(e)!=="section"||!Array.isArray(i)||o.size===0)return n;let r=Ft(n,e,t);const s=$e(O(r,e),t);const a=/* @__PURE__ */new Map;const l=p=>`${p.col}:${p.colSpan}`;s.forEach((p,h)=>{const u=o.get(h);if(!p||u===void 0||!v(i[h])||Me(i[h])==="all")return;a.set(l(p),Math.max(a.get(l(p))??1,Math.floor(u)))});const d=s.map((p,h)=>({cell:p,index:h})).filter(p=>p.cell!==null&&o.has(p.index));d.sort((p,h)=>p.cell.col-h.cell.col||p.cell.row-h.cell.row||p.index-h.index);let c=false;for(const{cell:p,index:h}of d){const u=a.get(l(p))??1;const f=$e(O(r,e),t)[h];const m=i[h];if(!f||u<=f.colSpan||!v(m)||Me(m)==="all")continue;const g=pa(r,[...e,"items",h],{colSpan:u},t);if(g){r=g.root;c=true}}return c?r:n}function hm(n,e,t,o,i){if(_(e)!=="item"||_(t)!=="section"||!v(O(n,e))||!v(O(n,t)))return ne(n,e);const r=e.slice(0,3);const s=Fe(r,t);let a=Ft(n,r,i(r));let l=e;if(!s){a=Ft(a,t,i(t));const p=O(a,[...t,"items"]);const h=Zc(a,e,[...t,"items"],Array.isArray(p)?p.length:0);if(h.selected===null||h.root===a)return ne(n,e);a=h.root;l=h.selected}const d=O(a,l);if(!v(d))return ne(n,e);const c=oo(a,l,Zo(d,{col:o.col,row:o.row,colSpan:null,rowSpan:null},i(t)));return{root:Tr(c.root,t),selected:c.selected}}function um(n,e,t,o,i,r,s){if(_(e)!=="section"||!v(O(n,e)))return ne(n);const a=Ft(n,e,r);let l=s;if(!l){const f=J(t);const m=f?f.create("probe",o):{type:t,id:"probe",label:o("Item")};const g=Me(m);l=Pc(O(a,e),r,g==="all"?1:g,Rt(m))}const d=Zf(a,e,t,o,i,l);const c=d.selected?O(d.root,d.selected):void 0;const p=O(d.root,[...e,"columns"]);if(!v(c)||typeof p!=="number"||!Number.isInteger(p))return d;const h=Me(c);const u=l.col+(h==="all"?1:h)-1;return u>p?{root:Se(d.root,e,"columns",u).root,selected:d.selected}:d}function fm(n,e,t){if(_(e)!=="item")return Jc(n,e);return Jc(Ft(n,e.slice(0,3),t),e)}function mm(n,e,t,o){if(_(e)!=="item"||!v(O(n,e)))return null;const i=e.slice(0,3);const r=e[4];let s=Ft(n,i,o);const a=$e(O(s,i),o);const l=a[r];if(!l)return null;if(!t)return{root:oo(s,e,{colSpan:void 0,col:l.col}).root,selected:e};if(a.some((c,p)=>p!==r&&c!==null&&c.row<l.row+l.rowSpan&&l.row<c.row+c.rowSpan))return null;const d=O(s,[...i,"columns"]);if(typeof d!=="number"&&typeof d!=="string")s=Se(s,i,"columns",Math.max(1,ra(O(s,i),a))).root;return{root:oo(s,e,{colSpan:"all",col:void 0}).root,selected:e}}function gm(n,e,t,o){if(_(t)!=="item")return n;const i=t.slice(0,3);const r=t[4];const s=f=>ia($e(O(f,i),o)).some(([m,g])=>m===r||g===r);const a=O(n,t);if(!v(a)||Me(a)==="all"||!s(n)||s(e))return n;const l=Ft(n,i,o);const d=O(l,i);const c=$e(d,o)[r];if(!c||!v(d)||!Array.isArray(d["items"]))return n;const p={...d,items:d["items"].filter((f,m)=>m!==r)};const h=Pc(p,o,c.colSpan,Rt(a)==="all"?"all":c.rowSpan);const u=O(l,t);return Tr(oo(l,t,Zo(u,{col:h.col,row:h.row,colSpan:null,rowSpan:null},o)).root,i)}function bm(n,e,t){if(!Array.isArray(n)||!v(n[e]))return ne(n);const o=Math.max(0,Math.min(Math.floor(t),n.length-1));return o===e?ne(n,[e]):{root:Vo(n,[],e,o),selected:[o]}}function ym(n,e,t,o){const i=O(n,e);const r=O(n,[t,"sections"]);if(_(e)!=="section"||!v(i)||!Array.isArray(r))return ne(n,e);if(e[0]===t){const d=e[2];const c=Math.max(0,Math.min(Math.floor(o),r.length-1));return c===d?ne(n,e):{root:Vo(n,[t,"sections"],d,c),selected:[t,"sections",c]}}const s=i["id"];const a=typeof s==="string"?Qo(i,"id",yn(la(n,t),s),kr.section):i;const l=Math.max(0,Math.min(Math.floor(o),r.length));return{root:Qn(gt(n,[t,"sections"],l,a),e),selected:[t,"sections",l]}}function wm(n,e,t){const o=no(e);if(!o)return ne(n);const i=e[e.length-1];const r=i+t;const s=O(n,o)?.length??0;if(r<0||r>=s||t===0)return ne(n,e);return{root:Vo(n,o,i,r),selected:[...o,r]}}const vm=n=>_([...n,0]);function Zc(n,e,t,o){const i=no(e);const r=O(n,e);const s=O(n,t);if(!i||r===void 0||!Array.isArray(s)||_(e)!==vm(t))return ne(n);if(t.length>=e.length&&e.every((p,h)=>t[h]===p))return ne(n);const a=Math.max(0,Math.min(Math.floor(o),s.length));if(Fe(i,t)){const p=e[e.length-1];const h=a>p?a-1:a;return h===p?ne(n,e):{root:Vo(n,i,p,h),selected:[...i,h]}}let l=r;if(_(e)==="item"&&v(r)){l={};for(const[p,h]of Object.entries(r))if(p!=="col"&&p!=="row")Object.defineProperty(l,p,{value:h,enumerable:true,writable:true,configurable:true})}const d=gt(n,t,a,l);const c=xm(e,t,a);return{root:Qn(d,c),selected:[...km(t,c),a]}}function xm(n,e,t){if(n.length<=e.length||!e.every((r,s)=>n[s]===r))return n;const o=n[e.length];if(typeof o!=="number"||o<t)return n;const i=[...n];i[e.length]=o+1;return i}function km(n,e){const t=e.slice(0,-1);const o=e[e.length-1];if(typeof o!=="number"||n.length<=t.length||!t.every((s,a)=>n[a]===s))return n;const i=n[t.length];if(typeof i!=="number"||i<o)return n;const r=[...n];r[t.length]=i-1;return r}function Se(n,e,t,o){const i=O(n,e);if(!v(i))return ne(n);if(o===void 0)return{root:Object.prototype.hasOwnProperty.call(i,t)?be(n,[...e,t],void 0):n,selected:bn(e)};return{root:be(n,e,Qo(i,t,o,Yf(e))),selected:bn(e)}}function Qc(n,e,t,o){const i=O(n,e);if(!v(i))return ne(n);const r=v(i["inputs"])?i["inputs"]:{};let s;if(o===void 0){s={};for(const[a,l]of Object.entries(r))if(a!==t)Object.defineProperty(s,a,{value:l,enumerable:true,writable:true,configurable:true})}else{s=Qo(r,t,o,J(String(i["type"]))?.inputs.map(a=>a.name)??[])}return Se(n,e,"inputs",Object.keys(s).length===0?void 0:s)}function ha(n,e,t){const o=O(n,e);if(!v(o)||_(e)!=="item"||o["type"]!=="toggle-group")return n;const i=o["inputs"];const r=o["choices"];if(!v(i)||i["exclusive"]!==true||!Array.isArray(r))return n;const s=r.flatMap((d,c)=>v(d)&&d["checked"]===true?[c]:[]);const a=t!==void 0&&s.includes(t)?t:s[0];let l=n;for(const d of s)if(d!==a)l=Se(l,[...e,"choices",d],"checked",void 0).root;return l}function oo(n,e,t){let o=ne(n,e);for(const i of["col","row","colSpan","rowSpan"]){if(!(i in t))continue;o=Se(o.root,e,i,t[i])}return{root:o.root,selected:e}}function Sm(n,e,t){const o=O(n,e);if(!v(o))return ne(n);const i=o["id"];let r=Se(n,e,"id",t);if(_(e)==="item"&&typeof i==="string"&&o["action"]===i)r=Se(r.root,e,"action",t);return{root:r.root,selected:e}}function ed(n,e){const t=(i,r)=>{const s=i["choices"];if(!Array.isArray(s))return[];const a=[];s.forEach((l,d)=>{if(!v(l))return;const c=[...r,"choices",d];const p=l["kind"];const h=p==="separator"?"—":to([l["label"],l["source"],l["value"]],e);a.push({path:c,kind:"choice",title:h,children:t(l,c)})});return a};const o=[];(Array.isArray(n)?n:[]).forEach((i,r)=>{if(!v(i))return;const s=[r];const a=[];(Array.isArray(i["sections"])?i["sections"]:[]).forEach((l,d)=>{if(!v(l))return;const c=[...s,"sections",d];const p=[];(Array.isArray(l["items"])?l["items"]:[]).forEach((h,u)=>{if(!v(h))return;const f=[...c,"items",u];const m=[h["label"],h["tooltip"],h["id"],h["type"]].find(g=>(bt(g,e)??"")!=="");p.push({path:f,kind:"item",title:bt(m,e)??"",type:typeof h["type"]==="string"?h["type"]:void 0,children:t(h,f)})});a.push({path:c,kind:"section",title:to([l["title"],l["id"]],e),children:p})});o.push({path:s,kind:"tab",title:to([i["label"],i["id"]],e),children:a})});return o}function Tm(n,e){const t=Array.from({length:n.length+1},(o,i)=>[i,...Array(e.length).fill(0)]);for(let o=1;o<=e.length;o++)t[0][o]=o;for(let o=1;o<=n.length;o++){for(let i=1;i<=e.length;i++){const r=n[o-1]===e[i-1]?0:1;t[o][i]=Math.min(t[o-1][i]+1,t[o][i-1]+1,t[o-1][i-1]+r);if(o>1&&i>1&&n[o-1]===e[i-2]&&n[o-2]===e[i-1])t[o][i]=Math.min(t[o][i],t[o-2][i-2]+1)}}return t[n.length][e.length]}function io(n,e){const t=n.toLowerCase();let o;let i=Infinity;for(const r of e){const s=Tm(t,r.toLowerCase());if(s<i){o=r;i=s}}return o!==void 0&&i<=Math.max(1,Math.min(2,Math.floor(o.length/3)))?o:void 0}function td(n){const e={error:0,warning:1,info:2};return n.map((t,o)=>({problem:t,index:o})).sort((t,o)=>e[t.problem.severity]-e[o.problem.severity]||t.index-o.index).map(t=>t.problem)}function tk(n,e){return`${n.code}:${q(n.path)}:${e}`}function Mm(n){const e=[];let t=0;while(t<n.length){while(n[t]===" ")t++;let o=-1;if(n[t]==="/"){const r=/\/[a-z]*\s*(?:,|$)/g;r.lastIndex=t+1;const s=r.exec(n);if(s){o=n.indexOf(",",s.index);if(o===-1)o=n.length}}if(o===-1)o=n.indexOf(",",t);if(o===-1)o=n.length;const i=n.slice(t,o).trim();if(i!=="")e.push(i);t=o+1}return e}const $m=n=>n.filter(e=>typeof e==="string").join(", ");function Am(n){const e=[];let t=0;while(t<n.length){while(n[t]===" ")t++;let o=-1;if(n[t]==="/"){const r=/\/[a-z]*\s*(?:&|$)/g;r.lastIndex=t+1;const s=r.exec(n);if(s)o=n.indexOf("&",s.index)}else{o=n.indexOf("&",t)}if(o===-1)o=n.length;const i=n.slice(t,o).trim();if(i!=="")e.push(i);t=o+1}return e}function Cm(n){const e=Am(n);if(e.length===0)return{kind:"empty"};for(const t of e){const o=/^\/(.*)\/([a-z]*)$/s.exec(t);if(!o)continue;try{new RegExp(o[1],o[2])}catch{return{kind:"expression",part:t}}}return null}const nd={aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#008000",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",rebeccapurple:"#663399",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"};function Om(n){const e=n.trim().toLowerCase();if(e==="transparent")return"#00000000";return Object.hasOwn(nd,e)?nd[e]:void 0}function Nm(n){if(typeof n!=="string")return void 0;const e=Om(n);return e===void 0?void 0:{name:n,code:e}}const Im=/* @__PURE__ */new Set(["large-button","button","styled-button","split-button","dropdown-button","toggle-button","checkbox","radio","label","table-picker"]);const Dm={separator:["kind"],header:["kind","label"],source:["kind","label","source"]};const od={separator:"A separator",header:"A heading",source:"A block of menu items"};const id=n=>v(n)&&"$fn"in n?String(n["$fn"]):void 0;const rd={ctrl:"ctrl",control:"ctrl",mod:"mod",cmd:"meta",command:"meta",meta:"meta",win:"meta",alt:"alt",option:"alt",opt:"alt",shift:"shift"};function sd(n){const e=n.split("+").map(o=>o.trim());if(e.length===0||e.some(o=>o==="")){if(!/\+\+$/.test(n.trim()))return null;const o=n.trim().slice(0,-2).split("+").map(i=>i.trim());return ad(o,"+")}const t=e[e.length-1];return ad(e.slice(0,-1),t)}const Em=/* @__PURE__ */new Set(["enter","return","esc","escape","tab","space","backspace","delete","del","insert","ins","home","end","pageup","pagedown","up","down","left","right","arrowup","arrowdown","arrowleft","arrowright","plus","minus","comma","period","pause","printscreen"]);const zm=n=>[...n].length===1||/^f([1-9]|1\d|2[0-4])$/i.test(n)||Em.has(n.toLowerCase());function ad(n,e){const t=/* @__PURE__ */new Set;for(const o of n){const i=rd[o.toLowerCase()];if(!i)return null;t.add(i)}if(rd[e.toLowerCase()]||!zm(e))return null;return[...["ctrl","mod","meta","alt","shift"].filter(o=>t.has(o)),e.toLowerCase()].join("+")}function ua(n,e){if(v(n)){for(const t of["label","tooltip","id","type"]){const o=bt(n[t]);if(o!==void 0&&o!=="")return o}}return`#${e+1}`}function Zt(n,e){const t=[];let o=n;for(let i=0;i<e.length;i++){const r=e[i];o=Array.isArray(o)&&typeof r==="number"?o[r]:v(o)&&typeof r==="string"?o[r]:void 0;if(o===void 0)break;if(typeof r==="number"&&v(o)){const s=e[i-1];t.push(s==="choices"?to([o["label"],o["value"],`#${r+1}`]):i===0?to([o["label"],o["id"],`#${r+1}`]):s==="sections"?to([o["title"],o["id"],`#${r+1}`]):ua(o,r))}else if(typeof r==="string"&&r!=="sections"&&r!=="items"&&r!=="choices"){t.push(r)}}return t.join(" › ")}function Lm(n,e={}){const t=[];const o=e.shortcutKey??sd;const i=new Set(e.customTypes??[]);const r=e.defaultRows??tt;const s=(k,S,$,A,R={})=>{t.push({code:S,severity:k,template:A,params:R,path:$})};const a=(k,S,$,A,R)=>{for(const j of Object.keys(k)){const P=$.find(F=>F.key===j);if(P){const F=k[j];const U=Wf(P,F);if(U)s("error","value",[...S,j],U.template,U.params);else if(Hn(F)!==void 0&&!P.bind)s("error","signal",[...S,j],`The property "{key}" of {what} takes no signal: the library reads it once, as a plain value. Write the value, or a call such as =tr('Home') that the loader turns into one.`,{key:j,what:Mr(R)});else if(id(F)!==void 0)s("error","function",[...S,j],"The property \"{key}\" of {what} takes no function. Write {\"$bind\": \"{name}\"} for a signal of the application, or the value itself.",{key:j,what:Mr(R),name:id(F)??""})}else if(!A.includes(j)){if(j==="component"&&(R==="item"||R==="compact")){s("warning","component",[...S,j],"A component cannot be written in JSON. Register the control under a name in the application and use that name as the \"type\".",{});continue}const F=io(j,A);if(F)s("warning","unknown",[...S,j],"The property \"{key}\" is not part of {what}. Did you mean \"{suggestion}\"?",{key:j,what:Mr(R),suggestion:F});else s("warning","unknown",[...S,j],"The property \"{key}\" is not part of {what}, so the ribbon ignores it.",{key:j,what:Mr(R)})}}};const l=(k,S)=>{const $=k["showForTags"];if(!Array.isArray($))return;$.forEach((A,R)=>{if(typeof A!=="string")return;const j=Cm(A);if(j?.kind==="empty")s("warning","mask",[...S,"showForTags",R],"The mask is empty, so it matches no window.");else if(j?.kind==="expression")s("warning","mask",[...S,"showForTags",R],"The part {part} of the mask is not a valid regular expression, so the mask matches no window.",{part:j.part})})};const d=/* @__PURE__ */new Map;const c=/* @__PURE__ */new Map;const p=/* @__PURE__ */new Map;const h=(k,S)=>{if(typeof k!=="string")return;if(k.trim()===""){s("warning","shortcut",S,"The shortcut is empty.");return}const $=o(k);if($===null){s("error","shortcut",S,"The shortcut \"{shortcut}\" is not valid. Write it like \"Ctrl+B\" or \"Ctrl+Shift+S\".",{shortcut:k});return}const A=p.get($);if(A)s("warning","shortcut-twice",S,"The shortcut \"{shortcut}\" is also used by \"{other}\".",{shortcut:k,other:Zt(n,A.path)});else p.set($,{path:S.slice(0,-1),shortcut:k})};const u=(k,S)=>{if(typeof k==="string"&&k!==""&&e.knownIcon&&!e.knownIcon(k))s("info","icon",S,"The icon \"{icon}\" is not in the registry of this editor. It is fine when the application has it.",{icon:k})};const f=(k,S)=>{if(Array.isArray(k))k.forEach(($,A)=>f($,[...S,A]));else if(v(k)){if("$fn"in k){const $=k["$fn"];if(typeof $!=="string"||!Wc.test($))s("error","function",S,"A function is written as {\"$fn\": \"name\"} with the name of a function of the application.");else if(Object.keys(k).length!==1)s("error","function",S,"A function is written as {\"$fn\": \"name\"}, with nothing else in the object: the loader takes an object with more keys for plain data.")}else for(const[$,A]of Object.entries(k))f(A,[...S,$])}};const m=(k,S)=>{const $=Nm(k);if($)s("warning","color-name",S,"The color picker of the library reads a code, not the name of a color: it shows no color for \"{name}\". Its code is {code}.",$)};const g=(k,S,$,A)=>{if(B(k))return;if(!v(k)){s("error","value",S,"The property \"{key}\" must be an object.",{key:"inputs"});return}f(k,S);if(!A)return;for(const[R,j]of Object.entries(k)){const P=A.inputs.find(U=>U.name===R);if(!P){const U=io(R,A.inputs.map(Z=>Z.name));if(R==="item")s("error","input",[...S,R],"The input \"item\" is set by the ribbon itself.");else if(U)s("error","input",[...S,R],"\"{name}\" is not an input of the control \"{type}\". Angular refuses it (NG0303). Did you mean \"{suggestion}\"?",{name:R,type:$??"",suggestion:U});else s("error","input",[...S,R],"\"{name}\" is not an input of the control \"{type}\". Angular refuses it (NG0303).",{name:R,type:$??""});continue}if(P.kind==="function"){const U=zt(j)!==void 0||v(j)&&typeof j["$fn"]==="string"&&Object.keys(j).length===1;if(!U)s("error","function",[...S,R],"The input \"{name}\" is a function. Write it as {\"$fn\": \"name\"} and register the function in the application.",{name:R});continue}if(Hn(j)!==void 0){s("error","signal",[...S,R],"The input \"{name}\" takes no signal: the ribbon passes the inputs to the control as they are. Write the value, or a call that the loader turns into one.",{name:R});continue}const F=Bf(P,j);if(F)s("error","value",[...S,R],F.template,F.params)}if(A.type==="color-picker"){m(k["automatic"],[...S,"automatic"]);const R=k["colors"];if(Array.isArray(R))R.forEach((j,P)=>m(j,[...S,"colors",P]))}if(A.type==="progress-bar"||A.type==="progress-ring"){const{min:R,max:j}=k;if(typeof R==="number"&&typeof j==="number"&&j<=R)s("warning","range",[...S,"max"],"The \"max\" has to be more than the \"min\", else the library draws the range from 0 to 100.")}};let y=false;const b=(k,S,$,A,R=false)=>{const j=/* @__PURE__ */new Set;if(B(k)){if(R)s("error","signal",S,"The submenu of a choice is a list of choices: the library takes no signal and no code here (the \"choices\" of an item can be a signal).");return j}if(!Array.isArray(k)){s("error","value",S,"The property \"{key}\" must be a list.",{key:"choices"});return j}const P=/* @__PURE__ */new Set;k.forEach((F,U)=>{const Z=[...S,U];if(B(F)){y=true;return}if(!v(F)){s("error","value",Z,"A choice must be an object.");return}a(F,Z,Jo,Zs,"choice");u(F["icon"],[...Z,"icon"]);h(F["shortcut"],[...Z,"shortcut"]);const de=F["kind"]??"item";const Qe=eo(A);if(de==="item"){if((bt(F["label"])??"")==="")s("warning","label",Z,"A choice needs a \"label\".");const pe=typeof F["value"]==="string"?F["value"]:typeof F["label"]==="string"?F["label"]:void 0;const kt=Qe.submenu&&Array.isArray(F["choices"])&&F["choices"].length>0;if(!kt&&(B(F["value"])||F["value"]===void 0&&B(F["label"])))y=true;if(pe!==void 0){if(P.has(pe))s("warning","choice-twice",Z,"Two choices have the key \"{key}\". Give one of them a different \"value\".",{key:pe});P.add(pe);if(!kt)j.add(pe)}}else if(de==="separator"||de==="header"){if(de==="header"&&(bt(F["label"])??"")==="")s("warning","label",Z,"A heading needs a \"label\", the text of the heading.");if(A&&!Qe.structure)s("warning","choice-kind",[...Z,"kind"],"A separator or a heading only works in a split button or a dropdown button. The control \"{type}\" leaves it out or shows it as an ordinary entry.",{type:$??""})}else if(de==="source"){const pe=F["source"];if(!B(pe)){if(typeof pe!=="string"||pe.trim()==="")s("warning","source",Z,"A block of menu items needs the name of its \"source\", for example \"gfy:documents\".");else if(pe.startsWith(jf)&&!Pf(pe)){const kt=io(pe,qo.map(fe=>fe.name));if(kt)s("warning","source",[...Z,"source"],"The library has no block \"{source}\": the names that start with \"gfy:\" are its own. Did you mean \"{suggestion}\"?",{source:pe,suggestion:kt});else s("warning","source",[...Z,"source"],"The library has no block \"{source}\": the names that start with \"gfy:\" are its own.",{source:pe})}}if(A&&!Qe.structure)s("warning","choice-kind",[...Z,"kind"],"A block of menu items only works in a split button or a dropdown button. The control \"{type}\" leaves it out or shows it as an ordinary entry.",{type:$??""})}if("source"in F&&de!=="source"&&!B(de))s("info","source-kind",[...Z,"source"],"The \"source\" is used only by a choice of the kind \"source\".");if(de==="separator"||de==="header"||de==="source"){for(const pe of Object.keys(F)){if(Dm[de].includes(pe)||pe==="choices"||pe==="source"||!Zs.includes(pe))continue;if(pe==="shortcut"&&typeof F["shortcut"]==="string")s("warning","kind-unused",[...Z,pe],"{kind} runs no command, but the ribbon still registers its shortcut \"{shortcut}\", which runs the action of the item. Take the shortcut out.",{kind:od[de],shortcut:F["shortcut"]});else s("info","kind-unused",[...Z,pe],"{kind} does not use \"{key}\": the menu leaves it out.",{kind:od[de],key:pe})}}if(A&&de==="item"){const pe=[["icon",Qe.icon],["preview",Qe.tile],["style",Qe.tile],["checked",Qe.checked],["disabled",Qe.disabled]];for(const[kt,fe]of pe)if(!fe&&kt in F)s("info","choice-unused",[...Z,kt],"The control \"{type}\" does not use \"{key}\" of a choice.",{type:$??"",key:kt})}if("choices"in F){if(A&&!Qe.submenu)s("warning","submenu",[...Z,"choices"],"A submenu works in a split button and a dropdown button only. The control \"{type}\" shows its choices as ordinary entries, or leaves them out.",{type:$??""});else if(de!=="item"&&!B(de))s("info","submenu",[...Z,"choices"],"Only a choice of the kind \"item\" has a submenu.");for(const pe of b(F["choices"],[...Z,"choices"],$,A,true))j.add(pe)}});return j};const x=(k,S)=>{if(B(k))return;if(!v(k)){s("error","value",S,"An item must be an object.");return}a(k,S,Xt,Nc,"item");l(k,S);const $=k["type"];if(typeof $!=="string"||$===""){s("error","type",S,"An item needs a \"type\", the control to show.")}else if($!=="custom"&&!J($)&&!i.has($)){s("warning","type",[...S,"type"],"The control \"{type}\" is not built in. The application has to register it, and this editor cannot show it.",{type:$})}else if($==="custom"){s("warning","type",[...S,"type"],"The type \"custom\" needs a component, which cannot be written in JSON. Register the control under a name instead.")}const A=typeof $==="string"?J($):void 0;const R=k["id"];if(typeof R==="string"&&R!==""){const F=c.get(R);if(F)s("error","id-twice",[...S,"id"],"The id \"{id}\" is used by another item: {other}.",{id:R,other:Zt(n,F)});else c.set(R,S)}else if(R===void 0||R===""){s("info","id",S,"Give the item an \"id\": the application binds its signals and handlers to the item by it.")}if(A&&Im.has(A.type)){const F=k["label"];const U=k["icon"];const Z=B(F)||typeof F==="string"&&F!=="";const de=A.icon&&(B(U)||typeof U==="string"&&U!=="");const Qe=B(k["tooltip"])||typeof k["tooltip"]==="string"&&k["tooltip"]!=="";if(!Z&&!de)s("warning","empty",S,A.icon?"The item has no label or icon, so nothing is visible. The tooltip does not show the item.":"The item has no label, so nothing is visible.");else if(!Z&&!Qe)s("info","name",S,"The item has an icon only: give it a label or a tooltip, which is its name for a screen reader.")}u(k["icon"],[...S,"icon"]);h(k["shortcut"],[...S,"shortcut"]);if(A?.command&&k["action"]===void 0)s("info","action",S,"Without an \"action\" the application cannot tell that this item was used.");if(typeof k["disabledReason"]==="string"&&k["disabled"]!==true&&!B(k["disabled"]))s("info","reason",[...S,"disabledReason"],"The reason is shown only while the item is disabled. The application can disable it with a signal.");if("inputs"in k)g(k["inputs"],[...S,"inputs"],typeof $==="string"?$:void 0,A);if($==="color-picker")m(k["value"],[...S,"value"]);let j=/* @__PURE__ */new Set;y=false;if("choices"in k){if(A?.choices==="none")s("warning","choices",[...S,"choices"],"The control \"{type}\" does not use \"choices\".",{type:A.type});j=b(k["choices"],[...S,"choices"],typeof $==="string"?$:void 0,A);if(A?.choices==="required"&&Array.isArray(k["choices"])&&k["choices"].length===0)s("warning","choices",[...S,"choices"],"The control \"{type}\" needs \"choices\" to show anything.",{type:A.type})}else if(A?.choices==="required"){s("warning","choices",S,"The control \"{type}\" needs \"choices\" to show anything.",{type:A.type})}if($==="toggle-group"&&v(k["inputs"])&&k["inputs"]["exclusive"]===true&&Array.isArray(k["choices"])){const F=k["choices"].flatMap((U,Z)=>v(U)&&U["checked"]===true?[Z]:[]);if(F.length>1)s("warning","exclusive-checked",[...S,"choices",F[1],"checked"],"Only one choice of an exclusive group can be on. Switch the others off, or turn \"exclusive\" off.")}const P=k["value"];if(A&&P!==void 0&&!B(P)){if(A.value==="none")s("info","value-unused",[...S,"value"],"The control \"{type}\" does not use a value.",{type:A.type});else if(A.value==="number"&&!(typeof P==="number"||typeof P==="string"&&P.trim()!==""&&Number.isFinite(Number(P))))s("warning","value-kind",[...S,"value"],"The value of the control \"{type}\" should be a number.",{type:A.type});else if(A.value==="text"&&typeof P!=="string"&&!(A.choices==="required"&&(typeof P==="number"||typeof P==="boolean")))s("warning","value-kind",[...S,"value"],"The value of the control \"{type}\" should be a text.",{type:A.type});else if(A.choices==="required"&&A.value==="text"&&j.size>0&&!y&&!j.has(String(P)))s("warning","value-choice",[...S,"value"],"No choice has the key \"{value}\".",{value:String(P)})}if(A&&!A.checked&&k["checked"]!==void 0)s("info","checked-unused",[...S,"checked"],"The control \"{type}\" does not use \"checked\".",{type:A.type});if("compact"in k){const F=k["compact"];if(!v(F))s("error","value",[...S,"compact"],"The property \"{key}\" must be an object.",{key:"compact"});else{const U=[...S,"compact"];a(F,U,Xt.filter(de=>Qs.includes(de.key)),Qs,"compact");const Z=typeof F["type"]==="string"?F["type"]:typeof $==="string"?$:void 0;if("type"in F&&typeof F["type"]!=="string")s("error","value",[...U,"type"],"The property \"{key}\" must be a text.",{key:"type"});if("inputs"in F)g(F["inputs"],[...U,"inputs"],Z,J(Z))}}};if(!Array.isArray(n)){s("error","root",[],"The ribbon must be a list of tabs: [ {…}, {…} ].");return t}if(n.length===0)s("info","empty-ribbon",[],"The ribbon has no tab yet.");const T=jc(n,r,e.uniformRows===true);n.forEach((k,S)=>{const $=[S];if(B(k))return;if(!v(k)){s("error","value",$,"A tab must be an object.");return}a(k,$,Uo,Cc,"tab");l(k,$);const A=k["id"];if(typeof A!=="string"||A==="")s("error","id",$,"A tab needs an \"id\".");else{const P=d.get(A);if(P)s("error","id-twice",[...$,"id"],"The id \"{id}\" is used by another tab.",{id:A});else d.set(A,$)}if((bt(k["label"])??"")==="")s("warning","label",$,"A tab needs a \"label\", the text of the tab.");const R=k["sections"];if(B(R))return;if(!Array.isArray(R)){s("error","sections",$,"A tab needs \"sections\", a list.");return}if(R.length===0)s("info","empty-tab",$,"The tab has no section yet.");const j=/* @__PURE__ */new Set;R.forEach((P,F)=>{const U=[...$,"sections",F];if(B(P))return;if(!v(P)){s("error","value",U,"A section must be an object.");return}a(P,U,Yo,Oc,"section");l(P,U);u(P["icon"],[...U,"icon"]);const Z=P["id"];if(typeof Z!=="string"||Z==="")s("error","id",U,"A section needs an \"id\".");else{if(j.has(Z))s("error","id-twice",[...U,"id"],"The id \"{id}\" is used by another section of this tab.",{id:Z});j.add(Z)}if((bt(P["title"])??"")==="")s("warning","label",U,"A section needs a \"title\".");const de=P["items"];if(B(de))return;if(!Array.isArray(de)){s("error","items",U,"A section needs \"items\", a list.");return}if(de.length===0)s("info","empty-section",U,"The section has no item yet.");de.forEach((fe,Re)=>x(fe,[...U,"items",Re]));const Qe=$e(P,T[S]);const pe=na(P["columns"]);Qe.forEach((fe,Re)=>{if(!fe)return;const hr=[...U,"items",Re];if(typeof k["rows"]==="number"&&fe.row+fe.rowSpan-1>T[S]&&fe.rowFixed){s("warning","rows",hr,"The item reaches row {row}, but the tab has {rows} rows.",{row:fe.row+fe.rowSpan-1,rows:T[S]})}if(fe.colFixed&&P["columns"]!==void 0&&fe.col+fe.colSpan-1>pe){s("info","columns",hr,"The item is in column {col}, but the section has {columns} columns. The grid adds a column of its own.",{col:fe.col+fe.colSpan-1,columns:pe})}});for(const[fe,Re]of ia(Qe)){s("warning","overlap",[...U,"items",Re],"The item is on the same cells as \"{other}\".",{other:ua(de[fe],fe)})}if(typeof P["columns"]!=="number"&&typeof P["columns"]!=="string"){de.forEach((fe,Re)=>{if(v(fe)&&Me(fe)==="all")s("warning","all-columns",[...U,"items",Re,"colSpan"],"The item covers all columns, but the section does not say how many it has (\"columns\"): the library then spans as many columns as the title of the section needs, which may be more or fewer than the items use. Give the section its number of columns.")})}const kt=["col","row","colSpan","rowSpan","type","inputs"];if(de.some(fe=>v(fe)&&v(fe["compact"])&&kt.some(Re=>Re in fe["compact"]))){const fe={...P,columns:P["compactColumns"]??P["columns"],items:de.map(Re=>v(Re)&&v(Re["compact"])?{...Re,...Re["compact"]}:Re)};for(const[Re,hr]of ia($e(fe,T[S]))){s("warning","overlap-compact",[...U,"items",hr,"compact"],"In the compact form the item is on the same cells as \"{other}\".",{other:ua(de[Re],Re)})}}})});if(e.functions)fa(n,[],e.functions,s);ma(n,[],s);return t}const Rm={call:"The code {code} is not a call of a function, so a file cannot carry it. Write a call of one of the functions of the Ribbon Options window, such as tr('Home').",function:"The function {function} of the code {code} is not known. Add it to the custom functions in the Ribbon Options window, or use one of the predefined ones.",argument:"The argument {argument} of the code {code} is not a plain value. A call in a file can take a text, a number, true, false or null."};const ld=n=>{const e=n.replace(/\s+/g," ").trim();return e.length>60?`${e.slice(0,59)}…`:e};function fa(n,e,t,o){const i=zt(n);if(i!==void 0){const r=Hf(i,t);if(!r.ok)o("error","expression",e,Rm[r.reason],{code:ld(i),function:r.callee??"",argument:ld(r.argument??"")});return}if(Array.isArray(n))n.forEach((r,s)=>fa(r,[...e,s],t,o));else if(v(n))for(const[r,s]of Object.entries(n))fa(s,[...e,r],t,o)}function ma(n,e,t){if(Array.isArray(n))n.forEach((o,i)=>ma(o,[...e,i],t));else if(v(n)){if(Go in n){const o=n[Go];if(Object.keys(n).length!==1||typeof o!=="string"||!br.test(o))t("error","bind",e,"A signal is written as {\"$bind\": \"name\"}, with nothing else in the object and a plain name of a signal of the application, such as noSelection.")}else if(Jt in n){const o=n[Jt];if(Object.keys(n).length!==1||typeof o!=="string"||o.trim()==="")t("error","expression",e,"Code is written as {\"$expr\": \"code\"}, with nothing else in the object and a code that is not empty: the loader takes any other object for plain data.")}else for(const[o,i]of Object.entries(n))ma(i,[...e,o],t)}}function Mr(n){switch(n){case"tab":return"a tab";case"section":return"a section";case"item":return"an item";case"choice":return"a choice";default:return"the compact form of an item"}}const Fm=["Identity","Content","Layout","Behavior","Keyboard","Control inputs","Compact form","Compact inputs"];const jm={identity:"Identity",content:"Content",layout:"Layout",behavior:"Behavior",keyboard:"Keyboard"};const qe="";const $r="$custom";const ei="custom-control";const ga="$custom-source";const yt=(n,e)=>`${n}:${e}`;const Pm="Code of the application, kept as written and shown with the = in front; the editor does not run it. Without the =, the text is a plain text; an empty field takes the property out.";const Wm="Worked out from the other items, so it cannot be typed: drag the item in the Editor to move it, and its handles to stretch it. \"Cover all columns\" in its menu gives the column span \"all\".";const Km=["col","row","colSpan","rowSpan"];const _m=`The name of a function of the application, a plain name such as percentText (this.percentText is the same). The ribbon gets the function by this name (written {"$fn": "name"} in the JSON). A call such as =format('x') is code.`;const Gm="The control is set when the item is added (the Toolbox, Add item; Control of the application for one that the application registers) and is not changed afterwards: what one control holds means little to another. For another control, add it and remove this item.";const Bm="The kind is set when the entry is added (Add choice has an entry of every kind) and is not changed afterwards: a separator, a heading and a block use almost nothing of what an entry holds. For another kind, add an entry of that kind and remove this one.";const Vm=["icon","compactColumns","collapsePriority","collapsible"];const Hm="In the shrunk section these inputs replace the inputs of the item as a whole: an input that is missing here is not set at all, not even to its default. The first one you set copies the inputs of the item.";const qm=n=>n===""?"=''":n.trimStart().startsWith("=")?`=${n}`:n;const cd=n=>{const e=n.trim().replace(/^this\./,"");return Wc.test(e)?e:void 0};function ro(n,e,t,o={}){const i=Um(n,e,t,o);return n.bind&&i.kind!=="text"&&i.kind!=="readonly"?{...i,bindable:true}:i}function Um(n,e,t,o){const i={id:e,label:n.key,category:t(jm[n.category]),description:t(n.description)};switch(n.kind){case"integer":return{...i,kind:"number",min:n.min,step:1,decimals:0,...o};case"boolean":return{...i,kind:"boolean",defaultValue:n.default===true,...o};case"choice":return{...i,kind:"select",options:[{value:qe,label:t("(not set)")},...(n.options??[]).map(r=>({value:r,label:r}))],defaultValue:qe,...o};case"span":return{...i,kind:"text",placeholder:t("a number, or all"),defaultValue:"",...o};case"columns":return{...i,kind:"text",placeholder:t("a number, or tracks such as 72px 1fr"),defaultValue:"",...o};case"value":return{...i,kind:"text",defaultValue:"",...o};case"tags":return{...i,kind:"text",placeholder:t("masks, such as gfy:main, doc*"),defaultValue:"",...o};default:return{...i,kind:n.color?"color":"text",defaultValue:"",...o}}}function Ar(n,e,t,o){const i={id:e,label:n.name,category:t,description:o(n.description)};const r=n.fallback;switch(n.kind){case"boolean":return{...i,kind:"boolean",defaultValue:typeof r==="boolean"?r:false};case"integer":return{...i,kind:"number",min:n.min,step:1,decimals:0,...(typeof r==="number"?{defaultValue:r}:{})};case"number":return{...i,kind:"number",...(typeof r==="number"?{defaultValue:r}:{})};case"text":return{...i,kind:n.color?"color":"text",defaultValue:""};case"choice":return{...i,kind:"select",options:[{value:qe,label:o("(not set)")},...(n.options??[]).map(s=>({value:s,label:s}))],defaultValue:qe};case"function":return{...i,kind:"text",placeholder:o("name of a function"),defaultValue:"",description:`${o(n.description)} ${o(_m)}`};default:return null}}function Ym(n,e){if(n?.value!=="text"||n.choices==="none")return void 0;const t=e["choices"];if(t!==void 0&&!Array.isArray(t))return void 0;const o=[];const i=s=>{for(const a of s){if(!v(a)||B(a))return false;const l=a["kind"];if(l==="separator"||l==="header")continue;if(l!==void 0&&l!=="item")return false;const d=a["choices"];if(n.choiceUse.submenu&&Array.isArray(d)&&d.length>0){if(!i(d))return false;continue}const c=Cr(a);if(c===void 0||c==="")return false;if(!o.includes(c))o.push(c)}return true};if(!i(t??[]))return void 0;const r=e["value"];if(r!==void 0&&typeof r!=="string")return void 0;if(r==="")return void 0;return o.map(s=>({value:s,label:s}))}function Cr(n){const e=n["value"];return typeof e==="string"?e:e===void 0&&typeof n["label"]==="string"?n["label"]:void 0}const Or=n=>(n?.inputs??[]).filter(e=>e.kind!=="list");function Jm(n,e,t,o){if(!o)return true;if(t?.ignores?.includes(n.key))return n.key in e;if(n.key==="icon"||n.key==="iconColor")return t?.icon===true||n.key in e;if(n.key==="value")return t?.value!=="none"||"value"in e;if(n.key==="checked")return t?.checked===true||"checked"in e;return true}function Xm(n,e,t){if(n.key in e)return true;const o=B(e["kind"])?"item":e["kind"]??"item";switch(n.key){case"kind":return t.structure;case"source":return o==="source";case"label":return o!=="separator";case"value":case"shortcut":return o==="item";case"icon":return o==="item"&&t.icon;case"preview":case"style":return o==="item"&&t.tile;case"checked":return o==="item"&&t.checked;case"disabled":return o==="item"&&t.disabled;default:return true}}function dd(n,e,t){if(n.name in e)return true;const o=n.dependsOn;if(!o)return true;const i=e[o.input];if(B(i))return true;const r=i!==void 0?i:t?.inputs.find(s=>s.name===o.input)?.fallback;return o.equals!==void 0?r===o.equals:r!==o.not}function pd(n,e,t){const o=[];if(t)o.push({value:qe,label:n("(the control of the item)")});for(const i of Xo)o.push({value:i.type,label:i.label});o.push({value:$r,label:n("A control of the application")});return{id:yt(e,"type"),label:e==="f"?"type":"compact.type",kind:"select",category:n(e==="f"?"Identity":"Compact form"),description:e==="f"?`${n("The control the item is.")} ${n(Gm)}`:n("The control of the item when the section is shrunk. Without it the control of the item stays."),options:o,...(e==="f"?{disabled:true}:{}),...(t?{defaultValue:qe}:{})}}const hd=(n,e)=>({id:yt(e,"typeName"),label:e==="f"?"typeName":"compact.typeName",kind:"text",category:n(e==="f"?"Identity":"Compact form"),description:n("The name the application registers the control with. It is the name of a control of the application only: the name of a built-in control is not taken."),defaultValue:""});function Zm(n){return{id:yt("f","source"),label:"source",kind:"select",category:n("Identity"),description:n("The block of menu items that the menu shows in this place when it opens. The items run their own commands."),options:[{value:qe,label:n("(not set)")},...qo.map(e=>({value:e.name,label:`${n(e.label)} (${e.name})`})),{value:ga,label:n("A block of the application")}],defaultValue:qe}}const Qm=n=>({id:yt("f","style"),label:"style",kind:"text",category:n("Content"),description:n("The CSS of the preview text in the tile of a gallery, as in a style attribute: font-family: Georgia; font-weight: bold; color: #c00. The file keeps it as an object. The text of the preview is drawn as text, not as HTML. Nothing else draws it: not a menu, not a list."),placeholder:"font-weight: bold; color: #c00",defaultValue:""});function ud(n){if(!v(n)||B(n)||!Object.values(n).every(e=>typeof e==="string"))return void 0;return Object.entries(n).map(([e,t])=>`${e}: ${t}`).join("; ")}function eg(n){const e=[];let t=0;let o=null;let i=0;for(let s=0;s<n.length;s++){const a=n[s];if(o){if(a===o)o=null}else if(a==="\""||a==="'")o=a;else if(a==="(")t++;else if(a===")")t=Math.max(0,t-1);else if(a===";"&&t===0){e.push(n.slice(i,s));i=s+1}}e.push(n.slice(i));const r={};for(const s of e){const a=s.indexOf(":");if(a<0)continue;const l=s.slice(0,a).trim();const d=s.slice(a+1).trim();if(/^-{0,2}[A-Za-z_][\w-]*$/.test(l)&&d!=="")Ae(r,l,d)}return Object.keys(r).length>0?r:void 0}const tg=n=>({id:yt("f","sourceName"),label:"sourceName",kind:"text",category:n("Identity"),description:n("The name the application registers the block with (GfyMenuSources), for example recent-files. An engine with a key has gfy:tools@key."),defaultValue:""});const fd=n=>qo.some(e=>e.name===n);const md=n=>n===void 0||!("kind"in n)||n.kind==="text"||n.kind==="value";const ng=n=>typeof n==="string"?n:typeof n==="number"||typeof n==="boolean"?String(n):void 0;function og(n,e,t){if(e===void 0)return n.kind==="select"?qe:void 0;switch(n.kind){case"boolean":return typeof e==="boolean"?e:void 0;case"number":return typeof e==="number"&&Number.isFinite(e)?e:void 0;case"select":return typeof e==="string"?e:qe;default:if(t&&"kind"in t&&t.kind==="function")return v(e)&&typeof e["$fn"]==="string"?e["$fn"]:void 0;if(t&&"kind"in t&&t.kind==="tags"&&Array.isArray(e))return $m(e);if(n.kind==="text"&&typeof e==="string"&&md(t))return qm(e);return ng(e)}}function ig(n,e){if(e===void 0)return true;if(typeof e==="number")return Number.isInteger(e)&&e>=1;return(n==="colSpan"||n==="rowSpan")&&e==="all"}function rg(n,e,t){const o=e[4];if(e.length!==5||typeof o!=="number")return null;return $e(O(n,e.slice(0,3)),t??oa(O(n,[e[0]])))[o]??null}function sg(n,e,t,o){const i=n.key;const r={...ro(n,yt("f",i),o),kind:"readonly",min:void 0,step:void 0,decimals:void 0,placeholder:void 0,defaultValue:void 0,description:`${o(n.description)} ${o(Wm)}`};return{row:r,text:e[i]==="all"?"all":String(t[i])}}function ba(n,e,t,o,i={}){const r=_(e);const s=O(n,e);if(r!=="tab"&&r!=="section"&&r!=="item"&&r!=="choice"||!v(s))return null;const a=[];const l={};const d=r==="item"?rg(n,e,o):null;const c=(b,x,T)=>{if(!b)return;const k=T&&"kind"in T&&T.kind==="function"&&!Nf(x);const S=k?void 0:Lt(x);if(S!==void 0){a.push({...b,kind:"text",options:void 0,min:void 0,step:void 0,decimals:void 0,placeholder:void 0,defaultValue:"",code:{was:b.kind==="readonly"||b.kind==="color"?"text":b.kind,defaultValue:b.defaultValue},description:`${b.description} ${t(Pm)}`});l[b.id]=`=${S}`;return}a.push(b);const $=og(b,x,T);if($!==void 0)l[b.id]=$};const p=r==="tab"?Uo:r==="section"?Yo:r==="item"?Xt:Jo;let h;if(r==="item"){const b=typeof s["type"]==="string"?s["type"]:void 0;h=J(b);const x=pd(t,"f",false);a.push(x);l[x.id]=h?h.type:$r;if(!h){const T=hd(t,"f");a.push(T);if(b!==void 0)l[T.id]=b}}const u=r!=="item"||h!==void 0;const f=r==="choice"?O(n,e.slice(0,5)):void 0;const m=r==="choice"?eo(v(f)?J(f["type"]):void 0):void 0;const g=i.collapsible===true;for(const b of p){if(r==="item"&&!Jm(b,s,h,u))continue;if(m&&!Xm(b,s,m))continue;if(r==="section"&&Vm.includes(b.key)&&!g&&!(b.key in s))continue;if(r==="choice"&&b.key==="kind"){c({...ro(b,yt("f","kind"),t),disabled:true,description:`${t(b.description)} ${t(Bm)}`},s["kind"],b);continue}if(b.kind==="tags"&&!vd(s[b.key]))continue;if(r==="choice"&&b.key==="style"){const A=s["style"]===void 0?"":ud(s["style"]);if(A===void 0)continue;a.push(Qm(t));if(A!=="")l[yt("f","style")]=A;continue}if(r==="choice"&&b.key==="source"){const A=typeof s["source"]==="string"?s["source"]:void 0;const R=A!==void 0&&fd(A);const j=Zm(t);a.push(j);l[j.id]=A===void 0?qe:R?A:ga;if(A!==void 0&&!R){const P=tg(t);a.push(P);l[P.id]=A}continue}if(d&&Km.includes(b.key)&&ig(b.key,s[b.key])){const{row:A,text:R}=sg(b,s,d,t);a.push(A);l[A.id]=R;continue}const x=r==="item"&&b.key==="value"&&h?.value==="number";const T=r==="item"&&b.key==="value"&&h?.type==="color-picker";const k=r==="item"&&b.key==="value"&&!B(s["value"])?Ym(h,s):void 0;const S=typeof s["value"]==="string"?s["value"]:void 0;const $=x?{kind:"number",defaultValue:void 0,step:1}:T?{kind:"color"}:k?{kind:"select",options:[{value:qe,label:t("(not set)")},...k,...(S!==void 0&&!k.some(A=>A.value===S)?[{value:S,label:`${S} (${t("none of the choices")})`}]:[])],defaultValue:qe}:{};c(ro(b,yt("f",b.key),t,$),s[b.key],b)}if(r==="item"){const b=v(s["inputs"])?s["inputs"]:{};for(const $ of Or(h))if(dd($,b,h))c(Ar($,yt("i",$.name),t("Control inputs"),t),b[$.name],$);const x=v(s["compact"])?s["compact"]:{};const T=typeof x["type"]==="string"?x["type"]:void 0;if(g||"type"in x){const $=pd(t,"c",true);a.push($);l[$.id]=T===void 0?qe:J(T)?T:$r;if(T!==void 0&&!J(T)){const A=hd(t,"c");a.push(A);l[A.id]=T}}for(const $ of["col","row","colSpan","rowSpan","justify","align"]){if(!g&&!($ in x))continue;const A=Xt.find(R=>R.key===$);c({...ro(A,yt("c",$),t),label:`compact.${$}`,category:t("Compact form")},x[$],A)}const k=J(T??(typeof s["type"]==="string"?s["type"]:void 0));const S=v(x["inputs"])?x["inputs"]:{};for(const $ of Or(k)){if(!g&&!($.name in S))continue;if(!dd($,S,k))continue;const A=Ar($,yt("ci",$.name),t("Compact inputs"),t);c(A?{...A,label:`compact.inputs.${$.name}`,description:`${A.description} ${t(Hm)}`}:A,S[$.name],$)}}const y=new Map(Fm.map((b,x)=>[t(b),x]));a.sort((b,x)=>(y.get(b.category)??99)-(y.get(x.category)??99));return{kind:r,path:e,rows:a,values:l,control:h}}const ya=n=>n===void 0||n===null||n===""||typeof n==="number"&&!Number.isFinite(n);function gd(n,e){const t=n.trim();if(/^\d+$/.test(t))return Number(t);return e&&t.toLowerCase()==="all"?"all":n}function bd(n,e,t){const o=n.trim()!==""&&Number.isFinite(Number(n));if(t?.value==="number")return o?Number(n):n;if(t?.value==="any"&&typeof e==="number"&&o)return Number(n);if(typeof e==="boolean"&&(n==="true"||n==="false"))return n==="true";return n}function ag(n,e){if(n==="")return void 0;if(n.startsWith("@")&&br.test(n.slice(1))&&!(e&&"kind"in e&&e.kind==="function"))return{[Go]:n.slice(1)};const t=cd(n);if(e&&"kind"in e&&e.kind==="function"&&t!==void 0)return{$fn:t};return{[Jt]:n}}function lg(n,e,t,o){const i=n.was;const r={id:"",label:"",category:"",description:"",kind:i,defaultValue:n.defaultValue};if(i!=="boolean"&&i!=="number")return so(r,e,t,o);const s=Hs(e.trim());return typeof s===i?so(r,s,t,o):{[Jt]:e.trim()}}function so(n,e,t,o){if(ya(e))return void 0;if(n?.kind==="text"&&typeof e==="string"&&e.trimStart().startsWith("=")){const s=e.trimStart().slice(1);const a=(n.code===void 0||n.code.was==="text")&&md(t);if(a&&s.trimStart().startsWith("="))return t&&"kind"in t&&t.kind==="value"?bd(s,o.node["value"],o.control):s;if(a&&(s.trim()==="''"||s.trim()==="\"\""))return"";return ag(s.trim(),t)}if(n?.code)return lg(n.code,String(e),t,o);const i=t?.kind;if(n?.kind==="boolean"){if(typeof e!=="boolean")return void 0;return e===(n.defaultValue===true)?void 0:e}if(n?.kind==="number"){if(typeof e!=="number")return void 0;return e}const r=String(e);if(i==="tags"){const s=Mm(r);return s.length>0?s:void 0}if(i==="span")return gd(r,true);if(i==="columns")return gd(r,false);if(i==="value")return bd(r,o.node["value"],o.control);if(i==="function"){const s=cd(r);return s!==void 0?{$fn:s}:{[Jt]:r.trim()}}return r}const cg=["col","row","colSpan","rowSpan","justify","align"];function yd(n,e){const t=O(n,e);if(!v(t)||!v(t["compact"])||Object.keys(t["compact"]).length>0)return n;return be(n,[...e,"compact"],void 0)}function wd(n,e,t,o){if(n==="i")return t?.inputs.find(i=>i.name===e);if(n==="ci")return(t??o)?.inputs.find(i=>i.name===e);return void 0}function wa(n,e,t,o,i,r=false){const s=_(e);const a=O(n,e);const l={root:n,selected:e};if(!v(a)||s!=="tab"&&s!=="section"&&s!=="item"&&s!=="choice")return l;const d=t.indexOf(":");const c=t.slice(0,d);const p=t.slice(d+1);const h=ba(n,e,i);const u=h?.rows.find(b=>b.id===t);const f=r&&u?{...u,kind:"text"}:u;const m=J(typeof a["type"]==="string"?a["type"]:void 0);if(c==="f"){if(s==="item"&&p==="type")return l;if(s==="item"&&p==="typeName"){const S=typeof o==="string"?o.trim():"";return S===""||J(S)||J(String(a["type"]))?l:Se(n,e,"type",S)}if(s==="choice"&&p==="source"){const S=typeof a["source"]==="string"?a["source"]:void 0;if(o===ga)return S!==void 0&&!fd(S)?l:Se(n,e,"source",$c);return Se(n,e,"source",typeof o==="string"&&o!==qe?o:void 0)}if(s==="choice"&&p==="sourceName"){const S=typeof o==="string"?o.trim():"";return S===""?l:Se(n,e,"source",S)}const b=s==="tab"?Uo:s==="section"?Yo:s==="item"?Xt:Jo;const x=b.find(S=>S.key===p);if(!x)return l;if(s==="choice"&&p==="kind")return l;if(s==="choice"&&p==="style")return Se(n,e,"style",eg(typeof o==="string"?o:""));const T=so(f===void 0||f.kind==="readonly"?ro(x,t,i):f,o,x,{node:a,control:m});if(T===void 0&&(p==="id"||s==="choice"&&p==="label"&&(a["kind"]??"item")==="item"))return l;if(p==="id"&&T==="")return l;if(p==="id"&&typeof T==="string")return Sm(n,e,T);const k=Se(n,e,p,T);if(s==="choice"&&p==="checked"&&T===true)return{root:ha(k.root,e.slice(0,-2),e[e.length-1]),selected:e};if(s==="choice"&&(p==="label"||p==="value"))return dg(n,k,e);return k}if(s!=="item")return l;if(c==="i"){const b=wd("i",p,m,void 0);const x=Qc(n,e,p,so(f??(b?Ar(b,t,"",i)??void 0:void 0),o,b,{node:a,control:m}));return p==="exclusive"?{root:ha(x.root,e),selected:x.selected}:x}const g=[...e,"compact"];const y=b=>v(O(b,g))?b:be(b,g,{});if(c==="c"){let b;if(p==="type"){if(o===$r){const T=O(n,[...g,"type"]);if(typeof T==="string"&&!J(T))return l;b=ei}else{b=ya(o)?void 0:String(o)}}else if(p==="typeName"){const T=ya(o)?"":String(o).trim();b=T===""?void 0:T}else if(cg.includes(p)){const T=Xt.find(k=>k.key===p);b=so(f??(T?ro(T,t,i):void 0),o,T,{node:a,control:m})}else{return l}const x=Se(y(n),g,p==="typeName"?"type":p,b);return{root:yd(x.root,e),selected:e}}if(c==="ci"){const b=O(n,g);const x=v(b)&&typeof b["type"]==="string"?b["type"]:void 0;const T=x===void 0?m:J(x);const k=wd("ci",p,T,m);if(k===void 0)return l;const S=so(f??Ar(k,t,"",i)??void 0,o,k,{node:a,control:T});let $=y(n);if(S!==void 0&&!v(v(b)?b["inputs"]:void 0)&&(x===void 0||x===a["type"])&&v(a["inputs"])){$=be($,[...g,"inputs"],Ys(a["inputs"]))}const A=Qc($,g,p,S);return{root:yd(A.root,e),selected:e}}return l}function dg(n,e,t){const o=t.slice(0,5);const i=O(e.root,o);const r=O(n,t);const s=O(e.root,t);const a=v(i)?J(i["type"]):void 0;if(!v(i)||a?.value!=="text"||a.choices==="none"||!v(r)||!v(s)||(s["kind"]??"item")!=="item")return e;const l=Cr(r);const d=Cr(s);if(l===void 0||d===void 0||l===d||i["value"]!==l)return e;return{root:Se(e.root,o,"value",d).root,selected:e.selected}}function pg(n){const e=n.flatMap(t=>t.split(/[^A-Za-z0-9_$]+/)).filter(t=>t!=="");return e.map((t,o)=>o===0?t.charAt(0).toLowerCase()+t.slice(1):t.charAt(0).toUpperCase()+t.slice(1)).join("")}function va(n,e=/* @__PURE__ */new Set){const t=Hn(n);if(t!==void 0)e.add(t);else if(Array.isArray(n))n.forEach(o=>va(o,e));else if(v(n))Object.values(n).forEach(o=>va(o,e));return e}function hg(n,e,t){const o=[];const i=d=>{const c=O(n,d);if(v(c)&&typeof c["id"]==="string")o.push(c["id"])};const r=_(e);if(r==="tab")i(e.slice(0,1));else if(r==="section"){i(e.slice(0,1));i(e.slice(0,3))}else{i(e.slice(0,5));for(let d=7;d<=e.length;d+=2){const c=O(n,e.slice(0,d));const p=v(c)?Cr(c):void 0;if(p!==void 0)o.push(p)}}const s=pg([...o,t]);const a=br.test(s)?s:t;const l=va(n);if(!l.has(a))return a;for(let d=2;;d++)if(!l.has(`${a}${d}`))return`${a}${d}`}function ug(n,e,t,o){const i=ba(n,e,o)?.rows.find(s=>s.id===t);const r=O(n,e);if(!i?.bindable||i.code||!v(r))return{root:n,selected:e};return wa(n,e,t,`=@${hg(n,e,t.slice(t.indexOf(":")+1))}`,o,true)}const Ae=(n,e,t)=>{Object.defineProperty(n,e,{value:t,enumerable:true,writable:true,configurable:true})};const vd=n=>!Array.isArray(n)||n.every(e=>typeof e==="string");function xd(n){switch(n){case"tab":return Cc.filter(e=>e!=="showForTags");case"section":return Oc.filter(e=>e!=="showForTags");case"item":return Nc.filter(e=>e!=="showForTags");case"choice":return Zs.filter(e=>e!=="style")}}function xa(n,e,t){if(n==="choice"&&t==="style")return ud(e["style"])!==void 0;if(n!=="choice"&&t==="showForTags")return vd(e["showForTags"]);if(!xd(n).includes(t))return false;return!((n==="item"||n==="choice")&&t==="choices"&&e[t]!==void 0&&!Array.isArray(e[t]))}function kd(n){const e=J(typeof n["type"]==="string"?n["type"]:void 0);return new Set(Or(e).map(t=>t.name))}const ka=["type","col","row","colSpan","rowSpan","justify","align"];function Sd(n){const e=v(n["compact"])?n["compact"]:{};const t=typeof e["type"]==="string"?e["type"]:typeof n["type"]==="string"?n["type"]:void 0;return new Set(Or(J(t)).map(o=>o.name))}function fg(n){const e=n["compact"];const t={};if(!v(e))return t;for(const[i,r]of Object.entries(e))if(i!=="inputs"&&!ka.includes(i))Ae(t,i,r);const o=e["inputs"];if(v(o)){const i=Sd(n);const r={};for(const[s,a]of Object.entries(o))if(!i.has(s))Ae(r,s,a);if(Object.keys(r).length>0)Ae(t,"inputs",r)}else if(o!==void 0)Ae(t,"inputs",o);return t}function mg(n,e){const t=_(e);const o=O(n,e);const i={};if(t!=="tab"&&t!=="section"&&t!=="item"&&t!=="choice"||!v(o))return i;for(const[r,s]of Object.entries(o))if(!xa(t,o,r))Ae(i,r,s);if(t==="item"&&v(o["inputs"])){const r=kd(o);const s={};for(const[a,l]of Object.entries(o["inputs"]))if(!r.has(a))Ae(s,a,l);if(Object.keys(s).length>0)Ae(i,"inputs",s)}if(t==="item"&&"inputs"in o&&!v(o["inputs"]))Ae(i,"inputs",o["inputs"]);if(t==="item"&&v(o["compact"])){const r=fg(o);if(Object.keys(r).length>0)Ae(i,"compact",r)}if(t==="item"&&"compact"in o&&!v(o["compact"]))Ae(i,"compact",o["compact"]);return i}function gg(n,e,t){const o=_(e);const i=O(n,e);if(o!=="tab"&&o!=="section"&&o!=="item"&&o!=="choice"||!v(i))return{ok:false,template:"There is nothing selected to change.",params:{}};if(!v(t))return{ok:false,template:"The other properties have to be an object: {\"name\": value, ...}.",params:{}};const r=xd(o);for(const u of Object.keys(t)){if(u==="inputs"&&o==="item")continue;if(u==="compact"&&o==="item"){const f=t[u];if(!v(f))return{ok:false,template:"The compact form has to be an object: {\"name\": value, ...}.",params:{}};const m=Object.keys(f).find(g=>ka.includes(g));if(m!==void 0)return{ok:false,template:"The property \"{key}\" has a row above, change it there.",params:{key:`compact.${m}`}};if("inputs"in f&&!v(f["inputs"]))return{ok:false,template:"The inputs have to be an object: {\"name\": value, ...}.",params:{}};continue}if(u==="choices"&&o==="item"){const f=t[u];if(!v(f)||!("$bind"in f)&&!("$expr"in f))return{ok:false,template:"The \"choices\" are a list of nodes of the outline here. Only code of the application ({\"$bind\": \"name\"}) is written in this place.",params:{}};continue}if(u==="choices"&&o==="choice"){if(Array.isArray(t[u]))return{ok:false,template:"The \"choices\" are a list of nodes of the outline here: add them in the Outline.",params:{}};continue}if(r.includes(u)||u in i&&xa(o,i,u))return{ok:false,template:"The property \"{key}\" has a row above, change it there.",params:{key:u}}}const s={};const a=o==="item"?kd(i):/* @__PURE__ */new Set;const l=v(i["inputs"])?i["inputs"]:{};let d=false;const c=()=>{d=true;const u={};for(const[m,g]of Object.entries(l))if(a.has(m))Ae(u,m,g);const f=t["inputs"];if(f!==void 0)for(const[m,g]of Object.entries(f))Ae(u,m,g);if(Object.keys(u).length>0)Ae(s,"inputs",u)};if(o==="item"&&t["inputs"]!==void 0&&!v(t["inputs"]))return{ok:false,template:"The inputs have to be an object: {\"name\": value, ...}.",params:{}};let p=false;const h=()=>{p=true;const u=v(i["compact"])?i["compact"]:{};const f=v(t["compact"])?t["compact"]:{};const m=Sd(i);const g={};for(const[b,x]of Object.entries(u))if(ka.includes(b))Ae(g,b,x);const y={};if(v(u["inputs"])){for(const[b,x]of Object.entries(u["inputs"]))if(m.has(b))Ae(y,b,x)}if(v(f["inputs"]))for(const[b,x]of Object.entries(f["inputs"]))Ae(y,b,x);if(Object.keys(y).length>0)Ae(g,"inputs",y);for(const[b,x]of Object.entries(f))if(b!=="inputs")Ae(g,b,x);if(Object.keys(g).length>0)Ae(s,"compact",g)};for(const[u,f]of Object.entries(i)){if(u==="inputs"&&o==="item")c();else if(u==="compact"&&o==="item"){if(v(f)||t["compact"]!==void 0)h()}else if(xa(o,i,u)&&!((o==="item"||o==="choice")&&u==="choices"&&t["choices"]!==void 0))Ae(s,u,f)}if(o==="item"&&!d)c();if(o==="item"&&!p&&t["compact"]!==void 0)h();for(const[u,f]of Object.entries(t))if(u!=="inputs"&&u!=="compact"||o!=="item")Ae(s,u,f);return{ok:true,root:be(n,e,s)}}const ao="fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\"";const Td=n=>`<svg viewBox="0 0 16 16" aria-hidden="true">${n}</svg>`;const ae=(...n)=>n.map(e=>`<path ${ao} d="${e}"/>`).join("");const N=(...n)=>Td(ae(...n));const le=(...n)=>Td(n.join(""));const nt=n=>`<path fill="currentColor" stroke="none" d="${n}"/>`;const bg={undo:N("M6 3 2.5 6.5 6 10","M2.5 6.5h7a3.75 3.75 0 0 1 0 7.5H6"),redo:N("M10 3l3.5 3.5L10 10","M13.5 6.5h-7a3.75 3.75 0 0 0 0 7.5H10"),remove:N("M3 4.5h10M6.5 4.5V3h3v1.5","M4.5 4.5l.6 8.5h5.8l.6-8.5","M7 7v3.5M9 7v3.5"),duplicate:N("M5.5 5.5h8v8h-8z","M10.5 5.5v-3h-8v8h3","M9.5 8v3M8 9.5h3"),up:N("M3.5 10 8 5.5l4.5 4.5"),down:N("M3.5 6 8 10.5 12.5 6"),format:N("M2.5 3.5h11M2.5 6.5h7M2.5 9.5h11M2.5 12.5h7"),copy:N("M5.5 5.5h8v8h-8z","M10.5 5.5v-3h-8v8h3"),download:N("M8 2.5v8M4.5 7 8 10.5 11.5 7","M3 13.5h10"),upload:N("M8 10.5v-8M4.5 6 8 2.5 11.5 6","M3 13.5h10"),save:N("M3 2.5h8.5L13.5 4.5v9H3z","M5.5 2.5v3.5h5V2.5","M5.5 13.5v-4h5v4"),"project-folder":N("M1.75 4h4.5l1.5 1.5h6.5v7.5H1.75z"),"project-file":N("M4 2.5h5.5l2.5 2.5v8.5H4z","M9.5 2.5V5H12"),background:le(ae("M2.5 2.5h11v11h-11z"),nt("M5 5h6v6H5z")),grid:N("M2.5 2.5h11v11h-11z","M2.5 6.2h11M2.5 9.8h11M6.2 2.5v11M9.8 2.5v11"),problems:N("M8 2 14.5 13.5h-13z","M8 6.5v3"),unknown:le(`<rect x="2.75" y="2.75" width="10.5" height="10.5" rx="2.5" ${ao} stroke-opacity=".55"/>`,`<circle cx="8" cy="8" r="1.4" fill="currentColor" fill-opacity=".55"/>`),sample:N("M3.5 2.5h9v11h-9z","M6 5.5h4M6 8h4M6 10.5h2.5"),clipboard:N("M5 3.5h6v2H5z","M4 4.5H3v9h10v-9h-1"),cursor:N("M3.5 2.5l8 4.25-3.25 1.25L10 11.5 8.5 12.5 6.75 9 4.5 11z"),info:le(`<circle cx="8" cy="8" r="5.75" ${ao}/>`,ae("M8 7.25v3.75"),"<circle cx=\"8\" cy=\"5\" r=\"0.95\" fill=\"currentColor\"/>"),flag:N("M4 13.5V2.5","M4 3h7.5l-2 2.5 2 2.5H4"),guides:N("M1.75 3.5c2.25-.75 4.25-.5 6.25.75v9c-2-1.25-4-1.5-6.25-.75z","M14.25 3.5c-2.25-.75-4.25-.5-6.25.75v9c2-1.25 4-1.5 6.25-.75z"),keyboard:N("M1.75 4.25h12.5v7.5H1.75z","M4.25 6.75h.01M6.75 6.75h.01M9.25 6.75h.01M11.75 6.75h.01","M5 9.25h6")};const Sa=n=>Object.fromEntries(Object.entries(bg).map(([e,t])=>[`${n}:${e}`,t]));const yg={"rbe:preview":N("M1.75 8S4 3.75 8 3.75 14.25 8 14.25 8 12 12.25 8 12.25 1.75 8 1.75 8z","M8 6.25a1.75 1.75 0 1 0 0 3.5 1.75 1.75 0 0 0 0-3.5z"),"rbe:tab":N("M2 13V4.5a1 1 0 0 1 1-1h3l1.25 1.75H13a1 1 0 0 1 1 1V13a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1z"),"rbe:section":N("M2.5 3h11v10h-11z","M2.5 10.25h11"),"rbe:item":N("M2.5 5h11v6h-11z","M5 8h3"),"rbe:choice":le(ae("M6 4h7.5M6 8h7.5M6 12h7.5"),nt("M2 4a.9.9 0 1 0 1.8 0A.9.9 0 0 0 2 4zM2 8a.9.9 0 1 0 1.8 0A.9.9 0 0 0 2 8zM2 12a.9.9 0 1 0 1.8 0A.9.9 0 0 0 2 12z")),"rbe:add-tab":N("M2 13V4.5a1 1 0 0 1 1-1h3l1.25 1.75H13a1 1 0 0 1 1 1V13a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1z","M8 7.5v4.5M5.75 9.75h4.5"),"rbe:add-section":N("M2.5 3h11v10h-11z","M2.5 10.25h11","M8 4.5v3.5M6.25 6.25h3.5"),"rbe:add-item":N("M2.5 5h11v6h-11z","M8 6.75v2.5M6.75 8h2.5"),"rbe:add-choice":N("M6 4h7.5M6 8h7.5M6 12h4","M12.5 10.5v3M11 12h3"),"rbe:choice-separator":N("M2.5 8h11","M4 4.5h8","M4 11.5h8"),"rbe:choice-header":N("M3 4h6","M3 8.5h10","M3 11.5h10"),"rbe:choice-source":le(ae("M2.5 3h11v10h-11z","M5 6h6M5 8.5h6M5 11h3"),nt("M11.5 10.5a1 1 0 1 0 2 0 1 1 0 0 0-2 0z"))};const wg={"rbe:control-large-button":N("M3 2.5h10v11H3z","M6 6h4v2.25H6z","M5.5 10.5h5"),"rbe:control-button":N("M2.5 5h11v6h-11z","M5 8h6"),"rbe:control-styled-button":N("M2.5 5h11v6h-11z","M4.5 7.25h2.5v1.5H4.5z","M9 8h2.5"),"rbe:control-split-button":N("M2.5 5h11v6h-11z","M10 5v6","M11 7.5l1 1 1-1","M4.5 8h3"),"rbe:control-dropdown-button":N("M2.5 4h11v4h-11z","M5 6h4","M10.5 5.5l1 1 1-1","M4 10.5h8M4 13h6"),"rbe:control-gallery":N("M2.5 2.5h4v4h-4z","M9.5 2.5h4v4h-4z","M2.5 9.5h4v4h-4z","M9.5 9.5h4v4h-4z"),"rbe:control-table-picker":N("M2.5 2.5h11v11h-11z","M2.5 6.2h11M2.5 9.8h11M6.2 2.5v11M9.8 2.5v11"),"rbe:control-color-picker":le(ae("M8 2.25c3.3 0 5.75 2.1 5.75 4.6 0 1.7-1.3 2.4-2.6 2.4h-1.5c-.7 0-1.1.5-1.1 1 0 .6.3.85.3 1.4 0 .8-.6 1.3-1.4 1.3-3 0-5.5-2.3-5.5-5.4C2.25 4.7 4.75 2.25 8 2.25z"),nt("M4.7 6.4a.85.85 0 1 0 1.7 0 .85.85 0 0 0-1.7 0zM7.2 4.6a.85.85 0 1 0 1.7 0 .85.85 0 0 0-1.7 0zM10 6.1a.85.85 0 1 0 1.7 0 .85.85 0 0 0-1.7 0z")),"rbe:control-toggle-button":le(ae("M2.5 5h11v6h-11z","M5 8h6"),`<path fill="currentColor" fill-opacity=".22" stroke="none" d="M2.5 5h11v6h-11z"/>`),"rbe:control-toggle-group":le(ae("M1.75 5h12.5v6H1.75z","M6 5v6M10 5v6"),`<path fill="currentColor" fill-opacity=".22" stroke="none" d="M6 5h4v6H6z"/>`),"rbe:control-checkbox":N("M2.5 2.5h11v11h-11z","M5 8.25l2.25 2.25L11.25 5.5"),"rbe:control-radio":le(ae("M8 2.25a5.75 5.75 0 1 0 0 11.5 5.75 5.75 0 0 0 0-11.5z"),nt("M8 5.25a2.75 2.75 0 1 0 0 5.5 2.75 2.75 0 0 0 0-5.5z")),"rbe:control-spinner":N("M2.5 4.5h11v7h-11z","M10 4.5v7","M11.1 7.2 11.75 6.4l.65.8","M11.1 9.2l.65.8.65-.8"),"rbe:control-combobox":N("M2.5 4.5h11v7h-11z","M10 4.5v7","M11 7.25l1 1 1-1","M4.5 8h3"),"rbe:control-select":N("M2.5 4.5h11v7h-11z","M11 7l1 1.25L13 7","M4.5 8h4"),"rbe:control-label":N("M3 4.5h10M8 4.5v7.5M6 12h4"),"rbe:control-progress-bar":le(ae("M2 6h12v4H2z"),`<path fill="currentColor" fill-opacity=".45" stroke="none" d="M2 6h7v4H2z"/>`),"rbe:control-progress-ring":`<svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="5.5" fill="none" stroke="currentColor" stroke-opacity=".3" stroke-width="1.8"/><path ${ao} stroke-width="1.8" d="M8 2.5a5.5 5.5 0 0 1 5.5 5.5"/></svg>`};const vg={"rbe:paste":N("M5 3.5h6v2H5z","M4 4.5H3v9h6.5","M7.5 7.5h5.5v6H7.5z"),"rbe:cut":le(ae("M4.5 2.5 10 10M11.5 2.5 6 10"),`<circle cx="5" cy="12" r="1.75" ${ao}/><circle cx="11" cy="12" r="1.75" ${ao}/>`),"rbe:format-painter":N("M3 2.5h8v3.5H3z","M11 4h2v4H7.5v2","M6 10h3v4H6z"),"rbe:bold":N("M5 3h3.5a2.25 2.25 0 0 1 0 4.5H5z","M5 7.5h4a2.25 2.25 0 0 1 0 4.5H5z","M5 3v9"),"rbe:italic":N("M7 3h4.5M4.5 13H9M9.5 3 6.5 13"),"rbe:underline":N("M4.5 2.5v5a3.5 3.5 0 0 0 7 0v-5","M3 14h10"),"rbe:align-left":N("M2.5 3.5h11M2.5 6.5h7M2.5 9.5h11M2.5 12.5h7"),"rbe:align-center":N("M2.5 3.5h11M4.5 6.5h7M2.5 9.5h11M4.5 12.5h7"),"rbe:align-right":N("M2.5 3.5h11M6.5 6.5h7M2.5 9.5h11M6.5 12.5h7"),"rbe:table":N("M2.5 3h11v10h-11z","M2.5 6.5h11M2.5 10h11M6.2 3v10M9.8 3v10"),"rbe:image":le(ae("M2.5 3h11v10h-11z","M2.5 11l3.25-3.5 2.5 2.5 2-2 3.25 3"),nt("M10 5.4a1 1 0 1 0 2 0 1 1 0 0 0-2 0z")),"rbe:link":N("M6.75 9.25a2.75 2.75 0 0 0 3.9 0l2-2a2.75 2.75 0 0 0-3.9-3.9l-.75.75","M9.25 6.75a2.75 2.75 0 0 0-3.9 0l-2 2a2.75 2.75 0 0 0 3.9 3.9l.75-.75"),"rbe:shapes":N("M2.5 8.5h5v5h-5z","M11 2.75a3 3 0 1 1 0 6 3 3 0 0 1 0-6z","M9.5 13.5 12 9.75l2.5 3.75z"),"rbe:zoom":N("M7 2.5a4.5 4.5 0 1 0 0 9 4.5 4.5 0 0 0 0-9z","M10.25 10.25 13.5 13.5","M5 7h4M7 5v4")};const xg={...Sa("rbe"),...yg,...wg,...vg};const ti=n=>`rbe:control-${n}`;function kg(n){n.setMany({...xg})}class jn{kept=null;guard=e=>e.preventDefault();guarding=false;destroyed=false;leave(e,t){if(this.destroyed)return;this.kept=e;this.setGuard(t)}take(){const e=this.kept;this.kept=null;this.setGuard(false);return e}ngOnDestroy(){this.destroyed=true;this.kept=null;this.setGuard(false)}setGuard(e){if(e===this.guarding)return;this.guarding=e;if(e)window.addEventListener("beforeunload",this.guard);else window.removeEventListener("beforeunload",this.guard)}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:jn,deps:[],target:w.ɵɵFactoryTarget.Directive});static ɵdir=w.ɵɵngDeclareDirective({minVersion:"14.0.0",version:"21.2.21",type:jn,isStandalone:true,ngImport:w})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:jn,decorators:[{type:zs}]});const Ta=n=>({past:[],present:n,future:[],mergeKey:null,changedAt:0});const lo=n=>n.past.length>0;const Nr=n=>n.future.length>0;function wn(n,e,t={}){if(Object.is(e,n.present))return n;const o=t.now??0;const i=t.mergeKey!==void 0&&t.mergeKey===n.mergeKey&&n.past.length>0&&o-n.changedAt<=(t.mergeWithin??1e3);const r=Math.max(1,t.limit??200);const s=i?n.past:[...n.past,n.present].slice(-r);return{past:s,present:e,future:[],mergeKey:t.mergeKey??null,changedAt:o}}function Ma(n){if(!lo(n))return n;const e=n.past.slice(0,-1);return{past:e,present:n.past[n.past.length-1],future:[n.present,...n.future],mergeKey:null,changedAt:0}}function $a(n){if(!Nr(n))return n;return{past:[...n.past,n.present],present:n.future[0],future:n.future.slice(1),mergeKey:null,changedAt:0}}const Aa={defaultRows:3,uniformRows:false,colWidth:null,colGap:null,collapsible:false,search:false,searchPlaceholder:null};const Ir=24;const Ct={...Aa,colWidth:Ir};const Sg=n=>n.colWidth??Ir;const Ca={colWidth:{min:0,inclusive:false},colGap:{min:0,inclusive:true}};function Md(n,e){if(typeof e!=="number"||!Number.isFinite(e))return false;return Ca[n].inclusive?e>=Ca[n].min:e>Ca[n].min}const ni={colWidth:{min:20,max:100},colGap:{min:0,max:20}};function Tg(n,e){if(!Md(n,e))return null;return Math.min(ni[n].max,Math.max(ni[n].min,e))}const Mg={defaultRows:"a whole number, 1 or more",uniformRows:"true or false",colWidth:"a number of px above 0",colGap:"a number of px, 0 or more",collapsible:"true or false",search:"true or false",searchPlaceholder:"a text"};function $g(n){const e={...Aa};const t=[];if(!v(n))return{options:e,notes:t};const o=n;const i=s=>{t.push({key:s,template:"The option \"{key}\" must be {expects}, so the default is used.",params:{key:s,expects:Mg[s]}})};const r=s=>o[s]!==void 0&&o[s]!==null;if(r("defaultRows")){const s=o["defaultRows"];if(typeof s==="number"&&Number.isInteger(s)&&s>=1)e.defaultRows=s;else i("defaultRows")}for(const s of["uniformRows","collapsible","search"]){if(!r(s))continue;const a=o[s];if(typeof a==="boolean")e[s]=a;else i(s)}if(r("rowHeight")){t.push({key:"rowHeight",template:"The option \"rowHeight\" ({value}) is left out: the ribbon has no such option any more, the height of the rows follows the density.",params:{value:typeof o["rowHeight"]==="number"?o["rowHeight"]:JSON.stringify(o["rowHeight"])}})}for(const s of["colGap","colWidth"]){if(!r(s))continue;const a=o[s];if(Md(s,a))e[s]=a;else i(s)}if(r("searchPlaceholder")){const s=o["searchPlaceholder"];if(typeof s==="string")e.searchPlaceholder=s;else i("searchPlaceholder")}return{options:e,notes:t}}function Ag(n){const e=[];if(n.colWidth===null){e.push({key:"colWidth",severity:"info",template:"The option \"colWidth\" is not set, so an application makes every column as wide as its content, as the Preview shows. The Editor draws the columns {width} px wide: the column span of an item counts these cells, and an item that covers fewer cells than its content needs is narrower there than in the application.",params:{width:Ir}})}for(const t of["colWidth","colGap"]){const o=n[t];const{min:i,max:r}=ni[t];if(o!==null&&(o<i||o>r)){e.push({key:t,severity:"warning",template:"The option \"{key}\" is {value} px, outside the {min} to {max} px that the editor offers. The file keeps it; a value typed into the field is brought into the range.",params:{key:t,value:o,min:i,max:r}})}}if(n.search&&n.searchPlaceholder===""){e.push({key:"searchPlaceholder",severity:"info",template:"The option \"searchPlaceholder\" is an empty text, so the search box shows no text. An emptied field gives the text of the library.",params:{}})}return e}function Cg(n){return{...n}}const $d={options:Ct,functions:""};const Ad=n=>n.history.present.root;const Cd=n=>n.history.present.options;const Og=n=>n.history.present.functions;const Dr=n=>({options:n.history.present.options,functions:n.history.present.functions});const Ng=n=>n.history.present!==n.saved;const Ig=n=>n.saved===n.history.present?n:{...n,saved:n.history.present};const Dg=n=>n.saved!==n.history.present?n:{...n,saved:{...n.history.present}};function co(n,e=null,t=$d,o=[]){const i=Hc(n).value;const r=Array.isArray(i)?i:[];const s=Ta({root:r,options:t.options,functions:t.functions});return{history:s,notes:o,selected:Er(r,e),saved:s.present}}function Er(n,e){if(e===null)return null;for(let t=e.length;t>=1;t--){const o=e.slice(0,t);const i=_(o);if((i==="tab"||i==="section"||i==="item"||i==="choice")&&v(O(n,o)))return o}return null}const Eg=(n,e)=>{const t=Er(Ad(n),e);return t===n.selected||t!==null&&n.selected!==null&&q(t)===q(n.selected)?n:{...n,selected:t}};function zg(n,e,t,o={}){const i=Hc(e).value;const r=Array.isArray(i)?i:[];const s=n.history.present;const a=wn(n.history,Object.is(r,s.root)?s:{...s,root:r},{mergeKey:o.mergeKey,now:o.now});return{...n,history:a,notes:a===n.history?n.notes:[],selected:Er(r,t===void 0?n.selected:t)}}function Lg(n,e,t={}){const o=n.history.present;if(JSON.stringify(e)===JSON.stringify(o.options))return n;return{...n,history:wn(n.history,{...o,options:e},{mergeKey:t.mergeKey,now:t.now})}}function Rg(n,e,t={}){const o=n.history.present;if(e===o.functions)return n;return{...n,history:wn(n.history,{...o,functions:e},{mergeKey:t.mergeKey,now:t.now})}}function Od(n,e){return{...n,history:e,notes:[],selected:Er(e.present.root,n.selected)}}const Fg=n=>n.history.past.length===0?n:Od(n,Ma(n.history));const jg=n=>n.history.future.length===0?n:Od(n,$a(n.history));const oi=/^[A-Za-z_$][\w$]*$/;const Nd=/^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*$/;function Ue(n){const e=n.split("'").length-1;const t=n.split("\"").length-1;const o=e>t?"\"":"'";const i=n.replace(/[\\'"\n\r\t\u2028\u2029]/g,r=>{switch(r){case"\\":return"\\\\";case"'":case"\"":return r===o?`\\${r}`:r;case"\n":return"\\n";case"\r":return"\\r";case"\t":return"\\t";default:return`\\u${r.charCodeAt(0).toString(16).padStart(4,"0")}`}});return`${o}${i}${o}`}function Id(n){return v(n)&&Object.keys(n).length===1&&typeof n["$fn"]==="string"&&Nd.test(n["$fn"])?n["$fn"]:void 0}function Dd(n){const e=Hn(n);return e!==void 0&&Nd.test(e)?e:void 0}const Ed=(n,e,t={})=>{const o=i=>i===void 0?void 0:t.member?`this.${i}`:i;return{indent:n,width:e,key:i=>oi.test(i)?i:Ue(i),primitive:i=>typeof i==="string"?Ue(i):JSON.stringify(i),special:i=>o(Id(i))??o(Dd(i))??zt(i)?.trim()??null,trailingComma:true}};const zd=n=>Zn(n,2,110);function Pg(n,e="tabs"){return`readonly ${e}: GfyRibbonTab[] = ${Us(n,Ed(4,150,{member:true}))};`}const Ld=(n,e)=>{const t=[];if(!Array.isArray(n))return t;for(const o of n){if(!v(o)||(o["kind"]??"item")!=="item")continue;const i=typeof o["value"]==="string"?o["value"]:o["label"];const r=e&&Array.isArray(o["choices"])&&o["choices"].length>0;if(typeof i==="string"&&!r)t.push(i);t.push(...Ld(o["choices"],e))}return t};function Wg(n){const e=/* @__PURE__ */new Map;const t=(o,i)=>{const r=e.get(o);if(r)r.uses.push(i);else e.set(o,{action:o,uses:[i]})};(Array.isArray(n)?n:[]).forEach((o,i)=>{const r=v(o)&&Array.isArray(o["sections"])?o["sections"]:[];r.forEach((s,a)=>{if(!v(s))return;const l=[i,"sections",a];if(typeof s["launcher"]==="string"&&s["launcher"]!==""){t(s["launcher"],{path:[...l,"launcher"],source:"launcher",title:bt(s["title"])??String(s["title"]??s["id"]??""),location:Zt(n,l),emits:"nothing",choices:[]})}const d=Array.isArray(s["items"])?s["items"]:[];d.forEach((c,p)=>{if(!v(c)||typeof c["action"]!=="string"||c["action"]==="")return;const h=typeof c["type"]==="string"?c["type"]:void 0;const u=J(h);const f=[...l,"items",p];const m=[c["label"],c["tooltip"],c["id"],h].find(y=>(bt(y)??"")!=="");const g=Ld(c["choices"],eo(u).submenu);t(c["action"],{path:f,source:"item",type:h,title:bt(m)??"",location:Zt(n,f),emits:u?.emits??"whatever the control reports",choices:g})})})});return[...e.values()]}function Kg(n){if(n.source==="launcher")return[`The launcher of the section "${n.title}" (${n.location})`];const e=J(n.type);const t=[`${e?e.label:n.type??"Item"} "${n.title}" (${n.location})`];if(n.emits!=="nothing"){const o=n.choices.length>0&&n.choices.length<=8?`: ${n.choices.map(Ue).join(" | ")}`:"";t.push(`event.value is ${n.emits}${o}`)}return t}function Rd(n,e={}){const t=e.method??"onAction";const o=e.eventType??"GfyRibbonActionEvent";const i=" ".repeat(e.indent??4);const r=Wg(n);const s=[`${t}(event: ${o}): void {`];if(r.length===0){s.push(`${i}// No item has an "action" yet.`,"}");return s.join("\n")}s.push(`${i}switch (event.item.action) {`);for(const a of r){s.push(`${i}${i}case ${Ue(a.action)}:`);for(const l of a.uses)for(const d of Kg(l))s.push(`${i}${i}${i}// ${d}`);s.push(`${i}${i}${i}break;`)}s.push(`${i}}`,"}");return s.join("\n")}function Fd(n){const e=[];(Array.isArray(n)?n:[]).forEach((t,o)=>{const i=v(t)&&Array.isArray(t["sections"])?t["sections"]:[];i.forEach((r,s)=>{const a=v(r)&&Array.isArray(r["items"])?r["items"]:[];a.forEach((l,d)=>{if(!v(l))return;const c=typeof l["type"]==="string"?l["type"]:void 0;const p=(f,m,g)=>{if(!v(f))return;for(const[y,b]of Object.entries(f)){const x=Id(b);if(x===void 0)continue;e.push({name:x,input:y,path:[...m,y],location:Zt(n,m.slice(0,5)),signature:J(g)?.inputs.find(T=>T.name===y)?.signature})}};const h=[o,"sections",s,"items",d];p(l["inputs"],[...h,"inputs"],c);const u=l["compact"];if(v(u))p(u["inputs"],[...h,"compact","inputs"],typeof u["type"]==="string"?u["type"]:c)})})});return e}function _g(n){const e=Fd(n);if(e.length===0)return"";const t=/* @__PURE__ */new Map;for(const i of e)t.set(i.name,[...(t.get(i.name)??[]),i]);const o=[];for(const[i,r]of t){const s=r.map(d=>`// ${d.input} of "${d.location}"`);const a=r.find(d=>d.signature)?.signature;if(i.includes(".")){o.push([...s,`// ${i} is a method of this.${i.slice(0,i.lastIndexOf("."))}${a?`: ${a}`:""}`].join("\n"));continue}const l=a?Gg(i,a):`${i}(...args: unknown[]): unknown {
6
+ return undefined;
7
+ }`;o.push([...s,l].join("\n"))}return o.join("\n\n")}function Gg(n,e){const t=/^\((.*)\)\s*=>\s*(.+)$/s.exec(e);if(!t)return`${n}(...args: unknown[]): unknown {
8
+ return undefined;
9
+ }`;const o=t[2].trim();const i=o==="string"?"`${Math.round(percent)} %`":o==="number"?"0":o==="boolean"?"false":"undefined";return`${n}(${t[1]}): ${o} {
10
+ return ${i};
11
+ }`}function Bg(n={},e="onAction"){const t={...Ct,...n};const o=["[tabs]=\"tabs\"",`(action)="${e}($event)"`];if(t.defaultRows!==Aa.defaultRows)o.push(`[defaultRows]="${t.defaultRows}"`);if(t.uniformRows)o.push("[uniformRows]=\"true\"");if(t.colWidth!==null)o.push(`[colWidth]="${t.colWidth}"`);if(t.colGap!==null)o.push(`[colGap]="${t.colGap}"`);if(t.collapsible)o.push("[collapsible]=\"true\"");if(t.search)o.push("[search]=\"true\"");if(t.search&&t.searchPlaceholder!==null)o.push(`searchPlaceholder="${t.searchPlaceholder.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;")}"`);return o.length<=3?`<gfy-ribbon ${o.join(" ")} />`:`<gfy-ribbon
12
+ ${o.map(i=>` ${i}`).join("\n")}
13
+ />`}function Vg(n){const e=/* @__PURE__ */new Set;const t=o=>{const i=zt(o);if(i!==void 0){const r=Vs(i);if(r)e.add(r.callee)}else if(Array.isArray(o))o.forEach(t);else if(v(o))Object.values(o).forEach(t)};t(n);return[...e]}function Hg(n){const e=/* @__PURE__ */new Set;const t=o=>{const i=Dd(o);if(i!==void 0)e.add(i);else if(Array.isArray(o))o.forEach(t);else if(v(o))Object.values(o).forEach(t)};t(n);return[...e]}function qg(n,e="ribbon.json"){const t=[.../* @__PURE__ */new Set([...Fd(n).map(s=>s.name),...Vg(n)])].filter(s=>!qn.includes(s));const o=Yg(n)[0];const i=[`import {gfyLoadRibbon, GfyRibbonTab} from '@gridify/studio';`,`import ribbon from './${e}';`,"","readonly loaded = gfyLoadRibbon(ribbon, {"];i.push(t.length>0?` functions: {${t.map(Ug).join(", ")}}, // {"$fn": "name"} and the calls such as s.field('size', 11); tr('Home') is the translation of the library`:` // functions: {nameInJson: this.nameInJson}, // {"$fn": "name"} and the calls such as s.field('size', 11); tr('Home') is the translation of the library`);const r=Hg(n);i.push(r.length>0?` signals: {${r.map(s=>oi.test(s)?`${s}: this.${s}`:`${Ue(s)}: this[${Ue(s)}]`).join(", ")}}, // {"$bind": "name"}: the signals of the application`:" // signals: {noSelection: this.noSelection}, // {\"$bind\": \"name\"}: the signals of the application");i.push(` // items: {${o===void 0?"":` ${oi.test(o)?o:Ue(o)}: {disabled: this.noSelection} `}}, // signals and handlers by the "id" of an item`);i.push(` // sections: {'home/clipboard': {hidden: this.readOnly}}, // by "<tab id>/<section id>"`," // tabs: {picture: {hidden: this.noPicture}}, // by the \"id\" of a tab","});");i.push("readonly tabs: GfyRibbonTab[] = this.loaded.tabs;","// the options of the file go to the element (what the file does not say is undefined, and the element uses its default):","// <gfy-ribbon [tabs]=\"tabs\" [defaultRows]=\"options.defaultRows ?? 3\" [uniformRows]=\"options.uniformRows\" [colWidth]=\"options.colWidth\" [colGap]=\"options.colGap\"","// [collapsible]=\"options.collapsible\" [search]=\"options.search\" [searchPlaceholder]=\"options.searchPlaceholder\" />","readonly options = this.loaded.options;");return i.join("\n")}function Ug(n){if(oi.test(n))return`${n}: this.${n}`;const e=n.split(".");if(e.length>1&&e.every(t=>oi.test(t)))return`${Ue(n)}: this.${n}.bind(this.${e.slice(0,-1).join(".")})`;return`${Ue(n)}: this[${Ue(n)}]`}function Yg(n){const e=[];for(const t of Array.isArray(n)?n:[]){for(const o of v(t)&&Array.isArray(t["sections"])?t["sections"]:[]){for(const i of v(o)&&Array.isArray(o["items"])?o["items"]:[]){if(v(i)&&typeof i["id"]==="string"&&i["id"]!=="")e.push(i["id"])}}}return e}const Jg="The ribbon has to be a list of tabs, [ { ... }, { ... } ], or the file of the editor, an object with the tabs: { \"tabs\": [ ... ] }.";const Xg=n=>v(n)&&Array.isArray(n["tabs"]);function Zg(n){const e=Array.isArray(n)?n.filter(t=>typeof t==="string"&&!/[\s,;]/.test(t.trim())).join(", "):typeof n==="string"?n:"";return sa(e).join(", ")}const Qg=Uo.map(n=>n.key);const eb=Yo.map(n=>n.key);const tb=[...Xt.map(n=>n.key),"choices"];const nb=Jo.map(n=>n.key);const ob=Qs.filter(n=>n!=="inputs");function jd(n){const e=[];const t=(i,r,s)=>{if(!v(i))return;for(const a of s){const l=i[a];if(!v(l)||Object.keys(l).length!==1||typeof l["$fn"]!=="string")continue;i[a]={$bind:l["$fn"]};e.push([...r,a])}};const o=(i,r)=>{if(!Array.isArray(i))return;i.forEach((s,a)=>{t(s,[...r,a],nb);if(v(s))o(s["choices"],[...r,a,"choices"])})};n.forEach((i,r)=>{t(i,[r],Qg);const s=v(i)&&Array.isArray(i["sections"])?i["sections"]:[];s.forEach((a,l)=>{t(a,[r,"sections",l],eb);const d=v(a)&&Array.isArray(a["items"])?a["items"]:[];d.forEach((c,p)=>{const h=[r,"sections",l,"items",p];t(c,h,tb);if(!v(c))return;t(c["compact"],[...h,"compact"],ob);o(c["choices"],[...h,"choices"])})})});return e}const ib=/^(?:this\s*\.\s*)?([A-Za-z_$][\w$]*(?:\s*\.\s*[A-Za-z_$][\w$]*)+)$/;function Pd(n){const e=(t,o)=>{const i=typeof o==="string"?J(o):void 0;if(!v(t)||!i)return;for(const r of i.inputs){const s=t[r.name];if(r.kind!=="function"||!v(s)||Object.keys(s).length!==1||typeof s["$expr"]!=="string")continue;const a=ib.exec(s["$expr"].trim());if(a)t[r.name]={$fn:a[1].replace(/\s+/g,"")}}};for(const t of n){const o=v(t)&&Array.isArray(t["sections"])?t["sections"]:[];for(const i of o){const r=v(i)&&Array.isArray(i["items"])?i["items"]:[];for(const s of r){if(!v(s))continue;e(s["inputs"],s["type"]);const a=s["compact"];if(v(a))e(a["inputs"],a["type"]??s["type"])}}}}const Oa=n=>Array.isArray(n)?n.some(Oa):v(n)?Object.keys(n).length===1&&typeof n["$fn"]==="string"||Object.values(n).some(Oa):false;const rb="A name is read as a reference to a function: {\"$fn\": \"name\"}.";const Wd=(n,e)=>Oa(e)?n:n.filter(t=>t.template!==rb);function Kd(n,e,t){if(n.length===0)return[];const o=e.get(q([...t,...n[0]]))??{line:1,column:1,offset:0};return[{...o,template:"A name in a property of the ribbon was read as the signal of that name, {\"$bind\": \"name\"}: {count} in all. Only an input of a control takes a function.",params:{count:n.length}}]}function _d(n){const e=Xn(n,{lenient:true});if(!e.ok)return{ok:false,error:e.error};const t=e.value;if(Xg(t)){const i=t["tabs"];const r=$g(v(t["options"])?t["options"]:{});const s={options:r.options,functions:Zg(t["functions"])};const a=[...e.notes];for(const l of r.notes){const d=e.positions.get(q(["options",l.key]))??e.positions.get(q(["options"]))??{line:1,column:1,offset:0};a.push({...d,template:l.template,params:l.params})}a.push(...Kd(jd(i),e.positions,["tabs"]));Pd(i);return{ok:true,tabs:i,settings:s,notes:Wd(a,i)}}if(Array.isArray(t)){const i=[...e.notes,...Kd(jd(t),e.positions,[])];Pd(t);return{ok:true,tabs:t,settings:null,notes:Wd(i,t)}}const o=e.positions.get("[]")??{line:1,column:1,offset:0};return{ok:false,error:{...o,template:Jg,params:{}}}}function sb(n,e){return zd({functions:sa(e.functions),options:Cg(e.options),tabs:n})}const Gd=n=>`t${n}`;const ab=n=>`s${n}`;let ii=vr(wr);const ri=n=>{const e=zt(n);if(e!==void 0)return Gc(e,ii);return Hn(n)===void 0?n:void 0};const Te=n=>bt(n,ii);const po=n=>{const e=ri(n);return typeof e==="boolean"?e:void 0};const si=64;const ai=(n,e=1)=>{const t=ri(n);return typeof t==="number"&&Number.isInteger(t)&&t>=e?Math.min(t,si):void 0};const lb=n=>n.replace(/repeat\(\s*(\d+)/g,(e,t)=>Number(t)>si?`repeat(${si}`:e);const Bd=n=>ri(n)==="all"?"all":ai(n);const zr=(n,e)=>n===void 0||n===""||!e.icon?n:e.icon(n);const Vd=n=>Js.find(e=>e===n);const vn=n=>{const e={};for(const[t,o]of n)if(o!==void 0)e[t]=o;return e};const cb=n=>()=>`ƒ ${n}`;function Hd(n,e){if(!v(e))return void 0;const t={};for(const o of n.inputs){const i=e[o.name];if(i===void 0)continue;if(o.kind==="function"){const a=zt(i);if(v(i)&&typeof i["$fn"]==="string")t[o.name]=cb(i["$fn"]);else if(a!==void 0)t[o.name]=()=>Bo(a);continue}const r=ri(i);if(r===void 0)continue;const s=(()=>{switch(o.kind){case"boolean":return typeof r!=="boolean";case"integer":return!Number.isInteger(r)||o.min!==void 0&&r<o.min;case"number":return typeof r!=="number"||!Number.isFinite(r);case"text":return typeof r!=="string";case"choice":return typeof r!=="string"||!o.options?.includes(r);case"list":return!Array.isArray(r)||!r.every(a=>typeof a==="string");default:return false}})();if(!s)t[o.name]=r}return Object.keys(t).length>0?t:void 0}function qd(n,e){if(!Array.isArray(n))return void 0;return n.map(t=>{if(!v(t))return{label:""};const o=Mc.find(r=>r===t["kind"]);if(o==="source")return vn([["label",`‹${Te(t["label"])||Te(t["source"])||"?"}›`],["icon",zr(Te(t["icon"]),e)],["disabled",true]]);const i=v(t["style"])&&Object.values(t["style"]).every(r=>typeof r==="string")?t["style"]:void 0;return vn([["kind",o],["label",Te(t["label"])??""],["value",Te(t["value"])],["icon",zr(Te(t["icon"]),e)],["checked",po(t["checked"])],["disabled",po(t["disabled"])],["style",i],["preview",Te(t["preview"])],["shortcut",Te(t["shortcut"])],["choices",qd(t["choices"],e)]])})}function db(n,e){const t=ri(e);switch(n.value){case"number":if(typeof t==="number"&&Number.isFinite(t))return t;return typeof t==="string"&&t.trim()!==""&&Number.isFinite(Number(t))?Number(t):void 0;case"text":if(n.choices==="required"&&(typeof t==="number"||typeof t==="boolean"))return t;return typeof t==="string"?t:void 0;case"any":return typeof t==="string"||typeof t==="number"?t:void 0;default:return void 0}}const Na=n=>[["col",ai(n["col"])],["row",ai(n["row"])],["colSpan",Bd(n["colSpan"])],["rowSpan",Bd(n["rowSpan"])],["justify",Vd(n["justify"])],["align",Vd(n["align"])]];function pb(n,e){if(!v(n))return void 0;const t=typeof n["type"]==="string"&&J(n["type"])?n["type"]:void 0;const o=J(t??e);const i=vn([["type",t],...Na(n),["inputs",o?Hd(o,n["inputs"]):void 0]]);return Object.keys(i).length>0?i:void 0}function hb(n,e){if(!v(n))return{type:"label",label:"?"};const t=Lt(n);if(t!==void 0)return{type:"label",label:Bo(t)};const o=Te(n["type"]);const i=J(o);if(!i){return vn([["type","label"],["label",`‹${o??"?"}›`],["tooltip",o?`The control "${o}" is not built in, so the editor shows its place only.`:"The item has no \"type\"."],...Na(n)])}return vn([["type",i.type],["inputs",Hd(i,n["inputs"])],...Na(n),["label",Te(n["label"])],["icon",zr(Te(n["icon"]),e)],["iconColor",Te(n["iconColor"])],["tooltip",Te(n["tooltip"])],["description",Te(n["description"])],["disabled",po(n["disabled"])],["disabledReason",Te(n["disabledReason"])],["value",db(i,n["value"])],["checked",i.checked?po(n["checked"]):void 0],["choices",i.choices==="none"?void 0:qd(n["choices"],e)],["action",Te(n["action"])],["shortcut",Te(n["shortcut"])],["keytip",Te(n["keytip"])],["compact",pb(n["compact"],i.type)]])}function ub(n,e,t){const o=ab(e);if(!v(n))return{id:o,title:"?",items:[]};const i=Lt(n);if(i!==void 0)return{id:o,title:Bo(i),items:[]};const r=s=>ai(s)??(typeof s==="string"&&s.trim()!==""?lb(s):void 0);return vn([["id",o],["title",Te(n["title"])??""],["columns",r(n["columns"])],["compactColumns",r(n["compactColumns"])],["launcher",Te(n["launcher"])||void 0],["icon",zr(Te(n["icon"]),t)],["collapsePriority",typeof n["collapsePriority"]==="number"&&Number.isFinite(n["collapsePriority"])?n["collapsePriority"]:void 0],["collapsible",po(n["collapsible"])],["items",(Array.isArray(n["items"])?n["items"]:[]).map(s=>hb(s,t))]])}function Ud(n,e={}){if(!Array.isArray(n))return[];const t=ii;ii=e.functions??vr(wr);try{return fb(n,e)}finally{ii=t}}function fb(n,e){return n.map((t,o)=>{const i=Gd(o);if(!v(t))return{id:i,label:"?",sections:[]};const r=Lt(t);if(r!==void 0)return{id:i,label:Bo(r),sections:[]};return vn([["id",i],["label",Te(t["label"])??`Tab ${o+1}`],["rows",ai(t["rows"])],["contextual",po(t["contextual"])],["keytip",Te(t["keytip"])],["sections",(Array.isArray(t["sections"])?t["sections"]:[]).map((s,a)=>ub(s,a,e))]])})}const mb=[{id:"home",label:"Home",sections:[{id:"clipboard",title:"Clipboard",items:[{type:"large-button",id:"paste",col:1,colSpan:3,icon:"rbe:paste",label:"Paste",action:"paste"}]}]}];const gb=[{id:"home",label:"Home",keytip:"H",sections:[{id:"clipboard",title:"Clipboard",launcher:"clipboard-options",items:[{type:"split-button",id:"paste",col:1,colSpan:3,label:"Paste",icon:"rbe:paste",action:"paste",shortcut:"Mod+V",keytip:"V",description:"Puts what you cut or copied into the document. The arrow offers other ways to paste.",inputs:{size:"large"},choices:[{label:"Paste",value:"paste",icon:"rbe:paste"},{label:"Paste as text",value:"text",shortcut:"Mod+Shift+V"},{kind:"separator"},{label:"Paste special…",value:"special"}]},{type:"button",id:"cut",col:4,row:1,colSpan:5,label:"Cut",icon:"rbe:cut",action:"cut",shortcut:"Mod+X",keytip:"X"},{type:"button",id:"copy",col:4,row:2,colSpan:5,label:"Copy",icon:"rbe:copy",action:"copy",shortcut:"Mod+C",keytip:"C"},{type:"button",id:"formatPainter",col:4,row:3,colSpan:5,label:"Format Painter",icon:"rbe:format-painter",action:"format-painter",keytip:"FP"}]},{id:"font",title:"Font",columns:12,compactColumns:3,items:[{type:"combobox",id:"fontFamily",action:"font-family",value:"Calibri",colSpan:8,col:1,row:1,tooltip:"Font",inputs:{placeholder:"Font"},choices:[{label:"Calibri"},{label:"Georgia"},{label:"Consolas"}]},{type:"spinner",id:"fontSize",action:"font-size",value:11,col:9,colSpan:4,row:1,tooltip:"Font size",inputs:{min:6,max:96,step:1,unit:"pt"}},{type:"toggle-button",id:"bold",icon:"rbe:bold",action:"bold",shortcut:"Mod+B",keytip:"1",tooltip:"Bold",col:1,row:2,inputs:{iconOnly:true}},{type:"toggle-button",id:"italic",icon:"rbe:italic",action:"italic",shortcut:"Mod+I",keytip:"2",tooltip:"Italic",col:2,row:2,inputs:{iconOnly:true}},{type:"toggle-button",id:"underline",icon:"rbe:underline",action:"underline",shortcut:"Mod+U",keytip:"3",tooltip:"Underline",col:3,row:2,inputs:{iconOnly:true}},{type:"color-picker",id:"fontColor",label:"Font color",action:"font-color",value:"#c00000",col:4,colSpan:3,row:2,inputs:{automatic:"#000000",moreColors:true}}]},{id:"paragraph",title:"Paragraph",items:[{type:"toggle-group",id:"alignment",col:1,row:1,colSpan:8,action:"align",inputs:{exclusive:true},choices:[{label:"Left",value:"left",icon:"rbe:align-left",checked:true},{label:"Center",value:"center",icon:"rbe:align-center"},{label:"Right",value:"right",icon:"rbe:align-right"}]},{type:"select",id:"lineSpacing",col:1,row:2,colSpan:8,action:"line-spacing",value:"1.15",tooltip:"Line spacing",choices:[{label:"1.0",value:"1.0"},{label:"1.15",value:"1.15"},{label:"1.5",value:"1.5"},{label:"2.0",value:"2.0"}]}]}]},{id:"insert",label:"Insert",keytip:"N",sections:[{id:"tables",title:"Tables",items:[{type:"table-picker",id:"table",col:1,colSpan:2,label:"Table",icon:"rbe:table",action:"insert-table",inputs:{size:"large",columns:8,rows:6}}]},{id:"illustrations",title:"Illustrations",items:[{type:"large-button",id:"picture",col:1,colSpan:3,label:"Picture",icon:"rbe:image",action:"insert-picture",keytip:"P"},{type:"dropdown-button",id:"shapes",col:4,colSpan:3,label:"Shapes",icon:"rbe:shapes",action:"insert-shape",value:"rectangle",inputs:{size:"large"},choices:[{label:"Rectangle",value:"rectangle"},{label:"Ellipse",value:"ellipse"},{label:"Triangle",value:"triangle"}]}]},{id:"links",title:"Links",items:[{type:"styled-button",id:"link",col:1,row:1,colSpan:6,label:"Link",icon:"rbe:link",action:"insert-link",shortcut:"Mod+K",inputs:{variant:"primary"}},{type:"label",id:"linkHint",col:1,row:2,colSpan:6,label:"Links open in a new window"}]},{id:"styles",title:"Styles",items:[{type:"gallery",id:"styleGallery",col:1,colSpan:7,action:"style",value:"normal",rowSpan:"all",inputs:{pageSize:3},choices:[{label:"Normal",value:"normal",preview:"AaBb"},{label:"Heading 1",value:"h1",preview:"AaBb",style:{"font-weight":"700","font-size":"18px"}},{label:"Heading 2",value:"h2",preview:"AaBb",style:{"font-weight":"600"}},{label:"Quote",value:"quote",preview:"AaBb",style:{"font-style":"italic"}}]}]}]},{id:"view",label:"View",keytip:"W",sections:[{id:"show",title:"Show",items:[{type:"checkbox",id:"ruler",col:1,row:1,colSpan:5,label:"Ruler",action:"ruler",checked:true},{type:"checkbox",id:"gridlines",col:1,row:2,colSpan:5,label:"Gridlines",action:"gridlines"},{type:"checkbox",id:"navigation",col:1,row:3,colSpan:5,label:"Navigation pane",action:"navigation",checked:true}]},{id:"layout",title:"Layout",items:[{type:"radio",id:"layoutPrint",col:1,row:1,colSpan:4,label:"Print layout",action:"layout-print",checked:true,inputs:{group:"layout"}},{type:"radio",id:"layoutWeb",col:1,row:2,colSpan:4,label:"Web layout",action:"layout-web",inputs:{group:"layout"}},{type:"radio",id:"layoutOutline",col:1,row:3,colSpan:4,label:"Outline",action:"layout-outline",inputs:{group:"layout"}}]},{id:"zoom",title:"Zoom",items:[{type:"large-button",id:"zoomDialog",col:1,colSpan:2,label:"Zoom",icon:"rbe:zoom",action:"zoom"},{type:"spinner",id:"zoomPercent",col:3,row:1,colSpan:4,action:"zoom-percent",value:100,tooltip:"Zoom",inputs:{min:10,max:500,step:10,unit:"%"}}]},{id:"status",title:"Status",items:[{type:"progress-bar",id:"saved",col:1,row:1,colSpan:6,label:"Saved",value:70,inputs:{showValue:true,variant:"success",valueText:{$fn:"percentText"}}},{type:"progress-ring",id:"pages",col:7,colSpan:2,label:"Pages",value:35,inputs:{showValue:true,size:"large",variant:"accent"}}]}]}];const bb=[];const Yd=[{id:"showcase",label:"Text editor (all 18 controls)",root:gb},{id:"basic",label:"One button",root:mb},{id:"empty",label:"Empty list",root:bb}];function Jd(n){return Yd.find(e=>e.id===n)}function Ia(){const n=(e,t={})=>e.replace(/\{([A-Za-z_][A-Za-z0-9_]*)\}/g,(o,i)=>Object.prototype.hasOwnProperty.call(t,i)?String(t[i]):o);return{text:n,signal:e=>E(e).asReadonly()}}const I=Ia();function Da(n){return new Promise(e=>{const t=document.createElement("input");t.type="file";t.accept=n;t.addEventListener("change",()=>{const o=t.files?.[0];if(!o)return e(null);o.text().then(i=>e({name:o.name,text:i}),()=>e(null))});t.addEventListener("cancel",()=>e(null));t.click()})}function li(n,e,t="text/plain"){const o=URL.createObjectURL(new Blob([n],{type:t}));const i=document.createElement("a");i.href=o;i.download=e;i.click();setTimeout(()=>URL.revokeObjectURL(o),1e3)}async function Ea(){try{return await navigator.clipboard.readText()}catch{return null}}async function Lr(n){try{await navigator.clipboard.writeText(n);return true}catch{return false}}function yb(n){return n.dataTransfer?.types.includes("Files")===true}function za(n){if(!yb(n)||!n.dataTransfer)return;n.preventDefault();n.dataTransfer.dropEffect="copy"}function La(n){const e=n.dataTransfer?.files?.[0];if(!e)return null;n.preventDefault();return e.text().then(t=>({name:e.name,text:t}),()=>null)}class ci extends Error{path;name="GfyEditorFileConflict";constructor(e,t=`${e} is not the file that was expected.`){super(t);this.path=e}}const Rr=n=>typeof n==="object"&&n!==null?n.name:void 0;const wb=n=>n instanceof ci||Rr(n)==="GfyEditorFileConflict";const Fr=n=>n!==""&&n!=="."&&n!==".."&&!/[/\\\u0000-\u001f]/.test(n);function ho(n){if(n==="")return[];const e=n.split("/");if(!e.every(Fr))throw new Error(`"${n}" is not a path of the project.`);return e}const jr=(n,e)=>n===""?e:`${n}/${e}`;const jt=n=>n.includes("/")?n.slice(0,n.lastIndexOf("/")):"";const Pr=n=>n.slice(n.lastIndexOf("/")+1);function vb(n){const e=n.url.trim().replace(/\/+$/,"");const t=n.fetch??((d,c)=>fetch(d,c));const o=()=>({...(typeof n.headers==="function"?n.headers():n.headers)});const i=(d,c)=>{const p=new URL(n.url.trim(),globalThis.location?.href??"http://localhost/");p.pathname=`${p.pathname.replace(/\/+$/,"")}/${d}`;p.searchParams.set("path",c);return p.toString()};const r=async(d,c)=>{try{return await t(d,{credentials:n.credentials,...c})}catch(p){if(Rr(p)==="AbortError")throw p;throw new Error(`The server ${e} cannot be reached: is it running, and does it allow this page (CORS)? (${p instanceof Error?p.message:String(p)})`,{cause:p})}};const s=async(d,c)=>{let p="";try{p=(await d.text()).trim().slice(0,300)}catch{}return new Error(`${c}: the server answered ${d.status}${d.statusText?` ${d.statusText}`:""}${p?` (${p})`:""}.`)};let a=false;const l=d=>{const c=d.headers.get("ETag");if(c===null&&!a){a=true;console.warn(`gfyHttpFiles: ${e} gives no ETag (or does not expose it: Access-Control-Expose-Headers), so the editors cannot tell a file that was changed elsewhere and write over it.`)}return c};return{id:n.id??e,label:n.label??e,async list(d){ho(d);const c=await r(i("list",d),{headers:o(),cache:"no-store"});if(!c.ok)throw await s(c,`The folder ${d||"/"} could not be listed`);const p=await c.json().catch(()=>null);const h=Array.isArray(p)?p:null;if(h===null)throw new Error(`The folder ${d||"/"} could not be listed: the server did not answer with a list of entries.`);return h.filter(u=>xb(u)).map(u=>({name:u.name,kind:u.kind}))},async read(d){ho(d);const c=await r(i("file",d),{headers:o(),cache:"no-store"});if(!c.ok)throw await s(c,`${d} could not be read`);return{text:await c.text(),version:l(c)}},async write(d,c,p={}){ho(d);const h={};if(p.ifVersion!==void 0)h["If-Match"]=p.ifVersion;if(p.ifAbsent)h["If-None-Match"]="*";const u=await r(i("file",d),{method:"PUT",headers:{...o(),"Content-Type":"text/plain; charset=utf-8",...h},body:c});if(u.status===412)throw new ci(d);if(!u.ok)throw await s(u,`${d} could not be written`);return{version:l(u)}}}}const xb=n=>typeof n==="object"&&n!==null&&typeof n.name==="string"&&Fr(n.name)&&["file","folder"].includes(n.kind);const Xd=()=>globalThis.showDirectoryPicker;const kb=()=>typeof Xd()==="function"&&globalThis.isSecureContext===true;async function Sb(n){const e=Xd();if(!e)throw new Error("This browser cannot open a folder of the computer: Chrome, Edge and the other browsers of Chromium can (on HTTPS or localhost).");try{return await e({mode:"readwrite",...(n?{id:n}:{})})}catch(t){if(Rr(t)==="AbortError")return null;throw t}}function Tb(n,e={}){const t=async()=>{const s=n;if(!s.queryPermission)return;if((await s.queryPermission({mode:"readwrite"}))==="granted")return;if((await s.requestPermission?.({mode:"readwrite"}))==="granted")return;throw new Error(`The browser may not read and write the folder ${n.name}: allow it when the browser asks.`)};const o=async s=>{let a=n;for(const l of ho(s))a=await a.getDirectoryHandle(l);return a};const i=async(s,a)=>{try{return await s.getFileHandle(a)}catch(l){if(Rr(l)==="NotFoundError")return null;throw l}};const r=s=>`${s.lastModified}-${s.size}`;return{...(e.id!==void 0?{id:e.id}:{}),label:e.label??n.name,async list(s){await t();const a=[];for await(const l of(await o(s)).values())a.push({name:l.name,kind:l.kind==="directory"?"folder":"file"});return a},async read(s){await t();const a=ho(s);const l=await(await o(jt(s))).getFileHandle(a[a.length-1]??"");const d=await l.getFile();return{text:await d.text(),version:r(d)}},async write(s,a,l={}){await t();const d=ho(s);const c=d[d.length-1];if(c===void 0)throw new Error("A file needs a name.");const p=await o(jt(s));const h=await i(p,c);if(l.ifAbsent&&h)throw new ci(s);if(l.ifVersion!==void 0&&(!h||r(await h.getFile())!==l.ifVersion))throw new ci(s);const u=h??(await p.getFileHandle(c,{create:true}));const f=await u.createWritable();try{await f.write(a);await f.close()}catch(m){await f.abort().catch(()=>void 0);throw m}return{version:r(await u.getFile())}}}}const Mb=/[<>:"|?*\\/\u0000-\u001f]/;const $b=(n,e)=>n.kind===e.kind?n.name.localeCompare(e.name,void 0,{numeric:true,sensitivity:"base"}):n.kind==="folder"?-1:1;const Zd=n=>n instanceof Error?n.message:String(n);class Ri{files=we.required(...(ngDevMode?[{debugName:"files"}]:([])));mode=we("open",...(ngDevMode?[{debugName:"mode"}]:([])));extension=we(".json",...(ngDevMode?[{debugName:"extension"}]:([])));icons=we("",...(ngDevMode?[{debugName:"icons"}]:([])));folder=we("",...(ngDevMode?[{debugName:"folder"}]:([])));name=Ls("",...(ngDevMode?[{debugName:"name"}]:([])));ref=lc();listings=E(/* @__PURE__ */new Map,...(ngDevMode?[{debugName:"listings"}]:([])));expanded=E(/* @__PURE__ */new Set,...(ngDevMode?[{debugName:"expanded"}]:([])));selected=E(null,...(ngDevMode?[{debugName:"selected"}]:([])));target=E("",...(ngDevMode?[{debugName:"target"}]:([])));failure=E("",...(ngDevMode?[{debugName:"failure"}]:([])));fileIcon=M(()=>this.icons()?`${this.icons()}:project-file`:"",...(ngDevMode?[{debugName:"fileIcon"}]:([])));folderIcon=M(()=>this.icons()?`${this.icons()}:project-folder`:"",...(ngDevMode?[{debugName:"folderIcon"}]:([])));nodes=M(()=>{const e=this.listings();const t=this.extension().toLowerCase();const o=i=>{const r=e.get(i);if(r?.state!=="loaded")return[];return[...r.entries].filter(s=>Fr(s.name)&&!s.name.startsWith(".")&&(s.kind==="folder"||s.name.toLowerCase().endsWith(t))).sort($b).map(s=>{const a=jr(i,s.name);if(s.kind==="file")return{id:a,name:s.name,kind:"file",icon:this.fileIcon(),title:a};const l=e.get(a);return{id:a,name:s.name,kind:"folder",icon:this.folderIcon(),title:a,lazy:l?.state!=="loaded",loading:l?.state==="loading",...(l?.state==="loaded"?{children:o(a)}:{})}})};return o("")},...(ngDevMode?[{debugName:"nodes"}]:([])));emptyText=M(()=>{const e=this.listings().get("");if(e===void 0||e.state==="loading")return"Loading…";if(e.state==="failed")return"The project could not be listed.";return`No folder and no ${this.extension()} file here.`},...(ngDevMode?[{debugName:"emptyText"}]:([])));kindOf(e){if(e===null)return null;const t=this.listings().get(jt(e));if(t?.state!=="loaded")return null;return t.entries.find(o=>o.name===Pr(e))?.kind??null}nameProblem=M(()=>{const e=this.name().trim();const t=this.extension();if(e==="")return"Type the name of the file.";if(e.includes("/")||e.includes("\\"))return"Type a name without a folder: choose the folder in the list.";if(Mb.test(e)||/[. ]$/.test(e)||!Fr(e))return"A name of a file cannot have the characters < > : \" | ? * and cannot end with a dot or a space.";if(!e.toLowerCase().endsWith(t.toLowerCase())||e.length===t.length)return`The name of a file of the editor ends with ${t}.`;if(e.startsWith("."))return"A name of a file cannot start with a dot: the list does not show such a file.";if(this.kindOf(jr(this.target(),e))==="folder")return`${e} is a folder.`;return""},...(ngDevMode?[{debugName:"nameProblem"}]:([])));chosen=M(()=>{if(this.mode()==="open")return this.kindOf(this.selected())==="file"?this.selected():null;return this.nameProblem()===""?jr(this.target(),this.name().trim()):null},...(ngDevMode?[{debugName:"chosen"}]:([])));problem=M(()=>this.failure()||(this.mode()==="save"&&this.listings().get("")?.state==="loaded"?this.nameProblem():""),...(ngDevMode?[{debugName:"problem"}]:([])));where=M(()=>{const e=this.chosen();if(e===null)return this.mode()==="open"?`Choose a ${this.extension()} file.`:"";return this.mode()==="open"?`Opens ${e}`:this.kindOf(e)==="file"?`Replaces ${e}`:`Saves as ${e}`},...(ngDevMode?[{debugName:"where"}]:([])));constructor(){Q(()=>this.ref.patchButton("ok",{disabled:this.chosen()===null}));Q(()=>{const e=this.files();const t=this.folder();ee(()=>void this.start(e,t))})}async start(e,t){const o=[""];if(t!==""){const s=t.split("/");s.forEach((a,l)=>o.push(s.slice(0,l+1).join("/")))}this.target.set("");for(const s of o){if(s!==""&&this.kindOf(s)!=="folder")break;if(!(await this.load(e,s)))break;if(s!==""){this.expanded.update(a=>/* @__PURE__ */new Set([...a,s]));this.target.set(s)}}const i=this.name().trim();const r=i!==""?jr(this.target(),i):null;this.select(r!==null&&this.kindOf(r)==="file"?r:this.target()!==""?this.target():null)}select(e){this.selected.set(e);const t=this.kindOf(e);if(e===null||t===null)return;if(t==="folder")this.target.set(e);else{this.target.set(jt(e));if(this.mode()==="save")this.name.set(Pr(e))}}async load(e,t){const o=this.listings().get(t);if(o?.state==="loaded")return true;if(o?.state==="loading")return false;this.setListing(t,{state:"loading"});try{const i=await e.list(t);if(this.files()!==e)return false;this.setListing(t,{state:"loaded",entries:i});this.failure.set("");return true}catch(i){this.setListing(t,{state:"failed",message:Zd(i)});this.failure.set(`${t===""?"The project":t} could not be listed: ${Zd(i)}`);this.expanded.update(r=>r.has(t)?new Set([...r].filter(s=>s!==t)):r);return false}}setListing(e,t){this.listings.update(o=>new Map(o).set(e,t))}toggled(e){if(e.open&&e.node.kind==="folder")void this.load(this.files(),e.node.id)}activated(e){if(e.kind!=="file")return;this.select(e.id);this.submit()}submit(){const e=this.chosen();if(e!==null)this.ref.close(e)}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Ri,deps:[],target:w.ɵɵFactoryTarget.Component});static ɵcmp=w.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"21.2.21",type:Ri,isStandalone:true,selector:"edk-project-file-dialog",inputs:{files:{classPropertyName:"files",publicName:"files",isSignal:true,isRequired:true,transformFunction:null},mode:{classPropertyName:"mode",publicName:"mode",isSignal:true,isRequired:false,transformFunction:null},extension:{classPropertyName:"extension",publicName:"extension",isSignal:true,isRequired:false,transformFunction:null},icons:{classPropertyName:"icons",publicName:"icons",isSignal:true,isRequired:false,transformFunction:null},folder:{classPropertyName:"folder",publicName:"folder",isSignal:true,isRequired:false,transformFunction:null},name:{classPropertyName:"name",publicName:"name",isSignal:true,isRequired:false,transformFunction:null}},outputs:{name:"nameChange"},ngImport:w,template:`
14
+ <div class="tree">
15
+ <gfy-explorer
16
+ [nodes]="nodes()"
17
+ [(expanded)]="expanded"
18
+ [selected]="selected()"
19
+ (selectedChange)="select($event)"
20
+ ariaLabel="Folders and files of the project"
21
+ [emptyText]="emptyText()"
22
+ (nodeToggled)="toggled($event)"
23
+ (nodeActivated)="activated($event)" />
24
+ </div>
25
+ @if (mode() === 'save') {
26
+ <gfy-input label="File name" [(value)]="name" [spellcheck]="false" autocomplete="off" />
27
+ }
28
+ <p class="line" [class.problem]="problem() !== ''" role="status">{{ problem() || where() }}</p>
29
+ `,isInline:true,styles:[":host{display:flex;flex-direction:column;gap:8px;height:100%;min-height:0;font:13px/1.4 var(--gfy-font-main, system-ui, sans-serif);color:var(--gfy-text-main)}.tree{flex:1 1 0;min-height:120px;border:1px solid var(--gfy-border-color, var(--gfy-border, rgba(127, 127, 127, .35)));border-radius:var(--gfy-radius-sm, 3px);overflow:hidden}.line{margin:0;min-height:1.4em;font-size:12px;color:var(--gfy-text-muted, inherit);overflow-wrap:anywhere}.line.problem{color:var(--gfy-warning-text, var(--gfy-warning, #b45309))}\n"],dependencies:[{kind:"component",type:cc,selector:"gfy-explorer",inputs:["nodes","expanded","selected","active","tools","toolbar","collapseToLevel","nodeMenu","ariaLabel","emptyText","moveRules","canMove"],outputs:["expandedChange","selectedChange","nodeActivated","nodeToggled","nodeRenamed","nodeMoved","nodeKeydown"]},{kind:"component",type:Ps,selector:"gfy-input",inputs:["controlId","type","inputmode","startText","endText","startIcon","endIcon","clearable"]}],changeDetection:w.ChangeDetectionStrategy.OnPush})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Ri,decorators:[{type:me,args:[{selector:"edk-project-file-dialog",standalone:true,imports:[cc,Ps],changeDetection:fn.OnPush,template:`
30
+ <div class="tree">
31
+ <gfy-explorer
32
+ [nodes]="nodes()"
33
+ [(expanded)]="expanded"
34
+ [selected]="selected()"
35
+ (selectedChange)="select($event)"
36
+ ariaLabel="Folders and files of the project"
37
+ [emptyText]="emptyText()"
38
+ (nodeToggled)="toggled($event)"
39
+ (nodeActivated)="activated($event)" />
40
+ </div>
41
+ @if (mode() === 'save') {
42
+ <gfy-input label="File name" [(value)]="name" [spellcheck]="false" autocomplete="off" />
43
+ }
44
+ <p class="line" [class.problem]="problem() !== ''" role="status">{{ problem() || where() }}</p>
45
+ `,styles:[":host{display:flex;flex-direction:column;gap:8px;height:100%;min-height:0;font:13px/1.4 var(--gfy-font-main, system-ui, sans-serif);color:var(--gfy-text-main)}.tree{flex:1 1 0;min-height:120px;border:1px solid var(--gfy-border-color, var(--gfy-border, rgba(127, 127, 127, .35)));border-radius:var(--gfy-radius-sm, 3px);overflow:hidden}.line{margin:0;min-height:1.4em;font-size:12px;color:var(--gfy-text-muted, inherit);overflow-wrap:anywhere}.line.problem{color:var(--gfy-warning-text, var(--gfy-warning, #b45309))}\n"]}]}],ctorParameters:()=>[],propDecorators:{files:[{type:w.Input,args:[{isSignal:true,alias:"files",required:true}]}],mode:[{type:w.Input,args:[{isSignal:true,alias:"mode",required:false}]}],extension:[{type:w.Input,args:[{isSignal:true,alias:"extension",required:false}]}],icons:[{type:w.Input,args:[{isSignal:true,alias:"icons",required:false}]}],folder:[{type:w.Input,args:[{isSignal:true,alias:"folder",required:false}]}],name:[{type:w.Input,args:[{isSignal:true,alias:"name",required:false}]},{type:w.Output,args:["nameChange"]}]}});const uo={kind:"new"};const Wr=n=>n.id??n.label;const Ab=n=>n instanceof Error?n.message:String(n);const fo=(n,e)=>n.saved===e?n:{...n,saved:e};class Cb{link=E(null,...(ngDevMode?[{debugName:"link"}]:([])));origin=E(uo,...(ngDevMode?[{debugName:"origin"}]:([])));busy=E(false,...(ngDevMode?[{debugName:"busy"}]:([])));generation=0;lastFolder=""}class Ob{options;dialogs=L(Ws);box=L(fr);source=E(()=>null,...(ngDevMode?[{debugName:"source"}]:([])));current=E(new Cb,...(ngDevMode?[{debugName:"current"}]:([])));files=M(()=>this.source()(),...(ngDevMode?[{debugName:"files"}]:([])));link=M(()=>this.current().link(),...(ngDevMode?[{debugName:"link"}]:([])));linked=M(()=>{const e=this.link();const t=this.files();return e!==null&&t!==null&&e.place===Wr(t)?e:null},...(ngDevMode?[{debugName:"linked"}]:([])));busy=M(()=>this.current().busy(),...(ngDevMode?[{debugName:"busy"}]:([])));origin=M(()=>this.current().origin(),...(ngDevMode?[{debugName:"origin"}]:([])));constructor(e){this.options=e}title(e){return Ib({origin:this.origin(),link:this.link(),files:this.files(),modified:e,noun:this.options.noun})}connect(e){this.source.set(()=>e()??null)}get state(){return this.current()}adopt(e){this.current.set(e)}replaced(e){const t=this.current();t.generation++;t.link.set(null);t.origin.set(e)}linkTo(e){const t=this.current();t.link.set({place:Wr(e.files),label:e.files.label,path:e.path,version:e.version});t.lastFolder=jt(e.path)}async open(){const e=this.files();const t=this.current();if(e===null||t.busy())return null;const o=this.linked();const i=await this.choose(e,"open",o?jt(o.path):t.lastFolder,o?Pr(o.path):"");if(i===null||t.busy())return null;t.busy.set(true);try{const r=await e.read(i);return{files:e,path:i,text:r.text,version:r.version}}catch(r){this.fail(`${i} could not be opened.`,r);return null}finally{t.busy.set(false)}}async save(e,t){const o=this.files();const i=this.linked();if(o===null)return false;if(i===null)return this.saveAs(e,t);return this.write(o,i.path,e,i.version===null?{}:{ifVersion:i.version},"changed")}async saveAs(e,t){const o=this.files();const i=this.current();if(o===null||i.busy())return false;const r=this.linked();const s=await this.choose(o,"save",r?jt(r.path):i.lastFolder,r?Pr(r.path):t);if(s===null)return false;if(r!==null&&s===r.path)return this.write(o,s,e,r.version===null?{}:{ifVersion:r.version},"changed");return this.write(o,s,e,{ifAbsent:true},"exists")}async write(e,t,o,i,r){const s=this.current();if(s.busy())return false;const a=s.generation;s.busy.set(true);this.options.say(`Saving ${t}…`);try{let l;try{l=await e.write(t,o,i)}catch(d){if(!wb(d))throw d;if(!(await this.mayOverwrite(t,r))){this.options.say(`${t} was not saved.`);return false}l=await e.write(t,o)}s.lastFolder=jt(t);this.options.say(`Saved: ${t}.`);if(a!==s.generation)return false;s.link.set({place:Wr(e),label:e.label,path:t,version:l.version});return true}catch(l){this.fail(`${t} could not be saved.`,l);return false}finally{s.busy.set(false)}}mayOverwrite(e,t){const{noun:o}=this.options;return t==="changed"?this.box.confirm(`${e} was changed or removed in the project since it was opened here. Overwrite it with the ${o} you are editing?`,{title:"The file was changed",confirmLabel:"Overwrite",cancelLabel:"Cancel",danger:true}):this.box.confirm(`${e} is in the project already. Replace it with the ${o} you are editing?`,{title:"The file exists",confirmLabel:"Replace",cancelLabel:"Cancel",danger:true})}fail(e,t){this.options.say(e);this.box.error(`${e}
46
+ ${Ab(t)}`,{title:"The files of the project"})}async choose(e,t,o,i){const{noun:r,extension:s,icons:a}=this.options;const l=this.dialogs.open({id:"editor-project:file",title:t==="open"?`Open a ${r} from the project`:`Save the ${r} in the project`,subtitle:e.label,component:Ri,inputs:{files:e,mode:t,extension:s,icons:a,folder:o,name:i},buttons:[{id:"cancel",label:"Cancel",cancel:true,result:null},{id:"ok",label:t==="open"?"Open":"Save",variant:"primary",default:true,disabled:true,closes:false,run:c=>void c.instance?.submit()}],width:560,height:480,fill:true,resizable:true,autoFocus:t==="open"?"[role=\"tree\"]":"input"});const d=await l.closed;return typeof d==="string"?d:null}remember(){const e=this.link();const t={...e,origin:this.origin()};try{localStorage.setItem(this.options.storageKey,JSON.stringify(t))}catch{}}forget(){try{localStorage.removeItem(this.options.storageKey)}catch{}}recall(){try{const e=JSON.parse(localStorage.getItem(this.options.storageKey)??"null");if(typeof e!=="object"||e===null)return;const{place:t,label:o,path:i,version:r,origin:s}=e;const a=this.current();if(Nb(s))a.origin.set(s);if(typeof t!=="string"||typeof o!=="string"||typeof i!=="string"||r!==null&&typeof r!=="string")return;a.link.set({place:t,label:o,path:i,version:r});a.lastFolder=jt(i)}catch{}}}function Nb(n){if(typeof n!=="object"||n===null)return false;const{kind:e,name:t}=n;return e==="new"||e==="clipboard"||(e==="sample"||e==="file")&&typeof t==="string"}const Ra=n=>new Ob(n);function Ib({origin:n,link:e,files:t,modified:o,noun:i}){const r=o?" It has changes that were not saved.":"";const s=(a,l)=>({text:o?`${a} •`:a,tooltip:`${l}${r}`});if(e!==null){if(t!==null&&e.place===Wr(t))return s(e.path,`${e.path}, the file of the project (${e.label}) that File > Save writes.`);return s(e.path,`${e.path}, a file of ${e.label}, which the editor does not have now${t===null?".":": File > Save asks where it goes."}`)}switch(n.kind){case"sample":return s(`Sample: ${n.name}`,`${n.name}, a sample of the editor, in no file yet.`);case"file":return s(n.name,`${n.name}, a file of this computer. The browser cannot write into it: ${t===null?"File > Download the file gives a new file.":"File > Save asks where it goes in the project."}`);case"clipboard":return s("From the clipboard","Pasted from the clipboard, in no file yet.");default:return s(`New ${i}`,`A new ${i}, in no file yet.`)}}const Db=["file","json","typescript","handler","template","usage"];const Fa="application/x-gfy-ribbon-control";const ja="gfy-ribbon-editor:text";const Kr="gfy-ribbon-editor:downloaded";const Pa="gfy-ribbon-editor:autosave";const Eb="gfy-ribbon-editor:project";const _r="ribbon.json";const zb=["gfy-ribbon-editor:functions","gfy-ribbon-editor:cells"];const Qd={remove:false,duplicate:false,moveUp:false,moveDown:false,addSection:false,addChoice:false,addSubChoice:false,choiceEntries:[]};const dt=n=>I.text(n);class Fi extends jn{static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Fi,deps:null,target:w.ɵɵFactoryTarget.Injectable});static ɵprov=w.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Fi,providedIn:"root"})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Fi,decorators:[{type:Pn,args:[{providedIn:"root"}]}]});const Wa=n=>{const e=n.inputs?.["group"];return n.type==="radio"&&typeof e==="string"&&e!==""?e:void 0};function Lb(n){for(const e of n)for(const t of e.sections)for(const o of t.items)if(Wa(o)!==void 0&&!sc(o.checked))o.checked=E(o.checked===true,...(ngDevMode?[{debugName:"checked"}]:([])));return n}function Rb(n,e){const t=Wa(e);if(t===void 0)return;for(const o of n)for(const i of o.sections)for(const r of i.items){if(Wa(r)!==t||!sc(r.checked)||!("set"in r.checked))continue;r.checked.set(r===e)}}const Fb=n=>typeof n["what"]==="string"?{...n,what:I.text(n["what"])}:n;class Ze{toast=L(Ks);box=L(fr);icons=L(Po);project=Ra({noun:"ribbon",extension:".json",icons:"rbe",storageKey:Eb,say:e=>this.say(e)});state=E(co([]),...(ngDevMode?[{debugName:"state"}]:([])));root=M(()=>Ad(this.state()),...(ngDevMode?[{debugName:"root"}]:([])));notes=M(()=>this.state().notes,...(ngDevMode?[{debugName:"notes"}]:([])));selected=M(()=>this.state().selected,{...(ngDevMode?{debugName:"selected"}:({})),equal:(e,t)=>e===t||e!==null&&t!==null&&Fe(e,t)});canUndo=M(()=>lo(this.state().history),...(ngDevMode?[{debugName:"canUndo"}]:([])));canRedo=M(()=>Nr(this.state().history),...(ngDevMode?[{debugName:"canRedo"}]:([])));modified=M(()=>Ng(this.state()),...(ngDevMode?[{debugName:"modified"}]:([])));documentSeq=E(0,...(ngDevMode?[{debugName:"documentSeq"}]:([])));options=M(()=>Cd(this.state()),...(ngDevMode?[{debugName:"options"}]:([])));showGrid=E(false,...(ngDevMode?[{debugName:"showGrid"}]:([])));showBackground=E(false,...(ngDevMode?[{debugName:"showBackground"}]:([])));previewWidth=E(null,...(ngDevMode?[{debugName:"previewWidth"}]:([])));checkIcons=E(false,...(ngDevMode?[{debugName:"checkIcons"}]:([])));customFunctions=M(()=>Og(this.state()),...(ngDevMode?[{debugName:"customFunctions"}]:([])));functions=M(()=>Uf(this.customFunctions()),...(ngDevMode?[{debugName:"functions"}]:([])));predefinedFunctions=wr;file=M(()=>sb(this.root(),{options:this.options(),functions:this.customFunctions()}),...(ngDevMode?[{debugName:"file"}]:([])));fitRequest=E(null,...(ngDevMode?[{debugName:"fitRequest"}]:([])));fitSeq=0;overflows=E([],...(ngDevMode?[{debugName:"overflows"}]:([])));dragType=E(null,...(ngDevMode?[{debugName:"dragType"}]:([])));outputKind=E("file",...(ngDevMode?[{debugName:"outputKind"}]:([])));status=E("",...(ngDevMode?[{debugName:"status"}]:([])));autoSave=E(false,...(ngDevMode?[{debugName:"autoSave"}]:([])));constructor(){kg(this.icons);this.forgetLegacy();this.autoSave.set(this.readAutoSave());const e=L(Fi);const t=e.take();if(t)this.takeBack(t);else if(this.autoSave())this.fresh=!this.restore();else{this.forgetText();this.fresh=true}const o=r=>{if(this.modified()&&(!this.autoSave()||this.notKept))r.preventDefault()};window.addEventListener("beforeunload",o);let i;L(lt).onDestroy(()=>{window.removeEventListener("beforeunload",o);clearTimeout(i);if(this.autoSave())this.saveText(this.file(),this.modified());e.leave({state:this.state(),shownTab:this.shownTab(),checkIcons:this.checkIcons(),outputKind:this.outputKind(),showGrid:this.showGrid(),showBackground:this.showBackground(),previewWidth:this.previewWidth(),project:this.project.state},this.modified()&&(!this.autoSave()||this.notKept))});Q(()=>{const r=this.autoSave();const s=this.file();const a=this.modified();this.project.link();ee(()=>{clearTimeout(i);if(r)i=setTimeout(()=>this.saveText(s,a,true),400);else this.forgetText()})})}takeBack(e){this.state.set(e.state);ee(()=>this.shownTab());this.shownTab.set(e.shownTab);this.checkIcons.set(e.checkIcons);this.outputKind.set(e.outputKind);this.showGrid.set(e.showGrid);this.showBackground.set(e.showBackground);this.previewWidth.set(e.previewWidth);this.project.adopt(e.project)}setAutoSave(e){if(e===this.autoSave())return;this.autoSave.set(e);try{if(e)localStorage.setItem(Pa,"1");else localStorage.removeItem(Pa)}catch{}this.notKept=false;if(!e)this.forgetText();this.say(I.text(e?"Auto save is on: the file is kept in this browser.":this.modified()?"Auto save is off: nothing of the file is kept. Save or download the file to keep the changes.":"Auto save is off: nothing of the file is kept."))}readAutoSave(){try{return localStorage.getItem(Pa)==="1"}catch{return false}}forgetLegacy(){try{for(const e of zb)localStorage.removeItem(e)}catch{}}restore(){try{const e=localStorage.getItem(ja);const t=e?_d(e):null;if(!t?.ok)return false;const o=co(t.tabs,null,t.settings??Dr(this.state()));this.state.set(localStorage.getItem(Kr)==="1"?o:Dg(o));this.project.recall();return true}catch{return false}}fresh=false;startWith(e){const t=Jd(e);if(!this.fresh||!t||this.modified()||lo(this.state().history))return;this.fresh=false;this.replaceDocument(co(t.root,null,Dr(this.state())));this.project.replaced({kind:"sample",name:I.text(t.label)});this.say(I.text("{name}: a sample to start from. Help > Getting started says how the editor works.",{name:I.text(t.label)}))}notKept=false;saveText(e,t,o=false){try{localStorage.setItem(ja,e);if(t)localStorage.removeItem(Kr);else localStorage.setItem(Kr,"1");this.project.remember();this.notKept=false}catch{this.project.forget();if(o&&!this.notKept)this.warn(I.text("Auto save could not keep the file in this browser (its storage is full or turned off). Save or download the file to keep the changes."),"ribbon-editor:autosave");this.notKept=true}}forgetText(){this.project.forget();try{localStorage.removeItem(ja);localStorage.removeItem(Kr)}catch{}}previewIcon=e=>/^[\w-]+:[\w-]+$/.test(e)&&!this.icons.has(e)?"rbe:unknown":e;tabs=M(()=>Ud(this.root(),{icon:this.previewIcon,functions:this.functions()}),...(ngDevMode?[{debugName:"tabs"}]:([])));liveTabs=M(()=>Lb(Ud(this.root(),{icon:this.previewIcon,functions:this.functions()})),...(ngDevMode?[{debugName:"liveTabs"}]:([])));activeTabId=M(()=>{const e=this.shownTab();return e===void 0?void 0:Gd(e)},...(ngDevMode?[{debugName:"activeTabId"}]:([])));shownTab=sf({...(ngDevMode?{debugName:"shownTab"}:({})),source:()=>{const e=this.selected();return e!==null&&typeof e[0]==="number"?e[0]:null},computation:(e,t)=>e??t?.value});rows=M(()=>jc(this.root(),this.options().defaultRows,this.options().uniformRows),...(ngDevMode?[{debugName:"rows"}]:([])));drawnColWidth=M(()=>Sg(this.options()),...(ngDevMode?[{debugName:"drawnColWidth"}]:([])));layoutRoot(){return lm(this.root(),this.rowsOf)}rowsOf=e=>typeof e[0]==="number"?this.rows()[e[0]]??this.options().defaultRows:this.options().defaultRows;controlOf(e){const t=O(this.root(),e.slice(0,5));return v(t)?J(t["type"]):void 0}trimmed(e,...t){if(e===null)return e;let o=e.root;const i=[];for(const r of t){if(i.some(s=>Fe(s,r)))continue;i.push(r);o=dm(o,r,this.rowsOf(r))}return o===e.root?e:{root:o,selected:e.selected}}inspector=M(()=>{const e=this.selected();return e===null?null:ba(this.root(),e,dt,typeof e[0]==="number"?this.rows()[e[0]]:void 0,{collapsible:this.options().collapsible})},...(ngDevMode?[{debugName:"inspector"}]:([])));otherProperties=M(()=>{const e=this.selected();return e===null?{}:mg(this.root(),e)},...(ngDevMode?[{debugName:"otherProperties"}]:([])));capabilities=M(()=>{const e=this.selected();if(e===null)return Qd;const t=this.root();const o=_(e);const i=no(e);if(i===null)return Qd;const r=e[e.length-1];const s=O(t,i)?.length??0;const a=O(t,e);const l=o==="item"&&v(a)?J(typeof a["type"]==="string"?a["type"]:void 0):void 0;return{remove:true,duplicate:true,moveUp:o!=="item"&&r>0,moveDown:o!=="item"&&r<s-1,addSection:true,addChoice:o==="choice"||o==="item"&&(l===void 0||l.choices!=="none")&&(!v(a)||a["choices"]===void 0||Array.isArray(a["choices"])),addSubChoice:o==="choice"&&eo(this.controlOf(e)).submenu&&v(a)&&(a["kind"]??"item")==="item",choiceEntries:o==="item"?Rc(l):o==="choice"?Rc(this.controlOf(e)):[]}},...(ngDevMode?[{debugName:"capabilities"}]:([])));problems=M(()=>{const e=this.notes();const t=[];const o="ribbon.json";e.forEach((l,d)=>{t.push({id:`json:note:${d}`,severity:"info",code:"json",message:I.text(l.template,l.params),file:o,path:o,line:l.line,column:l.column,nodePath:null})});const i=this.root();const r=this.options();const s=Lm(i,{defaultRows:r.defaultRows,uniformRows:r.uniformRows,shortcutKey:jb,knownIcon:this.checkIcons()?l=>this.icons.has(l):void 0,functions:this.functions()});if(r.colWidth!==null){for(const{path:l,needed:d,have:c}of this.overflows()){if(v(O(i,l)))s.push({code:"overflow",severity:"warning",template:"The content of this item needs {needed} columns, but it covers {have}. Widen the item or shorten its content.",params:{needed:d,have:c},path:l})}}const a=/* @__PURE__ */new Set;for(const l of Ag(r)){const d={code:"options",severity:l.severity,template:l.template,params:l.params,path:[]};a.add(d);s.push(d)}td(s).forEach((l,d)=>{t.push({id:`${l.code}:${q(l.path)}:${d}`,severity:l.severity,code:l.code,message:I.text(l.template,Fb(l.params)),file:a.has(l)?I.text("Ribbon Options"):Zt(i,l.path)||o,path:o,nodePath:bn(l.path).length>0?bn(l.path):null})});return t},...(ngDevMode?[{debugName:"problems"}]:([])));counts=M(()=>{const e=this.root();let t=0;let o=0;const i=Array.isArray(e)?e:[];for(const r of i){const s=v(r)&&Array.isArray(r["sections"])?r["sections"]:[];t+=s.length;for(const a of s)o+=v(a)&&Array.isArray(a["items"])?a["items"].length:0}return{tabs:i.length,sections:t,items:o}},...(ngDevMode?[{debugName:"counts"}]:([])));output=M(()=>{const e=this.root();switch(this.outputKind()){case"file":return this.file();case"json":return zd(e);case"typescript":return Pg(e);case"handler":{const t=_g(e);return t?`${Rd(e)}
47
+
48
+ ${t}`:Rd(e)}case"template":return Bg(this.options(),"onAction");case"usage":return qg(e)}},...(ngDevMode?[{debugName:"output"}]:([])));say(e){this.status.set(e)}warn(e,t){this.toast.warning(e,{id:t,closeAfter:5e3})}select(e){ee(()=>this.shownTab());this.state.update(t=>Eg(t,e))}selectTabById(e){const t=/^t(\d+)$/.exec(e);if(!t)return;const o=Number(t[1]);const i=this.selected();if(i!==null&&i[0]===o)return;this.select([o])}openProblem(e){if(e.nodePath)this.select(e.nodePath)}run(e,t){if(Ho(e.root,this.root())){this.select(e.selected);return false}this.state.update(o=>zg(o,e.root,e.selected,{mergeKey:t,now:Date.now()}));return true}shownTabIndex(){const e=this.shownTab()??0;const t=this.root();if(!Array.isArray(t)||t.length===0)return void 0;return e<t.length?e:0}placeForNewItem(){const e=this.root();const t=this.selected();if(t!==null&&t.length>=3)return{tab:t[0],section:t.slice(0,3)};const o=t!==null&&typeof t[0]==="number"?t[0]:this.shownTabIndex()??(Array.isArray(e)?e.length-1:-1);if(o<0)return{tab:o,section:null};const i=O(e,[o,"sections"]);return{tab:o,section:Array.isArray(i)&&i.length>0?[o,"sections",i.length-1]:null}}selectedTab(){const e=this.selected();return e!==null&&typeof e[0]==="number"?e[0]:void 0}addTab(){const e=this.selectedTab();if(this.run(Sr(this.root(),dt,e===void 0?void 0:e+1)))this.say(I.text("Tab added."))}addTabAtEnd(){if(this.run(Sr(this.root(),dt)))this.say(I.text("Tab added."))}addSection(){const e=this.root();const t=this.selectedTab()??this.shownTabIndex()??(Array.isArray(e)?e.length-1:-1);if(t<0){if(this.run(Sr(e,dt)))this.say(I.text("Tab added, with a section."));return}const o=this.selected();const i=o!==null&&o.length>=3?o[2]+1:void 0;const r=qc(e,t,dt,i);if(this.run(r))this.say(I.text("Section added."))}addItem(e,t){let o=this.layoutRoot();const i=t?.sectionPath===void 0?this.placeForNewItem():null;let r=t?.sectionPath??i?.section??null;if(r===null){const c=i!==null&&i.tab>=0?i.tab:Array.isArray(o)&&o.length>0?o.length-1:-1;if(c<0){o=Sr(o,dt).root;r=[0,"sections",0]}else{const p=qc(o,c,dt);o=p.root;r=p.selected??[c,"sections",0]}}if(t?.cell&&t.sectionPath){const c=this.rows()[t.sectionPath[0]]??tt;if(!this.isCellFree(t.sectionPath,{...t.cell,...this.spanOfControl(e,c)},null))return this.cellTaken()}const s=this.selected();const a=s!==null&&t?.sectionPath===void 0&&_(s)==="item"?s[s.length-1]+1:void 0;const l=um(o,r,e,dt,t?.index??a,this.rowsOf(r),t?.cell);const d=`fit:${this.fitSeq+1}`;if(!this.run(l,d))return;this.say(I.text("Item added: {control}.",{control:I.text(J(e)?.label??(e===ei?"Control of the application":e))}));if(l.selected!==null)this.requestFit([l.selected],d,false)}addChoice(e,t){const o=this.selected();if(o===null)return;const i=_(o);let r;if(i==="choice"&&e==="inside"&&!this.capabilities().addSubChoice)return;if(i==="choice"&&e!=="inside")r=tm(this.root(),o,dt,e??"after",t);else r=Qf(this.root(),i==="choice"||i==="item"?o:bn(o),dt,void 0,t);const s=`fit:${this.fitSeq+1}`;if(!this.run(r,s))return;this.say(t===void 0||t.kind==="item"?I.text("Choice added."):I.text("Menu entry added: {entry}.",{entry:I.text(t.label)}));if(r.selected!==null)this.requestFit([r.selected.slice(0,5)],s,"widened")}removeSelected(){const e=this.selected();if(e===null)return;const t=fm(_(e)==="item"?this.layoutRoot():this.root(),e,this.rowsOf(e));if(this.run(_(e)==="item"?this.trimmed(t,e.slice(0,3)):t))this.say(I.text("Removed."))}duplicateSelected(){const e=this.selected();if(e===null)return;const t=_(e)==="item";const o=t?this.layoutRoot():this.root();const i=im(o,e,this.rowsOf(e));if(t&&i.root===o)return this.warn(I.text("There is no free place in the section for a copy of the item."),"ribbon-editor:no-room");const r=_(e)==="choice";const s=r?`fit:${this.fitSeq+1}`:void 0;if(!this.run(i,s))return;this.say(I.text("Duplicated."));if(s!==void 0)this.requestFit([e.slice(0,5)],s,"widened")}moveSelected(e){const t=this.selected();if(t===null||_(t)==="item")return;this.run(wm(this.root(),t,e))}moveTabTo(e,t){this.run(bm(this.root(),e,t))}moveSectionTo(e,t,o){if(this.run(ym(this.root(),e,t,o))&&e[0]!==t)this.say(I.text("The section was moved to another tab."))}changeRow(e,t){const o=this.selected();if(o===null)return;const i=typeof t==="string"?t.trim():"";if(e==="f:typeName"&&J(i)){this.warn(I.text("\"{name}\" is a control of the library, and an item keeps the control it was added as. Add an item of it from the Toolbox.",{name:i}),"ribbon-editor:type-name");return}const r=`row:${e}:${q(o)}`;const s=this.itemWhoseContentChanged(o,e);const a=this.root();const l=wa(a,o,e,t,dt);const d=_(o)==="item"?gm(l.root,a,o,this.rowsOf(o)):l.root;if(!this.run({root:d,selected:l.selected},r))return;if(d!==l.root)this.say(I.text("The item covers more cells now, so it was moved to a free place of its section."));if(s!==null&&!Ho(O(this.root(),s),O(a,s)))this.requestFit([s],r,"widened")}canReset(e){const t=this.selected();return t!==null&&!Ho(wa(this.root(),t,e,void 0,dt).root,this.root())}bindRow(e){const t=this.selected();if(t===null)return;this.run(ug(this.root(),t,e,dt),`bind:${e}:${q(t)}`)}itemWhoseContentChanged(e,t){const o=_(e);if(o!=="item"&&o!=="choice")return null;const i=["f:label","f:icon"];if(o==="item"?!(t.startsWith("i:")||i.includes(t)||t==="f:type"||t==="f:typeName"):!i.includes(t))return null;return e.slice(0,5)}setDefaultRows(e){this.setOption("defaultRows",Math.max(1,Math.floor(e)))}setOtherProperties(e){const t=this.selected();if(t===null)return null;const o=Xn(e.trim()===""?"{}":e,{lenient:true});if(!o.ok)return I.text(o.error.template,o.error.params);const i=gg(this.root(),t,o.value);if(!i.ok)return I.text(i.template,i.params);this.run({root:i.root,selected:t},`other:${q(t)}`);return null}spanAllColumns(e,t){const o=mm(this.layoutRoot(),e,t,this.rowsOf(e));if(o===null)return this.warn(I.text("Another item stands in the rows of this item, so it cannot cover all columns."),"ribbon-editor:cell-taken");this.run(o)}isCellFree(e,t,o){const i=this.rows()[e[0]]??tt;const r=$e(O(this.root(),e),i);return!r.some((s,a)=>s!==null&&a!==o&&s.col<t.col+t.colSpan&&t.col<s.col+s.colSpan&&s.row<t.row+t.rowSpan&&t.row<s.row+s.rowSpan)}spanOfControl(e,t){const o=e?J(e):void 0;if(!o)return{colSpan:1,rowSpan:1};const i=o.create("preview",a=>a);const r=Me(i);const s=Rt(i);return{colSpan:r==="all"?1:r,rowSpan:s==="all"?t:s,...(s==="all"?{row:1}:{})}}cellTaken(){this.warn(I.text("That place is taken by another item."),"ribbon-editor:cell-taken")}placedSection(e){return $e(O(this.root(),e),this.rows()[e[0]]??tt)}plannedColumn(e,t,o){return sm(this.root(),e,t,o,typeof t[0]==="number"?this.rows()[t[0]]??tt:tt)}rowInNewColumn(e,t,o,i,r){if(t.length!==3||typeof t[0]!=="number")return null;const s=Fe(e.slice(0,3),t)&&typeof e[4]==="number"?e[4]:null;return Vf(O(this.root(),t),this.rows()[t[0]]??tt,o,i,r,s)}moveItemToNewColumn(e,t,o,i){if(t.length!==3||typeof t[0]!=="number")return;const r=this.rows()[t[0]]??tt;const s=this.placedCell(e)?.rowSpan??1;if(this.rowInNewColumn(e,t,o,s,i)!==i){this.cellTaken();return}const a=e.slice(0,3);const l=this.layoutRoot();const d=this.trimmed(am(l,e,t,o,i,r),a,t);if(d.root!==l)this.run(d)}placedCell(e){if(e.length!==5||typeof e[0]!=="number"||typeof e[4]!=="number")return null;const t=this.rows()[e[0]]??this.options().defaultRows;return $e(O(this.root(),e.slice(0,3)),t)[e[4]]??null}moveItemToCell(e,t,o){const i=this.layoutRoot();if(!v(O(i,e))||t.length!==3||typeof t[0]!=="number")return;const r=this.placedCell(e);if(!r)return;const s=Fe(e.slice(0,3),t)?e[4]:null;if(!this.isCellFree(t,{col:o.col,row:o.row,colSpan:r.colSpan,rowSpan:r.rowSpan},s))return this.cellTaken();const a=this.trimmed(hm(i,e,t,o,this.rowsOf),e.slice(0,3),t);if(a.root!==i)this.run(a)}resizeItem(e,t){const o=this.rowsOf(e);const i=this.trimmed(pa(this.layoutRoot(),e,t,o),e.slice(0,3));if(i!==null){this.run(i);return}const r=this.placedCell(e);if(r&&(t.row??r.row)+(t.rowSpan??r.rowSpan)-1>o)this.warn(I.text("The tab has {rows} rows: the item cannot reach further down.",{rows:o}),"ribbon-editor:cell-taken");else this.cellTaken()}canResize(e,t){return pa(this.root(),e,t,this.rowsOf(e))!==null}requestFit(e,t,o){this.fitRequest.set({seq:++this.fitSeq,items:e,key:t,announce:o})}fitItems(e,t={}){const o=this.layoutRoot();let i=o;let r=0;for(const{section:s,items:a}of e){const l=this.rowsOf(s);const d=$e(O(i,s),l);i=pm(i,s,l,a);const c=$e(O(i,s),l);d.forEach((p,h)=>{const u=c[h];if(p&&u&&u.colSpan>p.colSpan)r++})}if(i!==o)this.run({root:i,selected:this.selected()},t.key);if(t.announce==="widened"&&r>0)this.say(r===1?I.text("An item was widened to fit its content."):I.text("{count} items were widened to fit their content.",{count:r}));return r}nudgeItem(e,t,o){const i=this.placedCell(e);if(!i)return;const r=this.rows()[e[0]]??tt;const s=Math.max(1,Math.min(i.row+o,r-i.rowSpan+1));const a=Math.max(1,i.col+t);if(a===i.col&&s===i.row)return;this.moveItemToCell(e,e.slice(0,3),{col:a,row:s})}setOption(e,t){this.state.update(o=>Lg(o,{...Cd(o),[e]:t},{mergeKey:`option:${e}`,now:Date.now()}))}reportAction(e){if(e.item.type==="radio")Rb(this.liveTabs(),e.item);const t=e.item.action;if(t===void 0||t==="")return;this.say(e.value===void 0?I.text("Action: {action}",{action:t}):I.text("Action: {action}, value: {value}",{action:t,value:String(e.value)}))}setCustomFunctions(e){this.state.update(o=>Rg(o,sa(e).join(", "),{mergeKey:"functions",now:Date.now()}));const t=qf(e);if(t.length)this.say(I.text("{names}: the translations of the library need no entry, the expressions call them as they are.",{names:t.join(", ")}))}undo(){this.state.update(Fg)}redo(){this.state.update(jg)}async mayReplace(){if(!this.modified())return true;return this.box.confirm(I.text("Replace the ribbon you are editing? The changes that were not saved are lost, and so are the steps of undo."),{confirmLabel:I.text("Replace"),cancelLabel:I.text("Keep"),danger:true})}replaceDocument(e){this.state.set(e);this.shownTab.set(void 0);this.documentSeq.update(t=>t+1)}async newRibbon(){if(!(await this.mayReplace()))return;this.replaceDocument(co([],null,$d));this.project.replaced(uo);this.say(I.text("A new empty ribbon."))}async loadSample(e){const t=Jd(e);if(!t||!(await this.mayReplace()))return;this.replaceDocument(co(t.root,null,Dr(this.state())));this.project.replaced({kind:"sample",name:I.text(t.label)});this.say(I.text("Loaded: {name}.",{name:I.text(t.label)}))}async loadFromText(e,t,o={kind:"file",name:t}){const i=_d(e);if(!i.ok){const{error:r}=i;this.warn(`${I.text("{name} could not be read as a list of tabs: line {line}.",{name:t,line:r.line})} ${I.text(r.template,r.params)}`,"ribbon-editor:load");return false}if(!(await this.mayReplace()))return false;this.replaceDocument(co(i.tabs,null,i.settings??Dr(this.state()),i.notes));this.project.replaced(o);this.say(I.text("Loaded: {name}.",{name:t}));return true}openFile(){void Da(".json,.ts,.txt,application/json,text/plain").then(e=>e?this.loadFromText(e.text,e.name):false)}async openFromProject(){const e=await this.project.open();if(e!==null&&(await this.loadFromText(e.text,e.path)))this.project.linkTo(e)}async saveToProject(){const e=this.state().history.present;if(await this.project.save(this.file(),_r))this.state.update(t=>fo(t,e))}async saveToProjectAs(){const e=this.state().history.present;if(await this.project.saveAs(this.file(),_r))this.state.update(t=>fo(t,e))}async pasteRibbon(){const e=await Ea();if(e===null)this.warn(I.text("The clipboard cannot be read here. Save the text as a file and open it instead."),"ribbon-editor:clipboard");else await this.loadFromText(e,I.text("the clipboard"),{kind:"clipboard"})}async copyOutput(){if(await Lr(this.output()))this.toast.success(I.text("Copied."),{id:"ribbon-editor:copied",closeAfter:1500});else this.warn(I.text("The clipboard cannot be written here. Select the text of the output and copy it."),"ribbon-editor:clipboard")}downloadFile(){this.saveFile(this.file(),_r,"application/json");this.downloaded()}downloaded(){if(this.project.linked()===null)this.state.update(Ig)}downloadOutput(){const e={file:[_r,"application/json"],json:["ribbon-tabs.json","application/json"],typescript:["ribbon.ts","text/plain"],handler:["ribbon-actions.ts","text/plain"],template:["ribbon.html","text/html"],usage:["ribbon-loader.ts","text/plain"]};const[t,o]=e[this.outputKind()];this.saveFile(this.output(),t,o);if(this.outputKind()==="file")this.downloaded()}saveFile(e,t,o){li(e,t,o)}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Ze,deps:[],target:w.ɵɵFactoryTarget.Injectable});static ɵprov=w.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Ze})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Ze,decorators:[{type:Pn}],ctorParameters:()=>[]});function jb(n){const e=lf(n,"other");if(!e)return sd(n);return[e.ctrl?"ctrl":"",e.meta?"meta":"",e.alt?"alt":"",e.shift?"shift":"",e.key].filter(Boolean).join("+")}const ze=n=>I.text(n);function Pb(n){return[{label:ze("Add &tab"),icon:"rbe:add-tab",run:()=>n.addTabAtEnd()}]}const ep={item:"&Choice",separator:"&Separator",header:"&Heading",source:"&Block"};const tp=n=>n.kind==="item"?"rbe:add-choice":`rbe:choice-${n.kind}`;function np(n,e){const t=n.filter(i=>i.kind!=="source").map(i=>({label:ze(ep[i.kind]),icon:tp(i),run:()=>e(i)}));const o=n.filter(i=>i.kind==="source");if(o.length>0){const i=o.filter(a=>a.source!==void 0&&a.source.startsWith("gfy:"));const r=o.filter(a=>!i.includes(a));const s=a=>({label:ze(a.label),icon:tp(a),run:()=>e(a)});t.push({label:ze(ep.source),icon:"rbe:choice-source",children:[...i.map(s),...(i.length>0&&r.length>0?[{separator:true}]:[]),...r.map(s)]})}return t}function op(n,e){const t=n.capabilities();const o=(i,r,s=true)=>t.choiceEntries.length>1?{label:ze(i),icon:"rbe:add-choice",enabled:s,children:np(t.choiceEntries,a=>n.addChoice(r,a))}:{label:ze(i),icon:"rbe:add-choice",enabled:s,run:()=>n.addChoice(r)};if(e==="choice"){const i=[o("Add choice &before","before"),o("Add choice &after","after")];if(t.addSubChoice)i.push(o("Add sub-c&hoice","inside"));return i}return[o("Add &choice",void 0,t.addChoice)]}function ip(n,e){n.select(e);const t=_(e);const o=n.capabilities();const i=a=>a?{sectionPath:a}:void 0;const r=a=>[...Xo.map(l=>({label:ze(l.label),icon:ti(l.type),run:()=>n.addItem(l.type,i(a))})),{separator:true},{label:ze("Control of the application"),icon:"rbe:item",run:()=>n.addItem(ei,i(a))}];const s=[];if(t==="tab"){s.push({label:ze("Add &section"),icon:"rbe:add-section",run:()=>n.addSection()});s.push({label:ze("Add &tab"),icon:"rbe:add-tab",run:()=>n.addTab()})}else if(t==="section"){s.push({label:ze("Add &item"),icon:"rbe:add-item",children:r(e)});s.push({label:ze("Add s&ection"),icon:"rbe:add-section",run:()=>n.addSection()})}else{if(t==="item"){s.push({label:ze("Add &item"),icon:"rbe:add-item",children:r()});const a=O(n.root(),e);const l=v(a)&&a["colSpan"]==="all";s.push({label:l?ze("Co&ver one column"):ze("Co&ver all columns"),icon:"rbe:item",run:()=>n.spanAllColumns(e,!l)})}s.push(...op(n,t))}s.push({separator:true});s.push({label:ze("Dup&licate"),icon:"rbe:duplicate",shortcut:"Mod+D",enabled:o.duplicate,run:()=>n.duplicateSelected()});if(t!=="item"){s.push({label:ze("Move &up"),icon:"rbe:up",shortcut:"Alt+Up",enabled:o.moveUp,run:()=>n.moveSelected(-1)});s.push({label:ze("Move &down"),icon:"rbe:down",shortcut:"Alt+Down",enabled:o.moveDown,run:()=>n.moveSelected(1)})}s.push({separator:true});s.push({label:ze("&Remove"),icon:"rbe:remove",shortcut:"Del",enabled:o.remove,run:()=>n.removeSelected()});return s}function rp(n){const e=n.replace(/\[[^\]]*\]/g," ").trim();if(e===""||e==="none")return[];const t=[];for(const o of e.split(/\s+/)){const i=parseFloat(o);if(Number.isFinite(i)&&i>=0)t.push(i)}return t}function sp(n,e,t,o){const i=[];let r=t;for(const s of n){i.push({start:r,size:s});r+=s+e}return o===void 0?{list:i,gap:e}:{list:i,gap:e,fresh:o}}function Gr(n,e){const{list:t,gap:o}=n;if(t.length===0)return{start:0,size:0};const i=Math.max(1,Math.floor(e));if(i<=t.length)return t[i-1];const r=t[t.length-1];const s=n.fresh??r.size;return{start:r.start+r.size+o+(i-t.length-1)*(s+o),size:s}}function mo(n,e,t=false){const{list:o}=n;if(o.length===0)return 1;if(e<o[0].start)return 1;for(let i=0;i<o.length;i++){const r=o[i].start+o[i].size;if(e<=r)return i+1;const s=o[i+1];if(s&&e<s.start)return e-r<=s.start-e?i+1:i+2}return t?o.length+1:o.length}function Wb(n,e){const{list:t,gap:o}=n;if(t.length===0)return 1;const i=t[t.length-1];const r=i.start+i.size;if(e<=r)return mo(n,e);const s=(n.fresh??i.size)+o;if(s<=0)return t.length+1;return t.length+Math.max(1,Math.floor((e-r-o)/s)+1)}function go(n,e,t){const o=Gr(n,t.col);const i=Gr(n,t.col+Math.max(1,t.colSpan??1)-1);const r=Gr(e,t.row);const s=Gr(e,t.row+Math.max(1,t.rowSpan??1)-1);return{x:o.start,y:r.start,width:i.start+i.size-o.start,height:s.start+s.size-r.start}}const Kb=2;function ap(n,e,t){const o=n.list.length;if(o===0)return null;const i=Math.max(1,Math.min(Math.floor(e),o+1));if(i===1){const r=n.list[0].start;return t&&t.x<r?(t.x+r)/2:r-n.gap/2}if(i===o+1){const r=n.list[o-1];const s=r.start+r.size;const a=t?t.x+t.width:s;return a>s?(s+a)/2:s+n.gap/2}return(n.list[i-2].start+n.list[i-2].size+n.list[i-1].start)/2}function lp(n,e,t,o,i=null,r=Kb){const s=ap(n,t,o);if(s===null)return null;const a=e.list.length;let l=0;let d=0;if(a>0){const p=Math.max(1,Math.min(Math.floor(i?.row??1),a));const h=i?Math.max(p,Math.min(p+Math.max(1,Math.floor(i.rowSpan))-1,a)):a;l=e.list[p-1].start;d=e.list[h-1].start+e.list[h-1].size}let c=s-r/2;if(o)c=Math.max(o.x+1,Math.min(c,o.x+o.width-r-1));return{x:c,y:l,width:r,height:d-l}}function cp(n,e){if(n===null||e===null)return n===e;return Math.abs(n.x-e.x)<1&&Math.abs(n.y-e.y)<1&&Math.abs(n.width-e.width)<1&&Math.abs(n.height-e.height)<1}function Br(n){const e=/^t(\d+)\/s(\d+)$/.exec(n??"");return e?{tab:Number(e[1]),section:Number(e[2])}:null}function Ka(n,e,t){if(!(e>0)||!(n>0))return 1;return Math.max(1,Math.ceil((n+t)/(e+t)-0.02))}const nk=`
49
+ :host {
50
+ display: block;
51
+ height: 100vh;
52
+ color: var(--gfy-text-main);
53
+ font: 13px/1.3 var(--gfy-font-main, system-ui, sans-serif);
54
+ }
55
+ :host(.hosted) {
56
+ height: 100%;
57
+ }
58
+ .shell {
59
+ height: 100%;
60
+ display: flex;
61
+ flex-direction: column;
62
+ background: var(--gfy-bg-main);
63
+ }
64
+ .workspace {
65
+ flex: 1;
66
+ min-height: 0;
67
+ position: relative;
68
+ }
69
+ `;const ok=`
70
+ .ic {
71
+ flex: none;
72
+ display: grid;
73
+ width: var(--ic, 14px);
74
+ height: var(--ic, 14px);
75
+ }
76
+ `;const ik=`
77
+ :host {
78
+ display: flex;
79
+ flex-direction: column;
80
+ height: 100%;
81
+ min-height: 0;
82
+ background: var(--gfy-bg-panel, var(--gfy-bg-main));
83
+ color: var(--gfy-text-main);
84
+ font: 13px/1.3 var(--gfy-font-main, system-ui, sans-serif);
85
+ }
86
+ .tb {
87
+ flex: none;
88
+ display: flex;
89
+ flex-wrap: wrap;
90
+ align-items: center;
91
+ gap: 2px 4px;
92
+ padding: 3px 6px;
93
+ border-bottom: 1px solid var(--gfy-border-color, rgba(128, 128, 128, 0.3));
94
+ /* The buttons of the bar are compact: the size of a Gridify control comes from the density tokens, a container may make them smaller. */
95
+ --gfy-control-height: 24px;
96
+ --gfy-control-padding-x: 7px;
97
+ }
98
+ .tb .sp {
99
+ flex: 1;
100
+ }
101
+ .tb .sep {
102
+ width: 1px;
103
+ height: 16px;
104
+ margin: 0 4px;
105
+ background: var(--gfy-border-color, rgba(128, 128, 128, 0.4));
106
+ }
107
+ .fill {
108
+ flex: 1 1 auto;
109
+ min-height: 0;
110
+ }
111
+ .empty {
112
+ padding: 10px 12px;
113
+ opacity: 0.88;
114
+ }
115
+ .hint {
116
+ padding: 6px 10px;
117
+ font-size: 12px;
118
+ opacity: 0.88;
119
+ }
120
+ `;const wt=n=>parseFloat(n)||0;const Vr=n=>Array.from(n.children).filter(e=>e.tagName==="GFY-RIBBON-ITEM");function di(n){const e=Array.from(n.querySelectorAll(".ribbon-tabs > .ribbon-tab"));return Math.max(0,e.findIndex(t=>t.classList.contains("active")))}function _b(n,e){return n.querySelectorAll(".ribbon-tabs > .ribbon-tab")[e]??null}function bo(n,e,t){return n.querySelector(`.ribbon-section[data-key="t${e}/s${t}"]`)}function Qt(n){return n.querySelector(".section-grid")}function dp(n,e,t,o){const i=bo(n,e,t);const r=i?Qt(i):null;return r?Vr(r)[o]??null:null}function _a(n,e){if(!(n instanceof Element)||!e.contains(n))return null;if(n.closest("gfy-ribbon-search"))return null;const t=n.closest(".ribbon-tab");if(t&&t.parentElement){const r=Array.from(t.parentElement.children).filter(s=>s.classList.contains("ribbon-tab")).indexOf(t);return r>=0?{kind:"tab",tab:r}:null}const o=n.closest(".ribbon-section");const i=Br(o?.getAttribute("data-key"));if(o&&i){let r=n.closest("gfy-ribbon-item");while(r&&o.contains(r)){const s=r.parentElement;if(s&&s.classList.contains("section-grid")){const a=Vr(s).indexOf(r);if(a>=0)return{kind:"item",tab:i.tab,section:i.section,item:a}}r=s?s.closest("gfy-ribbon-item"):null}return{kind:"section",tab:i.tab,section:i.section}}if(n.closest(".ribbon-body"))return{kind:"body",tab:di(e)};return null}function pp(n,e){return n instanceof Element&&e.contains(n)&&n.matches(".ribbon-bar, .ribbon-tabs, .ribbon-tabs-end")}function hp(n,e){const t=n.getBoundingClientRect();if(t.width<=0||t.height<=0)return null;return{x:t.left-e.left,y:t.top-e.top,width:t.width,height:t.height}}function Hr(n,e){const t=getComputedStyle(n);const o=rp(t.gridTemplateColumns);const i=rp(t.gridTemplateRows);if(o.length===0||i.length===0)return null;const r=n.querySelector(".ghost-cell[data-pos=\"1:1\"]");let s;let a;if(r){const p=r.getBoundingClientRect();s=p.left-e.left;a=p.top-e.top}else{const p=n.getBoundingClientRect();const h=p.width-wt(t.borderLeftWidth)-wt(t.borderRightWidth)-wt(t.paddingLeft)-wt(t.paddingRight);const u=o.reduce((f,m)=>f+m,0)+wt(t.columnGap)*(o.length-1);s=p.left-e.left+wt(t.borderLeftWidth)+wt(t.paddingLeft)+(h-u)/2;a=p.top-e.top+wt(t.borderTopWidth)+wt(t.paddingTop)}const l=parseFloat(t.getPropertyValue("--_r-col-min"));const d=parseFloat(t.getPropertyValue("--_r-col-track"));const c=d>0?d:l;return{cols:sp(o,wt(t.columnGap),s,c>0?c:void 0),rows:sp(i,wt(t.rowGap),a)}}function up(n,e){if(n.getBoundingClientRect().width<=0)return 0;const{width:t,justifySelf:o}=n.style;n.style.width=e;n.style.justifySelf="start";const i=n.getBoundingClientRect().width;n.style.width=t;n.style.justifySelf=o;return i}const fp=n=>up(n,"max-content");const Gb=n=>up(n,"min-content");function Ga(n){return wt(getComputedStyle(n).columnGap)}const mp=n=>{switch(n.kind){case"tab":case"body":return[n.tab];case"section":return[n.tab,"sections",n.section];case"item":return[n.tab,"sections",n.section,"items",n.item]}};class ji{store=L(Ze);texts=I;popup=L(Wo);destroyRef=L(lt);frameRef=ct.required("frame");ribbonRef=ct.required("ribbon",{read:jo});selection=E(null,...(ngDevMode?[{debugName:"selection"}]:([])));hint=E(null,...(ngDevMode?[{debugName:"hint"}]:([])));spanCells=E([],...(ngDevMode?[{debugName:"spanCells"}]:([])));itemAreas=E([],...(ngDevMode?[{debugName:"itemAreas"}]:([])));busy=E(false,...(ngDevMode?[{debugName:"busy"}]:([])));handlesOf(e){const t=["nw","ne","sw","se"];if(e.width>=40)t.push("n","s");if(e.height>=40)t.push("e","w");return t}widthOptions=M(()=>[{value:"fit",label:I.text("Fit")},{value:"1000",label:"1000"},{value:"700",label:"700"},{value:"480",label:"480"},{value:"320",label:"320"}],...(ngDevMode?[{debugName:"widthOptions"}]:([])));widthKey=M(()=>{const e=this.store.previewWidth();return e===null?"fit":String(e)},...(ngDevMode?[{debugName:"widthKey"}]:([])));gesture=null;frameRequest=0;mutations=null;handledFit=ee(()=>this.store.fitRequest()?.seq??0);overflowSeq=0;constructor(){Q(()=>{this.store.selected();this.store.tabs();this.store.showGrid();this.store.showBackground();this.store.options();this.store.previewWidth();this.schedule()});Q(()=>{const e=this.store.fitRequest();if(e===null||e.seq<=this.handledFit)return;this.handledFit=e.seq;ee(()=>void this.fitWhenDrawn(e,this.store.tabs()))});Q(()=>{this.store.tabs();this.store.options();this.store.previewWidth();this.store.selected()?.[0];ee(()=>void this.checkOverflow())});this.destroyRef.onDestroy(()=>{this.destroyed=true;this.store.overflows.set([])});ur(()=>this.attach());this.destroyRef.onDestroy(()=>{cancelAnimationFrame(this.frameRequest);this.endGesture()})}frame(){return this.frameRef().nativeElement}destroyed=false;async inPage(e=()=>true){while(!this.frame().isConnected){if(this.destroyed||!e())return false;await new Promise(t=>setTimeout(t,200))}return!this.destroyed&&e()}attach(){const e=this.frame();const t=this.ribbonRef().nativeElement;const o=(s,a)=>{e.addEventListener(s,a,true);this.destroyRef.onDestroy(()=>e.removeEventListener(s,a,true))};o("pointerdown",s=>this.onPointerDown(s));for(const s of["mousedown","mouseup","click","dblclick","auxclick"])o(s,a=>this.onGuard(a));o("contextmenu",s=>this.onContextMenu(s));const i=new MutationObserver(()=>this.schedule());this.mutations=i;i.observe(t,{childList:true,subtree:true,attributes:true,attributeFilter:["class","data-state","style"]});const r=new ResizeObserver(()=>this.schedule());r.observe(e);r.observe(t);this.destroyRef.onDestroy(()=>{i.disconnect();r.disconnect()});this.schedule()}setWidth(e){this.store.previewWidth.set(e===null||e==="fit"?null:Number(e))}onTabChange(e){if(e!==void 0)this.store.selectTabById(e)}schedule(){if(this.frameRequest!==0)return;this.frameRequest=requestAnimationFrame(()=>{this.frameRequest=0;this.measure()})}measure(){const e=this.frame();const t=this.store.selected();let o=null;const i=t===null?void 0:t[0];if(t!==null&&typeof i==="number"){let r=null;let s="tab";if(t.length===1){r=_b(e,i)}else if(i===di(e)){const d=t[2];if(t.length<5){r=bo(e,i,d);s="section"}else{r=dp(e,i,d,t[4]);s=t.length===5?"item":"choice"}}const a=e.getBoundingClientRect();let l=r?hp(r,a):null;if(l&&(s==="item"||s==="choice"))l=this.cellsBox(e,t.slice(0,5),a)??l;if(l)o={box:l,kind:s}}this.selection.update(r=>r!==null&&o!==null&&r.kind===o.kind&&cp(r.box,o.box)?r:o);this.measureSpans(e)}cellsBox(e,t,o){const i=this.store.placedCell(t);const r=bo(e,t[0],t[2]);const s=r?Qt(r):null;const a=s?Hr(s,o):null;return i&&a?go(a.cols,a.rows,i):null}frames(e){return new Promise(t=>{const o=i=>{if(i<=0)t();else requestAnimationFrame(()=>o(i-1))};o(e)})}async fitWhenDrawn(e,t){if(!this.frame().isConnected){if(!(await this.inPage(()=>this.store.tabs()===t)))return}const o=this.store.drawnColWidth();for(let i=0;i<6;i++){await this.frames(2);const r=e.items[0]?.[0];if(typeof r!=="number"||r===di(this.frame()))break}this.store.fitItems(this.measureNeeds(this.frame(),o,e.items),{key:e.key,announce:e.announce})}async checkOverflow(){const e=++this.overflowSeq;if(!(await this.inPage(()=>e===this.overflowSeq)))return;await this.frames(3);if(e!==this.overflowSeq||!this.frame().isConnected)return;const t=this.store.drawnColWidth();const o=[];const i=this.frame();const r=di(i);for(const a of Array.from(i.querySelectorAll(".ribbon-section"))){const l=Br(a.getAttribute("data-key"));const d=l&&l.tab===r?Qt(a):null;if(!l||!d)continue;const c=Ga(d);const p=this.store.placedSection([r,"sections",l.section]);Vr(d).forEach((h,u)=>{const f=fp(h);const m=p[u]?.colSpan;const g=f>0?Ka(f,t,c):0;if(m!==void 0&&g>m)o.push({path:[r,"sections",l.section,"items",u],needed:g,have:m})})}this.mutations?.takeRecords();const s=a=>a.length===o.length&&a.every((l,d)=>l.needed===o[d].needed&&l.have===o[d].have&&Fe(l.path,o[d].path));if(!s(this.store.overflows()))this.store.overflows.set(o)}measureNeeds(e,t,o){const i=[];for(const r of Array.from(e.querySelectorAll(".ribbon-section"))){const s=Br(r.getAttribute("data-key"));const a=s?Qt(r):null;if(!s||!a)continue;const l=[s.tab,"sections",s.section];if(!o.some(p=>Fe(p.slice(0,3),l)))continue;const d=Ga(a);const c=/* @__PURE__ */new Map;Vr(a).forEach((p,h)=>{if(!o.some(f=>Fe(f,[...l,"items",h])))return;const u=fp(p);if(u>0)c.set(h,Ka(u,t,d))});if(c.size>0)i.push({section:l,items:c})}this.mutations?.takeRecords();return i}measureSpans(e){const t=[];const o=[];const i=this.store.showGrid();const r=this.store.showBackground();if(i||r){const a=e.getBoundingClientRect();const l=di(e);for(const d of Array.from(e.querySelectorAll(".ribbon-section"))){const c=Br(d.getAttribute("data-key"));const p=c&&c.tab===l?Qt(d):null;const h=c&&p?Hr(p,a):null;if(!c||!h)continue;for(const u of this.store.placedSection([l,"sections",c.section])){if(u===null)continue;if(r)o.push(go(h.cols,h.rows,u));if(!i||u.colSpan===1&&u.rowSpan===1||u.colSpan*u.rowSpan>200)continue;for(let f=u.col;f<u.col+u.colSpan;f++){for(let m=u.row;m<u.row+u.rowSpan;m++)t.push(go(h.cols,h.rows,{col:f,row:m,colSpan:1,rowSpan:1}))}}}}const s=(a,l)=>a.length===l.length&&a.every((d,c)=>cp(d,l[c]));this.spanCells.update(a=>s(a,t)?a:t);this.itemAreas.update(a=>s(a,o)?a:o)}hitAt(e){const t=_a(e.target,this.frame());if(t===null||t.kind!=="section")return t;const o=this.dropTargetFor(e.target,e.clientX,e.clientY);const i=this.frame().getBoundingClientRect();const r=(l,d)=>{const c=l.list[l.list.length-1];return c!==void 0&&d>=l.list[0].start&&d<=c.start+c.size};const s=o?.grid?r(o.grid.cols,e.clientX-i.left)&&r(o.grid.rows,e.clientY-i.top):false;const a=s&&o?.cell?this.itemAt(o.sectionPath,o.cell).at:-1;return a>=0?{kind:"item",tab:t.tab,section:t.section,item:a}:t}onPointerDown(e){const t=this.frame();const o=this.hitAt(e);if(o===null&&pp(e.target,t)){if(e.button===0)this.store.select(null);return}if(o===null||o.kind==="tab")return;e.preventDefault();t.focus({preventScroll:true});if(e.button!==0)return;if(o.kind==="body"){this.store.select(null);return}const i=mp(o);if(o.kind==="section"&&this.onTitle(e.target)){const l=this.store.selected();if(l!==null&&Fe(l,i))this.store.select(null);else this.store.select(i);return}this.store.select(i);if(o.kind!=="item")return;const r=this.store.placedCell(i);if(!r)return;const s=this.dropTargetFor(e.target,e.clientX,e.clientY);const a=s?.cell?{col:Math.max(0,Math.min(s.cell.col-r.col,r.colSpan-1)),row:Math.max(0,Math.min(s.cell.row-r.row,r.rowSpan-1))}:{col:0,row:0};this.begin({kind:"move",path:i,placed:r,startX:e.clientX,startY:e.clientY,grab:a,moved:false,target:null},e)}onStagePress(e){const t=e.currentTarget;if(e.target!==t||e.button!==0)return;const o=t.getBoundingClientRect();if(e.clientX-o.left>=t.clientWidth||e.clientY-o.top>=t.clientHeight)return;this.store.select(null)}onTitle(e){return e instanceof Element&&e.closest(".section-title")!==null&&e.closest(".launcher")===null}onGuard(e){const t=_a(e.target,this.frame());if(t===null)return;if(t.kind==="tab"){if(e.type==="click"){this.store.select([t.tab])}else if(e.type==="dblclick"){e.preventDefault();e.stopPropagation()}return}e.preventDefault();e.stopPropagation()}onContextMenu(e){const t=this.hitAt(e);if(t===null){if(!pp(e.target,this.frame()))return;e.preventDefault();e.stopPropagation();this.popup.open(Pb(this.store),{at:e});return}e.preventDefault();e.stopPropagation();this.popup.open(ip(this.store,mp(t)),{at:e})}dropTargetFor(e,t,o){const i=this.frame();const r=_a(e,i);if(r===null||r.kind==="tab"||r.kind==="body")return null;const s=bo(i,r.tab,r.section);if(!s)return null;const a=i.getBoundingClientRect();const l=[r.tab,"sections",r.section];const d=hp(s,a);const c=Qt(s);const p=c?Hr(c,a):null;if(!p)return{sectionPath:l,cell:null,grid:null,sectionBox:d};return{sectionPath:l,cell:{col:mo(p.cols,t-a.left,true),row:mo(p.rows,o-a.top)},grid:p,sectionBox:d}}rowsOf(e){return this.store.rows()[e[0]]??tt}hintOf(e,t,o,i){const r=o.col>e.cols.list.length?lp(e.cols,e.rows,o.col,t,{row:o.row,rowSpan:o.rowSpan??1}):null;return r?{box:r,ok:i,bar:true}:{box:go(e.cols,e.rows,o),ok:i}}isFree(e,t,o){return this.store.isCellFree(e,t,o)}spanOf(e,t){return this.store.spanOfControl(e,t)}onDragOver(e){if(!e.dataTransfer?.types.includes(Fa))return;e.preventDefault();e.dataTransfer.dropEffect="copy";const t=this.dropTargetFor(e.target,e.clientX,e.clientY);if(!t){this.hint.set(null);return}if(t.cell&&t.grid){const o=this.spanOf(this.store.dragType(),this.rowsOf(t.sectionPath));const i={...t.cell,...o};this.hint.set(this.hintOf(t.grid,t.sectionBox,i,this.isFree(t.sectionPath,i,null)))}else{this.hint.set(t.sectionBox?{box:t.sectionBox,ok:true}:null)}}onDragLeave(e){const t=e.relatedTarget;if(!(t instanceof Node)||!this.frame().contains(t))this.hint.set(null)}onDrop(e){const t=e.dataTransfer?.getData(Fa);this.hint.set(null);this.store.dragType.set(null);if(!t)return;e.preventDefault();const o=this.dropTargetFor(e.target,e.clientX,e.clientY);if(!o)this.store.addItem(t);else if(o.cell)this.store.addItem(t,{sectionPath:o.sectionPath,cell:o.cell});else this.store.addItem(t,{sectionPath:o.sectionPath})}startResize(e,t){const o=this.store.selected();if(e.button!==0||o===null||o.length!==5)return;const i=this.store.placedCell(o);if(!i)return;e.preventDefault();e.stopPropagation();this.begin({kind:"resize",path:o,placed:i,edge:t,minCols:this.leastColumns(o),size:null},e)}leastColumns(e){const t=this.store.drawnColWidth();const o=this.frame();const i=bo(o,e[0],e[2]);const r=i?Qt(i):null;const s=dp(o,e[0],e[2],e[4]);if(!r||!s)return 1;const a=Gb(s);this.mutations?.takeRecords();return a>0?Ka(a,t,Ga(r)):1}begin(e,t){this.endGesture();this.gesture=e;this.busy.set(true);try{this.frame().setPointerCapture(t.pointerId)}catch{}window.addEventListener("pointermove",this.onGestureMove);window.addEventListener("pointerup",this.onGestureEnd);window.addEventListener("pointercancel",this.onGestureCancel);window.addEventListener("keydown",this.onGestureKey,true)}endGesture(){window.removeEventListener("pointermove",this.onGestureMove);window.removeEventListener("pointerup",this.onGestureEnd);window.removeEventListener("pointercancel",this.onGestureCancel);window.removeEventListener("keydown",this.onGestureKey,true);this.gesture=null;this.hint.set(null);this.busy.set(false)}onGestureMove=e=>{const t=this.gesture;if(!t)return;if(t.kind==="move")this.moveTo(t,e);else this.stretchTo(t,e)};moveTo(e,t){if(!e.moved&&Math.hypot(t.clientX-e.startX,t.clientY-e.startY)<5)return;e.moved=true;const o=this.dropTargetFor(document.elementFromPoint(t.clientX,t.clientY),t.clientX,t.clientY);if(!o||!o.cell||!o.grid){e.target=null;this.hint.set(null);return}const i=this.cleanBoundary(e,o.sectionPath,o.cell,o.grid,o.sectionBox,t);if(i!==null){this.inNewColumn(e,{...o,cell:o.cell,grid:o.grid},i);return}const{placed:r}=e;const s=Math.max(1,o.cell.col-e.grab.col);const a=Math.max(1,Math.min(o.cell.row-e.grab.row,this.rowsOf(o.sectionPath)-r.rowSpan+1));e.target={sectionPath:o.sectionPath,cell:{col:s,row:a}};const l={col:s,row:a,colSpan:r.colSpan,rowSpan:r.rowSpan};const d=Fe(e.path.slice(0,3),o.sectionPath)?e.path[4]:null;this.hint.set(this.hintOf(o.grid,o.sectionBox,l,this.isFree(o.sectionPath,l,d)))}itemAt(e,t){const o=this.store.placedSection(e);const i=o.findIndex(r=>r!==null&&t.col>=r.col&&t.col<r.col+r.colSpan&&t.row>=r.row&&t.row<r.row+r.rowSpan);return{at:i,over:o[i]??void 0}}cleanBoundary(e,t,o,i,r,s){const{list:a,gap:l}=i.cols;const d=a.length;if(d===0)return null;const c=s.clientX-this.frame().getBoundingClientRect().left;const p=a[d-1];let h=null;if(c<=a[0].start+3)h=1;else if(c>=p.start+p.size-3)h=d+1;else{const m=Math.max(4,l/2+3);for(let g=2;g<=d&&h===null;g++)if(Math.abs((ap(i.cols,g,r)??Infinity)-c)<=m)h=g}if(h===null)return null;const u=h;if(this.store.placedSection(t).some(m=>m!==null&&m.col<u&&u<m.col+m.colSpan))return null;const f=Math.max(1,Math.min(o.row-e.grab.row,this.rowsOf(t)-e.placed.rowSpan+1));return this.store.rowInNewColumn(e.path,t,h,e.placed.rowSpan,f)===null?null:h}inNewColumn(e,t,o){const{placed:i}=e;const r=Math.max(1,Math.min(t.cell.row-e.grab.row,this.rowsOf(t.sectionPath)-i.rowSpan+1));const s=this.store.plannedColumn(e.path,t.sectionPath,o);if(!s.opens){e.target={sectionPath:t.sectionPath,cell:{col:s.column,row:r}};const d=e.path[4];this.hint.set(this.hintOf(t.grid,t.sectionBox,{col:s.column,row:r,colSpan:i.colSpan,rowSpan:i.rowSpan},this.isFree(t.sectionPath,{col:s.column,row:r,colSpan:i.colSpan,rowSpan:i.rowSpan},d)));return}const a=this.store.rowInNewColumn(e.path,t.sectionPath,o,i.rowSpan,r);const l=lp(t.grid.cols,t.grid.rows,o,t.sectionBox,{row:a??r,rowSpan:i.rowSpan});if(!l){e.target=null;this.hint.set(null);return}e.target=a===null?null:{sectionPath:t.sectionPath,column:o,row:a};this.hint.set({box:l,ok:a!==null,bar:true})}stretchTo(e,t){const o=this.frame();const i=o.getBoundingClientRect();const r=e.path.slice(0,3);const s=bo(o,r[0],r[2]);const a=s?Qt(s):null;const l=a?Hr(a,i):null;if(!l)return;const{placed:d,edge:c}=e;const p=t.clientX-i.left;const h=t.clientY-i.top;let u=d.col;let f=d.col+d.colSpan-1;let m=d.row;let g=d.row+d.rowSpan-1;if(c.includes("e"))f=Math.max(u,Math.min(Wb(l.cols,p),si));if(c.includes("w"))u=Math.min(f,mo(l.cols,p));if(c.includes("e"))f=Math.max(f,u+e.minCols-1);if(c.includes("w"))u=Math.max(1,Math.min(u,f-e.minCols+1));if(c.includes("s"))g=Math.max(m,mo(l.rows,h));if(c.includes("n"))m=Math.min(g,mo(l.rows,h));const y=f-u+1;const b=g-m+1;const x={};if(u!==d.col)x.col=u;if(m!==d.row)x.row=m;if(y!==d.colSpan)x.colSpan=y;if(b!==d.rowSpan)x.rowSpan=b;e.size=Object.keys(x).length===0?null:x;const T=f>d.col+d.colSpan-1;const k=T?this.stretchedBox(l,r,{...d,row:m},e.path[4],y,b):go(l.cols,l.rows,{col:u,row:m,colSpan:y,rowSpan:b});this.hint.set({box:k,ok:e.size===null||this.store.canResize(e.path,e.size)})}stretchedBox(e,t,o,i,r,s){const a=go(e.cols,e.rows,{col:o.col,row:o.row,colSpan:o.colSpan,rowSpan:s});let l=a.width;for(let d=o.col+o.colSpan;d<o.col+r;d++){const c=this.isFree(t,{col:d,row:o.row,colSpan:1,rowSpan:s},i);const p=c?e.cols.list[d-1]?.size??e.cols.fresh??20:e.cols.fresh??20;l+=e.cols.gap+p}return{...a,width:l}}onGestureEnd=()=>{const e=this.gesture;this.endGesture();if(!e)return;if(e.kind==="move"){const t=e.target;if(!e.moved||!t)return;if("column"in t){this.store.moveItemToNewColumn(e.path,t.sectionPath,t.column,t.row);return}const o=Fe(e.path.slice(0,3),t.sectionPath)&&t.cell.col===e.placed.col&&t.cell.row===e.placed.row;if(!o)this.store.moveItemToCell(e.path,t.sectionPath,t.cell)}else if(e.size){this.store.resizeItem(e.path,e.size)}};onGestureCancel=()=>this.endGesture();onGestureKey=e=>{if(e.key!=="Escape")return;e.preventDefault();e.stopPropagation();this.endGesture()};onKeydown(e){const t=e.target instanceof Element&&e.target.closest(".ribbon-tab")!==null;if(e.target!==e.currentTarget&&!t)return;const o=this.store.selected();if(o===null)return;const i=o.length===5?o:null;const r=e.ctrlKey||e.metaKey;const s={ArrowLeft:[-1,0],ArrowRight:[1,0],ArrowUp:[0,-1],ArrowDown:[0,1]};const a=s[e.key];if(e.key==="Delete"||e.key==="Backspace"){this.store.removeSelected()}else if(r&&e.key.toLowerCase()==="d"){this.store.duplicateSelected()}else if(a&&e.altKey){if(a[1]===0)return;this.store.moveSelected(a[1])}else if(a&&i){if(e.shiftKey){const l=this.store.placedCell(i);if(!l)return;const d={};if(a[0]!==0){const c=a[0]<0?Math.min(l.colSpan,this.leastColumns(i)):1;const p=Math.max(l.colSpan,si-l.col+1);d.colSpan=Math.max(c,Math.min(l.colSpan+a[0],p))}if(a[1]!==0)d.rowSpan=Math.max(1,l.rowSpan+a[1]);this.store.resizeItem(i,d)}else{this.store.nudgeItem(i,a[0],a[1])}}else{return}if(t)this.frame().focus({preventScroll:true});e.preventDefault()}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:ji,deps:[],target:w.ɵɵFactoryTarget.Component});static ɵcmp=w.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"21.2.21",type:ji,isStandalone:true,selector:"rbe-editor-panel",viewQueries:[{propertyName:"frameRef",first:true,predicate:["frame"],descendants:true,isSignal:true},{propertyName:"ribbonRef",first:true,predicate:["ribbon"],descendants:true,read:jo,isSignal:true}],ngImport:w,template:`
121
+ <div class="tb">
122
+ <gfy-toggle-group [options]="widthOptions()" [value]="widthKey()" (valueChange)="setWidth($event)" [ariaLabel]="texts.text('Width of the Editor')" />
123
+ <span class="sp"></span>
124
+ <gfy-button toggle appearance="flat" icon="rbe:background" [label]="texts.text('Show background')" [checked]="store.showBackground()" (checkedChange)="store.showBackground.set($event)" />
125
+ <gfy-button toggle appearance="flat" icon="rbe:grid" [label]="texts.text('Show grid')" [checked]="store.showGrid()" (checkedChange)="store.showGrid.set($event)" />
126
+ </div>
127
+ <div class="stage" (pointerdown)="onStagePress($event)">
128
+ <div
129
+ #frame
130
+ class="frame"
131
+ tabindex="0"
132
+ role="group"
133
+ [class.grid]="store.showGrid()"
134
+ [class.moving]="busy()"
135
+ [style.width.px]="store.previewWidth()"
136
+ [attr.aria-label]="texts.text('The ribbon in the Editor')"
137
+ (keydown)="onKeydown($event)"
138
+ (dragover)="onDragOver($event)"
139
+ (dragleave)="onDragLeave($event)"
140
+ (drop)="onDrop($event)">
141
+ <gfy-ribbon
142
+ #ribbon
143
+ [tabs]="store.tabs()"
144
+ [activeTab]="store.activeTabId()"
145
+ (activeTabChange)="onTabChange($event)"
146
+ [defaultRows]="store.options().defaultRows"
147
+ [uniformRows]="store.options().uniformRows"
148
+ [colWidth]="store.drawnColWidth()"
149
+ [colGap]="store.options().colGap ?? undefined"
150
+ [collapsible]="false"
151
+ [search]="store.options().search"
152
+ [searchPlaceholder]="store.options().searchPlaceholder ?? undefined"
153
+ [showGrid]="true"
154
+ [shortcuts]="false"
155
+ [keyTips]="false" />
156
+ <div class="overlay" aria-hidden="true">
157
+ @for (area of itemAreas(); track $index) {
158
+ <div class="itemarea" [style.left.px]="area.x" [style.top.px]="area.y" [style.width.px]="area.width" [style.height.px]="area.height"></div>
159
+ }
160
+ @for (cell of spanCells(); track $index) {
161
+ <div class="spancell" [style.left.px]="cell.x" [style.top.px]="cell.y" [style.width.px]="cell.width" [style.height.px]="cell.height"></div>
162
+ }
163
+ @if (selection(); as selected) {
164
+ <div [class]="'sel ' + selected.kind" [style.left.px]="selected.box.x" [style.top.px]="selected.box.y" [style.width.px]="selected.box.width" [style.height.px]="selected.box.height">
165
+ @if (selected.kind === 'item') {
166
+ @for (edge of handlesOf(selected.box); track edge) {
167
+ <span [class]="'handle ' + edge" (pointerdown)="startResize($event, edge)"></span>
168
+ }
169
+ }
170
+ </div>
171
+ }
172
+ @if (hint(); as frameHint) {
173
+ <div
174
+ class="cue"
175
+ [class.bar]="frameHint.bar"
176
+ [class.horizontal]="frameHint.bar && frameHint.box.width > frameHint.box.height"
177
+ [class.bad]="!frameHint.ok"
178
+ [style.left.px]="frameHint.box.x"
179
+ [style.top.px]="frameHint.box.y"
180
+ [style.width.px]="frameHint.box.width"
181
+ [style.height.px]="frameHint.box.height"></div>
182
+ }
183
+ </div>
184
+ </div>
185
+ @if (store.tabs().length === 0) {
186
+ <div class="help">{{ texts.text('The ribbon has no tab yet. Add one with Edit > Add tab, or with the menu of the right button on the bar of the tabs.') }}</div>
187
+ }
188
+ <div class="help">{{ texts.text('Click selects a node. Drag an item to move it (a frame is a free place, a line is a new column), drag its handles to stretch it, and drop a control from the Toolbox on a cell.') }}</div>
189
+ </div>
190
+ `,isInline:true,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n",".ic{flex:none;display:grid;width:var(--ic, 14px);height:var(--ic, 14px)}\n",".stage{flex:1 1 auto;min-height:0;overflow:auto;padding:10px}.frame{position:relative;max-width:100%;border:1px solid var(--gfy-border-color, rgba(128, 128, 128, .35));background:var(--gfy-bg-main);outline:none}.frame ::ng-deep .section-title{cursor:pointer}.frame ::ng-deep .section-title span:hover{text-decoration:underline}.frame ::ng-deep gfy-ribbon-spinner .field{flex:1 0 auto;margin-left:0}.frame ::ng-deep gfy-ribbon-spinner .field:first-child{margin-left:-4px}.frame.moving,.frame.moving *{cursor:grabbing!important}.frame:not(.grid) ::ng-deep .ghost-cell{visibility:hidden}.frame ::ng-deep .ghost-cell:after{content:none}.overlay{position:absolute;inset:0;pointer-events:none;overflow:hidden}.itemarea{position:absolute;box-sizing:border-box;border:1px solid color-mix(in srgb,var(--gfy-accent, #3a8fd6) 35%,transparent);border-radius:3px;background:color-mix(in srgb,var(--gfy-accent, #3a8fd6) 9%,transparent)}.spancell{position:absolute;box-sizing:border-box;border:1px dashed color-mix(in srgb,var(--gfy-accent, #3a8fd6) 55%,transparent);border-radius:2px}.sel,.cue{position:absolute;box-sizing:border-box;border-radius:3px}.sel{border:2px solid var(--gfy-accent, #3a8fd6);background:color-mix(in srgb,var(--gfy-accent, #3a8fd6) 10%,transparent)}.sel.section{border-style:dashed;background:transparent}.sel.tab{background:color-mix(in srgb,var(--gfy-accent, #3a8fd6) 18%,transparent)}.cue{border:2px dashed var(--gfy-success, #2e9e5b);background:color-mix(in srgb,var(--gfy-success, #2e9e5b) 16%,transparent)}.cue.bad{border-color:var(--gfy-warning, #d9a300);background:color-mix(in srgb,var(--gfy-warning, #d9a300) 18%,transparent)}.cue.bar{--hint-color: var(--gfy-success, #2e9e5b);border:0;border-radius:0;background:repeating-linear-gradient(to bottom,var(--hint-color) 0 6px,transparent 6px 10px)}.cue.bar.horizontal{background:repeating-linear-gradient(to right,var(--hint-color) 0 6px,transparent 6px 10px)}.cue.bar.bad{--hint-color: var(--gfy-warning, #d9a300)}.handle{position:absolute;width:7px;height:7px;box-sizing:border-box;border:1px solid var(--gfy-bg-main, #fff);border-radius:2px;background:var(--gfy-accent, #3a8fd6);pointer-events:auto;touch-action:none}.handle.nw{left:-4px;top:-4px;cursor:nwse-resize}.handle.ne{right:-4px;top:-4px;cursor:nesw-resize}.handle.sw{left:-4px;bottom:-4px;cursor:nesw-resize}.handle.se{right:-4px;bottom:-4px;cursor:nwse-resize}.handle.n{top:-4px;left:calc(50% - 4px);cursor:ns-resize}.handle.s{bottom:-4px;left:calc(50% - 4px);cursor:ns-resize}.handle.e{right:-4px;top:calc(50% - 4px);cursor:ew-resize}.handle.w{left:-4px;top:calc(50% - 4px);cursor:ew-resize}.help{padding:12px 2px 0;font-size:12px;opacity:.88}\n"],dependencies:[{kind:"component",type:ke,selector:"gfy-button",inputs:["label","icon","iconOnly","tooltip","ariaLabel","caret","variant","appearance","layout","toggle","checked","disabled","busy","type","name","haspopup","expanded","controls","joined","attached","reserveLabelSpace"],outputs:["checkedChange","pressed"]},{kind:"component",type:mr,selector:"gfy-ribbon",inputs:["tabs","activeTab","colWidth","colGap","defaultRows","uniformRows","showGrid","collapsible","shortcuts","keyTips","search","searchPlaceholder","quickAccess","minimized","messageBar"],outputs:["activeTabChange","minimizedChange","action","messageBarChange","messageBarClosed","messageBarActionInvoked"]},{kind:"component",type:St,selector:"gfy-toggle-group",inputs:["options","mode","value","values","allowEmpty","iconOnly","orientation","joined","variant","appearance","disabled","label","ariaLabel"],outputs:["valueChange","valuesChange","toggled"]}]})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:ji,decorators:[{type:me,args:[{selector:"rbe-editor-panel",standalone:true,imports:[ke,mr,St],template:`
191
+ <div class="tb">
192
+ <gfy-toggle-group [options]="widthOptions()" [value]="widthKey()" (valueChange)="setWidth($event)" [ariaLabel]="texts.text('Width of the Editor')" />
193
+ <span class="sp"></span>
194
+ <gfy-button toggle appearance="flat" icon="rbe:background" [label]="texts.text('Show background')" [checked]="store.showBackground()" (checkedChange)="store.showBackground.set($event)" />
195
+ <gfy-button toggle appearance="flat" icon="rbe:grid" [label]="texts.text('Show grid')" [checked]="store.showGrid()" (checkedChange)="store.showGrid.set($event)" />
196
+ </div>
197
+ <div class="stage" (pointerdown)="onStagePress($event)">
198
+ <div
199
+ #frame
200
+ class="frame"
201
+ tabindex="0"
202
+ role="group"
203
+ [class.grid]="store.showGrid()"
204
+ [class.moving]="busy()"
205
+ [style.width.px]="store.previewWidth()"
206
+ [attr.aria-label]="texts.text('The ribbon in the Editor')"
207
+ (keydown)="onKeydown($event)"
208
+ (dragover)="onDragOver($event)"
209
+ (dragleave)="onDragLeave($event)"
210
+ (drop)="onDrop($event)">
211
+ <gfy-ribbon
212
+ #ribbon
213
+ [tabs]="store.tabs()"
214
+ [activeTab]="store.activeTabId()"
215
+ (activeTabChange)="onTabChange($event)"
216
+ [defaultRows]="store.options().defaultRows"
217
+ [uniformRows]="store.options().uniformRows"
218
+ [colWidth]="store.drawnColWidth()"
219
+ [colGap]="store.options().colGap ?? undefined"
220
+ [collapsible]="false"
221
+ [search]="store.options().search"
222
+ [searchPlaceholder]="store.options().searchPlaceholder ?? undefined"
223
+ [showGrid]="true"
224
+ [shortcuts]="false"
225
+ [keyTips]="false" />
226
+ <div class="overlay" aria-hidden="true">
227
+ @for (area of itemAreas(); track $index) {
228
+ <div class="itemarea" [style.left.px]="area.x" [style.top.px]="area.y" [style.width.px]="area.width" [style.height.px]="area.height"></div>
229
+ }
230
+ @for (cell of spanCells(); track $index) {
231
+ <div class="spancell" [style.left.px]="cell.x" [style.top.px]="cell.y" [style.width.px]="cell.width" [style.height.px]="cell.height"></div>
232
+ }
233
+ @if (selection(); as selected) {
234
+ <div [class]="'sel ' + selected.kind" [style.left.px]="selected.box.x" [style.top.px]="selected.box.y" [style.width.px]="selected.box.width" [style.height.px]="selected.box.height">
235
+ @if (selected.kind === 'item') {
236
+ @for (edge of handlesOf(selected.box); track edge) {
237
+ <span [class]="'handle ' + edge" (pointerdown)="startResize($event, edge)"></span>
238
+ }
239
+ }
240
+ </div>
241
+ }
242
+ @if (hint(); as frameHint) {
243
+ <div
244
+ class="cue"
245
+ [class.bar]="frameHint.bar"
246
+ [class.horizontal]="frameHint.bar && frameHint.box.width > frameHint.box.height"
247
+ [class.bad]="!frameHint.ok"
248
+ [style.left.px]="frameHint.box.x"
249
+ [style.top.px]="frameHint.box.y"
250
+ [style.width.px]="frameHint.box.width"
251
+ [style.height.px]="frameHint.box.height"></div>
252
+ }
253
+ </div>
254
+ </div>
255
+ @if (store.tabs().length === 0) {
256
+ <div class="help">{{ texts.text('The ribbon has no tab yet. Add one with Edit > Add tab, or with the menu of the right button on the bar of the tabs.') }}</div>
257
+ }
258
+ <div class="help">{{ texts.text('Click selects a node. Drag an item to move it (a frame is a free place, a line is a new column), drag its handles to stretch it, and drop a control from the Toolbox on a cell.') }}</div>
259
+ </div>
260
+ `,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n",".ic{flex:none;display:grid;width:var(--ic, 14px);height:var(--ic, 14px)}\n",".stage{flex:1 1 auto;min-height:0;overflow:auto;padding:10px}.frame{position:relative;max-width:100%;border:1px solid var(--gfy-border-color, rgba(128, 128, 128, .35));background:var(--gfy-bg-main);outline:none}.frame ::ng-deep .section-title{cursor:pointer}.frame ::ng-deep .section-title span:hover{text-decoration:underline}.frame ::ng-deep gfy-ribbon-spinner .field{flex:1 0 auto;margin-left:0}.frame ::ng-deep gfy-ribbon-spinner .field:first-child{margin-left:-4px}.frame.moving,.frame.moving *{cursor:grabbing!important}.frame:not(.grid) ::ng-deep .ghost-cell{visibility:hidden}.frame ::ng-deep .ghost-cell:after{content:none}.overlay{position:absolute;inset:0;pointer-events:none;overflow:hidden}.itemarea{position:absolute;box-sizing:border-box;border:1px solid color-mix(in srgb,var(--gfy-accent, #3a8fd6) 35%,transparent);border-radius:3px;background:color-mix(in srgb,var(--gfy-accent, #3a8fd6) 9%,transparent)}.spancell{position:absolute;box-sizing:border-box;border:1px dashed color-mix(in srgb,var(--gfy-accent, #3a8fd6) 55%,transparent);border-radius:2px}.sel,.cue{position:absolute;box-sizing:border-box;border-radius:3px}.sel{border:2px solid var(--gfy-accent, #3a8fd6);background:color-mix(in srgb,var(--gfy-accent, #3a8fd6) 10%,transparent)}.sel.section{border-style:dashed;background:transparent}.sel.tab{background:color-mix(in srgb,var(--gfy-accent, #3a8fd6) 18%,transparent)}.cue{border:2px dashed var(--gfy-success, #2e9e5b);background:color-mix(in srgb,var(--gfy-success, #2e9e5b) 16%,transparent)}.cue.bad{border-color:var(--gfy-warning, #d9a300);background:color-mix(in srgb,var(--gfy-warning, #d9a300) 18%,transparent)}.cue.bar{--hint-color: var(--gfy-success, #2e9e5b);border:0;border-radius:0;background:repeating-linear-gradient(to bottom,var(--hint-color) 0 6px,transparent 6px 10px)}.cue.bar.horizontal{background:repeating-linear-gradient(to right,var(--hint-color) 0 6px,transparent 6px 10px)}.cue.bar.bad{--hint-color: var(--gfy-warning, #d9a300)}.handle{position:absolute;width:7px;height:7px;box-sizing:border-box;border:1px solid var(--gfy-bg-main, #fff);border-radius:2px;background:var(--gfy-accent, #3a8fd6);pointer-events:auto;touch-action:none}.handle.nw{left:-4px;top:-4px;cursor:nwse-resize}.handle.ne{right:-4px;top:-4px;cursor:nesw-resize}.handle.sw{left:-4px;bottom:-4px;cursor:nesw-resize}.handle.se{right:-4px;bottom:-4px;cursor:nwse-resize}.handle.n{top:-4px;left:calc(50% - 4px);cursor:ns-resize}.handle.s{bottom:-4px;left:calc(50% - 4px);cursor:ns-resize}.handle.e{right:-4px;top:calc(50% - 4px);cursor:ew-resize}.handle.w{left:-4px;top:calc(50% - 4px);cursor:ew-resize}.help{padding:12px 2px 0;font-size:12px;opacity:.88}\n"]}]}],ctorParameters:()=>[],propDecorators:{frameRef:[{type:w.ViewChild,args:["frame",{isSignal:true}]}],ribbonRef:[{type:w.ViewChild,args:["ribbon",{...{read:jo},isSignal:true}]}]}});const Bb=62;const gp=40;function Vb(n,e,t,o=gp){if(!(t>0))return o;const i=Math.ceil((n+e+1)/t*1e3)/10;return Math.max(o,Math.min(Bb,i))}class st{grid=L(Tt,{self:true});host=L(jo).nativeElement;ours;userSet=false;base=gp;last;frame=0;constructor(){Q(()=>{this.grid.properties();this.grid.nameWidth();ee(()=>this.schedule())});if(typeof ResizeObserver!=="undefined"){const e=new ResizeObserver(()=>this.schedule());e.observe(this.host);L(lt).onDestroy(()=>e.disconnect())}L(lt).onDestroy(()=>cancelAnimationFrame(this.frame))}schedule(){cancelAnimationFrame(this.frame);this.frame=requestAnimationFrame(()=>this.fit())}fit(){const e=this.grid.nameWidth();if(e===void 0||e===null){this.userSet=false;this.ours=void 0}else if(e!==this.ours){this.userSet=true}if(this.userSet)return;const t=this.host.querySelector(".row.property");const o=t?.querySelector(".cell.name");const i=t?.querySelector(".label");if(!t||!o||!i)return;const r=t.getBoundingClientRect().width;if(!(r>40))return;const s=getComputedStyle(o);const a=i.getBoundingClientRect().left-o.getBoundingClientRect().left+(parseFloat(s.paddingRight)||0)+(parseFloat(s.borderRightWidth)||0);if(e===void 0||e===null)this.base=Math.round(o.getBoundingClientRect().width/r*1e3)/10;const l=this.widest(i);if(l===0)return;let d=Vb(l,a,r,this.base);if(this.last&&Math.abs(this.last.width-r)<1)d=Math.max(d,this.last.percent);this.last={width:r,percent:d};const c=d<=this.base?void 0:d;if(c===(e??void 0))return;this.ours=c;this.grid.nameWidth.set(c)}widest(e){const t=getComputedStyle(e);const o=this.grid.properties().map(s=>s.label);if(o.length===0)return 0;const i=document.createElement("div");i.setAttribute("aria-hidden","true");Object.assign(i.style,{position:"absolute",visibility:"hidden",left:"-9999px",top:"0",whiteSpace:"nowrap",fontFamily:t.fontFamily,fontSize:t.fontSize,fontWeight:"600",letterSpacing:t.letterSpacing});for(const s of new Set(o)){const a=document.createElement("span");a.style.display="inline-block";a.textContent=s;i.appendChild(a)}document.body.appendChild(i);let r=0;for(const s of Array.from(i.children))r=Math.max(r,s.getBoundingClientRect().width);i.remove();return r}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:st,deps:[],target:w.ɵɵFactoryTarget.Directive});static ɵdir=w.ɵɵngDeclareDirective({minVersion:"14.0.0",version:"21.2.21",type:st,isStandalone:true,selector:"gfy-property-grid[edFitNames]",ngImport:w})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:st,decorators:[{type:zs,args:[{selector:"gfy-property-grid[edFitNames]",standalone:true}]}],ctorParameters:()=>[]});const Hb=["text","number"];function Ba(n,e,t,o){if(e===null||e.scope!==t)return n;const i=o(e.id);if(i===void 0||!Hb.includes(i))return n;return{...n,[e.id]:e.value===void 0||e.value===""?i==="number"?null:"":e.value}}class Pi{store=L(Ze);texts=I;rows=M(()=>this.store.inspector()?.rows??[],{...(ngDevMode?{debugName:"rows"}:({})),equal:(e,t)=>JSON.stringify(e)===JSON.stringify(t)});selectedKey=M(()=>{const e=this.store.selected();return e===null?null:q(e)},...(ngDevMode?[{debugName:"selectedKey"}]:([])));typed=E(null,...(ngDevMode?[{debugName:"typed"}]:([])));values=M(()=>{const e=this.store.inspector();if(!e)return{};const t=this.rows();return Ba(e.values,this.typed(),q(e.path),o=>t.find(i=>i.id===o)?.kind)},...(ngDevMode?[{debugName:"values"}]:([])));active=E(null,...(ngDevMode?[{debugName:"active"}]:([])));describing=M(()=>this.rows().some(e=>e.id===this.active()),...(ngDevMode?[{debugName:"describing"}]:([])));otherOpen=E(false,...(ngDevMode?[{debugName:"otherOpen"}]:([])));kindLabel=M(()=>{switch(this.store.inspector()?.kind){case"tab":return I.text("Tab");case"section":return I.text("Section");case"item":{const e=this.store.inspector()?.control;return e?I.text(e.label):I.text("Item")}case"choice":return I.text("Choice");default:return""}},...(ngDevMode?[{debugName:"kindLabel"}]:([])));icon=M(()=>{const e=this.store.inspector();if(!e)return"rbe:item";if(e.kind==="item")return e.control?ti(e.control.type):"rbe:item";return e.kind==="tab"?"rbe:tab":e.kind==="section"?"rbe:section":"rbe:choice"},...(ngDevMode?[{debugName:"icon"}]:([])));where=M(()=>{const e=this.store.selected();if(e===null)return"";const t=O(this.store.root(),e);const o=v(t)&&typeof t["type"]==="string"&&!J(t["type"])?` (${t["type"]})`:"";return Zt(this.store.root(),e)+o},...(ngDevMode?[{debugName:"where"}]:([])));canReset=M(()=>{const e=this.active();const t=e===null?void 0:this.rows().find(o=>o.id===e);return e!==null&&t!==void 0&&t.kind!=="readonly"&&t.disabled!==true&&this.store.canReset(e)},...(ngDevMode?[{debugName:"canReset"}]:([])));canBind=M(()=>{const e=this.active();const t=e===null?void 0:this.rows().find(o=>o.id===e);return t?.bindable===true&&t.code===void 0},...(ngDevMode?[{debugName:"canBind"}]:([])));draft=E(null,...(ngDevMode?[{debugName:"draft"}]:([])));otherError=E(null,...(ngDevMode?[{debugName:"otherError"}]:([])));otherText=M(()=>this.draft()??Zn(this.store.otherProperties(),2,60),...(ngDevMode?[{debugName:"otherText"}]:([])));constructor(){Q(()=>{this.selectedKey();ee(()=>{this.draft.set(null);this.otherError.set(null);this.typed.set(null)})});Q(()=>{const e=this.active();ee(()=>{if(this.typed()?.id!==e)this.typed.set(null)})});Q(()=>{const e=Object.keys(this.store.otherProperties()).length>0;ee(()=>{if(e)this.otherOpen.set(true)})})}onChange(e){const t=this.store.selected();this.typed.set(t===null?null:{scope:q(t),id:e.id,value:e.value});this.store.changeRow(e.id,e.value)}onGridFocusOut(e){const t=e.currentTarget;if(!(e.relatedTarget instanceof Node&&t.contains(e.relatedTarget)))this.typed.set(null)}bind(){const e=this.active();if(e!==null)this.store.bindRow(e)}reset(){const e=this.active();if(e!==null)this.store.changeRow(e,void 0)}onOther(e){if(e===this.otherText())return;this.draft.set(e);this.otherError.set(this.store.setOtherProperties(e))}endDraft(){if(this.otherError()===null)this.draft.set(null)}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Pi,deps:[],target:w.ɵɵFactoryTarget.Component});static ɵcmp=w.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"21.2.21",type:Pi,isStandalone:true,selector:"rbe-inspector",ngImport:w,template:`
261
+ @if (store.inspector(); as inspector) {
262
+ <div class="head">
263
+ <span class="ic" [gfyIcon]="icon()"></span>
264
+ <span class="kind">{{ kindLabel() }}</span>
265
+ <span class="where" [attr.title]="where()">{{ where() }}</span>
266
+ <gfy-button appearance="flat" iconOnly icon="rbe:link" [label]="texts.text('Bind the property to a signal of the application')" [disabled]="!canBind()" (pressed)="bind()" />
267
+ <gfy-button appearance="flat" iconOnly icon="gfy:close" [label]="texts.text('Reset the property')" [disabled]="!canReset()" (pressed)="reset()" />
268
+ </div>
269
+ <gfy-property-grid edFitNames [properties]="rows()" [values]="values()" [(active)]="active" [showDescription]="describing()" (propertyChanged)="onChange($event)" (focusout)="onGridFocusOut($event)" [ariaLabel]="texts.text('Properties')" />
270
+ <div class="other">
271
+ <gfy-expander [heading]="texts.text('Other properties (JSON)')" [(expanded)]="otherOpen" appearance="plain">
272
+ <div class="other-hint">
273
+ {{
274
+ texts.text(
275
+ 'What the rows above do not hold: properties of your application, the style of a choice and the masks when they hold code, lists such as colors, the inputs of a control the editor does not know, and the same of the compact form.'
276
+ )
277
+ }}
278
+ </div>
279
+ <div class="other-editor" (focusout)="endDraft()">
280
+ <gfy-code-editor language="json" [tabSize]="2" [lineNumbers]="false" [highlightCurrentLine]="false" [ariaLabel]="texts.text('Other properties')" [value]="otherText()" (valueChange)="onOther($event)" />
281
+ </div>
282
+ @if (otherError(); as message) {
283
+ <div class="other-error" role="alert">{{ message }}</div>
284
+ }
285
+ </gfy-expander>
286
+ </div>
287
+ } @else {
288
+ <div class="empty">{{ texts.text('Select a tab, a section, an item or a choice in the Outline or in the Editor.') }}</div>
289
+ }
290
+ `,isInline:true,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n",".ic{flex:none;display:grid;width:var(--ic, 14px);height:var(--ic, 14px)}\n",".head{flex:none;display:flex;align-items:center;gap:8px;padding:6px 10px;background:var(--gfy-bg-header, transparent);border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3))}.head .ic{--ic: 16px;color:var(--gfy-accent, #3a8fd6)}.head .kind{font-weight:600}.head .where{min-width:0;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;opacity:.88}gfy-property-grid{flex:1 1 auto;min-height:0}.other{flex:none;border-top:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3))}.other-editor{height:130px;border-top:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3))}.other-error{padding:4px 10px;color:var(--gfy-danger, #e51400);font-size:12px}.other-hint{padding:4px 10px;font-size:12px;opacity:.88}\n"],dependencies:[{kind:"component",type:ke,selector:"gfy-button",inputs:["label","icon","iconOnly","tooltip","ariaLabel","caret","variant","appearance","layout","toggle","checked","disabled","busy","type","name","haspopup","expanded","controls","joined","attached","reserveLabelSpace"],outputs:["checkedChange","pressed"]},{kind:"component",type:Wn,selector:"gfy-code-editor",inputs:["value","highlight","language","candidates","tokenColors","lineNumbers","tabSize","insertSpaces","readonly","disabled","ariaLabel","lineHeight","marks","highlightCurrentLine","focusFrame","contextMenu"],outputs:["valueChange","cursorMoved","languageDetected"]},{kind:"component",type:Yt,selector:"gfy-expander",inputs:["heading","description","icon","expanded","disabled","appearance","chevronAt","level","keepContent"],outputs:["expandedChange"]},{kind:"directive",type:mt,selector:"[gfyIcon]",inputs:["gfyIcon"]},{kind:"component",type:Tt,selector:"gfy-property-grid",inputs:["properties","values","view","nameWidth","showDescription","showToolbar","filter","collapsed","active","disabled","ariaLabel"],outputs:["valuesChange","viewChange","nameWidthChange","filterChange","collapsedChange","activeChange","propertyChanged"]},{kind:"directive",type:st,selector:"gfy-property-grid[edFitNames]"}]})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Pi,decorators:[{type:me,args:[{selector:"rbe-inspector",standalone:true,imports:[ke,Wn,Yt,mt,Tt,st],template:`
291
+ @if (store.inspector(); as inspector) {
292
+ <div class="head">
293
+ <span class="ic" [gfyIcon]="icon()"></span>
294
+ <span class="kind">{{ kindLabel() }}</span>
295
+ <span class="where" [attr.title]="where()">{{ where() }}</span>
296
+ <gfy-button appearance="flat" iconOnly icon="rbe:link" [label]="texts.text('Bind the property to a signal of the application')" [disabled]="!canBind()" (pressed)="bind()" />
297
+ <gfy-button appearance="flat" iconOnly icon="gfy:close" [label]="texts.text('Reset the property')" [disabled]="!canReset()" (pressed)="reset()" />
298
+ </div>
299
+ <gfy-property-grid edFitNames [properties]="rows()" [values]="values()" [(active)]="active" [showDescription]="describing()" (propertyChanged)="onChange($event)" (focusout)="onGridFocusOut($event)" [ariaLabel]="texts.text('Properties')" />
300
+ <div class="other">
301
+ <gfy-expander [heading]="texts.text('Other properties (JSON)')" [(expanded)]="otherOpen" appearance="plain">
302
+ <div class="other-hint">
303
+ {{
304
+ texts.text(
305
+ 'What the rows above do not hold: properties of your application, the style of a choice and the masks when they hold code, lists such as colors, the inputs of a control the editor does not know, and the same of the compact form.'
306
+ )
307
+ }}
308
+ </div>
309
+ <div class="other-editor" (focusout)="endDraft()">
310
+ <gfy-code-editor language="json" [tabSize]="2" [lineNumbers]="false" [highlightCurrentLine]="false" [ariaLabel]="texts.text('Other properties')" [value]="otherText()" (valueChange)="onOther($event)" />
311
+ </div>
312
+ @if (otherError(); as message) {
313
+ <div class="other-error" role="alert">{{ message }}</div>
314
+ }
315
+ </gfy-expander>
316
+ </div>
317
+ } @else {
318
+ <div class="empty">{{ texts.text('Select a tab, a section, an item or a choice in the Outline or in the Editor.') }}</div>
319
+ }
320
+ `,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n",".ic{flex:none;display:grid;width:var(--ic, 14px);height:var(--ic, 14px)}\n",".head{flex:none;display:flex;align-items:center;gap:8px;padding:6px 10px;background:var(--gfy-bg-header, transparent);border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3))}.head .ic{--ic: 16px;color:var(--gfy-accent, #3a8fd6)}.head .kind{font-weight:600}.head .where{min-width:0;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;opacity:.88}gfy-property-grid{flex:1 1 auto;min-height:0}.other{flex:none;border-top:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3))}.other-editor{height:130px;border-top:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3))}.other-error{padding:4px 10px;color:var(--gfy-danger, #e51400);font-size:12px}.other-hint{padding:4px 10px;font-size:12px;opacity:.88}\n"]}]}],ctorParameters:()=>[]});class Wi{store=L(Ze);texts=I;width=E(null,...(ngDevMode?[{debugName:"width"}]:([])));widthKey=M(()=>this.width()===null?"fit":String(this.width()),...(ngDevMode?[{debugName:"widthKey"}]:([])));widthOptions=M(()=>[{value:"fit",label:I.text("Fit")},{value:"1000",label:"1000"},{value:"700",label:"700"},{value:"480",label:"480"},{value:"320",label:"320"}],...(ngDevMode?[{debugName:"widthOptions"}]:([])));setWidth(e){this.width.set(e===null||e==="fit"?null:Number(e))}onTabChange(e){if(e!==void 0)this.store.selectTabById(e)}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Wi,deps:[],target:w.ɵɵFactoryTarget.Component});static ɵcmp=w.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"21.2.21",type:Wi,isStandalone:true,selector:"rbe-live-panel",ngImport:w,template:`
321
+ <div class="tb">
322
+ <gfy-toggle-group [options]="widthOptions()" [value]="widthKey()" (valueChange)="setWidth($event)" [ariaLabel]="texts.text('Width of the preview')" />
323
+ </div>
324
+ <div class="stage">
325
+ <div class="frame" role="group" [style.width.px]="width()" [attr.aria-label]="texts.text('Preview of the ribbon')">
326
+ <gfy-ribbon
327
+ [tabs]="store.liveTabs()"
328
+ [activeTab]="store.activeTabId()"
329
+ (activeTabChange)="onTabChange($event)"
330
+ (action)="store.reportAction($event)"
331
+ [defaultRows]="store.options().defaultRows"
332
+ [uniformRows]="store.options().uniformRows"
333
+ [colWidth]="store.options().colWidth ?? undefined"
334
+ [colGap]="store.options().colGap ?? undefined"
335
+ [collapsible]="store.options().collapsible"
336
+ [search]="store.options().search"
337
+ [searchPlaceholder]="store.options().searchPlaceholder ?? undefined"
338
+ [shortcuts]="false"
339
+ [keyTips]="false" />
340
+ </div>
341
+ @if (store.tabs().length === 0) {
342
+ <div class="help">{{ texts.text('The ribbon has no tab yet.') }}</div>
343
+ }
344
+ <div class="help">
345
+ {{
346
+ texts.text(
347
+ 'The ribbon as the application shows it, but without shortcuts and key tips (the editor keeps its own keys): menus open and controls respond, and the status bar says which action the application would get. It is edited in the Editor window.'
348
+ )
349
+ }}
350
+ </div>
351
+ </div>
352
+ `,isInline:true,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n",".stage{flex:1 1 auto;min-height:0;overflow:auto;padding:10px}.frame{max-width:100%;border:1px solid var(--gfy-border-color, rgba(128, 128, 128, .35));background:var(--gfy-bg-main)}.frame ::ng-deep gfy-ribbon-spinner .field{flex:1 0 auto;margin-left:0}.frame ::ng-deep gfy-ribbon-spinner .field:first-child{margin-left:-4px}.help{padding:12px 2px 0;font-size:12px;opacity:.88}\n"],dependencies:[{kind:"component",type:mr,selector:"gfy-ribbon",inputs:["tabs","activeTab","colWidth","colGap","defaultRows","uniformRows","showGrid","collapsible","shortcuts","keyTips","search","searchPlaceholder","quickAccess","minimized","messageBar"],outputs:["activeTabChange","minimizedChange","action","messageBarChange","messageBarClosed","messageBarActionInvoked"]},{kind:"component",type:St,selector:"gfy-toggle-group",inputs:["options","mode","value","values","allowEmpty","iconOnly","orientation","joined","variant","appearance","disabled","label","ariaLabel"],outputs:["valueChange","valuesChange","toggled"]}]})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Wi,decorators:[{type:me,args:[{selector:"rbe-live-panel",standalone:true,imports:[mr,St],template:`
353
+ <div class="tb">
354
+ <gfy-toggle-group [options]="widthOptions()" [value]="widthKey()" (valueChange)="setWidth($event)" [ariaLabel]="texts.text('Width of the preview')" />
355
+ </div>
356
+ <div class="stage">
357
+ <div class="frame" role="group" [style.width.px]="width()" [attr.aria-label]="texts.text('Preview of the ribbon')">
358
+ <gfy-ribbon
359
+ [tabs]="store.liveTabs()"
360
+ [activeTab]="store.activeTabId()"
361
+ (activeTabChange)="onTabChange($event)"
362
+ (action)="store.reportAction($event)"
363
+ [defaultRows]="store.options().defaultRows"
364
+ [uniformRows]="store.options().uniformRows"
365
+ [colWidth]="store.options().colWidth ?? undefined"
366
+ [colGap]="store.options().colGap ?? undefined"
367
+ [collapsible]="store.options().collapsible"
368
+ [search]="store.options().search"
369
+ [searchPlaceholder]="store.options().searchPlaceholder ?? undefined"
370
+ [shortcuts]="false"
371
+ [keyTips]="false" />
372
+ </div>
373
+ @if (store.tabs().length === 0) {
374
+ <div class="help">{{ texts.text('The ribbon has no tab yet.') }}</div>
375
+ }
376
+ <div class="help">
377
+ {{
378
+ texts.text(
379
+ 'The ribbon as the application shows it, but without shortcuts and key tips (the editor keeps its own keys): menus open and controls respond, and the status bar says which action the application would get. It is edited in the Editor window.'
380
+ )
381
+ }}
382
+ </div>
383
+ </div>
384
+ `,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n",".stage{flex:1 1 auto;min-height:0;overflow:auto;padding:10px}.frame{max-width:100%;border:1px solid var(--gfy-border-color, rgba(128, 128, 128, .35));background:var(--gfy-bg-main)}.frame ::ng-deep gfy-ribbon-spinner .field{flex:1 0 auto;margin-left:0}.frame ::ng-deep gfy-ribbon-spinner .field:first-child{margin-left:-4px}.help{padding:12px 2px 0;font-size:12px;opacity:.88}\n"]}]}]});class Ki{store=L(Ze);ui=L(cf);densityGap=M(()=>{const e=this.ui.density();const t=parseFloat(getComputedStyle(document.documentElement).getPropertyValue("--gfy-ribbon-col-gap"));return Number.isFinite(t)?{density:e,gap:t}:null},...(ngDevMode?[{debugName:"densityGap"}]:([])));texts=I;active=E(null,...(ngDevMode?[{debugName:"active"}]:([])));describing=M(()=>this.rows().some(e=>e.id===this.active()),...(ngDevMode?[{debugName:"describing"}]:([])));rows=M(()=>{const e=I.text("Inputs of <gfy-ribbon>");const t=I.text("Functions");const o=this.densityGap();return[{id:"defaultRows",label:"defaultRows",kind:"number",category:e,min:1,step:1,decimals:0,defaultValue:Ct.defaultRows,description:I.text("The least number of grid rows of a tab. A tab whose items stand lower, or that sets more rows, has as many rows as it needs.")},{id:"uniformRows",label:"uniformRows",kind:"boolean",category:e,defaultValue:Ct.uniformRows,description:I.text("All tabs have as many rows as the tallest one, so the ribbon does not change its height when the tab changes.")},{id:"colWidth",label:"colWidth",kind:"number",category:e,...ni.colWidth,step:0.5,unit:"px",defaultValue:Ct.colWidth,placeholder:I.text("content width"),description:I.text("The width of every column, 20 to 100 px (24 for a new ribbon). The Editor always draws columns of one width, so that an item covers as many cells as its column span says. Empty: not set, and an application makes every column as wide as its content, as the Preview shows (the Editor draws the columns {width} px wide then).",{width:Ir})},{id:"colGap",label:"colGap",kind:"number",category:e,...ni.colGap,step:0.5,unit:"px",defaultValue:Ct.colGap,...(o?{placeholder:I.text("{gap} ({density})",{gap:o.gap,density:o.density})}:{}),description:I.text("The gap between the columns, 0 to 20 px. 0: no gap. Empty: the gap of the density that the user chooses (3 to 10 px), which the empty field shows in grey; a number is the same gap in every density.")},{id:"collapsible",label:"collapsible",kind:"boolean",category:e,defaultValue:Ct.collapsible,description:I.text("A section that does not fit is shrunk to compact form and then collapsed to a button.")},{id:"search",label:"search",kind:"boolean",category:e,defaultValue:Ct.search,description:I.text("A search box at the end of the row of tabs finds the commands of the ribbon.")},{id:"searchPlaceholder",label:"searchPlaceholder",kind:"text",category:e,defaultValue:Ct.searchPlaceholder,description:I.text("The text of the empty search box. It is used only when the search is on. Empty: the text of the library. An empty text that a file holds (\"\") is kept: the search box shows no text then.")},{id:"predefinedFunctions",label:"predefinedFunctions",kind:"readonly",category:t,description:I.text("Functions that every file knows: the translations of the library, and the text is their first argument (the key for tk). They are always there, cannot be changed, and the application registers nothing for them.")},{id:"functions",label:"functions",kind:"text",category:t,placeholder:"s.field:2",defaultValue:"",description:I.text("Functions of your application that the expressions of the ribbon may call, as =name('text'): a list such as s.field:2, s.flag:2, where the number after the colon is the argument that holds the value to show (the first one without it). The application registers them for gfyLoadRibbon under these names. Not t, tr, tx and tk: they are the translations of the library. A call of any other function is a problem.")},{id:"checkIcons",label:"checkIcons",kind:"boolean",category:I.text("Editor"),defaultValue:false,description:I.text("Report an icon that this editor does not have. Leave it off if your application registers its own icons: they are drawn here as a placeholder.")}]},...(ngDevMode?[{debugName:"rows"}]:([])));typed=E(null,...(ngDevMode?[{debugName:"typed"}]:([])));values=M(()=>{const e=this.rows();const t={...this.store.options(),checkIcons:this.store.checkIcons(),predefinedFunctions:this.store.predefinedFunctions,functions:this.store.customFunctions()};return Ba(t,this.typed(),"options",o=>e.find(i=>i.id===o)?.kind)},...(ngDevMode?[{debugName:"values"}]:([])));constructor(){Q(()=>{const e=this.active();ee(()=>{if(this.typed()?.id!==e)this.typed.set(null)})})}onGridFocusOut(e){const t=e.currentTarget;if(!(e.relatedTarget instanceof Node&&t.contains(e.relatedTarget)))this.typed.set(null)}onChange(e){const{id:t,value:o}=e;this.typed.set({scope:"options",id:t,value:o});switch(t){case"defaultRows":this.store.setDefaultRows(o===null||o===void 0||o===""||!Number.isFinite(Number(o))?Ct.defaultRows:Math.max(1,Math.floor(Number(o))));break;case"colGap":this.setSize(t,o,null);break;case"colWidth":this.setSize(t,o,null);break;case"uniformRows":case"collapsible":case"search":this.store.setOption(t,o===true);break;case"searchPlaceholder":this.store.setOption("searchPlaceholder",typeof o==="string"&&o!==""?o:null);break;case"checkIcons":this.store.checkIcons.set(o===true);break;case"functions":this.store.setCustomFunctions(typeof o==="string"?o:"");break}}setSize(e,t,o){this.store.setOption(e,Tg(e,t)??o)}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Ki,deps:[],target:w.ɵɵFactoryTarget.Component});static ɵcmp=w.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"21.2.21",type:Ki,isStandalone:true,selector:"rbe-options",ngImport:w,template:`
385
+ <div class="hint">{{ texts.text('These are inputs of the element, not part of the tabs: they change the Editor, the Preview and the template of the output.') }}</div>
386
+ <gfy-property-grid edFitNames [properties]="rows()" [values]="values()" [(active)]="active" [showDescription]="describing()" (propertyChanged)="onChange($event)" (focusout)="onGridFocusOut($event)" [ariaLabel]="texts.text('Ribbon Options')" />
387
+ `,isInline:true,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n","gfy-property-grid{flex:1 1 auto;min-height:0}\n"],dependencies:[{kind:"component",type:Tt,selector:"gfy-property-grid",inputs:["properties","values","view","nameWidth","showDescription","showToolbar","filter","collapsed","active","disabled","ariaLabel"],outputs:["valuesChange","viewChange","nameWidthChange","filterChange","collapsedChange","activeChange","propertyChanged"]},{kind:"directive",type:st,selector:"gfy-property-grid[edFitNames]"}]})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Ki,decorators:[{type:me,args:[{selector:"rbe-options",standalone:true,imports:[Tt,st],template:`
388
+ <div class="hint">{{ texts.text('These are inputs of the element, not part of the tabs: they change the Editor, the Preview and the template of the output.') }}</div>
389
+ <gfy-property-grid edFitNames [properties]="rows()" [values]="values()" [(active)]="active" [showDescription]="describing()" (propertyChanged)="onChange($event)" (focusout)="onGridFocusOut($event)" [ariaLabel]="texts.text('Ribbon Options')" />
390
+ `,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n","gfy-property-grid{flex:1 1 auto;min-height:0}\n"]}]}],ctorParameters:()=>[]});const qb={error:"var(--gfy-danger, #e51400)",warning:"var(--gfy-warning, #d9a300)",info:"var(--gfy-accent, #3794ff)"};class _i{store=L(Ze);texts=I;popup=L(Wo);icons=L(Po);expanded=E(/* @__PURE__ */new Set,...(ngDevMode?[{debugName:"expanded"}]:([])));known=/* @__PURE__ */new Set;knownDocument=-1;selectedKey=M(()=>{const e=this.store.selected();return e===null?null:q(e)},...(ngDevMode?[{debugName:"selectedKey"}]:([])));marks=M(()=>{const e=/* @__PURE__ */new Map;const t={error:0,warning:1,info:2};for(const o of this.store.problems()){const i=o.severity;if(!o.nodePath||i===void 0||i==="info")continue;const r=q(o.nodePath);const s=e.get(r);if(s===void 0||t[i]<t[s])e.set(r,i)}return e},...(ngDevMode?[{debugName:"marks"}]:([])));nodes=M(()=>{const e=this.marks();const t={tab:I.text("(tab)"),section:I.text("(section)"),item:I.text("(item)"),choice:I.text("(choice)")};const o=i=>i.map(r=>{const s=q(r.path);const a=e.get(s);const l=r.kind==="item"?r.type!==void 0&&J(r.type)?ti(r.type):"rbe:item":r.kind==="choice"?"rbe:choice":r.kind==="section"?"rbe:section":"rbe:tab";return{id:s,kind:r.kind==="tab"||r.kind==="section"?r.kind:void 0,label:r.title===""?t[r.kind]:r.title,icon:this.icons.has(l)?l:void 0,iconColor:a?qb[a]:void 0,description:r.kind==="item"?r.type??"":void 0,children:o(r.children)}});return o(ed(this.store.root(),this.store.functions()))},...(ngDevMode?[{debugName:"nodes"}]:([])));constructor(){Q(()=>{const e=ed(this.store.root(),this.store.functions());const t=this.store.documentSeq();ee(()=>{if(t!==this.knownDocument){this.knownDocument=t;this.known.clear()}const o=new Set(this.expanded());let i=false;const r=s=>{for(const a of s){const l=q(a.path);if(!this.known.has(l)){this.known.add(l);if((a.kind==="tab"||a.kind==="section")&&!o.has(l)){o.add(l);i=true}}r(a.children)}};r(e);if(i)this.expanded.set(o)})});Q(()=>{const e=this.store.selected();if(e===null)return;ee(()=>{const t=new Set(this.expanded());let o=false;for(let i=1;i<e.length;i++){const r=e.slice(0,i);const s=_(r);if(s!=="tab"&&s!=="section"&&s!=="item"&&s!=="choice")continue;const a=q(r);if(!t.has(a)){t.add(a);o=true}}if(o)this.expanded.set(t)})})}onSelected(e){if(e===null)return;const t=Un(e);this.store.select(t)}moveRules={tab:{},section:{into:["tab"]}};onMoved(e){const t=Un(e.node.id);const o=_(t);if(o==="tab"&&typeof t[0]==="number")this.store.moveTabTo(t[0],e.index);else if(o==="section"&&e.parentId!==null){const i=Un(e.parentId)[0];if(typeof i==="number")this.store.moveSectionTo(t,i,e.index)}}onKey(e){const t=e.event.key;const o=e.event.ctrlKey||e.event.metaKey;if(t==="Delete"||t==="Backspace")this.store.removeSelected();else if(o&&t.toLowerCase()==="d")this.store.duplicateSelected();else if(e.event.altKey&&t==="ArrowUp")this.store.moveSelected(-1);else if(e.event.altKey&&t==="ArrowDown")this.store.moveSelected(1);else return;e.event.preventDefault()}menu=e=>ip(this.store,Un(e.id));onAddChoice(e){const t=this.store.capabilities().choiceEntries;const o=e.currentTarget instanceof Element?e.currentTarget:e.target?.closest("gfy-button");if(t.length<=1||!o){this.store.addChoice();return}this.popup.open(np(t,i=>this.store.addChoice(void 0,i)),{anchor:o,keyboard:e.detail===0})}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:_i,deps:[],target:w.ɵɵFactoryTarget.Component});static ɵcmp=w.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"21.2.21",type:_i,isStandalone:true,selector:"rbe-outline",ngImport:w,template:`
391
+ <div class="tb">
392
+ <gfy-button appearance="flat" iconOnly icon="rbe:undo" [label]="texts.text('Undo')" [disabled]="!store.canUndo()" (pressed)="store.undo()" />
393
+ <gfy-button appearance="flat" iconOnly icon="rbe:redo" [label]="texts.text('Redo')" [disabled]="!store.canRedo()" (pressed)="store.redo()" />
394
+ <span class="sep" aria-hidden="true"></span>
395
+ <gfy-button appearance="flat" iconOnly icon="rbe:add-tab" [label]="texts.text('Add tab')" (pressed)="store.addTab()" />
396
+ <gfy-button appearance="flat" iconOnly icon="rbe:add-section" [label]="texts.text('Add section')" (pressed)="store.addSection()" />
397
+ <gfy-button appearance="flat" iconOnly icon="rbe:add-choice" [label]="texts.text('Add choice')" [disabled]="!store.capabilities().addChoice" (pressed)="onAddChoice($event)" />
398
+ <span class="sep" aria-hidden="true"></span>
399
+ <gfy-button appearance="flat" iconOnly icon="rbe:duplicate" [label]="texts.text('Duplicate')" [disabled]="!store.capabilities().duplicate" (pressed)="store.duplicateSelected()" />
400
+ <gfy-button appearance="flat" iconOnly icon="rbe:up" [label]="texts.text('Move up')" [disabled]="!store.capabilities().moveUp" (pressed)="store.moveSelected(-1)" />
401
+ <gfy-button appearance="flat" iconOnly icon="rbe:down" [label]="texts.text('Move down')" [disabled]="!store.capabilities().moveDown" (pressed)="store.moveSelected(1)" />
402
+ <gfy-button appearance="flat" iconOnly icon="rbe:remove" [label]="texts.text('Remove')" [disabled]="!store.capabilities().remove" (pressed)="store.removeSelected()" />
403
+ </div>
404
+ <gfy-tree
405
+ [nodes]="nodes()"
406
+ [selected]="selectedKey()"
407
+ (selectedChange)="onSelected($event)"
408
+ [(expanded)]="expanded"
409
+ [nodeMenu]="menu"
410
+ [tools]="['collapseAll', 'expandAll']"
411
+ filterable
412
+ guides
413
+ [collapseToLevel]="1"
414
+ [moveRules]="moveRules"
415
+ (nodeMoved)="onMoved($event)"
416
+ [ariaLabel]="texts.text('Outline')"
417
+ [emptyText]="texts.text('The ribbon has no tab yet. Add one with the button above.')"
418
+ (nodeKeydown)="onKey($event)" />
419
+ `,isInline:true,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n","gfy-tree{flex:1 1 auto;min-height:0}gfy-tree ::ng-deep .bar{padding:6px}\n"],dependencies:[{kind:"component",type:ke,selector:"gfy-button",inputs:["label","icon","iconOnly","tooltip","ariaLabel","caret","variant","appearance","layout","toggle","checked","disabled","busy","type","name","haspopup","expanded","controls","joined","attached","reserveLabelSpace"],outputs:["checkedChange","pressed"]},{kind:"component",type:Kn,selector:"gfy-tree",inputs:["nodes","expanded","selected","selection","selectionMode","checkboxes","checked","checkMode","filter","filterable","filterMatch","twisty","guides","activateOnClick","tools","toolbar","collapseToLevel","nodeMenu","ariaLabel","emptyText","moveRules","canMove"],outputs:["expandedChange","selectedChange","selectionChange","checkedChange","filterChange","nodeActivated","nodeToggled","nodeChecked","nodeMoved","nodeKeydown"]}]})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:_i,decorators:[{type:me,args:[{selector:"rbe-outline",standalone:true,imports:[ke,Kn],template:`
420
+ <div class="tb">
421
+ <gfy-button appearance="flat" iconOnly icon="rbe:undo" [label]="texts.text('Undo')" [disabled]="!store.canUndo()" (pressed)="store.undo()" />
422
+ <gfy-button appearance="flat" iconOnly icon="rbe:redo" [label]="texts.text('Redo')" [disabled]="!store.canRedo()" (pressed)="store.redo()" />
423
+ <span class="sep" aria-hidden="true"></span>
424
+ <gfy-button appearance="flat" iconOnly icon="rbe:add-tab" [label]="texts.text('Add tab')" (pressed)="store.addTab()" />
425
+ <gfy-button appearance="flat" iconOnly icon="rbe:add-section" [label]="texts.text('Add section')" (pressed)="store.addSection()" />
426
+ <gfy-button appearance="flat" iconOnly icon="rbe:add-choice" [label]="texts.text('Add choice')" [disabled]="!store.capabilities().addChoice" (pressed)="onAddChoice($event)" />
427
+ <span class="sep" aria-hidden="true"></span>
428
+ <gfy-button appearance="flat" iconOnly icon="rbe:duplicate" [label]="texts.text('Duplicate')" [disabled]="!store.capabilities().duplicate" (pressed)="store.duplicateSelected()" />
429
+ <gfy-button appearance="flat" iconOnly icon="rbe:up" [label]="texts.text('Move up')" [disabled]="!store.capabilities().moveUp" (pressed)="store.moveSelected(-1)" />
430
+ <gfy-button appearance="flat" iconOnly icon="rbe:down" [label]="texts.text('Move down')" [disabled]="!store.capabilities().moveDown" (pressed)="store.moveSelected(1)" />
431
+ <gfy-button appearance="flat" iconOnly icon="rbe:remove" [label]="texts.text('Remove')" [disabled]="!store.capabilities().remove" (pressed)="store.removeSelected()" />
432
+ </div>
433
+ <gfy-tree
434
+ [nodes]="nodes()"
435
+ [selected]="selectedKey()"
436
+ (selectedChange)="onSelected($event)"
437
+ [(expanded)]="expanded"
438
+ [nodeMenu]="menu"
439
+ [tools]="['collapseAll', 'expandAll']"
440
+ filterable
441
+ guides
442
+ [collapseToLevel]="1"
443
+ [moveRules]="moveRules"
444
+ (nodeMoved)="onMoved($event)"
445
+ [ariaLabel]="texts.text('Outline')"
446
+ [emptyText]="texts.text('The ribbon has no tab yet. Add one with the button above.')"
447
+ (nodeKeydown)="onKey($event)" />
448
+ `,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n","gfy-tree{flex:1 1 auto;min-height:0}gfy-tree ::ng-deep .bar{padding:6px}\n"]}]}],ctorParameters:()=>[]});class Et{kinds=we.required(...(ngDevMode?[{debugName:"kinds"}]:([])));kind=we.required(...(ngDevMode?[{debugName:"kind"}]:([])));labels=we.required(...(ngDevMode?[{debugName:"labels"}]:([])));description=we("",...(ngDevMode?[{debugName:"description"}]:([])));language=we("json",...(ngDevMode?[{debugName:"language"}]:([])));text=we("",...(ngDevMode?[{debugName:"text"}]:([])));copyIcon=we("gfy:copy",...(ngDevMode?[{debugName:"copyIcon"}]:([])));downloadIcon=we("gfy:download",...(ngDevMode?[{debugName:"downloadIcon"}]:([])));kindChange=Rs();copyPressed=Rs();downloadPressed=Rs();onKind(e){if(e!==null)this.kindChange.emit(e)}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Et,deps:[],target:w.ɵɵFactoryTarget.Component});static ɵcmp=w.ɵɵngDeclareComponent({minVersion:"17.1.0",version:"21.2.21",type:Et,isStandalone:true,selector:"editor-output",inputs:{kinds:{classPropertyName:"kinds",publicName:"kinds",isSignal:true,isRequired:true,transformFunction:null},kind:{classPropertyName:"kind",publicName:"kind",isSignal:true,isRequired:true,transformFunction:null},labels:{classPropertyName:"labels",publicName:"labels",isSignal:true,isRequired:true,transformFunction:null},description:{classPropertyName:"description",publicName:"description",isSignal:true,isRequired:false,transformFunction:null},language:{classPropertyName:"language",publicName:"language",isSignal:true,isRequired:false,transformFunction:null},text:{classPropertyName:"text",publicName:"text",isSignal:true,isRequired:false,transformFunction:null},copyIcon:{classPropertyName:"copyIcon",publicName:"copyIcon",isSignal:true,isRequired:false,transformFunction:null},downloadIcon:{classPropertyName:"downloadIcon",publicName:"downloadIcon",isSignal:true,isRequired:false,transformFunction:null}},outputs:{kindChange:"kindChange",copyPressed:"copyPressed",downloadPressed:"downloadPressed"},ngImport:w,template:`
449
+ <div class="tb">
450
+ <gfy-toggle-group [options]="kinds()" [value]="kind()" (valueChange)="onKind($event)" [ariaLabel]="labels().form" />
451
+ <span class="sp"></span>
452
+ <gfy-button appearance="flat" [icon]="copyIcon()" [label]="labels().copy" (pressed)="copyPressed.emit()" />
453
+ <gfy-button appearance="flat" [icon]="downloadIcon()" [label]="labels().download" (pressed)="downloadPressed.emit()" />
454
+ </div>
455
+ <div class="hint">{{ description() }}</div>
456
+ <gfy-code-editor readonly [tabSize]="2" [focusFrame]="false" [language]="language()" [ariaLabel]="labels().output" [value]="text()" />
457
+ `,isInline:true,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n","gfy-code-editor{flex:1 1 auto;min-height:0}\n"],dependencies:[{kind:"component",type:ke,selector:"gfy-button",inputs:["label","icon","iconOnly","tooltip","ariaLabel","caret","variant","appearance","layout","toggle","checked","disabled","busy","type","name","haspopup","expanded","controls","joined","attached","reserveLabelSpace"],outputs:["checkedChange","pressed"]},{kind:"component",type:Wn,selector:"gfy-code-editor",inputs:["value","highlight","language","candidates","tokenColors","lineNumbers","tabSize","insertSpaces","readonly","disabled","ariaLabel","lineHeight","marks","highlightCurrentLine","focusFrame","contextMenu"],outputs:["valueChange","cursorMoved","languageDetected"]},{kind:"component",type:St,selector:"gfy-toggle-group",inputs:["options","mode","value","values","allowEmpty","iconOnly","orientation","joined","variant","appearance","disabled","label","ariaLabel"],outputs:["valueChange","valuesChange","toggled"]}]})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Et,decorators:[{type:me,args:[{selector:"editor-output",standalone:true,imports:[ke,Wn,St],template:`
458
+ <div class="tb">
459
+ <gfy-toggle-group [options]="kinds()" [value]="kind()" (valueChange)="onKind($event)" [ariaLabel]="labels().form" />
460
+ <span class="sp"></span>
461
+ <gfy-button appearance="flat" [icon]="copyIcon()" [label]="labels().copy" (pressed)="copyPressed.emit()" />
462
+ <gfy-button appearance="flat" [icon]="downloadIcon()" [label]="labels().download" (pressed)="downloadPressed.emit()" />
463
+ </div>
464
+ <div class="hint">{{ description() }}</div>
465
+ <gfy-code-editor readonly [tabSize]="2" [focusFrame]="false" [language]="language()" [ariaLabel]="labels().output" [value]="text()" />
466
+ `,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n","gfy-code-editor{flex:1 1 auto;min-height:0}\n"]}]}],propDecorators:{kinds:[{type:w.Input,args:[{isSignal:true,alias:"kinds",required:true}]}],kind:[{type:w.Input,args:[{isSignal:true,alias:"kind",required:true}]}],labels:[{type:w.Input,args:[{isSignal:true,alias:"labels",required:true}]}],description:[{type:w.Input,args:[{isSignal:true,alias:"description",required:false}]}],language:[{type:w.Input,args:[{isSignal:true,alias:"language",required:false}]}],text:[{type:w.Input,args:[{isSignal:true,alias:"text",required:false}]}],copyIcon:[{type:w.Input,args:[{isSignal:true,alias:"copyIcon",required:false}]}],downloadIcon:[{type:w.Input,args:[{isSignal:true,alias:"downloadIcon",required:false}]}],kindChange:[{type:w.Output,args:["kindChange"]}],copyPressed:[{type:w.Output,args:["copyPressed"]}],downloadPressed:[{type:w.Output,args:["downloadPressed"]}]}});const Ub={file:"File",json:"Tabs (JSON)",typescript:"TypeScript",handler:"Handler",template:"Template",usage:"Loader"};const Yb={file:"The file of the editor: the tabs with the options of the ribbon and its custom functions. Open it again in the editor, or load it in the application with gfyLoadRibbon.",json:"The value of [tabs] as JSON: what an application loads from a file or from a server.",typescript:"The value of [tabs] as a TypeScript literal, to paste into a component.",handler:"A handler for (action) with a case for every action of the ribbon, and a stub for every function the JSON refers to.",template:"The element for the template of a component, with the options of the ribbon that differ from the defaults.",usage:`Code that loads the file with gfyLoadRibbon: {"$fn": "name"} and the calls such as s.field('size', 11) are looked up in the functions of your application (tr('Home') is the translation of the library), {"$bind": "name"} in its signals, and the options come back with the tabs.`};const Jb={file:"json",json:"json",typescript:"ts",handler:"ts",template:"html",usage:"ts"};class Gi{store=L(Ze);options=M(()=>Db.map(e=>({value:e,label:I.text(Ub[e])})),...(ngDevMode?[{debugName:"options"}]:([])));labels=M(()=>({form:I.text("Form of the output"),output:I.text("Output"),copy:I.text("Copy"),download:I.text("Download")}),...(ngDevMode?[{debugName:"labels"}]:([])));description=M(()=>I.text(Yb[this.store.outputKind()]),...(ngDevMode?[{debugName:"description"}]:([])));language=M(()=>Jb[this.store.outputKind()],...(ngDevMode?[{debugName:"language"}]:([])));onKind(e){this.store.outputKind.set(e)}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Gi,deps:[],target:w.ɵɵFactoryTarget.Component});static ɵcmp=w.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"21.2.21",type:Gi,isStandalone:true,selector:"rbe-output",ngImport:w,template:`
467
+ <editor-output
468
+ [kinds]="options()"
469
+ [kind]="store.outputKind()"
470
+ [labels]="labels()"
471
+ [description]="description()"
472
+ [language]="language()"
473
+ [text]="store.output()"
474
+ copyIcon="rbe:copy"
475
+ downloadIcon="rbe:download"
476
+ (kindChange)="onKind($event)"
477
+ (copyPressed)="store.copyOutput()"
478
+ (downloadPressed)="store.downloadOutput()" />
479
+ `,isInline:true,styles:[":host{display:block;height:100%;min-height:0}\n"],dependencies:[{kind:"component",type:Et,selector:"editor-output",inputs:["kinds","kind","labels","description","language","text","copyIcon","downloadIcon"],outputs:["kindChange","copyPressed","downloadPressed"]}]})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Gi,decorators:[{type:me,args:[{selector:"rbe-output",standalone:true,imports:[Et],template:`
480
+ <editor-output
481
+ [kinds]="options()"
482
+ [kind]="store.outputKind()"
483
+ [labels]="labels()"
484
+ [description]="description()"
485
+ [language]="language()"
486
+ [text]="store.output()"
487
+ copyIcon="rbe:copy"
488
+ downloadIcon="rbe:download"
489
+ (kindChange)="onKind($event)"
490
+ (copyPressed)="store.copyOutput()"
491
+ (downloadPressed)="store.downloadOutput()" />
492
+ `,styles:[":host{display:block;height:100%;min-height:0}\n"]}]}]});class Bi{store=L(Ze);texts=I;severities=E(["error","warning","info"],...(ngDevMode?[{debugName:"severities"}]:([])));tools=[{type:"severity",severity:"error"},{type:"severity",severity:"warning"},{type:"severity",severity:"info"},{type:"filter"},{type:"spacer"}];open(e){this.store.openProblem(e)}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Bi,deps:[],target:w.ɵɵFactoryTarget.Component});static ɵcmp=w.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"21.2.21",type:Bi,isStandalone:true,selector:"rbe-problems",ngImport:w,template:` <gfy-problem-list [problems]="store.problems()" [tools]="tools" [(severities)]="severities" [ariaLabel]="texts.text('Problems')" [emptyText]="texts.text('No problems found.')" (problemActivated)="open($event)" /> `,isInline:true,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n","gfy-problem-list{flex:1 1 auto;min-height:0}\n"],dependencies:[{kind:"component",type:_n,selector:"gfy-problem-list",inputs:["problems","columns","columnTitles","tools","toolbar","toolbarPosition","severities","filter","selected","ariaLabel","emptyText"],outputs:["severitiesChange","filterChange","selectedChange","problemActivated","toolUsed"]}]})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Bi,decorators:[{type:me,args:[{selector:"rbe-problems",standalone:true,imports:[_n],template:` <gfy-problem-list [problems]="store.problems()" [tools]="tools" [(severities)]="severities" [ariaLabel]="texts.text('Problems')" [emptyText]="texts.text('No problems found.')" (problemActivated)="open($event)" /> `,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n","gfy-problem-list{flex:1 1 auto;min-height:0}\n"]}]}]});const Xb={buttons:"Buttons",menus:"Menus and pickers",toggles:"Toggles and choices",fields:"Fields",display:"Display"};const Zb={type:ei,label:"Control of the application",description:"A control that the application registers under a name of its own: write the name in the Inspector (typeName). The editor draws a placeholder for it.",icon:"rbe:item"};class Vi{store=L(Ze);texts=I;groups=M(()=>[..._f.map(e=>({group:e,label:I.text(Xb[e]),controls:Xo.filter(t=>t.group===e).map(t=>({type:t.type,label:t.label,description:t.description,icon:ti(t.type)}))})).filter(e=>e.controls.length>0),{group:"application",label:I.text("Of the application"),controls:[Zb]}],...(ngDevMode?[{debugName:"groups"}]:([])));add(e){this.store.addItem(e.type)}onDragStart(e,t){if(!e.dataTransfer)return;e.dataTransfer.setData(Fa,t.type);e.dataTransfer.setData("text/plain",t.type);e.dataTransfer.effectAllowed="copy";this.store.dragType.set(t.type)}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Vi,deps:[],target:w.ɵɵFactoryTarget.Component});static ɵcmp=w.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"21.2.21",type:Vi,isStandalone:true,selector:"rbe-toolbox",ngImport:w,template:`
493
+ <div class="hint">
494
+ {{ texts.text('Click a control to add it to the selected section, or drag it onto the Editor. The control of an item is the one it is added as. The entries of a menu are added by Add choice (the context menu, the Outline).') }}
495
+ </div>
496
+ <div class="scroll">
497
+ <gfy-accordion [ariaLabel]="texts.text('Controls')" multiple>
498
+ @for (group of groups(); track group.group) {
499
+ <gfy-expander [heading]="group.label" [expanded]="true" appearance="plain">
500
+ @for (entry of group.controls; track entry.type) {
501
+ <div
502
+ class="control"
503
+ role="button"
504
+ tabindex="0"
505
+ draggable="true"
506
+ [attr.title]="entry.type + ': ' + texts.text(entry.description)"
507
+ (click)="add(entry)"
508
+ (keydown.enter)="add(entry)"
509
+ (keydown.space)="add(entry); $event.preventDefault()"
510
+ (dragstart)="onDragStart($event, entry)"
511
+ (dragend)="store.dragType.set(null)">
512
+ <span class="ic" [gfyIcon]="entry.icon"></span>
513
+ <span class="name">{{ texts.text(entry.label) }}</span>
514
+ <span class="type">{{ entry.type }}</span>
515
+ </div>
516
+ }
517
+ </gfy-expander>
518
+ }
519
+ </gfy-accordion>
520
+ </div>
521
+ `,isInline:true,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n",".ic{flex:none;display:grid;width:var(--ic, 14px);height:var(--ic, 14px)}\n",".scroll{flex:1 1 auto;min-height:0;overflow:auto;padding:4px 6px 8px;container:toolbox/inline-size}.control{display:flex;align-items:center;gap:8px;padding:4px 8px;border-radius:var(--gfy-radius, 4px);cursor:grab;-webkit-user-select:none;user-select:none}.control:hover{background:color-mix(in srgb,var(--gfy-accent, #3a8fd6) 11%,transparent)}.control:focus-visible{outline:2px solid var(--gfy-accent, #3a8fd6);outline-offset:-2px}.control .ic{--ic: 16px;color:var(--gfy-accent, #3a8fd6)}.control .name{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.control .type{flex:0 100 auto;min-width:0;margin-left:auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font:11px var(--gfy-font-mono, Consolas, monospace);opacity:.88}@container toolbox (max-width: 270px){.control .type{display:none}}\n"],dependencies:[{kind:"component",type:gr,selector:"gfy-accordion",inputs:["multiple","layout","ariaLabel"]},{kind:"component",type:Yt,selector:"gfy-expander",inputs:["heading","description","icon","expanded","disabled","appearance","chevronAt","level","keepContent"],outputs:["expandedChange"]},{kind:"directive",type:mt,selector:"[gfyIcon]",inputs:["gfyIcon"]}]})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Vi,decorators:[{type:me,args:[{selector:"rbe-toolbox",standalone:true,imports:[gr,Yt,mt],template:`
522
+ <div class="hint">
523
+ {{ texts.text('Click a control to add it to the selected section, or drag it onto the Editor. The control of an item is the one it is added as. The entries of a menu are added by Add choice (the context menu, the Outline).') }}
524
+ </div>
525
+ <div class="scroll">
526
+ <gfy-accordion [ariaLabel]="texts.text('Controls')" multiple>
527
+ @for (group of groups(); track group.group) {
528
+ <gfy-expander [heading]="group.label" [expanded]="true" appearance="plain">
529
+ @for (entry of group.controls; track entry.type) {
530
+ <div
531
+ class="control"
532
+ role="button"
533
+ tabindex="0"
534
+ draggable="true"
535
+ [attr.title]="entry.type + ': ' + texts.text(entry.description)"
536
+ (click)="add(entry)"
537
+ (keydown.enter)="add(entry)"
538
+ (keydown.space)="add(entry); $event.preventDefault()"
539
+ (dragstart)="onDragStart($event, entry)"
540
+ (dragend)="store.dragType.set(null)">
541
+ <span class="ic" [gfyIcon]="entry.icon"></span>
542
+ <span class="name">{{ texts.text(entry.label) }}</span>
543
+ <span class="type">{{ entry.type }}</span>
544
+ </div>
545
+ }
546
+ </gfy-expander>
547
+ }
548
+ </gfy-accordion>
549
+ </div>
550
+ `,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n",".ic{flex:none;display:grid;width:var(--ic, 14px);height:var(--ic, 14px)}\n",".scroll{flex:1 1 auto;min-height:0;overflow:auto;padding:4px 6px 8px;container:toolbox/inline-size}.control{display:flex;align-items:center;gap:8px;padding:4px 8px;border-radius:var(--gfy-radius, 4px);cursor:grab;-webkit-user-select:none;user-select:none}.control:hover{background:color-mix(in srgb,var(--gfy-accent, #3a8fd6) 11%,transparent)}.control:focus-visible{outline:2px solid var(--gfy-accent, #3a8fd6);outline-offset:-2px}.control .ic{--ic: 16px;color:var(--gfy-accent, #3a8fd6)}.control .name{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.control .type{flex:0 100 auto;min-width:0;margin-left:auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font:11px var(--gfy-font-mono, Consolas, monospace);opacity:.88}@container toolbox (max-width: 270px){.control .type{display:none}}\n"]}]}]});const C={lead:n=>({kind:"lead",text:n}),text:n=>({kind:"text",text:n}),heading:n=>({kind:"heading",text:n}),note:n=>({kind:"note",text:n}),points:n=>({kind:"points",items:n}),steps:n=>({kind:"steps",items:n}),terms:n=>({kind:"terms",items:n}),keys:n=>({kind:"keys",items:n}),code:(n,e)=>({kind:"code",language:n,code:e})};const Qb=/* @__PURE__ */new Map([["ctrl","⌘"],["alt","⌥"],["shift","⇧"],["up","↑"],["down","↓"],["left","←"],["right","→"],["enter","↩"],["backspace","⌫"],["delete","⌦"]]);const ey=/`([^`]+)`|\[([^\]]+)\]|\*([^*]+)\*/g;function ty(n,e=false){const t=[];let o=0;for(const i of n.matchAll(ey)){if(i.index>o)t.push({kind:"text",text:n.slice(o,i.index),keys:[]});const[r,s,a,l]=i;if(s!==void 0)t.push({kind:"code",text:s,keys:[]});else if(a!==void 0)t.push({kind:"keys",text:a,keys:a.split(/\+(?=.)/).map(d=>e?Qb.get(d.trim().toLowerCase())??d.trim():d.trim())});else t.push({kind:"strong",text:l.replaceAll(" > "," › "),keys:[]});o=i.index+r.length}if(o<n.length)t.push({kind:"text",text:n.slice(o),keys:[]});return t}const ny=()=>dc("Mod+K").startsWith("⌘");function oy(n,e=false){const t=o=>ty(o,e);return n.blocks.map(o=>{const i={kind:o.kind,spans:[],items:[],code:"",language:""};switch(o.kind){case"points":return{...i,items:o.items.map(r=>({name:[],spans:t(r)}))};case"steps":case"terms":case"keys":return{...i,items:o.items.map(([r,s])=>({name:t(r),spans:t(s)}))};case"code":return{...i,code:o.code,language:o.language};default:return{...i,spans:t(o.text)}}})}class Ro{spans=we.required(...(ngDevMode?[{debugName:"spans"}]:([])));static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Ro,deps:[],target:w.ɵɵFactoryTarget.Component});static ɵcmp=w.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"21.2.21",type:Ro,isStandalone:true,selector:"editor-help-text",inputs:{spans:{classPropertyName:"spans",publicName:"spans",isSignal:true,isRequired:true,transformFunction:null}},ngImport:w,template:`@for (span of spans(); track $index) {
551
+ @switch (span.kind) {
552
+ @case ('keys') {
553
+ <span class="keys">
554
+ @for (key of span.keys; track $index) {
555
+ @if (!$first) {
556
+ <span class="plus" aria-hidden="true">+</span>
557
+ }
558
+ <kbd>{{ key }}</kbd>
559
+ }
560
+ </span>
561
+ }
562
+ @case ('strong') {
563
+ <strong [class.path]="span.text.includes(' › ')">{{ span.text }}</strong>
564
+ }
565
+ @case ('code') {
566
+ <code>{{ span.text }}</code>
567
+ }
568
+ @default {
569
+ <ng-container>{{ span.text }}</ng-container>
570
+ }
571
+ }
572
+ }`,isInline:true,styles:[".keys{white-space:nowrap}kbd{display:inline-block;box-sizing:border-box;min-width:1.75em;padding:0 .45em;border:1px solid var(--gfy-border-color, rgba(128, 128, 128, .45));border-bottom-width:2px;border-radius:4px;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:600 11px/1.55 var(--gfy-font-main, system-ui, sans-serif);text-align:center;vertical-align:1px}.plus{margin:0 2px;opacity:.88}strong{font-weight:600}.path,code{white-space:nowrap}code{padding:0 3px;border-radius:3px;background:color-mix(in srgb,var(--gfy-text-main) 9%,transparent);font:12px/1.4 var(--gfy-font-mono, ui-monospace, Consolas, monospace)}\n"],changeDetection:w.ChangeDetectionStrategy.OnPush})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Ro,decorators:[{type:me,args:[{selector:"editor-help-text",standalone:true,changeDetection:fn.OnPush,template:`@for (span of spans(); track $index) {
573
+ @switch (span.kind) {
574
+ @case ('keys') {
575
+ <span class="keys">
576
+ @for (key of span.keys; track $index) {
577
+ @if (!$first) {
578
+ <span class="plus" aria-hidden="true">+</span>
579
+ }
580
+ <kbd>{{ key }}</kbd>
581
+ }
582
+ </span>
583
+ }
584
+ @case ('strong') {
585
+ <strong [class.path]="span.text.includes(' › ')">{{ span.text }}</strong>
586
+ }
587
+ @case ('code') {
588
+ <code>{{ span.text }}</code>
589
+ }
590
+ @default {
591
+ <ng-container>{{ span.text }}</ng-container>
592
+ }
593
+ }
594
+ }`,styles:[".keys{white-space:nowrap}kbd{display:inline-block;box-sizing:border-box;min-width:1.75em;padding:0 .45em;border:1px solid var(--gfy-border-color, rgba(128, 128, 128, .45));border-bottom-width:2px;border-radius:4px;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:600 11px/1.55 var(--gfy-font-main, system-ui, sans-serif);text-align:center;vertical-align:1px}.plus{margin:0 2px;opacity:.88}strong{font-weight:600}.path,code{white-space:nowrap}code{padding:0 3px;border-radius:3px;background:color-mix(in srgb,var(--gfy-text-main) 9%,transparent);font:12px/1.4 var(--gfy-font-mono, ui-monospace, Consolas, monospace)}\n"]}]}],propDecorators:{spans:[{type:w.Input,args:[{isSignal:true,alias:"spans",required:true}]}]}});class Hi{help=we.required(...(ngDevMode?[{debugName:"help"}]:([])));page=Ls("",...(ngDevMode?[{debugName:"page"}]:([])));injector=L(Fs);article=ct.required("page");nav=ct.required(Ko);mac=ny();entries=M(()=>this.help().pages.map(e=>({id:e.id,label:e.title,icon:e.icon})),...(ngDevMode?[{debugName:"entries"}]:([])));current=M(()=>this.help().pages.find(e=>e.id===this.page())??this.help().pages.at(0),...(ngDevMode?[{debugName:"current"}]:([])));blocks=M(()=>{const e=this.current();return e?oy(e,this.mac):[]},...(ngDevMode?[{debugName:"blocks"}]:([])));show(e,t=false){this.page.set(e);this.article().nativeElement.scrollTop=0;if(t)ur(()=>this.nav().focusCurrent(),{injector:this.injector})}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Hi,deps:[],target:w.ɵɵFactoryTarget.Component});static ɵcmp=w.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"21.2.21",type:Hi,isStandalone:true,selector:"editor-help",inputs:{help:{classPropertyName:"help",publicName:"help",isSignal:true,isRequired:true,transformFunction:null},page:{classPropertyName:"page",publicName:"page",isSignal:true,isRequired:false,transformFunction:null}},outputs:{page:"pageChange"},viewQueries:[{propertyName:"article",first:true,predicate:["page"],descendants:true,isSignal:true},{propertyName:"nav",first:true,predicate:Ko,descendants:true,isSignal:true}],ngImport:w,template:`
595
+ <gfy-nav-list class="pages" ariaLabel="The pages of the help" ariaCurrent="page" [items]="entries()" [selected]="current()?.id ?? null" (itemInvoked)="show($event.id)" />
596
+ <article #page class="page" tabindex="0" [attr.aria-label]="current()?.title">
597
+ <div class="content">
598
+ <h3>{{ current()?.title }}</h3>
599
+ @for (block of blocks(); track $index) {
600
+ @switch (block.kind) {
601
+ @case ('lead') {
602
+ <p class="lead"><editor-help-text [spans]="block.spans" /></p>
603
+ }
604
+ @case ('heading') {
605
+ <h4><editor-help-text [spans]="block.spans" /></h4>
606
+ }
607
+ @case ('note') {
608
+ <p class="note"><editor-help-text [spans]="block.spans" /></p>
609
+ }
610
+ @case ('points') {
611
+ <ul>
612
+ @for (item of block.items; track $index) {
613
+ <li><editor-help-text [spans]="item.spans" /></li>
614
+ }
615
+ </ul>
616
+ }
617
+ @case ('steps') {
618
+ <ol>
619
+ @for (item of block.items; track $index) {
620
+ <li>
621
+ <div class="step-title"><editor-help-text [spans]="item.name" /></div>
622
+ <div><editor-help-text [spans]="item.spans" /></div>
623
+ </li>
624
+ }
625
+ </ol>
626
+ }
627
+ @case ('terms') {
628
+ <dl>
629
+ @for (item of block.items; track $index) {
630
+ <dt><editor-help-text [spans]="item.name" /></dt>
631
+ <dd><editor-help-text [spans]="item.spans" /></dd>
632
+ }
633
+ </dl>
634
+ }
635
+ @case ('keys') {
636
+ <table>
637
+ <tbody>
638
+ @for (item of block.items; track $index) {
639
+ <tr>
640
+ <th scope="row"><editor-help-text [spans]="item.name" /></th>
641
+ <td><editor-help-text [spans]="item.spans" /></td>
642
+ </tr>
643
+ }
644
+ </tbody>
645
+ </table>
646
+ }
647
+ @case ('code') {
648
+ <gfy-code-block [language]="block.language" [code]="block.code" />
649
+ }
650
+ @default {
651
+ <p><editor-help-text [spans]="block.spans" /></p>
652
+ }
653
+ }
654
+ }
655
+ </div>
656
+ </article>
657
+ `,isInline:true,styles:[":host{--help-line: var(--gfy-border-color, rgba(128, 128, 128, .3));--help-muted: color-mix(in srgb, var(--gfy-text-main) 72%, transparent);display:grid;grid-template-columns:188px minmax(0,1fr);min-height:0;color:var(--gfy-text-main);font:13px/1.5 var(--gfy-font-main, system-ui, sans-serif)}.pages{overflow:auto;padding-right:12px;border-right:1px solid var(--help-line)}.page{overflow:auto;min-height:0;padding:0 8px 8px 24px;outline:none}.page:focus-visible{box-shadow:inset 0 0 0 2px var(--gfy-accent)}.content{max-width:680px}h3{margin:2px 0 10px;font-size:19px;font-weight:600;line-height:1.3}h4{margin:22px 0 8px;font-size:14px;font-weight:600}p{margin:0 0 10px}.lead{font-size:14px;line-height:1.55}.note{margin:16px 0;padding:8px 12px;border-left:3px solid var(--gfy-accent);border-radius:0 4px 4px 0;background:color-mix(in srgb,var(--gfy-accent) 9%,transparent)}ul{margin:0 0 12px;padding-left:20px}ul>li+li{margin-top:6px}ol{display:grid;gap:12px;margin:14px 0;padding:0;list-style:none;counter-reset:step}ol>li{display:grid;grid-template-columns:24px minmax(0,1fr);column-gap:12px;counter-increment:step}ol>li:before{content:counter(step);grid-row:span 2;display:grid;place-items:center;width:24px;height:24px;border-radius:50%;background:var(--gfy-accent);color:var(--gfy-accent-contrast, #fff);font-size:12px;font-weight:600}.step-title{font-weight:600;line-height:24px}dl{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:6px 18px;margin:0 0 12px}dt{font-weight:600}dd{margin:0}table{width:100%;margin:0 0 12px;border-collapse:collapse}th,td{padding:6px 0;text-align:left;vertical-align:top}th{width:40%;padding-right:16px;font-weight:400}tr+tr>*{border-top:1px solid var(--help-line)}gfy-code-block{display:block;margin:0 0 12px}@media(max-width:560px){:host{grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr)}.pages{padding:0 0 8px;border-right:0;border-bottom:1px solid var(--help-line)}.page{padding:12px 4px 8px}}\n"],dependencies:[{kind:"component",type:Ro,selector:"editor-help-text",inputs:["spans"]},{kind:"component",type:pc,selector:"gfy-code-block",inputs:["code","language","candidates","tokenColors","lineNumbers","firstLine","showCopy","heading","ariaLabel","wrap","links","linkTitle"],outputs:["copied","languageDetected","linkActivated"]},{kind:"component",type:Ko,selector:"gfy-nav-list",inputs:["items","selected","label","ariaLabel","appearance","ariaCurrent"],outputs:["selectedChange","itemInvoked"]}],changeDetection:w.ChangeDetectionStrategy.OnPush})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Hi,decorators:[{type:me,args:[{selector:"editor-help",standalone:true,imports:[Ro,pc,Ko],changeDetection:fn.OnPush,template:`
658
+ <gfy-nav-list class="pages" ariaLabel="The pages of the help" ariaCurrent="page" [items]="entries()" [selected]="current()?.id ?? null" (itemInvoked)="show($event.id)" />
659
+ <article #page class="page" tabindex="0" [attr.aria-label]="current()?.title">
660
+ <div class="content">
661
+ <h3>{{ current()?.title }}</h3>
662
+ @for (block of blocks(); track $index) {
663
+ @switch (block.kind) {
664
+ @case ('lead') {
665
+ <p class="lead"><editor-help-text [spans]="block.spans" /></p>
666
+ }
667
+ @case ('heading') {
668
+ <h4><editor-help-text [spans]="block.spans" /></h4>
669
+ }
670
+ @case ('note') {
671
+ <p class="note"><editor-help-text [spans]="block.spans" /></p>
672
+ }
673
+ @case ('points') {
674
+ <ul>
675
+ @for (item of block.items; track $index) {
676
+ <li><editor-help-text [spans]="item.spans" /></li>
677
+ }
678
+ </ul>
679
+ }
680
+ @case ('steps') {
681
+ <ol>
682
+ @for (item of block.items; track $index) {
683
+ <li>
684
+ <div class="step-title"><editor-help-text [spans]="item.name" /></div>
685
+ <div><editor-help-text [spans]="item.spans" /></div>
686
+ </li>
687
+ }
688
+ </ol>
689
+ }
690
+ @case ('terms') {
691
+ <dl>
692
+ @for (item of block.items; track $index) {
693
+ <dt><editor-help-text [spans]="item.name" /></dt>
694
+ <dd><editor-help-text [spans]="item.spans" /></dd>
695
+ }
696
+ </dl>
697
+ }
698
+ @case ('keys') {
699
+ <table>
700
+ <tbody>
701
+ @for (item of block.items; track $index) {
702
+ <tr>
703
+ <th scope="row"><editor-help-text [spans]="item.name" /></th>
704
+ <td><editor-help-text [spans]="item.spans" /></td>
705
+ </tr>
706
+ }
707
+ </tbody>
708
+ </table>
709
+ }
710
+ @case ('code') {
711
+ <gfy-code-block [language]="block.language" [code]="block.code" />
712
+ }
713
+ @default {
714
+ <p><editor-help-text [spans]="block.spans" /></p>
715
+ }
716
+ }
717
+ }
718
+ </div>
719
+ </article>
720
+ `,styles:[":host{--help-line: var(--gfy-border-color, rgba(128, 128, 128, .3));--help-muted: color-mix(in srgb, var(--gfy-text-main) 72%, transparent);display:grid;grid-template-columns:188px minmax(0,1fr);min-height:0;color:var(--gfy-text-main);font:13px/1.5 var(--gfy-font-main, system-ui, sans-serif)}.pages{overflow:auto;padding-right:12px;border-right:1px solid var(--help-line)}.page{overflow:auto;min-height:0;padding:0 8px 8px 24px;outline:none}.page:focus-visible{box-shadow:inset 0 0 0 2px var(--gfy-accent)}.content{max-width:680px}h3{margin:2px 0 10px;font-size:19px;font-weight:600;line-height:1.3}h4{margin:22px 0 8px;font-size:14px;font-weight:600}p{margin:0 0 10px}.lead{font-size:14px;line-height:1.55}.note{margin:16px 0;padding:8px 12px;border-left:3px solid var(--gfy-accent);border-radius:0 4px 4px 0;background:color-mix(in srgb,var(--gfy-accent) 9%,transparent)}ul{margin:0 0 12px;padding-left:20px}ul>li+li{margin-top:6px}ol{display:grid;gap:12px;margin:14px 0;padding:0;list-style:none;counter-reset:step}ol>li{display:grid;grid-template-columns:24px minmax(0,1fr);column-gap:12px;counter-increment:step}ol>li:before{content:counter(step);grid-row:span 2;display:grid;place-items:center;width:24px;height:24px;border-radius:50%;background:var(--gfy-accent);color:var(--gfy-accent-contrast, #fff);font-size:12px;font-weight:600}.step-title{font-weight:600;line-height:24px}dl{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:6px 18px;margin:0 0 12px}dt{font-weight:600}dd{margin:0}table{width:100%;margin:0 0 12px;border-collapse:collapse}th,td{padding:6px 0;text-align:left;vertical-align:top}th{width:40%;padding-right:16px;font-weight:400}tr+tr>*{border-top:1px solid var(--help-line)}gfy-code-block{display:block;margin:0 0 12px}@media(max-width:560px){:host{grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr)}.pages{padding:0 0 8px;border-right:0;border-bottom:1px solid var(--help-line)}.page{padding:12px 4px 8px}}\n"]}]}],propDecorators:{help:[{type:w.Input,args:[{isSignal:true,alias:"help",required:true}]}],page:[{type:w.Input,args:[{isSignal:true,alias:"page",required:false}]},{type:w.Output,args:["pageChange"]}],article:[{type:w.ViewChild,args:["page",{isSignal:true}]}],nav:[{type:w.ViewChild,args:[w.forwardRef(()=>Ko),{isSignal:true}]}]}});function iy(n,e,t){const o=n.get(e.id);if(o?.isOpen()&&o.instance){o.instance.show(t,true);o.bringToFront();return o}return n.open({id:e.id,title:`${e.editor} help`,component:Hi,inputs:{help:e,page:t},modal:false,closeOnEscape:true,resizable:true,fill:true,width:"min(880px, 94vw)",height:"min(640px, 86vh)",minWidth:320,minHeight:260,autoFocus:"gfy-nav-list [aria-current]"})}function Va(n){const e=L(Ws);L(lt).onDestroy(()=>e.close(n.id));const t=o=>void iy(e,n,o);return{open:t,items:n.pages.map(o=>({label:`&${o.title}…`,icon:o.icon,run:()=>t(o.id)}))}}const ry=`// files-server.mjs: the files of a project for the editors of Gridify.
721
+ // A tool for development, on this computer only:
722
+ // node files-server.mjs src/assets
723
+ // and in Gridify Designer: Files > A server…, http://localhost:4300/files
724
+ import {createHash} from 'node:crypto';
725
+ import {existsSync, readdirSync, readFileSync, realpathSync, statSync,
726
+ writeFileSync} from 'node:fs';
727
+ import {createServer} from 'node:http';
728
+ import {basename, dirname, join, resolve, sep} from 'node:path';
729
+
730
+ const root = realpathSync(resolve(process.argv[2] ?? '.'));
731
+ const port = 4300;
732
+ const designer = 'http://localhost:4202'; // the page with the editors
733
+ const hidden = name => name.startsWith('.') || name === 'node_modules';
734
+ const isJson = name => name.toLowerCase().endsWith('.json');
735
+ const etagOf = text =>
736
+ \`"\${createHash('sha256').update(text).digest('base64url')}"\`;
737
+ const JSON_TYPE = {'Content-Type': 'application/json'};
738
+
739
+ /** The real place of a path (links followed): inside the folder, nothing
740
+ * hidden on the way, and a file is a .json file. */
741
+ function placeOf(path, file) {
742
+ const names = path === '' ? [] : path.split('/');
743
+ if (names.some(name => name === '' || name.includes('\\\\') || hidden(name)))
744
+ throw [400, \`"\${path}" is not a path of the project.\`];
745
+ const place = join(root, ...names);
746
+ const real = existsSync(place)
747
+ ? realpathSync(place)
748
+ : join(realpathSync(dirname(place)), basename(place));
749
+ const inside = real === root || (real.startsWith(root + sep)
750
+ && !real.slice(root.length + 1).split(sep).some(hidden));
751
+ if (!inside || (file && !isJson(real)))
752
+ throw [403, \`\${path} is not shown.\`];
753
+ return real;
754
+ }
755
+
756
+ /** What is in a folder: its folders and .json files (none that leads out). */
757
+ function list(path) {
758
+ return readdirSync(placeOf(path, false)).flatMap(name => {
759
+ try {
760
+ const real = placeOf(path === '' ? name : \`\${path}/\${name}\`, false);
761
+ if (statSync(real).isDirectory()) return [{name, kind: 'folder'}];
762
+ return isJson(name) && isJson(real) ? [{name, kind: 'file'}] : [];
763
+ } catch {
764
+ return []; // hidden, outside, or a link that leads nowhere
765
+ }
766
+ });
767
+ }
768
+
769
+ async function handle(request, url) {
770
+ const path = url.searchParams.get('path') ?? '';
771
+ const route = \`\${request.method} \${url.pathname}\`;
772
+ if (route === 'GET /files/list')
773
+ return [200, JSON.stringify(list(path)), JSON_TYPE];
774
+ if (route === 'GET /files/file') {
775
+ const text = readFileSync(placeOf(path, true), 'utf8');
776
+ return [200, text, {...JSON_TYPE, ETag: etagOf(text)}];
777
+ }
778
+ if (route === 'PUT /files/file') {
779
+ const place = placeOf(path, true);
780
+ let text = '';
781
+ request.setEncoding('utf8');
782
+ for await (const part of request) text += part;
783
+ JSON.parse(text); // only JSON is written
784
+ const there = existsSync(place) ? readFileSync(place, 'utf8') : null;
785
+ // Save sends the version it read (If-Match), a new file
786
+ // If-None-Match: *. Another version is not written over: 412,
787
+ // and the editor asks the user.
788
+ const ifMatch = request.headers['if-match'];
789
+ const ifNone = request.headers['if-none-match'];
790
+ if ((there !== null && ifNone === '*') || (ifMatch !== undefined
791
+ && (there === null || etagOf(there) !== ifMatch)))
792
+ return [412, \`\${path} is not the version that was read.\`];
793
+ // wx: a new file only where nothing is, not even a link
794
+ writeFileSync(place, text, {flag: there === null ? 'wx' : 'w'});
795
+ return [there === null ? 201 : 200, '', {ETag: etagOf(text)}];
796
+ }
797
+ return [404, 'The API is /files/list and /files/file.'];
798
+ }
799
+
800
+ createServer(async (request, response) => {
801
+ const answer = (status, body = '', headers = {}) => {
802
+ response.writeHead(status, {
803
+ 'Content-Type': 'text/plain; charset=utf-8', ...headers});
804
+ response.end(body);
805
+ };
806
+ // only this computer by its own name, and only the page with the editors
807
+ const host = request.headers.host;
808
+ if (host !== \`localhost:\${port}\` && host !== \`127.0.0.1:\${port}\`)
809
+ return answer(421, 'Ask for localhost.');
810
+ const origin = request.headers.origin;
811
+ if (origin !== undefined && origin !== designer)
812
+ return answer(403, \`\${origin} is not allowed.\`);
813
+ if (origin !== undefined) {
814
+ response.setHeader('Access-Control-Allow-Origin', origin);
815
+ response.setHeader('Access-Control-Expose-Headers', 'ETag');
816
+ }
817
+ if (request.method === 'OPTIONS')
818
+ return answer(204, '', {
819
+ 'Access-Control-Allow-Methods': 'GET, PUT',
820
+ 'Access-Control-Allow-Headers':
821
+ 'Content-Type, If-Match, If-None-Match',
822
+ });
823
+ try {
824
+ const url = new URL(request.url, \`http://\${host}\`);
825
+ answer(...(await handle(request, url)));
826
+ } catch (error) {
827
+ if (Array.isArray(error)) return answer(...error);
828
+ if (error instanceof SyntaxError)
829
+ return answer(400, 'Only JSON is written.');
830
+ if (error.code === 'ENOENT') return answer(404, 'It is not there.');
831
+ if (error.code === 'EEXIST')
832
+ return answer(412, 'There is a file already.');
833
+ console.error(error);
834
+ answer(500, 'The server failed: see its console.');
835
+ }
836
+ }).listen(port, '127.0.0.1',
837
+ () => console.log(\`http://localhost:\${port}/files\`));`;function Ha({icon:n,noun:e,component:t,selector:o}){return{id:"files",title:"Files",icon:n,blocks:[C.lead(`The editor can open and save the files of your project itself: the layouts, forms and ribbons in the assets of your application, with no download in between. Where they are is chosen by the application that shows the editor: in Gridify Designer it is *Files* in the header. Until a place is chosen nothing of it is on, and the editor opens a file of the computer and offers the ${e} for download.`),C.heading("The choices"),C.terms([["Off",`*File > Open file…* reads a file of the computer, and *File > Download the file* gives the ${e} as a new file. It works in every browser, but a browser cannot write into a file it opened: the download lands among the downloads, and you copy it into your project yourself.`],["A folder of this computer","The browser asks for a folder (choose the assets of your application) and for the permission to read and write it. Save writes straight into your project, and there is nothing to start. After a reload the browser asks for the permission again, at the first Open or Save."],["A server","The address of an API that keeps the files (`http://localhost:4300/files`). It works in every browser, the files can be wherever the server reaches, and the server can check what it writes. The repository of Gridify has one for a folder of your computer, and you can write your own (below)."]]),C.note("Which one? In Chrome or Edge on your own computer a folder is the quickest: nothing to start, and the files are written where your application reads them. A server is for Firefox and Safari, for files on another computer, and for a check of your own before a file is written (a schema, a formatter, git)."),C.heading("What the File menu gets"),C.points(["*File > Open from the project…* ([Ctrl+O]) shows the folders of the place and the `.json` files in them.",`*File > Save* ([Ctrl+S]) writes the ${e} back into the file it came from. The title in the middle of the menu bar names that file, with a dot while there are changes that were not saved.`,"Save asks first when the file was changed in the meantime (in another window, by git, by a colleague): *Overwrite*, or *Cancel* and nothing is written.",`A ${e} that is in no file yet (a new one, a sample, the clipboard, a file of the computer) asks where it goes, as *File > Save as…* ([Ctrl+Shift+S]) does.`,"*File > Open file…* and *File > Download the file* stay: a download is a copy, and Save still writes the file of the project."]),C.heading("Browsers"),C.terms([["Chrome, Edge, Opera","All three choices: a folder of this computer on a page from `https://` or `http://localhost` (the File System Access API)."],["Brave","Off and a server: Brave turns the File System Access API off (`brave://flags/#file-system-access-api` turns it on)."],["Firefox, Safari","Off and a server: they have no File System Access API, so *A folder of this computer* is grey."]]),C.heading("A server of your own"),C.text("Any server can keep the files, in any language: the editors send it three requests. `<url>` is the address that *Files > A server…* takes (in your own application, the `url` of `gfyHttpFiles`)."),C.terms([["`GET <url>/list?path=<folder>`","What is in a folder (`''` is the root): a JSON list of `{\"name\": \"main.json\", \"kind\": \"file\"}`, with `\"kind\": \"folder\"` for a folder."],["`GET <url>/file?path=<path>`","The text of the file, and its version in the header `ETag`."],["`PUT <url>/file?path=<path>`","Writes the text of the body, and answers `200` (or `201` for a new file) with the new `ETag`. With `If-Match: <version>` (Save) or `If-None-Match: *` (a new file) it answers `412` when the file is not that version, or is there already: the editor asks the user then."]]),C.text("What it has to allow, and what not:"),C.points(["The page of the editors when it has another address than the server (CORS): `Access-Control-Allow-Origin` with its address (`http://localhost:4202` for Gridify Designer), the methods `GET` and `PUT`, the headers `Content-Type`, `If-Match` and `If-None-Match`, and `Access-Control-Expose-Headers: ETag`. Without the last one the browser hides the version, and Save writes without the check.","Only the folder of the assets: no path with `..`, no name with a dot in front, no link that leads out of the folder; only `.json` files, and only JSON is written.","Only your computer: it listens on `127.0.0.1` and answers only a request for `localhost`. A server that writes files is a tool for development, not a server for the internet."]),C.text("A whole server in Node.js, with nothing to install: save it as `files-server.mjs` and start it with the folder of your assets. `designer` in it is the address of the page with the editors: change it when the page is elsewhere (on GitHub Pages `https://<user>.github.io`; the browser asks then for the access to the local network)."),C.code("js",ry),C.code("bash","node files-server.mjs src/assets"),C.note("The repository of Gridify has a fuller one: `npm run designer:files -- <folder>` (in the project of Gridify Designer `npm run files -- <folder>`), on `http://localhost:4300/files`; `--port` gives it another port, and `--origin` allows the page of another address."),C.heading("Connect it"),C.steps([["Start the server","With the folder of the assets of your application. It writes its address into the console."],["Choose it","In Gridify Designer: *Files > A server…*, type the address and press *Connect*. The designer lists the root folder first, and says what went wrong when it cannot (the server does not run, or does not allow the page)."],["Open and save","*File > Open from the project…* in any editor. This browser remembers the choice."]]),C.text(`In an application of your own that shows the editor (the package \`@gridify/editors\`), give it the place: \`gfyHttpFiles({url})\` for a server, \`gfyLocalFolderFiles(handle)\` for a folder.`),C.code("ts",`import {Component} from '@angular/core';
838
+ import {${t}, gfyHttpFiles} from '@gridify/editors';
839
+
840
+ @Component({
841
+ selector: 'app-editor-page',
842
+ imports: [${t}],
843
+ template: \`<${o} hosted [files]="files" />\`,
844
+ })
845
+ export class EditorPage {
846
+ readonly files = gfyHttpFiles({url: 'http://localhost:4300/files'});
847
+ }`),C.note("`headers` of `gfyHttpFiles` carries a token (`headers: () => ({Authorization: 'Bearer ' + token})`), and `credentials: 'include'` sends the cookies to a server of another address.")]}}const sy={id:"ribbon-editor:help",editor:"Ribbon editor",pages:[{id:"overview",title:"Overview",icon:"rbe:info",blocks:[C.lead("The Ribbon editor builds the ribbon of an application: its tabs, the sections in them and the controls in the sections (buttons, menus, galleries, check boxes and more), on a grid of cells. It saves a file; your application loads it, `<gfy-ribbon>` shows it, and your code reacts to the action of each item."),C.heading("What it is good for"),C.points(["*A ribbon you can see.* The Editor draws it as your application will, and in the Preview its menus open and its buttons respond.","*The behavior stays in your code.* An item has an `action`, and `(action)` of the ribbon tells which one was chosen. Signals of your application can drive the states: `disabled`, `checked`, `hidden`, a label.","*Mistakes found early.* The *Problems* window tells a duplicate `id`, two items on one cell, a shortcut used twice, an input that a control does not have."]),C.heading("What a file holds"),C.terms([["Tabs","The pages of the ribbon. A tab can be hidden by a signal of your application, and marked as contextual."],["Sections","The groups of a tab, each with a title. Their items stand on a grid of cells."],["Items","The controls: 18 built-in ones (a large button, a split button, a gallery, a color picker, a spinner, a combo box…) and controls of your application."],["Choices","The entries of a menu, a gallery, a select or a toggle group."],["Options","The inputs of `<gfy-ribbon>` that are not tabs (the rows, the width of a column, collapsing, the search box), in the *Ribbon Options* window."],["Code","JSON holds no functions: `{\"$fn\": \"percentText\"}`, `{\"$expr\": \"s.field('size', 11)\"}` and `{\"$bind\": \"noSelection\"}` name what your application registers when it loads the file. `t`, `tr`, `tx` and `tk` (`tr('Home')`) are the translations of the library: nothing to register."]]),C.heading("In your application"),C.text("`gfyLoadRibbon` reads the file and puts your functions and signals in. The *Output* window writes this code for the ribbon that is open (*Loader*), and a handler with a case for every action (*Handler*)."),C.code("ts","import {gfyLoadRibbon} from '@gridify/studio';\nimport ribbon from './ribbon.json';\n\nreadonly loaded = gfyLoadRibbon(ribbon, {functions: {percentText: this.percentText}, signals: {noSelection: this.noSelection}});\nreadonly tabs = this.loaded.tabs;"),C.code("html","<gfy-ribbon [tabs]=\"tabs\" (action)=\"onAction($event)\" />"),C.heading("The windows"),C.terms([["Outline","The tree of tabs, sections, items and choices. Its toolbar and its context menu add, duplicate, move and remove."],["Toolbox","The controls, in groups. A click adds one to the selected section, a drag puts it on a cell."],["Editor","The ribbon as your application draws it, with its grid: select, move and stretch the items here."],["Preview","The ribbon working: menus open, controls respond, and the status bar says which `action` your application would get."],["Inspector","The properties of the selected node, with their defaults and what they do."],["Ribbon Options","The inputs of `<gfy-ribbon>`, and the functions the file calls."],["Output","The file, the bare list of tabs, TypeScript, a handler for the actions, the template and the code that loads the file."],["Problems","What the reading changed, and what the check finds. A double click (or [Enter]) goes to its node."]]),C.heading("Good to know"),C.points(["The editor starts with an empty ribbon (Gridify Designer opens the sample of a text editor), and nothing is kept by itself: *File > Download the file* ([Ctrl+S]) saves the file, and with *File > Auto save* on the browser keeps it for the next visit.","An application that gives the editor the files of a project (*Files* in the header of Gridify Designer) adds *File > Open from the project…* ([Ctrl+O]), *Save* ([Ctrl+S]) and *Save as…* ([Ctrl+Shift+S]): Save writes the ribbon back into the file it came from, and asks first when that file was changed in the meantime. *Help > Files…* says how it works, and how to write a server of your own.","The title in the middle of the menu bar names the ribbon: its file of the project, or where it came from (*New ribbon*, *Sample: …*, the name of a file of this computer, *From the clipboard*), with a dot while it has changes that were not saved.","The `id` of an item is how your application finds it: keep it unique (the *Problems* window checks).","The controls do not react in the Editor, so they can be selected and dragged; try them in the *Preview*.","In the *Inspector* a value that starts with `=` is code of your application (`=tr('Home')`), and `=@name` binds a signal.","The windows are panels of a docking engine: drag a tab to move a window; *View > Reset the windows* puts them back."])]},{id:"start",title:"Getting started",icon:"rbe:flag",blocks:[C.lead("From an empty ribbon to the one in your application, in a few steps."),C.steps([["Start from something","*File > Samples* has a ribbon of a text editor with all 18 controls, and smaller ones. *File > Open file* ([Ctrl+O]) opens your own; a ribbon can also be pasted from the clipboard or dropped on the window, and a bare list of tabs (what `[tabs]` takes) is read too."],["Add tabs and sections","*Edit > Add tab* and *Edit > Add section*, the toolbar of the *Outline*, or a right click on a node."],["Add items","Click a control in the *Toolbox* to add it to the selected section, or drag it onto a free cell of the *Editor*."],["Arrange them","Drag an item to another cell, drag a handle to stretch it, or use the arrow keys (with [Shift] they stretch). A drop on the thin dashed line between two columns opens a new column."],["Set the properties","Select a node and fill in the *Inspector*: the label, the icon, the `action`, the shortcut, the key tip…"],["Fill the menus","*Add choice* (a right click on an item) adds an entry to a menu, a gallery or a select; where a menu takes them, separators, headings and blocks of menu items too."],["Try it","In the *Preview* the ribbon works: open its menus, press its buttons, and the status bar tells which `action` your application would get."],["Take it to your application","Download the file ([Ctrl+S]). The *Output* window has the code that loads it (*Loader*) and a handler for the actions (*Handler*); mend first what the *Problems* window lists."]]),C.note("While you drag, a dashed frame shows where the item goes; where it turns orange the item cannot go, and nothing changes.")]},{id:"guides",title:"How-to guides",icon:"rbe:guides",blocks:[C.lead("Short recipes for what a ribbon can do beyond the first steps. Each one names the windows and the rows of the *Inspector* it uses; the description under the grid of the Inspector says more about every row."),C.heading("Sections that shrink when the window gets narrow"),C.steps([["Turn shrinking on","Switch on `collapsible` in the *Ribbon Options* window. Only then has a section the rows about shrinking in the *Inspector*: `icon`, `compactColumns`, `collapsePriority` and `collapsible`."],["Say what goes first","`collapsePriority` of a section: a lower number shrinks first, and sections with the same number go from the right to the left."],["Give the items a smaller form","A section shrinks first: its items take their compact form (the rows `compact.type`, `compact.col`, `compact.inputs` of an item: a large button can become a small one, a button can show only its icon) and the section its `compactColumns`. A section without them skips this step."],["And then a button","When that is not enough, the section becomes a button with its title and its `icon` (without one, the icon of its first item), and a click opens the whole section. `collapsible` off keeps one section from becoming a button."],["Watch it","Give the *Preview* a narrower width in its toolbar (1000, 700, 480 or 320): the sections shrink and collapse in that order."]]),C.heading("A tab that appears only now and then"),C.steps([["Mark it","Select the tab and switch on `contextual` in the *Inspector*: the ribbon draws it in the color of a contextual tab (orange by default). That is the look only."],["Let your application show it","Bind its `hidden` to a signal: type `=@noPicture` in the row, or press *Bind the property to a signal of the application* in the head of the *Inspector*. Your application gives the signal when it loads the file (below)."]]),C.heading("Parts of the ribbon for some windows only"),C.text("`showForTags` of a tab, a section or an item lists the windows it is shown in, separated by commas: `gfy:main` (the main window), `gfy:popout` (a popout window), the tag of a tab in the window (`doc*` matches `doc-1`), both together (`gfy:popout&doc*`), or a regular expression (`/^doc-[0-9]+$/`). So a popout window of a document can have a tab of its own. The *Preview* draws one window and shows every node; the *Problems* window checks the masks."),C.heading("KeyTips and shortcuts"),C.points(["In your application, pressing and releasing [Alt] shows the KeyTips: a letter for every tab, and after it one for every control of the tab. They are made from the labels by themselves; `keytip` of a tab or an item fixes one (`H` for Home).","`shortcut` of an item runs its action from anywhere in the page (`Mod+S` is [Ctrl+S]). The *Problems* window tells a shortcut that two items use.","The *Preview* has the KeyTips and the shortcuts off, so the keys of the editor keep working: try them in your application."]),C.heading("The state of your application in the ribbon"),C.steps([["Bind a property","Select its row (`disabled`, `checked`, `hidden`, a `label`…) and press *Bind the property to a signal of the application* in the head of the *Inspector*, or type `=@` and a name: `=@noSelection`. The file keeps `{\"$bind\": \"noSelection\"}`."],["Give the signal","Your application registers it when it loads the file: `gfyLoadRibbon(ribbon, {signals: {noSelection: this.noSelection}})`. A writable signal goes both ways: a check box writes it back."],["React to the actions","Every item has an `action`, and `(action)` of `<gfy-ribbon>` tells which one was chosen. The *Handler* of the *Output* window has a case for every action."]]),C.note("What can be bound: the texts, the icon, the states and the value of an item, `hidden` of a tab and a section, `checked` and `disabled` of a choice, the list of `choices`. An `id`, an `action`, a shortcut and the inputs of a control are plain values."),C.heading("A button in the corner of a section"),C.text("`launcher` of a section shows the small ↘ button next to its title, the way an application opens a dialog with more options. The row holds an action: a click sends it to `(action)`, as a button does."),C.heading("A menu with the windows of the application"),C.text("In the menu of a split button or a dropdown button, *Add choice > Block* puts a block that the library fills when the menu opens: `gfy:documents` (the open documents), `gfy:tools` (the tool windows), `gfy:windows` (all the windows), `gfy:restore-layout`, or a block of your application. The *Editor* and the *Preview* show it as a disabled entry.")]},Ha({icon:"rbe:project-folder",noun:"ribbon",component:"RibbonEditor",selector:"ribbon-editor"}),{id:"keys",title:"Keyboard and mouse",icon:"rbe:keyboard",blocks:[C.heading("In the Editor"),C.keys([["Click","Select a tab, a section (by its title) or an item. A second click on the title of a section takes the selection away."],["Drag an item","Move it to a free cell of its section or of another one."],["Drag a handle","Stretch the item. To the right or the left, where another item stands in the way, a column opens when you let go; up or down onto a taken cell, the frame turns orange and nothing changes."],["Drop on a dashed line","Open a new column there: between two columns, or at the start or the end of a section."],["Right click","The commands of the node: add, duplicate, move, remove, *Add choice*. On the empty part of the tab bar: add a tab."],["[Arrow keys]","Move the selected item by a cell."],["[Shift+Arrow keys]","Stretch it, or shrink it."],["[Delete], [Backspace]","Remove the selected node."],["[Escape]","End a drag or a stretch without a change."]]),C.heading("The Toolbox and the Outline"),C.keys([["Click a control, or [Enter] or [Space] on it","Add it to the selected section (with nothing selected: to the tab that is shown)."],["Drag a control","Put it on a cell of the Editor."],["Drag a tab or a section in the Outline","Move it; a section can go into another tab."],["[Delete], [Backspace] in the Outline","Remove the selected node."],["Right click, [Shift+F10], [Menu] in the Outline","The same commands as in the Editor."]]),C.heading("The other windows"),C.keys([["Double click a problem, or [Enter]","Go to its node (a problem of the whole file has none)."],["`=` first in a row of the Inspector","Code of your application: `=tr('Home')`, and `=@name` for a signal."]]),C.heading("Everywhere"),C.keys([["[Ctrl+Z], [Ctrl+Y]","Undo, redo (in a text field: the typing)."],["[Ctrl+D]","Duplicate the selected node."],["[Alt+Up], [Alt+Down]","Move a tab, a section or a choice earlier or later."],["[Ctrl+O]","Open a file (with the files of a project: a file of the project)."],["[Ctrl+S]","Download the file (with the files of a project: save it into its file of the project)."],["[Ctrl+Shift+S]","Save as… (with the files of a project)."]])]}]};const bp=[{tag:"outline",title:"Outline",icon:"rbe:section",role:"tool",component:_i},{tag:"toolbox",title:"Toolbox",icon:"rbe:control-button",role:"tool",component:Vi},{tag:"editor",title:"Editor",icon:"rbe:grid",role:"document",component:ji,fixed:true},{tag:"preview",title:"Preview",icon:"rbe:preview",role:"document",component:Wi,fixed:true},{tag:"output",title:"Output",icon:"rbe:copy",role:"tool",component:Gi},{tag:"problems",title:"Problems",icon:"rbe:problems",role:"tool",component:Bi},{tag:"inspector",title:"Inspector",icon:"rbe:cursor",role:"tool",component:Pi},{tag:"options",title:"Ribbon Options",icon:"rbe:format",role:"tool",component:Ki}];const ay={showCloseButton:false,allowDetachOnDrag:false,showUndockButton:false};const en=n=>({tag:n.tag,role:n.role,icon:n.icon,title:I.signal(n.title),componentType:n.component,componentKey:`rbe-${n.tag}`,...(n.fixed?ay:{})});const qr=(n,e,t,o)=>({tag:n,type:"panel",role:e,size:t,activeTab:0,collapsed:false,tabs:o});const ly="gfy-ribbon-editor:windows";const tn=n=>bp.find(e=>e.tag===n);const cy=()=>({type:"row",size:100,children:[qr("left","tool",20,[en(tn("toolbox")),en(tn("outline"))]),{type:"column",size:56,children:[qr("docs","document",60,[en(tn("editor")),en(tn("preview"))]),qr("bottom","tool",40,[en(tn("output")),en(tn("problems"))])]},qr("right","tool",24,[en(tn("inspector")),en(tn("options"))])]});class qi{hosted=we(false,{...(ngDevMode?{debugName:"hosted"}:({})),transform:js});files=we(null,...(ngDevMode?[{debugName:"files"}]:([])));sample=we(null,...(ngDevMode?[{debugName:"sample"}]:([])));store=L(Ze);texts=I;help=Va(sy);engine=ct(Ie,...(ngDevMode?[{debugName:"engine"}]:([])));layout=cy();windowsKey=ly;constructor(){this.store.project.connect(this.files)}ngOnInit(){const e=this.sample();if(e)this.store.startWith(e)}saveWindows(){this.engine()?.saveLayout()}windowItems(){const e=t=>I.text(t);return this.engine()?.view.toolItems(bp.filter(t=>!t.fixed).map(t=>({tag:t.tag,label:()=>e(t.title),icon:t.icon})))??[]}resetLayout(){setTimeout(()=>this.engine()?.resetLayout())}menus=M(()=>{const e=this.store;const t=d=>I.text(d);const o=e.capabilities();const i=e.selected();const r=i===null?null:_(i);const s=Yd.map(d=>({label:t(d.label),run:()=>void e.loadSample(d.id)}));const a=e.project.files()!==null;const l=[...Xo.map(d=>({label:t(d.label),icon:ti(d.type),run:()=>e.addItem(d.type)})),{separator:true},{label:t("Control of the application"),icon:"rbe:item",run:()=>e.addItem(ei)}];return[{id:"file",label:t("&File"),items:[{label:t("&New ribbon"),icon:"rbe:add-tab",run:()=>void e.newRibbon()},{label:t("&Open file…"),icon:"rbe:upload",shortcut:a?void 0:"Mod+O",run:()=>e.openFile()},...(a?[{label:t("Open from the p&roject…"),icon:"rbe:project-folder",shortcut:"Mod+O",run:()=>void e.openFromProject()}]:[]),{label:t("&Paste ribbon from the clipboard"),icon:"rbe:paste",run:()=>void e.pasteRibbon()},{label:t("&Samples"),icon:"rbe:sample",children:s},{separator:true},...(a?[{label:t("Sa&ve"),icon:"rbe:save",shortcut:"Mod+S",run:()=>void e.saveToProject()},{label:t("Save as…"),shortcut:"Mod+Shift+S",run:()=>void e.saveToProjectAs()}]:[]),{label:t("&Download the file"),icon:"rbe:download",shortcut:a?void 0:"Mod+S",run:()=>e.downloadFile()},{label:t("&Copy the output"),icon:"rbe:copy",run:()=>void e.copyOutput()},{separator:true},{label:t("&Auto save"),checked:e.autoSave(),run:()=>e.setAutoSave(!e.autoSave())}]},{id:"edit",label:t("&Edit"),items:[{label:t("&Undo"),icon:"rbe:undo",shortcut:"Mod+Z",enabled:e.canUndo(),run:()=>e.undo()},{label:t("Re&do"),icon:"rbe:redo",shortcut:"Mod+Y",enabled:e.canRedo(),run:()=>e.redo()},{separator:true},{label:t("Add &tab"),icon:"rbe:add-tab",run:()=>e.addTab()},{label:t("Add &section"),icon:"rbe:add-section",run:()=>e.addSection()},{label:t("Add &item"),icon:"rbe:add-item",children:l},...op(e,r),{separator:true},{label:t("Dup&licate"),icon:"rbe:duplicate",shortcut:"Mod+D",enabled:o.duplicate,run:()=>e.duplicateSelected()},{label:t("Move u&p"),icon:"rbe:up",shortcut:"Alt+Up",enabled:o.moveUp,run:()=>e.moveSelected(-1)},{label:t("Move do&wn"),icon:"rbe:down",shortcut:"Alt+Down",enabled:o.moveDown,run:()=>e.moveSelected(1)},{label:t("&Remove"),icon:"rbe:remove",enabled:o.remove,run:()=>e.removeSelected()}]},{id:"view",label:t("&View"),items:[{label:t("&Windows"),icon:"rbe:section",children:this.windowItems()},{label:t("&Reset the windows"),run:()=>this.resetLayout()}]},{id:"help",label:t("&Help"),items:[...this.help.items]}]},...(ngDevMode?[{debugName:"menus"}]:([])));title=M(()=>this.store.project.title(this.store.modified()),...(ngDevMode?[{debugName:"title"}]:([])));statusItems=M(()=>{const e=this.store;const t=e.problems();const o=t.filter(l=>l.severity==="error").length;const i=t.filter(l=>l.severity==="warning").length;const r=e.counts();const s=e.selected();const a=s===null?"":Zt(e.root(),s);return[{id:"message",text:e.status()||I.text("Ready"),shrink:true,live:true},{id:"where",text:a,tooltip:I.text("The selected node"),align:"end",priority:4,visible:a!==""},{id:"counts",text:I.text("Tabs: {tabs}, sections: {sections}, items: {items}",r),tooltip:I.text("The size of the ribbon"),align:"end",priority:3},{id:"problems",icon:"rbe:problems",text:I.text("Errors: {errors}, warnings: {warnings}",{errors:o,warnings:i}),tooltip:I.text("The problems of the ribbon"),align:"end",priority:10,tone:o>0?"danger":i>0?"warning":"default"}]},...(ngDevMode?[{debugName:"statusItems"}]:([])));onFileDragOver(e){za(e)}onFileDrop(e){void La(e)?.then(t=>{if(t)void this.store.loadFromText(t.text,t.name);else this.store.say(I.text("The file that was dropped cannot be read."))})}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:qi,deps:[],target:w.ɵɵFactoryTarget.Component});static ɵcmp=w.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"21.2.21",type:qi,isStandalone:true,selector:"ribbon-editor",inputs:{hosted:{classPropertyName:"hosted",publicName:"hosted",isSignal:true,isRequired:false,transformFunction:null},files:{classPropertyName:"files",publicName:"files",isSignal:true,isRequired:false,transformFunction:null},sample:{classPropertyName:"sample",publicName:"sample",isSignal:true,isRequired:false,transformFunction:null}},host:{properties:{"class.hosted":"hosted()"}},providers:[Ze],viewQueries:[{propertyName:"engine",first:true,predicate:Ie,descendants:true,isSignal:true}],ngImport:w,template:`
848
+ <div class="shell" (dragover)="onFileDragOver($event)" (drop)="onFileDrop($event)">
849
+ <gfy-menu-bar [menus]="menus()" [shortcuts]="true">
850
+ @if (!hosted()) {
851
+ <span gfyMenuBarStart>{{ texts.text('Gridify Ribbon editor') }}</span>
852
+ }
853
+ <span gfyMenuBarTitle [attr.title]="title().tooltip">{{ title().text }}</span>
854
+ @if (!hosted()) {
855
+ <gfy-preference-select gfyMenuBarEnd kinds="theme density" />
856
+ }
857
+ </gfy-menu-bar>
858
+ <div class="workspace">
859
+ <gfy-docking-engine [defaultLayout]="layout" [layoutStorageKey]="windowsKey" (layoutChanged)="saveWindows()" />
860
+ </div>
861
+ <gfy-status-bar [items]="statusItems()" />
862
+ </div>
863
+ `,isInline:true,styles:[":host{display:block;height:100vh;color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}:host(.hosted){height:100%}.shell{height:100%;display:flex;flex-direction:column;background:var(--gfy-bg-main)}.workspace{flex:1;min-height:0;position:relative}\n"],dependencies:[{kind:"component",type:Ie,selector:"gfy-docking-engine",inputs:["defaultLayout","engineId","layoutStorageKey","emptyDocument","viewSources","viewTools","tabMenuItems","popouts"],outputs:["tabOpened","tabConfirmClose","tabClosed","tabActivated","tabReordered","tabDocked","tabFloated","tabDirtyChanged","tabMovedToWindow","tabActiveChanged","panelCollapsed","panelExpanded","panelResized","panelMaximized","panelRestored","floatingMoved","floatingResized","dragStarted","dragEnded","popoutOpened","popoutClosed","popoutRefused","layoutChanged","layoutSaved","layoutLoaded","layoutReset"]},{kind:"component",type:Gn,selector:"gfy-menu-bar",inputs:["menus","ariaLabel","overflow","overflowLabel","flexReserve","shortcuts","ignoreAlt","messageBar"],outputs:["messageBarChange","messageBarClosed","messageBarActionInvoked","itemInvoked"]},{kind:"component",type:Bn,selector:"gfy-preference-select",inputs:["kinds","showLabels","disabled"],outputs:["switchFailed"]},{kind:"component",type:Vn,selector:"gfy-status-bar",inputs:["items","variant","ariaLabel","overflowLabel","flexReserve"],outputs:["itemInvoked","choiceInvoked"]}],changeDetection:w.ChangeDetectionStrategy.OnPush})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:qi,decorators:[{type:me,args:[{selector:"ribbon-editor",standalone:true,imports:[Ie,Gn,Bn,Vn],providers:[Ze],changeDetection:fn.OnPush,host:{"[class.hosted]":"hosted()"},template:`
864
+ <div class="shell" (dragover)="onFileDragOver($event)" (drop)="onFileDrop($event)">
865
+ <gfy-menu-bar [menus]="menus()" [shortcuts]="true">
866
+ @if (!hosted()) {
867
+ <span gfyMenuBarStart>{{ texts.text('Gridify Ribbon editor') }}</span>
868
+ }
869
+ <span gfyMenuBarTitle [attr.title]="title().tooltip">{{ title().text }}</span>
870
+ @if (!hosted()) {
871
+ <gfy-preference-select gfyMenuBarEnd kinds="theme density" />
872
+ }
873
+ </gfy-menu-bar>
874
+ <div class="workspace">
875
+ <gfy-docking-engine [defaultLayout]="layout" [layoutStorageKey]="windowsKey" (layoutChanged)="saveWindows()" />
876
+ </div>
877
+ <gfy-status-bar [items]="statusItems()" />
878
+ </div>
879
+ `,styles:[":host{display:block;height:100vh;color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}:host(.hosted){height:100%}.shell{height:100%;display:flex;flex-direction:column;background:var(--gfy-bg-main)}.workspace{flex:1;min-height:0;position:relative}\n"]}]}],ctorParameters:()=>[],propDecorators:{hosted:[{type:w.Input,args:[{isSignal:true,alias:"hosted",required:false}]}],files:[{type:w.Input,args:[{isSignal:true,alias:"files",required:false}]}],sample:[{type:w.Input,args:[{isSignal:true,alias:"sample",required:false}]}],engine:[{type:w.ViewChild,args:[w.forwardRef(()=>Ie),{isSignal:true}]}]}});const qa=()=>({type:"row",size:100,children:[]});const je=n=>v(n)&&n["type"]==="panel";const Ke=n=>B(n);function Ua(n){if(!v(n)||B(n))return 0;const e=Array.isArray(n["tabs"])?n["tabs"]:Array.isArray(n["children"])?n["children"]:[];return e.reduce((t,o)=>t+(B(o)?1:Ua(o)),0)}const oe=(n,e)=>Object.prototype.hasOwnProperty.call(n,e);const K=n=>Array.isArray(n)?n:[];const yo=n=>je(n)?"tabs":"children";const he=n=>v(n)&&Boolean(n["shell"]);function se(n,e){if(!v(n))return null;let t=n;for(let o=0;o<e.length;o+=2){const i=e[o];const r=e[o+1];if(typeof i!=="string"||typeof r!=="number"||i!==yo(t))return null;const s=K(t[i])[r];if(!v(s)||Ke(s))return null;if(i==="tabs")return o+2===e.length?"tab":null;t=s}return je(t)?"panel":"container"}const Be=n=>n.length===0?null:n.slice(0,-2);const Pt=n=>n.length===0?-1:n[n.length-1];function pt(n,e){const t=(o,i)=>{if(o===e)return i;if(!v(o))return null;const r=yo(o);const s=K(o[r]);for(let a=0;a<s.length;a++){const l=t(s[a],[...i,r,a]);if(l)return l}return null};return t(n,[])}function yp(n,e){const t=se(n,e);if(t==="panel")return e;return t==="tab"?e.slice(0,-2):null}const dy=["inputs","contentStyle"];function Ye(n){if(n["serialize"]==="callback")return"callback";if(oe(n,"componentKey")||oe(n,"componentType"))return"component";if(n["kind"]==="component")return"element";if(!oe(n,"content")&&(dy.some(e=>oe(n,e))||n["serialize"]==="json"))return"component";return"html"}function De(n){if(typeof n==="string")return n;if(typeof n==="number"||typeof n==="boolean")return String(n);const e=zt(n);return e===void 0?"":`=${e.trim()}`}function Ur(n){const e=n["callback"];switch(Ye(n)){case"component":return De(n["componentKey"]);case"element":return De(n["componentTag"]);case"callback":return v(e)?De(e["key"]):"";default:return""}}function Mt(n){const e=[];const t=(o,i,r,s)=>{if(!v(o))return;const a=je(o);const l=he(o);const d=s||l;const c=K(o[yo(o)]);e.push({path:i,kind:a?"panel":"container",depth:r,shell:d,ownShell:l,type:a?typeof o["role"]==="string"?o["role"]:"":typeof o["type"]==="string"?o["type"]:"",tag:De(o["tag"]),title:"",componentKey:"",count:c.length});c.forEach((p,h)=>{if(!v(p)||Ke(p))return;if(a){e.push({path:[...i,"tabs",h],kind:"tab",depth:r+1,shell:d,ownShell:false,type:Ye(p),tag:De(p["tag"]),title:De(p["title"]),componentKey:Ur(p),count:0})}else{t(p,[...i,"children",h],r+1,d)}})};t(n,[],0,false);return e}function pi(n,e){if(!v(n))return false;const t=se(n,e)==="tab"?e.slice(0,-2):e;let o=n;for(let i=0;;i+=2){if(he(o))return true;if(i>=t.length)return false;const r=v(o)?K(o[yo(o)])[t[i+1]]:void 0;if(r===void 0)return false;o=r}}const Ya=(n,e)=>e.length>=2&&pi(n,e.slice(0,-2));function hi(n){if(v(n))return je(n)?{type:"row",size:100,children:[n]}:n;if(Array.isArray(n))return{type:"row",size:100,children:n};return qa()}function Yr(n){return Mt(n).flatMap(e=>{const t=e.kind==="tab"?X(n,e.path):void 0;return t?[{path:e.path,tab:t}]:[]})}function X(n,e){if(se(n,e)===null)return void 0;let t=n;for(let o=0;o<e.length;o+=2)t=K(t[e[o]])[e[o+1]];return v(t)?t:void 0}function py(n,e){if(e==="tab")return`tab "${De(n["title"])||Ur(n)||Ye(n)}"`;const t=e==="panel"?"panel":typeof n["type"]==="string"?n["type"]:"row";const o=De(n["tag"]);return o===""?t:`${t} "${o}"`}function Jr(n,e){if(!v(n))return"";const t=["layout"];let o=n;let i=0;for(;i+1<e.length;i+=2){const r=e[i];const s=e[i+1];if(typeof r!=="string"||typeof s!=="number"||r!==yo(o))break;const a=K(o[r])[s];if(!v(a))break;t.push(py(a,r==="tabs"?"tab":je(a)?"panel":"container"));o=a;if(r==="tabs"){i+=2;break}}for(;i<e.length;i++)t.push(String(e[i]));return t.join(" › ")}const hy=["roles","free"];const wp={dockingMode:"roles"};function uy(n){const e={...wp};if(v(n)&&(n["dockingMode"]==="roles"||n["dockingMode"]==="free"))e.dockingMode=n["dockingMode"];return e}function vp(n){const e=[];if(!Array.isArray(n))return e;for(const t of n){const o=typeof t==="string"?t.trim():"";if(o!==""&&!e.includes(o))e.push(o)}return e}const fy=n=>vp(n.split(/[\s,;]+/));const xp={options:wp,components:[]};const kp=n=>n.history.present.root;const Sp=n=>n.history.present.options;const my=n=>n.history.present.components;const Tp=n=>({options:n.history.present.options,components:n.history.present.components});const gy=n=>n.history.present!==n.saved;const by=n=>n.saved===n.history.present?n:{...n,saved:n.history.present};const yy=n=>n.saved!==n.history.present?n:{...n,saved:{...n.history.present}};function wo(n,e=null,t=xp,o=[]){const i=hi(n);const r=Ta({root:i,options:t.options,components:t.components});return{history:r,notes:o,selected:vo(i,e),saved:r.present}}function vo(n,e){if(e===null)return null;for(let t=e.length;t>=0;t--){const o=e.slice(0,t);if(se(n,o)!==null)return o}return null}const wy=(n,e)=>n===e||n!==null&&e!==null&&q(n)===q(e);const vy=(n,e)=>{const t=vo(kp(n),e);return wy(t,n.selected)?n:{...n,selected:t}};function Mp(n,e,t,o={}){const i=hi(e);const r=n.history.present;const s=wn(n.history,Object.is(i,r.root)?r:{...r,root:i},{mergeKey:o.mergeKey,now:o.now});return{...n,history:s,notes:s===n.history?n.notes:[],selected:vo(i,t===void 0?n.selected:t)}}function xy(n,e,t={},o){const i=n.history.present;if(JSON.stringify(e)===JSON.stringify(i.options))return n;const r=o===void 0?i.root:hi(o);const s=wn(n.history,{...i,options:e,root:r},{mergeKey:t.mergeKey,now:t.now});return{...n,history:s,notes:r===i.root?n.notes:[],selected:r===i.root?n.selected:vo(r,n.selected)}}function ky(n,e,t={}){const o=n.history.present;if(JSON.stringify(e)===JSON.stringify(o.components))return n;return{...n,history:wn(n.history,{...o,components:e},{mergeKey:t.mergeKey,now:t.now})}}function $p(n,e){return{...n,history:e,notes:[],selected:vo(e.present.root,n.selected)}}const Sy=n=>n.history.past.length===0?n:$p(n,Ma(n.history));const Ty=n=>n.history.future.length===0?n:$p(n,$a(n.history));function My(n){const e=n.normalize("NFKD").replace(/[̀-ͯ]/g,"").split(/[^A-Za-z0-9]+/).filter(o=>o!=="");const t=e.map(o=>o[0].toUpperCase()+o.slice(1)).join("");return`${t===""?"Tab":/^[0-9]/.test(t)?`C${t}`:t}Component`}function Ja(n){const e=/* @__PURE__ */new Map;const t=/* @__PURE__ */new Set;for(const o of n){const i=My(o);let r=i;for(let s=2;t.has(r);s++)r=`${i}${s}`;t.add(r);e.set(o,r)}return e}const $y=/^\s*(\d+(?:\.\d+)?|\.\d+)\s*(px|%|fr)\s*$/;function Je(n){if(typeof n==="number")return Number.isFinite(n)&&n>0?{value:n,unit:"fr"}:null;if(typeof n!=="string")return null;const e=$y.exec(n);if(!e)return null;const t=parseFloat(e[1]);return t>0?{value:t,unit:e[2]}:null}function Ot(n,e){const t=e==="px"?0:e==="%"?1:2;const o=10**t;return Math.round(n*o)/o}function xn(n,e){const t=Ot(n,e);return e==="fr"?t:`${t}${e}`}function Ay(n,e,t){return e>0&&t>0?n*e/t:void 0}function Cy(n,e){return xn(e==="px"?n.px:e==="%"?n.percent:n.ratio??n.percent,e)}function Oy(n,e){const t=Je(n);return xn(t?t.value:50,e)}function Ny(n){const e=n.trim();if(/^(?:\d+(?:\.\d+)?|\.\d+)$/.test(e)){const o=Ot(parseFloat(e),"fr");return o>0?o:null}const t=Je(e);return t&&Ot(t.value,t.unit)>0?xn(t.value,t.unit):null}const ui=n=>typeof n["type"]==="string"?n["type"]:"row";function kn(n){const e=[];if(!v(n)||je(n))return e;if(he(n))e.push({code:"root",path:[],params:{}});const t=(o,i,r,s)=>{const a=K(o["children"]);const l=a.map((c,p)=>p).filter(c=>!he(a[c]));const d=l.length<a.length;if(!r&&a.length>0){let c=false;a.forEach((h,u)=>{if(he(h)&&u!==0&&u!==a.length-1){c=true;e.push({code:"edge",path:[...i,"children",u],params:{index:u,type:ui(o)}})}});const p=a.filter(he).length;if(p===a.length)e.push({code:"all",path:i,params:{type:ui(o)}});else if(p>0&&!c&&a.length-p>1)e.push({code:"core",path:i,params:{type:ui(o),count:a.length-p}});if(!s){a.forEach((h,u)=>{if(he(h))e.push({code:"deep",path:[...i,"children",u],params:{type:ui(o)}})})}}a.forEach((c,p)=>{if(!v(c))return;const h=[...i,"children",p];const u=r||he(c);if(je(c)){const f=c["shellHeader"];const m=K(c["tabs"]).length;if(u&&(f==="text"||f==="none")&&m>1)e.push({code:"header",path:h,params:{header:f,tabs:m}})}else{t(c,h,u,!u&&s&&d&&l.length===1&&l[0]===p)}})};t(n,[],he(n),true);return e}const xo=n=>kn(n).filter(e=>e.code==="root"||e.code==="edge"||e.code==="all").length;const Xr=n=>kn(n).filter(e=>e.code!=="header").length;const Ap={tab:"A tab has no shell of its own: it takes the one of its panel.",root:"The root is the whole layout, so no core would be left. Make a node inside it the shell.",inside:"A container above is a shell already, and this node is part of it.",deep:"A shell is the outer frame of the layout: it stands at the edge of the root, or of the core that a shell above it leaves. This node stands inside a container of the dockable core, among the nodes that tabs are docked to. Put it at the edge of the layout first (in the Preview, dock its tab to an outer edge), then make it the shell.",edge:"The shell is the outer edge of the layout: the node has to be the first or the last of its siblings.",only:"A shell needs a core beside it, and this node is the only one of its level (or the others are shells too)."};function Xa(n,e){const t=se(n,e);if(t===null||t==="tab")return"tab";if(e.length===0)return"root";if(Ya(n,e))return"inside";const o=Be(e);if(!Cp(n).some(a=>a.length===o.length&&a.every((l,d)=>l===o[d])))return"deep";const i=O(n,o);const r=v(i)?K(i["children"]):[];const s=e[e.length-1];if(s!==0&&s!==r.length-1)return"edge";return r.some((a,l)=>l!==s&&!he(a))?null:"only"}function Iy(n){const e=n.reduce((t,o)=>{const i=v(o)?Je(o["size"]):null;return i&&i.unit==="fr"?t+i.value:t},0);return e>0?Ot(e,"fr"):100}function fi(n,e){const t=O(n,e);if(se(n,e)!=="container"||!v(t)||Ya(n,e)||he(t))return n;const o=K(t["children"]);const i=o.filter(l=>!he(l));if(i.length<2||i.length===o.length)return n;const r={type:ui(t),size:Iy(i),children:i};let s=false;const a=[];for(const l of o){if(he(l))a.push(l);else if(!s){a.push(r);s=true}}return be(n,[...e,yo(t)],a)}function Cp(n){const e=[];let t=[];for(;;){e.push(t);const o=O(n,t);if(!v(o))return e;const i=K(o["children"]);if(!i.some(he))return e;const r=i.map((s,a)=>({child:s,index:a})).filter(s=>!he(s.child));if(r.length!==1||!v(r[0].child)||je(r[0].child)||Ke(r[0].child))return e;t=[...t,"children",r[0].index]}}function Dy(n){const e=Cp(n);return e[e.length-1]}const ht=n=>v(n)&&!je(n)&&!Ke(n);const mi=n=>Ke(n["size"])||K(n["children"]).some(e=>Ke(e)||v(e)&&Ke(e["size"]));const $t=n=>n["collapsed"]===true;const Wt=n=>{const e=Je(n["size"]);return e!==null&&e.unit!=="fr"};const Za=n=>{const e=Je(n["size"]);return e!==null&&e.unit==="fr"?e.value:50};function nn(n){let e=[];let t=n;const o=he(n);for(;;){if(!ht(t))return e;const i=K(t["children"]);const r=i.map((s,a)=>({child:s,index:a})).filter(s=>!o&&!he(s.child));if(r.length===i.length)return e;if(r.length>1)return null;if(r.length===0)return e;e=[...e,"children",r[0].index];t=r[0].child}}function Ey(n,e){const t=nn(n);return t!==null&&qs(e,t)}const Op=n=>Array.isArray(n["tabs"])&&n["tabs"].length===0;function Qa(n){if(!v(n))return 0;if(je(n))return n["role"]==="document"?1:0;return K(n["children"]).reduce((e,t)=>e+Qa(t),0)}function Np(n,e,t){const o=K(n["children"]);const i=[];let r=false;for(const s of o){if(je(s)){const l=s;if(!Op(l)||e==="roles"&&l["role"]==="document"&&t.documents<=1){i.push(s);continue}if(l["role"]==="document")t.documents--;r=true;continue}if(!ht(s)){i.push(s);continue}const a=Np(s,e,t);if(K(a["children"]).length>0)i.push(a);else r=true;if(a!==s)r=true}return r?{...n,children:i}:n}function Ip(n){const e=K(n["children"]);const t=e.filter(v);let o;if(t.length>0&&!t.some(s=>!$t(s)&&!Wt(s))){o=t.find(s=>$t(s)&&!Wt(s))??(t.every($t)?t[0]:void 0)}let i=false;const r=e.map(s=>{let a=s;if(a===o&&v(a)){a={...a,collapsed:false};i=true}if(ht(a)){const l=Ip(a);if(l!==a){i=true;a=l}}return a});return i?{...n,children:r}:n}function Dp(n,e){if(!ht(n))return n;const t=e||he(n);let o=false;let i=K(n["children"]).map(d=>{if(!ht(d))return d;const c=Dp(d,t);if(c!==d)o=true;return c});const r=!t&&i.some(d=>v(d)&&he(d));const s=[];for(const d of i){if(!r&&ht(d)&&d["type"]===n["type"]&&!$t(d)&&!Wt(d)&&!mi(d)){const c=K(d["children"]);const p=c.filter(v).filter(m=>!Wt(m));const h=p.filter(m=>!$t(m));const u=h.length>0?p.reduce((m,g)=>m+Za(g),0):100;const f=Za(d)/u;for(const m of c)s.push(v(m)&&!Wt(m)?{...m,size:Ot(Za(m)*f,"fr")}:m);o=true}else{s.push(d)}}i=s;i=i.map(d=>{if(!ht(d))return d;const c=K(d["children"]);const p=c[0];if(c.length!==1||!v(p)||mi(d))return d;const h={...p};for(const u of["size","resizable"]){if(d[u]===void 0)delete h[u];else h[u]=d[u]}if($t(d))h["collapsed"]=true;o=true;return h});let a=o?{...n,children:i}:n;const l=i.length===1?i[0]:void 0;if(ht(l)&&!mi(l))a={...a,type:l["type"],children:K(l["children"])};return a}function el(n,e,t,o){const i=O(n,e);if(!ht(i))return n;const r={documents:Qa(O(n,t))};const s=Dp(Ip(Np(i,o,r)),false);return s===i?n:be(n,e,s)}function Sn(n,e,t="roles"){const o=nn(n);if(o===null||!qs(e,o))return n;if(se(n,o)!=="container")return n;let i=e;while(i.length>o.length&&se(n,i)!=="container")i=Be(i);if(i.length>o.length)i=Be(i);let r=el(n,i,o,t);while(i.length>o.length){const s=X(r,i);if(s!==void 0&&K(s["children"]).length>=2)break;i=Be(i);r=el(r,i,o,t)}return r}function zy(n,e="roles"){const t=nn(n);if(t===null||se(n,t)!=="container")return n;return el(n,t,t,e)}const gi=n=>typeof n["type"]==="string"?n["type"]:"row";function Ep(n,e="roles"){const t=[];if(!ht(n))return t;const o=nn(n);const i=(d,c)=>{const p=K(d["children"]);const h=p.filter(v);if(h.length>0&&!h.some(u=>!$t(u)&&!Wt(u))){const u=h.find(f=>$t(f)&&!Wt(f))??(h.every($t)?h[0]:void 0);if(u!==void 0)t.push({code:"open",path:[...c,"children",p.indexOf(u)],params:{type:gi(d)}})}p.forEach((u,f)=>{if(ht(u))i(u,[...c,"children",f])})};i(n,[]);if(o===null||se(n,o)!=="container")return t;const r=O(n,o);const s={documents:Qa(r)};const a=(d,c,p)=>{const h=p||he(d);const u=K(d["children"]);const f=!h&&u.some(m=>v(m)&&he(m));u.forEach((m,g)=>{const y=[...c,"children",g];if(je(m)){const x=m;if(!Op(x))return;if(e==="roles"&&x["role"]==="document"&&s.documents<=1)return;if(x["role"]==="document")s.documents--;t.push({code:"empty",path:y,params:{}});return}if(!ht(m))return;const b=K(m["children"]);if(b.length===0)t.push({code:"empty",path:y,params:{type:gi(m)}});else if(mi(m)){}else if(!f&&m["type"]===d["type"]&&!$t(m)&&!Wt(m))t.push({code:"merge",path:y,params:{type:gi(m)}});else if(b.length===1)t.push({code:"single",path:y,params:{type:gi(m)}});a(m,y,h)})};a(r,o,false);const l=K(r["children"]);if(l.length===1&&ht(l[0])&&!mi(l[0]))t.push({code:"absorb",path:[...o,"children",0],params:{type:gi(l[0])}});return t}const tl={alone:"Nothing beside the node is open and has a ratio to take its room, so the engine opens it again.",feature:"The active tab of the panel does not let it collapse (collapseFeature is off), so the engine opens it again.",header:"A shell panel without a header (shellHeader none) has no arrow to open it again, so the engine never leaves it collapsed.",empty:"The empty document area has no header to open it again, so the engine never leaves it collapsed."};function zp(n,e,t){const o=K(n["tabs"]);const i=Number.isInteger(n["activeTab"])?n["activeTab"]:0;const r=o[i];if(v(r)&&r["collapseFeature"]===false)return"feature";if(e&&n["shellHeader"]==="none")return"header";if(t==="roles"&&n["role"]==="document"&&o.length===0)return"empty";return null}function nl(n,e,t="roles"){const o=se(n,e);const i=X(n,e);if(o===null||o==="tab"||i===void 0)return null;if(e.length===0)return"alone";let r=false;let s=n;for(let d=0;d<=e.length;d+=2){if(he(s))r=true;if(d===e.length)break;s=K(s[e[d]])[e[d+1]]}if(o==="panel"){const d=zp(i,r,t);if(d!==null)return d}else{const d=[];const c=(h,u)=>{if(!v(h))return;const f=u||he(h);if(je(h))d.push({panel:h,shell:f});else K(h["children"]).forEach(m=>c(m,f))};c(i,r);const p=d.map(h=>zp(h.panel,h.shell,t)).find(h=>h!==null);if(p)return p}const a=K(O(n,[...Be(e),"children"]));const l=e[e.length-1];return a.some((d,c)=>c!==l&&v(d)&&!$t(d)&&!Wt(d))?null:"alone"}const ol={core:"The core of the layout cannot be taken out: a shell needs the dockable core beside it. Take out what is in the core, or turn the shell off first.",header:"A shell panel with the header \"text\" or \"none\" shows its first tab only, so it takes no second tab. Set its shellHeader to \"tabs\" first.",edge:"A panel there would stand outside the shell, which is the outer edge of the layout. Put it on the other side, beside a node of the core, or inside the shell.",role:"In the docking mode with roles a panel goes where the engine docks a tab of its role: documents beside a panel of documents; tools beside a panel of tools, at the edges of the document area or at the outer edges of the core. The free mode docks anything anywhere."};function Lp(n,e){const t=X(n,e);return t!==void 0&&pi(n,e)&&(t["shellHeader"]==="text"||t["shellHeader"]==="none")}function il(n,e,t){const o=X(n,e);if(o===void 0)return n;const i=o["activeTab"];if(i!==void 0&&typeof i!=="number")return n;const r=K(o["tabs"]).length;const s=Number.isInteger(i)?i:0;const a=Math.max(0,Math.min(t(s,r),r-1));if(a===s&&(i!==void 0||a===0))return n;return be(n,[...e,"activeTab"],a)}const Ly=n=>e=>e===n?Math.max(0,n-1):n<e?e-1:e;const Ry=(n,e)=>t=>{if(t===n)return e;if(n<t&&t<=e)return t-1;if(e<=t&&t<n)return t+1;return t};function rl(n,e,t){if(t===null)return null;if(n===e)return t;for(let o=t.length;o>=0;o-=2){const i=X(n,t.slice(0,o));const r=i===void 0?null:pt(e,i);if(r)return r}for(let o=t.length;o>=0;o-=2)if(se(e,t.slice(0,o))!==null)return t.slice(0,o);return[]}const sl=(n,e)=>n===e||JSON.stringify(n)===JSON.stringify(e);function Rp(n,e,t){for(let o=1;;o++){const i=`${n}${t}${o}`;if(!e.has(i))return i}}function bi(n){const e=n.normalize("NFKD").replace(/[̀-ͯ]/g,"").toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"");return e===""?"component":e}function ko(n){const e=[];for(const{tab:t}of Yr(n)){if(Ye(t)!=="component")continue;const o=De(t["componentKey"]);if(o!==""&&!e.includes(o))e.push(o)}return e}function Fy(n){const e=[];for(const{tab:t}of Yr(n)){if(Ye(t)!=="callback")continue;const o=De(v(t["callback"])?t["callback"]["key"]:void 0);if(o!==""&&!e.some(i=>i.key===o))e.push({key:o,title:De(t["title"])})}return e}function jy(n){const e=[];for(const{tab:t}of Yr(n)){if(Ye(t)!=="element")continue;const o=De(t["componentTag"]);if(o!==""&&!e.some(i=>i.tag===o))e.push({tag:o,title:De(t["title"])})}return e}function Py(n,e){const t=new Set(ko(n));return t.has(e)?Rp(e,t,"-"):e}const Wy=n=>`my-${bi(n)}`;function Fp(n,e,t){switch(e){case"html":return{content:""};case"component":return{componentKey:Py(n,bi(t))};case"element":return{kind:"component",componentTag:Wy(t)};case"callback":return{serialize:"callback",callback:{key:bi(t)}}}}function jp(n,e){const t=new Set(Yr(n).map(({tab:i})=>De(i["title"])));const o=Rp(e.title??(e.kind==="html"?"HTML":e.kind==="component"?"Component":e.kind==="element"?"Element":"Callback"),t," ");return{role:e.role,title:o,...Fp(n,e.kind,o)}}function Pp(n,e,t){if(t==="free"||n["role"]==="panel")return true;return n["role"]===e}function Ky(n,e,t){const o=Mt(n).find(i=>{if(i.kind!=="panel"||i.shell)return false;const r=X(n,i.path);return r!==void 0&&Pp(r,e,t)});return o?o.path:null}function Wp(n){const e=n.flatMap(t=>{const o=v(t)?Je(t["size"]):null;return o&&o.unit==="fr"?[o.value]:[]});return e.length===0?100:Ot(e.reduce((t,o)=>t+o,0)/e.length,"fr")}function _y(n,e,t){const o=t.mode??"roles";const i=jp(n,t);let r=e===null?null:yp(n,e);const s=r===null?void 0:X(n,r);if(r!==null&&(s===void 0||!Pp(s,t.role,o)))r=null;if(r!==null&&s!==void 0&&K(s["tabs"]).length>0&&Lp(n,r))r=null;const a=r!==null&&e!==null&&se(n,e)==="tab"?Pt(e)+1:void 0;r??=Ky(n,t.role,o);if(r!==null){const x=X(n,r);const T=a??K(x["tabs"]).length;const k=be(gt(n,[...r,"tabs"],T,i),[...r,"activeTab"],T);return{root:k,selected:[...r,"tabs",T]}}const l=Dy(n);const d=X(n,l);const c=K(d?.["children"]);const p=c.filter(x=>!he(x));const h={type:"panel",role:o==="free"?"panel":t.role,size:Wp(p),activeTab:0,collapsed:false,tabs:[i]};const u=c.reduce((x,T,k)=>he(T)?x:k,-1);const f=u>=0?u+1:c.length;const m=fi(gt(n,[...l,"children"],f,h),l);const g=pt(m,h);const y=g===null?m:Sn(m,g,o);const b=pt(y,h);return{root:y,selected:b===null?null:[...b,"tabs",0]}}function Gy(n,e,t){const o=X(n,e);if(o!==void 0&&je(o)&&o["role"]===t)return true;if(t==="document")return false;const i=Mt(n).filter(s=>s.kind==="panel"&&X(n,s.path)?.["role"]==="document").map(s=>s.path);if(i.length>0){let s=i[0];for(const a of i){let l=0;while(l<s.length&&l<a.length&&s[l]===a[l])l++;s=s.slice(0,l-l%2)}if(Fe(s,e))return true}const r=nn(n);return r!==null&&Fe(r,e)}const Kp=["size","resizable","shell"];function _p(n,e,t){const o=t.mode??"roles";const i=e===null?null:se(n,e);if(e===null||i===null)return{root:n,selected:e};const r=i==="tab"?Be(e):e;const s=X(n,r);if(r.length===0||s===void 0)return{root:n,selected:e};const a=Be(r);const l=X(n,a);const d=t.side==="left"||t.side==="right"?"row":"column";const c=t.side==="left"||t.side==="top";const p={type:"panel",role:o==="free"?"panel":t.role,size:50,activeTab:0,collapsed:false,tabs:[jp(n,t)]};let h;if((l?.["type"]==="column"?"column":"row")===d){const m=Je(s["size"]);h=n;if(m===null||m.unit==="fr"){const g=m?.value??50;const y=Ot(Math.min(30,g/2),"fr");p["size"]=y;h=be(h,[...r,"size"],xn(g-y,"fr"))}else{p["size"]=Wp(K(l?.["children"]))}h=gt(h,[...a,"children"],c?Pt(r):Pt(r)+1,p)}else{const m=Object.fromEntries(Object.entries(s).filter(([y])=>!Kp.includes(y)));m["size"]=50;const g={type:d,...Object.fromEntries(Kp.flatMap(y=>s[y]===void 0?[]:[[y,s[y]]]))};g["size"]??=50;g["children"]=c?[p,m]:[m,p];h=be(n,r,g)}if(xo(h)>xo(n))return{root:n,selected:e,refused:"edge"};h=fi(h,a);const u=pt(h,p);if(u!==null)h=Sn(h,u,o);const f=pt(h,p);if(o==="roles"&&f!==null&&!pi(h,f)){const m=pi(n,r)?nn(n):r;if(m===null||!Gy(n,m,t.role))return{root:n,selected:e,refused:"role"}}if(Xr(h)>Xr(n))return{root:n,selected:e,refused:"edge"};return{root:h,selected:f===null?null:[...f,"tabs",0]}}const Gp={tab:"The role of a tab is set when it is added (Add tool, Add document) and does not change: a document belongs to the panels of documents, a tool to the panels of tools.",panel:"The role of a panel does not change while it has tabs: it is a panel of documents or of tools."};function Bp(n,e,t="roles"){if(t!=="roles")return null;const o=se(n,e);const i=X(n,e);if(i===void 0)return null;const r=l=>l==="document"||l==="tool";if(o==="panel")return r(i["role"])&&K(i["tabs"]).length>0?"panel":null;if(o!=="tab"||!r(i["role"]))return null;const s=yp(n,e);const a=s===null?void 0:X(n,s);return a!==void 0&&a["role"]===i["role"]?"tab":null}function Vp(n,e){const t=Be(e);const o=X(n,t);const i=o?K(o[e[e.length-2]]).length:0;return i>0?[...e.slice(0,-1),Math.min(Pt(e),i-1)]:t}function Hp(n,e,t="roles"){const o=se(n,e);if(e.length===0||o===null)return{root:n,selected:e.length===0?[]:null};let i=Qn(n,e);const r=Be(e);if(o==="tab")i=il(i,r,Ly(Pt(e)));let s=Vp(i,e);const a=nn(n);let l=r;while(l.length>0&&!(a!==null&&Fe(l,a))&&se(i,l)==="container"&&K(X(i,l)?.["children"]).length===0){i=Qn(i,l);s=Vp(i,l);l=Be(l)}const d=Sn(i,l,t);if(xo(d)>xo(n))return{root:n,selected:e,refused:"core"};return{root:d,selected:rl(i,d,s)}}function al(n){if(Array.isArray(n))return n.map(al);if(!v(n))return n;return Object.fromEntries(Object.entries(n).flatMap(([e,t])=>e==="id"?[]:[[e,al(t)]]))}function qp(n,e,t="roles"){const o=se(n,e);const i=X(n,e);if(e.length===0||o===null||i===void 0||o!=="tab"&&he(i))return{root:n,selected:e};const r=Be(e);if(o==="tab"&&Lp(n,r))return{root:n,selected:e,refused:"header"};const s=al(Ys(i));const a=gt(n,e.slice(0,-1),Pt(e)+1,s);if(o==="tab"){const p=il(a,r,()=>Pt(e)+1);return{root:p,selected:pt(p,s)}}const l=fi(a,r);const d=pt(l,s);const c=d===null?l:Sn(l,d,t);if(Xr(c)>Xr(n))return{root:n,selected:e};return{root:c,selected:pt(c,s)??rl(l,c,d)}}function ll(n,e,t){if(e.length===0||se(n,e)===null)return{root:n,selected:e};const o=Pt(e);const i=Vo(n,e.slice(0,-1),o,o+t);if(i===n||xo(i)>xo(n))return{root:n,selected:e};const r=Math.max(0,Math.min(o+t,K(O(n,e.slice(0,-1))).length-1));const s=se(n,e)==="tab"?il(i,Be(e),Ry(o,r)):i;return{root:s,selected:[...e.slice(0,-1),r]}}const Up=["children","tabs","shell"];function on(n,e,t,o){if(se(n,e)===null||Up.includes(t))return n;const i=X(n,e);return sl(i[t],o)?n:be(n,[...e,t],o)}function By(n,e,t,o){const i=X(n,e);if(i===void 0)return n;const r=[...o,...Up];const s=Object.fromEntries([...Object.entries(i).filter(([a])=>r.includes(a)),...Object.entries(t).filter(([a])=>!r.includes(a))]);return sl(i,s)?n:be(n,e,s)}const Yp={content:["html"],componentKey:["component"],componentType:["component"],inputs:["component"],componentTag:["element"],componentProps:["element"],kind:["element"],callback:["callback"],sanitize:["html","callback"],contentStyle:["component","element","callback"],dockedPadding:["component","element","callback"],floatingPadding:["component","element","callback"],placeholder:["component","callback"]};const Vy={html:["html","none"],component:["json","none"],element:["json","none"],callback:["callback"]};function Hy(n,e,t,o=[]){const i=X(n,e);if(se(n,e)!=="tab"||i===void 0||Ye(i)===t)return n;const r=i["serialize"];const s=typeof r==="string"&&Vy[t].includes(r)&&t!=="callback";const a=Object.entries(i).filter(([h])=>h==="serialize"?s:!(h in Yp)||Yp[h].includes(t));const l=Fp(n,t,De(i["title"]));const d=bi(De(i["title"]));if(t==="component"&&o.includes(d))l["componentKey"]=d;const c=i["componentTag"];if(t==="element"&&typeof c==="string"&&c.trim()!=="")l["componentTag"]=c;const p={...Object.fromEntries(a),...l};return be(n,e,p)}function qy(n,e){let t=n;for(const o of Mt(n)){if(o.ownShell&&o.path.length>e.length&&qs(o.path,e))t=be(t,[...o.path,"shell"],void 0)}return t}function Jp(n){return kn(n).find(e=>e.code==="deep")?.path??null}function Xp(n,e,t,o="roles"){const i=se(n,e);const r=X(n,e);if(i!=="container"&&i!=="panel"||r===void 0)return{ok:false,reason:"tab"};if(!t){if(!he(r))return Ya(n,e)?{ok:false,reason:"inside"}:{ok:true,root:n,selected:e};const h=be(n,[...e,"shell"],void 0);const u=X(h,e);const f=Be(e);const m=f===null?h:fi(h,f);const g=pt(m,u)??e;let y=Sn(m,g,o);const b=pt(y,u)??rl(m,y,g)??e;if(!kn(n).some(x=>x.code==="deep")){for(let x=Jp(y);x!==null;x=Jp(y)){const T=Xp(y,x,false,o);if(!T.ok)break;y=T.root}}return{ok:true,root:y,selected:pt(y,u)??b}}if(he(r))return{ok:true,root:n,selected:e};const s=Xa(n,e);if(s!==null)return{ok:false,reason:s};const a=qy(be(n,[...e,"shell"],true),e);const l=X(a,e);const d=fi(a,Be(e));const c=O(d,Be(e))===O(a,Be(e))?null:nn(d);const p=c===null?d:Sn(d,c,o);return{ok:true,root:p,selected:pt(p,l)??e}}const Zp=n=>K(n["tabs"]).filter(e=>v(e)&&!Ke(e));function Uy(n,e){let t=n;for(const o of Mt(n)){if(o.kind!=="panel")continue;const i=X(n,o.path);let r;if(e==="free")r="panel";else{const s=Zp(i);const a=new Set(s.flatMap(l=>l["role"]==="document"||l["role"]==="tool"?[l["role"]]:[]));if(s.length===0)r="document";else if(a.size===1)r=[...a][0];else if(a.size===0)r="tool"}if(r!==void 0)t=on(t,o.path,"role",r)}return t}function Yy(n){return Mt(n).flatMap(e=>{if(e.kind!=="panel"||e.shell)return[];const t=X(n,e.path);const o=t["role"];const i=Zp(t).filter(r=>o==="panel"||r["role"]!==void 0&&r["role"]!==o);return i.length>0?[e.path]:[]})}function Jy(n,e,t,o){const i=se(n,e);const r=X(n,e);if(i!=="container"&&i!=="panel"||r===void 0)return n;const s=o?Cy(o,t):Oy(r["size"],t);return sl(r["size"],s)?n:be(n,[...e,"size"],s)}const Xy="The layout has to be a container: { \"type\": \"row\", \"size\": 100, \"children\": [ ... ] }.";function Qp(n,e,t){const o=[];const i=a=>e.get(q([...t,...a]))??e.get(q(t))??{line:1,column:1,offset:0};let r=n;const s=Ja(ko(n));for(const a of Mt(n)){const l=Zy(r,a.path);if(!l)continue;if(a.kind!=="tab"){const p=l["sizeUnit"];const h=l["size"];if((p==="px"||p==="%")&&typeof h==="number"&&h>0){const u=xn(h,p);r=be(r,a.path,Object.fromEntries(Object.entries(l).flatMap(([f,m])=>f==="sizeUnit"?[]:[[f,f==="size"?u:m]])));o.push({...i([...a.path,"sizeUnit"]),template:"A saved layout writes the size as a number and a \"sizeUnit\": {size} with the unit \"{unit}\" is read as \"{text}\".",params:{size:h,unit:p,text:u}})}continue}const d=typeof l["componentKey"]==="string"?l["componentKey"]:"";const c=s.get(d);if(c!==void 0&&Ye(l)==="component"&&Lt(l["componentType"])===c){r=be(r,[...a.path,"componentType"],void 0);o.push({...i([...a.path,"componentType"]),template:"The class {name} that the TypeScript output names beside the key \"{key}\" is left out: the key names the component, and a file cannot hold a class.",params:{name:c,key:d}})}}if(v(r)&&!je(r)&&!oe(r,"size")){o.push({...i([]),template:"The layout has no \"size\": the root gets 100, which the type of the engine requires.",params:{}});const{type:a,...l}=r;r=a===void 0?{size:100,...l}:{type:a,size:100,...l}}return{root:r,notes:o}}function Zy(n,e){let t=n;for(let o=0;o<e.length;o+=2)t=v(t)?K(t[e[o]])[e[o+1]]:void 0;return v(t)?t:void 0}const Qy=n=>v(n)&&!oe(n,"type")&&(v(n["layout"])||Array.isArray(n["layout"]));const ew=["options","components","layout"];function tw(n,e){const t=s=>e.get(q(s))??e.get(q([]))??{line:1,column:1,offset:0};const o=[];for(const s of Object.keys(n)){if(!ew.includes(s))o.push({...t([s]),template:"The file has \"{key}\", which the editor does not know: it is left out, and a save does not write it again.",params:{key:s}})}const i=n["options"];if(i!==void 0&&!v(i))o.push({...t(["options"]),template:"The \"options\" have to be an object, so the editor takes the default options.",params:{}});if(v(i)){for(const a of Object.keys(i)){if(a!=="dockingMode")o.push({...t(["options",a]),template:"The option \"{key}\" is not one of the editor (it knows \"dockingMode\"): it is left out.",params:{key:a}})}const s=i["dockingMode"];if(s!==void 0&&s!=="roles"&&s!=="free"){o.push({...t(["options","dockingMode"]),template:"The docking mode {mode} is neither \"roles\" nor \"free\", so the editor takes \"roles\".",params:{mode:JSON.stringify(s)}})}}const r=n["components"];if(r!==void 0&&!Array.isArray(r))o.push({...t(["components"]),template:"The \"components\" have to be a list of keys, so the list is empty.",params:{}});if(Array.isArray(r)){r.forEach((s,a)=>{if(typeof s!=="string"||s.trim()==="")o.push({...t(["components",a]),template:"The entry {entry} of \"components\" is no key, so it is left out.",params:{entry:JSON.stringify(s)}})})}return o}function eh(n){const e=Xn(n,{lenient:true});if(!e.ok)return{ok:false,error:e.error};const t=e.value;if(Qy(t)){const i=oe(t,"options")||oe(t,"components")?{options:uy(t["options"]),components:vp(t["components"])}:null;const r=Qp(hi(t["layout"]),e.positions,["layout"]);return{ok:true,root:r.root,settings:i,notes:[...e.notes,...tw(t,e.positions),...r.notes]}}if(v(t)||Array.isArray(t)){const i=Qp(hi(t),e.positions,[]);return{ok:true,root:i.root,settings:null,notes:[...e.notes,...i.notes]}}const o=e.positions.get("[]")??{line:1,column:1,offset:0};return{ok:false,error:{...o,template:Xy,params:{}}}}const th=n=>Zn(n,2,110);function nw(n,e){return th({options:{dockingMode:e.options.dockingMode},components:[...e.components],layout:n})}const cl=(n,e)=>n.filter(t=>!t.when||t.when(e));const Zr=["row","column"];const yi=["document","tool"];const dl=["document","tool","panel"];const nh=["tabs","text","none"];const oh=["tabs","text"];const pl={key:"tag",kind:"text",category:"identity",label:"tag",description:"A name of your own for the node: the application finds it with api.getByTag(). It may repeat, and it is saved with the layout."};const ih={key:"resizable",kind:"switch",category:"shell",label:"resizable",description:"May the user drag the splitter beside the node? Not set: a ratio can be dragged, a size in px or % cannot. A size in px or % that is resizable needs a neighbour with a ratio.",when:n=>!n.isRoot,unused:"a node that has a splitter beside it (the root has none)"};const rh={key:"collapsed",kind:"switch",category:"behavior",label:"collapsed",description:"The node starts collapsed to a bar at the edge.",when:n=>!n.isRoot,unused:"a node that has a place at the edge to collapse to (the root has none)"};const ow={...rh,required:true,requiredDefault:false};const hl=[{key:"type",kind:"choice",category:"identity",label:"type",description:"row puts the children side by side, column one under the other.",options:Zr,required:true},pl,ih,rh];const iw=n=>n==="document"?["tool"]:n===void 0||n==="tool"?["document"]:yi;const rw=n=>n==="free"?["panel"]:["document","tool"];const ul=[{key:"role",kind:"choice",category:"identity",label:"role",description:"document: a panel of documents; tool: a panel of tools (the docking mode with roles). panel: the neutral role of the free docking mode, where any tab goes to any panel.",options:dl,optionsFor:n=>rw(n.dockingMode),required:true},pl,{key:"activeTab",kind:"integer",category:"behavior",label:"activeTab",description:"The index (from 0) of the tab that is shown when the layout starts.",min:0,required:true,requiredDefault:0},ow,ih,{key:"shellHeader",kind:"choice",category:"shell",label:"shellHeader",description:"The header of a shell panel: tabs (a tab bar), text (the icon and the title of the first tab across the bar) or none (no header, so no collapse button either). text and none show the first tab only.",options:nh,when:n=>n.inShell,unused:"a panel of the shell (a container above that is a shell counts)"},{key:"singleTabHeader",kind:"choice",category:"shell",label:"singleTabHeader",description:"text: a panel that has exactly one tab shows it as a plain header (no tab pill, no buttons). With two tabs or more the tab bar is back. A shell panel has its shellHeader instead.",options:oh,when:n=>!n.inShell,unused:"a panel that is not part of the shell (the shellHeader decides in a shell)"}];const sw=["type","tag","size","children","resizable","shell","collapsed"];const aw=["type","tag","role","size","activeTab","collapsed","tabs","shell","resizable","shellHeader","singleTabHeader"];const lw=["none","html"];const cw=["none","json"];const dw=["none","json"];const rk=["callback"];const pw=["inherit","isolated"];const ot=" Not set: the setting of the engine.";const fl=n=>n.tabKind!==void 0&&n.tabKind!=="html";const ml="a tab that is a component, a custom element or a callback that gives a component (a plain HTML body has its own padding and look)";const Ve=n=>!n.inShell;const wi="a tab outside the shell (the engine turns it off for a tab of the shell)";const hw="a tab outside the shell (a tab of the shell has no menu)";const vi="a tab outside the shell (a tab of the shell never goes to a floating window)";const gl="a tab outside the shell (the shell is not saved with the layout: the application gives it every time)";const bl=[{key:"dragEnabled",kind:"switch",category:"behavior",label:"dragEnabled",description:`The tab can be dragged (docked, moved between panels, returned from a floating window).${ot}`,when:Ve,unused:wi},{key:"allowTabReorder",kind:"switch",category:"behavior",label:"allowTabReorder",description:`The tab can be reordered within its panel. Off: it keeps its place among the other tabs.${ot}`},{key:"allowDetachOnDrag",kind:"switch",category:"behavior",label:"allowDetachOnDrag",description:`Dragging the tab outside any drop target detaches it into a floating window.${ot}`,when:Ve,unused:wi},{key:"collapseFeature",kind:"switch",category:"behavior",label:"collapseFeature",description:`The panel can be collapsed (it is taken from the active tab of the panel).${ot}`},{key:"maximizable",kind:"switch",category:"behavior",label:"maximizable",description:`The panel can be maximized while this is its active tab: it fills the dockable core and the other panels wait behind it (a double-click on the strip of tabs, the button at the end of the header, Ctrl+M on the tab). The setting maximize of the engine says it by the role (documents by default: a document can, a tool cannot).${ot}`,when:Ve,unused:"a tab outside the shell (a tab of the shell is never maximized)"},{key:"showFocusFrame",kind:"switch",category:"behavior",label:"showFocusFrame",description:`The panel or the floating window that holds the tab has a focus frame.${ot}`},{key:"distinguishRolesByColor",kind:"switch",category:"behavior",label:"distinguishRolesByColor",description:`The role of the tab is told by color: the line above the selected tab, the frame under the cursor and the focus frame are drawn in the accent of documents or of tools.${ot}`,when:n=>n.dockingMode==="roles",unused:"the docking mode with roles (in the free mode every tab has the one accent)"},{key:"showUndockButton",kind:"switch",category:"behavior",label:"showUndockButton",description:`The tab has a button for detaching it into a floating window.${ot}`,when:Ve,unused:wi},{key:"tabMenu",kind:"switch",category:"behavior",label:"tabMenu",description:`The tab has a menu (the right mouse button, the Menu key, Shift+F10 and its button).${ot}`,when:Ve,unused:wi},{key:"showMenuButton",kind:"choice-or-switch",category:"behavior",label:"showMenuButton",description:`The button that opens the menu of the tab: active (while the tab is active, under the pointer or focused), always (true) or never (false).${ot}`,options:["active","true","false"],when:Ve,unused:hw},{key:"showCloseButton",kind:"switch",category:"behavior",label:"showCloseButton",description:`The tab has a close button.${ot}`,when:Ve,unused:wi},{key:"dockedPadding",kind:"number",category:"behavior",label:"dockedPadding",description:"Inner padding (px) of the content while the tab is docked. A plain HTML body keeps its own padding, so this is for a component, a custom element and a callback that gives a component.",min:0,when:fl,unused:ml},{key:"floatingPadding",kind:"number",category:"floating",label:"floatingPadding",description:"Inner padding (px) of the content while the tab is in a floating window. A plain HTML body keeps its own padding, so this is for a component, a custom element and a callback that gives a component.",min:0,when:n=>fl(n)&&Ve(n),unused:`${ml}, outside the shell (a tab of the shell never goes to a floating window)`},{key:"floatingStatusBar",kind:"switch",category:"floating",label:"floatingStatusBar",description:`The floating window of the tab has a status bar at the bottom.${ot}`,when:Ve,unused:vi},{key:"floatingWidth",kind:"length",category:"floating",label:"floatingWidth",description:"The width of the floating window the tab opens in: a number (px), a CSS length (30rem, 40%, 40vw, calc(100% - 80px)) or fit-content (the window wraps its content). Not set: the setting of the engine.",when:Ve,unused:vi},{key:"floatingHeight",kind:"length",category:"floating",label:"floatingHeight",description:"The height of the floating window the tab opens in: a number (px), a CSS length (30rem, 40%, 40vh, calc(100% - 80px)) or fit-content (the window wraps its content). Not set: the setting of the engine.",when:Ve,unused:vi},{key:"allowFloatingResize",kind:"switch",category:"floating",label:"allowFloatingResize",description:`The user can resize the floating window of the tab.${ot}`,when:Ve,unused:vi},{key:"showDockButton",kind:"choice-or-switch",category:"floating",label:"showDockButton",description:`The button of a floating window that puts the tab back in the dock: auto shows it only where the window cannot be dragged back, true always, false never.${ot}`,options:["auto","true","false"],when:Ve,unused:vi}];const sk=bl.map(n=>n.key);const uw=[{key:"role",kind:"choice",category:"identity",label:"role",description:"document: the tab goes to a panel of documents; tool: to a panel of tools. Not set: the engine takes the tab for a tool.",options:yi},pl,{key:"title",kind:"text",category:"identity",label:"title",description:"The text of the tab. Code of the application (=t('Explorer')) is kept as it is written, so the title can follow the language.",required:true,requiredDefault:""},{key:"icon",kind:"text",category:"identity",label:"icon",description:"A key of the icon registry (gfy:document), a text or an emoji. Not set: the icon of the role."},{key:"colorIndex",kind:"integer",category:"colors",label:"colorIndex",description:"The color (0 to 4) of a document tab in the themes that color the documents (the Binder themes). Not set: the engine counts.",min:0,max:4,when:n=>n.role==="document"&&n.dockingMode==="roles",unused:"a tab of documents (role \"document\") in the docking mode with roles"},{key:"contentRole",kind:"choice",category:"colors",label:"contentRole",description:"Only the colors of the content: it is drawn in the palette of the other role, in the themes that tell the roles apart (Mint Mixed, Macchiato, Saltmarsh, Retro Blue, the Binder themes; in the others nothing changes). Where the tab docks is its role, which this does not change: a tool whose content reads like a document stays a tool and is drawn on the light surface of the documents. Not set: the palette of the role.",options:yi,optionsFor:n=>iw(n.role),notOffered:"the role of the tab, so nothing changes"}];const fw=[{key:"serialize",kind:"choice",category:"persistence",label:"serialize",description:"How the tab is saved: html (the content is saved, the default) or none (the tab is not saved).",options:lw,when:n=>n.tabKind==="html"&&Ve(n),unused:gl},{key:"sanitize",kind:"switch",category:"content",label:"sanitize",description:"false: the HTML of this tab is never sanitized, even when the engine has a sanitizer. Not set: the engine decides.",when:n=>n.tabKind==="html"||n.tabKind==="callback",unused:"a tab that holds HTML (an HTML tab, or a callback that gives HTML)"}];const mw=[{key:"componentKey",kind:"text",category:"content",label:"componentKey",description:"The key of the component in the registry of the application (GfyContentRegistry): the engine makes the component from it. A file cannot carry a class, so the application registers the key.",when:n=>n.tabKind==="component",unused:"a component tab"},{key:"serialize",kind:"choice",category:"persistence",label:"serialize",description:"How the tab is saved: json (the key and the inputs, the default) or none (the tab is not saved).",options:cw,when:n=>n.tabKind==="component"&&Ve(n),unused:gl}];const gw=[{key:"componentTag",kind:"text",category:"content",label:"componentTag",description:"The name of the custom element (my-widget): the engine makes it with document.createElement and fills the panel body with it. The name has a dash in it. The element has no Angular context.",when:n=>n.tabKind==="element",unused:"a custom element tab"},{key:"serialize",kind:"choice",category:"persistence",label:"serialize",description:"How the tab is saved: json (the tag and the properties, the default) or none (the tab is not saved).",options:dw,when:n=>n.tabKind==="element"&&Ve(n),unused:gl}];const bw=[{key:"contentStyle",kind:"choice",category:"content",label:"contentStyle",description:"inherit: the component takes the styles of the engine (the default); isolated: it brings its own. A plain HTML body (an HTML tab, or a callback that gives HTML) always has the look of the engine.",options:pw,when:fl,unused:ml},{key:"placeholder",kind:"text",category:"persistence",label:"placeholder",description:"The text shown instead of the loader while the content is waited for (a callback, a component that is loaded lazily, a tab restored after a reload). Saved with the layout.",when:n=>n.tabKind==="component"||n.tabKind==="callback",unused:"a component or a callback (they are waited for; an HTML tab and a custom element are made at once)"}];const yl={html:"content",component:"inputs",element:"componentProps",callback:"callback"};const yw=["content","inputs","componentProps","callback","componentType"];const Qr=[...uw,...fw,...mw,...gw,...bw,...bl];const ww=[.../* @__PURE__ */new Set([...Qr.map(n=>n.key),"kind",...yw])];const sh=["id"];const vw=["identity","colors","content","shell","behavior","floating","persistence"];const So={identity:"Identity",colors:"Colors",content:"Content",shell:"Shell and size",behavior:"Behavior",floating:"Floating window",persistence:"Saving"};const xw=["dirty","statusHtml","persistedState","contentEdited"];function Tn(n){if(n.kind==="container")return cl(hl,n);if(n.kind==="panel")return cl(ul,n);return cl(Qr,n)}const kw=(n,e)=>n.optionsFor?.(e)??n.options??[];function ah(n,e){const t=n.key;if(B(e))return null;switch(n.kind){case"text":return typeof e==="string"?null:{template:"The property \"{key}\" must be a text.",params:{key:t}};case"switch":return typeof e==="boolean"?null:{template:"The property \"{key}\" must be true or false.",params:{key:t}};case"integer":case"number":{const o=n.kind==="integer";const i=typeof e==="number"&&Number.isFinite(e)&&(!o||Number.isInteger(e))&&(n.min===void 0||e>=n.min)&&(n.max===void 0||e<=n.max);if(i)return null;const r=o?"a whole number":"a number";if(n.min!==void 0&&n.max!==void 0)return{template:`The property "{key}" must be ${r} from {min} to {max}.`,params:{key:t,min:n.min,max:n.max}};if(n.min!==void 0)return{template:`The property "{key}" must be ${r} of {min} or more.`,params:{key:t,min:n.min}};return{template:`The property "{key}" must be ${r}.`,params:{key:t}}}case"choice":return typeof e==="string"&&n.options?.includes(e)?null:{template:"The property \"{key}\" must be one of: {options}.",params:{key:t,options:(n.options??[]).join(", ")}};case"choice-or-switch":return typeof e==="boolean"||typeof e==="string"&&e===n.options?.[0]?null:{template:"The property \"{key}\" must be {first}, true or false.",params:{key:t,first:n.options?.[0]??""}};case"length":return typeof e==="number"&&e>0||typeof e==="string"&&e.trim()!==""?null:{template:"The property \"{key}\" must be a number of pixels greater than 0, or a CSS length such as 40%.",params:{key:t}}}}const vt="";const rn=n=>`f:${n}`;const lh=n=>[{value:vt,label:n("(not set)")},{value:"true",label:"true"},{value:"false",label:"false"}];const ch={fr:"Ratio",px:"Fixed (px)","%":"Percent (%)"};const To={html:"HTML",component:"Component",element:"Custom element",callback:"Callback"};const dh=["html","component","element","callback"];function es(n,e,t="roles"){const o=se(n,e);const i=X(n,e);if(o===null||i===void 0)return null;return{kind:o,tabKind:o==="tab"?Ye(i):void 0,isRoot:e.length===0,inShell:pi(n,e),role:i["role"],dockingMode:t}}function Sw(n,e,t){const o={id:rn(n.key),label:n.label,category:t(So[n.category]),description:t(n.description),...(n.required?{required:true}:{})};const i=n.required?[]:[{value:vt,label:t("(not set)")}];switch(n.kind){case"switch":return{...o,kind:"select",options:n.required?lh(t).slice(1):lh(t),defaultValue:n.required?String(n.requiredDefault??false):vt};case"choice":return{...o,kind:"select",options:[...i,...kw(n,e).map(r=>({value:r,label:r}))],defaultValue:vt};case"choice-or-switch":{const r=(n.options??[]).filter(s=>s!=="true"&&s!=="false");return{...o,kind:"select",options:[{value:vt,label:t("(not set)")},...r.map(s=>({value:s,label:s})),{value:"true",label:"true"},{value:"false",label:"false"}],defaultValue:vt}}case"integer":return{...o,kind:"number",min:n.min,max:n.max,step:1,decimals:0};case"number":return{...o,kind:"number",min:n.min,max:n.max,step:1};case"length":return{...o,kind:"text",placeholder:t("pixels, or a length such as 40%"),defaultValue:""};default:return{...o,kind:"text",defaultValue:""}}}const Tw=n=>({id:rn("sizeUnit"),label:"size unit",kind:"select",category:n(So.shell),description:n("Ratio: a share against the siblings (the number is relative). Fixed: a length in pixels that the node keeps when the window changes. Percent: a share of the whole container."),options:Object.keys(ch).map(e=>({value:e,label:n(ch[e])})),defaultValue:"fr"});const ph=(n,e)=>({id:rn("size"),label:"size",kind:"number",category:n(So.shell),description:n("The size along the split of the container: the width in a row, the height in a column. The unit is the row above. The type of the engine requires a size above 0, so the row is never empty."),min:e==="px"?1:e==="%"?0.1:0.01,step:e==="px"?10:e==="%"?1:5,decimals:e==="px"?0:e==="%"?1:2,required:true});const hh="The node is part of the fixed frame of the application: the user cannot close it, detach it or dock anything into it. It stands at the edge of its siblings, and the rest is the dockable core.";const Mw=(n,e,t)=>({id:rn("shell"),label:"shell",kind:"boolean",category:n(So.shell),description:!e&&t!==null?`${n(hh)} ${n("Not possible here:")} ${n(Ap[t])}`:n(hh),defaultValue:false,...(!e&&t!==null?{disabled:true}:{})});const ts={html:"The tab holds HTML (the content, under the rows).",component:"A component of the application, found by its componentKey and given its inputs.",element:"A custom element (a web component): the engine makes it from its tag and gives it its properties.",callback:"The content comes from a callback that the application registers (GfyContentRegistry): it gives HTML or a component."};const $w=n=>({id:rn("kind"),label:"tab kind",kind:"select",category:n(So.identity),description:n(`HTML: ${ts.html} Component: ${ts.component} Custom element: ${ts.element} Callback: ${ts.callback}`),options:dh.map(e=>({value:e,label:n(To[e])})),defaultValue:"html",required:true});function uh(n){const e=Tn(n).map(t=>t.key);e.push(...sh);if(n.kind!=="tab")e.push("size");if(n.kind==="panel")e.push("type");if(n.tabKind!==void 0){e.push(yl[n.tabKind]);if(n.tabKind==="element")e.push("kind");if(n.tabKind==="callback")e.push("serialize")}return e}function Aw(n,e){if(e===void 0||e===null)return n.kind==="switch"||n.kind==="choice"||n.kind==="choice-or-switch"?vt:void 0;switch(n.kind){case"switch":return typeof e==="boolean"?String(e):vt;case"choice":return typeof e==="string"?e:vt;case"choice-or-switch":return typeof e==="boolean"?String(e):typeof e==="string"?e:vt;case"integer":case"number":return typeof e==="number"&&Number.isFinite(e)?e:void 0;default:return typeof e==="string"?e:typeof e==="number"||typeof e==="boolean"?String(e):void 0}}const wl={html:{label:"Content (HTML)",description:"The HTML the tab shows. A text that starts with = is code of the application (a signal), kept as it is written.",language:"html"},component:{label:"Inputs (JSON)",description:"The inputs of the component, an object: {\"name\": value}. Both input() and @Input() are set by name (or by alias). They are saved with the layout.",language:"json"},element:{label:"Properties (JSON)",description:"The properties the engine assigns to the custom element, an object: {\"name\": value}. They have to be JSON.",language:"json"},callback:{label:"Callback (JSON)",description:"The callback of the application: {\"key\": \"name\", \"params\": {...}}. The key is the name it is registered under (GfyContentRegistry); the params are given to it, and have to be JSON.",language:"json"}};function Cw(n,e,t=o=>o){const o=X(n,e);if(se(n,e)!=="tab"||o===void 0)return null;const i=Ye(o);const r=yl[i];const s=wl[i];const a=o[r];let l="";if(s.language==="html"){const d=Lt(a);l=typeof a==="string"?a:d!==void 0?`=${d}`:""}else if(a!==void 0){l=Zn(a,2,60)}return{key:r,label:t(s.label),description:t(s.description),language:s.language,text:l}}function Ow(n,e,t){const o=X(n,e);if(se(n,e)!=="tab"||o===void 0)return{ok:false,template:"There is no node to write to.",params:{}};const i=Ye(o);const r=yl[i];if(wl[i].language==="html"){const a=t.trimStart().startsWith("=")?vl(t.trimStart().slice(1)):void 0;return{ok:true,root:on(n,e,r,a??t)}}if(t.trim()==="")return{ok:true,root:on(n,e,r,void 0)};const s=Xn(t,{lenient:true});if(!s.ok)return{ok:false,template:s.error.template,params:s.error.params};if(!v(s.value))return{ok:false,template:"The {part} has to be an object: {\"name\": value, ...}.",params:{part:wl[i].label}};return{ok:true,root:on(n,e,r,s.value)}}function Nw(n,e,t,o="roles"){const i=es(n,e,o);const r=X(n,e);if(i===null||r===void 0)return null;const{kind:s,tabKind:a,isRoot:l}=i;const d=[];const c={};const p=(u,f,m)=>{const g=Lt(f);if(g!==void 0){d.push({...u,kind:"text",options:void 0,min:void 0,max:void 0,step:void 0,decimals:void 0,placeholder:void 0,defaultValue:"",code:true,description:`${u.description} ${t(Iw)}`});c[u.id]=`=${g}`;return}if(typeof f==="string"&&u.options&&u.kind==="select"&&m&&(m.kind==="choice"||m.kind==="choice-or-switch")&&!u.options.some(b=>b.value===f)){const b=m.notOffered!==void 0&&m.options?.includes(f)?m.notOffered:"not valid here";u={...u,options:[...u.options,{value:f,label:`${f} (${t(b)})`}]}}if(f===void 0&&m?.required&&u.options&&!u.options.some(b=>b.value===vt)){u={...u,options:[{value:vt,label:t("(not set)")},...u.options]}}d.push(u);const y=m?Aw(m,f):f;if(y!==void 0)c[u.id]=y};if(s==="tab"&&a!==void 0){const u=$w(t);d.push(u);c[u.id]=a}for(const u of Tn(i)){const f=Sw(u,i,t);if(u.key==="activeTab")f.max=Math.max(0,K(r["tabs"]).length-1);const m=u.key==="role"?Bp(n,e,o):null;if(m!==null){f.disabled=true;f.description=`${f.description} ${t(Gp[m])}`}const g=u.key==="collapsed"&&r["collapsed"]!==true?nl(n,e,o):null;if(g!==null){f.disabled=true;f.description=`${f.description} ${t("Not possible here:")} ${t(tl[g])}`}p(f,r[u.key],u)}if(s!=="tab"&&!l){const u=Je(r["size"]);const f=u?.unit??"fr";const m=Boolean(r["shell"]);const g=Tw(t);if(B(r["size"])){d.push({...g,disabled:true,description:`${g.description} ${t("Not possible here: the size is code of the application, which has its own unit.")}`});p(ph(t,f),r["size"])}else{d.push(g,ph(t,f));c[rn("sizeUnit")]=f;if(u)c[rn("size")]=u.value}d.push(Mw(t,m,Xa(n,e)));c[rn("shell")]=m}const h=u=>vw.findIndex(f=>t(So[f])===u.category);d.sort((u,f)=>h(u)-h(f));return{kind:s,path:e,rows:d,values:c,tabKind:a,part:Cw(n,e,t)}}const Iw="The value is code of the application (the row shows it after a =). Type a value without the = to write it as it is.";const fh=n=>typeof n==="string"&&n.trimStart().startsWith("=");function vl(n){const e=n.trim();if(e==="")return void 0;if(e.startsWith("@")&&br.test(e.slice(1)))return{[Go]:e.slice(1)};return{[Jt]:e}}function Dw(n,e){if(e===void 0||e===null||e==="")return void 0;if(fh(e))return vl(e.trimStart().slice(1));switch(n.kind){case"switch":return e==="true"?true:e==="false"?false:typeof e==="boolean"?e:void 0;case"choice-or-switch":return e==="true"?true:e==="false"?false:typeof e==="boolean"?e:typeof e==="string"&&n.options?.includes(e)?e:void 0;case"choice":return typeof e==="string"?e:void 0;case"integer":return typeof e==="number"&&Number.isInteger(e)?e:void 0;case"number":return typeof e==="number"&&Number.isFinite(e)?e:void 0;case"length":{const t=String(e).trim();if(t==="")return void 0;return /^\d+(?:\.\d+)?$/.test(t)?Number(t):t}default:return String(e)}}function Ew(n,e,t,o,i={}){const r=es(n,e,i.dockingMode);const s=X(n,e);const a={root:n,selected:e};if(r===null||s===void 0||!t.startsWith("f:"))return a;const l=t.slice(2);const d=i.dockingMode??"roles";const c=f=>{if(r.kind!=="container"||f===n)return{root:f,selected:e};const m=Sn(f,e,d);const g=X(f,e);const y=g===void 0?null:pt(m,g);return{root:m,selected:y??zw(m,e)??[],...(m!==f?{tidied:true}:{})}};if(l==="kind"){if(r.kind!=="tab"||typeof o!=="string"||!dh.includes(o))return a;return{root:Hy(n,e,o,i.registered),selected:e}}if(l==="role"){const f=Bp(n,e,i.dockingMode);if(f!==null)return{...a,locked:f}}if(l==="shell"){const f=Xp(n,e,o===true||o==="true",d);return f.ok?{root:f.root,selected:f.selected}:{...a,blocked:f.reason}}if(l==="sizeUnit"){if(B(s["size"]))return a;return c(Jy(n,e,o==="px"||o==="%"?o:"fr",i.measure))}if(l==="size"){if(fh(o)){const m=vl(o.trimStart().slice(1));return m===void 0?a:c(on(n,e,"size",m))}if(typeof o==="string"){const m=Ny(o);return m===null?a:c(on(n,e,"size",m))}if(typeof o!=="number")return a;const f=Je(s["size"])?.unit??"fr";if(!(Ot(o,f)>0))return a;return c(on(n,e,"size",xn(o,f)))}const p=Tn(r).find(f=>f.key===l);if(!p)return a;let h=Dw(p,o);if(h===void 0&&p.required){if(p.requiredDefault===void 0)return a;h=p.requiredDefault}if(l==="collapsed"&&h===true&&s["collapsed"]!==true){const f=nl(n,e,d);if(f!==null)return{...a,open:f}}const u=on(n,e,l,h);return l==="type"||l==="collapsed"?c(u):{root:u,selected:e}}function zw(n,e){for(let t=e.length;t>=0;t-=2){const o=e.slice(0,t);if(se(n,o)!==null)return o}return null}function Lw(n,e,t="roles"){const o=es(n,e,t);const i=X(n,e);if(o===null||i===void 0)return{};const r=["children","tabs","shell",...uh(o)];return Object.fromEntries(Object.entries(i).filter(([s])=>!r.includes(s)))}function Rw(n,e,t,o="roles"){const i=es(n,e,o);if(i===null)return{ok:false,template:"There is no node to write to.",params:{}};if(!v(t))return{ok:false,template:"The other properties have to be an object: {\"name\": value, ...}.",params:{}};const r=uh(i);const s=Object.keys(t).filter(a=>r.includes(a)||a==="children"||a==="tabs"||a==="shell");if(s.length>0)return{ok:false,template:"The property \"{key}\" has a row in the inspector: change it there.",params:{key:s[0]}};return{ok:true,root:By(n,e,t,r)}}function mh(n){return De(n["title"])||Ur(n)||To[Ye(n)]}const gh=(n,e)=>[.../* @__PURE__ */new Set([...e,...ko(n)])];function Fw(n){const e=/* @__PURE__ */new Map;const t=/* @__PURE__ */new Set;for(const o of n){const i=bi(o);let r=i;for(let s=2;t.has(r);s++)r=`${i}-${s}`;t.add(r);e.set(o,`./${r}.component`)}return e}const bh=(n,e)=>[.../* @__PURE__ */new Set([...ko(n),...e])];function yh(n,e){if(!v(n))return n;if(je(n)){const t=K(n["tabs"]).map(o=>{if(!v(o)||Ye(o)!=="component"||typeof o["componentKey"]!=="string"||o["componentType"]!==void 0)return o;const i=e.get(o["componentKey"]);if(i===void 0)return o;return Object.fromEntries(Object.entries(o).flatMap(([r,s])=>r==="componentKey"?[[r,s],["componentType",{$fn:i}]]:[[r,s]]))});return{...n,tabs:t}}return Array.isArray(n["children"])?{...n,children:n["children"].map(t=>yh(t,e))}:n}function jw(n,e,t="layout"){const o=Ja(ko(n));const i=Us(yh(n,o),Ed(4,150));const r=e?.options.dockingMode==="free"?"// The layout is made for the free docking mode: inject(GfyEngineSettings).setDockingMode('free').\n":"";return`${r}readonly ${t}: GfyDockContainerNodeInput = ${i};`}const Pw=(n="layout")=>`<gfy-docking-engine [defaultLayout]="${n}" />`;function Ww(n){const e=[];const t=(o,i)=>{if(B(o))e.push(i);else if(Array.isArray(o))o.forEach((r,s)=>t(r,[...i,s]));else if(v(o))for(const[r,s]of Object.entries(o))t(s,[...i,r])};t(n,[]);return e}function Kw(n,e,t="layout.json"){const o=gh(n,e.components);const i=Ja(bh(n,e.components));const r=Fw(bh(n,e.components));const s=Fy(n);const a=jy(n);const l=o.length>0||s.length>0;const d=["GfyDockContainerNodeInput","GfyEngineSettings","gfyLoadLayout",...(l?["GfyContentRegistry"]:[])].sort((u,f)=>u.localeCompare(f,"en",{sensitivity:"base"}));const c=["import {inject} from '@angular/core';",`import {${d.join(", ")}} from '@gridify/studio';`];for(const u of o)c.push(`import {${i.get(u)}} from '${r.get(u)}';`);c.push(`// the file is imported as JSON ("resolveJsonModule": true in tsconfig.json)`,`import file from './${t}';`,"");const p=[];if(l)p.push("const registry = inject(GfyContentRegistry);");if(s.length>0){p.push("// a tab saved by a callback finds its content by the key of the callback: the application registers every key, with the HTML or the component it gives (the \"params\" of the file come in the context)");for(const{key:u,title:f}of s){p.push(`registry.registerHtml(${Ue(u)}, () => ${Ue(`<p>TODO: the content of ${f===""?u:f}</p>`)});`);p.push(`// or, for a component: registry.registerComponentFactory(${Ue(u)}, () => ({componentType: YourComponent}));`)}}if(a.length>0){p.push("// a tab that is a custom element makes it with document.createElement: the application defines every tag before the layout is shown");for(const{tag:u}of a)p.push(`// customElements.define(${Ue(u)}, YourElement);`)}const h=Ww(n);if(h.length>0)p.push(`// the file holds code of the application in ${h.length} ${h.length===1?"place":"places"}: the loader leaves it out (and says so), so use the TypeScript output for this layout`);if(o.length>0){p.push("// a tab finds its component by the \"componentKey\": the loader gives it the class, and registers every component of the file");const u=o.map(f=>`${/^[A-Za-z_$][\w$]*$/.test(f)?f:Ue(f)}: ${i.get(f)}`);p.push(`const loaded = gfyLoadLayout(file, {components: {${u.join(", ")}}, registry});`)}else p.push(l?"const loaded = gfyLoadLayout(file, {registry});":"const loaded = gfyLoadLayout(file);");p.push("// the docking mode the layout is made for","inject(GfyEngineSettings).setDockingMode(loaded.dockingMode);","return loaded.layout;");c.push("/** The layout of the file for [defaultLayout]. It calls inject(), so call it in a component: readonly layout = loadLayout(); */","export function loadLayout(): GfyDockContainerNodeInput {",...p.map(u=>` ${u}`),"}");return c.join("\n")}const xl="lye:";const wh=n=>`${xl}${n}`;const _w={showCloseButton:false,allowDetachOnDrag:false,showUndockButton:false,tabMenu:false,showMenuButton:false};const Gw={html:"HTML",component:"Component",element:"Custom element",callback:"Callback"};const vh=n=>n.replace(/[&<>"']/g,e=>({"&":"&amp;","<":"&lt;",">":"&gt;","\"":"&quot;","'":"&#39;"})[e]);function Bw(n,e){const t=Ye(n);const o=Ur(n);const i=t==="html"||o===""?e[t]:`${e[t]}: ${o}`;return`<p><strong>${vh(mh(n))}</strong></p><p style="opacity:0.88">${vh(i)}</p>`}const Vw=n=>Je(n["size"])!==null?n["size"]:50;const xh=n=>typeof n==="boolean"?n:void 0;const Mn=(n,e)=>typeof n==="string"&&e.includes(n)?n:void 0;function sn(n,e,t){if(t!==void 0)n[e]=t}function Hw(n,e){const t=Mn(n["role"],dl);if(e==="free")return t??"panel";if(t==="document"||t==="tool")return t;if(t==="panel"){const o=K(n["tabs"]).filter(v);return o.length>0&&o.every(i=>i["role"]==="tool")?"tool":"document"}return"panel"}function qw(n,e,t){const o={tag:e};sn(o,"role",Mn(n["role"],yi));o["title"]=mh(n);o["content"]=Bw(n,t);if(typeof n["icon"]==="string"&&n["icon"]!=="")o["icon"]=n["icon"];if(Number.isInteger(n["colorIndex"])&&n["colorIndex"]>=0)o["colorIndex"]=n["colorIndex"];sn(o,"contentRole",Mn(n["contentRole"],yi));for(const i of bl){const r=n[i.key];if(r!==void 0&&!B(r)&&ah(i,r)===null)o[i.key]=r}return{...o,..._w}}function Uw(n,e={}){const t=e.lockShell!==false;const o=e.mode??"roles";const i={...Gw,...e.texts};const r=[];let s=0;const a=c=>{r.push(c);return wh(r.length-1)};const l=(c,p)=>{if(!v(c)||Ke(c))return null;const h=a(p);const u={tag:h,size:Vw(c)};sn(u,"resizable",xh(c["resizable"]));sn(u,"collapsed",xh(c["collapsed"]));if(t)sn(u,"shell",c["shell"]===true?true:void 0);if(c["type"]==="panel"){const m={type:"panel",role:Hw(c,o),...u};const g=K(c["tabs"]);const y=[];const b=/* @__PURE__ */new Map;g.forEach((T,k)=>{if(!v(T)||Ke(T))return;b.set(k,y.length);y.push(qw(T,a([...p,"tabs",k]),i));s++});const x=c["activeTab"];m["activeTab"]=(typeof x==="number"?b.get(x):void 0)??0;m["collapsed"]=u["collapsed"]===true;sn(m,"shellHeader",Mn(c["shellHeader"],nh));sn(m,"singleTabHeader",Mn(c["singleTabHeader"],oh));m["tabs"]=y;return m}const f=[];K(c["children"]).forEach((m,g)=>{const y=l(m,[...p,"children",g]);if(y)f.push(y)});return{type:Mn(c["type"],Zr)??"row",...u,children:f}};const d=l(n,[])??{type:"row",size:100,children:[]};return{layout:d,links:{paths:r},tabs:s}}function kl(n,e){if(e===void 0||!e.startsWith(xl))return null;const t=Number(e.slice(xl.length));return Number.isInteger(t)?n.paths[t]??null:null}function ak(n,e){const t=(i,r)=>i.length===r.length&&i.every((s,a)=>s===r[a]);const o=n.paths.findIndex(i=>t(i,e));return o<0?null:wh(o)}const kh=(n,e)=>n===e||JSON.stringify(n)===JSON.stringify(e);function Yw(n,e,t){const o=t||e.collapsed===true?e._baseSize??e.size:e.size;if(typeof o!=="number"||!Number.isFinite(o)||o<=0)return n;const i=e.sizeUnit==="px"||e.sizeUnit==="%"?e.sizeUnit:"fr";const r=Je(n)??{value:50,unit:"fr"};if(r.unit===i&&Ot(r.value,i)===Ot(o,i))return n;return xn(o,i)}function Sh(n,e){e.forEach((t,o)=>{if(Ke(t))n.splice(Math.min(o,n.length),0,t)})}function Jw(n,e,t,o={}){if(!v(n)||!t)return n;const i=a=>{const l=kl(e,a);if(!l)return void 0;let d=n;for(const c of l)d=v(d)||Array.isArray(d)?d[c]:void 0;return v(d)?d:void 0};const r=(a,l,d)=>{const c=i(a.tag);const p=a.type==="panel";const h=c!==void 0&&c["type"]==="panel"===p;const u=h?{...c}:p?{type:"panel",role:o.dockingMode==="free"?"panel":a.role??"document"}:{type:a.type};if(!p&&h&&(a.type==="row"||a.type==="column")&&a.type!==(Mn(c["type"],Zr)??"row"))u["type"]=a.type;if(!l)sn(u,"size",Yw(h?c["size"]:void 0,a,d)??(h?void 0:50));if(!l&&typeof a.resizable==="boolean")u["resizable"]=a.resizable;else if(!l&&h&&typeof c["resizable"]==="boolean")delete u["resizable"];if(p){const f=[];for(const S of a.tabs??[]){const $=i(S.tag);if($)f.push($)}const m=f[a.activeTab??0];const g=h?K(c["tabs"]):[];const y=h&&typeof c["activeTab"]==="number"?c["activeTab"]:0;const b=g[y];const x=g.filter(S=>v(S)&&!Ke(S));const T=!(v(b)&&!Ke(b))&&m===f[0]&&x.length===f.length&&x.every((S,$)=>S===f[$]);if(h)Sh(f,g);u["tabs"]=f;const k=m===void 0?-1:f.indexOf(m);if(!h)u["activeTab"]=k>=0?k:0;else if(k>=0&&k!==y&&!T)u["activeTab"]=k}else{const f=[];const m=(a.children??[]).some(g=>g.collapsed===true);for(const g of a.children??[]){const y=r(g,false,m);if(y)f.push(y)}if(h)Sh(f,K(c["children"]));u["children"]=f}if(a.collapsed===true)u["collapsed"]=true;else if(h&&c["collapsed"]===true||!h&&p)u["collapsed"]=false;return h&&kh(c,u)?c:u};const s=r(t,true,false);return s&&!kh(n,s)?s:n}const Th=(n,e)=>kl(n,e.tag)!==null;function Mh(n,e,t){const o=kl(e,t.tag);const i=o===null?void 0:O(n,o);const r=t.type==="panel";if(!v(i)||i["type"]==="panel"!==r)return[];return K(i[r?"tabs":"children"]).flatMap((s,a)=>Ke(s)?[a]:[])}function ns(n,e){let t=n;for(const o of e)if(o<=t)t++;return t}function $h(n,e,t,o){if(!t)return null;const i=(r,s)=>{if(o(r))return s;const a=Mh(n,e,r);if(r.type==="panel"){let d=0;for(const c of r.tabs??[]){if(!Th(e,c))continue;if(o(c))return[...s,"tabs",ns(d,a)];d++}return null}const l=r.children??[];for(let d=0;d<l.length;d++){const c=i(l[d],[...s,"children",ns(d,a)]);if(c)return c}return null};return i(t,[])}function Xw(n,e,t,o){return o===void 0?null:$h(n,e,t,i=>i.tag===o)}function Zw(n,e,t,o){return o===void 0||o===null||o===""?null:$h(n,e,t,i=>i.id===o)}function Qw(n,e,t,o){if(!t)return null;let i=t;for(let r=0;r<o.length;r+=2){const s=o[r];const a=o[r+1];if(typeof a!=="number")return null;const l=Mh(n,e,i);if(s==="children"){const d=(i.children??[]).find((c,p)=>ns(p,l)===a);if(!d)return null;i=d}else if(s==="tabs"&&r+2===o.length){return(i.tabs??[]).filter(d=>Th(e,d)).find((d,c)=>ns(c,l)===a)??null}else return null}return i}const ev=n=>n.startsWith("_");function tv(n,e,t,o){for(const i of t){if(!oe(n,i.key))continue;const r=ah(i,n[i.key]);if(r)o("error","value",[...e,i.key],r.template,r.params)}}function Sl(n,e,t,o,i,r=[]){const s=new Set(o.map(a=>a.key));tv(n,e,t.filter(a=>!r.includes(a.key)&&(o.includes(a)||!s.has(a.key))),i)}function Tl(n,e,t,o,i){for(const r of Object.keys(n)){if(t.includes(r)||sh.includes(r)||ev(r))continue;if(r==="sizeUnit"&&o!=="a tab"){i("warning","unknown",[...e,r],"A saved layout writes the size as a number and a \"sizeUnit\", and the engine reads it so, but the editor does not: write the size with its unit (\"240px\", \"25%\") instead.");continue}const s=io(r,t);if(s)i("warning","unknown",[...e,r],"The property \"{key}\" is not part of {what}. Did you mean \"{suggestion}\"?",{key:r,what:o,suggestion:s});else i("warning","unknown",[...e,r],"The property \"{key}\" is not part of {what}, so the engine ignores it.",{key:r,what:o})}if(oe(n,"id"))i("info","id",[...e,"id"],"The \"id\" is made by the engine afresh every time the layout is used, so it is ignored. Use a \"tag\" to find the node.")}function Ml(n,e,t,o,i,r){const s=new Set(Tn(o).map(l=>l.key));const a=new Set(i);for(const l of t){if(s.has(l.key)||a.has(l.key)||!l.unused||!oe(n,l.key))continue;a.add(l.key);r("info","unused",[...e,l.key],"The property \"{key}\" is read only for {where}, so the engine does not use it here.",{key:l.key,where:l.unused})}}const nv=/^[A-Za-z_][-A-Za-z0-9_.]*$/;const ov=/^[a-z][-a-z0-9_.]*$/;const iv={html:"HTML",component:"component",element:"custom element",callback:"callback"};const $l=n=>`${n==="html"?"an":"a"} ${iv[n]}`;function Ah(n,e,t){if(!oe(n,"size")){t("warning","size",e,"The node has no \"size\", so the engine gives it the ratio 50.");return}const o=n["size"];if(B(o))return;if(Je(o)===null)t("error","size",[...e,"size"],"The size must be a number, or a number with px, % or fr (30, \"312px\", \"25%\"). The engine replaces anything else by 50.")}function Ch(n,e,t,o){const i=n[e];if(!v(i)||i["resizable"]!==true)return;const r=Je(i["size"]);if(r===null||r.unit==="fr")return;const s=[n[e-1],n[e+1]].some(a=>{if(!v(a)||a["collapsed"]===true||a["resizable"]===false)return false;const l=Je(a["size"]);return l===null||l.unit==="fr"});if(!s)o("warning","resizable",[...t,"resizable"],"This node has a size in {unit} and may be resized, but neither of its neighbours is open and has a ratio to give its room to, so no splitter is drawn.",{unit:r.unit})}function rv(n,e={}){const t=[];const o=e.dockingMode??"roles";const i=e.components;const r=(p,h,u,f,m={})=>{t.push({severity:p,code:h,path:u,template:f,params:m})};if(!v(n)){r("error","root",[],"The layout has to be a container: { \"type\": \"row\", \"size\": 100, \"children\": [ ... ] }.");return t}const s=(p,h,u,f)=>{if(Ke(p)){r("info","code",h,"Code of the application stands for this tab: the editor keeps it as it is, and the Outline and the Preview leave it out.");return}if(!v(p)){r("error","value",h,"A tab must be an object.");return}const m=Ye(p);const g={kind:"tab",tabKind:m,isRoot:false,inShell:f,role:p["role"],dockingMode:o};Sl(p,h,Qr,Tn({...g,inShell:false}),r,m==="callback"?["serialize"]:[]);Tl(p,h,ww.concat(xw),"a tab",r);const y=p["role"];if(o==="roles"&&!f&&(u==="document"||u==="tool")){if(!oe(p,"role")&&u==="document")r("warning","tabRole",h,"The tab has no \"role\": the engine docks it like the documents of its panel, but shows it in the colors of a tool. Set \"role\": \"document\".");else if((y==="document"||y==="tool")&&y!==u)r("warning","tabRole",[...h,"role"],"The tab is a {role}, but the panel is of {panelRole}s. In the mode with roles it belongs to a panel of {role}s.",{role:y,panelRole:u})}const b=y===void 0?"tool":y;if((b==="document"||b==="tool")&&p["contentRole"]===b){r("info","unused",[...h,"contentRole"],"The \"contentRole\" is the role of the tab ({role}), so it changes nothing: it gives the content the palette of the other role.",{key:"contentRole",role:b})}if(!oe(p,"title"))r("warning","title",h,"The tab has no \"title\".");const x=(S,$,A)=>{if(!oe(p,S))return;const R=p[S];if(A==="text"?typeof R!=="string"&&!B(R):!v(R)&&!B(R)){r("error","value",[...h,S],A==="text"?"The property \"{key}\" must be a text.":"The property \"{key}\" must be an object.",{key:S})}else if(m!==$){r("info","unused",[...h,S],"The property \"{key}\" is read only for {where}, so the engine does not use it in {kind} tab.",{key:S,where:`${$l($)} tab`,kind:$l(m)})}};x("content","html","text");x("inputs","component","object");x("componentProps","element","object");const T=m==="callback"?["serialize"]:[];if(m==="component"&&oe(p,"componentTag")){T.push("componentTag");r("info","unused",[...h,"componentTag"],"The tab has a \"componentKey\" (or a class), so the engine makes the component and the \"componentTag\" is not used.")}else if(m==="html"&&oe(p,"componentTag")){T.push("componentTag");r("warning","componentTag",[...h,"componentTag"],"The \"componentTag\" makes a custom element only together with \"kind\": \"component\". Without it the engine shows the tab as HTML.")}Ml(p,h,Qr,{kind:"tab",tabKind:m,isRoot:false,inShell:f,role:p["role"],dockingMode:o},T,r);if(oe(p,"kind")&&p["kind"]!=="component"&&!B(p["kind"])){r("warning","kind",[...h,"kind"],"The engine knows only \"component\" as the \"kind\" of a tab (a custom element), so \"{value}\" is ignored.",{value:De(p["kind"])||JSON.stringify(p["kind"])})}const k=p["callback"];if(m==="callback"){const S=v(k)?k["key"]:void 0;if(!oe(p,"callback"))r("error","callback",[...h,"callback"],"A tab saved by \"callback\" needs {\"key\": \"...\"} of a callback that the application registers. Without it the engine takes the tab for another kind.");else if(v(k)?typeof S!=="string"&&!B(S):!B(k))r("error","callback",[...h,"callback"],"A tab saved by \"callback\" needs {\"key\": \"...\"} of a callback that the application registers.");else if(v(k)&&typeof S==="string"&&S.trim()==="")r("error","callback",[...h,"callback","key"],"The \"key\" of the callback is empty.");if(v(k)&&oe(k,"params")&&!v(k["params"])&&!B(k["params"]))r("error","value",[...h,"callback","params"],"The property \"{key}\" must be an object.",{key:"params"});if(v(k)){for(const $ of Object.keys(k)){if($==="key"||$==="params")continue;r("warning","unknown",[...h,"callback",$],"The property \"{key}\" is not part of {what}, so the engine ignores it.",{key:$,what:"a callback"})}}}else if(oe(p,"callback")){r("info","unused",[...h,"callback"],"The property \"{key}\" is read only for {where}, so the engine does not use it in {kind} tab.",{key:"callback",where:"a tab saved by \"callback\"",kind:$l(m)})}if(oe(p,"componentType"))r("info","componentType",[...h,"componentType"],"A class cannot be part of a file. The name is kept as written; the application can give the class with \"componentKey\" instead.");if(m==="component"){const S=p["componentKey"];if(oe(p,"componentKey")&&typeof S==="string"&&S.trim()===""){r("error","componentKey",[...h,"componentKey"],"The \"componentKey\" is empty.")}else if(!oe(p,"componentKey")&&!oe(p,"componentType")){r("warning","componentKey",h,"A component tab needs a \"componentKey\": the engine makes the component from the registry by it, and without one it shows an empty HTML tab.")}else if(typeof S==="string"&&S.trim()!==""&&i!==void 0&&!i.includes(S)){const $=io(S,i);if($)r("info","registration",[...h,"componentKey"],"The component \"{key}\" is not among the registered components (Layout Options). Did you mean \"{suggestion}\"?",{key:S,suggestion:$});else r("info","registration",[...h,"componentKey"],"The component \"{key}\" is not among the registered components (Layout Options). The application has to register it (GfyContentRegistry).",{key:S})}}if(m==="element"){const S=p["componentTag"];if(!oe(p,"componentTag")||typeof S==="string"&&S.trim()===""){r("error","componentTag",oe(p,"componentTag")?[...h,"componentTag"]:h,"A custom element needs a \"componentTag\" (my-widget). Without it the engine shows an empty HTML tab.")}else if(typeof S==="string"){if(!nv.test(S.trim()))r("error","componentTag",[...h,"componentTag"],"The tag \"{tag}\" is not a name of an element, so the engine shows an error in the tab.",{tag:S});else if(!S.includes("-")||!ov.test(S.trim()))r("warning","componentTag",[...h,"componentTag"],"The tag \"{tag}\" cannot be a custom element: the name has lowercase letters and a dash (my-widget).",{tag:S})}}};const a=(p,h,u,f,m)=>{const g={kind:"panel",isRoot:h.length===0,inShell:m,role:p["role"],dockingMode:o};Sl(p,h,ul,Tn(g),r);Ml(p,h,ul,g,[],r);Tl(p,h,aw,"a panel",r);Ah(p,h,r);Ch(u,f,h,r);if(oe(p,"shell")&&typeof p["shell"]!=="boolean")r("error","value",[...h,"shell"],"The property \"{key}\" must be true or false.",{key:"shell"});const y=p["role"];const b=p["tabs"];if(!oe(p,"role")){r("warning","role",h,"The panel has no \"role\": the engine takes it for neither a panel of documents nor of tools.")}else if(typeof y==="string"&&dl.includes(y)){const T=new Set(K(b).filter(k=>v(k)&&!Ke(k)).flatMap(k=>k["role"]==="document"||k["role"]==="tool"?[k["role"]]:[]));if(o==="roles"&&y==="panel"&&T.size>1)r("warning","role",[...h,"role"],"The role \"panel\" is for the free docking mode, and this panel holds documents and tools: in the mode with roles a panel holds one of them, and the engine refuses to switch to that mode with such a panel. Move the tabs apart in the Preview, then set the role.");else if(o==="roles"&&y==="panel")r("warning","role",[...h,"role"],"The role \"panel\" is for the free docking mode. In the mode with roles a panel is of documents or of tools.");if(o==="free"&&y!=="panel")r("warning","role",[...h,"role"],"The free docking mode has no panels of documents and of tools. Their role is \"panel\".")}if(!oe(p,"activeTab"))r("info","activeTab",h,"The panel has no \"activeTab\": the type of the engine requires it (0, the first tab).");if(!oe(p,"collapsed"))r("info","collapsed",h,"The panel has no \"collapsed\": the type of the engine requires it (false).");if(!Array.isArray(b)){r("error","value",[...h,"tabs"],"The property \"{key}\" must be a list.",{key:"tabs"});return}if(b.length===0&&m)r("warning","empty",h,"The shell panel has no tab, so it shows an empty panel.");const x=p["activeTab"];if(typeof x==="number"&&Number.isInteger(x)&&b.length>0&&x>=b.length){r("warning","activeTab",[...h,"activeTab"],"The \"activeTab\" {index} is past the last tab (the panel has {count} tabs).",{index:x,count:b.length})}b.forEach((T,k)=>s(T,[...h,"tabs",k],y,m))};const l=(p,h,u,f,m)=>{if(Ke(p)){r("info","code",h,"Code of the application stands for this node: the editor keeps it as it is, and the Outline and the Preview leave it out.");return}if(!v(p)){r("error","value",h,"A node must be an object.");return}const g=m||he(p);if(je(p)){a(p,h,u,f,g);return}const y={kind:"container",isRoot:h.length===0,inShell:g,role:p["role"],dockingMode:o};Sl(p,h,hl,Tn(y),r,["type"]);Ml(p,h,hl,y,[],r);Tl(p,h,sw,"a container",r);Ah(p,h,r);Ch(u,f,h,r);if(oe(p,"shell")&&typeof p["shell"]!=="boolean")r("error","value",[...h,"shell"],"The property \"{key}\" must be true or false.",{key:"shell"});const b=p["type"];if(!oe(p,"type")){r("error","type",h,"A node needs a \"type\": \"row\" or \"column\" for a container, \"panel\" for a panel.")}else if(b!=="row"&&b!=="column"){const T=typeof b==="string"?io(b,[...Zr,"panel"]):void 0;if(T)r("error","type",[...h,"type"],"The type \"{type}\" is none of row, column and panel. Did you mean \"{suggestion}\"?",{type:De(b)||JSON.stringify(b),suggestion:T});else r("error","type",[...h,"type"],"The type \"{type}\" is none of row, column and panel.",{type:De(b)||JSON.stringify(b)})}const x=p["children"];if(!Array.isArray(x)){r("error","value",[...h,"children"],"The property \"{key}\" must be a list.",{key:"children"});return}if(x.length===0&&h.length>0&&!Ey(n,h))r("warning","empty",h,"The container has no children, so it shows nothing.");x.forEach((T,k)=>l(T,[...h,"children",k],x,k,g))};l(n,[],[],0,false);const d=o==="free"?"when the layout is shown (the free docking mode)":"at the first docking";for(const p of Ep(n,o)){const h={...p.params,at:d};switch(p.code){case"empty":r("info","tidy",p.path,je(O(n,p.path))?"The panel has no tab: the engine takes it out {at} (in the mode with roles the last panel of documents stays, as the empty document area).":"The {type} has no children: the engine takes it out {at}.",h);break;case"merge":r("info","tidy",p.path,"This {type} stands in a {type} of its own type: the engine merges it into the one around it {at} (its tag and its other properties go), so the layout changes there.",h);break;case"single":r("info","tidy",p.path,"This {type} has one child: the engine puts the child in its place {at} (the {type}, its tag and its other properties go), so the layout changes there.",h);break;case"absorb":r("info","tidy",p.path,"The core holds nothing but this {type}: the engine takes its type and its children into the core {at} (its tag and its other properties go).",h);break;case"open":r("info","collapse",[...p.path,"collapsed"],"Nothing beside this collapsed node in the {type} is open and has a ratio to take its room, so the engine opens it when the layout is shown.",h);break}}const c=new Set(Ep(n,o).filter(p=>p.code==="open").map(p=>q(p.path)));for(const p of Mt(n)){if(p.kind==="tab"||c.has(q(p.path)))continue;const h=O(n,p.path);if(!v(h)||h["collapsed"]!==true)continue;const u=nl(n,p.path,o);if(u!==null&&u!=="alone")r("info","collapse",[...p.path,"collapsed"],tl[u])}for(const p of kn(n)){switch(p.code){case"root":r("error","shell",[...p.path,"shell"],"The root of the layout cannot be a shell: no dockable area would be left.");break;case"edge":r("error","shell",[...p.path,"shell"],"A shell must be the first or the last of its siblings, not at position {index} of the {type}: the shell is the outer edge of the dockable area.",p.params);break;case"all":r("error","shell",p.path,"Every child of this {type} is a shell, so no dockable area is left at this level. Make the shells one container with \"shell\": true.",p.params);break;case"core":r("warning","shell-core",p.path,"This {type} has a shell and {count} nodes beside each other that are not one. The engine gathers them into one container and reports it on the console. Put them in one container.",p.params);break;case"deep":r("warning","shell-deep",[...p.path,"shell"],"This shell stands inside a {type} that is part of the dockable core, not at the outer edge of the layout. The engine does not keep tabs out of it there. Put the node at the edge of the layout (in the Preview, dock its tab to an outer edge), or take its shell off.",p.params);break;case"header":r("error","shell-header",[...p.path,"shellHeader"],"The shell header \"{header}\" shows the first tab only, and the panel has {tabs} tabs. The others are ignored, and the engine reports it on the console.",p.params);break}}return t}const sv={"lye:preview":N("M1.75 8S4 3.75 8 3.75 14.25 8 14.25 8 12 12.25 8 12.25 1.75 8 1.75 8z","M8 6.25a1.75 1.75 0 1 0 0 3.5 1.75 1.75 0 0 0 0-3.5z"),"lye:row":N("M2.5 3h11v10h-11z","M8 3v10"),"lye:column":N("M2.5 3h11v10h-11z","M2.5 8h11"),"lye:panel":N("M2.5 4.5h11V13h-11z","M2.5 4.5V3h4.5v1.5"),"lye:tab-html":N("M6 5 3 8l3 3","M10 5l3 3-3 3"),"lye:tab-component":N("M8 2.5 13 5.25v5.5L8 13.5 3 10.75v-5.5z","M3 5.25 8 8l5-2.75","M8 8v5.5"),"lye:tab-element":N("M5.5 4 2.5 8l3 4","M10.5 4l3 4-3 4","M9 3.5 7 12.5"),"lye:tab-callback":N("M4 3.5c-1.5 0-1.5 1.25-1.5 2.5S2.5 8 1.75 8c.75 0 .75.75.75 2s0 2.5 1.5 2.5","M12 3.5c1.5 0 1.5 1.25 1.5 2.5S13.5 8 14.25 8c-.75 0-.75.75-.75 2s0 2.5-1.5 2.5","M6.5 8h3"),"lye:add-tab":N("M2 13V4.5a1 1 0 0 1 1-1h3l1.25 1.75H13a1 1 0 0 1 1 1V13a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1z","M8 7.5v4.5M5.75 9.75h4.5"),"lye:lock":N("M4.5 7h7v6.5h-7z","M6 7V5a2 2 0 0 1 4 0v2"),"lye:unlock":N("M4.5 7h7v6.5h-7z","M6 7V5a2 2 0 0 1 3.9-.6"),"lye:shell":le(ae("M2.5 3h11v10h-11z","M5.5 3v10"),`<path fill="currentColor" fill-opacity=".3" stroke="none" d="M2.5 3h3v10h-3z"/>`)};const av={...Sa("lye"),...sv};const Oh={html:"lye:tab-html",component:"lye:tab-component",element:"lye:tab-element",callback:"lye:tab-callback"};function lv(n){n.setMany({...av})}const He=Ia();const cv=n=>n;const os={options:{dockingMode:"roles"},components:[]};const xi=(n,e)=>({role:"document",title:n,content:e});const Mo=(n,e)=>({role:"tool",title:n,content:e});const dv=()=>({type:"row",size:100,children:[{type:"panel",tag:"explorer",role:"tool",size:"240px",activeTab:0,collapsed:false,shell:true,tabs:[Mo("Explorer","<p>Files</p>")]},{type:"column",size:100,children:[{type:"panel",tag:"documents",role:"document",size:70,activeTab:0,collapsed:false,tabs:[xi("Welcome","<h1>Welcome</h1>"),{role:"document",title:"Editor",componentKey:"editor"}]},{type:"panel",tag:"output",role:"tool",size:30,activeTab:0,collapsed:false,tabs:[Mo("Output",""),Mo("Problems","")]}]},{type:"panel",tag:"inspector",role:"tool",size:"280px",activeTab:0,collapsed:false,shell:true,tabs:[{role:"tool",title:"Inspector",componentKey:"inspector"}]}]});const pv=()=>({type:"row",size:100,children:[{type:"panel",tag:"left",role:"document",size:50,activeTab:0,collapsed:false,tabs:[xi("Left","<p>Left</p>")]},{type:"panel",tag:"right",role:"document",size:50,activeTab:0,collapsed:false,tabs:[xi("Right","<p>Right</p>")]}]});const hv=()=>({type:"column",size:100,children:[{type:"row",size:100,children:[{type:"panel",tag:"sales",role:"document",size:60,activeTab:0,collapsed:false,tabs:[{role:"document",title:"Sales",componentKey:"sales"}]},{type:"panel",tag:"orders",role:"document",size:40,activeTab:0,collapsed:false,tabs:[{role:"document",title:"Orders",componentKey:"orders"}]}]},{type:"panel",tag:"log",role:"tool",size:"160px",activeTab:0,collapsed:false,resizable:true,tabs:[Mo("Log","")]}]});const uv=()=>({type:"row",size:100,children:[{type:"panel",tag:"kinds",role:"document",size:100,activeTab:0,collapsed:false,tabs:[xi("HTML","<h1>HTML</h1><p>The content is the HTML of the tab.</p>"),{role:"document",title:"Component",componentKey:"customer",inputs:{customerId:7,region:"EU"},placeholder:"Loading the customer…"},{role:"document",title:"Custom element",kind:"component",componentTag:"my-chart",componentProps:{values:[3,5,8],title:"Sales"}},{role:"document",title:"Callback",serialize:"callback",callback:{key:"report",params:{year:2026}},placeholder:"Preparing the report…"}]}]});const fv=()=>({type:"row",size:100,children:[{type:"panel",tag:"a",role:"panel",size:50,activeTab:0,collapsed:false,tabs:[xi("Notes","<p>Notes</p>"),Mo("Tasks","<p>Tasks</p>")]},{type:"panel",tag:"b",role:"panel",size:50,activeTab:0,collapsed:false,tabs:[Mo("Search","<p>Search</p>")]}]});const Nh=[{id:"ide",label:"Workbench (shell and documents)",root:dv(),settings:{...os,components:["editor","inspector"]}},{id:"side-by-side",label:"Two documents",root:pv(),settings:os},{id:"dashboard",label:"Dashboard",root:hv(),settings:{...os,components:["sales","orders"]}},{id:"kinds",label:"Tabs of every kind",root:uv(),settings:{...os,components:["customer"]}},{id:"free",label:"Free docking",root:fv(),settings:{options:{dockingMode:"free"},components:[]}}];const Ih=n=>Nh.find(e=>e.id===n);const mv=["file","json","typescript","template","loader"];const Al="gfy-layout-editor:text";const is="gfy-layout-editor:downloaded";const Cl="gfy-layout-editor:autosave";const gv="gfy-layout-editor:project";const rs="layout.json";class Ui extends jn{static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Ui,deps:null,target:w.ɵɵFactoryTarget.Injectable});static ɵprov=w.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Ui,providedIn:"root"})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Ui,decorators:[{type:Pn,args:[{providedIn:"root"}]}]});const Dh={remove:false,duplicate:false,moveUp:false,moveDown:false};const bv={left:"on the left",right:"on the right",top:"above",bottom:"below"};class ft{toast=L(Ks);box=L(fr);icons=L(Po);project=Ra({noun:"layout",extension:".json",icons:"lye",storageKey:gv,say:e=>this.say(e)});state=E(wo(qa()),...(ngDevMode?[{debugName:"state"}]:([])));root=M(()=>kp(this.state()),...(ngDevMode?[{debugName:"root"}]:([])));notes=M(()=>this.state().notes,...(ngDevMode?[{debugName:"notes"}]:([])));selected=M(()=>this.state().selected,...(ngDevMode?[{debugName:"selected"}]:([])));canUndo=M(()=>lo(this.state().history),...(ngDevMode?[{debugName:"canUndo"}]:([])));canRedo=M(()=>Nr(this.state().history),...(ngDevMode?[{debugName:"canRedo"}]:([])));modified=M(()=>gy(this.state()),...(ngDevMode?[{debugName:"modified"}]:([])));options=M(()=>Sp(this.state()),...(ngDevMode?[{debugName:"options"}]:([])));components=M(()=>my(this.state()),...(ngDevMode?[{debugName:"components"}]:([])));file=M(()=>nw(this.root(),{options:this.options(),components:this.components()}),...(ngDevMode?[{debugName:"file"}]:([])));lockShell=E(true,...(ngDevMode?[{debugName:"lockShell"}]:([])));previewRevision=E(0,...(ngDevMode?[{debugName:"previewRevision"}]:([])));refusals=E(0,...(ngDevMode?[{debugName:"refusals"}]:([])));outputKind=E("file",...(ngDevMode?[{debugName:"outputKind"}]:([])));status=E("",...(ngDevMode?[{debugName:"status"}]:([])));autoSave=E(false,...(ngDevMode?[{debugName:"autoSave"}]:([])));constructor(){lv(this.icons);this.autoSave.set(this.readAutoSave());const e=L(Ui);const t=e.take();if(t!==null){this.state.set(t.state);this.outputKind.set(t.outputKind);this.lockShell.set(t.lockShell);this.project.adopt(t.project)}else if(this.autoSave())this.fresh=!this.restore();else this.fresh=true;if(!this.autoSave())this.forgetText();let o;Q(()=>{const s=this.autoSave();const a=this.file();const l=this.modified();this.project.link();ee(()=>{clearTimeout(o);if(s)o=setTimeout(()=>this.saveText(a,l,true),400);else this.forgetText()})});const i=L(ac).defaultView;const r=s=>{if(this.modified()&&(!this.autoSave()||this.notKept))s.preventDefault()};i?.addEventListener("beforeunload",r);L(lt).onDestroy(()=>{i?.removeEventListener("beforeunload",r);clearTimeout(o);if(this.autoSave())this.saveText(this.file(),this.modified());e.leave({state:this.state(),outputKind:this.outputKind(),lockShell:this.lockShell(),project:this.project.state},this.modified()&&(!this.autoSave()||this.notKept))})}setAutoSave(e){if(e===this.autoSave())return;this.autoSave.set(e);try{if(e)localStorage.setItem(Cl,"1");else localStorage.removeItem(Cl)}catch{}this.notKept=false;if(!e)this.forgetText();this.say(e?"Auto save is on: the file is kept in this browser.":this.modified()?"Auto save is off: nothing of the file is kept. Save or download the file to keep the changes.":"Auto save is off: nothing of the file is kept.")}readAutoSave(){try{return localStorage.getItem(Cl)==="1"}catch{return false}}restore(){try{const e=localStorage.getItem(Al);const t=e?eh(e):null;if(!t?.ok)return false;const o=wo(t.root,null,t.settings??Tp(this.state()));this.state.set(localStorage.getItem(is)==="1"?o:yy(o));this.project.recall();return true}catch{return false}}fresh=false;startWith(e){const t=Ih(e);if(!this.fresh||!t||this.modified()||lo(this.state().history))return;this.fresh=false;this.replaceState(wo(t.root,null,t.settings));this.project.replaced({kind:"sample",name:t.label});this.say(He.text("{name}: a sample to start from. Help > Getting started says how the editor works.",{name:t.label}))}notKept=false;saveText(e,t,o=false){try{localStorage.setItem(Al,e);if(t)localStorage.removeItem(is);else localStorage.setItem(is,"1");this.project.remember();this.notKept=false}catch{this.project.forget();if(o&&!this.notKept)this.warn("Auto save could not keep the file in this browser (its storage is full or turned off). Save or download the file to keep the changes.","layout-editor:autosave");this.notKept=true}}forgetText(){try{localStorage.removeItem(Al);localStorage.removeItem(is)}catch{}this.project.forget()}inspector=M(()=>{const e=this.selected();return e===null?null:Nw(this.root(),e,cv,this.options().dockingMode)},...(ngDevMode?[{debugName:"inspector"}]:([])));otherProperties=M(()=>{const e=this.selected();return e===null?{}:Lw(this.root(),e,this.options().dockingMode)},...(ngDevMode?[{debugName:"otherProperties"}]:([])));capabilities=M(()=>{const e=this.selected();if(e===null||e.length===0)return Dh;const t=this.root();if(se(t,e)===null)return Dh;const o=this.options().dockingMode;return{remove:Hp(t,e,o).root!==t,duplicate:qp(t,e,o).root!==t,moveUp:ll(t,e,-1).root!==t,moveDown:ll(t,e,1).root!==t}},...(ngDevMode?[{debugName:"capabilities"}]:([])));problems=M(()=>{const e=[];const t="layout.json";this.notes().forEach((s,a)=>{e.push({id:`json:note:${a}`,severity:"info",code:"json",message:He.text(s.template,s.params),file:t,path:t,line:s.line,column:s.column,nodePath:null})});const o=this.root();const i=this.components();const r=rv(o,{dockingMode:this.options().dockingMode,components:i.length>0?i:void 0});td(r).forEach((s,a)=>{e.push({id:`${s.code}:${q(s.path)}:${a}`,severity:s.severity,code:s.code,message:He.text(s.template,s.params),file:Jr(o,s.path)||t,path:t,nodePath:vo(o,s.path)})});return e},...(ngDevMode?[{debugName:"problems"}]:([])));counts=M(()=>{const e={panels:0,tabs:0};for(const t of Mt(this.root())){if(t.kind==="panel")e.panels++;else if(t.kind==="tab")e.tabs++}return e},...(ngDevMode?[{debugName:"counts"}]:([])));registered=M(()=>gh(this.root(),this.components()),...(ngDevMode?[{debugName:"registered"}]:([])));output=M(()=>{const e=this.root();const t={options:this.options(),components:this.components()};switch(this.outputKind()){case"file":return this.file();case"json":return th(e);case"typescript":return jw(e,t);case"template":return Pw();case"loader":return Kw(e,t)}},...(ngDevMode?[{debugName:"output"}]:([])));say(e){this.status.set(e)}warn(e,t){this.toast.warning(e,{id:t,closeAfter:5e3})}select(e){this.state.update(t=>vy(t,e))}openProblem(e){if(e.nodePath)this.select(e.nodePath)}replaceState(e){const t=this.root();this.state.set(e);if(this.root()!==t)this.previewRevision.update(o=>o+1)}run(e,t){const o=this.root();this.state.update(r=>Mp(r,e.root,e.selected,{mergeKey:t,now:Date.now()}));const i=this.root()!==o;if(i)this.previewRevision.update(r=>r+1);return i}mergeFromPreview(e,t,o,i){const r=Jw(e,t,o,{dockingMode:this.options().dockingMode});if(r===this.root()||JSON.stringify(r)===JSON.stringify(this.root()))return false;if(Ua(r)<Ua(e)){this.warn("That change would take away a container that holds code of the application (the preview does not show the code), so it is not taken. Make it in the Outline.","layout-editor:preview-code");this.previewRevision.update(s=>s+1);return false}if(kn(r).length>kn(this.root()).length){this.warn("That move would break the shell of the layout (a shell has to stay at the outer edge, beside one core), so it is not taken. Lock the shell to move tabs in the core only.","layout-editor:preview-shell");this.previewRevision.update(s=>s+1);return false}this.state.update(s=>Mp(s,r,void 0,{mergeKey:i,now:Date.now()}));return true}measurer=null;setMeasurer(e){this.measurer=e}addTab(e,t){const o=_y(this.root(),this.selected(),{kind:e,role:t,mode:this.options().dockingMode});if(this.run(o))this.say(He.text("Tab added: {kind} for {role}.",{kind:e==="html"?"HTML":e==="component"?"a component":e==="element"?"a custom element":"a callback",role:t==="document"?"documents":"tools"}))}addPanel(e,t){const o=_p(this.root(),this.selected(),{kind:"component",role:e,side:t,mode:this.options().dockingMode});if(o.refused!==void 0)return this.warn(ol[o.refused],"layout-editor:panel");if(this.run(o))this.say(He.text("Panel added: a panel of {role} {side}, with a component.",{role:e==="document"?"documents":"tools",side:bv[t]}))}canAddPanel(e,t){const o=_p(this.root(),this.selected(),{kind:"component",role:e,side:t,mode:this.options().dockingMode});return o.refused===void 0&&o.root!==this.root()}removeSelected(){const e=this.selected();if(e===null||e.length===0)return;const t=Hp(this.root(),e,this.options().dockingMode);if(t.refused!==void 0)return this.warn(ol[t.refused],"layout-editor:remove");if(this.run(t))this.say("Removed.")}duplicateSelected(){const e=this.selected();if(e===null||e.length===0)return;const t=qp(this.root(),e,this.options().dockingMode);if(t.refused!==void 0)return this.warn(ol[t.refused],"layout-editor:duplicate");if(t.root===this.root())return this.warn("A shell is not copied: the copy would stand beside it and break the edge of the core.","layout-editor:duplicate");if(this.run(t))this.say("Duplicated.")}moveSelected(e){const t=this.selected();if(t===null||t.length===0)return;const o=ll(this.root(),t,e);if(o.root===this.root()){const i=K(O(this.root(),t.slice(0,-1))).length;const r=Pt(t);if(r+e>=0&&r+e<i)this.warn("That would put a shell off the edge of the layout, or a node of the core in among the shells.","layout-editor:move");return}this.run(o)}changeRow(e,t){const o=this.selected();if(o===null)return;const i=e==="f:sizeUnit"?this.measurer?.(o):void 0;const r=Ew(this.root(),o,e,t,{registered:this.components(),measure:i,dockingMode:this.options().dockingMode});const s=r.blocked!==void 0?Ap[r.blocked]:r.locked!==void 0?Gp[r.locked]:r.open!==void 0?tl[r.open]:null;if(s!==null){const a=r.blocked!==void 0?"shell":r.locked!==void 0?"role":"collapse";this.warn(s,`layout-editor:${a}`);this.refusals.update(l=>l+1);return}this.run({root:r.root,selected:r.selected},`row:${e}:${q(o)}`);if(r.tidied)this.say("The layout was tidied as the engine does: a container of the same type as the one around it is merged into it, and one with a single child gives its place to the child.")}setOtherProperties(e){const t=this.selected();if(t===null)return null;const o=Xn(e.trim()===""?"{}":e,{lenient:true});if(!o.ok)return He.text(o.error.template,o.error.params);const i=Rw(this.root(),t,o.value,this.options().dockingMode);if(!i.ok)return He.text(i.template,i.params);this.run({root:i.root,selected:t},`other:${q(t)}`);return null}setPart(e){const t=this.selected();if(t===null)return null;const o=Ow(this.root(),t,e);if(!o.ok)return He.text(o.template,o.params);this.run({root:o.root,selected:t},`part:${q(t)}`);return null}setDockingMode(e){if(e===this.options().dockingMode)return;const t=Uy(this.root(),e);const o=e==="roles"?Yy(t):[];if(o.length>0){const s=o.slice(0,3).map(l=>Jr(t,l)).join("; ");const a=o.length>3?He.text(" and {count} more",{count:o.length-3}):"";this.toast.error(He.text("The layout stays in the free docking mode: a panel that holds both documents and tools has no role in the mode with roles ({where}{more}). Move its tabs into panels of their own role first.",{where:s,more:a}),{id:"layout-editor:docking-mode"});this.refusals.update(l=>l+1);return}const i=e==="free"?zy(t,e):t;const r=this.root();this.state.update(s=>xy(s,{...Sp(s),dockingMode:e},{now:Date.now()},i));if(this.root()!==r)this.previewRevision.update(s=>s+1)}setComponents(e){this.state.update(t=>ky(t,fy(e),{mergeKey:"components",now:Date.now()}))}undo(){this.replaceState(Sy(this.state()))}redo(){this.replaceState(Ty(this.state()))}async mayReplace(){if(!this.modified())return true;return this.box.confirm("Replace the layout you are editing? The changes that were not saved and the steps of undo are lost.",{confirmLabel:"Replace",cancelLabel:"Keep",danger:true})}async newLayout(){if(!(await this.mayReplace()))return;this.replaceState(wo(qa(),null,xp));this.project.replaced(uo);this.say("A new empty layout.")}async loadSample(e){const t=Ih(e);if(!t||!(await this.mayReplace()))return;this.replaceState(wo(t.root,null,t.settings));this.project.replaced({kind:"sample",name:t.label});this.say(He.text("Loaded: {name}.",{name:t.label}))}async loadFromText(e,t,o={kind:"file",name:t}){const i=eh(e);if(!i.ok){const{error:r}=i;this.warn(`${He.text("{name} could not be read as a layout: line {line}.",{name:t,line:r.line})} ${He.text(r.template,r.params)}`,"layout-editor:load");return false}if(!(await this.mayReplace()))return false;this.replaceState(wo(i.root,null,i.settings??Tp(this.state()),i.notes));this.project.replaced(o);this.say(He.text("Loaded: {name}.",{name:t}));return true}async openFromProject(){const e=await this.project.open();if(e!==null&&(await this.loadFromText(e.text,e.path)))this.project.linkTo(e)}async saveToProject(){const e=this.state().history.present;if(await this.project.save(this.file(),rs))this.state.update(t=>fo(t,e))}async saveToProjectAs(){const e=this.state().history.present;if(await this.project.saveAs(this.file(),rs))this.state.update(t=>fo(t,e))}openFile(){void Da(".json,.ts,.txt,application/json,text/plain").then(e=>e?this.loadFromText(e.text,e.name):false)}async pasteLayout(){const e=await Ea();if(e===null)this.warn("The clipboard cannot be read here. Save the text as a file and open it instead.","layout-editor:clipboard");else await this.loadFromText(e,"the clipboard",{kind:"clipboard"})}async copyOutput(){if(await Lr(this.output()))this.toast.success("Copied.",{id:"layout-editor:copied",closeAfter:1500});else this.warn("The clipboard cannot be written here. Select the text of the output and copy it.","layout-editor:clipboard")}downloadFile(){li(this.file(),rs,"application/json");this.downloaded()}downloaded(){if(this.project.linked()===null)this.state.update(by)}downloadOutput(){const e={file:[rs,"application/json"],json:["layout-tree.json","application/json"],typescript:["layout.ts","text/plain"],template:["layout.html","text/html"],loader:["layout-loader.ts","text/plain"]};const[t,o]=e[this.outputKind()];li(this.output(),t,o);if(this.outputKind()==="file")this.downloaded()}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:ft,deps:[],target:w.ɵɵFactoryTarget.Injectable});static ɵprov=w.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:ft})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:ft,decorators:[{type:Pn}],ctorParameters:()=>[]});const yv={id:"layout-editor:help",editor:"Layout editor",pages:[{id:"overview",title:"Overview",icon:"lye:info",blocks:[C.lead("The Layout editor arranges the windows of an application that is built on the docking engine: rows and columns of panels, the tabs in them, which panels hold documents and which hold tools, and the fixed frame around them. It saves a file, and your application gives it to `<gfy-docking-engine>` as the layout to start with."),C.heading("What it is good for"),C.points(["*Design in a live engine.* The Preview is a real docking engine: drag a splitter or a tab there, and the layout follows.","*Every property where it counts.* The Inspector shows what the engine reads for the selected container, panel or tab, with its default and what it does.","*The rules kept for you.* A command that would break the shell or the roles is grey (a row of the Inspector says why), and the *Problems* window tells what the engine would refuse or change by itself."]),C.heading("What a file holds"),C.terms([["Containers","A `row` or a `column` that shares its place among its children. The root is a container."],["Panels","A place with tabs. In the mode with roles a panel holds documents or tools, and a tab docks only to a panel of its role."],["Tabs","What a panel shows: HTML, a component of your application (by its key), a custom element, or a callback."],["Shell","The fixed outer frame (a bar of tools, a side bar…): nothing is docked into it or out of it."],["Sizes","A ratio (`1`, `30fr`), a length (`240px`) or a share of the container (`25%`)."],["Docking mode","`roles` (documents and tools apart, the default) or `free` (any tab anywhere), in the *Layout Options*."]]),C.heading("In your application"),C.text("The *Output* window writes the code that loads the file (*Loader*, downloaded as `layout-loader.ts`): it gives the tabs the classes of their components, registers them and sets the docking mode."),C.code("ts","import {loadLayout} from './layout-loader';\n\nreadonly layout = loadLayout();"),C.code("html","<gfy-docking-engine [defaultLayout]=\"layout\" />"),C.heading("The windows"),C.terms([["Outline","The tree of containers, panels and tabs. Its toolbar adds tabs, duplicates, moves and removes; its context menu adds panels too."],["Preview","The layout in a real engine, with a placeholder in every tab."],["Inspector","The properties of the selected node, the content of a tab, and what no row holds (Other properties)."],["Layout Options","The docking mode, and the components your application registers."],["Output","The file, the bare layout, TypeScript, the template and the code that loads the file."],["Problems","What cannot be read, and what the engine would refuse or change. A double click goes there."]]),C.heading("Good to know"),C.points(["The editor starts empty (Gridify Designer opens the sample of a workbench), and nothing is kept by itself: *File > Download the file* ([Ctrl+S]) saves the file, and with *File > Auto save* on the browser keeps it for the next visit.","An application that gives the editor the files of a project (*Files* in the header of Gridify Designer) adds *File > Open from the project…* ([Ctrl+O]), *Save* ([Ctrl+S]) and *Save as…* ([Ctrl+Shift+S]): Save writes the layout back into the file it came from, and asks first when that file was changed in the meantime. *Help > Files…* says how it works, and how to write a server of your own.","The title in the middle of the menu bar names the layout: its file of the project, or where it came from (*New layout*, *Sample: …*, the name of a file of this computer, *From the clipboard*), with a dot while it has changes that were not saved.","The editor does not run the components of your application: a tab of the Preview shows a placeholder.","The lock in the toolbar of the Preview (*View > Lock the shell in the preview*) keeps the shell as your application shows it; unlocked, tabs can be moved into and out of the shell panels too.","The windows of the editor are panels of a docking engine as well: drag a tab to move a window; *View > Reset the windows* puts them back."])]},{id:"start",title:"Getting started",icon:"lye:flag",blocks:[C.lead("From an empty editor to the layout your application starts with, in a few steps."),C.steps([["Start from something","*File > Samples* has a workbench with a shell, two documents side by side, a dashboard, a tab of every kind and the free mode. *File > Open file* ([Ctrl+O]) opens your own; a layout can also be pasted from the clipboard or dropped on the window. *File > New layout* starts afresh."],["Choose the docking mode","In the *Layout Options*: `roles` keeps documents and tools apart, `free` docks any tab anywhere. List the components of your application there too."],["Add tabs and panels","*Add tool* and *Add document* add a tab to the selected panel; *New tool panel* and *New document panel* put a new panel on a side of the selected node. A right click in the Preview offers them right where you want them."],["Arrange in the Preview","Drag the splitters, drag the tabs to other panels or to the edges, collapse panels: every change is written into the layout, as a step of undo."],["Set the properties","Select a node and change it in the *Inspector*: the size and its unit, the title and the content of a tab, whether it can be closed, dragged or floated, the shell…"],["Take it to your application","Download the file ([Ctrl+S]); the *Output* window has the code that loads it (*Loader*). Mend first what the *Problems* window lists."]]),C.note("A command that cannot be used where you are is grey, and the description of a grey row in the Inspector says why.")]},{id:"guides",title:"How-to guides",icon:"lye:guides",blocks:[C.lead("Short recipes for what a layout can do beyond the first steps. Each one names the windows and the rows of the *Inspector* it uses; the description under the grid of the Inspector says more about every row."),C.heading("A frame that stays (the shell)"),C.steps([["Choose its panels","Select a panel or a container at the edge (a bar of tools, a side bar) and check *Shell* in its menu: a right click in the *Preview* or in the *Outline*. Nothing is docked into the shell or out of it; the rest is the dockable core."],["Lock it in the Preview","The lock in the toolbar of the *Preview* (*View > Lock the shell in the preview*) keeps the shell as your application shows it. Unlocked, tabs can be moved into and out of the shell panels too."]]),C.note("A command that would break the rules of the shell is grey, and the *Problems* window tells what the engine would refuse."),C.heading("Documents and tools apart"),C.text("In the docking mode `roles` (*Layout Options*), a tab is a document or a tool and docks only to a panel of its role. *Add document* and *Add tool* choose the role, and it stays; *New document panel* and *New tool panel* put a panel of that role on a side of the selected node. In the mode `free` any tab docks anywhere."),C.heading("A tab with a component of your application"),C.steps([["Add the tab","*Add tool* or *Add document* adds a tab for a component; the row `componentKey` of the *Inspector* is the key it is found by."],["Register the key","List the components of your application in the *Layout Options* (`editor, explorer`): the *Problems* window tells a key that is not there."],["Give the classes","The *Loader* of the *Output* window imports a class for every key (the names are a guess: point them at your components) and gives them to `gfyLoadLayout`, which registers them."]]),C.heading("When your application saves the layout"),C.points(["An engine keeps the layout only when your application asks for it: `GfyEngineSettings.setAutoSaveLayout(true)` saves after every change, `engine.saveLayout()` when you call it. At the next visit the engine starts from what was saved under `layoutStorageKey`; the shell always comes from the file.","So a user who has a saved layout does not see a new layout file: when you ship one, change `layoutStorageKey` (`app-layout-2`), or call `engine.resetLayout()`. With `[layoutStorageKey]=\"null\"` nothing is kept at all."]),C.heading("What the engine changes by itself"),C.text("When a tab is docked, the engine tidies the layout: it takes out an empty panel (in the mode `roles` the last panel of documents stays: it is the empty document area) and an empty container, and merges a container into the one around it when both go the same way. The *Preview* is that engine, so a panel that is left empty there goes, and the *Problems* window tells what the engine would change.")]},Ha({icon:"lye:project-folder",noun:"layout",component:"LayoutEditor",selector:"layout-editor"}),{id:"keys",title:"Keyboard and mouse",icon:"lye:keyboard",blocks:[C.heading("In the Preview"),C.keys([["Click","Select a tab, a panel (a click into its body) or a container (a click on its splitter)."],["Drag a splitter or a tab, collapse a panel","Change the layout; every change is a step of undo."],["Right click, [Shift+F10], [Menu]","The menu of the node: add a tab or a panel right there, duplicate, move, remove."],["[Delete], [Backspace]","Remove the selected node."]]),C.heading("In the Outline"),C.keys([["Click","Select a node."],["Right click, [Shift+F10], [Menu]","The menu of the node, the same as in the Preview."],["[Delete], [Backspace]","Remove the selected node."]]),C.heading("The other windows"),C.keys([["Double click a problem, or [Enter]","Go to its node (a problem of the whole file has none)."]]),C.heading("Everywhere"),C.keys([["[Ctrl+Z], [Ctrl+Y]","Undo, redo (in a text field: the typing)."],["[Ctrl+D]","Duplicate the selected node."],["[Alt+Up], [Alt+Down]","Move it earlier or later."],["[Ctrl+O]","Open a file (with the files of a project: a file of the project)."],["[Ctrl+S]","Download the file (with the files of a project: save it into its file of the project)."],["[Ctrl+Shift+S]","Save as… (with the files of a project)."]])]}]};function Ol(n){return[{label:"Add &tool",icon:"gfy:tool",run:()=>n.addTab("component","tool")},{label:"Add d&ocument",icon:"gfy:document",run:()=>n.addTab("component","document")}]}const wv=[{side:"left",label:"&Left"},{side:"right",label:"&Right"},{side:"top",label:"&Above"},{side:"bottom",label:"&Below"}];function Eh(n,e){const t=e===null||e.length===0||se(n.root(),e)===null?null:e;const o=s=>wv.map(({side:a,label:l})=>({label:l,enabled:t!==null&&n.canAddPanel(s,a),run:()=>n.addPanel(s,a)}));const i=o("tool");const r=o("document");return[{label:"New tool pan&el",icon:"gfy:tool",enabled:i.some(s=>s.enabled),children:i},{label:"New document pa&nel",icon:"gfy:document",enabled:r.some(s=>s.enabled),children:r}]}function zh(n,e){const t=e===null?null:se(n.root(),e);if(e===null||t!=="container"&&t!=="panel"||e.length===0)return[];const o=X(n.root(),e);const i=o!==void 0&&he(o);return[{label:"S&hell",icon:"lye:shell",checked:i,enabled:i||Xa(n.root(),e)===null,run:()=>n.changeRow("f:shell",!i)}]}function Nl(n,e){n.select(e);const t=n.capabilities();const o=[...Ol(n),...Eh(n,e),...zh(n,e)];o.push({separator:true});o.push({label:"Dup&licate",icon:"lye:duplicate",shortcut:"Mod+D",enabled:t.duplicate,run:()=>n.duplicateSelected()});o.push({label:"Move &up",icon:"lye:up",shortcut:"Alt+Up",enabled:t.moveUp,run:()=>n.moveSelected(-1)});o.push({label:"Move &down",icon:"lye:down",shortcut:"Alt+Down",enabled:t.moveDown,run:()=>n.moveSelected(1)});o.push({separator:true});o.push({label:"&Remove",icon:"lye:remove",shortcut:"Del",enabled:t.remove,run:()=>n.removeSelected()});return o}class Yi{store=L(ft);rows=M(()=>this.store.inspector()?.rows??[],{...(ngDevMode?{debugName:"rows"}:({})),equal:(e,t)=>JSON.stringify(e)===JSON.stringify(t)});typed=E({},...(ngDevMode?[{debugName:"typed"}]:([])));values=M(()=>{this.store.refusals();return{...(this.store.inspector()?.values??{}),...this.typed()}},...(ngDevMode?[{debugName:"values"}]:([])));active=E(null,...(ngDevMode?[{debugName:"active"}]:([])));describing=M(()=>this.rows().some(e=>e.id===this.active()),...(ngDevMode?[{debugName:"describing"}]:([])));otherOpen=E(false,...(ngDevMode?[{debugName:"otherOpen"}]:([])));partOpen=E(true,...(ngDevMode?[{debugName:"partOpen"}]:([])));node=M(()=>{const e=this.store.selected();return e===null?void 0:O(this.store.root(),e)},...(ngDevMode?[{debugName:"node"}]:([])));kindLabel=M(()=>{const e=this.store.inspector();const t=this.node();switch(e?.kind){case"container":return v(t)&&t["type"]==="column"?"Column":"Row";case"panel":return"Panel";case"tab":return e.tabKind===void 0?"Tab":`${To[e.tabKind]} tab`;default:return""}},...(ngDevMode?[{debugName:"kindLabel"}]:([])));icon=M(()=>{const e=this.store.inspector();const t=this.node();switch(e?.kind){case"container":return v(t)&&t["type"]==="column"?"lye:column":"lye:row";case"tab":return e.tabKind===void 0?"lye:tab-html":Oh[e.tabKind];default:return"lye:panel"}},...(ngDevMode?[{debugName:"icon"}]:([])));where=M(()=>{const e=this.store.selected();return e===null?"":Jr(this.store.root(),e)},...(ngDevMode?[{debugName:"where"}]:([])));canReset=M(()=>{const e=this.active();const t=e===null?void 0:this.values()[e];return e!==null&&t!==void 0&&t!==""&&this.rows().some(o=>o.id===e&&!o.disabled&&!o.required&&!(o.kind==="boolean"&&t===o.defaultValue))},...(ngDevMode?[{debugName:"canReset"}]:([])));draft=E(null,...(ngDevMode?[{debugName:"draft"}]:([])));otherError=E(null,...(ngDevMode?[{debugName:"otherError"}]:([])));otherText=M(()=>this.draft()??Zn(this.store.otherProperties(),2,60),...(ngDevMode?[{debugName:"otherText"}]:([])));partDraft=E(null,...(ngDevMode?[{debugName:"partDraft"}]:([])));partError=E(null,...(ngDevMode?[{debugName:"partError"}]:([])));partText=M(()=>this.partDraft()??this.store.inspector()?.part?.text??"",...(ngDevMode?[{debugName:"partText"}]:([])));constructor(){Q(()=>{this.store.selected();ee(()=>{this.draft.set(null);this.otherError.set(null);this.typed.set({})})});Q(()=>{this.store.inspector()?.part?.key;this.store.selected();ee(()=>{this.partDraft.set(null);this.partError.set(null)})});Q(()=>{const e=Object.keys(this.store.otherProperties()).length>0;ee(()=>{if(e)this.otherOpen.set(true)})})}onChange(e){if(this.rows().some(t=>t.id===e.id&&(t.kind==="text"||t.kind==="number")))this.typed.update(t=>({...t,[e.id]:e.value}));this.store.changeRow(e.id,e.value)}endTyping(){if(Object.keys(this.typed()).length>0)this.typed.set({})}reset(){const e=this.active();if(e===null)return;this.typed.update(({[e]:t,...o})=>o);this.store.changeRow(e,void 0)}onOther(e){if(e===this.otherText())return;this.draft.set(e);this.otherError.set(this.store.setOtherProperties(e))}endDraft(){if(this.otherError()===null)this.draft.set(null)}onPart(e){if(e===this.partText())return;this.partDraft.set(e);this.partError.set(this.store.setPart(e))}endPartDraft(){if(this.partError()===null)this.partDraft.set(null)}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Yi,deps:[],target:w.ɵɵFactoryTarget.Component});static ɵcmp=w.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"21.2.21",type:Yi,isStandalone:true,selector:"lye-inspector",ngImport:w,template:`
880
+ @if (store.inspector(); as inspector) {
881
+ <div class="head">
882
+ <span class="ic" [gfyIcon]="icon()"></span>
883
+ <span class="kind">{{ kindLabel() }}</span>
884
+ <span class="where" [attr.title]="where()">{{ where() }}</span>
885
+ <gfy-button appearance="flat" iconOnly icon="gfy:close" label="Reset the property" [disabled]="!canReset()" (pressed)="reset()" />
886
+ </div>
887
+ <gfy-property-grid edFitNames [properties]="rows()" [values]="values()" [(active)]="active" [showDescription]="describing()" (propertyChanged)="onChange($event)" (focusout)="endTyping()" ariaLabel="Properties" />
888
+ @if (inspector.part; as part) {
889
+ <div class="other">
890
+ <gfy-expander [heading]="part.label" [(expanded)]="partOpen" appearance="plain">
891
+ <div class="other-hint">{{ part.description }}</div>
892
+ <div class="other-editor" (focusout)="endPartDraft()">
893
+ <gfy-code-editor [language]="part.language" [tabSize]="2" [lineNumbers]="false" [highlightCurrentLine]="false" [ariaLabel]="part.label" [value]="partText()" (valueChange)="onPart($event)" />
894
+ </div>
895
+ @if (partError(); as message) {
896
+ <div class="other-error" role="alert">{{ message }}</div>
897
+ }
898
+ </gfy-expander>
899
+ </div>
900
+ }
901
+ <div class="other">
902
+ <gfy-expander heading="Other properties (JSON)" [(expanded)]="otherOpen" appearance="plain">
903
+ <div class="other-hint">What the rows and the part above do not hold: properties that your application adds, and properties that are set where the engine does not read them (they are kept, and the Problems window tells).</div>
904
+ <div class="other-editor" (focusout)="endDraft()">
905
+ <gfy-code-editor language="json" [tabSize]="2" [lineNumbers]="false" [highlightCurrentLine]="false" ariaLabel="Other properties" [value]="otherText()" (valueChange)="onOther($event)" />
906
+ </div>
907
+ @if (otherError(); as message) {
908
+ <div class="other-error" role="alert">{{ message }}</div>
909
+ }
910
+ </gfy-expander>
911
+ </div>
912
+ } @else {
913
+ <div class="empty">Select a container, a panel or a tab in the Outline or in the Preview.</div>
914
+ }
915
+ `,isInline:true,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n",".ic{flex:none;display:grid;width:var(--ic, 14px);height:var(--ic, 14px)}\n",".head{flex:none;display:flex;align-items:center;gap:8px;padding:6px 10px;background:var(--gfy-bg-header, transparent);border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3))}.head .ic{--ic: 16px;color:var(--gfy-accent, #3a8fd6)}.head .kind{font-weight:600}.head .where{min-width:0;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;opacity:.88}gfy-property-grid{flex:1 1 auto;min-height:96px}.other{flex:0 1 auto;min-height:30px;overflow:auto;border-top:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3))}.other-editor{height:130px;border-top:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3))}.other-error{padding:4px 10px;color:var(--gfy-danger, #e51400);font-size:12px}.other-hint{padding:4px 10px;font-size:12px;opacity:.88}\n"],dependencies:[{kind:"component",type:ke,selector:"gfy-button",inputs:["label","icon","iconOnly","tooltip","ariaLabel","caret","variant","appearance","layout","toggle","checked","disabled","busy","type","name","haspopup","expanded","controls","joined","attached","reserveLabelSpace"],outputs:["checkedChange","pressed"]},{kind:"component",type:Wn,selector:"gfy-code-editor",inputs:["value","highlight","language","candidates","tokenColors","lineNumbers","tabSize","insertSpaces","readonly","disabled","ariaLabel","lineHeight","marks","highlightCurrentLine","focusFrame","contextMenu"],outputs:["valueChange","cursorMoved","languageDetected"]},{kind:"component",type:Yt,selector:"gfy-expander",inputs:["heading","description","icon","expanded","disabled","appearance","chevronAt","level","keepContent"],outputs:["expandedChange"]},{kind:"directive",type:mt,selector:"[gfyIcon]",inputs:["gfyIcon"]},{kind:"component",type:Tt,selector:"gfy-property-grid",inputs:["properties","values","view","nameWidth","showDescription","showToolbar","filter","collapsed","active","disabled","ariaLabel"],outputs:["valuesChange","viewChange","nameWidthChange","filterChange","collapsedChange","activeChange","propertyChanged"]},{kind:"directive",type:st,selector:"gfy-property-grid[edFitNames]"}]})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Yi,decorators:[{type:me,args:[{selector:"lye-inspector",standalone:true,imports:[ke,Wn,Yt,mt,Tt,st],template:`
916
+ @if (store.inspector(); as inspector) {
917
+ <div class="head">
918
+ <span class="ic" [gfyIcon]="icon()"></span>
919
+ <span class="kind">{{ kindLabel() }}</span>
920
+ <span class="where" [attr.title]="where()">{{ where() }}</span>
921
+ <gfy-button appearance="flat" iconOnly icon="gfy:close" label="Reset the property" [disabled]="!canReset()" (pressed)="reset()" />
922
+ </div>
923
+ <gfy-property-grid edFitNames [properties]="rows()" [values]="values()" [(active)]="active" [showDescription]="describing()" (propertyChanged)="onChange($event)" (focusout)="endTyping()" ariaLabel="Properties" />
924
+ @if (inspector.part; as part) {
925
+ <div class="other">
926
+ <gfy-expander [heading]="part.label" [(expanded)]="partOpen" appearance="plain">
927
+ <div class="other-hint">{{ part.description }}</div>
928
+ <div class="other-editor" (focusout)="endPartDraft()">
929
+ <gfy-code-editor [language]="part.language" [tabSize]="2" [lineNumbers]="false" [highlightCurrentLine]="false" [ariaLabel]="part.label" [value]="partText()" (valueChange)="onPart($event)" />
930
+ </div>
931
+ @if (partError(); as message) {
932
+ <div class="other-error" role="alert">{{ message }}</div>
933
+ }
934
+ </gfy-expander>
935
+ </div>
936
+ }
937
+ <div class="other">
938
+ <gfy-expander heading="Other properties (JSON)" [(expanded)]="otherOpen" appearance="plain">
939
+ <div class="other-hint">What the rows and the part above do not hold: properties that your application adds, and properties that are set where the engine does not read them (they are kept, and the Problems window tells).</div>
940
+ <div class="other-editor" (focusout)="endDraft()">
941
+ <gfy-code-editor language="json" [tabSize]="2" [lineNumbers]="false" [highlightCurrentLine]="false" ariaLabel="Other properties" [value]="otherText()" (valueChange)="onOther($event)" />
942
+ </div>
943
+ @if (otherError(); as message) {
944
+ <div class="other-error" role="alert">{{ message }}</div>
945
+ }
946
+ </gfy-expander>
947
+ </div>
948
+ } @else {
949
+ <div class="empty">Select a container, a panel or a tab in the Outline or in the Preview.</div>
950
+ }
951
+ `,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n",".ic{flex:none;display:grid;width:var(--ic, 14px);height:var(--ic, 14px)}\n",".head{flex:none;display:flex;align-items:center;gap:8px;padding:6px 10px;background:var(--gfy-bg-header, transparent);border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3))}.head .ic{--ic: 16px;color:var(--gfy-accent, #3a8fd6)}.head .kind{font-weight:600}.head .where{min-width:0;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;opacity:.88}gfy-property-grid{flex:1 1 auto;min-height:96px}.other{flex:0 1 auto;min-height:30px;overflow:auto;border-top:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3))}.other-editor{height:130px;border-top:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3))}.other-error{padding:4px 10px;color:var(--gfy-danger, #e51400);font-size:12px}.other-hint{padding:4px 10px;font-size:12px;opacity:.88}\n"]}]}],ctorParameters:()=>[]});const vv={roles:"Roles (documents and tools)",free:"Free (any tab in any panel)"};class Ji{store=L(ft);active=E(null,...(ngDevMode?[{debugName:"active"}]:([])));describing=M(()=>this.rows.some(e=>e.id===this.active()),...(ngDevMode?[{debugName:"describing"}]:([])));draft=E(null,...(ngDevMode?[{debugName:"draft"}]:([])));rows=[{id:"dockingMode",label:"dockingMode",kind:"select",category:"Engine",options:hy.map(e=>({value:e,label:vv[e]})),defaultValue:"roles",description:"The docking mode the layout is made for (inject(GfyEngineSettings).setDockingMode), and the one the Preview runs in: in the free mode any tab docks anywhere there, too. Switching it converts the roles of the panels in the same step of undo: the neutral role panel in the free mode (which keeps no empty panel), the role of their tabs in the mode with roles. The way back to the roles is not made while a panel holds both documents and tools (the message says which): move the tabs into panels of their own role first."},{id:"components",label:"components",kind:"text",category:"Components",placeholder:"editor, explorer",defaultValue:"",description:"The keys of the components your application registers with GfyContentRegistry, separated by commas. A tab of a component whose key is not here is reported (as information); the loader of the output gives gfyLoadLayout a class for these keys and the ones the tabs use, and so registers them (the TypeScript output names the class of a tab beside its key instead, and the engine registers it by itself)."},{id:"used",label:"usedComponents",kind:"readonly",category:"Components",description:"The keys the tabs of the layout name (componentKey), in the order of the layout. A tab that becomes a component takes the key of its title when it is registered."}];values=M(()=>{this.store.refusals();return{dockingMode:this.store.options().dockingMode,components:this.draft()??this.store.components().join(", "),used:ko(this.store.root()).join(", ")||"(none)"}},...(ngDevMode?[{debugName:"values"}]:([])));onChange(e){if(e.id==="dockingMode")this.store.setDockingMode(e.value==="free"?"free":"roles");else if(e.id==="components"){const t=typeof e.value==="string"?e.value:"";this.draft.set(t);this.store.setComponents(t)}}endDraft(){this.draft.set(null)}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Ji,deps:[],target:w.ɵɵFactoryTarget.Component});static ɵcmp=w.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"21.2.21",type:Ji,isStandalone:true,selector:"lye-options",ngImport:w,template:`
952
+ <div class="hint">These belong to the layout but are not part of it: they decide what the roles mean, which checks apply, and what the loader of the output registers.</div>
953
+ <gfy-property-grid edFitNames [properties]="rows" [values]="values()" [(active)]="active" [showDescription]="describing()" (propertyChanged)="onChange($event)" (focusout)="endDraft()" ariaLabel="Layout Options" />
954
+ `,isInline:true,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n","gfy-property-grid{flex:1 1 auto;min-height:0}\n"],dependencies:[{kind:"component",type:Tt,selector:"gfy-property-grid",inputs:["properties","values","view","nameWidth","showDescription","showToolbar","filter","collapsed","active","disabled","ariaLabel"],outputs:["valuesChange","viewChange","nameWidthChange","filterChange","collapsedChange","activeChange","propertyChanged"]},{kind:"directive",type:st,selector:"gfy-property-grid[edFitNames]"}]})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Ji,decorators:[{type:me,args:[{selector:"lye-options",standalone:true,imports:[Tt,st],template:`
955
+ <div class="hint">These belong to the layout but are not part of it: they decide what the roles mean, which checks apply, and what the loader of the output registers.</div>
956
+ <gfy-property-grid edFitNames [properties]="rows" [values]="values()" [(active)]="active" [showDescription]="describing()" (propertyChanged)="onChange($event)" (focusout)="endDraft()" ariaLabel="Layout Options" />
957
+ `,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n","gfy-property-grid{flex:1 1 auto;min-height:0}\n"]}]}]});const xv={error:"var(--gfy-danger, #e51400)",warning:"var(--gfy-warning, #d9a300)",info:"var(--gfy-accent, #3794ff)"};function kv(n){if(n.kind==="tab")return n.title||n.componentKey||`(${To[n.type]??n.type})`;if(n.kind==="container")return n.depth===0?"Layout":n.tag||n.type||"row";return n.tag||"Panel"}function Sv(n){const e=[];if(n.kind==="container")e.push(n.type||"row");else if(n.kind==="panel")e.push(n.type||"no role");else e.push(To[n.type]===void 0?n.type:`${To[n.type]} ${n.componentKey}`.trim());if(n.ownShell)e.push("shell");return e.join(", ")}function Tv(n){if(n.kind==="tab")return Oh[n.type]??"lye:tab-html";if(n.kind==="panel")return"lye:panel";return n.type==="column"?"lye:column":"lye:row"}class Xi{store=L(ft);icons=L(Po);addItems=Ol(this.store);expanded=E(/* @__PURE__ */new Set,...(ngDevMode?[{debugName:"expanded"}]:([])));known=/* @__PURE__ */new Set;selectedKey=M(()=>{const e=this.store.selected();return e===null?null:q(e)},...(ngDevMode?[{debugName:"selectedKey"}]:([])));marks=M(()=>{const e=/* @__PURE__ */new Map;const t={error:0,warning:1,info:2};for(const o of this.store.problems()){const i=o.severity;if(!o.nodePath||i===void 0||i==="info")continue;const r=q(o.nodePath);const s=e.get(r);if(s===void 0||t[i]<t[s])e.set(r,i)}return e},...(ngDevMode?[{debugName:"marks"}]:([])));nodes=M(()=>{const e=this.marks();const t=[];const o=[];for(const i of Mt(this.store.root())){const r=q(i.path);const s=e.get(r);const a=Tv(i);const l=[];const d={id:r,label:kv(i),icon:this.icons.has(a)?a:void 0,iconColor:s?xv[s]:void 0,description:Sv(i),children:l};while(o.length>0&&o[o.length-1].depth>=i.depth)o.pop();(o.length>0?o[o.length-1].children:t).push(d);o.push({depth:i.depth,children:l})}return t},...(ngDevMode?[{debugName:"nodes"}]:([])));constructor(){Q(()=>{const e=Mt(this.store.root());ee(()=>{const t=new Set(this.expanded());let o=false;for(const i of e){const r=q(i.path);if(this.known.has(r))continue;this.known.add(r);if(i.kind!=="tab"&&!t.has(r)){t.add(r);o=true}}if(o)this.expanded.set(t)})});Q(()=>{const e=this.store.selected();if(e===null)return;ee(()=>{const t=new Set(this.expanded());let o=false;for(let i=0;i<e.length;i+=2){const r=q(e.slice(0,i));if(!t.has(r)){t.add(r);o=true}}if(o)this.expanded.set(t)})})}onSelected(e){if(e!==null)this.store.select(Un(e))}onKey(e){const t=e.event.key;const o=e.event.ctrlKey||e.event.metaKey;if(t==="Delete"||t==="Backspace")this.store.removeSelected();else if(o&&t.toLowerCase()==="d")this.store.duplicateSelected();else if(e.event.altKey&&t==="ArrowUp")this.store.moveSelected(-1);else if(e.event.altKey&&t==="ArrowDown")this.store.moveSelected(1);else return;e.event.preventDefault()}menu=e=>Nl(this.store,Un(e.id));static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Xi,deps:[],target:w.ɵɵFactoryTarget.Component});static ɵcmp=w.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"21.2.21",type:Xi,isStandalone:true,selector:"lye-outline",ngImport:w,template:`
958
+ <div class="tb">
959
+ <gfy-button appearance="flat" iconOnly icon="lye:undo" label="Undo" [disabled]="!store.canUndo()" (pressed)="store.undo()" />
960
+ <gfy-button appearance="flat" iconOnly icon="lye:redo" label="Redo" [disabled]="!store.canRedo()" (pressed)="store.redo()" />
961
+ <span class="sep" aria-hidden="true"></span>
962
+ <gfy-dropdown-button appearance="flat" iconOnly icon="lye:add-tab" label="Add tab" [items]="addItems" />
963
+ <span class="sep" aria-hidden="true"></span>
964
+ <gfy-button appearance="flat" iconOnly icon="lye:duplicate" label="Duplicate" [disabled]="!store.capabilities().duplicate" (pressed)="store.duplicateSelected()" />
965
+ <gfy-button appearance="flat" iconOnly icon="lye:up" label="Move up" [disabled]="!store.capabilities().moveUp" (pressed)="store.moveSelected(-1)" />
966
+ <gfy-button appearance="flat" iconOnly icon="lye:down" label="Move down" [disabled]="!store.capabilities().moveDown" (pressed)="store.moveSelected(1)" />
967
+ <gfy-button appearance="flat" iconOnly icon="lye:remove" label="Remove" [disabled]="!store.capabilities().remove" (pressed)="store.removeSelected()" />
968
+ </div>
969
+ <gfy-tree [nodes]="nodes()" [selected]="selectedKey()" (selectedChange)="onSelected($event)" [(expanded)]="expanded" [nodeMenu]="menu" [tools]="['collapseAll', 'expandAll']" filterable guides ariaLabel="Outline" (nodeKeydown)="onKey($event)" />
970
+ `,isInline:true,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n","gfy-tree{flex:1 1 auto;min-height:0}gfy-tree ::ng-deep .bar{padding:6px}\n"],dependencies:[{kind:"component",type:ke,selector:"gfy-button",inputs:["label","icon","iconOnly","tooltip","ariaLabel","caret","variant","appearance","layout","toggle","checked","disabled","busy","type","name","haspopup","expanded","controls","joined","attached","reserveLabelSpace"],outputs:["checkedChange","pressed"]},{kind:"component",type:mn,selector:"gfy-dropdown-button"},{kind:"component",type:Kn,selector:"gfy-tree",inputs:["nodes","expanded","selected","selection","selectionMode","checkboxes","checked","checkMode","filter","filterable","filterMatch","twisty","guides","activateOnClick","tools","toolbar","collapseToLevel","nodeMenu","ariaLabel","emptyText","moveRules","canMove"],outputs:["expandedChange","selectedChange","selectionChange","checkedChange","filterChange","nodeActivated","nodeToggled","nodeChecked","nodeMoved","nodeKeydown"]}]})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Xi,decorators:[{type:me,args:[{selector:"lye-outline",standalone:true,imports:[ke,mn,Kn],template:`
971
+ <div class="tb">
972
+ <gfy-button appearance="flat" iconOnly icon="lye:undo" label="Undo" [disabled]="!store.canUndo()" (pressed)="store.undo()" />
973
+ <gfy-button appearance="flat" iconOnly icon="lye:redo" label="Redo" [disabled]="!store.canRedo()" (pressed)="store.redo()" />
974
+ <span class="sep" aria-hidden="true"></span>
975
+ <gfy-dropdown-button appearance="flat" iconOnly icon="lye:add-tab" label="Add tab" [items]="addItems" />
976
+ <span class="sep" aria-hidden="true"></span>
977
+ <gfy-button appearance="flat" iconOnly icon="lye:duplicate" label="Duplicate" [disabled]="!store.capabilities().duplicate" (pressed)="store.duplicateSelected()" />
978
+ <gfy-button appearance="flat" iconOnly icon="lye:up" label="Move up" [disabled]="!store.capabilities().moveUp" (pressed)="store.moveSelected(-1)" />
979
+ <gfy-button appearance="flat" iconOnly icon="lye:down" label="Move down" [disabled]="!store.capabilities().moveDown" (pressed)="store.moveSelected(1)" />
980
+ <gfy-button appearance="flat" iconOnly icon="lye:remove" label="Remove" [disabled]="!store.capabilities().remove" (pressed)="store.removeSelected()" />
981
+ </div>
982
+ <gfy-tree [nodes]="nodes()" [selected]="selectedKey()" (selectedChange)="onSelected($event)" [(expanded)]="expanded" [nodeMenu]="menu" [tools]="['collapseAll', 'expandAll']" filterable guides ariaLabel="Outline" (nodeKeydown)="onKey($event)" />
983
+ `,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n","gfy-tree{flex:1 1 auto;min-height:0}gfy-tree ::ng-deep .bar{padding:6px}\n"]}]}],ctorParameters:()=>[]});const Mv={file:"File",json:"Layout (JSON)",typescript:"TypeScript",template:"Template",loader:"Loader"};const $v={file:"The file of the editor: the layout with the docking mode it is made for and the components it names. Open it again in the editor.",json:"The value of [defaultLayout] as JSON: what an application loads from a file or from a server.",typescript:"The value of [defaultLayout] as a TypeScript literal, to paste into a component. A component names its class; code of the application is written as it is.",template:"The element for the template of a component.",loader:"Code that imports the file and reads it with gfyLoadLayout: a tab gets the class of its componentKey, the components are registered, and the layout and its docking mode go to the engine."};const Av={file:"json",json:"json",typescript:"ts",template:"html",loader:"ts"};class Zi{store=L(ft);options=mv.map(e=>({value:e,label:Mv[e]}));labels={form:"Form of the output",output:"Output",copy:"Copy",download:"Download"};description=M(()=>$v[this.store.outputKind()],...(ngDevMode?[{debugName:"description"}]:([])));language=M(()=>Av[this.store.outputKind()],...(ngDevMode?[{debugName:"language"}]:([])));onKind(e){this.store.outputKind.set(e)}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Zi,deps:[],target:w.ɵɵFactoryTarget.Component});static ɵcmp=w.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"21.2.21",type:Zi,isStandalone:true,selector:"lye-output",ngImport:w,template:`
984
+ <editor-output
985
+ [kinds]="options"
986
+ [kind]="store.outputKind()"
987
+ [labels]="labels"
988
+ [description]="description()"
989
+ [language]="language()"
990
+ [text]="store.output()"
991
+ copyIcon="lye:copy"
992
+ downloadIcon="lye:download"
993
+ (kindChange)="onKind($event)"
994
+ (copyPressed)="store.copyOutput()"
995
+ (downloadPressed)="store.downloadOutput()" />
996
+ `,isInline:true,styles:[":host{display:block;height:100%;min-height:0}\n"],dependencies:[{kind:"component",type:Et,selector:"editor-output",inputs:["kinds","kind","labels","description","language","text","copyIcon","downloadIcon"],outputs:["kindChange","copyPressed","downloadPressed"]}]})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Zi,decorators:[{type:me,args:[{selector:"lye-output",standalone:true,imports:[Et],template:`
997
+ <editor-output
998
+ [kinds]="options"
999
+ [kind]="store.outputKind()"
1000
+ [labels]="labels"
1001
+ [description]="description()"
1002
+ [language]="language()"
1003
+ [text]="store.output()"
1004
+ copyIcon="lye:copy"
1005
+ downloadIcon="lye:download"
1006
+ (kindChange)="onKind($event)"
1007
+ (copyPressed)="store.copyOutput()"
1008
+ (downloadPressed)="store.downloadOutput()" />
1009
+ `,styles:[":host{display:block;height:100%;min-height:0}\n"]}]}]});function Cv(n,e){const t=n.getBoundingClientRect();let o=t.left;let i=t.top;let r=t.right;let s=t.bottom;const a=n.ownerDocument.defaultView;for(let l=n.parentElement;l&&l!==e&&a;l=l.parentElement){const d=a.getComputedStyle(l);const c=d.overflowX!=="visible";const p=d.overflowY!=="visible";if(!c&&!p)continue;const h=l.getBoundingClientRect();if(c){o=Math.max(o,h.left);r=Math.min(r,h.right)}if(p){i=Math.max(i,h.top);s=Math.min(s,h.bottom)}}return{left:o,top:i,width:Math.max(0,r-o),height:Math.max(0,s-i)}}const Ov=120;class Qi{store=L(ft);host=L(jo);popup=L(Wo);settings=L(_s,{self:true});engine=ct(Ie,...(ngDevMode?[{debugName:"engine"}]:([])));made=M(()=>{const e=this.store.previewRevision();const t=this.store.lockShell();const o=this.store.options().dockingMode;const i=ee(()=>this.store.root());return{revision:e,base:i,built:Uw(i,{lockShell:t,mode:o}),mode:o}},...(ngDevMode?[{debugName:"made"}]:([])));hasNodes=M(()=>this.made().built.links.paths.length>1,...(ngDevMode?[{debugName:"hasNodes"}]:([])));layout=M(()=>this.made().built.layout,...(ngDevMode?[{debugName:"layout"}]:([])));selection=E(null,...(ngDevMode?[{debugName:"selection"}]:([])));shown=null;known;live=false;settling;pressed=null;constructor(){Q(()=>{const s=this.made();const a=this.engine();ee(()=>{if(!a){this.shown=null;this.known=void 0;this.settings.setDockingMode(s.mode);return}if(a!==this.known){this.known=a;this.shown=s;this.settle();return}if(s===this.shown)return;this.shown=s;this.live=false;a.setDefaultLayout(s.built.layout);this.settings.setDockingMode(s.mode);this.settle()})});Q(()=>{this.store.selected();this.store.root();ee(()=>this.mark())});this.store.setMeasurer(s=>this.measure(s));const e=this.host.nativeElement;const t=e.ownerDocument.defaultView;let o;const i=s=>{clearTimeout(o);this.pressed=s.button===0&&s.target instanceof Element&&s.target.closest("[data-tab-id]")!==null?"tab":"other"};const r=()=>{clearTimeout(o);o=setTimeout(()=>this.pressed=null)};e.addEventListener("pointerdown",i,true);t?.addEventListener("pointerup",r,true);t?.addEventListener("pointercancel",r,true);L(lt).onDestroy(()=>{clearTimeout(o);e.removeEventListener("pointerdown",i,true);t?.removeEventListener("pointerup",r,true);t?.removeEventListener("pointercancel",r,true)});L(lt).onDestroy(()=>{clearTimeout(this.settling);cancelAnimationFrame(this.frame);this.unwatch();this.store.setMeasurer(null)})}settle(){this.live=false;clearTimeout(this.settling);this.settling=setTimeout(()=>{this.live=true;this.mark()},Ov)}current(){return this.live&&this.shown!==null&&this.shown.revision===this.store.previewRevision()?this.shown:null}engineRoot(){const e=this.engine();return e?e.api.getRoot():null}onChanged(e){const t=this.current();const o=this.engineRoot();if(!t||!o)return;this.store.mergeFromPreview(t.base,t.built.links,o,`preview:${e}`);setTimeout(()=>this.mark())}onActive(e){const t=this.current();const o=this.engineRoot();if(!t||!o)return;this.onChanged("active");if(this.pressed==="other")return;const i=e.active?.tag;const r=Xw(t.base,t.built.links,o,i);if(r)this.store.select(r)}onClick(e){const t=this.pathAt(e.target);if(t)this.store.select(t)}onContextMenu(e){const t=this.pathAt(e.target);if(!t)return;e.preventDefault();this.popup.open(Nl(this.store,t),{at:e})}onKeydown(e){if((e.key==="Delete"||e.key==="Backspace")&&!e.ctrlKey&&!e.altKey&&!e.metaKey&&!e.shiftKey){const r=e.target;const s=r instanceof HTMLElement&&(r.isContentEditable||["INPUT","TEXTAREA","SELECT"].includes(r.tagName));if(s||!this.store.capabilities().remove)return;e.preventDefault();this.store.removeSelected();return}if(!(e.key==="ContextMenu"||e.key==="F10"&&e.shiftKey)||e.ctrlKey||e.altKey||e.metaKey)return;const t=e.target instanceof Element?e.target.closest("[data-tab-id]"):null;const o=t?this.pathAt(t):this.store.selected();const i=t??(o===null?null:this.elementOf(o)??(o.length===0?this.host.nativeElement.querySelector(".stage"):null));if(o===null||!i)return;e.preventDefault();this.popup.open(Nl(this.store,o),{...df(i),keyboard:true})}pathAt(e){if(!this.hasNodes())return e instanceof Element?[]:null;const t=this.current();const o=this.engineRoot();if(!t||!o||!(e instanceof Element))return null;const i=e.closest("[data-tab-id]")?.getAttribute("data-tab-id")??e.closest("[data-id]")?.getAttribute("data-id");return i===void 0||i===null?[]:Zw(t.base,t.built.links,o,i)}elementOf(e){const t=this.shown;const o=this.engineRoot();const i=this.host.nativeElement.querySelector(".stage");if(!t||!o||!i)return null;const r=Qw(t.base,t.built.links,o,e);if(!r)return null;if(e.length===0)return i.querySelector(".gfy-dock-grid-container");if(r.id===void 0)return null;const s=e[e.length-2]==="tabs"?"data-tab-id":"data-id";return Array.from(i.querySelectorAll(`[${s}]`)).find(a=>a.getAttribute(s)===r.id)??null}mark(){const e=this.host.nativeElement.querySelector(".stage");e?.querySelectorAll(".lye-selected").forEach(o=>o.classList.remove("lye-selected"));const t=this.store.selected();if(t!==null)this.elementOf(t)?.classList.add("lye-selected");this.watch();this.place()}place(){const e=this.host.nativeElement.querySelector(".stage");const t=this.store.selected();const o=e&&t!==null?this.elementOf(t):null;const i=t===null?null:se(this.store.root(),t);if(!e||!o||i===null){if(this.selection()!==null)this.selection.set(null);return}const r=e.getBoundingClientRect();const s=Cv(o,e);if(!(s.width>=1&&s.height>=1)){if(this.selection()!==null)this.selection.set(null);return}const a={kind:i,x:Math.round(s.left-r.left-e.clientLeft),y:Math.round(s.top-r.top-e.clientTop),width:Math.round(s.width),height:Math.round(s.height)};const l=this.selection();if(!l||l.kind!==a.kind||l.x!==a.x||l.y!==a.y||l.width!==a.width||l.height!==a.height)this.selection.set(a)}watched=null;mutations=null;sizes=null;scrolled=null;frame=0;watch(){const e=this.host.nativeElement.querySelector(".stage");const t=e?.querySelector("gfy-docking-engine")??null;if(t===this.watched)return;this.unwatch();this.watched=t;if(!e||!t)return;const o=()=>{cancelAnimationFrame(this.frame);this.frame=requestAnimationFrame(()=>this.place())};this.mutations=new MutationObserver(o);this.mutations.observe(t,{subtree:true,childList:true,attributes:true,attributeFilter:["style","class"]});if(typeof ResizeObserver!=="undefined"){this.sizes=new ResizeObserver(o);this.sizes.observe(e)}e.addEventListener("scroll",o,true);this.scrolled=()=>e.removeEventListener("scroll",o,true)}unwatch(){this.mutations?.disconnect();this.sizes?.disconnect();this.scrolled?.();this.mutations=null;this.sizes=null;this.scrolled=null;this.watched=null}measure(e){if(e.length<2)return void 0;const t=this.store.root();const o=O(t,e);if(!v(o)||o["collapsed"]===true)return void 0;const i=e.slice(0,-2);const r=this.elementOf(e);const s=this.elementOf(i);if(!r||!s)return void 0;const a=O(t,i);const l=!(v(a)&&a["type"]==="column");const d=f=>l?f.width:f.height;const c=d(r.getBoundingClientRect());const p=d(s.getBoundingClientRect());if(!(c>0&&p>0))return void 0;let h=0;let u=0;K(v(a)?a["children"]:void 0).forEach((f,m)=>{if(m===e[e.length-1]||!v(f)||f["collapsed"]===true)return;const g=Je(f["size"]);if(g!==null&&g.unit!=="fr")return;const y=this.elementOf([...i,"children",m])?.getBoundingClientRect();if(!y)return;h+=g?.value??50;u+=d(y)});return{px:Math.round(c),percent:c/p*100,ratio:Ay(c,h,u)}}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Qi,deps:[],target:w.ɵɵFactoryTarget.Component});static ɵcmp=w.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"21.2.21",type:Qi,isStandalone:true,selector:"lye-preview",providers:[_s],viewQueries:[{propertyName:"engine",first:true,predicate:Ie,descendants:true,isSignal:true}],ngImport:w,template:`
1010
+ <div class="tb">
1011
+ <gfy-button
1012
+ appearance="flat"
1013
+ [icon]="store.lockShell() ? 'lye:lock' : 'lye:unlock'"
1014
+ [label]="store.lockShell() ? 'Shell locked' : 'Shell unlocked'"
1015
+ tooltip="The shell is the fixed outer skeleton of the layout. Locked, it is as the application shows it and no tab can be docked into it; unlocked, a tab can be moved into and out of the shell panels here (the layout keeps its shell either way)."
1016
+ (pressed)="store.lockShell.set(!store.lockShell())" />
1017
+ </div>
1018
+ <!-- tabindex -1: a click on a panel or on the rest of the preview gives it the focus (a tab and a splitter take it themselves), so Delete and the Menu key work on what the click selected -->
1019
+ <div class="stage" tabindex="-1" role="group" aria-label="Preview of the layout" (click)="onClick($event)" (contextmenu)="onContextMenu($event)" (keydown)="onKeydown($event)">
1020
+ @if (hasNodes()) {
1021
+ <gfy-docking-engine
1022
+ [defaultLayout]="layout()"
1023
+ [layoutStorageKey]="null"
1024
+ (tabActiveChanged)="onActive($event)"
1025
+ (tabActivated)="onChanged('activated')"
1026
+ (tabDocked)="onChanged('docked')"
1027
+ (tabReordered)="onChanged('reordered')"
1028
+ (panelResized)="onChanged('resized')"
1029
+ (panelCollapsed)="onChanged('collapsed')"
1030
+ (panelExpanded)="onChanged('collapsed')"
1031
+ (layoutChanged)="onChanged('changed')" />
1032
+ } @else {
1033
+ <div class="empty">The layout has no panel yet. Add a tab with the button in the Outline, or open a sample in File > Samples.</div>
1034
+ }
1035
+ @if (selection(); as frame) {
1036
+ <div class="marks" aria-hidden="true">
1037
+ <div [class]="'sel ' + frame.kind" [style.left.px]="frame.x" [style.top.px]="frame.y" [style.width.px]="frame.width" [style.height.px]="frame.height"></div>
1038
+ </div>
1039
+ }
1040
+ </div>
1041
+ <div class="hint">The layout as the engine shows it, with a placeholder for the content of a tab. Drag the splitters, move the tabs, collapse the panels: the layout follows. Click to select a node.</div>
1042
+ `,isInline:true,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n",".stage{flex:1 1 auto;min-height:0;position:relative;margin:6px;border:1px solid var(--gfy-border-color, rgba(128, 128, 128, .35))}.stage gfy-docking-engine{position:absolute;inset:0}.stage .marks{position:absolute;inset:0;z-index:40;overflow:hidden;pointer-events:none}.stage .sel{position:absolute;box-sizing:border-box;border:3px solid var(--gfy-accent, #3a8fd6);border-radius:2px}.stage .sel.panel{background:color-mix(in srgb,var(--gfy-accent, #3a8fd6) 8%,transparent)}.stage .sel.tab{border-width:2px;background:color-mix(in srgb,var(--gfy-accent, #3a8fd6) 18%,transparent)}.stage .empty{position:absolute;inset:0;display:grid;place-items:center;text-align:center}\n"],dependencies:[{kind:"component",type:ke,selector:"gfy-button",inputs:["label","icon","iconOnly","tooltip","ariaLabel","caret","variant","appearance","layout","toggle","checked","disabled","busy","type","name","haspopup","expanded","controls","joined","attached","reserveLabelSpace"],outputs:["checkedChange","pressed"]},{kind:"component",type:Ie,selector:"gfy-docking-engine",inputs:["defaultLayout","engineId","layoutStorageKey","emptyDocument","viewSources","viewTools","tabMenuItems","popouts"],outputs:["tabOpened","tabConfirmClose","tabClosed","tabActivated","tabReordered","tabDocked","tabFloated","tabDirtyChanged","tabMovedToWindow","tabActiveChanged","panelCollapsed","panelExpanded","panelResized","panelMaximized","panelRestored","floatingMoved","floatingResized","dragStarted","dragEnded","popoutOpened","popoutClosed","popoutRefused","layoutChanged","layoutSaved","layoutLoaded","layoutReset"]}]})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Qi,decorators:[{type:me,args:[{selector:"lye-preview",standalone:true,imports:[ke,Ie],providers:[_s],template:`
1043
+ <div class="tb">
1044
+ <gfy-button
1045
+ appearance="flat"
1046
+ [icon]="store.lockShell() ? 'lye:lock' : 'lye:unlock'"
1047
+ [label]="store.lockShell() ? 'Shell locked' : 'Shell unlocked'"
1048
+ tooltip="The shell is the fixed outer skeleton of the layout. Locked, it is as the application shows it and no tab can be docked into it; unlocked, a tab can be moved into and out of the shell panels here (the layout keeps its shell either way)."
1049
+ (pressed)="store.lockShell.set(!store.lockShell())" />
1050
+ </div>
1051
+ <!-- tabindex -1: a click on a panel or on the rest of the preview gives it the focus (a tab and a splitter take it themselves), so Delete and the Menu key work on what the click selected -->
1052
+ <div class="stage" tabindex="-1" role="group" aria-label="Preview of the layout" (click)="onClick($event)" (contextmenu)="onContextMenu($event)" (keydown)="onKeydown($event)">
1053
+ @if (hasNodes()) {
1054
+ <gfy-docking-engine
1055
+ [defaultLayout]="layout()"
1056
+ [layoutStorageKey]="null"
1057
+ (tabActiveChanged)="onActive($event)"
1058
+ (tabActivated)="onChanged('activated')"
1059
+ (tabDocked)="onChanged('docked')"
1060
+ (tabReordered)="onChanged('reordered')"
1061
+ (panelResized)="onChanged('resized')"
1062
+ (panelCollapsed)="onChanged('collapsed')"
1063
+ (panelExpanded)="onChanged('collapsed')"
1064
+ (layoutChanged)="onChanged('changed')" />
1065
+ } @else {
1066
+ <div class="empty">The layout has no panel yet. Add a tab with the button in the Outline, or open a sample in File > Samples.</div>
1067
+ }
1068
+ @if (selection(); as frame) {
1069
+ <div class="marks" aria-hidden="true">
1070
+ <div [class]="'sel ' + frame.kind" [style.left.px]="frame.x" [style.top.px]="frame.y" [style.width.px]="frame.width" [style.height.px]="frame.height"></div>
1071
+ </div>
1072
+ }
1073
+ </div>
1074
+ <div class="hint">The layout as the engine shows it, with a placeholder for the content of a tab. Drag the splitters, move the tabs, collapse the panels: the layout follows. Click to select a node.</div>
1075
+ `,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n",".stage{flex:1 1 auto;min-height:0;position:relative;margin:6px;border:1px solid var(--gfy-border-color, rgba(128, 128, 128, .35))}.stage gfy-docking-engine{position:absolute;inset:0}.stage .marks{position:absolute;inset:0;z-index:40;overflow:hidden;pointer-events:none}.stage .sel{position:absolute;box-sizing:border-box;border:3px solid var(--gfy-accent, #3a8fd6);border-radius:2px}.stage .sel.panel{background:color-mix(in srgb,var(--gfy-accent, #3a8fd6) 8%,transparent)}.stage .sel.tab{border-width:2px;background:color-mix(in srgb,var(--gfy-accent, #3a8fd6) 18%,transparent)}.stage .empty{position:absolute;inset:0;display:grid;place-items:center;text-align:center}\n"]}]}],ctorParameters:()=>[],propDecorators:{engine:[{type:w.ViewChild,args:[w.forwardRef(()=>Ie),{isSignal:true}]}]}});class er{store=L(ft);severities=E(["error","warning","info"],...(ngDevMode?[{debugName:"severities"}]:([])));tools=[{type:"severity",severity:"error"},{type:"severity",severity:"warning"},{type:"severity",severity:"info"},{type:"filter"},{type:"spacer"}];open(e){this.store.openProblem(e)}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:er,deps:[],target:w.ɵɵFactoryTarget.Component});static ɵcmp=w.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"21.2.21",type:er,isStandalone:true,selector:"lye-problems",ngImport:w,template:` <gfy-problem-list [problems]="store.problems()" [tools]="tools" [(severities)]="severities" ariaLabel="Problems" emptyText="No problems found." (problemActivated)="open($event)" /> `,isInline:true,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n","gfy-problem-list{flex:1 1 auto;min-height:0}\n"],dependencies:[{kind:"component",type:_n,selector:"gfy-problem-list",inputs:["problems","columns","columnTitles","tools","toolbar","toolbarPosition","severities","filter","selected","ariaLabel","emptyText"],outputs:["severitiesChange","filterChange","selectedChange","problemActivated","toolUsed"]}]})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:er,decorators:[{type:me,args:[{selector:"lye-problems",standalone:true,imports:[_n],template:` <gfy-problem-list [problems]="store.problems()" [tools]="tools" [(severities)]="severities" ariaLabel="Problems" emptyText="No problems found." (problemActivated)="open($event)" /> `,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n","gfy-problem-list{flex:1 1 auto;min-height:0}\n"]}]}]});const Nv="gfy-layout-editor:windows";const Lh=[{tag:"outline",title:"Outline",icon:"lye:row",role:"tool",component:Xi},{tag:"preview",title:"Preview",icon:"lye:preview",role:"document",component:Qi,fixed:true},{tag:"output",title:"Output",icon:"lye:copy",role:"tool",component:Zi},{tag:"problems",title:"Problems",icon:"lye:problems",role:"tool",component:er},{tag:"inspector",title:"Inspector",icon:"lye:cursor",role:"tool",component:Yi},{tag:"options",title:"Layout Options",icon:"lye:format",role:"tool",component:Ji}];const Iv={showCloseButton:false,allowDetachOnDrag:false,showUndockButton:false};const $o=n=>({tag:n.tag,role:n.role,icon:n.icon,title:n.title,componentType:n.component,componentKey:`lye-${n.tag}`,...(n.fixed?Iv:{})});const ss=(n,e,t,o)=>({tag:n,type:"panel",role:e,size:t,activeTab:0,collapsed:false,tabs:o});const Ao=n=>Lh.find(e=>e.tag===n);const Dv=()=>({type:"row",size:100,children:[ss("left","tool",22,[$o(Ao("outline"))]),{type:"column",size:54,children:[ss("docs","document",60,[$o(Ao("preview"))]),ss("bottom","tool",40,[$o(Ao("output")),$o(Ao("problems"))])]},ss("right","tool",24,[$o(Ao("inspector")),$o(Ao("options"))])]});class tr{hosted=we(false,{...(ngDevMode?{debugName:"hosted"}:({})),transform:js});files=we(null,...(ngDevMode?[{debugName:"files"}]:([])));sample=we(null,...(ngDevMode?[{debugName:"sample"}]:([])));store=L(ft);help=Va(yv);engine=ct(Ie,...(ngDevMode?[{debugName:"engine"}]:([])));layout=Dv();windowsKey=Nv;constructor(){this.store.project.connect(this.files)}ngOnInit(){const e=this.sample();if(e)this.store.startWith(e)}saveWindows(){this.engine()?.saveLayout()}windowItems(){return this.engine()?.view.toolItems(Lh.filter(e=>!e.fixed).map(e=>({tag:e.tag,label:e.title,icon:e.icon})))??[]}resetWindows(){setTimeout(()=>this.engine()?.resetLayout())}menus=M(()=>{const e=this.store;const t=e.capabilities();const o=Nh.map(r=>({label:r.label,run:()=>void e.loadSample(r.id)}));const i=e.project.files()!==null;return[{id:"file",label:"&File",items:[{label:"&New layout",icon:"lye:add-tab",run:()=>void e.newLayout()},{label:"&Open file…",icon:"lye:upload",shortcut:i?void 0:"Mod+O",run:()=>e.openFile()},...(i?[{label:"Open from the p&roject…",icon:"lye:project-folder",shortcut:"Mod+O",run:()=>void e.openFromProject()}]:[]),{label:"&Paste layout from the clipboard",icon:"lye:clipboard",run:()=>void e.pasteLayout()},{label:"&Samples",icon:"lye:sample",children:o},{separator:true},...(i?[{label:"Sa&ve",icon:"lye:save",shortcut:"Mod+S",run:()=>void e.saveToProject()},{label:"Save as…",shortcut:"Mod+Shift+S",run:()=>void e.saveToProjectAs()}]:[]),{label:"&Download the file",icon:"lye:download",shortcut:i?void 0:"Mod+S",run:()=>e.downloadFile()},{label:"&Copy the output",icon:"lye:copy",run:()=>void e.copyOutput()},{separator:true},{label:"&Auto save",checked:e.autoSave(),run:()=>e.setAutoSave(!e.autoSave())}]},{id:"edit",label:"&Edit",items:[{label:"&Undo",icon:"lye:undo",shortcut:"Mod+Z",enabled:e.canUndo(),run:()=>e.undo()},{label:"Re&do",icon:"lye:redo",shortcut:"Mod+Y",enabled:e.canRedo(),run:()=>e.redo()},{separator:true},...Ol(e),...Eh(e,e.selected()),{separator:true},...zh(e,e.selected()),{label:"Dup&licate",icon:"lye:duplicate",shortcut:"Mod+D",enabled:t.duplicate,run:()=>e.duplicateSelected()},{label:"Move u&p",icon:"lye:up",shortcut:"Alt+Up",enabled:t.moveUp,run:()=>e.moveSelected(-1)},{label:"Move do&wn",icon:"lye:down",shortcut:"Alt+Down",enabled:t.moveDown,run:()=>e.moveSelected(1)},{label:"&Remove",icon:"lye:remove",enabled:t.remove,run:()=>e.removeSelected()}]},{id:"view",label:"&View",items:[{label:"&Windows",icon:"lye:row",children:this.windowItems()},{label:"&Lock the shell in the preview",icon:"lye:lock",checked:e.lockShell(),run:()=>e.lockShell.set(!e.lockShell())},{separator:true},{label:"&Reset the windows",run:()=>this.resetWindows()}]},{id:"help",label:"&Help",items:[...this.help.items]}]},...(ngDevMode?[{debugName:"menus"}]:([])));title=M(()=>this.store.project.title(this.store.modified()),...(ngDevMode?[{debugName:"title"}]:([])));statusItems=M(()=>{const e=this.store;const t=e.problems();const o=t.filter(l=>l.severity==="error").length;const i=t.filter(l=>l.severity==="warning").length;const r=e.counts();const s=e.selected();const a=s===null?"":Jr(e.root(),s);return[{id:"message",text:e.status()||"Ready",shrink:true,live:true},{id:"where",text:a,tooltip:"The selected node",align:"end",priority:4,visible:a!==""},{id:"counts",text:He.text("Panels: {panels}, tabs: {tabs}",r),tooltip:"The size of the layout",align:"end",priority:3},{id:"problems",icon:"lye:problems",text:He.text("Errors: {errors}, warnings: {warnings}",{errors:o,warnings:i}),tooltip:"The problems of the layout",align:"end",priority:10,tone:o>0?"danger":i>0?"warning":"default"}]},...(ngDevMode?[{debugName:"statusItems"}]:([])));onFileDragOver(e){za(e)}onFileDrop(e){void La(e)?.then(t=>{if(t)void this.store.loadFromText(t.text,t.name);else this.store.say("The file that was dropped cannot be read.")})}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:tr,deps:[],target:w.ɵɵFactoryTarget.Component});static ɵcmp=w.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"21.2.21",type:tr,isStandalone:true,selector:"layout-editor",inputs:{hosted:{classPropertyName:"hosted",publicName:"hosted",isSignal:true,isRequired:false,transformFunction:null},files:{classPropertyName:"files",publicName:"files",isSignal:true,isRequired:false,transformFunction:null},sample:{classPropertyName:"sample",publicName:"sample",isSignal:true,isRequired:false,transformFunction:null}},host:{properties:{"class.hosted":"hosted()"}},providers:[ft],viewQueries:[{propertyName:"engine",first:true,predicate:Ie,descendants:true,isSignal:true}],ngImport:w,template:`
1076
+ <div class="shell" (dragover)="onFileDragOver($event)" (drop)="onFileDrop($event)">
1077
+ <gfy-menu-bar [menus]="menus()" [shortcuts]="true">
1078
+ @if (!hosted()) {
1079
+ <span gfyMenuBarStart>Gridify Layout editor</span>
1080
+ }
1081
+ <span gfyMenuBarTitle [attr.title]="title().tooltip">{{ title().text }}</span>
1082
+ @if (!hosted()) {
1083
+ <gfy-preference-select gfyMenuBarEnd kinds="theme density" />
1084
+ }
1085
+ </gfy-menu-bar>
1086
+ <div class="workspace">
1087
+ <gfy-docking-engine [defaultLayout]="layout" [layoutStorageKey]="windowsKey" (layoutChanged)="saveWindows()" />
1088
+ </div>
1089
+ <gfy-status-bar [items]="statusItems()" />
1090
+ </div>
1091
+ `,isInline:true,styles:[":host{display:block;height:100vh;color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}:host(.hosted){height:100%}.shell{height:100%;display:flex;flex-direction:column;background:var(--gfy-bg-main)}.workspace{flex:1;min-height:0;position:relative}\n"],dependencies:[{kind:"component",type:Ie,selector:"gfy-docking-engine",inputs:["defaultLayout","engineId","layoutStorageKey","emptyDocument","viewSources","viewTools","tabMenuItems","popouts"],outputs:["tabOpened","tabConfirmClose","tabClosed","tabActivated","tabReordered","tabDocked","tabFloated","tabDirtyChanged","tabMovedToWindow","tabActiveChanged","panelCollapsed","panelExpanded","panelResized","panelMaximized","panelRestored","floatingMoved","floatingResized","dragStarted","dragEnded","popoutOpened","popoutClosed","popoutRefused","layoutChanged","layoutSaved","layoutLoaded","layoutReset"]},{kind:"component",type:Gn,selector:"gfy-menu-bar",inputs:["menus","ariaLabel","overflow","overflowLabel","flexReserve","shortcuts","ignoreAlt","messageBar"],outputs:["messageBarChange","messageBarClosed","messageBarActionInvoked","itemInvoked"]},{kind:"component",type:Bn,selector:"gfy-preference-select",inputs:["kinds","showLabels","disabled"],outputs:["switchFailed"]},{kind:"component",type:Vn,selector:"gfy-status-bar",inputs:["items","variant","ariaLabel","overflowLabel","flexReserve"],outputs:["itemInvoked","choiceInvoked"]}],changeDetection:w.ChangeDetectionStrategy.OnPush})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:tr,decorators:[{type:me,args:[{selector:"layout-editor",standalone:true,imports:[Ie,Gn,Bn,Vn],providers:[ft],changeDetection:fn.OnPush,host:{"[class.hosted]":"hosted()"},template:`
1092
+ <div class="shell" (dragover)="onFileDragOver($event)" (drop)="onFileDrop($event)">
1093
+ <gfy-menu-bar [menus]="menus()" [shortcuts]="true">
1094
+ @if (!hosted()) {
1095
+ <span gfyMenuBarStart>Gridify Layout editor</span>
1096
+ }
1097
+ <span gfyMenuBarTitle [attr.title]="title().tooltip">{{ title().text }}</span>
1098
+ @if (!hosted()) {
1099
+ <gfy-preference-select gfyMenuBarEnd kinds="theme density" />
1100
+ }
1101
+ </gfy-menu-bar>
1102
+ <div class="workspace">
1103
+ <gfy-docking-engine [defaultLayout]="layout" [layoutStorageKey]="windowsKey" (layoutChanged)="saveWindows()" />
1104
+ </div>
1105
+ <gfy-status-bar [items]="statusItems()" />
1106
+ </div>
1107
+ `,styles:[":host{display:block;height:100vh;color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}:host(.hosted){height:100%}.shell{height:100%;display:flex;flex-direction:column;background:var(--gfy-bg-main)}.workspace{flex:1;min-height:0;position:relative}\n"]}]}],ctorParameters:()=>[],propDecorators:{hosted:[{type:w.Input,args:[{isSignal:true,alias:"hosted",required:false}]}],files:[{type:w.Input,args:[{isSignal:true,alias:"files",required:false}]}],sample:[{type:w.Input,args:[{isSignal:true,alias:"sample",required:false}]}],engine:[{type:w.ViewChild,args:[w.forwardRef(()=>Ie),{isSignal:true}]}]}});const Rh={placeholder:{key:"placeholder",kind:"text",description:"What the empty field says."},label:{key:"label",kind:"text",description:"The caption of the control (a double click on it in the Editor edits it)."},text:{key:"text",kind:"text",description:"The text of the label in the preview."},options:{key:"options",kind:"list",description:"The options in the preview, separated by commas."},orientation:{key:"orientation",kind:"select",choices:["horizontal","vertical"],description:"The options side by side or one under another."},mask:{key:"mask",kind:"text",description:"What may be typed where: 9 a digit, a a letter, * a letter or a digit; any other character stands as it is (+420 999 999 999)."},min:{key:"min",kind:"number",description:"The least value."},max:{key:"max",kind:"number",description:"The greatest value."},appearance:{key:"appearance",kind:"select",choices:["box","row","strip"],description:"box: a large place with a dashed frame; row: one line, as high as a field; strip: a dashed line."},multiple:{key:"multiple",kind:"boolean",description:"More files at once (the list grows when files are chosen again)."},fit:{key:"fit",kind:"select",choices:["contain","cover"],description:"contain: the whole picture is seen; cover: the picture fills the frame, and what does not fit is cut off."},height:{key:"height",kind:"text",description:"The height of the frame of the picture: a number is px; 100% makes a picture as high as its place (with align stretch). Without it, the frame has the shape of aspectRatio (16 / 10)."},caption:{key:"caption",kind:"text",description:"The line under the picture."},mode:{key:"mode",kind:"select",choices:["value","time","stopwatch","countdown"],description:"value: the value the application gives; time: the time of the day; stopwatch: counts up; countdown: counts down."},format:{key:"format",kind:"text",description:"The places of the display: 9 a digit, . its decimal point, : a colon (999.9, 99:99:99)."},size:{key:"size",kind:"select",choices:["small","medium","large","xlarge"],description:"The height of a digit: 16, 28, 44 or 72 px."},variant:{key:"variant",kind:"select",choices:["primary","success","warning","danger"],description:"The color of the button: primary (the accent), success, warning or danger; without it the neutral button."},icon:{key:"icon",kind:"text",description:"The icon before the text: a name of an icon of the application (app:save) or of the library (gfy:plus)."},items:{key:"items",kind:"list",description:"The items of the menu, separated by commas. The Output writes them as a member of the component (each with an id from its text) and a method that gets the one that is chosen."}};const ki=[{as:"gfy-input",label:"Text field",short:"text field",role:"field",group:"fields",props:["placeholder"]},{as:"gfy-textarea",label:"Text area",short:"text area",role:"field",group:"fields",props:["placeholder"]},{as:"gfy-password",label:"Password",short:"password",role:"field",group:"fields",props:["placeholder"]},{as:"gfy-date-picker",label:"Date",short:"date",role:"field",group:"fields",props:["placeholder"]},{as:"gfy-select",label:"Select",short:"select",role:"field",group:"fields",props:["placeholder","options"]},{as:"gfy-combobox",label:"Combobox",short:"combobox",role:"field",group:"fields",props:["placeholder","options"]},{as:"gfy-checkbox",label:"Checkbox",short:"checkbox",role:"field",group:"fields",props:["label"]},{as:"gfy-radio-group",label:"Radio group",short:"radio group",role:"field",group:"fields",props:["options","orientation"]},{as:"gfy-switch",label:"Switch",short:"switch",role:"field",group:"fields",props:["label"]},{as:"gfy-spinner",label:"Number",short:"number",role:"field",group:"fields",props:["placeholder"]},{as:"gfy-button",label:"Button",short:"button",role:"button",group:"fields",props:["label","variant","icon"]},{as:"gfy-split-button",label:"Split button",short:"split button",role:"button",group:"fields",props:["label","variant","icon","items"]},{as:"gfy-dropdown-button",label:"Dropdown button",short:"dropdown button",role:"button",group:"fields",props:["label","variant","icon","items"]},{as:"gfy-label",label:"Label",short:"label",role:"label",group:"fields",props:["text"]},{as:"gfy-time-picker",label:"Time",short:"time",role:"field",group:"more",props:["placeholder"]},{as:"gfy-date-time-picker",label:"Date and time",short:"date and time",role:"field",group:"more",props:["placeholder"]},{as:"gfy-mask-input",label:"Masked field",short:"masked field",role:"field",group:"more",props:["mask"]},{as:"gfy-multi-select",label:"Multi-select",short:"multi-select",role:"field",group:"more",props:["placeholder","options"]},{as:"gfy-tags",label:"Tags",short:"tags",role:"field",group:"more",props:["placeholder"]},{as:"gfy-slider",label:"Slider",short:"slider",role:"field",group:"more",props:["min","max"]},{as:"gfy-toggle-group",label:"Toggle group",short:"toggle group",role:"field",group:"more",props:["options"]},{as:"gfy-color-picker",label:"Color",short:"color",role:"field",group:"more",props:["placeholder"]},{as:"gfy-file-upload",label:"File upload",short:"file upload",role:"field",group:"more",props:["appearance","multiple"]},{as:"gfy-picture",label:"Picture",short:"picture",role:"content",group:"content",props:["fit","height","caption"]},{as:"gfy-picture-gallery",label:"Picture gallery",short:"gallery",role:"content",group:"content",props:["fit","height"]},{as:"gfy-digital-display",label:"Digital display",short:"display",role:"content",group:"content",props:["mode","format","size"]}];const Si={"gfy-split-button":{items:[{label:"First"},{label:"Second"}]},"gfy-dropdown-button":{items:[{label:"First"},{label:"Second"}]},"gfy-file-upload":{appearance:"row"},"gfy-picture":{fit:"cover",height:"100%"},"gfy-picture-gallery":{fit:"cover",height:160},"gfy-digital-display":{format:"9999.9"}};const Fh=["gfy-checkbox","gfy-switch","gfy-button","gfy-split-button","gfy-dropdown-button"];const jh=new Map(ki.map(n=>[n.as,n]));const an=n=>n?jh.get(n):void 0;const Il=Object.fromEntries(ki.map(n=>[n.as,`${n.label} (${n.as})`]));const Ph=Object.fromEntries(ki.map(n=>[n.as,n.short]));const Wh=/^(?!gfy-)[a-z][a-z0-9]*(?:-[a-z0-9]+)+$/;const Kh="The tag of a component of the application is lower case letters and digits with a hyphen between the parts (app-address-picker), and not gfy-, the prefix of the library.";const it=n=>typeof n==="string"&&!jh.has(n)&&Wh.test(n);const Ev=n=>an(n)?.role==="content"||it(n);const _h="(own)";const Dl="app-component";function El(n){const e=n.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase().split(/[^a-z0-9]+/).filter(Boolean);const t=`app-${e.join("-")}`;return Wh.test(t)?t:Dl}const zv={"group-box":"group-box (default)",none:"none","property-sheet":"property-sheet"};const Gh="gfy-form-layout";const Bh=1;const zl=2;const Ll=4;const _e=999;const Co=/^[A-Za-z_][A-Za-z0-9_-]*$/;const $n=n=>{const e=n.grid?.division;return typeof e==="number"&&Number.isInteger(e)&&e>=1&&e<=Ll?e:zl};const as=(n,e)=>{if(n.kind!=="input")return 1;const t=n.preview?.as;const o=an(t)?.role;return o==="label"||o==="content"||it(t)?1:e};const ls="Label";function Vh(n){const e=n.replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/[_-]+/g," ").trim().toLowerCase();return e?e[0].toUpperCase()+e.slice(1):n}const rt=n=>({col:n.col,row:n.row,colSpan:Math.max(1,n.colSpan??1),rowSpan:Math.max(1,n.rowSpan??1)});function Oe(n,e){const t={col:e.col,row:e.row,colSpan:e.colSpan,rowSpan:e.rowSpan};if(n){for(const[o,i]of Object.entries(n))if(!Object.prototype.hasOwnProperty.call(t,o))t[o]=i}return t}const Ti=(n,e)=>n===null||e===null?n===e:n.col===e.col&&n.row===e.row&&n.colSpan===e.colSpan&&n.rowSpan===e.rowSpan;const ce=n=>n.kind==="group"&&Array.isArray(n.elements)?n.elements:[];const W=n=>n?.kind==="group"&&n.look==="property-sheet";function ve(n){const e=[];const t=(o,i)=>{o.forEach((r,s)=>{e.push({element:r,name:r.name,parent:i.length?i[i.length-1]:null,ancestors:i,index:s,depth:i.length});if(r.kind==="group")t(ce(r),[...i,r.name])})};t(Array.isArray(n.elements)?n.elements:[],[]);return e}const ge=(n,e)=>ve(n).find(t=>t.name===e);const V=(n,e)=>ge(n,e)?.element;function cs(n){return[n.name,...ce(n).flatMap(cs)]}function Kt(n,e){if(e===null)return Array.isArray(n.elements)?n.elements:[];const t=V(n,e);return t?ce(t):[]}function ln(n,e){const t=new Set(e);const o=Co.test(n)?n:"element";if(!t.has(o))return o;const i=o.replace(/\d+$/,"")||o;for(let r=2;;r++)if(!t.has(`${i}${r}`))return`${i}${r}`}const Oo=n=>ve(n).map(e=>e.name);const z=(n,e)=>Array.isArray(n.forms)?n.forms.find(t=>t.name===e):void 0;const G=(n,e)=>n&&Array.isArray(n.variants)?n.variants.find(t=>t.minWidth===e):void 0;const Nt=n=>[...(Array.isArray(n.variants)?n.variants:[])].sort((e,t)=>e.minWidth-t.minWidth);const ye=(n,e)=>n&&n.places&&Object.prototype.hasOwnProperty.call(n.places,e)?n.places[e]:null;function ue(n,e,t){const o=n.forms.findIndex(s=>s.name===e);if(o<0)return n;const i=t(n.forms[o]);if(i===n.forms[o])return n;const r=[...n.forms];r[o]=i;return{...n,forms:r}}function Xe(n,e,t){const o=n.variants.findIndex(s=>s.minWidth===e);if(o<0)return n;const i=t(n.variants[o]);if(i===n.variants[o])return n;const r=[...n.variants];r[o]=i;return{...n,variants:r}}function An(n,e){let t=false;const o=n.variants.map(i=>{const r=e(i);if(r!==i)t=true;return r});return t?{...n,variants:o}:n}function xe(n,e,t){const o=Object.prototype.hasOwnProperty.call(n.places,e);if(t===null&&!o)return n;const i={};let r=false;for(const[s,a]of Object.entries(n.places)){if(s!==e)i[s]=a;else if(t!==null){i[s]=t;r=true}}if(t!==null&&!r)i[e]=t;return{...n,places:i}}function Hh(n,e,t){let o=false;const i=[];for(const r of n){if(!o&&r.name===e){o=true;const s=t(r);if(s!==null)i.push(s);continue}if(!o&&r.kind==="group"){const s=ce(r);const a=Hh(s,e,t);if(a!==s){o=true;i.push({...r,elements:a});continue}}i.push(r)}return o?i:n}const _t=(n,e,t)=>{const o=Hh(n.elements,e,t);return o===n.elements?n:{...n,elements:o}};function Mi(n,e,t,o){if(o.length===0)return n;const i=r=>{const s=[...r];s.splice(t===void 0?s.length:Math.max(0,Math.min(t,s.length)),0,...o);return s};if(e===null)return{...n,elements:i(n.elements)};return _t(n,e,r=>r.kind==="group"?{...r,elements:i(ce(r))}:r)}function ds(n,e){const t=new Set(e);const o=r=>{let s=false;const a=[];for(const l of r){if(t.has(l.name)){s=true;continue}if(l.kind==="group"){const d=ce(l);const c=o(d);if(c!==d){s=true;a.push({...l,elements:c});continue}}a.push(l)}return s?a:r};const i=o(n.elements);return i===n.elements?n:{...n,elements:i}}function qh(n){const e=/* @__PURE__ */new Map;for(const t of n.layers??[])for(const o of t.layers??[])if(!e.has(o))e.set(o,t.name);return e}function Uh(n){return ve(n).flatMap(e=>e.element.kind==="subform"&&typeof e.element.form==="string"?[e.element.form]:[])}function ps(n,e,t){const o=/* @__PURE__ */new Set;const i=r=>{if(r===e)return true;if(o.has(r))return false;o.add(r);const s=z(n,r);return s?Uh(s).some(i):false};return i(t)}function cn(n){if(typeof n==="string")return n;if(dn(n)){const e=n.$expr;const t=/(['"`])((?:\\.|(?!\1).)*)\1/.exec(e);return t?t[2].replace(/\\(.)/g,"$1"):e}return""}const dn=n=>n!==null&&typeof n==="object"&&!Array.isArray(n)&&Object.keys(n).length===1&&typeof n.$expr==="string";const Pe=n=>({col:1,row:1,colSpan:Math.max(1,n.cols),rowSpan:Math.max(1,n.rows)});const Yh=(n,e)=>{const t=rt(n);return{col:e.col+t.col-1,row:e.row+t.row-1,colSpan:t.colSpan,rowSpan:t.rowSpan}};const Le=(n,e)=>({col:n.col-e.col+1,row:n.row-e.row+1,colSpan:n.colSpan,rowSpan:n.rowSpan});const ie=n=>n.col+n.colSpan-1;const te=n=>n.row+n.rowSpan-1;const ut=(n,e)=>n.col<=ie(e)&&e.col<=ie(n)&&n.row<=te(e)&&e.row<=te(n);const Ee=(n,e)=>n.col>=e.col&&n.row>=e.row&&ie(n)<=ie(e)&&te(n)<=te(e);function Cn(n){if(n.length===0)return null;const e=Math.min(...n.map(o=>o.col));const t=Math.min(...n.map(o=>o.row));return{col:e,row:t,colSpan:Math.max(...n.map(ie))-e+1,rowSpan:Math.max(...n.map(te))-t+1}}const No=(n,e)=>!n.some(t=>e.some(o=>o.group===t.group&&o.layer!==t.layer));const Lv=(n,e)=>n.cells!==null&&n.layers.every(t=>Object.prototype.hasOwnProperty.call(e,t.group)?e[t.group]===t.layer:t.first);function Ne(n,e){const t=[];const o=qh(n);const i=new Map((n.layers??[]).map(a=>[a.name,a.layers?.[0]]));const r=e?Pe(e):null;const s=(a,l,d,c,p)=>{const h=l&&W(l)?a.find(u=>u.kind==="group"&&ye(e,u.name)!==null)?.name??a[0]?.name:null;for(const u of a){const f=ye(e,u.name);const m=f&&d?Yh(f,d):null;let g=c;if(u.layer){const y=o.get(u.layer)??u.layer;g=[...g,{group:y,layer:u.layer,first:o.has(u.layer)?i.get(y)===u.layer:true}]}if(l&&W(l))g=[...g,{group:l.name,layer:u.name,first:h===u.name}];t.push({name:u.name,element:u,parent:l?.name??null,depth:p,order:t.length,place:f,cells:m,bounds:d,layers:g});if(u.kind==="group")s(ce(u),u,m,g,p+1)}};s(Array.isArray(n.elements)?n.elements:[],null,r,[],0);return t}const Rl={top:0,right:0,bottom:0,left:0};function Gt(n,e,t,o=4,i=false){if(n.kind!=="group"||i)return Rl;const r=n.look??"group-box";if(r==="none")return Rl;if(r==="group-box")return{top:t,right:1,bottom:1,left:1};switch(e?.tabs??"top"){case"bottom":return{top:1,right:1,bottom:t,left:1};case"start":return{top:1,right:1,bottom:1,left:o};case"end":return{top:1,right:o,bottom:1,left:1};default:return{top:t,right:1,bottom:1,left:1}}}function On(n,e){const t=Math.max(1,n.colSpan-e.left-e.right);const o=Math.max(1,n.rowSpan-e.top-e.bottom);return{col:n.col+Math.min(e.left,n.colSpan-1),row:n.row+Math.min(e.top,n.rowSpan-1),colSpan:t,rowSpan:o}}function Io(n,e,t,o=n.row){const i=Math.min(e.colSpan,n.colSpan);const r=Math.min(e.rowSpan,n.rowSpan);for(let s=Math.max(n.row,o);s+r-1<=te(n);s++){for(let a=n.col;a+i-1<=ie(n);a++){const l={col:a,row:s,colSpan:i,rowSpan:r};const d=t.find(c=>ut(c,l));if(!d)return l;a=Math.max(a,ie(d))}}return null}const hs=(n,e)=>Math.max(n.row,...e.filter(t=>ut(t,{...n,rowSpan:9999})).map(t=>te(t)+1));function Jh(n,e,t,o){let i=null;for(const s of n.variants??[]){if(s.cols>e||!o&&s.rows>t)continue;if(!i||s.minWidth>i.minWidth)i=s}if(i)return{variant:i,fits:true};const r=Nt(n)[0];return r?{variant:r,fits:false}:null}function Xh(n,e,t=[]){const o=e.element;if(o.kind!=="subform"||!e.cells||t.includes(o.form))return null;const i=z(n,o.form);if(!i)return null;const r=Jh(i,e.cells.colSpan,e.cells.rowSpan,e.place?.flow===true);if(!r)return null;const s=e.cells;const a=Ne(i,r.variant).map(l=>l.cells?{...l,cells:{...l.cells,col:l.cells.col+s.col-1,row:l.cells.row+s.row-1}}:l);return{form:i.name,minWidth:r.variant.minWidth,fits:r.fits,elements:a}}function Zh(n){const e=n.replace(/\[[^\]]*\]/g," ").trim();if(e===""||e==="none")return[];return e.split(/\s+/).map(t=>parseFloat(t)).filter(t=>Number.isFinite(t)&&t>=0)}function Qh(n,e){const t=[];let o=e;for(const i of n){t.push({start:o,size:i});o+=i}return t}function eu(n,e,t=false,o){if(n.length===0)return 1;if(e<n[0].start)return 1;for(let s=0;s<n.length;s++)if(e<n[s].start+n[s].size)return s+1;if(!t)return n.length;const i=n[n.length-1];const r=o??i.size;if(r<=0)return n.length+1;return n.length+1+Math.floor((e-i.start-i.size)/r)}function us(n,e,t){if(n.length===0)return{start:0,size:0};const o=Math.max(1,Math.floor(e));if(o<=n.length)return n[o-1];const i=n[n.length-1];const r=t??i.size;return{start:i.start+i.size+(o-n.length-1)*r,size:r}}function Fl(n,e,t,o){const i=us(n,t.col);const r=us(n,t.col+t.colSpan-1);const s=us(e,t.row,o);const a=us(e,t.row+t.rowSpan-1,o);return{x:i.start,y:s.start,width:r.start+r.size-i.start,height:a.start+a.size-s.start}}function jl(n,e){const t=Math.min(n.col,e.col);const o=Math.min(n.row,e.row);return{col:t,row:o,colSpan:Math.abs(n.col-e.col)+1,rowSpan:Math.abs(n.row-e.row)+1}}function fs(n,e,t=false){const o=Math.min(n.colSpan,e.colSpan);const i=Math.max(e.col,Math.min(n.col,e.col+e.colSpan-o));const r=t?n.rowSpan:Math.min(n.rowSpan,e.rowSpan);const s=t?Math.max(e.row,n.row):Math.max(e.row,Math.min(n.row,e.row+e.rowSpan-r));return{col:i,row:s,colSpan:o,rowSpan:r}}const tu=[{group:"labeled",label:"Fields with a label"},{group:"fields",label:"Fields"},{group:"more",label:"More fields",folded:true},{group:"texts",label:"Texts"},{group:"content",label:"Content"},{group:"containers",label:"Groups and subforms"}];const ms=[{id:"label-above",group:"labeled",label:"Label above a field",description:"A label and under it a text field it names (the label points to the field, so a click on it focuses the field).",icon:"fme:label-above"},{id:"label-beside",group:"labeled",label:"Label beside a field",description:"A label at the start of the row, and the text field it names after it.",icon:"fme:label-beside"},{id:"text-field",group:"fields",label:"Text field",description:"An input drawn as gfy-input: the place of a field of the application.",icon:"fme:input"},{id:"text-area",group:"fields",label:"Text area",description:"An input drawn as gfy-textarea, three lines high and stretched to the height of its place.",icon:"fme:textarea"},{id:"password",group:"fields",label:"Password",description:"An input drawn as gfy-password: the letters are hidden, and an eye shows them.",icon:"fme:password"},{id:"date",group:"fields",label:"Date",description:"An input drawn as gfy-date-picker: a date typed or picked in a calendar.",icon:"fme:date"},{id:"select",group:"fields",label:"Select",description:"An input drawn as gfy-select with a few options.",icon:"fme:select"},{id:"combobox",group:"fields",label:"Combobox",description:"An input drawn as gfy-combobox with a few suggestions.",icon:"fme:combobox"},{id:"checkbox",group:"fields",label:"Checkbox",description:"An input drawn as gfy-checkbox with its own label.",icon:"fme:checkbox"},{id:"radio-group",group:"fields",label:"Radio group",description:"An input drawn as gfy-radio-group: one place for the whole choice.",icon:"fme:radio"},{id:"switch",group:"fields",label:"Switch",description:"An input drawn as gfy-switch with its own label.",icon:"fme:switch"},{id:"spinner",group:"fields",label:"Number",description:"An input drawn as gfy-spinner.",icon:"fme:spinner"},{id:"button",group:"fields",label:"Button",description:"An input drawn as gfy-button, as wide as its place (as a field is), so buttons on places of one width are as wide as each other; justify start makes it as wide as its text.",icon:"fme:button"},{id:"styled-button",group:"fields",label:"Styled button",description:"An input drawn as gfy-button in a color: the accent (variant primary), or success, warning or danger in the Inspector, where an icon can be given too.",icon:"fme:styled-button"},{id:"split-button",group:"fields",label:"Split button",description:"An input drawn as gfy-split-button: the button does its usual action (Save), the arrow beside it opens a menu of the others (Save as); the items are in the Inspector.",icon:"fme:split-button"},{id:"dropdown-button",group:"fields",label:"Dropdown button",description:"An input drawn as gfy-dropdown-button: the whole button opens a menu (Sort by: name, date, size); the items are in the Inspector.",icon:"fme:dropdown-button"},{id:"time",group:"more",label:"Time",description:"An input drawn as gfy-time-picker: a time typed or picked on a clock.",icon:"fme:time"},{id:"date-time",group:"more",label:"Date and time",description:"An input drawn as gfy-date-time-picker: a date and a time in one field.",icon:"fme:date-time"},{id:"mask",group:"more",label:"Masked field",description:"An input drawn as gfy-mask-input: a text of a fixed shape (a phone number, a postal code); its mask says what may be typed where.",icon:"fme:mask"},{id:"multi-select",group:"more",label:"Multi-select",description:"An input drawn as gfy-multi-select: several options of a list.",icon:"fme:multi-select"},{id:"tags",group:"more",label:"Tags",description:"An input drawn as gfy-tags: words typed one by one, each one a chip.",icon:"fme:tags"},{id:"slider",group:"more",label:"Slider",description:"An input drawn as gfy-slider: a number between the least and the greatest one, dragged.",icon:"fme:slider"},{id:"toggle-group",group:"more",label:"Toggle group",description:"An input drawn as gfy-toggle-group: buttons side by side, one of them pressed (justify start).",icon:"fme:toggle-group"},{id:"color",group:"more",label:"Color",description:"An input drawn as gfy-color-picker: a color typed or picked.",icon:"fme:color"},{id:"file-upload",group:"more",label:"File upload",description:"An input drawn as gfy-file-upload, one line as high as a field (appearance row): a file chosen or dropped.",icon:"fme:file-upload"},{id:"label",group:"texts",label:"Label",description:"A static text in the look of the label of a field. Link it to an input in the Inspector (for).",icon:"fme:label"},{id:"caption",group:"texts",label:"Caption",description:"A small, muted text: the heading of a column, a note.",icon:"fme:caption"},{id:"text",group:"texts",label:"Text",description:"A line of plain text.",icon:"fme:text"},{id:"separator",group:"texts",label:"Separator",description:"A line across its place that parts the sections of a form, with a text on it when it has one (F2 writes it). Half the width at first: a handle makes it as wide as it should part.",icon:"fme:separator"},{id:"picture",group:"content",label:"Picture",description:"A place for a picture of the application, drawn as gfy-picture: it fills the place (align stretch, height 100%). It holds no field of the form.",icon:"fme:picture"},{id:"gallery",group:"content",label:"Picture gallery",description:"A place for pictures of the application, drawn as gfy-picture-gallery: one picture with arrows and a strip of small ones.",icon:"fme:gallery"},{id:"display",group:"content",label:"Digital display",description:"A place for a number, a time or a text of the application on a digital display, drawn as gfy-digital-display.",icon:"fme:display"},{id:"own",group:"content",label:"Own component",description:"A place for a component of your application (a map, a chart, a field of your own): the Editor and the Preview draw it as a box with its tag, the Output writes the tag. Its tag is in the Inspector.",icon:"fme:own"},{id:"group-box",group:"containers",label:"Group box",description:"A group with a frame and a title; its edge cells are left free for the frame. Draw its fields inside it.",icon:"fme:group-box"},{id:"group",group:"containers",label:"Group without a frame",description:"Elements that belong together (also for a screen reader, when the group has a title), without a frame.",icon:"fme:group"},{id:"property-sheet",group:"containers",label:"Property sheet",description:"A frame with tabs and two pages: one page is shown at a time. Click a tab in the Editor to show its page.",icon:"fme:sheet"},{id:"repeated-group",group:"containers",label:"Repeated field",description:"A field that repeats (a list of phones): a group without a frame that repeats, with the field and a button that removes it, and a button that adds one under it.",icon:"fme:repeat"},{id:"subform",group:"containers",label:"Subform",description:"Another form of the file placed here (an address, a company): its fields are reached by a path, billing.street.",icon:"fme:subform"}];const Rv=n=>ms.find(e=>e.id===n);const Do=n=>Math.max(1,Math.ceil(n/2));const gs=n=>Math.max(1,Math.round(n/2));function bs(n,e){return n.forms.map(t=>t.name).filter(t=>t!==e&&!ps(n,e,t))}function Fv(n,e){switch(n){case"label":case"caption":case"text":case"separator":case"picture":case"gallery":case"display":case"own":case"group":case"subform":return 1;case"group-box":case"property-sheet":return e+2;case"label-above":return Do(e)+e;default:return e}}function jv(n,e){const t=e.division;const o=Math.max(1,e.cols);switch(n){case"text-area":return{colSpan:o,rowSpan:3*t};case"button":case"styled-button":return{colSpan:Math.min(o,Math.max(2,Math.round(o/6))),rowSpan:t};case"split-button":case"dropdown-button":return{colSpan:Math.min(o,Math.max(3,Math.round(o/5))),rowSpan:t};case"label-above":return{colSpan:gs(o),rowSpan:Do(t)+t};case"label-beside":return{colSpan:o,rowSpan:t};case"label":case"caption":case"text":case"separator":return{colSpan:gs(o),rowSpan:Do(t)};case"picture":return{colSpan:gs(o),rowSpan:4*t};case"gallery":return{colSpan:o,rowSpan:8*t};case"display":return{colSpan:Math.min(o,Math.max(2,Math.round(o/4))),rowSpan:t};case"own":return{colSpan:o,rowSpan:3*t};case"group-box":return{colSpan:o,rowSpan:t+2*t+1};case"group":return{colSpan:o,rowSpan:2*t};case"property-sheet":return{colSpan:o,rowSpan:t+3*t+1};case"repeated-group":return{colSpan:o,rowSpan:2*t};case"subform":{const i=e.subform??bs(e.file,e.form)[0];const r=i?z(e.file,i):void 0;const s=r?Jh(r,o,_e,true):null;return{colSpan:Math.min(o,s?.variant.cols??o),rowSpan:Math.max(1,s?.variant.rows??2*t)}}default:return{colSpan:gs(o),rowSpan:t}}}const xt=(n,e={})=>({col:n.col,row:n.row,colSpan:n.colSpan,rowSpan:n.rowSpan,...e});const ys=(...n)=>n.map(e=>({value:e,label:e}));function Pv(n,e,t){const o=t.division;const i=Do(o);const r=(s,a={})=>({elements:[s],places:{[s.name]:xt(e,a)}});switch(n){case"text-field":return r({kind:"input",name:"field",preview:{as:"gfy-input"}});case"text-area":return r({kind:"input",name:"note",preview:{as:"gfy-textarea"}},{align:"stretch"});case"password":return r({kind:"input",name:"password",preview:{as:"gfy-password"}});case"date":return r({kind:"input",name:"date",preview:{as:"gfy-date-picker"}});case"select":return r({kind:"input",name:"choice",preview:{as:"gfy-select",props:{options:ys("First","Second","Third")}}});case"combobox":return r({kind:"input",name:"search",preview:{as:"gfy-combobox",props:{options:["First","Second","Third"]}}});case"checkbox":return r({kind:"input",name:"check",preview:{as:"gfy-checkbox",props:{label:"Check box"}}});case"radio-group":return r({kind:"input",name:"option",preview:{as:"gfy-radio-group",props:{options:ys("One","Two","Three"),orientation:"horizontal"}}});case"switch":return r({kind:"input",name:"toggle",preview:{as:"gfy-switch",props:{label:"Switch"}}});case"spinner":return r({kind:"input",name:"amount",preview:{as:"gfy-spinner"}});case"button":return r({kind:"input",name:"button",preview:{as:"gfy-button",props:{label:"Button"}}});case"styled-button":return r({kind:"input",name:"button",preview:{as:"gfy-button",props:{label:"Button",variant:"primary"}}});case"split-button":return r({kind:"input",name:"save",preview:{as:"gfy-split-button",props:{label:"Save",items:[{label:"Save as"},{label:"Save a copy"}]}}});case"dropdown-button":return r({kind:"input",name:"sortBy",preview:{as:"gfy-dropdown-button",props:{label:"Sort by",items:[{label:"Name"},{label:"Date"},{label:"Size"}]}}});case"time":return r({kind:"input",name:"time",preview:{as:"gfy-time-picker"}});case"date-time":return r({kind:"input",name:"dateTime",preview:{as:"gfy-date-time-picker"}});case"mask":return r({kind:"input",name:"phone",preview:{as:"gfy-mask-input",props:{mask:"+420 999 999 999"}}});case"multi-select":return r({kind:"input",name:"choices",preview:{as:"gfy-multi-select",props:{options:ys("First","Second","Third")}}});case"tags":return r({kind:"input",name:"tags",preview:{as:"gfy-tags"}});case"slider":return r({kind:"input",name:"level",preview:{as:"gfy-slider"}});case"toggle-group":return r({kind:"input",name:"size",preview:{as:"gfy-toggle-group",props:{options:ys("Small","Medium","Large")}}},{justify:"start"});case"color":return r({kind:"input",name:"color",preview:{as:"gfy-color-picker"}});case"file-upload":return r({kind:"input",name:"attachment",preview:{as:"gfy-file-upload",props:{...Si["gfy-file-upload"]}}});case"picture":return r({kind:"input",name:"picture",preview:{as:"gfy-picture",props:{...Si["gfy-picture"]}}},{align:"stretch"});case"gallery":return r({kind:"input",name:"gallery",preview:{as:"gfy-picture-gallery",props:{...Si["gfy-picture-gallery"]}}},{align:"start"});case"display":return r({kind:"input",name:"display",preview:{as:"gfy-digital-display",props:{...Si["gfy-digital-display"]}}},{justify:"start"});case"own":return r({kind:"input",name:"component",preview:{as:Dl}},{align:"stretch"});case"separator":return r({kind:"static",name:"separator",text:"",appearance:"separator"});case"label":return r({kind:"static",name:"label",text:ls});case"caption":return r({kind:"static",name:"caption",text:"Caption",appearance:"caption"});case"text":return r({kind:"static",name:"text",text:"Text",appearance:"text"});case"label-above":{const s={...e,rowSpan:Math.min(i,Math.max(1,e.rowSpan-1))};const a={...e,row:e.row+s.rowSpan,rowSpan:Math.max(1,e.rowSpan-s.rowSpan)};return{elements:[{kind:"static",name:"fieldLabel",text:ls,for:"field"},{kind:"input",name:"field",preview:{as:"gfy-input"}}],places:{fieldLabel:xt(s),field:xt(a)}}}case"label-beside":{if(e.colSpan<2)return{refused:"A label beside a field needs two columns at least: one for the label and one for the field."};const s=e.colSpan>1?Math.max(1,Math.round(e.colSpan/4)):1;const a={...e,colSpan:s};const l={...e,col:e.col+s,colSpan:Math.max(1,e.colSpan-s)};return{elements:[{kind:"static",name:"fieldLabel",text:ls,for:"field"},{kind:"input",name:"field",preview:{as:"gfy-input"}}],places:{fieldLabel:xt(a,{justify:"end"}),field:xt(l)}}}case"group-box":return r({kind:"group",name:"group",title:"Group",elements:[]});case"group":return r({kind:"group",name:"group",look:"none",elements:[]});case"property-sheet":{const s={col:2,row:o+1,colSpan:Math.max(1,e.colSpan-2),rowSpan:Math.max(1,e.rowSpan-o-1)};return{elements:[{kind:"group",name:"sheet",look:"property-sheet",elements:[{kind:"group",name:"page",title:"Page 1",elements:[]},{kind:"group",name:"page2",title:"Page 2",elements:[]}]}],places:{sheet:xt(e),page:xt(s),page2:xt(s)}}}case"repeated-group":{const s={...e,rowSpan:Math.max(1,Math.min(o,e.rowSpan))};const a={...e,row:e.row+s.rowSpan,rowSpan:Math.max(1,e.rowSpan-s.rowSpan)};const l=Math.min(e.colSpan-1,Math.max(2,Math.round(e.colSpan/6)));const d=Math.max(1,e.colSpan-Math.max(0,l));const c=[{kind:"group",name:"items",title:"Items",look:"none",repeat:true,elements:[{kind:"input",name:"item",preview:{as:"gfy-input"}},...(l>0?[{kind:"input",name:"removeItem",preview:{as:"gfy-button",props:{label:"Remove"}}}]:[])]},...(e.rowSpan>s.rowSpan?[{kind:"input",name:"addItem",preview:{as:"gfy-button",props:{label:"Add"}}}]:[])];const p={items:xt(s),item:xt({col:1,row:1,colSpan:d,rowSpan:s.rowSpan})};if(l>0)p["removeItem"]=xt({col:d+1,row:1,colSpan:l,rowSpan:s.rowSpan});if(e.rowSpan>s.rowSpan)p["addItem"]=xt(a);return{elements:c,places:p}}case"subform":{const s=t.subform??bs(t.file,t.form)[0];if(!s)return{refused:"A subform places another form of the file: add a form first (Insert > A form, or the Outline)."};if(s===t.form||ps(t.file,t.form,s))return{refused:`The form "${s}" cannot stand in "${t.form}": it would stand in itself.`};return r({kind:"subform",name:s,form:s})}}}const D=(n,e)=>({file:n,refused:e});const Ge=(n,e)=>new Map(Ne(n,e).map(t=>[t.name,t]));function Eo(n,e,t,o=Ge(n,e)){if(t===null)return Pe(e);return o.get(t)?.cells??null}function Pl(n,e){let t=e.rows;for(const o of Array.isArray(n.elements)?n.elements:[]){const i=ye(e,o.name);if(i)t=Math.max(t,te(rt(i)))}return t===e.rows?e:{...e,rows:Math.min(t,_e)}}const Bt=(n,e)=>Xe(n,e,t=>Pl(n,t));function nu(n,e,t,o,i){const r=Kt(n,t);const s=Ge(n,e);for(let a=0;a<r.length;a++){const l=r[a];if(i.has(l.name))continue;const d=s.get(l.name)?.cells;if(!d)continue;if(d.row>o.row||d.row===o.row&&d.col>o.col)return a}return r.length}function Wv(n,e,t){let o=0;for(let i=0;i<Math.min(e,n.length);i++)if(!t.has(n[i].name))o++;return o}function ou(n,e,t){const o=ge(n,e);if(!o)return`There is no element "${e}".`;if(t!==null){const r=ge(n,t);if(!r||r.element.kind!=="group")return`"${t}" is not a group.`;if(t===e||r.ancestors.includes(e))return`"${e}" cannot go into itself.`;if(W(r.element)&&o.element.kind!=="group")return`The elements of the property sheet "${t}" are its pages: put "${e}" into a page.`}const i=o.parent===null?null:V(n,o.parent);if(i&&W(i)&&t!==o.parent)return`"${e}" is a page of the property sheet "${o.parent}" and stays in it.`;return null}function Kv(n,e){const t=new Set(Oo(n));const o=/* @__PURE__ */new Map;const i=[];const r=c=>{for(const p of c){i.push(p);r(ce(p))}};r(e.elements);const s=new Set(i.map(c=>c.name));const a=c=>c.kind==="static"&&typeof c.for==="string"&&s.has(c.for)&&c.name===`${c.for}Label`;for(const c of i){if(a(c))continue;const p=ln(c.name,t);t.add(p);o.set(c.name,p)}for(const c of i){if(!a(c))continue;const p=ln(`${o.get(c.for)??c.for}Label`,t);t.add(p);o.set(c.name,p)}const l=c=>c.map(p=>{const h=o.get(p.name)??p.name;if(p.kind==="group")return{...p,name:h,elements:l(ce(p))};if(p.kind==="static"&&p.for&&o.has(p.for))return{...p,name:h,for:o.get(p.for)};return{...p,name:h}});const d={};for(const[c,p]of Object.entries(e.places))d[o.get(c)??c]=p;return{fragment:{elements:l(e.elements),places:d},renamed:o}}function $i(n,e,t,o){const i=z(n,e.form);const r=G(i,e.minWidth);if(!i||!r)return D(n,"There is no form to add to.");if(o.elements.length===0)return D(n,"Nothing to add.");if(t!==null){const h=V(i,t);if(!h||h.kind!=="group")return D(n,`"${t}" is not a group.`);if(W(h)&&o.elements.some(u=>u.kind!=="group"))return D(n,`The elements of the property sheet "${t}" are its pages: add into a page.`)}const s=Eo(i,r,t);if(!s)return D(n,`The group "${t}" has no place in this variant.`);const a=ve({name:"",elements:o.elements,variants:[]}).find(h=>h.element.kind==="subform"&&(h.element.form===e.form||ps(n,e.form,h.element.form)));if(a?.element.kind==="subform")return D(n,`The subform "${a.name}" places the form "${a.element.form}", which cannot stand in "${e.form}": it would stand in itself.`);const l=_v(i,o);const{fragment:d}=Kv(i,l.fragment);let c=Xe(i,e.minWidth,h=>{let u=h;for(const[f,m]of Object.entries(d.places))u=xe(u,f,m);return u});let p;for(const h of d.elements){const u=d.places[h.name];const f=G(c,e.minWidth);const m=u?nu(c,f,t,Yh(u,s),/* @__PURE__ */new Set):p;c=Mi(c,t,m,[h]);p=Kt(c,t).findIndex(g=>g.name===h.name)+1}c=Bt(c,e.minWidth);return{file:ue(n,e.form,()=>c),selected:d.elements.map(h=>h.name),...(l.note?{note:l.note}:{})}}function _v(n,e){const t=qh(n);const o=new Set([...ve(n),...ve({name:"",elements:e.elements,variants:[]})].filter(l=>l.element.kind==="input").map(l=>l.name));const i=[];const r=l=>l.map(d=>{const c={...d};if(typeof d.layer==="string"&&!t.has(d.layer)){delete c["layer"];i.push(d.name)}if(d.kind==="static"&&typeof d.for==="string"&&!o.has(d.for))delete c["for"];if(d.kind==="group")c["elements"]=r(ce(d));return c});const s=r(e.elements);const a=i.length?`The form "${n.name}" has no layer of ${i.map(l=>`"${l}"`).join(", ")}: ${i.length===1?"it is":"they are"} shown in every layer here.`:void 0;return{fragment:{elements:s,places:e.places},...(a?{note:a}:{})}}function iu(n,e,t){const o=z(n,e.form);if(!o)return D(n,"There is no form.");const i=t.map(l=>ge(o,l)).filter(l=>l!==void 0);if(i.length===0)return D(n,"Nothing is selected.");const r=new Set(i.flatMap(l=>cs(l.element)));let s=ds(o,r);s=An(s,l=>{let d=l;for(const c of r)d=xe(d,c,null);return d});s={...s,elements:ru(s.elements,r)};const a=i[0].parent;return{file:ue(n,e.form,()=>s),selected:a!==null&&!r.has(a)?[a]:[]}}function ru(n,e){return n.map(t=>{if(t.kind==="static"&&t.for&&e.has(t.for)){const o={...t};delete o["for"];return o}if(t.kind==="group")return{...t,elements:ru(ce(t),e)};return t})}function ws(n,e,t){let o=z(n,e.form);if(!o||!G(o,e.minWidth))return D(n,"There is no form.");const i=[];for(const s of t){const a=ou(o,s.name,s.parent);if(a)return D(n,a);const l=G(o,e.minWidth);const d=Eo(o,l,s.parent);if(!d)return D(n,`The group "${s.parent}" has no place in this variant.`);const c=s.parent===null?s.cells.col>=1&&s.cells.row>=1&&ie(s.cells)<=d.colSpan:Ee(s.cells,d);if(!c)return D(n,s.parent===null?"That is outside of the grid.":`That is outside of the group "${s.parent}".`);const p=ge(o,s.name);if(!p)continue;if(p.parent!==s.parent){const f=su(o,s.name,s.parent,e.minWidth,s.cells);o=f.form;i.push(...f.notes)}const h=G(o,e.minWidth);const u=Eo(o,h,s.parent);o=Xe(o,e.minWidth,f=>xe(f,s.name,Oe(ye(f,s.name),Le(s.cells,u))))}o=Bt(o,e.minWidth);const r=o;return{file:ue(n,e.form,()=>r),selected:t.map(s=>s.name),note:i.length?i.join(" "):void 0}}function su(n,e,t,o,i,r){const s=ge(n,e);const a=[];const l=new Map(n.variants.map(h=>[h.minWidth,Ge(n,h).get(e)?.cells??null]));let d=ds(n,[e]);const c=G(d,o);const p=r!==void 0?r:i&&c?nu(d,c,t,i,/* @__PURE__ */new Set([e])):void 0;d=Mi(d,t,p,[s.element]);d=An(d,h=>{if(h.minWidth===o&&i)return h;const u=l.get(h.minWidth)??null;if(!ye(h,e))return h;const f=Eo(d,h,t);if(u&&f&&(t===null?ie(u)<=f.colSpan:Ee(u,f))){const m=xe(h,e,Oe(ye(h,e),Le(u,f)));const g=Ne(d,m);const y=g.find(x=>x.name===e);const b=g.some(x=>x.parent===t&&x.name!==e&&x.cells&&ut(x.cells,u)&&No(x.layers,y?.layers??[]));if(!b)return m;a.push(`"${e}" has no place in the variant from ${h.minWidth} px now: its cells there are taken in ${t===null?"the grid":`"${t}"`}.`);return xe(h,e,null)}a.push(`"${e}" has no place in the variant from ${h.minWidth} px now: it does not lie in ${t===null?"the grid":`"${t}"`} there.`);return xe(h,e,null)});for(const h of d.variants)d=Bt(d,h.minWidth);return{form:d,notes:a}}function Wl(n,e,t,o,i){const r=z(n,e.form);if(!r)return D(n,"There is no form.");const s=ou(r,t,o);if(s)return D(n,s);const a=ge(r,t);if(!a)return D(n,`There is no element "${t}".`);if(a.parent===o){const d=Kt(r,o);const c=Math.max(0,Math.min(i,d.length-1));if(c===a.index)return{file:n};const p=d.filter(f=>f.name!==t);const h=[...p.slice(0,c),a.element,...p.slice(c)];const u=o===null?{...r,elements:h}:_t(r,o,f=>({...f,elements:h}));return{file:ue(n,e.form,()=>u),selected:[t]}}const l=su(r,t,o,e.minWidth,null,i);return{file:ue(n,e.form,()=>l.form),selected:[t],note:l.notes.length?l.notes.join(" "):void 0}}function Gv(n,e,t,o){const i=z(n,e.form);const r=i?ge(i,t):void 0;if(!i||!r)return D(n,"Nothing is selected.");const s=Kt(i,r.parent);const a=r.index+o;if(a<0||a>=s.length)return{file:n};return Wl(n,e,t,r.parent,a)}function Bv(n,e,t,o,i){const r=z(n,e.form);const s=G(r,e.minWidth);if(!r||!s)return D(n,"There is no form.");const a=Ge(r,s);const l=[];for(const d of It(r,t)){const c=a.get(d);if(!c?.cells||!c.bounds)continue;const p={...c.cells,col:c.cells.col+o,row:c.cells.row+i};const h=c.parent===null?p.col>=1&&p.row>=1&&ie(p)<=c.bounds.colSpan:Ee(p,c.bounds);if(!h)return{file:n};l.push({name:d,parent:c.parent,cells:p})}if(l.length===0)return{file:n};return ws(n,e,l)}function It(n,e){const t=new Set(e);return e.filter(o=>!(ge(n,o)?.ancestors??[]).some(i=>t.has(i)))}const au=(n,e)=>`"${n}" is a control: it takes ${e} rows at least (its height and the vertical space around it). A smaller spacing.y of the form or the file makes all the rows lower.`;function Ai(n,e,t,o){const i=z(n,e.form);const r=G(i,e.minWidth);if(!i||!r)return D(n,"There is no form.");const s=Ge(i,r);const a=s.get(t);if(!a?.cells||!a.bounds)return D(n,`"${t}" has no place in this variant.`);if(o.colSpan<1||o.rowSpan<1)return{file:n};const l=as(a.element,$n(n));if(o.rowSpan<l&&o.rowSpan<a.cells.rowSpan)return D(n,au(t,l));const d=a.parent===null?o.col>=1&&o.row>=1&&ie(o)<=a.bounds.colSpan:Ee(o,a.bounds);if(!d)return D(n,a.parent===null?"That is outside of the grid.":`That is outside of the group "${a.parent}".`);if(Ti(o,a.cells))return{file:n};let c=i;if(a.element.kind==="group"){const h=ce(a.element).map(m=>s.get(m.name)).filter(m=>m!==void 0&&m.cells!==null);const u=W(a.element);const f=h.filter(m=>!(u&&m.cells&&lu(a,m)));if(f.some(m=>!Ee(m.cells,o)))return D(n,`"${t}" cannot be smaller than what is in it.`);if(!u){const m=a.parent===null?void 0:s.get(a.parent);const g=Gt(a.element,a.place,$n(n),4,m!==void 0&&W(m.element));const y=(x,T)=>x.col>=T.col+g.left&&x.row>=T.row+g.top&&ie(x)<=ie(T)-g.right&&te(x)<=te(T)-g.bottom;const b=a.cells;if(f.some(x=>y(x.cells,b)&&!y(x.cells,o)))return D(n,`"${t}" cannot be smaller than what is in it with its frame around it.`)}for(const m of h.filter(g=>!f.includes(g))){const g=cu(a.cells,m.cells,o);const y=ce(m.element).map(b=>s.get(b.name)?.cells).filter(b=>b!==null&&b!==void 0).map(b=>Le(b,m.cells));if(y.some(b=>ie(b)>g.colSpan||te(b)>g.rowSpan))return D(n,`"${t}" cannot be smaller than what its page "${m.name}" holds.`)}c=Xe(c,e.minWidth,m=>{let g=m;for(const y of h){const b=y.cells;const x=f.includes(y)?b:cu(a.cells,b,o);g=xe(g,y.name,Oe(ye(g,y.name),Le(x,o)))}return g})}c=Xe(c,e.minWidth,h=>xe(h,t,Oe(ye(h,t),Le(o,a.bounds))));c=Bt(c,e.minWidth);const p=c;return{file:ue(n,e.form,()=>p),selected:[t]}}const lu=(n,e)=>e.cells!==null&&n.cells!==null&&e.cells.colSpan>=n.cells.colSpan/2&&e.cells.rowSpan>=n.cells.rowSpan/2;function cu(n,e,t){const o=e.col-n.col;const i=e.row-n.row;const r=ie(n)-ie(e);const s=te(n)-te(e);return{col:t.col+o,row:t.row+i,colSpan:Math.max(1,t.colSpan-o-r),rowSpan:Math.max(1,t.rowSpan-i-s)}}function Vv(n,e,t,o,i){const r=z(n,e.form);const s=r?Ge(r,G(r,e.minWidth)).get(t):void 0;if(!s?.cells)return{file:n};const a={...s.cells,colSpan:s.cells.colSpan+o,rowSpan:s.cells.rowSpan+i};if(a.colSpan<1||a.rowSpan<1)return{file:n};return Ai(n,e,t,a)}function Hv(n,e,t){const o=Math.max(e.col,Math.min(n.col,ie(e)-n.colSpan+1));const i=t?n.row:Math.max(e.row,Math.min(n.row,te(e)-n.rowSpan+1));return o===n.col&&i===n.row?n:{...n,col:o,row:i}}function qv(n,e,t){switch(t){case"left":return{...n,col:e.col};case"right":return{...n,col:ie(e)-n.colSpan+1};case"center":return{...n,col:e.col+Math.floor((e.colSpan-n.colSpan)/2)};case"top":return{...n,row:e.row};case"bottom":return{...n,row:te(e)-n.rowSpan+1};case"middle":return{...n,row:e.row+Math.floor((e.rowSpan-n.rowSpan)/2)};case"width":return{...n,colSpan:e.colSpan};case"height":return{...n,rowSpan:e.rowSpan};case"size":return{...n,colSpan:e.colSpan,rowSpan:e.rowSpan}}}function Uv(n,e,t,o){const i=z(n,e.form);const r=G(i,e.minWidth);if(!i||!r)return D(n,"There is no form.");const[s,...a]=t;if(s===void 0||a.length===0)return D(n,"Select the element to line the others up with first, then the others (Ctrl and a click).");const l=Ge(i,r).get(s)?.cells;if(!l)return D(n,`"${s}" has no place in this variant.`);const d=ge(i,s)?.ancestors??[];const c=[];let p=n;let h=0;for(const u of It(i,a)){if(u===s)continue;if(d.includes(u)){c.push(`"${u}" is a group around "${s}"`);continue}const f=z(p,e.form);const m=Ge(f,G(f,e.minWidth));const g=m.get(u);if(!g?.cells||!g.bounds){c.push(`"${u}" has no place in this variant`);continue}const y=o==="width"||o==="height"||o==="size";const b=qv(g.cells,l,o);const x=y?Hv(b,g.bounds,g.parent===null):b;if(Ti(x,g.cells))continue;const T=g.parent===null?x.col>=1&&x.row>=1&&ie(x)<=g.bounds.colSpan:Ee(x,g.bounds);if(!T){c.push(`"${u}" would leave ${g.parent===null?"the grid":`the group "${g.parent}"`}`);continue}const k=new Set(cs(g.element));const S=[...m.values()].find(A=>A.parent===g.parent&&A.cells&&!k.has(A.name)&&No(A.layers,g.layers)&&ut(A.cells,x));if(S){c.push(`"${u}" would land on "${S.name}"`);continue}const $=y?Ai(p,e,u,x):ws(p,e,[{name:u,parent:g.parent,cells:x}]);if($.refused){c.push($.refused.replace(/\.$/,""));continue}p=$.file;h++}if(h===0&&c.length)return D(n,`Nothing is lined up with "${s}": ${c.join("; ")}.`);return{file:p,selected:t,note:c.length?`Lined up with "${s}": ${h} of ${h+c.length}. Stays where it is: ${c.join("; ")}.`:void 0}}function vs(n,e,t,o){const i=z(n,e.form);if(!i||!G(i,e.minWidth)||!V(i,t))return D(n,`There is no element "${t}".`);let r=Xe(i,e.minWidth,a=>xe(a,t,o));r=Bt(r,e.minWidth);const s=r;return{file:ue(n,e.form,()=>s)}}function xs(n,e,t,o,i){const r=z(n,e.form);const s=ye(G(r,e.minWidth),t);if(!r||!s)return D(n,`"${t}" has no place in this variant.`);const a={...s};if(i===void 0||i===null||i===""||i===false)delete a[o];else a[o]=i;return vs(n,e,t,a)}function Yv(n,e,t,o,i){const r=z(n,e.form);const s=G(r,e.minWidth);if(!r||!s)return D(n,"There is no form.");const a=Ge(r,s);const l=a.get(t);if(!l?.cells||!l.place)return D(n,`"${t}" has no place in this variant.`);if(!W(l.element))return xs(n,e,t,"tabs",o);const d=o??"top";const c=l.place.tabs??"top";if(d===c)return{file:n};const p=$n(n);const h=l.cells;const u=ce(l.element).map(S=>a.get(S.name)).filter(S=>S!==void 0&&S.cells!==null);const f=c==="start"||c==="end"?Jv(h,u,c,i):i;const m=Math.max(1,Math.min(h.colSpan-2,i));const g={...l.place};if(d==="top")delete g["tabs"];else g["tabs"]=d;const y=On(h,Gt(l.element,l.place,p,f));const b=On(h,Gt(l.element,g,p,m));const x=[];for(const S of u){const $=S.cells;const A=lu(l,S)||Ti($,y)?b:Xv({...$,col:$.col+b.col-y.col,row:$.row+b.row-y.row},b);for(const R of ce(S.element)){const j=ye(s,R.name);if(!j)continue;const P=rt(j);if(ie(P)>A.colSpan||te(P)>A.rowSpan)return D(n,`With the tabs at the ${d}, the page "${S.name}" of "${t}" is ${A.colSpan} × ${A.rowSpan} cells: "${R.name}" does not fit into it. Make the sheet larger, or what is on the page smaller, first.`)}x.push({name:S.name,cells:A})}let T=Xe(r,e.minWidth,S=>{let $=xe(S,t,g);for(const A of x)$=xe($,A.name,Oe(ye($,A.name),Le(A.cells,h)));return $});T=Bt(T,e.minWidth);const k=T;return{file:ue(n,e.form,()=>k),selected:[t]}}function Jv(n,e,t,o){const i=e.map(r=>t==="start"?r.cells.col-n.col:ie(n)-ie(r.cells)).filter(r=>r>0);return i.length?Math.min(...i):o}function Xv(n,e){const t=Math.min(n.colSpan,e.colSpan);const o=Math.min(n.rowSpan,e.rowSpan);return{col:Math.max(e.col,Math.min(n.col,ie(e)-t+1)),row:Math.max(e.row,Math.min(n.row,te(e)-o+1)),colSpan:t,rowSpan:o}}function Zv(n,e,t,o,i){const r=Nt(n).filter(l=>l.minWidth!==t&&ye(l,e)).sort((l,d)=>Math.abs(l.minWidth-t)-Math.abs(d.minWidth-t));const s=r.length?Ge(n,r[0]).get(e):void 0;if(s?.cells&&s.bounds){const l=s.cells.colSpan/Math.max(1,s.bounds.colSpan);return{colSpan:Math.max(1,Math.min(o.colSpan,Math.round(l*o.colSpan))),rowSpan:s.cells.rowSpan}}const a=V(n,e);return{colSpan:Math.min(o.colSpan,Math.max(1,Math.round(o.colSpan/2))),rowSpan:a?.kind==="static"?Math.ceil(i/2):i}}function du(n,e,t,o){let i=z(n,e.form);if(!i||!G(i,e.minWidth))return D(n,"There is no form.");const r=[];for(const a of It(i,t)){const l=G(i,e.minWidth);if(ye(l,a))continue;const d=Ge(i,l);const c=ge(i,a);if(!c)continue;const p=Eo(i,l,c.parent,d);if(!p)continue;const h=c.parent===null?p:Ci(d,l,c.parent,o);const u=Zv(i,a,e.minWidth,h,o);const f=d.get(a)?.layers??[];const m=Kt(i,c.parent).map(x=>d.get(x.name)).filter(x=>x!==void 0&&x.cells!==null&&x.name!==a&&No(x.layers,f));const g=m.map(x=>x.cells);let y=Io(h,u,g);if(!y&&c.parent===null)y={col:1,row:hs(p,g),colSpan:u.colSpan,rowSpan:u.rowSpan};if(!y)continue;const b=Le(y,p);i=Xe(i,e.minWidth,x=>xe(x,a,Oe(null,b)));i=Bt(i,e.minWidth);r.push(a)}if(r.length===0)return D(n,It(i,t).length===1?"There is no free room for it here (a group it is in may have no place, or no room).":"There is no free room for them here (a group they are in may have no place, or no room).");const s=i;return{file:ue(n,e.form,()=>s),selected:r}}function pu(n,e,t){const o=z(n,e.form);const i=G(o,e.minWidth);if(!o||!i)return null;const r=Ge(o,i);const s=It(o,t).filter(l=>V(o,l));if(s.length===0)return null;const a={};for(const l of s){const d=V(o,l);for(const c of cs(d)){const p=r.get(c);if(!p?.place)continue;a[c]=c===l&&p.cells?Oe(p.place,p.cells):p.place}}return{elements:s.map(l=>V(o,l)),places:a}}function hu(n,e,t,o,i,r){const s=z(n,e.form);const a=G(s,e.minWidth);if(!s||!a)return D(n,"There is no form.");const l=Ge(s,a);const d=Eo(s,a,o,l);if(!d)return D(n,`The group "${o}" has no place in this variant.`);const c=o===null?void 0:V(s,o);if(c&&W(c)){const k=ce(c).map(A=>l.get(A.name)?.cells).find(A=>A!==null&&A!==void 0);const S=k??Ci(l,a,o,r);const $={...t.places};for(const A of t.elements)$[A.name]=Oe(t.places[A.name]??null,Le(S,d));return $i(n,e,o,{elements:t.elements,places:$})}const p=t.elements.map(k=>t.places[k.name]).filter(k=>k!==void 0);const h=o===null?d:Ci(l,a,o,r);const u=Cn(p.map(rt))??{col:1,row:1,colSpan:Math.min(d.colSpan,Math.max(1,Math.round(d.colSpan/2))),rowSpan:r};const f={colSpan:Math.min(u.colSpan,h.colSpan),rowSpan:u.rowSpan};if(o!==null&&p.length>0&&f.rowSpan>h.rowSpan)return D(n,`There is no room for it in "${o}".`);const m=Kt(s,o).map(k=>l.get(k.name)?.cells).filter(k=>k!==null&&k!==void 0);let g=null;if(i){const k={col:Math.max(h.col,Math.min(i.col,ie(h)-f.colSpan+1)),row:Math.max(h.row,i.row),...f};if((o===null||Ee(k,h))&&!m.some(S=>ut(S,k)))g=k}if(!g&&i)g=Io(h,f,m,Math.max(h.row,i.row-f.rowSpan));g??=Io(h,f,m);if(!g&&o===null)g={col:1,row:hs(d,m),...f};if(!g)return D(n,`There is no room for it in "${o}".`);const y=g.row-u.row;const b=f.colSpan/u.colSpan;const x={...t.places};for(const k of t.elements){const S=t.places[k.name];if(!S)continue;const $=rt(S);const A=g.col+Math.floor(($.col-u.col)*b);const R={col:A,row:$.row+y,colSpan:Math.max(1,Math.min(Math.round($.colSpan*b),ie(g)-A+1)),rowSpan:$.rowSpan};x[k.name]=Oe(S,Le(R,d))}let T=g.row+g.rowSpan;for(const k of t.elements){if(x[k.name])continue;const S={col:g.col,row:T,colSpan:f.colSpan,rowSpan:r};if(o!==null&&te(S)>te(h))continue;x[k.name]=Oe(null,Le(S,d));T+=r}return $i(n,e,o,{elements:t.elements,places:x})}function Qv(n,e,t,o){const i=z(n,e.form);const r=G(i,e.minWidth);if(!i||!r)return D(n,"There is no form.");const s=It(i,t);const a=new Set(s.map(h=>ge(i,h)?.parent??null));if(a.size!==1)return D(n,"Duplicate copies elements of one list: select elements of the same group.");const l=[...a][0];const d=pu(n,e,s);if(!d)return D(n,"Nothing is selected.");const c=Cn(d.elements.map(h=>d.places[h.name]).filter(h=>h!==void 0).map(rt));const p=c?{col:c.col,row:c.row+c.rowSpan}:null;return hu(n,e,d,l,p,o)}function Kl(n,e,t,o){const i=z(n,e);if(!i||!V(i,t))return D(n,`There is no element "${t}".`);if(o===t)return{file:n};if(!Co.test(o))return D(n,`"${o}" is not a name: a letter or "_" first, then letters, digits, "_" and "-".`);if(Oo(i).includes(o))return D(n,`The form "${e}" has an element "${o}" already.`);const r=V(i,t)?.kind==="input";const s=`${t}Label`;const a=V(i,s);const l=r&&a?.kind==="static"&&a.for===t&&!Oo(i).includes(`${o}Label`)&&`${o}Label`!==o;const d=u=>u.kind==="input"&&!!u.preview&&(u.preview.as===Dl||u.preview.as===El(t));let c=_t(i,t,u=>d(u)&&u.kind==="input"?{...u,name:o,preview:{...u.preview,as:El(o)}}:{...u,name:o});const p=u=>u.map(f=>{if(f.kind==="static"&&f.for===t){const m=l&&f.name===s?`${o}Label`:f.name;return{...f,name:m,for:o,...(r&&f.text===ls?{text:Vh(o)}:{})}}if(f.kind==="group")return{...f,elements:p(ce(f))};return f});c={...c,elements:p(c.elements)};c=An(c,u=>uu(u,t,o));if(l)c=An(c,u=>uu(u,s,`${o}Label`));const h=c;return{file:ue(n,e,()=>h),selected:[o]}}function uu(n,e,t){if(!Object.prototype.hasOwnProperty.call(n.places,e))return n;const o={};for(const[i,r]of Object.entries(n.places))o[i===e?t:i]=r;return{...n,places:o}}const ex={static:["kind","name","layer","text","for","appearance"],input:["kind","name","layer","defaults","preview"],group:["kind","name","layer","title","look","repeat","defaults","elements"],subform:["kind","name","layer","form","repeat","defaults"]};function Vt(n,e,t,o,i){const r=z(n,e.form);const s=r?ge(r,t):void 0;if(!r||!s)return D(n,`There is no element "${t}".`);const a=s.element;if(o==="name")return typeof i==="string"?Kl(n,e.form,t,i.trim()):D(n,"A name is a text.");if(!ex[a.kind].includes(o)||o==="kind"||o==="elements")return D(n,`"${o}" is not a property of a ${a.kind}.`);const l=s.parent===null?void 0:V(r,s.parent);if(o==="repeat"&&i===true&&(W(a)||W(l)))return D(n,W(a)?"A property sheet does not repeat.":"A page of a property sheet does not repeat.");if(o==="form"&&a.kind==="subform"){if(typeof i!=="string"||!z(n,i))return D(n,`The file has no form "${String(i)}".`);if(i===e.form||ps(n,e.form,i))return D(n,`The form "${i}" cannot stand in "${e.form}": it would stand in itself.`)}if(o==="layer"&&i!==void 0&&i!==""&&!(r.layers??[]).some(u=>u.layers.includes(i)))return D(n,`The form has no layer "${String(i)}".`);if(o==="look"&&i!=="property-sheet"&&W(a)){const u=ce(a);const f=r.variants.some(m=>{const g=Ge(r,m);const y=u.map(b=>g.get(b.name)?.cells).filter(b=>b!==null&&b!==void 0);return y.some((b,x)=>y.slice(x+1).some(T=>ut(b,T)))});if(f)return D(n,`The pages of "${t}" lie on the same cells: as groups they would cover each other. Keep one page (move what the others hold onto it, and remove them), then change the look.`)}const d=i===""&&!(o==="text"&&a.kind==="static");let c=_t(r,t,u=>{const f={...u};if(i===void 0||i===null||d||i===false&&o==="repeat")delete f[o];else f[o]=i;return f});let p;if(o==="look"&&i==="property-sheet"&&a.kind==="group"){const u=ce(a).filter(f=>f.kind!=="group");if(u.length>0){c=tx(c,t,u.map(f=>f.name));p=`What was not a page of "${t}" is in a new page now: the elements of a property sheet are its pages.`}c=_t(c,t,f=>{const m={...f};delete m["repeat"];return m});for(const f of ce(V(c,t))){if(f.kind!=="group"||f.look===void 0&&!f.repeat)continue;c=_t(c,f.name,m=>{const g={...m};delete g["look"];delete g["repeat"];return g})}}else if(o==="look"&&W(a)){const u=ce(a).filter(f=>f.kind==="group");for(const f of u)c=_t(c,f.name,m=>({...m,look:"none"}));if(u.length)p=u.length===1?`The page of "${t}" is a group without a frame in it now.`:`The pages of "${t}" are groups without a frame in it now.`}const h=c;return{file:ue(n,e.form,()=>h),note:p}}function tx(n,e,t){const o=ln("page",Oo(n));return fu(n,t,{kind:"group",name:o,title:"Page",elements:[]},e)}function fu(n,e,t,o,i,r=2){const s=Kt(n,o);const a=Math.min(...e.map(p=>s.findIndex(h=>h.name===p)).filter(p=>p>=0));const l=s.filter(p=>e.includes(p.name));const d=new Map(n.variants.map(p=>[p.minWidth,Ge(n,p)]));let c=ds(n,e);c=Mi(c,o,Wv(s,a,new Set(e)),[{...t,elements:l}]);c=An(c,p=>{const h=d.get(p.minWidth);const u=e.map(b=>h.get(b)?.cells).filter(b=>b!==null&&b!==void 0);const f=Cn(u);const m=o===null?Pe(p):h.get(o)?.cells??null;let g=p;if(!f||!m){for(const b of e)g=xe(g,b,null);return g}const y=i?nx(f,i,[...h.values()].filter(b=>b.parent===o&&b.cells&&!e.includes(b.name)).map(b=>b.cells),Ci(h,p,o,r)):f;g=xe(g,t.name,Oe(null,Le(y,m)));for(const b of e){const x=h.get(b);g=xe(g,b,x?.cells&&x.place?Oe(x.place,Le(x.cells,y)):null)}return g});return c}function Ci(n,e,t,o){if(t===null)return{...Pe(e),rowSpan:_e};const i=n.get(t);if(!i?.cells)return Pe(e);const r=i.parent?n.get(i.parent):void 0;return On(i.cells,Gt(i.element,i.place,o,4,r?.element.kind==="group"&&W(r.element)))}function nx(n,e,t,o){const i=c=>Ee(c,o)&&!t.some(p=>ut(p,c));const r=e.top>0&&i({col:n.col,row:n.row-e.top,colSpan:n.colSpan,rowSpan:e.top})?e.top:0;const s=e.bottom>0&&i({col:n.col,row:te(n)+1,colSpan:n.colSpan,rowSpan:e.bottom})?e.bottom:0;const a={row:n.row-r,rowSpan:n.rowSpan+r+s};const l=e.left>0&&i({col:n.col-e.left,...a,colSpan:e.left})?e.left:0;const d=e.right>0&&i({col:ie(n)+1,...a,colSpan:e.right})?e.right:0;return{col:n.col-l,row:a.row,colSpan:n.colSpan+l+d,rowSpan:a.rowSpan}}function ox(n,e,t,o,i,r){let s=n;const a=()=>{const y=z(s,e.form);const b=G(y,e.minWidth);const x=Ge(y,b);const T=Cn(t.map(S=>x.get(S)?.cells).filter(S=>S!==null&&S!==void 0));const k=[...x.values()].filter(S=>S.parent===o&&S.cells&&!t.includes(S.name)).map(S=>S.cells);return{form:y,variant:b,map:x,box:T,taken:k,limit:Ci(x,b,o,r)}};let l=a();if(!l.box)return s;const d=y=>Ee(y,l.limit)&&!l.taken.some(b=>ut(b,y));if(i.top>0&&!d({col:l.box.col,row:l.box.row-i.top,colSpan:l.box.colSpan,rowSpan:i.top})){const y=Ss(s,e,"row",l.box.row,i.top);if(!y.refused)s=y.file;l=a()}if(l.box&&i.bottom>0&&!d({col:l.box.col,row:te(l.box)+1,colSpan:l.box.colSpan,rowSpan:i.bottom})){const y=Ss(s,e,"row",te(l.box)+1,i.bottom);if(!y.refused)s=y.file;l=a()}const c=l.box;if(!c)return s;const p={row:c.row-i.top,rowSpan:c.rowSpan+i.top+i.bottom};const h=i.left>0&&!d({col:c.col-i.left,...p,colSpan:i.left});const u=i.right>0&&!d({col:ie(c)+1,...p,colSpan:i.right});if(!h&&!u)return s;const f=t.map(y=>l.map.get(y)).filter(y=>y!==void 0&&y.cells!==null&&y.place!==null);const m=/* @__PURE__ */new Map;for(const y of f){const b=y.cells;const x=h&&b.col===c.col?i.left:0;const T=u&&ie(b)===ie(c)?i.right:0;if(x+T===0||b.colSpan-x-T<1)continue;m.set(y.name,{...b,col:b.col+x,colSpan:b.colSpan-x-T})}if(m.size===0)return s;const g=Xe(l.form,e.minWidth,y=>ix(l.form,y,m));return ue(s,e.form,()=>g)}function ix(n,e,t){const o=/* @__PURE__ */new Map;const i=/* @__PURE__ */new Map;let r=e;for(const s of Ne(n,e)){if(!s.cells||!s.place)continue;const a=t.get(s.name);if(a&&s.bounds){const p=s.cells;const h=(u,f,m,g,y)=>g+Math.round((u-f)*y/m);i.set(s.name,u=>{const f=h(u.col,p.col,p.colSpan,a.col,a.colSpan);const m=h(u.row,p.row,p.rowSpan,a.row,a.rowSpan);const g=Math.max(f+1,h(u.col+u.colSpan,p.col,p.colSpan,a.col,a.colSpan));const y=Math.max(m+1,h(u.row+u.rowSpan,p.row,p.rowSpan,a.row,a.rowSpan));return{col:f,row:m,colSpan:g-f,rowSpan:y-m}});o.set(s.name,a);r=xe(r,s.name,Oe(s.place,Le(a,s.bounds)));continue}const l=s.parent!==null?o.get(s.parent):void 0;const d=s.parent!==null?i.get(s.parent):void 0;if(!l||!d)continue;const c=mu(d(s.cells),l);o.set(s.name,c);i.set(s.name,d);r=xe(r,s.name,Oe(s.place,Le(c,l)))}return r}function rx(n,e,t,o,i){const r=z(n,e.form);if(!r)return D(n,"There is no form.");const s=It(r,t);const a=new Set(s.map(m=>ge(r,m)?.parent??null));if(s.length===0)return D(n,"Nothing is selected.");if(a.size!==1)return D(n,"Only elements of one list go into a group: select elements of the same group.");const l=[...a][0];if(l!==null&&W(V(r,l)))return D(n,"The elements of a property sheet are its pages: a page is a group already.");const d=ln("group",Oo(r));const c=o==="group-box"?{kind:"group",name:d,title:"Group",elements:[]}:{kind:"group",name:d,look:"none",elements:[]};const p=o==="group-box"?{top:i,right:1,bottom:1,left:1}:void 0;let h=n;if(p)for(const m of r.variants)h=ox(h,{form:e.form,minWidth:m.minWidth},s,l,p,i);let u=fu(z(h,e.form),s,c,l,p,i);for(const m of u.variants)u=Bt(u,m.minWidth);const f=u;return{file:ue(n,e.form,()=>f),selected:[d]}}function sx(n,e,t){const o=z(n,e.form);const i=o?ge(o,t):void 0;if(!o||!i||i.element.kind!=="group")return D(n,"Select a group.");if(W(i.element))return D(n,"A property sheet is not ungrouped: its pages lie on the same cells.");const r=i.parent===null?null:V(o,i.parent);if(r&&W(r))return D(n,"A page of a property sheet is not ungrouped: what is in it would stand in the sheet without a page.");const s=i.element;const a=s.defaults&&Object.keys(s.defaults).length?s.defaults:void 0;const l=[];const d=ce(s).map(f=>{let m={...f};if(s.layer!==void 0&&f.layer===void 0)m["layer"]=s.layer;else if(s.layer!==void 0&&f.layer!==s.layer)l.push(f.name);if(a&&f.kind!=="static")m={...m,defaults:{...a,...(f.defaults??{})}};return m});const c=l.length?`"${t}" was in the layer "${s.layer}": ${l.map(f=>`"${f}"`).join(", ")} ${l.length===1?"keeps its own layer, so it is":"keep their own layers, so they are"} shown without "${s.layer}" now.`:void 0;const p=new Map(o.variants.map(f=>[f.minWidth,Ge(o,f)]));let h=ds(o,[t]);h=Mi(h,i.parent,i.index,d);h=An(h,f=>{const m=p.get(f.minWidth);const g=i.parent===null?Pe(f):m.get(i.parent)?.cells??null;let y=xe(f,t,null);for(const b of d){const x=m.get(b.name);y=xe(y,b.name,x?.cells&&x.place&&g?Oe(x.place,Le(x.cells,g)):null)}return y});const u=h;return{file:ue(n,e.form,()=>u),selected:d.map(f=>f.name),...(c?{note:c}:{})}}function ax(n,e,t,o){const i=z(n,e.form);const r=i?V(i,t):void 0;if(!i||!r||!W(r))return D(n,`"${t}" is not a property sheet.`);const s=ce(r);const a=ln("page",Oo(i));const l={kind:"group",name:a,title:`Page ${s.length+1}`,elements:[]};let d=Mi(i,t,void 0,[l]);d=An(d,p=>{const h=ye(p,t);if(!h)return p;const u=s.map(g=>ye(p,g.name)).find(g=>g!==null);if(u)return xe(p,a,Oe(null,rt(u)));const f=rt(h);const m=On({...f,col:1,row:1},Gt(r,h,o,Math.max(1,Math.min(4,f.colSpan-2))));return xe(p,a,Oe(null,m))});const c=d;return{file:ue(n,e.form,()=>c),selected:[a]}}function lx(n,e,t,o){const i=z(n,e);if(!i)return D(n,"There is no form.");if(!Number.isInteger(t)||t<0)return D(n,"The width of a variant is a whole number of px, 0 or more.");if(G(i,t))return D(n,`The form has a variant from ${t} px already.`);const r=G(i,o)??Nt(i)[0];const s=r?{...r,minWidth:t}:{minWidth:t,cols:24,rows:8,places:{}};const a=[...i.variants,s].sort((l,d)=>l.minWidth-d.minWidth);return{file:ue(n,e,l=>({...l,variants:a}))}}function cx(n,e,t){const o=z(n,e);if(!o||!G(o,t))return D(n,"There is no such variant.");if(o.variants.length<=1)return D(n,"A form has one variant at least.");let i=o.variants.filter(l=>l.minWidth!==t);const r=Nt({...o,variants:i})[0];const s=t===0&&r&&r.minWidth!==0?r.minWidth:null;if(s!==null)i=i.map(l=>l.minWidth===s?{...l,minWidth:0}:l);const a=i;return{file:ue(n,e,l=>({...l,variants:a})),...(s!==null?{note:`The variant from ${s} px is used from 0 px now: a form has a variant from 0 px.`}:{})}}function dx(n,e,t,o){const i=z(n,e);if(!i||!G(i,t))return D(n,"There is no such variant.");if(!Number.isInteger(o)||o<0)return D(n,"The width of a variant is a whole number of px, 0 or more.");if(o===t)return{file:n};if(G(i,o))return D(n,`The form has a variant from ${o} px already.`);if(t===0)return D(n,"The variant from 0 px stays the one from 0 px: a form needs one for the narrowest widths. Add a variant for wider forms instead.");const r=i.variants.map(s=>s.minWidth===t?{...s,minWidth:o}:s).sort((s,a)=>s.minWidth-a.minWidth);return{file:ue(n,e,s=>({...s,variants:r}))}}function ks(n,e,t,o){const i=Ne(n,e);const r=/* @__PURE__ */new Map;let s=e;for(const a of i){if(!a.place)continue;if(!a.cells)continue;const l=a.parent===null?o:r.get(a.parent)??null;const d=t(a.cells);const c=d&&l&&a.parent!==null?mu(d,l):d;r.set(a.name,c);s=xe(s,a.name,c&&l?Oe(a.place,Le(c,l)):null)}return s}function mu(n,e){const t=Math.min(Math.max(n.col,e.col),ie(e));const o=Math.min(Math.max(n.row,e.row),te(e));return{col:t,row:o,colSpan:Math.max(1,Math.min(n.colSpan,ie(e)-t+1)),rowSpan:Math.max(1,Math.min(n.rowSpan,te(e)-o+1))}}function px(n,e,t){if(t>=0)return n>=e?n+t:n;const o=-t;if(n>=e&&n<e+o)return null;return n>=e+o?n-o:n}function gu(n,e,t){if(!n)return void 0;const o={};for(const[i,r]of Object.entries(n)){const s=px(Number(i),e,t);if(s!==null)o[String(s)]=r}return Object.keys(o).length?o:void 0}function Nn(n,e,t){const o=e==="col"?"colSizes":"rowSizes";const i={...n};if(t&&Object.keys(t).length)i[o]=t;else delete i[o];return i}function Ss(n,e,t,o,i=1){const r=z(n,e.form);const s=G(r,e.minWidth);if(!r||!s)return D(n,"There is no form.");const a=t==="col"?s.cols:s.rows;if(o<1||o>a+1||i<1)return{file:n};if(a+i>_e)return D(n,`A variant has ${_e} columns and rows at most.`);const l=Pe(s);const d=h=>{const u=t==="col"?h.col:h.row;const f=t==="col"?h.colSpan:h.rowSpan;const m=u+f-1;const g=u>=o?u+i:u;const y=m>=o?m+i:m;return t==="col"?{...h,col:g,colSpan:y-g+1}:{...h,row:g,rowSpan:y-g+1}};let c=ks(r,s,d,l);c=t==="col"?{...c,cols:c.cols+i}:{...c,rows:c.rows+i};c=Nn(c,t,gu(t==="col"?c.colSizes:c.rowSizes,o,i));const p=c;return{file:ue(n,e.form,h=>Xe(h,e.minWidth,()=>p))}}function hx(n,e,t,o,i,r=4){const s=z(n,e.form);const a=G(s,e.minWidth);if(!s||!a)return D(n,"There is no form.");const l=(g,y)=>{const b=y.parent?g.find(x=>x.name===y.parent):void 0;return Gt(y.element,y.place,i,r,b?.element.kind==="group"&&W(b.element))};const d=Ne(s,a);const c=d.find(g=>g.name===t);if(!c?.cells||c.element.kind!=="group")return D(n,`The group "${t}" has no place in this variant.`);const p=l(d,c);const h=Math.min(a.rows+1,Math.max(c.cells.row+p.top,te(c.cells)+1-p.bottom));const u=Ss(n,e,"row",h,o);if(u.refused)return u;let f=u.file;let m=h+o-1;for(const g of[t,...[...(ge(s,t)?.ancestors??[])].reverse()]){const y=z(f,e.form);const b=Ne(y,G(y,e.minWidth));const x=b.find(k=>k.name===g);if(!x?.cells||!x.place)break;const T=m+l(b,x).bottom;if(te(x.cells)<T){const k=T-te(x.cells);const S=x.cells;const $=x.parent&&b.find(A=>A.name===x.parent&&A.element.kind==="group"&&W(A.element))?b.filter(A=>A.parent===x.parent&&A.cells&&Ti(A.cells,S)):[x];f=ue(f,e.form,A=>Xe(A,e.minWidth,R=>$.reduce((j,P)=>P.place?xe(j,P.name,Oe(P.place,{...rt(P.place),rowSpan:rt(P.place).rowSpan+k})):j,R)))}m=Math.max(T,te(x.cells))}return{file:ue(f,e.form,g=>Bt(g,e.minWidth)),row:h}}function bu(n,e,t,o){const i=[...new Set(o)].sort((u,f)=>f-u);if(i.length<=1)return i.length?yu(n,e,t,i[0]):{file:n};const r=z(n,e.form);const s=G(r,e.minWidth);if(!r||!s)return D(n,"There is no form.");const a=u=>{const f=z(u,e.form);return new Set(Ne(f,G(f,e.minWidth)).filter(m=>m.cells).map(m=>m.name))};const l=a(n);let d=n;for(const u of i){const f=yu(d,e,t,u);if(f.refused)return D(n,f.refused);d=f.file}const c=a(d);const p=[...l].filter(u=>!c.has(u));const h=t==="col"?"columns":"rows";return{file:d,note:p.length?`No place in this variant now: ${p.map(u=>`"${u}"`).join(", ")} (${p.length===1?"it":"they"} lay only on those ${h}).`:void 0}}function yu(n,e,t,o){const i=z(n,e.form);const r=G(i,e.minWidth);if(!i||!r)return D(n,"There is no form.");const s=t==="col"?r.cols:r.rows;if(s<=1)return D(n,`A variant has one ${t==="col"?"column":"row"} at least.`);if(o<1||o>s)return{file:n};const a=Pe(r);const l=[];const d=Ne(i,r);const c=u=>{const f=t==="col"?u.col:u.row;const m=t==="col"?u.colSpan:u.rowSpan;const g=f+m-1;if(f===o&&g===o)return null;const y=f>o?f-1:f;const b=g>=o?g-1:g;return t==="col"?{...u,col:y,colSpan:b-y+1}:{...u,row:y,rowSpan:b-y+1}};for(const u of d)if(u.cells&&c(u.cells)===null)l.push(u.name);let p=ks(i,r,c,a);p=t==="col"?{...p,cols:p.cols-1}:{...p,rows:p.rows-1};p=Nn(p,t,gu(t==="col"?p.colSizes:p.rowSizes,o,-1));const h=p;return{file:ue(n,e.form,u=>Xe(u,e.minWidth,()=>h)),note:l.length?`No place in this variant now: ${l.map(u=>`"${u}"`).join(", ")} (it lay only on that ${t==="col"?"column":"row"}).`:void 0}}function _l(n,e,t,o){const i=z(n,e.form);const r=G(i,e.minWidth);if(!i||!r)return D(n,"There is no form.");const s={...((t==="col"?r.colSizes:r.rowSizes)??{})};for(const[l,d]of o){const c=d===null?null:d.trim();if(c!==null&&c!==""&&!ux(c,t))return D(n,t==="col"?"The size of a column is px, fr or auto (120px, 2fr, auto).":"The size of a row is px or auto (40px, auto).");if(c===null||c==="")delete s[String(l)];else s[String(l)]=c}const a=Nn(r,t,s);return{file:ue(n,e.form,l=>Xe(l,e.minWidth,()=>a))}}function ux(n,e){if(n==="auto")return true;const t=/^(\d+(?:\.\d+)?|\.\d+)(px|fr)$/.exec(n);return t!==null&&parseFloat(t[1])>0&&(t[2]==="px"||e==="col")}function fx(n,e,t){const o=z(n,e.form);const i=G(o,e.minWidth);if(!o||!i)return D(n,"There is no form.");if(!Number.isInteger(t)||t<1||t>_e)return D(n,`A variant has 1 to ${_e} columns.`);if(t===i.cols)return{file:n};const r=t/i.cols;const s=c=>Math.round((c-1)*r)+1;const a=c=>{const p=s(c.col);const h=Math.max(p,s(ie(c)+1)-1);return{...c,col:p,colSpan:h-p+1}};let l=ks(o,{...i},a,Pe(i));for(const c of Ne(o,i))if(c.place&&!c.cells)l=xe(l,c.name,Oe(c.place,a(rt(c.place))));l=Nn({...l,cols:t},"col",void 0);if(i.colSizes)l=Nn(l,"col",Object.fromEntries(Object.entries(i.colSizes).map(([c,p])=>[String(Math.min(t,s(Number(c)))),p])));const d=l;return{file:ue(n,e.form,c=>Xe(c,e.minWidth,()=>d))}}function wu(n,e,t){const o=z(n,e.form);const i=G(o,e.minWidth);if(!o||!i)return D(n,"There is no form.");if(!Number.isInteger(t)||t<1||t>_e)return D(n,`A variant has 1 to ${_e} rows.`);const r=Pl(o,{...i,rows:1}).rows;if(t<r)return D(n,`The elements of this variant need ${r} rows.`);const s=i.rowSizes?Object.fromEntries(Object.entries(i.rowSizes).filter(([l])=>Number(l)<=t)):void 0;const a=Nn({...i,rows:t},"row",s);return{file:ue(n,e.form,l=>Xe(l,e.minWidth,()=>a))}}function vu(n,e){const t=Cn(Ne(n,e).flatMap(o=>o.cells?[o.cells]:[]));if(!t)return{top:0,bottom:Math.max(0,e.rows-1),left:0,right:0};return{top:t.row-1,bottom:Math.max(0,e.rows-te(t)),left:t.col-1,right:Math.max(0,e.cols-ie(t))}}function mx(n,e,t,o){const i=z(n,e.form);const r=G(i,e.minWidth);if(!i||!r)return D(n,"There is no form.");const s=vu(i,r);const a=t==="col"?r.cols:r.rows;const l=o.start?t==="col"?s.left:s.top:0;const d=o.end?t==="col"?s.right:s.bottom:0;const c=[...Array.from({length:l},(u,f)=>f+1),...Array.from({length:d},(u,f)=>a-f)];if(c.length===0)return{file:n};const p=bu(n,e,t,c);const h=Tu(n,e.form);if(p.refused||t==="row"||h.length===0)return p;return{...p,note:`${e.form} stands as a subform in ${h.join(", ")}: there it lies on the cells of the form it stands in, so with fewer columns this variant fills fewer of them.`}}function gx(n,e){const t=n.forms.map(s=>s.name);const o=ln(e&&Co.test(e)?e:"form",t);const i=n.forms[0]?Nt(n.forms[0])[0]:void 0;const r={name:o,elements:[],variants:[{minWidth:0,cols:i?.cols??24,rows:8,places:{}}]};return{file:{...n,forms:[...n.forms,r]},selected:[]}}function xu(n,e){if(!z(n,e))return D(n,`There is no form "${e}".`);if(n.forms.length<=1)return D(n,"A file has one form at least.");const t=n.forms.filter(o=>o.name!==e&&ve(o).some(i=>i.element.kind==="subform"&&i.element.form===e));if(t.length)return D(n,`The form "${e}" stands as a subform in ${t.map(o=>`"${o.name}"`).join(", ")}: take those subforms out first.`);return{file:{...n,forms:n.forms.filter(o=>o.name!==e)}}}function bx(n,e,t){if(!z(n,e))return D(n,`There is no form "${e}".`);if(t===e)return{file:n};if(!Co.test(t))return D(n,`"${t}" is not a name: a letter or "_" first, then letters, digits, "_" and "-".`);if(z(n,t))return D(n,`The file has a form "${t}" already.`);const o=r=>r.map(s=>{if(s.kind==="subform"&&s.form===e)return{...s,form:t};if(s.kind==="group")return{...s,elements:o(ce(s))};return s});const i=n.forms.map(r=>({...r,name:r.name===e?t:r.name,elements:o(r.elements)}));return{file:{...n,forms:i}}}function yx(n,e){const t=z(n,e);if(!t)return D(n,`There is no form "${e}".`);const o={...t,name:ln(e,n.forms.map(s=>s.name))};const i=n.forms.indexOf(t);const r=[...n.forms.slice(0,i+1),o,...n.forms.slice(i+1)];return{file:{...n,forms:r}}}function wx(n,e,t){const o=n.forms.findIndex(a=>a.name===e);const i=o+t;if(o<0||i<0||i>=n.forms.length)return{file:n};const r=[...n.forms];const[s]=r.splice(o,1);r.splice(i,0,s);return{file:{...n,forms:r}}}function vx(n){return(n.layers??[]).map(e=>`${e.name}: ${e.layers.join(", ")}`).join("; ")}const ku="layer";function xx(n){const e=[];const t=/* @__PURE__ */new Set;for(const o of n.split(/[;\n]/)){if(o.trim()==="")continue;const i=o.indexOf(":");const r=i<0?ku:o.slice(0,i).trim();const s=o.slice(i+1).split(/[,\s]+/).map(a=>a.trim()).filter(a=>a!=="");if(!Co.test(r))return{error:`"${r}" is not a name of a group of layers.`};if(e.some(a=>a.name===r)){const a=`A group without a name is the group "${ku}", and there is one already: give the groups names (subject: person, company; mode: simple, advanced).`;return{error:i<0?a:`Two groups of layers are named "${r}".`}}if(s.length===0)return{error:`The group of layers "${r}" has no layer.`};for(const a of s){if(!Co.test(a))return{error:`"${a}" is not a name of a layer.`};if(t.has(a))return{error:`The layer "${a}" is in two groups (a layer is in one group of the form).`};t.add(a)}e.push({name:r,layers:s})}return{groups:e}}function kx(n,e,t){const o=z(n,e);if(!o)return D(n,"There is no form.");const i=new Set(t.flatMap(l=>l.layers));const r=l=>l.map(d=>{let c=d;if(d.layer&&!i.has(d.layer)){const p={...d};delete p["layer"];c=p}if(c.kind==="group")c={...c,elements:r(ce(c))};return c});const s={...o,elements:r(o.elements)};if(t.length)s["layers"]=t.map(l=>({name:l.name,layers:[...l.layers]}));else delete s["layers"];const a=Ht(s,["name","layers","defaults","spacing","elements","variants"]);return{file:ue(n,e,()=>a)}}function Ht(n,e){const t={};for(const o of e)if(Object.prototype.hasOwnProperty.call(n,o))t[o]=n[o];for(const[o,i]of Object.entries(n))if(!Object.prototype.hasOwnProperty.call(t,o))t[o]=i;return t}function zo(n,e,t,o){const i={...(n[e]??{})};if(o===void 0||o===null||o==="")delete i[t];else i[t]=o;const r={...n};if(Object.keys(i).length)r[e]=i;else delete r[e];return r}const Oi=["format","version","grid","spacing","minFormWidth","defaults","functions","forms"];const Su=["name","layers","defaults","spacing","elements","variants"];function Sx(n,e){if(e!==null&&(!Number.isInteger(e)||e<1||e>Ll))return D(n,`The division is a whole number from 1 to ${Ll}.`);const t=Ht(zo(n,"grid","division",e??void 0),Oi);const o=$n(n);const i=e??zl;if(i===o)return{file:t};const r=i/o;const s=p=>Math.round((p-1)*r)+1;const a=p=>{const h=s(p.row);const u=Math.max(h,s(te(p)+1)-1);return{...p,row:h,rowSpan:u-h+1}};const l=[];const d=t.forms.map(p=>{const h=p.variants.map(u=>{let f=ks(p,u,a,Pe(u));for(const m of Ne(p,u))if(m.place&&!m.cells)f=xe(f,m.name,Oe(m.place,a(rt(m.place))));f=Nn({...f,rows:Math.max(1,s(u.rows+1)-1)},"row",Tx(u.rowSizes,r,s));f=Pl(p,f);for(const m of Ne(p,f))if(m.cells&&m.cells.rowSpan<as(m.element,i)&&!l.includes(m.name))l.push(m.name);return f});return{...p,variants:h}});const c=l.length===0?void 0:`The rows were rounded: ${l.slice(0,5).map(p=>`"${p}"`).join(", ")}${l.length>5?` and ${l.length-5} more`:""} ${l.length===1?"is":"are"} lower than a control now (the Problems window lists them).`;return{file:{...t,forms:d},...(c?{note:c}:{})}}function Tx(n,e,t){if(!n)return void 0;const o=l=>{const d=/^(\d+(?:\.\d*)?|\.\d+)px$/.exec(l);return d?parseFloat(d[1]):null};const i=l=>`${+l.toFixed(2)}px`;const r={};if(e>=1){for(const[l,d]of Object.entries(n)){const c=t(Number(l));const p=Math.max(c,t(Number(l)+1)-1);const h=o(d);for(let u=c;u<=p;u++)r[String(u)]=h===null?d:i(h/(p-c+1))}return r}const s=/* @__PURE__ */new Map;const a=Math.max(...Object.keys(n).map(Number));for(let l=1;l<=a;l++){const d=t(l);const c=t(l+1)>d?d:Math.max(1,d-1);s.set(c,[...(s.get(c)??[]),l])}for(const[l,d]of s){const c=d.map(p=>n[String(p)]);if(c.every(p=>p===void 0))continue;if(c.some(p=>p==="auto"))r[String(l)]="auto";else if(c.every(p=>p!==void 0&&o(p)!==null))r[String(l)]=i(c.reduce((p,h)=>p+o(h),0))}return r}function Gl(n){if(typeof n==="number")return Number.isInteger(n)&&n>=0&&n<=100;return typeof n==="string"&&/^\d+(\.\d+)?%$/.test(n)&&parseFloat(n)<=400}function Mx(n){const e=n.trim();if(e==="")return null;const t=/^(\d+)(px)?$/.exec(e);if(t)return Gl(Number(t[1]))?Number(t[1]):void 0;return Gl(e)?e:void 0}const Tu=(n,e)=>n.forms.filter(t=>t.name!==e&&Uh(t).includes(e)).map(t=>t.name);function $x(n,e,t,o){if(o!==null&&!Gl(o))return D(n,"A space is a whole number of px from 0 to 100, or a share of the height of a control such as 50% (0% to 400%).");if(e===null)return{file:Ht(zo(n,"spacing",t,o??void 0),Oi)};const i=z(n,e);if(!i)return D(n,"There is no form.");const r=ue(n,e,a=>Ht(zo(a,"spacing",t,o??void 0),Su));const s=Tu(n,e);if(o===null||s.length===0)return{file:r};return{file:r,note:`${e} stands as a subform in ${s.join(", ")}: there it lies on the cells of the form it stands in and takes its spacing. Its own spacing counts where ${e} is laid out by itself.`}}function Mu(n,e,t,o){if(!e.form)return{file:Ht(zo(n,"defaults",t,o),Oi)};const i=z(n,e.form);if(!i)return D(n,"There is no form.");if(!e.element)return{file:ue(n,e.form,a=>Ht(zo(a,"defaults",t,o),Su))};const r=V(i,e.element);if(!r||r.kind==="static")return D(n,"A text has no defaults of the fields.");const s=_t(i,e.element,a=>zo(a,"defaults",t,o));return{file:ue(n,e.form,()=>s)}}function Ax(n,e){if(e!==null&&(!Number.isInteger(e)||e<0))return D(n,"The narrowest width of the forms is a whole number of px, 0 or more.");const t={...n};if(e)t["minFormWidth"]=e;else delete t["minFormWidth"];return{file:Ht(t,Oi)}}function Cx(n,e){const t={...n};if(e.length)t["functions"]=[...e];else delete t["functions"];return{file:Ht(t,Oi)}}function In(n,e,t,o){const i=z(n,e.form);const r=i?V(i,t):void 0;if(!i||!r||r.kind!=="input")return D(n,"Only an input has a preview.");const s=_t(i,t,a=>{const l={...a};if(o===null)delete l["preview"];else l["preview"]=o.props&&Object.keys(o.props).length?{as:o.as,props:o.props}:{as:o.as};return Ht(l,["kind","name","layer","defaults","preview"])});return{file:ue(n,e.form,()=>s)}}const Bl=n=>n.history.present;const Ox=n=>n.history.present!==n.saved;const Nx=n=>n.saved===n.history.present?n:{...n,saved:n.history.present};const Ix=n=>n.saved!==n.history.present?n:{...n,saved:{...n.history.present}};function Ts(n,e){const t=(e?.form!==void 0?z(n,e.form):void 0)??n.forms[0];const o=t?Nt(t):[];const i=e?.minWidth??0;const r=o.find(a=>a.minWidth===i)??[...o].sort((a,l)=>Math.abs(a.minWidth-i)-Math.abs(l.minWidth-i))[0];const s=t?[...new Set(e?.names??[])].filter(a=>ge(t,a)!==void 0):[];return{form:t?.name??"",minWidth:r?.minWidth??0,names:s,scope:e?.scope??"variant"}}const $u=(n,e)=>n.form===e.form&&n.minWidth===e.minWidth&&n.scope===e.scope&&n.names.length===e.names.length&&n.names.every((t,o)=>t===e.names[o]);function pn(n,e=[],t=null){const o=Ta(n);return{history:o,selection:Ts(n,t),notes:e,saved:n}}function qt(n,e){const t=Ts(Bl(n),{...n.selection,...e});return $u(t,n.selection)?n:{...n,selection:t}}function Dx(n,e,t,o={}){const i=wn(n.history,e,{mergeKey:o.mergeKey,now:o.now});const r=Au(Bl(n),e,n.selection);const s=Ts(e,t===void 0?r:{...r,names:t});if(i===n.history&&$u(s,n.selection))return n;return{...n,history:i,notes:i===n.history?n.notes:[],selection:s}}function Vl(n,e){const t=n.filter(i=>!e.includes(i));const o=e.filter(i=>!n.includes(i));return t.length>0&&t.length===o.length?new Map(t.map((i,r)=>[i,o[r]])):null}function Au(n,e,t){if(n===e)return t;const o=z(e,t.form)?t.form:Vl(n.forms.map(l=>l.name),e.forms.map(l=>l.name))?.get(t.form)??t.form;const i=z(n,t.form);const r=z(e,o);if(!i||!r)return{...t,form:o};const s=r.variants.some(l=>l.minWidth===t.minWidth)?t.minWidth:Vl(i.variants.map(l=>l.minWidth),r.variants.map(l=>l.minWidth))?.get(t.minWidth)??t.minWidth;const a=t.names.some(l=>!ge(r,l))?Vl(ve(i).map(l=>l.name),ve(r).map(l=>l.name)):null;return{...t,form:o,minWidth:s,names:a?t.names.map(l=>a.get(l)??l):t.names}}function Cu(n,e){return{...n,history:e,notes:[],selection:Ts(e.present,Au(n.history.present,e.present,n.selection))}}const Ex=n=>n.history.past.length===0?n:Cu(n,Ma(n.history));const zx=n=>n.history.future.length===0?n:Cu(n,$a(n.history));const Lx="This is not a form layout: the file of the Form editor is an object with \"format\": \"gfy-form-layout\" and \"version\": 1.";function Ms(){return{format:Gh,version:Bh,forms:[Ou("form")]}}function Ou(n,e=24){return{name:n,elements:[],variants:[{minWidth:0,cols:e,rows:8,places:{}}]}}const Rx=["static","input","group","subform"];function Nu(n){const e=Xn(n,{lenient:true});if(!e.ok)return{ok:false,error:e.error};const t=e.value;const o=e.positions.get("[]")??{line:1,column:1,offset:0};if(!v(t)||t["format"]!==Gh)return{ok:false,error:{...o,template:Lx,params:{}}};if(t["version"]!==Bh)return{ok:false,error:{...o,template:"The file is of the version {version} of the format; the editor reads and writes the version 1.",params:{version:JSON.stringify(t["version"]??null)}}};const i=[...e.notes];const r=(l,d,c={})=>{const p=e.positions.get(q(l))??o;i.push({...p,template:d,params:c})};const s=[];const a=Array.isArray(t["forms"])?t["forms"]:[];if(!Array.isArray(t["forms"]))r(["forms"],"The file has no list of forms (\"forms\"); the editor starts it with one form.");a.forEach((l,d)=>{const c=Fx(l,["forms",d],r,s.map(p=>p.name));if(c)s.push(c)});if(s.length===0){if(Array.isArray(t["forms"]))r(["forms"],"The file has no form that can be read; the editor starts it with one form.");s.push(Ou("form"))}return{ok:true,file:{...t,forms:s},notes:i}}function Fx(n,e,t,o){if(!v(n)){t(e,"A form is an object with \"name\", \"elements\" and \"variants\"; the entry {index} is left out.",{index:Number(e[1])});return null}let i=typeof n["name"]==="string"?n["name"]:"";if(i===""){i=ln("form",o);t(e,"A form had no name; it is called \"{name}\" now.",{name:i})}const r=Array.isArray(n["elements"])?Iu(n["elements"],[...e,"elements"],t):[];if(!Array.isArray(n["elements"]))t([...e,"elements"],"The form \"{name}\" had no list of elements; it has none now.",{name:i});const s=[];if(Array.isArray(n["variants"])){n["variants"].forEach((l,d)=>{const c=Px(l,[...e,"variants",d],t,i);if(c&&!s.some(p=>p.minWidth===c.minWidth))s.push(c);else if(c)t([...e,"variants",d],"Two variants of the form \"{name}\" start at {width} px; the later one is left out.",{name:i,width:c.minWidth})})}if(s.length===0){t([...e,"variants"],"The form \"{name}\" had no variant that can be read; it has one from 0 px now.",{name:i});s.push({minWidth:0,cols:24,rows:8,places:{}})}const a={...n,name:i,elements:r,variants:s.sort((l,d)=>l.minWidth-d.minWidth)};if(n["layers"]!==void 0&&!Array.isArray(n["layers"])){delete a["layers"];t([...e,"layers"],"The groups of layers of the form \"{name}\" are not a list; they are left out.",{name:i})}else if(Array.isArray(n["layers"])){const l=jx(n["layers"],[...e,"layers"],t,i);if(l.length)a["layers"]=l;else if(n["layers"].length)delete a["layers"]}return a}function jx(n,e,t,o){const i=[];n.forEach((r,s)=>{if(!v(r)||typeof r["name"]!=="string"||!Array.isArray(r["layers"])){t([...e,s],"A group of layers of the form \"{form}\" needs a \"name\" and a list of \"layers\"; the entry {index} is left out.",{form:o,index:s});return}const a=r["layers"].filter(l=>typeof l==="string");if(a.length===r["layers"].length)i.push(r);else{i.push({...r,layers:a});t([...e,s,"layers"],"The layers of the group \"{group}\" of the form \"{form}\" are texts; what is not one is left out.",{group:r["name"],form:o})}});return i}function Iu(n,e,t){const o=[];n.forEach((i,r)=>{const s=[...e,r];if(!v(i)||typeof i["kind"]!=="string"||!Rx.includes(i["kind"])||typeof i["name"]!=="string"){t(s,"An element needs a \"kind\" (static, input, group, subform) and a \"name\"; the entry {index} is left out, with what is in it.",{index:r});return}const a={...i};if(i["kind"]==="group"){if(Array.isArray(i["elements"]))a["elements"]=Iu(i["elements"],[...s,"elements"],t);else{a["elements"]=[];t(s,"The group \"{name}\" had no list of elements; it has none now.",{name:i["name"]})}}if(i["kind"]==="static"&&i["text"]===void 0)a["text"]="";if(i["kind"]==="subform"&&typeof i["form"]!=="string")a["form"]="";o.push(a)});return o}const Ni=n=>typeof n==="number"&&Number.isInteger(n);function Px(n,e,t,o){if(!v(n)||!Ni(n["minWidth"])||n["minWidth"]<0){t(e,"A variant of the form \"{form}\" has no \"minWidth\" (a whole number of px); it is left out.",{form:o});return null}const i={...n};for(const s of["cols","rows"]){const a=n[s];if(!Ni(a)||a<1||a>_e){const l=Ni(a)?Math.max(1,Math.min(_e,a)):s==="cols"?24:8;i[s]=l;t([...e,s],"The variant from {width} px of the form \"{form}\" had {key} {value}; it has {fixed} now.",{width:n["minWidth"],form:o,key:s,value:JSON.stringify(a??null),fixed:l})}}const r={};if(v(n["places"])){for(const[s,a]of Object.entries(n["places"])){if(v(a)&&Ni(a["col"])&&Ni(a["row"]))r[s]=a;else t([...e,"places",s],"The place of \"{name}\" in the variant from {width} px has no whole \"col\" and \"row\"; it is left out.",{name:s,width:n["minWidth"]})}}else t([...e,"places"],"The variant from {width} px of the form \"{form}\" had no places; it has none now.",{width:n["minWidth"],form:o});i["places"]=r;return i}const Wx=n=>Zn(n,2,110);function hn(n){const e=[...n].sort((t,o)=>t-o);if(e.length>2&&e.every((t,o)=>o===0||t===e[o-1]+1))return`${e[0]}–${e[e.length-1]}`;return e.join(", ")}const Y="";const Hl=_h;const H=(n,e)=>({value:n,label:e});const re={element:"Element",text:"Text",group:"Group",subform:"Subform",preview:"Preview",place:"Place in this variant",defaults:"Defaults of the fields",grid:"Grid",spacing:"Spacing",layers:"Layers",code:"Code"};const Kx=re.defaults;const Du="A plain text, or code of your application with a = in front (=t('Name')): the file keeps the code and the application runs it when it loads the file. ==x is the text =x.";function Eu(n){if(dn(n))return`=${n.$expr}`;if(typeof n!=="string")return"";return n.startsWith("=")?`=${n}`:n}function ql(n){if(n.startsWith("=="))return n.slice(1);if(n.startsWith("=")&&n.slice(1).trim()!=="")return{$expr:n.slice(1).trim()};return n}const zu=/* @__PURE__ */new Set(["e:name","f:name","f:layers","v:minWidth","v:cols","g:division"]);const _x=[{key:"message",kind:"text",description:"Where the message of a field stands and how: \"bottom right text\" (the default of the library), \"top right badge -9 -6\" (a badge on the corner)."},{key:"reserveMessageSpace",kind:"boolean",description:"Room under the field for its message. A form keeps none (the message lies over what is under the field): give the field more rows and turn this on for room."},{key:"validateOn",kind:"select",options:["touched","input"],description:"When a field starts to report its validation: when it is left (touched) or as it is typed (input)."},{key:"validationIcons",kind:"boolean",description:"The symbols of the validation in a field (a check mark, an exclamation mark)."},{key:"validationColorFrame",kind:"boolean",description:"The frame of a field takes the color of its validation."},{key:"validationMessage",kind:"boolean",description:"The text of the validation is shown in the place of the message."},{key:"labelPlace",kind:"select",options:["start","end"],description:"The side of the label of a switch, a checkbox or a radio group."}];function Ii(n,e){const t=[];const o={};for(const i of _x){const r=`d:${i.key}`;const s=i.kind==="boolean"?[H(Y,"(not set)"),H(true,"true"),H(false,"false")]:i.options?[H(Y,"(not set)"),...i.options.map(l=>H(l,l))]:void 0;t.push({id:r,label:i.key,kind:s?"select":"text",category:re.defaults,description:`${i.description} Set here for ${e}; a nearer one wins.`,...(s?{options:s}:{}),placeholder:"(not set)"});const a=n?.[i.key];o[r]=a===void 0?s?Y:"":a}return{rows:t,values:o}}function Gx(n,e,t){const o=z(n,e.form);if(!o)return null;if(e.names.length>1)return qx(n,e);if(e.names.length===1)return Bx(n,e,e.names[0]);if(e.scope==="file")return Jx(n);if(e.scope==="form")return Yx(n,e.form);return Ux(n,e,t.track)}function Bx(n,e,t){const o=z(n,e.form);const i=o?ge(o,t):void 0;if(!o||!i)return null;const r=i.element;const s=[];const a={};const l=i.parent===null?void 0:V(o,i.parent);const d=W(l);s.push({id:"e:name",label:"name",kind:"text",category:re.element,description:r.kind==="input"?`The name of the place: the application puts its control here by it (*gfyFormArea="'name'"), and reaches the cell of the place by it (elementOf('name') of GfyForm). Unique in the form.`:"The name of the element, unique in the form: the application reaches what the form draws for it by it (elementOf('name') of GfyForm: a group, a property sheet, a text)."});a["e:name"]=r.name;s.push({id:"e:kind",label:"kind",kind:"readonly",category:re.element,description:"static: a text of the layout; input: the place of a control of the application; group: elements that belong together; subform: another form of the file."});a["e:kind"]=d?"group (a page of a property sheet)":r.kind;const c=(o.layers??[]).flatMap(p=>p.layers.map(h=>H(h,`${h} (${p.name})`)));s.push({id:"e:layer",label:"layer",kind:"select",category:re.element,description:"The element is shown only while its layer is the active one of its group (the Form has the groups of layers). Without one, it is always shown.",options:[H(Y,"(no layer)"),...c],disabled:c.length===0&&!r.layer});a["e:layer"]=r.layer??Y;switch(r.kind){case"static":{s.push({id:"e:text",label:"text",kind:"text",category:re.text,description:Du});a["e:text"]=Eu(r.text);const p=ve(o).filter(h=>h.element.kind==="input");s.push({id:"e:for",label:"for",kind:"select",category:re.text,description:"The input this text is the label of: it names the control for a screen reader, a click on it focuses the control, and in the page it stands right before the control. Only a label and a caption name an input (a plain text and a separator do not).",options:[H(Y,"(none)"),...p.map(h=>H(h.name,h.name))]});a["e:for"]=r.for??Y;s.push({id:"e:appearance",label:"appearance",kind:"select",category:re.text,description:"label: the bold look of the label of a field (the default); caption: small and muted; text: plain text; separator: a line across the place, with the text on it (an empty text: a plain line).",options:[H(Y,"label (default)"),H("caption","caption"),H("text","text"),H("separator","separator")]});a["e:appearance"]=r.appearance&&r.appearance!=="label"?r.appearance:Y;break}case"input":{const p=r.preview?.as??"";const h=it(p);s.push({id:"e:preview",label:"preview.as",kind:"select",category:re.preview,description:"How the Editor and the Preview draw the place: as this component of the library, or as a component of your application (its tag is the next row). Only the editor reads it; the application puts its own control or content here.",options:[H(Y,"(a box)"),...ki.map(m=>H(m.as,Il[m.as])),H(Hl,"Own component (the tag of a component of the application)")]});a["e:preview"]=h?Hl:an(p)?p:Y;if(h){s.push({id:"e:tag",label:"preview.as (tag)",kind:"text",category:re.preview,description:`The tag of the component of your application that stands here: the Editor and the Preview draw a box with it, the template of the Output writes it (the component imports it from your application). ${Kh}`});a["e:tag"]=p}const u=r.preview?.props??{};for(const m of an(p)?.props??[]){const g=Rh[m];s.push(Qx(g));a[`pp:${m}`]=e1(g,u[m])}const f=Ii(r.defaults,"this field");s.push(...f.rows);Object.assign(a,f.values);break}case"group":{s.push({id:"e:title",label:"title",kind:"text",category:re.group,description:`${d?"The text of the tab of the page.":"The title on the frame; it is also the name of the group for a screen reader."} ${Du}`});a["e:title"]=Eu(r.title);if(!d){s.push({id:"e:look",label:"look",kind:"select",category:re.group,description:"group-box: a frame with the title on its top line; none: no frame; property-sheet: a frame with tabs whose pages are the groups in it.",options:Object.entries(zv).map(([h,u])=>H(h==="group-box"?Y:h,u))});a["e:look"]=r.look&&r.look!=="group-box"?r.look:Y}if(!d&&!W(r)){s.push({id:"e:repeat",label:"repeat",kind:"boolean",category:re.group,description:"The place holds one instance of the group, and the application says how many there are (a gfy-repeater in the place): each one after the first takes rows of its own under it."});a["e:repeat"]=r.repeat===true}const p=Ii(r.defaults,"the fields of the group");s.push(...p.rows);Object.assign(a,p.values);break}case"subform":{const p=bs(n,e.form);const h=p.includes(r.form)?p:[r.form,...p];s.push({id:"e:form",label:"form",kind:"select",category:re.subform,description:"The form of the file that stands here. Its fields are reached by a path: billing.street for the input street of the subform billing.",options:h.map(f=>H(f,f))});a["e:form"]=r.form;s.push({id:"e:repeat",label:"repeat",kind:"boolean",category:re.subform,description:"The place holds one instance of the subform, and the application says how many there are (a gfy-repeater in the place)."});a["e:repeat"]=r.repeat===true;const u=Ii(r.defaults,"the fields of the subform");s.push(...u.rows);Object.assign(a,u.values);break}}Hx(n,e,i.element,s,a);return{kind:"element",title:d?"Page":Vx(r),subtitle:r.name,rows:s,values:a}}function Vx(n){switch(n.kind){case"static":return n.appearance==="caption"?"Caption":n.appearance==="text"?"Text":n.appearance==="separator"?"Separator":"Label";case"input":return it(n.preview?.as)?"Own component":n.preview?.as?Il[n.preview.as]??"Input":"Input";case"group":return n.look==="property-sheet"?"Property sheet":n.repeat?"Repeated group":n.look==="none"?"Group":"Group box";case"subform":return n.repeat?"Repeated subform":"Subform"}}function Hx(n,e,t,o,i){const r=z(n,e.form);const s=G(r,e.minWidth);if(!r||!s)return;const a=ye(s,t.name);const l=Ne(r,s).find(m=>m.name===t.name);const d=l?.bounds??null;const c=`${re.place} (from ${s.minWidth} px)`;o.push({id:"p:placed",label:"placed",kind:"boolean",category:c,description:d?"The element has a place in this variant. Without one it is not shown at these widths (nor is anything in it); the other variants keep theirs.":"The group the element is in has no place in this variant, so neither has the element.",disabled:!d});i["p:placed"]=a!==null;if(!a)return;const p=rt(a);const h=d?.colSpan??s.cols;const u=l?.parent?`the cells of the group "${l.parent}"`:"the grid";o.push({id:"p:col",label:"col",kind:"number",category:c,description:`The first column, counted in ${u} from 1.`,min:1,max:h,step:1});o.push({id:"p:row",label:"row",kind:"number",category:c,description:`The first row, counted in ${u} from 1.`,min:1,step:1});o.push({id:"p:colSpan",label:"colSpan",kind:"number",category:c,description:"How many columns the place takes.",min:1,max:h,step:1});o.push({id:"p:rowSpan",label:"rowSpan",kind:"number",category:c,description:"How many rows the place takes.",min:1,step:1});Object.assign(i,{"p:col":p.col,"p:row":p.row,"p:colSpan":p.colSpan,"p:rowSpan":p.rowSpan});const f=[H("start","start"),H("center","center"),H("end","end"),H("stretch","stretch")];if(t.kind==="static"||t.kind==="input"){o.push({id:"p:align",label:"align",kind:"select",category:c,description:"Where the element stands in its place, down: center (the default) keeps its own height; stretch makes it as high as the place (a text area, a list).",options:[H(Y,"center (default)"),...f.filter(m=>m.value!=="center")]});o.push({id:"p:justify",label:"justify",kind:"select",category:c,description:"Where the element stands in its place, across: stretch (the default) makes it as wide as the place, so buttons on places of one width are as wide as each other; the others keep its own width (a button as wide as its text).",options:[H(Y,"stretch (default)"),...f.filter(m=>m.value!=="stretch")]});i["p:align"]=a.align&&a.align!=="center"?a.align:Y;i["p:justify"]=a.justify&&a.justify!=="stretch"?a.justify:Y}if(t.kind==="subform"){o.push({id:"p:flow",label:"flow",kind:"boolean",category:c,description:"The subform may need more rows than its place has: they are added under the place. Without it the subform has to fit into its place."});i["p:flow"]=a.flow===true}if(W(t)){o.push({id:"p:tabs",label:"tabs",kind:"select",category:c,description:"Where the tabs stand in this variant: a wide variant can put them at the side and a narrow one on top. The pages move with the tabs (they leave the cells of the tabs free), and what is on a page stays where it is on the page.",options:[H(Y,"top (default)"),H("bottom","bottom"),H("start","start"),H("end","end")]});i["p:tabs"]=a.tabs&&a.tabs!=="top"?a.tabs:Y}}function qx(n,e){const t=z(n,e.form);if(!t)return null;const o=e.names.map(d=>V(t,d)).filter(d=>d!==void 0);const i=[];const r={};const s=d=>{const c=d(o[0]);return o.every(p=>d(p)===c)?c:void 0};const a=(t.layers??[]).flatMap(d=>d.layers.map(c=>H(c,`${c} (${d.name})`)));if(a.length){i.push({id:"e:layer",label:"layer",kind:"select",category:re.element,description:"The layer of all the selected elements.",options:[H(Y,"(no layer)"),...a]});r["e:layer"]=s(d=>d.layer??Y)??null}const l=G(t,e.minWidth);if(l&&o.every(d=>d.kind==="static"||d.kind==="input")){const d=[H("start","start"),H("center","center"),H("end","end"),H("stretch","stretch")];const c=`${re.place} (from ${l.minWidth} px)`;i.push({id:"p:align",label:"align",kind:"select",category:c,description:"Where the selected elements stand in their places, down.",options:[H(Y,"center (default)"),...d.filter(h=>h.value!=="center")]});i.push({id:"p:justify",label:"justify",kind:"select",category:c,description:"Where the selected elements stand in their places, across.",options:[H(Y,"stretch (default)"),...d.filter(h=>h.value!=="stretch")]});const p=(h,u)=>h&&h!==u?h:Y;r["p:align"]=s(h=>p(ye(l,h.name)?.align,"center"))??null;r["p:justify"]=s(h=>p(ye(l,h.name)?.justify,"stretch"))??null}if(l&&o.every(d=>ye(l,d.name))){const d=`${re.place} (from ${l.minWidth} px)`;i.push({id:"p:colSpan",label:"colSpan",kind:"number",category:d,description:"The columns each of the selected elements takes (from the column where it starts).",min:1,max:_e,step:1});i.push({id:"p:rowSpan",label:"rowSpan",kind:"number",category:d,description:"The rows each of the selected elements takes (from the row where it starts).",min:1,max:_e,step:1});r["p:colSpan"]=s(c=>ye(l,c.name)?.colSpan??1)??null;r["p:rowSpan"]=s(c=>ye(l,c.name)?.rowSpan??1)??null}if(o.every(d=>d.kind==="static")){i.push({id:"e:appearance",label:"appearance",kind:"select",category:re.text,description:"The look of the selected texts.",options:[H(Y,"label (default)"),H("caption","caption"),H("text","text"),H("separator","separator")]});r["e:appearance"]=s(d=>d.kind==="static"&&d.appearance&&d.appearance!=="label"?d.appearance:Y)??null}return{kind:"elements",title:`${o.length} elements`,subtitle:o.map(d=>d.name).join(", "),rows:i,values:r}}function Ux(n,e,t){const o=z(n,e.form);const i=G(o,e.minWidth);if(!o||!i)return null;const r=[{id:"v:minWidth",label:"minWidth",kind:"number",category:re.grid,description:"The least width of the form for this variant, in px: the form uses the variant with the largest minWidth that is not above its width. One variant has 0, and keeps it (the narrowest widths need one).",min:0,step:10,unit:"px",...(i.minWidth===0?{disabled:true}:{})},{id:"v:cols",label:"cols",kind:"number",category:re.grid,description:"The columns of the grid. They share the width of the form, so a change keeps every element at its share of the width (the places are scaled). To add room at one place, insert a column there (the menu of its number above the grid).",min:1,max:_e,step:1},{id:"v:rows",label:"rows",kind:"number",category:re.grid,description:"The rows of the grid; the empty rows at the bottom are the declared height of the form. The grid grows by itself when an element goes below its last row.",min:1,max:_e,step:1}];const s={"v:minWidth":i.minWidth,"v:cols":i.cols,"v:rows":i.rows};const a=t?t.axis==="col"?i.cols:i.rows:0;const l=t?t.indices.filter(d=>d>=1&&d<=a):[];if(t&&l.length){const d=t.axis==="col"?i.colSizes:i.rowSizes;const c=m=>d&&Object.prototype.hasOwnProperty.call(d,String(m))?d[String(m)]:"";const p=l.length>1;const h=hn(l);const u=l.every(m=>c(m)===c(l[0]));const f=t.axis==="col"?p?"Columns":"Column":p?"Rows":"Row";r.push({id:"v:track",label:t.axis==="col"?`colSizes.${h}`:`rowSizes.${h}`,kind:"text",category:`${f} ${h}`,description:t.axis==="col"?`The size of ${p?"each of these columns":"this column"}: px, fr (a share of the width that is left) or auto. Empty: 1fr, the share of every column.${p?" What is typed here is given to all of them.":""}`:`The size of ${p?"each of these rows":"this row"}: px or auto. Empty: the height of a row of the grid.${p?" What is typed here is given to all of them.":""}`,placeholder:!u?"different sizes":t.axis==="col"?"1fr":"row of the grid"});s["v:track"]=u?c(l[0]):""}return{kind:"variant",title:"Variant",subtitle:`${o.name}, from ${i.minWidth} px`,rows:r,values:s}}function $s(n){return typeof n==="number"?String(n):typeof n==="string"?n:""}function Yx(n,e){const t=z(n,e);if(!t)return null;const o=[{id:"f:name",label:"name",kind:"text",category:re.element,description:"The name of the form, unique in the file: what <gfy-form name=\"...\"> and a subform name."},{id:"f:layers",label:"layers",kind:"text",category:re.layers,description:`The groups of layers: parts of the form of which one is shown at a time. Write a group, a colon and its layers, groups separated by semicolons: subject: person, company. One group needs no name: person, company is the group layer. The application chooses the layer of a group by its name ([layers]="{subject: 'company'}"); the first layer of a group is shown until it does.`,placeholder:"subject: person, company"},{id:"f:spacingX",label:"spacing.x",kind:"text",category:re.spacing,description:"The space between two elements across: px (0 to 100) or a share of the height of a control (\"50%\"). Empty: the spacing of the file, or of the density. Where the form stands as a subform, it lies on the cells of the form it stands in and takes its spacing: its own counts where it is laid out by itself.",placeholder:"of the file"},{id:"f:spacingY",label:"spacing.y",kind:"text",category:re.spacing,description:"The space between two elements down: px (0 to 100) or a share of the height of a control (\"50%\"). A row is (the height of a control + this space) / grid.division high, and a field takes grid.division rows, so it is as high as a control and this space (half above it, half under it): a smaller space makes all the rows and the fields lower, a finer division does not. Empty: the spacing of the file, or of the density. Where the form stands as a subform, it lies on the cells of the form it stands in and takes its spacing: its own counts where it is laid out by itself.",placeholder:"of the file"}];const i={"f:name":t.name,"f:layers":vx(t),"f:spacingX":$s(t.spacing?.x),"f:spacingY":$s(t.spacing?.y)};const r=Ii(t.defaults,"the fields of the form");return{kind:"form",title:"Form",subtitle:t.name,rows:[...o,...r.rows],values:{...i,...r.values}}}function Jx(n){const e=[{id:"g:division",label:"grid.division",kind:"number",category:re.grid,description:"Into how many rows one line of fields is divided (1 to 4, default 2): a row is (the height of a control + the vertical space) / division high. With 2 a field takes two rows and a label above it one. A new division scales the rows of every variant of every form, so the elements keep their heights (rows that do not divide are rounded, and the status bar names what became lower than a control).",min:1,max:4,step:1,placeholder:"2"},{id:"g:spacingX",label:"spacing.x",kind:"text",category:re.spacing,description:"The space between two elements across, for all the forms: px (0 to 100) or a share of the height of a control (\"50%\"). Empty: the spacing of the density.",placeholder:"of the density"},{id:"g:spacingY",label:"spacing.y",kind:"text",category:re.spacing,description:"The space between two elements down, for all the forms: px (0 to 100) or a share of the height of a control (\"50%\"). A row is (the height of a control + this space) / grid.division high, and a field takes grid.division rows, so it is as high as a control and this space (half above it, half under it): a smaller space makes all the rows and the fields lower, a finer division does not. Empty: the spacing of the density.",placeholder:"of the density"},{id:"g:minFormWidth",label:"minFormWidth",kind:"number",category:re.grid,description:"The narrowest a form of the file gets, in px. <gfy-form> is not narrower: in a narrower container the form keeps this width (and the variant of this width), and the container scrolls it. The sliders of the Editor and of the Preview start at it (without it at 240 px); the Editor shows a variant that is not used at this width at its own widths. The variants below the one of this width are never used (a warning in the Problems; not for a form that a subform places, which takes the variant that fits its place). Empty: no limit, the columns of the narrowest variant get as narrow as the form.",min:0,step:10,placeholder:"no limit"},{id:"g:functions",label:"functions",kind:"text",category:re.code,description:"The functions of your application that the texts may call, separated by commas (s.field:2 for one whose second argument is the text). Not t, tr, tx and tk: they are the translations of the library, which the texts call without an entry here.",placeholder:"none"}];const t={"g:division":n.grid?.division??null,"g:spacingX":$s(n.spacing?.x),"g:spacingY":$s(n.spacing?.y),"g:minFormWidth":typeof n.minFormWidth==="number"&&n.minFormWidth>0?n.minFormWidth:null,"g:functions":(Array.isArray(n.functions)?n.functions:[]).join(", ")};const o=Ii(n.defaults,"all the fields of the file");return{kind:"file",title:"File",subtitle:`${n.forms.length} ${n.forms.length===1?"form":"forms"}`,rows:[...e,...o.rows],values:{...t,...o.values}}}const Dn=n=>typeof n==="number"&&Number.isFinite(n)?n:typeof n==="string"&&n.trim()!==""&&Number.isFinite(Number(n))?Number(n):null;const Xx=(n,e,t)=>n.split(",").map(o=>o.trim()).filter(o=>o!=="").map(o=>t==="items"?{label:o}:e==="gfy-combobox"?o:{value:o,label:o});function Zx(n,e,t,o,i){const r={form:e.form,minWidth:e.minWidth};const s=z(n,e.form);if(!s)return{file:n};if(e.names.length>1)return o1(n,e,t,o);if(e.names.length===1)return Lu(n,r,e.names[0],t,o,i.tabColumns??4);if(t.startsWith("d:")){const a=t.slice(2);const l=e.scope==="file"?{}:{form:e.form};return Mu(n,l,a,o===Y?void 0:o)}switch(t){case"g:division":return Sx(n,Dn(o));case"g:minFormWidth":{const a=Dn(o);return Ax(n,a===null?null:Math.round(a))}case"g:spacingX":case"g:spacingY":case"f:spacingX":case"f:spacingY":{const a=Mx(String(o??""));if(a===void 0)return{file:n,refused:"A space is a whole number of px from 0 to 100, or a share of the height of a control such as 50%."};return $x(n,t.startsWith("g:")?null:e.form,t.endsWith("X")?"x":"y",a)}case"g:functions":{const a=String(o??"").split(/[,\s]+/).map(d=>d.trim()).filter(d=>d!=="");const l=a.filter(d=>qn.includes(d.replace(/:\d+$/,"")));if(l.length)return{file:n,refused:`${l.join(", ")} ${l.length===1?"is a translation":"are translations"} of the library: the texts call ${l.length===1?"it":"them"} without an entry in functions.`};return Cx(n,a)}case"f:name":return bx(n,e.form,String(o??"").trim());case"f:layers":{const a=xx(String(o??""));if("error"in a)return{file:n,refused:a.error};return kx(n,e.form,a.groups)}case"v:minWidth":{const a=Dn(o);return a===null?{file:n}:dx(n,e.form,e.minWidth,Math.round(a))}case"v:cols":{const a=Dn(o);return a===null?{file:n}:fx(n,r,Math.round(a))}case"v:rows":{const a=Dn(o);return a===null?{file:n}:wu(n,r,Math.round(a))}case"v:track":{if(!i.track)return{file:n};const a=String(o??"").trim();const l=i.track.indices.map(d=>[d,a===""?null:a]);return _l(n,r,i.track.axis,l)}}return{file:n}}function Lu(n,e,t,o,i,r=4){const s=z(n,e.form);const a=V(s,t);if(!a)return{file:n};if(o.startsWith("d:"))return Mu(n,{form:e.form,element:t},o.slice(2),i===Y?void 0:i);if(o.startsWith("p:"))return n1(n,e,t,o.slice(2),i,r);switch(o){case"e:name":return Kl(n,e.form,t,String(i??"").trim());case"e:layer":return Vt(n,e,t,"layer",i===Y?void 0:i);case"e:text":case"e:title":{const l=ql(String(i??""));return Vt(n,e,t,o==="e:text"?"text":"title",o==="e:title"&&l===""?void 0:l)}case"e:for":case"e:appearance":case"e:look":case"e:form":return Vt(n,e,t,o.slice(2),i===Y?void 0:i);case"e:repeat":return Vt(n,e,t,"repeat",i===true?true:void 0);case"e:preview":{if(a.kind!=="input")return{file:n};if(i===Y)return In(n,e,t,null);const l=a.preview?.as;if(i===Hl)return it(l)?{file:n}:In(n,e,t,{as:El(t)});const d=String(i);const c=new Set(an(d)?.props??[]);const p=Object.fromEntries(Object.entries(a.preview?.props??{}).filter(([u])=>c.has(u)));const h={...(Si[d]??{}),...p};return In(n,e,t,{as:d,props:h})}case"e:tag":{if(a.kind!=="input")return{file:n};const l=String(i??"").trim();if(l===a.preview?.as)return{file:n};if(l==="")return In(n,e,t,null);if(an(l))return Lu(n,e,t,"e:preview",l);if(!it(l))return{file:n,refused:`"${l}" is no tag. ${Kh}`};return In(n,e,t,{as:l})}}if(o.startsWith("pp:"))return t1(n,e,a,o.slice(3),i);return{file:n}}function Qx(n){const e={id:`pp:${n.key}`,label:`preview.props.${n.key}`,category:re.preview,description:`${n.description} The Preview shows it, and the template of the Output writes it.`};switch(n.kind){case"select":return{...e,kind:"select",options:[H(Y,"(default)"),...(n.choices??[]).map(t=>H(t,t))]};case"boolean":return{...e,kind:"boolean"};case"number":return{...e,kind:"text",placeholder:"(default)"};default:return{...e,kind:"text"}}}function e1(n,e){switch(n.kind){case"select":return typeof e==="string"&&(n.choices??[]).includes(e)?e:Y;case"boolean":return e===true;case"list":return(Array.isArray(e)?e:[]).map(t=>typeof t==="string"?t:String(t?.label??"")).join(", ");default:return typeof e==="string"||typeof e==="number"?String(e):""}}function t1(n,e,t,o,i){const r=Rh[o];if(t.kind!=="input"||!t.preview||!r)return{file:n};const s={...(t.preview.props??{})};const a=i===null||i===void 0?"":String(i).trim();if(r.kind==="boolean"){if(i===true)s[o]=true;else delete s[o]}else if(a===""||i===Y)delete s[o];else if(r.kind==="list")s[o]=Xx(a,t.preview.as,o);else if(r.kind==="number"){const l=Number(a.replace(",","."));if(!Number.isFinite(l))return{file:n,refused:`${o} is a number, not "${a}".`};s[o]=l}else if(o==="height"&&/^\d+$/.test(a))s[o]=Number(a);else s[o]=r.kind==="select"?String(i):String(i??"");return In(n,e,t.name,{as:t.preview.as,props:s})}function n1(n,e,t,o,i,r){const s=z(n,e.form);const a=G(s,e.minWidth);if(!a)return{file:n};const l=ye(a,t);if(o==="placed"){if(i===true&&!l)return du(n,e,[t],$n(n));if(i!==true&&l)return vs(n,e,t,null);return{file:n}}if(!l)return{file:n};if(o==="tabs"&&W(V(s,t)))return Yv(n,e,t,i===Y?void 0:i,r);if(o==="align"||o==="justify"||o==="flow"||o==="tabs")return xs(n,e,t,o,i===Y?void 0:i);const d=Dn(i);if(d===null)return{file:n};const c=Ne(s,a).find(f=>f.name===t);if(!c?.cells||!c.bounds)return{file:n};const p=rt(l);const h={...p,[o]:Math.max(1,Math.round(d))};const u={col:c.bounds.col+h.col-1,row:c.bounds.row+h.row-1,colSpan:h.colSpan,rowSpan:h.rowSpan};if(o==="col"||o==="row")return ws(n,e,[{name:t,parent:c.parent,cells:{...u,colSpan:p.colSpan,rowSpan:p.rowSpan}}]);return Ai(n,e,t,u)}function o1(n,e,t,o){const i={form:e.form,minWidth:e.minWidth};let r=n;for(const s of e.names){let a;if(t==="p:align"||t==="p:justify")a=xs(r,i,s,t.slice(2),o===Y?void 0:o);else if(t==="e:layer"||t==="e:appearance")a=Vt(r,i,s,t.slice(2),o===Y?void 0:o);else if(t==="p:colSpan"||t==="p:rowSpan"){const l=Dn(o);if(l===null||!Number.isInteger(l)||l<1)return{file:n,refused:"A size is a whole number of cells, 1 or more."};const d=z(r,i.form);const c=d?Ne(d,G(d,i.minWidth)).find(p=>p.name===s):void 0;if(!c?.cells)continue;a=Ai(r,i,s,t==="p:colSpan"?{...c.cells,colSpan:l}:{...c.cells,rowSpan:l})}else return{file:n};if(a.refused)return{file:n,refused:a.refused};r=a.file}return{file:r}}const As=qn;function Ul(n){const e=/^\s*([A-Za-z_$][\w$]*(?:\s*\.\s*[A-Za-z_$][\w$]*)*)\s*\(/.exec(n);return e?e[1].replace(/\s+/g,""):null}const Yl=n=>Array.isArray(n.functions)?n.functions.filter(e=>typeof e==="string").map(e=>e.replace(/:\d+$/,"")):[];function En(n){if(!n||!n.form)return"file";const e=[n.form];if(n.minWidth!==void 0)e.push(`≥ ${n.minWidth} px`);if(n.element)e.push(n.element);return e.join(" › ")}function i1(n){return n.map((e,t)=>{const o=e.form!==void 0?{form:e.form,minWidth:e.minWidth,element:e.element}:null;return{id:`lib:${e.code}:${e.path}:${t}`,severity:e.severity,code:e.code,message:e.message,file:En(o),path:e.path||"the file",target:o}})}function r1(n){const e=[];const t=$n(n);const o=/* @__PURE__ */new Set([...As,...Yl(n)]);const i=/* @__PURE__ */new Set;for(const s of n.forms){for(const a of Nt(s)){const l=Ne(s,a);const d=new Map(l.map(c=>[c.name,c]));for(const c of l){if(c.cells&&c.cells.rowSpan<as(c.element,t)){const b={form:s.name,minWidth:a.minWidth,element:c.name};e.push({id:`edit:low:${s.name}:${a.minWidth}:${c.name}`,severity:"warning",code:"low",message:`"${c.name}" is ${c.cells.rowSpan} row${c.cells.rowSpan===1?"":"s"} high: a control needs ${t} (its height and the vertical space around it), so it would reach over what is above or under it. Make it higher (Shift and Down in the Editor).`,file:En(b),path:`forms[${n.forms.indexOf(s)}].variants[${s.variants.indexOf(a)}].places.${c.name}`,target:b})}const p=c.cells?s1(c.element,c.place?.align):null;if(p){const b={form:s.name,minWidth:a.minWidth,element:c.name};e.push({id:`edit:collapse:${s.name}:${a.minWidth}:${c.name}`,severity:"warning",code:"collapse",message:p,file:En(b),path:`forms[${n.forms.indexOf(s)}].variants[${s.variants.indexOf(a)}].places.${c.name}`,target:b})}if(!c.cells||c.parent===null)continue;const h=d.get(c.parent);if(!h?.cells||h.element.kind!=="group")continue;const u=h.element.look??"group-box";const f=h.parent===null?null:d.get(h.parent);const m=f?.element.kind==="group"&&f.element.look==="property-sheet";if(u==="none"||m)continue;const g=On(h.cells,Gt(h.element,h.place,t,1));if(Ee(c.cells,g))continue;const y={form:s.name,minWidth:a.minWidth,element:c.name};if(u==="property-sheet"){const b=h.place?.tabs??"top";const x=t===1?"row":`${t} rows`;const T=b==="bottom"?`its last ${x}`:b==="start"?"the columns before its pages":b==="end"?"the columns after its pages":`its first ${x}`;e.push({id:`edit:tabs:${s.name}:${a.minWidth}:${c.name}`,severity:"warning",code:"tabs",message:`The page "${c.name}" stands on the tabs or the frame of the property sheet "${h.name}" (its tabs are in ${T}, its frame in the other edge cells): what is on the page lies under them. Make the page smaller, or put the tabs at another side and back (the pages follow the tabs).`,file:En(y),path:`forms[${n.forms.indexOf(s)}].variants[${s.variants.indexOf(a)}].places.${c.name}`,target:y});continue}e.push({id:`edit:frame:${s.name}:${a.minWidth}:${c.name}`,severity:"warning",code:"frame",message:`"${c.name}" stands on the frame of the group box "${h.name}": the first ${t===1?"row":`${t} rows`} (the title), the last row and the first and the last column are the frame's.`,file:En(y),path:`forms[${n.forms.indexOf(s)}].variants[${s.variants.indexOf(a)}].places.${c.name}`,target:y})}}for(const a of ve(s)){const l=a.element.kind==="static"?a.element.text:a.element.kind==="group"?a.element.title:void 0;if(!dn(l))continue;const d=Ul(l.$expr);if(d===null||o.has(d)||i.has(`${s.name}:${d}`))continue;i.add(`${s.name}:${d}`);const c={form:s.name,element:a.name};e.push({id:`edit:function:${s.name}:${d}`,severity:"warning",code:"function",message:`"${a.name}" calls ${d}(), which is neither a function of the library (${As.join(", ")}) nor in the functions of the file: add it to the functions of the file (the Inspector of the file) and register it when the file is loaded.`,file:En(c),path:a.element.kind==="static"?"text":"title",target:c})}}const r=Yl(n).filter(s=>As.includes(s));if(r.length)e.push({id:"edit:function-listed",severity:"warning",code:"function",message:`The functions of the file list ${r.join(", ")}, ${r.length===1?"a translation":"translations"} of the library: the texts call ${r.length===1?"it":"them"} without an entry (the Inspector of the file).`,file:"file",path:"functions",target:null});return e}function s1(n,e){if(n.kind!=="input")return null;const t=n.preview?.as;const o=n.preview?.props?.["height"];if(t!=="gfy-picture"&&t!=="gfy-picture-gallery"||typeof o!=="string"||!o.trim().endsWith("%"))return null;if(t==="gfy-picture-gallery")return`"${n.name}" is ${o.trim()} high: a gallery cannot take a share of its place (its title and its strip are in it too), so its picture would not be seen. Give it a height in px (preview.props.height).`;if(e==="stretch")return null;return`"${n.name}" is ${o.trim()} high, but its place does not stretch it (align ${e??"center"}): the picture has no height then and is not seen. Set align to stretch, or give it a height in px.`}function a1(n){const e={};for(const t of n.forms){for(const o of ve(t)){const i=o.element.kind==="static"?o.element.text:o.element.kind==="group"?o.element.title:void 0;if(!dn(i))continue;const r=Ul(i.$expr);if(r)e[r]=(...s)=>String(s.find(a=>typeof a==="string")??"")}}for(const t of[...As,...Yl(n)])e[t]??=(...o)=>String(o.find(i=>typeof i==="string")??"");return e}const Ru={"gfy-input":"GfyInput","gfy-password":"GfyPassword","gfy-date-picker":"GfyDatePicker","gfy-textarea":"GfyTextarea","gfy-select":"GfySelect","gfy-combobox":"GfyCombobox","gfy-checkbox":"GfyCheckbox","gfy-radio-group":"GfyRadioGroup","gfy-switch":"GfySwitch","gfy-spinner":"GfySpinner","gfy-button":"GfyButton","gfy-split-button":"GfySplitButton","gfy-dropdown-button":"GfyDropdownButton","gfy-label":"GfyLabel","gfy-time-picker":"GfyTimePicker","gfy-date-time-picker":"GfyDateTimePicker","gfy-mask-input":"GfyMaskInput","gfy-multi-select":"GfyMultiSelect","gfy-tags":"GfyTags","gfy-slider":"GfySlider","gfy-toggle-group":"GfyToggleGroup","gfy-color-picker":"GfyColorPicker","gfy-file-upload":"GfyFileUpload","gfy-picture":"GfyPicture","gfy-picture-gallery":"GfyPictureGallery","gfy-digital-display":"GfyDigitalDisplay","gfy-repeater":"GfyRepeater"};const l1={"gfy-picture":{input:"src",suffix:"Src",type:"string | null",start:"null",what:"The address of the picture in"},"gfy-picture-gallery":{input:"items",suffix:"Pictures",type:"{src: string; caption?: string}[]",start:"[]",what:"The pictures in"},"gfy-digital-display":{input:"value",suffix:"Value",type:"number | string | null",start:"null",what:"What is shown in"}};const c1=/* @__PURE__ */new Set(["mask","min","max","appearance","multiple","fit","height","caption","mode","format","size","variant","icon"]);const d1=/* @__PURE__ */new Set(["gfy-button","gfy-split-button","gfy-dropdown-button"]);const Lo=n=>`'${n.replace(/\\/g,"\\\\").replace(/'/g,"\\'")}'`;const zn=n=>n.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;");const Ln=n=>n.replace(/[-_]+([a-zA-Z0-9])/g,(e,t)=>t.toUpperCase());const Fu=n=>n?n[0].toUpperCase()+n.slice(1):n;const Jl=n=>n.length>1&&n.endsWith("s")?n.slice(0,-1):n;function p1(n){const e=(Array.isArray(n)?n:[]).map(o=>typeof o==="string"?o:typeof o?.label==="string"?o.label:"").filter(o=>o!=="");const t=/* @__PURE__ */new Set;return e.map((o,i)=>{const r=o.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||`item-${i+1}`;let s=r;for(let a=2;t.has(s);a++)s=`${r}-${a}`;t.add(s);return{id:s,label:o}})}const Di=n=>/^[A-Za-z_$][\w$]*$/.test(n)?n:Lo(n);function Xl(n){if(Array.isArray(n))return`[${n.map(Xl).join(", ")}]`;if(n!==null&&typeof n==="object"){const e=Object.entries(n).filter(([,t])=>t!==void 0);return`{${e.map(([t,o])=>`${/^[A-Za-z_$][\w$]*$/.test(t)?t:JSON.stringify(t)}: ${Xl(o)}`).join(", ")}}`}return JSON.stringify(n)??"null"}const ju=(n,e)=>Ln(`${n}${e}`.replace(/\./g,"_"));const Pu=(n,e)=>`${ju(n,e)}List`;function Cs(n){if(n.kind!=="input")return{tag:"gfy-input",props:{}};const e=n.preview?.as;const t=e&&(Ru[e]||it(e))?e:"gfy-input";return{tag:t,props:{...(n.preview?.props??{})}}}const h1=n=>n.kind==="input"&&!it(Cs(n).tag)&&(an(Cs(n).tag)?.role??"field")==="field";function u1(n,e){if(typeof e==="string")return e===""?null:`${n}="${zn(e)}"`;if(e===true)return n;if(typeof e==="number"&&Number.isFinite(e))return`[${n}]="${e}"`;return null}function Wu(n){switch(n){case"gfy-checkbox":case"gfy-switch":return"false";case"gfy-spinner":return"this.fb.control<number | null>(null)";case"gfy-slider":return"this.fb.control<number>(0)";case"gfy-select":case"gfy-radio-group":case"gfy-toggle-group":case"gfy-time-picker":case"gfy-date-time-picker":return"this.fb.control<string | null>(null)";case"gfy-multi-select":case"gfy-tags":return"this.fb.control<readonly string[]>([])";case"gfy-file-upload":return"this.fb.control<readonly File[]>([])";default:return"''"}}function Os(n,e,t,o,i,r,s,a){const l=[];for(const d of e){if(d.kind==="static")continue;if(d.kind==="group"&&!d.repeat){l.push(...Os(n,ce(d),t,o,i,r,s,a));continue}if(d.kind==="subform"&&!d.repeat){const c=a.includes(d.form)?void 0:z(n,d.form);if(!c)continue;const p=/* @__PURE__ */new Map;const h=Os(n,c.elements,`${t}${d.name}.`,`${o} `,i,p,s,[...a,c.name]);if(h.length===0)continue;if(s){l.push(...h.map(u=>u.slice(4)));for(const[u,f]of p)r.set(u,f)}else{l.push(`${o}<ng-container formGroupName="${d.name}">`,...h,`${o}</ng-container>`);r.set(d.name,p)}continue}if((d.kind==="group"||d.kind==="subform")&&d.repeat){l.push(...f1(n,d,t,o,i,r,a));continue}l.push(m1(d,t,o,i,r,s))}return l}function f1(n,e,t,o,i,r,s){i.usesRepeater=true;i.components.add("GfyRepeater");const a=Pu(t,e.name);let l=[];let d=s;if(e.kind==="group")l=ce(e);else if(e.kind==="subform"){const T=s.includes(e.form)?void 0:z(n,e.form);l=T?T.elements:[];d=T?[...s,T.name]:s}const c=ve({name:"",elements:l,variants:[]}).filter(T=>h1(T.element));const p=c.length===1&&e.kind==="group";const h=/* @__PURE__ */new Map;const u=Os(n,l,"",`${o} `,i,h,{single:p},d);const f=p?Wu(Cs(c[0].element).tag):"";const m=p?Ku(f):`{${[...h.keys()].map(T=>`${Di(T)}: ${Ku(h.get(T))}`).join("; ")}}`;const g=p?_u(f):`({${[...h.entries()].map(([T,k])=>`${Di(T)}: ${_u(k)}`).join(", ")}})`;const y=`new${Fu(ju(t,Jl(e.name)))}`;i.members.set(y,`protected readonly ${y} = (): ${m} => ${g};`);const b=/^[\w$]+$|^\{.*\}$/.test(m)?m:`(${m})`;r.set(e.name,`this.fb.control<readonly ${b}[]>([${g}])`);const x=u.some(T=>T.includes("(pressed)=\"add()\""));return[`${o}<!-- ${e.name}: a list, one instance of the part for every item -->`,`${o}<gfy-repeater *gfyFormArea="${Lo(`${t}${e.name}`)}" #${a} formControlName="${e.name}" [newItem]="${y}">`,`${o} <ng-template gfyRepeaterItem let-index="index" let-remove="remove" let-canRemove="canRemove"${x?" let-add=\"add\"":""}>`,...u,`${o} </ng-template>`,`${o}</gfy-repeater>`]}const Ku=n=>n==="false"?"boolean":/^this\.fb\.control<(.+)>\(.*\)$/.exec(n)?.[1]??"string";const _u=n=>/^this\.fb\.control<.+>\((.*)\)$/.exec(n)?.[1]??n;function m1(n,e,t,o,i,r){const{tag:s,props:a}=Cs(n);const l=`*gfyFormArea="${Lo(`${e}${n.name}`)}"`;const d=[];const c=n.name;if(it(s)){o.own.add(s);return`${t}<${s} ${l} />`}o.components.add(Ru[s]);const p=Object.entries(a).filter(([u])=>c1.has(u)&&(an(s)?.props??[]).includes(u)).map(([u,f])=>u1(u,f)).filter(u=>u!==null);const h=l1[s];if(h){const u=`${Ln(c)}${h.suffix}`;o.members.set(u,`/** ${h.what} "${c}". */
1108
+ protected readonly ${u}: ${h.type} = ${h.start};`);return`${t}<${s} ${l} [${h.input}]="${u}"${p.length?` ${p.join(" ")}`:""} />`}if(d1.has(s)){const u=typeof a["label"]==="string"?a["label"]:c;d.push(`label="${zn(u)}"`,...p);if(s!=="gfy-button"){const f=p1(a["items"]);const m=`${Ln(c)}Items`;const g=`${Ln(c)}Chosen`;o.usesMenuItems=true;o.members.set(m,`/** The items of the menu of "${c}". */
1109
+ protected readonly ${m}: GfyMenuItem[] = [${f.map(y=>`{id: ${Lo(y.id)}, label: ${Lo(y.label)}}`).join(", ")}];`);o.members.set(g,`protected ${g}(item: GfyMenuItem): void {
1110
+ // what the items of "${c}" do${f.length?` (item.id: ${f.map(y=>y.id).join(", ")})`:""}
1111
+ }`);d.push(`[items]="${m}"`,`(itemInvoked)="${g}($event)"`)}if(s==="gfy-dropdown-button")return`${t}<${s} ${l} ${d.join(" ")} />`;if(r&&/^remove/i.test(c))d.push("[disabled]=\"!canRemove\"","(pressed)=\"remove()\"");else if(r&&/^(add|insert)/i.test(c))d.push("(pressed)=\"add()\"");else{const f=/^add/i.test(c);const m=o.lists.filter(x=>x.path===e);const g=x=>x.find(T=>Jl(c.slice(3).toLowerCase())===Jl(T.item.toLowerCase()));const y=x=>x.length===1?x[0]:void 0;const b=f?g(m)??g(o.lists)??y(m)??y(o.lists):void 0;if(b)d.push(`(pressed)="${b.ref}().add()"`);else{const x=Ln(c);o.members.set(x,`protected ${x}(): void {
1112
+ // what the button "${c}" does
1113
+ }`);d.push(`(pressed)="${x}()"`)}}return`${t}<${s} ${l} ${d.join(" ")} />`}if(s==="gfy-label")return`${t}<gfy-label ${l}>${zn(typeof a["text"]==="string"?a["text"]:c)}</gfy-label>`;if(r){o.usesItemField=true;d.push(r.single?"gfyItemField":`gfyItemField="${c}"`)}else d.push(`formControlName="${c}"`);if(s==="gfy-textarea")d.unshift("fill");if((s==="gfy-checkbox"||s==="gfy-switch")&&typeof a["label"]==="string")d.push(`label="${zn(a["label"])}"`);if(s==="gfy-select"||s==="gfy-combobox"||s==="gfy-radio-group"||s==="gfy-multi-select"||s==="gfy-toggle-group"){const u=`${Ln(c)}Options`;const f=Array.isArray(a["options"])?a["options"]:[];o.members.set(u,`protected readonly ${u} = ${Xl(f)};`);d.push(`[options]="${u}"`);if(s==="gfy-radio-group"&&typeof a["orientation"]==="string")d.push(`orientation="${zn(a["orientation"])}"`)}if(typeof a["placeholder"]==="string"&&a["placeholder"]!=="")d.push(`placeholder="${zn(a["placeholder"])}"`);d.push(...p);i.set(c,Wu(s));return`${t}<${s} ${l} ${d.join(" ")} />`}function g1(n){const e=n.layers??[];if(e.length===0)return"";return` [layers]="{${e.map(t=>`${Di(t.name)}: ${Lo(t.layers[0]??"")}`).join(", ")}}"`}function Gu(){return{components:/* @__PURE__ */new Set(["GfyForm","GfyFormAreaTemplate"]),controls:/* @__PURE__ */new Map,lists:[],members:/* @__PURE__ */new Map,own:/* @__PURE__ */new Set,usesItemField:false,usesRepeater:false,usesMenuItems:false}}function b1(n,e,t="layout"){return Bu(n,e,t,Gu()).join("\n")}function Bu(n,e,t,o){const i=z(n,e);if(!i)return[`<!-- the file has no form "${e}" -->`];o.lists.push(...Zl(n,i.elements,[i.name]));const r=[`<gfy-form [layout]="${t}" name="${zn(i.name)}"${g1(i)}${ve(i).some(s=>W(s.element))?" [(pages)]=\"pages\"":""}>`];r.push(...Os(n,i.elements,""," ",o,o.controls,null,[i.name]),"</gfy-form>");return r}function Zl(n,e,t,o=""){const i=[];for(const r of e){if((r.kind==="group"||r.kind==="subform")&&r.repeat)i.push({ref:Pu(o,r.name),item:r.name,path:o});else if(r.kind==="group")i.push(...Zl(n,ce(r),t,o));else if(r.kind==="subform"&&!t.includes(r.form)){const s=z(n,r.form);if(s)i.push(...Zl(n,s.elements,[...t,s.name],`${o}${r.name}.`))}}return i}function y1(n){const e=/* @__PURE__ */new Set;const t=o=>{const i=dn(o)?Ul(o.$expr):null;if(i!==null)e.add(i)};for(const o of n.forms){for(const i of ve(o)){if(i.element.kind==="static")t(i.element.text);if(i.element.kind==="group")t(i.element.title)}}return[...e]}function Vu(n,e){const t=[...n.entries()];if(t.length===0)return"{}";const o=t.map(([i,r])=>`${e} ${Di(i)}: ${typeof r==="string"?r:`this.fb.group(${Vu(r,`${e} `)})`},`);return`{
1114
+ ${o.join("\n")}
1115
+ ${e}}`}function w1(n,e,t){const o=Gu();const i=y1(n);const r=Bu(n,e,i.length?"layout()":"layout",o);const s=i.filter(g=>qn.includes(g));const a=i.filter(g=>!qn.includes(g));const l=[...o.components].sort((g,y)=>g.localeCompare(y));if(o.usesRepeater)l.push("GfyRepeaterItemTemplate");if(o.usesItemField)l.push("GfyItemField");const d=[.../* @__PURE__ */new Set([...l,"gfyLoadFormLayout"])].sort((g,y)=>g.replace(/^gfy/,"Gfy").localeCompare(y.replace(/^gfy/,"Gfy")));const c=g=>`${Di(g)}: (text: string) => text`;const p=[s.length?`${s.join(", ")} ${s.length===1?"is":"are"} the translation of the library, which the loader makes`:"",a.length?`${a.join(", ")} ${a.length===1?"is a function":"are functions"} of your application to give here`:""].filter(Boolean).join("; ");const h=a.length?`, {functions: {${a.map(c).join(", ")}}}`:"";const u=`${Fu(Ln(e))}Form`;const f=r.some(g=>g.includes("[(pages)]"));const m=[`import {Component${i.length?", computed":""}, inject${f?", signal":""}${o.usesRepeater?", viewChild":""}} from '@angular/core';`,`import {NonNullableFormBuilder, ReactiveFormsModule} from '@angular/forms';`,`import {${d.join(", ")}} from '@gridify/studio';`,...(o.usesMenuItems?[`import type {GfyMenuItem} from '@gridify/studio';`]:[]),`import layoutFile from './${t}';`,"","@Component({",` selector: 'app-${e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}-form',`,` imports: [ReactiveFormsModule, ${l.filter(g=>g!=="gfyLoadFormLayout").join(", ")}${o.own.size?` /* and the components of your application: ${[...o.own].join(", ")} */`:""}],`," template: `"," <form [formGroup]=\"form\">",...r.map(g=>` ${g}`)," </form>"," `,","})",`export class ${u} {`," private readonly fb = inject(NonNullableFormBuilder);","",...(i.length?[` /** The layout of the file. Its texts call functions as it is loaded: ${p}. In a computed the file is loaded again when the language changes. */`,` protected readonly layout = computed(() => gfyLoadFormLayout(layoutFile${h}).layout);`]:[" /** The layout of the file. */"," protected readonly layout = gfyLoadFormLayout(layoutFile).layout;"]),""," /** A control for every place: a subform is a group, a list a control whose value is the list. */",` protected readonly form = this.fb.group(${Vu(o.controls," ")});`];if(f)m.push(""," /** The page shown in each property sheet, by the path of the sheet. */"," protected readonly pages = signal<Record<string, string>>({});");for(const g of o.lists)m.push("",` protected readonly ${g.ref} = viewChild.required<GfyRepeater<unknown>>('${g.ref}');`);for(const g of o.members.values())m.push("",` ${g}`);m.push("}");return m.join("\n").replace(/\n{3,}/g,"\n\n")}const un=n=>`<path fill="currentColor" fill-opacity=".22" stroke="none" d="${n}"/>`;const Ut=(n,...e)=>le(ae(...[n,...e].filter(Boolean)),un(e.join(" ")));const v1={"fme:preview":N("M1.75 8S4 3.75 8 3.75 14.25 8 14.25 8 12 12.25 8 12.25 1.75 8 1.75 8z","M8 6.25a1.75 1.75 0 1 0 0 3.5 1.75 1.75 0 0 0 0-3.5z"),"fme:editor":le(ae("M2.5 2.5h11v11h-11z","M2.5 6.2h11M2.5 9.8h11M6.2 2.5v11M9.8 2.5v11"),un("M6.2 6.2h3.6v3.6H6.2z")),"fme:form":N("M3 2.5h10v11H3z","M5 5h3M5 7.25h6M5 9.5h3M5 11.75h6"),"fme:variant":N("M2 4h12v8H2z","M5 4v8","M8.5 7h3"),"fme:add-variant":N("M2 4h8v8H2z","M5 4v8","M12.5 6v4M10.5 8h4"),"fme:file":N("M4 2.5h5.5l2.5 2.5v8.5H4z","M9.5 2.5V5H12"),"fme:label":N("M3 4.5h10M8 4.5v7.5M6 12h4"),"fme:caption":N("M4 6h8M4 9h5","M4 12h6"),"fme:text":N("M2.5 4.5h11M2.5 7.5h11M2.5 10.5h7"),"fme:input":N("M2.5 4.5h11v7h-11z","M4.75 6.5v3"),"fme:textarea":N("M2.5 3h11v10h-11z","M4.5 5.5h7M4.5 8h7M4.5 10.5h4"),"fme:select":N("M2.5 4.5h11v7h-11z","M10.5 7l1 1.25L12.5 7","M4.5 8h4"),"fme:combobox":N("M2.5 4.5h11v7h-11z","M10 4.5v7","M11 7.25l1 1 1-1","M4.5 8h3"),"fme:checkbox":N("M2.5 2.5h11v11h-11z","M5 8.25l2.25 2.25L11.25 5.5"),"fme:radio":le(ae("M8 2.25a5.75 5.75 0 1 0 0 11.5 5.75 5.75 0 0 0 0-11.5z"),nt("M8 5.25a2.75 2.75 0 1 0 0 5.5 2.75 2.75 0 0 0 0-5.5z")),"fme:switch":le(ae("M5.5 4.75h5a3.25 3.25 0 0 1 0 6.5h-5a3.25 3.25 0 0 1 0-6.5z"),nt("M10.5 6.25a1.75 1.75 0 1 0 0 3.5 1.75 1.75 0 0 0 0-3.5z")),"fme:spinner":N("M2.5 4.5h11v7h-11z","M10 4.5v7","M11.1 7.2 11.75 6.4l.65.8","M11.1 9.2l.65.8.65-.8"),"fme:button":le(ae("M2.5 5h11v6h-11z","M5 8h6"),un("M2.5 5h11v6h-11z")),"fme:styled-button":le("<path fill=\"currentColor\" fill-rule=\"evenodd\" stroke=\"none\" d=\"M2.5 5h11v6h-11zM5 7.4h6v1.2H5z\"/>"),"fme:split-button":le(ae("M1.5 5h13v6h-13z","M10.5 5v6","M3.75 8h4.5","M11.75 7.4l.75.75.75-.75"),un("M1.5 5h9v6h-9z")),"fme:dropdown-button":le(ae("M1.5 5h13v6h-13z","M3.75 8h5","M10.75 7.25 12 8.5l1.25-1.25"),un("M1.5 5h13v6h-13z")),"fme:label-above":N("M3 3h6","M2.5 6.5h11v5h-11z"),"fme:label-beside":N("M1.5 8h4","M7 5.5h7.5v5H7z"),"fme:group":N("M2.5 3.5h11v9h-11z","M4.5 6h7M4.5 8.5h7M4.5 11h4"),"fme:group-box":N("M5.5 4h8v9h-11V4H3","M3.25 4h1.5","M4.5 7h7M4.5 9.5h7"),"fme:sheet":N("M2.5 5.5h11v8h-11z","M2.5 5.5V3h4l.75 2.5","M7.25 3h3.25l.6 2.5"),"fme:page":N("M3.5 2.5h9v11h-9z","M5.5 5h5M5.5 7.5h5M5.5 10h3"),"fme:repeat":N("M2.5 3h11v3.5h-11z","M2.5 9.5h11V13h-11z","M8 6.5v3","M6.75 8.25 8 9.5l1.25-1.25"),"fme:subform":le(ae("M2.5 2.5h11v11h-11z"),ae("M5 5h6v6H5z"),un("M5 5h6v6H5z")),"fme:wrap":N("M2.5 2.5h11v11h-11z","M5 5.5h6M5 8h6M5 10.5h4"),"fme:unwrap":N("M2.5 2.5h3M10.5 2.5h3v3M13.5 10.5v3h-3M5.5 13.5h-3v-3","M5 6h6M5 8.5h6M5 11h4"),"fme:place":N("M2.5 2.5h11v11h-11z","M8 5v6M5 8h6"),"fme:unplace":N("M2.5 2.5h11v11h-11z","M5 8h6"),"fme:tab-order":le(ae("M2.5 4.5h4v7h-4z","M9.5 4.5h4v7h-4z","M7 8h2"),nt("M3.75 7.25h1.5v1.5h-1.5zM10.75 7.25h1.5v1.5h-1.5z")),"fme:layers":N("M8 2.5 14 5.5 8 8.5 2 5.5z","M2 8.25 8 11.25l6-3","M2 11l6 3 6-3"),"fme:label-for":N("M2.5 4h5","M2.5 9.5h11v4h-11z","M5 4v3.5l1.25-1.25M5 7.5 3.75 6.25"),"fme:columns":N("M2.5 3h11v10h-11z","M6.2 3v10M9.8 3v10"),"fme:rows":N("M2.5 3h11v10h-11z","M2.5 6.4h11M2.5 9.6h11"),"fme:trim":N("M2.5 3h11v6h-11z","M2.5 12.5h2M6.5 12.5h3M11.5 12.5h2"),"fme:trim-cols":N("M3 2.5h6v11h-6z","M12.5 2.5v2M12.5 6.5v3M12.5 11.5v2"),"fme:cut":le(ae("M4.5 2.5 10 10M11.5 2.5 6 10"),`<circle cx="5" cy="12" r="1.75" fill="none" stroke="currentColor" stroke-width="1.6"/><circle cx="11" cy="12" r="1.75" fill="none" stroke="currentColor" stroke-width="1.6"/>`),"fme:paste":N("M5 3.5h6v2H5z","M4 4.5H3v9h6.5","M7.5 7.5h5.5v6H7.5z"),"fme:add-form":N("M3 2.5h7v11H3z","M5 5h3M5 7.5h3","M12.5 8.5v4M10.5 10.5h4"),"fme:align-left":Ut("M2.5 1.75v12.5","M4.75 3.5h8.5v3h-8.5z","M4.75 9.5h5v3h-5z"),"fme:align-center":Ut("M8 1.75v12.5","M3.25 3.5h9.5v3h-9.5z","M5.5 9.5h5v3h-5z"),"fme:align-right":Ut("M13.5 1.75v12.5","M2.75 3.5h8.5v3h-8.5z","M6.25 9.5h5v3h-5z"),"fme:same-width":Ut("M4.5 8h7M5.75 6.75 4.5 8l1.25 1.25M10.25 6.75 11.5 8l-1.25 1.25","M2.5 2.5h11v3h-11z","M2.5 10.5h11v3h-11z"),"fme:align-top":Ut("M1.75 2.5h12.5","M3.5 4.75h3v8.5h-3z","M9.5 4.75h3v5h-3z"),"fme:align-middle":Ut("M1.75 8h12.5","M3.5 3.25h3v9.5h-3z","M9.5 5.5h3v5h-3z"),"fme:align-bottom":Ut("M1.75 13.5h12.5","M3.5 2.75h3v8.5h-3z","M9.5 6.25h3v5h-3z"),"fme:same-height":Ut("M8 4.5v7M6.75 5.75 8 4.5l1.25 1.25M6.75 10.25 8 11.5l1.25-1.25","M2.5 2.5h3v11h-3z","M10.5 2.5h3v11h-3z"),"fme:same-size":Ut("","M2.5 2.5h5v5h-5z","M8.5 8.5h5v5h-5z"),"fme:password":le(ae("M2.5 4.5h11v7h-11z"),nt("M4.6 7.25h1.5v1.5H4.6zM7.25 7.25h1.5v1.5h-1.5zM9.9 7.25h1.5v1.5H9.9z")),"fme:date":N("M2.5 3.5h11v10h-11z","M2.5 6.5h11","M5.5 2v3M10.5 2v3","M5 9h1.5M7.25 9h1.5M9.5 9H11M5 11h1.5M7.25 11h1.5"),"fme:time":N("M8 2.25a5.75 5.75 0 1 0 0 11.5 5.75 5.75 0 0 0 0-11.5z","M8 4.75V8l2.25 1.5"),"fme:date-time":N("M1.5 3.5h8v7h-8z","M1.5 6h8","M3.75 2v2.5M7.25 2v2.5","M11.5 8.5a3 3 0 1 0 0 6 3 3 0 0 0 0-6z","M11.5 10v1.5h1.25"),"fme:mask":N("M2.5 4.5h11v7h-11z","M4.25 9.5h1.5M7.25 9.5h1.5M10.25 9.5h1.5"),"fme:multi-select":N("M2.25 3.75l1 1 1.75-1.75","M7.5 4h6","M2.25 7.75l1 1 1.75-1.75","M7.5 8h6","M2.75 12h2","M7.5 12h6"),"fme:tags":le(ae("M2 4h6.5L13 8l-4.5 4H2z"),nt("M4.25 7.25h1.5v1.5h-1.5z")),"fme:slider":le(ae("M1.75 8h12.5"),nt("M6 5.25a2.75 2.75 0 1 0 0 5.5 2.75 2.75 0 0 0 0-5.5z")),"fme:toggle-group":le(ae("M1.5 5h13v6h-13z","M5.83 5v6M10.17 5v6"),un("M5.83 5h4.34v6H5.83z")),"fme:color":le(ae("M2.5 4.5h11v7h-11z"),nt("M4.25 6.25h3.5v3.5h-3.5z")),"fme:file-upload":N("M8 10.5V3","M5 6 8 3l3 3","M2.5 9.5v3.5h11V9.5"),"fme:picture":le(ae("M2 3h12v10H2z","M2.5 11.5 6 8l2.5 2.5 2-2 3 3"),nt("M10.75 4.75a1.25 1.25 0 1 0 0 2.5 1.25 1.25 0 0 0 0-2.5z")),"fme:gallery":N("M2 2.5h12v7.5H2z","M2.5 9 5.5 6.25l2 2L10 6l3.5 3","M2 12h3.25v2H2zM6.4 12h3.25v2H6.4zM10.75 12H14v2h-3.25z"),"fme:display":N("M5 3h6","M4.5 3.5v4M11.5 3.5v4","M5 8h6","M4.5 8.5v4M11.5 8.5v4","M5 13h6"),"fme:own":N("M5.5 4.5 2 8l3.5 3.5","M10.5 4.5 14 8l-3.5 3.5","M9 3.5 7 12.5"),"fme:separator":le(ae("M1.5 8h13"),un("M1.5 3h13v2.5h-13zM1.5 10.5h13V13h-13z")),"fme:back":N("M13.5 8h-11","M6 4.5 2.5 8 6 11.5"),"fme:width":N("M1.75 8h12.5","M4 5.75 1.75 8 4 10.25M12 5.75 14.25 8 12 10.25")};const x1={...Sa("fme"),...v1};function Hu(n,e,t,o,i){switch(n){case"static":return i==="caption"?"fme:caption":i==="text"?"fme:text":i==="separator"?"fme:separator":"fme:label";case"input":if(it(o))return"fme:own";switch(o){case"gfy-textarea":return"fme:textarea";case"gfy-password":return"fme:password";case"gfy-date-picker":return"fme:date";case"gfy-select":return"fme:select";case"gfy-combobox":return"fme:combobox";case"gfy-checkbox":return"fme:checkbox";case"gfy-radio-group":return"fme:radio";case"gfy-switch":return"fme:switch";case"gfy-spinner":return"fme:spinner";case"gfy-button":return"fme:button";case"gfy-split-button":return"fme:split-button";case"gfy-dropdown-button":return"fme:dropdown-button";case"gfy-label":return"fme:label";case"gfy-time-picker":return"fme:time";case"gfy-date-time-picker":return"fme:date-time";case"gfy-mask-input":return"fme:mask";case"gfy-multi-select":return"fme:multi-select";case"gfy-tags":return"fme:tags";case"gfy-slider":return"fme:slider";case"gfy-toggle-group":return"fme:toggle-group";case"gfy-color-picker":return"fme:color";case"gfy-file-upload":return"fme:file-upload";case"gfy-picture":return"fme:picture";case"gfy-picture-gallery":return"fme:gallery";case"gfy-digital-display":return"fme:display";default:return"fme:input"}case"group":return e==="property-sheet"?"fme:sheet":t?"fme:repeat":e==="none"?"fme:group":"fme:group-box";case"subform":return t?"fme:repeat":"fme:subform";default:return"fme:input"}}function k1(n){n.setMany({...x1})}const Ei=Ia();class nr{from=we(0,...(ngDevMode?[{debugName:"from"}]:([])));taken=we([],...(ngDevMode?[{debugName:"taken"}]:([])));width=Ls(null,...(ngDevMode?[{debugName:"width"}]:([])));ref=lc();problem=M(()=>{const e=this.width();if(e===null)return"Type the width from which the variant is used.";if(!Number.isInteger(e)||e<1)return"The width is a whole number of px, 1 or more (every form has its variant from 0 px).";if(this.taken().includes(e))return`The form has a variant from ${e} px already.`;return""},...(ngDevMode?[{debugName:"problem"}]:([])));constructor(){Q(()=>this.ref.patchButton("add",{disabled:this.problem()!==""}))}submit(){const e=this.width();if(this.problem()===""&&e!==null)this.ref.close(e)}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:nr,deps:[],target:w.ɵɵFactoryTarget.Component});static ɵcmp=w.ɵɵngDeclareComponent({minVersion:"17.1.0",version:"21.2.21",type:nr,isStandalone:true,selector:"fme-variant-width",inputs:{from:{classPropertyName:"from",publicName:"from",isSignal:true,isRequired:false,transformFunction:null},taken:{classPropertyName:"taken",publicName:"taken",isSignal:true,isRequired:false,transformFunction:null},width:{classPropertyName:"width",publicName:"width",isSignal:true,isRequired:false,transformFunction:null}},outputs:{width:"widthChange"},ngImport:w,template:`
1116
+ <p>A copy of the variant from {{ from() }} px, used from this width up:</p>
1117
+ <gfy-spinner label="From" endText="px" [min]="1" [step]="10" [largeStep]="100" [(value)]="width" (keydown.enter)="submit()" />
1118
+ <p class="why" role="status">{{ problem() }}</p>
1119
+ `,isInline:true,styles:[":host{display:grid;gap:8px;font:13px/1.4 var(--gfy-font-main, system-ui, sans-serif);color:var(--gfy-text-main)}p{margin:0}.why{min-height:1.4em;font-size:12px;color:var(--gfy-warning-text, var(--gfy-warning, #b45309))}\n"],dependencies:[{kind:"component",type:Gs,selector:"gfy-spinner",inputs:["controlId","step","largeStep","min","max","decimals","buttons","wheel","locale","startText","endText","startIcon","endIcon"]}],changeDetection:w.ChangeDetectionStrategy.OnPush})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:nr,decorators:[{type:me,args:[{selector:"fme-variant-width",standalone:true,imports:[Gs],changeDetection:fn.OnPush,template:`
1120
+ <p>A copy of the variant from {{ from() }} px, used from this width up:</p>
1121
+ <gfy-spinner label="From" endText="px" [min]="1" [step]="10" [largeStep]="100" [(value)]="width" (keydown.enter)="submit()" />
1122
+ <p class="why" role="status">{{ problem() }}</p>
1123
+ `,styles:[":host{display:grid;gap:8px;font:13px/1.4 var(--gfy-font-main, system-ui, sans-serif);color:var(--gfy-text-main)}p{margin:0}.why{min-height:1.4em;font-size:12px;color:var(--gfy-warning-text, var(--gfy-warning, #b45309))}\n"]}]}],ctorParameters:()=>[],propDecorators:{from:[{type:w.Input,args:[{isSignal:true,alias:"from",required:false}]}],taken:[{type:w.Input,args:[{isSignal:true,alias:"taken",required:false}]}],width:[{type:w.Input,args:[{isSignal:true,alias:"width",required:false}]},{type:w.Output,args:["widthChange"]}]}});const S1={format:"gfy-form-layout",version:1,forms:[{name:"contact",elements:[{kind:"static",name:"nameLabel",text:"Name",for:"name"},{kind:"input",name:"name",preview:{as:"gfy-input",props:{placeholder:"Jane Doe"}}},{kind:"static",name:"emailLabel",text:"E-mail",for:"email"},{kind:"input",name:"email",preview:{as:"gfy-input",props:{placeholder:"jane@example.com"}}},{kind:"static",name:"topicLabel",text:"Topic",for:"topic"},{kind:"input",name:"topic",preview:{as:"gfy-select",props:{options:[{value:"Question",label:"Question"},{value:"Order",label:"Order"},{value:"Other",label:"Other"}]}}},{kind:"static",name:"messageLabel",text:"Message",for:"message"},{kind:"input",name:"message",preview:{as:"gfy-textarea"}},{kind:"input",name:"copy",preview:{as:"gfy-checkbox",props:{label:"Send me a copy"}}},{kind:"input",name:"send",preview:{as:"gfy-button",props:{label:"Send"}}}],variants:[{minWidth:0,cols:24,rows:20,places:{nameLabel:{col:1,row:1,colSpan:24,rowSpan:1},name:{col:1,row:2,colSpan:24,rowSpan:2},emailLabel:{col:1,row:4,colSpan:24,rowSpan:1},email:{col:1,row:5,colSpan:24,rowSpan:2},topicLabel:{col:1,row:7,colSpan:24,rowSpan:1},topic:{col:1,row:8,colSpan:24,rowSpan:2},messageLabel:{col:1,row:10,colSpan:24,rowSpan:1},message:{col:1,row:11,colSpan:24,rowSpan:6,align:"stretch"},copy:{col:1,row:17,colSpan:24,rowSpan:2},send:{col:1,row:19,colSpan:8,rowSpan:2,justify:"start"}}},{minWidth:640,cols:48,rows:14,places:{nameLabel:{col:1,row:1,colSpan:10,rowSpan:2,justify:"end"},name:{col:11,row:1,colSpan:18,rowSpan:2},emailLabel:{col:29,row:1,colSpan:5,rowSpan:2,justify:"end"},email:{col:34,row:1,colSpan:15,rowSpan:2},topicLabel:{col:1,row:3,colSpan:10,rowSpan:2,justify:"end"},topic:{col:11,row:3,colSpan:18,rowSpan:2},messageLabel:{col:1,row:5,colSpan:10,rowSpan:2,justify:"end"},message:{col:11,row:5,colSpan:38,rowSpan:6,align:"stretch"},copy:{col:11,row:11,colSpan:20,rowSpan:2},send:{col:11,row:13,colSpan:8,rowSpan:2,justify:"start"}}}]}]};const T1={format:"gfy-form-layout",version:1,grid:{division:2},spacing:{y:"75%"},defaults:{message:"top right badge -9 -6"},forms:[{name:"order",layers:[{name:"subject",layers:["person","company"]}],elements:[{kind:"static",name:"nameLabel",text:{$expr:"t('Full name')"},for:"name",layer:"person"},{kind:"input",name:"name",layer:"person",preview:{as:"gfy-input"}},{kind:"static",name:"emailLabel",text:{$expr:"t('E-mail address')"},for:"email",layer:"person"},{kind:"input",name:"email",layer:"person",preview:{as:"gfy-input"}},{kind:"static",name:"companyLabel",text:{$expr:"t('Company name')"},for:"company",layer:"company"},{kind:"input",name:"company",layer:"company",preview:{as:"gfy-input"}},{kind:"static",name:"vatLabel",text:{$expr:"t('VAT number')"},for:"vatId",layer:"company"},{kind:"input",name:"vatId",layer:"company",preview:{as:"gfy-input"}},{kind:"subform",name:"billing",form:"address"},{kind:"group",name:"delivery",title:{$expr:"t('Delivery')"},elements:[{kind:"static",name:"deliveryByLabel",text:{$expr:"t('Delivery by')"},for:"deliveryBy"},{kind:"input",name:"deliveryBy",preview:{as:"gfy-radio-group"}},{kind:"input",name:"gift",preview:{as:"gfy-checkbox"}}]},{kind:"static",name:"noteLabel",text:{$expr:"t('Note for the courier')"},for:"note"},{kind:"input",name:"note",preview:{as:"gfy-textarea"}}],variants:[{minWidth:0,cols:24,rows:24,places:{nameLabel:{col:1,row:1,colSpan:24,rowSpan:1},name:{col:1,row:2,colSpan:24,rowSpan:2},emailLabel:{col:1,row:4,colSpan:24,rowSpan:1},email:{col:1,row:5,colSpan:24,rowSpan:2},companyLabel:{col:1,row:1,colSpan:24,rowSpan:1},company:{col:1,row:2,colSpan:24,rowSpan:2},vatLabel:{col:1,row:4,colSpan:24,rowSpan:1},vatId:{col:1,row:5,colSpan:24,rowSpan:2},billing:{col:1,row:7,colSpan:24,rowSpan:1,flow:true},delivery:{col:1,row:8,colSpan:24,rowSpan:10},deliveryByLabel:{col:2,row:3,colSpan:22,rowSpan:1},deliveryBy:{col:2,row:4,colSpan:22,rowSpan:4,align:"start"},gift:{col:2,row:8,colSpan:22,rowSpan:2},noteLabel:{col:1,row:18,colSpan:24,rowSpan:1},note:{col:1,row:19,colSpan:24,rowSpan:6,align:"stretch"}}},{minWidth:560,cols:48,rows:15,places:{nameLabel:{col:1,row:1,colSpan:12,rowSpan:2,justify:"end"},name:{col:13,row:1,colSpan:36,rowSpan:2},emailLabel:{col:1,row:3,colSpan:12,rowSpan:2,justify:"end"},email:{col:13,row:3,colSpan:36,rowSpan:2},companyLabel:{col:1,row:1,colSpan:12,rowSpan:2,justify:"end"},company:{col:13,row:1,colSpan:36,rowSpan:2},vatLabel:{col:1,row:3,colSpan:12,rowSpan:2,justify:"end"},vatId:{col:13,row:3,colSpan:36,rowSpan:2},billing:{col:1,row:5,colSpan:48,rowSpan:1,flow:true},delivery:{col:1,row:6,colSpan:24,rowSpan:10},deliveryByLabel:{col:2,row:3,colSpan:22,rowSpan:1},deliveryBy:{col:2,row:4,colSpan:22,rowSpan:4,align:"start"},gift:{col:2,row:8,colSpan:22,rowSpan:2},noteLabel:{col:25,row:6,colSpan:24,rowSpan:1},note:{col:25,row:7,colSpan:24,rowSpan:9,align:"stretch"}}}]},{name:"address",elements:[{kind:"static",name:"streetLabel",text:{$expr:"t('Street and number')"},for:"street"},{kind:"input",name:"street"},{kind:"static",name:"cityLabel",text:{$expr:"t('City')"},for:"city"},{kind:"input",name:"city"},{kind:"static",name:"zipLabel",text:{$expr:"t('Postcode')"},for:"zip"},{kind:"input",name:"zip"}],variants:[{minWidth:0,cols:24,rows:9,places:{streetLabel:{col:1,row:1,colSpan:24,rowSpan:1},street:{col:1,row:2,colSpan:24,rowSpan:2},cityLabel:{col:1,row:4,colSpan:24,rowSpan:1},city:{col:1,row:5,colSpan:24,rowSpan:2},zipLabel:{col:1,row:7,colSpan:24,rowSpan:1},zip:{col:1,row:8,colSpan:24,rowSpan:2}}},{minWidth:560,cols:48,rows:4,places:{streetLabel:{col:1,row:1,colSpan:12,rowSpan:2,justify:"end"},street:{col:13,row:1,colSpan:36,rowSpan:2},cityLabel:{col:1,row:3,colSpan:12,rowSpan:2,justify:"end"},city:{col:13,row:3,colSpan:20,rowSpan:2},zipLabel:{col:33,row:3,colSpan:6,rowSpan:2,justify:"end"},zip:{col:39,row:3,colSpan:10,rowSpan:2}}}]}]};const M1={format:"gfy-form-layout",version:1,spacing:{y:"100%"},forms:[{name:"customer",elements:[{kind:"group",name:"card",title:"Customer card",look:"property-sheet",elements:[{kind:"group",name:"person",title:"Person",elements:[{kind:"static",name:"firstNameLabel",text:"First name",for:"firstName"},{kind:"input",name:"firstName"},{kind:"static",name:"lastNameLabel",text:"Last name",for:"lastName"},{kind:"input",name:"lastName"},{kind:"static",name:"emailLabel",text:"E-mail",for:"email"},{kind:"input",name:"email"}]},{kind:"group",name:"address",title:"Address",elements:[{kind:"static",name:"streetLabel",text:"Street and number",for:"street"},{kind:"input",name:"street"},{kind:"static",name:"cityLabel",text:"City",for:"city"},{kind:"input",name:"city"},{kind:"static",name:"postcodeLabel",text:"Postcode",for:"postcode"},{kind:"input",name:"postcode"}]},{kind:"group",name:"notes",title:"Notes",elements:[{kind:"static",name:"noteLabel",text:"Note",for:"note"},{kind:"input",name:"note"},{kind:"input",name:"newsletter"}]}]}],variants:[{minWidth:0,cols:24,rows:12,places:{card:{col:1,row:1,colSpan:24,rowSpan:12},person:{col:2,row:3,colSpan:22,rowSpan:9},address:{col:2,row:3,colSpan:22,rowSpan:9},notes:{col:2,row:3,colSpan:22,rowSpan:9},firstNameLabel:{col:1,row:1,colSpan:22,rowSpan:1},firstName:{col:1,row:2,colSpan:22,rowSpan:2},lastNameLabel:{col:1,row:4,colSpan:22,rowSpan:1},lastName:{col:1,row:5,colSpan:22,rowSpan:2},emailLabel:{col:1,row:7,colSpan:22,rowSpan:1},email:{col:1,row:8,colSpan:22,rowSpan:2},streetLabel:{col:1,row:1,colSpan:22,rowSpan:1},street:{col:1,row:2,colSpan:22,rowSpan:2},cityLabel:{col:1,row:4,colSpan:22,rowSpan:1},city:{col:1,row:5,colSpan:22,rowSpan:2},postcodeLabel:{col:1,row:7,colSpan:22,rowSpan:1},postcode:{col:1,row:8,colSpan:10,rowSpan:2},noteLabel:{col:1,row:1,colSpan:22,rowSpan:1},note:{col:1,row:2,colSpan:22,rowSpan:5,align:"stretch"},newsletter:{col:1,row:7,colSpan:22,rowSpan:2}}},{minWidth:600,cols:48,rows:11,places:{card:{col:1,row:1,colSpan:48,rowSpan:11,tabs:"start"},person:{col:5,row:2,colSpan:43,rowSpan:9},address:{col:5,row:2,colSpan:43,rowSpan:9},notes:{col:5,row:2,colSpan:43,rowSpan:9},firstNameLabel:{col:1,row:1,colSpan:10,rowSpan:2,justify:"end"},firstName:{col:11,row:1,colSpan:32,rowSpan:2},lastNameLabel:{col:1,row:3,colSpan:10,rowSpan:2,justify:"end"},lastName:{col:11,row:3,colSpan:32,rowSpan:2},emailLabel:{col:1,row:5,colSpan:10,rowSpan:2,justify:"end"},email:{col:11,row:5,colSpan:32,rowSpan:2},streetLabel:{col:1,row:1,colSpan:10,rowSpan:2,justify:"end"},street:{col:11,row:1,colSpan:32,rowSpan:2},cityLabel:{col:1,row:3,colSpan:10,rowSpan:2,justify:"end"},city:{col:11,row:3,colSpan:18,rowSpan:2},postcodeLabel:{col:29,row:3,colSpan:6,rowSpan:2,justify:"end"},postcode:{col:35,row:3,colSpan:8,rowSpan:2},noteLabel:{col:1,row:1,colSpan:10,rowSpan:2,justify:"end"},note:{col:11,row:1,colSpan:32,rowSpan:6,align:"stretch"},newsletter:{col:11,row:7,colSpan:32,rowSpan:2}}}]}]};const $1={format:"gfy-form-layout",version:1,spacing:{y:"75%"},defaults:{message:"top right badge -9 -6"},forms:[{name:"order",elements:[{kind:"static",name:"customerLabel",text:"Customer",for:"customer"},{kind:"input",name:"customer"},{kind:"static",name:"phonesLabel",text:"Phones"},{kind:"group",name:"phones",title:"Phones",look:"none",repeat:true,elements:[{kind:"input",name:"phone"},{kind:"input",name:"removePhone"}]},{kind:"input",name:"addPhone"},{kind:"group",name:"linesBox",title:"Order lines",elements:[{kind:"static",name:"productCaption",text:"Product",appearance:"caption"},{kind:"static",name:"quantityCaption",text:"Quantity",appearance:"caption"},{kind:"subform",name:"lines",form:"line",repeat:true},{kind:"input",name:"addLine"}]},{kind:"static",name:"noteLabel",text:"Note",for:"note"},{kind:"input",name:"note"}],variants:[{minWidth:0,cols:24,rows:21,places:{customerLabel:{col:1,row:1,colSpan:24,rowSpan:1},customer:{col:1,row:2,colSpan:24,rowSpan:2},phonesLabel:{col:1,row:4,colSpan:24,rowSpan:1},phones:{col:1,row:5,colSpan:24,rowSpan:2},phone:{col:1,row:1,colSpan:20,rowSpan:2},removePhone:{col:21,row:1,colSpan:4,rowSpan:2,justify:"start"},addPhone:{col:1,row:7,colSpan:24,rowSpan:2,justify:"start"},linesBox:{col:1,row:9,colSpan:24,rowSpan:8},productCaption:{col:2,row:3,colSpan:11,rowSpan:1},quantityCaption:{col:13,row:3,colSpan:7,rowSpan:1},lines:{col:2,row:4,colSpan:22,rowSpan:2},addLine:{col:2,row:6,colSpan:22,rowSpan:2,justify:"start"},noteLabel:{col:1,row:17,colSpan:24,rowSpan:1},note:{col:1,row:18,colSpan:24,rowSpan:4,align:"stretch"}}},{minWidth:600,cols:48,rows:18,places:{customerLabel:{col:1,row:1,colSpan:10,rowSpan:2,justify:"end"},customer:{col:11,row:1,colSpan:38,rowSpan:2},phonesLabel:{col:1,row:3,colSpan:10,rowSpan:2,justify:"end"},phones:{col:11,row:3,colSpan:38,rowSpan:2},phone:{col:1,row:1,colSpan:32,rowSpan:2},removePhone:{col:33,row:1,colSpan:6,rowSpan:2,justify:"start"},addPhone:{col:11,row:5,colSpan:38,rowSpan:2,justify:"start"},linesBox:{col:1,row:7,colSpan:48,rowSpan:8},productCaption:{col:2,row:3,colSpan:30,rowSpan:1},quantityCaption:{col:32,row:3,colSpan:9,rowSpan:1},lines:{col:2,row:4,colSpan:46,rowSpan:2},addLine:{col:2,row:6,colSpan:46,rowSpan:2,justify:"start"},noteLabel:{col:1,row:15,colSpan:10,rowSpan:2,justify:"end"},note:{col:11,row:15,colSpan:38,rowSpan:4,align:"stretch"}}}]},{name:"line",elements:[{kind:"input",name:"product"},{kind:"input",name:"quantity"},{kind:"input",name:"removeLine"}],variants:[{minWidth:0,cols:22,rows:2,places:{product:{col:1,row:1,colSpan:11,rowSpan:2},quantity:{col:12,row:1,colSpan:7,rowSpan:2},removeLine:{col:19,row:1,colSpan:4,rowSpan:2,justify:"start"}}},{minWidth:600,cols:46,rows:2,places:{product:{col:1,row:1,colSpan:30,rowSpan:2},quantity:{col:31,row:1,colSpan:9,rowSpan:2},removeLine:{col:40,row:1,colSpan:7,rowSpan:2,justify:"start"}}}]}]};const qu=[{id:"contact",label:"Contact form",file:S1},{id:"person-or-company",label:"Person or company, with a subform (the file of the tutorial 156)",file:T1},{id:"card-with-pages",label:"A card with pages (the file of the tutorial 157)",file:M1},{id:"order-with-lists",label:"An order with lists (the file of the tutorial 158)",file:$1}];const Ql=n=>qu.find(e=>e.id===n);const A1=["file","template","component"];const ec="application/x-gridify-form-tool";const C1={layers:{},pages:{},newLayer:{},designWidth:null,showGrid:true,previewWidth:null,previewFollows:false};class or extends jn{static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:or,deps:null,target:w.ɵɵFactoryTarget.Injectable});static ɵprov=w.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:or,providedIn:"root"})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:or,decorators:[{type:Pn,args:[{providedIn:"root"}]}]});const tc="gfy-form-editor:text";const Ns="gfy-form-editor:downloaded";const nc="gfy-form-editor:autosave";const O1="gfy-form-editor:project";const N1={left:"The left edges are lined up with",center:"The middles across are lined up with",right:"The right edges are lined up with",top:"The top edges are lined up with",middle:"The middles down are lined up with",bottom:"The bottom edges are lined up with",width:"The elements are as wide as",height:"The elements are as high as",size:"The elements are as large as"};class at{toast=L(Ks);box=L(fr);dialogs=L(Ws);icons=L(Po);project=Ra({noun:"form layout",extension:".json",icons:"fme",storageKey:O1,say:e=>this.say(e)});state=E(pn(Ms()),...(ngDevMode?[{debugName:"state"}]:([])));file=M(()=>Bl(this.state()),...(ngDevMode?[{debugName:"file"}]:([])));selection=M(()=>this.state().selection,...(ngDevMode?[{debugName:"selection"}]:([])));selected=M(()=>this.state().selection.names,...(ngDevMode?[{debugName:"selected"}]:([])));notes=M(()=>this.state().notes,...(ngDevMode?[{debugName:"notes"}]:([])));canUndo=M(()=>lo(this.state().history),...(ngDevMode?[{debugName:"canUndo"}]:([])));canRedo=M(()=>Nr(this.state().history),...(ngDevMode?[{debugName:"canRedo"}]:([])));modified=M(()=>Ox(this.state()),...(ngDevMode?[{debugName:"modified"}]:([])));fileText=M(()=>Wx(this.file()),...(ngDevMode?[{debugName:"fileText"}]:([])));form=M(()=>z(this.file(),this.selection().form),...(ngDevMode?[{debugName:"form"}]:([])));variant=M(()=>G(this.form(),this.selection().minWidth),...(ngDevMode?[{debugName:"variant"}]:([])));variants=M(()=>{const e=this.form();return e?Nt(e):[]},...(ngDevMode?[{debugName:"variants"}]:([])));division=M(()=>$n(this.file()),...(ngDevMode?[{debugName:"division"}]:([])));ctx=M(()=>({form:this.selection().form,minWidth:this.selection().minWidth}),...(ngDevMode?[{debugName:"ctx"}]:([])));view=E(C1,...(ngDevMode?[{debugName:"view"}]:([])));outputKind=E("file",...(ngDevMode?[{debugName:"outputKind"}]:([])));status=E("",...(ngDevMode?[{debugName:"status"}]:([])));focusEditor=E(0,...(ngDevMode?[{debugName:"focusEditor"}]:([])));autoSave=E(false,...(ngDevMode?[{debugName:"autoSave"}]:([])));dragTool=E(null,...(ngDevMode?[{debugName:"dragTool"}]:([])));placeTarget=null;trackScope=M(()=>{const{form:e,minWidth:t,scope:o}=this.selection();return o==="variant"?`${e}|${t}`:""},...(ngDevMode?[{debugName:"trackScope"}]:([])));chosenTrack=E(null,...(ngDevMode?[{debugName:"chosenTrack"}]:([])));track=M(()=>{const e=this.chosenTrack();return e&&e.scope!==""&&e.scope===this.trackScope()?e.track:null},...(ngDevMode?[{debugName:"track"}]:([])));drawnColumns=E([],...(ngDevMode?[{debugName:"drawnColumns"}]:([])));editorWidth=E(null,...(ngDevMode?[{debugName:"editorWidth"}]:([])));tabOrderMode=E(false,...(ngDevMode?[{debugName:"tabOrderMode"}]:([])));tabCounters=/* @__PURE__ */new Map;tabOrdered=E(/* @__PURE__ */new Set,...(ngDevMode?[{debugName:"tabOrdered"}]:([])));refusals=E(0,...(ngDevMode?[{debugName:"refusals"}]:([])));editingText=E(null,...(ngDevMode?[{debugName:"editingText"}]:([])));editingCaption=E(false,...(ngDevMode?[{debugName:"editingCaption"}]:([])));clipboard=E(null,...(ngDevMode?[{debugName:"clipboard"}]:([])));placed=M(()=>{const e=this.form();return e?Ne(e,this.variant()):[]},...(ngDevMode?[{debugName:"placed"}]:([])));placedByName=M(()=>new Map(this.placed().map(e=>[e.name,e])),...(ngDevMode?[{debugName:"placedByName"}]:([])));active=M(()=>{const e=this.selection().form;const t=this.view();return{...(t.layers[e]??{}),...(t.pages[e]??{})}},...(ngDevMode?[{debugName:"active"}]:([])));visible=M(()=>{const e=this.active();return new Set(this.placed().filter(t=>Lv(t,e)).map(t=>t.name))},...(ngDevMode?[{debugName:"visible"}]:([])));unplaced=M(()=>this.placed().filter(e=>e.cells===null&&e.place===null&&e.bounds!==null),...(ngDevMode?[{debugName:"unplaced"}]:([])));newLayer=M(()=>this.view().newLayer[this.selection().form]??"",...(ngDevMode?[{debugName:"newLayer"}]:([])));designWidth=M(()=>this.view().designWidth,...(ngDevMode?[{debugName:"designWidth"}]:([])));minFormWidth=M(()=>{const e=this.file().minFormWidth;return typeof e==="number"&&Number.isInteger(e)&&e>0?e:0},...(ngDevMode?[{debugName:"minFormWidth"}]:([])));variantRange=M(()=>{const e=this.selection().minWidth;const t=this.variants().find(o=>o.minWidth>e);return{from:e,to:t?t.minWidth-1:null}},...(ngDevMode?[{debugName:"variantRange"}]:([])));loaded=M(()=>{const e=this.file();return pf(e,{functions:a1(e),onProblem:()=>void 0})},...(ngDevMode?[{debugName:"loaded"}]:([])));layout=M(()=>this.loaded().layout,...(ngDevMode?[{debugName:"layout"}]:([])));problems=M(()=>{const e=[];this.notes().forEach((o,i)=>e.push({id:`note:${i}`,severity:"info",code:"json",message:Ei.text(o.template,o.params),file:"file",path:"the text of the file",line:o.line,column:o.column,target:null}));e.push(...i1(this.loaded().problems),...r1(this.file()));const t={error:0,warning:1,info:2};return e.map((o,i)=>({problem:o,index:i})).sort((o,i)=>t[o.problem.severity]-t[i.problem.severity]||o.index-i.index).map(o=>o.problem)},...(ngDevMode?[{debugName:"problems"}]:([])));problemsByElement=M(()=>{const e=/* @__PURE__ */new Map;const t=this.selection().form;const o=this.selection().minWidth;for(const i of this.problems()){const r=i.target;if(!r?.element||r.form!==t||i.severity==="info"||i.code==="unplaced")continue;if(r.minWidth!==void 0&&r.minWidth!==o)continue;if(e.get(r.element)!=="error")e.set(r.element,i.severity)}return e},...(ngDevMode?[{debugName:"problemsByElement"}]:([])));inspector=M(()=>Gx(this.file(),this.selection(),{track:this.track()}),...(ngDevMode?[{debugName:"inspector"}]:([])));output=M(()=>{const e=this.file();switch(this.outputKind()){case"file":return this.fileText();case"template":return b1(e,this.selection().form);case"component":return w1(e,this.selection().form,this.fileName())}},...(ngDevMode?[{debugName:"output"}]:([])));capabilities=M(()=>{const e=this.selected();const t=this.form();const o={remove:false,duplicate:false,copy:false,paste:this.clipboard()!==null,wrap:false,unwrap:false,unplace:false,addLabel:false,align:false};if(!t||e.length===0)return o;const i=e.map(c=>ge(t,c)).filter(c=>c!==void 0);const r=new Set(i.map(c=>c.parent));const s=i.length===1?i[0]:null;const a=s?.parent?V(t,s.parent):void 0;const l=this.variant();const d=this.placedByName();return{remove:i.length>0,duplicate:r.size===1&&i.every(c=>d.get(c.name)?.cells),copy:i.length>0,paste:this.clipboard()!==null,wrap:r.size===1&&!W(i[0].parent?V(t,i[0].parent):void 0),unwrap:s!==null&&s.element.kind==="group"&&!W(s.element)&&!W(a),unplace:l!==void 0&&i.some(c=>d.get(c.name)?.place),addLabel:s!==null&&s.element.kind==="input"&&!ve(t).some(c=>c.element.kind==="static"&&c.element.for===s.name),align:i.length>1&&Boolean(d.get(e[0])?.cells)}},...(ngDevMode?[{debugName:"capabilities"}]:([])));subformTargets=M(()=>bs(this.file(),this.selection().form),...(ngDevMode?[{debugName:"subformTargets"}]:([])));constructor(){k1(this.icons);this.autoSave.set(this.readAutoSave());const e=L(or);const t=e.take();if(t!==null){this.state.set(t.state);this.outputKind.set(t.outputKind);this.view.set(t.view);this.project.adopt(t.project)}else if(this.autoSave())this.restore();else{this.startWithSample();this.say("The contact form, a sample to start from. Help > Getting started says how the editor works.")}if(!this.autoSave())this.forgetText();Q(()=>{const a=this.file();ee(()=>{if(this.removal&&this.removal.file!==a){this.removal.ref.close();this.removal=null}})});let o;Q(()=>{const a=this.autoSave();const l=this.fileText();const d=this.modified();this.project.link();ee(()=>{clearTimeout(o);if(a)o=setTimeout(()=>this.saveText(l,d,true),400);else this.forgetText()})});Q(()=>{const a=this.trackScope();ee(()=>{if(this.chosenTrack()&&this.chosenTrack()?.scope!==a)this.chosenTrack.set(null)})});const i=M(()=>this.selection().form,...(ngDevMode?[{debugName:"edited"}]:([])));Q(()=>{i();ee(()=>this.newTabRound())});Q(()=>{const a=this.openedFrom();if(!a)return;const l=z(this.file(),a.form);const d=l?V(l,a.name):void 0;const c=d?.kind==="subform"&&d.form===this.selection().form;ee(()=>{if(!c)this.openedFrom.set(null)})});const r=L(ac).defaultView;const s=a=>{if(this.modified()&&(!this.autoSave()||this.notKept))a.preventDefault()};r?.addEventListener("beforeunload",s);L(lt).onDestroy(()=>{r?.removeEventListener("beforeunload",s);clearTimeout(o);if(this.autoSave())this.saveText(this.fileText(),this.modified());e.leave({state:this.state(),outputKind:this.outputKind(),view:this.view(),project:this.project.state},this.modified()&&(!this.autoSave()||this.notKept))})}setAutoSave(e){if(e===this.autoSave())return;this.autoSave.set(e);try{if(e)localStorage.setItem(nc,"1");else localStorage.removeItem(nc)}catch{}this.notKept=false;if(!e)this.forgetText();this.say(e?"Auto save is on: the file is kept in this browser.":this.modified()?"Auto save is off: nothing of the file is kept. Save or download the file to keep the changes.":"Auto save is off: nothing of the file is kept.")}readAutoSave(){try{return localStorage.getItem(nc)==="1"}catch{return false}}restore(){try{const e=localStorage.getItem(tc);const t=e?Nu(e):null;if(!t?.ok)return this.startWithSample();const o=pn(t.file);this.state.set(localStorage.getItem(Ns)!=="1"?Ix(o):o);this.project.recall()}catch{this.state.set(pn(Ms()));this.project.replaced(uo);this.openedFrom.set(null)}}startWithSample(){const e=Ql("contact");this.state.set(pn(e?.file??Ms()));this.project.replaced(e?{kind:"sample",name:e.label}:uo);this.fresh=e?.id??null}fresh=null;startWith(e){const t=Ql(e);if(this.fresh===null||this.fresh===e||!t||this.modified()||this.canUndo())return;this.fresh=t.id;this.state.set(pn(t.file));this.project.replaced({kind:"sample",name:t.label});this.say(`${t.label}: a sample to start from. Help > Getting started says how the editor works.`)}notKept=false;saveText(e,t,o=false){try{localStorage.setItem(tc,e);if(t)localStorage.removeItem(Ns);else localStorage.setItem(Ns,"1");this.project.remember();this.notKept=false}catch{this.project.forget();if(o&&!this.notKept)this.warn("Auto save could not keep the file in this browser (its storage is full or turned off). Save or download the file to keep the changes.","form-editor:autosave");this.notKept=true}}forgetText(){this.project.forget();try{localStorage.removeItem(tc);localStorage.removeItem(Ns)}catch{}}say(e){this.status.set(e)}warn(e,t="form-editor:refused"){this.toast.warning(e,{id:t,closeAfter:5e3})}select(e,t="variant"){this.state.update(o=>qt(o,{names:e,scope:t}));if(e.length)this.chosenTrack.set(null);for(const o of e)this.reveal(o)}toggle(e){const t=this.selected();this.select(t.includes(e)?t.filter(o=>o!==e):[...t,e])}addToSelection(e){const t=this.selected();const o=e.filter(i=>!t.includes(i));if(o.length===0)return this.say(e.length?"What the rectangle touches is selected already.":"The rectangle touches no element.");this.select([...t,...o]);this.say(o.length===1?`"${o[0]}" is added to the selection.`:`${o.length} elements are added to the selection.`)}selectForm(e,t="form"){this.state.update(o=>qt(o,{form:e,names:[],scope:t}))}editLayers(){this.selectForm(this.selection().form,"form");this.say("The layers are the row layers of the form in the Inspector: just the layers for one group (person, company), or a group, a colon and its layers, the groups separated by semicolons (subject: person, company; mode: simple, advanced).")}openedFrom=E(null,...(ngDevMode?[{debugName:"openedFrom"}]:([])));openSubform(e){const t=this.form();const o=t?V(t,e):void 0;if(!t||o?.kind!=="subform"||!z(this.file(),o.form))return;this.openedFrom.set({form:t.name,name:e});this.selectForm(o.form,"variant");this.say(`The form "${o.form}" that the subform "${e}" places: its elements are edited here. Escape (or "${t.name}" in the toolbar) leads back.`)}back(){const e=this.openedFrom();this.openedFrom.set(null);if(!e||!z(this.file(),e.form))return;this.selectForm(e.form,"variant");const t=this.form();if(t&&ge(t,e.name))this.select([e.name]);this.say(`Back in "${e.form}".`)}selectVariant(e){this.state.update(t=>qt(t,{minWidth:e,names:[],scope:"variant"}))}selectFile(){this.state.update(e=>qt(e,{names:[],scope:"file"}))}selectTrack(e){this.state.update(t=>qt(t,{names:[],scope:"variant"}));this.chosenTrack.set(e?{scope:this.trackScope(),track:e}:null)}selectAll(e){const t=this.form();if(!t)return;const o=this.selected()[0];const i=e!==void 0?e:o?ge(t,o)?.parent??null:null;const r=this.visible();this.select(Kt(t,i).filter(s=>r.has(s.name)).map(s=>s.name))}reveal(e){const t=this.placedByName().get(e);const o=this.form();if(!t||!o)return;for(const i of t.layers){const r=this.active();const s=Object.prototype.hasOwnProperty.call(r,i.group)?r[i.group]:null;if(s===null?i.first:s===i.layer)continue;if(W(V(o,i.group)))this.showPage(i.group,i.layer);else this.setLayer(i.group,i.layer)}}setLayer(e,t){const o=this.selection().form;const i=this.form();const r=(i?.layers??[]).find(l=>l.name===e)?.layers??[];this.view.update(l=>{const d=l.newLayer[o];const c=d!==void 0&&d!==""&&r.includes(d);return{...l,layers:{...l.layers,[o]:{...(l.layers[o]??{}),[e]:t}},newLayer:c?{...l.newLayer,[o]:t}:l.newLayer}});const s=this.visible();const a=this.selected().filter(l=>s.has(l));if(a.length!==this.selected().length)this.state.update(l=>qt(l,{names:a}))}setNewLayer(e){const t=this.selection().form;this.view.update(o=>({...o,newLayer:{...o.newLayer,[t]:e}}))}showPage(e,t,o=false){const i=this.selection().form;const r=this.visible();this.view.update(l=>({...l,pages:{...l.pages,[i]:{...(l.pages[i]??{}),[e]:t}}}));const s=this.visible();const a=this.selected().filter(l=>s.has(l)||!r.has(l));if(a.length!==this.selected().length)this.state.update(l=>qt(l,{names:a}));if(o)this.select([t])}setDesignWidth(e){this.view.update(t=>({...t,designWidth:e===null?null:Math.max(1,Math.min(4e3,Math.round(e)))}))}setShowGrid(e){this.view.update(t=>({...t,showGrid:e}))}setPreviewWidth(e){this.view.update(t=>({...t,previewWidth:e===null?null:Math.max(1,Math.min(4e3,Math.round(e)))}))}setPreviewFollows(e){const t=this.editorWidth();this.view.update(o=>({...o,previewFollows:e,...(!e&&o.previewFollows&&t!==null?{previewWidth:t}:{})}))}openProblem(e){const t=e.target;if(!t?.form)return this.selectFile();if(!z(this.file(),t.form))return;this.state.update(o=>qt(o,{form:t.form,...(t.minWidth!==void 0?{minWidth:t.minWidth}:{}),names:[],scope:t.element||t.minWidth!==void 0?"variant":"form"}));if(t.element)this.select([t.element])}stepKey(){const e=this.selection();return`${e.form}|${e.minWidth}|${e.names.join(",")}`}run(e,t,o){if(e.refused){this.warn(e.refused);return false}const i=this.file();const r=e.file!==i&&JSON.stringify(e.file)===JSON.stringify(i)?i:e.file;this.state.update(s=>Dx(s,r,e.selected,{mergeKey:t,now:Date.now()}));if(e.selected)for(const s of e.selected)this.reveal(s);if(e.note){this.say(e.note);this.toast.info(e.note,{id:"form-editor:note",closeAfter:6e3})}else if(o&&this.file()!==i)this.say(o);return this.file()!==i}targetList(){const e=this.form();const t=this.selected()[0];if(!e||!t)return null;const o=ge(e,t);if(!o)return null;const i=this.placedByName();if(o.element.kind==="group"&&i.get(o.name)?.cells){if(!W(o.element))return o.name;const r=this.shownPageOf(o.name);if(r)return r}return o.parent}shownPageOf(e){const t=this.form();const o=t?V(t,e):void 0;if(!o||o.kind!=="group")return null;const i=o.elements.filter(s=>s.kind==="group"&&this.placedByName().get(s.name)?.cells);const r=this.view().pages[this.selection().form]?.[e];return(i.find(s=>s.name===r)??i[0])?.name??null}innerCells(e){const t=this.variant();if(!t)return null;if(e===null)return Pe(t);const o=this.placedByName().get(e);if(!o?.cells)return null;const i=o.parent?this.placedByName().get(o.parent):void 0;const r=i?.element.kind==="group"&&W(i.element);return On(o.cells,Gt(o.element,o.place,this.division(),this.tabColumns(o),r))}tabColumns(e){const t=this.variant();if(!t||!e?.cells)return 2;const o=this.designWidth()??Math.max(this.selection().minWidth,480);const i=o/Math.max(1,t.cols);return Math.max(1,Math.min(e.cells.colSpan-1,Math.ceil(36/Math.max(1,i))))}addTool(e,t=null,o){if(t){const s=Fv(e,this.division());if(t.cells.rowSpan>=s)return this.putTool(e,t.parent,t.cells,0,o);const a={...t.cells,rowSpan:s};const l=this.insideOf(t.parent);const d=t.parent===null||l!==null&&te(a)<=l.row+l.rowSpan-1;if(d&&!this.takenIn(t.parent).some(p=>ut(p,a)))return this.putTool(e,t.parent,a,0,o);const c=this.toolRoom(e,t.parent,{col:t.cells.col,row:t.cells.row},o);if(c)this.putTool(e,t.parent,c.cells,c.grow,o);return}const i=this.targetList();const r=this.toolRoom(e,i,null,o);if(!r)return this.warn(i===null?"There is no variant to add to.":`The group "${i}" has no place in this variant.`);this.putTool(e,i,r.cells,r.grow,o)}addToolAtCell(e,t,o,i){const r=this.toolRoom(e,t,o,i);if(r)this.putTool(e,t,r.cells,r.grow,i)}takenIn(e){const t=this.newLayer();const o=t?[{group:this.groupOfLayer(t),layer:t,first:false}]:[];return this.placed().filter(i=>i.parent===e&&i.cells&&No(i.layers,o)).map(i=>i.cells)}insetsOf(e){const t=this.placedByName().get(e);if(!t)return Rl;const o=t.parent?this.placedByName().get(t.parent):void 0;return Gt(t.element,t.place,this.division(),this.tabColumns(t),o?.element.kind==="group"&&W(o.element))}insideOf(e){const t=this.variant();if(!t)return null;if(e===null)return Pe(t);const o=this.placedByName().get(e);if(!o?.cells)return null;const i=this.insetsOf(e);const r=On(o.cells,i);return{col:r.col,row:o.cells.row+i.top,colSpan:r.colSpan,rowSpan:o.cells.rowSpan-i.top-i.bottom}}toolRoom(e,t,o,i){const r=this.form();const s=this.variant();const a=this.insideOf(t);if(!r||!s||!a)return null;const l=jv(e,{division:this.division(),cols:a.colSpan,file:this.file(),form:r.name,subform:i});const d=Math.min(l.colSpan,a.colSpan);const c=this.takenIn(t);const p=y=>!c.some(b=>ut(b,y));const h=t===null;const u=a.rowSpan>=l.rowSpan?a:null;let f={col:a.col,row:a.row,colSpan:d,rowSpan:l.rowSpan};if(!o){const y={...f,row:Math.max(a.row,hs(a,c))};const b=a.row+a.rowSpan-1;if(h||te(y)<=b)return{cells:y,grow:0};return{cells:y,grow:te(y)-Math.max(b,y.row-1)}}f={...f,col:Math.max(a.col,Math.min(o.col,a.col+a.colSpan-d)),row:h?Math.max(1,o.row):Math.max(a.row,Math.min(o.row,a.row+a.rowSpan-l.rowSpan))};if((h||u)&&p(f))return{cells:f,grow:0};const m=h?Math.max(f.row,...c.map(y=>te(y)+1)):a.row+a.rowSpan-l.rowSpan;for(let y=f.row+1;y<=m;y++)if(p({...f,row:y}))return{cells:{...f,row:y},grow:0};const g=u?Io(u,{colSpan:d,rowSpan:l.rowSpan},c,f.row)??Io(u,{colSpan:d,rowSpan:l.rowSpan},c):null;if(g)return{cells:g,grow:0};if(h)return{cells:{...f,row:hs(a,c)},grow:0};return{cells:{...f,row:Math.max(a.row,a.row+a.rowSpan)},grow:l.rowSpan}}putTool(e,t,o,i,r){const s=this.form();const a=this.variant();if(!s||!a)return;let l=this.file();let d=o;if(i>0&&t!==null){const g=hx(l,this.ctx(),t,i,this.division(),this.tabColumns(this.placedByName().get(t)??null));if(g.refused)return this.warn(g.refused);l=g.file;d=g.row!==void 0&&o.row>=g.row?{...o,row:g.row}:o}const c=z(l,s.name);const p=G(c,a.minWidth);const h=t===null?Pe(p):Ne(c,p).find(g=>g.name===t)?.cells;if(!h)return this.warn(`The group "${t}" has no place in this variant.`);const u=Pv(e,Le(d,h),{division:this.division(),cols:d.colSpan,file:l,form:s.name,subform:r});if("refused"in u)return this.warn(u.refused);const f=this.newLayer();const m=f&&(s.layers??[]).some(g=>g.layers.includes(f))?{...u,elements:u.elements.map(g=>({...g,layer:f}))}:u;if(!this.run($i(l,this.ctx(),t,m)))return;this.say(this.addedText(i>0?t:null))}addedText(e){const t=this.form();const o=this.selected();if(!t||o.length===0)return"Added.";const i=o.length===1?`"${o[0]}"`:`${o.slice(0,-1).map(c=>`"${c}"`).join(", ")} and "${o[o.length-1]}"`;const r=o.find(c=>V(t,c)?.kind==="input");const s=V(t,o[0]);const a=r?`F2 renames "${r}"`:s?.kind==="static"?"F2 edits the text":s?.kind==="group"?"F2 edits the title":"";const l=this.variants().length-1;const d=l>0?` ${o.length===1?"It has":"They have"} no place in the other variant${l===1?"":"s"} yet.`:"";return`Added ${i}${e?`; "${e}" grew for it`:""}.${d}${a?` ${a}.`:""}`}unplacedCells(e,t){const o=this.form();const i=this.placedByName().get(e);if(!o||!i?.bounds)return null;const r=this.variants().filter(c=>c.minWidth!==this.selection().minWidth&&ye(c,e));const s=r.sort((c,p)=>Math.abs(c.minWidth-this.selection().minWidth)-Math.abs(p.minWidth-this.selection().minWidth))[0];const a=s?Ne(o,s).find(c=>c.name===e):void 0;const l=i.bounds;const d=a?.cells&&a.bounds?{colSpan:Math.max(1,Math.min(l.colSpan,Math.round(a.cells.colSpan/Math.max(1,a.bounds.colSpan)*l.colSpan))),rowSpan:a.cells.rowSpan}:{colSpan:Math.max(1,Math.round(l.colSpan/2)),rowSpan:i.element.kind==="static"?Do(this.division()):this.division()};return fs({col:t.col,row:t.row,...d},l,i.parent===null)}groupOfLayer(e){return(this.form()?.layers??[]).find(t=>t.layers.includes(e))?.name??e}addLabel(){const e=this.form();const t=this.selected()[0];const o=t?this.placedByName().get(t):void 0;if(!e||!o||o.element.kind!=="input")return;const i={kind:"static",name:`${t}Label`,text:Vh(t),for:t,...(o.element.layer?{layer:o.element.layer}:{})};const r=o.bounds;if(!o.cells||!r){this.run($i(this.file(),this.ctx(),o.parent,{elements:[i],places:{}}),void 0,"Label added (it has no place in this variant).");return}const s=Do(this.division());const a=this.placed().filter(u=>u.parent===o.parent&&u.cells&&u.name!==t&&No(u.layers,o.layers)).map(u=>u.cells);const l=this.innerCells(o.parent)??r;const d={col:o.cells.col,row:o.cells.row-s,colSpan:o.cells.colSpan,rowSpan:s};const c=u=>u.row>=l.row&&u.col>=l.col&&!a.some(f=>ut(f,u));let p=c(d)?d:null;if(!p){const u=Math.max(1,Math.round(o.cells.colSpan/3));const f={col:o.cells.col-u,row:o.cells.row,colSpan:u,rowSpan:o.cells.rowSpan};if(c(f))p=f}p??=Io(l,{colSpan:o.cells.colSpan,rowSpan:s},[...a,o.cells]);const h=p?{[i.name]:{...Le(p,r),...(p.rowSpan===o.cells.rowSpan&&p.row===o.cells.row?{justify:"end"}:{})}}:{};this.run($i(this.file(),this.ctx(),o.parent,{elements:[i],places:h}),void 0,p?"Label added.":"Label added: there is no free room for it here, so it waits in the strip under the grid.")}addPage(e){if(this.run(ax(this.file(),this.ctx(),e,this.division()),void 0,"A new page: give it its title in the Inspector, and draw its fields.")){const t=this.selected()[0];if(t)this.showPage(e,t,true)}}removeSelected(){const e=this.selected();const t=this.form();if(e.length===0||!t)return;const o=e.length===1?`"${e[0]}"`:`${e.length} elements`;const i=this.variants().filter(l=>l.minWidth!==this.selection().minWidth&&e.some(d=>ye(l,d)));const r=i.length?` (also from the variant${i.length===1?"":"s"} from ${i.map(l=>l.minWidth).join(", ")} px)`:"";if(!this.run(iu(this.file(),this.ctx(),e),void 0,`Removed ${o} from the form${r}. Ctrl+Z brings ${e.length===1?"it":"them"} back.`))return;const s=this.variants().length>1?` Shift+Delete takes ${e.length===1?"an element":"elements"} out of this variant only.`:"";const a=this.toast.info(`Removed ${o} from the form${r}.${s}`,{id:"form-editor:removed",closeAfter:8e3,actions:[{label:"Undo",icon:"fme:undo",run:()=>this.undoRemoval()}]});this.removal={ref:a,file:this.file()}}removal=null;undoRemoval(){const e=this.removal;this.removal=null;if(e&&this.file()===e.file)this.undo();else this.say("The removal is not the last step any more: Edit > Undo goes back step by step.")}duplicateSelected(){if(this.selected().length===0)return;this.run(Qv(this.file(),this.ctx(),this.selected(),this.division()),void 0,"Duplicated.")}copySelected(){const e=this.form();const t=this.selected();if(!e||t.length===0)return false;const o=pu(this.file(),this.ctx(),t);if(!o)return false;this.clipboard.set({fragment:o,form:e.name,parent:ge(e,t[0])?.parent??null});void Lr(JSON.stringify(o,null,2));this.say(t.length===1?`Copied "${t[0]}".`:`Copied ${t.length} elements.`);return true}cutSelected(){const e=this.selected();const t=this.form();if(!t||!this.copySelected())return;const o=new Set(e.flatMap(s=>ve(t).filter(a=>a.name===s||a.ancestors.includes(s)).map(a=>a.name)));const i=ve(t).flatMap(s=>s.element.kind==="static"&&s.element.for&&o.has(s.element.for)&&!o.has(s.name)?[{label:s.name,input:s.element.for}]:[]);const r=this.clipboard();if(r&&i.length)this.clipboard.set({...r,labels:i});this.run(iu(this.file(),this.ctx(),e),void 0,e.length===1?`Cut "${e[0]}": Ctrl+V puts it in again.`:`Cut ${e.length} elements: Ctrl+V puts them in again.`)}paste(e){const t=this.clipboard();if(!t)return this.warn("Nothing is copied yet: select elements and copy them (Ctrl+C).");const o=e?e.parent:this.targetList();const i=t.fragment.elements.map(d=>t.fragment.places[d.name]).filter(d=>d!==void 0);const r=i[0];const s=e?{col:e.col,row:e.row}:t.form===this.selection().form&&t.parent===o&&r?{col:Math.min(...i.map(d=>d.col)),row:Math.min(...i.map(d=>d.row))}:null;const a=hu(this.file(),this.ctx(),t.fragment,o,s,this.division());let l=a.file;if(!a.refused&&t.labels&&t.form===this.selection().form){const d=z(l,t.form);for(const{label:c,input:p}of t.labels){const h=d?V(d,c):void 0;if(h?.kind==="static"&&h.for===void 0&&d&&V(d,p)?.kind==="input")l=Vt(l,this.ctx(),c,"for",p).file}this.clipboard.set({fragment:t.fragment,form:t.form,parent:t.parent})}this.run({...a,file:l},void 0,"Pasted.")}nudgeSelected(e,t){if(this.selected().length===0)return;this.run(Bv(this.file(),this.ctx(),this.selected(),e,t),`nudge:${this.stepKey()}`)}growSelected(e,t){const o=this.form();const i=o?It(o,this.selected()):[];if(i.length===0)return;let r=this.file();let s;for(const l of i){const d=Vv(r,this.ctx(),l,e,t);s??=d.refused;r=d.file}if(r===this.file()){if(s)this.say(s);return}const a=i.length===1?ye(G(z(r,this.selection().form),this.selection().minWidth),i[0]):null;this.run({file:r,selected:this.selected()},`grow:${this.stepKey()}`,a?`"${i[0]}" takes ${a.colSpan??1} × ${a.rowSpan??1} cells.`:`${i.length} elements are larger or smaller.`)}alignSelected(e){const t=this.selected();if(t.length<2)return;const o=this.file();const i=Uv(o,this.ctx(),t,e);if(!i.refused&&i.file===o)return this.say(`They are lined up with "${t[0]}" already.`);this.run(i,void 0,`${N1[e]} "${t[0]}".`)}reorderSelected(e){const t=this.selected()[0];if(!t||this.selected().length!==1)return;this.run(Gv(this.file(),this.ctx(),t,e),void 0,e<0?"Earlier in the page.":"Later in the page.")}moveElements(e){const t=this.form();const o=e.length>0&&t&&e.every(r=>r.parent===e[0].parent&&ge(t,r.name)?.parent!==r.parent)?e[0].parent:void 0;const i=e.length===1?`"${e[0].name}"`:`${e.length} elements`;this.run(ws(this.file(),this.ctx(),e),void 0,o===void 0?`Moved ${i}.`:`Moved ${i} into ${o===null?"the form":`"${o}"`}.`)}resize(e,t){this.run(Ai(this.file(),this.ctx(),e,t),void 0,`"${e}" takes ${t.colSpan} × ${t.rowSpan} cells.`)}moveInTree(e,t,o){this.run(Wl(this.file(),this.ctx(),e,t,o),void 0,`Moved "${e}" in the order of the page.`)}rename(e,t){const o=this.form();const i=o?ve(o).find(a=>a.element.kind==="static"&&a.element.for===e):void 0;if(!this.run(Kl(this.file(),this.selection().form,e,t.trim())))return false;const r=i&&this.form()?ve(this.form()).find(a=>a.element.kind==="static"&&a.element.for===t.trim()):void 0;const s=r&&(r.name!==i?.name||JSON.stringify(r.element.kind==="static"?r.element.text:"")!==JSON.stringify(i?.element.kind==="static"?i.element.text:""));this.say(`Renamed "${e}" to "${t.trim()}"${s?`; its label follows ("${r.name}")`:""}.`);return true}setCaption(e,t){const o=this.form();const i=o?V(o,e):void 0;if(i?.kind!=="input"||!i.preview)return;const r={...(i.preview.props??{})};if(t==="")delete r["label"];else r["label"]=t;this.run(In(this.file(),this.ctx(),e,{as:i.preview.as,props:r}),void 0,t===""?`"${e}" has no caption.`:`The caption of "${e}" is "${t}".`)}textTarget(){const e=this.selected();if(e.length===1)return e[0];const t=this.form();const o=t?e.filter(i=>V(t,i)?.kind==="input"):[];return o.length===1?o[0]:null}editInPlace(e,t=false){const o=this.placedByName().get(e);if(!o)return false;if(!o.cells||!this.visible().has(e)){this.say(`"${e}" is not drawn in this variant: the Inspector has its name and its texts.`);return false}this.editingCaption.set(t);this.editingText.set(e);return true}setText(e,t){const o=this.form()?V(this.form(),e):void 0;if(!o)return;if(o.kind==="static")this.run(Vt(this.file(),this.ctx(),e,"text",ql(t)));else if(o.kind==="group")this.run(Vt(this.file(),this.ctx(),e,"title",t===""?void 0:ql(t)));else this.rename(e,t)}wrapSelected(e){this.run(rx(this.file(),this.ctx(),this.selected(),e,this.division()),void 0,"The elements are in a new group.")}unwrapSelected(){const e=this.selected()[0];if(e)this.run(sx(this.file(),this.ctx(),e),void 0,"The group is gone; its elements stay where they are.")}unplaceSelected(){const e=this.form();const t=e?It(e,this.selected()).filter(r=>this.placedByName().get(r)?.place):[];if(t.length===0)return this.say(this.selected().length?"What is selected has no place in this variant.":"Nothing is selected.");let o=this.file();for(const r of t)o=vs(o,this.ctx(),r,null).file;const i=t.length===1?`"${t[0]}" is`:`${t.length} elements are`;this.run({file:o,selected:[]},void 0,`${i} not placed in the variant from ${this.selection().minWidth} px: still in the form, in the strip under the grid (a drag or a double click places ${t.length===1?"it":"them"} again).`)}placeUnplaced(e){this.run(du(this.file(),this.ctx(),e,this.division()))}placeAt(e,t){const o=this.placedByName().get(e);if(!o?.bounds)return;this.run(vs(this.file(),this.ctx(),e,{...Le(t,o.bounds)}),void 0,`"${e}" is placed in this variant.`)}setPlaceSetting(e,t,o){this.run(xs(this.file(),this.ctx(),e,t,o))}setElementProperty(e,t,o){this.run(Vt(this.file(),this.ctx(),e,t,o))}changeRow(e,t){if(e==="e:name"&&this.selected().length===1){if(!this.rename(this.selected()[0],String(t??"")))this.refusals.update(s=>s+1);return}const o=Zx(this.file(),this.selection(),e,t,{track:this.track(),tabColumns:this.tabColumns(this.placedByName().get(this.selected()[0]??"")??null)});if(o.refused){const s=this.inspector()?.rows.find(a=>a.id===e)?.kind;if(s==="text"&&!zu.has(e)){this.say(o.refused);return}this.warn(o.refused,`form-editor:row:${e}`);this.refusals.update(a=>a+1);return}const i=e==="v:track"?this.track():null;const r=(this.selected().join(",")||`${this.selection().scope}:${this.selection().form}:${this.selection().minWidth}`)+(i?`:${i.axis}${i.indices.join(".")}`:"");this.run(o,`row:${e}:${r}`,this.rowDone(e,t))}rowDone(e,t){const o=String(t??"").trim();const{form:i,minWidth:r}=this.selection();switch(e){case"f:name":return`The form "${i}" is "${o}" now; the subforms that place it follow.`;case"f:layers":return o?`The layers of "${i}": ${o}.`:`The form "${i}" has no layers.`;case"v:minWidth":return`The variant from ${r} px is used from ${o} px now.`;case"v:cols":return`The variant has ${o} columns: every place keeps its share of the width.`;case"g:division":return`The division is ${o||zl}: the rows of every variant are scaled, so the elements keep their heights.`;default:return void 0}}setTabOrderMode(e){this.tabOrderMode.set(e);this.newTabRound();this.say(e?"Set the order of the page: click the elements one after another. Escape ends it.":"")}newTabRound(){this.tabCounters=/* @__PURE__ */new Map;if(this.tabOrdered().size)this.tabOrdered.set(/* @__PURE__ */new Set)}recountTabRound(){const e=this.form();const t=this.tabOrdered();if(!e||t.size===0)return;const o=/* @__PURE__ */new Set;this.tabCounters=/* @__PURE__ */new Map;for(const i of[null,...ve(e).flatMap(r=>r.element.kind==="group"?[r.name]:[])]){const r=Kt(e,i);let s=0;while(s<r.length&&t.has(r[s].name))o.add(r[s++].name);if(s)this.tabCounters.set(i??"",s)}this.tabOrdered.set(o)}clickInTabOrder(e){const t=this.form();const o=t?ge(t,e):void 0;if(!t||!o)return;const i=o.parent??"";const r=this.tabCounters.get(i)??0;this.tabCounters.set(i,r+1);this.tabOrdered.update(s=>/* @__PURE__ */new Set([...s,e]));this.run(Wl(this.file(),this.ctx(),e,o.parent,r),`tab-order:${this.selection().form}`);this.say(`"${e}" is number ${r+1} in ${o.parent?`"${o.parent}"`:"the form"}.`)}addVariant(e){const t=this.selection().form;const o=this.selection().minWidth;const i=`A variant from ${e} px: a copy of the one from ${o} px. Arrange it for the ${e>o?"wider":"narrower"} form.`;if(this.run(lx(this.file(),t,e,o),void 0,i))this.selectVariant(e)}async addVariantOfWidth(){const{from:e,to:t}=this.variantRange();const o=this.variants().map(l=>l.minWidth);const i=this.designWidth();const r=i!==null&&i>e&&(t===null||i<=t)?i:Math.round((t===null?e+160:(e+t)/2)/10)*10;const s=this.dialogs.open({id:"form-editor:variant-width",title:"A variant from another width",component:nr,inputs:{from:e,taken:o,width:r>0&&!o.includes(r)?r:null},buttons:[{id:"cancel",label:"Cancel",cancel:true},{id:"add",label:"Add the variant",variant:"primary",closes:false,run:l=>void l.instance?.submit()}],width:400,autoFocus:"input"});const a=await s.closed;if(typeof a==="number")this.addVariant(a)}variantProposals=M(()=>{const e=new Set(this.variants().map(t=>t.minWidth));return[360,480,600,640,768,800,960,1024,1280].filter(t=>!e.has(t))},...(ngDevMode?[{debugName:"variantProposals"}]:([])));async removeVariant(){const{form:e,minWidth:t}=this.selection();if(this.variants().length<=1)return this.warn("A form has one variant at least.");const o=t===0?this.variants().find(r=>r.minWidth>0):void 0;const i=o?` The variant from ${o.minWidth} px is used from 0 px then.`:"";if(!(await this.box.confirm(`Remove the variant from ${t} px of "${e}"? Its places go with it (undo brings them back).${i}`,{confirmLabel:"Remove",cancelLabel:"Keep",danger:true})))return;this.run(cx(this.file(),e,t),void 0,`The variant from ${t} px is gone.`)}insertTrack(e,t,o=1){const i=this.track();const r=this.run(Ss(this.file(),this.ctx(),e,t,o),void 0,`${o===1?"A":o} ${e==="col"?"column":"row"}${o===1?"":"s"} added.`);if(r&&i?.axis===e)this.selectTrack({axis:e,indices:Array.from({length:o},(s,a)=>t+a)})}deleteTrack(e,t){this.deleteTracks(e,[t])}deleteTracks(e,t){const o=t.length===1?`The ${e==="col"?"column":"row"} ${t[0]} is`:`The ${e==="col"?"columns":"rows"} ${hn(t)} are`;if(this.run(bu(this.file(),this.ctx(),e,t),void 0,`${o} gone.`))this.chosenTrack.set(null)}setTrackSizes(e,t,o){const i=t.length>1;const r=`The ${e==="col"?i?"columns":"column":i?"rows":"row"} ${hn(t)}`;const s=o===null?`${r} ${i?"have":"has"} the size of the others.`:`${r} ${i?"are each":"is"} ${o}.`;const a=t.map(l=>[l,o]);this.run(_l(this.file(),this.ctx(),e,a),void 0,s)}columnsOfSelection(){const e=/* @__PURE__ */new Set;for(const t of this.selected()){const o=this.placedByName().get(t)?.cells;if(o)for(let i=o.col;i<o.col+o.colSpan;i++)e.add(i)}return[...e].sort((t,o)=>t-o)}keepColumnWidths(e=this.columnsOfSelection()){const t=this.drawnColumns();const o=this.variant()?.cols??0;const i=this.variant()?.colSizes??{};const r=p=>/px$/.test(i[String(p)]??"");if(!e.length)return;if(t.length!==o)return this.say("The Editor measures the columns: open it, then keep their widths.");const s=e.filter(p=>!r(p)&&p<=o).map(p=>[p,`${Math.max(1,Math.round(t[p-1]))}px`]);if(!s.length)return this.say(`The ${e.length===1?`column ${e[0]} has its width`:`columns ${hn(e)} have their widths`} in px already.`);const a=s.map(([p])=>p);const l=new Set(s.map(([,p])=>p));const d=s.length===1?`The column ${a[0]} keeps its width: ${s[0][1]}.`:`The columns ${hn(a)} keep their widths: ${l.size===1?`${s[0][1]} each`:s.map(([p,h])=>`${p}: ${h}`).join(", ")}.`;const c=Array.from({length:o},(p,h)=>h+1).every(p=>r(p)||a.includes(p));this.run(_l(this.file(),this.ctx(),"col",s),void 0,c?`${d} Every column has its width in px now: the form does not grow with its container.`:d)}shareColumnWidths(){const e=this.columnsOfSelection();if(e.length)this.setTrackSizes("col",e,null)}selectColumnsOfSelection(){const e=this.columnsOfSelection();if(!e.length)return;this.selectTrack({axis:"col",indices:e});this.say(e.length===1?`The column ${e[0]}: its size is in the Inspector.`:`The columns ${hn(e)}: their size is in the Inspector.`)}setRows(e){this.run(wu(this.file(),this.ctx(),e),`rows:${this.selection().form}|${this.selection().minWidth}`,`The variant has ${e} row${e===1?"":"s"}.`);const t=this.track();if(t?.axis==="row"&&t.indices.some(o=>o>(this.variant()?.rows??0)))this.chosenTrack.set(null)}emptyEdges=M(()=>{const e=this.form();const t=this.variant();return e&&t?vu(e,t):{top:0,bottom:0,left:0,right:0}},...(ngDevMode?[{debugName:"emptyEdges"}]:([])));trimEdges(e,t,o){const i=this.emptyEdges();const r=(t?e==="col"?i.left:i.top:0)+(o?e==="col"?i.right:i.bottom:0);const s=e==="col"?r===1?"column":"columns":r===1?"row":"rows";const a=t&&o?e==="col"?"on the left and on the right":"at the top and at the bottom":t?e==="col"?"on the left":"at the top":e==="col"?"on the right":"at the bottom";const l=`${r} empty ${s} ${a} ${r===1?"is":"are"} gone${e==="col"?": the columns that share the width share it among fewer, so the elements are wider":""}.`;if(this.run(mx(this.file(),this.ctx(),e,{start:t,end:o}),void 0,l)&&this.track()?.axis===e)this.chosenTrack.set(null)}addForm(){const e=new Set(this.file().forms.map(t=>t.name));if(this.run(gx(this.file()))){const t=this.file().forms.find(o=>!e.has(o.name));if(t)this.selectForm(t.name,"form");this.say(`A new form "${t?.name}": rename it in the Inspector, and place it in another form as a subform.`)}}async removeForm(e){const t=xu(this.file(),e).refused;if(t)return this.warn(t);if(!(await this.box.confirm(`Remove the form "${e}" with its elements and variants (undo brings it back)?`,{confirmLabel:"Remove",cancelLabel:"Keep",danger:true})))return;this.run(xu(this.file(),e),void 0,`The form "${e}" is gone.`)}duplicateForm(e){const t=new Set(this.file().forms.map(i=>i.name));if(!this.run(yx(this.file(),e)))return;const o=this.file().forms.find(i=>!t.has(i.name));if(o)this.selectForm(o.name,"form");this.say(`"${o?.name}" is a copy of "${e}": rename it in the Inspector.`)}moveForm(e,t){this.run(wx(this.file(),e,t))}undo(){this.step(Ex,"Undone")}redo(){this.step(zx,"Redone")}step(e,t){const o=this.file();this.state.update(e);const i=this.file();if(i===o)return;this.recountTabRound();const r=i.forms.filter(m=>z(o,m.name)!==m);const s=r.find(m=>m.name===this.selection().form)??r[0];if(!s)return this.say(`${t}.`);const a=z(o,s.name);const l=Nt(s).filter(m=>G(a,m.minWidth)!==m);const d=this.selection();const c=l.find(m=>m.minWidth===d.minWidth&&s.name===d.form)??l[0];const p=new Set(ve(s).map(m=>m.name));const h=c?G(a,c.minWidth):void 0;const u=c?Object.keys({...c.places,...(h?.places??{})}).filter(m=>p.has(m)&&ye(c,m)!==ye(h,m)):[];if(s.name!==d.form||c&&c.minWidth!==d.minWidth||u.length){this.state.update(m=>qt(m,{form:s.name,...(c?{minWidth:c.minWidth}:{}),names:u.length?u:s.name===d.form?d.names.filter(g=>p.has(g)):[],scope:"variant"}))}const f=s.name!==d.form||c&&c.minWidth!==d.minWidth?` in ${s.name}${c?`, the variant from ${c.minWidth} px`:""}`:"";this.say(`${t}${f}.`)}async mayReplace(){if(!this.modified())return true;return this.box.confirm("Replace the file you are editing? The changes that were not saved and the steps of undo are lost.",{confirmLabel:"Replace",cancelLabel:"Keep",danger:true})}async newFile(){if(!(await this.mayReplace()))return;this.state.set(pn(Ms()));this.project.replaced(uo);this.openedFrom.set(null);this.newTabRound();this.view.update(e=>({...e,layers:{},pages:{},newLayer:{}}));this.say("A new file with one empty form: drag fields from the Toolbox, or draw an area in the grid.")}async loadSample(e){const t=Ql(e);if(!t||!(await this.mayReplace()))return;this.state.set(pn(t.file));this.project.replaced({kind:"sample",name:t.label});this.openedFrom.set(null);this.newTabRound();this.view.update(o=>({...o,layers:{},pages:{},newLayer:{}}));this.say(Ei.text("Loaded: {name}.",{name:t.label}))}async loadFromText(e,t,o={kind:"file",name:t}){const i=Nu(e);if(!i.ok){const{error:r}=i;this.warn(`${Ei.text("{name} could not be read as a form layout: line {line}.",{name:t,line:r.line})} ${Ei.text(r.template,r.params)}`,"form-editor:load");return false}if(!(await this.mayReplace()))return false;this.state.set(pn(i.file,i.notes));this.project.replaced(o);this.openedFrom.set(null);this.newTabRound();this.view.update(r=>({...r,layers:{},pages:{},newLayer:{}}));this.say(Ei.text("Loaded: {name}.",{name:t}));return true}openFile(){void Da(".json,.txt,application/json,text/plain").then(e=>e?this.loadFromText(e.text,e.name):false)}async openFromProject(){const e=await this.project.open();if(e!==null&&(await this.loadFromText(e.text,e.path)))this.project.linkTo(e)}async saveToProject(){const e=this.state().history.present;if(await this.project.save(this.fileText(),this.fileName()))this.state.update(t=>fo(t,e))}async saveToProjectAs(){const e=this.state().history.present;if(await this.project.saveAs(this.fileText(),this.fileName()))this.state.update(t=>fo(t,e))}async pasteFile(){const e=await Ea();if(e===null)this.warn("The clipboard cannot be read here. Save the text as a file and open it instead.","form-editor:clipboard");else await this.loadFromText(e,"the clipboard",{kind:"clipboard"})}async copyOutput(){if(await Lr(this.output()))this.toast.success("Copied.",{id:"form-editor:copied",closeAfter:1500});else this.warn("The clipboard cannot be written here. Select the text of the output and copy it.","form-editor:clipboard")}fileName(){return`${this.file().forms[0]?.name??"form"}.form.json`}downloadFile(){li(this.fileText(),this.fileName(),"application/json");this.downloaded()}downloaded(){if(this.project.linked()===null)this.state.update(Nx)}downloadOutput(){const e=this.selection().form;const t={file:[this.fileName(),"application/json"],template:[`${e}-form.html`,"text/html"],component:[`${e}-form.ts`,"text/plain"]};const[o,i]=t[this.outputKind()];li(this.output(),o,i);if(this.outputKind()==="file")this.downloaded()}where=M(()=>{const e=this.selection();return En({form:e.form,minWidth:e.minWidth,...(e.names.length===1?{element:e.names[0]}:{})})},...(ngDevMode?[{debugName:"where"}]:([])));elementsIn(e){const t=this.visible();const o=this.form();const i=(s,a)=>ut(a,e)&&(s.element.kind!=="group"||!Ee(e,a)||Ti(e,a));const r=this.placed().filter(s=>s.cells!==null&&t.has(s.name)&&i(s,s.cells)).map(s=>s.name);return o?It(o,r):r}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:at,deps:[],target:w.ɵɵFactoryTarget.Injectable});static ɵprov=w.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:at})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:at,decorators:[{type:Pn}],ctorParameters:()=>[]});function Is(n,e){const t=i=>{const r=ms.find(s=>s.id===i);if(i==="subform"){const s=n.subformTargets();return{label:r.label,icon:r.icon,enabled:s.length>0,children:s.map(a=>({label:a,icon:"fme:form",run:()=>e("subform",a)}))}}return{label:r.label,icon:r.icon,run:()=>e(i)}};const o=["label-above","label-beside","text-field","label","group-box"];return[{header:true,label:"Add here"},...o.map(t),{separator:true},...tu.map(i=>({label:i.label,children:ms.filter(r=>r.group===i.group).map(r=>t(r.id))}))]}const Uu=[{how:"left",label:"&Left edges",icon:"fme:align-left",text:"Line up the left edges with the first selected element",keys:"Mod+Left"},{how:"center",label:"&Centers across",icon:"fme:align-center",text:"Line up the middles across with the first selected element"},{how:"right",label:"&Right edges",icon:"fme:align-right",text:"Line up the right edges with the first selected element",keys:"Mod+Right"},{how:"width",label:"Same &width",icon:"fme:same-width",text:"Make the selected elements as wide as the first of them"},{how:"top",label:"&Top edges",icon:"fme:align-top",text:"Line up the top edges with the first selected element",keys:"Mod+Up"},{how:"middle",label:"&Middles down",icon:"fme:align-middle",text:"Line up the middles down with the first selected element"},{how:"bottom",label:"&Bottom edges",icon:"fme:align-bottom",text:"Line up the bottom edges with the first selected element",keys:"Mod+Down"},{how:"height",label:"Same &height",icon:"fme:same-height",text:"Make the selected elements as high as the first of them"},{how:"size",label:"Same si&ze",icon:"fme:same-size",text:"Make the selected elements as large as the first of them"}];function Yu(n,e){const t=n.capabilities().align;const o=r=>({label:r.label,icon:r.icon,enabled:t,...(e&&r.keys?{shortcut:r.keys}:{}),run:()=>n.alignSelected(r.how)});const i=r=>o(Uu.find(s=>s.how===r));return[{header:true,label:"Line up with the first selected"},...["left","center","right","width"].map(i),{separator:true},...["top","middle","bottom","height"].map(i),{separator:true},i("size")]}function I1(n,e,t){const o=n.elementsIn(t);return[...Is(n,(i,r)=>n.addTool(i,{parent:e,cells:t},r)),...(o.length?[{separator:true},{label:`&Select the ${o.length===1?"element":`${o.length} elements`} in the area`,run:()=>n.select(o)}]:[])]}function Ds(n,e,t="editor"){if(!n.selected().includes(e))n.select([e]);const o=n.form();const i=o?ge(o,e):void 0;if(!o||!i)return[];const r=i.element;const s=n.capabilities();const a=n.selected().length>1;const l=n.placedByName().get(e);const d=l?.place;const c=[];if(!a){if(r.kind==="input"&&s.addLabel)c.push({label:"Add a la&bel",icon:"fme:label-for",run:()=>n.addLabel()});const m=g=>void n.editInPlace(e,g);if(r.kind==="static")c.push({label:"&Edit the text",icon:"fme:text",shortcut:"F2",run:()=>m(false)});if(r.kind==="group"&&!W(r))c.push({label:"&Edit the title",icon:"fme:text",shortcut:"F2",run:()=>m(false)});if(r.kind==="input"&&Fh.includes(r.preview?.as??""))c.push({label:"&Edit the caption",icon:"fme:text",run:()=>m(true)});if(r.kind==="input"||r.kind==="subform"||W(r))c.push({label:"&Rename",shortcut:"F2",run:()=>m(false)});if(r.kind==="subform")c.push({label:`&Open the form "${r.form}"`,icon:"fme:form",run:()=>n.openSubform(e)});if(c.length)c.push({separator:true})}c.push({label:"Cu&t",icon:"fme:cut",shortcut:"Mod+X",run:()=>n.cutSelected()},{label:"&Copy",icon:"fme:copy",shortcut:"Mod+C",run:()=>void n.copySelected()},{label:"&Paste",icon:"fme:paste",shortcut:"Mod+V",enabled:s.paste,run:()=>n.paste()},{label:"Dup&licate",icon:"fme:duplicate",shortcut:"Mod+D",enabled:s.duplicate,run:()=>n.duplicateSelected()},{separator:true},{label:"Remove &from the form",icon:"fme:remove",shortcut:"Del",run:()=>n.removeSelected()},n.unplaced().some(m=>m.name===e)?{label:"Place in this &variant",icon:"fme:place",run:()=>n.placeUnplaced(n.selected())}:{label:"Not placed in this &variant",icon:"fme:unplace",shortcut:"Shift+Del",enabled:s.unplace,run:()=>n.unplaceSelected()},{separator:true});c.push({label:"Put into a &group",icon:"fme:wrap",enabled:s.wrap,children:[{label:"A group without a frame",icon:"fme:group",run:()=>n.wrapSelected("none")},{label:"A group box",icon:"fme:group-box",run:()=>n.wrapSelected("group-box")}]});if(!a&&r.kind==="group")c.push({label:"Ungr&oup",icon:"fme:unwrap",enabled:s.unwrap,run:()=>n.unwrapSelected()});if(a)c.push({label:"Li&ne up with the first",icon:"fme:align-left",enabled:s.align,children:Yu(n,t==="editor")});const p=n.columnsOfSelection();if(p.length)c.push({label:"Colu&mns",icon:"fme:columns",children:[{header:true,label:p.length===1?`The column ${p[0]}`:`The columns ${hn(p)}`},{label:p.length===1?"&Keep the width it has now (px)":"&Keep the width they have now (px)",run:()=>n.keepColumnWidths()},{label:"&Share the width (1fr)",run:()=>n.shareColumnWidths()},{label:p.length===1?"Se&lect it (its size in the Inspector)":"Se&lect them (their size in the Inspector)",run:()=>n.selectColumnsOfSelection()}]});const h=l?.cells;if(h)c.push({label:"&Insert",icon:"fme:rows",children:[{header:true,label:`Next to "${e}"`},{label:"A row &above",icon:"fme:rows",run:()=>n.insertTrack("row",h.row)},{label:"A row &below",icon:"fme:rows",run:()=>n.insertTrack("row",h.row+h.rowSpan)},{label:"A column &left",icon:"fme:columns",run:()=>n.insertTrack("col",h.col)},{label:"A column &right",icon:"fme:columns",run:()=>n.insertTrack("col",h.col+h.colSpan)}]});const u=W(r)?r.name:i.parent!==null&&W(V(o,i.parent))?i.parent:null;if(!a&&u)c.push({label:"&Add a page",icon:"fme:page",run:()=>n.addPage(u)});c.push({separator:true});const f=(o.layers??[]).flatMap(m=>m.layers.map(g=>({group:m.name,layer:g})));if(!f.length){c.push({label:"La&yer",icon:"fme:layers",children:[{label:"The form has no layers: define them in the Inspector of the form…",run:()=>n.editLayers()}]})}else{const m=a?void 0:r.layer;c.push({label:"La&yer",icon:"fme:layers",children:[{label:"No layer",checked:!a&&!m,run:()=>n.changeRow("e:layer","")},...f.map(({group:g,layer:y})=>({label:`${y} (${g})`,checked:m===y,run:()=>n.changeRow("e:layer",y)})),{separator:true},{label:"&Edit the layers…",run:()=>n.editLayers()}]})}if(!a&&r.kind==="input"){const m=r.preview?.as??"";const g=b=>({label:Il[b],checked:m===b,run:()=>n.changeRow("e:preview",b)});const y=b=>ki.filter(x=>x.group===b).map(x=>x.as);c.push({label:"Preview &as",children:[{label:"A box",checked:m==="",run:()=>n.changeRow("e:preview","")},{separator:true},...y("fields").map(g),{label:"&More fields",checked:y("more").includes(m),children:y("more").map(g)},{label:"&Content",checked:y("content").includes(m),children:y("content").map(g)},{separator:true},{label:"Own component (a tag of the application)",icon:"fme:own",checked:it(m),run:()=>n.changeRow("e:preview",_h)}]})}if(!a&&r.kind==="group"&&!W(i.parent?V(o,i.parent):void 0)){const m=r.look??"group-box";c.push({label:"Loo&k",children:[{label:"Group box",checked:m==="group-box",run:()=>n.changeRow("e:look","")},{label:"No frame",checked:m==="none",run:()=>n.changeRow("e:look","none")},{label:"Property sheet",checked:m==="property-sheet",run:()=>n.changeRow("e:look","property-sheet")}]})}if(!a&&(r.kind==="subform"||r.kind==="group"&&!W(r)&&!W(i.parent?V(o,i.parent):void 0))){const m=r.kind==="group"||r.kind==="subform"?r.repeat===true:false;c.push({label:"Repe&at",icon:"fme:repeat",checked:m,run:()=>n.changeRow("e:repeat",!m)})}if(!a&&(r.kind==="static"||r.kind==="input")&&d){const m=["start","center","end","stretch"];c.push({label:"Align (&down)",children:m.map(g=>({label:g,checked:(d.align??"center")===g,run:()=>n.setPlaceSetting(e,"align",g==="center"?void 0:g)}))},{label:"&Justify (across)",children:m.map(g=>({label:g,checked:(d.justify??"stretch")===g,run:()=>n.setPlaceSetting(e,"justify",g==="stretch"?void 0:g)}))})}return c}function oc(n,e,t){const o=n.variant();return[...Is(n,(i,r)=>n.addToolAtCell(i,e,t,r)),{separator:true},{label:"&Paste here",icon:"fme:paste",enabled:n.capabilities().paste,run:()=>n.paste({parent:e,col:t.col,row:t.row})},{label:"&Select all",run:()=>n.selectAll(e)},{separator:true},{label:"Insert a row &above",icon:"fme:rows",run:()=>n.insertTrack("row",t.row)},{label:"Insert a row &below",icon:"fme:rows",run:()=>n.insertTrack("row",t.row+1)},{label:"Insert a column &left",icon:"fme:columns",run:()=>n.insertTrack("col",t.col)},{label:"Insert a column &right",icon:"fme:columns",run:()=>n.insertTrack("col",t.col+1)},{label:`Remove the row ${t.row}`,enabled:(o?.rows??1)>1,run:()=>n.deleteTrack("row",t.row)},{label:`Remove the column ${t.col}`,enabled:(o?.cols??1)>1,run:()=>n.deleteTrack("col",t.col)},{separator:true},...Ju(n)]}function Ju(n){const e=n.emptyEdges();const t=(o,i,r,s)=>({label:`${o} (${i===0?"none":`${i} ${r}${i===1?"":"s"}`})`,enabled:i>0,run:s});return[{label:"&Trim the empty rows",icon:"fme:trim",enabled:e.top+e.bottom>0,children:[t("At the &top",e.top,"row",()=>n.trimEdges("row",true,false)),t("At the &bottom",e.bottom,"row",()=>n.trimEdges("row",false,true)),t("B&oth",e.top+e.bottom,"row",()=>n.trimEdges("row",true,true))]},{label:"Trim the empty colu&mns",icon:"fme:trim-cols",enabled:e.left+e.right>0,children:[t("On the &left",e.left,"column",()=>n.trimEdges("col",true,false)),t("On the &right",e.right,"column",()=>n.trimEdges("col",false,true)),t("B&oth",e.left+e.right,"column",()=>n.trimEdges("col",true,true))]}]}function D1(n,e,t){const o=n.track();const i=o&&o.axis===e&&o.indices.includes(t)?[...o.indices].sort((u,f)=>u-f):[t];n.selectTrack({axis:e,indices:i});const r=n.variant();const s=e==="col"?r?.cols??1:r?.rows??1;const a=i.length>1;const l=e==="col"?a?"columns":"column":a?"rows":"row";const d=e==="col"?r?.colSizes:r?.rowSizes;const c=u=>d?.[String(u)]??"";const p=u=>i.every(f=>c(f)===u);const h=u=>()=>n.setTrackSizes(e,i,u);return[{label:e==="col"?"Insert a column &left":"Insert a row &above",icon:e==="col"?"fme:columns":"fme:rows",run:()=>n.insertTrack(e,t)},{label:e==="col"?"Insert a column &right":"Insert a row &below",icon:e==="col"?"fme:columns":"fme:rows",run:()=>n.insertTrack(e,t+1)},{label:`Re&move the ${l} ${hn(i)}`,icon:"fme:remove",enabled:s>i.length,run:()=>n.deleteTracks(e,i)},{separator:true},{label:"&Size",children:[{label:e==="col"?"A share of the width (1fr)":"A row of the grid",checked:p(""),run:h(null)},{label:"As the content (auto)",checked:p("auto"),run:h("auto")},...(e==="col"?[{label:"Two shares (2fr)",checked:p("2fr"),run:h("2fr")},{label:a?"Keep the width they have now (px)":"Keep the width it has now (px)",run:()=>n.keepColumnWidths(i)}]:[]),{label:"Another size… (the Inspector)",run:()=>n.selectTrack({axis:e,indices:i})}]}]}const Xu={small:16,medium:28,large:44,xlarge:72};function E1(n){const e=n["mode"];const t=typeof n["format"]==="string"&&n["format"]!==""?n["format"]:e==="time"||e==="countdown"?"99:99:99":e==="stopwatch"?"99:99.99":"8888";return t.replace(/\\(.)/g,"$1").replace(/9/g,"8").replace(/[a*]/gi,"A")}const z1=n=>n.kind==="input"&&Fh.includes(n.preview?.as??"");const Zu=2;function L1(n,e){const t=[n.top>0?`${n.top} px over its top`:"",n.bottom>0?`${n.bottom} px under its bottom`:"",n.left>0?`${n.left} px left of it`:"",n.right>0?`${n.right} px right of it`:""].filter(s=>s!=="").join(", ");const o=n.top>0||n.bottom>0;const i=n.top>0!==n.bottom>0;const r=o&&i&&(e==="start"||e==="end")?`align ${e} puts it at the inner edge of the place (half a space in), so what is higher than the place reaches out on the other side: give it more rows (2, as high as a control), or align it center`:o?"give it more rows, or make it wider (a text and the options of a radio group go into more lines where the place is narrow)":"make it wider";return`it does not fit its place (${t}): ${r}`}const R1=(n,e)=>n.size===e.size&&[...n].every(([t,o])=>{const i=e.get(t);return i!==void 0&&i.top===o.top&&i.bottom===o.bottom&&i.left===o.left&&i.right===o.right});const F1=["nw","n","ne","e","se","s","sw","w"];const Qu=n=>typeof n==="number"?`${n}px`:typeof n==="string"&&n.endsWith("%")?`calc(var(--gfy-control-height, 28px) * ${parseFloat(n)/100})`:null;const ef=(n,e)=>n===void 0?e:n.endsWith("fr")?`minmax(0, ${n})`:n;class ir{store=L(at);popup=L(Wo);destroyRef=L(lt);stageRef=ct.required("stage");pageRef=ct.required("page");gridRef=ct.required("grid");editRef=ct("edit",...(ngDevMode?[{debugName:"editRef"}]:([])));edges=F1;tracks=E(null,...(ngDevMode?[{debugName:"tracks"}]:([])));hint=E(null,...(ngDevMode?[{debugName:"hint"}]:([])));into=E(null,...(ngDevMode?[{debugName:"into"}]:([])));busy=E(null,...(ngDevMode?[{debugName:"busy"}]:([])));placing=E(null,...(ngDevMode?[{debugName:"placing"}]:([])));stageWidth=E(0,...(ngDevMode?[{debugName:"stageWidth"}]:([])));overflow=E(/* @__PURE__ */new Map,...(ngDevMode?[{debugName:"overflow"}]:([])));gesture=null;gesturePointer=null;pending=null;lastResizeOk=true;frameRequest=0;alignCommands=Uu;alignTip(e){return e.keys?`${e.text} (${dc(e.keys)})`:e.text}variantOptions=M(()=>this.store.variants().map(e=>({value:String(e.minWidth),label:`≥ ${e.minWidth}`,tooltip:`The variant for the widths from ${e.minWidth} px (${e.cols} × ${e.rows} cells)`})),...(ngDevMode?[{debugName:"variantOptions"}]:([])));variantKey=M(()=>String(this.store.selection().minWidth),...(ngDevMode?[{debugName:"variantKey"}]:([])));variantItems=M(()=>[{header:true,label:"A copy of this variant, from"},...this.store.variantProposals().map(e=>({label:`${e} px`,run:()=>this.store.addVariant(e)})),{label:"Another width…",run:()=>void this.store.addVariantOfWidth()},{separator:true},{label:"Remove this variant…",icon:"fme:remove",enabled:this.store.variants().length>1,run:()=>void this.store.removeVariant()}],...(ngDevMode?[{debugName:"variantItems"}]:([])));rangeText=M(()=>{const e=this.store.variantRange();const t=this.store.minFormWidth();if(e.to!==null&&t>e.to)return`${e.from}–${e.to} px, never used (minFormWidth ${t} px)`;const o=Math.max(e.from,t);return e.to===null?`from ${o} px`:`${o}–${e.to} px`},...(ngDevMode?[{debugName:"rangeText"}]:([])));layerGroups=M(()=>{const e=this.store.active();return(this.store.form()?.layers??[]).map(t=>({name:t.name,value:Object.prototype.hasOwnProperty.call(e,t.name)?e[t.name]:t.layers[0]??"",options:t.layers.map(o=>({value:o,label:o,tooltip:`Show the elements of the layer ${o} (those of the other layers of ${t.name} are hidden, they may share cells)`}))}))},...(ngDevMode?[{debugName:"layerGroups"}]:([])));newLayerLabel=M(()=>this.layerGroups().length?`New: ${this.store.newLayer()||"no layer"}`:"Layers",...(ngDevMode?[{debugName:"newLayerLabel"}]:([])));newLayerItems=M(()=>{const e=this.store.newLayer();const t=this.store.form()?.layers??[];const o={label:"Edit the layers…",run:()=>this.store.editLayers()};if(!t.length)return[{header:true,label:"The form has no layers"},o];return[{header:true,label:"The layer of the elements you add"},{label:"No layer (always shown)",checked:e==="",run:()=>this.store.setNewLayer("")},...t.flatMap(i=>i.layers.map(r=>({label:`${r} (${i.name})`,checked:e===r,run:()=>this.store.setNewLayer(r)}))),{separator:true},o]},...(ngDevMode?[{debugName:"newLayerItems"}]:([])));slideRange=M(()=>{const{from:e,to:t}=this.store.variantRange();const o=this.store.minFormWidth();const i=Math.max(e,o>0?o:240);const r=t!==null&&i>t-10?Math.max(e,240):i;return{min:r,max:Math.max(r+10,t??Math.max(1280,r*2))}},...(ngDevMode?[{debugName:"slideRange"}]:([])));pxText=e=>`${e} px`;width=M(()=>{const{min:e,max:t}=this.slideRange();const o=this.store.designWidth();const i=o??this.stageWidth()-70;return Math.round(Math.min(t,Math.max(e,i)))},...(ngDevMode?[{debugName:"width"}]:([])));gridWidth=M(()=>{const e=this.tracks()?.cols??[];const t=e[e.length-1];return t?t.start+t.size:this.width()},...(ngDevMode?[{debugName:"gridWidth"}]:([])));spacingX=M(()=>{const e=this.store.file();return Qu(this.store.form()?.spacing?.x??e.spacing?.x)},...(ngDevMode?[{debugName:"spacingX"}]:([])));spacingY=M(()=>{const e=this.store.file();return Qu(this.store.form()?.spacing?.y??e.spacing?.y)},...(ngDevMode?[{debugName:"spacingY"}]:([])));columns=M(()=>{const e=this.store.variant();if(!e)return"none";return Array.from({length:e.cols},(t,o)=>ef(e.colSizes?.[String(o+1)],"minmax(0, 1fr)")).join(" ")},...(ngDevMode?[{debugName:"columns"}]:([])));rows=M(()=>{const e=this.store.variant();if(!e)return"none";return Array.from({length:e.rows},(t,o)=>ef(e.rowSizes?.[String(o+1)],"var(--_row)")).join(" ")},...(ngDevMode?[{debugName:"rows"}]:([])));colLines=M(()=>Array.from({length:this.store.variant()?.cols??0},(e,t)=>t+1),...(ngDevMode?[{debugName:"colLines"}]:([])));rowLines=M(()=>Array.from({length:this.store.variant()?.rows??0},(e,t)=>t+1),...(ngDevMode?[{debugName:"rowLines"}]:([])));colNums=M(()=>this.numbers("col"),...(ngDevMode?[{debugName:"colNums"}]:([])));rowNums=M(()=>this.numbers("row"),...(ngDevMode?[{debugName:"rowNums"}]:([])));numbers(e){const t=this.tracks();const o=this.store.variant();if(!t||!o)return[];const i=e==="col"?t.cols:t.rows;const r=e==="col"?o.colSizes:o.rowSizes;const s=i.reduce((d,c)=>d+c.size,0)/Math.max(1,i.length);const a=e==="col"?String(i.length).length*6+4:12;const l=[1,2,5,10,20,50,100,200,500].find(d=>d*s>=a)??1e3;return i.map((d,c)=>{const p=c+1;const h=r?.[String(p)];const u=p===1||p%l===0||h!==void 0&&l===1;return{n:p,x:d.start,y:d.start,size:d.size,label:u?String(p):"",sized:h!==void 0,title:`${e==="col"?"Column":"Row"} ${p}${h?`: ${h}`:""} (click: its size in the Inspector; Shift and a click, or a drag over the numbers: several, Ctrl and a click: one more or one less; right click: insert, remove, size)`}})}isTrack(e,t){const o=this.store.track();return o!==null&&o.axis===e&&o.indices.includes(t)}helpText=M(()=>this.store.tabOrderMode()?"Click the elements in the order the Tab key should take them: each click puts the element next in its list (the numbers show the order). Escape or the button ends it.":"Click selects (Ctrl adds), Shift and a drag adds what a rectangle touches, a drag moves (into a group when it lands in one), the handles stretch, a drag over empty cells draws an area and offers what to put there. The buttons above (and Ctrl and an arrow) line the selected elements up with the first selected one. Drop a tool of the Toolbox on a cell. Arrows move, Shift and arrows stretch, Alt and Up or Down change the order of the page, F2 edits the text or the name, Delete removes from the form and Shift+Delete only from this variant. Right click for more; Help > Keyboard and mouse has the rest.",...(ngDevMode?[{debugName:"helpText"}]:([])));orderNumbers=M(()=>{const e=this.store.form();const t=/* @__PURE__ */new Map;if(!e||!this.store.tabOrderMode())return t;const o=(i,r)=>{i.forEach((s,a)=>{const l=`${r}${a+1}`;t.set(s.name,l);o(ce(s),`${l}.`)})};o(e.elements,"");return t},...(ngDevMode?[{debugName:"orderNumbers"}]:([])));drawn=M(()=>{const e=this.store.visible();const t=this.store.problemsByElement();const o=this.orderNumbers();const i=this.store.placedByName();const r=a=>this.store.shownPageOf(a);const s=[];for(const a of this.store.placed()){if(!a.cells||!e.has(a.name))continue;s.push(this.drawnOf(a,a.cells,i,{key:a.name,ghost:false,z:1+a.depth*2,problem:t.get(a.name)??null,order:o.get(a.name)??"",shownPage:r}))}return s},...(ngDevMode?[{debugName:"drawn"}]:([])));pictured=M(()=>[...this.drawn(),...this.ghosts()],...(ngDevMode?[{debugName:"pictured"}]:([])));drawnOf(e,t,o,i){const r=e.element;const s=e.parent?o.get(e.parent):void 0;const a=s?.element.kind==="group"&&W(s.element);let l="";let d=false;let c="";let p="";let h=[];let u=[];let f="";let m=0;let g="";let y="";let b="";let x=false;if(r.kind==="static"){l=cn(r.text);d=dn(r.text)}else if(r.kind==="input"){c=r.preview?.as??"";p=c?Ph[c]??c:"";const T=r.preview?.props??{};l=typeof T["label"]==="string"?T["label"]:typeof T["text"]==="string"?T["text"]:"";h=Array.isArray(T["options"])?T["options"].slice(0,12).map(k=>typeof k==="string"?k:String(k?.label??"")):[];if(c==="gfy-digital-display"){f=E1(T);m=typeof T["size"]==="number"?Math.min(400,Math.max(8,T["size"])):Xu[String(T["size"])]??Xu["medium"]}if(c==="gfy-file-upload")g=T["appearance"]==="row"||T["appearance"]==="strip"?T["appearance"]:"box";if(c==="gfy-toggle-group"&&h.length===0)h=["First","Second","Third"];if(typeof T["variant"]==="string"&&T["variant"]!=="default")y=T["variant"];if(typeof T["icon"]==="string")b=T["icon"];x=c==="gfy-radio-group"&&T["orientation"]!=="horizontal"}else if(r.kind==="group"){l=cn(r.title);if(W(r)){const T=i.shownPage(r.name);u=ce(r).filter(k=>k.kind==="group"&&o.get(k.name)?.cells).map(k=>({name:k.name,title:cn(k.kind==="group"?k.title:"")||k.name,on:k.name===T}))}}return{key:i.key,ghost:i.ghost,name:e.name,placed:e,kind:r.kind,area:`${t.row} / ${t.col} / span ${t.rowSpan} / span ${t.colSpan}`,z:i.z,align:r.kind==="static"||r.kind==="input"?e.place?.align??"center":"stretch",justify:r.kind==="static"||r.kind==="input"?e.place?.justify??"stretch":"stretch",text:l,code:d,appearance:r.kind==="static"?r.appearance??"label":"",as:c,tag:p,look:r.kind==="group"?r.look??"group-box":"",repeat:(r.kind==="group"||r.kind==="subform")&&r.repeat===true,page:a,tabs:u,tabSide:e.place?.tabs??"top",sub:r.kind==="subform"?r.form:"",flow:r.kind==="subform"&&e.place?.flow===true,problem:i.problem,order:i.order,options:h,more:r.kind==="subform"&&e.place?.flow===true?this.flowRows(e):0,content:r.kind==="input"&&Ev(c),own:r.kind==="input"&&it(c),digits:f,digitSize:m,upload:g,variant:y,icon:b,vertical:x}}flowRows(e){const t=Xh(this.store.file(),e,[this.store.selection().form]);if(!t||!e.cells)return 0;const o=Math.max(0,...t.elements.filter(i=>i.cells).map(i=>i.cells.row+i.cells.rowSpan-1));return Math.max(0,o-(e.cells.row+e.cells.rowSpan-1))}ghosts=M(()=>{const e=[];const t=this.store.visible();const o=this.store.file();for(const i of this.store.placed()){if(i.element.kind!=="subform"||!i.cells||!t.has(i.name))continue;const r=Xh(o,i,[this.store.selection().form]);if(!r)continue;const s=new Map(r.elements.map(l=>[l.name,l]));const a=l=>r.elements.find(d=>d.parent===l&&d.layers.some(c=>c.group===l&&c.layer===d.name&&c.first))?.name??null;for(const l of r.elements){if(!l.cells||!Ee(l.cells,i.cells)||l.layers.some(d=>!d.first))continue;e.push(this.drawnOf(l,l.cells,s,{key:`${i.name}.${l.name}`,ghost:true,z:2+i.depth*2,problem:null,order:"",shownPage:a}))}}return e},...(ngDevMode?[{debugName:"ghosts"}]:([])));frames=M(()=>{const e=this.tracks();if(!e)return[];const t=this.store.placedByName();const o=this.store.visible();return this.store.selected().map(i=>t.get(i)).filter(i=>i!==void 0&&i.cells!==null&&o.has(i.name)).map(i=>{const r=Fl(e.cols,e.rows,i.cells);return{name:i.name,group:i.element.kind==="group",box:r,inside:r.y<22}})},...(ngDevMode?[{debugName:"frames"}]:([])));editTowardLeft=M(()=>{const e=this.store.editingText();const t=this.tracks();const o=e===null?null:this.store.placedByName().get(e)?.cells;if(!t||!o)return false;return Fl(t.cols,t.rows,o).x+84>this.gridWidth()},...(ngDevMode?[{debugName:"editTowardLeft"}]:([])));hintSize=M(()=>{const e=this.hint();const t=this.gesture;void e;if(t?.kind==="rows")return`${t.rows} rows`;if(t?.kind==="select"){const i=this.store.elementsIn(t.cells).filter(r=>!t.was.includes(r)).length;return i===1?"+1 element":`+${i} elements`}const o=t?.kind==="draw"||t?.kind==="resize"||t?.kind==="place"?t.cells:t?.kind==="move"?t.target?.box:this.outlinePlace?.cells??this.pending;return o?`${o.colSpan} × ${o.rowSpan}`:""},...(ngDevMode?[{debugName:"hintSize"}]:([])));titleOf(e){const t=e.placed.place?`col ${e.placed.place.col}, row ${e.placed.place.row}, ${e.placed.place.colSpan??1} × ${e.placed.place.rowSpan??1}`:"";const o=e.kind==="input"?`input${e.tag?` (${e.tag})`:""}`:e.kind==="group"?e.page?"page":e.look==="property-sheet"?"property sheet":`group${e.repeat?", repeated":""}`:e.kind==="subform"?`subform of the form "${e.sub}" (a double click opens it)`:e.kind;const i=e.ghost?void 0:this.overflow().get(e.name);const r=[i?L1(i,e.align):"",e.code?"its text is code of the application (ƒ)":"",e.repeat?"it repeats (×N): the place holds one instance, the application says how many":"",e.flow?"it flows (↧): it adds the rows it needs under its place":""].filter(s=>s!=="");return`${e.name}: ${o}${t?` — ${t}`:""}${r.length?`; ${r.join("; ")}`:""}`}constructor(){const e={over:(o,i,r)=>{this.outlinePlace=this.placeUnder(o,i,r);this.showPlace(this.outlinePlace)},drop:(o,i,r)=>{this.outlinePlace=null;this.hint.set(null);this.dropPlace(o,this.placeUnder(o,i,r))},leave:()=>{if(this.outlinePlace)this.hint.set(null);this.outlinePlace=null}};this.store.placeTarget=e;this.destroyRef.onDestroy(()=>{if(this.store.placeTarget===e)this.store.placeTarget=null});Q(()=>{this.store.placed();this.store.variant();this.store.view();this.store.division();this.width();this.spacingX();this.spacingY();this.store.visible();this.schedule()});Q(()=>{const o=this.store.selection();const i=`${o.form}|${o.minWidth}|${o.names.join(",")}`;if(i===this.shownKey)return;this.shownKey=i;if(o.names.length)ee(()=>requestAnimationFrame(()=>this.scrollToSelection()))});let t=this.store.focusEditor();Q(()=>{const o=this.store.focusEditor();if(o===t)return;t=o;ee(()=>this.stageRef().nativeElement.focus({preventScroll:true}))});Q(()=>{const o=this.width();const i=this.stageWidth()>0||this.store.designWidth()!==null;if(i)ee(()=>this.store.editorWidth.set(o))});Q(()=>{const o=this.store.editingText();const i=this.editRef()?.nativeElement;if(o!==null&&i){ee(()=>{i.focus();i.select()})}});ur(()=>{const o=new ResizeObserver(()=>{this.stageWidth.set(this.stageRef().nativeElement.clientWidth);this.schedule()});o.observe(this.stageRef().nativeElement);o.observe(this.gridRef().nativeElement);this.destroyRef.onDestroy(()=>o.disconnect());this.stageWidth.set(this.stageRef().nativeElement.clientWidth);this.schedule()});this.destroyRef.onDestroy(()=>{cancelAnimationFrame(this.frameRequest);this.endGesture();this.store.drawnColumns.set([])})}schedule(){if(this.frameRequest!==0)return;this.frameRequest=requestAnimationFrame(()=>{this.frameRequest=0;this.measure()})}measure(){const e=this.gridRef().nativeElement;const t=this.pageRef().nativeElement;const o=getComputedStyle(e);const i=t.getBoundingClientRect();const r=e.getBoundingClientRect();const s=Qh(Zh(o.gridTemplateColumns),r.left-i.left);const a=Qh(Zh(o.gridTemplateRows),r.top-i.top);this.tracks.update(p=>p&&tf(p.cols,s)&&tf(p.rows,a)?p:{cols:s,rows:a});const l=s.map(p=>p.size);const d=this.store.drawnColumns();if(l.length!==d.length||l.some((p,h)=>Math.abs(p-d[h])>0.25))this.store.drawnColumns.set(l);const c=/* @__PURE__ */new Map;for(const p of Array.from(e.querySelectorAll(":scope > .area:not(.ghost)"))){const h=p.getAttribute("data-name");const u=p.firstElementChild;if(!h||!u||!(p.classList.contains("k-static")||p.classList.contains("k-input")))continue;const f=p.getBoundingClientRect();const m=u.getBoundingClientRect();const g={top:f.top-m.top,bottom:m.bottom-f.bottom,left:f.left-m.left,right:m.right-f.right};if(Object.values(g).every(b=>b<=Zu))continue;const y=b=>b>Zu?Math.round(b):0;c.set(h,{top:y(g.top),bottom:y(g.bottom),left:y(g.left),right:y(g.right)})}if(!R1(c,this.overflow()))this.overflow.set(c)}onVariant(e){if(e!==null)this.store.selectVariant(Number(e))}onLayer(e,t){if(t!==null)this.store.setLayer(e,t)}onFit(e){this.store.setDesignWidth(e?null:this.width())}onSlide(e){this.store.setDesignWidth(e)}placeAll(){this.store.placeUnplaced(this.store.unplaced().map(e=>e.name))}placeChip(e){this.store.placeUnplaced([e]);this.stageRef().nativeElement.focus({preventScroll:true})}rowSize(){const e=this.tracks()?.rows??[];const t=e.map(o=>o.size).filter(o=>o>0);return t.length?t.sort((o,i)=>o-i)[Math.floor(t.length/2)]:18}cellAt(e,t){const o=this.tracks();if(!o)return null;const i=this.pageRef().nativeElement.getBoundingClientRect();return{col:eu(o.cols,e-i.left),row:eu(o.rows,t-i.top,true,this.rowSize())}}boxOf(e){const t=this.tracks();return t?Fl(t.cols,t.rows,e,this.rowSize()):null}nameAt(e){if(!(e instanceof Element))return null;const t=e.closest("[data-name]");return t&&this.gridRef().nativeElement.contains(t)?t.getAttribute("data-name"):null}containerFor(e,t=/* @__PURE__ */new Set){const o=this.store.visible();const i=this.store.form();let r=null;for(const s of this.store.placed()){if(s.element.kind!=="group"||!s.cells||!o.has(s.name)||W(s.element))continue;if(t.has(s.name)||i&&ve(i).find(l=>l.name===s.name)?.ancestors.some(l=>t.has(l)))continue;const a=this.store.innerCells(s.name);if(!a||!Ee(e,a))continue;if(!r||s.depth>r.depth)r=s}return r?.name??null}freeIn(e,t,o,i){return!this.store.placed().some(r=>r.parent===e&&r.cells&&!i.has(r.name)&&No(r.layers,o)&&ut(r.cells,t))}onStagePress(e){this.stageRef().nativeElement.focus({preventScroll:true});const t=e.target;if(e.button!==0||t.closest(".page, .tray, .rows-grip, .nums"))return;this.store.select([]);this.here()}here(){const e=this.store.selection();this.shownKey=`${e.form}|${e.minWidth}|${e.names.join(",")}`}onPress(e){this.press(e);this.here()}press(e){const t=e.target;if(t.closest(".edit, .handle, .grip"))return;this.stageRef().nativeElement.focus({preventScroll:true});if(e.button!==0)return;e.preventDefault();const o=t.closest("[data-page]");if(o){this.store.showPage(o.getAttribute("data-sheet"),o.getAttribute("data-page"),true);return}const i=this.cellAt(e.clientX,e.clientY);const r=this.store.variant();if(!i||!r)return;const s=this.nameAt(e.target);if(this.store.tabOrderMode()){if(s)this.store.clickInTabOrder(s);return}const a=this.store.selected();if(e.ctrlKey||e.metaKey||e.shiftKey){this.begin({kind:"press",startX:e.clientX,startY:e.clientY,name:s,cell:i,then:"select",list:null,limit:Pe(r),was:a},e);return}const l=Pe(r);if(!s){this.begin({kind:"press",startX:e.clientX,startY:e.clientY,name:null,cell:i,then:"draw",list:null,limit:l,was:a},e);return}const d=this.store.placedByName();const c=d.get(s);if(!c?.cells)return;const p=u=>{const f=u.parent?d.get(u.parent):void 0;return f!==void 0&&f.element.kind==="group"&&W(f.element)};let h;if(!a.includes(s)){for(let u=c.parent;u!==null;u=d.get(u)?.parent??null){const f=d.get(u);if(f&&a.includes(u)&&!p(f))h=f}}if(h?.cells){this.begin({kind:"press",startX:e.clientX,startY:e.clientY,name:h.name,cell:i,then:"move",list:h.parent,limit:l,was:a,inner:s},e);return}if(c.element.kind==="group"&&!(a.length===1&&a[0]===s)){const u=W(c.element)?this.store.shownPageOf(s):s;const f=u?this.store.innerCells(u):null;const m=this.store.placed().some(g=>g.parent===u&&g.cells&&this.store.visible().has(g.name)&&Ee({...i,colSpan:1,rowSpan:1},g.cells));if(u&&f&&Ee({...i,colSpan:1,rowSpan:1},f)&&!m){this.begin({kind:"press",startX:e.clientX,startY:e.clientY,name:s,cell:i,then:"draw",list:u,limit:f,was:a},e);return}}if(!a.includes(s))this.store.select([s]);this.begin({kind:"press",startX:e.clientX,startY:e.clientY,name:s,cell:i,then:"move",list:c.parent,limit:l,was:a},e)}startMove(e,t){if(e.button!==0)return;e.preventDefault();e.stopPropagation();const o=this.cellAt(e.clientX,e.clientY);const i=this.store.placedByName().get(t);if(!o||!i?.cells)return;this.begin({kind:"press",startX:e.clientX,startY:e.clientY,name:t,cell:o,then:"move",list:i.parent,limit:i.cells,was:this.store.selected()},e);this.toMove(this.gesture)}startResize(e,t,o){if(e.button!==0)return;e.preventDefault();e.stopPropagation();const i=o?this.store.placedByName().get(o):void 0;if(!o||!i?.cells||!i.bounds)return;let r=null;if(i.element.kind==="group"){const a=W(i.element);const l=this.store.placed().filter(c=>c.parent===o&&c.cells&&!(a&&c.element.kind==="group"));const d=Cn(l.map(c=>c.cells));if(d){const c=this.store.insetsOf(o);const p=i.cells;const h=Math.max(p.col,d.col-c.left);const u=Math.max(p.row,d.row-c.top);const f=Math.min(p.col+p.colSpan-1,d.col+d.colSpan-1+c.right);const m=Math.min(p.row+p.rowSpan-1,d.row+d.rowSpan-1+c.bottom);r={col:h,row:u,colSpan:Math.max(1,f-h+1),rowSpan:Math.max(1,m-u+1)}}}this.lastResizeOk=true;const s=Math.min(i.cells.rowSpan,as(i.element,this.store.division()));this.begin({kind:"resize",name:o,edge:t,start:i.cells,bounds:i.bounds,growDown:i.parent===null,keep:r,minRows:s,cells:null},e)}startRows(e){if(e.button!==0||!this.store.variant())return;e.preventDefault();this.begin({kind:"rows",rows:this.store.variant().rows},e)}begin(e,t,o=this.pageRef().nativeElement){this.endGesture();this.gesture=e;this.gesturePointer=t.pointerId;try{o.setPointerCapture(t.pointerId)}catch{}window.addEventListener("pointermove",this.onGestureMove);window.addEventListener("pointerup",this.onGestureEnd);window.addEventListener("pointercancel",this.onGestureCancel);window.addEventListener("keydown",this.onGestureKey,true)}endGesture(){window.removeEventListener("pointermove",this.onGestureMove);window.removeEventListener("pointerup",this.onGestureEnd);window.removeEventListener("pointercancel",this.onGestureCancel);window.removeEventListener("keydown",this.onGestureKey,true);this.gesture=null;this.gesturePointer=null;this.hint.set(null);this.into.set(null);this.busy.set(null);this.placing.set(null)}toMove(e){const t=this.store.form();if(!t)return;const o=e.name&&this.store.selected().includes(e.name)?this.store.selected():e.name?[e.name]:[];const i=this.store.placedByName();const r=o.filter(l=>!(ge(t,l)?.ancestors??[]).some(d=>o.includes(d)));const s=new Map(r.map(l=>[l,i.get(l)?.cells]).filter(l=>l[1]!==null&&l[1]!==void 0));if(!e.name||!s.has(e.name))return;const a=s.get(e.name);this.gesture={kind:"move",names:[...s.keys()],origin:s,primary:e.name,grab:{col:e.cell.col-a.col,row:e.cell.row-a.row},target:null};this.busy.set("move")}otherPointer(e){return this.gesturePointer!==null&&e.pointerId!==this.gesturePointer}onGestureMove=e=>{const t=this.gesture;if(!t||this.otherPointer(e))return;if(t.kind==="place"){if(!t.dragging){if(Math.hypot(e.clientX-t.startX,e.clientY-t.startY)<5)return;t.dragging=true;this.busy.set("move");this.placing.set(t.name)}const r=this.placeUnder(t.name,e.clientX,e.clientY);t.cells=r.cells;t.ok=r.ok;this.showPlace(r);return}if(t.kind==="press"){if(Math.hypot(e.clientX-t.startX,e.clientY-t.startY)<5)return;if(t.then==="move")this.toMove(t);else if(t.then==="select"){this.gesture={kind:"select",anchor:t.cell,was:t.was,cells:{...t.cell,colSpan:1,rowSpan:1}};this.busy.set("draw")}else{this.gesture={kind:"draw",list:t.list,limit:t.limit,growDown:t.list===null,anchor:t.cell,cells:{...t.cell,colSpan:1,rowSpan:1}};this.busy.set("draw")}}const o=this.gesture;const i=this.cellAt(e.clientX,e.clientY);if(!o||!i)return;if(o.kind==="move")this.moveTo(o,i);else if(o.kind==="draw")this.drawTo(o,i);else if(o.kind==="resize")this.stretchTo(o,i);else if(o.kind==="rows")this.rowsTo(o,i);else if(o.kind==="select")this.selectTo(o,i)};moveTo(e,t){const o=this.store.variant();const i=this.store.form();if(!o||!i)return;const r=e.origin.get(e.primary);const s=Cn([...e.origin.values()]);let a=t.col-e.grab.col-r.col;let l=t.row-e.grab.row-r.row;a=Math.max(1-s.col,Math.min(a,o.cols-(s.col+s.colSpan-1)));l=Math.max(1-s.row,l);const d={...s,col:s.col+a,row:s.row+l};const c=this.store.placedByName();const p=new Set(e.names.map(T=>c.get(T)?.parent??null));const h=new Set(e.names.flatMap(T=>ve(i).filter(k=>k.name===T||k.ancestors.includes(T)).map(k=>k.name)));const u=e.names.every(T=>{const k=c.get(T)?.parent;return k?W(c.get(k)?.element):false});let f=null;if(p.size===1&&!u)f=this.containerFor(d,h);else if(p.size===1)f=[...p][0];const m=[];let g=true;for(const T of e.names){const k=e.origin.get(T);const S={...k,col:k.col+a,row:k.row+l};const $=c.get(T);const A=p.size===1?f:$.parent;const R=A===null?Pe(o):c.get(A)?.cells??null;if(!R){g=false;continue}const j=A===null?S.col>=1&&S.col+S.colSpan-1<=o.cols&&S.row>=1:Ee(S,R);if(!j)g=false;if(!this.freeIn(A,S,$.layers,h))g=false;m.push({name:T,parent:A,cells:S})}const y=m.length===e.names.length&&m.every(T=>{const k=T.parent===null?Pe(o):c.get(T.parent)?.cells;return k!==void 0&&k!==null&&(T.parent===null?T.cells.col+T.cells.colSpan-1<=o.cols:Ee(T.cells,k))});e.target=y?{moves:m,box:d,ok:g,into:f}:null;e.tooBig=null;if(!g&&p.size===1&&!u){const T=this.store.placed().filter(S=>S.element.kind==="group"&&!W(S.element)&&S.cells&&!h.has(S.name)&&this.store.visible().has(S.name)&&Ee({...t,colSpan:1,rowSpan:1},S.cells)).sort((S,$)=>$.depth-S.depth)[0];const k=T?this.store.innerCells(T.name):null;if(T&&k&&T.name!==f&&(d.colSpan>k.colSpan||d.rowSpan>k.rowSpan))e.tooBig={group:T.name,inner:k}}const b=this.boxOf(d);this.hint.set(b?{box:b,ok:g&&y}:null);const x=f!==null?c.get(f)?.cells:null;this.into.set(x&&f!==c.get(e.primary)?.parent?this.boxOf(x):null)}drawTo(e,t){const o=fs(jl(e.anchor,t),e.limit,e.growDown);const i=e.growDown?o:fs(jl(e.anchor,{col:Math.min(Math.max(t.col,e.limit.col),e.limit.col+e.limit.colSpan-1),row:Math.min(Math.max(t.row,e.limit.row),e.limit.row+e.limit.rowSpan-1)}),e.limit);e.cells=i;const r=this.boxOf(i);this.hint.set(r?{box:r,ok:true,draw:true}:null)}selectTo(e,t){const o=this.store.variant();if(!o)return;e.cells=fs(jl(e.anchor,t),Pe(o),false);const i=this.boxOf(e.cells);this.hint.set(i?{box:i,ok:true,pick:true}:null)}stretchTo(e,t){const{start:o,bounds:i,edge:r}=e;let s=o.col;let a=o.col+o.colSpan-1;let l=o.row;let d=o.row+o.rowSpan-1;const c=i.col+i.colSpan-1;const p=e.growDown?_e:i.row+i.rowSpan-1;if(r.includes("e"))a=Math.max(s,Math.min(t.col,c));if(r.includes("w"))s=Math.min(a,Math.max(t.col,i.col));if(r.includes("s"))d=Math.max(l,Math.min(t.row,p));if(r.includes("n"))l=Math.min(d,Math.max(t.row,i.row));if(d-l+1<e.minRows){if(r.includes("n"))l=d-e.minRows+1;else d=l+e.minRows-1;this.store.say(au(e.name,e.minRows))}if(e.keep){const y=e.keep;s=Math.min(s,y.col);l=Math.min(l,y.row);a=Math.max(a,y.col+y.colSpan-1);d=Math.max(d,y.row+y.rowSpan-1)}const h={col:s,row:l,colSpan:a-s+1,rowSpan:d-l+1};e.cells=h;const u=this.boxOf(h);const f=e.name;const m=this.store.placedByName().get(f);const g=m?this.freeIn(m.parent,h,m.layers,/* @__PURE__ */new Set([f])):true;this.lastResizeOk=g;this.hint.set(u?{box:u,ok:g}:null)}rowsTo(e,t){const o=this.store.variant();if(!o)return;e.rows=Math.max(1,Math.min(_e,t.row));const i=this.boxOf({col:1,row:1,colSpan:o.cols,rowSpan:e.rows});this.hint.set(i?{box:i,ok:true,draw:true}:null)}onGestureEnd=e=>{if(this.otherPointer(e))return;const t=this.gesture;this.endGesture();if(!t)return;switch(t.kind){case"press":if(t.then==="select"){if(t.name!==null)this.store.toggle(t.name)}else if(t.name===null)this.store.select([]);else if(t.inner)this.store.select([t.inner]);else if(t.then==="draw")this.store.select([t.name]);else if(t.was.length>1&&t.was.includes(t.name))this.store.select([t.name]);this.here();return;case"move":if(t.target?.ok)this.store.moveElements(t.target.moves);else if(t.tooBig){const{group:o,inner:i}=t.tooBig;const r=t.target?.box;const s=t.names.length===1?`"${t.names[0]}"`:"What is selected";const a=r&&r.colSpan>i.colSpan?`${r.colSpan} columns wide, and the inside of "${o}" has ${i.colSpan}`:`${r?.rowSpan??""} rows high, and the inside of "${o}" has ${i.rowSpan}`;this.store.warn(`${s} does not fit into "${o}": it is ${a}. Make it smaller first (Shift and the arrows), or the group larger.`,"form-editor:taken")}else if(t.target)this.store.warn("Those cells are taken by an element that is shown together with it: drop it where the frame is green.","form-editor:taken");return;case"resize":if(t.cells&&this.lastResizeOk)this.store.resize(t.name,t.cells);else if(t.cells&&!this.lastResizeOk)this.store.warn("Those cells are taken by an element that is shown together with it.","form-editor:taken");return;case"draw":{const o=this.boxOf(t.cells);this.hint.set(o?{box:o,ok:true,draw:true}:null);this.pending=t.cells;const i=this.popup.open(I1(this.store,t.list,t.cells),{at:e});void i.closed.then(()=>{if(this.gesture===null&&this.pending===t.cells){this.hint.set(null);this.pending=null}});return}case"rows":this.store.setRows(t.rows);return;case"select":this.store.addToSelection(this.store.elementsIn(t.cells));this.here();return;case"place":if(t.dragging)this.dropPlace(t.name,t);return}};onGestureCancel=e=>{if(!this.otherPointer(e))this.endGesture()};onGestureKey=e=>{if(e.key!=="Escape")return;e.preventDefault();e.stopPropagation();this.endGesture()};trackAnchor=null;onTrackPress(e,t,o){if(e.button!==0)return;e.preventDefault();e.stopPropagation();this.stageRef().nativeElement.focus({preventScroll:true});const i=this.store.track();const r=i!==null&&i.axis===t;const s=(c,p)=>Array.from({length:Math.abs(p-c)+1},(h,u)=>Math.min(c,p)+u);if(e.shiftKey&&r&&this.trackAnchor?.axis===t){this.store.selectTrack({axis:t,indices:s(this.trackAnchor.n,o)});return}if((e.ctrlKey||e.metaKey)&&r){const c=i.indices.includes(o)?i.indices.filter(p=>p!==o):[...i.indices,o].sort((p,h)=>p-h);this.store.selectTrack(c.length?{axis:t,indices:c}:null);this.trackAnchor={axis:t,n:o};return}this.trackAnchor={axis:t,n:o};if(r&&i.indices.length===1&&i.indices[0]===o){this.store.selectTrack(null);return}this.store.selectTrack({axis:t,indices:[o]});const a=this.stageRef().nativeElement.ownerDocument;const l=c=>{const p=a.elementFromPoint(c.clientX,c.clientY)?.closest(`.num[data-axis="${t}"]`);const h=p?Number(p.dataset["n"]):NaN;if(Number.isInteger(h))this.store.selectTrack({axis:t,indices:s(o,h)})};const d=()=>{a.removeEventListener("pointermove",l);a.removeEventListener("pointerup",d);a.removeEventListener("pointercancel",d)};a.addEventListener("pointermove",l);a.addEventListener("pointerup",d);a.addEventListener("pointercancel",d)}onTrackMenu(e,t,o){e.preventDefault();e.stopPropagation();this.popup.open(D1(this.store,t,o),{at:e})}onContextMenu(e){e.preventDefault();const t=this.nameAt(e.target);const o=this.cellAt(e.clientX,e.clientY);if(t){const i=this.store.placedByName().get(t);if(i?.element.kind==="group"&&o){const r=W(i.element)?this.store.shownPageOf(t):t;const s=this.store.placed().some(l=>l.parent===r&&l.cells&&this.store.visible().has(l.name)&&Ee({...o,colSpan:1,rowSpan:1},l.cells));const a=r?this.store.innerCells(r):null;if(r&&a&&!s&&Ee({...o,colSpan:1,rowSpan:1},a)&&!this.store.selected().includes(t)){this.popup.open([...oc(this.store,r,o),{separator:true},{label:`The group "${t}"`,children:Ds(this.store,t)}],{at:e});return}}this.popup.open(Ds(this.store,t),{at:e});return}if(o)this.popup.open(oc(this.store,null,o),{at:e})}openMenuFromKeys(){const e=this.store.selected()[0];const t=e?this.stageRef().nativeElement.querySelector(".sel"):null;const o=(t??this.pageRef().nativeElement).getBoundingClientRect();this.popup.open(e?Ds(this.store,e):oc(this.store,null,{col:1,row:1}),{at:{x:o.left+8,y:o.top+8},keyboard:true})}onStageMenu(e){if(e.target===e.currentTarget)e.preventDefault()}onDoubleClick(e){const t=document.elementFromPoint(e.clientX,e.clientY);const o=t?.closest("[data-page]")?.getAttribute("data-page");const i=o&&this.store.placedByName().has(o)?o:this.nameAt(t);const r=i?this.store.placedByName().get(i):void 0;if(!i||!r||this.store.tabOrderMode())return;if(r.element.kind==="subform"){this.store.openSubform(i);return}this.store.select([i]);this.store.editInPlace(i,z1(r.element))}editValue(e){const t=e.placed.element;if(this.store.editingCaption()&&t.kind==="input")return typeof t.preview?.props?.["label"]==="string"?t.preview.props["label"]:"";if(t.kind==="static")return dn(t.text)?`=${t.text.$expr}`:typeof t.text==="string"?t.text:"";if(t.kind==="group"&&!W(t))return dn(t.title)?`=${t.title.$expr}`:typeof t.title==="string"?t.title:"";return t.name}onEditKey(e){e.stopPropagation();if(e.key==="Enter"){e.preventDefault();e.target.blur()}else if(e.key==="Escape"){e.preventDefault();this.store.editingCaption.set(false);this.store.editingText.set(null);this.stageRef().nativeElement.focus({preventScroll:true})}}commitEdit(e,t){if(this.store.editingText()!==e)return;const o=t.target.value;this.store.editingText.set(null);const i=this.store.placedByName().get(e);if(!i)return;const r=i.element;const s=this.store.editingCaption()&&r.kind==="input";const a=s||r.kind==="static"||r.kind==="group"&&!W(r)?this.editValue({placed:i}):r.name;this.store.editingCaption.set(false);if(o!==a){if(s)this.store.setCaption(e,o);else if(r.kind==="static"||r.kind==="group"&&!W(r))this.store.setText(e,o);else this.store.rename(e,o)}const l=t.relatedTarget;if(!(l instanceof Element)||this.stageRef().nativeElement.contains(l))this.stageRef().nativeElement.focus({preventScroll:true})}shownKey="";scrollToSelection(){const e=this.stageRef().nativeElement;const t=Array.from(e.querySelectorAll(".sel"));if(t.length===0)return;const o=e.getBoundingClientRect();const i=t.map(u=>u.getBoundingClientRect());const r=Math.min(...i.map(u=>u.top));const s=Math.max(...i.map(u=>u.bottom));const a=Math.min(...i.map(u=>u.left));const l=Math.max(...i.map(u=>u.right));const d=12;const c={top:o.top+28,left:o.left+34,bottom:o.top+e.clientHeight,right:o.left+e.clientWidth};let p=0;if(r<c.top)p=r-c.top-d;else if(s>c.bottom)p=Math.min(s-c.bottom+d,r-c.top-d);let h=0;if(a<c.left)h=a-c.left-d;else if(l>c.right)h=Math.min(l-c.right+d,a-c.left-d);if(h!==0||p!==0)e.scrollBy({left:h,top:p})}onDragOver(e){if(!(e.dataTransfer?.types??[]).includes(ec))return;e.preventDefault();if(e.dataTransfer)e.dataTransfer.dropEffect="copy";const t=this.cellAt(e.clientX,e.clientY);const o=this.store.dragTool();if(!t||!o)return;const i=this.containerFor({...t,colSpan:1,rowSpan:1});const r=this.store.toolRoom(o,i,t)?.cells??null;const s=i?this.store.placedByName().get(i)?.cells:null;this.into.set(s?this.boxOf(s):null);const a=r?this.boxOf(r):null;this.hint.set(a?{box:a,ok:true}:null)}onDragLeave(e){const t=e.relatedTarget;if(!(t instanceof Node)||!this.pageRef().nativeElement.contains(t)){this.hint.set(null);this.into.set(null)}}startPlace(e,t){if(e.button!==0)return;e.preventDefault();this.begin({kind:"place",name:t,startX:e.clientX,startY:e.clientY,dragging:false,cells:null,ok:false},e,e.currentTarget)}placeUnder(e,t,o){const i=this.pageRef().nativeElement.getBoundingClientRect();const r=t>=i.left&&t<=i.right&&o>=i.top&&o<=i.bottom;const s=r?this.cellAt(t,o):null;const a=this.store.placedByName().get(e);const l=s&&a?this.store.unplacedCells(e,s):null;return{cells:l,ok:l!==null&&a!==void 0&&this.freeIn(a.parent,l,a.layers,/* @__PURE__ */new Set([e]))}}showPlace(e){const t=e.cells?this.boxOf(e.cells):null;this.hint.set(t?{box:t,ok:e.ok}:null)}dropPlace(e,t){if(!t.cells)return;if(!t.ok){this.store.warn("Those cells are taken by an element that is shown together with it: drop it where the frame is green.","form-editor:taken");return}this.store.placeAt(e,t.cells);this.store.select([e]);this.here();this.stageRef().nativeElement.focus({preventScroll:true})}outlinePlace=null;onDrop(e){const t=e.dataTransfer;this.hint.set(null);this.into.set(null);const o=this.cellAt(e.clientX,e.clientY);if(!t||!o)return;const i=t.getData(ec);if(i&&Rv(i)){e.preventDefault();this.store.dragTool.set(null);const r=this.containerFor({...o,colSpan:1,rowSpan:1});const s=()=>this.stageRef().nativeElement.focus({preventScroll:true});if(i==="subform"&&this.store.subformTargets().length>1){this.popup.open([{header:true,label:"The form the subform places"},...this.store.subformTargets().map(a=>({label:a,icon:"fme:form",run:()=>{this.store.addToolAtCell("subform",r,o,a);s()}}))],{at:e});return}this.store.addToolAtCell(i,r,o);s()}}onKeydown(e){if(e.target instanceof Element&&e.target!==e.currentTarget&&e.target.closest("input, textarea, select, button, a[href], [contenteditable], [role=\"button\"]"))return;if(this.store.editingText()!==null){if(this.editRef())return;this.store.editingCaption.set(false);this.store.editingText.set(null)}const t=e.ctrlKey||e.metaKey;const o=e.key;const i={ArrowLeft:[-1,0],ArrowRight:[1,0],ArrowUp:[0,-1],ArrowDown:[0,1]};const r=i[o];const s=this.store.selected();if(o==="Escape"){if(this.store.tabOrderMode())this.store.setTabOrderMode(false);else if(s.length){const a=this.store.placedByName().get(s[0])?.parent??null;this.store.select(a&&s.length===1?[a]:[])}else if(this.store.track())this.store.selectTrack(null);else if(this.store.openedFrom())this.store.back();else return}else if(r&&t&&!e.altKey&&!e.shiftKey){if(!this.store.capabilities().align){this.store.say("Ctrl and an arrow line up the selected elements with the first of them: select it first, then the others (Ctrl and a click, or Shift and a drag).")}else this.store.alignSelected(o==="ArrowLeft"?"left":o==="ArrowRight"?"right":o==="ArrowUp"?"top":"bottom")}else if(r&&e.altKey){if(r[1]!==0)this.store.reorderSelected(r[1])}else if(r&&e.shiftKey){this.store.growSelected(r[0],r[1])}else if(r){if(!s.length)return;this.store.nudgeSelected(r[0],r[1])}else if(o==="Delete"||o==="Backspace"){if(e.shiftKey)this.store.unplaceSelected();else this.store.removeSelected()}else if(t&&o.toLowerCase()==="d"){this.store.duplicateSelected()}else if(t&&o.toLowerCase()==="c"){this.store.copySelected()}else if(t&&o.toLowerCase()==="x"){this.store.cutSelected()}else if(t&&o.toLowerCase()==="v"){this.store.paste()}else if(t&&o.toLowerCase()==="a"){this.store.selectAll()}else if(o==="F2"||o==="Enter"){const a=this.store.textTarget();if(!a)return;this.store.editInPlace(a)}else if((o==="ContextMenu"||o==="F10"&&e.shiftKey)&&!t&&!e.altKey){this.openMenuFromKeys()}else return;e.preventDefault()}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:ir,deps:[],target:w.ɵɵFactoryTarget.Component});static ɵcmp=w.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"21.2.21",type:ir,isStandalone:true,selector:"fme-canvas",viewQueries:[{propertyName:"stageRef",first:true,predicate:["stage"],descendants:true,isSignal:true},{propertyName:"pageRef",first:true,predicate:["page"],descendants:true,isSignal:true},{propertyName:"gridRef",first:true,predicate:["grid"],descendants:true,isSignal:true},{propertyName:"editRef",first:true,predicate:["edit"],descendants:true,isSignal:true}],ngImport:w,template:`
1124
+ <!-- two rows, so the bar does not wrap when the Editor and the Preview stand side by side: the variants and their layers above, what changes the selection and the view under them -->
1125
+ <div class="tb upper">
1126
+ @if (store.openedFrom(); as from) {
1127
+ <gfy-button appearance="flat" icon="fme:back" [label]="from.form" [tooltip]="'Back to the form ' + from.form + ' (the subform ' + from.name + ' places this form; Escape)'" (pressed)="store.back()" />
1128
+ <span class="sep" aria-hidden="true"></span>
1129
+ }
1130
+ <gfy-toggle-group [options]="variantOptions()" [value]="variantKey()" (valueChange)="onVariant($event)" ariaLabel="The variant that is edited" />
1131
+ <gfy-dropdown-button appearance="flat" iconOnly icon="fme:add-variant" label="Add a variant" [items]="variantItems()" />
1132
+ <span class="range">{{ rangeText() }}</span>
1133
+ <span class="sp"></span>
1134
+ @for (group of layerGroups(); track group.name) {
1135
+ @if (!$first) {
1136
+ <span class="sep" aria-hidden="true"></span>
1137
+ }
1138
+ <span class="label">{{ group.name }}</span>
1139
+ <gfy-toggle-group [options]="group.options" [value]="group.value" (valueChange)="onLayer(group.name, $event)" [ariaLabel]="'The layer of ' + group.name + ' that is shown'" />
1140
+ }
1141
+ <gfy-dropdown-button appearance="flat" icon="fme:layers" [label]="newLayerLabel()" [items]="newLayerItems()" />
1142
+ </div>
1143
+ <div class="tb">
1144
+ <span class="aligns" role="group" aria-label="Line up with the first selected element">
1145
+ @for (command of alignCommands; track command.how) {
1146
+ @if (command.how === 'top') {
1147
+ <span class="sep" aria-hidden="true"></span>
1148
+ }
1149
+ @if (command.how !== 'size') {
1150
+ <gfy-button appearance="flat" iconOnly [icon]="command.icon" [label]="command.text" [tooltip]="alignTip(command)" [disabled]="!store.capabilities().align" (pressed)="store.alignSelected(command.how)" />
1151
+ }
1152
+ }
1153
+ </span>
1154
+ @if (store.capabilities().align) {
1155
+ <span class="range" title="The first selected element: the others are lined up with it">to {{ store.selected()[0] }}</span>
1156
+ }
1157
+ <span class="sp"></span>
1158
+ <span class="widths" role="group" aria-label="The width the form is drawn at">
1159
+ <gfy-button toggle appearance="flat" label="Fit" tooltip="As wide as the window lets it be, within the widths of the variant" [checked]="store.designWidth() === null" (checkedChange)="onFit($event)" />
1160
+ <gfy-slider ariaLabel="The width of the form in the Editor" [min]="slideRange().min" [max]="slideRange().max" [value]="width()" [valueText]="pxText" (valueChange)="onSlide($event)" />
1161
+ <span class="range px">{{ width() }} px</span>
1162
+ </span>
1163
+ <span class="sep" aria-hidden="true"></span>
1164
+ <gfy-button toggle appearance="flat" iconOnly icon="fme:editor" label="Lines of the cells" [checked]="store.view().showGrid" (checkedChange)="store.setShowGrid($event)" />
1165
+ <gfy-button toggle appearance="flat" iconOnly icon="fme:tab-order" label="Set the order of the page (click the elements one after another)" [checked]="store.tabOrderMode()" (checkedChange)="store.setTabOrderMode($event)" />
1166
+ </div>
1167
+ <div #stage class="stage" tabindex="0" role="application" aria-label="The grid of the form" (keydown)="onKeydown($event)" (pointerdown)="onStagePress($event)" (contextmenu)="onStageMenu($event)">
1168
+ <div class="board">
1169
+ <div class="colhead">
1170
+ <div class="nums" aria-hidden="true" [style.left.px]="0" [style.top.px]="2" [style.height.px]="20">
1171
+ @for (col of colNums(); track col.n) {
1172
+ <div
1173
+ class="num"
1174
+ data-axis="col"
1175
+ [attr.data-n]="col.n"
1176
+ [class.on]="isTrack('col', col.n)"
1177
+ [class.sized]="col.sized"
1178
+ [class.bare]="!col.label"
1179
+ [style.left.px]="col.x"
1180
+ [style.width.px]="col.size"
1181
+ [style.height.px]="20"
1182
+ [attr.title]="col.title"
1183
+ (pointerdown)="onTrackPress($event, 'col', col.n)"
1184
+ (contextmenu)="onTrackMenu($event, 'col', col.n)">
1185
+ {{ col.label }}
1186
+ </div>
1187
+ }
1188
+ </div>
1189
+ </div>
1190
+ <div class="nums" aria-hidden="true" [style.left.px]="4" [style.top.px]="28" [style.width.px]="26">
1191
+ @for (row of rowNums(); track row.n) {
1192
+ <div
1193
+ class="num"
1194
+ data-axis="row"
1195
+ [attr.data-n]="row.n"
1196
+ [class.on]="isTrack('row', row.n)"
1197
+ [class.sized]="row.sized"
1198
+ [class.bare]="!row.label"
1199
+ [style.top.px]="row.y"
1200
+ [style.height.px]="row.size"
1201
+ [style.width.px]="26"
1202
+ [attr.title]="row.title"
1203
+ (pointerdown)="onTrackPress($event, 'row', row.n)"
1204
+ (contextmenu)="onTrackMenu($event, 'row', row.n)">
1205
+ {{ row.label }}
1206
+ </div>
1207
+ }
1208
+ </div>
1209
+ <div
1210
+ #page
1211
+ class="page"
1212
+ [class.busy]="busy() === 'move'"
1213
+ [class.drawing]="busy() === 'draw'"
1214
+ [class.ordering]="store.tabOrderMode()"
1215
+ [style.width]="'calc(' + width() + 'px + var(--_gx))'"
1216
+ [style.--_layout-gx]="spacingX()"
1217
+ [style.--_layout-gy]="spacingY()"
1218
+ [style.--_division]="store.division()"
1219
+ (pointerdown)="onPress($event)"
1220
+ (dblclick)="onDoubleClick($event)"
1221
+ (contextmenu)="onContextMenu($event)"
1222
+ (dragover)="onDragOver($event)"
1223
+ (dragleave)="onDragLeave($event)"
1224
+ (drop)="onDrop($event)">
1225
+ <div #grid class="grid" [style.grid-template-columns]="columns()" [style.grid-template-rows]="rows()">
1226
+ @if (store.view().showGrid) {
1227
+ @for (n of colLines(); track n) {
1228
+ <div class="vline" [class.major]="n % 6 === 0" [style.grid-column]="n"></div>
1229
+ }
1230
+ @for (n of rowLines(); track n) {
1231
+ <div class="hline" [class.major]="n % (store.division() * 2) === 0" [style.grid-row]="n"></div>
1232
+ }
1233
+ }
1234
+ <!-- the elements of the form, then those of its subforms over their places (ghost: faint, not to be pointed at) -->
1235
+ @for (item of pictured(); track item.key) {
1236
+ <div
1237
+ class="area"
1238
+ [class]="
1239
+ 'area k-' +
1240
+ item.kind +
1241
+ (item.ghost ? ' ghost' : '') +
1242
+ (item.content ? ' content' : '') +
1243
+ (item.page ? ' page-of-sheet' : '') +
1244
+ (item.problem ? ' problem-' + item.problem : '') +
1245
+ (item.align === 'stretch' ? ' stretch' : '')
1246
+ "
1247
+ [class.ordered]="item.order !== '' && store.tabOrdered().has(item.name)"
1248
+ [class.overflow]="!item.ghost && overflow().has(item.name)"
1249
+ [attr.data-name]="item.ghost ? null : item.name"
1250
+ [attr.title]="item.ghost ? null : titleOf(item)"
1251
+ [style.grid-area]="item.area"
1252
+ [style.z-index]="!item.ghost && store.editingText() === item.name ? 100 : item.z"
1253
+ [style.--_align]="item.align"
1254
+ [style.--_justify]="item.justify">
1255
+ @switch (item.kind) {
1256
+ @case ('static') {
1257
+ @if (item.appearance === 'separator') {
1258
+ <!-- a line across the place, with the text on it -->
1259
+ <span class="sepline">
1260
+ <span class="ln"></span>
1261
+ @if (item.text) {
1262
+ <span class="lt">
1263
+ @if (item.code) {
1264
+ <span class="code" title="Code of the application: the text is what the code gives (the Editor shows the first text in it)">ƒ</span>
1265
+ }
1266
+ {{ item.text }}</span
1267
+ ><span class="ln"></span>
1268
+ }
1269
+ </span>
1270
+ } @else {
1271
+ <span class="txt" [class]="'txt ' + item.appearance">
1272
+ @if (item.code) {
1273
+ <span class="code" title="Code of the application: the text is what the code gives (the Editor shows the first text in it)">ƒ</span>
1274
+ }
1275
+ {{ item.text || '(empty text)' }}
1276
+ </span>
1277
+ }
1278
+ }
1279
+ @case ('input') {
1280
+ @if (item.own) {
1281
+ <!-- a component of the application: a box with its tag -->
1282
+ <span class="own"
1283
+ ><span class="otag">&lt;{{ item.as }}&gt;</span><span class="nm">{{ item.name }}</span></span
1284
+ >
1285
+ } @else {
1286
+ @switch (item.as) {
1287
+ @case ('gfy-button') {
1288
+ <span class="fld button" [attr.data-variant]="item.variant || null">
1289
+ @if (item.icon) {
1290
+ <span class="ic" [gfyIcon]="item.icon"></span>
1291
+ }
1292
+ <span class="cut">{{ item.text || item.name }}</span></span
1293
+ >
1294
+ }
1295
+ @case ('gfy-split-button') {
1296
+ <!-- the button and the arrow that opens its menu, behind a line -->
1297
+ <span class="fld button split" [attr.data-variant]="item.variant || null"
1298
+ ><span class="main">
1299
+ @if (item.icon) {
1300
+ <span class="ic" [gfyIcon]="item.icon"></span>
1301
+ }
1302
+ <span class="cut">{{ item.text || item.name }}</span></span
1303
+ ><span class="arrow"><span class="ic caret" gfyIcon="gfy:chevron-down"></span></span
1304
+ ></span>
1305
+ }
1306
+ @case ('gfy-dropdown-button') {
1307
+ <span class="fld button" [attr.data-variant]="item.variant || null">
1308
+ @if (item.icon) {
1309
+ <span class="ic" [gfyIcon]="item.icon"></span>
1310
+ }
1311
+ <span class="cut">{{ item.text || item.name }}</span
1312
+ ><span class="ic caret" gfyIcon="gfy:chevron-down"></span
1313
+ ></span>
1314
+ }
1315
+ @case ('gfy-checkbox') {
1316
+ <span class="fld bare"
1317
+ ><span class="glyph"></span><span class="cut">{{ item.text || item.name }}</span></span
1318
+ >
1319
+ }
1320
+ @case ('gfy-switch') {
1321
+ <span class="fld bare"
1322
+ ><span class="glyph switch"></span><span class="cut">{{ item.text || item.name }}</span></span
1323
+ >
1324
+ }
1325
+ @case ('gfy-radio-group') {
1326
+ <!-- the options as gfy-radio-group lays them out: one under another, or side by side and into the next line where the place is too narrow -->
1327
+ <span class="radios" [class.vertical]="item.vertical">
1328
+ @for (option of item.options; track $index) {
1329
+ <span class="radio"
1330
+ ><span class="glyph round"></span><span class="rt">{{ option }}</span></span
1331
+ >
1332
+ }
1333
+ @if (item.options.length === 0) {
1334
+ <span class="radio"
1335
+ ><span class="glyph round"></span><span class="nm">{{ item.name }}</span></span
1336
+ >
1337
+ }
1338
+ </span>
1339
+ }
1340
+ @case ('gfy-label') {
1341
+ <span class="txt label">{{ item.text || item.name }}</span>
1342
+ }
1343
+ @case ('gfy-slider') {
1344
+ <span class="fld bare slider"><span class="track"></span><span class="knob"></span></span>
1345
+ }
1346
+ @case ('gfy-toggle-group') {
1347
+ <span class="fld bare seg">
1348
+ @for (option of item.options; track $index) {
1349
+ <span class="segment" [class.on]="$first">{{ option }}</span>
1350
+ }
1351
+ </span>
1352
+ }
1353
+ @case ('gfy-file-upload') {
1354
+ @if (item.upload === 'row') {
1355
+ <span class="fld"
1356
+ ><span class="nm">{{ item.name }}</span
1357
+ ><span class="browse">Browse…</span></span
1358
+ >
1359
+ } @else {
1360
+ <span class="drop" [class]="'drop ' + item.upload"
1361
+ ><span class="up" aria-hidden="true">⇪</span><span class="nm">{{ item.name }}</span></span
1362
+ >
1363
+ }
1364
+ }
1365
+ @case ('gfy-picture') {
1366
+ <span class="pic">
1367
+ <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M21 19V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2M8.5 13.5l2.5 3 3.5-4.5 4.5 6H5z" /></svg>
1368
+ <span class="nm">{{ item.name }}</span>
1369
+ </span>
1370
+ }
1371
+ @case ('gfy-picture-gallery') {
1372
+ <span class="pic gallery">
1373
+ <span class="frame"
1374
+ ><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M21 19V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2M8.5 13.5l2.5 3 3.5-4.5 4.5 6H5z" /></svg
1375
+ ></span>
1376
+ <span class="thumbs"><i></i><i></i><i></i><i></i></span>
1377
+ <span class="nm">{{ item.name }}</span>
1378
+ </span>
1379
+ }
1380
+ @case ('gfy-digital-display') {
1381
+ <span class="lcd" [style.font-size.px]="item.digitSize * 1.1">{{ item.digits }}</span>
1382
+ }
1383
+ @default {
1384
+ <span class="fld" [class.tall]="item.as === 'gfy-textarea'">
1385
+ @if (item.as === 'gfy-color-picker') {
1386
+ <span class="swatch"></span>
1387
+ }
1388
+ <span class="nm">{{ item.name }}</span>
1389
+ @if (item.tag) {
1390
+ <span class="tag">{{ item.tag }}</span>
1391
+ }
1392
+ @if (item.as === 'gfy-select' || item.as === 'gfy-combobox' || item.as === 'gfy-multi-select') {
1393
+ <span class="chev">▾</span>
1394
+ }
1395
+ </span>
1396
+ }
1397
+ }
1398
+ }
1399
+ }
1400
+ @case ('group') {
1401
+ @if (item.look === 'property-sheet' && !item.page) {
1402
+ <!-- the tabs lie in the edge cells of the sheet, the frame under them (or beside them) -->
1403
+ <div class="sheet" [class]="'sheet ' + item.tabSide">
1404
+ <div class="tabs">
1405
+ @for (tab of item.tabs; track tab.name) {
1406
+ <span class="tab" [class.on]="tab.on" [attr.data-page]="item.ghost ? null : tab.name" [attr.data-sheet]="item.name" [attr.title]="'Show the page ' + tab.name"
1407
+ ><span class="tt">{{ tab.title }}</span></span
1408
+ >
1409
+ }
1410
+ @if (item.tabs.length === 0) {
1411
+ <span class="tab none"><span class="tt">no pages</span></span>
1412
+ }
1413
+ </div>
1414
+ <div class="body"></div>
1415
+ </div>
1416
+ } @else if (item.look === 'group-box' && !item.page) {
1417
+ <gfy-group-box class="gbox" aria-hidden="true" fill [hover]="false" [heading]="item.text" />
1418
+ } @else {
1419
+ <div class="gbox"></div>
1420
+ }
1421
+ @if (!item.page && (item.look !== 'group-box' || !item.text)) {
1422
+ <span class="tagline">{{ item.name }}</span>
1423
+ }
1424
+ }
1425
+ @case ('subform') {
1426
+ <div class="sub">
1427
+ <span class="tagline">{{ item.name }} → {{ item.sub }}{{ item.more ? ' (+' + item.more + (item.more === 1 ? ' row' : ' rows') + ' under it)' : '' }}</span>
1428
+ </div>
1429
+ }
1430
+ }
1431
+ @if (item.repeat) {
1432
+ <span class="badge repeat" title="The place holds one instance; the application says how many">×N</span>
1433
+ }
1434
+ @if (item.flow) {
1435
+ <span class="badge flow" title="The subform adds the rows it needs under its place">↧</span>
1436
+ }
1437
+ @if (item.order) {
1438
+ <span class="badge order" [class.done]="store.tabOrdered().has(item.name)">{{ item.order }}</span>
1439
+ }
1440
+ @if (!item.ghost && overflow().get(item.name); as over) {
1441
+ <span class="badge overflow">{{ over.top || over.bottom ? '↕' : '↔' }}</span>
1442
+ }
1443
+ @if (!item.ghost && store.editingText() === item.name) {
1444
+ <input
1445
+ #edit
1446
+ class="edit"
1447
+ [class.toward-left]="editTowardLeft()"
1448
+ [class.line]="item.kind === 'group' || item.kind === 'subform'"
1449
+ [value]="editValue(item)"
1450
+ (keydown)="onEditKey($event)"
1451
+ (blur)="commitEdit(item.name, $event)"
1452
+ (pointerdown)="$event.stopPropagation()" />
1453
+ }
1454
+ </div>
1455
+ }
1456
+ </div>
1457
+ <div class="overlay">
1458
+ @if (store.form()?.elements?.length === 0) {
1459
+ <div class="empty-form">The form is empty. Drag a tool from the Toolbox onto the grid, or draw an area with the mouse and choose what goes there.</div>
1460
+ }
1461
+ @if (into(); as box) {
1462
+ <div class="into" [style.left.px]="box.x" [style.top.px]="box.y" [style.width.px]="box.width" [style.height.px]="box.height"></div>
1463
+ }
1464
+ @for (frame of frames(); track frame.name) {
1465
+ <div
1466
+ class="sel"
1467
+ [class.many]="frames().length > 1"
1468
+ [class.first]="frames().length > 1 && frame.name === store.selected()[0]"
1469
+ [style.left.px]="frame.box.x"
1470
+ [style.top.px]="frame.box.y"
1471
+ [style.width.px]="frame.box.width"
1472
+ [style.height.px]="frame.box.height">
1473
+ @if (frames().length > 1 && frame.name === store.selected()[0]) {
1474
+ <span class="first-mark" title="The first selected element: the others are lined up with it"></span>
1475
+ }
1476
+ @if (frames().length === 1 && !store.tabOrderMode()) {
1477
+ @for (edge of edges; track edge) {
1478
+ <span [class]="'handle ' + edge" (pointerdown)="startResize($event, edge, frame.name)"></span>
1479
+ }
1480
+ @if (frame.group) {
1481
+ <span class="grip" [class.inside]="frame.inside" title="Drag to move the group with what is in it" (pointerdown)="startMove($event, frame.name)"
1482
+ ><span class="ic" style="--ic: 10px" gfyIcon="fme:width"></span>{{ frame.name }}</span
1483
+ >
1484
+ }
1485
+ }
1486
+ </div>
1487
+ }
1488
+ @if (hint(); as cue) {
1489
+ <div class="cue" [class.bad]="!cue.ok" [class.draw]="cue.draw" [class.pick]="cue.pick" [style.left.px]="cue.box.x" [style.top.px]="cue.box.y" [style.width.px]="cue.box.width" [style.height.px]="cue.box.height">
1490
+ <span class="size">{{ hintSize() }}</span>
1491
+ </div>
1492
+ }
1493
+ </div>
1494
+ </div>
1495
+ <div class="rows-grip" [style.width.px]="gridWidth()" title="Drag to give the grid more rows or fewer" (pointerdown)="startRows($event)"></div>
1496
+ </div>
1497
+ @if (store.unplaced().length) {
1498
+ <div class="tray" (pointerdown)="$event.stopPropagation()">
1499
+ <span>Not placed in this variant (drag onto the grid):</span>
1500
+ @for (entry of store.unplaced(); track entry.name) {
1501
+ <span
1502
+ class="chip"
1503
+ [class]="'chip k-' + entry.element.kind"
1504
+ [class.dragged]="placing() === entry.name"
1505
+ role="button"
1506
+ tabindex="0"
1507
+ [attr.title]="'Drag ' + entry.name + ' onto its cells, or double-click it (Enter) to place it in the first free cells'"
1508
+ (pointerdown)="startPlace($event, entry.name)"
1509
+ (dblclick)="placeChip(entry.name)"
1510
+ (keydown.enter)="$event.preventDefault(); placeChip(entry.name)"
1511
+ (keydown.space)="$event.preventDefault(); placeChip(entry.name)"
1512
+ >{{ entry.name }}</span
1513
+ >
1514
+ }
1515
+ <gfy-button appearance="flat" icon="fme:place" label="Place all" (pressed)="placeAll()" />
1516
+ </div>
1517
+ }
1518
+ <div class="help">
1519
+ {{ helpText() }}
1520
+ </div>
1521
+ </div>
1522
+ `,isInline:true,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n",".ic{flex:none;display:grid;width:var(--ic, 14px);height:var(--ic, 14px)}\n",":host{--paper: var(--gfy-bg-document, var(--gfy-bg-main, #fff));--k-static: #8b5cf6;--k-input: #2f80ed;--k-group: #1f9d55;--k-subform: #e07b00;--k-content: #0d9488;--sel: var(--gfy-accent, #3a8fd6)}.tb .label{font-size:12px;opacity:.88;margin-left:2px}.tb.upper{border-bottom:0;padding-bottom:0}.tb .aligns,.tb .widths{display:inline-flex;align-items:center;gap:2px}.tb .widths gfy-slider{--gfy-slider-width: 140px;margin:0 4px}.tb .px{min-width:52px;text-align:end;font-variant-numeric:tabular-nums}.stage{flex:1 1 auto;min-height:0;overflow:auto;outline:none;background:color-mix(in srgb,var(--gfy-text-main, #333) 4%,var(--gfy-bg-panel, var(--gfy-bg-main)))}.stage:focus-visible .page{box-shadow:0 0 0 2px color-mix(in srgb,var(--sel) 45%,transparent)}.board{position:relative;display:inline-block;padding:0 24px 12px 34px;min-width:calc(100% - 58px)}.colhead{position:sticky;top:0;z-index:3;height:22px;margin-bottom:6px;background:color-mix(in srgb,var(--gfy-text-main, #333) 4%,var(--gfy-bg-panel, var(--gfy-bg-main)))}.page{--_gx: var(--_layout-gx, var(--gfy-form-spacing-x, 8px));--_gy: var(--_layout-gy, var(--gfy-form-spacing-y, 8px));--_row: calc((var(--gfy-control-height, 28px) + var(--_gy)) / var(--_division, 2));position:relative;background:var(--paper);color:var(--gfy-text-main);font-size:var(--gfy-font-size, 13px);box-shadow:0 0 0 1px var(--gfy-border-color, rgba(128, 128, 128, .35));-webkit-user-select:none;user-select:none;touch-action:none}.page.busy,.page.busy *{cursor:grabbing!important}.page.drawing,.page.drawing *{cursor:crosshair!important}.page.ordering .area{cursor:pointer}.grid{position:relative;isolation:isolate;display:grid;overflow-x:clip;cursor:crosshair}.vline,.hline{pointer-events:none;box-sizing:border-box}.vline{grid-row:1/-1;border-right:1px dotted color-mix(in srgb,var(--gfy-text-main, #333) 16%,transparent)}.hline{grid-column:1/-1;border-bottom:1px dotted color-mix(in srgb,var(--gfy-text-main, #333) 16%,transparent)}.vline.major{border-right-style:solid;border-right-color:color-mix(in srgb,var(--gfy-text-main, #333) 22%,transparent)}.hline.major{border-bottom-style:solid;border-bottom-color:color-mix(in srgb,var(--gfy-text-main, #333) 22%,transparent)}.area{--k: var(--k-input);position:relative;display:grid;grid-template-rows:minmax(0,1fr);box-sizing:border-box;min-width:0;min-height:0;padding:calc(var(--_gy) / 2) calc(var(--_gx) / 2);align-items:var(--_align, center);justify-items:var(--_justify, stretch);border-radius:3px;background:color-mix(in srgb,var(--k) 9%,transparent);outline:1px solid color-mix(in srgb,var(--k) 30%,transparent);outline-offset:-1px;cursor:grab}.area.k-static{--k: var(--k-static)}.area.content{--k: var(--k-content)}.area.k-group{--k: var(--k-group);background:color-mix(in srgb,var(--k) 4%,transparent);outline-style:dashed;align-items:stretch;justify-items:stretch}.area.k-subform{--k: var(--k-subform);background:color-mix(in srgb,var(--k) 6%,transparent);outline-style:dashed;align-items:stretch;justify-items:stretch}.area.page-of-sheet{background:transparent;outline-color:color-mix(in srgb,var(--k) 22%,transparent)}.area.overflow{outline:2px dashed var(--gfy-warning, #d9a300)}.area.problem-error{outline:2px solid var(--gfy-danger, #e51400)}.area.problem-warning{outline:2px dashed var(--gfy-warning, #d9a300)}.area.ghost{--k: var(--k-subform);background:none;outline:none;opacity:.6}.area.ghost,.area.ghost *{pointer-events:none}.area.ghost .fld{border-style:dashed;background:transparent}.txt{min-width:0;overflow-wrap:anywhere;line-height:var(--gfy-line-height, 1.3);pointer-events:none}.txt.label{font-weight:600}.txt.caption{font-size:calc(var(--gfy-font-size, 13px) * .88);opacity:.88}.code{font-family:var(--gfy-font-mono, Consolas, monospace);font-size:10px;color:var(--k-static);margin-right:3px}.fld{display:flex;align-items:center;gap:6px;box-sizing:border-box;min-width:0;height:var(--gfy-control-height, 28px);padding:0 8px;border:1px solid color-mix(in srgb,var(--k) 55%,var(--gfy-border-color, #888));border-radius:var(--gfy-control-radius, 4px);background:var(--gfy-input-bg, var(--paper));overflow:hidden;max-width:100%;pointer-events:none}.fld .cut{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.area.stretch>.fld,.fld.tall{height:100%;align-items:flex-start;padding-top:6px}.fld .nm{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font:12px var(--gfy-font-mono, Consolas, monospace);color:color-mix(in srgb,var(--gfy-text-main) 88%,transparent)}.fld .tag{margin-left:auto;flex:none;font-size:10px;opacity:.88;white-space:nowrap}.fld.bare{border:0;background:transparent;padding:0}.fld.button{justify-content:center;gap:.45em;padding:0 var(--gfy-button-padding-x, var(--gfy-control-padding-x, 10px));background:color-mix(in srgb,var(--k) 14%,var(--paper))}.fld.button[data-variant]{--_vc: var(--gfy-accent, #3b73b9);--_vt: var(--gfy-accent-contrast, #fff);border-color:var(--_vc);background:var(--_vc);color:var(--_vt)}.fld.button[data-variant=success]{--_vc: var(--gfy-success, #16a34a);--_vt: #fff}.fld.button[data-variant=warning]{--_vc: var(--gfy-warning, #d97706);--_vt: #fff}.fld.button[data-variant=danger]{--_vc: var(--gfy-danger, #e81123);--_vt: var(--gfy-danger-contrast, #fff)}.fld .caret{--ic: .95em;margin-inline-end:calc(var(--gfy-control-height, 28px) / 2 - 1px - var(--gfy-button-padding-x, var(--gfy-control-padding-x, 10px)) - .475em);opacity:.8}.fld.button.split{gap:0;padding:0}.fld.button.split>.main{display:flex;flex:1 1 auto;align-items:center;justify-content:center;gap:.45em;min-width:0;padding:0 var(--gfy-button-padding-x, var(--gfy-control-padding-x, 10px))}.fld.button.split>.arrow{display:flex;flex:none;align-items:center;justify-content:center;align-self:stretch;box-sizing:border-box;width:var(--gfy-control-height, 28px);border-left:1px solid color-mix(in srgb,currentColor 35%,transparent)}.fld.button.split>.arrow>.caret{margin:0}.sepline{display:flex;align-items:center;gap:8px;min-width:0;pointer-events:none}.sepline .ln{flex:1 1 0;min-width:8px;border-top:1px solid color-mix(in srgb,var(--gfy-text-main, #333) 35%,transparent)}.sepline .lt{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.9em;opacity:.88}.fld.slider{position:relative;gap:0}.slider .track{flex:1 1 auto;height:4px;border-radius:2px;background:color-mix(in srgb,var(--k) 45%,var(--gfy-border-color, #888))}.slider .knob{position:absolute;left:30%;width:14px;height:14px;box-sizing:border-box;border:2px solid var(--k);border-radius:50%;background:var(--paper)}.fld.seg{gap:0}.seg .segment{display:inline-flex;align-items:center;height:calc(var(--gfy-control-height, 28px) - 2px);padding:0 10px;margin-left:-1px;border:1px solid color-mix(in srgb,var(--k) 55%,var(--gfy-border-color, #888));white-space:nowrap}.seg .segment:first-child{margin-left:0;border-radius:var(--gfy-control-radius, 4px) 0 0 var(--gfy-control-radius, 4px)}.seg .segment:last-child{border-radius:0 var(--gfy-control-radius, 4px) var(--gfy-control-radius, 4px) 0}.seg .segment.on{background:color-mix(in srgb,var(--k) 18%,var(--paper));font-weight:600}.fld .browse{margin-left:auto;flex:none;padding:1px 6px;border-radius:3px;font-size:11px;background:color-mix(in srgb,var(--k) 14%,var(--paper))}.drop{display:flex;align-items:center;justify-content:center;gap:6px;box-sizing:border-box;min-width:0;overflow:hidden;border:1.5px dashed color-mix(in srgb,var(--k) 55%,var(--gfy-border-color, #888));border-radius:var(--gfy-control-radius, 4px);pointer-events:none}.drop.box{flex-direction:column;height:100%;min-height:88px}.drop.strip{height:calc(var(--gfy-control-height, 28px) * .8)}.drop .up{opacity:.6}.swatch{flex:none;width:14px;height:14px;border-radius:3px;background:linear-gradient(135deg,#e5484d,#f5a524 35%,#30a46c 65%,#3e63dd)}.pic{position:relative;display:grid;place-items:center;height:100%;min-height:0;box-sizing:border-box;overflow:hidden;border-radius:6px;background:color-mix(in srgb,var(--k) 12%,var(--paper));pointer-events:none}.pic svg{width:min(40px,50%);height:min(40px,50%);fill:color-mix(in srgb,var(--k) 60%,var(--gfy-text-main, #333))}.pic>.nm{position:absolute;top:4px;left:6px;max-width:calc(100% - 12px)}.pic.gallery{grid-template-rows:minmax(0,1fr) auto;place-items:stretch;gap:6px;background:transparent}.gallery .frame{display:grid;place-items:center;min-height:0;border-radius:6px;background:color-mix(in srgb,var(--k) 12%,var(--paper))}.gallery .thumbs{display:grid;grid-template-columns:repeat(4,1fr);gap:4px;height:24px}.gallery .thumbs i{border-radius:3px;background:color-mix(in srgb,var(--k) 24%,var(--paper))}.gallery .thumbs i:first-child{outline:2px solid color-mix(in srgb,var(--k) 70%,transparent);outline-offset:-2px}.lcd{justify-self:start;max-width:100%;overflow:hidden;font:italic 700 1em/1 var(--gfy-font-mono, Consolas, monospace);letter-spacing:-.05em;white-space:nowrap;color:var(--k);pointer-events:none}.own{display:grid;place-content:center;justify-items:center;gap:2px;height:100%;min-height:0;box-sizing:border-box;overflow:hidden;padding:0 6px;border:1.5px dashed color-mix(in srgb,var(--k) 60%,transparent);border-radius:6px;background:repeating-linear-gradient(45deg,color-mix(in srgb,var(--k) 8%,transparent) 0 6px,transparent 6px 12px);pointer-events:none}.own .otag{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font:600 12px var(--gfy-font-mono, Consolas, monospace);color:var(--k)}.own .nm{max-width:100%}.glyph{--_s: calc(var(--gfy-control-height, 28px) * .64);flex:none;display:inline-block;width:var(--_s);height:var(--_s);box-sizing:border-box;border:1.5px solid color-mix(in srgb,var(--gfy-text-main) 55%,transparent);border-radius:max(3px,var(--_s) * .2)}.glyph.round{border-radius:50%}.fld.bare:has(>.glyph){gap:calc(var(--gfy-control-gap, 6px) * 1.5)}.radios{display:flex;flex-flow:row wrap;align-items:center;column-gap:calc(var(--gfy-control-gap, 6px) * 3);min-width:0;pointer-events:none}.radios.vertical{flex-flow:column nowrap;align-items:flex-start}.radio{display:inline-flex;align-items:center;gap:calc(var(--gfy-control-gap, 6px) * 1.5);min-height:var(--gfy-control-height, 28px);max-width:100%;line-height:var(--gfy-line-height, 1.4)}.radio>.rt{min-width:0}.glyph.switch{width:calc(var(--_s) * 1.8);border-radius:999px}.chev{margin-left:auto;flex:none;opacity:.75}.gbox{position:relative;box-sizing:border-box;min-width:0;min-height:0;pointer-events:none}.tagline{position:absolute;right:4px;bottom:1px;max-width:calc(100% - 8px);overflow:hidden;text-overflow:ellipsis;font:10px var(--gfy-font-mono, Consolas, monospace);color:var(--k);opacity:.88;pointer-events:none;white-space:nowrap}.sheet{--_line: color-mix(in srgb, var(--gfy-text-main, #333) 28%, transparent);--_tab: var(--gfy-sheet-tab-height, var(--gfy-control-height, 28px));--_radius: var(--gfy-sheet-radius, var(--gfy-input-radius, 6px));display:flex;flex-direction:column;box-sizing:border-box;min-width:0;min-height:0;border:1px solid var(--_line);border-radius:var(--_radius);overflow:hidden;pointer-events:none}.sheet.bottom{flex-direction:column-reverse}.sheet.start{flex-direction:row}.sheet.end{flex-direction:row-reverse}.sheet>.body{flex:1 1 auto;min-width:0;min-height:0}.tabs{flex:none;display:flex;align-items:flex-end;gap:2px;box-sizing:border-box;min-width:0;padding:6px 8px 0;border-bottom:1px solid var(--_line);pointer-events:auto}.sheet.bottom>.tabs{align-items:flex-start;padding:0 8px 6px;border-bottom:0;border-top:1px solid var(--_line)}.sheet.start>.tabs,.sheet.end>.tabs{flex-direction:column;align-items:stretch;padding:8px 0;border-bottom:0}.sheet.start>.tabs{padding-left:6px;border-right:1px solid var(--_line)}.sheet.end>.tabs{padding-right:6px;border-left:1px solid var(--_line)}.tab{position:relative;flex:none;box-sizing:border-box;max-width:100%;height:var(--_tab);margin-bottom:-1px;padding:2px var(--gfy-sheet-tab-padding, 14px);border:1px solid transparent;border-radius:max(0px,var(--_radius) - 1px) max(0px,var(--_radius) - 1px) 0 0;font-size:var(--gfy-font-size, 13px);line-height:calc(var(--_tab) - 6px);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;cursor:pointer}.sheet.bottom .tab{margin:-1px 0 0;border-radius:0 0 max(0px,var(--_radius) - 1px) max(0px,var(--_radius) - 1px)}.sheet.start .tab,.sheet.end .tab{display:flex;align-items:center;justify-content:center;width:var(--_tab);height:auto;max-height:100%;padding:var(--gfy-sheet-tab-padding, 14px) 2px;line-height:var(--gfy-line-height, 1.4)}.sheet.start .tab{margin:0 -1px 0 0;border-radius:max(0px,var(--_radius) - 1px) 0 0 max(0px,var(--_radius) - 1px)}.sheet.end .tab{margin:0 0 0 -1px;border-radius:0 max(0px,var(--_radius) - 1px) max(0px,var(--_radius) - 1px) 0}.sheet.start .tab>.tt,.sheet.end .tab>.tt{writing-mode:vertical-rl;text-orientation:sideways;overflow:hidden;text-overflow:ellipsis}.sheet.start .tab>.tt{transform:rotate(180deg)}.tab.on{z-index:1;border-color:var(--_line);border-bottom-color:var(--paper);background:var(--paper)}.tab.on:before{content:\"\";position:absolute;inset:0 0 auto;height:2px;background:var(--gfy-sheet-indicator, var(--gfy-accent, #3b73b9))}.sheet.bottom .tab.on{border-bottom-color:var(--_line);border-top-color:var(--paper)}.sheet.bottom .tab.on:before{inset:auto 0 0}.sheet.start .tab.on{border-bottom-color:var(--_line);border-right-color:var(--paper)}.sheet.start .tab.on:before{inset:0 auto 0 0;width:2px;height:auto}.sheet.end .tab.on{border-bottom-color:var(--_line);border-left-color:var(--paper)}.sheet.end .tab.on:before{inset:0 0 0 auto;width:2px;height:auto}.tab:hover:not(.on):not(.none){background:var(--gfy-sheet-hover-bg, color-mix(in srgb, var(--gfy-accent, #3b73b9) 11%, transparent))}.tab.none{opacity:.6;cursor:default}.sub{position:relative;pointer-events:none}.badge{position:absolute;z-index:2;min-width:16px;height:16px;padding:0 4px;box-sizing:border-box;border-radius:8px;font:600 10px/16px system-ui,sans-serif;text-align:center;pointer-events:none}.badge.repeat{top:-7px;right:6px;background:var(--k);color:#fff}.badge.order{top:1px;left:1px;background:color-mix(in srgb,var(--gfy-text-main) 62%,var(--paper));color:var(--paper)}.badge.order.done{background:var(--sel);color:#fff;box-shadow:0 0 0 2px color-mix(in srgb,var(--sel) 35%,transparent)}.area.ordered{outline:2px solid var(--sel);outline-offset:-2px}.badge.flow{bottom:-7px;right:6px;background:var(--k-subform);color:#fff}.badge.overflow{top:-7px;right:6px;background:var(--gfy-warning, #d9a300);color:#fff}.edit{position:absolute;inset:2px;z-index:5;box-sizing:border-box;min-width:80px;padding:0 6px;border:2px solid var(--sel);border-radius:3px;background:var(--paper);color:var(--gfy-text-main);font:inherit;outline:none}.edit.line{bottom:auto;height:var(--gfy-control-height, 28px)}.edit.toward-left{left:auto;right:2px;width:calc(100% - 4px)}.empty-form{position:absolute;left:50%;top:40px;transform:translate(-50%);max-width:80%;padding:10px 14px;border-radius:6px;background:color-mix(in srgb,var(--sel) 10%,var(--paper));color:var(--gfy-text-main);font-size:13px;text-align:center}.overlay{position:absolute;inset:0;z-index:1;pointer-events:none}.sel,.cue,.into{position:absolute;box-sizing:border-box;border-radius:3px}.sel{border:2px solid var(--sel)}.sel.many{border-style:dashed}.sel.many.first{border-style:solid}.sel .first-mark{position:absolute;left:-5px;top:-5px;width:8px;height:8px;border-radius:2px;background:var(--sel);box-shadow:0 0 0 1px var(--paper)}.into{border:2px solid color-mix(in srgb,var(--k-group) 70%,transparent);background:color-mix(in srgb,var(--k-group) 8%,transparent)}.cue{border:2px dashed var(--gfy-success, #2e9e5b);background:color-mix(in srgb,var(--gfy-success, #2e9e5b) 14%,transparent)}.cue.bad{border-color:var(--gfy-warning, #d9a300);background:color-mix(in srgb,var(--gfy-warning, #d9a300) 16%,transparent)}.cue.draw{border-color:var(--sel);background:color-mix(in srgb,var(--sel) 12%,transparent)}.cue.pick{border:1px dashed var(--sel);background:color-mix(in srgb,var(--sel) 6%,transparent)}.cue .size{position:absolute;right:2px;bottom:1px;font:600 10px system-ui,sans-serif;color:var(--gfy-text-main);opacity:.88}.handle{position:absolute;width:8px;height:8px;box-sizing:border-box;border:1px solid var(--paper);border-radius:2px;background:var(--sel);pointer-events:auto;touch-action:none}.handle.nw{left:-5px;top:-5px;cursor:nwse-resize}.handle.n{left:calc(50% - 4px);top:-5px;cursor:ns-resize}.handle.ne{right:-5px;top:-5px;cursor:nesw-resize}.handle.e{right:-5px;top:calc(50% - 4px);cursor:ew-resize}.handle.se{right:-5px;bottom:-5px;cursor:nwse-resize}.handle.s{left:calc(50% - 4px);bottom:-5px;cursor:ns-resize}.handle.sw{left:-5px;bottom:-5px;cursor:nesw-resize}.handle.w{left:-5px;top:calc(50% - 4px);cursor:ew-resize}.grip{position:absolute;right:-2px;top:-20px;display:flex;align-items:center;gap:3px;height:16px;padding:0 5px;border-radius:3px 3px 0 0;background:var(--sel);color:#fff;font:600 10px/16px system-ui,sans-serif;white-space:nowrap;pointer-events:auto;cursor:grab}.grip.inside{top:0;right:0;border-radius:0 0 0 3px}.nums{position:absolute;pointer-events:none}.num{position:absolute;box-sizing:border-box;display:grid;place-items:center;font:10px system-ui,sans-serif;color:color-mix(in srgb,var(--gfy-text-main) 88%,transparent);pointer-events:auto;cursor:pointer;overflow:visible;white-space:nowrap}.num:hover,.num.on{color:var(--gfy-text-main);background:color-mix(in srgb,var(--sel) 16%,transparent)}.num.sized{color:var(--sel);font-weight:700}.num.sized.bare[data-axis=col]{box-shadow:inset 0 -2px color-mix(in srgb,var(--sel) 70%,transparent)}.num.sized.bare[data-axis=row]{box-shadow:inset -2px 0 color-mix(in srgb,var(--sel) 70%,transparent)}.rows-grip{position:relative;height:10px;margin-top:6px;border-radius:3px;background:repeating-linear-gradient(90deg,color-mix(in srgb,var(--gfy-text-main) 25%,transparent) 0 6px,transparent 6px 10px);opacity:.5;cursor:ns-resize}.rows-grip:hover{opacity:1}.tray{margin:10px 24px 0 34px;padding:6px 8px;border:1px dashed color-mix(in srgb,var(--gfy-warning, #d9a300) 70%,transparent);border-radius:6px;display:flex;flex-wrap:wrap;align-items:center;gap:6px;font-size:12px}.chip{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:10px;background:color-mix(in srgb,var(--k-input) 14%,var(--paper));font:12px var(--gfy-font-mono, Consolas, monospace);cursor:grab;touch-action:none}.chip.dragged{cursor:grabbing;outline:1px dashed currentColor}.chip.k-static{background:color-mix(in srgb,var(--k-static) 14%,var(--paper))}.chip.k-group{background:color-mix(in srgb,var(--k-group) 14%,var(--paper))}.chip.k-subform{background:color-mix(in srgb,var(--k-subform) 14%,var(--paper))}.help{padding:10px 24px 14px 34px;font-size:12px;opacity:.88;max-width:760px}.range{font-size:11px;opacity:.88;margin:0 4px;white-space:nowrap}\n"],dependencies:[{kind:"component",type:ke,selector:"gfy-button",inputs:["label","icon","iconOnly","tooltip","ariaLabel","caret","variant","appearance","layout","toggle","checked","disabled","busy","type","name","haspopup","expanded","controls","joined","attached","reserveLabelSpace"],outputs:["checkedChange","pressed"]},{kind:"component",type:mn,selector:"gfy-dropdown-button"},{kind:"component",type:hc,selector:"gfy-group-box",inputs:["heading","icon","legendStyle","disabled","hover","gap","fill"]},{kind:"directive",type:mt,selector:"[gfyIcon]",inputs:["gfyIcon"]},{kind:"component",type:_o,selector:"gfy-slider",inputs:["value","min","max","step","label","ariaLabel","showValue","valueText","variant","disabled","readonly","name","controlId"],outputs:["valueChange","valueCommitted"]},{kind:"component",type:St,selector:"gfy-toggle-group",inputs:["options","mode","value","values","allowEmpty","iconOnly","orientation","joined","variant","appearance","disabled","label","ariaLabel"],outputs:["valueChange","valuesChange","toggled"]}]})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:ir,decorators:[{type:me,args:[{selector:"fme-canvas",standalone:true,imports:[ke,mn,hc,mt,_o,St],template:`
1523
+ <!-- two rows, so the bar does not wrap when the Editor and the Preview stand side by side: the variants and their layers above, what changes the selection and the view under them -->
1524
+ <div class="tb upper">
1525
+ @if (store.openedFrom(); as from) {
1526
+ <gfy-button appearance="flat" icon="fme:back" [label]="from.form" [tooltip]="'Back to the form ' + from.form + ' (the subform ' + from.name + ' places this form; Escape)'" (pressed)="store.back()" />
1527
+ <span class="sep" aria-hidden="true"></span>
1528
+ }
1529
+ <gfy-toggle-group [options]="variantOptions()" [value]="variantKey()" (valueChange)="onVariant($event)" ariaLabel="The variant that is edited" />
1530
+ <gfy-dropdown-button appearance="flat" iconOnly icon="fme:add-variant" label="Add a variant" [items]="variantItems()" />
1531
+ <span class="range">{{ rangeText() }}</span>
1532
+ <span class="sp"></span>
1533
+ @for (group of layerGroups(); track group.name) {
1534
+ @if (!$first) {
1535
+ <span class="sep" aria-hidden="true"></span>
1536
+ }
1537
+ <span class="label">{{ group.name }}</span>
1538
+ <gfy-toggle-group [options]="group.options" [value]="group.value" (valueChange)="onLayer(group.name, $event)" [ariaLabel]="'The layer of ' + group.name + ' that is shown'" />
1539
+ }
1540
+ <gfy-dropdown-button appearance="flat" icon="fme:layers" [label]="newLayerLabel()" [items]="newLayerItems()" />
1541
+ </div>
1542
+ <div class="tb">
1543
+ <span class="aligns" role="group" aria-label="Line up with the first selected element">
1544
+ @for (command of alignCommands; track command.how) {
1545
+ @if (command.how === 'top') {
1546
+ <span class="sep" aria-hidden="true"></span>
1547
+ }
1548
+ @if (command.how !== 'size') {
1549
+ <gfy-button appearance="flat" iconOnly [icon]="command.icon" [label]="command.text" [tooltip]="alignTip(command)" [disabled]="!store.capabilities().align" (pressed)="store.alignSelected(command.how)" />
1550
+ }
1551
+ }
1552
+ </span>
1553
+ @if (store.capabilities().align) {
1554
+ <span class="range" title="The first selected element: the others are lined up with it">to {{ store.selected()[0] }}</span>
1555
+ }
1556
+ <span class="sp"></span>
1557
+ <span class="widths" role="group" aria-label="The width the form is drawn at">
1558
+ <gfy-button toggle appearance="flat" label="Fit" tooltip="As wide as the window lets it be, within the widths of the variant" [checked]="store.designWidth() === null" (checkedChange)="onFit($event)" />
1559
+ <gfy-slider ariaLabel="The width of the form in the Editor" [min]="slideRange().min" [max]="slideRange().max" [value]="width()" [valueText]="pxText" (valueChange)="onSlide($event)" />
1560
+ <span class="range px">{{ width() }} px</span>
1561
+ </span>
1562
+ <span class="sep" aria-hidden="true"></span>
1563
+ <gfy-button toggle appearance="flat" iconOnly icon="fme:editor" label="Lines of the cells" [checked]="store.view().showGrid" (checkedChange)="store.setShowGrid($event)" />
1564
+ <gfy-button toggle appearance="flat" iconOnly icon="fme:tab-order" label="Set the order of the page (click the elements one after another)" [checked]="store.tabOrderMode()" (checkedChange)="store.setTabOrderMode($event)" />
1565
+ </div>
1566
+ <div #stage class="stage" tabindex="0" role="application" aria-label="The grid of the form" (keydown)="onKeydown($event)" (pointerdown)="onStagePress($event)" (contextmenu)="onStageMenu($event)">
1567
+ <div class="board">
1568
+ <div class="colhead">
1569
+ <div class="nums" aria-hidden="true" [style.left.px]="0" [style.top.px]="2" [style.height.px]="20">
1570
+ @for (col of colNums(); track col.n) {
1571
+ <div
1572
+ class="num"
1573
+ data-axis="col"
1574
+ [attr.data-n]="col.n"
1575
+ [class.on]="isTrack('col', col.n)"
1576
+ [class.sized]="col.sized"
1577
+ [class.bare]="!col.label"
1578
+ [style.left.px]="col.x"
1579
+ [style.width.px]="col.size"
1580
+ [style.height.px]="20"
1581
+ [attr.title]="col.title"
1582
+ (pointerdown)="onTrackPress($event, 'col', col.n)"
1583
+ (contextmenu)="onTrackMenu($event, 'col', col.n)">
1584
+ {{ col.label }}
1585
+ </div>
1586
+ }
1587
+ </div>
1588
+ </div>
1589
+ <div class="nums" aria-hidden="true" [style.left.px]="4" [style.top.px]="28" [style.width.px]="26">
1590
+ @for (row of rowNums(); track row.n) {
1591
+ <div
1592
+ class="num"
1593
+ data-axis="row"
1594
+ [attr.data-n]="row.n"
1595
+ [class.on]="isTrack('row', row.n)"
1596
+ [class.sized]="row.sized"
1597
+ [class.bare]="!row.label"
1598
+ [style.top.px]="row.y"
1599
+ [style.height.px]="row.size"
1600
+ [style.width.px]="26"
1601
+ [attr.title]="row.title"
1602
+ (pointerdown)="onTrackPress($event, 'row', row.n)"
1603
+ (contextmenu)="onTrackMenu($event, 'row', row.n)">
1604
+ {{ row.label }}
1605
+ </div>
1606
+ }
1607
+ </div>
1608
+ <div
1609
+ #page
1610
+ class="page"
1611
+ [class.busy]="busy() === 'move'"
1612
+ [class.drawing]="busy() === 'draw'"
1613
+ [class.ordering]="store.tabOrderMode()"
1614
+ [style.width]="'calc(' + width() + 'px + var(--_gx))'"
1615
+ [style.--_layout-gx]="spacingX()"
1616
+ [style.--_layout-gy]="spacingY()"
1617
+ [style.--_division]="store.division()"
1618
+ (pointerdown)="onPress($event)"
1619
+ (dblclick)="onDoubleClick($event)"
1620
+ (contextmenu)="onContextMenu($event)"
1621
+ (dragover)="onDragOver($event)"
1622
+ (dragleave)="onDragLeave($event)"
1623
+ (drop)="onDrop($event)">
1624
+ <div #grid class="grid" [style.grid-template-columns]="columns()" [style.grid-template-rows]="rows()">
1625
+ @if (store.view().showGrid) {
1626
+ @for (n of colLines(); track n) {
1627
+ <div class="vline" [class.major]="n % 6 === 0" [style.grid-column]="n"></div>
1628
+ }
1629
+ @for (n of rowLines(); track n) {
1630
+ <div class="hline" [class.major]="n % (store.division() * 2) === 0" [style.grid-row]="n"></div>
1631
+ }
1632
+ }
1633
+ <!-- the elements of the form, then those of its subforms over their places (ghost: faint, not to be pointed at) -->
1634
+ @for (item of pictured(); track item.key) {
1635
+ <div
1636
+ class="area"
1637
+ [class]="
1638
+ 'area k-' +
1639
+ item.kind +
1640
+ (item.ghost ? ' ghost' : '') +
1641
+ (item.content ? ' content' : '') +
1642
+ (item.page ? ' page-of-sheet' : '') +
1643
+ (item.problem ? ' problem-' + item.problem : '') +
1644
+ (item.align === 'stretch' ? ' stretch' : '')
1645
+ "
1646
+ [class.ordered]="item.order !== '' && store.tabOrdered().has(item.name)"
1647
+ [class.overflow]="!item.ghost && overflow().has(item.name)"
1648
+ [attr.data-name]="item.ghost ? null : item.name"
1649
+ [attr.title]="item.ghost ? null : titleOf(item)"
1650
+ [style.grid-area]="item.area"
1651
+ [style.z-index]="!item.ghost && store.editingText() === item.name ? 100 : item.z"
1652
+ [style.--_align]="item.align"
1653
+ [style.--_justify]="item.justify">
1654
+ @switch (item.kind) {
1655
+ @case ('static') {
1656
+ @if (item.appearance === 'separator') {
1657
+ <!-- a line across the place, with the text on it -->
1658
+ <span class="sepline">
1659
+ <span class="ln"></span>
1660
+ @if (item.text) {
1661
+ <span class="lt">
1662
+ @if (item.code) {
1663
+ <span class="code" title="Code of the application: the text is what the code gives (the Editor shows the first text in it)">ƒ</span>
1664
+ }
1665
+ {{ item.text }}</span
1666
+ ><span class="ln"></span>
1667
+ }
1668
+ </span>
1669
+ } @else {
1670
+ <span class="txt" [class]="'txt ' + item.appearance">
1671
+ @if (item.code) {
1672
+ <span class="code" title="Code of the application: the text is what the code gives (the Editor shows the first text in it)">ƒ</span>
1673
+ }
1674
+ {{ item.text || '(empty text)' }}
1675
+ </span>
1676
+ }
1677
+ }
1678
+ @case ('input') {
1679
+ @if (item.own) {
1680
+ <!-- a component of the application: a box with its tag -->
1681
+ <span class="own"
1682
+ ><span class="otag">&lt;{{ item.as }}&gt;</span><span class="nm">{{ item.name }}</span></span
1683
+ >
1684
+ } @else {
1685
+ @switch (item.as) {
1686
+ @case ('gfy-button') {
1687
+ <span class="fld button" [attr.data-variant]="item.variant || null">
1688
+ @if (item.icon) {
1689
+ <span class="ic" [gfyIcon]="item.icon"></span>
1690
+ }
1691
+ <span class="cut">{{ item.text || item.name }}</span></span
1692
+ >
1693
+ }
1694
+ @case ('gfy-split-button') {
1695
+ <!-- the button and the arrow that opens its menu, behind a line -->
1696
+ <span class="fld button split" [attr.data-variant]="item.variant || null"
1697
+ ><span class="main">
1698
+ @if (item.icon) {
1699
+ <span class="ic" [gfyIcon]="item.icon"></span>
1700
+ }
1701
+ <span class="cut">{{ item.text || item.name }}</span></span
1702
+ ><span class="arrow"><span class="ic caret" gfyIcon="gfy:chevron-down"></span></span
1703
+ ></span>
1704
+ }
1705
+ @case ('gfy-dropdown-button') {
1706
+ <span class="fld button" [attr.data-variant]="item.variant || null">
1707
+ @if (item.icon) {
1708
+ <span class="ic" [gfyIcon]="item.icon"></span>
1709
+ }
1710
+ <span class="cut">{{ item.text || item.name }}</span
1711
+ ><span class="ic caret" gfyIcon="gfy:chevron-down"></span
1712
+ ></span>
1713
+ }
1714
+ @case ('gfy-checkbox') {
1715
+ <span class="fld bare"
1716
+ ><span class="glyph"></span><span class="cut">{{ item.text || item.name }}</span></span
1717
+ >
1718
+ }
1719
+ @case ('gfy-switch') {
1720
+ <span class="fld bare"
1721
+ ><span class="glyph switch"></span><span class="cut">{{ item.text || item.name }}</span></span
1722
+ >
1723
+ }
1724
+ @case ('gfy-radio-group') {
1725
+ <!-- the options as gfy-radio-group lays them out: one under another, or side by side and into the next line where the place is too narrow -->
1726
+ <span class="radios" [class.vertical]="item.vertical">
1727
+ @for (option of item.options; track $index) {
1728
+ <span class="radio"
1729
+ ><span class="glyph round"></span><span class="rt">{{ option }}</span></span
1730
+ >
1731
+ }
1732
+ @if (item.options.length === 0) {
1733
+ <span class="radio"
1734
+ ><span class="glyph round"></span><span class="nm">{{ item.name }}</span></span
1735
+ >
1736
+ }
1737
+ </span>
1738
+ }
1739
+ @case ('gfy-label') {
1740
+ <span class="txt label">{{ item.text || item.name }}</span>
1741
+ }
1742
+ @case ('gfy-slider') {
1743
+ <span class="fld bare slider"><span class="track"></span><span class="knob"></span></span>
1744
+ }
1745
+ @case ('gfy-toggle-group') {
1746
+ <span class="fld bare seg">
1747
+ @for (option of item.options; track $index) {
1748
+ <span class="segment" [class.on]="$first">{{ option }}</span>
1749
+ }
1750
+ </span>
1751
+ }
1752
+ @case ('gfy-file-upload') {
1753
+ @if (item.upload === 'row') {
1754
+ <span class="fld"
1755
+ ><span class="nm">{{ item.name }}</span
1756
+ ><span class="browse">Browse…</span></span
1757
+ >
1758
+ } @else {
1759
+ <span class="drop" [class]="'drop ' + item.upload"
1760
+ ><span class="up" aria-hidden="true">⇪</span><span class="nm">{{ item.name }}</span></span
1761
+ >
1762
+ }
1763
+ }
1764
+ @case ('gfy-picture') {
1765
+ <span class="pic">
1766
+ <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M21 19V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2M8.5 13.5l2.5 3 3.5-4.5 4.5 6H5z" /></svg>
1767
+ <span class="nm">{{ item.name }}</span>
1768
+ </span>
1769
+ }
1770
+ @case ('gfy-picture-gallery') {
1771
+ <span class="pic gallery">
1772
+ <span class="frame"
1773
+ ><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M21 19V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2M8.5 13.5l2.5 3 3.5-4.5 4.5 6H5z" /></svg
1774
+ ></span>
1775
+ <span class="thumbs"><i></i><i></i><i></i><i></i></span>
1776
+ <span class="nm">{{ item.name }}</span>
1777
+ </span>
1778
+ }
1779
+ @case ('gfy-digital-display') {
1780
+ <span class="lcd" [style.font-size.px]="item.digitSize * 1.1">{{ item.digits }}</span>
1781
+ }
1782
+ @default {
1783
+ <span class="fld" [class.tall]="item.as === 'gfy-textarea'">
1784
+ @if (item.as === 'gfy-color-picker') {
1785
+ <span class="swatch"></span>
1786
+ }
1787
+ <span class="nm">{{ item.name }}</span>
1788
+ @if (item.tag) {
1789
+ <span class="tag">{{ item.tag }}</span>
1790
+ }
1791
+ @if (item.as === 'gfy-select' || item.as === 'gfy-combobox' || item.as === 'gfy-multi-select') {
1792
+ <span class="chev">▾</span>
1793
+ }
1794
+ </span>
1795
+ }
1796
+ }
1797
+ }
1798
+ }
1799
+ @case ('group') {
1800
+ @if (item.look === 'property-sheet' && !item.page) {
1801
+ <!-- the tabs lie in the edge cells of the sheet, the frame under them (or beside them) -->
1802
+ <div class="sheet" [class]="'sheet ' + item.tabSide">
1803
+ <div class="tabs">
1804
+ @for (tab of item.tabs; track tab.name) {
1805
+ <span class="tab" [class.on]="tab.on" [attr.data-page]="item.ghost ? null : tab.name" [attr.data-sheet]="item.name" [attr.title]="'Show the page ' + tab.name"
1806
+ ><span class="tt">{{ tab.title }}</span></span
1807
+ >
1808
+ }
1809
+ @if (item.tabs.length === 0) {
1810
+ <span class="tab none"><span class="tt">no pages</span></span>
1811
+ }
1812
+ </div>
1813
+ <div class="body"></div>
1814
+ </div>
1815
+ } @else if (item.look === 'group-box' && !item.page) {
1816
+ <gfy-group-box class="gbox" aria-hidden="true" fill [hover]="false" [heading]="item.text" />
1817
+ } @else {
1818
+ <div class="gbox"></div>
1819
+ }
1820
+ @if (!item.page && (item.look !== 'group-box' || !item.text)) {
1821
+ <span class="tagline">{{ item.name }}</span>
1822
+ }
1823
+ }
1824
+ @case ('subform') {
1825
+ <div class="sub">
1826
+ <span class="tagline">{{ item.name }} → {{ item.sub }}{{ item.more ? ' (+' + item.more + (item.more === 1 ? ' row' : ' rows') + ' under it)' : '' }}</span>
1827
+ </div>
1828
+ }
1829
+ }
1830
+ @if (item.repeat) {
1831
+ <span class="badge repeat" title="The place holds one instance; the application says how many">×N</span>
1832
+ }
1833
+ @if (item.flow) {
1834
+ <span class="badge flow" title="The subform adds the rows it needs under its place">↧</span>
1835
+ }
1836
+ @if (item.order) {
1837
+ <span class="badge order" [class.done]="store.tabOrdered().has(item.name)">{{ item.order }}</span>
1838
+ }
1839
+ @if (!item.ghost && overflow().get(item.name); as over) {
1840
+ <span class="badge overflow">{{ over.top || over.bottom ? '↕' : '↔' }}</span>
1841
+ }
1842
+ @if (!item.ghost && store.editingText() === item.name) {
1843
+ <input
1844
+ #edit
1845
+ class="edit"
1846
+ [class.toward-left]="editTowardLeft()"
1847
+ [class.line]="item.kind === 'group' || item.kind === 'subform'"
1848
+ [value]="editValue(item)"
1849
+ (keydown)="onEditKey($event)"
1850
+ (blur)="commitEdit(item.name, $event)"
1851
+ (pointerdown)="$event.stopPropagation()" />
1852
+ }
1853
+ </div>
1854
+ }
1855
+ </div>
1856
+ <div class="overlay">
1857
+ @if (store.form()?.elements?.length === 0) {
1858
+ <div class="empty-form">The form is empty. Drag a tool from the Toolbox onto the grid, or draw an area with the mouse and choose what goes there.</div>
1859
+ }
1860
+ @if (into(); as box) {
1861
+ <div class="into" [style.left.px]="box.x" [style.top.px]="box.y" [style.width.px]="box.width" [style.height.px]="box.height"></div>
1862
+ }
1863
+ @for (frame of frames(); track frame.name) {
1864
+ <div
1865
+ class="sel"
1866
+ [class.many]="frames().length > 1"
1867
+ [class.first]="frames().length > 1 && frame.name === store.selected()[0]"
1868
+ [style.left.px]="frame.box.x"
1869
+ [style.top.px]="frame.box.y"
1870
+ [style.width.px]="frame.box.width"
1871
+ [style.height.px]="frame.box.height">
1872
+ @if (frames().length > 1 && frame.name === store.selected()[0]) {
1873
+ <span class="first-mark" title="The first selected element: the others are lined up with it"></span>
1874
+ }
1875
+ @if (frames().length === 1 && !store.tabOrderMode()) {
1876
+ @for (edge of edges; track edge) {
1877
+ <span [class]="'handle ' + edge" (pointerdown)="startResize($event, edge, frame.name)"></span>
1878
+ }
1879
+ @if (frame.group) {
1880
+ <span class="grip" [class.inside]="frame.inside" title="Drag to move the group with what is in it" (pointerdown)="startMove($event, frame.name)"
1881
+ ><span class="ic" style="--ic: 10px" gfyIcon="fme:width"></span>{{ frame.name }}</span
1882
+ >
1883
+ }
1884
+ }
1885
+ </div>
1886
+ }
1887
+ @if (hint(); as cue) {
1888
+ <div class="cue" [class.bad]="!cue.ok" [class.draw]="cue.draw" [class.pick]="cue.pick" [style.left.px]="cue.box.x" [style.top.px]="cue.box.y" [style.width.px]="cue.box.width" [style.height.px]="cue.box.height">
1889
+ <span class="size">{{ hintSize() }}</span>
1890
+ </div>
1891
+ }
1892
+ </div>
1893
+ </div>
1894
+ <div class="rows-grip" [style.width.px]="gridWidth()" title="Drag to give the grid more rows or fewer" (pointerdown)="startRows($event)"></div>
1895
+ </div>
1896
+ @if (store.unplaced().length) {
1897
+ <div class="tray" (pointerdown)="$event.stopPropagation()">
1898
+ <span>Not placed in this variant (drag onto the grid):</span>
1899
+ @for (entry of store.unplaced(); track entry.name) {
1900
+ <span
1901
+ class="chip"
1902
+ [class]="'chip k-' + entry.element.kind"
1903
+ [class.dragged]="placing() === entry.name"
1904
+ role="button"
1905
+ tabindex="0"
1906
+ [attr.title]="'Drag ' + entry.name + ' onto its cells, or double-click it (Enter) to place it in the first free cells'"
1907
+ (pointerdown)="startPlace($event, entry.name)"
1908
+ (dblclick)="placeChip(entry.name)"
1909
+ (keydown.enter)="$event.preventDefault(); placeChip(entry.name)"
1910
+ (keydown.space)="$event.preventDefault(); placeChip(entry.name)"
1911
+ >{{ entry.name }}</span
1912
+ >
1913
+ }
1914
+ <gfy-button appearance="flat" icon="fme:place" label="Place all" (pressed)="placeAll()" />
1915
+ </div>
1916
+ }
1917
+ <div class="help">
1918
+ {{ helpText() }}
1919
+ </div>
1920
+ </div>
1921
+ `,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n",".ic{flex:none;display:grid;width:var(--ic, 14px);height:var(--ic, 14px)}\n",":host{--paper: var(--gfy-bg-document, var(--gfy-bg-main, #fff));--k-static: #8b5cf6;--k-input: #2f80ed;--k-group: #1f9d55;--k-subform: #e07b00;--k-content: #0d9488;--sel: var(--gfy-accent, #3a8fd6)}.tb .label{font-size:12px;opacity:.88;margin-left:2px}.tb.upper{border-bottom:0;padding-bottom:0}.tb .aligns,.tb .widths{display:inline-flex;align-items:center;gap:2px}.tb .widths gfy-slider{--gfy-slider-width: 140px;margin:0 4px}.tb .px{min-width:52px;text-align:end;font-variant-numeric:tabular-nums}.stage{flex:1 1 auto;min-height:0;overflow:auto;outline:none;background:color-mix(in srgb,var(--gfy-text-main, #333) 4%,var(--gfy-bg-panel, var(--gfy-bg-main)))}.stage:focus-visible .page{box-shadow:0 0 0 2px color-mix(in srgb,var(--sel) 45%,transparent)}.board{position:relative;display:inline-block;padding:0 24px 12px 34px;min-width:calc(100% - 58px)}.colhead{position:sticky;top:0;z-index:3;height:22px;margin-bottom:6px;background:color-mix(in srgb,var(--gfy-text-main, #333) 4%,var(--gfy-bg-panel, var(--gfy-bg-main)))}.page{--_gx: var(--_layout-gx, var(--gfy-form-spacing-x, 8px));--_gy: var(--_layout-gy, var(--gfy-form-spacing-y, 8px));--_row: calc((var(--gfy-control-height, 28px) + var(--_gy)) / var(--_division, 2));position:relative;background:var(--paper);color:var(--gfy-text-main);font-size:var(--gfy-font-size, 13px);box-shadow:0 0 0 1px var(--gfy-border-color, rgba(128, 128, 128, .35));-webkit-user-select:none;user-select:none;touch-action:none}.page.busy,.page.busy *{cursor:grabbing!important}.page.drawing,.page.drawing *{cursor:crosshair!important}.page.ordering .area{cursor:pointer}.grid{position:relative;isolation:isolate;display:grid;overflow-x:clip;cursor:crosshair}.vline,.hline{pointer-events:none;box-sizing:border-box}.vline{grid-row:1/-1;border-right:1px dotted color-mix(in srgb,var(--gfy-text-main, #333) 16%,transparent)}.hline{grid-column:1/-1;border-bottom:1px dotted color-mix(in srgb,var(--gfy-text-main, #333) 16%,transparent)}.vline.major{border-right-style:solid;border-right-color:color-mix(in srgb,var(--gfy-text-main, #333) 22%,transparent)}.hline.major{border-bottom-style:solid;border-bottom-color:color-mix(in srgb,var(--gfy-text-main, #333) 22%,transparent)}.area{--k: var(--k-input);position:relative;display:grid;grid-template-rows:minmax(0,1fr);box-sizing:border-box;min-width:0;min-height:0;padding:calc(var(--_gy) / 2) calc(var(--_gx) / 2);align-items:var(--_align, center);justify-items:var(--_justify, stretch);border-radius:3px;background:color-mix(in srgb,var(--k) 9%,transparent);outline:1px solid color-mix(in srgb,var(--k) 30%,transparent);outline-offset:-1px;cursor:grab}.area.k-static{--k: var(--k-static)}.area.content{--k: var(--k-content)}.area.k-group{--k: var(--k-group);background:color-mix(in srgb,var(--k) 4%,transparent);outline-style:dashed;align-items:stretch;justify-items:stretch}.area.k-subform{--k: var(--k-subform);background:color-mix(in srgb,var(--k) 6%,transparent);outline-style:dashed;align-items:stretch;justify-items:stretch}.area.page-of-sheet{background:transparent;outline-color:color-mix(in srgb,var(--k) 22%,transparent)}.area.overflow{outline:2px dashed var(--gfy-warning, #d9a300)}.area.problem-error{outline:2px solid var(--gfy-danger, #e51400)}.area.problem-warning{outline:2px dashed var(--gfy-warning, #d9a300)}.area.ghost{--k: var(--k-subform);background:none;outline:none;opacity:.6}.area.ghost,.area.ghost *{pointer-events:none}.area.ghost .fld{border-style:dashed;background:transparent}.txt{min-width:0;overflow-wrap:anywhere;line-height:var(--gfy-line-height, 1.3);pointer-events:none}.txt.label{font-weight:600}.txt.caption{font-size:calc(var(--gfy-font-size, 13px) * .88);opacity:.88}.code{font-family:var(--gfy-font-mono, Consolas, monospace);font-size:10px;color:var(--k-static);margin-right:3px}.fld{display:flex;align-items:center;gap:6px;box-sizing:border-box;min-width:0;height:var(--gfy-control-height, 28px);padding:0 8px;border:1px solid color-mix(in srgb,var(--k) 55%,var(--gfy-border-color, #888));border-radius:var(--gfy-control-radius, 4px);background:var(--gfy-input-bg, var(--paper));overflow:hidden;max-width:100%;pointer-events:none}.fld .cut{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.area.stretch>.fld,.fld.tall{height:100%;align-items:flex-start;padding-top:6px}.fld .nm{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font:12px var(--gfy-font-mono, Consolas, monospace);color:color-mix(in srgb,var(--gfy-text-main) 88%,transparent)}.fld .tag{margin-left:auto;flex:none;font-size:10px;opacity:.88;white-space:nowrap}.fld.bare{border:0;background:transparent;padding:0}.fld.button{justify-content:center;gap:.45em;padding:0 var(--gfy-button-padding-x, var(--gfy-control-padding-x, 10px));background:color-mix(in srgb,var(--k) 14%,var(--paper))}.fld.button[data-variant]{--_vc: var(--gfy-accent, #3b73b9);--_vt: var(--gfy-accent-contrast, #fff);border-color:var(--_vc);background:var(--_vc);color:var(--_vt)}.fld.button[data-variant=success]{--_vc: var(--gfy-success, #16a34a);--_vt: #fff}.fld.button[data-variant=warning]{--_vc: var(--gfy-warning, #d97706);--_vt: #fff}.fld.button[data-variant=danger]{--_vc: var(--gfy-danger, #e81123);--_vt: var(--gfy-danger-contrast, #fff)}.fld .caret{--ic: .95em;margin-inline-end:calc(var(--gfy-control-height, 28px) / 2 - 1px - var(--gfy-button-padding-x, var(--gfy-control-padding-x, 10px)) - .475em);opacity:.8}.fld.button.split{gap:0;padding:0}.fld.button.split>.main{display:flex;flex:1 1 auto;align-items:center;justify-content:center;gap:.45em;min-width:0;padding:0 var(--gfy-button-padding-x, var(--gfy-control-padding-x, 10px))}.fld.button.split>.arrow{display:flex;flex:none;align-items:center;justify-content:center;align-self:stretch;box-sizing:border-box;width:var(--gfy-control-height, 28px);border-left:1px solid color-mix(in srgb,currentColor 35%,transparent)}.fld.button.split>.arrow>.caret{margin:0}.sepline{display:flex;align-items:center;gap:8px;min-width:0;pointer-events:none}.sepline .ln{flex:1 1 0;min-width:8px;border-top:1px solid color-mix(in srgb,var(--gfy-text-main, #333) 35%,transparent)}.sepline .lt{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.9em;opacity:.88}.fld.slider{position:relative;gap:0}.slider .track{flex:1 1 auto;height:4px;border-radius:2px;background:color-mix(in srgb,var(--k) 45%,var(--gfy-border-color, #888))}.slider .knob{position:absolute;left:30%;width:14px;height:14px;box-sizing:border-box;border:2px solid var(--k);border-radius:50%;background:var(--paper)}.fld.seg{gap:0}.seg .segment{display:inline-flex;align-items:center;height:calc(var(--gfy-control-height, 28px) - 2px);padding:0 10px;margin-left:-1px;border:1px solid color-mix(in srgb,var(--k) 55%,var(--gfy-border-color, #888));white-space:nowrap}.seg .segment:first-child{margin-left:0;border-radius:var(--gfy-control-radius, 4px) 0 0 var(--gfy-control-radius, 4px)}.seg .segment:last-child{border-radius:0 var(--gfy-control-radius, 4px) var(--gfy-control-radius, 4px) 0}.seg .segment.on{background:color-mix(in srgb,var(--k) 18%,var(--paper));font-weight:600}.fld .browse{margin-left:auto;flex:none;padding:1px 6px;border-radius:3px;font-size:11px;background:color-mix(in srgb,var(--k) 14%,var(--paper))}.drop{display:flex;align-items:center;justify-content:center;gap:6px;box-sizing:border-box;min-width:0;overflow:hidden;border:1.5px dashed color-mix(in srgb,var(--k) 55%,var(--gfy-border-color, #888));border-radius:var(--gfy-control-radius, 4px);pointer-events:none}.drop.box{flex-direction:column;height:100%;min-height:88px}.drop.strip{height:calc(var(--gfy-control-height, 28px) * .8)}.drop .up{opacity:.6}.swatch{flex:none;width:14px;height:14px;border-radius:3px;background:linear-gradient(135deg,#e5484d,#f5a524 35%,#30a46c 65%,#3e63dd)}.pic{position:relative;display:grid;place-items:center;height:100%;min-height:0;box-sizing:border-box;overflow:hidden;border-radius:6px;background:color-mix(in srgb,var(--k) 12%,var(--paper));pointer-events:none}.pic svg{width:min(40px,50%);height:min(40px,50%);fill:color-mix(in srgb,var(--k) 60%,var(--gfy-text-main, #333))}.pic>.nm{position:absolute;top:4px;left:6px;max-width:calc(100% - 12px)}.pic.gallery{grid-template-rows:minmax(0,1fr) auto;place-items:stretch;gap:6px;background:transparent}.gallery .frame{display:grid;place-items:center;min-height:0;border-radius:6px;background:color-mix(in srgb,var(--k) 12%,var(--paper))}.gallery .thumbs{display:grid;grid-template-columns:repeat(4,1fr);gap:4px;height:24px}.gallery .thumbs i{border-radius:3px;background:color-mix(in srgb,var(--k) 24%,var(--paper))}.gallery .thumbs i:first-child{outline:2px solid color-mix(in srgb,var(--k) 70%,transparent);outline-offset:-2px}.lcd{justify-self:start;max-width:100%;overflow:hidden;font:italic 700 1em/1 var(--gfy-font-mono, Consolas, monospace);letter-spacing:-.05em;white-space:nowrap;color:var(--k);pointer-events:none}.own{display:grid;place-content:center;justify-items:center;gap:2px;height:100%;min-height:0;box-sizing:border-box;overflow:hidden;padding:0 6px;border:1.5px dashed color-mix(in srgb,var(--k) 60%,transparent);border-radius:6px;background:repeating-linear-gradient(45deg,color-mix(in srgb,var(--k) 8%,transparent) 0 6px,transparent 6px 12px);pointer-events:none}.own .otag{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font:600 12px var(--gfy-font-mono, Consolas, monospace);color:var(--k)}.own .nm{max-width:100%}.glyph{--_s: calc(var(--gfy-control-height, 28px) * .64);flex:none;display:inline-block;width:var(--_s);height:var(--_s);box-sizing:border-box;border:1.5px solid color-mix(in srgb,var(--gfy-text-main) 55%,transparent);border-radius:max(3px,var(--_s) * .2)}.glyph.round{border-radius:50%}.fld.bare:has(>.glyph){gap:calc(var(--gfy-control-gap, 6px) * 1.5)}.radios{display:flex;flex-flow:row wrap;align-items:center;column-gap:calc(var(--gfy-control-gap, 6px) * 3);min-width:0;pointer-events:none}.radios.vertical{flex-flow:column nowrap;align-items:flex-start}.radio{display:inline-flex;align-items:center;gap:calc(var(--gfy-control-gap, 6px) * 1.5);min-height:var(--gfy-control-height, 28px);max-width:100%;line-height:var(--gfy-line-height, 1.4)}.radio>.rt{min-width:0}.glyph.switch{width:calc(var(--_s) * 1.8);border-radius:999px}.chev{margin-left:auto;flex:none;opacity:.75}.gbox{position:relative;box-sizing:border-box;min-width:0;min-height:0;pointer-events:none}.tagline{position:absolute;right:4px;bottom:1px;max-width:calc(100% - 8px);overflow:hidden;text-overflow:ellipsis;font:10px var(--gfy-font-mono, Consolas, monospace);color:var(--k);opacity:.88;pointer-events:none;white-space:nowrap}.sheet{--_line: color-mix(in srgb, var(--gfy-text-main, #333) 28%, transparent);--_tab: var(--gfy-sheet-tab-height, var(--gfy-control-height, 28px));--_radius: var(--gfy-sheet-radius, var(--gfy-input-radius, 6px));display:flex;flex-direction:column;box-sizing:border-box;min-width:0;min-height:0;border:1px solid var(--_line);border-radius:var(--_radius);overflow:hidden;pointer-events:none}.sheet.bottom{flex-direction:column-reverse}.sheet.start{flex-direction:row}.sheet.end{flex-direction:row-reverse}.sheet>.body{flex:1 1 auto;min-width:0;min-height:0}.tabs{flex:none;display:flex;align-items:flex-end;gap:2px;box-sizing:border-box;min-width:0;padding:6px 8px 0;border-bottom:1px solid var(--_line);pointer-events:auto}.sheet.bottom>.tabs{align-items:flex-start;padding:0 8px 6px;border-bottom:0;border-top:1px solid var(--_line)}.sheet.start>.tabs,.sheet.end>.tabs{flex-direction:column;align-items:stretch;padding:8px 0;border-bottom:0}.sheet.start>.tabs{padding-left:6px;border-right:1px solid var(--_line)}.sheet.end>.tabs{padding-right:6px;border-left:1px solid var(--_line)}.tab{position:relative;flex:none;box-sizing:border-box;max-width:100%;height:var(--_tab);margin-bottom:-1px;padding:2px var(--gfy-sheet-tab-padding, 14px);border:1px solid transparent;border-radius:max(0px,var(--_radius) - 1px) max(0px,var(--_radius) - 1px) 0 0;font-size:var(--gfy-font-size, 13px);line-height:calc(var(--_tab) - 6px);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;cursor:pointer}.sheet.bottom .tab{margin:-1px 0 0;border-radius:0 0 max(0px,var(--_radius) - 1px) max(0px,var(--_radius) - 1px)}.sheet.start .tab,.sheet.end .tab{display:flex;align-items:center;justify-content:center;width:var(--_tab);height:auto;max-height:100%;padding:var(--gfy-sheet-tab-padding, 14px) 2px;line-height:var(--gfy-line-height, 1.4)}.sheet.start .tab{margin:0 -1px 0 0;border-radius:max(0px,var(--_radius) - 1px) 0 0 max(0px,var(--_radius) - 1px)}.sheet.end .tab{margin:0 0 0 -1px;border-radius:0 max(0px,var(--_radius) - 1px) max(0px,var(--_radius) - 1px) 0}.sheet.start .tab>.tt,.sheet.end .tab>.tt{writing-mode:vertical-rl;text-orientation:sideways;overflow:hidden;text-overflow:ellipsis}.sheet.start .tab>.tt{transform:rotate(180deg)}.tab.on{z-index:1;border-color:var(--_line);border-bottom-color:var(--paper);background:var(--paper)}.tab.on:before{content:\"\";position:absolute;inset:0 0 auto;height:2px;background:var(--gfy-sheet-indicator, var(--gfy-accent, #3b73b9))}.sheet.bottom .tab.on{border-bottom-color:var(--_line);border-top-color:var(--paper)}.sheet.bottom .tab.on:before{inset:auto 0 0}.sheet.start .tab.on{border-bottom-color:var(--_line);border-right-color:var(--paper)}.sheet.start .tab.on:before{inset:0 auto 0 0;width:2px;height:auto}.sheet.end .tab.on{border-bottom-color:var(--_line);border-left-color:var(--paper)}.sheet.end .tab.on:before{inset:0 0 0 auto;width:2px;height:auto}.tab:hover:not(.on):not(.none){background:var(--gfy-sheet-hover-bg, color-mix(in srgb, var(--gfy-accent, #3b73b9) 11%, transparent))}.tab.none{opacity:.6;cursor:default}.sub{position:relative;pointer-events:none}.badge{position:absolute;z-index:2;min-width:16px;height:16px;padding:0 4px;box-sizing:border-box;border-radius:8px;font:600 10px/16px system-ui,sans-serif;text-align:center;pointer-events:none}.badge.repeat{top:-7px;right:6px;background:var(--k);color:#fff}.badge.order{top:1px;left:1px;background:color-mix(in srgb,var(--gfy-text-main) 62%,var(--paper));color:var(--paper)}.badge.order.done{background:var(--sel);color:#fff;box-shadow:0 0 0 2px color-mix(in srgb,var(--sel) 35%,transparent)}.area.ordered{outline:2px solid var(--sel);outline-offset:-2px}.badge.flow{bottom:-7px;right:6px;background:var(--k-subform);color:#fff}.badge.overflow{top:-7px;right:6px;background:var(--gfy-warning, #d9a300);color:#fff}.edit{position:absolute;inset:2px;z-index:5;box-sizing:border-box;min-width:80px;padding:0 6px;border:2px solid var(--sel);border-radius:3px;background:var(--paper);color:var(--gfy-text-main);font:inherit;outline:none}.edit.line{bottom:auto;height:var(--gfy-control-height, 28px)}.edit.toward-left{left:auto;right:2px;width:calc(100% - 4px)}.empty-form{position:absolute;left:50%;top:40px;transform:translate(-50%);max-width:80%;padding:10px 14px;border-radius:6px;background:color-mix(in srgb,var(--sel) 10%,var(--paper));color:var(--gfy-text-main);font-size:13px;text-align:center}.overlay{position:absolute;inset:0;z-index:1;pointer-events:none}.sel,.cue,.into{position:absolute;box-sizing:border-box;border-radius:3px}.sel{border:2px solid var(--sel)}.sel.many{border-style:dashed}.sel.many.first{border-style:solid}.sel .first-mark{position:absolute;left:-5px;top:-5px;width:8px;height:8px;border-radius:2px;background:var(--sel);box-shadow:0 0 0 1px var(--paper)}.into{border:2px solid color-mix(in srgb,var(--k-group) 70%,transparent);background:color-mix(in srgb,var(--k-group) 8%,transparent)}.cue{border:2px dashed var(--gfy-success, #2e9e5b);background:color-mix(in srgb,var(--gfy-success, #2e9e5b) 14%,transparent)}.cue.bad{border-color:var(--gfy-warning, #d9a300);background:color-mix(in srgb,var(--gfy-warning, #d9a300) 16%,transparent)}.cue.draw{border-color:var(--sel);background:color-mix(in srgb,var(--sel) 12%,transparent)}.cue.pick{border:1px dashed var(--sel);background:color-mix(in srgb,var(--sel) 6%,transparent)}.cue .size{position:absolute;right:2px;bottom:1px;font:600 10px system-ui,sans-serif;color:var(--gfy-text-main);opacity:.88}.handle{position:absolute;width:8px;height:8px;box-sizing:border-box;border:1px solid var(--paper);border-radius:2px;background:var(--sel);pointer-events:auto;touch-action:none}.handle.nw{left:-5px;top:-5px;cursor:nwse-resize}.handle.n{left:calc(50% - 4px);top:-5px;cursor:ns-resize}.handle.ne{right:-5px;top:-5px;cursor:nesw-resize}.handle.e{right:-5px;top:calc(50% - 4px);cursor:ew-resize}.handle.se{right:-5px;bottom:-5px;cursor:nwse-resize}.handle.s{left:calc(50% - 4px);bottom:-5px;cursor:ns-resize}.handle.sw{left:-5px;bottom:-5px;cursor:nesw-resize}.handle.w{left:-5px;top:calc(50% - 4px);cursor:ew-resize}.grip{position:absolute;right:-2px;top:-20px;display:flex;align-items:center;gap:3px;height:16px;padding:0 5px;border-radius:3px 3px 0 0;background:var(--sel);color:#fff;font:600 10px/16px system-ui,sans-serif;white-space:nowrap;pointer-events:auto;cursor:grab}.grip.inside{top:0;right:0;border-radius:0 0 0 3px}.nums{position:absolute;pointer-events:none}.num{position:absolute;box-sizing:border-box;display:grid;place-items:center;font:10px system-ui,sans-serif;color:color-mix(in srgb,var(--gfy-text-main) 88%,transparent);pointer-events:auto;cursor:pointer;overflow:visible;white-space:nowrap}.num:hover,.num.on{color:var(--gfy-text-main);background:color-mix(in srgb,var(--sel) 16%,transparent)}.num.sized{color:var(--sel);font-weight:700}.num.sized.bare[data-axis=col]{box-shadow:inset 0 -2px color-mix(in srgb,var(--sel) 70%,transparent)}.num.sized.bare[data-axis=row]{box-shadow:inset -2px 0 color-mix(in srgb,var(--sel) 70%,transparent)}.rows-grip{position:relative;height:10px;margin-top:6px;border-radius:3px;background:repeating-linear-gradient(90deg,color-mix(in srgb,var(--gfy-text-main) 25%,transparent) 0 6px,transparent 6px 10px);opacity:.5;cursor:ns-resize}.rows-grip:hover{opacity:1}.tray{margin:10px 24px 0 34px;padding:6px 8px;border:1px dashed color-mix(in srgb,var(--gfy-warning, #d9a300) 70%,transparent);border-radius:6px;display:flex;flex-wrap:wrap;align-items:center;gap:6px;font-size:12px}.chip{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:10px;background:color-mix(in srgb,var(--k-input) 14%,var(--paper));font:12px var(--gfy-font-mono, Consolas, monospace);cursor:grab;touch-action:none}.chip.dragged{cursor:grabbing;outline:1px dashed currentColor}.chip.k-static{background:color-mix(in srgb,var(--k-static) 14%,var(--paper))}.chip.k-group{background:color-mix(in srgb,var(--k-group) 14%,var(--paper))}.chip.k-subform{background:color-mix(in srgb,var(--k-subform) 14%,var(--paper))}.help{padding:10px 24px 14px 34px;font-size:12px;opacity:.88;max-width:760px}.range{font-size:11px;opacity:.88;margin:0 4px;white-space:nowrap}\n"]}]}],ctorParameters:()=>[],propDecorators:{stageRef:[{type:w.ViewChild,args:["stage",{isSignal:true}]}],pageRef:[{type:w.ViewChild,args:["page",{isSignal:true}]}],gridRef:[{type:w.ViewChild,args:["grid",{isSignal:true}]}],editRef:[{type:w.ViewChild,args:["edit",{isSignal:true}]}]}});const tf=(n,e)=>n.length===e.length&&n.every((t,o)=>Math.abs(t.start-e[o].start)<0.5&&Math.abs(t.size-e[o].size)<0.5);const j1={id:"form-editor:help",editor:"Form editor",pages:[{id:"overview",title:"Overview",icon:"fme:info",blocks:[C.lead("The Form editor draws the layout of forms: where the labels, the fields, the texts and the groups stand, at every width of the screen. It saves a file; your application loads it, and `<gfy-form>` lays the form out around your own controls."),C.heading("What it is good for"),C.points(["*Forms that fit every screen.* A form has variants, grids for the widths from a `minWidth` up: the same fields can be one column on a phone and three on a wide screen.","*No CSS to write.* You put the elements on cells with the mouse; the library sizes the cells and keeps the spacing.","*Your controls stay yours.* The form gives each field a place, and your template puts its own control there (`*gfyFormArea`), with its value, its validation and its focus.","*More than forms.* Separators, group boxes, pictures, galleries, displays and components of your own make the skeleton of any page."]),C.heading("What a file holds"),C.terms([["Forms","A file holds one or more forms; a form has elements and variants."],["Elements","Texts (labels, captions, separators), places for the fields and the buttons of your application (a button in a color, a split button and a dropdown button with their menus), content (pictures, galleries, displays, components of your own), groups and subforms."],["Variants","The grids of a form. Each one is used from its `minWidth` up and puts the elements on its cells; an element it does not place is not shown at those widths."],["Layers","Parts of a form of which one is shown at a time, which your application switches: `[layers]=\"{subject: 'company'}\"`. A form may have several groups of them (`subject`, `mode`), and one group needs no name (it is the group `layer`). They are written in the row `layers` of the form in the Inspector: the button of the layers above the grid has *Edit the layers…*."],["Cells","The columns share the width of the form (or a size of its own: px, auto, fr). A row is (the height of a control + the vertical space) / `division` high, so a field takes `division` rows (2 by default)."]]),C.heading("In your application"),C.text("Load the file, give one of its forms to `<gfy-form>` and put your controls into the places by their names. The *Output* window writes the template and a whole component for the form you edit."),C.code("ts","import {gfyLoadFormLayout} from '@gridify/studio';\nimport contactFile from './contact.form.json';\n\nreadonly layout = gfyLoadFormLayout(contactFile).layout;"),C.code("html",`<gfy-form [layout]="layout" name="contact">
1922
+ <gfy-input *gfyFormArea="'name'" [(value)]="name" />
1923
+ <gfy-input *gfyFormArea="'email'" [(value)]="email" />
1924
+ </gfy-form>`),C.heading("The windows"),C.terms([["Toolbox","What can be put into a form. Drag a tool onto the grid, or click it."],["Outline","The file, its forms and their variants, and the elements in the order of the page."],["Editor","The grid of the variant you edit, drawn as `<gfy-form>` lays it out: as wide as the window (*Fit*) or as the slider above it sets, within the widths of the variant."],["Preview","The form working, at a width you choose or drag, or (*Width of the Editor*) as wide as the Editor draws it."],["Inspector","The properties of what is selected: an element, the variant, the form or the file."],["Output","The file, a template and a component that loads the file, to copy or download."],["Problems","What the library would report when it loads the file, what the reading of its text mended, and what the editor checks besides (an element on the frame of its group, a control lower than a control, a function the file does not list). A double click goes there."]]),C.heading("Good to know"),C.points(["Nothing is kept by itself: *File > Download the file* ([Ctrl+S]) saves the file, and with *File > Auto save* on the browser keeps it for the next visit.","An application that gives the editor the files of a project (*Files* in the header of Gridify Designer) adds *File > Open from the project…* ([Ctrl+O]), *Save* ([Ctrl+S]) and *Save as…* ([Ctrl+Shift+S]): Save writes the form layout back into the file it came from, and asks first when that file was changed in the meantime. *Help > Files…* says how it works, and how to write a server of your own.","The title in the middle of the menu bar names the form layout: its file of the project, or where it came from (*New form layout*, *Sample: …*, the name of a file of this computer, *From the clipboard*), with a dot while it has changes that were not saved.","Every change is a step of undo ([Ctrl+Z], [Ctrl+Y]), and the Editor shows what a step changed.","A text that starts with `=` is code: `=t('Name')` is translated when the file is loaded. `t`, `tr`, `tx` and `tk` are the translations of the library, which the loader makes by itself; the functions of the file (the Inspector of the file) are only your own.","The windows are panels of a docking engine: drag a tab to move a window; *View > Reset the windows* puts them back.","`minFormWidth` of the file (click *File* in the *Outline*) is the narrowest a form gets: below it the form keeps that width and its container scrolls. The sliders start at it (without it at 240 px); the one of the Editor goes lower only for a variant that is not used at that width.","A label that should stay beside its field however wide the form gets: right click it, *Columns > Keep the width they have now (px)*. The columns it stands on get the width they have in the Editor now.","An orange frame with ↕ marks an element whose content does not fit its place at the width the Editor draws (a text of one row aligned to its top or its bottom, options in two lines): its tooltip says by how much and what to do.","A subform is drawn faintly in its place, as the Editor of its form draws it (with its first layers and pages): it lies on the cells of the form it stands in and takes its spacing, as the library lays it out (its own spacing counts where it is laid out by itself). What does not lie wholly in the place, such as the rows a flowing subform adds under it, the *Preview* shows. A double click opens its form."])]},{id:"start",title:"Getting started",icon:"fme:flag",blocks:[C.lead("A form in a few steps: start from a sample, change it, try it, and take it to your application."),C.steps([["Open a file","*File > Samples* has a contact form and the forms of the tutorials. *File > Open file* ([Ctrl+O]) opens your own; a file can also be pasted from the clipboard or dropped on the window. *File > New file* starts with an empty form."],["Put elements on the grid","Drag a tool from the *Toolbox* onto a cell, or click it: it goes under what is there. *Fields with a label* bring the label with the field. Or drag over empty cells and choose what goes into the area."],["Name the fields","[F2] renames the selected field, and its label follows. A double click edits what an element shows: a text, a title, a caption."],["Arrange","Drag to move, drag a handle to stretch, or use the arrow keys (with [Shift] they stretch). The buttons above the grid line the selected elements up with the first one you selected. A field or a button is as wide as its place, so buttons on places of one width are as wide as each other (*justify* start in the Inspector: as wide as its text)."],["Set the properties","Click an element and change it in the *Inspector*. A click on empty cells shows the variant; the *Outline* selects the form or the file."],["Add a variant for wider screens","*Add a variant* in the toolbar of the Editor copies the variant for another width (a usual one, or *Another width…*); arrange the form there. What a variant does not place waits in the strip under its grid."],["Try it","The *Preview* shows the form working: drag its slider (or its right edge), and the variants change where the marks are."],["Take it to your application","Download the file ([Ctrl+S]). The *Output* window has the template and a component that loads the file; mend first what the *Problems* window lists."]]),C.note("While you drag, a frame shows where the element goes: green on free cells, orange on cells that are taken. The status bar at the bottom says what was done; a message pops up to say why something could not be.")]},{id:"guides",title:"How-to guides",icon:"fme:guides",blocks:[C.lead("Short recipes for what a form can do beyond the first steps. Each one names the windows and the rows of the *Inspector* it uses; the description under the grid of the Inspector says more about every row."),C.heading("One form for every width"),C.steps([["Start narrow","The variant from `0` px is the one of a phone: put the fields one under another there."],["Add a wider variant","*Add a variant* in the toolbar of the Editor (or *Insert > A variant of this form*) copies the variant for another width. The form uses the variant with the largest `minWidth` that is not above its width."],["Arrange it","Move and stretch the elements there: a variant has places of its own for the same elements. An element that the variant should not show: [Shift+Delete] puts it into the strip under the grid."],["Try the widths","Drag the slider of the *Preview* (or its right edge): the variant changes where the marks are."]]),C.heading("Parts that take turns (layers)"),C.steps([["Name the layers","Click the form in the *Outline* and write its groups of layers in the row `layers` of the *Inspector*: `subject: person, company`. One group needs no name: `person, company` is the group `layer`. *Edit the layers…* in the button of the layers above the grid leads there too."],["Choose the layer you draw","The toolbar of the Editor chooses the layer of every group that is shown. The elements of a layer that is not shown are not drawn, so the elements of two layers can lie on the same cells."],["Put elements into a layer","The button of the layers (*New: …*) says which layer new elements get; an element that is there gets one in its row `layer` of the *Inspector*. An element without a layer is always shown."],["Switch it in your application","`<gfy-form [layout]=\"layout\" [layers]=\"{subject: 'company'}\">`: the first layer of a group is shown until your application chooses another."]]),C.heading("A form inside a form"),C.steps([["Make the inner form","*Insert > A form* adds a form to the file, an address with `street`, `city` and `zip`, say. Draw its fields as in any form."],["Place it","In the outer form, put *Subform* of the *Toolbox* on the cells it takes (with several forms the Toolbox asks which one). Its row `form` in the *Inspector* says which form it places."],["Reach its fields","Your application finds them by a path: `billing.street` is the field `street` of the subform `billing`. The *Component* of the *Output* window puts a `formGroupName` around them."],["Let it grow","With `flow` in the row of its place, a subform may take more rows than its place has: they are added under the place, so its height needs no thought."]]),C.note("One form can be placed several times, as a billing and a delivery address: change it once, and both change."),C.heading("Lists that grow (a list of phones)"),C.steps([["Add it","*Repeated field* of the *Toolbox* adds a group that repeats, with the field, a button that removes it and a button that adds one under it. A group or a subform repeats with `repeat` in the *Inspector*."],["Give it its items","The place holds one instance, and your application says how many there are: a `gfy-repeater` in the place, with an instance for every item of its list. The *Component* of the *Output* window writes it for you."]]),C.heading("Pages with tabs (a property sheet)"),C.text("*Property sheet* of the *Toolbox* adds a frame with tabs and two pages; a click on a tab in the Editor shows and selects its page, and a double click edits its title. Draw the fields of each page on it. The row `tabs` of the place of the sheet puts the tabs on top, at the bottom or at a side, for each variant on its own."),C.heading("The order of the Tab key"),C.text("The order of the elements is the order in which the Tab key goes through the controls and a screen reader reads the form, whatever the places. *View > Set the order of the page* (or its button above the grid): click the elements one after another, and each one takes the next number. The *Outline* shows the order too, and drags change it.")]},Ha({icon:"fme:project-folder",noun:"form layout",component:"FormEditor",selector:"form-editor"}),{id:"keys",title:"Keyboard and mouse",icon:"fme:keyboard",blocks:[C.heading("The mouse in the Editor"),C.keys([["Click","Select an element. On empty cells: select the variant."],["[Ctrl]+click, [Shift]+click","Add to the selection, or take out."],["[Shift]+drag, [Ctrl]+drag","A rectangle, from anywhere: what it touches is added to the selection; a group it touches is added itself, and what is in it goes with it. A rectangle that stays inside a group takes what it touches in the group."],["Drag an element","Move it by whole cells. It goes into a group when it lands inside one."],["Drag a group by its frame, or by the tab above it; a selected group from anywhere in it","Move the group with what is in it. A click without a drag in a selected group selects what is under the pointer. A page of a property sheet is not dragged from inside it: what is on it is."],["Drag a handle","Stretch."],["Drag over empty cells","Draw an area, then choose what goes there."],["Drag a name from the strip under the grid, or a node marked *not placed* from the Outline","Put the element that the variant does not place on the cells under the pointer (green: free). A double click on the name ([Enter] when it has the focus), or *Place all*, puts it into the first free cells."],["Double click","Edit what an element shows (a text, a title, a caption), or rename a field. On a subform: open its form ([Escape] goes back)."],["Click a tab of a property sheet","Show and select its page; a double click edits its title."],["Right click","The commands of an element, of empty cells, of a column or of a row. The menu of an element inserts a row above or below it, a column left or right of it (*Insert*)."],["Click a number around the grid","Select a column or a row: the Inspector has its size, and its menu puts tracks in, takes them out and sizes them."],["[Shift]+click, [Ctrl]+click, drag over the numbers","Select several columns or rows: a range, one more (or one less), the ones the drag passes. The Inspector and the menu of a selected number size them all at once."],["Click, in *Set the order of the page*","Put the element next in its list. Its number turns to the color of the selection, so you see what is in order already."]]),C.heading("The keyboard in the Editor"),C.keys([["[Arrow keys]","Move by a cell."],["[Shift+Arrow keys]","Stretch or shrink, to the right and down."],["[Ctrl+Arrow keys]","Line up the edges with the first selected element (the middles and the sizes: the buttons above the grid, the *Arrange* menu)."],["[Alt+Up], [Alt+Down]","Earlier or later in the order of the page."],["[F2], [Enter]","Edit a text or a title, or rename a field."],["[Delete], [Backspace]","Remove from the form, with the places in all its variants (the toast has Undo)."],["[Shift+Delete]","Not placed in this variant: the element waits in the strip under the grid."],["[Ctrl+C], [Ctrl+X], [Ctrl+V]","Copy, cut, paste."],["[Ctrl+D]","Duplicate."],["[Ctrl+A]","Select everything in the same group."],["[Menu], [Shift+F10]","The menu of the selected element (with nothing selected: of the first cell)."],["[Escape]","Select the group around the element (several elements: none); end a drag, the mode *Set the order of the page*, the selected columns or rows; go back from the form of a subform."]]),C.heading("The Toolbox and the Outline"),C.keys([["Drag a tool onto a cell","Add it there, in its own size."],["Click a tool","Add it under what is in the selected group (a full group grows)."],["Drag in the Outline","Change the order of the page, or move into another group."],["[Alt+Up], [Alt+Down]","Earlier or later in the order of the page."],["[Alt+Left], [Alt+Right]","Out of its group (after it), or into the group above it."],["Right click, [Shift+F10], [Menu]","The menu of the node."],["[F2]","Edit the text, the title or the name of the element in the Editor (one the variant does not draw: in the Inspector)."],["[Delete], [Shift+Delete], [Ctrl+C], [Ctrl+X], [Ctrl+V], [Ctrl+D]","The same as in the Editor."]]),C.heading("Everywhere"),C.keys([["[Ctrl+Z], [Ctrl+Y]","Undo, redo."],["[Ctrl+D]","Duplicate the selected elements."],["[Ctrl+O]","Open a file (with the files of a project: a file of the project)."],["[Ctrl+S]","Download the file (with the files of a project: save it into its file of the project)."],["[Ctrl+Shift+S]","Save as… (with the files of a project)."]])]}]};class rr{store=L(at);rows=M(()=>this.store.inspector()?.rows??[],{...(ngDevMode?{debugName:"rows"}:({})),equal:(e,t)=>JSON.stringify(e)===JSON.stringify(t)});scope=M(()=>{const e=this.store.selection();return`${e.form}|${e.minWidth}|${e.scope}|${e.names.join(",")}|${this.store.refusals()}`},...(ngDevMode?[{debugName:"scope"}]:([])));typed=E(null,...(ngDevMode?[{debugName:"typed"}]:([])));values=M(()=>{const e=this.store.inspector();if(!e)return{};const t=this.rows();return Ba(e.values,this.typed(),this.scope(),o=>t.find(i=>i.id===o)?.kind)},...(ngDevMode?[{debugName:"values"}]:([])));active=E(null,...(ngDevMode?[{debugName:"active"}]:([])));collapsed=E([Kx],...(ngDevMode?[{debugName:"collapsed"}]:([])));describing=M(()=>this.rows().some(e=>e.id===this.active()),...(ngDevMode?[{debugName:"describing"}]:([])));icon=M(()=>{const e=this.store.inspector();const t=this.store.form();if(!e||!t)return"fme:form";if(e.kind==="file")return"fme:file";if(e.kind==="form")return"fme:form";if(e.kind==="variant")return"fme:variant";const o=V(t,this.store.selected()[0]??"");if(!o)return"fme:input";return Hu(o.kind,o.kind==="group"?o.look:void 0,o.kind==="group"||o.kind==="subform"?o.repeat:void 0,o.kind==="input"?o.preview?.as:void 0,o.kind==="static"?o.appearance:void 0)},...(ngDevMode?[{debugName:"icon"}]:([])));pending=null;constructor(){Q(()=>{const e=this.scope();ee(()=>{this.typed.set(null);if(this.pending?.scope!==e)this.pending=null})});Q(()=>{const e=this.active();ee(()=>{if(this.pending&&this.pending.id!==e)this.commit();if(this.typed()?.id!==e)this.typed.set(null)})});L(lt).onDestroy(()=>this.commit())}onChange(e){this.typed.set({scope:this.scope(),id:e.id,value:e.value});if(zu.has(e.id)){if(this.pending?.id!==e.id){this.commit();const t=this.rows().find(o=>o.id===e.id)?.label??e.id;this.store.say(`${t}: Enter or Tab puts it into the file, Escape gives it up.`)}this.pending={scope:this.scope(),id:e.id,value:e.value};return}this.commit();this.store.changeRow(e.id,e.value)}commit(){const e=this.pending;this.pending=null;if(e&&e.scope===this.scope())this.store.changeRow(e.id,e.value)}onGridKey(e){if(e.key==="Enter"&&this.pending)this.commit();else if(e.key==="Escape"&&this.pending){e.stopPropagation();this.pending=null;this.typed.set(null);this.store.say("Given up: the row shows the value of the file.")}}onGridFocusOut(e){const t=e.currentTarget;if(e.relatedTarget instanceof Node&&t.contains(e.relatedTarget))return;this.commit();this.typed.set(null)}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:rr,deps:[],target:w.ɵɵFactoryTarget.Component});static ɵcmp=w.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"21.2.21",type:rr,isStandalone:true,selector:"fme-inspector",ngImport:w,template:`
1925
+ @if (store.inspector(); as inspector) {
1926
+ <div class="head">
1927
+ <span class="ic" [gfyIcon]="icon()"></span>
1928
+ <span class="kind">{{ inspector.title }}</span>
1929
+ <span class="where" [attr.title]="inspector.subtitle">{{ inspector.subtitle }}</span>
1930
+ @if (inspector.kind === 'element') {
1931
+ <gfy-button appearance="flat" iconOnly icon="fme:remove" label="Remove from the form (with its places in all the variants)" (pressed)="store.removeSelected()" />
1932
+ }
1933
+ </div>
1934
+ <gfy-property-grid
1935
+ edFitNames
1936
+ [properties]="rows()"
1937
+ [values]="values()"
1938
+ [(active)]="active"
1939
+ [(collapsed)]="collapsed"
1940
+ [showDescription]="describing()"
1941
+ (propertyChanged)="onChange($event)"
1942
+ (focusout)="onGridFocusOut($event)"
1943
+ (keydown)="onGridKey($event)"
1944
+ ariaLabel="Properties" />
1945
+ } @else {
1946
+ <div class="empty">Select an element in the Editor or the Outline, or the form, a variant or the file in the Outline.</div>
1947
+ }
1948
+ `,isInline:true,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n",".ic{flex:none;display:grid;width:var(--ic, 14px);height:var(--ic, 14px)}\n",".head{flex:none;display:flex;align-items:center;gap:8px;padding:6px 10px;background:var(--gfy-bg-header, transparent);border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3))}.head .ic{--ic: 16px;color:var(--gfy-accent, #3a8fd6)}.head .kind{font-weight:600;white-space:nowrap}.head .where{min-width:0;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;opacity:.88;font-family:var(--gfy-font-mono, Consolas, monospace);font-size:12px}gfy-property-grid{flex:1 1 auto;min-height:0}\n"],dependencies:[{kind:"component",type:ke,selector:"gfy-button",inputs:["label","icon","iconOnly","tooltip","ariaLabel","caret","variant","appearance","layout","toggle","checked","disabled","busy","type","name","haspopup","expanded","controls","joined","attached","reserveLabelSpace"],outputs:["checkedChange","pressed"]},{kind:"directive",type:mt,selector:"[gfyIcon]",inputs:["gfyIcon"]},{kind:"component",type:Tt,selector:"gfy-property-grid",inputs:["properties","values","view","nameWidth","showDescription","showToolbar","filter","collapsed","active","disabled","ariaLabel"],outputs:["valuesChange","viewChange","nameWidthChange","filterChange","collapsedChange","activeChange","propertyChanged"]},{kind:"directive",type:st,selector:"gfy-property-grid[edFitNames]"}]})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:rr,decorators:[{type:me,args:[{selector:"fme-inspector",standalone:true,imports:[ke,mt,Tt,st],template:`
1949
+ @if (store.inspector(); as inspector) {
1950
+ <div class="head">
1951
+ <span class="ic" [gfyIcon]="icon()"></span>
1952
+ <span class="kind">{{ inspector.title }}</span>
1953
+ <span class="where" [attr.title]="inspector.subtitle">{{ inspector.subtitle }}</span>
1954
+ @if (inspector.kind === 'element') {
1955
+ <gfy-button appearance="flat" iconOnly icon="fme:remove" label="Remove from the form (with its places in all the variants)" (pressed)="store.removeSelected()" />
1956
+ }
1957
+ </div>
1958
+ <gfy-property-grid
1959
+ edFitNames
1960
+ [properties]="rows()"
1961
+ [values]="values()"
1962
+ [(active)]="active"
1963
+ [(collapsed)]="collapsed"
1964
+ [showDescription]="describing()"
1965
+ (propertyChanged)="onChange($event)"
1966
+ (focusout)="onGridFocusOut($event)"
1967
+ (keydown)="onGridKey($event)"
1968
+ ariaLabel="Properties" />
1969
+ } @else {
1970
+ <div class="empty">Select an element in the Editor or the Outline, or the form, a variant or the file in the Outline.</div>
1971
+ }
1972
+ `,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n",".ic{flex:none;display:grid;width:var(--ic, 14px);height:var(--ic, 14px)}\n",".head{flex:none;display:flex;align-items:center;gap:8px;padding:6px 10px;background:var(--gfy-bg-header, transparent);border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3))}.head .ic{--ic: 16px;color:var(--gfy-accent, #3a8fd6)}.head .kind{font-weight:600;white-space:nowrap}.head .where{min-width:0;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;opacity:.88;font-family:var(--gfy-font-mono, Consolas, monospace);font-size:12px}gfy-property-grid{flex:1 1 auto;min-height:0}\n"]}]}],ctorParameters:()=>[]});const P1={static:"#8b5cf6",input:"#2f80ed",group:"#1f9d55",subform:"#e07b00"};const Es={error:"var(--gfy-danger, #e51400)",warning:"var(--gfy-warning, #d9a300)"};const ic=n=>`form:${n}`;const rc=(n,e)=>`el:${n}:${e}`;function Dt(n){if(n==="file")return{kind:"file"};const[e,t,o]=n.split(":");if(e==="form"||e==="variants")return{kind:e,form:t};if(e==="variant")return{kind:e,form:t,minWidth:Number(o)};if(e==="el")return{kind:e,form:t,name:n.slice(`el:${t}:`.length)};return null}function W1(n,e){switch(n.kind){case"static":if(n.appearance==="separator")return`separator${cn(n.text)?` "${cn(n.text)}"`:""}`;return`"${cn(n.text)}"${n.for?` → ${n.for}`:""}`;case"input":if(it(n.preview?.as))return`<${n.preview.as}>`;return n.preview?.as?Ph[n.preview.as]??n.preview.as:"input";case"group":return e?`page "${cn(n.title)||n.name}"`:n.look==="property-sheet"?"property sheet":n.look==="none"?n.repeat?"repeated group":"group":`group box${n.title?` "${cn(n.title)}"`:""}`;case"subform":return`subform → ${n.form}${n.repeat?", repeated":""}`}}class sr{store=L(at);expanded=E(/* @__PURE__ */new Set(["file"]),...(ngDevMode?[{debugName:"expanded"}]:([])));known=/* @__PURE__ */new Set;addItems=M(()=>Is(this.store,(e,t)=>this.store.addTool(e,null,t)).slice(1),...(ngDevMode?[{debugName:"addItems"}]:([])));moveRules={element:{into:["form","group"]},group:{into:["form","group"]}};selectedId=M(()=>{const e=this.store.selection();if(e.names.length)return rc(e.form,e.names[0]);if(e.scope==="file")return"file";if(e.scope==="form")return ic(e.form);return`variant:${e.form}:${e.minWidth}`},...(ngDevMode?[{debugName:"selectedId"}]:([])));nodes=M(()=>{const e=this.store.file();const t=this.store.selection();const o=this.store.problemsByElement();const i=this.store.placedByName();const r=this.store.problems();const s=/* @__PURE__ */new Map;for(const c of r){const p=c.target?.form;if(!p||c.severity==="info"||c.code==="unplaced")continue;if(s.get(p)!=="error")s.set(p,c.severity)}const a=new Set(r.filter(c=>c.code==="unplaced"&&c.target?.form===t.form&&c.target.minWidth===t.minWidth&&c.target.element).map(c=>c.target.element));const l=(c,p,h)=>{const u=c.name===t.form;const f=u?o.get(p.name):void 0;const m=i.get(p.name);const g=u&&!m?.cells;const y=!m?.parent||Boolean(i.get(m.parent)?.cells);const b=g&&a.has(p.name);const x=ce(p).map(T=>l(c,T,W(p)));return{id:rc(c.name,p.name),label:p.name,icon:Hu(p.kind,p.kind==="group"?p.look:void 0,p.kind==="group"||p.kind==="subform"?p.repeat:void 0,p.kind==="input"?p.preview?.as:void 0,p.kind==="static"?p.appearance:void 0),iconColor:f?Es[f]:b?Es.warning:P1[p.kind],description:`${W1(p,h)}${p.layer?` · ${p.layer}`:""}`,badge:[(p.kind==="group"||p.kind==="subform")&&p.repeat?"×N":"",g&&y?"not placed":""].filter(T=>T!=="").join(" · ")||void 0,title:!g?void 0:y?`"${p.name}" has no place in the variant from ${t.minWidth} px: it is not shown at those widths${b?", and its control is not shown at all there (a warning in Problems)":""}. Drag this node onto the grid of the Editor (or its name in the strip under the grid; a double click there puts it into the first free cells), or "Place in this variant" in the menu of this node.`:`"${p.name}" is not shown in the variant from ${t.minWidth} px: "${m?.parent}", which it is in, has no place there. Place that one, and what is in it comes with it.`,style:g?{opacity:0.88,"font-style":"italic"}:void 0,kind:p.kind==="group"?"group":"element",children:x.length?x:p.kind==="group"?[]:void 0}};const d=e.forms.map(c=>{const p=s.get(c.name);const h={id:`variants:${c.name}`,label:"Variants",icon:"fme:variant",description:`${c.variants.length}`,children:Nt(c).map(u=>{const f=Ne(c,u);const m=new Map(f.map(b=>[b.name,b.cells]));const g=f.filter(b=>b.cells===null&&(b.parent===null||m.get(b.parent)!==null));const y=r.some(b=>b.code==="unplaced"&&b.target?.form===c.name&&b.target.minWidth===u.minWidth);return{id:`variant:${c.name}:${u.minWidth}`,label:`≥ ${u.minWidth} px`,icon:"fme:variant",iconColor:y?Es.warning:void 0,description:`${u.cols} × ${u.rows} cells${g.length?` · ${g.length} not placed`:""}`,title:g.length?`Not placed in this variant: ${g.map(b=>b.name).join(", ")}`:void 0}})};return{id:ic(c.name),label:c.name,icon:"fme:form",iconColor:p?Es[p]:void 0,description:`${c.elements.length?"":"empty · "}${c.layers?.length?`layers: ${c.layers.map(u=>u.name).join(", ")}`:""}`.replace(/ · $/,""),kind:"form",children:[h,...c.elements.map(u=>l(c,u,false))]}});return[{id:"file",label:"File",icon:"fme:file",description:`${e.forms.length} ${e.forms.length===1?"form":"forms"}`,children:d}]},...(ngDevMode?[{debugName:"nodes"}]:([])));constructor(){L(lt).onDestroy(()=>this.unfollow?.());Q(()=>{const e=this.nodes();const t=this.selectedId();ee(()=>{const o=new Set(this.expanded());let i=false;const r=l=>{if(!o.has(l)){o.add(l);i=true}};const s=l=>{for(const d of l){if(!this.known.has(d.id)){this.known.add(d.id);if(d.id==="file"||d.id.startsWith("form:")||d.kind==="group"&&d.id.startsWith(`el:${this.store.selection().form}:`))r(d.id)}if(d.children)s(d.children)}};s(e);const a=Dt(t);if(a&&a.kind!=="file"){r("file");r(ic(a.form));if(a.kind==="variant")r(`variants:${a.form}`);if(a.kind==="el"){const l=this.store.file().forms.find(c=>c.name===a.form);const d=l?ge(l,a.name)?.ancestors??[]:[];for(const c of d)r(rc(a.form,c))}}if(i)this.expanded.set(o)})})}onSelected(e){const t=e===null?null:Dt(e);if(!t)return;switch(t.kind){case"file":this.store.selectFile();return;case"form":this.store.selectForm(t.form,"form");return;case"variants":this.store.selectForm(t.form,"variant");return;case"variant":if(t.form!==this.store.selection().form)this.store.selectForm(t.form,"variant");this.store.selectVariant(t.minWidth);return;case"el":if(t.form!==this.store.selection().form)this.store.selectForm(t.form,"variant");this.store.select([t.name]);return}}canMove=e=>{const t=Dt(e.node.id);const o=e.parentId===null?null:Dt(e.parentId);if(!t||t.kind!=="el"||!o)return false;const i=this.store.file().forms.find(l=>l.name===t.form);if(!i)return false;const r=e.previousParentId===null?null:Dt(e.previousParentId);const s=r?.kind==="el"&&W(V(i,r.name));if(o.kind==="form")return o.form===t.form&&e.index>=1&&!s;if(o.kind!=="el"||o.form!==t.form)return false;const a=W(V(i,o.name));if(s||a)return s&&a&&r?.kind==="el"&&r.name===o.name;return true};onMoved(e){const t=Dt(e.node.id);const o=e.parentId===null?null:Dt(e.parentId);if(!t||t.kind!=="el"||!o)return;if(t.form!==this.store.selection().form)this.store.selectForm(t.form,"variant");if(o.kind==="form")this.store.moveInTree(t.name,null,Math.max(0,e.index-1));else if(o.kind==="el")this.store.moveInTree(t.name,o.name,e.index)}unfollow=null;onTreePress(e){this.unfollow?.();if(e.button!==0||e.ctrlKey||e.metaKey||e.shiftKey||!(e.target instanceof Element))return;const t=e.target.closest("[data-node]")?.getAttribute("data-node");const o=t?Dt(t):null;if(o?.kind!=="el"||o.form!==this.store.selection().form||!this.store.unplaced().some(c=>c.name===o.name))return;const i=o.name;const r=e.pointerId;let s=false;const a=c=>{if(c.pointerId!==r)return;if(!s&&Math.hypot(c.clientX-e.clientX,c.clientY-e.clientY)<5)return;s=true;this.store.placeTarget?.over(i,c.clientX,c.clientY)};const l=c=>{if(c.pointerId!==r)return;this.unfollow?.();if(s)this.store.placeTarget?.drop(i,c.clientX,c.clientY)};const d=c=>{if(c instanceof KeyboardEvent&&c.key!=="Escape")return;this.unfollow?.();this.store.placeTarget?.leave()};window.addEventListener("pointermove",a,true);window.addEventListener("pointerup",l,true);window.addEventListener("pointercancel",d,true);window.addEventListener("keydown",d,true);this.unfollow=()=>{window.removeEventListener("pointermove",a,true);window.removeEventListener("pointerup",l,true);window.removeEventListener("pointercancel",d,true);window.removeEventListener("keydown",d,true);this.unfollow=null}}onKey(e){const t=e.event.key;const o=e.event.ctrlKey||e.event.metaKey;const i=Dt(e.node.id);if(i?.kind!=="el")return;const r=t==="Delete"||t==="Backspace";if(r&&e.event.shiftKey)this.store.unplaceSelected();else if(r)this.store.removeSelected();else if(o&&t.toLowerCase()==="d")this.store.duplicateSelected();else if(o&&t.toLowerCase()==="c")this.store.copySelected();else if(o&&t.toLowerCase()==="x")this.store.cutSelected();else if(o&&t.toLowerCase()==="v")this.store.paste();else if(t==="F2"&&!o&&!e.event.altKey&&!e.event.shiftKey)this.store.editInPlace(i.name);else return;e.event.preventDefault()}menu=e=>{const t=Dt(e.id);if(!t)return[];const o=this.store;switch(t.kind){case"file":o.selectFile();return[{label:"Add a &form",icon:"fme:add-form",run:()=>o.addForm()}];case"form":case"variants":{o.selectForm(t.form,t.kind==="form"?"form":"variant");const i=o.file().forms;const r=i.findIndex(s=>s.name===t.form);return[{label:"Add a &form",icon:"fme:add-form",run:()=>o.addForm()},{label:"&Duplicate the form",icon:"fme:duplicate",run:()=>o.duplicateForm(t.form)},{label:"Move &up",icon:"fme:up",enabled:r>0,run:()=>o.moveForm(t.form,-1)},{label:"Move do&wn",icon:"fme:down",enabled:r<i.length-1,run:()=>o.moveForm(t.form,1)},{separator:true},{label:"Add a &variant",icon:"fme:add-variant",children:[...o.variantProposals().map(s=>({label:`From ${s} px (a copy of the one from ${o.selection().minWidth} px)`,run:()=>o.addVariant(s)})),{label:"From another width…",run:()=>void o.addVariantOfWidth()}]},{separator:true},{label:"&Remove the form…",icon:"fme:remove",enabled:i.length>1,run:()=>void o.removeForm(t.form)}]}case"variant":if(t.form!==o.selection().form)o.selectForm(t.form,"variant");o.selectVariant(t.minWidth);return[{label:"Add a &variant",icon:"fme:add-variant",children:[...o.variantProposals().map(i=>({label:`From ${i} px (a copy of this one)`,run:()=>o.addVariant(i)})),{label:"From another width…",run:()=>void o.addVariantOfWidth()}]},...Ju(o),{separator:true},{label:"&Remove the variant…",icon:"fme:remove",enabled:o.variants().length>1,run:()=>void o.removeVariant()}];case"el":if(t.form!==o.selection().form)o.selectForm(t.form,"variant");return Ds(o,t.name,"outline")}};static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:sr,deps:[],target:w.ɵɵFactoryTarget.Component});static ɵcmp=w.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"21.2.21",type:sr,isStandalone:true,selector:"fme-outline",ngImport:w,template:`
1973
+ <div class="tb">
1974
+ <gfy-button appearance="flat" iconOnly icon="fme:undo" label="Undo" [disabled]="!store.canUndo()" (pressed)="store.undo()" />
1975
+ <gfy-button appearance="flat" iconOnly icon="fme:redo" label="Redo" [disabled]="!store.canRedo()" (pressed)="store.redo()" />
1976
+ <span class="sep" aria-hidden="true"></span>
1977
+ <gfy-dropdown-button appearance="flat" iconOnly icon="fme:place" label="Add to the selected group" [items]="addItems()" />
1978
+ <gfy-button appearance="flat" iconOnly icon="fme:add-form" label="Add a form" (pressed)="store.addForm()" />
1979
+ <span class="sep" aria-hidden="true"></span>
1980
+ <gfy-button appearance="flat" iconOnly icon="fme:duplicate" label="Duplicate" [disabled]="!store.capabilities().duplicate" (pressed)="store.duplicateSelected()" />
1981
+ <gfy-button appearance="flat" iconOnly icon="fme:remove" label="Remove from the form (Delete)" [disabled]="!store.capabilities().remove" (pressed)="store.removeSelected()" />
1982
+ </div>
1983
+ <gfy-tree
1984
+ (pointerdown)="onTreePress($event)"
1985
+ [nodes]="nodes()"
1986
+ [selected]="selectedId()"
1987
+ (selectedChange)="onSelected($event)"
1988
+ [(expanded)]="expanded"
1989
+ [nodeMenu]="menu"
1990
+ [moveRules]="moveRules"
1991
+ [canMove]="canMove"
1992
+ (nodeMoved)="onMoved($event)"
1993
+ [tools]="['collapseAll', 'expandAll']"
1994
+ filterable
1995
+ guides
1996
+ ariaLabel="Outline"
1997
+ (nodeKeydown)="onKey($event)" />
1998
+ `,isInline:true,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n","gfy-tree{flex:1 1 auto;min-height:0}gfy-tree ::ng-deep .bar{padding:6px}\n"],dependencies:[{kind:"component",type:ke,selector:"gfy-button",inputs:["label","icon","iconOnly","tooltip","ariaLabel","caret","variant","appearance","layout","toggle","checked","disabled","busy","type","name","haspopup","expanded","controls","joined","attached","reserveLabelSpace"],outputs:["checkedChange","pressed"]},{kind:"component",type:mn,selector:"gfy-dropdown-button"},{kind:"component",type:Kn,selector:"gfy-tree",inputs:["nodes","expanded","selected","selection","selectionMode","checkboxes","checked","checkMode","filter","filterable","filterMatch","twisty","guides","activateOnClick","tools","toolbar","collapseToLevel","nodeMenu","ariaLabel","emptyText","moveRules","canMove"],outputs:["expandedChange","selectedChange","selectionChange","checkedChange","filterChange","nodeActivated","nodeToggled","nodeChecked","nodeMoved","nodeKeydown"]}]})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:sr,decorators:[{type:me,args:[{selector:"fme-outline",standalone:true,imports:[ke,mn,Kn],template:`
1999
+ <div class="tb">
2000
+ <gfy-button appearance="flat" iconOnly icon="fme:undo" label="Undo" [disabled]="!store.canUndo()" (pressed)="store.undo()" />
2001
+ <gfy-button appearance="flat" iconOnly icon="fme:redo" label="Redo" [disabled]="!store.canRedo()" (pressed)="store.redo()" />
2002
+ <span class="sep" aria-hidden="true"></span>
2003
+ <gfy-dropdown-button appearance="flat" iconOnly icon="fme:place" label="Add to the selected group" [items]="addItems()" />
2004
+ <gfy-button appearance="flat" iconOnly icon="fme:add-form" label="Add a form" (pressed)="store.addForm()" />
2005
+ <span class="sep" aria-hidden="true"></span>
2006
+ <gfy-button appearance="flat" iconOnly icon="fme:duplicate" label="Duplicate" [disabled]="!store.capabilities().duplicate" (pressed)="store.duplicateSelected()" />
2007
+ <gfy-button appearance="flat" iconOnly icon="fme:remove" label="Remove from the form (Delete)" [disabled]="!store.capabilities().remove" (pressed)="store.removeSelected()" />
2008
+ </div>
2009
+ <gfy-tree
2010
+ (pointerdown)="onTreePress($event)"
2011
+ [nodes]="nodes()"
2012
+ [selected]="selectedId()"
2013
+ (selectedChange)="onSelected($event)"
2014
+ [(expanded)]="expanded"
2015
+ [nodeMenu]="menu"
2016
+ [moveRules]="moveRules"
2017
+ [canMove]="canMove"
2018
+ (nodeMoved)="onMoved($event)"
2019
+ [tools]="['collapseAll', 'expandAll']"
2020
+ filterable
2021
+ guides
2022
+ ariaLabel="Outline"
2023
+ (nodeKeydown)="onKey($event)" />
2024
+ `,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n","gfy-tree{flex:1 1 auto;min-height:0}gfy-tree ::ng-deep .bar{padding:6px}\n"]}]}],ctorParameters:()=>[]});const K1={file:"File",template:"Template",component:"Component"};const _1={file:"The file of the editor (\"format\": \"gfy-form-layout\"): open it again here, and load it in the application with gfyLoadFormLayout.",template:"The template of the form that is edited: <gfy-form> with a control for every place (*gfyFormArea), a gfy-repeater for every part that repeats and a formGroupName around the fields of a subform. Put it into a [formGroup].",component:"A component that loads the file, lays out the form that is edited and has a reactive form with a control for every place: a start to change into the form of your application."};const G1={file:"json",template:"html",component:"ts"};class ar{store=L(at);options=A1.map(e=>({value:e,label:K1[e]}));labels={form:"Form of the output",output:"Output",copy:"Copy",download:"Download"};description=M(()=>_1[this.store.outputKind()],...(ngDevMode?[{debugName:"description"}]:([])));language=M(()=>G1[this.store.outputKind()],...(ngDevMode?[{debugName:"language"}]:([])));onKind(e){this.store.outputKind.set(e)}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:ar,deps:[],target:w.ɵɵFactoryTarget.Component});static ɵcmp=w.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"21.2.21",type:ar,isStandalone:true,selector:"fme-output",ngImport:w,template:`
2025
+ <editor-output
2026
+ [kinds]="options"
2027
+ [kind]="store.outputKind()"
2028
+ [labels]="labels"
2029
+ [description]="description()"
2030
+ [language]="language()"
2031
+ [text]="store.output()"
2032
+ copyIcon="fme:copy"
2033
+ downloadIcon="fme:download"
2034
+ (kindChange)="onKind($event)"
2035
+ (copyPressed)="store.copyOutput()"
2036
+ (downloadPressed)="store.downloadOutput()" />
2037
+ `,isInline:true,styles:[":host{display:block;height:100%;min-height:0}\n"],dependencies:[{kind:"component",type:Et,selector:"editor-output",inputs:["kinds","kind","labels","description","language","text","copyIcon","downloadIcon"],outputs:["kindChange","copyPressed","downloadPressed"]}]})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:ar,decorators:[{type:me,args:[{selector:"fme-output",standalone:true,imports:[Et],template:`
2038
+ <editor-output
2039
+ [kinds]="options"
2040
+ [kind]="store.outputKind()"
2041
+ [labels]="labels"
2042
+ [description]="description()"
2043
+ [language]="language()"
2044
+ [text]="store.output()"
2045
+ copyIcon="fme:copy"
2046
+ downloadIcon="fme:download"
2047
+ (kindChange)="onKind($event)"
2048
+ (copyPressed)="store.copyOutput()"
2049
+ (downloadPressed)="store.downloadOutput()" />
2050
+ `,styles:[":host{display:block;height:100%;min-height:0}\n"]}]}]});const B1={"gfy-input":Ps,"gfy-password":Of,"gfy-date-picker":Cf,"gfy-textarea":Af,"gfy-select":$f,"gfy-combobox":Mf,"gfy-checkbox":Bs,"gfy-radio-group":Tf,"gfy-switch":Sf,"gfy-spinner":Gs,"gfy-button":ke,"gfy-split-button":kf,"gfy-dropdown-button":mn,"gfy-time-picker":xf,"gfy-date-time-picker":vf,"gfy-mask-input":wf,"gfy-multi-select":yf,"gfy-tags":bf,"gfy-slider":_o,"gfy-toggle-group":St,"gfy-color-picker":gf,"gfy-file-upload":mf,"gfy-picture":ff,"gfy-picture-gallery":uf,"gfy-digital-display":hf};function nf(n){const e=(o,i,r)=>`hsl(${o%360},${i}%,${r}%)`;const t=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 100"><defs><linearGradient id="sky" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="${e(n,70,80)}"/><stop offset="1" stop-color="${e(n,60,94)}"/></linearGradient></defs><rect width="160" height="100" fill="url(#sky)"/><circle cx="122" cy="28" r="12" fill="${e(n+180,85,72)}"/><path d="M0 78 38 44l26 22 22-18 40 30H0z" fill="${e(n,28,58)}"/><path d="M0 100V84l30-14 34 16 30-20 66 26v8z" fill="${e(n,32,38)}"/></svg>`;return`data:image/svg+xml,${encodeURIComponent(t)}`}function V1(n){const e=typeof n==="string"&&n!==""?n:"9999";const t=e.indexOf(".");const o=(t<0?e:e.slice(0,t)).split("9").length-1;const i=t<0?0:e.slice(t).split("9").length-1;const r="12345678901234567890";return Number(`${r.slice(0,Math.max(1,o))}.${r.slice(o,o+i)||"0"}`)}function H1(n,e,t,o){if(t.has("options")&&!Array.isArray(e["options"]))e["options"]=n==="gfy-combobox"?["First","Second","Third"]:["First","Second","Third"].map(r=>({value:r,label:r}));if((n==="gfy-checkbox"||n==="gfy-switch")&&!("label"in e))e["label"]=o;const i=n==="gfy-button"||n==="gfy-split-button"||n==="gfy-dropdown-button";if(!("ariaLabel"in e)&&t.has("ariaLabel")&&!i)e["ariaLabel"]=o;if(i&&!("label"in e))e["label"]=o;if(t.has("items")&&n!=="gfy-picture-gallery"&&!Array.isArray(e["items"]))e["items"]=[{label:"First"},{label:"Second"}];if(n==="gfy-textarea"&&t.has("fill"))e["fill"]=true;switch(n){case"gfy-mask-input":if(!("ghost"in e)&&t.has("ghost"))e["ghost"]=true;break;case"gfy-slider":{const r=typeof e["min"]==="number"?e["min"]:0;const s=typeof e["max"]==="number"?e["max"]:100;if(!("value"in e))e["value"]=Math.round(r+(s-r)*0.4);break}case"gfy-picture":if(!("src"in e))e["src"]=nf(205);if(!("alt"in e))e["alt"]=o;break;case"gfy-picture-gallery":if(!("items"in e))e["items"]=[205,150,30,275].map((r,s)=>({src:nf(r),alt:`${o} ${s+1}`}));if(!("label"in e)&&t.has("label"))e["label"]=o;break;case"gfy-digital-display":if(!("value"in e)&&(e["mode"]===void 0||e["mode"]==="value"))e["value"]=V1(e["format"]);break}}const of=/* @__PURE__ */new Map;function q1(n){let e=of.get(n);if(!e){e=new Set((af(n)?.inputs??[]).map(t=>t.templateName));of.set(n,e)}return e}class Fo{injector=Fs.create({providers:[{provide:uc,useValue:L(uc)},{provide:fc,useValue:L(fc,{optional:true})}],parent:L(Fs)});static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Fo,deps:[],target:w.ɵɵFactoryTarget.Directive});static ɵdir=w.ɵɵngDeclareDirective({minVersion:"14.0.0",version:"21.2.21",type:Fo,isStandalone:true,selector:"[fmePlace]",exportAs:["fmePlace"],ngImport:w})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:Fo,decorators:[{type:zs,args:[{selector:"[fmePlace]",standalone:true,exportAs:"fmePlace"}]}]});function zi(n,e,t,o,i){const r=[];for(const s of e){const a=`${t}${s.name}`;switch(s.kind){case"static":break;case"input":{const l=s.preview?.as;const d=s.preview?.props??{};if(l==="gfy-label"){r.push({path:a,kind:"label",text:typeof d["text"]==="string"?d["text"]:s.name});break}if(l&&it(l)){r.push({path:a,kind:"own",text:`<${l}>`});break}const c=l?B1[l]:void 0;if(!l||!c){r.push({path:a,kind:"box",text:a});break}const p=q1(c);const h={};for(const[u,f]of Object.entries(d))if(p.has(u))h[u]=f;H1(l,h,p,s.name);r.push({path:a,kind:"control",component:c,inputs:h});break}case"group":{if(s.repeat&&!i){r.push({path:a,kind:"list",inner:zi(n,s.elements,"",o,true),items:["",""]});break}r.push(...zi(n,s.elements,t,o,i));break}case"subform":{const l=o.includes(s.form)?void 0:n.forms.find(d=>d.name===s.form);if(!l)break;if(s.repeat&&!i){r.push({path:a,kind:"list",inner:zi(n,l.elements,"",[...o,l.name],true),items:[{},{}]});break}r.push(...zi(n,l.elements,s.repeat?"":`${a}.`,[...o,l.name],i));break}}}return r}class lr{store=L(at);stageRef=ct.required("stage");stageWidth=E(0,...(ngDevMode?[{debugName:"stageWidth"}]:([])));shownVariant=E(null,...(ngDevMode?[{debugName:"shownVariant"}]:([])));hasForm=M(()=>this.store.layout()?.forms.some(e=>e.name===this.store.selection().form)??false,...(ngDevMode?[{debugName:"hasForm"}]:([])));places=M(()=>{const e=this.store.layout();const t=e?.forms.find(o=>o.name===this.store.selection().form);return e&&t?zi(e,t.elements,"",[t.name],false):[]},...(ngDevMode?[{debugName:"places"}]:([])));pages=M(()=>this.store.view().pages[this.store.selection().form]??{},...(ngDevMode?[{debugName:"pages"}]:([])));slideRange=M(()=>{const e=Math.max(0,...this.store.variants().map(i=>i.minWidth));const t=this.store.minFormWidth();const o=t>0?t:240;return{min:o,max:Math.max(1280,e+480,o+10)}},...(ngDevMode?[{debugName:"slideRange"}]:([])));marks=M(()=>{const{min:e,max:t}=this.slideRange();return this.store.variants().filter(o=>o.minWidth>e&&o.minWidth<t).map(o=>({minWidth:o.minWidth,left:`calc(7px + (100% - 14px) * ${(o.minWidth-e)/(t-e)})`}))},...(ngDevMode?[{debugName:"marks"}]:([])));marksTitle=M(()=>{const e=this.store.variants().map(t=>t.minWidth);return`The marks are the variants: from ${e.join(", ")} px`},...(ngDevMode?[{debugName:"marksTitle"}]:([])));pxText=e=>`${e} px`;framePadding=16;width=M(()=>{const e=this.store.minFormWidth();const t=this.follows()?this.store.editorWidth():null;const o=t??this.store.view().previewWidth??Math.max(200,this.stageWidth()-48-this.framePadding*2);return Math.max(o,e>0?e:120)},...(ngDevMode?[{debugName:"width"}]:([])));follows=M(()=>this.store.view().previewFollows===true&&this.store.editorWidth()!==null,...(ngDevMode?[{debugName:"follows"}]:([])));info=M(()=>{const e=this.shownVariant();return e===null?"":`The variant from ${e} px`},...(ngDevMode?[{debugName:"info"}]:([])));layerGroups=M(()=>{const e=this.store.active();return(this.store.form()?.layers??[]).map(t=>({name:t.name,value:Object.prototype.hasOwnProperty.call(e,t.name)?e[t.name]:t.layers[0]??"",options:t.layers.map(o=>({value:o,label:o}))}))},...(ngDevMode?[{debugName:"layerGroups"}]:([])));constructor(){const e=L(lt);ur(()=>{const t=this.stageRef().nativeElement;const o=new ResizeObserver(()=>this.stageWidth.set(t.clientWidth));o.observe(t);this.stageWidth.set(t.clientWidth);e.onDestroy(()=>o.disconnect())});e.onDestroy(()=>this.stopResize?.())}onFit(e){this.store.setPreviewWidth(e?null:this.width())}onSlide(e){this.store.setPreviewWidth(e)}onLayer(e,t){if(t!==null)this.store.setLayer(e,t)}onPages(e){for(const[t,o]of Object.entries(e))if(this.pages()[t]!==o)this.store.showPage(t,o)}onVariant(e){this.shownVariant.set(e.minWidth)}stopResize=null;startResize(e){if(e.button!==0)return;e.preventDefault();this.stopResize?.();const t=e.pointerId;const o=e.clientX;const i=this.width();const r=this.store.view().previewWidth;const s=this.slideRange().max;const a=p=>{if(p.pointerId===t)this.store.setPreviewWidth(Math.min(s,i+p.clientX-o))};const l=p=>{if(p.pointerId===t)c()};const d=p=>{if(p.key!=="Escape")return;p.preventDefault();p.stopPropagation();this.store.setPreviewWidth(r);c()};const c=()=>{window.removeEventListener("pointermove",a);window.removeEventListener("pointerup",l);window.removeEventListener("pointercancel",l);window.removeEventListener("keydown",d,true);this.stopResize=null};this.stopResize=c;window.addEventListener("pointermove",a);window.addEventListener("pointerup",l);window.addEventListener("pointercancel",l);window.addEventListener("keydown",d,true)}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:lr,deps:[],target:w.ɵɵFactoryTarget.Component});static ɵcmp=w.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"21.2.21",type:lr,isStandalone:true,selector:"fme-preview",viewQueries:[{propertyName:"stageRef",first:true,predicate:["stage"],descendants:true,isSignal:true}],ngImport:w,template:`
2051
+ <!-- two rows, as in the Editor: what is shown (the variant of the width, the layers), and under it the width -->
2052
+ <div class="tb upper">
2053
+ <span class="info">{{ info() }}</span>
2054
+ <span class="sp"></span>
2055
+ @for (group of layerGroups(); track group.name) {
2056
+ @if (!$first) {
2057
+ <span class="sep" aria-hidden="true"></span>
2058
+ }
2059
+ <span class="label">{{ group.name }}</span>
2060
+ <gfy-toggle-group [options]="group.options" [value]="group.value" (valueChange)="onLayer(group.name, $event)" [ariaLabel]="'The layer of ' + group.name" />
2061
+ }
2062
+ </div>
2063
+ <div class="tb">
2064
+ <gfy-checkbox
2065
+ class="follow"
2066
+ label="Width of the Editor"
2067
+ title="The form is as wide as in the Editor: the width follows the slider of the Editor (and its Fit), and the width here is off"
2068
+ [reserveMessageSpace]="false"
2069
+ [checked]="store.view().previewFollows === true"
2070
+ (checkedChange)="store.setPreviewFollows($event)" />
2071
+ <span class="sp"></span>
2072
+ <span class="widths" role="group" aria-label="The width of the form">
2073
+ <gfy-button toggle appearance="flat" label="Fit" tooltip="As wide as the window" [disabled]="follows()" [checked]="store.view().previewWidth === null && !follows()" (checkedChange)="onFit($event)" />
2074
+ <!-- a mark on the track for every variant: where the form changes its variant -->
2075
+ <span class="slide" [title]="marksTitle()">
2076
+ @for (mark of marks(); track mark.minWidth) {
2077
+ <span class="mark" aria-hidden="true" [style.left]="mark.left"></span>
2078
+ }
2079
+ <gfy-slider ariaLabel="The width of the form in the Preview" [disabled]="follows()" [min]="slideRange().min" [max]="slideRange().max" [value]="width()" [valueText]="pxText" (valueChange)="onSlide($event)" />
2080
+ </span>
2081
+ <span class="px">{{ width() }} px</span>
2082
+ </span>
2083
+ </div>
2084
+ <div #stage class="stage">
2085
+ @if (store.layout() && hasForm()) {
2086
+ <div class="frame" [style.width.px]="width() + framePadding * 2">
2087
+ <gfy-form [layout]="store.layout()" [name]="store.selection().form" [layers]="store.active()" [pages]="pages()" (pagesChange)="onPages($event)" (variantChanged)="onVariant($event)">
2088
+ @for (place of places(); track place.path) {
2089
+ @switch (place.kind) {
2090
+ @case ('control') {
2091
+ <ng-container *gfyFormArea="place.path"
2092
+ ><ng-container fmePlace #own="fmePlace"><ng-container *ngComponentOutlet="place.component!; inputs: place.inputs!; injector: own.injector" /></ng-container
2093
+ ></ng-container>
2094
+ }
2095
+ @case ('label') {
2096
+ <gfy-label *gfyFormArea="place.path">{{ place.text }}</gfy-label>
2097
+ }
2098
+ @case ('box') {
2099
+ <div *gfyFormArea="place.path" class="box" [attr.title]="place.text">
2100
+ <span>{{ place.text }}</span>
2101
+ </div>
2102
+ }
2103
+ @case ('own') {
2104
+ <div *gfyFormArea="place.path" class="own" [attr.title]="'A component of the application: ' + place.text">
2105
+ <span>{{ place.text }}</span>
2106
+ </div>
2107
+ }
2108
+ @case ('list') {
2109
+ <gfy-repeater *gfyFormArea="place.path" [value]="place.items!" [ariaLabel]="place.path">
2110
+ <ng-template gfyRepeaterItem>
2111
+ @for (inner of place.inner!; track inner.path) {
2112
+ @switch (inner.kind) {
2113
+ @case ('control') {
2114
+ <ng-container *gfyFormArea="inner.path"
2115
+ ><ng-container fmePlace #own="fmePlace"><ng-container *ngComponentOutlet="inner.component!; inputs: inner.inputs!; injector: own.injector" /></ng-container
2116
+ ></ng-container>
2117
+ }
2118
+ @case ('label') {
2119
+ <gfy-label *gfyFormArea="inner.path">{{ inner.text }}</gfy-label>
2120
+ }
2121
+ @case ('own') {
2122
+ <div *gfyFormArea="inner.path" class="own" [attr.title]="'A component of the application: ' + inner.text">
2123
+ <span>{{ inner.text }}</span>
2124
+ </div>
2125
+ }
2126
+ @default {
2127
+ <div *gfyFormArea="inner.path" class="box" [attr.title]="inner.text ?? inner.path">
2128
+ <span>{{ inner.text ?? inner.path }}</span>
2129
+ </div>
2130
+ }
2131
+ }
2132
+ }
2133
+ </ng-template>
2134
+ </gfy-repeater>
2135
+ }
2136
+ }
2137
+ }
2138
+ </gfy-form>
2139
+ @if (!follows()) {
2140
+ <div class="resize" title="Drag to change the width of the form" (pointerdown)="startResize($event)"></div>
2141
+ }
2142
+ </div>
2143
+ } @else {
2144
+ <div class="none">The form cannot be laid out: the Problems window says why.</div>
2145
+ }
2146
+ </div>
2147
+ `,isInline:true,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n",".tb .label{font-size:12px;opacity:.88;margin-left:2px}.tb.upper{border-bottom:0;padding-bottom:0}.tb .info{line-height:var(--gfy-control-height);font-size:12px;opacity:.88;white-space:nowrap}.tb .px{min-width:52px;font-size:12px;text-align:end;font-variant-numeric:tabular-nums}.tb .widths{display:inline-flex;align-items:center;gap:2px}.tb .follow{flex:none;white-space:nowrap}.tb .slide{position:relative;display:inline-block;width:200px;margin:0 6px}.tb .slide gfy-slider{position:relative;z-index:1;display:block}.tb .mark{position:absolute;top:calc(50% - 6px);width:2px;height:12px;margin-left:-1px;border-radius:1px;background:color-mix(in srgb,var(--gfy-text-main) 60%,transparent);pointer-events:none}.stage{flex:1 1 auto;min-height:0;overflow:auto;padding:16px 24px 24px;background:color-mix(in srgb,var(--gfy-text-main, #333) 4%,var(--gfy-bg-panel, var(--gfy-bg-main)))}.frame{position:relative;box-sizing:border-box;padding:16px;overflow:clip;background:var(--gfy-bg-document, var(--gfy-bg-main));box-shadow:0 0 0 1px var(--gfy-border-color, rgba(128, 128, 128, .35))}.resize{position:absolute;top:0;right:0;bottom:0;width:12px;cursor:ew-resize;touch-action:none}.resize:after{content:\"\";position:absolute;top:calc(50% - 16px);left:4px;width:4px;height:32px;border-radius:2px;background:color-mix(in srgb,var(--gfy-text-main, #333) 30%,transparent)}.resize:hover:after{background:var(--gfy-accent, #3a8fd6)}.box{display:grid;box-sizing:border-box;min-height:var(--gfy-control-height, 28px);place-items:center;padding:0 8px;border:1px dashed color-mix(in srgb,#2f80ed 60%,transparent);border-radius:var(--gfy-control-radius, 4px);background:color-mix(in srgb,#2f80ed 8%,transparent);font:12px var(--gfy-font-mono, Consolas, monospace)}.box>span{max-width:100%;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.own{display:grid;box-sizing:border-box;height:100%;min-height:var(--gfy-control-height, 28px);place-items:center;padding:0 8px;border:1.5px dashed color-mix(in srgb,#0d9488 65%,transparent);border-radius:6px;background:repeating-linear-gradient(45deg,color-mix(in srgb,#0d9488 9%,transparent) 0 6px,transparent 6px 12px);font:600 12px var(--gfy-font-mono, Consolas, monospace);color:#0d9488}.own>span{max-width:100%;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.none{padding:16px;opacity:.88}\n"],dependencies:[{kind:"directive",type:vc,selector:"[ngComponentOutlet]",inputs:["ngComponentOutlet","ngComponentOutletInputs","ngComponentOutletInjector","ngComponentOutletEnvironmentInjector","ngComponentOutletContent","ngComponentOutletNgModule"],exportAs:["ngComponentOutlet"]},{kind:"directive",type:Fo,selector:"[fmePlace]",exportAs:["fmePlace"]},{kind:"component",type:ke,selector:"gfy-button",inputs:["label","icon","iconOnly","tooltip","ariaLabel","caret","variant","appearance","layout","toggle","checked","disabled","busy","type","name","haspopup","expanded","controls","joined","attached","reserveLabelSpace"],outputs:["checkedChange","pressed"]},{kind:"component",type:Bs,selector:"gfy-checkbox",inputs:["indeterminate","shape"],outputs:["indeterminateChange"]},{kind:"component",type:mc,selector:"gfy-form",inputs:["layout","name","layers","pages","width"],outputs:["pagesChange","variantChanged"]},{kind:"directive",type:gc,selector:"ng-template[gfyFormArea]",inputs:["gfyFormArea"]},{kind:"component",type:bc,selector:"gfy-label",inputs:["for","required","hint","hintPlace","disabled","appearance"],exportAs:["gfyLabel"]},{kind:"component",type:yc,selector:"gfy-repeater",inputs:["value","newItem","min","max","disabled","ariaLabel"],outputs:["valueChange"]},{kind:"directive",type:wc,selector:"ng-template[gfyRepeaterItem]",inputs:["gfyRepeaterItem"]},{kind:"component",type:_o,selector:"gfy-slider",inputs:["value","min","max","step","label","ariaLabel","showValue","valueText","variant","disabled","readonly","name","controlId"],outputs:["valueChange","valueCommitted"]},{kind:"component",type:St,selector:"gfy-toggle-group",inputs:["options","mode","value","values","allowEmpty","iconOnly","orientation","joined","variant","appearance","disabled","label","ariaLabel"],outputs:["valueChange","valuesChange","toggled"]}]})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:lr,decorators:[{type:me,args:[{selector:"fme-preview",standalone:true,imports:[vc,Fo,ke,Bs,mc,gc,bc,yc,wc,_o,St],template:`
2148
+ <!-- two rows, as in the Editor: what is shown (the variant of the width, the layers), and under it the width -->
2149
+ <div class="tb upper">
2150
+ <span class="info">{{ info() }}</span>
2151
+ <span class="sp"></span>
2152
+ @for (group of layerGroups(); track group.name) {
2153
+ @if (!$first) {
2154
+ <span class="sep" aria-hidden="true"></span>
2155
+ }
2156
+ <span class="label">{{ group.name }}</span>
2157
+ <gfy-toggle-group [options]="group.options" [value]="group.value" (valueChange)="onLayer(group.name, $event)" [ariaLabel]="'The layer of ' + group.name" />
2158
+ }
2159
+ </div>
2160
+ <div class="tb">
2161
+ <gfy-checkbox
2162
+ class="follow"
2163
+ label="Width of the Editor"
2164
+ title="The form is as wide as in the Editor: the width follows the slider of the Editor (and its Fit), and the width here is off"
2165
+ [reserveMessageSpace]="false"
2166
+ [checked]="store.view().previewFollows === true"
2167
+ (checkedChange)="store.setPreviewFollows($event)" />
2168
+ <span class="sp"></span>
2169
+ <span class="widths" role="group" aria-label="The width of the form">
2170
+ <gfy-button toggle appearance="flat" label="Fit" tooltip="As wide as the window" [disabled]="follows()" [checked]="store.view().previewWidth === null && !follows()" (checkedChange)="onFit($event)" />
2171
+ <!-- a mark on the track for every variant: where the form changes its variant -->
2172
+ <span class="slide" [title]="marksTitle()">
2173
+ @for (mark of marks(); track mark.minWidth) {
2174
+ <span class="mark" aria-hidden="true" [style.left]="mark.left"></span>
2175
+ }
2176
+ <gfy-slider ariaLabel="The width of the form in the Preview" [disabled]="follows()" [min]="slideRange().min" [max]="slideRange().max" [value]="width()" [valueText]="pxText" (valueChange)="onSlide($event)" />
2177
+ </span>
2178
+ <span class="px">{{ width() }} px</span>
2179
+ </span>
2180
+ </div>
2181
+ <div #stage class="stage">
2182
+ @if (store.layout() && hasForm()) {
2183
+ <div class="frame" [style.width.px]="width() + framePadding * 2">
2184
+ <gfy-form [layout]="store.layout()" [name]="store.selection().form" [layers]="store.active()" [pages]="pages()" (pagesChange)="onPages($event)" (variantChanged)="onVariant($event)">
2185
+ @for (place of places(); track place.path) {
2186
+ @switch (place.kind) {
2187
+ @case ('control') {
2188
+ <ng-container *gfyFormArea="place.path"
2189
+ ><ng-container fmePlace #own="fmePlace"><ng-container *ngComponentOutlet="place.component!; inputs: place.inputs!; injector: own.injector" /></ng-container
2190
+ ></ng-container>
2191
+ }
2192
+ @case ('label') {
2193
+ <gfy-label *gfyFormArea="place.path">{{ place.text }}</gfy-label>
2194
+ }
2195
+ @case ('box') {
2196
+ <div *gfyFormArea="place.path" class="box" [attr.title]="place.text">
2197
+ <span>{{ place.text }}</span>
2198
+ </div>
2199
+ }
2200
+ @case ('own') {
2201
+ <div *gfyFormArea="place.path" class="own" [attr.title]="'A component of the application: ' + place.text">
2202
+ <span>{{ place.text }}</span>
2203
+ </div>
2204
+ }
2205
+ @case ('list') {
2206
+ <gfy-repeater *gfyFormArea="place.path" [value]="place.items!" [ariaLabel]="place.path">
2207
+ <ng-template gfyRepeaterItem>
2208
+ @for (inner of place.inner!; track inner.path) {
2209
+ @switch (inner.kind) {
2210
+ @case ('control') {
2211
+ <ng-container *gfyFormArea="inner.path"
2212
+ ><ng-container fmePlace #own="fmePlace"><ng-container *ngComponentOutlet="inner.component!; inputs: inner.inputs!; injector: own.injector" /></ng-container
2213
+ ></ng-container>
2214
+ }
2215
+ @case ('label') {
2216
+ <gfy-label *gfyFormArea="inner.path">{{ inner.text }}</gfy-label>
2217
+ }
2218
+ @case ('own') {
2219
+ <div *gfyFormArea="inner.path" class="own" [attr.title]="'A component of the application: ' + inner.text">
2220
+ <span>{{ inner.text }}</span>
2221
+ </div>
2222
+ }
2223
+ @default {
2224
+ <div *gfyFormArea="inner.path" class="box" [attr.title]="inner.text ?? inner.path">
2225
+ <span>{{ inner.text ?? inner.path }}</span>
2226
+ </div>
2227
+ }
2228
+ }
2229
+ }
2230
+ </ng-template>
2231
+ </gfy-repeater>
2232
+ }
2233
+ }
2234
+ }
2235
+ </gfy-form>
2236
+ @if (!follows()) {
2237
+ <div class="resize" title="Drag to change the width of the form" (pointerdown)="startResize($event)"></div>
2238
+ }
2239
+ </div>
2240
+ } @else {
2241
+ <div class="none">The form cannot be laid out: the Problems window says why.</div>
2242
+ }
2243
+ </div>
2244
+ `,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n",".tb .label{font-size:12px;opacity:.88;margin-left:2px}.tb.upper{border-bottom:0;padding-bottom:0}.tb .info{line-height:var(--gfy-control-height);font-size:12px;opacity:.88;white-space:nowrap}.tb .px{min-width:52px;font-size:12px;text-align:end;font-variant-numeric:tabular-nums}.tb .widths{display:inline-flex;align-items:center;gap:2px}.tb .follow{flex:none;white-space:nowrap}.tb .slide{position:relative;display:inline-block;width:200px;margin:0 6px}.tb .slide gfy-slider{position:relative;z-index:1;display:block}.tb .mark{position:absolute;top:calc(50% - 6px);width:2px;height:12px;margin-left:-1px;border-radius:1px;background:color-mix(in srgb,var(--gfy-text-main) 60%,transparent);pointer-events:none}.stage{flex:1 1 auto;min-height:0;overflow:auto;padding:16px 24px 24px;background:color-mix(in srgb,var(--gfy-text-main, #333) 4%,var(--gfy-bg-panel, var(--gfy-bg-main)))}.frame{position:relative;box-sizing:border-box;padding:16px;overflow:clip;background:var(--gfy-bg-document, var(--gfy-bg-main));box-shadow:0 0 0 1px var(--gfy-border-color, rgba(128, 128, 128, .35))}.resize{position:absolute;top:0;right:0;bottom:0;width:12px;cursor:ew-resize;touch-action:none}.resize:after{content:\"\";position:absolute;top:calc(50% - 16px);left:4px;width:4px;height:32px;border-radius:2px;background:color-mix(in srgb,var(--gfy-text-main, #333) 30%,transparent)}.resize:hover:after{background:var(--gfy-accent, #3a8fd6)}.box{display:grid;box-sizing:border-box;min-height:var(--gfy-control-height, 28px);place-items:center;padding:0 8px;border:1px dashed color-mix(in srgb,#2f80ed 60%,transparent);border-radius:var(--gfy-control-radius, 4px);background:color-mix(in srgb,#2f80ed 8%,transparent);font:12px var(--gfy-font-mono, Consolas, monospace)}.box>span{max-width:100%;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.own{display:grid;box-sizing:border-box;height:100%;min-height:var(--gfy-control-height, 28px);place-items:center;padding:0 8px;border:1.5px dashed color-mix(in srgb,#0d9488 65%,transparent);border-radius:6px;background:repeating-linear-gradient(45deg,color-mix(in srgb,#0d9488 9%,transparent) 0 6px,transparent 6px 12px);font:600 12px var(--gfy-font-mono, Consolas, monospace);color:#0d9488}.own>span{max-width:100%;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.none{padding:16px;opacity:.88}\n"]}]}],ctorParameters:()=>[],propDecorators:{stageRef:[{type:w.ViewChild,args:["stage",{isSignal:true}]}]}});class cr{store=L(at);severities=E(["error","warning","info"],...(ngDevMode?[{debugName:"severities"}]:([])));tools=[{type:"severity",severity:"error"},{type:"severity",severity:"warning"},{type:"severity",severity:"info"},{type:"filter"},{type:"spacer"}];open(e){this.store.openProblem(e)}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:cr,deps:[],target:w.ɵɵFactoryTarget.Component});static ɵcmp=w.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"21.2.21",type:cr,isStandalone:true,selector:"fme-problems",ngImport:w,template:` <gfy-problem-list [problems]="store.problems()" [tools]="tools" [(severities)]="severities" ariaLabel="Problems" emptyText="No problems found." (problemActivated)="open($event)" /> `,isInline:true,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n","gfy-problem-list{flex:1 1 auto;min-height:0}\n"],dependencies:[{kind:"component",type:_n,selector:"gfy-problem-list",inputs:["problems","columns","columnTitles","tools","toolbar","toolbarPosition","severities","filter","selected","ariaLabel","emptyText"],outputs:["severitiesChange","filterChange","selectedChange","problemActivated","toolUsed"]}]})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:cr,decorators:[{type:me,args:[{selector:"fme-problems",standalone:true,imports:[_n],template:` <gfy-problem-list [problems]="store.problems()" [tools]="tools" [(severities)]="severities" ariaLabel="Problems" emptyText="No problems found." (problemActivated)="open($event)" /> `,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n","gfy-problem-list{flex:1 1 auto;min-height:0}\n"]}]}]});class dr{store=L(at);popup=L(Wo);groups=M(()=>tu.map(e=>({...e,tools:ms.filter(t=>t.group===e.group)})),...(ngDevMode?[{debugName:"groups"}]:([])));enabled(e){return e.id!=="subform"||this.store.subformTargets().length>0}add(e,t){if(!this.enabled(e))return;const o=t instanceof MouseEvent&&t.detail>0;const i=this.store.subformTargets();if(e.id==="subform"&&i.length>1){const r=t.currentTarget;this.popup.open([{header:true,label:"The form the subform places"},...i.map(s=>({label:s,icon:"fme:form",run:()=>this.addTool("subform",o,s)}))],{anchor:r});return}this.addTool(e.id,o)}addTool(e,t,o){const i=this.store.file();this.store.addTool(e,null,o);if(t&&this.store.file()!==i)this.store.focusEditor.update(r=>r+1)}onDragStart(e,t){if(!e.dataTransfer||!this.enabled(t))return;e.dataTransfer.setData(ec,t.id);e.dataTransfer.setData("text/plain",t.label);e.dataTransfer.effectAllowed="copy";this.store.dragTool.set(t.id)}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:dr,deps:[],target:w.ɵɵFactoryTarget.Component});static ɵcmp=w.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"21.2.21",type:dr,isStandalone:true,selector:"fme-toolbox",ngImport:w,template:`
2245
+ <div class="hint">Drag a tool onto the Editor, or click it to add it under what is in the selected group (or in the form).</div>
2246
+ <div class="scroll">
2247
+ <gfy-accordion ariaLabel="Tools" multiple>
2248
+ @for (group of groups(); track group.group) {
2249
+ <gfy-expander [heading]="group.label" [expanded]="!group.folded" appearance="plain">
2250
+ @for (tool of group.tools; track tool.id) {
2251
+ <div
2252
+ class="tool"
2253
+ [class]="'tool ' + tool.group + (tool.id === 'subform' ? ' subform' : '') + (enabled(tool) ? '' : ' off')"
2254
+ role="button"
2255
+ tabindex="0"
2256
+ [attr.aria-disabled]="!enabled(tool) || null"
2257
+ [draggable]="enabled(tool)"
2258
+ [attr.title]="tool.description + (enabled(tool) ? '' : ' (Add another form to the file first.)')"
2259
+ (click)="add(tool, $event)"
2260
+ (keydown.enter)="add(tool, $event)"
2261
+ (keydown.space)="add(tool, $event); $event.preventDefault()"
2262
+ (dragstart)="onDragStart($event, tool)"
2263
+ (dragend)="store.dragTool.set(null)">
2264
+ <span class="ic" [gfyIcon]="tool.icon"></span>
2265
+ <span class="name">{{ tool.label }}</span>
2266
+ </div>
2267
+ }
2268
+ </gfy-expander>
2269
+ }
2270
+ </gfy-accordion>
2271
+ </div>
2272
+ `,isInline:true,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n",".ic{flex:none;display:grid;width:var(--ic, 14px);height:var(--ic, 14px)}\n",".scroll{flex:1 1 auto;min-height:0;overflow:auto;padding:4px 6px 8px}.tool{display:flex;align-items:center;gap:8px;padding:4px 8px;border-radius:var(--gfy-radius, 4px);cursor:grab;-webkit-user-select:none;user-select:none}.tool:hover{background:color-mix(in srgb,var(--gfy-accent, #3a8fd6) 11%,transparent)}.tool:focus-visible{outline:2px solid var(--gfy-accent, #3a8fd6);outline-offset:-2px}.tool .ic{--ic: 16px;color:var(--tool-color, var(--gfy-accent, #3a8fd6))}.tool.fields .ic,.tool.more .ic,.tool.labeled .ic{--tool-color: #2f80ed}.tool.content .ic{--tool-color: #0d9488}.tool.texts .ic{--tool-color: #8b5cf6}.tool.containers .ic{--tool-color: #1f9d55}.tool.subform .ic{--tool-color: #e07b00}.tool .name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tool.off{opacity:.45;cursor:default}\n"],dependencies:[{kind:"component",type:gr,selector:"gfy-accordion",inputs:["multiple","layout","ariaLabel"]},{kind:"component",type:Yt,selector:"gfy-expander",inputs:["heading","description","icon","expanded","disabled","appearance","chevronAt","level","keepContent"],outputs:["expandedChange"]},{kind:"directive",type:mt,selector:"[gfyIcon]",inputs:["gfyIcon"]}]})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:dr,decorators:[{type:me,args:[{selector:"fme-toolbox",standalone:true,imports:[gr,Yt,mt],template:`
2273
+ <div class="hint">Drag a tool onto the Editor, or click it to add it under what is in the selected group (or in the form).</div>
2274
+ <div class="scroll">
2275
+ <gfy-accordion ariaLabel="Tools" multiple>
2276
+ @for (group of groups(); track group.group) {
2277
+ <gfy-expander [heading]="group.label" [expanded]="!group.folded" appearance="plain">
2278
+ @for (tool of group.tools; track tool.id) {
2279
+ <div
2280
+ class="tool"
2281
+ [class]="'tool ' + tool.group + (tool.id === 'subform' ? ' subform' : '') + (enabled(tool) ? '' : ' off')"
2282
+ role="button"
2283
+ tabindex="0"
2284
+ [attr.aria-disabled]="!enabled(tool) || null"
2285
+ [draggable]="enabled(tool)"
2286
+ [attr.title]="tool.description + (enabled(tool) ? '' : ' (Add another form to the file first.)')"
2287
+ (click)="add(tool, $event)"
2288
+ (keydown.enter)="add(tool, $event)"
2289
+ (keydown.space)="add(tool, $event); $event.preventDefault()"
2290
+ (dragstart)="onDragStart($event, tool)"
2291
+ (dragend)="store.dragTool.set(null)">
2292
+ <span class="ic" [gfyIcon]="tool.icon"></span>
2293
+ <span class="name">{{ tool.label }}</span>
2294
+ </div>
2295
+ }
2296
+ </gfy-expander>
2297
+ }
2298
+ </gfy-accordion>
2299
+ </div>
2300
+ `,styles:[":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--gfy-bg-panel, var(--gfy-bg-main));color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}.tb{flex:none;display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;padding:3px 6px;border-bottom:1px solid var(--gfy-border-color, rgba(128, 128, 128, .3));--gfy-control-height: 24px;--gfy-control-padding-x: 7px}.tb .sp{flex:1}.tb .sep{width:1px;height:16px;margin:0 4px;background:var(--gfy-border-color, rgba(128, 128, 128, .4))}.fill{flex:1 1 auto;min-height:0}.empty{padding:10px 12px;opacity:.88}.hint{padding:6px 10px;font-size:12px;opacity:.88}\n",".ic{flex:none;display:grid;width:var(--ic, 14px);height:var(--ic, 14px)}\n",".scroll{flex:1 1 auto;min-height:0;overflow:auto;padding:4px 6px 8px}.tool{display:flex;align-items:center;gap:8px;padding:4px 8px;border-radius:var(--gfy-radius, 4px);cursor:grab;-webkit-user-select:none;user-select:none}.tool:hover{background:color-mix(in srgb,var(--gfy-accent, #3a8fd6) 11%,transparent)}.tool:focus-visible{outline:2px solid var(--gfy-accent, #3a8fd6);outline-offset:-2px}.tool .ic{--ic: 16px;color:var(--tool-color, var(--gfy-accent, #3a8fd6))}.tool.fields .ic,.tool.more .ic,.tool.labeled .ic{--tool-color: #2f80ed}.tool.content .ic{--tool-color: #0d9488}.tool.texts .ic{--tool-color: #8b5cf6}.tool.containers .ic{--tool-color: #1f9d55}.tool.subform .ic{--tool-color: #e07b00}.tool .name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tool.off{opacity:.45;cursor:default}\n"]}]}]});const U1="gfy-form-editor:windows";const rf=[{tag:"toolbox",title:"Toolbox",icon:"fme:place",role:"tool",component:dr},{tag:"outline",title:"Outline",icon:"fme:form",role:"tool",component:sr},{tag:"editor",title:"Editor",icon:"fme:editor",role:"document",component:ir,fixed:true},{tag:"preview",title:"Preview",icon:"fme:preview",role:"document",component:lr,fixed:true},{tag:"output",title:"Output",icon:"fme:copy",role:"tool",component:ar},{tag:"problems",title:"Problems",icon:"fme:problems",role:"tool",component:cr},{tag:"inspector",title:"Inspector",icon:"fme:cursor",role:"tool",component:rr}];const Y1={showCloseButton:false,allowDetachOnDrag:false,showUndockButton:false};const Rn=n=>({tag:n.tag,role:n.role,icon:n.icon,title:n.title,componentType:n.component,componentKey:`fme-${n.tag}`,...(n.fixed?Y1:{})});const Li=(n,e,t,o)=>({tag:n,type:"panel",role:e,size:t,activeTab:0,collapsed:false,tabs:o});const Fn=n=>rf.find(e=>e.tag===n);const J1=()=>({type:"row",size:100,children:[{type:"column",size:19,children:[Li("toolbox","tool",46,[Rn(Fn("toolbox"))]),Li("outline","tool",54,[Rn(Fn("outline"))])]},{type:"column",size:57,children:[Li("docs","document",70,[Rn(Fn("editor")),Rn(Fn("preview"))]),Li("bottom","tool",30,[Rn(Fn("problems")),Rn(Fn("output"))])]},Li("right","tool",24,[Rn(Fn("inspector"))])]});class pr{hosted=we(false,{...(ngDevMode?{debugName:"hosted"}:({})),transform:js});files=we(null,...(ngDevMode?[{debugName:"files"}]:([])));sample=we(null,...(ngDevMode?[{debugName:"sample"}]:([])));store=L(at);help=Va(j1);engine=ct(Ie,...(ngDevMode?[{debugName:"engine"}]:([])));layout=J1();windowsKey=U1;constructor(){this.store.project.connect(this.files)}ngOnInit(){const e=this.sample();if(e)this.store.startWith(e)}saveWindows(){this.engine()?.saveLayout()}windowItems(){return this.engine()?.view.toolItems(rf.filter(e=>!e.fixed).map(e=>({tag:e.tag,label:e.title,icon:e.icon})))??[]}resetWindows(){setTimeout(()=>this.engine()?.resetLayout())}menus=M(()=>{const e=this.store;const t=e.capabilities();const o=qu.map(r=>({label:r.label,run:()=>void e.loadSample(r.id)}));const i=e.project.files()!==null;return[{id:"file",label:"&File",items:[{label:"&New file",icon:"fme:file",run:()=>void e.newFile()},{label:"&Open file…",icon:"fme:upload",shortcut:i?void 0:"Mod+O",run:()=>e.openFile()},...(i?[{label:"Open from the p&roject…",icon:"fme:project-folder",shortcut:"Mod+O",run:()=>void e.openFromProject()}]:[]),{label:"&Paste a file from the clipboard",icon:"fme:clipboard",run:()=>void e.pasteFile()},{label:"&Samples",icon:"fme:sample",children:o},{separator:true},...(i?[{label:"Sa&ve",icon:"fme:save",shortcut:"Mod+S",run:()=>void e.saveToProject()},{label:"Save as…",shortcut:"Mod+Shift+S",run:()=>void e.saveToProjectAs()}]:[]),{label:"&Download the file",icon:"fme:download",shortcut:i?void 0:"Mod+S",run:()=>e.downloadFile()},{label:"&Copy the output",icon:"fme:copy",run:()=>void e.copyOutput()},{separator:true},{label:"&Auto save",checked:e.autoSave(),run:()=>e.setAutoSave(!e.autoSave())}]},{id:"edit",label:"&Edit",items:[{label:"&Undo",icon:"fme:undo",shortcut:"Mod+Z",enabled:e.canUndo(),run:()=>e.undo()},{label:"Re&do",icon:"fme:redo",shortcut:"Mod+Y",enabled:e.canRedo(),run:()=>e.redo()},{separator:true},{label:"Cu&t",icon:"fme:cut",enabled:t.copy,run:()=>e.cutSelected()},{label:"&Copy",icon:"fme:copy",enabled:t.copy,run:()=>void e.copySelected()},{label:"&Paste",icon:"fme:paste",enabled:t.paste,run:()=>e.paste()},{label:"Dup&licate",icon:"fme:duplicate",shortcut:"Mod+D",enabled:t.duplicate,run:()=>e.duplicateSelected()},{separator:true},{label:"Remove &from the form",icon:"fme:remove",enabled:t.remove,run:()=>e.removeSelected()},{label:"Not placed in this &variant",icon:"fme:unplace",enabled:t.unplace,run:()=>e.unplaceSelected()},{separator:true},{label:"Select &all",run:()=>e.selectAll()},{label:"Put into a &group",icon:"fme:wrap",enabled:t.wrap,children:[{label:"A group without a frame",icon:"fme:group",run:()=>e.wrapSelected("none")},{label:"A group box",icon:"fme:group-box",run:()=>e.wrapSelected("group-box")}]},{label:"Ungr&oup",icon:"fme:unwrap",enabled:t.unwrap,run:()=>e.unwrapSelected()},{label:"Add a la&bel",icon:"fme:label-for",enabled:t.addLabel,run:()=>e.addLabel()}]},{id:"insert",label:"&Insert",items:[...Is(e,(r,s)=>e.addTool(r,null,s)).slice(1),{separator:true},{label:"A &form",icon:"fme:add-form",run:()=>e.addForm()},{label:"A &variant of this form",icon:"fme:add-variant",children:[...e.variantProposals().map(r=>({label:`From ${r} px`,run:()=>e.addVariant(r)})),{label:"From another width…",run:()=>void e.addVariantOfWidth()}]}]},{id:"arrange",label:"&Arrange",items:Yu(e,false)},{id:"view",label:"&View",items:[{label:"&Windows",icon:"fme:form",children:this.windowItems()},{label:"&Lines of the cells",icon:"fme:editor",checked:e.view().showGrid,run:()=>e.setShowGrid(!e.view().showGrid)},{label:"Set the &order of the page",icon:"fme:tab-order",checked:e.tabOrderMode(),run:()=>e.setTabOrderMode(!e.tabOrderMode())},{separator:true},{label:"&Reset the windows",run:()=>this.resetWindows()}]},{id:"help",label:"&Help",items:[...this.help.items]}]},...(ngDevMode?[{debugName:"menus"}]:([])));title=M(()=>this.store.project.title(this.store.modified()),...(ngDevMode?[{debugName:"title"}]:([])));statusItems=M(()=>{const e=this.store;const t=e.problems();const o=t.filter(l=>l.severity==="error").length;const i=t.filter(l=>l.severity==="warning").length;const r=e.form();const s=e.variant();const a=r?ve(r).length:0;return[{id:"message",text:e.status()||"Ready",shrink:true,live:true},{id:"where",text:e.where(),tooltip:"The form, the variant and the selected element",align:"end",priority:4},{id:"grid",text:s?`${s.cols} × ${s.rows} cells`:"",tooltip:"The columns and the rows of the variant",align:"end",priority:3,visible:s!==void 0},{id:"counts",text:`Elements: ${a}`,tooltip:"The elements of the form",align:"end",priority:2},{id:"problems",icon:"fme:problems",text:`Errors: ${o}, warnings: ${i}`,tooltip:"The problems of the file",align:"end",priority:10,tone:o>0?"danger":i>0?"warning":"default"}]},...(ngDevMode?[{debugName:"statusItems"}]:([])));onFileDragOver(e){za(e)}onFileDrop(e){void La(e)?.then(t=>{if(t)void this.store.loadFromText(t.text,t.name);else this.store.say("The file that was dropped cannot be read.")})}static ɵfac=w.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:pr,deps:[],target:w.ɵɵFactoryTarget.Component});static ɵcmp=w.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"21.2.21",type:pr,isStandalone:true,selector:"form-editor",inputs:{hosted:{classPropertyName:"hosted",publicName:"hosted",isSignal:true,isRequired:false,transformFunction:null},files:{classPropertyName:"files",publicName:"files",isSignal:true,isRequired:false,transformFunction:null},sample:{classPropertyName:"sample",publicName:"sample",isSignal:true,isRequired:false,transformFunction:null}},host:{properties:{"class.hosted":"hosted()"}},providers:[at],viewQueries:[{propertyName:"engine",first:true,predicate:Ie,descendants:true,isSignal:true}],ngImport:w,template:`
2301
+ <div class="shell" (dragover)="onFileDragOver($event)" (drop)="onFileDrop($event)">
2302
+ <gfy-menu-bar [menus]="menus()" [shortcuts]="true">
2303
+ @if (!hosted()) {
2304
+ <span gfyMenuBarStart>Gridify Form editor</span>
2305
+ }
2306
+ <span gfyMenuBarTitle [attr.title]="title().tooltip">{{ title().text }}</span>
2307
+ @if (!hosted()) {
2308
+ <gfy-preference-select gfyMenuBarEnd kinds="theme density" />
2309
+ }
2310
+ </gfy-menu-bar>
2311
+ <div class="workspace">
2312
+ <gfy-docking-engine [defaultLayout]="layout" [layoutStorageKey]="windowsKey" (layoutChanged)="saveWindows()" />
2313
+ </div>
2314
+ <gfy-status-bar [items]="statusItems()" />
2315
+ </div>
2316
+ `,isInline:true,styles:[":host{display:block;height:100vh;color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}:host(.hosted){height:100%}.shell{height:100%;display:flex;flex-direction:column;background:var(--gfy-bg-main)}.workspace{flex:1;min-height:0;position:relative}\n"],dependencies:[{kind:"component",type:Ie,selector:"gfy-docking-engine",inputs:["defaultLayout","engineId","layoutStorageKey","emptyDocument","viewSources","viewTools","tabMenuItems","popouts"],outputs:["tabOpened","tabConfirmClose","tabClosed","tabActivated","tabReordered","tabDocked","tabFloated","tabDirtyChanged","tabMovedToWindow","tabActiveChanged","panelCollapsed","panelExpanded","panelResized","panelMaximized","panelRestored","floatingMoved","floatingResized","dragStarted","dragEnded","popoutOpened","popoutClosed","popoutRefused","layoutChanged","layoutSaved","layoutLoaded","layoutReset"]},{kind:"component",type:Gn,selector:"gfy-menu-bar",inputs:["menus","ariaLabel","overflow","overflowLabel","flexReserve","shortcuts","ignoreAlt","messageBar"],outputs:["messageBarChange","messageBarClosed","messageBarActionInvoked","itemInvoked"]},{kind:"component",type:Bn,selector:"gfy-preference-select",inputs:["kinds","showLabels","disabled"],outputs:["switchFailed"]},{kind:"component",type:Vn,selector:"gfy-status-bar",inputs:["items","variant","ariaLabel","overflowLabel","flexReserve"],outputs:["itemInvoked","choiceInvoked"]}],changeDetection:w.ChangeDetectionStrategy.OnPush})}w.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"21.2.21",ngImport:w,type:pr,decorators:[{type:me,args:[{selector:"form-editor",standalone:true,imports:[Ie,Gn,Bn,Vn],providers:[at],changeDetection:fn.OnPush,host:{"[class.hosted]":"hosted()"},template:`
2317
+ <div class="shell" (dragover)="onFileDragOver($event)" (drop)="onFileDrop($event)">
2318
+ <gfy-menu-bar [menus]="menus()" [shortcuts]="true">
2319
+ @if (!hosted()) {
2320
+ <span gfyMenuBarStart>Gridify Form editor</span>
2321
+ }
2322
+ <span gfyMenuBarTitle [attr.title]="title().tooltip">{{ title().text }}</span>
2323
+ @if (!hosted()) {
2324
+ <gfy-preference-select gfyMenuBarEnd kinds="theme density" />
2325
+ }
2326
+ </gfy-menu-bar>
2327
+ <div class="workspace">
2328
+ <gfy-docking-engine [defaultLayout]="layout" [layoutStorageKey]="windowsKey" (layoutChanged)="saveWindows()" />
2329
+ </div>
2330
+ <gfy-status-bar [items]="statusItems()" />
2331
+ </div>
2332
+ `,styles:[":host{display:block;height:100vh;color:var(--gfy-text-main);font:13px/1.3 var(--gfy-font-main, system-ui, sans-serif)}:host(.hosted){height:100%}.shell{height:100%;display:flex;flex-direction:column;background:var(--gfy-bg-main)}.workspace{flex:1;min-height:0;position:relative}\n"]}]}],ctorParameters:()=>[],propDecorators:{hosted:[{type:w.Input,args:[{isSignal:true,alias:"hosted",required:false}]}],files:[{type:w.Input,args:[{isSignal:true,alias:"files",required:false}]}],sample:[{type:w.Input,args:[{isSignal:true,alias:"sample",required:false}]}],engine:[{type:w.ViewChild,args:[w.forwardRef(()=>Ie),{isSignal:true}]}]}});export{pr as FormEditor,ci as GfyEditorFileConflict,tr as LayoutEditor,qi as RibbonEditor,vb as gfyHttpFiles,Tb as gfyLocalFolderFiles,kb as gfyLocalFolderSupported,Sb as gfyPickLocalFolder};