react-native-unified-action-sheet 0.1.0
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/CHANGELOG.md +41 -0
- package/LICENSE +20 -0
- package/README.md +167 -0
- package/android/build.gradle +51 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/com/unifiedactionsheet/ActionSheetOptions.kt +134 -0
- package/android/src/main/java/com/unifiedactionsheet/SheetContentBuilder.kt +159 -0
- package/android/src/main/java/com/unifiedactionsheet/SheetPresenters.kt +214 -0
- package/android/src/main/java/com/unifiedactionsheet/SheetTheming.kt +56 -0
- package/android/src/main/java/com/unifiedactionsheet/UnifiedActionSheetModule.kt +126 -0
- package/android/src/main/java/com/unifiedactionsheet/UnifiedActionSheetPackage.kt +30 -0
- package/ios/UnifiedActionSheet.h +5 -0
- package/ios/UnifiedActionSheet.mm +96 -0
- package/ios/UnifiedActionSheetImpl.swift +240 -0
- package/jest/index.d.ts +12 -0
- package/jest/index.js +46 -0
- package/lib/commonjs/NativeUnifiedActionSheet.js +9 -0
- package/lib/commonjs/NativeUnifiedActionSheet.js.map +1 -0
- package/lib/commonjs/action-sheet-options.interface.js +2 -0
- package/lib/commonjs/action-sheet-options.interface.js.map +1 -0
- package/lib/commonjs/index.js +104 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/module/NativeUnifiedActionSheet.js +5 -0
- package/lib/module/NativeUnifiedActionSheet.js.map +1 -0
- package/lib/module/action-sheet-options.interface.js +2 -0
- package/lib/module/action-sheet-options.interface.js.map +1 -0
- package/lib/module/index.js +97 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/typescript/commonjs/package.json +1 -0
- package/lib/typescript/commonjs/src/NativeUnifiedActionSheet.d.ts +29 -0
- package/lib/typescript/commonjs/src/NativeUnifiedActionSheet.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/action-sheet-options.interface.d.ts +29 -0
- package/lib/typescript/commonjs/src/action-sheet-options.interface.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/index.d.ts +6 -0
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -0
- package/lib/typescript/module/package.json +1 -0
- package/lib/typescript/module/src/NativeUnifiedActionSheet.d.ts +29 -0
- package/lib/typescript/module/src/NativeUnifiedActionSheet.d.ts.map +1 -0
- package/lib/typescript/module/src/action-sheet-options.interface.d.ts +29 -0
- package/lib/typescript/module/src/action-sheet-options.interface.d.ts.map +1 -0
- package/lib/typescript/module/src/index.d.ts +6 -0
- package/lib/typescript/module/src/index.d.ts.map +1 -0
- package/package.json +155 -0
- package/react-native-unified-action-sheet.podspec +23 -0
- package/src/NativeUnifiedActionSheet.ts +29 -0
- package/src/action-sheet-options.interface.ts +43 -0
- package/src/index.tsx +131 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type TurboModule } from 'react-native';
|
|
2
|
+
export interface Spec extends TurboModule {
|
|
3
|
+
showActionSheetWithOptions(options: {
|
|
4
|
+
options: string[];
|
|
5
|
+
cancelButtonIndex?: number;
|
|
6
|
+
destructiveButtonIndices?: number[];
|
|
7
|
+
title?: string;
|
|
8
|
+
message?: string;
|
|
9
|
+
tintColor?: string;
|
|
10
|
+
cancelButtonTintColor?: string;
|
|
11
|
+
destructiveColor?: string;
|
|
12
|
+
buttonTextAlignment?: string;
|
|
13
|
+
disabledButtonIndices?: number[];
|
|
14
|
+
userInterfaceStyle?: string;
|
|
15
|
+
presentationStyle?: string;
|
|
16
|
+
anchorAlignment?: string;
|
|
17
|
+
anchorRect?: {
|
|
18
|
+
x: number;
|
|
19
|
+
y: number;
|
|
20
|
+
width: number;
|
|
21
|
+
height: number;
|
|
22
|
+
};
|
|
23
|
+
}): Promise<number>;
|
|
24
|
+
dismissActionSheet(): void;
|
|
25
|
+
dismissAllActionSheets(): void;
|
|
26
|
+
}
|
|
27
|
+
declare const _default: Spec;
|
|
28
|
+
export default _default;
|
|
29
|
+
//# sourceMappingURL=NativeUnifiedActionSheet.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NativeUnifiedActionSheet.d.ts","sourceRoot":"","sources":["../../../../src/NativeUnifiedActionSheet.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAErE,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,0BAA0B,CAAC,OAAO,EAAE;QAClC,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,wBAAwB,CAAC,EAAE,MAAM,EAAE,CAAC;QACpC,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,qBAAqB,CAAC,EAAE,MAAM,CAAC;QAC/B,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,mBAAmB,CAAC,EAAE,MAAM,CAAC;QAC7B,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;QACjC,kBAAkB,CAAC,EAAE,MAAM,CAAC;QAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,UAAU,CAAC,EAAE;YACX,CAAC,EAAE,MAAM,CAAC;YACV,CAAC,EAAE,MAAM,CAAC;YACV,KAAK,EAAE,MAAM,CAAC;YACd,MAAM,EAAE,MAAM,CAAC;SAChB,CAAC;KACH,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACpB,kBAAkB,IAAI,IAAI,CAAC;IAC3B,sBAAsB,IAAI,IAAI,CAAC;CAChC;;AAED,wBAA4E"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export interface ActionSheetButtonInterface {
|
|
2
|
+
label: string;
|
|
3
|
+
style?: 'cancel' | 'destructive';
|
|
4
|
+
disabled?: boolean;
|
|
5
|
+
onPress?: () => void;
|
|
6
|
+
}
|
|
7
|
+
export interface ActionSheetAnchorInterface {
|
|
8
|
+
measureInWindow: (callback: (x: number, y: number, width: number, height: number) => void) => void;
|
|
9
|
+
}
|
|
10
|
+
export interface ActionSheetCommonOptionsInterface {
|
|
11
|
+
options: ActionSheetButtonInterface[];
|
|
12
|
+
title?: string;
|
|
13
|
+
message?: string;
|
|
14
|
+
tintColor?: string;
|
|
15
|
+
cancelButtonTintColor?: string;
|
|
16
|
+
userInterfaceStyle?: 'light' | 'dark';
|
|
17
|
+
anchor?: ActionSheetAnchorInterface | {
|
|
18
|
+
current: ActionSheetAnchorInterface | null;
|
|
19
|
+
} | null;
|
|
20
|
+
destructiveColor?: string;
|
|
21
|
+
presentationStyle?: 'centered' | 'anchored';
|
|
22
|
+
}
|
|
23
|
+
export interface ActionSheetAndroidOptionsInterface {
|
|
24
|
+
buttonTextAlignment?: 'start' | 'center';
|
|
25
|
+
anchorAlignment?: 'start' | 'center';
|
|
26
|
+
}
|
|
27
|
+
export interface ActionSheetOptionsInterface extends ActionSheetCommonOptionsInterface, ActionSheetAndroidOptionsInterface {
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=action-sheet-options.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action-sheet-options.interface.d.ts","sourceRoot":"","sources":["../../../../src/action-sheet-options.interface.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,QAAQ,GAAG,aAAa,CAAC;IACjC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAGnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAID,MAAM,WAAW,0BAA0B;IACzC,eAAe,EAAE,CACf,QAAQ,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,KACpE,IAAI,CAAC;CACX;AAED,MAAM,WAAW,iCAAiC;IAChD,OAAO,EAAE,0BAA0B,EAAE,CAAC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,kBAAkB,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACtC,MAAM,CAAC,EACH,0BAA0B,GAC1B;QAAE,OAAO,EAAE,0BAA0B,GAAG,IAAI,CAAA;KAAE,GAC9C,IAAI,CAAC;IACT,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC;CAC7C;AAED,MAAM,WAAW,kCAAkC;IACjD,mBAAmB,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IACzC,eAAe,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;CACtC;AAED,MAAM,WAAW,2BACf,SACE,iCAAiC,EACjC,kCAAkC;CAAG"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ActionSheetOptionsInterface } from './action-sheet-options.interface.js';
|
|
2
|
+
export type { ActionSheetAnchorInterface, ActionSheetButtonInterface, ActionSheetCommonOptionsInterface, ActionSheetAndroidOptionsInterface, ActionSheetOptionsInterface, } from './action-sheet-options.interface.js';
|
|
3
|
+
export declare const showActionSheetWithOptions: (options: ActionSheetOptionsInterface) => Promise<number | undefined>;
|
|
4
|
+
export declare const dismissActionSheet: () => void;
|
|
5
|
+
export declare const dismissAllActionSheets: () => void;
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/index.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,qCAAkC,CAAC;AAEpF,YAAY,EACV,0BAA0B,EAC1B,0BAA0B,EAC1B,iCAAiC,EACjC,kCAAkC,EAClC,2BAA2B,GAC5B,MAAM,qCAAkC,CAAC;AAsF1C,eAAO,MAAM,0BAA0B,GACrC,SAAS,2BAA2B,KACnC,OAAO,CAAC,MAAM,GAAG,SAAS,CAiB5B,CAAC;AAEF,eAAO,MAAM,kBAAkB,QAAO,IAIrC,CAAC;AAIF,eAAO,MAAM,sBAAsB,QAAO,IAIzC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "react-native-unified-action-sheet",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Unified action sheet for React Native: a native UIAlertController on iOS, a native AppCompatDialog on Android",
|
|
5
|
+
"main": "./lib/commonjs/index.js",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"types": "./lib/typescript/commonjs/src/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"react-native-unified-action-sheet-source": "./src/index.tsx",
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./lib/typescript/module/src/index.d.ts",
|
|
13
|
+
"default": "./lib/module/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./lib/typescript/commonjs/src/index.d.ts",
|
|
17
|
+
"default": "./lib/commonjs/index.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"./package.json": "./package.json",
|
|
21
|
+
"./jest": {
|
|
22
|
+
"types": "./jest/index.d.ts",
|
|
23
|
+
"default": "./jest/index.js"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"src",
|
|
28
|
+
"lib",
|
|
29
|
+
"jest",
|
|
30
|
+
"android",
|
|
31
|
+
"ios",
|
|
32
|
+
"*.podspec",
|
|
33
|
+
"CHANGELOG.md",
|
|
34
|
+
"!android/build",
|
|
35
|
+
"!android/gradle",
|
|
36
|
+
"!android/gradlew",
|
|
37
|
+
"!android/gradlew.bat",
|
|
38
|
+
"!android/local.properties",
|
|
39
|
+
"!**/__tests__",
|
|
40
|
+
"!**/__fixtures__",
|
|
41
|
+
"!**/__mocks__",
|
|
42
|
+
"!**/.*"
|
|
43
|
+
],
|
|
44
|
+
"scripts": {
|
|
45
|
+
"example": "yarn workspace react-native-unified-action-sheet-example",
|
|
46
|
+
"clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib",
|
|
47
|
+
"prepare": "bob build",
|
|
48
|
+
"typecheck": "tsc",
|
|
49
|
+
"test": "jest",
|
|
50
|
+
"lint": "eslint \"**/*.{js,ts,tsx}\""
|
|
51
|
+
},
|
|
52
|
+
"keywords": [
|
|
53
|
+
"react-native",
|
|
54
|
+
"ios",
|
|
55
|
+
"android",
|
|
56
|
+
"action-sheet",
|
|
57
|
+
"actionsheet",
|
|
58
|
+
"action-sheet-ios",
|
|
59
|
+
"turbomodule"
|
|
60
|
+
],
|
|
61
|
+
"repository": {
|
|
62
|
+
"type": "git",
|
|
63
|
+
"url": "git+https://github.com/galikvalkin/react-native-unified-action-sheet.git"
|
|
64
|
+
},
|
|
65
|
+
"author": "Valentyn Halkin <galikvalkin@gmail.com> (https://github.com/galikvalkin)",
|
|
66
|
+
"license": "MIT",
|
|
67
|
+
"engines": {
|
|
68
|
+
"node": ">= 18"
|
|
69
|
+
},
|
|
70
|
+
"bugs": {
|
|
71
|
+
"url": "https://github.com/galikvalkin/react-native-unified-action-sheet/issues"
|
|
72
|
+
},
|
|
73
|
+
"homepage": "https://github.com/galikvalkin/react-native-unified-action-sheet#readme",
|
|
74
|
+
"publishConfig": {
|
|
75
|
+
"registry": "https://registry.npmjs.org/"
|
|
76
|
+
},
|
|
77
|
+
"devDependencies": {
|
|
78
|
+
"@eslint/compat": "^2.1.0",
|
|
79
|
+
"@eslint/eslintrc": "^3.3.5",
|
|
80
|
+
"@eslint/js": "^10.0.1",
|
|
81
|
+
"@jest/globals": "^30.4.1",
|
|
82
|
+
"@react-native/babel-preset": "0.85.0",
|
|
83
|
+
"@react-native/eslint-config": "0.85.0",
|
|
84
|
+
"@types/react": "^19.2.0",
|
|
85
|
+
"del-cli": "^7.0.0",
|
|
86
|
+
"eslint": "^9.39.4",
|
|
87
|
+
"eslint-config-prettier": "^10.1.8",
|
|
88
|
+
"eslint-plugin-ft-flow": "^3.0.11",
|
|
89
|
+
"eslint-plugin-prettier": "^5.5.6",
|
|
90
|
+
"jest": "^30.4.2",
|
|
91
|
+
"prettier": "^3.8.3",
|
|
92
|
+
"react": "19.2.3",
|
|
93
|
+
"react-native": "0.85.0",
|
|
94
|
+
"react-native-builder-bob": "^0.43.0",
|
|
95
|
+
"react-native-modal": "^14.0.0-rc.1",
|
|
96
|
+
"turbo": "^2.9.16",
|
|
97
|
+
"typescript": "^6.0.3"
|
|
98
|
+
},
|
|
99
|
+
"peerDependencies": {
|
|
100
|
+
"react": "*",
|
|
101
|
+
"react-native": ">=0.81.0"
|
|
102
|
+
},
|
|
103
|
+
"workspaces": [
|
|
104
|
+
"example"
|
|
105
|
+
],
|
|
106
|
+
"packageManager": "yarn@4.11.0",
|
|
107
|
+
"react-native-builder-bob": {
|
|
108
|
+
"source": "src",
|
|
109
|
+
"output": "lib",
|
|
110
|
+
"targets": [
|
|
111
|
+
[
|
|
112
|
+
"commonjs",
|
|
113
|
+
{
|
|
114
|
+
"esm": true
|
|
115
|
+
}
|
|
116
|
+
],
|
|
117
|
+
[
|
|
118
|
+
"module",
|
|
119
|
+
{
|
|
120
|
+
"esm": true
|
|
121
|
+
}
|
|
122
|
+
],
|
|
123
|
+
[
|
|
124
|
+
"typescript",
|
|
125
|
+
{
|
|
126
|
+
"project": "tsconfig.build.json"
|
|
127
|
+
}
|
|
128
|
+
]
|
|
129
|
+
]
|
|
130
|
+
},
|
|
131
|
+
"codegenConfig": {
|
|
132
|
+
"name": "UnifiedActionSheetSpec",
|
|
133
|
+
"type": "modules",
|
|
134
|
+
"jsSrcsDir": "src",
|
|
135
|
+
"android": {
|
|
136
|
+
"javaPackageName": "com.unifiedactionsheet"
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
"prettier": {
|
|
140
|
+
"quoteProps": "consistent",
|
|
141
|
+
"singleQuote": true,
|
|
142
|
+
"tabWidth": 2,
|
|
143
|
+
"trailingComma": "es5",
|
|
144
|
+
"useTabs": false
|
|
145
|
+
},
|
|
146
|
+
"create-react-native-library": {
|
|
147
|
+
"type": "turbo-module",
|
|
148
|
+
"languages": "kotlin-objc",
|
|
149
|
+
"tools": [
|
|
150
|
+
"eslint"
|
|
151
|
+
],
|
|
152
|
+
"version": "0.63.0"
|
|
153
|
+
},
|
|
154
|
+
"module": "./lib/module/index.js"
|
|
155
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = "react-native-unified-action-sheet"
|
|
7
|
+
s.version = package["version"]
|
|
8
|
+
s.summary = package["description"]
|
|
9
|
+
s.description = <<~DESC
|
|
10
|
+
One action-sheet API for both platforms, presented natively:
|
|
11
|
+
a UIAlertController on iOS and an AppCompatDialog on Android.
|
|
12
|
+
DESC
|
|
13
|
+
s.homepage = package["homepage"]
|
|
14
|
+
s.license = package["license"]
|
|
15
|
+
s.authors = package["author"]
|
|
16
|
+
|
|
17
|
+
s.platforms = { :ios => min_ios_version_supported }
|
|
18
|
+
s.source = { :git => "https://github.com/galikvalkin/react-native-unified-action-sheet.git", :tag => "v#{s.version}" }
|
|
19
|
+
|
|
20
|
+
s.source_files = "ios/**/*.{h,m,mm,swift}"
|
|
21
|
+
|
|
22
|
+
install_modules_dependencies(s)
|
|
23
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { TurboModuleRegistry, type TurboModule } from 'react-native';
|
|
2
|
+
|
|
3
|
+
export interface Spec extends TurboModule {
|
|
4
|
+
showActionSheetWithOptions(options: {
|
|
5
|
+
options: string[];
|
|
6
|
+
cancelButtonIndex?: number;
|
|
7
|
+
destructiveButtonIndices?: number[];
|
|
8
|
+
title?: string;
|
|
9
|
+
message?: string;
|
|
10
|
+
tintColor?: string;
|
|
11
|
+
cancelButtonTintColor?: string;
|
|
12
|
+
destructiveColor?: string;
|
|
13
|
+
buttonTextAlignment?: string;
|
|
14
|
+
disabledButtonIndices?: number[];
|
|
15
|
+
userInterfaceStyle?: string;
|
|
16
|
+
presentationStyle?: string;
|
|
17
|
+
anchorAlignment?: string;
|
|
18
|
+
anchorRect?: {
|
|
19
|
+
x: number;
|
|
20
|
+
y: number;
|
|
21
|
+
width: number;
|
|
22
|
+
height: number;
|
|
23
|
+
};
|
|
24
|
+
}): Promise<number>;
|
|
25
|
+
dismissActionSheet(): void;
|
|
26
|
+
dismissAllActionSheets(): void;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export default TurboModuleRegistry.getEnforcing<Spec>('UnifiedActionSheet');
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/// One button. `style` mirrors React Native's own Alert API and the native
|
|
2
|
+
/// button roles, which are mutually exclusive; `disabled` is independent of it.
|
|
3
|
+
export interface ActionSheetButtonInterface {
|
|
4
|
+
label: string;
|
|
5
|
+
style?: 'cancel' | 'destructive';
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
/// Runs when this button resolves the sheet, so callers need not match on the
|
|
8
|
+
/// index. A dismissal that resolves the cancel button counts as pressing it.
|
|
9
|
+
onPress?: () => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/// Anything measurable — every React Native host component ref has this method,
|
|
13
|
+
/// so a `useRef` on a View, Pressable or Touchable satisfies it.
|
|
14
|
+
export interface ActionSheetAnchorInterface {
|
|
15
|
+
measureInWindow: (
|
|
16
|
+
callback: (x: number, y: number, width: number, height: number) => void
|
|
17
|
+
) => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ActionSheetCommonOptionsInterface {
|
|
21
|
+
options: ActionSheetButtonInterface[];
|
|
22
|
+
title?: string;
|
|
23
|
+
message?: string;
|
|
24
|
+
tintColor?: string;
|
|
25
|
+
cancelButtonTintColor?: string;
|
|
26
|
+
userInterfaceStyle?: 'light' | 'dark';
|
|
27
|
+
anchor?:
|
|
28
|
+
| ActionSheetAnchorInterface
|
|
29
|
+
| { current: ActionSheetAnchorInterface | null }
|
|
30
|
+
| null;
|
|
31
|
+
destructiveColor?: string;
|
|
32
|
+
presentationStyle?: 'centered' | 'anchored';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface ActionSheetAndroidOptionsInterface {
|
|
36
|
+
buttonTextAlignment?: 'start' | 'center';
|
|
37
|
+
anchorAlignment?: 'start' | 'center';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface ActionSheetOptionsInterface
|
|
41
|
+
extends
|
|
42
|
+
ActionSheetCommonOptionsInterface,
|
|
43
|
+
ActionSheetAndroidOptionsInterface {}
|
package/src/index.tsx
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { Platform } from 'react-native';
|
|
2
|
+
|
|
3
|
+
import type { Spec } from './NativeUnifiedActionSheet';
|
|
4
|
+
import type { ActionSheetOptionsInterface } from './action-sheet-options.interface';
|
|
5
|
+
|
|
6
|
+
export type {
|
|
7
|
+
ActionSheetAnchorInterface,
|
|
8
|
+
ActionSheetButtonInterface,
|
|
9
|
+
ActionSheetCommonOptionsInterface,
|
|
10
|
+
ActionSheetAndroidOptionsInterface,
|
|
11
|
+
ActionSheetOptionsInterface,
|
|
12
|
+
} from './action-sheet-options.interface';
|
|
13
|
+
|
|
14
|
+
const DISMISSED_BY_API = -2;
|
|
15
|
+
|
|
16
|
+
/// The native wire format is index-based; the public API is not. Nothing below
|
|
17
|
+
/// index.tsx knows buttons are described as objects.
|
|
18
|
+
type WireOptions = Omit<ActionSheetOptionsInterface, 'options' | 'anchor'> & {
|
|
19
|
+
options: string[];
|
|
20
|
+
cancelButtonIndex?: number;
|
|
21
|
+
destructiveButtonIndices?: number[];
|
|
22
|
+
disabledButtonIndices?: number[];
|
|
23
|
+
anchorRect?: { x: number; y: number; width: number; height: number };
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const nativeModule = (): Spec =>
|
|
27
|
+
require('./NativeUnifiedActionSheet').default as Spec;
|
|
28
|
+
|
|
29
|
+
/// Flattens the buttons into the labels and index sets the native side expects.
|
|
30
|
+
/// Only the first button styled 'cancel' counts, since there is one cancel row.
|
|
31
|
+
const toWireOptions = ({
|
|
32
|
+
options,
|
|
33
|
+
// Dropped deliberately: the anchor is a ref, and only its measured rect
|
|
34
|
+
// crosses the bridge. Omit<> would not strip it at runtime.
|
|
35
|
+
anchor: _anchor,
|
|
36
|
+
...rest
|
|
37
|
+
}: ActionSheetOptionsInterface): WireOptions => {
|
|
38
|
+
const labels: string[] = [];
|
|
39
|
+
const destructive: number[] = [];
|
|
40
|
+
const disabled: number[] = [];
|
|
41
|
+
let cancelButtonIndex: number | undefined;
|
|
42
|
+
|
|
43
|
+
options.forEach((button, index) => {
|
|
44
|
+
labels.push(button.label);
|
|
45
|
+
|
|
46
|
+
if (button.style === 'destructive') destructive.push(index);
|
|
47
|
+
if (button.style === 'cancel' && cancelButtonIndex == null) {
|
|
48
|
+
cancelButtonIndex = index;
|
|
49
|
+
}
|
|
50
|
+
if (button.disabled) disabled.push(index);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
...rest,
|
|
55
|
+
options: labels,
|
|
56
|
+
...(cancelButtonIndex == null ? {} : { cancelButtonIndex }),
|
|
57
|
+
...(destructive.length === 0
|
|
58
|
+
? {}
|
|
59
|
+
: { destructiveButtonIndices: destructive }),
|
|
60
|
+
...(disabled.length === 0 ? {} : { disabledButtonIndices: disabled }),
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const showWithNativeModule = (
|
|
65
|
+
options: WireOptions
|
|
66
|
+
): Promise<number | undefined> =>
|
|
67
|
+
nativeModule()
|
|
68
|
+
.showActionSheetWithOptions(options)
|
|
69
|
+
// A programmatic dismiss resolves with no index rather than a selection.
|
|
70
|
+
.then((buttonIndex) =>
|
|
71
|
+
buttonIndex === DISMISSED_BY_API ? undefined : buttonIndex
|
|
72
|
+
)
|
|
73
|
+
.catch(() => options.cancelButtonIndex ?? -1);
|
|
74
|
+
|
|
75
|
+
/// The anchor is measured in JS and sent across as a rect, so neither native
|
|
76
|
+
/// module has to resolve a view: a ref's own measureInWindow is the supported
|
|
77
|
+
/// way to do this on both architectures, unlike a react tag.
|
|
78
|
+
const withAnchorRect = (
|
|
79
|
+
wire: WireOptions,
|
|
80
|
+
anchor: ActionSheetOptionsInterface['anchor']
|
|
81
|
+
): Promise<WireOptions> => {
|
|
82
|
+
const target =
|
|
83
|
+
anchor && 'measureInWindow' in anchor ? anchor : (anchor?.current ?? null);
|
|
84
|
+
|
|
85
|
+
if (!target) return Promise.resolve(wire);
|
|
86
|
+
|
|
87
|
+
return new Promise((resolve) => {
|
|
88
|
+
target.measureInWindow((x, y, width, height) => {
|
|
89
|
+
const measured = typeof x === 'number' && typeof y === 'number';
|
|
90
|
+
|
|
91
|
+
resolve(
|
|
92
|
+
measured ? { ...wire, anchorRect: { x, y, width, height } } : wire
|
|
93
|
+
);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export const showActionSheetWithOptions = (
|
|
99
|
+
options: ActionSheetOptionsInterface
|
|
100
|
+
): Promise<number | undefined> => {
|
|
101
|
+
const wire = toWireOptions(options);
|
|
102
|
+
|
|
103
|
+
// -1 and undefined index nothing, so optional chaining covers both.
|
|
104
|
+
const press = (buttonIndex: number | undefined) => {
|
|
105
|
+
if (buttonIndex != null) options.options[buttonIndex]?.onPress?.();
|
|
106
|
+
|
|
107
|
+
return buttonIndex;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
if (Platform.OS !== 'ios' && Platform.OS !== 'android') {
|
|
111
|
+
return Promise.resolve(undefined);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return withAnchorRect(wire, options.anchor)
|
|
115
|
+
.then(showWithNativeModule)
|
|
116
|
+
.then(press);
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
export const dismissActionSheet = (): void => {
|
|
120
|
+
if (Platform.OS === 'ios' || Platform.OS === 'android') {
|
|
121
|
+
nativeModule().dismissActionSheet();
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
/// Closes every open sheet, not just the top-most one. Each resolves with no
|
|
126
|
+
/// index, exactly as dismissActionSheet() does.
|
|
127
|
+
export const dismissAllActionSheets = (): void => {
|
|
128
|
+
if (Platform.OS === 'ios' || Platform.OS === 'android') {
|
|
129
|
+
nativeModule().dismissAllActionSheets();
|
|
130
|
+
}
|
|
131
|
+
};
|