feat: Add slide template picker and templates for carousel block#83
feat: Add slide template picker and templates for carousel block#83deepaklalwani97 wants to merge 4 commits intodevelopfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a two-step “first-run” setup experience for the Carousel block (slide count → template selection) and introduces a template registry that can be extended via a WordPress filter hook.
Changes:
- Added a slide template registry (
getSlideTemplates) with default templates (Blank, Image, Hero, Image + Caption, Query Loop) and a filter hook for extensibility. - Added a Template Picker UI component and editor styling for the picker.
- Updated Carousel block setup flow in
edit.tsxto support the two-step onboarding and initialize inner blocks based on the selected template.
Reviewed changes
Copilot reviewed 6 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
src/blocks/carousel/templates.ts |
Introduces default slide templates and exposes getSlideTemplates() via a filter hook. |
src/blocks/carousel/edit.tsx |
Implements the two-step setup flow and applies selected templates when initializing inner blocks. |
src/blocks/carousel/components/TemplatePicker.tsx |
Adds the template selection UI used during initial block setup. |
src/blocks/carousel/editor.scss |
Adds editor-only styling for the template picker grid and items. |
src/blocks/carousel/__tests__/templates.test.ts |
Adds unit coverage for template registry behavior and default template shapes. |
package.json |
Adds @wordpress/hooks as a direct dependency for the new filter-based extension point. |
package-lock.json |
Locks the updated @wordpress/hooks dependency version. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
… feature/79-slide-templates
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 7 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| :root { | ||
| // Border colors | ||
| --carousel-kit-border-default: #ddd; | ||
| --carousel-kit-border-dashed: #ccc; | ||
|
|
||
| // Background colors | ||
| --carousel-kit-bg-white: #fff; | ||
| --carousel-kit-bg-icon: #f0f0f0; | ||
|
|
||
| // Text colors | ||
| --carousel-kit-text-primary: #1e1e1e; | ||
| --carousel-kit-text-muted: #757575; | ||
|
|
||
| // Accent / interactive (falls back to WP admin theme color) | ||
| --carousel-kit-accent: var(--wp-admin-theme-color, #3858e9); | ||
| } |
There was a problem hiding this comment.
Defining these CSS custom properties on :root makes them global in the editor and can unintentionally affect other blocks/plugins (even if prefixed). Consider scoping them to the carousel wrapper (e.g., .carousel-kit / .editor-styles-wrapper .carousel-kit) so they only apply when the block is present.
| export function getSlideTemplates(): SlideTemplate[] { | ||
| const templates = applyFilters( | ||
| 'rtcamp.carouselKit.slideTemplates', | ||
| DEFAULT_TEMPLATES, | ||
| ); | ||
|
|
||
| if ( Array.isArray( templates ) ) { | ||
| return templates as SlideTemplate[]; | ||
| } |
There was a problem hiding this comment.
applyFilters receives DEFAULT_TEMPLATES by reference. Filter callbacks can accidentally mutate this array (e.g., templates.push(...)), which would permanently alter defaults for subsequent calls. Pass a shallow copy (and optionally validate/sanitize returned entries) before returning to keep defaults immutable and prevent malformed templates from breaking the picker.
| const [ emblaApi, setEmblaApi ] = useState<EmblaCarouselType | undefined>(); | ||
| const [ canScrollPrev, setCanScrollPrev ] = useState( false ); | ||
| const [ canScrollNext, setCanScrollNext ] = useState( false ); | ||
| const [ setupStep, setSetupStep ] = useState<SetupStep>( 'slide-count' ); | ||
| const [ pendingSlideCount, setPendingSlideCount ] = useState<number>( 0 ); | ||
|
|
There was a problem hiding this comment.
setupStep/pendingSlideCount are not reset after setup completes. If the user later deletes all inner blocks (making showSetup true again), the placeholder can reopen on the template step with a stale slide count and no direct Skip link. Consider resetting setup state when hasInnerBlocks transitions to false (e.g., in an effect keyed on showSetup).
| { setupStep === 'template' && ( | ||
| <TemplatePicker | ||
| templates={ getSlideTemplates() } | ||
| onSelect={ handleTemplateSelected } | ||
| onBack={ () => setSetupStep( 'slide-count' ) } | ||
| /> |
There was a problem hiding this comment.
getSlideTemplates() runs during render, which will re-run applyFilters on every re-render while the setup UI is shown. Consider memoizing the templates list (e.g., useMemo) or only computing it when entering the template step to avoid unnecessary work.
| expect( template.name.length ).toBeGreaterThan( 0 ); | ||
| expect( typeof template.label ).toBe( 'string' ); | ||
| expect( typeof template.description ).toBe( 'string' ); | ||
| expect( typeof template.icon ).toBe( 'object' ); |
There was a problem hiding this comment.
This assertion is brittle: IconType can be a string, function, or element depending on how icons are provided (especially for filtered/custom templates). Consider asserting the icon is defined (or is one of the allowed primitive types) rather than strictly typeof === 'object'.
| expect( typeof template.icon ).toBe( 'object' ); | |
| expect( template.icon ).toBeDefined(); | |
| expect( template.icon ).not.toBeNull(); | |
| expect( [ 'string', 'function', 'object' ] ).toContain( | |
| typeof template.icon, | |
| ); |

Summary
Adds a two-step setup flow to the Carousel block: users first pick a slide count, then choose a slide template (Blank, Image, Hero, Image + Caption, or Query Loop). Templates are extensible via the rtcamp.carouselKit.slideTemplates WordPress filter hook.
Type of change
Related issue(s)
Closes #79
What changed
Testing
Describe how this was tested.
Test details:
core/imageand acore/paragraphblock.Screenshots / recordings
Screen.Recording.2026-03-12.at.2.58.29.PM.mov
If applicable, add screenshots or short recordings.
Checklist