diff --git a/Libraries/ART/ART.xcodeproj/project.pbxproj b/Libraries/ART/ART.xcodeproj/project.pbxproj index 16272a5d1d..9dcf59b154 100644 --- a/Libraries/ART/ART.xcodeproj/project.pbxproj +++ b/Libraries/ART/ART.xcodeproj/project.pbxproj @@ -25,24 +25,6 @@ 0CF68B141AF0549300FF9E5C /* ARTShapeManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68B001AF0549300FF9E5C /* ARTShapeManager.m */; }; 0CF68B151AF0549300FF9E5C /* ARTSurfaceViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68B021AF0549300FF9E5C /* ARTSurfaceViewManager.m */; }; 0CF68B161AF0549300FF9E5C /* ARTTextManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68B041AF0549300FF9E5C /* ARTTextManager.m */; }; - 325CF7AD1E5F2ABA00AC9606 /* ARTBrush.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AEC1AF0549300FF9E5C /* ARTBrush.m */; }; - 325CF7AE1E5F2ABA00AC9606 /* ARTLinearGradient.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AEE1AF0549300FF9E5C /* ARTLinearGradient.m */; }; - 325CF7AF1E5F2ABA00AC9606 /* ARTPattern.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AF01AF0549300FF9E5C /* ARTPattern.m */; }; - 325CF7B01E5F2ABA00AC9606 /* ARTRadialGradient.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AF21AF0549300FF9E5C /* ARTRadialGradient.m */; }; - 325CF7B11E5F2ABA00AC9606 /* ARTSolidColor.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AF41AF0549300FF9E5C /* ARTSolidColor.m */; }; - 325CF7B21E5F2ABA00AC9606 /* ARTGroupManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AFA1AF0549300FF9E5C /* ARTGroupManager.m */; }; - 325CF7B31E5F2ABA00AC9606 /* ARTNodeManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AFC1AF0549300FF9E5C /* ARTNodeManager.m */; }; - 325CF7B41E5F2ABA00AC9606 /* ARTRenderableManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AFE1AF0549300FF9E5C /* ARTRenderableManager.m */; }; - 325CF7B51E5F2ABA00AC9606 /* ARTShapeManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68B001AF0549300FF9E5C /* ARTShapeManager.m */; }; - 325CF7B61E5F2ABA00AC9606 /* ARTSurfaceViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68B021AF0549300FF9E5C /* ARTSurfaceViewManager.m */; }; - 325CF7B71E5F2ABA00AC9606 /* ARTTextManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68B041AF0549300FF9E5C /* ARTTextManager.m */; }; - 325CF7B81E5F2ABA00AC9606 /* ARTGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68ADE1AF0549300FF9E5C /* ARTGroup.m */; }; - 325CF7B91E5F2ABA00AC9606 /* ARTNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AE01AF0549300FF9E5C /* ARTNode.m */; }; - 325CF7BA1E5F2ABA00AC9606 /* ARTRenderable.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AE21AF0549300FF9E5C /* ARTRenderable.m */; }; - 325CF7BB1E5F2ABA00AC9606 /* ARTShape.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AE41AF0549300FF9E5C /* ARTShape.m */; }; - 325CF7BC1E5F2ABA00AC9606 /* ARTSurfaceView.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AE61AF0549300FF9E5C /* ARTSurfaceView.m */; }; - 325CF7BD1E5F2ABA00AC9606 /* ARTText.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AE81AF0549300FF9E5C /* ARTText.m */; }; - 325CF7BE1E5F2ABA00AC9606 /* RCTConvert+ART.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AF71AF0549300FF9E5C /* RCTConvert+ART.m */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -55,15 +37,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 323A12851E5F266B004975B8 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = "include/$(PRODUCT_NAME)"; - dstSubfolderSpec = 16; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ @@ -107,7 +80,6 @@ 0CF68B021AF0549300FF9E5C /* ARTSurfaceViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTSurfaceViewManager.m; sourceTree = ""; }; 0CF68B031AF0549300FF9E5C /* ARTTextManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTTextManager.h; sourceTree = ""; }; 0CF68B041AF0549300FF9E5C /* ARTTextManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTTextManager.m; sourceTree = ""; }; - 323A12871E5F266B004975B8 /* libART-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libART-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -118,13 +90,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 323A12841E5F266B004975B8 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -161,7 +126,6 @@ isa = PBXGroup; children = ( 0CF68AC11AF0540F00FF9E5C /* libART.a */, - 323A12871E5F266B004975B8 /* libART-tvOS.a */, ); name = Products; sourceTree = ""; @@ -222,23 +186,6 @@ productReference = 0CF68AC11AF0540F00FF9E5C /* libART.a */; productType = "com.apple.product-type.library.static"; }; - 323A12861E5F266B004975B8 /* ART-tvOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 323A128D1E5F266B004975B8 /* Build configuration list for PBXNativeTarget "ART-tvOS" */; - buildPhases = ( - 323A12831E5F266B004975B8 /* Sources */, - 323A12841E5F266B004975B8 /* Frameworks */, - 323A12851E5F266B004975B8 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "ART-tvOS"; - productName = "ART-tvOS"; - productReference = 323A12871E5F266B004975B8 /* libART-tvOS.a */; - productType = "com.apple.product-type.library.static"; - }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -250,10 +197,6 @@ 0CF68AC01AF0540F00FF9E5C = { CreatedOnToolsVersion = 6.2; }; - 323A12861E5F266B004975B8 = { - CreatedOnToolsVersion = 6.2; - ProvisioningStyle = Automatic; - }; }; }; buildConfigurationList = 0CF68ABC1AF0540F00FF9E5C /* Build configuration list for PBXProject "ART" */; @@ -269,7 +212,6 @@ projectRoot = ""; targets = ( 0CF68AC01AF0540F00FF9E5C /* ART */, - 323A12861E5F266B004975B8 /* ART-tvOS */, ); }; /* End PBXProject section */ @@ -300,31 +242,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 323A12831E5F266B004975B8 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 325CF7B71E5F2ABA00AC9606 /* ARTTextManager.m in Sources */, - 325CF7B21E5F2ABA00AC9606 /* ARTGroupManager.m in Sources */, - 325CF7AF1E5F2ABA00AC9606 /* ARTPattern.m in Sources */, - 325CF7BD1E5F2ABA00AC9606 /* ARTText.m in Sources */, - 325CF7B31E5F2ABA00AC9606 /* ARTNodeManager.m in Sources */, - 325CF7B81E5F2ABA00AC9606 /* ARTGroup.m in Sources */, - 325CF7B41E5F2ABA00AC9606 /* ARTRenderableManager.m in Sources */, - 325CF7BC1E5F2ABA00AC9606 /* ARTSurfaceView.m in Sources */, - 325CF7B01E5F2ABA00AC9606 /* ARTRadialGradient.m in Sources */, - 325CF7B61E5F2ABA00AC9606 /* ARTSurfaceViewManager.m in Sources */, - 325CF7BB1E5F2ABA00AC9606 /* ARTShape.m in Sources */, - 325CF7BA1E5F2ABA00AC9606 /* ARTRenderable.m in Sources */, - 325CF7BE1E5F2ABA00AC9606 /* RCTConvert+ART.m in Sources */, - 325CF7B91E5F2ABA00AC9606 /* ARTNode.m in Sources */, - 325CF7B11E5F2ABA00AC9606 /* ARTSolidColor.m in Sources */, - 325CF7AE1E5F2ABA00AC9606 /* ARTLinearGradient.m in Sources */, - 325CF7AD1E5F2ABA00AC9606 /* ARTBrush.m in Sources */, - 325CF7B51E5F2ABA00AC9606 /* ARTShapeManager.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ @@ -424,41 +341,6 @@ }; name = Release; }; - 323A128E1E5F266B004975B8 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_TESTABILITY = YES; - GCC_NO_COMMON_BLOCKS = YES; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = appletvos; - SKIP_INSTALL = YES; - TVOS_DEPLOYMENT_TARGET = 9.2; - }; - name = Debug; - }; - 323A128F1E5F266B004975B8 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - GCC_NO_COMMON_BLOCKS = YES; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = appletvos; - SKIP_INSTALL = YES; - TVOS_DEPLOYMENT_TARGET = 9.2; - }; - name = Release; - }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -480,15 +362,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 323A128D1E5F266B004975B8 /* Build configuration list for PBXNativeTarget "ART-tvOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 323A128E1E5F266B004975B8 /* Debug */, - 323A128F1E5F266B004975B8 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; /* End XCConfigurationList section */ }; rootObject = 0CF68AB91AF0540F00FF9E5C /* Project object */; diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js index 0ecb7f466e..b882151146 100644 --- a/Libraries/Components/TextInput/TextInput.js +++ b/Libraries/Components/TextInput/TextInput.js @@ -8,6 +8,7 @@ * * @providesModule TextInput * @flow + * @format */ 'use strict'; @@ -21,7 +22,6 @@ const createReactClass = require('create-react-class'); const PropTypes = require('prop-types'); const NativeModules = require('NativeModules'); const ReactNative = require('ReactNative'); -const StyleSheet = require('StyleSheet'); const Text = require('Text'); const TextInputState = require('TextInputState'); /* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error @@ -31,6 +31,7 @@ const TimerMixin = require('react-timer-mixin'); const TouchableWithoutFeedback = require('TouchableWithoutFeedback'); const UIManager = require('UIManager'); const ViewPropTypes = require('ViewPropTypes'); +const {ViewContextTypes} = require('ViewContext'); /* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error * found when Flow v0.54 was deployed. To see the error delete this comment and @@ -48,12 +49,19 @@ const onlyMultiline = { children: true, }; +import type {ViewChildContext} from 'ViewContext'; + if (Platform.OS === 'android') { var AndroidTextInput = requireNativeComponent('AndroidTextInput', null); } else if (Platform.OS === 'ios' || Platform.OS === 'macos') { - var RCTMultilineTextInputView = requireNativeComponent('RCTMultilineTextInputView', null); - var RCTSinglelineTextInputView = requireNativeComponent('RCTTextField', null); - var RCTSecureTextField = requireNativeComponent('RCTSecureTextField', null); + var RCTMultilineTextInputView = requireNativeComponent( + 'RCTMultilineTextInputView', + null, + ); + var RCTSinglelineTextInputView = requireNativeComponent( + 'RCTSinglelineTextInputView', + null, + ); } type Event = Object; @@ -389,8 +397,8 @@ const TextInput = createReactClass({ */ password: PropTypes.bool, /** - * The highlight and cursor color of the text input. - */ + * The highlight and cursor color of the text input. + */ selectionColor: ColorPropType, /** * An instance of `DocumentSelectionState`, this is some state that is responsible for @@ -551,11 +559,6 @@ const TextInput = createReactClass({ ); }, - contextTypes: { - onFocusRequested: PropTypes.func, - focusEmitter: PropTypes.instanceOf(EventEmitter), - }, - _inputRef: (undefined: any), _focusSubscription: (undefined: ?Function), _lastNativeText: (undefined: ?string), @@ -577,7 +580,7 @@ const TextInput = createReactClass({ } else if (this.isFocused()) { this.blur(); } - } + }, ); if (this.props.autoFocus) { this.context.onFocusRequested(this); @@ -591,24 +594,32 @@ const TextInput = createReactClass({ } }, - getChildContext: function(): Object { - return { isInAParentText: true }; + getChildContext(): ViewChildContext { + return { + isInAParentText: true, + }; }, - childContextTypes: { - isInAParentText: PropTypes.bool, + childContextTypes: ViewContextTypes, + + contextTypes: { + ...ViewContextTypes, + onFocusRequested: PropTypes.func, + focusEmitter: PropTypes.instanceOf(EventEmitter), }, /** * Removes all text from the `TextInput`. */ clear: function() { - this.setNativeProps({ text: '' }); + this.setNativeProps({text: ''}); }, render: function() { if (Platform.OS === 'ios') { - return this._renderIOS(); + return UIManager.RCTVirtualText + ? this._renderIOS() + : this._renderIOSLegacy(); } else if (Platform.OS === 'macos') { return this._renderIOS(); } else if (Platform.OS === 'android') { @@ -620,15 +631,15 @@ const TextInput = createReactClass({ return typeof this.props.value === 'string' ? this.props.value : typeof this.props.defaultValue === 'string' - ? this.props.defaultValue - : ''; + ? this.props.defaultValue + : ''; }, _setNativeRef: function(ref: any) { this._inputRef = ref; }, - _renderIOS: function() { + _renderIOSLegacy: function() { var textContainer; var props = Object.assign({}, this.props); @@ -648,15 +659,14 @@ const TextInput = createReactClass({ const error = new Error( 'TextInput prop `' + propKey + - '` is only supported with multiline.' + '` is only supported with multiline.', ); warning(false, '%s', error.stack); } } } - var TextField = props.password ? RCTSecureTextField : RCTSinglelineTextInputView; textContainer = ( - ++childCount); invariant( !(props.value && childCount), - 'Cannot specify both value and children.' + 'Cannot specify both value and children.', ); if (childCount >= 1) { - children = {children}; + children = ( + + {children} + + ); } if (props.inputView) { children = [children, props.inputView]; } - props.style.unshift(styles.multilineInput); textContainer = ( + ); + + return ( + + {textContainer} + + ); + }, + _renderAndroid: function() { const props = Object.assign({}, this.props); props.style = [this.props.style]; @@ -732,7 +791,7 @@ const TextInput = createReactClass({ React.Children.forEach(children, () => ++childCount); invariant( !(this.props.value && childCount), - 'Cannot specify both value and children.' + 'Cannot specify both value and children.', ); if (childCount > 1) { children = {children}; @@ -843,7 +902,7 @@ const TextInput = createReactClass({ // Selection is also a controlled prop, if the native value doesn't match // JS, update to the JS value. - const { selection } = this.props; + const {selection} = this.props; if ( this._lastNativeSelection && selection && @@ -878,13 +937,4 @@ const TextInput = createReactClass({ }, }); -var styles = StyleSheet.create({ - multilineInput: { - // This default top inset makes RCTMultilineTextInputView seem as close as possible - // to single-line RCTSinglelineTextInputView defaults, using the system defaults - // of font size 17 and a height of 31 points. - paddingTop: 5, - }, -}); - -module.exports = TextInput; +module.exports = TextInput; \ No newline at end of file diff --git a/Libraries/Components/Touchable/TouchableOpacity.js b/Libraries/Components/Touchable/TouchableOpacity.js index 7470099842..1bf17b3dc1 100644 --- a/Libraries/Components/Touchable/TouchableOpacity.js +++ b/Libraries/Components/Touchable/TouchableOpacity.js @@ -259,8 +259,10 @@ var TouchableOpacity = createReactClass({ onResponderMove={this.touchableHandleResponderMove} onResponderRelease={this.touchableHandleResponderRelease} onResponderTerminate={this.touchableHandleResponderTerminate} - onMouseEnter={this.props.onMouseEnter} - onMouseLeave={this.props.onMouseLeave} + onMouseMove={this.props.onMouseMove} + onMouseOver={this.props.onMouseOver} + onMouseOut={this.props.onMouseOut} + onContextMenu={this.props.onContextMenu} onContextMenuItemClick={this.props.onContextMenuItemClick} contextMenu={this.props.contextMenu}> {this.props.children} diff --git a/Libraries/Components/Touchable/TouchableWithoutFeedback.js b/Libraries/Components/Touchable/TouchableWithoutFeedback.js index b55f63eb42..390426fa8c 100755 --- a/Libraries/Components/Touchable/TouchableWithoutFeedback.js +++ b/Libraries/Components/Touchable/TouchableWithoutFeedback.js @@ -110,8 +110,10 @@ const TouchableWithoutFeedback = createReactClass({ * views. */ hitSlop: EdgeInsetsPropType, - onMouseEnter: PropTypes.func, - onMouseLeave: PropTypes.func, + onMouseMove: PropTypes.func, + onMouseOver: PropTypes.func, + onMouseOut: PropTypes.func, + onContextMenu: PropTypes.func, onContextMenuItemClick: PropTypes.func, contextMenu: PropTypes.array, }, @@ -213,8 +215,10 @@ const TouchableWithoutFeedback = createReactClass({ onResponderMove: this.touchableHandleResponderMove, onResponderRelease: this.touchableHandleResponderRelease, onResponderTerminate: this.touchableHandleResponderTerminate, - onMouseEnter: this.props.onMouseEnter, - onMouseLeave: this.props.onMouseLeave, + onMouseMove: this.props.onMouseMove, + onMouseOver: this.props.onMouseOver, + onMouseOut: this.props.onMouseOut, + onContextMenu: this.props.onContextMenu, onContextMenuItemClick: this.props.onContextMenuItemClick, contextMenu: this.props.contextMenu, style, diff --git a/Libraries/Components/Touchable/__tests__/__snapshots__/TouchableHighlight-test.js.snap b/Libraries/Components/Touchable/__tests__/__snapshots__/TouchableHighlight-test.js.snap index 091bc6e748..07852b5d88 100644 --- a/Libraries/Components/Touchable/__tests__/__snapshots__/TouchableHighlight-test.js.snap +++ b/Libraries/Components/Touchable/__tests__/__snapshots__/TouchableHighlight-test.js.snap @@ -11,8 +11,8 @@ exports[`TouchableHighlight renders correctly 1`] = ` isTVSelectable={true} nativeID={undefined} onLayout={undefined} - onMouseEnter={undefined} - onMouseLeave={undefined} + onMouseOver={undefined} + onMouseOut={undefined} onResponderGrant={[Function]} onResponderMove={[Function]} onResponderRelease={[Function]} diff --git a/Libraries/Components/View/ReactNativeViewAttributes.js b/Libraries/Components/View/ReactNativeViewAttributes.js index 2648ff966b..bad80fe220 100644 --- a/Libraries/Components/View/ReactNativeViewAttributes.js +++ b/Libraries/Components/View/ReactNativeViewAttributes.js @@ -30,8 +30,10 @@ ReactNativeViewAttributes.UIView = { renderToHardwareTextureAndroid: true, shouldRasterizeIOS: true, onLayout: true, - onMouseEnter: true, - onMouseLeave: true, + onMouseMove: true, + onMouseOver: true, + onMouseOut: true, + onContextMenu: true, onAccessibilityTap: true, onMagicTap: true, collapsable: true, diff --git a/Libraries/Components/View/View.js b/Libraries/Components/View/View.js index f10f183c08..83d6bbbef9 100644 --- a/Libraries/Components/View/View.js +++ b/Libraries/Components/View/View.js @@ -13,17 +13,18 @@ const NativeMethodsMixin = require('NativeMethodsMixin'); const Platform = require('Platform'); -const PropTypes = require('prop-types'); const React = require('React'); const ReactNativeStyleAttributes = require('ReactNativeStyleAttributes'); const ReactNativeViewAttributes = require('ReactNativeViewAttributes'); const ViewPropTypes = require('ViewPropTypes'); +const {ViewContextTypes} = require('ViewContext'); const createReactClass = require('create-react-class'); const invariant = require('fbjs/lib/invariant'); const requireNativeComponent = require('requireNativeComponent'); import type {ViewProps} from 'ViewPropTypes'; +import type {ViewChildContext} from 'ViewContext'; export type Props = ViewProps; @@ -52,14 +53,18 @@ const View = createReactClass({ */ viewConfig: { uiViewClassName: 'RCTView', - validAttributes: ReactNativeViewAttributes.RCTView + validAttributes: ReactNativeViewAttributes.RCTView, }, - contextTypes: { - isInAParentText: PropTypes.bool, + childContextTypes: ViewContextTypes, + + getChildContext(): ViewChildContext { + return { + isInAParentText: false, + }; }, - render: function() { + render() { invariant( !(this.context.isInAParentText && Platform.OS === 'android'), 'Nesting of within is not supported on Android.'); diff --git a/Libraries/Components/View/ViewContext.js b/Libraries/Components/View/ViewContext.js new file mode 100644 index 0000000000..ed73187b0b --- /dev/null +++ b/Libraries/Components/View/ViewContext.js @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ViewContext + * @flow + * @format + */ +'use strict'; + +const PropTypes = require('prop-types'); + +export type ViewChildContext = {| + +isInAParentText: boolean, +|}; + +export const ViewContextTypes = { + isInAParentText: PropTypes.bool, +}; diff --git a/Libraries/Components/View/ViewPropTypes.js b/Libraries/Components/View/ViewPropTypes.js index d9771b890a..1a1254b9ff 100644 --- a/Libraries/Components/View/ViewPropTypes.js +++ b/Libraries/Components/View/ViewPropTypes.js @@ -433,11 +433,13 @@ module.exports = { * Desktop specific events * @platform macos */ - onMouseEnter: PropTypes.func, - onMouseLeave: PropTypes.func, + onMouseMove: PropTypes.func, + onMouseOver: PropTypes.func, + onMouseOut: PropTypes.func, onDragEnter: PropTypes.func, onDragLeave: PropTypes.func, onDrop: PropTypes.func, + onContextMenu: PropTypes.func, onContextMenuItemClick: PropTypes.func, /** * Mapped to toolTip property of NSView. Used to show extra information when diff --git a/Libraries/Image/Image.android.js b/Libraries/Image/Image.android.js index 1105134e45..a262131060 100644 --- a/Libraries/Image/Image.android.js +++ b/Libraries/Image/Image.android.js @@ -18,23 +18,19 @@ var NativeModules = require('NativeModules'); var React = require('React'); var PropTypes = require('prop-types'); var ReactNativeViewAttributes = require('ReactNativeViewAttributes'); -var Set = require('Set'); var StyleSheet = require('StyleSheet'); var StyleSheetPropType = require('StyleSheetPropType'); -var View = require('View'); var ViewPropTypes = require('ViewPropTypes'); -var ViewStylePropTypes = require('ViewStylePropTypes'); var createReactClass = require('create-react-class'); -var filterObject = require('fbjs/lib/filterObject'); var flattenStyle = require('flattenStyle'); var merge = require('merge'); var requireNativeComponent = require('requireNativeComponent'); var resolveAssetSource = require('resolveAssetSource'); -var { - ImageLoader, -} = NativeModules; +const {ViewContextTypes} = require('ViewContext'); + +var {ImageLoader} = NativeModules; let _requestId = 1; function generateRequestId() { @@ -64,19 +60,6 @@ function generateRequestId() { * More example code in ImageExample.js */ -var ImageViewAttributes = merge(ReactNativeViewAttributes.UIView, { - src: true, - loadingIndicatorSrc: true, - resizeMethod: true, - resizeMode: true, - progressiveRenderingEnabled: true, - fadeDuration: true, - shouldNotifyLoadEvents: true, -}); - -var ViewStyleKeys = new Set(Object.keys(ViewStylePropTypes)); -var ImageSpecificStyleKeys = new Set(Object.keys(ImageStylePropTypes).filter(x => !ViewStyleKeys.has(x))); - var Image = createReactClass({ displayName: 'Image', propTypes: { @@ -254,9 +237,7 @@ var Image = createReactClass({ validAttributes: ReactNativeViewAttributes.RCTView, }, - contextTypes: { - isInAParentText: PropTypes.bool - }, + contextTypes: ViewContextTypes, render: function() { const source = resolveAssetSource(this.props.source); diff --git a/Libraries/Image/RCTImage.xcodeproj/project.pbxproj b/Libraries/Image/RCTImage.xcodeproj/project.pbxproj index fe13264c31..3420ea2545 100644 --- a/Libraries/Image/RCTImage.xcodeproj/project.pbxproj +++ b/Libraries/Image/RCTImage.xcodeproj/project.pbxproj @@ -14,23 +14,9 @@ 139A38841C4D587C00862840 /* RCTResizeMode.m in Sources */ = {isa = PBXBuildFile; fileRef = 139A38831C4D587C00862840 /* RCTResizeMode.m */; }; 13EF7F7F1BC825B1003F47DD /* RCTLocalAssetImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 13EF7F7E1BC825B1003F47DD /* RCTLocalAssetImageLoader.m */; }; 143879381AAD32A300F088A5 /* RCTImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 143879371AAD32A300F088A5 /* RCTImageLoader.m */; }; - 2D3B5F1A1D9B0D0400451313 /* RCTImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = CCD34C261D4B8FE900268922 /* RCTImageCache.m */; }; - 2D3B5F1B1D9B0D0700451313 /* RCTImageBlurUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = EEF314711C9B0DD30049118E /* RCTImageBlurUtils.m */; }; - 2D3B5F1C1D9B0D1300451313 /* RCTResizeMode.m in Sources */ = {isa = PBXBuildFile; fileRef = 139A38831C4D587C00862840 /* RCTResizeMode.m */; }; - 2D3B5F1D1D9B0D1300451313 /* RCTLocalAssetImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 13EF7F7E1BC825B1003F47DD /* RCTLocalAssetImageLoader.m */; }; - 2D3B5F1E1D9B0D1300451313 /* RCTGIFImageDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 1304D5B11AA8C50D0002E2BE /* RCTGIFImageDecoder.m */; }; - 2D3B5F1F1D9B0D1300451313 /* RCTImageEditingManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 354631671B69857700AA0B86 /* RCTImageEditingManager.m */; }; - 2D3B5F201D9B0D1300451313 /* RCTImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 143879371AAD32A300F088A5 /* RCTImageLoader.m */; }; - 2D3B5F211D9B0D1300451313 /* RCTImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1304D5A81AA8C4A30002E2BE /* RCTImageView.m */; }; - 2D3B5F221D9B0D1300451313 /* RCTImageViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1304D5AA1AA8C4A30002E2BE /* RCTImageViewManager.m */; }; - 2D3B5F231D9B0D1300451313 /* RCTImageStoreManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 35123E6A1B59C99D00EBAD80 /* RCTImageStoreManager.m */; }; - 2D3B5F241D9B0D1300451313 /* RCTImageUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 134B00A11B54232B00EC8DFB /* RCTImageUtils.m */; }; 35123E6B1B59C99D00EBAD80 /* RCTImageStoreManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 35123E6A1B59C99D00EBAD80 /* RCTImageStoreManager.m */; }; 354631681B69857700AA0B86 /* RCTImageEditingManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 354631671B69857700AA0B86 /* RCTImageEditingManager.m */; }; 3D302E181DF8228100D6DDAE /* RCTImageUtils.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 134B00A01B54232B00EC8DFB /* RCTImageUtils.h */; }; - 3D302F211DF8269200D6DDAE /* RCTImageUtils.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 134B00A01B54232B00EC8DFB /* RCTImageUtils.h */; }; - 3DA05A5A1EE0312600805843 /* RCTImageShadowView.h in Headers */ = {isa = PBXBuildFile; fileRef = 59AB09281EDE5DD1009F97B5 /* RCTImageShadowView.h */; }; - 3DA05A5B1EE0312900805843 /* RCTImageShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 59AB09291EDE5DD1009F97B5 /* RCTImageShadowView.m */; }; 3DED3A8A1DE6F79800336DD7 /* RCTGIFImageDecoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 1304D5B01AA8C50D0002E2BE /* RCTGIFImageDecoder.h */; }; 3DED3A8B1DE6F79800336DD7 /* RCTImageBlurUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = EEF314701C9B0DD30049118E /* RCTImageBlurUtils.h */; }; 3DED3A8C1DE6F79800336DD7 /* RCTImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = CCD34C251D4B8FE900268922 /* RCTImageCache.h */; }; @@ -42,17 +28,6 @@ 3DED3A921DE6F79800336DD7 /* RCTImageViewManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1304D5A91AA8C4A30002E2BE /* RCTImageViewManager.h */; }; 3DED3A931DE6F79800336DD7 /* RCTLocalAssetImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 13EF7F7D1BC825B1003F47DD /* RCTLocalAssetImageLoader.h */; }; 3DED3A941DE6F79800336DD7 /* RCTResizeMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D5FA63E1DE4B44A0058FD77 /* RCTResizeMode.h */; }; - 3DED3A961DE6F7A400336DD7 /* RCTGIFImageDecoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 1304D5B01AA8C50D0002E2BE /* RCTGIFImageDecoder.h */; }; - 3DED3A971DE6F7A400336DD7 /* RCTImageBlurUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = EEF314701C9B0DD30049118E /* RCTImageBlurUtils.h */; }; - 3DED3A981DE6F7A400336DD7 /* RCTImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = CCD34C251D4B8FE900268922 /* RCTImageCache.h */; }; - 3DED3A991DE6F7A400336DD7 /* RCTImageEditingManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 354631661B69857700AA0B86 /* RCTImageEditingManager.h */; }; - 3DED3A9A1DE6F7A400336DD7 /* RCTImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D5FA63C1DE4B44A0058FD77 /* RCTImageLoader.h */; }; - 3DED3A9B1DE6F7A400336DD7 /* RCTImageStoreManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D5FA63D1DE4B44A0058FD77 /* RCTImageStoreManager.h */; }; - 3DED3A9C1DE6F7A400336DD7 /* RCTImageUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 134B00A01B54232B00EC8DFB /* RCTImageUtils.h */; }; - 3DED3A9D1DE6F7A400336DD7 /* RCTImageView.h in Headers */ = {isa = PBXBuildFile; fileRef = 1304D5A71AA8C4A30002E2BE /* RCTImageView.h */; }; - 3DED3A9E1DE6F7A400336DD7 /* RCTImageViewManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1304D5A91AA8C4A30002E2BE /* RCTImageViewManager.h */; }; - 3DED3A9F1DE6F7A400336DD7 /* RCTLocalAssetImageLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 13EF7F7D1BC825B1003F47DD /* RCTLocalAssetImageLoader.h */; }; - 3DED3AA01DE6F7A400336DD7 /* RCTResizeMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D5FA63E1DE4B44A0058FD77 /* RCTResizeMode.h */; }; 59AB092A1EDE5DD1009F97B5 /* RCTImageShadowView.h in Headers */ = {isa = PBXBuildFile; fileRef = 59AB09281EDE5DD1009F97B5 /* RCTImageShadowView.h */; }; 59AB092B1EDE5DD1009F97B5 /* RCTImageShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 59AB09291EDE5DD1009F97B5 /* RCTImageShadowView.m */; }; CCD34C271D4B8FE900268922 /* RCTImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = CCD34C261D4B8FE900268922 /* RCTImageCache.m */; }; @@ -71,17 +46,6 @@ name = "Copy Headers"; runOnlyForDeploymentPostprocessing = 0; }; - 3D302F201DF8268700D6DDAE /* Copy Headers */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = include/RCTImage; - dstSubfolderSpec = 16; - files = ( - 3D302F211DF8269200D6DDAE /* RCTImageUtils.h in Copy Headers */, - ); - name = "Copy Headers"; - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ @@ -97,7 +61,6 @@ 13EF7F7D1BC825B1003F47DD /* RCTLocalAssetImageLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTLocalAssetImageLoader.h; sourceTree = ""; }; 13EF7F7E1BC825B1003F47DD /* RCTLocalAssetImageLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTLocalAssetImageLoader.m; sourceTree = ""; }; 143879371AAD32A300F088A5 /* RCTImageLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageLoader.m; sourceTree = ""; }; - 2D2A283A1D9B042B00D4039D /* libRCTImage-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libRCTImage-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 35123E6A1B59C99D00EBAD80 /* RCTImageStoreManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageStoreManager.m; sourceTree = ""; }; 354631661B69857700AA0B86 /* RCTImageEditingManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTImageEditingManager.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 354631671B69857700AA0B86 /* RCTImageEditingManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageEditingManager.m; sourceTree = ""; }; @@ -174,7 +137,6 @@ isa = PBXGroup; children = ( 58B5115D1A9E6B3D00147676 /* libRCTImage.a */, - 2D2A283A1D9B042B00D4039D /* libRCTImage-tvOS.a */, ); name = Products; sourceTree = ""; @@ -201,45 +163,9 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 3DED3A951DE6F79D00336DD7 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 3DED3A961DE6F7A400336DD7 /* RCTGIFImageDecoder.h in Headers */, - 3DED3A971DE6F7A400336DD7 /* RCTImageBlurUtils.h in Headers */, - 3DED3A981DE6F7A400336DD7 /* RCTImageCache.h in Headers */, - 3DED3A991DE6F7A400336DD7 /* RCTImageEditingManager.h in Headers */, - 3DED3A9A1DE6F7A400336DD7 /* RCTImageLoader.h in Headers */, - 3DED3A9B1DE6F7A400336DD7 /* RCTImageStoreManager.h in Headers */, - 3DED3A9C1DE6F7A400336DD7 /* RCTImageUtils.h in Headers */, - 3DA05A5A1EE0312600805843 /* RCTImageShadowView.h in Headers */, - 3DED3A9D1DE6F7A400336DD7 /* RCTImageView.h in Headers */, - 3DED3A9E1DE6F7A400336DD7 /* RCTImageViewManager.h in Headers */, - 3DED3A9F1DE6F7A400336DD7 /* RCTLocalAssetImageLoader.h in Headers */, - 3DED3AA01DE6F7A400336DD7 /* RCTResizeMode.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ - 2D2A28391D9B042B00D4039D /* RCTImage-tvOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 2D2A28421D9B042B00D4039D /* Build configuration list for PBXNativeTarget "RCTImage-tvOS" */; - buildPhases = ( - 3DED3A951DE6F79D00336DD7 /* Headers */, - 3D302F201DF8268700D6DDAE /* Copy Headers */, - 2D2A28361D9B042B00D4039D /* Sources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "RCTImage-tvOS"; - productName = "RCTImage-tvOS"; - productReference = 2D2A283A1D9B042B00D4039D /* libRCTImage-tvOS.a */; - productType = "com.apple.product-type.library.static"; - }; 58B5115C1A9E6B3D00147676 /* RCTImage */ = { isa = PBXNativeTarget; buildConfigurationList = 58B511711A9E6B3D00147676 /* Build configuration list for PBXNativeTarget "RCTImage" */; @@ -267,10 +193,6 @@ LastUpgradeCheck = 0810; ORGANIZATIONNAME = Facebook; TargetAttributes = { - 2D2A28391D9B042B00D4039D = { - CreatedOnToolsVersion = 8.0; - ProvisioningStyle = Automatic; - }; 58B5115C1A9E6B3D00147676 = { CreatedOnToolsVersion = 6.1.1; }; @@ -289,31 +211,11 @@ projectRoot = ""; targets = ( 58B5115C1A9E6B3D00147676 /* RCTImage */, - 2D2A28391D9B042B00D4039D /* RCTImage-tvOS */, ); }; /* End PBXProject section */ /* Begin PBXSourcesBuildPhase section */ - 2D2A28361D9B042B00D4039D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 2D3B5F231D9B0D1300451313 /* RCTImageStoreManager.m in Sources */, - 2D3B5F1A1D9B0D0400451313 /* RCTImageCache.m in Sources */, - 2D3B5F1D1D9B0D1300451313 /* RCTLocalAssetImageLoader.m in Sources */, - 2D3B5F1F1D9B0D1300451313 /* RCTImageEditingManager.m in Sources */, - 2D3B5F1E1D9B0D1300451313 /* RCTGIFImageDecoder.m in Sources */, - 2D3B5F1C1D9B0D1300451313 /* RCTResizeMode.m in Sources */, - 2D3B5F221D9B0D1300451313 /* RCTImageViewManager.m in Sources */, - 2D3B5F211D9B0D1300451313 /* RCTImageView.m in Sources */, - 3DA05A5B1EE0312900805843 /* RCTImageShadowView.m in Sources */, - 2D3B5F201D9B0D1300451313 /* RCTImageLoader.m in Sources */, - 2D3B5F1B1D9B0D0700451313 /* RCTImageBlurUtils.m in Sources */, - 2D3B5F241D9B0D1300451313 /* RCTImageUtils.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 58B511591A9E6B3D00147676 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -336,40 +238,6 @@ /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ - 2D2A28401D9B042B00D4039D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_SUSPICIOUS_MOVES = YES; - ENABLE_TESTABILITY = YES; - GCC_NO_COMMON_BLOCKS = YES; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/RCTImage; - SDKROOT = appletvos; - TVOS_DEPLOYMENT_TARGET = 9.2; - }; - name = Debug; - }; - 2D2A28411D9B042B00D4039D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_SUSPICIOUS_MOVES = YES; - COPY_PHASE_STRIP = NO; - GCC_NO_COMMON_BLOCKS = YES; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/RCTImage; - SDKROOT = appletvos; - TVOS_DEPLOYMENT_TARGET = 9.2; - }; - name = Release; - }; 58B5116F1A9E6B3D00147676 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -496,15 +364,6 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 2D2A28421D9B042B00D4039D /* Build configuration list for PBXNativeTarget "RCTImage-tvOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 2D2A28401D9B042B00D4039D /* Debug */, - 2D2A28411D9B042B00D4039D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 58B511581A9E6B3D00147676 /* Build configuration list for PBXProject "RCTImage" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Libraries/LinkingIOS/RCTLinking.xcodeproj/project.pbxproj b/Libraries/LinkingIOS/RCTLinking.xcodeproj/project.pbxproj index e9661cc7a1..38a27d4bd0 100644 --- a/Libraries/LinkingIOS/RCTLinking.xcodeproj/project.pbxproj +++ b/Libraries/LinkingIOS/RCTLinking.xcodeproj/project.pbxproj @@ -8,14 +8,12 @@ /* Begin PBXBuildFile section */ 148699CF1ABD045300480536 /* RCTLinkingManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 148699CE1ABD045300480536 /* RCTLinkingManager.m */; }; - 2D3B5F251D9B0DE600451313 /* RCTLinkingManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 148699CE1ABD045300480536 /* RCTLinkingManager.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 134814201AA4EA6300B7C361 /* libRCTLinking.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTLinking.a; sourceTree = BUILT_PRODUCTS_DIR; }; 148699CD1ABD045300480536 /* RCTLinkingManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTLinkingManager.h; sourceTree = ""; }; 148699CE1ABD045300480536 /* RCTLinkingManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTLinkingManager.m; sourceTree = ""; }; - 2D2A28471D9B043800D4039D /* libRCTLinking-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libRCTLinking-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXGroup section */ @@ -33,7 +31,6 @@ 148699CD1ABD045300480536 /* RCTLinkingManager.h */, 148699CE1ABD045300480536 /* RCTLinkingManager.m */, 134814211AA4EA7D00B7C361 /* Products */, - 2D2A28471D9B043800D4039D /* libRCTLinking-tvOS.a */, ); indentWidth = 2; sourceTree = ""; @@ -43,21 +40,6 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 2D2A28461D9B043800D4039D /* RCTLinking-tvOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 2D2A284F1D9B043800D4039D /* Build configuration list for PBXNativeTarget "RCTLinking-tvOS" */; - buildPhases = ( - 2D2A28431D9B043800D4039D /* Sources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "RCTLinking-tvOS"; - productName = "RCTLinking-tvOS"; - productReference = 2D2A28471D9B043800D4039D /* libRCTLinking-tvOS.a */; - productType = "com.apple.product-type.library.static"; - }; 58B511DA1A9E6C8500147676 /* RCTLinking */ = { isa = PBXNativeTarget; buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTLinking" */; @@ -82,10 +64,6 @@ LastUpgradeCheck = 0610; ORGANIZATIONNAME = Facebook; TargetAttributes = { - 2D2A28461D9B043800D4039D = { - CreatedOnToolsVersion = 8.0; - ProvisioningStyle = Automatic; - }; 58B511DA1A9E6C8500147676 = { CreatedOnToolsVersion = 6.1.1; }; @@ -104,20 +82,11 @@ projectRoot = ""; targets = ( 58B511DA1A9E6C8500147676 /* RCTLinking */, - 2D2A28461D9B043800D4039D /* RCTLinking-tvOS */, ); }; /* End PBXProject section */ /* Begin PBXSourcesBuildPhase section */ - 2D2A28431D9B043800D4039D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 2D3B5F251D9B0DE600451313 /* RCTLinkingManager.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 58B511D71A9E6C8500147676 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -129,40 +98,6 @@ /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ - 2D2A284D1D9B043800D4039D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_SUSPICIOUS_MOVES = YES; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_TESTABILITY = YES; - GCC_NO_COMMON_BLOCKS = YES; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = appletvos; - TVOS_DEPLOYMENT_TARGET = 9.2; - }; - name = Debug; - }; - 2D2A284E1D9B043800D4039D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_SUSPICIOUS_MOVES = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - GCC_NO_COMMON_BLOCKS = YES; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = appletvos; - TVOS_DEPLOYMENT_TARGET = 9.2; - }; - name = Release; - }; 58B511ED1A9E6C8500147676 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -270,15 +205,6 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 2D2A284F1D9B043800D4039D /* Build configuration list for PBXNativeTarget "RCTLinking-tvOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 2D2A284D1D9B043800D4039D /* Debug */, - 2D2A284E1D9B043800D4039D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RCTLinking" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Libraries/NativeAnimation/RCTAnimation.xcodeproj/project.pbxproj b/Libraries/NativeAnimation/RCTAnimation.xcodeproj/project.pbxproj index d9274c4884..9416449b15 100644 --- a/Libraries/NativeAnimation/RCTAnimation.xcodeproj/project.pbxproj +++ b/Libraries/NativeAnimation/RCTAnimation.xcodeproj/project.pbxproj @@ -17,49 +17,10 @@ 13E501EE1D07A6C9005F35D8 /* RCTStyleAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501E31D07A6C9005F35D8 /* RCTStyleAnimatedNode.m */; }; 13E501EF1D07A6C9005F35D8 /* RCTTransformAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501E51D07A6C9005F35D8 /* RCTTransformAnimatedNode.m */; }; 13E501F01D07A6C9005F35D8 /* RCTValueAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501E71D07A6C9005F35D8 /* RCTValueAnimatedNode.m */; }; - 192F69811E823F4A008692C7 /* RCTAnimationUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501B71D07A644005F35D8 /* RCTAnimationUtils.h */; }; - 192F69821E823F4A008692C7 /* RCTNativeAnimatedModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501BD1D07A644005F35D8 /* RCTNativeAnimatedModule.h */; }; - 192F69831E823F4A008692C7 /* RCTNativeAnimatedNodesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 94DA09161DC7971C00AEA8C9 /* RCTNativeAnimatedNodesManager.h */; }; - 192F69841E823F4A008692C7 /* RCTAnimationDriver.h in Headers */ = {isa = PBXBuildFile; fileRef = 94C1294A1D4069170025F25C /* RCTAnimationDriver.h */; }; - 192F69851E823F4A008692C7 /* RCTEventAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = 19F00F201DC8847500113FEE /* RCTEventAnimation.h */; }; - 192F69861E823F4A008692C7 /* RCTFrameAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = 94C1294C1D4069170025F25C /* RCTFrameAnimation.h */; }; - 192F69871E823F4A008692C7 /* RCTSpringAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = 94C1294E1D4069170025F25C /* RCTSpringAnimation.h */; }; - 192F69881E823F4A008692C7 /* RCTDivisionAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C9894931D999639008027DB /* RCTDivisionAnimatedNode.h */; }; - 192F69891E823F4A008692C7 /* RCTDiffClampAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 193F64F21D776EC6004D1CAA /* RCTDiffClampAnimatedNode.h */; }; - 192F698A1E823F4A008692C7 /* RCTAdditionAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501D61D07A6C9005F35D8 /* RCTAdditionAnimatedNode.h */; }; - 192F698B1E823F4A008692C7 /* RCTAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501D81D07A6C9005F35D8 /* RCTAnimatedNode.h */; }; - 192F698C1E823F4A008692C7 /* RCTInterpolationAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501DC1D07A6C9005F35D8 /* RCTInterpolationAnimatedNode.h */; }; - 192F698D1E823F4A008692C7 /* RCTModuloAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 94DAE3F71D7334A70059942F /* RCTModuloAnimatedNode.h */; }; - 192F698E1E823F4A008692C7 /* RCTMultiplicationAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501DE1D07A6C9005F35D8 /* RCTMultiplicationAnimatedNode.h */; }; - 192F698F1E823F4A008692C7 /* RCTPropsAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501E01D07A6C9005F35D8 /* RCTPropsAnimatedNode.h */; }; - 192F69901E823F4A008692C7 /* RCTStyleAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501E21D07A6C9005F35D8 /* RCTStyleAnimatedNode.h */; }; - 192F69911E823F4A008692C7 /* RCTTransformAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501E41D07A6C9005F35D8 /* RCTTransformAnimatedNode.h */; }; - 192F69921E823F4A008692C7 /* RCTValueAnimatedNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501E61D07A6C9005F35D8 /* RCTValueAnimatedNode.h */; }; - 192F69941E823F78008692C7 /* RCTAnimationUtils.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501B71D07A644005F35D8 /* RCTAnimationUtils.h */; }; - 192F69951E823F78008692C7 /* RCTNativeAnimatedModule.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501BD1D07A644005F35D8 /* RCTNativeAnimatedModule.h */; }; - 192F69961E823F78008692C7 /* RCTNativeAnimatedNodesManager.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 94DA09161DC7971C00AEA8C9 /* RCTNativeAnimatedNodesManager.h */; }; - 192F69971E823F78008692C7 /* RCTAnimationDriver.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 94C1294A1D4069170025F25C /* RCTAnimationDriver.h */; }; - 192F69981E823F78008692C7 /* RCTEventAnimation.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 19F00F201DC8847500113FEE /* RCTEventAnimation.h */; }; - 192F69991E823F78008692C7 /* RCTFrameAnimation.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 94C1294C1D4069170025F25C /* RCTFrameAnimation.h */; }; - 192F699A1E823F78008692C7 /* RCTSpringAnimation.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 94C1294E1D4069170025F25C /* RCTSpringAnimation.h */; }; - 192F699B1E823F78008692C7 /* RCTDivisionAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 5C9894931D999639008027DB /* RCTDivisionAnimatedNode.h */; }; - 192F699C1E823F78008692C7 /* RCTDiffClampAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 193F64F21D776EC6004D1CAA /* RCTDiffClampAnimatedNode.h */; }; - 192F699D1E823F78008692C7 /* RCTAdditionAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501D61D07A6C9005F35D8 /* RCTAdditionAnimatedNode.h */; }; - 192F699E1E823F78008692C7 /* RCTAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501D81D07A6C9005F35D8 /* RCTAnimatedNode.h */; }; - 192F699F1E823F78008692C7 /* RCTInterpolationAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501DC1D07A6C9005F35D8 /* RCTInterpolationAnimatedNode.h */; }; - 192F69A01E823F78008692C7 /* RCTModuloAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 94DAE3F71D7334A70059942F /* RCTModuloAnimatedNode.h */; }; - 192F69A11E823F78008692C7 /* RCTMultiplicationAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501DE1D07A6C9005F35D8 /* RCTMultiplicationAnimatedNode.h */; }; - 192F69A21E823F78008692C7 /* RCTPropsAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501E01D07A6C9005F35D8 /* RCTPropsAnimatedNode.h */; }; - 192F69A31E823F78008692C7 /* RCTStyleAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501E21D07A6C9005F35D8 /* RCTStyleAnimatedNode.h */; }; - 192F69A41E823F78008692C7 /* RCTTransformAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501E41D07A6C9005F35D8 /* RCTTransformAnimatedNode.h */; }; - 192F69A51E823F78008692C7 /* RCTValueAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501E61D07A6C9005F35D8 /* RCTValueAnimatedNode.h */; }; 193F64F41D776EC6004D1CAA /* RCTDiffClampAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 193F64F31D776EC6004D1CAA /* RCTDiffClampAnimatedNode.m */; }; 194804ED1E975D8E00623005 /* RCTDecayAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = 194804EB1E975D8E00623005 /* RCTDecayAnimation.h */; }; 194804EE1E975D8E00623005 /* RCTDecayAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = 194804EC1E975D8E00623005 /* RCTDecayAnimation.m */; }; 194804EF1E975DB500623005 /* RCTDecayAnimation.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 194804EB1E975D8E00623005 /* RCTDecayAnimation.h */; }; - 194804F01E975DCF00623005 /* RCTDecayAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = 194804EB1E975D8E00623005 /* RCTDecayAnimation.h */; }; - 194804F11E975DD700623005 /* RCTDecayAnimation.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 194804EB1E975D8E00623005 /* RCTDecayAnimation.h */; }; - 194804F21E977DDB00623005 /* RCTDecayAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = 194804EC1E975D8E00623005 /* RCTDecayAnimation.m */; }; 1980B70E1E80D1C4004DC789 /* RCTAnimationUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501B71D07A644005F35D8 /* RCTAnimationUtils.h */; }; 1980B7101E80D1C4004DC789 /* RCTNativeAnimatedModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 13E501BD1D07A644005F35D8 /* RCTNativeAnimatedModule.h */; }; 1980B7121E80D1C4004DC789 /* RCTNativeAnimatedNodesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 94DA09161DC7971C00AEA8C9 /* RCTNativeAnimatedNodesManager.h */; }; @@ -97,24 +58,7 @@ 1980B7441E80DD6F004DC789 /* RCTTransformAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501E41D07A6C9005F35D8 /* RCTTransformAnimatedNode.h */; }; 1980B7451E80DD6F004DC789 /* RCTValueAnimatedNode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 13E501E61D07A6C9005F35D8 /* RCTValueAnimatedNode.h */; }; 19F00F221DC8847500113FEE /* RCTEventAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = 19F00F211DC8847500113FEE /* RCTEventAnimation.m */; }; - 19F00F231DC8848E00113FEE /* RCTEventAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = 19F00F211DC8847500113FEE /* RCTEventAnimation.m */; }; - 2D3B5EF21D9B0B3100451313 /* RCTAnimationUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501B81D07A644005F35D8 /* RCTAnimationUtils.m */; }; - 2D3B5EF41D9B0B3700451313 /* RCTNativeAnimatedModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501BE1D07A644005F35D8 /* RCTNativeAnimatedModule.m */; }; - 2D3B5EF51D9B0B4800451313 /* RCTDivisionAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 5C9894941D999639008027DB /* RCTDivisionAnimatedNode.m */; }; - 2D3B5EF61D9B0B4800451313 /* RCTDiffClampAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 193F64F31D776EC6004D1CAA /* RCTDiffClampAnimatedNode.m */; }; - 2D3B5EF71D9B0B4800451313 /* RCTAdditionAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501D71D07A6C9005F35D8 /* RCTAdditionAnimatedNode.m */; }; - 2D3B5EF81D9B0B4800451313 /* RCTAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501D91D07A6C9005F35D8 /* RCTAnimatedNode.m */; }; - 2D3B5EFA1D9B0B4800451313 /* RCTInterpolationAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501DD1D07A6C9005F35D8 /* RCTInterpolationAnimatedNode.m */; }; - 2D3B5EFB1D9B0B4800451313 /* RCTModuloAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 94DAE3F81D7334A70059942F /* RCTModuloAnimatedNode.m */; }; - 2D3B5EFC1D9B0B4800451313 /* RCTMultiplicationAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501DF1D07A6C9005F35D8 /* RCTMultiplicationAnimatedNode.m */; }; - 2D3B5EFD1D9B0B4800451313 /* RCTPropsAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501E11D07A6C9005F35D8 /* RCTPropsAnimatedNode.m */; }; - 2D3B5EFE1D9B0B4800451313 /* RCTStyleAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501E31D07A6C9005F35D8 /* RCTStyleAnimatedNode.m */; }; - 2D3B5EFF1D9B0B4800451313 /* RCTTransformAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501E51D07A6C9005F35D8 /* RCTTransformAnimatedNode.m */; }; - 2D3B5F001D9B0B4800451313 /* RCTValueAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E501E71D07A6C9005F35D8 /* RCTValueAnimatedNode.m */; }; 5C9894951D999639008027DB /* RCTDivisionAnimatedNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 5C9894941D999639008027DB /* RCTDivisionAnimatedNode.m */; }; - 944244D01DB962DA0032A02B /* RCTFrameAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = 94C1294D1D4069170025F25C /* RCTFrameAnimation.m */; }; - 944244D11DB962DC0032A02B /* RCTSpringAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = 94C1294F1D4069170025F25C /* RCTSpringAnimation.m */; }; - 9476E8EC1DC9232D005D5CD1 /* RCTNativeAnimatedNodesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 94DA09171DC7971C00AEA8C9 /* RCTNativeAnimatedNodesManager.m */; }; 94C129511D40692B0025F25C /* RCTFrameAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = 94C1294D1D4069170025F25C /* RCTFrameAnimation.m */; }; 94C129521D40692B0025F25C /* RCTSpringAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = 94C1294F1D4069170025F25C /* RCTSpringAnimation.m */; }; 94DA09181DC7971C00AEA8C9 /* RCTNativeAnimatedNodesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 94DA09171DC7971C00AEA8C9 /* RCTNativeAnimatedNodesManager.m */; }; @@ -122,34 +66,6 @@ /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ - 192F69931E823F4F008692C7 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = include/RCTAnimation; - dstSubfolderSpec = 16; - files = ( - 194804F11E975DD700623005 /* RCTDecayAnimation.h in CopyFiles */, - 192F69941E823F78008692C7 /* RCTAnimationUtils.h in CopyFiles */, - 192F69951E823F78008692C7 /* RCTNativeAnimatedModule.h in CopyFiles */, - 192F69961E823F78008692C7 /* RCTNativeAnimatedNodesManager.h in CopyFiles */, - 192F69971E823F78008692C7 /* RCTAnimationDriver.h in CopyFiles */, - 192F69981E823F78008692C7 /* RCTEventAnimation.h in CopyFiles */, - 192F69991E823F78008692C7 /* RCTFrameAnimation.h in CopyFiles */, - 192F699A1E823F78008692C7 /* RCTSpringAnimation.h in CopyFiles */, - 192F699B1E823F78008692C7 /* RCTDivisionAnimatedNode.h in CopyFiles */, - 192F699C1E823F78008692C7 /* RCTDiffClampAnimatedNode.h in CopyFiles */, - 192F699D1E823F78008692C7 /* RCTAdditionAnimatedNode.h in CopyFiles */, - 192F699E1E823F78008692C7 /* RCTAnimatedNode.h in CopyFiles */, - 192F699F1E823F78008692C7 /* RCTInterpolationAnimatedNode.h in CopyFiles */, - 192F69A01E823F78008692C7 /* RCTModuloAnimatedNode.h in CopyFiles */, - 192F69A11E823F78008692C7 /* RCTMultiplicationAnimatedNode.h in CopyFiles */, - 192F69A21E823F78008692C7 /* RCTPropsAnimatedNode.h in CopyFiles */, - 192F69A31E823F78008692C7 /* RCTStyleAnimatedNode.h in CopyFiles */, - 192F69A41E823F78008692C7 /* RCTTransformAnimatedNode.h in CopyFiles */, - 192F69A51E823F78008692C7 /* RCTValueAnimatedNode.h in CopyFiles */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 1980B7311E80D21C004DC789 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -208,7 +124,6 @@ 194804EC1E975D8E00623005 /* RCTDecayAnimation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDecayAnimation.m; sourceTree = ""; }; 19F00F201DC8847500113FEE /* RCTEventAnimation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTEventAnimation.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 19F00F211DC8847500113FEE /* RCTEventAnimation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTEventAnimation.m; sourceTree = ""; }; - 2D2A28201D9B03D100D4039D /* libRCTAnimation.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTAnimation.a; sourceTree = BUILT_PRODUCTS_DIR; }; 5C9894931D999639008027DB /* RCTDivisionAnimatedNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTDivisionAnimatedNode.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 5C9894941D999639008027DB /* RCTDivisionAnimatedNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDivisionAnimatedNode.m; sourceTree = ""; }; 94C1294A1D4069170025F25C /* RCTAnimationDriver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTAnimationDriver.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; @@ -272,7 +187,6 @@ 94C129491D4069170025F25C /* Drivers */, 13E501D51D07A6C9005F35D8 /* Nodes */, 134814211AA4EA7D00B7C361 /* Products */, - 2D2A28201D9B03D100D4039D /* libRCTAnimation.a */, ); indentWidth = 2; sourceTree = ""; @@ -298,32 +212,6 @@ /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ - 192F69801E823F2E008692C7 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 194804F01E975DCF00623005 /* RCTDecayAnimation.h in Headers */, - 192F69811E823F4A008692C7 /* RCTAnimationUtils.h in Headers */, - 192F69821E823F4A008692C7 /* RCTNativeAnimatedModule.h in Headers */, - 192F69831E823F4A008692C7 /* RCTNativeAnimatedNodesManager.h in Headers */, - 192F69841E823F4A008692C7 /* RCTAnimationDriver.h in Headers */, - 192F69851E823F4A008692C7 /* RCTEventAnimation.h in Headers */, - 192F69861E823F4A008692C7 /* RCTFrameAnimation.h in Headers */, - 192F69871E823F4A008692C7 /* RCTSpringAnimation.h in Headers */, - 192F69881E823F4A008692C7 /* RCTDivisionAnimatedNode.h in Headers */, - 192F69891E823F4A008692C7 /* RCTDiffClampAnimatedNode.h in Headers */, - 192F698A1E823F4A008692C7 /* RCTAdditionAnimatedNode.h in Headers */, - 192F698B1E823F4A008692C7 /* RCTAnimatedNode.h in Headers */, - 192F698C1E823F4A008692C7 /* RCTInterpolationAnimatedNode.h in Headers */, - 192F698D1E823F4A008692C7 /* RCTModuloAnimatedNode.h in Headers */, - 192F698E1E823F4A008692C7 /* RCTMultiplicationAnimatedNode.h in Headers */, - 192F698F1E823F4A008692C7 /* RCTPropsAnimatedNode.h in Headers */, - 192F69901E823F4A008692C7 /* RCTStyleAnimatedNode.h in Headers */, - 192F69911E823F4A008692C7 /* RCTTransformAnimatedNode.h in Headers */, - 192F69921E823F4A008692C7 /* RCTValueAnimatedNode.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 1980B70D1E80D1B5004DC789 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -353,23 +241,6 @@ /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ - 2D2A281F1D9B03D100D4039D /* RCTAnimation-tvOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 2D2A28281D9B03D100D4039D /* Build configuration list for PBXNativeTarget "RCTAnimation-tvOS" */; - buildPhases = ( - 2D2A281C1D9B03D100D4039D /* Sources */, - 192F69801E823F2E008692C7 /* Headers */, - 192F69931E823F4F008692C7 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "RCTAnimation-tvOS"; - productName = "RCTAnimation-tvOS"; - productReference = 2D2A28201D9B03D100D4039D /* libRCTAnimation.a */; - productType = "com.apple.product-type.library.static"; - }; 58B511DA1A9E6C8500147676 /* RCTAnimation */ = { isa = PBXNativeTarget; buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTAnimation" */; @@ -396,10 +267,6 @@ LastUpgradeCheck = 0730; ORGANIZATIONNAME = Facebook; TargetAttributes = { - 2D2A281F1D9B03D100D4039D = { - CreatedOnToolsVersion = 8.0; - ProvisioningStyle = Automatic; - }; 58B511DA1A9E6C8500147676 = { CreatedOnToolsVersion = 6.1.1; }; @@ -418,37 +285,11 @@ projectRoot = ""; targets = ( 58B511DA1A9E6C8500147676 /* RCTAnimation */, - 2D2A281F1D9B03D100D4039D /* RCTAnimation-tvOS */, ); }; /* End PBXProject section */ /* Begin PBXSourcesBuildPhase section */ - 2D2A281C1D9B03D100D4039D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 2D3B5F001D9B0B4800451313 /* RCTValueAnimatedNode.m in Sources */, - 2D3B5EFB1D9B0B4800451313 /* RCTModuloAnimatedNode.m in Sources */, - 2D3B5EF21D9B0B3100451313 /* RCTAnimationUtils.m in Sources */, - 2D3B5EF51D9B0B4800451313 /* RCTDivisionAnimatedNode.m in Sources */, - 2D3B5EF71D9B0B4800451313 /* RCTAdditionAnimatedNode.m in Sources */, - 19F00F231DC8848E00113FEE /* RCTEventAnimation.m in Sources */, - 2D3B5EF41D9B0B3700451313 /* RCTNativeAnimatedModule.m in Sources */, - 2D3B5EF61D9B0B4800451313 /* RCTDiffClampAnimatedNode.m in Sources */, - 2D3B5EF81D9B0B4800451313 /* RCTAnimatedNode.m in Sources */, - 2D3B5EFE1D9B0B4800451313 /* RCTStyleAnimatedNode.m in Sources */, - 2D3B5EFA1D9B0B4800451313 /* RCTInterpolationAnimatedNode.m in Sources */, - 2D3B5EFF1D9B0B4800451313 /* RCTTransformAnimatedNode.m in Sources */, - 2D3B5EFC1D9B0B4800451313 /* RCTMultiplicationAnimatedNode.m in Sources */, - 2D3B5EFD1D9B0B4800451313 /* RCTPropsAnimatedNode.m in Sources */, - 944244D01DB962DA0032A02B /* RCTFrameAnimation.m in Sources */, - 944244D11DB962DC0032A02B /* RCTSpringAnimation.m in Sources */, - 9476E8EC1DC9232D005D5CD1 /* RCTNativeAnimatedNodesManager.m in Sources */, - 194804F21E977DDB00623005 /* RCTDecayAnimation.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 58B511D71A9E6C8500147676 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -477,35 +318,6 @@ /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ - 2D2A28261D9B03D100D4039D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_SUSPICIOUS_MOVES = YES; - DEBUG_INFORMATION_FORMAT = dwarf; - GCC_NO_COMMON_BLOCKS = YES; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = RCTAnimation; - SDKROOT = appletvos; - }; - name = Debug; - }; - 2D2A28271D9B03D100D4039D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_SUSPICIOUS_MOVES = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - GCC_NO_COMMON_BLOCKS = YES; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = RCTAnimation; - SDKROOT = appletvos; - }; - name = Release; - }; 58B511ED1A9E6C8500147676 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -622,15 +434,6 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 2D2A28281D9B03D100D4039D /* Build configuration list for PBXNativeTarget "RCTAnimation-tvOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 2D2A28261D9B03D100D4039D /* Debug */, - 2D2A28271D9B03D100D4039D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RCTAnimation" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Libraries/Network/RCTNetwork.xcodeproj/project.pbxproj b/Libraries/Network/RCTNetwork.xcodeproj/project.pbxproj index 83a81e3e62..9860adf58f 100644 --- a/Libraries/Network/RCTNetwork.xcodeproj/project.pbxproj +++ b/Libraries/Network/RCTNetwork.xcodeproj/project.pbxproj @@ -11,12 +11,6 @@ 1372B7371AB03E7B00659ED6 /* RCTNetInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 1372B7361AB03E7B00659ED6 /* RCTNetInfo.m */; }; 13D6D66A1B5FCF8200883BE9 /* RCTNetworkTask.m in Sources */ = {isa = PBXBuildFile; fileRef = 13D6D6691B5FCF8200883BE9 /* RCTNetworkTask.m */; }; 13EF800E1BCBE015003F47DD /* RCTFileRequestHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 13EF800D1BCBE015003F47DD /* RCTFileRequestHandler.m */; }; - 2D3B5F261D9B0EAB00451313 /* RCTNetworkTask.m in Sources */ = {isa = PBXBuildFile; fileRef = 13D6D6691B5FCF8200883BE9 /* RCTNetworkTask.m */; }; - 2D3B5F271D9B0EB400451313 /* RCTHTTPRequestHandler.mm in Sources */ = {isa = PBXBuildFile; fileRef = 352DA0B81B17855800AA15A8 /* RCTHTTPRequestHandler.mm */; }; - 2D3B5F281D9B0EB400451313 /* RCTFileRequestHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 13EF800D1BCBE015003F47DD /* RCTFileRequestHandler.m */; }; - 2D3B5F291D9B0EB400451313 /* RCTDataRequestHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 134E96991BCEB7F800AFFDA1 /* RCTDataRequestHandler.m */; }; - 2D3B5F2A1D9B0EB400451313 /* RCTNetInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 1372B7361AB03E7B00659ED6 /* RCTNetInfo.m */; }; - 2D3B5F2B1D9B0EB400451313 /* RCTNetworking.mm in Sources */ = {isa = PBXBuildFile; fileRef = 58B512071A9E6CE300147676 /* RCTNetworking.mm */; }; 352DA0BA1B17855800AA15A8 /* RCTHTTPRequestHandler.mm in Sources */ = {isa = PBXBuildFile; fileRef = 352DA0B81B17855800AA15A8 /* RCTHTTPRequestHandler.mm */; }; 58B512081A9E6CE300147676 /* RCTNetworking.mm in Sources */ = {isa = PBXBuildFile; fileRef = 58B512071A9E6CE300147676 /* RCTNetworking.mm */; }; /* End PBXBuildFile section */ @@ -30,7 +24,6 @@ 13D6D6691B5FCF8200883BE9 /* RCTNetworkTask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTNetworkTask.m; sourceTree = ""; }; 13EF800C1BCBE015003F47DD /* RCTFileRequestHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTFileRequestHandler.h; sourceTree = ""; }; 13EF800D1BCBE015003F47DD /* RCTFileRequestHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTFileRequestHandler.m; sourceTree = ""; }; - 2D2A28541D9B044C00D4039D /* libRCTNetwork-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libRCTNetwork-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 352DA0B71B17855800AA15A8 /* RCTHTTPRequestHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTHTTPRequestHandler.h; sourceTree = ""; }; 352DA0B81B17855800AA15A8 /* RCTHTTPRequestHandler.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RCTHTTPRequestHandler.mm; sourceTree = ""; }; 3D5FA63F1DE4B4790058FD77 /* RCTNetworking.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTNetworking.h; sourceTree = ""; }; @@ -65,7 +58,6 @@ isa = PBXGroup; children = ( 58B511DB1A9E6C8500147676 /* libRCTNetwork.a */, - 2D2A28541D9B044C00D4039D /* libRCTNetwork-tvOS.a */, ); name = Products; sourceTree = ""; @@ -73,21 +65,6 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 2D2A28531D9B044C00D4039D /* RCTNetwork-tvOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 2D2A285C1D9B044C00D4039D /* Build configuration list for PBXNativeTarget "RCTNetwork-tvOS" */; - buildPhases = ( - 2D2A28501D9B044C00D4039D /* Sources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "RCTNetwork-tvOS"; - productName = "RCTNetwork-tvOS"; - productReference = 2D2A28541D9B044C00D4039D /* libRCTNetwork-tvOS.a */; - productType = "com.apple.product-type.library.static"; - }; 58B511DA1A9E6C8500147676 /* RCTNetwork */ = { isa = PBXNativeTarget; buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTNetwork" */; @@ -112,10 +89,6 @@ LastUpgradeCheck = 0810; ORGANIZATIONNAME = Facebook; TargetAttributes = { - 2D2A28531D9B044C00D4039D = { - CreatedOnToolsVersion = 8.0; - ProvisioningStyle = Automatic; - }; 58B511DA1A9E6C8500147676 = { CreatedOnToolsVersion = 6.1.1; }; @@ -134,25 +107,11 @@ projectRoot = ""; targets = ( 58B511DA1A9E6C8500147676 /* RCTNetwork */, - 2D2A28531D9B044C00D4039D /* RCTNetwork-tvOS */, ); }; /* End PBXProject section */ /* Begin PBXSourcesBuildPhase section */ - 2D2A28501D9B044C00D4039D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 2D3B5F2A1D9B0EB400451313 /* RCTNetInfo.m in Sources */, - 2D3B5F261D9B0EAB00451313 /* RCTNetworkTask.m in Sources */, - 2D3B5F281D9B0EB400451313 /* RCTFileRequestHandler.m in Sources */, - 2D3B5F271D9B0EB400451313 /* RCTHTTPRequestHandler.mm in Sources */, - 2D3B5F2B1D9B0EB400451313 /* RCTNetworking.mm in Sources */, - 2D3B5F291D9B0EB400451313 /* RCTDataRequestHandler.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 58B511D71A9E6C8500147676 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -169,40 +128,6 @@ /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ - 2D2A285A1D9B044C00D4039D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_SUSPICIOUS_MOVES = YES; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_TESTABILITY = YES; - GCC_NO_COMMON_BLOCKS = YES; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = appletvos; - TVOS_DEPLOYMENT_TARGET = 9.2; - }; - name = Debug; - }; - 2D2A285B1D9B044C00D4039D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_SUSPICIOUS_MOVES = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - GCC_NO_COMMON_BLOCKS = YES; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = appletvos; - TVOS_DEPLOYMENT_TARGET = 9.2; - }; - name = Release; - }; 58B511ED1A9E6C8500147676 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -325,15 +250,6 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 2D2A285C1D9B044C00D4039D /* Build configuration list for PBXNativeTarget "RCTNetwork-tvOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 2D2A285A1D9B044C00D4039D /* Debug */, - 2D2A285B1D9B044C00D4039D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RCTNetwork" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Libraries/RCTTest/RCTTest.xcodeproj/project.pbxproj b/Libraries/RCTTest/RCTTest.xcodeproj/project.pbxproj index e80e605813..abbc44e114 100644 --- a/Libraries/RCTTest/RCTTest.xcodeproj/project.pbxproj +++ b/Libraries/RCTTest/RCTTest.xcodeproj/project.pbxproj @@ -7,16 +7,8 @@ objects = { /* Begin PBXBuildFile section */ - 2D3B5F2D1D9B0F2800451313 /* RCTSnapshotManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 9913A84A1BBE833400D70E66 /* RCTSnapshotManager.m */; }; - 2D3B5F2E1D9B0F2B00451313 /* RCTTestModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 585135341AB3C56F00882537 /* RCTTestModule.m */; }; - 2D3B5F2F1D9B0F2E00451313 /* RCTTestRunner.m in Sources */ = {isa = PBXBuildFile; fileRef = 585135361AB3C56F00882537 /* RCTTestRunner.m */; }; - 2D3B5F301D9B0F3D00451313 /* FBSnapshotTestController.m in Sources */ = {isa = PBXBuildFile; fileRef = 58E64FE71AB964CD007446E2 /* FBSnapshotTestController.m */; }; - 2D3B5F311D9B0F4200451313 /* UIImage+Compare.m in Sources */ = {isa = PBXBuildFile; fileRef = 58E64FE91AB964CD007446E2 /* UIImage+Compare.m */; }; - 2D3B5F321D9B0F4500451313 /* UIImage+Diff.m in Sources */ = {isa = PBXBuildFile; fileRef = 58E64FEB1AB964CD007446E2 /* UIImage+Diff.m */; }; 3D3030281DF82A6300D6DDAE /* RCTTestRunner.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 585135351AB3C56F00882537 /* RCTTestRunner.h */; }; - 3D30302A1DF82A8300D6DDAE /* RCTTestRunner.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 585135351AB3C56F00882537 /* RCTTestRunner.h */; }; 3DED3AA21DE6FC3400336DD7 /* RCTTestRunner.h in Headers */ = {isa = PBXBuildFile; fileRef = 585135351AB3C56F00882537 /* RCTTestRunner.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 3DED3AA41DE6FC4C00336DD7 /* RCTTestRunner.h in Headers */ = {isa = PBXBuildFile; fileRef = 585135351AB3C56F00882537 /* RCTTestRunner.h */; settings = {ATTRIBUTES = (Private, ); }; }; 585135371AB3C56F00882537 /* RCTTestModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 585135341AB3C56F00882537 /* RCTTestModule.m */; }; 585135381AB3C57000882537 /* RCTTestRunner.m in Sources */ = {isa = PBXBuildFile; fileRef = 585135361AB3C56F00882537 /* RCTTestRunner.m */; }; 58E64FED1AB964CD007446E2 /* FBSnapshotTestController.m in Sources */ = {isa = PBXBuildFile; fileRef = 58E64FE71AB964CD007446E2 /* FBSnapshotTestController.m */; }; @@ -37,21 +29,9 @@ name = "Copy Headers"; runOnlyForDeploymentPostprocessing = 0; }; - 3D3030291DF82A6E00D6DDAE /* Copy Headers */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = include/RCTTest; - dstSubfolderSpec = 16; - files = ( - 3D30302A1DF82A8300D6DDAE /* RCTTestRunner.h in Copy Headers */, - ); - name = "Copy Headers"; - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 2D2A286E1D9B047700D4039D /* libRCTTest-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libRCTTest-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 580C376F1AB104AF0015E709 /* libRCTTest.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTTest.a; sourceTree = BUILT_PRODUCTS_DIR; }; 585135331AB3C56F00882537 /* RCTTestModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTestModule.h; sourceTree = ""; }; 585135341AB3C56F00882537 /* RCTTestModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTestModule.m; sourceTree = ""; }; @@ -70,13 +50,6 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - 2D2A286B1D9B047700D4039D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; 580C376C1AB104AF0015E709 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -108,7 +81,6 @@ isa = PBXGroup; children = ( 580C376F1AB104AF0015E709 /* libRCTTest.a */, - 2D2A286E1D9B047700D4039D /* libRCTTest-tvOS.a */, ); name = Products; sourceTree = ""; @@ -139,35 +111,9 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 3DED3AA31DE6FC4700336DD7 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 3DED3AA41DE6FC4C00336DD7 /* RCTTestRunner.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ - 2D2A286D1D9B047700D4039D /* RCTTest-tvOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 2D2A28761D9B047700D4039D /* Build configuration list for PBXNativeTarget "RCTTest-tvOS" */; - buildPhases = ( - 3DED3AA31DE6FC4700336DD7 /* Headers */, - 3D3030291DF82A6E00D6DDAE /* Copy Headers */, - 2D2A286A1D9B047700D4039D /* Sources */, - 2D2A286B1D9B047700D4039D /* Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "RCTTest-tvOS"; - productName = "RCTTest-tvOS"; - productReference = 2D2A286E1D9B047700D4039D /* libRCTTest-tvOS.a */; - productType = "com.apple.product-type.library.static"; - }; 580C376E1AB104AF0015E709 /* RCTTest */ = { isa = PBXNativeTarget; buildConfigurationList = 580C37831AB104AF0015E709 /* Build configuration list for PBXNativeTarget "RCTTest" */; @@ -195,10 +141,6 @@ LastUpgradeCheck = 0610; ORGANIZATIONNAME = Facebook; TargetAttributes = { - 2D2A286D1D9B047700D4039D = { - CreatedOnToolsVersion = 8.0; - ProvisioningStyle = Automatic; - }; 580C376E1AB104AF0015E709 = { CreatedOnToolsVersion = 6.1.1; }; @@ -217,25 +159,11 @@ projectRoot = ""; targets = ( 580C376E1AB104AF0015E709 /* RCTTest */, - 2D2A286D1D9B047700D4039D /* RCTTest-tvOS */, ); }; /* End PBXProject section */ /* Begin PBXSourcesBuildPhase section */ - 2D2A286A1D9B047700D4039D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 2D3B5F311D9B0F4200451313 /* UIImage+Compare.m in Sources */, - 2D3B5F2F1D9B0F2E00451313 /* RCTTestRunner.m in Sources */, - 2D3B5F321D9B0F4500451313 /* UIImage+Diff.m in Sources */, - 2D3B5F301D9B0F3D00451313 /* FBSnapshotTestController.m in Sources */, - 2D3B5F2D1D9B0F2800451313 /* RCTSnapshotManager.m in Sources */, - 2D3B5F2E1D9B0F2B00451313 /* RCTTestModule.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 580C376B1AB104AF0015E709 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -252,42 +180,6 @@ /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ - 2D2A28741D9B047700D4039D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_SUSPICIOUS_MOVES = YES; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_TESTABILITY = YES; - GCC_NO_COMMON_BLOCKS = YES; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/RCTTest; - SDKROOT = appletvos; - TVOS_DEPLOYMENT_TARGET = 9.2; - }; - name = Debug; - }; - 2D2A28751D9B047700D4039D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_SUSPICIOUS_MOVES = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - GCC_NO_COMMON_BLOCKS = YES; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/RCTTest; - SDKROOT = appletvos; - TVOS_DEPLOYMENT_TARGET = 9.2; - }; - name = Release; - }; 580C37811AB104AF0015E709 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -325,7 +217,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MACOSX_DEPLOYMENT_TARGET = 10.10; + MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -368,7 +260,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MACOSX_DEPLOYMENT_TARGET = 10.10; + MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SKIP_INSTALL = YES; @@ -412,15 +304,6 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 2D2A28761D9B047700D4039D /* Build configuration list for PBXNativeTarget "RCTTest-tvOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 2D2A28741D9B047700D4039D /* Debug */, - 2D2A28751D9B047700D4039D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 580C376A1AB104AF0015E709 /* Build configuration list for PBXProject "RCTTest" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Libraries/ReactNative/requireNativeComponent.js b/Libraries/ReactNative/requireNativeComponent.js index c7ffc9fb17..ed7717f602 100644 --- a/Libraries/ReactNative/requireNativeComponent.js +++ b/Libraries/ReactNative/requireNativeComponent.js @@ -133,18 +133,34 @@ function requireNativeComponent( } let baseModuleName = viewConfig.baseModuleName; - let nativeProps = {...viewConfig.NativeProps}; + let bubblingEventTypes = viewConfig.bubblingEventTypes; + let directEventTypes = viewConfig.directEventTypes; + let nativeProps = viewConfig.NativeProps; while (baseModuleName) { const baseModule = UIManager[baseModuleName]; if (!baseModule) { warning(false, 'Base module "%s" does not exist', baseModuleName); baseModuleName = null; } else { - nativeProps = {...nativeProps, ...baseModule.NativeProps}; + bubblingEventTypes = { + ...baseModule.bubblingEventTypes, + ...bubblingEventTypes, + }; + directEventTypes = { + ...baseModule.directEventTypes, + ...directEventTypes, + }; + nativeProps = { + ...baseModule.NativeProps, + ...nativeProps, + }; baseModuleName = baseModule.baseModuleName; } } + viewConfig.bubblingEventTypes = bubblingEventTypes; + viewConfig.directEventTypes = directEventTypes; + for (const key in nativeProps) { let useAttribute = false; const attribute = {}; diff --git a/Libraries/Settings/RCTSettings.xcodeproj/project.pbxproj b/Libraries/Settings/RCTSettings.xcodeproj/project.pbxproj index cf4cea1c7d..a01167e412 100644 --- a/Libraries/Settings/RCTSettings.xcodeproj/project.pbxproj +++ b/Libraries/Settings/RCTSettings.xcodeproj/project.pbxproj @@ -8,14 +8,12 @@ /* Begin PBXBuildFile section */ 13DBA45E1AEE749000A17CF8 /* RCTSettingsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13DBA45D1AEE749000A17CF8 /* RCTSettingsManager.m */; }; - 2D3B5F2C1D9B0ECA00451313 /* RCTSettingsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13DBA45D1AEE749000A17CF8 /* RCTSettingsManager.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 134814201AA4EA6300B7C361 /* libRCTSettings.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTSettings.a; sourceTree = BUILT_PRODUCTS_DIR; }; 13DBA45C1AEE749000A17CF8 /* RCTSettingsManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTSettingsManager.h; sourceTree = ""; }; 13DBA45D1AEE749000A17CF8 /* RCTSettingsManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSettingsManager.m; sourceTree = ""; }; - 2D2A28611D9B046600D4039D /* libRCTSettings-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libRCTSettings-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXGroup section */ @@ -33,7 +31,6 @@ 13DBA45C1AEE749000A17CF8 /* RCTSettingsManager.h */, 13DBA45D1AEE749000A17CF8 /* RCTSettingsManager.m */, 134814211AA4EA7D00B7C361 /* Products */, - 2D2A28611D9B046600D4039D /* libRCTSettings-tvOS.a */, ); indentWidth = 2; sourceTree = ""; @@ -43,21 +40,6 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 2D2A28601D9B046600D4039D /* RCTSettings-tvOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 2D2A28691D9B046600D4039D /* Build configuration list for PBXNativeTarget "RCTSettings-tvOS" */; - buildPhases = ( - 2D2A285D1D9B046600D4039D /* Sources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "RCTSettings-tvOS"; - productName = "RCTSettings-tvOS"; - productReference = 2D2A28611D9B046600D4039D /* libRCTSettings-tvOS.a */; - productType = "com.apple.product-type.library.static"; - }; 58B511DA1A9E6C8500147676 /* RCTSettings */ = { isa = PBXNativeTarget; buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTSettings" */; @@ -82,10 +64,6 @@ LastUpgradeCheck = 0610; ORGANIZATIONNAME = Facebook; TargetAttributes = { - 2D2A28601D9B046600D4039D = { - CreatedOnToolsVersion = 8.0; - ProvisioningStyle = Automatic; - }; 58B511DA1A9E6C8500147676 = { CreatedOnToolsVersion = 6.1.1; }; @@ -104,20 +82,11 @@ projectRoot = ""; targets = ( 58B511DA1A9E6C8500147676 /* RCTSettings */, - 2D2A28601D9B046600D4039D /* RCTSettings-tvOS */, ); }; /* End PBXProject section */ /* Begin PBXSourcesBuildPhase section */ - 2D2A285D1D9B046600D4039D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 2D3B5F2C1D9B0ECA00451313 /* RCTSettingsManager.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 58B511D71A9E6C8500147676 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -129,40 +98,6 @@ /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ - 2D2A28671D9B046600D4039D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_SUSPICIOUS_MOVES = YES; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_TESTABILITY = YES; - GCC_NO_COMMON_BLOCKS = YES; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = appletvos; - TVOS_DEPLOYMENT_TARGET = 9.2; - }; - name = Debug; - }; - 2D2A28681D9B046600D4039D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_SUSPICIOUS_MOVES = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - GCC_NO_COMMON_BLOCKS = YES; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = appletvos; - TVOS_DEPLOYMENT_TARGET = 9.2; - }; - name = Release; - }; 58B511ED1A9E6C8500147676 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -200,7 +135,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MACOSX_DEPLOYMENT_TARGET = 10.10; + MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -243,7 +178,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MACOSX_DEPLOYMENT_TARGET = 10.10; + MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SKIP_INSTALL = YES; @@ -276,15 +211,6 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 2D2A28691D9B046600D4039D /* Build configuration list for PBXNativeTarget "RCTSettings-tvOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 2D2A28671D9B046600D4039D /* Debug */, - 2D2A28681D9B046600D4039D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RCTSettings" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Libraries/Text/BaseText/RCTBaseTextShadowView.h b/Libraries/Text/BaseText/RCTBaseTextShadowView.h new file mode 100644 index 0000000000..736eed8ac0 --- /dev/null +++ b/Libraries/Text/BaseText/RCTBaseTextShadowView.h @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import + +#import "RCTTextAttributes.h" + +NS_ASSUME_NONNULL_BEGIN + +extern NSString *const RCTBaseTextShadowViewEmbeddedShadowViewAttributeName; + +@interface RCTBaseTextShadowView : RCTShadowView + +@property (nonatomic, strong) RCTTextAttributes *textAttributes; + +- (NSAttributedString *)attributedTextWithBaseTextAttributes:(nullable RCTTextAttributes *)baseTextAttributes; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Libraries/Text/BaseText/RCTBaseTextShadowView.m b/Libraries/Text/BaseText/RCTBaseTextShadowView.m new file mode 100644 index 0000000000..efafad36de --- /dev/null +++ b/Libraries/Text/BaseText/RCTBaseTextShadowView.m @@ -0,0 +1,125 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "RCTBaseTextShadowView.h" + +#import + +#import "RCTRawTextShadowView.h" +#import "RCTVirtualTextShadowView.h" + +NSString *const RCTBaseTextShadowViewEmbeddedShadowViewAttributeName = @"RCTBaseTextShadowViewEmbeddedShadowViewAttributeName"; + +@implementation RCTBaseTextShadowView +{ + NSAttributedString *_Nullable _cachedAttributedText; + RCTTextAttributes *_Nullable _cachedTextAttributes; +} + +- (instancetype)init +{ + if (self = [super init]) { + _textAttributes = [RCTTextAttributes new]; + } + + return self; +} + +- (void)setReactTag:(NSNumber *)reactTag +{ + [super setReactTag:reactTag]; + _textAttributes.tag = reactTag; +} + +#pragma mark - attributedString + +- (NSAttributedString *)attributedTextWithBaseTextAttributes:(nullable RCTTextAttributes *)baseTextAttributes +{ + RCTTextAttributes *textAttributes; + + if (baseTextAttributes) { + textAttributes = [baseTextAttributes copy]; + [textAttributes applyTextAttributes:self.textAttributes]; + } else { + textAttributes = [self.textAttributes copy]; + } + + if (_cachedAttributedText && [_cachedTextAttributes isEqual:textAttributes]) { + return _cachedAttributedText; + } + + NSMutableAttributedString *attributedText = [NSMutableAttributedString new]; + + [attributedText beginEditing]; + + for (RCTShadowView *shadowView in self.reactSubviews) { + // Special Case: RCTRawTextShadowView + if ([shadowView isKindOfClass:[RCTRawTextShadowView class]]) { + RCTRawTextShadowView *rawTextShadowView = (RCTRawTextShadowView *)shadowView; + NSString *text = rawTextShadowView.text; + if (text) { + NSAttributedString *rawTextAttributedString = + [[NSAttributedString alloc] initWithString:rawTextShadowView.text + attributes:textAttributes.effectiveTextAttributes]; + [attributedText appendAttributedString:rawTextAttributedString]; + } + continue; + } + + // Special Case: RCTBaseTextShadowView + if ([shadowView isKindOfClass:[RCTBaseTextShadowView class]]) { + RCTBaseTextShadowView *baseTextShadowView = (RCTBaseTextShadowView *)shadowView; + NSAttributedString *baseTextAttributedString = + [baseTextShadowView attributedTextWithBaseTextAttributes:textAttributes]; + [attributedText appendAttributedString:baseTextAttributedString]; + continue; + } + + // Generic Case: Any RCTShadowView + NSTextAttachment *attachment = [NSTextAttachment new]; + NSMutableAttributedString *embeddedShadowViewAttributedString = [NSMutableAttributedString new]; + [embeddedShadowViewAttributedString beginEditing]; + [embeddedShadowViewAttributedString appendAttributedString:[NSAttributedString attributedStringWithAttachment:attachment]]; + [embeddedShadowViewAttributedString addAttribute:RCTBaseTextShadowViewEmbeddedShadowViewAttributeName + value:shadowView + range:(NSRange){0, embeddedShadowViewAttributedString.length}]; + [embeddedShadowViewAttributedString endEditing]; + [attributedText appendAttributedString:embeddedShadowViewAttributedString]; + } + + [attributedText endEditing]; + + [self clearLayout]; + + _cachedAttributedText = [attributedText copy]; + _cachedTextAttributes = textAttributes; + + return _cachedAttributedText; +} + +- (void)dirtyLayout +{ + [super dirtyLayout]; + _cachedAttributedText = nil; + _cachedTextAttributes = nil; +} + +- (void)didUpdateReactSubviews +{ + [super didUpdateReactSubviews]; + [self dirtyLayout]; +} + +- (void)didSetProps:(NSArray *)changedProps +{ + [super didSetProps:changedProps]; + [self dirtyLayout]; +} + +@end diff --git a/Libraries/Text/BaseText/RCTBaseTextViewManager.h b/Libraries/Text/BaseText/RCTBaseTextViewManager.h new file mode 100644 index 0000000000..da73cf0708 --- /dev/null +++ b/Libraries/Text/BaseText/RCTBaseTextViewManager.h @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface RCTBaseTextViewManager : RCTViewManager + +@end + +NS_ASSUME_NONNULL_END diff --git a/Libraries/Text/BaseText/RCTBaseTextViewManager.m b/Libraries/Text/BaseText/RCTBaseTextViewManager.m new file mode 100644 index 0000000000..207608af28 --- /dev/null +++ b/Libraries/Text/BaseText/RCTBaseTextViewManager.m @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "RCTBaseTextViewManager.h" + +@implementation RCTBaseTextViewManager + +RCT_EXPORT_MODULE(RCTBaseText) + +- (NSView *)view +{ + RCTAssert(NO, @"The `-[RCTBaseTextViewManager view]` property must be overridden in subclass."); + return nil; +} + +- (RCTShadowView *)shadowView +{ + RCTAssert(NO, @"The `-[RCTBaseTextViewManager shadowView]` property must be overridden in subclass."); + return nil; +} + +#pragma mark - Text Attributes + +// Color +RCT_REMAP_SHADOW_PROPERTY(color, textAttributes.foregroundColor, NSColor) +RCT_REMAP_SHADOW_PROPERTY(backgroundColor, textAttributes.backgroundColor, NSColor) +RCT_REMAP_SHADOW_PROPERTY(opacity, textAttributes.opacity, CGFloat) +// Font +RCT_REMAP_SHADOW_PROPERTY(fontFamily, textAttributes.fontFamily, NSString) +RCT_REMAP_SHADOW_PROPERTY(fontSize, textAttributes.fontSize, CGFloat) +RCT_REMAP_SHADOW_PROPERTY(fontWeight, textAttributes.fontWeight, NSString) +RCT_REMAP_SHADOW_PROPERTY(fontStyle, textAttributes.fontStyle, NSString) +RCT_REMAP_SHADOW_PROPERTY(fontVariant, textAttributes.fontVariant, NSArray) +RCT_REMAP_SHADOW_PROPERTY(allowFontScaling, textAttributes.allowFontScaling, BOOL) +RCT_REMAP_SHADOW_PROPERTY(letterSpacing, textAttributes.letterSpacing, CGFloat) +// Paragraph Styles +RCT_REMAP_SHADOW_PROPERTY(lineHeight, textAttributes.lineHeight, CGFloat) +RCT_REMAP_SHADOW_PROPERTY(textAlign, textAttributes.alignment, NSTextAlignment) +RCT_REMAP_SHADOW_PROPERTY(writingDirection, textAttributes.baseWritingDirection, NSWritingDirection) +// Decoration +RCT_REMAP_SHADOW_PROPERTY(textDecorationColor, textAttributes.textDecorationColor, NSColor) +RCT_REMAP_SHADOW_PROPERTY(textDecorationStyle, textAttributes.textDecorationStyle, NSUnderlineStyle) +RCT_REMAP_SHADOW_PROPERTY(textDecorationLine, textAttributes.textDecorationLine, RCTTextDecorationLineType) +// Shadow +RCT_REMAP_SHADOW_PROPERTY(textShadowOffset, textAttributes.textShadowOffset, CGSize) +RCT_REMAP_SHADOW_PROPERTY(textShadowRadius, textAttributes.textShadowRadius, CGFloat) +RCT_REMAP_SHADOW_PROPERTY(textShadowColor, textAttributes.textShadowColor, NSColor) +// Special +RCT_REMAP_SHADOW_PROPERTY(isHighlighted, textAttributes.isHighlighted, BOOL) + +@end diff --git a/Libraries/Text/NSBezierPath+CGPath.h b/Libraries/Text/NSBezierPath+CGPath.h new file mode 100644 index 0000000000..ad20b455e6 --- /dev/null +++ b/Libraries/Text/NSBezierPath+CGPath.h @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface NSBezierPath (CGPath) + +- (CGPathRef)CGPath; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Libraries/Text/NSBezierPath+CGPath.m b/Libraries/Text/NSBezierPath+CGPath.m new file mode 100644 index 0000000000..838c3d1907 --- /dev/null +++ b/Libraries/Text/NSBezierPath+CGPath.m @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "NSBezierPath+CGPath.h" + +@implementation NSBezierPath (CGPath) + +// Taken from: https://stackoverflow.com/a/1956021/2228559 +- (CGPathRef)CGPath +{ + CGPathRef path = NULL; + + NSInteger numElements = self.elementCount; + if (numElements > 0) { + CGMutablePathRef mutablePath = CGPathCreateMutable(); + BOOL didClosePath = YES; + + for (NSInteger i = 0; i < numElements; i++) { + NSPoint p[3]; + switch ([self elementAtIndex:i associatedPoints:p]) { + case NSMoveToBezierPathElement: + CGPathMoveToPoint(mutablePath, NULL, p[0].x, p[0].y); + break; + + case NSLineToBezierPathElement: + CGPathAddLineToPoint(mutablePath, NULL, p[0].x, p[0].y); + didClosePath = NO; + break; + + case NSCurveToBezierPathElement: + CGPathAddCurveToPoint(mutablePath, NULL, p[0].x, p[0].y, p[1].x, p[1].y, p[2].x, p[2].y); + didClosePath = NO; + break; + + case NSClosePathBezierPathElement: + CGPathCloseSubpath(mutablePath); + didClosePath = YES; + break; + } + } + + // Be sure the path is closed or Quartz may not do valid hit detection. + if (!didClosePath) { + CGPathCloseSubpath(mutablePath); + } + + path = CGPathCreateCopy(path); + CGPathRelease(mutablePath); + } + + return path; +} + +@end diff --git a/Libraries/Text/NSFont+LineHeight.h b/Libraries/Text/NSFont+LineHeight.h new file mode 100644 index 0000000000..cddd349482 --- /dev/null +++ b/Libraries/Text/NSFont+LineHeight.h @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface NSFont (LineHeight) + +- (CGFloat)lineHeight; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Libraries/Text/NSFont+LineHeight.m b/Libraries/Text/NSFont+LineHeight.m new file mode 100644 index 0000000000..de76ce0c59 --- /dev/null +++ b/Libraries/Text/NSFont+LineHeight.m @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "NSFont+LineHeight.h" + +@implementation NSFont (LineHeight) + +// Taken from: https://github.com/bvanderveen/Thor/blob/0ea3cbd031df6c00fffc54a9b35de7ef787ea36f/Thor/Classes/NSFont%2BLineHeight.m#L5-L7 +- (CGFloat)lineHeight +{ + return ceilf(self.ascender + ABS(self.descender) + self.leading); +} + +@end diff --git a/Libraries/Text/NSLabel.h b/Libraries/Text/NSLabel.h new file mode 100644 index 0000000000..cf97b66017 --- /dev/null +++ b/Libraries/Text/NSLabel.h @@ -0,0 +1,42 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 Leonard Hecker + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#import + +@interface NSLabel : NSView + +@property (nonatomic, copy) NSString *text; +@property (nonatomic, copy) NSAttributedString *attributedText; +@property (nonatomic, retain) NSFont *font; +@property (nonatomic, retain) NSColor *textColor; +@property (nonatomic, retain) NSColor *backgroundColor; +@property (nonatomic, assign) NSInteger numberOfLines; +@property (nonatomic, assign) NSTextAlignment alignment; +@property (nonatomic, assign) NSLineBreakMode lineBreakMode; +@property (nonatomic, assign) CGFloat preferredMaxLayoutWidth; + +- (instancetype)init; +- (instancetype)initWithFrame:(NSRect)frameRect NS_DESIGNATED_INITIALIZER; + +@end diff --git a/Libraries/Text/NSLabel.m b/Libraries/Text/NSLabel.m new file mode 100644 index 0000000000..2f81889175 --- /dev/null +++ b/Libraries/Text/NSLabel.m @@ -0,0 +1,237 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 Leonard Hecker + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#import "NSLabel.h" + +#import + +@implementation NSLabel +{ + NSRect _drawingRect; +} + +#pragma mark - NSView overrides + +- (instancetype)init +{ + return [self initWithFrame:NSZeroRect]; +} + +- (instancetype)initWithFrame:(NSRect)frameRect +{ + if (self = [super initWithFrame:frameRect]) { + // _text, _attributedText and _preferredMaxLayoutWidth are nil/0 by default + self.font = self.defaultFont; + self.textColor = self.defaultTextColor; + self.backgroundColor = self.defaultBackgroundColor; + self.numberOfLines = 1; + self.alignment = NSTextAlignmentLeft; + self.lineBreakMode = NSLineBreakByTruncatingTail; + } + + return self; +} + +RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)coder) + +- (BOOL)isOpaque +{ + return self.backgroundColor.alphaComponent == 1.0; +} + +- (CGFloat)baselineOffsetFromBottom +{ + return self.drawingRect.origin.y; +} + +- (NSSize)intrinsicContentSize +{ + return self.drawingRect.size; +} + +- (void)invalidateIntrinsicContentSize +{ + _drawingRect = NSZeroRect; + [super invalidateIntrinsicContentSize]; +} + +- (void)drawRect:(NSRect)dirtyRect +{ + NSRect bounds = self.bounds; + NSRect drawRect = {self.drawingRect.origin, bounds.size}; + NSString* text = nil; + NSAttributedString* attributedText = nil; + + [self.backgroundColor setFill]; + NSRectFillUsingOperation(bounds, NSCompositeSourceOver); + + if ((text = self.text)) { + [text drawWithRect:drawRect options:self.drawingOptions attributes:@{ + NSFontAttributeName : self.font, + NSForegroundColorAttributeName : self.textColor, + NSBackgroundColorAttributeName : self.backgroundColor, + NSParagraphStyleAttributeName : self.drawingParagraphStyle, + }]; + } else if ((attributedText = self.attributedText)) { + [attributedText drawWithRect:drawRect options:self.drawingOptions]; + } +} + +#pragma mark - Private + +- (NSRect)drawingRect +{ + // invalidated by [NSLabel invalidateIntrinsicContentSize] + + NSString* text = nil; + NSAttributedString* attributedText = nil; + + if (NSIsEmptyRect(_drawingRect) && ((text = self.text) || (attributedText = self.attributedText))) { + NSSize size = NSMakeSize(self.preferredMaxLayoutWidth, 0.0); + + if (text) { + _drawingRect = [text boundingRectWithSize:size options:self.drawingOptions attributes:@{ + NSFontAttributeName : self.font, + NSForegroundColorAttributeName : self.textColor, + NSBackgroundColorAttributeName : self.backgroundColor, + NSParagraphStyleAttributeName : self.drawingParagraphStyle, + }]; + } else { + _drawingRect = [attributedText boundingRectWithSize:size options:self.drawingOptions]; + } + + _drawingRect = (NSRect) { + { + ceil(-_drawingRect.origin.x), + ceil(-_drawingRect.origin.y), + }, { + ceil(_drawingRect.size.width), + ceil(_drawingRect.size.height), + } + }; + } + + return _drawingRect; +} + +- (NSStringDrawingOptions)drawingOptions +{ + NSStringDrawingOptions options = NSStringDrawingUsesFontLeading; + + if (self.numberOfLines == 0) { + options |= NSStringDrawingUsesLineFragmentOrigin; + } + + return options; +} + +- (NSParagraphStyle*)drawingParagraphStyle +{ + NSMutableParagraphStyle* ps = [NSMutableParagraphStyle new]; + ps.alignment = self.alignment; + ps.lineBreakMode = self.lineBreakMode; + return ps; +} + +- (NSFont*)defaultFont +{ + return [NSFont labelFontOfSize:12.0]; +} + +- (NSColor*)defaultTextColor +{ + return [NSColor blackColor]; +} + +- (NSColor*)defaultBackgroundColor +{ + return [NSColor clearColor]; +} + +#pragma mark - Display setters + +- (void)setText:(NSString*)text +{ + _text = [text copy]; + _attributedText = nil; + [self invalidateIntrinsicContentSize]; + [self setNeedsDisplay:YES]; +} + +- (void)setAttributedText:(NSAttributedString*)attributedText +{ + _text = nil; + _attributedText = [attributedText copy]; + [self invalidateIntrinsicContentSize]; + [self setNeedsDisplay:YES]; +} + +- (void)setFont:(NSFont*)font +{ + _font = font ? font : self.defaultFont; + [self invalidateIntrinsicContentSize]; + [self setNeedsDisplay:YES]; +} + +- (void)setTextColor:(NSColor*)textColor +{ + _textColor = textColor ? textColor : self.defaultTextColor; + [self setNeedsDisplay:YES]; +} + +- (void)setBackgroundColor:(NSColor*)backgroundColor +{ + _backgroundColor = backgroundColor ? backgroundColor : self.defaultBackgroundColor; + [self setNeedsDisplay:YES]; +} + +- (void)setNumberOfLines:(NSInteger)numberOfLines +{ + _numberOfLines = numberOfLines; + [self invalidateIntrinsicContentSize]; + [self setNeedsDisplay:YES]; +} + +- (void)setAlignment:(NSTextAlignment)alignment +{ + _alignment = alignment; + [self invalidateIntrinsicContentSize]; + [self setNeedsDisplay:YES]; +} + +- (void)setLineBreakMode:(NSLineBreakMode)lineBreakMode +{ + _lineBreakMode = lineBreakMode; + [self invalidateIntrinsicContentSize]; + [self setNeedsDisplay:YES]; +} + +- (void)setPreferredMaxLayoutWidth:(CGFloat)preferredMaxLayoutWidth +{ + _preferredMaxLayoutWidth = preferredMaxLayoutWidth; + [self invalidateIntrinsicContentSize]; + [self setNeedsDisplay:YES]; +} + +@end diff --git a/Libraries/Text/NSText+Editing.h b/Libraries/Text/NSText+Editing.h new file mode 100644 index 0000000000..0705bef972 --- /dev/null +++ b/Libraries/Text/NSText+Editing.h @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface NSText (Editing) + +- (BOOL)endEditing:(BOOL)force; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Libraries/Text/NSText+Editing.m b/Libraries/Text/NSText+Editing.m new file mode 100644 index 0000000000..ff5898718d --- /dev/null +++ b/Libraries/Text/NSText+Editing.m @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "NSText+Editing.h" + +@implementation NSText (Editing) + +- (BOOL)endEditing:(BOOL)force +{ + if (self != self.window.firstResponder) { + return YES; + } + if (force || [self.delegate textShouldEndEditing:self]) { + [self.window makeFirstResponder:nil]; + return YES; + } + return NO; +} + +@end diff --git a/Libraries/Text/NSValue+CoreGraphics.h b/Libraries/Text/NSValue+CoreGraphics.h new file mode 100644 index 0000000000..eb6e0236ad --- /dev/null +++ b/Libraries/Text/NSValue+CoreGraphics.h @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface NSValue (CoreGraphics) + ++ (NSValue *)valueWithCGSize:(CGSize)size; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Libraries/Text/NSValue+CoreGraphics.m b/Libraries/Text/NSValue+CoreGraphics.m new file mode 100644 index 0000000000..521e4f01c7 --- /dev/null +++ b/Libraries/Text/NSValue+CoreGraphics.m @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "NSValue+CoreGraphics.h" + +@implementation NSValue (CoreGraphics) + +// Taken from: https://github.com/dbainbridge/mapbox-osx/blob/3461e73eddd397c415c873d317d346d1d351787a/Map/src/NSValue%2BiOS.m#L32-L35 ++ (NSValue *)valueWithCGSize:(CGSize)size +{ + return [NSValue valueWithSize:NSSizeFromCGSize(size)]; +} + +@end diff --git a/Libraries/Text/RCTConvert+Text.h b/Libraries/Text/RCTConvert+Text.h index 794b1e4e1c..242d1cc207 100644 --- a/Libraries/Text/RCTConvert+Text.h +++ b/Libraries/Text/RCTConvert+Text.h @@ -9,9 +9,13 @@ #import +NS_ASSUME_NONNULL_BEGIN + @interface RCTConvert (Text) // //+ (NSTextAutocorrectionType)NSTextAutocorrectionType:(id)json; //+ (NSTextSpellCheckingType)NSTextSpellCheckingType:(id)json; @end + +NS_ASSUME_NONNULL_END diff --git a/Libraries/Text/RCTConvert+Text.m b/Libraries/Text/RCTConvert+Text.m index 5e4815b1e7..d1b2e13fce 100644 --- a/Libraries/Text/RCTConvert+Text.m +++ b/Libraries/Text/RCTConvert+Text.m @@ -11,20 +11,20 @@ @implementation RCTConvert (Text) -+ (UITextAutocorrectionType)UITextAutocorrectionType:(id)json -{ - return - json == nil ? UITextAutocorrectionTypeDefault : - [RCTConvert BOOL:json] ? UITextAutocorrectionTypeYes : - UITextAutocorrectionTypeNo; -} - -+ (UITextSpellCheckingType)UITextSpellCheckingType:(id)json -{ - return - json == nil ? UITextSpellCheckingTypeDefault : - [RCTConvert BOOL:json] ? UITextSpellCheckingTypeYes : - UITextSpellCheckingTypeNo; -} +//+ (UITextAutocorrectionType)UITextAutocorrectionType:(id)json +//{ +// return +// json == nil ? UITextAutocorrectionTypeDefault : +// [RCTConvert BOOL:json] ? UITextAutocorrectionTypeYes : +// UITextAutocorrectionTypeNo; +//} +// +//+ (UITextSpellCheckingType)UITextSpellCheckingType:(id)json +//{ +// return +// json == nil ? UITextSpellCheckingTypeDefault : +// [RCTConvert BOOL:json] ? UITextSpellCheckingTypeYes : +// UITextSpellCheckingTypeNo; +//} @end diff --git a/Libraries/Text/RCTText.xcodeproj/project.pbxproj b/Libraries/Text/RCTText.xcodeproj/project.pbxproj index d3117cbcff..2725edc2a1 100644 --- a/Libraries/Text/RCTText.xcodeproj/project.pbxproj +++ b/Libraries/Text/RCTText.xcodeproj/project.pbxproj @@ -7,41 +7,67 @@ objects = { /* Begin PBXBuildFile section */ - 59E604521FE9CAF100BD90C5 /* RCTTextShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 59E6042F1FE9CAF100BD90C5 /* RCTTextShadowView.m */; }; - 59E604531FE9CAF100BD90C5 /* RCTTextShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 59E6042F1FE9CAF100BD90C5 /* RCTTextShadowView.m */; }; - 59E604541FE9CAF100BD90C5 /* RCTTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 59E604311FE9CAF100BD90C5 /* RCTTextView.m */; }; - 59E604551FE9CAF100BD90C5 /* RCTTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 59E604311FE9CAF100BD90C5 /* RCTTextView.m */; }; - 59E604561FE9CAF100BD90C5 /* RCTTextViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 59E604331FE9CAF100BD90C5 /* RCTTextViewManager.m */; }; - 59E604571FE9CAF100BD90C5 /* RCTTextViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 59E604331FE9CAF100BD90C5 /* RCTTextViewManager.m */; }; - 59E604581FE9CAF100BD90C5 /* RCTRawTextShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 59E604341FE9CAF100BD90C5 /* RCTRawTextShadowView.m */; }; - 59E604591FE9CAF100BD90C5 /* RCTRawTextShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 59E604341FE9CAF100BD90C5 /* RCTRawTextShadowView.m */; }; - 59E6045A1FE9CAF100BD90C5 /* RCTRawTextViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 59E604361FE9CAF100BD90C5 /* RCTRawTextViewManager.m */; }; - 59E6045B1FE9CAF100BD90C5 /* RCTRawTextViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 59E604361FE9CAF100BD90C5 /* RCTRawTextViewManager.m */; }; - 59E604731FE9CB3F00BD90C5 /* RCTFontAttributes.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = A85C82981F742AA20036C019 /* RCTFontAttributes.h */; }; - 59E604741FE9CB3F00BD90C5 /* RCTFontAttributesDelegate.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = A85C82BA1F742D8F0036C019 /* RCTFontAttributesDelegate.h */; }; - 59E604751FE9CB3F00BD90C5 /* RCTRawTextShadowView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 59E6042C1FE9CAF100BD90C5 /* RCTRawTextShadowView.h */; }; - 59E604761FE9CB3F00BD90C5 /* RCTRawTextViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 59E604351FE9CAF100BD90C5 /* RCTRawTextViewManager.h */; }; - 59E604771FE9CB3F00BD90C5 /* RCTTextShadowView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 59E6042E1FE9CAF100BD90C5 /* RCTTextShadowView.h */; }; - 59E604781FE9CB3F00BD90C5 /* RCTTextView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 59E604301FE9CAF100BD90C5 /* RCTTextView.h */; }; - 59E604791FE9CB3F00BD90C5 /* RCTTextViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 59E604321FE9CAF100BD90C5 /* RCTTextViewManager.h */; }; - 59E604881FE9CB4A00BD90C5 /* RCTFontAttributes.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = A85C82981F742AA20036C019 /* RCTFontAttributes.h */; }; - 59E604891FE9CB4A00BD90C5 /* RCTFontAttributesDelegate.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = A85C82BA1F742D8F0036C019 /* RCTFontAttributesDelegate.h */; }; - 59E6048A1FE9CB4A00BD90C5 /* RCTRawTextShadowView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 59E6042C1FE9CAF100BD90C5 /* RCTRawTextShadowView.h */; }; - 59E6048B1FE9CB4A00BD90C5 /* RCTRawTextViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 59E604351FE9CAF100BD90C5 /* RCTRawTextViewManager.h */; }; - 59E6048C1FE9CB4A00BD90C5 /* RCTTextShadowView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 59E6042E1FE9CAF100BD90C5 /* RCTTextShadowView.h */; }; - 59E6048D1FE9CB4A00BD90C5 /* RCTTextView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 59E604301FE9CAF100BD90C5 /* RCTTextView.h */; }; - 59E6048E1FE9CB4A00BD90C5 /* RCTTextViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 59E604321FE9CAF100BD90C5 /* RCTTextViewManager.h */; }; - 59E8C5CC1F8833D100204F5E /* RCTFontAttributes.m in Sources */ = {isa = PBXBuildFile; fileRef = A85C82991F742AA20036C019 /* RCTFontAttributes.m */; }; - A85C829A1F742AA20036C019 /* RCTFontAttributes.m in Sources */ = {isa = PBXBuildFile; fileRef = A85C82991F742AA20036C019 /* RCTFontAttributes.m */; }; - D4EEE317201FA3B300C4CBB6 /* RCTMultilineTextInputView.m in Sources */ = {isa = PBXBuildFile; fileRef = D4EEE303201FA3B100C4CBB6 /* RCTMultilineTextInputView.m */; }; - D4EEE318201FA3B300C4CBB6 /* RCTUITextView.m in Sources */ = {isa = PBXBuildFile; fileRef = D4EEE307201FA3B100C4CBB6 /* RCTUITextView.m */; }; - D4EEE31A201FA3B300C4CBB6 /* RCTShadowTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = D4EEE30C201FA3B200C4CBB6 /* RCTShadowTextView.m */; }; - D4EEE31B201FA3B300C4CBB6 /* RCTTextSelection.m in Sources */ = {isa = PBXBuildFile; fileRef = D4EEE30D201FA3B200C4CBB6 /* RCTTextSelection.m */; }; - D4EEE31C201FA3B300C4CBB6 /* RCTTextFieldManager.m in Sources */ = {isa = PBXBuildFile; fileRef = D4EEE310201FA3B200C4CBB6 /* RCTTextFieldManager.m */; }; - D4EEE31D201FA3B300C4CBB6 /* RCTSecureTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = D4EEE312201FA3B200C4CBB6 /* RCTSecureTextField.m */; }; - D4EEE31E201FA3B300C4CBB6 /* RCTTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = D4EEE313201FA3B200C4CBB6 /* RCTTextField.m */; }; - D4EEE31F201FA3B300C4CBB6 /* RCTShadowTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = D4EEE315201FA3B300C4CBB6 /* RCTShadowTextField.m */; }; - D4EEE320201FA3B300C4CBB6 /* RCTTextViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = D4EEE316201FA3B300C4CBB6 /* RCTTextViewManager.m */; }; + 5956B130200FEBAA008D9D16 /* RCTRawTextShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B0FD200FEBA9008D9D16 /* RCTRawTextShadowView.m */; }; + 5956B131200FEBAA008D9D16 /* RCTRawTextViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B0FE200FEBA9008D9D16 /* RCTRawTextViewManager.m */; }; + 5956B132200FEBAA008D9D16 /* RCTSinglelineTextInputView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B101200FEBA9008D9D16 /* RCTSinglelineTextInputView.m */; }; + 5956B133200FEBAA008D9D16 /* RCTUITextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B103200FEBA9008D9D16 /* RCTUITextField.m */; }; + 5956B134200FEBAA008D9D16 /* RCTSinglelineTextInputViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B106200FEBA9008D9D16 /* RCTSinglelineTextInputViewManager.m */; }; + 5956B135200FEBAA008D9D16 /* RCTBaseTextInputView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B10A200FEBA9008D9D16 /* RCTBaseTextInputView.m */; }; + 5956B136200FEBAA008D9D16 /* RCTBackedTextInputDelegateAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B10D200FEBA9008D9D16 /* RCTBackedTextInputDelegateAdapter.m */; }; + 5956B137200FEBAA008D9D16 /* RCTBaseTextInputShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B10F200FEBA9008D9D16 /* RCTBaseTextInputShadowView.m */; }; + 5956B138200FEBAA008D9D16 /* RCTTextSelection.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B110200FEBA9008D9D16 /* RCTTextSelection.m */; }; + 5956B139200FEBAA008D9D16 /* RCTBaseTextInputViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B111200FEBA9008D9D16 /* RCTBaseTextInputViewManager.m */; }; + 5956B13A200FEBAA008D9D16 /* RCTMultilineTextInputView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B115200FEBA9008D9D16 /* RCTMultilineTextInputView.m */; }; + 5956B13B200FEBAA008D9D16 /* RCTMultilineTextInputViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B118200FEBA9008D9D16 /* RCTMultilineTextInputViewManager.m */; }; + 5956B13C200FEBAA008D9D16 /* RCTUITextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B119200FEBA9008D9D16 /* RCTUITextView.m */; }; + 5956B13D200FEBAA008D9D16 /* RCTBaseTextShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B11E200FEBA9008D9D16 /* RCTBaseTextShadowView.m */; }; + 5956B13E200FEBAA008D9D16 /* RCTBaseTextViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B11F200FEBA9008D9D16 /* RCTBaseTextViewManager.m */; }; + 5956B13F200FEBAA008D9D16 /* RCTTextAttributes.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B120200FEBA9008D9D16 /* RCTTextAttributes.m */; }; + 5956B140200FEBAA008D9D16 /* RCTTextShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B122200FEBAA008D9D16 /* RCTTextShadowView.m */; }; + 5956B141200FEBAA008D9D16 /* NSTextStorage+FontScaling.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B125200FEBAA008D9D16 /* NSTextStorage+FontScaling.m */; }; + 5956B142200FEBAA008D9D16 /* RCTTextViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B127200FEBAA008D9D16 /* RCTTextViewManager.m */; }; + 5956B143200FEBAA008D9D16 /* RCTTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B128200FEBAA008D9D16 /* RCTTextView.m */; }; + 5956B144200FEBAA008D9D16 /* RCTVirtualTextViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B12B200FEBAA008D9D16 /* RCTVirtualTextViewManager.m */; }; + 5956B145200FEBAA008D9D16 /* RCTVirtualTextShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B12E200FEBAA008D9D16 /* RCTVirtualTextShadowView.m */; }; + 5956B146200FEBAA008D9D16 /* RCTConvert+Text.m in Sources */ = {isa = PBXBuildFile; fileRef = 5956B12F200FEBAA008D9D16 /* RCTConvert+Text.m */; }; + 5956B160200FF324008D9D16 /* RCTBaseTextShadowView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B11D200FEBA9008D9D16 /* RCTBaseTextShadowView.h */; }; + 5956B161200FF324008D9D16 /* RCTBaseTextViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B11C200FEBA9008D9D16 /* RCTBaseTextViewManager.h */; }; + 5956B162200FF324008D9D16 /* RCTRawTextShadowView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B0FC200FEBA9008D9D16 /* RCTRawTextShadowView.h */; }; + 5956B163200FF324008D9D16 /* RCTRawTextViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B0FB200FEBA9008D9D16 /* RCTRawTextViewManager.h */; }; + 5956B164200FF324008D9D16 /* RCTConvert+Text.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B0F9200FEBA9008D9D16 /* RCTConvert+Text.h */; }; + 5956B165200FF324008D9D16 /* RCTTextAttributes.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B11A200FEBA9008D9D16 /* RCTTextAttributes.h */; }; + 5956B166200FF324008D9D16 /* NSTextStorage+FontScaling.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B129200FEBAA008D9D16 /* NSTextStorage+FontScaling.h */; }; + 5956B167200FF324008D9D16 /* RCTTextShadowView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B126200FEBAA008D9D16 /* RCTTextShadowView.h */; }; + 5956B168200FF324008D9D16 /* RCTTextView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B123200FEBAA008D9D16 /* RCTTextView.h */; }; + 5956B169200FF324008D9D16 /* RCTTextViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B124200FEBAA008D9D16 /* RCTTextViewManager.h */; }; + 5956B16A200FF324008D9D16 /* RCTMultilineTextInputView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B117200FEBA9008D9D16 /* RCTMultilineTextInputView.h */; }; + 5956B16B200FF324008D9D16 /* RCTMultilineTextInputViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B114200FEBA9008D9D16 /* RCTMultilineTextInputViewManager.h */; }; + 5956B16C200FF324008D9D16 /* RCTUITextView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B116200FEBA9008D9D16 /* RCTUITextView.h */; }; + 5956B16D200FF324008D9D16 /* RCTBackedTextInputDelegate.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B10C200FEBA9008D9D16 /* RCTBackedTextInputDelegate.h */; }; + 5956B16E200FF324008D9D16 /* RCTBackedTextInputDelegateAdapter.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B107200FEBA9008D9D16 /* RCTBackedTextInputDelegateAdapter.h */; }; + 5956B16F200FF324008D9D16 /* RCTBackedTextInputViewProtocol.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B112200FEBA9008D9D16 /* RCTBackedTextInputViewProtocol.h */; }; + 5956B170200FF324008D9D16 /* RCTBaseTextInputShadowView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B109200FEBA9008D9D16 /* RCTBaseTextInputShadowView.h */; }; + 5956B171200FF324008D9D16 /* RCTBaseTextInputView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B10E200FEBA9008D9D16 /* RCTBaseTextInputView.h */; }; + 5956B172200FF324008D9D16 /* RCTBaseTextInputViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B10B200FEBA9008D9D16 /* RCTBaseTextInputViewManager.h */; }; + 5956B173200FF324008D9D16 /* RCTTextSelection.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B108200FEBA9008D9D16 /* RCTTextSelection.h */; }; + 5956B174200FF324008D9D16 /* RCTSinglelineTextInputView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B104200FEBA9008D9D16 /* RCTSinglelineTextInputView.h */; }; + 5956B175200FF324008D9D16 /* RCTSinglelineTextInputViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B102200FEBA9008D9D16 /* RCTSinglelineTextInputViewManager.h */; }; + 5956B176200FF324008D9D16 /* RCTUITextField.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B105200FEBA9008D9D16 /* RCTUITextField.h */; }; + 5956B177200FF324008D9D16 /* RCTVirtualTextShadowView.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B12C200FEBAA008D9D16 /* RCTVirtualTextShadowView.h */; }; + 5956B178200FF324008D9D16 /* RCTVirtualTextViewManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 5956B12D200FEBAA008D9D16 /* RCTVirtualTextViewManager.h */; }; + 70588F392227118900CD1EEA /* NSFont+LineHeight.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 705EDE3B221378CC000CAA67 /* NSFont+LineHeight.h */; }; + 70588F3A222715DD00CD1EEA /* NSValue+CoreGraphics.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 705EDE3E22137BE7000CAA67 /* NSValue+CoreGraphics.h */; }; + 70588F642227335B00CD1EEA /* NSLabel.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 705EDE4422138919000CAA67 /* NSLabel.h */; }; + 70588F652227336100CD1EEA /* NSLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 705EDE422213890E000CAA67 /* NSLabel.m */; }; + 70588F6922273F2300CD1EEA /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 70588F6822273F2300CD1EEA /* AppKit.framework */; }; + 70588F6C222741ED00CD1EEA /* RCTFieldEditor.m in Sources */ = {isa = PBXBuildFile; fileRef = 70588F6B222741EC00CD1EEA /* RCTFieldEditor.m */; }; + 70588F6D222741F600CD1EEA /* RCTFieldEditor.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 70588F6A222741EC00CD1EEA /* RCTFieldEditor.h */; }; + 70588F702227427700CD1EEA /* NSText+Editing.m in Sources */ = {isa = PBXBuildFile; fileRef = 70588F6E2227427600CD1EEA /* NSText+Editing.m */; }; + 70588F712227428000CD1EEA /* NSText+Editing.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 70588F6F2227427700CD1EEA /* NSText+Editing.h */; }; + 705EDE3022132863000CAA67 /* NSBezierPath+CGPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 705EDE2F22132863000CAA67 /* NSBezierPath+CGPath.m */; }; + 705EDE3D221378CC000CAA67 /* NSFont+LineHeight.m in Sources */ = {isa = PBXBuildFile; fileRef = 705EDE3C221378CC000CAA67 /* NSFont+LineHeight.m */; }; + 705EDE4022137BE7000CAA67 /* NSValue+CoreGraphics.m in Sources */ = {isa = PBXBuildFile; fileRef = 705EDE3F22137BE7000CAA67 /* NSValue+CoreGraphics.m */; }; + 70DB420B2225E4470019CAF9 /* NSBezierPath+CGPath.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 705EDE2E22132863000CAA67 /* NSBezierPath+CGPath.h */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -51,30 +77,37 @@ dstPath = include/RCTText; dstSubfolderSpec = 16; files = ( - 59E604881FE9CB4A00BD90C5 /* RCTFontAttributes.h in Copy Headers */, - 59E604891FE9CB4A00BD90C5 /* RCTFontAttributesDelegate.h in Copy Headers */, - 59E6048A1FE9CB4A00BD90C5 /* RCTRawTextShadowView.h in Copy Headers */, - 59E6048B1FE9CB4A00BD90C5 /* RCTRawTextViewManager.h in Copy Headers */, - 59E6048C1FE9CB4A00BD90C5 /* RCTTextShadowView.h in Copy Headers */, - 59E6048D1FE9CB4A00BD90C5 /* RCTTextView.h in Copy Headers */, - 59E6048E1FE9CB4A00BD90C5 /* RCTTextViewManager.h in Copy Headers */, - ); - name = "Copy Headers"; - runOnlyForDeploymentPostprocessing = 0; - }; - 599DF2601F0306AD0079B53E /* Copy Headers */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = include/RCTText; - dstSubfolderSpec = 16; - files = ( - 59E604731FE9CB3F00BD90C5 /* RCTFontAttributes.h in Copy Headers */, - 59E604741FE9CB3F00BD90C5 /* RCTFontAttributesDelegate.h in Copy Headers */, - 59E604751FE9CB3F00BD90C5 /* RCTRawTextShadowView.h in Copy Headers */, - 59E604761FE9CB3F00BD90C5 /* RCTRawTextViewManager.h in Copy Headers */, - 59E604771FE9CB3F00BD90C5 /* RCTTextShadowView.h in Copy Headers */, - 59E604781FE9CB3F00BD90C5 /* RCTTextView.h in Copy Headers */, - 59E604791FE9CB3F00BD90C5 /* RCTTextViewManager.h in Copy Headers */, + 70588F712227428000CD1EEA /* NSText+Editing.h in Copy Headers */, + 70588F6D222741F600CD1EEA /* RCTFieldEditor.h in Copy Headers */, + 70588F642227335B00CD1EEA /* NSLabel.h in Copy Headers */, + 70588F3A222715DD00CD1EEA /* NSValue+CoreGraphics.h in Copy Headers */, + 70588F392227118900CD1EEA /* NSFont+LineHeight.h in Copy Headers */, + 70DB420B2225E4470019CAF9 /* NSBezierPath+CGPath.h in Copy Headers */, + 5956B160200FF324008D9D16 /* RCTBaseTextShadowView.h in Copy Headers */, + 5956B161200FF324008D9D16 /* RCTBaseTextViewManager.h in Copy Headers */, + 5956B162200FF324008D9D16 /* RCTRawTextShadowView.h in Copy Headers */, + 5956B163200FF324008D9D16 /* RCTRawTextViewManager.h in Copy Headers */, + 5956B164200FF324008D9D16 /* RCTConvert+Text.h in Copy Headers */, + 5956B165200FF324008D9D16 /* RCTTextAttributes.h in Copy Headers */, + 5956B166200FF324008D9D16 /* NSTextStorage+FontScaling.h in Copy Headers */, + 5956B167200FF324008D9D16 /* RCTTextShadowView.h in Copy Headers */, + 5956B168200FF324008D9D16 /* RCTTextView.h in Copy Headers */, + 5956B169200FF324008D9D16 /* RCTTextViewManager.h in Copy Headers */, + 5956B16A200FF324008D9D16 /* RCTMultilineTextInputView.h in Copy Headers */, + 5956B16B200FF324008D9D16 /* RCTMultilineTextInputViewManager.h in Copy Headers */, + 5956B16C200FF324008D9D16 /* RCTUITextView.h in Copy Headers */, + 5956B16D200FF324008D9D16 /* RCTBackedTextInputDelegate.h in Copy Headers */, + 5956B16E200FF324008D9D16 /* RCTBackedTextInputDelegateAdapter.h in Copy Headers */, + 5956B16F200FF324008D9D16 /* RCTBackedTextInputViewProtocol.h in Copy Headers */, + 5956B170200FF324008D9D16 /* RCTBaseTextInputShadowView.h in Copy Headers */, + 5956B171200FF324008D9D16 /* RCTBaseTextInputView.h in Copy Headers */, + 5956B172200FF324008D9D16 /* RCTBaseTextInputViewManager.h in Copy Headers */, + 5956B173200FF324008D9D16 /* RCTTextSelection.h in Copy Headers */, + 5956B174200FF324008D9D16 /* RCTSinglelineTextInputView.h in Copy Headers */, + 5956B175200FF324008D9D16 /* RCTSinglelineTextInputViewManager.h in Copy Headers */, + 5956B176200FF324008D9D16 /* RCTUITextField.h in Copy Headers */, + 5956B177200FF324008D9D16 /* RCTVirtualTextShadowView.h in Copy Headers */, + 5956B178200FF324008D9D16 /* RCTVirtualTextViewManager.h in Copy Headers */, ); name = "Copy Headers"; runOnlyForDeploymentPostprocessing = 0; @@ -82,55 +115,106 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 2D2A287B1D9B048500D4039D /* libRCTText-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libRCTText-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 58B5119B1A9E6C1200147676 /* libRCTText.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTText.a; sourceTree = BUILT_PRODUCTS_DIR; }; - 59E6042C1FE9CAF100BD90C5 /* RCTRawTextShadowView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTRawTextShadowView.h; sourceTree = ""; }; - 59E6042E1FE9CAF100BD90C5 /* RCTTextShadowView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTextShadowView.h; sourceTree = ""; }; - 59E6042F1FE9CAF100BD90C5 /* RCTTextShadowView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTextShadowView.m; sourceTree = ""; }; - 59E604301FE9CAF100BD90C5 /* RCTTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTextView.h; sourceTree = ""; }; - 59E604311FE9CAF100BD90C5 /* RCTTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTextView.m; sourceTree = ""; }; - 59E604321FE9CAF100BD90C5 /* RCTTextViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTextViewManager.h; sourceTree = ""; }; - 59E604331FE9CAF100BD90C5 /* RCTTextViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTextViewManager.m; sourceTree = ""; }; - 59E604341FE9CAF100BD90C5 /* RCTRawTextShadowView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRawTextShadowView.m; sourceTree = ""; }; - 59E604351FE9CAF100BD90C5 /* RCTRawTextViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTRawTextViewManager.h; sourceTree = ""; }; - 59E604361FE9CAF100BD90C5 /* RCTRawTextViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRawTextViewManager.m; sourceTree = ""; }; - A85C82981F742AA20036C019 /* RCTFontAttributes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTFontAttributes.h; sourceTree = ""; }; - A85C82991F742AA20036C019 /* RCTFontAttributes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTFontAttributes.m; sourceTree = ""; }; - A85C82BA1F742D8F0036C019 /* RCTFontAttributesDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTFontAttributesDelegate.h; sourceTree = ""; }; - D4EEE303201FA3B100C4CBB6 /* RCTMultilineTextInputView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RCTMultilineTextInputView.m; path = TextInputLegacy/RCTMultilineTextInputView.m; sourceTree = ""; }; - D4EEE304201FA3B100C4CBB6 /* RCTShadowTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RCTShadowTextField.h; path = TextInputLegacy/RCTShadowTextField.h; sourceTree = ""; }; - D4EEE305201FA3B100C4CBB6 /* RCTShadowTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RCTShadowTextView.h; path = TextInputLegacy/RCTShadowTextView.h; sourceTree = ""; }; - D4EEE306201FA3B100C4CBB6 /* RCTTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RCTTextField.h; path = TextInputLegacy/RCTTextField.h; sourceTree = ""; }; - D4EEE307201FA3B100C4CBB6 /* RCTUITextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RCTUITextView.m; path = TextInputLegacy/RCTUITextView.m; sourceTree = ""; }; - D4EEE308201FA3B100C4CBB6 /* RCTTextFieldManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RCTTextFieldManager.h; path = TextInputLegacy/RCTTextFieldManager.h; sourceTree = ""; }; - D4EEE309201FA3B100C4CBB6 /* RCTTextSelection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RCTTextSelection.h; path = TextInputLegacy/RCTTextSelection.h; sourceTree = ""; }; - D4EEE30A201FA3B100C4CBB6 /* RCTSecureTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RCTSecureTextField.h; path = TextInputLegacy/RCTSecureTextField.h; sourceTree = ""; }; - D4EEE30C201FA3B200C4CBB6 /* RCTShadowTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RCTShadowTextView.m; path = TextInputLegacy/RCTShadowTextView.m; sourceTree = ""; }; - D4EEE30D201FA3B200C4CBB6 /* RCTTextSelection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RCTTextSelection.m; path = TextInputLegacy/RCTTextSelection.m; sourceTree = ""; }; - D4EEE30E201FA3B200C4CBB6 /* RCTMultilineTextInputView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RCTMultilineTextInputView.h; path = TextInputLegacy/RCTMultilineTextInputView.h; sourceTree = ""; }; - D4EEE30F201FA3B200C4CBB6 /* RCTTextViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RCTTextViewManager.h; path = TextInputLegacy/RCTTextViewManager.h; sourceTree = ""; }; - D4EEE310201FA3B200C4CBB6 /* RCTTextFieldManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RCTTextFieldManager.m; path = TextInputLegacy/RCTTextFieldManager.m; sourceTree = ""; }; - D4EEE311201FA3B200C4CBB6 /* RCTUITextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RCTUITextView.h; path = TextInputLegacy/RCTUITextView.h; sourceTree = ""; }; - D4EEE312201FA3B200C4CBB6 /* RCTSecureTextField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RCTSecureTextField.m; path = TextInputLegacy/RCTSecureTextField.m; sourceTree = ""; }; - D4EEE313201FA3B200C4CBB6 /* RCTTextField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RCTTextField.m; path = TextInputLegacy/RCTTextField.m; sourceTree = ""; }; - D4EEE315201FA3B300C4CBB6 /* RCTShadowTextField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RCTShadowTextField.m; path = TextInputLegacy/RCTShadowTextField.m; sourceTree = ""; }; - D4EEE316201FA3B300C4CBB6 /* RCTTextViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RCTTextViewManager.m; path = TextInputLegacy/RCTTextViewManager.m; sourceTree = ""; }; + 5956B0F9200FEBA9008D9D16 /* RCTConvert+Text.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RCTConvert+Text.h"; sourceTree = ""; }; + 5956B0FB200FEBA9008D9D16 /* RCTRawTextViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTRawTextViewManager.h; sourceTree = ""; }; + 5956B0FC200FEBA9008D9D16 /* RCTRawTextShadowView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTRawTextShadowView.h; sourceTree = ""; }; + 5956B0FD200FEBA9008D9D16 /* RCTRawTextShadowView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRawTextShadowView.m; sourceTree = ""; }; + 5956B0FE200FEBA9008D9D16 /* RCTRawTextViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRawTextViewManager.m; sourceTree = ""; }; + 5956B101200FEBA9008D9D16 /* RCTSinglelineTextInputView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSinglelineTextInputView.m; sourceTree = ""; }; + 5956B102200FEBA9008D9D16 /* RCTSinglelineTextInputViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTSinglelineTextInputViewManager.h; sourceTree = ""; }; + 5956B103200FEBA9008D9D16 /* RCTUITextField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTUITextField.m; sourceTree = ""; }; + 5956B104200FEBA9008D9D16 /* RCTSinglelineTextInputView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTSinglelineTextInputView.h; sourceTree = ""; }; + 5956B105200FEBA9008D9D16 /* RCTUITextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTUITextField.h; sourceTree = ""; }; + 5956B106200FEBA9008D9D16 /* RCTSinglelineTextInputViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSinglelineTextInputViewManager.m; sourceTree = ""; }; + 5956B107200FEBA9008D9D16 /* RCTBackedTextInputDelegateAdapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBackedTextInputDelegateAdapter.h; sourceTree = ""; }; + 5956B108200FEBA9008D9D16 /* RCTTextSelection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTextSelection.h; sourceTree = ""; }; + 5956B109200FEBA9008D9D16 /* RCTBaseTextInputShadowView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBaseTextInputShadowView.h; sourceTree = ""; }; + 5956B10A200FEBA9008D9D16 /* RCTBaseTextInputView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBaseTextInputView.m; sourceTree = ""; }; + 5956B10B200FEBA9008D9D16 /* RCTBaseTextInputViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBaseTextInputViewManager.h; sourceTree = ""; }; + 5956B10C200FEBA9008D9D16 /* RCTBackedTextInputDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBackedTextInputDelegate.h; sourceTree = ""; }; + 5956B10D200FEBA9008D9D16 /* RCTBackedTextInputDelegateAdapter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBackedTextInputDelegateAdapter.m; sourceTree = ""; }; + 5956B10E200FEBA9008D9D16 /* RCTBaseTextInputView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBaseTextInputView.h; sourceTree = ""; }; + 5956B10F200FEBA9008D9D16 /* RCTBaseTextInputShadowView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBaseTextInputShadowView.m; sourceTree = ""; }; + 5956B110200FEBA9008D9D16 /* RCTTextSelection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTextSelection.m; sourceTree = ""; }; + 5956B111200FEBA9008D9D16 /* RCTBaseTextInputViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBaseTextInputViewManager.m; sourceTree = ""; }; + 5956B112200FEBA9008D9D16 /* RCTBackedTextInputViewProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBackedTextInputViewProtocol.h; sourceTree = ""; }; + 5956B114200FEBA9008D9D16 /* RCTMultilineTextInputViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTMultilineTextInputViewManager.h; sourceTree = ""; }; + 5956B115200FEBA9008D9D16 /* RCTMultilineTextInputView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTMultilineTextInputView.m; sourceTree = ""; }; + 5956B116200FEBA9008D9D16 /* RCTUITextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTUITextView.h; sourceTree = ""; }; + 5956B117200FEBA9008D9D16 /* RCTMultilineTextInputView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTMultilineTextInputView.h; sourceTree = ""; }; + 5956B118200FEBA9008D9D16 /* RCTMultilineTextInputViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTMultilineTextInputViewManager.m; sourceTree = ""; }; + 5956B119200FEBA9008D9D16 /* RCTUITextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTUITextView.m; sourceTree = ""; }; + 5956B11A200FEBA9008D9D16 /* RCTTextAttributes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTextAttributes.h; sourceTree = ""; }; + 5956B11C200FEBA9008D9D16 /* RCTBaseTextViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBaseTextViewManager.h; sourceTree = ""; }; + 5956B11D200FEBA9008D9D16 /* RCTBaseTextShadowView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBaseTextShadowView.h; sourceTree = ""; }; + 5956B11E200FEBA9008D9D16 /* RCTBaseTextShadowView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBaseTextShadowView.m; sourceTree = ""; }; + 5956B11F200FEBA9008D9D16 /* RCTBaseTextViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBaseTextViewManager.m; sourceTree = ""; }; + 5956B120200FEBA9008D9D16 /* RCTTextAttributes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTextAttributes.m; sourceTree = ""; }; + 5956B122200FEBAA008D9D16 /* RCTTextShadowView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTextShadowView.m; sourceTree = ""; }; + 5956B123200FEBAA008D9D16 /* RCTTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTextView.h; sourceTree = ""; }; + 5956B124200FEBAA008D9D16 /* RCTTextViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTextViewManager.h; sourceTree = ""; }; + 5956B125200FEBAA008D9D16 /* NSTextStorage+FontScaling.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSTextStorage+FontScaling.m"; sourceTree = ""; }; + 5956B126200FEBAA008D9D16 /* RCTTextShadowView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTTextShadowView.h; sourceTree = ""; }; + 5956B127200FEBAA008D9D16 /* RCTTextViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTextViewManager.m; sourceTree = ""; }; + 5956B128200FEBAA008D9D16 /* RCTTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTTextView.m; sourceTree = ""; }; + 5956B129200FEBAA008D9D16 /* NSTextStorage+FontScaling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSTextStorage+FontScaling.h"; sourceTree = ""; }; + 5956B12B200FEBAA008D9D16 /* RCTVirtualTextViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTVirtualTextViewManager.m; sourceTree = ""; }; + 5956B12C200FEBAA008D9D16 /* RCTVirtualTextShadowView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTVirtualTextShadowView.h; sourceTree = ""; }; + 5956B12D200FEBAA008D9D16 /* RCTVirtualTextViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTVirtualTextViewManager.h; sourceTree = ""; }; + 5956B12E200FEBAA008D9D16 /* RCTVirtualTextShadowView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTVirtualTextShadowView.m; sourceTree = ""; }; + 5956B12F200FEBAA008D9D16 /* RCTConvert+Text.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RCTConvert+Text.m"; sourceTree = ""; }; + 70588F6822273F2300CD1EEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; + 70588F6A222741EC00CD1EEA /* RCTFieldEditor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTFieldEditor.h; sourceTree = ""; }; + 70588F6B222741EC00CD1EEA /* RCTFieldEditor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTFieldEditor.m; sourceTree = ""; }; + 70588F6E2227427600CD1EEA /* NSText+Editing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSText+Editing.m"; sourceTree = ""; }; + 70588F6F2227427700CD1EEA /* NSText+Editing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSText+Editing.h"; sourceTree = ""; }; + 705EDE2E22132863000CAA67 /* NSBezierPath+CGPath.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSBezierPath+CGPath.h"; sourceTree = ""; }; + 705EDE2F22132863000CAA67 /* NSBezierPath+CGPath.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSBezierPath+CGPath.m"; sourceTree = ""; }; + 705EDE3B221378CC000CAA67 /* NSFont+LineHeight.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSFont+LineHeight.h"; sourceTree = ""; }; + 705EDE3C221378CC000CAA67 /* NSFont+LineHeight.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSFont+LineHeight.m"; sourceTree = ""; }; + 705EDE3E22137BE7000CAA67 /* NSValue+CoreGraphics.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSValue+CoreGraphics.h"; sourceTree = ""; }; + 705EDE3F22137BE7000CAA67 /* NSValue+CoreGraphics.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSValue+CoreGraphics.m"; sourceTree = ""; }; + 705EDE422213890E000CAA67 /* NSLabel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NSLabel.m; sourceTree = ""; }; + 705EDE4422138919000CAA67 /* NSLabel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NSLabel.h; sourceTree = ""; }; /* End PBXFileReference section */ +/* Begin PBXFrameworksBuildPhase section */ + 70588F6622273F1B00CD1EEA /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 70588F6922273F2300CD1EEA /* AppKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + /* Begin PBXGroup section */ 58B511921A9E6C1200147676 = { isa = PBXGroup; children = ( - D4EEE302201FA3A100C4CBB6 /* TextInputLegacy */, + 70588F6F2227427700CD1EEA /* NSText+Editing.h */, + 70588F6E2227427600CD1EEA /* NSText+Editing.m */, + 705EDE4422138919000CAA67 /* NSLabel.h */, + 705EDE422213890E000CAA67 /* NSLabel.m */, + 705EDE3E22137BE7000CAA67 /* NSValue+CoreGraphics.h */, + 705EDE3F22137BE7000CAA67 /* NSValue+CoreGraphics.m */, + 705EDE3B221378CC000CAA67 /* NSFont+LineHeight.h */, + 705EDE3C221378CC000CAA67 /* NSFont+LineHeight.m */, + 705EDE2E22132863000CAA67 /* NSBezierPath+CGPath.h */, + 705EDE2F22132863000CAA67 /* NSBezierPath+CGPath.m */, + 5956B11B200FEBA9008D9D16 /* BaseText */, 58B5119C1A9E6C1200147676 /* Products */, - A85C82981F742AA20036C019 /* RCTFontAttributes.h */, - A85C82991F742AA20036C019 /* RCTFontAttributes.m */, - A85C82BA1F742D8F0036C019 /* RCTFontAttributesDelegate.h */, - 59E6042C1FE9CAF100BD90C5 /* RCTRawTextShadowView.h */, - 59E604341FE9CAF100BD90C5 /* RCTRawTextShadowView.m */, - 59E604351FE9CAF100BD90C5 /* RCTRawTextViewManager.h */, - 59E604361FE9CAF100BD90C5 /* RCTRawTextViewManager.m */, - 59E6042D1FE9CAF100BD90C5 /* Text */, + 5956B0FA200FEBA9008D9D16 /* RawText */, + 5956B0F9200FEBA9008D9D16 /* RCTConvert+Text.h */, + 5956B12F200FEBAA008D9D16 /* RCTConvert+Text.m */, + 5956B11A200FEBA9008D9D16 /* RCTTextAttributes.h */, + 5956B120200FEBA9008D9D16 /* RCTTextAttributes.m */, + 5956B121200FEBAA008D9D16 /* Text */, + 5956B0FF200FEBA9008D9D16 /* TextInput */, + 5956B12A200FEBAA008D9D16 /* VirtualText */, + 70588F6722273F2200CD1EEA /* Frameworks */, ); indentWidth = 2; sourceTree = ""; @@ -141,74 +225,125 @@ isa = PBXGroup; children = ( 58B5119B1A9E6C1200147676 /* libRCTText.a */, - 2D2A287B1D9B048500D4039D /* libRCTText-tvOS.a */, ); name = Products; sourceTree = ""; }; - 59E6042D1FE9CAF100BD90C5 /* Text */ = { + 5956B0FA200FEBA9008D9D16 /* RawText */ = { isa = PBXGroup; children = ( - 59E6042E1FE9CAF100BD90C5 /* RCTTextShadowView.h */, - 59E6042F1FE9CAF100BD90C5 /* RCTTextShadowView.m */, - 59E604301FE9CAF100BD90C5 /* RCTTextView.h */, - 59E604311FE9CAF100BD90C5 /* RCTTextView.m */, - 59E604321FE9CAF100BD90C5 /* RCTTextViewManager.h */, - 59E604331FE9CAF100BD90C5 /* RCTTextViewManager.m */, + 5956B0FC200FEBA9008D9D16 /* RCTRawTextShadowView.h */, + 5956B0FD200FEBA9008D9D16 /* RCTRawTextShadowView.m */, + 5956B0FB200FEBA9008D9D16 /* RCTRawTextViewManager.h */, + 5956B0FE200FEBA9008D9D16 /* RCTRawTextViewManager.m */, ); - path = Text; + path = RawText; sourceTree = ""; }; - D4EEE302201FA3A100C4CBB6 /* TextInputLegacy */ = { + 5956B0FF200FEBA9008D9D16 /* TextInput */ = { isa = PBXGroup; children = ( - D4EEE30E201FA3B200C4CBB6 /* RCTMultilineTextInputView.h */, - D4EEE303201FA3B100C4CBB6 /* RCTMultilineTextInputView.m */, - D4EEE30A201FA3B100C4CBB6 /* RCTSecureTextField.h */, - D4EEE312201FA3B200C4CBB6 /* RCTSecureTextField.m */, - D4EEE304201FA3B100C4CBB6 /* RCTShadowTextField.h */, - D4EEE315201FA3B300C4CBB6 /* RCTShadowTextField.m */, - D4EEE305201FA3B100C4CBB6 /* RCTShadowTextView.h */, - D4EEE30C201FA3B200C4CBB6 /* RCTShadowTextView.m */, - D4EEE306201FA3B100C4CBB6 /* RCTTextField.h */, - D4EEE313201FA3B200C4CBB6 /* RCTTextField.m */, - D4EEE308201FA3B100C4CBB6 /* RCTTextFieldManager.h */, - D4EEE310201FA3B200C4CBB6 /* RCTTextFieldManager.m */, - D4EEE309201FA3B100C4CBB6 /* RCTTextSelection.h */, - D4EEE30D201FA3B200C4CBB6 /* RCTTextSelection.m */, - D4EEE30F201FA3B200C4CBB6 /* RCTTextViewManager.h */, - D4EEE316201FA3B300C4CBB6 /* RCTTextViewManager.m */, - D4EEE311201FA3B200C4CBB6 /* RCTUITextView.h */, - D4EEE307201FA3B100C4CBB6 /* RCTUITextView.m */, + 5956B113200FEBA9008D9D16 /* Multiline */, + 5956B10C200FEBA9008D9D16 /* RCTBackedTextInputDelegate.h */, + 5956B107200FEBA9008D9D16 /* RCTBackedTextInputDelegateAdapter.h */, + 5956B10D200FEBA9008D9D16 /* RCTBackedTextInputDelegateAdapter.m */, + 5956B112200FEBA9008D9D16 /* RCTBackedTextInputViewProtocol.h */, + 5956B109200FEBA9008D9D16 /* RCTBaseTextInputShadowView.h */, + 5956B10F200FEBA9008D9D16 /* RCTBaseTextInputShadowView.m */, + 5956B10E200FEBA9008D9D16 /* RCTBaseTextInputView.h */, + 5956B10A200FEBA9008D9D16 /* RCTBaseTextInputView.m */, + 5956B10B200FEBA9008D9D16 /* RCTBaseTextInputViewManager.h */, + 5956B111200FEBA9008D9D16 /* RCTBaseTextInputViewManager.m */, + 5956B108200FEBA9008D9D16 /* RCTTextSelection.h */, + 5956B110200FEBA9008D9D16 /* RCTTextSelection.m */, + 5956B100200FEBA9008D9D16 /* Singleline */, ); - name = TextInputLegacy; + path = TextInput; sourceTree = ""; }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 2D2A287A1D9B048500D4039D /* RCTText-tvOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 2D2A28831D9B048500D4039D /* Build configuration list for PBXNativeTarget "RCTText-tvOS" */; - buildPhases = ( - 599DF2601F0306AD0079B53E /* Copy Headers */, - 2D2A28771D9B048500D4039D /* Sources */, + 5956B100200FEBA9008D9D16 /* Singleline */ = { + isa = PBXGroup; + children = ( + 70588F6A222741EC00CD1EEA /* RCTFieldEditor.h */, + 70588F6B222741EC00CD1EEA /* RCTFieldEditor.m */, + 5956B104200FEBA9008D9D16 /* RCTSinglelineTextInputView.h */, + 5956B101200FEBA9008D9D16 /* RCTSinglelineTextInputView.m */, + 5956B102200FEBA9008D9D16 /* RCTSinglelineTextInputViewManager.h */, + 5956B106200FEBA9008D9D16 /* RCTSinglelineTextInputViewManager.m */, + 5956B105200FEBA9008D9D16 /* RCTUITextField.h */, + 5956B103200FEBA9008D9D16 /* RCTUITextField.m */, ); - buildRules = ( + path = Singleline; + sourceTree = ""; + }; + 5956B113200FEBA9008D9D16 /* Multiline */ = { + isa = PBXGroup; + children = ( + 5956B117200FEBA9008D9D16 /* RCTMultilineTextInputView.h */, + 5956B115200FEBA9008D9D16 /* RCTMultilineTextInputView.m */, + 5956B114200FEBA9008D9D16 /* RCTMultilineTextInputViewManager.h */, + 5956B118200FEBA9008D9D16 /* RCTMultilineTextInputViewManager.m */, + 5956B116200FEBA9008D9D16 /* RCTUITextView.h */, + 5956B119200FEBA9008D9D16 /* RCTUITextView.m */, ); - dependencies = ( + path = Multiline; + sourceTree = ""; + }; + 5956B11B200FEBA9008D9D16 /* BaseText */ = { + isa = PBXGroup; + children = ( + 5956B11D200FEBA9008D9D16 /* RCTBaseTextShadowView.h */, + 5956B11E200FEBA9008D9D16 /* RCTBaseTextShadowView.m */, + 5956B11C200FEBA9008D9D16 /* RCTBaseTextViewManager.h */, + 5956B11F200FEBA9008D9D16 /* RCTBaseTextViewManager.m */, ); - name = "RCTText-tvOS"; - productName = "RCTText-tvOS"; - productReference = 2D2A287B1D9B048500D4039D /* libRCTText-tvOS.a */; - productType = "com.apple.product-type.library.static"; + path = BaseText; + sourceTree = ""; + }; + 5956B121200FEBAA008D9D16 /* Text */ = { + isa = PBXGroup; + children = ( + 5956B129200FEBAA008D9D16 /* NSTextStorage+FontScaling.h */, + 5956B125200FEBAA008D9D16 /* NSTextStorage+FontScaling.m */, + 5956B126200FEBAA008D9D16 /* RCTTextShadowView.h */, + 5956B122200FEBAA008D9D16 /* RCTTextShadowView.m */, + 5956B123200FEBAA008D9D16 /* RCTTextView.h */, + 5956B128200FEBAA008D9D16 /* RCTTextView.m */, + 5956B124200FEBAA008D9D16 /* RCTTextViewManager.h */, + 5956B127200FEBAA008D9D16 /* RCTTextViewManager.m */, + ); + path = Text; + sourceTree = ""; }; + 5956B12A200FEBAA008D9D16 /* VirtualText */ = { + isa = PBXGroup; + children = ( + 5956B12C200FEBAA008D9D16 /* RCTVirtualTextShadowView.h */, + 5956B12E200FEBAA008D9D16 /* RCTVirtualTextShadowView.m */, + 5956B12D200FEBAA008D9D16 /* RCTVirtualTextViewManager.h */, + 5956B12B200FEBAA008D9D16 /* RCTVirtualTextViewManager.m */, + ); + path = VirtualText; + sourceTree = ""; + }; + 70588F6722273F2200CD1EEA /* Frameworks */ = { + isa = PBXGroup; + children = ( + 70588F6822273F2300CD1EEA /* AppKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ 58B5119A1A9E6C1200147676 /* RCTText */ = { isa = PBXNativeTarget; buildConfigurationList = 58B511AF1A9E6C1300147676 /* Build configuration list for PBXNativeTarget "RCTText" */; buildPhases = ( 599DF25E1F0306540079B53E /* Copy Headers */, 58B511971A9E6C1200147676 /* Sources */, + 70588F6622273F1B00CD1EEA /* Frameworks */, ); buildRules = ( ); @@ -228,10 +363,6 @@ LastUpgradeCheck = 0610; ORGANIZATIONNAME = Facebook; TargetAttributes = { - 2D2A287A1D9B048500D4039D = { - CreatedOnToolsVersion = 8.0; - ProvisioningStyle = Automatic; - }; 58B5119A1A9E6C1200147676 = { CreatedOnToolsVersion = 6.1.1; }; @@ -250,84 +381,50 @@ projectRoot = ""; targets = ( 58B5119A1A9E6C1200147676 /* RCTText */, - 2D2A287A1D9B048500D4039D /* RCTText-tvOS */, ); }; /* End PBXProject section */ /* Begin PBXSourcesBuildPhase section */ - 2D2A28771D9B048500D4039D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 59E604571FE9CAF100BD90C5 /* RCTTextViewManager.m in Sources */, - 59E604531FE9CAF100BD90C5 /* RCTTextShadowView.m in Sources */, - 59E604591FE9CAF100BD90C5 /* RCTRawTextShadowView.m in Sources */, - 59E604551FE9CAF100BD90C5 /* RCTTextView.m in Sources */, - 59E8C5CC1F8833D100204F5E /* RCTFontAttributes.m in Sources */, - 59E6045B1FE9CAF100BD90C5 /* RCTRawTextViewManager.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 58B511971A9E6C1200147676 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 59E604561FE9CAF100BD90C5 /* RCTTextViewManager.m in Sources */, - D4EEE318201FA3B300C4CBB6 /* RCTUITextView.m in Sources */, - D4EEE31C201FA3B300C4CBB6 /* RCTTextFieldManager.m in Sources */, - D4EEE31D201FA3B300C4CBB6 /* RCTSecureTextField.m in Sources */, - 59E604521FE9CAF100BD90C5 /* RCTTextShadowView.m in Sources */, - D4EEE320201FA3B300C4CBB6 /* RCTTextViewManager.m in Sources */, - D4EEE31A201FA3B300C4CBB6 /* RCTShadowTextView.m in Sources */, - D4EEE31F201FA3B300C4CBB6 /* RCTShadowTextField.m in Sources */, - D4EEE31B201FA3B300C4CBB6 /* RCTTextSelection.m in Sources */, - D4EEE317201FA3B300C4CBB6 /* RCTMultilineTextInputView.m in Sources */, - 59E604581FE9CAF100BD90C5 /* RCTRawTextShadowView.m in Sources */, - D4EEE31E201FA3B300C4CBB6 /* RCTTextField.m in Sources */, - 59E604541FE9CAF100BD90C5 /* RCTTextView.m in Sources */, - A85C829A1F742AA20036C019 /* RCTFontAttributes.m in Sources */, - 59E6045A1FE9CAF100BD90C5 /* RCTRawTextViewManager.m in Sources */, + 70588F652227336100CD1EEA /* NSLabel.m in Sources */, + 5956B13D200FEBAA008D9D16 /* RCTBaseTextShadowView.m in Sources */, + 5956B140200FEBAA008D9D16 /* RCTTextShadowView.m in Sources */, + 5956B131200FEBAA008D9D16 /* RCTRawTextViewManager.m in Sources */, + 5956B137200FEBAA008D9D16 /* RCTBaseTextInputShadowView.m in Sources */, + 5956B146200FEBAA008D9D16 /* RCTConvert+Text.m in Sources */, + 5956B13F200FEBAA008D9D16 /* RCTTextAttributes.m in Sources */, + 5956B143200FEBAA008D9D16 /* RCTTextView.m in Sources */, + 5956B13C200FEBAA008D9D16 /* RCTUITextView.m in Sources */, + 5956B136200FEBAA008D9D16 /* RCTBackedTextInputDelegateAdapter.m in Sources */, + 5956B13E200FEBAA008D9D16 /* RCTBaseTextViewManager.m in Sources */, + 70588F6C222741ED00CD1EEA /* RCTFieldEditor.m in Sources */, + 5956B145200FEBAA008D9D16 /* RCTVirtualTextShadowView.m in Sources */, + 5956B142200FEBAA008D9D16 /* RCTTextViewManager.m in Sources */, + 705EDE4022137BE7000CAA67 /* NSValue+CoreGraphics.m in Sources */, + 705EDE3022132863000CAA67 /* NSBezierPath+CGPath.m in Sources */, + 5956B135200FEBAA008D9D16 /* RCTBaseTextInputView.m in Sources */, + 5956B144200FEBAA008D9D16 /* RCTVirtualTextViewManager.m in Sources */, + 5956B13B200FEBAA008D9D16 /* RCTMultilineTextInputViewManager.m in Sources */, + 5956B134200FEBAA008D9D16 /* RCTSinglelineTextInputViewManager.m in Sources */, + 705EDE3D221378CC000CAA67 /* NSFont+LineHeight.m in Sources */, + 5956B139200FEBAA008D9D16 /* RCTBaseTextInputViewManager.m in Sources */, + 5956B138200FEBAA008D9D16 /* RCTTextSelection.m in Sources */, + 5956B130200FEBAA008D9D16 /* RCTRawTextShadowView.m in Sources */, + 5956B141200FEBAA008D9D16 /* NSTextStorage+FontScaling.m in Sources */, + 70588F702227427700CD1EEA /* NSText+Editing.m in Sources */, + 5956B132200FEBAA008D9D16 /* RCTSinglelineTextInputView.m in Sources */, + 5956B13A200FEBAA008D9D16 /* RCTMultilineTextInputView.m in Sources */, + 5956B133200FEBAA008D9D16 /* RCTUITextField.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ - 2D2A28811D9B048500D4039D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_SUSPICIOUS_MOVES = YES; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_TESTABILITY = YES; - GCC_NO_COMMON_BLOCKS = YES; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = appletvos; - TVOS_DEPLOYMENT_TARGET = 9.2; - }; - name = Debug; - }; - 2D2A28821D9B048500D4039D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_SUSPICIOUS_MOVES = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - GCC_NO_COMMON_BLOCKS = YES; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = appletvos; - TVOS_DEPLOYMENT_TARGET = 9.2; - }; - name = Release; - }; 58B511AD1A9E6C1300147676 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -444,15 +541,6 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 2D2A28831D9B048500D4039D /* Build configuration list for PBXNativeTarget "RCTText-tvOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 2D2A28811D9B048500D4039D /* Debug */, - 2D2A28821D9B048500D4039D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 58B511961A9E6C1200147676 /* Build configuration list for PBXProject "RCTText" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Libraries/Text/RCTTextAttributes.h b/Libraries/Text/RCTTextAttributes.h new file mode 100644 index 0000000000..32e6d24ef6 --- /dev/null +++ b/Libraries/Text/RCTTextAttributes.h @@ -0,0 +1,85 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import + +#import + +NS_ASSUME_NONNULL_BEGIN + +extern NSString *const RCTTextAttributesIsHighlightedAttributeName; +extern NSString *const RCTTextAttributesTagAttributeName; + +/** + * Represents knowledge about all supported *text* attributes + * assigned to some text component such as , , + * and . + */ +@interface RCTTextAttributes : NSObject + +// Color +@property (nonatomic, strong, nullable) NSColor *foregroundColor; +@property (nonatomic, strong, nullable) NSColor *backgroundColor; +@property (nonatomic, assign) CGFloat opacity; +// Font +@property (nonatomic, copy, nullable) NSString *fontFamily; +@property (nonatomic, assign) CGFloat fontSize; +@property (nonatomic, assign) CGFloat fontSizeMultiplier; +@property (nonatomic, copy, nullable) NSString *fontWeight; +@property (nonatomic, copy, nullable) NSString *fontStyle; +@property (nonatomic, copy, nullable) NSArray *fontVariant; +@property (nonatomic, assign) BOOL allowFontScaling; +@property (nonatomic, assign) CGFloat letterSpacing; +// Paragraph Styles +@property (nonatomic, assign) CGFloat lineHeight; +@property (nonatomic, assign) NSTextAlignment alignment; +@property (nonatomic, assign) NSWritingDirection baseWritingDirection; +// Decoration +@property (nonatomic, strong, nullable) NSColor *textDecorationColor; +@property (nonatomic, assign) NSUnderlineStyle textDecorationStyle; +@property (nonatomic, assign) RCTTextDecorationLineType textDecorationLine; +// Shadow +@property (nonatomic, assign) CGSize textShadowOffset; +@property (nonatomic, assign) CGFloat textShadowRadius; +@property (nonatomic, strong, nullable) NSColor *textShadowColor; +// Special +@property (nonatomic, assign) BOOL isHighlighted; +@property (nonatomic, strong, nullable) NSNumber *tag; +@property (nonatomic, assign) NSUserInterfaceLayoutDirection layoutDirection; + +#pragma mark - Inheritance + +- (void)applyTextAttributes:(RCTTextAttributes *)textAttributes; + +#pragma mark - Adapters + +/** + * Text attributes in NSAttributedString terms. + */ +- (NSDictionary *)effectiveTextAttributes; + +/** + * Constructed font. + */ +- (NSFont *)effectiveFont; + +/** + * Font size multiplier reflects `allowFontScaling` and `fontSizeMultiplier`. + */ +- (CGFloat)effectiveFontSizeMultiplier; + +/** + * Foreground and background colors with opacity and right defaults. + */ +- (NSColor *)effectiveForegroundColor; +- (NSColor *)effectiveBackgroundColor; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Libraries/Text/RCTTextAttributes.m b/Libraries/Text/RCTTextAttributes.m new file mode 100644 index 0000000000..530b5dcb3a --- /dev/null +++ b/Libraries/Text/RCTTextAttributes.m @@ -0,0 +1,270 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "RCTTextAttributes.h" + +#import +#import +#import + +NSString *const RCTTextAttributesIsHighlightedAttributeName = @"RCTTextAttributesIsHighlightedAttributeName"; +NSString *const RCTTextAttributesTagAttributeName = @"RCTTextAttributesTagAttributeName"; + +@implementation RCTTextAttributes + +- (instancetype)init +{ + if (self = [super init]) { + _fontSize = NAN; + _letterSpacing = NAN; + _textDecorationStyle = NSUnderlineStyleSingle; + _fontSizeMultiplier = NAN; + _alignment = NSTextAlignmentNatural; + _baseWritingDirection = NSWritingDirectionNatural; + _textShadowRadius = NAN; + _opacity = NAN; + } + + return self; +} + +- (void)applyTextAttributes:(RCTTextAttributes *)textAttributes +{ + // Note: All lines marked with `*` does not use explicit/correct rules to compare old and new values becuase + // their types do not have special designated value representing undefined/unspecified/inherit meaning. + // We will address this in the future. + + // Color + _foregroundColor = textAttributes->_foregroundColor ?: _foregroundColor; + _backgroundColor = textAttributes->_backgroundColor ?: _backgroundColor; + _opacity = !isnan(textAttributes->_opacity) ? (isnan(_opacity) ? 1.0 : _opacity) * textAttributes->_opacity : _opacity; + + // Font + _fontFamily = textAttributes->_fontFamily ?: _fontFamily; + _fontSize = !isnan(textAttributes->_fontSize) ? textAttributes->_fontSize : _fontSize; + _fontSizeMultiplier = !isnan(textAttributes->_fontSizeMultiplier) ? textAttributes->_fontSizeMultiplier : _fontSizeMultiplier; + _fontWeight = textAttributes->_fontWeight ?: _fontWeight; + _fontStyle = textAttributes->_fontStyle ?: _fontStyle; + _fontVariant = textAttributes->_fontVariant ?: _fontVariant; + _allowFontScaling = textAttributes->_allowFontScaling || _allowFontScaling; // * + _letterSpacing = !isnan(textAttributes->_letterSpacing) ? textAttributes->_letterSpacing : _letterSpacing; + + // Paragraph Styles + _lineHeight = !isnan(textAttributes->_lineHeight) ? textAttributes->_lineHeight : _lineHeight; + _alignment = textAttributes->_alignment != NSTextAlignmentNatural ? textAttributes->_alignment : _alignment; // * + _baseWritingDirection = textAttributes->_baseWritingDirection != NSWritingDirectionNatural ? textAttributes->_baseWritingDirection : _baseWritingDirection; // * + + // Decoration + _textDecorationColor = textAttributes->_textDecorationColor ?: _textDecorationColor; + _textDecorationStyle = textAttributes->_textDecorationStyle != NSUnderlineStyleSingle ? textAttributes->_textDecorationStyle : _textDecorationStyle; // * + _textDecorationLine = textAttributes->_textDecorationLine != RCTTextDecorationLineTypeNone ? textAttributes->_textDecorationLine : _textDecorationLine; // * + + // Shadow + _textShadowOffset = !CGSizeEqualToSize(textAttributes->_textShadowOffset, CGSizeZero) ? textAttributes->_textShadowOffset : _textShadowOffset; // * + _textShadowRadius = !isnan(textAttributes->_textShadowRadius) ? textAttributes->_textShadowRadius : _textShadowRadius; + _textShadowColor = textAttributes->_textShadowColor ?: _textShadowColor; + + // Special + _isHighlighted = textAttributes->_isHighlighted || _isHighlighted; // * + _tag = textAttributes->_tag ?: _tag; + _layoutDirection = textAttributes->_layoutDirection != NSUserInterfaceLayoutDirectionLeftToRight ? textAttributes->_layoutDirection : _layoutDirection; +} + +- (NSDictionary *)effectiveTextAttributes +{ + NSMutableDictionary *attributes = + [NSMutableDictionary dictionaryWithCapacity:10]; + + // Font + NSFont *font = self.effectiveFont; + if (font) { + attributes[NSFontAttributeName] = font; + } + + // Colors + NSColor *effectiveForegroundColor = self.effectiveForegroundColor; + + if (_foregroundColor || !isnan(_opacity)) { + attributes[NSForegroundColorAttributeName] = effectiveForegroundColor; + } + + if (_backgroundColor || !isnan(_opacity)) { + attributes[NSBackgroundColorAttributeName] = self.effectiveBackgroundColor; + } + + // Kerning + if (!isnan(_letterSpacing)) { + attributes[NSKernAttributeName] = @(_letterSpacing); + } + + // Paragraph Style + NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new]; + BOOL isParagraphStyleUsed = NO; + if (_alignment != NSTextAlignmentNatural) { + NSTextAlignment alignment = _alignment; + if (_layoutDirection == NSUserInterfaceLayoutDirectionRightToLeft) { + if (alignment == NSTextAlignmentRight) { + alignment = NSTextAlignmentLeft; + } else if (alignment == NSTextAlignmentLeft) { + alignment = NSTextAlignmentRight; + } + } + + paragraphStyle.alignment = alignment; + isParagraphStyleUsed = YES; + } + + if (_baseWritingDirection != NSWritingDirectionNatural) { + paragraphStyle.baseWritingDirection = _baseWritingDirection; + isParagraphStyleUsed = YES; + } + + if (!isnan(_lineHeight)) { + CGFloat lineHeight = _lineHeight * self.effectiveFontSizeMultiplier; + paragraphStyle.minimumLineHeight = lineHeight; + paragraphStyle.maximumLineHeight = lineHeight; + isParagraphStyleUsed = YES; + } + + if (isParagraphStyleUsed) { + attributes[NSParagraphStyleAttributeName] = paragraphStyle; + } + + // Decoration + BOOL isTextDecorationEnabled = NO; + if (_textDecorationLine == RCTTextDecorationLineTypeUnderline || + _textDecorationLine == RCTTextDecorationLineTypeUnderlineStrikethrough) { + isTextDecorationEnabled = YES; + attributes[NSUnderlineStyleAttributeName] = @(_textDecorationStyle); + } + + if (_textDecorationLine == RCTTextDecorationLineTypeStrikethrough || + _textDecorationLine == RCTTextDecorationLineTypeUnderlineStrikethrough){ + isTextDecorationEnabled = YES; + attributes[NSStrikethroughStyleAttributeName] = @(_textDecorationStyle); + } + + if (_textDecorationColor || isTextDecorationEnabled) { + attributes[NSStrikethroughColorAttributeName] = _textDecorationColor ?: effectiveForegroundColor; + attributes[NSUnderlineColorAttributeName] = _textDecorationColor ?: effectiveForegroundColor; + } + + // Shadow + if (!CGSizeEqualToSize(_textShadowOffset, CGSizeZero)) { + NSShadow *shadow = [NSShadow new]; + shadow.shadowOffset = _textShadowOffset; + shadow.shadowBlurRadius = _textShadowRadius; + shadow.shadowColor = _textShadowColor; + attributes[NSShadowAttributeName] = shadow; + } + + // Special + if (_isHighlighted) { + attributes[RCTTextAttributesIsHighlightedAttributeName] = @YES; + } + + if (_tag) { + attributes[RCTTextAttributesTagAttributeName] = _tag; + } + + return [attributes copy]; +} + +- (NSFont *)effectiveFont +{ + // FIXME: RCTFont has thread-safety issues and must be rewritten. + return [RCTFont updateFont:nil + withFamily:_fontFamily + size:@(isnan(_fontSize) ? 0 : _fontSize) + weight:_fontWeight + style:_fontStyle + variant:_fontVariant + scaleMultiplier:self.effectiveFontSizeMultiplier]; +} + +- (CGFloat)effectiveFontSizeMultiplier +{ + return _allowFontScaling && !isnan(_fontSizeMultiplier) ? _fontSizeMultiplier : 1.0; +} + +- (NSColor *)effectiveForegroundColor +{ + NSColor *effectiveForegroundColor = _foregroundColor ?: [NSColor blackColor]; + + if (!isnan(_opacity)) { + effectiveForegroundColor = [effectiveForegroundColor colorWithAlphaComponent:CGColorGetAlpha(effectiveForegroundColor.CGColor) * _opacity]; + } + + return effectiveForegroundColor; +} + +- (NSColor *)effectiveBackgroundColor +{ + NSColor *effectiveBackgroundColor = _backgroundColor;// ?: [[NSColor whiteColor] colorWithAlphaComponent:0]; + + if (effectiveBackgroundColor && !isnan(_opacity)) { + effectiveBackgroundColor = [effectiveBackgroundColor colorWithAlphaComponent:CGColorGetAlpha(effectiveBackgroundColor.CGColor) * _opacity]; + } + + return effectiveBackgroundColor ?: [NSColor clearColor]; +} + +- (RCTTextAttributes *)copyWithZone:(NSZone *)zone +{ + RCTTextAttributes *textAttributes = [RCTTextAttributes new]; + [textAttributes applyTextAttributes:self]; + return textAttributes; +} + +#pragma mark - NSObject + +- (BOOL)isEqual:(RCTTextAttributes *)textAttributes +{ + if (self == textAttributes) { + return YES; + } + +#define RCTTextAttributesCompareFloats(a) ((a == textAttributes->a) || (isnan(a) && isnan(textAttributes->a))) +#define RCTTextAttributesCompareSize(a) CGSizeEqualToSize(a, textAttributes->a) +#define RCTTextAttributesCompareObjects(a) ((a == textAttributes->a) || [a isEqual:textAttributes->a]) +#define RCTTextAttributesCompareStrings(a) ((a == textAttributes->a) || [a isEqualToString:textAttributes->a]) +#define RCTTextAttributesCompareOthers(a) (a == textAttributes->a) + + return + RCTTextAttributesCompareObjects(_foregroundColor) && + RCTTextAttributesCompareObjects(_backgroundColor) && + RCTTextAttributesCompareFloats(_opacity) && + // Font + RCTTextAttributesCompareObjects(_fontFamily) && + RCTTextAttributesCompareFloats(_fontSize) && + RCTTextAttributesCompareFloats(_fontSizeMultiplier) && + RCTTextAttributesCompareStrings(_fontWeight) && + RCTTextAttributesCompareObjects(_fontStyle) && + RCTTextAttributesCompareObjects(_fontVariant) && + RCTTextAttributesCompareOthers(_allowFontScaling) && + RCTTextAttributesCompareFloats(_letterSpacing) && + // Paragraph Styles + RCTTextAttributesCompareFloats(_lineHeight) && + RCTTextAttributesCompareFloats(_alignment) && + RCTTextAttributesCompareOthers(_baseWritingDirection) && + // Decoration + RCTTextAttributesCompareObjects(_textDecorationColor) && + RCTTextAttributesCompareOthers(_textDecorationStyle) && + RCTTextAttributesCompareOthers(_textDecorationLine) && + // Shadow + RCTTextAttributesCompareSize(_textShadowOffset) && + RCTTextAttributesCompareFloats(_textShadowRadius) && + RCTTextAttributesCompareObjects(_textShadowColor) && + // Special + RCTTextAttributesCompareOthers(_isHighlighted) && + RCTTextAttributesCompareObjects(_tag) && + RCTTextAttributesCompareOthers(_layoutDirection); +} + +@end diff --git a/Libraries/Text/RawText/RCTRawTextShadowView.h b/Libraries/Text/RawText/RCTRawTextShadowView.h new file mode 100644 index 0000000000..52e61f0ba9 --- /dev/null +++ b/Libraries/Text/RawText/RCTRawTextShadowView.h @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface RCTRawTextShadowView : RCTShadowView + +@property (nonatomic, copy, nullable) NSString *text; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Libraries/Text/RawText/RCTRawTextShadowView.m b/Libraries/Text/RawText/RCTRawTextShadowView.m new file mode 100644 index 0000000000..d350d29684 --- /dev/null +++ b/Libraries/Text/RawText/RCTRawTextShadowView.m @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "RCTRawTextShadowView.h" + +#import + +@implementation RCTRawTextShadowView + +- (void)setText:(NSString *)text +{ + if (_text != text && ![_text isEqualToString:text]) { + _text = [text copy]; + [self dirtyLayout]; + } +} + +- (void)dirtyLayout +{ + [self.superview dirtyLayout]; +} + +- (NSString *)description +{ + NSString *superDescription = super.description; + return [[superDescription substringToIndex:superDescription.length - 1] stringByAppendingFormat:@"; text: %@>", self.text]; +} + +@end diff --git a/Libraries/Text/RawText/RCTRawTextViewManager.h b/Libraries/Text/RawText/RCTRawTextViewManager.h new file mode 100644 index 0000000000..38d83e385b --- /dev/null +++ b/Libraries/Text/RawText/RCTRawTextViewManager.h @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface RCTRawTextViewManager : RCTViewManager + +@end + +NS_ASSUME_NONNULL_END diff --git a/Libraries/Text/RawText/RCTRawTextViewManager.m b/Libraries/Text/RawText/RCTRawTextViewManager.m new file mode 100644 index 0000000000..3aea9e8f25 --- /dev/null +++ b/Libraries/Text/RawText/RCTRawTextViewManager.m @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "RCTRawTextViewManager.h" + +#import "RCTRawTextShadowView.h" + +@implementation RCTRawTextViewManager + +RCT_EXPORT_MODULE(RCTRawText) + +- (NSView *)view +{ + return [NSView new]; +} + +- (RCTShadowView *)shadowView +{ + return [RCTRawTextShadowView new]; +} + +RCT_EXPORT_SHADOW_PROPERTY(text, NSString) + +@end diff --git a/Libraries/Text/Text.js b/Libraries/Text/Text.js index d5582890a2..dc5055eff2 100644 --- a/Libraries/Text/Text.js +++ b/Libraries/Text/Text.js @@ -8,42 +8,29 @@ * * @providesModule Text * @flow + * @format */ 'use strict'; const ColorPropType = require('ColorPropType'); const EdgeInsetsPropType = require('EdgeInsetsPropType'); const NativeMethodsMixin = require('NativeMethodsMixin'); -const Platform = require('Platform'); const React = require('React'); const PropTypes = require('prop-types'); -const ReactNativeViewAttributes = require('ReactNativeViewAttributes'); const StyleSheetPropType = require('StyleSheetPropType'); const TextStylePropTypes = require('TextStylePropTypes'); const Touchable = require('Touchable'); +const UIManager = require('UIManager'); const createReactClass = require('create-react-class'); -const createReactNativeComponentClass = require('createReactNativeComponentClass'); +const requireNativeComponent = require('requireNativeComponent'); const mergeFast = require('mergeFast'); const processColor = require('processColor'); +const {ViewContextTypes} = require('ViewContext'); const stylePropType = StyleSheetPropType(TextStylePropTypes); -const viewConfig = { - validAttributes: mergeFast(ReactNativeViewAttributes.UIView, { - isHighlighted: true, - numberOfLines: true, - ellipsizeMode: true, - allowFontScaling: true, - disabled: true, - selectable: true, - selectionColor: true, - adjustsFontSizeToFit: true, - minimumFontScale: true, - textBreakStrategy: true, - }), - uiViewClassName: 'RCTText', -}; +import type {ViewChildContext} from 'ViewContext'; /** * A React component for displaying text. @@ -418,16 +405,13 @@ const Text = createReactClass({ }); }, mixins: [NativeMethodsMixin], - viewConfig: viewConfig, - getChildContext(): Object { - return {isInAParentText: true}; - }, - childContextTypes: { - isInAParentText: PropTypes.bool - }, - contextTypes: { - isInAParentText: PropTypes.bool + getChildContext(): ViewChildContext { + return { + isInAParentText: true, + }; }, + childContextTypes: ViewContextTypes, + contextTypes: ViewContextTypes, /** * Only assigned if touch is needed. */ @@ -449,10 +433,11 @@ const Text = createReactClass({ if (this.props.onStartShouldSetResponder || this._hasPressHandler()) { if (!this._handlers) { this._handlers = { - onStartShouldSetResponder: (): bool => { - const shouldSetFromProps = this.props.onStartShouldSetResponder && - // $FlowFixMe(>=0.41.0) - this.props.onStartShouldSetResponder(); + onStartShouldSetResponder: (): boolean => { + const shouldSetFromProps = + this.props.onStartShouldSetResponder && + // $FlowFixMe(>=0.41.0) + this.props.onStartShouldSetResponder(); const setResponder = shouldSetFromProps || this._hasPressHandler(); if (setResponder && !this.touchableHandleActivePressIn) { // Attach and bind all the other handlers only the first time a touch @@ -463,7 +448,10 @@ const Text = createReactClass({ } } this.touchableHandleActivePressIn = () => { - if (this.props.suppressHighlighting || !this._hasPressHandler()) { + if ( + this.props.suppressHighlighting || + !this._hasPressHandler() + ) { return; } this.setState({ @@ -472,7 +460,10 @@ const Text = createReactClass({ }; this.touchableHandleActivePressOut = () => { - if (this.props.suppressHighlighting || !this._hasPressHandler()) { + if ( + this.props.suppressHighlighting || + !this._hasPressHandler() + ) { return; } this.setState({ @@ -514,12 +505,15 @@ const Text = createReactClass({ this.props.onResponderTerminate && this.props.onResponderTerminate.apply(this, arguments); }.bind(this), - onResponderTerminationRequest: function(): bool { + onResponderTerminationRequest: function(): boolean { // Allow touchable or props.onResponderTerminationRequest to deny // the request var allowTermination = this.touchableHandleResponderTerminationRequest(); if (allowTermination && this.props.onResponderTerminationRequest) { - allowTermination = this.props.onResponderTerminationRequest.apply(this, arguments); + allowTermination = this.props.onResponderTerminationRequest.apply( + this, + arguments, + ); } return allowTermination; }.bind(this), @@ -534,7 +528,7 @@ const Text = createReactClass({ if (newProps.selectionColor != null) { newProps = { ...newProps, - selectionColor: processColor(newProps.selectionColor) + selectionColor: processColor(newProps.selectionColor), }; } if (Touchable.TOUCH_TARGET_DEBUG && newProps.onPress) { @@ -556,23 +550,13 @@ type RectOffset = { left: number, right: number, bottom: number, -} - -var PRESS_RECT_OFFSET = {top: 20, left: 20, right: 20, bottom: 30}; +}; -var RCTText = createReactNativeComponentClass( - viewConfig.uiViewClassName, - () => viewConfig -); -var RCTVirtualText = RCTText; +const PRESS_RECT_OFFSET = {top: 20, left: 20, right: 20, bottom: 30}; -if (Platform.OS === 'android') { - RCTVirtualText = createReactNativeComponentClass('RCTVirtualText', () => ({ - validAttributes: mergeFast(ReactNativeViewAttributes.UIView, { - isHighlighted: true, - }), - uiViewClassName: 'RCTVirtualText', - })); -} +const RCTText = requireNativeComponent('RCTText'); +const RCTVirtualText = UIManager.RCTVirtualText + ? requireNativeComponent('RCTVirtualText') + : RCTText; module.exports = Text; diff --git a/Libraries/Text/Text/NSTextStorage+FontScaling.h b/Libraries/Text/Text/NSTextStorage+FontScaling.h new file mode 100644 index 0000000000..9abc3c45f8 --- /dev/null +++ b/Libraries/Text/Text/NSTextStorage+FontScaling.h @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import + +@interface NSTextStorage (FontScaling) + +- (void)scaleFontSizeToFitSize:(CGSize)size + minimumFontSize:(CGFloat)minimumFontSize + maximumFontSize:(CGFloat)maximumFontSize; + +- (void)scaleFontSizeWithRatio:(CGFloat)ratio + minimumFontSize:(CGFloat)minimumFontSize + maximumFontSize:(CGFloat)maximumFontSize; + +@end diff --git a/Libraries/Text/Text/NSTextStorage+FontScaling.m b/Libraries/Text/Text/NSTextStorage+FontScaling.m new file mode 100644 index 0000000000..60f73eac60 --- /dev/null +++ b/Libraries/Text/Text/NSTextStorage+FontScaling.m @@ -0,0 +1,139 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "NSTextStorage+FontScaling.h" + +typedef NS_OPTIONS(NSInteger, RCTTextSizeComparisonOptions) { + RCTTextSizeComparisonSmaller = 1 << 0, + RCTTextSizeComparisonLarger = 1 << 1, + RCTTextSizeComparisonWithinRange = 1 << 2, +}; + +@implementation NSTextStorage (FontScaling) + +- (void)scaleFontSizeToFitSize:(CGSize)size + minimumFontSize:(CGFloat)minimumFontSize + maximumFontSize:(CGFloat)maximumFontSize +{ + CGFloat bottomRatio = 1.0/128.0; + CGFloat topRatio = 128.0; + CGFloat ratio = 1.0; + + NSAttributedString *originalAttributedString = [self copy]; + + CGFloat lastRatioWhichFits = 0.02; + + while (true) { + [self scaleFontSizeWithRatio:ratio + minimumFontSize:minimumFontSize + maximumFontSize:maximumFontSize]; + + RCTTextSizeComparisonOptions comparsion = + [self compareToSize:size thresholdRatio:0.01]; + + if ( + (comparsion & RCTTextSizeComparisonWithinRange) && + (comparsion & RCTTextSizeComparisonSmaller) + ) { + return; + } else if (comparsion & RCTTextSizeComparisonSmaller) { + bottomRatio = ratio; + lastRatioWhichFits = ratio; + } else { + topRatio = ratio; + } + + ratio = (topRatio + bottomRatio) / 2.0; + + CGFloat kRatioThreshold = 0.005; + if ( + ABS(topRatio - bottomRatio) < kRatioThreshold || + ABS(topRatio - ratio) < kRatioThreshold || + ABS(bottomRatio - ratio) < kRatioThreshold + ) { + [self replaceCharactersInRange:(NSRange){0, self.length} + withAttributedString:originalAttributedString]; + + [self scaleFontSizeWithRatio:lastRatioWhichFits + minimumFontSize:minimumFontSize + maximumFontSize:maximumFontSize]; + return; + } + + [self replaceCharactersInRange:(NSRange){0, self.length} + withAttributedString:originalAttributedString]; + } +} + + +- (RCTTextSizeComparisonOptions)compareToSize:(CGSize)size thresholdRatio:(CGFloat)thresholdRatio +{ + NSLayoutManager *layoutManager = self.layoutManagers.firstObject; + NSTextContainer *textContainer = layoutManager.textContainers.firstObject; + + [layoutManager ensureLayoutForTextContainer:textContainer]; + + // Does it fit the text container? + NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer]; + NSRange truncatedGlyphRange = [layoutManager truncatedGlyphRangeInLineFragmentForGlyphAtIndex:glyphRange.length - 1]; + + if (truncatedGlyphRange.location != NSNotFound) { + return RCTTextSizeComparisonLarger; + } + + CGSize measuredSize = [layoutManager usedRectForTextContainer:textContainer].size; + + // Does it fit the size? + BOOL fitsSize = + size.width >= measuredSize.width && + size.height >= measuredSize.height; + + CGSize thresholdSize = (CGSize){ + size.width * thresholdRatio, + size.height * thresholdRatio, + }; + + RCTTextSizeComparisonOptions result = 0; + + result |= (fitsSize) ? RCTTextSizeComparisonSmaller : RCTTextSizeComparisonLarger; + + if (ABS(measuredSize.width - size.width) < thresholdSize.width) { + result = result | RCTTextSizeComparisonWithinRange; + } + + return result; +} + +- (void)scaleFontSizeWithRatio:(CGFloat)ratio + minimumFontSize:(CGFloat)minimumFontSize + maximumFontSize:(CGFloat)maximumFontSize +{ + [self beginEditing]; + + [self enumerateAttribute:NSFontAttributeName + inRange:(NSRange){0, self.length} + options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired + usingBlock: + ^(NSFont *_Nullable font, NSRange range, BOOL *_Nonnull stop) { + if (!font) { + return; + } + + CGFloat fontSize = MAX(MIN(font.pointSize * ratio, maximumFontSize), minimumFontSize); + + [self addAttribute:NSFontAttributeName + value:[NSFont fontWithDescriptor:font.fontDescriptor size:fontSize] + range:range]; + } + ]; + + [self endEditing]; +} + +@end diff --git a/Libraries/Text/Text/RCTTextShadowView.h b/Libraries/Text/Text/RCTTextShadowView.h index df087cc6b1..6cdd8fdd31 100644 --- a/Libraries/Text/Text/RCTTextShadowView.h +++ b/Libraries/Text/Text/RCTTextShadowView.h @@ -8,49 +8,22 @@ */ #import -#import - -typedef NS_ENUM(NSInteger, RCTSizeComparison) -{ - RCTSizeTooLarge, - RCTSizeTooSmall, - RCTSizeWithinRange, -}; - - -extern NSString *const RCTIsHighlightedAttributeName; -extern NSString *const RCTReactTagAttributeName; - -@interface RCTTextShadowView : RCTShadowView - -@property (nonatomic, strong) NSColor *color; -@property (nonatomic, strong) NSColor *backgroundColor; -@property (nonatomic, copy) NSString *fontFamily; -@property (nonatomic, assign) CGFloat fontSize; -@property (nonatomic, copy) NSString *fontWeight; -@property (nonatomic, copy) NSString *fontStyle; -@property (nonatomic, copy) NSArray *fontVariant; -@property (nonatomic, assign) BOOL isHighlighted; -@property (nonatomic, assign) CGFloat letterSpacing; -@property (nonatomic, assign) CGFloat lineHeight; -@property (nonatomic, assign) NSUInteger numberOfLines; -@property (nonatomic, assign) NSLineBreakMode ellipsizeMode; -@property (nonatomic, assign) CGSize shadowOffset; -@property (nonatomic, assign) NSTextAlignment textAlign; -@property (nonatomic, assign) NSWritingDirection writingDirection; -@property (nonatomic, strong) NSColor *textDecorationColor; -@property (nonatomic, assign) NSUnderlineStyle textDecorationStyle; -@property (nonatomic, assign) RCTTextDecorationLineType textDecorationLine; -@property (nonatomic, assign) CGFloat fontSizeMultiplier; -@property (nonatomic, assign) BOOL allowFontScaling; -@property (nonatomic, assign) CGFloat opacity; -@property (nonatomic, assign) CGSize textShadowOffset; -@property (nonatomic, assign) CGFloat textShadowRadius; -@property (nonatomic, strong) NSColor *textShadowColor; + +#import "RCTBaseTextShadowView.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface RCTTextShadowView : RCTBaseTextShadowView + +- (instancetype)initWithBridge:(RCTBridge *)bridge; + +@property (nonatomic, assign) NSInteger maximumNumberOfLines; +@property (nonatomic, assign) NSLineBreakMode lineBreakMode; @property (nonatomic, assign) BOOL adjustsFontSizeToFit; @property (nonatomic, assign) CGFloat minimumFontScale; -@property (nonatomic, assign) BOOL selectable; -- (void)recomputeText; +- (void)uiManagerWillPerformMounting; @end + +NS_ASSUME_NONNULL_END diff --git a/Libraries/Text/Text/RCTTextShadowView.m b/Libraries/Text/Text/RCTTextShadowView.m index e7bc8d1127..4c64aee88a 100644 --- a/Libraries/Text/Text/RCTTextShadowView.m +++ b/Libraries/Text/Text/RCTTextShadowView.m @@ -9,680 +9,333 @@ #import "RCTTextShadowView.h" -// TODO: (critical) Fix accessibility -// #import #import -#import -#import -#import #import #import -#import +#import -#import "RCTRawTextShadowView.h" +#import "NSTextStorage+FontScaling.h" +#import "NSValue+CoreGraphics.h" +#import "NSFont+LineHeight.h" #import "RCTTextView.h" -#import "RCTMultilineTextInputView.h" - -NSString *const RCTIsHighlightedAttributeName = @"IsHighlightedAttributeName"; -NSString *const RCTReactTagAttributeName = @"ReactTagAttributeName"; - -static NSString *const kShadowViewAttributeName = @"RCTShadowViewAttributeName"; - -static CGFloat const kAutoSizeWidthErrorMargin = 0.05f; -static CGFloat const kAutoSizeHeightErrorMargin = 0.025f; -static CGFloat const kAutoSizeGranularity = 0.001f; @implementation RCTTextShadowView { - NSTextStorage *_cachedTextStorage; - CGFloat _cachedTextStorageWidth; - CGFloat _cachedTextStorageWidthMode; - NSAttributedString *_cachedAttributedString; - CGFloat _effectiveLetterSpacing; - NSUserInterfaceLayoutDirection _cachedLayoutDirection; + __weak RCTBridge *_bridge; + BOOL _needsUpdateView; + NSMapTable *_cachedTextStorages; } -static YGSize RCTMeasure(YGNodeRef node, float width, YGMeasureMode widthMode, float height, YGMeasureMode heightMode) +- (instancetype)initWithBridge:(RCTBridge *)bridge { - RCTTextShadowView *shadowText = (__bridge RCTTextShadowView *)YGNodeGetContext(node); - NSTextStorage *textStorage = [shadowText buildTextStorageForWidth:width widthMode:widthMode]; - [shadowText calculateTextFrame:textStorage]; - NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject; - NSTextContainer *textContainer = layoutManager.textContainers.firstObject; - CGSize computedSize = [layoutManager usedRectForTextContainer:textContainer].size; - - YGSize result; - result.width = RCTCeilPixelValue(computedSize.width); - if (shadowText->_effectiveLetterSpacing < 0) { - result.width -= shadowText->_effectiveLetterSpacing; + if (self = [super init]) { + _bridge = bridge; + _cachedTextStorages = [NSMapTable strongToStrongObjectsMapTable]; + _needsUpdateView = YES; + YGNodeSetMeasureFunc(self.yogaNode, RCTTextShadowViewMeasure); } - result.height = RCTCeilPixelValue(computedSize.height); - return result; -} -- (instancetype)init -{ - if ((self = [super init])) { - _fontSize = NAN; - _letterSpacing = NAN; - _isHighlighted = NO; - _textDecorationStyle = NSUnderlineStyleSingle; - _opacity = 1.0; - _cachedTextStorageWidth = -1; - _cachedTextStorageWidthMode = -1; - _fontSizeMultiplier = 1.0; - _textAlign = NSTextAlignmentNatural; - _writingDirection = NSWritingDirectionNatural; - _cachedLayoutDirection = NSUserInterfaceLayoutDirectionLeftToRight; - - YGNodeSetMeasureFunc(self.yogaNode, RCTMeasure); - - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(contentSizeMultiplierDidChange:) - name:RCTUIManagerWillUpdateViewsDueToContentSizeMultiplierChangeNotification - object:nil]; - } return self; } -- (void)dealloc +- (BOOL)isYogaLeafNode { - [[NSNotificationCenter defaultCenter] removeObserver:self]; + return YES; } -- (NSString *)description +- (void)dirtyLayout { - NSString *superDescription = super.description; - return [[superDescription substringToIndex:superDescription.length - 1] stringByAppendingFormat:@"; text: %@>", [self attributedString].string]; + [super dirtyLayout]; + YGNodeMarkDirty(self.yogaNode); + [self invalidateCache]; } -- (BOOL)isYogaLeafNode +- (void)invalidateCache { - return YES; + [_cachedTextStorages removeAllObjects]; + _needsUpdateView = YES; } -- (void)contentSizeMultiplierDidChange:(NSNotification *)note -{ - YGNodeMarkDirty(self.yogaNode); - [self dirtyText]; -} +#pragma mark - RCTUIManagerObserver -- (NSDictionary *)processUpdatedProperties:(NSMutableSet *)applierBlocks - parentProperties:(NSDictionary *)parentProperties +- (void)uiManagerWillPerformMounting { - if ([[self reactSuperview] isKindOfClass:[RCTTextShadowView class]]) { - return parentProperties; + if (YGNodeIsDirty(self.yogaNode)) { + return; } - parentProperties = [super processUpdatedProperties:applierBlocks - parentProperties:parentProperties]; - - CGFloat availableWidth = self.availableSize.width; - NSNumber *parentTag = [[self reactSuperview] reactTag]; - NSTextStorage *textStorage = [self buildTextStorageForWidth:availableWidth widthMode:YGMeasureModeExactly]; - CGRect textFrame = [self calculateTextFrame:textStorage]; - BOOL selectable = _selectable; - [applierBlocks addObject:^(NSDictionary *viewRegistry) { - RCTTextView *view = (RCTTextView *)viewRegistry[self.reactTag]; - view.textFrame = textFrame; - view.textStorage = textStorage; - view.selectable = selectable; - - /** - * NOTE: this logic is included to support rich text editing inside multiline - * `` controls. It is required in order to ensure that the - * textStorage (aka attributed string) is copied over from the RCTTextShadowView - * to the RCTTextView view in time to be used to update the editable text content. - * TODO: we should establish a delegate relationship betweeen RCTMultilineTextInputView - * and its contaned RCTTextView element when they get inserted and get rid of this - */ - NSView *parentView = viewRegistry[parentTag]; - if ([parentView respondsToSelector:@selector(performTextUpdate)]) { - [(RCTMultilineTextInputView *)parentView performTextUpdate]; - } - }]; + if (!_needsUpdateView) { + return; + } + _needsUpdateView = NO; + + CGRect contentFrame = self.contentFrame; + NSTextStorage *textStorage = [self textStorageAndLayoutManagerThatFitsSize:self.contentFrame.size + exclusiveOwnership:YES]; + + NSNumber *tag = self.reactTag; + NSMutableArray *descendantViewTags = [NSMutableArray new]; + [textStorage enumerateAttribute:RCTBaseTextShadowViewEmbeddedShadowViewAttributeName + inRange:NSMakeRange(0, textStorage.length) + options:0 + usingBlock: + ^(RCTShadowView *shadowView, NSRange range, __unused BOOL *stop) { + if (!shadowView) { + return; + } - return parentProperties; -} + [descendantViewTags addObject:shadowView.reactTag]; + } + ]; -- (void)applyLayoutNode:(YGNodeRef)node - viewsWithNewFrame:(NSMutableSet *)viewsWithNewFrame - absolutePosition:(CGPoint)absolutePosition -{ - [super applyLayoutNode:node viewsWithNewFrame:viewsWithNewFrame absolutePosition:absolutePosition]; - [self dirtyPropagation]; -} + [_bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary *viewRegistry) { + RCTTextView *textView = (RCTTextView *)viewRegistry[tag]; + if (!textView) { + return; + } -- (void)applyLayoutToChildren:(YGNodeRef)node - viewsWithNewFrame:(NSMutableSet *)viewsWithNewFrame - absolutePosition:(CGPoint)absolutePosition -{ - // Run layout on subviews. - CGFloat availableWidth = self.availableSize.width; - NSTextStorage *textStorage = [self buildTextStorageForWidth:availableWidth widthMode:YGMeasureModeExactly]; - NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject; - NSTextContainer *textContainer = layoutManager.textContainers.firstObject; - NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer]; - NSRange characterRange = [layoutManager characterRangeForGlyphRange:glyphRange actualGlyphRange:NULL]; - [layoutManager.textStorage enumerateAttribute:kShadowViewAttributeName inRange:characterRange options:0 usingBlock:^(RCTShadowView *child, NSRange range, BOOL *_) { - if (child) { - YGNodeRef childNode = child.yogaNode; - float width = YGNodeStyleGetWidth(childNode).value; - float height = YGNodeStyleGetHeight(childNode).value; - if (YGFloatIsUndefined(width) || YGFloatIsUndefined(height)) { - RCTLogError(@"Views nested within a must have a width and height"); + NSMutableArray *descendantViews = + [NSMutableArray arrayWithCapacity:descendantViewTags.count]; + [descendantViewTags enumerateObjectsUsingBlock:^(NSNumber *_Nonnull descendantViewTag, NSUInteger index, BOOL *_Nonnull stop) { + NSView *descendantView = viewRegistry[descendantViewTag]; + if (!descendantView) { + return; } - NSFont *font = [textStorage attribute:NSFontAttributeName atIndex:range.location effectiveRange:nil]; - CGRect glyphRect = [layoutManager boundingRectForGlyphRange:range inTextContainer:textContainer]; - CGRect childFrame = {{ - RCTRoundPixelValue(glyphRect.origin.x), - RCTRoundPixelValue(glyphRect.origin.y + glyphRect.size.height - height + font.descender) - }, { - RCTRoundPixelValue(width), - RCTRoundPixelValue(height) - }}; - NSRange truncatedGlyphRange = [layoutManager truncatedGlyphRangeInLineFragmentForGlyphAtIndex:range.location]; - BOOL childIsTruncated = NSIntersectionRange(range, truncatedGlyphRange).length != 0; + [descendantViews addObject:descendantView]; + }]; - [child collectUpdatedFrames:viewsWithNewFrame - withFrame:childFrame - hidden:childIsTruncated - absolutePosition:absolutePosition]; - } + // Removing all references to Shadow Views to avoid unnececery retainning. + [textStorage removeAttribute:RCTBaseTextShadowViewEmbeddedShadowViewAttributeName range:NSMakeRange(0, textStorage.length)]; + + [textView setTextStorage:textStorage + contentFrame:contentFrame + descendantViews:descendantViews]; }]; } -- (NSTextStorage *)buildTextStorageForWidth:(CGFloat)width widthMode:(YGMeasureMode)widthMode +- (void)postprocessAttributedText:(NSMutableAttributedString *)attributedText { - if ( - _cachedTextStorage && - (width == _cachedTextStorageWidth || (isnan(width) && isnan(_cachedTextStorageWidth))) && - widthMode == _cachedTextStorageWidthMode && - _cachedLayoutDirection == self.layoutDirection - ) { - return _cachedTextStorage; - } - - NSLayoutManager *layoutManager = [NSLayoutManager new]; - - NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:self.attributedString]; - [textStorage addLayoutManager:layoutManager]; + __block CGFloat maximumLineHeight = 0; + + [attributedText enumerateAttribute:NSParagraphStyleAttributeName + inRange:NSMakeRange(0, attributedText.length) + options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired + usingBlock: + ^(NSParagraphStyle *paragraphStyle, __unused NSRange range, __unused BOOL *stop) { + if (!paragraphStyle) { + return; + } - NSTextContainer *textContainer = [NSTextContainer new]; - textContainer.lineFragmentPadding = 0.0; + maximumLineHeight = MAX(paragraphStyle.maximumLineHeight, maximumLineHeight); + } + ]; - if (_numberOfLines > 0) { - textContainer.lineBreakMode = _ellipsizeMode; - } else { - textContainer.lineBreakMode = NSLineBreakByClipping; + if (maximumLineHeight == 0) { + // `lineHeight` was not specified, nothing to do. + return; } - textContainer.maximumNumberOfLines = _numberOfLines; - textContainer.size = (CGSize){ - widthMode == YGMeasureModeUndefined || isnan(width) ? CGFLOAT_MAX : width, - CGFLOAT_MAX - }; - - [layoutManager addTextContainer:textContainer]; - [layoutManager ensureLayoutForTextContainer:textContainer]; + [attributedText beginEditing]; - _cachedTextStorageWidth = width; - _cachedTextStorageWidthMode = widthMode; - _cachedTextStorage = textStorage; + [attributedText enumerateAttribute:NSFontAttributeName + inRange:NSMakeRange(0, attributedText.length) + options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired + usingBlock: + ^(NSFont *font, NSRange range, __unused BOOL *stop) { + if (!font) { + return; + } - return textStorage; -} + if (maximumLineHeight <= font.lineHeight) { + return; + } -- (void)dirtyText -{ - [super dirtyText]; - _cachedTextStorage = nil; -} + CGFloat baseLineOffset = maximumLineHeight / 2.0 - font.lineHeight / 2.0; -- (void)recomputeText -{ - [self attributedString]; - [self setTextComputed]; - [self dirtyPropagation]; -} + [attributedText addAttribute:NSBaselineOffsetAttributeName + value:@(baseLineOffset) + range:range]; + } + ]; -- (NSAttributedString *)attributedString -{ - return [self _attributedStringWithFontFamily:nil - fontSize:nil - fontWeight:nil - fontStyle:nil - letterSpacing:nil - useBackgroundColor:YES - foregroundColor:self.color ?: [NSColor textColor] - backgroundColor:self.backgroundColor - opacity:self.opacity]; + [attributedText endEditing]; } -- (NSAttributedString *)_attributedStringWithFontFamily:(NSString *)fontFamily - fontSize:(NSNumber *)fontSize - fontWeight:(NSString *)fontWeight - fontStyle:(NSString *)fontStyle - letterSpacing:(NSNumber *)letterSpacing - useBackgroundColor:(BOOL)useBackgroundColor - foregroundColor:(NSColor *)foregroundColor - backgroundColor:(NSColor *)backgroundColor - opacity:(CGFloat)opacity +- (NSAttributedString *)attributedTextWithMeasuredAttachmentsThatFitSize:(CGSize)size { - if ( - ![self isTextDirty] && - _cachedAttributedString && - _cachedLayoutDirection == self.layoutDirection - ) { - return _cachedAttributedString; - } + NSMutableAttributedString *attributedText = + [[NSMutableAttributedString alloc] initWithAttributedString:[self attributedTextWithBaseTextAttributes:nil]]; - _cachedLayoutDirection = self.layoutDirection; + [attributedText beginEditing]; - if (_fontSize && !isnan(_fontSize)) { - fontSize = @(_fontSize); - } - if (_fontWeight) { - fontWeight = _fontWeight; - } - if (_fontStyle) { - fontStyle = _fontStyle; - } - if (_fontFamily) { - fontFamily = _fontFamily; - } - if (!isnan(_letterSpacing)) { - letterSpacing = @(_letterSpacing); - } - - _effectiveLetterSpacing = letterSpacing.doubleValue; - - NSFont *font = [RCTFont updateFont:nil - withFamily:fontFamily - size:fontSize - weight:fontWeight - style:fontStyle - variant:_fontVariant - scaleMultiplier:_allowFontScaling ? _fontSizeMultiplier : 1.0]; - - CGFloat heightOfTallestSubview = 0.0; - NSMutableAttributedString *attributedString = [NSMutableAttributedString new]; - for (RCTShadowView *child in [self reactSubviews]) { - if ([child isKindOfClass:[RCTTextShadowView class]]) { - RCTTextShadowView *shadowText = (RCTTextShadowView *)child; - [attributedString appendAttributedString: - [shadowText _attributedStringWithFontFamily:fontFamily - fontSize:fontSize - fontWeight:fontWeight - fontStyle:fontStyle - letterSpacing:letterSpacing - useBackgroundColor:YES - foregroundColor:shadowText.color ?: foregroundColor - backgroundColor:shadowText.backgroundColor ?: backgroundColor - opacity:opacity * shadowText.opacity]]; - [child setTextComputed]; - } else if ([child isKindOfClass:[RCTRawTextShadowView class]]) { - RCTRawTextShadowView *shadowRawText = (RCTRawTextShadowView *)child; - [attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:shadowRawText.text ?: @""]]; - [child setTextComputed]; - } else { - float width = YGNodeStyleGetWidth(child.yogaNode).value; - float height = YGNodeStyleGetHeight(child.yogaNode).value; - if (YGFloatIsUndefined(width) || YGFloatIsUndefined(height)) { - RCTLogError(@"Views nested within a must have a width and height"); + [attributedText enumerateAttribute:RCTBaseTextShadowViewEmbeddedShadowViewAttributeName + inRange:NSMakeRange(0, attributedText.length) + options:0 + usingBlock: + ^(RCTShadowView *shadowView, NSRange range, __unused BOOL *stop) { + if (!shadowView) { + return; } + + CGSize fittingSize = [shadowView sizeThatFitsMinimumSize:CGSizeZero + maximumSize:size]; NSTextAttachment *attachment = [NSTextAttachment new]; - attachment.bounds = (CGRect){CGPointZero, {width, height}}; - NSMutableAttributedString *attachmentString = [NSMutableAttributedString new]; - [attachmentString appendAttributedString:[NSAttributedString attributedStringWithAttachment:attachment]]; - [attachmentString addAttribute:kShadowViewAttributeName value:child range:(NSRange){0, attachmentString.length}]; - [attributedString appendAttributedString:attachmentString]; - if (height > heightOfTallestSubview) { - heightOfTallestSubview = height; - } - // Don't call setTextComputed on this child. RCTTextViewManager takes care of - // processing inline UIViews. + attachment.bounds = (CGRect){CGPointZero, fittingSize}; + [attributedText addAttribute:NSAttachmentAttributeName value:attachment range:range]; } - } - - [self _addAttribute:NSForegroundColorAttributeName - withValue:[foregroundColor colorWithAlphaComponent:CGColorGetAlpha(foregroundColor.CGColor) * opacity] - toAttributedString:attributedString]; + ]; - if (_isHighlighted) { - [self _addAttribute:RCTIsHighlightedAttributeName withValue:@YES toAttributedString:attributedString]; - } - if (useBackgroundColor && backgroundColor) { - [self _addAttribute:NSBackgroundColorAttributeName - withValue:[backgroundColor colorWithAlphaComponent:CGColorGetAlpha(backgroundColor.CGColor) * opacity] - toAttributedString:attributedString]; - } + [attributedText endEditing]; - [self _addAttribute:NSFontAttributeName withValue:font toAttributedString:attributedString]; - [self _addAttribute:NSKernAttributeName withValue:letterSpacing toAttributedString:attributedString]; - [self _addAttribute:RCTReactTagAttributeName withValue:self.reactTag toAttributedString:attributedString]; -// [self _setParagraphStyleOnAttributedString:attributedString -// fontLineHeight:[NSLayoutManager defaultLineHeightForFont: font] -// heightOfTallestSubview:heightOfTallestSubview]; - - // create a non-mutable attributedString for use by the Text system which avoids copies down the line - _cachedAttributedString = [[NSAttributedString alloc] initWithAttributedString:attributedString]; - YGNodeMarkDirty(self.yogaNode); - - return _cachedAttributedString; + return [attributedText copy]; } -- (void)_addAttribute:(NSString *)attribute withValue:(id)attributeValue toAttributedString:(NSMutableAttributedString *)attributedString +- (NSTextStorage *)textStorageAndLayoutManagerThatFitsSize:(CGSize)size + exclusiveOwnership:(BOOL)exclusiveOwnership { - [attributedString enumerateAttribute:attribute inRange:NSMakeRange(0, attributedString.length) options:0 usingBlock:^(id value, NSRange range, BOOL *stop) { - if (!value && attributeValue) { - [attributedString addAttribute:attribute value:attributeValue range:range]; - } - }]; -} + NSValue *key = [NSValue valueWithCGSize:size]; + NSTextStorage *cachedTextStorage = [_cachedTextStorages objectForKey:key]; -/* - * LineHeight works the same way line-height works in the web: if children and self have - * varying lineHeights, we simply take the max. - */ -- (void)_setParagraphStyleOnAttributedString:(NSMutableAttributedString *)attributedString - fontLineHeight:(CGFloat)fontLineHeight - heightOfTallestSubview:(CGFloat)heightOfTallestSubview -{ - __block BOOL hasParagraphStyle = NO; + if (cachedTextStorage) { + if (exclusiveOwnership) { + [_cachedTextStorages removeObjectForKey:key]; + } - if (_lineHeight != 0.0 || _textAlign != NSTextAlignmentNatural) { - hasParagraphStyle = YES; + return cachedTextStorage; } - CGFloat fontSizeMultiplier = _allowFontScaling ? _fontSizeMultiplier : 1.0; + NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:size]; - // Text line height - __block float compoundLineHeight = _lineHeight * fontSizeMultiplier; + textContainer.lineFragmentPadding = 0.0; // Note, the default value is 5. + textContainer.lineBreakMode = + _maximumNumberOfLines > 0 ? _lineBreakMode : NSLineBreakByClipping; + textContainer.maximumNumberOfLines = _maximumNumberOfLines; - // Checking for `maximumLineHeight` on each of our children and updating `compoundLineHeight` with the maximum value on the go. - [attributedString enumerateAttribute:NSParagraphStyleAttributeName - inRange:(NSRange){0, attributedString.length} - options:0 - usingBlock:^(NSParagraphStyle *paragraphStyle, NSRange range, BOOL *stop) { - - if (!paragraphStyle) { - return; - } + NSLayoutManager *layoutManager = [NSLayoutManager new]; + [layoutManager addTextContainer:textContainer]; - hasParagraphStyle = YES; - compoundLineHeight = MAX(compoundLineHeight, paragraphStyle.maximumLineHeight); - }]; + NSTextStorage *textStorage = + [[NSTextStorage alloc] initWithAttributedString:[self attributedTextWithMeasuredAttachmentsThatFitSize:size]]; - compoundLineHeight = MAX(round(compoundLineHeight), ceilf(heightOfTallestSubview)); + [self postprocessAttributedText:textStorage]; - // Text alignment - NSTextAlignment textAlign = _textAlign; - if (textAlign == NSTextAlignmentRight || textAlign == NSTextAlignmentLeft) { - if (_cachedLayoutDirection == NSUserInterfaceLayoutDirectionRightToLeft) { - if (textAlign == NSTextAlignmentRight) { - textAlign = NSTextAlignmentLeft; - } else { - textAlign = NSTextAlignmentRight; - } - } - } + [textStorage addLayoutManager:layoutManager]; - if (hasParagraphStyle) { - NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new]; - paragraphStyle.alignment = textAlign; - paragraphStyle.baseWritingDirection = _writingDirection; - paragraphStyle.minimumLineHeight = compoundLineHeight; - paragraphStyle.maximumLineHeight = compoundLineHeight; - [attributedString addAttribute:NSParagraphStyleAttributeName - value:paragraphStyle - range:(NSRange){0, attributedString.length}]; - - if (compoundLineHeight > fontLineHeight) { - [attributedString addAttribute:NSBaselineOffsetAttributeName - value:@(compoundLineHeight / 2 - fontLineHeight / 2) - range:(NSRange){0, attributedString.length}]; - } + if (_adjustsFontSizeToFit) { + CGFloat minimumFontSize = + MAX(_minimumFontScale * (self.textAttributes.effectiveFont.pointSize), 4.0); + [textStorage scaleFontSizeToFitSize:size + minimumFontSize:minimumFontSize + maximumFontSize:72.0]; } - // Text decoration - if (_textDecorationLine == RCTTextDecorationLineTypeUnderline || - _textDecorationLine == RCTTextDecorationLineTypeUnderlineStrikethrough) { - [self _addAttribute:NSUnderlineStyleAttributeName withValue:@(_textDecorationStyle) - toAttributedString:attributedString]; - } - if (_textDecorationLine == RCTTextDecorationLineTypeStrikethrough || - _textDecorationLine == RCTTextDecorationLineTypeUnderlineStrikethrough){ - [self _addAttribute:NSStrikethroughStyleAttributeName withValue:@(_textDecorationStyle) - toAttributedString:attributedString]; - } - if (_textDecorationColor) { - [self _addAttribute:NSStrikethroughColorAttributeName withValue:_textDecorationColor - toAttributedString:attributedString]; - [self _addAttribute:NSUnderlineColorAttributeName withValue:_textDecorationColor - toAttributedString:attributedString]; + if (!exclusiveOwnership) { + [_cachedTextStorages setObject:textStorage forKey:key]; } - // Text shadow - if (!CGSizeEqualToSize(_textShadowOffset, CGSizeZero)) { - NSShadow *shadow = [NSShadow new]; - shadow.shadowOffset = _textShadowOffset; - shadow.shadowBlurRadius = _textShadowRadius; - shadow.shadowColor = _textShadowColor; - [self _addAttribute:NSShadowAttributeName withValue:shadow toAttributedString:attributedString]; - } + return textStorage; } -#pragma mark Autosizing - -- (CGRect)calculateTextFrame:(NSTextStorage *)textStorage +- (void)layoutWithMetrics:(RCTLayoutMetrics)layoutMetrics + layoutContext:(RCTLayoutContext)layoutContext { - CGRect textFrame = UIEdgeInsetsInsetRect((CGRect){CGPointZero, self.frame.size}, - self.compoundInsets); - - if (_adjustsFontSizeToFit) { - textFrame = [self updateStorage:textStorage toFitFrame:textFrame]; + // If the view got new `contentFrame`, we have to redraw it because + // and sizes of embedded views may change. + if (!CGRectEqualToRect(self.layoutMetrics.contentFrame, layoutMetrics.contentFrame)) { + _needsUpdateView = YES; } - return textFrame; -} - -- (CGRect)updateStorage:(NSTextStorage *)textStorage toFitFrame:(CGRect)frame -{ - BOOL fits = [self attemptScale:1.0f - inStorage:textStorage - forFrame:frame]; - CGSize requiredSize; - if (!fits) { - requiredSize = [self calculateOptimumScaleInFrame:frame - forStorage:textStorage - minScale:self.minimumFontScale - maxScale:1.0 - prevMid:INT_MAX]; - } else { - requiredSize = [self calculateSize:textStorage]; + if (self.textAttributes.layoutDirection != layoutMetrics.layoutDirection) { + self.textAttributes.layoutDirection = layoutMetrics.layoutDirection; + [self invalidateCache]; } - // Vertically center draw position for new text sizing. - frame.origin.y = self.compoundInsets.top + RCTRoundPixelValue((CGRectGetHeight(frame) - requiredSize.height) / 2.0f); - return frame; -} - -- (CGSize)calculateOptimumScaleInFrame:(CGRect)frame - forStorage:(NSTextStorage *)textStorage - minScale:(CGFloat)minScale - maxScale:(CGFloat)maxScale - prevMid:(CGFloat)prevMid -{ - CGFloat midScale = (minScale + maxScale) / 2.0f; - if (round((prevMid / kAutoSizeGranularity)) == round((midScale / kAutoSizeGranularity))) { - //Bail because we can't meet error margin. - return [self calculateSize:textStorage]; - } else { - RCTSizeComparison comparison = [self attemptScale:midScale - inStorage:textStorage - forFrame:frame]; - if (comparison == RCTSizeWithinRange) { - return [self calculateSize:textStorage]; - } else if (comparison == RCTSizeTooLarge) { - return [self calculateOptimumScaleInFrame:frame - forStorage:textStorage - minScale:minScale - maxScale:midScale - kAutoSizeGranularity - prevMid:midScale]; - } else { - return [self calculateOptimumScaleInFrame:frame - forStorage:textStorage - minScale:midScale + kAutoSizeGranularity - maxScale:maxScale - prevMid:midScale]; - } - } + [super layoutWithMetrics:layoutMetrics layoutContext:layoutContext]; } -- (RCTSizeComparison)attemptScale:(CGFloat)scale - inStorage:(NSTextStorage *)textStorage - forFrame:(CGRect)frame +- (void)layoutSubviewsWithContext:(RCTLayoutContext)layoutContext { - NSLayoutManager *layoutManager = [textStorage.layoutManagers firstObject]; - NSTextContainer *textContainer = [layoutManager.textContainers firstObject]; - - NSRange glyphRange = NSMakeRange(0, textStorage.length); - [textStorage beginEditing]; - [textStorage enumerateAttribute:NSFontAttributeName - inRange:glyphRange - options:0 - usingBlock:^(NSFont *font, NSRange range, BOOL *stop) - { - if (font) { - NSFont *originalFont = [self.attributedString attribute:NSFontAttributeName - atIndex:range.location - effectiveRange:&range]; - - NSFont *newFont = [NSFont fontWithName: originalFont.fontName size:originalFont.pointSize * scale]; - [textStorage removeAttribute:NSFontAttributeName range:range]; - [textStorage addAttribute:NSFontAttributeName value:newFont range:range]; - } - }]; + NSTextStorage *textStorage = + [self textStorageAndLayoutManagerThatFitsSize:self.availableSize + exclusiveOwnership:NO]; + NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject; + NSTextContainer *textContainer = layoutManager.textContainers.firstObject; + NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer]; + NSRange characterRange = [layoutManager characterRangeForGlyphRange:glyphRange + actualGlyphRange:NULL]; + + [textStorage enumerateAttribute:RCTBaseTextShadowViewEmbeddedShadowViewAttributeName + inRange:characterRange + options:0 + usingBlock: + ^(RCTShadowView *shadowView, NSRange range, BOOL *stop) { + if (!shadowView) { + return; + } - [textStorage endEditing]; + CGRect glyphRect = [layoutManager boundingRectForGlyphRange:range + inTextContainer:textContainer]; - NSInteger linesRequired = [self numberOfLinesRequired:[textStorage.layoutManagers firstObject]]; - CGSize requiredSize = [self calculateSize:textStorage]; + NSTextAttachment *attachment = + [textStorage attribute:NSAttachmentAttributeName atIndex:range.location effectiveRange:nil]; - BOOL fitSize = requiredSize.height <= CGRectGetHeight(frame) && - requiredSize.width <= CGRectGetWidth(frame); + CGSize attachmentSize = attachment.bounds.size; - BOOL fitLines = linesRequired <= textContainer.maximumNumberOfLines || - textContainer.maximumNumberOfLines == 0; + NSFont *font = [textStorage attribute:NSFontAttributeName atIndex:range.location effectiveRange:nil]; - if (fitLines && fitSize) { - if ((requiredSize.width + (CGRectGetWidth(frame) * kAutoSizeWidthErrorMargin)) > CGRectGetWidth(frame) && - (requiredSize.height + (CGRectGetHeight(frame) * kAutoSizeHeightErrorMargin)) > CGRectGetHeight(frame)) - { - return RCTSizeWithinRange; - } else { - return RCTSizeTooSmall; - } - } else { - return RCTSizeTooLarge; - } -} + CGRect frame = {{ + RCTRoundPixelValue(glyphRect.origin.x), + RCTRoundPixelValue(glyphRect.origin.y + glyphRect.size.height - attachmentSize.height + font.descender) + }, { + RCTRoundPixelValue(attachmentSize.width), + RCTRoundPixelValue(attachmentSize.height) + }}; -// Via Apple Text Layout Programming Guide -// https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/TextLayout/Tasks/CountLines.html -- (NSInteger)numberOfLinesRequired:(NSLayoutManager *)layoutManager -{ - NSInteger numberOfLines, index, numberOfGlyphs = [layoutManager numberOfGlyphs]; - NSRange lineRange; - for (numberOfLines = 0, index = 0; index < numberOfGlyphs; numberOfLines++){ - (void) [layoutManager lineFragmentRectForGlyphAtIndex:index - effectiveRange:&lineRange]; - index = NSMaxRange(lineRange); - } + RCTLayoutContext localLayoutContext = layoutContext; + localLayoutContext.absolutePosition.x += frame.origin.x; + localLayoutContext.absolutePosition.y += frame.origin.y; - return numberOfLines; + [shadowView layoutWithMinimumSize:frame.size + maximumSize:frame.size + layoutDirection:self.layoutMetrics.layoutDirection + layoutContext:localLayoutContext]; + } + ]; } -// Via Apple Text Layout Programming Guide -//https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/TextLayout/Tasks/StringHeight.html -- (CGSize)calculateSize:(NSTextStorage *)storage +static YGSize RCTTextShadowViewMeasure(YGNodeRef node, float width, YGMeasureMode widthMode, float height, YGMeasureMode heightMode) { - NSLayoutManager *layoutManager = [storage.layoutManagers firstObject]; - NSTextContainer *textContainer = [layoutManager.textContainers firstObject]; + CGSize maximumSize = (CGSize){ + widthMode == YGMeasureModeUndefined ? CGFLOAT_MAX : RCTCoreGraphicsFloatFromYogaFloat(width), + heightMode == YGMeasureModeUndefined ? CGFLOAT_MAX : RCTCoreGraphicsFloatFromYogaFloat(height), + }; - [textContainer setLineBreakMode:NSLineBreakByWordWrapping]; - NSInteger maxLines = [textContainer maximumNumberOfLines]; - [textContainer setMaximumNumberOfLines:0]; - (void) [layoutManager glyphRangeForTextContainer:textContainer]; - CGSize requiredSize = [layoutManager usedRectForTextContainer:textContainer].size; - [textContainer setMaximumNumberOfLines:maxLines]; + RCTTextShadowView *shadowTextView = (__bridge RCTTextShadowView *)YGNodeGetContext(node); - return requiredSize; -} + NSTextStorage *textStorage = + [shadowTextView textStorageAndLayoutManagerThatFitsSize:maximumSize + exclusiveOwnership:NO]; -#define RCT_TEXT_PROPERTY(setProp, ivar, type) \ -- (void)set##setProp:(type)value; \ -{ \ - ivar = value; \ - [self dirtyText]; \ -} + NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject; + NSTextContainer *textContainer = layoutManager.textContainers.firstObject; + [layoutManager ensureLayoutForTextContainer:textContainer]; + CGSize size = [layoutManager usedRectForTextContainer:textContainer].size; -RCT_TEXT_PROPERTY(AdjustsFontSizeToFit, _adjustsFontSizeToFit, BOOL) -RCT_TEXT_PROPERTY(Color, _color, NSColor *) -RCT_TEXT_PROPERTY(FontFamily, _fontFamily, NSString *) -RCT_TEXT_PROPERTY(FontSize, _fontSize, CGFloat) -RCT_TEXT_PROPERTY(FontWeight, _fontWeight, NSString *) -RCT_TEXT_PROPERTY(FontStyle, _fontStyle, NSString *) -RCT_TEXT_PROPERTY(FontVariant, _fontVariant, NSArray *) -RCT_TEXT_PROPERTY(IsHighlighted, _isHighlighted, BOOL) -RCT_TEXT_PROPERTY(LetterSpacing, _letterSpacing, CGFloat) -RCT_TEXT_PROPERTY(LineHeight, _lineHeight, CGFloat) -RCT_TEXT_PROPERTY(NumberOfLines, _numberOfLines, NSUInteger) -RCT_TEXT_PROPERTY(EllipsizeMode, _ellipsizeMode, NSLineBreakMode) -RCT_TEXT_PROPERTY(TextAlign, _textAlign, NSTextAlignment) -RCT_TEXT_PROPERTY(TextDecorationColor, _textDecorationColor, NSColor *); -RCT_TEXT_PROPERTY(TextDecorationLine, _textDecorationLine, RCTTextDecorationLineType); -RCT_TEXT_PROPERTY(TextDecorationStyle, _textDecorationStyle, NSUnderlineStyle); -RCT_TEXT_PROPERTY(WritingDirection, _writingDirection, NSWritingDirection) -RCT_TEXT_PROPERTY(Opacity, _opacity, CGFloat) -RCT_TEXT_PROPERTY(TextShadowOffset, _textShadowOffset, CGSize); -RCT_TEXT_PROPERTY(TextShadowRadius, _textShadowRadius, CGFloat); -RCT_TEXT_PROPERTY(TextShadowColor, _textShadowColor, NSColor *); - -- (void)setAllowFontScaling:(BOOL)allowFontScaling -{ - _allowFontScaling = allowFontScaling; - for (RCTShadowView *child in [self reactSubviews]) { - if ([child isKindOfClass:[RCTTextShadowView class]]) { - ((RCTTextShadowView *)child).allowFontScaling = allowFontScaling; - } + CGFloat letterSpacing = shadowTextView.textAttributes.letterSpacing; + if (!isnan(letterSpacing) && letterSpacing < 0) { + size.width -= letterSpacing; } - [self dirtyText]; -} -- (void)setFontSizeMultiplier:(CGFloat)fontSizeMultiplier -{ - _fontSizeMultiplier = fontSizeMultiplier; - if (_fontSizeMultiplier == 0) { - RCTLogError(@"fontSizeMultiplier value must be > zero."); - _fontSizeMultiplier = 1.0; - } - for (RCTShadowView *child in [self reactSubviews]) { - if ([child isKindOfClass:[RCTTextShadowView class]]) { - ((RCTTextShadowView *)child).fontSizeMultiplier = fontSizeMultiplier; - } - } - [self dirtyText]; -} + size = (CGSize){ + MIN(RCTCeilPixelValue(size.width), maximumSize.width), + MIN(RCTCeilPixelValue(size.height), maximumSize.height) + }; -- (void)setMinimumFontScale:(CGFloat)minimumFontScale -{ - if (minimumFontScale >= 0.01) { - _minimumFontScale = minimumFontScale; - } - [self dirtyText]; + return (YGSize){ + RCTYogaFloatFromCoreGraphicsFloat(size.width), + RCTYogaFloatFromCoreGraphicsFloat(size.height) + }; } @end diff --git a/Libraries/Text/Text/RCTTextView.h b/Libraries/Text/Text/RCTTextView.h index 66fd19c59a..00a64787ec 100644 --- a/Libraries/Text/Text/RCTTextView.h +++ b/Libraries/Text/Text/RCTTextView.h @@ -9,14 +9,16 @@ #import -CGRect UIEdgeInsetsInsetRect(CGRect rect, NSEdgeInsets insets); +NS_ASSUME_NONNULL_BEGIN @interface RCTTextView : NSView -@property (nonatomic, assign) NSEdgeInsets contentInset; -@property (nonatomic, strong) NSTextStorage *textStorage; -@property (nonatomic, assign) CGRect textFrame; @property (nonatomic, assign) BOOL selectable; -@property (nonatomic, assign) BOOL respondsToLiveResizing; +- (void)setTextStorage:(NSTextStorage *)textStorage + contentFrame:(CGRect)contentFrame + descendantViews:(NSArray *)descendantViews; + @end + +NS_ASSUME_NONNULL_END diff --git a/Libraries/Text/Text/RCTTextView.m b/Libraries/Text/Text/RCTTextView.m index e2489a54b1..1d42bba7fb 100644 --- a/Libraries/Text/Text/RCTTextView.m +++ b/Libraries/Text/Text/RCTTextView.m @@ -10,143 +10,64 @@ #import "RCTTextView.h" #import -// #import #import #import #import "RCTTextShadowView.h" - -// https://github.com/BigZaphod/Chameleon/blob/84605ede274bd82b330d72dd6ac41e64eb925fd7/UIKit/Classes/UIGeometry.h -CGRect UIEdgeInsetsInsetRect(CGRect rect, NSEdgeInsets insets) { - rect.origin.x += insets.left; - rect.origin.y += insets.top; - rect.size.width -= (insets.left + insets.right); - rect.size.height -= (insets.top + insets.bottom); - return rect; -} - -@implementation NSBezierPath (BezierPathQuartzUtilities) -// This method works only in OS X v10.2 and later. -- (CGPathRef)quartzPath -{ - long i, numElements; - - // Need to begin a path here. - CGPathRef immutablePath = NULL; - - // Then draw the path elements. - numElements = [self elementCount]; - if (numElements > 0) - { - CGMutablePathRef path = CGPathCreateMutable(); - NSPoint points[3]; - BOOL didClosePath = YES; - - for (i = 0; i < numElements; i++) - { - switch ([self elementAtIndex:i associatedPoints:points]) - { - case NSMoveToBezierPathElement: - CGPathMoveToPoint(path, NULL, points[0].x, points[0].y); - break; - - case NSLineToBezierPathElement: - CGPathAddLineToPoint(path, NULL, points[0].x, points[0].y); - didClosePath = NO; - break; - - case NSCurveToBezierPathElement: - CGPathAddCurveToPoint(path, NULL, points[0].x, points[0].y, - points[1].x, points[1].y, - points[2].x, points[2].y); - didClosePath = NO; - break; - - case NSClosePathBezierPathElement: - CGPathCloseSubpath(path); - didClosePath = YES; - break; - } - } - - // Be sure the path is closed or Quartz may not do valid hit detection. - if (!didClosePath) - CGPathCloseSubpath(path); - - immutablePath = CGPathCreateCopy(path); - CGPathRelease(path); - } - - return immutablePath; // TODO: potential leak -} -@end - -static void collectNonTextDescendants(RCTTextView *view, NSMutableArray *nonTextDescendants) -{ - for (NSView *child in view.reactSubviews) { - if ([child isKindOfClass:[RCTTextView class]]) { - collectNonTextDescendants((RCTTextView *)child, nonTextDescendants); - } else if (!CGRectEqualToRect(child.frame, CGRectZero)) { - [nonTextDescendants addObject:child]; - } - } -} +#import "NSBezierPath+CGPath.h" @implementation RCTTextView { - NSTextStorage *_textStorage; CAShapeLayer *_highlightLayer; + + + NSArray *_Nullable _descendantViews; + NSTextStorage *_Nullable _textStorage; + CGRect _contentFrame; } - (instancetype)initWithFrame:(CGRect)frame { - if ((self = [super initWithFrame:frame])) { - _textStorage = [NSTextStorage new]; + if (self = [super initWithFrame:frame]) { +// self.isAccessibilityElement = YES; +// self.accessibilityTraits |= UIAccessibilityTraitStaticText; +// self.contentMode = UIViewContentModeRedraw; } return self; } -- (BOOL)isFlipped -{ - return YES; -} - - (NSString *)description { NSString *superDescription = super.description; NSRange semicolonRange = [superDescription rangeOfString:@";"]; - NSString *replacement = [NSString stringWithFormat:@"; reactTag: %@; text: %@", self.reactTag, self.textStorage.string]; + NSString *replacement = [NSString stringWithFormat:@"; reactTag: %@; text: %@", self.reactTag, _textStorage.string]; return [superDescription stringByReplacingCharactersInRange:semicolonRange withString:replacement]; } -- (void)setSelectable:(BOOL)selectable -{ - if (_selectable == selectable) { - return; - } - _selectable = selectable; - if (_selectable) { - [self enableContextMenu]; - } - else { - [self disableContextMenu]; - } -} -- (void)reactSetFrame:(CGRect)frame -{ - [super reactSetFrame:frame]; -} -- (void)reactSetInheritedBackgroundColor:(NSColor *)inheritedBackgroundColor + + + + + + + + + + + + +- (void)reactSetFrame:(CGRect)frame { - if (self.wantsLayer == NO) { - self.wantsLayer = YES; - } - self.layer.backgroundColor = [inheritedBackgroundColor CGColor]; + // Text looks super weird if its frame is animated. + // This disables the frame animation, without affecting opacity, etc. + [NSView performWithoutAnimation:^{ + [super reactSetFrame:frame]; + }]; } - (void)didUpdateReactSubviews @@ -155,55 +76,65 @@ - (void)didUpdateReactSubviews } - (void)setTextStorage:(NSTextStorage *)textStorage + contentFrame:(CGRect)contentFrame + descendantViews:(NSArray *)descendantViews { - if (_textStorage != textStorage) { - _textStorage = textStorage; - - // Update subviews - NSMutableArray *nonTextDescendants = [NSMutableArray new]; - collectNonTextDescendants(self, nonTextDescendants); - NSArray *subviews = self.subviews; - if (![subviews isEqualToArray:nonTextDescendants]) { - for (NSView *child in subviews) { - if (![nonTextDescendants containsObject:child]) { - [child removeFromSuperview]; - } - } - for (NSView *child in nonTextDescendants) { - [self addSubview:child]; - } - } + _textStorage = textStorage; + _contentFrame = contentFrame; - [self setNeedsDisplay:YES]; + // FIXME: Optimize this. + for (NSView *view in _descendantViews) { + [view removeFromSuperview]; + } + + _descendantViews = descendantViews; + + for (NSView *view in descendantViews) { + [self addSubview:view]; } + + [self setNeedsDisplay:YES]; } -- (void)drawRect:(CGRect)dirtyRect +- (void)drawRect:(CGRect)rect { - NSLayoutManager *layoutManager = [_textStorage.layoutManagers firstObject]; - NSTextContainer *textContainer = [layoutManager.textContainers firstObject]; + if (!_textStorage) { + return; + } - NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer]; - CGRect textFrame = self.textFrame; - [layoutManager drawBackgroundForGlyphRange:glyphRange atPoint:textFrame.origin]; - [layoutManager drawGlyphsForGlyphRange:glyphRange atPoint:textFrame.origin]; - __block NSBezierPath *highlightPath = nil; - NSRange characterRange = [layoutManager characterRangeForGlyphRange:glyphRange actualGlyphRange:NULL]; + NSLayoutManager *layoutManager = _textStorage.layoutManagers.firstObject; + NSTextContainer *textContainer = layoutManager.textContainers.firstObject; - [layoutManager.textStorage enumerateAttribute:RCTIsHighlightedAttributeName inRange:characterRange options:0 usingBlock:^(NSNumber *value, NSRange range, BOOL *_) { - if (!value.boolValue) { - return; - } + NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer]; + [layoutManager drawBackgroundForGlyphRange:glyphRange atPoint:_contentFrame.origin]; + [layoutManager drawGlyphsForGlyphRange:glyphRange atPoint:_contentFrame.origin]; - [layoutManager enumerateEnclosingRectsForGlyphRange:range withinSelectedGlyphRange:range inTextContainer:textContainer usingBlock:^(CGRect enclosingRect, __unused BOOL *__) { - NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:CGRectInset(enclosingRect, -2, -2) xRadius:2 yRadius:2]; - if (highlightPath) { - [highlightPath appendBezierPath:path]; - } else { - highlightPath = path; + __block NSBezierPath *highlightPath = nil; + NSRange characterRange = [layoutManager characterRangeForGlyphRange:glyphRange + actualGlyphRange:NULL]; + [_textStorage enumerateAttribute:RCTTextAttributesIsHighlightedAttributeName + inRange:characterRange + options:0 + usingBlock: + ^(NSNumber *value, NSRange range, __unused BOOL *stop) { + if (!value.boolValue) { + return; } - }]; + + [layoutManager enumerateEnclosingRectsForGlyphRange:range + withinSelectedGlyphRange:range + inTextContainer:textContainer + usingBlock: + ^(CGRect enclosingRect, __unused BOOL *anotherStop) { + NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:CGRectInset(enclosingRect, -2, -2) xRadius:2 yRadius:2]; + if (highlightPath) { + [highlightPath appendBezierPath:path]; + } else { + highlightPath = path; + } + } + ]; }]; if (highlightPath) { @@ -212,14 +143,15 @@ - (void)drawRect:(CGRect)dirtyRect _highlightLayer.fillColor = [NSColor colorWithWhite:0 alpha:0.25].CGColor; [self.layer addSublayer:_highlightLayer]; } - _highlightLayer.position = (CGPoint){_contentInset.left, _contentInset.top}; - _highlightLayer.path = highlightPath.quartzPath; + _highlightLayer.position = _contentFrame.origin; + _highlightLayer.path = highlightPath.CGPath; } else { [_highlightLayer removeFromSuperlayer]; _highlightLayer = nil; } } + - (NSNumber *)reactTagAtPoint:(CGPoint)point { NSNumber *reactTag = self.reactTag; @@ -234,8 +166,9 @@ - (NSNumber *)reactTagAtPoint:(CGPoint)point // If the point is not before (fraction == 0.0) the first character and not // after (fraction == 1.0) the last character, then the attribute is valid. if (_textStorage.length > 0 && (fraction > 0 || characterIndex > 0) && (fraction < 1 || characterIndex < _textStorage.length - 1)) { - reactTag = [_textStorage attribute:RCTReactTagAttributeName atIndex:characterIndex effectiveRange:NULL]; + reactTag = [_textStorage attribute:RCTTextAttributesTagAttributeName atIndex:characterIndex effectiveRange:NULL]; } + return reactTag; } @@ -249,12 +182,11 @@ - (void)viewDidMoveToWindow [_highlightLayer removeFromSuperlayer]; _highlightLayer = nil; } - } else if (_textStorage.length) { + } else if (_textStorage) { [self setNeedsDisplay:YES]; } } - #pragma mark - Accessibility - (NSString *)accessibilityLabel @@ -266,35 +198,63 @@ - (NSString *)accessibilityLabel return _textStorage.string; } -#pragma mark - Context Menu -- (void)enableContextMenu -{ -} -- (void)disableContextMenu -{ -} + + + + + + + + + + + + + + + + + + + + + + + + + + + + - (BOOL)canBecomeFirstResponder { return _selectable; } -//- (BOOL)canPerformAction:(SEL)action withSender:(id)sender -//{ -// if (_selectable && action == @selector(copy:)) { -// return YES; -// } -// -// return [self.nextResponder canPerformAction:action withSender:sender]; -//} +- (BOOL)tryToPerform:(SEL)action with:(id)object +{ + if (_selectable && action == @selector(copy:)) { + return YES; + } + + return [self.nextResponder tryToPerform:action with:object]; +} - (void)copy:(id)sender { #if !TARGET_OS_TV - #endif + NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; + [pasteboard clearContents]; [pasteboard writeObjects:@[_textStorage]]; +#endif +} + +- (BOOL)isFlipped +{ + return YES; } @end diff --git a/Libraries/Text/Text/RCTTextViewManager.h b/Libraries/Text/Text/RCTTextViewManager.h index 9028878bd3..957c88d477 100644 --- a/Libraries/Text/Text/RCTTextViewManager.h +++ b/Libraries/Text/Text/RCTTextViewManager.h @@ -9,6 +9,8 @@ #import -@interface RCTTextViewManager : RCTViewManager +#import "RCTBaseTextViewManager.h" + +@interface RCTTextViewManager : RCTBaseTextViewManager @end diff --git a/Libraries/Text/Text/RCTTextViewManager.m b/Libraries/Text/Text/RCTTextViewManager.m index 1d5a4165a0..47fc8aaca9 100644 --- a/Libraries/Text/Text/RCTTextViewManager.m +++ b/Libraries/Text/Text/RCTTextViewManager.m @@ -9,42 +9,52 @@ #import "RCTTextViewManager.h" -#import -// #import -#import -#import -#import +//#import #import -#import +#import +#import +#import -#import "RCTRawTextShadowView.h" #import "RCTTextShadowView.h" #import "RCTTextView.h" -#import "RCTMultilineTextInputView.h" - -static void collectDirtyNonTextDescendants(RCTTextShadowView *shadowView, NSMutableArray *nonTextDescendants) { - for (RCTShadowView *child in shadowView.reactSubviews) { - if ([child isKindOfClass:[RCTTextShadowView class]]) { - collectDirtyNonTextDescendants((RCTTextShadowView *)child, nonTextDescendants); - } else if ([child isKindOfClass:[RCTRawTextShadowView class]]) { - // no-op - } else if ([child isTextDirty]) { - [nonTextDescendants addObject:child]; - } - } -} - -@interface RCTTextShadowView (Private) -- (NSTextStorage *)buildTextStorageForWidth:(CGFloat)width widthMode:(YGMeasureMode)widthMode; +@interface RCTTextViewManager () @end - @implementation RCTTextViewManager +{ + NSHashTable *_shadowViews; + CGFloat _fontSizeMultiplier; +} RCT_EXPORT_MODULE(RCTText) +RCT_REMAP_SHADOW_PROPERTY(numberOfLines, maximumNumberOfLines, NSInteger) +RCT_REMAP_SHADOW_PROPERTY(ellipsizeMode, lineBreakMode, NSLineBreakMode) +RCT_REMAP_SHADOW_PROPERTY(adjustsFontSizeToFit, adjustsFontSizeToFit, BOOL) +RCT_REMAP_SHADOW_PROPERTY(minimumFontScale, minimumFontScale, CGFloat) + +RCT_EXPORT_VIEW_PROPERTY(selectable, BOOL) + +- (void)setBridge:(RCTBridge *)bridge +{ + [super setBridge:bridge]; + _shadowViews = [NSHashTable weakObjectsHashTable]; + + [bridge.uiManager.observerCoordinator addObserver:self]; + +// [[NSNotificationCenter defaultCenter] addObserver:self +// selector:@selector(handleDidUpdateMultiplierNotification) +// name:RCTAccessibilityManagerDidUpdateMultiplierNotification +// object:bridge.accessibilityManager]; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + - (NSView *)view { return [RCTTextView new]; @@ -52,86 +62,33 @@ - (NSView *)view - (RCTShadowView *)shadowView { - return [RCTTextShadowView new]; + RCTTextShadowView *shadowView = [[RCTTextShadowView alloc] initWithBridge:self.bridge]; +// shadowView.textAttributes.fontSizeMultiplier = self.bridge.accessibilityManager.multiplier; + [_shadowViews addObject:shadowView]; + return shadowView; } -#pragma mark - Shadow properties - -RCT_EXPORT_SHADOW_PROPERTY(color, NSColor) -RCT_EXPORT_SHADOW_PROPERTY(backgroundColor, NSColor) -RCT_EXPORT_SHADOW_PROPERTY(fontFamily, NSString) -RCT_EXPORT_SHADOW_PROPERTY(fontSize, CGFloat) -RCT_EXPORT_SHADOW_PROPERTY(fontWeight, NSString) -RCT_EXPORT_SHADOW_PROPERTY(fontStyle, NSString) -RCT_EXPORT_SHADOW_PROPERTY(fontVariant, NSArray) -RCT_EXPORT_SHADOW_PROPERTY(isHighlighted, BOOL) -RCT_EXPORT_SHADOW_PROPERTY(letterSpacing, CGFloat) -RCT_EXPORT_SHADOW_PROPERTY(lineHeight, CGFloat) -RCT_EXPORT_SHADOW_PROPERTY(numberOfLines, NSUInteger) -RCT_EXPORT_SHADOW_PROPERTY(ellipsizeMode, NSLineBreakMode) -RCT_EXPORT_SHADOW_PROPERTY(textAlign, NSTextAlignment) -RCT_EXPORT_SHADOW_PROPERTY(textDecorationStyle, NSUnderlineStyle) -RCT_EXPORT_SHADOW_PROPERTY(textDecorationColor, NSColor) -RCT_EXPORT_SHADOW_PROPERTY(textDecorationLine, RCTTextDecorationLineType) -RCT_EXPORT_SHADOW_PROPERTY(writingDirection, NSWritingDirection) -RCT_EXPORT_SHADOW_PROPERTY(allowFontScaling, BOOL) -RCT_EXPORT_SHADOW_PROPERTY(opacity, CGFloat) -RCT_EXPORT_SHADOW_PROPERTY(textShadowOffset, CGSize) -RCT_EXPORT_SHADOW_PROPERTY(textShadowRadius, CGFloat) -RCT_EXPORT_SHADOW_PROPERTY(textShadowColor, NSColor) -RCT_EXPORT_SHADOW_PROPERTY(adjustsFontSizeToFit, BOOL) -RCT_EXPORT_SHADOW_PROPERTY(minimumFontScale, CGFloat) -RCT_EXPORT_SHADOW_PROPERTY(selectable, BOOL) - -- (RCTViewManagerUIBlock)uiBlockToAmendWithShadowViewRegistry:(NSDictionary *)shadowViewRegistry +#pragma mark - RCTUIManagerObserver + +- (void)uiManagerWillPerformMounting:(__unused RCTUIManager *)uiManager { - for (RCTShadowView *rootView in shadowViewRegistry.allValues) { - if (![rootView isReactRootView]) { - // This isn't a root view - continue; - } - - if (![rootView isTextDirty]) { - // No text processing to be done - continue; - } - - NSMutableArray *queue = [NSMutableArray arrayWithObject:rootView]; - for (NSInteger i = 0; i < queue.count; i++) { - RCTShadowView *shadowView = queue[i]; - RCTAssert([shadowView isTextDirty], @"Don't process any nodes that don't have dirty text"); - - if ([shadowView isKindOfClass:[RCTTextShadowView class]]) { - // ((RCTTextShadowView *)shadowView).fontSizeMultiplier = self.bridge.accessibilityManager.multiplier; - [(RCTTextShadowView *)shadowView recomputeText]; - collectDirtyNonTextDescendants((RCTTextShadowView *)shadowView, queue); - } else if ([shadowView isKindOfClass:[RCTRawTextShadowView class]]) { - RCTLogError(@"Raw text cannot be used outside of a tag. Not rendering string: '%@'", - [(RCTRawTextShadowView *)shadowView text]); - } else { - for (RCTShadowView *child in [shadowView reactSubviews]) { - if ([child isTextDirty]) { - [queue addObject:child]; - } - } - } - - [shadowView setTextComputed]; - } + for (RCTTextShadowView *shadowView in _shadowViews) { + [shadowView uiManagerWillPerformMounting]; } - - return nil; } -- (RCTViewManagerUIBlock)uiBlockToAmendWithShadowView:(RCTTextShadowView *)shadowView -{ - NSNumber *reactTag = shadowView.reactTag; - NSEdgeInsets padding = shadowView.paddingAsInsets; - - return ^(RCTUIManager *uiManager, NSDictionary *viewRegistry) { - RCTTextView *text = viewRegistry[reactTag]; - text.contentInset = padding; - }; -} +#pragma mark - Font Size Multiplier + +//- (void)handleDidUpdateMultiplierNotification +//{ +// CGFloat fontSizeMultiplier = self.bridge.accessibilityManager.multiplier; +// +// for (RCTTextShadowView *shadowView in _shadowViews) { +// shadowView.textAttributes.fontSizeMultiplier = fontSizeMultiplier; +// [shadowView dirtyLayout]; +// } +// +// [self.bridge.uiManager setNeedsLayout]; +//} @end diff --git a/Libraries/Text/TextInput/Multiline/RCTMultilineTextInputView.h b/Libraries/Text/TextInput/Multiline/RCTMultilineTextInputView.h index 1a6e7d7c09..dc43082674 100644 --- a/Libraries/Text/TextInput/Multiline/RCTMultilineTextInputView.h +++ b/Libraries/Text/TextInput/Multiline/RCTMultilineTextInputView.h @@ -7,33 +7,28 @@ * of patent rights can be found in the PATENTS file in the same directory. */ -#import - -#import -#import - #import "RCTBaseTextInputView.h" -@class RCTBridge; +NS_ASSUME_NONNULL_BEGIN -@interface RCTMultilineTextInputView : RCTBaseTextInputView +@class RCTTextScrollView; -//@property (nonatomic, assign) BOOL blurOnSubmit; -//@property (nonatomic, assign) BOOL clearTextOnFocus; -//@property (nonatomic, assign) BOOL selectTextOnFocus; -@property (nonatomic, assign) NSEdgeInsets contentInset; -@property (nonatomic, assign) BOOL automaticallyAdjustContentInsets; -@property (nonatomic, copy) NSString *text; -@property (nonatomic, strong) NSColor *placeholderTextColor; -@property (nonatomic, copy) NSString *placeholder; -@property (nonatomic, strong) NSFont *font; -// @property (nonatomic, assign) NSInteger mostRecentEventCount; -@property (nonatomic, strong) NSNumber *maxLength; - -@property (nonatomic, copy) RCTDirectEventBlock onChange; -@property (nonatomic, copy) RCTDirectEventBlock onTextInput; +@interface RCTMultilineTextInputView : RCTBaseTextInputView @property (nonatomic, copy) RCTDirectEventBlock onScroll; +@end -- (void)performTextUpdate; +#pragma mark - +@protocol RCTTextScrollViewDelegate +- (void)scrollViewDidScroll:(RCTTextScrollView *)scrollView; @end + +#pragma mark - + +@interface RCTTextScrollView : NSScrollView +@property (nonatomic, weak) id delegate; +@property (nonatomic, assign) BOOL scrollEnabled; +@property (readonly) NSPoint contentOffset; +@end + +NS_ASSUME_NONNULL_END diff --git a/Libraries/Text/TextInput/Multiline/RCTMultilineTextInputView.m b/Libraries/Text/TextInput/Multiline/RCTMultilineTextInputView.m index 41e88f7557..507a75f401 100644 --- a/Libraries/Text/TextInput/Multiline/RCTMultilineTextInputView.m +++ b/Libraries/Text/TextInput/Multiline/RCTMultilineTextInputView.m @@ -9,383 +9,83 @@ #import "RCTMultilineTextInputView.h" -#import -#import -#import -#import #import #import -#import "RCTTextShadowView.h" -#import "RCTTextView.h" -#import "RCTTextSelection.h" #import "RCTUITextView.h" -@interface RCTMultilineTextInputView () - +@interface RCTMultilineTextInputView () @end @implementation RCTMultilineTextInputView { - RCTUITextView *_backedTextInput; - RCTTextView *_richTextView; - NSAttributedString *_pendingAttributedText; - - NSString *_predictedText; - - BOOL _blockTextShouldChange; - BOOL _nativeUpdatesInFlight; + RCTUITextView *_backedTextInputView; + RCTTextScrollView *_scrollView; } - (instancetype)initWithBridge:(RCTBridge *)bridge { - RCTAssertParam(bridge); - if (self = [super initWithBridge:bridge]) { // `blurOnSubmit` defaults to `false` for by design. - _blurOnSubmit = NO; + self.blurOnSubmit = NO; - _backedTextInput = [[RCTUITextView alloc] initWithFrame:self.bounds]; - _backedTextInput.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; - _backedTextInput.backgroundColor = [NSColor clearColor]; - _backedTextInput.textColor = [NSColor blackColor]; + _backedTextInputView = [[RCTUITextView alloc] initWithFrame:self.bounds]; + _backedTextInputView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; + _backedTextInputView.backgroundColor = [NSColor clearColor]; + _backedTextInputView.textColor = [NSColor blackColor]; // This line actually removes 5pt (default value) left and right padding in UITextView. - _backedTextInput.textContainer.lineFragmentPadding = 0; -//#if !TARGET_OS_TV -// _backedTextInput.scrollsToTop = NO; -//#endif -// _backedTextInput.scrollEnabled = YES; - _backedTextInput.textInputDelegate = self; - _backedTextInput.font = self.fontAttributes.font; - - [self addSubview:_backedTextInput]; - } - return self; -} - -RCT_NOT_IMPLEMENTED(- (instancetype)initWithFrame:(CGRect)frame) -RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) - -- (id)backedTextInputView -{ - return _backedTextInput; -} - -#pragma mark - RCTComponent - -- (void)insertReactSubview:(NSView *)subview atIndex:(NSInteger)index -{ - [super insertReactSubview:subview atIndex:index]; - - if ([subview isKindOfClass:[RCTTextView class]]) { - if (_richTextView) { - RCTLogError(@"Tried to insert a second into - there can only be one."); - } - _richTextView = (RCTTextView *)subview; - - // If this is in rich text editing mode, and the child node providing rich text - // styling has a backgroundColor, then the attributedText produced by the child node will have an - // NSBackgroundColor attribute. We need to forward this attribute to the text view manually because the text view - // always has a clear background color in `initWithBridge:`. - // - // TODO: This should be removed when the related hack in -performPendingTextUpdate is removed. - if (subview.layer.backgroundColor) { - NSMutableDictionary *attrs = [_backedTextInput.typingAttributes mutableCopy]; - NSColor *backgroundColor = [NSColor colorWithCGColor:subview.layer.backgroundColor]; - attrs[NSBackgroundColorAttributeName] = backgroundColor; - _backedTextInput.typingAttributes = attrs; - } - - [self performTextUpdate]; - } -} - -- (void)removeReactSubview:(NSView *)subview -{ - [super removeReactSubview:subview]; - if (_richTextView == subview) { - _richTextView = nil; - [self performTextUpdate]; - } -} - -- (void)didUpdateReactSubviews -{ - // Do nothing, as we don't allow non-text subviews. -} + _backedTextInputView.textContainer.lineFragmentPadding = 0; + _backedTextInputView.textInputDelegate = self; -#pragma mark - Routine + _scrollView = [[RCTTextScrollView alloc] initWithFrame:NSZeroRect]; + _scrollView.documentView = _backedTextInputView; + _scrollView.delegate = self; -- (void)setMostRecentEventCount:(NSInteger)mostRecentEventCount -{ - _mostRecentEventCount = mostRecentEventCount; - - // Props are set after uiBlockToAmendWithShadowViewRegistry, which means that - // at the time performTextUpdate is called, _mostRecentEventCount will be - // behind _eventCount, with the result that performPendingTextUpdate will do - // nothing. For that reason we call it again here after mostRecentEventCount - // has been set. - [self performPendingTextUpdate]; -} - -- (void)performTextUpdate -{ - if (_richTextView) { - _pendingAttributedText = _richTextView.textStorage; - [self performPendingTextUpdate]; - } else if (!self.text) { - _backedTextInput.attributedString = nil; + [self addSubview:_scrollView]; } -} -static NSAttributedString *removeReactTagFromString(NSAttributedString *string) -{ - if (string.length == 0) { - return string; - } else { - NSMutableAttributedString *mutableString = [[NSMutableAttributedString alloc] initWithAttributedString:string]; - [mutableString removeAttribute:RCTReactTagAttributeName range:NSMakeRange(0, mutableString.length)]; - return mutableString; - } -} - -- (void)performPendingTextUpdate -{ - if (!_pendingAttributedText || _mostRecentEventCount < _nativeEventCount || _nativeUpdatesInFlight) { - return; - } - - // The underlying node that produces _pendingAttributedText has a react tag attribute on it that causes the - // -isEqualToAttributedString: comparison below to spuriously fail. We don't want that comparison to fail unless it - // needs to because when the comparison fails, we end up setting attributedText on the text view, which clears - // autocomplete state for CKJ text input. - // - // TODO: Kill this after we finish passing all style/attribute info into JS. - _pendingAttributedText = removeReactTagFromString(_pendingAttributedText); - - if ([_backedTextInput.attributedText isEqualToAttributedString:_pendingAttributedText]) { - _pendingAttributedText = nil; // Don't try again. - return; - } - - // When we update the attributed text, there might be pending autocorrections - // that will get accepted by default. In order for this to not garble our text, - // we temporarily block all textShouldChange events so they are not applied. - _blockTextShouldChange = YES; - - UITextRange *selection = _backedTextInput.selectedTextRange; - NSInteger oldTextLength = _backedTextInput.attributedText.length; - - _backedTextInput.attributedText = _pendingAttributedText; - _predictedText = _pendingAttributedText.string; - _pendingAttributedText = nil; - - if (selection.empty) { - // maintain cursor position relative to the end of the old text - NSInteger start = [_backedTextInput offsetFromPosition:_backedTextInput.beginningOfDocument toPosition:selection.start]; - NSInteger offsetFromEnd = oldTextLength - start; - NSInteger newOffset = _backedTextInput.attributedText.length - offsetFromEnd; - NSTextPosition *position = [_backedTextInput positionFromPosition:_backedTextInput.beginningOfDocument offset:newOffset]; - [_backedTextInput setSelectedTextRange:[_backedTextInput textRangeFromPosition:position toPosition:position] - notifyDelegate:YES]; - } - - [_backedTextInput layoutIfNeeded]; - - [self invalidateContentSize]; - - _blockTextShouldChange = NO; -} - -#pragma mark - Properties - -- (NSFont *)font -{ - return _backedTextInput.font; + return self; } -- (void)setFont:(NSFont *)font +- (void)setFrame:(NSRect)frame { - _backedTextInput.font = font; - [self setNeedsLayout]; + [super setFrame:frame]; + _scrollView.frameSize = frame.size; } -- (NSString *)text +- (void)setReactBorderInsets:(NSEdgeInsets)reactBorderInsets { - return _backedTextInput.text; + [super setReactBorderInsets:reactBorderInsets]; + _scrollView.contentInsets = self.reactCompoundInsets; } -- (void)setText:(NSString *)text +- (void)setReactPaddingInsets:(NSEdgeInsets)reactPaddingInsets { - NSInteger eventLag = _nativeEventCount - _mostRecentEventCount; - if (eventLag == 0 && ![text isEqualToString:_backedTextInput.text]) { - UITextRange *selection = _backedTextInput.selectedTextRange; - NSInteger oldTextLength = _backedTextInput.text.length; - - _predictedText = text; - _backedTextInput.text = text; - - if (selection.empty) { - // maintain cursor position relative to the end of the old text - NSInteger start = [_backedTextInput offsetFromPosition:_backedTextInput.beginningOfDocument toPosition:selection.start]; - NSInteger offsetFromEnd = oldTextLength - start; - NSInteger newOffset = text.length - offsetFromEnd; - UITextPosition *position = [_backedTextInput positionFromPosition:_backedTextInput.beginningOfDocument offset:newOffset]; - [_backedTextInput setSelectedTextRange:[_backedTextInput textRangeFromPosition:position toPosition:position] - notifyDelegate:YES]; - } - - [self invalidateContentSize]; - } else if (eventLag > RCTTextUpdateLagWarningThreshold) { - RCTLogWarn(@"Native TextInput(%@) is %lld events ahead of JS - try to make your JS faster.", self.text, (long long)eventLag); - } + [super setReactPaddingInsets:reactPaddingInsets]; + _scrollView.contentInsets = self.reactCompoundInsets; } -#pragma mark - RCTBackedTextInputDelegate +RCT_NOT_IMPLEMENTED(- (instancetype)initWithFrame:(CGRect)frame) +RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)coder) -- (BOOL)textInputShouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text +- (id)backedTextInputView { - if (!_backedTextInput.textWasPasted) { - [_eventDispatcher sendTextEventWithType:RCTTextEventTypeKeyPress - reactTag:self.reactTag - text:nil - key:text - eventCount:_nativeEventCount]; - } - - // So we need to track that there is a native update in flight just in case JS manages to come back around and update - // things /before/ UITextView can update itself asynchronously. If there is a native update in flight, we defer the - // JS update when it comes in and apply the deferred update once textViewDidChange fires with the native update applied. - if (_blockTextShouldChange) { - return NO; - } - - if (_maxLength) { - NSUInteger allowedLength = _maxLength.integerValue - _backedTextInput.text.length + range.length; - if (text.length > allowedLength) { - // If we typed/pasted more than one character, limit the text inputted - if (text.length > 1) { - // Truncate the input string so the result is exactly maxLength - NSString *limitedString = [text substringToIndex:allowedLength]; - NSMutableString *newString = _backedTextInput.text.mutableCopy; - [newString replaceCharactersInRange:range withString:limitedString]; - _backedTextInput.text = newString; - _predictedText = newString; - - // Collapse selection at end of insert to match normal paste behavior - UITextPosition *insertEnd = [_backedTextInput positionFromPosition:_backedTextInput.beginningOfDocument - offset:(range.location + allowedLength)]; - [_backedTextInput setSelectedTextRange:[_backedTextInput textRangeFromPosition:insertEnd toPosition:insertEnd] - notifyDelegate:YES]; - - [self textInputDidChange]; - } - return NO; - } - } - - _nativeUpdatesInFlight = YES; - - if (range.location + range.length > _predictedText.length) { - // _predictedText got out of sync in a bad way, so let's just force sync it. Haven't been able to repro this, but - // it's causing a real crash here: #6523822 - _predictedText = _backedTextInput.text; - } - - NSString *previousText = [_predictedText substringWithRange:range]; - if (_predictedText) { - _predictedText = [_predictedText stringByReplacingCharactersInRange:range withString:text]; - } else { - _predictedText = text; - } - - if (_onTextInput) { - _onTextInput(@{ - @"text": text, - @"previousText": previousText ?: @"", - @"range": @{ - @"start": @(range.location), - @"end": @(range.location + range.length) - }, - @"eventCount": @(_nativeEventCount), - }); - } - - return YES; + return _backedTextInputView; } -static BOOL findMismatch(NSString *first, NSString *second, NSRange *firstRange, NSRange *secondRange) -{ - NSInteger firstMismatch = -1; - for (NSUInteger ii = 0; ii < MAX(first.length, second.length); ii++) { - if (ii >= first.length || ii >= second.length || [first characterAtIndex:ii] != [second characterAtIndex:ii]) { - firstMismatch = ii; - break; - } - } - - if (firstMismatch == -1) { - return NO; - } - - NSUInteger ii = second.length; - NSUInteger lastMismatch = first.length; - while (ii > firstMismatch && lastMismatch > firstMismatch) { - if ([first characterAtIndex:(lastMismatch - 1)] != [second characterAtIndex:(ii - 1)]) { - break; - } - ii--; - lastMismatch--; - } - - *firstRange = NSMakeRange(firstMismatch, lastMismatch - firstMismatch); - *secondRange = NSMakeRange(firstMismatch, ii - firstMismatch); - return YES; -} +#pragma mark - NSScrollViewDelegate -- (void)textInputDidChange +- (void)scrollViewDidScroll:(RCTTextScrollView *)scrollView { - [self invalidateContentSize]; - - // Detect when _backedTextInput updates happend that didn't invoke `shouldChangeTextInRange` - // (e.g. typing simplified chinese in pinyin will insert and remove spaces without - // calling shouldChangeTextInRange). This will cause JS to get out of sync so we - // update the mismatched range. - NSRange currentRange; - NSRange predictionRange; - if (findMismatch(_backedTextInput.text, _predictedText, ¤tRange, &predictionRange)) { - NSString *replacement = [_backedTextInput.text substringWithRange:currentRange]; - [self textInputShouldChangeTextInRange:predictionRange replacementText:replacement]; - // JS will assume the selection changed based on the location of our shouldChangeTextInRange, so reset it. - [self textInputDidChangeSelection]; - _predictedText = _backedTextInput.text; - } - - _nativeUpdatesInFlight = NO; - _nativeEventCount++; - - if (!self.reactTag || !_onChange) { - return; - } - - _onChange(@{ - @"text": self.text, - @"target": self.reactTag, - @"eventCount": @(_nativeEventCount), - }); -} + RCTDirectEventBlock onScroll = self.onScroll; -#pragma mark - UIScrollViewDelegate + if (onScroll) { + NSSize size = scrollView.bounds.size; + NSSize contentSize = scrollView.contentSize; + NSPoint contentOffset = scrollView.contentOffset; + NSEdgeInsets contentInset = scrollView.contentInsets; -- (void)scrollViewDidScroll:(NSScrollView *)scrollView -{ - if (_onScroll) { - CGPoint contentOffset = scrollView.contentOffset; - CGSize contentSize = scrollView.contentSize; - CGSize size = scrollView.bounds.size; - NSEdgeInsets contentInset = scrollView.contentInset; - - _onScroll(@{ + onScroll(@{ @"contentOffset": @{ @"x": @(contentOffset.x), @"y": @(contentOffset.y) @@ -404,9 +104,45 @@ - (void)scrollViewDidScroll:(NSScrollView *)scrollView @"width": @(size.width), @"height": @(size.height) }, - @"zoomScale": @(scrollView.zoomScale ?: 1), + @"zoomScale": @(1), + @"target": self.reactTag, }); } } @end + +@implementation RCTTextScrollView + +- (instancetype)initWithFrame:(NSRect)frame +{ + if (self = [super initWithFrame:frame]) { + self.drawsBackground = NO; + self.hasVerticalScroller = YES; + self.automaticallyAdjustsContentInsets = NO; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(_didScroll) + name:NSViewBoundsDidChangeNotification + object:self.contentView]; + } + + return self; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (NSPoint)contentOffset +{ + return self.contentView.bounds.origin; +} + +- (void)_didScroll +{ + [self.delegate scrollViewDidScroll:self]; +} + +@end diff --git a/Libraries/Text/TextInput/Multiline/RCTMultilineTextInputViewManager.h b/Libraries/Text/TextInput/Multiline/RCTMultilineTextInputViewManager.h index 322cfa1679..b2053435fc 100644 --- a/Libraries/Text/TextInput/Multiline/RCTMultilineTextInputViewManager.h +++ b/Libraries/Text/TextInput/Multiline/RCTMultilineTextInputViewManager.h @@ -9,6 +9,10 @@ #import "RCTBaseTextInputViewManager.h" +NS_ASSUME_NONNULL_BEGIN + @interface RCTMultilineTextInputViewManager : RCTBaseTextInputViewManager @end + +NS_ASSUME_NONNULL_END diff --git a/Libraries/Text/TextInput/Multiline/RCTMultilineTextInputViewManager.m b/Libraries/Text/TextInput/Multiline/RCTMultilineTextInputViewManager.m index c405570f0c..cccabc9134 100644 --- a/Libraries/Text/TextInput/Multiline/RCTMultilineTextInputViewManager.m +++ b/Libraries/Text/TextInput/Multiline/RCTMultilineTextInputViewManager.m @@ -9,25 +9,12 @@ #import "RCTMultilineTextInputViewManager.h" -#import -#import -#import -#import -#import - -#import "RCTConvert+Text.h" -#import "RCTMultilineTextInputShadowView.h" #import "RCTMultilineTextInputView.h" @implementation RCTMultilineTextInputViewManager RCT_EXPORT_MODULE() -- (RCTShadowView *)shadowView -{ - return [RCTMultilineTextInputShadowView new]; -} - - (NSView *)view { return [[RCTMultilineTextInputView alloc] initWithBridge:self.bridge]; @@ -35,14 +22,10 @@ - (NSView *)view #pragma mark - Multiline (aka TextView) specific properties -RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock) -RCT_EXPORT_VIEW_PROPERTY(onContentSizeChange, RCTBubblingEventBlock) -RCT_EXPORT_VIEW_PROPERTY(onSelectionChange, RCTDirectEventBlock) -RCT_EXPORT_VIEW_PROPERTY(onScroll, RCTDirectEventBlock) -RCT_EXPORT_VIEW_PROPERTY(onTextInput, RCTDirectEventBlock) +//#if !TARGET_OS_TV +//RCT_REMAP_VIEW_PROPERTY(dataDetectorTypes, backedTextInputView.dataDetectorTypes, UIDataDetectorTypes) +//#endif -#if !TARGET_OS_TV -RCT_REMAP_VIEW_PROPERTY(dataDetectorTypes, backedTextInputView.dataDetectorTypes, UIDataDetectorTypes) -#endif +RCT_EXPORT_VIEW_PROPERTY(onScroll, RCTDirectEventBlock) @end diff --git a/Libraries/Text/TextInput/Multiline/RCTUITextView.h b/Libraries/Text/TextInput/Multiline/RCTUITextView.h index 2ce9dcf6ba..bb56fe491b 100644 --- a/Libraries/Text/TextInput/Multiline/RCTUITextView.h +++ b/Libraries/Text/TextInput/Multiline/RCTUITextView.h @@ -16,22 +16,19 @@ NS_ASSUME_NONNULL_BEGIN /* - * Just regular UITextView... but much better! + * Just regular NSTextView... but much better! */ - @interface RCTUITextView : NSTextView - (instancetype)initWithFrame:(CGRect)frame textContainer:(nullable NSTextContainer *)textContainer NS_UNAVAILABLE; -- (instancetype)initWithCoder:(NSCoder *)aDecoder NS_UNAVAILABLE; +- (instancetype)initWithCoder:(NSCoder *)decoder NS_UNAVAILABLE; @property (nonatomic, weak) id textInputDelegate; -// - (void)setText:(NSString *)text; -- (void)setAttributedText:(NSAttributedString *)attributedText; -@property (nonatomic, strong) NSAttributedString *placeholderAttributedString; -@property (nonatomic, assign) BOOL textWasPasted; -@property (nonatomic, copy, nullable) NSString *placeholderText; -@property (nonatomic, assign, nullable) NSColor *placeholderTextColor; +@property (nonatomic, assign, readonly) BOOL textWasPasted; +// @property (nonatomic, copy, nullable) NSString *placeholder; +// @property (nonatomic, strong, nullable) NSColor *placeholderColor; +@property (nonatomic, assign) NSEdgeInsets paddingInsets; @property (nonatomic, assign) CGFloat preferredMaxLayoutWidth; @end diff --git a/Libraries/Text/TextInput/Multiline/RCTUITextView.m b/Libraries/Text/TextInput/Multiline/RCTUITextView.m index de4738fd3c..a3d93e8ace 100644 --- a/Libraries/Text/TextInput/Multiline/RCTUITextView.m +++ b/Libraries/Text/TextInput/Multiline/RCTUITextView.m @@ -7,55 +7,33 @@ * of patent rights can be found in the PATENTS file in the same directory. */ -#import #import "RCTUITextView.h" -#import #import - -CGRect UIEdgeInsetsSizeRect(CGRect rect, CGSize insets) { -// rect.origin.x += insets.left; - // rect.origin.y += insets.top; - rect.size.width -= (insets.width); - rect.size.height -= (insets.height); - return rect; -} - +#import #import "RCTBackedTextInputDelegateAdapter.h" @implementation RCTUITextView { - NSTextField *_placeholderView; - NSTextView *_detachedTextView; RCTBackedTextViewDelegateAdapter *_textInputDelegateAdapter; } -static NSFont *defaultPlaceholderFont() -{ - return [NSFont systemFontOfSize:17]; -} - -static NSColor *defaultPlaceholderTextColor() -{ - // Default placeholder color from UITextField. - return [NSColor colorWithRed:0 green:0 blue:0.0980392 alpha:0.22]; -} - - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { - _placeholderView = [[NSTextField alloc] initWithFrame:self.bounds]; -// _placeholderView.isAccessibilityElement = NO; -// _placeholderView.numberOfLines = 0; - [self addSubview:_placeholderView]; - _textInputDelegateAdapter = [[RCTBackedTextViewDelegateAdapter alloc] initWithTextView:self]; } return self; } +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +#pragma mark - Properties - (NSString *)accessibilityLabel { @@ -66,119 +44,74 @@ - (NSString *)accessibilityLabel [accessibilityLabel appendString:superAccessibilityLabel]; } - if (self.placeholder.length > 0 && self.text.length == 0) { - if (accessibilityLabel.length > 0) { - [accessibilityLabel appendString:@" "]; - } - [accessibilityLabel appendString:self.placeholder]; - } - return accessibilityLabel; } -#pragma mark - Properties - -- (void)setPlaceholder:(NSString *)placeholder -{ - _placeholderText = placeholderText; - _placeholderView.stringValue = _placeholderText; -} - -- (void)setPlaceholderTextColor:(NSColor *)placeholderTextColor -{ - _placeholderColor = placeholderColor; - _placeholderView.textColor = _placeholderColor ?: defaultPlaceholderColor(); -} - -- (void)textDidChange -{ - _textWasPasted = NO; - [self invalidatePlaceholderVisibility]; -} - -#pragma mark - Overrides - -- (void)setFont:(NSFont *)font -{ - // [super setFont:font]; - [[super textStorage] setFont:font]; - _placeholderView.font = font ?: defaultPlaceholderFont(); -} - -- (void)setTextAlignment:(NSTextAlignment)textAlignment -{ - // [super setTextAlignment:textAlignment]; - // _placeholderView.textAlignment = textAlignment; -} - -- (void)setText:(NSString *)text +- (NSAttributedString *)attributedText { - [self setString:text]; - [self textDidChange]; + return self.textStorage; } - (void)setAttributedText:(NSAttributedString *)attributedText { [self.textStorage setAttributedString:attributedText]; - [self textDidChange]; } -#pragma mark - Overrides +- (NSRange)selectedTextRange +{ + return self.selectedRange; +} -- (void)setSelectedTextRange:(UITextRange *)selectedTextRange notifyDelegate:(BOOL)notifyDelegate +- (void)setSelectedTextRange:(NSRange)selectedTextRange notifyDelegate:(BOOL)notifyDelegate { if (!notifyDelegate) { // We have to notify an adapter that following selection change was initiated programmatically, // so the adapter must not generate a notification for it. [_textInputDelegateAdapter skipNextTextInputDidChangeSelectionEventWithTextRange:selectedTextRange]; } - - [super setSelectedTextRange:selectedTextRange]; + [super setSelectedRange:selectedTextRange]; } -- (void)paste:(id)sender -{ - [super paste:sender]; - _textWasPasted = YES; -} - -- (void)setContentOffset:(CGPoint)contentOffset animated:(__unused BOOL)animated -{ - // Turning off scroll animation. - // This fixes the problem also known as "flaky scrolling". - // [super setContentOffset:contentOffset animated:NO]; -} - -#pragma mark - Layout +#pragma mark - Overrides -- (void)layout +- (BOOL)becomeFirstResponder { - [super layout]; + if ([super becomeFirstResponder]) { + // Move the cursor to the end of the current text. Note: Mouse clicks override this selection (which is intended). + self.selectedRange = NSMakeRange(self.textStorage.length, 0); - CGRect textFrame = UIEdgeInsetsSizeRect(self.bounds, self.textContainerInset); - CGFloat placeholderHeight = [_placeholderView sizeThatFits:textFrame.size].height; - textFrame.size.height = MIN(placeholderHeight, textFrame.size.height); - _placeholderView.frame = textFrame; + [_textInputDelegateAdapter performSelector:@selector(textViewDidFocus) withObject:nil afterDelay:0.0]; + return YES; + } + return NO; } -- (CGSize)intrinsicContentSize +- (void)keyDown:(NSEvent *)event { - // Returning size DOES contain `textContainerInset` (aka `padding`). - return [self sizeThatFits:CGSizeMake(self.preferredMaxLayoutWidth, INFINITY)]; + // Intercept "tab" key for focus control. + if (event.keyCode == 48) { + if (event.modifierFlags & NSShiftKeyMask) { + [self.window selectPreviousKeyView:nil]; + } else { + [self.window selectNextKeyView:nil]; + } + } else { + [super keyDown:event]; + } } -- (CGSize)sizeThatFits:(CGSize)size +- (void)paste:(id)sender { - NSRect rect = [super.layoutManager usedRectForTextContainer:super.textContainer]; - return CGSizeMake(MIN(rect.size.width, size.width), rect.size.height); + _textWasPasted = YES; + [super paste:sender]; } -#pragma mark - Placeholder - -- (void)invalidatePlaceholderVisibility +- (void)didChangeText { - BOOL isVisible = _placeholderText.length != 0 && self.string.length == 0; - _placeholderView.hidden = !isVisible; + [super didChangeText]; + + _textWasPasted = NO; + [self invalidateIntrinsicContentSize]; } @end diff --git a/Libraries/Text/TextInput/RCTBackedTextInputDelegate.h b/Libraries/Text/TextInput/RCTBackedTextInputDelegate.h index 444f0aa1b0..ed6a4fd238 100644 --- a/Libraries/Text/TextInput/RCTBackedTextInputDelegate.h +++ b/Libraries/Text/TextInput/RCTBackedTextInputDelegate.h @@ -11,6 +11,8 @@ @protocol RCTBackedTextInputViewProtocol; +NS_ASSUME_NONNULL_BEGIN + @protocol RCTBackedTextInputDelegate - (BOOL)textInputShouldBeginEditing; // Return `NO` to disallow editing. @@ -28,3 +30,5 @@ - (void)textInputDidChangeSelection; @end + +NS_ASSUME_NONNULL_END diff --git a/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.h b/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.h index c4a96c746e..3db40c6293 100644 --- a/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.h +++ b/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.h @@ -12,23 +12,31 @@ #import "RCTBackedTextInputViewProtocol.h" #import "RCTBackedTextInputDelegate.h" -#pragma mark - RCTBackedTextFieldDelegateAdapter (for UITextField) +NS_ASSUME_NONNULL_BEGIN + +#pragma mark - RCTBackedTextFieldDelegateAdapter (for NSTextField) @interface RCTBackedTextFieldDelegateAdapter : NSObject -- (instancetype)initWithTextField:(NSTextField *)backedTextInput; +- (instancetype)initWithTextField:(NSTextField *)backedTextInputView; -- (void)skipNextTextInputDidChangeSelectionEventWithTextRange:(NSRange *)textRange; +- (void)skipNextTextInputDidChangeSelectionEventWithTextRange:(NSRange)textRange; - (void)selectedTextRangeWasSet; +- (void)textFieldDidFocus; +- (void)textFieldDidBlur; +- (BOOL)shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text; @end -#pragma mark - RCTBackedTextViewDelegateAdapter (for UITextView) +#pragma mark - RCTBackedTextViewDelegateAdapter (for NSTextView) @interface RCTBackedTextViewDelegateAdapter : NSObject -- (instancetype)initWithTextView:(NSTextView *)backedTextInput; +- (instancetype)initWithTextView:(NSTextView *)backedTextInputView; -- (void)skipNextTextInputDidChangeSelectionEventWithTextRange:(NSRange *)textRange; +- (void)skipNextTextInputDidChangeSelectionEventWithTextRange:(NSRange)textRange; +- (void)textViewDidFocus; @end + +NS_ASSUME_NONNULL_END diff --git a/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.m b/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.m index a904823475..cf77e9afb1 100644 --- a/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.m +++ b/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.m @@ -8,8 +8,10 @@ */ #import "RCTBackedTextInputDelegateAdapter.h" +#import "RCTUITextView.h" +#import "NSText+Editing.h" -#pragma mark - RCTBackedTextFieldDelegateAdapter (for UITextField) +#pragma mark - RCTBackedTextFieldDelegateAdapter (for NSTextField) static void *TextFieldSelectionObservingContext = &TextFieldSelectionObservingContext; @@ -17,102 +19,83 @@ @interface RCTBackedTextFieldDelegateAdapter () @end @implementation RCTBackedTextFieldDelegateAdapter { - __weak NSTextField *_backedTextInput; + __weak NSTextField *_backedTextInputView; BOOL _textDidChangeIsComing; - NSRange *_previousSelectedTextRange; + NSRange _previousSelectedTextRange; } -- (instancetype)initWithTextField:(NSTextField *)backedTextInput +- (instancetype)initWithTextField:(NSTextField *)backedTextInputView { if (self = [super init]) { - _backedTextInput = backedTextInput; - backedTextInput.delegate = self; - - [_backedTextInput addTarget:self action:@selector(textFieldDidChange) forControlEvents:UIControlEventEditingChanged]; - [_backedTextInput addTarget:self action:@selector(textFieldDidEndEditingOnExit) forControlEvents:UIControlEventEditingDidEndOnExit]; + _backedTextInputView = backedTextInputView; + backedTextInputView.delegate = self; } return self; } -- (void)dealloc -{ - [_backedTextInput removeTarget:self action:nil forControlEvents:UIControlEventEditingChanged]; - [_backedTextInput removeTarget:self action:nil forControlEvents:UIControlEventEditingDidEndOnExit]; -} - -#pragma mark - UITextFieldDelegate +#pragma mark - NSTextFieldDelegate -- (BOOL)textFieldShouldBeginEditing:(__unused NSTextField *)textField +- (BOOL)control:(__unused NSControl *)control textShouldBeginEditing:(__unused NSText *)fieldEditor { - return [_backedTextInput.textInputDelegate textInputShouldBeginEditing]; + return [_backedTextInputView.textInputDelegate textInputShouldBeginEditing]; } -- (void)textFieldDidBeginEditing:(__unused NSTextField *)textField +- (void)textFieldDidFocus { - [_backedTextInput.textInputDelegate textInputDidBeginEditing]; + [_backedTextInputView.textInputDelegate textInputDidBeginEditing]; } -- (BOOL)textFieldShouldEndEditing:(__unused NSTextField *)textField +- (BOOL)control:(__unused NSControl *)control textShouldEndEditing:(__unused NSText *)fieldEditor { - return [_backedTextInput.textInputDelegate textInputShouldEndEditing]; + return [_backedTextInputView.textInputDelegate textInputShouldEndEditing]; } -- (void)textFieldDidEndEditing:(__unused NSTextField *)textField +- (void)textFieldDidBlur { if (_textDidChangeIsComing) { // iOS does't call `textViewDidChange:` delegate method if the change was happened because of autocorrection // which was triggered by losing focus. So, we call it manually. _textDidChangeIsComing = NO; - [_backedTextInput.textInputDelegate textInputDidChange]; + [_backedTextInputView.textInputDelegate textInputDidChange]; } - [_backedTextInput.textInputDelegate textInputDidEndEditing]; + [_backedTextInputView.textInputDelegate textInputDidEndEditing]; } -- (BOOL)textField:(__unused NSTextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string +- (BOOL)shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text { - BOOL result = [_backedTextInput.textInputDelegate textInputShouldChangeTextInRange:range replacementText:string]; + BOOL result = [_backedTextInputView.textInputDelegate textInputShouldChangeTextInRange:range replacementText:text]; if (result) { _textDidChangeIsComing = YES; } return result; } -- (BOOL)textFieldShouldReturn:(__unused NSTextField *)textField -{ - return [_backedTextInput.textInputDelegate textInputShouldReturn]; -} - #pragma mark - UIControlEventEditing* Family Events -- (void)textFieldDidChange +- (void)controlTextDidChange:(NSNotification *)notification { _textDidChangeIsComing = NO; - [_backedTextInput.textInputDelegate textInputDidChange]; + [_backedTextInputView.textInputDelegate textInputDidChange]; // `selectedTextRangeWasSet` isn't triggered during typing. [self textFieldProbablyDidChangeSelection]; } -- (void)textFieldDidEndEditingOnExit -{ - [_backedTextInput.textInputDelegate textInputDidReturn]; -} - #pragma mark - UIKeyboardInput (private UIKit protocol) // This method allows us to detect a [Backspace] `keyPress` // even when there is no more text in the `UITextField`. -- (BOOL)keyboardInputShouldDelete:(__unused NSTextField *)textField -{ - [_backedTextInput.textInputDelegate textInputShouldChangeTextInRange:NSMakeRange(0, 0) replacementText:@""]; - return YES; -} +//- (BOOL)keyboardInputShouldDelete:(__unused UITextField *)textField +//{ +// [_backedTextInputView.textInputDelegate textInputShouldChangeTextInRange:NSMakeRange(0, 0) replacementText:@""]; +// return YES; +//} #pragma mark - Public Interface -- (void)skipNextTextInputDidChangeSelectionEventWithTextRange:(NSRange *)textRange +- (void)skipNextTextInputDidChangeSelectionEventWithTextRange:(NSRange)textRange { _previousSelectedTextRange = textRange; } @@ -126,12 +109,12 @@ - (void)selectedTextRangeWasSet - (void)textFieldProbablyDidChangeSelection { - if ([_backedTextInput.selectedTextRange isEqual:_previousSelectedTextRange]) { + if (NSEqualRanges(_backedTextInputView.selectedTextRange, _previousSelectedTextRange)) { return; } - _previousSelectedTextRange = _backedTextInput.selectedTextRange; - [_backedTextInput.textInputDelegate textInputDidChangeSelection]; + _previousSelectedTextRange = _backedTextInputView.selectedTextRange; + [_backedTextInputView.textInputDelegate textInputDidChangeSelection]; } @end @@ -142,82 +125,87 @@ @interface RCTBackedTextViewDelegateAdapter () @end @implementation RCTBackedTextViewDelegateAdapter { - __weak NSTextView *_backedTextInput; + __unsafe_unretained NSTextView *_backedTextInputView; BOOL _textDidChangeIsComing; - NSRange *_previousSelectedTextRange; + NSRange _previousSelectedTextRange; } -- (instancetype)initWithTextView:(NSTextView *)backedTextInput +- (instancetype)initWithTextView:(NSTextView *)backedTextInputView { if (self = [super init]) { - _backedTextInput = backedTextInput; - backedTextInput.delegate = self; + _backedTextInputView = backedTextInputView; + backedTextInputView.delegate = self; } return self; } -#pragma mark - UITextViewDelegate +#pragma mark - NSTextViewDelegate -- (BOOL)textViewShouldBeginEditing:(__unused NSTextView *)textView +- (BOOL)textShouldBeginEditing:(__unused NSText *)text { - return [_backedTextInput.textInputDelegate textInputShouldBeginEditing]; + return [_backedTextInputView.textInputDelegate textInputShouldBeginEditing]; } -- (void)textViewDidBeginEditing:(__unused NSTextView *)textView +- (void)textViewDidFocus { - [_backedTextInput.textInputDelegate textInputDidBeginEditing]; + [_backedTextInputView.textInputDelegate textInputDidBeginEditing]; } -- (BOOL)textViewShouldEndEditing:(__unused UITextView *)textView +- (BOOL)textShouldEndEditing:(__unused NSText *)text { - return [_backedTextInput.textInputDelegate textInputShouldEndEditing]; + return [_backedTextInputView.textInputDelegate textInputShouldEndEditing]; } -- (void)textViewDidEndEditing:(__unused UITextView *)textView +- (void)textDidEndEditing:(__unused NSNotification *)notification { if (_textDidChangeIsComing) { // iOS does't call `textViewDidChange:` delegate method if the change was happened because of autocorrection // which was triggered by losing focus. So, we call it manually. _textDidChangeIsComing = NO; - [_backedTextInput.textInputDelegate textInputDidChange]; + [_backedTextInputView.textInputDelegate textInputDidChange]; } - [_backedTextInput.textInputDelegate textInputDidEndEditing]; + // Silently clear the selection when editing ends. + [_backedTextInputView setSelectedTextRange:(NSRange){0, 0} notifyDelegate:NO]; + + [_backedTextInputView.textInputDelegate textInputDidEndEditing]; } -- (BOOL)textView:(__unused NSTextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text +- (BOOL)textView:(__unused NSTextView *)textView shouldChangeTextInRange:(NSRange)range replacementString:(NSString *)text { - // Custom implementation of `textInputShouldReturn` and `textInputDidReturn` pair for `UITextView`. - if (!_backedTextInput.textWasPasted && [text isEqualToString:@"\n"]) { - if ([_backedTextInput.textInputDelegate textInputShouldReturn]) { - [_backedTextInput.textInputDelegate textInputDidReturn]; - [_backedTextInput endEditing:NO]; + // Custom implementation of `textInputShouldReturn` and `textInputDidReturn` pair for `NSTextView`. + if (!_backedTextInputView.textWasPasted && [text isEqualToString:@"\n"]) { + if ([_backedTextInputView.textInputDelegate textInputShouldReturn]) { + [_backedTextInputView.textInputDelegate textInputDidReturn]; + [_backedTextInputView endEditing:NO]; return NO; } } - BOOL result = [_backedTextInput.textInputDelegate textInputShouldChangeTextInRange:range replacementText:text]; + BOOL result = [_backedTextInputView.textInputDelegate textInputShouldChangeTextInRange:range replacementText:text]; if (result) { _textDidChangeIsComing = YES; } return result; } -- (void)textViewDidChange:(__unused UITextView *)textView +- (void)textDidChange:(__unused NSNotification *)notification { _textDidChangeIsComing = NO; - [_backedTextInput.textInputDelegate textInputDidChange]; + [_backedTextInputView.textInputDelegate textInputDidChange]; } -- (void)textViewDidChangeSelection:(__unused UITextView *)textView +- (void)textViewDidChangeSelection:(__unused NSNotification *)notification { - [self textViewProbablyDidChangeSelection]; + if (_backedTextInputView == _backedTextInputView.window.firstResponder) { + [self textViewProbablyDidChangeSelection]; + } } #pragma mark - Public Interface -- (void)skipNextTextInputDidChangeSelectionEventWithTextRange:(UITextRange *)textRange +- (void)skipNextTextInputDidChangeSelectionEventWithTextRange:(NSRange)textRange { _previousSelectedTextRange = textRange; } @@ -226,12 +214,12 @@ - (void)skipNextTextInputDidChangeSelectionEventWithTextRange:(UITextRange *)tex - (void)textViewProbablyDidChangeSelection { - if ([_backedTextInput.selectedTextRange isEqual:_previousSelectedTextRange]) { + if (NSEqualRanges(_backedTextInputView.selectedTextRange, _previousSelectedTextRange)) { return; } - _previousSelectedTextRange = _backedTextInput.selectedTextRange; - [_backedTextInput.textInputDelegate textInputDidChangeSelection]; + _previousSelectedTextRange = _backedTextInputView.selectedTextRange; + [_backedTextInputView.textInputDelegate textInputDidChangeSelection]; } @end diff --git a/Libraries/Text/TextInput/RCTBackedTextInputViewProtocol.h b/Libraries/Text/TextInput/RCTBackedTextInputViewProtocol.h index e60de04816..b7614378fa 100644 --- a/Libraries/Text/TextInput/RCTBackedTextInputViewProtocol.h +++ b/Libraries/Text/TextInput/RCTBackedTextInputViewProtocol.h @@ -11,25 +11,37 @@ @protocol RCTBackedTextInputDelegate; -@protocol RCTBackedTextInputViewProtocol +NS_ASSUME_NONNULL_BEGIN + +@protocol RCTBackedTextInputViewProtocol -@property (nonatomic, copy, nullable) NSString *text; @property (nonatomic, strong, nullable) NSColor *textColor; -@property (nonatomic, copy, nullable) NSString *placeholder; -@property (nonatomic, strong, nullable) NSColor *placeholderColor; -@property (nonatomic, assign, readonly) BOOL textWasPasted; @property (nonatomic, strong, nullable) NSFont *font; -@property (nonatomic, assign) NSEdgeInsets textContainerInset; -@property (nonatomic, strong, nullable) NSView *inputAccessoryView; +@property (nonatomic, copy, nullable) NSAttributedString *attributedText; +// @property (nonatomic, copy, nullable) NSString *placeholder; +// @property (nonatomic, strong, nullable) NSColor *placeholderColor; +@property (nonatomic, assign) NSTextAlignment alignment; +@property (nonatomic, assign, readonly) BOOL textWasPasted; +@property (nonatomic, assign) NSEdgeInsets paddingInsets; +//@property (nonatomic, strong, nullable) NSView *inputAccessoryView; @property (nonatomic, weak, nullable) id textInputDelegate; -@property (nonatomic, readonly) CGSize contentSize; +//@property (nonatomic, readonly) CGSize contentSize; // This protocol disallows direct access to `selectedTextRange` property because // unwise usage of it can break the `delegate` behavior. So, we always have to // explicitly specify should `delegate` be notified about the change or not. // If the change was initiated programmatically, we must NOT notify the delegate. // If the change was a result of user actions (like typing or touches), we MUST notify the delegate. -- (void)setSelectedTextRange:(NSRange)selectedTextRange NS_UNAVAILABLE; +@property (nonatomic, readonly) NSRange selectedTextRange; - (void)setSelectedTextRange:(NSRange)selectedTextRange notifyDelegate:(BOOL)notifyDelegate; +// This protocol disallows direct access to `text` property because +// unwise usage of it can break the `attributeText` behavior. +// Use `attributedText.string` instead. +//@property (nonatomic, copy, nullable) NSString *text NS_UNAVAILABLE; + +- (void)selectAll:(nullable id)sender; + @end + +NS_ASSUME_NONNULL_END diff --git a/Libraries/Text/TextInput/RCTBaseTextInputShadowView.h b/Libraries/Text/TextInput/RCTBaseTextInputShadowView.h new file mode 100644 index 0000000000..3f1e8185b3 --- /dev/null +++ b/Libraries/Text/TextInput/RCTBaseTextInputShadowView.h @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "RCTBaseTextShadowView.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface RCTBaseTextInputShadowView : RCTBaseTextShadowView + +- (instancetype)initWithBridge:(RCTBridge *)bridge; + +@property (nonatomic, copy, nullable) NSString *text; +@property (nonatomic, copy, nullable) NSString *placeholder; +@property (nonatomic, assign) NSInteger maximumNumberOfLines; +@property (nonatomic, copy, nullable) RCTDirectEventBlock onContentSizeChange; + +- (void)uiManagerWillPerformMounting; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Libraries/Text/TextInput/RCTBaseTextInputShadowView.m b/Libraries/Text/TextInput/RCTBaseTextInputShadowView.m new file mode 100644 index 0000000000..b4a045f19b --- /dev/null +++ b/Libraries/Text/TextInput/RCTBaseTextInputShadowView.m @@ -0,0 +1,313 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "RCTBaseTextInputShadowView.h" + +#import +#import +#import +#import + +#import "NSTextStorage+FontScaling.h" +#import "RCTBaseTextInputView.h" + +@implementation RCTBaseTextInputShadowView +{ + __weak RCTBridge *_bridge; + NSAttributedString *_Nullable _previousAttributedText; + BOOL _needsUpdateView; + NSAttributedString *_Nullable _localAttributedText; + CGSize _previousContentSize; + + NSString *_text; + NSTextStorage *_textStorage; + NSTextContainer *_textContainer; + NSLayoutManager *_layoutManager; +} + +- (instancetype)initWithBridge:(RCTBridge *)bridge +{ + if (self = [super init]) { + _bridge = bridge; + _needsUpdateView = YES; + + YGNodeSetMeasureFunc(self.yogaNode, RCTBaseTextInputShadowViewMeasure); + YGNodeSetBaselineFunc(self.yogaNode, RCTTextInputShadowViewBaseline); + } + + return self; +} + +- (BOOL)isYogaLeafNode +{ + return YES; +} + +- (void)layoutSubviewsWithContext:(RCTLayoutContext)layoutContext +{ + // Do nothing. +} + +- (void)setLocalData:(NSObject *)localData +{ + NSAttributedString *attributedText = (NSAttributedString *)localData; + + if ([attributedText isEqualToAttributedString:_localAttributedText]) { + return; + } + + _localAttributedText = attributedText; + [self dirtyLayout]; +} + +- (void)dirtyLayout +{ + [super dirtyLayout]; + _needsUpdateView = YES; + YGNodeMarkDirty(self.yogaNode); + [self invalidateContentSize]; +} + +- (void)invalidateContentSize +{ + if (!_onContentSizeChange) { + return; + } + + CGSize maximumSize = self.layoutMetrics.frame.size; + + if (_maximumNumberOfLines == 1) { + maximumSize.width = CGFLOAT_MAX; + } else { + maximumSize.height = CGFLOAT_MAX; + } + + CGSize contentSize = [self sizeThatFitsMinimumSize:(CGSize)CGSizeZero maximumSize:maximumSize]; + + if (CGSizeEqualToSize(_previousContentSize, contentSize)) { + return; + } + _previousContentSize = contentSize; + + _onContentSizeChange(@{ + @"contentSize": @{ + @"height": @(contentSize.height), + @"width": @(contentSize.width), + }, + @"target": self.reactTag, + }); +} + +- (NSString *)text +{ + return _text; +} + +- (void)setText:(NSString *)text +{ + _text = text; + // Clear `_previousAttributedText` to notify the view about the change + // when `text` native prop is set. + _previousAttributedText = nil; + [self dirtyLayout]; +} + +#pragma mark - RCTUIManagerObserver + +- (void)uiManagerWillPerformMounting +{ + if (YGNodeIsDirty(self.yogaNode)) { + return; + } + + if (!_needsUpdateView) { + return; + } + _needsUpdateView = NO; + + NSEdgeInsets borderInsets = self.borderAsInsets; + NSEdgeInsets paddingInsets = self.paddingAsInsets; + + RCTTextAttributes *textAttributes = [self.textAttributes copy]; + + NSMutableAttributedString *attributedText = + [[NSMutableAttributedString alloc] initWithAttributedString:[self attributedTextWithBaseTextAttributes:nil]]; + + // Removing all references to Shadow Views and tags to avoid unnececery retainning + // and problems with comparing the strings. + [attributedText removeAttribute:RCTBaseTextShadowViewEmbeddedShadowViewAttributeName + range:NSMakeRange(0, attributedText.length)]; + + [attributedText removeAttribute:RCTTextAttributesTagAttributeName + range:NSMakeRange(0, attributedText.length)]; + + if (self.text.length) { + NSAttributedString *propertyAttributedText = + [[NSAttributedString alloc] initWithString:self.text + attributes:self.textAttributes.effectiveTextAttributes]; + [attributedText insertAttributedString:propertyAttributedText atIndex:0]; + } + + BOOL isAttributedTextChanged = NO; + if (![_previousAttributedText isEqualToAttributedString:attributedText]) { + // We have to follow `set prop` pattern: + // If the value has not changed, we must not notify the view about the change, + // otherwise we may break local (temporary) state of the text input. + isAttributedTextChanged = YES; + _previousAttributedText = [attributedText copy]; + } + + NSNumber *tag = self.reactTag; + + [_bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary *viewRegistry) { + RCTBaseTextInputView *baseTextInputView = (RCTBaseTextInputView *)viewRegistry[tag]; + if (!baseTextInputView) { + return; + } + + baseTextInputView.textAttributes = textAttributes; + baseTextInputView.reactBorderInsets = borderInsets; + baseTextInputView.reactPaddingInsets = paddingInsets; + + if (isAttributedTextChanged) { + baseTextInputView.attributedText = attributedText; + } + }]; +} + +#pragma mark - + +- (NSAttributedString *)measurableAttributedText +{ + // Only for the very first render when we don't have `_localAttributedText`, + // we use value directly from the property and/or nested content. + NSAttributedString *attributedText = + _localAttributedText ?: [self attributedTextWithBaseTextAttributes:nil]; + + if (attributedText.length == 0) { + // It's impossible to measure empty attributed string because all attributes are + // assosiated with some characters, so no characters means no data. + + // Placeholder also can represent the intrinsic size when it is visible. + NSString *text = self.placeholder; + if (!text.length) { + // Note: `zero-width space` is insufficient in some cases. + text = @"I"; + } + attributedText = [[NSAttributedString alloc] initWithString:text attributes:self.textAttributes.effectiveTextAttributes]; + } + + return attributedText; +} + +- (CGSize)sizeThatFitsMinimumSize:(CGSize)minimumSize maximumSize:(CGSize)maximumSize +{ + NSAttributedString *attributedText = [self measurableAttributedText]; + + if (!_textStorage) { + _textContainer = [NSTextContainer new]; + _textContainer.lineFragmentPadding = 0.0; // Note, the default value is 5. + _layoutManager = [NSLayoutManager new]; + [_layoutManager addTextContainer:_textContainer]; + _textStorage = [NSTextStorage new]; + [_textStorage addLayoutManager:_layoutManager]; + } + + _textContainer.size = maximumSize; + _textContainer.maximumNumberOfLines = _maximumNumberOfLines; + [_textStorage replaceCharactersInRange:(NSRange){0, _textStorage.length} + withAttributedString:attributedText]; + [_layoutManager ensureLayoutForTextContainer:_textContainer]; + CGSize size = [_layoutManager usedRectForTextContainer:_textContainer].size; + + return (CGSize){ + MAX(minimumSize.width, MIN(RCTCeilPixelValue(size.width), maximumSize.width)), + MAX(minimumSize.height, MIN(RCTCeilPixelValue(size.height), maximumSize.height)) + }; +} + +- (CGFloat)lastBaselineForSize:(CGSize)size +{ + NSAttributedString *attributedText = [self measurableAttributedText]; + + __block CGFloat maximumDescender = 0.0; + + [attributedText enumerateAttribute:NSFontAttributeName + inRange:NSMakeRange(0, attributedText.length) + options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired + usingBlock: + ^(NSFont *font, NSRange range, __unused BOOL *stop) { + if (maximumDescender > font.descender) { + maximumDescender = font.descender; + } + } + ]; + + return size.height + maximumDescender; +} + +static YGSize RCTBaseTextInputShadowViewMeasure(YGNodeRef node, float width, YGMeasureMode widthMode, float height, YGMeasureMode heightMode) +{ + RCTShadowView *shadowView = (__bridge RCTShadowView *)YGNodeGetContext(node); + + CGSize minimumSize = CGSizeMake(0, 0); + CGSize maximumSize = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX); + + CGSize size = { + RCTCoreGraphicsFloatFromYogaFloat(width), + RCTCoreGraphicsFloatFromYogaFloat(height) + }; + + switch (widthMode) { + case YGMeasureModeUndefined: + break; + case YGMeasureModeExactly: + minimumSize.width = size.width; + maximumSize.width = size.width; + break; + case YGMeasureModeAtMost: + maximumSize.width = size.width; + break; + } + + switch (heightMode) { + case YGMeasureModeUndefined: + break; + case YGMeasureModeExactly: + minimumSize.height = size.height; + maximumSize.height = size.height; + break; + case YGMeasureModeAtMost: + maximumSize.height = size.height; + break; + } + + CGSize measuredSize = [shadowView sizeThatFitsMinimumSize:minimumSize maximumSize:maximumSize]; + + return (YGSize){ + RCTYogaFloatFromCoreGraphicsFloat(measuredSize.width), + RCTYogaFloatFromCoreGraphicsFloat(measuredSize.height) + }; +} + +static float RCTTextInputShadowViewBaseline(YGNodeRef node, const float width, const float height) +{ + RCTBaseTextInputShadowView *shadowTextView = (__bridge RCTBaseTextInputShadowView *)YGNodeGetContext(node); + + CGSize size = (CGSize){ + RCTCoreGraphicsFloatFromYogaFloat(width), + RCTCoreGraphicsFloatFromYogaFloat(height) + }; + + CGFloat lastBaseline = [shadowTextView lastBaselineForSize:size]; + + return RCTYogaFloatFromCoreGraphicsFloat(lastBaseline); +} + +@end diff --git a/Libraries/Text/TextInput/RCTBaseTextInputView.h b/Libraries/Text/TextInput/RCTBaseTextInputView.h index 8edebf4391..e81b9159ef 100644 --- a/Libraries/Text/TextInput/RCTBaseTextInputView.h +++ b/Libraries/Text/TextInput/RCTBaseTextInputView.h @@ -11,22 +11,17 @@ #import +#import "RCTBackedTextInputDelegate.h" #import "RCTBackedTextInputViewProtocol.h" -#import "RCTFontAttributes.h" -#import "RCTFontAttributesDelegate.h" @class RCTBridge; @class RCTEventDispatcher; +@class RCTTextAttributes; @class RCTTextSelection; -@interface RCTBaseTextInputView : RCTView { -@protected - __weak RCTBridge *_bridge; - RCTEventDispatcher *_eventDispatcher; - NSInteger _nativeEventCount; - NSInteger _mostRecentEventCount; - BOOL _blurOnSubmit; -} +NS_ASSUME_NONNULL_BEGIN + +@interface RCTBaseTextInputView : RCTView - (instancetype)initWithBridge:(RCTBridge *)bridge NS_DESIGNATED_INITIALIZER; @@ -36,33 +31,26 @@ @property (nonatomic, readonly) NSView *backedTextInputView; +@property (nonatomic, strong, nullable) RCTTextAttributes *textAttributes; @property (nonatomic, assign) NSEdgeInsets reactPaddingInsets; @property (nonatomic, assign) NSEdgeInsets reactBorderInsets; -@property (nonatomic, assign, readonly) CGSize contentSize; - -@property (nonatomic, copy) RCTDirectEventBlock onContentSizeChange; -@property (nonatomic, copy) RCTDirectEventBlock onSelectionChange; -@property (nonatomic, readonly, strong) RCTFontAttributes *fontAttributes; +@property (nonatomic, copy, nullable) RCTDirectEventBlock onContentSizeChange; +@property (nonatomic, copy, nullable) RCTDirectEventBlock onSelectionChange; +@property (nonatomic, copy, nullable) RCTDirectEventBlock onChange; +@property (nonatomic, copy, nullable) RCTDirectEventBlock onTextInput; +//@property (nonatomic, copy, nullable) RCTDirectEventBlock onScroll; @property (nonatomic, assign) NSInteger mostRecentEventCount; @property (nonatomic, assign) BOOL blurOnSubmit; @property (nonatomic, assign) BOOL selectTextOnFocus; @property (nonatomic, assign) BOOL clearTextOnFocus; @property (nonatomic, copy) RCTTextSelection *selection; - -- (void)setFont:(NSFont *)font; - -- (void)invalidateContentSize; - -// Temporary exposure of particial `RCTBackedTextInputDelegate` support. -// In the future all methods of the protocol should move to this class. -- (BOOL)textInputShouldBeginEditing; -- (void)textInputDidBeginEditing; -- (BOOL)textInputShouldReturn; -- (void)textInputDidReturn; -- (void)textInputDidChangeSelection; -- (BOOL)textInputShouldEndEditing; -- (void)textInputDidEndEditing; +@property (nonatomic, strong, nullable) NSNumber *maxLength; +@property (nonatomic, copy) NSAttributedString *attributedText; +@property (nonatomic, copy, nullable) NSString *placeholder; +@property (nonatomic, strong, nullable) NSColor *placeholderColor; @end + +NS_ASSUME_NONNULL_END diff --git a/Libraries/Text/TextInput/RCTBaseTextInputView.m b/Libraries/Text/TextInput/RCTBaseTextInputView.m index 6a6e616763..780ee61448 100644 --- a/Libraries/Text/TextInput/RCTBaseTextInputView.m +++ b/Libraries/Text/TextInput/RCTBaseTextInputView.m @@ -9,7 +9,7 @@ #import "RCTBaseTextInputView.h" -#import +//#import #import #import #import @@ -17,11 +17,17 @@ #import #import +#import "NSLabel.h" +#import "RCTTextAttributes.h" #import "RCTTextSelection.h" @implementation RCTBaseTextInputView { - CGSize _previousContentSize; - BOOL _hasInputAccesoryView; + __weak RCTBridge *_bridge; + __weak RCTEventDispatcher *_eventDispatcher; +// BOOL _hasInputAccesoryView; + NSString *_Nullable _predictedText; + NSInteger _nativeEventCount; + NSLabel *_placeholderView; } - (instancetype)initWithBridge:(RCTBridge *)bridge @@ -31,8 +37,8 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge if (self = [super initWithFrame:CGRectZero]) { _bridge = bridge; _eventDispatcher = bridge.eventDispatcher; - _fontAttributes = [[RCTFontAttributes alloc] initWithAccessibilityManager:bridge.accessibilityManager]; - _fontAttributes.delegate = self; + + self.clipsToBounds = YES; } return self; @@ -42,47 +48,91 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)decoder) RCT_NOT_IMPLEMENTED(- (instancetype)initWithFrame:(CGRect)frame) -- (id)backedTextInputView +- (NSView *)backedTextInputView { RCTAssert(NO, @"-[RCTBaseTextInputView backedTextInputView] must be implemented in subclass."); return nil; } -- (void)setFont:(NSFont *)font -{ - self.backedTextInputView.font = font; - [self invalidateContentSize]; -} +#pragma mark - RCTComponent -- (void)fontAttributesDidChangeWithFont:(NSFont *)font +- (void)didUpdateReactSubviews { - self.font = font; + // Do nothing. } #pragma mark - Properties +- (void)setTextAttributes:(RCTTextAttributes *)textAttributes +{ + _textAttributes = textAttributes; + + id backedTextInputView = self.backedTextInputView; + backedTextInputView.font = _textAttributes.effectiveFont; + backedTextInputView.textColor = _textAttributes.effectiveForegroundColor; + backedTextInputView.alignment = _textAttributes.alignment; + + [self updatePlaceholderStyle]; +} + - (void)setReactPaddingInsets:(NSEdgeInsets)reactPaddingInsets { _reactPaddingInsets = reactPaddingInsets; // We apply `paddingInsets` as `backedTextInputView`'s `textContainerInset`. - self.backedTextInputView.textContainerInset = reactPaddingInsets; - [self setNeedsLayout]; + self.backedTextInputView.paddingInsets = reactPaddingInsets; + [self updatePlaceholderFrame]; + [self setNeedsLayout:YES]; } - (void)setReactBorderInsets:(NSEdgeInsets)reactBorderInsets { _reactBorderInsets = reactBorderInsets; - // We apply `borderInsets` as `backedTextInputView` layout offset. - self.backedTextInputView.frame = NSEdgeInsetsInsetRect(self.bounds, reactBorderInsets); - [self setNeedsLayout]; + [self updatePlaceholderFrame]; + [self setNeedsLayout:YES]; +} + +- (NSAttributedString *)attributedText +{ + return self.backedTextInputView.attributedText; +} + +- (void)setAttributedText:(NSAttributedString *)attributedText +{ + NSInteger eventLag = _nativeEventCount - _mostRecentEventCount; + + if (eventLag == 0 && ![attributedText isEqualToAttributedString:self.backedTextInputView.attributedText]) { + NSRange selection = self.backedTextInputView.selectedTextRange; + NSInteger oldTextLength = self.backedTextInputView.attributedText.string.length; + + self.backedTextInputView.attributedText = attributedText; + [self updatePlaceholderVisibility]; + + if (selection.length == 0) { + // Maintaining a cursor position relative to the end of the old text. + NSInteger offsetStart = selection.location; +// [self.backedTextInputView offsetFromPosition:self.backedTextInputView.beginningOfDocument +// toPosition:selection.start]; + NSInteger offsetFromEnd = oldTextLength - offsetStart; + NSInteger newOffset = attributedText.string.length - offsetFromEnd; +// UITextPosition *position = +// [self.backedTextInputView positionFromPosition:self.backedTextInputView.beginningOfDocument +// offset:newOffset]; + [self.backedTextInputView setSelectedTextRange:(NSRange){newOffset, 0} + notifyDelegate:YES]; + } + + [self updateLocalData]; + } else if (eventLag > RCTTextUpdateLagWarningThreshold) { + RCTLogWarn(@"Native TextInput(%@) is %lld events ahead of JS - try to make your JS faster.", self.backedTextInputView.attributedText.string, (long long)eventLag); + } } - (RCTTextSelection *)selection { - id backedTextInput = self.backedTextInputView; - NSTextRange *selectedTextRange = backedTextInput.selectedTextRange; - return [[RCTTextSelection new] initWithStart:[backedTextInput offsetFromPosition:backedTextInput.beginningOfDocument toPosition:selectedTextRange.start] - end:[backedTextInput offsetFromPosition:backedTextInput.beginningOfDocument toPosition:selectedTextRange.end]]; + id backedTextInputView = self.backedTextInputView; + NSRange selectedTextRange = [backedTextInputView selectedTextRange]; + return [[RCTTextSelection new] initWithStart:selectedTextRange.location + end:selectedTextRange.location + selectedTextRange.length]; } - (void)setSelection:(RCTTextSelection *)selection @@ -91,18 +141,18 @@ - (void)setSelection:(RCTTextSelection *)selection return; } - id backedTextInput = self.backedTextInputView; + id backedTextInputView = self.backedTextInputView; + + NSRange previousSelectedTextRange = [backedTextInputView selectedTextRange]; + NSRange selectedTextRange = (NSRange){selection.start, selection.end - selection.start}; + - NSRange previousSelectedTextRange = backedTextInput.; - NSTextPosition *start = [backedTextInput positionFromPosition:backedTextInput.beginningOfDocument offset:selection.start]; - NSTextPosition *end = [backedTextInput positionFromPosition:backedTextInput.beginningOfDocument offset:selection.end]; - NSRange selectedTextRange = [backedTextInput textRangeFromPosition:start toPosition:end]; NSInteger eventLag = _nativeEventCount - _mostRecentEventCount; - if (eventLag == 0 && ![previousSelectedTextRange isEqual:selectedTextRange]) { - [backedTextInput setSelectedTextRange:selectedTextRange notifyDelegate:NO]; + if (eventLag == 0 && !NSEqualRanges(previousSelectedTextRange, selectedTextRange)) { + [backedTextInputView setSelectedTextRange:selectedTextRange notifyDelegate:NO]; } else if (eventLag > RCTTextUpdateLagWarningThreshold) { - RCTLogWarn(@"Native TextInput(%@) is %lld events ahead of JS - try to make your JS faster.", backedTextInput.text, (long long)eventLag); + RCTLogWarn(@"Native TextInput(%@) is %lld events ahead of JS - try to make your JS faster.", backedTextInputView.attributedText.string, (long long)eventLag); } } @@ -116,7 +166,8 @@ - (BOOL)textInputShouldBeginEditing - (void)textInputDidBeginEditing { if (_clearTextOnFocus) { - self.backedTextInputView.text = @""; + self.backedTextInputView.attributedText = [NSAttributedString new]; + [self updatePlaceholderVisibility]; } if (_selectTextOnFocus) { @@ -125,47 +176,11 @@ - (void)textInputDidBeginEditing [_eventDispatcher sendTextEventWithType:RCTTextEventTypeFocus reactTag:self.reactTag - text:self.backedTextInputView.text + text:self.backedTextInputView.attributedText.string key:nil eventCount:_nativeEventCount]; } -- (BOOL)textInputShouldReturn -{ - // We send `submit` event here, in `textInputShouldReturn` - // (not in `textInputDidReturn)`, because of semantic of the event: - // `onSubmitEditing` is called when "Submit" button - // (the blue key on onscreen keyboard) did pressed - // (no connection to any specific "submitting" process). - [_eventDispatcher sendTextEventWithType:RCTTextEventTypeSubmit - reactTag:self.reactTag - text:self.backedTextInputView.text - key:nil - eventCount:_nativeEventCount]; - - return _blurOnSubmit; -} - -- (void)textInputDidReturn -{ - // Does nothing. -} - -- (void)textInputDidChangeSelection -{ - if (!_onSelectionChange) { - return; - } - - RCTTextSelection *selection = self.selection; - _onSelectionChange(@{ - @"selection": @{ - @"start": @(selection.start), - @"end": @(selection.end), - }, - }); -} - - (BOOL)textInputShouldEndEditing { return YES; @@ -175,91 +190,192 @@ - (void)textInputDidEndEditing { [_eventDispatcher sendTextEventWithType:RCTTextEventTypeEnd reactTag:self.reactTag - text:self.backedTextInputView.text + text:self.backedTextInputView.attributedText.string key:nil eventCount:_nativeEventCount]; [_eventDispatcher sendTextEventWithType:RCTTextEventTypeBlur reactTag:self.reactTag - text:self.backedTextInputView.text + text:self.backedTextInputView.attributedText.string key:nil eventCount:_nativeEventCount]; } -#pragma mark - Content Size (in Yoga terms, without any insets) +- (BOOL)textInputShouldReturn +{ + return _blurOnSubmit; +} -- (CGSize)contentSize +- (void)textInputDidReturn { - CGSize contentSize = self.backedTextInputView.contentSize; - UIEdgeInsets reactPaddingInsets = self.reactPaddingInsets; - contentSize.width -= reactPaddingInsets.left + reactPaddingInsets.right; - contentSize.height -= reactPaddingInsets.top + reactPaddingInsets.bottom; - // Returning value does NOT include border and padding insets. - return contentSize; + [_eventDispatcher sendTextEventWithType:RCTTextEventTypeSubmit + reactTag:self.reactTag + text:self.backedTextInputView.attributedText.string + key:nil + eventCount:_nativeEventCount]; } -- (void)invalidateContentSize +- (BOOL)textInputShouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text { - // Updates `contentSize` property and notifies Yoga about the change, if necessary. - CGSize contentSize = self.contentSize; + id backedTextInputView = self.backedTextInputView; + + if (!backedTextInputView.textWasPasted) { + [_eventDispatcher sendTextEventWithType:RCTTextEventTypeKeyPress + reactTag:self.reactTag + text:nil + key:text + eventCount:_nativeEventCount]; + } - if (CGSizeEqualToSize(_previousContentSize, contentSize)) { - return; + if (_maxLength) { + NSUInteger allowedLength = _maxLength.integerValue - backedTextInputView.attributedText.string.length + range.length; + + if (text.length > allowedLength) { + // If we typed/pasted more than one character, limit the text inputted. + if (text.length > 1) { + // Truncate the input string so the result is exactly maxLength + NSString *limitedString = [text substringToIndex:allowedLength]; + NSMutableAttributedString *newAttributedText = [backedTextInputView.attributedText mutableCopy]; + [newAttributedText replaceCharactersInRange:range withString:limitedString]; + backedTextInputView.attributedText = newAttributedText; + _predictedText = newAttributedText.string; + + // Collapse selection at end of insert to match normal paste behavior. + [backedTextInputView setSelectedTextRange:(NSRange){range.location + allowedLength, 0} + notifyDelegate:YES]; + + + + [self textInputDidChange]; + } + + return NO; + } } - _previousContentSize = contentSize; - [_bridge.uiManager setIntrinsicContentSize:contentSize forView:self]; + if (range.location + range.length > _predictedText.length) { + // _predictedText got out of sync in a bad way, so let's just force sync it. Haven't been able to repro this, but + // it's causing a real crash here: #6523822 + _predictedText = backedTextInputView.attributedText.string; + } - if (_onContentSizeChange) { - _onContentSizeChange(@{ - @"contentSize": @{ - @"height": @(contentSize.height), - @"width": @(contentSize.width), + NSString *previousText = [_predictedText substringWithRange:range] ?: @""; + + // After clearing the text by replacing it with an empty string, `_predictedText` + // still preserves the deleted text. + // As the first character in the TextInput always comes with the range value (0, 0), + // we should check the range value in order to avoid appending a character to the deleted string + // (which caused the issue #18374) + if (!NSEqualRanges(range, NSMakeRange(0, 0)) && _predictedText) { + _predictedText = [_predictedText stringByReplacingCharactersInRange:range withString:text]; + } else { + _predictedText = [text copy]; + } + + if (_onTextInput) { + _onTextInput(@{ + @"text": text, + @"previousText": previousText, + @"range": @{ + @"start": @(range.location), + @"end": @(range.location + range.length) }, - @"target": self.reactTag, + @"eventCount": @(_nativeEventCount), }); } -} -#pragma mark - Layout (in UIKit terms, with all insets) + return YES; +} -- (CGSize)intrinsicContentSize +- (void)textInputDidChange { - CGSize size = self.backedTextInputView.intrinsicContentSize; - size.width += _reactBorderInsets.left + _reactBorderInsets.right; - size.height += _reactBorderInsets.top + _reactBorderInsets.bottom; - // Returning value DOES include border and padding insets. - return size; + [self updateLocalData]; + [self updatePlaceholderVisibility]; + + NSString *text = self.attributedText.string; + + // Detect when `backedTextInputView` updates happend that didn't invoke `shouldChangeTextInRange` + // (e.g. typing simplified chinese in pinyin will insert and remove spaces without + // calling shouldChangeTextInRange). This will cause JS to get out of sync so we + // update the mismatched range. + NSRange currentRange; + NSRange predictionRange; + if (findMismatch(text, _predictedText, ¤tRange, &predictionRange)) { + NSString *replacement = [text substringWithRange:currentRange]; + [self textInputShouldChangeTextInRange:predictionRange replacementText:replacement]; + // JS will assume the selection changed based on the location of our shouldChangeTextInRange, so reset it. + [self textInputDidChangeSelection]; + _predictedText = text; + } + + _nativeEventCount++; + + if (_onChange) { + _onChange(@{ + @"text": text, + @"target": self.reactTag, + @"eventCount": @(_nativeEventCount), + }); + } } -- (CGSize)sizeThatFits:(CGSize)size +- (void)textInputDidChangeSelection { - CGFloat compoundHorizontalBorderInset = _reactBorderInsets.left + _reactBorderInsets.right; - CGFloat compoundVerticalBorderInset = _reactBorderInsets.top + _reactBorderInsets.bottom; + if (!_onSelectionChange) { + return; + } - size.width -= compoundHorizontalBorderInset; - size.height -= compoundVerticalBorderInset; + RCTTextSelection *selection = self.selection; - // Note: `paddingInsets` was already included in `backedTextInputView` size - // because it was applied as `textContainerInset`. - CGSize fittingSize = [self.backedTextInputView sizeThatFits:size]; + _onSelectionChange(@{ + @"selection": @{ + @"start": @(selection.start), + @"end": @(selection.end), + }, + }); +} - fittingSize.width += compoundHorizontalBorderInset; - fittingSize.height += compoundVerticalBorderInset; +- (void)updateLocalData +{ +// [self enforceTextAttributesIfNeeded]; - // Returning value DOES include border and padding insets. - return fittingSize; + [_bridge.uiManager setLocalData:[self.backedTextInputView.attributedText copy] + forView:self]; } -- (void)layoutSubviews +#pragma mark - Layout (in UIKit terms, with all insets) + +- (CGSize)intrinsicContentSize { - [super layoutSubviews]; - [self invalidateContentSize]; + CGSize size = self.backedTextInputView.intrinsicContentSize; + size.width += _reactBorderInsets.left + _reactBorderInsets.right; + size.height += _reactBorderInsets.top + _reactBorderInsets.bottom; + // Returning value DOES include border and padding insets. + return size; } +//- (CGSize)sizeThatFits:(CGSize)size +//{ +// CGFloat compoundHorizontalBorderInset = _reactBorderInsets.left + _reactBorderInsets.right; +// CGFloat compoundVerticalBorderInset = _reactBorderInsets.top + _reactBorderInsets.bottom; +// +// size.width -= compoundHorizontalBorderInset; +// size.height -= compoundVerticalBorderInset; +// +// // Note: `paddingInsets` was already included in `backedTextInputView` size +// // because it was applied as `textContainerInset`. +// CGSize fittingSize = [self.backedTextInputView sizeThatFits:size]; +// +// fittingSize.width += compoundHorizontalBorderInset; +// fittingSize.height += compoundVerticalBorderInset; +// +// // Returning value DOES include border and padding insets. +// return fittingSize; +//} + #pragma mark - Accessibility -- (UIView *)reactAccessibilityElement +- (NSView *)reactAccessibilityElement { return self.backedTextInputView; } @@ -283,64 +399,171 @@ - (void)didMoveToWindow #pragma mark - Custom Input Accessory View -- (void)didSetProps:(NSArray *)changedProps +//- (void)didSetProps:(NSArray *)changedProps +//{ +// [self invalidateInputAccessoryView]; +//} +// +//- (void)invalidateInputAccessoryView +//{ +//#if !TARGET_OS_TV +// NSView *textInputView = self.backedTextInputView; +// UIKeyboardType keyboardType = textInputView.keyboardType; +// +// // These keyboard types (all are number pads) don't have a "Done" button by default, +// // so we create an `inputAccessoryView` with this button for them. +// BOOL shouldHaveInputAccesoryView = +// ( +// keyboardType == UIKeyboardTypeNumberPad || +// keyboardType == UIKeyboardTypePhonePad || +// keyboardType == UIKeyboardTypeDecimalPad || +// keyboardType == UIKeyboardTypeASCIICapableNumberPad +// ) && +// textInputView.returnKeyType == UIReturnKeyDone; +// +// if (_hasInputAccesoryView == shouldHaveInputAccesoryView) { +// return; +// } +// +// _hasInputAccesoryView = shouldHaveInputAccesoryView; +// +// if (shouldHaveInputAccesoryView) { +// UIToolbar *toolbarView = [[UIToolbar alloc] init]; +// [toolbarView sizeToFit]; +// UIBarButtonItem *flexibleSpace = +// [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace +// target:nil +// action:nil]; +// UIBarButtonItem *doneButton = +// [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone +// target:self +// action:@selector(handleInputAccessoryDoneButton)]; +// toolbarView.items = @[flexibleSpace, doneButton]; +// textInputView.inputAccessoryView = toolbarView; +// } +// else { +// textInputView.inputAccessoryView = nil; +// } +// +// // We have to call `reloadInputViews` for focused text inputs to update an accessory view. +// if (textInputView.isFirstResponder) { +// [textInputView reloadInputViews]; +// } +//#endif +//} +// +//- (void)handleInputAccessoryDoneButton +//{ +// if ([self textInputShouldReturn]) { +// [self.backedTextInputView endEditing:YES]; +// } +//} + +#pragma mark - Helpers + +static BOOL findMismatch(NSString *first, NSString *second, NSRange *firstRange, NSRange *secondRange) { - [self invalidateInputAccessoryView]; + NSInteger firstMismatch = -1; + for (NSUInteger ii = 0; ii < MAX(first.length, second.length); ii++) { + if (ii >= first.length || ii >= second.length || [first characterAtIndex:ii] != [second characterAtIndex:ii]) { + firstMismatch = ii; + break; + } + } + + if (firstMismatch == -1) { + return NO; + } + + NSUInteger ii = second.length; + NSUInteger lastMismatch = first.length; + while (ii > firstMismatch && lastMismatch > firstMismatch) { + if ([first characterAtIndex:(lastMismatch - 1)] != [second characterAtIndex:(ii - 1)]) { + break; + } + ii--; + lastMismatch--; + } + + *firstRange = NSMakeRange(firstMismatch, lastMismatch - firstMismatch); + *secondRange = NSMakeRange(firstMismatch, ii - firstMismatch); + return YES; } -- (void)invalidateInputAccessoryView +#pragma mark - Placeholder + +- (NSLabel *)placeholderView { -#if !TARGET_OS_TV - UIView *textInputView = self.backedTextInputView; - UIKeyboardType keyboardType = textInputView.keyboardType; + if (_placeholderView == nil) { + _placeholderView = [[NSLabel alloc] initWithFrame:NSZeroRect]; + [self updatePlaceholderStyle]; + [self addSubview:_placeholderView positioned:NSWindowBelow relativeTo:self.backedTextInputView]; + } + return _placeholderView; +} - // These keyboard types (all are number pads) don't have a "Done" button by default, - // so we create an `inputAccessoryView` with this button for them. - BOOL shouldHaveInputAccesoryView = - ( - keyboardType == UIKeyboardTypeNumberPad || - keyboardType == UIKeyboardTypePhonePad || - keyboardType == UIKeyboardTypeDecimalPad || - keyboardType == UIKeyboardTypeASCIICapableNumberPad - ) && - textInputView.returnKeyType == UIReturnKeyDone; +- (NSString *)placeholder +{ + return _placeholderView.text; +} - if (_hasInputAccesoryView == shouldHaveInputAccesoryView) { - return; +- (void)setPlaceholder:(NSString *)placeholder +{ + if (placeholder) { + // Use "self" to ensure "placeholderView" exists. + self.placeholderView.text = placeholder; + [self updatePlaceholderFrame]; + } else if (_placeholderView) { + [_placeholderView removeFromSuperview]; + _placeholderView = nil; } +} - _hasInputAccesoryView = shouldHaveInputAccesoryView; - - if (shouldHaveInputAccesoryView) { - UIToolbar *toolbarView = [[UIToolbar alloc] init]; - [toolbarView sizeToFit]; - UIBarButtonItem *flexibleSpace = - [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace - target:nil - action:nil]; - UIBarButtonItem *doneButton = - [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone - target:self - action:@selector(handleInputAccessoryDoneButton)]; - toolbarView.items = @[flexibleSpace, doneButton]; - textInputView.inputAccessoryView = toolbarView; - } - else { - textInputView.inputAccessoryView = nil; +- (NSColor *)placeholderColor +{ + return _placeholderView.textColor; +} + +- (void)setPlaceholderColor:(NSColor *)color +{ + // Use "self" to ensure "placeholderView" exists. + self.placeholderView.textColor = color ?: _textAttributes.effectiveForegroundColor; +} + +- (void)updatePlaceholderStyle +{ + if (_placeholderView && _textAttributes) { + _placeholderView.font = _textAttributes.effectiveFont; + _placeholderView.textColor = _textAttributes.effectiveForegroundColor; + _placeholderView.alignment = _textAttributes.alignment; } +} - // We have to call `reloadInputViews` for focused text inputs to update an accessory view. - if (textInputView.isFirstResponder) { - [textInputView reloadInputViews]; +- (void)updatePlaceholderFrame +{ + if (_placeholderView) { + NSEdgeInsets insets = self.reactCompoundInsets; + CGFloat maxWidth = self.bounds.size.width - (insets.left + insets.right); + if (maxWidth != _placeholderView.preferredMaxLayoutWidth) { + _placeholderView.preferredMaxLayoutWidth = maxWidth; + } + NSRect bounds = (NSRect){NSZeroPoint, _placeholderView.intrinsicContentSize}; + _placeholderView.frame = NSOffsetRect(bounds, insets.left, insets.top - 1); } -#endif } -- (void)handleInputAccessoryDoneButton +- (void)updatePlaceholderVisibility { - if ([self textInputShouldReturn]) { - [self.backedTextInputView endEditing:YES]; + if (_placeholderView) { + BOOL hidden = _placeholderView.text.length == 0 || self.attributedText.length > 0; + _placeholderView.hidden = hidden; } } +- (void)setFrame:(NSRect)frame +{ + [super setFrame:frame]; + [self updatePlaceholderFrame]; +} + @end diff --git a/Libraries/Text/TextInput/RCTBaseTextInputViewManager.h b/Libraries/Text/TextInput/RCTBaseTextInputViewManager.h index 0d5b669c92..710536aaa4 100644 --- a/Libraries/Text/TextInput/RCTBaseTextInputViewManager.h +++ b/Libraries/Text/TextInput/RCTBaseTextInputViewManager.h @@ -7,8 +7,8 @@ * of patent rights can be found in the PATENTS file in the same directory. */ -#import +#import "RCTBaseTextViewManager.h" -@interface RCTBaseTextInputViewManager : RCTViewManager +@interface RCTBaseTextInputViewManager : RCTBaseTextViewManager @end diff --git a/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m b/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m index f4fe8305d9..0941371224 100644 --- a/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m +++ b/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m @@ -9,59 +9,111 @@ #import "RCTBaseTextInputViewManager.h" +//#import #import #import #import #import #import +#import +#import -#import "RCTConvert+Text.h" +#import "RCTBaseTextInputShadowView.h" #import "RCTBaseTextInputView.h" +#import "RCTConvert+Text.h" + +@interface RCTBaseTextInputViewManager () + +@end @implementation RCTBaseTextInputViewManager +{ + NSHashTable *_shadowViews; +} RCT_EXPORT_MODULE() #pragma mark - Unified properties -RCT_REMAP_VIEW_PROPERTY(allowFontScaling, fontAttributes.allowFontScaling, BOOL) -RCT_REMAP_VIEW_PROPERTY(autoCapitalize, backedTextInputView.autocapitalizationType, UITextAutocapitalizationType) -RCT_REMAP_VIEW_PROPERTY(autoCorrect, backedTextInputView.autocorrectionType, UITextAutocorrectionType) -RCT_REMAP_VIEW_PROPERTY(color, backedTextInputView.textColor, UIColor) +//RCT_REMAP_VIEW_PROPERTY(autoCapitalize, backedTextInputView.autocapitalizationType, UITextAutocapitalizationType) +//RCT_REMAP_VIEW_PROPERTY(autoCorrect, backedTextInputView.autocorrectionType, UITextAutocorrectionType) RCT_REMAP_VIEW_PROPERTY(editable, backedTextInputView.editable, BOOL) -RCT_REMAP_VIEW_PROPERTY(enablesReturnKeyAutomatically, backedTextInputView.enablesReturnKeyAutomatically, BOOL) -RCT_REMAP_VIEW_PROPERTY(fontSize, fontAttributes.fontSize, NSNumber) -RCT_REMAP_VIEW_PROPERTY(fontWeight, fontAttributes.fontWeight, NSString) -RCT_REMAP_VIEW_PROPERTY(fontStyle, fontAttributes.fontStyle, NSString) -RCT_REMAP_VIEW_PROPERTY(fontFamily, fontAttributes.fontFamily, NSString) -RCT_REMAP_VIEW_PROPERTY(keyboardAppearance, backedTextInputView.keyboardAppearance, UIKeyboardAppearance) -RCT_REMAP_VIEW_PROPERTY(keyboardType, backedTextInputView.keyboardType, UIKeyboardType) -RCT_REMAP_VIEW_PROPERTY(placeholder, backedTextInputView.placeholder, NSString) -RCT_REMAP_VIEW_PROPERTY(placeholderTextColor, backedTextInputView.placeholderColor, UIColor) -RCT_REMAP_VIEW_PROPERTY(returnKeyType, backedTextInputView.returnKeyType, UIReturnKeyType) + + + +RCT_EXPORT_VIEW_PROPERTY(placeholder, NSString) +RCT_REMAP_VIEW_PROPERTY(placeholderTextColor, placeholderColor, NSColor) + RCT_REMAP_VIEW_PROPERTY(secureTextEntry, backedTextInputView.secureTextEntry, BOOL) -RCT_REMAP_VIEW_PROPERTY(selectionColor, backedTextInputView.tintColor, UIColor) -RCT_REMAP_VIEW_PROPERTY(spellCheck, backedTextInputView.spellCheckingType, UITextSpellCheckingType) -RCT_REMAP_VIEW_PROPERTY(textAlign, backedTextInputView.textAlignment, NSTextAlignment) +//RCT_REMAP_VIEW_PROPERTY(selectionColor, backedTextInputView.tintColor, NSColor) +//RCT_REMAP_VIEW_PROPERTY(spellCheck, backedTextInputView.spellCheckingType, UITextSpellCheckingType) +//RCT_REMAP_VIEW_PROPERTY(caretHidden, backedTextInputView.caretHidden, BOOL) + RCT_EXPORT_VIEW_PROPERTY(blurOnSubmit, BOOL) RCT_EXPORT_VIEW_PROPERTY(clearTextOnFocus, BOOL) RCT_EXPORT_VIEW_PROPERTY(maxLength, NSNumber) RCT_EXPORT_VIEW_PROPERTY(selectTextOnFocus, BOOL) RCT_EXPORT_VIEW_PROPERTY(selection, RCTTextSelection) -RCT_EXPORT_VIEW_PROPERTY(text, NSString) + +RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock) +RCT_EXPORT_VIEW_PROPERTY(onSelectionChange, RCTDirectEventBlock) +RCT_EXPORT_VIEW_PROPERTY(onTextInput, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(mostRecentEventCount, NSInteger) -- (RCTViewManagerUIBlock)uiBlockToAmendWithShadowView:(RCTShadowView *)shadowView +RCT_EXPORT_SHADOW_PROPERTY(text, NSString) +RCT_EXPORT_SHADOW_PROPERTY(placeholder, NSString) +RCT_EXPORT_SHADOW_PROPERTY(onContentSizeChange, RCTBubblingEventBlock) + + +- (RCTShadowView *)shadowView { - NSNumber *reactTag = shadowView.reactTag; - NSEdgeInsets borderAsInsets = shadowView.borderAsInsets; - NSEdgeInsets paddingAsInsets = shadowView.paddingAsInsets; - return ^(RCTUIManager *uiManager, NSDictionary *viewRegistry) { - RCTBaseTextInputView *view = viewRegistry[reactTag]; - view.reactBorderInsets = borderAsInsets; - view.reactPaddingInsets = paddingAsInsets; - }; + RCTBaseTextInputShadowView *shadowView = [[RCTBaseTextInputShadowView alloc] initWithBridge:self.bridge]; +// shadowView.textAttributes.fontSizeMultiplier = self.bridge.accessibilityManager.multiplier; + [_shadowViews addObject:shadowView]; + return shadowView; } +- (void)setBridge:(RCTBridge *)bridge +{ + [super setBridge:bridge]; + + _shadowViews = [NSHashTable weakObjectsHashTable]; + + [bridge.uiManager.observerCoordinator addObserver:self]; + +// [[NSNotificationCenter defaultCenter] addObserver:self +// selector:@selector(handleDidUpdateMultiplierNotification) +// name:RCTAccessibilityManagerDidUpdateMultiplierNotification +// object:bridge.accessibilityManager]; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +#pragma mark - RCTUIManagerObserver + +- (void)uiManagerWillPerformMounting:(__unused RCTUIManager *)uiManager +{ + for (RCTBaseTextInputShadowView *shadowView in _shadowViews) { + [shadowView uiManagerWillPerformMounting]; + } +} + +#pragma mark - Font Size Multiplier + +//- (void)handleDidUpdateMultiplierNotification +//{ +// CGFloat fontSizeMultiplier = self.bridge.accessibilityManager.multiplier; +// +// for (RCTBaseTextInputShadowView *shadowView in _shadowViews) { +// shadowView.textAttributes.fontSizeMultiplier = fontSizeMultiplier; +// [shadowView dirtyLayout]; +// } +// +// [self.bridge.uiManager setNeedsLayout]; +//} + @end diff --git a/Libraries/Text/TextInput/Singleline/RCTFieldEditor.h b/Libraries/Text/TextInput/Singleline/RCTFieldEditor.h new file mode 100644 index 0000000000..80bc2bd0e5 --- /dev/null +++ b/Libraries/Text/TextInput/Singleline/RCTFieldEditor.h @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@class RCTFieldEditor; + +@protocol RCTFieldEditorDelegate +@optional +- (void)fieldEditor:(RCTFieldEditor *)editor didPaste:(NSString *)text; +- (void)fieldEditorDidReturn:(RCTFieldEditor *)editor; +@end + +@interface RCTFieldEditor : NSTextView +@property (nullable, weak) id delegate; +@end + +NS_ASSUME_NONNULL_END diff --git a/Libraries/Text/TextInput/Singleline/RCTFieldEditor.m b/Libraries/Text/TextInput/Singleline/RCTFieldEditor.m new file mode 100644 index 0000000000..a474013af9 --- /dev/null +++ b/Libraries/Text/TextInput/Singleline/RCTFieldEditor.m @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "RCTFieldEditor.h" + +@implementation RCTFieldEditor + +@dynamic delegate; + +- (instancetype)init +{ + if (self = [super init]) { + self.fieldEditor = YES; + } + return self; +} + +- (void)paste:(id)sender +{ + NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; + NSString *text = [pasteboard stringForType:NSPasteboardTypeString]; + + if (text && [self.delegate respondsToSelector:@selector(fieldEditor:didPaste:)]) { + [self.delegate fieldEditor:self didPaste:text]; + } + + [super paste:sender]; +} + +- (void)keyDown:(NSEvent *)event +{ + [super keyDown:event]; + + if (event.keyCode == 36 && [self.delegate respondsToSelector:@selector(fieldEditorDidReturn:)]) { + [self.delegate fieldEditorDidReturn:self]; + } +} + +@end diff --git a/Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputView.h b/Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputView.h index 7e3e89072c..5338e0c630 100644 --- a/Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputView.h +++ b/Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputView.h @@ -7,18 +7,12 @@ * of patent rights can be found in the PATENTS file in the same directory. */ -#import - -#import -#import - #import "RCTBaseTextInputView.h" -@class RCTUITextField; +NS_ASSUME_NONNULL_BEGIN @interface RCTSinglelineTextInputView : RCTBaseTextInputView -@property (nonatomic, assign) BOOL caretHidden; -@property (nonatomic, strong) NSNumber *maxLength; - @end + +NS_ASSUME_NONNULL_END diff --git a/Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputView.m b/Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputView.m index 1300b441f3..7324c09747 100644 --- a/Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputView.m +++ b/Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputView.m @@ -10,133 +10,52 @@ #import "RCTSinglelineTextInputView.h" #import -#import -#import -#import -#import -#import -#import -#import "RCTBackedTextInputDelegate.h" -#import "RCTTextSelection.h" #import "RCTUITextField.h" -@interface RCTSinglelineTextInputView () - -@end - @implementation RCTSinglelineTextInputView { - RCTUITextField *_backedTextInput; - BOOL _submitted; - CGSize _previousContentSize; + RCTUITextField *_backedTextInputView; } - (instancetype)initWithBridge:(RCTBridge *)bridge { if (self = [super initWithBridge:bridge]) { // `blurOnSubmit` defaults to `true` for by design. - _blurOnSubmit = YES; + self.blurOnSubmit = YES; - _backedTextInput = [[RCTUITextField alloc] initWithFrame:self.bounds]; - _backedTextInput.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; - _backedTextInput.textInputDelegate = self; - _backedTextInput.font = self.fontAttributes.font; + _backedTextInputView = [[RCTUITextField alloc] initWithFrame:self.bounds]; + _backedTextInputView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; + _backedTextInputView.textInputDelegate = self; - [self addSubview:_backedTextInput]; + [self addSubview:_backedTextInputView]; } return self; } RCT_NOT_IMPLEMENTED(- (instancetype)initWithFrame:(CGRect)frame) -RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder) +RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)coder) - (id)backedTextInputView { - return _backedTextInput; -} - -- (void)sendKeyValueForString:(NSString *)string -{ - [_eventDispatcher sendTextEventWithType:RCTTextEventTypeKeyPress - reactTag:self.reactTag - text:nil - key:string - eventCount:_nativeEventCount]; + return _backedTextInputView; } -#pragma mark - Properties - -- (NSString *)text -{ - return _backedTextInput.text; -} - -- (void)setText:(NSString *)text -{ - NSInteger eventLag = _nativeEventCount - _mostRecentEventCount; - if (eventLag == 0 && ![text isEqualToString:self.text]) { - UITextRange *selection = _backedTextInput.selectedTextRange; - NSInteger oldTextLength = _backedTextInput.text.length; - - _backedTextInput.text = text; - - if (selection.empty) { - // maintain cursor position relative to the end of the old text - NSInteger offsetStart = [_backedTextInput offsetFromPosition:_backedTextInput.beginningOfDocument toPosition:selection.start]; - NSInteger offsetFromEnd = oldTextLength - offsetStart; - NSInteger newOffset = text.length - offsetFromEnd; - UITextPosition *position = [_backedTextInput positionFromPosition:_backedTextInput.beginningOfDocument offset:newOffset]; - [_backedTextInput setSelectedTextRange:[_backedTextInput textRangeFromPosition:position toPosition:position] - notifyDelegate:YES]; - } - } else if (eventLag > RCTTextUpdateLagWarningThreshold) { - RCTLogWarn(@"Native TextInput(%@) is %lld events ahead of JS - try to make your JS faster.", _backedTextInput.text, (long long)eventLag); - } +static inline CGRect NSEdgeInsetsInsetRect(CGRect rect, NSEdgeInsets insets) { + rect.origin.x += insets.left; + rect.origin.y += insets.top; + rect.size.width -= (insets.left + insets.right); + rect.size.height -= (insets.top + insets.bottom); + return rect; } -#pragma mark - RCTBackedTextInputDelegate - -- (BOOL)textInputShouldChangeTextInRange:(NSRange)range replacementText:(NSString *)string +- (void)setReactBorderInsets:(NSEdgeInsets)reactBorderInsets { - // Only allow single keypresses for `onKeyPress`, pasted text will not be sent. - if (!_backedTextInput.textWasPasted) { - [self sendKeyValueForString:string]; - } - - if (_maxLength != nil && ![string isEqualToString:@"\n"]) { // Make sure forms can be submitted via return. - NSUInteger allowedLength = _maxLength.integerValue - MIN(_maxLength.integerValue, _backedTextInput.text.length) + range.length; - if (string.length > allowedLength) { - if (string.length > 1) { - // Truncate the input string so the result is exactly `maxLength`. - NSString *limitedString = [string substringToIndex:allowedLength]; - NSMutableString *newString = _backedTextInput.text.mutableCopy; - [newString replaceCharactersInRange:range withString:limitedString]; - _backedTextInput.text = newString; + // We apply `borderInsets` as `backedTextInputView` layout offset. + self.backedTextInputView.frame = NSEdgeInsetsInsetRect(self.bounds, reactBorderInsets); - // Collapse selection at end of insert to match normal paste behavior. - UITextPosition *insertEnd = [_backedTextInput positionFromPosition:_backedTextInput.beginningOfDocument - offset:(range.location + allowedLength)]; - [_backedTextInput setSelectedTextRange:[_backedTextInput textRangeFromPosition:insertEnd toPosition:insertEnd] - notifyDelegate:YES]; - [self textInputDidChange]; - } - return NO; - } - } - - return YES; -} - -- (void)textInputDidChange -{ - _nativeEventCount++; - [_eventDispatcher sendTextEventWithType:RCTTextEventTypeChange - reactTag:self.reactTag - text:_backedTextInput.text - key:nil - eventCount:_nativeEventCount]; + [super setReactBorderInsets:reactBorderInsets]; } @end diff --git a/Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputViewManager.h b/Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputViewManager.h index 90f5fbda24..57439e6bf3 100644 --- a/Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputViewManager.h +++ b/Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputViewManager.h @@ -9,6 +9,10 @@ #import "RCTBaseTextInputViewManager.h" +NS_ASSUME_NONNULL_BEGIN + @interface RCTSinglelineTextInputViewManager : RCTBaseTextInputViewManager @end + +NS_ASSUME_NONNULL_END diff --git a/Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputViewManager.m b/Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputViewManager.m index 36d424c965..3b854c8e26 100644 --- a/Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputViewManager.m +++ b/Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputViewManager.m @@ -9,15 +9,8 @@ #import "RCTSinglelineTextInputViewManager.h" -#import -#import -#import -#import - -#import "RCTConvert+Text.h" -#import "RCTSinglelineTextInputShadowView.h" +#import "RCTBaseTextInputShadowView.h" #import "RCTSinglelineTextInputView.h" -#import "RCTUITextField.h" @implementation RCTSinglelineTextInputViewManager @@ -25,7 +18,12 @@ @implementation RCTSinglelineTextInputViewManager - (RCTShadowView *)shadowView { - return [RCTSinglelineTextInputShadowView new]; + RCTBaseTextInputShadowView *shadowView = + (RCTBaseTextInputShadowView *)[super shadowView]; + + shadowView.maximumNumberOfLines = 1; + + return shadowView; } - (NSView *)view @@ -33,10 +31,4 @@ - (NSView *)view return [[RCTSinglelineTextInputView alloc] initWithBridge:self.bridge]; } -#pragma mark - Singleline (aka TextField) specific properties - -RCT_REMAP_VIEW_PROPERTY(caretHidden, backedTextInputView.caretHidden, BOOL) -RCT_REMAP_VIEW_PROPERTY(clearButtonMode, backedTextInputView.clearButtonMode, UITextFieldViewMode) -RCT_EXPORT_VIEW_PROPERTY(onSelectionChange, RCTDirectEventBlock) - @end diff --git a/Libraries/Text/TextInput/Singleline/RCTUITextField.h b/Libraries/Text/TextInput/Singleline/RCTUITextField.h index 686bb6c543..2da138c3f4 100644 --- a/Libraries/Text/TextInput/Singleline/RCTUITextField.h +++ b/Libraries/Text/TextInput/Singleline/RCTUITextField.h @@ -14,7 +14,7 @@ NS_ASSUME_NONNULL_BEGIN /* - * Just regular UITextField... but much better! + * Just regular NSTextField... but much better! */ @interface RCTUITextField : NSTextField @@ -24,9 +24,8 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, assign) BOOL caretHidden; @property (nonatomic, assign, readonly) BOOL textWasPasted; -@property (nonatomic, copy, nullable) NSString *placeholder; -@property (nonatomic, strong, nullable) NSColor *placeholderColor; -@property (nonatomic, assign) NSEdgeInsets textContainerInset; +// @property (nonatomic, strong, nullable) NSColor *placeholderColor; +@property (nonatomic, assign) NSEdgeInsets paddingInsets; @end diff --git a/Libraries/Text/TextInput/Singleline/RCTUITextField.m b/Libraries/Text/TextInput/Singleline/RCTUITextField.m index 7247b73491..dc0727ec3f 100644 --- a/Libraries/Text/TextInput/Singleline/RCTUITextField.m +++ b/Libraries/Text/TextInput/Singleline/RCTUITextField.m @@ -11,16 +11,48 @@ #import #import +#import #import "RCTBackedTextInputDelegateAdapter.h" +#import "RCTFieldEditor.h" +#import "NSText+Editing.h" + +// The "field editor" is a NSTextView whose delegate is this NSTextField. +@interface NSTextField () +@end + +@interface RCTUITextFieldCell : NSTextFieldCell +@property (nullable, assign) RCTUITextField *controlView; +@end + +@interface RCTUITextField (RCTFieldEditor) +- (RCTFieldEditor *)currentEditor; +@end @implementation RCTUITextField { RCTBackedTextFieldDelegateAdapter *_textInputDelegateAdapter; } +@dynamic font, alignment; // NSTextField provides these properties + - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(_textDidChange) + name:NSControlTextDidChangeNotification + object:self]; + + self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; + self.allowsEditingTextAttributes = NO; + self.drawsBackground = NO; + self.focusRingType = NSFocusRingTypeNone; + self.bordered = NO; + self.bezeled = NO; + + self.cell.scrollable = YES; + self.cell.usesSingleLineMode = YES; + object_setClass(self.cell, RCTUITextFieldCell.class); _textInputDelegateAdapter = [[RCTBackedTextFieldDelegateAdapter alloc] initWithTextField:self]; } @@ -38,136 +70,138 @@ - (void)_textDidChange _textWasPasted = NO; } -#pragma mark - Properties +#pragma mark - Overrides -- (void)setTextContainerInset:(NSEdgeInsets)textContainerInset +- (NSRange)selectedTextRange { - _textContainerInset = textContainerInset; - [self setNeedsLayout:YES]; + return self.currentEditor.selectedRange; } -- (void)setPlaceholder:(NSString *)placeholder +- (void)setSelectedTextRange:(NSRange)selectedTextRange notifyDelegate:(BOOL)notifyDelegate { - if (placeholder != nil && ![_placeholder isEqual:placeholder]) { - _placeholder = placeholder; - [self updatePlaceholder]; + if (!notifyDelegate) { + // We have to notify an adapter that following selection change was initiated programmatically, + // so the adapter must not generate a notification for it. + [_textInputDelegateAdapter skipNextTextInputDidChangeSelectionEventWithTextRange:selectedTextRange]; } + + self.currentEditor.selectedRange = selectedTextRange; + [_textInputDelegateAdapter selectedTextRangeWasSet]; } -- (void)setPlaceholderColor:(NSColor *)placeholderColor +- (void)textViewDidChangeSelection:(NSNotification *)notification { - _placeholderColor = placeholderColor; - [self _updatePlaceholder]; + [super textViewDidChangeSelection:notification]; + [_textInputDelegateAdapter selectedTextRangeWasSet]; } -- (void)_updatePlaceholder +- (BOOL)textView:(NSTextView *)textView shouldChangeTextInRange:(NSRange)range replacementString:(NSString *)string { - if (self.placeholder == nil) { - return; + if ([super textView:textView shouldChangeTextInRange:range replacementString:string]) { + return [_textInputDelegateAdapter shouldChangeTextInRange:range replacementText:string]; } + return NO; +} - NSMutableDictionary *attributes = [NSMutableDictionary new]; - if (_placeholderColor) { - [attributes setObject:_placeholderColor forKey:NSForegroundColorAttributeName]; +- (void)textDidEndEditing:(NSNotification *)notification +{ + [super textDidEndEditing:notification]; + if (self.currentEditor == nil) { + [_textInputDelegateAdapter textFieldDidBlur]; } - - - - self.placeholderAttributedString = [[NSAttributedString alloc] initWithString:self.placeholder - attributes:attributes]; } -- (BOOL)isEditable +- (BOOL)becomeFirstResponder { - return self.isEnabled; + if ([super becomeFirstResponder]) { + // Move the cursor to the end of the current text. Note: Mouse clicks override this selection (which is intended). + self.currentEditor.selectedRange = NSMakeRange(self.stringValue.length, 0); + + self.currentEditor.textContainerInset = (NSSize){_paddingInsets.left, _paddingInsets.top}; + [_textInputDelegateAdapter performSelector:@selector(textFieldDidFocus) withObject:nil afterDelay:0.0]; + return YES; + } + return NO; } -- (void)setEditable:(BOOL)editable +#pragma mark - RCTBackedTextInputViewProtocol + +- (NSAttributedString *)attributedText { - self.enabled = editable; + return self.attributedStringValue; } -#pragma mark - Caret Manipulation - -//- (CGRect)caretRectForPosition:(UITextPosition *)position -//{ -// if (_caretHidden) { -// return CGRectZero; -// } -// -// return [super caretRectForPosition:position]; -//} +- (void)setAttributedText:(NSAttributedString *)attributedText +{ + self.attributedStringValue = attributedText; +} -#pragma mark - Positioning Overrides +- (void)setPaddingInsets:(NSEdgeInsets)paddingInsets +{ + // Account for strange rendering offset. (NSTextView doesn't have this issue) + paddingInsets.top -= 1; + paddingInsets.left -= 2; -static inline CGRect NSEdgeInsetsInsetRect(CGRect rect, NSEdgeInsets insets) { - rect.origin.x += insets.left; - rect.origin.y += insets.top; - rect.size.width -= (insets.left + insets.right); - rect.size.height -= (insets.top + insets.bottom); - return rect; + _paddingInsets = paddingInsets; } -//- (CGRect)textRectForBounds:(CGRect)bounds -//{ -// return NSEdgeInsetsInsetRect([super textRectForBounds:bounds], _textContainerInset); -//} - -//- (CGRect)editingRectForBounds:(CGRect)bounds -//{ -// return [self textRectForBounds:bounds]; -//} +- (void)selectAll:(nullable id)sender +{ + [self.currentEditor selectAll:sender]; +} -#pragma mark - Overrides +#pragma mark - RCTFieldEditorDelegate -- (void)setSelectedTextRange:(NSRange)selectedTextRange +- (void)fieldEditor:(RCTFieldEditor *)editor didPaste:(NSString *)text { - [[super currentEditor] setSelectedRange:selectedTextRange]; - [_textInputDelegateAdapter selectedTextRangeWasSet]; + _textWasPasted = YES; } -- (void)setSelectedTextRange:(NSRange)selectedTextRange notifyDelegate:(BOOL)notifyDelegate +- (void)fieldEditorDidReturn:(RCTFieldEditor *)editor { - if (!notifyDelegate) { - // We have to notify an adapter that following selection change was initiated programmatically, - // so the adapter must not generate a notification for it. - [_textInputDelegateAdapter skipNextTextInputDidChangeSelectionEventWithTextRange:selectedTextRange]; + if ([self.textInputDelegate textInputShouldReturn]) { + [self.textInputDelegate textInputDidReturn]; + [self.currentEditor endEditing:NO]; } - - [[super currentEditor] setSelectedRange:selectedTextRange]; } -- (void)paste:(id)sender +@end + +@implementation RCTUITextFieldCell { - [[super currentEditor] paste:sender]; - _textWasPasted = YES; + RCTFieldEditor *_fieldEditor; } -#pragma mark - Layout +@dynamic controlView; + +static inline CGRect NSEdgeInsetsInsetRect(CGRect rect, NSEdgeInsets insets) { + rect.origin.x += insets.left; + rect.origin.y += insets.top; + rect.size.width -= (insets.left + insets.right); + rect.size.height -= (insets.top + insets.bottom); + return rect; +} -- (CGSize)contentSize +- (NSRect)drawingRectForBounds:(NSRect)bounds { - // Returning size DOES contain `textContainerInset` (aka `padding`). - return self.intrinsicContentSize; + NSRect rect = [super drawingRectForBounds:bounds]; + return NSEdgeInsetsInsetRect(rect, self.controlView.paddingInsets); } -- (CGSize)intrinsicContentSize +- (NSTextView *)fieldEditorForView:(NSView *)controlView { - // Note: `placeholder` defines intrinsic size for ``. - NSString *text = self.placeholder ?: @""; - CGSize size = [text sizeWithAttributes:@{NSFontAttributeName: self.font}]; - size = CGSizeMake(RCTCeilPixelValue(size.width), RCTCeilPixelValue(size.height)); - size.width += _textContainerInset.left + _textContainerInset.right; - size.height += _textContainerInset.top + _textContainerInset.bottom; - // Returning size DOES contain `textContainerInset` (aka `padding`). - return size; + if (_fieldEditor == nil) { + _fieldEditor = [RCTFieldEditor new]; + } + return _fieldEditor; } -- (CGSize)sizeThatFits:(CGSize)size +- (NSText *)setUpFieldEditorAttributes:(NSTextView *)fieldEditor { - // All size values here contain `textContainerInset` (aka `padding`). - CGSize intrinsicSize = self.intrinsicContentSize; - return CGSizeMake(MIN(size.width, intrinsicSize.width), MIN(size.height, intrinsicSize.height)); + fieldEditor.font = self.font; + fieldEditor.textColor = self.textColor; + fieldEditor.backgroundColor = NSColor.clearColor; + return fieldEditor; } @end diff --git a/Libraries/Text/VirtualText/RCTVirtualTextShadowView.h b/Libraries/Text/VirtualText/RCTVirtualTextShadowView.h new file mode 100644 index 0000000000..ae5d158b0e --- /dev/null +++ b/Libraries/Text/VirtualText/RCTVirtualTextShadowView.h @@ -0,0 +1,14 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "RCTBaseTextShadowView.h" + +@interface RCTVirtualTextShadowView : RCTBaseTextShadowView + +@end diff --git a/Libraries/Text/VirtualText/RCTVirtualTextShadowView.m b/Libraries/Text/VirtualText/RCTVirtualTextShadowView.m new file mode 100644 index 0000000000..b5710f13c0 --- /dev/null +++ b/Libraries/Text/VirtualText/RCTVirtualTextShadowView.m @@ -0,0 +1,75 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "RCTVirtualTextShadowView.h" + +#import +#import + +#import "RCTRawTextShadowView.h" + +@implementation RCTVirtualTextShadowView { + BOOL _isLayoutDirty; +} + +#pragma mark - Life Cycle + +- (void)insertReactSubview:(RCTShadowView *)subview atIndex:(NSInteger)index +{ + [super insertReactSubview:subview atIndex:index]; + + [self dirtyLayout]; + + if (![subview isKindOfClass:[RCTVirtualTextShadowView class]]) { + YGNodeSetDirtiedFunc(subview.yogaNode, RCTVirtualTextShadowViewYogaNodeDirtied); + } + +} + +- (void)removeReactSubview:(RCTShadowView *)subview +{ + if (![subview isKindOfClass:[RCTVirtualTextShadowView class]]) { + YGNodeSetDirtiedFunc(subview.yogaNode, NULL); + } + + [self dirtyLayout]; + + [super removeReactSubview:subview]; +} + +#pragma mark - Layout + +- (void)dirtyLayout +{ + [super dirtyLayout]; + + if (_isLayoutDirty) { + return; + } + _isLayoutDirty = YES; + + [self.superview dirtyLayout]; +} + +- (void)clearLayout +{ + _isLayoutDirty = NO; +} + +static void RCTVirtualTextShadowViewYogaNodeDirtied(YGNodeRef node) +{ + RCTShadowView *shadowView = (__bridge RCTShadowView *)YGNodeGetContext(node); + + RCTVirtualTextShadowView *virtualTextShadowView = + (RCTVirtualTextShadowView *)shadowView.reactSuperview; + + [virtualTextShadowView dirtyLayout]; +} + +@end diff --git a/Libraries/Text/VirtualText/RCTVirtualTextViewManager.h b/Libraries/Text/VirtualText/RCTVirtualTextViewManager.h new file mode 100644 index 0000000000..b7225dbb51 --- /dev/null +++ b/Libraries/Text/VirtualText/RCTVirtualTextViewManager.h @@ -0,0 +1,14 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "RCTBaseTextViewManager.h" + +@interface RCTVirtualTextViewManager : RCTBaseTextViewManager + +@end diff --git a/Libraries/Text/VirtualText/RCTVirtualTextViewManager.m b/Libraries/Text/VirtualText/RCTVirtualTextViewManager.m new file mode 100644 index 0000000000..b88a5fc9ab --- /dev/null +++ b/Libraries/Text/VirtualText/RCTVirtualTextViewManager.m @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "RCTVirtualTextViewManager.h" + +#import "RCTVirtualTextShadowView.h" + +@implementation RCTVirtualTextViewManager + +RCT_EXPORT_MODULE(RCTVirtualText) + +- (NSView *)view +{ + return [NSView new]; +} + +- (RCTShadowView *)shadowView +{ + return [RCTVirtualTextShadowView new]; +} + +@end diff --git a/Libraries/WebSocket/RCTWebSocket.xcodeproj/project.pbxproj b/Libraries/WebSocket/RCTWebSocket.xcodeproj/project.pbxproj index e6350493c8..688ae3650c 100644 --- a/Libraries/WebSocket/RCTWebSocket.xcodeproj/project.pbxproj +++ b/Libraries/WebSocket/RCTWebSocket.xcodeproj/project.pbxproj @@ -9,17 +9,10 @@ /* Begin PBXBuildFile section */ 1338BBE01B04ACC80064A9C9 /* RCTSRWebSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 1338BBDD1B04ACC80064A9C9 /* RCTSRWebSocket.m */; }; 1338BBE11B04ACC80064A9C9 /* RCTWebSocketExecutor.m in Sources */ = {isa = PBXBuildFile; fileRef = 1338BBDF1B04ACC80064A9C9 /* RCTWebSocketExecutor.m */; }; - 2D3B5F3D1D9B165B00451313 /* RCTSRWebSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 1338BBDD1B04ACC80064A9C9 /* RCTSRWebSocket.m */; }; - 2D3B5F3E1D9B165B00451313 /* RCTWebSocketExecutor.m in Sources */ = {isa = PBXBuildFile; fileRef = 1338BBDF1B04ACC80064A9C9 /* RCTWebSocketExecutor.m */; }; - 2D3B5F401D9B165B00451313 /* RCTWebSocketModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C86DF7B1ADF695F0047B81A /* RCTWebSocketModule.m */; }; - 2DC5E5281F3A6CFD000EE84B /* libfishhook-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DC5E5271F3A6CFD000EE84B /* libfishhook-tvOS.a */; }; 3C86DF7C1ADF695F0047B81A /* RCTWebSocketModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C86DF7B1ADF695F0047B81A /* RCTWebSocketModule.m */; }; 3DBE0D141F3B185A0099AA32 /* fishhook.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DBE0D121F3B185A0099AA32 /* fishhook.c */; }; - 3DBE0D151F3B185A0099AA32 /* fishhook.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DBE0D121F3B185A0099AA32 /* fishhook.c */; }; 3DBE0D801F3B1AF00099AA32 /* fishhook.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3DBE0D131F3B185A0099AA32 /* fishhook.h */; }; - 3DBE0D821F3B1B0C0099AA32 /* fishhook.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3DBE0D131F3B185A0099AA32 /* fishhook.h */; }; A12E9E2E1E5DEC4E0029001B /* RCTReconnectingWebSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = A12E9E2D1E5DEC4E0029001B /* RCTReconnectingWebSocket.m */; }; - A12E9E2F1E5DEC550029001B /* RCTReconnectingWebSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = A12E9E2D1E5DEC4E0029001B /* RCTReconnectingWebSocket.m */; }; D426ACCE20D56EFD003B4C4D /* libfishhook.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DBE0D001F3B181A0099AA32 /* libfishhook.a */; }; /* End PBXBuildFile section */ @@ -31,13 +24,6 @@ remoteGlobalIDString = 3DBE0CF41F3B181A0099AA32; remoteInfo = fishhook; }; - 3DBE0D101F3B184D0099AA32 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 3C86DF3E1ADF2C930047B81A /* Project object */; - proxyType = 1; - remoteGlobalIDString = 3DBE0D011F3B181C0099AA32; - remoteInfo = "fishhook-tvOS"; - }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -51,16 +37,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 3DBE0D811F3B1B010099AA32 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = include/fishhook; - dstSubfolderSpec = 16; - files = ( - 3DBE0D821F3B1B0C0099AA32 /* fishhook.h in CopyFiles */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ @@ -69,13 +45,11 @@ 1338BBDE1B04ACC80064A9C9 /* RCTWebSocketExecutor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWebSocketExecutor.h; sourceTree = ""; }; 1338BBDF1B04ACC80064A9C9 /* RCTWebSocketExecutor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTWebSocketExecutor.m; sourceTree = ""; }; 13526A511F362F7F0008EF00 /* libfishhook.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libfishhook.a; sourceTree = ""; }; - 2D2A28881D9B049200D4039D /* libRCTWebSocket-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libRCTWebSocket-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 2DC5E5271F3A6CFD000EE84B /* libfishhook-tvOS.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libfishhook-tvOS.a"; path = "../fishhook/build/Debug-appletvos/libfishhook-tvOS.a"; sourceTree = ""; }; 3C86DF461ADF2C930047B81A /* libRCTWebSocket.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTWebSocket.a; sourceTree = BUILT_PRODUCTS_DIR; }; 3C86DF7A1ADF695F0047B81A /* RCTWebSocketModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWebSocketModule.h; sourceTree = ""; }; 3C86DF7B1ADF695F0047B81A /* RCTWebSocketModule.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = RCTWebSocketModule.m; sourceTree = ""; tabWidth = 2; }; 3DBE0D001F3B181A0099AA32 /* libfishhook.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libfishhook.a; sourceTree = BUILT_PRODUCTS_DIR; }; - 3DBE0D0D1F3B181C0099AA32 /* libfishhook-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libfishhook-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 3DBE0D121F3B185A0099AA32 /* fishhook.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fishhook.c; path = ../fishhook/fishhook.c; sourceTree = ""; }; 3DBE0D131F3B185A0099AA32 /* fishhook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fishhook.h; path = ../fishhook/fishhook.h; sourceTree = ""; }; A12E9E2C1E5DEC4E0029001B /* RCTReconnectingWebSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTReconnectingWebSocket.h; sourceTree = ""; }; @@ -91,14 +65,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 2DC5E5151F3A6C39000EE84B /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 2DC5E5281F3A6CFD000EE84B /* libfishhook-tvOS.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -136,9 +102,7 @@ isa = PBXGroup; children = ( 3C86DF461ADF2C930047B81A /* libRCTWebSocket.a */, - 2D2A28881D9B049200D4039D /* libRCTWebSocket-tvOS.a */, 3DBE0D001F3B181A0099AA32 /* libfishhook.a */, - 3DBE0D0D1F3B181C0099AA32 /* libfishhook-tvOS.a */, ); name = Products; sourceTree = ""; @@ -146,23 +110,6 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 2D2A28871D9B049200D4039D /* RCTWebSocket-tvOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 2D2A28901D9B049200D4039D /* Build configuration list for PBXNativeTarget "RCTWebSocket-tvOS" */; - buildPhases = ( - 2D2A28841D9B049200D4039D /* Sources */, - 2DC5E5151F3A6C39000EE84B /* Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - 3DBE0D111F3B184D0099AA32 /* PBXTargetDependency */, - ); - name = "RCTWebSocket-tvOS"; - productName = "RCTWebSocket-tvOS"; - productReference = 2D2A28881D9B049200D4039D /* libRCTWebSocket-tvOS.a */; - productType = "com.apple.product-type.library.static"; - }; 3C86DF451ADF2C930047B81A /* RCTWebSocket */ = { isa = PBXNativeTarget; buildConfigurationList = 3C86DF5A1ADF2C930047B81A /* Build configuration list for PBXNativeTarget "RCTWebSocket" */; @@ -196,22 +143,6 @@ productReference = 3DBE0D001F3B181A0099AA32 /* libfishhook.a */; productType = "com.apple.product-type.library.static"; }; - 3DBE0D011F3B181C0099AA32 /* fishhook-tvOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 3DBE0D0A1F3B181C0099AA32 /* Build configuration list for PBXNativeTarget "fishhook-tvOS" */; - buildPhases = ( - 3DBE0D811F3B1B010099AA32 /* CopyFiles */, - 3DBE0D021F3B181C0099AA32 /* Sources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "fishhook-tvOS"; - productName = "RCTWebSocket-tvOS"; - productReference = 3DBE0D0D1F3B181C0099AA32 /* libfishhook-tvOS.a */; - productType = "com.apple.product-type.library.static"; - }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -221,10 +152,6 @@ LastUpgradeCheck = 0630; ORGANIZATIONNAME = Facebook; TargetAttributes = { - 2D2A28871D9B049200D4039D = { - CreatedOnToolsVersion = 8.0; - ProvisioningStyle = Automatic; - }; 3C86DF451ADF2C930047B81A = { CreatedOnToolsVersion = 6.3; }; @@ -243,25 +170,12 @@ projectRoot = ""; targets = ( 3C86DF451ADF2C930047B81A /* RCTWebSocket */, - 2D2A28871D9B049200D4039D /* RCTWebSocket-tvOS */, 3DBE0CF41F3B181A0099AA32 /* fishhook */, - 3DBE0D011F3B181C0099AA32 /* fishhook-tvOS */, ); }; /* End PBXProject section */ /* Begin PBXSourcesBuildPhase section */ - 2D2A28841D9B049200D4039D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 2D3B5F3E1D9B165B00451313 /* RCTWebSocketExecutor.m in Sources */, - 2D3B5F401D9B165B00451313 /* RCTWebSocketModule.m in Sources */, - A12E9E2F1E5DEC550029001B /* RCTReconnectingWebSocket.m in Sources */, - 2D3B5F3D1D9B165B00451313 /* RCTSRWebSocket.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 3C86DF421ADF2C930047B81A /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -281,14 +195,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 3DBE0D021F3B181C0099AA32 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 3DBE0D151F3B185A0099AA32 /* fishhook.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -297,46 +203,9 @@ target = 3DBE0CF41F3B181A0099AA32 /* fishhook */; targetProxy = 3DBE0D0E1F3B18490099AA32 /* PBXContainerItemProxy */; }; - 3DBE0D111F3B184D0099AA32 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 3DBE0D011F3B181C0099AA32 /* fishhook-tvOS */; - targetProxy = 3DBE0D101F3B184D0099AA32 /* PBXContainerItemProxy */; - }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ - 2D2A288E1D9B049200D4039D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_SUSPICIOUS_MOVES = YES; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_TESTABILITY = YES; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = appletvos; - TVOS_DEPLOYMENT_TARGET = 9.2; - WARNING_CFLAGS = ""; - }; - name = Debug; - }; - 2D2A288F1D9B049200D4039D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_SUSPICIOUS_MOVES = YES; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = appletvos; - TVOS_DEPLOYMENT_TARGET = 9.2; - WARNING_CFLAGS = ""; - }; - name = Release; - }; 3C86DF581ADF2C930047B81A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -483,48 +352,9 @@ }; name = Release; }; - 3DBE0D0B1F3B181C0099AA32 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_SUSPICIOUS_MOVES = YES; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_TESTABILITY = YES; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = appletvos; - TVOS_DEPLOYMENT_TARGET = 9.2; - }; - name = Debug; - }; - 3DBE0D0C1F3B181C0099AA32 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_SUSPICIOUS_MOVES = YES; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = appletvos; - TVOS_DEPLOYMENT_TARGET = 9.2; - }; - name = Release; - }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 2D2A28901D9B049200D4039D /* Build configuration list for PBXNativeTarget "RCTWebSocket-tvOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 2D2A288E1D9B049200D4039D /* Debug */, - 2D2A288F1D9B049200D4039D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 3C86DF411ADF2C930047B81A /* Build configuration list for PBXProject "RCTWebSocket" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -552,15 +382,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 3DBE0D0A1F3B181C0099AA32 /* Build configuration list for PBXNativeTarget "fishhook-tvOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 3DBE0D0B1F3B181C0099AA32 /* Debug */, - 3DBE0D0C1F3B181C0099AA32 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; /* End XCConfigurationList section */ }; rootObject = 3C86DF3E1ADF2C930047B81A /* Project object */; diff --git a/RNTester/RNTester.xcodeproj/xcshareddata/xcschemes/RNTester-tvOS.xcscheme b/RNTester/RNTester.xcodeproj/xcshareddata/xcschemes/RNTester-tvOS.xcscheme deleted file mode 100644 index df1600ff8a..0000000000 --- a/RNTester/RNTester.xcodeproj/xcshareddata/xcschemes/RNTester-tvOS.xcscheme +++ /dev/null @@ -1,134 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/RNTester/RNTester/AppDelegate.m b/RNTester/RNTester/AppDelegate.m index 2c5edb6987..6bbece42f6 100644 --- a/RNTester/RNTester/AppDelegate.m +++ b/RNTester/RNTester/AppDelegate.m @@ -21,6 +21,7 @@ #import #import #import +#import @interface AppDelegate() @@ -28,54 +29,33 @@ @interface AppDelegate() @implementation AppDelegate - --(id)init { - if(self = [super init]) { - - // -- Init Window - NSRect contentSize = NSMakeRect(200, 500, 1000, 500); - - self.window = [[NSWindow alloc] initWithContentRect:contentSize - styleMask:NSTitledWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask | NSClosableWindowMask - backing:NSBackingStoreBuffered - defer:NO]; - NSWindowController *windowController = [[NSWindowController alloc] initWithWindow:self.window]; - - [[self window] setTitle:@"RNTester"]; - [[self window] setTitleVisibility:NSWindowTitleHidden]; - [windowController showWindow:self.window]; - - [windowController setShouldCascadeWindows:NO]; - [windowController setWindowFrameAutosaveName:@"RNTester"]; - [self setDefaultURL]; - - // -- Init Toolbar - NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@"mainToolbar"]; - [toolbar setDelegate:self]; - [toolbar setSizeMode:NSToolbarSizeModeRegular]; - - [self.window setToolbar:toolbar]; - - // -- Init Menu - [self setUpMainMenu]; - } - return self; + NSToolbar *_toolbar; } - (void)applicationDidFinishLaunching:(NSNotification * __unused)aNotification { + [self setDefaultURL]; _bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:@{@"argv": [self argv]}]; - RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:_bridge - moduleName:@"RNTesterApp" - initialProperties:nil]; + _window = [[RCTWindow alloc] initWithBridge:_bridge + contentRect:NSMakeRect(200, 500, 1000, 500) + styleMask:(NSTitledWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask | NSClosableWindowMask) + defer:NO]; + + _window.title = @"RNTester"; + _window.titleVisibility = NSWindowTitleHidden; + [self setUpToolbar]; + [self setUpMainMenu]; + _window.contentView = [[RCTRootView alloc] initWithBridge:_bridge + moduleName:@"RNTesterApp" + initialProperties:nil]; - [self.window setContentView:rootView]; + [_window makeKeyAndOrderFront:nil]; } - (void)setDefaultURL @@ -105,6 +85,14 @@ - (void)loadSourceForBridge:(RCTBridge *)bridge onComplete:loadCallback]; } +- (void)setUpToolbar +{ + NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@"mainToolbar"]; + toolbar.delegate = self; + toolbar.sizeMode = NSToolbarSizeModeRegular; + _window.toolbar = toolbar; +} + - (NSArray *)toolbarAllowedItemIdentifiers:(__unused NSToolbar *)toolbar { return @[NSToolbarFlexibleSpaceItemIdentifier, @"searchBar", NSToolbarFlexibleSpaceItemIdentifier, @"resetButton"]; diff --git a/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testTabBarExample_1-iOS10@2x.png b/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testTabBarExample_1-iOS10@2x.png index 3f455893b7..66c1403e18 100644 Binary files a/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testTabBarExample_1-iOS10@2x.png and b/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testTabBarExample_1-iOS10@2x.png differ diff --git a/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testTabBarExample_1-iOS11@2x.png b/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testTabBarExample_1-iOS11@2x.png index ff34070cd5..238678f049 100644 Binary files a/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testTabBarExample_1-iOS11@2x.png and b/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testTabBarExample_1-iOS11@2x.png differ diff --git a/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testTabBarExample_1@2x.png b/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testTabBarExample_1@2x.png index 6a17f7a8c9..7c79f2bcf1 100644 Binary files a/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testTabBarExample_1@2x.png and b/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testTabBarExample_1@2x.png differ diff --git a/RNTester/js/DragnDropExample.macos.js b/RNTester/js/DragnDropExample.macos.js index 43eab54820..221960f6bc 100644 --- a/RNTester/js/DragnDropExample.macos.js +++ b/RNTester/js/DragnDropExample.macos.js @@ -41,8 +41,8 @@ class DragExample extends React.Component { this.state.mouseOver ? 'orange' : 'white', padding: 40, alignItems: 'center'}} draggedTypes={['NSFilenamesPboardType']} - onMouseEnter={() => this.setState({mouseOver: true})} - onMouseLeave={() => this.setState({mouseOver: false})} + onMouseOver={() => this.setState({mouseOver: true})} + onMouseOut={() => this.setState({mouseOver: false})} onDragEnter={() => this.setState({dragOver: true})} onDragLeave={() => this.setState({dragOver: false})} onDrop={(e) => this.setState({files: e.nativeEvent.files, dragOver: false})}> diff --git a/RNTester/js/RNTesterExampleContainer.js b/RNTester/js/RNTesterExampleContainer.js index 635cd02147..44de267417 100644 --- a/RNTester/js/RNTesterExampleContainer.js +++ b/RNTester/js/RNTesterExampleContainer.js @@ -19,6 +19,9 @@ const RNTesterPage = require('./RNTesterPage'); class RNTesterExampleContainer extends React.Component { renderExample(example, i) { + if (example.unsupported) { + return null; + } // Filter platform-specific examples var {title, description, platform} = example; if (platform) { diff --git a/RNTester/js/TextExample.ios.js b/RNTester/js/TextExample.ios.js index 1980ced736..b4e2a84829 100644 --- a/RNTester/js/TextExample.ios.js +++ b/RNTester/js/TextExample.ios.js @@ -233,8 +233,20 @@ exports.examples = [ render: function() { return ( + The text + + Text Inside + Another text Inside + + Total inseption + + Insepted Text Inside + + + The text should wrap if it goes on multiple lines. See, this is going to the next line. + The text after. ); }, diff --git a/RNTester/js/TextInputExample.macos.js b/RNTester/js/TextInputExample.macos.js index 7246a025a1..0e80693eb3 100644 --- a/RNTester/js/TextInputExample.macos.js +++ b/RNTester/js/TextInputExample.macos.js @@ -1,24 +1,20 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. + * Copyright (c) Facebook, Inc. and its affiliates. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. * + * @format * @flow - * @providesModule TextInputExample */ + 'use strict'; -var React = require('react'); -var ReactNative = require('react-native'); -var { - Text, - TextInput, - View, - StyleSheet, -} = ReactNative; +const Button = require('Button'); +// const InputAccessoryView = require('InputAccessoryView'); +const React = require('react'); +const ReactNative = require('react-native'); +const {Text, TextInput, View, StyleSheet, Slider, Switch, Alert} = ReactNative; class WithLabel extends React.Component<$FlowFixMeProps> { render() { @@ -41,8 +37,8 @@ class TextEventsExample extends React.Component<{}, $FlowFixMeState> { prev3Text: '', }; - updateText = (text) => { - this.setState((state) => { + updateText = text => { + this.setState(state => { return { curText: text, prevText: state.curText, @@ -56,32 +52,39 @@ class TextEventsExample extends React.Component<{}, $FlowFixMeState> { return ( this.updateText('onFocus')} onBlur={() => this.updateText('onBlur')} - onChange={(event) => this.updateText( - 'onChange text: ' + event.nativeEvent.text - )} - onEndEditing={(event) => this.updateText( - 'onEndEditing text: ' + event.nativeEvent.text - )} - onSubmitEditing={(event) => this.updateText( - 'onSubmitEditing text: ' + event.nativeEvent.text - )} - onSelectionChange={(event) => this.updateText( - 'onSelectionChange range: ' + - event.nativeEvent.selection.start + ',' + - event.nativeEvent.selection.end - )} - onKeyPress={(event) => { + onChange={event => + this.updateText('onChange text: ' + event.nativeEvent.text) + } + onTextInput={event => + this.updateText('onTextInput: ' + JSON.stringify(event.nativeEvent)) + } + onEndEditing={event => + this.updateText('onEndEditing text: ' + event.nativeEvent.text) + } + onSubmitEditing={event => + this.updateText('onSubmitEditing text: ' + event.nativeEvent.text) + } + onSelectionChange={event => + this.updateText( + 'onSelectionChange range: ' + + event.nativeEvent.selection.start + + ',' + + (event.nativeEvent.selection.end || ''), + ) + } + onKeyPress={event => { this.updateText('onKeyPress key: ' + event.nativeEvent.key); }} style={styles.default} /> - {this.state.curText}{'\n'} + {this.state.curText} + {'\n'} (prev: {this.state.prevText}){'\n'} (prev2: {this.state.prev2Text}){'\n'} (prev3: {this.state.prev3Text}) @@ -91,21 +94,56 @@ class TextEventsExample extends React.Component<{}, $FlowFixMeState> { } } +// class TextInputAccessoryViewExample extends React.Component<{}, *> { +// /* $FlowFixMe(>=0.85.0 site=react_native_ios_fb) This comment suppresses an +// * error found when Flow v0.85 was deployed. To see the error, delete this +// * comment and run Flow. */ +// constructor(props) { +// super(props); +// this.state = {text: 'Placeholder Text'}; +// } +// +// render() { +// const inputAccessoryViewID = 'inputAccessoryView1'; +// return ( +// +// this.setState({text})} +// value={this.state.text} +// /> +// +// +//