Skip to content

Commit

Permalink
Merge pull request #229 from 10play/fix-bridgeless
Browse files Browse the repository at this point in the history
Fix IOS Bridgeless mode
  • Loading branch information
GuySerfaty authored Dec 9, 2024
2 parents 0817797 + 10caf44 commit ab4ab08
Show file tree
Hide file tree
Showing 8 changed files with 216 additions and 110 deletions.
99 changes: 91 additions & 8 deletions example76/App.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,114 @@
import React from 'react';
import type {NativeStackScreenProps} from '@react-navigation/native-stack';
import React, {useRef} from 'react';
import {
SafeAreaView,
View,
KeyboardAvoidingView,
Platform,
StyleSheet,
} from 'react-native';
import {RichText, Toolbar, useEditorBridge} from '@10play/tentap-editor';
import {
RichText,
Toolbar,
useEditorBridge,
ColorKeyboard,
CustomKeyboard,
DEFAULT_TOOLBAR_ITEMS,
useKeyboard,
type EditorBridge,
useBridgeState,
TenTapStartKit,
CoreBridge,
Images,
} from '@10play/tentap-editor';

export const App = () => {
export const WithKeyboard = ({}: NativeStackScreenProps<any, any, any>) => {
const editor = useEditorBridge({
autofocus: true,
avoidIosKeyboard: true,
initialContent,
bridgeExtensions: [
...TenTapStartKit,
CoreBridge.configureCSS(`
* {
font-family: 'Rubik', sans-serif;
}
`),
],
});

const rootRef = useRef(null);
const [activeKeyboard, setActiveKeyboard] = React.useState<string>();

return (
<SafeAreaView style={exampleStyles.fullScreen}>
<RichText editor={editor} />
<SafeAreaView
style={{...exampleStyles.fullScreen, backgroundColor: 'white'}}

Check warning on line 45 in example76/App.tsx

View workflow job for this annotation

GitHub Actions / lint

Inline style: { backgroundColor: 'white' }
ref={rootRef}>
<View style={{...exampleStyles.fullScreen, paddingHorizontal: 12}}>

Check warning on line 47 in example76/App.tsx

View workflow job for this annotation

GitHub Actions / lint

Inline style: { paddingHorizontal: 12 }
<RichText editor={editor} />
</View>
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
style={exampleStyles.keyboardAvoidingView}>
<Toolbar editor={editor} />
<ToolbarWithColor
editor={editor}
activeKeyboard={activeKeyboard}
setActiveKeyboard={setActiveKeyboard}
/>
<CustomKeyboard
rootRef={rootRef}
activeKeyboardID={activeKeyboard}
setActiveKeyboardID={setActiveKeyboard}
keyboards={[ColorKeyboard]}
editor={editor}
/>
</KeyboardAvoidingView>
</SafeAreaView>
);
};

interface ToolbarWithColorProps {
editor: EditorBridge;
activeKeyboard: string | undefined;
setActiveKeyboard: (id: string | undefined) => void;
}
const ToolbarWithColor = ({
editor,
activeKeyboard,
setActiveKeyboard,
}: ToolbarWithColorProps) => {
// Get updates of editor state
const editorState = useBridgeState(editor);

const {isKeyboardUp: isNativeKeyboardUp} = useKeyboard();
const customKeyboardOpen = activeKeyboard !== undefined;
const isKeyboardUp = isNativeKeyboardUp || customKeyboardOpen;

// Here we make sure not to hide the keyboard if our custom keyboard is visible
const hideToolbar =
!isKeyboardUp || (!editorState.isFocused && !customKeyboardOpen);

return (
<Toolbar
editor={editor}
hidden={hideToolbar}
items={[
{
onPress: () => () => {
const isActive = activeKeyboard === ColorKeyboard.id;
if (isActive) editor.focus();

Check warning on line 99 in example76/App.tsx

View workflow job for this annotation

GitHub Actions / lint

Expected { after 'if' condition
setActiveKeyboard(isActive ? undefined : ColorKeyboard.id);
},
active: () => activeKeyboard === ColorKeyboard.id,
disabled: () => false,
image: () => Images.palette,
},
...DEFAULT_TOOLBAR_ITEMS,
]}
/>
);
};

const exampleStyles = StyleSheet.create({
fullScreen: {
flex: 1,
Expand All @@ -37,6 +120,6 @@ const exampleStyles = StyleSheet.create({
},
});

const initialContent = `<p>This is a basic example!</p>`;
const initialContent = `<p>This is a basic <a href="https://google.com">example</a> of using ColorKeyboard </p><img src="https://source.unsplash.com/8xznAGy4HcY/800x400" /><p></p>`;

export default App;
export default WithKeyboard;
17 changes: 0 additions & 17 deletions example76/__tests__/App.test.tsx

This file was deleted.

6 changes: 3 additions & 3 deletions example76/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1642,7 +1642,7 @@ PODS:
- ReactCommon/turbomodule/core
- Yoga
- SocketRocket (0.7.1)
- tentap (0.5.23):
- tentap (0.5.24):
- DoubleConversion
- glog
- hermes-engine
Expand Down Expand Up @@ -1944,9 +1944,9 @@ SPEC CHECKSUMS:
ReactCommon: 422e364463f33e336fc4db196aeb50fd801d90d6
RNScreens: 27587018b2e6082f5172b1ecf158c14a0e8842d6
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
tentap: 9b1d11b4314fb5c0fcd1d7009a75b5bcd420941f
tentap: b1c2108d2ee928b660e721422a4633617ca93a86
Yoga: 157bed1c62656587df4639d4dc29714898f8fb10

PODFILE CHECKSUM: 4b049e2945e28f3fea1fc2d2c2795ae6684a657b

COCOAPODS: 1.15.2
COCOAPODS: 1.16.2
2 changes: 1 addition & 1 deletion ios/TenTapViewImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// Fabric
#import <React/RCTFabricSurface.h>
#import <React/RCTSurfaceHostingProxyRootView.h>

#import <React/RCTSurfacePresenter.h>
#endif // RCT_NEW_ARCH_ENABLED

@interface TenTapViewImpl : UIView
Expand Down
181 changes: 107 additions & 74 deletions ios/TenTapViewImpl.mm
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
#import "TentapUtils.h"
#import <WebKit/WebKit.h>
#import <React/RCTUIManager.h>
#import <objc/runtime.h>
#import <objc/message.h>
#import <React/RCTBridge.h>


static UIView *globalCustomKeyboard; // Store the custom keyboard reference globally

@interface HelperViewTemp : UIView

Expand All @@ -11,101 +17,128 @@ @interface HelperViewTemp : UIView

@implementation HelperViewTemp

- (BOOL)canBecomeFirstResponder
{
// In order for our keyboard to popup - our helper view (which contains the inputViewController) must be first responder
return YES;
- (BOOL)canBecomeFirstResponder {
// In order for our keyboard to popup - our helper view (which contains the inputViewController) must be first responder
return YES;
}

- (BOOL)resignFirstResponder
{
// Once no longer first responder (blur) - remove self from super view
BOOL rv = [super resignFirstResponder];
[self removeFromSuperview];
return rv;
- (BOOL)resignFirstResponder {
// Once no longer first responder (blur) - remove self from super view
BOOL rv = [super resignFirstResponder];
[self removeFromSuperview];
return rv;
}

@end

@implementation TenTapViewImpl

- (instancetype)init {
self = [super init];
if (self) {
}
return self;
self = [super init];
return self;
}



- (void)cleanupKeyboard {
// Remove the custom keyboard from its superview
if (globalCustomKeyboard) {
[globalCustomKeyboard removeFromSuperview];
globalCustomKeyboard = nil;
}
}

- (void)setKeyboardID:(NSString *)keyboardID {
_keyboardID = keyboardID;
_keyboardID = keyboardID;

// When keyboardID is unset, clean up the keyboard
if ([_keyboardID isEqualToString:@""]) {
[self cleanupKeyboard];
}
}

- (void)setInputTag:(NSNumber *)inputTag {
_inputTag = inputTag;
if(self.bridge == nil)
{
NSLog(@"No bridge");
_inputTag = inputTag;

if (self.bridge == nil) {
NSLog(@"No bridge");
return;
}

// Get input field from tag (react ref)
UIView *inputField = [self.bridge.uiManager viewForReactTag:inputTag];
if (inputField != nil) {
// Create input controller
UIInputViewController *inputController = [[UIInputViewController alloc] init];
UIInputView *inputView = [[UIInputView alloc] initWithFrame:CGRectZero inputViewStyle:UIInputViewStyleKeyboard];
inputView.allowsSelfSizing = YES;
inputView.translatesAutoresizingMaskIntoConstraints = NO;
inputController.inputView = inputView;

UIView *customKeyboard = nil;
#ifdef RCT_NEW_ARCH_ENABLED
// On new arch we create RCTSurfaceHostingProxyRootView via rootViewFactory which is on AppDelegate
// using the viewWithModuleName function
id appDelegate = [UIApplication sharedApplication].delegate;

// Ensure the app delegate responds to `rootViewFactory`
if ([appDelegate respondsToSelector:NSSelectorFromString(@"rootViewFactory")]) {
id rootViewFactory = [appDelegate valueForKey:@"rootViewFactory"];
SEL viewWithModuleNameSelector = NSSelectorFromString(@"viewWithModuleName:initialProperties:");
if ([rootViewFactory respondsToSelector:viewWithModuleNameSelector]) {
RCTSurfaceHostingProxyRootView *hostingRootView = (RCTSurfaceHostingProxyRootView *)((UIView *(*)(id, SEL, NSString *, NSDictionary *))
objc_msgSend)(rootViewFactory, viewWithModuleNameSelector, _keyboardID, @{});
customKeyboard = hostingRootView;
} else {
NSLog(@"rootViewFactory does not respond to viewWithModuleName:initialProperties:");
return;
}
} else {
NSLog(@"AppDelegate does not have a rootViewFactory property");
return;
}
#else
// on old arch use legacy RCTRootView
customKeyboard = [[RCTRootView alloc] initWithBridge:self.bridge moduleName:_keyboardID initialProperties:nil];
#endif

// Get input field from tag (react ref)
UIView* inputField = [self.bridge.uiManager viewForReactTag:inputTag];
if(inputField != nil) {
// Create input controller
UIInputViewController *inputController = [[UIInputViewController alloc] init];
UIInputView *inputView = [[UIInputView alloc] initWithFrame:CGRectZero inputViewStyle:UIInputViewStyleKeyboard];
inputView.allowsSelfSizing = YES;
inputView.translatesAutoresizingMaskIntoConstraints = NO;
inputController.inputView = inputView;

// Create Keyboard
UIView *customKeyboard = nil;
#ifdef RCT_NEW_ARCH_ENABLED
// On new arch use fabric view
id<RCTSurfaceProtocol> surface = [[RCTFabricSurface alloc] initWithBridge:self.bridge
moduleName:_keyboardID
initialProperties:{}];
customKeyboard = [[RCTSurfaceHostingProxyRootView alloc] initWithSurface:surface];
#else
// on old arch use RCTRootView
customKeyboard = [[RCTRootView alloc] initWithBridge:self.bridge moduleName:_keyboardID initialProperties:nil];
#endif /* RCT_NEW_ARCH_ENABLED */

if(_rootBackground != nil){
customKeyboard.backgroundColor = _rootBackground;
}

customKeyboard.translatesAutoresizingMaskIntoConstraints = NO;
// Add keyboard to inputView
[inputView addSubview:customKeyboard];

// Activate constraints
[NSLayoutConstraint activateConstraints:@[
[customKeyboard.leadingAnchor constraintEqualToAnchor:inputController.view.leadingAnchor],
[customKeyboard.trailingAnchor constraintEqualToAnchor:inputController.view.trailingAnchor],
[customKeyboard.topAnchor constraintEqualToAnchor:inputController.view.topAnchor],
[customKeyboard.bottomAnchor constraintEqualToAnchor:inputController.view.bottomAnchor],
[customKeyboard.heightAnchor constraintEqualToConstant:[self.keyboardHeight floatValue]]
]];
[inputView setNeedsLayout];

// Create helper view
// This view will contain our custom inputController and will be the first responder
HelperViewTemp *helperView = [[HelperViewTemp alloc] initWithFrame:CGRectZero];
helperView.backgroundColor = [UIColor clearColor];

[inputField.superview addSubview:helperView];
[inputField.superview sendSubviewToBack:helperView];

helperView.inputViewController = inputController;
[helperView reloadInputViews];
[helperView becomeFirstResponder];
return;
if (_rootBackground != nil) {
customKeyboard.backgroundColor = _rootBackground;
}

customKeyboard.translatesAutoresizingMaskIntoConstraints = NO;
// Add keyboard to inputView
[inputView addSubview:customKeyboard];

// Activate constraints
[NSLayoutConstraint activateConstraints:@[
[customKeyboard.leadingAnchor constraintEqualToAnchor:inputController.view.leadingAnchor],
[customKeyboard.trailingAnchor constraintEqualToAnchor:inputController.view.trailingAnchor],
[customKeyboard.topAnchor constraintEqualToAnchor:inputController.view.topAnchor],
[customKeyboard.bottomAnchor constraintEqualToAnchor:inputController.view.bottomAnchor],
[customKeyboard.heightAnchor constraintEqualToConstant:[self.keyboardHeight floatValue]]
]];
[inputView setNeedsLayout];

// Create helper view
HelperViewTemp *helperView = [[HelperViewTemp alloc] initWithFrame:CGRectZero];
helperView.backgroundColor = [UIColor clearColor];

[inputField.superview addSubview:helperView];
[inputField.superview sendSubviewToBack:helperView];

helperView.inputViewController = inputController;
[helperView reloadInputViews];
[helperView becomeFirstResponder];

// Store the custom keyboard reference globally
globalCustomKeyboard = customKeyboard;
return;
}
}

- (void) setKeyboardHeight:(NSNumber *)keyboardHeight{
_keyboardHeight = keyboardHeight;
- (void)setKeyboardHeight:(NSNumber *)keyboardHeight {
_keyboardHeight = keyboardHeight;
}

@end
Loading

0 comments on commit ab4ab08

Please sign in to comment.