Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New block: Modal block using the Interactivity API #675

Merged
merged 11 commits into from
Dec 18, 2024
Merged
62 changes: 62 additions & 0 deletions mu-plugins/blocks/modal/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php
/**
* Block Name: Modal
* Description: Display content in a modal, hidden behind a button click.
*
* @package wporg
*/

namespace WordPressdotorg\MU_Plugins\Modal;

add_action( 'init', __NAMESPACE__ . '\init' );

/**
* Registers the block using the metadata loaded from the `block.json` file.
* Behind the scenes, it registers also all assets so they can be enqueued
* through the block editor in the corresponding context.
*
* @see https://developer.wordpress.org/reference/functions/register_block_type/
*/
function init() {
register_block_type( __DIR__ . '/build' );
}

/**
* Get the style declaration for a color attribute.
*
* The base color attribute (e.g. `backgroundColor`) is the preset color name,
* and needs to be converted into a CSS variable.
* The custom* color attribute (e.g. `customBackgroundColor`) is a hex value.
*
* In most cases, the base color attribute has a default value (see block.json),
* so there will always be a value for that attribute. This means we can pick
* up the custom* color attribute first, and fall back to the preset color if
* it's not found. Also, when picked in the color picker, the custom color
* will be prefilled with the hex value of the preset color.
*
* The overlayColor is a special case, it sets a default on `customOverlayColor`.
* If only `overlayColor` is set, the custom default will be used. If coding a
* modal by hand, make sure to set both `overlayColor` and `customColorOverlay`
* when needed (or only `customColorOverlay`).
*
* @param array $attributes The block attributes.
* @param string $name The name of the base attribute.
*
* @return string The style declaration (or empty if no colors set).
*/
function get_style_decl_from_attr( $attributes, $name ) {
$value = false;
if ( ! empty( $attributes[ 'custom' . ucfirst( $name ) ] ) ) {
$value = $attributes[ 'custom' . ucfirst( $name ) ];
} elseif ( ! empty( $attributes[ $name ] ) ) {
$value = "var(--wp--preset--color--{$attributes[$name]})";
}

if ( $value ) {
// Get the custom property name.
$slug = _wp_to_kebab_case( str_replace( 'Color', '', $name ) );
return "--wp--custom--wporg-modal--color--{$slug}: {$value};";
}

return '';
}
81 changes: 81 additions & 0 deletions mu-plugins/blocks/modal/render.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php
/**
* Render the modal.
*/

use function WordPressdotorg\MU_Plugins\Modal\get_style_decl_from_attr;

$attributes['label'] = $attributes['label'] ?: __( 'Open modal', 'wporg' );

$style = '';
$style .= get_style_decl_from_attr( $attributes, 'backgroundColor' );
$style .= get_style_decl_from_attr( $attributes, 'textColor' );
$style .= get_style_decl_from_attr( $attributes, 'overlayColor' );
$style .= get_style_decl_from_attr( $attributes, 'closeButtonColor' );

$button_class = 'wp-block-button';
if ( ! empty( $attributes['buttonStyle'] ) ) {
$button_class .= ' is-style-' . $attributes['buttonStyle'];
}

// Initial state to pass to Interactivity API.
$init_state = [
'isOpen' => false,
];

// Set up a unique ID for this modal.
$html_id = wp_unique_id( 'modal-' );

?>
<div
<?php echo get_block_wrapper_attributes( [ 'style' => $style ]); // phpcs:ignore ?>
data-wp-interactive="wporg/modal"
data-wp-watch="callbacks.init"
data-wp-on--keydown="actions.handleKeydown"
data-wp-class--is-modal-open="context.isOpen"
<?php echo wp_interactivity_data_wp_context( $init_state ); // phpcs:ignore ?>
>
<div class="wp-block-buttons">
<div class="<?php echo esc_attr( $button_class ); ?>">
<?php if ( ! empty( $attributes['href'] ) ) : ?>
<a
href="<?php echo esc_attr( $attributes['href'] ); ?>"
download
class="wporg-modal__toggle wp-block-button__link"
data-wp-on--click="actions.toggle"
data-wp-bind--aria-expanded="context.isOpen"
aria-controls="<?php echo esc_attr( $html_id ); ?>"
><?php echo wp_kses_post( $attributes['label'] ); ?></a>
<?php else : ?>
<button
class="wporg-modal__toggle wp-block-button__link"
data-wp-on--click="actions.toggle"
data-wp-bind--aria-expanded="context.isOpen"
aria-controls="<?php echo esc_attr( $html_id ); ?>"
><?php echo wp_kses_post( $attributes['label'] ); ?></button>
<?php endif; ?>
</div>
</div>

<div
class="wporg-modal__modal-backdrop"
data-wp-bind--hidden="!context.isOpen"
data-wp-on--click="actions.clickBackdrop"
>
<div
class="wporg-modal__modal"
id="<?php echo esc_attr( $html_id ); ?>"
data-wp-bind--hidden="!context.isOpen"
>
<button
class="wporg-modal__modal-close"
data-wp-on--click="actions.close"
aria-label="<?php esc_attr_e( 'Close', 'wporg' ); ?>"
></button>

<div class="wporg-modal__modal-content">
<?php echo wp_kses_post( $content ); ?>
</div>
</div> <!-- /.wporg-modal__modal -->
</div> <!-- /.wporg-modal__modal-backdrop -->
</div> <!-- /.wporg-modal -->
60 changes: 60 additions & 0 deletions mu-plugins/blocks/modal/src/block.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "wporg/modal",
"title": "Modal",
"icon": "location",
"category": "layout",
"description": "A modal dialog.",
"textdomain": "wporg",
"attributes": {
"backgroundColor": {
"type": "string",
"default": "white"
},
"customBackgroundColor": {
"type": "string"
},
"textColor": {
"type": "string",
"default": "charcoal-1"
},
"customTextColor": {
"type": "string"
},
"closeButtonColor": {
"type": "string",
"default": "charcoal-1"
},
"customCloseButtonColor": {
"type": "string"
},
"overlayColor": {
"type": "string"
},
"customOverlayColor": {
"type": "string",
"default": "#1e1e1ecc"
},
"href": {
"type": "string"
},
"label": {
"type": "string",
"default": "Open modal"
},
"buttonStyle": {
"type": "string",
"default": ""
}
},
"supports": {
"align": false,
"layout": false,
"interactivity": true
},
"editorScript": "file:./index.js",
"style": "file:./style-index.css",
"viewScriptModule": "file:./view.js",
"render": "file:../render.php"
}
Loading
Loading