├── .githooks
└── pre-push
├── .github
├── FUNDING.yml
└── workflows
│ └── ci.yml
├── .gitignore
├── .ocamlformat
├── CHANGES.md
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── README.md
├── docs
├── .nojekyll
├── _sidebar.md
├── all_snippets.ml
├── api.html
├── children.md
├── composite_components.md
├── context.md
├── custom_elements.md
├── dune
├── dune_jsoo.md
├── first_components.md
├── gen_js_api.md
├── hooks.md
├── host_components.md
├── index.html
├── lists_and_keys.md
├── new_to_ocaml.md
├── quickstart.md
├── readme.md
├── refs.md
├── snippets
│ └── basic.ml
└── use_js_components.md
├── dune-project
├── example
├── package.json
├── src
│ ├── App.re
│ ├── Bindings.rei
│ ├── Click.re
│ ├── Code.re
│ ├── EffectsAndState.re
│ ├── Events.re
│ ├── HelloWorldOCaml.ml
│ ├── HelloWorldReason.re
│ ├── Interface.re
│ ├── Interface.rei
│ ├── Main.re
│ ├── Refs.re
│ ├── UseEffect.re
│ ├── WebComponent.ml
│ ├── dune
│ ├── index.html
│ ├── static-requires.js
│ └── static
│ │ ├── leafy.js
│ │ ├── primitive.css
│ │ ├── prism.css
│ │ └── prism.js
├── webpack.config.js
└── yarn.lock
├── interop.md
├── jsoo-react.opam
├── lib
├── core.mli
├── dom.mli
├── dom_aria_attributes.ml
├── dom_aria_attributes.mli
├── dom_dsl_core.ml
├── dom_dsl_core.mli
├── dom_html.ml
├── dom_html.mli
├── dom_svg.ml
├── dom_svg.mli
├── dune
├── event.ml
├── event.mli
├── hooks.ml
├── hooks.mli
├── imports.ml
├── react.ml
├── router.ml
├── router.mli
└── test_utils
│ ├── ReactDOMTestUtils.js
│ ├── dune
│ └── reactDOMTestUtils.mli
├── ppx
├── dune
├── html.ml
├── html.mli
├── ppx.ml
└── test
│ ├── .ocamlformat-ignore
│ ├── dune
│ ├── input_errors_01_external_component_multi_prim.ml
│ ├── input_errors_02_external_component_unlabelled_arg.ml
│ ├── input_ocaml.ml
│ ├── input_reason.re
│ ├── main.ml
│ ├── pp_errors_01_external_component_multi_prim.expected
│ ├── pp_errors_02_external_component_unlabelled_arg.expected
│ ├── pp_ocaml.expected
│ ├── pp_ocaml_dev.expected
│ └── pp_reason.expected
├── rfcs
├── 0000-template.md
└── 0001-ocaml-syntax.md
└── test
├── dune
├── external.js
├── jsdom.js
├── jsdom.mli
├── package.json
├── react-requires.js
├── test_jsoo_react.ml
├── test_ml.ml
├── test_reason.re
└── yarn.lock
/.githooks/pre-push:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | if ! ( make format-check ); then
4 | echo "some files are not properly formatted, refusing to push"
5 | exit 1
6 | fi
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: jchavarri
4 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | pull_request:
5 | push:
6 | schedule:
7 | # Prime the caches every Monday
8 | - cron: 0 1 * * MON
9 |
10 | jobs:
11 | build:
12 | name: Build and test
13 |
14 | runs-on: ${{ matrix.os }}
15 |
16 | strategy:
17 | fail-fast: false
18 | matrix:
19 | os:
20 | - macos-latest
21 | - ubuntu-latest
22 | - windows-latest
23 | ocaml-compiler:
24 | - 4.12.1
25 |
26 | steps:
27 | - name: Checkout code
28 | uses: actions/checkout@v2
29 |
30 | - name: Use OCaml ${{ matrix.ocaml-compiler }}
31 | uses: ocaml/setup-ocaml@v2
32 | with:
33 | ocaml-compiler: ${{ matrix.ocaml-compiler }}
34 | dune-cache: ${{ matrix.os != 'windows-latest' }}
35 |
36 | - name: Use Node 12
37 | uses: actions/setup-node@v1
38 | with:
39 | node-version: 12
40 |
41 | - name: Install dependencies
42 | run: |
43 | opam install . --deps-only --with-doc --with-test
44 | opam install ocamlformat.0.21.0
45 |
46 | - name: Build
47 | run: make build
48 |
49 | - name: Check formatting
50 | run: make format-check
51 |
52 | - name: "Install npm packages for tests"
53 | run: yarn install
54 | working-directory: test
55 |
56 | - name: Run tests
57 | run: make test
58 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.gitignore.io/api/node
3 |
4 | ### OS ###
5 | .DS_Store
6 |
7 | ### Node ###
8 | # Logs
9 | logs
10 | *.log
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 |
15 | # Runtime data
16 | pids
17 | *.pid
18 | *.seed
19 | *.pid.lock
20 |
21 | # Directory for instrumented libs generated by jscoverage/JSCover
22 | lib-cov
23 |
24 | # Coverage directory used by tools like istanbul
25 | coverage
26 |
27 | # nyc test coverage
28 | .nyc_output
29 |
30 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
31 | .grunt
32 |
33 | # Bower dependency directory (https://bower.io/)
34 | bower_components
35 |
36 | # node-waf configuration
37 | .lock-wscript
38 |
39 | # Compiled binary addons (http://nodejs.org/api/addons.html)
40 | build/Release
41 |
42 | # Dependency directories
43 | node_modules/
44 | jspm_packages/
45 |
46 | # Typescript v1 declaration files
47 | typings/
48 |
49 | # Optional npm cache directory
50 | .npm
51 |
52 | # Optional eslint cache
53 | .eslintcache
54 |
55 | # Optional REPL history
56 | .node_repl_history
57 |
58 | # Output of 'npm pack'
59 | *.tgz
60 |
61 | # Yarn Integrity file
62 | .yarn-integrity
63 |
64 | # dotenv environment variables file
65 | .env
66 |
67 |
68 | # End of https://www.gitignore.io/api/node
69 |
70 | *.annot
71 | *.cmo
72 | *.cma
73 | *.cmi
74 | *.a
75 | *.o
76 | *.cmx
77 | *.cmxs
78 | *.cmxa
79 |
80 | # ocamlbuild working directory
81 | _build/
82 |
83 | # ocamlbuild targets
84 | *.byte
85 | *.native
86 |
87 | # oasis generated files
88 | setup.data
89 | setup.log
90 |
91 | # Merlin configuring file for Vim and Emacs
92 | .merlin
93 |
94 | # Dune generated files
95 | *.install
96 |
97 | # Local OPAM switch
98 | _opam/
99 |
100 | # Example output folder
101 | build
102 |
--------------------------------------------------------------------------------
/.ocamlformat:
--------------------------------------------------------------------------------
1 | profile = default
2 | break-separators = before
3 | dock-collection-brackets = false
4 | exp-grouping = preserve
5 | type-decl = sparse
6 | break-fun-decl = fit-or-vertical
7 | break-fun-sig = fit-or-vertical
8 |
--------------------------------------------------------------------------------
/CHANGES.md:
--------------------------------------------------------------------------------
1 | ## 0.1 (2023-04-06)
2 |
3 | ### What's Changed
4 | * Add fragments and remove jsxv2 code from ppx by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/9
5 | * Refs + fix for keys by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/11
6 | * Bindings to useEffect Hook by @schinns in https://github.com/ml-in-barcelona/jsoo-react/pull/10
7 | * Use pipe first for more ergonomic Lwt.bind calls by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/16
8 | * Consolidate option libs and return unmount effects by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/17
9 | * Fix forwardRef unsafety + make DOM refs types more idiomatic by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/19
10 | * Eslint Config by @schinns in https://github.com/ml-in-barcelona/jsoo-react/pull/20
11 | * Fix deep elements () tests by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/21
12 | * Use metaquot by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/22
13 | * Fix example by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/24
14 | * Upgrade to OCaml 4.08 + new bindings approach + gen_js_api by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/25
15 | * Fix displayName so components names show properly in React devtools. by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/26
16 | * Add example of autogenerated `code` element reading from file with ppx-blob by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/27
17 | * changed dune lib name to jsoo_react_ppx by @idkjs in https://github.com/ml-in-barcelona/jsoo-react/pull/29
18 | * Add more examples, add ReactEvent and domProps bindings by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/30
19 | * fix example cd path by @naartjie in https://github.com/ml-in-barcelona/jsoo-react/pull/31
20 | * Bump acorn from 6.3.0 to 6.4.1 in /example by @dependabot in https://github.com/ml-in-barcelona/jsoo-react/pull/33
21 | * Fix build for dune 2, esy 0.6 and lwt 5 by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/35
22 | * OCaml 4.10 + more by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/40
23 | * Add ReactTestUtils, jsdom bindings, some initial tests for the bindings by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/41
24 | * readme: minor fixes by @zindel in https://github.com/ml-in-barcelona/jsoo-react/pull/42
25 | * Add memo and memoCustomCompareProps by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/44
26 | * dune: remove `(wrapped false)` by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/45
27 | * Allow consumers to decide how React is provided by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/48
28 | * add ci by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/49
29 | * Bump ini from 1.3.5 to 1.3.7 in /example by @dependabot in https://github.com/ml-in-barcelona/jsoo-react/pull/50
30 | * Bump elliptic from 6.5.3 to 6.5.4 in /example by @dependabot in https://github.com/ml-in-barcelona/jsoo-react/pull/53
31 | * Specify minimum on gen-js-api 1.0.7 by @davesnx in https://github.com/ml-in-barcelona/jsoo-react/pull/55
32 | * Switch to ppxlib by @keremc in https://github.com/ml-in-barcelona/jsoo-react/pull/64
33 | * CI: Update setup-ocaml to v2 by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/68
34 | * Add pre-push hook to check formatting by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/70
35 | * Inline props as object by @davesnx in https://github.com/ml-in-barcelona/jsoo-react/pull/66
36 | * refactor: Rename createMarkup to makeInnerHtml by @davesnx in https://github.com/ml-in-barcelona/jsoo-react/pull/74
37 | * Add 'help' command in Make by @davesnx in https://github.com/ml-in-barcelona/jsoo-react/pull/73
38 | * Better support for OCaml syntax by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/72
39 | * RFC: Better support for OCaml syntax by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/67
40 | * Type-safe HTML and SVG tags by @davesnx in https://github.com/ml-in-barcelona/jsoo-react/pull/71
41 | * fix: Ensure optionals are passed as undefineds by @davesnx in https://github.com/ml-in-barcelona/jsoo-react/pull/84
42 | * Create a test case for capturing error messages at build(ppx)-time by @davesnx in https://github.com/ml-in-barcelona/jsoo-react/pull/87
43 | * replace {dev} with :with-test by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/80
44 | * Remove filtering of optional props in make_js_props_obj by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/89
45 | * Update README.md by @davesnx in https://github.com/ml-in-barcelona/jsoo-react/pull/97
46 | * refactor: require `react`, `react-dom` within OCaml by @zbaylin in https://github.com/ml-in-barcelona/jsoo-react/pull/96
47 | * Keep useReducer dispatch and useState updater refs constant by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/101
48 | * Allow `string option` transformations for native elements by @davesnx in https://github.com/ml-in-barcelona/jsoo-react/pull/92
49 | * chore(deps): open jsoo constraint to 3.11.0 by @zbaylin in https://github.com/ml-in-barcelona/jsoo-react/pull/103
50 | * fix build & test instructions in CONTRIBUTING by @glennsl in https://github.com/ml-in-barcelona/jsoo-react/pull/107
51 | * Unify tests by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/108
52 | * Remove React.list by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/102
53 | * ppx: fix inexistent locations on comps that return element list by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/110
54 | * style: use functions as style key creation mechanism by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/116
55 | * chore(deps): bump follow-redirects from 1.14.5 to 1.14.7 in /example by @dependabot in https://github.com/ml-in-barcelona/jsoo-react/pull/114
56 | * Bindings to external JS components by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/106
57 | * fix: Add location on errors for invalid key/ref usage on props by @davesnx in https://github.com/ml-in-barcelona/jsoo-react/pull/118
58 | * ppx: don't assume external components are functions by @glennsl in https://github.com/ml-in-barcelona/jsoo-react/pull/124
59 | * ppx: fix external optional args by @glennsl in https://github.com/ml-in-barcelona/jsoo-react/pull/126
60 | * PPX-less API for creating DOM elements and props. by @glennsl in https://github.com/ml-in-barcelona/jsoo-react/pull/119
61 | * Wrong component type signature when using type annotation #85 by @davesnx in https://github.com/ml-in-barcelona/jsoo-react/pull/117
62 | * PoC: automatic js ffi conversion of external props by @glennsl in https://github.com/ml-in-barcelona/jsoo-react/pull/127
63 | * add Webcomponent example by @glennsl in https://github.com/ml-in-barcelona/jsoo-react/pull/129
64 | * ppx: Remove @@@react.dom + transform lowercase elements to Dsl functions by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/128
65 | * fix(ppx): Ensure we pass rec_flag on value_binding by @davesnx in https://github.com/ml-in-barcelona/jsoo-react/pull/133
66 | * Help Merlin find ast nodes inside let%component by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/134
67 | * ppx: fix bug on externals by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/135
68 | * Convert API to snake case by @glennsl in https://github.com/ml-in-barcelona/jsoo-react/pull/138
69 | * build(deps): bump follow-redirects from 1.14.7 to 1.14.8 in /example by @dependabot in https://github.com/ml-in-barcelona/jsoo-react/pull/140
70 | * Docs: experiment with docsify by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/139
71 | * Add ARIA 1.1 into global-attributes by @davesnx in https://github.com/ml-in-barcelona/jsoo-react/pull/145
72 | * Add global_attributes into both html and svg Props. by @davesnx in https://github.com/ml-in-barcelona/jsoo-react/pull/144
73 | * build(deps): bump url-parse from 1.5.3 to 1.5.7 in /example by @dependabot in https://github.com/ml-in-barcelona/jsoo-react/pull/148
74 | * Experiment: more ergonomic/idiomatic API by @glennsl in https://github.com/ml-in-barcelona/jsoo-react/pull/141
75 | * chore: bump js_of_ocaml to 4.0.0 by @glennsl in https://github.com/ml-in-barcelona/jsoo-react/pull/150
76 | * build(deps): bump url-parse from 1.5.7 to 1.5.10 in /example by @dependabot in https://github.com/ml-in-barcelona/jsoo-react/pull/152
77 | * consistent project-wide formatting by @glennsl in https://github.com/ml-in-barcelona/jsoo-react/pull/155
78 | * ci: try to fix win by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/159
79 | * dsl: fix react runtime warning when using maybe with None by @glennsl in https://github.com/ml-in-barcelona/jsoo-react/pull/156
80 | * allow locally abstract type and type constraint on component definitions by @glennsl in https://github.com/ml-in-barcelona/jsoo-react/pull/151
81 | * dsl: add classNames helper to Html and Svg props by @glennsl in https://github.com/ml-in-barcelona/jsoo-react/pull/157
82 | * dom: add create_portal by @glennsl in https://github.com/ml-in-barcelona/jsoo-react/pull/158
83 | * dsl: expose ARIA attributes by @glennsl in https://github.com/ml-in-barcelona/jsoo-react/pull/160
84 | * Update ppxlib 0.26 ocamlformat 0.21 by @jchavarri in https://github.com/ml-in-barcelona/jsoo-react/pull/163
85 | * Relax upper bounds to allow OCaml 4.14 and dune 3 by @sim642 in https://github.com/ml-in-barcelona/jsoo-react/pull/162
86 | * build(deps): bump minimist from 1.2.5 to 1.2.6 in /example by @dependabot in https://github.com/ml-in-barcelona/jsoo-react/pull/161
87 | * Hooks using OCaml idioms and equality semantics by @glennsl in https://github.com/ml-in-barcelona/jsoo-react/pull/154
88 | * ppx: set display name on let%component by @glennsl in https://github.com/ml-in-barcelona/jsoo-react/pull/166
89 | * A few ergonomic additions for dealing with conditional rendering by @glennsl in https://github.com/ml-in-barcelona/jsoo-react/pull/165
90 | * dom: add missing svg props by @glennsl in https://github.com/ml-in-barcelona/jsoo-react/pull/164
91 | * build(deps): bump async from 2.6.3 to 2.6.4 in /example by @dependabot in https://github.com/ml-in-barcelona/jsoo-react/pull/168
92 | * chore(deps): relax `gen_js_api` constraint to allow ^1.1.0 by @zbaylin in https://github.com/ml-in-barcelona/jsoo-react/pull/167
93 | * Add bindings to StrictMode by @schinns in https://github.com/ml-in-barcelona/jsoo-react/pull/169
94 | * build(deps): bump decode-uri-component from 0.2.0 to 0.2.2 in /example by @dependabot in https://github.com/ml-in-barcelona/jsoo-react/pull/172
95 | * OPAM: upgrade Js_of_ocaml to 5.1.0 by @zbaylin in https://github.com/ml-in-barcelona/jsoo-react/pull/177
96 | * Prefix Option and Array with Stdlib by @davesnx in https://github.com/ml-in-barcelona/jsoo-react/pull/178
97 |
98 | ### New Contributors
99 | * @jchavarri made their first contribution in https://github.com/ml-in-barcelona/jsoo-react/pull/9
100 | * @schinns made their first contribution in https://github.com/ml-in-barcelona/jsoo-react/pull/10
101 | * @idkjs made their first contribution in https://github.com/ml-in-barcelona/jsoo-react/pull/29
102 | * @naartjie made their first contribution in https://github.com/ml-in-barcelona/jsoo-react/pull/31
103 | * @dependabot made their first contribution in https://github.com/ml-in-barcelona/jsoo-react/pull/33
104 | * @zindel made their first contribution in https://github.com/ml-in-barcelona/jsoo-react/pull/42
105 | * @davesnx made their first contribution in https://github.com/ml-in-barcelona/jsoo-react/pull/55
106 | * @keremc made their first contribution in https://github.com/ml-in-barcelona/jsoo-react/pull/64
107 | * @zbaylin made their first contribution in https://github.com/ml-in-barcelona/jsoo-react/pull/96
108 | * @glennsl made their first contribution in https://github.com/ml-in-barcelona/jsoo-react/pull/107
109 | * @sim642 made their first contribution in https://github.com/ml-in-barcelona/jsoo-react/pull/162
110 |
111 | **Full Changelog**: https://github.com/ml-in-barcelona/jsoo-react/commits/0.1
112 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | ## Getting started
4 |
5 | - Install opam: https://opam.ocaml.org/doc/Install.html
6 | - Create local switch by running `make init` (this step will take a few minutes, as it will build whole OCaml compiler)
7 | - Build with `make build`
8 | - Run tests with
9 | - Install test dependencies with `(cd test; yarn)`
10 | - `make test`
11 |
12 | It is recommended to run `git config --local core.hooksPath .githooks/` to make sure git hooks run,
13 | otherwise you could get CI errors due to formatting.
14 |
15 | ## Ideas / decisions
16 |
17 | - Abstract over Js_of_ocaml "native" types (`js_string `, `js_array`) as much as
18 | possible behind the bindings. To do so, the library uses [`gen_js_api`](https://github.com/LexiFi/gen_js_api)
19 | to convert from/to these types to their more idiomatic OCaml representation.
20 | - Keep the API as close as possible to ReasonReact. This is useful for many reasons:
21 | - Battle tested.
22 | - Reduce cognitive load by leveraging ReasonReact knowledge.
23 | - Maximize potential reuse of existing components and libraries.
24 |
25 | ## Bindings
26 |
27 | See [`interop.md`](interop.md).
28 |
29 | ## Running the example
30 |
31 | ```bash
32 | git clone https://github.com/ml-in-barcelona/jsoo-react/
33 | cd ./jsoo-react
34 | make init
35 | eval $(opam env)
36 | make dev
37 | # in another tab / terminal session
38 | cd ./jsoo-react/example
39 | yarn && yarn server
40 | ```
41 |
42 | After that, open up `localhost:8000`. Then modify `App.re` file in `src` and refresh the page to see the changes. The example
43 | will not work without server as it relies on history / client-side routing using `jsoo-react` router to navigate through the pages.
44 |
45 | ### Ppx
46 |
47 | - `make test` to run the test against the expected result.
48 | - `make test-promote` when you want to update the expected results.
49 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Javier Chávarri
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | project_name = jsoo-react
2 |
3 | DUNE = opam exec -- dune
4 | opam_file = $(project_name).opam
5 | current_hash = $(shell git rev-parse HEAD)
6 |
7 | .PHONY: build build-prod dev test test-promote deps format format-check init publish-example
8 |
9 | .PHONY: help
10 | help: ## Print this help message
11 | @echo "List of available make commands";
12 | @echo "";
13 | @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-15s\033[0m %s\n", $$1, $$2}';
14 | @echo "";
15 |
16 | build: ## Build the project, including non installable libraries and executables
17 | $(DUNE) build @@default
18 |
19 | build-prod: ## Build for production (--profile=prod)
20 | $(DUNE) build --profile=prod @@default
21 |
22 | dev: ## Build in watch mode
23 | $(DUNE) build -w @@default
24 |
25 | test: ## Run the unit tests
26 | $(DUNE) build @runtest
27 |
28 | test-watch: ## Run the unit tests in watch mode
29 | $(DUNE) build @runtest -w
30 |
31 | test-promote: ## Updates snapshots and promotes it to correct
32 | $(DUNE) build @runtest --auto-promote
33 |
34 | deps: $(opam_file) ## Alias to update the opam file and install the needed deps
35 |
36 | format: ## Format the codebase with ocamlformat
37 | $(DUNE) build @fmt --auto-promote
38 |
39 | format-check: ## Checks if format is correct
40 | $(DUNE) build @fmt
41 |
42 | publish-example: ## Publish example/ to gh-pages
43 | git checkout main && $(DUNE) build --profile=prod @@default && cd example && yarn webpack:production \
44 | && cd - && git checkout gh-pages && cp example/build/* . && git commit -am "$(current_hash)"
45 |
46 | $(opam_file): dune-project ## Update the package dependencies when new deps are added to dune-project
47 | $(DUNE) build @install
48 | opam install . --deps-only --with-test # Install the new dependencies
49 |
50 | init: ## Create a local opam switch and setups githooks
51 | git config core.hooksPath .githooks
52 | opam switch create . 4.12.1 --deps-only --with-test
53 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # jsoo-react
2 |
3 | [](https://github.com/ml-in-barcelona/jsoo-react/actions?query=branch%3Amain)
4 |
5 | Bindings to [React](https://reactjs.org/) for [js_of_ocaml](https://ocsigen.org/js_of_ocaml/), including the JSX ppx.
6 |
7 | > **Status**: experimental phase
8 | >
9 | > The library is expected to break backwards compatibility on minor releases.
10 |
11 | Adapted from [ReasonReact](https://github.com/reasonml/reason-react/).
12 |
13 | Bug reports and contributions are welcome!
14 |
15 | ## Getting started
16 |
17 | ### New project
18 |
19 | For new projects, the best way to start is by using [the jsoo-react template](https://github.com/ml-in-barcelona/jsoo-react-template).
20 |
21 | ### Existing project
22 |
23 | 1. Install the `jsoo-react` package:
24 |
25 | ```bash
26 | opam install jsoo-react
27 | ```
28 |
29 | 2. Add `jsoo-react` library and ppx to [dune](https://dune.readthedocs.io/en/stable/) file of your executable JavaScript app:
30 |
31 | ```dune
32 | (executables
33 | (names index)
34 | (modes js)
35 | (libraries jsoo-react.lib)
36 | (preprocess
37 | (pps jsoo-react.ppx)))
38 | ```
39 |
40 | 3. Provision React.js library
41 |
42 | `jsoo-react` uses `require` to import React and ReactDOM. This means that you will likely need to use a bundler such as Webpack or rollup.js.
43 |
44 | Note that at this moment, `jsoo-react` is compatible with **React 16**, so be sure to have the appropriate constraints in your `package.json`.
45 |
46 | ## Contributing
47 |
48 | Take a look at our [Contributing Guide](CONTRIBUTING.md).
49 |
50 | ## Acknowledgements
51 |
52 | Thanks to the authors and maintainers of ReasonReact, in particular [@rickyvetter](https://github.com/rickyvetter) for his work on the v3 of the JSX ppx.
53 |
54 | Thanks to the authors and maintainers of Js_of_ocaml, in particular [@hhugo](https://github.com/hhugo) who has been answering many many questions in GitHub threads.
55 |
56 | Thanks to the Lexifi team for creating and maintaining [gen_js_api](https://github.com/LexiFi/gen_js_api).
57 |
58 | Thanks to [@tmattio](https://github.com/tmattio/) for creating Spin and the jsoo-react template :raised_hands:
59 |
60 | And thanks to the team behind React.js! What an amazing library :)
61 |
--------------------------------------------------------------------------------
/docs/.nojekyll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ml-in-barcelona/jsoo-react/308aceb57bac5f06e761af3f6e5dee39cc059213/docs/.nojekyll
--------------------------------------------------------------------------------
/docs/_sidebar.md:
--------------------------------------------------------------------------------
1 | - Introduction
2 |
3 | - [New to OCaml?](new_to_ocaml.md)
4 | - [Quick start](quickstart.md)
5 | - [Your first components](first_components.md)
6 |
7 | - Main concepts
8 |
9 | - [Host (lowercase) components](host_components.md)
10 | - [Composite (uppercase) components](composite_components.md)
11 | - [Children](children.md)
12 | - [Hooks](hooks.md)
13 | - [Refs](refs.md)
14 | - [Lists and keys](lists_and_keys.md)
15 |
16 | - Guides
17 |
18 | - [Context](context.md)
19 | - [Custom elements and data-* attributes](custom_elements.md)
20 | - [Building with Dune and Js_of_ocaml](dune_jsoo.md)
21 | - [Gen_js_api](gen_js_api.md)
22 | - [Use JavaScript components](use_js_components.md)
23 |
24 | - [API](api.html)
25 |
--------------------------------------------------------------------------------
/docs/all_snippets.ml:
--------------------------------------------------------------------------------
1 | include Basic
2 |
--------------------------------------------------------------------------------
/docs/children.md:
--------------------------------------------------------------------------------
1 | # Children
2 |
3 | todo
4 |
--------------------------------------------------------------------------------
/docs/composite_components.md:
--------------------------------------------------------------------------------
1 | # Composite (uppercase) components
2 |
3 | todo
4 |
--------------------------------------------------------------------------------
/docs/context.md:
--------------------------------------------------------------------------------
1 | # Context
2 |
3 | todo
4 |
--------------------------------------------------------------------------------
/docs/custom_elements.md:
--------------------------------------------------------------------------------
1 | # Custom elements
2 |
3 | todo
4 |
--------------------------------------------------------------------------------
/docs/dune:
--------------------------------------------------------------------------------
1 | (include_subdirs unqualified)
2 |
3 | (executables
4 | (names All_snippets)
5 | (modes js)
6 | (libraries js_of_ocaml react)
7 | (preprocess
8 | (pps jsoo_react_ppx)))
9 |
10 | (rule
11 | (alias runtest)
12 | (deps All_snippets.bc.js)
13 | (action
14 | (run echo "docs")))
15 |
--------------------------------------------------------------------------------
/docs/dune_jsoo.md:
--------------------------------------------------------------------------------
1 | # Building with Dune and Js_of_ocaml
2 |
3 | todo
4 |
--------------------------------------------------------------------------------
/docs/first_components.md:
--------------------------------------------------------------------------------
1 | # Your first components
2 |
3 | ## A simple component
4 |
5 | Jsoo-react components are functions that take input data and returns what to display. The library provides a DSL that allows to create elements like `div`, or `p` with just plain OCaml functions. The uppercase component props are passed as labelled arguments, while lowercase components take an array of attributes.
6 |
7 | [filename](snippets/basic.ml ':include :type=code :fragment=demo')
8 |
--------------------------------------------------------------------------------
/docs/gen_js_api.md:
--------------------------------------------------------------------------------
1 | # Gen_js_api
2 |
3 | todo
4 |
--------------------------------------------------------------------------------
/docs/hooks.md:
--------------------------------------------------------------------------------
1 | # Hooks
2 |
3 | todo
4 |
--------------------------------------------------------------------------------
/docs/host_components.md:
--------------------------------------------------------------------------------
1 | # Host (lowercase) components
2 |
3 | todo
4 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Document
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
32 |
33 |
34 |
35 |
36 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/docs/lists_and_keys.md:
--------------------------------------------------------------------------------
1 | # Lists and keys
2 |
3 | todo
4 |
--------------------------------------------------------------------------------
/docs/new_to_ocaml.md:
--------------------------------------------------------------------------------
1 | # New to OCaml?
2 |
3 | todo
4 |
--------------------------------------------------------------------------------
/docs/quickstart.md:
--------------------------------------------------------------------------------
1 | # Quick start
2 |
3 | ## New project
4 |
5 | For new projects, the best way to start is by cloning [the jsoo-react template](https://github.com/ml-in-barcelona/jsoo-react-template).
6 |
7 | ## Existing project
8 |
9 | 1. Install the `jsoo-react` package:
10 |
11 | ```bash
12 | opam pin add -y jsoo-react https://github.com/ml-in-barcelona/jsoo-react.git
13 | ```
14 |
15 | 2. Add `jsoo-react` library and ppx to [dune](https://dune.readthedocs.io/en/stable/) file of your executable JavaScript app:
16 |
17 | ```dune
18 | (executables
19 | (names index)
20 | (modes js)
21 | (libraries jsoo-react.lib)
22 | (preprocess
23 | (pps jsoo-react.ppx)))
24 | ```
25 |
26 | 3. Provision React.js library
27 |
28 | `jsoo-react` uses `require` to import React and ReactDOM. This means that you will likely need to use a bundler such as Webpack or rollup.js.
29 |
30 | Note that at this moment, `jsoo-react` is compatible with **React 16.x**, so be sure to have the appropriate constraints in your `package.json`.
31 |
32 |
--------------------------------------------------------------------------------
/docs/readme.md:
--------------------------------------------------------------------------------
1 | # jsoo-react
2 |
3 | > React.js in OCaml.
4 |
5 | ## What it is
6 |
7 | Jsoo-react are the bindings to [React.js](reactjs.org/) for the [OCaml](https://ocaml.org/) language, in particular, for [Js_of_ocaml](https://ocsigen.org/js_of_ocaml/latest/manual/overview), a compiler that transforms OCaml bytecode into JavaScript.
8 |
9 | Jsoo-react allows to write components in a way that is familiar for both OCaml and JavaScript developers.
10 |
11 | See the [Quick start](quickstart.md) guide for more details.
12 |
13 | ## Features
14 |
15 | - Support for both Reason syntax and OCaml syntax
16 | - Integrated with Js_of_ocaml and the OCaml ecosystem
17 | - Optimized output, small footprint on JavaScript bundles
18 | - Heavily tested
19 |
20 | ## Examples
21 |
22 | Check out the [Real World Example App](https://github.com/jchavarri/jsoo-react-realworld-example-app) to see Jsoo-react in use.
23 |
24 | ## Community
25 |
26 | Users and the development team usually hang out in the [Reason](https://discord.gg/reasonml) and [OCaml](https://discord.gg/cCYQbqN) Discord servers. If you have specific questions, don't hesitate to start a [discussion on the GitHub repo](https://github.com/ml-in-barcelona/jsoo-react/discussions).
27 |
--------------------------------------------------------------------------------
/docs/refs.md:
--------------------------------------------------------------------------------
1 | # Refs
2 |
3 | todo
4 |
--------------------------------------------------------------------------------
/docs/snippets/basic.ml:
--------------------------------------------------------------------------------
1 | (* [demo] *)
2 | open React.Dom.Dsl
3 | open Html
4 |
5 | module Hello_message = struct
6 | let%component make ~name = div [||] [ React.string ("Hello " ^ name) ]
7 | end
8 |
9 | let () =
10 | React.Dom.render_to_element ~id:"hello-example"
11 | (Hello_message.make ~name:"Taylor" ())
12 | (* [demo] *)
13 |
--------------------------------------------------------------------------------
/docs/use_js_components.md:
--------------------------------------------------------------------------------
1 | # Use JavaScript components
2 |
3 | todo
4 |
--------------------------------------------------------------------------------
/dune-project:
--------------------------------------------------------------------------------
1 | (lang dune 2.7)
2 |
3 | (name jsoo-react)
4 |
5 | (license MIT)
6 |
7 | (maintainers "Javier Chávarri ")
8 |
9 | (authors "Javier Chávarri ")
10 |
11 | (source
12 | (github ml-in-barcelona/jsoo-react))
13 |
14 | (generate_opam_files true)
15 |
16 | (implicit_transitive_deps false)
17 |
18 | (package
19 | (name jsoo-react)
20 | (synopsis "Bindings to ReactJS for js_of_ocaml, including JSX ppx")
21 | (depends
22 | ;; General system dependencies
23 | (ocaml (>= 4.12.0))
24 |
25 | (js_of_ocaml (>= 4.0.0))
26 | (gen_js_api (and (>= 1.0.8) (< 1.2.0)))
27 | (ppxlib (>= 0.23.0))
28 |
29 | ;; Test dependencies
30 | (webtest :with-test)
31 | (webtest-js :with-test)
32 | (js_of_ocaml-ppx :with-test)
33 | (conf-npm :with-test)
34 |
35 | ;; Dev dependencies, using with-test so that consumers don't install them (until package is released in opam)
36 | (ocamlformat (and (= 0.21.0) :with-test))
37 | (reason (and (= 3.8.2) :with-test))
38 |
39 | ;; Example dependencies, using with-test so that consumers don't install them (until package is released in opam)
40 | (ppx_blob :with-test)
41 | (js_of_ocaml-lwt :with-test)
42 | ))
43 |
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "app",
3 | "version": "0.0.1",
4 | "scripts": {
5 | "webpack": "webpack -w",
6 | "webpack:production": "webpack --mode=production",
7 | "server": "webpack-dev-server",
8 | "analyze": "webpack --mode=production --profile --json > stats.json && webpack-bundle-analyzer stats.json"
9 | },
10 | "license": "MIT",
11 | "devDependencies": {
12 | "css-loader": "^3.2.0",
13 | "html-webpack-plugin": "^3.2.0",
14 | "style-loader": "^1.0.0",
15 | "webpack": "^4.44.2",
16 | "webpack-bundle-analyzer": "^3.9.0",
17 | "webpack-cli": "^3.3.12",
18 | "webpack-dev-server": "^3.11.0"
19 | },
20 | "dependencies": {
21 | "react": "^16.13.1",
22 | "react-dom": "^16.13.1"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/example/src/App.re:
--------------------------------------------------------------------------------
1 | React.Dom.render_to_element(~id="app", );
2 |
--------------------------------------------------------------------------------
/example/src/Bindings.rei:
--------------------------------------------------------------------------------
1 | module Console: {
2 | [@js.global "console.log"]
3 | let log: 'a => unit;
4 | [@js.global "console.log"]
5 | let log2: ('a, 'b) => unit;
6 | [@js.global "console.log"]
7 | let log3: ('a, 'b, 'c) => unit;
8 | [@js.global "console.log"]
9 | let log4: ('a, 'b, 'c, 'd) => unit;
10 | };
11 |
12 | module Window: {
13 | type window;
14 | [@js.global "window"]
15 | let get: option(window);
16 | [@js.call]
17 | let alert: (window, string) => unit;
18 | [@js.get]
19 | let value: Ojs.t => string;
20 | };
21 |
--------------------------------------------------------------------------------
/example/src/Click.re:
--------------------------------------------------------------------------------
1 | type action =
2 | | Clicked(int, int);
3 |
4 | let reducer = (state, action) =>
5 | switch (action) {
6 | | Clicked(x, y) => [(x, y), ...state]
7 | };
8 |
9 | [@react.component]
10 | let make = () => {
11 | let (state, dispatch) = React.use_reducer(~init=[], reducer);
12 |
105 | {"You have seen the embedded code snippets in the examples. The one below is from the Main component of this page."
106 | |> s}
107 | {"Interface.re" |> s}
108 | {"." |> s}
109 |
110 |
111 | {"These snippets always stay in sync with the code itself. The strings from the files get captured at compile time via a "
112 | |> s}
113 |
116 | {"ppx" |> s}
117 |
118 | {" (preprocessor extension) that is called " |> s}
119 |
120 | {"ppx_blob" |> s}
121 |
122 | {" by calling " |> s}
123 | {"" |> s}
124 | {". Then, we just pass that string to a component " |> s}
125 | {"Code" |> s}
126 | {"." |> s}
127 |