Skip to content

Commit 8908028

Browse files
committed
docs: document option 2 DOM API shape
1 parent ca0ae31 commit 8908028

5 files changed

Lines changed: 39 additions & 39 deletions

File tree

docs/content/docs/api-surface.mdx

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,9 @@ Global singleton APIs such as `Location`, `Crypto`, and `Performance` expose dir
3737
functions and properties. Object-owned APIs still use the value as the receiver.
3838

3939
```ReScript
40+
let href = WebAPI.Location.href
4041
let location = WebAPI.Location.current
41-
let href = location.href
42+
let sameHref = location.href
4243
4344
WebAPI.Location.reload()
4445
```
@@ -51,8 +52,7 @@ helper modules.
5152
```ReScript
5253
let req: WebAPI.Request.t = WebAPI.Request.fromURL("https://example.com")
5354
let headers = WebAPI.Headers.make()
54-
let document = WebAPI.Window.current->WebAPI.Window.document
55-
let element = document->WebAPI.Document.createElement("button")
55+
let element: WebAPI.Element.t = WebAPI.Document.createElement("button")
5656
```
5757

5858
With `"-open WebAPI"`, the same modules can be referenced without the `WebAPI.` prefix:
@@ -266,30 +266,24 @@ let redirect = WebAPI.Response.redirect(~url="/login", ~status=302)
266266

267267
## DOM
268268

269-
DOM values are operated on through public interface modules.
270-
`WebAPI.Element` is the method module for element values. When you need to name the element type explicitly, use `WebAPI.DOM.element`; most examples can rely on inference from `Document.createElement`, `Document.querySelector`, and related DOM helpers.
269+
Common document entry points are exposed directly on `WebAPI.Document`, bound to
270+
`globalThis.document`. DOM object properties use dot syntax, and instance methods stay
271+
receiver-based through the owner module. When you need to name an element type explicitly,
272+
use `WebAPI.Element.t`.
271273

272274
```ReScript
273-
let document = WebAPI.Window.current->WebAPI.Window.document
274-
275-
let maybeButton = document
276-
->WebAPI.Document.querySelector("button")
277-
->Null.toOption
278-
279-
switch maybeButton {
280-
| Some(button) =>
281-
switch button->WebAPI.Element.getAttribute("data-user-id") {
282-
| Null.Value(id) => Console.log(id)
283-
| Null => Console.log("anonymous")
284-
}
285-
| None => Console.log("button not found")
286-
}
275+
let button: WebAPI.Element.t = WebAPI.Document.createElement("button")
276+
button.id = "save"
277+
button.className = "primary"
278+
button.innerHTML = "Save"
279+
button->WebAPI.Element.setAttribute(~qualifiedName="data-state", ~value="ready")
280+
let maybeButton = WebAPI.Document.querySelector("#save")->Null.toOption
287281
```
288282

289283
Use conversion helpers when moving between related DOM interface types.
290284

291285
```ReScript
292-
let element: WebAPI.DOM.element = document->WebAPI.Document.createElement("div")
286+
let element: WebAPI.Element.t = WebAPI.Document.createElement("div")
293287
let node = element->WebAPI.Element.asNode
294288
```
295289

