From 99c46e8880b30f20154d443ef823ca46f94713bb Mon Sep 17 00:00:00 2001 From: Abdelhafidh Belalia <16493223+s77rt@users.noreply.github.com> Date: Sat, 13 Jul 2024 18:26:47 +0100 Subject: [PATCH 01/18] Add onPaste to TextInput --- .../AndroidTextInputNativeComponent.js | 9 +++++ .../TextInput/RCTTextInputViewConfig.js | 4 ++ .../Components/TextInput/TextInput.d.ts | 5 +++ .../Components/TextInput/TextInput.flow.js | 5 +++ .../Components/TextInput/TextInput.js | 5 +++ .../Text/TextInput/Multiline/RCTUITextView.mm | 1 + .../TextInput/RCTBackedTextInputDelegate.h | 1 + .../RCTBackedTextInputDelegateAdapter.h | 2 + .../RCTBackedTextInputDelegateAdapter.mm | 10 +++++ .../Text/TextInput/RCTBaseTextInputView.h | 1 + .../Text/TextInput/RCTBaseTextInputView.mm | 8 ++++ .../TextInput/RCTBaseTextInputViewManager.mm | 1 + .../TextInput/Singleline/RCTUITextField.mm | 1 + .../TextInput/RCTTextInputComponentView.mm | 7 ++++ .../react/views/textinput/PasteWatcher.java | 17 +++++++++ .../react/views/textinput/ReactEditText.java | 13 ++++++- .../textinput/ReactTextInputManager.java | 31 +++++++++++++++ .../textinput/ReactTextInputPasteEvent.java | 38 +++++++++++++++++++ .../iostextinput/TextInputEventEmitter.cpp | 4 ++ .../iostextinput/TextInputEventEmitter.h | 1 + .../TextInput/TextInputSharedExamples.js | 1 + 21 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/PasteWatcher.java create mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputPasteEvent.java diff --git a/packages/react-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js b/packages/react-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js index a77e5b42f715af..fb763b44cd8a6a 100644 --- a/packages/react-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js +++ b/packages/react-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js @@ -455,6 +455,11 @@ export type NativeProps = $ReadOnly<{| |}>, >, + /** + * Callback that is called when the clipboard content is pasted. + */ + onPaste?: ?DirectEventHandler<$ReadOnly<{|target: Int32|}>>, + /** * The string that will be rendered before text input has been entered. */ @@ -658,6 +663,9 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig = { topScroll: { registrationName: 'onScroll', }, + topPaste: { + registrationName: 'onPaste', + }, }, validAttributes: { maxFontSizeMultiplier: true, @@ -712,6 +720,7 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig = { textBreakStrategy: true, onScroll: true, onContentSizeChange: true, + onPaste: true, disableFullscreenUI: true, includeFontPadding: true, fontWeight: true, diff --git a/packages/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js b/packages/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js index 0aa8965bda382d..e51b7991086c8b 100644 --- a/packages/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js +++ b/packages/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js @@ -85,6 +85,9 @@ const RCTTextInputViewConfig = { topContentSizeChange: { registrationName: 'onContentSizeChange', }, + topPaste: { + registrationName: 'onPaste', + }, }, validAttributes: { fontSize: true, @@ -150,6 +153,7 @@ const RCTTextInputViewConfig = { onSelectionChange: true, onContentSizeChange: true, onScroll: true, + onPaste: true, }), }, }; diff --git a/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts b/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts index 0aa50fe80fc277..0f7d1c8c3b9aba 100644 --- a/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts +++ b/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts @@ -801,6 +801,11 @@ export interface TextInputProps | ((e: NativeSyntheticEvent) => void) | undefined; + /** + * Callback that is called when the clipboard content is pasted. + */ + onPaste?: ((e: NativeSyntheticEvent) => void) | undefined; + /** * The string that will be rendered before text input has been entered */ diff --git a/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js b/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js index 638acd7c7925a2..2ca2cb40888063 100644 --- a/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js +++ b/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js @@ -812,6 +812,11 @@ export type Props = $ReadOnly<{| */ onScroll?: ?(e: ScrollEvent) => mixed, + /** + * Callback that is called when the clipboard content is pasted. + */ + onPaste?: ?(e: TargetEvent) => mixed, + /** * The string that will be rendered before text input has been entered. */ diff --git a/packages/react-native/Libraries/Components/TextInput/TextInput.js b/packages/react-native/Libraries/Components/TextInput/TextInput.js index 55451b9772f18c..b0efd88f1b05b0 100644 --- a/packages/react-native/Libraries/Components/TextInput/TextInput.js +++ b/packages/react-native/Libraries/Components/TextInput/TextInput.js @@ -811,6 +811,11 @@ export type Props = $ReadOnly<{| */ onScroll?: ?(e: ScrollEvent) => mixed, + /** + * Callback that is called when the clipboard content is pasted. + */ + onPaste?: ?(e: TargetEvent) => mixed, + /** * The string that will be rendered before text input has been entered. */ diff --git a/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm b/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm index d5e2e220b1e290..21947f05915788 100644 --- a/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm +++ b/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm @@ -173,6 +173,7 @@ - (void)paste:(id)sender { _textWasPasted = YES; [super paste:sender]; + [_textInputDelegateAdapter didPaste]; } // Turn off scroll animation to fix flaky scrolling. diff --git a/packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegate.h b/packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegate.h index 7187177b69d400..aaa6a17960b3aa 100644 --- a/packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegate.h +++ b/packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegate.h @@ -36,6 +36,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)textInputDidChange; - (void)textInputDidChangeSelection; +- (void)textInputDidPaste; @optional diff --git a/packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.h b/packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.h index f1c32e6e33bb05..2b91f03b3d1196 100644 --- a/packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.h +++ b/packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.h @@ -20,6 +20,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)skipNextTextInputDidChangeSelectionEventWithTextRange:(UITextRange *)textRange; - (void)selectedTextRangeWasSet; +- (void)didPaste; @end @@ -30,6 +31,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithTextView:(UITextView *)backedTextInputView; - (void)skipNextTextInputDidChangeSelectionEventWithTextRange:(UITextRange *)textRange; +- (void)didPaste; @end diff --git a/packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.mm b/packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.mm index ac8e464fc2dce8..71fe54984caf32 100644 --- a/packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.mm +++ b/packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.mm @@ -147,6 +147,11 @@ - (void)selectedTextRangeWasSet [self textFieldProbablyDidChangeSelection]; } +- (void)didPaste +{ + [_backedTextInputView.textInputDelegate textInputDidPaste]; +} + #pragma mark - Generalization - (void)textFieldProbablyDidChangeSelection @@ -292,6 +297,11 @@ - (void)skipNextTextInputDidChangeSelectionEventWithTextRange:(UITextRange *)tex _previousSelectedTextRange = textRange; } +- (void)didPaste +{ + [_backedTextInputView.textInputDelegate textInputDidPaste]; +} + #pragma mark - Generalization - (void)textViewProbablyDidChangeSelection diff --git a/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.h b/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.h index 9a02b8224960f6..06442b4d03b847 100644 --- a/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.h +++ b/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.h @@ -37,6 +37,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, copy, nullable) RCTDirectEventBlock onChange; @property (nonatomic, copy, nullable) RCTDirectEventBlock onChangeSync; @property (nonatomic, copy, nullable) RCTDirectEventBlock onScroll; +@property (nonatomic, copy, nullable) RCTDirectEventBlock onPaste; @property (nonatomic, assign) NSInteger mostRecentEventCount; @property (nonatomic, assign, readonly) NSInteger nativeEventCount; diff --git a/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.mm b/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.mm index 72cf885c37e824..e599b09a40823e 100644 --- a/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.mm +++ b/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.mm @@ -543,6 +543,14 @@ - (void)textInputDidChangeSelection }); } +- (void)textInputDidPaste +{ + if (!_onPaste) { + return; + } + _onPaste(@{@"target" : self.reactTag}); +} + - (void)updateLocalData { [self enforceTextAttributesIfNeeded]; diff --git a/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputViewManager.mm b/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputViewManager.mm index 20749a602881bf..9782162f56bafd 100644 --- a/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputViewManager.mm +++ b/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputViewManager.mm @@ -65,6 +65,7 @@ @implementation RCTBaseTextInputViewManager { RCT_EXPORT_VIEW_PROPERTY(onChangeSync, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(onSelectionChange, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(onScroll, RCTDirectEventBlock) +RCT_EXPORT_VIEW_PROPERTY(onPaste, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(mostRecentEventCount, NSInteger) diff --git a/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm b/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm index 03186710893e36..01301e2266c916 100644 --- a/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm +++ b/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm @@ -223,6 +223,7 @@ - (void)paste:(id)sender { _textWasPasted = YES; [super paste:sender]; + [_textInputDelegateAdapter didPaste]; } #pragma mark - Layout diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm index 8e7cc58c43a12b..5ec85c1233a101 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm @@ -404,6 +404,13 @@ - (void)textInputDidChangeSelection } } +- (void)textInputDidPaste +{ + if (_eventEmitter) { + static_cast(*_eventEmitter).onPaste(); + } +} + #pragma mark - RCTBackedTextInputDelegate (UIScrollViewDelegate) - (void)scrollViewDidScroll:(UIScrollView *)scrollView diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/PasteWatcher.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/PasteWatcher.java new file mode 100644 index 00000000000000..7eacc511ef52f5 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/PasteWatcher.java @@ -0,0 +1,17 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react.views.textinput; + +/** + * Implement this interface to be informed of paste event in the + * ReactTextEdit This is used by the ReactTextInputManager to forward events + * from the EditText to JS + */ +interface PasteWatcher { + public void onPaste(); +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java index c96859ccb2c57a..dd11c041267eff 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java @@ -109,6 +109,7 @@ public class ReactEditText extends AppCompatEditText { private @Nullable SelectionWatcher mSelectionWatcher; private @Nullable ContentSizeWatcher mContentSizeWatcher; private @Nullable ScrollWatcher mScrollWatcher; + private @Nullable PasteWatcher mPasteWatcher; private InternalKeyListener mKeyListener; private boolean mDetectScrollMovement = false; private boolean mOnKeyPress = false; @@ -154,6 +155,7 @@ public ReactEditText(Context context) { mKeyListener = new InternalKeyListener(); } mScrollWatcher = null; + mPasteWatcher = null; mTextAttributes = new TextAttributes(); applyTextAttributes(); @@ -321,8 +323,13 @@ public InputConnection onCreateInputConnection(EditorInfo outAttrs) { */ @Override public boolean onTextContextMenuItem(int id) { - if (id == android.R.id.paste) { + if (id == android.R.id.paste || id == android.R.id.pasteAsPlainText) { id = android.R.id.pasteAsPlainText; + boolean actionPerformed = super.onTextContextMenuItem(id); + if (mPasteWatcher != null) { + mPasteWatcher.onPaste(); + } + return actionPerformed; } return super.onTextContextMenuItem(id); } @@ -384,6 +391,10 @@ public void setScrollWatcher(@Nullable ScrollWatcher scrollWatcher) { mScrollWatcher = scrollWatcher; } + public void setPasteWatcher(@Nullable PasteWatcher pasteWatcher) { + mPasteWatcher = pasteWatcher; + } + /** * Attempt to set a selection or fail silently. Intentionally meant to handle bad inputs. * EventCounter is the same one used as with text. diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java index 7e0c3fccf16946..5c6828333efb08 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java @@ -260,6 +260,9 @@ public Map getExportedCustomDirectEventTypeConstants() { .put( ScrollEventType.getJSEventName(ScrollEventType.SCROLL), MapBuilder.of("registrationName", "onScroll")) + .put( + "topPaste", + MapBuilder.of("registrationName", "onPaste")) .build()); return eventTypeConstants; } @@ -476,6 +479,15 @@ public void setOnScroll(final ReactEditText view, boolean onScroll) { } } + @ReactProp(name = "onPaste", defaultBoolean = false) + public void setOnPaste(final ReactEditText view, boolean onPaste) { + if (onPaste) { + view.setPasteWatcher(new ReactPasteWatcher(view)); + } else { + view.setPasteWatcher(null); + } + } + @ReactProp(name = "onKeyPress", defaultBoolean = false) public void setOnKeyPress(final ReactEditText view, boolean onKeyPress) { view.setOnKeyPress(onKeyPress); @@ -1307,6 +1319,25 @@ public void onScrollChanged(int horiz, int vert, int oldHoriz, int oldVert) { } } + private static class ReactPasteWatcher implements PasteWatcher { + private final ReactEditText mReactEditText; + private final EventDispatcher mEventDispatcher; + private final int mSurfaceId; + + public ReactPasteWatcher(ReactEditText editText) { + mReactEditText = editText; + ReactContext reactContext = getReactContext(editText); + mEventDispatcher = getEventDispatcher(reactContext, editText); + mSurfaceId = UIManagerHelper.getSurfaceId(reactContext); + } + + @Override + public void onPaste() { + mEventDispatcher.dispatchEvent( + new ReactTextInputPasteEvent(mSurfaceId, mReactEditText.getId())); + } + } + @Override public @Nullable Map getExportedViewConstants() { return MapBuilder.of( diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputPasteEvent.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputPasteEvent.java new file mode 100644 index 00000000000000..058206aaab9bdb --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputPasteEvent.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react.views.textinput; + +import com.facebook.react.uimanager.common.ViewUtil; +import com.facebook.react.uimanager.events.Event; + +/** + * Event emitted by EditText native view when clipboard content is pasted + */ +class ReactTextInputPasteEvent extends Event { + + private static final String EVENT_NAME = "topPaste"; + + @Deprecated + public ReactTextInputPasteEvent(int viewId) { + this(ViewUtil.NO_SURFACE_ID, viewId); + } + + public ReactTextInputPasteEvent(int surfaceId, int viewId) { + super(surfaceId, viewId); + } + + @Override + public String getEventName() { + return EVENT_NAME; + } + + @Override + public boolean canCoalesce() { + return false; + } +} diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputEventEmitter.cpp b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputEventEmitter.cpp index 6eb58c1681af72..9f6d8c07794b09 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputEventEmitter.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputEventEmitter.cpp @@ -172,6 +172,10 @@ void TextInputEventEmitter::onScroll(const Metrics& textInputMetrics) const { }); } +void TextInputEventEmitter::onPaste() const { + dispatchEvent("onPaste"); +} + void TextInputEventEmitter::dispatchTextInputEvent( const std::string& name, const Metrics& textInputMetrics) const { diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputEventEmitter.h b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputEventEmitter.h index 9182dd3d2edccb..c6ef1f421c5d57 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputEventEmitter.h +++ b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputEventEmitter.h @@ -43,6 +43,7 @@ class TextInputEventEmitter : public ViewEventEmitter { void onSubmitEditing(const Metrics& textInputMetrics) const; void onKeyPress(const KeyPressMetrics& keyPressMetrics) const; void onScroll(const Metrics& textInputMetrics) const; + void onPaste() const; private: void dispatchTextInputEvent( diff --git a/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js b/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js index 9ed0fb7f161eb4..4f6e072b69e703 100644 --- a/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js +++ b/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js @@ -415,6 +415,7 @@ class TextEventsExample extends React.Component<{...}, $FlowFixMeState> { onKeyPress={event => this.updateText('onKeyPress key: ' + event.nativeEvent.key) } + onPaste={() => this.updateText('onPaste')} style={styles.singleLine} /> From 61cc3c76ad114d4a4b9794b41b54c2b218fe046e Mon Sep 17 00:00:00 2001 From: Abdelhafidh Belalia <16493223+s77rt@users.noreply.github.com> Date: Mon, 15 Jul 2024 10:57:33 +0100 Subject: [PATCH 02/18] Update snapshot --- .../Libraries/__tests__/__snapshots__/public-api-test.js.snap | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap index 9f1ca1d4acf8ca..d5e927fb74365d 100644 --- a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap +++ b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap @@ -2324,6 +2324,7 @@ export type NativeProps = $ReadOnly<{| |}>, |}>, >, + onPaste?: ?DirectEventHandler<$ReadOnly<{| target: Int32 |}>>, placeholder?: ?Stringish, placeholderTextColor?: ?ColorValue, secureTextEntry?: ?boolean, @@ -2711,6 +2712,7 @@ export type Props = $ReadOnly<{| onSelectionChange?: ?(e: SelectionChangeEvent) => mixed, onSubmitEditing?: ?(e: EditingEvent) => mixed, onScroll?: ?(e: ScrollEvent) => mixed, + onPaste?: ?(e: TargetEvent) => mixed, placeholder?: ?Stringish, placeholderTextColor?: ?ColorValue, readOnly?: ?boolean, @@ -3050,6 +3052,7 @@ export type Props = $ReadOnly<{| onSelectionChange?: ?(e: SelectionChangeEvent) => mixed, onSubmitEditing?: ?(e: EditingEvent) => mixed, onScroll?: ?(e: ScrollEvent) => mixed, + onPaste?: ?(e: TargetEvent) => mixed, placeholder?: ?Stringish, placeholderTextColor?: ?ColorValue, readOnly?: ?boolean, From 9b4aaf5288889358fa3d1f7192121e4d4fe356b6 Mon Sep 17 00:00:00 2001 From: Abdelhafidh Belalia <16493223+s77rt@users.noreply.github.com> Date: Thu, 18 Jul 2024 01:41:36 +0100 Subject: [PATCH 03/18] return valid getEventData --- .../views/textinput/ReactTextInputPasteEvent.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputPasteEvent.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputPasteEvent.java index 058206aaab9bdb..8ce2cecf3f0bf6 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputPasteEvent.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputPasteEvent.java @@ -7,6 +7,9 @@ package com.facebook.react.views.textinput; +import androidx.annotation.Nullable; +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.WritableMap; import com.facebook.react.uimanager.common.ViewUtil; import com.facebook.react.uimanager.events.Event; @@ -35,4 +38,11 @@ public String getEventName() { public boolean canCoalesce() { return false; } + + @Nullable + @Override + protected WritableMap getEventData() { + WritableMap eventData = Arguments.createMap(); + return eventData; + } } From 8f504d1a4f4fa9f3e6374b1496fd33e2eaede56e Mon Sep 17 00:00:00 2001 From: Abdelhafidh Belalia <16493223+s77rt@users.noreply.github.com> Date: Sun, 21 Jul 2024 15:41:19 +0100 Subject: [PATCH 04/18] Call onPaste before pasting the text --- .../Libraries/Text/TextInput/Multiline/RCTUITextView.mm | 2 +- .../Libraries/Text/TextInput/Singleline/RCTUITextField.mm | 2 +- .../java/com/facebook/react/views/textinput/ReactEditText.java | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm b/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm index 21947f05915788..979019093831de 100644 --- a/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm +++ b/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm @@ -172,8 +172,8 @@ - (void)scrollRangeToVisible:(NSRange)range - (void)paste:(id)sender { _textWasPasted = YES; - [super paste:sender]; [_textInputDelegateAdapter didPaste]; + [super paste:sender]; } // Turn off scroll animation to fix flaky scrolling. diff --git a/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm b/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm index 01301e2266c916..ea458b45fc34ac 100644 --- a/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm +++ b/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm @@ -222,8 +222,8 @@ - (void)scrollRangeToVisible:(NSRange)range - (void)paste:(id)sender { _textWasPasted = YES; - [super paste:sender]; [_textInputDelegateAdapter didPaste]; + [super paste:sender]; } #pragma mark - Layout diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java index dd11c041267eff..6457f5ed986c46 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java @@ -325,11 +325,9 @@ public InputConnection onCreateInputConnection(EditorInfo outAttrs) { public boolean onTextContextMenuItem(int id) { if (id == android.R.id.paste || id == android.R.id.pasteAsPlainText) { id = android.R.id.pasteAsPlainText; - boolean actionPerformed = super.onTextContextMenuItem(id); if (mPasteWatcher != null) { mPasteWatcher.onPaste(); } - return actionPerformed; } return super.onTextContextMenuItem(id); } From 27743c6c4ce6650941b3292b34a329743b66d9e6 Mon Sep 17 00:00:00 2001 From: Abdelhafidh Belalia <16493223+s77rt@users.noreply.github.com> Date: Sun, 21 Jul 2024 15:52:21 +0100 Subject: [PATCH 05/18] Better onPaste comment --- .../Components/TextInput/AndroidTextInputNativeComponent.js | 2 +- .../react-native/Libraries/Components/TextInput/TextInput.d.ts | 2 +- .../Libraries/Components/TextInput/TextInput.flow.js | 2 +- .../react-native/Libraries/Components/TextInput/TextInput.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/react-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js b/packages/react-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js index fb763b44cd8a6a..6ce537e51e7ae7 100644 --- a/packages/react-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js +++ b/packages/react-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js @@ -456,7 +456,7 @@ export type NativeProps = $ReadOnly<{| >, /** - * Callback that is called when the clipboard content is pasted. + * Invoked when the user performs the paste action. */ onPaste?: ?DirectEventHandler<$ReadOnly<{|target: Int32|}>>, diff --git a/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts b/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts index 0f7d1c8c3b9aba..68d3a9f4b4978a 100644 --- a/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts +++ b/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts @@ -802,7 +802,7 @@ export interface TextInputProps | undefined; /** - * Callback that is called when the clipboard content is pasted. + * Invoked when the user performs the paste action. */ onPaste?: ((e: NativeSyntheticEvent) => void) | undefined; diff --git a/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js b/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js index 2ca2cb40888063..e81be957f30909 100644 --- a/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js +++ b/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js @@ -813,7 +813,7 @@ export type Props = $ReadOnly<{| onScroll?: ?(e: ScrollEvent) => mixed, /** - * Callback that is called when the clipboard content is pasted. + * Invoked when the user performs the paste action. */ onPaste?: ?(e: TargetEvent) => mixed, diff --git a/packages/react-native/Libraries/Components/TextInput/TextInput.js b/packages/react-native/Libraries/Components/TextInput/TextInput.js index b0efd88f1b05b0..4ba67a7a9a5681 100644 --- a/packages/react-native/Libraries/Components/TextInput/TextInput.js +++ b/packages/react-native/Libraries/Components/TextInput/TextInput.js @@ -812,7 +812,7 @@ export type Props = $ReadOnly<{| onScroll?: ?(e: ScrollEvent) => mixed, /** - * Callback that is called when the clipboard content is pasted. + * Invoked when the user performs the paste action. */ onPaste?: ?(e: TargetEvent) => mixed, From af06d9ed1da0988654b8ba483024c203a5b7feb0 Mon Sep 17 00:00:00 2001 From: Abdelhafidh Belalia <16493223+s77rt@users.noreply.github.com> Date: Wed, 24 Jul 2024 03:24:46 +0100 Subject: [PATCH 06/18] Android: Pass clipboard data to onPaste event --- .../react/views/textinput/PasteWatcher.java | 2 +- .../react/views/textinput/ReactEditText.java | 34 ++++++++++++++++- .../textinput/ReactTextInputManager.java | 4 +- .../textinput/ReactTextInputPasteEvent.java | 21 +++++++++-- .../TextInput/TextInputSharedExamples.js | 37 ++++++++++++++++++- 5 files changed, 90 insertions(+), 8 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/PasteWatcher.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/PasteWatcher.java index 7eacc511ef52f5..bfb5819f45a3db 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/PasteWatcher.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/PasteWatcher.java @@ -13,5 +13,5 @@ * from the EditText to JS */ interface PasteWatcher { - public void onPaste(); + public void onPaste(String type, String data); } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java index 6457f5ed986c46..184652bc22e5df 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java @@ -9,6 +9,10 @@ import static com.facebook.react.uimanager.UIManagerHelper.getReactContext; +import android.content.ClipboardManager; +import android.content.ClipData; +import android.content.ClipDescription; +import android.content.ContentResolver; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; @@ -16,6 +20,7 @@ import android.graphics.Rect; import android.graphics.Typeface; import android.graphics.drawable.Drawable; +import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.text.Editable; @@ -27,6 +32,7 @@ import android.text.TextWatcher; import android.text.method.KeyListener; import android.text.method.QwertyKeyListener; +import android.util.Base64; import android.util.TypedValue; import android.view.ActionMode; import android.view.Gravity; @@ -68,6 +74,7 @@ import com.facebook.react.views.text.internal.span.ReactUnderlineSpan; import com.facebook.react.views.text.internal.span.TextInlineImageSpan; import com.facebook.react.views.view.ReactViewBackgroundManager; +import java.io.IOException; import java.util.ArrayList; import java.util.Objects; @@ -326,7 +333,32 @@ public boolean onTextContextMenuItem(int id) { if (id == android.R.id.paste || id == android.R.id.pasteAsPlainText) { id = android.R.id.pasteAsPlainText; if (mPasteWatcher != null) { - mPasteWatcher.onPaste(); + ClipboardManager clipboardManager = + (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE); + ClipData clipData = clipboardManager.getPrimaryClip(); + String type = null; + String data = null; + if (clipData.getDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) { + type = ClipDescription.MIMETYPE_TEXT_PLAIN; + data = clipData.getItemAt(0).getText().toString(); + } else { + Uri itemUri = clipData.getItemAt(0).getUri(); + if (itemUri != null) { + ContentResolver cr = getReactContext(this).getContentResolver(); + type = cr.getType(itemUri); + if (type != null) { + try { + String encodedData = Base64.encodeToString(cr.openInputStream(itemUri).readAllBytes(), Base64.DEFAULT); + data = "data:" + type + ";base64," + encodedData; + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + if (type != null && data != null) { + mPasteWatcher.onPaste(type, data); + } } } return super.onTextContextMenuItem(id); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java index 5c6828333efb08..f7009e83297f58 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java @@ -1332,9 +1332,9 @@ public ReactPasteWatcher(ReactEditText editText) { } @Override - public void onPaste() { + public void onPaste(String type, String data) { mEventDispatcher.dispatchEvent( - new ReactTextInputPasteEvent(mSurfaceId, mReactEditText.getId())); + new ReactTextInputPasteEvent(mSurfaceId, mReactEditText.getId(), type, data)); } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputPasteEvent.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputPasteEvent.java index 8ce2cecf3f0bf6..3697b56d155610 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputPasteEvent.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputPasteEvent.java @@ -10,6 +10,7 @@ import androidx.annotation.Nullable; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.WritableMap; +import com.facebook.react.bridge.WritableArray; import com.facebook.react.uimanager.common.ViewUtil; import com.facebook.react.uimanager.events.Event; @@ -20,13 +21,18 @@ class ReactTextInputPasteEvent extends Event { private static final String EVENT_NAME = "topPaste"; + private String mType; + private String mData; + @Deprecated - public ReactTextInputPasteEvent(int viewId) { - this(ViewUtil.NO_SURFACE_ID, viewId); + public ReactTextInputPasteEvent(int viewId, String type, String data) { + this(ViewUtil.NO_SURFACE_ID, viewId, type, data); } - public ReactTextInputPasteEvent(int surfaceId, int viewId) { + public ReactTextInputPasteEvent(int surfaceId, int viewId, String type, String data) { super(surfaceId, viewId); + mType = type; + mData = data; } @Override @@ -43,6 +49,15 @@ public boolean canCoalesce() { @Override protected WritableMap getEventData() { WritableMap eventData = Arguments.createMap(); + + WritableArray items = Arguments.createArray(); + WritableMap primaryClip = Arguments.createMap(); + primaryClip.putString("type", mType); + primaryClip.putString("data", mData); + items.pushMap(primaryClip); + + eventData.putArray("items", items); + return eventData; } } diff --git a/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js b/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js index 4f6e072b69e703..2658e5cdfae1d0 100644 --- a/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js +++ b/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js @@ -20,6 +20,7 @@ import * as React from 'react'; import {useContext, useState} from 'react'; import { Button, + Image, Platform, StyleSheet, Text, @@ -415,7 +416,9 @@ class TextEventsExample extends React.Component<{...}, $FlowFixMeState> { onKeyPress={event => this.updateText('onKeyPress key: ' + event.nativeEvent.key) } - onPaste={() => this.updateText('onPaste')} + onPaste={event => + this.updateText('onPaste type: ' + event.nativeEvent.items[0].type) + } style={styles.singleLine} /> @@ -847,6 +850,32 @@ function MultilineStyledTextInput({ ); } +function PasteboardTextInput() { + const [pasteboard, setPasteboard] = useState(null); + const {type, data} = pasteboard?.items[0] ?? {}; + const isText = type === "text/plain" + const isImage = type && type.startsWith("image/"); + + return ( + + setPasteboard(event.nativeEvent)} + placeholder="Paste text or image" + multiline={true}> + + {type && ( + {"Type: " + type} + )} + {isText && ( + {"Data: " + data} + )} + {isImage && ( + + )} + + ); +} + module.exports = ([ { title: 'Auto-focus & select text on focus', @@ -1150,4 +1179,10 @@ module.exports = ([ ); }, }, + { + title: 'Pasteboard', + render: function (): React.Element { + return ; + }, + }, ]: Array); From d0b72edc14d95ab233ac172e7d13f7744d8eeaee Mon Sep 17 00:00:00 2001 From: Abdelhafidh Belalia <16493223+s77rt@users.noreply.github.com> Date: Wed, 24 Jul 2024 03:38:38 +0100 Subject: [PATCH 07/18] RN-Tester: PasteboardTextInput fix image size --- .../rn-tester/js/examples/TextInput/TextInputSharedExamples.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js b/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js index 2658e5cdfae1d0..b4ba633070e436 100644 --- a/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js +++ b/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js @@ -870,7 +870,7 @@ function PasteboardTextInput() { {"Data: " + data} )} {isImage && ( - + )} ); From 4a6bed541faee58ecc11d699ce86dec5ffb88f35 Mon Sep 17 00:00:00 2001 From: Abdelhafidh Belalia <16493223+s77rt@users.noreply.github.com> Date: Wed, 24 Jul 2024 04:14:20 +0100 Subject: [PATCH 08/18] rename variable --- .../react/views/textinput/ReactTextInputPasteEvent.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputPasteEvent.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputPasteEvent.java index 3697b56d155610..78b14b7fbf4179 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputPasteEvent.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputPasteEvent.java @@ -51,10 +51,10 @@ protected WritableMap getEventData() { WritableMap eventData = Arguments.createMap(); WritableArray items = Arguments.createArray(); - WritableMap primaryClip = Arguments.createMap(); - primaryClip.putString("type", mType); - primaryClip.putString("data", mData); - items.pushMap(primaryClip); + WritableMap item = Arguments.createMap(); + item.putString("type", mType); + item.putString("data", mData); + items.pushMap(item); eventData.putArray("items", items); From 5baad1a94a55efed5c66016c8ce8a20c3c5283ef Mon Sep 17 00:00:00 2001 From: Abdelhafidh Belalia <16493223+s77rt@users.noreply.github.com> Date: Wed, 24 Jul 2024 13:41:58 +0100 Subject: [PATCH 09/18] Update Podfile.lock --- packages/rn-tester/Podfile.lock | 435 +++++++++++++++++++++++--------- 1 file changed, 321 insertions(+), 114 deletions(-) diff --git a/packages/rn-tester/Podfile.lock b/packages/rn-tester/Podfile.lock index 07b5b5b40b7d4e..c0653f0516f60a 100644 --- a/packages/rn-tester/Podfile.lock +++ b/packages/rn-tester/Podfile.lock @@ -15,7 +15,7 @@ PODS: - hermes-engine/inspector (1000.0.0) - hermes-engine/inspector_chrome (1000.0.0) - hermes-engine/Public (1000.0.0) - - MyNativeView (0.75.0-main): + - MyNativeView (0.76.0-main): - DoubleConversion - glog - hermes-engine @@ -36,7 +36,7 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga - - NativeCxxModuleExample (0.75.0-main): + - NativeCxxModuleExample (0.76.0-main): - DoubleConversion - glog - hermes-engine @@ -58,6 +58,27 @@ PODS: - ReactCommon/turbomodule/core - Yoga - OCMock (3.9.1) + - OSSLibraryExample (0.76.0-main): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.01.01.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - RCT-Folly (2024.01.01.00): - boost - DoubleConversion @@ -378,6 +399,31 @@ PODS: - React-perflogger (= 1000.0.0) - React-runtimeexecutor (= 1000.0.0) - React-debug (1000.0.0) + - React-defaultsnativemodule (1000.0.0): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.01.01.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-domnativemodule + - React-Fabric + - React-featureflags + - React-featureflagsnativemodule + - React-graphics + - React-idlecallbacksnativemodule + - React-ImageManager + - React-microtasksnativemodule + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - React-domnativemodule (1000.0.0): - DoubleConversion - glog @@ -388,9 +434,7 @@ PODS: - React-Core - React-debug - React-Fabric - - React-Fabric/components/root - - React-Fabric/dom - - React-Fabric/uimanager + - React-FabricComponents - React-featureflags - React-graphics - React-ImageManager @@ -423,10 +467,10 @@ PODS: - React-Fabric/imagemanager (= 1000.0.0) - React-Fabric/leakchecker (= 1000.0.0) - React-Fabric/mounting (= 1000.0.0) + - React-Fabric/observers (= 1000.0.0) - React-Fabric/scheduler (= 1000.0.0) - React-Fabric/telemetry (= 1000.0.0) - React-Fabric/templateprocessor (= 1000.0.0) - - React-Fabric/textlayoutmanager (= 1000.0.0) - React-Fabric/uimanager (= 1000.0.0) - React-featureflags - React-graphics @@ -528,17 +572,8 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-Fabric/components/inputaccessory (= 1000.0.0) - - React-Fabric/components/iostextinput (= 1000.0.0) - React-Fabric/components/legacyviewmanagerinterop (= 1000.0.0) - - React-Fabric/components/modal (= 1000.0.0) - - React-Fabric/components/rncore (= 1000.0.0) - React-Fabric/components/root (= 1000.0.0) - - React-Fabric/components/safeareaview (= 1000.0.0) - - React-Fabric/components/scrollview (= 1000.0.0) - - React-Fabric/components/text (= 1000.0.0) - - React-Fabric/components/textinput (= 1000.0.0) - - React-Fabric/components/unimplementedview (= 1000.0.0) - React-Fabric/components/view (= 1000.0.0) - React-featureflags - React-graphics @@ -549,7 +584,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/inputaccessory (1000.0.0): + - React-Fabric/components/legacyviewmanagerinterop (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -569,7 +604,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/iostextinput (1000.0.0): + - React-Fabric/components/root (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -589,7 +624,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/legacyviewmanagerinterop (1000.0.0): + - React-Fabric/components/view (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -609,7 +644,8 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/modal (1000.0.0): + - Yoga + - React-Fabric/core (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -629,7 +665,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/rncore (1000.0.0): + - React-Fabric/dom (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -649,7 +685,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/root (1000.0.0): + - React-Fabric/imagemanager (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -669,7 +705,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/safeareaview (1000.0.0): + - React-Fabric/leakchecker (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -689,7 +725,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/scrollview (1000.0.0): + - React-Fabric/mounting (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -709,7 +745,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/text (1000.0.0): + - React-Fabric/observers (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -720,6 +756,7 @@ PODS: - React-Core - React-cxxreact - React-debug + - React-Fabric/observers/events (= 1000.0.0) - React-featureflags - React-graphics - React-jsi @@ -729,7 +766,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/textinput (1000.0.0): + - React-Fabric/observers/events (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -749,7 +786,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/unimplementedview (1000.0.0): + - React-Fabric/scheduler (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -760,16 +797,58 @@ PODS: - React-Core - React-cxxreact - React-debug + - React-Fabric/observers/events - React-featureflags - React-graphics - React-jsi - React-jsiexecutor - React-logger + - React-performancetimeline - React-rendererdebug - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/view (1000.0.0): + - React-Fabric/telemetry (1000.0.0): + - DoubleConversion + - fmt (= 9.1.0) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.01.01.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/templateprocessor (1000.0.0): + - DoubleConversion + - fmt (= 9.1.0) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.01.01.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/uimanager (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -780,17 +859,64 @@ PODS: - React-Core - React-cxxreact - React-debug + - React-Fabric/uimanager/consistency (= 1000.0.0) - React-featureflags - React-graphics - React-jsi - React-jsiexecutor - React-logger + - React-rendererconsistency - React-rendererdebug - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core + - React-Fabric/uimanager/consistency (1000.0.0): + - DoubleConversion + - fmt (= 9.1.0) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.01.01.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererconsistency + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-FabricComponents (1000.0.0): + - DoubleConversion + - fmt (= 9.1.0) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2024.01.01.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric + - React-FabricComponents/components (= 1000.0.0) + - React-FabricComponents/textlayoutmanager (= 1000.0.0) + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/core - Yoga - - React-Fabric/core (1000.0.0): + - React-FabricComponents/components (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -801,6 +927,16 @@ PODS: - React-Core - React-cxxreact - React-debug + - React-Fabric + - React-FabricComponents/components/inputaccessory (= 1000.0.0) + - React-FabricComponents/components/iostextinput (= 1000.0.0) + - React-FabricComponents/components/modal (= 1000.0.0) + - React-FabricComponents/components/rncore (= 1000.0.0) + - React-FabricComponents/components/safeareaview (= 1000.0.0) + - React-FabricComponents/components/scrollview (= 1000.0.0) + - React-FabricComponents/components/text (= 1000.0.0) + - React-FabricComponents/components/textinput (= 1000.0.0) + - React-FabricComponents/components/unimplementedview (= 1000.0.0) - React-featureflags - React-graphics - React-jsi @@ -809,8 +945,10 @@ PODS: - React-rendererdebug - React-runtimescheduler - React-utils + - ReactCodegen - ReactCommon/turbomodule/core - - React-Fabric/dom (1000.0.0): + - Yoga + - React-FabricComponents/components/inputaccessory (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -821,9 +959,7 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-Fabric/components/root - - React-Fabric/components/text - - React-Fabric/core + - React-Fabric - React-featureflags - React-graphics - React-jsi @@ -832,8 +968,10 @@ PODS: - React-rendererdebug - React-runtimescheduler - React-utils + - ReactCodegen - ReactCommon/turbomodule/core - - React-Fabric/imagemanager (1000.0.0): + - Yoga + - React-FabricComponents/components/iostextinput (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -844,6 +982,7 @@ PODS: - React-Core - React-cxxreact - React-debug + - React-Fabric - React-featureflags - React-graphics - React-jsi @@ -852,8 +991,10 @@ PODS: - React-rendererdebug - React-runtimescheduler - React-utils + - ReactCodegen - ReactCommon/turbomodule/core - - React-Fabric/leakchecker (1000.0.0): + - Yoga + - React-FabricComponents/components/modal (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -864,6 +1005,7 @@ PODS: - React-Core - React-cxxreact - React-debug + - React-Fabric - React-featureflags - React-graphics - React-jsi @@ -872,8 +1014,10 @@ PODS: - React-rendererdebug - React-runtimescheduler - React-utils + - ReactCodegen - ReactCommon/turbomodule/core - - React-Fabric/mounting (1000.0.0): + - Yoga + - React-FabricComponents/components/rncore (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -884,6 +1028,7 @@ PODS: - React-Core - React-cxxreact - React-debug + - React-Fabric - React-featureflags - React-graphics - React-jsi @@ -892,8 +1037,10 @@ PODS: - React-rendererdebug - React-runtimescheduler - React-utils + - ReactCodegen - ReactCommon/turbomodule/core - - React-Fabric/scheduler (1000.0.0): + - Yoga + - React-FabricComponents/components/safeareaview (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -904,6 +1051,7 @@ PODS: - React-Core - React-cxxreact - React-debug + - React-Fabric - React-featureflags - React-graphics - React-jsi @@ -912,8 +1060,10 @@ PODS: - React-rendererdebug - React-runtimescheduler - React-utils + - ReactCodegen - ReactCommon/turbomodule/core - - React-Fabric/telemetry (1000.0.0): + - Yoga + - React-FabricComponents/components/scrollview (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -924,6 +1074,7 @@ PODS: - React-Core - React-cxxreact - React-debug + - React-Fabric - React-featureflags - React-graphics - React-jsi @@ -932,8 +1083,10 @@ PODS: - React-rendererdebug - React-runtimescheduler - React-utils + - ReactCodegen - ReactCommon/turbomodule/core - - React-Fabric/templateprocessor (1000.0.0): + - Yoga + - React-FabricComponents/components/text (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -944,6 +1097,7 @@ PODS: - React-Core - React-cxxreact - React-debug + - React-Fabric - React-featureflags - React-graphics - React-jsi @@ -952,8 +1106,10 @@ PODS: - React-rendererdebug - React-runtimescheduler - React-utils + - ReactCodegen - ReactCommon/turbomodule/core - - React-Fabric/textlayoutmanager (1000.0.0): + - Yoga + - React-FabricComponents/components/textinput (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -964,7 +1120,7 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-Fabric/uimanager + - React-Fabric - React-featureflags - React-graphics - React-jsi @@ -973,8 +1129,10 @@ PODS: - React-rendererdebug - React-runtimescheduler - React-utils + - ReactCodegen - ReactCommon/turbomodule/core - - React-Fabric/uimanager (1000.0.0): + - Yoga + - React-FabricComponents/components/unimplementedview (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -985,19 +1143,19 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-Fabric/dom - - React-Fabric/uimanager/consistency (= 1000.0.0) + - React-Fabric - React-featureflags - React-graphics - React-jsi - React-jsiexecutor - React-logger - - React-rendererconsistency - React-rendererdebug - React-runtimescheduler - React-utils + - ReactCodegen - ReactCommon/turbomodule/core - - React-Fabric/uimanager/consistency (1000.0.0): + - Yoga + - React-FabricComponents/textlayoutmanager (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -1008,17 +1166,18 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-Fabric/dom + - React-Fabric - React-featureflags - React-graphics - React-jsi - React-jsiexecutor - React-logger - - React-rendererconsistency - React-rendererdebug - React-runtimescheduler - React-utils + - ReactCodegen - ReactCommon/turbomodule/core + - Yoga - React-FabricImage (1000.0.0): - DoubleConversion - fmt (= 9.1.0) @@ -1079,6 +1238,28 @@ PODS: - React-jsinspector - React-perflogger (= 1000.0.0) - React-runtimeexecutor + - React-idlecallbacksnativemodule (1000.0.0): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.01.01.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - React-ImageManager (1000.0.0): - glog - RCT-Folly/Fabric @@ -1116,6 +1297,7 @@ PODS: - RCT-Folly (= 2024.01.01.00) - React-featureflags - React-jsi + - React-perflogger (= 1000.0.0) - React-runtimeexecutor (= 1000.0.0) - React-jsitracing (1000.0.0): - React-jsi @@ -1157,7 +1339,12 @@ PODS: - React-runtimeexecutor - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - React-perflogger (1000.0.0) + - React-perflogger (1000.0.0): + - DoubleConversion + - RCT-Folly (= 2024.01.01.00) + - React-performancetimeline (1000.0.0): + - RCT-Folly (= 2024.01.01.00) + - React-cxxreact - React-RCTActionSheet (1000.0.0): - React-Core/RCTActionSheetHeaders (= 1000.0.0) - React-RCTAnimation (1000.0.0): @@ -1175,13 +1362,11 @@ PODS: - React-Core - React-CoreModules - React-debug - - React-domnativemodule + - React-defaultsnativemodule - React-Fabric - React-featureflags - - React-featureflagsnativemodule - React-graphics - React-hermes - - React-microtasksnativemodule - React-nativeconfig - React-NativeModulesApple - React-RCTFabric @@ -1215,6 +1400,7 @@ PODS: - React-Core - React-debug - React-Fabric + - React-FabricComponents - React-FabricImage - React-featureflags - React-graphics @@ -1222,6 +1408,7 @@ PODS: - React-jsi - React-jsinspector - React-nativeconfig + - React-performancetimeline - React-RCTImage - React-RCTText - React-rendererconsistency @@ -1425,7 +1612,7 @@ PODS: - React-logger (= 1000.0.0) - React-perflogger (= 1000.0.0) - React-utils (= 1000.0.0) - - ScreenshotManager (0.75.0-main): + - ScreenshotManager (0.76.0-main): - DoubleConversion - glog - hermes-engine @@ -1459,6 +1646,7 @@ DEPENDENCIES: - MyNativeView (from `NativeComponentExample`) - NativeCxxModuleExample (from `NativeCxxModuleExample`) - OCMock (~> 3.9.1) + - OSSLibraryExample (from `../react-native-test-library`) - RCT-Folly (from `../react-native/third-party-podspecs/RCT-Folly.podspec`) - RCT-Folly/Fabric (from `../react-native/third-party-podspecs/RCT-Folly.podspec`) - RCTDeprecation (from `../react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation`) @@ -1471,13 +1659,16 @@ DEPENDENCIES: - React-CoreModules (from `../react-native/React/CoreModules`) - React-cxxreact (from `../react-native/ReactCommon/cxxreact`) - React-debug (from `../react-native/ReactCommon/react/debug`) + - React-defaultsnativemodule (from `../react-native/ReactCommon/react/nativemodule/defaults`) - React-domnativemodule (from `../react-native/ReactCommon/react/nativemodule/dom`) - React-Fabric (from `../react-native/ReactCommon`) + - React-FabricComponents (from `../react-native/ReactCommon`) - React-FabricImage (from `../react-native/ReactCommon`) - React-featureflags (from `../react-native/ReactCommon/react/featureflags`) - React-featureflagsnativemodule (from `../react-native/ReactCommon/react/nativemodule/featureflags`) - React-graphics (from `../react-native/ReactCommon/react/renderer/graphics`) - React-hermes (from `../react-native/ReactCommon/hermes`) + - React-idlecallbacksnativemodule (from `../react-native/ReactCommon/react/nativemodule/idlecallbacks`) - React-ImageManager (from `../react-native/ReactCommon/react/renderer/imagemanager/platform/ios`) - React-jserrorhandler (from `../react-native/ReactCommon/jserrorhandler`) - React-jsi (from `../react-native/ReactCommon/jsi`) @@ -1490,6 +1681,7 @@ DEPENDENCIES: - React-nativeconfig (from `../react-native/ReactCommon`) - React-NativeModulesApple (from `../react-native/ReactCommon/react/nativemodule/core/platform/ios`) - React-perflogger (from `../react-native/ReactCommon/reactperflogger`) + - React-performancetimeline (from `../react-native/ReactCommon/react/performance/timeline`) - React-RCTActionSheet (from `../react-native/Libraries/ActionSheetIOS`) - React-RCTAnimation (from `../react-native/Libraries/NativeAnimation`) - React-RCTAppDelegate (from `../react-native/Libraries/AppDelegate`) @@ -1541,6 +1733,8 @@ EXTERNAL SOURCES: :path: NativeComponentExample NativeCxxModuleExample: :path: NativeCxxModuleExample + OSSLibraryExample: + :path: "../react-native-test-library" RCT-Folly: :podspec: "../react-native/third-party-podspecs/RCT-Folly.podspec" RCTDeprecation: @@ -1561,10 +1755,14 @@ EXTERNAL SOURCES: :path: "../react-native/ReactCommon/cxxreact" React-debug: :path: "../react-native/ReactCommon/react/debug" + React-defaultsnativemodule: + :path: "../react-native/ReactCommon/react/nativemodule/defaults" React-domnativemodule: :path: "../react-native/ReactCommon/react/nativemodule/dom" React-Fabric: :path: "../react-native/ReactCommon" + React-FabricComponents: + :path: "../react-native/ReactCommon" React-FabricImage: :path: "../react-native/ReactCommon" React-featureflags: @@ -1575,6 +1773,8 @@ EXTERNAL SOURCES: :path: "../react-native/ReactCommon/react/renderer/graphics" React-hermes: :path: "../react-native/ReactCommon/hermes" + React-idlecallbacksnativemodule: + :path: "../react-native/ReactCommon/react/nativemodule/idlecallbacks" React-ImageManager: :path: "../react-native/ReactCommon/react/renderer/imagemanager/platform/ios" React-jserrorhandler: @@ -1599,6 +1799,8 @@ EXTERNAL SOURCES: :path: "../react-native/ReactCommon/react/nativemodule/core/platform/ios" React-perflogger: :path: "../react-native/ReactCommon/reactperflogger" + React-performancetimeline: + :path: "../react-native/ReactCommon/react/performance/timeline" React-RCTActionSheet: :path: "../react-native/Libraries/ActionSheetIOS" React-RCTAnimation: @@ -1655,73 +1857,78 @@ EXTERNAL SOURCES: :path: "../react-native/ReactCommon/yoga" SPEC CHECKSUMS: - boost: b6c2ab552684b545148f00ac9e0bb243cc0a43f5 + boost: 4cb898d0bf20404aab1850c656dcea009429d6c1 DoubleConversion: 76ab83afb40bddeeee456813d9c04f67f78771b5 - FBLazyVector: f4492a543c5a8fa1502d3a5867e3f7252497cfe8 + FBLazyVector: d72a406427161a9c57371654484a88bcc6ce47d0 fmt: 4c2741a687cc09f0634a2e2c72a838b99f1ff120 - glog: c5d68082e772fa1c511173d6b30a9de2c05a69a2 - hermes-engine: 221c62bc31d84593845e639e3288c6f64abc75ac - MyNativeView: 1314dd52cc27c4a26957a5185aae6ecac6e4e2ff - NativeCxxModuleExample: 65632ba6e8c216048f7af7d3c7bb1431d22bc2d0 + glog: 69ef571f3de08433d766d614c73a9838a06bf7eb + hermes-engine: 8abc52a1910cbcca360090a7e59754658eef8c45 + MyNativeView: dd2c3b5b84dd52785838bcc2be84c997260405eb + NativeCxxModuleExample: 6167b4e77d00d92935efa7508668d937d7b33e3a OCMock: 9491e4bec59e0b267d52a9184ff5605995e74be8 - RCT-Folly: 02617c592a293bd6d418e0a88ff4ee1f88329b47 + OSSLibraryExample: d28d4a371b619dabe805659c5141bc6edd581ccd + RCT-Folly: f0ef9f32d6d4e2505313af21546e89c7ce929a02 RCTDeprecation: 3808e36294137f9ee5668f4df2e73dc079cd1dcf - RCTRequired: 82c56a03b3efd524bfdb581a906add903f78f978 - RCTTypeSafety: 5f57d4ae5dfafc85a0f575d756c909b584722c52 - React: cb6dc75e09f32aeddb4d8fb58a394a67219a92fe - React-callinvoker: bae59cbd6affd712bbfc703839dad868ff35069d - React-Core: 738c8db837b21aae813479f2eb284d5507a5c256 - React-CoreModules: 7647d54882adb778c614ac0053865ef1f92eb211 - React-cxxreact: 73a61f1e212fa084d3ae19a4ee4e3531aff646a9 - React-debug: 296b501a90c41f83961f58c6d96a01330d499da5 - React-domnativemodule: d38559c0807e0694565b806f347a465a2486a30e - React-Fabric: 1ea5efc1cd04fd179021a481a82773bb6574f46a - React-FabricImage: da62cc5089fe6bdaa6ec0ab6ccca75c7d679065d - React-featureflags: 23f83a12963770bf3cff300e8990678192436b36 - React-featureflagsnativemodule: 7f69e5d1ddaf2dacd69ba0d75faf396c5f148508 - React-graphics: 62a954b0806e51009878ea1a65497bb3f5e32968 - React-hermes: 65dd94615e5cb47f0f2f7510231f80c65abf338c - React-ImageManager: 716592dcbe11a4960e1eb3d82adb264ee15b5f6d - React-jserrorhandler: 3dded3f19f30d85a3eb7c866921edbe954ca6439 - React-jsi: fe80ef997eef6f16a7ee40b585db2b6013d51db8 - React-jsiexecutor: 42eeb6b4e73e1b50caa3940ad0189171723c6b29 - React-jsinspector: 8c41e3113f94f08385a730aff19eb16af810c82d - React-jsitracing: dd08057dd5b74119cb406beb42028da85ed5b8a5 - React-logger: 8486d7a1d32b972414b1d34a93470ee2562c6ee2 - React-Mapbuffer: fd0d0306c1c4326be5f18a61e978d32a66b20a85 - React-microtasksnativemodule: 0f4976afa97a9e6cac7e8ec7bf15b856c690c4d9 - React-nativeconfig: 40a2c848083ef4065c163c854e1c82b5f9e9db84 - React-NativeModulesApple: 48f0205edc54b8a1c24328f2deeb74b4f1570418 - React-perflogger: 70d009f755dd10002183454cdf5ad9b22de4a1d7 - React-RCTActionSheet: 943bd5f540f3af1e5a149c13c4de81858edf718a - React-RCTAnimation: 4d88a95a05dbb9a5cbc9a55e08f1a79364aeb206 - React-RCTAppDelegate: 937edc1048069bc6ff393d594a258bd50a35b90d - React-RCTBlob: 74c2fa0adba3a2e4ebbc4f9fc4ec3c3691b93854 - React-RCTFabric: 88e94c937c676ef00351244e8043908ba5b43e81 - React-RCTImage: 2413fa5ca25235b878fb2694115b26b176280f31 - React-RCTLinking: 7c821b30c5b4401037ed3da63f9580ac42b9e02e - React-RCTNetwork: a556f5005d28d99df0b577d9ef8b28f29c0ff498 - React-RCTPushNotification: c0871d7ebfd7832a5763b571f68b936772654ed3 - React-RCTSettings: 25141964d76155f25dd993b87345656a29dd0d24 - React-RCTTest: 3b9f62c66c3814ccace402441597160aefc9e812 - React-RCTText: d9925903524a7b179cf7803162a98038e0bfb4fd - React-RCTVibration: 63e015aa41be5e956440ebe8b8796f56ddd1acc8 - React-rendererconsistency: e4c6cb78c9cf114b3f3371f5e133c2db025951ef - React-rendererdebug: 0abbd75e947eeae23542f3bf7491b048ae063141 - React-rncore: e903b3d2819a25674403c548ec103f34bf02ba2b - React-RuntimeApple: b43ad6a5d60157f37ff3139e4dfb0cd6340e9be6 - React-RuntimeCore: 7cfdac312222d7260d8ba9604686fbb4aa4f8a13 - React-runtimeexecutor: e1c32bc249dd3cf3919cb4664fd8dc84ef70cff7 - React-RuntimeHermes: b19a99a600c6e1e33d7796cb91a5c76f92bd3407 - React-runtimescheduler: ca22ce34a60276d228399191dd039929cc9c6bc1 - React-utils: f5525c0072f467cf2f25bdd8dbbf0835f6384972 + RCTRequired: 97cc9122a80aaeb18a665947fbc90c3d6da39e63 + RCTTypeSafety: ef362937cc8be1b97fe948d4ffb642a0b9ad4a7f + React: a896e41701cc4aacb57cd0052497179881bb98a3 + React-callinvoker: df5cf9062e792abe1dfdc67b711c40617fb4047c + React-Core: 302137c05d7a4ede74284734c6793e57864c763b + React-CoreModules: 33c98646e0a27b6598b97a5b784ce60ba52179c7 + React-cxxreact: 30c9e3282064e8fa7541f7cebfd65bf80c149517 + React-debug: 72dcb97aff6132acf64ee58145bf233c324d7fc3 + React-defaultsnativemodule: 1b9273b457d161ae5391b99bdf0ca2d33f894a88 + React-domnativemodule: 3d998a3846ecf607a46be2fdde01cb62997f79b1 + React-Fabric: b587f171819ee3a5e6b871df61fa193819d4a376 + React-FabricComponents: 1e2e2a259538a1204be676eb22be9e5091208422 + React-FabricImage: 7b1357db4a3ec68d31d7b40eb7b010ad0e3fe3c8 + React-featureflags: f836c41ecb4b77b37a07c57f6e894fbeee94ee9b + React-featureflagsnativemodule: b9cc63b6a28c3fca8c0f6d5b3fa9886ec730d1ef + React-graphics: 218593e3d3d3c8dd560bdb95be44d0c7ccbeee45 + React-hermes: 4d2d928b266485f359124895e3500ba62b93f80c + React-idlecallbacksnativemodule: 575d801944ae2dacef6b4f290fe3ecc9e09befec + React-ImageManager: cdbeab64bd49a058565dc7edfcc5c235dce6be15 + React-jserrorhandler: c1a988cbdcea6e2937749deac53e3de5b5aecaaf + React-jsi: f9de7f0229d2eb0a0485658c3207d49257d044bb + React-jsiexecutor: a19ba52b4cb2fc6fa4dc8a5b4456a5a88aea14a1 + React-jsinspector: 2863c2b836c25bdc8e6f1c225063f120e94acd5c + React-jsitracing: 009e42e31959c5839b0e3c9cdd66cd69d8f3e3ef + React-logger: f775c546ebd86008b7d4a861f19012927b8eb26d + React-Mapbuffer: d2a1c1774a6de7976cc276a7311d10e3e958fa7a + React-microtasksnativemodule: 88785ad3bd26b7d83ee150bc5b249daa16ae9b66 + React-nativeconfig: cf7003929050942a4e37904c09b6e4aa6a31699a + React-NativeModulesApple: 870ecfbd00f54ed4d1b3c4e5c1044074059c1ae6 + React-perflogger: fa7520421b359dd4f78ed0f159b674966aaf77e2 + React-performancetimeline: cfddf8794402f068f58f2f45fd9cba66f5f6dc5d + React-RCTActionSheet: a0c6440ea15ee377cd0f6aa2c0994a90b7c9d375 + React-RCTAnimation: 6453e66858a921524ba2b61d1f289685b1b75961 + React-RCTAppDelegate: 601658ae319008b255a8c373c976ffc5eeb01bca + React-RCTBlob: 6b0ecea7eb59fb8e3adda1020772993ff6aebc3d + React-RCTFabric: af06620a22647fec2b4a0d702bcd419340752c09 + React-RCTImage: e5b7aafbb065219ac3b934ca8fd38b966d08bd84 + React-RCTLinking: 41341d10286614cf399def9c882def3f5df904a1 + React-RCTNetwork: c361540125cc61ee74705c9e3fd33fe17b994c42 + React-RCTPushNotification: 620f05c7a2bb3023366eb51db6a758ec4605b24a + React-RCTSettings: 719dfc11f683947c02ef3c925c2f1f85f5f77612 + React-RCTTest: 384ea92d077c460202b1a4400e6171500d82759f + React-RCTText: 814ef7d3a60f6db0ba2ad325634f16996db1d0a0 + React-RCTVibration: 1f416c8cb1dad2811996a38ad629444679a3af25 + React-rendererconsistency: 9ed5b0b375f763913e2782971d8a6213986931da + React-rendererdebug: 39d5d3de6cc90c31e4235478c4a214b72762cd17 + React-rncore: fbe8b5405b10db4ddcf7ca4c4b227d851f9c7386 + React-RuntimeApple: b403894bc2d0abca49de059bc89062692dac2af4 + React-RuntimeCore: 54ac5ddf06bc8ceba6302a373db410ebd24649df + React-runtimeexecutor: 3a95702b5502ac6de3abc03dbbd82bfd15f4e11c + React-RuntimeHermes: b7679f1841871615b38533d3dfe6b237d99d9d67 + React-runtimescheduler: 331fc52842c18d2488ac22dad3fee2d04647fe7b + React-utils: 1abc63758a96aa20003a1a8d7e50a212f792687d ReactCodegen: 23192ed6132b7eb93d61cc2ee8e21a816b361a37 - ReactCommon: 37e362e6877a42d74cc3d71be3d15a73f5f8c8ff - ReactCommon-Samples: e2bf03c8237c461fa36bda8e4638368fa82b633c - ScreenshotManager: 16fcf9cbbee5b261ac46641a0f502fc1cb73a089 + ReactCommon: b2b96bdfe39947d7b405e8ce6960c48b27b990b1 + ReactCommon-Samples: 234c8bfe932143313078569f55a22e38694f29ba + ScreenshotManager: ef3c2c6427fecb146407d8d89f44b73188042ef7 SocketRocket: abac6f5de4d4d62d24e11868d7a2f427e0ef940d - Yoga: f58ba5e0ac1e7eb3ef4caedcf80c5aa39985b039 + Yoga: a45d814f9cf447ad53f4b404385c75be3e46a120 -PODFILE CHECKSUM: 60b84dd598fc04e9ed84dbc82e2cb3b99b1d7adf +PODFILE CHECKSUM: 8591f96a513620a2a83a0b9a125ad3fa32ea1369 -COCOAPODS: 1.14.3 +COCOAPODS: 1.15.2 From b04cca817ad1d25efcf9fdc1cc3a84156abcbc80 Mon Sep 17 00:00:00 2001 From: Abdelhafidh Belalia <16493223+s77rt@users.noreply.github.com> Date: Wed, 24 Jul 2024 13:45:11 +0100 Subject: [PATCH 10/18] iOS: Pass clipboard data to onPaste event --- .../Text/TextInput/Multiline/RCTUITextView.mm | 5 ++++- .../Text/TextInput/RCTBackedTextInputDelegate.h | 2 +- .../RCTBackedTextInputDelegateAdapter.h | 4 ++-- .../RCTBackedTextInputDelegateAdapter.mm | 8 ++++---- .../Text/TextInput/RCTBaseTextInputView.mm | 16 ++++++++++++++-- .../Text/TextInput/Singleline/RCTUITextField.mm | 5 ++++- .../TextInput/RCTTextInputComponentView.mm | 4 ++-- .../iostextinput/TextInputEventEmitter.cpp | 13 +++++++++++-- .../iostextinput/TextInputEventEmitter.h | 2 +- 9 files changed, 43 insertions(+), 16 deletions(-) diff --git a/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm b/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm index 979019093831de..556b0ba935af8f 100644 --- a/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm +++ b/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm @@ -13,6 +13,8 @@ #import #import +#import + @implementation RCTUITextView { UILabel *_placeholderView; UITextView *_detachedTextView; @@ -172,7 +174,8 @@ - (void)scrollRangeToVisible:(NSRange)range - (void)paste:(id)sender { _textWasPasted = YES; - [_textInputDelegateAdapter didPaste]; + UIPasteboard *clipboard = [UIPasteboard generalPasteboard]; + [_textInputDelegateAdapter didPaste:@"text/plain" withData:clipboard.string]; [super paste:sender]; } diff --git a/packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegate.h b/packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegate.h index aaa6a17960b3aa..748c4cce4589e2 100644 --- a/packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegate.h +++ b/packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegate.h @@ -36,7 +36,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)textInputDidChange; - (void)textInputDidChangeSelection; -- (void)textInputDidPaste; +- (void)textInputDidPaste:(NSString *)type withData:(NSString *)data; @optional diff --git a/packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.h b/packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.h index 2b91f03b3d1196..0ce9dfe7c8e0a2 100644 --- a/packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.h +++ b/packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.h @@ -20,7 +20,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)skipNextTextInputDidChangeSelectionEventWithTextRange:(UITextRange *)textRange; - (void)selectedTextRangeWasSet; -- (void)didPaste; +- (void)didPaste:(NSString *)type withData:(NSString *)data; @end @@ -31,7 +31,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithTextView:(UITextView *)backedTextInputView; - (void)skipNextTextInputDidChangeSelectionEventWithTextRange:(UITextRange *)textRange; -- (void)didPaste; +- (void)didPaste:(NSString *)type withData:(NSString *)data; @end diff --git a/packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.mm b/packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.mm index 71fe54984caf32..2b91802a1238f4 100644 --- a/packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.mm +++ b/packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.mm @@ -147,9 +147,9 @@ - (void)selectedTextRangeWasSet [self textFieldProbablyDidChangeSelection]; } -- (void)didPaste +- (void)didPaste:(NSString *)type withData:(NSString *)data { - [_backedTextInputView.textInputDelegate textInputDidPaste]; + [_backedTextInputView.textInputDelegate textInputDidPaste:type withData:data]; } #pragma mark - Generalization @@ -297,9 +297,9 @@ - (void)skipNextTextInputDidChangeSelectionEventWithTextRange:(UITextRange *)tex _previousSelectedTextRange = textRange; } -- (void)didPaste +- (void)didPaste:(NSString *)type withData:(NSString *)data { - [_backedTextInputView.textInputDelegate textInputDidPaste]; + [_backedTextInputView.textInputDelegate textInputDidPaste:type withData:data]; } #pragma mark - Generalization diff --git a/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.mm b/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.mm index e599b09a40823e..972c11ad065b4f 100644 --- a/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.mm +++ b/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.mm @@ -543,12 +543,24 @@ - (void)textInputDidChangeSelection }); } -- (void)textInputDidPaste +- (void)textInputDidPaste:(NSString *)type withData:(NSString *)data { if (!_onPaste) { return; } - _onPaste(@{@"target" : self.reactTag}); + + NSMutableArray *items = [NSMutableArray new]; + [items addObject:@{ + @"type" : type, + @"data" : data, + }]; + + NSDictionary *payload = @{ + @"target" : self.reactTag, + @"items" : items, + }; + + _onPaste(payload); } - (void)updateLocalData diff --git a/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm b/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm index ea458b45fc34ac..7d524d2076a4bc 100644 --- a/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm +++ b/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm @@ -12,6 +12,8 @@ #import #import +#import + @implementation RCTUITextField { RCTBackedTextFieldDelegateAdapter *_textInputDelegateAdapter; NSDictionary *_defaultTextAttributes; @@ -222,7 +224,8 @@ - (void)scrollRangeToVisible:(NSRange)range - (void)paste:(id)sender { _textWasPasted = YES; - [_textInputDelegateAdapter didPaste]; + UIPasteboard *clipboard = [UIPasteboard generalPasteboard]; + [_textInputDelegateAdapter didPaste:@"text/plain" withData:clipboard.string]; [super paste:sender]; } diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm index 5ec85c1233a101..6d5b8f2fe80584 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm @@ -404,10 +404,10 @@ - (void)textInputDidChangeSelection } } -- (void)textInputDidPaste +- (void)textInputDidPaste:(NSString *)type withData:(NSString *)data { if (_eventEmitter) { - static_cast(*_eventEmitter).onPaste(); + static_cast(*_eventEmitter).onPaste(std::string([type UTF8String]), std::string([data UTF8String])); } } diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputEventEmitter.cpp b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputEventEmitter.cpp index 9f6d8c07794b09..15a85cf40152a7 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputEventEmitter.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputEventEmitter.cpp @@ -172,8 +172,17 @@ void TextInputEventEmitter::onScroll(const Metrics& textInputMetrics) const { }); } -void TextInputEventEmitter::onPaste() const { - dispatchEvent("onPaste"); +void TextInputEventEmitter::onPaste(const std::string& type, const std::string& data) const { + dispatchEvent("onPaste", [type, data](jsi::Runtime& runtime) { + auto payload = jsi::Object(runtime); + auto items = jsi::Array(runtime, 1); + auto item = jsi::Object(runtime); + item.setProperty(runtime, "type", type); + item.setProperty(runtime, "data", data); + items.setValueAtIndex(runtime, 0, item); + payload.setProperty(runtime, "items", items); + return payload; + }); } void TextInputEventEmitter::dispatchTextInputEvent( diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputEventEmitter.h b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputEventEmitter.h index c6ef1f421c5d57..46700186b1eb79 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputEventEmitter.h +++ b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/ios/react/renderer/components/iostextinput/TextInputEventEmitter.h @@ -43,7 +43,7 @@ class TextInputEventEmitter : public ViewEventEmitter { void onSubmitEditing(const Metrics& textInputMetrics) const; void onKeyPress(const KeyPressMetrics& keyPressMetrics) const; void onScroll(const Metrics& textInputMetrics) const; - void onPaste() const; + void onPaste(const std::string& type, const std::string& data) const; private: void dispatchTextInputEvent( From c580a3b59cbc7f10f1a194bed73fe27d2da5dab8 Mon Sep 17 00:00:00 2001 From: Abdelhafidh Belalia <16493223+s77rt@users.noreply.github.com> Date: Thu, 25 Jul 2024 00:51:07 +0100 Subject: [PATCH 11/18] Revert "Update Podfile.lock" This reverts commit 5baad1a94a55efed5c66016c8ce8a20c3c5283ef. --- packages/rn-tester/Podfile.lock | 435 +++++++++----------------------- 1 file changed, 114 insertions(+), 321 deletions(-) diff --git a/packages/rn-tester/Podfile.lock b/packages/rn-tester/Podfile.lock index c0653f0516f60a..07b5b5b40b7d4e 100644 --- a/packages/rn-tester/Podfile.lock +++ b/packages/rn-tester/Podfile.lock @@ -15,7 +15,7 @@ PODS: - hermes-engine/inspector (1000.0.0) - hermes-engine/inspector_chrome (1000.0.0) - hermes-engine/Public (1000.0.0) - - MyNativeView (0.76.0-main): + - MyNativeView (0.75.0-main): - DoubleConversion - glog - hermes-engine @@ -36,7 +36,7 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga - - NativeCxxModuleExample (0.76.0-main): + - NativeCxxModuleExample (0.75.0-main): - DoubleConversion - glog - hermes-engine @@ -58,27 +58,6 @@ PODS: - ReactCommon/turbomodule/core - Yoga - OCMock (3.9.1) - - OSSLibraryExample (0.76.0-main): - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2024.01.01.00) - - RCTRequired - - RCTTypeSafety - - React-Core - - React-debug - - React-Fabric - - React-featureflags - - React-graphics - - React-ImageManager - - React-NativeModulesApple - - React-RCTFabric - - React-rendererdebug - - React-utils - - ReactCodegen - - ReactCommon/turbomodule/bridging - - ReactCommon/turbomodule/core - - Yoga - RCT-Folly (2024.01.01.00): - boost - DoubleConversion @@ -399,31 +378,6 @@ PODS: - React-perflogger (= 1000.0.0) - React-runtimeexecutor (= 1000.0.0) - React-debug (1000.0.0) - - React-defaultsnativemodule (1000.0.0): - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2024.01.01.00) - - RCTRequired - - RCTTypeSafety - - React-Core - - React-debug - - React-domnativemodule - - React-Fabric - - React-featureflags - - React-featureflagsnativemodule - - React-graphics - - React-idlecallbacksnativemodule - - React-ImageManager - - React-microtasksnativemodule - - React-NativeModulesApple - - React-RCTFabric - - React-rendererdebug - - React-utils - - ReactCodegen - - ReactCommon/turbomodule/bridging - - ReactCommon/turbomodule/core - - Yoga - React-domnativemodule (1000.0.0): - DoubleConversion - glog @@ -434,7 +388,9 @@ PODS: - React-Core - React-debug - React-Fabric - - React-FabricComponents + - React-Fabric/components/root + - React-Fabric/dom + - React-Fabric/uimanager - React-featureflags - React-graphics - React-ImageManager @@ -467,10 +423,10 @@ PODS: - React-Fabric/imagemanager (= 1000.0.0) - React-Fabric/leakchecker (= 1000.0.0) - React-Fabric/mounting (= 1000.0.0) - - React-Fabric/observers (= 1000.0.0) - React-Fabric/scheduler (= 1000.0.0) - React-Fabric/telemetry (= 1000.0.0) - React-Fabric/templateprocessor (= 1000.0.0) + - React-Fabric/textlayoutmanager (= 1000.0.0) - React-Fabric/uimanager (= 1000.0.0) - React-featureflags - React-graphics @@ -572,8 +528,17 @@ PODS: - React-Core - React-cxxreact - React-debug + - React-Fabric/components/inputaccessory (= 1000.0.0) + - React-Fabric/components/iostextinput (= 1000.0.0) - React-Fabric/components/legacyviewmanagerinterop (= 1000.0.0) + - React-Fabric/components/modal (= 1000.0.0) + - React-Fabric/components/rncore (= 1000.0.0) - React-Fabric/components/root (= 1000.0.0) + - React-Fabric/components/safeareaview (= 1000.0.0) + - React-Fabric/components/scrollview (= 1000.0.0) + - React-Fabric/components/text (= 1000.0.0) + - React-Fabric/components/textinput (= 1000.0.0) + - React-Fabric/components/unimplementedview (= 1000.0.0) - React-Fabric/components/view (= 1000.0.0) - React-featureflags - React-graphics @@ -584,7 +549,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/legacyviewmanagerinterop (1000.0.0): + - React-Fabric/components/inputaccessory (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -604,7 +569,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/root (1000.0.0): + - React-Fabric/components/iostextinput (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -624,88 +589,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/view (1000.0.0): - - DoubleConversion - - fmt (= 9.1.0) - - glog - - hermes-engine - - RCT-Folly/Fabric (= 2024.01.01.00) - - RCTRequired - - RCTTypeSafety - - React-Core - - React-cxxreact - - React-debug - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-rendererdebug - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - Yoga - - React-Fabric/core (1000.0.0): - - DoubleConversion - - fmt (= 9.1.0) - - glog - - hermes-engine - - RCT-Folly/Fabric (= 2024.01.01.00) - - RCTRequired - - RCTTypeSafety - - React-Core - - React-cxxreact - - React-debug - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-rendererdebug - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - React-Fabric/dom (1000.0.0): - - DoubleConversion - - fmt (= 9.1.0) - - glog - - hermes-engine - - RCT-Folly/Fabric (= 2024.01.01.00) - - RCTRequired - - RCTTypeSafety - - React-Core - - React-cxxreact - - React-debug - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-rendererdebug - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - React-Fabric/imagemanager (1000.0.0): - - DoubleConversion - - fmt (= 9.1.0) - - glog - - hermes-engine - - RCT-Folly/Fabric (= 2024.01.01.00) - - RCTRequired - - RCTTypeSafety - - React-Core - - React-cxxreact - - React-debug - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-rendererdebug - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - React-Fabric/leakchecker (1000.0.0): + - React-Fabric/components/legacyviewmanagerinterop (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -725,7 +609,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/mounting (1000.0.0): + - React-Fabric/components/modal (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -745,7 +629,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/observers (1000.0.0): + - React-Fabric/components/rncore (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -756,7 +640,6 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-Fabric/observers/events (= 1000.0.0) - React-featureflags - React-graphics - React-jsi @@ -766,7 +649,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/observers/events (1000.0.0): + - React-Fabric/components/root (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -786,7 +669,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/scheduler (1000.0.0): + - React-Fabric/components/safeareaview (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -797,18 +680,16 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-Fabric/observers/events - React-featureflags - React-graphics - React-jsi - React-jsiexecutor - React-logger - - React-performancetimeline - React-rendererdebug - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/telemetry (1000.0.0): + - React-Fabric/components/scrollview (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -828,7 +709,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/templateprocessor (1000.0.0): + - React-Fabric/components/text (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -848,7 +729,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/uimanager (1000.0.0): + - React-Fabric/components/textinput (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -859,18 +740,16 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-Fabric/uimanager/consistency (= 1000.0.0) - React-featureflags - React-graphics - React-jsi - React-jsiexecutor - React-logger - - React-rendererconsistency - React-rendererdebug - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/uimanager/consistency (1000.0.0): + - React-Fabric/components/unimplementedview (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -886,12 +765,11 @@ PODS: - React-jsi - React-jsiexecutor - React-logger - - React-rendererconsistency - React-rendererdebug - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-FabricComponents (1000.0.0): + - React-Fabric/components/view (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -902,9 +780,6 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-Fabric - - React-FabricComponents/components (= 1000.0.0) - - React-FabricComponents/textlayoutmanager (= 1000.0.0) - React-featureflags - React-graphics - React-jsi @@ -913,10 +788,9 @@ PODS: - React-rendererdebug - React-runtimescheduler - React-utils - - ReactCodegen - ReactCommon/turbomodule/core - Yoga - - React-FabricComponents/components (1000.0.0): + - React-Fabric/core (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -927,16 +801,6 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-Fabric - - React-FabricComponents/components/inputaccessory (= 1000.0.0) - - React-FabricComponents/components/iostextinput (= 1000.0.0) - - React-FabricComponents/components/modal (= 1000.0.0) - - React-FabricComponents/components/rncore (= 1000.0.0) - - React-FabricComponents/components/safeareaview (= 1000.0.0) - - React-FabricComponents/components/scrollview (= 1000.0.0) - - React-FabricComponents/components/text (= 1000.0.0) - - React-FabricComponents/components/textinput (= 1000.0.0) - - React-FabricComponents/components/unimplementedview (= 1000.0.0) - React-featureflags - React-graphics - React-jsi @@ -945,10 +809,8 @@ PODS: - React-rendererdebug - React-runtimescheduler - React-utils - - ReactCodegen - ReactCommon/turbomodule/core - - Yoga - - React-FabricComponents/components/inputaccessory (1000.0.0): + - React-Fabric/dom (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -959,7 +821,9 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-Fabric + - React-Fabric/components/root + - React-Fabric/components/text + - React-Fabric/core - React-featureflags - React-graphics - React-jsi @@ -968,10 +832,8 @@ PODS: - React-rendererdebug - React-runtimescheduler - React-utils - - ReactCodegen - ReactCommon/turbomodule/core - - Yoga - - React-FabricComponents/components/iostextinput (1000.0.0): + - React-Fabric/imagemanager (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -982,7 +844,6 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-Fabric - React-featureflags - React-graphics - React-jsi @@ -991,10 +852,8 @@ PODS: - React-rendererdebug - React-runtimescheduler - React-utils - - ReactCodegen - ReactCommon/turbomodule/core - - Yoga - - React-FabricComponents/components/modal (1000.0.0): + - React-Fabric/leakchecker (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -1005,7 +864,6 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-Fabric - React-featureflags - React-graphics - React-jsi @@ -1014,10 +872,8 @@ PODS: - React-rendererdebug - React-runtimescheduler - React-utils - - ReactCodegen - ReactCommon/turbomodule/core - - Yoga - - React-FabricComponents/components/rncore (1000.0.0): + - React-Fabric/mounting (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -1028,7 +884,6 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-Fabric - React-featureflags - React-graphics - React-jsi @@ -1037,10 +892,8 @@ PODS: - React-rendererdebug - React-runtimescheduler - React-utils - - ReactCodegen - ReactCommon/turbomodule/core - - Yoga - - React-FabricComponents/components/safeareaview (1000.0.0): + - React-Fabric/scheduler (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -1051,7 +904,6 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-Fabric - React-featureflags - React-graphics - React-jsi @@ -1060,10 +912,8 @@ PODS: - React-rendererdebug - React-runtimescheduler - React-utils - - ReactCodegen - ReactCommon/turbomodule/core - - Yoga - - React-FabricComponents/components/scrollview (1000.0.0): + - React-Fabric/telemetry (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -1074,7 +924,6 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-Fabric - React-featureflags - React-graphics - React-jsi @@ -1083,10 +932,8 @@ PODS: - React-rendererdebug - React-runtimescheduler - React-utils - - ReactCodegen - ReactCommon/turbomodule/core - - Yoga - - React-FabricComponents/components/text (1000.0.0): + - React-Fabric/templateprocessor (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -1097,7 +944,6 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-Fabric - React-featureflags - React-graphics - React-jsi @@ -1106,10 +952,8 @@ PODS: - React-rendererdebug - React-runtimescheduler - React-utils - - ReactCodegen - ReactCommon/turbomodule/core - - Yoga - - React-FabricComponents/components/textinput (1000.0.0): + - React-Fabric/textlayoutmanager (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -1120,7 +964,7 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-Fabric + - React-Fabric/uimanager - React-featureflags - React-graphics - React-jsi @@ -1129,10 +973,8 @@ PODS: - React-rendererdebug - React-runtimescheduler - React-utils - - ReactCodegen - ReactCommon/turbomodule/core - - Yoga - - React-FabricComponents/components/unimplementedview (1000.0.0): + - React-Fabric/uimanager (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -1143,19 +985,19 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-Fabric + - React-Fabric/dom + - React-Fabric/uimanager/consistency (= 1000.0.0) - React-featureflags - React-graphics - React-jsi - React-jsiexecutor - React-logger + - React-rendererconsistency - React-rendererdebug - React-runtimescheduler - React-utils - - ReactCodegen - ReactCommon/turbomodule/core - - Yoga - - React-FabricComponents/textlayoutmanager (1000.0.0): + - React-Fabric/uimanager/consistency (1000.0.0): - DoubleConversion - fmt (= 9.1.0) - glog @@ -1166,18 +1008,17 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-Fabric + - React-Fabric/dom - React-featureflags - React-graphics - React-jsi - React-jsiexecutor - React-logger + - React-rendererconsistency - React-rendererdebug - React-runtimescheduler - React-utils - - ReactCodegen - ReactCommon/turbomodule/core - - Yoga - React-FabricImage (1000.0.0): - DoubleConversion - fmt (= 9.1.0) @@ -1238,28 +1079,6 @@ PODS: - React-jsinspector - React-perflogger (= 1000.0.0) - React-runtimeexecutor - - React-idlecallbacksnativemodule (1000.0.0): - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2024.01.01.00) - - RCTRequired - - RCTTypeSafety - - React-Core - - React-debug - - React-Fabric - - React-featureflags - - React-graphics - - React-ImageManager - - React-NativeModulesApple - - React-RCTFabric - - React-rendererdebug - - React-runtimescheduler - - React-utils - - ReactCodegen - - ReactCommon/turbomodule/bridging - - ReactCommon/turbomodule/core - - Yoga - React-ImageManager (1000.0.0): - glog - RCT-Folly/Fabric @@ -1297,7 +1116,6 @@ PODS: - RCT-Folly (= 2024.01.01.00) - React-featureflags - React-jsi - - React-perflogger (= 1000.0.0) - React-runtimeexecutor (= 1000.0.0) - React-jsitracing (1000.0.0): - React-jsi @@ -1339,12 +1157,7 @@ PODS: - React-runtimeexecutor - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - React-perflogger (1000.0.0): - - DoubleConversion - - RCT-Folly (= 2024.01.01.00) - - React-performancetimeline (1000.0.0): - - RCT-Folly (= 2024.01.01.00) - - React-cxxreact + - React-perflogger (1000.0.0) - React-RCTActionSheet (1000.0.0): - React-Core/RCTActionSheetHeaders (= 1000.0.0) - React-RCTAnimation (1000.0.0): @@ -1362,11 +1175,13 @@ PODS: - React-Core - React-CoreModules - React-debug - - React-defaultsnativemodule + - React-domnativemodule - React-Fabric - React-featureflags + - React-featureflagsnativemodule - React-graphics - React-hermes + - React-microtasksnativemodule - React-nativeconfig - React-NativeModulesApple - React-RCTFabric @@ -1400,7 +1215,6 @@ PODS: - React-Core - React-debug - React-Fabric - - React-FabricComponents - React-FabricImage - React-featureflags - React-graphics @@ -1408,7 +1222,6 @@ PODS: - React-jsi - React-jsinspector - React-nativeconfig - - React-performancetimeline - React-RCTImage - React-RCTText - React-rendererconsistency @@ -1612,7 +1425,7 @@ PODS: - React-logger (= 1000.0.0) - React-perflogger (= 1000.0.0) - React-utils (= 1000.0.0) - - ScreenshotManager (0.76.0-main): + - ScreenshotManager (0.75.0-main): - DoubleConversion - glog - hermes-engine @@ -1646,7 +1459,6 @@ DEPENDENCIES: - MyNativeView (from `NativeComponentExample`) - NativeCxxModuleExample (from `NativeCxxModuleExample`) - OCMock (~> 3.9.1) - - OSSLibraryExample (from `../react-native-test-library`) - RCT-Folly (from `../react-native/third-party-podspecs/RCT-Folly.podspec`) - RCT-Folly/Fabric (from `../react-native/third-party-podspecs/RCT-Folly.podspec`) - RCTDeprecation (from `../react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation`) @@ -1659,16 +1471,13 @@ DEPENDENCIES: - React-CoreModules (from `../react-native/React/CoreModules`) - React-cxxreact (from `../react-native/ReactCommon/cxxreact`) - React-debug (from `../react-native/ReactCommon/react/debug`) - - React-defaultsnativemodule (from `../react-native/ReactCommon/react/nativemodule/defaults`) - React-domnativemodule (from `../react-native/ReactCommon/react/nativemodule/dom`) - React-Fabric (from `../react-native/ReactCommon`) - - React-FabricComponents (from `../react-native/ReactCommon`) - React-FabricImage (from `../react-native/ReactCommon`) - React-featureflags (from `../react-native/ReactCommon/react/featureflags`) - React-featureflagsnativemodule (from `../react-native/ReactCommon/react/nativemodule/featureflags`) - React-graphics (from `../react-native/ReactCommon/react/renderer/graphics`) - React-hermes (from `../react-native/ReactCommon/hermes`) - - React-idlecallbacksnativemodule (from `../react-native/ReactCommon/react/nativemodule/idlecallbacks`) - React-ImageManager (from `../react-native/ReactCommon/react/renderer/imagemanager/platform/ios`) - React-jserrorhandler (from `../react-native/ReactCommon/jserrorhandler`) - React-jsi (from `../react-native/ReactCommon/jsi`) @@ -1681,7 +1490,6 @@ DEPENDENCIES: - React-nativeconfig (from `../react-native/ReactCommon`) - React-NativeModulesApple (from `../react-native/ReactCommon/react/nativemodule/core/platform/ios`) - React-perflogger (from `../react-native/ReactCommon/reactperflogger`) - - React-performancetimeline (from `../react-native/ReactCommon/react/performance/timeline`) - React-RCTActionSheet (from `../react-native/Libraries/ActionSheetIOS`) - React-RCTAnimation (from `../react-native/Libraries/NativeAnimation`) - React-RCTAppDelegate (from `../react-native/Libraries/AppDelegate`) @@ -1733,8 +1541,6 @@ EXTERNAL SOURCES: :path: NativeComponentExample NativeCxxModuleExample: :path: NativeCxxModuleExample - OSSLibraryExample: - :path: "../react-native-test-library" RCT-Folly: :podspec: "../react-native/third-party-podspecs/RCT-Folly.podspec" RCTDeprecation: @@ -1755,14 +1561,10 @@ EXTERNAL SOURCES: :path: "../react-native/ReactCommon/cxxreact" React-debug: :path: "../react-native/ReactCommon/react/debug" - React-defaultsnativemodule: - :path: "../react-native/ReactCommon/react/nativemodule/defaults" React-domnativemodule: :path: "../react-native/ReactCommon/react/nativemodule/dom" React-Fabric: :path: "../react-native/ReactCommon" - React-FabricComponents: - :path: "../react-native/ReactCommon" React-FabricImage: :path: "../react-native/ReactCommon" React-featureflags: @@ -1773,8 +1575,6 @@ EXTERNAL SOURCES: :path: "../react-native/ReactCommon/react/renderer/graphics" React-hermes: :path: "../react-native/ReactCommon/hermes" - React-idlecallbacksnativemodule: - :path: "../react-native/ReactCommon/react/nativemodule/idlecallbacks" React-ImageManager: :path: "../react-native/ReactCommon/react/renderer/imagemanager/platform/ios" React-jserrorhandler: @@ -1799,8 +1599,6 @@ EXTERNAL SOURCES: :path: "../react-native/ReactCommon/react/nativemodule/core/platform/ios" React-perflogger: :path: "../react-native/ReactCommon/reactperflogger" - React-performancetimeline: - :path: "../react-native/ReactCommon/react/performance/timeline" React-RCTActionSheet: :path: "../react-native/Libraries/ActionSheetIOS" React-RCTAnimation: @@ -1857,78 +1655,73 @@ EXTERNAL SOURCES: :path: "../react-native/ReactCommon/yoga" SPEC CHECKSUMS: - boost: 4cb898d0bf20404aab1850c656dcea009429d6c1 + boost: b6c2ab552684b545148f00ac9e0bb243cc0a43f5 DoubleConversion: 76ab83afb40bddeeee456813d9c04f67f78771b5 - FBLazyVector: d72a406427161a9c57371654484a88bcc6ce47d0 + FBLazyVector: f4492a543c5a8fa1502d3a5867e3f7252497cfe8 fmt: 4c2741a687cc09f0634a2e2c72a838b99f1ff120 - glog: 69ef571f3de08433d766d614c73a9838a06bf7eb - hermes-engine: 8abc52a1910cbcca360090a7e59754658eef8c45 - MyNativeView: dd2c3b5b84dd52785838bcc2be84c997260405eb - NativeCxxModuleExample: 6167b4e77d00d92935efa7508668d937d7b33e3a + glog: c5d68082e772fa1c511173d6b30a9de2c05a69a2 + hermes-engine: 221c62bc31d84593845e639e3288c6f64abc75ac + MyNativeView: 1314dd52cc27c4a26957a5185aae6ecac6e4e2ff + NativeCxxModuleExample: 65632ba6e8c216048f7af7d3c7bb1431d22bc2d0 OCMock: 9491e4bec59e0b267d52a9184ff5605995e74be8 - OSSLibraryExample: d28d4a371b619dabe805659c5141bc6edd581ccd - RCT-Folly: f0ef9f32d6d4e2505313af21546e89c7ce929a02 + RCT-Folly: 02617c592a293bd6d418e0a88ff4ee1f88329b47 RCTDeprecation: 3808e36294137f9ee5668f4df2e73dc079cd1dcf - RCTRequired: 97cc9122a80aaeb18a665947fbc90c3d6da39e63 - RCTTypeSafety: ef362937cc8be1b97fe948d4ffb642a0b9ad4a7f - React: a896e41701cc4aacb57cd0052497179881bb98a3 - React-callinvoker: df5cf9062e792abe1dfdc67b711c40617fb4047c - React-Core: 302137c05d7a4ede74284734c6793e57864c763b - React-CoreModules: 33c98646e0a27b6598b97a5b784ce60ba52179c7 - React-cxxreact: 30c9e3282064e8fa7541f7cebfd65bf80c149517 - React-debug: 72dcb97aff6132acf64ee58145bf233c324d7fc3 - React-defaultsnativemodule: 1b9273b457d161ae5391b99bdf0ca2d33f894a88 - React-domnativemodule: 3d998a3846ecf607a46be2fdde01cb62997f79b1 - React-Fabric: b587f171819ee3a5e6b871df61fa193819d4a376 - React-FabricComponents: 1e2e2a259538a1204be676eb22be9e5091208422 - React-FabricImage: 7b1357db4a3ec68d31d7b40eb7b010ad0e3fe3c8 - React-featureflags: f836c41ecb4b77b37a07c57f6e894fbeee94ee9b - React-featureflagsnativemodule: b9cc63b6a28c3fca8c0f6d5b3fa9886ec730d1ef - React-graphics: 218593e3d3d3c8dd560bdb95be44d0c7ccbeee45 - React-hermes: 4d2d928b266485f359124895e3500ba62b93f80c - React-idlecallbacksnativemodule: 575d801944ae2dacef6b4f290fe3ecc9e09befec - React-ImageManager: cdbeab64bd49a058565dc7edfcc5c235dce6be15 - React-jserrorhandler: c1a988cbdcea6e2937749deac53e3de5b5aecaaf - React-jsi: f9de7f0229d2eb0a0485658c3207d49257d044bb - React-jsiexecutor: a19ba52b4cb2fc6fa4dc8a5b4456a5a88aea14a1 - React-jsinspector: 2863c2b836c25bdc8e6f1c225063f120e94acd5c - React-jsitracing: 009e42e31959c5839b0e3c9cdd66cd69d8f3e3ef - React-logger: f775c546ebd86008b7d4a861f19012927b8eb26d - React-Mapbuffer: d2a1c1774a6de7976cc276a7311d10e3e958fa7a - React-microtasksnativemodule: 88785ad3bd26b7d83ee150bc5b249daa16ae9b66 - React-nativeconfig: cf7003929050942a4e37904c09b6e4aa6a31699a - React-NativeModulesApple: 870ecfbd00f54ed4d1b3c4e5c1044074059c1ae6 - React-perflogger: fa7520421b359dd4f78ed0f159b674966aaf77e2 - React-performancetimeline: cfddf8794402f068f58f2f45fd9cba66f5f6dc5d - React-RCTActionSheet: a0c6440ea15ee377cd0f6aa2c0994a90b7c9d375 - React-RCTAnimation: 6453e66858a921524ba2b61d1f289685b1b75961 - React-RCTAppDelegate: 601658ae319008b255a8c373c976ffc5eeb01bca - React-RCTBlob: 6b0ecea7eb59fb8e3adda1020772993ff6aebc3d - React-RCTFabric: af06620a22647fec2b4a0d702bcd419340752c09 - React-RCTImage: e5b7aafbb065219ac3b934ca8fd38b966d08bd84 - React-RCTLinking: 41341d10286614cf399def9c882def3f5df904a1 - React-RCTNetwork: c361540125cc61ee74705c9e3fd33fe17b994c42 - React-RCTPushNotification: 620f05c7a2bb3023366eb51db6a758ec4605b24a - React-RCTSettings: 719dfc11f683947c02ef3c925c2f1f85f5f77612 - React-RCTTest: 384ea92d077c460202b1a4400e6171500d82759f - React-RCTText: 814ef7d3a60f6db0ba2ad325634f16996db1d0a0 - React-RCTVibration: 1f416c8cb1dad2811996a38ad629444679a3af25 - React-rendererconsistency: 9ed5b0b375f763913e2782971d8a6213986931da - React-rendererdebug: 39d5d3de6cc90c31e4235478c4a214b72762cd17 - React-rncore: fbe8b5405b10db4ddcf7ca4c4b227d851f9c7386 - React-RuntimeApple: b403894bc2d0abca49de059bc89062692dac2af4 - React-RuntimeCore: 54ac5ddf06bc8ceba6302a373db410ebd24649df - React-runtimeexecutor: 3a95702b5502ac6de3abc03dbbd82bfd15f4e11c - React-RuntimeHermes: b7679f1841871615b38533d3dfe6b237d99d9d67 - React-runtimescheduler: 331fc52842c18d2488ac22dad3fee2d04647fe7b - React-utils: 1abc63758a96aa20003a1a8d7e50a212f792687d + RCTRequired: 82c56a03b3efd524bfdb581a906add903f78f978 + RCTTypeSafety: 5f57d4ae5dfafc85a0f575d756c909b584722c52 + React: cb6dc75e09f32aeddb4d8fb58a394a67219a92fe + React-callinvoker: bae59cbd6affd712bbfc703839dad868ff35069d + React-Core: 738c8db837b21aae813479f2eb284d5507a5c256 + React-CoreModules: 7647d54882adb778c614ac0053865ef1f92eb211 + React-cxxreact: 73a61f1e212fa084d3ae19a4ee4e3531aff646a9 + React-debug: 296b501a90c41f83961f58c6d96a01330d499da5 + React-domnativemodule: d38559c0807e0694565b806f347a465a2486a30e + React-Fabric: 1ea5efc1cd04fd179021a481a82773bb6574f46a + React-FabricImage: da62cc5089fe6bdaa6ec0ab6ccca75c7d679065d + React-featureflags: 23f83a12963770bf3cff300e8990678192436b36 + React-featureflagsnativemodule: 7f69e5d1ddaf2dacd69ba0d75faf396c5f148508 + React-graphics: 62a954b0806e51009878ea1a65497bb3f5e32968 + React-hermes: 65dd94615e5cb47f0f2f7510231f80c65abf338c + React-ImageManager: 716592dcbe11a4960e1eb3d82adb264ee15b5f6d + React-jserrorhandler: 3dded3f19f30d85a3eb7c866921edbe954ca6439 + React-jsi: fe80ef997eef6f16a7ee40b585db2b6013d51db8 + React-jsiexecutor: 42eeb6b4e73e1b50caa3940ad0189171723c6b29 + React-jsinspector: 8c41e3113f94f08385a730aff19eb16af810c82d + React-jsitracing: dd08057dd5b74119cb406beb42028da85ed5b8a5 + React-logger: 8486d7a1d32b972414b1d34a93470ee2562c6ee2 + React-Mapbuffer: fd0d0306c1c4326be5f18a61e978d32a66b20a85 + React-microtasksnativemodule: 0f4976afa97a9e6cac7e8ec7bf15b856c690c4d9 + React-nativeconfig: 40a2c848083ef4065c163c854e1c82b5f9e9db84 + React-NativeModulesApple: 48f0205edc54b8a1c24328f2deeb74b4f1570418 + React-perflogger: 70d009f755dd10002183454cdf5ad9b22de4a1d7 + React-RCTActionSheet: 943bd5f540f3af1e5a149c13c4de81858edf718a + React-RCTAnimation: 4d88a95a05dbb9a5cbc9a55e08f1a79364aeb206 + React-RCTAppDelegate: 937edc1048069bc6ff393d594a258bd50a35b90d + React-RCTBlob: 74c2fa0adba3a2e4ebbc4f9fc4ec3c3691b93854 + React-RCTFabric: 88e94c937c676ef00351244e8043908ba5b43e81 + React-RCTImage: 2413fa5ca25235b878fb2694115b26b176280f31 + React-RCTLinking: 7c821b30c5b4401037ed3da63f9580ac42b9e02e + React-RCTNetwork: a556f5005d28d99df0b577d9ef8b28f29c0ff498 + React-RCTPushNotification: c0871d7ebfd7832a5763b571f68b936772654ed3 + React-RCTSettings: 25141964d76155f25dd993b87345656a29dd0d24 + React-RCTTest: 3b9f62c66c3814ccace402441597160aefc9e812 + React-RCTText: d9925903524a7b179cf7803162a98038e0bfb4fd + React-RCTVibration: 63e015aa41be5e956440ebe8b8796f56ddd1acc8 + React-rendererconsistency: e4c6cb78c9cf114b3f3371f5e133c2db025951ef + React-rendererdebug: 0abbd75e947eeae23542f3bf7491b048ae063141 + React-rncore: e903b3d2819a25674403c548ec103f34bf02ba2b + React-RuntimeApple: b43ad6a5d60157f37ff3139e4dfb0cd6340e9be6 + React-RuntimeCore: 7cfdac312222d7260d8ba9604686fbb4aa4f8a13 + React-runtimeexecutor: e1c32bc249dd3cf3919cb4664fd8dc84ef70cff7 + React-RuntimeHermes: b19a99a600c6e1e33d7796cb91a5c76f92bd3407 + React-runtimescheduler: ca22ce34a60276d228399191dd039929cc9c6bc1 + React-utils: f5525c0072f467cf2f25bdd8dbbf0835f6384972 ReactCodegen: 23192ed6132b7eb93d61cc2ee8e21a816b361a37 - ReactCommon: b2b96bdfe39947d7b405e8ce6960c48b27b990b1 - ReactCommon-Samples: 234c8bfe932143313078569f55a22e38694f29ba - ScreenshotManager: ef3c2c6427fecb146407d8d89f44b73188042ef7 + ReactCommon: 37e362e6877a42d74cc3d71be3d15a73f5f8c8ff + ReactCommon-Samples: e2bf03c8237c461fa36bda8e4638368fa82b633c + ScreenshotManager: 16fcf9cbbee5b261ac46641a0f502fc1cb73a089 SocketRocket: abac6f5de4d4d62d24e11868d7a2f427e0ef940d - Yoga: a45d814f9cf447ad53f4b404385c75be3e46a120 + Yoga: f58ba5e0ac1e7eb3ef4caedcf80c5aa39985b039 -PODFILE CHECKSUM: 8591f96a513620a2a83a0b9a125ad3fa32ea1369 +PODFILE CHECKSUM: 60b84dd598fc04e9ed84dbc82e2cb3b99b1d7adf -COCOAPODS: 1.15.2 +COCOAPODS: 1.14.3 From 5e829208a775b0e93c5fa26a566095ebf965a4b3 Mon Sep 17 00:00:00 2001 From: Abdelhafidh Belalia <16493223+s77rt@users.noreply.github.com> Date: Thu, 25 Jul 2024 18:21:57 +0100 Subject: [PATCH 12/18] iOS: Support image pasting --- .../Text/TextInput/Multiline/RCTUITextView.mm | 48 ++++++++++++++++++- .../TextInput/Singleline/RCTUITextField.mm | 48 ++++++++++++++++++- 2 files changed, 92 insertions(+), 4 deletions(-) diff --git a/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm b/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm index 556b0ba935af8f..c14ce52087bd7c 100644 --- a/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm +++ b/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm @@ -175,8 +175,48 @@ - (void)paste:(id)sender { _textWasPasted = YES; UIPasteboard *clipboard = [UIPasteboard generalPasteboard]; - [_textInputDelegateAdapter didPaste:@"text/plain" withData:clipboard.string]; - [super paste:sender]; + if (clipboard.hasImages) { + NSArray *clipboardTypes = [clipboard pasteboardTypes]; + if ([clipboardTypes containsObject:@"com.compuserve.gif"]) { + NSString *type = @"image/gif"; + NSString *encodedData = [[clipboard dataForPasteboardType:@"com.compuserve.gif"] base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; + NSString *data = [NSString stringWithFormat:@"data:%@;base64,%@", type, encodedData]; + [_textInputDelegateAdapter didPaste:type withData:data]; + } else if ([clipboardTypes containsObject:@"public.png"]) { + NSString *type = @"image/png"; + NSString *encodedData = [[clipboard dataForPasteboardType:@"public.png"] base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; + NSString *data = [NSString stringWithFormat:@"data:%@;base64,%@", type, encodedData]; + [_textInputDelegateAdapter didPaste:type withData:data]; + } else if ([clipboardTypes containsObject:@"public.jpeg"]) { + NSString *type = @"image/jpeg"; + NSString *encodedData = [[clipboard dataForPasteboardType:@"public.jpeg"] base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; + NSString *data = [NSString stringWithFormat:@"data:%@;base64,%@", type, encodedData]; + [_textInputDelegateAdapter didPaste:type withData:data]; + } else if ([clipboardTypes containsObject:@"org.webmproject.webp"]) { + NSString *type = @"image/webp"; + NSString *encodedData = [[clipboard dataForPasteboardType:@"org.webmproject.webp"] base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; + NSString *data = [NSString stringWithFormat:@"data:%@;base64,%@", type, encodedData]; + [_textInputDelegateAdapter didPaste:type withData:data]; + } else if ([clipboardTypes containsObject:@"public.tiff"]) { + NSString *type = @"image/tiff"; + NSString *encodedData = [[clipboard dataForPasteboardType:@"public.tiff"] base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; + NSString *data = [NSString stringWithFormat:@"data:%@;base64,%@", type, encodedData]; + [_textInputDelegateAdapter didPaste:type withData:data]; + } else if ([clipboardTypes containsObject:@"com.microsoft.bmp"]) { + NSString *type = @"image/bmp"; + NSString *encodedData = [[clipboard dataForPasteboardType:@"com.microsoft.bmp"] base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; + NSString *data = [NSString stringWithFormat:@"data:%@;base64,%@", type, encodedData]; + [_textInputDelegateAdapter didPaste:type withData:data]; + } else if ([clipboardTypes containsObject:@"public.svg-image"]) { + NSString *type = @"image/svg+xml"; + NSString *encodedData = [[clipboard dataForPasteboardType:@"public.svg-image"] base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; + NSString *data = [NSString stringWithFormat:@"data:%@;base64,%@", type, encodedData]; + [_textInputDelegateAdapter didPaste:type withData:data]; + } + } else { + [_textInputDelegateAdapter didPaste:@"text/plain" withData:clipboard.string]; + [super paste:sender]; + } } // Turn off scroll animation to fix flaky scrolling. @@ -268,6 +308,10 @@ - (BOOL)canPerformAction:(SEL)action withSender:(id)sender return NO; } + if (action == @selector(paste:) && [UIPasteboard generalPasteboard].hasImages) { + return YES; + } + return [super canPerformAction:action withSender:sender]; } diff --git a/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm b/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm index 7d524d2076a4bc..1a34211c57b321 100644 --- a/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm +++ b/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm @@ -141,6 +141,10 @@ - (BOOL)canPerformAction:(SEL)action withSender:(id)sender return NO; } + if (action == @selector(paste:) && [UIPasteboard generalPasteboard].hasImages) { + return YES; + } + return [super canPerformAction:action withSender:sender]; } @@ -225,8 +229,48 @@ - (void)paste:(id)sender { _textWasPasted = YES; UIPasteboard *clipboard = [UIPasteboard generalPasteboard]; - [_textInputDelegateAdapter didPaste:@"text/plain" withData:clipboard.string]; - [super paste:sender]; + if (clipboard.hasImages) { + NSArray *clipboardTypes = [clipboard pasteboardTypes]; + if ([clipboardTypes containsObject:@"com.compuserve.gif"]) { + NSString *type = @"image/gif"; + NSString *encodedData = [[clipboard dataForPasteboardType:@"com.compuserve.gif"] base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; + NSString *data = [NSString stringWithFormat:@"data:%@;base64,%@", type, encodedData]; + [_textInputDelegateAdapter didPaste:type withData:data]; + } else if ([clipboardTypes containsObject:@"public.png"]) { + NSString *type = @"image/png"; + NSString *encodedData = [[clipboard dataForPasteboardType:@"public.png"] base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; + NSString *data = [NSString stringWithFormat:@"data:%@;base64,%@", type, encodedData]; + [_textInputDelegateAdapter didPaste:type withData:data]; + } else if ([clipboardTypes containsObject:@"public.jpeg"]) { + NSString *type = @"image/jpeg"; + NSString *encodedData = [[clipboard dataForPasteboardType:@"public.jpeg"] base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; + NSString *data = [NSString stringWithFormat:@"data:%@;base64,%@", type, encodedData]; + [_textInputDelegateAdapter didPaste:type withData:data]; + } else if ([clipboardTypes containsObject:@"org.webmproject.webp"]) { + NSString *type = @"image/webp"; + NSString *encodedData = [[clipboard dataForPasteboardType:@"org.webmproject.webp"] base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; + NSString *data = [NSString stringWithFormat:@"data:%@;base64,%@", type, encodedData]; + [_textInputDelegateAdapter didPaste:type withData:data]; + } else if ([clipboardTypes containsObject:@"public.tiff"]) { + NSString *type = @"image/tiff"; + NSString *encodedData = [[clipboard dataForPasteboardType:@"public.tiff"] base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; + NSString *data = [NSString stringWithFormat:@"data:%@;base64,%@", type, encodedData]; + [_textInputDelegateAdapter didPaste:type withData:data]; + } else if ([clipboardTypes containsObject:@"com.microsoft.bmp"]) { + NSString *type = @"image/bmp"; + NSString *encodedData = [[clipboard dataForPasteboardType:@"com.microsoft.bmp"] base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; + NSString *data = [NSString stringWithFormat:@"data:%@;base64,%@", type, encodedData]; + [_textInputDelegateAdapter didPaste:type withData:data]; + } else if ([clipboardTypes containsObject:@"public.svg-image"]) { + NSString *type = @"image/svg+xml"; + NSString *encodedData = [[clipboard dataForPasteboardType:@"public.svg-image"] base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; + NSString *data = [NSString stringWithFormat:@"data:%@;base64,%@", type, encodedData]; + [_textInputDelegateAdapter didPaste:type withData:data]; + } + } else { + [_textInputDelegateAdapter didPaste:@"text/plain" withData:clipboard.string]; + [super paste:sender]; + } } #pragma mark - Layout From 2fe029c24250f3e798890d1d1b9878ad0a7d7b33 Mon Sep 17 00:00:00 2001 From: Abdelhafidh Belalia <16493223+s77rt@users.noreply.github.com> Date: Sat, 27 Jul 2024 07:32:43 +0100 Subject: [PATCH 13/18] Update onPaste prop --- .../AndroidTextInputNativeComponent.js | 12 +++++- .../Components/TextInput/TextInput.d.ts | 14 ++++++- .../Components/TextInput/TextInput.flow.js | 14 ++++++- .../Components/TextInput/TextInput.js | 14 ++++++- .../__snapshots__/public-api-test.js.snap | 38 +++++++++++++++++-- .../TextInput/TextInputSharedExamples.js | 14 +++---- 6 files changed, 92 insertions(+), 14 deletions(-) diff --git a/packages/react-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js b/packages/react-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js index 6ce537e51e7ae7..f8c8c8a7919268 100644 --- a/packages/react-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js +++ b/packages/react-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js @@ -458,7 +458,17 @@ export type NativeProps = $ReadOnly<{| /** * Invoked when the user performs the paste action. */ - onPaste?: ?DirectEventHandler<$ReadOnly<{|target: Int32|}>>, + onPaste?: ?DirectEventHandler< + $ReadOnly<{| + target: Int32, + items: $ReadOnlyArray< + $ReadOnly<{| + type: string, + data: string, + |}>, + >, + |}>, + >, /** * The string that will be rendered before text input has been entered. diff --git a/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts b/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts index 0cbefdc9185b4d..eeecc3b251fe80 100644 --- a/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts +++ b/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts @@ -487,6 +487,16 @@ export interface TextInputSubmitEditingEventData { text: string; } +/** + * @see TextInputProps.onPaste + */ +export interface TextInputPasteEventData extends TargetedEvent { + items: Array<{ + type: string; + data: string; + }>; +} + /** * @see https://reactnative.dev/docs/textinput#props */ @@ -834,7 +844,9 @@ export interface TextInputProps /** * Invoked when the user performs the paste action. */ - onPaste?: ((e: NativeSyntheticEvent) => void) | undefined; + onPaste?: + | ((e: NativeSyntheticEvent) => void) + | undefined; /** * The string that will be rendered before text input has been entered diff --git a/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js b/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js index e81be957f30909..2f357310223a2f 100644 --- a/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js +++ b/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js @@ -94,6 +94,18 @@ export type EditingEvent = SyntheticEvent< |}>, >; +export type PasteEvent = SyntheticEvent< + $ReadOnly<{| + target: number, + items: $ReadOnlyArray< + $ReadOnly<{| + type: string, + data: string, + |}>, + >, + |}>, +>; + type DataDetectorTypesType = | 'phoneNumber' | 'link' @@ -815,7 +827,7 @@ export type Props = $ReadOnly<{| /** * Invoked when the user performs the paste action. */ - onPaste?: ?(e: TargetEvent) => mixed, + onPaste?: ?(e: PasteEvent) => mixed, /** * The string that will be rendered before text input has been entered. diff --git a/packages/react-native/Libraries/Components/TextInput/TextInput.js b/packages/react-native/Libraries/Components/TextInput/TextInput.js index c480423afd6fe0..a8ba5715d1a4f6 100644 --- a/packages/react-native/Libraries/Components/TextInput/TextInput.js +++ b/packages/react-native/Libraries/Components/TextInput/TextInput.js @@ -133,6 +133,18 @@ export type EditingEvent = SyntheticEvent< |}>, >; +export type PasteEvent = SyntheticEvent< + $ReadOnly<{| + target: number, + items: $ReadOnlyArray< + $ReadOnly<{| + type: string, + data: string, + |}>, + >, + |}>, +>; + type DataDetectorTypesType = | 'phoneNumber' | 'link' @@ -814,7 +826,7 @@ export type Props = $ReadOnly<{| /** * Invoked when the user performs the paste action. */ - onPaste?: ?(e: TargetEvent) => mixed, + onPaste?: ?(e: PasteEvent) => mixed, /** * The string that will be rendered before text input has been entered. diff --git a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap index 0613592ff1b70c..ffe9e17ae8f14e 100644 --- a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap +++ b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap @@ -2783,7 +2783,17 @@ export type NativeProps = $ReadOnly<{| |}>, |}>, >, - onPaste?: ?DirectEventHandler<$ReadOnly<{| target: Int32 |}>>, + onPaste?: ?DirectEventHandler< + $ReadOnly<{| + target: Int32, + items: $ReadOnlyArray< + $ReadOnly<{| + type: string, + data: string, + |}>, + >, + |}>, + >, placeholder?: ?Stringish, placeholderTextColor?: ?ColorValue, secureTextEntry?: ?boolean, @@ -2937,6 +2947,17 @@ export type EditingEvent = SyntheticEvent< target: number, |}>, >; +export type PasteEvent = SyntheticEvent< + $ReadOnly<{| + target: number, + items: $ReadOnlyArray< + $ReadOnly<{| + type: string, + data: string, + |}>, + >, + |}>, +>; type DataDetectorTypesType = | \\"phoneNumber\\" | \\"link\\" @@ -3171,7 +3192,7 @@ export type Props = $ReadOnly<{| onSelectionChange?: ?(e: SelectionChangeEvent) => mixed, onSubmitEditing?: ?(e: EditingEvent) => mixed, onScroll?: ?(e: ScrollEvent) => mixed, - onPaste?: ?(e: TargetEvent) => mixed, + onPaste?: ?(e: PasteEvent) => mixed, placeholder?: ?Stringish, placeholderTextColor?: ?ColorValue, readOnly?: ?boolean, @@ -3283,6 +3304,17 @@ export type EditingEvent = SyntheticEvent< target: number, |}>, >; +export type PasteEvent = SyntheticEvent< + $ReadOnly<{| + target: number, + items: $ReadOnlyArray< + $ReadOnly<{| + type: string, + data: string, + |}>, + >, + |}>, +>; type DataDetectorTypesType = | \\"phoneNumber\\" | \\"link\\" @@ -3511,7 +3543,7 @@ export type Props = $ReadOnly<{| onSelectionChange?: ?(e: SelectionChangeEvent) => mixed, onSubmitEditing?: ?(e: EditingEvent) => mixed, onScroll?: ?(e: ScrollEvent) => mixed, - onPaste?: ?(e: TargetEvent) => mixed, + onPaste?: ?(e: PasteEvent) => mixed, placeholder?: ?Stringish, placeholderTextColor?: ?ColorValue, readOnly?: ?boolean, diff --git a/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js b/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js index b4ba633070e436..34c273b18f06d6 100644 --- a/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js +++ b/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js @@ -853,24 +853,24 @@ function MultilineStyledTextInput({ function PasteboardTextInput() { const [pasteboard, setPasteboard] = useState(null); const {type, data} = pasteboard?.items[0] ?? {}; - const isText = type === "text/plain" - const isImage = type && type.startsWith("image/"); + const isText = type === 'text/plain'; + const isImage = type && type.startsWith('image/'); return ( setPasteboard(event.nativeEvent)} placeholder="Paste text or image" - multiline={true}> - + multiline={true} + /> {type && ( - {"Type: " + type} + {'Type: ' + type} )} {isText && ( - {"Data: " + data} + {'Data: ' + data} )} {isImage && ( - + )} ); From 401d59756711d53939353793709709d8e155338d Mon Sep 17 00:00:00 2001 From: Abdelhafidh Belalia <16493223+s77rt@users.noreply.github.com> Date: Sat, 27 Jul 2024 08:35:09 +0100 Subject: [PATCH 14/18] fix flow check --- .../TextInput/TextInputSharedExamples.js | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js b/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js index 34c273b18f06d6..0b3d9ceae3cc18 100644 --- a/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js +++ b/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js @@ -12,6 +12,7 @@ import type {RNTesterModuleExample} from '../../types/RNTesterTypes'; import type {TextStyle} from 'react-native/Libraries/StyleSheet/StyleSheet'; +import type {PasteEvent} from 'react-native/Libraries/Components/TextInput/TextInput'; import RNTesterButton from '../../components/RNTesterButton'; import {RNTesterThemeContext} from '../../components/RNTesterTheme'; @@ -851,26 +852,25 @@ function MultilineStyledTextInput({ } function PasteboardTextInput() { - const [pasteboard, setPasteboard] = useState(null); - const {type, data} = pasteboard?.items[0] ?? {}; - const isText = type === 'text/plain'; - const isImage = type && type.startsWith('image/'); + const [pasteEvent, setPasteEvent] = useState(); + const content = pasteEvent?.items[0]; return ( setPasteboard(event.nativeEvent)} + onPaste={event => setPasteEvent(event.nativeEvent)} placeholder="Paste text or image" multiline={true} /> - {type && ( - {'Type: ' + type} - )} - {isText && ( - {'Data: ' + data} - )} - {isImage && ( - + {content && ( + <> + {'Type: ' + content.type} + {content.type.startsWith('text/') ? ( + {'Data: ' + content.data} + ) : content.type.startsWith('image/') ? ( + + ) : null} + )} ); From df52d5c331ff6335c884711c0e1d2cb44e762b61 Mon Sep 17 00:00:00 2001 From: Abdelhafidh Belalia <16493223+s77rt@users.noreply.github.com> Date: Sat, 27 Jul 2024 08:43:29 +0100 Subject: [PATCH 15/18] format --- .../TextInput/TextInputSharedExamples.js | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js b/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js index 0b3d9ceae3cc18..458159a390b94a 100644 --- a/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js +++ b/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js @@ -11,8 +11,8 @@ 'use strict'; import type {RNTesterModuleExample} from '../../types/RNTesterTypes'; -import type {TextStyle} from 'react-native/Libraries/StyleSheet/StyleSheet'; import type {PasteEvent} from 'react-native/Libraries/Components/TextInput/TextInput'; +import type {TextStyle} from 'react-native/Libraries/StyleSheet/StyleSheet'; import RNTesterButton from '../../components/RNTesterButton'; import {RNTesterThemeContext} from '../../components/RNTesterTheme'; @@ -864,12 +864,21 @@ function PasteboardTextInput() { /> {content && ( <> - {'Type: ' + content.type} - {content.type.startsWith('text/') ? ( - {'Data: ' + content.data} - ) : content.type.startsWith('image/') ? ( - - ) : null} + {'Type: ' + content.type} + {content.type.startsWith('text/') ? ( + {'Data: ' + content.data} + ) : content.type.startsWith('image/') ? ( + + ) : null} )} From 8bf252a13b44d64e961735b791b017de1e72a4d7 Mon Sep 17 00:00:00 2001 From: Abdelhafidh Belalia <16493223+s77rt@users.noreply.github.com> Date: Mon, 5 Aug 2024 23:55:26 +0100 Subject: [PATCH 16/18] Pass URI instead of base64 encoded data for files --- .../Text/TextInput/Multiline/RCTUITextView.mm | 56 +++++++------------ .../TextInput/Singleline/RCTUITextField.mm | 56 +++++++------------ .../react/views/textinput/ReactEditText.java | 11 +--- 3 files changed, 39 insertions(+), 84 deletions(-) diff --git a/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm b/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm index c14ce52087bd7c..6fdd4b7eb60909 100644 --- a/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm +++ b/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm @@ -13,6 +13,7 @@ #import #import +#import #import @implementation RCTUITextView { @@ -176,45 +177,26 @@ - (void)paste:(id)sender _textWasPasted = YES; UIPasteboard *clipboard = [UIPasteboard generalPasteboard]; if (clipboard.hasImages) { - NSArray *clipboardTypes = [clipboard pasteboardTypes]; - if ([clipboardTypes containsObject:@"com.compuserve.gif"]) { - NSString *type = @"image/gif"; - NSString *encodedData = [[clipboard dataForPasteboardType:@"com.compuserve.gif"] base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; - NSString *data = [NSString stringWithFormat:@"data:%@;base64,%@", type, encodedData]; - [_textInputDelegateAdapter didPaste:type withData:data]; - } else if ([clipboardTypes containsObject:@"public.png"]) { - NSString *type = @"image/png"; - NSString *encodedData = [[clipboard dataForPasteboardType:@"public.png"] base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; - NSString *data = [NSString stringWithFormat:@"data:%@;base64,%@", type, encodedData]; - [_textInputDelegateAdapter didPaste:type withData:data]; - } else if ([clipboardTypes containsObject:@"public.jpeg"]) { - NSString *type = @"image/jpeg"; - NSString *encodedData = [[clipboard dataForPasteboardType:@"public.jpeg"] base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; - NSString *data = [NSString stringWithFormat:@"data:%@;base64,%@", type, encodedData]; - [_textInputDelegateAdapter didPaste:type withData:data]; - } else if ([clipboardTypes containsObject:@"org.webmproject.webp"]) { - NSString *type = @"image/webp"; - NSString *encodedData = [[clipboard dataForPasteboardType:@"org.webmproject.webp"] base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; - NSString *data = [NSString stringWithFormat:@"data:%@;base64,%@", type, encodedData]; - [_textInputDelegateAdapter didPaste:type withData:data]; - } else if ([clipboardTypes containsObject:@"public.tiff"]) { - NSString *type = @"image/tiff"; - NSString *encodedData = [[clipboard dataForPasteboardType:@"public.tiff"] base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; - NSString *data = [NSString stringWithFormat:@"data:%@;base64,%@", type, encodedData]; - [_textInputDelegateAdapter didPaste:type withData:data]; - } else if ([clipboardTypes containsObject:@"com.microsoft.bmp"]) { - NSString *type = @"image/bmp"; - NSString *encodedData = [[clipboard dataForPasteboardType:@"com.microsoft.bmp"] base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; - NSString *data = [NSString stringWithFormat:@"data:%@;base64,%@", type, encodedData]; - [_textInputDelegateAdapter didPaste:type withData:data]; - } else if ([clipboardTypes containsObject:@"public.svg-image"]) { - NSString *type = @"image/svg+xml"; - NSString *encodedData = [[clipboard dataForPasteboardType:@"public.svg-image"] base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; - NSString *data = [NSString stringWithFormat:@"data:%@;base64,%@", type, encodedData]; - [_textInputDelegateAdapter didPaste:type withData:data]; + for (NSItemProvider *itemProvider in [clipboard itemProviders]) { + if ([itemProvider canLoadObjectOfClass:[UIImage class]]) { + NSString *identifier = itemProvider.registeredTypeIdentifiers.firstObject; + if (identifier != nil) { + NSString *MIMEType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)identifier, kUTTagClassMIMEType); + NSString *fileExtension = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)identifier, kUTTagClassFilenameExtension); + NSString *fileName = [NSString stringWithFormat:@"%@.%@", itemProvider.suggestedName ?: @"file", fileExtension]; + NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName]; + NSURL *fileURL = [NSURL fileURLWithPath:filePath]; + NSData *fileData = [clipboard dataForPasteboardType:identifier]; + [fileData writeToFile:filePath atomically:YES]; + [_textInputDelegateAdapter didPaste:MIMEType withData:[fileURL absoluteString]]; + } + break; + } } } else { - [_textInputDelegateAdapter didPaste:@"text/plain" withData:clipboard.string]; + if (clipboard.hasStrings) { + [_textInputDelegateAdapter didPaste:@"text/plain" withData:clipboard.string]; + } [super paste:sender]; } } diff --git a/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm b/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm index 1a34211c57b321..7842501f022766 100644 --- a/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm +++ b/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm @@ -12,6 +12,7 @@ #import #import +#import #import @implementation RCTUITextField { @@ -230,45 +231,26 @@ - (void)paste:(id)sender _textWasPasted = YES; UIPasteboard *clipboard = [UIPasteboard generalPasteboard]; if (clipboard.hasImages) { - NSArray *clipboardTypes = [clipboard pasteboardTypes]; - if ([clipboardTypes containsObject:@"com.compuserve.gif"]) { - NSString *type = @"image/gif"; - NSString *encodedData = [[clipboard dataForPasteboardType:@"com.compuserve.gif"] base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; - NSString *data = [NSString stringWithFormat:@"data:%@;base64,%@", type, encodedData]; - [_textInputDelegateAdapter didPaste:type withData:data]; - } else if ([clipboardTypes containsObject:@"public.png"]) { - NSString *type = @"image/png"; - NSString *encodedData = [[clipboard dataForPasteboardType:@"public.png"] base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; - NSString *data = [NSString stringWithFormat:@"data:%@;base64,%@", type, encodedData]; - [_textInputDelegateAdapter didPaste:type withData:data]; - } else if ([clipboardTypes containsObject:@"public.jpeg"]) { - NSString *type = @"image/jpeg"; - NSString *encodedData = [[clipboard dataForPasteboardType:@"public.jpeg"] base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; - NSString *data = [NSString stringWithFormat:@"data:%@;base64,%@", type, encodedData]; - [_textInputDelegateAdapter didPaste:type withData:data]; - } else if ([clipboardTypes containsObject:@"org.webmproject.webp"]) { - NSString *type = @"image/webp"; - NSString *encodedData = [[clipboard dataForPasteboardType:@"org.webmproject.webp"] base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; - NSString *data = [NSString stringWithFormat:@"data:%@;base64,%@", type, encodedData]; - [_textInputDelegateAdapter didPaste:type withData:data]; - } else if ([clipboardTypes containsObject:@"public.tiff"]) { - NSString *type = @"image/tiff"; - NSString *encodedData = [[clipboard dataForPasteboardType:@"public.tiff"] base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; - NSString *data = [NSString stringWithFormat:@"data:%@;base64,%@", type, encodedData]; - [_textInputDelegateAdapter didPaste:type withData:data]; - } else if ([clipboardTypes containsObject:@"com.microsoft.bmp"]) { - NSString *type = @"image/bmp"; - NSString *encodedData = [[clipboard dataForPasteboardType:@"com.microsoft.bmp"] base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; - NSString *data = [NSString stringWithFormat:@"data:%@;base64,%@", type, encodedData]; - [_textInputDelegateAdapter didPaste:type withData:data]; - } else if ([clipboardTypes containsObject:@"public.svg-image"]) { - NSString *type = @"image/svg+xml"; - NSString *encodedData = [[clipboard dataForPasteboardType:@"public.svg-image"] base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; - NSString *data = [NSString stringWithFormat:@"data:%@;base64,%@", type, encodedData]; - [_textInputDelegateAdapter didPaste:type withData:data]; + for (NSItemProvider *itemProvider in [clipboard itemProviders]) { + if ([itemProvider canLoadObjectOfClass:[UIImage class]]) { + NSString *identifier = itemProvider.registeredTypeIdentifiers.firstObject; + if (identifier != nil) { + NSString *MIMEType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)identifier, kUTTagClassMIMEType); + NSString *fileExtension = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)identifier, kUTTagClassFilenameExtension); + NSString *fileName = [NSString stringWithFormat:@"%@.%@", itemProvider.suggestedName ?: @"file", fileExtension]; + NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName]; + NSURL *fileURL = [NSURL fileURLWithPath:filePath]; + NSData *fileData = [clipboard dataForPasteboardType:identifier]; + [fileData writeToFile:filePath atomically:YES]; + [_textInputDelegateAdapter didPaste:MIMEType withData:[fileURL absoluteString]]; + } + break; + } } } else { - [_textInputDelegateAdapter didPaste:@"text/plain" withData:clipboard.string]; + if (clipboard.hasStrings) { + [_textInputDelegateAdapter didPaste:@"text/plain" withData:clipboard.string]; + } [super paste:sender]; } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java index 184652bc22e5df..883fa2441891ba 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java @@ -32,7 +32,6 @@ import android.text.TextWatcher; import android.text.method.KeyListener; import android.text.method.QwertyKeyListener; -import android.util.Base64; import android.util.TypedValue; import android.view.ActionMode; import android.view.Gravity; @@ -74,7 +73,6 @@ import com.facebook.react.views.text.internal.span.ReactUnderlineSpan; import com.facebook.react.views.text.internal.span.TextInlineImageSpan; import com.facebook.react.views.view.ReactViewBackgroundManager; -import java.io.IOException; import java.util.ArrayList; import java.util.Objects; @@ -346,14 +344,7 @@ public boolean onTextContextMenuItem(int id) { if (itemUri != null) { ContentResolver cr = getReactContext(this).getContentResolver(); type = cr.getType(itemUri); - if (type != null) { - try { - String encodedData = Base64.encodeToString(cr.openInputStream(itemUri).readAllBytes(), Base64.DEFAULT); - data = "data:" + type + ";base64," + encodedData; - } catch (IOException e) { - e.printStackTrace(); - } - } + data = itemUri.toString(); } } if (type != null && data != null) { From 6a2f11b08ba2eefd491afb73c315d9e5b3418f0f Mon Sep 17 00:00:00 2001 From: Abdelhafidh Belalia <16493223+s77rt@users.noreply.github.com> Date: Sat, 10 Aug 2024 06:10:04 +0100 Subject: [PATCH 17/18] use identifier that conforms to UTTypeImage --- .../Text/TextInput/Multiline/RCTUITextView.mm | 27 ++++++++++--------- .../TextInput/Singleline/RCTUITextField.mm | 27 ++++++++++--------- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm b/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm index 6fdd4b7eb60909..0c86161a26378e 100644 --- a/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm +++ b/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm @@ -13,6 +13,7 @@ #import #import +#import #import #import @@ -177,18 +178,20 @@ - (void)paste:(id)sender _textWasPasted = YES; UIPasteboard *clipboard = [UIPasteboard generalPasteboard]; if (clipboard.hasImages) { - for (NSItemProvider *itemProvider in [clipboard itemProviders]) { - if ([itemProvider canLoadObjectOfClass:[UIImage class]]) { - NSString *identifier = itemProvider.registeredTypeIdentifiers.firstObject; - if (identifier != nil) { - NSString *MIMEType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)identifier, kUTTagClassMIMEType); - NSString *fileExtension = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)identifier, kUTTagClassFilenameExtension); - NSString *fileName = [NSString stringWithFormat:@"%@.%@", itemProvider.suggestedName ?: @"file", fileExtension]; - NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName]; - NSURL *fileURL = [NSURL fileURLWithPath:filePath]; - NSData *fileData = [clipboard dataForPasteboardType:identifier]; - [fileData writeToFile:filePath atomically:YES]; - [_textInputDelegateAdapter didPaste:MIMEType withData:[fileURL absoluteString]]; + for (NSItemProvider *itemProvider in clipboard.itemProviders) { + if ([itemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeImage]) { + for (NSString *identifier in itemProvider.registeredTypeIdentifiers) { + if (UTTypeConformsTo((__bridge CFStringRef)identifier, kUTTypeImage)) { + NSString *MIMEType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)identifier, kUTTagClassMIMEType); + NSString *fileExtension = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)identifier, kUTTagClassFilenameExtension); + NSString *fileName = [NSString stringWithFormat:@"%@.%@", itemProvider.suggestedName ?: @"file", fileExtension]; + NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName]; + NSURL *fileURL = [NSURL fileURLWithPath:filePath]; + NSData *fileData = [clipboard dataForPasteboardType:identifier]; + [fileData writeToFile:filePath atomically:YES]; + [_textInputDelegateAdapter didPaste:MIMEType withData:[fileURL absoluteString]]; + break; + } } break; } diff --git a/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm b/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm index 7842501f022766..bb10f1cbbad7c8 100644 --- a/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm +++ b/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm @@ -12,6 +12,7 @@ #import #import +#import #import #import @@ -231,18 +232,20 @@ - (void)paste:(id)sender _textWasPasted = YES; UIPasteboard *clipboard = [UIPasteboard generalPasteboard]; if (clipboard.hasImages) { - for (NSItemProvider *itemProvider in [clipboard itemProviders]) { - if ([itemProvider canLoadObjectOfClass:[UIImage class]]) { - NSString *identifier = itemProvider.registeredTypeIdentifiers.firstObject; - if (identifier != nil) { - NSString *MIMEType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)identifier, kUTTagClassMIMEType); - NSString *fileExtension = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)identifier, kUTTagClassFilenameExtension); - NSString *fileName = [NSString stringWithFormat:@"%@.%@", itemProvider.suggestedName ?: @"file", fileExtension]; - NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName]; - NSURL *fileURL = [NSURL fileURLWithPath:filePath]; - NSData *fileData = [clipboard dataForPasteboardType:identifier]; - [fileData writeToFile:filePath atomically:YES]; - [_textInputDelegateAdapter didPaste:MIMEType withData:[fileURL absoluteString]]; + for (NSItemProvider *itemProvider in clipboard.itemProviders) { + if ([itemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeImage]) { + for (NSString *identifier in itemProvider.registeredTypeIdentifiers) { + if (UTTypeConformsTo((__bridge CFStringRef)identifier, kUTTypeImage)) { + NSString *MIMEType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)identifier, kUTTagClassMIMEType); + NSString *fileExtension = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)identifier, kUTTagClassFilenameExtension); + NSString *fileName = [NSString stringWithFormat:@"%@.%@", itemProvider.suggestedName ?: @"file", fileExtension]; + NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName]; + NSURL *fileURL = [NSURL fileURLWithPath:filePath]; + NSData *fileData = [clipboard dataForPasteboardType:identifier]; + [fileData writeToFile:filePath atomically:YES]; + [_textInputDelegateAdapter didPaste:MIMEType withData:[fileURL absoluteString]]; + break; + } } break; } From 01e75217f74cf20836413e9f87f6cc08299f8b34 Mon Sep 17 00:00:00 2001 From: Abdelhafidh Belalia <16493223+s77rt@users.noreply.github.com> Date: Sat, 10 Aug 2024 23:06:25 +0100 Subject: [PATCH 18/18] iOS: Use unique filename on paste --- .../Libraries/Text/TextInput/Multiline/RCTUITextView.mm | 2 +- .../Libraries/Text/TextInput/Singleline/RCTUITextField.mm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm b/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm index 0c86161a26378e..a11679a1153ef0 100644 --- a/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm +++ b/packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm @@ -184,7 +184,7 @@ - (void)paste:(id)sender if (UTTypeConformsTo((__bridge CFStringRef)identifier, kUTTypeImage)) { NSString *MIMEType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)identifier, kUTTagClassMIMEType); NSString *fileExtension = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)identifier, kUTTagClassFilenameExtension); - NSString *fileName = [NSString stringWithFormat:@"%@.%@", itemProvider.suggestedName ?: @"file", fileExtension]; + NSString *fileName = [NSString stringWithFormat:@"%@.%@", [[NSUUID UUID] UUIDString], fileExtension]; NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName]; NSURL *fileURL = [NSURL fileURLWithPath:filePath]; NSData *fileData = [clipboard dataForPasteboardType:identifier]; diff --git a/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm b/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm index bb10f1cbbad7c8..bb165d72d919c8 100644 --- a/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm +++ b/packages/react-native/Libraries/Text/TextInput/Singleline/RCTUITextField.mm @@ -238,7 +238,7 @@ - (void)paste:(id)sender if (UTTypeConformsTo((__bridge CFStringRef)identifier, kUTTypeImage)) { NSString *MIMEType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)identifier, kUTTagClassMIMEType); NSString *fileExtension = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)identifier, kUTTagClassFilenameExtension); - NSString *fileName = [NSString stringWithFormat:@"%@.%@", itemProvider.suggestedName ?: @"file", fileExtension]; + NSString *fileName = [NSString stringWithFormat:@"%@.%@", [[NSUUID UUID] UUIDString], fileExtension]; NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName]; NSURL *fileURL = [NSURL fileURLWithPath:filePath]; NSData *fileData = [clipboard dataForPasteboardType:identifier];