dce-reactkit 2.0.11 → 3.0.0-beta.10

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.
Files changed (129) hide show
  1. package/dist/cjs/index.js +921 -0
  2. package/dist/cjs/index.js.map +1 -0
  3. package/{lib → dist/cjs/types}/components/AppWrapper.d.ts +9 -4
  4. package/{lib → dist/cjs/types}/components/ErrorBox.d.ts +0 -0
  5. package/{lib → dist/cjs/types}/components/LoadingSpinner.d.ts +1 -0
  6. package/{lib → dist/cjs/types}/components/Modal.d.ts +5 -36
  7. package/{lib → dist/cjs/types}/components/TabBox.d.ts +0 -0
  8. package/{lib → dist/cjs/types}/errors/ErrorWithCode.d.ts +0 -0
  9. package/{lib → dist/cjs/types}/helpers/abbreviate.d.ts +1 -0
  10. package/{lib → dist/cjs/types}/helpers/avg.d.ts +0 -0
  11. package/{lib → dist/cjs/types}/helpers/ceilToNumDecimals.d.ts +0 -0
  12. package/{lib → dist/cjs/types}/helpers/floorToNumDecimals.d.ts +0 -0
  13. package/{lib → dist/cjs/types}/helpers/forceNumIntoBounds.d.ts +0 -0
  14. package/{lib → dist/cjs/types}/helpers/padDecimalZeros.d.ts +0 -0
  15. package/{lib → dist/cjs/types}/helpers/padZerosLeft.d.ts +0 -0
  16. package/{lib → dist/cjs/types}/helpers/roundToNumDecimals.d.ts +0 -0
  17. package/{lib → dist/cjs/types}/helpers/sum.d.ts +0 -0
  18. package/{lib → dist/cjs/types}/helpers/waitMs.d.ts +0 -0
  19. package/dist/cjs/types/index.d.ts +22 -0
  20. package/dist/cjs/types/types/ModalButtonType.d.ts +17 -0
  21. package/dist/cjs/types/types/ModalSize.d.ts +11 -0
  22. package/dist/cjs/types/types/ModalType.d.ts +16 -0
  23. package/{lib → dist/cjs/types}/types/ReactKitErrorCode.d.ts +0 -0
  24. package/{lib → dist/cjs/types}/types/Variant.d.ts +0 -0
  25. package/dist/esm/index.js +890 -0
  26. package/dist/esm/index.js.map +1 -0
  27. package/dist/esm/types/components/AppWrapper.d.ts +40 -0
  28. package/dist/esm/types/components/ErrorBox.d.ts +12 -0
  29. package/dist/esm/types/components/LoadingSpinner.d.ts +7 -0
  30. package/dist/esm/types/components/Modal.d.ts +40 -0
  31. package/dist/esm/types/components/TabBox.d.ts +11 -0
  32. package/dist/esm/types/errors/ErrorWithCode.d.ts +9 -0
  33. package/dist/esm/types/helpers/abbreviate.d.ts +10 -0
  34. package/dist/esm/types/helpers/avg.d.ts +8 -0
  35. package/dist/esm/types/helpers/ceilToNumDecimals.d.ts +9 -0
  36. package/dist/esm/types/helpers/floorToNumDecimals.d.ts +9 -0
  37. package/dist/esm/types/helpers/forceNumIntoBounds.d.ts +10 -0
  38. package/dist/esm/types/helpers/padDecimalZeros.d.ts +10 -0
  39. package/dist/esm/types/helpers/padZerosLeft.d.ts +9 -0
  40. package/dist/esm/types/helpers/roundToNumDecimals.d.ts +9 -0
  41. package/dist/esm/types/helpers/sum.d.ts +8 -0
  42. package/dist/esm/types/helpers/waitMs.d.ts +7 -0
  43. package/dist/esm/types/index.d.ts +22 -0
  44. package/dist/esm/types/types/ModalButtonType.d.ts +17 -0
  45. package/dist/esm/types/types/ModalSize.d.ts +11 -0
  46. package/dist/esm/types/types/ModalType.d.ts +16 -0
  47. package/dist/esm/types/types/ReactKitErrorCode.d.ts +13 -0
  48. package/dist/esm/types/types/Variant.d.ts +15 -0
  49. package/dist/index.d.ts +274 -0
  50. package/package.json +23 -15
  51. package/rollup.config.js +45 -0
  52. package/src/components/AppWrapper.tsx +38 -37
  53. package/src/components/LoadingSpinner.tsx +3 -0
  54. package/src/components/Modal.tsx +86 -173
  55. package/src/helpers/abbreviate.tsx +2 -0
  56. package/src/helpers/padDecimalZeros.tsx +1 -1
  57. package/src/index.ts +61 -0
  58. package/src/types/ModalButtonType.tsx +18 -0
  59. package/src/types/ModalSize.tsx +12 -0
  60. package/src/types/ModalType.tsx +17 -0
  61. package/tsconfig.json +16 -17
  62. package/lib/components/AppWrapper.js +0 -277
  63. package/lib/components/AppWrapper.js.map +0 -1
  64. package/lib/components/ErrorBox.js +0 -65
  65. package/lib/components/ErrorBox.js.map +0 -1
  66. package/lib/components/LoadingSpinner.js +0 -41
  67. package/lib/components/LoadingSpinner.js.map +0 -1
  68. package/lib/components/Modal.js +0 -321
  69. package/lib/components/Modal.js.map +0 -1
  70. package/lib/components/TabBox.js +0 -42
  71. package/lib/components/TabBox.js.map +0 -1
  72. package/lib/errors/ErrorWithCode.js +0 -33
  73. package/lib/errors/ErrorWithCode.js.map +0 -1
  74. package/lib/helpers/abbreviate.js +0 -21
  75. package/lib/helpers/abbreviate.js.map +0 -1
  76. package/lib/helpers/alert.d.ts +0 -2
  77. package/lib/helpers/alert.js +0 -5
  78. package/lib/helpers/alert.js.map +0 -1
  79. package/lib/helpers/avg.js +0 -24
  80. package/lib/helpers/avg.js.map +0 -1
  81. package/lib/helpers/ceilToNumDecimals.js +0 -15
  82. package/lib/helpers/ceilToNumDecimals.js.map +0 -1
  83. package/lib/helpers/confirm.d.ts +0 -2
  84. package/lib/helpers/confirm.js +0 -5
  85. package/lib/helpers/confirm.js.map +0 -1
  86. package/lib/helpers/floorToNumDecimals.js +0 -15
  87. package/lib/helpers/floorToNumDecimals.js.map +0 -1
  88. package/lib/helpers/forceNumIntoBounds.js +0 -15
  89. package/lib/helpers/forceNumIntoBounds.js.map +0 -1
  90. package/lib/helpers/handleError.d.ts +0 -14
  91. package/lib/helpers/handleError.js +0 -54
  92. package/lib/helpers/handleError.js.map +0 -1
  93. package/lib/helpers/handleSuccess.d.ts +0 -8
  94. package/lib/helpers/handleSuccess.js +0 -20
  95. package/lib/helpers/handleSuccess.js.map +0 -1
  96. package/lib/helpers/padDecimalZeros.js +0 -30
  97. package/lib/helpers/padDecimalZeros.js.map +0 -1
  98. package/lib/helpers/padZerosLeft.js +0 -21
  99. package/lib/helpers/padZerosLeft.js.map +0 -1
  100. package/lib/helpers/parseRequest.d.ts +0 -21
  101. package/lib/helpers/parseRequest.js +0 -240
  102. package/lib/helpers/parseRequest.js.map +0 -1
  103. package/lib/helpers/roundToNumDecimals.js +0 -15
  104. package/lib/helpers/roundToNumDecimals.js.map +0 -1
  105. package/lib/helpers/showFatalError.d.ts +0 -2
  106. package/lib/helpers/showFatalError.js +0 -5
  107. package/lib/helpers/showFatalError.js.map +0 -1
  108. package/lib/helpers/sum.js +0 -15
  109. package/lib/helpers/sum.js.map +0 -1
  110. package/lib/helpers/visitServerEndpoint.d.ts +0 -23
  111. package/lib/helpers/visitServerEndpoint.js +0 -135
  112. package/lib/helpers/visitServerEndpoint.js.map +0 -1
  113. package/lib/helpers/waitMs.js +0 -55
  114. package/lib/helpers/waitMs.js.map +0 -1
  115. package/lib/types/ParamType.d.ts +0 -17
  116. package/lib/types/ParamType.js +0 -21
  117. package/lib/types/ParamType.js.map +0 -1
  118. package/lib/types/ReactKitErrorCode.js +0 -18
  119. package/lib/types/ReactKitErrorCode.js.map +0 -1
  120. package/lib/types/Variant.js +0 -19
  121. package/lib/types/Variant.js.map +0 -1
  122. package/src/helpers/alert.tsx +0 -3
  123. package/src/helpers/confirm.tsx +0 -3
  124. package/src/helpers/handleError.ts +0 -65
  125. package/src/helpers/handleSuccess.ts +0 -18
  126. package/src/helpers/parseRequest.ts +0 -299
  127. package/src/helpers/showFatalError.tsx +0 -3
  128. package/src/helpers/visitServerEndpoint.tsx +0 -110
  129. package/src/types/ParamType.ts +0 -18
