@vectoriox/iox-ui 4.16.0 → 4.16.2

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.
@@ -2275,37 +2275,45 @@ class GalleryLoop {
2275
2275
  * same index 0 — so the static frame and the first live frame match and there is no hydration flash.
2276
2276
  */
2277
2277
  class ClientGalleryComponent {
2278
+ /** Manual images — `GalleryImage[]` or a plain `string[]` of URLs (normalised on set). */
2279
+ set images(v) {
2280
+ this._images = v ?? [];
2281
+ this.urls = resolveGalleryUrls(this.normalizeImages(), null);
2282
+ // A live edit (image added/removed/reordered) while the loop runs → restart on the new set so
2283
+ // the canvas reflects it and the loop cycles through the new count.
2284
+ if (this.loopActive)
2285
+ this.startLoop();
2286
+ }
2287
+ get images() { return this._images; }
2288
+ set showDuration(v) { this._showDuration = v; this.loop?.setDurations(v, this._fadeDuration); }
2289
+ get showDuration() { return this._showDuration; }
2290
+ set fadeDuration(v) { this._fadeDuration = v; this.loop?.setDurations(this._showDuration, v); }
2291
+ get fadeDuration() { return this._fadeDuration; }
2278
2292
  constructor(platformId, cdr) {
2279
2293
  this.cdr = cdr;
2280
2294
  this.nodeId = '';
2281
- /** Manual images — `GalleryImage[]` or a plain `string[]` of URLs (normalised on set). */
2282
- this.images = [];
2283
2295
  this.effect = 'fade';
2284
- this.showDuration = 4000;
2285
- this.fadeDuration = 1000;
2286
2296
  this.autoStart = true;
2287
2297
  /** Layout mode — only `'stack'` is rendered in v1 (`'grid'` scaffolded for later). */
2288
2298
  this.layout = 'stack';
2289
- /** The flat, display-ready URLs the loop cycles. Recomputed when `images` changes. */
2299
+ // ── Inputs that mutate live state use SETTERS, not ngOnChanges ──────────────────────────────
2300
+ // The builder trait panel pushes edits via DIRECT property assignment (`instance.images = v`),
2301
+ // which does NOT trigger ngOnChanges — so a gallery that recomputed in ngOnChanges never refreshed
2302
+ // when you added an image on the canvas. A setter fires on BOTH direct assignment (builder panel)
2303
+ // and setInput (SSR engine / render.directive), so it's the one path that works everywhere.
2304
+ this._images = [];
2305
+ this._showDuration = 4000;
2306
+ this._fadeDuration = 1000;
2307
+ /** The flat, display-ready URLs the loop cycles. Recomputed whenever `images` is set. */
2290
2308
  this.urls = [];
2291
2309
  this.currentIndex = 0;
2292
2310
  this.fadingOutIndex = null;
2293
2311
  this.started = false;
2312
+ /** True once the loop has been started (in ngAfterViewInit) — gates the setter-driven restart. */
2313
+ this.loopActive = false;
2294
2314
  this.loop = null;
2295
2315
  this.isBrowser = isPlatformBrowser(platformId);
2296
2316
  }
2297
- ngOnChanges(changes) {
2298
- if (changes['images']) {
2299
- this.urls = resolveGalleryUrls(this.normalizeImages(), null);
2300
- }
2301
- if (this.loop && (changes['showDuration'] || changes['fadeDuration'])) {
2302
- this.loop.setDurations(this.showDuration, this.fadeDuration);
2303
- }
2304
- // If the image set changed after the loop was already running, restart it on the new count.
2305
- if (this.loop && changes['images'] && !changes['images'].firstChange) {
2306
- this.startLoop();
2307
- }
2308
- }
2309
2317
  ngAfterViewInit() {
2310
2318
  if (this.isBrowser && this.autoStart) {
2311
2319
  this.startLoop();
@@ -2314,6 +2322,7 @@ class ClientGalleryComponent {
2314
2322
  ngOnDestroy() {
2315
2323
  this.loop?.stop();
2316
2324
  this.loop = null;
2325
+ this.loopActive = false;
2317
2326
  }
2318
2327
  /** Per-slide inline style. Before the loop activates (server + no-JS + pre-first-frame) the first
2319
2328
  * image is the visible static frame; once running, the effect owns each slide's look. */
@@ -2333,6 +2342,7 @@ class ClientGalleryComponent {
2333
2342
  startLoop() {
2334
2343
  if (!this.isBrowser)
2335
2344
  return;
2345
+ this.loopActive = true;
2336
2346
  this.loop?.stop();
2337
2347
  this.loop = new GalleryLoop({
2338
2348
  showMs: this.showDuration,
@@ -2350,7 +2360,7 @@ class ClientGalleryComponent {
2350
2360
  return (this.images ?? []).map(img => (typeof img === 'string' ? { url: img } : img));
2351
2361
  }
2352
2362
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: ClientGalleryComponent, deps: [{ token: PLATFORM_ID }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
2353
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: ClientGalleryComponent, isStandalone: false, selector: "iox-gallery", inputs: { nodeId: "nodeId", images: "images", effect: "effect", showDuration: "showDuration", fadeDuration: "fadeDuration", autoStart: "autoStart", layout: "layout" }, usesOnChanges: true, ngImport: i0, template: `
2363
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: ClientGalleryComponent, isStandalone: false, selector: "iox-gallery", inputs: { nodeId: "nodeId", effect: "effect", autoStart: "autoStart", layout: "layout", images: "images", showDuration: "showDuration", fadeDuration: "fadeDuration" }, ngImport: i0, template: `
2354
2364
  <div class="iox-gallery" [class]="'iox-node-' + nodeId">
2355
2365
  <div *ngFor="let url of urls; index as i"
2356
2366
  class="iox-gallery__img"
@@ -2358,7 +2368,7 @@ class ClientGalleryComponent {
2358
2368
  [ngStyle]="slideStyle(i)"></div>
2359
2369
  <div class="iox-gallery__overlay"></div>
2360
2370
  </div>
2361
- `, isInline: true, styles: [":host{display:block;width:100%;height:100%}.iox-gallery{position:relative;width:100%;height:100%;overflow:hidden;box-sizing:border-box}.iox-gallery__img{position:absolute;inset:0;background-size:cover;background-position:center;pointer-events:none;opacity:0;filter:brightness(1.35);-webkit-mask-image:radial-gradient(circle at 50% 50%,rgba(0,0,0,1) 80%,rgba(0,0,0,.1) 95%,rgba(0,0,0,0) 100%);mask-image:radial-gradient(circle at 50% 50%,#000 80%,#0000001a 95%,#0000)}.iox-gallery__overlay{position:absolute;inset:0;pointer-events:none;z-index:3;background:linear-gradient(to bottom,#00000080,#00000026 20% 80%,#00000080)}\n"], dependencies: [{ kind: "directive", type: i1$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] }); }
2371
+ `, isInline: true, styles: [":host{display:block}.iox-gallery{position:relative;overflow:hidden;box-sizing:border-box}.iox-gallery__img{position:absolute;inset:0;background-size:cover;background-position:center;pointer-events:none;opacity:0;filter:brightness(1.35);-webkit-mask-image:radial-gradient(circle at 50% 50%,rgba(0,0,0,1) 80%,rgba(0,0,0,.1) 95%,rgba(0,0,0,0) 100%);mask-image:radial-gradient(circle at 50% 50%,#000 80%,#0000001a 95%,#0000)}.iox-gallery__overlay{position:absolute;inset:0;pointer-events:none;z-index:3;background:linear-gradient(to bottom,#00000080,#00000026 20% 80%,#00000080)}\n"], dependencies: [{ kind: "directive", type: i1$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] }); }
2362
2372
  }
2363
2373
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: ClientGalleryComponent, decorators: [{
2364
2374
  type: Component,
@@ -2370,24 +2380,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
2370
2380
  [ngStyle]="slideStyle(i)"></div>
2371
2381
  <div class="iox-gallery__overlay"></div>
2372
2382
  </div>
2373
- `, standalone: false, styles: [":host{display:block;width:100%;height:100%}.iox-gallery{position:relative;width:100%;height:100%;overflow:hidden;box-sizing:border-box}.iox-gallery__img{position:absolute;inset:0;background-size:cover;background-position:center;pointer-events:none;opacity:0;filter:brightness(1.35);-webkit-mask-image:radial-gradient(circle at 50% 50%,rgba(0,0,0,1) 80%,rgba(0,0,0,.1) 95%,rgba(0,0,0,0) 100%);mask-image:radial-gradient(circle at 50% 50%,#000 80%,#0000001a 95%,#0000)}.iox-gallery__overlay{position:absolute;inset:0;pointer-events:none;z-index:3;background:linear-gradient(to bottom,#00000080,#00000026 20% 80%,#00000080)}\n"] }]
2383
+ `, standalone: false, styles: [":host{display:block}.iox-gallery{position:relative;overflow:hidden;box-sizing:border-box}.iox-gallery__img{position:absolute;inset:0;background-size:cover;background-position:center;pointer-events:none;opacity:0;filter:brightness(1.35);-webkit-mask-image:radial-gradient(circle at 50% 50%,rgba(0,0,0,1) 80%,rgba(0,0,0,.1) 95%,rgba(0,0,0,0) 100%);mask-image:radial-gradient(circle at 50% 50%,#000 80%,#0000001a 95%,#0000)}.iox-gallery__overlay{position:absolute;inset:0;pointer-events:none;z-index:3;background:linear-gradient(to bottom,#00000080,#00000026 20% 80%,#00000080)}\n"] }]
2374
2384
  }], ctorParameters: () => [{ type: undefined, decorators: [{
2375
2385
  type: Inject,
2376
2386
  args: [PLATFORM_ID]
2377
2387
  }] }, { type: i0.ChangeDetectorRef }], propDecorators: { nodeId: [{
2378
2388
  type: Input
2379
- }], images: [{
2380
- type: Input
2381
2389
  }], effect: [{
2382
2390
  type: Input
2383
- }], showDuration: [{
2384
- type: Input
2385
- }], fadeDuration: [{
2386
- type: Input
2387
2391
  }], autoStart: [{
2388
2392
  type: Input
2389
2393
  }], layout: [{
2390
2394
  type: Input
2395
+ }], images: [{
2396
+ type: Input
2397
+ }], showDuration: [{
2398
+ type: Input
2399
+ }], fadeDuration: [{
2400
+ type: Input
2391
2401
  }] } });
2392
2402
 
2393
2403
  const COMPONENTS = [