From 3307fbfb7021c1729833b5f700d8281fbf880788 Mon Sep 17 00:00:00 2001 From: Christoph Knittel Date: Mon, 26 May 2025 16:31:08 +0200 Subject: [PATCH 01/14] Add @rescript/react package --- packages/react/.gitignore | 21 + packages/react/LICENSE | 21 + packages/react/package-lock.json | 96 ++++ packages/react/package.json | 39 ++ packages/react/rescript.json | 12 + packages/react/src/React.bs.js | 33 ++ packages/react/src/React.res | 443 ++++++++++++++++ packages/react/src/ReactDOM.bs.js | 58 +++ packages/react/src/ReactDOM.res | 249 +++++++++ packages/react/src/ReactDOMServer.bs.js | 2 + packages/react/src/ReactDOMServer.res | 5 + packages/react/src/ReactDOMStatic.bs.js | 2 + packages/react/src/ReactDOMStatic.res | 30 ++ packages/react/src/ReactDOMStyle.bs.js | 12 + packages/react/src/ReactDOMStyle.res | 16 + packages/react/src/ReactEvent.bs.js | 53 ++ packages/react/src/ReactEvent.res | 273 ++++++++++ packages/react/src/ReactEvent.resi | 472 ++++++++++++++++++ packages/react/src/ReactTestUtils.bs.js | 105 ++++ packages/react/src/ReactTestUtils.res | 134 +++++ packages/react/src/ReactTestUtils.resi | 56 +++ .../src/RescriptReactErrorBoundary.bs.js | 33 ++ .../react/src/RescriptReactErrorBoundary.res | 44 ++ .../react/src/RescriptReactErrorBoundary.resi | 14 + packages/react/src/RescriptReactRouter.bs.js | 219 ++++++++ packages/react/src/RescriptReactRouter.res | 214 ++++++++ packages/react/src/RescriptReactRouter.resi | 46 ++ 27 files changed, 2702 insertions(+) create mode 100644 packages/react/.gitignore create mode 100644 packages/react/LICENSE create mode 100644 packages/react/package-lock.json create mode 100644 packages/react/package.json create mode 100644 packages/react/rescript.json create mode 100644 packages/react/src/React.bs.js create mode 100644 packages/react/src/React.res create mode 100644 packages/react/src/ReactDOM.bs.js create mode 100644 packages/react/src/ReactDOM.res create mode 100644 packages/react/src/ReactDOMServer.bs.js create mode 100644 packages/react/src/ReactDOMServer.res create mode 100644 packages/react/src/ReactDOMStatic.bs.js create mode 100644 packages/react/src/ReactDOMStatic.res create mode 100644 packages/react/src/ReactDOMStyle.bs.js create mode 100644 packages/react/src/ReactDOMStyle.res create mode 100644 packages/react/src/ReactEvent.bs.js create mode 100644 packages/react/src/ReactEvent.res create mode 100644 packages/react/src/ReactEvent.resi create mode 100644 packages/react/src/ReactTestUtils.bs.js create mode 100644 packages/react/src/ReactTestUtils.res create mode 100644 packages/react/src/ReactTestUtils.resi create mode 100644 packages/react/src/RescriptReactErrorBoundary.bs.js create mode 100644 packages/react/src/RescriptReactErrorBoundary.res create mode 100644 packages/react/src/RescriptReactErrorBoundary.resi create mode 100644 packages/react/src/RescriptReactRouter.bs.js create mode 100644 packages/react/src/RescriptReactRouter.res create mode 100644 packages/react/src/RescriptReactRouter.resi diff --git a/packages/react/.gitignore b/packages/react/.gitignore new file mode 100644 index 0000000000..06844f2b81 --- /dev/null +++ b/packages/react/.gitignore @@ -0,0 +1,21 @@ +.DS_Store +/node_modules* +finalOutput/*.js +.merlin +.install +/lib/bs/ +/lib/js/ +/lib/ocaml/ +/docs/ +*.log +.bsb.lock +_esy +_build +*.install +src/legacy/*.bs.js + +# Editor +/.idea/ + +# React +!/src/react/*.js diff --git a/packages/react/LICENSE b/packages/react/LICENSE new file mode 100644 index 0000000000..76d46ad4ae --- /dev/null +++ b/packages/react/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Sander, 2020 The ReScript Project + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/react/package-lock.json b/packages/react/package-lock.json new file mode 100644 index 0000000000..26294ad1d4 --- /dev/null +++ b/packages/react/package-lock.json @@ -0,0 +1,96 @@ +{ + "name": "@rescript/react", + "version": "0.14.0-rc.1", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "@rescript/react", + "version": "0.14.0-rc.1", + "license": "MIT", + "devDependencies": { + "react": "^19.1.0", + "react-dom": "^19.1.0", + "rescript": "^11.0.0" + }, + "peerDependencies": { + "react": ">=19.0.0", + "react-dom": ">=19.0.0" + } + }, + "node_modules/react": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", + "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", + "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "scheduler": "^0.26.0" + }, + "peerDependencies": { + "react": "^19.1.0" + } + }, + "node_modules/rescript": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/rescript/-/rescript-11.0.0.tgz", + "integrity": "sha512-uIUwDZZmDUb7ymGkBiiGioxMg8hXh1mze/2k/qhYQcZGgi7PrLHQIW9AksM7gb9WnpjCAvFsA8U2VgC0nA468w==", + "dev": true, + "hasInstallScript": true, + "bin": { + "bsc": "bsc", + "bstracing": "lib/bstracing", + "rescript": "rescript" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/scheduler": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", + "dev": true, + "license": "MIT" + } + }, + "dependencies": { + "react": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", + "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", + "dev": true + }, + "react-dom": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", + "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", + "dev": true, + "requires": { + "scheduler": "^0.26.0" + } + }, + "rescript": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/rescript/-/rescript-11.0.0.tgz", + "integrity": "sha512-uIUwDZZmDUb7ymGkBiiGioxMg8hXh1mze/2k/qhYQcZGgi7PrLHQIW9AksM7gb9WnpjCAvFsA8U2VgC0nA468w==", + "dev": true + }, + "scheduler": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", + "dev": true + } + } +} diff --git a/packages/react/package.json b/packages/react/package.json new file mode 100644 index 0000000000..3dfa78705d --- /dev/null +++ b/packages/react/package.json @@ -0,0 +1,39 @@ +{ + "name": "@rescript/react", + "version": "0.14.0-rc.1", + "description": "React bindings for ReScript", + "files": [ + "README.md", + "CHANGELOG.md", + "LICENSE", + "rescript.json", + "src/**/*.res", + "src/**/*.resi" + ], + "scripts": { + "build": "rescript build", + "start": "rescript build -w", + "clean": "rescript clean -with-deps", + "test": "echo 'tests disabled for now'" + }, + "keywords": [ + "rescript", + "react" + ], + "author": "Ricky Vetter", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/rescript-lang/rescript-react.git" + }, + "homepage": "https://rescript-lang.org/docs/react/latest/introduction", + "devDependencies": { + "react": "^19.1.0", + "react-dom": "^19.1.0", + "rescript": "^11.0.0" + }, + "peerDependencies": { + "react": ">=19.0.0", + "react-dom": ">=19.0.0" + } +} diff --git a/packages/react/rescript.json b/packages/react/rescript.json new file mode 100644 index 0000000000..599e1f6777 --- /dev/null +++ b/packages/react/rescript.json @@ -0,0 +1,12 @@ +{ + "name": "@rescript/react", + "jsx": { + "version": 4, + "mode": "classic" + }, + "sources": [{ "dir": "src", "subdirs": true }], + "package-specs": [{ "module": "commonjs", "in-source": true }], + "suffix": ".bs.js", + "bs-dev-dependencies": [], + "bsc-flags": [] +} diff --git a/packages/react/src/React.bs.js b/packages/react/src/React.bs.js new file mode 100644 index 0000000000..ef827dd7e4 --- /dev/null +++ b/packages/react/src/React.bs.js @@ -0,0 +1,33 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE +'use strict'; + +var React = require("react"); + +var Children = {}; + +var Context = {}; + +var Fragment = {}; + +var StrictMode = {}; + +var Suspense = {}; + +function lazy_(load) { + return React.lazy(async function () { + return { + default: await load() + }; + }); +} + +var Uncurried = {}; + +exports.Children = Children; +exports.Context = Context; +exports.Fragment = Fragment; +exports.StrictMode = StrictMode; +exports.Suspense = Suspense; +exports.lazy_ = lazy_; +exports.Uncurried = Uncurried; +/* react Not a pure module */ diff --git a/packages/react/src/React.res b/packages/react/src/React.res new file mode 100644 index 0000000000..f1f6831518 --- /dev/null +++ b/packages/react/src/React.res @@ -0,0 +1,443 @@ +type element = Jsx.element + +@val external null: element = "null" + +external float: float => element = "%identity" +external int: int => element = "%identity" +external string: string => element = "%identity" +external promise: promise => element = "%identity" + +external array: array => element = "%identity" + +type componentLike<'props, 'return> = Jsx.componentLike<'props, 'return> + +type component<'props> = Jsx.component<'props> + +external component: componentLike<'props, element> => component<'props> = "%identity" + +@module("react") +external createElement: (component<'props>, 'props) => element = "createElement" + +@module("react") +external cloneElement: (element, 'props) => element = "cloneElement" + +@module("react") +external isValidElement: 'a => bool = "isValidElement" + +@variadic @module("react") +external createElementVariadic: (component<'props>, 'props, array) => element = + "createElement" + +@module("react/jsx-runtime") +external jsx: (component<'props>, 'props) => element = "jsx" + +@module("react/jsx-runtime") +external jsxKeyed: (component<'props>, 'props, ~key: string=?, @ignore unit) => element = "jsx" + +@module("react/jsx-runtime") +external jsxs: (component<'props>, 'props) => element = "jsxs" + +@module("react/jsx-runtime") +external jsxsKeyed: (component<'props>, 'props, ~key: string=?, @ignore unit) => element = "jsxs" + +type fragmentProps = {children?: element} + +@module("react/jsx-runtime") external jsxFragment: component = "Fragment" + +type ref<'value> = {mutable current: 'value} + +@module("react") +external createRef: unit => ref> = "createRef" + +module Children = { + @module("react") @scope("Children") + external map: (element, element => element) => element = "map" + @module("react") @scope("Children") + external mapWithIndex: (element, (element, int) => element) => element = "map" + @module("react") @scope("Children") + external forEach: (element, element => unit) => unit = "forEach" + @module("react") @scope("Children") + external forEachWithIndex: (element, (element, int) => unit) => unit = "forEach" + @module("react") @scope("Children") + external count: element => int = "count" + @module("react") @scope("Children") + external only: element => element = "only" + @module("react") @scope("Children") + external toArray: element => array = "toArray" +} + +module Context = { + type t<'context> + + type props<'context> = { + value: 'context, + children: element, + } + + @get + external provider: t<'context> => component> = "Provider" +} + +@module("react") +external createContext: 'a => Context.t<'a> = "createContext" + +@module("react") +external forwardRef: (('props, Js.Nullable.t>) => element) => component<'props> = + "forwardRef" + +@module("react") +external memo: component<'props> => component<'props> = "memo" + +@module("react") +external memoCustomCompareProps: ( + component<'props>, + ('props, 'props) => bool, +) => component<'props> = "memo" + +@module("react") external fragment: component = "Fragment" + +module Fragment = { + type props = {key?: string, children: element} + + @module("react") + external make: component = "Fragment" +} + +module StrictMode = { + type props = {key?: string, children: element} + + @module("react") + external make: component = "StrictMode" +} + +module Suspense = { + type props = {key?: string, children?: element, fallback?: element} + + @module("react") + external make: component = "Suspense" +} + +type dynamicallyImportedModule<'a> = {default: component<'a>} + +@module("react") +external lazy_: (unit => promise>) => component<'a> = "lazy" + +let lazy_ = load => lazy_(async () => {default: await load()}) + +/* HOOKS */ + +/* + * Yeah, we know this api isn't great. tl;dr: useReducer instead. + * It's because useState can take functions or non-function values and treats + * them differently. Lazy initializer + callback which returns state is the + * only way to safely have any type of state and be able to update it correctly. + */ +@module("react") +external useState: (unit => 'state) => ('state, ('state => 'state) => unit) = "useState" + +@module("react") +external useReducer: (('state, 'action) => 'state, 'state) => ('state, 'action => unit) = + "useReducer" + +@module("react") +external useReducerWithMapState: ( + ('state, 'action) => 'state, + 'initialState, + 'initialState => 'state, +) => ('state, 'action => unit) = "useReducer" + +@module("react") +external useEffectOnEveryRender: (unit => option unit>) => unit = "useEffect" +@module("react") +external useEffect: (unit => option unit>, 'deps) => unit = "useEffect" +@module("react") +external useEffect0: (unit => option unit>, @as(json`[]`) _) => unit = "useEffect" +@module("react") +external useEffect1: (unit => option unit>, array<'a>) => unit = "useEffect" +@module("react") +external useEffect2: (unit => option unit>, ('a, 'b)) => unit = "useEffect" +@module("react") +external useEffect3: (unit => option unit>, ('a, 'b, 'c)) => unit = "useEffect" +@module("react") +external useEffect4: (unit => option unit>, ('a, 'b, 'c, 'd)) => unit = "useEffect" +@module("react") +external useEffect5: (unit => option unit>, ('a, 'b, 'c, 'd, 'e)) => unit = "useEffect" +@module("react") +external useEffect6: (unit => option unit>, ('a, 'b, 'c, 'd, 'e, 'f)) => unit = "useEffect" +@module("react") +external useEffect7: (unit => option unit>, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => unit = + "useEffect" + +@module("react") +external useLayoutEffectOnEveryRender: (unit => option unit>) => unit = "useLayoutEffect" +@module("react") +external useLayoutEffect: (unit => option unit>, 'deps) => unit = "useLayoutEffect" +@module("react") +external useLayoutEffect0: (unit => option unit>, @as(json`[]`) _) => unit = + "useLayoutEffect" +@module("react") +external useLayoutEffect1: (unit => option unit>, array<'a>) => unit = "useLayoutEffect" +@module("react") +external useLayoutEffect2: (unit => option unit>, ('a, 'b)) => unit = "useLayoutEffect" +@module("react") +external useLayoutEffect3: (unit => option unit>, ('a, 'b, 'c)) => unit = "useLayoutEffect" +@module("react") +external useLayoutEffect4: (unit => option unit>, ('a, 'b, 'c, 'd)) => unit = + "useLayoutEffect" +@module("react") +external useLayoutEffect5: (unit => option unit>, ('a, 'b, 'c, 'd, 'e)) => unit = + "useLayoutEffect" +@module("react") +external useLayoutEffect6: (unit => option unit>, ('a, 'b, 'c, 'd, 'e, 'f)) => unit = + "useLayoutEffect" +@module("react") +external useLayoutEffect7: (unit => option unit>, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => unit = + "useLayoutEffect" + +@module("react") +external useMemo: (unit => 'any, 'deps) => 'any = "useMemo" + +@module("react") +external useMemo0: (unit => 'any, @as(json`[]`) _) => 'any = "useMemo" + +@module("react") +external useMemo1: (unit => 'any, array<'a>) => 'any = "useMemo" + +@module("react") +external useMemo2: (unit => 'any, ('a, 'b)) => 'any = "useMemo" + +@module("react") +external useMemo3: (unit => 'any, ('a, 'b, 'c)) => 'any = "useMemo" + +@module("react") +external useMemo4: (unit => 'any, ('a, 'b, 'c, 'd)) => 'any = "useMemo" + +@module("react") +external useMemo5: (unit => 'any, ('a, 'b, 'c, 'd, 'e)) => 'any = "useMemo" + +@module("react") +external useMemo6: (unit => 'any, ('a, 'b, 'c, 'd, 'e, 'f)) => 'any = "useMemo" + +@module("react") +external useMemo7: (unit => 'any, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => 'any = "useMemo" + +@module("react") +external useCallback: ('f, 'deps) => 'f = "useCallback" + +@module("react") +external useCallback0: ('f, @as(json`[]`) _) => 'f = "useCallback" + +@module("react") +external useCallback1: ('f, array<'a>) => 'f = "useCallback" + +@module("react") +external useCallback2: ('f, ('a, 'b)) => 'f = "useCallback" + +@module("react") +external useCallback3: ('f, ('a, 'b, 'c)) => 'f = "useCallback" + +@module("react") +external useCallback4: ('f, ('a, 'b, 'c, 'd)) => 'f = "useCallback" + +@module("react") +external useCallback5: ('f, ('a, 'b, 'c, 'd, 'e)) => 'f = "useCallback" + +@module("react") +external useCallback6: ('callback, ('a, 'b, 'c, 'd, 'e, 'f)) => 'callback = "useCallback" + +@module("react") +external useCallback7: ('callback, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => 'callback = "useCallback" + +@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") +external useImperativeHandleOnEveryRender: (Js.Nullable.t>, unit => 'value) => unit = + "useImperativeHandle" + +@module("react") +external useImperativeHandle: (Js.Nullable.t>, unit => 'value, 'deps) => unit = + "useImperativeHandle" + +@module("react") +external useImperativeHandle0: ( + Js.Nullable.t>, + unit => 'value, + @as(json`[]`) _, +) => unit = "useImperativeHandle" + +@module("react") +external useImperativeHandle1: (Js.Nullable.t>, unit => 'value, array<'a>) => unit = + "useImperativeHandle" + +@module("react") +external useImperativeHandle2: (Js.Nullable.t>, unit => 'value, ('a, 'b)) => unit = + "useImperativeHandle" + +@module("react") +external useImperativeHandle3: (Js.Nullable.t>, unit => 'value, ('a, 'b, 'c)) => unit = + "useImperativeHandle" + +@module("react") +external useImperativeHandle4: ( + Js.Nullable.t>, + unit => 'value, + ('a, 'b, 'c, 'd), +) => unit = "useImperativeHandle" + +@module("react") +external useImperativeHandle5: ( + Js.Nullable.t>, + unit => 'value, + ('a, 'b, 'c, 'd, 'e), +) => unit = "useImperativeHandle" + +@module("react") +external useImperativeHandle6: ( + Js.Nullable.t>, + unit => 'value, + ('a, 'b, 'c, 'd, 'e, 'f), +) => unit = "useImperativeHandle" + +@module("react") +external useImperativeHandle7: ( + Js.Nullable.t>, + unit => 'value, + ('a, 'b, 'c, 'd, 'e, 'f, 'g), +) => unit = "useImperativeHandle" + +@module("react") external useId: unit => string = "useId" + +/** `useDeferredValue` is a React Hook that lets you defer updating a part of the UI. */ +@module("react") +external useDeferredValue: ('value, ~initialValue: 'value=?) => 'value = "useDeferredValue" + +@module("react") +external useInsertionEffectOnEveryRender: (unit => option unit>) => unit = + "useInsertionEffect" +@module("react") +external useInsertionEffect: (unit => option unit>, 'deps) => unit = "useInsertionEffect" +@module("react") +external useInsertionEffect0: (unit => option unit>, @as(json`[]`) _) => unit = + "useInsertionEffect" +@module("react") +external useInsertionEffect1: (unit => option unit>, array<'a>) => unit = + "useInsertionEffect" +@module("react") +external useInsertionEffect2: (unit => option unit>, ('a, 'b)) => unit = + "useInsertionEffect" +@module("react") +external useInsertionEffect3: (unit => option unit>, ('a, 'b, 'c)) => unit = + "useInsertionEffect" +@module("react") +external useInsertionEffect4: (unit => option unit>, ('a, 'b, 'c, 'd)) => unit = + "useInsertionEffect" +@module("react") +external useInsertionEffect5: (unit => option unit>, ('a, 'b, 'c, 'd, 'e)) => unit = + "useInsertionEffect" +@module("react") +external useInsertionEffect6: (unit => option unit>, ('a, 'b, 'c, 'd, 'e, 'f)) => unit = + "useInsertionEffect" +@module("react") +external useInsertionEffect7: (unit => option unit>, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => unit = + "useInsertionEffect" + +@module("react") +external useSyncExternalStore: ( + ~subscribe: (unit => unit) => unit => unit, + ~getSnapshot: unit => 'state, +) => 'state = "useSyncExternalStore" + +@module("react") +external useSyncExternalStoreWithServerSnapshot: ( + ~subscribe: (unit => unit) => unit => unit, + ~getSnapshot: unit => 'state, + ~getServerSnapshot: unit => 'state, +) => 'state = "useSyncExternalStore" + +module Uncurried = { + @module("react") + external useState: (unit => 'state) => ('state, ('state => 'state) => unit) = "useState" + + @module("react") + external useReducer: (('state, 'action) => 'state, 'state) => ('state, 'action => unit) = + "useReducer" + + @module("react") + external useReducerWithMapState: ( + ('state, 'action) => 'state, + 'initialState, + 'initialState => 'state, + ) => ('state, 'action => unit) = "useReducer" + + @module("react") + external useCallback: ('f, 'deps) => 'f = "useCallback" + + @module("react") + external useCallback0: ('f, @as(json`[]`) _) => 'f = "useCallback" + + @module("react") + external useCallback1: ('f, array<'a>) => 'f = "useCallback" + + @module("react") + external useCallback2: ('f, ('a, 'b)) => 'f = "useCallback" + + @module("react") + external useCallback3: ('f, ('a, 'b, 'c)) => 'f = "useCallback" + + @module("react") + external useCallback4: ('f, ('a, 'b, 'c, 'd)) => 'f = "useCallback" + + @module("react") + external useCallback5: ('f, ('a, 'b, 'c, 'd, 'e)) => 'f = "useCallback" + + @module("react") + external useCallback6: ('callback, ('a, 'b, 'c, 'd, 'e, 'f)) => 'callback = "useCallback" + + @module("react") + external useCallback7: ('callback, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => 'callback = "useCallback" +} + +@set +external setDisplayName: (component<'props>, string) => unit = "displayName" + +@get @return(nullable) +external displayName: component<'props> => option = "displayName" + +// Actions + +type transitionFunction = unit => promise + +type transitionStartFunction = transitionFunction => unit + +/** `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" + +type action<'state, 'payload> = ('state, 'payload) => promise<'state> + +type formAction<'formData> = 'formData => promise + +/** `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) => promise = "act" diff --git a/packages/react/src/ReactDOM.bs.js b/packages/react/src/ReactDOM.bs.js new file mode 100644 index 0000000000..fa516402fa --- /dev/null +++ b/packages/react/src/ReactDOM.bs.js @@ -0,0 +1,58 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE +'use strict'; + +var Caml_option = require("rescript/lib/js/caml_option.js"); + +var Root = {}; + +var Client = { + Root: Root +}; + +function getString(formData, name) { + var value = formData.get(name); + if (!(value == null) && typeof value === "string") { + return Caml_option.some(value); + } + +} + +function getFile(formData, name) { + var value = formData.get(name); + if (!(value == null) && typeof value !== "string") { + return Caml_option.some(value); + } + +} + +function getAll(t, string) { + return t.getAll(string).map(function (value) { + if (typeof value === "string") { + return { + TAG: "String", + _0: value + }; + } else { + return { + TAG: "File", + _0: value + }; + } + }); +} + +var $$FormData = { + getString: getString, + getFile: getFile, + getAll: getAll +}; + +var Ref = {}; + +var Style; + +exports.Client = Client; +exports.$$FormData = $$FormData; +exports.Ref = Ref; +exports.Style = Style; +/* No side effect */ diff --git a/packages/react/src/ReactDOM.res b/packages/react/src/ReactDOM.res new file mode 100644 index 0000000000..fbd564bf4d --- /dev/null +++ b/packages/react/src/ReactDOM.res @@ -0,0 +1,249 @@ +/* First time reading a ReScript file? */ +/* `external` is the foreign function call in OCaml. */ +/* here we're saying `I guarantee that on the JS side, we have a `render` function in the module "react-dom" + that takes in a reactElement, a dom element, and returns unit (nothing) */ +/* It's like `let`, except you're pointing the implementation to the JS side. The compiler will inline these + calls and add the appropriate `require("react-dom")` in the file calling this `render` */ + +// Helper so that ReactDOM itself doesn't bring any runtime +@val @return(nullable) +external querySelector: string => option = "document.querySelector" + +module Client = { + module Root = { + type t + + @send external render: (t, React.element) => unit = "render" + + @send external unmount: (t, unit) => unit = "unmount" + } + + @module("react-dom/client") + external createRoot: Dom.element => Root.t = "createRoot" + + @module("react-dom/client") + external hydrateRoot: (Dom.element, React.element) => Root.t = "hydrateRoot" +} + +// Very rudimentary form data bindings +module FormData = { + type t + type file + + type formValue = + | String(string) + | File(file) + + @new external make: unit => t = "FormData" + + @send external append: (t, string, ~filename: string=?) => unit = "append" + @send external delete: (t, string) => unit = "delete" + @return(nullable) @send external getUnsafe: (t, string) => option<'a> = "get" + @send external getAllUnsafe: (t, string) => array<'a> = "getAll" + + let getString = (formData, name) => { + switch formData->getUnsafe(name) { + | Some(value) => Js.typeof(value) === "string" ? Some(value) : None + | _ => None + } + } + + external _asFile: 'a => file = "%identity" + + let getFile = (formData, name) => { + switch formData->getUnsafe(name) { + | Some(value) => Js.typeof(value) === "string" ? None : Some(value->_asFile) + | _ => None + } + } + + let getAll = (t, string) => { + t + ->getAllUnsafe(string) + ->Js.Array2.map(value => { + Js.typeof(value) === "string" ? String(value) : File(value->_asFile) + }) + } + + @send external set: (string, string) => unit = "set" + @send external has: string => bool = "has" + // @send external keys: t => Iterator.t = "keys"; + // @send external values: t => Iterator.t = "values"; +} + +@module("react-dom") +external createPortal: (React.element, Dom.element) => React.element = "createPortal" + +external domElementToObj: Dom.element => {..} = "%identity" + +type style = ReactDOMStyle.t + +type domRef = JsxDOM.domRef + +module Ref = { + type t = domRef + type currentDomRef = React.ref> + type callbackDomRef = Js.nullable => option unit> + + external domRef: currentDomRef => domRef = "%identity" + external callbackDomRef: callbackDomRef => domRef = "%identity" +} + +// Hooks + +type formStatus<'state> = { + /** If true, this means the parent
is pending submission. Otherwise, false. */ + pending: bool, + /** An object implementing the FormData interface that contains the data the parent is submitting. If there is no active submission or no parent , it will be null. */ + data: FormData.t, + /** This represents whether the parent is submitting with either a GET or POST HTTP method. By default, a will use the GET method and can be specified by the method property. */ + method: [#get | #post], + /** A reference to the function passed to the action prop on the parent . If there is no parent , the property is null. If there is a URI value provided to the action prop, or no action prop specified, status.action will be null. */ + action: React.action<'state, FormData.t>, +} + +external formAction: React.formAction => string = "%identity" + +/** `useFormStatus` is a Hook that gives you status information of the last form submission. */ +@module("react-dom") +external useFormStatus: unit => formStatus<'state> = "useFormStatus" + +// Resource Preloading APIs + +/** The CORS policy to use. */ +type crossOrigin = [ + | #anonymous + | #"use-credentials" +] + +/** The Referrer header to send when fetching. */ +type referrerPolicy = [ + | #"referrer-when-downgrade" + | #"no-referrer" + | #origin + | #"origin-when-cross-origin" + | #"unsafe-url" +] + +/** Suggests a relative priority for fetching the resource. */ +type fetchPriority = [#auto | #high | #low] + +/** `prefetchDNS` lets you eagerly look up the IP of a server that you expect to load resources from. */ +@module("react-dom") +external prefetchDNS: string => unit = "prefetchDNS" + +/** `preconnect` lets you eagerly connect to a server that you expect to load resources from. */ +@module("react-dom") +external preconnect: string => unit = "preconnect" + +type preloadOptions = { + /** The type of resource. */ + @as("as") + as_: [ + | #audio + | #document + | #embed + | #fetch + | #font + | #image + | #object + | #script + | #style + | #track + | #video + | #worker + ], + /** The CORS policy to use. It is required when as is set to "fetch". */ + crossOrigin?: crossOrigin, + /** The Referrer header to send when fetching. */ + referrerPolicy?: referrerPolicy, + /** A cryptographic hash of the resource, to verify its authenticity. */ + integrity?: string, + /** The MIME type of the resource. */ + @as("type") + type_?: string, + /** A cryptographic nonce to allow the resource when using a strict Content Security Policy. */ + nonce?: string, + /** Suggests a relative priority for fetching the resource. */ + fetchPriority?: fetchPriority, + /** For use only with as: "image". Specifies the source set of the image. */ + imageSrcSet?: string, + /** For use only with as: "image". Specifies the sizes of the image. */ + imageSizes?: string, +} + +/** `preload` lets you eagerly fetch a resource such as a stylesheet, font, or external script that you expect to use. */ +@module("react-dom") +external preload: (string, preloadOptions) => unit = "preload" + +type preloadModuleOptions = { + /** The type of resource. */ + @as("as") + as_: [#script], + /** The CORS policy to use. It is required when as is set to "fetch". */ + crossOrigin?: crossOrigin, + /** A cryptographic hash of the resource, to verify its authenticity. */ + integrity?: string, + /** A cryptographic nonce to allow the resource when using a strict Content Security Policy. */ + nonce?: string, +} + +/** `preloadModule` lets you eagerly fetch an ESM module that you expect to use. */ +@module("react-dom") +external preloadModule: (string, preloadModuleOptions) => unit = "preloadModule" + +type preinitOptions = { + /** The type of resource. */ + @as("as") + as_: [#script | #style], + /** Required with stylesheets. Says where to insert the stylesheet relative to others. Stylesheets with higher precedence can override those with lower precedence. */ + precedence?: [#reset | #low | #medium | #high], + /** The CORS policy to use. It is required when as is set to "fetch". */ + crossOrigin?: crossOrigin, + /** The Referrer header to send when fetching. */ + referrerPolicy?: referrerPolicy, + /** A cryptographic hash of the resource, to verify its authenticity. */ + integrity?: string, + nonce?: string, + /** Suggests a relative priority for fetching the resource. */ + fetchPriority?: fetchPriority, +} + +/** `preinit` lets you eagerly fetch and evaluate a stylesheet or external script. */ +@module("react-dom") +external preinit: (string, preinitOptions) => unit = "preinit" + +/** To preinit an ESM module, call the `preinitModule` function from react-dom. */ +@module("react-dom") +external preinitModule: (string, preloadModuleOptions) => unit = "preinitModule" + +// Runtime + +type domProps = JsxDOM.domProps + +@variadic @module("react") +external createElement: (string, ~props: domProps=?, array) => React.element = + "createElement" + +@variadic @module("react") +external createDOMElementVariadic: ( + string, + ~props: domProps=?, + array, +) => React.element = "createElement" + +external someElement: React.element => option = "%identity" + +@module("react/jsx-runtime") +external jsx: (string, JsxDOM.domProps) => Jsx.element = "jsx" + +@module("react/jsx-runtime") +external jsxKeyed: (string, JsxDOM.domProps, ~key: string=?, @ignore unit) => Jsx.element = "jsx" + +@module("react/jsx-runtime") +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 = ReactDOMStyle diff --git a/packages/react/src/ReactDOMServer.bs.js b/packages/react/src/ReactDOMServer.bs.js new file mode 100644 index 0000000000..d856702bfe --- /dev/null +++ b/packages/react/src/ReactDOMServer.bs.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/packages/react/src/ReactDOMServer.res b/packages/react/src/ReactDOMServer.res new file mode 100644 index 0000000000..d50ddc14fe --- /dev/null +++ b/packages/react/src/ReactDOMServer.res @@ -0,0 +1,5 @@ +@module("react-dom/server") +external renderToString: React.element => string = "renderToString" + +@module("react-dom/server") +external renderToStaticMarkup: React.element => string = "renderToStaticMarkup" diff --git a/packages/react/src/ReactDOMStatic.bs.js b/packages/react/src/ReactDOMStatic.bs.js new file mode 100644 index 0000000000..d856702bfe --- /dev/null +++ b/packages/react/src/ReactDOMStatic.bs.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/packages/react/src/ReactDOMStatic.res b/packages/react/src/ReactDOMStatic.res new file mode 100644 index 0000000000..7988fbb754 --- /dev/null +++ b/packages/react/src/ReactDOMStatic.res @@ -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, + bootstrapModules?: array, + 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 = + "prerender" + +type staticResultNode = {prelude: nodeStream} + +@module("react-dom/static") +external prerenderToNodeStream: ( + React.element, + ~options: prerenderOptions<'error>=?, +) => promise = "prerenderToNodeStream" diff --git a/packages/react/src/ReactDOMStyle.bs.js b/packages/react/src/ReactDOMStyle.bs.js new file mode 100644 index 0000000000..18702c8d1e --- /dev/null +++ b/packages/react/src/ReactDOMStyle.bs.js @@ -0,0 +1,12 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE +'use strict'; + + +function unsafeAddProp(style, key, value) { + var dict = {}; + dict[key] = value; + return Object.assign({}, style, dict); +} + +exports.unsafeAddProp = unsafeAddProp; +/* No side effect */ diff --git a/packages/react/src/ReactDOMStyle.res b/packages/react/src/ReactDOMStyle.res new file mode 100644 index 0000000000..ae68d03554 --- /dev/null +++ b/packages/react/src/ReactDOMStyle.res @@ -0,0 +1,16 @@ +type t = JsxDOMStyle.t + +/* CSS2Properties: https://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSS2Properties */ +@val +external combine: (@as(json`{}`) _, t, t) => t = "Object.assign" + +external _dictToStyle: Js.Dict.t => t = "%identity" + +let unsafeAddProp = (style, key, value) => { + let dict = Js.Dict.empty() + Js.Dict.set(dict, key, value) + combine(style, _dictToStyle(dict)) +} + +@val +external unsafeAddStyle: (@as(json`{}`) _, t, {..}) => t = "Object.assign" diff --git a/packages/react/src/ReactEvent.bs.js b/packages/react/src/ReactEvent.bs.js new file mode 100644 index 0000000000..179cde2e62 --- /dev/null +++ b/packages/react/src/ReactEvent.bs.js @@ -0,0 +1,53 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE +'use strict'; + + +var Synthetic = {}; + +var Clipboard = {}; + +var Composition = {}; + +var Keyboard = {}; + +var Focus = {}; + +var Form = {}; + +var Mouse = {}; + +var Pointer = {}; + +var $$Selection = {}; + +var $$Touch = {}; + +var UI = {}; + +var Wheel = {}; + +var Media = {}; + +var $$Image = {}; + +var $$Animation = {}; + +var Transition = {}; + +exports.Synthetic = Synthetic; +exports.Clipboard = Clipboard; +exports.Composition = Composition; +exports.Keyboard = Keyboard; +exports.Focus = Focus; +exports.Form = Form; +exports.Mouse = Mouse; +exports.Pointer = Pointer; +exports.$$Selection = $$Selection; +exports.$$Touch = $$Touch; +exports.UI = UI; +exports.Wheel = Wheel; +exports.Media = Media; +exports.$$Image = $$Image; +exports.$$Animation = $$Animation; +exports.Transition = Transition; +/* No side effect */ diff --git a/packages/react/src/ReactEvent.res b/packages/react/src/ReactEvent.res new file mode 100644 index 0000000000..2d927a1907 --- /dev/null +++ b/packages/react/src/ReactEvent.res @@ -0,0 +1,273 @@ +type synthetic<'a> = JsxEvent.synthetic<'a> + +module MakeEventWithType = ( + Type: { + type t + }, +) => { + @get external bubbles: Type.t => bool = "bubbles" + @get external cancelable: Type.t => bool = "cancelable" + @get + external currentTarget: Type.t => {..} = "currentTarget" /* Should return Dom.eventTarget */ + @get external defaultPrevented: Type.t => bool = "defaultPrevented" + @get external eventPhase: Type.t => int = "eventPhase" + @get external isTrusted: Type.t => bool = "isTrusted" + @get external nativeEvent: Type.t => {..} = "nativeEvent" /* Should return Dom.event */ + @send external preventDefault: Type.t => unit = "preventDefault" + @send + external isDefaultPrevented: Type.t => bool = "isDefaultPrevented" + @send external stopPropagation: Type.t => unit = "stopPropagation" + @send + external isPropagationStopped: Type.t => bool = "isPropagationStopped" + @get external target: Type.t => {..} = "target" /* Should return Dom.eventTarget */ + @get external timeStamp: Type.t => float = "timeStamp" + @get external type_: Type.t => string = "type" + @send external persist: Type.t => unit = "persist" +} + +module Synthetic = { + type tag = JsxEvent.Synthetic.tag + type t = synthetic + @get external bubbles: synthetic<'a> => bool = "bubbles" + @get external cancelable: synthetic<'a> => bool = "cancelable" + @get + external currentTarget: synthetic<'a> => {..} = + "currentTarget" /* Should return Dom.eventTarget */ + @get + external defaultPrevented: synthetic<'a> => bool = "defaultPrevented" + @get external eventPhase: synthetic<'a> => int = "eventPhase" + @get external isTrusted: synthetic<'a> => bool = "isTrusted" + @get + external nativeEvent: synthetic<'a> => {..} = "nativeEvent" /* Should return Dom.event */ + @send + external preventDefault: synthetic<'a> => unit = "preventDefault" + @send + external isDefaultPrevented: synthetic<'a> => bool = "isDefaultPrevented" + @send + external stopPropagation: synthetic<'a> => unit = "stopPropagation" + @send + external isPropagationStopped: synthetic<'a> => bool = "isPropagationStopped" + @get external target: synthetic<'a> => {..} = "target" /* Should return Dom.eventTarget */ + @get external timeStamp: synthetic<'a> => float = "timeStamp" + @get external type_: synthetic<'a> => string = "type" + @send external persist: synthetic<'a> => unit = "persist" +} + +/* Cast any event type to the general synthetic type. This is safe, since synthetic is more general */ +external toSyntheticEvent: synthetic<'a> => Synthetic.t = "%identity" + +module Clipboard = { + type tag = JsxEvent.Clipboard.tag + type t = synthetic + include MakeEventWithType({ + type t = t + }) + @get external clipboardData: t => {..} = "clipboardData" /* Should return Dom.dataTransfer */ +} + +module Composition = { + type tag = JsxEvent.Composition.tag + type t = synthetic + include MakeEventWithType({ + type t = t + }) + @get external data: t => string = "data" +} + +module Keyboard = { + type tag = JsxEvent.Keyboard.tag + type t = synthetic + include MakeEventWithType({ + type t = t + }) + @get external altKey: t => bool = "altKey" + @get external charCode: t => int = "charCode" + @get external code: t => string = "code" + @get external ctrlKey: t => bool = "ctrlKey" + @send + external getModifierState: (t, string) => bool = "getModifierState" + @get external key: t => string = "key" + @get external keyCode: t => int = "keyCode" + @get external locale: t => string = "locale" + @get external location: t => int = "location" + @get external metaKey: t => bool = "metaKey" + @get external repeat: t => bool = "repeat" + @get external shiftKey: t => bool = "shiftKey" + @get external which: t => int = "which" +} + +module Focus = { + type tag = JsxEvent.Focus.tag + type t = synthetic + include MakeEventWithType({ + type t = t + }) + @get @return(nullable) + external relatedTarget: t => option<{..}> = "relatedTarget" /* Should return Dom.eventTarget */ +} + +module Form = { + type tag = JsxEvent.Form.tag + type t = synthetic + include MakeEventWithType({ + type t = t + }) +} + +module Mouse = { + type tag = JsxEvent.Mouse.tag + type t = synthetic + include MakeEventWithType({ + type t = t + }) + @get external altKey: t => bool = "altKey" + @get external button: t => int = "button" + @get external buttons: t => int = "buttons" + @get external clientX: t => int = "clientX" + @get external clientY: t => int = "clientY" + @get external ctrlKey: t => bool = "ctrlKey" + @send + external getModifierState: (t, string) => bool = "getModifierState" + @get external metaKey: t => bool = "metaKey" + @get external movementX: t => int = "movementX" + @get external movementY: t => int = "movementY" + @get external pageX: t => int = "pageX" + @get external pageY: t => int = "pageY" + @get @return(nullable) + external relatedTarget: t => option<{..}> = "relatedTarget" /* Should return Dom.eventTarget */ + @get external screenX: t => int = "screenX" + @get external screenY: t => int = "screenY" + @get external shiftKey: t => bool = "shiftKey" +} + +module Pointer = { + type tag = JsxEvent.Pointer.tag + type t = synthetic + include MakeEventWithType({ + type t = t + }) + + // UIEvent + @get external detail: t => int = "detail" + @get external view: t => Dom.window = "view" /* Should return DOMAbstractView/WindowProxy */ + + // MouseEvent + @get external screenX: t => int = "screenX" + @get external screenY: t => int = "screenY" + @get external clientX: t => int = "clientX" + @get external clientY: t => int = "clientY" + @get external pageX: t => int = "pageX" + @get external pageY: t => int = "pageY" + @get external movementX: t => int = "movementX" + @get external movementY: t => int = "movementY" + + @get external ctrlKey: t => bool = "ctrlKey" + @get external shiftKey: t => bool = "shiftKey" + @get external altKey: t => bool = "altKey" + @get external metaKey: t => bool = "metaKey" + @send + external getModifierState: (t, string) => bool = "getModifierState" + + @get external button: t => int = "button" + @get external buttons: t => int = "buttons" + + @get @return(nullable) + external relatedTarget: t => option<{..}> = "relatedTarget" /* Should return Dom.eventTarget */ + + // PointerEvent + @get external pointerId: t => Dom.eventPointerId = "pointerId" + @get external width: t => float = "width" + @get external height: t => float = "height" + @get external pressure: t => float = "pressure" + @get external tangentialPressure: t => float = "tangentialPressure" + @get external tiltX: t => int = "tiltX" + @get external tiltY: t => int = "tiltY" + @get external twist: t => int = "twist" + @get external pointerType: t => string = "pointerType" + @get external isPrimary: t => bool = "isPrimary" +} + +module Selection = { + type tag = JsxEvent.Selection.tag + type t = synthetic + include MakeEventWithType({ + type t = t + }) +} + +module Touch = { + type tag = JsxEvent.Touch.tag + type t = synthetic + include MakeEventWithType({ + type t = t + }) + @get external altKey: t => bool = "altKey" + @get external changedTouches: t => {..} = "changedTouches" /* Should return Dom.touchList */ + @get external ctrlKey: t => bool = "ctrlKey" + @send + external getModifierState: (t, string) => bool = "getModifierState" + @get external metaKey: t => bool = "metaKey" + @get external shiftKey: t => bool = "shiftKey" + @get external targetTouches: t => {..} = "targetTouches" /* Should return Dom.touchList */ + @get external touches: t => {..} = "touches" /* Should return Dom.touchList */ +} + +module UI = { + type tag = JsxEvent.UI.tag + type t = synthetic + include MakeEventWithType({ + type t = t + }) + @get external detail: t => int = "detail" + @get external view: t => Dom.window = "view" /* Should return DOMAbstractView/WindowProxy */ +} + +module Wheel = { + type tag = JsxEvent.Wheel.tag + type t = synthetic + include MakeEventWithType({ + type t = t + }) + @get external deltaMode: t => int = "deltaMode" + @get external deltaX: t => float = "deltaX" + @get external deltaY: t => float = "deltaY" + @get external deltaZ: t => float = "deltaZ" +} + +module Media = { + type tag = JsxEvent.Media.tag + type t = synthetic + include MakeEventWithType({ + type t = t + }) +} + +module Image = { + type tag = JsxEvent.Image.tag + type t = synthetic + include MakeEventWithType({ + type t = t + }) +} + +module Animation = { + type tag = JsxEvent.Animation.tag + type t = synthetic + include MakeEventWithType({ + type t = t + }) + @get external animationName: t => string = "animationName" + @get external pseudoElement: t => string = "pseudoElement" + @get external elapsedTime: t => float = "elapsedTime" +} + +module Transition = { + type tag = JsxEvent.Transition.tag + type t = synthetic + include MakeEventWithType({ + type t = t + }) + @get external propertyName: t => string = "propertyName" + @get external pseudoElement: t => string = "pseudoElement" + @get external elapsedTime: t => float = "elapsedTime" +} diff --git a/packages/react/src/ReactEvent.resi b/packages/react/src/ReactEvent.resi new file mode 100644 index 0000000000..61b5d4b5db --- /dev/null +++ b/packages/react/src/ReactEvent.resi @@ -0,0 +1,472 @@ +/* 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. + + In each module, the type `t` commonly means "the type of that module" (OCaml convention). In our case, e.g. + `ReactEvent.Mouse.t` represents a ReactJS synthetic mouse event. You'd use it to type your props: + + ``` + type props = { + onClick: ReactEvent.Mouse.t => unit + }; + ``` + + All the methods and properties of a type of event are in the module, as seen below. + + Each module also has a `tag` type. You can ignore it; they're only needed by their `t` type. This way, we + get to allow a base `Synthetic` event module with generic methods. So e.g. even a mouse event (`Mouse.t`) + get to be passed to a generic handler: + + ``` + let handleClick = ({state, props}, event) => { + ReactEvent.Mouse.preventDefault(event); + ... + }; + let handleSubmit = ({state, props}, event) => { + // this handler can be triggered by either a Keyboard or a Mouse event; + // conveniently use the generic preventDefault + ReactEvent.Synthetic.preventDefault(event); + ... + }; + + let render = (_) => ; + ``` + + How to translate idioms from ReactJS: + + 1. myMouseEvent.preventDefault() -> ReactEvent.Mouse.preventDefault(myMouseEvent) + 2. myKeyboardEvent.which -> ReactEvent.Keyboard.which(myKeyboardEvent) + */ +type synthetic<'a> = JsxEvent.synthetic<'a> + +module Synthetic: { + type tag = JsxEvent.Synthetic.tag + type t = synthetic + @get external bubbles: synthetic<'a> => bool = "bubbles" + @get external cancelable: synthetic<'a> => bool = "cancelable" + @get + external currentTarget: synthetic<'a> => {..} = "currentTarget" + @get + external defaultPrevented: synthetic<'a> => bool = "defaultPrevented" + @get external eventPhase: synthetic<'a> => int = "eventPhase" + @get external isTrusted: synthetic<'a> => bool = "isTrusted" + @get + external nativeEvent: synthetic<'a> => {..} = "nativeEvent" + @send + external preventDefault: synthetic<'a> => unit = "preventDefault" + @send + external isDefaultPrevented: synthetic<'a> => bool = "isDefaultPrevented" + @send + external stopPropagation: synthetic<'a> => unit = "stopPropagation" + @send + external isPropagationStopped: synthetic<'a> => bool = "isPropagationStopped" + @get external target: synthetic<'a> => {..} = "target" + @get external timeStamp: synthetic<'a> => float = "timeStamp" + @get external type_: synthetic<'a> => string = "type" + @send external persist: synthetic<'a> => unit = "persist" +} + +/* Cast any event type to the general synthetic type. This is safe, since synthetic is more general */ +external toSyntheticEvent: synthetic<'a> => Synthetic.t = "%identity" + +module Clipboard: { + type tag = JsxEvent.Clipboard.tag + type t = synthetic + @get external bubbles: t => bool = "bubbles" + @get external cancelable: t => bool = "cancelable" + @get external currentTarget: t => {..} = "currentTarget" + @get external defaultPrevented: t => bool = "defaultPrevented" + @get external eventPhase: t => int = "eventPhase" + @get external isTrusted: t => bool = "isTrusted" + @get external nativeEvent: t => {..} = "nativeEvent" + @send external preventDefault: t => unit = "preventDefault" + @send external isDefaultPrevented: t => bool = "isDefaultPrevented" + @send external stopPropagation: t => unit = "stopPropagation" + @send external isPropagationStopped: t => bool = "isPropagationStopped" + @get external target: t => {..} = "target" + @get external timeStamp: t => float = "timeStamp" + @get external type_: t => string = "type" + @send external persist: t => unit = "persist" + @get external clipboardData: t => {..} = "clipboardData" /* Should return Dom.dataTransfer */ +} + +module Composition: { + type tag = JsxEvent.Composition.tag + type t = synthetic + @get external bubbles: t => bool = "bubbles" + @get external cancelable: t => bool = "cancelable" + @get external currentTarget: t => {..} = "currentTarget" + @get external defaultPrevented: t => bool = "defaultPrevented" + @get external eventPhase: t => int = "eventPhase" + @get external isTrusted: t => bool = "isTrusted" + @get external nativeEvent: t => {..} = "nativeEvent" + @send external preventDefault: t => unit = "preventDefault" + @send external isDefaultPrevented: t => bool = "isDefaultPrevented" + @send external stopPropagation: t => unit = "stopPropagation" + @send external isPropagationStopped: t => bool = "isPropagationStopped" + @get external target: t => {..} = "target" + @get external timeStamp: t => float = "timeStamp" + @get external type_: t => string = "type" + @send external persist: t => unit = "persist" + @get external data: t => string = "data" +} + +module Keyboard: { + type tag = JsxEvent.Keyboard.tag + type t = synthetic + @get external bubbles: t => bool = "bubbles" + @get external cancelable: t => bool = "cancelable" + @get external currentTarget: t => {..} = "currentTarget" + @get external defaultPrevented: t => bool = "defaultPrevented" + @get external eventPhase: t => int = "eventPhase" + @get external isTrusted: t => bool = "isTrusted" + @get external nativeEvent: t => {..} = "nativeEvent" + @send external preventDefault: t => unit = "preventDefault" + @send external isDefaultPrevented: t => bool = "isDefaultPrevented" + @send external stopPropagation: t => unit = "stopPropagation" + @send external isPropagationStopped: t => bool = "isPropagationStopped" + @get external target: t => {..} = "target" + @get external timeStamp: t => float = "timeStamp" + @get external type_: t => string = "type" + @send external persist: t => unit = "persist" + @get external altKey: t => bool = "altKey" + @get external charCode: t => int = "charCode" + @get external code: t => string = "code" + @get external ctrlKey: t => bool = "ctrlKey" + @send + external getModifierState: (t, string) => bool = "getModifierState" + @get external key: t => string = "key" + @get external keyCode: t => int = "keyCode" + @get external locale: t => string = "locale" + @get external location: t => int = "location" + @get external metaKey: t => bool = "metaKey" + @get external repeat: t => bool = "repeat" + @get external shiftKey: t => bool = "shiftKey" + @get external which: t => int = "which" +} + +module Focus: { + type tag = JsxEvent.Focus.tag + type t = synthetic + @get external bubbles: t => bool = "bubbles" + @get external cancelable: t => bool = "cancelable" + @get external currentTarget: t => {..} = "currentTarget" + @get external defaultPrevented: t => bool = "defaultPrevented" + @get external eventPhase: t => int = "eventPhase" + @get external isTrusted: t => bool = "isTrusted" + @get external nativeEvent: t => {..} = "nativeEvent" + @send external preventDefault: t => unit = "preventDefault" + @send external isDefaultPrevented: t => bool = "isDefaultPrevented" + @send external stopPropagation: t => unit = "stopPropagation" + @send external isPropagationStopped: t => bool = "isPropagationStopped" + @get external target: t => {..} = "target" + @get external timeStamp: t => float = "timeStamp" + @get external type_: t => string = "type" + @send external persist: t => unit = "persist" + @get @return(nullable) + external relatedTarget: t => option<{..}> = "relatedTarget" /* Should return Dom.eventTarget */ +} + +module Form: { + type tag = JsxEvent.Form.tag + type t = synthetic + @get external bubbles: t => bool = "bubbles" + @get external cancelable: t => bool = "cancelable" + @get external currentTarget: t => {..} = "currentTarget" + @get external defaultPrevented: t => bool = "defaultPrevented" + @get external eventPhase: t => int = "eventPhase" + @get external isTrusted: t => bool = "isTrusted" + @get external nativeEvent: t => {..} = "nativeEvent" + @send external preventDefault: t => unit = "preventDefault" + @send external isDefaultPrevented: t => bool = "isDefaultPrevented" + @send external stopPropagation: t => unit = "stopPropagation" + @send external isPropagationStopped: t => bool = "isPropagationStopped" + @get external target: t => {..} = "target" + @get external timeStamp: t => float = "timeStamp" + @get external type_: t => string = "type" + @send external persist: t => unit = "persist" +} + +module Mouse: { + type tag = JsxEvent.Mouse.tag + type t = synthetic + @get external bubbles: t => bool = "bubbles" + @get external cancelable: t => bool = "cancelable" + @get external currentTarget: t => {..} = "currentTarget" + @get external defaultPrevented: t => bool = "defaultPrevented" + @get external eventPhase: t => int = "eventPhase" + @get external isTrusted: t => bool = "isTrusted" + @get external nativeEvent: t => {..} = "nativeEvent" + @send external preventDefault: t => unit = "preventDefault" + @send external isDefaultPrevented: t => bool = "isDefaultPrevented" + @send external stopPropagation: t => unit = "stopPropagation" + @send external isPropagationStopped: t => bool = "isPropagationStopped" + @get external target: t => {..} = "target" + @get external timeStamp: t => float = "timeStamp" + @get external type_: t => string = "type" + @send external persist: t => unit = "persist" + @get external altKey: t => bool = "altKey" + @get external button: t => int = "button" + @get external buttons: t => int = "buttons" + @get external clientX: t => int = "clientX" + @get external clientY: t => int = "clientY" + @get external ctrlKey: t => bool = "ctrlKey" + @send + external getModifierState: (t, string) => bool = "getModifierState" + @get external metaKey: t => bool = "metaKey" + @get external movementX: t => int = "movementX" + @get external movementY: t => int = "movementY" + @get external pageX: t => int = "pageX" + @get external pageY: t => int = "pageY" + @get @return(nullable) + external relatedTarget: t => option<{..}> = "relatedTarget" /* Should return Dom.eventTarget */ + @get external screenX: t => int = "screenX" + @get external screenY: t => int = "screenY" + @get external shiftKey: t => bool = "shiftKey" +} + +module Pointer: { + type tag = JsxEvent.Pointer.tag + type t = synthetic + + // Event + @get external type_: t => string = "type" + @get external target: t => {..} = "target" + @get external currentTarget: t => {..} = "currentTarget" + + @get external eventPhase: t => int = "eventPhase" + + @send external stopPropagation: t => unit = "stopPropagation" // aka cancelBubble + @get external bubbles: t => bool = "bubbles" + @get external cancelable: t => bool = "cancelable" + @send external preventDefault: t => unit = "preventDefault" + @get external defaultPrevented: t => bool = "defaultPrevented" + + @get external isTrusted: t => bool = "isTrusted" + @get external timeStamp: t => float = "timeStamp" + + // SyntheticEvent + @get external nativeEvent: t => {..} = "nativeEvent" + @send external isDefaultPrevented: t => bool = "isDefaultPrevented" + @send external isPropagationStopped: t => bool = "isPropagationStopped" + @send external persist: t => unit = "persist" + + // UIEvent + @get external detail: t => int = "detail" + @get external view: t => Dom.window = "view" /* Should return DOMAbstractView/WindowProxy */ + + // MouseEvent + @get external screenX: t => int = "screenX" + @get external screenY: t => int = "screenY" + @get external clientX: t => int = "clientX" + @get external clientY: t => int = "clientY" + @get external pageX: t => int = "pageX" + @get external pageY: t => int = "pageY" + @get external movementX: t => int = "movementX" + @get external movementY: t => int = "movementY" + + @get external ctrlKey: t => bool = "ctrlKey" + @get external shiftKey: t => bool = "shiftKey" + @get external altKey: t => bool = "altKey" + @get external metaKey: t => bool = "metaKey" + @send + external getModifierState: (t, string) => bool = "getModifierState" + + @get external button: t => int = "button" + @get external buttons: t => int = "buttons" + + @get @return(nullable) + external relatedTarget: t => option<{..}> = "relatedTarget" /* Should return Dom.eventTarget */ + + // PointerEvent + @get external pointerId: t => Dom.eventPointerId = "pointerId" + @get external width: t => float = "width" + @get external height: t => float = "height" + @get external pressure: t => float = "pressure" + @get external tangentialPressure: t => float = "tangentialPressure" + @get external tiltX: t => int = "tiltX" + @get external tiltY: t => int = "tiltY" + @get external twist: t => int = "twist" + @get external pointerType: t => string = "pointerType" + @get external isPrimary: t => bool = "isPrimary" +} + +module Selection: { + type tag = JsxEvent.Selection.tag + type t = synthetic + @get external bubbles: t => bool = "bubbles" + @get external cancelable: t => bool = "cancelable" + @get external currentTarget: t => {..} = "currentTarget" + @get external defaultPrevented: t => bool = "defaultPrevented" + @get external eventPhase: t => int = "eventPhase" + @get external isTrusted: t => bool = "isTrusted" + @get external nativeEvent: t => {..} = "nativeEvent" + @send external preventDefault: t => unit = "preventDefault" + @send external isDefaultPrevented: t => bool = "isDefaultPrevented" + @send external stopPropagation: t => unit = "stopPropagation" + @send external isPropagationStopped: t => bool = "isPropagationStopped" + @get external target: t => {..} = "target" + @get external timeStamp: t => float = "timeStamp" + @get external type_: t => string = "type" + @send external persist: t => unit = "persist" +} + +module Touch: { + type tag = JsxEvent.Touch.tag + type t = synthetic + @get external bubbles: t => bool = "bubbles" + @get external cancelable: t => bool = "cancelable" + @get external currentTarget: t => {..} = "currentTarget" + @get external defaultPrevented: t => bool = "defaultPrevented" + @get external eventPhase: t => int = "eventPhase" + @get external isTrusted: t => bool = "isTrusted" + @get external nativeEvent: t => {..} = "nativeEvent" + @send external preventDefault: t => unit = "preventDefault" + @send external isDefaultPrevented: t => bool = "isDefaultPrevented" + @send external stopPropagation: t => unit = "stopPropagation" + @send external isPropagationStopped: t => bool = "isPropagationStopped" + @get external target: t => {..} = "target" + @get external timeStamp: t => float = "timeStamp" + @get external type_: t => string = "type" + @send external persist: t => unit = "persist" + @get external altKey: t => bool = "altKey" + @get external changedTouches: t => {..} = "changedTouches" /* Should return Dom.touchList */ + @get external ctrlKey: t => bool = "ctrlKey" + @send + external getModifierState: (t, string) => bool = "getModifierState" + @get external metaKey: t => bool = "metaKey" + @get external shiftKey: t => bool = "shiftKey" + @get external targetTouches: t => {..} = "targetTouches" /* Should return Dom.touchList */ + @get external touches: t => {..} = "touches" /* Should return Dom.touchList */ +} + +module UI: { + type tag = JsxEvent.UI.tag + type t = synthetic + @get external bubbles: t => bool = "bubbles" + @get external cancelable: t => bool = "cancelable" + @get external currentTarget: t => {..} = "currentTarget" + @get external defaultPrevented: t => bool = "defaultPrevented" + @get external eventPhase: t => int = "eventPhase" + @get external isTrusted: t => bool = "isTrusted" + @get external nativeEvent: t => {..} = "nativeEvent" + @send external preventDefault: t => unit = "preventDefault" + @send external isDefaultPrevented: t => bool = "isDefaultPrevented" + @send external stopPropagation: t => unit = "stopPropagation" + @send external isPropagationStopped: t => bool = "isPropagationStopped" + @get external target: t => {..} = "target" + @get external timeStamp: t => float = "timeStamp" + @get external type_: t => string = "type" + @send external persist: t => unit = "persist" + @get external detail: t => int = "detail" + @get external view: t => Dom.window = "view" /* Should return DOMAbstractView/WindowProxy */ +} + +module Wheel: { + type tag = JsxEvent.Wheel.tag + type t = synthetic + @get external bubbles: t => bool = "bubbles" + @get external cancelable: t => bool = "cancelable" + @get external currentTarget: t => {..} = "currentTarget" + @get external defaultPrevented: t => bool = "defaultPrevented" + @get external eventPhase: t => int = "eventPhase" + @get external isTrusted: t => bool = "isTrusted" + @get external nativeEvent: t => {..} = "nativeEvent" + @send external preventDefault: t => unit = "preventDefault" + @send external isDefaultPrevented: t => bool = "isDefaultPrevented" + @send external stopPropagation: t => unit = "stopPropagation" + @send external isPropagationStopped: t => bool = "isPropagationStopped" + @get external target: t => {..} = "target" + @get external timeStamp: t => float = "timeStamp" + @get external type_: t => string = "type" + @send external persist: t => unit = "persist" + @get external deltaMode: t => int = "deltaMode" + @get external deltaX: t => float = "deltaX" + @get external deltaY: t => float = "deltaY" + @get external deltaZ: t => float = "deltaZ" +} + +module Media: { + type tag = JsxEvent.Media.tag + type t = synthetic + @get external bubbles: t => bool = "bubbles" + @get external cancelable: t => bool = "cancelable" + @get external currentTarget: t => {..} = "currentTarget" + @get external defaultPrevented: t => bool = "defaultPrevented" + @get external eventPhase: t => int = "eventPhase" + @get external isTrusted: t => bool = "isTrusted" + @get external nativeEvent: t => {..} = "nativeEvent" + @send external preventDefault: t => unit = "preventDefault" + @send external isDefaultPrevented: t => bool = "isDefaultPrevented" + @send external stopPropagation: t => unit = "stopPropagation" + @send external isPropagationStopped: t => bool = "isPropagationStopped" + @get external target: t => {..} = "target" + @get external timeStamp: t => float = "timeStamp" + @get external type_: t => string = "type" + @send external persist: t => unit = "persist" +} + +module Image: { + type tag = JsxEvent.Image.tag + type t = synthetic + @get external bubbles: t => bool = "bubbles" + @get external cancelable: t => bool = "cancelable" + @get external currentTarget: t => {..} = "currentTarget" + @get external defaultPrevented: t => bool = "defaultPrevented" + @get external eventPhase: t => int = "eventPhase" + @get external isTrusted: t => bool = "isTrusted" + @get external nativeEvent: t => {..} = "nativeEvent" + @send external preventDefault: t => unit = "preventDefault" + @send external isDefaultPrevented: t => bool = "isDefaultPrevented" + @send external stopPropagation: t => unit = "stopPropagation" + @send external isPropagationStopped: t => bool = "isPropagationStopped" + @get external target: t => {..} = "target" + @get external timeStamp: t => float = "timeStamp" + @get external type_: t => string = "type" + @send external persist: t => unit = "persist" +} + +module Animation: { + type tag = JsxEvent.Animation.tag + type t = synthetic + @get external bubbles: t => bool = "bubbles" + @get external cancelable: t => bool = "cancelable" + @get external currentTarget: t => {..} = "currentTarget" + @get external defaultPrevented: t => bool = "defaultPrevented" + @get external eventPhase: t => int = "eventPhase" + @get external isTrusted: t => bool = "isTrusted" + @get external nativeEvent: t => {..} = "nativeEvent" + @send external preventDefault: t => unit = "preventDefault" + @send external isDefaultPrevented: t => bool = "isDefaultPrevented" + @send external stopPropagation: t => unit = "stopPropagation" + @send external isPropagationStopped: t => bool = "isPropagationStopped" + @get external target: t => {..} = "target" + @get external timeStamp: t => float = "timeStamp" + @get external type_: t => string = "type" + @send external persist: t => unit = "persist" + @get external animationName: t => string = "animationName" + @get external pseudoElement: t => string = "pseudoElement" + @get external elapsedTime: t => float = "elapsedTime" +} + +module Transition: { + type tag = JsxEvent.Transition.tag + type t = synthetic + @get external bubbles: t => bool = "bubbles" + @get external cancelable: t => bool = "cancelable" + @get external currentTarget: t => {..} = "currentTarget" + @get external defaultPrevented: t => bool = "defaultPrevented" + @get external eventPhase: t => int = "eventPhase" + @get external isTrusted: t => bool = "isTrusted" + @get external nativeEvent: t => {..} = "nativeEvent" + @send external preventDefault: t => unit = "preventDefault" + @send external isDefaultPrevented: t => bool = "isDefaultPrevented" + @send external stopPropagation: t => unit = "stopPropagation" + @send external isPropagationStopped: t => bool = "isPropagationStopped" + @get external target: t => {..} = "target" + @get external timeStamp: t => float = "timeStamp" + @get external type_: t => string = "type" + @send external persist: t => unit = "persist" + @get external propertyName: t => string = "propertyName" + @get external pseudoElement: t => string = "pseudoElement" + @get external elapsedTime: t => float = "elapsedTime" +} diff --git a/packages/react/src/ReactTestUtils.bs.js b/packages/react/src/ReactTestUtils.bs.js new file mode 100644 index 0000000000..7ddadac5a3 --- /dev/null +++ b/packages/react/src/ReactTestUtils.bs.js @@ -0,0 +1,105 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE +'use strict'; + +var Caml_option = require("rescript/lib/js/caml_option.js"); +var TestUtils = require("react-dom/test-utils"); + +function act(func) { + var reactFunc = function () { + func(); + }; + TestUtils.act(reactFunc); +} + +function actAsync(func) { + return TestUtils.act(function () { + return func(); + }); +} + +function changeWithValue(element, value) { + var $$event = { + target: { + value: value + } + }; + TestUtils.Simulate.change(element, $$event); +} + +function changeWithChecked(element, value) { + var $$event = { + target: { + checked: value + } + }; + TestUtils.Simulate.change(element, $$event); +} + +var Simulate = { + changeWithValue: changeWithValue, + changeWithChecked: changeWithChecked +}; + +function findBySelector(element, selector) { + return element.querySelector(selector); +} + +function findByAllSelector(element, selector) { + return Array.from(element.querySelectorAll(selector)); +} + +function findBySelectorAndTextContent(element, selector, content) { + return Caml_option.undefined_to_opt(Array.from(element.querySelectorAll(selector)).find(function (node) { + return node.textContent === content; + })); +} + +function findBySelectorAndPartialTextContent(element, selector, content) { + return Caml_option.undefined_to_opt(Array.from(element.querySelectorAll(selector)).find(function (node) { + return node.textContent.includes(content); + })); +} + +var DOM = { + findBySelector: findBySelector, + findByAllSelector: findByAllSelector, + findBySelectorAndTextContent: findBySelectorAndTextContent, + findBySelectorAndPartialTextContent: findBySelectorAndPartialTextContent +}; + +function prepareContainer(container, param) { + var containerElement = document.createElement("div"); + var body = document.body; + if (body !== undefined) { + Caml_option.valFromOption(body).appendChild(containerElement); + } + container.contents = Caml_option.some(containerElement); +} + +function cleanupContainer(container, param) { + var contents = container.contents; + if (contents !== undefined) { + Caml_option.valFromOption(contents).remove(); + } + container.contents = undefined; +} + +function getContainer(container) { + var contents = container.contents; + if (contents !== undefined) { + return Caml_option.valFromOption(contents); + } + throw { + RE_EXN_ID: "Not_found", + Error: new Error() + }; +} + +exports.act = act; +exports.actAsync = actAsync; +exports.Simulate = Simulate; +exports.DOM = DOM; +exports.prepareContainer = prepareContainer; +exports.cleanupContainer = cleanupContainer; +exports.getContainer = getContainer; +/* react-dom/test-utils Not a pure module */ diff --git a/packages/react/src/ReactTestUtils.res b/packages/react/src/ReactTestUtils.res new file mode 100644 index 0000000000..a6c2b5e2a3 --- /dev/null +++ b/packages/react/src/ReactTestUtils.res @@ -0,0 +1,134 @@ +type undefined = Js.undefined + +let undefined: undefined = Js.Undefined.empty + +@module("react-dom/test-utils") +external reactAct: (unit => undefined) => unit = "act" + +let act: (unit => unit) => unit = func => { + let reactFunc = () => { + func() + undefined + } + reactAct(reactFunc) +} + +@module("react-dom/test-utils") +external reactActAsync: (unit => Js.Promise.t<'a>) => Js.Promise.t = "act" + +let actAsync = func => { + let reactFunc = () => func() + reactActAsync(reactFunc) +} + +@module("react-dom/test-utils") +external isElement: 'element => bool = "isElement" + +@module("react-dom/test-utils") +external isElementOfType: ('element, React.component<'props>) => bool = "isElementOfType" + +@module("react-dom/test-utils") +external isDOMComponent: 'element => bool = "isDOMComponent" + +@module("react-dom/test-utils") +external isCompositeComponent: 'element => bool = "isCompositeComponent" + +@module("react-dom/test-utils") +external isCompositeComponentWithType: ('element, React.component<'props>) => bool = + "isCompositeComponentWithType" + +module Simulate = { + @module("react-dom/test-utils") @scope("Simulate") + external click: Dom.element => unit = "click" + @module("react-dom/test-utils") @scope("Simulate") + external clickWithEvent: (Dom.element, 'event) => unit = "click" + @module("react-dom/test-utils") @scope("Simulate") + external change: Dom.element => unit = "change" + @module("react-dom/test-utils") @scope("Simulate") + external blur: Dom.element => unit = "blur" + @module("react-dom/test-utils") @scope("Simulate") + external changeWithEvent: (Dom.element, 'event) => unit = "change" + let changeWithValue = (element, value) => { + let event = { + "target": { + "value": value, + }, + } + changeWithEvent(element, event) + } + let changeWithChecked = (element, value) => { + let event = { + "target": { + "checked": value, + }, + } + changeWithEvent(element, event) + } + @module("react-dom/test-utils") @scope("Simulate") + external canPlay: Dom.element => unit = "canPlay" + @module("react-dom/test-utils") @scope("Simulate") + external timeUpdate: Dom.element => unit = "timeUpdate" + @module("react-dom/test-utils") @scope("Simulate") + external ended: Dom.element => unit = "ended" + @module("react-dom/test-utils") @scope("Simulate") + external focus: Dom.element => unit = "focus" +} + +@val external document: Dom.document = "document" + +@send +external querySelector: (Dom.element, string) => option = "querySelector" + +@send +external querySelectorAll: (Dom.element, string) => Js.Array.array_like = + "querySelectorAll" + +@get external textContent: Dom.element => string = "textContent" +@get external body: Dom.document => option = "body" +@send +external createElement: (Dom.document, string) => Dom.element = "createElement" +@send external remove: Dom.element => unit = "remove" +@send +external appendChild: (Dom.element, Dom.element) => Dom.element = "appendChild" + +let querySelectorAll = (element, string) => Js.Array.from(querySelectorAll(element, string)) + +module DOM = { + @return(nullable) @get + external value: Dom.element => option = "value" + + let findBySelector = (element, selector) => querySelector(element, selector) + + let findByAllSelector = (element, selector) => querySelectorAll(element, selector) + + let findBySelectorAndTextContent = (element, selector, content) => + querySelectorAll(element, selector)->Js.Array2.find(node => node->textContent === content) + + let findBySelectorAndPartialTextContent = (element, selector, content) => + querySelectorAll(element, selector)->Js.Array2.find(node => + node->textContent->Js.String2.includes(content) + ) +} + +let prepareContainer = (container: ref>, ()) => { + let containerElement = document->createElement("div") + switch document->body { + | Some(body) => body->appendChild(containerElement)->ignore + | None => () + } + container := Some(containerElement) +} + +let cleanupContainer = (container: ref>, ()) => { + switch container.contents { + | Some(contents) => remove(contents) + | None => () + } + container := None +} + +let getContainer = container => + switch container.contents { + | Some(contents) => contents + | None => raise(Not_found) + } diff --git a/packages/react/src/ReactTestUtils.resi b/packages/react/src/ReactTestUtils.resi new file mode 100644 index 0000000000..79afd696e7 --- /dev/null +++ b/packages/react/src/ReactTestUtils.resi @@ -0,0 +1,56 @@ +let act: (unit => unit) => unit + +let actAsync: (unit => Js.Promise.t<'a>) => Js.Promise.t + +@module("react-dom/test-utils") +external isElement: 'element => bool = "isElement" + +@module("react-dom/test-utils") +external isElementOfType: ('element, React.component<'props>) => bool = "isElementOfType" + +@module("react-dom/test-utils") +external isDOMComponent: 'element => bool = "isDOMComponent" + +@module("react-dom/test-utils") +external isCompositeComponent: 'element => bool = "isCompositeComponent" + +@module("react-dom/test-utils") +external isCompositeComponentWithType: ('element, React.component<'props>) => bool = + "isCompositeComponentWithType" + +module Simulate: { + @module("react-dom/test-utils") @scope("Simulate") + external click: Dom.element => unit = "click" + @module("react-dom/test-utils") @scope("Simulate") + external clickWithEvent: (Dom.element, 'event) => unit = "click" + @module("react-dom/test-utils") @scope("Simulate") + external change: Dom.element => unit = "change" + @module("react-dom/test-utils") @scope("Simulate") + external blur: Dom.element => unit = "blur" + @module("react-dom/test-utils") @scope("Simulate") + external changeWithEvent: (Dom.element, 'event) => unit = "change" + let changeWithValue: (Dom.element, string) => unit + let changeWithChecked: (Dom.element, bool) => unit + @module("react-dom/test-utils") @scope("Simulate") + external canPlay: Dom.element => unit = "canPlay" + @module("react-dom/test-utils") @scope("Simulate") + external timeUpdate: Dom.element => unit = "timeUpdate" + @module("react-dom/test-utils") @scope("Simulate") + external ended: Dom.element => unit = "ended" + @module("react-dom/test-utils") @scope("Simulate") + external focus: Dom.element => unit = "focus" +} + +module DOM: { + @return(nullable) @get + external value: Dom.element => option = "value" + + let findBySelector: (Dom.element, string) => option + let findByAllSelector: (Dom.element, string) => array + let findBySelectorAndTextContent: (Dom.element, string, string) => option + let findBySelectorAndPartialTextContent: (Dom.element, string, string) => option +} + +let prepareContainer: (ref>, unit) => unit +let cleanupContainer: (ref>, unit) => unit +let getContainer: ref> => Dom.element diff --git a/packages/react/src/RescriptReactErrorBoundary.bs.js b/packages/react/src/RescriptReactErrorBoundary.bs.js new file mode 100644 index 0000000000..fe5f73e5ed --- /dev/null +++ b/packages/react/src/RescriptReactErrorBoundary.bs.js @@ -0,0 +1,33 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE +'use strict'; + +var React = require("react"); + +var noOp = (function (_x) {}); + +var reactComponentClass = React.Component; + +noOp(reactComponentClass); + +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); +; + +var make = ErrorBoundary; + +exports.make = make; +/* reactComponentClass Not a pure module */ diff --git a/packages/react/src/RescriptReactErrorBoundary.res b/packages/react/src/RescriptReactErrorBoundary.res new file mode 100644 index 0000000000..3caa0e8e17 --- /dev/null +++ b/packages/react/src/RescriptReactErrorBoundary.res @@ -0,0 +1,44 @@ +@ocaml.doc(" + * 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" diff --git a/packages/react/src/RescriptReactErrorBoundary.resi b/packages/react/src/RescriptReactErrorBoundary.resi new file mode 100644 index 0000000000..3bc8071da3 --- /dev/null +++ b/packages/react/src/RescriptReactErrorBoundary.resi @@ -0,0 +1,14 @@ +@ocaml.doc(" + * 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 diff --git a/packages/react/src/RescriptReactRouter.bs.js b/packages/react/src/RescriptReactRouter.bs.js new file mode 100644 index 0000000000..eb542b64f1 --- /dev/null +++ b/packages/react/src/RescriptReactRouter.bs.js @@ -0,0 +1,219 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE +'use strict'; + +var React = require("react"); +var Caml_option = require("rescript/lib/js/caml_option.js"); + +function safeMakeEvent(eventName) { + if (typeof Event === "function") { + return new Event(eventName); + } + var $$event = document.createEvent("Event"); + $$event.initEvent(eventName, true, true); + return $$event; +} + +function pathParse(str) { + switch (str) { + case "" : + case "/" : + return /* [] */0; + default: + var raw = str.slice(1); + var match = raw[raw.length - 1 | 0]; + var raw$1 = match === "/" ? raw.slice(0, -1) : raw; + var match$1 = raw$1.split("?", 2); + var raw$2 = match$1.length !== 2 ? raw$1 : match$1[0]; + var a = raw$2.split("/").filter(function (item) { + return item.length !== 0; + }); + var _i = a.length - 1 | 0; + var _res = /* [] */0; + while(true) { + var res = _res; + var i = _i; + if (i < 0) { + return res; + } + _res = { + hd: a[i], + tl: res + }; + _i = i - 1 | 0; + continue ; + }; + } +} + +function path(serverUrlString, param) { + var match = globalThis.window; + if (serverUrlString !== undefined) { + return pathParse(serverUrlString); + } else if (match !== undefined) { + return pathParse(Caml_option.valFromOption(match).location.pathname); + } else { + return /* [] */0; + } +} + +function hash() { + var $$window = globalThis.window; + if ($$window === undefined) { + return ""; + } + var raw = Caml_option.valFromOption($$window).location.hash; + switch (raw) { + case "" : + case "#" : + return ""; + default: + return raw.slice(1); + } +} + +function searchParse(str) { + switch (str) { + case "" : + case "?" : + return ""; + default: + var match = str.split("?", 2); + if (match.length !== 2) { + return ""; + } else { + return match[1]; + } + } +} + +function search(serverUrlString, param) { + var match = globalThis.window; + if (serverUrlString !== undefined) { + return searchParse(serverUrlString); + } else if (match !== undefined) { + return searchParse(Caml_option.valFromOption(match).location.search); + } else { + return ""; + } +} + +function push(path) { + var match = globalThis.history; + var match$1 = globalThis.window; + if (match !== undefined && match$1 !== undefined) { + Caml_option.valFromOption(match).pushState(null, "", path); + Caml_option.valFromOption(match$1).dispatchEvent(safeMakeEvent("popstate")); + return ; + } + +} + +function replace(path) { + var match = globalThis.history; + var match$1 = globalThis.window; + if (match !== undefined && match$1 !== undefined) { + Caml_option.valFromOption(match).replaceState(null, "", path); + Caml_option.valFromOption(match$1).dispatchEvent(safeMakeEvent("popstate")); + return ; + } + +} + +function urlNotEqual(a, b) { + if (a.hash !== b.hash || a.search !== b.search) { + return true; + } else { + var _aList = a.path; + var _bList = b.path; + while(true) { + var bList = _bList; + var aList = _aList; + if (!aList) { + if (bList) { + return true; + } else { + return false; + } + } + if (!bList) { + return true; + } + if (aList.hd !== bList.hd) { + return true; + } + _bList = bList.tl; + _aList = aList.tl; + continue ; + }; + } +} + +function url(serverUrlString, param) { + return { + path: path(serverUrlString, undefined), + hash: hash(), + search: search(serverUrlString, undefined) + }; +} + +function watchUrl(callback) { + var $$window = globalThis.window; + if ($$window === undefined) { + return function () { + + }; + } + var watcherID = function () { + callback(url(undefined, undefined)); + }; + Caml_option.valFromOption($$window).addEventListener("popstate", watcherID); + return watcherID; +} + +function unwatchUrl(watcherID) { + var $$window = globalThis.window; + if ($$window !== undefined) { + Caml_option.valFromOption($$window).removeEventListener("popstate", watcherID); + return ; + } + +} + +function useUrl(serverUrl, param) { + var match = React.useState(function () { + if (serverUrl !== undefined) { + return serverUrl; + } else { + return url(undefined, undefined); + } + }); + var setUrl = match[1]; + var url$1 = match[0]; + React.useEffect((function () { + var watcherId = watchUrl(function (url) { + setUrl(function (param) { + return url; + }); + }); + var newUrl = url(undefined, undefined); + if (urlNotEqual(newUrl, url$1)) { + setUrl(function (param) { + return newUrl; + }); + } + return (function () { + unwatchUrl(watcherId); + }); + }), []); + return url$1; +} + +var dangerouslyGetInitialUrl = url; + +exports.push = push; +exports.replace = replace; +exports.watchUrl = watchUrl; +exports.unwatchUrl = unwatchUrl; +exports.dangerouslyGetInitialUrl = dangerouslyGetInitialUrl; +exports.useUrl = useUrl; +/* react Not a pure module */ diff --git a/packages/react/src/RescriptReactRouter.res b/packages/react/src/RescriptReactRouter.res new file mode 100644 index 0000000000..80f3d758d8 --- /dev/null +++ b/packages/react/src/RescriptReactRouter.res @@ -0,0 +1,214 @@ +@scope("globalThis") +external window: option = "window" + +@scope("globalThis") +external history: option = "history" + +@get external location: Dom.window => Dom.location = "location" + +/* actually the cb is Dom.event => unit, but let's restrict the access for now */ +@send +external addEventListener: (Dom.window, string, unit => unit) => unit = "addEventListener" + +@send +external removeEventListener: (Dom.window, string, unit => unit) => unit = "removeEventListener" + +@send +external dispatchEvent: (Dom.window, Dom.event) => unit = "dispatchEvent" + +@get external pathname: Dom.location => string = "pathname" + +@get external hash: Dom.location => string = "hash" + +@get external search: Dom.location => string = "search" + +@send +external pushState: (Dom.history, @as(json`null`) _, @as("") _, ~href: string) => unit = "pushState" + +@send +external replaceState: (Dom.history, @as(json`null`) _, @as("") _, ~href: string) => unit = + "replaceState" + +@val external event: 'a = "Event" + +@new external makeEventIE11Compatible: string => Dom.event = "Event" + +@val @scope("document") +external createEventNonIEBrowsers: string => Dom.event = "createEvent" + +@send +external initEventNonIEBrowsers: (Dom.event, string, bool, bool) => unit = "initEvent" + +let safeMakeEvent = eventName => + if Js.typeof(event) == "function" { + makeEventIE11Compatible(eventName) + } else { + let event = createEventNonIEBrowsers("Event") + initEventNonIEBrowsers(event, eventName, true, true) + event + } + +/* This is copied from array.ml. We want to cut dependencies for rescript-react so + that it's friendlier to use in size-constrained codebases */ +let arrayToList = a => { + let rec tolist = (i, res) => + if i < 0 { + res + } else { + tolist(i - 1, list{a->Js.Array2.unsafe_get(i), ...res}) + } + tolist(a->Js.Array2.length - 1, list{}) +} +/* if we ever roll our own parser in the future, make sure you test all url combinations + e.g. foo.com/?#bar + */ +/* sigh URLSearchParams doesn't work on IE11, edge16, etc. */ +/* actually you know what, not gonna provide search for now. It's a mess. + We'll let users roll their own solution/data structure for now */ +let pathParse = str => + switch str { + | "" + | "/" => + list{} + | raw => + /* remove the preceeding /, which every pathname seems to have */ + let raw = raw->Js.String2.sliceToEnd(~from=1) + /* remove the trailing /, which some pathnames might have. Ugh */ + let raw = switch raw->Js.String2.get(raw->Js.String2.length - 1) { + | "/" => raw->Js.String2.slice(~from=0, ~to_=-1) + | _ => raw + } + /* remove search portion if present in string */ + let raw = switch raw->Js.String2.splitAtMost("?", ~limit=2) { + | [path, _] => path + | _ => raw + } + + raw->Js.String2.split("/")->Js.Array2.filter(item => item->Js.String2.length != 0)->arrayToList + } +let path = (~serverUrlString=?, ()) => + switch (serverUrlString, window) { + | (None, None) => list{} + | (Some(serverUrlString), _) => pathParse(serverUrlString) + | (_, Some(window: Dom.window)) => pathParse(window->location->pathname) + } +let hash = () => + switch window { + | None => "" + | Some(window: Dom.window) => + switch window->location->hash { + | "" + | "#" => "" + | raw => + /* remove the preceeding #, which every hash seems to have. + Why is this even included in location.hash?? */ + raw->Js.String2.sliceToEnd(~from=1) + } + } +let searchParse = str => + switch str { + | "" + | "?" => "" + | raw => + switch raw->Js.String2.splitAtMost("?", ~limit=2) { + | [_, search] => search + | _ => "" + } + } + +let search = (~serverUrlString=?, ()) => + switch (serverUrlString, window) { + | (None, None) => "" + | (Some(serverUrlString), _) => searchParse(serverUrlString) + | (_, Some(window: Dom.window)) => searchParse(window->location->search) + } + +let push = path => + switch (history, window) { + | (None, _) + | (_, None) => () + | (Some(history: Dom.history), Some(window: Dom.window)) => + pushState(history, ~href=path) + dispatchEvent(window, safeMakeEvent("popstate")) + } + +let replace = path => + switch (history, window) { + | (None, _) + | (_, None) => () + | (Some(history: Dom.history), Some(window: Dom.window)) => + replaceState(history, ~href=path) + dispatchEvent(window, safeMakeEvent("popstate")) + } + +type url = { + path: list, + hash: string, + search: string, +} + +let urlNotEqual = (a, b) => { + let rec listNotEqual = (aList, bList) => + switch (aList, bList) { + | (list{}, list{}) => false + | (list{}, list{_, ..._}) + | (list{_, ..._}, list{}) => true + | (list{aHead, ...aRest}, list{bHead, ...bRest}) => + if aHead !== bHead { + true + } else { + listNotEqual(aRest, bRest) + } + } + a.hash !== b.hash || (a.search !== b.search || listNotEqual(a.path, b.path)) +} + +type watcherID = unit => unit + +let url = (~serverUrlString=?, ()) => { + path: path(~serverUrlString?, ()), + hash: hash(), + search: search(~serverUrlString?, ()), +} + +/* alias exposed publicly */ +let dangerouslyGetInitialUrl = url + +let watchUrl = callback => + switch window { + | None => () => () + | Some(window: Dom.window) => + let watcherID = () => callback(url()) + addEventListener(window, "popstate", watcherID) + watcherID + } + +let unwatchUrl = watcherID => + switch window { + | None => () + | Some(window: Dom.window) => removeEventListener(window, "popstate", watcherID) + } + +let useUrl = (~serverUrl=?, ()) => { + let (url, setUrl) = React.useState(() => + switch serverUrl { + | Some(url) => url + | None => dangerouslyGetInitialUrl() + } + ) + + React.useEffect(() => { + let watcherId = watchUrl(url => setUrl(_ => url)) + + // check for updates that may have occured between the initial state and + // the subscribe above + let newUrl = dangerouslyGetInitialUrl() + if urlNotEqual(newUrl, url) { + setUrl(_ => newUrl) + } + + Some(() => unwatchUrl(watcherId)) + }, []) + + url +} diff --git a/packages/react/src/RescriptReactRouter.resi b/packages/react/src/RescriptReactRouter.resi new file mode 100644 index 0000000000..654235e842 --- /dev/null +++ b/packages/react/src/RescriptReactRouter.resi @@ -0,0 +1,46 @@ +@ocaml.doc( + "update the url with the string path. Example: `push(\"/book/1\")`, `push(\"/books#title\")` " +) +let push: string => unit + +@ocaml.doc( + "update the url with the string path. modifies the current history entry instead of creating a new one. Example: `replace(\"/book/1\")`, `replace(\"/books#title\")` " +) +let replace: string => unit +type watcherID +type url = { + /* path takes window.location.path, like "/book/title/edit" and turns it into `["book", "title", "edit"]` */ + path: list, + /* the url's hash, if any. The # symbol is stripped out for you */ + hash: string, + /* the url's query params, if any. The ? symbol is stripped out for you */ + search: string, +} + +@ocaml.doc( + "start watching for URL changes. Returns a subscription token. Upon url change, calls the callback and passes it the url record " +) +let watchUrl: (url => unit) => watcherID + +@ocaml.doc(" stop watching for URL changes ") +let unwatchUrl: watcherID => unit + +@ocaml.doc("this is marked as \"dangerous\" because you technically shouldn't + be accessing the URL outside of watchUrl's callback; you'd read a potentially + stale url, instead of the fresh one inside watchUrl. + + But this helper is sometimes needed, if you'd like to initialize a page + whose display/state depends on the URL, instead of reading from it in + watchUrl's callback, which you'd probably have put inside didMount (aka + too late, the page's already rendered). + + So, the correct (and idiomatic) usage of this helper is to only use it in + a component that's also subscribed to watchUrl. Please see + https://github.com/reasonml-community/reason-react-example/blob/master/src/todomvc/TodoItem.re + for an example.") +let dangerouslyGetInitialUrl: (~serverUrlString: string=?, unit) => url + +@ocaml.doc("hook for watching url changes. + * serverUrl is used for ssr. it allows you to specify the url without relying on browser apis existing/working as expected + ") +let useUrl: (~serverUrl: url=?, unit) => url From 82dcfdd7f29b2508160f7136133d3187cee9468c Mon Sep 17 00:00:00 2001 From: Christoph Knittel Date: Mon, 26 May 2025 16:37:08 +0200 Subject: [PATCH 02/14] Use @rescript/react from workspace --- analysis/examples/larger-project/package.json | 2 +- packages/playground/package.json | 2 +- packages/react/package.json | 6 +-- .../tests-reanalyze/deadcode/package.json | 2 +- tests/analysis_tests/tests/package.json | 2 +- .../typescript-react-example/package.json | 2 +- tests/tools_tests/package.json | 2 +- yarn.lock | 43 ++++++------------- 8 files changed, 21 insertions(+), 40 deletions(-) diff --git a/analysis/examples/larger-project/package.json b/analysis/examples/larger-project/package.json index 1426ee18c6..c414245957 100644 --- a/analysis/examples/larger-project/package.json +++ b/analysis/examples/larger-project/package.json @@ -14,6 +14,6 @@ }, "dependencies": { "@glennsl/bs-json": "^5.0.4", - "@rescript/react": "^0.10.3" + "@rescript/react": "workspace:^" } } diff --git a/packages/playground/package.json b/packages/playground/package.json index c36b14bd40..283f909917 100644 --- a/packages/playground/package.json +++ b/packages/playground/package.json @@ -9,7 +9,7 @@ "upload-bundle": "node scripts/upload_bundle.mjs" }, "dependencies": { - "@rescript/react": "^0.13.1", + "@rescript/react": "workspace:^", "rescript": "workspace:^" }, "devDependencies": { diff --git a/packages/react/package.json b/packages/react/package.json index 3dfa78705d..358697059f 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -27,10 +27,8 @@ "url": "git+https://github.com/rescript-lang/rescript-react.git" }, "homepage": "https://rescript-lang.org/docs/react/latest/introduction", - "devDependencies": { - "react": "^19.1.0", - "react-dom": "^19.1.0", - "rescript": "^11.0.0" + "dependencies": { + "rescript": "workspace:^" }, "peerDependencies": { "react": ">=19.0.0", diff --git a/tests/analysis_tests/tests-reanalyze/deadcode/package.json b/tests/analysis_tests/tests-reanalyze/deadcode/package.json index ec9305fdb8..a61fbc97ed 100644 --- a/tests/analysis_tests/tests-reanalyze/deadcode/package.json +++ b/tests/analysis_tests/tests-reanalyze/deadcode/package.json @@ -6,7 +6,7 @@ "clean": "rescript clean -with-deps" }, "dependencies": { - "@rescript/react": "link:../../../dependencies/rescript-react", + "@rescript/react": "workspace:^", "rescript": "workspace:^" } } diff --git a/tests/analysis_tests/tests/package.json b/tests/analysis_tests/tests/package.json index 2ada6a7cb0..fd8de6a7c1 100644 --- a/tests/analysis_tests/tests/package.json +++ b/tests/analysis_tests/tests/package.json @@ -6,7 +6,7 @@ "clean": "rescript clean -with-deps" }, "dependencies": { - "@rescript/react": "link:../../dependencies/rescript-react", + "@rescript/react": "workspace:^", "rescript": "workspace:^" } } diff --git a/tests/gentype_tests/typescript-react-example/package.json b/tests/gentype_tests/typescript-react-example/package.json index 721b4bf4ba..f752a1ba72 100644 --- a/tests/gentype_tests/typescript-react-example/package.json +++ b/tests/gentype_tests/typescript-react-example/package.json @@ -9,7 +9,7 @@ "check": "biome check --changed --no-errors-on-unmatched ." }, "dependencies": { - "@rescript/react": "^0.13.1", + "@rescript/react": "workspace:^", "react": "^18.3.1", "react-dom": "^18.3.1", "rescript": "workspace:^" diff --git a/tests/tools_tests/package.json b/tests/tools_tests/package.json index f1f0ea9a57..b8f4b43ab6 100644 --- a/tests/tools_tests/package.json +++ b/tests/tools_tests/package.json @@ -7,7 +7,7 @@ "dev": "rescript -w" }, "dependencies": { - "@rescript/react": "link:../dependencies/rescript-react", + "@rescript/react": "workspace:^", "rescript": "workspace:^" } } diff --git a/yarn.lock b/yarn.lock index a0ea540067..37310a77dd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -412,33 +412,16 @@ __metadata: languageName: unknown linkType: soft -"@rescript/react@link:../../../dependencies/rescript-react::locator=%40tests%2Freanalyze-deadcode%40workspace%3Atests%2Fanalysis_tests%2Ftests-reanalyze%2Fdeadcode": +"@rescript/react@workspace:^, @rescript/react@workspace:packages/react": version: 0.0.0-use.local - resolution: "@rescript/react@link:../../../dependencies/rescript-react::locator=%40tests%2Freanalyze-deadcode%40workspace%3Atests%2Fanalysis_tests%2Ftests-reanalyze%2Fdeadcode" - languageName: node - linkType: soft - -"@rescript/react@link:../../dependencies/rescript-react::locator=%40tests%2Fanalysis%40workspace%3Atests%2Fanalysis_tests%2Ftests": - version: 0.0.0-use.local - resolution: "@rescript/react@link:../../dependencies/rescript-react::locator=%40tests%2Fanalysis%40workspace%3Atests%2Fanalysis_tests%2Ftests" - languageName: node - linkType: soft - -"@rescript/react@link:../dependencies/rescript-react::locator=%40tests%2Ftools%40workspace%3Atests%2Ftools_tests": - version: 0.0.0-use.local - resolution: "@rescript/react@link:../dependencies/rescript-react::locator=%40tests%2Ftools%40workspace%3Atests%2Ftools_tests" - languageName: node - linkType: soft - -"@rescript/react@npm:^0.13.1": - version: 0.13.1 - resolution: "@rescript/react@npm:0.13.1" + resolution: "@rescript/react@workspace:packages/react" + dependencies: + rescript: "workspace:^" peerDependencies: - react: ">=18.0.0" - react-dom: ">=18.0.0" - checksum: 10c0/c4d04536daf7acc3f6452890665333211ad08723ecb9e9efdd66ea7bf7de6503f513d6dabad400415fcae7625740431f1c121fa3abbc4b7446b60e2e7052df32 - languageName: node - linkType: hard + react: ">=19.0.0" + react-dom: ">=19.0.0" + languageName: unknown + linkType: soft "@rescript/std@workspace:packages/std": version: 0.0.0-use.local @@ -630,7 +613,7 @@ __metadata: version: 0.0.0-use.local resolution: "@tests/analysis@workspace:tests/analysis_tests/tests" dependencies: - "@rescript/react": "link:../../dependencies/rescript-react" + "@rescript/react": "workspace:^" rescript: "workspace:^" languageName: unknown linkType: soft @@ -648,7 +631,7 @@ __metadata: resolution: "@tests/gentype-react-example@workspace:tests/gentype_tests/typescript-react-example" dependencies: "@biomejs/biome": "npm:1.9.4" - "@rescript/react": "npm:^0.13.1" + "@rescript/react": "workspace:^" "@types/react": "npm:^18.3.3" "@types/react-dom": "npm:^18.3.0" react: "npm:^18.3.1" @@ -670,7 +653,7 @@ __metadata: version: 0.0.0-use.local resolution: "@tests/reanalyze-deadcode@workspace:tests/analysis_tests/tests-reanalyze/deadcode" dependencies: - "@rescript/react": "link:../../../dependencies/rescript-react" + "@rescript/react": "workspace:^" rescript: "workspace:^" languageName: unknown linkType: soft @@ -693,7 +676,7 @@ __metadata: version: 0.0.0-use.local resolution: "@tests/tools@workspace:tests/tools_tests" dependencies: - "@rescript/react": "link:../dependencies/rescript-react" + "@rescript/react": "workspace:^" rescript: "workspace:^" languageName: unknown linkType: soft @@ -2383,7 +2366,7 @@ __metadata: version: 0.0.0-use.local resolution: "playground@workspace:packages/playground" dependencies: - "@rescript/react": "npm:^0.13.1" + "@rescript/react": "workspace:^" "@rollup/plugin-node-resolve": "npm:^16.0.0" glob: "npm:^11.0.1" rescript: "workspace:^" From 6beb42077ec40a27c781814b44b923fcd1d0481c Mon Sep 17 00:00:00 2001 From: Christoph Knittel Date: Mon, 26 May 2025 16:43:22 +0200 Subject: [PATCH 03/14] React.Ref.t -> React.ref --- tests/gentype_tests/typescript-react-example/src/Hooks.res | 2 +- .../data/idempotency/reason-react/src/ReactDOMRe.res | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/gentype_tests/typescript-react-example/src/Hooks.res b/tests/gentype_tests/typescript-react-example/src/Hooks.res index 5468269e3a..a324e9d015 100644 --- a/tests/gentype_tests/typescript-react-example/src/Hooks.res +++ b/tests/gentype_tests/typescript-react-example/src/Hooks.res @@ -103,7 +103,7 @@ module ForwardRef = { @genType type testReactContext = React.Context.t -@genType type testReactRef = React.Ref.t +@genType type testReactRef = React.ref @genType type testDomRef = ReactDOM.domRef diff --git a/tests/syntax_tests/data/idempotency/reason-react/src/ReactDOMRe.res b/tests/syntax_tests/data/idempotency/reason-react/src/ReactDOMRe.res index 49b21613c0..2c4bd1d936 100644 --- a/tests/syntax_tests/data/idempotency/reason-react/src/ReactDOMRe.res +++ b/tests/syntax_tests/data/idempotency/reason-react/src/ReactDOMRe.res @@ -81,7 +81,7 @@ type domRef module Ref = { type t = domRef - type currentDomRef = React.Ref.t> + type currentDomRef = React.ref> type callbackDomRef = Js.nullable => unit external domRef: currentDomRef => domRef = "%identity" From 6531bab458efc5a8bc59cec8e929bffe48ddcbfc Mon Sep 17 00:00:00 2001 From: Christoph Knittel Date: Mon, 26 May 2025 16:46:23 +0200 Subject: [PATCH 04/14] Analysis test output changes --- .../expected/CompletionExpressions.res.txt | 4 +- .../expected/CompletionInferValues.res.txt | 57 ++----------------- .../tests/src/expected/CompletionJsx.res.txt | 10 +--- .../src/expected/CompletionJsxProps.res.txt | 27 +-------- .../src/expected/CompletionPipeChain.res.txt | 22 +------ .../tests/src/expected/Div.res.txt | 10 +--- .../tests/src/expected/Fragment.res.txt | 2 +- .../tests/src/expected/Hover.res.txt | 2 +- .../tests/src/expected/Jsx2.res.txt | 20 +------ .../tests/src/expected/Jsx2.resi.txt | 16 +----- .../tests/src/expected/JsxV4.res.txt | 2 +- 11 files changed, 21 insertions(+), 151 deletions(-) diff --git a/tests/analysis_tests/tests/src/expected/CompletionExpressions.res.txt b/tests/analysis_tests/tests/src/expected/CompletionExpressions.res.txt index bfea51f5fc..aadc323691 100644 --- a/tests/analysis_tests/tests/src/expected/CompletionExpressions.res.txt +++ b/tests/analysis_tests/tests/src/expected/CompletionExpressions.res.txt @@ -865,13 +865,13 @@ ContextPath CArgument Value[fnTakingCallback]($2) ContextPath Value[fnTakingCallback] Path fnTakingCallback [{ - "label": "event => event", + "label": "mouse => mouse", "kind": 12, "tags": [], "detail": "ReactEvent.Mouse.t => unit", "documentation": null, "sortText": "A", - "insertText": "${1:event} => ${0:event}", + "insertText": "${1:mouse} => ${0:mouse}", "insertTextFormat": 2 }] diff --git a/tests/analysis_tests/tests/src/expected/CompletionInferValues.res.txt b/tests/analysis_tests/tests/src/expected/CompletionInferValues.res.txt index d9fe7877f9..2c46bcb49c 100644 --- a/tests/analysis_tests/tests/src/expected/CompletionInferValues.res.txt +++ b/tests/analysis_tests/tests/src/expected/CompletionInferValues.res.txt @@ -250,16 +250,7 @@ ContextPath CArgument CArgument Value[reactEventFn]($0)($0) ContextPath CArgument Value[reactEventFn]($0) ContextPath Value[reactEventFn] Path reactEventFn -CPPipe pathFromEnv:ReactEvent.Mouse found:false -Path ReactEvent.Mouse.pr -Path pr -[{ - "label": "ReactEvent.Mouse.preventDefault", - "kind": 12, - "tags": [], - "detail": "t => unit", - "documentation": null - }] +[] Complete src/CompletionInferValues.res 41:50 posCursor:[41:50] posNoWhite:[41:49] Found expr:[41:11->41:56] @@ -275,17 +266,7 @@ Path event ContextPath CArgument CJsxPropValue [div] onMouseEnter($0) ContextPath CJsxPropValue [div] onMouseEnter Path ReactDOM.domProps -Path JsxDOM.domProps -CPPipe pathFromEnv:JsxEvent.Mouse found:false -Path JsxEvent.Mouse.pr -Path pr -[{ - "label": "JsxEvent.Mouse.preventDefault", - "kind": 12, - "tags": [], - "detail": "t => unit", - "documentation": null - }] +[] Complete src/CompletionInferValues.res 44:50 posCursor:[44:50] posNoWhite:[44:49] Found expr:[44:11->44:56] @@ -832,22 +813,7 @@ ContextPath CArgument CArgument Value[fn2](~cb)($0) ContextPath CArgument Value[fn2](~cb) ContextPath Value[fn2] Path fn2 -CPPipe pathFromEnv:ReactDOM.Client.Root found:false -Path ReactDOM.Client.Root. -Path -[{ - "label": "ReactDOM.Client.Root.unmount", - "kind": 12, - "tags": [], - "detail": "(t, unit) => unit", - "documentation": null - }, { - "label": "ReactDOM.Client.Root.render", - "kind": 12, - "tags": [], - "detail": "(t, React.element) => unit", - "documentation": null - }] +[] Complete src/CompletionInferValues.res 139:30 posCursor:[139:30] posNoWhite:[139:29] Found expr:[139:3->139:33] @@ -974,22 +940,7 @@ ContextPath CArgument CArgument Value[CompletionSupport2, makeRenderer](~render) ContextPath CArgument Value[CompletionSupport2, makeRenderer](~render) ContextPath Value[CompletionSupport2, makeRenderer] Path CompletionSupport2.makeRenderer -CPPipe pathFromEnv:ReactDOM.Client.Root found:false -Path ReactDOM.Client.Root. -Path -[{ - "label": "ReactDOM.Client.Root.unmount", - "kind": 12, - "tags": [], - "detail": "(t, unit) => unit", - "documentation": null - }, { - "label": "ReactDOM.Client.Root.render", - "kind": 12, - "tags": [], - "detail": "(t, React.element) => unit", - "documentation": null - }] +[] Hover src/CompletionInferValues.res 160:27 Nothing at that position. Now trying to use completion. diff --git a/tests/analysis_tests/tests/src/expected/CompletionJsx.res.txt b/tests/analysis_tests/tests/src/expected/CompletionJsx.res.txt index ed71ec31d9..61b261707e 100644 --- a/tests/analysis_tests/tests/src/expected/CompletionJsx.res.txt +++ b/tests/analysis_tests/tests/src/expected/CompletionJsx.res.txt @@ -629,14 +629,8 @@ Completable: Cjsx([h1], hidd, [hidd]) Package opens Stdlib.place holder Pervasives.JsxModules.place holder Resolved opens 1 Stdlib Path ReactDOM.domProps -Path JsxDOM.domProps -[{ - "label": "hidden", - "kind": 4, - "tags": [], - "detail": "bool", - "documentation": null - }] +[completing-lowercase-jsx] could not find element props to complete from. +[] Complete src/CompletionJsx.res 61:30 posCursor:[61:30] posNoWhite:[61:28] Found expr:[61:3->61:29] diff --git a/tests/analysis_tests/tests/src/expected/CompletionJsxProps.res.txt b/tests/analysis_tests/tests/src/expected/CompletionJsxProps.res.txt index 686f4f5ec9..8d83639661 100644 --- a/tests/analysis_tests/tests/src/expected/CompletionJsxProps.res.txt +++ b/tests/analysis_tests/tests/src/expected/CompletionJsxProps.res.txt @@ -223,20 +223,7 @@ Package opens Stdlib.place holder Pervasives.JsxModules.place holder Resolved opens 1 Stdlib ContextPath CJsxPropValue [div] muted Path ReactDOM.domProps -Path JsxDOM.domProps -[{ - "label": "true", - "kind": 4, - "tags": [], - "detail": "bool", - "documentation": null - }, { - "label": "false", - "kind": 4, - "tags": [], - "detail": "bool", - "documentation": null - }] +[] Complete src/CompletionJsxProps.res 18:29 posCursor:[18:29] posNoWhite:[18:28] Found expr:[18:11->18:32] @@ -246,17 +233,7 @@ Package opens Stdlib.place holder Pervasives.JsxModules.place holder Resolved opens 1 Stdlib ContextPath CJsxPropValue [div] onMouseEnter Path ReactDOM.domProps -Path JsxDOM.domProps -[{ - "label": "event => event", - "kind": 12, - "tags": [], - "detail": "JsxEvent.Mouse.t => unit", - "documentation": null, - "sortText": "A", - "insertText": "{${1:event} => ${0:event}}", - "insertTextFormat": 2 - }] +[] Complete src/CompletionJsxProps.res 22:52 posCursor:[22:52] posNoWhite:[22:51] Found expr:[22:11->22:52] diff --git a/tests/analysis_tests/tests/src/expected/CompletionPipeChain.res.txt b/tests/analysis_tests/tests/src/expected/CompletionPipeChain.res.txt index dcf268e218..8dae38a68c 100644 --- a/tests/analysis_tests/tests/src/expected/CompletionPipeChain.res.txt +++ b/tests/analysis_tests/tests/src/expected/CompletionPipeChain.res.txt @@ -470,16 +470,7 @@ Path support CPPipe pathFromEnv:CompletionSupport.Nested found:false Path CompletionSupport.Nested.root Path root -CPPipe pathFromEnv:ReactDOM.Client.Root found:false -Path ReactDOM.Client.Root.ren -Path ren -[{ - "label": "ReactDOM.Client.Root.render", - "kind": 12, - "tags": [], - "detail": "(t, React.element) => unit", - "documentation": null - }] +[] Complete src/CompletionPipeChain.res 88:16 posCursor:[88:16] posNoWhite:[88:15] Found expr:[76:15->93:1] @@ -496,16 +487,7 @@ Resolved opens 1 Stdlib ContextPath Value[root]->ren ContextPath Value[root] Path root -CPPipe pathFromEnv:ReactDOM.Client.Root found:false -Path ReactDOM.Client.Root.ren -Path ren -[{ - "label": "ReactDOM.Client.Root.render", - "kind": 12, - "tags": [], - "detail": "(t, React.element) => unit", - "documentation": null - }] +[] Complete src/CompletionPipeChain.res 95:20 posCursor:[95:20] posNoWhite:[95:19] Found expr:[95:3->95:21] diff --git a/tests/analysis_tests/tests/src/expected/Div.res.txt b/tests/analysis_tests/tests/src/expected/Div.res.txt index deb951ada8..966984d6bc 100644 --- a/tests/analysis_tests/tests/src/expected/Div.res.txt +++ b/tests/analysis_tests/tests/src/expected/Div.res.txt @@ -8,12 +8,6 @@ Completable: Cjsx([div], dangerous, [dangerous]) Package opens Stdlib.place holder Pervasives.JsxModules.place holder Resolved opens 1 Stdlib Path ReactDOM.domProps -Path JsxDOM.domProps -[{ - "label": "dangerouslySetInnerHTML", - "kind": 4, - "tags": [], - "detail": "{\"__html\": string}", - "documentation": null - }] +[completing-lowercase-jsx] could not find element props to complete from. +[] diff --git a/tests/analysis_tests/tests/src/expected/Fragment.res.txt b/tests/analysis_tests/tests/src/expected/Fragment.res.txt index 2dba106a7d..46261004a3 100644 --- a/tests/analysis_tests/tests/src/expected/Fragment.res.txt +++ b/tests/analysis_tests/tests/src/expected/Fragment.res.txt @@ -1,5 +1,5 @@ Hover src/Fragment.res 6:19 -{"contents": {"kind": "markdown", "value": "```rescript\nReact.component>\n```\n\n---\n\n```\n \n```\n```rescript\ntype React.component<'props> = Jsx.component<'props>\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22React.res%22%2C12%2C0%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype SectionHeader.props<'children> = {children: 'children}\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22Fragment.res%22%2C1%2C2%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype React.element = Jsx.element\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22React.res%22%2C0%2C0%5D)\n"}} +{"contents": {"kind": "markdown", "value": "```rescript\nReact.component>\n```\n\n---\n\n```\n \n```\n```rescript\ntype SectionHeader.props<'children> = {children: 'children}\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22Fragment.res%22%2C1%2C2%5D)\n"}} Hover src/Fragment.res 9:56 Nothing at that position. Now trying to use completion. diff --git a/tests/analysis_tests/tests/src/expected/Hover.res.txt b/tests/analysis_tests/tests/src/expected/Hover.res.txt index b31b9aa14c..db758b2e97 100644 --- a/tests/analysis_tests/tests/src/expected/Hover.res.txt +++ b/tests/analysis_tests/tests/src/expected/Hover.res.txt @@ -253,7 +253,7 @@ Path }] Hover src/Hover.res 197:4 -{"contents": {"kind": "markdown", "value": "```rescript\nCompV4.props => React.element\n```\n\n---\n\n```\n \n```\n```rescript\ntype CompV4.props<'n, 's> = {n?: 'n, s: 's}\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22Hover.res%22%2C190%2C2%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype React.element = Jsx.element\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22React.res%22%2C0%2C0%5D)\n"}} +{"contents": {"kind": "markdown", "value": "```rescript\nCompV4.props => React.element\n```\n\n---\n\n```\n \n```\n```rescript\ntype CompV4.props<'n, 's> = {n?: 'n, s: 's}\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22Hover.res%22%2C190%2C2%5D)\n"}} Hover src/Hover.res 202:16 {"contents": {"kind": "markdown", "value": "```rescript\nuseR\n```\n\n---\n\n```\n \n```\n```rescript\ntype useR = {x: int, y: list>>}\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22Hover.res%22%2C200%2C0%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype r<'a> = {i: 'a, f: float}\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22Hover.res%22%2C101%2C0%5D)\n"}} diff --git a/tests/analysis_tests/tests/src/expected/Jsx2.res.txt b/tests/analysis_tests/tests/src/expected/Jsx2.res.txt index 66920cb633..5f60fdf6ea 100644 --- a/tests/analysis_tests/tests/src/expected/Jsx2.res.txt +++ b/tests/analysis_tests/tests/src/expected/Jsx2.res.txt @@ -356,13 +356,7 @@ Package opens Stdlib.place holder Pervasives.JsxModules.place holder Resolved opens 1 Stdlib ContextPath Type[React, e] Path React.e -[{ - "label": "element", - "kind": 22, - "tags": [], - "detail": "type element", - "documentation": {"kind": "markdown", "value": "```rescript\ntype element = Jsx.element\n```"} - }] +[] Complete src/Jsx2.res 96:20 posCursor:[96:20] posNoWhite:[96:19] Found pattern:[96:7->99:6] @@ -472,17 +466,7 @@ Package opens Stdlib.place holder Pervasives.JsxModules.place holder Resolved opens 1 Stdlib ContextPath CJsxPropValue [div] x Path ReactDOM.domProps -Path JsxDOM.domProps -[{ - "label": "\"\"", - "kind": 12, - "tags": [], - "detail": "string", - "documentation": null, - "sortText": "A", - "insertText": "{\"$0\"}", - "insertTextFormat": 2 - }] +[] Complete src/Jsx2.res 150:21 posCursor:[150:21] posNoWhite:[150:20] Found expr:[150:11->150:32] diff --git a/tests/analysis_tests/tests/src/expected/Jsx2.resi.txt b/tests/analysis_tests/tests/src/expected/Jsx2.resi.txt index c34ab6fca5..c70c9688c4 100644 --- a/tests/analysis_tests/tests/src/expected/Jsx2.resi.txt +++ b/tests/analysis_tests/tests/src/expected/Jsx2.resi.txt @@ -12,13 +12,7 @@ Package opens Stdlib.place holder Pervasives.JsxModules.place holder Resolved opens 1 Stdlib ContextPath Type[React, e] Path React.e -[{ - "label": "element", - "kind": 22, - "tags": [], - "detail": "type element", - "documentation": {"kind": "markdown", "value": "```rescript\ntype element = Jsx.element\n```"} - }] +[] Complete src/Jsx2.resi 10:18 posCursor:[10:18] posNoWhite:[10:17] Found type:[10:11->10:18] @@ -28,11 +22,5 @@ Package opens Stdlib.place holder Pervasives.JsxModules.place holder Resolved opens 1 Stdlib ContextPath Type[React, e] Path React.e -[{ - "label": "element", - "kind": 22, - "tags": [], - "detail": "type element", - "documentation": {"kind": "markdown", "value": "```rescript\ntype element = Jsx.element\n```"} - }] +[] diff --git a/tests/analysis_tests/tests/src/expected/JsxV4.res.txt b/tests/analysis_tests/tests/src/expected/JsxV4.res.txt index ba54c5d047..0319c267b3 100644 --- a/tests/analysis_tests/tests/src/expected/JsxV4.res.txt +++ b/tests/analysis_tests/tests/src/expected/JsxV4.res.txt @@ -17,7 +17,7 @@ Path M4.make }] Hover src/JsxV4.res 14:9 -{"contents": {"kind": "markdown", "value": "```rescript\nReact.component>\n```\n\n---\n\n```\n \n```\n```rescript\ntype React.component<'props> = Jsx.component<'props>\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22React.res%22%2C12%2C0%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype M4.props<'first, 'fun, 'second> = {\n first: 'first,\n fun?: 'fun,\n second?: 'second,\n}\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22JsxV4.res%22%2C3%2C2%5D)\n\n---\n Doc Comment For M4 "}} +{"contents": {"kind": "markdown", "value": "```rescript\nReact.component>\n```\n\n---\n\n```\n \n```\n```rescript\ntype M4.props<'first, 'fun, 'second> = {\n first: 'first,\n fun?: 'fun,\n second?: 'second,\n}\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22JsxV4.res%22%2C3%2C2%5D)\n\n---\n Doc Comment For M4 "}} Create Interface src/JsxV4.res module M4: { From 3bb883d9f04c227fe964b6cd729ffc6ac650a10d Mon Sep 17 00:00:00 2001 From: Christoph Knittel Date: Mon, 26 May 2025 16:49:37 +0200 Subject: [PATCH 05/14] Remove tests/dependencies/rescript-react --- package.json | 1 - tests/dependencies/.gitattributes | 1 - tests/dependencies/.gitignore | 1 - .../dependencies/rescript-react/package.json | 4 - .../dependencies/rescript-react/rescript.json | 10 - .../dependencies/rescript-react/src/React.res | 407 --------------- .../rescript-react/src/ReactDOM.res | 73 --- .../rescript-react/src/ReactDOMStyle.res | 16 - .../rescript-react/src/ReactEvent.res | 243 --------- .../rescript-react/src/ReactEvent.resi | 472 ------------------ yarn.lock | 6 - 11 files changed, 1234 deletions(-) delete mode 100644 tests/dependencies/.gitattributes delete mode 100644 tests/dependencies/.gitignore delete mode 100644 tests/dependencies/rescript-react/package.json delete mode 100644 tests/dependencies/rescript-react/rescript.json delete mode 100644 tests/dependencies/rescript-react/src/React.res delete mode 100644 tests/dependencies/rescript-react/src/ReactDOM.res delete mode 100644 tests/dependencies/rescript-react/src/ReactDOMStyle.res delete mode 100644 tests/dependencies/rescript-react/src/ReactEvent.res delete mode 100644 tests/dependencies/rescript-react/src/ReactEvent.resi diff --git a/package.json b/package.json index a246219042..08c7a1ef0b 100644 --- a/package.json +++ b/package.json @@ -94,7 +94,6 @@ "workspaces": [ "packages/*", "packages/@rescript/*", - "tests/dependencies/**", "tests/analysis_tests/**", "tests/gentype_tests/**", "tests/tools_tests" diff --git a/tests/dependencies/.gitattributes b/tests/dependencies/.gitattributes deleted file mode 100644 index 36eaad9fbd..0000000000 --- a/tests/dependencies/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -* linguist-vendored diff --git a/tests/dependencies/.gitignore b/tests/dependencies/.gitignore deleted file mode 100644 index 521ebedd3d..0000000000 --- a/tests/dependencies/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.res.js diff --git a/tests/dependencies/rescript-react/package.json b/tests/dependencies/rescript-react/package.json deleted file mode 100644 index cd0136bdd3..0000000000 --- a/tests/dependencies/rescript-react/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "@tests/rescript-react", - "private": true -} diff --git a/tests/dependencies/rescript-react/rescript.json b/tests/dependencies/rescript-react/rescript.json deleted file mode 100644 index e1339a2b05..0000000000 --- a/tests/dependencies/rescript-react/rescript.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "@rescript/react", - "jsx": { - "version": 4, - "mode": "classic" - }, - "sources": { "dir": "src", "subdirs": true }, - "package-specs": { "module": "commonjs", "in-source": true }, - "suffix": ".res.js" -} diff --git a/tests/dependencies/rescript-react/src/React.res b/tests/dependencies/rescript-react/src/React.res deleted file mode 100644 index 0beaa59080..0000000000 --- a/tests/dependencies/rescript-react/src/React.res +++ /dev/null @@ -1,407 +0,0 @@ -type element = Jsx.element - -@val external null: element = "null" - -external float: float => element = "%identity" -external int: int => element = "%identity" -external string: string => element = "%identity" - -external array: array => element = "%identity" - -type componentLike<'props, 'return> = Jsx.componentLike<'props, 'return> - -type component<'props> = Jsx.component<'props> - -external component: componentLike<'props, element> => component<'props> = "%identity" - -@module("react") -external createElement: (component<'props>, 'props) => element = "createElement" - -@module("react") -external cloneElement: (element, 'props) => element = "cloneElement" - -@module("react") -external isValidElement: 'a => bool = "isValidElement" - -@variadic @module("react") -external createElementVariadic: (component<'props>, 'props, array) => element = - "createElement" - -@module("react/jsx-runtime") -external jsx: (component<'props>, 'props) => element = "jsx" - -@module("react/jsx-runtime") -external jsxKeyed: (component<'props>, 'props, ~key: string=?, @ignore unit) => element = "jsx" - -@module("react/jsx-runtime") -external jsxs: (component<'props>, 'props) => element = "jsxs" - -@module("react/jsx-runtime") -external jsxsKeyed: (component<'props>, 'props, ~key: string=?, @ignore unit) => element = "jsxs" - -type fragmentProps = {children?: element} - -@module("react/jsx-runtime") external jsxFragment: component = "Fragment" - -type ref<'value> = {mutable current: 'value} - -@module("react") -external createRef: unit => ref> = "createRef" - -module Children = { - @module("react") @scope("Children") - external map: (element, element => element) => element = "map" - @module("react") @scope("Children") - external mapWithIndex: (element, (element, int) => element) => element = "map" - @module("react") @scope("Children") - external forEach: (element, element => unit) => unit = "forEach" - @module("react") @scope("Children") - external forEachWithIndex: (element, (element, int) => unit) => unit = "forEach" - @module("react") @scope("Children") - external count: element => int = "count" - @module("react") @scope("Children") - external only: element => element = "only" - @module("react") @scope("Children") - external toArray: element => array = "toArray" -} - -module Context = { - type t<'context> - - type props<'context> = { - value: 'context, - children: element, - } - - @get - external provider: t<'context> => component> = "Provider" -} - -@module("react") -external createContext: 'a => Context.t<'a> = "createContext" - -@module("react") -external forwardRef: (('props, Js.Nullable.t>) => element) => component<'props> = - "forwardRef" - -@module("react") -external memo: component<'props> => component<'props> = "memo" - -@module("react") -external memoCustomCompareProps: ( - component<'props>, - ('props, 'props) => bool, -) => component<'props> = "memo" - -@module("react") external fragment: component = "Fragment" - -module Fragment = { - type props = {key?: string, children: element} - - @module("react") - external make: component = "Fragment" -} - -module StrictMode = { - type props = {key?: string, children: element} - - @module("react") - external make: component = "StrictMode" -} - -module Suspense = { - type props = {key?: string, children?: element, fallback?: element} - - @module("react") - external make: component = "Suspense" -} - -type dynamicallyImportedModule<'a> = {default: component<'a>} - -@module("react") -external lazy_: (unit => promise>) => component<'a> = "lazy" - -let lazy_ = load => lazy_(async () => {default: await load()}) - -/* HOOKS */ - -/* - * Yeah, we know this api isn't great. tl;dr: useReducer instead. - * It's because useState can take functions or non-function values and treats - * them differently. Lazy initializer + callback which returns state is the - * only way to safely have any type of state and be able to update it correctly. - */ -@module("react") -external useState: (unit => 'state) => ('state, ('state => 'state) => unit) = "useState" - -@module("react") -external useReducer: (('state, 'action) => 'state, 'state) => ('state, 'action => unit) = - "useReducer" - -@module("react") -external useReducerWithMapState: ( - ('state, 'action) => 'state, - 'initialState, - 'initialState => 'state, -) => ('state, 'action => unit) = "useReducer" - -@module("react") -external useEffectOnEveryRender: (unit => option unit>) => unit = "useEffect" -@module("react") -external useEffect: (unit => option unit>, 'deps) => unit = "useEffect" -@module("react") -external useEffect0: (unit => option unit>, @as(json`[]`) _) => unit = "useEffect" -@module("react") -external useEffect1: (unit => option unit>, array<'a>) => unit = "useEffect" -@module("react") -external useEffect2: (unit => option unit>, ('a, 'b)) => unit = "useEffect" -@module("react") -external useEffect3: (unit => option unit>, ('a, 'b, 'c)) => unit = "useEffect" -@module("react") -external useEffect4: (unit => option unit>, ('a, 'b, 'c, 'd)) => unit = "useEffect" -@module("react") -external useEffect5: (unit => option unit>, ('a, 'b, 'c, 'd, 'e)) => unit = "useEffect" -@module("react") -external useEffect6: (unit => option unit>, ('a, 'b, 'c, 'd, 'e, 'f)) => unit = "useEffect" -@module("react") -external useEffect7: (unit => option unit>, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => unit = - "useEffect" - -@module("react") -external useLayoutEffectOnEveryRender: (unit => option unit>) => unit = "useLayoutEffect" -@module("react") -external useLayoutEffect: (unit => option unit>, 'deps) => unit = "useLayoutEffect" -@module("react") -external useLayoutEffect0: (unit => option unit>, @as(json`[]`) _) => unit = - "useLayoutEffect" -@module("react") -external useLayoutEffect1: (unit => option unit>, array<'a>) => unit = "useLayoutEffect" -@module("react") -external useLayoutEffect2: (unit => option unit>, ('a, 'b)) => unit = "useLayoutEffect" -@module("react") -external useLayoutEffect3: (unit => option unit>, ('a, 'b, 'c)) => unit = "useLayoutEffect" -@module("react") -external useLayoutEffect4: (unit => option unit>, ('a, 'b, 'c, 'd)) => unit = - "useLayoutEffect" -@module("react") -external useLayoutEffect5: (unit => option unit>, ('a, 'b, 'c, 'd, 'e)) => unit = - "useLayoutEffect" -@module("react") -external useLayoutEffect6: (unit => option unit>, ('a, 'b, 'c, 'd, 'e, 'f)) => unit = - "useLayoutEffect" -@module("react") -external useLayoutEffect7: (unit => option unit>, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => unit = - "useLayoutEffect" - -@module("react") -external useMemo: (unit => 'any, 'deps) => 'any = "useMemo" - -@module("react") -external useMemo0: (unit => 'any, @as(json`[]`) _) => 'any = "useMemo" - -@module("react") -external useMemo1: (unit => 'any, array<'a>) => 'any = "useMemo" - -@module("react") -external useMemo2: (unit => 'any, ('a, 'b)) => 'any = "useMemo" - -@module("react") -external useMemo3: (unit => 'any, ('a, 'b, 'c)) => 'any = "useMemo" - -@module("react") -external useMemo4: (unit => 'any, ('a, 'b, 'c, 'd)) => 'any = "useMemo" - -@module("react") -external useMemo5: (unit => 'any, ('a, 'b, 'c, 'd, 'e)) => 'any = "useMemo" - -@module("react") -external useMemo6: (unit => 'any, ('a, 'b, 'c, 'd, 'e, 'f)) => 'any = "useMemo" - -@module("react") -external useMemo7: (unit => 'any, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => 'any = "useMemo" - -@module("react") -external useCallback: ('f, 'deps) => 'f = "useCallback" - -@module("react") -external useCallback0: ('f, @as(json`[]`) _) => 'f = "useCallback" - -@module("react") -external useCallback1: ('f, array<'a>) => 'f = "useCallback" - -@module("react") -external useCallback2: ('f, ('a, 'b)) => 'f = "useCallback" - -@module("react") -external useCallback3: ('f, ('a, 'b, 'c)) => 'f = "useCallback" - -@module("react") -external useCallback4: ('f, ('a, 'b, 'c, 'd)) => 'f = "useCallback" - -@module("react") -external useCallback5: ('f, ('a, 'b, 'c, 'd, 'e)) => 'f = "useCallback" - -@module("react") -external useCallback6: ('callback, ('a, 'b, 'c, 'd, 'e, 'f)) => 'callback = "useCallback" - -@module("react") -external useCallback7: ('callback, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => 'callback = "useCallback" - -@module("react") -external useContext: Context.t<'any> => 'any = "useContext" - -@module("react") external useRef: 'value => ref<'value> = "useRef" - -@module("react") -external useImperativeHandleOnEveryRender: (Js.Nullable.t>, unit => 'value) => unit = - "useImperativeHandle" - -@module("react") -external useImperativeHandle: (Js.Nullable.t>, unit => 'value, 'deps) => unit = - "useImperativeHandle" - -@module("react") -external useImperativeHandle0: ( - Js.Nullable.t>, - unit => 'value, - @as(json`[]`) _, -) => unit = "useImperativeHandle" - -@module("react") -external useImperativeHandle1: (Js.Nullable.t>, unit => 'value, array<'a>) => unit = - "useImperativeHandle" - -@module("react") -external useImperativeHandle2: (Js.Nullable.t>, unit => 'value, ('a, 'b)) => unit = - "useImperativeHandle" - -@module("react") -external useImperativeHandle3: (Js.Nullable.t>, unit => 'value, ('a, 'b, 'c)) => unit = - "useImperativeHandle" - -@module("react") -external useImperativeHandle4: ( - Js.Nullable.t>, - unit => 'value, - ('a, 'b, 'c, 'd), -) => unit = "useImperativeHandle" - -@module("react") -external useImperativeHandle5: ( - Js.Nullable.t>, - unit => 'value, - ('a, 'b, 'c, 'd, 'e), -) => unit = "useImperativeHandle" - -@module("react") -external useImperativeHandle6: ( - Js.Nullable.t>, - unit => 'value, - ('a, 'b, 'c, 'd, 'e, 'f), -) => unit = "useImperativeHandle" - -@module("react") -external useImperativeHandle7: ( - Js.Nullable.t>, - unit => 'value, - ('a, 'b, 'c, 'd, 'e, 'f, 'g), -) => unit = "useImperativeHandle" - -@module("react") external useId: unit => string = "useId" - -@module("react") external useDeferredValue: 'value => 'value = "useDeferredValue" - -@module("react") -external useTransition: unit => (bool, (unit => unit) => unit) = "useTransition" - -@module("react") -external useInsertionEffectOnEveryRender: (unit => option unit>) => unit = - "useInsertionEffect" -@module("react") -external useInsertionEffect: (unit => option unit>, 'deps) => unit = "useInsertionEffect" -@module("react") -external useInsertionEffect0: (unit => option unit>, @as(json`[]`) _) => unit = - "useInsertionEffect" -@module("react") -external useInsertionEffect1: (unit => option unit>, array<'a>) => unit = - "useInsertionEffect" -@module("react") -external useInsertionEffect2: (unit => option unit>, ('a, 'b)) => unit = - "useInsertionEffect" -@module("react") -external useInsertionEffect3: (unit => option unit>, ('a, 'b, 'c)) => unit = - "useInsertionEffect" -@module("react") -external useInsertionEffect4: (unit => option unit>, ('a, 'b, 'c, 'd)) => unit = - "useInsertionEffect" -@module("react") -external useInsertionEffect5: (unit => option unit>, ('a, 'b, 'c, 'd, 'e)) => unit = - "useInsertionEffect" -@module("react") -external useInsertionEffect6: (unit => option unit>, ('a, 'b, 'c, 'd, 'e, 'f)) => unit = - "useInsertionEffect" -@module("react") -external useInsertionEffect7: (unit => option unit>, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => unit = - "useInsertionEffect" - -@module("react") -external useSyncExternalStore: ( - ~subscribe: (unit => unit) => unit => unit, - ~getSnapshot: unit => 'state, -) => 'state = "useSyncExternalStore" - -@module("react") -external useSyncExternalStoreWithServerSnapshot: ( - ~subscribe: (unit => unit) => unit => unit, - ~getSnapshot: unit => 'state, - ~getServerSnapshot: unit => 'state, -) => 'state = "useSyncExternalStore" - -module Uncurried = { - @module("react") - external useState: (unit => 'state) => ('state, ('state => 'state) => unit) = "useState" - - @module("react") - external useReducer: (('state, 'action) => 'state, 'state) => ('state, 'action => unit) = - "useReducer" - - @module("react") - external useReducerWithMapState: ( - ('state, 'action) => 'state, - 'initialState, - 'initialState => 'state, - ) => ('state, 'action => unit) = "useReducer" - - @module("react") - external useCallback: ('f, 'deps) => 'f = "useCallback" - - @module("react") - external useCallback0: ('f, @as(json`[]`) _) => 'f = "useCallback" - - @module("react") - external useCallback1: ('f, array<'a>) => 'f = "useCallback" - - @module("react") - external useCallback2: ('f, ('a, 'b)) => 'f = "useCallback" - - @module("react") - external useCallback3: ('f, ('a, 'b, 'c)) => 'f = "useCallback" - - @module("react") - external useCallback4: ('f, ('a, 'b, 'c, 'd)) => 'f = "useCallback" - - @module("react") - external useCallback5: ('f, ('a, 'b, 'c, 'd, 'e)) => 'f = "useCallback" - - @module("react") - external useCallback6: ('callback, ('a, 'b, 'c, 'd, 'e, 'f)) => 'callback = "useCallback" - - @module("react") - external useCallback7: ('callback, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => 'callback = "useCallback" -} - -@set -external setDisplayName: (component<'props>, string) => unit = "displayName" - -@get @return(nullable) -external displayName: component<'props> => option = "displayName" diff --git a/tests/dependencies/rescript-react/src/ReactDOM.res b/tests/dependencies/rescript-react/src/ReactDOM.res deleted file mode 100644 index 04c39c2647..0000000000 --- a/tests/dependencies/rescript-react/src/ReactDOM.res +++ /dev/null @@ -1,73 +0,0 @@ -/* First time reading a ReScript file? */ -/* `external` is the foreign function call in OCaml. */ -/* here we're saying `I guarantee that on the JS side, we have a `render` function in the module "react-dom" - that takes in a reactElement, a dom element, and returns unit (nothing) */ -/* It's like `let`, except you're pointing the implementation to the JS side. The compiler will inline these - calls and add the appropriate `require("react-dom")` in the file calling this `render` */ - -// Helper so that ReactDOM itself doesn't bring any runtime -@val @return(nullable) -external querySelector: string => option = "document.querySelector" - -module Client = { - module Root = { - type t - - @send external render: (t, React.element) => unit = "render" - - @send external unmount: (t, unit) => unit = "unmount" - } - - @module("react-dom/client") - external createRoot: Dom.element => Root.t = "createRoot" - - @module("react-dom/client") - external hydrateRoot: (Dom.element, React.element) => Root.t = "hydrateRoot" -} - -@module("react-dom") -external createPortal: (React.element, Dom.element) => React.element = "createPortal" - -external domElementToObj: Dom.element => {..} = "%identity" - -type style = ReactDOMStyle.t - -type domRef = JsxDOM.domRef - -module Ref = { - type t = domRef - type currentDomRef = React.ref> - type callbackDomRef = Js.nullable => unit - - external domRef: currentDomRef => domRef = "%identity" - external callbackDomRef: callbackDomRef => domRef = "%identity" -} - -type domProps = JsxDOM.domProps - -@variadic @module("react") -external createElement: (string, ~props: domProps=?, array) => React.element = - "createElement" - -@variadic @module("react") -external createDOMElementVariadic: ( - string, - ~props: domProps=?, - array, -) => React.element = "createElement" - -external someElement: React.element => option = "%identity" - -@module("react/jsx-runtime") -external jsx: (string, JsxDOM.domProps) => Jsx.element = "jsx" - -@module("react/jsx-runtime") -external jsxKeyed: (string, JsxDOM.domProps, ~key: string=?, @ignore unit) => Jsx.element = "jsx" - -@module("react/jsx-runtime") -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 = ReactDOMStyle diff --git a/tests/dependencies/rescript-react/src/ReactDOMStyle.res b/tests/dependencies/rescript-react/src/ReactDOMStyle.res deleted file mode 100644 index ae68d03554..0000000000 --- a/tests/dependencies/rescript-react/src/ReactDOMStyle.res +++ /dev/null @@ -1,16 +0,0 @@ -type t = JsxDOMStyle.t - -/* CSS2Properties: https://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSS2Properties */ -@val -external combine: (@as(json`{}`) _, t, t) => t = "Object.assign" - -external _dictToStyle: Js.Dict.t => t = "%identity" - -let unsafeAddProp = (style, key, value) => { - let dict = Js.Dict.empty() - Js.Dict.set(dict, key, value) - combine(style, _dictToStyle(dict)) -} - -@val -external unsafeAddStyle: (@as(json`{}`) _, t, {..}) => t = "Object.assign" diff --git a/tests/dependencies/rescript-react/src/ReactEvent.res b/tests/dependencies/rescript-react/src/ReactEvent.res deleted file mode 100644 index 54ac5910c2..0000000000 --- a/tests/dependencies/rescript-react/src/ReactEvent.res +++ /dev/null @@ -1,243 +0,0 @@ -type synthetic<'a> = JsxEvent.synthetic<'a> - -module MakeEventWithType = ( - Type: { - type t - }, -) => { - @get external bubbles: Type.t => bool = "bubbles" - @get external cancelable: Type.t => bool = "cancelable" - @get - external currentTarget: Type.t => {..} = "currentTarget" /* Should return Dom.eventTarget */ - @get external defaultPrevented: Type.t => bool = "defaultPrevented" - @get external eventPhase: Type.t => int = "eventPhase" - @get external isTrusted: Type.t => bool = "isTrusted" - @get external nativeEvent: Type.t => {..} = "nativeEvent" /* Should return Dom.event */ - @send external preventDefault: Type.t => unit = "preventDefault" - @send - external isDefaultPrevented: Type.t => bool = "isDefaultPrevented" - @send external stopPropagation: Type.t => unit = "stopPropagation" - @send - external isPropagationStopped: Type.t => bool = "isPropagationStopped" - @get external target: Type.t => {..} = "target" /* Should return Dom.eventTarget */ - @get external timeStamp: Type.t => float = "timeStamp" - @get external type_: Type.t => string = "type" - @send external persist: Type.t => unit = "persist" -} - -module Synthetic = { - type tag = JsxEvent.Synthetic.tag - type t = synthetic - @get external bubbles: synthetic<'a> => bool = "bubbles" - @get external cancelable: synthetic<'a> => bool = "cancelable" - @get - external currentTarget: synthetic<'a> => {..} = - "currentTarget" /* Should return Dom.eventTarget */ - @get - external defaultPrevented: synthetic<'a> => bool = "defaultPrevented" - @get external eventPhase: synthetic<'a> => int = "eventPhase" - @get external isTrusted: synthetic<'a> => bool = "isTrusted" - @get - external nativeEvent: synthetic<'a> => {..} = "nativeEvent" /* Should return Dom.event */ - @send - external preventDefault: synthetic<'a> => unit = "preventDefault" - @send - external isDefaultPrevented: synthetic<'a> => bool = "isDefaultPrevented" - @send - external stopPropagation: synthetic<'a> => unit = "stopPropagation" - @send - external isPropagationStopped: synthetic<'a> => bool = "isPropagationStopped" - @get external target: synthetic<'a> => {..} = "target" /* Should return Dom.eventTarget */ - @get external timeStamp: synthetic<'a> => float = "timeStamp" - @get external type_: synthetic<'a> => string = "type" - @send external persist: synthetic<'a> => unit = "persist" -} - -/* Cast any event type to the general synthetic type. This is safe, since synthetic is more general */ -external toSyntheticEvent: synthetic<'a> => Synthetic.t = "%identity" - -module Clipboard = { - type tag = JsxEvent.Clipboard.tag - type t = synthetic - include MakeEventWithType({type t = t}) - @get external clipboardData: t => {..} = "clipboardData" /* Should return Dom.dataTransfer */ -} - -module Composition = { - type tag = JsxEvent.Composition.tag - type t = synthetic - include MakeEventWithType({type t = t}) - @get external data: t => string = "data" -} - -module Keyboard = { - type tag = JsxEvent.Keyboard.tag - type t = synthetic - include MakeEventWithType({type t = t}) - @get external altKey: t => bool = "altKey" - @get external charCode: t => int = "charCode" - @get external code: t => string = "code" - @get external ctrlKey: t => bool = "ctrlKey" - @send - external getModifierState: (t, string) => bool = "getModifierState" - @get external key: t => string = "key" - @get external keyCode: t => int = "keyCode" - @get external locale: t => string = "locale" - @get external location: t => int = "location" - @get external metaKey: t => bool = "metaKey" - @get external repeat: t => bool = "repeat" - @get external shiftKey: t => bool = "shiftKey" - @get external which: t => int = "which" -} - -module Focus = { - type tag = JsxEvent.Focus.tag - type t = synthetic - include MakeEventWithType({type t = t}) - @get @return(nullable) - external relatedTarget: t => option<{..}> = "relatedTarget" /* Should return Dom.eventTarget */ -} - -module Form = { - type tag = JsxEvent.Form.tag - type t = synthetic - include MakeEventWithType({type t = t}) -} - -module Mouse = { - type tag = JsxEvent.Mouse.tag - type t = synthetic - include MakeEventWithType({type t = t}) - @get external altKey: t => bool = "altKey" - @get external button: t => int = "button" - @get external buttons: t => int = "buttons" - @get external clientX: t => int = "clientX" - @get external clientY: t => int = "clientY" - @get external ctrlKey: t => bool = "ctrlKey" - @send - external getModifierState: (t, string) => bool = "getModifierState" - @get external metaKey: t => bool = "metaKey" - @get external movementX: t => int = "movementX" - @get external movementY: t => int = "movementY" - @get external pageX: t => int = "pageX" - @get external pageY: t => int = "pageY" - @get @return(nullable) - external relatedTarget: t => option<{..}> = "relatedTarget" /* Should return Dom.eventTarget */ - @get external screenX: t => int = "screenX" - @get external screenY: t => int = "screenY" - @get external shiftKey: t => bool = "shiftKey" -} - -module Pointer = { - type tag = JsxEvent.Pointer.tag - type t = synthetic - include MakeEventWithType({type t = t}) - - // UIEvent - @get external detail: t => int = "detail" - @get external view: t => Dom.window = "view" /* Should return DOMAbstractView/WindowProxy */ - - // MouseEvent - @get external screenX: t => int = "screenX" - @get external screenY: t => int = "screenY" - @get external clientX: t => int = "clientX" - @get external clientY: t => int = "clientY" - @get external pageX: t => int = "pageX" - @get external pageY: t => int = "pageY" - @get external movementX: t => int = "movementX" - @get external movementY: t => int = "movementY" - - @get external ctrlKey: t => bool = "ctrlKey" - @get external shiftKey: t => bool = "shiftKey" - @get external altKey: t => bool = "altKey" - @get external metaKey: t => bool = "metaKey" - @send - external getModifierState: (t, string) => bool = "getModifierState" - - @get external button: t => int = "button" - @get external buttons: t => int = "buttons" - - @get @return(nullable) - external relatedTarget: t => option<{..}> = "relatedTarget" /* Should return Dom.eventTarget */ - - // PointerEvent - @get external pointerId: t => Dom.eventPointerId = "pointerId" - @get external width: t => float = "width" - @get external height: t => float = "height" - @get external pressure: t => float = "pressure" - @get external tangentialPressure: t => float = "tangentialPressure" - @get external tiltX: t => int = "tiltX" - @get external tiltY: t => int = "tiltY" - @get external twist: t => int = "twist" - @get external pointerType: t => string = "pointerType" - @get external isPrimary: t => bool = "isPrimary" -} - -module Selection = { - type tag = JsxEvent.Selection.tag - type t = synthetic - include MakeEventWithType({type t = t}) -} - -module Touch = { - type tag = JsxEvent.Touch.tag - type t = synthetic - include MakeEventWithType({type t = t}) - @get external altKey: t => bool = "altKey" - @get external changedTouches: t => {..} = "changedTouches" /* Should return Dom.touchList */ - @get external ctrlKey: t => bool = "ctrlKey" - @send - external getModifierState: (t, string) => bool = "getModifierState" - @get external metaKey: t => bool = "metaKey" - @get external shiftKey: t => bool = "shiftKey" - @get external targetTouches: t => {..} = "targetTouches" /* Should return Dom.touchList */ - @get external touches: t => {..} = "touches" /* Should return Dom.touchList */ -} - -module UI = { - type tag = JsxEvent.UI.tag - type t = synthetic - include MakeEventWithType({type t = t}) - @get external detail: t => int = "detail" - @get external view: t => Dom.window = "view" /* Should return DOMAbstractView/WindowProxy */ -} - -module Wheel = { - type tag = JsxEvent.Wheel.tag - type t = synthetic - include MakeEventWithType({type t = t}) - @get external deltaMode: t => int = "deltaMode" - @get external deltaX: t => float = "deltaX" - @get external deltaY: t => float = "deltaY" - @get external deltaZ: t => float = "deltaZ" -} - -module Media = { - type tag = JsxEvent.Media.tag - type t = synthetic - include MakeEventWithType({type t = t}) -} - -module Image = { - type tag = JsxEvent.Image.tag - type t = synthetic - include MakeEventWithType({type t = t}) -} - -module Animation = { - type tag = JsxEvent.Animation.tag - type t = synthetic - include MakeEventWithType({type t = t}) - @get external animationName: t => string = "animationName" - @get external pseudoElement: t => string = "pseudoElement" - @get external elapsedTime: t => float = "elapsedTime" -} - -module Transition = { - type tag = JsxEvent.Transition.tag - type t = synthetic - include MakeEventWithType({type t = t}) - @get external propertyName: t => string = "propertyName" - @get external pseudoElement: t => string = "pseudoElement" - @get external elapsedTime: t => float = "elapsedTime" -} diff --git a/tests/dependencies/rescript-react/src/ReactEvent.resi b/tests/dependencies/rescript-react/src/ReactEvent.resi deleted file mode 100644 index 61b5d4b5db..0000000000 --- a/tests/dependencies/rescript-react/src/ReactEvent.resi +++ /dev/null @@ -1,472 +0,0 @@ -/* 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. - - In each module, the type `t` commonly means "the type of that module" (OCaml convention). In our case, e.g. - `ReactEvent.Mouse.t` represents a ReactJS synthetic mouse event. You'd use it to type your props: - - ``` - type props = { - onClick: ReactEvent.Mouse.t => unit - }; - ``` - - All the methods and properties of a type of event are in the module, as seen below. - - Each module also has a `tag` type. You can ignore it; they're only needed by their `t` type. This way, we - get to allow a base `Synthetic` event module with generic methods. So e.g. even a mouse event (`Mouse.t`) - get to be passed to a generic handler: - - ``` - let handleClick = ({state, props}, event) => { - ReactEvent.Mouse.preventDefault(event); - ... - }; - let handleSubmit = ({state, props}, event) => { - // this handler can be triggered by either a Keyboard or a Mouse event; - // conveniently use the generic preventDefault - ReactEvent.Synthetic.preventDefault(event); - ... - }; - - let render = (_) => ; - ``` - - How to translate idioms from ReactJS: - - 1. myMouseEvent.preventDefault() -> ReactEvent.Mouse.preventDefault(myMouseEvent) - 2. myKeyboardEvent.which -> ReactEvent.Keyboard.which(myKeyboardEvent) - */ -type synthetic<'a> = JsxEvent.synthetic<'a> - -module Synthetic: { - type tag = JsxEvent.Synthetic.tag - type t = synthetic - @get external bubbles: synthetic<'a> => bool = "bubbles" - @get external cancelable: synthetic<'a> => bool = "cancelable" - @get - external currentTarget: synthetic<'a> => {..} = "currentTarget" - @get - external defaultPrevented: synthetic<'a> => bool = "defaultPrevented" - @get external eventPhase: synthetic<'a> => int = "eventPhase" - @get external isTrusted: synthetic<'a> => bool = "isTrusted" - @get - external nativeEvent: synthetic<'a> => {..} = "nativeEvent" - @send - external preventDefault: synthetic<'a> => unit = "preventDefault" - @send - external isDefaultPrevented: synthetic<'a> => bool = "isDefaultPrevented" - @send - external stopPropagation: synthetic<'a> => unit = "stopPropagation" - @send - external isPropagationStopped: synthetic<'a> => bool = "isPropagationStopped" - @get external target: synthetic<'a> => {..} = "target" - @get external timeStamp: synthetic<'a> => float = "timeStamp" - @get external type_: synthetic<'a> => string = "type" - @send external persist: synthetic<'a> => unit = "persist" -} - -/* Cast any event type to the general synthetic type. This is safe, since synthetic is more general */ -external toSyntheticEvent: synthetic<'a> => Synthetic.t = "%identity" - -module Clipboard: { - type tag = JsxEvent.Clipboard.tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" - @get external clipboardData: t => {..} = "clipboardData" /* Should return Dom.dataTransfer */ -} - -module Composition: { - type tag = JsxEvent.Composition.tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" - @get external data: t => string = "data" -} - -module Keyboard: { - type tag = JsxEvent.Keyboard.tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" - @get external altKey: t => bool = "altKey" - @get external charCode: t => int = "charCode" - @get external code: t => string = "code" - @get external ctrlKey: t => bool = "ctrlKey" - @send - external getModifierState: (t, string) => bool = "getModifierState" - @get external key: t => string = "key" - @get external keyCode: t => int = "keyCode" - @get external locale: t => string = "locale" - @get external location: t => int = "location" - @get external metaKey: t => bool = "metaKey" - @get external repeat: t => bool = "repeat" - @get external shiftKey: t => bool = "shiftKey" - @get external which: t => int = "which" -} - -module Focus: { - type tag = JsxEvent.Focus.tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" - @get @return(nullable) - external relatedTarget: t => option<{..}> = "relatedTarget" /* Should return Dom.eventTarget */ -} - -module Form: { - type tag = JsxEvent.Form.tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" -} - -module Mouse: { - type tag = JsxEvent.Mouse.tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" - @get external altKey: t => bool = "altKey" - @get external button: t => int = "button" - @get external buttons: t => int = "buttons" - @get external clientX: t => int = "clientX" - @get external clientY: t => int = "clientY" - @get external ctrlKey: t => bool = "ctrlKey" - @send - external getModifierState: (t, string) => bool = "getModifierState" - @get external metaKey: t => bool = "metaKey" - @get external movementX: t => int = "movementX" - @get external movementY: t => int = "movementY" - @get external pageX: t => int = "pageX" - @get external pageY: t => int = "pageY" - @get @return(nullable) - external relatedTarget: t => option<{..}> = "relatedTarget" /* Should return Dom.eventTarget */ - @get external screenX: t => int = "screenX" - @get external screenY: t => int = "screenY" - @get external shiftKey: t => bool = "shiftKey" -} - -module Pointer: { - type tag = JsxEvent.Pointer.tag - type t = synthetic - - // Event - @get external type_: t => string = "type" - @get external target: t => {..} = "target" - @get external currentTarget: t => {..} = "currentTarget" - - @get external eventPhase: t => int = "eventPhase" - - @send external stopPropagation: t => unit = "stopPropagation" // aka cancelBubble - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @send external preventDefault: t => unit = "preventDefault" - @get external defaultPrevented: t => bool = "defaultPrevented" - - @get external isTrusted: t => bool = "isTrusted" - @get external timeStamp: t => float = "timeStamp" - - // SyntheticEvent - @get external nativeEvent: t => {..} = "nativeEvent" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @send external persist: t => unit = "persist" - - // UIEvent - @get external detail: t => int = "detail" - @get external view: t => Dom.window = "view" /* Should return DOMAbstractView/WindowProxy */ - - // MouseEvent - @get external screenX: t => int = "screenX" - @get external screenY: t => int = "screenY" - @get external clientX: t => int = "clientX" - @get external clientY: t => int = "clientY" - @get external pageX: t => int = "pageX" - @get external pageY: t => int = "pageY" - @get external movementX: t => int = "movementX" - @get external movementY: t => int = "movementY" - - @get external ctrlKey: t => bool = "ctrlKey" - @get external shiftKey: t => bool = "shiftKey" - @get external altKey: t => bool = "altKey" - @get external metaKey: t => bool = "metaKey" - @send - external getModifierState: (t, string) => bool = "getModifierState" - - @get external button: t => int = "button" - @get external buttons: t => int = "buttons" - - @get @return(nullable) - external relatedTarget: t => option<{..}> = "relatedTarget" /* Should return Dom.eventTarget */ - - // PointerEvent - @get external pointerId: t => Dom.eventPointerId = "pointerId" - @get external width: t => float = "width" - @get external height: t => float = "height" - @get external pressure: t => float = "pressure" - @get external tangentialPressure: t => float = "tangentialPressure" - @get external tiltX: t => int = "tiltX" - @get external tiltY: t => int = "tiltY" - @get external twist: t => int = "twist" - @get external pointerType: t => string = "pointerType" - @get external isPrimary: t => bool = "isPrimary" -} - -module Selection: { - type tag = JsxEvent.Selection.tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" -} - -module Touch: { - type tag = JsxEvent.Touch.tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" - @get external altKey: t => bool = "altKey" - @get external changedTouches: t => {..} = "changedTouches" /* Should return Dom.touchList */ - @get external ctrlKey: t => bool = "ctrlKey" - @send - external getModifierState: (t, string) => bool = "getModifierState" - @get external metaKey: t => bool = "metaKey" - @get external shiftKey: t => bool = "shiftKey" - @get external targetTouches: t => {..} = "targetTouches" /* Should return Dom.touchList */ - @get external touches: t => {..} = "touches" /* Should return Dom.touchList */ -} - -module UI: { - type tag = JsxEvent.UI.tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" - @get external detail: t => int = "detail" - @get external view: t => Dom.window = "view" /* Should return DOMAbstractView/WindowProxy */ -} - -module Wheel: { - type tag = JsxEvent.Wheel.tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" - @get external deltaMode: t => int = "deltaMode" - @get external deltaX: t => float = "deltaX" - @get external deltaY: t => float = "deltaY" - @get external deltaZ: t => float = "deltaZ" -} - -module Media: { - type tag = JsxEvent.Media.tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" -} - -module Image: { - type tag = JsxEvent.Image.tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" -} - -module Animation: { - type tag = JsxEvent.Animation.tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" - @get external animationName: t => string = "animationName" - @get external pseudoElement: t => string = "pseudoElement" - @get external elapsedTime: t => float = "elapsedTime" -} - -module Transition: { - type tag = JsxEvent.Transition.tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" - @get external propertyName: t => string = "propertyName" - @get external pseudoElement: t => string = "pseudoElement" - @get external elapsedTime: t => float = "elapsedTime" -} diff --git a/yarn.lock b/yarn.lock index 37310a77dd..c4bfdf1bf7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -666,12 +666,6 @@ __metadata: languageName: unknown linkType: soft -"@tests/rescript-react@workspace:tests/dependencies/rescript-react": - version: 0.0.0-use.local - resolution: "@tests/rescript-react@workspace:tests/dependencies/rescript-react" - languageName: unknown - linkType: soft - "@tests/tools@workspace:tests/tools_tests": version: 0.0.0-use.local resolution: "@tests/tools@workspace:tests/tools_tests" From 58788238a96e40c7112131d8c4b35f95f4b5d4b2 Mon Sep 17 00:00:00 2001 From: Christoph Knittel Date: Mon, 26 May 2025 16:54:55 +0200 Subject: [PATCH 06/14] Add package.json for tests/tests --- package.json | 1 + tests/tests/package.json | 9 +++++++++ tests/tests/rescript.json | 1 + yarn.lock | 9 +++++++++ 4 files changed, 20 insertions(+) create mode 100644 tests/tests/package.json diff --git a/package.json b/package.json index 08c7a1ef0b..27282a67d6 100644 --- a/package.json +++ b/package.json @@ -96,6 +96,7 @@ "packages/@rescript/*", "tests/analysis_tests/**", "tests/gentype_tests/**", + "tests/tests", "tests/tools_tests" ], "packageManager": "yarn@4.9.1", diff --git a/tests/tests/package.json b/tests/tests/package.json new file mode 100644 index 0000000000..a767eb7a93 --- /dev/null +++ b/tests/tests/package.json @@ -0,0 +1,9 @@ +{ + "name": "@tests/tests", + "private": true, + "dependencies": { + "@rescript/react": "workspace:^", + "rescript": "workspace:^" + }, + "type": "module" +} diff --git a/tests/tests/rescript.json b/tests/tests/rescript.json index 4a21d34945..b5c2a25404 100644 --- a/tests/tests/rescript.json +++ b/tests/tests/rescript.json @@ -11,6 +11,7 @@ "in-source": true, "suffix": ".mjs" }, + "bs-dependencies": ["@rescript/react"], "bsc-flags": [ "-w -3-6-26-27-29-30-32..40-44-45-52-60-9-106+104", "-warn-error A" diff --git a/yarn.lock b/yarn.lock index c4bfdf1bf7..0d5cd079b7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -666,6 +666,15 @@ __metadata: languageName: unknown linkType: soft +"@tests/tests@workspace:tests/tests": + version: 0.0.0-use.local + resolution: "@tests/tests@workspace:tests/tests" + dependencies: + "@rescript/react": "workspace:^" + rescript: "workspace:^" + languageName: unknown + linkType: soft + "@tests/tools@workspace:tests/tools_tests": version: 0.0.0-use.local resolution: "@tests/tools@workspace:tests/tools_tests" From fd51523bf4b3d7db206cf434a734c0663e4adffe Mon Sep 17 00:00:00 2001 From: Christoph Knittel Date: Mon, 26 May 2025 16:55:11 +0200 Subject: [PATCH 07/14] Remove other copies of @rescript/react / ReasonReact sources --- tests/tests/src/react.mjs | 32 - tests/tests/src/react.res | 443 --------- tests/tests/src/reactDOM.mjs | 59 -- tests/tests/src/reactDOM.res | 249 ----- tests/tests/src/reactDOMServer.mjs | 2 - tests/tests/src/reactDOMServer.res | 5 - tests/tests/src/reactEvent.mjs | 51 - tests/tests/src/reactEvent.res | 196 ---- tests/tests/src/reactEvent.resi | 405 -------- tests/tests/src/reactTestUtils.mjs | 91 -- tests/tests/src/reactTestUtils.res | 133 --- tests/tests/src/reactTestUtils.resi | 56 -- tests/tests/src/reasonReact.mjs | 137 --- tests/tests/src/reasonReact.res | 310 ------ tests/tests/src/reasonReact.resi | 214 ----- tests/tests/src/reasonReactCompat.mjs | 13 - tests/tests/src/reasonReactCompat.res | 10 - tests/tests/src/reasonReactCompat.resi | 14 - .../src/reasonReactOptimizedCreateClass.mjs | 894 ------------------ .../src/reasonReactOptimizedCreateClass.res | 889 ----------------- tests/tests/src/reasonReactRouter.mjs | 184 ---- tests/tests/src/reasonReactRouter.res | 191 ---- tests/tests/src/reasonReactRouter.resi | 33 - 23 files changed, 4611 deletions(-) delete mode 100644 tests/tests/src/react.mjs delete mode 100644 tests/tests/src/react.res delete mode 100644 tests/tests/src/reactDOM.mjs delete mode 100644 tests/tests/src/reactDOM.res delete mode 100644 tests/tests/src/reactDOMServer.mjs delete mode 100644 tests/tests/src/reactDOMServer.res delete mode 100644 tests/tests/src/reactEvent.mjs delete mode 100644 tests/tests/src/reactEvent.res delete mode 100644 tests/tests/src/reactEvent.resi delete mode 100644 tests/tests/src/reactTestUtils.mjs delete mode 100644 tests/tests/src/reactTestUtils.res delete mode 100644 tests/tests/src/reactTestUtils.resi delete mode 100644 tests/tests/src/reasonReact.mjs delete mode 100644 tests/tests/src/reasonReact.res delete mode 100644 tests/tests/src/reasonReact.resi delete mode 100644 tests/tests/src/reasonReactCompat.mjs delete mode 100644 tests/tests/src/reasonReactCompat.res delete mode 100644 tests/tests/src/reasonReactCompat.resi delete mode 100644 tests/tests/src/reasonReactOptimizedCreateClass.mjs delete mode 100644 tests/tests/src/reasonReactOptimizedCreateClass.res delete mode 100644 tests/tests/src/reasonReactRouter.mjs delete mode 100644 tests/tests/src/reasonReactRouter.res delete mode 100644 tests/tests/src/reasonReactRouter.resi diff --git a/tests/tests/src/react.mjs b/tests/tests/src/react.mjs deleted file mode 100644 index 1d5280226e..0000000000 --- a/tests/tests/src/react.mjs +++ /dev/null @@ -1,32 +0,0 @@ -// Generated by ReScript, PLEASE EDIT WITH CARE - -import * as React from "react"; - -let Children = {}; - -let Context = {}; - -let Fragment = {}; - -let StrictMode = {}; - -let Suspense = {}; - -function lazy_(load) { - return React.lazy(async () => ({ - default: await load() - })); -} - -let Uncurried = {}; - -export { - Children, - Context, - Fragment, - StrictMode, - Suspense, - lazy_, - Uncurried, -} -/* react Not a pure module */ diff --git a/tests/tests/src/react.res b/tests/tests/src/react.res deleted file mode 100644 index f1f6831518..0000000000 --- a/tests/tests/src/react.res +++ /dev/null @@ -1,443 +0,0 @@ -type element = Jsx.element - -@val external null: element = "null" - -external float: float => element = "%identity" -external int: int => element = "%identity" -external string: string => element = "%identity" -external promise: promise => element = "%identity" - -external array: array => element = "%identity" - -type componentLike<'props, 'return> = Jsx.componentLike<'props, 'return> - -type component<'props> = Jsx.component<'props> - -external component: componentLike<'props, element> => component<'props> = "%identity" - -@module("react") -external createElement: (component<'props>, 'props) => element = "createElement" - -@module("react") -external cloneElement: (element, 'props) => element = "cloneElement" - -@module("react") -external isValidElement: 'a => bool = "isValidElement" - -@variadic @module("react") -external createElementVariadic: (component<'props>, 'props, array) => element = - "createElement" - -@module("react/jsx-runtime") -external jsx: (component<'props>, 'props) => element = "jsx" - -@module("react/jsx-runtime") -external jsxKeyed: (component<'props>, 'props, ~key: string=?, @ignore unit) => element = "jsx" - -@module("react/jsx-runtime") -external jsxs: (component<'props>, 'props) => element = "jsxs" - -@module("react/jsx-runtime") -external jsxsKeyed: (component<'props>, 'props, ~key: string=?, @ignore unit) => element = "jsxs" - -type fragmentProps = {children?: element} - -@module("react/jsx-runtime") external jsxFragment: component = "Fragment" - -type ref<'value> = {mutable current: 'value} - -@module("react") -external createRef: unit => ref> = "createRef" - -module Children = { - @module("react") @scope("Children") - external map: (element, element => element) => element = "map" - @module("react") @scope("Children") - external mapWithIndex: (element, (element, int) => element) => element = "map" - @module("react") @scope("Children") - external forEach: (element, element => unit) => unit = "forEach" - @module("react") @scope("Children") - external forEachWithIndex: (element, (element, int) => unit) => unit = "forEach" - @module("react") @scope("Children") - external count: element => int = "count" - @module("react") @scope("Children") - external only: element => element = "only" - @module("react") @scope("Children") - external toArray: element => array = "toArray" -} - -module Context = { - type t<'context> - - type props<'context> = { - value: 'context, - children: element, - } - - @get - external provider: t<'context> => component> = "Provider" -} - -@module("react") -external createContext: 'a => Context.t<'a> = "createContext" - -@module("react") -external forwardRef: (('props, Js.Nullable.t>) => element) => component<'props> = - "forwardRef" - -@module("react") -external memo: component<'props> => component<'props> = "memo" - -@module("react") -external memoCustomCompareProps: ( - component<'props>, - ('props, 'props) => bool, -) => component<'props> = "memo" - -@module("react") external fragment: component = "Fragment" - -module Fragment = { - type props = {key?: string, children: element} - - @module("react") - external make: component = "Fragment" -} - -module StrictMode = { - type props = {key?: string, children: element} - - @module("react") - external make: component = "StrictMode" -} - -module Suspense = { - type props = {key?: string, children?: element, fallback?: element} - - @module("react") - external make: component = "Suspense" -} - -type dynamicallyImportedModule<'a> = {default: component<'a>} - -@module("react") -external lazy_: (unit => promise>) => component<'a> = "lazy" - -let lazy_ = load => lazy_(async () => {default: await load()}) - -/* HOOKS */ - -/* - * Yeah, we know this api isn't great. tl;dr: useReducer instead. - * It's because useState can take functions or non-function values and treats - * them differently. Lazy initializer + callback which returns state is the - * only way to safely have any type of state and be able to update it correctly. - */ -@module("react") -external useState: (unit => 'state) => ('state, ('state => 'state) => unit) = "useState" - -@module("react") -external useReducer: (('state, 'action) => 'state, 'state) => ('state, 'action => unit) = - "useReducer" - -@module("react") -external useReducerWithMapState: ( - ('state, 'action) => 'state, - 'initialState, - 'initialState => 'state, -) => ('state, 'action => unit) = "useReducer" - -@module("react") -external useEffectOnEveryRender: (unit => option unit>) => unit = "useEffect" -@module("react") -external useEffect: (unit => option unit>, 'deps) => unit = "useEffect" -@module("react") -external useEffect0: (unit => option unit>, @as(json`[]`) _) => unit = "useEffect" -@module("react") -external useEffect1: (unit => option unit>, array<'a>) => unit = "useEffect" -@module("react") -external useEffect2: (unit => option unit>, ('a, 'b)) => unit = "useEffect" -@module("react") -external useEffect3: (unit => option unit>, ('a, 'b, 'c)) => unit = "useEffect" -@module("react") -external useEffect4: (unit => option unit>, ('a, 'b, 'c, 'd)) => unit = "useEffect" -@module("react") -external useEffect5: (unit => option unit>, ('a, 'b, 'c, 'd, 'e)) => unit = "useEffect" -@module("react") -external useEffect6: (unit => option unit>, ('a, 'b, 'c, 'd, 'e, 'f)) => unit = "useEffect" -@module("react") -external useEffect7: (unit => option unit>, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => unit = - "useEffect" - -@module("react") -external useLayoutEffectOnEveryRender: (unit => option unit>) => unit = "useLayoutEffect" -@module("react") -external useLayoutEffect: (unit => option unit>, 'deps) => unit = "useLayoutEffect" -@module("react") -external useLayoutEffect0: (unit => option unit>, @as(json`[]`) _) => unit = - "useLayoutEffect" -@module("react") -external useLayoutEffect1: (unit => option unit>, array<'a>) => unit = "useLayoutEffect" -@module("react") -external useLayoutEffect2: (unit => option unit>, ('a, 'b)) => unit = "useLayoutEffect" -@module("react") -external useLayoutEffect3: (unit => option unit>, ('a, 'b, 'c)) => unit = "useLayoutEffect" -@module("react") -external useLayoutEffect4: (unit => option unit>, ('a, 'b, 'c, 'd)) => unit = - "useLayoutEffect" -@module("react") -external useLayoutEffect5: (unit => option unit>, ('a, 'b, 'c, 'd, 'e)) => unit = - "useLayoutEffect" -@module("react") -external useLayoutEffect6: (unit => option unit>, ('a, 'b, 'c, 'd, 'e, 'f)) => unit = - "useLayoutEffect" -@module("react") -external useLayoutEffect7: (unit => option unit>, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => unit = - "useLayoutEffect" - -@module("react") -external useMemo: (unit => 'any, 'deps) => 'any = "useMemo" - -@module("react") -external useMemo0: (unit => 'any, @as(json`[]`) _) => 'any = "useMemo" - -@module("react") -external useMemo1: (unit => 'any, array<'a>) => 'any = "useMemo" - -@module("react") -external useMemo2: (unit => 'any, ('a, 'b)) => 'any = "useMemo" - -@module("react") -external useMemo3: (unit => 'any, ('a, 'b, 'c)) => 'any = "useMemo" - -@module("react") -external useMemo4: (unit => 'any, ('a, 'b, 'c, 'd)) => 'any = "useMemo" - -@module("react") -external useMemo5: (unit => 'any, ('a, 'b, 'c, 'd, 'e)) => 'any = "useMemo" - -@module("react") -external useMemo6: (unit => 'any, ('a, 'b, 'c, 'd, 'e, 'f)) => 'any = "useMemo" - -@module("react") -external useMemo7: (unit => 'any, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => 'any = "useMemo" - -@module("react") -external useCallback: ('f, 'deps) => 'f = "useCallback" - -@module("react") -external useCallback0: ('f, @as(json`[]`) _) => 'f = "useCallback" - -@module("react") -external useCallback1: ('f, array<'a>) => 'f = "useCallback" - -@module("react") -external useCallback2: ('f, ('a, 'b)) => 'f = "useCallback" - -@module("react") -external useCallback3: ('f, ('a, 'b, 'c)) => 'f = "useCallback" - -@module("react") -external useCallback4: ('f, ('a, 'b, 'c, 'd)) => 'f = "useCallback" - -@module("react") -external useCallback5: ('f, ('a, 'b, 'c, 'd, 'e)) => 'f = "useCallback" - -@module("react") -external useCallback6: ('callback, ('a, 'b, 'c, 'd, 'e, 'f)) => 'callback = "useCallback" - -@module("react") -external useCallback7: ('callback, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => 'callback = "useCallback" - -@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") -external useImperativeHandleOnEveryRender: (Js.Nullable.t>, unit => 'value) => unit = - "useImperativeHandle" - -@module("react") -external useImperativeHandle: (Js.Nullable.t>, unit => 'value, 'deps) => unit = - "useImperativeHandle" - -@module("react") -external useImperativeHandle0: ( - Js.Nullable.t>, - unit => 'value, - @as(json`[]`) _, -) => unit = "useImperativeHandle" - -@module("react") -external useImperativeHandle1: (Js.Nullable.t>, unit => 'value, array<'a>) => unit = - "useImperativeHandle" - -@module("react") -external useImperativeHandle2: (Js.Nullable.t>, unit => 'value, ('a, 'b)) => unit = - "useImperativeHandle" - -@module("react") -external useImperativeHandle3: (Js.Nullable.t>, unit => 'value, ('a, 'b, 'c)) => unit = - "useImperativeHandle" - -@module("react") -external useImperativeHandle4: ( - Js.Nullable.t>, - unit => 'value, - ('a, 'b, 'c, 'd), -) => unit = "useImperativeHandle" - -@module("react") -external useImperativeHandle5: ( - Js.Nullable.t>, - unit => 'value, - ('a, 'b, 'c, 'd, 'e), -) => unit = "useImperativeHandle" - -@module("react") -external useImperativeHandle6: ( - Js.Nullable.t>, - unit => 'value, - ('a, 'b, 'c, 'd, 'e, 'f), -) => unit = "useImperativeHandle" - -@module("react") -external useImperativeHandle7: ( - Js.Nullable.t>, - unit => 'value, - ('a, 'b, 'c, 'd, 'e, 'f, 'g), -) => unit = "useImperativeHandle" - -@module("react") external useId: unit => string = "useId" - -/** `useDeferredValue` is a React Hook that lets you defer updating a part of the UI. */ -@module("react") -external useDeferredValue: ('value, ~initialValue: 'value=?) => 'value = "useDeferredValue" - -@module("react") -external useInsertionEffectOnEveryRender: (unit => option unit>) => unit = - "useInsertionEffect" -@module("react") -external useInsertionEffect: (unit => option unit>, 'deps) => unit = "useInsertionEffect" -@module("react") -external useInsertionEffect0: (unit => option unit>, @as(json`[]`) _) => unit = - "useInsertionEffect" -@module("react") -external useInsertionEffect1: (unit => option unit>, array<'a>) => unit = - "useInsertionEffect" -@module("react") -external useInsertionEffect2: (unit => option unit>, ('a, 'b)) => unit = - "useInsertionEffect" -@module("react") -external useInsertionEffect3: (unit => option unit>, ('a, 'b, 'c)) => unit = - "useInsertionEffect" -@module("react") -external useInsertionEffect4: (unit => option unit>, ('a, 'b, 'c, 'd)) => unit = - "useInsertionEffect" -@module("react") -external useInsertionEffect5: (unit => option unit>, ('a, 'b, 'c, 'd, 'e)) => unit = - "useInsertionEffect" -@module("react") -external useInsertionEffect6: (unit => option unit>, ('a, 'b, 'c, 'd, 'e, 'f)) => unit = - "useInsertionEffect" -@module("react") -external useInsertionEffect7: (unit => option unit>, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => unit = - "useInsertionEffect" - -@module("react") -external useSyncExternalStore: ( - ~subscribe: (unit => unit) => unit => unit, - ~getSnapshot: unit => 'state, -) => 'state = "useSyncExternalStore" - -@module("react") -external useSyncExternalStoreWithServerSnapshot: ( - ~subscribe: (unit => unit) => unit => unit, - ~getSnapshot: unit => 'state, - ~getServerSnapshot: unit => 'state, -) => 'state = "useSyncExternalStore" - -module Uncurried = { - @module("react") - external useState: (unit => 'state) => ('state, ('state => 'state) => unit) = "useState" - - @module("react") - external useReducer: (('state, 'action) => 'state, 'state) => ('state, 'action => unit) = - "useReducer" - - @module("react") - external useReducerWithMapState: ( - ('state, 'action) => 'state, - 'initialState, - 'initialState => 'state, - ) => ('state, 'action => unit) = "useReducer" - - @module("react") - external useCallback: ('f, 'deps) => 'f = "useCallback" - - @module("react") - external useCallback0: ('f, @as(json`[]`) _) => 'f = "useCallback" - - @module("react") - external useCallback1: ('f, array<'a>) => 'f = "useCallback" - - @module("react") - external useCallback2: ('f, ('a, 'b)) => 'f = "useCallback" - - @module("react") - external useCallback3: ('f, ('a, 'b, 'c)) => 'f = "useCallback" - - @module("react") - external useCallback4: ('f, ('a, 'b, 'c, 'd)) => 'f = "useCallback" - - @module("react") - external useCallback5: ('f, ('a, 'b, 'c, 'd, 'e)) => 'f = "useCallback" - - @module("react") - external useCallback6: ('callback, ('a, 'b, 'c, 'd, 'e, 'f)) => 'callback = "useCallback" - - @module("react") - external useCallback7: ('callback, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => 'callback = "useCallback" -} - -@set -external setDisplayName: (component<'props>, string) => unit = "displayName" - -@get @return(nullable) -external displayName: component<'props> => option = "displayName" - -// Actions - -type transitionFunction = unit => promise - -type transitionStartFunction = transitionFunction => unit - -/** `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" - -type action<'state, 'payload> = ('state, 'payload) => promise<'state> - -type formAction<'formData> = 'formData => promise - -/** `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) => promise = "act" diff --git a/tests/tests/src/reactDOM.mjs b/tests/tests/src/reactDOM.mjs deleted file mode 100644 index 3064f39b11..0000000000 --- a/tests/tests/src/reactDOM.mjs +++ /dev/null @@ -1,59 +0,0 @@ -// Generated by ReScript, PLEASE EDIT WITH CARE - -import * as Primitive_option from "rescript/lib/es6/Primitive_option.js"; - -let Root = {}; - -let Client = { - Root: Root -}; - -function getString(formData, name) { - let value = formData.get(name); - if (!(value == null) && typeof value === "string") { - return Primitive_option.some(value); - } - -} - -function getFile(formData, name) { - let value = formData.get(name); - if (!(value == null) && typeof value !== "string") { - return Primitive_option.some(value); - } - -} - -function getAll(t, string) { - return t.getAll(string).map(value => { - if (typeof value === "string") { - return { - TAG: "String", - _0: value - }; - } else { - return { - TAG: "File", - _0: value - }; - } - }); -} - -let FormData = { - getString: getString, - getFile: getFile, - getAll: getAll -}; - -let Ref = {}; - -let Style; - -export { - Client, - FormData, - Ref, - Style, -} -/* No side effect */ diff --git a/tests/tests/src/reactDOM.res b/tests/tests/src/reactDOM.res deleted file mode 100644 index 3cb44aac83..0000000000 --- a/tests/tests/src/reactDOM.res +++ /dev/null @@ -1,249 +0,0 @@ -/* First time reading a ReScript file? */ -/* `external` is the foreign function call in OCaml. */ -/* here we're saying `I guarantee that on the JS side, we have a `render` function in the module "react-dom" - that takes in a reactElement, a dom element, and returns unit (nothing) */ -/* It's like `let`, except you're pointing the implementation to the JS side. The compiler will inline these - calls and add the appropriate `require("react-dom")` in the file calling this `render` */ - -// Helper so that ReactDOM itself doesn't bring any runtime -@val @return(nullable) -external querySelector: string => option = "document.querySelector" - -module Client = { - module Root = { - type t - - @send external render: (t, React.element) => unit = "render" - - @send external unmount: (t, unit) => unit = "unmount" - } - - @module("react-dom/client") - external createRoot: Dom.element => Root.t = "createRoot" - - @module("react-dom/client") - external hydrateRoot: (Dom.element, React.element) => Root.t = "hydrateRoot" -} - -// Very rudimentary form data bindings -module FormData = { - type t - type file - - type formValue = - | String(string) - | File(file) - - @new external make: unit => t = "FormData" - - @send external append: (t, string, ~filename: string=?) => unit = "append" - @send external delete: (t, string) => unit = "delete" - @return(nullable) @send external getUnsafe: (t, string) => option<'a> = "get" - @send external getAllUnsafe: (t, string) => array<'a> = "getAll" - - let getString = (formData, name) => { - switch formData->getUnsafe(name) { - | Some(value) => Js.typeof(value) === "string" ? Some(value) : None - | _ => None - } - } - - external _asFile: 'a => file = "%identity" - - let getFile = (formData, name) => { - switch formData->getUnsafe(name) { - | Some(value) => Js.typeof(value) === "string" ? None : Some(value->_asFile) - | _ => None - } - } - - let getAll = (t, string) => { - t - ->getAllUnsafe(string) - ->Js.Array2.map(value => { - Js.typeof(value) === "string" ? String(value) : File(value->_asFile) - }) - } - - @send external set: (string, string) => unit = "set" - @send external has: string => bool = "has" - // @send external keys: t => Iterator.t = "keys"; - // @send external values: t => Iterator.t = "values"; -} - -@module("react-dom") -external createPortal: (React.element, Dom.element) => React.element = "createPortal" - -external domElementToObj: Dom.element => {..} = "%identity" - -type style = JsxDOMStyle.t - -type domRef = JsxDOM.domRef - -module Ref = { - type t = domRef - type currentDomRef = React.ref> - type callbackDomRef = Js.nullable => option unit> - - external domRef: currentDomRef => domRef = "%identity" - external callbackDomRef: callbackDomRef => domRef = "%identity" -} - -// Hooks - -type formStatus<'state> = { - /** If true, this means the parent is pending submission. Otherwise, false. */ - pending: bool, - /** An object implementing the FormData interface that contains the data the parent is submitting. If there is no active submission or no parent , it will be null. */ - data: FormData.t, - /** This represents whether the parent is submitting with either a GET or POST HTTP method. By default, a will use the GET method and can be specified by the method property. */ - method: [#get | #post], - /** A reference to the function passed to the action prop on the parent . If there is no parent , the property is null. If there is a URI value provided to the action prop, or no action prop specified, status.action will be null. */ - action: React.action<'state, FormData.t>, -} - -external formAction: React.formAction => string = "%identity" - -/** `useFormStatus` is a Hook that gives you status information of the last form submission. */ -@module("react-dom") -external useFormStatus: unit => formStatus<'state> = "useFormStatus" - -// Resource Preloading APIs - -/** The CORS policy to use. */ -type crossOrigin = [ - | #anonymous - | #"use-credentials" -] - -/** The Referrer header to send when fetching. */ -type referrerPolicy = [ - | #"referrer-when-downgrade" - | #"no-referrer" - | #origin - | #"origin-when-cross-origin" - | #"unsafe-url" -] - -/** Suggests a relative priority for fetching the resource. */ -type fetchPriority = [#auto | #high | #low] - -/** `prefetchDNS` lets you eagerly look up the IP of a server that you expect to load resources from. */ -@module("react-dom") -external prefetchDNS: string => unit = "prefetchDNS" - -/** `preconnect` lets you eagerly connect to a server that you expect to load resources from. */ -@module("react-dom") -external preconnect: string => unit = "preconnect" - -type preloadOptions = { - /** The type of resource. */ - @as("as") - as_: [ - | #audio - | #document - | #embed - | #fetch - | #font - | #image - | #object - | #script - | #style - | #track - | #video - | #worker - ], - /** The CORS policy to use. It is required when as is set to "fetch". */ - crossOrigin?: crossOrigin, - /** The Referrer header to send when fetching. */ - referrerPolicy?: referrerPolicy, - /** A cryptographic hash of the resource, to verify its authenticity. */ - integrity?: string, - /** The MIME type of the resource. */ - @as("type") - type_?: string, - /** A cryptographic nonce to allow the resource when using a strict Content Security Policy. */ - nonce?: string, - /** Suggests a relative priority for fetching the resource. */ - fetchPriority?: fetchPriority, - /** For use only with as: "image". Specifies the source set of the image. */ - imageSrcSet?: string, - /** For use only with as: "image". Specifies the sizes of the image. */ - imageSizes?: string, -} - -/** `preload` lets you eagerly fetch a resource such as a stylesheet, font, or external script that you expect to use. */ -@module("react-dom") -external preload: (string, preloadOptions) => unit = "preload" - -type preloadModuleOptions = { - /** The type of resource. */ - @as("as") - as_: [#script], - /** The CORS policy to use. It is required when as is set to "fetch". */ - crossOrigin?: crossOrigin, - /** A cryptographic hash of the resource, to verify its authenticity. */ - integrity?: string, - /** A cryptographic nonce to allow the resource when using a strict Content Security Policy. */ - nonce?: string, -} - -/** `preloadModule` lets you eagerly fetch an ESM module that you expect to use. */ -@module("react-dom") -external preloadModule: (string, preloadModuleOptions) => unit = "preloadModule" - -type preinitOptions = { - /** The type of resource. */ - @as("as") - as_: [#script | #style], - /** Required with stylesheets. Says where to insert the stylesheet relative to others. Stylesheets with higher precedence can override those with lower precedence. */ - precedence?: [#reset | #low | #medium | #high], - /** The CORS policy to use. It is required when as is set to "fetch". */ - crossOrigin?: crossOrigin, - /** The Referrer header to send when fetching. */ - referrerPolicy?: referrerPolicy, - /** A cryptographic hash of the resource, to verify its authenticity. */ - integrity?: string, - nonce?: string, - /** Suggests a relative priority for fetching the resource. */ - fetchPriority?: fetchPriority, -} - -/** `preinit` lets you eagerly fetch and evaluate a stylesheet or external script. */ -@module("react-dom") -external preinit: (string, preinitOptions) => unit = "preinit" - -/** To preinit an ESM module, call the `preinitModule` function from react-dom. */ -@module("react-dom") -external preinitModule: (string, preloadModuleOptions) => unit = "preinitModule" - -// Runtime - -type domProps = JsxDOM.domProps - -@variadic @module("react") -external createElement: (string, ~props: domProps=?, array) => React.element = - "createElement" - -@variadic @module("react") -external createDOMElementVariadic: ( - string, - ~props: domProps=?, - array, -) => React.element = "createElement" - -external someElement: React.element => option = "%identity" - -@module("react/jsx-runtime") -external jsx: (string, JsxDOM.domProps) => Jsx.element = "jsx" - -@module("react/jsx-runtime") -external jsxKeyed: (string, JsxDOM.domProps, ~key: string=?, @ignore unit) => Jsx.element = "jsx" - -@module("react/jsx-runtime") -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 diff --git a/tests/tests/src/reactDOMServer.mjs b/tests/tests/src/reactDOMServer.mjs deleted file mode 100644 index d856702bfe..0000000000 --- a/tests/tests/src/reactDOMServer.mjs +++ /dev/null @@ -1,2 +0,0 @@ -// 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/tests/tests/src/reactDOMServer.res b/tests/tests/src/reactDOMServer.res deleted file mode 100644 index d50ddc14fe..0000000000 --- a/tests/tests/src/reactDOMServer.res +++ /dev/null @@ -1,5 +0,0 @@ -@module("react-dom/server") -external renderToString: React.element => string = "renderToString" - -@module("react-dom/server") -external renderToStaticMarkup: React.element => string = "renderToStaticMarkup" diff --git a/tests/tests/src/reactEvent.mjs b/tests/tests/src/reactEvent.mjs deleted file mode 100644 index 093c936081..0000000000 --- a/tests/tests/src/reactEvent.mjs +++ /dev/null @@ -1,51 +0,0 @@ -// Generated by ReScript, PLEASE EDIT WITH CARE - - -let Synthetic = {}; - -let Clipboard = {}; - -let Composition = {}; - -let Keyboard = {}; - -let Focus = {}; - -let Form = {}; - -let Mouse = {}; - -let Selection = {}; - -let Touch = {}; - -let UI = {}; - -let Wheel = {}; - -let Media = {}; - -let Image = {}; - -let Animation = {}; - -let Transition = {}; - -export { - Synthetic, - Clipboard, - Composition, - Keyboard, - Focus, - Form, - Mouse, - Selection, - Touch, - UI, - Wheel, - Media, - Image, - Animation, - Transition, -} -/* No side effect */ diff --git a/tests/tests/src/reactEvent.res b/tests/tests/src/reactEvent.res deleted file mode 100644 index 54921be983..0000000000 --- a/tests/tests/src/reactEvent.res +++ /dev/null @@ -1,196 +0,0 @@ -type synthetic<'a> - -module MakeEventWithType = ( - Type: { - type t - }, -) => { - @get external bubbles: Type.t => bool = "bubbles" - @get external cancelable: Type.t => bool = "cancelable" - @get external currentTarget: Type.t => {..} = "currentTarget" /* Should return Dom.eventTarget */ - @get external defaultPrevented: Type.t => bool = "defaultPrevented" - @get external eventPhase: Type.t => int = "eventPhase" - @get external isTrusted: Type.t => bool = "isTrusted" - @get external nativeEvent: Type.t => {..} = "nativeEvent" /* Should return Dom.event */ - @send external preventDefault: Type.t => unit = "preventDefault" - @send - external isDefaultPrevented: Type.t => bool = "isDefaultPrevented" - @send external stopPropagation: Type.t => unit = "stopPropagation" - @send - external isPropagationStopped: Type.t => bool = "isPropagationStopped" - @get external target: Type.t => {..} = "target" /* Should return Dom.eventTarget */ - @get external timeStamp: Type.t => float = "timeStamp" - @get external type_: Type.t => string = "type" - @send external persist: Type.t => unit = "persist" -} - -module Synthetic = { - type tag - type t = synthetic - @get external bubbles: synthetic<'a> => bool = "bubbles" - @get external cancelable: synthetic<'a> => bool = "cancelable" - @get - external currentTarget: synthetic<'a> => {..} = - "currentTarget" /* Should return Dom.eventTarget */ - @get - external defaultPrevented: synthetic<'a> => bool = "defaultPrevented" - @get external eventPhase: synthetic<'a> => int = "eventPhase" - @get external isTrusted: synthetic<'a> => bool = "isTrusted" - @get - external nativeEvent: synthetic<'a> => {..} = "nativeEvent" /* Should return Dom.event */ - @send - external preventDefault: synthetic<'a> => unit = "preventDefault" - @send - external isDefaultPrevented: synthetic<'a> => bool = "isDefaultPrevented" - @send - external stopPropagation: synthetic<'a> => unit = "stopPropagation" - @send - external isPropagationStopped: synthetic<'a> => bool = "isPropagationStopped" - @get external target: synthetic<'a> => {..} = "target" /* Should return Dom.eventTarget */ - @get external timeStamp: synthetic<'a> => float = "timeStamp" - @get external type_: synthetic<'a> => string = "type" - @send external persist: synthetic<'a> => unit = "persist" -} - -/* Cast any event type to the general synthetic type. This is safe, since synthetic is more general */ -external toSyntheticEvent: synthetic<'a> => Synthetic.t = "%identity" - -module Clipboard = { - type tag - type t = synthetic - include MakeEventWithType({type t = t}) - @get external clipboardData: t => {..} = "clipboardData" /* Should return Dom.dataTransfer */ -} - -module Composition = { - type tag - type t = synthetic - include MakeEventWithType({type t = t}) - @get external data: t => string = "data" -} - -module Keyboard = { - type tag - type t = synthetic - include MakeEventWithType({type t = t}) - @get external altKey: t => bool = "altKey" - @get external charCode: t => int = "charCode" - @get external ctrlKey: t => bool = "ctrlKey" - @send - external getModifierState: (t, string) => bool = "getModifierState" - @get external key: t => string = "key" - @get external keyCode: t => int = "keyCode" - @get external locale: t => string = "locale" - @get external location: t => int = "location" - @get external metaKey: t => bool = "metaKey" - @get external repeat: t => bool = "repeat" - @get external shiftKey: t => bool = "shiftKey" - @get external which: t => int = "which" -} - -module Focus = { - type tag - type t = synthetic - include MakeEventWithType({type t = t}) - @get @return(nullable) - external relatedTarget: t => option<{..}> = "relatedTarget" /* Should return Dom.eventTarget */ -} - -module Form = { - type tag - type t = synthetic - include MakeEventWithType({type t = t}) -} - -module Mouse = { - type tag - type t = synthetic - include MakeEventWithType({type t = t}) - @get external altKey: t => bool = "altKey" - @get external button: t => int = "button" - @get external buttons: t => int = "buttons" - @get external clientX: t => int = "clientX" - @get external clientY: t => int = "clientY" - @get external ctrlKey: t => bool = "ctrlKey" - @send - external getModifierState: (t, string) => bool = "getModifierState" - @get external metaKey: t => bool = "metaKey" - @get external movementX: t => int = "movementX" - @get external movementY: t => int = "movementY" - @get external pageX: t => int = "pageX" - @get external pageY: t => int = "pageY" - @get @return(nullable) - external relatedTarget: t => option<{..}> = "relatedTarget" /* Should return Dom.eventTarget */ - @get external screenX: t => int = "screenX" - @get external screenY: t => int = "screenY" - @get external shiftKey: t => bool = "shiftKey" -} - -module Selection = { - type tag - type t = synthetic - include MakeEventWithType({type t = t}) -} - -module Touch = { - type tag - type t = synthetic - include MakeEventWithType({type t = t}) - @get external altKey: t => bool = "altKey" - @get external changedTouches: t => {..} = "changedTouches" /* Should return Dom.touchList */ - @get external ctrlKey: t => bool = "ctrlKey" - @send - external getModifierState: (t, string) => bool = "getModifierState" - @get external metaKey: t => bool = "metaKey" - @get external shiftKey: t => bool = "shiftKey" - @get external targetTouches: t => {..} = "targetTouches" /* Should return Dom.touchList */ - @get external touches: t => {..} = "touches" /* Should return Dom.touchList */ -} - -module UI = { - type tag - type t = synthetic - include MakeEventWithType({type t = t}) - @get external detail: t => int = "detail" - @get external view: t => Dom.window = "view" /* Should return DOMAbstractView/WindowProxy */ -} - -module Wheel = { - type tag - type t = synthetic - include MakeEventWithType({type t = t}) - @get external deltaMode: t => int = "deltaMode" - @get external deltaX: t => float = "deltaX" - @get external deltaY: t => float = "deltaY" - @get external deltaZ: t => float = "deltaZ" -} - -module Media = { - type tag - type t = synthetic - include MakeEventWithType({type t = t}) -} - -module Image = { - type tag - type t = synthetic - include MakeEventWithType({type t = t}) -} - -module Animation = { - type tag - type t = synthetic - include MakeEventWithType({type t = t}) - @get external animationName: t => string = "animationName" - @get external pseudoElement: t => string = "pseudoElement" - @get external elapsedTime: t => float = "elapsedTime" -} - -module Transition = { - type tag - type t = synthetic - include MakeEventWithType({type t = t}) - @get external propertyName: t => string = "propertyName" - @get external pseudoElement: t => string = "pseudoElement" - @get external elapsedTime: t => float = "elapsedTime" -} diff --git a/tests/tests/src/reactEvent.resi b/tests/tests/src/reactEvent.resi deleted file mode 100644 index 44a6535aa8..0000000000 --- a/tests/tests/src/reactEvent.resi +++ /dev/null @@ -1,405 +0,0 @@ -/* 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. - - In each module, the type `t` commonly means "the type of that module" (OCaml convention). In our case, e.g. - `ReactEvent.Mouse.t` represents a ReactJS synthetic mouse event. You'd use it to type your props: - - ``` - type props = { - onClick: ReactEvent.Mouse.t => unit - }; - ``` - - All the methods and properties of a type of event are in the module, as seen below. - - Each module also has a `tag` type. You can ignore it; they're only needed by their `t` type. This way, we - get to allow a base `Synthetic` event module with generic methods. So e.g. even a mouse event (`Mouse.t`) - get to be passed to a generic handler: - - ``` - let handleClick = ({state, props}, event) => { - ReactEvent.Mouse.preventDefault(event); - ... - }; - let handleSubmit = ({state, props}, event) => { - /* this handler can be triggered by either a Keyboard or a Mouse event; conveniently use the generic - preventDefault */ - ReactEvent.Synthetic.preventDefault(event); - ... - }; - - let render = (_) => ; - ``` - - How to translate idioms from ReactJS: - - 1. myMouseEvent.preventDefault() -> ReactEvent.Mouse.preventDefault(myMouseEvent) - 2. myKeyboardEvent.which -> ReactEvent.Keyboard.which(myKeyboardEvent) - */ -type synthetic<'a> - -module Synthetic: { - type tag - type t = synthetic - @get external bubbles: synthetic<'a> => bool = "bubbles" - @get external cancelable: synthetic<'a> => bool = "cancelable" - @get - external currentTarget: synthetic<'a> => {..} = "currentTarget" - @get - external defaultPrevented: synthetic<'a> => bool = "defaultPrevented" - @get external eventPhase: synthetic<'a> => int = "eventPhase" - @get external isTrusted: synthetic<'a> => bool = "isTrusted" - @get - external nativeEvent: synthetic<'a> => {..} = "nativeEvent" - @send - external preventDefault: synthetic<'a> => unit = "preventDefault" - @send - external isDefaultPrevented: synthetic<'a> => bool = "isDefaultPrevented" - @send - external stopPropagation: synthetic<'a> => unit = "stopPropagation" - @send - external isPropagationStopped: synthetic<'a> => bool = "isPropagationStopped" - @get external target: synthetic<'a> => {..} = "target" - @get external timeStamp: synthetic<'a> => float = "timeStamp" - @get external type_: synthetic<'a> => string = "type" - @send external persist: synthetic<'a> => unit = "persist" -} - -/* Cast any event type to the general synthetic type. This is safe, since synthetic is more general */ -external toSyntheticEvent: synthetic<'a> => Synthetic.t = "%identity" - -module Clipboard: { - type tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" - @get external clipboardData: t => {..} = "clipboardData" /* Should return Dom.dataTransfer */ -} - -module Composition: { - type tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" - @get external data: t => string = "data" -} - -module Keyboard: { - type tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" - @get external altKey: t => bool = "altKey" - @get external charCode: t => int = "charCode" - @get external ctrlKey: t => bool = "ctrlKey" - @send - external getModifierState: (t, string) => bool = "getModifierState" - @get external key: t => string = "key" - @get external keyCode: t => int = "keyCode" - @get external locale: t => string = "locale" - @get external location: t => int = "location" - @get external metaKey: t => bool = "metaKey" - @get external repeat: t => bool = "repeat" - @get external shiftKey: t => bool = "shiftKey" - @get external which: t => int = "which" -} - -module Focus: { - type tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" - @get @return(nullable) - external relatedTarget: t => option<{..}> = "relatedTarget" /* Should return Dom.eventTarget */ -} - -module Form: { - type tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" -} - -module Mouse: { - type tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" - @get external altKey: t => bool = "altKey" - @get external button: t => int = "button" - @get external buttons: t => int = "buttons" - @get external clientX: t => int = "clientX" - @get external clientY: t => int = "clientY" - @get external ctrlKey: t => bool = "ctrlKey" - @send - external getModifierState: (t, string) => bool = "getModifierState" - @get external metaKey: t => bool = "metaKey" - @get external movementX: t => int = "movementX" - @get external movementY: t => int = "movementY" - @get external pageX: t => int = "pageX" - @get external pageY: t => int = "pageY" - @get @return(nullable) - external relatedTarget: t => option<{..}> = "relatedTarget" /* Should return Dom.eventTarget */ - @get external screenX: t => int = "screenX" - @get external screenY: t => int = "screenY" - @get external shiftKey: t => bool = "shiftKey" -} - -module Selection: { - type tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" -} - -module Touch: { - type tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" - @get external altKey: t => bool = "altKey" - @get external changedTouches: t => {..} = "changedTouches" /* Should return Dom.touchList */ - @get external ctrlKey: t => bool = "ctrlKey" - @send - external getModifierState: (t, string) => bool = "getModifierState" - @get external metaKey: t => bool = "metaKey" - @get external shiftKey: t => bool = "shiftKey" - @get external targetTouches: t => {..} = "targetTouches" /* Should return Dom.touchList */ - @get external touches: t => {..} = "touches" /* Should return Dom.touchList */ -} - -module UI: { - type tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" - @get external detail: t => int = "detail" - @get external view: t => Dom.window = "view" /* Should return DOMAbstractView/WindowProxy */ -} - -module Wheel: { - type tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" - @get external deltaMode: t => int = "deltaMode" - @get external deltaX: t => float = "deltaX" - @get external deltaY: t => float = "deltaY" - @get external deltaZ: t => float = "deltaZ" -} - -module Media: { - type tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" -} - -module Image: { - type tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" -} - -module Animation: { - type tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" - @get external animationName: t => string = "animationName" - @get external pseudoElement: t => string = "pseudoElement" - @get external elapsedTime: t => float = "elapsedTime" -} - -module Transition: { - type tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" - @get external propertyName: t => string = "propertyName" - @get external pseudoElement: t => string = "pseudoElement" - @get external elapsedTime: t => float = "elapsedTime" -} diff --git a/tests/tests/src/reactTestUtils.mjs b/tests/tests/src/reactTestUtils.mjs deleted file mode 100644 index 33c59321af..0000000000 --- a/tests/tests/src/reactTestUtils.mjs +++ /dev/null @@ -1,91 +0,0 @@ -// Generated by ReScript, PLEASE EDIT WITH CARE - -import * as Belt_Array from "rescript/lib/es6/Belt_Array.js"; -import * as Belt_Option from "rescript/lib/es6/Belt_Option.js"; -import * as Primitive_option from "rescript/lib/es6/Primitive_option.js"; -import * as TestUtils from "react-dom/test-utils"; - -function act(func) { - let reactFunc = () => { - func(); - }; - TestUtils.act(reactFunc); -} - -function actAsync(func) { - return TestUtils.act(() => func()); -} - -function changeWithValue(element, value) { - let event = { - target: { - value: value - } - }; - TestUtils.Simulate.change(element, event); -} - -function changeWithChecked(element, value) { - let event = { - target: { - checked: value - } - }; - TestUtils.Simulate.change(element, event); -} - -let Simulate = { - changeWithValue: changeWithValue, - changeWithChecked: changeWithChecked -}; - -function findBySelector(element, selector) { - return element.querySelector(selector); -} - -function findByAllSelector(element, selector) { - return Array.from(element.querySelectorAll(selector)); -} - -function findBySelectorAndTextContent(element, selector, content) { - return Belt_Array.getBy(Array.from(element.querySelectorAll(selector)), node => node.textContent === content); -} - -function findBySelectorAndPartialTextContent(element, selector, content) { - return Belt_Array.getBy(Array.from(element.querySelectorAll(selector)), node => node.textContent.includes(content)); -} - -let DOM = { - findBySelector: findBySelector, - findByAllSelector: findByAllSelector, - findBySelectorAndTextContent: findBySelectorAndTextContent, - findBySelectorAndPartialTextContent: findBySelectorAndPartialTextContent -}; - -function prepareContainer(container, param) { - let containerElement = document.createElement("div"); - Belt_Option.map(document.body, body => body.appendChild(containerElement)); - container.contents = Primitive_option.some(containerElement); -} - -function cleanupContainer(container, param) { - Belt_Option.map(container.contents, prim => { - prim.remove(); - }); - container.contents = undefined; -} - -function getContainer(container) { - return Belt_Option.getExn(container.contents); -} - -export { - act, - actAsync, - Simulate, - DOM, - prepareContainer, - cleanupContainer, - getContainer, -} -/* react-dom/test-utils Not a pure module */ diff --git a/tests/tests/src/reactTestUtils.res b/tests/tests/src/reactTestUtils.res deleted file mode 100644 index 74b7e62450..0000000000 --- a/tests/tests/src/reactTestUtils.res +++ /dev/null @@ -1,133 +0,0 @@ -type undefined = Js.undefined - -let undefined: undefined = Js.Undefined.empty - -@module("react-dom/test-utils") -external reactAct: (unit => undefined) => unit = "act" - -let act: (unit => unit) => unit = func => { - let reactFunc = () => { - func() - undefined - } - reactAct(reactFunc) -} - -@module("react-dom/test-utils") -external reactActAsync: (unit => Js.Promise.t<'a>) => Js.Promise.t = "act" - -let actAsync = func => { - let reactFunc = () => func() - reactActAsync(reactFunc) -} - -@module("react-dom/test-utils") -external isElement: 'element => bool = "isElement" - -@module("react-dom/test-utils") -external isElementOfType: ('element, React.component<'props>) => bool = "isElement" - -@module("react-dom/test-utils") -external isDOMComponent: 'element => bool = "isDOMComponent" - -@module("react-dom/test-utils") -external isCompositeComponent: 'element => bool = "isCompositeComponent" - -@module("react-dom/test-utils") -external isCompositeComponentWithType: ('element, React.component<'props>) => bool = - "isCompositeComponentWithType" - -module Simulate = { - @module("react-dom/test-utils") @scope("Simulate") - external click: Dom.element => unit = "click" - @module("react-dom/test-utils") @scope("Simulate") - external clickWithEvent: (Dom.element, 'event) => unit = "click" - @module("react-dom/test-utils") @scope("Simulate") - external change: Dom.element => unit = "change" - @module("react-dom/test-utils") @scope("Simulate") - external blur: Dom.element => unit = "blur" - @module("react-dom/test-utils") @scope("Simulate") - external changeWithEvent: (Dom.element, 'event) => unit = "change" - let changeWithValue = (element, value) => { - let event = { - "target": { - "value": value, - }, - } - changeWithEvent(element, event) - } - let changeWithChecked = (element, value) => { - let event = { - "target": { - "checked": value, - }, - } - changeWithEvent(element, event) - } - @module("react-dom/test-utils") @scope("Simulate") - external canPlay: Dom.element => unit = "canPlay" - @module("react-dom/test-utils") @scope("Simulate") - external timeUpdate: Dom.element => unit = "timeUpdate" - @module("react-dom/test-utils") @scope("Simulate") - external ended: Dom.element => unit = "ended" - @module("react-dom/test-utils") @scope("Simulate") - external focus: Dom.element => unit = "focus" -} - -@val external document: Dom.document = "document" - -@send -external querySelector: (Dom.element, string) => option = "querySelector" - -@send -external querySelectorAll: (Dom.element, string) => Js.Array.array_like = - "querySelectorAll" - -@get external textContent: Dom.element => string = "textContent" -@get external body: Dom.document => option = "body" -@send -external createElement: (Dom.document, string) => Dom.element = "createElement" -@send external remove: Dom.element => unit = "remove" -@send -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 = "value" - - let findBySelector = (element, selector) => querySelector(element, selector) - - let findByAllSelector = (element, selector) => querySelectorAll(element, selector) - - let findBySelectorAndTextContent = (element, selector, content) => - querySelectorAll(element, selector)->Array.getBy(node => node->textContent === content) - - let findBySelectorAndPartialTextContent = (element, selector, content) => - querySelectorAll(element, selector)->Array.getBy(node => - node->textContent->Js.String2.includes(content) - ) -} - -let prepareContainer = (container: ref>, ()) => { - open Belt - - let containerElement = document->createElement("div") - let _ = document->body->Option.map(body => body->appendChild(containerElement)) - container := Some(containerElement) -} - -let cleanupContainer = (container: ref>, ()) => { - open Belt - - let _ = container.contents->Option.map(remove) - container := None -} - -let getContainer = container => { - open Belt - container.contents->Option.getExn -} diff --git a/tests/tests/src/reactTestUtils.resi b/tests/tests/src/reactTestUtils.resi deleted file mode 100644 index 3e9b1d81fc..0000000000 --- a/tests/tests/src/reactTestUtils.resi +++ /dev/null @@ -1,56 +0,0 @@ -let act: (unit => unit) => unit - -let actAsync: (unit => Js.Promise.t<'a>) => Js.Promise.t - -@module("react-dom/test-utils") -external isElement: 'element => bool = "isElement" - -@module("react-dom/test-utils") -external isElementOfType: ('element, React.component<'props>) => bool = "isElement" - -@module("react-dom/test-utils") -external isDOMComponent: 'element => bool = "isDOMComponent" - -@module("react-dom/test-utils") -external isCompositeComponent: 'element => bool = "isCompositeComponent" - -@module("react-dom/test-utils") -external isCompositeComponentWithType: ('element, React.component<'props>) => bool = - "isCompositeComponentWithType" - -module Simulate: { - @module("react-dom/test-utils") @scope("Simulate") - external click: Dom.element => unit = "click" - @module("react-dom/test-utils") @scope("Simulate") - external clickWithEvent: (Dom.element, 'event) => unit = "click" - @module("react-dom/test-utils") @scope("Simulate") - external change: Dom.element => unit = "change" - @module("react-dom/test-utils") @scope("Simulate") - external blur: Dom.element => unit = "blur" - @module("react-dom/test-utils") @scope("Simulate") - external changeWithEvent: (Dom.element, 'event) => unit = "change" - let changeWithValue: (Dom.element, string) => unit - let changeWithChecked: (Dom.element, bool) => unit - @module("react-dom/test-utils") @scope("Simulate") - external canPlay: Dom.element => unit = "canPlay" - @module("react-dom/test-utils") @scope("Simulate") - external timeUpdate: Dom.element => unit = "timeUpdate" - @module("react-dom/test-utils") @scope("Simulate") - external ended: Dom.element => unit = "ended" - @module("react-dom/test-utils") @scope("Simulate") - external focus: Dom.element => unit = "focus" -} - -module DOM: { - @return(nullable) @get - external value: Dom.element => option = "value" - - let findBySelector: (Dom.element, string) => option - let findByAllSelector: (Dom.element, string) => array - let findBySelectorAndTextContent: (Dom.element, string, string) => option - let findBySelectorAndPartialTextContent: (Dom.element, string, string) => option -} - -let prepareContainer: (ref>, unit) => unit -let cleanupContainer: (ref>, unit) => unit -let getContainer: ref> => Dom.element diff --git a/tests/tests/src/reasonReact.mjs b/tests/tests/src/reasonReact.mjs deleted file mode 100644 index e1f8ab1ec5..0000000000 --- a/tests/tests/src/reasonReact.mjs +++ /dev/null @@ -1,137 +0,0 @@ -// Generated by ReScript, PLEASE EDIT WITH CARE - -import * as React from "react"; -import * as Js_array from "rescript/lib/es6/Js_array.js"; - -function createDomElement(s, props, children) { - let vararg = Js_array.concat(children, [ - s, - props - ]); - return React.createElement.apply(null, vararg); -} - -function anyToUnit(param) { - -} - -function anyToTrue(param) { - return true; -} - -function willReceivePropsDefault(param) { - return param.state; -} - -function renderDefault(_self) { - return "RenderNotImplemented"; -} - -function initialStateDefault() { - -} - -function reducerDefault(_action, _state) { - return "NoUpdate"; -} - -function basicComponent(debugName) { - return { - debugName: debugName, - reactClassInternal: debugName, - handedOffState: { - contents: undefined - }, - willReceiveProps: willReceivePropsDefault, - didMount: anyToUnit, - didUpdate: anyToUnit, - willUnmount: anyToUnit, - willUpdate: anyToUnit, - shouldUpdate: anyToTrue, - render: renderDefault, - initialState: initialStateDefault, - retainedProps: undefined, - reducer: reducerDefault, - jsElementWrapped: undefined - }; -} - -let statelessComponent = basicComponent; - -let statelessComponentWithRetainedProps = basicComponent; - -let reducerComponent = basicComponent; - -let reducerComponentWithRetainedProps = basicComponent; - -function element(keyOpt, refOpt, component) { - let key = keyOpt !== undefined ? keyOpt : undefined; - let ref = refOpt !== undefined ? refOpt : undefined; - let element$1 = { - TAG: "Element", - _0: component - }; - let jsElementWrapped = component.jsElementWrapped; - if (jsElementWrapped !== undefined) { - return jsElementWrapped(key, ref); - } else { - return React.createElement(component.reactClassInternal, { - key: key, - ref: ref, - reasonProps: element$1 - }); - } -} - -function wrapReasonForJs(component, jsPropsToReason) { - let uncurriedJsPropsToReason = jsProps => jsPropsToReason(jsProps); - component.reactClassInternal.prototype.jsPropsToReason = uncurriedJsPropsToReason; - return component.reactClassInternal; -} - -let dummyInteropComponent = basicComponent("interop"); - -function wrapJsForReason(reactClass, props, children) { - let jsElementWrapped = (extra, extra$1) => { - let props$1 = Object.assign(Object.assign({}, props), { - ref: extra$1, - key: extra - }); - let varargs = Js_array.concat(children, [ - reactClass, - props$1 - ]); - return React.createElement.apply(null, varargs); - }; - return { - debugName: dummyInteropComponent.debugName, - reactClassInternal: dummyInteropComponent.reactClassInternal, - handedOffState: dummyInteropComponent.handedOffState, - willReceiveProps: dummyInteropComponent.willReceiveProps, - didMount: dummyInteropComponent.didMount, - didUpdate: dummyInteropComponent.didUpdate, - willUnmount: dummyInteropComponent.willUnmount, - willUpdate: dummyInteropComponent.willUpdate, - shouldUpdate: dummyInteropComponent.shouldUpdate, - render: dummyInteropComponent.render, - initialState: dummyInteropComponent.initialState, - retainedProps: dummyInteropComponent.retainedProps, - reducer: dummyInteropComponent.reducer, - jsElementWrapped: jsElementWrapped - }; -} - -let Router; - -export { - statelessComponent, - statelessComponentWithRetainedProps, - reducerComponent, - reducerComponentWithRetainedProps, - element, - wrapReasonForJs, - createDomElement, - wrapJsForReason, - Router, -} -/* dummyInteropComponent Not a pure module */ diff --git a/tests/tests/src/reasonReact.res b/tests/tests/src/reasonReact.res deleted file mode 100644 index c86c69ef87..0000000000 --- a/tests/tests/src/reasonReact.res +++ /dev/null @@ -1,310 +0,0 @@ -// Prevent warning about the `retainedProps` field being defined in both -// `self` and `componentSpec` record types. -@@warning("-30") - -type reactClass - -type jsProps - -type reactElement = React.element - -type reactRef - -@val external null: reactElement = "null" - -external string: string => reactElement = "%identity" - -external array: array => reactElement = "%identity" - -external refToJsObj: reactRef => {..} = "%identity" - -@variadic @val @module("react") -external createElement: (reactClass, ~props: {..}=?, array) => reactElement = - "createElement" - -@variadic @module("react") -external cloneElement: (reactElement, ~props: {..}=?, array) => reactElement = - "cloneElement" - -@val @module("react") -external createElementVerbatim: 'a = "createElement" - -let createDomElement = (s, ~props, children) => { - let vararg = Js.Array.concat(children, [Obj.magic(s), Obj.magic(props)]) - /* Use varargs to avoid warnings on duplicate keys in children */ - Obj.magic(createElementVerbatim)["apply"](Js.Nullable.null, vararg) -} - -@val external magicNull: 'a = "null" - -type reactClassInternal = reactClass - -type renderNotImplemented = RenderNotImplemented - -type stateless = unit - -type noRetainedProps = unit - -type actionless = unit - -/* ** - * Elements are what JSX blocks become. They represent the *potential* for a - * component instance and state to be created / updated. They are not yet - * instances. - */ -type rec element = Element(component<'state, 'retainedProps, 'action>): element -and jsPropsToReason<'jsProps, 'state, 'retainedProps, 'action> = 'jsProps => component< - 'state, - 'retainedProps, - 'action, -> -and uncurriedJsPropsToReason<'jsProps, 'state, 'retainedProps, 'action> = 'jsProps => component< - 'state, - 'retainedProps, - 'action, -> -/* ** - * Type of hidden field for Reason components that use JS components - */ -and jsElementWrapped = option< - (~key: Js.nullable, ~ref: Js.nullable => unit>) => reactElement, -> -and update<'state, 'retainedProps, 'action> = - | NoUpdate - | Update('state) - | SideEffects(self<'state, 'retainedProps, 'action> => unit) - | UpdateWithSideEffects('state, self<'state, 'retainedProps, 'action> => unit) -/* ** - * Granularly types state, and initial state as being independent, so that we - * may include a template that all instances extend from. - */ -and componentSpec<'state, 'initialState, 'retainedProps, 'initialRetainedProps, 'action> = { - debugName: string, - reactClassInternal: reactClassInternal, - /* Keep here as a way to prove that the API may be implemented soundly */ - mutable handedOffState: ref>, - willReceiveProps: self<'state, 'retainedProps, 'action> => 'state, - didMount: self<'state, 'retainedProps, 'action> => unit, - didUpdate: oldNewSelf<'state, 'retainedProps, 'action> => unit, - willUnmount: self<'state, 'retainedProps, 'action> => unit, - willUpdate: oldNewSelf<'state, 'retainedProps, 'action> => unit, - shouldUpdate: oldNewSelf<'state, 'retainedProps, 'action> => bool, - render: self<'state, 'retainedProps, 'action> => reactElement, - initialState: unit => 'initialState, - retainedProps: 'initialRetainedProps, - reducer: ('action, 'state) => update<'state, 'retainedProps, 'action>, - jsElementWrapped: jsElementWrapped, -} -and component<'state, 'retainedProps, 'action> = componentSpec< - 'state, - 'state, - 'retainedProps, - 'retainedProps, - 'action, -> -and self<'state, 'retainedProps, 'action> = { - handle: 'payload. (('payload, self<'state, 'retainedProps, 'action>) => unit, 'payload) => unit, - state: 'state, - retainedProps: 'retainedProps, - send: 'action => unit, - onUnmount: (unit => unit) => unit, -} -and oldNewSelf<'state, 'retainedProps, 'action> = { - oldSelf: self<'state, 'retainedProps, 'action>, - newSelf: self<'state, 'retainedProps, 'action>, -} - -type rec jsComponentThis<'state, 'props, 'retainedProps, 'action> = { - "state": totalState<'state, 'retainedProps, 'action>, - "props": {"reasonProps": 'props}, - "setState": @meth ( - ( - totalState<'state, 'retainedProps, 'action>, - 'props, - ) => totalState<'state, 'retainedProps, 'action>, - Js.nullable unit>, - ) => unit, - "jsPropsToReason": option>, -} -/* ** - * `totalState` tracks all of the internal reason API bookkeeping. - * - * Since we will mutate `totalState` in `shouldComponentUpdate`, and since - * there's no guarantee that returning true from `shouldComponentUpdate` - * guarantees that a component's update *actually* takes place (it could get - * rolled back by Fiber etc), then we should put all properties that we - * mutate directly on the totalState, so that when Fiber makes backup shallow - * backup copies of `totalState`, our changes can be rolled back correctly - * even when we mutate them. - */ -and totalState<'state, 'retainedProps, 'action> = {"reasonState": 'state} - -let anyToUnit = _ => () - -let anyToTrue = _ => true - -let willReceivePropsDefault = ({state}) => state - -let renderDefault = _self => string("RenderNotImplemented") - -let initialStateDefault = () => () - -let reducerDefault: ('action, 'state) => update<'state, 'retainedProps, 'action> = ( - _action, - _state, -) => NoUpdate - -let convertPropsIfTheyreFromJs = (props, jsPropsToReason, debugName) => { - let props = Obj.magic(props) - switch (Js.Nullable.toOption(props["reasonProps"]), jsPropsToReason) { - | (Some(props), _) => props - | (None, Some(toReasonProps)) => Element(toReasonProps(props)) - | (None, None) => - throw( - Invalid_argument( - "A JS component called the Reason component " ++ - (debugName ++ - " which didn't implement the JS->Reason React props conversion."), - ), - ) - } -} - -// Old reason-react sources converted from .re syntax. -// The OCaml object system is not available in ReScript anymore -// let createClass = (type reasonState retainedProps action, debugName): reactClass => -// ReasonReactOptimizedCreateClass.createClass(. Pexp_object not implemented in printer) -let createClass = Obj.magic - -let basicComponent = debugName => { - let componentTemplate = { - reactClassInternal: createClass(debugName), - debugName, - /* Keep here as a way to prove that the API may be implemented soundly */ - handedOffState: { - contents: None, - }, - didMount: anyToUnit, - willReceiveProps: willReceivePropsDefault, - didUpdate: anyToUnit, - willUnmount: anyToUnit, - willUpdate: anyToUnit, - /* ** - * Called when component will certainly mount at some point - and may be - * called on the sever for server side React rendering. - */ - shouldUpdate: anyToTrue, - render: renderDefault, - initialState: initialStateDefault, - reducer: reducerDefault, - jsElementWrapped: None, - retainedProps: (), - } - componentTemplate -} - -let statelessComponent = (debugName): component => - basicComponent(debugName) - -let statelessComponentWithRetainedProps = (debugName): componentSpec< - stateless, - stateless, - 'retainedProps, - noRetainedProps, - actionless, -> => basicComponent(debugName) - -let reducerComponent = (debugName): componentSpec< - 'state, - stateless, - noRetainedProps, - noRetainedProps, - 'action, -> => basicComponent(debugName) - -let reducerComponentWithRetainedProps = (debugName): componentSpec< - 'state, - stateless, - 'retainedProps, - noRetainedProps, - 'action, -> => basicComponent(debugName) - -/* ** - * Convenience for creating React elements before we have a better JSX transform. Hopefully this makes it - * usable to build some components while waiting to migrate the JSX transform to the next API. - * - * Constrain the component here instead of relying on the Element constructor which would lead to confusing - * error messages. - */ -let element = ( - ~key: string=Obj.magic(Js.Nullable.undefined), - ~ref: Js.nullable => unit=Obj.magic(Js.Nullable.undefined), - component: component<'state, 'retainedProps, 'action>, -) => { - let element = Element(component) - switch component.jsElementWrapped { - | Some(jsElementWrapped) => - jsElementWrapped(~key=Js.Nullable.return(key), ~ref=Js.Nullable.return(ref)) - | None => - createElement( - component.reactClassInternal, - ~props={"key": key, "ref": ref, "reasonProps": element}, - [], - ) - } -} - -let wrapReasonForJs = ( - ~component, - jsPropsToReason: jsPropsToReason<'jsProps, 'state, 'retainedProps, 'action>, -) => { - let jsPropsToReason: jsPropsToReason = Obj.magic( - jsPropsToReason, - ) /* cast 'jsProps to jsProps */ - let uncurriedJsPropsToReason: uncurriedJsPropsToReason< - jsProps, - 'state, - 'retainedProps, - 'action, - > = jsProps => jsPropsToReason(jsProps) - Obj.magic(component.reactClassInternal)["prototype"]["jsPropsToReason"] = Some( - uncurriedJsPropsToReason, - ) - component.reactClassInternal -} - -module WrapProps = { - /* We wrap the props for reason->reason components, as a marker that "these props were passed from another - reason component" */ - let wrapProps = ( - ~reactClass, - ~props, - children, - ~key: Js.nullable, - ~ref: Js.nullable => unit>, - ) => { - let props = Js.Obj.assign( - Js.Obj.assign(Js.Obj.empty(), Obj.magic(props)), - {"ref": ref, "key": key}, - ) - let varargs = Js.Array.concat(Obj.magic(children), [Obj.magic(reactClass), Obj.magic(props)]) - /* Use varargs under the hood */ - Obj.magic(createElementVerbatim)["apply"](Js.Nullable.null, varargs) - } - let dummyInteropComponent = basicComponent("interop") - let wrapJsForReason = (~reactClass, ~props, children): component< - stateless, - noRetainedProps, - _, - > => { - let jsElementWrapped = Some(wrapProps(~reactClass, ~props, children, ...)) - {...dummyInteropComponent, jsElementWrapped} - } -} - -let wrapJsForReason = WrapProps.wrapJsForReason - -@module("react") external fragment: 'a = "Fragment" - -module Router = ReasonReactRouter diff --git a/tests/tests/src/reasonReact.resi b/tests/tests/src/reasonReact.resi deleted file mode 100644 index 89d3b7f58a..0000000000 --- a/tests/tests/src/reasonReact.resi +++ /dev/null @@ -1,214 +0,0 @@ -/* ** - * This API assumes that JSX will desugar into: - * - * ReasonReact.element( - * Foo.make(~key, ~ref, ~attr1=val1, ~attrn=valn, [| |] - * ) - */ - -type reactClass - -type reactElement = React.element - -type reactRef - -@val external null: reactElement = "null" - -external string: string => reactElement = "%identity" - -external array: array => reactElement = "%identity" - -external refToJsObj: reactRef => {..} = "%identity" - -/* This should _not_ be used directly, unless you're passing a class like this: - - switch (actionsClass) { - | Some(actions) => - ReasonReact.createElement( - actions, - ~props={ - "className": "hi" - }, - [|whatever|], - ) - } - - In every other case, you should be using the JSX - */ -@variadic @val @module("react") -external createElement: (reactClass, ~props: {..}=?, array) => reactElement = - "createElement" - -@variadic @module("react") -external cloneElement: (reactElement, ~props: {..}=?, array) => reactElement = - "cloneElement" - -type renderNotImplemented = RenderNotImplemented - -/* ** - * A stateless component is a component with state of type unit. This cannot be - * abstract for now, because a stateless component's willReceiveProps needs to - * return the state, aka unit. We can provide a helper - * ReasonReact.statelessReturn that's of type `stateless`, but that's verbose - */ -type stateless = unit - -type noRetainedProps - -/* ** An actionless component is a component with actions of type unit */ -type actionless = unit - -/* Control how a state update is performed. - The state can be updated of left unchanged. - Side effects can be specified and are scheduled for later execution. - Note: when a side effect is scheduled, it's added to a queue of existing pending side effects. - All the side effects are performed in batch after all the state updates have been performed, - in the same order in which they were scheduled, just before shouldUpdate is called. */ -type rec update<'state, 'retainedProps, 'action> = - | /* Don't update the state. */ - NoUpdate - /* Update the state with the given one. */ - | Update('state) - /* Perform side effects without updating state, and don't trigger a re-render. - Do not prevent a re-render either, if one was scheduled to happen. - The side effects function is invoked when all the updates have completed. */ - | SideEffects(self<'state, 'retainedProps, 'action> => unit) - /* Update the state and perform side effects. - The side effects function is invoked when all the updates have completed. */ - | UpdateWithSideEffects('state, self<'state, 'retainedProps, 'action> => unit) -and self<'state, 'retainedProps, 'action> = { - /* ** - * Call a handler function. - * - * The callback is passed the payload and current state immediately. - * Note: the callback typically performs side effects, since it returns nothing. - */ - handle: 'payload. (('payload, self<'state, 'retainedProps, 'action>) => unit, 'payload) => unit, - state: 'state, - retainedProps: 'retainedProps, - send: 'action => unit, - onUnmount: (unit => unit) => unit, -} - -type reactClassInternal - -/* ** For internal use only */ -type jsElementWrapped - -type oldNewSelf<'state, 'retainedProps, 'action> = { - oldSelf: self<'state, 'retainedProps, 'action>, - newSelf: self<'state, 'retainedProps, 'action>, -} - -type rec componentSpec<'state, 'initialState, 'retainedProps, 'initialRetainedProps, 'action> = { - debugName: string, - reactClassInternal: reactClassInternal, - /* Keep here as a way to prove that the API may be implemented soundly */ - mutable handedOffState: ref>, - /* ** Callback invoked when the component receives new props or state. - * Note: this callback must not perform side effects. - */ - willReceiveProps: self<'state, 'retainedProps, 'action> => 'state, - didMount: self<'state, 'retainedProps, 'action> => unit, - didUpdate: oldNewSelf<'state, 'retainedProps, 'action> => unit, - willUnmount: self<'state, 'retainedProps, 'action> => unit, - willUpdate: oldNewSelf<'state, 'retainedProps, 'action> => unit, - shouldUpdate: oldNewSelf<'state, 'retainedProps, 'action> => bool, - render: self<'state, 'retainedProps, 'action> => reactElement, - initialState: unit => 'initialState, - retainedProps: 'initialRetainedProps, - /* ** Reducer callback. - * - * The callback is invoked by the reduce function contained in self. - * A state update is scheduled based on the action passed, and added to the queue of pending updates. - * The state received will be the resulting one after the pending updates have been executed. - * - * Note: this callback must not perform side effects. - * If side effects are required, they should be contained in a - * side-effectful function specified in the returned update. - */ - reducer: ('action, 'state) => update<'state, 'retainedProps, 'action>, - jsElementWrapped: jsElementWrapped, -} -and component<'state, 'retainedProps, 'action> = componentSpec< - 'state, - 'state, - 'retainedProps, - 'retainedProps, - 'action, -> - -/* ** Create a stateless component: i.e. a component where state has type stateless. */ -let statelessComponent: string => componentSpec< - stateless, - stateless, - noRetainedProps, - noRetainedProps, - actionless, -> - -let statelessComponentWithRetainedProps: string => componentSpec< - stateless, - stateless, - 'retainedProps, - noRetainedProps, - actionless, -> - -let reducerComponent: string => componentSpec< - 'state, - stateless, - noRetainedProps, - noRetainedProps, - 'action, -> - -let reducerComponentWithRetainedProps: string => componentSpec< - 'state, - stateless, - 'retainedProps, - noRetainedProps, - 'action, -> - -let element: ( - ~key: string=?, - ~ref: Js.nullable => unit=?, - component<'state, 'retainedProps, 'action>, -) => reactElement - -type jsPropsToReason<'jsProps, 'state, 'retainedProps, 'action> = 'jsProps => component< - 'state, - 'retainedProps, - 'action, -> - -/* ** - * We *under* constrain the kind of component spec this accepts because we actually extend the *originally* - * defined component. It uses mutation on the original component, so that even if it is extended with - * {...component}, all extensions will also see the underlying js class. I can sleep at night because js - * interop is integrating with untyped, code and it is *possible* to create pure-ReasonReact apps without JS - * interop entirely. */ -let wrapReasonForJs: ( - ~component: componentSpec<'state, 'initialState, 'retainedProps, 'initialRetainedProps, 'action>, - jsPropsToReason<_>, -) => reactClass - -@deprecated(" -Were you using this because you needed to pass a children array reference to a DOM element? We now support children spread for DOM elements: `
...children
`. -Alternatively, if you're using this because the prop name contains a hyphen, please use `ReactDOMRe.createElementVariadic` instead.") -let createDomElement: (string, ~props: {..}, array) => reactElement - -/** - * Wrap props into a JS component - * Use for interop when Reason components use JS components - */ -let wrapJsForReason: ( - ~reactClass: reactClass, - ~props: 'a, - 'b, -) => component - -@module("react") external fragment: 'a = "Fragment" - -module Router = ReasonReactRouter diff --git a/tests/tests/src/reasonReactCompat.mjs b/tests/tests/src/reasonReactCompat.mjs deleted file mode 100644 index 0080545c14..0000000000 --- a/tests/tests/src/reasonReactCompat.mjs +++ /dev/null @@ -1,13 +0,0 @@ -// Generated by ReScript, PLEASE EDIT WITH CARE - -import * as ReasonReact from "./reasonReact.mjs"; - -let wrapReactForReasonReact = ReasonReact.wrapJsForReason; - -let wrapReasonReactForReact = ReasonReact.wrapReasonForJs; - -export { - wrapReactForReasonReact, - wrapReasonReactForReact, -} -/* ReasonReact Not a pure module */ diff --git a/tests/tests/src/reasonReactCompat.res b/tests/tests/src/reasonReactCompat.res deleted file mode 100644 index 3118ab160c..0000000000 --- a/tests/tests/src/reasonReactCompat.res +++ /dev/null @@ -1,10 +0,0 @@ -external componentToReasonReactClass: React.component<'props> => ReasonReact.reactClass = - "%identity" - -external reasonReactClassToComponent: ReasonReact.reactClass => React.component<'props> = - "%identity" -let wrapReactForReasonReact = (component, props, children) => - ReasonReact.wrapJsForReason(~reactClass=componentToReasonReactClass(component), ~props, children) - -let wrapReasonReactForReact = (~component, propsConverter) => - reasonReactClassToComponent(ReasonReact.wrapReasonForJs(~component, propsConverter)) diff --git a/tests/tests/src/reasonReactCompat.resi b/tests/tests/src/reasonReactCompat.resi deleted file mode 100644 index bb6e9c257c..0000000000 --- a/tests/tests/src/reasonReactCompat.resi +++ /dev/null @@ -1,14 +0,0 @@ -let wrapReactForReasonReact: ( - React.component<'props>, - 'props, - 'children, -) => ReasonReact.component< - ReasonReact.stateless, - ReasonReact.noRetainedProps, - ReasonReact.actionless, -> - -let wrapReasonReactForReact: ( - ~component: ReasonReact.componentSpec<'a, 'b, 'c, 'd, 'e>, - ReasonReact.jsPropsToReason<'props, 'g, 'h, 'i>, -) => React.component<'props> diff --git a/tests/tests/src/reasonReactOptimizedCreateClass.mjs b/tests/tests/src/reasonReactOptimizedCreateClass.mjs deleted file mode 100644 index 1f5612b73c..0000000000 --- a/tests/tests/src/reasonReactOptimizedCreateClass.mjs +++ /dev/null @@ -1,894 +0,0 @@ -// Generated by ReScript, PLEASE EDIT WITH CARE - -import * as React from "react"; - -function _assign(prim0, prim1) { - return Object.assign(prim0, prim1); -} - -let emptyObject = {}; - -/** - * Copyright 2013-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -// 'use strict'; - -// var _assign = require('object-assign'); - -// var emptyObject = require('emptyObject'); -// var _invariant = require('invariant'); - -// if (process.env.NODE_ENV !== 'production') { -// var warning = require('fbjs/lib/warning'); -// } - -var MIXINS_KEY = 'mixins'; - -// Helper function to allow the creation of anonymous functions which do not -// have .name set to the name of the variable being assigned to. -function identity(fn) { - return fn; -} - -var ReactPropTypeLocationNames; -// if (process.env.NODE_ENV !== 'production') { -// ReactPropTypeLocationNames = { -// prop: 'prop', -// context: 'context', -// childContext: 'child context' -// }; -// } else { - ReactPropTypeLocationNames = {}; -// } -; - -let factory = (function factory(ReactComponent, isValidElement, ReactNoopUpdateQueue) { - /** - * Policies that describe methods in \`ReactClassInterface\`. - */ - - var injectedMixins = []; - - /** - * Composite components are higher-level components that compose other composite - * or host components. - * - * To create a new type of \`ReactClass\`, pass a specification of - * your new class to \`React.createClass\`. The only requirement of your class - * specification is that you implement a \`render\` method. - * - * var MyComponent = React.createClass({ - * render: function() { - * return
Hello World
; - * } - * }); - * - * The class specification supports a specific protocol of methods that have - * special meaning (e.g. \`render\`). See \`ReactClassInterface\` for - * more the comprehensive protocol. Any other properties and methods in the - * class specification will be available on the prototype. - * - * @interface ReactClassInterface - * @internal - */ - var ReactClassInterface = { - /** - * An array of Mixin objects to include when defining your component. - * - * @type {array} - * @optional - */ - mixins: 'DEFINE_MANY', - - /** - * An object containing properties and methods that should be defined on - * the component's constructor instead of its prototype (static methods). - * - * @type {object} - * @optional - */ - statics: 'DEFINE_MANY', - - /** - * Definition of prop types for this component. - * - * @type {object} - * @optional - */ - propTypes: 'DEFINE_MANY', - - /** - * Definition of context types for this component. - * - * @type {object} - * @optional - */ - contextTypes: 'DEFINE_MANY', - - /** - * Definition of context types this component sets for its children. - * - * @type {object} - * @optional - */ - childContextTypes: 'DEFINE_MANY', - - // ==== Definition methods ==== - - /** - * Invoked when the component is mounted. Values in the mapping will be set on - * \`this.props\` if that prop is not specified (i.e. using an \`in\` check). - * - * This method is invoked before \`getInitialState\` and therefore cannot rely - * on \`this.state\` or use \`this.setState\`. - * - * @return {object} - * @optional - */ - getDefaultProps: 'DEFINE_MANY_MERGED', - - /** - * Invoked once before the component is mounted. The return value will be used - * as the initial value of \`this.state\`. - * - * getInitialState: function() { - * return { - * isOn: false, - * fooBaz: new BazFoo() - * } - * } - * - * @return {object} - * @optional - */ - getInitialState: 'DEFINE_MANY_MERGED', - - /** - * @return {object} - * @optional - */ - getChildContext: 'DEFINE_MANY_MERGED', - - /** - * Uses props from \`this.props\` and state from \`this.state\` to render the - * structure of the component. - * - * No guarantees are made about when or how often this method is invoked, so - * it must not have side effects. - * - * render: function() { - * var name = this.props.name; - * return
Hello, {name}!
; - * } - * - * @return {ReactComponent} - * @required - */ - render: 'DEFINE_ONCE', - - // ==== Delegate methods ==== - - /** - * Invoked when the component is initially created and about to be mounted. - * This may have side effects, but any external subscriptions or data created - * by this method must be cleaned up in \`componentWillUnmount\`. - * - * @optional - */ - componentWillMount: 'DEFINE_MANY', - - /** - * Invoked when the component has been mounted and has a DOM representation. - * However, there is no guarantee that the DOM node is in the document. - * - * Use this as an opportunity to operate on the DOM when the component has - * been mounted (initialized and rendered) for the first time. - * - * @param {DOMElement} rootNode DOM element representing the component. - * @optional - */ - componentDidMount: 'DEFINE_MANY', - - /** - * Invoked before the component receives new props. - * - * Use this as an opportunity to react to a prop transition by updating the - * state using \`this.setState\`. Current props are accessed via \`this.props\`. - * - * componentWillReceiveProps: function(nextProps, nextContext) { - * this.setState({ - * likesIncreasing: nextProps.likeCount > this.props.likeCount - * }); - * } - * - * NOTE: There is no equivalent \`componentWillReceiveState\`. An incoming prop - * transition may cause a state change, but the opposite is not true. If you - * need it, you are probably looking for \`componentWillUpdate\`. - * - * @param {object} nextProps - * @optional - */ - componentWillReceiveProps: 'DEFINE_MANY', - - /** - * Invoked while deciding if the component should be updated as a result of - * receiving new props, state and/or context. - * - * Use this as an opportunity to \`return false\` when you're certain that the - * transition to the new props/state/context will not require a component - * update. - * - * shouldComponentUpdate: function(nextProps, nextState, nextContext) { - * return !equal(nextProps, this.props) || - * !equal(nextState, this.state) || - * !equal(nextContext, this.context); - * } - * - * @param {object} nextProps - * @param {?object} nextState - * @param {?object} nextContext - * @return {boolean} True if the component should update. - * @optional - */ - shouldComponentUpdate: 'DEFINE_ONCE', - - /** - * Invoked when the component is about to update due to a transition from - * \`this.props\`, \`this.state\` and \`this.context\` to \`nextProps\`, \`nextState\` - * and \`nextContext\`. - * - * Use this as an opportunity to perform preparation before an update occurs. - * - * NOTE: You **cannot** use \`this.setState()\` in this method. - * - * @param {object} nextProps - * @param {?object} nextState - * @param {?object} nextContext - * @param {ReactReconcileTransaction} transaction - * @optional - */ - componentWillUpdate: 'DEFINE_MANY', - - /** - * Invoked when the component's DOM representation has been updated. - * - * Use this as an opportunity to operate on the DOM when the component has - * been updated. - * - * @param {object} prevProps - * @param {?object} prevState - * @param {?object} prevContext - * @param {DOMElement} rootNode DOM element representing the component. - * @optional - */ - componentDidUpdate: 'DEFINE_MANY', - - /** - * Invoked when the component is about to be removed from its parent and have - * its DOM representation destroyed. - * - * Use this as an opportunity to deallocate any external resources. - * - * NOTE: There is no \`componentDidUnmount\` since your component will have been - * destroyed by that point. - * - * @optional - */ - componentWillUnmount: 'DEFINE_MANY', - - // ==== Advanced methods ==== - - /** - * Updates the component's currently mounted DOM representation. - * - * By default, this implements React's rendering and reconciliation algorithm. - * Sophisticated clients may wish to override this. - * - * @param {ReactReconcileTransaction} transaction - * @internal - * @overridable - */ - updateComponent: 'OVERRIDE_BASE' - }; - - /** - * Mapping from class specification keys to special processing functions. - * - * Although these are declared like instance properties in the specification - * when defining classes using \`React.createClass\`, they are actually static - * and are accessible on the constructor instead of the prototype. Despite - * being static, they must be defined outside of the "statics" key under - * which all other static methods are defined. - */ - var RESERVED_SPEC_KEYS = { - displayName: function(Constructor, displayName) { - Constructor.displayName = displayName; - }, - mixins: function(Constructor, mixins) { - if (mixins) { - for (var i = 0; i < mixins.length; i++) { - mixSpecIntoComponent(Constructor, mixins[i]); - } - } - }, - childContextTypes: function(Constructor, childContextTypes) { - // if (process.env.NODE_ENV !== 'production') { - // validateTypeDef(Constructor, childContextTypes, 'childContext'); - // } - Constructor.childContextTypes = _assign( - {}, - Constructor.childContextTypes, - childContextTypes - ); - }, - contextTypes: function(Constructor, contextTypes) { - // if (process.env.NODE_ENV !== 'production') { - // validateTypeDef(Constructor, contextTypes, 'context'); - // } - Constructor.contextTypes = _assign( - {}, - Constructor.contextTypes, - contextTypes - ); - }, - /** - * Special case getDefaultProps which should move into statics but requires - * automatic merging. - */ - getDefaultProps: function(Constructor, getDefaultProps) { - if (Constructor.getDefaultProps) { - Constructor.getDefaultProps = createMergedResultFunction( - Constructor.getDefaultProps, - getDefaultProps - ); - } else { - Constructor.getDefaultProps = getDefaultProps; - } - }, - propTypes: function(Constructor, propTypes) { - // if (process.env.NODE_ENV !== 'production') { - // validateTypeDef(Constructor, propTypes, 'prop'); - // } - Constructor.propTypes = _assign({}, Constructor.propTypes, propTypes); - }, - statics: function(Constructor, statics) { - mixStaticSpecIntoComponent(Constructor, statics); - }, - autobind: function() {} - }; - - function validateTypeDef(Constructor, typeDef, location) { - for (var propName in typeDef) { - // if (typeDef.hasOwnProperty(propName)) { - // // use a warning instead of an _invariant so components - // // don't show up in prod but only in __DEV__ - // // if (process.env.NODE_ENV !== 'production') { - // // warning( - // // typeof typeDef[propName] === 'function', - // // '%s: %s type \`%s\` is invalid; it must be a function, usually from ' + - // // 'React.PropTypes.', - // // Constructor.displayName || 'ReactClass', - // // ReactPropTypeLocationNames[location], - // // propName - // // ); - // // } - // } - } - } - - function validateMethodOverride(isAlreadyDefined, name) { - var specPolicy = ReactClassInterface.hasOwnProperty(name) - ? ReactClassInterface[name] - : null; - - // Disallow overriding of base class methods unless explicitly allowed. - if (ReactClassMixin.hasOwnProperty(name)) { - // _invariant( - // specPolicy === 'OVERRIDE_BASE', - // 'ReactClassInterface: You are attempting to override ' + - // '\`%s\` from your class specification. Ensure that your method names ' + - // 'do not overlap with React methods.', - // name - // ); - } - - // Disallow defining methods more than once unless explicitly allowed. - if (isAlreadyDefined) { - // _invariant( - // specPolicy === 'DEFINE_MANY' || specPolicy === 'DEFINE_MANY_MERGED', - // 'ReactClassInterface: You are attempting to define ' + - // '\`%s\` on your component more than once. This conflict may be due ' + - // 'to a mixin.', - // name - // ); - } - } - - /** - * Mixin helper which handles policy validation and reserved - * specification keys when building React classes. - */ - function mixSpecIntoComponent(Constructor, spec) { - if (!spec) { - // if (process.env.NODE_ENV !== 'production') { - // var typeofSpec = typeof spec; - // var isMixinValid = typeofSpec === 'object' && spec !== null; - // - // if (process.env.NODE_ENV !== 'production') { - // warning( - // isMixinValid, - // "%s: You're attempting to include a mixin that is either null " + - // 'or not an object. Check the mixins included by the component, ' + - // 'as well as any mixins they include themselves. ' + - // 'Expected object but got %s.', - // Constructor.displayName || 'ReactClass', - // spec === null ? null : typeofSpec - // ); - // } - // } - - return; - } - - // _invariant( - // typeof spec !== 'function', - // "ReactClass: You're attempting to " + - // 'use a component class or function as a mixin. Instead, just use a ' + - // 'regular object.' - // ); - // _invariant( - // !isValidElement(spec), - // "ReactClass: You're attempting to " + - // 'use a component as a mixin. Instead, just use a regular object.' - // ); - - var proto = Constructor.prototype; - var autoBindPairs = proto.__reactAutoBindPairs; - - // By handling mixins before any other properties, we ensure the same - // chaining order is applied to methods with DEFINE_MANY policy, whether - // mixins are listed before or after these methods in the spec. - if (spec.hasOwnProperty(MIXINS_KEY)) { - RESERVED_SPEC_KEYS.mixins(Constructor, spec.mixins); - } - - for (var name in spec) { - if (!spec.hasOwnProperty(name)) { - continue; - } - - if (name === MIXINS_KEY) { - // We have already handled mixins in a special case above. - continue; - } - - var property = spec[name]; - var isAlreadyDefined = proto.hasOwnProperty(name); - validateMethodOverride(isAlreadyDefined, name); - - if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) { - RESERVED_SPEC_KEYS[name](Constructor, property); - } else { - // Setup methods on prototype: - // The following member methods should not be automatically bound: - // 1. Expected ReactClass methods (in the "interface"). - // 2. Overridden methods (that were mixed in). - var isReactClassMethod = ReactClassInterface.hasOwnProperty(name); - var isFunction = typeof property === 'function'; - var shouldAutoBind = - isFunction && - !isReactClassMethod && - !isAlreadyDefined && - spec.autobind !== false; - - if (shouldAutoBind) { - autoBindPairs.push(name, property); - proto[name] = property; - } else { - if (isAlreadyDefined) { - var specPolicy = ReactClassInterface[name]; - - // These cases should already be caught by validateMethodOverride. - // _invariant( - // isReactClassMethod && - // (specPolicy === 'DEFINE_MANY_MERGED' || - // specPolicy === 'DEFINE_MANY'), - // 'ReactClass: Unexpected spec policy %s for key %s ' + - // 'when mixing in component specs.', - // specPolicy, - // name - // ); - - // For methods which are defined more than once, call the existing - // methods before calling the new property, merging if appropriate. - if (specPolicy === 'DEFINE_MANY_MERGED') { - proto[name] = createMergedResultFunction(proto[name], property); - } else if (specPolicy === 'DEFINE_MANY') { - proto[name] = createChainedFunction(proto[name], property); - } - } else { - proto[name] = property; - // if (process.env.NODE_ENV !== 'production') { - // // Add verbose displayName to the function, which helps when looking - // // at profiling tools. - // if (typeof property === 'function' && spec.displayName) { - // proto[name].displayName = spec.displayName + '_' + name; - // } - // } - } - } - } - } - } - - function mixStaticSpecIntoComponent(Constructor, statics) { - if (!statics) { - return; - } - for (var name in statics) { - var property = statics[name]; - if (!statics.hasOwnProperty(name)) { - continue; - } - - var isReserved = name in RESERVED_SPEC_KEYS; - // _invariant( - // !isReserved, - // 'ReactClass: You are attempting to define a reserved ' + - // 'property, \`%s\`, that shouldn\\'t be on the "statics" key. Define it ' + - // 'as an instance property instead; it will still be accessible on the ' + - // 'constructor.', - // name - // ); - - var isInherited = name in Constructor; - // _invariant( - // !isInherited, - // 'ReactClass: You are attempting to define ' + - // '\`%s\` on your component more than once. This conflict may be ' + - // 'due to a mixin.', - // name - // ); - Constructor[name] = property; - } - } - - /** - * Merge two objects, but throw if both contain the same key. - * - * @param {object} one The first object, which is mutated. - * @param {object} two The second object - * @return {object} one after it has been mutated to contain everything in two. - */ - function mergeIntoWithNoDuplicateKeys(one, two) { - // _invariant( - // one && two && typeof one === 'object' && typeof two === 'object', - // 'mergeIntoWithNoDuplicateKeys(): Cannot merge non-objects.' - // ); - - for (var key in two) { - if (two.hasOwnProperty(key)) { - // _invariant( - // one[key] === undefined, - // 'mergeIntoWithNoDuplicateKeys(): ' + - // 'Tried to merge two objects with the same key: \`%s\`. This conflict ' + - // 'may be due to a mixin; in particular, this may be caused by two ' + - // 'getInitialState() or getDefaultProps() methods returning objects ' + - // 'with clashing keys.', - // key - // ); - one[key] = two[key]; - } - } - return one; - } - - /** - * Creates a function that invokes two functions and merges their return values. - * - * @param {function} one Function to invoke first. - * @param {function} two Function to invoke second. - * @return {function} Function that invokes the two argument functions. - * @private - */ - function createMergedResultFunction(one, two) { - return function mergedResult() { - var a = one.apply(this, arguments); - var b = two.apply(this, arguments); - if (a == null) { - return b; - } else if (b == null) { - return a; - } - var c = {}; - mergeIntoWithNoDuplicateKeys(c, a); - mergeIntoWithNoDuplicateKeys(c, b); - return c; - }; - } - - /** - * Creates a function that invokes two functions and ignores their return vales. - * - * @param {function} one Function to invoke first. - * @param {function} two Function to invoke second. - * @return {function} Function that invokes the two argument functions. - * @private - */ - function createChainedFunction(one, two) { - return function chainedFunction() { - one.apply(this, arguments); - two.apply(this, arguments); - }; - } - - /** - * Binds a method to the component. - * - * @param {object} component Component whose method is going to be bound. - * @param {function} method Method to be bound. - * @return {function} The bound method. - */ - function bindAutoBindMethod(component, method) { - var boundMethod = method.bind(component); - // if (process.env.NODE_ENV !== 'production') { - // boundMethod.__reactBoundContext = component; - // boundMethod.__reactBoundMethod = method; - // boundMethod.__reactBoundArguments = null; - // var componentName = component.constructor.displayName; - // var _bind = boundMethod.bind; - // boundMethod.bind = function(newThis) { - // for ( - // var _len = arguments.length, - // args = Array(_len > 1 ? _len - 1 : 0), - // _key = 1; - // _key < _len; - // _key++ - // ) { - // args[_key - 1] = arguments[_key]; - // } - // - // // User is trying to bind() an autobound method; we effectively will - // // ignore the value of "this" that the user is trying to use, so - // // let's warn. - // if (newThis !== component && newThis !== null) { - // if (process.env.NODE_ENV !== 'production') { - // warning( - // false, - // 'bind(): React component methods may only be bound to the ' + - // 'component instance. See %s', - // componentName - // ); - // } - // } else if (!args.length) { - // if (process.env.NODE_ENV !== 'production') { - // warning( - // false, - // 'bind(): You are binding a component method to the component. ' + - // 'React does this for you automatically in a high-performance ' + - // 'way, so you can safely remove this call. See %s', - // componentName - // ); - // } - // return boundMethod; - // } - // var reboundMethod = _bind.apply(boundMethod, arguments); - // reboundMethod.__reactBoundContext = component; - // reboundMethod.__reactBoundMethod = method; - // reboundMethod.__reactBoundArguments = args; - // return reboundMethod; - // }; - // } - return boundMethod; - } - - /** - * Binds all auto-bound methods in a component. - * - * @param {object} component Component whose method is going to be bound. - */ - function bindAutoBindMethods(component) { - var pairs = component.__reactAutoBindPairs; - for (var i = 0; i < pairs.length; i += 2) { - var autoBindKey = pairs[i]; - var method = pairs[i + 1]; - component[autoBindKey] = bindAutoBindMethod(component, method); - } - } - - var IsMountedPreMixin = { - componentDidMount: function() { - this.__isMounted = true; - } - }; - - var IsMountedPostMixin = { - componentWillUnmount: function() { - this.__isMounted = false; - } - }; - - /** - * Add more to the ReactClass base class. These are all legacy features and - * therefore not already part of the modern ReactComponent. - */ - var ReactClassMixin = { - /** - * TODO: This will be deprecated because state should always keep a consistent - * type signature and the only use case for this, is to avoid that. - */ - replaceState: function(newState, callback) { - this.updater.enqueueReplaceState(this, newState, callback); - }, - - /** - * Checks whether or not this composite component is mounted. - * @return {boolean} True if mounted, false otherwise. - * @protected - * @final - */ - isMounted: function() { - // if (process.env.NODE_ENV !== 'production') { - // warning( - // this.__didWarnIsMounted, - // '%s: isMounted is deprecated. Instead, make sure to clean up ' + - // 'subscriptions and pending requests in componentWillUnmount to ' + - // 'prevent memory leaks.', - // (this.constructor && this.constructor.displayName) || - // this.name || - // 'Component' - // ); - // this.__didWarnIsMounted = true; - // } - return !!this.__isMounted; - } - }; - - var ReactClassComponent = function() {}; - _assign( - ReactClassComponent.prototype, - ReactComponent.prototype, - ReactClassMixin - ); - - /** - * Creates a composite component class given a class specification. - * See https://facebook.github.io/react/docs/top-level-api.html#react.createclass - * - * @param {object} spec Class specification (which must define \`render\`). - * @return {function} Component constructor function. - * @public - */ - function createClass(spec) { - // To keep our warnings more understandable, we'll use a little hack here to - // ensure that Constructor.name !== 'Constructor'. This makes sure we don't - // unnecessarily identify a class without displayName as 'Constructor'. - var Constructor = identity(function(props, context, updater) { - // This constructor gets overridden by mocks. The argument is used - // by mocks to assert on what gets mounted. - - // if (process.env.NODE_ENV !== 'production') { - // warning( - // this instanceof Constructor, - // 'Something is calling a React component directly. Use a factory or ' + - // 'JSX instead. See: https://fb.me/react-legacyfactory' - // ); - // } - - // Wire up auto-binding - if (this.__reactAutoBindPairs.length) { - bindAutoBindMethods(this); - } - - this.props = props; - this.context = context; - this.refs = emptyObject; - this.updater = updater || ReactNoopUpdateQueue; - - this.state = null; - - // ReactClasses doesn't have constructors. Instead, they use the - // getInitialState and componentWillMount methods for initialization. - - var initialState = this.getInitialState ? this.getInitialState() : null; - // if (process.env.NODE_ENV !== 'production') { - // // We allow auto-mocks to proceed as if they're returning null. - // if ( - // initialState === undefined && - // this.getInitialState._isMockFunction - // ) { - // // This is probably bad practice. Consider warning here and - // // deprecating this convenience. - // initialState = null; - // } - // } - // _invariant( - // typeof initialState === 'object' && !Array.isArray(initialState), - // '%s.getInitialState(): must return an object or null', - // Constructor.displayName || 'ReactCompositeComponent' - // ); - - this.state = initialState; - }); - Constructor.prototype = new ReactClassComponent(); - Constructor.prototype.constructor = Constructor; - Constructor.prototype.__reactAutoBindPairs = []; - - injectedMixins.forEach(mixSpecIntoComponent.bind(null, Constructor)); - - mixSpecIntoComponent(Constructor, IsMountedPreMixin); - mixSpecIntoComponent(Constructor, spec); - mixSpecIntoComponent(Constructor, IsMountedPostMixin); - - // Initialize the defaultProps property after all mixins have been merged. - if (Constructor.getDefaultProps) { - Constructor.defaultProps = Constructor.getDefaultProps(); - } - - // if (process.env.NODE_ENV !== 'production') { - // // This is a tag to indicate that the use of these method names is ok, - // // since it's used with createClass. If it's not, then it's likely a - // // mistake so we'll warn you to use the static property, property - // // initializer or constructor respectively. - // if (Constructor.getDefaultProps) { - // Constructor.getDefaultProps.isReactClassApproved = {}; - // } - // if (Constructor.prototype.getInitialState) { - // Constructor.prototype.getInitialState.isReactClassApproved = {}; - // } - // } - - // _invariant( - // Constructor.prototype.render, - // 'createClass(...): Class specification must implement a \`render\` method.' - // ); - - // if (process.env.NODE_ENV !== 'production') { - // warning( - // !Constructor.prototype.componentShouldUpdate, - // '%s has a method called ' + - // 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' + - // 'The name is phrased as a question because the function is ' + - // 'expected to return a value.', - // spec.displayName || 'A component' - // ); - // warning( - // !Constructor.prototype.componentWillRecieveProps, - // '%s has a method called ' + - // 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?', - // spec.displayName || 'A component' - // ); - // } - - // Reduce time spent doing lookups by setting these on the prototype. - for (var methodName in ReactClassInterface) { - if (!Constructor.prototype[methodName]) { - Constructor.prototype[methodName] = null; - } - } - - return Constructor; - } - - return createClass; -}); - -let reactNoopUpdateQueue = new React.Component().updater; - -let createClass = factory(React.Component, React.isValidElement, reactNoopUpdateQueue); - -export { - _assign, - emptyObject, - factory, - reactNoopUpdateQueue, - createClass, -} -/* Not a pure module */ diff --git a/tests/tests/src/reasonReactOptimizedCreateClass.res b/tests/tests/src/reasonReactOptimizedCreateClass.res deleted file mode 100644 index 34350c989c..0000000000 --- a/tests/tests/src/reasonReactOptimizedCreateClass.res +++ /dev/null @@ -1,889 +0,0 @@ -let _assign = Js.Obj.assign - -let emptyObject = Js.Obj.empty() - -%%raw(` -/** - * Copyright 2013-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -// 'use strict'; - -// var _assign = require('object-assign'); - -// var emptyObject = require('emptyObject'); -// var _invariant = require('invariant'); - -// if (process.env.NODE_ENV !== 'production') { -// var warning = require('fbjs/lib/warning'); -// } - -var MIXINS_KEY = 'mixins'; - -// Helper function to allow the creation of anonymous functions which do not -// have .name set to the name of the variable being assigned to. -function identity(fn) { - return fn; -} - -var ReactPropTypeLocationNames; -// if (process.env.NODE_ENV !== 'production') { -// ReactPropTypeLocationNames = { -// prop: 'prop', -// context: 'context', -// childContext: 'child context' -// }; -// } else { - ReactPropTypeLocationNames = {}; -// } -`) - -let factory = %raw(` -function factory(ReactComponent, isValidElement, ReactNoopUpdateQueue) { - /** - * Policies that describe methods in \`ReactClassInterface\`. - */ - - var injectedMixins = []; - - /** - * Composite components are higher-level components that compose other composite - * or host components. - * - * To create a new type of \`ReactClass\`, pass a specification of - * your new class to \`React.createClass\`. The only requirement of your class - * specification is that you implement a \`render\` method. - * - * var MyComponent = React.createClass({ - * render: function() { - * return
Hello World
; - * } - * }); - * - * The class specification supports a specific protocol of methods that have - * special meaning (e.g. \`render\`). See \`ReactClassInterface\` for - * more the comprehensive protocol. Any other properties and methods in the - * class specification will be available on the prototype. - * - * @interface ReactClassInterface - * @internal - */ - var ReactClassInterface = { - /** - * An array of Mixin objects to include when defining your component. - * - * @type {array} - * @optional - */ - mixins: 'DEFINE_MANY', - - /** - * An object containing properties and methods that should be defined on - * the component's constructor instead of its prototype (static methods). - * - * @type {object} - * @optional - */ - statics: 'DEFINE_MANY', - - /** - * Definition of prop types for this component. - * - * @type {object} - * @optional - */ - propTypes: 'DEFINE_MANY', - - /** - * Definition of context types for this component. - * - * @type {object} - * @optional - */ - contextTypes: 'DEFINE_MANY', - - /** - * Definition of context types this component sets for its children. - * - * @type {object} - * @optional - */ - childContextTypes: 'DEFINE_MANY', - - // ==== Definition methods ==== - - /** - * Invoked when the component is mounted. Values in the mapping will be set on - * \`this.props\` if that prop is not specified (i.e. using an \`in\` check). - * - * This method is invoked before \`getInitialState\` and therefore cannot rely - * on \`this.state\` or use \`this.setState\`. - * - * @return {object} - * @optional - */ - getDefaultProps: 'DEFINE_MANY_MERGED', - - /** - * Invoked once before the component is mounted. The return value will be used - * as the initial value of \`this.state\`. - * - * getInitialState: function() { - * return { - * isOn: false, - * fooBaz: new BazFoo() - * } - * } - * - * @return {object} - * @optional - */ - getInitialState: 'DEFINE_MANY_MERGED', - - /** - * @return {object} - * @optional - */ - getChildContext: 'DEFINE_MANY_MERGED', - - /** - * Uses props from \`this.props\` and state from \`this.state\` to render the - * structure of the component. - * - * No guarantees are made about when or how often this method is invoked, so - * it must not have side effects. - * - * render: function() { - * var name = this.props.name; - * return
Hello, {name}!
; - * } - * - * @return {ReactComponent} - * @required - */ - render: 'DEFINE_ONCE', - - // ==== Delegate methods ==== - - /** - * Invoked when the component is initially created and about to be mounted. - * This may have side effects, but any external subscriptions or data created - * by this method must be cleaned up in \`componentWillUnmount\`. - * - * @optional - */ - componentWillMount: 'DEFINE_MANY', - - /** - * Invoked when the component has been mounted and has a DOM representation. - * However, there is no guarantee that the DOM node is in the document. - * - * Use this as an opportunity to operate on the DOM when the component has - * been mounted (initialized and rendered) for the first time. - * - * @param {DOMElement} rootNode DOM element representing the component. - * @optional - */ - componentDidMount: 'DEFINE_MANY', - - /** - * Invoked before the component receives new props. - * - * Use this as an opportunity to react to a prop transition by updating the - * state using \`this.setState\`. Current props are accessed via \`this.props\`. - * - * componentWillReceiveProps: function(nextProps, nextContext) { - * this.setState({ - * likesIncreasing: nextProps.likeCount > this.props.likeCount - * }); - * } - * - * NOTE: There is no equivalent \`componentWillReceiveState\`. An incoming prop - * transition may cause a state change, but the opposite is not true. If you - * need it, you are probably looking for \`componentWillUpdate\`. - * - * @param {object} nextProps - * @optional - */ - componentWillReceiveProps: 'DEFINE_MANY', - - /** - * Invoked while deciding if the component should be updated as a result of - * receiving new props, state and/or context. - * - * Use this as an opportunity to \`return false\` when you're certain that the - * transition to the new props/state/context will not require a component - * update. - * - * shouldComponentUpdate: function(nextProps, nextState, nextContext) { - * return !equal(nextProps, this.props) || - * !equal(nextState, this.state) || - * !equal(nextContext, this.context); - * } - * - * @param {object} nextProps - * @param {?object} nextState - * @param {?object} nextContext - * @return {boolean} True if the component should update. - * @optional - */ - shouldComponentUpdate: 'DEFINE_ONCE', - - /** - * Invoked when the component is about to update due to a transition from - * \`this.props\`, \`this.state\` and \`this.context\` to \`nextProps\`, \`nextState\` - * and \`nextContext\`. - * - * Use this as an opportunity to perform preparation before an update occurs. - * - * NOTE: You **cannot** use \`this.setState()\` in this method. - * - * @param {object} nextProps - * @param {?object} nextState - * @param {?object} nextContext - * @param {ReactReconcileTransaction} transaction - * @optional - */ - componentWillUpdate: 'DEFINE_MANY', - - /** - * Invoked when the component's DOM representation has been updated. - * - * Use this as an opportunity to operate on the DOM when the component has - * been updated. - * - * @param {object} prevProps - * @param {?object} prevState - * @param {?object} prevContext - * @param {DOMElement} rootNode DOM element representing the component. - * @optional - */ - componentDidUpdate: 'DEFINE_MANY', - - /** - * Invoked when the component is about to be removed from its parent and have - * its DOM representation destroyed. - * - * Use this as an opportunity to deallocate any external resources. - * - * NOTE: There is no \`componentDidUnmount\` since your component will have been - * destroyed by that point. - * - * @optional - */ - componentWillUnmount: 'DEFINE_MANY', - - // ==== Advanced methods ==== - - /** - * Updates the component's currently mounted DOM representation. - * - * By default, this implements React's rendering and reconciliation algorithm. - * Sophisticated clients may wish to override this. - * - * @param {ReactReconcileTransaction} transaction - * @internal - * @overridable - */ - updateComponent: 'OVERRIDE_BASE' - }; - - /** - * Mapping from class specification keys to special processing functions. - * - * Although these are declared like instance properties in the specification - * when defining classes using \`React.createClass\`, they are actually static - * and are accessible on the constructor instead of the prototype. Despite - * being static, they must be defined outside of the "statics" key under - * which all other static methods are defined. - */ - var RESERVED_SPEC_KEYS = { - displayName: function(Constructor, displayName) { - Constructor.displayName = displayName; - }, - mixins: function(Constructor, mixins) { - if (mixins) { - for (var i = 0; i < mixins.length; i++) { - mixSpecIntoComponent(Constructor, mixins[i]); - } - } - }, - childContextTypes: function(Constructor, childContextTypes) { - // if (process.env.NODE_ENV !== 'production') { - // validateTypeDef(Constructor, childContextTypes, 'childContext'); - // } - Constructor.childContextTypes = _assign( - {}, - Constructor.childContextTypes, - childContextTypes - ); - }, - contextTypes: function(Constructor, contextTypes) { - // if (process.env.NODE_ENV !== 'production') { - // validateTypeDef(Constructor, contextTypes, 'context'); - // } - Constructor.contextTypes = _assign( - {}, - Constructor.contextTypes, - contextTypes - ); - }, - /** - * Special case getDefaultProps which should move into statics but requires - * automatic merging. - */ - getDefaultProps: function(Constructor, getDefaultProps) { - if (Constructor.getDefaultProps) { - Constructor.getDefaultProps = createMergedResultFunction( - Constructor.getDefaultProps, - getDefaultProps - ); - } else { - Constructor.getDefaultProps = getDefaultProps; - } - }, - propTypes: function(Constructor, propTypes) { - // if (process.env.NODE_ENV !== 'production') { - // validateTypeDef(Constructor, propTypes, 'prop'); - // } - Constructor.propTypes = _assign({}, Constructor.propTypes, propTypes); - }, - statics: function(Constructor, statics) { - mixStaticSpecIntoComponent(Constructor, statics); - }, - autobind: function() {} - }; - - function validateTypeDef(Constructor, typeDef, location) { - for (var propName in typeDef) { - // if (typeDef.hasOwnProperty(propName)) { - // // use a warning instead of an _invariant so components - // // don't show up in prod but only in __DEV__ - // // if (process.env.NODE_ENV !== 'production') { - // // warning( - // // typeof typeDef[propName] === 'function', - // // '%s: %s type \`%s\` is invalid; it must be a function, usually from ' + - // // 'React.PropTypes.', - // // Constructor.displayName || 'ReactClass', - // // ReactPropTypeLocationNames[location], - // // propName - // // ); - // // } - // } - } - } - - function validateMethodOverride(isAlreadyDefined, name) { - var specPolicy = ReactClassInterface.hasOwnProperty(name) - ? ReactClassInterface[name] - : null; - - // Disallow overriding of base class methods unless explicitly allowed. - if (ReactClassMixin.hasOwnProperty(name)) { - // _invariant( - // specPolicy === 'OVERRIDE_BASE', - // 'ReactClassInterface: You are attempting to override ' + - // '\`%s\` from your class specification. Ensure that your method names ' + - // 'do not overlap with React methods.', - // name - // ); - } - - // Disallow defining methods more than once unless explicitly allowed. - if (isAlreadyDefined) { - // _invariant( - // specPolicy === 'DEFINE_MANY' || specPolicy === 'DEFINE_MANY_MERGED', - // 'ReactClassInterface: You are attempting to define ' + - // '\`%s\` on your component more than once. This conflict may be due ' + - // 'to a mixin.', - // name - // ); - } - } - - /** - * Mixin helper which handles policy validation and reserved - * specification keys when building React classes. - */ - function mixSpecIntoComponent(Constructor, spec) { - if (!spec) { - // if (process.env.NODE_ENV !== 'production') { - // var typeofSpec = typeof spec; - // var isMixinValid = typeofSpec === 'object' && spec !== null; - // - // if (process.env.NODE_ENV !== 'production') { - // warning( - // isMixinValid, - // "%s: You're attempting to include a mixin that is either null " + - // 'or not an object. Check the mixins included by the component, ' + - // 'as well as any mixins they include themselves. ' + - // 'Expected object but got %s.', - // Constructor.displayName || 'ReactClass', - // spec === null ? null : typeofSpec - // ); - // } - // } - - return; - } - - // _invariant( - // typeof spec !== 'function', - // "ReactClass: You're attempting to " + - // 'use a component class or function as a mixin. Instead, just use a ' + - // 'regular object.' - // ); - // _invariant( - // !isValidElement(spec), - // "ReactClass: You're attempting to " + - // 'use a component as a mixin. Instead, just use a regular object.' - // ); - - var proto = Constructor.prototype; - var autoBindPairs = proto.__reactAutoBindPairs; - - // By handling mixins before any other properties, we ensure the same - // chaining order is applied to methods with DEFINE_MANY policy, whether - // mixins are listed before or after these methods in the spec. - if (spec.hasOwnProperty(MIXINS_KEY)) { - RESERVED_SPEC_KEYS.mixins(Constructor, spec.mixins); - } - - for (var name in spec) { - if (!spec.hasOwnProperty(name)) { - continue; - } - - if (name === MIXINS_KEY) { - // We have already handled mixins in a special case above. - continue; - } - - var property = spec[name]; - var isAlreadyDefined = proto.hasOwnProperty(name); - validateMethodOverride(isAlreadyDefined, name); - - if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) { - RESERVED_SPEC_KEYS[name](Constructor, property); - } else { - // Setup methods on prototype: - // The following member methods should not be automatically bound: - // 1. Expected ReactClass methods (in the "interface"). - // 2. Overridden methods (that were mixed in). - var isReactClassMethod = ReactClassInterface.hasOwnProperty(name); - var isFunction = typeof property === 'function'; - var shouldAutoBind = - isFunction && - !isReactClassMethod && - !isAlreadyDefined && - spec.autobind !== false; - - if (shouldAutoBind) { - autoBindPairs.push(name, property); - proto[name] = property; - } else { - if (isAlreadyDefined) { - var specPolicy = ReactClassInterface[name]; - - // These cases should already be caught by validateMethodOverride. - // _invariant( - // isReactClassMethod && - // (specPolicy === 'DEFINE_MANY_MERGED' || - // specPolicy === 'DEFINE_MANY'), - // 'ReactClass: Unexpected spec policy %s for key %s ' + - // 'when mixing in component specs.', - // specPolicy, - // name - // ); - - // For methods which are defined more than once, call the existing - // methods before calling the new property, merging if appropriate. - if (specPolicy === 'DEFINE_MANY_MERGED') { - proto[name] = createMergedResultFunction(proto[name], property); - } else if (specPolicy === 'DEFINE_MANY') { - proto[name] = createChainedFunction(proto[name], property); - } - } else { - proto[name] = property; - // if (process.env.NODE_ENV !== 'production') { - // // Add verbose displayName to the function, which helps when looking - // // at profiling tools. - // if (typeof property === 'function' && spec.displayName) { - // proto[name].displayName = spec.displayName + '_' + name; - // } - // } - } - } - } - } - } - - function mixStaticSpecIntoComponent(Constructor, statics) { - if (!statics) { - return; - } - for (var name in statics) { - var property = statics[name]; - if (!statics.hasOwnProperty(name)) { - continue; - } - - var isReserved = name in RESERVED_SPEC_KEYS; - // _invariant( - // !isReserved, - // 'ReactClass: You are attempting to define a reserved ' + - // 'property, \`%s\`, that shouldn\\'t be on the "statics" key. Define it ' + - // 'as an instance property instead; it will still be accessible on the ' + - // 'constructor.', - // name - // ); - - var isInherited = name in Constructor; - // _invariant( - // !isInherited, - // 'ReactClass: You are attempting to define ' + - // '\`%s\` on your component more than once. This conflict may be ' + - // 'due to a mixin.', - // name - // ); - Constructor[name] = property; - } - } - - /** - * Merge two objects, but throw if both contain the same key. - * - * @param {object} one The first object, which is mutated. - * @param {object} two The second object - * @return {object} one after it has been mutated to contain everything in two. - */ - function mergeIntoWithNoDuplicateKeys(one, two) { - // _invariant( - // one && two && typeof one === 'object' && typeof two === 'object', - // 'mergeIntoWithNoDuplicateKeys(): Cannot merge non-objects.' - // ); - - for (var key in two) { - if (two.hasOwnProperty(key)) { - // _invariant( - // one[key] === undefined, - // 'mergeIntoWithNoDuplicateKeys(): ' + - // 'Tried to merge two objects with the same key: \`%s\`. This conflict ' + - // 'may be due to a mixin; in particular, this may be caused by two ' + - // 'getInitialState() or getDefaultProps() methods returning objects ' + - // 'with clashing keys.', - // key - // ); - one[key] = two[key]; - } - } - return one; - } - - /** - * Creates a function that invokes two functions and merges their return values. - * - * @param {function} one Function to invoke first. - * @param {function} two Function to invoke second. - * @return {function} Function that invokes the two argument functions. - * @private - */ - function createMergedResultFunction(one, two) { - return function mergedResult() { - var a = one.apply(this, arguments); - var b = two.apply(this, arguments); - if (a == null) { - return b; - } else if (b == null) { - return a; - } - var c = {}; - mergeIntoWithNoDuplicateKeys(c, a); - mergeIntoWithNoDuplicateKeys(c, b); - return c; - }; - } - - /** - * Creates a function that invokes two functions and ignores their return vales. - * - * @param {function} one Function to invoke first. - * @param {function} two Function to invoke second. - * @return {function} Function that invokes the two argument functions. - * @private - */ - function createChainedFunction(one, two) { - return function chainedFunction() { - one.apply(this, arguments); - two.apply(this, arguments); - }; - } - - /** - * Binds a method to the component. - * - * @param {object} component Component whose method is going to be bound. - * @param {function} method Method to be bound. - * @return {function} The bound method. - */ - function bindAutoBindMethod(component, method) { - var boundMethod = method.bind(component); - // if (process.env.NODE_ENV !== 'production') { - // boundMethod.__reactBoundContext = component; - // boundMethod.__reactBoundMethod = method; - // boundMethod.__reactBoundArguments = null; - // var componentName = component.constructor.displayName; - // var _bind = boundMethod.bind; - // boundMethod.bind = function(newThis) { - // for ( - // var _len = arguments.length, - // args = Array(_len > 1 ? _len - 1 : 0), - // _key = 1; - // _key < _len; - // _key++ - // ) { - // args[_key - 1] = arguments[_key]; - // } - // - // // User is trying to bind() an autobound method; we effectively will - // // ignore the value of "this" that the user is trying to use, so - // // let's warn. - // if (newThis !== component && newThis !== null) { - // if (process.env.NODE_ENV !== 'production') { - // warning( - // false, - // 'bind(): React component methods may only be bound to the ' + - // 'component instance. See %s', - // componentName - // ); - // } - // } else if (!args.length) { - // if (process.env.NODE_ENV !== 'production') { - // warning( - // false, - // 'bind(): You are binding a component method to the component. ' + - // 'React does this for you automatically in a high-performance ' + - // 'way, so you can safely remove this call. See %s', - // componentName - // ); - // } - // return boundMethod; - // } - // var reboundMethod = _bind.apply(boundMethod, arguments); - // reboundMethod.__reactBoundContext = component; - // reboundMethod.__reactBoundMethod = method; - // reboundMethod.__reactBoundArguments = args; - // return reboundMethod; - // }; - // } - return boundMethod; - } - - /** - * Binds all auto-bound methods in a component. - * - * @param {object} component Component whose method is going to be bound. - */ - function bindAutoBindMethods(component) { - var pairs = component.__reactAutoBindPairs; - for (var i = 0; i < pairs.length; i += 2) { - var autoBindKey = pairs[i]; - var method = pairs[i + 1]; - component[autoBindKey] = bindAutoBindMethod(component, method); - } - } - - var IsMountedPreMixin = { - componentDidMount: function() { - this.__isMounted = true; - } - }; - - var IsMountedPostMixin = { - componentWillUnmount: function() { - this.__isMounted = false; - } - }; - - /** - * Add more to the ReactClass base class. These are all legacy features and - * therefore not already part of the modern ReactComponent. - */ - var ReactClassMixin = { - /** - * TODO: This will be deprecated because state should always keep a consistent - * type signature and the only use case for this, is to avoid that. - */ - replaceState: function(newState, callback) { - this.updater.enqueueReplaceState(this, newState, callback); - }, - - /** - * Checks whether or not this composite component is mounted. - * @return {boolean} True if mounted, false otherwise. - * @protected - * @final - */ - isMounted: function() { - // if (process.env.NODE_ENV !== 'production') { - // warning( - // this.__didWarnIsMounted, - // '%s: isMounted is deprecated. Instead, make sure to clean up ' + - // 'subscriptions and pending requests in componentWillUnmount to ' + - // 'prevent memory leaks.', - // (this.constructor && this.constructor.displayName) || - // this.name || - // 'Component' - // ); - // this.__didWarnIsMounted = true; - // } - return !!this.__isMounted; - } - }; - - var ReactClassComponent = function() {}; - _assign( - ReactClassComponent.prototype, - ReactComponent.prototype, - ReactClassMixin - ); - - /** - * Creates a composite component class given a class specification. - * See https://facebook.github.io/react/docs/top-level-api.html#react.createclass - * - * @param {object} spec Class specification (which must define \`render\`). - * @return {function} Component constructor function. - * @public - */ - function createClass(spec) { - // To keep our warnings more understandable, we'll use a little hack here to - // ensure that Constructor.name !== 'Constructor'. This makes sure we don't - // unnecessarily identify a class without displayName as 'Constructor'. - var Constructor = identity(function(props, context, updater) { - // This constructor gets overridden by mocks. The argument is used - // by mocks to assert on what gets mounted. - - // if (process.env.NODE_ENV !== 'production') { - // warning( - // this instanceof Constructor, - // 'Something is calling a React component directly. Use a factory or ' + - // 'JSX instead. See: https://fb.me/react-legacyfactory' - // ); - // } - - // Wire up auto-binding - if (this.__reactAutoBindPairs.length) { - bindAutoBindMethods(this); - } - - this.props = props; - this.context = context; - this.refs = emptyObject; - this.updater = updater || ReactNoopUpdateQueue; - - this.state = null; - - // ReactClasses doesn't have constructors. Instead, they use the - // getInitialState and componentWillMount methods for initialization. - - var initialState = this.getInitialState ? this.getInitialState() : null; - // if (process.env.NODE_ENV !== 'production') { - // // We allow auto-mocks to proceed as if they're returning null. - // if ( - // initialState === undefined && - // this.getInitialState._isMockFunction - // ) { - // // This is probably bad practice. Consider warning here and - // // deprecating this convenience. - // initialState = null; - // } - // } - // _invariant( - // typeof initialState === 'object' && !Array.isArray(initialState), - // '%s.getInitialState(): must return an object or null', - // Constructor.displayName || 'ReactCompositeComponent' - // ); - - this.state = initialState; - }); - Constructor.prototype = new ReactClassComponent(); - Constructor.prototype.constructor = Constructor; - Constructor.prototype.__reactAutoBindPairs = []; - - injectedMixins.forEach(mixSpecIntoComponent.bind(null, Constructor)); - - mixSpecIntoComponent(Constructor, IsMountedPreMixin); - mixSpecIntoComponent(Constructor, spec); - mixSpecIntoComponent(Constructor, IsMountedPostMixin); - - // Initialize the defaultProps property after all mixins have been merged. - if (Constructor.getDefaultProps) { - Constructor.defaultProps = Constructor.getDefaultProps(); - } - - // if (process.env.NODE_ENV !== 'production') { - // // This is a tag to indicate that the use of these method names is ok, - // // since it's used with createClass. If it's not, then it's likely a - // // mistake so we'll warn you to use the static property, property - // // initializer or constructor respectively. - // if (Constructor.getDefaultProps) { - // Constructor.getDefaultProps.isReactClassApproved = {}; - // } - // if (Constructor.prototype.getInitialState) { - // Constructor.prototype.getInitialState.isReactClassApproved = {}; - // } - // } - - // _invariant( - // Constructor.prototype.render, - // 'createClass(...): Class specification must implement a \`render\` method.' - // ); - - // if (process.env.NODE_ENV !== 'production') { - // warning( - // !Constructor.prototype.componentShouldUpdate, - // '%s has a method called ' + - // 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' + - // 'The name is phrased as a question because the function is ' + - // 'expected to return a value.', - // spec.displayName || 'A component' - // ); - // warning( - // !Constructor.prototype.componentWillRecieveProps, - // '%s has a method called ' + - // 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?', - // spec.displayName || 'A component' - // ); - // } - - // Reduce time spent doing lookups by setting these on the prototype. - for (var methodName in ReactClassInterface) { - if (!Constructor.prototype[methodName]) { - Constructor.prototype[methodName] = null; - } - } - - return Constructor; - } - - return createClass; -} -`) - -@module("react") external reactComponent: 'a = "Component" - -@module("react") external reactIsValidElement: bool = "isValidElement" - -@module("react") @new -external newReactComponent: unit => {"updater": 'a} = "Component" - -let reactNoopUpdateQueue = newReactComponent()["updater"] - -let createClass = factory(reactComponent, reactIsValidElement, reactNoopUpdateQueue) diff --git a/tests/tests/src/reasonReactRouter.mjs b/tests/tests/src/reasonReactRouter.mjs deleted file mode 100644 index 1e22e6d9b2..0000000000 --- a/tests/tests/src/reasonReactRouter.mjs +++ /dev/null @@ -1,184 +0,0 @@ -// Generated by ReScript, PLEASE EDIT WITH CARE - -import * as React from "react"; -import * as Js_string from "rescript/lib/es6/Js_string.js"; -import * as Primitive_option from "rescript/lib/es6/Primitive_option.js"; - -function safeMakeEvent(eventName) { - if (typeof Event === "function") { - return new Event(eventName); - } - let event = document.createEvent("Event"); - event.initEvent(eventName, true, true); - return event; -} - -function path() { - let window = globalThis.window; - if (window === undefined) { - return /* [] */0; - } - let raw = Primitive_option.valFromOption(window).location.pathname; - switch (raw) { - case "" : - case "/" : - return /* [] */0; - default: - let raw$1 = Js_string.sliceToEnd(1, raw); - let match = raw$1[raw$1.length - 1 | 0]; - let raw$2 = match === "/" ? Js_string.slice(0, -1, raw$1) : raw$1; - let a = Js_string.split("/", raw$2); - let _i = a.length - 1 | 0; - let _res = /* [] */0; - while (true) { - let res = _res; - let i = _i; - if (i < 0) { - return res; - } - _res = { - hd: a[i], - tl: res - }; - _i = i - 1 | 0; - continue; - }; - } -} - -function hash() { - let window = globalThis.window; - if (window === undefined) { - return ""; - } - let raw = Primitive_option.valFromOption(window).location.hash; - switch (raw) { - case "" : - case "#" : - return ""; - default: - return Js_string.sliceToEnd(1, raw); - } -} - -function search() { - let window = globalThis.window; - if (window === undefined) { - return ""; - } - let raw = Primitive_option.valFromOption(window).location.search; - switch (raw) { - case "" : - case "?" : - return ""; - default: - return Js_string.sliceToEnd(1, raw); - } -} - -function push(path) { - let match = globalThis.history; - let match$1 = globalThis.window; - if (match !== undefined && match$1 !== undefined) { - Primitive_option.valFromOption(match).pushState(null, "", path); - Primitive_option.valFromOption(match$1).dispatchEvent(safeMakeEvent("popstate")); - return; - } - -} - -function replace(path) { - let match = globalThis.history; - let match$1 = globalThis.window; - if (match !== undefined && match$1 !== undefined) { - Primitive_option.valFromOption(match).replaceState(null, "", path); - Primitive_option.valFromOption(match$1).dispatchEvent(safeMakeEvent("popstate")); - return; - } - -} - -function urlNotEqual(a, b) { - if (a.hash !== b.hash || a.search !== b.search) { - return true; - } else { - let _aList = a.path; - let _bList = b.path; - while (true) { - let bList = _bList; - let aList = _aList; - if (aList === 0) { - return bList !== 0; - } - if (bList === 0) { - return true; - } - if (aList.hd !== bList.hd) { - return true; - } - _bList = bList.tl; - _aList = aList.tl; - continue; - }; - } -} - -function url() { - return { - path: path(), - hash: hash(), - search: search() - }; -} - -function watchUrl(callback) { - let window = globalThis.window; - if (window === undefined) { - return () => {}; - } - let watcherID = () => callback(url()); - Primitive_option.valFromOption(window).addEventListener("popstate", watcherID); - return watcherID; -} - -function unwatchUrl(watcherID) { - let window = globalThis.window; - if (window !== undefined) { - Primitive_option.valFromOption(window).removeEventListener("popstate", watcherID); - return; - } - -} - -function useUrl(serverUrl, param) { - let match = React.useState(() => { - if (serverUrl !== undefined) { - return serverUrl; - } else { - return url(); - } - }); - let setUrl = match[1]; - let url$1 = match[0]; - React.useEffect(() => { - let watcherId = watchUrl(url => setUrl(param => url)); - let newUrl = url(); - if (urlNotEqual(newUrl, url$1)) { - setUrl(param => newUrl); - } - return () => unwatchUrl(watcherId); - }, []); - return url$1; -} - -let dangerouslyGetInitialUrl = url; - -export { - push, - replace, - watchUrl, - unwatchUrl, - dangerouslyGetInitialUrl, - useUrl, -} -/* react Not a pure module */ diff --git a/tests/tests/src/reasonReactRouter.res b/tests/tests/src/reasonReactRouter.res deleted file mode 100644 index 295ab3d413..0000000000 --- a/tests/tests/src/reasonReactRouter.res +++ /dev/null @@ -1,191 +0,0 @@ -@get external location: Dom.window => Dom.location = "location" - -@send -external /* actually the cb is Dom.event => unit, but let's restrict the access for now */ -addEventListener: (Dom.window, string, unit => unit) => unit = "addEventListener" - -@send -external removeEventListener: (Dom.window, string, unit => unit) => unit = "removeEventListener" - -@send -external dispatchEvent: (Dom.window, Dom.event) => unit = "dispatchEvent" - -@get external pathname: Dom.location => string = "pathname" - -@get external hash: Dom.location => string = "hash" - -@get external search: Dom.location => string = "search" - -@send -external pushState: (Dom.history, @as(json`null`) _, @as("") _, ~href: string) => unit = "pushState" - -@send -external replaceState: (Dom.history, @as(json`null`) _, @as("") _, ~href: string) => unit = - "replaceState" - -@val external event: 'a = "Event" - -@new external makeEventIE11Compatible: string => Dom.event = "Event" - -@val @scope("document") -external createEventNonIEBrowsers: string => Dom.event = "createEvent" - -@send -external initEventNonIEBrowsers: (Dom.event, string, bool, bool) => unit = "initEvent" - -@val @scope("globalThis") -external window: option = "window" - -@val @scope("globalThis") -external history: option = "history" - -let safeMakeEvent = eventName => - if Js.typeof(event) == "function" { - makeEventIE11Compatible(eventName) - } else { - let event = createEventNonIEBrowsers("Event") - initEventNonIEBrowsers(event, eventName, true, true) - event - } - -/* This is copied from array.ml. We want to cut dependencies for ReasonReact so - that it's friendlier to use in size-constrained codebases */ -let arrayToList = a => { - open Belt - let rec tolist = (i, res) => - if i < 0 { - res - } else { - tolist(i - 1, list{Array.getUnsafe(a, i), ...res}) - } - tolist(Array.length(a) - 1, list{}) -} -/* if we ever roll our own parser in the future, make sure you test all url combinations - e.g. foo.com/?#bar - */ -/* sigh URLSearchParams doesn't work on IE11, edge16, etc. */ -/* actually you know what, not gonna provide search for now. It's a mess. - We'll let users roll their own solution/data structure for now */ -let path = () => - switch window { - | None => list{} - | Some(window) => - switch pathname(location(window)) { - | "" - | "/" => - list{} - | raw => - /* remove the preceeding /, which every pathname seems to have */ - let raw = Js.String.sliceToEnd(~from=1, raw) - /* remove the trailing /, which some pathnames might have. Ugh */ - let raw = switch Js.String.get(raw, Js.String.length(raw) - 1) { - | "/" => Js.String.slice(~from=0, ~to_=-1, raw) - | _ => raw - } - arrayToList(Js.String.split("/", raw)) - } - } -let hash = () => - switch window { - | None => "" - | Some(window) => - switch hash(location(window)) { - | "" - | "#" => "" - | raw => - /* remove the preceeding #, which every hash seems to have. - Why is this even included in location.hash?? */ - Js.String.sliceToEnd(~from=1, raw) - } - } -let search = () => - switch window { - | None => "" - | Some(window) => - switch search(location(window)) { - | "" - | "?" => "" - | raw => - /* remove the preceeding ?, which every search seems to have. */ - Js.String.sliceToEnd(~from=1, raw) - } - } -let push = path => - switch (history, window) { - | (None, _) - | (_, None) => () - | (Some(history), Some(window)) => - pushState(history, ~href=path) - dispatchEvent(window, safeMakeEvent("popstate")) - } -let replace = path => - switch (history, window) { - | (None, _) - | (_, None) => () - | (Some(history), Some(window)) => - replaceState(history, ~href=path) - dispatchEvent(window, safeMakeEvent("popstate")) - } -type url = { - path: list, - hash: string, - search: string, -} -let urlNotEqual = (a, b) => { - let rec listNotEqual = (aList, bList) => - switch (aList, bList) { - | (list{}, list{}) => false - | (list{}, list{_, ..._}) - | (list{_, ..._}, list{}) => true - | (list{aHead, ...aRest}, list{bHead, ...bRest}) => - if aHead !== bHead { - true - } else { - listNotEqual(aRest, bRest) - } - } - a.hash !== b.hash || (a.search !== b.search || listNotEqual(a.path, b.path)) -} -type watcherID = unit => unit -let url = () => {path: path(), hash: hash(), search: search()} -/* alias exposed publicly */ -let dangerouslyGetInitialUrl = url -let watchUrl = callback => - switch window { - | None => () => () - | Some(window) => - let watcherID = () => callback(url()) - addEventListener(window, "popstate", watcherID) - watcherID - } -let unwatchUrl = watcherID => - switch window { - | None => () - | Some(window) => removeEventListener(window, "popstate", watcherID) - } - -let useUrl = (~serverUrl=?, ()) => { - let (url, setUrl) = React.useState(() => - switch serverUrl { - | Some(url) => url - | None => dangerouslyGetInitialUrl() - } - ) - - React.useEffect0(() => { - let watcherId = watchUrl(url => setUrl(_ => url)) - - /* - * check for updates that may have occured between - * the initial state and the subscribe above - */ - let newUrl = dangerouslyGetInitialUrl() - if urlNotEqual(newUrl, url) { - setUrl(_ => newUrl) - } - - Some(() => unwatchUrl(watcherId)) - }) - - url -} diff --git a/tests/tests/src/reasonReactRouter.resi b/tests/tests/src/reasonReactRouter.resi deleted file mode 100644 index 65c9baed35..0000000000 --- a/tests/tests/src/reasonReactRouter.resi +++ /dev/null @@ -1,33 +0,0 @@ -/** update the url with the string path. Example: `push(\"/book/1\")`, `push(\"/books#title\")` */ -let push: string => unit -/** update the url with the string path. modifies the current history entry instead of creating a new one. Example: `replace(\"/book/1\")`, `replace(\"/books#title\")` */ -let replace: string => unit -type watcherID -type url = { - /* path takes window.location.path, like "/book/title/edit" and turns it into `["book", "title", "edit"]` */ - path: list, - /* the url's hash, if any. The # symbol is stripped out for you */ - hash: string, - /* the url's query params, if any. The ? symbol is stripped out for you */ - search: string, -} -/** start watching for URL changes. Returns a subscription token. Upon url change, calls the callback and passes it the url record */ -let watchUrl: (url => unit) => watcherID -/** stop watching for URL changes */ -let unwatchUrl: watcherID => unit -/** this is marked as \"dangerous\" because you technically shouldn't be accessing the URL outside of watchUrl's callback; - you'd read a potentially stale url, instead of the fresh one inside watchUrl. - - But this helper is sometimes needed, if you'd like to initialize a page whose display/state depends on the URL, - instead of reading from it in watchUrl's callback, which you'd probably have put inside didMount (aka too late, - the page's already rendered). - - So, the correct (and idiomatic) usage of this helper is to only use it in a component that's also subscribed to - watchUrl. Please see https://github.com/reasonml-community/reason-react-example/blob/master/src/todomvc/TodoItem.re - for an example. - */ -let dangerouslyGetInitialUrl: unit => url -/** hook for watching url changes. - * serverUrl is used for ssr. it allows you to specify the url without relying on browser apis existing/working as expected - */ -let useUrl: (~serverUrl: url=?, unit) => url From 302867471124e22f402734510b074e4b2039ed4b Mon Sep 17 00:00:00 2001 From: Christoph Knittel Date: Mon, 26 May 2025 17:15:44 +0200 Subject: [PATCH 08/14] Make @rescript/react package private --- packages/react/package.json | 31 +------------------------------ yarn.lock | 3 --- 2 files changed, 1 insertion(+), 33 deletions(-) diff --git a/packages/react/package.json b/packages/react/package.json index 358697059f..94de119333 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,37 +1,8 @@ { "name": "@rescript/react", "version": "0.14.0-rc.1", - "description": "React bindings for ReScript", - "files": [ - "README.md", - "CHANGELOG.md", - "LICENSE", - "rescript.json", - "src/**/*.res", - "src/**/*.resi" - ], - "scripts": { - "build": "rescript build", - "start": "rescript build -w", - "clean": "rescript clean -with-deps", - "test": "echo 'tests disabled for now'" - }, - "keywords": [ - "rescript", - "react" - ], - "author": "Ricky Vetter", - "license": "MIT", - "repository": { - "type": "git", - "url": "git+https://github.com/rescript-lang/rescript-react.git" - }, - "homepage": "https://rescript-lang.org/docs/react/latest/introduction", + "private": true, "dependencies": { "rescript": "workspace:^" - }, - "peerDependencies": { - "react": ">=19.0.0", - "react-dom": ">=19.0.0" } } diff --git a/yarn.lock b/yarn.lock index 0d5cd079b7..d6849a94b8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -417,9 +417,6 @@ __metadata: resolution: "@rescript/react@workspace:packages/react" dependencies: rescript: "workspace:^" - peerDependencies: - react: ">=19.0.0" - react-dom: ">=19.0.0" languageName: unknown linkType: soft From a7412766d587338587af526d5bd0888cc9b684fb Mon Sep 17 00:00:00 2001 From: Christoph Knittel Date: Mon, 26 May 2025 17:17:39 +0200 Subject: [PATCH 09/14] Format ReScript sources in packages folder, too --- packages/playground/src/App.res | 1 + packages/react/src/ReactEvent.res | 60 ++++++++----------------------- scripts/format.sh | 2 +- scripts/format_check.sh | 2 +- 4 files changed, 18 insertions(+), 47 deletions(-) diff --git a/packages/playground/src/App.res b/packages/playground/src/App.res index e69de29bb2..8b13789179 100644 --- a/packages/playground/src/App.res +++ b/packages/playground/src/App.res @@ -0,0 +1 @@ + diff --git a/packages/react/src/ReactEvent.res b/packages/react/src/ReactEvent.res index 2d927a1907..54ac5910c2 100644 --- a/packages/react/src/ReactEvent.res +++ b/packages/react/src/ReactEvent.res @@ -59,27 +59,21 @@ external toSyntheticEvent: synthetic<'a> => Synthetic.t = "%identity" module Clipboard = { type tag = JsxEvent.Clipboard.tag type t = synthetic - include MakeEventWithType({ - type t = t - }) + include MakeEventWithType({type t = t}) @get external clipboardData: t => {..} = "clipboardData" /* Should return Dom.dataTransfer */ } module Composition = { type tag = JsxEvent.Composition.tag type t = synthetic - include MakeEventWithType({ - type t = t - }) + include MakeEventWithType({type t = t}) @get external data: t => string = "data" } module Keyboard = { type tag = JsxEvent.Keyboard.tag type t = synthetic - include MakeEventWithType({ - type t = t - }) + include MakeEventWithType({type t = t}) @get external altKey: t => bool = "altKey" @get external charCode: t => int = "charCode" @get external code: t => string = "code" @@ -99,9 +93,7 @@ module Keyboard = { module Focus = { type tag = JsxEvent.Focus.tag type t = synthetic - include MakeEventWithType({ - type t = t - }) + include MakeEventWithType({type t = t}) @get @return(nullable) external relatedTarget: t => option<{..}> = "relatedTarget" /* Should return Dom.eventTarget */ } @@ -109,17 +101,13 @@ module Focus = { module Form = { type tag = JsxEvent.Form.tag type t = synthetic - include MakeEventWithType({ - type t = t - }) + include MakeEventWithType({type t = t}) } module Mouse = { type tag = JsxEvent.Mouse.tag type t = synthetic - include MakeEventWithType({ - type t = t - }) + include MakeEventWithType({type t = t}) @get external altKey: t => bool = "altKey" @get external button: t => int = "button" @get external buttons: t => int = "buttons" @@ -143,9 +131,7 @@ module Mouse = { module Pointer = { type tag = JsxEvent.Pointer.tag type t = synthetic - include MakeEventWithType({ - type t = t - }) + include MakeEventWithType({type t = t}) // UIEvent @get external detail: t => int = "detail" @@ -190,17 +176,13 @@ module Pointer = { module Selection = { type tag = JsxEvent.Selection.tag type t = synthetic - include MakeEventWithType({ - type t = t - }) + include MakeEventWithType({type t = t}) } module Touch = { type tag = JsxEvent.Touch.tag type t = synthetic - include MakeEventWithType({ - type t = t - }) + include MakeEventWithType({type t = t}) @get external altKey: t => bool = "altKey" @get external changedTouches: t => {..} = "changedTouches" /* Should return Dom.touchList */ @get external ctrlKey: t => bool = "ctrlKey" @@ -215,9 +197,7 @@ module Touch = { module UI = { type tag = JsxEvent.UI.tag type t = synthetic - include MakeEventWithType({ - type t = t - }) + include MakeEventWithType({type t = t}) @get external detail: t => int = "detail" @get external view: t => Dom.window = "view" /* Should return DOMAbstractView/WindowProxy */ } @@ -225,9 +205,7 @@ module UI = { module Wheel = { type tag = JsxEvent.Wheel.tag type t = synthetic - include MakeEventWithType({ - type t = t - }) + include MakeEventWithType({type t = t}) @get external deltaMode: t => int = "deltaMode" @get external deltaX: t => float = "deltaX" @get external deltaY: t => float = "deltaY" @@ -237,25 +215,19 @@ module Wheel = { module Media = { type tag = JsxEvent.Media.tag type t = synthetic - include MakeEventWithType({ - type t = t - }) + include MakeEventWithType({type t = t}) } module Image = { type tag = JsxEvent.Image.tag type t = synthetic - include MakeEventWithType({ - type t = t - }) + include MakeEventWithType({type t = t}) } module Animation = { type tag = JsxEvent.Animation.tag type t = synthetic - include MakeEventWithType({ - type t = t - }) + include MakeEventWithType({type t = t}) @get external animationName: t => string = "animationName" @get external pseudoElement: t => string = "pseudoElement" @get external elapsedTime: t => float = "elapsedTime" @@ -264,9 +236,7 @@ module Animation = { module Transition = { type tag = JsxEvent.Transition.tag type t = synthetic - include MakeEventWithType({ - type t = t - }) + include MakeEventWithType({type t = t}) @get external propertyName: t => string = "propertyName" @get external pseudoElement: t => string = "pseudoElement" @get external elapsedTime: t => float = "elapsedTime" diff --git a/scripts/format.sh b/scripts/format.sh index b9b8f0fed7..ae7638e68b 100755 --- a/scripts/format.sh +++ b/scripts/format.sh @@ -4,7 +4,7 @@ shopt -s extglob dune build @fmt --auto-promote -files=$(find runtime tests -type f \( -name "*.res" -o -name "*.resi" \) ! -name "syntaxErrors*" ! -name "generated_mocha_test.res" ! -path "tests/syntax_*" ! -path "tests/analysis_tests/tests*" ! -path "*/node_modules/*") +files=$(find runtime tests packages -type f \( -name "*.res" -o -name "*.resi" \) ! -name "syntaxErrors*" ! -name "generated_mocha_test.res" ! -path "tests/syntax_*" ! -path "tests/analysis_tests/tests*" ! -path "*/node_modules/*") ./cli/rescript.js format $files yarn format diff --git a/scripts/format_check.sh b/scripts/format_check.sh index 656f86a732..73241ccf99 100755 --- a/scripts/format_check.sh +++ b/scripts/format_check.sh @@ -17,7 +17,7 @@ case "$(uname -s)" in fi echo "Checking ReScript code formatting..." - files=$(find runtime tests -type f \( -name "*.res" -o -name "*.resi" \) ! -name "syntaxErrors*" ! -name "generated_mocha_test.res" ! -path "tests/syntax_*" ! -path "tests/analysis_tests/tests*" ! -path "*/node_modules/*") + files=$(find runtime tests packages -type f \( -name "*.res" -o -name "*.resi" \) ! -name "syntaxErrors*" ! -name "generated_mocha_test.res" ! -path "tests/syntax_*" ! -path "tests/analysis_tests/tests*" ! -path "*/node_modules/*") if ./cli/rescript.js format -check $files; then printf "${successGreen}✅ ReScript code formatting ok.${reset}\n" else From de23cb4ff023702164859bbe403aced991b9ee6d Mon Sep 17 00:00:00 2001 From: Christoph Knittel Date: Tue, 27 May 2025 08:49:54 +0200 Subject: [PATCH 10/14] Revert "Remove tests/dependencies/rescript-react" This reverts commit 3bb883d9f04c227fe964b6cd729ffc6ac650a10d. # Conflicts: # yarn.lock --- package.json | 1 + tests/dependencies/.gitattributes | 1 + tests/dependencies/.gitignore | 1 + .../dependencies/rescript-react/package.json | 4 + .../dependencies/rescript-react/rescript.json | 10 + .../dependencies/rescript-react/src/React.res | 407 +++++++++++++++ .../rescript-react/src/ReactDOM.res | 73 +++ .../rescript-react/src/ReactDOMStyle.res | 16 + .../rescript-react/src/ReactEvent.res | 243 +++++++++ .../rescript-react/src/ReactEvent.resi | 472 ++++++++++++++++++ yarn.lock | 6 + 11 files changed, 1234 insertions(+) create mode 100644 tests/dependencies/.gitattributes create mode 100644 tests/dependencies/.gitignore create mode 100644 tests/dependencies/rescript-react/package.json create mode 100644 tests/dependencies/rescript-react/rescript.json create mode 100644 tests/dependencies/rescript-react/src/React.res create mode 100644 tests/dependencies/rescript-react/src/ReactDOM.res create mode 100644 tests/dependencies/rescript-react/src/ReactDOMStyle.res create mode 100644 tests/dependencies/rescript-react/src/ReactEvent.res create mode 100644 tests/dependencies/rescript-react/src/ReactEvent.resi diff --git a/package.json b/package.json index 27282a67d6..969c0131df 100644 --- a/package.json +++ b/package.json @@ -94,6 +94,7 @@ "workspaces": [ "packages/*", "packages/@rescript/*", + "tests/dependencies/**", "tests/analysis_tests/**", "tests/gentype_tests/**", "tests/tests", diff --git a/tests/dependencies/.gitattributes b/tests/dependencies/.gitattributes new file mode 100644 index 0000000000..36eaad9fbd --- /dev/null +++ b/tests/dependencies/.gitattributes @@ -0,0 +1 @@ +* linguist-vendored diff --git a/tests/dependencies/.gitignore b/tests/dependencies/.gitignore new file mode 100644 index 0000000000..521ebedd3d --- /dev/null +++ b/tests/dependencies/.gitignore @@ -0,0 +1 @@ +*.res.js diff --git a/tests/dependencies/rescript-react/package.json b/tests/dependencies/rescript-react/package.json new file mode 100644 index 0000000000..cd0136bdd3 --- /dev/null +++ b/tests/dependencies/rescript-react/package.json @@ -0,0 +1,4 @@ +{ + "name": "@tests/rescript-react", + "private": true +} diff --git a/tests/dependencies/rescript-react/rescript.json b/tests/dependencies/rescript-react/rescript.json new file mode 100644 index 0000000000..e1339a2b05 --- /dev/null +++ b/tests/dependencies/rescript-react/rescript.json @@ -0,0 +1,10 @@ +{ + "name": "@rescript/react", + "jsx": { + "version": 4, + "mode": "classic" + }, + "sources": { "dir": "src", "subdirs": true }, + "package-specs": { "module": "commonjs", "in-source": true }, + "suffix": ".res.js" +} diff --git a/tests/dependencies/rescript-react/src/React.res b/tests/dependencies/rescript-react/src/React.res new file mode 100644 index 0000000000..0beaa59080 --- /dev/null +++ b/tests/dependencies/rescript-react/src/React.res @@ -0,0 +1,407 @@ +type element = Jsx.element + +@val external null: element = "null" + +external float: float => element = "%identity" +external int: int => element = "%identity" +external string: string => element = "%identity" + +external array: array => element = "%identity" + +type componentLike<'props, 'return> = Jsx.componentLike<'props, 'return> + +type component<'props> = Jsx.component<'props> + +external component: componentLike<'props, element> => component<'props> = "%identity" + +@module("react") +external createElement: (component<'props>, 'props) => element = "createElement" + +@module("react") +external cloneElement: (element, 'props) => element = "cloneElement" + +@module("react") +external isValidElement: 'a => bool = "isValidElement" + +@variadic @module("react") +external createElementVariadic: (component<'props>, 'props, array) => element = + "createElement" + +@module("react/jsx-runtime") +external jsx: (component<'props>, 'props) => element = "jsx" + +@module("react/jsx-runtime") +external jsxKeyed: (component<'props>, 'props, ~key: string=?, @ignore unit) => element = "jsx" + +@module("react/jsx-runtime") +external jsxs: (component<'props>, 'props) => element = "jsxs" + +@module("react/jsx-runtime") +external jsxsKeyed: (component<'props>, 'props, ~key: string=?, @ignore unit) => element = "jsxs" + +type fragmentProps = {children?: element} + +@module("react/jsx-runtime") external jsxFragment: component = "Fragment" + +type ref<'value> = {mutable current: 'value} + +@module("react") +external createRef: unit => ref> = "createRef" + +module Children = { + @module("react") @scope("Children") + external map: (element, element => element) => element = "map" + @module("react") @scope("Children") + external mapWithIndex: (element, (element, int) => element) => element = "map" + @module("react") @scope("Children") + external forEach: (element, element => unit) => unit = "forEach" + @module("react") @scope("Children") + external forEachWithIndex: (element, (element, int) => unit) => unit = "forEach" + @module("react") @scope("Children") + external count: element => int = "count" + @module("react") @scope("Children") + external only: element => element = "only" + @module("react") @scope("Children") + external toArray: element => array = "toArray" +} + +module Context = { + type t<'context> + + type props<'context> = { + value: 'context, + children: element, + } + + @get + external provider: t<'context> => component> = "Provider" +} + +@module("react") +external createContext: 'a => Context.t<'a> = "createContext" + +@module("react") +external forwardRef: (('props, Js.Nullable.t>) => element) => component<'props> = + "forwardRef" + +@module("react") +external memo: component<'props> => component<'props> = "memo" + +@module("react") +external memoCustomCompareProps: ( + component<'props>, + ('props, 'props) => bool, +) => component<'props> = "memo" + +@module("react") external fragment: component = "Fragment" + +module Fragment = { + type props = {key?: string, children: element} + + @module("react") + external make: component = "Fragment" +} + +module StrictMode = { + type props = {key?: string, children: element} + + @module("react") + external make: component = "StrictMode" +} + +module Suspense = { + type props = {key?: string, children?: element, fallback?: element} + + @module("react") + external make: component = "Suspense" +} + +type dynamicallyImportedModule<'a> = {default: component<'a>} + +@module("react") +external lazy_: (unit => promise>) => component<'a> = "lazy" + +let lazy_ = load => lazy_(async () => {default: await load()}) + +/* HOOKS */ + +/* + * Yeah, we know this api isn't great. tl;dr: useReducer instead. + * It's because useState can take functions or non-function values and treats + * them differently. Lazy initializer + callback which returns state is the + * only way to safely have any type of state and be able to update it correctly. + */ +@module("react") +external useState: (unit => 'state) => ('state, ('state => 'state) => unit) = "useState" + +@module("react") +external useReducer: (('state, 'action) => 'state, 'state) => ('state, 'action => unit) = + "useReducer" + +@module("react") +external useReducerWithMapState: ( + ('state, 'action) => 'state, + 'initialState, + 'initialState => 'state, +) => ('state, 'action => unit) = "useReducer" + +@module("react") +external useEffectOnEveryRender: (unit => option unit>) => unit = "useEffect" +@module("react") +external useEffect: (unit => option unit>, 'deps) => unit = "useEffect" +@module("react") +external useEffect0: (unit => option unit>, @as(json`[]`) _) => unit = "useEffect" +@module("react") +external useEffect1: (unit => option unit>, array<'a>) => unit = "useEffect" +@module("react") +external useEffect2: (unit => option unit>, ('a, 'b)) => unit = "useEffect" +@module("react") +external useEffect3: (unit => option unit>, ('a, 'b, 'c)) => unit = "useEffect" +@module("react") +external useEffect4: (unit => option unit>, ('a, 'b, 'c, 'd)) => unit = "useEffect" +@module("react") +external useEffect5: (unit => option unit>, ('a, 'b, 'c, 'd, 'e)) => unit = "useEffect" +@module("react") +external useEffect6: (unit => option unit>, ('a, 'b, 'c, 'd, 'e, 'f)) => unit = "useEffect" +@module("react") +external useEffect7: (unit => option unit>, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => unit = + "useEffect" + +@module("react") +external useLayoutEffectOnEveryRender: (unit => option unit>) => unit = "useLayoutEffect" +@module("react") +external useLayoutEffect: (unit => option unit>, 'deps) => unit = "useLayoutEffect" +@module("react") +external useLayoutEffect0: (unit => option unit>, @as(json`[]`) _) => unit = + "useLayoutEffect" +@module("react") +external useLayoutEffect1: (unit => option unit>, array<'a>) => unit = "useLayoutEffect" +@module("react") +external useLayoutEffect2: (unit => option unit>, ('a, 'b)) => unit = "useLayoutEffect" +@module("react") +external useLayoutEffect3: (unit => option unit>, ('a, 'b, 'c)) => unit = "useLayoutEffect" +@module("react") +external useLayoutEffect4: (unit => option unit>, ('a, 'b, 'c, 'd)) => unit = + "useLayoutEffect" +@module("react") +external useLayoutEffect5: (unit => option unit>, ('a, 'b, 'c, 'd, 'e)) => unit = + "useLayoutEffect" +@module("react") +external useLayoutEffect6: (unit => option unit>, ('a, 'b, 'c, 'd, 'e, 'f)) => unit = + "useLayoutEffect" +@module("react") +external useLayoutEffect7: (unit => option unit>, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => unit = + "useLayoutEffect" + +@module("react") +external useMemo: (unit => 'any, 'deps) => 'any = "useMemo" + +@module("react") +external useMemo0: (unit => 'any, @as(json`[]`) _) => 'any = "useMemo" + +@module("react") +external useMemo1: (unit => 'any, array<'a>) => 'any = "useMemo" + +@module("react") +external useMemo2: (unit => 'any, ('a, 'b)) => 'any = "useMemo" + +@module("react") +external useMemo3: (unit => 'any, ('a, 'b, 'c)) => 'any = "useMemo" + +@module("react") +external useMemo4: (unit => 'any, ('a, 'b, 'c, 'd)) => 'any = "useMemo" + +@module("react") +external useMemo5: (unit => 'any, ('a, 'b, 'c, 'd, 'e)) => 'any = "useMemo" + +@module("react") +external useMemo6: (unit => 'any, ('a, 'b, 'c, 'd, 'e, 'f)) => 'any = "useMemo" + +@module("react") +external useMemo7: (unit => 'any, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => 'any = "useMemo" + +@module("react") +external useCallback: ('f, 'deps) => 'f = "useCallback" + +@module("react") +external useCallback0: ('f, @as(json`[]`) _) => 'f = "useCallback" + +@module("react") +external useCallback1: ('f, array<'a>) => 'f = "useCallback" + +@module("react") +external useCallback2: ('f, ('a, 'b)) => 'f = "useCallback" + +@module("react") +external useCallback3: ('f, ('a, 'b, 'c)) => 'f = "useCallback" + +@module("react") +external useCallback4: ('f, ('a, 'b, 'c, 'd)) => 'f = "useCallback" + +@module("react") +external useCallback5: ('f, ('a, 'b, 'c, 'd, 'e)) => 'f = "useCallback" + +@module("react") +external useCallback6: ('callback, ('a, 'b, 'c, 'd, 'e, 'f)) => 'callback = "useCallback" + +@module("react") +external useCallback7: ('callback, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => 'callback = "useCallback" + +@module("react") +external useContext: Context.t<'any> => 'any = "useContext" + +@module("react") external useRef: 'value => ref<'value> = "useRef" + +@module("react") +external useImperativeHandleOnEveryRender: (Js.Nullable.t>, unit => 'value) => unit = + "useImperativeHandle" + +@module("react") +external useImperativeHandle: (Js.Nullable.t>, unit => 'value, 'deps) => unit = + "useImperativeHandle" + +@module("react") +external useImperativeHandle0: ( + Js.Nullable.t>, + unit => 'value, + @as(json`[]`) _, +) => unit = "useImperativeHandle" + +@module("react") +external useImperativeHandle1: (Js.Nullable.t>, unit => 'value, array<'a>) => unit = + "useImperativeHandle" + +@module("react") +external useImperativeHandle2: (Js.Nullable.t>, unit => 'value, ('a, 'b)) => unit = + "useImperativeHandle" + +@module("react") +external useImperativeHandle3: (Js.Nullable.t>, unit => 'value, ('a, 'b, 'c)) => unit = + "useImperativeHandle" + +@module("react") +external useImperativeHandle4: ( + Js.Nullable.t>, + unit => 'value, + ('a, 'b, 'c, 'd), +) => unit = "useImperativeHandle" + +@module("react") +external useImperativeHandle5: ( + Js.Nullable.t>, + unit => 'value, + ('a, 'b, 'c, 'd, 'e), +) => unit = "useImperativeHandle" + +@module("react") +external useImperativeHandle6: ( + Js.Nullable.t>, + unit => 'value, + ('a, 'b, 'c, 'd, 'e, 'f), +) => unit = "useImperativeHandle" + +@module("react") +external useImperativeHandle7: ( + Js.Nullable.t>, + unit => 'value, + ('a, 'b, 'c, 'd, 'e, 'f, 'g), +) => unit = "useImperativeHandle" + +@module("react") external useId: unit => string = "useId" + +@module("react") external useDeferredValue: 'value => 'value = "useDeferredValue" + +@module("react") +external useTransition: unit => (bool, (unit => unit) => unit) = "useTransition" + +@module("react") +external useInsertionEffectOnEveryRender: (unit => option unit>) => unit = + "useInsertionEffect" +@module("react") +external useInsertionEffect: (unit => option unit>, 'deps) => unit = "useInsertionEffect" +@module("react") +external useInsertionEffect0: (unit => option unit>, @as(json`[]`) _) => unit = + "useInsertionEffect" +@module("react") +external useInsertionEffect1: (unit => option unit>, array<'a>) => unit = + "useInsertionEffect" +@module("react") +external useInsertionEffect2: (unit => option unit>, ('a, 'b)) => unit = + "useInsertionEffect" +@module("react") +external useInsertionEffect3: (unit => option unit>, ('a, 'b, 'c)) => unit = + "useInsertionEffect" +@module("react") +external useInsertionEffect4: (unit => option unit>, ('a, 'b, 'c, 'd)) => unit = + "useInsertionEffect" +@module("react") +external useInsertionEffect5: (unit => option unit>, ('a, 'b, 'c, 'd, 'e)) => unit = + "useInsertionEffect" +@module("react") +external useInsertionEffect6: (unit => option unit>, ('a, 'b, 'c, 'd, 'e, 'f)) => unit = + "useInsertionEffect" +@module("react") +external useInsertionEffect7: (unit => option unit>, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => unit = + "useInsertionEffect" + +@module("react") +external useSyncExternalStore: ( + ~subscribe: (unit => unit) => unit => unit, + ~getSnapshot: unit => 'state, +) => 'state = "useSyncExternalStore" + +@module("react") +external useSyncExternalStoreWithServerSnapshot: ( + ~subscribe: (unit => unit) => unit => unit, + ~getSnapshot: unit => 'state, + ~getServerSnapshot: unit => 'state, +) => 'state = "useSyncExternalStore" + +module Uncurried = { + @module("react") + external useState: (unit => 'state) => ('state, ('state => 'state) => unit) = "useState" + + @module("react") + external useReducer: (('state, 'action) => 'state, 'state) => ('state, 'action => unit) = + "useReducer" + + @module("react") + external useReducerWithMapState: ( + ('state, 'action) => 'state, + 'initialState, + 'initialState => 'state, + ) => ('state, 'action => unit) = "useReducer" + + @module("react") + external useCallback: ('f, 'deps) => 'f = "useCallback" + + @module("react") + external useCallback0: ('f, @as(json`[]`) _) => 'f = "useCallback" + + @module("react") + external useCallback1: ('f, array<'a>) => 'f = "useCallback" + + @module("react") + external useCallback2: ('f, ('a, 'b)) => 'f = "useCallback" + + @module("react") + external useCallback3: ('f, ('a, 'b, 'c)) => 'f = "useCallback" + + @module("react") + external useCallback4: ('f, ('a, 'b, 'c, 'd)) => 'f = "useCallback" + + @module("react") + external useCallback5: ('f, ('a, 'b, 'c, 'd, 'e)) => 'f = "useCallback" + + @module("react") + external useCallback6: ('callback, ('a, 'b, 'c, 'd, 'e, 'f)) => 'callback = "useCallback" + + @module("react") + external useCallback7: ('callback, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => 'callback = "useCallback" +} + +@set +external setDisplayName: (component<'props>, string) => unit = "displayName" + +@get @return(nullable) +external displayName: component<'props> => option = "displayName" diff --git a/tests/dependencies/rescript-react/src/ReactDOM.res b/tests/dependencies/rescript-react/src/ReactDOM.res new file mode 100644 index 0000000000..04c39c2647 --- /dev/null +++ b/tests/dependencies/rescript-react/src/ReactDOM.res @@ -0,0 +1,73 @@ +/* First time reading a ReScript file? */ +/* `external` is the foreign function call in OCaml. */ +/* here we're saying `I guarantee that on the JS side, we have a `render` function in the module "react-dom" + that takes in a reactElement, a dom element, and returns unit (nothing) */ +/* It's like `let`, except you're pointing the implementation to the JS side. The compiler will inline these + calls and add the appropriate `require("react-dom")` in the file calling this `render` */ + +// Helper so that ReactDOM itself doesn't bring any runtime +@val @return(nullable) +external querySelector: string => option = "document.querySelector" + +module Client = { + module Root = { + type t + + @send external render: (t, React.element) => unit = "render" + + @send external unmount: (t, unit) => unit = "unmount" + } + + @module("react-dom/client") + external createRoot: Dom.element => Root.t = "createRoot" + + @module("react-dom/client") + external hydrateRoot: (Dom.element, React.element) => Root.t = "hydrateRoot" +} + +@module("react-dom") +external createPortal: (React.element, Dom.element) => React.element = "createPortal" + +external domElementToObj: Dom.element => {..} = "%identity" + +type style = ReactDOMStyle.t + +type domRef = JsxDOM.domRef + +module Ref = { + type t = domRef + type currentDomRef = React.ref> + type callbackDomRef = Js.nullable => unit + + external domRef: currentDomRef => domRef = "%identity" + external callbackDomRef: callbackDomRef => domRef = "%identity" +} + +type domProps = JsxDOM.domProps + +@variadic @module("react") +external createElement: (string, ~props: domProps=?, array) => React.element = + "createElement" + +@variadic @module("react") +external createDOMElementVariadic: ( + string, + ~props: domProps=?, + array, +) => React.element = "createElement" + +external someElement: React.element => option = "%identity" + +@module("react/jsx-runtime") +external jsx: (string, JsxDOM.domProps) => Jsx.element = "jsx" + +@module("react/jsx-runtime") +external jsxKeyed: (string, JsxDOM.domProps, ~key: string=?, @ignore unit) => Jsx.element = "jsx" + +@module("react/jsx-runtime") +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 = ReactDOMStyle diff --git a/tests/dependencies/rescript-react/src/ReactDOMStyle.res b/tests/dependencies/rescript-react/src/ReactDOMStyle.res new file mode 100644 index 0000000000..ae68d03554 --- /dev/null +++ b/tests/dependencies/rescript-react/src/ReactDOMStyle.res @@ -0,0 +1,16 @@ +type t = JsxDOMStyle.t + +/* CSS2Properties: https://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSS2Properties */ +@val +external combine: (@as(json`{}`) _, t, t) => t = "Object.assign" + +external _dictToStyle: Js.Dict.t => t = "%identity" + +let unsafeAddProp = (style, key, value) => { + let dict = Js.Dict.empty() + Js.Dict.set(dict, key, value) + combine(style, _dictToStyle(dict)) +} + +@val +external unsafeAddStyle: (@as(json`{}`) _, t, {..}) => t = "Object.assign" diff --git a/tests/dependencies/rescript-react/src/ReactEvent.res b/tests/dependencies/rescript-react/src/ReactEvent.res new file mode 100644 index 0000000000..54ac5910c2 --- /dev/null +++ b/tests/dependencies/rescript-react/src/ReactEvent.res @@ -0,0 +1,243 @@ +type synthetic<'a> = JsxEvent.synthetic<'a> + +module MakeEventWithType = ( + Type: { + type t + }, +) => { + @get external bubbles: Type.t => bool = "bubbles" + @get external cancelable: Type.t => bool = "cancelable" + @get + external currentTarget: Type.t => {..} = "currentTarget" /* Should return Dom.eventTarget */ + @get external defaultPrevented: Type.t => bool = "defaultPrevented" + @get external eventPhase: Type.t => int = "eventPhase" + @get external isTrusted: Type.t => bool = "isTrusted" + @get external nativeEvent: Type.t => {..} = "nativeEvent" /* Should return Dom.event */ + @send external preventDefault: Type.t => unit = "preventDefault" + @send + external isDefaultPrevented: Type.t => bool = "isDefaultPrevented" + @send external stopPropagation: Type.t => unit = "stopPropagation" + @send + external isPropagationStopped: Type.t => bool = "isPropagationStopped" + @get external target: Type.t => {..} = "target" /* Should return Dom.eventTarget */ + @get external timeStamp: Type.t => float = "timeStamp" + @get external type_: Type.t => string = "type" + @send external persist: Type.t => unit = "persist" +} + +module Synthetic = { + type tag = JsxEvent.Synthetic.tag + type t = synthetic + @get external bubbles: synthetic<'a> => bool = "bubbles" + @get external cancelable: synthetic<'a> => bool = "cancelable" + @get + external currentTarget: synthetic<'a> => {..} = + "currentTarget" /* Should return Dom.eventTarget */ + @get + external defaultPrevented: synthetic<'a> => bool = "defaultPrevented" + @get external eventPhase: synthetic<'a> => int = "eventPhase" + @get external isTrusted: synthetic<'a> => bool = "isTrusted" + @get + external nativeEvent: synthetic<'a> => {..} = "nativeEvent" /* Should return Dom.event */ + @send + external preventDefault: synthetic<'a> => unit = "preventDefault" + @send + external isDefaultPrevented: synthetic<'a> => bool = "isDefaultPrevented" + @send + external stopPropagation: synthetic<'a> => unit = "stopPropagation" + @send + external isPropagationStopped: synthetic<'a> => bool = "isPropagationStopped" + @get external target: synthetic<'a> => {..} = "target" /* Should return Dom.eventTarget */ + @get external timeStamp: synthetic<'a> => float = "timeStamp" + @get external type_: synthetic<'a> => string = "type" + @send external persist: synthetic<'a> => unit = "persist" +} + +/* Cast any event type to the general synthetic type. This is safe, since synthetic is more general */ +external toSyntheticEvent: synthetic<'a> => Synthetic.t = "%identity" + +module Clipboard = { + type tag = JsxEvent.Clipboard.tag + type t = synthetic + include MakeEventWithType({type t = t}) + @get external clipboardData: t => {..} = "clipboardData" /* Should return Dom.dataTransfer */ +} + +module Composition = { + type tag = JsxEvent.Composition.tag + type t = synthetic + include MakeEventWithType({type t = t}) + @get external data: t => string = "data" +} + +module Keyboard = { + type tag = JsxEvent.Keyboard.tag + type t = synthetic + include MakeEventWithType({type t = t}) + @get external altKey: t => bool = "altKey" + @get external charCode: t => int = "charCode" + @get external code: t => string = "code" + @get external ctrlKey: t => bool = "ctrlKey" + @send + external getModifierState: (t, string) => bool = "getModifierState" + @get external key: t => string = "key" + @get external keyCode: t => int = "keyCode" + @get external locale: t => string = "locale" + @get external location: t => int = "location" + @get external metaKey: t => bool = "metaKey" + @get external repeat: t => bool = "repeat" + @get external shiftKey: t => bool = "shiftKey" + @get external which: t => int = "which" +} + +module Focus = { + type tag = JsxEvent.Focus.tag + type t = synthetic + include MakeEventWithType({type t = t}) + @get @return(nullable) + external relatedTarget: t => option<{..}> = "relatedTarget" /* Should return Dom.eventTarget */ +} + +module Form = { + type tag = JsxEvent.Form.tag + type t = synthetic + include MakeEventWithType({type t = t}) +} + +module Mouse = { + type tag = JsxEvent.Mouse.tag + type t = synthetic + include MakeEventWithType({type t = t}) + @get external altKey: t => bool = "altKey" + @get external button: t => int = "button" + @get external buttons: t => int = "buttons" + @get external clientX: t => int = "clientX" + @get external clientY: t => int = "clientY" + @get external ctrlKey: t => bool = "ctrlKey" + @send + external getModifierState: (t, string) => bool = "getModifierState" + @get external metaKey: t => bool = "metaKey" + @get external movementX: t => int = "movementX" + @get external movementY: t => int = "movementY" + @get external pageX: t => int = "pageX" + @get external pageY: t => int = "pageY" + @get @return(nullable) + external relatedTarget: t => option<{..}> = "relatedTarget" /* Should return Dom.eventTarget */ + @get external screenX: t => int = "screenX" + @get external screenY: t => int = "screenY" + @get external shiftKey: t => bool = "shiftKey" +} + +module Pointer = { + type tag = JsxEvent.Pointer.tag + type t = synthetic + include MakeEventWithType({type t = t}) + + // UIEvent + @get external detail: t => int = "detail" + @get external view: t => Dom.window = "view" /* Should return DOMAbstractView/WindowProxy */ + + // MouseEvent + @get external screenX: t => int = "screenX" + @get external screenY: t => int = "screenY" + @get external clientX: t => int = "clientX" + @get external clientY: t => int = "clientY" + @get external pageX: t => int = "pageX" + @get external pageY: t => int = "pageY" + @get external movementX: t => int = "movementX" + @get external movementY: t => int = "movementY" + + @get external ctrlKey: t => bool = "ctrlKey" + @get external shiftKey: t => bool = "shiftKey" + @get external altKey: t => bool = "altKey" + @get external metaKey: t => bool = "metaKey" + @send + external getModifierState: (t, string) => bool = "getModifierState" + + @get external button: t => int = "button" + @get external buttons: t => int = "buttons" + + @get @return(nullable) + external relatedTarget: t => option<{..}> = "relatedTarget" /* Should return Dom.eventTarget */ + + // PointerEvent + @get external pointerId: t => Dom.eventPointerId = "pointerId" + @get external width: t => float = "width" + @get external height: t => float = "height" + @get external pressure: t => float = "pressure" + @get external tangentialPressure: t => float = "tangentialPressure" + @get external tiltX: t => int = "tiltX" + @get external tiltY: t => int = "tiltY" + @get external twist: t => int = "twist" + @get external pointerType: t => string = "pointerType" + @get external isPrimary: t => bool = "isPrimary" +} + +module Selection = { + type tag = JsxEvent.Selection.tag + type t = synthetic + include MakeEventWithType({type t = t}) +} + +module Touch = { + type tag = JsxEvent.Touch.tag + type t = synthetic + include MakeEventWithType({type t = t}) + @get external altKey: t => bool = "altKey" + @get external changedTouches: t => {..} = "changedTouches" /* Should return Dom.touchList */ + @get external ctrlKey: t => bool = "ctrlKey" + @send + external getModifierState: (t, string) => bool = "getModifierState" + @get external metaKey: t => bool = "metaKey" + @get external shiftKey: t => bool = "shiftKey" + @get external targetTouches: t => {..} = "targetTouches" /* Should return Dom.touchList */ + @get external touches: t => {..} = "touches" /* Should return Dom.touchList */ +} + +module UI = { + type tag = JsxEvent.UI.tag + type t = synthetic + include MakeEventWithType({type t = t}) + @get external detail: t => int = "detail" + @get external view: t => Dom.window = "view" /* Should return DOMAbstractView/WindowProxy */ +} + +module Wheel = { + type tag = JsxEvent.Wheel.tag + type t = synthetic + include MakeEventWithType({type t = t}) + @get external deltaMode: t => int = "deltaMode" + @get external deltaX: t => float = "deltaX" + @get external deltaY: t => float = "deltaY" + @get external deltaZ: t => float = "deltaZ" +} + +module Media = { + type tag = JsxEvent.Media.tag + type t = synthetic + include MakeEventWithType({type t = t}) +} + +module Image = { + type tag = JsxEvent.Image.tag + type t = synthetic + include MakeEventWithType({type t = t}) +} + +module Animation = { + type tag = JsxEvent.Animation.tag + type t = synthetic + include MakeEventWithType({type t = t}) + @get external animationName: t => string = "animationName" + @get external pseudoElement: t => string = "pseudoElement" + @get external elapsedTime: t => float = "elapsedTime" +} + +module Transition = { + type tag = JsxEvent.Transition.tag + type t = synthetic + include MakeEventWithType({type t = t}) + @get external propertyName: t => string = "propertyName" + @get external pseudoElement: t => string = "pseudoElement" + @get external elapsedTime: t => float = "elapsedTime" +} diff --git a/tests/dependencies/rescript-react/src/ReactEvent.resi b/tests/dependencies/rescript-react/src/ReactEvent.resi new file mode 100644 index 0000000000..61b5d4b5db --- /dev/null +++ b/tests/dependencies/rescript-react/src/ReactEvent.resi @@ -0,0 +1,472 @@ +/* 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. + + In each module, the type `t` commonly means "the type of that module" (OCaml convention). In our case, e.g. + `ReactEvent.Mouse.t` represents a ReactJS synthetic mouse event. You'd use it to type your props: + + ``` + type props = { + onClick: ReactEvent.Mouse.t => unit + }; + ``` + + All the methods and properties of a type of event are in the module, as seen below. + + Each module also has a `tag` type. You can ignore it; they're only needed by their `t` type. This way, we + get to allow a base `Synthetic` event module with generic methods. So e.g. even a mouse event (`Mouse.t`) + get to be passed to a generic handler: + + ``` + let handleClick = ({state, props}, event) => { + ReactEvent.Mouse.preventDefault(event); + ... + }; + let handleSubmit = ({state, props}, event) => { + // this handler can be triggered by either a Keyboard or a Mouse event; + // conveniently use the generic preventDefault + ReactEvent.Synthetic.preventDefault(event); + ... + }; + + let render = (_) => ; + ``` + + How to translate idioms from ReactJS: + + 1. myMouseEvent.preventDefault() -> ReactEvent.Mouse.preventDefault(myMouseEvent) + 2. myKeyboardEvent.which -> ReactEvent.Keyboard.which(myKeyboardEvent) + */ +type synthetic<'a> = JsxEvent.synthetic<'a> + +module Synthetic: { + type tag = JsxEvent.Synthetic.tag + type t = synthetic + @get external bubbles: synthetic<'a> => bool = "bubbles" + @get external cancelable: synthetic<'a> => bool = "cancelable" + @get + external currentTarget: synthetic<'a> => {..} = "currentTarget" + @get + external defaultPrevented: synthetic<'a> => bool = "defaultPrevented" + @get external eventPhase: synthetic<'a> => int = "eventPhase" + @get external isTrusted: synthetic<'a> => bool = "isTrusted" + @get + external nativeEvent: synthetic<'a> => {..} = "nativeEvent" + @send + external preventDefault: synthetic<'a> => unit = "preventDefault" + @send + external isDefaultPrevented: synthetic<'a> => bool = "isDefaultPrevented" + @send + external stopPropagation: synthetic<'a> => unit = "stopPropagation" + @send + external isPropagationStopped: synthetic<'a> => bool = "isPropagationStopped" + @get external target: synthetic<'a> => {..} = "target" + @get external timeStamp: synthetic<'a> => float = "timeStamp" + @get external type_: synthetic<'a> => string = "type" + @send external persist: synthetic<'a> => unit = "persist" +} + +/* Cast any event type to the general synthetic type. This is safe, since synthetic is more general */ +external toSyntheticEvent: synthetic<'a> => Synthetic.t = "%identity" + +module Clipboard: { + type tag = JsxEvent.Clipboard.tag + type t = synthetic + @get external bubbles: t => bool = "bubbles" + @get external cancelable: t => bool = "cancelable" + @get external currentTarget: t => {..} = "currentTarget" + @get external defaultPrevented: t => bool = "defaultPrevented" + @get external eventPhase: t => int = "eventPhase" + @get external isTrusted: t => bool = "isTrusted" + @get external nativeEvent: t => {..} = "nativeEvent" + @send external preventDefault: t => unit = "preventDefault" + @send external isDefaultPrevented: t => bool = "isDefaultPrevented" + @send external stopPropagation: t => unit = "stopPropagation" + @send external isPropagationStopped: t => bool = "isPropagationStopped" + @get external target: t => {..} = "target" + @get external timeStamp: t => float = "timeStamp" + @get external type_: t => string = "type" + @send external persist: t => unit = "persist" + @get external clipboardData: t => {..} = "clipboardData" /* Should return Dom.dataTransfer */ +} + +module Composition: { + type tag = JsxEvent.Composition.tag + type t = synthetic + @get external bubbles: t => bool = "bubbles" + @get external cancelable: t => bool = "cancelable" + @get external currentTarget: t => {..} = "currentTarget" + @get external defaultPrevented: t => bool = "defaultPrevented" + @get external eventPhase: t => int = "eventPhase" + @get external isTrusted: t => bool = "isTrusted" + @get external nativeEvent: t => {..} = "nativeEvent" + @send external preventDefault: t => unit = "preventDefault" + @send external isDefaultPrevented: t => bool = "isDefaultPrevented" + @send external stopPropagation: t => unit = "stopPropagation" + @send external isPropagationStopped: t => bool = "isPropagationStopped" + @get external target: t => {..} = "target" + @get external timeStamp: t => float = "timeStamp" + @get external type_: t => string = "type" + @send external persist: t => unit = "persist" + @get external data: t => string = "data" +} + +module Keyboard: { + type tag = JsxEvent.Keyboard.tag + type t = synthetic + @get external bubbles: t => bool = "bubbles" + @get external cancelable: t => bool = "cancelable" + @get external currentTarget: t => {..} = "currentTarget" + @get external defaultPrevented: t => bool = "defaultPrevented" + @get external eventPhase: t => int = "eventPhase" + @get external isTrusted: t => bool = "isTrusted" + @get external nativeEvent: t => {..} = "nativeEvent" + @send external preventDefault: t => unit = "preventDefault" + @send external isDefaultPrevented: t => bool = "isDefaultPrevented" + @send external stopPropagation: t => unit = "stopPropagation" + @send external isPropagationStopped: t => bool = "isPropagationStopped" + @get external target: t => {..} = "target" + @get external timeStamp: t => float = "timeStamp" + @get external type_: t => string = "type" + @send external persist: t => unit = "persist" + @get external altKey: t => bool = "altKey" + @get external charCode: t => int = "charCode" + @get external code: t => string = "code" + @get external ctrlKey: t => bool = "ctrlKey" + @send + external getModifierState: (t, string) => bool = "getModifierState" + @get external key: t => string = "key" + @get external keyCode: t => int = "keyCode" + @get external locale: t => string = "locale" + @get external location: t => int = "location" + @get external metaKey: t => bool = "metaKey" + @get external repeat: t => bool = "repeat" + @get external shiftKey: t => bool = "shiftKey" + @get external which: t => int = "which" +} + +module Focus: { + type tag = JsxEvent.Focus.tag + type t = synthetic + @get external bubbles: t => bool = "bubbles" + @get external cancelable: t => bool = "cancelable" + @get external currentTarget: t => {..} = "currentTarget" + @get external defaultPrevented: t => bool = "defaultPrevented" + @get external eventPhase: t => int = "eventPhase" + @get external isTrusted: t => bool = "isTrusted" + @get external nativeEvent: t => {..} = "nativeEvent" + @send external preventDefault: t => unit = "preventDefault" + @send external isDefaultPrevented: t => bool = "isDefaultPrevented" + @send external stopPropagation: t => unit = "stopPropagation" + @send external isPropagationStopped: t => bool = "isPropagationStopped" + @get external target: t => {..} = "target" + @get external timeStamp: t => float = "timeStamp" + @get external type_: t => string = "type" + @send external persist: t => unit = "persist" + @get @return(nullable) + external relatedTarget: t => option<{..}> = "relatedTarget" /* Should return Dom.eventTarget */ +} + +module Form: { + type tag = JsxEvent.Form.tag + type t = synthetic + @get external bubbles: t => bool = "bubbles" + @get external cancelable: t => bool = "cancelable" + @get external currentTarget: t => {..} = "currentTarget" + @get external defaultPrevented: t => bool = "defaultPrevented" + @get external eventPhase: t => int = "eventPhase" + @get external isTrusted: t => bool = "isTrusted" + @get external nativeEvent: t => {..} = "nativeEvent" + @send external preventDefault: t => unit = "preventDefault" + @send external isDefaultPrevented: t => bool = "isDefaultPrevented" + @send external stopPropagation: t => unit = "stopPropagation" + @send external isPropagationStopped: t => bool = "isPropagationStopped" + @get external target: t => {..} = "target" + @get external timeStamp: t => float = "timeStamp" + @get external type_: t => string = "type" + @send external persist: t => unit = "persist" +} + +module Mouse: { + type tag = JsxEvent.Mouse.tag + type t = synthetic + @get external bubbles: t => bool = "bubbles" + @get external cancelable: t => bool = "cancelable" + @get external currentTarget: t => {..} = "currentTarget" + @get external defaultPrevented: t => bool = "defaultPrevented" + @get external eventPhase: t => int = "eventPhase" + @get external isTrusted: t => bool = "isTrusted" + @get external nativeEvent: t => {..} = "nativeEvent" + @send external preventDefault: t => unit = "preventDefault" + @send external isDefaultPrevented: t => bool = "isDefaultPrevented" + @send external stopPropagation: t => unit = "stopPropagation" + @send external isPropagationStopped: t => bool = "isPropagationStopped" + @get external target: t => {..} = "target" + @get external timeStamp: t => float = "timeStamp" + @get external type_: t => string = "type" + @send external persist: t => unit = "persist" + @get external altKey: t => bool = "altKey" + @get external button: t => int = "button" + @get external buttons: t => int = "buttons" + @get external clientX: t => int = "clientX" + @get external clientY: t => int = "clientY" + @get external ctrlKey: t => bool = "ctrlKey" + @send + external getModifierState: (t, string) => bool = "getModifierState" + @get external metaKey: t => bool = "metaKey" + @get external movementX: t => int = "movementX" + @get external movementY: t => int = "movementY" + @get external pageX: t => int = "pageX" + @get external pageY: t => int = "pageY" + @get @return(nullable) + external relatedTarget: t => option<{..}> = "relatedTarget" /* Should return Dom.eventTarget */ + @get external screenX: t => int = "screenX" + @get external screenY: t => int = "screenY" + @get external shiftKey: t => bool = "shiftKey" +} + +module Pointer: { + type tag = JsxEvent.Pointer.tag + type t = synthetic + + // Event + @get external type_: t => string = "type" + @get external target: t => {..} = "target" + @get external currentTarget: t => {..} = "currentTarget" + + @get external eventPhase: t => int = "eventPhase" + + @send external stopPropagation: t => unit = "stopPropagation" // aka cancelBubble + @get external bubbles: t => bool = "bubbles" + @get external cancelable: t => bool = "cancelable" + @send external preventDefault: t => unit = "preventDefault" + @get external defaultPrevented: t => bool = "defaultPrevented" + + @get external isTrusted: t => bool = "isTrusted" + @get external timeStamp: t => float = "timeStamp" + + // SyntheticEvent + @get external nativeEvent: t => {..} = "nativeEvent" + @send external isDefaultPrevented: t => bool = "isDefaultPrevented" + @send external isPropagationStopped: t => bool = "isPropagationStopped" + @send external persist: t => unit = "persist" + + // UIEvent + @get external detail: t => int = "detail" + @get external view: t => Dom.window = "view" /* Should return DOMAbstractView/WindowProxy */ + + // MouseEvent + @get external screenX: t => int = "screenX" + @get external screenY: t => int = "screenY" + @get external clientX: t => int = "clientX" + @get external clientY: t => int = "clientY" + @get external pageX: t => int = "pageX" + @get external pageY: t => int = "pageY" + @get external movementX: t => int = "movementX" + @get external movementY: t => int = "movementY" + + @get external ctrlKey: t => bool = "ctrlKey" + @get external shiftKey: t => bool = "shiftKey" + @get external altKey: t => bool = "altKey" + @get external metaKey: t => bool = "metaKey" + @send + external getModifierState: (t, string) => bool = "getModifierState" + + @get external button: t => int = "button" + @get external buttons: t => int = "buttons" + + @get @return(nullable) + external relatedTarget: t => option<{..}> = "relatedTarget" /* Should return Dom.eventTarget */ + + // PointerEvent + @get external pointerId: t => Dom.eventPointerId = "pointerId" + @get external width: t => float = "width" + @get external height: t => float = "height" + @get external pressure: t => float = "pressure" + @get external tangentialPressure: t => float = "tangentialPressure" + @get external tiltX: t => int = "tiltX" + @get external tiltY: t => int = "tiltY" + @get external twist: t => int = "twist" + @get external pointerType: t => string = "pointerType" + @get external isPrimary: t => bool = "isPrimary" +} + +module Selection: { + type tag = JsxEvent.Selection.tag + type t = synthetic + @get external bubbles: t => bool = "bubbles" + @get external cancelable: t => bool = "cancelable" + @get external currentTarget: t => {..} = "currentTarget" + @get external defaultPrevented: t => bool = "defaultPrevented" + @get external eventPhase: t => int = "eventPhase" + @get external isTrusted: t => bool = "isTrusted" + @get external nativeEvent: t => {..} = "nativeEvent" + @send external preventDefault: t => unit = "preventDefault" + @send external isDefaultPrevented: t => bool = "isDefaultPrevented" + @send external stopPropagation: t => unit = "stopPropagation" + @send external isPropagationStopped: t => bool = "isPropagationStopped" + @get external target: t => {..} = "target" + @get external timeStamp: t => float = "timeStamp" + @get external type_: t => string = "type" + @send external persist: t => unit = "persist" +} + +module Touch: { + type tag = JsxEvent.Touch.tag + type t = synthetic + @get external bubbles: t => bool = "bubbles" + @get external cancelable: t => bool = "cancelable" + @get external currentTarget: t => {..} = "currentTarget" + @get external defaultPrevented: t => bool = "defaultPrevented" + @get external eventPhase: t => int = "eventPhase" + @get external isTrusted: t => bool = "isTrusted" + @get external nativeEvent: t => {..} = "nativeEvent" + @send external preventDefault: t => unit = "preventDefault" + @send external isDefaultPrevented: t => bool = "isDefaultPrevented" + @send external stopPropagation: t => unit = "stopPropagation" + @send external isPropagationStopped: t => bool = "isPropagationStopped" + @get external target: t => {..} = "target" + @get external timeStamp: t => float = "timeStamp" + @get external type_: t => string = "type" + @send external persist: t => unit = "persist" + @get external altKey: t => bool = "altKey" + @get external changedTouches: t => {..} = "changedTouches" /* Should return Dom.touchList */ + @get external ctrlKey: t => bool = "ctrlKey" + @send + external getModifierState: (t, string) => bool = "getModifierState" + @get external metaKey: t => bool = "metaKey" + @get external shiftKey: t => bool = "shiftKey" + @get external targetTouches: t => {..} = "targetTouches" /* Should return Dom.touchList */ + @get external touches: t => {..} = "touches" /* Should return Dom.touchList */ +} + +module UI: { + type tag = JsxEvent.UI.tag + type t = synthetic + @get external bubbles: t => bool = "bubbles" + @get external cancelable: t => bool = "cancelable" + @get external currentTarget: t => {..} = "currentTarget" + @get external defaultPrevented: t => bool = "defaultPrevented" + @get external eventPhase: t => int = "eventPhase" + @get external isTrusted: t => bool = "isTrusted" + @get external nativeEvent: t => {..} = "nativeEvent" + @send external preventDefault: t => unit = "preventDefault" + @send external isDefaultPrevented: t => bool = "isDefaultPrevented" + @send external stopPropagation: t => unit = "stopPropagation" + @send external isPropagationStopped: t => bool = "isPropagationStopped" + @get external target: t => {..} = "target" + @get external timeStamp: t => float = "timeStamp" + @get external type_: t => string = "type" + @send external persist: t => unit = "persist" + @get external detail: t => int = "detail" + @get external view: t => Dom.window = "view" /* Should return DOMAbstractView/WindowProxy */ +} + +module Wheel: { + type tag = JsxEvent.Wheel.tag + type t = synthetic + @get external bubbles: t => bool = "bubbles" + @get external cancelable: t => bool = "cancelable" + @get external currentTarget: t => {..} = "currentTarget" + @get external defaultPrevented: t => bool = "defaultPrevented" + @get external eventPhase: t => int = "eventPhase" + @get external isTrusted: t => bool = "isTrusted" + @get external nativeEvent: t => {..} = "nativeEvent" + @send external preventDefault: t => unit = "preventDefault" + @send external isDefaultPrevented: t => bool = "isDefaultPrevented" + @send external stopPropagation: t => unit = "stopPropagation" + @send external isPropagationStopped: t => bool = "isPropagationStopped" + @get external target: t => {..} = "target" + @get external timeStamp: t => float = "timeStamp" + @get external type_: t => string = "type" + @send external persist: t => unit = "persist" + @get external deltaMode: t => int = "deltaMode" + @get external deltaX: t => float = "deltaX" + @get external deltaY: t => float = "deltaY" + @get external deltaZ: t => float = "deltaZ" +} + +module Media: { + type tag = JsxEvent.Media.tag + type t = synthetic + @get external bubbles: t => bool = "bubbles" + @get external cancelable: t => bool = "cancelable" + @get external currentTarget: t => {..} = "currentTarget" + @get external defaultPrevented: t => bool = "defaultPrevented" + @get external eventPhase: t => int = "eventPhase" + @get external isTrusted: t => bool = "isTrusted" + @get external nativeEvent: t => {..} = "nativeEvent" + @send external preventDefault: t => unit = "preventDefault" + @send external isDefaultPrevented: t => bool = "isDefaultPrevented" + @send external stopPropagation: t => unit = "stopPropagation" + @send external isPropagationStopped: t => bool = "isPropagationStopped" + @get external target: t => {..} = "target" + @get external timeStamp: t => float = "timeStamp" + @get external type_: t => string = "type" + @send external persist: t => unit = "persist" +} + +module Image: { + type tag = JsxEvent.Image.tag + type t = synthetic + @get external bubbles: t => bool = "bubbles" + @get external cancelable: t => bool = "cancelable" + @get external currentTarget: t => {..} = "currentTarget" + @get external defaultPrevented: t => bool = "defaultPrevented" + @get external eventPhase: t => int = "eventPhase" + @get external isTrusted: t => bool = "isTrusted" + @get external nativeEvent: t => {..} = "nativeEvent" + @send external preventDefault: t => unit = "preventDefault" + @send external isDefaultPrevented: t => bool = "isDefaultPrevented" + @send external stopPropagation: t => unit = "stopPropagation" + @send external isPropagationStopped: t => bool = "isPropagationStopped" + @get external target: t => {..} = "target" + @get external timeStamp: t => float = "timeStamp" + @get external type_: t => string = "type" + @send external persist: t => unit = "persist" +} + +module Animation: { + type tag = JsxEvent.Animation.tag + type t = synthetic + @get external bubbles: t => bool = "bubbles" + @get external cancelable: t => bool = "cancelable" + @get external currentTarget: t => {..} = "currentTarget" + @get external defaultPrevented: t => bool = "defaultPrevented" + @get external eventPhase: t => int = "eventPhase" + @get external isTrusted: t => bool = "isTrusted" + @get external nativeEvent: t => {..} = "nativeEvent" + @send external preventDefault: t => unit = "preventDefault" + @send external isDefaultPrevented: t => bool = "isDefaultPrevented" + @send external stopPropagation: t => unit = "stopPropagation" + @send external isPropagationStopped: t => bool = "isPropagationStopped" + @get external target: t => {..} = "target" + @get external timeStamp: t => float = "timeStamp" + @get external type_: t => string = "type" + @send external persist: t => unit = "persist" + @get external animationName: t => string = "animationName" + @get external pseudoElement: t => string = "pseudoElement" + @get external elapsedTime: t => float = "elapsedTime" +} + +module Transition: { + type tag = JsxEvent.Transition.tag + type t = synthetic + @get external bubbles: t => bool = "bubbles" + @get external cancelable: t => bool = "cancelable" + @get external currentTarget: t => {..} = "currentTarget" + @get external defaultPrevented: t => bool = "defaultPrevented" + @get external eventPhase: t => int = "eventPhase" + @get external isTrusted: t => bool = "isTrusted" + @get external nativeEvent: t => {..} = "nativeEvent" + @send external preventDefault: t => unit = "preventDefault" + @send external isDefaultPrevented: t => bool = "isDefaultPrevented" + @send external stopPropagation: t => unit = "stopPropagation" + @send external isPropagationStopped: t => bool = "isPropagationStopped" + @get external target: t => {..} = "target" + @get external timeStamp: t => float = "timeStamp" + @get external type_: t => string = "type" + @send external persist: t => unit = "persist" + @get external propertyName: t => string = "propertyName" + @get external pseudoElement: t => string = "pseudoElement" + @get external elapsedTime: t => float = "elapsedTime" +} diff --git a/yarn.lock b/yarn.lock index d6849a94b8..056f7494ae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -663,6 +663,12 @@ __metadata: languageName: unknown linkType: soft +"@tests/rescript-react@workspace:tests/dependencies/rescript-react": + version: 0.0.0-use.local + resolution: "@tests/rescript-react@workspace:tests/dependencies/rescript-react" + languageName: unknown + linkType: soft + "@tests/tests@workspace:tests/tests": version: 0.0.0-use.local resolution: "@tests/tests@workspace:tests/tests" From f59e16fc81147b3006e943b967d9a3a21adcedc7 Mon Sep 17 00:00:00 2001 From: Christoph Knittel Date: Tue, 27 May 2025 08:54:10 +0200 Subject: [PATCH 11/14] Move packages/react over to test dependencies --- packages/react/package.json | 8 - packages/react/rescript.json | 12 - packages/react/src/React.bs.js | 33 -- packages/react/src/React.res | 443 ---------------- packages/react/src/ReactDOM.bs.js | 58 --- packages/react/src/ReactDOM.res | 249 --------- packages/react/src/ReactDOMServer.bs.js | 2 - packages/react/src/ReactDOMStatic.bs.js | 2 - packages/react/src/ReactDOMStyle.bs.js | 12 - packages/react/src/ReactDOMStyle.res | 16 - packages/react/src/ReactEvent.bs.js | 53 -- packages/react/src/ReactEvent.res | 243 --------- packages/react/src/ReactEvent.resi | 472 ------------------ packages/react/src/ReactTestUtils.bs.js | 105 ---- .../src/RescriptReactErrorBoundary.bs.js | 33 -- packages/react/src/RescriptReactRouter.bs.js | 219 -------- .../dependencies/rescript-react}/.gitignore | 0 .../dependencies/rescript-react}/LICENSE | 0 .../rescript-react}/package-lock.json | 0 .../dependencies/rescript-react/package.json | 8 +- .../dependencies/rescript-react/src/React.res | 42 +- .../rescript-react/src/ReactDOM.res | 178 ++++++- .../rescript-react}/src/ReactDOMServer.res | 0 .../rescript-react}/src/ReactDOMStatic.res | 0 .../rescript-react}/src/ReactTestUtils.res | 0 .../rescript-react}/src/ReactTestUtils.resi | 0 .../src/RescriptReactErrorBoundary.res | 4 +- .../src/RescriptReactErrorBoundary.resi | 4 +- .../src/RescriptReactRouter.res | 0 .../src/RescriptReactRouter.resi | 22 +- yarn.lock | 10 +- 31 files changed, 236 insertions(+), 1992 deletions(-) delete mode 100644 packages/react/package.json delete mode 100644 packages/react/rescript.json delete mode 100644 packages/react/src/React.bs.js delete mode 100644 packages/react/src/React.res delete mode 100644 packages/react/src/ReactDOM.bs.js delete mode 100644 packages/react/src/ReactDOM.res delete mode 100644 packages/react/src/ReactDOMServer.bs.js delete mode 100644 packages/react/src/ReactDOMStatic.bs.js delete mode 100644 packages/react/src/ReactDOMStyle.bs.js delete mode 100644 packages/react/src/ReactDOMStyle.res delete mode 100644 packages/react/src/ReactEvent.bs.js delete mode 100644 packages/react/src/ReactEvent.res delete mode 100644 packages/react/src/ReactEvent.resi delete mode 100644 packages/react/src/ReactTestUtils.bs.js delete mode 100644 packages/react/src/RescriptReactErrorBoundary.bs.js delete mode 100644 packages/react/src/RescriptReactRouter.bs.js rename {packages/react => tests/dependencies/rescript-react}/.gitignore (100%) rename {packages/react => tests/dependencies/rescript-react}/LICENSE (100%) rename {packages/react => tests/dependencies/rescript-react}/package-lock.json (100%) rename {packages/react => tests/dependencies/rescript-react}/src/ReactDOMServer.res (100%) rename {packages/react => tests/dependencies/rescript-react}/src/ReactDOMStatic.res (100%) rename {packages/react => tests/dependencies/rescript-react}/src/ReactTestUtils.res (100%) rename {packages/react => tests/dependencies/rescript-react}/src/ReactTestUtils.resi (100%) rename {packages/react => tests/dependencies/rescript-react}/src/RescriptReactErrorBoundary.res (98%) rename {packages/react => tests/dependencies/rescript-react}/src/RescriptReactErrorBoundary.resi (95%) rename {packages/react => tests/dependencies/rescript-react}/src/RescriptReactRouter.res (100%) rename {packages/react => tests/dependencies/rescript-react}/src/RescriptReactRouter.resi (68%) diff --git a/packages/react/package.json b/packages/react/package.json deleted file mode 100644 index 94de119333..0000000000 --- a/packages/react/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "@rescript/react", - "version": "0.14.0-rc.1", - "private": true, - "dependencies": { - "rescript": "workspace:^" - } -} diff --git a/packages/react/rescript.json b/packages/react/rescript.json deleted file mode 100644 index 599e1f6777..0000000000 --- a/packages/react/rescript.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "@rescript/react", - "jsx": { - "version": 4, - "mode": "classic" - }, - "sources": [{ "dir": "src", "subdirs": true }], - "package-specs": [{ "module": "commonjs", "in-source": true }], - "suffix": ".bs.js", - "bs-dev-dependencies": [], - "bsc-flags": [] -} diff --git a/packages/react/src/React.bs.js b/packages/react/src/React.bs.js deleted file mode 100644 index ef827dd7e4..0000000000 --- a/packages/react/src/React.bs.js +++ /dev/null @@ -1,33 +0,0 @@ -// Generated by ReScript, PLEASE EDIT WITH CARE -'use strict'; - -var React = require("react"); - -var Children = {}; - -var Context = {}; - -var Fragment = {}; - -var StrictMode = {}; - -var Suspense = {}; - -function lazy_(load) { - return React.lazy(async function () { - return { - default: await load() - }; - }); -} - -var Uncurried = {}; - -exports.Children = Children; -exports.Context = Context; -exports.Fragment = Fragment; -exports.StrictMode = StrictMode; -exports.Suspense = Suspense; -exports.lazy_ = lazy_; -exports.Uncurried = Uncurried; -/* react Not a pure module */ diff --git a/packages/react/src/React.res b/packages/react/src/React.res deleted file mode 100644 index f1f6831518..0000000000 --- a/packages/react/src/React.res +++ /dev/null @@ -1,443 +0,0 @@ -type element = Jsx.element - -@val external null: element = "null" - -external float: float => element = "%identity" -external int: int => element = "%identity" -external string: string => element = "%identity" -external promise: promise => element = "%identity" - -external array: array => element = "%identity" - -type componentLike<'props, 'return> = Jsx.componentLike<'props, 'return> - -type component<'props> = Jsx.component<'props> - -external component: componentLike<'props, element> => component<'props> = "%identity" - -@module("react") -external createElement: (component<'props>, 'props) => element = "createElement" - -@module("react") -external cloneElement: (element, 'props) => element = "cloneElement" - -@module("react") -external isValidElement: 'a => bool = "isValidElement" - -@variadic @module("react") -external createElementVariadic: (component<'props>, 'props, array) => element = - "createElement" - -@module("react/jsx-runtime") -external jsx: (component<'props>, 'props) => element = "jsx" - -@module("react/jsx-runtime") -external jsxKeyed: (component<'props>, 'props, ~key: string=?, @ignore unit) => element = "jsx" - -@module("react/jsx-runtime") -external jsxs: (component<'props>, 'props) => element = "jsxs" - -@module("react/jsx-runtime") -external jsxsKeyed: (component<'props>, 'props, ~key: string=?, @ignore unit) => element = "jsxs" - -type fragmentProps = {children?: element} - -@module("react/jsx-runtime") external jsxFragment: component = "Fragment" - -type ref<'value> = {mutable current: 'value} - -@module("react") -external createRef: unit => ref> = "createRef" - -module Children = { - @module("react") @scope("Children") - external map: (element, element => element) => element = "map" - @module("react") @scope("Children") - external mapWithIndex: (element, (element, int) => element) => element = "map" - @module("react") @scope("Children") - external forEach: (element, element => unit) => unit = "forEach" - @module("react") @scope("Children") - external forEachWithIndex: (element, (element, int) => unit) => unit = "forEach" - @module("react") @scope("Children") - external count: element => int = "count" - @module("react") @scope("Children") - external only: element => element = "only" - @module("react") @scope("Children") - external toArray: element => array = "toArray" -} - -module Context = { - type t<'context> - - type props<'context> = { - value: 'context, - children: element, - } - - @get - external provider: t<'context> => component> = "Provider" -} - -@module("react") -external createContext: 'a => Context.t<'a> = "createContext" - -@module("react") -external forwardRef: (('props, Js.Nullable.t>) => element) => component<'props> = - "forwardRef" - -@module("react") -external memo: component<'props> => component<'props> = "memo" - -@module("react") -external memoCustomCompareProps: ( - component<'props>, - ('props, 'props) => bool, -) => component<'props> = "memo" - -@module("react") external fragment: component = "Fragment" - -module Fragment = { - type props = {key?: string, children: element} - - @module("react") - external make: component = "Fragment" -} - -module StrictMode = { - type props = {key?: string, children: element} - - @module("react") - external make: component = "StrictMode" -} - -module Suspense = { - type props = {key?: string, children?: element, fallback?: element} - - @module("react") - external make: component = "Suspense" -} - -type dynamicallyImportedModule<'a> = {default: component<'a>} - -@module("react") -external lazy_: (unit => promise>) => component<'a> = "lazy" - -let lazy_ = load => lazy_(async () => {default: await load()}) - -/* HOOKS */ - -/* - * Yeah, we know this api isn't great. tl;dr: useReducer instead. - * It's because useState can take functions or non-function values and treats - * them differently. Lazy initializer + callback which returns state is the - * only way to safely have any type of state and be able to update it correctly. - */ -@module("react") -external useState: (unit => 'state) => ('state, ('state => 'state) => unit) = "useState" - -@module("react") -external useReducer: (('state, 'action) => 'state, 'state) => ('state, 'action => unit) = - "useReducer" - -@module("react") -external useReducerWithMapState: ( - ('state, 'action) => 'state, - 'initialState, - 'initialState => 'state, -) => ('state, 'action => unit) = "useReducer" - -@module("react") -external useEffectOnEveryRender: (unit => option unit>) => unit = "useEffect" -@module("react") -external useEffect: (unit => option unit>, 'deps) => unit = "useEffect" -@module("react") -external useEffect0: (unit => option unit>, @as(json`[]`) _) => unit = "useEffect" -@module("react") -external useEffect1: (unit => option unit>, array<'a>) => unit = "useEffect" -@module("react") -external useEffect2: (unit => option unit>, ('a, 'b)) => unit = "useEffect" -@module("react") -external useEffect3: (unit => option unit>, ('a, 'b, 'c)) => unit = "useEffect" -@module("react") -external useEffect4: (unit => option unit>, ('a, 'b, 'c, 'd)) => unit = "useEffect" -@module("react") -external useEffect5: (unit => option unit>, ('a, 'b, 'c, 'd, 'e)) => unit = "useEffect" -@module("react") -external useEffect6: (unit => option unit>, ('a, 'b, 'c, 'd, 'e, 'f)) => unit = "useEffect" -@module("react") -external useEffect7: (unit => option unit>, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => unit = - "useEffect" - -@module("react") -external useLayoutEffectOnEveryRender: (unit => option unit>) => unit = "useLayoutEffect" -@module("react") -external useLayoutEffect: (unit => option unit>, 'deps) => unit = "useLayoutEffect" -@module("react") -external useLayoutEffect0: (unit => option unit>, @as(json`[]`) _) => unit = - "useLayoutEffect" -@module("react") -external useLayoutEffect1: (unit => option unit>, array<'a>) => unit = "useLayoutEffect" -@module("react") -external useLayoutEffect2: (unit => option unit>, ('a, 'b)) => unit = "useLayoutEffect" -@module("react") -external useLayoutEffect3: (unit => option unit>, ('a, 'b, 'c)) => unit = "useLayoutEffect" -@module("react") -external useLayoutEffect4: (unit => option unit>, ('a, 'b, 'c, 'd)) => unit = - "useLayoutEffect" -@module("react") -external useLayoutEffect5: (unit => option unit>, ('a, 'b, 'c, 'd, 'e)) => unit = - "useLayoutEffect" -@module("react") -external useLayoutEffect6: (unit => option unit>, ('a, 'b, 'c, 'd, 'e, 'f)) => unit = - "useLayoutEffect" -@module("react") -external useLayoutEffect7: (unit => option unit>, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => unit = - "useLayoutEffect" - -@module("react") -external useMemo: (unit => 'any, 'deps) => 'any = "useMemo" - -@module("react") -external useMemo0: (unit => 'any, @as(json`[]`) _) => 'any = "useMemo" - -@module("react") -external useMemo1: (unit => 'any, array<'a>) => 'any = "useMemo" - -@module("react") -external useMemo2: (unit => 'any, ('a, 'b)) => 'any = "useMemo" - -@module("react") -external useMemo3: (unit => 'any, ('a, 'b, 'c)) => 'any = "useMemo" - -@module("react") -external useMemo4: (unit => 'any, ('a, 'b, 'c, 'd)) => 'any = "useMemo" - -@module("react") -external useMemo5: (unit => 'any, ('a, 'b, 'c, 'd, 'e)) => 'any = "useMemo" - -@module("react") -external useMemo6: (unit => 'any, ('a, 'b, 'c, 'd, 'e, 'f)) => 'any = "useMemo" - -@module("react") -external useMemo7: (unit => 'any, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => 'any = "useMemo" - -@module("react") -external useCallback: ('f, 'deps) => 'f = "useCallback" - -@module("react") -external useCallback0: ('f, @as(json`[]`) _) => 'f = "useCallback" - -@module("react") -external useCallback1: ('f, array<'a>) => 'f = "useCallback" - -@module("react") -external useCallback2: ('f, ('a, 'b)) => 'f = "useCallback" - -@module("react") -external useCallback3: ('f, ('a, 'b, 'c)) => 'f = "useCallback" - -@module("react") -external useCallback4: ('f, ('a, 'b, 'c, 'd)) => 'f = "useCallback" - -@module("react") -external useCallback5: ('f, ('a, 'b, 'c, 'd, 'e)) => 'f = "useCallback" - -@module("react") -external useCallback6: ('callback, ('a, 'b, 'c, 'd, 'e, 'f)) => 'callback = "useCallback" - -@module("react") -external useCallback7: ('callback, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => 'callback = "useCallback" - -@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") -external useImperativeHandleOnEveryRender: (Js.Nullable.t>, unit => 'value) => unit = - "useImperativeHandle" - -@module("react") -external useImperativeHandle: (Js.Nullable.t>, unit => 'value, 'deps) => unit = - "useImperativeHandle" - -@module("react") -external useImperativeHandle0: ( - Js.Nullable.t>, - unit => 'value, - @as(json`[]`) _, -) => unit = "useImperativeHandle" - -@module("react") -external useImperativeHandle1: (Js.Nullable.t>, unit => 'value, array<'a>) => unit = - "useImperativeHandle" - -@module("react") -external useImperativeHandle2: (Js.Nullable.t>, unit => 'value, ('a, 'b)) => unit = - "useImperativeHandle" - -@module("react") -external useImperativeHandle3: (Js.Nullable.t>, unit => 'value, ('a, 'b, 'c)) => unit = - "useImperativeHandle" - -@module("react") -external useImperativeHandle4: ( - Js.Nullable.t>, - unit => 'value, - ('a, 'b, 'c, 'd), -) => unit = "useImperativeHandle" - -@module("react") -external useImperativeHandle5: ( - Js.Nullable.t>, - unit => 'value, - ('a, 'b, 'c, 'd, 'e), -) => unit = "useImperativeHandle" - -@module("react") -external useImperativeHandle6: ( - Js.Nullable.t>, - unit => 'value, - ('a, 'b, 'c, 'd, 'e, 'f), -) => unit = "useImperativeHandle" - -@module("react") -external useImperativeHandle7: ( - Js.Nullable.t>, - unit => 'value, - ('a, 'b, 'c, 'd, 'e, 'f, 'g), -) => unit = "useImperativeHandle" - -@module("react") external useId: unit => string = "useId" - -/** `useDeferredValue` is a React Hook that lets you defer updating a part of the UI. */ -@module("react") -external useDeferredValue: ('value, ~initialValue: 'value=?) => 'value = "useDeferredValue" - -@module("react") -external useInsertionEffectOnEveryRender: (unit => option unit>) => unit = - "useInsertionEffect" -@module("react") -external useInsertionEffect: (unit => option unit>, 'deps) => unit = "useInsertionEffect" -@module("react") -external useInsertionEffect0: (unit => option unit>, @as(json`[]`) _) => unit = - "useInsertionEffect" -@module("react") -external useInsertionEffect1: (unit => option unit>, array<'a>) => unit = - "useInsertionEffect" -@module("react") -external useInsertionEffect2: (unit => option unit>, ('a, 'b)) => unit = - "useInsertionEffect" -@module("react") -external useInsertionEffect3: (unit => option unit>, ('a, 'b, 'c)) => unit = - "useInsertionEffect" -@module("react") -external useInsertionEffect4: (unit => option unit>, ('a, 'b, 'c, 'd)) => unit = - "useInsertionEffect" -@module("react") -external useInsertionEffect5: (unit => option unit>, ('a, 'b, 'c, 'd, 'e)) => unit = - "useInsertionEffect" -@module("react") -external useInsertionEffect6: (unit => option unit>, ('a, 'b, 'c, 'd, 'e, 'f)) => unit = - "useInsertionEffect" -@module("react") -external useInsertionEffect7: (unit => option unit>, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => unit = - "useInsertionEffect" - -@module("react") -external useSyncExternalStore: ( - ~subscribe: (unit => unit) => unit => unit, - ~getSnapshot: unit => 'state, -) => 'state = "useSyncExternalStore" - -@module("react") -external useSyncExternalStoreWithServerSnapshot: ( - ~subscribe: (unit => unit) => unit => unit, - ~getSnapshot: unit => 'state, - ~getServerSnapshot: unit => 'state, -) => 'state = "useSyncExternalStore" - -module Uncurried = { - @module("react") - external useState: (unit => 'state) => ('state, ('state => 'state) => unit) = "useState" - - @module("react") - external useReducer: (('state, 'action) => 'state, 'state) => ('state, 'action => unit) = - "useReducer" - - @module("react") - external useReducerWithMapState: ( - ('state, 'action) => 'state, - 'initialState, - 'initialState => 'state, - ) => ('state, 'action => unit) = "useReducer" - - @module("react") - external useCallback: ('f, 'deps) => 'f = "useCallback" - - @module("react") - external useCallback0: ('f, @as(json`[]`) _) => 'f = "useCallback" - - @module("react") - external useCallback1: ('f, array<'a>) => 'f = "useCallback" - - @module("react") - external useCallback2: ('f, ('a, 'b)) => 'f = "useCallback" - - @module("react") - external useCallback3: ('f, ('a, 'b, 'c)) => 'f = "useCallback" - - @module("react") - external useCallback4: ('f, ('a, 'b, 'c, 'd)) => 'f = "useCallback" - - @module("react") - external useCallback5: ('f, ('a, 'b, 'c, 'd, 'e)) => 'f = "useCallback" - - @module("react") - external useCallback6: ('callback, ('a, 'b, 'c, 'd, 'e, 'f)) => 'callback = "useCallback" - - @module("react") - external useCallback7: ('callback, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => 'callback = "useCallback" -} - -@set -external setDisplayName: (component<'props>, string) => unit = "displayName" - -@get @return(nullable) -external displayName: component<'props> => option = "displayName" - -// Actions - -type transitionFunction = unit => promise - -type transitionStartFunction = transitionFunction => unit - -/** `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" - -type action<'state, 'payload> = ('state, 'payload) => promise<'state> - -type formAction<'formData> = 'formData => promise - -/** `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) => promise = "act" diff --git a/packages/react/src/ReactDOM.bs.js b/packages/react/src/ReactDOM.bs.js deleted file mode 100644 index fa516402fa..0000000000 --- a/packages/react/src/ReactDOM.bs.js +++ /dev/null @@ -1,58 +0,0 @@ -// Generated by ReScript, PLEASE EDIT WITH CARE -'use strict'; - -var Caml_option = require("rescript/lib/js/caml_option.js"); - -var Root = {}; - -var Client = { - Root: Root -}; - -function getString(formData, name) { - var value = formData.get(name); - if (!(value == null) && typeof value === "string") { - return Caml_option.some(value); - } - -} - -function getFile(formData, name) { - var value = formData.get(name); - if (!(value == null) && typeof value !== "string") { - return Caml_option.some(value); - } - -} - -function getAll(t, string) { - return t.getAll(string).map(function (value) { - if (typeof value === "string") { - return { - TAG: "String", - _0: value - }; - } else { - return { - TAG: "File", - _0: value - }; - } - }); -} - -var $$FormData = { - getString: getString, - getFile: getFile, - getAll: getAll -}; - -var Ref = {}; - -var Style; - -exports.Client = Client; -exports.$$FormData = $$FormData; -exports.Ref = Ref; -exports.Style = Style; -/* No side effect */ diff --git a/packages/react/src/ReactDOM.res b/packages/react/src/ReactDOM.res deleted file mode 100644 index fbd564bf4d..0000000000 --- a/packages/react/src/ReactDOM.res +++ /dev/null @@ -1,249 +0,0 @@ -/* First time reading a ReScript file? */ -/* `external` is the foreign function call in OCaml. */ -/* here we're saying `I guarantee that on the JS side, we have a `render` function in the module "react-dom" - that takes in a reactElement, a dom element, and returns unit (nothing) */ -/* It's like `let`, except you're pointing the implementation to the JS side. The compiler will inline these - calls and add the appropriate `require("react-dom")` in the file calling this `render` */ - -// Helper so that ReactDOM itself doesn't bring any runtime -@val @return(nullable) -external querySelector: string => option = "document.querySelector" - -module Client = { - module Root = { - type t - - @send external render: (t, React.element) => unit = "render" - - @send external unmount: (t, unit) => unit = "unmount" - } - - @module("react-dom/client") - external createRoot: Dom.element => Root.t = "createRoot" - - @module("react-dom/client") - external hydrateRoot: (Dom.element, React.element) => Root.t = "hydrateRoot" -} - -// Very rudimentary form data bindings -module FormData = { - type t - type file - - type formValue = - | String(string) - | File(file) - - @new external make: unit => t = "FormData" - - @send external append: (t, string, ~filename: string=?) => unit = "append" - @send external delete: (t, string) => unit = "delete" - @return(nullable) @send external getUnsafe: (t, string) => option<'a> = "get" - @send external getAllUnsafe: (t, string) => array<'a> = "getAll" - - let getString = (formData, name) => { - switch formData->getUnsafe(name) { - | Some(value) => Js.typeof(value) === "string" ? Some(value) : None - | _ => None - } - } - - external _asFile: 'a => file = "%identity" - - let getFile = (formData, name) => { - switch formData->getUnsafe(name) { - | Some(value) => Js.typeof(value) === "string" ? None : Some(value->_asFile) - | _ => None - } - } - - let getAll = (t, string) => { - t - ->getAllUnsafe(string) - ->Js.Array2.map(value => { - Js.typeof(value) === "string" ? String(value) : File(value->_asFile) - }) - } - - @send external set: (string, string) => unit = "set" - @send external has: string => bool = "has" - // @send external keys: t => Iterator.t = "keys"; - // @send external values: t => Iterator.t = "values"; -} - -@module("react-dom") -external createPortal: (React.element, Dom.element) => React.element = "createPortal" - -external domElementToObj: Dom.element => {..} = "%identity" - -type style = ReactDOMStyle.t - -type domRef = JsxDOM.domRef - -module Ref = { - type t = domRef - type currentDomRef = React.ref> - type callbackDomRef = Js.nullable => option unit> - - external domRef: currentDomRef => domRef = "%identity" - external callbackDomRef: callbackDomRef => domRef = "%identity" -} - -// Hooks - -type formStatus<'state> = { - /** If true, this means the parent is pending submission. Otherwise, false. */ - pending: bool, - /** An object implementing the FormData interface that contains the data the parent is submitting. If there is no active submission or no parent , it will be null. */ - data: FormData.t, - /** This represents whether the parent is submitting with either a GET or POST HTTP method. By default, a will use the GET method and can be specified by the method property. */ - method: [#get | #post], - /** A reference to the function passed to the action prop on the parent . If there is no parent , the property is null. If there is a URI value provided to the action prop, or no action prop specified, status.action will be null. */ - action: React.action<'state, FormData.t>, -} - -external formAction: React.formAction => string = "%identity" - -/** `useFormStatus` is a Hook that gives you status information of the last form submission. */ -@module("react-dom") -external useFormStatus: unit => formStatus<'state> = "useFormStatus" - -// Resource Preloading APIs - -/** The CORS policy to use. */ -type crossOrigin = [ - | #anonymous - | #"use-credentials" -] - -/** The Referrer header to send when fetching. */ -type referrerPolicy = [ - | #"referrer-when-downgrade" - | #"no-referrer" - | #origin - | #"origin-when-cross-origin" - | #"unsafe-url" -] - -/** Suggests a relative priority for fetching the resource. */ -type fetchPriority = [#auto | #high | #low] - -/** `prefetchDNS` lets you eagerly look up the IP of a server that you expect to load resources from. */ -@module("react-dom") -external prefetchDNS: string => unit = "prefetchDNS" - -/** `preconnect` lets you eagerly connect to a server that you expect to load resources from. */ -@module("react-dom") -external preconnect: string => unit = "preconnect" - -type preloadOptions = { - /** The type of resource. */ - @as("as") - as_: [ - | #audio - | #document - | #embed - | #fetch - | #font - | #image - | #object - | #script - | #style - | #track - | #video - | #worker - ], - /** The CORS policy to use. It is required when as is set to "fetch". */ - crossOrigin?: crossOrigin, - /** The Referrer header to send when fetching. */ - referrerPolicy?: referrerPolicy, - /** A cryptographic hash of the resource, to verify its authenticity. */ - integrity?: string, - /** The MIME type of the resource. */ - @as("type") - type_?: string, - /** A cryptographic nonce to allow the resource when using a strict Content Security Policy. */ - nonce?: string, - /** Suggests a relative priority for fetching the resource. */ - fetchPriority?: fetchPriority, - /** For use only with as: "image". Specifies the source set of the image. */ - imageSrcSet?: string, - /** For use only with as: "image". Specifies the sizes of the image. */ - imageSizes?: string, -} - -/** `preload` lets you eagerly fetch a resource such as a stylesheet, font, or external script that you expect to use. */ -@module("react-dom") -external preload: (string, preloadOptions) => unit = "preload" - -type preloadModuleOptions = { - /** The type of resource. */ - @as("as") - as_: [#script], - /** The CORS policy to use. It is required when as is set to "fetch". */ - crossOrigin?: crossOrigin, - /** A cryptographic hash of the resource, to verify its authenticity. */ - integrity?: string, - /** A cryptographic nonce to allow the resource when using a strict Content Security Policy. */ - nonce?: string, -} - -/** `preloadModule` lets you eagerly fetch an ESM module that you expect to use. */ -@module("react-dom") -external preloadModule: (string, preloadModuleOptions) => unit = "preloadModule" - -type preinitOptions = { - /** The type of resource. */ - @as("as") - as_: [#script | #style], - /** Required with stylesheets. Says where to insert the stylesheet relative to others. Stylesheets with higher precedence can override those with lower precedence. */ - precedence?: [#reset | #low | #medium | #high], - /** The CORS policy to use. It is required when as is set to "fetch". */ - crossOrigin?: crossOrigin, - /** The Referrer header to send when fetching. */ - referrerPolicy?: referrerPolicy, - /** A cryptographic hash of the resource, to verify its authenticity. */ - integrity?: string, - nonce?: string, - /** Suggests a relative priority for fetching the resource. */ - fetchPriority?: fetchPriority, -} - -/** `preinit` lets you eagerly fetch and evaluate a stylesheet or external script. */ -@module("react-dom") -external preinit: (string, preinitOptions) => unit = "preinit" - -/** To preinit an ESM module, call the `preinitModule` function from react-dom. */ -@module("react-dom") -external preinitModule: (string, preloadModuleOptions) => unit = "preinitModule" - -// Runtime - -type domProps = JsxDOM.domProps - -@variadic @module("react") -external createElement: (string, ~props: domProps=?, array) => React.element = - "createElement" - -@variadic @module("react") -external createDOMElementVariadic: ( - string, - ~props: domProps=?, - array, -) => React.element = "createElement" - -external someElement: React.element => option = "%identity" - -@module("react/jsx-runtime") -external jsx: (string, JsxDOM.domProps) => Jsx.element = "jsx" - -@module("react/jsx-runtime") -external jsxKeyed: (string, JsxDOM.domProps, ~key: string=?, @ignore unit) => Jsx.element = "jsx" - -@module("react/jsx-runtime") -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 = ReactDOMStyle diff --git a/packages/react/src/ReactDOMServer.bs.js b/packages/react/src/ReactDOMServer.bs.js deleted file mode 100644 index d856702bfe..0000000000 --- a/packages/react/src/ReactDOMServer.bs.js +++ /dev/null @@ -1,2 +0,0 @@ -// 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/packages/react/src/ReactDOMStatic.bs.js b/packages/react/src/ReactDOMStatic.bs.js deleted file mode 100644 index d856702bfe..0000000000 --- a/packages/react/src/ReactDOMStatic.bs.js +++ /dev/null @@ -1,2 +0,0 @@ -// 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/packages/react/src/ReactDOMStyle.bs.js b/packages/react/src/ReactDOMStyle.bs.js deleted file mode 100644 index 18702c8d1e..0000000000 --- a/packages/react/src/ReactDOMStyle.bs.js +++ /dev/null @@ -1,12 +0,0 @@ -// Generated by ReScript, PLEASE EDIT WITH CARE -'use strict'; - - -function unsafeAddProp(style, key, value) { - var dict = {}; - dict[key] = value; - return Object.assign({}, style, dict); -} - -exports.unsafeAddProp = unsafeAddProp; -/* No side effect */ diff --git a/packages/react/src/ReactDOMStyle.res b/packages/react/src/ReactDOMStyle.res deleted file mode 100644 index ae68d03554..0000000000 --- a/packages/react/src/ReactDOMStyle.res +++ /dev/null @@ -1,16 +0,0 @@ -type t = JsxDOMStyle.t - -/* CSS2Properties: https://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSS2Properties */ -@val -external combine: (@as(json`{}`) _, t, t) => t = "Object.assign" - -external _dictToStyle: Js.Dict.t => t = "%identity" - -let unsafeAddProp = (style, key, value) => { - let dict = Js.Dict.empty() - Js.Dict.set(dict, key, value) - combine(style, _dictToStyle(dict)) -} - -@val -external unsafeAddStyle: (@as(json`{}`) _, t, {..}) => t = "Object.assign" diff --git a/packages/react/src/ReactEvent.bs.js b/packages/react/src/ReactEvent.bs.js deleted file mode 100644 index 179cde2e62..0000000000 --- a/packages/react/src/ReactEvent.bs.js +++ /dev/null @@ -1,53 +0,0 @@ -// Generated by ReScript, PLEASE EDIT WITH CARE -'use strict'; - - -var Synthetic = {}; - -var Clipboard = {}; - -var Composition = {}; - -var Keyboard = {}; - -var Focus = {}; - -var Form = {}; - -var Mouse = {}; - -var Pointer = {}; - -var $$Selection = {}; - -var $$Touch = {}; - -var UI = {}; - -var Wheel = {}; - -var Media = {}; - -var $$Image = {}; - -var $$Animation = {}; - -var Transition = {}; - -exports.Synthetic = Synthetic; -exports.Clipboard = Clipboard; -exports.Composition = Composition; -exports.Keyboard = Keyboard; -exports.Focus = Focus; -exports.Form = Form; -exports.Mouse = Mouse; -exports.Pointer = Pointer; -exports.$$Selection = $$Selection; -exports.$$Touch = $$Touch; -exports.UI = UI; -exports.Wheel = Wheel; -exports.Media = Media; -exports.$$Image = $$Image; -exports.$$Animation = $$Animation; -exports.Transition = Transition; -/* No side effect */ diff --git a/packages/react/src/ReactEvent.res b/packages/react/src/ReactEvent.res deleted file mode 100644 index 54ac5910c2..0000000000 --- a/packages/react/src/ReactEvent.res +++ /dev/null @@ -1,243 +0,0 @@ -type synthetic<'a> = JsxEvent.synthetic<'a> - -module MakeEventWithType = ( - Type: { - type t - }, -) => { - @get external bubbles: Type.t => bool = "bubbles" - @get external cancelable: Type.t => bool = "cancelable" - @get - external currentTarget: Type.t => {..} = "currentTarget" /* Should return Dom.eventTarget */ - @get external defaultPrevented: Type.t => bool = "defaultPrevented" - @get external eventPhase: Type.t => int = "eventPhase" - @get external isTrusted: Type.t => bool = "isTrusted" - @get external nativeEvent: Type.t => {..} = "nativeEvent" /* Should return Dom.event */ - @send external preventDefault: Type.t => unit = "preventDefault" - @send - external isDefaultPrevented: Type.t => bool = "isDefaultPrevented" - @send external stopPropagation: Type.t => unit = "stopPropagation" - @send - external isPropagationStopped: Type.t => bool = "isPropagationStopped" - @get external target: Type.t => {..} = "target" /* Should return Dom.eventTarget */ - @get external timeStamp: Type.t => float = "timeStamp" - @get external type_: Type.t => string = "type" - @send external persist: Type.t => unit = "persist" -} - -module Synthetic = { - type tag = JsxEvent.Synthetic.tag - type t = synthetic - @get external bubbles: synthetic<'a> => bool = "bubbles" - @get external cancelable: synthetic<'a> => bool = "cancelable" - @get - external currentTarget: synthetic<'a> => {..} = - "currentTarget" /* Should return Dom.eventTarget */ - @get - external defaultPrevented: synthetic<'a> => bool = "defaultPrevented" - @get external eventPhase: synthetic<'a> => int = "eventPhase" - @get external isTrusted: synthetic<'a> => bool = "isTrusted" - @get - external nativeEvent: synthetic<'a> => {..} = "nativeEvent" /* Should return Dom.event */ - @send - external preventDefault: synthetic<'a> => unit = "preventDefault" - @send - external isDefaultPrevented: synthetic<'a> => bool = "isDefaultPrevented" - @send - external stopPropagation: synthetic<'a> => unit = "stopPropagation" - @send - external isPropagationStopped: synthetic<'a> => bool = "isPropagationStopped" - @get external target: synthetic<'a> => {..} = "target" /* Should return Dom.eventTarget */ - @get external timeStamp: synthetic<'a> => float = "timeStamp" - @get external type_: synthetic<'a> => string = "type" - @send external persist: synthetic<'a> => unit = "persist" -} - -/* Cast any event type to the general synthetic type. This is safe, since synthetic is more general */ -external toSyntheticEvent: synthetic<'a> => Synthetic.t = "%identity" - -module Clipboard = { - type tag = JsxEvent.Clipboard.tag - type t = synthetic - include MakeEventWithType({type t = t}) - @get external clipboardData: t => {..} = "clipboardData" /* Should return Dom.dataTransfer */ -} - -module Composition = { - type tag = JsxEvent.Composition.tag - type t = synthetic - include MakeEventWithType({type t = t}) - @get external data: t => string = "data" -} - -module Keyboard = { - type tag = JsxEvent.Keyboard.tag - type t = synthetic - include MakeEventWithType({type t = t}) - @get external altKey: t => bool = "altKey" - @get external charCode: t => int = "charCode" - @get external code: t => string = "code" - @get external ctrlKey: t => bool = "ctrlKey" - @send - external getModifierState: (t, string) => bool = "getModifierState" - @get external key: t => string = "key" - @get external keyCode: t => int = "keyCode" - @get external locale: t => string = "locale" - @get external location: t => int = "location" - @get external metaKey: t => bool = "metaKey" - @get external repeat: t => bool = "repeat" - @get external shiftKey: t => bool = "shiftKey" - @get external which: t => int = "which" -} - -module Focus = { - type tag = JsxEvent.Focus.tag - type t = synthetic - include MakeEventWithType({type t = t}) - @get @return(nullable) - external relatedTarget: t => option<{..}> = "relatedTarget" /* Should return Dom.eventTarget */ -} - -module Form = { - type tag = JsxEvent.Form.tag - type t = synthetic - include MakeEventWithType({type t = t}) -} - -module Mouse = { - type tag = JsxEvent.Mouse.tag - type t = synthetic - include MakeEventWithType({type t = t}) - @get external altKey: t => bool = "altKey" - @get external button: t => int = "button" - @get external buttons: t => int = "buttons" - @get external clientX: t => int = "clientX" - @get external clientY: t => int = "clientY" - @get external ctrlKey: t => bool = "ctrlKey" - @send - external getModifierState: (t, string) => bool = "getModifierState" - @get external metaKey: t => bool = "metaKey" - @get external movementX: t => int = "movementX" - @get external movementY: t => int = "movementY" - @get external pageX: t => int = "pageX" - @get external pageY: t => int = "pageY" - @get @return(nullable) - external relatedTarget: t => option<{..}> = "relatedTarget" /* Should return Dom.eventTarget */ - @get external screenX: t => int = "screenX" - @get external screenY: t => int = "screenY" - @get external shiftKey: t => bool = "shiftKey" -} - -module Pointer = { - type tag = JsxEvent.Pointer.tag - type t = synthetic - include MakeEventWithType({type t = t}) - - // UIEvent - @get external detail: t => int = "detail" - @get external view: t => Dom.window = "view" /* Should return DOMAbstractView/WindowProxy */ - - // MouseEvent - @get external screenX: t => int = "screenX" - @get external screenY: t => int = "screenY" - @get external clientX: t => int = "clientX" - @get external clientY: t => int = "clientY" - @get external pageX: t => int = "pageX" - @get external pageY: t => int = "pageY" - @get external movementX: t => int = "movementX" - @get external movementY: t => int = "movementY" - - @get external ctrlKey: t => bool = "ctrlKey" - @get external shiftKey: t => bool = "shiftKey" - @get external altKey: t => bool = "altKey" - @get external metaKey: t => bool = "metaKey" - @send - external getModifierState: (t, string) => bool = "getModifierState" - - @get external button: t => int = "button" - @get external buttons: t => int = "buttons" - - @get @return(nullable) - external relatedTarget: t => option<{..}> = "relatedTarget" /* Should return Dom.eventTarget */ - - // PointerEvent - @get external pointerId: t => Dom.eventPointerId = "pointerId" - @get external width: t => float = "width" - @get external height: t => float = "height" - @get external pressure: t => float = "pressure" - @get external tangentialPressure: t => float = "tangentialPressure" - @get external tiltX: t => int = "tiltX" - @get external tiltY: t => int = "tiltY" - @get external twist: t => int = "twist" - @get external pointerType: t => string = "pointerType" - @get external isPrimary: t => bool = "isPrimary" -} - -module Selection = { - type tag = JsxEvent.Selection.tag - type t = synthetic - include MakeEventWithType({type t = t}) -} - -module Touch = { - type tag = JsxEvent.Touch.tag - type t = synthetic - include MakeEventWithType({type t = t}) - @get external altKey: t => bool = "altKey" - @get external changedTouches: t => {..} = "changedTouches" /* Should return Dom.touchList */ - @get external ctrlKey: t => bool = "ctrlKey" - @send - external getModifierState: (t, string) => bool = "getModifierState" - @get external metaKey: t => bool = "metaKey" - @get external shiftKey: t => bool = "shiftKey" - @get external targetTouches: t => {..} = "targetTouches" /* Should return Dom.touchList */ - @get external touches: t => {..} = "touches" /* Should return Dom.touchList */ -} - -module UI = { - type tag = JsxEvent.UI.tag - type t = synthetic - include MakeEventWithType({type t = t}) - @get external detail: t => int = "detail" - @get external view: t => Dom.window = "view" /* Should return DOMAbstractView/WindowProxy */ -} - -module Wheel = { - type tag = JsxEvent.Wheel.tag - type t = synthetic - include MakeEventWithType({type t = t}) - @get external deltaMode: t => int = "deltaMode" - @get external deltaX: t => float = "deltaX" - @get external deltaY: t => float = "deltaY" - @get external deltaZ: t => float = "deltaZ" -} - -module Media = { - type tag = JsxEvent.Media.tag - type t = synthetic - include MakeEventWithType({type t = t}) -} - -module Image = { - type tag = JsxEvent.Image.tag - type t = synthetic - include MakeEventWithType({type t = t}) -} - -module Animation = { - type tag = JsxEvent.Animation.tag - type t = synthetic - include MakeEventWithType({type t = t}) - @get external animationName: t => string = "animationName" - @get external pseudoElement: t => string = "pseudoElement" - @get external elapsedTime: t => float = "elapsedTime" -} - -module Transition = { - type tag = JsxEvent.Transition.tag - type t = synthetic - include MakeEventWithType({type t = t}) - @get external propertyName: t => string = "propertyName" - @get external pseudoElement: t => string = "pseudoElement" - @get external elapsedTime: t => float = "elapsedTime" -} diff --git a/packages/react/src/ReactEvent.resi b/packages/react/src/ReactEvent.resi deleted file mode 100644 index 61b5d4b5db..0000000000 --- a/packages/react/src/ReactEvent.resi +++ /dev/null @@ -1,472 +0,0 @@ -/* 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. - - In each module, the type `t` commonly means "the type of that module" (OCaml convention). In our case, e.g. - `ReactEvent.Mouse.t` represents a ReactJS synthetic mouse event. You'd use it to type your props: - - ``` - type props = { - onClick: ReactEvent.Mouse.t => unit - }; - ``` - - All the methods and properties of a type of event are in the module, as seen below. - - Each module also has a `tag` type. You can ignore it; they're only needed by their `t` type. This way, we - get to allow a base `Synthetic` event module with generic methods. So e.g. even a mouse event (`Mouse.t`) - get to be passed to a generic handler: - - ``` - let handleClick = ({state, props}, event) => { - ReactEvent.Mouse.preventDefault(event); - ... - }; - let handleSubmit = ({state, props}, event) => { - // this handler can be triggered by either a Keyboard or a Mouse event; - // conveniently use the generic preventDefault - ReactEvent.Synthetic.preventDefault(event); - ... - }; - - let render = (_) => ; - ``` - - How to translate idioms from ReactJS: - - 1. myMouseEvent.preventDefault() -> ReactEvent.Mouse.preventDefault(myMouseEvent) - 2. myKeyboardEvent.which -> ReactEvent.Keyboard.which(myKeyboardEvent) - */ -type synthetic<'a> = JsxEvent.synthetic<'a> - -module Synthetic: { - type tag = JsxEvent.Synthetic.tag - type t = synthetic - @get external bubbles: synthetic<'a> => bool = "bubbles" - @get external cancelable: synthetic<'a> => bool = "cancelable" - @get - external currentTarget: synthetic<'a> => {..} = "currentTarget" - @get - external defaultPrevented: synthetic<'a> => bool = "defaultPrevented" - @get external eventPhase: synthetic<'a> => int = "eventPhase" - @get external isTrusted: synthetic<'a> => bool = "isTrusted" - @get - external nativeEvent: synthetic<'a> => {..} = "nativeEvent" - @send - external preventDefault: synthetic<'a> => unit = "preventDefault" - @send - external isDefaultPrevented: synthetic<'a> => bool = "isDefaultPrevented" - @send - external stopPropagation: synthetic<'a> => unit = "stopPropagation" - @send - external isPropagationStopped: synthetic<'a> => bool = "isPropagationStopped" - @get external target: synthetic<'a> => {..} = "target" - @get external timeStamp: synthetic<'a> => float = "timeStamp" - @get external type_: synthetic<'a> => string = "type" - @send external persist: synthetic<'a> => unit = "persist" -} - -/* Cast any event type to the general synthetic type. This is safe, since synthetic is more general */ -external toSyntheticEvent: synthetic<'a> => Synthetic.t = "%identity" - -module Clipboard: { - type tag = JsxEvent.Clipboard.tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" - @get external clipboardData: t => {..} = "clipboardData" /* Should return Dom.dataTransfer */ -} - -module Composition: { - type tag = JsxEvent.Composition.tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" - @get external data: t => string = "data" -} - -module Keyboard: { - type tag = JsxEvent.Keyboard.tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" - @get external altKey: t => bool = "altKey" - @get external charCode: t => int = "charCode" - @get external code: t => string = "code" - @get external ctrlKey: t => bool = "ctrlKey" - @send - external getModifierState: (t, string) => bool = "getModifierState" - @get external key: t => string = "key" - @get external keyCode: t => int = "keyCode" - @get external locale: t => string = "locale" - @get external location: t => int = "location" - @get external metaKey: t => bool = "metaKey" - @get external repeat: t => bool = "repeat" - @get external shiftKey: t => bool = "shiftKey" - @get external which: t => int = "which" -} - -module Focus: { - type tag = JsxEvent.Focus.tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" - @get @return(nullable) - external relatedTarget: t => option<{..}> = "relatedTarget" /* Should return Dom.eventTarget */ -} - -module Form: { - type tag = JsxEvent.Form.tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" -} - -module Mouse: { - type tag = JsxEvent.Mouse.tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" - @get external altKey: t => bool = "altKey" - @get external button: t => int = "button" - @get external buttons: t => int = "buttons" - @get external clientX: t => int = "clientX" - @get external clientY: t => int = "clientY" - @get external ctrlKey: t => bool = "ctrlKey" - @send - external getModifierState: (t, string) => bool = "getModifierState" - @get external metaKey: t => bool = "metaKey" - @get external movementX: t => int = "movementX" - @get external movementY: t => int = "movementY" - @get external pageX: t => int = "pageX" - @get external pageY: t => int = "pageY" - @get @return(nullable) - external relatedTarget: t => option<{..}> = "relatedTarget" /* Should return Dom.eventTarget */ - @get external screenX: t => int = "screenX" - @get external screenY: t => int = "screenY" - @get external shiftKey: t => bool = "shiftKey" -} - -module Pointer: { - type tag = JsxEvent.Pointer.tag - type t = synthetic - - // Event - @get external type_: t => string = "type" - @get external target: t => {..} = "target" - @get external currentTarget: t => {..} = "currentTarget" - - @get external eventPhase: t => int = "eventPhase" - - @send external stopPropagation: t => unit = "stopPropagation" // aka cancelBubble - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @send external preventDefault: t => unit = "preventDefault" - @get external defaultPrevented: t => bool = "defaultPrevented" - - @get external isTrusted: t => bool = "isTrusted" - @get external timeStamp: t => float = "timeStamp" - - // SyntheticEvent - @get external nativeEvent: t => {..} = "nativeEvent" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @send external persist: t => unit = "persist" - - // UIEvent - @get external detail: t => int = "detail" - @get external view: t => Dom.window = "view" /* Should return DOMAbstractView/WindowProxy */ - - // MouseEvent - @get external screenX: t => int = "screenX" - @get external screenY: t => int = "screenY" - @get external clientX: t => int = "clientX" - @get external clientY: t => int = "clientY" - @get external pageX: t => int = "pageX" - @get external pageY: t => int = "pageY" - @get external movementX: t => int = "movementX" - @get external movementY: t => int = "movementY" - - @get external ctrlKey: t => bool = "ctrlKey" - @get external shiftKey: t => bool = "shiftKey" - @get external altKey: t => bool = "altKey" - @get external metaKey: t => bool = "metaKey" - @send - external getModifierState: (t, string) => bool = "getModifierState" - - @get external button: t => int = "button" - @get external buttons: t => int = "buttons" - - @get @return(nullable) - external relatedTarget: t => option<{..}> = "relatedTarget" /* Should return Dom.eventTarget */ - - // PointerEvent - @get external pointerId: t => Dom.eventPointerId = "pointerId" - @get external width: t => float = "width" - @get external height: t => float = "height" - @get external pressure: t => float = "pressure" - @get external tangentialPressure: t => float = "tangentialPressure" - @get external tiltX: t => int = "tiltX" - @get external tiltY: t => int = "tiltY" - @get external twist: t => int = "twist" - @get external pointerType: t => string = "pointerType" - @get external isPrimary: t => bool = "isPrimary" -} - -module Selection: { - type tag = JsxEvent.Selection.tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" -} - -module Touch: { - type tag = JsxEvent.Touch.tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" - @get external altKey: t => bool = "altKey" - @get external changedTouches: t => {..} = "changedTouches" /* Should return Dom.touchList */ - @get external ctrlKey: t => bool = "ctrlKey" - @send - external getModifierState: (t, string) => bool = "getModifierState" - @get external metaKey: t => bool = "metaKey" - @get external shiftKey: t => bool = "shiftKey" - @get external targetTouches: t => {..} = "targetTouches" /* Should return Dom.touchList */ - @get external touches: t => {..} = "touches" /* Should return Dom.touchList */ -} - -module UI: { - type tag = JsxEvent.UI.tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" - @get external detail: t => int = "detail" - @get external view: t => Dom.window = "view" /* Should return DOMAbstractView/WindowProxy */ -} - -module Wheel: { - type tag = JsxEvent.Wheel.tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" - @get external deltaMode: t => int = "deltaMode" - @get external deltaX: t => float = "deltaX" - @get external deltaY: t => float = "deltaY" - @get external deltaZ: t => float = "deltaZ" -} - -module Media: { - type tag = JsxEvent.Media.tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" -} - -module Image: { - type tag = JsxEvent.Image.tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" -} - -module Animation: { - type tag = JsxEvent.Animation.tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" - @get external animationName: t => string = "animationName" - @get external pseudoElement: t => string = "pseudoElement" - @get external elapsedTime: t => float = "elapsedTime" -} - -module Transition: { - type tag = JsxEvent.Transition.tag - type t = synthetic - @get external bubbles: t => bool = "bubbles" - @get external cancelable: t => bool = "cancelable" - @get external currentTarget: t => {..} = "currentTarget" - @get external defaultPrevented: t => bool = "defaultPrevented" - @get external eventPhase: t => int = "eventPhase" - @get external isTrusted: t => bool = "isTrusted" - @get external nativeEvent: t => {..} = "nativeEvent" - @send external preventDefault: t => unit = "preventDefault" - @send external isDefaultPrevented: t => bool = "isDefaultPrevented" - @send external stopPropagation: t => unit = "stopPropagation" - @send external isPropagationStopped: t => bool = "isPropagationStopped" - @get external target: t => {..} = "target" - @get external timeStamp: t => float = "timeStamp" - @get external type_: t => string = "type" - @send external persist: t => unit = "persist" - @get external propertyName: t => string = "propertyName" - @get external pseudoElement: t => string = "pseudoElement" - @get external elapsedTime: t => float = "elapsedTime" -} diff --git a/packages/react/src/ReactTestUtils.bs.js b/packages/react/src/ReactTestUtils.bs.js deleted file mode 100644 index 7ddadac5a3..0000000000 --- a/packages/react/src/ReactTestUtils.bs.js +++ /dev/null @@ -1,105 +0,0 @@ -// Generated by ReScript, PLEASE EDIT WITH CARE -'use strict'; - -var Caml_option = require("rescript/lib/js/caml_option.js"); -var TestUtils = require("react-dom/test-utils"); - -function act(func) { - var reactFunc = function () { - func(); - }; - TestUtils.act(reactFunc); -} - -function actAsync(func) { - return TestUtils.act(function () { - return func(); - }); -} - -function changeWithValue(element, value) { - var $$event = { - target: { - value: value - } - }; - TestUtils.Simulate.change(element, $$event); -} - -function changeWithChecked(element, value) { - var $$event = { - target: { - checked: value - } - }; - TestUtils.Simulate.change(element, $$event); -} - -var Simulate = { - changeWithValue: changeWithValue, - changeWithChecked: changeWithChecked -}; - -function findBySelector(element, selector) { - return element.querySelector(selector); -} - -function findByAllSelector(element, selector) { - return Array.from(element.querySelectorAll(selector)); -} - -function findBySelectorAndTextContent(element, selector, content) { - return Caml_option.undefined_to_opt(Array.from(element.querySelectorAll(selector)).find(function (node) { - return node.textContent === content; - })); -} - -function findBySelectorAndPartialTextContent(element, selector, content) { - return Caml_option.undefined_to_opt(Array.from(element.querySelectorAll(selector)).find(function (node) { - return node.textContent.includes(content); - })); -} - -var DOM = { - findBySelector: findBySelector, - findByAllSelector: findByAllSelector, - findBySelectorAndTextContent: findBySelectorAndTextContent, - findBySelectorAndPartialTextContent: findBySelectorAndPartialTextContent -}; - -function prepareContainer(container, param) { - var containerElement = document.createElement("div"); - var body = document.body; - if (body !== undefined) { - Caml_option.valFromOption(body).appendChild(containerElement); - } - container.contents = Caml_option.some(containerElement); -} - -function cleanupContainer(container, param) { - var contents = container.contents; - if (contents !== undefined) { - Caml_option.valFromOption(contents).remove(); - } - container.contents = undefined; -} - -function getContainer(container) { - var contents = container.contents; - if (contents !== undefined) { - return Caml_option.valFromOption(contents); - } - throw { - RE_EXN_ID: "Not_found", - Error: new Error() - }; -} - -exports.act = act; -exports.actAsync = actAsync; -exports.Simulate = Simulate; -exports.DOM = DOM; -exports.prepareContainer = prepareContainer; -exports.cleanupContainer = cleanupContainer; -exports.getContainer = getContainer; -/* react-dom/test-utils Not a pure module */ diff --git a/packages/react/src/RescriptReactErrorBoundary.bs.js b/packages/react/src/RescriptReactErrorBoundary.bs.js deleted file mode 100644 index fe5f73e5ed..0000000000 --- a/packages/react/src/RescriptReactErrorBoundary.bs.js +++ /dev/null @@ -1,33 +0,0 @@ -// Generated by ReScript, PLEASE EDIT WITH CARE -'use strict'; - -var React = require("react"); - -var noOp = (function (_x) {}); - -var reactComponentClass = React.Component; - -noOp(reactComponentClass); - -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); -; - -var make = ErrorBoundary; - -exports.make = make; -/* reactComponentClass Not a pure module */ diff --git a/packages/react/src/RescriptReactRouter.bs.js b/packages/react/src/RescriptReactRouter.bs.js deleted file mode 100644 index eb542b64f1..0000000000 --- a/packages/react/src/RescriptReactRouter.bs.js +++ /dev/null @@ -1,219 +0,0 @@ -// Generated by ReScript, PLEASE EDIT WITH CARE -'use strict'; - -var React = require("react"); -var Caml_option = require("rescript/lib/js/caml_option.js"); - -function safeMakeEvent(eventName) { - if (typeof Event === "function") { - return new Event(eventName); - } - var $$event = document.createEvent("Event"); - $$event.initEvent(eventName, true, true); - return $$event; -} - -function pathParse(str) { - switch (str) { - case "" : - case "/" : - return /* [] */0; - default: - var raw = str.slice(1); - var match = raw[raw.length - 1 | 0]; - var raw$1 = match === "/" ? raw.slice(0, -1) : raw; - var match$1 = raw$1.split("?", 2); - var raw$2 = match$1.length !== 2 ? raw$1 : match$1[0]; - var a = raw$2.split("/").filter(function (item) { - return item.length !== 0; - }); - var _i = a.length - 1 | 0; - var _res = /* [] */0; - while(true) { - var res = _res; - var i = _i; - if (i < 0) { - return res; - } - _res = { - hd: a[i], - tl: res - }; - _i = i - 1 | 0; - continue ; - }; - } -} - -function path(serverUrlString, param) { - var match = globalThis.window; - if (serverUrlString !== undefined) { - return pathParse(serverUrlString); - } else if (match !== undefined) { - return pathParse(Caml_option.valFromOption(match).location.pathname); - } else { - return /* [] */0; - } -} - -function hash() { - var $$window = globalThis.window; - if ($$window === undefined) { - return ""; - } - var raw = Caml_option.valFromOption($$window).location.hash; - switch (raw) { - case "" : - case "#" : - return ""; - default: - return raw.slice(1); - } -} - -function searchParse(str) { - switch (str) { - case "" : - case "?" : - return ""; - default: - var match = str.split("?", 2); - if (match.length !== 2) { - return ""; - } else { - return match[1]; - } - } -} - -function search(serverUrlString, param) { - var match = globalThis.window; - if (serverUrlString !== undefined) { - return searchParse(serverUrlString); - } else if (match !== undefined) { - return searchParse(Caml_option.valFromOption(match).location.search); - } else { - return ""; - } -} - -function push(path) { - var match = globalThis.history; - var match$1 = globalThis.window; - if (match !== undefined && match$1 !== undefined) { - Caml_option.valFromOption(match).pushState(null, "", path); - Caml_option.valFromOption(match$1).dispatchEvent(safeMakeEvent("popstate")); - return ; - } - -} - -function replace(path) { - var match = globalThis.history; - var match$1 = globalThis.window; - if (match !== undefined && match$1 !== undefined) { - Caml_option.valFromOption(match).replaceState(null, "", path); - Caml_option.valFromOption(match$1).dispatchEvent(safeMakeEvent("popstate")); - return ; - } - -} - -function urlNotEqual(a, b) { - if (a.hash !== b.hash || a.search !== b.search) { - return true; - } else { - var _aList = a.path; - var _bList = b.path; - while(true) { - var bList = _bList; - var aList = _aList; - if (!aList) { - if (bList) { - return true; - } else { - return false; - } - } - if (!bList) { - return true; - } - if (aList.hd !== bList.hd) { - return true; - } - _bList = bList.tl; - _aList = aList.tl; - continue ; - }; - } -} - -function url(serverUrlString, param) { - return { - path: path(serverUrlString, undefined), - hash: hash(), - search: search(serverUrlString, undefined) - }; -} - -function watchUrl(callback) { - var $$window = globalThis.window; - if ($$window === undefined) { - return function () { - - }; - } - var watcherID = function () { - callback(url(undefined, undefined)); - }; - Caml_option.valFromOption($$window).addEventListener("popstate", watcherID); - return watcherID; -} - -function unwatchUrl(watcherID) { - var $$window = globalThis.window; - if ($$window !== undefined) { - Caml_option.valFromOption($$window).removeEventListener("popstate", watcherID); - return ; - } - -} - -function useUrl(serverUrl, param) { - var match = React.useState(function () { - if (serverUrl !== undefined) { - return serverUrl; - } else { - return url(undefined, undefined); - } - }); - var setUrl = match[1]; - var url$1 = match[0]; - React.useEffect((function () { - var watcherId = watchUrl(function (url) { - setUrl(function (param) { - return url; - }); - }); - var newUrl = url(undefined, undefined); - if (urlNotEqual(newUrl, url$1)) { - setUrl(function (param) { - return newUrl; - }); - } - return (function () { - unwatchUrl(watcherId); - }); - }), []); - return url$1; -} - -var dangerouslyGetInitialUrl = url; - -exports.push = push; -exports.replace = replace; -exports.watchUrl = watchUrl; -exports.unwatchUrl = unwatchUrl; -exports.dangerouslyGetInitialUrl = dangerouslyGetInitialUrl; -exports.useUrl = useUrl; -/* react Not a pure module */ diff --git a/packages/react/.gitignore b/tests/dependencies/rescript-react/.gitignore similarity index 100% rename from packages/react/.gitignore rename to tests/dependencies/rescript-react/.gitignore diff --git a/packages/react/LICENSE b/tests/dependencies/rescript-react/LICENSE similarity index 100% rename from packages/react/LICENSE rename to tests/dependencies/rescript-react/LICENSE diff --git a/packages/react/package-lock.json b/tests/dependencies/rescript-react/package-lock.json similarity index 100% rename from packages/react/package-lock.json rename to tests/dependencies/rescript-react/package-lock.json diff --git a/tests/dependencies/rescript-react/package.json b/tests/dependencies/rescript-react/package.json index cd0136bdd3..94de119333 100644 --- a/tests/dependencies/rescript-react/package.json +++ b/tests/dependencies/rescript-react/package.json @@ -1,4 +1,8 @@ { - "name": "@tests/rescript-react", - "private": true + "name": "@rescript/react", + "version": "0.14.0-rc.1", + "private": true, + "dependencies": { + "rescript": "workspace:^" + } } diff --git a/tests/dependencies/rescript-react/src/React.res b/tests/dependencies/rescript-react/src/React.res index 0beaa59080..f1f6831518 100644 --- a/tests/dependencies/rescript-react/src/React.res +++ b/tests/dependencies/rescript-react/src/React.res @@ -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 = "%identity" external array: array => element = "%identity" @@ -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") @@ -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 = @@ -405,3 +408,36 @@ external setDisplayName: (component<'props>, string) => unit = "displayName" @get @return(nullable) external displayName: component<'props> => option = "displayName" + +// Actions + +type transitionFunction = unit => promise + +type transitionStartFunction = transitionFunction => unit + +/** `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" + +type action<'state, 'payload> = ('state, 'payload) => promise<'state> + +type formAction<'formData> = 'formData => promise + +/** `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) => promise = "act" diff --git a/tests/dependencies/rescript-react/src/ReactDOM.res b/tests/dependencies/rescript-react/src/ReactDOM.res index 04c39c2647..fbd564bf4d 100644 --- a/tests/dependencies/rescript-react/src/ReactDOM.res +++ b/tests/dependencies/rescript-react/src/ReactDOM.res @@ -25,6 +25,52 @@ module Client = { external hydrateRoot: (Dom.element, React.element) => Root.t = "hydrateRoot" } +// Very rudimentary form data bindings +module FormData = { + type t + type file + + type formValue = + | String(string) + | File(file) + + @new external make: unit => t = "FormData" + + @send external append: (t, string, ~filename: string=?) => unit = "append" + @send external delete: (t, string) => unit = "delete" + @return(nullable) @send external getUnsafe: (t, string) => option<'a> = "get" + @send external getAllUnsafe: (t, string) => array<'a> = "getAll" + + let getString = (formData, name) => { + switch formData->getUnsafe(name) { + | Some(value) => Js.typeof(value) === "string" ? Some(value) : None + | _ => None + } + } + + external _asFile: 'a => file = "%identity" + + let getFile = (formData, name) => { + switch formData->getUnsafe(name) { + | Some(value) => Js.typeof(value) === "string" ? None : Some(value->_asFile) + | _ => None + } + } + + let getAll = (t, string) => { + t + ->getAllUnsafe(string) + ->Js.Array2.map(value => { + Js.typeof(value) === "string" ? String(value) : File(value->_asFile) + }) + } + + @send external set: (string, string) => unit = "set" + @send external has: string => bool = "has" + // @send external keys: t => Iterator.t = "keys"; + // @send external values: t => Iterator.t = "values"; +} + @module("react-dom") external createPortal: (React.element, Dom.element) => React.element = "createPortal" @@ -37,12 +83,142 @@ type domRef = JsxDOM.domRef module Ref = { type t = domRef type currentDomRef = React.ref> - type callbackDomRef = Js.nullable => unit + type callbackDomRef = Js.nullable => option unit> external domRef: currentDomRef => domRef = "%identity" external callbackDomRef: callbackDomRef => domRef = "%identity" } +// Hooks + +type formStatus<'state> = { + /** If true, this means the parent is pending submission. Otherwise, false. */ + pending: bool, + /** An object implementing the FormData interface that contains the data the parent is submitting. If there is no active submission or no parent , it will be null. */ + data: FormData.t, + /** This represents whether the parent is submitting with either a GET or POST HTTP method. By default, a will use the GET method and can be specified by the method property. */ + method: [#get | #post], + /** A reference to the function passed to the action prop on the parent . If there is no parent , the property is null. If there is a URI value provided to the action prop, or no action prop specified, status.action will be null. */ + action: React.action<'state, FormData.t>, +} + +external formAction: React.formAction => string = "%identity" + +/** `useFormStatus` is a Hook that gives you status information of the last form submission. */ +@module("react-dom") +external useFormStatus: unit => formStatus<'state> = "useFormStatus" + +// Resource Preloading APIs + +/** The CORS policy to use. */ +type crossOrigin = [ + | #anonymous + | #"use-credentials" +] + +/** The Referrer header to send when fetching. */ +type referrerPolicy = [ + | #"referrer-when-downgrade" + | #"no-referrer" + | #origin + | #"origin-when-cross-origin" + | #"unsafe-url" +] + +/** Suggests a relative priority for fetching the resource. */ +type fetchPriority = [#auto | #high | #low] + +/** `prefetchDNS` lets you eagerly look up the IP of a server that you expect to load resources from. */ +@module("react-dom") +external prefetchDNS: string => unit = "prefetchDNS" + +/** `preconnect` lets you eagerly connect to a server that you expect to load resources from. */ +@module("react-dom") +external preconnect: string => unit = "preconnect" + +type preloadOptions = { + /** The type of resource. */ + @as("as") + as_: [ + | #audio + | #document + | #embed + | #fetch + | #font + | #image + | #object + | #script + | #style + | #track + | #video + | #worker + ], + /** The CORS policy to use. It is required when as is set to "fetch". */ + crossOrigin?: crossOrigin, + /** The Referrer header to send when fetching. */ + referrerPolicy?: referrerPolicy, + /** A cryptographic hash of the resource, to verify its authenticity. */ + integrity?: string, + /** The MIME type of the resource. */ + @as("type") + type_?: string, + /** A cryptographic nonce to allow the resource when using a strict Content Security Policy. */ + nonce?: string, + /** Suggests a relative priority for fetching the resource. */ + fetchPriority?: fetchPriority, + /** For use only with as: "image". Specifies the source set of the image. */ + imageSrcSet?: string, + /** For use only with as: "image". Specifies the sizes of the image. */ + imageSizes?: string, +} + +/** `preload` lets you eagerly fetch a resource such as a stylesheet, font, or external script that you expect to use. */ +@module("react-dom") +external preload: (string, preloadOptions) => unit = "preload" + +type preloadModuleOptions = { + /** The type of resource. */ + @as("as") + as_: [#script], + /** The CORS policy to use. It is required when as is set to "fetch". */ + crossOrigin?: crossOrigin, + /** A cryptographic hash of the resource, to verify its authenticity. */ + integrity?: string, + /** A cryptographic nonce to allow the resource when using a strict Content Security Policy. */ + nonce?: string, +} + +/** `preloadModule` lets you eagerly fetch an ESM module that you expect to use. */ +@module("react-dom") +external preloadModule: (string, preloadModuleOptions) => unit = "preloadModule" + +type preinitOptions = { + /** The type of resource. */ + @as("as") + as_: [#script | #style], + /** Required with stylesheets. Says where to insert the stylesheet relative to others. Stylesheets with higher precedence can override those with lower precedence. */ + precedence?: [#reset | #low | #medium | #high], + /** The CORS policy to use. It is required when as is set to "fetch". */ + crossOrigin?: crossOrigin, + /** The Referrer header to send when fetching. */ + referrerPolicy?: referrerPolicy, + /** A cryptographic hash of the resource, to verify its authenticity. */ + integrity?: string, + nonce?: string, + /** Suggests a relative priority for fetching the resource. */ + fetchPriority?: fetchPriority, +} + +/** `preinit` lets you eagerly fetch and evaluate a stylesheet or external script. */ +@module("react-dom") +external preinit: (string, preinitOptions) => unit = "preinit" + +/** To preinit an ESM module, call the `preinitModule` function from react-dom. */ +@module("react-dom") +external preinitModule: (string, preloadModuleOptions) => unit = "preinitModule" + +// Runtime + type domProps = JsxDOM.domProps @variadic @module("react") diff --git a/packages/react/src/ReactDOMServer.res b/tests/dependencies/rescript-react/src/ReactDOMServer.res similarity index 100% rename from packages/react/src/ReactDOMServer.res rename to tests/dependencies/rescript-react/src/ReactDOMServer.res diff --git a/packages/react/src/ReactDOMStatic.res b/tests/dependencies/rescript-react/src/ReactDOMStatic.res similarity index 100% rename from packages/react/src/ReactDOMStatic.res rename to tests/dependencies/rescript-react/src/ReactDOMStatic.res diff --git a/packages/react/src/ReactTestUtils.res b/tests/dependencies/rescript-react/src/ReactTestUtils.res similarity index 100% rename from packages/react/src/ReactTestUtils.res rename to tests/dependencies/rescript-react/src/ReactTestUtils.res diff --git a/packages/react/src/ReactTestUtils.resi b/tests/dependencies/rescript-react/src/ReactTestUtils.resi similarity index 100% rename from packages/react/src/ReactTestUtils.resi rename to tests/dependencies/rescript-react/src/ReactTestUtils.resi diff --git a/packages/react/src/RescriptReactErrorBoundary.res b/tests/dependencies/rescript-react/src/RescriptReactErrorBoundary.res similarity index 98% rename from packages/react/src/RescriptReactErrorBoundary.res rename to tests/dependencies/rescript-react/src/RescriptReactErrorBoundary.res index 3caa0e8e17..cb00d25bc2 100644 --- a/packages/react/src/RescriptReactErrorBoundary.res +++ b/tests/dependencies/rescript-react/src/RescriptReactErrorBoundary.res @@ -1,8 +1,8 @@ -@ocaml.doc(" +/*** * 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> = { diff --git a/packages/react/src/RescriptReactErrorBoundary.resi b/tests/dependencies/rescript-react/src/RescriptReactErrorBoundary.resi similarity index 95% rename from packages/react/src/RescriptReactErrorBoundary.resi rename to tests/dependencies/rescript-react/src/RescriptReactErrorBoundary.resi index 3bc8071da3..0ebdbc8aff 100644 --- a/packages/react/src/RescriptReactErrorBoundary.resi +++ b/tests/dependencies/rescript-react/src/RescriptReactErrorBoundary.resi @@ -1,8 +1,8 @@ -@ocaml.doc(" +/*** * 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> = { diff --git a/packages/react/src/RescriptReactRouter.res b/tests/dependencies/rescript-react/src/RescriptReactRouter.res similarity index 100% rename from packages/react/src/RescriptReactRouter.res rename to tests/dependencies/rescript-react/src/RescriptReactRouter.res diff --git a/packages/react/src/RescriptReactRouter.resi b/tests/dependencies/rescript-react/src/RescriptReactRouter.resi similarity index 68% rename from packages/react/src/RescriptReactRouter.resi rename to tests/dependencies/rescript-react/src/RescriptReactRouter.resi index 654235e842..25357f3267 100644 --- a/packages/react/src/RescriptReactRouter.resi +++ b/tests/dependencies/rescript-react/src/RescriptReactRouter.resi @@ -1,11 +1,7 @@ -@ocaml.doc( - "update the url with the string path. Example: `push(\"/book/1\")`, `push(\"/books#title\")` " -) +/** update the url with the string path. Example: `push(\"/book/1\")`, `push(\"/books#title\")` */ let push: string => unit -@ocaml.doc( - "update the url with the string path. modifies the current history entry instead of creating a new one. Example: `replace(\"/book/1\")`, `replace(\"/books#title\")` " -) +/** update the url with the string path. modifies the current history entry instead of creating a new one. Example: `replace(\"/book/1\")`, `replace(\"/books#title\")` */ let replace: string => unit type watcherID type url = { @@ -17,15 +13,13 @@ type url = { search: string, } -@ocaml.doc( - "start watching for URL changes. Returns a subscription token. Upon url change, calls the callback and passes it the url record " -) +/** start watching for URL changes. Returns a subscription token. Upon url change, calls the callback and passes it the url record */ let watchUrl: (url => unit) => watcherID -@ocaml.doc(" stop watching for URL changes ") +/** stop watching for URL changes */ let unwatchUrl: watcherID => unit -@ocaml.doc("this is marked as \"dangerous\" because you technically shouldn't +/** this is marked as \"dangerous\" because you technically shouldn't be accessing the URL outside of watchUrl's callback; you'd read a potentially stale url, instead of the fresh one inside watchUrl. @@ -37,10 +31,10 @@ let unwatchUrl: watcherID => unit So, the correct (and idiomatic) usage of this helper is to only use it in a component that's also subscribed to watchUrl. Please see https://github.com/reasonml-community/reason-react-example/blob/master/src/todomvc/TodoItem.re - for an example.") + for an example. */ let dangerouslyGetInitialUrl: (~serverUrlString: string=?, unit) => url -@ocaml.doc("hook for watching url changes. +/** hook for watching url changes. * serverUrl is used for ssr. it allows you to specify the url without relying on browser apis existing/working as expected - ") + */ let useUrl: (~serverUrl: url=?, unit) => url diff --git a/yarn.lock b/yarn.lock index 056f7494ae..abf9fff983 100644 --- a/yarn.lock +++ b/yarn.lock @@ -412,9 +412,9 @@ __metadata: languageName: unknown linkType: soft -"@rescript/react@workspace:^, @rescript/react@workspace:packages/react": +"@rescript/react@workspace:^, @rescript/react@workspace:tests/dependencies/rescript-react": version: 0.0.0-use.local - resolution: "@rescript/react@workspace:packages/react" + resolution: "@rescript/react@workspace:tests/dependencies/rescript-react" dependencies: rescript: "workspace:^" languageName: unknown @@ -663,12 +663,6 @@ __metadata: languageName: unknown linkType: soft -"@tests/rescript-react@workspace:tests/dependencies/rescript-react": - version: 0.0.0-use.local - resolution: "@tests/rescript-react@workspace:tests/dependencies/rescript-react" - languageName: unknown - linkType: soft - "@tests/tests@workspace:tests/tests": version: 0.0.0-use.local resolution: "@tests/tests@workspace:tests/tests" From f097370bfa15e9d2fbf0aef08c5472ad826cec23 Mon Sep 17 00:00:00 2001 From: Christoph Knittel Date: Tue, 27 May 2025 08:58:56 +0200 Subject: [PATCH 12/14] Update analysis snapshot --- .../tests-reanalyze/deadcode/expected/deadcode.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/analysis_tests/tests-reanalyze/deadcode/expected/deadcode.txt b/tests/analysis_tests/tests-reanalyze/deadcode/expected/deadcode.txt index a0b06162e0..eecccef315 100644 --- a/tests/analysis_tests/tests-reanalyze/deadcode/expected/deadcode.txt +++ b/tests/analysis_tests/tests-reanalyze/deadcode/expected/deadcode.txt @@ -417,7 +417,7 @@ addValueDeclaration +make Hooks.res:63:6 path:+Hooks.RenderPropRequiresConversion addRecordLabelDeclaration name Hooks.res:1:16 path:+Hooks.vehicle addRecordLabelDeclaration vehicle Hooks.res:4:12 path:+Hooks.props - addValueReference Hooks.res:5:26 --> React.res:134:0 + addValueReference Hooks.res:5:26 --> React.res:135:0 addTypeReference Hooks.res:10:29 --> Hooks.res:1:16 addValueReference Hooks.res:10:29 --> Hooks.res:4:12 addValueReference Hooks.res:10:75 --> Hooks.res:5:7 From 387feaa3f7628e03c63fb0e2a234171eb7055dc8 Mon Sep 17 00:00:00 2001 From: Christoph Knittel Date: Tue, 27 May 2025 09:06:36 +0200 Subject: [PATCH 13/14] Enforce constraints for packages in packages folder only. --- yarn.config.cjs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/yarn.config.cjs b/yarn.config.cjs index 072de76869..2d0ae80557 100644 --- a/yarn.config.cjs +++ b/yarn.config.cjs @@ -15,7 +15,10 @@ async function enforceCompilerMeta({ Yarn }) { for (const workspace of Yarn.workspaces()) { const { ident } = workspace.pkg; - if (ident === "rescript" || ident.startsWith("@rescript/")) { + if ( + workspace.cwd.startsWith("packages") && + (ident === "rescript" || ident.startsWith("@rescript/")) + ) { workspace.set("version", EXPECTED_VERSION); workspace.set("homepage", "https://rescript-lang.org"); workspace.set("bugs", "https://github.com/rescript-lang/rescript/issues"); From 9089886839d5e8a933324553752493d06f601626 Mon Sep 17 00:00:00 2001 From: Christoph Knittel Date: Tue, 27 May 2025 09:11:46 +0200 Subject: [PATCH 14/14] Remove superfluous .gitignore --- tests/dependencies/rescript-react/.gitignore | 21 -------------------- 1 file changed, 21 deletions(-) delete mode 100644 tests/dependencies/rescript-react/.gitignore diff --git a/tests/dependencies/rescript-react/.gitignore b/tests/dependencies/rescript-react/.gitignore deleted file mode 100644 index 06844f2b81..0000000000 --- a/tests/dependencies/rescript-react/.gitignore +++ /dev/null @@ -1,21 +0,0 @@ -.DS_Store -/node_modules* -finalOutput/*.js -.merlin -.install -/lib/bs/ -/lib/js/ -/lib/ocaml/ -/docs/ -*.log -.bsb.lock -_esy -_build -*.install -src/legacy/*.bs.js - -# Editor -/.idea/ - -# React -!/src/react/*.js