diff --git a/projects/ng-gallery-demo/src/app/pages/lab/lab.component.html b/projects/ng-gallery-demo/src/app/pages/lab/lab.component.html index 4830e413..7238acdd 100644 --- a/projects/ng-gallery-demo/src/app/pages/lab/lab.component.html +++ b/projects/ng-gallery-demo/src/app/pages/lab/lab.component.html @@ -27,6 +27,12 @@

(itemClick)="onItemClick($event)" (thumbClick)="onThumbClick($event)"> + + @if (navConfig.nav) { } @@ -173,7 +179,8 @@

Item autosize
- Thumb autosize + Thumb autosize +
@@ -240,7 +247,8 @@

Centralize Thumbnails

- Detach thumbnails + Detach thumbnails +
Disable thumbnails' clicks diff --git a/projects/ng-gallery-demo/src/app/pages/lab/lab.component.ts b/projects/ng-gallery-demo/src/app/pages/lab/lab.component.ts index c0927f50..57653c04 100644 --- a/projects/ng-gallery-demo/src/app/pages/lab/lab.component.ts +++ b/projects/ng-gallery-demo/src/app/pages/lab/lab.component.ts @@ -1,7 +1,7 @@ import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; import { Title } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; -import { NgIf, NgFor, AsyncPipe } from '@angular/common'; +import { NgIf, NgFor, AsyncPipe, NgOptimizedImage } from '@angular/common'; import { GalleryItem, GalleryConfig, @@ -9,7 +9,12 @@ import { Orientation, ThumbnailsPosition, GalleryComponent, - GalleryThumbsComponent, GalleryNavComponent, GalleryBulletsComponent, GalleryCounterComponent + GalleryThumbsComponent, + GalleryNavComponent, + GalleryBulletsComponent, + GalleryCounterComponent, + GalleryItemDef, + ImgRecognizer } from 'ng-gallery'; import { MatInputModule } from '@angular/material/input'; import { MatCheckboxModule } from '@angular/material/checkbox'; @@ -53,6 +58,9 @@ import { FooterComponent } from '../../shared/footer/footer.component'; GalleryNavComponent, GalleryBulletsComponent, GalleryCounterComponent, + GalleryItemDef, + ImgRecognizer, + NgOptimizedImage ] }) export class LabComponent implements OnInit { diff --git a/projects/ng-gallery/src/lib/autoplay/autoplay.directive.ts b/projects/ng-gallery/src/lib/autoplay/autoplay.directive.ts index 2dc3f6f6..06581af8 100644 --- a/projects/ng-gallery/src/lib/autoplay/autoplay.directive.ts +++ b/projects/ng-gallery/src/lib/autoplay/autoplay.directive.ts @@ -26,28 +26,28 @@ export class AutoplayDirective { // TODO: Should not observe config in the two effects, will be refactored // TODO: Make especial inputs for the autoplay directive such as autoplayScrollBehavior - effect((onCleanup: EffectCleanupRegisterFn) => { - const config: GalleryConfig = this._galleryRef.config(); - const isPlaying: boolean = this._galleryRef.isPlaying(); - - untracked(() => { - if (isPlaying) { - sub = this._imgManager.getActiveItem().pipe( - switchMap(() => of({}).pipe( - delay(config.autoplayInterval), - tap(() => { - if (this._galleryRef.hasNext()) { - this._galleryRef.next(config.scrollBehavior); - } else { - this._galleryRef.set(0, config.scrollBehavior); - } - }) - )) - ).subscribe(); - } - onCleanup(() => sub?.unsubscribe()); - }); - }); + // effect((onCleanup: EffectCleanupRegisterFn) => { + // const config: GalleryConfig = this._galleryRef.config(); + // const isPlaying: boolean = this._galleryRef.isPlaying(); + // + // untracked(() => { + // if (isPlaying) { + // sub = this._imgManager.getActiveItem().pipe( + // switchMap(() => of({}).pipe( + // delay(config.autoplayInterval), + // tap(() => { + // if (this._galleryRef.hasNext()) { + // this._galleryRef.next(config.scrollBehavior); + // } else { + // this._galleryRef.set(0, config.scrollBehavior); + // } + // }) + // )) + // ).subscribe(); + // } + // onCleanup(() => sub?.unsubscribe()); + // }); + // }); effect(() => { const autoplay: boolean = this._galleryRef.config().autoplay; diff --git a/projects/ng-gallery/src/lib/components/gallery-item.component.ts b/projects/ng-gallery/src/lib/components/gallery-item.component.ts index dd9b94f0..4b60de13 100644 --- a/projects/ng-gallery/src/lib/components/gallery-item.component.ts +++ b/projects/ng-gallery/src/lib/components/gallery-item.component.ts @@ -1,6 +1,5 @@ import { Component, - inject, signal, output, computed, @@ -16,19 +15,12 @@ import { NgTemplateOutlet } from '@angular/common'; import { toObservable } from '@angular/core/rxjs-interop'; import { Observable } from 'rxjs'; import { GalleryItemContext } from '../directives/gallery-item-def.directive'; -import { GalleryIframeComponent } from './templates/gallery-iframe.component'; -import { GalleryVideoComponent } from './templates/gallery-video.component'; -import { GalleryImageComponent } from './templates/gallery-image.component'; import { GalleryItemType, GalleryItemTypes, LoadingStrategy } from '../models/constants'; import { GalleryItemData, - ImageItemData, ItemState, VideoItemData, - VimeoItemData, - YoutubeItemData } from './templates/items.model'; -import { GalleryRef } from '../services/gallery-ref'; import { SliderItem } from './items/items'; @Component({ @@ -41,67 +33,68 @@ import { SliderItem } from './items/items'; }, providers: [{ provide: SliderItem, useExisting: GalleryItemComponent }], template: ` - @if (load()) { - @switch (type()) { - @case (Types.Image) { - - @if (galleryRef.config().imageTemplate) { -
- -
- } - } - @case (Types.Video) { - - } - @case (Types.Youtube) { - - } - @case (Types.Vimeo) { - - } - @case (Types.Iframe) { - - } - @default { - @if (galleryRef.config().itemTemplate) { -
- -
- } - } - } - } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + `, styleUrl: './gallery-item.scss', changeDetection: ChangeDetectionStrategy.OnPush, - imports: [NgTemplateOutlet, GalleryImageComponent, GalleryVideoComponent, GalleryIframeComponent] + imports: [NgTemplateOutlet] }) export class GalleryItemComponent extends SliderItem implements AfterViewInit { - readonly galleryRef: GalleryRef = inject(GalleryRef); - readonly Types = GalleryItemTypes; /** A stream that indicates that the height was emitted after the image is loaded, used only for gallery image types */ @@ -113,9 +106,6 @@ export class GalleryItemComponent extends SliderItem implements AfterViewInit { * The img recognizer directive will set it to true*/ isItemContainImage: boolean; - /** Item's index in the gallery */ - index: InputSignal = input(); - /** The number of total items */ count: InputSignal = input(); @@ -138,31 +128,31 @@ export class GalleryItemComponent extends SliderItem implements AfterViewInit { } }); - load: Signal = computed(() => { - switch (this.galleryRef.config().loadingStrategy) { - case LoadingStrategy.Preload: - return true; - case LoadingStrategy.Lazy: - return this.currIndex() === this.index(); - default: - return this.currIndex() === this.index() || this.currIndex() === this.index() - 1 || this.currIndex() === this.index() + 1; - } - }); - - - imageContext: Signal> = computed(() => { - return { - $implicit: this.imageData, - index: this.index(), - type: this.type(), - active: this.active(), - count: this.count(), - first: this.index() === 0, - last: this.index() === this.count() - 1 - }; - }); - - itemContext: Signal> = computed(() => { + // load: Signal = computed(() => { + // switch (this.galleryRef.config().loadingStrategy) { + // case LoadingStrategy.Preload: + // return true; + // case LoadingStrategy.Lazy: + // return this.currIndex() === this.index(); + // default: + // return this.currIndex() === this.index() || this.currIndex() === this.index() - 1 || this.currIndex() === this.index() + 1; + // } + // }); + + + // imageContext: Signal> = computed(() => { + // return { + // $implicit: this.imageData, + // index: this.index(), + // type: this.type(), + // active: this.active(), + // count: this.count(), + // first: this.index() === 0, + // last: this.index() === this.count() - 1 + // }; + // }); + + itemContext: Signal> = computed(() => { return { $implicit: this.data(), index: this.index(), @@ -174,38 +164,38 @@ export class GalleryItemComponent extends SliderItem implements AfterViewInit { }; }); - youtubeSrc: Signal = computed(() => { - let autoplay: 1 | 0 = 0; - if (this.active() && this.type() === GalleryItemTypes.Youtube && (this.data() as YoutubeItemData).autoplay) { - autoplay = 1; - } - const url: URL = new URL(this.data().src as string); - url.search = new URLSearchParams({ - wmode: 'transparent', - ...(this.data() as YoutubeItemData).params, - autoplay - }).toString(); - return url.href; - }); - - vimeoSrc: Signal = computed(() => { - let autoplay: 1 | 0 = 0; - if (this.active() && this.type() === GalleryItemTypes.Vimeo) { - if ((this.data as VimeoItemData).autoplay) { - autoplay = 1; - } - } - const url: URL = new URL(this.data().src as string); - url.search = new URLSearchParams({ - ...(this.data() as VimeoItemData).params, - autoplay, - }).toString(); - return url.href; - }); - - get imageData(): ImageItemData { - return this.data(); - } + // youtubeSrc: Signal = computed(() => { + // let autoplay: 1 | 0 = 0; + // if (this.active() && this.type() === GalleryItemTypes.Youtube && (this.data() as YoutubeItemData).autoplay) { + // autoplay = 1; + // } + // const url: URL = new URL(this.data().src as string); + // url.search = new URLSearchParams({ + // wmode: 'transparent', + // ...(this.data() as YoutubeItemData).params, + // autoplay + // }).toString(); + // return url.href; + // }); + // + // vimeoSrc: Signal = computed(() => { + // let autoplay: 1 | 0 = 0; + // if (this.active() && this.type() === GalleryItemTypes.Vimeo) { + // if ((this.data as VimeoItemData).autoplay) { + // autoplay = 1; + // } + // } + // const url: URL = new URL(this.data().src as string); + // url.search = new URLSearchParams({ + // ...(this.data() as VimeoItemData).params, + // autoplay, + // }).toString(); + // return url.href; + // }); + // + // get imageData(): ImageItemData { + // return this.data(); + // } get videoData(): VideoItemData { return this.data(); diff --git a/projects/ng-gallery/src/lib/components/gallery-item.scss b/projects/ng-gallery/src/lib/components/gallery-item.scss index 7b3c7564..aaf42aee 100644 --- a/projects/ng-gallery/src/lib/components/gallery-item.scss +++ b/projects/ng-gallery/src/lib/components/gallery-item.scss @@ -33,6 +33,16 @@ height: 100%; } } + ::ng-deep { + img.g-image-item { + object-fit: var(--image-object-fit); + width: 100%; + height: 100%; + pointer-events: none; + max-height: 100%; + max-width: 100%; + } + } } gallery-image { diff --git a/projects/ng-gallery/src/lib/components/gallery-slider.component.ts b/projects/ng-gallery/src/lib/components/gallery-slider.component.ts index aac69431..ea6a173c 100644 --- a/projects/ng-gallery/src/lib/components/gallery-slider.component.ts +++ b/projects/ng-gallery/src/lib/components/gallery-slider.component.ts @@ -8,14 +8,16 @@ import { GalleryItemComponent } from './gallery-item.component'; import { ScrollSnapType } from '../services/scroll-snap-type'; import { ResizeSensor } from '../services/resize-sensor'; import { SliderComponent } from './slider/slider'; +import { AutoHeight } from '../observers/auto-height'; @Component({ standalone: true, selector: 'gallery-slider', template: ` ).nativeElement; + + /** Item's index in the gallery */ + index: InputSignal = input(); + /** A stream that indicates that the height was emitted after the image is loaded, used only for gallery image types */ readonly state: WritableSignal = signal('loading'); + readonly visible: Signal = computed(() => { + return !!this.galleryRef.visibleItems()[this.index()] + }); + readonly state$: Observable = toObservable(this.state); /** A flag that indicates if the item is type of image, it can be a custom template by the user, diff --git a/projects/ng-gallery/src/lib/components/slider/slider.ts b/projects/ng-gallery/src/lib/components/slider/slider.ts index 977615c4..baa5edaf 100644 --- a/projects/ng-gallery/src/lib/components/slider/slider.ts +++ b/projects/ng-gallery/src/lib/components/slider/slider.ts @@ -24,7 +24,7 @@ import { SliderItem } from '../items/items'; '[class.g-slider]': 'true', '[attr.centralised]': 'centralized()', '[attr.orientation]': 'orientation()', - '[attr.autoSize]': 'autoSize()', + '[attr.autosize]': 'autosize()', }, selector: 'g-slider', template: ` @@ -39,7 +39,7 @@ export class SliderComponent { readonly orientation: InputSignal = input(); - readonly autoSize: InputSignal = input(); + readonly autosize: InputSignal = input(); readonly centralized: InputSignal = input(); diff --git a/projects/ng-gallery/src/lib/components/templates/gallery-image.component.ts b/projects/ng-gallery/src/lib/components/templates/gallery-image.component.ts index 109e535c..9bc7c0a5 100644 --- a/projects/ng-gallery/src/lib/components/templates/gallery-image.component.ts +++ b/projects/ng-gallery/src/lib/components/templates/gallery-image.component.ts @@ -16,6 +16,7 @@ import { animate, style, transition, trigger } from '@angular/animations'; import { imageFailedSvg } from './svg-assets'; import { ImgRecognizer } from '../../utils/img-recognizer'; import { ItemState } from './items.model'; +import { NgOptimizedImage } from '@angular/common'; @Component({ standalone: true, @@ -34,7 +35,8 @@ import { ItemState } from './items.model'; template: ` @if (isThumbnail()) { } @else { - } @@ -82,7 +83,7 @@ import { ItemState } from './items.model'; `, styleUrl: './gallery-image.scss', changeDetection: ChangeDetectionStrategy.OnPush, - imports: [ImgRecognizer] + imports: [ImgRecognizer, NgOptimizedImage] }) export class GalleryImageComponent { diff --git a/projects/ng-gallery/src/lib/components/templates/gallery-image.scss b/projects/ng-gallery/src/lib/components/templates/gallery-image.scss index 9e106869..5ea2dbde 100644 --- a/projects/ng-gallery/src/lib/components/templates/gallery-image.scss +++ b/projects/ng-gallery/src/lib/components/templates/gallery-image.scss @@ -1,4 +1,5 @@ :host { + position: relative; display: flex; width: 100%; height: 100%; diff --git a/projects/ng-gallery/src/lib/directives/gallery-item-def.directive.ts b/projects/ng-gallery/src/lib/directives/gallery-item-def.directive.ts index 4db53d32..34635fde 100644 --- a/projects/ng-gallery/src/lib/directives/gallery-item-def.directive.ts +++ b/projects/ng-gallery/src/lib/directives/gallery-item-def.directive.ts @@ -1,4 +1,4 @@ -import { Directive, TemplateRef } from '@angular/core'; +import { Directive, inject, TemplateRef } from '@angular/core'; import { GalleryItemData } from '../components/templates/items.model'; import { GalleryItemType } from '../models/constants'; @@ -7,14 +7,13 @@ import { GalleryItemType } from '../models/constants'; selector: '[galleryItemDef]' }) export class GalleryItemDef { - constructor(public templateRef: TemplateRef>) { - } + templateRef: TemplateRef> = inject(TemplateRef>) // Make sure the template checker knows the type of the context with which the // template of this directive will be rendered static ngTemplateContextGuard( directive: GalleryItemDef, - context: unknown + context: GalleryItemContext ): context is GalleryItemContext { return true; } diff --git a/projects/ng-gallery/src/lib/models/config.model.ts b/projects/ng-gallery/src/lib/models/config.model.ts index 94747bdb..a9196102 100644 --- a/projects/ng-gallery/src/lib/models/config.model.ts +++ b/projects/ng-gallery/src/lib/models/config.model.ts @@ -1,6 +1,7 @@ import { InjectionToken, Provider, TemplateRef } from '@angular/core'; import { BezierEasingOptions } from '../smooth-scroll'; import { defaultConfig } from '../utils/gallery.default'; +import { GalleryItemData } from '../components/templates/items.model'; export const GALLERY_CONFIG: InjectionToken = new InjectionToken('GALLERY_CONFIG', { providedIn: 'root', @@ -56,7 +57,7 @@ interface SliderConfig { loadingStrategy?: LoadingStrategy; loadingAttr?: LoadingAttr; boxTemplate?: TemplateRef; - itemTemplate?: TemplateRef; + itemTemplate?: TemplateRef; imageTemplate?: TemplateRef; centralized?: boolean; } diff --git a/projects/ng-gallery/src/lib/observers/auto-height.ts b/projects/ng-gallery/src/lib/observers/auto-height.ts new file mode 100644 index 00000000..89fe67a7 --- /dev/null +++ b/projects/ng-gallery/src/lib/observers/auto-height.ts @@ -0,0 +1,86 @@ +import { + Directive, + effect, + inject, + signal, + untracked, + input, + ElementRef, + InputSignal, + WritableSignal, + EffectCleanupRegisterFn +} from '@angular/core'; +import { Observable, Subscription, of, filter, fromEvent, switchMap, tap, take } from 'rxjs'; +import { ImgManager } from '../utils/img-manager'; +import { GalleryRef } from '../services/gallery-ref'; + +/** + * Auto height feature prerequisites: + * - autosize should be set to 'false' + * - if thumbnails exist, it should not be aligned to the right or left + */ + +@Directive({ + standalone: true, + selector: '[autoHeight]' +}) +export class AutoHeight { + + private readonly galleryRef: GalleryRef = inject(GalleryRef); + + private readonly manager: ImgManager = inject(ImgManager); + + private readonly _viewport: HTMLElement = inject(ElementRef).nativeElement; + + private readonly _galleryCore: HTMLElement = this._viewport.parentElement.parentElement.parentElement; + + readonly isResizing: WritableSignal = signal(false); + + disabled: InputSignal = input(false, { alias: 'disableAutoHeight' }); + + constructor() { + let sub$: Subscription; + + let afterHeightChanged$: Observable; + + + // Check if height has transition for the auto-height feature + const transitionDuration: string = getComputedStyle(this._viewport).transitionDuration; + console.log(parseFloat(transitionDuration)) + if (!parseFloat(transitionDuration)) { + afterHeightChanged$ = of(null); + } else { + afterHeightChanged$ = fromEvent(this._viewport, 'transitionend'); + } + + effect((onCleanup: EffectCleanupRegisterFn) => { + if (this.disabled()) return; + // const currIndex = this.galleryRef.currIndex(); + untracked(() => { + sub$ = this.manager.getActiveItem().pipe( + tap((img)=> { + console.log('🤡 getActiveItem!', img.height, this._viewport.clientHeight); + }), + // SKip if img height is equal the slider height + filter((img: HTMLImageElement) => img.height !== this._viewport.clientHeight), + switchMap((img: HTMLImageElement) => { + // TODO: Check if even to execute this code if there is no transition duration set. + this._galleryCore.style.setProperty('--slider-height', `${ img.clientHeight }px`); + this.isResizing.set(true); + console.log('👽 Resize started!') + + return afterHeightChanged$.pipe( + tap(() => { + this.isResizing.set(false); + console.log('🍄 Resize ended!') + }), + take(1) + ); + }) + ).subscribe(); + + onCleanup(() => sub$?.unsubscribe()); + }); + }); + } +} diff --git a/projects/ng-gallery/src/lib/observers/intersection-sensor.directive.ts b/projects/ng-gallery/src/lib/observers/intersection-sensor.directive.ts index ff7b5776..3d999d2a 100644 --- a/projects/ng-gallery/src/lib/observers/intersection-sensor.directive.ts +++ b/projects/ng-gallery/src/lib/observers/intersection-sensor.directive.ts @@ -93,6 +93,7 @@ export class IntersectionSensor { if (disabled) return; + // TODO: Should handle vertical orientation untracked(() => { const elements: Element[] = visibleElements.map((entry: IntersectionObserverEntry) => entry.target); @@ -103,8 +104,8 @@ export class IntersectionSensor { const options: IntersectionObserverInit = { root: this.nativeElement, - threshold: .99, - rootMargin: `0px ${ -diffSize }px 0px ${ -diffSize }px` + threshold: .999, + rootMargin: `1000px ${ -diffSize }px 1000px ${ -diffSize }px` }; this.zone.runOutsideAngular(() => { @@ -120,6 +121,8 @@ export class IntersectionSensor { const index: number = +elementWithHighestIntersectionRatio.target.getAttribute('galleryIndex'); + // TODO: There is a bug where index becomes 1 then goes back to 0 + console.log('intersection observer index', index, entries) if (index === this.galleryRef.currIndex()) return; // Set the new current index diff --git a/projects/ng-gallery/src/lib/observers/slider-resize-observer.directive.ts b/projects/ng-gallery/src/lib/observers/slider-resize-observer.directive.ts index cdcb2b82..bd628a3d 100644 --- a/projects/ng-gallery/src/lib/observers/slider-resize-observer.directive.ts +++ b/projects/ng-gallery/src/lib/observers/slider-resize-observer.directive.ts @@ -65,13 +65,13 @@ export class SliderResizeObserver implements AfterViewChecked, OnInit { // Stream that emits after the transition to the new height is completed private _afterHeightChanged$: Observable; - private _isAutoHeight: Signal = computed(() => { - const config: GalleryConfig = this._galleryRef.config(); - return config.autoHeight && - !config.itemAutosize && - config.orientation === 'horizontal' && - (config.thumbPosition === 'top' || config.thumbPosition === 'bottom'); - }); + // private _isAutoHeight: Signal = computed(() => { + // const config: GalleryConfig = this._galleryRef.config(); + // return config.autoHeight && + // !config.itemAutosize && + // config.orientation === 'horizontal' && + // (config.thumbPosition === 'top' || config.thumbPosition === 'bottom'); + // }); adapter: InputSignal = input(); @@ -84,7 +84,7 @@ export class SliderResizeObserver implements AfterViewChecked, OnInit { effect((onCleanup: EffectCleanupRegisterFn) => { const config = this._galleryRef.config(); - const isAutoHeight = this._isAutoHeight(); + // const isAutoHeight = this._isAutoHeight(); untracked(() => { this._zone.runOutsideAngular(() => { @@ -100,7 +100,7 @@ export class SliderResizeObserver implements AfterViewChecked, OnInit { // Update CSS variables with the proper values this.updateSliderSize(); - if (isAutoHeight) { + // if (isAutoHeight) { const img: HTMLImageElement = await firstValueFrom(this._imgManager.getActiveItem()); // If img height is identical to the viewport height then skip if (img.height === this._viewport.clientHeight) { @@ -118,9 +118,9 @@ export class SliderResizeObserver implements AfterViewChecked, OnInit { observe: true }); } - } else { - requestAnimationFrame(() => this.resetResizingState({ shouldSkip: true })); - } + // } else { + // requestAnimationFrame(() => this.resetResizingState({ shouldSkip: true })); + // } }) ).subscribe(); }); diff --git a/projects/ng-gallery/src/lib/services/resize-sensor.ts b/projects/ng-gallery/src/lib/services/resize-sensor.ts index c6ce0693..6295486c 100644 --- a/projects/ng-gallery/src/lib/services/resize-sensor.ts +++ b/projects/ng-gallery/src/lib/services/resize-sensor.ts @@ -27,7 +27,7 @@ import { SliderComponent } from '../components/slider/slider'; } }) export class ResizeSensor { - + // TODO: This directive is used in both slider and thumbs, maybe we can only observe the root element once private readonly sharedResizeObserver: SharedResizeObserver = inject(SharedResizeObserver) private readonly slider: SliderComponent = inject(SliderComponent, { self: true }); diff --git a/projects/ng-gallery/src/lib/styles/debug.scss b/projects/ng-gallery/src/lib/styles/debug.scss index d18dc3a0..fa17a6a6 100644 --- a/projects/ng-gallery/src/lib/styles/debug.scss +++ b/projects/ng-gallery/src/lib/styles/debug.scss @@ -2,7 +2,7 @@ ::ng-deep { .g-sliding, .g-resizing, .g-scrolling { gallery-item.g-item-highlight { - visibility: hidden; + //visibility: hidden; } } } @@ -28,7 +28,7 @@ } gallery-item { - outline: 1px solid darkorange; + //outline: 1px solid darkorange; &.g-item-highlight { &:after { diff --git a/projects/ng-gallery/src/lib/tests/common.ts b/projects/ng-gallery/src/lib/tests/common.ts index f5acea8f..6a49243c 100644 --- a/projects/ng-gallery/src/lib/tests/common.ts +++ b/projects/ng-gallery/src/lib/tests/common.ts @@ -1,11 +1,15 @@ import { Component, Signal, viewChild } from '@angular/core'; -import { GalleryComponent, GalleryItem, ImageItem } from 'ng-gallery'; +import { GalleryComponent, GalleryItem, GalleryItemDef, ImageItem, ImgRecognizer } from 'ng-gallery'; @Component({ standalone: true, - imports: [GalleryComponent], + imports: [GalleryComponent, GalleryItemDef, ImgRecognizer], template: ` - + + + ` }) export class TestComponent { diff --git a/projects/ng-gallery/src/lib/tests/resize-directive.spec.ts b/projects/ng-gallery/src/lib/tests/resize-directive.spec.ts index b368a600..a3e7493a 100644 --- a/projects/ng-gallery/src/lib/tests/resize-directive.spec.ts +++ b/projects/ng-gallery/src/lib/tests/resize-directive.spec.ts @@ -71,7 +71,7 @@ describe('Resize sensor directive', () => { }); it('should update the size signal when component size changes', async () => { - await afterTimeout(0); + await afterTimeout(16); expect(resizeSensorDirective.slideSize().width).toBe(500); expect(resizeSensorDirective.slideSize().height).toBe(300); expect(sliderComponent.nativeElement.style.getPropertyValue('--slider-width')).toBe('500px'); diff --git a/projects/ng-gallery/src/lib/utils/img-manager.ts b/projects/ng-gallery/src/lib/utils/img-manager.ts index a3fe55cc..175fbc87 100644 --- a/projects/ng-gallery/src/lib/utils/img-manager.ts +++ b/projects/ng-gallery/src/lib/utils/img-manager.ts @@ -1,7 +1,8 @@ import { inject, Injectable } from '@angular/core'; -import { Observable, BehaviorSubject, filter, map, switchMap, EMPTY } from 'rxjs'; +import { Observable, BehaviorSubject, filter, map, switchMap, EMPTY, merge, Subject, tap } from 'rxjs'; import { ItemState } from '../components/templates/items.model'; import { GalleryRef } from '../services/gallery-ref'; +import { toObservable } from '@angular/core/rxjs-interop'; interface ImageRegistry { state$: Observable; @@ -13,12 +14,14 @@ export class ImgManager { private readonly galleryRef: GalleryRef = inject(GalleryRef); - private readonly trigger$: BehaviorSubject = new BehaviorSubject(null); + private readonly trigger$: Subject = new Subject(); + + private readonly currIndex$ = toObservable(this.galleryRef.currIndex); private readonly images: Map = new Map(); getActiveItem(): Observable { - return this.trigger$.pipe( + return merge(this.currIndex$.pipe(tap((x) => console.log('index', x))), this.trigger$.pipe(tap(() => console.log('trigger!')))).pipe( switchMap(() => { const img: ImageRegistry = this.images.get(this.galleryRef.currIndex()); if (img) { diff --git a/projects/ng-gallery/src/lib/utils/img-recognizer.ts b/projects/ng-gallery/src/lib/utils/img-recognizer.ts index a0bf9331..0f5198b0 100644 --- a/projects/ng-gallery/src/lib/utils/img-recognizer.ts +++ b/projects/ng-gallery/src/lib/utils/img-recognizer.ts @@ -3,9 +3,7 @@ import { inject, effect, untracked, - input, ElementRef, - InputSignal, EffectCleanupRegisterFn } from '@angular/core'; import { ImgManager } from './img-manager'; @@ -15,6 +13,8 @@ import { SliderItem } from '../components/items/items'; standalone: true, selector: 'img[galleryImage]', host: { + '[class.g-image-item]': 'true', + // '[style.visibility]': 'item.state() === "success" ? "visible" : "hidden"', '(load)': 'item.state.set("success")', '(error)': 'item.state.set("failed")' } @@ -27,8 +27,6 @@ export class ImgRecognizer { readonly item: SliderItem = inject(SliderItem); - index: InputSignal = input(null, { alias: 'galleryImage' }); - constructor() { if (this.item) { // Mark the gallery-item component as an image item @@ -38,7 +36,7 @@ export class ImgRecognizer { } effect((onCleanup: EffectCleanupRegisterFn) => { - const index: number = this.index(); + const index: number = this.item.index(); untracked(() => { if (index != null) { diff --git a/projects/ng-gallery/src/public-api.ts b/projects/ng-gallery/src/public-api.ts index 2748ad46..83af4246 100644 --- a/projects/ng-gallery/src/public-api.ts +++ b/projects/ng-gallery/src/public-api.ts @@ -4,6 +4,7 @@ export * from './lib/components/gallery-nav.component'; export * from './lib/components/gallery-thumbs.component'; export * from './lib/components/gallery-bullets.component'; export * from './lib/components/gallery-counter.component'; +export * from './lib/utils/img-recognizer'; export * from './lib/components/gallery.component'; export * from './lib/components/templates/items.model'; export * from './lib/components/templates/gallery-iframe.component';