UNPKG

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
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