@kustomizer/visual-editor 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, inject, Injectable, makeEnvironmentProviders, ViewContainerRef, DestroyRef, input, effect, reflectComponentType, ChangeDetectionStrategy, Component, computed, NgZone,
|
|
2
|
+
import { InjectionToken, inject, Injectable, makeEnvironmentProviders, provideEnvironmentInitializer, signal, ViewContainerRef, DestroyRef, input, effect, reflectComponentType, ChangeDetectionStrategy, Component, computed, NgZone, viewChild, output, isDevMode } from '@angular/core';
|
|
3
3
|
import { Router, ActivatedRoute } from '@angular/router';
|
|
4
4
|
import { of, startWith, map, delay, throwError, isObservable, Observable, BehaviorSubject, tap, Subject, filter, firstValueFrom, debounceTime, switchMap as switchMap$1, takeUntil } from 'rxjs';
|
|
5
5
|
import { switchMap, map as map$1, catchError } from 'rxjs/operators';
|
|
@@ -2104,6 +2104,17 @@ function provideEditorComponents(definitions) {
|
|
|
2104
2104
|
useValue: definitions,
|
|
2105
2105
|
multi: true,
|
|
2106
2106
|
},
|
|
2107
|
+
// Fallback: directly register definitions via environment initializer.
|
|
2108
|
+
// This ensures registration works even when the InjectionToken doesn't
|
|
2109
|
+
// match between pre-bundled library code and app code (e.g. ng serve with Vite).
|
|
2110
|
+
provideEnvironmentInitializer(() => {
|
|
2111
|
+
const registry = inject(ComponentRegistryService);
|
|
2112
|
+
for (const def of definitions) {
|
|
2113
|
+
if (!registry.has(def.type)) {
|
|
2114
|
+
registry.register(def);
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2117
|
+
}),
|
|
2107
2118
|
]);
|
|
2108
2119
|
}
|
|
2109
2120
|
|
|
@@ -2112,10 +2123,28 @@ function provideEditorComponents(definitions) {
|
|
|
2112
2123
|
*/
|
|
2113
2124
|
class ComponentRegistryService {
|
|
2114
2125
|
definitions = new Map();
|
|
2126
|
+
_version = signal(0, ...(ngDevMode ? [{ debugName: "_version" }] : []));
|
|
2115
2127
|
injectedDefinitions = inject(EDITOR_COMPONENT_DEFINITIONS, { optional: true }) ?? [];
|
|
2116
2128
|
constructor() {
|
|
2117
2129
|
this.injectedDefinitions.flat().forEach((def) => this.register(def));
|
|
2118
2130
|
}
|
|
2131
|
+
/**
|
|
2132
|
+
* Clear all registered definitions
|
|
2133
|
+
*/
|
|
2134
|
+
clear() {
|
|
2135
|
+
this.definitions.clear();
|
|
2136
|
+
this._version.update(v => v + 1);
|
|
2137
|
+
}
|
|
2138
|
+
/**
|
|
2139
|
+
* Unregister a single component definition by type
|
|
2140
|
+
*/
|
|
2141
|
+
unregister(type) {
|
|
2142
|
+
const deleted = this.definitions.delete(type);
|
|
2143
|
+
if (deleted) {
|
|
2144
|
+
this._version.update(v => v + 1);
|
|
2145
|
+
}
|
|
2146
|
+
return deleted;
|
|
2147
|
+
}
|
|
2119
2148
|
/**
|
|
2120
2149
|
* Register a component definition
|
|
2121
2150
|
*/
|
|
@@ -2124,6 +2153,7 @@ class ComponentRegistryService {
|
|
|
2124
2153
|
console.warn(`ComponentRegistry: Component type "${definition.type}" is already registered. Overwriting.`);
|
|
2125
2154
|
}
|
|
2126
2155
|
this.definitions.set(definition.type, definition);
|
|
2156
|
+
this._version.update(v => v + 1);
|
|
2127
2157
|
}
|
|
2128
2158
|
/**
|
|
2129
2159
|
* Register multiple definitions
|
|
@@ -2172,6 +2202,7 @@ class ComponentRegistryService {
|
|
|
2172
2202
|
* Get all definitions
|
|
2173
2203
|
*/
|
|
2174
2204
|
getAll() {
|
|
2205
|
+
this._version(); // reactive dependency for signal consumers
|
|
2175
2206
|
return Array.from(this.definitions.values());
|
|
2176
2207
|
}
|
|
2177
2208
|
/**
|
|
@@ -2365,8 +2396,7 @@ class DynamicRendererComponent {
|
|
|
2365
2396
|
/** Additional context (sectionId, index, etc.) */
|
|
2366
2397
|
context = input({}, ...(ngDevMode ? [{ debugName: "context" }] : []));
|
|
2367
2398
|
/** Error state signal */
|
|
2368
|
-
|
|
2369
|
-
error = () => this._error;
|
|
2399
|
+
error = signal(false, ...(ngDevMode ? [{ debugName: "error" }] : []));
|
|
2370
2400
|
componentRef = null;
|
|
2371
2401
|
currentType = null;
|
|
2372
2402
|
currentAvailableInputs = null;
|
|
@@ -2392,13 +2422,17 @@ class DynamicRendererComponent {
|
|
|
2392
2422
|
this.cleanup();
|
|
2393
2423
|
const componentType = this.registry.getComponent(element.type);
|
|
2394
2424
|
if (!componentType) {
|
|
2395
|
-
this.
|
|
2425
|
+
this.error.set(true);
|
|
2396
2426
|
this.currentType = null;
|
|
2397
2427
|
this.currentAvailableInputs = null;
|
|
2398
|
-
|
|
2428
|
+
const all = this.registry.getAll();
|
|
2429
|
+
const hasType = this.registry.has(element.type);
|
|
2430
|
+
console.warn(`DynamicRenderer: No component registered for type "${element.type}".`, hasType
|
|
2431
|
+
? `Definition exists but has no "component" class (manifest-only).`
|
|
2432
|
+
: `Registry has ${all.length} definition(s): [${all.map(d => d.type).join(', ')}]`);
|
|
2399
2433
|
return;
|
|
2400
2434
|
}
|
|
2401
|
-
this.
|
|
2435
|
+
this.error.set(false);
|
|
2402
2436
|
this.currentType = element.type;
|
|
2403
2437
|
this.previousInputs.clear();
|
|
2404
2438
|
this.componentRef = this.viewContainerRef.createComponent(componentType);
|
|
@@ -7814,22 +7848,64 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
7814
7848
|
class ManifestLoaderService {
|
|
7815
7849
|
http = inject(HttpClient);
|
|
7816
7850
|
registry = inject(ComponentRegistryService);
|
|
7851
|
+
watchInterval = null;
|
|
7852
|
+
lastManifestHash = '';
|
|
7853
|
+
manifestTypes = new Set();
|
|
7817
7854
|
/**
|
|
7818
7855
|
* Fetch the manifest from the given URL and register all components.
|
|
7819
7856
|
*/
|
|
7820
7857
|
loadManifest(url) {
|
|
7821
|
-
return this.http.get(url).pipe(tap((manifest) =>
|
|
7858
|
+
return this.http.get(url).pipe(tap((manifest) => {
|
|
7859
|
+
this.registerManifestComponents(manifest);
|
|
7860
|
+
this.lastManifestHash = this.hashManifest(manifest);
|
|
7861
|
+
}));
|
|
7862
|
+
}
|
|
7863
|
+
/**
|
|
7864
|
+
* Poll the manifest URL for changes and re-register components when the
|
|
7865
|
+
* content hash differs. Only active in dev mode. No-op in production.
|
|
7866
|
+
*/
|
|
7867
|
+
startWatching(manifestUrl, intervalMs = 2000) {
|
|
7868
|
+
if (!isDevMode() || this.watchInterval)
|
|
7869
|
+
return;
|
|
7870
|
+
this.watchInterval = setInterval(() => {
|
|
7871
|
+
this.http.get(manifestUrl).subscribe({
|
|
7872
|
+
next: (manifest) => {
|
|
7873
|
+
const hash = this.hashManifest(manifest);
|
|
7874
|
+
if (hash !== this.lastManifestHash) {
|
|
7875
|
+
console.log('[Kustomizer] Manifest changed, reloading components…');
|
|
7876
|
+
this.lastManifestHash = hash;
|
|
7877
|
+
this.registerManifestComponents(manifest);
|
|
7878
|
+
}
|
|
7879
|
+
},
|
|
7880
|
+
error: () => { }, // silently ignore polling errors
|
|
7881
|
+
});
|
|
7882
|
+
}, intervalMs);
|
|
7883
|
+
}
|
|
7884
|
+
ngOnDestroy() {
|
|
7885
|
+
if (this.watchInterval) {
|
|
7886
|
+
clearInterval(this.watchInterval);
|
|
7887
|
+
this.watchInterval = null;
|
|
7888
|
+
}
|
|
7822
7889
|
}
|
|
7823
7890
|
/**
|
|
7824
7891
|
* Register manifest entries in the ComponentRegistryService.
|
|
7825
7892
|
* Each entry becomes a ComponentDefinition without a `component` field.
|
|
7826
7893
|
*/
|
|
7827
7894
|
registerManifestComponents(manifest) {
|
|
7895
|
+
// Remove only previously manifest-loaded definitions, preserving local components
|
|
7896
|
+
for (const type of this.manifestTypes) {
|
|
7897
|
+
this.registry.unregister(type);
|
|
7898
|
+
}
|
|
7899
|
+
this.manifestTypes.clear();
|
|
7828
7900
|
for (const entry of manifest.components) {
|
|
7829
7901
|
const definition = this.manifestEntryToDefinition(entry);
|
|
7830
7902
|
this.registry.register(definition);
|
|
7903
|
+
this.manifestTypes.add(definition.type);
|
|
7831
7904
|
}
|
|
7832
7905
|
}
|
|
7906
|
+
hashManifest(manifest) {
|
|
7907
|
+
return JSON.stringify(manifest.components.map(c => c.type + c.name + JSON.stringify(c.props ?? {}) + JSON.stringify(c.slots ?? [])));
|
|
7908
|
+
}
|
|
7833
7909
|
manifestEntryToDefinition(entry) {
|
|
7834
7910
|
return {
|
|
7835
7911
|
type: entry.type,
|