Skip to content

Commit

Permalink
feat: support popup position
Browse files Browse the repository at this point in the history
  • Loading branch information
azu committed Jul 24, 2020
1 parent b99bd82 commit 42aa2f8
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 62 deletions.
1 change: 1 addition & 0 deletions packages/textchecker-element/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
"eventmit": "^1.0.2",
"lit-html": "^1.2.1",
"text-caret-pos": "^1.0.1",
"to-px": "^1.1.0",
"@textlint/kernel": "^3.2.1",
"@textlint/textlint-plugin-markdown": "^5.1.12",
"textlint-rule-preset-ja-technical-writing": "^4.0.0"
Expand Down
10 changes: 7 additions & 3 deletions packages/textchecker-element/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@
width: 800px;
margin: auto;
position: relative;

display: flex;
align-items: center;
}

textarea {
width: 12em;
height: 5em;
width: 100%;
height: 10em;
font-size: 24px;
}
</style>
Expand All @@ -25,7 +28,8 @@
</head>
<body>
<main class="main">
<label for="js-target"></label><textarea class="textarea" id="js-target">0123456789!ABCDEFGH? 日本語もいけるかな?</textarea>
<label for="js-target"></label><textarea class="textarea" id="js-target">0123456789!ABCDEFGH? 日本語もいけるかな?
お刺身が食べれない</textarea>
</main>
<script src="./index.ts"></script>
</body>
Expand Down
72 changes: 37 additions & 35 deletions packages/textchecker-element/public/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { TextCheckerElement } from "../src/textchecker-element";
import { TextCheckerPopupElement } from "../src/text-checker-popup-element";
import type { TextlintResult } from "@textlint/types";
import { RectItem } from "../src/textchecker-store";

const targetElement = document.querySelector("#js-target") as HTMLTextAreaElement;
const textChecker = new TextCheckerElement({
targetElement: targetElement
targetElement: targetElement,
hoverPadding: 4
});
const textCheckerPopup = new TextCheckerPopupElement();
targetElement.before(textChecker);
Expand All @@ -23,37 +25,37 @@ function debounce(fn: () => void, delay: number) {
}

const linter = new (window as any).Textlint();
targetElement.addEventListener(
"input",
debounce(async () => {
const result: TextlintResult = await linter.lintText(targetElement.value);
const messages = result.messages;
console.log(result);
const annotations = messages.map((message) => {
const card = {
id: message.ruleId + "::" + message.index,
message: message.message
};
return {
start: message.index,
end: message.index + 1,
onMouseEnter: ({ rectItem }) => {
console.log("enteR", count);
const boundingClientRect = targetElement.getBoundingClientRect();
textCheckerPopup.updateCard(card, {
index: rectItem.index,
top: boundingClientRect.y + rectItem.top + rectItem.height,
left: boundingClientRect.x + rectItem.left,
width: rectItem.width,
height: rectItem.height
});
},
onMouseLeave() {
console.log("leave", count);
textCheckerPopup.dismissCard(card);
}
};
});
textChecker.updateAnnotations(annotations);
}, 500)
);
const update = debounce(async () => {
const result: TextlintResult = await linter.lintText(targetElement.value);
const messages = result.messages;
console.log(result);
const annotations = messages.map((message) => {
const card = {
id: message.ruleId + "::" + message.index,
message: message.message
};
return {
start: message.index,
end: message.index + 1,
onMouseEnter: ({ rectItem }: { rectItem: RectItem }) => {
textCheckerPopup.updateCard(card, {
top:
rectItem.boxBorderWidth +
rectItem.boxMarginTop +
rectItem.boxPaddingTop +
rectItem.boxAbsoluteY +
rectItem.top +
rectItem.height,
left: rectItem.boxAbsoluteX + rectItem.left,
width: rectItem.width
});
},
onMouseLeave() {
textCheckerPopup.dismissCard(card);
}
};
});
textChecker.updateAnnotations(annotations);
}, 500);
targetElement.addEventListener("input", update);
update();
14 changes: 10 additions & 4 deletions packages/textchecker-element/src/text-checker-popup-element.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
import { html, render } from "lit-html";
import { eventmit } from "eventmit";
import { RectItem } from "./textchecker-store";