docs/content/docs/contributing/api-module-structure.mdx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,14 @@ type rec node = {
6464
and element = Base__Element.t
6565
```
6666

67-
For shared DOM base interfaces such as `Element`, keep the root type as a thin opaque owner such as `Base__Element.t`. The DOM API module can expose `DOM.element` as a public alias while method modules use `DomTypes.element`.
67+
Public interface modules own their public `t` type. For example, `Element.res` exposes
68+
`Element.t`, `Document.res` exposes `Document.t`, and `Location.res` exposes `Location.t`.
69+
These public `t` types are the names consumers should use in annotations.
70+
71+
When an interface needs a shared structural owner across APIs or inheritance chains, keep
72+
that shared shape in a base module such as `Base__Element.t`. The public interface module
73+
then aliases the base shape as its own `t`, while generated structural modules can keep
74+
using internal aliases such as `DomTypes.element` where needed.
6875

6976
## Auxiliary Types
7077

docs/content/docs/contributing/module-type-structure.mdx

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -76,22 +76,26 @@ external checkValidity: htmlButtonElement => bool = "checkValidity"
7676

7777
<Code code={buttonModule} title="DOMAPI/HTMLButtonElement.res" lang="ReScript"></Code>
7878

79-
## Shared element base
79+
## Shared Object Bases
8080

81-
`Element.res` is a method module. It does not define the `element` type directly. The shared DOM element type is a thin opaque base handle threaded back into DOM through aliases:
81+
Public interface modules expose their own `t` type even when the underlying shape is shared.
82+
For a shared DOM object base, keep the structural owner in a base module and make the public
83+
interface module a same-type alias of that base:
8284

8385
```ReScript
8486
// Base__Element.res
8587
type t = private {}
8688
87-
// DomTypes.res
88-
type element = Base__Element.t = private {...Base__Element.t}
89-
9089
// Element.res
91-
include Impl({type t = DomTypes.element})
90+
type t = Base__Element.t = {...Base__Element.t}
91+
92+
// DomTypes.res
93+
type element = Base__Element.t = {...Base__Element.t}
9294
```
9395

94-
This keeps `Element.Impl` reusable for element subtypes while giving the package one shared base element handle. Subtype modules should continue to include the nearest base method implementation:
96+
This keeps `Element.t` as the public type name while still allowing generated DOM structural
97+
types to share the same object identity. `Element.Impl` remains reusable for element subtypes,
98+
and subtype modules should continue to include the nearest base method implementation:
9599

96100
```ReScript
97101
// HTMLElement.res
@@ -101,4 +105,4 @@ include Element.Impl({type t = DomTypes.htmlElement})
101105
include HTMLElement.Impl({type t = DomTypes.htmlButtonElement})
102106
```
103107

104-
Use `asElement` when a subtype needs to be passed to a function that expects the shared element type.
108+
Use `asElement` when a subtype needs to be passed to a function that expects `Element.t`.

docs/content/docs/philosophy.mdx

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,12 @@ In other words, if you are searching for a specific JavaScript binding, begin yo
2020
The bindings are exposed under the `WebAPI` namespace with the same flat module structure as the original package.
2121

2222
```ReScript
23-
open WebAPI.DOM
24-
25-
let myElement: WebAPI.DOM.element = document->WebAPI.Document.createElement("div")
23+
let myElement: WebAPI.Element.t = WebAPI.Document.createElement("div")
2624
let id = myElement.id
2725
```
2826

2927
Consumers can also configure `rescript.json` with `"compiler-flags": ["-open WebAPI"]`
30-
when they want to use modules such as `DOM`, `Document`, and `Element` without the
28+
when they want to use modules such as `Document`, `Element`, and `Location` without the
3129
`WebAPI.` prefix.
3230

3331
## Interfaces
@@ -40,7 +38,7 @@ Methods are modeled as functions in a separate module. The idea is that these wi
4038

4139
Inherited methods are duplicated in the inheriting module to eliminate the need to cast the type to the base type.
4240

43-
For DOM elements, `WebAPI.Element` is the method module. The element type itself is exposed as `WebAPI.DOM.element`. Most code does not need to annotate the type because functions such as `Document.createElement` and `Document.querySelector` already return it.
41+
For DOM elements, `WebAPI.Element.t` is the public element type and `WebAPI.Element` is the method module. Most code does not need to annotate the type because functions such as `Document.createElement` and `Document.querySelector` already return it.
4442

4543
### Overloads
4644

@@ -51,9 +49,7 @@ JavaScript supports function overloads, where a function can have multiple signa
5149
In some cases, type conversion will be required. Subtypes can safely be cast to their base type using conversion helpers within their module.
5250

5351
```ReScript
54-
open WebAPI.DOM
55-
56-
let element: WebAPI.DOM.element = document->WebAPI.Document.createElement("div")
52+
let element: WebAPI.Element.t = WebAPI.Document.createElement("div")
5753
let node = element->WebAPI.Element.asNode
5854
```
5955

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
external toHTMLInputElement: DomTypes.element => DomTypes.htmlInputElement = "%identity"
22

3-
let input: DomTypes.htmlInputElement =
4-
Document.createElement("input")->toHTMLInputElement
3+
let input: DomTypes.htmlInputElement = Document.createElement("input")->toHTMLInputElement
54
input->HTMLInputElement.checkValidity->ignore

0 commit comments

Comments
 (0)