@ngxviewbuilder/plugin-templates 0.13.6 → 0.14.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.
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import{BuilderActionButton as f,BuilderIconButton as x,CreatorStructureService as C,EventService as E,HeaderTabEnum as N,NGX_VIEW_BUILDER_TEMPLATES_CAPABILITY as b,NGX_VIEW_BUILDER_TEMPLATES_FEATURE_PACK_ID as w,NativeCodeEditor as T,NgxViewBuilderApiService as z,NvbStyleOutlet as y,TemplateEngineService as I,UiTranslatePipe as S,provideNgxViewBuilderExtensions as M}from"@ngxviewbuilder/designer";import*as i from"@angular/core";import{ChangeDetectionStrategy as F,Component as A,ViewChild as B,computed as p,inject as _,input as R,signal as m}from"@angular/core";import*as g from"@angular/forms";import{FormsModule as k}from"@angular/forms";var D=class l{previewTemplateScopeId=`nvb-template-preview-${Math.random().toString(36).slice(2,11)}`;previewTemplateScopeSelector=`[data-nvb-template-scope="${this.previewTemplateScopeId}"]`;static SIDEBAR_WIDTH_STORAGE_KEY="nvb-templates-sidebar-width";static MIN_SIDEBAR_WIDTH=200;static MAX_SIDEBAR_WIDTH=400;static DEFAULT_SIDEBAR_WIDTH=280;sidebarRef;sidebarWidth=l.DEFAULT_SIDEBAR_WIDTH;isResizingSidebar=false;creatorStructureService=_(C);templateEngineService=_(I);eventService=_(E);ngxViewBuilderApiService=_(z);theme=R("light",...ngDevMode?[{debugName:"theme"}]:[]);templates=m([],...ngDevMode?[{debugName:"templates"}]:[]);selectedTemplateName=m("",...ngDevMode?[{debugName:"selectedTemplateName"}]:[]);draft=m(null,...ngDevMode?[{debugName:"draft"}]:[]);error=m("",...ngDevMode?[{debugName:"error"}]:[]);formatError=m("",...ngDevMode?[{debugName:"formatError"}]:[]);cssFormatError=m("",...ngDevMode?[{debugName:"cssFormatError"}]:[]);previewItemsJson=m(JSON.stringify({name:"John",lastname:"Smith",status:"Y"},null,2),...ngDevMode?[{debugName:"previewItemsJson"}]:[]);onTemplatesLoadedHandler=()=>{this.reload()};onTemplateSavedHandler=()=>{this.reload(this.selectedTemplateName())};onTemplateDeletedHandler=()=>{this.reload()};previewState=p(()=>{const e=String(this.previewItemsJson()??"").trim();if(!e)return{item:null,error:""};try{const t=JSON.parse(e);if(t&&typeof t==="object"&&!Array.isArray(t))return{item:t,error:""};return{item:null,error:"templates.preview.invalidObject"}}catch{return{item:null,error:"templates.preview.invalidJson"}}},...ngDevMode?[{debugName:"previewState"}]:[]);previewItem=p(()=>this.previewState().item,...ngDevMode?[{debugName:"previewItem"}]:[]);previewJsonError=p(()=>this.previewState().error,...ngDevMode?[{debugName:"previewJsonError"}]:[]);hasTemplates=p(()=>this.templates().length>0,...ngDevMode?[{debugName:"hasTemplates"}]:[]);isDirty=p(()=>{const e=this.draft();if(!e)return false;const t=this.templates().find(a=>a.name===e.originalName);if(!t)return true;return String(e.name??"").trim()!==t.name||String(e.title??"").trim()!==String(t.title??"")||String(e.content??"")!==String(t.content??"")||String(e.css??"").trim()!==String(t.css??"")},...ngDevMode?[{debugName:"isDirty"}]:[]);previewCard=p(()=>{const e=this.draft();if(!e)return"";const t=this.composeTemplateMarkup(e);const a=this.previewItem();if(!a)return"";const r={...this.ngxViewBuilderApiService.getData({includeInternal:true})??{},item:a,row:a,index:0,value:a};return this.templateEngineService.renderTemplate(t,r)},...ngDevMode?[{debugName:"previewCard"}]:[]);previewTemplateCss=p(()=>{const e=this.draft();if(!e)return"";const t=this.composeTemplateMarkup(e);return this.templateEngineService.resolveTemplateCss(t,this.previewTemplateScopeSelector)},...ngDevMode?[{debugName:"previewTemplateCss"}]:[]);ngOnInit(){this.ngxViewBuilderApiService.onTemplatesLoaded.add(this.onTemplatesLoadedHandler);this.ngxViewBuilderApiService.onTemplateSaved.add(this.onTemplateSavedHandler);this.ngxViewBuilderApiService.onTemplateDeleted.add(this.onTemplateDeletedHandler);this.reload()}ngAfterViewInit(){const e=parseInt(localStorage.getItem(l.SIDEBAR_WIDTH_STORAGE_KEY)??"",10);if(Number.isFinite(e))this.sidebarWidth=this.clampSidebarWidth(e);this.applySidebarWidth()}ngOnDestroy(){this.ngxViewBuilderApiService.onTemplatesLoaded.remove(this.onTemplatesLoadedHandler);this.ngxViewBuilderApiService.onTemplateSaved.remove(this.onTemplateSavedHandler);this.ngxViewBuilderApiService.onTemplateDeleted.remove(this.onTemplateDeletedHandler);document.removeEventListener("mousemove",this.onSidebarResizeMouseMove);document.removeEventListener("mouseup",this.onSidebarResizeMouseUp)}onSidebarResizeMouseDown(e){e.preventDefault();this.isResizingSidebar=true;document.addEventListener("mousemove",this.onSidebarResizeMouseMove);document.addEventListener("mouseup",this.onSidebarResizeMouseUp)}onSidebarResizeMouseMove=e=>{if(!this.isResizingSidebar||!this.sidebarRef)return;const t=this.sidebarRef.nativeElement.getBoundingClientRect();this.sidebarWidth=this.clampSidebarWidth(e.clientX-t.left);this.applySidebarWidth()};onSidebarResizeMouseUp=()=>{this.isResizingSidebar=false;document.removeEventListener("mousemove",this.onSidebarResizeMouseMove);document.removeEventListener("mouseup",this.onSidebarResizeMouseUp);localStorage.setItem(l.SIDEBAR_WIDTH_STORAGE_KEY,String(this.sidebarWidth))};clampSidebarWidth(e){return Math.min(l.MAX_SIDEBAR_WIDTH,Math.max(l.MIN_SIDEBAR_WIDTH,e))}applySidebarWidth(){if(this.sidebarRef)this.sidebarRef.nativeElement.style.width=`${this.sidebarWidth}px`}trackByName(e,t){return`${e}:${t.name}`}isSelected(e){return this.selectedTemplateName()===String(e??"").trim()}selectTemplate(e){const t=String(e??"").trim();if(!t)return;const a=this.templates().find(r=>r.name===t);if(!a)return;this.selectedTemplateName.set(t);this.draft.set({...a,originalName:t});this.error.set("");this.formatError.set("");this.cssFormatError.set("")}addTemplate(){const e=this.readTemplatesFromStructure();const t=new Set(e.map(c=>c.name));const a="template";let r=1;let n=`${a}${r}`;while(t.has(n)){r+=1;n=`${a}${r}`}const o={name:n,title:`Template ${r}`,content:"",css:"",requestBodyJson:"",extraJsonSettings:""};const d=this.sortTemplates([...e,o]);this.persistTemplates(d);this.reload(n)}deleteSelectedTemplate(){const e=this.selectedTemplateName();if(!e)return;this.deleteTemplate(e)}deleteTemplate(e){const t=String(e??"").trim();if(!t)return;const a=this.readTemplatesFromStructure().filter(n=>n.name!==t);const r=this.selectedTemplateName()===t?a[0]?.name??"":this.selectedTemplateName();this.persistTemplates(a);this.ngxViewBuilderApiService.onTemplateDeleted.fire({code:t,timestamp:Date.now()});this.reload(r)}saveDraft(){const e=this.draft();if(!e)return;const t=String(e.name??"").trim();const a=String(e.title??"").trim();const r=String(e.content??"");const n=String(e.css??"").trim();const o=String(e.requestBodyJson??"").trim();const d=String(e.extraJsonSettings??"").trim();if(!t){this.error.set("templates.error.nameRequired");return}const c=this.readTemplatesFromStructure();if(c.find(v=>v.name===t&&v.name!==e.originalName)){this.error.set("templates.error.duplicateName");return}const u={name:t,title:a||void 0,content:r,css:n||void 0,requestBodyJson:o||void 0,extraJsonSettings:d||void 0};const s=String(e.originalName??"").trim();const h=c.filter(v=>{if(s&&v.name===s)return false;return v.name!==t});this.persistTemplates(this.sortTemplates([...h,u]));this.ngxViewBuilderApiService.onTemplateSaved.fire({template:{...u,code:t},previousCode:s&&s!==t?s:void 0,timestamp:Date.now()});this.reload(t)}updateDraftField(e,t){const a=this.draft();if(!a)return;this.draft.set({...a,[e]:t});if(e==="content"){this.formatError.set("");return}if(e==="css")this.cssFormatError.set("")}async onTemplateContentBlur(e){this.updateDraftField("content",e);await this.formatTemplateContent()}async onTemplateCssBlur(e){this.updateDraftField("css",e);await this.formatTemplateCss()}async formatTemplateContent(){const e=this.draft();if(!e)return;const t=String(e.content??"");if(!t.trim()){this.updateDraftField("content","");this.formatError.set("");return}try{const a=await this.formatHtmlWithPrettier(t);this.updateDraftField("content",a);this.formatError.set("")}catch(a){const r=a instanceof Error&&a.message?a.message:"templates.error.formatFailed";this.formatError.set(r)}}async formatTemplateCss(){const e=this.draft();if(!e)return;const t=String(e.css??"");if(!t.trim()){this.updateDraftField("css","");this.cssFormatError.set("");return}try{const a=await this.formatCssWithPrettier(t);this.updateDraftField("css",a);this.cssFormatError.set("")}catch(a){const r=a instanceof Error?a.message:"Failed to format CSS.";this.cssFormatError.set(r)}}async onPreviewTemplateClick(e,t,a){const r={...this.ngxViewBuilderApiService.getData({includeInternal:true})??{},item:t,row:t,value:t,index:a};await this.templateEngineService.handleTemplateClickEvent(e,r)}composeTemplateMarkup(e){const t=String(e?.content??"");const a=String(e?.css??"").trim();if(!a)return t;return`<style>${a}</style>
|
|
2
|
-
${t}`}async formatHtmlWithPrettier(e){const[{format:t},a]=await Promise.all([import("prettier/standalone"),import("prettier/plugins/html")]);const r=a.default??a;return t(String(e??""),{parser:"angular",plugins:[r],printWidth:100,tabWidth:2})}async formatCssWithPrettier(e){const[{format:t},a]=await Promise.all([import("prettier/standalone"),import("prettier/plugins/postcss")]);const r=a.default??a;return t(String(e??""),{parser:"css",plugins:[r],printWidth:100,tabWidth:2})}reload(e){const t=this.readTemplatesFromStructure();const a=this.sortTemplates(t);this.templates.set(a);const r=o=>a.some(d=>d.name===o);const n=(e&&r(e)?e:r(this.selectedTemplateName())?this.selectedTemplateName():"")||a[0]?.name||"";if(!n){this.selectedTemplateName.set("");this.draft.set(null);this.error.set("");this.formatError.set("");this.cssFormatError.set("");return}this.selectTemplate(n)}notifyStructureChanged(){this.eventService.afterPropertyChanged.fire({payload:null});this.ngxViewBuilderApiService.notifyStructureChanged()}persistTemplates(e){const t=this.creatorStructureService.getStructure();if(!t)return;if(!t.settings||typeof t.settings!=="object")t.settings={width:"1182",language:"lt"};t.settings.templates=this.sortTemplates(e).map(a=>({...a}));this.notifyStructureChanged()}readTemplatesFromStructure(){const e=this.creatorStructureService.getStructure()?.settings?.templates;if(!Array.isArray(e))return[];return e.map(t=>this.normalizeTemplate(t)).filter(t=>t!==null)}normalizeTemplate(e){if(!e||typeof e!=="object")return null;const t=e;const a=String(t["name"]??t["code"]??"").trim();if(!a)return null;const r=String(t["title"]??"").trim();const n=String(t["description"]??"").trim();const o=String(t["css"]??"").trim();const d=String(t["requestBodyJson"]??"").trim();const c=String(t["extraJsonSettings"]??"").trim();const u=Array.isArray(t["tags"])?t["tags"].map(h=>String(h??"").trim()).filter(h=>h.length>0):[];const s={...t,name:a,title:r||void 0,description:n||void 0,content:String(t["content"]??""),css:o||void 0,requestBodyJson:d||void 0,extraJsonSettings:c||void 0,tags:u.length>0?u:void 0};delete s["code"];return s}sortTemplates(e){return[...e].sort((t,a)=>t.name.localeCompare(a.name))}static ɵfac=i.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"22.2.1",ngImport:i,type:l,deps:[],target:i.ɵɵFactoryTarget.Component});static ɵcmp=i.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"22.2.1",type:l,isStandalone:true,selector:"templates-editor",inputs:{theme:{classPropertyName:"theme",publicName:"theme",isSignal:true,isRequired:false,transformFunction:null}},viewQueries:[{propertyName:"sidebarRef",first:true,predicate:["sidebar"],descendants:true}],ngImport:i,template:"<div class=\"templates\" data-testid=\"templates-editor-root\">\n <aside class=\"templates__sidebar\" #sidebar>\n <header class=\"templates__sidebar-header\">\n <h3 class=\"templates__sidebar-title\">\n {{ 'templates.title' | uiT: 'Templates' }}\n @if (hasTemplates()) {\n <span class=\"templates__count\">{{ templates().length }}</span>\n }\n </h3>\n <builder-icon-button\n icon=\"add\"\n size=\"sm\"\n testId=\"templates-add\"\n [ariaLabel]=\"'templates.add' | uiT: 'Add template'\"\n [title]=\"'templates.add' | uiT: 'Add template'\"\n (clicked)=\"addTemplate()\"\n />\n </header>\n\n @if (!hasTemplates()) {\n <div class=\"templates__empty\">\n <span>{{ 'templates.empty' | uiT: 'No templates yet.' }}</span>\n <builder-action-button\n tone=\"primary\"\n size=\"sm\"\n icon=\"add\"\n [label]=\"'templates.add' | uiT: 'Add template'\"\n testId=\"templates-add-empty\"\n (clicked)=\"addTemplate()\"\n />\n </div>\n } @else {\n <ul class=\"templates__list\">\n @for (template of templates(); track trackByName($index, template)) {\n <li\n class=\"templates__list-row\"\n [class.templates__list-row--active]=\"isSelected(template.name)\"\n >\n <button\n type=\"button\"\n class=\"templates__item\"\n (click)=\"selectTemplate(template.name)\"\n [attr.data-testid]=\"'templates-item-' + template.name\"\n >\n <span class=\"templates__item-title\">{{ template.title || template.name }}</span>\n <span class=\"templates__item-name\">{{ template.name }}</span>\n </button>\n <builder-icon-button\n class=\"templates__item-delete\"\n [className]=\"'templates__item-delete'\"\n icon=\"delete\"\n tone=\"danger\"\n size=\"sm\"\n [ghost]=\"true\"\n (clicked)=\"deleteTemplate(template.name)\"\n [ariaLabel]=\"'templates.delete' | uiT: 'Delete'\"\n [title]=\"'templates.delete' | uiT: 'Delete'\"\n [testId]=\"'templates-delete-' + template.name\"\n />\n </li>\n }\n </ul>\n }\n\n <div\n class=\"templates__resize-handle\"\n data-testid=\"templates-sidebar-resize\"\n (mousedown)=\"onSidebarResizeMouseDown($event)\"\n ></div>\n </aside>\n\n <section class=\"templates__editor\">\n @if (draft(); as currentDraft) {\n <div class=\"templates__workspace\">\n <div class=\"templates__workspace-panel templates__workspace-panel--content\">\n <section class=\"templates__card templates__card--editor\">\n <header class=\"templates__card-header\">\n <h3 class=\"templates__card-title\">\n {{ 'templates.content' | uiT: 'Template (Angular syntax)' }}\n </h3>\n <builder-icon-button\n icon=\"code_blocks\"\n size=\"xs\"\n [ghost]=\"true\"\n testId=\"templates-format\"\n [ariaLabel]=\"'templates.format' | uiT: 'Format template'\"\n [title]=\"'templates.format' | uiT: 'Format template'\"\n (clicked)=\"formatTemplateContent()\"\n />\n </header>\n <div class=\"templates__card-body\">\n <native-code-editor\n language=\"template\"\n [theme]=\"theme()\"\n [value]=\"currentDraft.content || ''\"\n (valueChange)=\"updateDraftField('content', $event)\"\n (editorBlur)=\"onTemplateContentBlur($event)\"\n data-testid=\"templates-content\"\n />\n </div>\n @if (formatError()) {\n <div class=\"templates__alert\" role=\"alert\">\n {{ formatError() | uiT: formatError() }}\n </div>\n }\n </section>\n\n <section class=\"templates__card templates__card--editor\">\n <header class=\"templates__card-header\">\n <h3 class=\"templates__card-title\">{{ 'templates.css' | uiT: 'CSS classes' }}</h3>\n <builder-icon-button\n icon=\"code_blocks\"\n size=\"xs\"\n [ghost]=\"true\"\n testId=\"templates-css-format\"\n [ariaLabel]=\"'templates.css.format' | uiT: 'Format CSS'\"\n [title]=\"'templates.css.format' | uiT: 'Format CSS'\"\n (clicked)=\"formatTemplateCss()\"\n />\n </header>\n <div class=\"templates__card-body\">\n <native-code-editor\n language=\"css\"\n [theme]=\"theme()\"\n [value]=\"currentDraft.css || ''\"\n (valueChange)=\"updateDraftField('css', $event)\"\n (editorBlur)=\"onTemplateCssBlur($event)\"\n data-testid=\"templates-css\"\n />\n </div>\n @if (cssFormatError()) {\n <div class=\"templates__alert\" role=\"alert\">\n {{ cssFormatError() | uiT: cssFormatError() }}\n </div>\n }\n </section>\n </div>\n\n <div class=\"templates__workspace-panel\">\n <section class=\"templates__card templates__card--settings\">\n <header class=\"templates__card-header\">\n <h3 class=\"templates__card-title\">\n {{ 'templates.settings' | uiT: 'Template settings' }}\n </h3>\n @if (isDirty()) {\n <span\n class=\"templates__dirty-dot\"\n [title]=\"'templates.unsaved' | uiT: 'Unsaved changes'\"\n ></span>\n }\n <builder-action-button\n tone=\"primary\"\n size=\"sm\"\n [label]=\"'templates.save' | uiT: 'Save'\"\n testId=\"templates-save\"\n (clicked)=\"saveDraft()\"\n />\n </header>\n <div class=\"templates__settings\">\n <label class=\"templates__field\">\n <span>{{ 'templates.name' | uiT: 'Name' }}</span>\n <input\n type=\"text\"\n class=\"nvb-control__text-input\"\n [ngModel]=\"currentDraft.name\"\n (ngModelChange)=\"updateDraftField('name', $event)\"\n data-testid=\"templates-name\"\n />\n </label>\n\n <label class=\"templates__field\">\n <span>{{ 'templates.titleField' | uiT: 'Title' }}</span>\n <input\n type=\"text\"\n class=\"nvb-control__text-input\"\n [ngModel]=\"currentDraft.title\"\n (ngModelChange)=\"updateDraftField('title', $event)\"\n data-testid=\"templates-title\"\n />\n </label>\n </div>\n @if (error()) {\n <div class=\"templates__alert\" role=\"alert\" data-testid=\"templates-error\">\n {{ error() | uiT: error() }}\n </div>\n }\n </section>\n\n <section class=\"templates__card templates__card--preview\">\n <header class=\"templates__card-header\">\n <h3 class=\"templates__card-title\">\n {{ 'templates.previewTitle' | uiT: 'Preview' }}\n </h3>\n </header>\n <div class=\"templates__preview\" data-testid=\"templates-preview\">\n @if (previewTemplateCss()) {\n <nvb-style-outlet [cssText]=\"previewTemplateCss()\"></nvb-style-outlet>\n }\n @if (!previewCard()) {\n <div class=\"templates__preview-placeholder\">\n {{ 'templates.preview.empty' | uiT: 'No preview object.' }}\n </div>\n } @else {\n <article\n class=\"templates__preview-card\"\n [attr.data-nvb-template-scope]=\"previewTemplateScopeId\"\n [innerHTML]=\"previewCard()\"\n (click)=\"onPreviewTemplateClick($event, previewItem()!, 0)\"\n ></article>\n }\n </div>\n <div class=\"templates__preview-data\">\n <header class=\"templates__card-header templates__card-header--sub\">\n <h4 class=\"templates__card-title\">\n {{ 'templates.previewData' | uiT: 'Preview data (JSON)' }}\n </h4>\n </header>\n <div class=\"templates__preview-data-editor\">\n <native-code-editor\n language=\"json\"\n [theme]=\"theme()\"\n [value]=\"previewItemsJson()\"\n (valueChange)=\"previewItemsJson.set($event)\"\n data-testid=\"templates-preview-data\"\n />\n </div>\n @if (previewJsonError()) {\n <div class=\"templates__alert\" role=\"alert\">\n {{ previewJsonError() | uiT: 'Preview data must be a valid JSON object.' }}\n </div>\n }\n </div>\n </section>\n </div>\n </div>\n } @else {\n <div class=\"templates__placeholder\">\n {{ 'templates.select' | uiT: 'Select a template to edit.' }}\n </div>\n }\n </section>\n</div>\n",styles:['@charset "UTF-8";:host{display:block;height:100%;overflow:hidden;background:color-mix(in oklab,var(--color-neutral-050) 84%,white)}.templates{height:100%;min-height:0;display:grid;grid-template-columns:auto minmax(0,1fr);gap:10px;padding:10px;overflow:hidden}.templates__card{display:flex;flex-direction:column;min-width:0;min-height:0;background:var(--nvb-card-bg);border:1px solid var(--nvb-card-border-color);border-radius:var(--nvb-card-radius);box-shadow:var(--nvb-card-shadow);overflow:hidden}.templates__card-header{flex:0 0 auto;display:flex;align-items:center;gap:8px;min-height:36px;padding:4px 8px 4px 12px;border-bottom:1px solid var(--color-neutral-200);background:var(--nvb-card-bg)}.templates__card-header--sub{border-top:1px solid var(--color-neutral-200);border-bottom:none;min-height:30px}.templates__card-title{flex:1 1 auto;margin:0;font-size:12px;font-weight:600;line-height:16px;color:var(--color-neutral-700)}.templates__card-header--sub .templates__card-title{color:var(--color-neutral-600)}.templates__card-body{flex:1 1 auto;min-height:0;padding:8px;overflow:hidden}.templates__sidebar{position:relative;display:flex;flex-direction:column;width:280px;min-width:200px;max-width:400px;min-height:0;background:var(--nvb-card-bg);border:1px solid var(--nvb-card-border-color);border-radius:var(--nvb-card-radius);box-shadow:var(--nvb-card-shadow);overflow:hidden}.templates__sidebar-header{flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;gap:8px;min-height:36px;padding:4px 8px 4px 12px;border-bottom:1px solid var(--color-neutral-200);background:var(--nvb-card-bg)}.templates__sidebar-title{display:inline-flex;align-items:center;gap:6px;margin:0;font-size:12px;font-weight:600;line-height:16px;color:var(--color-neutral-700)}.templates__count{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:16px;padding:0 5px;border-radius:999px;background:var(--color-neutral-100);color:var(--color-neutral-600);font-size:10px;font-weight:600;letter-spacing:0}.templates__resize-handle{position:absolute;top:0;right:0;width:6px;height:100%;z-index:10;cursor:ew-resize;background-color:transparent}.templates__resize-handle:after{content:"";position:absolute;top:50%;right:2px;width:2px;height:40px;transform:translateY(-50%);border-radius:999px;background-color:var(--color-neutral-300);opacity:0;transition:opacity .15s ease,background-color .15s ease}.templates__resize-handle:hover:after{opacity:1;background-color:var(--color-primary-500)}.templates__list{list-style:none;margin:0;padding:6px;display:grid;gap:2px;align-content:start;grid-auto-rows:min-content;flex:1 1 auto;min-height:0;overflow:auto}.templates__list-row{position:relative;display:flex;align-items:center;min-width:0}.templates__item{flex:1 1 auto;min-width:0;display:grid;gap:1px;text-align:left;border:none;border-left:2px solid transparent;border-radius:var(--radius-md);background:transparent;padding:6px 34px 6px 10px;cursor:pointer;font:inherit;transition:background-color .14s ease,border-color .14s ease}.templates__item-title{font-size:13px;font-weight:600;color:var(--color-neutral-700);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.templates__item-name{font-size:11px;color:var(--color-neutral-400);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.templates__item:hover{background:color-mix(in oklab,var(--color-neutral-100) 70%,var(--color-neutral-000))}.templates__list-row--active .templates__item{border-left-color:var(--color-primary-500);background:color-mix(in oklab,var(--color-primary-500) 8%,var(--color-surface-mix-target, white))}.templates__list-row--active .templates__item-title{color:var(--color-primary-700)}.templates__item-delete{position:absolute;top:50%;right:6px;transform:translateY(-50%);opacity:0;transition:opacity .14s ease}.templates__list-row:hover .templates__item-delete,.templates__list-row:focus-within .templates__item-delete,.templates__list-row--active .templates__item-delete{opacity:1}.templates__empty{flex:1 1 auto;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:16px;color:var(--color-neutral-500);font-size:13px;text-align:center}.templates__editor{display:flex;flex-direction:column;min-width:0;min-height:0;overflow:hidden}.templates__workspace{display:grid;grid-template-columns:minmax(0,1fr) minmax(340px,.82fr);gap:10px;flex:1 1 auto;min-height:0;overflow:hidden}.templates__workspace-panel{min-width:0;min-height:0;display:flex;flex-direction:column;gap:10px;overflow:hidden}.templates__workspace-panel--content .templates__card--editor{flex:1 1 0}.templates__card--settings{flex:0 0 auto;--nvb-input-height: 36px;--nvb-input-font-size: 13px}.templates__settings{display:grid;grid-template-columns:1fr 1fr;gap:10px;padding:10px 12px 12px}.templates__field{display:flex;flex-direction:column;gap:4px;min-width:0}.templates__field span{font-size:12px;color:var(--color-neutral-600)}.templates__field .nvb-control__text-input{height:36px;min-height:36px}.templates__dirty-dot{flex:0 0 auto;width:8px;height:8px;border-radius:50%;background:var(--color-caution-500)}.templates__card--preview{flex:1 1 auto}.templates__preview{flex:1 1 auto;min-height:0;padding:16px;overflow:auto;background-color:color-mix(in oklab,var(--color-neutral-050) 60%,var(--color-neutral-000));background-image:radial-gradient(var(--color-neutral-200) 1px,transparent 1px);background-size:16px 16px}.templates__preview-card{all:unset;display:block;width:100%}.templates__preview-placeholder{color:var(--color-neutral-500);font-size:13px}.templates__preview-data{flex:0 0 auto;display:flex;flex-direction:column}.templates__preview-data-editor{height:120px;padding:8px;overflow:hidden}.templates__placeholder{flex:1 1 auto;display:flex;align-items:center;justify-content:center;color:var(--color-neutral-500);font-size:13px;background:var(--nvb-card-bg);border:1px solid var(--nvb-card-border-color);border-radius:var(--nvb-card-radius);box-shadow:var(--nvb-card-shadow)}.templates__alert{flex:0 0 auto;margin:8px;padding:8px 10px;border:1px solid color-mix(in oklab,var(--color-risk-500) 35%,transparent);border-radius:var(--radius-md);background:color-mix(in oklab,var(--color-risk-050) 70%,var(--color-surface-mix-target, white));color:var(--color-risk-700);font-size:12px;line-height:1.4}@media(max-width:1000px){.templates{grid-template-columns:1fr;grid-template-rows:minmax(220px,40%) minmax(0,1fr)}.templates__sidebar{width:auto!important;max-width:none}.templates__resize-handle{display:none}.templates__workspace{grid-template-columns:1fr;overflow:auto}.templates__workspace-panel{overflow:visible}.templates__workspace-panel--content .templates__card--editor{flex:1 1 auto;min-height:220px}.templates__card--preview .templates__preview{min-height:160px}.templates__settings{grid-template-columns:1fr}}\n'],dependencies:[{kind:"ngmodule",type:k},{kind:"directive",type:g.DefaultValueAccessor,selector:"input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]"},{kind:"directive",type:g.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:g.NgModel,selector:"[ngModel]:not([formControlName]):not([formControl])",inputs:["name","disabled","ngModel","ngModelOptions"],outputs:["ngModelChange"],exportAs:["ngModel"]},{kind:"component",type:T,selector:"native-code-editor",inputs:["value","language","theme","readOnly","completions"],outputs:["valueChange","editorBlur"]},{kind:"component",type:y,selector:"nvb-style-outlet",inputs:["cssText","renderInPlace","styleKey"]},{kind:"component",type:f,selector:"builder-action-button",inputs:["label","ariaLabel","testId","title","icon","className","tone","size","align","active","fullWidth","disabled"],outputs:["clicked"]},{kind:"component",type:x,selector:"builder-icon-button",inputs:["icon","ariaLabel","title","testId","iconSet","size","tone","ghost","dragHandle","active","disabled","className"],outputs:["clicked"]},{kind:"pipe",type:S,name:"uiT"}],changeDetection:i.ChangeDetectionStrategy.Eager})};i.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"22.2.1",ngImport:i,type:D,decorators:[{type:A,args:[{selector:"templates-editor",imports:[k,S,T,y,f,x],changeDetection:F.Eager,template:"<div class=\"templates\" data-testid=\"templates-editor-root\">\n <aside class=\"templates__sidebar\" #sidebar>\n <header class=\"templates__sidebar-header\">\n <h3 class=\"templates__sidebar-title\">\n {{ 'templates.title' | uiT: 'Templates' }}\n @if (hasTemplates()) {\n <span class=\"templates__count\">{{ templates().length }}</span>\n }\n </h3>\n <builder-icon-button\n icon=\"add\"\n size=\"sm\"\n testId=\"templates-add\"\n [ariaLabel]=\"'templates.add' | uiT: 'Add template'\"\n [title]=\"'templates.add' | uiT: 'Add template'\"\n (clicked)=\"addTemplate()\"\n />\n </header>\n\n @if (!hasTemplates()) {\n <div class=\"templates__empty\">\n <span>{{ 'templates.empty' | uiT: 'No templates yet.' }}</span>\n <builder-action-button\n tone=\"primary\"\n size=\"sm\"\n icon=\"add\"\n [label]=\"'templates.add' | uiT: 'Add template'\"\n testId=\"templates-add-empty\"\n (clicked)=\"addTemplate()\"\n />\n </div>\n } @else {\n <ul class=\"templates__list\">\n @for (template of templates(); track trackByName($index, template)) {\n <li\n class=\"templates__list-row\"\n [class.templates__list-row--active]=\"isSelected(template.name)\"\n >\n <button\n type=\"button\"\n class=\"templates__item\"\n (click)=\"selectTemplate(template.name)\"\n [attr.data-testid]=\"'templates-item-' + template.name\"\n >\n <span class=\"templates__item-title\">{{ template.title || template.name }}</span>\n <span class=\"templates__item-name\">{{ template.name }}</span>\n </button>\n <builder-icon-button\n class=\"templates__item-delete\"\n [className]=\"'templates__item-delete'\"\n icon=\"delete\"\n tone=\"danger\"\n size=\"sm\"\n [ghost]=\"true\"\n (clicked)=\"deleteTemplate(template.name)\"\n [ariaLabel]=\"'templates.delete' | uiT: 'Delete'\"\n [title]=\"'templates.delete' | uiT: 'Delete'\"\n [testId]=\"'templates-delete-' + template.name\"\n />\n </li>\n }\n </ul>\n }\n\n <div\n class=\"templates__resize-handle\"\n data-testid=\"templates-sidebar-resize\"\n (mousedown)=\"onSidebarResizeMouseDown($event)\"\n ></div>\n </aside>\n\n <section class=\"templates__editor\">\n @if (draft(); as currentDraft) {\n <div class=\"templates__workspace\">\n <div class=\"templates__workspace-panel templates__workspace-panel--content\">\n <section class=\"templates__card templates__card--editor\">\n <header class=\"templates__card-header\">\n <h3 class=\"templates__card-title\">\n {{ 'templates.content' | uiT: 'Template (Angular syntax)' }}\n </h3>\n <builder-icon-button\n icon=\"code_blocks\"\n size=\"xs\"\n [ghost]=\"true\"\n testId=\"templates-format\"\n [ariaLabel]=\"'templates.format' | uiT: 'Format template'\"\n [title]=\"'templates.format' | uiT: 'Format template'\"\n (clicked)=\"formatTemplateContent()\"\n />\n </header>\n <div class=\"templates__card-body\">\n <native-code-editor\n language=\"template\"\n [theme]=\"theme()\"\n [value]=\"currentDraft.content || ''\"\n (valueChange)=\"updateDraftField('content', $event)\"\n (editorBlur)=\"onTemplateContentBlur($event)\"\n data-testid=\"templates-content\"\n />\n </div>\n @if (formatError()) {\n <div class=\"templates__alert\" role=\"alert\">\n {{ formatError() | uiT: formatError() }}\n </div>\n }\n </section>\n\n <section class=\"templates__card templates__card--editor\">\n <header class=\"templates__card-header\">\n <h3 class=\"templates__card-title\">{{ 'templates.css' | uiT: 'CSS classes' }}</h3>\n <builder-icon-button\n icon=\"code_blocks\"\n size=\"xs\"\n [ghost]=\"true\"\n testId=\"templates-css-format\"\n [ariaLabel]=\"'templates.css.format' | uiT: 'Format CSS'\"\n [title]=\"'templates.css.format' | uiT: 'Format CSS'\"\n (clicked)=\"formatTemplateCss()\"\n />\n </header>\n <div class=\"templates__card-body\">\n <native-code-editor\n language=\"css\"\n [theme]=\"theme()\"\n [value]=\"currentDraft.css || ''\"\n (valueChange)=\"updateDraftField('css', $event)\"\n (editorBlur)=\"onTemplateCssBlur($event)\"\n data-testid=\"templates-css\"\n />\n </div>\n @if (cssFormatError()) {\n <div class=\"templates__alert\" role=\"alert\">\n {{ cssFormatError() | uiT: cssFormatError() }}\n </div>\n }\n </section>\n </div>\n\n <div class=\"templates__workspace-panel\">\n <section class=\"templates__card templates__card--settings\">\n <header class=\"templates__card-header\">\n <h3 class=\"templates__card-title\">\n {{ 'templates.settings' | uiT: 'Template settings' }}\n </h3>\n @if (isDirty()) {\n <span\n class=\"templates__dirty-dot\"\n [title]=\"'templates.unsaved' | uiT: 'Unsaved changes'\"\n ></span>\n }\n <builder-action-button\n tone=\"primary\"\n size=\"sm\"\n [label]=\"'templates.save' | uiT: 'Save'\"\n testId=\"templates-save\"\n (clicked)=\"saveDraft()\"\n />\n </header>\n <div class=\"templates__settings\">\n <label class=\"templates__field\">\n <span>{{ 'templates.name' | uiT: 'Name' }}</span>\n <input\n type=\"text\"\n class=\"nvb-control__text-input\"\n [ngModel]=\"currentDraft.name\"\n (ngModelChange)=\"updateDraftField('name', $event)\"\n data-testid=\"templates-name\"\n />\n </label>\n\n <label class=\"templates__field\">\n <span>{{ 'templates.titleField' | uiT: 'Title' }}</span>\n <input\n type=\"text\"\n class=\"nvb-control__text-input\"\n [ngModel]=\"currentDraft.title\"\n (ngModelChange)=\"updateDraftField('title', $event)\"\n data-testid=\"templates-title\"\n />\n </label>\n </div>\n @if (error()) {\n <div class=\"templates__alert\" role=\"alert\" data-testid=\"templates-error\">\n {{ error() | uiT: error() }}\n </div>\n }\n </section>\n\n <section class=\"templates__card templates__card--preview\">\n <header class=\"templates__card-header\">\n <h3 class=\"templates__card-title\">\n {{ 'templates.previewTitle' | uiT: 'Preview' }}\n </h3>\n </header>\n <div class=\"templates__preview\" data-testid=\"templates-preview\">\n @if (previewTemplateCss()) {\n <nvb-style-outlet [cssText]=\"previewTemplateCss()\"></nvb-style-outlet>\n }\n @if (!previewCard()) {\n <div class=\"templates__preview-placeholder\">\n {{ 'templates.preview.empty' | uiT: 'No preview object.' }}\n </div>\n } @else {\n <article\n class=\"templates__preview-card\"\n [attr.data-nvb-template-scope]=\"previewTemplateScopeId\"\n [innerHTML]=\"previewCard()\"\n (click)=\"onPreviewTemplateClick($event, previewItem()!, 0)\"\n ></article>\n }\n </div>\n <div class=\"templates__preview-data\">\n <header class=\"templates__card-header templates__card-header--sub\">\n <h4 class=\"templates__card-title\">\n {{ 'templates.previewData' | uiT: 'Preview data (JSON)' }}\n </h4>\n </header>\n <div class=\"templates__preview-data-editor\">\n <native-code-editor\n language=\"json\"\n [theme]=\"theme()\"\n [value]=\"previewItemsJson()\"\n (valueChange)=\"previewItemsJson.set($event)\"\n data-testid=\"templates-preview-data\"\n />\n </div>\n @if (previewJsonError()) {\n <div class=\"templates__alert\" role=\"alert\">\n {{ previewJsonError() | uiT: 'Preview data must be a valid JSON object.' }}\n </div>\n }\n </div>\n </section>\n </div>\n </div>\n } @else {\n <div class=\"templates__placeholder\">\n {{ 'templates.select' | uiT: 'Select a template to edit.' }}\n </div>\n }\n </section>\n</div>\n",styles:['@charset "UTF-8";:host{display:block;height:100%;overflow:hidden;background:color-mix(in oklab,var(--color-neutral-050) 84%,white)}.templates{height:100%;min-height:0;display:grid;grid-template-columns:auto minmax(0,1fr);gap:10px;padding:10px;overflow:hidden}.templates__card{display:flex;flex-direction:column;min-width:0;min-height:0;background:var(--nvb-card-bg);border:1px solid var(--nvb-card-border-color);border-radius:var(--nvb-card-radius);box-shadow:var(--nvb-card-shadow);overflow:hidden}.templates__card-header{flex:0 0 auto;display:flex;align-items:center;gap:8px;min-height:36px;padding:4px 8px 4px 12px;border-bottom:1px solid var(--color-neutral-200);background:var(--nvb-card-bg)}.templates__card-header--sub{border-top:1px solid var(--color-neutral-200);border-bottom:none;min-height:30px}.templates__card-title{flex:1 1 auto;margin:0;font-size:12px;font-weight:600;line-height:16px;color:var(--color-neutral-700)}.templates__card-header--sub .templates__card-title{color:var(--color-neutral-600)}.templates__card-body{flex:1 1 auto;min-height:0;padding:8px;overflow:hidden}.templates__sidebar{position:relative;display:flex;flex-direction:column;width:280px;min-width:200px;max-width:400px;min-height:0;background:var(--nvb-card-bg);border:1px solid var(--nvb-card-border-color);border-radius:var(--nvb-card-radius);box-shadow:var(--nvb-card-shadow);overflow:hidden}.templates__sidebar-header{flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;gap:8px;min-height:36px;padding:4px 8px 4px 12px;border-bottom:1px solid var(--color-neutral-200);background:var(--nvb-card-bg)}.templates__sidebar-title{display:inline-flex;align-items:center;gap:6px;margin:0;font-size:12px;font-weight:600;line-height:16px;color:var(--color-neutral-700)}.templates__count{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:16px;padding:0 5px;border-radius:999px;background:var(--color-neutral-100);color:var(--color-neutral-600);font-size:10px;font-weight:600;letter-spacing:0}.templates__resize-handle{position:absolute;top:0;right:0;width:6px;height:100%;z-index:10;cursor:ew-resize;background-color:transparent}.templates__resize-handle:after{content:"";position:absolute;top:50%;right:2px;width:2px;height:40px;transform:translateY(-50%);border-radius:999px;background-color:var(--color-neutral-300);opacity:0;transition:opacity .15s ease,background-color .15s ease}.templates__resize-handle:hover:after{opacity:1;background-color:var(--color-primary-500)}.templates__list{list-style:none;margin:0;padding:6px;display:grid;gap:2px;align-content:start;grid-auto-rows:min-content;flex:1 1 auto;min-height:0;overflow:auto}.templates__list-row{position:relative;display:flex;align-items:center;min-width:0}.templates__item{flex:1 1 auto;min-width:0;display:grid;gap:1px;text-align:left;border:none;border-left:2px solid transparent;border-radius:var(--radius-md);background:transparent;padding:6px 34px 6px 10px;cursor:pointer;font:inherit;transition:background-color .14s ease,border-color .14s ease}.templates__item-title{font-size:13px;font-weight:600;color:var(--color-neutral-700);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.templates__item-name{font-size:11px;color:var(--color-neutral-400);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.templates__item:hover{background:color-mix(in oklab,var(--color-neutral-100) 70%,var(--color-neutral-000))}.templates__list-row--active .templates__item{border-left-color:var(--color-primary-500);background:color-mix(in oklab,var(--color-primary-500) 8%,var(--color-surface-mix-target, white))}.templates__list-row--active .templates__item-title{color:var(--color-primary-700)}.templates__item-delete{position:absolute;top:50%;right:6px;transform:translateY(-50%);opacity:0;transition:opacity .14s ease}.templates__list-row:hover .templates__item-delete,.templates__list-row:focus-within .templates__item-delete,.templates__list-row--active .templates__item-delete{opacity:1}.templates__empty{flex:1 1 auto;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:16px;color:var(--color-neutral-500);font-size:13px;text-align:center}.templates__editor{display:flex;flex-direction:column;min-width:0;min-height:0;overflow:hidden}.templates__workspace{display:grid;grid-template-columns:minmax(0,1fr) minmax(340px,.82fr);gap:10px;flex:1 1 auto;min-height:0;overflow:hidden}.templates__workspace-panel{min-width:0;min-height:0;display:flex;flex-direction:column;gap:10px;overflow:hidden}.templates__workspace-panel--content .templates__card--editor{flex:1 1 0}.templates__card--settings{flex:0 0 auto;--nvb-input-height: 36px;--nvb-input-font-size: 13px}.templates__settings{display:grid;grid-template-columns:1fr 1fr;gap:10px;padding:10px 12px 12px}.templates__field{display:flex;flex-direction:column;gap:4px;min-width:0}.templates__field span{font-size:12px;color:var(--color-neutral-600)}.templates__field .nvb-control__text-input{height:36px;min-height:36px}.templates__dirty-dot{flex:0 0 auto;width:8px;height:8px;border-radius:50%;background:var(--color-caution-500)}.templates__card--preview{flex:1 1 auto}.templates__preview{flex:1 1 auto;min-height:0;padding:16px;overflow:auto;background-color:color-mix(in oklab,var(--color-neutral-050) 60%,var(--color-neutral-000));background-image:radial-gradient(var(--color-neutral-200) 1px,transparent 1px);background-size:16px 16px}.templates__preview-card{all:unset;display:block;width:100%}.templates__preview-placeholder{color:var(--color-neutral-500);font-size:13px}.templates__preview-data{flex:0 0 auto;display:flex;flex-direction:column}.templates__preview-data-editor{height:120px;padding:8px;overflow:hidden}.templates__placeholder{flex:1 1 auto;display:flex;align-items:center;justify-content:center;color:var(--color-neutral-500);font-size:13px;background:var(--nvb-card-bg);border:1px solid var(--nvb-card-border-color);border-radius:var(--nvb-card-radius);box-shadow:var(--nvb-card-shadow)}.templates__alert{flex:0 0 auto;margin:8px;padding:8px 10px;border:1px solid color-mix(in oklab,var(--color-risk-500) 35%,transparent);border-radius:var(--radius-md);background:color-mix(in oklab,var(--color-risk-050) 70%,var(--color-surface-mix-target, white));color:var(--color-risk-700);font-size:12px;line-height:1.4}@media(max-width:1000px){.templates{grid-template-columns:1fr;grid-template-rows:minmax(220px,40%) minmax(0,1fr)}.templates__sidebar{width:auto!important;max-width:none}.templates__resize-handle{display:none}.templates__workspace{grid-template-columns:1fr;overflow:auto}.templates__workspace-panel{overflow:visible}.templates__workspace-panel--content .templates__card--editor{flex:1 1 auto;min-height:220px}.templates__card--preview .templates__preview{min-height:160px}.templates__settings{grid-template-columns:1fr}}\n']}]}],propDecorators:{sidebarRef:[{type:B,args:["sidebar"]}],theme:[{type:i.Input,args:[{isSignal:true,alias:"theme",required:false}]}]}});function J(){return M({featurePacks:[{id:w,title:"Templates",capabilities:[b],builderTabs:[{id:N.TEMPLATES,label:"tab.templates",component:D,order:350,icon:"auto_awesome_mosaic",description:"tab.templates.description"}],uiDictionaries:{en:{"tab.templates.description":"Reusable card, row and option markup"}}}]})}export{b as NGX_VIEW_BUILDER_TEMPLATES_CAPABILITY,w as NGX_VIEW_BUILDER_TEMPLATES_FEATURE_PACK_ID,J as provideNgxViewBuilderTemplates};
|
|
2
|
+
${t}`}async formatHtmlWithPrettier(e){const[{format:t},a]=await Promise.all([import("prettier/standalone"),import("prettier/plugins/html")]);const r=a.default??a;return t(String(e??""),{parser:"angular",plugins:[r],printWidth:100,tabWidth:2})}async formatCssWithPrettier(e){const[{format:t},a]=await Promise.all([import("prettier/standalone"),import("prettier/plugins/postcss")]);const r=a.default??a;return t(String(e??""),{parser:"css",plugins:[r],printWidth:100,tabWidth:2})}reload(e){const t=this.readTemplatesFromStructure();const a=this.sortTemplates(t);this.templates.set(a);const r=o=>a.some(d=>d.name===o);const n=(e&&r(e)?e:r(this.selectedTemplateName())?this.selectedTemplateName():"")||a[0]?.name||"";if(!n){this.selectedTemplateName.set("");this.draft.set(null);this.error.set("");this.formatError.set("");this.cssFormatError.set("");return}this.selectTemplate(n)}notifyStructureChanged(){this.eventService.afterPropertyChanged.fire({payload:null});this.ngxViewBuilderApiService.notifyStructureChanged()}persistTemplates(e){const t=this.creatorStructureService.getStructure();if(!t)return;if(!t.settings||typeof t.settings!=="object")t.settings={width:"1182",language:"lt"};t.settings.templates=this.sortTemplates(e).map(a=>({...a}));this.notifyStructureChanged()}readTemplatesFromStructure(){const e=this.creatorStructureService.getStructure()?.settings?.templates;if(!Array.isArray(e))return[];return e.map(t=>this.normalizeTemplate(t)).filter(t=>t!==null)}normalizeTemplate(e){if(!e||typeof e!=="object")return null;const t=e;const a=String(t["name"]??t["code"]??"").trim();if(!a)return null;const r=String(t["title"]??"").trim();const n=String(t["description"]??"").trim();const o=String(t["css"]??"").trim();const d=String(t["requestBodyJson"]??"").trim();const c=String(t["extraJsonSettings"]??"").trim();const u=Array.isArray(t["tags"])?t["tags"].map(h=>String(h??"").trim()).filter(h=>h.length>0):[];const s={...t,name:a,title:r||void 0,description:n||void 0,content:String(t["content"]??""),css:o||void 0,requestBodyJson:d||void 0,extraJsonSettings:c||void 0,tags:u.length>0?u:void 0};delete s["code"];return s}sortTemplates(e){return[...e].sort((t,a)=>t.name.localeCompare(a.name))}static ɵfac=i.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"22.2.1",ngImport:i,type:l,deps:[],target:i.ɵɵFactoryTarget.Component});static ɵcmp=i.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"22.2.1",type:l,isStandalone:true,selector:"templates-editor",inputs:{theme:{classPropertyName:"theme",publicName:"theme",isSignal:true,isRequired:false,transformFunction:null}},viewQueries:[{propertyName:"sidebarRef",first:true,predicate:["sidebar"],descendants:true}],ngImport:i,template:"<div class=\"templates\" data-testid=\"templates-editor-root\">\n <aside class=\"templates__sidebar\" #sidebar>\n <header class=\"templates__sidebar-header\">\n <h3 class=\"templates__sidebar-title\">\n {{ 'templates.title' | uiT: 'Templates' }}\n @if (hasTemplates()) {\n <span class=\"templates__count\">{{ templates().length }}</span>\n }\n </h3>\n <builder-icon-button\n icon=\"add\"\n size=\"sm\"\n testId=\"templates-add\"\n [ariaLabel]=\"'templates.add' | uiT: 'Add template'\"\n [title]=\"'templates.add' | uiT: 'Add template'\"\n (clicked)=\"addTemplate()\"\n />\n </header>\n\n @if (!hasTemplates()) {\n <div class=\"templates__empty\">\n <span>{{ 'templates.empty' | uiT: 'No templates yet.' }}</span>\n <builder-action-button\n tone=\"primary\"\n size=\"sm\"\n icon=\"add\"\n [label]=\"'templates.add' | uiT: 'Add template'\"\n testId=\"templates-add-empty\"\n (clicked)=\"addTemplate()\"\n />\n </div>\n } @else {\n <ul class=\"templates__list\">\n @for (template of templates(); track trackByName($index, template)) {\n <li\n class=\"templates__list-row\"\n [class.templates__list-row--active]=\"isSelected(template.name)\"\n >\n <button\n type=\"button\"\n class=\"templates__item\"\n (click)=\"selectTemplate(template.name)\"\n [attr.data-testid]=\"'templates-item-' + template.name\"\n >\n <span class=\"templates__item-title\">{{ template.title || template.name }}</span>\n <span class=\"templates__item-name\">{{ template.name }}</span>\n </button>\n <builder-icon-button\n class=\"templates__item-delete\"\n [className]=\"'templates__item-delete'\"\n icon=\"delete\"\n tone=\"danger\"\n size=\"sm\"\n [ghost]=\"true\"\n (clicked)=\"deleteTemplate(template.name)\"\n [ariaLabel]=\"'templates.delete' | uiT: 'Delete'\"\n [title]=\"'templates.delete' | uiT: 'Delete'\"\n [testId]=\"'templates-delete-' + template.name\"\n />\n </li>\n }\n </ul>\n }\n\n <div\n class=\"templates__resize-handle\"\n data-testid=\"templates-sidebar-resize\"\n (mousedown)=\"onSidebarResizeMouseDown($event)\"\n ></div>\n </aside>\n\n <section class=\"templates__editor\">\n @if (draft(); as currentDraft) {\n <div class=\"templates__workspace\">\n <div class=\"templates__workspace-panel templates__workspace-panel--content\">\n <section class=\"templates__card templates__card--editor\">\n <header class=\"templates__card-header\">\n <h3 class=\"templates__card-title\">\n {{ 'templates.content' | uiT: 'Template (Angular syntax)' }}\n </h3>\n <builder-icon-button\n icon=\"code_blocks\"\n size=\"xs\"\n [ghost]=\"true\"\n testId=\"templates-format\"\n [ariaLabel]=\"'templates.format' | uiT: 'Format template'\"\n [title]=\"'templates.format' | uiT: 'Format template'\"\n (clicked)=\"formatTemplateContent()\"\n />\n </header>\n <div class=\"templates__card-body\">\n <native-code-editor\n language=\"template\"\n [theme]=\"theme()\"\n [value]=\"currentDraft.content || ''\"\n (valueChange)=\"updateDraftField('content', $event)\"\n (editorBlur)=\"onTemplateContentBlur($event)\"\n data-testid=\"templates-content\"\n />\n </div>\n @if (formatError()) {\n <div class=\"templates__alert\" role=\"alert\">\n {{ formatError() | uiT: formatError() }}\n </div>\n }\n </section>\n\n <section class=\"templates__card templates__card--editor\">\n <header class=\"templates__card-header\">\n <h3 class=\"templates__card-title\">{{ 'templates.css' | uiT: 'CSS classes' }}</h3>\n <builder-icon-button\n icon=\"code_blocks\"\n size=\"xs\"\n [ghost]=\"true\"\n testId=\"templates-css-format\"\n [ariaLabel]=\"'templates.css.format' | uiT: 'Format CSS'\"\n [title]=\"'templates.css.format' | uiT: 'Format CSS'\"\n (clicked)=\"formatTemplateCss()\"\n />\n </header>\n <div class=\"templates__card-body\">\n <native-code-editor\n language=\"css\"\n [theme]=\"theme()\"\n [value]=\"currentDraft.css || ''\"\n (valueChange)=\"updateDraftField('css', $event)\"\n (editorBlur)=\"onTemplateCssBlur($event)\"\n data-testid=\"templates-css\"\n />\n </div>\n @if (cssFormatError()) {\n <div class=\"templates__alert\" role=\"alert\">\n {{ cssFormatError() | uiT: cssFormatError() }}\n </div>\n }\n </section>\n </div>\n\n <div class=\"templates__workspace-panel\">\n <section class=\"templates__card templates__card--settings\">\n <header class=\"templates__card-header\">\n <h3 class=\"templates__card-title\">\n {{ 'templates.settings' | uiT: 'Template settings' }}\n </h3>\n @if (isDirty()) {\n <span\n class=\"templates__dirty-dot\"\n [title]=\"'templates.unsaved' | uiT: 'Unsaved changes'\"\n ></span>\n }\n <builder-action-button\n tone=\"primary\"\n size=\"sm\"\n [label]=\"'templates.save' | uiT: 'Save'\"\n testId=\"templates-save\"\n (clicked)=\"saveDraft()\"\n />\n </header>\n <div class=\"templates__settings\">\n <label class=\"templates__field\">\n <span>{{ 'templates.name' | uiT: 'Name' }}</span>\n <input\n type=\"text\"\n class=\"nvb-control__text-input\"\n [ngModel]=\"currentDraft.name\"\n (ngModelChange)=\"updateDraftField('name', $event)\"\n data-testid=\"templates-name\"\n />\n </label>\n\n <label class=\"templates__field\">\n <span>{{ 'templates.titleField' | uiT: 'Title' }}</span>\n <input\n type=\"text\"\n class=\"nvb-control__text-input\"\n [ngModel]=\"currentDraft.title\"\n (ngModelChange)=\"updateDraftField('title', $event)\"\n data-testid=\"templates-title\"\n />\n </label>\n </div>\n @if (error()) {\n <div class=\"templates__alert\" role=\"alert\" data-testid=\"templates-error\">\n {{ error() | uiT: error() }}\n </div>\n }\n </section>\n\n <section class=\"templates__card templates__card--preview\">\n <header class=\"templates__card-header\">\n <h3 class=\"templates__card-title\">\n {{ 'templates.previewTitle' | uiT: 'Preview' }}\n </h3>\n </header>\n <div class=\"templates__preview\" data-testid=\"templates-preview\">\n @if (previewTemplateCss()) {\n <nvb-style-outlet [cssText]=\"previewTemplateCss()\"></nvb-style-outlet>\n }\n @if (!previewCard()) {\n <div class=\"templates__preview-placeholder\">\n {{ 'templates.preview.empty' | uiT: 'No preview object.' }}\n </div>\n } @else {\n <article\n class=\"templates__preview-card\"\n [attr.data-nvb-template-scope]=\"previewTemplateScopeId\"\n [innerHTML]=\"previewCard()\"\n (click)=\"onPreviewTemplateClick($event, previewItem()!, 0)\"\n ></article>\n }\n </div>\n <div class=\"templates__preview-data\">\n <header class=\"templates__card-header templates__card-header--sub\">\n <h4 class=\"templates__card-title\">\n {{ 'templates.previewData' | uiT: 'Preview data (JSON)' }}\n </h4>\n </header>\n <div class=\"templates__preview-data-editor\">\n <native-code-editor\n language=\"json\"\n [theme]=\"theme()\"\n [value]=\"previewItemsJson()\"\n (valueChange)=\"previewItemsJson.set($event)\"\n data-testid=\"templates-preview-data\"\n />\n </div>\n @if (previewJsonError()) {\n <div class=\"templates__alert\" role=\"alert\">\n {{ previewJsonError() | uiT: 'Preview data must be a valid JSON object.' }}\n </div>\n }\n </div>\n </section>\n </div>\n </div>\n } @else {\n <div class=\"templates__placeholder\">\n {{ 'templates.select' | uiT: 'Select a template to edit.' }}\n </div>\n }\n </section>\n</div>\n",styles:['@charset "UTF-8";:host{display:block;height:100%;overflow:hidden;background:color-mix(in oklab,var(--color-neutral-050) 84%,white)}.templates{height:100%;min-height:0;display:grid;grid-template-columns:auto minmax(0,1fr);gap:10px;padding:10px;overflow:hidden}.templates__card{display:flex;flex-direction:column;min-width:0;min-height:0;background:var(--nvb-card-bg);border:1px solid var(--nvb-card-border-color);border-radius:var(--nvb-card-radius);box-shadow:var(--nvb-card-shadow);overflow:hidden}.templates__card-header{flex:0 0 auto;display:flex;align-items:center;gap:8px;min-height:36px;padding:4px 8px 4px 12px;border-bottom:1px solid var(--color-neutral-200);background:var(--nvb-card-bg)}.templates__card-header--sub{border-top:1px solid var(--color-neutral-200);border-bottom:none;min-height:30px}.templates__card-title{flex:1 1 auto;margin:0;font-size:12px;font-weight:600;line-height:16px;color:var(--color-neutral-700)}.templates__card-header--sub .templates__card-title{color:var(--color-neutral-600)}.templates__card-body{flex:1 1 auto;min-height:0;padding:8px;overflow:hidden}.templates__sidebar{position:relative;display:flex;flex-direction:column;width:280px;min-width:200px;max-width:400px;min-height:0;background:var(--nvb-card-bg);border:1px solid var(--nvb-card-border-color);border-radius:var(--nvb-card-radius);box-shadow:var(--nvb-card-shadow);overflow:hidden}.templates__sidebar-header{flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;gap:8px;min-height:36px;padding:4px 8px 4px 12px;border-bottom:1px solid var(--color-neutral-200);background:var(--nvb-card-bg)}.templates__sidebar-title{display:inline-flex;align-items:center;gap:6px;margin:0;font-size:12px;font-weight:600;line-height:16px;color:var(--color-neutral-700)}.templates__count{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:16px;padding:0 5px;border-radius:999px;background:var(--color-neutral-100);color:var(--color-neutral-600);font-size:10px;font-weight:600;letter-spacing:0}.templates__resize-handle{position:absolute;top:0;right:0;width:6px;height:100%;z-index:10;cursor:ew-resize;background-color:transparent}.templates__resize-handle:after{content:"";position:absolute;top:50%;right:2px;width:2px;height:40px;transform:translateY(-50%);border-radius:999px;background-color:var(--color-neutral-300);opacity:0;transition:opacity .15s ease,background-color .15s ease}.templates__resize-handle:hover:after{opacity:1;background-color:var(--color-primary-500)}.templates__list{list-style:none;margin:0;padding:6px;display:grid;gap:2px;align-content:start;grid-auto-rows:min-content;flex:1 1 auto;min-height:0;overflow:auto}.templates__list-row{position:relative;display:flex;align-items:center;min-width:0}.templates__item{flex:1 1 auto;min-width:0;display:grid;gap:1px;text-align:left;border:none;border-left:2px solid transparent;border-radius:var(--radius-md);background:transparent;padding:6px 34px 6px 10px;cursor:pointer;font:inherit;transition:background-color .14s ease,border-color .14s ease}.templates__item-title{font-size:13px;font-weight:600;color:var(--color-neutral-700);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.templates__item-name{font-size:11px;color:var(--color-neutral-400);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.templates__item:hover{background:color-mix(in oklab,var(--color-neutral-100) 70%,var(--color-neutral-000))}.templates__list-row--active .templates__item{border-left-color:var(--color-primary-500);background:color-mix(in oklab,var(--color-primary-500) 8%,var(--color-surface-mix-target, white))}.templates__list-row--active .templates__item-title{color:var(--color-primary-700)}.templates__item-delete{position:absolute;top:50%;right:6px;transform:translateY(-50%);opacity:0;transition:opacity .14s ease}.templates__list-row:hover .templates__item-delete,.templates__list-row:focus-within .templates__item-delete,.templates__list-row--active .templates__item-delete{opacity:1}.templates__empty{flex:1 1 auto;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:16px;color:var(--color-neutral-500);font-size:13px;text-align:center}.templates__editor{display:flex;flex-direction:column;min-width:0;min-height:0;overflow:hidden}.templates__workspace{display:grid;grid-template-columns:minmax(0,1fr) minmax(340px,.82fr);gap:10px;flex:1 1 auto;min-height:0;overflow:hidden}.templates__workspace-panel{min-width:0;min-height:0;display:flex;flex-direction:column;gap:10px;overflow:hidden}.templates__workspace-panel--content .templates__card--editor{flex:1 1 0}.templates__card--settings{flex:0 0 auto;--nvb-input-height: 36px;--nvb-input-font-size: 13px}.templates__settings{display:grid;grid-template-columns:1fr 1fr;gap:10px;padding:10px 12px 12px}.templates__field{display:flex;flex-direction:column;gap:4px;min-width:0}.templates__field span{font-size:12px;color:var(--color-neutral-600)}.templates__field .nvb-control__text-input{height:36px;min-height:36px}.templates__dirty-dot{flex:0 0 auto;width:8px;height:8px;border-radius:50%;background:var(--color-caution-500)}.templates__card--preview{flex:1 1 auto}.templates__preview{flex:1 1 auto;min-height:0;padding:16px;overflow:auto;background-color:color-mix(in oklab,var(--color-neutral-050) 60%,var(--color-neutral-000));background-image:radial-gradient(var(--color-neutral-200) 1px,transparent 1px);background-size:16px 16px}.templates__preview-card{all:unset;display:block;width:100%}.templates__preview-placeholder{color:var(--color-neutral-500);font-size:13px}.templates__preview-data{flex:0 0 auto;display:flex;flex-direction:column}.templates__preview-data-editor{height:120px;padding:8px;overflow:hidden}.templates__placeholder{flex:1 1 auto;display:flex;align-items:center;justify-content:center;color:var(--color-neutral-500);font-size:13px;background:var(--nvb-card-bg);border:1px solid var(--nvb-card-border-color);border-radius:var(--nvb-card-radius);box-shadow:var(--nvb-card-shadow)}.templates__alert{flex:0 0 auto;margin:8px;padding:8px 10px;border:1px solid color-mix(in oklab,var(--color-risk-500) 35%,transparent);border-radius:var(--radius-md);background:color-mix(in oklab,var(--color-risk-050) 70%,var(--color-surface-mix-target, white));color:var(--color-risk-700);font-size:12px;line-height:1.4}@media(max-width:1000px){.templates{grid-template-columns:1fr;grid-template-rows:minmax(220px,40%) minmax(0,1fr)}.templates__sidebar{width:auto!important;max-width:none}.templates__resize-handle{display:none}.templates__workspace{grid-template-columns:1fr;overflow:auto}.templates__workspace-panel{overflow:visible}.templates__workspace-panel--content .templates__card--editor{flex:1 1 auto;min-height:220px}.templates__card--preview .templates__preview{min-height:160px}.templates__settings{grid-template-columns:1fr}}\n'],dependencies:[{kind:"ngmodule",type:k},{kind:"directive",type:g.DefaultValueAccessor,selector:"input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]"},{kind:"directive",type:g.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:g.NgModel,selector:"[ngModel]:not([formControlName]):not([formControl])",inputs:["name","disabled","ngModel","ngModelOptions"],outputs:["ngModelChange"],exportAs:["ngModel"]},{kind:"component",type:T,selector:"native-code-editor",inputs:["value","language","theme","readOnly","completions","mergeOriginal","mergeCollapseUnchanged"],outputs:["valueChange","editorBlur"]},{kind:"component",type:y,selector:"nvb-style-outlet",inputs:["cssText","renderInPlace","styleKey"]},{kind:"component",type:f,selector:"builder-action-button",inputs:["label","ariaLabel","testId","title","icon","className","tone","size","align","active","fullWidth","disabled"],outputs:["clicked"]},{kind:"component",type:x,selector:"builder-icon-button",inputs:["icon","ariaLabel","title","testId","iconSet","size","tone","ghost","dragHandle","active","disabled","className"],outputs:["clicked"]},{kind:"pipe",type:S,name:"uiT"}],changeDetection:i.ChangeDetectionStrategy.Eager})};i.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"22.2.1",ngImport:i,type:D,decorators:[{type:A,args:[{selector:"templates-editor",imports:[k,S,T,y,f,x],changeDetection:F.Eager,template:"<div class=\"templates\" data-testid=\"templates-editor-root\">\n <aside class=\"templates__sidebar\" #sidebar>\n <header class=\"templates__sidebar-header\">\n <h3 class=\"templates__sidebar-title\">\n {{ 'templates.title' | uiT: 'Templates' }}\n @if (hasTemplates()) {\n <span class=\"templates__count\">{{ templates().length }}</span>\n }\n </h3>\n <builder-icon-button\n icon=\"add\"\n size=\"sm\"\n testId=\"templates-add\"\n [ariaLabel]=\"'templates.add' | uiT: 'Add template'\"\n [title]=\"'templates.add' | uiT: 'Add template'\"\n (clicked)=\"addTemplate()\"\n />\n </header>\n\n @if (!hasTemplates()) {\n <div class=\"templates__empty\">\n <span>{{ 'templates.empty' | uiT: 'No templates yet.' }}</span>\n <builder-action-button\n tone=\"primary\"\n size=\"sm\"\n icon=\"add\"\n [label]=\"'templates.add' | uiT: 'Add template'\"\n testId=\"templates-add-empty\"\n (clicked)=\"addTemplate()\"\n />\n </div>\n } @else {\n <ul class=\"templates__list\">\n @for (template of templates(); track trackByName($index, template)) {\n <li\n class=\"templates__list-row\"\n [class.templates__list-row--active]=\"isSelected(template.name)\"\n >\n <button\n type=\"button\"\n class=\"templates__item\"\n (click)=\"selectTemplate(template.name)\"\n [attr.data-testid]=\"'templates-item-' + template.name\"\n >\n <span class=\"templates__item-title\">{{ template.title || template.name }}</span>\n <span class=\"templates__item-name\">{{ template.name }}</span>\n </button>\n <builder-icon-button\n class=\"templates__item-delete\"\n [className]=\"'templates__item-delete'\"\n icon=\"delete\"\n tone=\"danger\"\n size=\"sm\"\n [ghost]=\"true\"\n (clicked)=\"deleteTemplate(template.name)\"\n [ariaLabel]=\"'templates.delete' | uiT: 'Delete'\"\n [title]=\"'templates.delete' | uiT: 'Delete'\"\n [testId]=\"'templates-delete-' + template.name\"\n />\n </li>\n }\n </ul>\n }\n\n <div\n class=\"templates__resize-handle\"\n data-testid=\"templates-sidebar-resize\"\n (mousedown)=\"onSidebarResizeMouseDown($event)\"\n ></div>\n </aside>\n\n <section class=\"templates__editor\">\n @if (draft(); as currentDraft) {\n <div class=\"templates__workspace\">\n <div class=\"templates__workspace-panel templates__workspace-panel--content\">\n <section class=\"templates__card templates__card--editor\">\n <header class=\"templates__card-header\">\n <h3 class=\"templates__card-title\">\n {{ 'templates.content' | uiT: 'Template (Angular syntax)' }}\n </h3>\n <builder-icon-button\n icon=\"code_blocks\"\n size=\"xs\"\n [ghost]=\"true\"\n testId=\"templates-format\"\n [ariaLabel]=\"'templates.format' | uiT: 'Format template'\"\n [title]=\"'templates.format' | uiT: 'Format template'\"\n (clicked)=\"formatTemplateContent()\"\n />\n </header>\n <div class=\"templates__card-body\">\n <native-code-editor\n language=\"template\"\n [theme]=\"theme()\"\n [value]=\"currentDraft.content || ''\"\n (valueChange)=\"updateDraftField('content', $event)\"\n (editorBlur)=\"onTemplateContentBlur($event)\"\n data-testid=\"templates-content\"\n />\n </div>\n @if (formatError()) {\n <div class=\"templates__alert\" role=\"alert\">\n {{ formatError() | uiT: formatError() }}\n </div>\n }\n </section>\n\n <section class=\"templates__card templates__card--editor\">\n <header class=\"templates__card-header\">\n <h3 class=\"templates__card-title\">{{ 'templates.css' | uiT: 'CSS classes' }}</h3>\n <builder-icon-button\n icon=\"code_blocks\"\n size=\"xs\"\n [ghost]=\"true\"\n testId=\"templates-css-format\"\n [ariaLabel]=\"'templates.css.format' | uiT: 'Format CSS'\"\n [title]=\"'templates.css.format' | uiT: 'Format CSS'\"\n (clicked)=\"formatTemplateCss()\"\n />\n </header>\n <div class=\"templates__card-body\">\n <native-code-editor\n language=\"css\"\n [theme]=\"theme()\"\n [value]=\"currentDraft.css || ''\"\n (valueChange)=\"updateDraftField('css', $event)\"\n (editorBlur)=\"onTemplateCssBlur($event)\"\n data-testid=\"templates-css\"\n />\n </div>\n @if (cssFormatError()) {\n <div class=\"templates__alert\" role=\"alert\">\n {{ cssFormatError() | uiT: cssFormatError() }}\n </div>\n }\n </section>\n </div>\n\n <div class=\"templates__workspace-panel\">\n <section class=\"templates__card templates__card--settings\">\n <header class=\"templates__card-header\">\n <h3 class=\"templates__card-title\">\n {{ 'templates.settings' | uiT: 'Template settings' }}\n </h3>\n @if (isDirty()) {\n <span\n class=\"templates__dirty-dot\"\n [title]=\"'templates.unsaved' | uiT: 'Unsaved changes'\"\n ></span>\n }\n <builder-action-button\n tone=\"primary\"\n size=\"sm\"\n [label]=\"'templates.save' | uiT: 'Save'\"\n testId=\"templates-save\"\n (clicked)=\"saveDraft()\"\n />\n </header>\n <div class=\"templates__settings\">\n <label class=\"templates__field\">\n <span>{{ 'templates.name' | uiT: 'Name' }}</span>\n <input\n type=\"text\"\n class=\"nvb-control__text-input\"\n [ngModel]=\"currentDraft.name\"\n (ngModelChange)=\"updateDraftField('name', $event)\"\n data-testid=\"templates-name\"\n />\n </label>\n\n <label class=\"templates__field\">\n <span>{{ 'templates.titleField' | uiT: 'Title' }}</span>\n <input\n type=\"text\"\n class=\"nvb-control__text-input\"\n [ngModel]=\"currentDraft.title\"\n (ngModelChange)=\"updateDraftField('title', $event)\"\n data-testid=\"templates-title\"\n />\n </label>\n </div>\n @if (error()) {\n <div class=\"templates__alert\" role=\"alert\" data-testid=\"templates-error\">\n {{ error() | uiT: error() }}\n </div>\n }\n </section>\n\n <section class=\"templates__card templates__card--preview\">\n <header class=\"templates__card-header\">\n <h3 class=\"templates__card-title\">\n {{ 'templates.previewTitle' | uiT: 'Preview' }}\n </h3>\n </header>\n <div class=\"templates__preview\" data-testid=\"templates-preview\">\n @if (previewTemplateCss()) {\n <nvb-style-outlet [cssText]=\"previewTemplateCss()\"></nvb-style-outlet>\n }\n @if (!previewCard()) {\n <div class=\"templates__preview-placeholder\">\n {{ 'templates.preview.empty' | uiT: 'No preview object.' }}\n </div>\n } @else {\n <article\n class=\"templates__preview-card\"\n [attr.data-nvb-template-scope]=\"previewTemplateScopeId\"\n [innerHTML]=\"previewCard()\"\n (click)=\"onPreviewTemplateClick($event, previewItem()!, 0)\"\n ></article>\n }\n </div>\n <div class=\"templates__preview-data\">\n <header class=\"templates__card-header templates__card-header--sub\">\n <h4 class=\"templates__card-title\">\n {{ 'templates.previewData' | uiT: 'Preview data (JSON)' }}\n </h4>\n </header>\n <div class=\"templates__preview-data-editor\">\n <native-code-editor\n language=\"json\"\n [theme]=\"theme()\"\n [value]=\"previewItemsJson()\"\n (valueChange)=\"previewItemsJson.set($event)\"\n data-testid=\"templates-preview-data\"\n />\n </div>\n @if (previewJsonError()) {\n <div class=\"templates__alert\" role=\"alert\">\n {{ previewJsonError() | uiT: 'Preview data must be a valid JSON object.' }}\n </div>\n }\n </div>\n </section>\n </div>\n </div>\n } @else {\n <div class=\"templates__placeholder\">\n {{ 'templates.select' | uiT: 'Select a template to edit.' }}\n </div>\n }\n </section>\n</div>\n",styles:['@charset "UTF-8";:host{display:block;height:100%;overflow:hidden;background:color-mix(in oklab,var(--color-neutral-050) 84%,white)}.templates{height:100%;min-height:0;display:grid;grid-template-columns:auto minmax(0,1fr);gap:10px;padding:10px;overflow:hidden}.templates__card{display:flex;flex-direction:column;min-width:0;min-height:0;background:var(--nvb-card-bg);border:1px solid var(--nvb-card-border-color);border-radius:var(--nvb-card-radius);box-shadow:var(--nvb-card-shadow);overflow:hidden}.templates__card-header{flex:0 0 auto;display:flex;align-items:center;gap:8px;min-height:36px;padding:4px 8px 4px 12px;border-bottom:1px solid var(--color-neutral-200);background:var(--nvb-card-bg)}.templates__card-header--sub{border-top:1px solid var(--color-neutral-200);border-bottom:none;min-height:30px}.templates__card-title{flex:1 1 auto;margin:0;font-size:12px;font-weight:600;line-height:16px;color:var(--color-neutral-700)}.templates__card-header--sub .templates__card-title{color:var(--color-neutral-600)}.templates__card-body{flex:1 1 auto;min-height:0;padding:8px;overflow:hidden}.templates__sidebar{position:relative;display:flex;flex-direction:column;width:280px;min-width:200px;max-width:400px;min-height:0;background:var(--nvb-card-bg);border:1px solid var(--nvb-card-border-color);border-radius:var(--nvb-card-radius);box-shadow:var(--nvb-card-shadow);overflow:hidden}.templates__sidebar-header{flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;gap:8px;min-height:36px;padding:4px 8px 4px 12px;border-bottom:1px solid var(--color-neutral-200);background:var(--nvb-card-bg)}.templates__sidebar-title{display:inline-flex;align-items:center;gap:6px;margin:0;font-size:12px;font-weight:600;line-height:16px;color:var(--color-neutral-700)}.templates__count{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:16px;padding:0 5px;border-radius:999px;background:var(--color-neutral-100);color:var(--color-neutral-600);font-size:10px;font-weight:600;letter-spacing:0}.templates__resize-handle{position:absolute;top:0;right:0;width:6px;height:100%;z-index:10;cursor:ew-resize;background-color:transparent}.templates__resize-handle:after{content:"";position:absolute;top:50%;right:2px;width:2px;height:40px;transform:translateY(-50%);border-radius:999px;background-color:var(--color-neutral-300);opacity:0;transition:opacity .15s ease,background-color .15s ease}.templates__resize-handle:hover:after{opacity:1;background-color:var(--color-primary-500)}.templates__list{list-style:none;margin:0;padding:6px;display:grid;gap:2px;align-content:start;grid-auto-rows:min-content;flex:1 1 auto;min-height:0;overflow:auto}.templates__list-row{position:relative;display:flex;align-items:center;min-width:0}.templates__item{flex:1 1 auto;min-width:0;display:grid;gap:1px;text-align:left;border:none;border-left:2px solid transparent;border-radius:var(--radius-md);background:transparent;padding:6px 34px 6px 10px;cursor:pointer;font:inherit;transition:background-color .14s ease,border-color .14s ease}.templates__item-title{font-size:13px;font-weight:600;color:var(--color-neutral-700);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.templates__item-name{font-size:11px;color:var(--color-neutral-400);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.templates__item:hover{background:color-mix(in oklab,var(--color-neutral-100) 70%,var(--color-neutral-000))}.templates__list-row--active .templates__item{border-left-color:var(--color-primary-500);background:color-mix(in oklab,var(--color-primary-500) 8%,var(--color-surface-mix-target, white))}.templates__list-row--active .templates__item-title{color:var(--color-primary-700)}.templates__item-delete{position:absolute;top:50%;right:6px;transform:translateY(-50%);opacity:0;transition:opacity .14s ease}.templates__list-row:hover .templates__item-delete,.templates__list-row:focus-within .templates__item-delete,.templates__list-row--active .templates__item-delete{opacity:1}.templates__empty{flex:1 1 auto;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:16px;color:var(--color-neutral-500);font-size:13px;text-align:center}.templates__editor{display:flex;flex-direction:column;min-width:0;min-height:0;overflow:hidden}.templates__workspace{display:grid;grid-template-columns:minmax(0,1fr) minmax(340px,.82fr);gap:10px;flex:1 1 auto;min-height:0;overflow:hidden}.templates__workspace-panel{min-width:0;min-height:0;display:flex;flex-direction:column;gap:10px;overflow:hidden}.templates__workspace-panel--content .templates__card--editor{flex:1 1 0}.templates__card--settings{flex:0 0 auto;--nvb-input-height: 36px;--nvb-input-font-size: 13px}.templates__settings{display:grid;grid-template-columns:1fr 1fr;gap:10px;padding:10px 12px 12px}.templates__field{display:flex;flex-direction:column;gap:4px;min-width:0}.templates__field span{font-size:12px;color:var(--color-neutral-600)}.templates__field .nvb-control__text-input{height:36px;min-height:36px}.templates__dirty-dot{flex:0 0 auto;width:8px;height:8px;border-radius:50%;background:var(--color-caution-500)}.templates__card--preview{flex:1 1 auto}.templates__preview{flex:1 1 auto;min-height:0;padding:16px;overflow:auto;background-color:color-mix(in oklab,var(--color-neutral-050) 60%,var(--color-neutral-000));background-image:radial-gradient(var(--color-neutral-200) 1px,transparent 1px);background-size:16px 16px}.templates__preview-card{all:unset;display:block;width:100%}.templates__preview-placeholder{color:var(--color-neutral-500);font-size:13px}.templates__preview-data{flex:0 0 auto;display:flex;flex-direction:column}.templates__preview-data-editor{height:120px;padding:8px;overflow:hidden}.templates__placeholder{flex:1 1 auto;display:flex;align-items:center;justify-content:center;color:var(--color-neutral-500);font-size:13px;background:var(--nvb-card-bg);border:1px solid var(--nvb-card-border-color);border-radius:var(--nvb-card-radius);box-shadow:var(--nvb-card-shadow)}.templates__alert{flex:0 0 auto;margin:8px;padding:8px 10px;border:1px solid color-mix(in oklab,var(--color-risk-500) 35%,transparent);border-radius:var(--radius-md);background:color-mix(in oklab,var(--color-risk-050) 70%,var(--color-surface-mix-target, white));color:var(--color-risk-700);font-size:12px;line-height:1.4}@media(max-width:1000px){.templates{grid-template-columns:1fr;grid-template-rows:minmax(220px,40%) minmax(0,1fr)}.templates__sidebar{width:auto!important;max-width:none}.templates__resize-handle{display:none}.templates__workspace{grid-template-columns:1fr;overflow:auto}.templates__workspace-panel{overflow:visible}.templates__workspace-panel--content .templates__card--editor{flex:1 1 auto;min-height:220px}.templates__card--preview .templates__preview{min-height:160px}.templates__settings{grid-template-columns:1fr}}\n']}]}],propDecorators:{sidebarRef:[{type:B,args:["sidebar"]}],theme:[{type:i.Input,args:[{isSignal:true,alias:"theme",required:false}]}]}});function J(){return M({featurePacks:[{id:w,title:"Templates",capabilities:[b],builderTabs:[{id:N.TEMPLATES,label:"tab.templates",component:D,order:350,icon:"auto_awesome_mosaic",description:"tab.templates.description"}],uiDictionaries:{en:{"tab.templates.description":"Reusable card, row and option markup"}}}]})}export{b as NGX_VIEW_BUILDER_TEMPLATES_CAPABILITY,w as NGX_VIEW_BUILDER_TEMPLATES_FEATURE_PACK_ID,J as provideNgxViewBuilderTemplates};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ngxviewbuilder/plugin-templates",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.1",
|
|
4
4
|
"description": "Templates plugin for the NGX View Builder designer: save a view section as a reusable template and drop it into other views.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"homepage": "https://ngxviewbuilder.io",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"@angular/cdk": "^22.0.0",
|
|
28
28
|
"@angular/common": "^22.0.0",
|
|
29
29
|
"@angular/core": "^22.0.0",
|
|
30
|
-
"@ngxviewbuilder/designer": "^0.
|
|
30
|
+
"@ngxviewbuilder/designer": "^0.14.0"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"tslib": "^2.6.0",
|