Skip to content

feat: add Embla initialization hooks#145

Open
sunmorgn wants to merge 3 commits into
rtCamp:developfrom
sunmorgn:codex/embla-init-filters
Open

feat: add Embla initialization hooks#145
sunmorgn wants to merge 3 commits into
rtCamp:developfrom
sunmorgn:codex/embla-init-filters

Conversation

@sunmorgn
Copy link
Copy Markdown

@sunmorgn sunmorgn commented May 19, 2026

Summary

Adds stable JavaScript hooks around rtCarousel's Embla initialization so projects can adjust Embla options, append Embla plugins, and access the initialized Embla API for methods and events without forking the plugin.

Type of change

  • Bug fix
  • New feature
  • Enhancement/refactor
  • Documentation update
  • Test update
  • Build/CI/tooling

Related issue(s)

Closes #144

What changed

  • Added rtcamp.carouselKit.emblaOptions to filter the options passed to EmblaCarousel.
  • Added rtcamp.carouselKit.emblaPlugins to filter the Embla plugin array after the built-in Autoplay plugin is configured.
  • Added rtcamp.carouselKit.emblaInit so integrations can call Embla methods or subscribe to Embla events after initialization.
  • Added API documentation and unit test coverage for the extension hooks.

Breaking changes

Does this introduce a breaking change? If yes, describe the impact and migration path below.

  • Yes — migration path:
  • No

Testing

Describe how this was tested.

  • Unit tests
  • Manual testing - tested numerous previously unavailable options and all official and up-to-date third-party plugins.
  • Cross-browser testing (if UI changes)

Test details:

  • npm run lint:js
  • npm run lint:js:types
  • npm run test:js -- --runTestsByPath src/blocks/carousel/__tests__/view.test.ts
  • npm run build
  • Manually tested in a local WordPress install by adding site-level filters/actions for Embla options, plugins, methods, and events, including Auto Height, Auto Scroll, Class Names, Fade, Wheel Gestures, and A11y.

Screenshots / recordings

Not applicable; this change exposes developer extension hooks and does not alter saved markup or default carousel behavior.

Checklist

  • I have self-reviewed this PR
  • I have added/updated tests where needed
  • I have updated docs where needed
  • I have checked for breaking changes

@sunmorgn sunmorgn marked this pull request as ready for review May 19, 2026 17:16
@sunmorgn sunmorgn force-pushed the codex/embla-init-filters branch from 2d40494 to 1a0dd9c Compare May 19, 2026 17:28
@sunmorgn sunmorgn changed the title feat: add Embla initialization filters feat: add Embla initialization hooks May 19, 2026
@sunmorgn
Copy link
Copy Markdown
Author

Additional local manual test after adding rtcamp.carouselKit.emblaInit:

  • Updated a local WordPress test install to use the PR build.
  • Registered a site-level addAction( "rtcamp.carouselKit.emblaInit", ... ) listener from the active theme.
  • Confirmed the action fired for 15 carousel initializations on a page containing multiple carousel variants.
  • Confirmed the callback receives the Embla API instance plus the expected context object, and can call methods such as selectedScrollSnap(), canScrollPrev(), and canScrollNext().
  • No browser console errors were reported during the test.

@sunmorgn
Copy link
Copy Markdown
Author

Additional local test using WordPress block-style classes:

  • Switched the local theme integration from temporary has-embla-* classes to is-style-* block style classes.
  • Confirmed is-style-auto-height triggers the theme-level rtcamp.carouselKit.emblaPlugins filter and loads the autoHeight Embla plugin.
  • Confirmed the Auto Height carousel container updates height between slides (201px to 267px) after navigation.
  • Confirmed no old has-embla-* classes remain on the test page and no browser console errors were reported.

This keeps the PR API compatible with normal WordPress block style workflows.

