├── .gitignore ├── .idea ├── .gitignore ├── dictionaries │ └── daniel.xml ├── misc.xml ├── modules.xml ├── react-bootstrap-sweetalert.iml └── vcs.xml ├── .npmignore ├── CHANGE_LOG.md ├── LICENSE ├── README.md ├── demo ├── assets │ ├── bmab.png │ ├── bootstrap.min.css │ ├── demo.css │ ├── demo.gif │ ├── favicon.png │ ├── index.html │ ├── openbase.png │ └── thumbs-up.jpg ├── demo-server.js └── demo.bundle.js ├── examples └── redux │ ├── .env │ ├── .gitignore │ ├── README.md │ ├── package.json │ ├── public │ ├── index.html │ └── manifest.json │ ├── src │ ├── App.test.js │ ├── actions │ │ └── index.js │ ├── components │ │ ├── Footer.js │ │ └── HeaverNav.js │ ├── constants │ │ └── ActionTypes.js │ ├── containers │ │ ├── App │ │ │ ├── App.css │ │ │ ├── NoMatch.js │ │ │ └── index.js │ │ ├── HeaderContainer.js │ │ └── HomeContainer.js │ ├── index.js │ ├── reducers │ │ ├── index.js │ │ └── notifications.js │ ├── serviceWorker.js │ ├── store.js │ └── styles │ │ ├── app.scss │ │ ├── bootstrap.scss │ │ ├── index.scss │ │ └── overrides.scss │ └── yarn.lock ├── gulpfile.js ├── index.html ├── package.json ├── src ├── components │ ├── Buttons.tsx │ ├── Content.tsx │ ├── CustomIcon.tsx │ ├── ErrorIcon.tsx │ ├── InfoIcon.tsx │ ├── Input.tsx │ ├── Overlay.tsx │ ├── SuccessIcon.tsx │ ├── SweetAlert.tsx │ ├── Title.tsx │ ├── ValidationMessage.tsx │ └── WarningIcon.tsx ├── constants │ └── patterns.ts ├── css │ └── animations.css ├── default-props.ts ├── demo │ ├── index.d.ts │ ├── src │ │ ├── Demo.tsx │ │ ├── examples │ │ │ ├── Animations.tsx │ │ │ ├── Basic.tsx │ │ │ ├── CustomButtons.tsx │ │ │ ├── CustomStyle.tsx │ │ │ ├── Example.ts │ │ │ ├── FocusCancelButton.tsx │ │ │ ├── HTML.tsx │ │ │ ├── IconAndCloseButton.tsx │ │ │ ├── Input.tsx │ │ │ ├── LongMessage.tsx │ │ │ ├── Password.tsx │ │ │ ├── ReverseButtons.tsx │ │ │ ├── SmallButtons.tsx │ │ │ ├── Success.tsx │ │ │ ├── Timer.tsx │ │ │ ├── TitleWithText.tsx │ │ │ ├── WarningWithCallbacks.tsx │ │ │ └── index.ts │ │ └── index.tsx │ ├── tsconfig.json │ └── webpack.config.js ├── index.ts ├── prop-types.ts ├── styles │ └── SweetAlertStyles.ts └── types.ts ├── tsconfig.json ├── tslint.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .vscode/ 3 | dist/ 4 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /workspace.xml -------------------------------------------------------------------------------- /.idea/dictionaries/daniel.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | sweetalert 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/react-bootstrap-sweetalert.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | demo/ 3 | examples/ 4 | src/ 5 | dist/demo/ 6 | server.js 7 | webpack.config.js 8 | gulpfile.js 9 | .babelrc 10 | -------------------------------------------------------------------------------- /CHANGE_LOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | v5.2 4 | ----- 5 | * Added `props.dependencies` that re-renders the alert whenever the provided Array of `dependencies` value changes. 6 | * Added new supported value of `'controlled'` for `props.type`. If `props.type === 'controlled'` then `props.onConfirm` will return `props.dependencies`. 7 | * Added support for using a function as your alert content/children, aka render props. 8 | 9 | v5.1 10 | ----- 11 | * Fixed deprecation warning from componentWillMount, componentWillUpdate and componentWillReceiveProps 12 | * Fixed Sweetalert input validation message overflowing container. 13 | * Added `props.focusCancelBtn` that focuses on the cancel button by default. 14 | * Added `props.reverseButtons` that reverses the cancel and confirm button order. 15 | * Added `props.customActions` that overrides the buttons in the alert message. In here it would be possible to create more buttons or add some custom behaviour. 16 | * Added support for custom show and hide animations with `props.openAnim` and `props.closeAnim`. 17 | 18 | v5.0 19 | ----- 20 | 21 | * Converted source code to typescript, added index.d.ts. 22 | * Added `props.showCloseButton` for displaying an X close button in the top right. 23 | * Added `props.closeButtonStyle` for overriding the styles of the close button. 24 | * Added support for long content that requires scrolling, and moved ESC key listener to the overlay. 25 | * Removed strict match on bootstrap button variation. 26 | 27 | v4.4 28 | ----- 29 | 30 | * Added `props.validationRegex` for validating input. default: `/^.+$/` 31 | 32 | v4.3 33 | ----- 34 | 35 | * Added `props.timeout` which calls onConfirm to close the alert automatically after a certain number of milliseconds. default: `0` 36 | 37 | v4.2 38 | ----- 39 | 40 | * Fixed auto-focus on confirm button 41 | * Removed outline css from alert 42 | * Updated examples to not show deprecated params 43 | * Added `props.focusConfirmBtn` to control whether you want to focus on the button automatically. default: `true` 44 | 45 | v4.1 46 | ----- 47 | 48 | * Added `props.closeOnClickOutside` to trigger onClose when clicking outside. default=true 49 | * Added `props.btnSize` to allow custom button size 50 | * Added `props.confirmBtnCssClass` to allow custom class on confirm button 51 | * Added `props.cancelBtnCssClass` to allow custom class on cancel button 52 | * Added `props.confirmBtnStyle` to allow custom inline style on confirm button 53 | * Added `props.cancelBtnStyle` to allow custom inline style on cancel button 54 | 55 | v4.0 56 | ----- 57 | 58 | * Added `prop-types` as peer dependency 59 | * Added `props.showConfirm` to allow hiding the confirm button 60 | * Added `props.show` to allow hiding the alert 61 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2020 djorg83 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-bootstrap-sweetalert 2 | 3 | [![NPM version](http://img.shields.io/npm/v/react-bootstrap-sweetalert.svg)](https://www.npmjs.com/package/react-bootstrap-sweetalert) 4 | [![Downloads](https://img.shields.io/npm/dm/react-bootstrap-sweetalert.svg)](https://www.npmjs.com/package/react-bootstrap-sweetalert) 5 | [![David](https://img.shields.io/david/djorg83/react-bootstrap-sweetalert.svg?maxAge=2592000)](https://github.com/djorg83/react-bootstrap-sweetalert) 6 | [![GitHub issues](https://img.shields.io/github/issues/djorg83/react-bootstrap-sweetalert.svg?maxAge=2592000)](https://github.com/djorg83/react-bootstrap-sweetalert) 7 | [![license](https://img.shields.io/github/license/djorg83/react-bootstrap-sweetalert.svg?maxAge=2592000)](https://github.com/djorg83/react-bootstrap-sweetalert) 8 | [![GitHub stars](https://img.shields.io/github/stars/djorg83/react-bootstrap-sweetalert.svg?style=social&label=Star&maxAge=2592000)](https://github.com/djorg83/react-bootstrap-sweetalert) 9 | 10 | [![openbase](https://djorg83.github.io/react-bootstrap-sweetalert/demo/assets/openbase.png) Openbase Dashboard](https://openbase.io/js/react-bootstrap-sweetalert) 11 | 12 | [![NPM](https://nodei.co/npm/react-bootstrap-sweetalert.png?downloads=true&stars=true)](https://nodei.co/npm/react-bootstrap-sweetalert/) 13 | 14 | # SweetAlert for React/Bootstrap 15 | 16 | An awesome replacement for JavaScript's alert. 17 | 18 | ---- 19 | 20 | ## Support 21 | 22 | If you think I've done a good job, consider showing your support by buying me a beer. Cheers! :beers: 23 | 24 | [![Buy me a beer](https://djorg83.github.io/react-bootstrap-sweetalert/demo/assets/bmab.png)](https://www.buymeacoffee.com/djorg83) 25 | 26 | ---- 27 | 28 | ## Demo & Examples 29 | 30 | See the demo with examples of common use cases and a live editor. 31 | 32 | :alien: [TAKE ME TO YOUR DEMO](http://djorg83.github.io/react-bootstrap-sweetalert/) :alien: 33 | 34 | ![Demo GIF](https://djorg83.github.io/react-bootstrap-sweetalert/demo/assets/demo.gif) 35 | ---- 36 | 37 | ## Getting Started 38 | 39 | ### Installation 40 | ``` 41 | $ npm i react-bootstrap-sweetalert 42 | ``` 43 | 44 | > or 45 | 46 | ``` 47 | $ yarn add react-bootstrap-sweetalert 48 | ``` 49 | 50 | ### Import 51 | ``` 52 | const SweetAlert = require('react-bootstrap-sweetalert'); 53 | ``` 54 | > or 55 | 56 | ``` 57 | import SweetAlert from 'react-bootstrap-sweetalert'; 58 | ``` 59 | 60 | ---- 61 | 62 | ## Recommended Usage 63 | 64 | It is recommended that you keep an alert in your state, and remove it when the `onConfirm` or `onCancel` callbacks are invoked. 65 | 66 | You can have stackable alerts by keeping an array of alerts in your data store, and always providing the first alert in 67 | the array as the visible alert. When an alert is closed, remove it from the store. 68 | 69 | See [`examples/redux`](https://github.com/djorg83/react-bootstrap-sweetalert/tree/master/examples/redux) for a working example of how to implement stackable alerts with a Redux store. 70 | 71 | ---- 72 | 73 | ## Tip: Receiving an input value 74 | 75 | If you're using `input` type, the value of the input will be sent to the `onConfirm` callback as the first argument. 76 | 77 | ``` js 78 | onConfirm={(response) => this.onRecieveInput(response)} 79 | ``` 80 | 81 | ## Custom Forms / Using Render Props 82 | 83 | If you want to build an alert that re-renders based on external state changes, or simply want to build a custom form, 84 | then you will find the render props pattern to be your best option. 85 | 86 | - For re-rendering based on external state changes, use [props.dependencies](#propsdependencies) 87 | - See the `SweetAlertRenderProps` interface in [types.ts](https://github.com/djorg83/react-bootstrap-sweetalert/blob/master/src/types.ts) for some information on the available render props. 88 | 89 | ```typescript jsx 90 | 96 | {(renderProps: SweetAlertRenderProps) => ( 97 |
98 | Your name is: {this.state.firstName} {this.state.lastName} 99 |
100 | this.setState({ firstName: e.target.value })} 107 | placeholder={'First name'} 108 | /> 109 |
110 | this.setState({ lastName: e.target.value })} 116 | placeholder={'Last name'} 117 | /> 118 |
119 |
120 | )} 121 |
122 | ``` 123 | 124 | ## Changes in version 5.2 125 | 126 | * Added `props.dependencies` that re-renders the alert whenever the provided Array of `dependencies` value changes. 127 | * Added new supported value of `'controlled'` for `props.type`. If `props.type === 'controlled'` then `props.onConfirm` will return `props.dependencies`. 128 | * Added support for using a function as your alert content/children, aka render props. 129 | 130 | For more see [CHANGE_LOG.md](https://github.com/djorg83/react-bootstrap-sweetalert/blob/master/CHANGE_LOG.md) 131 | 132 | ## Props 133 | 134 | - [title](#propstitle) (required) 135 | - [type](#propstype) 136 | - [onConfirm](#propsonconfirm) (required) 137 | - [onCancel](#propsoncancel) 138 | - [customIcon](#propscustomicon) 139 | - [allowEscape](#propsallowescape) 140 | - [closeOnClickOutside](#propscloseonclickoutside) 141 | - [hideOverlay](#propshideoverlay) 142 | - [timeout](#propstimeout) 143 | - [show](#propsshow) 144 | - [dependencies](#propsdependencies) 145 | 146 | ##### Buttons 147 | 148 | - [btnSize](#propsbtnsize) 149 | - [confirmBtnText](#propsconfirmbtntext) 150 | - [confirmBtnBsStyle](#propsconfirmbtnbsstyle) 151 | - [confirmBtnCssClass](#propsconfirmbtncssclass) 152 | - [confirmBtnStyle](#propsconfirmbtnstyle) 153 | - [cancelBtnText](#propscancelbtntext) 154 | - [cancelBtnBsStyle](#propscancelbtnbsstyle) 155 | - [cancelBtnCssClass](#propscancelbtncssclass) 156 | - [cancelBtnStyle](#propscancelbtnstyle) 157 | - [showCloseButton](#propsshowclosebutton) 158 | - [reverseButtons](#propsreversebuttons) 159 | - [customButtons](#propscustombuttons) 160 | - [focusConfirmBtn](#propsfocusconfirmbtn) 161 | - [focusCancelBtn](#propsfocuscancelbtn) 162 | - [closeBtnStyle](#propsclosebtnstyle) 163 | - [showConfirm](#propsshowconfirm) 164 | - [showCancel](#propsshowcancel) 165 | - [disabled](#propsdisabled) 166 | 167 | ##### Input 168 | 169 | - [placeholder](#propsplaceholder) 170 | - [required](#propsrequired) 171 | - [validationMsg](#propsvalidationmsg) 172 | - [validationRegex](#propsvalidationregex) 173 | - [defaultValue](#propsdefaultvalue) 174 | - [inputType](#propsinputtype) 175 | 176 | ##### Hooks 177 | 178 | - [beforeMount](#propsbeforemount) 179 | - [afterMount](#propsaftermount) 180 | - [afterUpdate](#propsafterupdate) 181 | - [beforeUnmount](#propsbeforeunmount) 182 | 183 | ##### Styling 184 | 185 | - [style](#propsstyle) 186 | - [customClass](#propscustomclass) 187 | 188 | ##### Animations 189 | 190 | - [openAnim](#propsopenanim) 191 | - [closeAnim](#propscloseanim) 192 | 193 | ---- 194 | 195 | ### `props.title` 196 | The text to display for the title. JSX/ReactNode allowed. 197 | - Type: `ReactNode|string` 198 | - Default: `undefined` 199 | ---- 200 | ### `props.onConfirm` 201 | Invoked when user clicks confirm button. Also invoked if user hits ENTER key. 202 | - Type: `(response?: any) => any` 203 | - Default: `undefined` 204 | ---- 205 | ### `props.onCancel` 206 | Invoked when user clicks cancel button. Also invoked if allowEscape is true and user hits ESCAPE key. 207 | - Type: `() => any` 208 | - Default: `undefined` 209 | ---- 210 | ### `props.type` 211 | The type of alert to display. 212 | - Type: `'default'|'info'|'success'|'warning'|'danger'|'error'|'input'|'custom'|'controlled'` 213 | - Default: `'default'` 214 | 215 | > NOTE 216 | > - If `props.type === 'controlled'` then `props.onConfirm` will receive `props.dependencies` as its first argument. 217 | > - If `props.type === 'input'` then `props.onConfirm` will receive `props.dependencies` as its first argument. 218 | ---- 219 | ### `props.btnSize` 220 | The type of alert to display. 221 | - Type: `'lg'|'sm'|'xs'` 222 | - Default: `'lg'` 223 | - Allowed values: `'lg'`, `'sm'`, `'xs'` 224 | ---- 225 | ### `props.confirmBtnText` 226 | Content of confirm button, or JSX/ReactNode. 227 | - Type: `ReactNode|string` 228 | - Default: `'OK'` 229 | ---- 230 | ### `props.confirmBtnBsStyle` 231 | Bootstrap style of confirm button. 232 | - Type: `'default'|'primary'|'link'|'info'|'success'|'warning'|'danger'|'secondary'|'outline-{variant}'` 233 | - Default: `'primary'` 234 | ---- 235 | ### `props.confirmBtnCssClass` 236 | CSS class added to confirm button. 237 | - Type: `string` 238 | - Default: `''` 239 | ---- 240 | ### `props.confirmBtnStyle` 241 | Inline style added to confirm button. 242 | - Type: `CSSProperties` 243 | - Default: `{}` 244 | ---- 245 | ### `props.cancelBtnText` 246 | Content of cancel button, or JSX/ReactNode. 247 | - Type: `ReactNode|string` 248 | - Default: `'Cancel'` 249 | ---- 250 | ### `props.cancelBtnBsStyle` 251 | Text of cancel button, or JSX/ReactNode. 252 | - Type: `string` 253 | - Default: `'link'` 254 | - Recommended values: `'default'|'primary'|'link'|'info'|'success'|'warning'|'danger'|'secondary'|'outline-{variant}'` 255 | ---- 256 | ### `props.cancelBtnCssClass` 257 | CSS class added to cancel button. 258 | - Type: `string` 259 | - Default: `''` 260 | ---- 261 | ### `props.cancelBtnStyle` 262 | Inline style added to cancel button. 263 | - Type: `CSSProperties` 264 | - Default: `{}` 265 | ---- 266 | ### `props.showCloseButton` 267 | If set to true, then an X close button will be shown in the top right of the alert. 268 | 269 | > NOTE: You must also implement `props.onCancel` in order for this props to work. This is because visibility of the 270 | > component is controlled externally through either `props.show` or by removing the `` in your render method. 271 | 272 | - Type: `boolean` 273 | - Default: `false` 274 | ---- 275 | ### `props.reverseButtons` 276 | Reverses the order of the Confirm and Cancel buttons. Default positioning is [Cancel] [Confirm] 277 | - Type: `boolean` 278 | - Default: `false` 279 | ---- 280 | ### `props.customButtons` 281 | Custom buttons to use in place of the default Confirm and Cancel buttons. Can render any JSX/ReactNodes here. 282 | - Type: `ReactNode` 283 | - Default: `undefined` 284 | ---- 285 | ### `props.customIcon` 286 | Either a string url for an image to use as the icon, or JSX/ReactNode. 287 | - Type: `ReactNode|string` 288 | - Default: `undefined` 289 | ---- 290 | ### `props.placeholder` 291 | If `props.type` is `'input'`, this is the placeholder for the input field. 292 | - Type: `string` 293 | - Default: `undefined` 294 | ---- 295 | ### `props.show` 296 | If false, the alert will not be rendered. 297 | Warning: Using this option should be a last resort, and is somewhat of an anti-pattern for this library. 298 | The recommended way to control visibility is to only render a `` element when you want one to be displayed, 299 | and remove it when the `onConfirm` or `onCancel` methods are called. 300 | - Type: `boolean` 301 | - Default: `true` 302 | ---- 303 | ### `props.dependencies` 304 | If you have external state that should trigger your alert to re-render it's content, you can provide an `Array` of `dependencies`. 305 | Whenever the dependencies are changed, using `===` comparision, the content of the alert will be re-rendered. 306 | - Type: `any[]` 307 | - Default: `true` 308 | 309 | Example 310 | ```typescript jsx 311 | const [firstName, setFirstName] = useState(''); 312 | const [lastName, setLastName] = useState(''); 313 | 314 | 315 |
316 |

