diff --git a/CHANGELOG.md b/CHANGELOG.md index a3ffcdf..bdf45e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## [1.0.3](https://github.com/rtCamp/carousel-system-interactivity-api/compare/v1.0.2...v1.0.3) (2026-02-24) + + +### Bug Fixes + +* enable loop on editor ([fe4566a](https://github.com/rtCamp/carousel-system-interactivity-api/commit/fe4566afcf72e1e663c7eb481a7957d62c2d3365)) +* state corruption when clicking between slides ([637e4a5](https://github.com/rtCamp/carousel-system-interactivity-api/commit/637e4a507eb2c58576c4004d5460e8aa7295db9f)) + ## [1.0.2](https://github.com/rtCamp/carousel-system-interactivity-api/compare/v1.0.1...v1.0.2) (2026-02-23) diff --git a/package-lock.json b/package-lock.json index ebb9365..36e1bdb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "carousel-kit", - "version": "1.0.2", + "version": "1.0.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "carousel-kit", - "version": "1.0.2", + "version": "1.0.3", "dependencies": { "@wordpress/babel-preset-default": "8.38.0", "@wordpress/block-editor": "^15.10.0", diff --git a/package.json b/package.json index b2561c0..9268bef 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "carousel-kit", - "version": "1.0.2", + "version": "1.0.3", "description": "Carousel block using Embla and WordPress Interactivity API", "author": "rtCamp", "private": true, diff --git a/src/blocks/carousel/edit.tsx b/src/blocks/carousel/edit.tsx index 98241e8..3b0d652 100644 --- a/src/blocks/carousel/edit.tsx +++ b/src/blocks/carousel/edit.tsx @@ -189,7 +189,7 @@ export default function Edit( { checked={ loop } onChange={ ( value ) => setAttributes( { loop: value } ) } help={ __( - 'Infinite scrolling of slides (Frontend only). Disabled in editor for stability.', + 'Enables infinite scrolling of slides.', 'carousel-kit', ) } /> diff --git a/src/blocks/carousel/viewport/edit.tsx b/src/blocks/carousel/viewport/edit.tsx index 309d022..8ff0563 100644 --- a/src/blocks/carousel/viewport/edit.tsx +++ b/src/blocks/carousel/viewport/edit.tsx @@ -93,22 +93,22 @@ export default function Edit( { return; } + const viewportEl = emblaRef.current; let embla: EmblaCarouselType | undefined; - let observer: MutationObserver | undefined; const initEmbla = () => { if ( embla ) { embla.destroy(); } - const queryLoopContainer = emblaRef.current?.querySelector( + const queryLoopContainer = viewportEl.querySelector( '.wp-block-post-template', ) as HTMLElement; // eslint-disable-next-line @typescript-eslint/no-explicit-any const options = carouselOptions as any; - embla = EmblaCarousel( emblaRef.current!, { + embla = EmblaCarousel( viewportEl, { loop: options?.loop ?? false, dragFree: options?.dragFree ?? false, containScroll: options?.containScroll || 'trimSnaps', @@ -117,9 +117,12 @@ export default function Edit( { direction: options?.direction || 'ltr', slidesToScroll: options?.slidesToScroll || 1, container: queryLoopContainer || undefined, + watchDrag: false, // Clicks in slide gaps must not trigger Embla scroll in the editor. + watchSlides: false, // Gutenberg injects block UI nodes into .embla__container; Embla's built-in MutationObserver would call reInit() on those, corrupting slide order and transforms. + watchResize: false, // Block toolbar appearing on selection can cause a layout shift that triggers an unwanted reInit. } ); - ( emblaRef.current as { [EMBLA_KEY]?: typeof embla } )[ EMBLA_KEY ] = embla; + ( viewportEl as { [EMBLA_KEY]?: typeof embla } )[ EMBLA_KEY ] = embla; const onSelect = () => { const canPrev = embla!.canScrollPrev(); @@ -140,42 +143,40 @@ export default function Edit( { initEmbla(); - if ( emblaRef.current ) { - observer = new MutationObserver( ( mutations ) => { - let shouldReInit = false; + const observer = new MutationObserver( ( mutations ) => { + let shouldReInit = false; - for ( const mutation of mutations ) { - const target = mutation.target as HTMLElement; + for ( const mutation of mutations ) { + const target = mutation.target as HTMLElement; - if ( target.classList.contains( 'wp-block-post-template' ) ) { - shouldReInit = true; - break; - } + if ( target.classList.contains( 'wp-block-post-template' ) ) { + shouldReInit = true; + break; + } - if ( - mutation.addedNodes.length > 0 && + if ( + mutation.addedNodes.length > 0 && ( target.querySelector( '.wp-block-post-template' ) || Array.from( mutation.addedNodes ).some( ( node ) => node instanceof HTMLElement && node.classList.contains( 'wp-block-post-template' ), ) ) - ) { - shouldReInit = true; - break; - } + ) { + shouldReInit = true; + break; } + } - if ( shouldReInit ) { - setTimeout( initEmbla, 10 ); - } - } ); + if ( shouldReInit ) { + setTimeout( initEmbla, 10 ); + } + } ); - observer.observe( emblaRef.current, { - childList: true, - subtree: true, - } ); - } + observer.observe( viewportEl, { + childList: true, + subtree: true, + } ); return () => { if ( embla ) { @@ -184,11 +185,7 @@ export default function Edit( { if ( observer ) { observer.disconnect(); } - if ( emblaRef.current ) { - delete ( emblaRef.current as { [EMBLA_KEY]?: typeof embla } )[ - EMBLA_KEY - ]; - } + delete ( viewportEl as { [EMBLA_KEY]?: typeof embla } )[ EMBLA_KEY ]; }; }, [ setEmblaApi, setCanScrollPrev, setCanScrollNext, carouselOptions ] );