Skip to content

Commit

Permalink
Add React 18 bindings (#756)
Browse files Browse the repository at this point in the history
Co-authored-by: Antonio Nuno Monteiro <anmonteiro@gmail.com>
  • Loading branch information
davesnx and anmonteiro authored Oct 9, 2023
1 parent 3327dc2 commit 1fdc7b1
Show file tree
Hide file tree
Showing 19 changed files with 2,149 additions and 6,431 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ help: ## Print this help message

.PHONY: build
build: ## Build the project, including non installable libraries and executables
@$(DUNE) build @@default
@$(DUNE) build @all

.PHONY: build-prod
build-prod: ## Build for production (--profile=prod)
Expand Down
2 changes: 1 addition & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
default = pkgs.mkShell {
dontDetectOcamlConflicts = true;
inputsFrom = pkgs.lib.attrValues packages;
nativeBuildInputs = with pkgs.ocamlPackages; [ ocamlformat ];
nativeBuildInputs = with pkgs.ocamlPackages; [ ocamlformat pkgs.nodejs_latest ];
propagatedBuildInputs = with pkgs.ocamlPackages; [ merlin ];
};
};
Expand Down
7,114 changes: 1,195 additions & 5,919 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@
"homepage": "https://reasonml.github.io/reason-react/",
"devDependencies": {
"jest": "^26.0.1",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-test-renderer": "^18.0.0"
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-test-renderer": "^18.2.0"
},
"jest": {
"moduleDirectories": [
Expand Down
4 changes: 3 additions & 1 deletion ppx/test/input.re
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,9 @@ module External = {
{|require("my-react-library").MyReactComponent|};
};

module type X_int = {let x: int;};
module type X_int = {
let x: int;
};

module Func = (M: X_int) => {
let x = M.x + 1;
Expand Down
34 changes: 1 addition & 33 deletions src/React.re
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,16 @@ module DOM = DOM;
module ErrorBoundary = ErrorBoundary;
module Event = Event;
module Router = Router;

type element = Types.element;

external null: element = "null";

external float: float => element = "%identity";
external int: int => element = "%identity";
external string: string => element = "%identity";

external array: array(element) => element = "%identity";

type componentLike('props, 'return) = Types.componentLike('props, 'return);

type component('props) = componentLike('props, element);

/* this function exists to prepare for making `component` abstract */
Expand Down Expand Up @@ -141,36 +139,6 @@ module Suspense = {
"Suspense";
};

/* Experimental React.SuspenseList */
module SuspenseList = {
type revealOrder;
type tail;
[@mel.obj]
external makeProps:
(
~children: element=?,
~revealOrder: [ | `forwards | `backwards | `together]=?,
~tail: [ | `collapsed | `hidden]=?,
unit
) =>
{
.
"children": option(element),
"revealOrder": option(revealOrder),
"tail": option(tail),
};

[@mel.module "react"]
external make:
component({
.
"children": option(element),
"revealOrder": option(revealOrder),
"tail": option(tail),
}) =
"SuspenseList";
};

include Hooks;

[@mel.set]
Expand Down
196 changes: 151 additions & 45 deletions src/React.rei
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@ type componentLike('props, 'return) = 'props => 'return;
type component('props) = componentLike('props, element);

external null: element = "null";

external float: float => element = "%identity";
external int: int => element = "%identity";
external string: string => element = "%identity";

external array: array(element) => element = "%identity";

/* this function exists to prepare for making `component` abstract */
Expand Down Expand Up @@ -156,35 +154,6 @@ module Suspense: {
"Suspense";
};

/* Experimental React.SuspenseList */
module SuspenseList: {
type revealOrder;
type tail;
[@mel.obj]
external makeProps:
(
~children: element=?,
~revealOrder: [ | `forwards | `backwards | `together]=?,
~tail: [ | `collapsed | `hidden]=?,
unit
) =>
{
.
"children": option(element),
"revealOrder": option(revealOrder),
"tail": option(tail),
};

[@mel.module "react"]
external make:
component({
.
"children": option(element),
"revealOrder": option(revealOrder),
"tail": option(tail),
}) =
"SuspenseList";
};
/* HOOKS */

/*
Expand Down Expand Up @@ -214,6 +183,25 @@ external useReducerWithMapState:
('state, 'action => unit) =
"useReducer";

[@mel.module "react"]
external useSyncExternalStore:
(
~subscribe: (([@mel.uncurry] (unit => unit)) => ([@mel.uncurry] (unit => unit))),
~getSnapshot: unit => 'snapshot
) =>
'snapshot =
"useSyncExternalStore";

[@mel.module "react"]
external useSyncExternalStoreWithServer:
(
~subscribe: (([@mel.uncurry] (unit => unit)) => ([@mel.uncurry] (unit => unit))),
~getSnapshot: unit => 'snapshot,
~getServerSnapshot: [@mel.uncurry] (unit => 'snapshot)
) =>
'snapshot =
"useSyncExternalStore";

[@mel.module "react"]
external useEffect: ([@mel.uncurry] (unit => option(unit => unit))) => unit =
"useEffect";
Expand Down Expand Up @@ -263,6 +251,56 @@ external useEffect7:
unit =
"useEffect";

[@mel.module "react"]
external useInsertionEffect:
([@mel.uncurry] (unit => option(unit => unit))) => unit =
"useInsertionEffect";
[@mel.module "react"]
external useInsertionEffect0:
(
[@mel.uncurry] (unit => option(unit => unit)),
[@mel.as {json|[]|json}] _
) =>
unit =
"useInsertionEffect";
[@mel.module "react"]
external useInsertionEffect1:
([@mel.uncurry] (unit => option(unit => unit)), array('a)) => unit =
"useInsertionEffect";
[@mel.module "react"]
external useInsertionEffect2:
([@mel.uncurry] (unit => option(unit => unit)), ('a, 'b)) => unit =
"useInsertionEffect";
[@mel.module "react"]
external useInsertionEffect3:
([@mel.uncurry] (unit => option(unit => unit)), ('a, 'b, 'c)) => unit =
"useInsertionEffect";
[@mel.module "react"]
external useInsertionEffect4:
([@mel.uncurry] (unit => option(unit => unit)), ('a, 'b, 'c, 'd)) => unit =
"useInsertionEffect";
[@mel.module "react"]
external useInsertionEffect5:
([@mel.uncurry] (unit => option(unit => unit)), ('a, 'b, 'c, 'd, 'e)) =>
unit =
"useInsertionEffect";
[@mel.module "react"]
external useInsertionEffect6:
(
[@mel.uncurry] (unit => option(unit => unit)),
('a, 'b, 'c, 'd, 'e, 'f)
) =>
unit =
"useInsertionEffect";
[@mel.module "react"]
external useInsertionEffect7:
(
[@mel.uncurry] (unit => option(unit => unit)),
('a, 'b, 'c, 'd, 'e, 'f, 'g)
) =>
unit =
"useInsertionEffect";

[@mel.module "react"]
external useLayoutEffect:
([@mel.uncurry] (unit => option(unit => unit))) => unit =
Expand Down Expand Up @@ -371,6 +409,9 @@ external useCallback7: ('fn, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => 'fn =
external useContext: Context.t('any) => 'any = "useContext";

[@mel.module "react"] external useRef: 'value => ref('value) = "useRef";
[@mel.module "react"] external useId: unit => string = "useId";

[@mel.module "react"] external useDeferredValue: 'a => 'a = "useDeferredValue";

[@mel.module "react"]
external useImperativeHandle0:
Expand Down Expand Up @@ -519,20 +560,25 @@ module Uncurried: {
"useCallback";
};

type transitionConfig = {timeoutMs: int};

[@mel.module "react"]
external useTransition:
(~config: transitionConfig=?, unit) =>
(callback(callback(unit, unit), unit), bool) =
external useTransition: unit => (bool, callback(callback(unit, unit), unit)) =
"useTransition";

module Experimental: {
/* This module is used to bind to APIs for future versions of React. There is no guarantee of backwards compatibility or stability. */
[@mel.module "react"] external use: Js.Promise.t('a) => 'a = "use";
};

[@mel.set]
external setDisplayName: (component('props), string) => unit = "displayName";

[@mel.get] [@mel.return nullable]
external displayName: component('props) => option(string) = "displayName";

[@mel.module "react"]
external useDebugValue: ('value, ~format: 'value => string=?, unit) => unit =
"useDebugValue";

module Event: {
/* This is the whole synthetic event system of ReactJS/ReasonReact. The first module `Synthetic` represents
the generic synthetic event. The rest are the specific ones.
Expand Down Expand Up @@ -1511,27 +1557,84 @@ module DOM: {

[@mel.module "react-dom/server"]
external renderToStaticMarkup: element => string = "renderToStaticMarkup";

[@deriving abstract]
type options = {
[@mel.optional]
bootstrapScriptContent: option(string),
[@mel.optional]
bootstrapScripts: option(array(string)),
[@mel.optional]
bootstrapModules: option(array(string)),
[@mel.optional]
identifierPrefix: option(string),
[@mel.optional]
namespaceURI: option(string),
[@mel.optional]
nonce: option(string),
[@mel.optional]
onAllReady: option(unit => unit),
[@mel.optional]
onError: option(Js.Exn.t => unit),
[@mel.optional]
onShellReady: option(unit => unit),
[@mel.optional]
onShellError: option(Js.Exn.t => unit),
[@mel.optional]
progressiveChunkSize: option(int),
};

type pipeableStream = {
/* Using empty object instead of Node.stream since Melange don't provide a binding to node's Stream (https://nodejs.org/api/stream.html) */
pipe: {.} => unit,
abort: unit => unit,
};

let renderToPipeableStream:
(
~bootstrapScriptContent: string=?,
~bootstrapScripts: array(string)=?,
~bootstrapModules: array(string)=?,
~identifierPrefix: string=?,
~namespaceURI: string=?,
~nonce: string=?,
~onAllReady: unit => unit=?,
~onError: Js.Exn.t => unit=?,
~onShellReady: unit => unit=?,
~onShellError: Js.Exn.t => unit=?,
~progressiveChunkSize: int=?,
element
) =>
pipeableStream;
};

[@mel.return nullable]
external querySelector: string => option(Dom.element) =
"document.querySelector";

[@mel.module "react-dom"]
external render: (element, Dom.element) => unit = "render";

module Experimental: {
module Client: {
type root;

[@mel.module "react-dom"]
external createRoot: Dom.element => root = "createRoot";
[@mel.send] external render: (root, element) => unit = "render";

[@mel.module "react-dom"]
external createBlockingRoot: Dom.element => root = "createBlockingRoot";
[@mel.send] external unmount: (root, unit) => unit = "unmount";

[@mel.send] external render: (root, element) => unit = "render";
[@mel.module "react-dom/client"]
external createRoot: Dom.element => root = "createRoot";

[@mel.module "react-dom/client"]
external hydrateRoot: (Dom.element, element) => root = "hydrateRoot";
};

[@deprecated
"This function will be removed in the next release. Use React.DOM.Client.render instead."
]
[@mel.module "react-dom"]
external render: (element, Dom.element) => unit = "render";

[@deprecated
"This function will be removed in the next release. Use React.DOM.Client.hydrateRoot instead."
]
[@mel.module "react-dom"]
external hydrate: (element, Dom.element) => unit = "hydrate";

Expand All @@ -1542,6 +1645,9 @@ module DOM: {
external unmountComponentAtNode: Dom.element => unit =
"unmountComponentAtNode";

[@mel.module "react-dom"]
external flushSync: (unit => unit) => unit = "flushSync";

external domElementToObj: Dom.element => Js.t({..}) = "%identity";

type style = Style.t;
Expand Down
Loading

0 comments on commit 1fdc7b1

Please sign in to comment.