Hello {{firstName}} {{lastName}}

317 | setFirstName(e.target.value)} /> 318 | setLastName(e.target.value)} /> 319 |
320 |
321 | ``` 322 | ---- 323 | ### `props.focusConfirmBtn` 324 | If true the Confirm button will receive focus automatically. NOTE: Does not apply when `props.type` is `'input'` 325 | - Type: `boolean` 326 | - Default: `true` 327 | ---- 328 | ### `props.focusCancelBtn` 329 | If true the Cancel button will receive focus automatically. NOTE: Does not apply when `props.type` is `'input'` 330 | - Type: `boolean` 331 | - Default: `false` 332 | ---- 333 | ### `props.required` 334 | If `props.type` is `'input'`, this prop controls whether the input field is required to have a value. 335 | - Type: `boolean` 336 | - Default: `true` 337 | ---- 338 | ### `props.validationMsg` 339 | If `props.type` is `'input'` and `props.required` is `true`, this is the message to display when the user clicks confirm without entering a value. 340 | - Type: `string` 341 | - Default: `'Please enter a response!'` 342 | ---- 343 | ### `props.validationRegex` 344 | If `props.type` is `'input'` and `props.required` is `true`, this Regex is used to validate input value. 345 | - Type: `RegExp` 346 | - Default: `/^.+$/` 347 | ---- 348 | ### `props.defaultValue` 349 | If `props.type` is `'input'`, this is the default value for the input field. 350 | - Type: `number|string` 351 | - Default: `undefined` 352 | ---- 353 | ### `props.inputType` 354 | If `props.type` is `'input'`, this is the default value for the input field. 355 | - Type: `string` 356 | - Default: `'text'` 357 | - Recommended values: `'text'|'password'|'number'|'textarea'` 358 | ---- 359 | ### `props.style` 360 | Style overrides applied to the sweetalert wrapper. 361 | - Type: `CSSProperties` 362 | - Default: `{}` 363 | ---- 364 | ### `props.closeBtnStyle` 365 | Style overrides applied to the X close button. 366 | - Type: `CSSProperties` 367 | - Default: `{}` 368 | ---- 369 | ### `props.customClass` 370 | Custom CSS class applied to the sweetalert wrapper. 371 | - Type: `string` 372 | - Default: `''` 373 | ---- 374 | ### `props.showConfirm` 375 | If `true`, the Confirm button will show. 376 | - Type: `boolean` 377 | - Default: `true` 378 | ---- 379 | ### `props.showCancel` 380 | If `true`, the Cancel button will show. 381 | - Type: `boolean` 382 | - Default: `false` 383 | ---- 384 | ### `props.allowEscape` 385 | If `true`, the `onCancel` function will be invoked when the user hits the `ESCAPE` key. 386 | - Type: `boolean` 387 | - Default: `true` 388 | ---- 389 | ### `props.closeOnClickOutside` 390 | If `true`, the `onCancel` function will be invoked when clicking outside the modal. 391 | - Type: `boolean` 392 | - Default: `true` 393 | ---- 394 | ### `props.hideOverlay` 395 | If `true`, then the modal overlay will not be rendered. 396 | - Type: `boolean` 397 | - Default: `false` 398 | ---- 399 | ### `props.disabled` 400 | If `true`, then the Confirm button will be disabled. (NOTE: This does not effect the `props.allowEscape` behavior.) 401 | If you set disabled to `true` but do not provide an `onCancel` function, then the `disabled` property will not be honored. 402 | - Type: `boolean` 403 | - Default: `false` 404 | ---- 405 | ### `props.beforeMount` 406 | Hook which is invoked at the end of the component `constructor` function. 407 | - Type: `() => any` 408 | - Default: `() => {}` 409 | ---- 410 | ### `props.afterMount` 411 | Hook which is invoked at the end of the `componentDidMount` method. 412 | - Type: `() => any` 413 | - Default: `() => {}` 414 | ---- 415 | ### `props.afterUpdate` 416 | Hook which is invoked at the end of the `componentDidUpdate` method. 417 | - Type: `() => any` 418 | - Default: `() => {}` 419 | ---- 420 | ### `props.beforeUnmount` 421 | Hook which is invoked at the end of the `componentWillUnmount` method. 422 | - Type: `() => any` 423 | - Default: `() => {}` 424 | ---- 425 | ### `props.timeout` 426 | If defined, and greater than `0`, `props.onConfirm` will be invoked to close the alert automatically after the specified number of milliseconds. 427 | - Type: `number` 428 | - Default: `0` 429 | ---- 430 | ### `props.openAnim` 431 | Provide custom show animation or false to have no animation. To specify a custom animation, provide the name of your css animation and duration of the animation in milliseconds. 432 | - Type: `boolean|SweetAlertAnimationProps` 433 | - Default: `{ name: 'showSweetAlert', duration: 300 }` 434 | ---- 435 | ### `props.closeAnim` 436 | Provide custom hide animation or false to have no animation. To specify a custom animation, provide the name of your css animation and duration of the animation in milliseconds. For a simple hide animation you can use `{ name: 'hideSweetAlert', duration: 100 }` 437 | - Type: `boolean|SweetAlertAnimationProps` 438 | - Default: `false` 439 | 440 | ## Related projects 441 | 442 | * [SweetAlert](https://github.com/t4t5/sweetalert) 443 | * [SweetAlert for Android](https://github.com/pedant/sweet-alert-dialog) 444 | * [SweetAlert for Bootstrap](https://github.com/lipis/bootstrap-sweetalert) 445 | * [SweetAlert for AngularJS](https://github.com/oitozero/ngSweetAlert) 446 | * [SweetAlert for RubyOnRails](https://github.com/sharshenov/sweetalert-rails) 447 | 448 | ## Development 449 | 450 | ``` bash 451 | $ yarn demo && open http://localhost:3000 452 | ``` 453 | -------------------------------------------------------------------------------- /demo/assets/bmab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djorg83/react-bootstrap-sweetalert/f7d83933ff49b4680e2b3e927c9ac0054d7f7132/demo/assets/bmab.png -------------------------------------------------------------------------------- /demo/assets/demo.css: -------------------------------------------------------------------------------- 1 | .jumbotron { 2 | font-size: 16px; 3 | text-align: center; 4 | color: #fff; 5 | color: rgba(255,255,255,.75); 6 | background-color: #cb4b16; 7 | border-radius: 0; 8 | } 9 | .jumbotron h1 { 10 | font-size: 63px; 11 | margin-bottom: 15px; 12 | font-weight: 300; 13 | letter-spacing: -1px; 14 | color: #fff; 15 | } 16 | .jumbotron p { 17 | margin-bottom: 15px; 18 | font-size: 21px; 19 | font-weight: 200; 20 | } 21 | .jumbotron .small { 22 | font-size: .9em; 23 | } 24 | .jumbotron iframe { 25 | width: 90px!important; 26 | height: 20px!important; 27 | border: none; 28 | overflow: hidden; 29 | margin: 2px; 30 | } 31 | .jumbotron p a, 32 | .jumbotron-links a { 33 | font-weight: 500; 34 | color: #fff; 35 | transition: all .1s ease-in-out; 36 | } 37 | .jumbotron p a:hover, 38 | .jumbotron-links a:hover { 39 | text-shadow: 0 0 10px rgba(255,255,255,.55); 40 | } 41 | .jumbotron-links { 42 | margin-top: 15px; 43 | padding-left: 0; 44 | list-style: none; 45 | font-size: 14px; 46 | } 47 | .jumbotron-links li { 48 | display: inline; 49 | } 50 | .jumbotron-links li + li { 51 | margin-left: 20px; 52 | } 53 | .btn-outline { 54 | margin-top: 15px; 55 | margin-bottom: 15px; 56 | padding: 18px 24px; 57 | font-size: inherit; 58 | font-weight: 500; 59 | color: #fff; 60 | background-color: transparent; 61 | border-color: #fff; 62 | border-color: rgba(255,255,255,.5); 63 | transition: all .1s ease-in-out; 64 | } 65 | .btn-outline:hover, 66 | .btn-outline:active { 67 | color: @color-bg; 68 | background-color: #fff; 69 | border-color: #fff; 70 | } 71 | .container { 72 | max-width: 80vw; 73 | } 74 | h1, 75 | h2 { 76 | font-weight: 300; 77 | margin-top: 32px; 78 | margin-bottom: 32px; 79 | text-align: center; 80 | } 81 | h4 { 82 | font-weight: 300; 83 | margin-top: 36px; 84 | margin-bottom: 24px; 85 | } 86 | pre { 87 | font-size: 0.8em; 88 | overflow: auto; 89 | word-wrap: normal; 90 | white-space: pre; 91 | display: block; 92 | padding: 9.5px; 93 | margin: 0 0 10px; 94 | line-height: 1.42857143; 95 | color: #2d2d2d; 96 | word-break: break-all; 97 | background-color: #f7f7f7; 98 | border: 1px solid #bbbbbb; 99 | border-radius: 2px; 100 | text-align: left; 101 | } 102 | footer { 103 | text-align: center; 104 | opacity: .8; 105 | padding: 40px 0; 106 | margin-top: 40px; 107 | border-top: 1px solid #ccc; 108 | } 109 | .examples { 110 | text-align: center; 111 | } 112 | .examples .btn { 113 | margin-bottom: 4px; 114 | } 115 | .links { 116 | margin: 0; 117 | list-style: none; 118 | padding-left: 0; 119 | } 120 | .links li { 121 | display: inline; 122 | padding: 0 10px; 123 | } 124 | -------------------------------------------------------------------------------- /demo/assets/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djorg83/react-bootstrap-sweetalert/f7d83933ff49b4680e2b3e927c9ac0054d7f7132/demo/assets/demo.gif -------------------------------------------------------------------------------- /demo/assets/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djorg83/react-bootstrap-sweetalert/f7d83933ff49b4680e2b3e927c9ac0054d7f7132/demo/assets/favicon.png -------------------------------------------------------------------------------- /demo/assets/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | React Bootstrap SweetAlert Demo 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /demo/assets/openbase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djorg83/react-bootstrap-sweetalert/f7d83933ff49b4680e2b3e927c9ac0054d7f7132/demo/assets/openbase.png -------------------------------------------------------------------------------- /demo/assets/thumbs-up.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djorg83/react-bootstrap-sweetalert/f7d83933ff49b4680e2b3e927c9ac0054d7f7132/demo/assets/thumbs-up.jpg -------------------------------------------------------------------------------- /demo/demo-server.js: -------------------------------------------------------------------------------- 1 | process.title = 'Demo Server'; 2 | 3 | const express = require('express'); 4 | const path = require('path'); 5 | const app = express(); 6 | 7 | app.use('/assets', express.static(path.join(__dirname, '/assets'))); 8 | app.use('/demo/assets', express.static(path.join(__dirname, '/assets'))); 9 | 10 | app.get('/', (req, res) => { 11 | res.sendFile(path.join(__dirname + '/assets/index.html')); 12 | }); 13 | 14 | app.get('/js/demo.bundle.js', (req, res) => { 15 | res.sendFile(path.join(__dirname + '/demo.bundle.js')); 16 | }); 17 | 18 | app.listen(3000, () => console.log(`Demo running on: http://localhost:3000`)); -------------------------------------------------------------------------------- /examples/redux/.env: -------------------------------------------------------------------------------- 1 | SKIP_PREFLIGHT_CHECK=true 2 | -------------------------------------------------------------------------------- /examples/redux/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # production 7 | /build 8 | 9 | # misc 10 | .DS_Store 11 | 12 | npm-debug.log* 13 | yarn-debug.log* 14 | yarn-error.log* 15 | -------------------------------------------------------------------------------- /examples/redux/README.md: -------------------------------------------------------------------------------- 1 | # React Bootstrap SweetAlert - Redux Example 2 | 3 | ``` bash 4 | git clone https://github.com/djorg83/react-bootstrap-sweetalert.git 5 | cd react-bootstrap-sweetalert/examples/redux 6 | npm install 7 | npm start 8 | open http://localhost:3000 9 | ``` 10 | -------------------------------------------------------------------------------- /examples/redux/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-bootstrap-sweetalert-redux-example", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "react-scripts start", 7 | "build": "react-scripts build", 8 | "test": "react-scripts test", 9 | "eject": "react-scripts eject" 10 | }, 11 | "dependencies": { 12 | "bootstrap": "^4.3.1", 13 | "connected-react-router": "^6.5.2", 14 | "history": "^4.9.0", 15 | "prop-types": "^15.7.2", 16 | "react": "^16.8.6", 17 | "react-addons-update": "^15.6.2", 18 | "react-bootstrap": "^1.0.0-beta.9", 19 | "react-bootstrap-sweetalert": "^4.4.1", 20 | "react-dom": "^16.8.6", 21 | "react-redux": "^7.1.0", 22 | "react-router-dom": "^5.0.1", 23 | "react-scripts": "3.0.1", 24 | "redux": "^4.0.1", 25 | "redux-logger": "^3.0.6", 26 | "redux-thunk": "^2.3.0" 27 | }, 28 | "eslintConfig": { 29 | "extends": "react-app" 30 | }, 31 | "browserslist": { 32 | "production": [ 33 | ">0.2%", 34 | "not dead", 35 | "not op_mini all" 36 | ], 37 | "development": [ 38 | "last 1 chrome version", 39 | "last 1 firefox version", 40 | "last 1 safari version" 41 | ] 42 | }, 43 | "devDependencies": { 44 | "node-sass": "^4.12.0" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /examples/redux/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 21 | Example 22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /examples/redux/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Example", 3 | "name": "Example", 4 | "icons": [ 5 | ], 6 | "start_url": ".", 7 | "display": "standalone", 8 | "theme_color": "#000000", 9 | "background_color": "#ffffff" 10 | } 11 | -------------------------------------------------------------------------------- /examples/redux/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /examples/redux/src/actions/index.js: -------------------------------------------------------------------------------- 1 | import * as types from '../constants/ActionTypes'; 2 | 3 | const addAlert = alert => ({ 4 | type: types.ADD_ALERT, 5 | alert 6 | }); 7 | 8 | const removeAlert = id => ({ 9 | type: types.REMOVE_ALERT, 10 | id 11 | }); 12 | 13 | export const showAlert = (alertProps) => dispatch => { 14 | 15 | if (!alertProps.id) { 16 | alertProps.id = '' + Date.now() + Math.random() + Math.random(); 17 | } 18 | 19 | // auto-close on confirm 20 | if (alertProps.onConfirm) { 21 | const onConfirm = alertProps.onConfirm; 22 | alertProps.onConfirm = (...args) => { 23 | onConfirm(...args); 24 | closeAlert(alertProps.id)(dispatch); 25 | } 26 | } else { 27 | alertProps.onConfirm = () => closeAlert(alertProps.id)(dispatch); 28 | } 29 | 30 | // auto-close on cancel 31 | if (alertProps.onCancel) { 32 | const onCancel = alertProps.onCancel; 33 | alertProps.onCancel = (...args) => { 34 | onCancel(...args); 35 | closeAlert(alertProps.id)(dispatch); 36 | } 37 | } else { 38 | alertProps.onCancel = () => closeAlert(alertProps.id)(dispatch); 39 | } 40 | 41 | dispatch(addAlert(alertProps)); 42 | }; 43 | 44 | export const closeAlert = (id) => dispatch => { 45 | dispatch(removeAlert(id)); 46 | }; 47 | -------------------------------------------------------------------------------- /examples/redux/src/components/Footer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Navbar} from 'react-bootstrap'; 3 | 4 | function Footer() { 5 | return ( 6 | 7 |
8 | © example.com {new Date().getFullYear()} 9 |
10 |
11 | ); 12 | } 13 | 14 | export default Footer; 15 | -------------------------------------------------------------------------------- /examples/redux/src/components/HeaverNav.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Navbar} from 'react-bootstrap'; 3 | 4 | const HeaderNav = () => ( 5 | 6 | 7 | 8 | 9 | ); 10 | 11 | HeaderNav.propTypes = { 12 | }; 13 | 14 | export default HeaderNav; 15 | -------------------------------------------------------------------------------- /examples/redux/src/constants/ActionTypes.js: -------------------------------------------------------------------------------- 1 | export const ADD_ALERT = 'ADD_ALERT'; 2 | export const REMOVE_ALERT = 'REMOVE_ALERT'; 3 | -------------------------------------------------------------------------------- /examples/redux/src/containers/App/App.css: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /examples/redux/src/containers/App/NoMatch.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const NoMatch = () => ( 4 |
5 |

6 | 404 Page Not Found 7 |

8 |
9 | Sorry, not sorry. 10 |
11 |
12 | ); 13 | 14 | export default NoMatch; 15 | -------------------------------------------------------------------------------- /examples/redux/src/containers/App/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from "prop-types"; 3 | import {connect} from "react-redux"; 4 | import { Route, Switch } from 'react-router-dom'; 5 | import { ConnectedRouter } from 'connected-react-router'; 6 | import SweetAlert from 'react-bootstrap-sweetalert'; 7 | import './App.css'; 8 | import { history } from '../../store'; 9 | import {getVisibleAlert} from "../../reducers/notifications"; 10 | import Footer from '../../components/Footer'; 11 | import HeaderContainer from '../HeaderContainer'; 12 | import HomeContainer from '../HomeContainer'; 13 | import NoMatch from "./NoMatch"; 14 | 15 | const App = ({ visibleAlert }) => ( 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | {visibleAlert && {visibleAlert.content}} 26 | 27 |
28 |
29 |
30 | ); 31 | 32 | App.propTypes = { 33 | visibleAlert: PropTypes.any, 34 | }; 35 | 36 | const mapStateToProps = state => ({ 37 | visibleAlert: getVisibleAlert(state.notifications), 38 | }); 39 | 40 | export default connect( 41 | mapStateToProps, 42 | {} 43 | )(App); 44 | -------------------------------------------------------------------------------- /examples/redux/src/containers/HeaderContainer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Navbar} from 'react-bootstrap'; 3 | import {connect} from "react-redux"; 4 | import HeaderNav from "../components/HeaverNav"; 5 | 6 | class HeaderContainer extends React.Component { 7 | 8 | constructor(props) { 9 | super(props); 10 | this.state = { navExpanded: false }; 11 | } 12 | 13 | componentDidMount() { 14 | document.addEventListener('click', this.onClickOutside); 15 | } 16 | 17 | componentWillUnmount() { 18 | document.removeEventListener('click', this.onClickOutside); 19 | } 20 | 21 | onClickOutside = (event) => { 22 | const closestCollapse = event.target.closest('.navbar-collapse'); 23 | const closestToggler = event.target.closest('.navbar-toggler'); 24 | 25 | if (closestCollapse || closestToggler) return; 26 | 27 | if (this.state.navExpanded) { 28 | this.setNavExpanded(false); 29 | } 30 | }; 31 | 32 | setNavExpanded = (expanded) => { 33 | this.setState({ navExpanded: expanded }); 34 | }; 35 | 36 | closeNav = () => { 37 | this.setNavExpanded(false); 38 | }; 39 | 40 | render() { 41 | 42 | return ( 43 | 51 | 52 |
53 | {'Example'} 54 |
55 |
56 | 57 | 58 | 59 | 60 |
61 | ); 62 | } 63 | } 64 | 65 | HeaderContainer.propTypes = { 66 | }; 67 | 68 | const mapStateToProps = state => ({ 69 | }); 70 | 71 | export default connect( 72 | mapStateToProps, 73 | {} 74 | )(HeaderContainer); 75 | -------------------------------------------------------------------------------- /examples/redux/src/containers/HomeContainer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { connect } from 'react-redux'; 4 | import { withRouter } from 'react-router-dom'; 5 | import {Button} from "react-bootstrap"; 6 | import { showAlert} from '../actions'; 7 | 8 | const HomeContainer = ({ showAlert }) => ( 9 |
10 |
11 | 19 |
20 |
21 | ); 22 | 23 | HomeContainer.propTypes = { 24 | showAlert: PropTypes.func.isRequired, 25 | }; 26 | 27 | const mapStateToProps = () => ({ 28 | }); 29 | 30 | export default connect( 31 | mapStateToProps, 32 | { showAlert } 33 | )(withRouter(HomeContainer)); 34 | -------------------------------------------------------------------------------- /examples/redux/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from 'react-dom'; 3 | import { Provider } from 'react-redux'; 4 | import store from './store'; 5 | import App from './containers/App'; 6 | import * as serviceWorker from './serviceWorker'; 7 | import './styles/index.scss'; 8 | 9 | global.fetch = require('node-fetch'); 10 | 11 | render( 12 | 13 | 14 | , 15 | document.getElementById('root') 16 | ); 17 | 18 | // If you want your app to work offline and load faster, you can change 19 | // unregister() to register() below. Note this comes with some pitfalls. 20 | // Learn more about service workers: https://bit.ly/CRA-PWA 21 | serviceWorker.unregister(); 22 | 23 | -------------------------------------------------------------------------------- /examples/redux/src/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | import { connectRouter } from 'connected-react-router'; 3 | import notifications from './notifications'; 4 | 5 | export default (history) => combineReducers({ 6 | router: connectRouter(history), 7 | notifications, 8 | }); 9 | -------------------------------------------------------------------------------- /examples/redux/src/reducers/notifications.js: -------------------------------------------------------------------------------- 1 | import { 2 | ADD_ALERT, 3 | REMOVE_ALERT, 4 | } from '../constants/ActionTypes'; 5 | 6 | const initialState = { 7 | alerts: [], 8 | }; 9 | 10 | const alerts = (state = initialState, action) => { 11 | switch (action.type) { 12 | case ADD_ALERT: 13 | return { 14 | ...state, 15 | alerts: [...state.alerts, action.alert] 16 | }; 17 | case REMOVE_ALERT: 18 | return { 19 | ...state, 20 | alerts: [...state.alerts].filter(a => a.id !== action.id) 21 | }; 22 | default: 23 | return state; 24 | } 25 | }; 26 | 27 | export const getVisibleAlert = (state) => (state.alerts && state.alerts.length > 0) ? state.alerts[0] : null; 28 | 29 | export default alerts; -------------------------------------------------------------------------------- /examples/redux/src/serviceWorker.js: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read https://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === '[::1]' || 17 | // 127.0.0.1/8 is considered localhost for IPv4. 18 | window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ); 22 | 23 | export function register(config) { 24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 25 | // The URL constructor is available in all browsers that support SW. 26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); 27 | if (publicUrl.origin !== window.location.origin) { 28 | // Our service worker won't work if PUBLIC_URL is on a different origin 29 | // from what our page is served on. This might happen if a CDN is used to 30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 31 | return; 32 | } 33 | 34 | window.addEventListener('load', () => { 35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 36 | 37 | if (isLocalhost) { 38 | // This is running on localhost. Let's check if a service worker still exists or not. 39 | checkValidServiceWorker(swUrl, config); 40 | 41 | // Add some additional logging to localhost, pointing developers to the 42 | // service worker/PWA documentation. 43 | navigator.serviceWorker.ready.then(() => { 44 | console.log( 45 | 'This web app is being served cache-first by a service ' + 46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA' 47 | ); 48 | }); 49 | } else { 50 | // Is not localhost. Just register service worker 51 | registerValidSW(swUrl, config); 52 | } 53 | }); 54 | } 55 | } 56 | 57 | function registerValidSW(swUrl, config) { 58 | navigator.serviceWorker 59 | .register(swUrl) 60 | .then(registration => { 61 | registration.onupdatefound = () => { 62 | const installingWorker = registration.installing; 63 | if (installingWorker == null) { 64 | return; 65 | } 66 | installingWorker.onstatechange = () => { 67 | if (installingWorker.state === 'installed') { 68 | if (navigator.serviceWorker.controller) { 69 | // At this point, the updated precached content has been fetched, 70 | // but the previous service worker will still serve the older 71 | // content until all client tabs are closed. 72 | console.log( 73 | 'New content is available and will be used when all ' + 74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' 75 | ); 76 | 77 | // Execute callback 78 | if (config && config.onUpdate) { 79 | config.onUpdate(registration); 80 | } 81 | } else { 82 | // At this point, everything has been precached. 83 | // It's the perfect time to display a 84 | // "Content is cached for offline use." message. 85 | console.log('Content is cached for offline use.'); 86 | 87 | // Execute callback 88 | if (config && config.onSuccess) { 89 | config.onSuccess(registration); 90 | } 91 | } 92 | } 93 | }; 94 | }; 95 | }) 96 | .catch(error => { 97 | console.error('Error during service worker registration:', error); 98 | }); 99 | } 100 | 101 | function checkValidServiceWorker(swUrl, config) { 102 | // Check if the service worker can be found. If it can't reload the page. 103 | fetch(swUrl) 104 | .then(response => { 105 | // Ensure service worker exists, and that we really are getting a JS file. 106 | const contentType = response.headers.get('content-type'); 107 | if ( 108 | response.status === 404 || 109 | (contentType != null && contentType.indexOf('javascript') === -1) 110 | ) { 111 | // No service worker found. Probably a different app. Reload the page. 112 | navigator.serviceWorker.ready.then(registration => { 113 | registration.unregister().then(() => { 114 | window.location.reload(); 115 | }); 116 | }); 117 | } else { 118 | // Service worker found. Proceed as normal. 119 | registerValidSW(swUrl, config); 120 | } 121 | }) 122 | .catch(() => { 123 | console.log( 124 | 'No internet connection found. App is running in offline mode.' 125 | ); 126 | }); 127 | } 128 | 129 | export function unregister() { 130 | if ('serviceWorker' in navigator) { 131 | navigator.serviceWorker.ready.then(registration => { 132 | registration.unregister(); 133 | }); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /examples/redux/src/store.js: -------------------------------------------------------------------------------- 1 | import thunk from "redux-thunk"; 2 | import {createLogger} from "redux-logger"; 3 | import {applyMiddleware, compose, createStore} from "redux"; 4 | import { createBrowserHistory } from 'history'; 5 | import { routerMiddleware } from 'connected-react-router'; 6 | import createRootReducer from './reducers'; 7 | 8 | const middleware = [ thunk ]; 9 | if (process.env.NODE_ENV !== 'production') { 10 | middleware.push(createLogger()); 11 | } 12 | 13 | export const history = createBrowserHistory(); 14 | 15 | export default createStore( 16 | createRootReducer(history), // root reducer with router state 17 | compose( 18 | applyMiddleware( 19 | routerMiddleware(history), // for dispatching history actions 20 | ...middleware, 21 | ), 22 | ), 23 | ); 24 | -------------------------------------------------------------------------------- /examples/redux/src/styles/app.scss: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 4 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | html, body, #root { 11 | width: 100%; 12 | height: 100%; 13 | } 14 | 15 | *:not(.fa) { 16 | font-family: 'Ubuntu', sans-serif !important; 17 | } 18 | 19 | button:focus, 20 | .btn:focus { 21 | outline: none !important; 22 | } 23 | -------------------------------------------------------------------------------- /examples/redux/src/styles/bootstrap.scss: -------------------------------------------------------------------------------- 1 | // Variable overrides 2 | $white: #fff !default; 3 | $gray-100: #f8f9fa !default; 4 | $gray-200: #e9ecef !default; 5 | $gray-300: #dee2e6 !default; 6 | $gray-400: #ced4da !default; 7 | $gray-500: #adb5bd !default; 8 | $gray-600: #6c757d !default; 9 | $gray-700: #495057 !default; 10 | $gray-800: #343a40 !default; 11 | $gray-900: #212529 !default; 12 | $black: #000 !default; 13 | 14 | $blue: #007bff !default; 15 | $indigo: #6610f2 !default; 16 | $purple: #6f42c1 !default; 17 | $pink: #e83e8c !default; 18 | $red: #bb0718 !default; 19 | $orange: #fd7e14 !default; 20 | $yellow: #ffc107 !default; 21 | $green: #28a745 !default; 22 | $teal: #20c997 !default; 23 | $cyan: #17a2b8 !default; 24 | $paleBlue: #ccf5ff !default; 25 | 26 | $primary: $gray-800 !default; 27 | $secondary: $yellow !default; 28 | $success: $green !default; 29 | $info: $paleBlue !default; 30 | $warning: $yellow !default; 31 | $danger: $red !default; 32 | $light: $gray-200 !default; 33 | $dark: $gray-700 !default; 34 | 35 | $border-radius: .05rem !default; 36 | $border-radius-lg: .1rem !default; 37 | $border-radius-sm: .08rem !default; 38 | 39 | $navbar-dark-toggler-border-color: rgba($white, 0) !default; 40 | 41 | $transition-collapse: height .1s ease !default; 42 | 43 | // Load Bootstrap and its default variables 44 | @import '../../node_modules/bootstrap/scss/bootstrap'; 45 | -------------------------------------------------------------------------------- /examples/redux/src/styles/index.scss: -------------------------------------------------------------------------------- 1 | @import './bootstrap.scss'; 2 | @import './app.scss'; 3 | @import 'overrides'; 4 | 5 | -------------------------------------------------------------------------------- /examples/redux/src/styles/overrides.scss: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp'); 2 | const inject = require("gulp-inject-file"); 3 | 4 | gulp.task('default', async () => { 5 | 6 | }); 7 | 8 | gulp.task('copy-css', async () => { 9 | return gulp.src('./src/css/**/*') 10 | .pipe(gulp.dest('./dist/css')); 11 | }); 12 | 13 | gulp.task('inject-css', async () => { 14 | return gulp.src('./dist/components/SweetAlert.js') 15 | .pipe(inject({ 16 | pattern: '', 17 | transform: (content) => { 18 | // remove whitespace 19 | return content.replace(/[\r\t\n]/g, ''); 20 | } 21 | })) 22 | .pipe(gulp.dest('./dist/components')); 23 | }); -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | React Bootstrap SweetAlert Demo 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-bootstrap-sweetalert", 3 | "version": "5.2.0", 4 | "description": "A variant of sweetalert for use with React and Bootstrap", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "preversion": "yarn build", 8 | "postversion": "git push && git push --tags && npm publish", 9 | "test": "echo \"Error: no test specified\" && exit 1", 10 | "lint": "tslint -c tslint.json 'src/**/*.ts' --fix", 11 | "build": "yarn lint && rm -rf ./dist && tsc --declaration && yarn inject-css", 12 | "build-demo": "cd ./src/demo && NODE_ENV=development webpack", 13 | "start-demo": "NODE_ENV=development node ./demo/demo-server.js", 14 | "demo": "yarn build-demo && yarn start-demo && yarn open", 15 | "inject-css": "gulp copy-css && gulp inject-css", 16 | "open": "open http://localhost:3000" 17 | }, 18 | "files": [ 19 | "dist", 20 | "!dist/demo" 21 | ], 22 | "repository": { 23 | "type": "git", 24 | "url": "git+https://djorg83@github.com/djorg83/react-bootstrap-sweetalert.git" 25 | }, 26 | "keywords": [ 27 | "react", 28 | "bootstrap", 29 | "alert", 30 | "sweetalert", 31 | "confirm", 32 | "modal" 33 | ], 34 | "author": "Daniel Jorgensen", 35 | "license": "MIT", 36 | "bugs": { 37 | "url": "https://github.com/djorg83/react-bootstrap-sweetalert/issues" 38 | }, 39 | "homepage": "http://djorg83.github.io/react-bootstrap-sweetalert/", 40 | "peerDependencies": { 41 | "prop-types": ">=15.0.0", 42 | "react": ">=16.0.0" 43 | }, 44 | "resolutions": { 45 | "@types/react": "16.9.43" 46 | }, 47 | "devDependencies": { 48 | "@types/node": "^12.7.1", 49 | "@types/react": "^16.9.43", 50 | "@types/react-dom": "^16.9.8", 51 | "css-loader": "^3.2.0", 52 | "express": "^4.17.1", 53 | "gulp": "^4.0.2", 54 | "gulp-inject-file": "0.0.19", 55 | "prop-types": "^15.7.2", 56 | "react": "^16.13.1", 57 | "react-bootstrap": "^1.3.0", 58 | "react-dom": "^16.13.1", 59 | "react-tools": "^0.13.3", 60 | "source-map-loader": "^0.2.4", 61 | "style-loader": "^1.0.0", 62 | "ts-loader": "^6.0.4", 63 | "typescript": "^3.9.7", 64 | "webpack": "^4.39.1", 65 | "webpack-cli": "^3.3.6" 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/components/Buttons.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import * as styles from '../styles/SweetAlertStyles'; 3 | import {SweetAlertProps} from "../types"; 4 | import {actions as actionsStyle } from "../styles/SweetAlertStyles"; 5 | 6 | export default class Buttons extends React.Component { 7 | 8 | static defaultProps = { 9 | confirmBtnText: 'OK', 10 | confirmBtnBsStyle: 'primary', 11 | confirmBtnCssClass: '', 12 | confirmBtnStyle: {}, 13 | cancelBtnText: 'Cancel', 14 | cancelBtnBsStyle: 'link', 15 | cancelBtnCssClass: '', 16 | cancelBtnStyle: {}, 17 | focusConfirmBtn: true, 18 | focusCancelBtn: false, 19 | showConfirm: true, 20 | showCancel: false, 21 | reverseButtons: false, 22 | btnSize: 'lg', 23 | }; 24 | 25 | static styles: { [key: string]: { borderColor: string, shadowColor: string } } = { 26 | primary: { 27 | borderColor: '#286090', 28 | shadowColor: 'rgb(165, 202, 234)' 29 | }, 30 | success: { 31 | borderColor: '#4cae4c', 32 | shadowColor: 'rgba(76, 174, 76, 0.6)' 33 | }, 34 | info: { 35 | borderColor: '#46b8da', 36 | shadowColor: 'rgba(70, 184, 218, 0.6)' 37 | }, 38 | danger: { 39 | borderColor: '#d43f3a', 40 | shadowColor: 'rgba(212, 63, 58, 0.6)' 41 | }, 42 | warning: { 43 | borderColor: '#eea236', 44 | shadowColor: 'rgba(238, 162, 54, 0.6)' 45 | }, 46 | default: { 47 | borderColor: '#cccccc', 48 | shadowColor: 'rgba(204, 204, 204, 0.6)' 49 | }, 50 | secondary: { 51 | borderColor: '#cccccc', 52 | shadowColor: 'rgba(204, 204, 204, 0.6)' 53 | } 54 | }; 55 | 56 | private buttonStyles = {}; 57 | private confirmButtonElement: HTMLAnchorElement = null; 58 | private cancelButtonElement: HTMLAnchorElement = null; 59 | 60 | componentDidMount() { 61 | this.focusButton(); 62 | } 63 | 64 | componentDidUpdate(prevProps: SweetAlertProps) { 65 | // when displaying back to back alerts React will treat this 66 | // as an update to the same alert. this causes componentDidMount 67 | // to not be called for the subsequent alerts. i hope to find a better 68 | // way to handle this in the future, but for now i'm checking if the 69 | // title, type, or button text has changed 70 | if ( 71 | prevProps.type !== this.props.type || 72 | prevProps.confirmBtnText !== this.props.confirmBtnText || 73 | prevProps.title !== this.props.title 74 | ) { 75 | setTimeout(() => this.focusButton(), 0); 76 | } 77 | } 78 | 79 | setConfirmButtonElementRef = (element: HTMLAnchorElement) => { 80 | this.confirmButtonElement = element; 81 | }; 82 | 83 | setCancelButtonElementRef = (element: HTMLAnchorElement) => { 84 | this.cancelButtonElement = element; 85 | }; 86 | 87 | focusButton() { 88 | if (this.props.focusCancelBtn && this.cancelButtonElement) { 89 | try { 90 | this.cancelButtonElement.focus(); 91 | } catch (e) { 92 | // whoops 93 | } 94 | } else if (this.props.focusConfirmBtn && this.confirmButtonElement) { 95 | try { 96 | this.confirmButtonElement.focus(); 97 | } catch (e) { 98 | // whoops 99 | } 100 | } 101 | } 102 | 103 | getButtonStyle = (bsStyle: string) => { 104 | if (bsStyle === 'error') bsStyle = 'danger'; 105 | if (this.buttonStyles[bsStyle] == null) { 106 | const style = Buttons.styles[bsStyle] || Buttons.styles.default; 107 | this.buttonStyles[bsStyle] = { 108 | borderColor: `${style.borderColor}`, 109 | boxShadow: `inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px ${style.shadowColor}`, 110 | }; 111 | } 112 | return this.buttonStyles[bsStyle]; 113 | }; 114 | 115 | confirmButtonRender() { 116 | if(!this.props.showConfirm) 117 | return false; 118 | 119 | const confirmBtnBsStyle = this.props.confirmBtnBsStyle === 'error' ? 'danger' : this.props.confirmBtnBsStyle; 120 | const confirmButtonStyle = Object.assign( 121 | {}, 122 | styles.button, 123 | this.getButtonStyle(confirmBtnBsStyle), 124 | this.props.confirmBtnStyle || {} 125 | ); 126 | 127 | /** 128 | * These buttons are anchor tags because for some reason React is triggering click events on