From 5aa7ceafc00bce029bc85f3eb274739099db1118 Mon Sep 17 00:00:00 2001 From: Steven Lin Date: Tue, 7 Jan 2025 23:13:51 +0800 Subject: [PATCH 1/2] Add IntersectionObserverAPI --- src/IntersectionObserverAPI.js | 2 + src/IntersectionObserverAPI.res | 66 +++++++++++++++++++ .../IntersectionObserver.js | 2 + .../IntersectionObserver.res | 35 ++++++++++ .../IntersectionObserver__test.js | 45 +++++++++++++ .../IntersectionObserver__test.res | 24 +++++++ 6 files changed, 174 insertions(+) create mode 100644 src/IntersectionObserverAPI.js create mode 100644 src/IntersectionObserverAPI.res create mode 100644 src/IntersectionObserverAPI/IntersectionObserver.js create mode 100644 src/IntersectionObserverAPI/IntersectionObserver.res create mode 100644 tests/IntersectionObserverAPI/IntersectionObserver__test.js create mode 100644 tests/IntersectionObserverAPI/IntersectionObserver__test.res diff --git a/src/IntersectionObserverAPI.js b/src/IntersectionObserverAPI.js new file mode 100644 index 0000000..d856702 --- /dev/null +++ b/src/IntersectionObserverAPI.js @@ -0,0 +1,2 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/src/IntersectionObserverAPI.res b/src/IntersectionObserverAPI.res new file mode 100644 index 0000000..b40d01d --- /dev/null +++ b/src/IntersectionObserverAPI.res @@ -0,0 +1,66 @@ +@@warning("-30") + +open DOMAPI + +/** +provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document's viewport. +[See IntersectionObserver on MDN](https://developer.mozilla.org/docs/Web/API/IntersectionObserver) +*/ +@editor.completeFrom(IntersectionObserver) +type intersectionObserver = { + /** + [Read more on MDN](https://developer.mozilla.org/docs/Web/API/IntersectionObserver/root) + */ + root: Null.t, + /** + [Read more on MDN](https://developer.mozilla.org/docs/Web/API/IntersectionObserver/rootMargin) + */ + rootMargin: string, + /** + [Read more on MDN](https://developer.mozilla.org/docs/Web/API/IntersectionObserver/thresholds) + */ + thresholds: array, +} + +/** +This Intersection Observer API interface describes the intersection between the target element and its root container at a specific moment of transition. +[See IntersectionObserverEntry on MDN](https://developer.mozilla.org/docs/Web/API/IntersectionObserverEntry) +*/ +type intersectionObserverEntry = { + /** + [Read more on MDN](https://developer.mozilla.org/docs/Web/API/IntersectionObserverEntry/time) + */ + time: float, + /** + [Read more on MDN](https://developer.mozilla.org/docs/Web/API/IntersectionObserverEntry/rootBounds) + */ + rootBounds: Null.t, + /** + [Read more on MDN](https://developer.mozilla.org/docs/Web/API/IntersectionObserverEntry/boundingClientRect) + */ + boundingClientRect: domRectReadOnly, + /** + [Read more on MDN](https://developer.mozilla.org/docs/Web/API/IntersectionObserverEntry/intersectionRect) + */ + intersectionRect: domRectReadOnly, + /** + [Read more on MDN](https://developer.mozilla.org/docs/Web/API/IntersectionObserverEntry/isIntersecting) + */ + isIntersecting: bool, + /** + [Read more on MDN](https://developer.mozilla.org/docs/Web/API/IntersectionObserverEntry/intersectionRatio) + */ + intersectionRatio: float, + /** + [Read more on MDN](https://developer.mozilla.org/docs/Web/API/IntersectionObserverEntry/target) + */ + target: element, +} + +type intersectionObserverInit = { + mutable root?: Null.t, + mutable rootMargin?: string, + mutable threshold?: array, +} + +type intersectionObserverCallback = (array, intersectionObserver) => unit diff --git a/src/IntersectionObserverAPI/IntersectionObserver.js b/src/IntersectionObserverAPI/IntersectionObserver.js new file mode 100644 index 0000000..d856702 --- /dev/null +++ b/src/IntersectionObserverAPI/IntersectionObserver.js @@ -0,0 +1,2 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/src/IntersectionObserverAPI/IntersectionObserver.res b/src/IntersectionObserverAPI/IntersectionObserver.res new file mode 100644 index 0000000..3ed85ed --- /dev/null +++ b/src/IntersectionObserverAPI/IntersectionObserver.res @@ -0,0 +1,35 @@ +open DOMAPI +open IntersectionObserverAPI + +/** +[Read more on MDN](https://developer.mozilla.org/docs/Web/API/IntersectionObserver) +*/ +@new +external make: ( + ~callback: intersectionObserverCallback, + ~options: intersectionObserverInit=?, +) => intersectionObserver = "IntersectionObserver" + +/** +[Read more on MDN](https://developer.mozilla.org/docs/Web/API/IntersectionObserver/observe) +*/ +@send +external observe: (intersectionObserver, element) => unit = "observe" + +/** +[Read more on MDN](https://developer.mozilla.org/docs/Web/API/IntersectionObserver/unobserve) +*/ +@send +external unobserve: (intersectionObserver, element) => unit = "unobserve" + +/** +[Read more on MDN](https://developer.mozilla.org/docs/Web/API/IntersectionObserver/disconnect) +*/ +@send +external disconnect: intersectionObserver => unit = "disconnect" + +/** +[Read more on MDN](https://developer.mozilla.org/docs/Web/API/IntersectionObserver/takeRecords) +*/ +@send +external takeRecords: intersectionObserver => array = "takeRecords" diff --git a/tests/IntersectionObserverAPI/IntersectionObserver__test.js b/tests/IntersectionObserverAPI/IntersectionObserver__test.js new file mode 100644 index 0000000..d1867d5 --- /dev/null +++ b/tests/IntersectionObserverAPI/IntersectionObserver__test.js @@ -0,0 +1,45 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE + +import * as Primitive_option from "rescript/lib/es6/Primitive_option.js"; + +let observer = new IntersectionObserver((entry, observer) => { + console.log(entry, observer); +}); + +let observer2 = new IntersectionObserver((entry, observer) => { + console.log(entry, observer); +}, { + rootMargin: "10px", + threshold: [0.1] +}); + +let root2 = observer2.root; + +let rootMargin2 = observer2.rootMargin; + +let targetElement = document.querySelector("#targetElement"); + +if (targetElement !== null) { + observer2.observe(targetElement); + observer2.unobserve(targetElement); +} else { + console.log("Target element not found."); +} + +let entries2 = observer2.takeRecords(); + +console.log(entries2.length); + +observer2.disconnect(); + +let targetElement$1 = targetElement === null ? undefined : Primitive_option.some(targetElement); + +export { + observer, + observer2, + root2, + rootMargin2, + targetElement$1 as targetElement, + entries2, +} +/* observer Not a pure module */ diff --git a/tests/IntersectionObserverAPI/IntersectionObserver__test.res b/tests/IntersectionObserverAPI/IntersectionObserver__test.res new file mode 100644 index 0000000..c042bc9 --- /dev/null +++ b/tests/IntersectionObserverAPI/IntersectionObserver__test.res @@ -0,0 +1,24 @@ +let observer = IntersectionObserver.make(~callback=(entry, observer) => { + Console.log2(entry, observer) +}) + +let observer2 = IntersectionObserver.make(~callback=(entry, observer) => { + Console.log2(entry, observer) +}, ~options={rootMargin: "10px", threshold: [0.1]}) + +let root2 = observer2.root +let rootMargin2 = observer2.rootMargin + +let targetElement = Global.document->Document.querySelector("#targetElement")->Null.toOption +switch targetElement { +| Some(e) => { + observer2->IntersectionObserver.observe(e) + observer2->IntersectionObserver.unobserve(e) + } +| _ => Console.log("Target element not found.") +} + +let entries2 = observer2->IntersectionObserver.takeRecords +Console.log(entries2->Array.length) + +observer2->IntersectionObserver.disconnect From 57769c32b953ba112799b61918b06915d7c6efbe Mon Sep 17 00:00:00 2001 From: Steven Lin Date: Wed, 8 Jan 2025 03:01:35 +0800 Subject: [PATCH 2/2] Use variant for IntersectionObserver root --- src/DOMAPI/Document.js | 7 ++++++ src/DOMAPI/Document.res | 2 ++ src/DOMAPI/Element.js | 5 ++++ src/DOMAPI/Element.res | 2 ++ src/IntersectionObserverAPI.res | 7 ++++-- .../IntersectionObserverRoot.js | 25 +++++++++++++++++++ .../IntersectionObserverRoot.res | 22 ++++++++++++++++ .../IntersectionObserver__test.js | 16 ++++++++++-- .../IntersectionObserver__test.res | 14 +++++++++-- 9 files changed, 94 insertions(+), 6 deletions(-) create mode 100644 src/IntersectionObserverAPI/IntersectionObserverRoot.js create mode 100644 src/IntersectionObserverAPI/IntersectionObserverRoot.res diff --git a/src/DOMAPI/Document.js b/src/DOMAPI/Document.js index e6a3a30..eee8545 100644 --- a/src/DOMAPI/Document.js +++ b/src/DOMAPI/Document.js @@ -4,4 +4,11 @@ import * as Node$WebAPI from "./Node.js"; Node$WebAPI.Impl({}); +function isInstanceOf(param) { + return (param instanceof Document); +} + +export { + isInstanceOf, +} /* Not a pure module */ diff --git a/src/DOMAPI/Document.res b/src/DOMAPI/Document.res index 946d76f..60cef5b 100644 --- a/src/DOMAPI/Document.res +++ b/src/DOMAPI/Document.res @@ -458,3 +458,5 @@ external hasStorageAccess: document => promise = "hasStorageAccess" */ @send external requestStorageAccess: document => promise = "requestStorageAccess" + +let isInstanceOf = (_: 't): bool => %raw(`param instanceof Document`) diff --git a/src/DOMAPI/Element.js b/src/DOMAPI/Element.js index d7d93d7..78c6978 100644 --- a/src/DOMAPI/Element.js +++ b/src/DOMAPI/Element.js @@ -9,7 +9,12 @@ function Impl(T) { Node$WebAPI.Impl({}); +function isInstanceOf(param) { + return (param instanceof Element); +} + export { Impl, + isInstanceOf, } /* Not a pure module */ diff --git a/src/DOMAPI/Element.res b/src/DOMAPI/Element.res index 5fd2444..73860c9 100644 --- a/src/DOMAPI/Element.res +++ b/src/DOMAPI/Element.res @@ -498,3 +498,5 @@ Returns true if qualifiedName is now present, and false otherwise. include Impl({ type t = element }) + +let isInstanceOf = (_: 't): bool => %raw(`param instanceof Element`) diff --git a/src/IntersectionObserverAPI.res b/src/IntersectionObserverAPI.res index b40d01d..933c425 100644 --- a/src/IntersectionObserverAPI.res +++ b/src/IntersectionObserverAPI.res @@ -2,6 +2,9 @@ open DOMAPI +@editor.completeFrom(IntersectionObserverRoot) +type root + /** provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document's viewport. [See IntersectionObserver on MDN](https://developer.mozilla.org/docs/Web/API/IntersectionObserver) @@ -11,7 +14,7 @@ type intersectionObserver = { /** [Read more on MDN](https://developer.mozilla.org/docs/Web/API/IntersectionObserver/root) */ - root: Null.t, + root: root, /** [Read more on MDN](https://developer.mozilla.org/docs/Web/API/IntersectionObserver/rootMargin) */ @@ -58,7 +61,7 @@ type intersectionObserverEntry = { } type intersectionObserverInit = { - mutable root?: Null.t, + mutable root?: root, mutable rootMargin?: string, mutable threshold?: array, } diff --git a/src/IntersectionObserverAPI/IntersectionObserverRoot.js b/src/IntersectionObserverAPI/IntersectionObserverRoot.js new file mode 100644 index 0000000..5418042 --- /dev/null +++ b/src/IntersectionObserverAPI/IntersectionObserverRoot.js @@ -0,0 +1,25 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE + +import * as Element$WebAPI from "../DOMAPI/Element.js"; +import * as Document$WebAPI from "../DOMAPI/Document.js"; + +function decode(t) { + if (Element$WebAPI.isInstanceOf(t)) { + return { + TAG: "Element", + _0: t + }; + } else if (Document$WebAPI.isInstanceOf(t)) { + return { + TAG: "Document", + _0: t + }; + } else { + return "Null"; + } +} + +export { + decode, +} +/* Element-WebAPI Not a pure module */ diff --git a/src/IntersectionObserverAPI/IntersectionObserverRoot.res b/src/IntersectionObserverAPI/IntersectionObserverRoot.res new file mode 100644 index 0000000..7bb8c75 --- /dev/null +++ b/src/IntersectionObserverAPI/IntersectionObserverRoot.res @@ -0,0 +1,22 @@ +open DOMAPI +open IntersectionObserverAPI + +external fromDocument: document => root = "%identity" +external fromElement: element => root = "%identity" +external fromNull: root = "null" + +type decoded = + | Element(element) + | Document(document) + | Null + +let decode = (t: root): decoded => { + open Prelude + if Element.isInstanceOf(t) { + Element(t->unsafeConversation) + } else if Document.isInstanceOf(t) { + Document(t->unsafeConversation) + } else { + Null + } +} diff --git a/tests/IntersectionObserverAPI/IntersectionObserver__test.js b/tests/IntersectionObserverAPI/IntersectionObserver__test.js index d1867d5..113ecec 100644 --- a/tests/IntersectionObserverAPI/IntersectionObserver__test.js +++ b/tests/IntersectionObserverAPI/IntersectionObserver__test.js @@ -1,19 +1,31 @@ // Generated by ReScript, PLEASE EDIT WITH CARE import * as Primitive_option from "rescript/lib/es6/Primitive_option.js"; +import * as IntersectionObserverRoot$WebAPI from "../../src/IntersectionObserverAPI/IntersectionObserverRoot.js"; let observer = new IntersectionObserver((entry, observer) => { console.log(entry, observer); }); +let root = document.querySelector("#root"); + let observer2 = new IntersectionObserver((entry, observer) => { console.log(entry, observer); }, { + root: Primitive_option.some(root), rootMargin: "10px", threshold: [0.1] }); -let root2 = observer2.root; +let match = IntersectionObserverRoot$WebAPI.decode(observer2.root); + +if (typeof match !== "object") { + console.log("Null"); +} else if (match.TAG === "Element") { + console.log("Element"); +} else { + console.log("Document"); +} let rootMargin2 = observer2.rootMargin; @@ -36,8 +48,8 @@ let targetElement$1 = targetElement === null ? undefined : Primitive_option.some export { observer, + root, observer2, - root2, rootMargin2, targetElement$1 as targetElement, entries2, diff --git a/tests/IntersectionObserverAPI/IntersectionObserver__test.res b/tests/IntersectionObserverAPI/IntersectionObserver__test.res index c042bc9..eeba8c8 100644 --- a/tests/IntersectionObserverAPI/IntersectionObserver__test.res +++ b/tests/IntersectionObserverAPI/IntersectionObserver__test.res @@ -2,11 +2,21 @@ let observer = IntersectionObserver.make(~callback=(entry, observer) => { Console.log2(entry, observer) }) +let root = Global.document->Document.querySelector("#root")->Null.getUnsafe + let observer2 = IntersectionObserver.make(~callback=(entry, observer) => { Console.log2(entry, observer) -}, ~options={rootMargin: "10px", threshold: [0.1]}) +}, ~options={ + root: root->IntersectionObserverRoot.fromElement, + rootMargin: "10px", + threshold: [0.1], +}) -let root2 = observer2.root +switch observer2.root->IntersectionObserverRoot.decode { +| Element(_) => Console.log("Element") +| Document(_) => Console.log("Document") +| Null => Console.log("Null") +} let rootMargin2 = observer2.rootMargin let targetElement = Global.document->Document.querySelector("#targetElement")->Null.toOption