Skip to content

Commit

Permalink
[RNMobile] Social icons (#23017)
Browse files Browse the repository at this point in the history
  • Loading branch information
lukewalczak authored Jul 9, 2020
1 parent e8daf61 commit d4bdb05
Show file tree
Hide file tree
Showing 13 changed files with 823 additions and 366 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const BlockSelectionButton = ( {
rootBlockIcon && [
<Icon
key="parent-icon"
size={ 20 }
size={ 24 }
icon={ rootBlockIcon.src }
fill={ styles.icon.color }
/>,
Expand Down
67 changes: 38 additions & 29 deletions packages/block-editor/src/components/block-list/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -312,41 +312,50 @@ export class BlockList extends Component {
}

export default compose( [
withSelect( ( select, { rootClientId, orientation } ) => {
const {
getBlockCount,
getBlockOrder,
getSelectedBlockClientId,
isBlockInsertionPointVisible,
getSettings,
getBlockHierarchyRootClientId,
} = select( 'core/block-editor' );
withSelect(
( select, { rootClientId, orientation, filterInnerBlocks } ) => {
const {
getBlockCount,
getBlockOrder,
getSelectedBlockClientId,
isBlockInsertionPointVisible,
getSettings,
getBlockHierarchyRootClientId,
} = select( 'core/block-editor' );

const isStackedHorizontally = orientation === 'horizontal';
const isStackedHorizontally = orientation === 'horizontal';

const selectedBlockClientId = getSelectedBlockClientId();
const blockClientIds = getBlockOrder( rootClientId );
const selectedBlockClientId = getSelectedBlockClientId();

const isReadOnly = getSettings().readOnly;
let blockClientIds = getBlockOrder( rootClientId );
// Display only block which fulfill the condition in passed `filterInnerBlocks` function
if ( filterInnerBlocks ) {
blockClientIds = filterInnerBlocks( blockClientIds );
}

const rootBlockId = getBlockHierarchyRootClientId(
selectedBlockClientId
);
const hasRootInnerBlocks = !! getBlockCount( rootBlockId );
const isReadOnly = getSettings().readOnly;

const isFloatingToolbarVisible =
!! selectedBlockClientId && hasRootInnerBlocks;
const blockCount = getBlockCount( rootBlockId );

return {
blockClientIds,
blockCount: getBlockCount( rootClientId ),
isBlockInsertionPointVisible: isBlockInsertionPointVisible(),
isReadOnly,
isRootList: rootClientId === undefined,
isFloatingToolbarVisible,
isStackedHorizontally,
};
} ),
const rootBlockId = getBlockHierarchyRootClientId(
selectedBlockClientId
);
const hasRootInnerBlocks = !! blockCount;

const isFloatingToolbarVisible =
!! selectedBlockClientId && hasRootInnerBlocks;

return {
blockClientIds,
blockCount,
isBlockInsertionPointVisible: isBlockInsertionPointVisible(),
isReadOnly,
isRootList: rootClientId === undefined,
isFloatingToolbarVisible,
isStackedHorizontally,
};
}
),
withDispatch( ( dispatch ) => {
const { insertBlock, replaceBlock, clearSelectedBlock } = dispatch(
'core/block-editor'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ function UncontrolledInnerBlocks( props ) {
marginVertical,
marginHorizontal,
horizontalAlignment,
filterInnerBlocks,
} = props;

const block = useSelect(
Expand Down Expand Up @@ -80,6 +81,7 @@ function UncontrolledInnerBlocks( props ) {
contentStyle={ contentStyle }
onAddBlock={ onAddBlock }
onDeleteBlock={ onDeleteBlock }
filterInnerBlocks={ filterInnerBlocks }
/>
);

Expand Down
33 changes: 31 additions & 2 deletions packages/block-library/src/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* External dependencies
*/
import { Platform } from 'react-native';
import { sortBy } from 'lodash';

/**
* WordPress dependencies
Expand Down Expand Up @@ -60,6 +61,8 @@ import * as tagCloud from './tag-cloud';
import * as classic from './classic';
import * as group from './group';
import * as buttons from './buttons';
import * as socialLink from './social-link';
import * as socialLinks from './social-links';

export const coreBlocks = [
// Common blocks are grouped at the top to prioritize their display
Expand Down Expand Up @@ -108,6 +111,8 @@ export const coreBlocks = [
video,
classic,
buttons,
socialLink,
socialLinks,
].reduce( ( accumulator, block ) => {
accumulator[ block.name ] = block;
return accumulator;
Expand All @@ -130,20 +135,41 @@ const registerBlock = ( block ) => {
} );
};

/**
* Function to register a block variations e.g. social icons different types.
*
* @param {Object} block The block which variations will be registered.
*
*/
const registerBlockVariations = ( block ) => {
const { metadata, settings, name } = block;

sortBy( settings.variations, 'title' ).forEach( ( v ) => {
registerBlockType( `${ name }-${ v.name }`, {
...metadata,
name: `${ name }-${ v.name }`,
...settings,
icon: v.icon(),
title: v.title,
} );
} );
};

// only enable code block for development
// eslint-disable-next-line no-undef
const devOnly = ( block ) => ( !! __DEV__ ? block : null );

const iOSOnly = ( block ) =>
Platform.OS === 'ios' ? block : devOnly( block );

// Hide the Classic block
// Hide the Classic block and SocialLink block
addFilter(
'blocks.registerBlockType',
'core/react-native-editor',
( settings, name ) => {
const hiddenBlocks = [ 'core/freeform', 'core/social-link' ];
if (
name === 'core/freeform' &&
hiddenBlocks.includes( name ) &&
hasBlockSupport( settings, 'inserter', true )
) {
settings.supports = {
Expand Down Expand Up @@ -193,9 +219,12 @@ export const registerCoreBlocks = () => {
latestPosts,
verse,
cover,
socialLink,
socialLinks,
iOSOnly( pullquote ),
].forEach( registerBlock );

registerBlockVariations( socialLink );
setDefaultBlockName( paragraph.name );
setFreeformContentHandlerName( classic.name );
setUnregisteredTypeHandlerName( missing.name );
Expand Down
209 changes: 209 additions & 0 deletions packages/block-library/src/social-link/edit.native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
/**
* External dependencies
*/
import { View, Animated, Easing, TouchableWithoutFeedback } from 'react-native';

/**
* WordPress dependencies
*/
import { BlockControls } from '@wordpress/block-editor';
import { useEffect, useState, useRef } from '@wordpress/element';
import {
ToolbarGroup,
ToolbarButton,
LinkSettings,
} from '@wordpress/components';
import { compose, usePreferredColorSchemeStyle } from '@wordpress/compose';
import { __, sprintf } from '@wordpress/i18n';
import { link, Icon } from '@wordpress/icons';
import { withSelect } from '@wordpress/data';
/**
* Internal dependencies
*/
import { getIconBySite, getNameBySite } from './social-list';
import styles from './editor.scss';

const ANIMATION_DELAY = 300;
const ANIMATION_DURATION = 400;

const linkSettingsOptions = {
url: {
label: __( 'URL' ),
placeholder: __( 'Add URL' ),
autoFocus: true,
},
linkLabel: {
label: __( 'Link label' ),
placeholder: __( 'None' ),
},
footer: {
label: __( 'Briefly describe the link to help screen reader user' ),
},
};

const SocialLinkEdit = ( {
attributes,
setAttributes,
isSelected,
onFocus,
name,
} ) => {
const { url, service = name } = attributes;
const [ isLinkSheetVisible, setIsLinkSheetVisible ] = useState( false );
const [ hasUrl, setHasUrl ] = useState( !! url );

const activeIcon =
styles[ `wp-social-link-${ service }` ] || styles[ `wp-social-link` ];

const inactiveIcon = usePreferredColorSchemeStyle(
styles.inactiveIcon,
styles.inactiveIconDark
);

const animatedValue = useRef( new Animated.Value( 0 ) ).current;

const IconComponent = getIconBySite( service )();
const socialLinkName = getNameBySite( service );

// When new social icon is added link sheet is opened automatically
useEffect( () => {
if ( isSelected && ! url ) {
setIsLinkSheetVisible( true );
}
}, [] );

useEffect( () => {
if ( ! url ) {
setHasUrl( false );
animatedValue.setValue( 0 );
} else if ( url ) {
animateColors();
}
}, [ url ] );

const interpolationColors = {
backgroundColor: animatedValue.interpolate( {
inputRange: [ 0, 1 ],
outputRange: [
inactiveIcon.backgroundColor,
activeIcon.backgroundColor,
],
} ),
color: animatedValue.interpolate( {
inputRange: [ 0, 1 ],
outputRange: [ inactiveIcon.color, activeIcon.color ],
} ),
stroke: '',
};

const { backgroundColor, color, stroke } = hasUrl
? activeIcon
: interpolationColors;

function animateColors() {
Animated.sequence( [
Animated.delay( ANIMATION_DELAY ),
Animated.timing( animatedValue, {
toValue: 1,
duration: ANIMATION_DURATION,
easing: Easing.circle,
} ),
] ).start( () => setHasUrl( true ) );
}

function onCloseSettingsSheet() {
setIsLinkSheetVisible( false );
}

function onOpenSettingsSheet() {
setIsLinkSheetVisible( true );
}

function onEmptyURL() {
animatedValue.setValue( 0 );
setHasUrl( false );
}

function onIconPress() {
if ( isSelected ) {
setIsLinkSheetVisible( true );
} else {
onFocus();
}
}

const accessibilityHint = url
? sprintf(
// translators: %s: social link name e.g: "Instagram".
__( '%s has URL set' ),
socialLinkName
)
: sprintf(
// translators: %s: social link name e.g: "Instagram".
__( '%s has no URL set' ),
socialLinkName
);

return (
<View>
{ isSelected && (
<BlockControls>
<ToolbarGroup>
<ToolbarButton
title={ sprintf(
// translators: %s: social link name e.g: "Instagram".
__( 'Add link to %s' ),
socialLinkName
) }
icon={ link }
onClick={ onOpenSettingsSheet }
isActive={ url }
/>
</ToolbarGroup>
</BlockControls>
) }
<LinkSettings
isVisible={ isLinkSheetVisible }
attributes={ attributes }
onEmptyURL={ onEmptyURL }
onClose={ onCloseSettingsSheet }
setAttributes={ setAttributes }
options={ linkSettingsOptions }
withBottomSheet={ true }
/>
<TouchableWithoutFeedback
onPress={ onIconPress }
accessibilityRole={ 'button' }
accessibilityLabel={ sprintf(
// translators: %s: social link name e.g: "Instagram".
__( '%s social icon' ),
socialLinkName
) }
accessibilityHint={ accessibilityHint }
>
<Animated.View
style={ [ styles.iconContainer, { backgroundColor } ] }
>
<Icon
animated
icon={ IconComponent }
style={ { stroke, color } }
/>
</Animated.View>
</TouchableWithoutFeedback>
</View>
);
};

export default compose( [
withSelect( ( select, { clientId } ) => {
const { getBlock } = select( 'core/block-editor' );

const block = getBlock( clientId );
const name = block?.name.substring( 17 );

return {
name,
};
} ),
] )( SocialLinkEdit );
Loading

0 comments on commit d4bdb05

Please sign in to comment.