├── .editorconfig
├── .github
└── workflows
│ └── test.yml
├── .gitignore
├── .munit
├── README.md
├── changes.md
├── doc
├── compilation-flags.md
├── control-structures.md
├── custom-meta.md
├── defines.json
├── metadata.json
├── react-next-roadmap.md
├── react-next.md
├── react-refs-api.md
├── static-components.md
├── typing-props.md
└── wrapping-with-hoc.md
├── extraParams.hxml
├── haxelib.json
├── mdk
└── info.json
├── releaseHaxelib.sh
├── res
└── gen
│ ├── GenHtmlEntities.hx
│ └── Main.hx
├── samples
├── docs
│ ├── .gitignore
│ ├── README.md
│ ├── build-static.hxml
│ ├── build.hxml
│ ├── common.hxml
│ ├── install.hxml
│ ├── makefile
│ ├── package.json
│ ├── res
│ │ └── base.css
│ └── src
│ │ ├── AppContext.hx
│ │ ├── Main.hx
│ │ ├── StaticGenerator.hx
│ │ ├── comp
│ │ ├── App.hx
│ │ ├── Article.hx
│ │ ├── SidePanel.hx
│ │ ├── html
│ │ │ └── ExternalLink.hx
│ │ ├── import.hx
│ │ └── layout
│ │ │ ├── MainContent.hx
│ │ │ ├── MainContentContainer.hx
│ │ │ ├── MainWrapper.hx
│ │ │ ├── StaticBorderBottom.hx
│ │ │ └── StaticBorderTop.hx
│ │ └── data
│ │ └── DocChapter.hx
└── todoapp
│ ├── bin
│ ├── index.html
│ └── styles.css
│ ├── build.hxml
│ ├── install.hxml
│ ├── readme.md
│ └── src
│ ├── Main.hx
│ ├── store
│ ├── TodoActions.hx
│ ├── TodoItem.hx
│ └── TodoStore.hx
│ └── view
│ ├── TodoApp.hx
│ └── TodoList.hx
├── src
└── lib
│ └── react
│ ├── BaseProps.hx
│ ├── Empty.hx
│ ├── Fragment.hx
│ ├── Partial.hx
│ ├── PureComponent.hx
│ ├── React.hx
│ ├── ReactClipboardEvent.hx
│ ├── ReactComponent.hx
│ ├── ReactComponentMacro.hx
│ ├── ReactContext.hx
│ ├── ReactDOM.hx
│ ├── ReactDOMServer.hx
│ ├── ReactEvent.hx
│ ├── ReactFocusEvent.hx
│ ├── ReactKeyboardEvent.hx
│ ├── ReactMacro.hx
│ ├── ReactMouseEvent.hx
│ ├── ReactNode.hx
│ ├── ReactPropTypes.hx
│ ├── ReactRef.hx
│ ├── ReactSharedInternals.hx
│ ├── ReactTestUtils.hx
│ ├── ReactTouchEvent.hx
│ ├── ReactType.hx
│ ├── ReactUIEvent.hx
│ ├── ReactUtil.hx
│ ├── ReactWheelEvent.hx
│ ├── StrictMode.hx
│ ├── Suspense.hx
│ ├── jsx
│ ├── AriaAttributes.hx
│ ├── JsxLiteral.hx
│ ├── JsxMacro.hx
│ ├── JsxPropsBuilder.hx
│ └── JsxStaticMacro.hx
│ └── macro
│ ├── ContextMacro.hx
│ ├── MacroUtil.hx
│ ├── PropsValidator.hx
│ ├── PureComponentMacro.hx
│ ├── ReactComponentMacro.hx
│ ├── ReactDebugMacro.hx
│ ├── ReactMeta.hx
│ ├── ReactTypeMacro.hx
│ └── ReactWrapperMacro.hx
├── tagNext.sh
├── tagRelease.sh
├── test.hxml
└── test
├── src
├── AssertTools.hx
├── ReactMacroTest.hx
├── TestMain.hx
├── TestSuite.hx
├── react
│ ├── Fragment.hx
│ ├── React.hx
│ └── ReactComponent.hx
└── support
│ └── sub
│ ├── CompExternModule.hx
│ └── CompModule.hx
└── test.hxml
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*]
2 | end_of_line = lf
3 | charset = utf-8
4 | trim_trailing_whitespace = true
5 | insert_final_newline = true
6 | indent_style = tab
7 | indent_size = 4
8 |
9 | [*.{json,yml}]
10 | indent_style = space
11 | indent_size = 2
12 |
13 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Tests
2 |
3 | on: [push, repository_dispatch]
4 |
5 | jobs:
6 | build:
7 | runs-on: ubuntu-latest
8 |
9 | strategy:
10 | fail-fast: false
11 | matrix:
12 | haxe: [4.3.2, latest]
13 |
14 | steps:
15 | - uses: actions/checkout@v1
16 |
17 | - name: Setup haxe ${{ matrix.haxe }}
18 | uses: krdlab/setup-haxe@v1
19 | with:
20 | haxe-version: ${{ matrix.haxe }}
21 |
22 | - name: Install libs
23 | run: |
24 | git config --global url."https://github.com/".insteadOf "git@github.com:"
25 | haxelib newrepo
26 | haxelib install munit
27 | haxelib install hxnodejs
28 | haxelib git tink_hxx git@github.com:kLabz/tink_hxx.git
29 | haxelib git tink_anon git@github.com:haxetink/tink_anon.git
30 |
31 | - name: Run tests
32 | run: |
33 | haxelib run munit test -js
34 |
35 | - name: "[Samples] SSR sample : react-next docs website"
36 | run: |
37 | cd samples/docs
38 | make setup
39 | make server
40 | make static
41 |
42 | - name: "[Samples] TODO App"
43 | run: |
44 | cd samples/todoapp
45 | haxelib newrepo
46 | haxelib dev react-next ../..
47 | haxelib install --skip-dependencies --always install.hxml
48 | haxe build.hxml
49 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | example-minimal/node_modules
3 | example-commentbox/node_modules
4 | example-filterproducts/node_modules
5 | /.idea
6 | *.iml
7 | *.hxproj
8 | *.map
9 | test/report/
10 | test/build/
11 | haxe-react.zip
12 | .haxelib
13 |
--------------------------------------------------------------------------------
/.munit:
--------------------------------------------------------------------------------
1 | version=munit
2 | src=test/src
3 | bin=test/build
4 | report=test/report
5 | hxml=test/test.hxml
6 | classPaths=src
7 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Haxe React [#next](./doc/react-next.md) temp fork (See [Roadmap](./doc/react-next-roadmap.md))
2 |
3 | [](https://travis-ci.org/kLabz/haxe-react)
4 | [](http://lib.haxe.org/p/react-next)
5 | [](https://gitter.im/haxe-react/Lobby)
6 |
7 | A Haxe library offering externs and tool functions leveraging Haxe's excellent type system and
8 | compile time macros to offer a strongly typed language to work with the increasingly popular
9 | [React](https://facebook.github.io/react/) library.
10 |
11 | haxelib install react-next
12 |
13 | ### ⚠️ Warning: README.md outdated
14 |
15 | This readme needs many updates. See [changes in #next](./doc/react-next.md); other docs available
16 | in [`doc` folder](./doc/).
17 |
18 | ### What's included / not included
19 |
20 | This library covers React core and ReactDOM.
21 | It does NOT cover: ReactAddOns, react-router or React Native.
22 |
23 | We recommend looking into / contributing to the following efforts:
24 |
25 | - https://github.com/haxe-react (React native and others libs)
26 | - https://github.com/tokomlabs/haxe-react-addons (various externs to pick)
27 |
28 |
29 | ### Application architecture examples
30 |
31 | React doesn't enforce any specific application architecture; here are a few approaches:
32 |
33 | **Redux**, a very popular new approach of Model-View-Intent architecture: global state object,
34 | following immutability principles, but the wiring has been re-imagined to use the best of Haxe:
35 |
36 | - https://github.com/elsassph/haxe-react-redux
37 |
38 | **MMVC**, classic, battle tested, Model-View-Mediator with state of the art Dependency Injection:
39 |
40 | - https://github.com/elsassph/haxe-react-mmvc
41 |
42 | **Flux**, inspired by Facebook's suggested architecture for React; this is a very quick PoC
43 | which probably won't scale well to complex apps, but it shows a good range of React features:
44 |
45 | - https://github.com/massiveinteractive/haxe-react/tree/master/samples/todoapp
46 |
47 |
48 | ### Support / discussions
49 |
50 | If you have questions / issues, join [haxe-react on Gitter.im](https://gitter.im/haxe-react/Lobby)
51 |
52 |
53 | ## API
54 |
55 | Most of the regular React API is integrated (non-JSX example):
56 |
57 | ```haxe
58 | import react.React;
59 | import react.ReactDOM;
60 |
61 | class App extends ReactComponent {
62 |
63 | static public function main() {
64 | ReactDOM.render(React.createElement(App), Browser.document.getElementById('app'));
65 | }
66 |
67 | public function new() {
68 | super();
69 | }
70 |
71 | override function render() {
72 | var cname = 'foo';
73 | return React.createElement('div', {className:cname}, [/*children*/]);
74 | }
75 | }
76 | ```
77 |
78 | Note that `React.createElement` strictly expects either a `String`, a `Function`, or a class
79 | extending `ReactComponent`. It includes when writing externs for 3rd party JS libraries you
80 | must specify `extends`:
81 |
82 | ```haxe
83 | @:jsRequire('react-redux', 'Provider')
84 | extern class Provider extends react.ReactComponent { }
85 | ```
86 |
87 | ## JSX
88 |
89 | The Haxe compiler (and editors) doesn't allow to use exactly the JSX XML DSL,
90 | so we had to compromise a bit...
91 |
92 | This library's take on JSX is to use a compile-time macro to parse JSX as a string to generate
93 | the same kind of code that Facebook's JSX, Babel and Typescript will generate.
94 |
95 | Both classic JSX `{}` binding and Haxe string interpolation `$var` / `${expression}` / `<$Comp>`
96 | are allowed. The advantage of string interpolation is Haxe editor supports for completion and
97 | code navigation.
98 |
99 | Spread operator and complex expressions within curly braces are supported.
100 |
101 | ```haxe
102 | import react.React;
103 | import react.ReactDOM;
104 | import react.ReactMacro.jsx;
105 |
106 | class App extends ReactComponent {
107 |
108 | static public function main() {
109 | ReactDOM.render(jsx(''), Browser.document.getElementById('app'));
110 | }
111 |
112 | public function new() {
113 | super();
114 | }
115 |
116 | override function render() {
117 | var cname = 'foo';
118 | return jsx('
119 |
120 |
121 | ${/*children*/}
122 |
123 | ');
124 | }
125 |
126 | static function statelessComponent(props:Dynamic) {
127 | return jsx('');
128 | }
129 | }
130 | ```
131 |
132 | ### JSX Fragments
133 |
134 | [Fragments](https://reactjs.org/docs/fragments.html) (React 16.2+) let you group
135 | a list of children without adding extra nodes to the DOM.
136 |
137 | Two syntaxes are supported:
138 | ```jsx
139 |
140 | Text
141 | more text
142 | Still more text
143 |
144 |
145 | // or short syntax:
146 | <>
147 | Text
148 | more text
149 | Still more text
150 | >
151 | ```
152 |
153 | ### JSX gotchas
154 |
155 | 1. JSX is not String magic! **Do not concatenate Strings** to construct the JSX expression
156 |
157 | 2. Haxe's JSX parser is not "re-entrant"
158 |
159 | In JavaScript you can nest JSX inside curly-brace expressions:
160 | ```javascript
161 | return (
162 |
{ isA ? : }
163 | );
164 | ```
165 |
166 | However this isn't allowed in Haxe, so you must extract nested JSX into variables:
167 | ```haxe
168 | var content = isA ? jsx('') : jsx('');
169 | return jsx('
{content}
');
170 | ```
171 |
172 | ## Components strict typing
173 |
174 | The default `ReactComponent` type is a shorthand for `ReactComponentOf`,
175 | a fully untyped component.
176 |
177 | To fully benefit from Haxe's strict typing you should look into extending a stricter base class:
178 |
179 | ```haxe
180 | typedef ReactComponentOfProps = ReactComponentOf;
181 | typedef ReactComponentOfState = ReactComponentOf;
182 | typedef ReactComponentOfPropsAndState = ReactComponentOf;
183 | ```
184 |
185 | ## React JS dependency
186 |
187 | There are 2 ways to link the React JS library:
188 |
189 | ### Require method (default)
190 |
191 | By default the library uses `require('react')` to reference React JS.
192 |
193 | This means you are expected to use `npm` to install this dependency:
194 |
195 | npm install react
196 |
197 | and a second build step to generate the final JS file, for instance using `browserify`:
198 |
199 | npm install browserify
200 | browserify haxe-output.js -o final-output.js
201 |
202 | (note that you can use `watchify` to automatically run this build step)
203 |
204 | ### Global JS
205 |
206 | The other common method is to download or reference the CDN files of React JS in your HTML page:
207 |
208 | ```html
209 |
210 |
211 | ```
212 |
213 | and don't forget to add the following Haxe define to your build command:
214 |
215 | -D react_global
216 |
217 | Look at `samples/todoapp` for an example of this approach.
218 |
219 |
220 | ## JSX Optimizing Compiler
221 |
222 | ### Inline ReactElements
223 |
224 | By default, when building for release (eg. without `-debug`), calls to `React.createElement` are replaced by inline JS objects (if possible).
225 |
226 | See: https://github.com/facebook/react/issues/3228
227 |
228 | ```javascript
229 | // regular
230 | return React.createElement('div', {key:'bar', className:'foo'});
231 |
232 | // inlined (simplified)
233 | return {$$typeof:Symbol.for('react.element'), type:'div', props:{className:'foo'}, key:'bar'}
234 | ```
235 |
236 | This behaviour can be **disabled** using `-D react_no_inline`.
237 |
238 | ## Optimization tools
239 |
240 | ### Avoidable renders warning
241 |
242 | Setting `-D react_render_warning` will enable runtime warnings for avoidable renders.
243 |
244 | This will add a `componentDidUpdate` (or update the existing one) where a **shallowCompare** is done on current and previous props and state. If both did not change, a warning will be displayed in the console.
245 |
246 | False positives can happen if your props are not flat, due to the shallowCompare.
247 |
--------------------------------------------------------------------------------
/changes.md:
--------------------------------------------------------------------------------
1 | ## Changes
2 |
3 | ### 1.4.0
4 |
5 | - Generate `displayName` for `@:jsxStatic` components #86
6 | - React 16.2: added Fragments support #87: https://reactjs.org/blog/2017/11/28/react-v16.2.0-fragment-support.html
7 | - User overloads instead of `EitherType` for `setState` #91
8 | - Added utility function `ReactUtil.copyWithout` #96
9 | - ReactComponent macros refactoring #97
10 | - Travis CI
11 |
12 | ### 1.3.0
13 |
14 | - React 16 support; React 15 is still compatible but won't support new APIs (`componentDidCatch`, `createPortal`)
15 | - added missing `ReactDOM.hydrate` method (server-side rendering)
16 | - added `@:jsxStatic` optional meta
17 | - breaking: `react.ReactPropTypes` now requires the NPM `prop-types` module
18 |
19 | ### 1.2.1
20 |
21 | - fixed auto-complete issue on `this.state` caused by the `1.2.0` changes
22 |
23 | ### 1.2.0
24 |
25 | - `setState` now accepts `Partial`; where `T` is a `typedef`, `Partial` is `T` will all the fields made optional
26 | - `react.React.PropTypes` removed in favor of `react.ReactPropTypes`
27 | - added `-D react_render_warning` option
28 |
--------------------------------------------------------------------------------
/doc/compilation-flags.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Custom compilation flags
3 | ---
4 |
5 | # Custom compilation flags used by haxe-react
6 |
7 | ## `-debug` / `-D debug`
8 |
9 | This is not a custom compilation flag, but it enables/disables some features in
10 | haxe-react. Basically, you'll want to compile with it when using dev version of
11 | react, and remove it when using prod version.
12 |
13 | ### Disabled features
14 |
15 | #### Inline ReactElements
16 |
17 | By default, when building for release (eg. without `-debug`), calls to
18 | `React.createElement` are replaced by inline JS objects (if possible). This can
19 | also be disabled with `-D react_no_inline`.
20 |
21 | See: https://github.com/facebook/react/issues/3228
22 |
23 | ```javascript
24 | // regular
25 | return React.createElement('div', {key:'bar', className:'foo'});
26 |
27 | // inlined (simplified)
28 | return {$$typeof:Symbol.for('react.element'), type:'div', props:{className:'foo'}, key:'bar'}
29 | ```
30 |
31 | ### Enabled features
32 |
33 | #### Display names
34 |
35 | When compiling in debug mode, display names are added for your components, for
36 | use with your browser's react developer tools.
37 |
38 | #### React shared internals
39 |
40 | Some react shared internals data are only available when compiling in debug mode
41 | (and using dev version of react), for advanced debugging.
42 |
43 | #### React runtime warnings
44 |
45 | Haxe-react adds some runtime warnings when enabled with both debug mode and
46 | `-D react_runtime_warnings`. There is still work to be done here, especially
47 | with the re-render warnings that have some false positives atm.
48 |
49 | This warnings include:
50 |
51 | * Runtime warnings about avoidable re-renders, unless you also compile with
52 | `-D react_runtime_warnings_ignore_rerender` **or** for a specific component if
53 | you add a `@:ignoreRenderWarning` meta to it. This feature can be disabled
54 | because it can have false positives when dealing with legacy context API or
55 | hot reloading.
56 |
57 | * Runtime errors when a stateful component does not initialize its state inside
58 | its constructor. There would be errors thrown by react later in the component
59 | lifecycle, but without the source cause.
60 |
61 | ```haxe
62 | js.Browser.console.error(
63 | 'Warning: component ${inClass.name} is stateful but its '
64 | + '`state` is not initialized inside its constructor.\n\n'
65 |
66 | + 'Either add a `state = { ... }` statement to its constructor '
67 | + 'or define this component as a `ReactComponentOfProps` '
68 | + 'if it is only using `props`.\n\n'
69 |
70 | + 'If it is using neither `props` nor `state`, you might '
71 | + 'consider using `@:jsxStatic` to avoid unneeded lifecycle. '
72 | + 'See https://github.com/kLabz/haxe-react/blob/next/doc/static-components.md '
73 | + 'for more information on static components.'
74 | );
75 | ```
76 |
77 | #### Runtime errors for `null` nodes
78 |
79 | `ReactType` adds a runtime error when a node ends up with a `null` value, which
80 | is usually due to an extern component not resolving to its real value.
81 |
82 | ## `-D react_global`
83 |
84 | Use this compilation flag when you are loading react by embedding react js files
85 | in your HTML page (instead of using `require()` from modular or webpack).
86 |
87 | ## `-D react_hot`
88 |
89 | Adds some data needed for react hot reloading with modular / webpack. See
90 | [haxe-modular documentation](https://github.com/elsassph/haxe-modular/blob/master/doc/hmr-usage.md).
91 |
92 | ## `-D react_deprecated_context`
93 |
94 | The `context` field on `ReactComponent` has been removed because it has been
95 | deprecated in react and its use as a class field is discouraged. You can add it
96 | back with this flag if needed.
97 |
98 | ## `-D react_ignore_failed_props_inference`
99 |
100 | Jsx parser currently cannot apply type checker on some components (see
101 | [#7](https://github.com/kLabz/haxe-react/issues/7)) and will produce warnings.
102 |
103 | This compilation flags disable these warnings.
104 |
105 | ## `-D react_wrap_strict`
106 |
107 | Enable strict mode for `@:wrap` HOC wrapping. This will ensure you define the
108 | public props type of your component wrapped with `@:wrap` so that jsx type
109 | checking can be done.
110 | See [Wrapping your components in HOCs](./wrapping-with-hoc.md).
111 |
112 | ## `-D react_check_jsxstatic_type`
113 |
114 | Enable prototype type checker for `@:jsxStatic` expressions.
115 |
116 | ## `-D react_jsx_no_aria`
117 |
118 | Since [`affd6e4a`][affd6e4a], `aria-*` props are type-checked against their
119 | [specification][aria-specs], and enums are provided where necessary (see
120 | `react.jsx.AriaAttributes`). They are enabled by default for both html elements
121 | and react components. You can disable support for `aria-*` props entirely with
122 | `-D react_jsx_no_aria`, or only disable it for react components with
123 | `-D react_jsx_no_aria_for_components`.
124 |
125 | ## `-D react_jsx_no_data_for_components`
126 |
127 | Since [`affd6e4a`][affd6e4a], `data-*` props are enabled by default for react
128 | components (all unknown props are already accepted for html elements), with a
129 | type of `Dynamic`. This behavior can be disabled with
130 | `-D react_jsx_no_data_for_components`, meaning that `data-*` props need to be
131 | explicitely accepted by the components (which is currently not that easy in
132 | Haxe).
133 |
134 | ## `-D react_auto_jsx` (haxe 4 only)
135 |
136 | Haxe 4 introduces inline xml-like markup, allowing us to drop the strings in our
137 | `jsx(...)` expressions.
138 |
139 | With this option, `react-next` goes one step further and automatically wraps all
140 | xml markup in `render` (and also `renderSomething`) functions in classes
141 | extending `ReactComponent` in a call to `ReactMacro.jsx()`, as well as in the
142 | methods used in `@:jsxStatic(myMethod)`.
143 |
144 | Note that this feature has been reported to be incompatible with `cococonut`.
145 |
146 | [affd6e4a]: https://github.com/kLabz/haxe-react/commit/affd6e4a
147 | [aria-specs]: https://www.w3.org/TR/wai-aria-1.1/#state_prop_def
148 |
--------------------------------------------------------------------------------
/doc/control-structures.md:
--------------------------------------------------------------------------------
1 | ## Control structures
2 |
3 | React next supports `tink_hxx` control structures. This doc comes directly from
4 | `tink_hxx`'s README with minor adaptations for use with Haxe React.
5 |
6 | HXX has support for a few control structures. Their main reason for existence
7 | is that implementing a reentrant parser with autocompletion support proved
8 | rather problematic in Haxe 3.
9 |
10 | ### If
11 |
12 | This is what conditionals look like:
13 |
14 | ```html
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | ```
28 |
29 | Note that `else` (as well as `elseif`) is optional and that both `elseif` and
30 | `else if` will work.
31 |
32 | ### Switch
33 |
34 | Switch statements are also supported, including guards but without `default`
35 | branches (just use a catch-all `case` instead). The above example for
36 | conditionals would look like this:
37 |
38 | ```html
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | ```
61 |
62 | ### For
63 |
64 | For loops are pretty straight forward:
65 |
66 | ```html
67 |
68 |
69 |
70 | ```
71 |
72 | ### Let
73 |
74 | You can define variables with `` and access them within the tag.
75 |
76 | ```html
77 |
78 |
79 |
80 |
81 |
82 | ```
83 |
--------------------------------------------------------------------------------
/doc/custom-meta.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Custom metadata
3 | ---
4 |
5 | # Custom meta used by haxe-react
6 |
7 | ## `@:wrap(hoc)`
8 |
9 | Wrap current component (must extend `ReactComponent`) in a HOC.
10 |
11 | See [Wrapping your components in HOCs](./wrapping-with-hoc.md) for more
12 | information about this meta and the following related meta:
13 |
14 | #### `@:publicProps(TProps)`
15 |
16 | Set public props type to ensure jsx type checking.
17 |
18 | #### `@:noPublicProps`
19 |
20 | Disallow public props for this component when used in jsx.
21 |
22 | #### `@:wrapped_by_macro`
23 |
24 | This special meta is added by the `@:wrap` macro for internal use, do not set it
25 | if you don't want to break the functionality.
26 |
27 | ## `@:jsxStatic(method)`
28 |
29 | Create a static component that you can use in jsx (and where "real" components
30 | are expected) from a static function from a class (**not** a `ReactComponent`
31 | class).
32 |
33 | See [Static components](./static-components.md).
34 |
35 | ## `@:ignoreEmptyRender`
36 |
37 | There is a compile-time check for an override of the `render` function in your
38 | components. This helps catching following runtime warning sooner:
39 |
40 | Warning: Index(...): No `render` method found on the returned component
41 | instance: you may have forgotten to define `render`.
42 |
43 | Catching it at compile-time also ensures it does not happen to a component only
44 | visible for a few specific application state.
45 |
46 | You can disable this with the `-D react_ignore_empty_render` compilation flag,
47 | or for a specific component by adding `@:ignoreEmptyRender` meta to it.
48 |
49 | ## `@:pureComponent`
50 |
51 | TODO: Documentation for macro implementation of pure components.
52 |
53 | ## `@:ignoreRenderWarning`
54 |
55 | TODO: Documentation for runtime warnings.
56 |
57 | ## `@:acceptsMoreProps`
58 |
59 | Some components accept specific props, but also any number of additional props
60 | that are usually passed down to an unknown child component.
61 |
62 | This is not the safest pattern out there, but you might have to write or use
63 | externs for this kind of components. Haxe React jsx parser being very strict
64 | with the props, this meta was needed to define this behavior.
65 |
66 | ```haxe
67 | typedef Props = { /* define your props here */ }
68 |
69 | @:acceptsMoreProps
70 | class MyComponent extends ReactComponentOfProps {}
71 | ```
72 |
73 | ### Custom props validators with `@:acceptsMoreProps('validator_key')`
74 |
75 | (New in react-next 1.105.0)
76 |
77 | Sometimes, especially when dealing with externs, you want to be able to validate
78 | props in a way that is not really possible with haxe type system.
79 |
80 | You can register custom props validator (at macro level) for your component with
81 | an initialization macro in your `.hxml`:
82 |
83 | ```
84 | --macro pack.InitMacro.registerValidator()
85 | ```
86 |
87 | This macro will look like this:
88 |
89 | ```haxe
90 | package pack;
91 |
92 | import haxe.macro.Expr;
93 | import react.macro.PropsValidator;
94 |
95 | class InitMacro {
96 | // Initialization macro doing the registration
97 | public static function registerValidator() {
98 | PropsValidator.register('my_very_unique_key', validator);
99 | }
100 |
101 | // The actual validator
102 | public static function validator(name:String, expr:Expr):Null {
103 | if (some_condition) {
104 | // Ok, I recognize this prop!
105 | // Add an `ECheckType` around the expr to validate the props typing
106 | // Note: just return `expr` if you don't want to check its type
107 | var expectedType:ComplexType = macro :ExpectedType;
108 | return macro @:pos(expr.pos) (${expr}:$expectedType);
109 | }
110 |
111 | // This prop isn't known by the validator, let jsx throw the usual error
112 | return null;
113 | }
114 | }
115 | ```
116 |
117 | Your component can the use `@:acceptsMoreProps` to tell the jsx macro how to
118 | validate extra props:
119 |
120 | ```haxe
121 | private typedef Props = {
122 | var normalProp:String;
123 | @:optional var normalOptionalProp:Int;
124 | }
125 |
126 | @:acceptsMoreProps('my_very_unique_key')
127 | class MyComponent extends ReactComponentOfProps {
128 | // ...
129 | }
130 | ```
131 |
132 | Note that you will have to avoid validator key conflict yourself, so make sure
133 | your keys will likely be unique (by namespacing, for example), especially if you
134 | use this feature in a library.
135 |
--------------------------------------------------------------------------------
/doc/defines.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "define": "react_no_inline",
4 | "doc": "Skip React.createElement inlining optimization."
5 | },
6 | {
7 | "define": "react_global",
8 | "doc": "Use window.React instead of require() from modular/webpack."
9 | },
10 | {
11 | "define": "react_hot",
12 | "doc": "Adds some data needed for react hot reloading with modular/webpack."
13 | },
14 | {
15 | "define": "react_runtime_warnings",
16 | "doc": "Enable some runtime warnings for debug purpose."
17 | }
18 | ]
19 |
--------------------------------------------------------------------------------
/doc/metadata.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "metadata": ":wrap",
4 | "doc": "Wrap current class component in a HOC.",
5 | "params": ["HOC"],
6 | "targets": ["TClass"]
7 | },
8 | {
9 | "metadata": ":publicProps",
10 | "doc": "Set public props type to ensure jsx type checking.",
11 | "params": ["TProps"],
12 | "targets": ["TClass"]
13 | },
14 | {
15 | "metadata": ":noPublicProps",
16 | "doc": "Disallow public props for this component when used in jsx.",
17 | "targets": ["TClass"]
18 | }
19 | ]
20 |
--------------------------------------------------------------------------------
/doc/react-next-roadmap.md:
--------------------------------------------------------------------------------
1 | ---
2 | order: 1
3 | title: React "next" Roadmap
4 | ---
5 |
6 | # Haxe React #next: roadmap
7 |
8 | There's still work to be done being this fork is ready for a haxe-react 2.0.0
9 | candidate. This file will be updated with new bugs and new feature ideas that
10 | should be included in the release.
11 |
12 | Done tasks will be deleted from here, if you are looking for differences with
13 | upstream haxe-react, see [React #next doc](./react-next.md).
14 |
15 | PRs are welcome for helping with any of these, but you may want to get in touch
16 | (via gitter for example) before doing so, as some features/fix are already
17 | started and sometimes almost finished.
18 |
19 | If you have wishes or suggestions, come to gitter or open issues here; I'll be
20 | happy to consider them.
21 |
22 | ## Features needing improvements / new features
23 |
24 | * Jsx macro performances improvement to reduce compilation time
25 | * Implement missing React APIs (see #11)
26 | * Update react events handling
27 |
28 | ### Some more things that **may** be added too
29 |
30 | * Inline `@:jsxStatic` proxy field to help with performance and file size
31 | * Some helpers to create HOCs (which can then be used with `@:wrap`)
32 | * More stability with both runtime warnings and hot reloading enabled
33 | * Some improvements for `Partial`
34 | * Generate `propTypes` from components' `TProps` when compiling with `-debug`
35 | and `-D react-generate-proptypes`
36 |
37 | ## Documentation
38 |
39 | * PureComponent
40 | * Runtime warnings documentation
41 | * Update README.md
42 | * Proper migration guide (based off [react #next doc](./react-next.md))
43 | * Test (and potentially update) samples
44 | * Add more samples for new APIs
45 |
--------------------------------------------------------------------------------
/doc/react-refs-api.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: React Refs API (React 16.3)
3 | ---
4 |
5 | # New React Refs API (React 16.3)
6 |
7 | Externs have been added for [`React.createRef()`][createRef] and
8 | [`React.forwardRef()`][forwardRef] from the new refs API introduced in React
9 | `16.3`.
10 |
11 | ## Example usage
12 |
13 | ```haxe
14 | import js.html.InputElement;
15 | import react.React;
16 | import react.ReactRef;
17 | import react.ReactComponent;
18 | import react.ReactMacro.jsx;
19 |
20 | class TestComponent extends ReactComponentOfState<{message: String}> {
21 | var inputRef:ReactRef = React.createRef();
22 |
23 | public function new(props) {
24 | super(props);
25 |
26 | state = {message: null};
27 | }
28 |
29 | override public function render() {
30 | return jsx('
31 | <>
32 | ${state.message}
33 |
34 |
35 | >
36 | ');
37 | }
38 |
39 | function updateMessage() {
40 | setState({message: inputRef.current.value});
41 | }
42 | }
43 | ```
44 |
45 | We can also use `var inputRef = React.createRef();` but I personally prefer to
46 | type my refs to the underlying element.
47 |
48 | [createRef]: https://reactjs.org/docs/react-api.html#reactcreateref
49 | [forwardRef]: https://reactjs.org/docs/react-api.html#reactforwardref
50 |
--------------------------------------------------------------------------------
/doc/static-components.md:
--------------------------------------------------------------------------------
1 | # Static components
2 |
3 | Static/functional components (sometimes called presentational or dumb
4 | components) are lightweight components that only rely on their props to render.
5 |
6 | Not being real components means that they are not subject to react component
7 | lifecycle, and so are more lightweight than standard components.
8 |
9 | They serve a different purpose than `PureComponent`: their render function will
10 | still get called everytime their parent updates, regardless of the static
11 | component's props. Static components should have simple render functions,
12 | allowing them to be faster than pure components even if they do not support
13 | `shouldComponentUpdate`.
14 |
15 | Static components should be avoided when their parent updates often and the
16 | static component's props mostly stays the same. Use `PureComponent` for this use
17 | case.
18 |
19 | Static components can be expressed as static functions:
20 | ```haxe
21 | class MyComponents {
22 | public static function heading(props:{children:String}) {
23 | return jsx('
24 |
${props.content}
25 | ');
26 | }
27 | }
28 | ```
29 |
30 | And used in your jsx like this:
31 | ```haxe
32 | jsx('
33 |
38 | ');
39 | ```
40 |
41 | But sometimes you want these components to blend in, and be able to call them
42 | just like any other component (especially when you start with a "normal"
43 | component and only then change it into a static component for performance).
44 |
45 | ## `@:jsxStatic` components
46 |
47 | Since haxe-react `1.3.0`, you can use a special meta on any class to transform
48 | it into a static component in the eyes of the jsx parser:
49 |
50 | ```haxe
51 | private typedef Props = {
52 | var children:ReactFragment;
53 | }
54 |
55 | @:jsxStatic(myRenderFunction)
56 | class Heading {
57 | public static function myRenderFunction(props:Props) {
58 | return jsx('
59 |
${props.content}
60 | ');
61 | }
62 | }
63 | ```
64 |
65 | Which can be used in jsx just like any other component:
66 | ```haxe
67 | jsx('
68 |
73 | ');
74 | ```
75 |
76 |
--------------------------------------------------------------------------------
/doc/typing-props.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Typing your props
3 | ---
4 |
5 | # Typing your props with haxe-react
6 |
7 | One of the points of using Haxe to develop javascript applications is to benefit
8 | from a statically typed language. So, naturally, you'll want your components to
9 | be able to define the type of props they are going to get and are able to use.
10 |
11 | ## Using `PropTypes`?
12 |
13 | In React, this is usually done using [`PropTypes`][react-proptypes], which uses
14 | an object with validators for each prop. These validators are runtime ones (they
15 | can also be used by flow or typescript at compile-time), and are not types but
16 | descriptors of types.
17 |
18 | A simplified example from the documentation:
19 |
20 | ```javascript
21 | MyComponent.propTypes = {
22 | optionalArray: PropTypes.array,
23 | optionalBool: PropTypes.bool,
24 | optionalFunc: PropTypes.func,
25 | optionalNumber: PropTypes.number,
26 | requiredFunc: PropTypes.func.isRequired
27 | };
28 | ```
29 |
30 | You can declare them with haxe-react by using `react.ReactPropTypes`:
31 |
32 | ```haxe
33 | import react.ReactComponent;
34 | import react.ReactPropTypes as PropTypes;
35 |
36 | class MyComponent extends ReactComponent {
37 | static var propTypes = {
38 | optionalArray: PropTypes.array,
39 | optionalBool: PropTypes.bool,
40 | optionalFunc: PropTypes.func,
41 | optionalNumber: PropTypes.number,
42 | requiredFunc: PropTypes.func.isRequired
43 | };
44 |
45 | // ...
46 | }
47 | ```
48 |
49 | Note that this won't do any compile-time check, though, as it is not the primary
50 | typing system for props in haxe-react.
51 |
52 | ## Use real static typing with `TProps`
53 |
54 | In Haxe React, props typing is usually done using `TProps`, a typedef typing the
55 | props your component can use and should be called with.
56 |
57 | These types are enforced at compile times when using jsx (haxe-react #next only)
58 |
59 | The above example would be implemented with something like that:
60 |
61 | ```haxe
62 | import react.ReactComponent;
63 |
64 | typedef MyComponentProps = {
65 | var requiredFunc:String->Void;
66 | @:optional var optionalArray:Array;
67 | @:optional var optionalBool:Bool;
68 | @:optional var optionalFunc:Int->String;
69 | @:optional var optionalNumber:Int;
70 | }
71 |
72 | class MyComponent extends ReactComponentOfProps {
73 | // ...
74 | }
75 | ```
76 |
77 |
78 | [react-proptypes]: https://reactjs.org/docs/typechecking-with-proptypes.html
79 |
--------------------------------------------------------------------------------
/doc/wrapping-with-hoc.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Wrap with HOC
3 | ---
4 |
5 | # Wrapping your components in HOCs
6 |
7 | You can use HOCs with your components (unless they are `@:jsxStatic` components)
8 | by adding `@:wrap` meta.
9 |
10 | ```haxe
11 | import react.ReactComponent;
12 | import react.ReactMacro.jsx;
13 | import react.router.ReactRouter;
14 | import react.router.Route.RouteRenderProps;
15 |
16 | @:wrap(ReactRouter.withRouter)
17 | class MyComponent extends ReactComponentOfProps {
18 | override public function render() {
19 | return jsx('
53 | Current path is ${props.location.pathname} and the answer is ${props.answer}
54 |
55 | ');
56 | }
57 | }
58 | ```
59 |
60 | ## `@:publicProps(TProps)`
61 |
62 | One thing to note, though: you will loose props type checking in jsx. You can
63 | get this back by separating your component's public and final props:
64 |
65 | ```haxe
66 | // Final props
67 | private typedef Props = {
68 | > PublicProps,
69 | > RouteRenderProps,
70 | }
71 |
72 | // Public props, which need to be provided via jsx
73 | private typedef PublicProps = {
74 | var path:String;
75 | }
76 | ```
77 |
78 | You can then tell `@:wrap` what public props you are expecting by adding a
79 | `@:publicProps` meta, and get back all the props typing (including missing and
80 | extra props warnings/errors) like a "normal" component:
81 |
82 | ```haxe
83 | @:publicProps(PublicProps)
84 | @:wrap(ReactRouter.withRouter)
85 | class MyComponent extends ReactComponentOfProps {
86 | override public function render() {
87 | if (props.path != props.location.pathname) return null;
88 |
89 | return jsx('
Welcome to ${props.path}!
');
90 | }
91 | }
92 | ```
93 |
94 | ## `@:noPublicProps`
95 |
96 | However, sometimes your component doesn't have any public prop. You can then use
97 | `@:noPublicProps` meta to get errors when sending extra props to this component:
98 |
99 | ```haxe
100 | import react.ReactComponent;
101 | import react.ReactMacro.jsx;
102 | import react.router.ReactRouter;
103 | import react.router.Route.RouteRenderProps;
104 |
105 | @:noPublicProps
106 | @:wrap(ReactRouter.withRouter)
107 | class MyComponent extends ReactComponentOfProps {
108 | override public function render() {
109 | return jsx('
90 | ');
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/lib/react/BaseProps.hx:
--------------------------------------------------------------------------------
1 | package react;
2 |
3 | import react.ReactComponent.ReactFragment;
4 | import react.ReactComponent.ReactSingleFragment;
5 | import tink.core.Noise;
6 |
7 | typedef BaseProps = {
8 | var children:TChildren;
9 | }
10 |
11 | typedef BasePropsOpt = {
12 | @:optional var children:TChildren;
13 | }
14 |
15 | typedef BasePropsWithChildren = BaseProps;
16 | typedef BasePropsWithChild = BaseProps;
17 |
18 | typedef BasePropsWithoutChildren = BasePropsOpt;
19 |
20 | typedef BasePropsWithOptChildren = BasePropsOpt;
21 | typedef BasePropsWithOptChild = BasePropsOpt;
22 |
--------------------------------------------------------------------------------
/src/lib/react/Empty.hx:
--------------------------------------------------------------------------------
1 | package react;
2 |
3 | typedef Empty = {}
4 |
5 |
--------------------------------------------------------------------------------
/src/lib/react/Fragment.hx:
--------------------------------------------------------------------------------
1 | package react;
2 |
3 | import react.BaseProps;
4 | import react.ReactComponent;
5 |
6 | /**
7 | Warning: Fragments are only available in react 16.2.0+
8 | https://reactjs.org/blog/2017/11/28/react-v16.2.0-fragment-support.html
9 | **/
10 | #if (!react_global)
11 | @:jsRequire("react", "Fragment")
12 | #end
13 | @:native('React.Fragment')
14 | extern class Fragment extends ReactComponentOfProps {}
15 |
16 |
--------------------------------------------------------------------------------
/src/lib/react/Partial.hx:
--------------------------------------------------------------------------------
1 | /*
2 | From a gist by George Corney:
3 | https://gist.github.com/haxiomic/ad4f5d329ac616543819395f42037aa1
4 |
5 | A Partial, where T is a typedef, is T where all the fields are optional
6 | */
7 | package react;
8 |
9 | import haxe.macro.Context;
10 | import haxe.macro.Expr;
11 | import haxe.macro.TypeTools;
12 |
13 | #if !macro
14 | @:genericBuild(react.PartialMacro.build())
15 | #end
16 | class Partial {}
17 |
18 | @:dce
19 | class PartialMacro {
20 | #if macro
21 | static var cache:Map = new Map();
22 |
23 | static function build() {
24 | var localType = Context.getLocalType();
25 | var cacheKey = TypeTools.toString(localType);
26 | if (cache.exists(cacheKey)) return cache.get(cacheKey);
27 |
28 | switch (localType) {
29 | // Match when class's type parameter leads to an anonymous type (we convert to a complex type in the process to make it easier to work with)
30 | case TInst(_, [Context.followWithAbstracts(_) => TypeTools.toComplexType(_) => TAnonymous(fields)]):
31 | // Add @:optional meta to all fields
32 | var newFields = fields.map(addMeta);
33 | var ret = TAnonymous(newFields);
34 | cache.set(cacheKey, ret);
35 | return ret;
36 |
37 | default:
38 | Context.fatalError('Type parameter should be an anonymous structure', Context.currentPos());
39 | }
40 |
41 | return null;
42 | }
43 |
44 | static function addMeta(field: Field): Field {
45 | // Handle Null and optional fields already parsed by the compiler
46 | var kind = switch (field.kind) {
47 | case FVar(TPath({
48 | name: 'StdTypes',
49 | sub: 'Null',
50 | params: [TPType(TPath(tpath))]
51 | }), write):
52 | FVar(TPath(tpath), write);
53 |
54 | default:
55 | field.kind;
56 | }
57 |
58 | return {
59 | name: field.name,
60 | kind: kind,
61 | access: field.access,
62 | meta: field.meta.concat([{
63 | name: ':optional',
64 | params: [],
65 | pos: Context.currentPos()
66 | }]),
67 | pos: field.pos
68 | };
69 | }
70 | #end
71 | }
72 |
--------------------------------------------------------------------------------
/src/lib/react/PureComponent.hx:
--------------------------------------------------------------------------------
1 | package react;
2 |
3 | import react.ReactComponent;
4 |
5 | typedef PureComponent = PureComponentOf;
6 | typedef PureComponentOfProps = PureComponentOf;
7 | typedef PureComponentOfState = PureComponentOf;
8 |
9 | #if (!react_global)
10 | @:jsRequire("react", "PureComponent")
11 | #end
12 | @:native('React.PureComponent')
13 | @:keepSub
14 | extern class PureComponentOf
15 | extends ReactComponentOf
16 | {}
17 |
--------------------------------------------------------------------------------
/src/lib/react/React.hx:
--------------------------------------------------------------------------------
1 | package react;
2 |
3 | import js.Symbol;
4 | import js.lib.Promise;
5 |
6 | import react.ReactComponent.ReactElement;
7 | import react.ReactComponent.ReactFragment;
8 | import react.ReactComponent.ReactSingleFragment;
9 | import react.ReactContext;
10 | import react.ReactType;
11 |
12 | /**
13 | https://react.dev/reference/react/apis
14 | https://react.dev/reference/react/legacy
15 | **/
16 | #if (!react_global)
17 | @:jsRequire("react")
18 | #end
19 | @:native('React')
20 | extern class React {
21 | /**
22 | https://react.dev/reference/react/createElement
23 | **/
24 | public static function createElement(type:ReactType, ?attrs:Dynamic, children:haxe.extern.Rest):ReactElement;
25 |
26 | /**
27 | Warning:
28 | Using `cloneElement` is uncommon and can lead to fragile code
29 |
30 | https://react.dev/reference/react/cloneElement
31 | **/
32 | public static function cloneElement(element:ReactElement, ?attrs:Dynamic, children:haxe.extern.Rest):ReactElement;
33 |
34 | /**
35 | https://react.dev/reference/react/isValidElement
36 | **/
37 | public static function isValidElement(object:ReactFragment):Bool;
38 |
39 | /**
40 | https://react.dev/reference/react/createContext
41 |
42 | Creates a `{ Provider, Consumer }` pair.
43 | When React renders a context `Consumer`, it will read the current
44 | context value from the closest matching `Provider` above it in the tree.
45 |
46 | The `defaultValue` argument is **only** used by a `Consumer` when it
47 | does not have a matching Provider above it in the tree. This can be
48 | helpful for testing components in isolation without wrapping them.
49 |
50 | Note: passing `undefined` as a `Provider` value does not cause Consumers
51 | to use `defaultValue`.
52 | **/
53 | public static function createContext(
54 | ?defaultValue:TContext,
55 | ?calculateChangedBits:TContext->TContext->Int
56 | ):ReactContext;
57 |
58 | /**
59 | https://react.dev/reference/react/createRef
60 |
61 | Note: this API has been introduced in React 16.3
62 | If you are using an earlier release of React, use callback refs instead
63 | https://reactjs.org/docs/refs-and-the-dom.html#callback-refs
64 | **/
65 | public static function createRef():ReactRef;
66 |
67 | /**
68 | https://react.dev/reference/react/forwardRef
69 | See also https://react.dev/learn/manipulating-the-dom-with-refs
70 |
71 | Note: this API has been introduced in React 16.3
72 | If you are using an earlier release of React, use callback refs instead
73 | https://reactjs.org/docs/refs-and-the-dom.html#callback-refs
74 | **/
75 | public static function forwardRef(render:TProps->ReactRef->ReactFragment):ReactType;
76 |
77 | /**
78 | Warning
79 | Using `Children` is uncommon and can lead to fragile code.
80 |
81 | https://react.dev/reference/react/Children
82 | **/
83 | public static var Children:ReactChildren;
84 |
85 | /**
86 | https://react.dev/reference/react/lazy
87 | **/
88 | public static function lazy(loader:Void->Promise>):ReactType;
89 |
90 | /**
91 | Utility to use `React.lazy()` on an already loaded `ReactType` (either
92 | class component or function), mostly to be used with `react.Suspense`.
93 | **/
94 | public static inline function lazify(t:ReactType):ReactType {
95 | return lazy(() -> Promise.resolve(React.createModule(t)));
96 | }
97 |
98 | /**
99 | Let any `ReactType` pretend to be a module in order to be usable by
100 | `React.lazy()`. Works with class components, functions, etc.
101 | **/
102 | public static inline function createModule(t:ReactType):Module return t;
103 |
104 | public static var version:String;
105 |
106 | public static var Fragment:Symbol;
107 | public static var StrictMode:Symbol;
108 | public static var unstable_AsyncMode:Symbol;
109 | public static var unstable_Profiler:Symbol;
110 |
111 | @:native('__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED')
112 | public static var _internals:ReactSharedInternals;
113 | }
114 |
115 | /**
116 | https://react.dev/reference/react/Children
117 | **/
118 | extern interface ReactChildren {
119 | /**
120 | https://react.dev/reference/react/Children#children-map
121 | **/
122 | function map(children:Dynamic, fn:Array->ReactFragment):Null>;
123 |
124 | /**
125 | https://react.dev/reference/react/Children#children-foreach
126 | **/
127 | function foreach(children:Dynamic, fn:ReactFragment->Void):Void;
128 |
129 | /**
130 | https://react.dev/reference/react/Children#children-count
131 | **/
132 | function count(children:ReactFragment):Int;
133 |
134 | /**
135 | https://react.dev/reference/react/Children#children-only
136 | **/
137 | function only(children:ReactFragment):ReactSingleFragment;
138 |
139 | /**
140 | https://react.dev/reference/react/Children#children-toarray
141 | **/
142 | function toArray(children:ReactFragment):Array;
143 | }
144 |
145 | @:deprecated
146 | typedef CreateElementType = ReactType;
147 |
148 | @:coreType abstract Module {
149 | @:from
150 | static function fromT(v:T):Module return cast {"default": v};
151 | }
152 |
--------------------------------------------------------------------------------
/src/lib/react/ReactClipboardEvent.hx:
--------------------------------------------------------------------------------
1 | package react;
2 |
3 | /**
4 | https://facebook.github.io/react/docs/events.html
5 | **/
6 | extern class ReactClipboardEvent extends ReactEvent
7 | {
8 | public var clipboardData(default, null):String;
9 | }
10 |
--------------------------------------------------------------------------------
/src/lib/react/ReactComponent.hx:
--------------------------------------------------------------------------------
1 | package react;
2 |
3 | #if haxe4
4 | import js.lib.Error;
5 | #else
6 | import js.Error;
7 | #end
8 |
9 | import haxe.extern.EitherType;
10 |
11 | typedef ReactComponentProps = {
12 | /**
13 | Children have to be manipulated using React.Children.*
14 | **/
15 | @:optional var children:Dynamic;
16 | }
17 |
18 | /**
19 | https://facebook.github.io/react/docs/react-component.html
20 |
21 | Can be used as:
22 | - `ReactComponent`, which means TProps = Dynamic and TState = Dynamic (not
23 | recommended, but can help when starting to write externs)
24 |
25 | - `ReactComponent` which means your component doesn't have a state
26 | - `ReactComponent`
27 |
28 | For a component with state and no props, continue using
29 | `ReactComponentOfState`.
30 | **/
31 | @:genericBuild(react.macro.ReactComponentMacro.buildVariadic())
32 | class ReactComponent {}
33 |
34 | typedef ReactComponentOfProps = ReactComponentOf;
35 | typedef ReactComponentOfState = ReactComponentOf;
36 |
37 | // Keep the old ReactComponentOfPropsAndState typedef available
38 | typedef ReactComponentOfPropsAndState = ReactComponentOf;
39 |
40 | #if (!react_global)
41 | @:jsRequire("react", "Component")
42 | #end
43 | @:native('React.Component')
44 | @:keepSub
45 | @:autoBuild(react.macro.ReactComponentMacro.build())
46 | extern class ReactComponentOf
47 | {
48 | #if haxe4
49 | final props:TProps;
50 | #else
51 | var props(default, null):TProps;
52 | #end
53 |
54 | // Note: cannot use final for haxe 4.1.0 - 4.1.1 because of
55 | // https://github.com/HaxeFoundation/haxe/issues/9552
56 | var state(default, null):TState;
57 |
58 | #if react_deprecated_context
59 | // It's better to define it in your ReactComponent subclass as needed, with the right typing.
60 | var context(default, null):Dynamic;
61 | #end
62 |
63 | function new(?props:TProps, ?context:Dynamic);
64 |
65 | /**
66 | https://facebook.github.io/react/docs/react-component.html#forceupdate
67 | **/
68 | function forceUpdate(?callback:Void -> Void):Void;
69 |
70 | /**
71 | https://facebook.github.io/react/docs/react-component.html#setstate
72 | **/
73 | @:overload(function(nextState:TState, ?callback:Void -> Void):Void {})
74 | @:overload(function(nextState:TState -> TProps -> TState, ?callback:Void -> Void):Void {})
75 | function setState(nextState:TState -> TState, ?callback:Void -> Void):Void;
76 |
77 | /**
78 | https://facebook.github.io/react/docs/react-component.html#render
79 | **/
80 | function render():ReactFragment;
81 |
82 | /**
83 | https://facebook.github.io/react/docs/react-component.html#componentwillmount
84 | **/
85 | function componentWillMount():Void;
86 |
87 | /**
88 | https://facebook.github.io/react/docs/react-component.html#componentdidmount
89 | **/
90 | function componentDidMount():Void;
91 |
92 | /**
93 | https://facebook.github.io/react/docs/react-component.html#componentwillunmount
94 | **/
95 | function componentWillUnmount():Void;
96 |
97 | /**
98 | https://facebook.github.io/react/docs/react-component.html#componentwillreceiveprops
99 | **/
100 | function componentWillReceiveProps(nextProps:TProps):Void;
101 |
102 | /**
103 | https://facebook.github.io/react/docs/react-component.html#shouldcomponentupdate
104 | **/
105 | dynamic function shouldComponentUpdate(nextProps:TProps, nextState:TState):Bool;
106 |
107 | /**
108 | https://facebook.github.io/react/docs/react-component.html#componentwillupdate
109 | **/
110 | function componentWillUpdate(nextProps:TProps, nextState:TState):Void;
111 |
112 | /**
113 | https://facebook.github.io/react/docs/react-component.html#componentdidupdate
114 | **/
115 | function componentDidUpdate(prevProps:TProps, prevState:TState):Void;
116 |
117 | /**
118 | https://reactjs.org/blog/2017/07/26/error-handling-in-react-16.html
119 | **/
120 | function componentDidCatch(error:Error, info:{ componentStack:String }):Void;
121 |
122 | #if (js && (react_force_inline || (!debug && !react_no_inline)))
123 | static function __init__():Void {
124 | // required magic value to tag literal react elements
125 | #if haxe4
126 | js.Syntax.code("var $$tre = (typeof Symbol === \"function\" && Symbol.for && Symbol.for(\"react.element\")) || 0xeac7");
127 | #else
128 | untyped __js__("var $$tre = (typeof Symbol === \"function\" && Symbol.for && Symbol.for(\"react.element\")) || 0xeac7");
129 | #end
130 | }
131 | #end
132 | }
133 |
134 | // Used internally to make @:acceptsMoreProps and @:wrap compatible
135 | // Needs to be tested extensively before encouraging manual use
136 | typedef ACCEPTS_MORE_PROPS = TProps;
137 |
138 | typedef ReactSource = {
139 | fileName:String,
140 | lineNumber:Int
141 | }
142 |
143 | typedef ReactElement = {
144 | type:ReactType,
145 | props:Dynamic,
146 | ?key:Dynamic,
147 | ?ref:Dynamic,
148 | ?_owner:Dynamic,
149 |
150 | #if debug
151 | ?_store:{validated:Bool},
152 | ?_shadowChildren:Dynamic,
153 | ?_source:ReactSource,
154 | #end
155 | }
156 |
157 | @:pure @:coreType abstract ReactSingleFragment
158 | from String
159 | from Float
160 | from Bool
161 | from ReactElement {}
162 |
163 | @:pure @:coreType abstract ReactFragment
164 | from ReactSingleFragment
165 | from Array
166 | from Array
167 | from Array
168 | from Array
169 | from Array
170 | from Array
171 | from Array {}
172 |
--------------------------------------------------------------------------------
/src/lib/react/ReactComponentMacro.hx:
--------------------------------------------------------------------------------
1 | package react;
2 |
3 | import react.macro.ReactComponentMacro as RealReactComponentMacro;
4 | import react.macro.ReactComponentMacro.Builder;
5 |
6 | @:dce
7 | @:deprecated('ReactComponentMacro has moved to react.macro package')
8 | class ReactComponentMacro {
9 | @:deprecated('ReactComponentMacro has moved to react.macro package')
10 | static public function appendBuilder(builder:Builder):Void
11 | {
12 | RealReactComponentMacro.appendBuilder(builder);
13 | }
14 |
15 | @:deprecated('ReactComponentMacro has moved to react.macro package')
16 | static public function prependBuilder(builder:Builder):Void
17 | {
18 | RealReactComponentMacro.prependBuilder(builder);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/lib/react/ReactContext.hx:
--------------------------------------------------------------------------------
1 | package react;
2 |
3 | import react.ReactComponent.ReactFragment;
4 | import react.ReactType;
5 |
6 | @:forward
7 | abstract ReactContext(IReactContext) from IReactContext to IReactContext {
8 | @:to
9 | public function toReactType():ReactTypeOf<{children:T->ReactFragment}> {
10 | return cast this;
11 | }
12 | }
13 |
14 | extern interface IReactContext {
15 | var displayName:String;
16 | var Consumer:ReactContext;
17 | var Provider:ReactProviderType;
18 |
19 | var unstable_read:Void->T;
20 | var _calculateChangedBits:NullT->Int>;
21 |
22 | var _currentValue:T;
23 | var _currentValue2:T;
24 |
25 | #if debug
26 | @:optional var _currentRenderer:Null;
27 | @:optional var _currentRenderer2:Null;
28 | #end
29 | }
30 |
31 | @:pure @:coreType
32 | abstract ReactProviderType
33 | from IReactProviderType
34 | to IReactProviderType
35 | to ReactTypeOf<{value:T}> {}
36 |
37 | extern interface IReactProviderType {
38 | var _context:ReactContext;
39 | }
40 |
--------------------------------------------------------------------------------
/src/lib/react/ReactDOM.hx:
--------------------------------------------------------------------------------
1 | package react;
2 |
3 | import js.html.Element;
4 | import react.ReactComponent;
5 |
6 | /**
7 | https://react.dev/reference/react-dom
8 | **/
9 | #if (!react_global)
10 | @:jsRequire("react-dom")
11 | #end
12 | @:native('ReactDOM')
13 | extern class ReactDOM
14 | {
15 | /**
16 | https://react.dev/reference/react-dom/render
17 | **/
18 | @:deprecated("Use ReactDOMClient.createRoot")
19 | public static function render(element:ReactFragment, container:Element, ?callback:Void -> Void):ReactFragment;
20 |
21 | /**
22 | https://react.dev/reference/react-dom/hydrate
23 | **/
24 | @:deprecated("Use ReactDOMClient.hydrateRoot")
25 | public static function hydrate(element:ReactFragment, container:Element, ?callback:Void -> Void):ReactFragment;
26 |
27 | /**
28 | https://react.dev/reference/react-dom/unmountComponentAtNode
29 | **/
30 | @:deprecated("In React 18, unmountComponentAtNode was replaced by root.unmount()")
31 | public static function unmountComponentAtNode(container:Element):Bool;
32 |
33 | /**
34 | https://react.dev/reference/react-dom/findDOMNode
35 | **/
36 | @:deprecated
37 | public static function findDOMNode(component:ReactComponent):Element;
38 |
39 | /**
40 | https://react.dev/reference/react-dom/createPortal
41 | **/
42 | public static function createPortal(child:ReactFragment, container:Element):ReactFragment;
43 |
44 | /**
45 | Warning:
46 | Using flushSync is uncommon and can hurt the performance of your app.
47 |
48 | https://react.dev/reference/react-dom/flushSync
49 | **/
50 | public static function flushSync(callback:Void->Void):Void;
51 | }
52 |
53 | #if (!react_global)
54 | @:jsRequire("react-dom/client")
55 | #end
56 | @:native('ReactDOM')
57 | extern class ReactDOMClient {
58 | /**
59 | `createRoot` lets you create a root to display React components inside a
60 | browser DOM node.
61 |
62 | Notes:
63 | - If your app is server-rendered, using `createRoot()` is not supported.
64 | Use `hydrateRoot()` instead
65 | - You’ll likely have only one `createRoot` call in your app
66 | - When you want to render a piece of JSX in a different part of the DOM
67 | tree that isn’t a child of your component (for example, a modal or a
68 | tooltip), use `ReactDOM.createPortal` instead of `createRoot`
69 |
70 | https://react.dev/reference/react-dom/client/createRoot
71 | **/
72 | public static function createRoot(container:Element, ?options:{
73 | ?identifierPrefix:String,
74 | ?onRecoverableError:(err:Any)->Void
75 | }):RootType;
76 |
77 | /**
78 | `hydrateRoot` lets you display React components inside a browser DOM
79 | node whose HTML content was previously generated by `ReactDOMServer`.
80 |
81 | Notes:
82 | - `hydrateRoot()` expects the rendered content to be identical with the
83 | server-rendered content. You should treat mismatches as bugs and fix
84 | them
85 | - In development mode, React warns about mismatches during hydration.
86 | There are no guarantees that attribute differences will be patched up
87 | in case of mismatches
88 | - You’ll likely have only one `hydrateRoot` call in your app
89 | - If your app is client-rendered with no HTML rendered already, using
90 | `hydrateRoot()` is not supported. Use `createRoot()` instead
91 |
92 |
93 | https://react.dev/reference/react-dom/client/hydrateRoot
94 | **/
95 | public static function hydrateRoot(container:Element, element:ReactFragment, ?options:{
96 | ?identifierPrefix:String,
97 | ?onRecoverableError:(err:Any)->Void
98 | }):RootType;
99 | }
100 |
101 | typedef RootType = {
102 | render:(node:ReactFragment)->Void,
103 | unmount:()->Void
104 | }
105 |
--------------------------------------------------------------------------------
/src/lib/react/ReactDOMServer.hx:
--------------------------------------------------------------------------------
1 | package react;
2 |
3 | import js.html.AbortSignal;
4 | import js.lib.Promise;
5 | import react.ReactComponent.ReactFragment;
6 |
7 | #if nodejs
8 | import js.node.stream.Readable;
9 | import js.node.stream.Writable;
10 | #end
11 |
12 | /**
13 | The `ReactDOMServer` APIs let you render React components to HTML on the
14 | server. These APIs are only used on the server at the top level of your app to
15 | generate the initial HTML. Most of your components don’t need to import or use them.
16 |
17 | https://react.dev/reference/react-dom/server
18 | **/
19 | #if (!react_global)
20 | @:jsRequire('react-dom/server')
21 | #end
22 | @:native('ReactDOMServer')
23 | extern class ReactDOMServer {
24 | /**
25 | Note: `renderToString` does not support streaming or waiting for data.
26 | See the alternatives.
27 |
28 | https://react.dev/reference/react-dom/server/renderToString
29 | **/
30 | public static function renderToString(node:ReactFragment):String;
31 |
32 | /**
33 | `renderToStaticMarkup` renders a non-interactive React tree to an HTML
34 | string.
35 |
36 | Notes:
37 | - `renderToStaticMarkup` output cannot be hydrated.
38 | - `renderToStaticMarkup` has limited `Suspense support`. If a component
39 | suspends, `renderToStaticMarkup` immediately sends its fallback as HTML.
40 |
41 | https://react.dev/reference/react-dom/server/renderToStaticMarkup
42 | **/
43 | public static function renderToStaticMarkup(node:ReactFragment):String;
44 |
45 | #if nodejs
46 | /**
47 | `renderToPipeableStream` renders a React tree to a pipeable Node.js Stream.
48 |
49 | Note: This API is specific to Node.js.
50 | Environments with Web Streams should use `renderToReadableStream` instead.
51 |
52 | https://react.dev/reference/react-dom/server/renderToPipeableStream
53 | **/
54 | public static function renderToPipeableStream(node:ReactFragment, options:{
55 | ?bootstrapScriptContent:String,
56 | ?bootstrapScripts:Array,
57 | ?bootstrapModules:Array,
58 | ?identifierPrefix:String,
59 | ?namespaceURI:String,
60 | ?nonce:String,
61 | ?onAllReady:Void->Void,
62 | ?onError:Any->Void,
63 | ?onShellReady:Void->Void,
64 | ?onShellError:Any->Void,
65 | ?progressiveChunkSize:Int
66 | }):{
67 | pipe:IWritable->Void,
68 | abort:Void->Void
69 | }
70 |
71 | /**
72 | `renderToStaticNodeStream` renders a non-interactive React tree to a
73 | Node.js Readable Stream.
74 |
75 | Notes:
76 | - `renderToStaticNodeStream` output cannot be hydrated.
77 | - This method will wait for all `Suspense` boundaries to complete before
78 | returning any output.
79 | - As of React 18, this method buffers all of its output, so it doesn't
80 | actually provide any streaming benefits.
81 | - The returned stream is a byte stream encoded in utf-8
82 |
83 | https://react.dev/reference/react-dom/server/renderToStaticNodeStream
84 | **/
85 | public static function renderToStaticNodeStream(node:ReactFragment):IReadable;
86 |
87 | /**
88 | https://react.dev/reference/react-dom/server/renderToNodeStream
89 | **/
90 | @:deprecated("Use renderToPipeableStream instead")
91 | public static function renderToNodeStream(node:ReactFragment):IReadable;
92 | #else
93 | /**
94 | `renderToReadableStream` renders a React tree to a Readable Web Stream.
95 |
96 | Note: This API depends on Web Streams.
97 | For Node.js, use `renderToPipeableStream` instead.
98 |
99 | https://react.dev/reference/react-dom/server/renderToReadableStream
100 | **/
101 | public static function renderToReadableStream(node:ReactFragment, options:{
102 | ?bootstrapScriptContent:String,
103 | ?bootstrapScripts:Array,
104 | ?bootstrapModules:Array,
105 | ?identifierPrefix:String,
106 | ?namespaceURI:String,
107 | ?nonce:String,
108 | ?onError:Any->Void,
109 | ?progressiveChunkSize:Int,
110 | ?signal:AbortSignal
111 | }):Promise;
112 | #end
113 | }
114 |
--------------------------------------------------------------------------------
/src/lib/react/ReactEvent.hx:
--------------------------------------------------------------------------------
1 | package react;
2 |
3 | import js.html.Event;
4 | import js.html.EventTarget;
5 |
6 | /**
7 | https://facebook.github.io/react/docs/events.html
8 | **/
9 | extern class ReactEvent
10 | {
11 | public var bubbles(default, null):Bool;
12 | public var cancelable(default, null):Bool;
13 | public var currentTarget(default, null):EventTarget;
14 | public var defaultPrevented(default, null):Bool;
15 | public var eventPhase(default, null):Int;
16 | public var isTrusted(default, null):Bool;
17 | public var nativeEvent(default, null):Event;
18 | public var target(default, null):EventTarget;
19 | public var timeStamp(default, null):Date;
20 | public var type(default, null):String;
21 |
22 | public function preventDefault():Void;
23 | public function isDefaultPrevented():Bool;
24 | public function stopPropagation():Void;
25 | public function isPropagationStopped():Bool;
26 | }
27 |
--------------------------------------------------------------------------------
/src/lib/react/ReactFocusEvent.hx:
--------------------------------------------------------------------------------
1 | package react;
2 |
3 | import js.html.EventTarget;
4 |
5 | /**
6 | https://facebook.github.io/react/docs/events.html
7 | **/
8 | extern class ReactFocusEvent extends ReactEvent
9 | {
10 | public var relatedTarget:EventTarget;
11 | }
12 |
--------------------------------------------------------------------------------
/src/lib/react/ReactKeyboardEvent.hx:
--------------------------------------------------------------------------------
1 | package react;
2 |
3 | /**
4 | https://facebook.github.io/react/docs/events.html
5 | **/
6 | extern class ReactKeyboardEvent extends ReactEvent
7 | {
8 | public var altKey(default, null):Bool;
9 | public var charCode(default, null):Int;
10 | public var ctrlKey(default, null):Bool;
11 | public var key(default, null):String;
12 | public var keyCode(default, null):Int;
13 | public var locale(default, null):String;
14 | public var location(default, null):Int;
15 | public var metaKey(default, null):Bool;
16 | public var repeat(default, null):Bool;
17 | public var shiftKey(default, null):Bool;
18 | public var which(default, null):Int;
19 |
20 | public function getModifierState(key:Int):Bool;
21 | }
22 |
--------------------------------------------------------------------------------
/src/lib/react/ReactMouseEvent.hx:
--------------------------------------------------------------------------------
1 | package react;
2 |
3 | import js.html.EventTarget;
4 |
5 | /**
6 | https://facebook.github.io/react/docs/events.html
7 | **/
8 | extern class ReactMouseEvent extends ReactEvent
9 | {
10 | public var altKey:Bool;
11 | public var button:Int;
12 | public var buttons:Int;
13 | public var clientX:Int;
14 | public var clientY:Int;
15 | public var ctrlKey:Bool;
16 | public var metaKey:Bool;
17 | public var pageX:Int;
18 | public var pageY:Int;
19 | public var relatedTarget:EventTarget;
20 | public var screenX:Int;
21 | public var screenY:Int;
22 | public var shiftKey:Bool;
23 |
24 | public function getModifierState(key:Int):Bool;
25 | }
26 |
--------------------------------------------------------------------------------
/src/lib/react/ReactNode.hx:
--------------------------------------------------------------------------------
1 | package react;
2 |
3 | import react.ReactType;
4 |
5 | #if !react_ignore_reactnode_deprecation @:deprecated #end
6 | typedef ReactNode = ReactType;
7 |
8 | #if !react_ignore_reactnode_deprecation @:deprecated #end
9 | typedef ReactNodeOf = ReactTypeOf;
10 |
--------------------------------------------------------------------------------
/src/lib/react/ReactPropTypes.hx:
--------------------------------------------------------------------------------
1 | package react;
2 |
3 | #if haxe4
4 | import js.lib.Error;
5 | #else
6 | import js.Error;
7 | #end
8 |
9 | import haxe.extern.EitherType;
10 | import react.ReactComponent;
11 |
12 | /**
13 | https://reactjs.org/docs/typechecking-with-proptypes.html
14 | **/
15 | #if (!react_global)
16 | @:jsRequire('prop-types')
17 | #end
18 | @:native('PropTypes')
19 | extern class ReactPropTypes
20 | {
21 | static var any:ChainableTypeChecker;
22 | static var array:ChainableTypeChecker;
23 | static var bool:ChainableTypeChecker;
24 | static var func:ChainableTypeChecker;
25 | static var number:ChainableTypeChecker;
26 | static var object:ChainableTypeChecker;
27 | static var string:ChainableTypeChecker;
28 | static var symbol:ChainableTypeChecker;
29 | static var element:ChainableTypeChecker;
30 | static var node:ChainableTypeChecker;
31 |
32 | static var arrayOf:ArrayOfTypeChecker -> ChainableTypeChecker;
33 | static var instanceOf:Class -> ChainableTypeChecker;
34 | static var objectOf:ArrayOfTypeChecker -> ChainableTypeChecker;
35 | static var oneOf:Array -> ChainableTypeChecker;
36 | static var oneOfType:Array -> ChainableTypeChecker;
37 | static var shape:TypeShape->ChainableTypeChecker;
38 | static var exact:TypeShape->ChainableTypeChecker;
39 |
40 | static function checkPropTypes(
41 | typeSpecs:Dynamic,
42 | values:Dynamic,
43 | location:PropTypesLocation,
44 | componentName:String,
45 | ?getStack:Void -> Dynamic
46 | ):Dynamic;
47 | }
48 |
49 | typedef TypeChecker = EitherType;
50 | typedef ArrayOfTypeChecker = EitherType;
51 | typedef CustomTypeChecker = Dynamic -> String -> String -> Null;
52 | typedef CustomArrayOfTypeChecker = Array -> String -> String -> PropTypesLocation -> String -> Null;
53 | typedef TypeShape = Dynamic;
54 |
55 | enum abstract PropTypesLocation(String) from String {
56 | var Prop = 'prop';
57 | var Context = 'context';
58 | var ChildContext = 'child context';
59 | }
60 |
61 | private typedef ChainableTypeChecker = {
62 | @:optional var isRequired:Dynamic;
63 | }
64 |
--------------------------------------------------------------------------------
/src/lib/react/ReactRef.hx:
--------------------------------------------------------------------------------
1 | package react;
2 |
3 | import haxe.Constraints.Function;
4 |
5 | @:callable
6 | abstract ReactRef(Function) {
7 | public var current(get, never):T;
8 |
9 | public function get_current():T {
10 | return untyped this.current;
11 | }
12 | }
13 |
14 |
--------------------------------------------------------------------------------
/src/lib/react/ReactSharedInternals.hx:
--------------------------------------------------------------------------------
1 | package react;
2 |
3 | import react.ReactComponent.ReactSource;
4 |
5 | extern interface ReactSharedInternals
6 | {
7 | var ReactCurrentOwner:{
8 | current: Null,
9 | currentDispatcher: Null
10 | };
11 |
12 | #if debug
13 | var ReactDebugCurrentFrame:{
14 | getCurrentStack:NullString>,
15 | getStackAddendum:Void->String
16 | };
17 | #end
18 | }
19 |
20 | /**
21 | https://github.com/facebook/react/blob/master/packages/shared/ReactWorkTags.js
22 | **/
23 | enum abstract WorkTag(Int) from Int to Int
24 | {
25 | var FunctionalComponent = 0;
26 | var FunctionalComponentLazy = 1;
27 | var ClassComponent = 2;
28 | var ClassComponentLazy = 3;
29 | var IndeterminateComponent = 4; // Before we know whether it is functional or class
30 | var HostRoot = 5; // Root of a host tree. Could be nested inside another node.
31 | var HostPortal = 6; // A subtree. Could be an entry point to a different renderer.
32 | var HostComponent = 7;
33 | var HostText = 8;
34 | var Fragment = 9;
35 | var Mode = 10;
36 | var ContextConsumer = 11;
37 | var ContextProvider = 12;
38 | var ForwardRef = 13;
39 | var ForwardRefLazy = 14;
40 | var Profiler = 15;
41 | var PlaceholderComponent = 16;
42 | }
43 |
44 | extern interface Instance {
45 | // Tag identifying the type of fiber.
46 | var tag:WorkTag;
47 |
48 | // Unique identifier of this child.
49 | var key:Null;
50 |
51 | // The function/class/module associated with this fiber.
52 | var type:Any;
53 |
54 | // The local state associated with this fiber.
55 | var stateNode:Any;
56 | }
57 |
58 | extern interface ReactFiber extends Instance {
59 |
60 | // The Fiber to return to after finishing processing this one.
61 | // This is effectively the parent, but there can be multiple parents (two)
62 | // so this is only the parent of the thing we're currently processing.
63 | // It is conceptually the same as the return address of a stack frame.
64 | @:native("return")
65 | var _return:Null;
66 |
67 | // Singly Linked List Tree Structure.
68 | var child:Null;
69 | var sibling:Null;
70 | var index:Int;
71 |
72 | // The ref last used to attach this node.
73 | // I'll avoid adding an owner field for prod and model that as functions.
74 | // ref: null | (((handle: mixed) => void) & {_stringRef: ?string}) | RefObject,
75 | var ref:Null;
76 |
77 | // Input is the data coming into process this fiber. Arguments. Props.
78 | var pendingProps:Any; // This type will be more specific once we overload the tag.
79 | var memoizedProps:Any; // The props used to create the output.
80 |
81 | // A queue of state updates and callbacks.
82 | var updateQueue:Null>;
83 |
84 | // The state used to create the output
85 | var memoizedState:Any;
86 |
87 | // A linked-list of contexts that this fiber depends on
88 | var firstContextDependency:Null>;
89 |
90 | // Bitfield that describes properties about the fiber and its subtree. E.g.
91 | // the AsyncMode flag indicates whether the subtree should be async-by-
92 | // default. When a fiber is created, it inherits the mode of its
93 | // parent. Additional flags can be set at creation time, but after that the
94 | // value should remain unchanged throughout the fiber's lifetime, particularly
95 | // before its child fibers are created.
96 | var mode:TypeOfMode;
97 |
98 | // Effect
99 | var effectTag:SideEffectTag;
100 |
101 | // Singly linked list fast path to the next fiber with side-effects.
102 | var nextEffect:Null;
103 |
104 | // The first and last fiber with side-effect within this subtree. This allows
105 | // us to reuse a slice of the linked list when we reuse the work done within
106 | // this fiber.
107 | var firstEffect:Null;
108 | var lastEffect:Null;
109 |
110 | // Represents a time in the future by which this work should be completed.
111 | // Does not include work found in its subtree.
112 | var expirationTime:Float;
113 |
114 | // This is used to quickly determine if a subtree has no pending changes.
115 | var childExpirationTime:Float;
116 |
117 | // This is a pooled version of a Fiber. Every fiber that gets updated will
118 | // eventually have a pair. There are cases when we can clean up pairs to save
119 | // memory if we need to.
120 | var alternate:Null;
121 |
122 | // Time spent rendering this Fiber and its descendants for the current update.
123 | // This tells us how well the tree makes use of sCU for memoization.
124 | // It is reset to 0 each time we render and only updated when we don't bailout.
125 | // This field is only set when the enableProfilerTimer flag is enabled.
126 | @:optional var actualDuration:Float;
127 |
128 | // If the Fiber is currently active in the "render" phase,
129 | // This marks the time at which the work began.
130 | // This field is only set when the enableProfilerTimer flag is enabled.
131 | @:optional var actualStartTime:Float;
132 |
133 | // Duration of the most recent render time for this Fiber.
134 | // This value is not updated when we bailout for memoization purposes.
135 | // This field is only set when the enableProfilerTimer flag is enabled.
136 | @:optional var selfBaseDuration:Float;
137 |
138 | // Sum of base times for all descedents of this Fiber.
139 | // This value bubbles up during the "complete" phase.
140 | // This field is only set when the enableProfilerTimer flag is enabled.
141 | @:optional var treeBaseDuration:Float;
142 |
143 | #if debug
144 | @:optional var debugID:Float;
145 | @:optional var debugSource:Null;
146 | @:optional var debugOwner:Null;
147 | @:optional var debugIsCurrentlyTiming:Bool;
148 | #end
149 | }
150 |
151 | extern interface Update
152 | {
153 | var expirationTime:Float;
154 |
155 | var tag:UpdateTag;
156 | var payload:Any;
157 | var callback:NullDynamic>;
158 |
159 | var next:Null>;
160 | var nextEffect:Null>;
161 | }
162 |
163 | extern interface UpdateQueue
164 | {
165 | var baseState:State;
166 |
167 | var firstUpdate:Null>;
168 | var lastUpdate:Null>;
169 |
170 | var firstCapturedUpdate:Null>;
171 | var lastCapturedUpdate:Null>;
172 |
173 | var firstEffect:Null>;
174 | var lastEffect:Null>;
175 |
176 | var firstCapturedEffect:Null>;
177 | var lastCapturedEffect:Null>;
178 | }
179 |
180 | enum abstract UpdateTag(Int) from Int to Int
181 | {
182 | var UpdateState = 0;
183 | var ReplaceState = 1;
184 | var ForceUpdate = 2;
185 | var CaptureUpdate = 3;
186 | }
187 |
188 | enum abstract TypeOfMode(Int) from Int to Int
189 | {
190 | var NoContext = 0;
191 | var AsyncMode = 1;
192 | var StrictMode = 2;
193 | var ProfileMode = 3;
194 | }
195 |
196 | enum abstract SideEffectTag(Int) from Int to Int
197 | {
198 | var NoEffect = 0;
199 | var PerformedWork = 1;
200 |
201 | var Placement = 2;
202 | var Update = 4;
203 | var PlacementAndUpdate = Placement & Update;
204 | var Deletion = 8;
205 | var ContentReset = 16;
206 | var Callback = 32;
207 | var DidCapture = 64;
208 | var Ref = 128;
209 | var Snapshot = 256;
210 | var LifecycleEffectMask = Update & Callback & Ref & Snapshot;
211 |
212 | // Union of all host effects
213 | var HostEffectMask = 511;
214 |
215 | var Incomplete = 512;
216 | var ShouldCapture = 1024;
217 | }
218 |
219 | extern interface ContextDependency
220 | {
221 | var context:ReactContext;
222 | var observedBits:Int;
223 | var next:Null>;
224 | }
225 |
226 | typedef ReactDispatcher = {
227 | var readContext:haxe.Constraints.Function;
228 | }
229 |
--------------------------------------------------------------------------------
/src/lib/react/ReactTestUtils.hx:
--------------------------------------------------------------------------------
1 | package react;
2 |
3 | import react.ReactComponent;
4 |
5 | /**
6 | https://reactjs.org/docs/test-utils.html
7 | **/
8 | @:jsRequire("react-dom/test-utils")
9 | extern class ReactTestUtils {
10 | /**
11 | To prepare a component for assertions, wrap the code rendering it and
12 | performing updates inside an act() call. This makes your test run closer
13 | to how React works in the browser.
14 |
15 | https://reactjs.org/docs/test-utils.html#act
16 | **/
17 | public static function act(task:Void->Void):Void;
18 |
19 | /**
20 | Returns true if element is any React element.
21 |
22 | https://reactjs.org/docs/test-utils.html#iselement
23 | **/
24 | public static function isElement(element:ReactFragment):Bool;
25 |
26 | /**
27 | Returns true if element is a React element whose type is of a React
28 | componentClass.
29 |
30 | https://reactjs.org/docs/test-utils.html#iselementoftype
31 | **/
32 | public static function isElementOfType(
33 | element:ReactFragment,
34 | componentClass:ReactType
35 | ):Bool;
36 |
37 | /**
38 | Returns true if instance is a DOM component (such as a