From 1f0322776d62d07bdff8ff21eb034093a9cb17e1 Mon Sep 17 00:00:00 2001 From: Doma Date: Tue, 9 Aug 2022 15:49:05 +0800 Subject: [PATCH] feat(confirm/prompt): add okButtonDangerous option (#53) --- README.md | 2 ++ demo/index.jsx | 4 ++++ index.d.ts | 4 +++- src/InteractionModal.jsx | 4 ++-- src/__tests__/InteractionModal.test.js | 11 +++++++++-- src/__tests__/confirm.test.js | 10 ++++++++++ src/__tests__/prompt.test.js | 10 ++++++++++ src/confirm.jsx | 8 +++++++- src/prompt.jsx | 14 ++++++++++++-- 9 files changed, 59 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 0555f54..3f65db1 100644 --- a/README.md +++ b/README.md @@ -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. @@ -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. diff --git a/demo/index.jsx b/demo/index.jsx index c2da2f5..ccb6f2e 100644 --- a/demo/index.jsx +++ b/demo/index.jsx @@ -45,6 +45,7 @@ function App() { if ( await confirm('Are you sure you want to do this?', { okButtonText: 'Yes', + okButtonDangerous: true, cancelButtonText: 'No', }) ) { @@ -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'); @@ -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(); @@ -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(); diff --git a/index.d.ts b/index.d.ts index 2aa7343..61dddc1 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,5 +1,5 @@ import * as React from 'react'; -import { InputProps } from 'rsuite/lib/Input'; +import type { InputProps } from 'rsuite'; interface AlertModalProps { okButtonText?: string; @@ -8,6 +8,7 @@ interface AlertModalProps { interface ConfirmModalProps { okButtonText?: string; + okButtonDangerous?: boolean; cancelButtonText?: string; onOk?: (() => void) | (() => Promise); onCancel?: (isSubmitLoading?: boolean) => any; @@ -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); diff --git a/src/InteractionModal.jsx b/src/InteractionModal.jsx index 9c2c7e4..abb3249 100644 --- a/src/InteractionModal.jsx +++ b/src/InteractionModal.jsx @@ -3,7 +3,7 @@ import { Button, Modal } from 'rsuite'; function InteractionModal({ okButtonText = '确定', - okButtonDisabled = false, + okButtonProps, onOk, showCancelButton = true, cancelButtonText = '取消', @@ -100,9 +100,9 @@ function InteractionModal({ )} diff --git a/src/__tests__/InteractionModal.test.js b/src/__tests__/InteractionModal.test.js index bcef25f..d074ba8 100644 --- a/src/__tests__/InteractionModal.test.js +++ b/src/__tests__/InteractionModal.test.js @@ -56,9 +56,11 @@ 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( - Hey + + Hey + ); expect( @@ -66,6 +68,11 @@ it('disables ok button when okButtonDisabled=true', () => { name: '确定', }) ).toBeDisabled(); + expect( + within(getByRole('alertdialog')).getByRole('button', { + name: '确定', + }) + ).toHaveClass('rs-btn-red'); }); it('hides dialog on clicking ok button', async () => { diff --git a/src/__tests__/confirm.test.js b/src/__tests__/confirm.test.js index fc90e71..1622138 100644 --- a/src/__tests__/confirm.test.js +++ b/src/__tests__/confirm.test.js @@ -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'); diff --git a/src/__tests__/prompt.test.js b/src/__tests__/prompt.test.js index ed7a5f5..7d5c032 100644 --- a/src/__tests__/prompt.test.js +++ b/src/__tests__/prompt.test.js @@ -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, diff --git a/src/confirm.jsx b/src/confirm.jsx index cfb48fa..4b82265 100644 --- a/src/confirm.jsx +++ b/src/confirm.jsx @@ -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( { if (!isFunction(modalConfig?.onOk)) { resolve(true); diff --git a/src/prompt.jsx b/src/prompt.jsx index 18d5463..cc4ac87 100644 --- a/src/prompt.jsx +++ b/src/prompt.jsx @@ -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'; @@ -8,6 +8,7 @@ import { isFunction } from './utils'; function PromptModal({ message, defaultResult = '', + okButtonDangerous = false, onOk, validate, inputProps, @@ -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 (