Skip to content

Commit

Permalink
Fix create comment, edit comment, create post text area being cut off (
Browse files Browse the repository at this point in the history
…aeharding#332)

* Fix create comment, edit comment, create post text area being cut off

This is really fragile logic, but I've tried to abstract it to
IonModalAutosizedForOnScreenKeyboard to keep it modular at least...

* Abstract TextareaAutosizedForOnScreenKeyboard
  • Loading branch information
aeharding authored Jul 8, 2023
1 parent d79e110 commit 0362cb6
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 12 deletions.
11 changes: 6 additions & 5 deletions src/features/comment/reply/CommentReply.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,25 @@ import { Centered, Spinner } from "../../auth/Login";
import { handleSelector, jwtSelector } from "../../auth/authSlice";
import { css } from "@emotion/react";
import { preventPhotoswipeGalleryFocusTrap } from "../../gallery/GalleryImg";
import TextareaAutosizedForOnScreenKeyboard from "../../shared/TextareaAutosizedForOnScreenKeyboard";

export const Container = styled.div`
position: absolute;
inset: 0;
min-height: 100%;
display: flex;
flex-direction: column;
`;

export const Textarea = styled.textarea`
export const Textarea = styled(TextareaAutosizedForOnScreenKeyboard)`
border: 0;
background: none;
resize: none;
outline: 0;
padding: 1rem;
flex: 1 0 0;
min-height: 7rem;
min-height: 200px;
flex: 1 0 auto;
${({ theme }) =>
!theme.dark &&
Expand Down
8 changes: 4 additions & 4 deletions src/features/post/new/NewPostText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,23 @@ import {
import { useState } from "react";
import { Centered, Spinner } from "../../auth/Login";
import { css } from "@emotion/react";
import TextareaAutosizedForOnScreenKeyboard from "../../shared/TextareaAutosizedForOnScreenKeyboard";

const Container = styled.div`
position: absolute;
inset: 0;
min-height: 100%;
display: flex;
flex-direction: column;
`;

const Textarea = styled.textarea`
const Textarea = styled(TextareaAutosizedForOnScreenKeyboard)`
border: 0;
background: none;
resize: none;
outline: 0;
padding: 1rem;
flex: 1 0 0;
flex: 1 0 auto;
min-height: 7rem;
${({ theme }) =>
Expand Down
7 changes: 4 additions & 3 deletions src/features/shared/DynamicDismissableModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import React, {
useRef,
useState,
} from "react";
import { IonModal, useIonActionSheet } from "@ionic/react";
import { useIonActionSheet } from "@ionic/react";
import { PageContext } from "../auth/PageContext";
import { Prompt, useLocation } from "react-router";
import IonModalAutosizedForOnScreenKeyboard from "./IonModalAutosizedForOnScreenKeyboard";

export interface DismissableProps {
dismiss: () => void;
Expand Down Expand Up @@ -82,7 +83,7 @@ export function DynamicDismissableModal({
when={!canDismiss}
message="Are you sure you want to discard your work?"
/>
<IonModal
<IonModalAutosizedForOnScreenKeyboard
isOpen={isOpen}
canDismiss={canDismiss ? canDismiss : onDismissAttemptCb}
onDidDismiss={() => setIsOpen(false)}
Expand All @@ -99,7 +100,7 @@ export function DynamicDismissableModal({
onDismissAttemptCb();
},
})}
</IonModal>
</IonModalAutosizedForOnScreenKeyboard>
</>
);
}
Expand Down
108 changes: 108 additions & 0 deletions src/features/shared/IonModalAutosizedForOnScreenKeyboard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { IonModal } from "@ionic/react";
import React, { useCallback, useEffect, useRef, useState } from "react";
import usePageVisibility from "../../helpers/usePageVisibility";
import styled from "@emotion/styled";

// TODO it's a bit buggy trying to compute this
// in realtime with the new post dialog + comment dialogs
// So hardcode for now
const FIXED_HEADER_HEIGHT = 56;

const StyledIonModal = styled(IonModal)<{ viewportHeight: number }>`
ion-content::part(scroll) {
max-height: ${({ viewportHeight }) => viewportHeight}px;
}
`;

export default function IonModalAutosizedForOnScreenKeyboard(
props: React.ComponentProps<typeof IonModal>
) {
const [viewportHeight, setViewportHeight] = useState(
document.documentElement.clientHeight
);
const isVisible = usePageVisibility();
// eslint-disable-next-line no-undef
const modalRef = useRef<HTMLIonModalElement>(null);

const updateViewport = useCallback(() => {
if (!props.isOpen) return;

// For the rare legacy browsers that don't support it
if (!window.visualViewport) {
return;
}

const page = modalRef.current?.querySelector(
".ion-page:not(.ion-page-hidden)"
);

setViewportHeight(
window.visualViewport.height -
(page instanceof HTMLElement ? cumulativeOffset(page).top : 0) -
FIXED_HEADER_HEIGHT
);
}, [props.isOpen]);

const onScroll = useCallback(() => {
setTimeout(() => {
window.scrollTo(0, 0);
}, 100);
}, []);

// Turning iPhone on/off can mess up the scrolling to top again
useEffect(() => {
if (!props.isOpen) return;

updateViewport();
}, [isVisible, updateViewport, props.isOpen]);

useEffect(() => {
if (!props.isOpen) return;

document.addEventListener("scroll", onScroll);

return () => {
document.removeEventListener("scroll", onScroll);
};
}, [onScroll, props.isOpen]);

useEffect(() => {
if (!props.isOpen) return;

const onResize = () => {
updateViewport();
};

window.visualViewport?.addEventListener("resize", onResize);

return () => {
window.visualViewport?.removeEventListener("resize", onResize);
};
}, [updateViewport, props.isOpen]);

return (
<StyledIonModal
ref={modalRef}
viewportHeight={viewportHeight}
onDidPresent={() => {
window.scrollTo(0, 0);
}}
{...props}
/>
);
}

function cumulativeOffset(element: HTMLElement) {
let top = 0,
left = 0;
do {
top += element.offsetTop || 0;
left += element.offsetLeft || 0;
element = element.offsetParent as HTMLElement;
} while (element instanceof HTMLElement);

return {
top: top,
left: left,
};
}
29 changes: 29 additions & 0 deletions src/features/shared/TextareaAutosizedForOnScreenKeyboard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from "react";
import { isAppleDeviceInstalledToHomescreen } from "../../helpers/device";
import { fixSafariAutoscroll } from "../../helpers/safari";
import TextareaAutosize, {
TextareaAutosizeProps,
} from "react-textarea-autosize";

export default function TextareaAutosizedForOnScreenKeyboard(
props: Omit<
TextareaAutosizeProps & React.RefAttributes<HTMLTextAreaElement>,
"onFocus"
>
) {
return (
<TextareaAutosize
onFocus={(e) => {
if (!isAppleDeviceInstalledToHomescreen()) return;

// https://stackoverflow.com/a/74902393/1319878
const target = e.currentTarget;
target.style.opacity = "0";
setTimeout(() => (target.style.opacity = "1"));

fixSafariAutoscroll();
}}
{...props}
/>
);
}
13 changes: 13 additions & 0 deletions src/helpers/safari.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export function fixSafariAutoscroll() {
let checkAttempts = 0;

const interval = setInterval(() => {
window.scrollTo(0, 0);

if (window.scrollY === 0) {
checkAttempts++;

if (checkAttempts > 10) clearInterval(interval);
}
}, 100);
}

0 comments on commit 0362cb6

Please sign in to comment.