@momo-kits/calculator-keyboard 0.150.2-beta.3 → 0.150.2-beta.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -3
- package/android/src/main/java/com/calculatorkeyboard/CalculatorKeyboardPackage.kt +1 -1
- package/android/src/main/java/com/calculatorkeyboard/CustomKeyboardView.kt +225 -90
- package/android/src/main/java/com/calculatorkeyboard/Event.kt +36 -0
- package/android/src/main/java/com/calculatorkeyboard/InputCalculatorViewManager.kt +270 -0
- package/android/src/main/java/com/calculatorkeyboard/KeyboardOverplayHost.kt +232 -0
- package/ios/CalculatorKeyboardView.h +30 -0
- package/ios/CalculatorKeyboardView.mm +231 -0
- package/ios/NativeInputCalculator.h +11 -0
- package/ios/NativeInputCalculator.mm +369 -0
- package/package.json +21 -131
- package/react-native-calculator-keyboard.podspec +5 -4
- package/src/InputCalculatorNativeComponent.ts +62 -0
- package/src/index.tsx +104 -31
- package/android/src/main/java/com/calculatorkeyboard/RCTInputCalculator.kt +0 -179
- package/ios/CalculatorKeyboardView.swift +0 -115
- package/ios/InputCalculator-Bridging-Header.h +0 -23
- package/ios/InputCalculator.m +0 -79
- package/ios/InputCalculator.swift +0 -138
- package/ios/extension.swift +0 -23
- package/lib/commonjs/index.js +0 -48
- package/lib/commonjs/index.js.map +0 -1
- package/lib/module/index.js +0 -44
- package/lib/module/index.js.map +0 -1
- package/lib/typescript/commonjs/package.json +0 -1
- package/lib/typescript/commonjs/src/index.d.ts +0 -13
- package/lib/typescript/commonjs/src/index.d.ts.map +0 -1
- package/lib/typescript/module/package.json +0 -1
- package/lib/typescript/module/src/index.d.ts +0 -13
- package/lib/typescript/module/src/index.d.ts.map +0 -1
package/package.json
CHANGED
|
@@ -1,22 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@momo-kits/calculator-keyboard",
|
|
3
|
-
"version": "0.150.2-beta.
|
|
3
|
+
"version": "0.150.2-beta.30",
|
|
4
4
|
"description": "react native calculator keyboard",
|
|
5
|
-
"
|
|
6
|
-
"main": "./lib/commonjs/index.js",
|
|
7
|
-
"module": "./lib/module/index.js",
|
|
8
|
-
"exports": {
|
|
9
|
-
".": {
|
|
10
|
-
"import": {
|
|
11
|
-
"types": "./lib/typescript/module/src/index.d.ts",
|
|
12
|
-
"default": "./lib/module/index.js"
|
|
13
|
-
},
|
|
14
|
-
"require": {
|
|
15
|
-
"types": "./lib/typescript/commonjs/src/index.d.ts",
|
|
16
|
-
"default": "./lib/commonjs/index.js"
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
},
|
|
5
|
+
"main": "./src/index.tsx",
|
|
20
6
|
"files": [
|
|
21
7
|
"src",
|
|
22
8
|
"lib",
|
|
@@ -40,9 +26,7 @@
|
|
|
40
26
|
"test": "jest",
|
|
41
27
|
"typecheck": "tsc",
|
|
42
28
|
"lint": "eslint \"**/*.{js,ts,tsx}\"",
|
|
43
|
-
"
|
|
44
|
-
"build": "bob build",
|
|
45
|
-
"release": "release-it"
|
|
29
|
+
"build": "echo"
|
|
46
30
|
},
|
|
47
31
|
"keywords": [
|
|
48
32
|
"react-native",
|
|
@@ -62,124 +46,30 @@
|
|
|
62
46
|
"publishConfig": {
|
|
63
47
|
"registry": "https://registry.npmjs.org/"
|
|
64
48
|
},
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
|
|
71
|
-
"@types/jest": "^29.5.5",
|
|
72
|
-
"@types/react": "^18.2.44",
|
|
73
|
-
"commitlint": "^17.0.2",
|
|
74
|
-
"del-cli": "^5.1.0",
|
|
75
|
-
"eslint": "^8.51.0",
|
|
76
|
-
"eslint-config-prettier": "^9.0.0",
|
|
77
|
-
"eslint-plugin-prettier": "^5.0.1",
|
|
78
|
-
"jest": "^29.7.0",
|
|
79
|
-
"prettier": "^3.0.3",
|
|
80
|
-
"react": "18.3.1",
|
|
81
|
-
"react-native": "0.76.5",
|
|
82
|
-
"react-native-builder-bob": "^0.32.0",
|
|
83
|
-
"release-it": "^17.10.0",
|
|
84
|
-
"turbo": "^1.10.7",
|
|
85
|
-
"typescript": "^5.2.2"
|
|
86
|
-
},
|
|
87
|
-
"resolutions": {
|
|
88
|
-
"@types/react": "^18.2.44"
|
|
89
|
-
},
|
|
90
|
-
"peerDependencies": {
|
|
91
|
-
"react": "*",
|
|
92
|
-
"react-native": "*"
|
|
93
|
-
},
|
|
94
|
-
"jest": {
|
|
95
|
-
"preset": "react-native",
|
|
96
|
-
"modulePathIgnorePatterns": [
|
|
97
|
-
"<rootDir>/example/node_modules",
|
|
98
|
-
"<rootDir>/lib/"
|
|
99
|
-
]
|
|
100
|
-
},
|
|
101
|
-
"commitlint": {
|
|
102
|
-
"extends": [
|
|
103
|
-
"@commitlint/config-conventional"
|
|
104
|
-
]
|
|
105
|
-
},
|
|
106
|
-
"release-it": {
|
|
107
|
-
"git": {
|
|
108
|
-
"commitMessage": "chore: release ${version}",
|
|
109
|
-
"tagName": "v${version}"
|
|
110
|
-
},
|
|
111
|
-
"npm": {
|
|
112
|
-
"publish": true
|
|
113
|
-
},
|
|
114
|
-
"github": {
|
|
115
|
-
"release": true
|
|
49
|
+
"codegenConfig": {
|
|
50
|
+
"name": "CalculatorKeyboardSpecs",
|
|
51
|
+
"type": "components",
|
|
52
|
+
"jsSrcsDir": "src",
|
|
53
|
+
"android": {
|
|
54
|
+
"javaPackageName": "com.calculatorkeyboard"
|
|
116
55
|
},
|
|
117
|
-
"
|
|
118
|
-
"
|
|
119
|
-
"
|
|
56
|
+
"ios": {
|
|
57
|
+
"componentProvider": {
|
|
58
|
+
"NativeInputCalculator": "NativeInputCalculator"
|
|
120
59
|
}
|
|
121
60
|
}
|
|
122
61
|
},
|
|
123
|
-
"
|
|
124
|
-
"
|
|
125
|
-
"
|
|
126
|
-
"@react-native",
|
|
127
|
-
"prettier"
|
|
128
|
-
],
|
|
129
|
-
"rules": {
|
|
130
|
-
"react/react-in-jsx-scope": "off",
|
|
131
|
-
"prettier/prettier": [
|
|
132
|
-
"error",
|
|
133
|
-
{
|
|
134
|
-
"quoteProps": "consistent",
|
|
135
|
-
"singleQuote": true,
|
|
136
|
-
"tabWidth": 2,
|
|
137
|
-
"trailingComma": "es5",
|
|
138
|
-
"useTabs": false
|
|
139
|
-
}
|
|
140
|
-
]
|
|
141
|
-
}
|
|
142
|
-
},
|
|
143
|
-
"eslintIgnore": [
|
|
144
|
-
"node_modules/",
|
|
145
|
-
"lib/"
|
|
146
|
-
],
|
|
147
|
-
"prettier": {
|
|
148
|
-
"quoteProps": "consistent",
|
|
149
|
-
"singleQuote": true,
|
|
150
|
-
"tabWidth": 2,
|
|
151
|
-
"trailingComma": "es5",
|
|
152
|
-
"useTabs": false
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"react": "19.0.0",
|
|
64
|
+
"react-native": "0.80.1"
|
|
153
65
|
},
|
|
154
|
-
"
|
|
155
|
-
"
|
|
156
|
-
"
|
|
157
|
-
"
|
|
158
|
-
[
|
|
159
|
-
"commonjs",
|
|
160
|
-
{
|
|
161
|
-
"esm": true
|
|
162
|
-
}
|
|
163
|
-
],
|
|
164
|
-
[
|
|
165
|
-
"module",
|
|
166
|
-
{
|
|
167
|
-
"esm": true
|
|
168
|
-
}
|
|
169
|
-
],
|
|
170
|
-
[
|
|
171
|
-
"typescript",
|
|
172
|
-
{
|
|
173
|
-
"project": "tsconfig.build.json",
|
|
174
|
-
"esm": true
|
|
175
|
-
}
|
|
176
|
-
]
|
|
177
|
-
]
|
|
66
|
+
"peerDependencies": {
|
|
67
|
+
"react": "*",
|
|
68
|
+
"react-native": "*",
|
|
69
|
+
"@momo-kits/foundation": "latest"
|
|
178
70
|
},
|
|
179
|
-
"
|
|
180
|
-
"
|
|
181
|
-
"languages": "kotlin-swift",
|
|
182
|
-
"version": "0.45.5"
|
|
71
|
+
"engines": {
|
|
72
|
+
"node": ">=18.0.0"
|
|
183
73
|
},
|
|
184
74
|
"dependencies": {}
|
|
185
75
|
}
|
|
@@ -5,7 +5,7 @@ folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1
|
|
|
5
5
|
|
|
6
6
|
Pod::Spec.new do |s|
|
|
7
7
|
s.name = "react-native-calculator-keyboard"
|
|
8
|
-
s.version = "
|
|
8
|
+
s.version = package["version"]
|
|
9
9
|
s.summary = package["description"]
|
|
10
10
|
s.homepage = package["homepage"]
|
|
11
11
|
s.license = package["license"]
|
|
@@ -14,9 +14,10 @@ Pod::Spec.new do |s|
|
|
|
14
14
|
s.platforms = { :ios => min_ios_version_supported }
|
|
15
15
|
s.source = { :git => "https://github.com/wem2017/react-native-calculator-keyboard.git/react-native-calculator-keyboard.git", :tag => "#{s.version}" }
|
|
16
16
|
|
|
17
|
-
s.source_files = "ios/**/*.{h,m,mm
|
|
18
|
-
s.
|
|
19
|
-
|
|
17
|
+
s.source_files = "ios/**/*.{h,m,mm}"
|
|
18
|
+
# s.public_header_files = "ios/CalculatorKeyboardView.h"
|
|
19
|
+
# s.private_header_files = "ios/NativeInputCalculator.h"
|
|
20
|
+
|
|
20
21
|
# Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
|
|
21
22
|
# See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.
|
|
22
23
|
if respond_to?(:install_modules_dependencies, true)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type * as React from 'react';
|
|
2
|
+
import type { HostComponent, ViewProps } from 'react-native';
|
|
3
|
+
import {
|
|
4
|
+
CodegenTypes,
|
|
5
|
+
codegenNativeComponent,
|
|
6
|
+
codegenNativeCommands,
|
|
7
|
+
} from 'react-native';
|
|
8
|
+
|
|
9
|
+
export type CustomKeyBackground = 'primary' | 'default' | string;
|
|
10
|
+
|
|
11
|
+
export enum CustomKeyState {
|
|
12
|
+
Default = 'default',
|
|
13
|
+
Disable = 'disable',
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export enum Mode {
|
|
17
|
+
NumDefault = 'NumDefault',
|
|
18
|
+
NumWithCTA = 'NumWithCTA',
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type OnKeyPressEvent = Readonly<{
|
|
22
|
+
key: string;
|
|
23
|
+
}>;
|
|
24
|
+
|
|
25
|
+
export type OnChangeEvent = Readonly<{
|
|
26
|
+
text: string;
|
|
27
|
+
}>;
|
|
28
|
+
|
|
29
|
+
export type TextAttributes = Readonly<{
|
|
30
|
+
fontSize?: CodegenTypes.Float;
|
|
31
|
+
fontWeight?: string;
|
|
32
|
+
}>;
|
|
33
|
+
|
|
34
|
+
export interface NativeInputCalculatorProps extends ViewProps {
|
|
35
|
+
value?: string;
|
|
36
|
+
textAttributes?: TextAttributes;
|
|
37
|
+
mode?: string;
|
|
38
|
+
customKeyText?: string;
|
|
39
|
+
customKeyBackground?: string;
|
|
40
|
+
customKeyTextColor?: string;
|
|
41
|
+
customKeyState?: string;
|
|
42
|
+
onChange?: CodegenTypes.BubblingEventHandler<OnChangeEvent>;
|
|
43
|
+
onKeyPress?: CodegenTypes.BubblingEventHandler<OnKeyPressEvent>;
|
|
44
|
+
onCustomKeyEvent?: CodegenTypes.DirectEventHandler<{}>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface NativeInputCalculatorCommands {
|
|
48
|
+
focus(
|
|
49
|
+
viewRef: React.ElementRef<HostComponent<NativeInputCalculatorProps>>,
|
|
50
|
+
): void;
|
|
51
|
+
blur(
|
|
52
|
+
viewRef: React.ElementRef<HostComponent<NativeInputCalculatorProps>>,
|
|
53
|
+
): void;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export const Commands = codegenNativeCommands<NativeInputCalculatorCommands>({
|
|
57
|
+
supportedCommands: ['focus', 'blur'],
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
export default codegenNativeComponent<NativeInputCalculatorProps>(
|
|
61
|
+
'NativeInputCalculator',
|
|
62
|
+
);
|
package/src/index.tsx
CHANGED
|
@@ -1,21 +1,43 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useContext } from 'react';
|
|
3
|
+
import { ApplicationContext, Colors } from '@momo-kits/foundation';
|
|
2
4
|
import {
|
|
3
5
|
type NativeSyntheticEvent,
|
|
4
|
-
type TextInputChangeEventData,
|
|
5
6
|
type TextInputProps,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
findNodeHandle,
|
|
7
|
+
StyleSheet,
|
|
8
|
+
StyleProp,
|
|
9
|
+
TextStyle,
|
|
10
10
|
} from 'react-native';
|
|
11
|
-
import {
|
|
11
|
+
import NativeInputCalculator, {
|
|
12
|
+
TextAttributes,
|
|
13
|
+
} from './InputCalculatorNativeComponent';
|
|
14
|
+
import { Commands } from './InputCalculatorNativeComponent';
|
|
12
15
|
|
|
13
|
-
const
|
|
14
|
-
|
|
16
|
+
const NativeInput = NativeInputCalculator;
|
|
17
|
+
|
|
18
|
+
type KeyPressEvent = { nativeEvent: { key: string } };
|
|
15
19
|
|
|
16
20
|
interface InputCalculatorProps extends TextInputProps {
|
|
17
21
|
text?: string | undefined;
|
|
18
|
-
|
|
22
|
+
mode?: Mode;
|
|
23
|
+
onKeyPress?: (e: KeyPressEvent) => void;
|
|
24
|
+
customKeyText?: string | undefined;
|
|
25
|
+
customKeyBackground?: CustomKeyBackground;
|
|
26
|
+
customKeyState?: CustomKeyState;
|
|
27
|
+
onCustomKeyEvent?: () => void;
|
|
28
|
+
style?: StyleProp<TextStyle>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type CustomKeyBackground = 'primary' | 'default' | string;
|
|
32
|
+
|
|
33
|
+
export enum CustomKeyState {
|
|
34
|
+
Default = 'default',
|
|
35
|
+
Disable = 'disable',
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export enum Mode {
|
|
39
|
+
NumDefault = 'NumDefault',
|
|
40
|
+
NumWithCTA = 'NumWithCTA',
|
|
19
41
|
}
|
|
20
42
|
|
|
21
43
|
export type InputCalculatorRef = {
|
|
@@ -23,49 +45,100 @@ export type InputCalculatorRef = {
|
|
|
23
45
|
blur: () => void;
|
|
24
46
|
};
|
|
25
47
|
|
|
26
|
-
const
|
|
27
|
-
(
|
|
48
|
+
const omitUndefined = <T extends object>(obj: T): T =>
|
|
49
|
+
Object.fromEntries(
|
|
50
|
+
Object.entries(obj).filter(([, v]) => v !== undefined),
|
|
51
|
+
) as T;
|
|
52
|
+
|
|
53
|
+
function isEmpty(obj: object | undefined | null) {
|
|
54
|
+
return !obj || Object.keys(obj).length === 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function styleToTextAttributes(
|
|
58
|
+
style?: StyleProp<TextStyle>,
|
|
59
|
+
): Readonly<TextAttributes> {
|
|
60
|
+
const s = StyleSheet.flatten(style) ?? {};
|
|
61
|
+
const attrs: TextAttributes = {
|
|
62
|
+
fontSize: s.fontSize ?? undefined,
|
|
63
|
+
fontWeight: (s.fontWeight as TextAttributes['fontWeight']) ?? undefined,
|
|
64
|
+
};
|
|
65
|
+
return Object.freeze(omitUndefined(attrs));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const InputCalculator = React.forwardRef<
|
|
69
|
+
InputCalculatorRef,
|
|
70
|
+
InputCalculatorProps
|
|
71
|
+
>(
|
|
72
|
+
(
|
|
73
|
+
{
|
|
74
|
+
customKeyBackground = 'default',
|
|
75
|
+
mode = Mode.NumDefault,
|
|
76
|
+
customKeyText,
|
|
77
|
+
onKeyPress,
|
|
78
|
+
customKeyState = CustomKeyState.Default,
|
|
79
|
+
onCustomKeyEvent,
|
|
80
|
+
style,
|
|
81
|
+
...props
|
|
82
|
+
},
|
|
83
|
+
ref,
|
|
84
|
+
) => {
|
|
85
|
+
const { theme } = useContext(ApplicationContext);
|
|
28
86
|
const nativeRef = React.useRef<any>(null);
|
|
29
87
|
|
|
30
|
-
const _onChange = (
|
|
31
|
-
event: NativeSyntheticEvent<TextInputChangeEventData>
|
|
32
|
-
) => {
|
|
88
|
+
const _onChange = (event: NativeSyntheticEvent<any>) => {
|
|
33
89
|
const currentText = event.nativeEvent.text;
|
|
34
|
-
props.onChange
|
|
35
|
-
props.onChangeText
|
|
90
|
+
props.onChange?.(event);
|
|
91
|
+
props.onChangeText?.(currentText);
|
|
36
92
|
};
|
|
37
93
|
|
|
38
94
|
const text = props.text ?? props.defaultValue ?? '';
|
|
95
|
+
let keyBackground = Colors.black_06;
|
|
96
|
+
let textKeyColor = Colors.black_20;
|
|
97
|
+
|
|
98
|
+
if (mode === Mode.NumWithCTA) {
|
|
99
|
+
if (customKeyBackground === 'primary') {
|
|
100
|
+
keyBackground = theme.colors.primary;
|
|
101
|
+
textKeyColor = Colors.black_01;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (customKeyState === CustomKeyState.Disable) {
|
|
105
|
+
keyBackground = theme.colors.background.disable;
|
|
106
|
+
textKeyColor = Colors.black_01;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
39
109
|
|
|
40
110
|
React.useImperativeHandle(ref, () => ({
|
|
41
111
|
focus() {
|
|
42
|
-
|
|
43
|
-
if (!node) return;
|
|
44
|
-
const config = UIManager.getViewManagerConfig(NAME);
|
|
45
|
-
if (config?.Commands?.focus != null) {
|
|
46
|
-
UIManager.dispatchViewManagerCommand(node, config.Commands.focus, []);
|
|
47
|
-
}
|
|
112
|
+
if (nativeRef.current) Commands.focus(nativeRef.current);
|
|
48
113
|
},
|
|
49
114
|
blur() {
|
|
50
|
-
|
|
51
|
-
if (!node) return;
|
|
52
|
-
const config = UIManager.getViewManagerConfig(NAME);
|
|
53
|
-
if (config?.Commands?.blur != null) {
|
|
54
|
-
UIManager.dispatchViewManagerCommand(node, config.Commands.blur, []);
|
|
55
|
-
}
|
|
115
|
+
if (nativeRef.current) Commands.blur(nativeRef.current);
|
|
56
116
|
},
|
|
57
117
|
}));
|
|
58
118
|
|
|
119
|
+
const derivedTA = React.useMemo(
|
|
120
|
+
() => styleToTextAttributes(style),
|
|
121
|
+
[style],
|
|
122
|
+
);
|
|
123
|
+
|
|
59
124
|
return (
|
|
60
125
|
<NativeInput
|
|
61
126
|
{...props}
|
|
127
|
+
style={style}
|
|
128
|
+
textAttributes={isEmpty(derivedTA) ? undefined : derivedTA}
|
|
62
129
|
ref={nativeRef}
|
|
63
130
|
onChange={_onChange}
|
|
131
|
+
onKeyPress={onKeyPress}
|
|
64
132
|
value={text}
|
|
65
|
-
|
|
133
|
+
mode={mode}
|
|
134
|
+
customKeyText={customKeyText}
|
|
135
|
+
customKeyBackground={keyBackground}
|
|
136
|
+
customKeyTextColor={textKeyColor}
|
|
137
|
+
customKeyState={customKeyState}
|
|
138
|
+
onCustomKeyEvent={onCustomKeyEvent}
|
|
66
139
|
/>
|
|
67
140
|
);
|
|
68
|
-
}
|
|
141
|
+
},
|
|
69
142
|
);
|
|
70
143
|
|
|
71
144
|
export default InputCalculator;
|
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
package com.calculatorkeyboard
|
|
2
|
-
|
|
3
|
-
import android.annotation.SuppressLint
|
|
4
|
-
import android.app.Activity
|
|
5
|
-
import android.graphics.PixelFormat
|
|
6
|
-
import android.graphics.drawable.ColorDrawable
|
|
7
|
-
import android.view.Gravity
|
|
8
|
-
import android.view.KeyEvent
|
|
9
|
-
import android.view.View
|
|
10
|
-
import android.view.WindowInsets
|
|
11
|
-
import android.view.WindowManager
|
|
12
|
-
import android.widget.PopupWindow
|
|
13
|
-
import androidx.constraintlayout.widget.ConstraintLayout
|
|
14
|
-
import androidx.core.graphics.toColorInt
|
|
15
|
-
import com.facebook.react.bridge.ReadableArray
|
|
16
|
-
import com.facebook.react.bridge.UiThreadUtil
|
|
17
|
-
import com.facebook.react.uimanager.ThemedReactContext
|
|
18
|
-
import com.facebook.react.uimanager.annotations.ReactProp
|
|
19
|
-
import com.facebook.react.views.textinput.ReactEditText
|
|
20
|
-
import com.facebook.react.views.textinput.ReactTextInputManager
|
|
21
|
-
import androidx.core.graphics.drawable.toDrawable
|
|
22
|
-
import androidx.core.view.ViewCompat
|
|
23
|
-
import androidx.core.view.WindowInsetsCompat
|
|
24
|
-
import com.facebook.react.uimanager.PixelUtil.dpToPx
|
|
25
|
-
|
|
26
|
-
class RCTInputCalculator : ReactTextInputManager() {
|
|
27
|
-
|
|
28
|
-
private var keyboardView: CustomKeyboardView? = null
|
|
29
|
-
private var calculatorHeight: Int = 290.dpToPx().toInt()
|
|
30
|
-
private var popup: PopupWindow? = null
|
|
31
|
-
private val animationDuration = 250L
|
|
32
|
-
|
|
33
|
-
private lateinit var editText: CalculatorEditText
|
|
34
|
-
|
|
35
|
-
override fun getName() = REACT_CLASS
|
|
36
|
-
|
|
37
|
-
companion object {
|
|
38
|
-
const val REACT_CLASS = "RCTInputCalculator"
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
@ReactProp(name = "value")
|
|
42
|
-
fun setValue(view: ReactEditText, value: String?) {
|
|
43
|
-
UiThreadUtil.runOnUiThread {
|
|
44
|
-
val e = view.editableText ?: run { view.setText(value ?: ""); return@runOnUiThread }
|
|
45
|
-
val newText = value ?: ""
|
|
46
|
-
if (e.toString() == newText) return@runOnUiThread
|
|
47
|
-
|
|
48
|
-
val wasFocused = view.hasFocus()
|
|
49
|
-
val atEnd = wasFocused && view.selectionStart == e.length && view.selectionEnd == e.length
|
|
50
|
-
|
|
51
|
-
e.replace(0, e.length, newText)
|
|
52
|
-
|
|
53
|
-
if (!wasFocused || atEnd) {
|
|
54
|
-
view.setSelection(newText.length)
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
@ReactProp(name = "keyboardColor")
|
|
60
|
-
fun setKeyboardColor(view: ReactEditText, color: String) {
|
|
61
|
-
keyboardView?.updateButtonColors(color.toColorInt())
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
@SuppressLint("ClickableViewAccessibility")
|
|
65
|
-
override fun createViewInstance(context: ThemedReactContext): ReactEditText {
|
|
66
|
-
editText = CalculatorEditText(context).apply {
|
|
67
|
-
showSoftInputOnFocus = false
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
keyboardView = CustomKeyboardView(context, editText).apply {
|
|
71
|
-
setBackgroundColor("#f2f2f6".toColorInt())
|
|
72
|
-
elevation = 24f
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
editText.onFocusListener = object : CalculatorEditText.OnFocusChangeListener {
|
|
76
|
-
override fun onFocusChange(view: CalculatorEditText, hasFocus: Boolean) {
|
|
77
|
-
UiThreadUtil.runOnUiThread {
|
|
78
|
-
if (hasFocus) {
|
|
79
|
-
showKeyboardPopup(view)
|
|
80
|
-
} else {
|
|
81
|
-
hideKeyboardPopup()
|
|
82
|
-
}
|
|
83
|
-
view.setOnKeyListener { v, keyCode, _ ->
|
|
84
|
-
if (keyCode == KeyEvent.KEYCODE_BACK && hasFocus) {
|
|
85
|
-
v.clearFocus()
|
|
86
|
-
true
|
|
87
|
-
} else false
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return editText
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
override fun getCommandsMap(): Map<String, Int> {
|
|
97
|
-
return mapOf(
|
|
98
|
-
"blur" to 1,
|
|
99
|
-
"focus" to 2
|
|
100
|
-
)
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
override fun receiveCommand(reactEditText: ReactEditText, commandId: Int, args: ReadableArray?) {
|
|
104
|
-
when (commandId) {
|
|
105
|
-
1 -> blur()
|
|
106
|
-
2 -> focus()
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
private fun ensurePopup() {
|
|
111
|
-
if (popup != null) return
|
|
112
|
-
val content = keyboardView ?: return
|
|
113
|
-
|
|
114
|
-
popup = PopupWindow(
|
|
115
|
-
content,
|
|
116
|
-
WindowManager.LayoutParams.MATCH_PARENT,
|
|
117
|
-
calculatorHeight + bottomInsetFrom(editText.rootView),
|
|
118
|
-
false
|
|
119
|
-
).apply {
|
|
120
|
-
setBackgroundDrawable(android.graphics.Color.TRANSPARENT.toDrawable())
|
|
121
|
-
isOutsideTouchable = false
|
|
122
|
-
isClippingEnabled = false
|
|
123
|
-
softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING
|
|
124
|
-
inputMethodMode = PopupWindow.INPUT_METHOD_NOT_NEEDED
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
private fun bottomInsetFrom(view: View): Int {
|
|
129
|
-
val insets = ViewCompat.getRootWindowInsets(view) ?: return 0
|
|
130
|
-
val mask = WindowInsetsCompat.Type.navigationBars() or WindowInsetsCompat.Type.displayCutout()
|
|
131
|
-
return insets.getInsets(mask).bottom
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
private fun showKeyboardPopup(anchor: View) {
|
|
135
|
-
ensurePopup()
|
|
136
|
-
val p = popup ?: return
|
|
137
|
-
if (p.isShowing) return
|
|
138
|
-
|
|
139
|
-
val root = keyboardView ?: return
|
|
140
|
-
|
|
141
|
-
root.translationY = calculatorHeight.toFloat()
|
|
142
|
-
p.showAtLocation(anchor.rootView, Gravity.BOTTOM or Gravity.START, 0, 0)
|
|
143
|
-
|
|
144
|
-
root.animate()
|
|
145
|
-
?.translationY(0f)
|
|
146
|
-
?.setDuration(animationDuration)
|
|
147
|
-
?.start()
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
private fun hideKeyboardPopup() {
|
|
151
|
-
val p = popup ?: return
|
|
152
|
-
if (!p.isShowing) return
|
|
153
|
-
val root = keyboardView ?: return
|
|
154
|
-
|
|
155
|
-
root.animate()
|
|
156
|
-
.translationY(calculatorHeight.toFloat())
|
|
157
|
-
.setDuration(animationDuration)
|
|
158
|
-
.withEndAction {
|
|
159
|
-
try {
|
|
160
|
-
if (p.isShowing) p.dismiss()
|
|
161
|
-
} catch (_: Throwable) { }
|
|
162
|
-
}
|
|
163
|
-
.start()
|
|
164
|
-
|
|
165
|
-
popup = null
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
private fun focus() {
|
|
169
|
-
UiThreadUtil.runOnUiThread {
|
|
170
|
-
if (!editText.isFocused) editText.requestFocus()
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
private fun blur() {
|
|
175
|
-
UiThreadUtil.runOnUiThread {
|
|
176
|
-
if (editText.isFocused) editText.clearFocus()
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|