-
Notifications
You must be signed in to change notification settings - Fork 54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
♻️ Change flag opening/closing logic #80
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[moved comment inline]
src/quill-cursors/quill-cursors.ts
Outdated
@@ -110,6 +116,26 @@ export default class QuillCursors { | |||
private _registerDomListeners(): void { | |||
const editor = this.quill.container.getElementsByClassName('ql-editor')[0]; | |||
editor.addEventListener('scroll', () => this.update()); | |||
|
|||
editor.addEventListener('mousemove', throttle(this._toggleNearCursors.bind(this), 100)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels pretty heavy-handed to me. Using a throttle like this is a bit of a code smell.
Did you try mouseenter
and mouseleave
? I think from experience they can be a bit flaky, so no big deal if they didn't work.
However, I'd rather we then move to use mouseover
, and specifically attach to the elements we care about our mouse being inside. That would at least target our events a bit better, and would avoid needing to have the concept of being "near" the cursor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've tried it, but it doesn't work with z-index: -1
.
But we need to have z-index: -1
, otherwise a caret overflows the text and we can't really click on the text (also, keep in mind, that it should work with touch devices).
assets/quill-cursors.scss
Outdated
padding: 0 $spacing-sm; | ||
z-index: 1; | ||
|
||
z-index: -1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this might theoretically be breaking. If you have a background on your Quill instance, the carets will no longer be visible.
If we need this, then fine, but we should major version and add this to the changelog.
@fyvfyv thanks for your patience! I've done a bit of tinkering, and I've potentially got an avenue we can explore that doesn't require constantly listening for The basic principles are:
This potentially handles a lot of events if a client makes extremely small movements within the cursor (thus staying in the manual mouseout check), but given that the cursor is so small, I think this is very unlikely. What do you think? |
@alecgibson Yeah, it might work. I'm trying to implement it in this repo and let's check |
6d7e1b4
to
7aaa8d9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
7aaa8d9
to
bd73218
Compare
29fae41
to
0badba7
Compare
src/quill-cursors/cursor.ts
Outdated
@@ -106,6 +132,28 @@ export default class Cursor { | |||
selections.forEach((selection: ClientRect) => this._addSelection(selection, container)); | |||
} | |||
|
|||
private _setHoverState(): void { | |||
this._caretEl.classList.add(Cursor.CONTAINER_NO_POINTER_CLASS); | |||
document.addEventListener('mouseover', this._toggleOpenedCursor); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're still getting the flag "stuck" as per my previous comment. However, I think we can fix it if we change this to listen for mousemove
instead:
document.addEventListener('mouseover', this._toggleOpenedCursor); | |
document.addEventListener('mousemove', this._toggleOpenedCursor); |
src/quill-cursors/cursor.ts
Outdated
@@ -29,11 +33,15 @@ export default class Cursor { | |||
private _hideDelay: string; | |||
private _hideSpeedMs: number; | |||
private _positionFlag: (flag: HTMLElement, caretRectangle: ClientRect, container: ClientRect) => void; | |||
private _showFlagTimeout: NodeJS.Timeout; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused?
src/quill-cursors/cursor.ts
Outdated
@@ -106,6 +132,28 @@ export default class Cursor { | |||
selections.forEach((selection: ClientRect) => this._addSelection(selection, container)); | |||
} | |||
|
|||
private _setHoverState(): void { | |||
this._caretEl.classList.add(Cursor.CONTAINER_NO_POINTER_CLASS); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think you need this line
src/quill-cursors/cursor.ts
Outdated
document.removeEventListener('mouseover', this._toggleOpenedCursor); | ||
if (!shouldShow) { | ||
this._showFlagTimeout = null; | ||
return; | ||
} | ||
|
||
this._showFlagTimeout = setTimeout(this._setHoverState, 100); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if I'm missing something here?
document.removeEventListener('mouseover', this._toggleOpenedCursor); | |
if (!shouldShow) { | |
this._showFlagTimeout = null; | |
return; | |
} | |
this._showFlagTimeout = setTimeout(this._setHoverState, 100); | |
if (!shouldShow) document.removeEventListener('mousemove', this._toggleOpenedCursor); |
src/quill-cursors/cursor.ts
Outdated
const {x, y, width, height} = this._caretEl.getBoundingClientRect(); | ||
this.coordinates = {x, y, width, height}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think our maths would be more readable if we changed to:
const {x, y, width, height} = this._caretEl.getBoundingClientRect(); | |
this.coordinates = {x, y, width, height}; | |
const {left, right, top, bottom} = this._caretEl.getBoundingClientRect(); | |
this.coordinates = {left, right, top, bottom}; |
src/quill-cursors/cursor.ts
Outdated
const isYNear = pointY - y - height <= 0 && pointY - y >= 0; | ||
const shouldShow = isXNear && isYNear; | ||
|
||
this.toggleFlag(shouldShow); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
toggleFlag()
(deliberately) ignores the hideDelay
option, but we should honour the hideDelay
when moving our mouse away.
public toggleFlag(shouldShow?: boolean): void { | ||
const isShown = this._flagEl.classList.toggle(Cursor.SHOW_FLAG_CLASS, shouldShow); | ||
if (isShown) return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did we remove this early return?
src/quill-cursors/cursor.ts
Outdated
} | ||
|
||
private _updateCoordinates(): void { | ||
const {x, y, width, height} = this._caretEl.getBoundingClientRect(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think getBoundingClientRect()
is an expensive function — rather than proactively update and track our coordinates, I think we should just ask for them when needed, so:
- Remove the
coordinates
property - Change
_updateCoordinates(): void
->_getCoordinates(): ICoordinates
- Replace references to
this.coordinates
withthis._getCoordinates()
0badba7
to
c48be2b
Compare
c48be2b
to
ff7c5ce
Compare
ff7c5ce
to
051adf4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couple of small tweaks, and I think we're there!
package.json
Outdated
@@ -1,6 +1,6 @@ | |||
{ | |||
"name": "quill-cursors", | |||
"version": "3.1.2", | |||
"version": "3.2.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's be conservative and bump a major version, since we're changing (including removing) some CSS classes, which people might be overriding, etc.
Also please update the CHANGELOG
with the breaking changes.
src/quill-cursors/quill-cursors.ts
Outdated
} | ||
|
||
private _handleCursorTouch(e: MouseEvent): void { | ||
const touchFlagDelay = 2000; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we use this._hideDelay
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, changed it to this.options.hideDelayMs
There is the issue with using CSS for opening/closing logic for flags. It's broken on touch devices (which don't trigger the `:hover` styling) (Issue #77). To fix it, we moved all the logic to JS: - Changed `z-index` to «move» a cursor behind the text. It resolves the issue, when a cursor prevent clicking on the text (even if a user clicks exactly on cursor) - Added listeners for `mousemove` and `touchstart` with a callback, which shows/closes flags depends on a point position To achieve it there are added a couple of callbacks to update cursors position and store it in the quill-cursors module. It should be enough to cover all cases for touch and non-touch devices. Also, there is a small throttling for mousemove events to improve performance and decrease amount of callbacks executions
051adf4
to
d4a57f9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉
There is the issue with using CSS for opening/closing logic for flags. It's broken on touch devices (which don't trigger the
:hover
styling) (Issue #77). To fix it, we moved all the logic to JS:z-index
to «move» a cursor behind the text. It resolves the issue, when a cursor prevent clicking on the text (even if a user clicks exactly on cursor)mousemove
andtouchstart
with a callback, which shows/closes flags depends on a point positionTo achieve it there are added a couple of callbacks to update cursors position and store it in the quill-cursors module. It should be enough to cover all cases for touch and non-touch devices. Also, there is a small throttling for mousemove events to improve performance and decrease amount of callbacks executions