dce-reactkit 5.0.8 → 5.0.9

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.
@@ -0,0 +1,20 @@
1
+ import BackButtonController from '../types/BackButtonController';
2
+ /**
3
+ * Controller for driving back navigation from anywhere in the app. Requires
4
+ * useBackButton to have been called in the top-level app
5
+ * @author Yuen Ler Chow
6
+ */
7
+ export declare const backButtonController: BackButtonController;
8
+ /**
9
+ * Hook that makes the browser's back button navigate within the app instead of
10
+ * leaving it. Call this once in your top-level app, then use
11
+ * backButtonController to enter subpanels and describe their state.
12
+ *
13
+ * Assumes a single level of navigation: one home screen plus subpanels that the
14
+ * user returns home from.
15
+ * @author Yuen Ler Chow
16
+ * @param handleGoHomeFunc handler that performs the app state changes required
17
+ * to return to the home screen
18
+ */
19
+ declare const useBackButton: (handleGoHomeFunc: () => void) => void;
20
+ export default useBackButton;
@@ -37,6 +37,7 @@ import isMobileOrTablet from './helpers/isMobileOrTablet';
37
37
  import makeLinksClickable from './helpers/makeLinksClickable';
38
38
  import combineClassNames from './helpers/combineClassNames';
39
39
  import useForceRender from './helpers/useForceRender';
40
+ import useBackButton, { backButtonController } from './helpers/useBackButton';
40
41
  import isSelectAdmin from './helpers/isSelectAdmin';
41
42
  import ModalButtonType from './types/ModalButtonType';
42
43
  import ModalSize from './types/ModalSize';
@@ -45,8 +46,10 @@ import Variant from './types/Variant';
45
46
  import IntelliTableColumn from './types/IntelliTableColumn';
46
47
  import DropdownItemType from './types/DropdownItemType';
47
48
  import ProgressBarSize from './types/ProgressBarSize';
49
+ import BackState from './types/BackState';
50
+ import BackButtonController from './types/BackButtonController';
48
51
  import PickableItem from './components/ItemPicker/types/PickableItem';
49
52
  import DBEntry from './components/DBEntryManagerPanel/types/DBEntry';
50
53
  import DBEntryField from './components/DBEntryManagerPanel/types/DBEntryField';
51
54
  import DBEntryFieldType from './components/DBEntryManagerPanel/types/DBEntryFieldType';
