From edfade5db5509f6b3d728fa36184be0da2422e75 Mon Sep 17 00:00:00 2001 From: James Amner Date: Wed, 19 Jun 2024 17:31:20 +0100 Subject: [PATCH] [FEATURE] Add an icon block Change Details -------------- Adds an icon block to the iconography package --- package-lock.json | 100 +++--------------- .../includes/IconographyService.php | 12 +++ .../iconography/src/block/Attributes.type.ts | 4 +- packages/iconography/src/block/Edit.tsx | 46 +++++--- packages/iconography/src/block/Save.tsx | 7 +- packages/iconography/src/block/block.json | 44 +++++--- packages/iconography/src/block/index.ts | 14 +++ packages/iconography/src/block/style.scss | 3 + packages/iconography/src/index.tsx | 9 -- .../tests/TestIcononographyService.php | 20 ++++ packages/iconography/webpack.config.js | 9 ++ 11 files changed, 144 insertions(+), 124 deletions(-) create mode 100644 packages/iconography/src/block/index.ts create mode 100644 packages/iconography/src/block/style.scss create mode 100644 packages/iconography/webpack.config.js diff --git a/package-lock.json b/package-lock.json index 9a13254..8ebf748 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5095,19 +5095,6 @@ "npm": ">=8.19.2" } }, - "node_modules/@wordpress/api-fetch/node_modules/@wordpress/hooks": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-4.0.0.tgz", - "integrity": "sha512-Bpw4kjnaouc+sy3LFtiSYtyl/SmiMtGa4hhxWtpN4bNGIPfOnMixNKBbm289Bn+aoU7GrOPifP/gWTKW98Rs4A==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.16.0" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - } - }, "node_modules/@wordpress/api-fetch/node_modules/@wordpress/i18n": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-5.0.0.tgz", @@ -7516,24 +7503,25 @@ } }, "node_modules/@wordpress/interface": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@wordpress/interface/-/interface-6.0.0.tgz", - "integrity": "sha512-7nx+3cJfGzpR/0+i2I8nVLH+OtkNEVGP9eG7oVli+IrCisOzIqK2d5R6+c7mmD8m16ypul+PKnhTRF3QGmt+4Q==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@wordpress/interface/-/interface-6.1.0.tgz", + "integrity": "sha512-tL1oRtXDXx1MpYhIwhPcaL/n9Q7QlDNANY3ZL6Um3LLuf4bJwkIW8L6j8dBKq/8yTKhnIKIoo3QINjCLDbz5CA==", "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/a11y": "^4.0.0", - "@wordpress/components": "^28.0.0", - "@wordpress/compose": "^7.0.0", - "@wordpress/data": "^10.0.0", - "@wordpress/deprecated": "^4.0.0", - "@wordpress/element": "^6.0.0", - "@wordpress/i18n": "^5.0.0", - "@wordpress/icons": "^10.0.0", - "@wordpress/plugins": "^7.0.0", - "@wordpress/preferences": "^4.0.0", - "@wordpress/private-apis": "^1.0.0", - "@wordpress/viewport": "^6.0.0", + "@wordpress/a11y": "^4.1.0", + "@wordpress/components": "^28.1.0", + "@wordpress/compose": "^7.1.0", + "@wordpress/data": "^10.1.0", + "@wordpress/deprecated": "^4.1.0", + "@wordpress/element": "^6.1.0", + "@wordpress/i18n": "^5.1.0", + "@wordpress/icons": "^10.1.0", + "@wordpress/plugins": "^7.1.0", + "@wordpress/preferences": "^4.1.0", + "@wordpress/private-apis": "^1.1.0", + "@wordpress/viewport": "^6.1.0", "clsx": "^2.1.1" }, "engines": { @@ -7821,51 +7809,6 @@ "npm": ">=8.19.2" } }, - "node_modules/@wordpress/interface": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@wordpress/interface/-/interface-6.1.0.tgz", - "integrity": "sha512-tL1oRtXDXx1MpYhIwhPcaL/n9Q7QlDNANY3ZL6Um3LLuf4bJwkIW8L6j8dBKq/8yTKhnIKIoo3QINjCLDbz5CA==", - "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@babel/runtime": "^7.16.0", - "@wordpress/a11y": "^4.1.0", - "@wordpress/components": "^28.1.0", - "@wordpress/compose": "^7.1.0", - "@wordpress/data": "^10.1.0", - "@wordpress/deprecated": "^4.1.0", - "@wordpress/element": "^6.1.0", - "@wordpress/i18n": "^5.1.0", - "@wordpress/icons": "^10.1.0", - "@wordpress/plugins": "^7.1.0", - "@wordpress/preferences": "^4.1.0", - "@wordpress/private-apis": "^1.1.0", - "@wordpress/viewport": "^6.1.0", - "clsx": "^2.1.1" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - }, - "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" - } - }, - "node_modules/@wordpress/is-shallow-equal": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@wordpress/is-shallow-equal/-/is-shallow-equal-5.1.0.tgz", - "integrity": "sha512-OZH/p43ZNJaSF40oi6dNdlsLqxjd4pZ1H4QxDg46vXT0TztU1rT/HOeJWyVmHIjx/4utuGaLJBZcfK4cKPQXUg==", - "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@babel/runtime": "^7.16.0" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - } - }, "node_modules/@wordpress/interface/node_modules/@wordpress/keycodes": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-4.0.0.tgz", @@ -11215,17 +11158,6 @@ "node": ">=12" } }, - "node_modules/@wordpress/wordcount": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@wordpress/wordcount/-/wordcount-4.0.0.tgz", - "integrity": "sha512-g734YzL5n/96qx6SPTtOxWIFjSOU036ICCjPAUqSULO4Z61QgbKh0IPvajAvJD5Tq++FyaFPSVNlky40qJCLkA==", - "dev": true, - "license": "GPL-2.0-or-later", - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - } - }, "node_modules/@wordpress/wordcount": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/@wordpress/wordcount/-/wordcount-4.1.0.tgz", diff --git a/packages/iconography/includes/IconographyService.php b/packages/iconography/includes/IconographyService.php index dacaeff..c23292b 100644 --- a/packages/iconography/includes/IconographyService.php +++ b/packages/iconography/includes/IconographyService.php @@ -29,6 +29,7 @@ public function __construct( private ConfigurationParser $configuration_parser ) * Init Hooks */ public function init(): void { + add_action( 'init', array( $this, 'register_block' ) ); add_action( 'wp_enqueue_scripts', array( $this, 'register_assets' ) ); add_action( 'wp_footer', array( $this, 'enqueue_assets' ), 1, 0 ); add_action( 'enqueue_block_assets', array( $this, 'register_assets' ), 1, 0 ); @@ -36,6 +37,17 @@ public function init(): void { add_action( 'enqueue_block_assets', array( $this, 'enqueue_all_assets' ) ); } + /** + * Register the block + * + * @return void + */ + public function register_block(): void { + register_block_type_from_metadata( + plugin_dir_path( __DIR__ ) . 'build/block' + ); + } + /** * Register all assets in WP * diff --git a/packages/iconography/src/block/Attributes.type.ts b/packages/iconography/src/block/Attributes.type.ts index e8960e2..09828b7 100644 --- a/packages/iconography/src/block/Attributes.type.ts +++ b/packages/iconography/src/block/Attributes.type.ts @@ -1,7 +1,7 @@ import type { WPFormat } from '@wordpress/rich-text/build-types/register-format-type'; export type Attributes = Partial< { - className: WPFormat[ 'className' ]; - tagName: WPFormat[ 'tagName' ]; + iconClass: WPFormat[ 'className' ]; + iconTag: WPFormat[ 'tagName' ]; iconContent: string; } >; diff --git a/packages/iconography/src/block/Edit.tsx b/packages/iconography/src/block/Edit.tsx index 7aebe25..68b1ded 100644 --- a/packages/iconography/src/block/Edit.tsx +++ b/packages/iconography/src/block/Edit.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import { IconToolbarButton } from '../IconToolbarButton'; +/* WordPress Dependencies */ import { BlockControls, InspectorControls, @@ -9,14 +9,25 @@ import { import { store as RichTextStore } from '@wordpress/rich-text'; import { useSelect } from '@wordpress/data'; import { useState } from '@wordpress/element'; -import { Button, Panel, PanelBody } from '@wordpress/components'; +import { + Button, + Panel, + PanelBody, + ToolbarButton, + Icon, +} from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; +import { replace } from '@wordpress/icons'; + +/* Internal deps */ +import { IconModal } from '../IconModal'; +import './style.scss'; /* Types */ import type { Attributes } from './Attributes.type'; import type { BlockEditProps } from '@wordpress/blocks'; import type { RichTextValue } from '@wordpress/rich-text'; import type { WPFormat } from '@wordpress/rich-text/build-types/register-format-type'; -import { IconModal } from '../IconModal'; export const Edit = ( { attributes, @@ -42,35 +53,46 @@ export const Edit = ( { setAttributes( { iconContent: value.text, - tagName: format.tagName, - className: format.className, + iconTag: format.tagName, + iconClass: format.className, } ); }; const TagName = - ( attributes.tagName as keyof HTMLElementTagNameMap ) ?? 'span'; + ( attributes.iconTag as keyof HTMLElementTagNameMap ) ?? 'span'; + + const buttonText = attributes.iconContent + ? __( 'Change Icon', 'boxuk' ) + : __( 'Select Icon', 'boxuk' ); const ShowModalButton = () => ( + text={ buttonText } + icon={ } + /> ); return ( <> - + + + } + onClick={ () => setShowIconModal( ! showIconModal ) } + title={ buttonText } + /> +
{ attributes.iconContent && ( - + { attributes.iconContent } ) } diff --git a/packages/iconography/src/block/Save.tsx b/packages/iconography/src/block/Save.tsx index f514a23..f377fc1 100644 --- a/packages/iconography/src/block/Save.tsx +++ b/packages/iconography/src/block/Save.tsx @@ -1,5 +1,6 @@ import React from 'react'; +/* WordPress Dependencies */ import { useBlockProps } from '@wordpress/block-editor'; /* Types */ @@ -7,12 +8,12 @@ import type { Attributes } from './Attributes.type'; import type { BlockSaveProps } from '@wordpress/blocks'; export const Save = ( { attributes }: BlockSaveProps< Attributes > ) => { - const { className, tagName, iconContent } = attributes; - const TagName = ( tagName as keyof HTMLElementTagNameMap ) ?? 'span'; + const { iconClass, iconTag, iconContent } = attributes; + const TagName = ( iconTag as keyof HTMLElementTagNameMap ) ?? 'span'; return (
- { iconContent } + { iconContent }
); }; diff --git a/packages/iconography/src/block/block.json b/packages/iconography/src/block/block.json index ad0c210..c17ba7e 100644 --- a/packages/iconography/src/block/block.json +++ b/packages/iconography/src/block/block.json @@ -8,24 +8,33 @@ "icon": "star-filled", "keywords": [ "icon", "emoji", "symbol" ], "textdomain": "boxuk", + "style": "file:./style-index.css", + "editorScript": "file:./index.ts", "supports": { - "align": [ "wide", "full" ], - "alignWide": true, + "anchor": false, + "align": [], + "alignWide": false, + "ariaLabel": true, + "background": { + "backgroundImage": false, + "backgroundSize": false + }, + "className": true, "color": { "background": true, "text": true }, - "background": { "backgroundImage": true, "backgroundSize": true }, - "anchor": false, - "ariaLabel": true, - "className": true, "customClassName": true, - "dimensions": { "aspectRatio": false, "minHeight": true }, - "filter": { "duotone": false }, + "dimensions": { + "aspectRatio": false, + "minHeight": false + }, + "filter": { + "duotone": false + }, "html": false, "inserter": true, "interactivity": false, - "layout": true, "lock": true, "multiple": true, "position": { @@ -33,26 +42,33 @@ }, "renaming": true, "reusable": true, - "shadow": false, + "shadow": true, "spacing": { "margin": true, - "padding": true + "padding": true, + "blockGrap": false }, "typography": { "fontSize": true, - "lineHeight": true, + "lineHeight": false, "textAlign": true } }, "attributes": { - "className": { + "iconClass": { "type": "string" }, - "tagName": { + "iconTag": { "type": "string" }, "iconContent": { "type": "string" + }, + "style": { + "type": "object", + "default": { + "textAlign": "center" + } } }, "example": {} diff --git a/packages/iconography/src/block/index.ts b/packages/iconography/src/block/index.ts new file mode 100644 index 0000000..14c2deb --- /dev/null +++ b/packages/iconography/src/block/index.ts @@ -0,0 +1,14 @@ +/* WordPress Dependencies */ +import { registerBlockType } from '@wordpress/blocks'; + +/* Internal deps */ +import metadata from './block.json'; +import { Edit } from './Edit'; +import { Save } from './Save'; +import { ReactComponent as AddReactionOutlined } from '../AddReactionOutlined.svg'; + +registerBlockType( metadata, { + icon: AddReactionOutlined, + edit: Edit, + save: Save, +} ); diff --git a/packages/iconography/src/block/style.scss b/packages/iconography/src/block/style.scss new file mode 100644 index 0000000..9947b29 --- /dev/null +++ b/packages/iconography/src/block/style.scss @@ -0,0 +1,3 @@ +.wp-block-boxuk-icon { + text-align: center; +} \ No newline at end of file diff --git a/packages/iconography/src/index.tsx b/packages/iconography/src/index.tsx index 67c28d0..7877897 100644 --- a/packages/iconography/src/index.tsx +++ b/packages/iconography/src/index.tsx @@ -3,13 +3,9 @@ import React, { ComponentProps } from 'react'; /* WordPress Dependencies */ import domReady from '@wordpress/dom-ready'; import { registerFormatType } from '@wordpress/rich-text'; -import { registerBlockType } from '@wordpress/blocks'; import { BlockControls } from '@wordpress/block-editor'; /* Internal deps */ -import metadata from './block/block.json'; -import { Edit } from './block/Edit'; -import { Save } from './block/Save'; import { IconToolbarButton } from './IconToolbarButton'; import { getIconGroups, selectIconAtCurrentCursor } from './utils'; @@ -83,8 +79,3 @@ export const registerIconography = () => { domReady( () => { registerIconography(); } ); - -registerBlockType( metadata, { - edit: Edit, - save: Save, -} ); diff --git a/packages/iconography/tests/TestIcononographyService.php b/packages/iconography/tests/TestIcononographyService.php index c9b87c6..ec1397c 100644 --- a/packages/iconography/tests/TestIcononographyService.php +++ b/packages/iconography/tests/TestIcononographyService.php @@ -25,6 +25,7 @@ class TestIcononographyService extends TestCase { */ public function testInit(): void { $class_in_test = new IconographyService( new ConfigurationParser() ); + \WP_Mock::expectActionAdded( 'init', array( $class_in_test, 'register_block' ) ); \WP_Mock::expectActionAdded( 'wp_enqueue_scripts', array( $class_in_test, 'register_assets' ) ); \WP_Mock::expectActionAdded( 'wp_footer', array( $class_in_test, 'enqueue_assets' ), 1, 0 ); \WP_Mock::expectActionAdded( 'enqueue_block_assets', array( $class_in_test, 'register_assets' ), 1, 0 ); @@ -35,6 +36,25 @@ public function testInit(): void { $this->assertConditionsMet(); } + /** + * Test Register Block + * + * @return void + */ + public function testRegisterBlock(): void { + \WP_Mock::userFunction( 'plugin_dir_path' ) + ->once() + ->andReturn( 'test/' ); + + \WP_Mock::userFunction( 'register_block_type_from_metadata' ) + ->once() + ->with( 'test/build/block' ); + + $class_in_test = new IconographyService( new ConfigurationParser() ); + $class_in_test->register_block(); + $this->assertConditionsMet(); + } + /** * Test Register Assets * diff --git a/packages/iconography/webpack.config.js b/packages/iconography/webpack.config.js new file mode 100644 index 0000000..0afd7c6 --- /dev/null +++ b/packages/iconography/webpack.config.js @@ -0,0 +1,9 @@ +const defaultConfig = require( '@wordpress/scripts/config/webpack.config' ); + +module.exports = { + ...defaultConfig, + entry: { + ...defaultConfig.entry(), + index: './src/index.tsx', + }, +};