feat: add position configuration for pagination and navigation

This commit is contained in:
punitverma123 2025-05-19 14:46:02 +05:30
parent 6a3a30d59d
commit fe866cdd8e
10 changed files with 565 additions and 389 deletions

1
package-lock.json generated
View file

@ -18,6 +18,7 @@
"@wordpress/icons": "^10.14.0",
"@wordpress/media-utils": "^5.14.0",
"@wordpress/notices": "^5.17.0",
"clsx": "^2.1.1",
"swiper": "^11.1.14"
},
"devDependencies": {

View file

@ -30,6 +30,7 @@
"@wordpress/icons": "^10.14.0",
"@wordpress/media-utils": "^5.14.0",
"@wordpress/notices": "^5.17.0",
"clsx": "^2.1.1",
"swiper": "^11.1.14"
}
}

View file

@ -153,9 +153,15 @@
"navigationSize": {
"type": "string"
},
"navigationSpacing": {
"type": "object"
},
"navigationOffset": {
"type": "object"
},
"navigationPosition": {
"type": "string"
},
"navigationBorderRadius": {
"type": "string"
},
@ -165,6 +171,9 @@
"paginationOffset": {
"type": "object"
},
"paginationPosition": {
"type": "string"
},
"paginationColor": {
"type": "object",
"properties": {
@ -190,7 +199,10 @@
"supports": {
"anchor": true,
"html": false,
"align": [ "wide", "full" ],
"align": [
"wide",
"full"
],
"color": {
"gradients": true,
"link": true,
@ -202,7 +214,10 @@
}
},
"spacing": {
"margin": [ "top", "bottom" ],
"margin": [
"top",
"bottom"
],
"padding": true,
"__experimentalDefaultControls": {
"padding": true,
@ -219,7 +234,9 @@
}
}
},
"allowedBlocks": [ "blablablocks/slide" ],
"allowedBlocks": [
"blablablocks/slide"
],
"textdomain": "blablablocks-slider",
"editorScript": "file:./index.js",
"editorStyle": "file:./index.css",

File diff suppressed because it is too large Load diff

View file

@ -4,7 +4,7 @@
* Replace them with your own styles or remove the file completely.
*/

.slide_effects > .components-base-control {
.slide_effects>.components-base-control {
width: 100%;
}

@ -38,7 +38,7 @@
transform: rotate(-90deg);
}

.slider_color_popover .components-popover__content > div {
.slider_color_popover .components-popover__content>div {
margin: -8px;
width: 260px;
}
@ -99,3 +99,15 @@
.responsive_field_control .components-base-control__help {
margin-top: 2px;
}

.bbb-slider-navigation-position>div[role="row"]:nth-child(2)>span:not(:nth-child(2)) {
visibility: hidden;
}

.bbb-slider-pagination-position {
grid-template-rows: repeat(2, 1fr) !important;
}

.bbb-slider-pagination-position>div[role="row"]:nth-child(2) {
display: none;
}

View file

@ -149,7 +149,12 @@ $wrapper_attributes = get_block_wrapper_attributes(
<div <?php echo wp_kses_data($wrapper_attributes); ?> role="region" aria-roledescription="carousel" aria-label="Slider block">
<div class="swiper" <?php echo 'data-swiper="' . esc_attr(wp_json_encode($attributes)) . '"'; ?>>
<div class="swiper-wrapper">
<?php echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
<?php echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
?>
</div>
<div class="bbb-slider-nav-container">
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
</div>
</div>
</div>

View file

@ -1,6 +1,7 @@
/**
* Wordpress dependencies
*/
import clsx from 'clsx';
import { memo, useEffect, useRef } from '@wordpress/element';
import { useSelect, subscribe, select } from '@wordpress/data';
import {
@ -150,7 +151,7 @@ const Slider = memo(
} else if (attributes.autoplay) {
swiper.autoplay.start();
}
}, [ isAnySlideFocused, attributes ]);
}, [isAnySlideFocused, attributes]);