52
- export { AppWrapper, LoadingSpinner, ErrorBox, Modal, TabBox, RadioButton, CheckboxButton, ButtonInputGroup, SimpleDateChooser, SimpleMonthChooser, SimpleTimeChooser, Drawer, PopSuccessMark, PopFailureMark, PopPendingMark, CopiableBox, ItemPicker, LogReviewer, IntelliTable, CSVDownloadButton, DBEntryManagerPanel, Tooltip, ToggleSwitch, AutoscrollToBottomContainer, MultiSwitch, Dropdown, ProgressBar, FakeProgressBar, alert, prompt, confirm, showFatalError, DynamicWord, stubServerEndpoint, canReviewLogs, isMobileOrTablet, makeLinksClickable, isSelectAdmin, initClient, visitServerEndpoint, logClientEvent, addFatalErrorHandler, leaveToURL, combineClassNames, useForceRender, setClientEventMetadataPopulator, ModalButtonType, ModalSize, ModalType, Variant, IntelliTableColumn, DropdownItemType, LogReviewerFilterState, ProgressBarSize, PickableItem, DBEntry, DBEntryField, DBEntryFieldType, ErrorWithCode, MINUTE_IN_MS, HOUR_IN_MS, DAY_IN_MS, LOG_REVIEW_ROUTE_PATH_PREFIX, LOG_ROUTE_PATH, LOG_REVIEW_STATUS_ROUTE, LOG_REVIEW_GET_LOGS_ROUTE, SELECT_ADMIN_CHECK_ROUTE, abbreviate, avg, ceilToNumDecimals, floorToNumDecimals, forceNumIntoBounds, padDecimalZeros, padZerosLeft, roundToNumDecimals, sum, waitMs, getOrdinal, getTimeInfoInET, getMondayOfTimestamp, startMinWait, getHumanReadableDate, getPartOfDay, stringsToHumanReadableList, onlyKeepLetters, parallelLimit, getMonthName, genCSV, extractProp, compareArraysByProp, getLocalTimeInfo, genCommaList, validateEmail, validatePhoneNumber, validateString, idify, prefixWithAOrAn, everyAsync, filterAsync, forEachAsync, mapAsync, someAsync, capitalize, shuffleArray, getWordCount, cloneDeep, getTimestampFromTimeInfoInET, spaceAtCapitals, ParamType, DayOfWeek, Log, LogType, LogSource, LogAction, LogBuiltInMetadata, LogMetadataType, LogFunction, LogTypeSpecificInfo, LogMainInfo, LogSourceSpecificInfo, LogLevel, CommonKitErrorCode, };
55
+ export { AppWrapper, LoadingSpinner, ErrorBox, Modal, TabBox, RadioButton, CheckboxButton, ButtonInputGroup, SimpleDateChooser, SimpleMonthChooser, SimpleTimeChooser, Drawer, PopSuccessMark, PopFailureMark, PopPendingMark, CopiableBox, ItemPicker, LogReviewer, IntelliTable, CSVDownloadButton, DBEntryManagerPanel, Tooltip, ToggleSwitch, AutoscrollToBottomContainer, MultiSwitch, Dropdown, ProgressBar, FakeProgressBar, alert, prompt, confirm, showFatalError, DynamicWord, stubServerEndpoint, canReviewLogs, isMobileOrTablet, makeLinksClickable, isSelectAdmin, initClient, visitServerEndpoint, logClientEvent, addFatalErrorHandler, leaveToURL, combineClassNames, useForceRender, useBackButton, backButtonController, setClientEventMetadataPopulator, ModalButtonType, ModalSize, ModalType, Variant, IntelliTableColumn, DropdownItemType, LogReviewerFilterState, ProgressBarSize, BackState, BackButtonController, PickableItem, DBEntry, DBEntryField, DBEntryFieldType, ErrorWithCode, MINUTE_IN_MS, HOUR_IN_MS, DAY_IN_MS, LOG_REVIEW_ROUTE_PATH_PREFIX, LOG_ROUTE_PATH, LOG_REVIEW_STATUS_ROUTE, LOG_REVIEW_GET_LOGS_ROUTE, SELECT_ADMIN_CHECK_ROUTE, abbreviate, avg, ceilToNumDecimals, floorToNumDecimals, forceNumIntoBounds, padDecimalZeros, padZerosLeft, roundToNumDecimals, sum, waitMs, getOrdinal, getTimeInfoInET, getMondayOfTimestamp, startMinWait, getHumanReadableDate, getPartOfDay, stringsToHumanReadableList, onlyKeepLetters, parallelLimit, getMonthName, genCSV, extractProp, compareArraysByProp, getLocalTimeInfo, genCommaList, validateEmail, validatePhoneNumber, validateString, idify, prefixWithAOrAn, everyAsync, filterAsync, forEachAsync, mapAsync, someAsync, capitalize, shuffleArray, getWordCount, cloneDeep, getTimestampFromTimeInfoInET, spaceAtCapitals, ParamType, DayOfWeek, Log, LogType, LogSource, LogAction, LogBuiltInMetadata, LogMetadataType, LogFunction, LogTypeSpecificInfo, LogMainInfo, LogSourceSpecificInfo, LogLevel, CommonKitErrorCode, };
@@ -0,0 +1,40 @@
1
+ import BackState from './BackState';
2
+ /**
3
+ * Controller for the back button, used to drive back navigation from anywhere
4
+ * in the app. Pass this to subpanels so they can describe their state and
5
+ * send the user home.
6
+ * @author Yuen Ler Chow
7
+ */
8
+ type BackButtonController = {
9
+ /**
10
+ * Call this when the user navigates to a child of the home screen (something
11
+ * they can come back from)
12
+ */
13
+ onSubpanelEntered: () => void;
14
+ /**
15
+ * Send the user back to the home screen
16
+ * @param [force] if true, go home immediately without checking the subpanel
17
+ * state (no confirmation, not blocked). If falsy, nothing happens when
18
+ * blocked and confirmation is required when there are unsaved changes
19
+ */
20
+ goHome: (force?: boolean) => Promise<void>;
21
+ /**
22
+ * Set the state of the current subpanel, which determines what happens when
23
+ * the user tries to go back
24
+ * @param newSubpanelState the new state of the subpanel
25
+ */
26
+ setSubpanelState: (newSubpanelState: BackState) => void;
27
+ /**
28
+ * Set the confirmation message shown if the user tries to go back while there
29
+ * are unsaved changes (cleared upon returning to the home screen)
30
+ * @param message the message to show
31
+ */
32
+ setCustomUnsavedChangesMessage: (message: string) => void;
33
+ /**
34
+ * Set the message shown if the user tries to go back while blocked (cleared
35
+ * upon returning to the home screen)
36
+ * @param message the message to show
37
+ */
38
+ setCustomBlockedMessage: (message: string) => void;
39
+ };
40
+ export default BackButtonController;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * State of the current subpanel, determining what happens when the user tries
3
+ * to go back to the home screen
4
+ * @author Yuen Ler Chow
5
+ */
6
+ declare enum BackState {
7
+ Normal = "Normal",
8
+ UnsavedChanges = "UnsavedChanges",
9
+ Blocked = "Blocked"
10
+ }
11
+ export default BackState;
package/dist/esm/index.js CHANGED
@@ -2860,22 +2860,23 @@ const NestableItemList = (props) => {
2860
2860
  onChanged(changeChecked(item.id, checked, items));
2861
2861
  }, ariaLabel: `Select ${accessibleName}`, checkedVariant: Variant$1.Light, uncheckedVariant: Variant$1.Light }));
