dce-reactkit 3.5.11 → 3.5.13
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 +145 -4
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/components/AppWrapper.d.ts +8 -0
- package/dist/cjs/types/helpers/getPartOfDay.d.ts +1 -0
- package/dist/cjs/types/helpers/makeLinksClickable.d.ts +16 -0
- package/dist/cjs/types/index.d.ts +3 -2
- package/dist/esm/index.js +144 -5
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/components/AppWrapper.d.ts +8 -0
- package/dist/esm/types/helpers/getPartOfDay.d.ts +1 -0
- package/dist/esm/types/helpers/makeLinksClickable.d.ts +16 -0
- package/dist/esm/types/index.d.ts +3 -2
- package/dist/index.d.ts +25 -1
- package/package.json +1 -1
- package/src/components/AppWrapper.tsx +116 -1
- package/src/helpers/getPartOfDay.ts +2 -1
- package/src/helpers/makeLinksClickable.tsx +98 -0
- package/src/index.ts +4 -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
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Given some text, make the links clickable
|
|
4
|
+
* @author Gabe Abrams
|
|
5
|
+
* @param text the text to process
|
|
6
|
+
* @param [opts] options to customize behavior
|
|
7
|
+
* @param [opts.newTab] if true, links will open in a new tab
|
|
8
|
+
* @param [opts.preventPropagation] if true, clicks to link will prevent default
|
|
9
|
+
* and propagation
|
|
10
|
+
* @returns the processed text
|
|
11
|
+
*/
|
|
12
|
+
declare const makeLinksClickable: (text: string, opts?: {
|
|
13
|
+
newTab?: boolean;
|
|
14
|
+
preventPropagation?: boolean;
|
|
15
|
+
}) => React.ReactNode;
|
|
16
|
+
export default makeLinksClickable;
|
|
@@ -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';
|
|
@@ -65,6 +65,7 @@ import validateEmail from './helpers/validators/validateEmail';
|
|
|
65
65
|
import validatePhoneNumber from './helpers/validators/validatePhoneNumber';
|
|
66
66
|
import validateString from './helpers/validators/validateString';
|
|
67
67
|
import idify from './helpers/idify';
|
|
68
|
+
import makeLinksClickable from './helpers/makeLinksClickable';
|
|
68
69
|
import ModalButtonType from './types/ModalButtonType';
|
|
69
70
|
import ModalSize from './types/ModalSize';
|
|
70
71
|
import ModalType from './types/ModalType';
|
|
@@ -83,4 +84,4 @@ import PickableItem from './components/ItemPicker/types/PickableItem';
|
|
|
83
84
|
import DBEntry from './components/DBEntryManagerPanel/types/DBEntry';
|
|
84
85
|
import DBEntryField from './components/DBEntryManagerPanel/types/DBEntryField';
|
|
85
86
|
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, };
|
|
87
|
+
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, makeLinksClickable, 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
|
|
@@ -1117,6 +1125,7 @@ declare const getHumanReadableDate: (dateOrTimestamp?: Date | number) => string;
|
|
|
1117
1125
|
/**
|
|
1118
1126
|
* Get the current part of day (morning, evening, etc.)
|
|
1119
1127
|
* @author Gabe Abrams
|
|
1128
|
+
* @returns the part of day (morning, evening, etc.)
|
|
1120
1129
|
*/
|
|
1121
1130
|
declare const getPartOfDay: () => string;
|
|
1122
1131
|
|
|
@@ -1364,6 +1373,21 @@ declare const validateString: (input: string, opts: {
|
|
|
1364
1373
|
*/
|
|
1365
1374
|
declare const idify: (str: string) => string;
|
|
1366
1375
|
|
|
1376
|
+
/**
|
|
1377
|
+
* Given some text, make the links clickable
|
|
1378
|
+
* @author Gabe Abrams
|
|
1379
|
+
* @param text the text to process
|
|
1380
|
+
* @param [opts] options to customize behavior
|
|
1381
|
+
* @param [opts.newTab] if true, links will open in a new tab
|
|
1382
|
+
* @param [opts.preventPropagation] if true, clicks to link will prevent default
|
|
1383
|
+
* and propagation
|
|
1384
|
+
* @returns the processed text
|
|
1385
|
+
*/
|
|
1386
|
+
declare const makeLinksClickable: (text: string, opts?: {
|
|
1387
|
+
newTab?: boolean;
|
|
1388
|
+
preventPropagation?: boolean;
|
|
1389
|
+
}) => React.ReactNode;
|
|
1390
|
+
|
|
1367
1391
|
/**
|
|
1368
1392
|
* List of error codes built into the react kit
|
|
1369
1393
|
* @author Gabe Abrams
|
|
@@ -1414,4 +1438,4 @@ declare const LogBuiltInMetadata: {
|
|
|
1414
1438
|
};
|
|
1415
1439
|
};
|
|
1416
1440
|
|
|
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 };
|
|
1441
|
+
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, makeLinksClickable, 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
|
</>
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Get the current part of day (morning, evening, etc.)
|
|
3
3
|
* @author Gabe Abrams
|
|
4
|
+
* @returns the part of day (morning, evening, etc.)
|
|
4
5
|
*/
|
|
5
6
|
const getPartOfDay = () => {
|
|
6
7
|
// Setup the post-it time of day
|
|
7
8
|
let partOfDay = 'day';
|
|
8
|
-
|
|
9
|
+
const hours = new Date().getHours();
|
|
9
10
|
if (hours < 12) {
|
|
10
11
|
partOfDay = 'morning';
|
|
11
12
|
} else if (hours >= 12 && hours <= 16) {
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// Import React
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
// Regular express that matches urls
|
|
5
|
+
const urlRegex = /(https?:\/\/)?([a-z0-9-]+\.)+[a-z0-9]{2,6}(:[0-9]{1,5})?(\/\S*)?/g;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Given some text, make the links clickable
|
|
9
|
+
* @author Gabe Abrams
|
|
10
|
+
* @param text the text to process
|
|
11
|
+
* @param [opts] options to customize behavior
|
|
12
|
+
* @param [opts.newTab] if true, links will open in a new tab
|
|
13
|
+
* @param [opts.preventPropagation] if true, clicks to link will prevent default
|
|
14
|
+
* and propagation
|
|
15
|
+
* @returns the processed text
|
|
16
|
+
*/
|
|
17
|
+
const makeLinksClickable = (
|
|
18
|
+
text: string,
|
|
19
|
+
opts?: {
|
|
20
|
+
newTab?: boolean,
|
|
21
|
+
preventPropagation?: boolean,
|
|
22
|
+
},
|
|
23
|
+
): React.ReactNode => {
|
|
24
|
+
// Search text for links
|
|
25
|
+
let matches = urlRegex.exec(text);
|
|
26
|
+
|
|
27
|
+
// If no matches, just return the text
|
|
28
|
+
if (!matches) {
|
|
29
|
+
return text;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Check if using new tab
|
|
33
|
+
const newTab = opts?.newTab;
|
|
34
|
+
|
|
35
|
+
// Next element key
|
|
36
|
+
let nextKey = 0;
|
|
37
|
+
|
|
38
|
+
// Process each link
|
|
39
|
+
const elements: React.ReactNode[] = [];
|
|
40
|
+
let lastIndex = 0;
|
|
41
|
+
while (matches) {
|
|
42
|
+
// Get the link
|
|
43
|
+
const link = matches[0];
|
|
44
|
+
|
|
45
|
+
// Get the index of the link
|
|
46
|
+
const { index } = matches;
|
|
47
|
+
|
|
48
|
+
// Add the text before the link
|
|
49
|
+
elements.push(
|
|
50
|
+
<span key={nextKey += 1}>
|
|
51
|
+
{text.substring(lastIndex, index)}
|
|
52
|
+
</span>,
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
// Add the link
|
|
56
|
+
elements.push(
|
|
57
|
+
<a
|
|
58
|
+
key={nextKey += 1}
|
|
59
|
+
href={link}
|
|
60
|
+
target={newTab ? '_blank' : undefined}
|
|
61
|
+
rel={newTab ? 'noopener noreferrer' : undefined}
|
|
62
|
+
style={{
|
|
63
|
+
textDecoration: 'underline',
|
|
64
|
+
}}
|
|
65
|
+
onClick={(e) => {
|
|
66
|
+
// Prevent default and propagation if requested
|
|
67
|
+
if (opts?.preventPropagation) {
|
|
68
|
+
e.preventDefault();
|
|
69
|
+
e.stopPropagation();
|
|
70
|
+
}
|
|
71
|
+
}}
|
|
72
|
+
>
|
|
73
|
+
{link}
|
|
74
|
+
</a>,
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
// Update the last index
|
|
78
|
+
lastIndex = index + link.length;
|
|
79
|
+
|
|
80
|
+
// Get the next match
|
|
81
|
+
matches = urlRegex.exec(text);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Add the last bit of text
|
|
85
|
+
const remainingText = text.substring(lastIndex);
|
|
86
|
+
if (remainingText && remainingText.length > 0) {
|
|
87
|
+
elements.push(
|
|
88
|
+
<span key={nextKey += 1}>
|
|
89
|
+
{remainingText}
|
|
90
|
+
</span>,
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Return the elements
|
|
95
|
+
return elements;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export default makeLinksClickable;
|
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';
|
|
@@ -79,6 +80,7 @@ import validateEmail from './helpers/validators/validateEmail';
|
|
|
79
80
|
import validatePhoneNumber from './helpers/validators/validatePhoneNumber';
|
|
80
81
|
import validateString from './helpers/validators/validateString';
|
|
81
82
|
import idify from './helpers/idify';
|
|
83
|
+
import makeLinksClickable from './helpers/makeLinksClickable';
|
|
82
84
|
|
|
83
85
|
// Import types
|
|
84
86
|
import ModalButtonType from './types/ModalButtonType';
|
|
@@ -171,11 +173,13 @@ export {
|
|
|
171
173
|
validateString,
|
|
172
174
|
getLocalTimeInfo,
|
|
173
175
|
idify,
|
|
176
|
+
makeLinksClickable,
|
|
174
177
|
// Client helpers
|
|
175
178
|
initClient,
|
|
176
179
|
visitServerEndpoint,
|
|
177
180
|
logClientEvent,
|
|
178
181
|
addFatalErrorHandler,
|
|
182
|
+
leaveToURL,
|
|
179
183
|
// Server helpers
|
|
180
184
|
initServer,
|
|
181
185
|
genRouteHandler,
|