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

[FEATURE] Add an icon block #35

Merged
merged 1 commit into from
Jul 4, 2024
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
12 changes: 12 additions & 0 deletions packages/iconography/includes/IconographyService.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,25 @@ 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 );
add_action( 'enqueue_block_assets', array( $this, 'enqueue_editor_scripts' ) );
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
*
Expand Down
4 changes: 2 additions & 2 deletions packages/iconography/src/block/Attributes.type.ts
Original file line number Diff line number Diff line change
@@ -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;
} >;
70 changes: 26 additions & 44 deletions packages/iconography/src/block/Edit.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
import React from 'react';

import { IconToolbarButton } from '../IconToolbarButton';
import {
BlockControls,
InspectorControls,
useBlockProps,
} from '@wordpress/block-editor';
/* WordPress Dependencies */
import { useBlockProps } from '@wordpress/block-editor';
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 { Icon, Spinner } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { replace } from '@wordpress/icons';

/* Internal deps */
import { IconToolbarButton } from '../shared';
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,
setAttributes,
}: BlockEditProps< Attributes > ) => {
const [ showIconModal, setShowIconModal ] = useState( false );
const blockProps = useBlockProps();
const { getFormatType } = useSelect(
( select ) =>
Expand All @@ -42,52 +41,35 @@ 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';

const ShowModalButton = () => (
<Button
variant={ 'primary' }
onClick={ () => setShowIconModal( ! showIconModal ) }
>
Select Icon
</Button>
);
( attributes.iconTag as keyof HTMLElementTagNameMap ) ?? 'span';

return (
<>
<InspectorControls>
<Panel>
<PanelBody>
<ShowModalButton />
</PanelBody>
</Panel>
</InspectorControls>
<IconToolbarButton
icon={ <Icon icon={ replace } /> }
onChange={ handleChange }
value={ {
text: '',
formats: [],
replacements: [],
start: 0,
end: 0,
} }
initialOpen={ ! attributes.iconContent }
/>
<div { ...blockProps }>
{ attributes.iconContent && (
<TagName className={ attributes.className ?? '' }>
<TagName className={ attributes.iconClass ?? '' }>
{ attributes.iconContent }
</TagName>
) }
{ ! attributes.iconContent && <ShowModalButton /> }
{ showIconModal && (
<IconModal
onRequestClose={ () => setShowIconModal( false ) }
onChange={ handleChange }
value={ {
text: '',
formats: [],
replacements: [],
start: 0,
end: 0,
} }
/>
) }
{ ! attributes.iconContent && <Spinner /> }
</div>
</>
);
Expand Down
7 changes: 4 additions & 3 deletions packages/iconography/src/block/Save.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import React from 'react';

/* WordPress Dependencies */
import { useBlockProps } from '@wordpress/block-editor';

/* Types */
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 (
<div { ...useBlockProps.save() }>
<TagName className={ className ?? '' }>{ iconContent }</TagName>
<TagName className={ iconClass ?? '' }>{ iconContent }</TagName>
</div>
);
};
44 changes: 30 additions & 14 deletions packages/iconography/src/block/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,51 +8,67 @@
"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": {
"sticky": false
},
"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": {}
Expand Down
14 changes: 14 additions & 0 deletions packages/iconography/src/block/index.ts
Original file line number Diff line number Diff line change
@@ -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 '../Icon.svg';

registerBlockType( metadata, {
icon: AddReactionOutlined,
edit: Edit,
save: Save,
} );
3 changes: 3 additions & 0 deletions packages/iconography/src/block/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.wp-block-boxuk-icon {
text-align: center;
}
14 changes: 14 additions & 0 deletions packages/iconography/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/* WordPress Dependencies */
import domReady from '@wordpress/dom-ready';

/* Internal deps */
import registerInlineIconography from './registerInlineIconography';

domReady( () => {
registerInlineIconography();
} );

/* Export for other packages to consume */
export * from './types';
export * from './shared';
export * from './utils';
Original file line number Diff line number Diff line change
@@ -1,22 +1,16 @@
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 { IconToolbarButton } from './shared';
import { getIconGroups, selectIconAtCurrentCursor } from './utils';

/* Types */
import type { IconGroup } from './types';

export const handleKeyDown =
const handleKeyDown =
( iconGroups: IconGroup[] | undefined ) => ( event: KeyboardEvent ) => {
switch ( event.key ) {
case 'ArrowLeft':
Expand All @@ -29,7 +23,7 @@ export const handleKeyDown =
}
};

export const handleKeyUp =
const handleKeyUp =
( iconGroups: IconGroup[] | undefined ) => ( event: KeyboardEvent ) => {
if ( 'ArrowRight' === event.key ) {
const { selection, icon } = selectIconAtCurrentCursor( iconGroups );
Expand All @@ -55,7 +49,7 @@ export const handleKeyEvent =
}
};

export const registerIconography = () => {
export const registerInlineIconography = () => {
const iconGroups = getIconGroups();
if ( ! iconGroups ) {
return;
Expand All @@ -65,11 +59,7 @@ export const registerIconography = () => {
if ( index === 0 ) {
iconGroup.edit = (
props: ComponentProps< typeof IconToolbarButton >
) => (
<BlockControls group="inline">
<IconToolbarButton { ...props } />
</BlockControls>
);
) => <IconToolbarButton { ...props } />;
}
registerFormatType( iconGroup.name, iconGroup );
} );
Expand All @@ -80,11 +70,4 @@ export const registerIconography = () => {
document.addEventListener( 'keyup', handleKeyEvent( iconGroups ) );
};

domReady( () => {
registerIconography();
} );

registerBlockType( metadata, {
edit: Edit,
save: Save,
} );
export default registerInlineIconography;
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { useState, useMemo } from '@wordpress/element';

/* Internal Dependencies */
import { PlaceholderIconPanel } from './PlaceholderIconPanel';
import { getIconGroups } from './utils';
import { getIconGroups } from '../utils';

/* Types */
import type { RichTextValue } from '@wordpress/rich-text';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { describe, expect, jest, test } from '@jest/globals';
import { render, screen } from '@testing-library/react';
import { generateRichTextFormat } from '../utils';

import { IconPanel } from '../IconPanel';
import { IconPanel } from './IconPanel';

jest.mock( '../utils', () => ( {
generateRichTextFormat: jest.fn(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import {
} from '@wordpress/components';

/* Internal Dependencies */
import { generateRichTextFormat } from './utils';
import { generateRichTextFormat } from '../utils';

/* Types */
import type { IconGroup } from './types';
import type { IconGroup } from '../types';
import type { RichTextValue } from '@wordpress/rich-text';

export type IconPanelProps = {
Expand Down
Loading
Loading