interestfor 1.0.7 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -5
- package/build.sh +1 -1
- package/package.json +2 -4
- package/src/interestfor.js +43 -4
- package/src/interestfor.min.js +1 -1
package/README.md
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
# `interestfor` Polyfill
|
|
2
2
|
|
|
3
3
|
A polyfill for the `interestfor` attribute. This is a new API for "interest
|
|
4
|
-
interactions" that is in the process of being implemented in browsers. It
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
See the explainer for all of the details for the "real" feature:
|
|
4
|
+
interactions" that is in the process of being implemented in browsers. It [shipped](https://chromestatus.com/feature/4530756656562176)
|
|
5
|
+
in Chromium browsers (e.g. Chrome, Edge) in version 142 (October 2025).
|
|
6
|
+
See the MDN documentation for more details:
|
|
8
7
|
|
|
9
|
-
|
|
8
|
+
https://developer.mozilla.org/en-US/docs/Web/API/Popover_API/Using_interest_invokers
|
|
10
9
|
|
|
11
10
|
## Usage
|
|
12
11
|
To use this polyfill, simply load it:
|
package/build.sh
CHANGED
|
@@ -11,7 +11,7 @@ MINIFIED_FILE="${BUILD_DIR}/interestfor.min.js"
|
|
|
11
11
|
OUTPUT_FILE="${SRC_DIR}/interestfor.min.js"
|
|
12
12
|
|
|
13
13
|
# Minify the combined file
|
|
14
|
-
terser "${SOURCE_FILE}" --compress --mangle --output "${MINIFIED_FILE}"
|
|
14
|
+
npx terser "${SOURCE_FILE}" --compress --mangle --output "${MINIFIED_FILE}"
|
|
15
15
|
|
|
16
16
|
cat COPYRIGHT "${MINIFIED_FILE}" > "${OUTPUT_FILE}"
|
|
17
17
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "interestfor",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "A polyfill for the `interestfor` API",
|
|
5
5
|
"keywords": "interestfor, interesttarget, polyfill, hover-triggering",
|
|
6
6
|
"homepage": "https://github.com/mfreed7/interestfor#readme",
|
|
@@ -11,7 +11,5 @@
|
|
|
11
11
|
},
|
|
12
12
|
"author": "Mason Freed <mfreed@mfreed.com>",
|
|
13
13
|
"license": "BSD-3-Clause",
|
|
14
|
-
"main": "src/interestfor.min.js"
|
|
15
|
-
"dependencies": {}
|
|
14
|
+
"main": "src/interestfor.min.js"
|
|
16
15
|
}
|
|
17
|
-
|
package/src/interestfor.js
CHANGED
|
@@ -44,6 +44,35 @@
|
|
|
44
44
|
capture: true,
|
|
45
45
|
});
|
|
46
46
|
}
|
|
47
|
+
|
|
48
|
+
if(!window.InterestEvent) {
|
|
49
|
+
window.InterestEvent = class InterestEvent extends Event {
|
|
50
|
+
#source;
|
|
51
|
+
constructor(type, eventInit = {}) {
|
|
52
|
+
super(type, eventInit);
|
|
53
|
+
const { source } = eventInit;
|
|
54
|
+
if (source != null && !(source instanceof Element)) {
|
|
55
|
+
throw new TypeError(`source must be an element`);
|
|
56
|
+
}
|
|
57
|
+
this.#source = source;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
get [Symbol.toStringTag]() {
|
|
61
|
+
return "InterestEvent";
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
get source() {
|
|
65
|
+
const source = this.#source;
|
|
66
|
+
if (!source) return null;
|
|
67
|
+
// Retarget `source` to the current event's root:
|
|
68
|
+
const sourceRoot = getRootNode(source);
|
|
69
|
+
if (sourceRoot !== getRootNode(this.target || document)) {
|
|
70
|
+
return sourceRoot.host;
|
|
71
|
+
}
|
|
72
|
+
return source;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
47
76
|
|
|
48
77
|
// Enum-like state and source
|
|
49
78
|
const InterestState = {
|
|
@@ -58,6 +87,14 @@
|
|
|
58
87
|
Touch: "touch",
|
|
59
88
|
};
|
|
60
89
|
|
|
90
|
+
function getRootNode(node) {
|
|
91
|
+
if (node && typeof node.getRootNode === "function") {
|
|
92
|
+
return node.getRootNode();
|
|
93
|
+
}
|
|
94
|
+
if (node && node.parentNode) return getRootNode(node.parentNode);
|
|
95
|
+
return node;
|
|
96
|
+
}
|
|
97
|
+
|
|
61
98
|
// Gain or lose interest
|
|
62
99
|
function GainOrLoseInterest(invoker, target, newState) {
|
|
63
100
|
if (!invoker || !target) {
|
|
@@ -208,7 +245,8 @@
|
|
|
208
245
|
if (data.state !== InterestState.NoInterest) {
|
|
209
246
|
throw new Error("Invalid state");
|
|
210
247
|
}
|
|
211
|
-
target.dispatchEvent(new
|
|
248
|
+
const shouldContinue = target.dispatchEvent(new InterestEvent(interestEventName, { source: invoker }));
|
|
249
|
+
if (!shouldContinue) return;
|
|
212
250
|
try {
|
|
213
251
|
target.showPopover({ source: invoker });
|
|
214
252
|
} catch {}
|
|
@@ -243,13 +281,14 @@
|
|
|
243
281
|
return true;
|
|
244
282
|
}
|
|
245
283
|
|
|
246
|
-
function clearState(invoker) {
|
|
284
|
+
function clearState(invoker, force = false) {
|
|
247
285
|
const data = invoker[dataField];
|
|
248
286
|
clearTimeout(data.gainedTimer);
|
|
249
287
|
clearTimeout(data.lostTimer);
|
|
250
288
|
if (data.state !== InterestState.NoInterest) {
|
|
251
289
|
const target = GetInterestForTarget(invoker);
|
|
252
|
-
target.dispatchEvent(new
|
|
290
|
+
const shouldContinue = target.dispatchEvent(new InterestEvent(loseInterestEventName, { source: invoker }));
|
|
291
|
+
if (!force && !shouldContinue) return;
|
|
253
292
|
try {
|
|
254
293
|
target.hidePopover();
|
|
255
294
|
} catch {}
|
|
@@ -411,7 +450,7 @@
|
|
|
411
450
|
document.body.addEventListener("keydown", (e) => {
|
|
412
451
|
if (e.key === "Escape") {
|
|
413
452
|
invokersWithInterest.forEach((invoker) => {
|
|
414
|
-
clearState(invoker);
|
|
453
|
+
clearState(invoker, true);
|
|
415
454
|
});
|
|
416
455
|
}
|
|
417
456
|
});
|
package/src/interestfor.min.js
CHANGED
|
@@ -5,4 +5,4 @@
|
|
|
5
5
|
// LICENSE file in the root directory of this source tree.
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
!function(){const e="interest",t="loseinterest",n="--interest-delay-start",r="--interest-delay-end",o="--interest-delay",
|
|
8
|
+
!function(){const e="interest",t="loseinterest",n="--interest-delay-start",r="--interest-delay-end",o="--interest-delay",s="__interestForData",i="__interestForTargetData",a=new Set;let l=!1;if(window.interestForPolyfillInstalled)return;window.interestForPolyfillInstalled=!0;const c=HTMLButtonElement.prototype.hasOwnProperty("interestForElement");if(c&&!window.interestForUsePolyfillAlways)return;if(c){const n=e=>{e.isTrusted&&(e.preventDefault(),e.stopImmediatePropagation())};document.body.addEventListener(e,n,{capture:!0}),document.body.addEventListener(t,n,{capture:!0})}window.InterestEvent||(window.InterestEvent=class extends Event{#e;constructor(e,t={}){super(e,t);const{source:n}=t;if(null!=n&&!(n instanceof Element))throw new TypeError("source must be an element");this.#e=n}get[Symbol.toStringTag](){return"InterestEvent"}get source(){const e=this.#e;if(!e)return null;const t=p(e);return t!==p(this.target||document)?t.host:e}});const u="none",d="full",m="hover",f="dehover",h="focus",g="blur";function p(e){return e&&"function"==typeof e.getRootNode?e.getRootNode():e&&e.parentNode?p(e.parentNode):e}function y(t,n,r){if(!t||!n)return!1;if(!t.isConnected||T(t)!==n||r===u&&b(n)!==t)return!1;if(r!==u){const o=b(n);if(o){if(o===t)return o[s].clearLostTask(),!1;if(!y(o,n,u))return!1;if(!t.isConnected||T(t)!==n)return!1}return function(t,n){const r=t[s],o=T(t);if(n!==d)throw new Error("Invalid state");if(r.state!==u)throw new Error("Invalid state");if(!o.dispatchEvent(new InterestEvent(e,{source:t})))return;try{o.showPopover({source:t})}catch{}if(r.state=d,o[i]||(o[i]={}),o[i].invoker=t,o.hasAttribute("popover")&&(o[i].toggleListener=L,o.addEventListener("toggle",L)),a.add(t),t.classList.add("interest-source"),o.classList.add("interest-target"),P(o)||t.setAttribute("aria-expanded","true"),"none"===getComputedStyle(t).anchorName&&"auto"===getComputedStyle(o).positionAnchor){const e=`--interest-anchor-${Math.random().toString(36).substring(2)}`;t.style.anchorName=e,o.style.positionAnchor=e,r.anchorName=e}return!0}(t,r)}return k(t),!0}function v(e){const t=1e3*w(e,r);!isFinite(t)||t<0||(e[s].clearLostTask(),e[s].lostTimer=setTimeout(()=>{y(e,T(e),u)},t))}function b(e){const t=e[i]?.invoker||null;return t&&t[s]?.state!==u?t:null}function T(e){const t=e.getAttribute("interestfor");return document.getElementById(t)}function L(e){const t=e.target;if("closed"===e.newState){const e=t[i]?.invoker;e&&y(e,t,u)}}function E(e){const t=String(e).trim(),n=t.match(/^([\d.]+)s$/);if(n)return parseFloat(n[1]);const r=t.match(/^([\d.]+)ms$/);return r?parseFloat(r[1])/1e3:parseFloat(t)||0}function w(e,t){const r=getComputedStyle(e),s=r.getPropertyValue(t).trim();if("normal"!==s.toLowerCase())return E(s);const i=r.getPropertyValue(o).trim();if(i&&"normal"!==i.toLowerCase()){const e=i.split(/\s+/).filter(e=>e.length>0);if(e.length>0){const r=e[0],o=e.length>1?e[1]:r;let s;if(s=t===n?r:o,"normal"!==s.toLowerCase())return E(s)}}return t===n?.5:.25}function k(e,n=!1){const r=e[s];if(clearTimeout(r.gainedTimer),clearTimeout(r.lostTimer),r.state!==u){const o=T(e),s=o.dispatchEvent(new InterestEvent(t,{source:e}));if(!n&&!s)return;try{o.hidePopover()}catch{}o[i]?.toggleListener&&o.removeEventListener("toggle",o[i].toggleListener),o[i]=null,a.delete(e),e.classList.remove("interest-source"),o.classList.remove("interest-target"),P(o)||e.setAttribute("aria-expanded","false"),r.anchorName&&(e.style.anchorName="",o.style.positionAnchor="",r.anchorName=null),r.state=u}}const A=["a[href]","area[href]","input:not([disabled])","select:not([disabled])","textarea:not([disabled])","button:not([disabled])","iframe","object","embed","[contenteditable]",'[tabindex]:not([tabindex="-1"])'].join(",");function P(e){if("hint"!==e.getAttribute("popover")?.toLowerCase())return!1;if(e.querySelector(A))return!1;if(e.querySelector("h1,h2,h3,h4,h5,h6,ul,ol,li,table,nav,header,footer,main,aside,article,section,form,blockquote,details,summary,dialog"))return!1;const t=e.querySelectorAll("[role]");for(const e of t){const t=e.getAttribute("role").toLowerCase();if(!["presentation","none","generic","image"].includes(t))return!1}return!0}function S(e){if(e[s])return;e[s]={state:u,gainedTimer:null,lostTimer:null,longPressTimer:null,clearGainedTask(){clearTimeout(this.gainedTimer)},clearLostTask(){clearTimeout(this.lostTimer)}};const t=T(e);t&&function(e,t){P(t)?e.setAttribute("aria-describedby",t.id):(e.setAttribute("aria-details",t.id),e.setAttribute("aria-expanded","false"),t.hasAttribute("role")||t.setAttribute("role","tooltip"))}(e,t)}function C(e,t){if(l)return;if(!e.isConnected)return;if(!T(e)){const n=e.closest(".interest-target");if(n){const r=b(n);r&&(t===m||t===h?r[s].clearLostTask():t!==g&&e.matches(":hover")||v(r))}return}S(e);const r=e[s],o=b(e);t===m||t===h?(r.clearLostTask&&r.clearLostTask(),o&&o[s].clearLostTask(),function(e,t){const r=1e3*w(e,n);!isFinite(r)||r<0||(e[s].clearGainedTask(),e[s].gainedTimer=setTimeout(()=>{y(e,T(e),t)},r))}(e,d)):(r.clearGainedTask&&r.clearGainedTask(),r.state!==u&&v(e),o&&(o[s].clearGainedTask(),t!==g&&e.matches(":hover")||v(o)))}function x(){!function(){const e=document.createElement("style");e.textContent=`@property ${n} {syntax: "normal | <time>"; inherits: false; initial-value: normal;}\n @property ${r} {syntax: "normal | <time>"; inherits: false; initial-value: normal;}\n @property ${o} {syntax: "[ normal | <time> ]{1,2}"; inherits: false; initial-value: normal;}`,document.head.appendChild(e),document[s]={globalPropsStyle:e}}(),function(){const e=(e,t)=>{for(let n=e.target;n;n=n.parentElement)C(n,t)};document.body.addEventListener("mouseover",t=>e(t,m)),document.body.addEventListener("mouseout",t=>e(t,f)),document.body.addEventListener("focusin",t=>e(t,h)),document.body.addEventListener("focusout",t=>e(t,g)),document.body.addEventListener("keydown",e=>{"Escape"===e.key&&a.forEach(e=>{k(e,!0)})}),document.body.addEventListener("touchstart",e=>{l=!0;const t=e.target.closest("button[interestfor]");t&&(S(t),t[s].longPressTimer=setTimeout(()=>{y(t,T(t),d),t[s].longPressTimer=null},500))});const t=e=>{const t=e.target.closest("button[interestfor]");t&&t[s]?.longPressTimer&&(clearTimeout(t[s].longPressTimer),t[s].longPressTimer=null)};document.body.addEventListener("touchend",e=>{t(e),l=!1}),document.body.addEventListener("touchmove",t)}(),console.log(`interestfor polyfill installed (native: ${c}).`)}"complete"===document.readyState?x():window.addEventListener("load",x)}();
|