- Now cursor is right position while scrolling.
- Hide if non-editable element.
This commit is contained in:
vorotamoroz 2022-08-31 12:02:12 +09:00
parent 37a17b1c29
commit f1f018e983
2 changed files with 153 additions and 111 deletions

90
main.ts
View file

@ -23,8 +23,30 @@ class NinjaCursorForWindow {
ad.body.appendChild(this.wrapperElement);
this.cursorElement.addClass("x-cursor");
const root = ad.documentElement;
const moveCursor = () => {
let datumTop = 0;
let datumElement: HTMLElement;
let cursorVisibility = false;
const moveCursor = (e?: Event, noAnimate?: boolean) => {
if (e && e.target instanceof HTMLElement && (e.target.isContentEditable || e.target.tagName == "INPUT")) {
// If it caused by clicking an element and it is editable.
datumElement = e.target;
if (!cursorVisibility) {
root.style.setProperty("--cursor-visibility", `visible`);
cursorVisibility = true;
}
} else if (e != null) {
// If it caused by clicking an element but it is not editable.
if (cursorVisibility) {
root.style.setProperty("--cursor-visibility", `hidden`);
cursorVisibility = false;
}
return;
}
if (e && e.target instanceof HTMLElement) {
// Memo datum element for scroll.
datumElement = e.target;
}
datumTop = datumElement.getBoundingClientRect().top;
const selection = aw.getSelection();
if (!selection) {
console.log("Could not find selection");
@ -45,15 +67,15 @@ class NinjaCursorForWindow {
if (textRect.x == 0 && textRect.y == 0) {
textRange.setStart(range.endContainer, range.endOffset - 1);
textRange.setEnd(range.endContainer, range.endOffset);
const textRectx = textRange.getClientRects();
const txx = textRectx.item(textRectx.length - 1);
if (!txx) {
const textRects = textRange.getClientRects();
const tempRect = textRects.item(textRects.length - 1);
if (!tempRect) {
console.log("Could not found");
return;
}
textRect = txx;
textRect.x = txx.right;
textRect.y = txx.bottom - txx.height;
textRect = tempRect;
textRect.x = tempRect.right;
textRect.y = tempRect.bottom - tempRect.height;
}
if (textRect.x == 0 && textRect.y == 0) {
@ -78,6 +100,7 @@ class NinjaCursorForWindow {
Math.abs(Math.sin(cursorDragAngle)) * 8 +
Math.abs(Math.cos(cursorDragAngle)) * rect.height;
const cursorDragWidth = cursorDragDistance;
root.style.setProperty(
"--cursor-drag-height",
`${cursorDragHeight}px`
@ -92,13 +115,19 @@ class NinjaCursorForWindow {
);
root.style.setProperty("--cursor-height", `${rect.height}px`);
root.style.setProperty("--cursor-x1", `${this.lastPos.x}px`);
root.style.setProperty("--cursor-y1", `${this.lastPos.y}px`);
root.style.setProperty("--cursor-y1src", `${this.lastPos.y}px`);
root.style.setProperty("--cursor-x2", `${rect.x}px`);
root.style.setProperty("--cursor-y2", `${rect.y}px`);
root.style.setProperty("--cursor-y2src", `${rect.y}px`);
root.style.setProperty("--cursor-offset-y", `${0}px`);
if (noAnimate) {
this.lastPos = rect;
return;
}
this.cursorElement.removeClass("x-cursor0");
this.cursorElement.removeClass("x-cursor1");
this.cursorElement.getAnimations().forEach((anim) => anim.cancel());
datumTop = datumElement.getBoundingClientRect().top;
aw.requestAnimationFrame((time) => {
this.cursorElement.addClass(`x-cursor${this.styleCount}`);
this.lastPos = rect;
@ -106,23 +135,30 @@ class NinjaCursorForWindow {
};
registerDomEvent(aw, "keydown", () => {
moveCursor();
});
registerDomEvent(aw, "keyup", () => {
moveCursor();
});
registerDomEvent(aw, "mousedown", () => {
moveCursor();
});
registerDomEvent(aw, "mouseup", () => {
moveCursor();
});
registerDomEvent(aw, "touchend", () => {
moveCursor();
});
registerDomEvent(aw, "touchstart", () => {
moveCursor();
const supportVIMMode = true;
const eventNames = ["keydown", "mousedown", "touchend", ...(supportVIMMode ? ["keyup", "mouseup", "touchstart"] : [])];
for (const event of eventNames) {
registerDomEvent(aw, event, (ev: Event) => {
moveCursor(ev);
});
}
// Handles scroll till scroll is finish.
const applyWheelScroll = (last?: number | boolean) => {
requestAnimationFrame(() => {
if (datumElement) {
const curTop = datumElement.getBoundingClientRect().top;
const diff = curTop - datumTop;
root.style.setProperty("--cursor-offset-y", `${diff}px`);
if (last === false || last != diff) {
requestAnimationFrame(() => applyWheelScroll(diff));
} else if (last == diff) {
moveCursor(undefined, true);
}
}
});
}
registerDomEvent(aw, "wheel", (e: WheelEvent) => {
applyWheelScroll(false);
});
}

View file

@ -1,114 +1,120 @@
.x-cursor {
position: absolute;
top: 0;
left: 0;
height: var(--cursor-height);
width: 8px;
display: inline-block;
user-select: none;
background: var(--text-normal);
transform: translate3d(var(--cursor-x2), var(--cursor-y2), 0);
opacity: 0;
pointer-events: none;
position: relative;
top: 0;
left: 0;
height: var(--cursor-height);
width: 8px;
display: inline-block;
user-select: none;
background: var(--text-normal);
transform: translate3d(var(--cursor-x2), var(--cursor-y2), 0);
opacity: 0;
pointer-events: none;
visibility: var(--cursor-visibility);
}
.x-cursor:after {
content: "";
height: var(--cursor-drag-height);
width: var(--cursor-drag-width);
display: inline-block;
user-select: none;
background: linear-gradient(to right, var(--text-normal), transparent);
transform: rotate(var(--cursor-drag-angle));
transform-origin: 4px center;
opacity: 0.5;
pointer-events: none;
content: "";
height: var(--cursor-drag-height);
width: var(--cursor-drag-width);
display: inline-block;
user-select: none;
background: linear-gradient(to right, var(--text-normal), transparent);
transform: rotate(var(--cursor-drag-angle));
transform-origin: 4px center;
opacity: 0.5;
pointer-events: none;
}
.x-cursor0 {
animation: a1 75ms cubic-bezier(0.34, 1.26, 0.84, 1) 0s both;
animation: a1 75ms cubic-bezier(0.34, 1.26, 0.84, 1) 0s both;
}
.x-cursor1 {
animation: a2 75ms cubic-bezier(0.34, 1.26, 0.84, 1) 0s both;
animation: a2 75ms cubic-bezier(0.34, 1.26, 0.84, 1) 0s both;
}
:root {
--cursor-x1: "0px";
--cursor-x2: "0px";
--cursor-y1: "0px";
--cursor-y2: "0px";
--cursor-drag-distance: "0px";
--cursor-drag-angle: "0deg";
--cursor-drag-width: "0px";
--cursor-drag-height: "0px";
--cursor-x1: "0px";
--cursor-x2: "0px";
--cursor-y1src: "0px";
--cursor-y2src: "0px";
--cursor-offset-y: "0px";
--cursor-drag-distance: "0px";
--cursor-drag-angle: "0deg";
--cursor-drag-width: "0px";
--cursor-drag-height: "0px";
--cursor-height: 18px;
--cursor-height: 18px;
--cursor-y1: calc(var(--cursor-y1src) + var(--cursor-offset-y));
--cursor-y2: calc(var(--cursor-y2src) + var(--cursor-offset-y));
--cursor-visibility: "hidden";
/* --cursor-color: --text-normal; */
}
.cursorWrapper {
display: block;
overflow: hidden;
user-select: none;
pointer-events: none;
background-color: transparent;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: 0;
padding: 0;
display: block;
overflow: hidden;
user-select: none;
pointer-events: none;
background-color: transparent;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: 0;
padding: 0;
}
@keyframes a1 {
0% {
transform: translate3d(var(--cursor-x1), var(--cursor-y1), 0);
background-color: var(--text-normal);
opacity: 0;
}
0% {
transform: translate3d(var(--cursor-x1), var(--cursor-y1), 0);
background-color: var(--text-normal);
opacity: 0;
}
4% {
opacity: 1;
}
4% {
opacity: 1;
}
80% {
opacity: 0.95;
}
80% {
opacity: 0.95;
}
90% {
transform: translate3d(var(--cursor-x2), var(--cursor-y2), 0);
background-color: var(--text-normal);
opacity: 0.9;
}
90% {
transform: translate3d(var(--cursor-x2), var(--cursor-y2), 0);
background-color: var(--text-normal);
opacity: 0.9;
}
100% {
opacity: 0;
}
100% {
opacity: 0;
}
}
@keyframes a2 {
0% {
transform: translate3d(var(--cursor-x1), var(--cursor-y1), 0);
background-color: var(--text-normal);
opacity: 0;
}
0% {
transform: translate3d(var(--cursor-x1), var(--cursor-y1), 0);
background-color: var(--text-normal);
opacity: 0;
}
4% {
opacity: 1;
}
4% {
opacity: 1;
}
80% {
opacity: 0.95;
}
80% {
opacity: 0.95;
}
90% {
transform: translate3d(var(--cursor-x2), var(--cursor-y2), 0);
background-color: var(--text-normal);
opacity: 0.9;
}
90% {
transform: translate3d(var(--cursor-x2), var(--cursor-y2), 0);
background-color: var(--text-normal);
opacity: 0.9;
}
100% {
opacity: 0;
}
}
100% {
opacity: 0;
}
}