Skip to content

Commit

Permalink
Merge pull request #23 from masuP9/fix/reposition-alt-editor
Browse files Browse the repository at this point in the history
Fix reposition alt editor
  • Loading branch information
masuP9 authored May 9, 2021
2 parents 3e528ab + 569c612 commit cbaa076
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 35 deletions.
61 changes: 40 additions & 21 deletions src/scripts/components/AltEditor/AltEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useEffect, useState, useMemo } from 'react';
import styled from 'styled-components';

export type Position = {
Expand All @@ -11,41 +11,60 @@ type Props = React.FormHTMLAttributes<HTMLFormElement> & {
onClose: () => void;
};

const MARGIN_BETWEEN_FORM_AND_IMAGE = 12;

const getPositionFromImage = (image: HTMLImageElement): Position => {
const rect = image.getBoundingClientRect();

return {
left: rect.right + 12,
top: rect.top,
left: rect.right + MARGIN_BETWEEN_FORM_AND_IMAGE,
top: window.pageYOffset + rect.top,
};
};

export const AltEditor: React.VFC<Props> = ({ selectedImage, onClose, ...rest }) => {
const [value, setValue] = React.useState('');
const [position, setPosition] = React.useState<Position>({ left: 0, top: 0 });
const [altUpdateSuccess, setAltUpdateSuccess] = React.useState(false);
const imageObserver = React.useMemo(
const [value, setValue] = useState('');
const [position, setPosition] = useState<Position>({ left: 0, top: 0 });
const [altUpdateSuccess, setAltUpdateSuccess] = useState(false);

const imageSizeObserver = useMemo(
() =>
new MutationObserver((records) => {
records.forEach((record) => {
const { target, oldValue, attributeName } = record;
if (
target instanceof HTMLImageElement &&
attributeName !== null &&
oldValue !== target.getAttribute(attributeName)
) {
setPosition(getPositionFromImage(target));
}
new ResizeObserver((records) => {
records.forEach((entry) => {
const { contentRect } = entry;
setPosition(contentRect);
});
}),
[],
);

React.useEffect(() => {
useEffect(() => {
setValue(selectedImage.alt);
setPosition(getPositionFromImage(selectedImage));
imageObserver.observe(selectedImage, { attributeFilter: ['style'] });
}, [selectedImage, imageObserver]);
imageSizeObserver.observe(selectedImage);

return () => {
imageSizeObserver.disconnect();
};
}, [selectedImage, imageSizeObserver]);

const bodySizeObserver = useMemo(
() =>
new ResizeObserver((entries) =>
entries.forEach((entry) => {
setPosition(getPositionFromImage(selectedImage));
}),
),
[selectedImage],
);

useEffect(() => {
bodySizeObserver.observe(document.body);

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

const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
Expand Down Expand Up @@ -91,7 +110,7 @@ type FormProps = {
const Form = styled.form<FormProps>`
position: absolute !important;
z-index: 1 !important;
top: ${({ position }) => `${window.pageYOffset + position.top}px`} !important;
top: ${({ position }) => `${position.top}px`} !important;
left: ${({ position }) => `${position.left}px`} !important;
padding: 1em !important;
border-radius: 4px !important;
Expand Down
21 changes: 8 additions & 13 deletions src/scripts/components/App/App.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,30 @@
import React from 'react';
import React, { useEffect, useState, useMemo } from 'react';
import { AltEditor } from '../AltEditor';

export type Position = {
left: number;
top: number;
};

const filterFirstChildImagesFromNodes = (nodeList: NodeList): HTMLImageElement[] => {
const childNodes = Array.from(nodeList).flatMap((node) => (node.firstChild != null ? [node.firstChild] : []));
const images = childNodes.filter((node): node is HTMLImageElement => node instanceof HTMLImageElement);
return images;
};

export const App: React.VFC = () => {
const [selectedImage, setSelectedImage] = React.useState<HTMLImageElement | null>(null);
const [observingRoot, setObservingRoot] = React.useState<boolean>(false);
const [selectedImage, setSelectedImage] = useState<HTMLImageElement | null>(null);
const [observingRoot, setObservingRoot] = useState<boolean>(false);

const handleClickAddedImage = (e: Event) => {
if (e.target instanceof HTMLImageElement) {
setSelectedImage(e.target);
}
};

const editorObserverOption = React.useMemo<MutationObserverInit>(
const editorObserverOption = useMemo<MutationObserverInit>(
() => ({
childList: true,
}),
[],
);

const editorObserver = React.useMemo(
const editorObserver = useMemo(
() =>
new MutationObserver((records) => {
records.forEach((record) => {
Expand Down Expand Up @@ -60,14 +55,14 @@ export const App: React.VFC = () => {
[],
);

const rootObserverOption = React.useMemo<MutationObserverInit>(
const rootObserverOption = useMemo<MutationObserverInit>(
() => ({
childList: true,
}),
[],
);

const rootObserver = React.useMemo(
const rootObserver = useMemo(
() =>
new MutationObserver((recodes) => {
recodes.forEach((_recode) => {
Expand All @@ -93,7 +88,7 @@ export const App: React.VFC = () => {
[editorObserver, editorObserverOption, observingRoot],
);

React.useEffect(() => {
useEffect(() => {
const editorElement = document.getElementById('note-body');

if (!observingRoot) {
Expand Down
2 changes: 1 addition & 1 deletion src/scripts/components/App/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { App, Position } from './App';
export { App } from './App';

0 comments on commit cbaa076

Please sign in to comment.