diff --git a/docs/manifest.json b/docs/manifest.json index abcc27569c88e..5ffb21b8e7c86 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -1037,6 +1037,12 @@ "markdown_source": "../packages/components/src/menu-items-choice/README.md", "parent": "components" }, + { + "title": "BottomSheetNavigation", + "slug": "bottom-sheet-navigation", + "markdown_source": "../packages/components/src/mobile/bottom-sheet/bottom-sheet-navigation/README.md", + "parent": "components" + }, { "title": "Modal", "slug": "modal", diff --git a/package-lock.json b/package-lock.json index 30a0b3d39da0a..1ef619832ba3d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1367,6 +1367,14 @@ "minimist": "^1.2.0" } }, + "@egjs/hammerjs": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz", + "integrity": "sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==", + "requires": { + "@types/hammerjs": "^2.0.36" + } + }, "@egoist/vue-to-react": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@egoist/vue-to-react/-/vue-to-react-1.1.0.tgz", @@ -7092,10 +7100,80 @@ "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-3.0.0.tgz", "integrity": "sha512-ng6Tm537E/M42GjE4TRUxQyL8sRfClcL7bQWblOCoxPZzJ2J3bdALsjeG3vDnVCIfI/R0AeFalN9KjMt0+Z/Zg==" }, + "@react-native-community/masked-view": { + "version": "git+https://github.com/wordpress-mobile/react-native-masked-view.git#098004d0968f853fc7d96c2aa5f96afe7a133c58", + "from": "git+https://github.com/wordpress-mobile/react-native-masked-view.git#098004d0968f853fc7d96c2aa5f96afe7a133c58" + }, "@react-native-community/slider": { "version": "git+https://github.com/wordpress-mobile/react-native-slider.git#d263ff16cdd9fb7352b354342522ff030f220f42", "from": "git+https://github.com/wordpress-mobile/react-native-slider.git#d263ff16cdd9fb7352b354342522ff030f220f42" }, + "@react-navigation/core": { + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-5.12.0.tgz", + "integrity": "sha512-CTmYrFXCZwInN40CpEzkPxhrpzujj20qvsUgpH05+oO1flwsnaJsyBfYawIcTS62/1/Z6SAM7iW5PbKk+qw9iQ==", + "requires": { + "@react-navigation/routers": "^5.4.9", + "escape-string-regexp": "^4.0.0", + "nanoid": "^3.1.9", + "query-string": "^6.13.1", + "react-is": "^16.13.0", + "use-subscription": "^1.4.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + }, + "query-string": { + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.13.1.tgz", + "integrity": "sha512-RfoButmcK+yCta1+FuU8REvisx1oEzhMKwhLUNcepQTPGcNMp1sIqjnfCtfnvGSQZQEhaBHvccujtWoUV3TTbA==", + "requires": { + "decode-uri-component": "^0.2.0", + "split-on-first": "^1.0.0", + "strict-uri-encode": "^2.0.0" + } + }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "strict-uri-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", + "integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY=" + } + } + }, + "@react-navigation/native": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-5.7.0.tgz", + "integrity": "sha512-a2JBOdRB3q20Jdc5hF8shR4Dk+ZmjF2Rr9RviErtARztu08lU+jcb1gK6c31OKL37JDuaS3xexE9Cb7dYeMy3Q==", + "requires": { + "@react-navigation/core": "^5.12.0", + "nanoid": "^3.1.9" + } + }, + "@react-navigation/routers": { + "version": "5.4.9", + "resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-5.4.9.tgz", + "integrity": "sha512-dYD5qrIKUmuBEp+O98hB0tDYpEsGQgCQFQgMEoFKBmVVhx2JnJJ1zxRjU7xWcCU4VdBA8IOowgHQHJsVNKYyrg==", + "requires": { + "nanoid": "^3.1.9" + } + }, + "@react-navigation/stack": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/@react-navigation/stack/-/stack-5.6.2.tgz", + "integrity": "sha512-51Aasxg8j2eKxz4mhA0ajJXrhAyJQkk2iiNE511zcqJ3tlfxv/h70Eej3PetnbbHFMOwNsEwc2GjB3OnfQcxjQ==", + "requires": { + "color": "^3.1.2", + "react-native-iphone-x-helper": "^1.2.1" + } + }, "@samverschueren/stream-to-observable": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz", @@ -10116,6 +10194,11 @@ "@types/node": "*" } }, + "@types/hammerjs": { + "version": "2.0.36", + "resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.36.tgz", + "integrity": "sha512-7TUK/k2/QGpEAv/BCwSHlYu3NXZhQ9ZwBYpzr9tjlPIL2C5BeGhH3DmVavRx3ZNyELX5TLC91JTz/cen6AAtIQ==" + }, "@types/history": { "version": "4.7.4", "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.4.tgz", @@ -11762,7 +11845,10 @@ "requires": { "@babel/runtime": "^7.9.2", "@react-native-community/blur": "3.6.0", + "@react-native-community/masked-view": "git+https://github.com/wordpress-mobile/react-native-masked-view.git#098004d0968f853fc7d96c2aa5f96afe7a133c58", "@react-native-community/slider": "git+https://github.com/wordpress-mobile/react-native-slider.git#d263ff16cdd9fb7352b354342522ff030f220f42", + "@react-navigation/native": "^5.6.1", + "@react-navigation/stack": "5.6.2", "@wordpress/api-fetch": "file:packages/api-fetch", "@wordpress/block-editor": "file:packages/block-editor", "@wordpress/block-library": "file:packages/block-library", @@ -11784,14 +11870,18 @@ "node-fetch": "^2.6.0", "react-native": "0.61.5", "react-native-dark-mode": "git+https://github.com/wordpress-mobile/react-native-dark-mode.git#f09bf1480e7b34536413ab3300f29e4375edb2c6", + "react-native-gesture-handler": "git+https://github.com/wordpress-mobile/react-native-gesture-handler.git#b80e959908b383a26d6e35d992d6d529efad0b16", "react-native-get-random-values": "git+https://github.com/wordpress-mobile/react-native-get-random-values.git#f03f2c16414aff4ea76064dcd00a9e3c6efc838d", "react-native-hr": "git+https://github.com/Riglerr/react-native-hr.git#2d01a5cf77212d100e8b99e0310cce5234f977b3", "react-native-hsv-color-picker": "git+https://github.com/wordpress-mobile/react-native-hsv-color-picker.git", "react-native-keyboard-aware-scroll-view": "git+https://github.com/wordpress-mobile/react-native-keyboard-aware-scroll-view.git#gb-v0.8.8", "react-native-linear-gradient": "git+https://github.com/wordpress-mobile/react-native-linear-gradient.git#52bf43077171cff8714ce3e0155f3ebb7f55bc37", "react-native-modal": "^6.5.0", + "react-native-reanimated": "git+https://github.com/wordpress-mobile/react-native-reanimated.git#ed48f510fba751cd75da7629e92276166766be91", "react-native-safe-area": "^0.5.0", + "react-native-safe-area-context": "git+https://github.com/wordpress-mobile/react-native-safe-area-context.git#1e3c0d34f31b59fb79f71ec0b4c39c513f684871", "react-native-sass-transformer": "^1.1.1", + "react-native-screens": "git+https://github.com/wordpress-mobile/react-native-screens.git#835843f4c3697bba5c330d05d8fc270d50ca9d2a", "react-native-svg": "git+https://github.com/wordpress-mobile/react-native-svg.git#a628e92990a2404e30a0086f168bd2b5b7b4ce96", "react-native-url-polyfill": "^1.1.2", "react-native-video": "git+https://github.com/wordpress-mobile/react-native-video.git#1b964b107863351ed744fc104d7952bbec3e2d4f" @@ -22760,6 +22850,15 @@ "object-visit": "^1.0.0" } }, + "color": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/color/-/color-3.1.2.tgz", + "integrity": "sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg==", + "requires": { + "color-convert": "^1.9.1", + "color-string": "^1.5.2" + } + }, "color-convert": { "version": "1.9.2", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz", @@ -22773,6 +22872,15 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=" }, + "color-string": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", + "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, "color-support": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", @@ -40442,6 +40550,11 @@ "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" }, + "nanoid": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.10.tgz", + "integrity": "sha512-iZFMXKeXWkxzlfmMfM91gw7YhN2sdJtixY+eZh9V6QWJWTOiurhpKhBMgr82pfzgSqglQgqYSCowEYsz8D++6w==" + }, "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", @@ -46392,6 +46505,16 @@ } } }, + "react-native-gesture-handler": { + "version": "git+https://github.com/wordpress-mobile/react-native-gesture-handler.git#b80e959908b383a26d6e35d992d6d529efad0b16", + "from": "git+https://github.com/wordpress-mobile/react-native-gesture-handler.git#b80e959908b383a26d6e35d992d6d529efad0b16", + "requires": { + "@egjs/hammerjs": "^2.0.17", + "hoist-non-react-statics": "^2.3.1", + "invariant": "^2.2.4", + "prop-types": "^15.7.2" + } + }, "react-native-get-random-values": { "version": "git+https://github.com/wordpress-mobile/react-native-get-random-values.git#f03f2c16414aff4ea76064dcd00a9e3c6efc838d", "from": "git+https://github.com/wordpress-mobile/react-native-get-random-values.git#f03f2c16414aff4ea76064dcd00a9e3c6efc838d", @@ -46437,6 +46560,35 @@ "react-native-animatable": "^1.2.4" } }, + "react-native-reanimated": { + "version": "git+https://github.com/wordpress-mobile/react-native-reanimated.git#ed48f510fba751cd75da7629e92276166766be91", + "from": "git+https://github.com/wordpress-mobile/react-native-reanimated.git#ed48f510fba751cd75da7629e92276166766be91", + "requires": { + "fbjs": "^1.0.0" + }, + "dependencies": { + "core-js": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", + "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==" + }, + "fbjs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-1.0.0.tgz", + "integrity": "sha512-MUgcMEJaFhCaF1QtWGnmq9ZDRAzECTCRAF7O6UZIlAlkTs1SasiX9aP0Iw7wfD2mJ7wDTNfg2w7u5fSCwJk1OA==", + "requires": { + "core-js": "^2.4.1", + "fbjs-css-vars": "^1.0.0", + "isomorphic-fetch": "^2.1.1", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.18" + } + } + } + }, "react-native-safe-area": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/react-native-safe-area/-/react-native-safe-area-0.5.1.tgz", @@ -46445,6 +46597,10 @@ "@types/react": "^16.8.8" } }, + "react-native-safe-area-context": { + "version": "git+https://github.com/wordpress-mobile/react-native-safe-area-context.git#1e3c0d34f31b59fb79f71ec0b4c39c513f684871", + "from": "git+https://github.com/wordpress-mobile/react-native-safe-area-context.git#1e3c0d34f31b59fb79f71ec0b4c39c513f684871" + }, "react-native-sass-transformer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/react-native-sass-transformer/-/react-native-sass-transformer-1.4.0.tgz", @@ -46462,6 +46618,10 @@ } } }, + "react-native-screens": { + "version": "git+https://github.com/wordpress-mobile/react-native-screens.git#835843f4c3697bba5c330d05d8fc270d50ca9d2a", + "from": "git+https://github.com/wordpress-mobile/react-native-screens.git#835843f4c3697bba5c330d05d8fc270d50ca9d2a" + }, "react-native-svg": { "version": "git+https://github.com/wordpress-mobile/react-native-svg.git#a628e92990a2404e30a0086f168bd2b5b7b4ce96", "from": "git+https://github.com/wordpress-mobile/react-native-svg.git#a628e92990a2404e30a0086f168bd2b5b7b4ce96", @@ -48896,7 +49056,6 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", - "dev": true, "requires": { "is-arrayish": "^0.3.1" }, @@ -48904,8 +49063,7 @@ "is-arrayish": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", - "dev": true + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" } } }, @@ -49275,6 +49433,11 @@ "through": "2" } }, + "split-on-first": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", + "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==" + }, "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", @@ -52858,6 +53021,14 @@ "tslib": "^1.9.3" } }, + "use-subscription": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/use-subscription/-/use-subscription-1.4.1.tgz", + "integrity": "sha512-7+IIwDG/4JICrWHL/Q/ZPK5yozEnvRm6vHImu0LKwQlmWGKeiF7mbAenLlK/cTNXrTtXHU/SFASQHzB6+oSJMQ==", + "requires": { + "object-assign": "^4.1.1" + } + }, "util": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", 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 302030563debe..a316b2c86cf5f 100644 --- a/packages/block-editor/src/components/block-settings/container.native.js +++ b/packages/block-editor/src/components/block-settings/container.native.js @@ -1,21 +1,20 @@ /** * WordPress dependencies */ -import { - BottomSheet, - BottomSheetConsumer, - ColorSettings, - colorsUtils, -} from '@wordpress/components'; -import { withSelect, withDispatch } from '@wordpress/data'; -import { compose } from '@wordpress/compose'; import { InspectorControls } from '@wordpress/block-editor'; - +import { BottomSheet, ColorSettings } from '@wordpress/components'; +import { compose } from '@wordpress/compose'; +import { withDispatch, withSelect } from '@wordpress/data'; /** * Internal dependencies */ import styles from './container.native.scss'; +export const blockSettingsScreens = { + settings: 'Settings', + color: 'Color', +}; + function BottomSheetSettings( { editorSidebarOpened, closeGeneralSidebar, @@ -30,23 +29,18 @@ function BottomSheetSettings( { contentStyle={ styles.content } { ...props } > - - { ( { currentScreen, extraProps, ...bottomSheetProps } ) => { - switch ( currentScreen ) { - case colorsUtils.subsheets.color: - return ( - - ); - case colorsUtils.subsheets.settings: - default: - return ; - } - } } - + + + + + + + + ); } diff --git a/packages/block-editor/src/components/block-settings/index.native.js b/packages/block-editor/src/components/block-settings/index.native.js index f3895a9c69792..9daa470d59798 100644 --- a/packages/block-editor/src/components/block-settings/index.native.js +++ b/packages/block-editor/src/components/block-settings/index.native.js @@ -1,2 +1,5 @@ export { default as BlockSettingsButton } from './button'; -export { default as BottomSheetSettings } from './container'; +export { + default as BottomSheetSettings, + blockSettingsScreens, +} from './container'; diff --git a/packages/block-editor/src/components/colors-gradients/panel-color-gradient-settings.native.js b/packages/block-editor/src/components/colors-gradients/panel-color-gradient-settings.native.js index f9e7bd2950dc0..126064cfd3865 100644 --- a/packages/block-editor/src/components/colors-gradients/panel-color-gradient-settings.native.js +++ b/packages/block-editor/src/components/colors-gradients/panel-color-gradient-settings.native.js @@ -1,43 +1,47 @@ +/** + * External dependencies + */ +import { useNavigation } from '@react-navigation/native'; + /** * WordPress dependencies */ -import { - ColorControl, - BottomSheetConsumer, - PanelBody, -} from '@wordpress/components'; +import { ColorControl, PanelBody } from '@wordpress/components'; + +/** + * Internal dependencies + */ +import { blockSettingsScreens } from '../block-settings'; export default function PanelColorGradientSettings( { settings, title } ) { + const navigation = useNavigation(); + return ( - - { ( { onReplaceSubsheet } ) => - settings.map( - ( { - onColorChange, - colorValue, - onGradientChange, - gradientValue, - label, - } ) => ( - { - onReplaceSubsheet( 'Color', { - onColorChange, - colorValue: gradientValue || colorValue, - gradientValue, - onGradientChange, - label, - } ); - } } - key={ `color-setting-${ label }` } - label={ label } - color={ gradientValue || colorValue } - /> - ) - ) - } - + { settings.map( + ( { + onColorChange, + colorValue, + onGradientChange, + gradientValue, + label, + } ) => ( + { + navigation.navigate( blockSettingsScreens.color, { + onColorChange, + colorValue: gradientValue || colorValue, + gradientValue, + onGradientChange, + label, + } ); + } } + key={ `color-setting-${ label }` } + label={ label } + color={ gradientValue || colorValue } + /> + ) + ) } ); } diff --git a/packages/block-editor/src/components/index.native.js b/packages/block-editor/src/components/index.native.js index 2dff50cea14cb..fffd9854296b3 100644 --- a/packages/block-editor/src/components/index.native.js +++ b/packages/block-editor/src/components/index.native.js @@ -35,7 +35,11 @@ export { default as Caption } from './caption'; export { default as PanelColorSettings } from './panel-color-settings'; export { default as __experimentalPanelColorGradientSettings } from './colors-gradients/panel-color-gradient-settings'; -export { BottomSheetSettings, BlockSettingsButton } from './block-settings'; +export { + BottomSheetSettings, + BlockSettingsButton, + blockSettingsScreens, +} from './block-settings'; export { default as VideoPlayer, VIDEO_ASPECT_RATIO } from './video-player'; // Content Related Components diff --git a/packages/block-library/src/cover/edit.native.js b/packages/block-library/src/cover/edit.native.js index d698791df731d..39e6d685b0557 100644 --- a/packages/block-library/src/cover/edit.native.js +++ b/packages/block-library/src/cover/edit.native.js @@ -204,8 +204,8 @@ const Cover = ( { function openColorPicker() { if ( isParentSelected ) { - openGeneralSidebar(); setCustomColorPickerShowing( true ); + openGeneralSidebar(); } } @@ -314,25 +314,29 @@ const Cover = ( { { ( { shouldEnableBottomSheetScroll, - shouldDisableBottomSheetMaxHeight, - onCloseBottomSheet, - onHardwareButtonPress, + shouldEnableBottomSheetMaxHeight, + onHandleClosingBottomSheet, + onHandleHardwareButtonPress, isBottomSheetContentScrolling, } ) => ( { setCustomColor( color ); setColor( color ); } } onNavigationBack={ closeSettingsBottomSheet } - onCloseBottomSheet={ onCloseBottomSheet } - onHardwareButtonPress={ onHardwareButtonPress } + onHandleClosingBottomSheet={ + onHandleClosingBottomSheet + } + onHandleHardwareButtonPress={ + onHandleHardwareButtonPress + } onBottomSheetClosed={ () => { setCustomColorPickerShowing( false ); } } diff --git a/packages/components/src/color-palette/index.native.js b/packages/components/src/color-palette/index.native.js index 149063b0e7360..cc75a22c67d3c 100644 --- a/packages/components/src/color-palette/index.native.js +++ b/packages/components/src/color-palette/index.native.js @@ -24,7 +24,6 @@ import { usePreferredColorSchemeStyle } from '@wordpress/compose'; import styles from './style.scss'; import ColorIndicator from '../color-indicator'; import { colorsUtils } from '../mobile/color-settings/utils'; -import { performLayoutAnimation } from '../mobile/layout-animation'; const ANIMATION_DURATION = 200; @@ -138,7 +137,6 @@ function ColorPalette( { contentWidth - scrollPosition - customIndicatorWidth < width; if ( isCustomGradientColor ) { - performLayoutAnimation(); if ( ! isIOS ) { // Scroll position on Android doesn't adjust automatically when removing the last item from the horizontal list. // https://github.com/facebook/react-native/issues/27504 diff --git a/packages/components/src/color-picker/index.native.js b/packages/components/src/color-picker/index.native.js index daea6ce175fbd..27682f7ff2542 100644 --- a/packages/components/src/color-picker/index.native.js +++ b/packages/components/src/color-picker/index.native.js @@ -2,12 +2,13 @@ * External dependencies */ import { View, Text, TouchableWithoutFeedback, Platform } from 'react-native'; +import React from 'react'; import HsvColorPicker from 'react-native-hsv-color-picker'; import tinycolor from 'tinycolor2'; /** * WordPress dependencies */ -import { useState, useEffect } from '@wordpress/element'; +import { useState, useEffect, useRef } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import { BottomSheet } from '@wordpress/components'; import { usePreferredColorSchemeStyle } from '@wordpress/compose'; @@ -19,23 +20,27 @@ import styles from './style.scss'; function ColorPicker( { shouldEnableBottomSheetScroll, - shouldDisableBottomSheetMaxHeight, + shouldEnableBottomSheetMaxHeight, isBottomSheetContentScrolling, setColor, activeColor, isGradientColor, onNavigationBack, - onCloseBottomSheet, + onHandleClosingBottomSheet, onBottomSheetClosed, - onHardwareButtonPress, + onHandleHardwareButtonPress, bottomLabelText, } ) { + const didMount = useRef( false ); const isIOS = Platform.OS === 'ios'; const hitSlop = { top: 22, bottom: 22, left: 22, right: 22 }; - - const [ hue, setHue ] = useState( 0 ); - const [ sat, setSaturation ] = useState( 0.5 ); - const [ val, setValue ] = useState( 0.5 ); + const { h: initH, s: initS, v: initV } = + ! isGradientColor && activeColor + ? tinycolor( activeColor ).toHsv() + : { h: 0, s: 0.5, v: 0.5 }; + const [ hue, setHue ] = useState( initH ); + const [ sat, setSaturation ] = useState( initS ); + const [ val, setValue ] = useState( initV ); const [ savedColor ] = useState( activeColor ); const { @@ -71,32 +76,24 @@ function ColorPicker( { `hsv ${ hue } ${ sat } ${ val }` ).toHexString(); - function setHSVFromHex( color ) { - const { h, s, v } = tinycolor( color ).toHsv(); - - setHue( h ); - setSaturation( s ); - setValue( v ); - } - useEffect( () => { + if ( ! didMount.current ) { + didMount.current = true; + return; + } setColor( currentColor ); }, [ currentColor ] ); useEffect( () => { - if ( ! isGradientColor && activeColor ) { - setHSVFromHex( activeColor ); - } - setColor( activeColor ); - shouldDisableBottomSheetMaxHeight( false ); - onCloseBottomSheet( () => { + shouldEnableBottomSheetMaxHeight( false ); + onHandleClosingBottomSheet( () => { setColor( savedColor ); if ( onBottomSheetClosed ) { onBottomSheetClosed(); } } ); - if ( onHardwareButtonPress ) { - onHardwareButtonPress( onButtonPress ); + if ( onHandleHardwareButtonPress ) { + onHandleHardwareButtonPress( onButtonPress ); } }, [] ); @@ -111,8 +108,8 @@ function ColorPicker( { function onButtonPress( action ) { onNavigationBack(); - onCloseBottomSheet( null ); - shouldDisableBottomSheetMaxHeight( true ); + onHandleClosingBottomSheet( null ); + shouldEnableBottomSheetMaxHeight( true ); setColor( action === 'apply' ? currentColor : savedColor ); if ( onBottomSheetClosed ) { onBottomSheetClosed(); diff --git a/packages/components/src/custom-gradient-picker/index.native.js b/packages/components/src/custom-gradient-picker/index.native.js index 696078941d5a6..52d662df0a9bb 100644 --- a/packages/components/src/custom-gradient-picker/index.native.js +++ b/packages/components/src/custom-gradient-picker/index.native.js @@ -13,7 +13,6 @@ import { useState } from '@wordpress/element'; * Internal dependencies */ import { colorsUtils } from '../mobile/color-settings/utils'; -import { performLayoutAnimation } from '../mobile/layout-animation'; import { getGradientParsed } from './utils'; import { serializeGradient } from './serializer'; import { @@ -22,14 +21,16 @@ import { } from './constants'; import styles from './style.scss'; -function CustomGradientPicker( { currentValue, setColor, isGradientColor } ) { +function CustomGradientPicker( { setColor, currentValue, isGradientColor } ) { const [ gradientOrientation, setGradientOrientation ] = useState( HORIZONTAL_GRADIENT_ORIENTATION ); + const [ currentColor, setCurrentColor ] = useState( currentValue ); + const { getGradientType, gradients, gradientOptions } = colorsUtils; - const { gradientAST } = getGradientParsed( currentValue ); - const gradientType = getGradientType( currentValue ); + const { gradientAST } = getGradientParsed( currentColor ); + const gradientType = getGradientType( currentColor ); function isLinearGradient( type ) { return type === gradients.linear; @@ -62,7 +63,7 @@ function CustomGradientPicker( { currentValue, setColor, isGradientColor } ) { function onGradientTypeChange( type ) { const gradientColor = getGradientColor( type ); - performLayoutAnimation(); + setCurrentColor( gradientColor ); setColor( gradientColor ); } @@ -75,7 +76,8 @@ function CustomGradientPicker( { currentValue, setColor, isGradientColor } ) { }, } ); - if ( isGradientColor && gradientColor !== currentValue ) { + if ( isGradientColor && gradientColor !== currentColor ) { + setCurrentColor( gradientColor ); setColor( gradientColor ); } } @@ -87,7 +89,6 @@ function CustomGradientPicker( { currentValue, setColor, isGradientColor } ) { DEFAULT_LINEAR_GRADIENT_ANGLE ); } - return ( <> diff --git a/packages/components/src/index.native.js b/packages/components/src/index.native.js index fe5a8df75c8f2..18c46804e64ef 100644 --- a/packages/components/src/index.native.js +++ b/packages/components/src/index.native.js @@ -59,7 +59,11 @@ export * from './text'; // Mobile Components export { default as BottomSheet } from './mobile/bottom-sheet'; -export { BottomSheetConsumer } from './mobile/bottom-sheet/bottom-sheet-context'; +export { + BottomSheetConsumer, + BottomSheetProvider, + BottomSheetContext, +} from './mobile/bottom-sheet/bottom-sheet-context'; export { default as HTMLTextInput } from './mobile/html-text-input'; export { default as KeyboardAvoidingView } from './mobile/keyboard-avoiding-view'; export { default as KeyboardAwareFlatList } from './mobile/keyboard-aware-flat-list'; diff --git a/packages/components/src/mobile/bottom-sheet/bottom-sheet-context.native.js b/packages/components/src/mobile/bottom-sheet/bottom-sheet-context.native.js index 9252e5daf3ac4..ebfc384f53069 100644 --- a/packages/components/src/mobile/bottom-sheet/bottom-sheet-context.native.js +++ b/packages/components/src/mobile/bottom-sheet/bottom-sheet-context.native.js @@ -18,26 +18,23 @@ if ( // Context in BottomSheet is necessary for controlling the // transition flow between subsheets and replacing a content inside them -export const { - Provider: BottomSheetProvider, - Consumer: BottomSheetConsumer, -} = createContext( { +export const BottomSheetContext = createContext( { // Specifies whether content is currently scrolling isBottomSheetContentScrolling: false, // Function called to enable scroll within bottom sheet shouldEnableBottomSheetScroll: () => {}, - // Function called to disable bottom sheet max height. + // Function called to enable/disable bottom sheet max height. // E.g. used to extend bottom sheet on full screen in ColorPicker, // which is helpful on small devices with set the largest font/display size. - shouldDisableBottomSheetMaxHeight: () => {}, + shouldEnableBottomSheetMaxHeight: () => {}, // Callback that is called on closing bottom sheet - onCloseBottomSheet: () => {}, + onHandleClosingBottomSheet: () => {}, // Android only: Function called to control android hardware back button functionality - onHardwareButtonPress: () => {}, - // Function called to navigate to another subsheet - onReplaceSubsheet: () => {}, - // Object contains extra data passed to the current subsheet - extraProps: {}, - // Specifies the currently active subsheet name - currentScreen: undefined, + // Return true if the bottom-sheet default close action shouldn't be called + onHandleHardwareButtonPress: () => {}, } ); + +export const { + Provider: BottomSheetProvider, + Consumer: BottomSheetConsumer, +} = BottomSheetContext; diff --git a/packages/components/src/mobile/bottom-sheet/bottom-sheet-navigation/README.md b/packages/components/src/mobile/bottom-sheet/bottom-sheet-navigation/README.md new file mode 100644 index 0000000000000..4ad61cc91f66d --- /dev/null +++ b/packages/components/src/mobile/bottom-sheet/bottom-sheet-navigation/README.md @@ -0,0 +1,88 @@ +# BottomSheet Navigation +We use [`react-navigation`](https://reactnavigation.org/) v5 to handle multiple screens inside the bottom-sheet. We have two components that help use it w/o additional settings. +- BottomSheet.NavigationContainer +- BottomSheet.NavigationScreen + +## BottomSheet.NavigationContainer + +`BottomSheet.NavigationContainer` is a React component to render a Stack Navigator with settings prepared for the Bottom-Sheet. This component also handles the height animation of bottom-sheet when back or pushing a new screen. + +**NOTE:** Children of the `BottomSheet.NavigationContainer` can be only `BottomSheet.NavigationScreen` + +## BottomSheet.NavigationScreen + +`BottomSheet.NavigationScreen` is a React component to render a Screen inside the stack that is passed from parent. This component can be rendered only inside the `BottomSheet.NavigationContainer` and is responsible for handling the hardware back button on Android and setting the correct height of the parent (container). + + +## Usage + + +```jsx +import { BottomSheet } from '@wordpress/components'; + + +const BottomSheetWithNavigation = () => ( +  +    +      +        +      +      +        +      +    +); +``` + +## Props + +### BottomSheet.NavigationContainer +The component accepts the following props. + +### animate + +This prop determines if the container height should be animated. It should be set to `true` only for the root container in BottomSheet. In nested `BottomSheet.NavigationContainer` set it to `false`. + +- Type: `Boolean` +- Required: No +- Default: `false` + +### main + +Since we do not wrap the whole editor inside navigation (yet) we need to determine if the container is the very top one (root one). Set it to `true` in only for NOT nested navigation container. + +Note: This prop is needed until we wrap the editor inside the navigation container. + +- Type: `Boolean` +- Required: No +- Default: `false` + +### theme + +This prop is to set the theme of navigation containers. Please read: https://reactnavigation.org/docs/themes/ + +- Type: `Object` +- Required: No + + +### BottomSheet.NavigationScreen +The component accepts the following props. Props not included in this set will be applied to the Stack.Screen from `react-navigation`. + +### name + +This prop is used as a Screen name. + +- Type: `String` +- Required: Yes + +### children + +The component that should be rendered as content. + +- Type: React Element +- Required: Yes \ No newline at end of file diff --git a/packages/components/src/mobile/bottom-sheet/bottom-sheet-navigation/bottom-sheet-navigation-context.native.js b/packages/components/src/mobile/bottom-sheet/bottom-sheet-navigation/bottom-sheet-navigation-context.native.js new file mode 100644 index 0000000000000..9e89c285b2534 --- /dev/null +++ b/packages/components/src/mobile/bottom-sheet/bottom-sheet-navigation/bottom-sheet-navigation-context.native.js @@ -0,0 +1,16 @@ +/** + * WordPress dependencies + */ +import { createContext } from '@wordpress/element'; + +// Navigation context in BottomSheet is necessary for controlling the +// height of navigation container. +export const BottomSheetNavigationContext = createContext( { + currentHeight: 1, + setHeight: () => {}, +} ); + +export const { + Provider: BottomSheetNavigationProvider, + Consumer: BottomSheetNavigationConsumer, +} = BottomSheetNavigationContext; diff --git a/packages/components/src/mobile/bottom-sheet/bottom-sheet-navigation/navigation-container.native.js b/packages/components/src/mobile/bottom-sheet/bottom-sheet-navigation/navigation-container.native.js new file mode 100644 index 0000000000000..a8b802d6cf2cb --- /dev/null +++ b/packages/components/src/mobile/bottom-sheet/bottom-sheet-navigation/navigation-container.native.js @@ -0,0 +1,129 @@ +/** + * External dependencies + */ +import { View, Easing } from 'react-native'; +import { NavigationContainer, DefaultTheme } from '@react-navigation/native'; +import { createStackNavigator } from '@react-navigation/stack'; + +/** + * WordPress dependencies + */ +import { + useState, + useContext, + useMemo, + Children, + useRef, +} from '@wordpress/element'; + +import { usePreferredColorSchemeStyle } from '@wordpress/compose'; + +/** + * Internal dependencies + */ +import { performLayoutAnimation } from '../../layout-animation'; +import { + BottomSheetNavigationContext, + BottomSheetNavigationProvider, +} from './bottom-sheet-navigation-context'; + +import styles from './styles.scss'; + +const AnimationSpec = { + animation: 'timing', + config: { + duration: 200, + easing: Easing.ease, + }, +}; + +const fadeConfig = ( { current } ) => { + return { + cardStyle: { + opacity: current.progress, + }, + }; +}; + +const options = { + transitionSpec: { + open: AnimationSpec, + close: AnimationSpec, + }, + headerShown: false, + gestureEnabled: false, + cardStyleInterpolator: fadeConfig, +}; + +const ANIMATION_DURATION = 190; + +function BottomSheetNavigationContainer( { children, animate, main, theme } ) { + const Stack = useRef( createStackNavigator() ).current; + const context = useContext( BottomSheetNavigationContext ); + const [ currentHeight, setCurrentHeight ] = useState( + context.currentHeight || 1 + ); + + const backgroundStyle = usePreferredColorSchemeStyle( + styles.background, + styles.backgroundDark + ); + + const _theme = theme || { + ...DefaultTheme, + colors: { + ...DefaultTheme.colors, + background: backgroundStyle.backgroundColor, + }, + }; + + const setHeight = ( height, layout ) => { + if ( currentHeight !== height && height > 1 ) { + if ( animate && layout && currentHeight === 1 ) { + setCurrentHeight( height ); + } else if ( animate ) { + performLayoutAnimation( ANIMATION_DURATION ); + setCurrentHeight( height ); + } else { + setCurrentHeight( height ); + } + } + }; + + const screens = useMemo( () => { + return Children.map( children, ( child ) => { + const { name, ...otherProps } = child.props; + return ( + child } + /> + ); + } ); + }, [ children ] ); + + return useMemo( () => { + return ( + + + { main ? ( + + + { screens } + + + ) : ( + + { screens } + + ) } + + + ); + }, [ currentHeight ] ); +} + +export default BottomSheetNavigationContainer; diff --git a/packages/components/src/mobile/bottom-sheet/bottom-sheet-navigation/navigation-screen.native.js b/packages/components/src/mobile/bottom-sheet/bottom-sheet-navigation/navigation-screen.native.js new file mode 100644 index 0000000000000..3c13517f1a0d2 --- /dev/null +++ b/packages/components/src/mobile/bottom-sheet/bottom-sheet-navigation/navigation-screen.native.js @@ -0,0 +1,67 @@ +/** + * External dependencies + */ +import { + useFocusEffect, + useIsFocused, + useNavigation, +} from '@react-navigation/native'; +import { View } from 'react-native'; +import { debounce } from 'lodash'; + +/** + * WordPress dependencies + */ +import { BottomSheetContext } from '@wordpress/components'; + +import { useRef, useCallback, useContext, useMemo } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { BottomSheetNavigationContext } from './bottom-sheet-navigation-context'; + +const BottomSheetNavigationScreen = ( { children } ) => { + const navigation = useNavigation(); + const heightRef = useRef( { maxHeight: 0 } ); + const isFocused = useIsFocused(); + const { + onHandleHardwareButtonPress, + shouldEnableBottomSheetMaxHeight, + } = useContext( BottomSheetContext ); + + const { setHeight } = useContext( BottomSheetNavigationContext ); + + const setHeightDebounce = useCallback( debounce( setHeight, 10 ), [] ); + + useFocusEffect( + useCallback( () => { + onHandleHardwareButtonPress( () => { + if ( navigation.canGoBack() ) { + shouldEnableBottomSheetMaxHeight( true ); + navigation.goBack(); + return true; + } + onHandleHardwareButtonPress( null ); + return false; + } ); + if ( heightRef.current.maxHeight !== 0 ) { + setHeight( heightRef.current.maxHeight ); + } + return () => {}; + }, [] ) + ); + const onLayout = ( { nativeEvent } ) => { + const { height } = nativeEvent.layout; + if ( heightRef.current.maxHeight !== height && isFocused ) { + heightRef.current.maxHeight = height; + setHeightDebounce( height, true ); + } + }; + + return useMemo( () => { + return { children }; + }, [ children, isFocused ] ); +}; + +export default BottomSheetNavigationScreen; diff --git a/packages/components/src/mobile/bottom-sheet/bottom-sheet-navigation/styles.native.scss b/packages/components/src/mobile/bottom-sheet/bottom-sheet-navigation/styles.native.scss new file mode 100644 index 0000000000000..ebed998355726 --- /dev/null +++ b/packages/components/src/mobile/bottom-sheet/bottom-sheet-navigation/styles.native.scss @@ -0,0 +1,7 @@ +.background { + background-color: $white; +} + +.backgroundDark { + background-color: $background-dark-elevated; +} diff --git a/packages/components/src/mobile/bottom-sheet/index.native.js b/packages/components/src/mobile/bottom-sheet/index.native.js index f617098f2ac35..2a407d34cea61 100644 --- a/packages/components/src/mobile/bottom-sheet/index.native.js +++ b/packages/components/src/mobile/bottom-sheet/index.native.js @@ -34,9 +34,10 @@ import SwitchCell from './switch-cell'; import RangeCell from './range-cell'; import ColorCell from './color-cell'; import RadioCell from './radio-cell'; +import NavigationScreen from './bottom-sheet-navigation/navigation-screen'; +import NavigationContainer from './bottom-sheet-navigation/navigation-container'; import KeyboardAvoidingView from './keyboard-avoiding-view'; import { BottomSheetProvider } from './bottom-sheet-context'; -import { performLayoutAnimation } from '../layout-animation'; class BottomSheet extends Component { constructor() { @@ -48,6 +49,7 @@ class BottomSheet extends Component { this.onShouldSetBottomSheetMaxHeight = this.onShouldSetBottomSheetMaxHeight.bind( this ); + this.onDimensionsChange = this.onDimensionsChange.bind( this ); this.onCloseBottomSheet = this.onCloseBottomSheet.bind( this ); this.onHandleClosingBottomSheet = this.onHandleClosingBottomSheet.bind( @@ -57,7 +59,6 @@ class BottomSheet extends Component { this.onHandleHardwareButtonPress = this.onHandleHardwareButtonPress.bind( this ); - this.onReplaceSubsheet = this.onReplaceSubsheet.bind( this ); this.keyboardWillShow = this.keyboardWillShow.bind( this ); this.keyboardDidHide = this.keyboardDidHide.bind( this ); @@ -68,11 +69,9 @@ class BottomSheet extends Component { keyboardHeight: 0, scrollEnabled: true, isScrolling: false, - onCloseBottomSheet: null, - onHardwareButtonPress: null, + handleClosingBottomSheet: null, + handleHardwareButtonPress: null, isMaxHeightSet: true, - currentScreen: '', - extraProps: {}, }; SafeArea.getSafeAreaInsetsForRootView().then( @@ -120,6 +119,8 @@ class BottomSheet extends Component { } componentWillUnmount() { + this.keyboardWillShowListener.remove(); + this.keyboardDidHideListener.remove(); if ( this.androidModalClosedSubscription ) { this.androidModalClosedSubscription.remove(); } @@ -132,16 +133,6 @@ class BottomSheet extends Component { 'safeAreaInsetsForRootViewDidChange', this.onSafeAreaInsetsUpdate ); - this.keyboardWillShowListener.remove(); - this.keyboardDidHideListener.remove(); - } - - componentDidUpdate( prevProps ) { - const { isVisible } = this.props; - - if ( ! prevProps.isVisible && isVisible ) { - this.setState( { currentScreen: '' } ); - } } onSafeAreaInsetsUpdate( result ) { @@ -221,29 +212,34 @@ class BottomSheet extends Component { } onHandleClosingBottomSheet( action ) { - this.setState( { onCloseBottomSheet: action } ); + this.setState( { handleClosingBottomSheet: action } ); } onHandleHardwareButtonPress( action ) { - this.setState( { onHardwareButtonPress: action } ); + this.setState( { handleHardwareButtonPress: action } ); } onCloseBottomSheet() { const { onClose } = this.props; - const { onCloseBottomSheet } = this.state; - if ( onCloseBottomSheet ) { - onCloseBottomSheet(); + const { handleClosingBottomSheet } = this.state; + if ( handleClosingBottomSheet ) { + handleClosingBottomSheet(); } - onClose(); + if ( onClose ) { + onClose(); + } + this.onShouldSetBottomSheetMaxHeight( true ); } onHardwareButtonPress() { const { onClose } = this.props; - const { onHardwareButtonPress } = this.state; - if ( onHardwareButtonPress ) { - return onHardwareButtonPress(); + const { handleHardwareButtonPress } = this.state; + if ( handleHardwareButtonPress && handleHardwareButtonPress() ) { + return; + } + if ( onClose ) { + return onClose(); } - return onClose(); } getContentStyle() { @@ -256,18 +252,6 @@ class BottomSheet extends Component { }; } - onReplaceSubsheet( destination, extraProps, callback ) { - performLayoutAnimation(); - - this.setState( - { - currentScreen: destination, - extraProps: extraProps || {}, - }, - callback - ); - } - render() { const { title = '', @@ -291,8 +275,6 @@ class BottomSheet extends Component { isScrolling, scrollEnabled, isMaxHeightSet, - extraProps, - currentScreen, } = this.state; const panResponder = PanResponder.create( { @@ -362,7 +344,7 @@ class BottomSheet extends Component { @@ -451,5 +430,7 @@ ThemedBottomSheet.SwitchCell = SwitchCell; ThemedBottomSheet.RangeCell = RangeCell; ThemedBottomSheet.ColorCell = ColorCell; ThemedBottomSheet.RadioCell = RadioCell; +ThemedBottomSheet.NavigationScreen = NavigationScreen; +ThemedBottomSheet.NavigationContainer = NavigationContainer; export default ThemedBottomSheet; diff --git a/packages/components/src/mobile/bottom-sheet/range-cell.native.js b/packages/components/src/mobile/bottom-sheet/range-cell.native.js index b34e369aa5079..f42b406b1c0e0 100644 --- a/packages/components/src/mobile/bottom-sheet/range-cell.native.js +++ b/packages/components/src/mobile/bottom-sheet/range-cell.native.js @@ -188,9 +188,9 @@ class BottomSheetRangeCell extends Component { styles.sliderDarkTextInput ); - const cellRowContainerStyle = [ - styles.cellRowStyles, - isIOS ? styles.cellRowStylesIOS : styles.cellRowStylesAndroid, + const containerStyle = [ + styles.container, + isIOS ? styles.containerIOS : styles.containerAndroid, ]; return ( @@ -200,7 +200,7 @@ class BottomSheetRangeCell extends Component { styles.cellContainerStyles, cellContainerStyle, ] } - cellRowContainerStyle={ cellRowContainerStyle } + cellRowContainerStyle={ containerStyle } accessibilityRole={ 'none' } value={ '' } editable={ false } @@ -213,7 +213,7 @@ class BottomSheetRangeCell extends Component { __( 'Double tap to change the value using slider' ) } > - + { rangePreview } { + const navigation = useNavigation(); + const route = useRoute(); + const { setColor, currentValue, isGradientColor } = route.params; + return ( + + + + + ); +}; + +export default GradientPickerScreen; diff --git a/packages/components/src/mobile/color-settings/index.native.js b/packages/components/src/mobile/color-settings/index.native.js index 79aa0c8a98aec..ec8be2ac573c6 100644 --- a/packages/components/src/mobile/color-settings/index.native.js +++ b/packages/components/src/mobile/color-settings/index.native.js @@ -1,240 +1,84 @@ /** * External dependencies */ -import { View, Text } from 'react-native'; +import React from 'react'; + /** * WordPress dependencies */ -import { __ } from '@wordpress/i18n'; -import { useState, useEffect } from '@wordpress/element'; -import { usePreferredColorSchemeStyle } from '@wordpress/compose'; -import { ColorControl, PanelBody } from '@wordpress/components'; +import { useEffect, useContext } from '@wordpress/element'; +import { BottomSheetContext, BottomSheet } from '@wordpress/components'; +import { useRoute } from '@react-navigation/native'; + /** * Internal dependencies */ -import ColorPicker from '../../color-picker'; -import ColorPalette from '../../color-palette'; -import ColorIndicator from '../../color-indicator'; -import CustomGradientPicker from '../../custom-gradient-picker'; -import NavigationHeader from '../bottom-sheet/navigation-header'; -import SegmentedControls from '../segmented-control'; -import { colorsUtils } from './utils'; -import { performLayoutAnimation } from '../layout-animation'; - -import styles from './style.scss'; - -function ColorSettings( { - label, - onColorChange, - onGradientChange, - colorValue, - onReplaceSubsheet, - shouldEnableBottomSheetScroll, - shouldDisableBottomSheetMaxHeight, - isBottomSheetContentScrolling, - onCloseBottomSheet, - onHardwareButtonPress, - defaultSettings, -} ) { - const [ currentValue, setCurrentValue ] = useState( colorValue ); - const [ isCustomScreen, setIsCustomScreen ] = useState( false ); - const [ isCustomGradientScreen, setIsCustomGradientScreen ] = useState( - false - ); - - const { segments, subsheets, isGradient } = colorsUtils; - const isGradientColor = isGradient( currentValue ); - const selectedSegmentIndex = isGradientColor ? 1 : 0; - - const [ currentSegment, setCurrentSegment ] = useState( - segments[ selectedSegmentIndex ] - ); - - const isSolidSegment = currentSegment === segments[ 0 ]; - const isCustomGadientShown = ! isSolidSegment && isGradientColor; - - const horizontalSeparatorStyle = usePreferredColorSchemeStyle( - styles.horizontalSeparator, - styles.horizontalSeparatorDark - ); - - useEffect( () => { - onHardwareButtonPress( () => { - if ( isCustomScreen ) { - onCustomScreenToggle( false ); - } else if ( isCustomGradientScreen ) { - onCustomGradientScreenToggle( false ); - } else { - onReplaceSubsheet( - subsheets[ 0 ], - {}, - afterHardwareButtonPress() - ); - } - } ); - }, [ isCustomScreen, isCustomGradientScreen ] ); - - useEffect( () => { - performLayoutAnimation(); - }, [ isCustomGadientShown ] ); +import PickerScreen from './picker-screen'; +import GradientPickerScreen from './gradient-picker-screen'; +import PaletteScreen from './palette.screen'; - useEffect( () => { - setCurrentSegment( segments[ selectedSegmentIndex ] ); - shouldDisableBottomSheetMaxHeight( true ); - onCloseBottomSheet( null ); - }, [] ); - - function afterHardwareButtonPress() { - onHardwareButtonPress( null ); - shouldDisableBottomSheetMaxHeight( true ); - } - - function onCustomScreenToggle( shouldShow ) { - performLayoutAnimation(); - setIsCustomScreen( shouldShow ); - } - - function onCustomGradientScreenToggle( shouldShow ) { - performLayoutAnimation(); - setIsCustomGradientScreen( shouldShow ); - } - - function onCustomPress() { - if ( isSolidSegment ) { - onCustomScreenToggle( true ); - } else { - onCustomGradientScreenToggle( true ); - } - } - - function setColor( color ) { - setCurrentValue( color ); - if ( isSolidSegment && onColorChange && onGradientChange ) { - onColorChange( color ); - onGradientChange( '' ); - } else if ( isSolidSegment && onColorChange ) { - onColorChange( color ); - } else if ( ! isSolidSegment && onGradientChange ) { - onGradientChange( color ); - onColorChange( '' ); - } - } +import { colorsUtils } from './utils'; - function getFooter() { - if ( onGradientChange ) { - return ( - - ) - } - /> - ); - } +const ColorSettingsMemo = React.memo( + ( { + defaultSettings, + onHandleClosingBottomSheet, + shouldEnableBottomSheetMaxHeight, + onColorChange, + colorValue, + gradientValue, + onGradientChange, + label, + } ) => { + useEffect( () => { + shouldEnableBottomSheetMaxHeight( true ); + onHandleClosingBottomSheet( null ); + }, [] ); return ( - - - { currentValue && ( - - ) } - - + - { __( 'Select a color' ) } - - - + + + + + + + + + ); } +); +function ColorSettings( props ) { + const route = useRoute(); + const { + onHandleClosingBottomSheet, + shouldEnableBottomSheetMaxHeight, + } = useContext( BottomSheetContext ); return ( - - { isCustomScreen && ( - - onCustomScreenToggle( false ) } - onCloseBottomSheet={ onCloseBottomSheet } - isBottomSheetContentScrolling={ - isBottomSheetContentScrolling - } - /> - - ) } - { ! isCustomScreen && ! isCustomGradientScreen && ( - - - onReplaceSubsheet( subsheets[ 0 ] ) - } - /> - - { isCustomGadientShown && ( - <> - - - - onCustomGradientScreenToggle( true ) - } - withColorIndicator={ false } - /> - - - ) } - - { getFooter() } - - ) } - { isCustomGradientScreen && ( - - - onCustomGradientScreenToggle( false ) - } - /> - - - ) } - + ); } diff --git a/packages/components/src/mobile/color-settings/palette.screen.native.js b/packages/components/src/mobile/color-settings/palette.screen.native.js new file mode 100644 index 0000000000000..91cd1cc8e7195 --- /dev/null +++ b/packages/components/src/mobile/color-settings/palette.screen.native.js @@ -0,0 +1,156 @@ +/** + * External dependencies + */ +import { View, Text } from 'react-native'; + +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { useState, useContext } from '@wordpress/element'; +import { usePreferredColorSchemeStyle } from '@wordpress/compose'; +import { + ColorControl, + PanelBody, + BottomSheetContext, +} from '@wordpress/components'; +import { useRoute, useNavigation } from '@react-navigation/native'; +/** + * Internal dependencies + */ +import ColorPalette from '../../color-palette'; +import ColorIndicator from '../../color-indicator'; +import NavigationHeader from '../bottom-sheet/navigation-header'; +import SegmentedControls from '../segmented-control'; +import { colorsUtils } from './utils'; + +import styles from './style.scss'; + +const PaletteScreen = () => { + const route = useRoute(); + const navigation = useNavigation(); + const { shouldEnableBottomSheetScroll } = useContext( BottomSheetContext ); + const { + label, + onColorChange, + onGradientChange, + colorValue, + defaultSettings, + } = route.params || {}; + const { segments, isGradient } = colorsUtils; + const [ currentValue, setCurrentValue ] = useState( colorValue ); + const isGradientColor = isGradient( currentValue ); + const selectedSegmentIndex = isGradientColor ? 1 : 0; + + const [ currentSegment, setCurrentSegment ] = useState( + segments[ selectedSegmentIndex ] + ); + + const horizontalSeparatorStyle = usePreferredColorSchemeStyle( + styles.horizontalSeparator, + styles.horizontalSeparatorDark + ); + + const isSolidSegment = currentSegment === segments[ 0 ]; + const isCustomGadientShown = ! isSolidSegment && isGradientColor; + + const setColor = ( color ) => { + setCurrentValue( color ); + if ( isSolidSegment && onColorChange && onGradientChange ) { + onColorChange( color ); + onGradientChange( '' ); + } else if ( isSolidSegment && onColorChange ) { + onColorChange( color ); + } else if ( ! isSolidSegment && onGradientChange ) { + onGradientChange( color ); + onColorChange( '' ); + } + }; + + function onCustomPress() { + if ( isSolidSegment ) { + navigation.navigate( colorsUtils.screens.picker, { + currentValue, + setColor, + } ); + } else { + navigation.navigate( colorsUtils.screens.gradientPicker, { + setColor, + isGradientColor, + currentValue, + } ); + } + } + + function getFooter() { + if ( onGradientChange ) { + return ( + + ) + } + /> + ); + } + return ( + + + { currentValue && ( + + ) } + + + { __( 'Select a color' ) } + + + + ); + } + return ( + + + + { isCustomGadientShown && ( + <> + + + + + + ) } + + { getFooter() } + + ); +}; + +export default PaletteScreen; diff --git a/packages/components/src/mobile/color-settings/picker-screen.native.js b/packages/components/src/mobile/color-settings/picker-screen.native.js new file mode 100644 index 0000000000000..3d11cbae38a82 --- /dev/null +++ b/packages/components/src/mobile/color-settings/picker-screen.native.js @@ -0,0 +1,60 @@ +/** + * External dependencies + */ +import { useRoute, useNavigation } from '@react-navigation/native'; +import React from 'react'; + +/** + * WordPress dependencies + */ +import { useContext, useMemo } from '@wordpress/element'; +import { BottomSheetContext } from '@wordpress/components'; + +/** + * Internal dependencies + */ +import ColorPicker from '../../color-picker'; + +const PickerScreen = () => { + const route = useRoute(); + const navigation = useNavigation(); + const { + onShouldEnableInnerHandling, + shouldEnableBottomSheetMaxHeight, + onHandleClosingBottomSheet, + isBottomSheetContentScrolling, + shouldEnableBottomSheetScroll, + onHandleHardwareButtonPress, + } = useContext( BottomSheetContext ); + const { setColor, currentValue, isGradientColor } = route.params; + return useMemo( () => { + return ( + + ); + }, [ + setColor, + currentValue, + isGradientColor, + onShouldEnableInnerHandling, + shouldEnableBottomSheetMaxHeight, + onHandleClosingBottomSheet, + isBottomSheetContentScrolling, + shouldEnableBottomSheetScroll, + onHandleHardwareButtonPress, + ] ); +}; + +export default PickerScreen; diff --git a/packages/components/src/mobile/color-settings/utils.native.js b/packages/components/src/mobile/color-settings/utils.native.js index e331f601e4b4c..a49da82b08008 100644 --- a/packages/components/src/mobile/color-settings/utils.native.js +++ b/packages/components/src/mobile/color-settings/utils.native.js @@ -18,9 +18,10 @@ const getGradientType = ( color ) => { }; export const colorsUtils = { - subsheets: { - settings: 'Settings', - color: 'Color', + screens: { + gradientPicker: 'GradientPicker', + picker: 'Picker', + palette: 'Palette', }, segments: [ 'Solid', 'Gradient' ], gradients, diff --git a/packages/react-native-bridge/android/build.gradle b/packages/react-native-bridge/android/build.gradle index 9eb117f9d2754..efc20f008d4f5 100644 --- a/packages/react-native-bridge/android/build.gradle +++ b/packages/react-native-bridge/android/build.gradle @@ -155,6 +155,11 @@ dependencies { implementation project(':react-native-video') implementation project(':@react-native-community_slider') implementation project(':react-native-get-random-values') + implementation project(':@react-native-community_masked-view') + implementation project(':react-native-gesture-handler') + implementation project(':react-native-screens') + implementation project(':react-native-safe-area-context') + implementation project(':react-native-reanimated') implementation 'com.facebook.react:react-native:+' } else { @@ -165,6 +170,11 @@ dependencies { implementation (waitJitpack('com.github.wordpress-mobile', 'react-native-linear-gradient', readHashedVersion('../../react-native-editor/package.json', 'react-native-linear-gradient', 'dependencies'))) implementation (waitJitpack('com.github.wordpress-mobile', 'react-native-slider', readHashedVersion('../../react-native-editor/package.json', '@react-native-community/slider', 'dependencies'))) implementation (waitJitpack('com.github.wordpress-mobile', 'react-native-get-random-values', readHashedVersion('../../react-native-editor/package.json', 'react-native-get-random-values', 'dependencies'))) + implementation (waitJitpack('com.github.wordpress-mobile', 'react-native-masked-view', readHashedVersion('../../react-native-editor/package.json', '@react-native-community/masked-view', 'dependencies'))) + implementation (waitJitpack('com.github.wordpress-mobile', 'react-native-gesture-handler', readHashedVersion('../../react-native-editor/package.json', 'react-native-gesture-handler', 'dependencies'))) + implementation (waitJitpack('com.github.wordpress-mobile', 'react-native-screens', readHashedVersion('../../react-native-editor/package.json', 'react-native-screens', 'dependencies'))) + implementation (waitJitpack('com.github.wordpress-mobile', 'react-native-safe-area-context', readHashedVersion('../../react-native-editor/package.json', 'react-native-safe-area-context', 'dependencies'))) + implementation (waitJitpack('com.github.wordpress-mobile', 'react-native-reanimated', readHashedVersion('../../react-native-editor/package.json', 'react-native-reanimated', 'dependencies'))) // FIXME Temporary fix to get Jitpack builds to green while I work on a solution without hardcoded values. //def rnVersion = readReactNativeVersion('../package.json', 'peerDependencies') 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 27e59f4cdc05d..7a1d236deae19 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 @@ -37,6 +37,12 @@ import com.BV.LinearGradient.LinearGradientPackage; import com.reactnativecommunity.slider.ReactSliderPackage; import org.linusu.RNGetRandomValuesPackage; +import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView; +import com.swmansion.gesturehandler.react.RNGestureHandlerPackage; +import com.swmansion.reanimated.ReanimatedPackage; +import com.swmansion.rnscreens.RNScreensPackage; +import com.th3rdwave.safeareacontext.SafeAreaContextPackage; +import org.reactnative.maskedview.RNCMaskedViewPackage; import org.wordpress.android.util.AppLog; import org.wordpress.mobile.ReactNativeAztec.ReactAztecPackage; @@ -392,6 +398,11 @@ public void requestStarterPageTemplatesTooltipShown(StarterPageTemplatesTooltipS new ReactVideoPackage(), new ReactSliderPackage(), new RNGetRandomValuesPackage(), + new RNGestureHandlerPackage(), + new RNScreensPackage(), + new SafeAreaContextPackage(), + new RNCMaskedViewPackage(), + new ReanimatedPackage(), mRnReactNativeGutenbergBridgePackage); } @@ -415,7 +426,7 @@ public void onCreateView(Context initContext, mIsDarkMode = gutenbergProps.isDarkMode(); mExceptionLogger = exceptionLogger; mBreadcrumbLogger = breadcrumbLogger; - mReactRootView = new ReactRootView(new MutableContextWrapper(initContext)); + mReactRootView = new RNGestureHandlerEnabledRootView(new MutableContextWrapper(initContext)); mReactRootView.setBackgroundColor(colorBackground); ReactInstanceManagerBuilder builder = diff --git a/packages/react-native-editor/android/app/build.gradle b/packages/react-native-editor/android/app/build.gradle index 3f150b4c1669d..fc595ce89b2e6 100644 --- a/packages/react-native-editor/android/app/build.gradle +++ b/packages/react-native-editor/android/app/build.gradle @@ -166,6 +166,11 @@ dependencies { implementation project(':react-native-video') implementation project(':react-native-svg') implementation project(':react-native-get-random-values') + implementation project(':@react-native-community_masked-view') + implementation project(':react-native-gesture-handler') + implementation project(':react-native-screens') + implementation project(':react-native-safe-area-context') + implementation project(':react-native-reanimated') implementation "org.wordpress:utils:$wordpressUtilsVersion" implementation 'androidx.appcompat:appcompat:1.0.0' implementation "com.facebook.react:react-native:+" // From node_modules 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 fe21447c9f622..e9dbb45a78915 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 @@ -31,6 +31,11 @@ import com.facebook.react.ReactPackage; import com.facebook.react.shell.MainReactPackage; import com.facebook.soloader.SoLoader; +import com.swmansion.gesturehandler.react.RNGestureHandlerPackage; +import com.swmansion.reanimated.ReanimatedPackage; +import com.swmansion.rnscreens.RNScreensPackage; +import com.th3rdwave.safeareacontext.SafeAreaContextPackage; +import org.reactnative.maskedview.RNCMaskedViewPackage; import java.util.Arrays; import java.util.List; @@ -185,6 +190,11 @@ protected List getPackages() { new ReactAztecPackage(null, null), new LinearGradientPackage(), new RNGetRandomValuesPackage(), + new RNCMaskedViewPackage(), + new RNGestureHandlerPackage(), + new ReanimatedPackage(), + new SafeAreaContextPackage(), + new RNScreensPackage(), mRnReactNativeGutenbergBridgePackage); } diff --git a/packages/react-native-editor/android/settings.gradle b/packages/react-native-editor/android/settings.gradle index f7ae4dfa566f5..733c341d7fc5f 100644 --- a/packages/react-native-editor/android/settings.gradle +++ b/packages/react-native-editor/android/settings.gradle @@ -14,5 +14,15 @@ include ':react-native-linear-gradient' project(':react-native-linear-gradient').projectDir = new File(rootProject.projectDir, '../../../node_modules/react-native-linear-gradient/android') include ':react-native-get-random-values' project(':react-native-get-random-values').projectDir = new File(rootProject.projectDir, '../../../node_modules/react-native-get-random-values/android') +include ':@react-native-community_masked-view' +project(':@react-native-community_masked-view').projectDir = new File(rootProject.projectDir, '../../../node_modules/@react-native-community/masked-view/android') +include ':react-native-gesture-handler' +project(':react-native-gesture-handler').projectDir = new File(rootProject.projectDir, '../../../node_modules/react-native-gesture-handler/android') +include ':react-native-screens' +project(':react-native-screens').projectDir = new File(rootProject.projectDir, '../../../node_modules/react-native-screens/android') +include ':react-native-safe-area-context' +project(':react-native-safe-area-context').projectDir = new File(rootProject.projectDir, '../../../node_modules/react-native-safe-area-context/android') +include ':react-native-reanimated' +project(':react-native-reanimated').projectDir = new File(rootProject.projectDir, '../../../node_modules/react-native-reanimated/android') include ':app' diff --git a/packages/react-native-editor/babel.config.js b/packages/react-native-editor/babel.config.js index 0fd51ac0d1006..868045c19ca90 100644 --- a/packages/react-native-editor/babel.config.js +++ b/packages/react-native-editor/babel.config.js @@ -24,7 +24,7 @@ module.exports = function ( api ) { }, ], ], - exclude: /node_modules\/(react-native|@react-native-community)/, + exclude: /node_modules\/(react-native|@react-native-community|@react-navigation)/, }, { // Auto-add `import { createElement } from '@wordpress/element';` when JSX is found @@ -39,7 +39,7 @@ module.exports = function ( api ) { }, ], ], - exclude: /node_modules\/(react-native|@react-native-community)/, + exclude: /node_modules\/(react-native|@react-native-community|@react-navigation)/, }, ], env: { diff --git a/packages/react-native-editor/index.js b/packages/react-native-editor/index.js index 1417cc0322975..b84a0fe9760b6 100644 --- a/packages/react-native-editor/index.js +++ b/packages/react-native-editor/index.js @@ -1,3 +1,7 @@ +/** + * External dependencies + */ +import 'react-native-gesture-handler'; /** * Internal dependencies */ diff --git a/packages/react-native-editor/ios/Podfile.lock b/packages/react-native-editor/ios/Podfile.lock index 867fce1b1063e..f75fd8c978827 100644 --- a/packages/react-native-editor/ios/Podfile.lock +++ b/packages/react-native-editor/ios/Podfile.lock @@ -197,6 +197,8 @@ PODS: - React - react-native-safe-area (0.5.1): - React + - react-native-safe-area-context (3.1.1): + - React - react-native-slider (3.0.2): - React - react-native-video (5.0.2): @@ -241,6 +243,14 @@ PODS: - ReactCommon/jscallinvoker (= 0.61.5) - ReactNativeDarkMode (0.0.10): - React + - RNCMaskedView (0.1.10): + - React + - RNGestureHandler (1.6.0): + - React + - RNReanimated (1.9.0): + - React + - RNScreens (2.9.0): + - React - RNSVG (9.13.6-gb): - React - RNTAztecView (1.34.0): @@ -272,6 +282,7 @@ DEPENDENCIES: - react-native-get-random-values (from `../../../node_modules/react-native-get-random-values`) - react-native-keyboard-aware-scroll-view (from `../../../node_modules/react-native-keyboard-aware-scroll-view`) - react-native-safe-area (from `../../../node_modules/react-native-safe-area`) + - react-native-safe-area-context (from `../../../node_modules/react-native-safe-area-context`) - "react-native-slider (from `../../../node_modules/@react-native-community/slider`)" - react-native-video (from `../../../node_modules/react-native-video`) - React-RCTActionSheet (from `../../../node_modules/react-native/Libraries/ActionSheetIOS`) @@ -286,6 +297,10 @@ DEPENDENCIES: - ReactCommon/jscallinvoker (from `../../../node_modules/react-native/ReactCommon`) - ReactCommon/turbomodule/core (from `../../../node_modules/react-native/ReactCommon`) - ReactNativeDarkMode (from `../../../node_modules/react-native-dark-mode`) + - "RNCMaskedView (from `../../../node_modules/@react-native-community/masked-view`)" + - RNGestureHandler (from `../../../node_modules/react-native-gesture-handler`) + - RNReanimated (from `../../../node_modules/react-native-reanimated`) + - RNScreens (from `../../../node_modules/react-native-screens`) - RNSVG (from `../../../node_modules/react-native-svg`) - RNTAztecView (from `../../react-native-aztec/RNTAztecView.podspec`) - Yoga (from `../../../node_modules/react-native/ReactCommon/yoga`) @@ -336,6 +351,8 @@ EXTERNAL SOURCES: :path: "../../../node_modules/react-native-keyboard-aware-scroll-view" react-native-safe-area: :path: "../../../node_modules/react-native-safe-area" + react-native-safe-area-context: + :path: "../../../node_modules/react-native-safe-area-context" react-native-slider: :path: "../../../node_modules/@react-native-community/slider" react-native-video: @@ -362,6 +379,14 @@ EXTERNAL SOURCES: :path: "../../../node_modules/react-native/ReactCommon" ReactNativeDarkMode: :path: "../../../node_modules/react-native-dark-mode" + RNCMaskedView: + :path: "../../../node_modules/@react-native-community/masked-view" + RNGestureHandler: + :path: "../../../node_modules/react-native-gesture-handler" + RNReanimated: + :path: "../../../node_modules/react-native-reanimated" + RNScreens: + :path: "../../../node_modules/react-native-screens" RNSVG: :path: "../../../node_modules/react-native-svg" RNTAztecView: @@ -391,8 +416,9 @@ SPEC CHECKSUMS: react-native-get-random-values: 8940331a943a46c165d3ed05802c09c392f8dd46 react-native-keyboard-aware-scroll-view: ffa9152671fec9a571197ed2d02e0fcb90206e60 react-native-safe-area: e8230b0017d76c00de6b01e2412dcf86b127c6a3 + react-native-safe-area-context: 4c3249e4840225c61fcd215b136af0a737bccb79 react-native-slider: ecb7f25c14f2348d1c1f629a6f2be7611d22a066 - react-native-video: d01ed7ff1e38fa7dcc6c15c94cf505e661b7bfd0 + react-native-video: 961749da457e73bf0b5565edfbaffc25abfb8974 React-RCTActionSheet: 600b4d10e3aea0913b5a92256d2719c0cdd26d76 React-RCTAnimation: 791a87558389c80908ed06cc5dfc5e7920dfa360 React-RCTBlob: d89293cc0236d9cb0933d85e430b0bbe81ad1d72 @@ -404,6 +430,10 @@ SPEC CHECKSUMS: React-RCTVibration: a49a1f42bf8f5acf1c3e297097517c6b3af377ad ReactCommon: 198c7c8d3591f975e5431bec1b0b3b581aa1c5dd ReactNativeDarkMode: f61376360c5d983907e5c316e8e1c853a8c2f348 + RNCMaskedView: f5c7d14d6847b7b44853f7acb6284c1da30a3459 + RNGestureHandler: dde546180bf24af0b5f737c8ad04b6f3fa51609a + RNReanimated: b5ccb50650ba06f6e749c7c329a1bc3ae0c88b43 + RNScreens: c526239bbe0e957b988dacc8d75ac94ec9cb19da RNSVG: 68a534a5db06dcbdaebfd5079349191598caef7b RNTAztecView: b2a8bbc94328376f6cd7a238e826f5d49b20ae1a WordPress-Aztec-iOS: b7ac8b30f746992e85d9668453ac87c2cdcecf4f diff --git a/packages/react-native-editor/ios/gutenberg.xcodeproj/project.pbxproj b/packages/react-native-editor/ios/gutenberg.xcodeproj/project.pbxproj index 81a72bc9af7c8..b5cb62934183a 100644 --- a/packages/react-native-editor/ios/gutenberg.xcodeproj/project.pbxproj +++ b/packages/react-native-editor/ios/gutenberg.xcodeproj/project.pbxproj @@ -470,7 +470,11 @@ "${BUILT_PRODUCTS_DIR}/Folly/folly.framework", "${BUILT_PRODUCTS_DIR}/Gutenberg/Gutenberg.framework", "${BUILT_PRODUCTS_DIR}/RCTTypeSafety/RCTTypeSafety.framework", + "${BUILT_PRODUCTS_DIR}/RNCMaskedView/RNCMaskedView.framework", + "${BUILT_PRODUCTS_DIR}/RNGestureHandler/RNGestureHandler.framework", + "${BUILT_PRODUCTS_DIR}/RNReanimated/RNReanimated.framework", "${BUILT_PRODUCTS_DIR}/RNSVG/RNSVG.framework", + "${BUILT_PRODUCTS_DIR}/RNScreens/RNScreens.framework", "${BUILT_PRODUCTS_DIR}/RNTAztecView/RNTAztecView.framework", "${BUILT_PRODUCTS_DIR}/React-Core/React.framework", "${BUILT_PRODUCTS_DIR}/React-CoreModules/CoreModules.framework", @@ -496,6 +500,7 @@ "${BUILT_PRODUCTS_DIR}/react-native-get-random-values/react_native_get_random_values.framework", "${BUILT_PRODUCTS_DIR}/react-native-keyboard-aware-scroll-view/react_native_keyboard_aware_scroll_view.framework", "${BUILT_PRODUCTS_DIR}/react-native-safe-area/react_native_safe_area.framework", + "${BUILT_PRODUCTS_DIR}/react-native-safe-area-context/react_native_safe_area_context.framework", "${BUILT_PRODUCTS_DIR}/react-native-slider/react_native_slider.framework", ); name = "[CP] Embed Pods Frameworks"; @@ -506,7 +511,11 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/folly.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Gutenberg.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RCTTypeSafety.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RNCMaskedView.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RNGestureHandler.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RNReanimated.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RNSVG.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RNScreens.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RNTAztecView.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CoreModules.framework", @@ -532,6 +541,7 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/react_native_get_random_values.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/react_native_keyboard_aware_scroll_view.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/react_native_safe_area.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/react_native_safe_area_context.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/react_native_slider.framework", ); runOnlyForDeploymentPostprocessing = 0; diff --git a/packages/react-native-editor/package.json b/packages/react-native-editor/package.json index a659008228aa8..9bd566d7a1828 100644 --- a/packages/react-native-editor/package.json +++ b/packages/react-native-editor/package.json @@ -31,7 +31,10 @@ "dependencies": { "@babel/runtime": "^7.9.2", "@react-native-community/blur": "3.6.0", + "@react-native-community/masked-view": "git+https://github.com/wordpress-mobile/react-native-masked-view.git#098004d0968f853fc7d96c2aa5f96afe7a133c58", "@react-native-community/slider": "git+https://github.com/wordpress-mobile/react-native-slider.git#d263ff16cdd9fb7352b354342522ff030f220f42", + "@react-navigation/native": "^5.6.1", + "@react-navigation/stack": "5.6.2", "@wordpress/api-fetch": "file:../api-fetch", "@wordpress/block-editor": "file:../block-editor", "@wordpress/block-library": "file:../block-library", @@ -53,14 +56,18 @@ "node-fetch": "^2.6.0", "react-native": "0.61.5", "react-native-dark-mode": "git+https://github.com/wordpress-mobile/react-native-dark-mode.git#f09bf1480e7b34536413ab3300f29e4375edb2c6", + "react-native-gesture-handler": "git+https://github.com/wordpress-mobile/react-native-gesture-handler.git#b80e959908b383a26d6e35d992d6d529efad0b16", "react-native-get-random-values": "git+https://github.com/wordpress-mobile/react-native-get-random-values.git#f03f2c16414aff4ea76064dcd00a9e3c6efc838d", "react-native-hr": "git+https://github.com/Riglerr/react-native-hr.git#2d01a5cf77212d100e8b99e0310cce5234f977b3", "react-native-hsv-color-picker": "git+https://github.com/wordpress-mobile/react-native-hsv-color-picker", "react-native-keyboard-aware-scroll-view": "git+https://github.com/wordpress-mobile/react-native-keyboard-aware-scroll-view.git#gb-v0.8.8", "react-native-linear-gradient": "git+https://github.com/wordpress-mobile/react-native-linear-gradient.git#52bf43077171cff8714ce3e0155f3ebb7f55bc37", "react-native-modal": "^6.5.0", + "react-native-reanimated": "git+https://github.com/wordpress-mobile/react-native-reanimated.git#ed48f510fba751cd75da7629e92276166766be91", "react-native-safe-area": "^0.5.0", + "react-native-safe-area-context": "git+https://github.com/wordpress-mobile/react-native-safe-area-context.git#1e3c0d34f31b59fb79f71ec0b4c39c513f684871", "react-native-sass-transformer": "^1.1.1", + "react-native-screens": "git+https://github.com/wordpress-mobile/react-native-screens.git#835843f4c3697bba5c330d05d8fc270d50ca9d2a", "react-native-svg": "git+https://github.com/wordpress-mobile/react-native-svg.git#a628e92990a2404e30a0086f168bd2b5b7b4ce96", "react-native-url-polyfill": "^1.1.2", "react-native-video": "git+https://github.com/wordpress-mobile/react-native-video.git#1b964b107863351ed744fc104d7952bbec3e2d4f" diff --git a/test/native/__mocks__/fileMock.js b/test/native/__mocks__/fileMock.js new file mode 100644 index 0000000000000..59890f6a201a5 --- /dev/null +++ b/test/native/__mocks__/fileMock.js @@ -0,0 +1,3 @@ +// __mocks__/fileMock.js + +module.exports = 'test-file-stub'; diff --git a/test/native/jest.config.js b/test/native/jest.config.js index 18ccbb421ea7f..2443e29ef5f4e 100644 --- a/test/native/jest.config.js +++ b/test/native/jest.config.js @@ -49,6 +49,8 @@ module.exports = { moduleNameMapper: { // Mock the CSS modules. See https://facebook.github.io/jest/docs/en/webpack.html#handling-static-assets '\\.(scss)$': '/' + configPath + '/__mocks__/styleMock.js', + '\\.(jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': + '/' + configPath + '/__mocks__/fileMock.js', [ `@wordpress\\/(${ transpiledPackageNames.join( '|' ) })$` ]: '/packages/$1/src', diff --git a/test/native/setup.js b/test/native/setup.js index 3f90fe422455c..9ca6804e56454 100644 --- a/test/native/setup.js +++ b/test/native/setup.js @@ -2,6 +2,7 @@ * External dependencies */ import { NativeModules } from 'react-native'; +import 'react-native-gesture-handler/jestSetup'; jest.mock( '@wordpress/element', () => { return { @@ -122,3 +123,16 @@ Object.keys( mockNativeModules ).forEach( ( module ) => { } ); } } ); + +jest.mock( 'react-native-reanimated', () => { + const Reanimated = require( 'react-native-reanimated/mock' ); + + // The mock for `call` immediately calls the callback which is incorrect + // So we override it with a no-op + Reanimated.default.call = () => {}; + + return Reanimated; +} ); + +// Silence the warning: Animated: `useNativeDriver` is not supported because the native animated module is missing +jest.mock( 'react-native/Libraries/Animated/src/NativeAnimatedHelper' );