Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion analysis/examples/larger-project/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@
},
"dependencies": {
"@glennsl/bs-json": "^5.0.4",
"@rescript/react": "^0.10.3"
"@rescript/react": "workspace:^"
}
}
1 change: 1 addition & 0 deletions biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"files": {
"ignore": [
".yarn/**",
"tests/dependencies/**/src/**",
"tests/analysis_tests/**/src/**",
"tests/build_tests/**/src/**",
"tests/docstring_tests/**",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,10 @@
"workspaces": [
"packages/playground",
"packages/@rescript/*",
"tests/dependencies/**",
"tests/analysis_tests/**",
"tests/docstring_tests",
"tests/gentype_tests/**",
"tests/tests",
"tests/tools_tests",
"scripts/res"
],
Expand Down
3 changes: 3 additions & 0 deletions packages/@rescript/react/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
lib/
*.res.js
*.res.mjs
9 changes: 9 additions & 0 deletions packages/@rescript/react/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "@rescript/react",
"version": "0.14.0",
"private": true,
"description": "React bindings for ReScript",
"dependencies": {
"rescript": "workspace:^"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ type element = Jsx.element
external float: float => element = "%identity"
external int: int => element = "%identity"
external string: string => element = "%identity"
external promise: promise<element> => element = "%identity"

external array: array<element> => element = "%identity"

Expand Down Expand Up @@ -250,6 +251,9 @@ external useCallback7: ('callback, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => 'callback =
@module("react")
external useContext: Context.t<'any> => 'any = "useContext"

@module("react")
external usePromise: promise<'a> => 'a = "use"

@module("react") external useRef: 'value => ref<'value> = "useRef"

@module("react")
Expand Down Expand Up @@ -309,10 +313,9 @@ external useImperativeHandle7: (

@module("react") external useId: unit => string = "useId"

@module("react") external useDeferredValue: 'value => 'value = "useDeferredValue"

/** `useDeferredValue` is a React Hook that lets you defer updating a part of the UI. */
@module("react")
external useTransition: unit => (bool, (unit => unit) => unit) = "useTransition"
external useDeferredValue: ('value, ~initialValue: 'value=?) => 'value = "useDeferredValue"

@module("react")
external useInsertionEffectOnEveryRender: (unit => option<unit => unit>) => unit =
Expand Down Expand Up @@ -405,3 +408,46 @@ external setDisplayName: (component<'props>, string) => unit = "displayName"

@get @return(nullable)
external displayName: component<'props> => option<string> = "displayName"

// Actions

type transitionFunction = unit => unit
type transitionStartFunction = transitionFunction => unit

type transitionFunctionAsync = unit => promise<unit>
type transitionStartFunctionAsync = transitionFunctionAsync => unit

/** `startTransition` lets you render a part of the UI in the background. */
@module("react")
external startTransition: transitionStartFunction = "startTransition"
@module("react")
external startTransitionAsync: transitionStartFunctionAsync = "startTransition"

/** `useTransition` is a React Hook that lets you render a part of the UI in the background. */
@module("react")
external useTransition: unit => (bool, transitionStartFunction) = "useTransition"
@module("react")
external useTransitionAsync: unit => (bool, transitionStartFunctionAsync) = "useTransition"

type action<'state, 'payload> = ('state, 'payload) => promise<'state>

type formAction<'formData> = 'formData => promise<unit>

/** `useActionState` is a Hook that allows you to update state based on the result of a form action. */
@module("react")
external useActionState: (
action<'state, 'payload>,
'state,
~permalink: string=?,
) => ('state, formAction<'payload>, bool) = "useActionState"

/** `useOptimistic` is a React Hook that lets you optimistically update the UI. */
@module("react")
external useOptimistic: (
'state,
~updateFn: ('state, 'action) => 'state=?,
) => ('state, 'action => unit) = "useOptimistic"

/** `act` is a test helper to apply pending React updates before making assertions. */
@module("react")
external act: (unit => promise<unit>) => promise<unit> = "act"
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ external createPortal: (React.element, Dom.element) => React.element = "createPo

external domElementToObj: Dom.element => {..} = "%identity"

type style = JsxDOMStyle.t
type style = ReactDOMStyle.t

type domRef = JsxDOM.domRef

Expand Down Expand Up @@ -246,4 +246,4 @@ external jsxs: (string, JsxDOM.domProps) => Jsx.element = "jsxs"
@module("react/jsx-runtime")
external jsxsKeyed: (string, JsxDOM.domProps, ~key: string=?, @ignore unit) => Jsx.element = "jsxs"

module Style = JsxDOMStyle
module Style = ReactDOMStyle
30 changes: 30 additions & 0 deletions packages/@rescript/react/src/ReactDOMStatic.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
type abortSignal // WebAPI.EventAPI.abortSignal

type nodeStream // NodeJs.Stream.stream

type readableStream // WebAPI.FileAPI.readableStream

type prerenderOptions<'error> = {
bootstrapScriptContent?: string,
bootstrapScripts?: array<string>,
bootstrapModules?: array<string>,
identifierPrefix?: string,
namespaceURI?: string,
onError?: 'error => unit,
progressiveChunkSize?: int,
signal?: abortSignal,
}

type staticResult = {prelude: readableStream}

@module("react-dom/static")
external prerender: (React.element, ~options: prerenderOptions<'error>=?) => promise<staticResult> =
"prerender"

type staticResultNode = {prelude: nodeStream}

@module("react-dom/static")
external prerenderToNodeStream: (
React.element,
~options: prerenderOptions<'error>=?,
) => promise<staticResultNode> = "prerenderToNodeStream"
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ let actAsync = func => {
external isElement: 'element => bool = "isElement"

@module("react-dom/test-utils")
external isElementOfType: ('element, React.component<'props>) => bool = "isElement"
external isElementOfType: ('element, React.component<'props>) => bool = "isElementOfType"

@module("react-dom/test-utils")
external isDOMComponent: 'element => bool = "isDOMComponent"
Expand Down Expand Up @@ -94,8 +94,6 @@ external appendChild: (Dom.element, Dom.element) => Dom.element = "appendChild"
let querySelectorAll = (element, string) => Js.Array.from(querySelectorAll(element, string))

module DOM = {
open Belt

@return(nullable) @get
external value: Dom.element => option<string> = "value"

Expand All @@ -104,30 +102,33 @@ module DOM = {
let findByAllSelector = (element, selector) => querySelectorAll(element, selector)

let findBySelectorAndTextContent = (element, selector, content) =>
querySelectorAll(element, selector)->Array.getBy(node => node->textContent === content)
querySelectorAll(element, selector)->Js.Array2.find(node => node->textContent === content)

let findBySelectorAndPartialTextContent = (element, selector, content) =>
querySelectorAll(element, selector)->Array.getBy(node =>
querySelectorAll(element, selector)->Js.Array2.find(node =>
node->textContent->Js.String2.includes(content)
)
}

let prepareContainer = (container: ref<option<Dom.element>>, ()) => {
open Belt

let containerElement = document->createElement("div")
let _ = document->body->Option.map(body => body->appendChild(containerElement))
switch document->body {
| Some(body) => body->appendChild(containerElement)->ignore
| None => ()
}
container := Some(containerElement)
}

let cleanupContainer = (container: ref<option<Dom.element>>, ()) => {
open Belt

let _ = container.contents->Option.map(remove)
switch container.contents {
| Some(contents) => remove(contents)
| None => ()
}
container := None
}

let getContainer = container => {
open Belt
container.contents->Option.getExn
}
let getContainer = container =>
switch container.contents {
| Some(contents) => contents
| None => raise(Not_found)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ let actAsync: (unit => Js.Promise.t<'a>) => Js.Promise.t<unit>
external isElement: 'element => bool = "isElement"

@module("react-dom/test-utils")
external isElementOfType: ('element, React.component<'props>) => bool = "isElement"
external isElementOfType: ('element, React.component<'props>) => bool = "isElementOfType"

@module("react-dom/test-utils")
external isDOMComponent: 'element => bool = "isDOMComponent"
Expand Down
44 changes: 44 additions & 0 deletions packages/@rescript/react/src/RescriptReactErrorBoundary.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/***
* Important note on this module:
* As soon as React provides a mechanism for error-catching using functional component,
* this is likely to be deprecated and/or move to user space.
*/
type info = {componentStack: string}

type params<'error> = {
error: 'error,
info: info,
}

type reactComponentClass
@module("react") external component: reactComponentClass = "Component"
let noOp: reactComponentClass => unit = %raw(`function (_x) {}`)
let reactComponentClass = component
// this is so that the compiler doesn't optimize away the previous line
noOp(reactComponentClass)

%%raw(`

var ErrorBoundary = (function (Component) {
function ErrorBoundary(props) {
Component.call(this);
this.state = { error: undefined };
}
ErrorBoundary.prototype = Object.create(Component.prototype);
ErrorBoundary.prototype.componentDidCatch = function (error, info) {
this.setState({ error: { error: error, info: info } });
};
ErrorBoundary.prototype.render = function () {
return this.state.error != undefined
? this.props.fallback(this.state.error)
: this.props.children;
};
return ErrorBoundary;
})(reactComponentClass);
`)

@react.component @val
external make: (
~children: React.element,
~fallback: params<'error> => React.element,
) => React.element = "ErrorBoundary"
14 changes: 14 additions & 0 deletions packages/@rescript/react/src/RescriptReactErrorBoundary.resi
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/***
* Important note on this module:
* As soon as React provides a mechanism for error-catching using functional component,
* this is likely to be deprecated and/or move to user space.
*/
type info = {componentStack: string}

type params<'error> = {
error: 'error,
info: info,
}

@react.component
let make: (~children: React.element, ~fallback: params<'error> => React.element) => React.element
Loading
Loading