From 48f1a4a18a0eef326b6602b62cab1d65c2f07374 Mon Sep 17 00:00:00 2001 From: Matt Chowning Date: Fri, 16 Oct 2020 10:52:28 -0400 Subject: [PATCH 01/17] Add support for xpost suggestions on mobile --- .../GutenbergBridgeJS2Parent.java | 4 +- .../RNReactNativeGutenbergBridgeModule.java | 9 +- .../mobile/WPAndroidGlue/AddMentionUtil.java | 7 -- .../WPAndroidGlue/ShowSuggestionsUtil.java | 8 ++ .../WPAndroidGlue/WPAndroidGlueCode.java | 14 +-- packages/react-native-bridge/index.js | 8 +- .../java/com/gutenberg/MainApplication.java | 9 +- .../rich-text/src/component/index.native.js | 89 ++++++++++++------- 8 files changed, 99 insertions(+), 49 deletions(-) delete mode 100644 packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/AddMentionUtil.java create mode 100644 packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/ShowSuggestionsUtil.java diff --git a/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergBridgeJS2Parent.java b/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergBridgeJS2Parent.java index f912598e0f498b..6c94893d143df9 100644 --- a/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergBridgeJS2Parent.java +++ b/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/GutenbergBridgeJS2Parent.java @@ -166,7 +166,9 @@ void gutenbergDidRequestUnsupportedBlockFallback(ReplaceUnsupportedBlockCallback void gutenbergDidSendButtonPressedAction(String buttonType); - void onAddMention(Consumer onSuccess); + void onShowUserSuggestions(Consumer onResult); + + void onShowXpostSuggestions(Consumer onResult); void setStarterPageTemplatesTooltipShown(boolean tooltipShown); diff --git a/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/RNReactNativeGutenbergBridgeModule.java b/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/RNReactNativeGutenbergBridgeModule.java index 4a6b844b2f5c10..d00dc5a566a74a 100644 --- a/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/RNReactNativeGutenbergBridgeModule.java +++ b/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/RNReactNativeGutenbergBridgeModule.java @@ -323,8 +323,13 @@ private OtherMediaOptionsReceivedCallback getNewOtherMediaReceivedCallback(final } @ReactMethod - public void addMention(Promise promise) { - mGutenbergBridgeJS2Parent.onAddMention(promise::resolve); + public void showUserSuggestions(Promise promise) { + mGutenbergBridgeJS2Parent.onShowUserSuggestions(promise::resolve); + } + + @ReactMethod + public void showXpostSuggestions(Promise promise) { + mGutenbergBridgeJS2Parent.onShowXpostSuggestions(promise::resolve); } @ReactMethod diff --git a/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/AddMentionUtil.java b/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/AddMentionUtil.java deleted file mode 100644 index 837f10e1562835..00000000000000 --- a/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/AddMentionUtil.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.wordpress.mobile.WPAndroidGlue; - -import androidx.core.util.Consumer; - -public interface AddMentionUtil { - void getMention(Consumer onResult); -} diff --git a/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/ShowSuggestionsUtil.java b/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/ShowSuggestionsUtil.java new file mode 100644 index 00000000000000..cd78ded5b6b242 --- /dev/null +++ b/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/ShowSuggestionsUtil.java @@ -0,0 +1,8 @@ +package org.wordpress.mobile.WPAndroidGlue; + +import androidx.core.util.Consumer; + +public interface ShowSuggestionsUtil { + void showUserSuggestions(Consumer onResult); + void showXpostSuggestions(Consumer onResult); +} diff --git a/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/WPAndroidGlueCode.java b/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/WPAndroidGlueCode.java index b523510db89c4f..4cec5e8d646d0b 100644 --- a/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/WPAndroidGlueCode.java +++ b/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/WPAndroidGlueCode.java @@ -109,7 +109,7 @@ public class WPAndroidGlueCode { private CountDownLatch mGetContentCountDownLatch; private WeakReference mLastFocusedView = null; private RequestExecutor mRequestExecutor; - private AddMentionUtil mAddMentionUtil; + private ShowSuggestionsUtil mShowSuggestionsUtil; private @Nullable Bundle mEditorTheme = null; private static OkHttpHeaderInterceptor sAddCookiesInterceptor = new OkHttpHeaderInterceptor(); @@ -411,8 +411,12 @@ public void gutenbergDidSendButtonPressedAction(String buttonType) { } @Override - public void onAddMention(Consumer onSuccess) { - mAddMentionUtil.getMention(onSuccess); + public void onShowUserSuggestions(Consumer onResult) { + mShowSuggestionsUtil.showUserSuggestions(onResult); + } + + @Override public void onShowXpostSuggestions(Consumer onResult) { + mShowSuggestionsUtil.showXpostSuggestions(onResult); } @Override @@ -531,7 +535,7 @@ public void attachToContainer(ViewGroup viewGroup, OnLogGutenbergUserEventListener onLogGutenbergUserEventListener, OnGutenbergDidRequestUnsupportedBlockFallbackListener onGutenbergDidRequestUnsupportedBlockFallbackListener, OnGutenbergDidSendButtonPressedActionListener onGutenbergDidSendButtonPressedActionListener, - AddMentionUtil addMentionUtil, + ShowSuggestionsUtil showSuggestionsUtil, OnStarterPageTemplatesTooltipShownEventListener onStarterPageTemplatesTooltipListener, OnMediaFilesCollectionBasedBlockEditorListener onMediaFilesCollectionBasedBlockEditorListener, boolean isDarkMode) { @@ -549,7 +553,7 @@ public void attachToContainer(ViewGroup viewGroup, mOnLogGutenbergUserEventListener = onLogGutenbergUserEventListener; mOnGutenbergDidRequestUnsupportedBlockFallbackListener = onGutenbergDidRequestUnsupportedBlockFallbackListener; mOnGutenbergDidSendButtonPressedActionListener = onGutenbergDidSendButtonPressedActionListener; - mAddMentionUtil = addMentionUtil; + mShowSuggestionsUtil = showSuggestionsUtil; mOnStarterPageTemplatesTooltipShownListener = onStarterPageTemplatesTooltipListener; mOnMediaFilesCollectionBasedBlockEditorListener = onMediaFilesCollectionBasedBlockEditorListener; diff --git a/packages/react-native-bridge/index.js b/packages/react-native-bridge/index.js index f7d76c91d53cd5..e5bc1db51a0ab2 100644 --- a/packages/react-native-bridge/index.js +++ b/packages/react-native-bridge/index.js @@ -279,8 +279,12 @@ export function logUserEvent( event, properties ) { return RNReactNativeGutenbergBridge.logUserEvent( event, properties ); } -export function addMention() { - return RNReactNativeGutenbergBridge.addMention(); +export function showUserSuggestions() { + return RNReactNativeGutenbergBridge.showUserSuggestions(); +} + +export function showXpostSuggestions() { + return RNReactNativeGutenbergBridge.showXpostSuggestions(); } export function requestStarterPageTemplatesTooltipShown( callback ) { diff --git a/packages/react-native-editor/android/app/src/main/java/com/gutenberg/MainApplication.java b/packages/react-native-editor/android/app/src/main/java/com/gutenberg/MainApplication.java index 628feb8b8b6dbb..afa269ee7ce1c6 100644 --- a/packages/react-native-editor/android/app/src/main/java/com/gutenberg/MainApplication.java +++ b/packages/react-native-editor/android/app/src/main/java/com/gutenberg/MainApplication.java @@ -189,8 +189,13 @@ public void gutenbergDidRequestUnsupportedBlockFallback(ReplaceUnsupportedBlockC } @Override - public void onAddMention(Consumer onSuccess) { - onSuccess.accept("matt"); + public void onShowUserSuggestions(Consumer onResult) { + onResult.accept("matt"); + } + + @Override + public void onShowXpostSuggestions(Consumer onResult) { + onResult.accept("ma.tt"); } @Override diff --git a/packages/rich-text/src/component/index.native.js b/packages/rich-text/src/component/index.native.js index 7e59d11c094181..2494afa5ed60c5 100644 --- a/packages/rich-text/src/component/index.native.js +++ b/packages/rich-text/src/component/index.native.js @@ -8,7 +8,10 @@ */ import RCTAztecView from '@wordpress/react-native-aztec'; import { View, Platform } from 'react-native'; -import { addMention } from '@wordpress/react-native-bridge'; +import { + showUserSuggestions, + showXpostSuggestions, +} from '@wordpress/react-native-bridge'; import { get, pickBy, debounce } from 'lodash'; import memize from 'memize'; @@ -82,7 +85,6 @@ export class RichText extends Component { this.onKeyDown = this.onKeyDown.bind( this ); this.handleEnter = this.handleEnter.bind( this ); this.handleDelete = this.handleDelete.bind( this ); - this.handleMention = this.handleMention.bind( this ); this.onPaste = this.onPaste.bind( this ); this.onFocus = this.onFocus.bind( this ); this.onBlur = this.onBlur.bind( this ); @@ -100,7 +102,16 @@ export class RichText extends Component { ); this.valueToFormat = this.valueToFormat.bind( this ); this.getHtmlToRender = this.getHtmlToRender.bind( this ); - this.showMention = this.showMention.bind( this ); + this.handleSuggestionFunc = this.handleSuggestionFunc.bind( this ); + this.handleUserSuggestion = this.handleSuggestionFunc( + showUserSuggestions, + '@' + ).bind( this ); + this.handleXpostSuggestion = this.handleSuggestionFunc( + showXpostSuggestions, + '+' + ).bind( this ); + this.triggerKeyCodeHandlers = this.triggerKeyCodeHandlers.bind( this ); this.insertString = this.insertString.bind( this ); this.state = { activeFormats: [], @@ -321,7 +332,7 @@ export class RichText extends Component { this.handleDelete( event ); this.handleEnter( event ); - this.handleMention( event ); + this.handleTriggerKeyCodes( event ); } handleEnter( event ) { @@ -400,33 +411,53 @@ export class RichText extends Component { this.lastAztecEventType = 'input'; } - handleMention( event ) { + handleTriggerKeyCodes( event ) { + const keyCodeHandlers = this.triggerKeyCodeHandlers(); + const { keyCode } = event; + const triggeredKeyCodeChar = Object.keys( keyCodeHandlers ).find( + ( charKey ) => charKey.charCodeAt( 0 ) === keyCode + ); - if ( keyCode !== '@'.charCodeAt( 0 ) ) { - return; + if ( triggeredKeyCodeChar ) { + const record = this.getRecord(); + const text = getTextContent( record ); + // Only respond to the trigger if the selection is on the start of text or the character before is a space + const useTrigger = + text.length === 0 || + record.start === 0 || + text.charAt( record.start - 1 ) === ' '; + + if ( useTrigger ) { + keyCodeHandlers[ triggeredKeyCodeChar ](); + } else { + this.insertString( record, triggeredKeyCodeChar ); + } } - const record = this.getRecord(); - const text = getTextContent( record ); - // Only start the mention UI if the selection is on the start of text or the character before is a space - if ( - text.length === 0 || - record.start === 0 || - text.charAt( record.start - 1 ) === ' ' - ) { - this.showMention(); - } else { - this.insertString( record, '@' ); + } + + triggerKeyCodeHandlers() { + if ( this.props.disableEditingMenu ) { + return {}; } + + return { + '+': this.handleXpostSuggestion, + ...( this.props.isMentionsSupported && { + '@': this.handleUserSuggestion, + } ), + }; } - showMention() { - const record = this.getRecord(); - addMention() - .then( ( mentionUserId ) => { - this.insertString( record, `@${ mentionUserId } ` ); - } ) - .catch( () => {} ); + handleSuggestionFunc( suggestionFunction, prefix ) { + return () => { + const record = this.getRecord(); + suggestionFunction() + .then( ( suggestion ) => { + this.insertString( record, `${ prefix }${ suggestion } ` ); + } ) + .catch( () => {} ); + }; } /** @@ -873,11 +904,9 @@ export class RichText extends Component { onFocus={ this.onFocus } onBlur={ this.onBlur } onKeyDown={ this.onKeyDown } - triggerKeyCodes={ - disableEditingMenu === false && isMentionsSupported - ? [ '@' ] - : [] - } + triggerKeyCodes={ Object.keys( + this.triggerKeyCodeHandlers() + ) } onPaste={ this.onPaste } activeFormats={ this.getActiveFormatNames( record ) } onContentSizeChange={ this.onContentSizeChange } From 409e54915fc987ae22def3004b1e84ee06050ecd Mon Sep 17 00:00:00 2001 From: Paul Von Schrottky Date: Mon, 19 Oct 2020 13:03:31 -0300 Subject: [PATCH 02/17] Add xpost bridge methods for iOS --- .../ios/GutenbergBridgeDelegate.swift | 4 ++++ .../ios/RNReactNativeGutenbergBridge.m | 3 ++- .../ios/RNReactNativeGutenbergBridge.swift | 14 +++++++++++++- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/packages/react-native-bridge/ios/GutenbergBridgeDelegate.swift b/packages/react-native-bridge/ios/GutenbergBridgeDelegate.swift index 2e624791346908..97466bdee69057 100644 --- a/packages/react-native-bridge/ios/GutenbergBridgeDelegate.swift +++ b/packages/react-native-bridge/ios/GutenbergBridgeDelegate.swift @@ -225,6 +225,10 @@ public protocol GutenbergBridgeDelegate: class { /// - Parameter callback: Completion handler to be called with an user mention or an error func gutenbergDidRequestMention(callback: @escaping (Swift.Result) -> Void) + /// Tells the delegate that the editor requested a mention + /// - Parameter callback: Completion handler to be called with an xpost or an error + func gutenbergDidRequestXpost(callback: @escaping (Swift.Result) -> Void) + /// Tells the delegate that the editor requested to show the tooltip func gutenbergDidRequestStarterPageTemplatesTooltipShown() -> Bool diff --git a/packages/react-native-bridge/ios/RNReactNativeGutenbergBridge.m b/packages/react-native-bridge/ios/RNReactNativeGutenbergBridge.m index aafdce5c869aa0..9443cae473c1f3 100644 --- a/packages/react-native-bridge/ios/RNReactNativeGutenbergBridge.m +++ b/packages/react-native-bridge/ios/RNReactNativeGutenbergBridge.m @@ -20,7 +20,8 @@ @interface RCT_EXTERN_MODULE(RNReactNativeGutenbergBridge, NSObject) RCT_EXTERN_METHOD(requestMediaEditor:(NSString *)mediaUrl callback:(RCTResponseSenderBlock)callback) RCT_EXTERN_METHOD(logUserEvent:(NSString *)event properties:(NSDictionary *)properties) RCT_EXTERN_METHOD(requestUnsupportedBlockFallback:(NSString *)content blockId:(NSString *)blockId blockName:(NSString *)blockName blockTitle:(NSString *)blockTitle) -RCT_EXTERN_METHOD(addMention:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)rejecter) +RCT_EXTERN_METHOD(showUserSuggestions:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)rejecter) +RCT_EXTERN_METHOD(showXpostSuggestions:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)rejecter) RCT_EXTERN_METHOD(requestStarterPageTemplatesTooltipShown:(RCTResponseSenderBlock)callback) RCT_EXTERN_METHOD(setStarterPageTemplatesTooltipShown:(BOOL)tooltipShown) RCT_EXTERN_METHOD(requestMediaFilesEditorLoad:(NSArray *)mediaFiles blockId:(NSString *)blockId) diff --git a/packages/react-native-bridge/ios/RNReactNativeGutenbergBridge.swift b/packages/react-native-bridge/ios/RNReactNativeGutenbergBridge.swift index 3d8168ba17e8d4..927a59eb8e0fbe 100644 --- a/packages/react-native-bridge/ios/RNReactNativeGutenbergBridge.swift +++ b/packages/react-native-bridge/ios/RNReactNativeGutenbergBridge.swift @@ -267,7 +267,7 @@ public class RNReactNativeGutenbergBridge: RCTEventEmitter { } @objc - func addMention(_ resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) { + func showUserSuggestions(_ resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) { self.delegate?.gutenbergDidRequestMention(callback: { (result) in switch result { case .success(let mention): @@ -278,6 +278,18 @@ public class RNReactNativeGutenbergBridge: RCTEventEmitter { }) } + @objc + func showXpostSuggestions(_ resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) { + self.delegate?.gutenbergDidRequestXpost(callback: { (result) in + switch result { + case .success(let mention): + resolver([mention]) + case .failure(let error): + rejecter(error.domain, "\(error.code)", error) + } + }) + } + @objc func requestStarterPageTemplatesTooltipShown(_ callback: @escaping RCTResponseSenderBlock) { callback([self.delegate?.gutenbergDidRequestStarterPageTemplatesTooltipShown() ?? false]) From 259b3ece4852c4389be8e89db4e5f8e6d8ca5d66 Mon Sep 17 00:00:00 2001 From: Paul Von Schrottky Date: Mon, 19 Oct 2020 17:39:26 -0300 Subject: [PATCH 03/17] Update @mention toolbar button callback Update it to the new callback function --- packages/rich-text/src/component/index.native.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rich-text/src/component/index.native.js b/packages/rich-text/src/component/index.native.js index 2494afa5ed60c5..b46d5b710c98fa 100644 --- a/packages/rich-text/src/component/index.native.js +++ b/packages/rich-text/src/component/index.native.js @@ -954,7 +954,7 @@ export class RichText extends Component { } - onClick={ this.showMention } + onClick={ this.handleUserSuggestion } /> ) From b1040b0f84f77506d937a3785f9c1a7ecf07d8d7 Mon Sep 17 00:00:00 2001 From: Matt Chowning Date: Thu, 12 Nov 2020 10:35:44 -0500 Subject: [PATCH 04/17] Check for trigger key codes at beginning of lines --- packages/rich-text/src/component/index.native.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/rich-text/src/component/index.native.js b/packages/rich-text/src/component/index.native.js index b46d5b710c98fa..6e65a833c24e6d 100644 --- a/packages/rich-text/src/component/index.native.js +++ b/packages/rich-text/src/component/index.native.js @@ -422,10 +422,12 @@ export class RichText extends Component { if ( triggeredKeyCodeChar ) { const record = this.getRecord(); const text = getTextContent( record ); - // Only respond to the trigger if the selection is on the start of text or the character before is a space + // Only respond to the trigger if the selection is on the start of text or line + // or if the character before is a space const useTrigger = text.length === 0 || record.start === 0 || + text.charAt( record.start - 1 ) === '\n' || text.charAt( record.start - 1 ) === ' '; if ( useTrigger ) { From cf73fbdb3ccc2dec6d63c5544d433b53a3d95e9d Mon Sep 17 00:00:00 2001 From: Matt Chowning Date: Tue, 17 Nov 2020 20:06:43 -0500 Subject: [PATCH 05/17] Add xposts capability handling This is limited to Android at this time --- .../mobile/WPAndroidGlue/GutenbergProps.kt | 3 +++ .../rich-text/src/component/index.native.js | 19 +++++++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/GutenbergProps.kt b/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/GutenbergProps.kt index f9f65dd9c20838..7049bc099c8221 100644 --- a/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/GutenbergProps.kt +++ b/packages/react-native-bridge/android/src/main/java/org/wordpress/mobile/WPAndroidGlue/GutenbergProps.kt @@ -5,6 +5,7 @@ import android.os.Bundle data class GutenbergProps @JvmOverloads constructor( val enableMediaFilesCollectionBlocks: Boolean, val enableMentions: Boolean, + val enableXPosts: Boolean, val enableUnsupportedBlockEditor: Boolean, val canEnableUnsupportedBlockEditor: Boolean, val localeSlug: String, @@ -38,6 +39,7 @@ data class GutenbergProps @JvmOverloads constructor( fun getUpdatedCapabilitiesProps() = Bundle().apply { putBoolean(PROP_CAPABILITIES_MENTIONS, enableMentions) + putBoolean(PROP_CAPABILITIES_XPOSTS, enableXPosts) putBoolean(PROP_CAPABILITIES_MEDIAFILES_COLLECTION_BLOCK, enableMediaFilesCollectionBlocks) putBoolean(PROP_CAPABILITIES_UNSUPPORTED_BLOCK_EDITOR, enableUnsupportedBlockEditor) putBoolean(PROP_CAPABILITIES_CAN_ENABLE_UNSUPPORTED_BLOCK_EDITOR, canEnableUnsupportedBlockEditor) @@ -68,6 +70,7 @@ data class GutenbergProps @JvmOverloads constructor( const val PROP_CAPABILITIES = "capabilities" const val PROP_CAPABILITIES_MEDIAFILES_COLLECTION_BLOCK = "mediaFilesCollectionBlock" const val PROP_CAPABILITIES_MENTIONS = "mentions" + const val PROP_CAPABILITIES_XPOSTS = "xposts" const val PROP_CAPABILITIES_UNSUPPORTED_BLOCK_EDITOR = "unsupportedBlockEditor" const val PROP_CAPABILITIES_CAN_ENABLE_UNSUPPORTED_BLOCK_EDITOR = "canEnableUnsupportedBlockEditor" const val PROP_CAPABILITIES_MODAL_LAYOUT_PICKER = "modalLayoutPicker" diff --git a/packages/rich-text/src/component/index.native.js b/packages/rich-text/src/component/index.native.js index 6e65a833c24e6d..00d4ee74d0c6f0 100644 --- a/packages/rich-text/src/component/index.native.js +++ b/packages/rich-text/src/component/index.native.js @@ -444,8 +444,10 @@ export class RichText extends Component { } return { - '+': this.handleXpostSuggestion, - ...( this.props.isMentionsSupported && { + ...( this.props.areXPostsSupported && { + '+': this.handleXpostSuggestion, + } ), + ...( this.props.areMentionsSupported && { '@': this.handleUserSuggestion, } ), }; @@ -790,7 +792,7 @@ export class RichText extends Component { withoutInteractiveFormatting, accessibilityLabel, disableEditingMenu = false, - isMentionsSupported, + areMentionsSupported, } = this.props; const record = this.getRecord(); @@ -951,12 +953,14 @@ export class RichText extends Component { { // eslint-disable-next-line no-undef - isMentionsSupported && ( + areMentionsSupported && ( } - onClick={ this.handleUserSuggestion } + onClick={ + this.handleUserSuggestion + } /> ) @@ -987,8 +991,11 @@ export default compose( [ return { formatTypes: select( 'core/rich-text' ).getFormatTypes(), - isMentionsSupported: + areMentionsSupported: getSettings( 'capabilities' ).mentions === true, + areXPostsSupported: + getSettings( 'capabilities' ).xposts === true || + Platform.OS === 'ios', ...{ parentBlockStyles }, }; } ), From df7bf4bbfb830409316e74a69d6a9afaf0fda612 Mon Sep 17 00:00:00 2001 From: Paul Von Schrottky Date: Mon, 30 Nov 2020 17:35:22 -0300 Subject: [PATCH 06/17] added xposts capability for iOS --- .../react-native-bridge/ios/GutenbergBridgeDelegate.swift | 1 + packages/rich-text/src/component/index.native.js | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/react-native-bridge/ios/GutenbergBridgeDelegate.swift b/packages/react-native-bridge/ios/GutenbergBridgeDelegate.swift index 97466bdee69057..753515f600a7e3 100644 --- a/packages/react-native-bridge/ios/GutenbergBridgeDelegate.swift +++ b/packages/react-native-bridge/ios/GutenbergBridgeDelegate.swift @@ -18,6 +18,7 @@ public struct MediaInfo: Encodable { public enum Capabilities: String { case mediaFilesCollectionBlock case mentions + case xposts case unsupportedBlockEditor case canEnableUnsupportedBlockEditor case modalLayoutPicker diff --git a/packages/rich-text/src/component/index.native.js b/packages/rich-text/src/component/index.native.js index 00d4ee74d0c6f0..1dae0ef8bab649 100644 --- a/packages/rich-text/src/component/index.native.js +++ b/packages/rich-text/src/component/index.native.js @@ -993,9 +993,7 @@ export default compose( [ formatTypes: select( 'core/rich-text' ).getFormatTypes(), areMentionsSupported: getSettings( 'capabilities' ).mentions === true, - areXPostsSupported: - getSettings( 'capabilities' ).xposts === true || - Platform.OS === 'ios', + areXPostsSupported: getSettings( 'capabilities' ).xposts === true, ...{ parentBlockStyles }, }; } ), From e730f2e6c45ce8ddb33ffae10babefd5c16cb530 Mon Sep 17 00:00:00 2001 From: Paul Von Schrottky Date: Thu, 3 Dec 2020 17:46:10 -0300 Subject: [PATCH 07/17] Add Xpost to toolbar via long-press on @-mentions Long-pressing the @-mentions toolbar button will now let the user add an Xpost or an @-mention --- .../GutenbergViewController.swift | 4 ++ .../rich-text/src/component/index.native.js | 43 ++++++++++++++++++- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/packages/react-native-editor/ios/GutenbergDemo/GutenbergViewController.swift b/packages/react-native-editor/ios/GutenbergDemo/GutenbergViewController.swift index bb1ee8618f2e94..4039bc04df0415 100644 --- a/packages/react-native-editor/ios/GutenbergDemo/GutenbergViewController.swift +++ b/packages/react-native-editor/ios/GutenbergDemo/GutenbergViewController.swift @@ -225,6 +225,10 @@ extension GutenbergViewController: GutenbergBridgeDelegate { callback(.success("matt")) } + func gutenbergDidRequestXpost(callback: @escaping (Result) -> Void) { + callback(.success("ma.tt")) + } + func gutenbergDidRequestStarterPageTemplatesTooltipShown() -> Bool { return false; } diff --git a/packages/rich-text/src/component/index.native.js b/packages/rich-text/src/component/index.native.js index 1dae0ef8bab649..3c1fa270b401db 100644 --- a/packages/rich-text/src/component/index.native.js +++ b/packages/rich-text/src/component/index.native.js @@ -20,14 +20,14 @@ import memize from 'memize'; */ import { BlockFormatControls } from '@wordpress/block-editor'; import { Component } from '@wordpress/element'; -import { Toolbar, ToolbarButton } from '@wordpress/components'; +import { Toolbar, ToolbarButton, Picker } from '@wordpress/components'; import { compose, withPreferredColorScheme } from '@wordpress/compose'; import { withSelect } from '@wordpress/data'; import { childrenBlock } from '@wordpress/blocks'; import { decodeEntities } from '@wordpress/html-entities'; import { BACKSPACE, DELETE, ENTER } from '@wordpress/keycodes'; import { isURL } from '@wordpress/url'; -import { Icon, atSymbol } from '@wordpress/icons'; +import { Icon, atSymbol, plus } from '@wordpress/icons'; import { __ } from '@wordpress/i18n'; /** @@ -111,6 +111,7 @@ export class RichText extends Component { showXpostSuggestions, '+' ).bind( this ); + this.handleSuggestionLongPress = this.handleSuggestionLongPress.bind( this ); this.triggerKeyCodeHandlers = this.triggerKeyCodeHandlers.bind( this ); this.insertString = this.insertString.bind( this ); this.state = { @@ -464,6 +465,12 @@ export class RichText extends Component { }; } + handleSuggestionLongPress() { + if ( this.suggestionPicker ) { + this.suggestionPicker.presentPicker(); + } + } + /** * Handles a paste event from the native Aztec Wrapper. * @@ -866,6 +873,19 @@ export class RichText extends Component { backgroundColor: style.backgroundColor, }; + const onSuggestionPickerSelect = ( suggestionType ) => { + switch (suggestionType) { + case 'mention': + this.handleUserSuggestion(); + break; + case 'xpost': + this.handleXpostSuggestion(); + break; + default: + break; + } + } + return ( { children && @@ -961,6 +981,9 @@ export class RichText extends Component { onClick={ this.handleUserSuggestion } + onLongPress={ + this.handleSuggestionLongPress + } /> ) @@ -968,6 +991,22 @@ export class RichText extends Component { ) } + ( this.suggestionPicker = instance ) } + options={ [ + { + value: 'mention', + label: __( 'Mention' ), + icon: atSymbol, + },{ + value: 'xpost', + label: __( 'Xpost' ), + icon: plus, + } + ] } + onChange={ onSuggestionPickerSelect } + hideCancelButton + /> ); } From 3f2d0c233bf715c97a20a4603a7cbadd27e71b90 Mon Sep 17 00:00:00 2001 From: Paul Von Schrottky Date: Thu, 3 Dec 2020 18:18:26 -0300 Subject: [PATCH 08/17] Updated code formatting --- packages/rich-text/src/component/index.native.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/rich-text/src/component/index.native.js b/packages/rich-text/src/component/index.native.js index 3c1fa270b401db..43c6125cc1bfe9 100644 --- a/packages/rich-text/src/component/index.native.js +++ b/packages/rich-text/src/component/index.native.js @@ -111,7 +111,9 @@ export class RichText extends Component { showXpostSuggestions, '+' ).bind( this ); - this.handleSuggestionLongPress = this.handleSuggestionLongPress.bind( this ); + this.handleSuggestionLongPress = this.handleSuggestionLongPress.bind( + this + ); this.triggerKeyCodeHandlers = this.triggerKeyCodeHandlers.bind( this ); this.insertString = this.insertString.bind( this ); this.state = { @@ -874,7 +876,7 @@ export class RichText extends Component { }; const onSuggestionPickerSelect = ( suggestionType ) => { - switch (suggestionType) { + switch ( suggestionType ) { case 'mention': this.handleUserSuggestion(); break; @@ -884,7 +886,7 @@ export class RichText extends Component { default: break; } - } + }; return ( @@ -998,11 +1000,12 @@ export class RichText extends Component { value: 'mention', label: __( 'Mention' ), icon: atSymbol, - },{ + }, + { value: 'xpost', label: __( 'Xpost' ), icon: plus, - } + }, ] } onChange={ onSuggestionPickerSelect } hideCancelButton From 7e3662a3ec8e50e7f3eb05775e09ff3747ef5067 Mon Sep 17 00:00:00 2001 From: Matt Chowning Date: Tue, 8 Dec 2020 16:59:13 -0500 Subject: [PATCH 09/17] Dynamically update suggestions button --- .../rich-text/src/component/index.native.js | 54 ++++++++++++++----- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/packages/rich-text/src/component/index.native.js b/packages/rich-text/src/component/index.native.js index 43c6125cc1bfe9..7c0fa2197e6a49 100644 --- a/packages/rich-text/src/component/index.native.js +++ b/packages/rich-text/src/component/index.native.js @@ -802,6 +802,7 @@ export class RichText extends Component { accessibilityLabel, disableEditingMenu = false, areMentionsSupported, + areXPostsSupported, } = this.props; const record = this.getRecord(); @@ -975,15 +976,32 @@ export class RichText extends Component { { // eslint-disable-next-line no-undef - areMentionsSupported && ( + ( areMentionsSupported || + areXPostsSupported ) && ( } + title={ + areMentionsSupported + ? __( 'Insert mention' ) + : __( 'Insert crosspost' ) + } + icon={ + + } onClick={ - this.handleUserSuggestion + areMentionsSupported + ? this.handleUserSuggestion + : this.handleXpostSuggestion } onLongPress={ + areMentionsSupported && + areXPostsSupported && this.handleSuggestionLongPress } /> @@ -996,16 +1014,24 @@ export class RichText extends Component { ( this.suggestionPicker = instance ) } options={ [ - { - value: 'mention', - label: __( 'Mention' ), - icon: atSymbol, - }, - { - value: 'xpost', - label: __( 'Xpost' ), - icon: plus, - }, + ...( areMentionsSupported + ? [ + { + value: 'mention', + label: __( 'Mention' ), + icon: atSymbol, + }, + ] + : [] ), + ...( areXPostsSupported + ? [ + { + value: 'xpost', + label: __( 'Xpost' ), + icon: plus, + }, + ] + : [] ), ] } onChange={ onSuggestionPickerSelect } hideCancelButton From 5b4d3564b85bab43875e422006ba0e39a354da70 Mon Sep 17 00:00:00 2001 From: Matt Chowning Date: Wed, 9 Dec 2020 09:56:17 -0500 Subject: [PATCH 10/17] Update snapshot tests broken by xpost modal The addition of the xposts modal in e730f2e6c45ce8ddb33ffae10babefd5c16cb530 broke these snapshot tests. --- .../src/file/test/__snapshots__/edit.native.js.snap | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/block-library/src/file/test/__snapshots__/edit.native.js.snap b/packages/block-library/src/file/test/__snapshots__/edit.native.js.snap index a4f88395a19e90..35be1c62188398 100644 --- a/packages/block-library/src/file/test/__snapshots__/edit.native.js.snap +++ b/packages/block-library/src/file/test/__snapshots__/edit.native.js.snap @@ -94,6 +94,7 @@ exports[`File block renders file error state without crashing 1`] = ` textAlign="left" triggerKeyCodes={Array []} /> + Modal Svg @@ -186,6 +187,7 @@ exports[`File block renders file error state without crashing 1`] = ` textAlign="center" triggerKeyCodes={Array []} /> + Modal @@ -286,6 +288,7 @@ exports[`File block renders file without crashing 1`] = ` textAlign="left" triggerKeyCodes={Array []} /> + Modal + Modal From 1df18c85742d2251d5474c33effe47b326f13b8c Mon Sep 17 00:00:00 2001 From: Matt Chowning Date: Thu, 10 Dec 2020 04:43:08 -0500 Subject: [PATCH 11/17] Extract suggestions format button component --- .../rich-text/src/component/index.native.js | 93 ++----------------- .../src/component/suggestions.native.js | 86 +++++++++++++++++ 2 files changed, 95 insertions(+), 84 deletions(-) create mode 100644 packages/rich-text/src/component/suggestions.native.js diff --git a/packages/rich-text/src/component/index.native.js b/packages/rich-text/src/component/index.native.js index 7c0fa2197e6a49..c34bcf60ac4d4f 100644 --- a/packages/rich-text/src/component/index.native.js +++ b/packages/rich-text/src/component/index.native.js @@ -20,15 +20,12 @@ import memize from 'memize'; */ import { BlockFormatControls } from '@wordpress/block-editor'; import { Component } from '@wordpress/element'; -import { Toolbar, ToolbarButton, Picker } from '@wordpress/components'; import { compose, withPreferredColorScheme } from '@wordpress/compose'; import { withSelect } from '@wordpress/data'; import { childrenBlock } from '@wordpress/blocks'; import { decodeEntities } from '@wordpress/html-entities'; import { BACKSPACE, DELETE, ENTER } from '@wordpress/keycodes'; import { isURL } from '@wordpress/url'; -import { Icon, atSymbol, plus } from '@wordpress/icons'; -import { __ } from '@wordpress/i18n'; /** * Internal dependencies @@ -46,6 +43,7 @@ import { removeLineSeparator } from '../remove-line-separator'; import { isCollapsed } from '../is-collapsed'; import { remove } from '../remove'; import styles from './style.scss'; +import SuggestionToolbarButton from './suggestions.native'; const unescapeSpaces = ( text ) => { return text.replace( / | /gi, ' ' ); @@ -111,9 +109,6 @@ export class RichText extends Component { showXpostSuggestions, '+' ).bind( this ); - this.handleSuggestionLongPress = this.handleSuggestionLongPress.bind( - this - ); this.triggerKeyCodeHandlers = this.triggerKeyCodeHandlers.bind( this ); this.insertString = this.insertString.bind( this ); this.state = { @@ -467,12 +462,6 @@ export class RichText extends Component { }; } - handleSuggestionLongPress() { - if ( this.suggestionPicker ) { - this.suggestionPicker.presentPicker(); - } - } - /** * Handles a paste event from the native Aztec Wrapper. * @@ -876,19 +865,6 @@ export class RichText extends Component { backgroundColor: style.backgroundColor, }; - const onSuggestionPickerSelect = ( suggestionType ) => { - switch ( suggestionType ) { - case 'mention': - this.handleUserSuggestion(); - break; - case 'xpost': - this.handleXpostSuggestion(); - break; - default: - break; - } - }; - return ( { children && @@ -974,68 +950,17 @@ export class RichText extends Component { onFocus={ () => {} } /> - { - // eslint-disable-next-line no-undef - ( areMentionsSupported || - areXPostsSupported ) && ( - - - } - onClick={ - areMentionsSupported - ? this.handleUserSuggestion - : this.handleXpostSuggestion - } - onLongPress={ - areMentionsSupported && - areXPostsSupported && - this.handleSuggestionLongPress - } - /> - - ) - } + ) } - ( this.suggestionPicker = instance ) } - options={ [ - ...( areMentionsSupported - ? [ - { - value: 'mention', - label: __( 'Mention' ), - icon: atSymbol, - }, - ] - : [] ), - ...( areXPostsSupported - ? [ - { - value: 'xpost', - label: __( 'Xpost' ), - icon: plus, - }, - ] - : [] ), - ] } - onChange={ onSuggestionPickerSelect } - hideCancelButton - /> ); } diff --git a/packages/rich-text/src/component/suggestions.native.js b/packages/rich-text/src/component/suggestions.native.js new file mode 100644 index 00000000000000..13c6264009be1e --- /dev/null +++ b/packages/rich-text/src/component/suggestions.native.js @@ -0,0 +1,86 @@ +/** + * WordPress dependencies + */ +import { Picker, Toolbar, ToolbarButton } from '@wordpress/components'; +import { useRef } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; +import { atSymbol, Icon, plus } from '@wordpress/icons'; + +export default function SuggestionToolbarButton( { + areMentionsSupported, + areXPostsSupported, + onUserSuggestionsTriggered, + onXPostsTriggered, +} ) { + const picker = useRef(); + function presentPicker() { + if ( picker.current ) { + picker.current.presentPicker(); + } + } + + const mentionKey = 'mention'; + const xpostKey = 'xpost'; + function onSuggestionTypeSelected( suggestionType ) { + switch ( suggestionType ) { + case mentionKey: + onUserSuggestionsTriggered(); + break; + case xpostKey: + onXPostsTriggered(); + break; + default: + break; + } + } + + return ( + ( areMentionsSupported || areXPostsSupported ) && ( + <> + + + } + onClick={ + areMentionsSupported + ? onUserSuggestionsTriggered + : onXPostsTriggered + } + onLongPress={ + areMentionsSupported && + areXPostsSupported && + presentPicker + } + /> + + { areMentionsSupported && areXPostsSupported && ( + + ) } + + ) + ); +} From 056125ff694b1a57586fbc7c8b04bb55987ba254 Mon Sep 17 00:00:00 2001 From: Matt Chowning Date: Thu, 10 Dec 2020 06:30:16 -0500 Subject: [PATCH 12/17] Make suggestions toolbar button generic --- .../rich-text/src/component/index.native.js | 74 ++++++++-------- .../src/component/suggestions.native.js | 86 ------------------- .../toolbar-button-with-options.native.js | 58 +++++++++++++ 3 files changed, 97 insertions(+), 121 deletions(-) delete mode 100644 packages/rich-text/src/component/suggestions.native.js create mode 100644 packages/rich-text/src/component/toolbar-button-with-options.native.js diff --git a/packages/rich-text/src/component/index.native.js b/packages/rich-text/src/component/index.native.js index c34bcf60ac4d4f..f3844c928f5ef5 100644 --- a/packages/rich-text/src/component/index.native.js +++ b/packages/rich-text/src/component/index.native.js @@ -26,6 +26,8 @@ import { childrenBlock } from '@wordpress/blocks'; import { decodeEntities } from '@wordpress/html-entities'; import { BACKSPACE, DELETE, ENTER } from '@wordpress/keycodes'; import { isURL } from '@wordpress/url'; +import { atSymbol, plus } from '@wordpress/icons'; +import { __ } from '@wordpress/i18n'; /** * Internal dependencies @@ -43,7 +45,7 @@ import { removeLineSeparator } from '../remove-line-separator'; import { isCollapsed } from '../is-collapsed'; import { remove } from '../remove'; import styles from './style.scss'; -import SuggestionToolbarButton from './suggestions.native'; +import ToolbarButtonWithOptions from './toolbar-button-with-options'; const unescapeSpaces = ( text ) => { return text.replace( / | /gi, ' ' ); @@ -109,7 +111,7 @@ export class RichText extends Component { showXpostSuggestions, '+' ).bind( this ); - this.triggerKeyCodeHandlers = this.triggerKeyCodeHandlers.bind( this ); + this.suggestionOptions = this.suggestionOptions.bind( this ); this.insertString = this.insertString.bind( this ); this.state = { activeFormats: [], @@ -410,14 +412,13 @@ export class RichText extends Component { } handleTriggerKeyCodes( event ) { - const keyCodeHandlers = this.triggerKeyCodeHandlers(); - const { keyCode } = event; - const triggeredKeyCodeChar = Object.keys( keyCodeHandlers ).find( - ( charKey ) => charKey.charCodeAt( 0 ) === keyCode - ); + const triggeredOption = this.suggestionOptions().find( ( option ) => { + const triggeredKeyCode = option.triggerChar.charCodeAt( 0 ); + return triggeredKeyCode === keyCode; + } ); - if ( triggeredKeyCodeChar ) { + if ( triggeredOption ) { const record = this.getRecord(); const text = getTextContent( record ); // Only respond to the trigger if the selection is on the start of text or line @@ -428,27 +429,37 @@ export class RichText extends Component { text.charAt( record.start - 1 ) === '\n' || text.charAt( record.start - 1 ) === ' '; - if ( useTrigger ) { - keyCodeHandlers[ triggeredKeyCodeChar ](); + if ( useTrigger && triggeredOption.onClick ) { + triggeredOption.onClick(); } else { - this.insertString( record, triggeredKeyCodeChar ); + this.insertString( record, triggeredOption.triggerChar ); } } } - triggerKeyCodeHandlers() { - if ( this.props.disableEditingMenu ) { - return {}; - } - - return { - ...( this.props.areXPostsSupported && { - '+': this.handleXpostSuggestion, - } ), - ...( this.props.areMentionsSupported && { - '@': this.handleUserSuggestion, - } ), - }; + suggestionOptions() { + const { areMentionsSupported, areXPostsSupported } = this.props; + const allOptions = [ + { + supported: areMentionsSupported, + title: __( 'Insert mention' ), + onClick: this.handleUserSuggestion, + triggerChar: '@', + value: 'mention', + label: __( 'Mention' ), + icon: atSymbol, + }, + { + supported: areXPostsSupported, + title: __( 'Insert crosspost' ), + onClick: this.handleXpostSuggestion, + triggerChar: '+', + value: 'crosspost', + label: __( 'Crosspost' ), + icon: plus, + }, + ]; + return allOptions.filter( ( op ) => op.supported ); } handleSuggestionFunc( suggestionFunction, prefix ) { @@ -790,8 +801,6 @@ export class RichText extends Component { withoutInteractiveFormatting, accessibilityLabel, disableEditingMenu = false, - areMentionsSupported, - areXPostsSupported, } = this.props; const record = this.getRecord(); @@ -907,8 +916,8 @@ export class RichText extends Component { onFocus={ this.onFocus } onBlur={ this.onBlur } onKeyDown={ this.onKeyDown } - triggerKeyCodes={ Object.keys( - this.triggerKeyCodeHandlers() + triggerKeyCodes={ this.suggestionOptions().map( + ( op ) => op.triggerChar ) } onPaste={ this.onPaste } activeFormats={ this.getActiveFormatNames( record ) } @@ -950,13 +959,8 @@ export class RichText extends Component { onFocus={ () => {} } /> - diff --git a/packages/rich-text/src/component/suggestions.native.js b/packages/rich-text/src/component/suggestions.native.js deleted file mode 100644 index 13c6264009be1e..00000000000000 --- a/packages/rich-text/src/component/suggestions.native.js +++ /dev/null @@ -1,86 +0,0 @@ -/** - * WordPress dependencies - */ -import { Picker, Toolbar, ToolbarButton } from '@wordpress/components'; -import { useRef } from '@wordpress/element'; -import { __ } from '@wordpress/i18n'; -import { atSymbol, Icon, plus } from '@wordpress/icons'; - -export default function SuggestionToolbarButton( { - areMentionsSupported, - areXPostsSupported, - onUserSuggestionsTriggered, - onXPostsTriggered, -} ) { - const picker = useRef(); - function presentPicker() { - if ( picker.current ) { - picker.current.presentPicker(); - } - } - - const mentionKey = 'mention'; - const xpostKey = 'xpost'; - function onSuggestionTypeSelected( suggestionType ) { - switch ( suggestionType ) { - case mentionKey: - onUserSuggestionsTriggered(); - break; - case xpostKey: - onXPostsTriggered(); - break; - default: - break; - } - } - - return ( - ( areMentionsSupported || areXPostsSupported ) && ( - <> - - - } - onClick={ - areMentionsSupported - ? onUserSuggestionsTriggered - : onXPostsTriggered - } - onLongPress={ - areMentionsSupported && - areXPostsSupported && - presentPicker - } - /> - - { areMentionsSupported && areXPostsSupported && ( - - ) } - - ) - ); -} diff --git a/packages/rich-text/src/component/toolbar-button-with-options.native.js b/packages/rich-text/src/component/toolbar-button-with-options.native.js new file mode 100644 index 00000000000000..aa88ebb736e481 --- /dev/null +++ b/packages/rich-text/src/component/toolbar-button-with-options.native.js @@ -0,0 +1,58 @@ +/** + * WordPress dependencies + */ +import { Picker, Toolbar, ToolbarButton } from '@wordpress/components'; +import { useRef } from '@wordpress/element'; +import { Icon } from '@wordpress/icons'; + +/** + * Toolbar button component that, upon a long press, opens a Picker + * to allow selecting from among multiple options. + */ +function ToolbarButtonWithOptions( { options } ) { + const picker = useRef(); + + function presentPicker() { + if ( picker.current ) { + picker.current.presentPicker(); + } + } + + function onValueSelected( selectedValue ) { + const selectedOption = options.find( + ( op ) => op.value === selectedValue + ); + if ( selectedOption ) { + selectedOption.onClick(); + } + } + + if ( ! options || options.length === 0 ) { + return null; + } + const firstOption = options[ 0 ]; + const enablePicker = options.length > 1; + + return ( + <> + + } + onClick={ firstOption.onClick } + onLongPress={ enablePicker && presentPicker } + /> + + { enablePicker && ( + + ) } + + ); +} + +export default ToolbarButtonWithOptions; From d7ef2ad07e45a61814a2fb3638e6674e3e23ed65 Mon Sep 17 00:00:00 2001 From: Matt Chowning Date: Thu, 10 Dec 2020 06:33:53 -0500 Subject: [PATCH 13/17] Replace Toolbar with ToolbarGroup Because using Toolbar with a label prop is deprecated: https://github.com/WordPress/gutenberg/blob/af768dc98c625e33de8023084c6a5c198c52f8ef/packages/components/src/toolbar/index.js#L30-L34 --- .../src/component/toolbar-button-with-options.native.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/rich-text/src/component/toolbar-button-with-options.native.js b/packages/rich-text/src/component/toolbar-button-with-options.native.js index aa88ebb736e481..81c80f3825c1ac 100644 --- a/packages/rich-text/src/component/toolbar-button-with-options.native.js +++ b/packages/rich-text/src/component/toolbar-button-with-options.native.js @@ -1,7 +1,7 @@ /** * WordPress dependencies */ -import { Picker, Toolbar, ToolbarButton } from '@wordpress/components'; +import { Picker, ToolbarGroup, ToolbarButton } from '@wordpress/components'; import { useRef } from '@wordpress/element'; import { Icon } from '@wordpress/icons'; @@ -35,14 +35,14 @@ function ToolbarButtonWithOptions( { options } ) { return ( <> - + } onClick={ firstOption.onClick } onLongPress={ enablePicker && presentPicker } /> - + { enablePicker && ( Date: Thu, 10 Dec 2020 08:35:21 -0500 Subject: [PATCH 14/17] Update mobile snapshot tests to remove Modal --- .../src/file/test/__snapshots__/edit.native.js.snap | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/block-library/src/file/test/__snapshots__/edit.native.js.snap b/packages/block-library/src/file/test/__snapshots__/edit.native.js.snap index 35be1c62188398..a4f88395a19e90 100644 --- a/packages/block-library/src/file/test/__snapshots__/edit.native.js.snap +++ b/packages/block-library/src/file/test/__snapshots__/edit.native.js.snap @@ -94,7 +94,6 @@ exports[`File block renders file error state without crashing 1`] = ` textAlign="left" triggerKeyCodes={Array []} /> - Modal Svg @@ -187,7 +186,6 @@ exports[`File block renders file error state without crashing 1`] = ` textAlign="center" triggerKeyCodes={Array []} /> - Modal @@ -288,7 +286,6 @@ exports[`File block renders file without crashing 1`] = ` textAlign="left" triggerKeyCodes={Array []} /> - Modal - Modal From cb3df6cfa8d5b2e8d372cb3fc5b71be0d8e87624 Mon Sep 17 00:00:00 2001 From: Matt Chowning Date: Mon, 14 Dec 2020 16:54:10 -0500 Subject: [PATCH 15/17] Enable xposts in Android demo app --- .../android/app/src/main/java/com/gutenberg/MainActivity.java | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react-native-editor/android/app/src/main/java/com/gutenberg/MainActivity.java b/packages/react-native-editor/android/app/src/main/java/com/gutenberg/MainActivity.java index 83bbea9e5d5a15..ed3fdb7616676a 100644 --- a/packages/react-native-editor/android/app/src/main/java/com/gutenberg/MainActivity.java +++ b/packages/react-native-editor/android/app/src/main/java/com/gutenberg/MainActivity.java @@ -29,6 +29,7 @@ protected Bundle getLaunchOptions() { Bundle bundle = new Bundle(); Bundle capabilities = new Bundle(); capabilities.putBoolean(GutenbergProps.PROP_CAPABILITIES_MENTIONS, true); + capabilities.putBoolean(GutenbergProps.PROP_CAPABILITIES_XPOSTS, true); capabilities.putBoolean(GutenbergProps.PROP_CAPABILITIES_UNSUPPORTED_BLOCK_EDITOR, true); bundle.putBundle(GutenbergProps.PROP_CAPABILITIES, capabilities); return bundle; From bb6ecb54b5a85dc64de2eb6cc7803fb4c98097f7 Mon Sep 17 00:00:00 2001 From: Matt Chowning Date: Mon, 14 Dec 2020 17:10:44 -0500 Subject: [PATCH 16/17] Enable xposts in ios demo app --- .../ios/GutenbergDemo/GutenbergViewController.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react-native-editor/ios/GutenbergDemo/GutenbergViewController.swift b/packages/react-native-editor/ios/GutenbergDemo/GutenbergViewController.swift index a87322adbdbb32..b0002e0e7b5917 100644 --- a/packages/react-native-editor/ios/GutenbergDemo/GutenbergViewController.swift +++ b/packages/react-native-editor/ios/GutenbergDemo/GutenbergViewController.swift @@ -302,6 +302,7 @@ extension GutenbergViewController: GutenbergBridgeDataSource { func gutenbergCapabilities() -> [Capabilities : Bool] { return [ .mentions: true, + .xposts: true, .unsupportedBlockEditor: unsupportedBlockEnabled, .canEnableUnsupportedBlockEditor: unsupportedBlockCanBeActivated, .mediaFilesCollectionBlock: true, From f8027c51a7a362fd4ff8a34c021692a33ec19b83 Mon Sep 17 00:00:00 2001 From: Paul Von Schrottky Date: Thu, 17 Dec 2020 17:48:13 -0300 Subject: [PATCH 17/17] Add change log item for cross-posts --- packages/react-native-editor/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/react-native-editor/CHANGELOG.md b/packages/react-native-editor/CHANGELOG.md index 24caa6a16beb7c..040b237a5fb9d9 100644 --- a/packages/react-native-editor/CHANGELOG.md +++ b/packages/react-native-editor/CHANGELOG.md @@ -16,6 +16,10 @@ For each user feature we should also add a importance categorization label to i * [**] Support to render background/text colors in Group, Paragraph and Quote blocksĀ [#25994] * [*] Fix theme colors syncing with the editor [#26821] +## 1.44.0 + +* [***] Add support for cross-posting between sites + ## 1.41.0 * [***] Faster editor start and overall operation on Android [#26732]