Compare commits

...
3 Commits
6 changed files with 34 additions and 31 deletions
@@ -0,0 +1,11 @@
global.ResizeObserver = class ResizeObserver {
observe() {
// do nothing
}
unobserve() {
// do nothing
}
disconnect() {
// do nothing
}
};
@@ -76,11 +76,11 @@ export function useDropdown(disableClosing?: boolean) {
handleChangeIframeSize(dropdownElement); handleChangeIframeSize(dropdownElement);
const observer = new MutationObserver(() => { const observer = new ResizeObserver(() => {
handleChangeIframeSize(dropdownElement); handleChangeIframeSize(dropdownElement);
}); });
observer.observe(dropdownElement, { attributes: true, childList: true, subtree: true }); observer.observe(dropdownElement);
return () => { return () => {
document.body.style.removeProperty('min-height'); document.body.style.removeProperty('min-height');
@@ -13,6 +13,7 @@
line-height: 1.4; line-height: 1.4;
border: 0; border: 0;
resize: none; resize: none;
overflow: hidden; /* prevent scrollbar from appearing */
backface-visibility: hidden; /* let's try to fix blinking in Safari */ backface-visibility: hidden; /* let's try to fix blinking in Safari */
transform: translateZ(0); /* let's try to fix blinking in Safari, again */ transform: translateZ(0); /* let's try to fix blinking in Safari, again */
@@ -1,5 +1,5 @@
import { h, Component, Fragment } from 'preact'; import { h, Component, Fragment } from 'preact';
import { useEffect, useRef } from 'preact/hooks'; import { useEffect } from 'preact/hooks';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import b from 'bem-react-helper'; import b from 'bem-react-helper';
import { IntlShape, useIntl, FormattedMessage, defineMessages } from 'react-intl'; import { IntlShape, useIntl, FormattedMessage, defineMessages } from 'react-intl';
@@ -42,6 +42,13 @@ import { setCollapse } from 'store/thread/actions';
import styles from './root.module.css'; 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) => ({ const mapStateToProps = (state: StoreState) => ({
sort: state.comments.sort, sort: state.comments.sort,
isCommentsLoading: state.comments.isFetching, isCommentsLoading: state.comments.isFetching,
@@ -287,10 +294,6 @@ export class Root extends Component<Props, State> {
} }
} }
function updateIframeHeight() {
postMessageToParent({ height: document.body.offsetHeight });
}
interface CommentsProps { interface CommentsProps {
isLoading: boolean; isLoading: boolean;
topComments: string[]; topComments: string[];
@@ -298,33 +301,12 @@ interface CommentsProps {
showMore(): void; showMore(): void;
} }
function Comments({ isLoading, topComments, commentsShown, showMore }: CommentsProps) { 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 = const renderComments =
IS_MOBILE && commentsShown < topComments.length ? topComments.slice(0, commentsShown) : topComments; IS_MOBILE && commentsShown < topComments.length ? topComments.slice(0, commentsShown) : topComments;
const isShowMoreButtonVisible = IS_MOBILE && commentsShown < topComments.length; const isShowMoreButtonVisible = IS_MOBILE && commentsShown < topComments.length;
return ( return (
<div className="root__threads" role="list" ref={rootRef}> <div className="root__threads" role="list">
{isLoading ? ( {isLoading ? (
<Preloader className="root__preloader" /> <Preloader className="root__preloader" />
) : ( ) : (
@@ -362,6 +344,14 @@ export function ConnectedRoot() {
const props = useSelector(mapStateToProps); const props = useSelector(mapStateToProps);
const actions = useActions(boundActions); const actions = useActions(boundActions);
useEffect(() => {
const observer = new ResizeObserver(updateIframeHeight);
updateIframeHeight();
observer.observe(document.body);
return () => observer.disconnect();
}, []);
if (!window.remark_config) { if (!window.remark_config) {
throw new Error('Remark42: Config object is undefined'); throw new Error('Remark42: Config object is undefined');
} }
@@ -2,13 +2,13 @@ import { h, JSX } from 'preact';
import { forwardRef } from 'preact/compat'; import { forwardRef } from 'preact/compat';
import { useEffect, useRef } from 'preact/hooks'; import { useEffect, useRef } from 'preact/hooks';
function autoResize(textarea: HTMLTextAreaElement) { function autoResize(textarea: HTMLTextAreaElement, onResize?: () => void) {
textarea.style.height = ''; textarea.style.height = '';
textarea.style.height = `${textarea.scrollHeight}px`; textarea.style.height = `${textarea.scrollHeight}px`;
} }
type Props = Omit<JSX.HTMLAttributes<HTMLTextAreaElement>, 'onInput'> & { type Props = Omit<JSX.HTMLAttributes<HTMLTextAreaElement>, 'onInput'> & {
onInput?: (evt: JSX.TargetedEvent<HTMLTextAreaElement, Event>) => void; onInput?(evt: JSX.TargetedEvent<HTMLTextAreaElement, Event>): void;
}; };
export const TextareaAutosize = forwardRef<HTMLTextAreaElement, Props>(({ onInput, value, ...props }, externalRef) => { export const TextareaAutosize = forwardRef<HTMLTextAreaElement, Props>(({ onInput, value, ...props }, externalRef) => {
+1
View File
@@ -33,6 +33,7 @@ const config: Config = {
setupFilesAfterEnv: [ setupFilesAfterEnv: [
'<rootDir>/app/__mocks__/fetch.ts', '<rootDir>/app/__mocks__/fetch.ts',
'<rootDir>/app/__mocks__/localstorage.ts', '<rootDir>/app/__mocks__/localstorage.ts',
'<rootDir>/app/__mocks__/resize-observer.ts',
'<rootDir>/app/__stubs__/remark-config.ts', '<rootDir>/app/__stubs__/remark-config.ts',
'<rootDir>/app/__stubs__/static-config.ts', '<rootDir>/app/__stubs__/static-config.ts',
], ],