@sunmorgn sunmorgn force-pushed the codex/embla-init-filters branch from a55530e to 1a0dd9c Compare May 20, 2026 21:22
Comment thread docs/API.md Outdated
);
```

Both filters receive the carousel context object as the third argument. `rtcamp.carouselKit.emblaPlugins` also receives the filtered options on `options`.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Contradicting statement: In @wordpress/hooks, the first argument passed to a filter callback is the filtered value (i.e. options or plugins).

applyFilters( 'hookName', content, arg1, arg2, moreArgs, finalArg )

The registered callback will receive filterContext as its second argument (not the third).
https://developer.wordpress.org/block-editor/reference-guides/packages/packages-hooks/

So the second argument received by the callback is not the "carousel context object", but rather a wrapper filterContext object containing the context property along with root, viewport, etc.

Suggested change
Both filters receive the carousel context object as the third argument. `rtcamp.carouselKit.emblaPlugins` also receives the filtered options on `options`.
Both filters receive the filter context object as the second argument of the callback. `rtcamp.carouselKit.emblaPlugins` also receives the filtered options on the `options` property of this object.

Comment thread src/blocks/carousel/view.ts Outdated
return value;
}

return applyFilters( hookName, value, filterContext ) as T;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return value is cast without runtime validation.

Suggested change
return applyFilters( hookName, value, filterContext ) as T;
const result = applyFilters( hookName, value, filterContext );
return ( result !== null && result !== undefined ) ? result as T : value;

Comment thread src/blocks/carousel/view.ts Outdated
{ ...filterContext, options: filteredOptions },
);

const embla = EmblaCarousel( viewport, filteredOptions, filteredPlugins );
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No guard on filteredPlugins being an array

Suggested change
const embla = EmblaCarousel( viewport, filteredOptions, filteredPlugins );
const safePlugins = Array.isArray( filteredPlugins ) ? filteredPlugins : plugins;
const embla = EmblaCarousel( viewport, filteredOptions, safePlugins );

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review. I’ve pushed an update addressing these points:

  • Corrected the API docs to describe the @wordpress/hooks filter callback arguments accurately.
  • Updated the filter wrapper so null/undefined results fall back to the original value.
  • Added a guard so rtcamp.carouselKit.emblaPlugins only passes an array to Embla, falling back to the original plugins otherwise.
  • Added regression tests for the defensive fallback cases.

Verified with:

  • npm run test:js -- src/blocks/carousel/__tests__/view.test.ts --runInBand
  • npm run lint:js:types
  • npm run lint:js
  • npm run test:js -- --runInBand
  • npm run build

milindmore22
milindmore22 previously approved these changes May 28, 2026
Copy link
Copy Markdown

@milindmore22 milindmore22 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the PR; this looks good to me. A great addition 👍🏼

@theMasudRana theMasudRana self-requested a review May 29, 2026 14:01
Copy link
Copy Markdown
Collaborator

@theMasudRana theMasudRana left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @sunmorgn,
Could we rename the new hook namespace from rtcamp.carouselKit.* to follow the current plugin convention, since the plugin has been renamed to rt-carousel?

For example, something like:

  • rtcamp.rtCarousel.emblaOptions
  • rtcamp.rtCarousel.emblaPlugins
  • rtcamp.rtCarousel.emblaInit

This would keep the extension API aligned with the current plugin branding and avoid carrying forward the old carouselKit name.

@sunmorgn
Copy link
Copy Markdown
Author

Thanks for catching that. I’ve pushed an update renaming the new Embla hooks to follow the current plugin namespace:

  • rtcamp.rtCarousel.emblaOptions
  • rtcamp.rtCarousel.emblaPlugins
  • rtcamp.rtCarousel.emblaInit

I updated the docs, source, and tests.

I left the existing rtcamp.carouselKit.slideTemplates hook alone because it appears to be pre-existing API outside this PR.

Verified with the JS tests, type check, lint, and build.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Enhancement]: Add filters for extending Embla Carousel options and plugins

3 participants