Skip to content
18 changes: 10 additions & 8 deletions action-sheet/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,18 +84,20 @@ to select.

#### ShowActionsResult

| Prop | Type | Description | Since |
| ----------- | ------------------- | -------------------------------------------- | ----- |
| **`index`** | <code>number</code> | The index of the clicked option (Zero-based) | 1.0.0 |
| Prop | Type | Description | Since |
| -------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- |
| **`index`** | <code>number</code> | The index of the clicked option (Zero-based), or -1 if the sheet was canceled. On iOS, if there is a button with <a href="#actionsheetbuttonstyle">ActionSheetButtonStyle.Cancel</a>, and user clicks outside the sheet, the index of the cancel option is returned | 1.0.0 |
| **`canceled`** | <code>boolean</code> | True if sheet was canceled by user; False otherwise | 6.1.0 |


#### ShowActionsOptions

| Prop | Type | Description | Since |
| ------------- | -------------------------------- | ------------------------------------------------------------------------ | ----- |
| **`title`** | <code>string</code> | The title of the Action Sheet. | 1.0.0 |
| **`message`** | <code>string</code> | A message to show under the title. This option is only supported on iOS. | 1.0.0 |
| **`options`** | <code>ActionSheetButton[]</code> | Options the user can choose from. | 1.0.0 |
| Prop | Type | Description | Since |
| ---------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- |
| **`title`** | <code>string</code> | The title of the Action Sheet. | 1.0.0 |
| **`message`** | <code>string</code> | A message to show under the title. This option is only supported on iOS. | 1.0.0 |
| **`options`** | <code>ActionSheetButton[]</code> | Options the user can choose from. | 1.0.0 |
| **`cancelable`** | <code>boolean</code> | If true, sheet is canceled when clicked outside; If false, it is not. By default, false. On iOS, the sheet is also cancelable if a button with <a href="#actionsheetbuttonstyle">ActionSheetButtonStyle.Cancel</a> is provided and cancelable is false. | 6.1.0 |


