From 8ffe945094c0fc50aa91225a778cbd43c195fd36 Mon Sep 17 00:00:00 2001 From: Harry Marr Date: Fri, 18 Dec 2020 11:39:48 -0500 Subject: [PATCH] Add elementFilter option --- example/example.js | 11 ++++++++ example/index.html | 1 + src/element-overlay.ts | 1 + src/element-picker.ts | 57 +++++++++++++++++++++++++++++------------- 4 files changed, 53 insertions(+), 17 deletions(-) diff --git a/example/example.js b/example/example.js index 540d611..28a57d0 100644 --- a/example/example.js +++ b/example/example.js @@ -3,6 +3,7 @@ import { ElementPicker } from "pick-dom-element"; function main() { const status = document.getElementById("status"); const startButton = document.getElementById("start"); + const onlyEmphasisCheckbox = document.getElementById("only-emphasis"); const setElement = (el) => { const tags = []; @@ -17,6 +18,10 @@ function main() { }; const picker = new ElementPicker(); + let onlyEmphasis = onlyEmphasisCheckbox.checked; + onlyEmphasisCheckbox.onchange = (ev) => { + onlyEmphasis = ev.target.checked; + } const start = () => { startButton.disabled = true; picker.start({ @@ -25,6 +30,12 @@ function main() { picker.stop(); startButton.disabled = false; }, + elementFilter: (el) => { + if (!onlyEmphasis) { + return true; + } + return ['I', 'B'].includes(el.tagName); + } }); }; diff --git a/example/index.html b/example/index.html index a58bf4b..e9e9d55 100644 --- a/example/index.html +++ b/example/index.html @@ -22,5 +22,6 @@

Element Picker example

Click "start" to activate the picker.
+ diff --git a/src/element-overlay.ts b/src/element-overlay.ts index 165367d..99b7e20 100644 --- a/src/element-overlay.ts +++ b/src/element-overlay.ts @@ -38,6 +38,7 @@ export default class ElementOverlay { } removeFromDOM() { + this.setBounds({ x: 0, y: 0, width: 0, height: 0 }); this.overlay.remove(); if (this.usingShadowDOM) { this.shadowContainer.remove(); diff --git a/src/element-picker.ts b/src/element-picker.ts index 4df66ac..549fe74 100644 --- a/src/element-picker.ts +++ b/src/element-picker.ts @@ -1,12 +1,13 @@ import ElementOverlay from "./element-overlay"; import { getElementBounds } from "./utils"; -type ElementCallback = (el: HTMLElement) => void; +type ElementCallback = (el: HTMLElement) => T; type ElementPickerOptions = { parentElement?: Node; useShadowDOM?: boolean; - onClick?: ElementCallback; - onHover?: ElementCallback; + onClick?: ElementCallback; + onHover?: ElementCallback; + elementFilter?: ElementCallback; }; export default class ElementPicker { @@ -50,6 +51,9 @@ export default class ElementPicker { document.removeEventListener("click", this.handleClick, true); this.overlay.removeFromDOM(); + this.target = undefined; + this.mouseX = undefined; + this.mouseY = undefined; if (this.tickReq) { window.cancelAnimationFrame(this.tickReq); @@ -69,24 +73,43 @@ export default class ElementPicker { }; private tick = () => { - if (this.mouseX && this.mouseY) { - this.overlay.ignoreCursor(); - const elAtCursor = document.elementFromPoint(this.mouseX, this.mouseY); - const newTarget = elAtCursor as HTMLElement; - this.overlay.captureCursor(); + this.updateTarget(); + this.tickReq = window.requestAnimationFrame(this.tick); + }; + + private updateTarget() { + if (this.mouseX === undefined || this.mouseY === undefined) { + return; + } - if (newTarget && newTarget !== this.target) { - this.target = newTarget; + // Peek through the overlay to find the new target + this.overlay.ignoreCursor(); + const elAtCursor = document.elementFromPoint(this.mouseX, this.mouseY); + const newTarget = elAtCursor as HTMLElement; + this.overlay.captureCursor(); - const bounds = getElementBounds(newTarget); - this.overlay.setBounds(bounds); + // If the target hasn't changed, there's nothing to do + if (!newTarget || newTarget === this.target) { + return; + } - if (this.options?.onHover) { - this.options.onHover(newTarget); - } + // If we have an element filter and the new target doesn't match, + // clear out the target + if (this.options?.elementFilter) { + if (!this.options.elementFilter(newTarget)) { + this.target = undefined; + this.overlay.setBounds({ x: 0, y: 0, width: 0, height: 0 }); + return; } } - this.tickReq = window.requestAnimationFrame(this.tick); - }; + this.target = newTarget; + + const bounds = getElementBounds(newTarget); + this.overlay.setBounds(bounds); + + if (this.options?.onHover) { + this.options.onHover(newTarget); + } + } }