export type TextCheckerElementAttributes = {
target?: HTMLElement;
};
type TextCheckerCard = {
export type TextCheckerCard = {
id: string;
message: string;
};
export type TextCheckerCardRect = {
left: number;
top: number;
width: number;
height?: number;
};

type TextCheckerPopupState = {
card?: TextCheckerCard;
targetRect?: RectItem;
targetRect?: TextCheckerCardRect;
};
const createTextCheckerPopupState = (state?: Partial<TextCheckerPopupState>) => {
let currentState: TextCheckerPopupState = {
Expand Down Expand Up @@ -78,7 +84,7 @@ export class TextCheckerPopupElement extends HTMLElement {
});
}

public updateCard(card: TextCheckerCard, rect: RectItem) {
public updateCard(card: TextCheckerCard, rect: TextCheckerCardRect) {
this.store.update({
card,
targetRect: rect
Expand Down
71 changes: 54 additions & 17 deletions packages/textchecker-element/src/textchecker-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import textCaretPos from "text-caret-pos";
import { html, render } from "lit-html";
import { AnnotationItem, createTextCheckerStore, RectItem, TextCheckerState } from "./textchecker-store";

const toPX = require("to-px");
export type TextCheckerElementAttributes = {
targetElement: HTMLTextAreaElement;
hoverPadding: number;
};
const Marker = (rect: RectItem, isHighLight: boolean = false) => {
if (isHighLight) {
Expand All @@ -21,10 +23,12 @@ export class TextCheckerElement extends HTMLElement {
private annotationBox!: HTMLDivElement;
private targetElement!: HTMLTextAreaElement;
private store: ReturnType<typeof createTextCheckerStore>;
private hoverPadding: number;

constructor(args: TextCheckerElementAttributes) {
super();
this.targetElement = args.targetElement;
this.hoverPadding = args.hoverPadding;
this.store = createTextCheckerStore();
}

Expand Down Expand Up @@ -72,7 +76,18 @@ export class TextCheckerElement extends HTMLElement {
})
.join("");
this.annotationBox.setAttribute("style", copyStyle + "pointer-events: none;");
//
// box
const fontSize: number = toPX(targetStyle.getPropertyValue("font-size")) ?? 16.123;
const boxMarginTop: number = toPX(targetStyle.getPropertyValue("margin-top")) ?? 0;
const boxMarginBottom: number = toPX(targetStyle.getPropertyValue("margin-bottom")) ?? 0;
const boxBorderWidth: number = toPX(targetStyle.getPropertyValue("border-width")) ?? 0;
const boxPaddingTop: number = toPX(targetStyle.getPropertyValue("padding-top")) ?? 0;
const boxPaddingBottom: number = toPX(targetStyle.getPropertyValue("padding-bottom")) ?? 0;
const boundingClientRect = target.getBoundingClientRect();
const boxAbsoluteX: number = boundingClientRect.x;
const boxAbsoluteY: number = boundingClientRect.y;
const boxWidth: number = boundingClientRect.width;
const boxHeight: number = boundingClientRect.height;
const rectItems = annotationItems.flatMap((annotation, index) => {
const start = annotation.start;
const end = annotation.end;
Expand All @@ -89,7 +104,6 @@ export class TextCheckerElement extends HTMLElement {
returnDiv: true,
debug: false
});
const fontSize = Number(targetStyle.getPropertyValue("font-size").replace("px", ""));
const rectItems: RectItem[] =
startCoordinate.top === endCoordinate.top
? [
Expand All @@ -98,7 +112,16 @@ export class TextCheckerElement extends HTMLElement {
left: target.offsetLeft - target.scrollLeft + startCoordinate.left,
top: target.offsetTop - target.scrollTop + startCoordinate.top,
height: fontSize, //startCoordinate.height,
width: endCoordinate.left - startCoordinate.left
width: endCoordinate.left - startCoordinate.left,
boxMarginTop,
boxMarginBottom,
boxBorderWidth,
boxAbsoluteX,
boxAbsoluteY,
boxWidth,
boxHeight,
boxPaddingTop,
boxPaddingBottom
}
]
: // two line
Expand All @@ -108,14 +131,31 @@ export class TextCheckerElement extends HTMLElement {
left: target.offsetLeft - target.scrollLeft + startCoordinate.left,
top: target.offsetTop - target.scrollTop + startCoordinate.top,
height: fontSize, //startCoordinate.height,
width: (startCoordinate?._div?.getBoundingClientRect()?.width ?? 0) - startCoordinate.left
width:
(startCoordinate?._div?.getBoundingClientRect()?.width ?? 0) - startCoordinate.left,
boxMarginTop,
boxMarginBottom,
boxBorderWidth,
boxAbsoluteX,
boxAbsoluteY,
boxWidth,
boxHeight
},
{
index,
left: target.offsetLeft - target.scrollLeft,
top: target.offsetTop - target.scrollTop + endCoordinate.top,
height: fontSize,
width: (startCoordinate?._div?.getBoundingClientRect()?.left ?? 0) + endCoordinate.left
width: (startCoordinate?._div?.getBoundingClientRect()?.left ?? 0) + endCoordinate.left,
boxMarginTop,
boxMarginBottom,
boxBorderWidth,
boxAbsoluteX,
boxAbsoluteY,
boxWidth,
boxHeight,
boxPaddingTop,
boxPaddingBottom
}
];
return rectItems;
Expand All @@ -132,22 +172,19 @@ export class TextCheckerElement extends HTMLElement {
};

onMouseUpdate = (event: MouseEvent) => {
const clientRect = (event.currentTarget as HTMLTextAreaElement)?.getBoundingClientRect() ?? {
left: 0,
top: 0
};
const point = {
x: event.clientX - clientRect.left,
y: event.clientY - clientRect.top
};
const state = this.store.get();
const hoverPadding = this.hoverPadding;
const isIncludedIndexes = state.rectItems
.filter((rect) => {
const point = {
x: event.clientX - rect.boxAbsoluteX,
y: event.clientY - rect.boxAbsoluteY
};
return (
rect.left <= point.x &&
point.x <= rect.left + rect.width &&
rect.top <= point.y &&
point.y <= rect.top + rect.height
rect.left - hoverPadding <= point.x &&
point.x <= rect.left + hoverPadding + rect.width &&
rect.top - hoverPadding <= point.y &&
point.y <= rect.top + rect.height + hoverPadding
);
})
.map((item) => item.index);
Expand Down
24 changes: 21 additions & 3 deletions packages/textchecker-element/src/textchecker-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,26 @@ export type AnnotationItem = {
onMouseEnter: ({ rectItem }: { rectItem: RectItem }) => void;
onMouseLeave: ({ rectItem }: { rectItem: RectItem }) => void;
};

export type RectItem = { index: number; left: number; top: number; height: number; width: number };
/**
* RectItem is pixel based
*/
export type RectItem = {
index: number;
left: number;
top: number;
height: number;
width: number;
// box
boxPaddingTop: number;
boxPaddingBottom: number;
boxMarginTop: number;
boxMarginBottom: number;
boxBorderWidth: number;
boxAbsoluteX: number;
boxAbsoluteY: number;
boxWidth: number;
boxHeight: number;
};
export type TextCheckerState = {
rectItems: RectItem[];
annotationItems: AnnotationItem[];
Expand Down Expand Up @@ -37,7 +55,7 @@ export const createTextCheckerStore = (initialState?: Partial<TextCheckerState>)
highlightRectIndexes(indexes: RectItem["index"][]) {
textCheckerState = {
...textCheckerState,
highlightRectIdSet: new Set([...textCheckerState.highlightRectIdSet, ...indexes])
highlightRectIdSet: new Set(indexes)
};
changeEvent.emit();
},
Expand Down
12 changes: 12 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5018,6 +5018,11 @@ parse-json@^5.0.0:
json-parse-better-errors "^1.0.1"
lines-and-columns "^1.1.6"

parse-unit@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/parse-unit/-/parse-unit-1.0.1.tgz#7e1bb6d5bef3874c28e392526a2541170291eecf"
integrity sha1-fhu21b7zh0wo45JSaiVBFwKR7s8=

parse5@5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.0.tgz#c59341c9723f414c452975564c7c00a68d58acd2"
Expand Down Expand Up @@ -7098,6 +7103,13 @@ to-object-path@^0.3.0:
dependencies:
kind-of "^3.0.2"

to-px@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/to-px/-/to-px-1.1.0.tgz#b6b269ed5db0cc9aefc15272a4c8bcb2ca1e99ca"
integrity sha512-bfg3GLYrGoEzrGoE05TAL/Uw+H/qrf2ptr9V3W7U0lkjjyYnIfgxmVLUfhQ1hZpIQwin81uxhDjvUkDYsC0xWw==
dependencies:
parse-unit "^1.0.1"

to-regex-range@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38"
Expand Down

0 comments on commit 42aa2f8

Please sign in to comment.