Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions includes/BlockRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ class BlockRenderer {
*/
public static function render( $attributes ) {
// Block attributes
$icon_data = $attributes['icon'] ?? [];
$radius = (string) ( $attributes['borderRadius'] ?? '0px' );
$link_url = (string) ( $attributes['url'] ?? '' );
$link_label = (string) ( $attributes['label'] ?? '' );
$icon_data = $attributes['icon'] ?? [];
$radius = (string) ( $attributes['borderRadius'] ?? '0px' );
$link_url = (string) ( $attributes['url'] ?? '' );
$link_label = (string) ( $attributes['label'] ?? '' );
$target_blank = ! empty( $attributes['targetBlank'] );

$collection_name = $icon_data['collection'] ?? null;
$icon_name = $icon_data['name'] ?? null;
Expand Down Expand Up @@ -52,10 +53,17 @@ public static function render( $attributes ) {

// Start block link
if ( ! empty( $link_url ) ) {
$link_attrs = '';
if ( ! empty( $link_label ) ) {
$link_attrs .= sprintf( ' aria-label="%s"', esc_attr( $link_label ) );
}
if ( $target_blank ) {
$link_attrs .= ' target="_blank" rel="noopener noreferrer"';
}
$html .= sprintf(
'<a class="wp-block-blockparty-icon__link" href="%s"%s>',
esc_url( $link_url ),
! empty( $link_label ) ? sprintf( ' aria-label="%s"', esc_attr( $link_label ) ) : ''
$link_attrs
);
}

Expand Down
4 changes: 4 additions & 0 deletions src/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@
},
"label": {
"type": "string"
},
"targetBlank": {
"type": "boolean",
"default": false
}
},
"textdomain": "blockparty-icons",
Expand Down
79 changes: 46 additions & 33 deletions src/components/link-url-popover.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ import {
store as blockEditorStore,
} from '@wordpress/block-editor';
import { __ } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import { Button, ToggleControl } from '@wordpress/components';
import { keyboardReturn } from '@wordpress/icons';

export default function SocialLinkURLPopover( {
url,
targetBlank,
setAttributes,
setPopover,
popoverAnchor,
Expand All @@ -25,42 +26,54 @@ export default function SocialLinkURLPopover( {
anchor={ popoverAnchor }
onClose={ () => setPopover( false ) }
>
<form
className="block-editor-url-popover__link-editor"
onSubmit={ ( event ) => {
event.preventDefault();
setPopover( false );
} }
>
<div className="block-editor-url-input">
<URLInput
<div className="blockparty-icons-link-url-popover">
<form
className="blockparty-icons-link-url-popover__form block-editor-url-popover__link-editor"
onSubmit={ ( event ) => {
event.preventDefault();
setPopover( false );
} }
>
<div className="block-editor-url-input">
<URLInput
__nextHasNoMarginBottom
value={ url }
onChange={ ( nextURL ) =>
setAttributes( { url: nextURL } )
}
placeholder={ __( 'Enter address' ) }
disableSuggestions={ true }
onKeyDown={ ( event ) => {
if (
!! url ||
event.defaultPrevented ||
! [ BACKSPACE, DELETE ].includes(
event.keyCode
)
) {
return;
}
removeBlock( clientId );
} }
/>
</div>
<Button
icon={ keyboardReturn }
label={ __( 'Apply' ) }
type="submit"
/>
</form>
<div className="blockparty-icons-link-url-popover__settings">
<ToggleControl
__nextHasNoMarginBottom
value={ url }
onChange={ ( nextURL ) =>
setAttributes( { url: nextURL } )
label={ __( 'Open in a new tab', 'blockparty-icons' ) }
checked={ !! targetBlank }
onChange={ ( value ) =>
setAttributes( { targetBlank: value } )
}
placeholder={ __( 'Enter address' ) }
disableSuggestions={ true }
onKeyDown={ ( event ) => {
if (
!! url ||
event.defaultPrevented ||
! [ BACKSPACE, DELETE ].includes(
event.keyCode
)
) {
return;
}
removeBlock( clientId );
} }
/>
</div>
<Button
icon={ keyboardReturn }
label={ __( 'Apply' ) }
type="submit"
/>
</form>
</div>
</URLPopover>
);
}
42 changes: 31 additions & 11 deletions src/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ export default function Edit( {
isSelected,
setAttributes,
} ) {
const { borderRadius, iconColor, icon, label, size, url } = attributes;
const { borderRadius, iconColor, icon, label, targetBlank, size, url } =
attributes;

const blockRef = useRef( null );
const [ icons, setIcons ] = useState( null );
Expand All @@ -107,7 +108,8 @@ export default function Edit( {
};

const removeLink = () => {
setAttributes( { url: '' } );
setPopover( false );
setAttributes( { url: '', targetBlank: false } );
};

const openIconModal = () => {
Expand Down Expand Up @@ -233,15 +235,32 @@ export default function Edit( {
{ icon && (
<>
<BlockControls group="other">
<ToolbarButton
icon={ url ? linkOff : link }
onClick={ url ? removeLink : openLinkPopover }
label={
url
? __( 'Remove link', 'blockparty-icons' )
: __( 'Add a link', 'blockparty-icons' )
}
/>
{ url ? (
<ToolbarGroup>
<ToolbarButton
icon={ link }
onClick={ openLinkPopover }
label={ __(
'Edit link',
'blockparty-icons'
) }
/>
<ToolbarButton
icon={ linkOff }
onClick={ removeLink }
label={ __(
'Remove link',
'blockparty-icons'
) }
/>
</ToolbarGroup>
) : (
<ToolbarButton
icon={ link }
onClick={ openLinkPopover }
label={ __( 'Add a link', 'blockparty-icons' ) }
/>
) }
</BlockControls>
<BlockControls>
<ToolbarGroup>
Expand All @@ -267,6 +286,7 @@ export default function Edit( {
{ showURLPopover && (
<LinkURLPopover
url={ url }
targetBlank={ targetBlank }
setAttributes={ setAttributes }
setPopover={ setPopover }
popoverAnchor={ popoverAnchor }
Expand Down
26 changes: 26 additions & 0 deletions src/editor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,32 @@
grid-column: 1 / -1;
}

// Link URL popover: URL + apply in a row, toggle below.
.blockparty-icons-link-url-popover {
display: flex;
flex-direction: column;
gap: 12px;
min-width: 280px;
padding: 12px 16px;

&__form.block-editor-url-popover__link-editor {
display: flex;
flex-direction: row;
align-items: center;
gap: 8px;
width: 100%;
}

.block-editor-url-input {
flex: 1;
min-width: 0;
}

&__settings .components-toggle-control__label {
white-space: nowrap;
}
}

// -----------------------------------------------------------------------------
// Raw icon component (inline SVG in editor)
// -----------------------------------------------------------------------------
Expand Down
50 changes: 50 additions & 0 deletions tests/phpunit/BlockRendererTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,56 @@ public function test_link_without_a_label_has_no_aria_label(): void {
$this->assertStringNotContainsString( 'aria-label', $html );
}

public function test_url_without_target_blank_has_no_target_or_rel(): void {
$html = $this->render(
[
'icon' => $this->icon(),
'url' => 'https://example.org',
]
);

$this->assertStringNotContainsString( 'target=', $html );
$this->assertStringNotContainsString( 'rel=', $html );
}

public function test_target_blank_adds_target_and_rel(): void {
$html = $this->render(
[
'icon' => $this->icon(),
'url' => 'https://example.org',
'targetBlank' => true,
]
);

$this->assertStringContainsString( 'target="_blank"', $html );
$this->assertStringContainsString( 'rel="noopener noreferrer"', $html );
}

public function test_target_blank_false_leaves_link_unchanged(): void {
$html = $this->render(
[
'icon' => $this->icon(),
'url' => 'https://example.org',
'targetBlank' => false,
]
);

$this->assertStringContainsString( 'href="https://example.org"', $html );
$this->assertStringNotContainsString( 'target=', $html );
$this->assertStringNotContainsString( 'rel=', $html );
}

public function test_target_blank_without_url_produces_no_link(): void {
$html = $this->render(
[
'icon' => $this->icon(),
'targetBlank' => true,
]
);

$this->assertStringNotContainsString( '<a ', $html );
}

/* --------------------------------------------------------------- color */

/**
Expand Down
Loading