feat: add Content Slider block#2872
Conversation
Bundle Size Diff
|
|
Plugin build for fea13af is ready 🛎️!
|
E2E TestsPlaywright Test Status: See serial and parallel matrix jobs Performance ResultsserverResponse: {"q25":462.2,"q50":474.95,"q75":492.7,"cnt":10}, firstPaint: {"q25":538.4,"q50":611.2,"q75":669.1,"cnt":10}, domContentLoaded: {"q25":3343.2,"q50":3401.45,"q75":3426.7,"cnt":10}, loaded: {"q25":3345.1,"q50":3403.35,"q75":3428.9,"cnt":10}, firstContentfulPaint: {"q25":3883,"q50":3952.05,"q75":3974.8,"cnt":10}, firstBlock: {"q25":13396,"q50":13484.6,"q75":13554.9,"cnt":10}, type: {"q25":22.57,"q50":23.88,"q75":25.45,"cnt":10}, typeWithoutInspector: {"q25":19.24,"q50":22.4,"q75":31.16,"cnt":10}, typeWithTopToolbar: {"q25":28.37,"q50":29.07,"q75":29.93,"cnt":10}, typeContainer: {"q25":12.21,"q50":12.63,"q75":13.35,"cnt":10}, focus: {"q25":101.63,"q50":103.55,"q75":107.14,"cnt":10}, inserterOpen: {"q25":35.36,"q50":35.86,"q75":36.4,"cnt":10}, inserterSearch: {"q25":11.89,"q50":11.99,"q75":12.47,"cnt":10}, inserterHover: {"q25":4.53,"q50":4.68,"q75":4.97,"cnt":20}, loadPatterns: {"q25":1466.23,"q50":1547.41,"q75":1673.57,"cnt":10}, listViewOpen: {"q25":210.13,"q50":214.21,"q75":218.13,"cnt":10} |
Add `themeisle-blocks/content-slider`, an InnerBlocks-based slider where each direct child block is a slide, so slides can hold any content (text, images, buttons, Atomic Wind layouts) rather than just images like the Image Slider. - Static save; raw inner blocks are the slides, sized via CSS scroll-snap. - Thin (~2KB) frontend script for arrows, dots, autoplay (hover/focus pause, reduced-motion aware), keyboard nav and soft-wrap loop — no carousel library. - Editor shows one slide at a time with toolbar prev/next + add-slide; default template demos image+caption group slides. - Chrome (arrows/dots) styled via scoped CSS variables and :where() so it never competes with slide content; structural CSS only on the track. - Conditional frontend enqueue wired through class-registration. - e2e coverage for editor nav, frontend nav, loop, autoplay, reduced-motion, chrome toggles and color variables. - Disable themeisle-sdk survey/tracking scripts in the e2e env to keep the console clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Insert advanced-heading, button-group/button and accordion blocks as slides and assert each renders inside the track on the frontend. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a slide mixing core blocks (heading, image, list, quote, buttons), a content-heavy slide (10+ paragraphs, an 8-item list, 3 columns, a quote), and a slide combining core and Otter blocks; assert all render inside the track. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4693e5e to
9a69c0b
Compare
There was a problem hiding this comment.
Pull request overview
This PR introduces a new Content Slider Gutenberg block to Otter Blocks: a lightweight, scroll-snap–based carousel where each inner block becomes a slide, with optional arrows/dots and autoplay.
Changes:
- Added the
themeisle-blocks/content-sliderblock (editor UI, inspector controls, save markup, styles, and shared chrome styling). - Added a dedicated frontend script entry to wire navigation (arrows/dots), autoplay, keyboard navigation, and loop behavior.
- Added Playwright E2E coverage for editor behavior and frontend rendering/interaction, plus an E2E bootstrap tweak to reduce unrelated console noise.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| webpack.config.js | Adds a new webpack entrypoint for the content slider frontend script bundle. |
| blocks.json | Registers build inputs for the new block’s editor and frontend styles. |
| inc/class-registration.php | Registers the frontend script + localized strings when the block is present. |
| src/blocks/blocks/index.js | Registers the new block in the editor bundle import list. |
| src/blocks/blocks/content-slider/block.json | Declares block metadata, attributes, and asset handles. |
| src/blocks/blocks/content-slider/index.js | Registers the block type (title/description/icon/keywords) and binds edit/save. |
| src/blocks/blocks/content-slider/edit.js | Implements editor experience (single-slide view, toolbar navigation, add-slide, dots/arrows). |
| src/blocks/blocks/content-slider/inspector.js | Adds inspector controls for slides-per-view, gap, height, loop, autoplay, and colors. |
| src/blocks/blocks/content-slider/save.js | Outputs frontend markup, data attributes, CSS variables, and accessibility attributes. |
| src/blocks/blocks/content-slider/style.scss | Implements scroll-snap track layout for the frontend. |
| src/blocks/blocks/content-slider/editor.scss | Editor-only styling for the track and slide wrappers. |
| src/blocks/blocks/content-slider/_chrome.scss | Shared “chrome” styling for arrows/dots with low specificity. |
| src/blocks/blocks/content-slider/components/icons.js | Adds the shared arrow SVG icon component. |
| src/blocks/frontend/content-slider/index.js | Frontend initialization: dots creation, arrows, scroll-sync, autoplay, keyboard, loop. |
| src/blocks/test/e2e/blocks/content-slider.spec.js | Adds E2E tests for block insertion, editor navigation, frontend behavior, and accessibility semantics. |
| packages/e2e-tests/mu-plugins/otter-e2e-bootstrap.php | Disables ThemeIsle SDK survey/tracking scripts in E2E to avoid unrelated console errors. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const dot = document.createElement( 'button' ); | ||
| dot.type = 'button'; | ||
| dot.className = 'o-content-dot'; | ||
| dot.setAttribute( 'aria-label', goToSlideLabel.replace( '%d', i + 1 ) ); | ||
| dot.addEventListener( 'click', () => goTo( i ) ); | ||
| dotsContainer.appendChild( dot ); |
| slider.addEventListener( 'keydown', ( event ) => { | ||
| if ( 'ArrowLeft' === event.key ) { | ||
| event.preventDefault(); | ||
| goTo( current - 1 ); | ||
| } else if ( 'ArrowRight' === event.key ) { | ||
| event.preventDefault(); | ||
| goTo( current + 1 ); | ||
| } | ||
| }); |
|
@Soare-Robert-Daniel, The Content Slider block works fine with most of the blocks. However, when a Form block is placed inside it — form submissions do not work.
|
The slider keydown handler claimed ArrowLeft/ArrowRight unconditionally, breaking caret movement for interactive inner blocks (form inputs, textareas, selects, contenteditable) used as slides. Skip navigation when focus is inside such an element. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
I could not replicate this. The |

Closes https://github.com/Codeinwp/otter-internals/issues/272
Summary
Screenshots
Test instructions
Checklist before the final review