Skip to content
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
6 changes: 6 additions & 0 deletions extensions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,3 +233,9 @@ The build pipeline also supports [Color studio](https://github.com/Automattic/co
### Icons

Please use outline versions of [Material icons](https://material.io/tools/icons/?style=outline) to stay in line with Gutenberg. Don't rely on icons used in WordPress core to avoid visual mixing up with core blocks.

## Native support

This is still very much experimental and subject to change.
React Native support for Jetpack blocks is being added as part of the WordPress [Android](https://github.com/wordpress-mobile/WordPress-Android) and [iOS](https://github.com/wordpress-mobile/WordPress-iOS) apps.
A react-native build configuration will attempt to resolve `.native.js` extensions before `.js` ones, making `.native.js` a simple approach to write "cross-platform" gutenberg blocks.
117 changes: 117 additions & 0 deletions extensions/blocks/contact-info/address/edit.native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/**
* External dependencies
*/
import { View } from 'react-native';
import { __ } from '@wordpress/i18n';
import { Component, Fragment } from '@wordpress/element';
import { PlainText } from '@wordpress/block-editor';
import { ToggleControl } from '@wordpress/components';

class AddressEdit extends Component {
constructor( ...args ) {
super( ...args );

this.preventEnterKey = this.preventEnterKey.bind( this );
}

preventEnterKey( event ) {
if ( event.key === 'Enter' ) {
event.preventDefault();
return;
}
}

render() {
const {
attributes: {
address,
addressLine2,
addressLine3,
city,
region,
postal,
country,
linkToGoogleMaps,
},
setAttributes,
onFocus,
} = this.props;

const externalLink = (
<ToggleControl
label={ __( 'Link address to Google Maps', 'jetpack' ) }
checked={ linkToGoogleMaps }
onChange={ newlinkToGoogleMaps => {
setAttributes( { linkToGoogleMaps: newlinkToGoogleMaps } );
onFocus();
} }
/>
);

return (
<View>
<Fragment>
<PlainText
value={ address }
placeholder={ __( 'Street Address', 'jetpack' ) }
aria-label={ __( 'Street Address', 'jetpack' ) }
onChange={ newAddress => setAttributes( { address: newAddress } ) }
onKeyDown={ this.preventEnterKey }
onFocus={ onFocus }
/>
<PlainText
value={ addressLine2 }
placeholder={ __( 'Address Line 2', 'jetpack' ) }
aria-label={ __( 'Address Line 2', 'jetpack' ) }
onChange={ newAddressLine2 => setAttributes( { addressLine2: newAddressLine2 } ) }
onKeyDown={ this.preventEnterKey }
onFocus={ onFocus }
/>
<PlainText
value={ addressLine3 }
placeholder={ __( 'Address Line 3', 'jetpack' ) }
aria-label={ __( 'Address Line 3', 'jetpack' ) }
onChange={ newAddressLine3 => setAttributes( { addressLine3: newAddressLine3 } ) }
onKeyDown={ this.preventEnterKey }
onFocus={ onFocus }
/>
<PlainText
value={ city }
placeholder={ __( 'City', 'jetpack' ) }
aria-label={ __( 'City', 'jetpack' ) }
onChange={ newCity => setAttributes( { city: newCity } ) }
onKeyDown={ this.preventEnterKey }
onFocus={ onFocus }
/>
<PlainText
value={ region }
placeholder={ __( 'State/Province/Region', 'jetpack' ) }
aria-label={ __( 'State/Province/Region', 'jetpack' ) }
onChange={ newRegion => setAttributes( { region: newRegion } ) }
onKeyDown={ this.preventEnterKey }
onFocus={ onFocus }
/>
<PlainText
value={ postal }
placeholder={ __( 'Postal/Zip Code', 'jetpack' ) }
aria-label={ __( 'Postal/Zip Code', 'jetpack' ) }
onChange={ newPostal => setAttributes( { postal: newPostal } ) }
onKeyDown={ this.preventEnterKey }
onFocus={ onFocus }
/>
<PlainText
value={ country }
placeholder={ __( 'Country', 'jetpack' ) }
aria-label={ __( 'Country', 'jetpack' ) }
onChange={ newCountry => setAttributes( { country: newCountry } ) }
onKeyDown={ this.preventEnterKey }
onFocus={ onFocus }
/>
{ externalLink }
</Fragment>
</View>
);
}
}

export default AddressEdit;
41 changes: 41 additions & 0 deletions extensions/blocks/contact-info/edit.native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* External dependencies
*/
import { InnerBlocks } from '@wordpress/block-editor';
import { View } from 'react-native';

/**
* Internal dependencies
*/
const ALLOWED_BLOCKS = [
'jetpack/address',
'jetpack/email',
'jetpack/phone',
'core/paragraph',
'core/image',
'core/heading',
'core/gallery',
'core/list',
'core/quote',
'core/shortcode',
'core/audio',
'core/code',
'core/cover',
'core/html',
'core/separator',
'core/spacer',
'core/subhead',
'core/video',
];

const TEMPLATE = [ [ 'jetpack/email' ], [ 'jetpack/phone' ], [ 'jetpack/address' ] ];

const ContactInfoEdit = () => {
return (
<View>
<InnerBlocks allowedBlocks={ ALLOWED_BLOCKS } templateLock={ false } template={ TEMPLATE } />
</View>
);
};

export default ContactInfoEdit;
7 changes: 7 additions & 0 deletions extensions/editor.native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* Internal dependencies
*/
import './shared/block-category';

// Register blocks
import './blocks/contact-info/editor';
63 changes: 63 additions & 0 deletions extensions/shared/register-jetpack-block.native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* External dependencies
*/
import { registerBlockType } from '@wordpress/blocks';

/**
* Internal dependencies
*/
import extensionList from '../index.json';
import getJetpackExtensionAvailability from './get-jetpack-extension-availability';

const betaExtensions = extensionList.beta || [];

function requiresPlan( unavailableReason, details ) {
if ( unavailableReason === 'missing_plan' ) {
return details.required_plan;
}
return false;
}

/**
* Registers a gutenberg block if the availability requirements are met.
*
* @param {string} name The block's name.
* @param {object} settings The block's settings.
* @param {object} childBlocks The block's child blocks.
* @returns {object|false} Either false if the block is not available, or the results of `registerBlockType`
*/
export default function registerJetpackBlock( name, settings, childBlocks = [] ) {
const { available, details, unavailableReason } = getJetpackExtensionAvailability( name );

const requiredPlan = requiresPlan( unavailableReason, details );

if ( ! available && ! requiredPlan ) {
if ( 'production' !== process.env.NODE_ENV ) {
// eslint-disable-next-line no-console
console.warn(
`Block ${ name } couldn't be registered because it is unavailable (${ unavailableReason }).`
);
}
return false;
}

const result = registerBlockType( `jetpack/${ name }`, {
...settings,
title: betaExtensions.includes( name ) ? `${ settings.title } (beta)` : settings.title,
edit: settings.edit,
example: requiredPlan ? undefined : settings.example,
} );

if ( 'production' !== process.env.NODE_ENV ) {
// eslint-disable-next-line no-console
console.log( `Block jetpack/${ name } registered.` );
}

// Register child blocks. Using `registerBlockType()` directly avoids availability checks -- if
// their parent is available, we register them all, without checking for their individual availability.
childBlocks.forEach( childBlock =>
registerBlockType( `jetpack/${ childBlock.name }`, childBlock.settings )
);

return result;
}
23 changes: 23 additions & 0 deletions extensions/shared/simple-input.native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* External dependencies
*/
import { PlainText } from '@wordpress/block-editor';
import { View } from 'react-native';

const simpleInput = ( type, props, label, view, onChange ) => {
const { onFocus } = props;
const value = props.attributes[ type ];
return (
<View>
<PlainText
value={ value }
placeholder={ label }
aria-label={ label }
onChange={ onChange }
onFocus={ onFocus }
/>
</View>
);
};

export default simpleInput;