ngx-json-ui
Version:
This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 19.2.0.
364 lines (351 loc) • 19.8 kB
JavaScript
import * as i0 from '@angular/core';
import { EventEmitter, Output, Input, Component, HostBinding, Injectable, NgModule, InjectionToken, Optional, Inject } from '@angular/core';
import { CommonModule } from '@angular/common';
import * as i1 from '@angular/cdk/overlay';
import { OverlayConfig, OverlayModule } from '@angular/cdk/overlay';
import { ComponentPortal } from '@angular/cdk/portal';
import { FormGroup } from '@angular/forms';
class ModalComponent {
constructor() {
/**
* Event emitted when the modal should be closed.
*/
this.closeOverlay = new EventEmitter();
}
ngOnInit() { }
/**
* Called when the close button is clicked.
*/
onClose() {
this.closeOverlay.emit();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.6", type: ModalComponent, isStandalone: true, selector: "nju-modal", inputs: { title: "title", content: "content" }, outputs: { closeOverlay: "closeOverlay" }, ngImport: i0, template: "<!-- modal.component.html -->\r\n<div role=\"dialog\" class=\"modal fade show\" tabindex=\"-1\" aria-hidden=\"true\" style=\"display: block;\">\r\n <div class=\"modal-dialog modal-lg modal-dialog-centered modal-dialog-scrollable\">\r\n <div class=\"modal-content\">\r\n <div class=\"modal-header\">\r\n <h5 class=\"modal-title\">Modal title</h5>\r\n <a type=\"button\" href=\"\" data-bs-dismiss=\"modal\" aria-label=\"Close\" (click)=\"onClose()\">\r\n <i class=\"ph ph-x color-subdued icon icon-sm icon-interactive\"></i>\r\n </a>\r\n </div>\r\n <div class=\"modal-body\">\r\n <h6>Default Modal: It closes automatically when clicked anywhere outside it or pressed escape key</h6>\r\n </div>\r\n <div class=\"modal-footer\">\r\n <button type=\"button\" class=\"btn btn-plain\" data-bs-dismiss=\"modal\">Cancel</button>\r\n <button type=\"button\" class=\"btn btn-primary\">Save changes</button>\r\n </div>\r\n </div>\r\n </div>\r\n</div>" }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ModalComponent, decorators: [{
type: Component,
args: [{ selector: 'nju-modal', template: "<!-- modal.component.html -->\r\n<div role=\"dialog\" class=\"modal fade show\" tabindex=\"-1\" aria-hidden=\"true\" style=\"display: block;\">\r\n <div class=\"modal-dialog modal-lg modal-dialog-centered modal-dialog-scrollable\">\r\n <div class=\"modal-content\">\r\n <div class=\"modal-header\">\r\n <h5 class=\"modal-title\">Modal title</h5>\r\n <a type=\"button\" href=\"\" data-bs-dismiss=\"modal\" aria-label=\"Close\" (click)=\"onClose()\">\r\n <i class=\"ph ph-x color-subdued icon icon-sm icon-interactive\"></i>\r\n </a>\r\n </div>\r\n <div class=\"modal-body\">\r\n <h6>Default Modal: It closes automatically when clicked anywhere outside it or pressed escape key</h6>\r\n </div>\r\n <div class=\"modal-footer\">\r\n <button type=\"button\" class=\"btn btn-plain\" data-bs-dismiss=\"modal\">Cancel</button>\r\n <button type=\"button\" class=\"btn btn-primary\">Save changes</button>\r\n </div>\r\n </div>\r\n </div>\r\n</div>" }]
}], ctorParameters: () => [], propDecorators: { title: [{
type: Input
}], content: [{
type: Input
}], closeOverlay: [{
type: Output
}] } });
class ToastComponent {
constructor() {
// Dynamic css styling control variabled
this.hostClasses = ''; // Binding class to overall component
this.labelCssClassName = 'toast-container';
this.cssClassName = 'toast toast-custom';
}
// Lifecycle method in angular called when the component is initialized
ngOnInit() {
// Set css styling variable from json schema
this.hostClasses = 'd-flex justify-content-center';
this.labelCssClassName = 'toast-container';
this.cssClassName = 'toast toast-custom fade show';
this.cssStyle = '';
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ToastComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.6", type: ToastComponent, isStandalone: true, selector: "nju-toast", inputs: { config: "config" }, host: { properties: { "class": "this.hostClasses" } }, ngImport: i0, template: "<div [class]=\"labelCssClassName\">\r\n <div class=\"{{cssClassName}}\" role=\"alert\" aria-live=\"assertive\" aria-atomic=\"true\">\r\n Hello\r\n </div>\r\n</div>\r\n" }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ToastComponent, decorators: [{
type: Component,
args: [{ selector: 'nju-toast', template: "<div [class]=\"labelCssClassName\">\r\n <div class=\"{{cssClassName}}\" role=\"alert\" aria-live=\"assertive\" aria-atomic=\"true\">\r\n Hello\r\n </div>\r\n</div>\r\n" }]
}], propDecorators: { config: [{
type: Input
}], hostClasses: [{
type: HostBinding,
args: ['class']
}] } });
class NgxOverlayService {
constructor(overlay, injector) {
this.overlay = overlay;
this.injector = injector;
}
/**
* Opens a modal overlay.
* @param data Data to pass to the ModalComponent.
*/
openModal(data) {
const config = this.getDefaultConfig();
const overlayRef = this.overlay.create(config);
// Automatically close the modal when the backdrop is clicked.
overlayRef.backdropClick().subscribe(() => overlayRef.dispose());
const portal = new ComponentPortal(ModalComponent, null, this.createInjector(data));
overlayRef.attach(portal);
return overlayRef;
}
/**
* Opens a toast overlay.
* @param data Data to pass to the ToastComponent.
*/
openToast(data) {
const config = this.getDefaultConfig({
hasBackdrop: false,
panelClass: 'nju-toast-overlay',
positionStrategy: this.overlay
.position()
.global()
.bottom('20px')
.right('20px')
});
const overlayRef = this.overlay.create(config);
const portal = new ComponentPortal(ToastComponent, null, this.createInjector(data));
overlayRef.attach(portal);
return overlayRef;
}
/**
* Returns a default OverlayConfig object merged with any additional options.
*/
getDefaultConfig(options) {
const defaultConfig = new OverlayConfig({
hasBackdrop: true,
backdropClass: 'cdk-overlay-dark-backdrop',
panelClass: 'nju-overlay-panel',
scrollStrategy: this.overlay.scrollStrategies.block(),
positionStrategy: this.overlay
.position()
.global()
.centerHorizontally()
.centerVertically()
});
return { ...defaultConfig, ...options };
}
/**
* Creates a simple injector to pass data into the overlay component.
* For more advanced data passing, you might create a custom InjectionToken and PortalInjector.
*/
createInjector(data) {
// In this minimal implementation we simply return the root injector.
// Extend this function if you need to pass custom tokens/data.
return this.injector;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: NgxOverlayService, deps: [{ token: i1.Overlay }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: NgxOverlayService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: NgxOverlayService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}], ctorParameters: () => [{ type: i1.Overlay }, { type: i0.Injector }] });
// File: src/lib/form-builder.module.ts
class FormBuilderModule {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: FormBuilderModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.6", ngImport: i0, type: FormBuilderModule, imports: [CommonModule,
OverlayModule,
ModalComponent], exports: [ModalComponent] }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: FormBuilderModule, providers: [
NgxOverlayService
], imports: [CommonModule,
OverlayModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: FormBuilderModule, decorators: [{
type: NgModule,
args: [{
imports: [
CommonModule,
OverlayModule,
ModalComponent
],
exports: [
ModalComponent
],
providers: [
NgxOverlayService
]
}]
}] });
class TypeNotFoundComponent {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TypeNotFoundComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.6", type: TypeNotFoundComponent, isStandalone: true, selector: "nju-type-not-found", ngImport: i0, template: `<div class="nju-error">Component type not found.</div>`, isInline: true }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TypeNotFoundComponent, decorators: [{
type: Component,
args: [{
selector: 'nju-type-not-found',
template: `<div class="nju-error">Component type not found.</div>`
}]
}] });
const COMPONENT_MAPPING_CONFIG = new InjectionToken('COMPONENT_MAPPING_CONFIG', {
providedIn: 'root',
factory: () => ({ useDefaultMappings: true }) // Defaults to using the built-in mappings.
});
const COMPONENT_MAPPINGS = new InjectionToken('COMPONENT_MAPPINGS');
class ComponentMappingService {
constructor(config, customMappings) {
this.mappings = {};
// Check configuration flag to decide whether to load default mappings.
if (config?.useDefaultMappings ?? true) {
this.mappings = {
'modal': { schema: 'overlay', alias: 'modal', component: ModalComponent }
};
}
// Merge custom mappings (if any) into the mappings object.
if (customMappings) {
customMappings.forEach(mapping => {
this.mappings[mapping.alias] = mapping;
});
}
}
getMapping(type) {
return this.mappings[type] || {
schema: 'atom',
alias: 'unknown',
component: TypeNotFoundComponent
};
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ComponentMappingService, deps: [{ token: COMPONENT_MAPPING_CONFIG, optional: true }, { token: COMPONENT_MAPPINGS, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ComponentMappingService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ComponentMappingService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}], ctorParameters: () => [{ type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: [COMPONENT_MAPPING_CONFIG]
}] }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: [COMPONENT_MAPPINGS]
}] }] });
class ComponentFactoryService {
constructor(mappingService, overlayService) {
this.mappingService = mappingService;
this.overlayService = overlayService;
}
/**
* Loads one or more components based on the provided configuration.
* @param config A single ComponentModel or an array of ComponentModel objects.
* @param container The container (ViewContainerRef) where components should be added.
* @param form (Optional) The parent FormGroup/FormArray for form components.
* @param validationSchema (Optional) Validation configuration used for form controls.
*/
loadComponents(config, container, form, validationSchema) {
if (Array.isArray(config)) {
config.forEach(c => this.loadSingleComponent(c, container, form, validationSchema));
}
else {
this.loadSingleComponent(config, container, form, validationSchema);
}
}
/**
* Loads a single component based on its configuration.
* For 'formGroup' types, it recursively loads child components into the corresponding sub-form.
* @param componentConfig The configuration for the component.
* @param container The ViewContainerRef to create the component in.
* @param form (Optional) The parent FormGroup/FormArray.
* @param validationSchema (Optional) Validation configuration for form controls.
*/
loadSingleComponent(componentConfig, container, form, validationSchema) {
// Handle overlay types separately.
// If the component type is 'modal', 'toast', 'alert', or 'offcanvas', use the overlay service.
if (['modal', 'toast', 'alert', 'offcanvas'].includes(componentConfig.type)) {
const overlayData = {
config: componentConfig,
form: form,
validationSchema: validationSchema
};
switch (componentConfig.type) {
case 'modal':
this.overlayService.openModal(overlayData);
break;
case 'toast':
this.overlayService.openToast(overlayData);
break;
default:
console.error(`Unsupported overlay type: ${componentConfig.type}`);
break;
}
return;
}
// If the component type is 'formGroup' and a form is provided, ensure a valid name exists.
if (componentConfig.type === 'formGroup' && form) {
if (!componentConfig?.name) {
console.error(`FormGroup configuration error: 'name' property is missing. Received config: ${JSON.stringify(componentConfig)}`);
return;
}
const childForm = form.get(componentConfig.name);
if (!childForm) {
console.error(`FormGroup not found for component name: ${componentConfig.name}`);
return;
}
if (!(childForm instanceof FormGroup)) {
console.error(`Expected a FormGroup for '${componentConfig.name}', but received a different control type.`);
return;
}
// If there are child components, load them into the retrieved form group.
if (Array.isArray(componentConfig?.components) && componentConfig.components.length > 0) {
this.loadComponents(componentConfig.components, container, childForm, validationSchema);
}
return;
}
// Determine which component to load using safe navigation.
const mapping = this.mappingService.getMapping(componentConfig?.type ?? '');
const componentToLoad = mapping?.component || TypeNotFoundComponent;
const componentRef = container.createComponent(componentToLoad);
componentRef.instance.config = componentConfig;
if (form) {
componentRef.instance.form = form;
}
// Attach validationSchema for specific component types if provided.
if (form &&
['formArray', 'formArraySelect', 'formArrayCheckbox', 'collapse'].includes(componentConfig?.type ?? '')) {
const schemaKey = componentConfig?.name;
componentRef.instance.validationSchema = componentConfig.type === 'collapse'
? validationSchema
: this.findValidationSchema(validationSchema, schemaKey ?? '');
}
// Recursively load nested child components, if any.
if (Array.isArray(componentConfig?.components) && componentConfig.components.length > 0) {
const nestedContainer = componentRef.instance.viewContainerRef || container;
this.loadComponents(componentConfig.components, nestedContainer, form, validationSchema);
}
}
/**
* Recursively searches a validation schema for a specific key.
* @param schema The validation schema object.
* @param key The key to search for.
* @returns The matching schema section or null if not found.
*/
findValidationSchema(schema, key) {
if (!schema)
return null;
for (const k in schema) {
if (k === 'default')
continue;
if (k === key)
return schema[k];
if (typeof schema[k] === 'object' && schema[k] !== null) {
const result = this.findValidationSchema(schema[k], key);
if (result)
return result;
}
}
return null;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ComponentFactoryService, deps: [{ token: ComponentMappingService }, { token: NgxOverlayService }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ComponentFactoryService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: ComponentFactoryService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}], ctorParameters: () => [{ type: ComponentMappingService }, { type: NgxOverlayService }] });
/*
* Public API Surface of ngx-json-ui
*/
// public-api.ts
/**
* Generated bundle index. Do not edit.
*/
export { COMPONENT_MAPPINGS, COMPONENT_MAPPING_CONFIG, ComponentFactoryService, ComponentMappingService, FormBuilderModule, ModalComponent, NgxOverlayService };
//# sourceMappingURL=ngx-json-ui.mjs.map