diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b276add3..452f5f94 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,16 +17,11 @@ jobs: os: - ubuntu-latest ocaml-compiler: - - "4.13" - - "4.14" - - "5.0" - - "5.1" - - "5.2" + - "5.3" + - "5.4" include: - os: macos-latest - ocaml-compiler: "4.14" - - os: macos-latest - ocaml-compiler: "5.2" + ocaml-compiler: "5.4" runs-on: ${{ matrix.os }} @@ -44,8 +39,15 @@ jobs: if: runner.os == 'macOS' run: brew update && brew reinstall openssl@3 + - name: Install external dependencies + # The version of binaryen available in ubuntu is too old and doesn't + # contain wasm-merge needed by wasm_of_ocaml. + if: runner.os == 'Linux' + run: | + curl -sL https://github.com/WebAssembly/binaryen/releases/download/version_129/binaryen-version_129-x86_64-linux.tar.gz | sudo tar xz -C /usr/local --strip-components=1 + - run: opam pin add -n eliom https://github.com/ocsigen/eliom.git - run: opam install . --deps-only - - run: opam exec -- make + - run: opam exec -- dune build @install diff --git a/.gitignore b/.gitignore index dcfbd6c2..e35d8850 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1 @@ -.depend -_client -_deps -_server -lib -_opam -doc/client -doc/server +_build diff --git a/META.in b/META.in deleted file mode 100644 index 73f3b274..00000000 --- a/META.in +++ /dev/null @@ -1,19 +0,0 @@ -names = "@@PKG_NAME@@" -version = "@@PKG_VERS@@" -description = "@@PKG_DESC@@" - -package "server" ( - requires = "@@SERVER_REQUIRES@@" - directory = "server" - archive(byte) = "@@SERVER_ARCHIVES_BYTE@@" - archive(byte, plugin) = "@@SERVER_ARCHIVES_BYTE@@" - archive(native) = "@@SERVER_ARCHIVES_NATIVE@@" - archive(native, plugin) = "@@SERVER_ARCHIVES_NATIVE_PLUGIN@@" -) - -package "client" ( - requires = "@@CLIENT_REQUIRES@@" - directory = "client" - archive(byte) = "@@CLIENT_ARCHIVES_BYTE@@" - archive(byte, plugin) = "@@CLIENT_ARCHIVES_BYTE@@" -) diff --git a/Makefile b/Makefile deleted file mode 100644 index 71e97434..00000000 --- a/Makefile +++ /dev/null @@ -1,228 +0,0 @@ - -##---------------------------------------------------------------------- -## DISCLAIMER -## -## This file contains the rules to make an ocsigen package. The project -## is configured through the variables in the file Makefile.options. -##---------------------------------------------------------------------- - -include Makefile.options - -##---------------------------------------------------------------------- -## Internals - -## Required binaries -ELIOMC := eliomc -ppx ${WARNING_FLAGS} -ELIOMOPT := eliomopt -ppx ${WARNING_FLAGS} -JS_OF_ELIOM := js_of_eliom -ppx -ELIOMDEP := eliomdep -OCAMLFIND := ocamlfind - -## Where to put intermediate object files. -## - ELIOM_{SERVER,CLIENT}_DIR must be distinct -## - ELIOM_CLIENT_DIR must not be the local dir. -## - ELIOM_SERVER_DIR could be ".", but you need to -## remove it from the "clean" rules... -export ELIOM_SERVER_DIR := _server -export ELIOM_CLIENT_DIR := _client -export ELIOM_TYPE_DIR := _server - -ifeq ($(DEBUG),yes) - GENERATE_DEBUG ?= -g -endif - -ifeq ($(NATIVE),yes) - OPT_RULE = opt -endif - -##---------------------------------------------------------------------- -## General - -.PHONY: all byte opt doc -all: byte $(OPT_RULE) -byte:: $(LIBDIR)/${PKG_NAME}.server.cma $(LIBDIR)/${PKG_NAME}.client.cma -opt:: $(LIBDIR)/${PKG_NAME}.server.cmxs - -##---------------------------------------------------------------------- -## Aux - -eliomdep=$(shell $(ELIOMDEP) $(1) -ppx -sort $(2) $(filter %.eliom %.ml,$(3)))) -objs=$(patsubst %.ml,$(1)/%.$(2),$(patsubst %.eliom,$(1)/%.$(2),$(filter %.eliom %.ml,$(3)))) -depsort=$(call objs,$(1),$(2),$(call eliomdep,$(3),$(4),$(5))) - -$(LIBDIR): - mkdir $(LIBDIR) - -##---------------------------------------------------------------------- -## Server side compilation - -## make it more elegant ? -SERVER_DIRS := $(shell echo $(foreach f, $(SERVER_FILES), $(dir $(f))) | tr ' ' '\n' | sort -u | tr '\n' ' ') -SERVER_DEP_DIRS := ${addprefix -eliom-inc ,${SERVER_DIRS}} -SERVER_INC_DIRS := ${addprefix -I $(ELIOM_SERVER_DIR)/, ${SERVER_DIRS}} - -SERVER_INC := ${addprefix -package ,${SERVER_PACKAGES} ${SERVER_PPX_PACKAGES}} - -${ELIOM_TYPE_DIR}/%.type_mli: %.eliom - ${ELIOMC} -infer ${SERVER_INC} ${SERVER_INC_DIRS} $< - -$(LIBDIR)/$(PKG_NAME).server.cma: $(call objs,$(ELIOM_SERVER_DIR),cmo,$(SERVER_FILES)) | $(LIBDIR) - ${ELIOMC} -a -o $@ $(GENERATE_DEBUG) \ - $(call depsort,$(ELIOM_SERVER_DIR),cmo,-server,$(SERVER_INC),$(SERVER_FILES)) - -$(LIBDIR)/$(PKG_NAME).server.cmxa: $(call objs,$(ELIOM_SERVER_DIR),cmx,$(SERVER_FILES)) | $(LIBDIR) - ${ELIOMOPT} -a -o $@ $(GENERATE_DEBUG) \ - $(call depsort,$(ELIOM_SERVER_DIR),cmx,-server,$(SERVER_INC),$(SERVER_FILES)) - -%.cmxs: %.cmxa - $(ELIOMOPT) -shared -linkall -o $@ $(GENERATE_DEBUG) $< - -${ELIOM_SERVER_DIR}/%.cmi: %.mli - ${ELIOMC} -c ${SERVER_INC} ${SERVER_INC_DIRS} $(GENERATE_DEBUG) $< - -${ELIOM_SERVER_DIR}/%.cmi: %.eliomi - ${ELIOMC} -c ${SERVER_INC} ${SERVER_INC_DIRS} $(GENERATE_DEBUG) $< - -${ELIOM_SERVER_DIR}/%.cmo: %.ml - ${ELIOMC} -c ${SERVER_INC} ${SERVER_INC_DIRS} $(GENERATE_DEBUG) $< -${ELIOM_SERVER_DIR}/%.cmo: %.eliom - ${ELIOMC} -c ${SERVER_INC} ${SERVER_INC_DIRS} $(GENERATE_DEBUG) $< - -${ELIOM_SERVER_DIR}/%.cmx: %.ml - ${ELIOMOPT} -c ${SERVER_INC} ${SERVER_INC_DIRS} $(GENERATE_DEBUG) $< -${ELIOM_SERVER_DIR}/%.cmx: %.eliom - ${ELIOMOPT} -c ${SERVER_INC} ${SERVER_INC_DIRS} $(GENERATE_DEBUG) $< - - -##---------------------------------------------------------------------- -## Client side compilation - -## make it more elegant ? -CLIENT_DIRS := $(shell echo $(foreach f, $(CLIENT_FILES), $(dir $(f))) | tr ' ' '\n' | sort -u | tr '\n' ' ') -CLIENT_DEP_DIRS := ${addprefix -eliom-inc ,${CLIENT_DIRS}} -CLIENT_INC_DIRS := ${addprefix -I $(ELIOM_CLIENT_DIR)/,${CLIENT_DIRS}} - -CLIENT_LIBS := ${addprefix -package ,${CLIENT_PACKAGES} ${CLIENT_PPX_PACKAGES}} -CLIENT_INC := ${addprefix -package ,${CLIENT_PACKAGES} ${CLIENT_PPX_PACKAGES}} - -CLIENT_OBJS := $(filter %.eliom %.ml, $(CLIENT_FILES)) -CLIENT_OBJS := $(patsubst %.eliom,${ELIOM_CLIENT_DIR}/%.cmo, ${CLIENT_OBJS}) -CLIENT_OBJS := $(patsubst %.ml,${ELIOM_CLIENT_DIR}/%.cmo, ${CLIENT_OBJS}) - -$(LIBDIR)/$(PKG_NAME).client.cma: $(call objs,$(ELIOM_CLIENT_DIR),cmo,$(CLIENT_FILES)) | $(LIBDIR) - ${JS_OF_ELIOM} -a -o $@ $(GENERATE_DEBUG) \ - $(call depsort,$(ELIOM_CLIENT_DIR),cmo,-client,$(CLIENT_INC),$(CLIENT_FILES)) - -${ELIOM_CLIENT_DIR}/%.cmi: %.mli - ${JS_OF_ELIOM} -c ${CLIENT_INC} ${CLIENT_INC_DIRS} $(GENERATE_DEBUG) $< - -${ELIOM_CLIENT_DIR}/%.cmo: %.eliom - ${JS_OF_ELIOM} -c ${CLIENT_INC} ${CLIENT_INC_DIRS} $(GENERATE_DEBUG) $< -${ELIOM_CLIENT_DIR}/%.cmo: %.ml - ${JS_OF_ELIOM} -c ${CLIENT_INC} ${CLIENT_INC_DIRS} $(GENERATE_DEBUG) $< - -${ELIOM_CLIENT_DIR}/%.cmi: %.eliomi - ${JS_OF_ELIOM} -c ${CLIENT_INC} ${CLIENT_INC_DIRS} $(GENERATE_DEBUG) $< - -##---------------------------------------------------------------------- -## Installation - -CLIENT_CMO=$(wildcard $(addsuffix /$(MODULE_PREFIX)*.cmo,$(addprefix $(ELIOM_CLIENT_DIR)/,$(CLIENT_DIRS)))) -CLIENT_CMI=$(wildcard $(addsuffix /$(MODULE_PREFIX)*.cmi,$(addprefix $(ELIOM_CLIENT_DIR)/,$(CLIENT_DIRS)))) -SERVER_CMI=$(wildcard $(addsuffix /$(MODULE_PREFIX)*.cmi,$(addprefix $(ELIOM_SERVER_DIR)/,$(SERVER_DIRS)))) -SERVER_CMX=$(wildcard $(addsuffix /$(MODULE_PREFIX)*.cmx,$(addprefix $(ELIOM_SERVER_DIR)/,$(SERVER_DIRS)))) - -basename_for_each = $(shell echo $(foreach f,$(1),$(shell basename $(f)))) -CLIENT_CMO_META=$(call basename_for_each, $(call depsort,$(ELIOM_CLIENT_DIR),cmo,-client,$(CLIENT_INC),$(CLIENT_FILES))) - -META: META.in - sed -e 's#@@PKG_NAME@@#$(PKG_NAME)#g' \ - -e 's#@@PKG_VERS@@#$(PKG_VERS)#g' \ - -e 's#@@PKG_DESC@@#$(PKG_DESC)#g' \ - -e 's#@@CLIENT_REQUIRES@@#$(CLIENT_PACKAGES)#g' \ - -e 's#@@CLIENT_ARCHIVES_BYTE@@#$(CLIENT_CMO_META)#g' \ - -e 's#@@SERVER_REQUIRES@@#$(SERVER_PACKAGES)#g' \ - -e 's#@@SERVER_ARCHIVES_BYTE@@#$(PKG_NAME).server.cma#g' \ - -e 's#@@SERVER_ARCHIVES_NATIVE@@#$(PKG_NAME).server.cmxa#g' \ - -e 's#@@SERVER_ARCHIVES_NATIVE_PLUGIN@@#$(PKG_NAME).server.cmxs#g' \ - $< > $@ - -install: all META - $(OCAMLFIND) install $(PKG_NAME) META - mkdir -p `$(OCAMLFIND) query $(PKG_NAME)`/client - mkdir -p `$(OCAMLFIND) query $(PKG_NAME)`/server - cp $(CLIENT_CMI) `$(OCAMLFIND) query $(PKG_NAME)`/client - cp $(CLIENT_CMO) `$(OCAMLFIND) query $(PKG_NAME)`/client - cp $(SERVER_CMI) `$(OCAMLFIND) query $(PKG_NAME)`/server - cp $(SERVER_CMX) `$(OCAMLFIND) query $(PKG_NAME)`/server - cp $(LIBDIR)/$(PKG_NAME).server.cm* `$(OCAMLFIND) query $(PKG_NAME)`/server - cp $(LIBDIR)/$(PKG_NAME).server.a `$(OCAMLFIND) query $(PKG_NAME)`/server - -uninstall: - rm -rf `$(OCAMLFIND) query $(PKG_NAME)`/client - rm -rf `$(OCAMLFIND) query $(PKG_NAME)`/server - $(OCAMLFIND) remove $(PKG_NAME) - -reinstall: uninstall install - -##---------------------------------------------------------------------- -## Dependencies - -ifneq ($(MAKECMDGOALS),distclean) -ifneq ($(MAKECMDGOALS),clean) -ifneq ($(MAKECMDGOALS),depend) - include .depend -endif -endif -endif - -DEPSDIR := _deps - -.depend: $(patsubst %,$(DEPSDIR)/%.server,$(SERVER_FILES)) $(patsubst %,$(DEPSDIR)/%.client,$(CLIENT_FILES)) - cat $^ > $@ - -$(DEPSDIR)/%.server: % | $(DEPSDIR) - $(ELIOMDEP) -server -ppx $(SERVER_INC) $(SERVER_DEP_DIRS) $< > $@ - -$(DEPSDIR)/%.client: % | $(DEPSDIR) - $(ELIOMDEP) -client -ppx $(CLIENT_INC) $(CLIENT_DEP_DIRS) $< > $@ - -$(DEPSDIR): - mkdir -p $@ - mkdir -p $(addprefix $@/, ${CLIENT_DIRS}) - mkdir -p $(addprefix $@/, ${SERVER_DIRS}) - -##---------------------------------------------------------------------- -## Documentation - -COMMON_OPTIONS := -colorize-code -stars -sort - -eliomdoc_wiki = ODOC_WIKI_SUBPROJECT="$(1)" eliomdoc -$(1) -ppx -intro doc/indexdoc.$(1) $(COMMON_OPTIONS) -i $(shell ocamlfind query wikidoc) -g odoc_wiki.cma -d doc/$(1)/wiki $(2) -eliomdoc_html = ODOC_WIKI_SUBPROJECT="$(1)" eliomdoc -$(1) -ppx -intro doc/indexdoc.$(1) $(COMMON_OPTIONS) -html -d doc/$(1)/html $(2) - -doc: doc-clean - mkdir -p doc/client/html - mkdir -p doc/client/wiki - mkdir -p doc/server/html - mkdir -p doc/server/wiki - $(call eliomdoc_html,client, $(CLIENT_INC) $(CLIENT_INC_DIRS) $(CLIENT_FILES_DOC)) - $(call eliomdoc_wiki,client, $(CLIENT_INC) $(CLIENT_INC_DIRS) $(CLIENT_FILES_DOC)) - $(call eliomdoc_html,server, $(SERVER_INC) $(SERVER_INC_DIRS) $(SERVER_FILES_DOC)) - $(call eliomdoc_wiki,server, $(SERVER_INC) $(SERVER_INC_DIRS) $(SERVER_FILES_DOC)) - -doc-clean: - rm -rf doc/client - rm -rf doc/server - -##---------------------------------------------------------------------- -## Clean up - -clean: - -rm -f .depend - -rm -f *.cm[ioax] *.cmxa *.cmxs *.o *.a *.annot - -rm -f *.type_mli - -rm -f META - -rm -rf ${ELIOM_CLIENT_DIR} ${ELIOM_SERVER_DIR} ${LIBDIR} ${DEPSDIR} - -distclean: clean - -rm -rf $(DEPSDIR) .depend diff --git a/Makefile.options b/Makefile.options deleted file mode 100644 index f598b5c5..00000000 --- a/Makefile.options +++ /dev/null @@ -1,62 +0,0 @@ -#---------------------------------------------------------------------- -# SETTINGS FOR YOUR PACKAGE -#---------------------------------------------------------------------- - -# Package name for your -PKG_NAME := ocsigen-toolkit -PKG_VERS := 1.1 -PKG_DESC := reusable UI components meant for Eliom applications - -# Source files for the server -SERVER_FILES := $(wildcard \ - src/*.ml* \ - src/*.eliom* \ - src/widgets/*.eliom* \ -) - -# Source files for the client -CLIENT_FILES := $(wildcard \ - src/*.eliom* \ - src/widgets/*.eliom* \ -) - -# Source files for the server -SERVER_FILES_DOC := $(wildcard \ - src/*.eliomi \ - src/*.mli \ - src/widgets/*.eliomi \ -) - -# Source files for the client -CLIENT_FILES_DOC := $(wildcard \ - src/*.eliomi \ - src/widgets/*.eliomi \ -) - -# Template directory (used when installing template with distillery) -TEMPLATE_DIR := template.distillery - -# Template name (name used by distillery) -TEMPLATE_NAME := none.pgocaml - -# OCamlfind packages for the server -SERVER_PACKAGES := calendar -SERVER_PPX_PACKAGES := js_of_ocaml-ppx_deriving_json -# OCamlfind packages for the client -CLIENT_PACKAGES := calendar js_of_ocaml js_of_ocaml-lwt -CLIENT_PPX_PACKAGES := js_of_ocaml-ppx js_of_ocaml-ppx_deriving_json - -# Debug package (yes/no): Debugging info in compilation -DEBUG := yes - -# Native mode (yes/no): Compile also with native mode (it will always -# compile with byte mode) -NATIVE := yes - -# Package's library $(PKG_NAME).{client,server}.cma (a,cmxa,cmxs only -# server side) -LIBDIR := lib/ - -WARNING_FLAGS=-w +A@3-4@5..16@20..43-44@45..68-69-70 - -MODULE_PREFIX = ot diff --git a/dune b/dune new file mode 100644 index 00000000..4293baf3 --- /dev/null +++ b/dune @@ -0,0 +1,7 @@ +(vendored_dirs ocsigen-dune-rules) + +; Install the CSS files into share/ocsigen-toolkit/css/ +(install + (section share) + (files + (glob_files css/*.css))) diff --git a/dune-project b/dune-project new file mode 100644 index 00000000..11e6f5ad --- /dev/null +++ b/dune-project @@ -0,0 +1,44 @@ +(lang dune 3.18) + +(name ocsigen-toolkit) + +(generate_opam_files true) + +(source + (github ocsigen/ocsigen-toolkit)) + +(homepage "http://www.ocsigen.org") + +(authors "dev@ocsigen.org") + +(maintainers "dev@ocsigen.org") + +(license "LGPL-2.1-only WITH OCaml-LGPL-linking-exception") + +(maintenance_intent "(latest)") + +(dialect + (name "eliom-server") + (implementation + (extension "eliom")) + (interface + (extension "eliomi"))) + +(package + (name ocsigen-toolkit) + (synopsis + "Reusable UI components for Eliom applications (client only, or client-server)") + (description + "The Ocsigen Toolkit is a set of user interface widgets that facilitate the development of Eliom applications.") + (depends + (ocaml + (>= "4.08.0")) + (js_of_ocaml + (>= "6.0.0")) + (eliom + (>= "11.0.0")) + (calendar + (>= "2.0.0")) + ; ocsigen-dune-rules dependencies + cmdliner + ocsigen-ppx-rpc)) diff --git a/ocsigen-dune-rules/.gitignore b/ocsigen-dune-rules/.gitignore new file mode 100644 index 00000000..e35d8850 --- /dev/null +++ b/ocsigen-dune-rules/.gitignore @@ -0,0 +1 @@ +_build diff --git a/ocsigen-dune-rules/.ocamlformat b/ocsigen-dune-rules/.ocamlformat new file mode 100644 index 00000000..dbc03d39 --- /dev/null +++ b/ocsigen-dune-rules/.ocamlformat @@ -0,0 +1 @@ +version = 0.28.1 diff --git a/ocsigen-dune-rules/LICENSE b/ocsigen-dune-rules/LICENSE new file mode 100644 index 00000000..877734eb --- /dev/null +++ b/ocsigen-dune-rules/LICENSE @@ -0,0 +1,21 @@ +# MIT License + +Copyright (c) 2026 Tarides, Jules Aguillon + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/ocsigen-dune-rules/README.md b/ocsigen-dune-rules/README.md new file mode 100644 index 00000000..f204f9c1 --- /dev/null +++ b/ocsigen-dune-rules/README.md @@ -0,0 +1,58 @@ +# ocsigen-dune-rules + +Generate Dune rules for building a client/server application or library. + +## Usage + +The following `dune` file builds the client and server parts of your library. +Place it in a directory containing `*.eliom` files. + +`lib/dune`: +```dune +(library + (public_name my_lib.server) + (name my_lib) + (modes byte native) + (wrapped false) + (preprocess + (pps + eliom.ppx.server + ocsigen-ppx-rpc + --rpc-raw)) + (libraries eliom.server js_of_ocaml)) + +(subdir + client + (library + (public_name my_lib.client) + (name my_lib) + (modes byte) + (wrapped false) + (preprocess + (pps eliom.ppx.client js_of_ocaml-ppx)) + (libraries eliom.client js_of_ocaml js_of_ocaml-lwt)) + (dynamic_include ../dune.client)) + +(rule + (deps + (glob_files *.eliom) + (glob_files *.eliomi)) + (action + (with-stdout-to + dune.client + (run ocsigen-dune-rules .)))) +``` + +You must also tell Dune that `*.eliom` files contain source code by adding this to your `dune-project` file: + +`dune-project`: +```dune +(dialect + (name "eliom-server") + (implementation + (extension "eliom")) + (interface + (extension "eliomi"))) +``` + +See [ocsigen-toolkit](https://github.com/ocsigen/ocsigen-toolkit/tree/master) for a working example. diff --git a/ocsigen-dune-rules/dune-project b/ocsigen-dune-rules/dune-project new file mode 100644 index 00000000..313fc1ce --- /dev/null +++ b/ocsigen-dune-rules/dune-project @@ -0,0 +1,19 @@ +(lang dune 3.14) + +(name ocsigen-dune-rules) + +(cram enable) + +(generate_opam_files true) + +(authors "Jules Aguillon ") + +(maintainers "Jules Aguillon ") + +(license MIT) + +(package + (name ocsigen-dune-rules) + (synopsis + "Generate Dune rules for building a client/server application or library.") + (depends ocaml cmdliner ocsigen-ppx-rpc eliom)) diff --git a/ocsigen-dune-rules/ocsigen-dune-rules.opam b/ocsigen-dune-rules/ocsigen-dune-rules.opam new file mode 100644 index 00000000..8914b4cd --- /dev/null +++ b/ocsigen-dune-rules/ocsigen-dune-rules.opam @@ -0,0 +1,29 @@ +# This file is generated by dune, edit dune-project instead +opam-version: "2.0" +synopsis: + "Generate Dune rules for building a client/server application or library." +maintainer: ["Jules Aguillon "] +authors: ["Jules Aguillon "] +license: "MIT" +depends: [ + "dune" {>= "3.14"} + "ocaml" + "cmdliner" + "ocsigen-ppx-rpc" + "eliom" + "odoc" {with-doc} +] +build: [ + ["dune" "subst"] {dev} + [ + "dune" + "build" + "-p" + name + "-j" + jobs + "@install" + "@runtest" {with-test} + "@doc" {with-doc} + ] +] diff --git a/ocsigen-dune-rules/ocsigen-dune-rules/dune b/ocsigen-dune-rules/ocsigen-dune-rules/dune new file mode 100644 index 00000000..778b68e6 --- /dev/null +++ b/ocsigen-dune-rules/ocsigen-dune-rules/dune @@ -0,0 +1,4 @@ +(executable + (public_name ocsigen-dune-rules) + (name main) + (libraries cmdliner)) diff --git a/ocsigen-dune-rules/ocsigen-dune-rules/gen_rules.ml b/ocsigen-dune-rules/ocsigen-dune-rules/gen_rules.ml new file mode 100644 index 00000000..ff004966 --- /dev/null +++ b/ocsigen-dune-rules/ocsigen-dune-rules/gen_rules.ml @@ -0,0 +1,38 @@ +let pf = Printf.printf +let spf = Printf.sprintf + +let gen_eliom_ppx_rule ~target ~input ~args = + (* The [chdir] instruction is needed to obtain the correct path for + [-loc-filename] to be used in error messages. *) + pf + {|(rule + (with-stdout-to %s + (chdir %%{workspace_root} + (run ocsigen-ppx-client -as-pp -loc-filename %%{dep:%s} %s %%{dep:%s})))) +|} + target input (String.concat " " args) input + +let gen_rule_for_module ~server_rel_prefix ~impl fname = + let target = Filename.basename fname in + let fname_no_ext = Filename.remove_extension fname in + let input = Filename.concat server_rel_prefix fname in + if Filename.extension fname_no_ext = ".pp" then () + else + let args = + if impl then + let server_cmo = Filename.concat server_rel_prefix fname_no_ext in + [ "--impl"; "-server-cmo"; spf "%%{cmo:%s}" server_cmo ] + else [ "--intf" ] + in + gen_eliom_ppx_rule ~target ~input ~args + +(** Relative path to server modules from the generated client modules. *) +let server_rel_prefix = ".." + +let gen_rule_for_file fname = + match Filename.extension fname with + | ".eliom" -> gen_rule_for_module ~server_rel_prefix ~impl:true fname + | ".eliomi" -> gen_rule_for_module ~server_rel_prefix ~impl:false fname + | _ -> () + +let run files = List.iter gen_rule_for_file files diff --git a/ocsigen-dune-rules/ocsigen-dune-rules/main.ml b/ocsigen-dune-rules/ocsigen-dune-rules/main.ml new file mode 100644 index 00000000..7b608f24 --- /dev/null +++ b/ocsigen-dune-rules/ocsigen-dune-rules/main.ml @@ -0,0 +1,20 @@ +let run dir = + let files = Utils.list_dir dir in + let files = List.filter (Fun.negate Utils.is_dir) files in + Gen_rules.run files + +open Cmdliner + +let arg_dir = + let doc = "Directory containing the Eliom modules." in + Arg.(required & pos 0 (some dir) None & info ~doc ~docv:"DIR" []) + +let cmd = + let term = Term.(const run $ arg_dir) in + let doc = + "Generate dune rules for building an ocsigen application or library." + in + let info = Cmd.info "ocsigen-dune-rules" ~version:"%%VERSION%%" ~doc in + Cmd.v info term + +let () = exit (Cmd.eval cmd) diff --git a/ocsigen-dune-rules/ocsigen-dune-rules/utils.ml b/ocsigen-dune-rules/ocsigen-dune-rules/utils.ml new file mode 100644 index 00000000..0b9e1825 --- /dev/null +++ b/ocsigen-dune-rules/ocsigen-dune-rules/utils.ml @@ -0,0 +1,13 @@ +(** List the content of a directory. Returns qualified paths. Returned path + doesn't contain [./] if [p] is equal to ["."]. *) +let list_dir p = + (* Let [Sys_error] escape. *) + let files = Sys.readdir p in + (* Sorted for reproducibility. *) + Array.sort String.compare files; + let concat_p = if p = "." then Fun.id else Filename.concat p in + Array.iteri (fun i fname -> files.(i) <- concat_p fname) files; + Array.to_list files + +(** Do not raise. *) +let is_dir p = try Sys.is_directory p with Sys_error _ -> false diff --git a/ocsigen-dune-rules/ocsigen-ppx-client/dune b/ocsigen-dune-rules/ocsigen-ppx-client/dune new file mode 100644 index 00000000..ff7a6d26 --- /dev/null +++ b/ocsigen-dune-rules/ocsigen-ppx-client/dune @@ -0,0 +1,5 @@ +(executable + (public_name ocsigen-ppx-client) + (package ocsigen-dune-rules) + (name main) + (libraries ocsigen-ppx-rpc eliom.ppx.client)) diff --git a/ocsigen-dune-rules/ocsigen-ppx-client/main.ml b/ocsigen-dune-rules/ocsigen-ppx-client/main.ml new file mode 100644 index 00000000..e3cba404 --- /dev/null +++ b/ocsigen-dune-rules/ocsigen-ppx-client/main.ml @@ -0,0 +1 @@ +let () = Ppxlib.Driver.standalone () diff --git a/ocsigen-dune-rules/test/dune b/ocsigen-dune-rules/test/dune new file mode 100644 index 00000000..58b3ec1e --- /dev/null +++ b/ocsigen-dune-rules/test/dune @@ -0,0 +1,2 @@ +(cram + (deps %{bin:ocsigen-dune-rules})) diff --git a/ocsigen-dune-rules/test/rules.t/a.eliom b/ocsigen-dune-rules/test/rules.t/a.eliom new file mode 100644 index 00000000..e69de29b diff --git a/ocsigen-dune-rules/test/rules.t/b.eliom b/ocsigen-dune-rules/test/rules.t/b.eliom new file mode 100644 index 00000000..e69de29b diff --git a/ocsigen-dune-rules/test/rules.t/b.eliomi b/ocsigen-dune-rules/test/rules.t/b.eliomi new file mode 100644 index 00000000..e69de29b diff --git a/ocsigen-dune-rules/test/rules.t/not_eliom.ml b/ocsigen-dune-rules/test/rules.t/not_eliom.ml new file mode 100644 index 00000000..e69de29b diff --git a/ocsigen-dune-rules/test/rules.t/run.t b/ocsigen-dune-rules/test/rules.t/run.t new file mode 100644 index 00000000..cd8b0a53 --- /dev/null +++ b/ocsigen-dune-rules/test/rules.t/run.t @@ -0,0 +1,13 @@ + $ ocsigen-dune-rules . + (rule + (with-stdout-to a.eliom + (chdir %{workspace_root} + (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../a.eliom} --impl -server-cmo %{cmo:../a} %{dep:../a.eliom})))) + (rule + (with-stdout-to b.eliom + (chdir %{workspace_root} + (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../b.eliom} --impl -server-cmo %{cmo:../b} %{dep:../b.eliom})))) + (rule + (with-stdout-to b.eliomi + (chdir %{workspace_root} + (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../b.eliomi} --intf %{dep:../b.eliomi})))) diff --git a/ocsigen-dune-rules/test/rules.t/subdir/.keep b/ocsigen-dune-rules/test/rules.t/subdir/.keep new file mode 100644 index 00000000..e69de29b diff --git a/ocsigen-toolkit.install b/ocsigen-toolkit.install deleted file mode 100644 index f79e6bcd..00000000 --- a/ocsigen-toolkit.install +++ /dev/null @@ -1,16 +0,0 @@ -share: [ - "css/ot_carousel.css" {"css/ot_carousel.css"} - "css/ot_spinner.css" {"css/ot_spinner.css"} - "css/ot_popup.css" {"css/ot_popup.css"} - "css/ot_datetime.css" {"css/ot_datetime.css"} - "css/ot_picture_uploader.css" {"css/ot_picture_uploader.css"} - "css/ot_icons.css" {"css/ot_icons.css"} - "css/ot_drawer.css" {"css/ot_drawer.css"} - "css/ot_buttons.css" {"css/ot_buttons.css"} - "css/ot_sticky.css" {"css/ot_sticky.css"} - "css/ot_page_transition.css" {"css/ot_page_transition.css"} - "css/ot_color_picker.css" {"css/ot_color_picker.css"} - "css/ot_pull_to_refresh.css" {"css/ot_pull_to_refresh.css"} - "css/ot_tongue.css" {"css/ot_tongue.css"} - "css/ot_form.css" {"css/ot_form.css"} -] diff --git a/ocsigen-toolkit.opam b/ocsigen-toolkit.opam new file mode 100644 index 00000000..fc5e4e42 --- /dev/null +++ b/ocsigen-toolkit.opam @@ -0,0 +1,37 @@ +# This file is generated by dune, edit dune-project instead +opam-version: "2.0" +synopsis: + "Reusable UI components for Eliom applications (client only, or client-server)" +description: + "The Ocsigen Toolkit is a set of user interface widgets that facilitate the development of Eliom applications." +maintainer: ["dev@ocsigen.org"] +authors: ["dev@ocsigen.org"] +license: "LGPL-2.1-only WITH OCaml-LGPL-linking-exception" +homepage: "http://www.ocsigen.org" +bug-reports: "https://github.com/ocsigen/ocsigen-toolkit/issues" +depends: [ + "dune" {>= "3.18"} + "ocaml" {>= "4.08.0"} + "js_of_ocaml" {>= "6.0.0"} + "eliom" {>= "11.0.0"} + "calendar" {>= "2.0.0"} + "cmdliner" + "ocsigen-ppx-rpc" + "odoc" {with-doc} +] +build: [ + ["dune" "subst"] {dev} + [ + "dune" + "build" + "-p" + name + "-j" + jobs + "@install" + "@runtest" {with-test} + "@doc" {with-doc} + ] +] +dev-repo: "git+https://github.com/ocsigen/ocsigen-toolkit.git" +x-maintenance-intent: ["(latest)"] diff --git a/opam b/opam deleted file mode 100644 index 60e033be..00000000 --- a/opam +++ /dev/null @@ -1,21 +0,0 @@ -opam-version: "2.0" -name: "ocsigen-toolkit" -version: "4.2.0" -maintainer: "dev@ocsigen.org" -synopsis: "Reusable UI components for Eliom applications (client only, or client-server)" -description: "The Ocsigen Toolkit is a set of user interface widgets that facilitate the development of Eliom applications." -authors: "dev@ocsigen.org" -homepage: "http://www.ocsigen.org" -bug-reports: "https://github.com/ocsigen/ocsigen-toolkit/issues/" -dev-repo: "git+https://github.com/ocsigen/ocsigen-toolkit.git" -license: "LGPL-2.1-only WITH OCaml-LGPL-linking-exception" -build: [ make "-j%{jobs}%" ] -install: [ make "install" ] -available: arch != "x86_32" & arch != "arm32" -depends: [ - "ocaml" {>= "4.08.0"} - "js_of_ocaml" {>= "6.0.0"} - "eliom" {>= "11.0.0"} - "calendar" {>= "2.0.0"} -] -x-maintenance-intent: ["(latest)" ] diff --git a/src/widgets/dune b/src/widgets/dune new file mode 100644 index 00000000..5f6f40ed --- /dev/null +++ b/src/widgets/dune @@ -0,0 +1,39 @@ +(env + (_ + (flags + (:standard -w +A-4-9-16-27-32-33-39-44-48-60-70)))) + +(library + (public_name ocsigen-toolkit.server) + (name widgets_server) + (modes byte native) + (wrapped false) + (preprocess + (pps + eliom.ppx.server + lwt_ppx + js_of_ocaml-ppx_deriving_json + ocsigen-ppx-rpc + --rpc-raw)) + (libraries eliom.server calendar js_of_ocaml)) + +(subdir + client + (library + (public_name ocsigen-toolkit.client) + (name widgets_client) + (modes byte) + (wrapped false) + (preprocess + (pps js_of_ocaml-ppx lwt_ppx js_of_ocaml-ppx_deriving_json)) + (libraries eliom.client calendar js_of_ocaml js_of_ocaml-lwt)) + (dynamic_include ../dune.client)) + +(rule + (deps + (glob_files *.eliom) + (glob_files *.eliomi)) + (action + (with-stdout-to + dune.client + (run ocsigen-dune-rules .)))) diff --git a/src/widgets/ot_calendar.eliom b/src/widgets/ot_calendar.eliom index 4f0efde3..19259d10 100644 --- a/src/widgets/ot_calendar.eliom +++ b/src/widgets/ot_calendar.eliom @@ -582,13 +582,15 @@ let%server make : ?button_labels ?intl () -> - C.node - [%client - (make ?init:~%init ?highlight:~%highlight - ?click_non_highlighted:~%click_non_highlighted ?update:~%update - ?action:~%action ?period:~%period ?intl:~%intl - ?button_labels:~%button_labels () - : [> `Div] elt)] + (C.node + [%client + (make ?init:~%init ?highlight:~%highlight + ?click_non_highlighted:~%click_non_highlighted ?update:~%update + ?action:~%action ?period:~%period ?intl:~%intl + ?button_labels:~%button_labels () + : [> `Div] elt)] + : [`Div] elt + :> [> `Div] elt) let%shared make_date_picker ?init ?update ?button_labels ?intl ?period () = let init = diff --git a/src/widgets/ot_carousel.eliom b/src/widgets/ot_carousel.eliom index fd76dc66..4c7fe31c 100644 --- a/src/widgets/ot_carousel.eliom +++ b/src/widgets/ot_carousel.eliom @@ -972,6 +972,9 @@ let%shared ~pos content = + let change = + (change :> ([`Prev | `Goto of int] -> unit) Eliom_client_value.t) + in Form.button_no_value ~button_type:`Button ~a: (R.a_class (Eliom_shared.React.S.map [%shared fun p -> blur (p = 0)] pos) @@ -997,6 +1000,9 @@ let%shared ~length content = + let change = + (change :> ([`Next | `Goto of int] -> unit) Eliom_client_value.t) + in Form.button_no_value ~button_type:`Button ~a: (R.a_class diff --git a/src/widgets/ot_color_picker.eliom b/src/widgets/ot_color_picker.eliom index a45620a8..c061fd66 100644 --- a/src/widgets/ot_color_picker.eliom +++ b/src/widgets/ot_color_picker.eliom @@ -21,6 +21,7 @@ [%%shared.start] +open Eliom_content.Html open Eliom_shared.React.S.Infix let hsv_to_rgb h s v = @@ -46,7 +47,6 @@ let rgb_to_css (r, g, b) = (int_of_float b) let display_hue_selector ~setter (sel_hue, sel_sat, sel_ltn) = - let open Eliom_content.Html in let dim = 111 in let irange = Array.init dim (fun x -> x) in let step = 360.0 /. float_of_int dim in @@ -84,7 +84,6 @@ let display_hue_selector ~setter (sel_hue, sel_sat, sel_ltn) = * TODO: use a CSS3 gradient in each cell to make the grid look smoother *) let display_sl_grid ~setter (sel_hue, sel_sat, sel_ltn) = - let open Eliom_content.Html in let hue = float_of_int sel_hue in let dim = 51 in let irange = Array.init (dim * dim) (fun x -> x) in @@ -130,19 +129,16 @@ let display_sl_grid ~setter (sel_hue, sel_sat, sel_ltn) = D.(div ~a:[a_class ["ot-color-picker-sl-picker"]] (Array.to_list rows)) let display_aux ?(a = []) ~setter sel = - let open Eliom_content.Html in D.div ~a:(D.a_class ["ot-color-picker"] :: a) [display_hue_selector ~setter sel; display_sl_grid ~setter sel] let display ?a cp_sig = let setter = snd cp_sig in - fst cp_sig - >|= [%shared display_aux ?a:~%a ~setter:~%setter] - |> Eliom_content.Html.R.node + fst cp_sig >|= [%shared display_aux ?a:~%a ~setter:~%setter] |> R.node let make - ?a + ?(a : [< Html_types.div_attrib > `Class] attrib list option) ?hsv ?(update = [%client (React.E.never : (int * float * float) React.E.t)]) () @@ -150,13 +146,13 @@ let make let ((cp_sig, cp_set) as cp_react) = Eliom_shared.React.S.create (Option.value hsv ~default:(255, 1.0, 0.0)) in + let a = (a :> Html_types.div_attrib attrib list option) in let elt, signal = display ?a cp_react, cp_sig in - let elt = Eliom_content.Html.D.div [elt] in + let elt = D.div [elt] in ignore [%client (* /!\ How to avoid the effectful signal ? *) - (Eliom_lib.Dom_reference.retain - (Eliom_content.Html.To_dom.of_element ~%elt) + (Eliom_lib.Dom_reference.retain (To_dom.of_element ~%elt) ~keep: (React.E.map (fun update -> ~%cp_set update) ~%update : unit React.event) diff --git a/src/widgets/ot_form.eliom b/src/widgets/ot_form.eliom index 42b0d9f6..7a80c40f 100644 --- a/src/widgets/ot_form.eliom +++ b/src/widgets/ot_form.eliom @@ -690,7 +690,8 @@ let%shared password_input ?(a = []) ?placeholder () = (* -- Password toggle (non-reactive) ------------------------------ *) -let%shared password_toggle (inp : [< Html_types.input] elt) = +let%shared password_toggle inp = + let inp = (inp : [< Html_types.input] elt :> Html_types.input elt) in let toggle_icon = D.span ~a:[a_class ["ot-password-toggle-show"]] [] in diff --git a/src/widgets/ot_picture_uploader.eliom b/src/widgets/ot_picture_uploader.eliom index 9d31d45d..c01140a5 100644 --- a/src/widgets/ot_picture_uploader.eliom +++ b/src/widgets/ot_picture_uploader.eliom @@ -457,7 +457,7 @@ let%client ocaml_service_upload ~service ~arg ?progress ?cropping file = let%client do_submit input ?progress ?cropping ~upload () = process_file input @@ fun file -> - let* _ = upload ?progress ?cropping file in + let* () = upload ?progress ?cropping file in Lwt.return_unit let%client @@ -503,7 +503,7 @@ let%shared ?crop ?input:(input_a, input_content = [], []) ?submit:(submit_a, submit_content = [], []) - (upload : 'a upload) + (upload : unit upload) = let preview = preview () in let input, input_label = input ~a:input_a input_content in diff --git a/src/widgets/ot_picture_uploader.eliomi b/src/widgets/ot_picture_uploader.eliomi index df129b10..933d6fbe 100644 --- a/src/widgets/ot_picture_uploader.eliomi +++ b/src/widgets/ot_picture_uploader.eliomi @@ -87,7 +87,7 @@ val do_submit : Dom_html.inputElement Js.t Eliom_client_value.t -> ?progress:(int -> int -> unit) -> ?cropping:cropping - -> upload:'a upload + -> upload:unit upload -> unit -> unit Lwt.t (** [ do_submit input ?cropping ~upload () ] @@ -99,7 +99,7 @@ val bind_submit : Dom_html.inputElement Js.t Eliom_client_value.t -> #Dom_html.eventTarget Js.t Eliom_client_value.t -> ?cropping:cropping - -> upload:'a upload + -> upload:unit upload -> after_submit:(unit -> unit Lwt.t) -> unit -> unit @@ -113,7 +113,7 @@ val bind : -> preview:Dom_html.imageElement Js.t -> ?crop:(unit -> unit) * cropping -> submit:#Dom_html.eventTarget Js.t Eliom_client_value.t - -> upload:'a upload + -> upload:unit upload -> after_submit:(unit -> unit Lwt.t) -> unit -> unit @@ -150,7 +150,7 @@ val mk_form : -> ?submit: [< Html_types.button_attrib > `Class] Eliom_content.Html.attrib list * [< Html_types.button_content_fun] Eliom_content.Html.elt list - -> 'a upload + -> unit upload -> [> `Form] Eliom_content.Html.elt Lwt.t (** Ready-to-use form. Customizable with [input], the input button content, [submit], the submit button content. diff --git a/src/widgets/ot_pulltorefresh.eliom b/src/widgets/ot_pulltorefresh.eliom index 23aaf803..397bc07d 100644 --- a/src/widgets/ot_pulltorefresh.eliom +++ b/src/widgets/ot_pulltorefresh.eliom @@ -4,10 +4,11 @@ type state = Pulling | Ready | Loading | Succeeded | Failed [%%client open Eliom_content.Html] -open Eliom_content.Html.D +module H = Eliom_content.Html +open H.D -let%shared default_header = - let open Eliom_content.Html in +let%shared default_header : state option -> [> `Div] H.elt list = + let open H in function | Some Loading -> [F.div ~a:[F.a_class ["ot-icon-animation-spinning"]] []] | _ -> [] @@ -19,7 +20,7 @@ open Lwt.Syntax module type CONF = sig val dragThreshold : float val scale : float - val container : Html_types.div Eliom_content.Html.D.elt + val container : Html_types.div H.D.elt val set_state : ?step:React.step -> state option -> unit val timeout : float val afterPull : unit -> bool Lwt.t @@ -168,13 +169,13 @@ module Make (Conf : CONF) = struct end] let make - ?(a = []) + ?(a : [< Html_types.div_attrib > `Class] H.attrib list = []) ?(app_only = true) ?(scale = 5.) ?(dragThreshold = 80.) ?(refresh_timeout = 20.) ?(header = [%shared default_header]) - ~content + ~(content : Html_types.div_content H.elt) (afterPull : (unit -> bool Lwt.t) Eliom_client_value.t) = if app_only && not (Eliom_client.is_client_app ()) @@ -182,10 +183,10 @@ let make else let state_s, set_state = Eliom_shared.React.S.create None in let headContainer = - Eliom_content.Html.R.node + H.R.node @@ Eliom_shared.React.S.map [%shared - let open Eliom_content.Html in + let open H in fun s -> D.div ~a:[D.a_class ["ot-pull-refresh-head-container"]] @@ Eliom_shared.Value.local ~%header @@ -209,5 +210,6 @@ let make let module Ptr = Make (Ptr_conf) in Ptr.init () : unit)]; - let open Eliom_content.Html in - F.div ~a:(F.a_class ["ot-pull-refresh-wrapper"] :: a) [container] + let open H in + (F.div ~a:(F.a_class ["ot-pull-refresh-wrapper"] :: a) [container] + :> [> `Div] elt) diff --git a/src/widgets/ot_pulltorefresh.eliomi b/src/widgets/ot_pulltorefresh.eliomi index c45d0054..331d5b42 100644 --- a/src/widgets/ot_pulltorefresh.eliomi +++ b/src/widgets/ot_pulltorefresh.eliomi @@ -20,13 +20,11 @@ val make : -> ?dragThreshold:float -> ?refresh_timeout:float -> ?header: - (state option - -> ([< Html_types.div_content_fun > `Div] as 'a) Eliom_content.Html.elt - list) + (state option -> Html_types.div_content Eliom_content.Html.elt list) Eliom_shared.Value.t - -> content:'a Eliom_content.Html.elt + -> content:Html_types.div_content Eliom_content.Html.elt -> (unit -> bool Lwt.t) Eliom_client_value.t - -> 'a Eliom_content.Html.elt + -> [> `Div] Eliom_content.Html.elt (** Creates a pull-to-refresh container from an html element. [?a] is the attribute array of the returned element diff --git a/src/widgets/ot_swipe.eliom b/src/widgets/ot_swipe.eliom index d17f739f..3112f344 100644 --- a/src/widgets/ot_swipe.eliom +++ b/src/widgets/ot_swipe.eliom @@ -107,11 +107,11 @@ let%shared (Dom_html.touchEvent Js.t -> int -> unit) Eliom_client_value.t option) ?(onend : (Dom_html.touchEvent Js.t -> int -> unit) Eliom_client_value.t option) - (elt : _ elt) + (elt : Html_types.div_content elt) = ignore [%client - (let elt = ~%elt in + (let elt = (~%elt :> Html_types.div_content elt) in let elt' = To_dom.of_element elt in let startx = ref 0. diff --git a/src/widgets/ot_swipe.eliomi b/src/widgets/ot_swipe.eliomi index e3103a21..7ba988b7 100644 --- a/src/widgets/ot_swipe.eliomi +++ b/src/widgets/ot_swipe.eliomi @@ -11,7 +11,7 @@ val bind : -> ?onstart:(Dom_html.touchEvent Js.t -> int -> unit) Eliom_client_value.t -> ?onmove:(Dom_html.touchEvent Js.t -> int -> unit) Eliom_client_value.t -> ?onend:(Dom_html.touchEvent Js.t -> int -> unit) Eliom_client_value.t - -> 'a Eliom_content.Html.elt + -> Html_types.div_content Eliom_content.Html.elt -> unit (** [bind ~compute_final_pos elt] makes [elt] left-right diff --git a/src/widgets/ot_tongue.eliomi b/src/widgets/ot_tongue.eliomi index 49e5de53..025eb61d 100644 --- a/src/widgets/ot_tongue.eliomi +++ b/src/widgets/ot_tongue.eliomi @@ -25,7 +25,7 @@ val tongue : -> ?side:[`Bottom | `Left | `Right | `Top] -> ?stops:stop list -> ?init:simple_stop - -> ?handle:[> `Div] Eliom_content.Html.elt + -> ?handle:Html_types.div_content Eliom_content.Html.elt -> ?update:simple_stop React.event Eliom_client_value.t -> [< Html_types.div_content_fun] Eliom_content.Html.elt list -> tongue