From 5f5b585c7328328494f13802a4600ed9d5f7c54a Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 18 Nov 2024 10:39:23 +0100 Subject: [PATCH 1/3] Proof of concept querySelector helpers --- README.md | 2 +- docs/content/docs/index.mdx | 4 +- src/DOMAPI/Document.js | 12 +++++- src/DOMAPI/Document.res | 9 ++-- src/DOMAPI/FillStyle.js | 8 ++-- src/DOMAPI/HTMLCanvasElement.js | 11 ++++- src/DOMAPI/HTMLCanvasElement.res | 1 + src/DOMAPI/QuerySelector.js | 22 ++++++++++ src/DOMAPI/QuerySelector.res | 36 ++++++++++++++++ tests/DOMAPI/HTMLCanvasElement__tes.js | 55 +++++++++++-------------- tests/DOMAPI/HTMLCanvasElement__tes.res | 31 +++++++------- 11 files changed, 132 insertions(+), 59 deletions(-) create mode 100644 src/DOMAPI/QuerySelector.js create mode 100644 src/DOMAPI/QuerySelector.res diff --git a/README.md b/README.md index 667fcf7..54c0e16 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Experimental successor to [rescript-webapi](https://github.com/TheSpyder/rescrip Install the package using your favorite package manager: ```shell -npm i -D @rescript/webapi@experimental +npm i @rescript/webapi@experimental ``` and add `@rescript/webapi` to your `rescript.json`: diff --git a/docs/content/docs/index.mdx b/docs/content/docs/index.mdx index 87c4d2c..15d4e4a 100644 --- a/docs/content/docs/index.mdx +++ b/docs/content/docs/index.mdx @@ -30,14 +30,14 @@ Install the package using your favorite package manager: diff --git a/src/DOMAPI/Document.js b/src/DOMAPI/Document.js index d856702..c6e4ad6 100644 --- a/src/DOMAPI/Document.js +++ b/src/DOMAPI/Document.js @@ -1,2 +1,12 @@ // Generated by ReScript, PLEASE EDIT WITH CARE -/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ + +import * as QuerySelector$WebAPI from "./QuerySelector.js"; + +let include = QuerySelector$WebAPI.Impl({}); + +let querySelector_htmlCanvasElement = include.querySelector_htmlCanvasElement; + +export { + querySelector_htmlCanvasElement, +} +/* include Not a pure module */ diff --git a/src/DOMAPI/Document.res b/src/DOMAPI/Document.res index 8501ac2..c54b183 100644 --- a/src/DOMAPI/Document.res +++ b/src/DOMAPI/Document.res @@ -77,12 +77,9 @@ Throws a "HierarchyRequestError" DOMException if the constraints of the node tre @send external replaceChildren2: (document, string) => unit = "replaceChildren" -/** -Returns the first element that is a descendant of node that matches selectors. -[Read more on MDN](https://developer.mozilla.org/docs/Web/API/Document/querySelector) -*/ -@send -external querySelector: (document, string) => element = "querySelector" +include QuerySelector.Impl({ + type t = document +}) /** Returns all element descendants of node that match selectors. diff --git a/src/DOMAPI/FillStyle.js b/src/DOMAPI/FillStyle.js index 1e79cc4..d12dfc1 100644 --- a/src/DOMAPI/FillStyle.js +++ b/src/DOMAPI/FillStyle.js @@ -1,15 +1,15 @@ // Generated by ReScript, PLEASE EDIT WITH CARE -import * as CanvasPattern$WebApi from "../CanvasAPI/CanvasPattern.js"; -import * as CanvasGradient$WebApi from "../CanvasAPI/CanvasGradient.js"; +import * as CanvasPattern$WebAPI from "../CanvasAPI/CanvasPattern.js"; +import * as CanvasGradient$WebAPI from "../CanvasAPI/CanvasGradient.js"; function decode(t) { - if (CanvasGradient$WebApi.isInstanceOf(t)) { + if (CanvasGradient$WebAPI.isInstanceOf(t)) { return { TAG: "CanvasGradient", _0: t }; - } else if (CanvasPattern$WebApi.isInstanceOf(t)) { + } else if (CanvasPattern$WebAPI.isInstanceOf(t)) { return { TAG: "CanvasPattern", _0: t diff --git a/src/DOMAPI/HTMLCanvasElement.js b/src/DOMAPI/HTMLCanvasElement.js index d856702..25f61a2 100644 --- a/src/DOMAPI/HTMLCanvasElement.js +++ b/src/DOMAPI/HTMLCanvasElement.js @@ -1,2 +1,11 @@ // Generated by ReScript, PLEASE EDIT WITH CARE -/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ + + +function isInstanceOf(param) { + return (param instanceof HTMLCanvasElement); +} + +export { + isInstanceOf, +} +/* No side effect */ diff --git a/src/DOMAPI/HTMLCanvasElement.res b/src/DOMAPI/HTMLCanvasElement.res index 6fcc4da..4ef7d6d 100644 --- a/src/DOMAPI/HTMLCanvasElement.res +++ b/src/DOMAPI/HTMLCanvasElement.res @@ -8,6 +8,7 @@ external asHTMLElement: htmlCanvasElement => htmlElement = "%identity" external asElement: htmlCanvasElement => element = "%identity" external asNode: htmlCanvasElement => node = "%identity" external asEventTarget: htmlCanvasElement => eventTarget = "%identity" +let isInstanceOf = (_: 't): bool => %raw(`param instanceof HTMLCanvasElement`) /** [Read more on MDN](https://developer.mozilla.org/docs/Web/API/HTMLElement/focus) */ diff --git a/src/DOMAPI/QuerySelector.js b/src/DOMAPI/QuerySelector.js new file mode 100644 index 0000000..70b1bd8 --- /dev/null +++ b/src/DOMAPI/QuerySelector.js @@ -0,0 +1,22 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE + +import * as HTMLCanvasElement$WebAPI from "./HTMLCanvasElement.js"; + +function Impl(T) { + let querySelector_htmlCanvasElement = (t, selector) => { + let e = t.querySelector(selector); + if (e === null || !HTMLCanvasElement$WebAPI.isInstanceOf(e)) { + return; + } else { + return e; + } + }; + return { + querySelector_htmlCanvasElement: querySelector_htmlCanvasElement + }; +} + +export { + Impl, +} +/* No side effect */ diff --git a/src/DOMAPI/QuerySelector.res b/src/DOMAPI/QuerySelector.res new file mode 100644 index 0000000..096ff96 --- /dev/null +++ b/src/DOMAPI/QuerySelector.res @@ -0,0 +1,36 @@ +open Prelude +open DOMAPI + +module Impl = ( + T: { + type t + }, +) => { + /** +`querySelector(T.t, string)` + +Returns the first element that is a descendant of node that matches selectors. +If nothing matches, the result is `null`. Use `querySelector_` helpers to get a typed result. + +```res +t->querySelector("#myCanvas") +``` + +[Read more on MDN](https://developer.mozilla.org/docs/Web/API/Document/querySelector) + */ + @send + external querySelector: (T.t, string) => null = "querySelector" + + let querySelector_htmlCanvasElement = (t: T.t, selector: string): option => { + let e = querySelector(t, selector) + switch e { + | Null.Null => None + | Null.Value(e) => + if HTMLCanvasElement.isInstanceOf(e) { + Some(unsafeConversation(e)) + } else { + None + } + } + } +} diff --git a/tests/DOMAPI/HTMLCanvasElement__tes.js b/tests/DOMAPI/HTMLCanvasElement__tes.js index c135597..29e9f6a 100644 --- a/tests/DOMAPI/HTMLCanvasElement__tes.js +++ b/tests/DOMAPI/HTMLCanvasElement__tes.js @@ -1,39 +1,34 @@ // Generated by ReScript, PLEASE EDIT WITH CARE +import * as Option from "rescript/lib/es6/Option.js"; +import * as Document$WebAPI from "../../src/DOMAPI/Document.js"; import * as FillStyle$WebAPI from "../../src/DOMAPI/FillStyle.js"; -let myCanvas = document.getElementById("myCanvas"); - -let ctx = myCanvas.getContext("2d"); - -ctx.fillStyle = "red"; - -ctx.fillRect(50, 50, 200, 200); - -ctx.fillStyle = "black"; - -ctx.font = "2px Tahoma"; - -ctx.textBaseline = "top"; - -ctx.fillText("MY TEXT", 60, 60); - -let color = FillStyle$WebAPI.decode(ctx.fillStyle); - -switch (color.TAG) { - case "String" : - console.log("Color: " + color._0); - break; - case "CanvasGradient" : - console.log("CanvasGradient"); - break; - case "CanvasPattern" : - console.log("CanvasPattern"); - break; -} +let myCanvas = Document$WebAPI.querySelector_htmlCanvasElement(document, "#myCanvas"); + +Option.forEach(myCanvas, myCanvas => { + let ctx = myCanvas.getContext("2d"); + ctx.fillStyle = "red"; + ctx.fillRect(50, 50, 200, 200); + ctx.fillStyle = "black"; + ctx.font = "2px Tahoma"; + ctx.textBaseline = "top"; + ctx.fillText("MY TEXT", 60, 60); + let color = FillStyle$WebAPI.decode(ctx.fillStyle); + switch (color.TAG) { + case "String" : + console.log("Color: " + color._0); + return; + case "CanvasGradient" : + console.log("CanvasGradient"); + return; + case "CanvasPattern" : + console.log("CanvasPattern"); + return; + } +}); export { myCanvas, - ctx, } /* myCanvas Not a pure module */ diff --git a/tests/DOMAPI/HTMLCanvasElement__tes.res b/tests/DOMAPI/HTMLCanvasElement__tes.res index 920340b..a99fa9c 100644 --- a/tests/DOMAPI/HTMLCanvasElement__tes.res +++ b/tests/DOMAPI/HTMLCanvasElement__tes.res @@ -1,19 +1,22 @@ open WebAPI.Global -let myCanvas: DOMAPI.htmlCanvasElement = - document->Document.getElementById("myCanvas")->Prelude.unsafeConversation -let ctx = myCanvas->HTMLCanvasElement.getContext_2D +let myCanvas: option = + document->Document.querySelector_htmlCanvasElement("#myCanvas") -ctx.fillStyle = FillStyle.fromString("red") -ctx->CanvasRenderingContext2D.fillRect(~x=50., ~y=50., ~w=200., ~h=200.) +myCanvas->Option.forEach(myCanvas => { + let ctx = myCanvas->HTMLCanvasElement.getContext_2D -ctx.fillStyle = FillStyle.fromString("black") -ctx.font = "2px Tahoma" -ctx.textBaseline = CanvasAPI.Top -ctx->CanvasRenderingContext2D.fillText(~text="MY TEXT", ~x=60., ~y=60.) + ctx.fillStyle = FillStyle.fromString("red") + ctx->CanvasRenderingContext2D.fillRect(~x=50., ~y=50., ~w=200., ~h=200.) -switch ctx.fillStyle->FillStyle.decode { -| FillStyle.String(color) => Console.log(`Color: ${color}`) -| FillStyle.CanvasGradient(_) => Console.log("CanvasGradient") -| FillStyle.CanvasPattern(_) => Console.log("CanvasPattern") -} + ctx.fillStyle = FillStyle.fromString("black") + ctx.font = "2px Tahoma" + ctx.textBaseline = CanvasAPI.Top + ctx->CanvasRenderingContext2D.fillText(~text="MY TEXT", ~x=60., ~y=60.) + + switch ctx.fillStyle->FillStyle.decode { + | FillStyle.String(color) => Console.log(`Color: ${color}`) + | FillStyle.CanvasGradient(_) => Console.log("CanvasGradient") + | FillStyle.CanvasPattern(_) => Console.log("CanvasPattern") + } +}) From 374f47c5407fb7ec5c4d1860151f1d0a90c717bd Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 18 Nov 2024 11:56:17 +0100 Subject: [PATCH 2/3] Add example about querySelector usage in inherited interfaces. --- src/DOMAPI/Document.js | 6 ++++++ src/DOMAPI/HTMLCanvasElement.js | 11 +---------- src/DOMAPI/HTMLCanvasElement.res | 2 +- src/DOMAPI/HTMLDivElement.js | 18 +++++++++++++++++- src/DOMAPI/HTMLDivElement.res | 9 +++------ src/DOMAPI/QuerySelector.js | 24 +++++++++++++++++++----- src/DOMAPI/QuerySelector.res | 20 +++++++++++++------- tests/DOMAPI/HTMLCanvasElement__tes.js | 8 ++++++-- tests/DOMAPI/HTMLCanvasElement__tes.res | 4 +++- 9 files changed, 69 insertions(+), 33 deletions(-) diff --git a/src/DOMAPI/Document.js b/src/DOMAPI/Document.js index c6e4ad6..e8c547a 100644 --- a/src/DOMAPI/Document.js +++ b/src/DOMAPI/Document.js @@ -4,9 +4,15 @@ import * as QuerySelector$WebAPI from "./QuerySelector.js"; let include = QuerySelector$WebAPI.Impl({}); +let safeQuerySelector = include.safeQuerySelector; + let querySelector_htmlCanvasElement = include.querySelector_htmlCanvasElement; +let querySelector_htmlDivElement = include.querySelector_htmlDivElement; + export { + safeQuerySelector, querySelector_htmlCanvasElement, + querySelector_htmlDivElement, } /* include Not a pure module */ diff --git a/src/DOMAPI/HTMLCanvasElement.js b/src/DOMAPI/HTMLCanvasElement.js index 25f61a2..d856702 100644 --- a/src/DOMAPI/HTMLCanvasElement.js +++ b/src/DOMAPI/HTMLCanvasElement.js @@ -1,11 +1,2 @@ // Generated by ReScript, PLEASE EDIT WITH CARE - - -function isInstanceOf(param) { - return (param instanceof HTMLCanvasElement); -} - -export { - isInstanceOf, -} -/* No side effect */ +/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ diff --git a/src/DOMAPI/HTMLCanvasElement.res b/src/DOMAPI/HTMLCanvasElement.res index 4ef7d6d..4d089cc 100644 --- a/src/DOMAPI/HTMLCanvasElement.res +++ b/src/DOMAPI/HTMLCanvasElement.res @@ -8,7 +8,7 @@ external asHTMLElement: htmlCanvasElement => htmlElement = "%identity" external asElement: htmlCanvasElement => element = "%identity" external asNode: htmlCanvasElement => node = "%identity" external asEventTarget: htmlCanvasElement => eventTarget = "%identity" -let isInstanceOf = (_: 't): bool => %raw(`param instanceof HTMLCanvasElement`) + /** [Read more on MDN](https://developer.mozilla.org/docs/Web/API/HTMLElement/focus) */ diff --git a/src/DOMAPI/HTMLDivElement.js b/src/DOMAPI/HTMLDivElement.js index d856702..e8c547a 100644 --- a/src/DOMAPI/HTMLDivElement.js +++ b/src/DOMAPI/HTMLDivElement.js @@ -1,2 +1,18 @@ // Generated by ReScript, PLEASE EDIT WITH CARE -/* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */ + +import * as QuerySelector$WebAPI from "./QuerySelector.js"; + +let include = QuerySelector$WebAPI.Impl({}); + +let safeQuerySelector = include.safeQuerySelector; + +let querySelector_htmlCanvasElement = include.querySelector_htmlCanvasElement; + +let querySelector_htmlDivElement = include.querySelector_htmlDivElement; + +export { + safeQuerySelector, + querySelector_htmlCanvasElement, + querySelector_htmlDivElement, +} +/* include Not a pure module */ diff --git a/src/DOMAPI/HTMLDivElement.res b/src/DOMAPI/HTMLDivElement.res index cfc7b51..a4732a0 100644 --- a/src/DOMAPI/HTMLDivElement.res +++ b/src/DOMAPI/HTMLDivElement.res @@ -72,12 +72,9 @@ Throws a "HierarchyRequestError" DOMException if the constraints of the node tre @send external replaceChildren2: (htmlDivElement, string) => unit = "replaceChildren" -/** -Returns the first element that is a descendant of node that matches selectors. -[Read more on MDN](https://developer.mozilla.org/docs/Web/API/Document/querySelector) -*/ -@send -external querySelector: (htmlDivElement, string) => element = "querySelector" +include QuerySelector.Impl({ + type t = htmlDivElement +}) /** Returns all element descendants of node that match selectors. diff --git a/src/DOMAPI/QuerySelector.js b/src/DOMAPI/QuerySelector.js index 70b1bd8..7e84cac 100644 --- a/src/DOMAPI/QuerySelector.js +++ b/src/DOMAPI/QuerySelector.js @@ -1,22 +1,36 @@ // Generated by ReScript, PLEASE EDIT WITH CARE -import * as HTMLCanvasElement$WebAPI from "./HTMLCanvasElement.js"; +import * as Primitive_option from "rescript/lib/es6/Primitive_option.js"; + +function isInstanceOfHTMLCanvasElement(param) { + return (param instanceof HTMLCanvasElement); +} + +function isInstanceOfHTMLDivElement(param) { + return (param instanceof HTMLDivElement); +} function Impl(T) { - let querySelector_htmlCanvasElement = (t, selector) => { + let safeQuerySelector = (predicate, t, selector) => { let e = t.querySelector(selector); - if (e === null || !HTMLCanvasElement$WebAPI.isInstanceOf(e)) { + if (e === null || !predicate(t)) { return; } else { - return e; + return Primitive_option.some(e); } }; + let querySelector_htmlCanvasElement = (t, selector) => safeQuerySelector(isInstanceOfHTMLCanvasElement, t, selector); + let querySelector_htmlDivElement = (t, selector) => safeQuerySelector(isInstanceOfHTMLDivElement, t, selector); return { - querySelector_htmlCanvasElement: querySelector_htmlCanvasElement + safeQuerySelector: safeQuerySelector, + querySelector_htmlCanvasElement: querySelector_htmlCanvasElement, + querySelector_htmlDivElement: querySelector_htmlDivElement }; } export { + isInstanceOfHTMLCanvasElement, + isInstanceOfHTMLDivElement, Impl, } /* No side effect */ diff --git a/src/DOMAPI/QuerySelector.res b/src/DOMAPI/QuerySelector.res index 096ff96..32b29da 100644 --- a/src/DOMAPI/QuerySelector.res +++ b/src/DOMAPI/QuerySelector.res @@ -1,6 +1,9 @@ open Prelude open DOMAPI +let isInstanceOfHTMLCanvasElement = (_: 't): bool => %raw(`param instanceof HTMLCanvasElement`) +let isInstanceOfHTMLDivElement = (_: 't): bool => %raw(`param instanceof HTMLDivElement`) + module Impl = ( T: { type t @@ -21,16 +24,19 @@ t->querySelector("#myCanvas") @send external querySelector: (T.t, string) => null = "querySelector" - let querySelector_htmlCanvasElement = (t: T.t, selector: string): option => { + let safeQuerySelector = (predicate: T.t => bool, t: T.t, selector: string): option<'return> => { let e = querySelector(t, selector) switch e { | Null.Null => None - | Null.Value(e) => - if HTMLCanvasElement.isInstanceOf(e) { - Some(unsafeConversation(e)) - } else { - None - } + | Null.Value(e) => predicate(t) ? Some(unsafeConversation(e)) : None } } + + let querySelector_htmlCanvasElement = (t: T.t, selector: string): option => { + safeQuerySelector(isInstanceOfHTMLCanvasElement, t, selector) + } + + let querySelector_htmlDivElement = (t: T.t, selector: string): option => { + safeQuerySelector(isInstanceOfHTMLDivElement, t, selector) + } } diff --git a/tests/DOMAPI/HTMLCanvasElement__tes.js b/tests/DOMAPI/HTMLCanvasElement__tes.js index 29e9f6a..f1e62e4 100644 --- a/tests/DOMAPI/HTMLCanvasElement__tes.js +++ b/tests/DOMAPI/HTMLCanvasElement__tes.js @@ -3,8 +3,11 @@ import * as Option from "rescript/lib/es6/Option.js"; import * as Document$WebAPI from "../../src/DOMAPI/Document.js"; import * as FillStyle$WebAPI from "../../src/DOMAPI/FillStyle.js"; +import * as HTMLDivElement$WebAPI from "../../src/DOMAPI/HTMLDivElement.js"; -let myCanvas = Document$WebAPI.querySelector_htmlCanvasElement(document, "#myCanvas"); +let myDiv = Document$WebAPI.querySelector_htmlDivElement(document, "#myDiv"); + +let myCanvas = Option.flatMap(myDiv, div => HTMLDivElement$WebAPI.querySelector_htmlCanvasElement(div, "#myCanvas")); Option.forEach(myCanvas, myCanvas => { let ctx = myCanvas.getContext("2d"); @@ -29,6 +32,7 @@ Option.forEach(myCanvas, myCanvas => { }); export { + myDiv, myCanvas, } -/* myCanvas Not a pure module */ +/* myDiv Not a pure module */ diff --git a/tests/DOMAPI/HTMLCanvasElement__tes.res b/tests/DOMAPI/HTMLCanvasElement__tes.res index a99fa9c..d427b3a 100644 --- a/tests/DOMAPI/HTMLCanvasElement__tes.res +++ b/tests/DOMAPI/HTMLCanvasElement__tes.res @@ -1,7 +1,9 @@ open WebAPI.Global +let myDiv = document->Document.querySelector_htmlDivElement("#myDiv") + let myCanvas: option = - document->Document.querySelector_htmlCanvasElement("#myCanvas") + myDiv->Option.flatMap(div => div->HTMLDivElement.querySelector_htmlCanvasElement("#myCanvas")) myCanvas->Option.forEach(myCanvas => { let ctx = myCanvas->HTMLCanvasElement.getContext_2D From 54c0cc8ddfa25e5f9fd9fce7a805f1814776a854 Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 18 Nov 2024 16:07:36 +0100 Subject: [PATCH 3/3] Add all querySelector helpers --- src/DOMAPI.res | 29 +++ src/DOMAPI/Document.js | 186 +++++++++++++++ src/DOMAPI/HTMLDivElement.js | 186 +++++++++++++++ src/DOMAPI/QuerySelector.js | 436 ++++++++++++++++++++++++++++++++++- src/DOMAPI/QuerySelector.res | 277 +++++++++++++++++++++- 5 files changed, 1112 insertions(+), 2 deletions(-) diff --git a/src/DOMAPI.res b/src/DOMAPI.res index df04130..3261920 100644 --- a/src/DOMAPI.res +++ b/src/DOMAPI.res @@ -7442,6 +7442,19 @@ and htmlTableRowElement = { cells: htmlCollectionOf, } +/** +Provides special properties (beyond the HTMLElement interface it also has available to it inheritance) for manipulating single or grouped table column elements. +[See HTMLTableColElement on MDN](https://developer.mozilla.org/docs/Web/API/HTMLTableColElement) +*/ +type htmlTableColElement = { + ...htmlElement, + /** + Sets or retrieves the number of columns in the group. + [Read more on MDN](https://developer.mozilla.org/docs/Web/API/HTMLTableColElement/span) + */ + mutable span: int, +} + /** Provides properties and methods (beyond the regular HTMLElement interface it also has available to it by inheritance) for manipulating