dce-reactkit 3.0.22 → 3.0.25

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.
@@ -4,7 +4,10 @@
4
4
  */
5
5
 
6
6
  // Import React
7
- import React from 'react';
7
+ import React, { useState, useEffect } from 'react';
8
+
9
+ // Import other components
10
+ import waitMs from '../helpers/waitMs';
8
11
 
9
12
  // Import types
10
13
  import Variant from '../types/Variant';
@@ -114,7 +117,6 @@ const style = `
114
117
  height: 100vw;
115
118
  background-color: rgba(0, 0, 0, 0.7);
116
119
  }
117
-
118
120
  .Modal-fading-in {
119
121
  animation-name: Modal-fading-in;
120
122
  animation-duration: ${Math.floor(MS_TO_ANIMATE * 2)}ms;
@@ -122,7 +124,6 @@ const style = `
122
124
  animation-fill-mode: both;
123
125
  animation-timing-function: ease-out;
124
126
  }
125
-
126
127
  @keyframes Modal-fading-in {
127
128
  0% {
128
129
  opacity: 0;
@@ -131,7 +132,21 @@ const style = `
131
132
  opacity: 1;
132
133
  }
133
134
  }
134
-
135
+ .Modal-fading-out {
136
+ animation-name: Modal-fading-out;
137
+ animation-duration: ${MS_TO_ANIMATE}ms;
138
+ animation-iteration-count: 1;
139
+ animation-fill-mode: both;
140
+ animation-timing-function: ease-in;
141
+ }
142
+ @keyframes Modal-fading-out {
143
+ 0% {
144
+ opacity: 1;
145
+ }
146
+ 100% {
147
+ opacity: 0;
148
+ }
149
+ }
135
150
  .Modal-animating-in {
136
151
  animation-name: Modal-animating-in;
137
152
  animation-duration: ${MS_TO_ANIMATE}ms;
@@ -139,7 +154,6 @@ const style = `
139
154
  animation-fill-mode: both;
140
155
  animation-timing-function: ease-out;
141
156
  }
142
-
143
157
  @keyframes Modal-animating-in {
144
158
  0% {
145
159
  transform: scale(1.05) translate(0, -1.5rem);
@@ -150,6 +164,44 @@ const style = `
150
164
  opacity: 1;
151
165
  }
152
166
  }
167
+ .Modal-animating-pop {
168
+ animation-name: Modal-animating-pop;
169
+ animation-duration: ${MS_TO_ANIMATE}ms;
170
+ animation-iteration-count: 1;
171
+ animation-fill-mode: both;
172
+ animation-timing-function: ease-in-out;
173
+ }
174
+ @keyframes Modal-animating-pop {
175
+ 0% {
176
+ transform: scale(1);
177
+ opacity: 1;
178
+ }
179
+ 50% {
180
+ transform: scale(1.05);
181
+ opacity: 0.9;
182
+ }
183
+ 100% {
184
+ transform: scale(1);
185
+ opacity: 1;
186
+ }
187
+ }
188
+ .Modal-animating-out {
189
+ animation-name: Modal-animating-out;
190
+ animation-duration: ${MS_TO_ANIMATE}ms;
191
+ animation-iteration-count: 1;
192
+ animation-fill-mode: both;
193
+ animation-timing-function: ease-in;
194
+ }
195
+ @keyframes Modal-animating-out {
196
+ 0% {
197
+ transform: scale(1) translate(0, 0);
198
+ opacity: 1;
199
+ }
200
+ 100% {
201
+ transform: scale(1.05) translate(0, -1.5rem);
202
+ opacity: 0;
203
+ }
204
+ }
153
205
  `;
154
206
 
155
207
  /*------------------------------------------------------------------------*/
@@ -234,6 +286,77 @@ const Modal: React.FC<Props> = (props) => {
234
286
  onTopOfOtherModals,
235
287
  } = props;
236
288
 
289
+ /* -------------- State ------------- */
290
+
291
+ // If true, the modal is shown
292
+ const [visible, setVisible] = useState(false);
293
+
294
+ // True if animation is in use
295
+ const [animatingIn, setAnimatingIn] = useState(true);
296
+ const [animatingPop, setAnimatingPop] = useState(false);
297
+ const [animatingOut, setAnimatingOut] = useState(false);
298
+
299
+ /*------------------------------------------------------------------------*/
300
+ /* Lifecycle Functions */
301
+ /*------------------------------------------------------------------------*/
302
+
303
+ /**
304
+ * Mount
305
+ * @author Gabe Abrams
306
+ */
307
+ useEffect(
308
+ () => {
309
+ (async () => {
310
+ // Set defaults
311
+ setVisible(false);
312
+ setAnimatingIn(true);
313
+ setAnimatingPop(false);
314
+ setAnimatingOut(false);
315
+ // Wait for animation
316
+ await waitMs(MS_TO_ANIMATE);
317
+ // Update to state after animated in
318
+ setVisible(true);
319
+ setAnimatingIn(false);
320
+ })();
321
+ },
322
+ [],
323
+ );
324
+
325
+ /*------------------------------------------------------------------------*/
326
+ /* Component Functions */
327
+ /*------------------------------------------------------------------------*/
328
+
329
+ /**
330
+ * Handles the closing of the modal
331
+ * @author Gabe Abrams
332
+ * @param ModalButtonType the button that was clicked when closing the
333
+ * modal
334
+ */
335
+ const handleClose = async (ModalButtonType: ModalButtonType) => {
336
+ // Don't close if no handler
337
+ if (!onClose) {
338
+ return;
339
+ }
340
+
341
+ // Don't close if animating in
342
+ if (animatingIn) {
343
+ return;
344
+ }
345
+
346
+ // Don't close if already closed
347
+ if (!visible) {
348
+ return;
349
+ }
350
+
351
+ // Update the state
352
+ setVisible(false);
353
+ setAnimatingOut(true);
354
+
355
+ // Call the handler after the modal has animated out
356
+ await waitMs(MS_TO_ANIMATE);
357
+ onClose(ModalButtonType);
358
+ };
359
+
237
360
  /*------------------------------------------------------------------------*/
238
361
  /* Render */
239
362
  /*------------------------------------------------------------------------*/
@@ -246,19 +369,19 @@ const Modal: React.FC<Props> = (props) => {
246
369
  const ModalButtonTypes: ModalButtonType[] = modalTypeToModalButtonTypes[type] ?? [];
247
370
 
248
371
  // Create buttons
249
- const buttons = ModalButtonTypes.map((buttonType: ModalButtonType, i) => {
372
+ const buttons = ModalButtonTypes.map((ModalButtonType: ModalButtonType, i) => {
250
373
  // Get default style
251
374
  let {
252
375
  label,
253
376
  variant,
254
- } = ModalButtonTypeToLabelAndVariant[buttonType];
377
+ } = ModalButtonTypeToLabelAndVariant[ModalButtonType];
255
378
 
256
379
  // Override with customizations
257
- const newLabel = props[`${buttonType}Label`];
380
+ const newLabel = props[`${ModalButtonType}Label`];
258
381
  if (newLabel) {
259
382
  label = newLabel;
260
383
  }
261
- const newVariant = props[`${buttonType}Variant`];
384
+ const newVariant = props[`${ModalButtonType}Variant`];
262
385
  if (newVariant) {
263
386
  variant = newVariant;
264
387
  }
@@ -269,13 +392,11 @@ const Modal: React.FC<Props> = (props) => {
269
392
  // Create the button
270
393
  return (
271
394
  <button
272
- key={buttonType}
395
+ key={ModalButtonType}
273
396
  type="button"
274
- className={`Modal-${buttonType}-button btn btn-${variant} ${last ? '' : 'me-1'}`}
397
+ className={`Modal-${ModalButtonType}-button btn btn-${variant} ${last ? '' : 'me-1'}`}
275
398
  onClick={() => {
276
- if (onClose) {
277
- onClose(buttonType);
278
- }
399
+ handleClose(ModalButtonType);
279
400
  }}
280
401
  >
281
402
  {label}
@@ -294,10 +415,23 @@ const Modal: React.FC<Props> = (props) => {
294
415
  : undefined
295
416
  );
296
417
 
418
+ // Choose an animation
419
+ let animationClass = '';
420
+ let backdropAnimationClass = '';
421
+ if (animatingIn) {
422
+ animationClass = 'Modal-animating-in';
423
+ backdropAnimationClass = 'Modal-fading-in';
424
+ } else if (animatingOut) {
425
+ animationClass = 'Modal-animating-out';
426
+ backdropAnimationClass = 'Modal-fading-out';
427
+ } else if (animatingPop) {
428
+ animationClass = 'Modal-animating-pop';
429
+ }
430
+
297
431
  // Render the modal
298
432
  return (
299
433
  <div
300
- className="modal show modal-dialog-scrollable modal-dialog-centered"
434
+ className={`modal show modal-dialog-scrollable modal-dialog-centered`}
301
435
  tabIndex={-1}
302
436
  style={{
303
437
  zIndex: (
@@ -313,22 +447,29 @@ const Modal: React.FC<Props> = (props) => {
313
447
  >
314
448
  <style>{style}</style>
315
449
  <div
316
- className="Modal-backdrop Modal-fading-in"
450
+ className={`Modal-backdrop ${backdropAnimationClass}`}
317
451
  style={{
318
452
  zIndex: 5000000003,
319
453
  }}
320
454
  onClick={async () => {
321
455
  // Skip if exit via backdrop not allowed
322
456
  if (dontAllowBackdropExit || !onClose) {
457
+ // Show pop animation
458
+ if (!animatingPop) {
459
+ setAnimatingPop(true);
460
+
461
+ // Wait then stop pop animation
462
+ await waitMs(MS_TO_ANIMATE);
463
+ setAnimatingPop(false);
464
+ }
323
465
  return;
324
466
  }
325
-
326
467
  // Handle close
327
- onClose(ModalButtonType.Cancel);
468
+ handleClose(ModalButtonType.Cancel);
328
469
  }}
329
470
  />
330
471
  <div
331
- className={`modal-dialog modal-${size} Modal-animating-in`}
472
+ className={`modal-dialog modal-${size} ${animationClass}`}
332
473
  style={{
333
474
  zIndex: 5000000002,
334
475
  }}
@@ -351,7 +492,7 @@ const Modal: React.FC<Props> = (props) => {
351
492
  aria-label="Close"
352
493
  onClick={() => {
353
494
  // Handle close
354
- onClose(ModalButtonType.Cancel);
495
+ handleClose(ModalButtonType.Cancel);
355
496
  }}
356
497
  />
357
498
  )}