Skip to content

Commit 5f6530d

Browse files
committed
update UI, add unlink button, add arrow key navigation
1 parent 0debf21 commit 5f6530d

File tree

2 files changed

+101
-54
lines changed

2 files changed

+101
-54
lines changed

src/components/block-styles-control/editor.scss

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@
7979
}
8080

8181
.ugb-block-styles-controls__popover {
82+
.components-popover__content {
83+
width: 350px !important;
84+
}
8285
.components-button {
8386
width: 100%;
8487
position: relative;

src/components/block-styles-control/index.js

Lines changed: 98 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -43,33 +43,29 @@ export const BlockStylesControl = props => {
4343
const blockAttributesFilter = getBlockStyleAttributesFilter( blockName )
4444
const defaultBlockAttributes = useMemo( () => getFilteredAttributes( blockType.attributes, blockAttributesFilter ), [] )
4545

46+
const [ userCanManageOptions, setUserCanManageOptions ] = useState( false )
4647
const [ openProNotice, setOpenProNotice ] = useState( false )
4748
const [ openSaveModal, setOpenSaveModal ] = useState( false )
4849
const [ openPopover, setOpenPopover ] = useState( false )
50+
const [ focusedIndex, setFocusedIndex ] = useState( 0 )
4951

5052
const prevBlockStyleRef = useRef( null )
5153
const buttonRef = useRef( null )
52-
const panelBodyRef = useRef( null )
54+
const blockStylesListRef = useRef( null )
55+
const blockStyleButtonsRef = useRef( [] )
5356

54-
const [ userCanManageOptions, setUserCanManageOptions ] = useState( false )
5557
const id = useSelect( select => select( 'core' ).getCurrentUser()?.id, [] )
5658

57-
// Check if the user has "manage options" capabilities and can manage block styles.
58-
useEffect( () => {
59-
const checkCapabilities = async () => {
60-
const capabilities = await currentUserHasCapability( 'manage_options' )
61-
setUserCanManageOptions( capabilities )
62-
}
63-
64-
checkCapabilities()
65-
}, [ id ] )
59+
const attributes = useBlockAttributesContext()
60+
const setAttributes = useBlockSetAttributesContext()
6661

67-
// Reset openProNotice when the popover is closed
68-
useEffect( () => {
69-
if ( ! openPopover ) {
70-
setOpenProNotice( false )
71-
}
72-
}, [ openPopover ] )
62+
const {
63+
blockStyle,
64+
modifiedBlockStyle: isModified,
65+
uniqueId: _uniqueId,
66+
generatedCss: _generatedCss,
67+
...otherAttributes
68+
} = attributes
7369

7470
const mainClasses = classnames( [
7571
'components-panel__body',
@@ -82,17 +78,75 @@ export const BlockStylesControl = props => {
8278
'ugb-pro-control-button--hidden': ! openProNotice,
8379
} )
8480

85-
const attributes = useBlockAttributesContext()
81+
// Handle keyboard navigation for block style buttons
82+
const handleKeyDown = event => {
83+
// eslint-disable-next-line @wordpress/no-global-active-element
84+
if ( ! blockStyleButtonsRef.current.includes( document.activeElement ) ) {
85+
return
86+
}
8687

87-
const {
88-
blockStyle,
89-
modifiedBlockStyle: isModified,
90-
uniqueId: _uniqueId,
91-
generatedCss: _generatedCss,
92-
...otherAttributes
93-
} = attributes
88+
if ( event.key === 'ArrowDown' ) {
89+
event.preventDefault()
90+
setFocusedIndex( prevIndex => ( prevIndex + 1 ) % blockStyleButtonsRef.current.length )
91+
} else if ( event.key === 'ArrowUp' ) {
92+
event.preventDefault()
93+
setFocusedIndex( prevIndex => ( prevIndex - 1 + blockStyleButtonsRef.current.length ) % blockStyleButtonsRef.current.length )
94+
}
95+
}
9496

95-
const setAttributes = useBlockSetAttributesContext()
97+
// Update focused block style
98+
useEffect( () => {
99+
if ( blockStyleButtonsRef.current[ focusedIndex ] ) {
100+
blockStyleButtonsRef.current[ focusedIndex ].focus()
101+
}
102+
}, [ focusedIndex ] )
103+
104+
useEffect( () => {
105+
// Reset openProNotice, focusedIndex, and blockStyleButtonsRef when the popover is closed
106+
if ( ! openPopover ) {
107+
setOpenProNotice( false )
108+
setFocusedIndex( -1 )
109+
blockStyleButtonsRef.current = []
110+
111+
return
112+
}
113+
114+
const list = blockStylesListRef.current
115+
116+
if ( ! list ) {
117+
return
118+
}
119+
120+
if ( ! blockStyleButtonsRef.current.length ) {
121+
blockStyleButtonsRef.current = Array.from( list.querySelectorAll( 'button' ) )
122+
}
123+
124+
// Focus on the selected block style button when the popover is opened.
125+
const selected = list.querySelector( '.ugb-block-styles-controls__selected' )
126+
127+
if ( selected && blockStyleButtonsRef.current.length ) {
128+
const index = blockStyleButtonsRef.current.indexOf( selected )
129+
setFocusedIndex( index )
130+
}
131+
132+
list.addEventListener( 'keydown', handleKeyDown )
133+
134+
return () => {
135+
if ( list ) {
136+
list.removeEventListener( 'keydown', handleKeyDown )
137+
}
138+
}
139+
}, [ openPopover ] )
140+
141+
// Check if the user has "manage options" capabilities and can manage block styles.
142+
useEffect( () => {
143+
const checkCapabilities = async () => {
144+
const capabilities = await currentUserHasCapability( 'manage_options' )
145+
setUserCanManageOptions( capabilities )
146+
}
147+
148+
checkCapabilities()
149+
}, [ id ] )
96150

97151
useEffect( () => {
98152
if ( prevBlockStyleRef.current === null ) {
@@ -137,6 +191,8 @@ export const BlockStylesControl = props => {
137191
}, [ blockStyle ] )
138192

139193
const onSelectDefaultBlockStyle = () => {
194+
setFocusedIndex( 0 )
195+
140196
// Do nothing if block style is already "Default"
141197
if ( ! blockStyle ) {
142198
return
@@ -145,7 +201,9 @@ export const BlockStylesControl = props => {
145201
setAttributes( { ...defaultBlockAttributes, modifiedBlockStyle: false } )
146202
}
147203

148-
const onSelectBlockStyle = option => {
204+
const onSelectBlockStyle = ( option, index ) => {
205+
setFocusedIndex( index )
206+
149207
if ( isPro ) {
150208
doAction( 'stackable.global-settings.global-block-styles.select-block-style',
151209
option, blockStyle, globalBlockStyles, defaultBlockAttributes, setAttributes )
@@ -176,13 +234,7 @@ export const BlockStylesControl = props => {
176234
size="small"
177235
icon="edit"
178236
iconSize={ 12 }
179-
onMouseDown={ () => {
180-
setOpenPopover( isOpen => ! isOpen )
181-
// Focus on the selected block style button when the popover is opened.
182-
setTimeout( () => {
183-
panelBodyRef.current?.querySelector( '.ugb-block-styles-controls__selected' )?.focus()
184-
}, 50 )
185-
} }
237+
onMouseDown={ () => setOpenPopover( isOpen => ! isOpen ) }
186238
ref={ buttonRef }
187239
>
188240
{ `${ __( 'Block Style', i18n ) }:` } <wbr /> { blockStyleLabel }{ isModified && inBlockStyleOptions ? <span className="stk-panel-modified-indicator stk--visible"></span> : '' }
@@ -210,22 +262,22 @@ export const BlockStylesControl = props => {
210262
{ openPopover && (
211263
<Popover
212264
className="ugb-button-icon-control__popover ugb-block-styles-controls__popover"
213-
focusOnMount={ false }
265+
anchor={ buttonRef.current }
214266
onEscape={ () => setOpenPopover( false ) }
215267
onClose={ () => setOpenPopover( false ) }
216-
anchor={ buttonRef.current }
217-
offset={ 8 }
268+
focusOnMount={ false }
218269
placement="left-start"
219270
resize={ false }
271+
offset={ 8 }
220272
>
221-
<PanelBody ref={ panelBodyRef }>
273+
<PanelBody>
222274
<h2 className="components-panel__body-title">{ __( 'Block Styles', i18n ) }</h2>
223275
<p className="components-panel__body-description">
224276
{ __( 'Save the styles of this block to reuse on others. You can also update a saved style, and the changes will apply wherever it\'s used.', i18n ) }
225277
&nbsp;
226278
<a href="https://docs.wpstackable.com/article/737-how-to-use-block-styles" target="_docs" rel="noreferrer">{ __( 'Learn more', i18n ) }</a>
227279
</p>
228-
<ul className="ugb-block-styles-controls__list">
280+
<ul className="ugb-block-styles-controls__list" ref={ blockStylesListRef }>
229281
<li>
230282
<Button
231283
onClick={ () => onSelectDefaultBlockStyle() }
@@ -239,7 +291,7 @@ export const BlockStylesControl = props => {
239291
{ globalBlockStyles.map( ( option, index ) => {
240292
return <li key={ index }>
241293
<Button
242-
onClick={ () => onSelectBlockStyle( option.slug ) }
294+
onClick={ () => onSelectBlockStyle( option.slug, index + 1 ) }
243295
className={ blockStyle === option.slug ? 'ugb-block-styles-controls__selected' : '' }
244296
tabIndex={ 0 }
245297
>
@@ -254,6 +306,7 @@ export const BlockStylesControl = props => {
254306
</ul>
255307
{ userCanManageOptions && (
256308
<SaveUpdateButtons
309+
blockName={ blockName }
257310
blockStyle={ blockStyle }
258311
inOptions={ inBlockStyleOptions }
259312
isModified={ isModified }
@@ -280,26 +333,17 @@ export const BlockStylesControl = props => {
280333
}
281334

282335
const SaveUpdateButtons = props => {
283-
const {
284-
blockStyle, inOptions, isModified, setOpenSaveModal, onAddBlockStyle,
285-
} = props
286-
287-
const UpdateButton = applyFilters( 'stackable.global-settings.global-block-styles.update-button', Fragment )
336+
const { onAddBlockStyle, ...propsToPass } = props
337+
const ActionButtons = applyFilters( 'stackable.global-settings.global-block-styles.action-buttons', Fragment )
288338

289339
return ( <>
290340
<Flex style={ { marginTop: '24px' } }>
291-
<FlexItem>
292-
<UpdateButton
293-
blockStyle={ blockStyle }
294-
inOptions={ inOptions }
295-
isModified={ isModified }
296-
setOpenSaveModal={ setOpenSaveModal }
297-
/>
298-
</FlexItem>
299-
<FlexItem>
341+
<ActionButtons { ...propsToPass } />
342+
<FlexItem style={ ! props.blockStyle || ! props.inOptions ? { marginLeft: 'auto' } : {} }>
300343
<Button
301344
variant="primary"
302345
onClick={ () => onAddBlockStyle() }
346+
size="small"
303347
>
304348
{ __( 'Save as New Style', i18n ) }
305349
{ ! isPro && <span className="stk-pulsating-circle" role="presentation" /> }

0 commit comments

Comments
 (0)