diff --git a/lib/page-with-shareable-state.tsx b/lib/page-with-shareable-state.tsx
index 1003030..8ff1da5 100644
--- a/lib/page-with-shareable-state.tsx
+++ b/lib/page-with-shareable-state.tsx
@@ -45,6 +45,30 @@ export function createPageWithStateSearchParams(
return search;
}
+const DeserializationErrorModal: React.FC = () => {
+ const [show, setShow] = useState(true);
+
+ if (!show) return null;
+
+ // TODO: This isn't accessible at all; it ought to trap keyboard focus,
+ // disappear when the user presses ESC, and so on.
+
+ return (
+
+
+
+ Sorry, an error occurred when trying to load the composition on this
+ page.
+
+
+ Either its data is corrupted, or displaying it is no longer supported.
+
+
+
+
+ );
+};
+
/**
* Create a component that represents a page which exposes some
* aspect of its state in the current URL, so that it can be
@@ -84,13 +108,16 @@ export function createPageWithShareableState({
*/
const [isInOnChange, setIsInOnChange] = useState(false);
- /** The default state from th URL, which we'll pass into our component. */
+ /** The default state from the URL, which we'll pass into our component. */
let defaults: T = defaultValue;
+ let didDeserializeThrow = false;
+
try {
defaults = deserialize(state || "");
} catch (e) {
console.log(`Error deserializing state: ${e}`);
+ didDeserializeThrow = true;
}
const onChange = useCallback(
@@ -115,7 +142,12 @@ export function createPageWithShareableState({
}
}, [isInOnChange, state, latestState, key]);
- return ;
+ return (
+ <>
+ {didDeserializeThrow && }
+
+ >
+ );
};
return PageWithShareableState;
diff --git a/lib/page.css b/lib/page.css
index 3af522b..0a63fcc 100644
--- a/lib/page.css
+++ b/lib/page.css
@@ -116,3 +116,37 @@ ul.navbar li:last-child {
.error {
color: red;
}
+
+.page-error {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background-color: rgba(0, 0, 0, 0.75);
+}
+
+.page-error div {
+ background: crimson;
+ color: white;
+ padding: 2em;
+ max-width: 50em;
+}
+
+.page-error div p:first-child {
+ margin-top: 0;
+}
+
+.page-error div p:last-child {
+ margin-bottom: 0;
+}
+
+.page-error div button {
+ display: block;
+ width: 66%;
+ margin: 3em auto 0 auto;
+ text-align: center;
+}