dce-reactkit 3.5.10 → 3.5.12
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.
- package/dist/cjs/index.js +103 -19
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/components/AppWrapper.d.ts +8 -0
- package/dist/cjs/types/index.d.ts +2 -2
- package/dist/esm/index.js +103 -20
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/components/AppWrapper.d.ts +8 -0
- package/dist/esm/types/index.d.ts +2 -2
- package/dist/index.d.ts +9 -1
- package/package.json +1 -1
- package/src/components/AppWrapper.tsx +116 -1
- package/src/components/AutoscrollToBottomContainer.tsx +24 -18
- package/src/index.ts +2 -0
|
@@ -9,6 +9,14 @@ type Props = {
|
|
|
9
9
|
children: React.ReactNode;
|
|
10
10
|
dark?: boolean;
|
|
11
11
|
};
|
|
12
|
+
/**
|
|
13
|
+
* Redirect to a new page
|
|
14
|
+
* @author Gabe Abrams
|
|
15
|
+
* @param url the url to redirect to
|
|
16
|
+
* @param destination the destination of the redirect, for example "YouTube"
|
|
17
|
+
* and will be used in the following text: `Redirecting to ${destination}...`
|
|
18
|
+
*/
|
|
19
|
+
export declare const leaveToURL: (url: string, destination: string) => Promise<void>;
|
|
12
20
|
/**
|
|
13
21
|
* Show an alert modal with an "Okay" button
|
|
14
22
|
* @author Gabe Abrams
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import AppWrapper, { alert, confirm, showFatalError, addFatalErrorHandler } from './components/AppWrapper';
|
|
1
|
+
import AppWrapper, { alert, confirm, showFatalError, addFatalErrorHandler, leaveToURL } from './components/AppWrapper';
|
|
2
2
|
import LoadingSpinner from './components/LoadingSpinner';
|
|
3
3
|
import ErrorBox from './components/ErrorBox';
|
|
4
4
|
import Modal from './components/Modal';
|
|
@@ -83,4 +83,4 @@ import PickableItem from './components/ItemPicker/types/PickableItem';
|
|
|
83
83
|
import DBEntry from './components/DBEntryManagerPanel/types/DBEntry';
|
|
84
84
|
import DBEntryField from './components/DBEntryManagerPanel/types/DBEntryField';
|
|
85
85
|
import DBEntryFieldType from './components/DBEntryManagerPanel/types/DBEntryFieldType';
|
|
86
|
-
export { AppWrapper, LoadingSpinner, ErrorBox, Modal, TabBox, RadioButton, CheckboxButton, ButtonInputGroup, SimpleDateChooser, Drawer, PopSuccessMark, PopFailureMark, PopPendingMark, CopiableBox, ItemPicker, LogReviewer, IntelliTable, CSVDownloadButton, DBEntryManagerPanel, Tooltip, ToggleSwitch, AutoscrollToBottomContainer, alert, confirm, showFatalError, ErrorWithCode, MINUTE_IN_MS, HOUR_IN_MS, DAY_IN_MS, DynamicWord, abbreviate, avg, ceilToNumDecimals, floorToNumDecimals, forceNumIntoBounds, padDecimalZeros, padZerosLeft, roundToNumDecimals, sum, waitMs, getOrdinal, getTimeInfoInET, stubServerEndpoint, startMinWait, getHumanReadableDate, getPartOfDay, stringsToHumanReadableList, onlyKeepLetters, parallelLimit, getMonthName, genCSV, canReviewLogs, isMobileOrTablet, extractProp, compareArraysByProp, genCommaList, validateEmail, validatePhoneNumber, validateString, getLocalTimeInfo, idify, initClient, visitServerEndpoint, logClientEvent, addFatalErrorHandler, initServer, genRouteHandler, handleError, handleSuccess, initLogCollection, addDBEditorEndpoints, ModalButtonType, ModalSize, ModalType, ReactKitErrorCode, Variant, DayOfWeek, Log, LogType, LogSource, LogAction, LogBuiltInMetadata, LogMetadataType, IntelliTableColumn, PickableItem, DBEntry, DBEntryField, DBEntryFieldType, ParamType, };
|
|
86
|
+
export { AppWrapper, LoadingSpinner, ErrorBox, Modal, TabBox, RadioButton, CheckboxButton, ButtonInputGroup, SimpleDateChooser, Drawer, PopSuccessMark, PopFailureMark, PopPendingMark, CopiableBox, ItemPicker, LogReviewer, IntelliTable, CSVDownloadButton, DBEntryManagerPanel, Tooltip, ToggleSwitch, AutoscrollToBottomContainer, alert, confirm, showFatalError, ErrorWithCode, MINUTE_IN_MS, HOUR_IN_MS, DAY_IN_MS, DynamicWord, abbreviate, avg, ceilToNumDecimals, floorToNumDecimals, forceNumIntoBounds, padDecimalZeros, padZerosLeft, roundToNumDecimals, sum, waitMs, getOrdinal, getTimeInfoInET, stubServerEndpoint, startMinWait, getHumanReadableDate, getPartOfDay, stringsToHumanReadableList, onlyKeepLetters, parallelLimit, getMonthName, genCSV, canReviewLogs, isMobileOrTablet, extractProp, compareArraysByProp, genCommaList, validateEmail, validatePhoneNumber, validateString, getLocalTimeInfo, idify, initClient, visitServerEndpoint, logClientEvent, addFatalErrorHandler, leaveToURL, initServer, genRouteHandler, handleError, handleSuccess, initLogCollection, addDBEditorEndpoints, ModalButtonType, ModalSize, ModalType, ReactKitErrorCode, Variant, DayOfWeek, Log, LogType, LogSource, LogAction, LogBuiltInMetadata, LogMetadataType, IntelliTableColumn, PickableItem, DBEntry, DBEntryField, DBEntryFieldType, ParamType, };
|
package/dist/index.d.ts
CHANGED
|
@@ -28,6 +28,14 @@ type Props$k = {
|
|
|
28
28
|
children: React.ReactNode;
|
|
29
29
|
dark?: boolean;
|
|
30
30
|
};
|
|
31
|
+
/**
|
|
32
|
+
* Redirect to a new page
|
|
33
|
+
* @author Gabe Abrams
|
|
34
|
+
* @param url the url to redirect to
|
|
35
|
+
* @param destination the destination of the redirect, for example "YouTube"
|
|
36
|
+
* and will be used in the following text: `Redirecting to ${destination}...`
|
|
37
|
+
*/
|
|
38
|
+
declare const leaveToURL: (url: string, destination: string) => Promise<void>;
|
|
31
39
|
/**
|
|
32
40
|
* Show an alert modal with an "Okay" button
|
|
33
41
|
* @author Gabe Abrams
|
|
@@ -1414,4 +1422,4 @@ declare const LogBuiltInMetadata: {
|
|
|
1414
1422
|
};
|
|
1415
1423
|
};
|
|
1416
1424
|
|
|
1417
|
-
export { AppWrapper, AutoscrollToBottomContainer, ButtonInputGroup, CSVDownloadButton, CheckboxButton, CopiableBox, DAY_IN_MS, DBEntry, DBEntryField, DBEntryFieldType, DBEntryManagerPanel, DayOfWeek, Drawer, DynamicWord, ErrorBox, ErrorWithCode, HOUR_IN_MS, IntelliTable, IntelliTableColumn, ItemPicker, LoadingSpinner, Log, LogAction, LogBuiltInMetadata, LogMetadataType, LogReviewer, LogSource, LogType, MINUTE_IN_MS, Modal, ModalButtonType, ModalSize, ModalType, ParamType, PickableItem, PopFailureMark, PopPendingMark, PopSuccessMark, RadioButton, ReactKitErrorCode, SimpleDateChooser, TabBox, ToggleSwitch, Tooltip, Variant, abbreviate, addDBEditorEndpoints, addFatalErrorHandler, alert, avg, canReviewLogs, ceilToNumDecimals, compareArraysByProp, confirm, extractProp, floorToNumDecimals, forceNumIntoBounds, genCSV, genCommaList, genRouteHandler, getHumanReadableDate, getLocalTimeInfo, getMonthName, getOrdinal, getPartOfDay, getTimeInfoInET, handleError, handleSuccess, idify, initClient, initLogCollection, initServer, isMobileOrTablet, logClientEvent, onlyKeepLetters, padDecimalZeros, padZerosLeft, parallelLimit, roundToNumDecimals, showFatalError, startMinWait, stringsToHumanReadableList, stubServerEndpoint, sum, validateEmail, validatePhoneNumber, validateString, visitServerEndpoint, waitMs };
|
|
1425
|
+
export { AppWrapper, AutoscrollToBottomContainer, ButtonInputGroup, CSVDownloadButton, CheckboxButton, CopiableBox, DAY_IN_MS, DBEntry, DBEntryField, DBEntryFieldType, DBEntryManagerPanel, DayOfWeek, Drawer, DynamicWord, ErrorBox, ErrorWithCode, HOUR_IN_MS, IntelliTable, IntelliTableColumn, ItemPicker, LoadingSpinner, Log, LogAction, LogBuiltInMetadata, LogMetadataType, LogReviewer, LogSource, LogType, MINUTE_IN_MS, Modal, ModalButtonType, ModalSize, ModalType, ParamType, PickableItem, PopFailureMark, PopPendingMark, PopSuccessMark, RadioButton, ReactKitErrorCode, SimpleDateChooser, TabBox, ToggleSwitch, Tooltip, Variant, abbreviate, addDBEditorEndpoints, addFatalErrorHandler, alert, avg, canReviewLogs, ceilToNumDecimals, compareArraysByProp, confirm, extractProp, floorToNumDecimals, forceNumIntoBounds, genCSV, genCommaList, genRouteHandler, getHumanReadableDate, getLocalTimeInfo, getMonthName, getOrdinal, getPartOfDay, getTimeInfoInET, handleError, handleSuccess, idify, initClient, initLogCollection, initServer, isMobileOrTablet, leaveToURL, logClientEvent, onlyKeepLetters, padDecimalZeros, padZerosLeft, parallelLimit, roundToNumDecimals, showFatalError, startMinWait, stringsToHumanReadableList, stubServerEndpoint, sum, validateEmail, validatePhoneNumber, validateString, visitServerEndpoint, waitMs };
|
package/package.json
CHANGED
|
@@ -44,6 +44,47 @@ type Props = {
|
|
|
44
44
|
/* --------------------------- Static Helpers --------------------------- */
|
|
45
45
|
/*------------------------------------------------------------------------*/
|
|
46
46
|
|
|
47
|
+
/*----------------------------------------*/
|
|
48
|
+
/* ----------- Redirect/Leave ----------- */
|
|
49
|
+
/*----------------------------------------*/
|
|
50
|
+
|
|
51
|
+
// Stored copy of setter for url to leave to
|
|
52
|
+
let setURLToLeaveTo: (
|
|
53
|
+
opts: {
|
|
54
|
+
url: string,
|
|
55
|
+
destination: string,
|
|
56
|
+
},
|
|
57
|
+
) => void;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Redirect to a new page
|
|
61
|
+
* @author Gabe Abrams
|
|
62
|
+
* @param url the url to redirect to
|
|
63
|
+
* @param destination the destination of the redirect, for example "YouTube"
|
|
64
|
+
* and will be used in the following text: `Redirecting to ${destination}...`
|
|
65
|
+
*/
|
|
66
|
+
export const leaveToURL = async (url: string, destination: string) => {
|
|
67
|
+
if (setURLToLeaveTo) {
|
|
68
|
+
// Beautiful redirect
|
|
69
|
+
setURLToLeaveTo({ url, destination });
|
|
70
|
+
} else {
|
|
71
|
+
// Overwrite page in a janky way
|
|
72
|
+
window.document.body.innerHTML = `
|
|
73
|
+
<div>
|
|
74
|
+
<h1>
|
|
75
|
+
Redirecting to ${destination}...
|
|
76
|
+
</h1>
|
|
77
|
+
<p>
|
|
78
|
+
If you are not redirected in 5 seconds, please <a href="${url}">click here</a>.
|
|
79
|
+
</p>
|
|
80
|
+
</div>
|
|
81
|
+
`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Redirect to location
|
|
85
|
+
window.location.href = url;
|
|
86
|
+
};
|
|
87
|
+
|
|
47
88
|
/*----------------------------------------*/
|
|
48
89
|
/* ---------------- Alert --------------- */
|
|
49
90
|
/*----------------------------------------*/
|
|
@@ -247,6 +288,32 @@ export const showSessionExpiredMessage = (): undefined => {
|
|
|
247
288
|
return undefined;
|
|
248
289
|
};
|
|
249
290
|
|
|
291
|
+
/*------------------------------------------------------------------------*/
|
|
292
|
+
/* -------------------------------- Style ------------------------------- */
|
|
293
|
+
/*------------------------------------------------------------------------*/
|
|
294
|
+
|
|
295
|
+
const style = `
|
|
296
|
+
.AppWrapper-leave-to-url-notice {
|
|
297
|
+
opacity: 0;
|
|
298
|
+
|
|
299
|
+
animation-name: AppWrapper-leave-to-url-notice-appear;
|
|
300
|
+
animation-duration: 0.5s;
|
|
301
|
+
animation-delay: 1s;
|
|
302
|
+
animation-fill-mode: both;
|
|
303
|
+
animation-timing-function: ease-out;
|
|
304
|
+
animation-iteration-count: 1;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
@keyframes AppWrapper-leave-to-url-notice-appear {
|
|
308
|
+
0% {
|
|
309
|
+
opacity: 0;
|
|
310
|
+
}
|
|
311
|
+
100% {
|
|
312
|
+
opacity: 1;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
`;
|
|
316
|
+
|
|
250
317
|
/*------------------------------------------------------------------------*/
|
|
251
318
|
/* ------------------------------ Component ----------------------------- */
|
|
252
319
|
/*------------------------------------------------------------------------*/
|
|
@@ -265,6 +332,13 @@ const AppWrapper: React.FC<Props> = (props: Props): React.ReactElement => {
|
|
|
265
332
|
|
|
266
333
|
/* -------------- State ------------- */
|
|
267
334
|
|
|
335
|
+
// Leave to URL
|
|
336
|
+
const [
|
|
337
|
+
urlToLeaveTo,
|
|
338
|
+
setURLToLeaveToInner,
|
|
339
|
+
] = useState<{ url: string, destination: string } | undefined>();
|
|
340
|
+
setURLToLeaveTo = setURLToLeaveToInner;
|
|
341
|
+
|
|
268
342
|
// Fatal error
|
|
269
343
|
const [
|
|
270
344
|
fatalErrorMessage,
|
|
@@ -386,9 +460,47 @@ const AppWrapper: React.FC<Props> = (props: Props): React.ReactElement => {
|
|
|
386
460
|
// Body that will be filled with the current view
|
|
387
461
|
let body: React.ReactNode;
|
|
388
462
|
|
|
463
|
+
/* ---------- Leave to URL ---------- */
|
|
464
|
+
|
|
465
|
+
if (!body && urlToLeaveTo) {
|
|
466
|
+
// Destructure url info
|
|
467
|
+
const {
|
|
468
|
+
url,
|
|
469
|
+
destination,
|
|
470
|
+
} = urlToLeaveTo;
|
|
471
|
+
|
|
472
|
+
// Show pretty redirect screen
|
|
473
|
+
body = (
|
|
474
|
+
<div className="AppWrapper-leave-to-url-container p-5 text-center">
|
|
475
|
+
<div className="AppWrapper-leave-to-url-notice d-inline-block">
|
|
476
|
+
<h3 className="text-start m-0">
|
|
477
|
+
Redirecting to
|
|
478
|
+
{' '}
|
|
479
|
+
{destination}
|
|
480
|
+
...
|
|
481
|
+
</h3>
|
|
482
|
+
<div className="text-start">
|
|
483
|
+
If you are not automatically redirected in 5 seconds, please
|
|
484
|
+
{' '}
|
|
485
|
+
<a
|
|
486
|
+
href={url}
|
|
487
|
+
aria-label={`Click here to leave to ${destination}`}
|
|
488
|
+
>
|
|
489
|
+
click here
|
|
490
|
+
</a>
|
|
491
|
+
.
|
|
492
|
+
</div>
|
|
493
|
+
</div>
|
|
494
|
+
</div>
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
|
|
389
498
|
/* ----------- Fatal Error ---------- */
|
|
390
499
|
|
|
391
|
-
if (
|
|
500
|
+
if (
|
|
501
|
+
!body
|
|
502
|
+
&& (fatalErrorMessage || fatalErrorCode || sessionHasExpired)
|
|
503
|
+
) {
|
|
392
504
|
// Re-encapsulate in an error
|
|
393
505
|
const error = (
|
|
394
506
|
sessionHasExpired
|
|
@@ -441,6 +553,9 @@ const AppWrapper: React.FC<Props> = (props: Props): React.ReactElement => {
|
|
|
441
553
|
|
|
442
554
|
return (
|
|
443
555
|
<>
|
|
556
|
+
<style>
|
|
557
|
+
{style}
|
|
558
|
+
</style>
|
|
444
559
|
{modal}
|
|
445
560
|
{body}
|
|
446
561
|
</>
|
|
@@ -215,7 +215,7 @@ const AutoscrollToBottomContainer: React.FC<Props> = (props) => {
|
|
|
215
215
|
// Initialize refs
|
|
216
216
|
const lastItemIds = useRef<(string | number)[]>([]);
|
|
217
217
|
const container = useRef<HTMLDivElement | null>(null);
|
|
218
|
-
const
|
|
218
|
+
const wasLastScrolledToBottom = useRef<boolean>(true);
|
|
219
219
|
|
|
220
220
|
/*------------------------------------------------------------------------*/
|
|
221
221
|
/* ------------------------- Component Functions ------------------------ */
|
|
@@ -253,7 +253,12 @@ const AutoscrollToBottomContainer: React.FC<Props> = (props) => {
|
|
|
253
253
|
);
|
|
254
254
|
|
|
255
255
|
// Figure out if we're scrolled to the bottom
|
|
256
|
-
|
|
256
|
+
const atBottom = (distanceToBottomRems < SCROLLED_TO_BOTTOM_THRESHOLD_REMS);
|
|
257
|
+
|
|
258
|
+
// Remember if we scrolled to the bottom
|
|
259
|
+
wasLastScrolledToBottom.current = atBottom;
|
|
260
|
+
|
|
261
|
+
return atBottom;
|
|
257
262
|
};
|
|
258
263
|
|
|
259
264
|
/**
|
|
@@ -272,7 +277,13 @@ const AutoscrollToBottomContainer: React.FC<Props> = (props) => {
|
|
|
272
277
|
});
|
|
273
278
|
|
|
274
279
|
// Scroll to bottom
|
|
275
|
-
container.current.scrollTop =
|
|
280
|
+
container.current.scrollTop = (
|
|
281
|
+
container.current.scrollHeight
|
|
282
|
+
- container.current.clientHeight
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
// Remember that we scrolled to the bottom
|
|
286
|
+
wasLastScrolledToBottom.current = true;
|
|
276
287
|
};
|
|
277
288
|
|
|
278
289
|
/*----------------------------------------*/
|
|
@@ -289,8 +300,9 @@ const AutoscrollToBottomContainer: React.FC<Props> = (props) => {
|
|
|
289
300
|
return;
|
|
290
301
|
}
|
|
291
302
|
|
|
292
|
-
// If scrolled to bottom, hide the button
|
|
303
|
+
// If scrolled to bottom, hide the button and remember position
|
|
293
304
|
if (isScrolledToBottom()) {
|
|
305
|
+
// Hide button
|
|
294
306
|
dispatch({
|
|
295
307
|
type: ActionType.HideJumpToBottomButton,
|
|
296
308
|
});
|
|
@@ -324,22 +336,24 @@ const AutoscrollToBottomContainer: React.FC<Props> = (props) => {
|
|
|
324
336
|
|
|
325
337
|
// Check if new content appeared at bottom
|
|
326
338
|
const newContentAppeared = (
|
|
339
|
+
// There are items
|
|
327
340
|
currentItemIds.length > 0
|
|
328
|
-
|
|
329
|
-
&& lastItemIds.current.
|
|
330
|
-
|
|
331
|
-
currentItemIds[currentItemIds.length - 1]
|
|
332
|
-
!== lastItemIds.current[lastItemIds.current.length - 1]
|
|
341
|
+
// The last item is new
|
|
342
|
+
&& !lastItemIds.current.includes(
|
|
343
|
+
currentItemIds[currentItemIds.length - 1],
|
|
333
344
|
)
|
|
334
345
|
);
|
|
335
346
|
|
|
347
|
+
// Update last item ids
|
|
348
|
+
lastItemIds.current = currentItemIds;
|
|
349
|
+
|
|
336
350
|
// Do nothing if no new content
|
|
337
351
|
if (!newContentAppeared) {
|
|
338
352
|
return;
|
|
339
353
|
}
|
|
340
354
|
|
|
341
355
|
// Check if used to be scrolled to the bottom
|
|
342
|
-
if (
|
|
356
|
+
if (wasLastScrolledToBottom.current) {
|
|
343
357
|
// Was scrolled to the bottom! Autoscroll.
|
|
344
358
|
scrollToBottom();
|
|
345
359
|
} else {
|
|
@@ -348,14 +362,6 @@ const AutoscrollToBottomContainer: React.FC<Props> = (props) => {
|
|
|
348
362
|
type: ActionType.ShowJumpToBottomButton,
|
|
349
363
|
});
|
|
350
364
|
}
|
|
351
|
-
|
|
352
|
-
// Update last item ids
|
|
353
|
-
lastItemIds.current = currentItemIds;
|
|
354
|
-
|
|
355
|
-
// Remember if we were scrolled to the bottom before the update
|
|
356
|
-
return () => {
|
|
357
|
-
wasScrolledToBottomBeforeItemsUpdate.current = isScrolledToBottom();
|
|
358
|
-
};
|
|
359
365
|
},
|
|
360
366
|
[items],
|
|
361
367
|
);
|
package/src/index.ts
CHANGED
|
@@ -4,6 +4,7 @@ import AppWrapper, {
|
|
|
4
4
|
confirm,
|
|
5
5
|
showFatalError,
|
|
6
6
|
addFatalErrorHandler,
|
|
7
|
+
leaveToURL,
|
|
7
8
|
} from './components/AppWrapper';
|
|
8
9
|
import LoadingSpinner from './components/LoadingSpinner';
|
|
9
10
|
import ErrorBox from './components/ErrorBox';
|
|
@@ -176,6 +177,7 @@ export {
|
|
|
176
177
|
visitServerEndpoint,
|
|
177
178
|
logClientEvent,
|
|
178
179
|
addFatalErrorHandler,
|
|
180
|
+
leaveToURL,
|
|
179
181
|
// Server helpers
|
|
180
182
|
initServer,
|
|
181
183
|
genRouteHandler,
|