From fa3bfd5e960fb6d9901edc05530a27454ecb912a Mon Sep 17 00:00:00 2001 From: Antonis Lilis Date: Tue, 29 Jun 2021 13:47:27 +0300 Subject: [PATCH] [RN Mobile][Global Styles] Adds new Prop for Global Styles Settings (#30544) * Adds new Prop for Global Styles Settings * Rename updateTheme to be more generic for update settings include GSS (#31566) * Fix wrong naming of subscribeUpdateEditorSettings * Update Gutenberg demo * Updates new props to rawStyles and rawFeatures * Update iOS Bridge for new values * Mobile - Global styles: Pass settings and set color palette and gradients (#30684) * Mobile - Read global styles and set color palette and gradients * Parse all color variables * Fix gradients * Update global styles mocked data * Move color settings * Removed added spaces * Add tests * Update experimental features path and prepare for rawGlobalStylesBaseStyles * Remove mock data and update code to use latest API changes * Removes Android rawFeatures prop * Mobile - Remove usage of rawFeatures * Remove rawFeatures * Adds raw Styles in React Native Bridge * Mobile - Pass rawStyles on initial props and fix colors and gradients * Add Raw Features back * Revert "Removes Android rawFeatures prop" This reverts commit 32a2b3aff85ed83d2a3c953f94d4f37685b4f2ca. * Add rawFeatures in the mobile editor * Mobile - Global styles: Set theme's background and text color (#30810) * Mobile - Read global styles and set color palette and gradients * Mobile - Enable colors for blocks that support it * Parse all color variables * Mobile - Set background, title, text and link colors * Fix gradients * Add placeholder color * Update global styles mocked data * Move color settings * Removed added spaces * Add tests * Update experimental features path and prepare for rawGlobalStylesBaseStyles * Add missing provider * Get the right color attribute * Remove mock data * Mobile - Fix base global colors Co-authored-by: Chip Co-authored-by: Gerardo Pacheco --- .../src/components/block-list/block.native.js | 7 + .../block-settings/container.native.js | 9 +- .../src/components/provider/index.native.js | 3 +- packages/block-editor/src/hooks/color.js | 2 +- .../src/paragraph/edit.native.js | 5 + packages/components/src/index.native.js | 1 + .../global-styles-context/index.native.js | 5 + .../test/utils.native.js | 189 +++++++++++++++++- .../global-styles-context/utils.native.js | 40 ++++ .../src/components/layout/index.native.js | 30 ++- .../src/components/post-title/index.native.js | 30 ++- .../src/components/provider/index.native.js | 43 ++-- .../RNReactNativeGutenbergBridgeModule.java | 10 +- .../mobile/WPAndroidGlue/GutenbergProps.kt | 6 + packages/react-native-bridge/index.js | 7 +- .../react-native-bridge/ios/Gutenberg.swift | 38 ++-- .../ios/GutenbergBridgeDataSource.swift | 7 +- .../ios/RNReactNativeGutenbergBridge.swift | 2 +- .../GutenbergViewController.swift | 2 +- packages/react-native-editor/src/index.js | 4 + .../rich-text/src/component/index.native.js | 15 +- test/native/setup.js | 2 +- 22 files changed, 384 insertions(+), 73 deletions(-) diff --git a/packages/block-editor/src/components/block-list/block.native.js b/packages/block-editor/src/components/block-list/block.native.js index 018cf4760a07e..c81a2d5469ecc 100644 --- a/packages/block-editor/src/components/block-list/block.native.js +++ b/packages/block-editor/src/components/block-list/block.native.js @@ -48,11 +48,13 @@ function BlockForType( { parentWidth, wrapperProps, blockWidth, + baseGlobalStyles, } ) { const defaultColors = useSetting( 'color.palette' ) || emptyArray; const globalStyle = useGlobalStyles(); const mergedStyle = useMemo( () => { return getMergedGlobalStyles( + baseGlobalStyles, globalStyle, wrapperProps.style, attributes, @@ -300,6 +302,7 @@ export default compose( [ withSelect( ( select, { clientId, rootClientId } ) => { const { getBlockIndex, + getSettings, isBlockSelected, __unstableGetBlockWithoutInnerBlocks, getSelectedBlockClientId, @@ -347,6 +350,9 @@ export default compose( [ isDescendantOfParentSelected || isParentSelected || parentId === ''; + const baseGlobalStyles = getSettings() + ?.__experimentalGlobalStylesBaseStyles; + return { icon, name: name || 'core/missing', @@ -360,6 +366,7 @@ export default compose( [ isParentSelected, firstToSelectId, isTouchable, + baseGlobalStyles, wrapperProps: getWrapperProps( attributes, blockType.getEditWrapperProps diff --git a/packages/block-editor/src/components/block-settings/container.native.js b/packages/block-editor/src/components/block-settings/container.native.js index e9f16b185a556..7f9d8a9073d39 100644 --- a/packages/block-editor/src/components/block-settings/container.native.js +++ b/packages/block-editor/src/components/block-settings/container.native.js @@ -1,7 +1,7 @@ /** * WordPress dependencies */ -import { InspectorControls } from '@wordpress/block-editor'; +import { InspectorControls, useSetting } from '@wordpress/block-editor'; import { BottomSheet, ColorSettings, @@ -29,6 +29,11 @@ function BottomSheetSettings( { settings, ...props } ) { + const colorSettings = { + colors: useSetting( 'color.palette' ) || settings.colors, + gradients: useSetting( 'color.gradients' ) || settings.gradients, + }; + return ( - + { children }; } export default withRegistryProvider( BlockEditorProvider ); diff --git a/packages/block-editor/src/hooks/color.js b/packages/block-editor/src/hooks/color.js index 554781d057b5f..2da9875c07584 100644 --- a/packages/block-editor/src/hooks/color.js +++ b/packages/block-editor/src/hooks/color.js @@ -234,7 +234,7 @@ export function ColorEdit( props ) { localAttributes.current = attributes; }, [ attributes ] ); - if ( ! hasColorSupport( blockName ) || Platform.OS !== 'web' ) { + if ( ! hasColorSupport( blockName ) ) { return null; } diff --git a/packages/block-library/src/paragraph/edit.native.js b/packages/block-library/src/paragraph/edit.native.js index a51a708a22276..1cd7575854300 100644 --- a/packages/block-library/src/paragraph/edit.native.js +++ b/packages/block-library/src/paragraph/edit.native.js @@ -30,6 +30,11 @@ function ParagraphBlock( { const { align, content, placeholder } = attributes; const styles = { + ...( mergedStyle?.baseColors && { + color: mergedStyle.baseColors?.color?.text, + placeholderColor: mergedStyle.baseColors?.color?.text, + linkColor: mergedStyle.baseColors?.elements?.link?.color?.text, + } ), ...mergedStyle, ...style, }; diff --git a/packages/components/src/index.native.js b/packages/components/src/index.native.js index ac8f5b0a237f2..e7e1deea5f752 100644 --- a/packages/components/src/index.native.js +++ b/packages/components/src/index.native.js @@ -124,3 +124,4 @@ export { withGlobalStyles, getMergedGlobalStyles, } from './mobile/global-styles-context'; +export { getGlobalStyles } from './mobile/global-styles-context/utils'; diff --git a/packages/components/src/mobile/global-styles-context/index.native.js b/packages/components/src/mobile/global-styles-context/index.native.js index 81a60ccc8eb56..1d4d0d45be676 100644 --- a/packages/components/src/mobile/global-styles-context/index.native.js +++ b/packages/components/src/mobile/global-styles-context/index.native.js @@ -22,16 +22,21 @@ const GlobalStylesContext = createContext( { style: {} } ); GlobalStylesContext.BLOCK_STYLE_ATTRIBUTES = BLOCK_STYLE_ATTRIBUTES; export const getMergedGlobalStyles = ( + baseGlobalStyles, globalStyle, wrapperPropsStyle, blockAttributes, defaultColors ) => { + const baseGlobalColors = { + baseColors: baseGlobalStyles || {}, + }; const blockStyleAttributes = pick( blockAttributes, BLOCK_STYLE_ATTRIBUTES ); const mergedStyle = { + ...baseGlobalColors, ...globalStyle, ...wrapperPropsStyle, }; diff --git a/packages/components/src/mobile/global-styles-context/test/utils.native.js b/packages/components/src/mobile/global-styles-context/test/utils.native.js index 396dee85b215f..e29dc8bbed7fa 100644 --- a/packages/components/src/mobile/global-styles-context/test/utils.native.js +++ b/packages/components/src/mobile/global-styles-context/test/utils.native.js @@ -1,7 +1,12 @@ /** * Internal dependencies */ -import { getBlockPaddings, getBlockColors } from '../utils'; +import { + getBlockPaddings, + getBlockColors, + parseColorVariables, + getGlobalStyles, +} from '../utils'; const DEFAULT_COLORS = [ { color: '#cd2653', name: 'Accent Color', slug: 'accent' }, @@ -9,6 +14,142 @@ const DEFAULT_COLORS = [ { color: '#6d6d6d', name: 'Secondary', slug: 'secondary' }, ]; +const GLOBAL_STYLES_PALETTE = [ + { + slug: 'green', + color: '#D1E4DD', + name: 'Green', + }, + { + slug: 'blue', + color: '#D1DFE4', + name: 'Blue', + }, + { + slug: 'purple', + color: '#D1D1E4', + name: 'Purple', + }, +]; + +const GLOBAL_STYLES_GRADIENTS = [ + { + slug: 'purple-to-blue', + gradient: + 'linear-gradient(160deg, var(--wp--preset--color--purple), var(--wp--preset--color--blue))', + name: 'Purple to Blue', + }, + { + slug: 'green-to-purple', + gradient: + 'linear-gradient(160deg, var(--wp--preset--color--green), var(--wp--preset--color--purple))', + name: 'Green to Purple', + }, +]; + +const DEFAULT_GLOBAL_STYLES = { + styles: { + color: { + background: 'var(--wp--preset--color--green)', + text: 'var(--wp--preset--color--blue)', + }, + elements: { + link: { + color: { + text: 'var(--wp--preset--color--purple)', + }, + }, + }, + }, +}; + +const PARSED_GLOBAL_STYLES = { + styles: { + color: { + background: '#D1E4DD', + text: '#D1DFE4', + }, + elements: { + link: { + color: { + text: '#D1D1E4', + }, + }, + }, + }, +}; + +const RAW_FEATURES = { + color: { + palette: { + core: [ + { + name: 'Black', + slug: 'black', + color: '#000000', + }, + { + name: 'Cyan bluish gray', + slug: 'cyan-bluish-gray', + color: '#abb8c3', + }, + { + name: 'White', + slug: 'white', + color: '#ffffff', + }, + ], + theme: [ + { + slug: 'green', + color: '#D1E4DD', + name: 'Green', + }, + { + slug: 'blue', + color: '#D1DFE4', + name: 'Blue', + }, + { + slug: 'purple', + color: '#D1D1E4', + name: 'Purple', + }, + ], + }, + gradients: { + core: [ + { + name: 'Vivid cyan blue to vivid purple', + gradient: + 'linear-gradient(135deg,rgba(6,147,227,1) 0%,rgb(155,81,224) 100%)', + slug: 'vivid-cyan-blue-to-vivid-purple', + }, + { + name: 'Light green cyan to vivid green cyan', + gradient: + 'linear-gradient(135deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%)', + slug: 'light-green-cyan-to-vivid-green-cyan', + }, + ], + theme: [ + { + slug: 'purple-to-blue', + gradient: + 'linear-gradient(160deg, var(--wp--preset--color--purple), var(--wp--preset--color--blue))', + name: 'Purple to Blue', + }, + { + slug: 'green-to-purple', + gradient: + 'linear-gradient(160deg, var(--wp--preset--color--green), var(--wp--preset--color--purple))', + name: 'Green to Purple', + }, + ], + }, + }, +}; + describe( 'getBlockPaddings', () => { const PADDING = 12; @@ -84,3 +225,49 @@ describe( 'getBlockColors', () => { ); } ); } ); + +describe( 'parseColorVariables', () => { + it( 'returns the parsed colors values correctly', () => { + const blockColors = parseColorVariables( + JSON.stringify( DEFAULT_GLOBAL_STYLES ), + GLOBAL_STYLES_PALETTE + ); + expect( blockColors ).toEqual( + expect.objectContaining( PARSED_GLOBAL_STYLES ) + ); + } ); +} ); + +describe( 'getGlobalStyles', () => { + it( 'returns the global styles data correctly', () => { + const rawFeatures = JSON.stringify( RAW_FEATURES ); + const globalStyles = getGlobalStyles( + JSON.stringify( DEFAULT_GLOBAL_STYLES ), + rawFeatures, + GLOBAL_STYLES_PALETTE, + GLOBAL_STYLES_GRADIENTS + ); + const gradients = parseColorVariables( + JSON.stringify( GLOBAL_STYLES_GRADIENTS ), + GLOBAL_STYLES_PALETTE + ); + const parsedExperimentalFeatures = parseColorVariables( + rawFeatures, + GLOBAL_STYLES_PALETTE + ); + + expect( globalStyles ).toEqual( + expect.objectContaining( { + colors: GLOBAL_STYLES_PALETTE, + gradients, + __experimentalFeatures: { + color: { + palette: parsedExperimentalFeatures?.color?.palette, + gradients: parsedExperimentalFeatures?.color?.gradients, + }, + }, + __experimentalGlobalStylesBaseStyles: PARSED_GLOBAL_STYLES, + } ) + ); + } ); +} ); diff --git a/packages/components/src/mobile/global-styles-context/utils.native.js b/packages/components/src/mobile/global-styles-context/utils.native.js index c8e2bce0c91f8..0cf5bee75c4c7 100644 --- a/packages/components/src/mobile/global-styles-context/utils.native.js +++ b/packages/components/src/mobile/global-styles-context/utils.native.js @@ -66,3 +66,43 @@ export function getBlockColors( blockStyleAttributes, defaultColors ) { return blockStyles; } + +export function parseColorVariables( styles, colorPalette ) { + const stylesBase = styles; + const colorPrefixRegex = /var\(--wp--preset--color--(.*?)\)/g; + + return stylesBase + ? JSON.parse( + stylesBase?.replace( colorPrefixRegex, ( _$1, $2 ) => { + const mappedColor = find( colorPalette, { + slug: $2, + } ); + return mappedColor?.color; + } ) + ) + : styles; +} + +export function getGlobalStyles( rawStyles, rawFeatures, colors, gradients ) { + const parsedGradients = parseColorVariables( + JSON.stringify( gradients ), + colors + ); + const globalStyles = parseColorVariables( rawStyles, colors ); + const parsedExperimentalFeatures = parseColorVariables( + rawFeatures, + colors + ); + + return { + colors, + gradients: parsedGradients, + __experimentalFeatures: { + color: { + palette: parsedExperimentalFeatures?.color?.palette, + gradients: parsedExperimentalFeatures?.color?.gradients, + }, + }, + __experimentalGlobalStylesBaseStyles: globalStyles, + }; +} diff --git a/packages/edit-post/src/components/layout/index.native.js b/packages/edit-post/src/components/layout/index.native.js index f0abe54cfc9e9..d98bae6739ef5 100644 --- a/packages/edit-post/src/components/layout/index.native.js +++ b/packages/edit-post/src/components/layout/index.native.js @@ -9,7 +9,11 @@ import SafeArea from 'react-native-safe-area'; */ import { Component } from '@wordpress/element'; import { withSelect } from '@wordpress/data'; -import { BottomSheetSettings, FloatingToolbar } from '@wordpress/block-editor'; +import { + BottomSheetSettings, + FloatingToolbar, + store as blockEditorStore, +} from '@wordpress/block-editor'; import { compose, withPreferredColorScheme } from '@wordpress/compose'; import { HTMLTextInput, @@ -101,7 +105,7 @@ class Layout extends Component { } render() { - const { getStylesFromColorScheme, mode } = this.props; + const { getStylesFromColorScheme, mode, globalStyles } = this.props; const isHtmlView = mode === 'text'; @@ -118,6 +122,16 @@ class Layout extends Component { bottom: this.state.safeAreaInsets.bottom, }; + const editorStyles = [ + getStylesFromColorScheme( + styles.background, + styles.backgroundDark + ), + globalStyles?.background && { + backgroundColor: globalStyles.background, + }, + ]; + return ( - + { isHtmlView ? this.renderHTML() : this.renderVisual() } { ! isHtmlView && Platform.OS === 'android' && ( @@ -176,9 +185,14 @@ export default compose( [ editorStore ); const { getEditorMode } = select( editPostStore ); + const { getSettings } = select( blockEditorStore ); + const globalStyles = getSettings()?.__experimentalGlobalStylesBaseStyles + ?.color; + return { isReady: isEditorReady(), mode: getEditorMode(), + globalStyles, }; } ), withPreferredColorScheme, diff --git a/packages/editor/src/components/post-title/index.native.js b/packages/editor/src/components/post-title/index.native.js index 0587f26227ec8..4e117f73fb315 100644 --- a/packages/editor/src/components/post-title/index.native.js +++ b/packages/editor/src/components/post-title/index.native.js @@ -19,6 +19,8 @@ import { withFocusOutside } from '@wordpress/components'; import { withInstanceId, compose } from '@wordpress/compose'; import { __, sprintf } from '@wordpress/i18n'; import { pasteHandler } from '@wordpress/blocks'; +import { store as blockEditorStore } from '@wordpress/block-editor'; +import { store as editorStore } from '@wordpress/editor'; /** * Internal dependencies @@ -107,12 +109,20 @@ class PostTitle extends Component { borderStyle, isDimmed, postType, + globalStyles, } = this.props; const decodedPlaceholder = decodeEntities( placeholder ); const borderColor = this.props.isSelected ? focusedBorderColor : 'transparent'; + const titleStyles = { + ...style, + ...( globalStyles?.text && { + color: globalStyles.text, + placeholderColor: globalStyles.text, + } ), + }; return ( { const { isPostTitleSelected, getEditedPostAttribute } = select( - 'core/editor' - ); - - const { getSelectedBlockClientId, getBlockRootClientId } = select( - 'core/block-editor' + editorStore ); + const { + getSelectedBlockClientId, + getBlockRootClientId, + getSettings, + } = select( blockEditorStore ); const selectedId = getSelectedBlockClientId(); const selectionIsNested = !! getBlockRootClientId( selectedId ); + const globalStyles = getSettings()?.__experimentalGlobalStylesBaseStyles + ?.color; return { postType: getEditedPostAttribute( 'type' ), isAnyBlockSelected: !! selectedId, isSelected: isPostTitleSelected(), isDimmed: selectionIsNested, + globalStyles, }; } ), withDispatch( ( dispatch ) => { const { undo, redo, togglePostTitleSelection } = dispatch( - 'core/editor' + editorStore ); const { clearSelectedBlock, insertDefaultBlock } = dispatch( - 'core/block-editor' + blockEditorStore ); return { diff --git a/packages/editor/src/components/provider/index.native.js b/packages/editor/src/components/provider/index.native.js index df425e279fc05..8440c99885662 100644 --- a/packages/editor/src/components/provider/index.native.js +++ b/packages/editor/src/components/provider/index.native.js @@ -13,14 +13,10 @@ import RNReactNativeGutenbergBridge, { subscribeSetTitle, subscribeMediaAppend, subscribeReplaceBlock, - subscribeUpdateTheme, + subscribeUpdateEditorSettings, subscribeUpdateCapabilities, subscribeShowNotice, } from '@wordpress/react-native-bridge'; - -/** - * WordPress dependencies - */ import { Component } from '@wordpress/element'; import { count as wordCount } from '@wordpress/wordcount'; import { @@ -37,6 +33,7 @@ import { validateThemeGradients, store as blockEditorStore, } from '@wordpress/block-editor'; +import { getGlobalStyles } from '@wordpress/components'; const postTypeEntities = [ { name: 'post', baseURL: '/wp/v2/posts' }, @@ -84,13 +81,11 @@ class NativeEditorProvider extends Component { } componentDidMount() { - const { capabilities, colors, gradients } = this.props; + const { capabilities, updateSettings } = this.props; - this.props.updateSettings( { + updateSettings( { ...capabilities, - // Set theme colors for the editor - ...( colors ? { colors } : {} ), - ...( gradients ? { gradients } : {} ), + ...this.getThemeColors( this.props ), } ); this.subscriptionParentGetHtml = subscribeParentGetHtml( () => { @@ -137,15 +132,10 @@ class NativeEditorProvider extends Component { } ); - this.subscriptionParentUpdateTheme = subscribeUpdateTheme( - ( theme ) => { - // Reset the colors and gradients in case one theme was set with custom items and then updated to a theme without custom elements. - - theme.colors = validateThemeColors( theme.colors ); - - theme.gradients = validateThemeGradients( theme.gradients ); - - this.props.updateSettings( theme ); + this.subscriptionParentUpdateEditorSettings = subscribeUpdateEditorSettings( + ( editorSettings ) => { + const themeColors = this.getThemeColors( editorSettings ); + updateSettings( themeColors ); } ); @@ -187,8 +177,8 @@ class NativeEditorProvider extends Component { this.subscriptionParentMediaAppend.remove(); } - if ( this.subscriptionParentUpdateTheme ) { - this.subscriptionParentUpdateTheme.remove(); + if ( this.subscriptionParentUpdateEditorSettings ) { + this.subscriptionParentUpdateEditorSettings.remove(); } if ( this.subscriptionParentUpdateCapabilities ) { @@ -200,6 +190,17 @@ class NativeEditorProvider extends Component { } } + getThemeColors( { colors, gradients, rawStyles, rawFeatures } ) { + return { + ...( rawStyles + ? getGlobalStyles( rawStyles, rawFeatures, colors, gradients ) + : { + colors: validateThemeColors( colors ), + gradients: validateThemeGradients( gradients ), + } ), + }; + } + componentDidUpdate( prevProps ) { if ( ! prevProps.isReady && this.props.isReady ) { const blocks = this.props.blocks; diff --git a/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/RNReactNativeGutenbergBridgeModule.java b/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/RNReactNativeGutenbergBridgeModule.java index 4f7c04bd8b3ca..896748b541559 100644 --- a/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/RNReactNativeGutenbergBridgeModule.java +++ b/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/RNReactNativeGutenbergBridgeModule.java @@ -44,7 +44,7 @@ public class RNReactNativeGutenbergBridgeModule extends ReactContextBaseJavaModu private static final String EVENT_NAME_NOTIFY_MODAL_CLOSED = "notifyModalClosed"; private static final String EVENT_NAME_PREFERRED_COLOR_SCHEME = "preferredColorScheme"; private static final String EVENT_NAME_MEDIA_REPLACE_BLOCK = "replaceBlock"; - private static final String EVENT_NAME_UPDATE_THEME = "updateTheme"; + private static final String EVENT_NAME_UPDATE_EDITOR_SETTINGS = "updateEditorSettings"; private static final String EVENT_NAME_SHOW_NOTICE = "showNotice"; private static final String MAP_KEY_UPDATE_HTML = "html"; @@ -57,6 +57,7 @@ public class RNReactNativeGutenbergBridgeModule extends ReactContextBaseJavaModu public static final String MAP_KEY_MEDIA_FILE_UPLOAD_MEDIA_TYPE = "mediaType"; private static final String MAP_KEY_THEME_UPDATE_COLORS = "colors"; private static final String MAP_KEY_THEME_UPDATE_GRADIENTS = "gradients"; + private static final String MAP_KEY_THEME_UPDATE_RAW_STYLES = "rawStyles"; public static final String MAP_KEY_MEDIA_FINAL_SAVE_RESULT_SUCCESS_VALUE = "success"; private static final String MAP_KEY_IS_PREFERRED_COLOR_SCHEME_DARK = "isPreferredColorSchemeDark"; @@ -144,6 +145,7 @@ public void updateTheme(@Nullable Bundle editorTheme) { WritableMap writableMap = new WritableNativeMap(); Serializable colors = editorTheme.getSerializable(MAP_KEY_THEME_UPDATE_COLORS); Serializable gradients = editorTheme.getSerializable(MAP_KEY_THEME_UPDATE_GRADIENTS); + Serializable rawStyles = editorTheme.getSerializable(MAP_KEY_THEME_UPDATE_RAW_STYLES); if (colors != null) { writableMap.putArray(MAP_KEY_THEME_UPDATE_COLORS, Arguments.fromList((ArrayList)colors)); @@ -153,7 +155,11 @@ public void updateTheme(@Nullable Bundle editorTheme) { writableMap.putArray(MAP_KEY_THEME_UPDATE_GRADIENTS, Arguments.fromList((ArrayList)gradients)); } - emitToJS(EVENT_NAME_UPDATE_THEME, writableMap); + if (rawStyles != null) { + writableMap.putString(MAP_KEY_THEME_UPDATE_RAW_STYLES, rawStyles.toString()); + } + + emitToJS(EVENT_NAME_UPDATE_EDITOR_SETTINGS, writableMap); } @ReactMethod diff --git a/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/WPAndroidGlue/GutenbergProps.kt b/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/WPAndroidGlue/GutenbergProps.kt index 4425769cfe8b8..aa49f177f3c23 100644 --- a/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/WPAndroidGlue/GutenbergProps.kt +++ b/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/WPAndroidGlue/GutenbergProps.kt @@ -36,6 +36,10 @@ data class GutenbergProps @JvmOverloads constructor( editorTheme?.also { theme -> theme.getSerializable(PROP_COLORS)?.let { putSerializable(PROP_COLORS, it) } theme.getSerializable(PROP_GRADIENTS)?.let { putSerializable(PROP_GRADIENTS, it) } + theme.getSerializable(PROP_STYLES) + ?.let { putSerializable(PROP_STYLES, it) } + theme.getSerializable(PROP_FEATURES) + ?.let { putSerializable(PROP_FEATURES, it) } } } @@ -69,6 +73,8 @@ data class GutenbergProps @JvmOverloads constructor( private const val PROP_TRANSLATIONS = "translations" private const val PROP_COLORS = "colors" private const val PROP_GRADIENTS = "gradients" + private const val PROP_STYLES = "rawStyles" + private const val PROP_FEATURES = "rawFeatures" const val PROP_CAPABILITIES = "capabilities" const val PROP_CAPABILITIES_CONTACT_INFO_BLOCK = "contactInfoBlock" diff --git a/packages/react-native-bridge/index.js b/packages/react-native-bridge/index.js index fde2f09856346..7d781095749b0 100644 --- a/packages/react-native-bridge/index.js +++ b/packages/react-native-bridge/index.js @@ -125,8 +125,11 @@ export function subscribeAndroidModalClosed( callback ) { : undefined; } -export function subscribeUpdateTheme( callback ) { - return gutenbergBridgeEvents.addListener( 'updateTheme', callback ); +export function subscribeUpdateEditorSettings( callback ) { + return gutenbergBridgeEvents.addListener( + 'updateEditorSettings', + callback + ); } export function subscribePreferredColorScheme( callback ) { diff --git a/packages/react-native-bridge/ios/Gutenberg.swift b/packages/react-native-bridge/ios/Gutenberg.swift index d6cc760538512..cd143ae0d831f 100644 --- a/packages/react-native-bridge/ios/Gutenberg.swift +++ b/packages/react-native-bridge/ios/Gutenberg.swift @@ -79,13 +79,10 @@ public class Gutenberg: NSObject { initialProps["capabilities"] = capabilities.toJSPayload() } - let editorTheme = dataSource.gutenbergEditorTheme() - if let colors = editorTheme?.colors { - initialProps["colors"] = colors - } - - if let gradients = editorTheme?.gradients { - initialProps["gradients"] = gradients + let editorSettings = dataSource.gutenbergEditorSettings() + let settingsUpdates = properties(from: editorSettings) + initialProps.merge(settingsUpdates) { (intialProp, settingsUpdates) -> Any in + settingsUpdates } return initialProps @@ -184,19 +181,32 @@ public class Gutenberg: NSObject { bridgeModule.sendEventIfNeeded(.setFocusOnTitle, body: nil) } - public func updateTheme(_ editorTheme: GutenbergEditorTheme?) { + public func updateEditorSettings(_ editorSettings: GutenbergEditorSettings?) { + let settingsUpdates = properties(from: editorSettings) + sendEvent(.updateEditorSettings, body: settingsUpdates) + } + + private func properties(from editorSettings: GutenbergEditorSettings?) -> [String : Any] { + var settingsUpdates = [String : Any]() + settingsUpdates["isFSETheme"] = editorSettings?.isFSETheme ?? false - var themeUpdates = [String : Any]() + if let rawStyles = editorSettings?.rawStyles { + settingsUpdates["rawStyles"] = rawStyles + } + + if let rawFeatures = editorSettings?.rawFeatures { + settingsUpdates["rawFeatures"] = rawFeatures + } - if let colors = editorTheme?.colors { - themeUpdates["colors"] = colors + if let colors = editorSettings?.colors { + settingsUpdates["colors"] = colors } - if let gradients = editorTheme?.gradients { - themeUpdates["gradients"] = gradients + if let gradients = editorSettings?.gradients { + settingsUpdates["gradients"] = gradients } - sendEvent(.updateTheme, body:themeUpdates) + return settingsUpdates } public func showNotice(_ message: String) { diff --git a/packages/react-native-bridge/ios/GutenbergBridgeDataSource.swift b/packages/react-native-bridge/ios/GutenbergBridgeDataSource.swift index d6023f4d1508d..b082cbd60682d 100644 --- a/packages/react-native-bridge/ios/GutenbergBridgeDataSource.swift +++ b/packages/react-native-bridge/ios/GutenbergBridgeDataSource.swift @@ -46,7 +46,7 @@ public protocol GutenbergBridgeDataSource: class { func gutenbergCapabilities() -> [Capabilities: Bool] /// Asks the data source for a list of theme colors. - func gutenbergEditorTheme() -> GutenbergEditorTheme? + func gutenbergEditorSettings() -> GutenbergEditorSettings? /// Asks the data source for a view to show while the Editor is loading. var loadingView: UIView? { get } @@ -70,7 +70,10 @@ public extension GutenbergBridgeDataSource { } } -public protocol GutenbergEditorTheme { +public protocol GutenbergEditorSettings { + var isFSETheme: Bool { get } + var rawStyles: String? { get } + var rawFeatures: String? { get } var colors: [[String: String]]? { get } var gradients: [[String: String]]? { get } } diff --git a/packages/react-native-bridge/ios/RNReactNativeGutenbergBridge.swift b/packages/react-native-bridge/ios/RNReactNativeGutenbergBridge.swift index 82f19d50a5a15..2b57384df9610 100644 --- a/packages/react-native-bridge/ios/RNReactNativeGutenbergBridge.swift +++ b/packages/react-native-bridge/ios/RNReactNativeGutenbergBridge.swift @@ -369,7 +369,7 @@ extension RNReactNativeGutenbergBridge { case mediaUpload case setFocusOnTitle case mediaAppend - case updateTheme + case updateEditorSettings case replaceBlock case updateCapabilities case showNotice diff --git a/packages/react-native-editor/ios/GutenbergDemo/GutenbergViewController.swift b/packages/react-native-editor/ios/GutenbergDemo/GutenbergViewController.swift index 4e24a4dc1f75d..ae3cb177d7ccb 100644 --- a/packages/react-native-editor/ios/GutenbergDemo/GutenbergViewController.swift +++ b/packages/react-native-editor/ios/GutenbergDemo/GutenbergViewController.swift @@ -296,7 +296,7 @@ extension GutenbergViewController: GutenbergBridgeDataSource { return ExampleAttachmentDelegate() } - func gutenbergEditorTheme() -> GutenbergEditorTheme? { + func gutenbergEditorSettings() -> GutenbergEditorSettings? { return nil } diff --git a/packages/react-native-editor/src/index.js b/packages/react-native-editor/src/index.js index 2d9cd3ed6c79a..c8b8fd8b152ab 100644 --- a/packages/react-native-editor/src/index.js +++ b/packages/react-native-editor/src/index.js @@ -81,6 +81,8 @@ const setupInitHooks = () => { featuredImageId, colors, gradients, + rawStyles, + rawFeatures, } = props; if ( initialData === undefined && __DEV__ ) { @@ -106,6 +108,8 @@ const setupInitHooks = () => { capabilities, colors, gradients, + rawStyles, + rawFeatures, }; } ); diff --git a/packages/rich-text/src/component/index.native.js b/packages/rich-text/src/component/index.native.js index 195de53e802fe..8f5afcc485716 100644 --- a/packages/rich-text/src/component/index.native.js +++ b/packages/rich-text/src/component/index.native.js @@ -3,21 +3,18 @@ /** * External dependencies */ +import { View, Platform } from 'react-native'; +import { get, pickBy, debounce, isString } from 'lodash'; +import memize from 'memize'; + /** * WordPress dependencies */ import RCTAztecView from '@wordpress/react-native-aztec'; -import { View, Platform } from 'react-native'; import { showUserSuggestions, showXpostSuggestions, } from '@wordpress/react-native-bridge'; -import { get, pickBy, debounce, isString } from 'lodash'; -import memize from 'memize'; - -/** - * WordPress dependencies - */ import { BlockFormatControls } from '@wordpress/block-editor'; import { Component } from '@wordpress/element'; import { compose, withPreferredColorScheme } from '@wordpress/compose'; @@ -982,10 +979,12 @@ export class RichText extends Component { text: html, eventCount: this.lastEventCount, selection, - linkTextColor: defaultTextDecorationColor, + linkTextColor: + style?.linkColor || defaultTextDecorationColor, } } placeholder={ this.props.placeholder } placeholderTextColor={ + style?.placeholderColor || this.props.placeholderTextColor || defaultPlaceholderTextColor } diff --git a/test/native/setup.js b/test/native/setup.js index 2df7fb1889b29..6fd0a13c87337 100644 --- a/test/native/setup.js +++ b/test/native/setup.js @@ -48,7 +48,7 @@ jest.mock( '@wordpress/react-native-bridge', () => { subscribeFeaturedImageIdNativeUpdated: jest.fn(), subscribeMediaAppend: jest.fn(), subscribeAndroidModalClosed: jest.fn(), - subscribeUpdateTheme: jest.fn(), + subscribeUpdateEditorSettings: jest.fn(), subscribePreferredColorScheme: () => 'light', subscribeUpdateCapabilities: jest.fn(), subscribeShowNotice: jest.fn(),