#### ActionSheetButton
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ public interface OnCancelListener {
@Override
public void onCancel(DialogInterface dialog) {
super.onCancel(dialog);
this.cancelListener.onCancel();
if (this.cancelListener != null) {
this.cancelListener.onCancel();
}
}

private String title;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public class ActionSheetPlugin extends Plugin {
@PluginMethod
public void showActions(final PluginCall call) {
String title = call.getString("title");
boolean cancelable = Boolean.TRUE.equals(call.getBoolean("cancelable", false));
JSArray options = call.getArray("options");
if (options == null) {
call.reject("Must supply options");
Expand All @@ -39,19 +40,23 @@ public void showActions(final PluginCall call) {
}
implementation.setTitle(title);
implementation.setOptions(actionOptions);
implementation.setCancelable(false);
implementation.setOnSelectedListener(
index -> {
JSObject ret = new JSObject();
ret.put("index", index);
call.resolve(ret);
implementation.dismiss();
}
);
implementation.setCancelable(cancelable);
if (cancelable) {
implementation.setOnCancelListener(() -> resolve(call, -1));
}
implementation.setOnSelectedListener(index -> resolve(call, index));
implementation.show(getActivity().getSupportFragmentManager(), "capacitorModalsActionSheet");
} catch (JSONException ex) {
Logger.error("JSON error processing an option for showActions", ex);
call.reject("JSON error processing an option for showActions", ex);
}
}

private void resolve(final PluginCall call, int selectedIndex) {
JSObject ret = new JSObject();
ret.put("index", selectedIndex);
ret.put("canceled", selectedIndex < 0);
call.resolve(ret);
implementation.dismiss();
}
}
38 changes: 34 additions & 4 deletions action-sheet/ios/Sources/ActionSheetPlugin/ActionSheetPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,28 @@ public class ActionSheetPlugin: CAPPlugin, CAPBridgedPlugin {
private let implementation = ActionSheet()

@objc func showActions(_ call: CAPPluginCall) {
let title = call.options["title"] as? String
let message = call.options["message"] as? String
let title = call.getString("title")
let message = call.getString("message")
let cancelable = call.getBool("cancelable", false)

let options = call.getArray("options", JSObject.self) ?? []
var alertActions = [UIAlertAction]()
var forceCancelableOnClickOutside = cancelable
for (index, option) in options.enumerated() {
let style = option["style"] as? String ?? "DEFAULT"
let title = option["title"] as? String ?? ""
var buttonStyle: UIAlertAction.Style = .default
if style == "DESTRUCTIVE" {
buttonStyle = .destructive
} else if style == "CANCEL" {
// if there's a cancel action, then it will already be cancelable when clicked outside
forceCancelableOnClickOutside = false
buttonStyle = .cancel
}
let action = UIAlertAction(title: title, style: buttonStyle, handler: { (_) -> Void in
call.resolve([
"index": index
"index": index,
"canceled": false
])
})
alertActions.append(action)
Expand All @@ -40,9 +45,34 @@ public class ActionSheetPlugin: CAPPlugin, CAPBridgedPlugin {
DispatchQueue.main.async { [weak self] in
if let alertController = self?.implementation.buildActionSheet(title: title, message: message, actions: alertActions) {
self?.setCenteredPopover(alertController)
self?.bridge?.viewController?.present(alertController, animated: true, completion: nil)
self?.bridge?.viewController?.present(alertController, animated: true) {
if (forceCancelableOnClickOutside) {
let gestureRecognizer = TapGestureRecognizerWithClosure {
alertController.dismiss(animated: true, completion: nil)
call.resolve([
"index": -1,
"canceled": true
])
}
let backroundView = alertController.view.superview?.subviews[0]
backroundView?.addGestureRecognizer(gestureRecognizer)
}
}
}
}
}

private final class TapGestureRecognizerWithClosure: UITapGestureRecognizer {
private let onTap: () -> Void

init(onTap: @escaping () -> Void) {
self.onTap = onTap
super.init(target: nil, action: nil)
self.addTarget(self, action: #selector(action))
}

@objc private func action() {
onTap()
}
}
}
19 changes: 18 additions & 1 deletion action-sheet/src/definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ export interface ShowActionsOptions {
* @since 1.0.0
*/
options: ActionSheetButton[];

/**
* If true, sheet is canceled when clicked outside; If false, it is not. By default, false.
*
* On iOS, the sheet is also cancelable if a button with ActionSheetButtonStyle.Cancel is provided and cancelable is false.
*
* @since 6.1.0
*/
cancelable?: boolean;
}

export enum ActionSheetButtonStyle {
Expand Down Expand Up @@ -76,11 +85,19 @@ export interface ActionSheetButton {

export interface ShowActionsResult {
/**
* The index of the clicked option (Zero-based)
* The index of the clicked option (Zero-based), or -1 if the sheet was canceled.
*
* On iOS, if there is a button with ActionSheetButtonStyle.Cancel, and user clicks outside the sheet, the index of the cancel option is returned
*
* @since 1.0.0
*/
index: number;
/**
* True if sheet was canceled by user; False otherwise
*
* @since 6.1.0
*/
canceled: boolean;
}

export interface ActionSheetPlugin {
Expand Down
11 changes: 10 additions & 1 deletion action-sheet/src/web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,30 @@

export class ActionSheetWeb extends WebPlugin implements ActionSheetPlugin {
async showActions(options: ShowActionsOptions): Promise<ShowActionsResult> {
return new Promise<ShowActionsResult>((resolve, _reject) => {

Check warning on line 11 in action-sheet/src/web.ts

View workflow job for this annotation

GitHub Actions / lint (action-sheet)

'_reject' is defined but never used
let actionSheet: any = document.querySelector('pwa-action-sheet');
if (!actionSheet) {
actionSheet = document.createElement('pwa-action-sheet');
document.body.appendChild(actionSheet);
}
actionSheet.header = options.title;
actionSheet.cancelable = false;
actionSheet.cancelable = options.cancelable;
actionSheet.options = options.options;
actionSheet.addEventListener('onSelection', async (e: any) => {
const selection = e.detail;
resolve({
index: selection,
canceled: false,
});
});
if (options.cancelable) {
actionSheet.addEventListener('onCanceled', async () => {
resolve({
index: -1,
canceled: true,
});
});
}
});
}
}
Loading