-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathinner-block-slider-controlled.js
More file actions
139 lines (123 loc) · 4.47 KB
/
inner-block-slider-controlled.js
File metadata and controls
139 lines (123 loc) · 4.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import PropTypes from 'prop-types';
import { useRef, useEffect } from 'react';
import { createBlock } from '@wordpress/blocks';
import { useSelect, useDispatch } from '@wordpress/data';
import InnerBlocksDisplaySingle from './inner-block-single-display';
import Navigation from './navigation';
/**
* InnerBlockSlider component.
*
* @param {object} props Component props.
* @param {string} props.parentBlockId Parent block clientId.
* @param {string} props.allowedBlock Allowed block type.
* @param {Array} props.template Initial block template.
* @param {number} props.slideLimit Maximum allowed slides.
* @param {number} props.currentItemIndex Override current index, if managing this externally.
* @param {Function} props.setCurrentItemIndex Override set item Index
* @param {Function} props.showNavigation Override display nav
* @param {number} props.perPage Number of items to display per page.
* @returns {React.ReactNode} Component.
*/
const InnerBlockSliderControlled = ( {
parentBlockId,
allowedBlock,
template,
slideLimit = 10,
currentItemIndex,
setCurrentItemIndex,
showNavigation = true,
perPage = 1,
} ) => {
const innerBlockTemplate = template || [ [ allowedBlock ] ];
const {
slideBlocks,
selectedBlockId,
getLowestCommonAncestorWithSelectedBlock,
} = useSelect(
( select ) => {
const blockEditorStore = select( 'core/block-editor' );
return {
slideBlocks: blockEditorStore.getBlock( parentBlockId ).innerBlocks,
selectedBlockId: blockEditorStore.getSelectedBlockClientId(),
getLowestCommonAncestorWithSelectedBlock: blockEditorStore.getLowestCommonAncestorWithSelectedBlock,
};
}
);
const { selectBlock } = useDispatch( 'core/block-editor' );
// Track state in a ref, to allow us to determine if slides are added or removed.
const slideCount = useRef( slideBlocks.length );
const { insertBlock } = useDispatch( 'core/block-editor' );
/**
* Function to add a new slide to the group of slides.
*/
const addSlide = () => {
const created = createBlock( allowedBlock );
insertBlock( created, undefined, parentBlockId );
};
/**
* If a slide is added, switch to the new slide. If one is deleted, make sure we don't
* show a non-existent slide.
*/
useEffect( () => {
if ( slideBlocks.length > slideCount.current ) {
// Slide added
const newIndex = slideBlocks.length - 1;
setCurrentItemIndex( newIndex );
selectBlock( slideBlocks[ newIndex ].clientId );
} else if ( slideBlocks.length < slideCount.current ) {
// Slide deleted
if ( currentItemIndex + 1 > slideBlocks.length ) {
const newIndex = slideBlocks.length - 1;
setCurrentItemIndex( newIndex );
selectBlock( slideBlocks[ newIndex ].clientId );
}
}
// Update ref with new value..
slideCount.current = slideBlocks.length;
}, [ slideBlocks.length, currentItemIndex, slideCount, setCurrentItemIndex, selectBlock, slideBlocks ] );
/**
* If the selected block ID changes to either a slideBlock, or an Innerblock of a slide, focus that slide.
*/
useEffect( () => {
const found = slideBlocks.findIndex( ( slideBlock ) => {
return getLowestCommonAncestorWithSelectedBlock( slideBlock.clientId ) === slideBlock.clientId;
} );
if ( found >= 0 ) {
setCurrentItemIndex( found );
}
}, [ selectedBlockId, slideBlocks, setCurrentItemIndex, getLowestCommonAncestorWithSelectedBlock ] );
return (
<div className="inner-block-slider">
<InnerBlocksDisplaySingle
allowedBlocks={ [ allowedBlock ] }
className="slides"
currentItemIndex={ currentItemIndex }
parentBlockId={ parentBlockId }
perPage={ perPage }
template={ innerBlockTemplate }
/>
{ showNavigation && (
<Navigation
addSlide={ addSlide }
addSlideEnabled={ slideBlocks.length < slideLimit }
currentPage={ currentItemIndex + 1 }
nextEnabled={ currentItemIndex + 1 < slideBlocks.length }
prevEnabled={ currentItemIndex + 1 > 1 }
setCurrentPage={ ( page ) => {
setCurrentItemIndex( page - 1 );
selectBlock( slideBlocks[ page - 1 ].clientId );
} }
totalPages={ slideBlocks.length }
/> ) }
</div>
);
};
InnerBlockSliderControlled.propTypes = {
parentBlockId: PropTypes.string.isRequired,
allowedBlock: PropTypes.string.isRequired,
template: PropTypes.array,
showNavigation: PropTypes.bool,
currentItemIndex: PropTypes.number.isRequired,
setCurrentItemIndex: PropTypes.func.isRequired,
};
export default InnerBlockSliderControlled;