@@ -0,0 +1,921 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var React = require('react');
6
+ var reactFontawesome = require('@fortawesome/react-fontawesome');
7
+ var freeSolidSvgIcons = require('@fortawesome/free-solid-svg-icons');
8
+
9
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
10
+
11
+ var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
12
+
13
+ /******************************************************************************
14
+ Copyright (c) Microsoft Corporation.
15
+
16
+ Permission to use, copy, modify, and/or distribute this software for any
17
+ purpose with or without fee is hereby granted.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
20
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
21
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
22
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
23
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
24
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
25
+ PERFORMANCE OF THIS SOFTWARE.
26
+ ***************************************************************************** */
27
+
28
+ function __awaiter(thisArg, _arguments, P, generator) {
29
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
30
+ return new (P || (P = Promise))(function (resolve, reject) {
31
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
32
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
33
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
34
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
35
+ });
36
+ }
37
+
38
+ // Highest error code = DRK2
39
+ /**
40
+ * List of error codes built into the react kit
41
+ * @author Gabe Abrams
42
+ */
43
+ var ReactKitErrorCode;
44
+ (function (ReactKitErrorCode) {
45
+ ReactKitErrorCode["NoResponse"] = "DRK1";
46
+ ReactKitErrorCode["NoCode"] = "DRK2";
47
+ ReactKitErrorCode["SessionExpired"] = "DRK3";
48
+ ReactKitErrorCode["MissingParameter"] = "DRK4";
49
+ ReactKitErrorCode["InvalidParameter"] = "DRK5";
50
+ ReactKitErrorCode["WrongCourse"] = "DRK6";
51
+ })(ReactKitErrorCode || (ReactKitErrorCode = {}));
52
+ var ReactKitErrorCode$1 = ReactKitErrorCode;
53
+
54
+ /**
55
+ * Displays an error
56
+ * @author Gabe Abrams
57
+ */
58
+ /*------------------------------------------------------------------------*/
59
+ /* Component */
60
+ /*------------------------------------------------------------------------*/
61
+ const ErrorBox = (props) => {
62
+ /*------------------------------------------------------------------------*/
63
+ /* Setup */
64
+ /*------------------------------------------------------------------------*/
65
+ var _a;
66
+ /* -------------- Props ------------- */
67
+ const { error, title = 'An Error Occurred', onClose, } = props;
68
+ /*------------------------------------------------------------------------*/
69
+ /* Render */
70
+ /*------------------------------------------------------------------------*/
71
+ // Determine error text
72
+ const errorText = (typeof error === 'string'
73
+ ? error.trim()
74
+ : String(error.message || 'An unknown error occurred. Please contact support.'));
75
+ // Error code box
76
+ let errorCodeBox;
77
+ if (error && error.code) {
78
+ errorCodeBox = (React__default["default"].createElement("span", null,
79
+ ' ',
80
+ React__default["default"].createElement("span", { style: {
81
+ backgroundColor: 'white',
82
+ borderRadius: '5px',
83
+ paddingLeft: '3px',
84
+ paddingRight: '3px',
85
+ color: '#DC4150',
86
+ fontVariant: 'small-caps',
87
+ fontSize: '80%',
88
+ whiteSpace: 'nowrap',
89
+ } },
90
+ "code:",
91
+ ' ',
92
+ String((_a = error.code) !== null && _a !== void 0 ? _a : ReactKitErrorCode$1.NoCode).toUpperCase())));
93
+ }
94
+ // Main UI
95
+ return (React__default["default"].createElement("div", { className: "alert alert-danger text-center", style: {
96
+ maxWidth: '650px',
97
+ margin: 'auto',
98
+ } },
99
+ React__default["default"].createElement("h4", { className: "mb-1" },
100
+ React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faExclamationTriangle, className: "me-2" }),
101
+ title),
102
+ React__default["default"].createElement("div", null,
103
+ errorText,
104
+ errorCodeBox),
105
+ onClose && (React__default["default"].createElement("div", { className: "mt-2" },
106
+ React__default["default"].createElement("button", { type: "button", className: "btn btn-light", "aria-label": "dismiss error and close this activity or view", onClick: onClose }, "Close")))));
107
+ };
108
+
109
+ /**
110
+ * Types of buttons in the modal
111
+ * @author Gabe Abrams
112
+ */
113
+ var ModalButtonType;
114
+ (function (ModalButtonType) {
115
+ ModalButtonType["Okay"] = "okay";
116
+ ModalButtonType["Cancel"] = "cancel";
117
+ ModalButtonType["Yes"] = "yes";
118
+ ModalButtonType["No"] = "no";
119
+ ModalButtonType["Abandon"] = "abandon";
120
+ ModalButtonType["GoBack"] = "goBack";
121
+ ModalButtonType["Continue"] = "continue";
122
+ ModalButtonType["ImSure"] = "imSure";
123
+ ModalButtonType["Delete"] = "delete";
124
+ ModalButtonType["Confirm"] = "confirm";
125
+ })(ModalButtonType || (ModalButtonType = {}));
126
+ var ModalButtonType$1 = ModalButtonType;
127
+
128
+ /**
129
+ * Types of modals
130
+ * @author Gabe Abrams
131
+ */
132
+ var ModalType;
133
+ (function (ModalType) {
134
+ ModalType["Okay"] = "okay";
135
+ ModalType["OkayCancel"] = "okay-cancel";
136
+ ModalType["YesNo"] = "yes-no";
137
+ ModalType["YesNoCancel"] = "yes-no-cancel";
138
+ ModalType["AbandonGoBack"] = "abandon-goBack";
139
+ ModalType["ImSureCancel"] = "imSure-cancel";
140
+ ModalType["DeleteCancel"] = "delete-cancel";
141
+ ModalType["ConfirmCancel"] = "confirm-cancel";
142
+ ModalType["NoButtons"] = "-";
143
+ })(ModalType || (ModalType = {}));
144
+ var ModalType$1 = ModalType;
145
+
146
+ /**
147
+ * Wait for a certain number of ms
148
+ * @author Gabe Abrams
149
+ * @param ms number of ms to wait
150
+ */
151
+ const waitMs = (ms = 0) => __awaiter(void 0, void 0, void 0, function* () {
152
+ return new Promise((resolve) => {
153
+ setTimeout(resolve, ms);
154
+ });
155
+ });
156
+
157
+ /**
158
+ * Bootstrap variants
159
+ * @author Gabe Abrams
160
+ */
161
+ var Variant;
162
+ (function (Variant) {
163
+ Variant["Primary"] = "primary";
164
+ Variant["Secondary"] = "secondary";
165
+ Variant["Success"] = "success";
166
+ Variant["Warning"] = "warning";
167
+ Variant["Info"] = "info";
168
+ Variant["Danger"] = "danger";
169
+ Variant["Light"] = "light";
170
+ Variant["Dark"] = "dark";
171
+ })(Variant || (Variant = {}));
172
+ var Variant$1 = Variant;
173
+
174
+ /**
175
+ * Modal sizes
176
+ * @author Gabe Abrams
177
+ */
178
+ var ModalSize;
179
+ (function (ModalSize) {
180
+ ModalSize["Small"] = "sm";
181
+ ModalSize["Medium"] = "md";
182
+ ModalSize["Large"] = "lg";
183
+ ModalSize["ExtraLarge"] = "xl";
184
+ })(ModalSize || (ModalSize = {}));
185
+ var ModalSize$1 = ModalSize;
186
+
187
+ /**
188
+ * A generic popup modal
189
+ * @author Gabe Abrams
190
+ */
191
+ /*------------------------------------------------------------------------*/
192
+ /* Constants */
193
+ /*------------------------------------------------------------------------*/
194
+ // Constants
195
+ const MS_TO_ANIMATE = 400; // Time to animate in/out (defined by bootstrap)
196
+ const MS_ANIMATE_IN_DELAY = 10;
197
+ // Time to wait before animating in (must be >0 or animation won't trigger)
198
+ // Modal type to list of buttons
199
+ const modalTypeToModalButtonTypes = {
200
+ [ModalType$1.Okay]: [
201
+ ModalButtonType$1.Okay,
202
+ ],
203
+ [ModalType$1.OkayCancel]: [
204
+ ModalButtonType$1.Okay,
205
+ ModalButtonType$1.Cancel,
206
+ ],
207
+ [ModalType$1.YesNo]: [
208
+ ModalButtonType$1.Yes,
209
+ ModalButtonType$1.No,
210
+ ],
211
+ [ModalType$1.YesNoCancel]: [
212
+ ModalButtonType$1.Yes,
213
+ ModalButtonType$1.No,
214
+ ModalButtonType$1.Cancel,
215
+ ],
216
+ [ModalType$1.AbandonGoBack]: [
217
+ ModalButtonType$1.Abandon,
218
+ ModalButtonType$1.GoBack,
219
+ ],
220
+ [ModalType$1.ImSureCancel]: [
221
+ ModalButtonType$1.ImSure,
222
+ ModalButtonType$1.Cancel,
223
+ ],
224
+ [ModalType$1.DeleteCancel]: [
225
+ ModalButtonType$1.Delete,
226
+ ModalButtonType$1.Cancel,
227
+ ],
228
+ [ModalType$1.ConfirmCancel]: [
229
+ ModalButtonType$1.Confirm,
230
+ ModalButtonType$1.Cancel,
231
+ ],
232
+ };
233
+ // Button type styling and labels
234
+ const ModalButtonTypeToLabelAndVariant = {
235
+ [ModalButtonType$1.Okay]: {
236
+ label: 'Okay',
237
+ variant: Variant$1.Dark,
238
+ },
239
+ [ModalButtonType$1.Cancel]: {
240
+ label: 'Cancel',
241
+ variant: Variant$1.Secondary,
242
+ },
243
+ [ModalButtonType$1.Yes]: {
244
+ label: 'Yes',
245
+ variant: Variant$1.Dark,
246
+ },
247
+ [ModalButtonType$1.No]: {
248
+ label: 'No',
249
+ variant: Variant$1.Secondary,
250
+ },
251
+ [ModalButtonType$1.Abandon]: {
252
+ label: 'Abandon Changes',
253
+ variant: Variant$1.Warning,
254
+ },
255
+ [ModalButtonType$1.GoBack]: {
256
+ label: 'Go Back',
257
+ variant: Variant$1.Secondary,
258
+ },
259
+ [ModalButtonType$1.Continue]: {
260
+ label: 'Continue',
261
+ variant: Variant$1.Dark,
262
+ },
263
+ [ModalButtonType$1.ImSure]: {
264
+ label: 'I am sure',
265
+ variant: Variant$1.Warning,
266
+ },
267
+ [ModalButtonType$1.Delete]: {
268
+ label: 'Yes, Delete',
269
+ variant: Variant$1.Danger,
270
+ },
271
+ [ModalButtonType$1.Confirm]: {
272
+ label: 'Confirm',
273
+ variant: Variant$1.Dark,
274
+ },
275
+ };
276
+ /*------------------------------------------------------------------------*/
277
+ /* Component */
278
+ /*------------------------------------------------------------------------*/
279
+ const Modal = (props) => {
280
+ /*------------------------------------------------------------------------*/
281
+ /* Setup */
282
+ /*------------------------------------------------------------------------*/
283
+ var _a;
284
+ /* -------------- Props ------------- */
285
+ const { type = ModalType$1.NoButtons, size = ModalSize$1.Large, title, children, onClose, dontAllowBackdropExit, onTopOfOtherModals, } = props;
286
+ /* -------------- State ------------- */
287
+ // If true, the modal is shown
288
+ const [visible, setVisible] = React.useState(false);
289
+ // True if currently animating in
290
+ const [animatingIn, setAnimatingIn] = React.useState(false);
291
+ /*------------------------------------------------------------------------*/
292
+ /* Lifecycle Functions */
293
+ /*------------------------------------------------------------------------*/
294
+ /**
295
+ * Mount
296
+ * @author Gabe Abrams
297
+ */
298
+ React.useEffect(() => {
299
+ (() => __awaiter(void 0, void 0, void 0, function* () {
300
+ // Start the component animating in
301
+ yield waitMs(MS_ANIMATE_IN_DELAY);
302
+ setAnimatingIn(true);
303
+ // Wait and then set visible to true
304
+ yield waitMs(MS_TO_ANIMATE);
305
+ setVisible(true);
306
+ }))();
307
+ }, []);
308
+ /*------------------------------------------------------------------------*/
309
+ /* Component Functions */
310
+ /*------------------------------------------------------------------------*/
311
+ /**
312
+ * Handles the closing of the modal
313
+ * @author Gabe Abrams
314
+ * @param ModalButtonType the button that was clicked when closing the
315
+ * modal
316
+ */
317
+ const handleClose = (ModalButtonType) => __awaiter(void 0, void 0, void 0, function* () {
318
+ // Don't close if no handler
319
+ if (!onClose) {
320
+ return;
321
+ }
322
+ // Don't close if animating in
323
+ if (animatingIn) {
324
+ return;
325
+ }
326
+ // Don't close if already closed
327
+ if (!visible) {
328
+ return;
329
+ }
330
+ // Update the state
331
+ setVisible(false);
332
+ // Call the handler after the modal has animated out
333
+ yield waitMs(MS_TO_ANIMATE);
334
+ onClose(ModalButtonType);
335
+ });
336
+ /*------------------------------------------------------------------------*/
337
+ /* Render */
338
+ /*------------------------------------------------------------------------*/
339
+ /*----------------------------------------*/
340
+ /* Footer */
341
+ /*----------------------------------------*/
342
+ // Get list of buttons for this modal type
343
+ const ModalButtonTypes = (_a = modalTypeToModalButtonTypes[type]) !== null && _a !== void 0 ? _a : [];
344
+ // Create buttons
345
+ const buttons = ModalButtonTypes.map((ModalButtonType, i) => {
346
+ // Get default style
347
+ let { label, variant, } = ModalButtonTypeToLabelAndVariant[ModalButtonType];
348
+ // Override with customizations
349
+ const newLabel = props[`${ModalButtonType}Label`];
350
+ if (newLabel) {
351
+ label = newLabel;
352
+ }
353
+ const newVariant = props[`${ModalButtonType}Variant`];
354
+ if (newVariant) {
355
+ variant = newVariant;
356
+ }
357
+ // Check if this button is last
358
+ const last = (i === ModalButtonTypes.length - 1);
359
+ // Create the button
360
+ return (React__default["default"].createElement("button", { type: "button", className: `Modal-${ModalButtonType}-button btn btn-${variant} ${last ? '' : 'mr-1'}`, onClick: () => {
361
+ handleClose(ModalButtonType);
362
+ } }, label));
363
+ });
364
+ // Put all buttons in a footer
365
+ const footer = ((buttons && buttons.length)
366
+ ? (React__default["default"].createElement("div", null, buttons))
367
+ : undefined);
368
+ // Render the modal
369
+ return (React__default["default"].createElement("div", { className: `modal show modal-dialog-scrollable modal-dialog-centered modal-${size}`, tabIndex: -1, style: {
370
+ zIndex: (onTopOfOtherModals
371
+ ? 6000000000
372
+ : 5000000000),
373
+ display: 'block',
374
+ margin: 'auto',
375
+ } },
376
+ React__default["default"].createElement("div", { className: "modal-dialog" },
377
+ React__default["default"].createElement("div", { className: "modal-content" },
378
+ React__default["default"].createElement("div", { className: "modal-header" },
379
+ React__default["default"].createElement("h5", { className: "modal-title" }, title),
380
+ onClose && (React__default["default"].createElement("button", { type: "button", className: "btn-close", "data-bs-dismiss": "modal", "aria-label": "Close", onClick: () => {
381
+ handleClose(ModalButtonType$1.Cancel);
382
+ } }))),
383
+ children && (React__default["default"].createElement("div", { className: "modal-body" }, children)),
384
+ footer && (React__default["default"].createElement("div", { className: "modal-footer" }, footer))))));
385
+ };
386
+
387
+ /**
388
+ * An error with a code
389
+ * @author Gabe Abrams
390
+ */
391
+ class ErrorWithCode extends Error {
392
+ constructor(message, code) {
393
+ super(message);
394
+ this.name = 'ErrorWithCode';
395
+ this.code = code;
396
+ }
397
+ }
398
+
399
+ /**
400
+ * A wrapper for the entire React app that adds global functionality like
401
+ * handling for fatal error messages, adds bootstrap support
402
+ * @author Gabe Abrams
403
+ */
404
+ /*------------------------------------------------------------------------*/
405
+ /* Static Helpers */
406
+ /*------------------------------------------------------------------------*/
407
+ /*----------------------------------------*/
408
+ /* Alert */
409
+ /*----------------------------------------*/
410
+ // Stored copies of setters
411
+ let setAlertInfo;
412
+ let onAlertClosed;
413
+ /**
414
+ * Show an alert modal with an "Okay" button
415
+ * @author Gabe Abrams
416
+ * @param title the title text to display at the top of the alert
417
+ * @param text the text to display in the alert
418
+ */
419
+ const alert = (title, text) => __awaiter(void 0, void 0, void 0, function* () {
420
+ // Fallback if alert not available
421
+ if (!setAlertInfo) {
422
+ window.alert(`${title}\n\n${text}`);
423
+ return undefined;
424
+ }
425
+ // Return promise that resolves when alert is closed
426
+ return new Promise((resolve) => {
427
+ // Setup handler
428
+ onAlertClosed = () => {
429
+ resolve(undefined);
430
+ };
431
+ // Show the alert
432
+ setAlertInfo({
433
+ title,
434
+ text,
435
+ });
436
+ });
437
+ });
438
+ /*----------------------------------------*/
439
+ /* Confirm */
440
+ /*----------------------------------------*/
441
+ // Stored copies of setters
442
+ let setConfirmInfo;
443
+ let onConfirmClosed;
444
+ /**
445
+ * Show a confirmation modal with an "Okay" and a "Cancel" button
446
+ * @author Gabe Abrams
447
+ * @param title the title text to display at the top of the alert
448
+ * @param text the text to display in the alert
449
+ * @returns true if the user confirmed
450
+ */
451
+ const confirm = (title, text) => __awaiter(void 0, void 0, void 0, function* () {
452
+ // Fallback if confirm is not available
453
+ if (!setConfirmInfo) {
454
+ return window.confirm(`${title}\n\n${text}`);
455
+ }
456
+ // Return promise that resolves with result of confirmation
457
+ return new Promise((resolve) => {
458
+ // Setup handler
459
+ onConfirmClosed = (confirmed) => {
460
+ resolve(confirmed);
461
+ };
462
+ // Show the confirm
463
+ setConfirmInfo({
464
+ title,
465
+ text,
466
+ });
467
+ });
468
+ });
469
+ /*----------------------------------------*/
470
+ /* Fatal Error */
471
+ /*----------------------------------------*/
472
+ // Stored copies of setters
473
+ let setFatalErrorMessage;
474
+ let setFatalErrorCode;
475
+ let setFatalErrorTitle;
476
+ /**
477
+ * Show a fatal error message
478
+ * @author Gabe Abrams
479
+ * @param error the error to show
480
+ * @param [errorTitle] title of the error box
481
+ */
482
+ const showFatalError = (error, errorTitle = 'An Error Occurred') => {
483
+ var _a, _b;
484
+ // Determine message and code
485
+ const message = (typeof error === 'string'
486
+ ? error.trim()
487
+ : String((_a = error.message) !== null && _a !== void 0 ? _a : 'An unknown error occurred.'));
488
+ const code = (typeof error === 'string'
489
+ ? ReactKitErrorCode$1.NoCode
490
+ : String((_b = error.code) !== null && _b !== void 0 ? _b : ReactKitErrorCode$1.NoCode));
491
+ // Handle case where app hasn't loaded
492
+ if (!setFatalErrorMessage || !setFatalErrorCode) {
493
+ alert(errorTitle, `${message} (code: ${code}). Please contact support.`);
494
+ return undefined;
495
+ }
496
+ // Use setters
497
+ setFatalErrorMessage(message);
498
+ setFatalErrorCode(code);
499
+ setFatalErrorTitle(errorTitle);
500
+ return undefined;
501
+ };
502
+ /*------------------------------------------------------------------------*/
503
+ /* Component */
504
+ /*------------------------------------------------------------------------*/
505
+ const AppWrapper = (props) => {
506
+ /*------------------------------------------------------------------------*/
507
+ /* Setup */
508
+ /*------------------------------------------------------------------------*/
509
+ /* -------------- Props ------------- */
510
+ const { children, dark, sessionExpiredMessage = 'Your session has expired. Please go back to Canvas and start over.', } = props;
511
+ /* -------------- State ------------- */
512
+ // Fatal error
513
+ const [fatalErrorMessage, setFatalErrorMessageInner,] = React.useState();
514
+ setFatalErrorMessage = setFatalErrorMessageInner;
515
+ const [fatalErrorCode, setFatalErrorCodeInner,] = React.useState();
516
+ setFatalErrorCode = setFatalErrorCodeInner;
517
+ const [fatalErrorTitle, setFatalErrorTitleInner,] = React.useState();
518
+ setFatalErrorTitle = setFatalErrorTitleInner;
519
+ // Alert
520
+ const [alertInfo, setAlertInfoInner,] = React.useState();
521
+ setAlertInfo = setAlertInfoInner;
522
+ // Confirm
523
+ const [confirmInfo, setConfirmInfoInner,] = React.useState();
524
+ setConfirmInfo = setConfirmInfoInner;
525
+ // Session expired
526
+ const [sessionHasExpired, setSessionHasExpiredInner,] = React.useState(false);
527
+ /*------------------------------------------------------------------------*/
528
+ /* Render */
529
+ /*------------------------------------------------------------------------*/
530
+ /*----------------------------------------*/
531
+ /* Modal */
532
+ /*----------------------------------------*/
533
+ // Modal that may be defined
534
+ let modal;
535
+ /* -------------- Alert ------------- */
536
+ if (alertInfo) {
537
+ modal = (React__default["default"].createElement(Modal, { title: alertInfo.title, type: ModalType$1.Okay, onClose: () => {
538
+ // Alert closed
539
+ if (onAlertClosed) {
540
+ onAlertClosed();
541
+ }
542
+ }, onTopOfOtherModals: true }, alertInfo.text));
543
+ }
544
+ /* ------------- Confirm ------------ */
545
+ if (confirmInfo) {
546
+ modal = (React__default["default"].createElement(Modal, { title: confirmInfo.title, type: ModalType$1.OkayCancel, onClose: (buttonType) => {
547
+ if (onConfirmClosed) {
548
+ onConfirmClosed(buttonType === ModalButtonType$1.Okay);
549
+ }
550
+ }, dontAllowBackdropExit: true }));
551
+ }
552
+ /*----------------------------------------*/
553
+ /* Views */
554
+ /*----------------------------------------*/
555
+ // Body that will be filled with the current view
556
+ let body;
557
+ /* ----------- Fatal Error ---------- */
558
+ if (fatalErrorMessage || fatalErrorCode || sessionHasExpired) {
559
+ // Re-encapsulate in an error
560
+ const error = (sessionHasExpired
561
+ ? new ErrorWithCode((fatalErrorMessage !== null && fatalErrorMessage !== void 0 ? fatalErrorMessage : 'An unknown error has occurred. Please contact support.'), (fatalErrorCode !== null && fatalErrorCode !== void 0 ? fatalErrorCode : ReactKitErrorCode$1.NoCode))
562
+ : new ErrorWithCode(sessionExpiredMessage, ReactKitErrorCode$1.SessionExpired));
563
+ // Build error screen
564
+ body = (React__default["default"].createElement("div", { style: {
565
+ display: 'block',
566
+ width: '100vw',
567
+ minHeight: '100vh',
568
+ paddingTop: '2rem',
569
+ backgroundColor: (dark
570
+ ? '#222'
571
+ : '#fff'),
572
+ } },
573
+ React__default["default"].createElement(ErrorBox, { title: (sessionHasExpired
574
+ ? 'Session Expired'
575
+ : fatalErrorTitle), error: error })));
576
+ }
577
+ /* --------------- App -------------- */
578
+ if (!body) {
579
+ body = (React__default["default"].createElement(React__default["default"].Fragment, null, children));
580
+ }
581
+ /*----------------------------------------*/
582
+ /* Main UI */
583
+ /*----------------------------------------*/
584
+ return (React__default["default"].createElement(React__default["default"].Fragment, null,
585
+ modal,
586
+ body));
587
+ };
588
+
589
+ /**
590
+ * Loading spinner/indicator
591
+ * @author Gabe Abrams
592
+ */
593
+ /*------------------------------------------------------------------------*/
594
+ /* Style */
595
+ /*------------------------------------------------------------------------*/
596
+ const style$1 = `
597
+ /* Blips */
598
+ .LoadingSpinner-blip-1,
599
+ .LoadingSpinner-blip-2,
600
+ .LoadingSpinner-blip-3,
601
+ .LoadingSpinner-blip-4 {
602
+ font-size: 25px;
603
+ opacity: 0.6;
604
+ margin-top: 20px;
605
+ margin-bottom: 20px;
606
+ }
607
+
608
+ /* First Blip */
609
+ .LoadingSpinner-blip-1 {
610
+ animation: LoadingSpinner-pop-animation 2s infinite;
611
+ }
612
+
613
+ /* Second Blip */
614
+ .LoadingSpinner-blip-2 {
615
+ animation: LoadingSpinner-pop-animation 2s infinite;
616
+ -webkit-animation-delay: 0.1s;
617
+ animation-delay: 0.1s;
618
+ }
619
+
620
+ /* Third Blip */
621
+ .LoadingSpinner-blip-3 {
622
+ animation: LoadingSpinner-pop-animation 2s infinite;
623
+ animation-delay: 0.2s;
624
+ }
625
+
626
+ /* Fourth Blip */
627
+ .LoadingSpinner-blip-4 {
628
+ animation: LoadingSpinner-pop-animation 2s infinite;
629
+ animation-delay: 0.3s;
630
+ }
631
+
632
+ /* Pop Animation for Each Blip */
633
+ @keyframes LoadingSpinner-pop-animation {
634
+ 0% {
635
+ transform: scale(1.0);
636
+ }
637
+ 10% {
638
+ transform: scale(1.5);
639
+ }
640
+ 30% {
641
+ transform: scale(1.0);
642
+ }
643
+ 100% {
644
+ transform: scale(1.0);
645
+ }
646
+ }
647
+ `;
648
+ /*------------------------------------------------------------------------*/
649
+ /* Component */
650
+ /*------------------------------------------------------------------------*/
651
+ const LoadingSpinner = () => {
652
+ /*------------------------------------------------------------------------*/
653
+ /* Render */
654
+ /*------------------------------------------------------------------------*/
655
+ // Add all four blips to a container
656
+ return (React__default["default"].createElement("div", { className: "text-center LoadingSpinner LoadingSpinner-container" },
657
+ React__default["default"].createElement("style", null, style$1),
658
+ React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faCircle, className: "LoadingSpinner-blip-1 me-1" }),
659
+ React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faCircle, className: "LoadingSpinner-blip-2 me-1" }),
660
+ React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faCircle, className: "LoadingSpinner-blip-3 me-1" }),
661
+ React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faCircle, className: "LoadingSpinner-blip-4" })));
662
+ };
663
+
664
+ /**
665
+ * A box with a tab on the top that holds buttons and other content
666
+ * @author Gabe Abrams
667
+ */
668
+ /*------------------------------------------------------------------------*/
669
+ /* Style */
670
+ /*------------------------------------------------------------------------*/
671
+ const style = `
672
+ /* Tab Box */
673
+ .TabBox-box {
674
+ /* Light Border */
675
+ border: 2px solid #dedede;
676
+
677
+ /* Rounded Corners (except top-left) */
678
+ border-bottom-right-radius: 5px;
679
+ border-bottom-left-radius: 5px;
680
+ border-top-right-radius: 5px;
681
+
682
+ /* Very Light Gray Border */
683
+ background: #fdfdfd;
684
+
685
+ /* Align Contents on Left */
686
+ text-align: left;
687
+ }
688
+
689
+ /* Container for Title */
690
+ .TabBox-title-container {
691
+ /* Place on Left */
692
+ position: relative;
693
+ left: 0;
694
+ text-align: left;
695
+ }
696
+
697
+ /* Tab-style Title */
698
+ .TabBox-title {
699
+ /* Place so it Barely Overlaps the Box Border */
700
+ display: inline-block;
701
+ position: relative;
702
+ top: 2px; /* Gives Illusion that Border Doesn't Exist Below Tab */
703
+
704
+ /* Title-sized Font */
705
+ font-size: 25px;
706
+
707
+ /* Add Border on Top and Sides */
708
+ border-top: 2px solid #dedede;
709
+ border-left: 2px solid #dedede;
710
+ border-right: 2px solid #dedede;
711
+
712
+ /* Round the Top Corners */
713
+ border-top-left-radius: 5px;
714
+ border-top-right-radius: 5px;
715
+
716
+ /* Add Text Padding */
717
+ padding-left: 12px;
718
+ padding-right: 12px;
719
+
720
+ /* Match Background Color of Box */
721
+ background: #fdfdfd;
722
+ }
723
+
724
+ /* Make the TabBox's Children Appear Above Title if Overlap Occurs */
725
+ .TabBox-children {
726
+ position: relative;
727
+ z-index: 1;
728
+ }
729
+ `;
730
+ /*------------------------------------------------------------------------*/
731
+ /* Component */
732
+ /*------------------------------------------------------------------------*/
733
+ const TabBox = (props) => {
734
+ /*------------------------------------------------------------------------*/
735
+ /* Setup */
736
+ /*------------------------------------------------------------------------*/
737
+ /* -------------- Props ------------- */
738
+ const { title, children, } = props;
739
+ /*------------------------------------------------------------------------*/
740
+ /* Render */
741
+ /*------------------------------------------------------------------------*/
742
+ /*----------------------------------------*/
743
+ /* Main UI */
744
+ /*----------------------------------------*/
745
+ // Full UI
746
+ return (React__default["default"].createElement("div", null,
747
+ React__default["default"].createElement("style", null, style),
748
+ React__default["default"].createElement("div", { className: "TabBox-title-container" },
749
+ React__default["default"].createElement("div", { className: "TabBox-title" }, title)),
750
+ React__default["default"].createElement("div", { className: "TabBox-box p-2" },
751
+ React__default["default"].createElement("div", { className: "TabBox-children" }, children))));
752
+ };
753
+
754
+ /**
755
+ * Shorten text so it fits into a certain number of chars
756
+ * @author Gabe Abrams
757
+ * @param text the text to abbreviate
758
+ * @param maxChars the maximum number of chars to include
759
+ * @returns abbreviated text with length no greater than maxChars
760
+ * (including ellipses if applicable)
761
+ */
762
+ const abbreviate = (text, maxChars) => {
763
+ // Check if already short enough
764
+ if (text.trim().length < maxChars) {
765
+ return text.trim();
766
+ }
767
+ // Abbreviate
768
+ const shortenedText = (text
769
+ .trim()
770
+ .substring(0, maxChars - 3)
771
+ .trim());
772
+ return `${shortenedText}...`;
773
+ };
774
+
775
+ /**
776
+ * Sum the numbers in an array
777
+ * @author Gabe Abrams
778
+ * @param nums the numbers to sum
779
+ * @returns the sum of the numbers
780
+ */
781
+ const sum = (nums) => {
782
+ return nums.reduce((a, b) => {
783
+ return (a + b);
784
+ }, 0);
785
+ };
786
+
787
+ /**
788
+ * Get the average of a set of numbers
789
+ * @author Gabe Abrams
790
+ * @param nums the numbers to average
791
+ * @returns average value or 0 if no numbers
792
+ */
793
+ const avg = (nums) => {
794
+ // Handle empty array case
795
+ if (nums.length === 0) {
796
+ return 0;
797
+ }
798
+ // Get the total value
799
+ const total = sum(nums);
800
+ // Get average
801
+ return (total / nums.length);
802
+ };
803
+
804
+ /**
805
+ * Round a number (ceiling) to a certain number of decimals
806
+ * @author Gabe Abrams
807
+ * @param num the number to round
808
+ * @param numDecimals the number of decimals to round to
809
+ * @returns rounded number
810
+ */
811
+ const ceilToNumDecimals = (num, numDecimals) => {
812
+ const rounder = 10 ** numDecimals;
813
+ return (Math.ceil(num * rounder) / rounder);
814
+ };
815
+
816
+ /**
817
+ * Round a number (floor) to a certain number of decimals
818
+ * @author Gabe Abrams
819
+ * @param num the number to round
820
+ * @param numDecimals the number of decimals to round to
821
+ * @returns rounded number
822
+ */
823
+ const floorToNumDecimals = (num, numDecimals) => {
824
+ const rounder = 10 ** numDecimals;
825
+ return (Math.floor(num * rounder) / rounder);
826
+ };
827
+
828
+ /**
829
+ * Force a number to stay within specific bounds
830
+ * @author Gabe Abrams
831
+ * @param num the number to move into the bounds
832
+ * @param min the minimum number in the bound
833
+ * @param max the maximum number in the bound
834
+ * @returns bounded number
835
+ */
836
+ const forceNumIntoBounds = (num, min, max) => {
837
+ return Math.max(min, Math.min(max, num));
838
+ };
839
+
840
+ /**
841
+ * Pad a number's decimal with zeros on the right
842
+ * (e.g. 5.2 becomes 5.20 with 2 digit padding)
843
+ * @author Gabe Abrams
844
+ * @param num the number to pad
845
+ * @param numDigits the minimum number of digits after the decimal
846
+ * @returns padded number
847
+ */
848
+ const padDecimalZeros = (num, numDigits) => {
849
+ // Skip if nothing to do
850
+ if (numDigits < 1) {
851
+ return String(num);
852
+ }
853
+ // Convert to string
854
+ let out = String(num);
855
+ // Add a decimal point if there isn't one
856
+ if (!out.includes('.')) {
857
+ out += '.';
858
+ }
859
+ // Add zeros
860
+ while (out.split('.')[1].length < numDigits) {
861
+ out = `${out}0`;
862
+ }
863
+ // Return
864
+ return out;
865
+ };
866
+
867
+ /**
868
+ * Pad a number with zeros on the left (e.g. 5 becomes 05 with 2 digit padding)
869
+ * @author Gabe Abrams
870
+ * @param num the number to pad
871
+ * @param numDigits the minimum number of digits before the decimal
872
+ * @returns padded number
873
+ */
874
+ const padZerosLeft = (num, numDigits) => {
875
+ // Convert to string
876
+ let out = String(num);
877
+ // Add zeros
878
+ while (out.split('.')[0].length < numDigits) {
879
+ out = `0${out}`;
880
+ }
881
+ // Return
882
+ return out;
883
+ };
884
+
885
+ /**
886
+ * Round a number to a certain number of decimals
887
+ * @author Gabe Abrams
888
+ * @param num the number to round
889
+ * @param numDecimals the number of decimals to round to
890
+ * @returns rounded number
891
+ */
892
+ const roundToNumDecimals = (num, numDecimals) => {
893
+ const rounder = 10 ** numDecimals;
894
+ return (Math.round(num * rounder) / rounder);
895
+ };
896
+
897
+ exports.AppWrapper = AppWrapper;
898
+ exports.ErrorBox = ErrorBox;
899
+ exports.ErrorWithCode = ErrorWithCode;
900
+ exports.LoadingSpinner = LoadingSpinner;
901
+ exports.Modal = Modal;
902
+ exports.ModalButtonType = ModalButtonType$1;
903
+ exports.ModalSize = ModalSize$1;
904
+ exports.ModalType = ModalType$1;
905
+ exports.ReactKitErrorCode = ReactKitErrorCode$1;
906
+ exports.TabBox = TabBox;
907
+ exports.Variant = Variant$1;
908
+ exports.abbreviate = abbreviate;
909
+ exports.alert = alert;
910
+ exports.avg = avg;
911
+ exports.ceilToNumDecimals = ceilToNumDecimals;
912
+ exports.confirm = confirm;
913
+ exports.floorToNumDecimals = floorToNumDecimals;
914
+ exports.forceNumIntoBounds = forceNumIntoBounds;
915
+ exports.padDecimalZeros = padDecimalZeros;
916
+ exports.padZerosLeft = padZerosLeft;
917
+ exports.roundToNumDecimals = roundToNumDecimals;
918
+ exports.showFatalError = showFatalError;
919
+ exports.sum = sum;
920
+ exports.waitMs = waitMs;
921
+ //# sourceMappingURL=index.js.map