2862
2862
  return (React__default.createElement("div", { key: item.id },
2863
- React__default.createElement("span", { className: "NestableItemList-dropdown-button-container d-inline-block", style: {
2864
- minWidth: '2rem',
2865
- } }, item.isGroup && (React__default.createElement("button", { className: `NestableItemList-dropdown-button NestableItemList-dropdown-button-${item.id}`, style: {
2866
- border: 0,
2867
- backgroundColor: 'transparent',
2868
- }, type: "button", onClick: () => {
2869
- dispatch({
2870
- type: ActionType$9.ToggleChild,
2871
- id: item.id,
2872
- });
2873
- }, "aria-label": `${childExpanded[item.id] ? 'Hide' : 'Show'} items in ${accessibleName}` },
2874
- React__default.createElement(FontAwesomeIcon, { icon: childExpanded[item.id] ? faChevronDown : faChevronRight })))),
2875
- item.tooltip
2876
- ? (React__default.createElement(Tooltip, { text: item.tooltip },
2877
- React__default.createElement("span", { className: "d-inline-block" }, checkbox)))
2878
- : checkbox,
2863
+ React__default.createElement("div", { className: "NestableItemList-item d-flex align-items-center" },
2864
+ React__default.createElement("span", { className: "NestableItemList-dropdown-button-container", style: {
2865
+ minWidth: '2rem',
2866
+ } }, item.isGroup && (React__default.createElement("button", { className: `NestableItemList-dropdown-button NestableItemList-dropdown-button-${item.id}`, style: {
2867
+ border: 0,
2868
+ backgroundColor: 'transparent',
2869
+ }, type: "button", onClick: () => {
2870
+ dispatch({
2871
+ type: ActionType$9.ToggleChild,
2872
+ id: item.id,
2873
+ });
2874
+ }, "aria-label": `${childExpanded[item.id] ? 'Hide' : 'Show'} items in ${accessibleName}` },
2875
+ React__default.createElement(FontAwesomeIcon, { icon: childExpanded[item.id] ? faChevronDown : faChevronRight })))),
2876
+ item.tooltip
2877
+ ? (React__default.createElement(Tooltip, { text: item.tooltip },
2878
+ React__default.createElement("span", { className: "d-inline-block" }, checkbox)))
2879
+ : checkbox),
2879
2880
  (item.isGroup && childExpanded[item.id]) && (React__default.createElement("div", { className: "NestableItemList-children-container", style: {
2880
2881
  paddingLeft: '2.2rem',
2881
2882
  } },
@@ -14751,6 +14752,286 @@ const useForceRender = (useReducer) => {
14751
14752
  };
14752
14753
  };
14753
14754
 
14755
+ /**
14756
+ * State of the current subpanel, determining what happens when the user tries
14757
+ * to go back to the home screen
14758
+ * @author Yuen Ler Chow
14759
+ */
14760
+ var BackState;
14761
+ (function (BackState) {
14762
+ // The user can go back immediately, no confirmation required
14763
+ BackState["Normal"] = "Normal";
14764
+ // The user must confirm before going back because progress will be lost
14765
+ BackState["UnsavedChanges"] = "UnsavedChanges";
14766
+ // The user cannot go back right now because work is in progress
14767
+ BackState["Blocked"] = "Blocked";
14768
+ })(BackState || (BackState = {}));
14769
+ var BackState$1 = BackState;
14770
+
14771
+ /*------------------------------------------------------------------------*/
14772
+ /* ------------------------------ Constants ----------------------------- */
14773
+ /*------------------------------------------------------------------------*/
14774
+ // Marker stored on history entries owned by this hook
14775
+ const HISTORY_STATE_MARKER = { dceReactKitBackButton: true };
14776
+ // Default message shown when the user tries to go back while blocked
14777
+ const BLOCKED_TITLE = 'Cannot Go Back';
14778
+ const BLOCKED_MESSAGE = 'A task is currently in progress. Please try again once it finishes.';
14779
+ // Default message shown when the user tries to go back with unsaved changes
14780
+ const UNSAVED_CHANGES_TITLE = 'Abandon Changes?';
14781
+ const UNSAVED_CHANGES_MESSAGE = 'Any unsaved changes may be lost.';
14782
+ /*------------------------------------------------------------------------*/
14783
+ /* --------------------------- Static State ----------------------------- */
14784
+ /*------------------------------------------------------------------------*/
14785
+ // Current state, stored statically so that any subpanel can drive the back
14786
+ // button without prop drilling or context
14787
+ let state = {
14788
+ promptVisible: false,
14789
+ bypassNextPop: false,
14790
+ };
14791
+ /*------------------------------------------------------------------------*/
14792
+ /* ------------------------- Helper Functions --------------------------- */
14793
+ /*------------------------------------------------------------------------*/
14794
+ /**
14795
+ * Get the app's go-home handler, throwing if the hook has not been set up yet
14796
+ * @author Yuen Ler Chow
14797
+ * @returns handler that returns the app to its home screen
14798
+ */
14799
+ const getHandleGoHome = () => {
14800
+ if (!state.handleGoHome) {
14801
+ throw new Error('Cannot use the back button: call useBackButton in your top-level app before using backButtonController.');
14802
+ }
14803
+ return state.handleGoHome;
14804
+ };
14805
+ /**
14806
+ * Return to the home screen: clear the current subpanel and run the app's
14807
+ * go-home handler
14808
+ * @author Yuen Ler Chow
14809
+ * @param consumeHistoryEntry if true, also step back over the history entry
14810
+ * that was added when the subpanel was entered
14811
+ */
14812
+ const returnHome = (consumeHistoryEntry) => {
14813
+ const handleGoHome = getHandleGoHome();
14814
+ const wasInSubpanel = !!state.subpanel;
14815
+ // Dropping the subpanel clears its back state and custom messages at once
14816
+ state.subpanel = undefined;
14817
+ // Update the app
14818
+ handleGoHome();
14819
+ // Entering a subpanel added a history entry. When the user leaves via an
14820
+ // in-app control, that entry is still on the stack, so we step over it to keep
14821
+ // the browser history in sync with the app. When the browser's back button is
14822
+ // what brought us here, that entry has already been consumed by the browser,
14823
+ // and stepping back again would take the user out of the app entirely
14824
+ if (consumeHistoryEntry && wasInSubpanel) {
14825
+ state.bypassNextPop = true;
14826
+ window.history.back();
14827
+ }
14828
+ };
14829
+ /**
14830
+ * Keep the user in place after a back navigation that should not be allowed.
14831
+ * The browser's popstate event is not cancelable, so the only way to stay put
14832
+ * is to immediately push a new entry to replace the one that was just popped.
14833
+ * This has to happen synchronously while handling the pop, before awaiting
14834
+ * anything, otherwise the navigation has already taken effect
14835
+ * @author Yuen Ler Chow
14836
+ */
14837
+ const undoPop = () => {
14838
+ window.history.pushState(HISTORY_STATE_MARKER, '');
14839
+ };
14840
+ /**
14841
+ * Tell the user that they cannot go back right now
14842
+ * @author Yuen Ler Chow
14843
+ */
14844
+ const showBlockedMessage = () => __awaiter(void 0, void 0, void 0, function* () {
14845
+ var _a, _b;
14846
+ state.promptVisible = true;
14847
+ yield alert(BLOCKED_TITLE, (_b = (_a = state.subpanel) === null || _a === void 0 ? void 0 : _a.customBlockedMessage) !== null && _b !== void 0 ? _b : BLOCKED_MESSAGE);
14848
+ state.promptVisible = false;
14849
+ });
14850
+ /**
14851
+ * Ask the user whether they want to leave despite having unsaved changes
14852
+ * @author Yuen Ler Chow
14853
+ * @returns true if the user wants to leave
14854
+ */
14855
+ const askToAbandonChanges = () => __awaiter(void 0, void 0, void 0, function* () {
14856
+ var _c, _d;
14857
+ state.promptVisible = true;
14858
+ const confirmed = yield confirm(UNSAVED_CHANGES_TITLE, (_d = (_c = state.subpanel) === null || _c === void 0 ? void 0 : _c.customUnsavedChangesMessage) !== null && _d !== void 0 ? _d : UNSAVED_CHANGES_MESSAGE, {
14859
+ confirmButtonText: 'Abandon Changes',
14860
+ cancelButtonText: 'Stay Here',
14861
+ });
14862
+ state.promptVisible = false;
14863
+ return confirmed;
14864
+ });
14865
+ /**
14866
+ * Handle a back navigation performed by the browser
14867
+ * @author Yuen Ler Chow
14868
+ */
14869
+ const handlePopState = () => {
14870
+ // Back navigation that we triggered ourselves: let it through
14871
+ if (state.bypassNextPop) {
14872
+ state.bypassNextPop = false;
14873
+ return;
14874
+ }
14875
+ // Already on the home screen: nothing for us to intercept
14876
+ if (!state.subpanel) {
14877
+ return;
14878
+ }
14879
+ // A prompt is already on screen: stay put instead of stacking another one
14880
+ if (state.promptVisible) {
14881
+ undoPop();
14882
+ return;
14883
+ }
14884
+ // Blocked: stay put and explain why
14885
+ if (state.subpanel.backState === BackState$1.Blocked) {
14886
+ undoPop();
14887
+ showBlockedMessage();
14888
+ return;
14889
+ }
14890
+ // Unsaved changes: stay put until the user confirms. The pop is undone
14891
+ // asynchronously here, before awaiting the confirmation, so that the user
14892
+ // remains in the subpanel while they decide
14893
+ if (state.subpanel.backState === BackState$1.UnsavedChanges) {
14894
+ undoPop();
14895
+ (() => __awaiter(void 0, void 0, void 0, function* () {
14896
+ if (yield askToAbandonChanges()) {
14897
+ returnHome(true);
14898
+ }
14899
+ }))();
14900
+ return;
14901
+ }
14902
+ // Normal: allow it. The browser already consumed the history entry, so there
14903
+ // is nothing left for us to step over
14904
+ returnHome(false);
14905
+ };
14906
+ /*------------------------------------------------------------------------*/
14907
+ /* ------------------------------ Controller ---------------------------- */
14908
+ /*------------------------------------------------------------------------*/
14909
+ /**
14910
+ * Controller for driving back navigation from anywhere in the app. Requires
14911
+ * useBackButton to have been called in the top-level app
14912
+ * @author Yuen Ler Chow
14913
+ */
14914
+ const backButtonController = {
14915
+ /**
14916
+ * Call this when the user navigates to a child of the home screen (something
14917
+ * they can come back from)
14918
+ * @author Yuen Ler Chow
14919
+ */
14920
+ onSubpanelEntered: () => {
14921
+ getHandleGoHome();
14922
+ state.subpanel = {
14923
+ backState: BackState$1.Normal,
14924
+ };
14925
+ // Add a history entry to come back to, so that the next back navigation is
14926
+ // intercepted instead of leaving the app
14927
+ window.history.pushState(HISTORY_STATE_MARKER, '');
14928
+ },
14929
+ /**
14930
+ * Send the user back to the home screen
14931
+ * @author Yuen Ler Chow
14932
+ * @param [force] if true, go home immediately without checking the subpanel
14933
+ * state. If falsy, nothing happens while blocked and confirmation is
14934
+ * required when there are unsaved changes
14935
+ */
14936
+ goHome: (force) => __awaiter(void 0, void 0, void 0, function* () {
14937
+ var _e, _f;
14938
+ getHandleGoHome();
14939
+ // Unless the caller is forcing the navigation, the subpanel's state decides
14940
+ // whether the user may leave: a blocked subpanel refuses and explains why,
14941
+ // and one with unsaved changes leaves only if the user confirms
14942
+ if (!force) {
14943
+ // A prompt is already asking the user this same question
14944
+ if (state.promptVisible) {
14945
+ return;
14946
+ }
14947
+ if (((_e = state.subpanel) === null || _e === void 0 ? void 0 : _e.backState) === BackState$1.Blocked) {
14948
+ yield showBlockedMessage();
14949
+ return;
14950
+ }
14951
+ if (((_f = state.subpanel) === null || _f === void 0 ? void 0 : _f.backState) === BackState$1.UnsavedChanges) {
14952
+ const confirmed = yield askToAbandonChanges();
14953
+ if (!confirmed) {
14954
+ return;
14955
+ }
14956
+ }
14957
+ }
14958
+ returnHome(true);
14959
+ }),
14960
+ /**
14961
+ * Set the state of the current subpanel, which determines what happens when
14962
+ * the user tries to go back. Ignored while on the home screen, where there
14963
+ * is no back navigation to describe
14964
+ * @author Yuen Ler Chow
14965
+ * @param newSubpanelState the new state of the subpanel
14966
+ */
14967
+ setSubpanelState: (newSubpanelState) => {
14968
+ if (!state.subpanel) {
14969
+ return;
14970
+ }
14971
+ state.subpanel.backState = newSubpanelState;
14972
+ },
14973
+ /**
14974
+ * Set the confirmation message shown if the user tries to go back while there
14975
+ * are unsaved changes. Cleared upon returning to the home screen
14976
+ * @author Yuen Ler Chow
14977
+ * @param message the message to show
14978
+ */
14979
+ setCustomUnsavedChangesMessage: (message) => {
14980
+ if (!state.subpanel) {
14981
+ return;
14982
+ }
14983
+ state.subpanel.customUnsavedChangesMessage = message;
14984
+ },
14985
+ /**
14986
+ * Set the message shown if the user tries to go back while blocked. Cleared
14987
+ * upon returning to the home screen
14988
+ * @author Yuen Ler Chow
14989
+ * @param message the message to show
14990
+ */
14991
+ setCustomBlockedMessage: (message) => {
14992
+ if (!state.subpanel) {
14993
+ return;
14994
+ }
14995
+ state.subpanel.customBlockedMessage = message;
14996
+ },
14997
+ };
14998
+ /*------------------------------------------------------------------------*/
14999
+ /* --------------------------------- Hook ------------------------------- */
15000
+ /*------------------------------------------------------------------------*/
15001
+ /**
15002
+ * Hook that makes the browser's back button navigate within the app instead of
15003
+ * leaving it. Call this once in your top-level app, then use
15004
+ * backButtonController to enter subpanels and describe their state.
15005
+ *
15006
+ * Assumes a single level of navigation: one home screen plus subpanels that the
15007
+ * user returns home from.
15008
+ * @author Yuen Ler Chow
15009
+ * @param handleGoHomeFunc handler that performs the app state changes required
15010
+ * to return to the home screen
15011
+ */
15012
+ const useBackButton = (handleGoHomeFunc) => {
15013
+ // Store the handler on every render so that the listener below, which is only
15014
+ // registered once, always calls the app's current version of it
15015
+ state.handleGoHome = handleGoHomeFunc;
15016
+ // The popstate listener has to be attached to the window, which is outside of
15017
+ // React, so an effect is used to add it when the app mounts and remove it if
15018
+ // the app ever unmounts. The empty dependency array keeps this to a single
15019
+ // listener for the lifetime of the app instead of one per render
15020
+ useEffect(() => {
15021
+ // Mark the current entry as the home entry
15022
+ window.history.replaceState(HISTORY_STATE_MARKER, '');
15023
+ window.addEventListener('popstate', handlePopState);
15024
+ return () => {
15025
+ window.removeEventListener('popstate', handlePopState);
15026
+ // Clear the static state so that a remount starts from scratch
15027
+ state = {
15028
+ promptVisible: false,
15029
+ bypassNextPop: false,
15030
+ };
15031
+ };
15032
+ }, []);
15033
+ };
15034
+
14754
15035
  /*------------------------------------------------------------------------*/
14755
15036
  /* ------------------------------- Caching ------------------------------ */
14756
15037
  /*------------------------------------------------------------------------*/
@@ -14787,5 +15068,5 @@ const isSelectAdmin = () => __awaiter(void 0, void 0, void 0, function* () {
14787
15068
  }
14788
15069
  });
14789
15070
 
14790
- export { AppWrapper, AutoscrollToBottomContainer, ButtonInputGroup, CSVDownloadButton, CheckboxButton, CopiableBox, DBEntryFieldType$1 as DBEntryFieldType, DBEntryManagerPanel, Drawer, Dropdown, DropdownItemType$1 as DropdownItemType, DynamicWord, ErrorBox, FakeProgressBar, IntelliTable, ItemPicker, LoadingSpinner, LogReviewer, Modal, ModalButtonType$1 as ModalButtonType, ModalSize$1 as ModalSize, ModalType$1 as ModalType, MultiSwitch, PopFailureMark, PopPendingMark, PopSuccessMark, ProgressBar, ProgressBarSize$1 as ProgressBarSize, RadioButton, SimpleDateChooser, SimpleMonthChooser, SimpleTimeChooser, TabBox, ToggleSwitch, Tooltip, Variant$1 as Variant, addFatalErrorHandler, alert, canReviewLogs, combineClassNames, confirm, initClient, isMobileOrTablet, isSelectAdmin, leaveToURL, logClientEvent, makeLinksClickable, prompt, setClientEventMetadataPopulator, showFatalError, stubServerEndpoint, useForceRender, visitServerEndpoint };
15071
+ export { AppWrapper, AutoscrollToBottomContainer, BackState$1 as BackState, ButtonInputGroup, CSVDownloadButton, CheckboxButton, CopiableBox, DBEntryFieldType$1 as DBEntryFieldType, DBEntryManagerPanel, Drawer, Dropdown, DropdownItemType$1 as DropdownItemType, DynamicWord, ErrorBox, FakeProgressBar, IntelliTable, ItemPicker, LoadingSpinner, LogReviewer, Modal, ModalButtonType$1 as ModalButtonType, ModalSize$1 as ModalSize, ModalType$1 as ModalType, MultiSwitch, PopFailureMark, PopPendingMark, PopSuccessMark, ProgressBar, ProgressBarSize$1 as ProgressBarSize, RadioButton, SimpleDateChooser, SimpleMonthChooser, SimpleTimeChooser, TabBox, ToggleSwitch, Tooltip, Variant$1 as Variant, addFatalErrorHandler, alert, backButtonController, canReviewLogs, combineClassNames, confirm, initClient, isMobileOrTablet, isSelectAdmin, leaveToURL, logClientEvent, makeLinksClickable, prompt, setClientEventMetadataPopulator, showFatalError, stubServerEndpoint, useBackButton, useForceRender, visitServerEndpoint };
14791
15072
  //# sourceMappingURL=index.js.map