const navigationStyles = generateNavigationStyles(attributes);
const applyPadding = innerBlocks.length >= 2 ? '100px' : '';
@ -158,6 +159,10 @@ const Slider = memo(
return (
<div
{...useBlockProps({
className: clsx(
'bbb-slider-nav-position-' + (attributes.navigationPosition?.replace(/\s+/g, '-') ?? 'center'),
'bbb-slider-pag-position-' + (attributes.paginationPosition?.replace(/\s+/g, '-') ?? 'bottom-center')
),
role: 'region',
'aria-roledescription': 'carousel',
'aria-label': 'Slider block',
@ -166,6 +171,10 @@ const Slider = memo(
>
<div ref={swiperContainerRef}>
<div {...innerBlocksProps} />
<div className='bbb-slider-nav-container'>
<div className="swiper-button-prev"></div>
<div className="swiper-button-next"></div>
</div>
</div>
</div>
);

View file

@ -11,6 +11,81 @@
position: relative;
}

// Navigation Position
.bbb-slider-nav-position-top-left .bbb-slider-nav-container {
top: 0;
justify-content: flex-start;
}

.bbb-slider-nav-position-bottom-left .bbb-slider-nav-container {
top: auto;
bottom: 0;
justify-content: flex-start;
}

.bbb-slider-nav-position-top-right .bbb-slider-nav-container {
top: 0;
justify-content: flex-end;
}

.bbb-slider-nav-position-bottom-right .bbb-slider-nav-container {
top: auto;
bottom: 0;
justify-content: flex-end;
}

.bbb-slider-nav-position-top-center .bbb-slider-nav-container {
top: 0;
justify-content: center;
}

.bbb-slider-nav-position-bottom-center .bbb-slider-nav-container {
top: auto;
bottom: 0;
justify-content: center;
}

.bbb-slider-nav-position-center .bbb-slider-nav-container,
.bbb-slider-nav-position-center-center .bbb-slider-nav-container {
transform: translateY(-50%);
top: 50%;
justify-content: space-between;
}

// Pagination Position
.bbb-slider-pag-position-top-left .swiper-pagination {
top: 0;
justify-content: flex-start;
}

.bbb-slider-pag-position-bottom-left .swiper-pagination {
top: auto;
bottom: 0;
justify-content: flex-start;
}

.bbb-slider-pag-position-top-right .swiper-pagination {
top: 0;
justify-content: flex-end;
}

.bbb-slider-pag-position-bottom-right .swiper-pagination {
top: auto;
bottom: 0;
justify-content: flex-end;
}

.bbb-slider-pag-position-top-center .swiper-pagination {
top: 0;
justify-content: center;
}

.bbb-slider-pag-position-bottom-center .swiper-pagination {
top: auto;
bottom: 0;
justify-content: center;
}

.wp-block-blablablocks-slider .swiper {
position: initial;

@ -18,22 +93,30 @@
gap: 0;
}

.swiper-button-prev {
left: var(--navigation-offset-left);
}

.swiper-button-next {
right: var(--navigation-offset-right);
.bbb-slider-nav-container {
display: flex;
align-items: center;
width: 100%;
transform: translateX(-50%);
left: 50%;
gap: var(--navigation-spacing);
position: absolute;
margin-top: var(--navigation-offset-top);
margin-bottom: var(--navigation-offset-bottom);
margin-left: var(--navigation-offset-left);
margin-right: var(--navigation-offset-right);
z-index: 1000;
}

.swiper-button-prev,
.swiper-button-next {
position: relative;
left: 0;
right: 0;
color: var(--navigation-arrow-color, var(--swiper-theme-color));
background-color: var(--navigation-background-color);
border-radius: var(--navigation-border-radius);
padding: var(--navigation-padding-top) var(--navigation-padding-right) var(--navigation-padding-bottom) var(--navigation-padding-left);
top: var(--navigation-offset-top);
bottom: var(--navigation-offset-bottom);

&:hover {
color: var(--navigation-arrow-hover-color, var(--swiper-theme-color));
@ -42,10 +125,11 @@
}

.swiper-pagination {
top: var(--pagination-offset-top);
right: var(--pagination-offset-right);
bottom: var(--pagination-offset-bottom);
left: var(--pagination-offset-left);
margin-top: var(--pagination-offset-top);
margin-right: var(--pagination-offset-right);
margin-bottom: var(--pagination-offset-bottom);
margin-left: var(--pagination-offset-left);
display: flex;
}

.swiper-pagination-bullet {

View file

@ -20,7 +20,7 @@ import {
*
* @return {Object} Device-specific Swiper settings.
*/
function getDeviceSettings( options, deviceType, isFadeEffect ) {
function getDeviceSettings(options, deviceType, isFadeEffect, container) {
const defaultSettings = {
Desktop: { slidesPerView: 3, spaceBetween: 30 },
Tablet: { slidesPerView: 2, spaceBetween: 20 },
@ -28,22 +28,24 @@ function getDeviceSettings( options, deviceType, isFadeEffect ) {
};

const deviceSettings =
defaultSettings[ deviceType ] || defaultSettings.Desktop;
defaultSettings[deviceType] || defaultSettings.Desktop;

return {
slidesPerView: isFadeEffect
? 1
: options?.slidesPerView?.[ deviceType.toLowerCase() ] ??
: options?.slidesPerView?.[deviceType.toLowerCase()] ??
deviceSettings.slidesPerView,
spaceBetween:
options?.slidesSpacing?.[ deviceType.toLowerCase() ] ??
options?.slidesSpacing?.[deviceType.toLowerCase()] ??
deviceSettings.spaceBetween,
pagination: {
enabled: options?.pagination?.[ deviceType.toLowerCase() ] ?? false,
enabled: options?.pagination?.[deviceType.toLowerCase()] ?? false,
clickable: true,
},
navigation: {
enabled: options?.navigation?.[ deviceType.toLowerCase() ] ?? false,
enabled: options?.navigation?.[deviceType.toLowerCase()] ?? false,
nextEl: container.querySelector('.swiper-button-next'),
prevEl: container.querySelector('.swiper-button-prev'),
},
};
}
@ -68,7 +70,8 @@ export function SwiperInit(
const currentDeviceSettings = getDeviceSettings(
options,
deviceType,
isFadeEffect
isFadeEffect,
container
);

// Base Swiper parameters
@ -101,16 +104,20 @@ export function SwiperInit(
};

// Add breakpoints and universal settings if not in the editor
if ( ! isEditor ) {
if (!isEditor) {
parameters.pagination = { enabled: true, clickable: true };
parameters.navigation = { enabled: true };
parameters.navigation = {
enabled: true,
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
};
parameters.breakpoints = {
320: getDeviceSettings( options, 'Mobile', isFadeEffect ),
480: getDeviceSettings( options, 'Mobile', isFadeEffect ),
768: getDeviceSettings( options, 'Tablet', isFadeEffect ),
1024: getDeviceSettings( options, 'Desktop', isFadeEffect ),
320: getDeviceSettings(options, 'Mobile', isFadeEffect, container),
480: getDeviceSettings(options, 'Mobile', isFadeEffect, container),
768: getDeviceSettings(options, 'Tablet', isFadeEffect, container),
1024: getDeviceSettings(options, 'Desktop', isFadeEffect, container),
};
}

return new Swiper( container, parameters );
return new Swiper(container, parameters);
}

View file

@ -5,20 +5,20 @@
* @param {string|number} defaultValue - The default value.
* @return {string} - A valid CSS spacing size value.
*/
const resolveSpacingSizeValue = ( value, defaultValue = '0px' ) => {
if ( typeof value === 'string' ) {
if ( value.startsWith( 'var:' ) ) {
const resolveSpacingSizeValue = (value, defaultValue = '0px') => {
if (typeof value === 'string') {
if (value.startsWith('var:')) {
// Convert "var:some|value" into "var(--wp--some--value)"
const cssVariable = value
.replace( 'var:', '--wp--' )
.replace( /\|/g, '--' );
return `var(${ cssVariable })`;
.replace('var:', '--wp--')
.replace(/\|/g, '--');
return `var(${cssVariable})`;
}
return value; // If it's a valid CSS string, return as-is
}

if ( typeof value === 'number' ) {
return `${ value }px`; // Convert numbers to pixel values
if (typeof value === 'number') {
return `${value}px`; // Convert numbers to pixel values
}

// use defaultValue if value is invalid or undefined
@ -32,8 +32,8 @@ const resolveSpacingSizeValue = ( value, defaultValue = '0px' ) => {
* @param {string|number} defaultValue - The default value.
* @return {string} - A valid CSS border-radius value.
*/
const getBorderRadiusStyles = ( borderRadius, defaultValue = '0px' ) => {
if ( typeof borderRadius === 'string' ) {
const getBorderRadiusStyles = (borderRadius, defaultValue = '0px') => {
if (typeof borderRadius === 'string') {
return borderRadius;
}

@ -42,7 +42,7 @@ const getBorderRadiusStyles = ( borderRadius, defaultValue = '0px' ) => {
const topRight = borderRadius?.topRight || defaultValue;
const bottomRight = borderRadius?.bottomRight || defaultValue;
const bottomLeft = borderRadius?.bottomLeft || defaultValue;
return `${ topLeft } ${ topRight } ${ bottomRight } ${ bottomLeft }`;
return `${topLeft} ${topRight} ${bottomRight} ${bottomLeft}`;
};

/**
@ -53,110 +53,73 @@ const getBorderRadiusStyles = ( borderRadius, defaultValue = '0px' ) => {
*
* @return {Object} - An object with CSS variable definitions for the navigation.
*/
export const generateNavigationStyles = ( attributes = {} ) => {
export const generateNavigationStyles = (attributes = {}) => {
const styles = {};

// Helper function to add a style with a fallback to default values
const addStyle = ( key, value, defaultValue = '0px' ) => {
if ( value !== undefined && value !== null ) {
styles[ key ] = value;
} else if ( defaultValue ) {
styles[ key ] = defaultValue;
const addVar = (key, value, defaultValue = '0px') => {
if (value !== undefined && value !== null) {
styles[key] = value;
} else if (defaultValue) {
styles[key] = defaultValue;
}
};

addStyle(
addVar(
'--navigation-arrow-color',
attributes?.navigationColor?.arrowColor?.default,
'#000'
);
addStyle(
addVar(
'--navigation-background-color',
attributes?.navigationColor?.backgroundColor?.default,
'transparent'
);
addStyle(
addVar(
'--navigation-arrow-hover-color',
attributes?.navigationColor?.arrowColor?.hover,
'#333'
);
addStyle(
addVar(
'--navigation-background-hover-color',
attributes?.navigationColor?.backgroundColor?.hover,
'transparent'
);
addStyle( '--swiper-navigation-size', attributes?.navigationSize, '40px' );
addStyle(
addVar('--swiper-navigation-size', attributes?.navigationSize, '40px');
addVar(
'--navigation-border-radius',
getBorderRadiusStyles( attributes?.navigationBorderRadius, '4px' )
getBorderRadiusStyles(attributes?.navigationBorderRadius, '4px')
);

// Padding styles with defaults
addStyle(
'--navigation-padding-top',
resolveSpacingSizeValue( attributes?.navigationPadding?.top, '0px' )
);
addStyle(
'--navigation-padding-right',
resolveSpacingSizeValue( attributes?.navigationPadding?.right, '0px' )
);
addStyle(
'--navigation-padding-bottom',
resolveSpacingSizeValue( attributes?.navigationPadding?.bottom, '0px' )
);
addStyle(
'--navigation-padding-left',
resolveSpacingSizeValue( attributes?.navigationPadding?.left, '0px' )
);
['top', 'right', 'bottom', 'left'].forEach((dir) => {
addVar(`--navigation-padding-${dir}`, resolveSpacingSizeValue(attributes?.navigationPadding?.[dir], '0px'));
});

// Navigation offset styles with defaults
['top', 'right', 'bottom', 'left'].forEach((dir) => {
addVar(`--navigation-offset-${dir}`, resolveSpacingSizeValue(attributes?.navigationOffset?.[dir], '0px'));
});

addVar(`--navigation-spacing`, resolveSpacingSizeValue(attributes?.navigationSpacing?.left, '20px'));

// Pagination styles
addStyle( '--pagination-size', attributes?.paginationSize, '8px' );
addStyle(
addVar('--pagination-size', attributes?.paginationSize, '8px');
addVar(
'--pagination-active-color',
attributes?.paginationColor?.activeColor?.default,
'#000'
);
addStyle(
addVar(
'--pagination-inactive-color',
attributes?.paginationColor?.inactiveColor?.default,
'#ccc'
);

// Pagination offset styles with defaults
addStyle(
'--pagination-offset-top',
resolveSpacingSizeValue( attributes?.paginationOffset?.top, 'auto' )
);
addStyle(
'--pagination-offset-right',
resolveSpacingSizeValue( attributes?.paginationOffset?.right )
);
addStyle(
'--pagination-offset-bottom',
resolveSpacingSizeValue( attributes?.paginationOffset?.bottom, '8px' )
);
addStyle(
'--pagination-offset-left',
resolveSpacingSizeValue( attributes?.paginationOffset?.left )
);

// Navigation offset styles with defaults
addStyle(
'--navigation-offset-top',
resolveSpacingSizeValue( attributes?.navigationOffset?.top, '50%' )
);
addStyle(
'--navigation-offset-right',
resolveSpacingSizeValue( attributes?.navigationOffset?.right, '10px' )
);
addStyle(
'--navigation-offset-bottom',
resolveSpacingSizeValue( attributes?.navigationOffset?.bottom )
);
addStyle(
'--navigation-offset-left',
resolveSpacingSizeValue( attributes?.navigationOffset?.left, '10px' )
);
['top', 'right', 'bottom', 'left'].forEach((dir) => {
addVar(`--pagination-offset-${dir}`, resolveSpacingSizeValue(attributes?.paginationOffset?.[dir], dir === 'bottom' ? '8px' : 'auto'));
});

return styles;
};