Skip to content

Commit

Permalink
refac: use resize observer instead mutation observer in order to resi…
Browse files Browse the repository at this point in the history
…ze iframe
  • Loading branch information
Pavel Mineev authored and umputun committed Dec 5, 2022
1 parent 68b8468 commit 050bce1
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 61 deletions.
4 changes: 2 additions & 2 deletions frontend/apps/remark42/app/components/auth/auth.hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,11 @@ export function useDropdown(disableClosing?: boolean) {

handleChangeIframeSize(dropdownElement);

const observer = new MutationObserver(() => {
const observer = new ResizeObserver(() => {
handleChangeIframeSize(dropdownElement);
});

observer.observe(dropdownElement, { attributes: true, childList: true, subtree: true });
observer.observe(dropdownElement);

return () => {
document.body.style.removeProperty('min-height');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import { SubscribeByRSS } from './__subscribe-by-rss';
import { MarkdownToolbar } from './markdown-toolbar';
import { TextExpander } from './text-expander';
import { updatePersistedComments, getPersistedComment, removePersistedComment } from './comment-form.persist';
import { updateIframeHeight } from 'utils/post-message';

export type Props = {
id: string;
Expand Down Expand Up @@ -453,7 +452,6 @@ export class CommentForm extends Component<Props, State> {
disabled={isDisabled}
autofocus={!!autofocus}
spellcheck={true}
onResize={updateIframeHeight}
/>
</TextExpander>
{charactersLeft < 100 && <span className="comment-form__counter">{charactersLeft}</span>}
Expand Down
42 changes: 18 additions & 24 deletions frontend/apps/remark42/app/components/root/root.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { h, Component, Fragment } from 'preact';
import { useEffect, useRef } from 'preact/hooks';
import { useEffect } from 'preact/hooks';
import { useSelector } from 'react-redux';
import b from 'bem-react-helper';
import { IntlShape, useIntl, FormattedMessage, defineMessages } from 'react-intl';
Expand Down Expand Up @@ -36,12 +36,19 @@ import { ConnectedComment as Comment } from 'components/comment/connected-commen
import { uploadImage, getPreview } from 'common/api';
import { isUserAnonymous } from 'utils/isUserAnonymous';
import { bindActions } from 'utils/actionBinder';
import { postMessageToParent, parseMessage, updateIframeHeight } from 'utils/post-message';
import { postMessageToParent, parseMessage } from 'utils/post-message';
import { useActions } from 'hooks/useAction';
import { setCollapse } from 'store/thread/actions';

import styles from './root.module.css';

/**
* Sends size of the iframe to parent window
*/
export function updateIframeHeight() {
postMessageToParent({ height: document.body.offsetHeight });
}

const mapStateToProps = (state: StoreState) => ({
sort: state.comments.sort,
isCommentsLoading: state.comments.isFetching,
Expand Down Expand Up @@ -294,33 +301,12 @@ interface CommentsProps {
showMore(): void;
}
function Comments({ isLoading, topComments, commentsShown, showMore }: CommentsProps) {
const rootRef = useRef<HTMLDivElement>(null);

useEffect(() => {
if (!rootRef.current) {
return;
}

updateIframeHeight();
// TODO: throttle updates
const observer = new MutationObserver(() => {
// a hacky way to force iframe height update when new image is rendered and loaded
rootRef.current?.querySelectorAll('img').forEach((img) => {
img.addEventListener('load', updateIframeHeight);
});
});

observer.observe(rootRef.current, { attributes: true, childList: true, subtree: true });

return () => observer.disconnect();
}, []);

const renderComments =
IS_MOBILE && commentsShown < topComments.length ? topComments.slice(0, commentsShown) : topComments;
const isShowMoreButtonVisible = IS_MOBILE && commentsShown < topComments.length;

return (
<div className="root__threads" role="list" ref={rootRef}>
<div className="root__threads" role="list">
{isLoading ? (
<Preloader className="root__preloader" />
) : (
Expand Down Expand Up @@ -358,6 +344,14 @@ export function ConnectedRoot() {
const props = useSelector(mapStateToProps);
const actions = useActions(boundActions);

useEffect(() => {
const observer = new ResizeObserver(updateIframeHeight);

updateIframeHeight();
observer.observe(document.body);
return () => observer.disconnect();
}, []);

if (!window.remark_config) {
throw new Error('Remark42: Config object is undefined');
}
Expand Down
45 changes: 19 additions & 26 deletions frontend/apps/remark42/app/components/textarea-autosize.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,33 @@ import { useEffect, useRef } from 'preact/hooks';
function autoResize(textarea: HTMLTextAreaElement, onResize?: () => void) {
textarea.style.height = '';
textarea.style.height = `${textarea.scrollHeight}px`;
// Call on rezie callback after textarea height is changed
if (onResize) {
window.requestAnimationFrame(onResize);
}
}

type Props = Omit<JSX.HTMLAttributes<HTMLTextAreaElement>, 'onInput'> & {
onInput?(evt: JSX.TargetedEvent<HTMLTextAreaElement, Event>): void;
onResize?(): void;
};

export const TextareaAutosize = forwardRef<HTMLTextAreaElement, Props>(
({ onInput, value, onResize, ...props }, externalRef) => {
const localRef = useRef<HTMLTextAreaElement>(null);
const ref = externalRef || localRef;
export const TextareaAutosize = forwardRef<HTMLTextAreaElement, Props>(({ onInput, value, ...props }, externalRef) => {
const localRef = useRef<HTMLTextAreaElement>(null);
const ref = externalRef || localRef;

const handleInput: JSX.GenericEventHandler<HTMLTextAreaElement> = (evt) => {
if (!ref.current) {
return;
}
const handleInput: JSX.GenericEventHandler<HTMLTextAreaElement> = (evt) => {
if (!ref.current) {
return;
}

if (onInput) {
return onInput(evt);
}
if (onInput) {
return onInput(evt);
}

autoResize(ref.current, onResize);
};
autoResize(ref.current);
};

useEffect(() => {
if (ref.current) {
autoResize(ref.current, onResize);
}
}, [onResize, value, ref]);
useEffect(() => {
if (ref.current) {
autoResize(ref.current);
}
}, [value, ref]);

return <textarea {...props} data-testid={props.id} onInput={handleInput} value={value} ref={ref} />;
}
);
return <textarea {...props} data-testid={props.id} onInput={handleInput} value={value} ref={ref} />;
});
7 changes: 0 additions & 7 deletions frontend/apps/remark42/app/utils/post-message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,3 @@ export function parseMessage({ data }: MessageEvent): AllMessages {

return data as AllMessages;
}

/**
* Sends size of the iframe to parent window
*/
export function updateIframeHeight() {
postMessageToParent({ height: document.body.offsetHeight });
}

0 comments on commit 050bce1

Please sign in to comment.