mirror of
https://ghproxy.net/https://github.com/lubusIN/blablablocks-slider-block.git
synced 2025-10-04 02:25:48 +08:00
update navigation & pagination to toolsPanel (#3)
* update navigation & pagination to toolsPanel * add resetAll for toolsPanel
This commit is contained in:
parent
974e4a112a
commit
1a61bc7214
4 changed files with 393 additions and 308 deletions
|
@ -15,82 +15,81 @@ import {
|
|||
} from '@wordpress/components';
|
||||
|
||||
/**
|
||||
* Render Color Picker
|
||||
* @param root0
|
||||
* @param root0.label
|
||||
* @param root0.colorValue
|
||||
* @param root0.onChangeColor
|
||||
* Renders a color control dropdown for selecting colors.
|
||||
*
|
||||
* @param {Object} props - The component props.
|
||||
* @param {string} props.label - The label for the color control.
|
||||
* @param {Object} props.colorValue - The current color values. Should include `default` and optionally `hover` (if `hasHover` is true).
|
||||
* @param {Function} props.onChangeColor - Callback function to handle color changes. Accepts an object with updated color values.
|
||||
* @param {boolean} props.hasHover - Determines if hover color support is enabled. If true, a tab for hover colors is displayed.
|
||||
*
|
||||
* @returns {JSX.Element} The rendered ColorControlDropdown component.
|
||||
*/
|
||||
function ColorControlDropdown( { label, colorValue = {}, onChangeColor } ) {
|
||||
const [ activeTab, setActiveTab ] = useState( 'default' );
|
||||
const hasHover = 'hover' in colorValue; // Determine if hover is provided
|
||||
function ColorControlDropdown({ label, colorValue = {}, onChangeColor, hasHover = false }) {
|
||||
const [activeTab, setActiveTab] = useState('default');
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
popoverProps={ {
|
||||
popoverProps={{
|
||||
placement: 'left-start',
|
||||
offset: 36,
|
||||
shift: true,
|
||||
} }
|
||||
}}
|
||||
contentClassName="slider_color_popover"
|
||||
renderToggle={ ( { isOpen, onToggle } ) => (
|
||||
renderToggle={({ isOpen, onToggle }) => (
|
||||
<Button
|
||||
className={ `slider_color_button ${
|
||||
isOpen ? 'isOpen' : ''
|
||||
}` }
|
||||
aria-expanded={ isOpen }
|
||||
onClick={ onToggle }
|
||||
className={`slider_color_button ${isOpen ? 'isOpen' : ''}`}
|
||||
aria-expanded={isOpen}
|
||||
onClick={onToggle}
|
||||
>
|
||||
<HStack justify="left">
|
||||
<ZStack offset={ 10 }>
|
||||
<ColorIndicator colorValue={ colorValue.default } />
|
||||
{ hasHover && (
|
||||
<ColorIndicator
|
||||
colorValue={ colorValue.hover }
|
||||
/>
|
||||
) }
|
||||
<ZStack offset={10}>
|
||||
<ColorIndicator colorValue={colorValue.default} />
|
||||
{hasHover && (
|
||||
<ColorIndicator colorValue={colorValue.hover} />
|
||||
)}
|
||||
</ZStack>
|
||||
<Text>{ label }</Text>
|
||||
<Text>{label}</Text>
|
||||
</HStack>
|
||||
</Button>
|
||||
) }
|
||||
renderContent={ () =>
|
||||
)}
|
||||
renderContent={() =>
|
||||
hasHover ? (
|
||||
<TabPanel
|
||||
onSelect={ ( tab ) => setActiveTab( tab ) }
|
||||
tabs={ [
|
||||
onSelect={(tab) => setActiveTab(tab)}
|
||||
tabs={[
|
||||
{
|
||||
name: 'default',
|
||||
title: __( 'Default', 'slider-block' ),
|
||||
title: __('Default', 'slider-block'),
|
||||
},
|
||||
{
|
||||
name: 'hover',
|
||||
title: __( 'Hover', 'slider-block' ),
|
||||
title: __('Hover', 'slider-block'),
|
||||
},
|
||||
] }
|
||||
]}
|
||||
>
|
||||
{ ( tab ) => (
|
||||
{(tab) => (
|
||||
<ColorPalette
|
||||
__experimentalIsRenderedInSidebar
|
||||
value={ colorValue[ tab.name ] || '' }
|
||||
onChange={ ( color ) => {
|
||||
onChangeColor( {
|
||||
value={colorValue[tab.name] || ''}
|
||||
onChange={(color) => {
|
||||
onChangeColor({
|
||||
...colorValue,
|
||||
[ tab.name ]: color,
|
||||
} );
|
||||
} }
|
||||
[tab.name]: color,
|
||||
});
|
||||
}}
|
||||
enableAlpha
|
||||
/>
|
||||
) }
|
||||
)}
|
||||
</TabPanel>
|
||||
) : (
|
||||
<ColorPalette
|
||||
className="ls-color-pallete-container"
|
||||
__experimentalIsRenderedInSidebar
|
||||
value={ colorValue.default || '' }
|
||||
onChange={ ( color ) => {
|
||||
onChangeColor( { ...colorValue, default: color } );
|
||||
} }
|
||||
value={colorValue.default || ''}
|
||||
onChange={(color) => {
|
||||
onChangeColor({ ...colorValue, default: color });
|
||||
}}
|
||||
enableAlpha
|
||||
/>
|
||||
)
|
||||
|
|
|
@ -122,16 +122,6 @@
|
|||
},
|
||||
"navigationColor": {
|
||||
"type": "object",
|
||||
"default": {
|
||||
"arrowColor": {
|
||||
"default": "",
|
||||
"hover": ""
|
||||
},
|
||||
"backgroundColor": {
|
||||
"default": "",
|
||||
"hover": ""
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"arrowColor": {
|
||||
"type": "object",
|
||||
|
@ -161,34 +151,19 @@
|
|||
"type": "object"
|
||||
},
|
||||
"navigationSize": {
|
||||
"type": "string",
|
||||
"default": "40px"
|
||||
"type": "string"
|
||||
},
|
||||
"navigationOffset": {
|
||||
"type": "object",
|
||||
"default": {
|
||||
"top": "50%",
|
||||
"bottom": "0px",
|
||||
"left": "10px",
|
||||
"right": "10px"
|
||||
}
|
||||
"type": "object"
|
||||
},
|
||||
"navigationBorderRadius": {
|
||||
"type": "string",
|
||||
"default": "4px"
|
||||
"type": "string"
|
||||
},
|
||||
"paginationSize": {
|
||||
"type": "string",
|
||||
"default": "8px"
|
||||
"type": "string"
|
||||
},
|
||||
"paginationOffset": {
|
||||
"type": "object",
|
||||
"default": {
|
||||
"top": "auto",
|
||||
"bottom": "8px",
|
||||
"left": "0px",
|
||||
"right": "0px"
|
||||
}
|
||||
"type": "object"
|
||||
},
|
||||
"paginationColor": {
|
||||
"type": "object",
|
||||
|
|
|
@ -23,6 +23,8 @@ import {
|
|||
ToolbarGroup,
|
||||
__experimentalVStack as VStack,
|
||||
__experimentalHeading as Heading,
|
||||
__experimentalToolsPanel as ToolsPanel,
|
||||
__experimentalToolsPanelItem as ToolsPanelItem,
|
||||
__experimentalToggleGroupControl as ToggleGroupControl,
|
||||
__experimentalToggleGroupControlOption as ToggleGroupControlOption,
|
||||
} from '@wordpress/components';
|
||||
|
@ -43,22 +45,22 @@ const DEFAULT_BLOCK = {
|
|||
/**
|
||||
* Slider component.
|
||||
*/
|
||||
const Slider = memo( ( { attributes, innerBlocksProps, innerBlocks } ) => {
|
||||
const Slider = memo(({ attributes, innerBlocksProps, innerBlocks }) => {
|
||||
const editorDeviceType = useSelect(
|
||||
( select ) => select( 'core/editor' ).getDeviceType(),
|
||||
(select) => select('core/editor').getDeviceType(),
|
||||
[]
|
||||
);
|
||||
const swiperContainerRef = useRef( null );
|
||||
const swiperInstanceRef = useRef( null );
|
||||
const swiperContainerRef = useRef(null);
|
||||
const swiperInstanceRef = useRef(null);
|
||||
|
||||
useEffect( () => {
|
||||
if ( swiperContainerRef.current && innerBlocks.length > 0 ) {
|
||||
useEffect(() => {
|
||||
if (swiperContainerRef.current && innerBlocks.length > 0) {
|
||||
// Clear existing Swiper classes
|
||||
swiperContainerRef.current.className = 'swiper';
|
||||
|
||||
// Destroy the existing Swiper instance, if any
|
||||
if ( swiperInstanceRef.current ) {
|
||||
swiperInstanceRef.current.destroy( true, true );
|
||||
if (swiperInstanceRef.current) {
|
||||
swiperInstanceRef.current.destroy(true, true);
|
||||
swiperInstanceRef.current = null;
|
||||
}
|
||||
|
||||
|
@ -75,28 +77,28 @@ const Slider = memo( ( { attributes, innerBlocksProps, innerBlocks } ) => {
|
|||
|
||||
// Cleanup on unmount
|
||||
return () => {
|
||||
if ( swiperInstanceRef.current ) {
|
||||
swiperInstanceRef.current.destroy( true, true );
|
||||
if (swiperInstanceRef.current) {
|
||||
swiperInstanceRef.current.destroy(true, true);
|
||||
}
|
||||
};
|
||||
}, [ editorDeviceType, attributes, innerBlocks.length ] );
|
||||
}, [editorDeviceType, attributes, innerBlocks.length]);
|
||||
|
||||
// Inline styles for navigation
|
||||
const navigationStyles = generateNavigationStyles( attributes );
|
||||
const navigationStyles = generateNavigationStyles(attributes);
|
||||
const applyPadding = innerBlocks.length >= 2 ? '100px' : '';
|
||||
|
||||
return (
|
||||
<div
|
||||
{ ...useBlockProps( {
|
||||
{...useBlockProps({
|
||||
style: { ...navigationStyles, padding: applyPadding },
|
||||
} ) }
|
||||
})}
|
||||
>
|
||||
<div ref={ swiperContainerRef }>
|
||||
<div { ...innerBlocksProps } />
|
||||
<div ref={swiperContainerRef}>
|
||||
<div {...innerBlocksProps} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} );
|
||||
});
|
||||
|
||||
/**
|
||||
* The edit function describes the structure of your block in the context of the
|
||||
|
@ -109,9 +111,9 @@ const Slider = memo( ( { attributes, innerBlocksProps, innerBlocks } ) => {
|
|||
*
|
||||
* @return {JSX.Element} The component rendering for the block editor.
|
||||
*/
|
||||
export default function Edit( { clientId, attributes, setAttributes } ) {
|
||||
export default function Edit({ clientId, attributes, setAttributes }) {
|
||||
const { allowedBlocks } = attributes;
|
||||
const { insertBlock } = useDispatch( blockEditorStore );
|
||||
const { insertBlock } = useDispatch(blockEditorStore);
|
||||
|
||||
const innerBlocksProps = useInnerBlocksProps(
|
||||
{ className: 'swiper-wrapper' },
|
||||
|
@ -125,409 +127,504 @@ export default function Edit( { clientId, attributes, setAttributes } ) {
|
|||
|
||||
// Check if inner blocks exist using useSelect
|
||||
const innerBlocks = useSelect(
|
||||
( select ) => select( blockEditorStore ).getBlocks( clientId ),
|
||||
[ clientId ]
|
||||
(select) => select(blockEditorStore).getBlocks(clientId),
|
||||
[clientId]
|
||||
);
|
||||
|
||||
const hasInnerBlocks = innerBlocks.length > 0;
|
||||
|
||||
const addSlide = () => {
|
||||
const block = createBlock( 'lubus/slide' );
|
||||
insertBlock( block, innerBlocks.length, clientId, false );
|
||||
const block = createBlock('lubus/slide');
|
||||
insertBlock(block, innerBlocks.length, clientId, false);
|
||||
};
|
||||
|
||||
return hasInnerBlocks ? (
|
||||
<>
|
||||
<Slider
|
||||
attributes={ attributes }
|
||||
innerBlocksProps={ innerBlocksProps }
|
||||
innerBlocks={ innerBlocks }
|
||||
attributes={attributes}
|
||||
innerBlocksProps={innerBlocksProps}
|
||||
innerBlocks={innerBlocks}
|
||||
/>
|
||||
<BlockControls>
|
||||
<ToolbarGroup>
|
||||
<ToolbarButton icon="plus" onClick={ addSlide }>
|
||||
{ __( 'Add Slide', 'slider-block' ) }
|
||||
<ToolbarButton icon="plus" onClick={addSlide}>
|
||||
{__('Add Slide', 'slider-block')}
|
||||
</ToolbarButton>
|
||||
</ToolbarGroup>
|
||||
</BlockControls>
|
||||
<InspectorControls>
|
||||
<PanelBody title={ __( 'Settings', 'slider-block' ) }>
|
||||
<VStack style={ { marginBottom: '8px' } }>
|
||||
<PanelBody title={__('Settings', 'slider-block')}>
|
||||
<VStack style={{ marginBottom: '8px' }}>
|
||||
<ResponsiveDropdown
|
||||
label="Slides Per View"
|
||||
attributes={ attributes }
|
||||
setAttributes={ setAttributes }
|
||||
attributes={attributes}
|
||||
setAttributes={setAttributes}
|
||||
responsiveKey="slidesPerView"
|
||||
/>
|
||||
<RangeControl
|
||||
__nextHasNoMarginBottom
|
||||
__next40pxDefaultSize
|
||||
help={ __(
|
||||
help={__(
|
||||
"Number of slides visible at the same time on slider's container.",
|
||||
'slider-block'
|
||||
) }
|
||||
)}
|
||||
value={
|
||||
attributes.slidesPerView[
|
||||
attributes.slidesPerView.activeDevice
|
||||
attributes.slidesPerView.activeDevice
|
||||
]
|
||||
}
|
||||
min={ 1 }
|
||||
max={ 30 }
|
||||
onChange={ ( value ) =>
|
||||
setAttributes( {
|
||||
min={1}
|
||||
max={30}
|
||||
onChange={(value) =>
|
||||
setAttributes({
|
||||
slidesPerView: {
|
||||
...attributes.slidesPerView,
|
||||
[ attributes.slidesPerView
|
||||
.activeDevice ]: value,
|
||||
[attributes.slidesPerView
|
||||
.activeDevice]: value,
|
||||
},
|
||||
} )
|
||||
})
|
||||
}
|
||||
/>
|
||||
</VStack>
|
||||
<VStack style={ { marginBottom: '16px' } }>
|
||||
<VStack style={{ marginBottom: '16px' }}>
|
||||
<ResponsiveDropdown
|
||||
label={ __( 'Slides Spacing', 'slider-block' ) }
|
||||
attributes={ attributes }
|
||||
setAttributes={ setAttributes }
|
||||
label={__('Slides Spacing', 'slider-block')}
|
||||
attributes={attributes}
|
||||
setAttributes={setAttributes}
|
||||
responsiveKey="slidesSpacing"
|
||||
/>
|
||||
<RangeControl
|
||||
__nextHasNoMarginBottom
|
||||
__next40pxDefaultSize
|
||||
help={ __(
|
||||
help={__(
|
||||
'Adjust the spacing between slides.',
|
||||
'slider-block'
|
||||
) }
|
||||
initialPosition={ 30 }
|
||||
)}
|
||||
initialPosition={30}
|
||||
value={
|
||||
attributes.slidesSpacing[
|
||||
attributes.slidesSpacing.activeDevice
|
||||
attributes.slidesSpacing.activeDevice
|
||||
]
|
||||
}
|
||||
min={ 0 }
|
||||
onChange={ ( value ) =>
|
||||
setAttributes( {
|
||||
min={0}
|
||||
onChange={(value) =>
|
||||
setAttributes({
|
||||
slidesSpacing: {
|
||||
...attributes.slidesSpacing,
|
||||
[ attributes.slidesSpacing
|
||||
.activeDevice ]: value,
|
||||
[attributes.slidesSpacing
|
||||
.activeDevice]: value,
|
||||
},
|
||||
} )
|
||||
})
|
||||
}
|
||||
/>
|
||||
</VStack>
|
||||
<RangeControl
|
||||
__nextHasNoMarginBottom
|
||||
__next40pxDefaultSize
|
||||
help={ __(
|
||||
help={__(
|
||||
'Set the duration of transition between slides.',
|
||||
'slider-block'
|
||||
) }
|
||||
label={ __( 'Speed (ms)', 'slider-block' ) }
|
||||
min={ 100 } // minimum speed in ms
|
||||
max={ 10000 } // maximum speed in ms
|
||||
step={ 100 }
|
||||
value={ attributes.speed }
|
||||
onChange={ ( value ) =>
|
||||
setAttributes( { speed: value } )
|
||||
)}
|
||||
label={__('Speed (ms)', 'slider-block')}
|
||||
min={100} // minimum speed in ms
|
||||
max={10000} // maximum speed in ms
|
||||
step={100}
|
||||
value={attributes.speed}
|
||||
onChange={(value) =>
|
||||
setAttributes({ speed: value })
|
||||
}
|
||||
/>
|
||||
<ToggleGroupControl
|
||||
isBlock
|
||||
__nextHasNoMarginBottom
|
||||
__next40pxDefaultSize
|
||||
label={ __( 'Effects', 'slider-block' ) }
|
||||
value={ attributes.effects }
|
||||
onChange={ ( value ) =>
|
||||
setAttributes( { effects: value } )
|
||||
label={__('Effects', 'slider-block')}
|
||||
value={attributes.effects}
|
||||
onChange={(value) =>
|
||||
setAttributes({ effects: value })
|
||||
}
|
||||
help={ __(
|
||||
help={__(
|
||||
'Select how slides transition.',
|
||||
'slider-block'
|
||||
) }
|
||||
)}
|
||||
>
|
||||
<ToggleGroupControlOption
|
||||
label={ __( 'Slide', 'slider-block' ) }
|
||||
label={__('Slide', 'slider-block')}
|
||||
value="slide"
|
||||
/>
|
||||
<ToggleGroupControlOption
|
||||
label={ __( 'Fade', 'slider-block' ) }
|
||||
label={__('Fade', 'slider-block')}
|
||||
value="fade"
|
||||
/>
|
||||
</ToggleGroupControl>
|
||||
<ToggleControl
|
||||
__nextHasNoMarginBottom
|
||||
className='responsive_field_control'
|
||||
help={ __(
|
||||
help={__(
|
||||
'Enable navigation arrows to manually move between slides.',
|
||||
'slider-block'
|
||||
) }
|
||||
)}
|
||||
checked={
|
||||
attributes.navigation[
|
||||
attributes.navigation.activeDevice
|
||||
attributes.navigation.activeDevice
|
||||
]
|
||||
}
|
||||
label={
|
||||
<ResponsiveDropdown
|
||||
label={ __( 'Navigation', 'slider-block' ) }
|
||||
attributes={ attributes }
|
||||
setAttributes={ setAttributes }
|
||||
label={__('Navigation', 'slider-block')}
|
||||
attributes={attributes}
|
||||
setAttributes={setAttributes}
|
||||
responsiveKey="navigation"
|
||||
/>
|
||||
}
|
||||
onChange={ ( value ) =>
|
||||
setAttributes( {
|
||||
onChange={(value) =>
|
||||
setAttributes({
|
||||
navigation: {
|
||||
...attributes.navigation,
|
||||
[ attributes.navigation.activeDevice ]:
|
||||
[attributes.navigation.activeDevice]:
|
||||
value,
|
||||
},
|
||||
} )
|
||||
})
|
||||
}
|
||||
/>
|
||||
<ToggleControl
|
||||
__nextHasNoMarginBottom
|
||||
className='responsive_field_control'
|
||||
help={ __(
|
||||
help={__(
|
||||
'Enable pagination indicators to show slide positions.',
|
||||
'slider-block'
|
||||
) }
|
||||
)}
|
||||
checked={
|
||||
attributes.pagination[
|
||||
attributes.pagination.activeDevice
|
||||
attributes.pagination.activeDevice
|
||||
]
|
||||
}
|
||||
label={
|
||||
<ResponsiveDropdown
|
||||
label={ __( 'Pagination', 'slider-block' ) }
|
||||
attributes={ attributes }
|
||||
setAttributes={ setAttributes }
|
||||
label={__('Pagination', 'slider-block')}
|
||||
attributes={attributes}
|
||||
setAttributes={setAttributes}
|
||||
responsiveKey="pagination"
|
||||
/>
|
||||
}
|
||||
onChange={ ( value ) =>
|
||||
setAttributes( {
|
||||
onChange={(value) =>
|
||||
setAttributes({
|
||||
pagination: {
|
||||
...attributes.pagination,
|
||||
[ attributes.pagination.activeDevice ]:
|
||||
[attributes.pagination.activeDevice]:
|
||||
value,
|
||||
},
|
||||
} )
|
||||
})
|
||||
}
|
||||
/>
|
||||
<ToggleControl
|
||||
__nextHasNoMarginBottom
|
||||
help={ __(
|
||||
help={__(
|
||||
'Enable loop to continuously cycle through slides.',
|
||||
'slider-block'
|
||||
) }
|
||||
checked={ attributes.loop }
|
||||
label={ __( 'Loop', 'slider-block' ) }
|
||||
onChange={ ( value ) =>
|
||||
setAttributes( { loop: value } )
|
||||
)}
|
||||
checked={attributes.loop}
|
||||
label={__('Loop', 'slider-block')}
|
||||
onChange={(value) =>
|
||||
setAttributes({ loop: value })
|
||||
}
|
||||
/>
|
||||
<ToggleControl
|
||||
__nextHasNoMarginBottom
|
||||
help={ __(
|
||||
help={__(
|
||||
'Enable automatic slide transition.',
|
||||
'slider-block'
|
||||
) }
|
||||
checked={ attributes.autoplay }
|
||||
label={ __( 'Autoplay', 'slider-block' ) }
|
||||
onChange={ ( value ) =>
|
||||
setAttributes( { autoplay: value } )
|
||||
)}
|
||||
checked={attributes.autoplay}
|
||||
label={__('Autoplay', 'slider-block')}
|
||||
onChange={(value) =>
|
||||
setAttributes({ autoplay: value })
|
||||
}
|
||||
/>
|
||||
{ attributes.autoplay && (
|
||||
{attributes.autoplay && (
|
||||
<RangeControl
|
||||
__nextHasNoMarginBottom
|
||||
__next40pxDefaultSize
|
||||
help={ __(
|
||||
help={__(
|
||||
'Set the delay between slides in milliseconds.',
|
||||
'slider-block'
|
||||
) }
|
||||
label={ __( 'Delay (ms)', 'slider-block' ) }
|
||||
min={ 100 } // minimum delay in ms
|
||||
max={ 10000 } // maximum delay in ms
|
||||
step={ 100 }
|
||||
value={ attributes.delay }
|
||||
onChange={ ( value ) =>
|
||||
setAttributes( { delay: value } )
|
||||
)}
|
||||
label={__('Delay (ms)', 'slider-block')}
|
||||
min={100} // minimum delay in ms
|
||||
max={10000} // maximum delay in ms
|
||||
step={100}
|
||||
value={attributes.delay}
|
||||
onChange={(value) =>
|
||||
setAttributes({ delay: value })
|
||||
}
|
||||
/>
|
||||
) }
|
||||
)}
|
||||
</PanelBody>
|
||||
</InspectorControls>
|
||||
<InspectorControls group="styles">
|
||||
<PanelBody
|
||||
title={ __( 'Navigation', 'slider-block' ) }
|
||||
initialOpen={ true }
|
||||
<ToolsPanel
|
||||
label={__('Navigation', 'slider-block')}
|
||||
resetAll={() =>
|
||||
setAttributes({
|
||||
navigationSize: undefined,
|
||||
navigationColor: {
|
||||
arrow: { default: undefined, hover: undefined },
|
||||
background: { default: undefined, hover: undefined },
|
||||
},
|
||||
navigationPadding: undefined,
|
||||
navigationOffset: undefined,
|
||||
navigationBorderRadius: undefined,
|
||||
})
|
||||
}
|
||||
>
|
||||
<VStack spacing={ 4 }>
|
||||
<ToolsPanelItem
|
||||
label={__('Size', 'slider-block')}
|
||||
isShownByDefault
|
||||
hasValue={() => !!attributes.navigationSize}
|
||||
onDeselect={() => setAttributes({ navigationSize: undefined })}
|
||||
>
|
||||
<FontSizePicker
|
||||
__next40pxDefaultSize
|
||||
withSlider
|
||||
withReset={ false }
|
||||
onChange={ ( size ) =>
|
||||
setAttributes( { navigationSize: size } )
|
||||
withReset={false}
|
||||
onChange={(size) =>
|
||||
setAttributes({ navigationSize: size })
|
||||
}
|
||||
value={ attributes.navigationSize }
|
||||
value={attributes.navigationSize}
|
||||
/>
|
||||
<VStack spacing={ 0 }>
|
||||
</ToolsPanelItem>
|
||||
<ToolsPanelItem
|
||||
label={__('Color', 'slider-block')}
|
||||
isShownByDefault
|
||||
hasValue={() =>
|
||||
!!attributes?.navigationColor?.arrowColor?.default ||
|
||||
!!attributes?.navigationColor?.arrowColor?.hover ||
|
||||
!!attributes?.navigationColor?.backgroundColor?.default ||
|
||||
!!attributes?.navigationColor?.backgroundColor?.hover
|
||||
}
|
||||
onDeselect={() =>
|
||||
setAttributes({
|
||||
navigationColor: {
|
||||
arrow: {
|
||||
default: undefined,
|
||||
hover: undefined,
|
||||
},
|
||||
background: {
|
||||
default: undefined,
|
||||
hover: undefined,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
>
|
||||
<VStack spacing={0}>
|
||||
<Heading
|
||||
lineHeight={ 1 }
|
||||
level={ 3 }
|
||||
weight={ 500 }
|
||||
lineHeight={1}
|
||||
level={3}
|
||||
weight={500}
|
||||
upperCase
|
||||
>
|
||||
Color
|
||||
</Heading>
|
||||
<VStack
|
||||
className="slider_color-support-panel"
|
||||
spacing={ 0 }
|
||||
spacing={0}
|
||||
>
|
||||
<ColorControlDropdown
|
||||
label={ __( 'Arrow', 'slider-block' ) }
|
||||
label={__('Arrow', 'slider-block')}
|
||||
colorValue={
|
||||
attributes?.navigationColor
|
||||
?.arrowColor || {}
|
||||
}
|
||||
onChangeColor={ ( newColor ) =>
|
||||
setAttributes( {
|
||||
onChangeColor={(newColor) =>
|
||||
setAttributes({
|
||||
navigationColor: {
|
||||
...attributes.navigationColor,
|
||||
arrowColor: newColor,
|
||||
},
|
||||
} )
|
||||
})
|
||||
}
|
||||
hasHover={true}
|
||||
/>
|
||||
<ColorControlDropdown
|
||||
label={ __( 'Background', 'slider-block' ) }
|
||||
label={__('Background', 'slider-block')}
|
||||
colorValue={
|
||||
attributes?.navigationColor
|
||||
?.backgroundColor || {}
|
||||
}
|
||||
onChangeColor={ ( newColor ) =>
|
||||
setAttributes( {
|
||||
onChangeColor={(newColor) =>
|
||||
setAttributes({
|
||||
navigationColor: {
|
||||
...attributes?.navigationColor,
|
||||
backgroundColor: newColor,
|
||||
},
|
||||
} )
|
||||
})
|
||||
}
|
||||
hasHover={true}
|
||||
/>
|
||||
</VStack>
|
||||
</VStack>
|
||||
</ToolsPanelItem>
|
||||
<ToolsPanelItem
|
||||
label={__('Padding', 'slider-block')}
|
||||
hasValue={() => !!attributes.navigationPadding}
|
||||
onDeselect={() => setAttributes({ navigationPadding: undefined })}
|
||||
>
|
||||
<SpacingSizesControl
|
||||
values={ attributes.navigationPadding }
|
||||
onChange={ ( value ) =>
|
||||
setAttributes( { navigationPadding: value } )
|
||||
values={attributes.navigationPadding}
|
||||
onChange={(value) =>
|
||||
setAttributes({ navigationPadding: value })
|
||||
}
|
||||
label={ __( 'Padding', 'slider-block' ) }
|
||||
allowReset={ false }
|
||||
splitOnAxis={ true }
|
||||
label={__('Padding', 'slider-block')}
|
||||
allowReset={false}
|
||||
splitOnAxis={true}
|
||||
/>
|
||||
</ToolsPanelItem>
|
||||
<ToolsPanelItem
|
||||
label={__('Offset', 'slider-block')}
|
||||
hasValue={() => !!attributes.navigationOffset}
|
||||
onDeselect={() => setAttributes({ navigationOffset: undefined })}
|
||||
>
|
||||
<SpacingSizesControl
|
||||
values={ attributes.navigationOffset }
|
||||
onChange={ ( value ) =>
|
||||
setAttributes( { navigationOffset: value } )
|
||||
values={attributes.navigationOffset}
|
||||
onChange={(value) =>
|
||||
setAttributes({ navigationOffset: value })
|
||||
}
|
||||
label={ __( 'Offset', 'slider-block' ) }
|
||||
minimumCustomValue={ -Infinity }
|
||||
allowReset={ false }
|
||||
splitOnAxis={ true }
|
||||
label={__('Offset', 'slider-block')}
|
||||
minimumCustomValue={-Infinity}
|
||||
allowReset={false}
|
||||
splitOnAxis={true}
|
||||
/>
|
||||
</ToolsPanelItem>
|
||||
<ToolsPanelItem
|
||||
label={__('Radius', 'slider-block')}
|
||||
hasValue={() => !!attributes.navigationBorderRadius}
|
||||
onDeselect={() => setAttributes({ navigationBorderRadius: undefined })}
|
||||
>
|
||||
<BorderRadiusControl
|
||||
values={ attributes.navigationBorderRadius }
|
||||
onChange={ ( value ) =>
|
||||
setAttributes( {
|
||||
values={attributes.navigationBorderRadius}
|
||||
onChange={(value) =>
|
||||
setAttributes({
|
||||
navigationBorderRadius: value,
|
||||
} )
|
||||
})
|
||||
}
|
||||
/>
|
||||
</VStack>
|
||||
</PanelBody>
|
||||
</ToolsPanelItem>
|
||||
</ToolsPanel>
|
||||
</InspectorControls>
|
||||
<InspectorControls group="styles">
|
||||
<PanelBody
|
||||
title={ __( 'Pagination', 'slider-block' ) }
|
||||
initialOpen={ true }
|
||||
<ToolsPanel
|
||||
label={__('Pagination', 'slider-block')}
|
||||
resetAll={() =>
|
||||
setAttributes({
|
||||
paginationSize: undefined,
|
||||
paginationColor: {
|
||||
activeColor: undefined,
|
||||
inactiveColor: undefined,
|
||||
},
|
||||
paginationOffset: undefined,
|
||||
})
|
||||
}
|
||||
>
|
||||
<VStack spacing={ 4 }>
|
||||
<ToolsPanelItem
|
||||
label={__('Size', 'slider-block')}
|
||||
isShownByDefault
|
||||
hasValue={() => !!attributes.paginationSize}
|
||||
onDeselect={() => setAttributes({ paginationSize: undefined })}
|
||||
>
|
||||
<FontSizePicker
|
||||
__next40pxDefaultSize
|
||||
withSlider
|
||||
withReset={ false }
|
||||
onChange={ ( size ) =>
|
||||
setAttributes( { paginationSize: size } )
|
||||
withReset={false}
|
||||
onChange={(size) =>
|
||||
setAttributes({ paginationSize: size })
|
||||
}
|
||||
value={ attributes.paginationSize }
|
||||
value={attributes.paginationSize}
|
||||
/>
|
||||
<VStack spacing={ 0 }>
|
||||
</ToolsPanelItem>
|
||||
<ToolsPanelItem
|
||||
label={__('Color', 'slider-block')}
|
||||
isShownByDefault
|
||||
hasValue={() => !!attributes?.paginationColor?.activeColor || !!attributes?.paginationColor?.inactiveColor}
|
||||
onDeselect={() =>
|
||||
setAttributes({
|
||||
paginationColor: {
|
||||
activeColor: undefined,
|
||||
inactiveColor: undefined,
|
||||
},
|
||||
})
|
||||
}
|
||||
>
|
||||
<VStack spacing={0}>
|
||||
<Heading
|
||||
lineHeight={ 1 }
|
||||
level={ 3 }
|
||||
weight={ 500 }
|
||||
lineHeight={1}
|
||||
level={3}
|
||||
weight={500}
|
||||
upperCase
|
||||
>
|
||||
Color
|
||||
</Heading>
|
||||
<VStack
|
||||
className="slider_color-support-panel"
|
||||
spacing={ 0 }
|
||||
spacing={0}
|
||||
>
|
||||
<ColorControlDropdown
|
||||
label={ __( 'Active', 'slider-block' ) }
|
||||
label={__('Active', 'slider-block')}
|
||||
colorValue={
|
||||
attributes?.paginationColor
|
||||
?.activeColor || {}
|
||||
}
|
||||
onChangeColor={ ( newColor ) =>
|
||||
setAttributes( {
|
||||
onChangeColor={(newColor) =>
|
||||
setAttributes({
|
||||
paginationColor: {
|
||||
...attributes.paginationColor,
|
||||
activeColor: newColor,
|
||||
},
|
||||
} )
|
||||
})
|
||||
}
|
||||
/>
|
||||
<ColorControlDropdown
|
||||
label={ __( 'Inactive', 'slider-block' ) }
|
||||
label={__('Inactive', 'slider-block')}
|
||||
colorValue={
|
||||
attributes?.paginationColor
|
||||
?.inactiveColor || {}
|
||||
}
|
||||
onChangeColor={ ( newColor ) =>
|
||||
setAttributes( {
|
||||
onChangeColor={(newColor) =>
|
||||
setAttributes({
|
||||
paginationColor: {
|
||||
...attributes?.paginationColor,
|
||||
inactiveColor: newColor,
|
||||
},
|
||||
} )
|
||||
})
|
||||
}
|
||||
/>
|
||||
</VStack>
|
||||
</VStack>
|
||||
</ToolsPanelItem>
|
||||
<ToolsPanelItem
|
||||
label={__('Offset', 'slider-block')}
|
||||
hasValue={() => !!attributes.paginationOffset}
|
||||
onDeselect={() => setAttributes({ paginationOffset: undefined })}
|
||||
>
|
||||
<SpacingSizesControl
|
||||
values={ attributes.paginationOffset }
|
||||
onChange={ ( value ) =>
|
||||
setAttributes( { paginationOffset: value } )
|
||||
values={attributes.paginationOffset}
|
||||
onChange={(value) =>
|
||||
setAttributes({ paginationOffset: value })
|
||||
}
|
||||
label={ __( 'Offset', 'slider-block' ) }
|
||||
minimumCustomValue={ -Infinity }
|
||||
allowReset={ false }
|
||||
splitOnAxis={ true }
|
||||
label={__('Offset', 'slider-block')}
|
||||
minimumCustomValue={-Infinity}
|
||||
allowReset={false}
|
||||
splitOnAxis={true}
|
||||
/>
|
||||
</VStack>
|
||||
</PanelBody>
|
||||
</ToolsPanelItem>
|
||||
</ToolsPanel>
|
||||
</InspectorControls>
|
||||
</>
|
||||
) : (
|
||||
<Placeholder
|
||||
clientId={ clientId }
|
||||
attributes={ attributes }
|
||||
setAttributes={ setAttributes }
|
||||
clientId={clientId}
|
||||
attributes={attributes}
|
||||
setAttributes={setAttributes}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,45 +2,47 @@
|
|||
* Resolves a spacing size value into a usable CSS value.
|
||||
*
|
||||
* @param {string|number} value - The input spacing size value.
|
||||
* @param {string|number} defaultValue - The default value.
|
||||
* @return {string} - A valid CSS spacing size value.
|
||||
*/
|
||||
const resolveSpacingSizeValue = ( value ) => {
|
||||
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
|
||||
}
|
||||
|
||||
// Fallback to '0px' if value is invalid or undefined
|
||||
return '0px';
|
||||
// use defaultValue if value is invalid or undefined
|
||||
return defaultValue;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a border-radius string from either a string or an object.
|
||||
*
|
||||
* @param {string|object} borderRadius - The border radius definition.
|
||||
* @param {string|number} defaultValue - The default value.
|
||||
* @return {string} - A valid CSS border-radius value.
|
||||
*/
|
||||
const getBorderRadiusStyles = ( borderRadius ) => {
|
||||
if ( typeof borderRadius === 'string' ) {
|
||||
const getBorderRadiusStyles = (borderRadius, defaultValue = '0px') => {
|
||||
if (typeof borderRadius === 'string') {
|
||||
return borderRadius;
|
||||
}
|
||||
|
||||
// If it's an object, return a four-value shorthand for border-radius
|
||||
const topLeft = borderRadius?.topLeft || '0px';
|
||||
const topRight = borderRadius?.topRight || '0px';
|
||||
const bottomRight = borderRadius?.bottomRight || '0px';
|
||||
const bottomLeft = borderRadius?.bottomLeft || '0px';
|
||||
return `${ topLeft } ${ topRight } ${ bottomRight } ${ bottomLeft }`;
|
||||
const topLeft = borderRadius?.topLeft || defaultValue;
|
||||
const topRight = borderRadius?.topRight || defaultValue;
|
||||
const bottomRight = borderRadius?.bottomRight || defaultValue;
|
||||
const bottomLeft = borderRadius?.bottomLeft || defaultValue;
|
||||
return `${topLeft} ${topRight} ${bottomRight} ${bottomLeft}`;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -51,101 +53,113 @@ const getBorderRadiusStyles = ( borderRadius ) => {
|
|||
*
|
||||
* @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 only if the value is valid
|
||||
const addStyle = ( key, value ) => {
|
||||
if ( value ) {
|
||||
styles[ key ] = value;
|
||||
// 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;
|
||||
}
|
||||
};
|
||||
|
||||
addStyle(
|
||||
'--navigation-arrow-color',
|
||||
attributes?.navigationColor?.arrowColor?.default
|
||||
attributes?.navigationColor?.arrowColor?.default,
|
||||
'#000'
|
||||
);
|
||||
addStyle(
|
||||
'--navigation-background-color',
|
||||
attributes?.navigationColor?.backgroundColor?.default
|
||||
attributes?.navigationColor?.backgroundColor?.default,
|
||||
'transparent'
|
||||
);
|
||||
addStyle(
|
||||
'--navigation-arrow-hover-color',
|
||||
attributes?.navigationColor?.arrowColor?.hover
|
||||
attributes?.navigationColor?.arrowColor?.hover,
|
||||
'#333'
|
||||
);
|
||||
addStyle(
|
||||
'--navigation-background-hover-color',
|
||||
attributes?.navigationColor?.backgroundColor?.hover
|
||||
attributes?.navigationColor?.backgroundColor?.hover,
|
||||
'transparent'
|
||||
);
|
||||
addStyle(
|
||||
'--swiper-navigation-size',
|
||||
attributes?.navigationSize,
|
||||
'40px'
|
||||
);
|
||||
addStyle( '--swiper-navigation-size', attributes?.navigationSize );
|
||||
addStyle(
|
||||
'--navigation-border-radius',
|
||||
getBorderRadiusStyles( attributes?.navigationBorderRadius )
|
||||
getBorderRadiusStyles(attributes?.navigationBorderRadius, '4px'),
|
||||
);
|
||||
|
||||
// Padding styles
|
||||
// Padding styles with defaults
|
||||
addStyle(
|
||||
'--navigation-padding-top',
|
||||
resolveSpacingSizeValue( attributes?.navigationPadding?.top )
|
||||
resolveSpacingSizeValue(attributes?.navigationPadding?.top, '10px')
|
||||
);
|
||||
addStyle(
|
||||
'--navigation-padding-right',
|
||||
resolveSpacingSizeValue( attributes?.navigationPadding?.right )
|
||||
resolveSpacingSizeValue(attributes?.navigationPadding?.right, '10px')
|
||||
);
|
||||
addStyle(
|
||||
'--navigation-padding-bottom',
|
||||
resolveSpacingSizeValue( attributes?.navigationPadding?.bottom )
|
||||
resolveSpacingSizeValue(attributes?.navigationPadding?.bottom, '10px')
|
||||
);
|
||||
addStyle(
|
||||
'--navigation-padding-left',
|
||||
resolveSpacingSizeValue( attributes?.navigationPadding?.left )
|
||||
resolveSpacingSizeValue(attributes?.navigationPadding?.left, '10px')
|
||||
);
|
||||
|
||||
// Pagination styles
|
||||
addStyle( '--pagination-size', attributes?.paginationSize );
|
||||
addStyle('--pagination-size', attributes?.paginationSize, '8px');
|
||||
addStyle(
|
||||
'--pagination-active-color',
|
||||
attributes?.paginationColor?.activeColor?.default
|
||||
attributes?.paginationColor?.activeColor?.default,
|
||||
'#000'
|
||||
);
|
||||
addStyle(
|
||||
'--pagination-inactive-color',
|
||||
attributes?.paginationColor?.inactiveColor?.default
|
||||
attributes?.paginationColor?.inactiveColor?.default,
|
||||
'#ccc'
|
||||
);
|
||||
|
||||
// Pagination offset styles
|
||||
// Pagination offset styles with defaults
|
||||
addStyle(
|
||||
'--pagination-offset-top',
|
||||
resolveSpacingSizeValue( attributes?.paginationOffset?.top )
|
||||
resolveSpacingSizeValue(attributes?.paginationOffset?.top, 'auto')
|
||||
);
|
||||
addStyle(
|
||||
'--pagination-offset-right',
|
||||
resolveSpacingSizeValue( attributes?.paginationOffset?.right )
|
||||
resolveSpacingSizeValue(attributes?.paginationOffset?.right)
|
||||
);
|
||||
addStyle(
|
||||
'--pagination-offset-bottom',
|
||||
resolveSpacingSizeValue( attributes?.paginationOffset?.bottom )
|
||||
resolveSpacingSizeValue(attributes?.paginationOffset?.bottom, '8px')
|
||||
);
|
||||
addStyle(
|
||||
'--pagination-offset-left',
|
||||
resolveSpacingSizeValue( attributes?.paginationOffset?.left )
|
||||
resolveSpacingSizeValue(attributes?.paginationOffset?.left)
|
||||
);
|
||||
|
||||
// Navigation offset styles
|
||||
// Navigation offset styles with defaults
|
||||
addStyle(
|
||||
'--navigation-offset-top',
|
||||
resolveSpacingSizeValue( attributes?.navigationOffset?.top )
|
||||
resolveSpacingSizeValue(attributes?.navigationOffset?.top, '50%')
|
||||
);
|
||||
addStyle(
|
||||
'--navigation-offset-right',
|
||||
resolveSpacingSizeValue( attributes?.navigationOffset?.right )
|
||||
resolveSpacingSizeValue(attributes?.navigationOffset?.right, '10px')
|
||||
);
|
||||
addStyle(
|
||||
'--navigation-offset-bottom',
|
||||
resolveSpacingSizeValue( attributes?.navigationOffset?.bottom )
|
||||
resolveSpacingSizeValue(attributes?.navigationOffset?.bottom)
|
||||
);
|
||||
addStyle(
|
||||
'--navigation-offset-left',
|
||||
resolveSpacingSizeValue( attributes?.navigationOffset?.left )
|
||||
resolveSpacingSizeValue(attributes?.navigationOffset?.left, '10px')
|
||||
);
|
||||
|
||||
return styles;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue