Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions js_libraries/types/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# CHANGELOG

## 4.3.3
- Add `inputType` to the `<input>` and `<textarea>` input event typings to distinguish paste from normal input.

## 4.3.2
- Add `android-overlay-scope` to `<overlay>` typings.

Expand Down
2 changes: 1 addition & 1 deletion js_libraries/types/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@lynx-js/types",
"version": "4.3.2",
"version": "4.3.3",
"description": "",
"keywords": [
"lynx",
Expand Down
6 changes: 6 additions & 0 deletions js_libraries/types/test/pages/input.test-d.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ function noop() {}
assertType<number>(e.detail.selectionStart);
assertType<number>(e.detail.selectionEnd);
assertType<boolean | undefined>(e.detail.isComposing);
assertType<'paste' | 'normal' | undefined>(e.detail.inputType);
expectError(() => {
// @ts-expect-error type error
assertType<number>(e.detail.value);
Expand All @@ -198,6 +199,8 @@ function noop() {}
assertType<string>(e.detail.selectionEnd);
// @ts-expect-error type error
assertType<number>(e.detail.isComposing);
// @ts-expect-error type error
assertType<boolean>(e.detail.inputType);
});
}}
/>;
Expand All @@ -207,6 +210,7 @@ function noop() {}
assertType<number>(e.detail.selectionStart);
assertType<number>(e.detail.selectionEnd);
assertType<boolean | undefined>(e.detail.isComposing);
assertType<'paste' | 'normal' | undefined>(e.detail.inputType);
expectError(() => {
// @ts-expect-error type error
assertType<number>(e.detail.value);
Expand All @@ -216,6 +220,8 @@ function noop() {}
assertType<string>(e.detail.selectionEnd);
// @ts-expect-error type error
assertType<number>(e.detail.isComposing);
// @ts-expect-error type error
assertType<boolean>(e.detail.inputType);
});
}}
/>;
Expand Down
8 changes: 8 additions & 0 deletions js_libraries/types/types/common/element/input.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,14 @@ export interface InputInputEvent {
* @since 3.4
*/
isComposing?: boolean;
/**
* The type of input action, "paste" when pasting, "normal" otherwise
* @Android
* @iOS
* @Harmony
* @since 4.3
*/
inputType?: 'paste' | 'normal';
}

export interface InputSelectionEvent {
Expand Down
8 changes: 8 additions & 0 deletions js_libraries/types/types/common/element/textarea.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ export interface TextAreaInputEvent {
* @since 3.4
*/
isComposing?: boolean;
/**
* The type of input action, "paste" when pasting, "normal" otherwise
* @Android
* @iOS
* @Harmony
* @since 4.3
*/
inputType?: 'paste' | 'normal';
}

export interface TextAreaFocusEvent {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,9 @@ open class LynxUIBaseInput(context: LynxContext, params: Any?) : LynxUI<LynxEdit
addDetail("selectionStart", selectionStart)
addDetail("selectionEnd", selectionEnd)
addDetail("isComposing", mView?.inputConnection()?.hasComposingText(it))
addDetail("inputType", if (mView.mPasting) "paste" else "normal")
})
mView.mPasting = false
}
}
}
Expand Down
1 change: 0 additions & 1 deletion platform/darwin/ios/lynx_xelement/input/LynxUIBaseInput.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ NS_ASSUME_NONNULL_BEGIN
- (void)didApplyOverflowReplacementForInput:(id<UITextInput>)input;

- (NSString *)filterString:(NSString *)source withMaxLength:(NSInteger)maxLength;

@end

NS_ASSUME_NONNULL_END
51 changes: 28 additions & 23 deletions platform/darwin/ios/lynx_xelement/input/LynxUIBaseInput.m
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
#define UNDEFINED_INT NSUIntegerMax
#define UNDEFINED_FLOAT CGFLOAT_MIN

@protocol LynxPasteAwareInput <NSObject>
@property(nonatomic, assign) BOOL pasting;
@end

@interface LynxUIBaseInput () <LynxFontFaceObserver, LynxKeyboardEventObserver>

@property (nonatomic, strong) NSString *preValue;
Expand All @@ -35,6 +39,7 @@ @interface LynxUIBaseInput () <LynxFontFaceObserver, LynxKeyboardEventObserver>
@property (nonatomic, assign) BOOL enableHoldKeyboard;
@property (nonatomic, assign) BOOL shouldSuppressInputEvent;
@property (nonatomic, assign) BOOL defaultValueConsumed;

@end

static const NSTimeInterval kLynxInputKeyboardDefaultAnimationDuration = 0.3;
Expand Down Expand Up @@ -560,23 +565,26 @@ - (BOOL)inputViewDidChange:(id<UITextInput>)input {
if (self.shouldSuppressInputEvent) {
return YES;
}

[self sendInputEvent];

return YES;
}

- (void)sendInputEvent {
if (self.shouldSuppressInputEvent) {
return;
}
id<LynxPasteAwareInput> input = (id<LynxPasteAwareInput>)self.view;
BOOL isPasting = input.pasting;
if (!self.sendComposingInputEvent) {
NSString *curValue = [self getText];
if (![curValue isEqualToString:self.preValue]) {
[self emitEvent:@"input" detail:@{
@"value" : curValue,
@"selectionStart": @(self.view.isFirstResponder ? [self.view offsetFromPosition:self.view.beginningOfDocument toPosition:self.view.selectedTextRange.start] : -1),
@"selectionEnd": @(self.view.isFirstResponder ? [self.view offsetFromPosition:self.view.beginningOfDocument toPosition:self.view.selectedTextRange.end] : -1),
@"inputType": isPasting ? @"paste" : @"normal",
}];
self.preValue = curValue;
}
Expand All @@ -585,13 +593,15 @@ - (void)sendInputEvent {
@"value" : [self getText],
@"selectionStart": @(self.view.isFirstResponder ? [self.view offsetFromPosition:self.view.beginningOfDocument toPosition:self.view.selectedTextRange.start] : -1),
@"selectionEnd": @(self.view.isFirstResponder ? [self.view offsetFromPosition:self.view.beginningOfDocument toPosition:self.view.selectedTextRange.end] : -1),
@"isComposing" : @([self.view markedTextRange] != nil)
@"isComposing" : @([self.view markedTextRange] != nil),
@"inputType": isPasting ? @"paste" : @"normal",
};
if (![curInputData isEqual:self.preInputData]) {
[self emitEvent:@"input" detail:curInputData];
self.preInputData = curInputData;
}
}
input.pasting = NO;
}

- (void)setCollapsedSelectionForInput:(id<UITextInput>)input offset:(NSInteger)offset {
Expand Down Expand Up @@ -652,31 +662,26 @@ - (void)didApplyOverflowReplacementForInput:(id<UITextInput>)input {
}

- (BOOL)inputView:(id<UITextInput>)input shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if (!self.readonly) {
[self emitEvent:@"beforeinput" detail:@{
@"value" : [self getText],
@"cursor": @(range.location),
@"length": @(range.length),
@"replace" : string ? : @"",
@"isComposing" : @([self isComposing])
}];
BOOL shouldChange = !self.readonly;
if (shouldChange) {
[self emitEvent:@"beforeinput" detail:@{
@"value" : [self getText],
@"cursor": @(range.location),
@"length": @(range.length),
@"replace" : string ? : @"",
@"isComposing" : @([self isComposing])
}];
NSString *currentText = self.getText;
NSUInteger newLength = [currentText length] + [string length] - range.length;
if (newLength > self.maxLength) {
if ([self handleOverflowReplacementForInput:input
currentText:currentText
range:range
replacementString:string ? : @""]) {
return NO;
}
// MAX
return NO;
[self handleOverflowReplacementForInput:input
currentText:currentText
range:range
replacementString:string ? : @""];
shouldChange = NO;
}
} else {
return NO;
}

return YES;
return shouldChange;
}

- (void)inputWillBeFilteredFrom:(NSString *)source to:(NSString *)dest {
Expand Down
6 changes: 6 additions & 0 deletions platform/darwin/ios/lynx_xelement/input/LynxUIInput.m
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ - (BOOL)shouldSuppressInputEvent;
@interface LynxTextFieldLite : UITextField

@property(nonatomic, assign) UIEdgeInsets padding;
@property(nonatomic, assign) BOOL pasting;

@end

Expand All @@ -32,6 +33,11 @@ - (UIEditingInteractionConfiguration)editingInteractionConfiguration API_AVAILAB
- (void)scrollTextFieldToVisibleIfNecessary {
}

- (void)paste:(id)sender {
self.pasting = YES;
[super paste:sender];
}

- (void)setPadding:(UIEdgeInsets)padding {
_padding = padding;
[self setNeedsLayout];
Expand Down
31 changes: 23 additions & 8 deletions platform/darwin/ios/lynx_xelement/input/LynxUITextArea.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,21 @@
static CGFloat kLynxTextAreaEpsilonThreshold = 1.0f;
static NSInteger kLynxTextAreaOutOfMaxlines = -1;

@interface LynxTextViewLite : UITextView

@property(nonatomic, assign) BOOL pasting;

@end

@implementation LynxTextViewLite

- (void)paste:(id)sender {
self.pasting = YES;
[super paste:sender];
}

@end

@interface LynxUIBaseInput (LynxDefaultValueInputEventSuppression)
// Reuse the default-value input suppression flag owned by LynxUIBaseInput.m.
// The flag stays private; this local declaration only makes the existing
Expand Down Expand Up @@ -41,7 +56,7 @@ - (instancetype)init {
}

- (UITextView *)createView {
UITextView* textView = [[UITextView alloc] init];
LynxTextViewLite* textView = [[LynxTextViewLite alloc] init];
textView.autoresizesSubviews = NO;
textView.clipsToBounds = YES;
textView.delegate = self;
Expand All @@ -51,14 +66,14 @@ - (UITextView *)createView {
textView.textContainer.lineFragmentPadding = 0;

textView.tag = gTextareaLightTag++;

textView.showsVerticalScrollIndicator = NO;

kLynxTextAreaEpsilonThreshold = UIScreen.mainScreen.scale;

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onWillShowKeyboard:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onWillHideKeyboard:) name:UIKeyboardWillHideNotification object:nil];

return textView;
}

Expand Down Expand Up @@ -290,6 +305,7 @@ - (void)textViewDidChange:(UITextView*)textView {
if (![[self getText] isEqualToString:(self.lastValue ? : @"")]) {
[self sendInputEvent];
}

self.lastValue = [self getText];

}
Expand Down Expand Up @@ -330,17 +346,16 @@ - (void)didApplyOverflowReplacementForInput:(id<UITextInput>)input {

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
if ([text isEqualToString:@"\n"] && textView.returnKeyType != UIReturnKeyDefault) {
// If the confirm-type is not "default"(next-line), send confirm manually, cause UITextView do not have the callback of `textFieldShouldReturn:`
return [self inputViewShouldReturn:textView];
}

// The last line needs to be filtered when it is '\n'. This is essentially to be compatible with a bug from UIKit.
NSArray<NSString *> *currentLines = [textView.text componentsSeparatedByCharactersInSet:NSCharacterSet.newlineCharacterSet];
NSArray<NSString *> *comingLines = [text componentsSeparatedByCharactersInSet:NSCharacterSet.newlineCharacterSet];
if ( currentLines.count + comingLines.count - 1 > self.maxlines) {
return NO;
}

return [self inputView:textView shouldChangeCharactersInRange:range replacementString:text];
}

Expand Down
6 changes: 5 additions & 1 deletion platform/harmony/lynx_xelement/input/ui_base_input.cc
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,8 @@ void UIBaseInput::OnNodeEvent(ArkUI_NodeEvent* event) {
{.i32 = readonly_ ? 0 : 1},
};
OH_ArkUI_NodeEvent_SetReturnNumberValue(event, value, 1);
} else if (type == GetOnPasteEventType()) {
is_pasting_ = true;
}
}

Expand Down Expand Up @@ -601,7 +603,7 @@ int32_t UIBaseInput::MeasureTextHeight(float font_size, float max_width,
return height;
}

void UIBaseInput::SendInputEvent() const {
void UIBaseInput::SendInputEvent() {
const auto value = NodeManager::Instance().GetAttribute<std::string>(
input_node_, GetTextAttributeType());

Expand All @@ -619,8 +621,10 @@ void UIBaseInput::SendInputEvent() const {
param->SetValue("selectionStart", selectionStart);
param->SetValue("selectionEnd", selectionEnd);
param->SetValue("isComposing", false);
param->SetValue("inputType", std::string(is_pasting_ ? "paste" : "normal"));
CustomEvent event{Sign(), "input", "detail", lepus_value(param)};
context_->SendEvent(event);
is_pasting_ = false;
}

void UIBaseInput::SendSelectionChangeEvent(const int32_t start,
Expand Down
6 changes: 5 additions & 1 deletion platform/harmony/lynx_xelement/input/ui_base_input.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class UIBaseInput : public UIView {
void OnNodeEvent(ArkUI_NodeEvent* event) override;
void OnFocusChange(bool has_focus, bool is_focus_transition) override;
float OnArkUILayoutChanged();
void SendInputEvent() const;
void SendInputEvent();
void SendSelectionChangeEvent(int32_t start, int32_t end) const;
void SendConfirmEvent() const;
void SendFocusEvent() const;
Expand All @@ -41,6 +41,7 @@ class UIBaseInput : public UIView {
bool keyboard_event_observer_registered_{false};
bool default_value_consumed_{false};
bool should_suppress_default_value_events_{false};
bool is_pasting_{false};

float computed_height_{INPUT_UNDEFINED_FLOAT};
float max_height_{INPUT_UNDEFINED_FLOAT};
Expand Down Expand Up @@ -81,6 +82,9 @@ class UIBaseInput : public UIView {
virtual ArkUI_NodeEventType GetOnWillDeleteEventType() const {
return static_cast<ArkUI_NodeEventType>(-1);
}
virtual ArkUI_NodeEventType GetOnPasteEventType() const {
return static_cast<ArkUI_NodeEventType>(-1);
}

UIBaseInput(LynxContext* context, ArkUI_NodeType type, int sign, const std::string& tag,
ArkUI_NodeType input_node_type);
Expand Down
9 changes: 9 additions & 0 deletions platform/harmony/lynx_xelement/input/ui_input.cc
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ UIInput::UIInput(LynxContext* context, ArkUI_NodeType type, int sign,
NodeManager::Instance().RegisterNodeEvent(input_node_,
NODE_TEXT_INPUT_ON_SUBMIT, this);

NodeManager::Instance().RegisterNodeEvent(input_node_, GetOnPasteEventType(),
this);

NodeManager::Instance().SetAttributeWithNumberValue(
input_node_, NODE_TEXT_INPUT_PLACEHOLDER_COLOR, INPUT_DEFAULT_COLOR);
}
Expand All @@ -150,6 +153,8 @@ UIInput::~UIInput() {
GetOnWillInsertEventType());
NodeManager::Instance().UnregisterNodeEvent(input_node_,
GetOnWillDeleteEventType());
NodeManager::Instance().UnregisterNodeEvent(input_node_,
GetOnPasteEventType());
}

void UIInput::OnNodeEvent(ArkUI_NodeEvent* event) {
Expand Down Expand Up @@ -210,6 +215,10 @@ ArkUI_NodeEventType UIInput::GetOnWillDeleteEventType() const {
return NODE_TEXT_INPUT_ON_WILL_DELETE;
}

ArkUI_NodeEventType UIInput::GetOnPasteEventType() const {
return NODE_TEXT_INPUT_ON_PASTE;
}

} // namespace harmony
} // namespace tasm
} // namespace lynx
Loading
Loading