Skip to content

Commit

Permalink
New block: Modal block using the Interactivity API (#675)
Browse files Browse the repository at this point in the history
* Add a Modal block

* Add editor UI

* Add color controls

* Modal style: Use default content width

* Remove editor CSS

The frontend style is loaded in the editor iframe, so this is not used

* Dry the color code, explain how values are set

* Render button as a div in the editor to prevent keyboard events

* Fix or ignore eslint issues

* Add button style options

* Add `is-small` style options

* Fix linter
  • Loading branch information
ryelle authored Dec 18, 2024
1 parent 127a982 commit b19c079
Show file tree
Hide file tree
Showing 7 changed files with 597 additions and 0 deletions.
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

0 comments on commit b19c079

Please sign in to comment.