Skip to content

Commit

Permalink
feat(confirm/prompt): add okButtonDangerous option (#53)
Browse files Browse the repository at this point in the history
  • Loading branch information
SevenOutman authored Aug 9, 2022
1 parent b17661d commit 1f03227
Show file tree
Hide file tree
Showing 9 changed files with 59 additions and 8 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ interface ConfirmModalProps {
```

- `okButtonText`: Customize "OK" button text.
- `okButtonDangerous`: When set `true`, "OK" button is red colored.
- `cancelButtonText`: Customize "Cancel" button text.
- `onOk`: Callback function when "OK" is clicked. If `onOk` returns a `Promise`, "OK" button shows loading status until the promise finishes.
- `onCancel`: Callback function when "Cancel" is clicked. If not provided, "Cancel" is disabled when "OK" is loading.
Expand Down Expand Up @@ -117,6 +118,7 @@ interface PromptModalProps {
```

- `okButtonText`: Customize "OK" button text.
- `okButtonDangerous`: When set `true`, "OK" button is red colored.
- `cancelButtonText`: Customize "Cancel" button text.
- `validate`: Validate current input value. Disable OK button if validation fails.
- `onOk`: Callback function when "OK" is clicked, receiving a string representing the user input. If `onOk` returns a `Promise`, "OK" button shows loading status until the promise finishes.
Expand Down
4 changes: 4 additions & 0 deletions demo/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ function App() {
if (
await confirm('Are you sure you want to do this?', {
okButtonText: 'Yes',
okButtonDangerous: true,
cancelButtonText: 'No',
})
) {
Expand All @@ -56,6 +57,7 @@ function App() {
if (
await confirm('Are you sure you want to do this?', {
okButtonText: 'Yes',
okButtonDangerous: true,
cancelButtonText: 'No',
onOk: () => {
alert('You just clicked Yes');
Expand All @@ -70,6 +72,7 @@ function App() {
if (
await confirm('Are you sure you want to do this?', {
okButtonText: 'Yes',
okButtonDangerous: true,
cancelButtonText: 'No',
onOk: async () => {
await getNTimeout();
Expand All @@ -85,6 +88,7 @@ function App() {
if (
await confirm('Are you sure you want to do this?', {
okButtonText: 'Yes',
okButtonDangerous: true,
cancelButtonText: 'No',
onOk: async () => {
await getNTimeout();
Expand Down
4 changes: 3 additions & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { InputProps } from 'rsuite/lib/Input';
import type { InputProps } from 'rsuite';

interface AlertModalProps {
okButtonText?: string;
Expand All @@ -8,6 +8,7 @@ interface AlertModalProps {

interface ConfirmModalProps {
okButtonText?: string;
okButtonDangerous?: boolean;
cancelButtonText?: string;
onOk?: (() => void) | (() => Promise<any>);
onCancel?: (isSubmitLoading?: boolean) => any;
Expand All @@ -16,6 +17,7 @@ interface ConfirmModalProps {

interface PromptModalProps {
okButtonText?: string;
okButtonDangerous?: boolean;
cancelButtonText?: string;
validate?: (inputValue: string) => boolean;
onOk?: ((inputVal?: string) => void) | ((inputVal: string) => Promise<any>);
Expand Down
4 changes: 2 additions & 2 deletions src/InteractionModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Button, Modal } from 'rsuite';

function InteractionModal({
okButtonText = '确定',
okButtonDisabled = false,
okButtonProps,
onOk,
showCancelButton = true,
cancelButtonText = '取消',
Expand Down Expand Up @@ -100,9 +100,9 @@ function InteractionModal({
)}
<Button
loading={submitLoading}
disabled={okButtonDisabled}
onClick={handleOk}
appearance="primary"
{...okButtonProps}
>
{okButtonText}
</Button>
Expand Down
11 changes: 9 additions & 2 deletions src/__tests__/InteractionModal.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,23 @@ it('renders custom button text', () => {
expect(getByRole('button', { name: okButtonText })).toBeInTheDocument();
});

it('disables ok button when okButtonDisabled=true', () => {
it('accepts custom props on ok button via okButtonProps prop', () => {
const { getByRole } = render(
<InteractionModal okButtonDisabled>Hey</InteractionModal>
<InteractionModal okButtonProps={{ color: 'red', disabled: true }}>
Hey
</InteractionModal>
);

expect(
within(getByRole('alertdialog')).getByRole('button', {
name: '确定',
})
).toBeDisabled();
expect(
within(getByRole('alertdialog')).getByRole('button', {
name: '确定',
})
).toHaveClass('rs-btn-red');
});

it('hides dialog on clicking ok button', async () => {
Expand Down
10 changes: 10 additions & 0 deletions src/__tests__/confirm.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@ it('renders custom button text', async () => {
).toBeInTheDocument();
});

it('renders red ok button when okButtonDangerous=true', () => {
confirm('Message', {
okButtonDangerous: true,
});

expect(screen.getByRole('button', { name: '确定' })).toHaveClass(
'rs-btn-red'
);
});

describe('resolves correctly', () => {
it('hides modal and resolves true on clicking ok button', async () => {
const promise = confirm('Message');
Expand Down
10 changes: 10 additions & 0 deletions src/__tests__/prompt.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,16 @@ it('renders custom button text', async () => {
).toBeInTheDocument();
});

it('renders red ok button when okButtonDangerous=true', () => {
prompt('Message', '', {
okButtonDangerous: true,
});

expect(screen.getByRole('button', { name: '确定' })).toHaveClass(
'rs-btn-red'
);
});

it('disable OK button if validation fails', () => {
prompt('Message', '', {
validate: () => false,
Expand Down
8 changes: 7 additions & 1 deletion src/confirm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,19 @@ import InteractionModal from './InteractionModal';
import getContainerDOM from './getContainerDOM';
import { isFunction } from './utils';

export default function confirm(message, modalConfig) {
export default function confirm(
message,
{ okButtonDangerous = false, ...modalConfig } = {}
) {
return new Promise((resolve, reject) => {
ReactDOM.render(
<InteractionModal
key={Date.now()}
canCancelOnLoading={!!modalConfig?.onCancel}
{...modalConfig}
okButtonProps={{
color: okButtonDangerous ? 'red' : undefined,
}}
onOk={() => {
if (!isFunction(modalConfig?.onOk)) {
resolve(true);
Expand Down
14 changes: 12 additions & 2 deletions src/prompt.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, useState } from 'react';
import React, { useCallback, useState, useMemo } from 'react';
import ReactDOM from 'react-dom';
import { Input } from 'rsuite';
import InteractionModal from './InteractionModal';
Expand All @@ -8,6 +8,7 @@ import { isFunction } from './utils';
function PromptModal({
message,
defaultResult = '',
okButtonDangerous = false,
onOk,
validate,
inputProps,
Expand All @@ -20,10 +21,19 @@ function PromptModal({

const handleOk = useCallback(() => onOk(result), [onOk, result]);

const okButtonDisabled = useMemo(() => {
return validate?.(result) === false;
}, [result, validate]);

const okButtonColor = okButtonDangerous ? 'red' : undefined;

return (
<InteractionModal
{...props}
okButtonDisabled={validate?.(result) === false}
okButtonProps={{
color: okButtonColor,
disabled: okButtonDisabled,
}}
onOk={handleOk}
>
<div style={{ padding: '5px' }} className="modal-content">
Expand Down

0 comments on commit 1f03227

Please sign in to comment.