ngx-view-builder-runtime 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +69 -0
- package/README.md +98 -0
- package/fesm2022/ngx-view-builder-runtime-avatar-element-D9TPAiIC.mjs +1 -0
- package/fesm2022/ngx-view-builder-runtime-breadcrumbs-element-B-IYngp0.mjs +1 -0
- package/fesm2022/ngx-view-builder-runtime-icon-element-D2Zs5vIG.mjs +1 -0
- package/fesm2022/ngx-view-builder-runtime-ngx-view-builder-runtime-q8FSSVhq.mjs +49 -0
- package/fesm2022/ngx-view-builder-runtime-toast-element-zLm-618Z.mjs +1 -0
- package/fesm2022/ngx-view-builder-runtime.mjs +1 -0
- package/package.json +61 -0
- package/styles/base.css +0 -0
- package/styles/components.css +443 -0
- package/styles/element.css +618 -0
- package/styles/fp-utilities.css +310 -0
- package/styles/index.css +7 -0
- package/styles/reset.css +54 -0
- package/styles/tokens.css +290 -0
- package/types/ngx-view-builder-runtime.d.ts +8801 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# NGX View Builder Runtime License Agreement
|
|
2
|
+
|
|
3
|
+
Copyright © 2026 NGX View Builder (https://ngxviewbuilder.io). All rights reserved.
|
|
4
|
+
|
|
5
|
+
This is a legal agreement between you (the **"Licensee"**) and NGX View Builder (the **"Licensor"**) covering the `ngx-view-builder-runtime` package (the **"Runtime"**). By installing or using the Runtime you agree to these terms.
|
|
6
|
+
|
|
7
|
+
**This is proprietary software, and it is free to use.** The Runtime is not open source: the source form being readable in the npm distribution does not grant any open-source rights. It does, however, cost nothing to use in production, requires no License Key, and never expires.
|
|
8
|
+
|
|
9
|
+
The visual editor is a separate product under separate, paid terms. See the `ngx-view-builder-designer` package and its `LICENSE.md`.
|
|
10
|
+
|
|
11
|
+
## 1. Definitions
|
|
12
|
+
|
|
13
|
+
- **"Application"** a software product that incorporates the Runtime, developed by Licensee for itself **or for a client of Licensee** (contract / agency work).
|
|
14
|
+
- **"View Definition"** a JSON document describing a view, authored by any means, that the Runtime renders.
|
|
15
|
+
|
|
16
|
+
## 2. License grant
|
|
17
|
+
|
|
18
|
+
Licensor grants Licensee a non-exclusive, non-transferable, worldwide, royalty-free, perpetual license to:
|
|
19
|
+
|
|
20
|
+
1. install and use the Runtime to develop Applications, in any number of projects and by any number of developers;
|
|
21
|
+
2. deploy and distribute the Runtime **as an integral part of an Application**, in any number of applications, environments and end users, including commercial and production use;
|
|
22
|
+
3. develop Applications **for third parties (Licensee's clients)** and deliver or transfer such Applications to them, which the client may operate, host and use without any separate agreement with Licensor;
|
|
23
|
+
4. keep using any version of the Runtime perpetually. No version of the Runtime checks a License Key, displays a watermark, or stops working.
|
|
24
|
+
|
|
25
|
+
No fee is payable for any of the above.
|
|
26
|
+
|
|
27
|
+
## 3. Restrictions
|
|
28
|
+
|
|
29
|
+
Licensee may not:
|
|
30
|
+
|
|
31
|
+
1. redistribute, resell, rent, lease, or sublicense the Runtime on its own (i.e. other than embedded in an Application);
|
|
32
|
+
2. offer the Runtime, or a product derived from it, as a form-builder, view-builder, or low-code SDK/service that competes with the Licensor's products;
|
|
33
|
+
3. build or distribute a visual editor, designer, or other authoring tool for View Definitions on top of the Runtime, whether or not it is offered commercially;
|
|
34
|
+
4. modify, reverse engineer, decompile, or create derivative works of the Runtime, except as permitted by mandatory applicable law;
|
|
35
|
+
5. remove or alter copyright or license notices.
|
|
36
|
+
|
|
37
|
+
Authoring View Definitions by hand, generating them with your own tooling, or generating them with an AI agent for use in your own Applications is expressly permitted and is not restricted by Section 3.3.
|
|
38
|
+
|
|
39
|
+
## 4. Third-party software
|
|
40
|
+
|
|
41
|
+
The Runtime depends on third-party open-source packages installed separately from npm, each under its own license (MIT: `codemirror`, `@codemirror/*`, `jexl`, `prettier`, `lodash-es`; 0BSD: `tslib`). Those licenses govern those packages only; this agreement governs the Runtime.
|
|
42
|
+
|
|
43
|
+
## 5. Ownership
|
|
44
|
+
|
|
45
|
+
The Runtime is licensed, not sold. Licensor retains all right, title, and interest in and to the Runtime.
|
|
46
|
+
|
|
47
|
+
## 6. Support
|
|
48
|
+
|
|
49
|
+
This agreement grants no right to support, updates, or new versions. Bug reports and questions are welcome at https://github.com/ngxviewbuilder/ngx-view-builder-community, with no service commitment. Paid support is available with a `ngx-view-builder-designer` license.
|
|
50
|
+
|
|
51
|
+
## 7. Warranty disclaimer
|
|
52
|
+
|
|
53
|
+
THE RUNTIME IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
|
|
54
|
+
|
|
55
|
+
## 8. Limitation of liability
|
|
56
|
+
|
|
57
|
+
TO THE MAXIMUM EXTENT PERMITTED BY LAW, LICENSOR SHALL NOT BE LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES, NOR FOR LOSS OF PROFITS, DATA, OR BUSINESS, ARISING FROM THE USE OF THE RUNTIME. BECAUSE THE RUNTIME IS PROVIDED FREE OF CHARGE, LICENSOR'S AGGREGATE LIABILITY UNDER THIS AGREEMENT SHALL NOT EXCEED EUR 100.
|
|
58
|
+
|
|
59
|
+
## 9. Termination
|
|
60
|
+
|
|
61
|
+
This agreement terminates automatically if Licensee materially breaches it. Upon termination, Licensee must stop using and distributing the Runtime. Sections 4–10 survive termination.
|
|
62
|
+
|
|
63
|
+
## 10. Governing law
|
|
64
|
+
|
|
65
|
+
This agreement is governed by the laws of the Republic of Lithuania. Any disputes shall be resolved by the competent courts of the Republic of Lithuania.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
Questions about licensing: support@ngxviewbuilder.io · Pricing: https://ngxviewbuilder.io/pricing
|
package/README.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# ngx-view-builder-runtime
|
|
2
|
+
|
|
3
|
+
Render whole Angular screens from JSON. Forms, dashboards, data tables and multi-step flows are designed once, saved as a plain JSON document, and rendered back inside your own app. Nothing is hosted on our side: views run in your app, on your router, your HTTP layer and your styles.
|
|
4
|
+
|
|
5
|
+
This package is the **runtime** half: it renders a saved view and contains no editor code. The visual editor is a separate package, [`ngx-view-builder-designer`](https://www.npmjs.com/package/ngx-view-builder-designer). An app that only shows views to end users installs this one alone, so the editor never reaches production. The runtime is free and never checks a license key.
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
|
|
9
|
+
Angular 22 or newer. `@angular/common`, `@angular/core` and `@angular/cdk` are peer dependencies.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm i ngx-view-builder-runtime
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Register the providers where you bootstrap the app:
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { bootstrapApplication } from '@angular/platform-browser';
|
|
21
|
+
import { provideNgxViewBuilderRuntime } from 'ngx-view-builder-runtime';
|
|
22
|
+
import { AppComponent } from './app/app.component';
|
|
23
|
+
|
|
24
|
+
bootstrapApplication(AppComponent, {
|
|
25
|
+
providers: [provideNgxViewBuilderRuntime()],
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Import the stylesheet once from a **global** stylesheet, not from a component:
|
|
30
|
+
|
|
31
|
+
```css
|
|
32
|
+
@import 'ngx-view-builder-runtime/styles/index.css';
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Render a view
|
|
36
|
+
|
|
37
|
+
Hand the component the JSON you saved from the designer, plus any starting data:
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { Component } from '@angular/core';
|
|
41
|
+
import { NgxViewBuilderRuntime, IStructure } from 'ngx-view-builder-runtime';
|
|
42
|
+
|
|
43
|
+
@Component({
|
|
44
|
+
selector: 'app-registration',
|
|
45
|
+
imports: [NgxViewBuilderRuntime],
|
|
46
|
+
template: `
|
|
47
|
+
<ngx-view-builder-runtime
|
|
48
|
+
[pageJson]="view"
|
|
49
|
+
[dataJson]="data"
|
|
50
|
+
(valueChanged)="onValueChanged($event)" />
|
|
51
|
+
`,
|
|
52
|
+
})
|
|
53
|
+
export class RegistrationComponent {
|
|
54
|
+
view!: IStructure;
|
|
55
|
+
data: Record<string, unknown> = { customerEmail: '' };
|
|
56
|
+
|
|
57
|
+
onValueChanged(event: unknown) {}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`pageJson` and `dataJson` take either a parsed object or a raw JSON string, so an API response can go in unparsed.
|
|
62
|
+
|
|
63
|
+
That is the whole setup. Theming, languages, data sources, custom elements, expressions and the `NgxViewBuilderApiService` are covered in the [developer guide](https://ngxviewbuilder.io/developers/).
|
|
64
|
+
|
|
65
|
+
## Upgrading from `ngx-view-builder`
|
|
66
|
+
|
|
67
|
+
That package was one library containing both halves, so every production build shipped the editor. From 0.5.0 it is two packages.
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npm rm ngx-view-builder
|
|
71
|
+
npm i ngx-view-builder-runtime
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Change the import source and the stylesheet path; selectors, inputs, outputs and saved JSON are unchanged, and older views migrate automatically on load.
|
|
75
|
+
|
|
76
|
+
```diff
|
|
77
|
+
-import { NgxViewBuilderRuntime } from 'ngx-view-builder';
|
|
78
|
+
+import { NgxViewBuilderRuntime } from 'ngx-view-builder-runtime';
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
```diff
|
|
82
|
+
-@import 'ngx-view-builder/styles/index.css';
|
|
83
|
+
+@import 'ngx-view-builder-runtime/styles/index.css';
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Documentation
|
|
87
|
+
|
|
88
|
+
https://ngxviewbuilder.io
|
|
89
|
+
|
|
90
|
+
- Developer guide: https://ngxviewbuilder.io/developers/
|
|
91
|
+
- Creator guide: https://ngxviewbuilder.io/creators/
|
|
92
|
+
- Live demo: https://ngxviewbuilder.io/demo
|
|
93
|
+
|
|
94
|
+
## License
|
|
95
|
+
|
|
96
|
+
Terms in [LICENSE.md](./LICENSE.md). The runtime is free: rendering views in production, in any number of apps, costs nothing and needs no key. A license covers the designer.
|
|
97
|
+
|
|
98
|
+
Pricing: https://ngxviewbuilder.io/pricing
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{NgStyle as o}from"@angular/common";import*as n from"@angular/core";import{input as d,signal as s,inject as v,computed as l,ChangeDetectionStrategy as m,Component as u}from"@angular/core";import{E as g,a as p,D as c}from"./ngx-view-builder-runtime-ngx-view-builder-runtime-q8FSSVhq.mjs";class i{model=d.required(...ngDevMode?[{debugName:"model"}]:[]);previewOpen=s(false,...ngDevMode?[{debugName:"previewOpen"}]:[]);previewSrc=s("",...ngDevMode?[{debugName:"previewSrc"}]:[]);elementActionService=v(g);avatarStyle=l(()=>{const e=Number(this.model()?.size);const a=Number.isFinite(e)&&e>0?Math.floor(e):48;const t=String(this.model()?.shape??"circle").trim().toLowerCase();return{width:`${a}px`,height:`${a}px`,"border-radius":t==="square"?"10px":"999px","background-color":String(this.model()?.backgroundColor??"#dfe6ff").trim()||"#dfe6ff",color:String(this.model()?.textColor??"#1b2d6b").trim()||"#1b2d6b",border:this.model().showBorder?"1px solid var(--nvb-color-neutral-300)":"none"}},...ngDevMode?[{debugName:"avatarStyle"}]:[]);initials=l(()=>{const e=String(this.model()?.nameText??"").trim();if(!e){return"U"}const a=e.split(/\s+/).map(t=>t.trim()).filter(t=>t.length>0);if(!a.length){return"U"}return a.slice(0,2).map(t=>t[0].toUpperCase()).join("")},...ngDevMode?[{debugName:"initials"}]:[]);onAvatarClick(e,a){a.preventDefault();a.stopPropagation();const t={value:e||this.initials(),item:null,row:null};const r=String(this.model().name??"").trim();if(r){t[r]=t["value"]}void this.elementActionService.runActions(this.model(),this.model().events??[],"click",t);if(!this.model().showPreview||!e){return}this.previewSrc.set(e);this.previewOpen.set(true)}closePreview(e){e?.preventDefault();e?.stopPropagation();this.previewOpen.set(false);this.previewSrc.set("")}static ɵfac=n.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"22.1.4",ngImport:n,type:i,deps:[],target:n.ɵɵFactoryTarget.Component});static ɵcmp=n.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"22.1.4",type:i,isStandalone:true,selector:"avatar-element",inputs:{model:{classPropertyName:"model",publicName:"model",isSignal:true,isRequired:true,transformFunction:null}},ngImport:n,template:'<element-wrapper [model]="model()">\n @let avatarSrc = model().src | dynamicText: model();\n @let avatarName = model().nameText | dynamicText: model();\n\n <div class="nvb-avatar-wrap" data-testid="avatar-root">\n <button\n type="button"\n class="nvb-avatar"\n [ngStyle]="avatarStyle()"\n (click)="onAvatarClick(avatarSrc, $event)"\n >\n @if (avatarSrc) {\n <img [src]="avatarSrc" [alt]="avatarName" />\n } @else {\n <span>{{ initials() }}</span>\n }\n </button>\n </div>\n\n @if (previewOpen()) {\n <div class="nvb-avatar-preview" (click)="closePreview()">\n <button type="button" class="nvb-avatar-preview__close" (click)="closePreview($event)">\n <span class="material-symbols-outlined">close</span>\n </button>\n <img [src]="previewSrc()" [alt]="avatarName" />\n </div>\n }\n</element-wrapper>\n',styles:[":host{display:block;width:100%}.nvb-avatar-wrap{width:100%;display:flex;justify-content:flex-start;align-items:center}.nvb-avatar{border:none;padding:0;overflow:hidden;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;font-weight:700;font-size:14px;line-height:1}.nvb-avatar img{width:100%;height:100%;object-fit:cover;display:block}.nvb-avatar-preview{position:fixed;inset:0;background:#000000b8;z-index:1300;display:grid;place-items:center;padding:20px}.nvb-avatar-preview img{width:min(300px,100vw - 40px);height:min(300px,100vw - 40px);object-fit:cover;border-radius:14px;box-shadow:0 16px 32px #0000004d;background:#fff}.nvb-avatar-preview__close{position:absolute;top:12px;right:12px;width:36px;height:36px;border:none;border-radius:8px;background:#ffffff2e;color:#fff;cursor:pointer;display:inline-flex;align-items:center;justify-content:center}.nvb-avatar-preview__close span{font-size:20px}\n"],dependencies:[{kind:"component",type:p,selector:"element-wrapper",inputs:["model","controlIdInput","labelForInput","groupRole","showTextWrapperInput"],exportAs:["elementWrapper"]},{kind:"directive",type:o,selector:"[ngStyle]",inputs:["ngStyle"]},{kind:"pipe",type:c,name:"dynamicText"}],changeDetection:n.ChangeDetectionStrategy.OnPush})}n.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"22.1.4",ngImport:n,type:i,decorators:[{type:u,args:[{selector:"avatar-element",changeDetection:m.OnPush,imports:[p,o,c],template:'<element-wrapper [model]="model()">\n @let avatarSrc = model().src | dynamicText: model();\n @let avatarName = model().nameText | dynamicText: model();\n\n <div class="nvb-avatar-wrap" data-testid="avatar-root">\n <button\n type="button"\n class="nvb-avatar"\n [ngStyle]="avatarStyle()"\n (click)="onAvatarClick(avatarSrc, $event)"\n >\n @if (avatarSrc) {\n <img [src]="avatarSrc" [alt]="avatarName" />\n } @else {\n <span>{{ initials() }}</span>\n }\n </button>\n </div>\n\n @if (previewOpen()) {\n <div class="nvb-avatar-preview" (click)="closePreview()">\n <button type="button" class="nvb-avatar-preview__close" (click)="closePreview($event)">\n <span class="material-symbols-outlined">close</span>\n </button>\n <img [src]="previewSrc()" [alt]="avatarName" />\n </div>\n }\n</element-wrapper>\n',styles:[":host{display:block;width:100%}.nvb-avatar-wrap{width:100%;display:flex;justify-content:flex-start;align-items:center}.nvb-avatar{border:none;padding:0;overflow:hidden;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;font-weight:700;font-size:14px;line-height:1}.nvb-avatar img{width:100%;height:100%;object-fit:cover;display:block}.nvb-avatar-preview{position:fixed;inset:0;background:#000000b8;z-index:1300;display:grid;place-items:center;padding:20px}.nvb-avatar-preview img{width:min(300px,100vw - 40px);height:min(300px,100vw - 40px);object-fit:cover;border-radius:14px;box-shadow:0 16px 32px #0000004d;background:#fff}.nvb-avatar-preview__close{position:absolute;top:12px;right:12px;width:36px;height:36px;border:none;border-radius:8px;background:#ffffff2e;color:#fff;cursor:pointer;display:inline-flex;align-items:center;justify-content:center}.nvb-avatar-preview__close span{font-size:20px}\n"]}]}],propDecorators:{model:[{type:n.Input,args:[{isSignal:true,alias:"model",required:true}]}]}});export{i as AvatarElement};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import*as s from"@angular/core";import{input as y,inject as p,signal as S,computed as v,ChangeDetectionStrategy as x,Component as w}from"@angular/core";import{Router as I,NavigationEnd as _}from"@angular/router";import{get as k}from"lodash-es";import{filter as C}from"rxjs";import{E as T,M as R,U as D,a as f,N as h,D as g}from"./ngx-view-builder-runtime-ngx-view-builder-runtime-q8FSSVhq.mjs";class d{model=y.required(...ngDevMode?[{debugName:"model"}]:[]);elementActionService=p(T);markupSecurityService=p(R);uiTranslationService=p(D);router=p(I,{optional:true});routeRefresh=S(0,...ngDevMode?[{debugName:"routeRefresh"}]:[]);navigationSubscription=null;ngOnInit(){if(!this.router){return}this.navigationSubscription=this.router.events.pipe(C(r=>r instanceof _)).subscribe(()=>{this.routeRefresh.update(r=>r+1)})}ngOnDestroy(){this.navigationSubscription?.unsubscribe();this.navigationSubscription=null}renderedItems=v(()=>{this.routeRefresh();const r=this.resolveSourceItems();const e=[];if(this.model().showHome){const n=String(this.model()?.homeLabel??"").trim();e.push({label:n||this.uiTranslationService.translate("breadcrumbs.home","Home"),value:String(this.model()?.homeUrl??"/").trim()||"/"})}e.push(...r);const t=Number(this.model()?.maxItems??0);const i=Number.isFinite(t)&&t>0?Math.floor(t):0;if(i>0&&e.length>i&&i>=2){const n=e[0];const a=e.slice(e.length-(i-1));return[n,{label:"...",value:"",ellipsis:true},...a]}return e},...ngDevMode?[{debugName:"renderedItems"}]:[]);separatorIcon=v(()=>{const r=String(this.model()?.separator??"").trim();return r||"chevron_right"},...ngDevMode?[{debugName:"separatorIcon"}]:[]);resolveItemHref(r){return this.markupSecurityService.sanitizeNavigationUrl(String(r??""))}onItemClick(r,e,t){if(r.ellipsis){t.preventDefault();return}const i=Array.isArray(this.model().events)&&this.model().events.length>0;if(i){t.preventDefault()}else{const o=t.currentTarget instanceof HTMLAnchorElement?String(t.currentTarget.getAttribute("href")??"").trim():"";if(o.startsWith("/")&&this.router){t.preventDefault();this.router.navigateByUrl(o).catch(()=>{if(typeof window!=="undefined"&&typeof window.location?.assign==="function"){window.location.assign(o)}});return}}const n={item:r,row:r,index:e,value:r.value};const a=String(this.model().name??"").trim();if(a){n[a]=r.value}void this.elementActionService.runActions(this.model(),this.model().events??[],"click",n)}resolveSourceItems(){if(this.model()?.itemsSource==="route"){return this.buildRouteItems()}return Array.isArray(this.model()?.items)?[...this.model().items]:[]}buildRouteItems(){const r=this.router?.routerState?.snapshot?.root??null;if(!r){return[]}const e=String(this.model()?.routeLabelDataKey??"breadcrumb").trim()||"breadcrumb";const t=this.model()?.routeUsePathFallback!==false;const i=this.model()?.routeIncludeCurrent!==false;const n=this.resolveLeafSnapshot(r);const a=[];const o=[];for(const m of n.pathFromRoot){const c=m.url.map(l=>String(l?.path??"").trim()).filter(Boolean);if(c.length>0){a.push(...c)}const u=this.resolveRouteItem(m,a,e,t);if(u){o.push(u)}}if(!i&&o.length>0){o.pop()}return o}resolveLeafSnapshot(r){let e=r;while(e.firstChild){e=e.firstChild}return e}resolveRouteItem(r,e,t,i){const n=this.resolveRouteBreadcrumbConfig(r,t);if(n?.skip){return null}const a=i?this.resolveFallbackRouteLabel(r):"";const o=this.resolveRouteTemplate(String(n?.label??a??"").trim(),r,e);if(!o){return null}const m=this.resolveRouteTemplate(String(n?.value??"").trim(),r,e);const c=e.length>0?`/${e.join("/")}`:"/";return{label:o,value:m||c}}resolveRouteBreadcrumbConfig(r,e){const t=r.data?.[e];if(t===false||t===null){return{skip:true}}if(typeof t==="string"){const n=t.trim();return n?{label:n}:null}if(!t||typeof t!=="object"||Array.isArray(t)){return null}const i=t;return{label:String(i["label"]??"").trim()||void 0,value:String(i["value"]??"").trim()||void 0,skip:Boolean(i["skip"])}}resolveFallbackRouteLabel(r){const e=String(r.data?.["title"]??"").trim();if(e){return e}const t=r.url.map(n=>this.humanizeSegment(String(n?.path??"").trim())).filter(Boolean).join(" / ");if(t){return t}const i=String(r.routeConfig?.path??"").trim();if(i.startsWith(":")){const n=i.slice(1).split("/")[0];const a=String(r.params?.[n]??"").trim();if(a){return a}}return""}humanizeSegment(r){const e=decodeURIComponent(String(r??"").trim());if(!e){return""}return e.replace(/[-_]+/g," ").replace(/\s+/g," ").trim().replace(/\b\w/g,t=>t.toUpperCase())}resolveRouteTemplate(r,e,t){const i=String(r??"").trim();if(!i){return""}const n=t.length>0?`/${t.join("/")}`:"/";const a=String(e.params?.["id"]??e.paramMap.get("id")??"").trim()||void 0;const o={route:{id:a,url:n,params:e.params??{},queryParams:e.queryParams??{},data:e.data??{},fragment:e.fragment??"",path:String(e.routeConfig?.path??"").trim()},id:a,url:n,params:e.params??{},queryParams:e.queryParams??{},data:e.data??{}};const m=u=>{const l=String(u??"").trim();if(!l){return""}const b=k(o,l);if(b===null||b===void 0){return""}return String(b)};const c=i.replace(/\{\{([^}]+)\}\}/g,(u,l)=>m(l));return c.replace(/\{([^}]+)\}/g,(u,l)=>m(l))}static ɵfac=s.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"22.1.4",ngImport:s,type:d,deps:[],target:s.ɵɵFactoryTarget.Component});static ɵcmp=s.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"22.1.4",type:d,isStandalone:true,selector:"breadcrumbs-element",inputs:{model:{classPropertyName:"model",publicName:"model",isSignal:true,isRequired:true,transformFunction:null}},ngImport:s,template:'<element-wrapper [model]="model()">\n <nav class="nvb-breadcrumbs" aria-label="Breadcrumbs" data-testid="breadcrumbs-root">\n <ol>\n @for (item of renderedItems(); track $index; let itemIndex = $index; let isLast = $last) {\n <li>\n @if (item.ellipsis) {\n <span class="nvb-breadcrumbs__ellipsis">...</span>\n } @else if (!isLast && item.value) {\n <a\n [attr.href]="resolveItemHref(item.value | dynamicText: model())"\n (click)="onItemClick(item, itemIndex, $event)"\n >\n {{ item.label | dynamicText: model() }}\n </a>\n } @else {\n <span class="nvb-breadcrumbs__current">{{ item.label | dynamicText: model() }}</span>\n }\n\n @if (!isLast) {\n <nvb-icon class="nvb-breadcrumbs__separator" [name]="separatorIcon()"></nvb-icon>\n }\n </li>\n }\n </ol>\n </nav>\n</element-wrapper>\n',styles:[":host{display:block;width:100%}.nvb-breadcrumbs{width:100%}.nvb-breadcrumbs ol{list-style:none;margin:0;padding:0;display:flex;align-items:center;flex-wrap:wrap;gap:6px;min-width:0}.nvb-breadcrumbs li{display:inline-flex;align-items:center;gap:6px;min-width:0}.nvb-breadcrumbs a,.nvb-breadcrumbs__current,.nvb-breadcrumbs__ellipsis{font-size:12px;line-height:1.3;text-decoration:none;max-width:220px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.nvb-breadcrumbs a{color:var(--nvb-color-primary-700);cursor:pointer}.nvb-breadcrumbs a:hover{text-decoration:underline}.nvb-breadcrumbs__current{color:var(--nvb-color-neutral-700);font-weight:600}.nvb-breadcrumbs__ellipsis{color:var(--nvb-color-neutral-500)}.nvb-breadcrumbs__separator{font-size:14px;color:var(--nvb-color-neutral-500)}\n"],dependencies:[{kind:"component",type:f,selector:"element-wrapper",inputs:["model","controlIdInput","labelForInput","groupRole","showTextWrapperInput"],exportAs:["elementWrapper"]},{kind:"component",type:h,selector:"nvb-icon",inputs:["name","svg","ariaLabel"]},{kind:"pipe",type:g,name:"dynamicText"}],changeDetection:s.ChangeDetectionStrategy.OnPush})}s.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"22.1.4",ngImport:s,type:d,decorators:[{type:w,args:[{selector:"breadcrumbs-element",changeDetection:x.OnPush,imports:[f,g,h],template:'<element-wrapper [model]="model()">\n <nav class="nvb-breadcrumbs" aria-label="Breadcrumbs" data-testid="breadcrumbs-root">\n <ol>\n @for (item of renderedItems(); track $index; let itemIndex = $index; let isLast = $last) {\n <li>\n @if (item.ellipsis) {\n <span class="nvb-breadcrumbs__ellipsis">...</span>\n } @else if (!isLast && item.value) {\n <a\n [attr.href]="resolveItemHref(item.value | dynamicText: model())"\n (click)="onItemClick(item, itemIndex, $event)"\n >\n {{ item.label | dynamicText: model() }}\n </a>\n } @else {\n <span class="nvb-breadcrumbs__current">{{ item.label | dynamicText: model() }}</span>\n }\n\n @if (!isLast) {\n <nvb-icon class="nvb-breadcrumbs__separator" [name]="separatorIcon()"></nvb-icon>\n }\n </li>\n }\n </ol>\n </nav>\n</element-wrapper>\n',styles:[":host{display:block;width:100%}.nvb-breadcrumbs{width:100%}.nvb-breadcrumbs ol{list-style:none;margin:0;padding:0;display:flex;align-items:center;flex-wrap:wrap;gap:6px;min-width:0}.nvb-breadcrumbs li{display:inline-flex;align-items:center;gap:6px;min-width:0}.nvb-breadcrumbs a,.nvb-breadcrumbs__current,.nvb-breadcrumbs__ellipsis{font-size:12px;line-height:1.3;text-decoration:none;max-width:220px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.nvb-breadcrumbs a{color:var(--nvb-color-primary-700);cursor:pointer}.nvb-breadcrumbs a:hover{text-decoration:underline}.nvb-breadcrumbs__current{color:var(--nvb-color-neutral-700);font-weight:600}.nvb-breadcrumbs__ellipsis{color:var(--nvb-color-neutral-500)}.nvb-breadcrumbs__separator{font-size:14px;color:var(--nvb-color-neutral-500)}\n"]}]}],propDecorators:{model:[{type:s.Input,args:[{isSignal:true,alias:"model",required:true}]}]}});export{d as BreadcrumbsElement};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{NgClass as l,NgStyle as s}from"@angular/common";import*as n from"@angular/core";import{input as p,inject as m,computed as r,ChangeDetectionStrategy as d,Component as v}from"@angular/core";import{E as g,a as c,N as a}from"./ngx-view-builder-runtime-ngx-view-builder-runtime-q8FSSVhq.mjs";class o{model=p.required(...ngDevMode?[{debugName:"model"}]:[]);elementActionService=m(g);iconName=r(()=>{const e=String(this.model()?.iconName??"").trim();return e||"star"},...ngDevMode?[{debugName:"iconName"}]:[]);iconStyle=r(()=>{const e=this.resolveSize(this.model()?.iconSize,24);const i=String(this.model()?.iconColor??"").trim();return{width:`${e+18}px`,height:`${e+18}px`,color:i||"var(--nvb-color-neutral-700)","font-size":`${e}px`}},...ngDevMode?[{debugName:"iconStyle"}]:[]);previewStyle=r(()=>{const e=this.resolveSize(this.model()?.previewSize,64);const i=String(this.model()?.iconColor??"").trim();return{width:`${e+20}px`,height:`${e+20}px`,color:i||"var(--nvb-color-neutral-700)","font-size":`${e}px`}},...ngDevMode?[{debugName:"previewStyle"}]:[]);onIconClick(e){e.preventDefault();e.stopPropagation();const i={value:this.iconName(),item:null,row:null};const t=String(this.model().name??"").trim();if(t){i[t]=this.iconName()}void this.elementActionService.runActions(this.model(),this.model().events??[],"click",i)}resolveSize(e,i){const t=Number(e);if(!Number.isFinite(t)||t<=0){return i}return Math.floor(t)}static ɵfac=n.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"22.1.4",ngImport:n,type:o,deps:[],target:n.ɵɵFactoryTarget.Component});static ɵcmp=n.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"22.1.4",type:o,isStandalone:true,selector:"icon-element",inputs:{model:{classPropertyName:"model",publicName:"model",isSignal:true,isRequired:true,transformFunction:null}},ngImport:n,template:"<element-wrapper [model]=\"model()\">\n <section class=\"nvb-icon-wrap\" data-testid=\"icon-root\">\n <button\n type=\"button\"\n class=\"nvb-icon\"\n [ngClass]=\"{ 'nvb-icon--filled': model().filled }\"\n [ngStyle]=\"iconStyle()\"\n (click)=\"onIconClick($event)\"\n >\n <nvb-icon [name]=\"iconName()\"></nvb-icon>\n </button>\n\n @if (model().showPreview) {\n <div class=\"nvb-icon__preview\" [ngStyle]=\"previewStyle()\">\n <nvb-icon [name]=\"iconName()\"></nvb-icon>\n </div>\n }\n </section>\n</element-wrapper>\n",styles:[':host{display:block;width:100%}.nvb-icon-wrap{width:100%;display:inline-flex;align-items:center;gap:10px;flex-wrap:wrap}.nvb-icon,.nvb-icon__preview{border:1px solid var(--nvb-color-neutral-300);background:var(--nvb-color-neutral-000);border-radius:10px;display:inline-flex;align-items:center;justify-content:center}.nvb-icon{cursor:pointer;min-width:42px;min-height:42px;padding:0}.nvb-icon span,.nvb-icon__preview span{line-height:1}.nvb-icon--filled span{font-variation-settings:"FILL" 1,"wght" 400,"GRAD" 0,"opsz" 24}\n'],dependencies:[{kind:"component",type:c,selector:"element-wrapper",inputs:["model","controlIdInput","labelForInput","groupRole","showTextWrapperInput"],exportAs:["elementWrapper"]},{kind:"directive",type:l,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:s,selector:"[ngStyle]",inputs:["ngStyle"]},{kind:"component",type:a,selector:"nvb-icon",inputs:["name","svg","ariaLabel"]}],changeDetection:n.ChangeDetectionStrategy.OnPush})}n.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"22.1.4",ngImport:n,type:o,decorators:[{type:v,args:[{selector:"icon-element",changeDetection:d.OnPush,imports:[c,l,s,a],template:"<element-wrapper [model]=\"model()\">\n <section class=\"nvb-icon-wrap\" data-testid=\"icon-root\">\n <button\n type=\"button\"\n class=\"nvb-icon\"\n [ngClass]=\"{ 'nvb-icon--filled': model().filled }\"\n [ngStyle]=\"iconStyle()\"\n (click)=\"onIconClick($event)\"\n >\n <nvb-icon [name]=\"iconName()\"></nvb-icon>\n </button>\n\n @if (model().showPreview) {\n <div class=\"nvb-icon__preview\" [ngStyle]=\"previewStyle()\">\n <nvb-icon [name]=\"iconName()\"></nvb-icon>\n </div>\n }\n </section>\n</element-wrapper>\n",styles:[':host{display:block;width:100%}.nvb-icon-wrap{width:100%;display:inline-flex;align-items:center;gap:10px;flex-wrap:wrap}.nvb-icon,.nvb-icon__preview{border:1px solid var(--nvb-color-neutral-300);background:var(--nvb-color-neutral-000);border-radius:10px;display:inline-flex;align-items:center;justify-content:center}.nvb-icon{cursor:pointer;min-width:42px;min-height:42px;padding:0}.nvb-icon span,.nvb-icon__preview span{line-height:1}.nvb-icon--filled span{font-variation-settings:"FILL" 1,"wght" 400,"GRAD" 0,"opsz" 24}\n']}]}],propDecorators:{model:[{type:n.Input,args:[{isSignal:true,alias:"model",required:true}]}]}});export{o as IconElement};
|