From 931746b030e87a5d0b79d765da934e5723d01b13 Mon Sep 17 00:00:00 2001
From: Chip <chip.snyder3@gmail.com>
Date: Wed, 15 Jan 2020 12:00:14 -0500
Subject: [PATCH] [RNMobile] Shortcode block support (#19534)

* Added very basic support for displaying shortcode blocks on pages

* Updated style for native shortcode editing

* Updated the shortcode block styles based on the style guide

* Added test cases for shortcode block

* Migrated shortcode attributes to block.json to be read by javascript and php

* Correct formatting issues

* Update test expectations to preserve attributes when shortcode isn't converted to block

* Resolve PHP formatting issues

* Removed unnecessary comment block.

* Copy the block.json files with the php files to allow easier reference in php

* Added very basic support for displaying shortcode blocks on pages

* Migrated shortcode attributes to block.json to be read by javascript and php

* Apply changes from master that add the devOnly const
---
 packages/block-library/src/index.native.js    |  1 +
 .../block-library/src/shortcode/block.json    | 10 +++++
 .../src/shortcode/edit.native.js              | 45 +++++++++++++++++++
 packages/block-library/src/shortcode/index.js |  6 ++-
 .../block-library/src/shortcode/index.php     |  9 ++--
 .../src/shortcode/style.native.scss           | 37 +++++++++++++++
 .../src/shortcode/test/edit.native.js         | 26 +++++++++++
 test/integration/shortcode-converter.test.js  |  5 +--
 webpack.config.js                             |  7 +++
 9 files changed, 135 insertions(+), 11 deletions(-)
 create mode 100644 packages/block-library/src/shortcode/block.json
 create mode 100644 packages/block-library/src/shortcode/edit.native.js
 create mode 100644 packages/block-library/src/shortcode/style.native.scss
 create mode 100644 packages/block-library/src/shortcode/test/edit.native.js

diff --git a/packages/block-library/src/index.native.js b/packages/block-library/src/index.native.js
index 9f4d56ceb95f7f..ec835f02e802da 100644
--- a/packages/block-library/src/index.native.js
+++ b/packages/block-library/src/index.native.js
@@ -150,6 +150,7 @@ export const registerCoreBlocks = () => {
 		gallery,
 		devOnly( group ),
 		spacer,
+		shortcode,
 	].forEach( registerBlock );
 
 	setDefaultBlockName( paragraph.name );
diff --git a/packages/block-library/src/shortcode/block.json b/packages/block-library/src/shortcode/block.json
new file mode 100644
index 00000000000000..b31c213871e505
--- /dev/null
+++ b/packages/block-library/src/shortcode/block.json
@@ -0,0 +1,10 @@
+{
+	"name": "core/shortcode",
+	"category": "widgets",
+	"attributes": {
+		"text": {
+			"type": "string",
+			"source": "html"
+		}
+	}
+}
diff --git a/packages/block-library/src/shortcode/edit.native.js b/packages/block-library/src/shortcode/edit.native.js
new file mode 100644
index 00000000000000..ee39391f9b747b
--- /dev/null
+++ b/packages/block-library/src/shortcode/edit.native.js
@@ -0,0 +1,45 @@
+/**
+ * External dependencies
+ */
+import { View, Text } from 'react-native';
+
+/**
+ * WordPress dependencies
+ */
+import { __ } from '@wordpress/i18n';
+import { PlainText } from '@wordpress/block-editor';
+import { withPreferredColorScheme } from '@wordpress/compose';
+
+/**
+ * Internal dependencies
+ */
+
+import styles from './style.scss';
+
+export function ShortcodeEdit( props ) {
+	const { attributes, setAttributes, onFocus, onBlur, getStylesFromColorScheme } = props;
+	const titleStyle = getStylesFromColorScheme( styles.blockTitle, styles.blockTitleDark );
+	const shortcodeStyle = getStylesFromColorScheme( styles.blockShortcode, styles.blockShortcodeDark );
+	const placeholderStyle = getStylesFromColorScheme( styles.placeholder, styles.placeholderDark );
+
+	return (
+		<View>
+			<Text style={ titleStyle } >{ __( 'Shortcode' ) }</Text>
+			<PlainText
+				value={ attributes.text }
+				style={ shortcodeStyle }
+				multiline={ true }
+				underlineColorAndroid="transparent"
+				onChange={ ( text ) => setAttributes( { text } ) }
+				placeholder={ __( 'Add a shortcode…' ) }
+				aria-label={ __( 'Shortcode' ) }
+				isSelected={ props.isSelected }
+				onFocus={ onFocus }
+				onBlur={ onBlur }
+				placeholderTextColor={ placeholderStyle.color }
+			/>
+		</View>
+	);
+}
+
+export default withPreferredColorScheme( ShortcodeEdit );
diff --git a/packages/block-library/src/shortcode/index.js b/packages/block-library/src/shortcode/index.js
index d1ccb00e17d9bc..69dc9a0dcd2647 100644
--- a/packages/block-library/src/shortcode/index.js
+++ b/packages/block-library/src/shortcode/index.js
@@ -10,14 +10,16 @@ import edit from './edit';
 import icon from './icon';
 import save from './save';
 import transforms from './transforms';
+import metadata from './block.json';
 
-export const name = 'core/shortcode';
+const { name } = metadata;
+
+export { metadata, name };
 
 export const settings = {
 	title: __( 'Shortcode' ),
 	description: __( 'Insert additional custom elements with a WordPress shortcode.' ),
 	icon,
-	category: 'widgets',
 	transforms,
 	supports: {
 		customClassName: false,
diff --git a/packages/block-library/src/shortcode/index.php b/packages/block-library/src/shortcode/index.php
index 79df091f8a3d3c..ce227a16df5622 100644
--- a/packages/block-library/src/shortcode/index.php
+++ b/packages/block-library/src/shortcode/index.php
@@ -21,15 +21,12 @@ function render_block_core_shortcode( $attributes, $content ) {
  * Registers the `core/shortcode` block on server.
  */
 function register_block_core_shortcode() {
+	$path     = __DIR__ . '/shortcode.json';
+	$metadata = json_decode( file_get_contents( $path ), true );
 	register_block_type(
 		'core/shortcode',
 		array(
-			'attributes'      => array(
-				'text' => array(
-					'type'   => 'string',
-					'source' => 'html',
-				),
-			),
+			'attributes'      => $metadata['attributes'],
 			'render_callback' => 'render_block_core_shortcode',
 		)
 	);
diff --git a/packages/block-library/src/shortcode/style.native.scss b/packages/block-library/src/shortcode/style.native.scss
new file mode 100644
index 00000000000000..a786ad4141ae22
--- /dev/null
+++ b/packages/block-library/src/shortcode/style.native.scss
@@ -0,0 +1,37 @@
+.blockTitle {
+	font-family: $default-regular-font;
+	font-weight: 500;
+	font-size: 10px;
+	color: rgba($black, 0.6);
+	text-transform: uppercase;
+	letter-spacing: 0.4px;
+}
+
+.blockTitleDark {
+	color: rgba($white, 0.6);
+}
+
+.blockShortcode {
+	font-family: $default-monospace-font;
+	font-weight: 400;
+	font-size: 14px;
+	padding: 12px;
+	border-radius: 4px;
+	background-color: $gray-light;
+}
+
+.blockShortcodeDark {
+	color: $white;
+	background-color: $gray-100;
+}
+
+.placeholder {
+	font-family: $default-monospace-font;
+	font-weight: 400;
+	font-size: 14px;
+	color: rgba($black, 0.25);
+}
+
+.placeholderDark {
+	color: $gray-50;
+}
diff --git a/packages/block-library/src/shortcode/test/edit.native.js b/packages/block-library/src/shortcode/test/edit.native.js
new file mode 100644
index 00000000000000..bf90133b05b72e
--- /dev/null
+++ b/packages/block-library/src/shortcode/test/edit.native.js
@@ -0,0 +1,26 @@
+/**
+ * External dependencies
+ */
+import renderer from 'react-test-renderer';
+
+/**
+ * Internal dependencies
+ */
+import Shortcode from '../edit';
+import { TextInput } from 'react-native';
+
+describe( 'Shortcode', () => {
+	it( 'renders without crashing', () => {
+		const component = renderer.create( <Shortcode attributes={ { text: '' } } /> );
+		const rendered = component.toJSON();
+		expect( rendered ).toBeTruthy();
+	} );
+
+	it( 'renders given text without crashing', () => {
+		const component = renderer.create( <Shortcode attributes={ { text: '[youtube https://www.youtube.com/watch?v=ssfHW5lwFZg]' } } /> );
+		const testInstance = component.root;
+		const textInput = testInstance.findByType( TextInput );
+		expect( textInput ).toBeTruthy();
+		expect( textInput.props.value ).toBe( '[youtube https://www.youtube.com/watch?v=ssfHW5lwFZg]' );
+	} );
+} );
diff --git a/test/integration/shortcode-converter.test.js b/test/integration/shortcode-converter.test.js
index 305301e0237bb5..1690bdebc5a654 100644
--- a/test/integration/shortcode-converter.test.js
+++ b/test/integration/shortcode-converter.test.js
@@ -129,9 +129,8 @@ describe( 'segmentHTMLToShortcodeBlock', () => {
 
 	it( 'should not convert a shortcode to a block type with a failing `isMatch`', () => {
 		const original = `<p>[my-broccoli id="1000"]</p>`;
-
 		const transformed = segmentHTMLToShortcodeBlock( original, 0 );
-		const expectedBlock = createBlock( 'core/shortcode' );
+		const expectedBlock = createBlock( 'core/shortcode', { text: '[my-broccoli id="1000"]' } );
 		expectedBlock.clientId = transformed[ 1 ].clientId;
 		expect( transformed[ 1 ] ).toEqual( expectedBlock );
 	} );
@@ -146,7 +145,7 @@ describe( 'segmentHTMLToShortcodeBlock', () => {
 		firstExpectedBlock.clientId = transformed[ 1 ].clientId;
 		const secondExpectedBlock = createBlock( 'test/broccoli', { id: 42 } );
 		secondExpectedBlock.clientId = transformed[ 3 ].clientId;
-		const thirdExpectedBlock = createBlock( 'core/shortcode' );
+		const thirdExpectedBlock = createBlock( 'core/shortcode', { text: '[my-broccoli id="1000"]' } );
 		thirdExpectedBlock.clientId = transformed[ 5 ].clientId;
 		expect( transformed[ 1 ] ).toEqual( firstExpectedBlock );
 		expect( transformed[ 3 ] ).toEqual( secondExpectedBlock );
diff --git a/webpack.config.js b/webpack.config.js
index 586a28df6d5001..0f7f5bb91039a8 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -150,6 +150,13 @@ module.exports = {
 				},
 			},
 		] ),
+		new CopyWebpackPlugin( [
+			{
+				from: './packages/block-library/src/+(shortcode)/block.json',
+				test: new RegExp( `([\\w-]+)${ escapeRegExp( sep ) }block\\.json$` ),
+				to: 'build/block-library/blocks/[1].json',
+			},
+		] ),
 		new DependencyExtractionWebpackPlugin( { injectPolyfill: true } ),
 	],
 	devtool,