ngx-view-builder 0.0.1 → 0.1.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.
package/LICENSE.md ADDED
@@ -0,0 +1,77 @@
1
+ # NGX View Builder Commercial 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` package and the official `ngx-view-builder-plugin-*` packages (together the **"Software"**). By installing or using the Software you agree to these terms.
6
+
7
+ **This is commercial software. It is not open source.** The Software's source form being readable in the npm distribution does not grant any open-source rights.
8
+
9
+ ## 1. Definitions
10
+
11
+ - **"License Key"** — a cryptographically signed key issued by Licensor that identifies the customer, plan, and expiry date (the **"License Term"**).
12
+ - **"Covered Version"** — any version of the Software whose release date is earlier than the expiry date of Licensee's License Key.
13
+ - **"Application"** — a software product that incorporates the Software, developed by Licensee for itself **or for a client of Licensee** (contract / agency work).
14
+
15
+ ## 2. License grant
16
+
17
+ Subject to the purchase of a valid License Key and compliance with this agreement, Licensor grants Licensee a non-exclusive, non-transferable, worldwide license to:
18
+
19
+ 1. use the Software to develop Applications, within the limits of the purchased plan;
20
+ 2. deploy Covered Versions in any number of Applications and environments, unless the purchased plan states otherwise;
21
+ 3. develop Applications **for third parties (Licensee's clients)** and deliver or transfer such Applications to them — the client may operate, host, and use the delivered Application without a separate License Key;
22
+ 4. keep using Covered Versions **perpetually** — this right survives the end of the License Term.
23
+
24
+ End users of Licensee's Applications do **not** need their own License Key; the runtime shows no license UI.
25
+
26
+ For clarity, development with the Software must be covered by a License Key held by **either side of a contract-work relationship**:
27
+
28
+ - If Licensee is a development company or agency, its License Key covers the development it performs for its clients (Section 2.3).
29
+ - If Licensee is the end customer of an Application, Licensee's License Key also covers **contractors and outsourced developers** working on that Application on Licensee's behalf. Such contractor use is limited to Licensee's Applications and does not extend to the contractor's own or other clients' projects.
30
+
31
+ Any party that develops with the Software outside these two cases needs its own License Key.
32
+
33
+ ## 3. Evaluation use
34
+
35
+ The Software may be used **without** a License Key for evaluation and development trial purposes only. In that mode the builder displays a watermark. Any production use requires a valid License Key.
36
+
37
+ ## 4. Updates
38
+
39
+ Versions of the Software released **after** the end of the License Term are not Covered Versions. Using them requires renewing the License Key; without renewal they run in degraded (watermarked) mode.
40
+
41
+ ## 5. Restrictions
42
+
43
+ Licensee may not:
44
+
45
+ 1. redistribute, resell, rent, lease, or sublicense the Software on its own (i.e. other than embedded in an Application);
46
+ 2. offer the Software, or a product derived from it, as a form-builder, view-builder, or low-code SDK/service that competes with the Software;
47
+ 3. remove, disable, alter, or circumvent the license-enforcement mechanisms (License Keys, watermark, signature or server validation), nor assist or permit anyone else to do so;
48
+ 4. exceed the seat, plan, or usage limits of the purchased plan;
49
+ 5. remove or alter copyright or license notices.
50
+
51
+ ## 6. Third-party software
52
+
53
+ The Software 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 Software.
54
+
55
+ ## 7. Ownership
56
+
57
+ The Software is licensed, not sold. Licensor retains all right, title, and interest in and to the Software.
58
+
59
+ ## 8. Warranty disclaimer
60
+
61
+ THE SOFTWARE 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.
62
+
63
+ ## 9. Limitation of liability
64
+
65
+ 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 SOFTWARE. LICENSOR'S AGGREGATE LIABILITY UNDER THIS AGREEMENT SHALL NOT EXCEED THE LICENSE FEES PAID BY LICENSEE IN THE TWELVE (12) MONTHS PRECEDING THE CLAIM.
66
+
67
+ ## 10. Termination
68
+
69
+ This agreement terminates automatically if Licensee materially breaches it. Upon termination, Licensee must stop using the Software; rights to Covered Versions granted under Section 2.3 do not survive termination for breach. Sections 6–11 survive termination.
70
+
71
+ ## 11. Governing law
72
+
73
+ 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.
74
+
75
+ ---
76
+
77
+ Questions about licensing: support@ngxviewbuilder.io · Pricing and License Keys: https://ngxviewbuilder.io/pricing
package/README.md ADDED
@@ -0,0 +1,19 @@
1
+ # NGX View Builder
2
+
3
+ Visual builder and native runtime for complete Angular views — forms, dashboards, data tables, and guided flows defined as JSON.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm i ngx-view-builder
9
+ ```
10
+
11
+ ## Documentation
12
+
13
+ Full guides, API reference, and examples: https://ngxviewbuilder.io
14
+
15
+ ## License
16
+
17
+ NGX View Builder is **commercial software** — see [LICENSE.md](./LICENSE.md). Evaluate for free (the builder shows a watermark; the production runtime never does). A paid license key covers all versions released during your license term, perpetually.
18
+
19
+ Pricing and keys: https://ngxviewbuilder.io/pricing
@@ -0,0 +1,77 @@
1
+ import { NgStyle } from '@angular/common';
2
+ import * as i0 from '@angular/core';
3
+ import { input, signal, inject, computed, ChangeDetectionStrategy, Component } from '@angular/core';
4
+ import { E as ElementActionService, a as ElementWrapper, D as DynamicTextPipe } from './ngx-view-builder-ngx-view-builder-B54ZEWUk.mjs';
5
+
6
+ class AvatarElement {
7
+ model = input.required(...(ngDevMode ? [{ debugName: "model" }] : /* istanbul ignore next */ []));
8
+ previewOpen = signal(false, ...(ngDevMode ? [{ debugName: "previewOpen" }] : /* istanbul ignore next */ []));
9
+ previewSrc = signal('', ...(ngDevMode ? [{ debugName: "previewSrc" }] : /* istanbul ignore next */ []));
10
+ elementActionService = inject(ElementActionService);
11
+ avatarStyle = computed(() => {
12
+ const sizeRaw = Number(this.model()?.size);
13
+ const size = Number.isFinite(sizeRaw) && sizeRaw > 0 ? Math.floor(sizeRaw) : 48;
14
+ const shape = String(this.model()?.shape ?? 'circle')
15
+ .trim()
16
+ .toLowerCase();
17
+ return {
18
+ width: `${size}px`,
19
+ height: `${size}px`,
20
+ 'border-radius': shape === 'square' ? '10px' : '999px',
21
+ 'background-color': String(this.model()?.backgroundColor ?? '#dfe6ff').trim() || '#dfe6ff',
22
+ color: String(this.model()?.textColor ?? '#1b2d6b').trim() || '#1b2d6b',
23
+ border: this.model().showBorder ? '1px solid var(--color-neutral-300)' : 'none',
24
+ };
25
+ }, ...(ngDevMode ? [{ debugName: "avatarStyle" }] : /* istanbul ignore next */ []));
26
+ initials = computed(() => {
27
+ const value = String(this.model()?.nameText ?? '').trim();
28
+ if (!value) {
29
+ return 'U';
30
+ }
31
+ const parts = value
32
+ .split(/\s+/)
33
+ .map((part) => part.trim())
34
+ .filter((part) => part.length > 0);
35
+ if (!parts.length) {
36
+ return 'U';
37
+ }
38
+ return parts
39
+ .slice(0, 2)
40
+ .map((part) => part[0].toUpperCase())
41
+ .join('');
42
+ }, ...(ngDevMode ? [{ debugName: "initials" }] : /* istanbul ignore next */ []));
43
+ onAvatarClick(src, event) {
44
+ event.preventDefault();
45
+ event.stopPropagation();
46
+ const runtimeContext = {
47
+ value: src || this.initials(),
48
+ item: null,
49
+ row: null,
50
+ };
51
+ const elementName = String(this.model().name ?? '').trim();
52
+ if (elementName) {
53
+ runtimeContext[elementName] = runtimeContext['value'];
54
+ }
55
+ void this.elementActionService.runActions(this.model(), this.model().events ?? [], 'click', runtimeContext);
56
+ if (!this.model().showPreview || !src) {
57
+ return;
58
+ }
59
+ this.previewSrc.set(src);
60
+ this.previewOpen.set(true);
61
+ }
62
+ closePreview(event) {
63
+ event?.preventDefault();
64
+ event?.stopPropagation();
65
+ this.previewOpen.set(false);
66
+ this.previewSrc.set('');
67
+ }
68
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: AvatarElement, deps: [], target: i0.ɵɵFactoryTarget.Component });
69
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: AvatarElement, isStandalone: true, selector: "avatar-element", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<element-wrapper [model]=\"model()\">\r\n @let avatarSrc = model().src | dynamicText: model();\r\n @let avatarName = model().nameText | dynamicText: model();\r\n\r\n <div class=\"nvb-avatar-wrap\" data-testid=\"avatar-root\">\r\n <button\r\n type=\"button\"\r\n class=\"nvb-avatar\"\r\n [ngStyle]=\"avatarStyle()\"\r\n (click)=\"onAvatarClick(avatarSrc, $event)\"\r\n >\r\n @if (avatarSrc) {\r\n <img [src]=\"avatarSrc\" [alt]=\"avatarName\" />\r\n } @else {\r\n <span>{{ initials() }}</span>\r\n }\r\n </button>\r\n </div>\r\n\r\n @if (previewOpen()) {\r\n <div class=\"nvb-avatar-preview\" (click)=\"closePreview()\">\r\n <button type=\"button\" class=\"nvb-avatar-preview__close\" (click)=\"closePreview($event)\">\r\n <span class=\"material-symbols-outlined\">close</span>\r\n </button>\r\n <img [src]=\"previewSrc()\" [alt]=\"avatarName\" />\r\n </div>\r\n }\r\n</element-wrapper>\r\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: ElementWrapper, selector: "element-wrapper", inputs: ["model", "controlIdInput", "labelForInput", "groupRole", "showTextWrapperInput"], exportAs: ["elementWrapper"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
70
+ }
71
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: AvatarElement, decorators: [{
72
+ type: Component,
73
+ args: [{ selector: 'avatar-element', changeDetection: ChangeDetectionStrategy.OnPush, imports: [ElementWrapper, NgStyle, DynamicTextPipe], template: "<element-wrapper [model]=\"model()\">\r\n @let avatarSrc = model().src | dynamicText: model();\r\n @let avatarName = model().nameText | dynamicText: model();\r\n\r\n <div class=\"nvb-avatar-wrap\" data-testid=\"avatar-root\">\r\n <button\r\n type=\"button\"\r\n class=\"nvb-avatar\"\r\n [ngStyle]=\"avatarStyle()\"\r\n (click)=\"onAvatarClick(avatarSrc, $event)\"\r\n >\r\n @if (avatarSrc) {\r\n <img [src]=\"avatarSrc\" [alt]=\"avatarName\" />\r\n } @else {\r\n <span>{{ initials() }}</span>\r\n }\r\n </button>\r\n </div>\r\n\r\n @if (previewOpen()) {\r\n <div class=\"nvb-avatar-preview\" (click)=\"closePreview()\">\r\n <button type=\"button\" class=\"nvb-avatar-preview__close\" (click)=\"closePreview($event)\">\r\n <span class=\"material-symbols-outlined\">close</span>\r\n </button>\r\n <img [src]=\"previewSrc()\" [alt]=\"avatarName\" />\r\n </div>\r\n }\r\n</element-wrapper>\r\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"] }]
74
+ }], propDecorators: { model: [{ type: i0.Input, args: [{ isSignal: true, alias: "model", required: true }] }] } });
75
+
76
+ export { AvatarElement };
77
+ //# sourceMappingURL=ngx-view-builder-avatar-element-Bwq_4ceZ.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ngx-view-builder-avatar-element-Bwq_4ceZ.mjs","sources":["../../../projects/ngx-view-builder/src/lib/core/shared/elements/avatar-element/avatar-element.ts","../../../projects/ngx-view-builder/src/lib/core/shared/elements/avatar-element/avatar-element.html"],"sourcesContent":["import { NgStyle } from '@angular/common';\r\nimport { Component, computed, inject, input, signal, ChangeDetectionStrategy } from '@angular/core';\r\n\r\nimport { ElementWrapper } from '../../components/element-wrapper/element-wrapper';\r\n\r\nimport { AvatarModel } from '../../models/elements/avatar.model';\r\n\r\nimport { DynamicTextPipe } from '../../pipes/dynamic-text.pipe';\r\n\r\nimport { ElementActionService } from '../../services/element-action.service';\r\n\r\n@Component({\r\n selector: 'avatar-element',\r\n\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n\r\n imports: [ElementWrapper, NgStyle, DynamicTextPipe],\r\n\r\n templateUrl: './avatar-element.html',\r\n\r\n styleUrl: './avatar-element.scss',\r\n})\r\nexport class AvatarElement {\r\n model = input.required<AvatarModel>();\r\n\r\n previewOpen = signal<boolean>(false);\r\n\r\n previewSrc = signal<string>('');\r\n\r\n private elementActionService = inject(ElementActionService);\r\n\r\n avatarStyle = computed<Record<string, string>>(() => {\r\n const sizeRaw = Number(this.model()?.size);\r\n\r\n const size = Number.isFinite(sizeRaw) && sizeRaw > 0 ? Math.floor(sizeRaw) : 48;\r\n\r\n const shape = String(this.model()?.shape ?? 'circle')\r\n .trim()\r\n\r\n .toLowerCase();\r\n\r\n return {\r\n width: `${size}px`,\r\n\r\n height: `${size}px`,\r\n\r\n 'border-radius': shape === 'square' ? '10px' : '999px',\r\n\r\n 'background-color': String(this.model()?.backgroundColor ?? '#dfe6ff').trim() || '#dfe6ff',\r\n\r\n color: String(this.model()?.textColor ?? '#1b2d6b').trim() || '#1b2d6b',\r\n\r\n border: this.model().showBorder ? '1px solid var(--color-neutral-300)' : 'none',\r\n };\r\n });\r\n\r\n initials = computed(() => {\r\n const value = String(this.model()?.nameText ?? '').trim();\r\n\r\n if (!value) {\r\n return 'U';\r\n }\r\n\r\n const parts = value\r\n\r\n .split(/\\s+/)\r\n\r\n .map((part) => part.trim())\r\n\r\n .filter((part) => part.length > 0);\r\n\r\n if (!parts.length) {\r\n return 'U';\r\n }\r\n\r\n return parts\r\n\r\n .slice(0, 2)\r\n\r\n .map((part) => part[0].toUpperCase())\r\n\r\n .join('');\r\n });\r\n\r\n onAvatarClick(src: string, event: MouseEvent): void {\r\n event.preventDefault();\r\n\r\n event.stopPropagation();\r\n\r\n const runtimeContext: Record<string, unknown> = {\r\n value: src || this.initials(),\r\n\r\n item: null,\r\n\r\n row: null,\r\n };\r\n\r\n const elementName = String(this.model().name ?? '').trim();\r\n\r\n if (elementName) {\r\n runtimeContext[elementName] = runtimeContext['value'];\r\n }\r\n\r\n void this.elementActionService.runActions(\r\n this.model(),\r\n\r\n this.model().events ?? [],\r\n\r\n 'click',\r\n\r\n runtimeContext,\r\n );\r\n\r\n if (!this.model().showPreview || !src) {\r\n return;\r\n }\r\n\r\n this.previewSrc.set(src);\r\n\r\n this.previewOpen.set(true);\r\n }\r\n\r\n closePreview(event?: Event): void {\r\n event?.preventDefault();\r\n\r\n event?.stopPropagation();\r\n\r\n this.previewOpen.set(false);\r\n\r\n this.previewSrc.set('');\r\n }\r\n}\r\n","<element-wrapper [model]=\"model()\">\r\n @let avatarSrc = model().src | dynamicText: model();\r\n @let avatarName = model().nameText | dynamicText: model();\r\n\r\n <div class=\"nvb-avatar-wrap\" data-testid=\"avatar-root\">\r\n <button\r\n type=\"button\"\r\n class=\"nvb-avatar\"\r\n [ngStyle]=\"avatarStyle()\"\r\n (click)=\"onAvatarClick(avatarSrc, $event)\"\r\n >\r\n @if (avatarSrc) {\r\n <img [src]=\"avatarSrc\" [alt]=\"avatarName\" />\r\n } @else {\r\n <span>{{ initials() }}</span>\r\n }\r\n </button>\r\n </div>\r\n\r\n @if (previewOpen()) {\r\n <div class=\"nvb-avatar-preview\" (click)=\"closePreview()\">\r\n <button type=\"button\" class=\"nvb-avatar-preview__close\" (click)=\"closePreview($event)\">\r\n <span class=\"material-symbols-outlined\">close</span>\r\n </button>\r\n <img [src]=\"previewSrc()\" [alt]=\"avatarName\" />\r\n </div>\r\n }\r\n</element-wrapper>\r\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,249 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, inject, signal, computed, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { Router, NavigationEnd } from '@angular/router';
4
+ import { get } from 'lodash-es';
5
+ import { filter } from 'rxjs';
6
+ import { E as ElementActionService, M as MarkupSecurityService, U as UiTranslationService, a as ElementWrapper, N as NvbIcon, D as DynamicTextPipe } from './ngx-view-builder-ngx-view-builder-B54ZEWUk.mjs';
7
+
8
+ class BreadcrumbsElement {
9
+ model = input.required(...(ngDevMode ? [{ debugName: "model" }] : /* istanbul ignore next */ []));
10
+ elementActionService = inject(ElementActionService);
11
+ markupSecurityService = inject(MarkupSecurityService);
12
+ uiTranslationService = inject(UiTranslationService);
13
+ router = inject(Router, { optional: true });
14
+ routeRefresh = signal(0, ...(ngDevMode ? [{ debugName: "routeRefresh" }] : /* istanbul ignore next */ []));
15
+ navigationSubscription = null;
16
+ ngOnInit() {
17
+ if (!this.router) {
18
+ return;
19
+ }
20
+ this.navigationSubscription = this.router.events
21
+ .pipe(filter((event) => event instanceof NavigationEnd))
22
+ .subscribe(() => {
23
+ this.routeRefresh.update((value) => value + 1);
24
+ });
25
+ }
26
+ ngOnDestroy() {
27
+ this.navigationSubscription?.unsubscribe();
28
+ this.navigationSubscription = null;
29
+ }
30
+ renderedItems = computed(() => {
31
+ this.routeRefresh();
32
+ const source = this.resolveSourceItems();
33
+ const items = [];
34
+ if (this.model().showHome) {
35
+ const configuredHomeLabel = String(this.model()?.homeLabel ?? '').trim();
36
+ items.push({
37
+ label: configuredHomeLabel || this.uiTranslationService.translate('breadcrumbs.home', 'Home'),
38
+ value: String(this.model()?.homeUrl ?? '/').trim() || '/',
39
+ });
40
+ }
41
+ items.push(...source);
42
+ const maxItemsRaw = Number(this.model()?.maxItems ?? 0);
43
+ const maxItems = Number.isFinite(maxItemsRaw) && maxItemsRaw > 0 ? Math.floor(maxItemsRaw) : 0;
44
+ if (maxItems > 0 && items.length > maxItems && maxItems >= 2) {
45
+ const first = items[0];
46
+ const lastItems = items.slice(items.length - (maxItems - 1));
47
+ return [first, { label: '...', value: '', ellipsis: true }, ...lastItems];
48
+ }
49
+ return items;
50
+ }, ...(ngDevMode ? [{ debugName: "renderedItems" }] : /* istanbul ignore next */ []));
51
+ separatorIcon = computed(() => {
52
+ const value = String(this.model()?.separator ?? '').trim();
53
+ return value || 'chevron_right';
54
+ }, ...(ngDevMode ? [{ debugName: "separatorIcon" }] : /* istanbul ignore next */ []));
55
+ resolveItemHref(value) {
56
+ return this.markupSecurityService.sanitizeNavigationUrl(String(value ?? ''));
57
+ }
58
+ onItemClick(item, index, event) {
59
+ if (item.ellipsis) {
60
+ event.preventDefault();
61
+ return;
62
+ }
63
+ const hasClickActions = Array.isArray(this.model().events) && this.model().events.length > 0;
64
+ if (hasClickActions) {
65
+ event.preventDefault();
66
+ }
67
+ else {
68
+ const anchorHref = event.currentTarget instanceof HTMLAnchorElement
69
+ ? String(event.currentTarget.getAttribute('href') ?? '').trim()
70
+ : '';
71
+ if (anchorHref.startsWith('/') && this.router) {
72
+ event.preventDefault();
73
+ this.router.navigateByUrl(anchorHref).catch(() => {
74
+ if (typeof window !== 'undefined' && typeof window.location?.assign === 'function') {
75
+ window.location.assign(anchorHref);
76
+ }
77
+ });
78
+ return;
79
+ }
80
+ }
81
+ const runtimeContext = {
82
+ item,
83
+ row: item,
84
+ index,
85
+ value: item.value,
86
+ };
87
+ const elementName = String(this.model().name ?? '').trim();
88
+ if (elementName) {
89
+ runtimeContext[elementName] = item.value;
90
+ }
91
+ void this.elementActionService.runActions(this.model(), this.model().events ?? [], 'click', runtimeContext);
92
+ }
93
+ resolveSourceItems() {
94
+ if (this.model()?.itemsSource === 'route') {
95
+ return this.buildRouteItems();
96
+ }
97
+ return Array.isArray(this.model()?.items) ? [...this.model().items] : [];
98
+ }
99
+ buildRouteItems() {
100
+ const rootSnapshot = this.router?.routerState?.snapshot?.root ?? null;
101
+ if (!rootSnapshot) {
102
+ return [];
103
+ }
104
+ const labelDataKey = String(this.model()?.routeLabelDataKey ?? 'breadcrumb').trim() || 'breadcrumb';
105
+ const usePathFallback = this.model()?.routeUsePathFallback !== false;
106
+ const includeCurrent = this.model()?.routeIncludeCurrent !== false;
107
+ const leaf = this.resolveLeafSnapshot(rootSnapshot);
108
+ const accumulatedSegments = [];
109
+ const items = [];
110
+ for (const snapshot of leaf.pathFromRoot) {
111
+ const urlSegments = snapshot.url
112
+ .map((segment) => String(segment?.path ?? '').trim())
113
+ .filter(Boolean);
114
+ if (urlSegments.length > 0) {
115
+ accumulatedSegments.push(...urlSegments);
116
+ }
117
+ const item = this.resolveRouteItem(snapshot, accumulatedSegments, labelDataKey, usePathFallback);
118
+ if (item) {
119
+ items.push(item);
120
+ }
121
+ }
122
+ if (!includeCurrent && items.length > 0) {
123
+ items.pop();
124
+ }
125
+ return items;
126
+ }
127
+ resolveLeafSnapshot(snapshot) {
128
+ let current = snapshot;
129
+ while (current.firstChild) {
130
+ current = current.firstChild;
131
+ }
132
+ return current;
133
+ }
134
+ resolveRouteItem(snapshot, accumulatedSegments, labelDataKey, usePathFallback) {
135
+ const config = this.resolveRouteBreadcrumbConfig(snapshot, labelDataKey);
136
+ if (config?.skip) {
137
+ return null;
138
+ }
139
+ const fallbackLabel = usePathFallback ? this.resolveFallbackRouteLabel(snapshot) : '';
140
+ const label = this.resolveRouteTemplate(String(config?.label ?? fallbackLabel ?? '').trim(), snapshot, accumulatedSegments);
141
+ if (!label) {
142
+ return null;
143
+ }
144
+ const explicitValue = this.resolveRouteTemplate(String(config?.value ?? '').trim(), snapshot, accumulatedSegments);
145
+ const accumulatedUrl = accumulatedSegments.length > 0 ? `/${accumulatedSegments.join('/')}` : '/';
146
+ return {
147
+ label,
148
+ value: explicitValue || accumulatedUrl,
149
+ };
150
+ }
151
+ resolveRouteBreadcrumbConfig(snapshot, labelDataKey) {
152
+ const rawConfig = snapshot.data?.[labelDataKey];
153
+ if (rawConfig === false || rawConfig === null) {
154
+ return { skip: true };
155
+ }
156
+ if (typeof rawConfig === 'string') {
157
+ const label = rawConfig.trim();
158
+ return label ? { label } : null;
159
+ }
160
+ if (!rawConfig || typeof rawConfig !== 'object' || Array.isArray(rawConfig)) {
161
+ return null;
162
+ }
163
+ const config = rawConfig;
164
+ return {
165
+ label: String(config['label'] ?? '').trim() || undefined,
166
+ value: String(config['value'] ?? '').trim() || undefined,
167
+ skip: Boolean(config['skip']),
168
+ };
169
+ }
170
+ resolveFallbackRouteLabel(snapshot) {
171
+ const dataTitle = String(snapshot.data?.['title'] ?? '').trim();
172
+ if (dataTitle) {
173
+ return dataTitle;
174
+ }
175
+ const urlLabel = snapshot.url
176
+ .map((segment) => this.humanizeSegment(String(segment?.path ?? '').trim()))
177
+ .filter(Boolean)
178
+ .join(' / ');
179
+ if (urlLabel) {
180
+ return urlLabel;
181
+ }
182
+ const routePath = String(snapshot.routeConfig?.path ?? '').trim();
183
+ if (routePath.startsWith(':')) {
184
+ const paramName = routePath.slice(1).split('/')[0];
185
+ const paramValue = String(snapshot.params?.[paramName] ?? '').trim();
186
+ if (paramValue) {
187
+ return paramValue;
188
+ }
189
+ }
190
+ return '';
191
+ }
192
+ humanizeSegment(value) {
193
+ const normalized = decodeURIComponent(String(value ?? '').trim());
194
+ if (!normalized) {
195
+ return '';
196
+ }
197
+ return normalized
198
+ .replace(/[-_]+/g, ' ')
199
+ .replace(/\s+/g, ' ')
200
+ .trim()
201
+ .replace(/\b\w/g, (letter) => letter.toUpperCase());
202
+ }
203
+ resolveRouteTemplate(template, snapshot, accumulatedSegments) {
204
+ const normalizedTemplate = String(template ?? '').trim();
205
+ if (!normalizedTemplate) {
206
+ return '';
207
+ }
208
+ const currentUrl = accumulatedSegments.length > 0 ? `/${accumulatedSegments.join('/')}` : '/';
209
+ const routeId = String(snapshot.params?.['id'] ?? snapshot.paramMap.get('id') ?? '').trim() || undefined;
210
+ const context = {
211
+ route: {
212
+ id: routeId,
213
+ url: currentUrl,
214
+ params: snapshot.params ?? {},
215
+ queryParams: snapshot.queryParams ?? {},
216
+ data: snapshot.data ?? {},
217
+ fragment: snapshot.fragment ?? '',
218
+ path: String(snapshot.routeConfig?.path ?? '').trim(),
219
+ },
220
+ id: routeId,
221
+ url: currentUrl,
222
+ params: snapshot.params ?? {},
223
+ queryParams: snapshot.queryParams ?? {},
224
+ data: snapshot.data ?? {},
225
+ };
226
+ const resolveToken = (token) => {
227
+ const path = String(token ?? '').trim();
228
+ if (!path) {
229
+ return '';
230
+ }
231
+ const resolved = get(context, path);
232
+ if (resolved === null || resolved === undefined) {
233
+ return '';
234
+ }
235
+ return String(resolved);
236
+ };
237
+ const withMustache = normalizedTemplate.replace(/\{\{([^}]+)\}\}/g, (_match, token) => resolveToken(token));
238
+ return withMustache.replace(/\{([^}]+)\}/g, (_match, token) => resolveToken(token));
239
+ }
240
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: BreadcrumbsElement, deps: [], target: i0.ɵɵFactoryTarget.Component });
241
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: BreadcrumbsElement, isStandalone: true, selector: "breadcrumbs-element", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<element-wrapper [model]=\"model()\">\r\n <nav class=\"nvb-breadcrumbs\" aria-label=\"Breadcrumbs\" data-testid=\"breadcrumbs-root\">\r\n <ol>\r\n @for (item of renderedItems(); track $index; let itemIndex = $index; let isLast = $last) {\r\n <li>\r\n @if (item.ellipsis) {\r\n <span class=\"nvb-breadcrumbs__ellipsis\">...</span>\r\n } @else if (!isLast && item.value) {\r\n <a\r\n [attr.href]=\"resolveItemHref(item.value | dynamicText: model())\"\r\n (click)=\"onItemClick(item, itemIndex, $event)\"\r\n >\r\n {{ item.label | dynamicText: model() }}\r\n </a>\r\n } @else {\r\n <span class=\"nvb-breadcrumbs__current\">{{ item.label | dynamicText: model() }}</span>\r\n }\r\n\r\n @if (!isLast) {\r\n <nvb-icon class=\"nvb-breadcrumbs__separator\" [name]=\"separatorIcon()\"></nvb-icon>\r\n }\r\n </li>\r\n }\r\n </ol>\r\n </nav>\r\n</element-wrapper>\r\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(--color-primary-700);cursor:pointer}.nvb-breadcrumbs a:hover{text-decoration:underline}.nvb-breadcrumbs__current{color:var(--color-neutral-700);font-weight:600}.nvb-breadcrumbs__ellipsis{color:var(--color-neutral-500)}.nvb-breadcrumbs__separator{font-size:14px;color:var(--color-neutral-500)}\n"], dependencies: [{ kind: "component", type: ElementWrapper, selector: "element-wrapper", inputs: ["model", "controlIdInput", "labelForInput", "groupRole", "showTextWrapperInput"], exportAs: ["elementWrapper"] }, { kind: "component", type: NvbIcon, selector: "nvb-icon", inputs: ["name", "svg", "ariaLabel"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
242
+ }
243
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: BreadcrumbsElement, decorators: [{
244
+ type: Component,
245
+ args: [{ selector: 'breadcrumbs-element', changeDetection: ChangeDetectionStrategy.OnPush, imports: [ElementWrapper, DynamicTextPipe, NvbIcon], template: "<element-wrapper [model]=\"model()\">\r\n <nav class=\"nvb-breadcrumbs\" aria-label=\"Breadcrumbs\" data-testid=\"breadcrumbs-root\">\r\n <ol>\r\n @for (item of renderedItems(); track $index; let itemIndex = $index; let isLast = $last) {\r\n <li>\r\n @if (item.ellipsis) {\r\n <span class=\"nvb-breadcrumbs__ellipsis\">...</span>\r\n } @else if (!isLast && item.value) {\r\n <a\r\n [attr.href]=\"resolveItemHref(item.value | dynamicText: model())\"\r\n (click)=\"onItemClick(item, itemIndex, $event)\"\r\n >\r\n {{ item.label | dynamicText: model() }}\r\n </a>\r\n } @else {\r\n <span class=\"nvb-breadcrumbs__current\">{{ item.label | dynamicText: model() }}</span>\r\n }\r\n\r\n @if (!isLast) {\r\n <nvb-icon class=\"nvb-breadcrumbs__separator\" [name]=\"separatorIcon()\"></nvb-icon>\r\n }\r\n </li>\r\n }\r\n </ol>\r\n </nav>\r\n</element-wrapper>\r\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(--color-primary-700);cursor:pointer}.nvb-breadcrumbs a:hover{text-decoration:underline}.nvb-breadcrumbs__current{color:var(--color-neutral-700);font-weight:600}.nvb-breadcrumbs__ellipsis{color:var(--color-neutral-500)}.nvb-breadcrumbs__separator{font-size:14px;color:var(--color-neutral-500)}\n"] }]
246
+ }], propDecorators: { model: [{ type: i0.Input, args: [{ isSignal: true, alias: "model", required: true }] }] } });
247
+
248
+ export { BreadcrumbsElement };
249
+ //# sourceMappingURL=ngx-view-builder-breadcrumbs-element-B7bwS9wN.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ngx-view-builder-breadcrumbs-element-B7bwS9wN.mjs","sources":["../../../projects/ngx-view-builder/src/lib/core/shared/elements/breadcrumbs-element/breadcrumbs-element.ts","../../../projects/ngx-view-builder/src/lib/core/shared/elements/breadcrumbs-element/breadcrumbs-element.html"],"sourcesContent":["import {\r\n Component,\r\n OnDestroy,\r\n OnInit,\r\n computed,\r\n inject,\r\n input,\r\n signal,\r\n ChangeDetectionStrategy,\r\n} from '@angular/core';\r\nimport { ActivatedRouteSnapshot, NavigationEnd, Router } from '@angular/router';\r\nimport { get } from 'lodash-es';\r\nimport { filter, Subscription } from 'rxjs';\r\nimport { ElementWrapper } from '../../components/element-wrapper/element-wrapper';\r\nimport { NvbIcon } from '../../components/nvb-icon/nvb-icon';\r\nimport {\r\n BreadcrumbsModel,\r\n IBreadcrumbItem,\r\n IRouteBreadcrumbConfig,\r\n} from '../../models/elements/breadcrumbs.model';\r\nimport { DynamicTextPipe } from '../../pipes/dynamic-text.pipe';\r\nimport { ElementActionService } from '../../services/element-action.service';\r\nimport { MarkupSecurityService } from '../../services/markup-security.service';\r\nimport { UiTranslationService } from '../../services/ui-translation.service';\r\n\r\ninterface IRenderedBreadcrumbItem extends IBreadcrumbItem {\r\n ellipsis?: boolean;\r\n}\r\n\r\n@Component({\r\n selector: 'breadcrumbs-element',\r\n\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n imports: [ElementWrapper, DynamicTextPipe, NvbIcon],\r\n templateUrl: './breadcrumbs-element.html',\r\n styleUrl: './breadcrumbs-element.scss',\r\n})\r\nexport class BreadcrumbsElement implements OnInit, OnDestroy {\r\n model = input.required<BreadcrumbsModel>();\r\n\r\n private elementActionService = inject(ElementActionService);\r\n private markupSecurityService = inject(MarkupSecurityService);\r\n private uiTranslationService = inject(UiTranslationService);\r\n private router = inject(Router, { optional: true });\r\n private routeRefresh = signal(0);\r\n private navigationSubscription: Subscription | null = null;\r\n\r\n ngOnInit(): void {\r\n if (!this.router) {\r\n return;\r\n }\r\n this.navigationSubscription = this.router.events\r\n .pipe(filter((event) => event instanceof NavigationEnd))\r\n .subscribe(() => {\r\n this.routeRefresh.update((value) => value + 1);\r\n });\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this.navigationSubscription?.unsubscribe();\r\n this.navigationSubscription = null;\r\n }\r\n\r\n renderedItems = computed<IRenderedBreadcrumbItem[]>(() => {\r\n this.routeRefresh();\r\n const source = this.resolveSourceItems();\r\n const items: IRenderedBreadcrumbItem[] = [];\r\n if (this.model().showHome) {\r\n const configuredHomeLabel = String(this.model()?.homeLabel ?? '').trim();\r\n items.push({\r\n label:\r\n configuredHomeLabel || this.uiTranslationService.translate('breadcrumbs.home', 'Home'),\r\n value: String(this.model()?.homeUrl ?? '/').trim() || '/',\r\n });\r\n }\r\n items.push(...source);\r\n const maxItemsRaw = Number(this.model()?.maxItems ?? 0);\r\n const maxItems = Number.isFinite(maxItemsRaw) && maxItemsRaw > 0 ? Math.floor(maxItemsRaw) : 0;\r\n if (maxItems > 0 && items.length > maxItems && maxItems >= 2) {\r\n const first = items[0];\r\n const lastItems = items.slice(items.length - (maxItems - 1));\r\n return [first, { label: '...', value: '', ellipsis: true }, ...lastItems];\r\n }\r\n return items;\r\n });\r\n\r\n separatorIcon = computed(() => {\r\n const value = String(this.model()?.separator ?? '').trim();\r\n return value || 'chevron_right';\r\n });\r\n\r\n resolveItemHref(value: string | null | undefined): string | null {\r\n return this.markupSecurityService.sanitizeNavigationUrl(String(value ?? ''));\r\n }\r\n\r\n onItemClick(item: IRenderedBreadcrumbItem, index: number, event: MouseEvent): void {\r\n if (item.ellipsis) {\r\n event.preventDefault();\r\n return;\r\n }\r\n const hasClickActions = Array.isArray(this.model().events) && this.model().events.length > 0;\r\n if (hasClickActions) {\r\n event.preventDefault();\r\n } else {\r\n const anchorHref =\r\n event.currentTarget instanceof HTMLAnchorElement\r\n ? String(event.currentTarget.getAttribute('href') ?? '').trim()\r\n : '';\r\n if (anchorHref.startsWith('/') && this.router) {\r\n event.preventDefault();\r\n this.router.navigateByUrl(anchorHref).catch(() => {\r\n if (typeof window !== 'undefined' && typeof window.location?.assign === 'function') {\r\n window.location.assign(anchorHref);\r\n }\r\n });\r\n return;\r\n }\r\n }\r\n const runtimeContext: Record<string, unknown> = {\r\n item,\r\n row: item,\r\n index,\r\n value: item.value,\r\n };\r\n const elementName = String(this.model().name ?? '').trim();\r\n if (elementName) {\r\n runtimeContext[elementName] = item.value;\r\n }\r\n void this.elementActionService.runActions(\r\n this.model(),\r\n this.model().events ?? [],\r\n 'click',\r\n runtimeContext,\r\n );\r\n }\r\n\r\n private resolveSourceItems(): IRenderedBreadcrumbItem[] {\r\n if (this.model()?.itemsSource === 'route') {\r\n return this.buildRouteItems();\r\n }\r\n return Array.isArray(this.model()?.items) ? [...this.model().items] : [];\r\n }\r\n\r\n private buildRouteItems(): IRenderedBreadcrumbItem[] {\r\n const rootSnapshot = this.router?.routerState?.snapshot?.root ?? null;\r\n if (!rootSnapshot) {\r\n return [];\r\n }\r\n\r\n const labelDataKey =\r\n String(this.model()?.routeLabelDataKey ?? 'breadcrumb').trim() || 'breadcrumb';\r\n const usePathFallback = this.model()?.routeUsePathFallback !== false;\r\n const includeCurrent = this.model()?.routeIncludeCurrent !== false;\r\n const leaf = this.resolveLeafSnapshot(rootSnapshot);\r\n const accumulatedSegments: string[] = [];\r\n const items: IRenderedBreadcrumbItem[] = [];\r\n\r\n for (const snapshot of leaf.pathFromRoot) {\r\n const urlSegments = snapshot.url\r\n .map((segment) => String(segment?.path ?? '').trim())\r\n .filter(Boolean);\r\n if (urlSegments.length > 0) {\r\n accumulatedSegments.push(...urlSegments);\r\n }\r\n\r\n const item = this.resolveRouteItem(\r\n snapshot,\r\n accumulatedSegments,\r\n labelDataKey,\r\n usePathFallback,\r\n );\r\n if (item) {\r\n items.push(item);\r\n }\r\n }\r\n\r\n if (!includeCurrent && items.length > 0) {\r\n items.pop();\r\n }\r\n\r\n return items;\r\n }\r\n\r\n private resolveLeafSnapshot(snapshot: ActivatedRouteSnapshot): ActivatedRouteSnapshot {\r\n let current = snapshot;\r\n while (current.firstChild) {\r\n current = current.firstChild;\r\n }\r\n return current;\r\n }\r\n\r\n private resolveRouteItem(\r\n snapshot: ActivatedRouteSnapshot,\r\n accumulatedSegments: string[],\r\n labelDataKey: string,\r\n usePathFallback: boolean,\r\n ): IRenderedBreadcrumbItem | null {\r\n const config = this.resolveRouteBreadcrumbConfig(snapshot, labelDataKey);\r\n if (config?.skip) {\r\n return null;\r\n }\r\n\r\n const fallbackLabel = usePathFallback ? this.resolveFallbackRouteLabel(snapshot) : '';\r\n const label = this.resolveRouteTemplate(\r\n String(config?.label ?? fallbackLabel ?? '').trim(),\r\n snapshot,\r\n accumulatedSegments,\r\n );\r\n if (!label) {\r\n return null;\r\n }\r\n\r\n const explicitValue = this.resolveRouteTemplate(\r\n String(config?.value ?? '').trim(),\r\n snapshot,\r\n accumulatedSegments,\r\n );\r\n const accumulatedUrl =\r\n accumulatedSegments.length > 0 ? `/${accumulatedSegments.join('/')}` : '/';\r\n\r\n return {\r\n label,\r\n value: explicitValue || accumulatedUrl,\r\n };\r\n }\r\n\r\n private resolveRouteBreadcrumbConfig(\r\n snapshot: ActivatedRouteSnapshot,\r\n labelDataKey: string,\r\n ): IRouteBreadcrumbConfig | null {\r\n const rawConfig = snapshot.data?.[labelDataKey];\r\n if (rawConfig === false || rawConfig === null) {\r\n return { skip: true };\r\n }\r\n if (typeof rawConfig === 'string') {\r\n const label = rawConfig.trim();\r\n return label ? { label } : null;\r\n }\r\n if (!rawConfig || typeof rawConfig !== 'object' || Array.isArray(rawConfig)) {\r\n return null;\r\n }\r\n\r\n const config = rawConfig as Record<string, unknown>;\r\n return {\r\n label: String(config['label'] ?? '').trim() || undefined,\r\n value: String(config['value'] ?? '').trim() || undefined,\r\n skip: Boolean(config['skip']),\r\n };\r\n }\r\n\r\n private resolveFallbackRouteLabel(snapshot: ActivatedRouteSnapshot): string {\r\n const dataTitle = String(snapshot.data?.['title'] ?? '').trim();\r\n if (dataTitle) {\r\n return dataTitle;\r\n }\r\n\r\n const urlLabel = snapshot.url\r\n .map((segment) => this.humanizeSegment(String(segment?.path ?? '').trim()))\r\n .filter(Boolean)\r\n .join(' / ');\r\n if (urlLabel) {\r\n return urlLabel;\r\n }\r\n\r\n const routePath = String(snapshot.routeConfig?.path ?? '').trim();\r\n if (routePath.startsWith(':')) {\r\n const paramName = routePath.slice(1).split('/')[0];\r\n const paramValue = String(snapshot.params?.[paramName] ?? '').trim();\r\n if (paramValue) {\r\n return paramValue;\r\n }\r\n }\r\n\r\n return '';\r\n }\r\n\r\n private humanizeSegment(value: string): string {\r\n const normalized = decodeURIComponent(String(value ?? '').trim());\r\n if (!normalized) {\r\n return '';\r\n }\r\n return normalized\r\n .replace(/[-_]+/g, ' ')\r\n .replace(/\\s+/g, ' ')\r\n .trim()\r\n .replace(/\\b\\w/g, (letter) => letter.toUpperCase());\r\n }\r\n\r\n private resolveRouteTemplate(\r\n template: string,\r\n snapshot: ActivatedRouteSnapshot,\r\n accumulatedSegments: string[],\r\n ): string {\r\n const normalizedTemplate = String(template ?? '').trim();\r\n if (!normalizedTemplate) {\r\n return '';\r\n }\r\n\r\n const currentUrl = accumulatedSegments.length > 0 ? `/${accumulatedSegments.join('/')}` : '/';\r\n const routeId =\r\n String(snapshot.params?.['id'] ?? snapshot.paramMap.get('id') ?? '').trim() || undefined;\r\n const context = {\r\n route: {\r\n id: routeId,\r\n url: currentUrl,\r\n params: snapshot.params ?? {},\r\n queryParams: snapshot.queryParams ?? {},\r\n data: snapshot.data ?? {},\r\n fragment: snapshot.fragment ?? '',\r\n path: String(snapshot.routeConfig?.path ?? '').trim(),\r\n },\r\n id: routeId,\r\n url: currentUrl,\r\n params: snapshot.params ?? {},\r\n queryParams: snapshot.queryParams ?? {},\r\n data: snapshot.data ?? {},\r\n } as Record<string, unknown>;\r\n\r\n const resolveToken = (token: string): string => {\r\n const path = String(token ?? '').trim();\r\n if (!path) {\r\n return '';\r\n }\r\n const resolved = get(context, path);\r\n if (resolved === null || resolved === undefined) {\r\n return '';\r\n }\r\n return String(resolved);\r\n };\r\n\r\n const withMustache = normalizedTemplate.replace(/\\{\\{([^}]+)\\}\\}/g, (_match, token: string) =>\r\n resolveToken(token),\r\n );\r\n return withMustache.replace(/\\{([^}]+)\\}/g, (_match, token: string) => resolveToken(token));\r\n }\r\n}\r\n","<element-wrapper [model]=\"model()\">\r\n <nav class=\"nvb-breadcrumbs\" aria-label=\"Breadcrumbs\" data-testid=\"breadcrumbs-root\">\r\n <ol>\r\n @for (item of renderedItems(); track $index; let itemIndex = $index; let isLast = $last) {\r\n <li>\r\n @if (item.ellipsis) {\r\n <span class=\"nvb-breadcrumbs__ellipsis\">...</span>\r\n } @else if (!isLast && item.value) {\r\n <a\r\n [attr.href]=\"resolveItemHref(item.value | dynamicText: model())\"\r\n (click)=\"onItemClick(item, itemIndex, $event)\"\r\n >\r\n {{ item.label | dynamicText: model() }}\r\n </a>\r\n } @else {\r\n <span class=\"nvb-breadcrumbs__current\">{{ item.label | dynamicText: model() }}</span>\r\n }\r\n\r\n @if (!isLast) {\r\n <nvb-icon class=\"nvb-breadcrumbs__separator\" [name]=\"separatorIcon()\"></nvb-icon>\r\n }\r\n </li>\r\n }\r\n </ol>\r\n </nav>\r\n</element-wrapper>\r\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ import { NgClass, NgStyle } from '@angular/common';
2
+ import * as i0 from '@angular/core';
3
+ import { input, inject, computed, ChangeDetectionStrategy, Component } from '@angular/core';
4
+ import { E as ElementActionService, a as ElementWrapper, N as NvbIcon } from './ngx-view-builder-ngx-view-builder-B54ZEWUk.mjs';
5
+
6
+ class IconElement {
7
+ model = input.required(...(ngDevMode ? [{ debugName: "model" }] : /* istanbul ignore next */ []));
8
+ elementActionService = inject(ElementActionService);
9
+ iconName = computed(() => {
10
+ const value = String(this.model()?.iconName ?? '').trim();
11
+ return value || 'star';
12
+ }, ...(ngDevMode ? [{ debugName: "iconName" }] : /* istanbul ignore next */ []));
13
+ iconStyle = computed(() => {
14
+ const size = this.resolveSize(this.model()?.iconSize, 24);
15
+ const color = String(this.model()?.iconColor ?? '').trim();
16
+ return {
17
+ width: `${size + 18}px`,
18
+ height: `${size + 18}px`,
19
+ color: color || 'var(--color-neutral-700)',
20
+ 'font-size': `${size}px`,
21
+ };
22
+ }, ...(ngDevMode ? [{ debugName: "iconStyle" }] : /* istanbul ignore next */ []));
23
+ previewStyle = computed(() => {
24
+ const size = this.resolveSize(this.model()?.previewSize, 64);
25
+ const color = String(this.model()?.iconColor ?? '').trim();
26
+ return {
27
+ width: `${size + 20}px`,
28
+ height: `${size + 20}px`,
29
+ color: color || 'var(--color-neutral-700)',
30
+ 'font-size': `${size}px`,
31
+ };
32
+ }, ...(ngDevMode ? [{ debugName: "previewStyle" }] : /* istanbul ignore next */ []));
33
+ onIconClick(event) {
34
+ event.preventDefault();
35
+ event.stopPropagation();
36
+ const runtimeContext = {
37
+ value: this.iconName(),
38
+ item: null,
39
+ row: null,
40
+ };
41
+ const elementName = String(this.model().name ?? '').trim();
42
+ if (elementName) {
43
+ runtimeContext[elementName] = this.iconName();
44
+ }
45
+ void this.elementActionService.runActions(this.model(), this.model().events ?? [], 'click', runtimeContext);
46
+ }
47
+ resolveSize(value, fallback) {
48
+ const parsed = Number(value);
49
+ if (!Number.isFinite(parsed) || parsed <= 0) {
50
+ return fallback;
51
+ }
52
+ return Math.floor(parsed);
53
+ }
54
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: IconElement, deps: [], target: i0.ɵɵFactoryTarget.Component });
55
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: IconElement, isStandalone: true, selector: "icon-element", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<element-wrapper [model]=\"model()\">\r\n <section class=\"nvb-icon-wrap\" data-testid=\"icon-root\">\r\n <button\r\n type=\"button\"\r\n class=\"nvb-icon\"\r\n [ngClass]=\"{ 'nvb-icon--filled': model().filled }\"\r\n [ngStyle]=\"iconStyle()\"\r\n (click)=\"onIconClick($event)\"\r\n >\r\n <nvb-icon [name]=\"iconName()\"></nvb-icon>\r\n </button>\r\n\r\n @if (model().showPreview) {\r\n <div class=\"nvb-icon__preview\" [ngStyle]=\"previewStyle()\">\r\n <nvb-icon [name]=\"iconName()\"></nvb-icon>\r\n </div>\r\n }\r\n </section>\r\n</element-wrapper>\r\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(--color-neutral-300);background:var(--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: ElementWrapper, selector: "element-wrapper", inputs: ["model", "controlIdInput", "labelForInput", "groupRole", "showTextWrapperInput"], exportAs: ["elementWrapper"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: NvbIcon, selector: "nvb-icon", inputs: ["name", "svg", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
56
+ }
57
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: IconElement, decorators: [{
58
+ type: Component,
59
+ args: [{ selector: 'icon-element', changeDetection: ChangeDetectionStrategy.OnPush, imports: [ElementWrapper, NgClass, NgStyle, NvbIcon], template: "<element-wrapper [model]=\"model()\">\r\n <section class=\"nvb-icon-wrap\" data-testid=\"icon-root\">\r\n <button\r\n type=\"button\"\r\n class=\"nvb-icon\"\r\n [ngClass]=\"{ 'nvb-icon--filled': model().filled }\"\r\n [ngStyle]=\"iconStyle()\"\r\n (click)=\"onIconClick($event)\"\r\n >\r\n <nvb-icon [name]=\"iconName()\"></nvb-icon>\r\n </button>\r\n\r\n @if (model().showPreview) {\r\n <div class=\"nvb-icon__preview\" [ngStyle]=\"previewStyle()\">\r\n <nvb-icon [name]=\"iconName()\"></nvb-icon>\r\n </div>\r\n }\r\n </section>\r\n</element-wrapper>\r\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(--color-neutral-300);background:var(--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"] }]
60
+ }], propDecorators: { model: [{ type: i0.Input, args: [{ isSignal: true, alias: "model", required: true }] }] } });
61
+
62
+ export { IconElement };
63
+ //# sourceMappingURL=ngx-view-builder-icon-element-DY8JkPss.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ngx-view-builder-icon-element-DY8JkPss.mjs","sources":["../../../projects/ngx-view-builder/src/lib/core/shared/elements/icon-element/icon-element.ts","../../../projects/ngx-view-builder/src/lib/core/shared/elements/icon-element/icon-element.html"],"sourcesContent":["import { NgClass, NgStyle } from '@angular/common';\r\nimport { Component, computed, inject, input, ChangeDetectionStrategy } from '@angular/core';\r\nimport { ElementWrapper } from '../../components/element-wrapper/element-wrapper';\r\nimport { NvbIcon } from '../../components/nvb-icon/nvb-icon';\r\nimport { IconModel } from '../../models/elements/icon.model';\r\nimport { ElementActionService } from '../../services/element-action.service';\r\n\r\n@Component({\r\n selector: 'icon-element',\r\n\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n imports: [ElementWrapper, NgClass, NgStyle, NvbIcon],\r\n templateUrl: './icon-element.html',\r\n\r\n styleUrl: './icon-element.scss',\r\n})\r\nexport class IconElement {\r\n model = input.required<IconModel>();\r\n\r\n private elementActionService = inject(ElementActionService);\r\n\r\n iconName = computed(() => {\r\n const value = String(this.model()?.iconName ?? '').trim();\r\n\r\n return value || 'star';\r\n });\r\n\r\n iconStyle = computed<Record<string, string>>(() => {\r\n const size = this.resolveSize(this.model()?.iconSize, 24);\r\n\r\n const color = String(this.model()?.iconColor ?? '').trim();\r\n\r\n return {\r\n width: `${size + 18}px`,\r\n\r\n height: `${size + 18}px`,\r\n\r\n color: color || 'var(--color-neutral-700)',\r\n\r\n 'font-size': `${size}px`,\r\n };\r\n });\r\n\r\n previewStyle = computed<Record<string, string>>(() => {\r\n const size = this.resolveSize(this.model()?.previewSize, 64);\r\n\r\n const color = String(this.model()?.iconColor ?? '').trim();\r\n\r\n return {\r\n width: `${size + 20}px`,\r\n\r\n height: `${size + 20}px`,\r\n\r\n color: color || 'var(--color-neutral-700)',\r\n\r\n 'font-size': `${size}px`,\r\n };\r\n });\r\n\r\n onIconClick(event: MouseEvent): void {\r\n event.preventDefault();\r\n\r\n event.stopPropagation();\r\n\r\n const runtimeContext: Record<string, unknown> = {\r\n value: this.iconName(),\r\n\r\n item: null,\r\n\r\n row: null,\r\n };\r\n\r\n const elementName = String(this.model().name ?? '').trim();\r\n\r\n if (elementName) {\r\n runtimeContext[elementName] = this.iconName();\r\n }\r\n\r\n void this.elementActionService.runActions(\r\n this.model(),\r\n\r\n this.model().events ?? [],\r\n\r\n 'click',\r\n\r\n runtimeContext,\r\n );\r\n }\r\n\r\n private resolveSize(value: unknown, fallback: number): number {\r\n const parsed = Number(value);\r\n\r\n if (!Number.isFinite(parsed) || parsed <= 0) {\r\n return fallback;\r\n }\r\n\r\n return Math.floor(parsed);\r\n }\r\n}\r\n","<element-wrapper [model]=\"model()\">\r\n <section class=\"nvb-icon-wrap\" data-testid=\"icon-root\">\r\n <button\r\n type=\"button\"\r\n class=\"nvb-icon\"\r\n [ngClass]=\"{ 'nvb-icon--filled': model().filled }\"\r\n [ngStyle]=\"iconStyle()\"\r\n (click)=\"onIconClick($event)\"\r\n >\r\n <nvb-icon [name]=\"iconName()\"></nvb-icon>\r\n </button>\r\n\r\n @if (model().showPreview) {\r\n <div class=\"nvb-icon__preview\" [ngStyle]=\"previewStyle()\">\r\n <nvb-icon [name]=\"iconName()\"></nvb-icon>\r\n </div>\r\n }\r\n </section>\r\n</element-wrapper>\r\n"],"names":[],"mappings":"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"}