@colisweb/rescript-toolkit 2.67.0 → 2.67.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/.gitlab-ci.yml +3 -2
  2. package/.yarn/cache/boolbase-npm-1.0.0-965fe9af6d-3e25c80ef6.zip +0 -0
  3. package/.yarn/cache/camelcase-npm-3.0.0-0c65af0c7f-ae4fe1c17c.zip +0 -0
  4. package/.yarn/cache/comma-separated-tokens-npm-1.0.8-00dbbf3418-0adcb07174.zip +0 -0
  5. package/.yarn/cache/css-selector-parser-npm-1.4.1-b8c642c4c5-31948754e5.zip +0 -0
  6. package/.yarn/cache/fault-npm-2.0.1-c462630f58-c9b30f47d9.zip +0 -0
  7. package/.yarn/cache/format-npm-0.2.2-679f3acc64-646a60e133.zip +0 -0
  8. package/.yarn/cache/github-slugger-npm-2.0.0-3afba76e6c-250375cde2.zip +0 -0
  9. package/.yarn/cache/hast-util-has-property-npm-1.0.4-a09b607810-23025cee66.zip +0 -0
  10. package/.yarn/cache/hast-util-has-property-npm-2.0.1-aa6919669c-cc909b7e29.zip +0 -0
  11. package/.yarn/cache/hast-util-heading-rank-npm-2.1.1-0d71da5801-a49233e9ac.zip +0 -0
  12. package/.yarn/cache/hast-util-is-element-npm-1.1.0-be10e62fa7-30fad3f65e.zip +0 -0
  13. package/.yarn/cache/hast-util-is-element-npm-2.1.3-3051d610ff-9d988f6839.zip +0 -0
  14. package/.yarn/cache/hast-util-select-npm-1.0.1-115974f390-9cdb20850f.zip +0 -0
  15. package/.yarn/cache/hast-util-to-string-npm-2.0.0-c6108aa2b8-0c087f8dee.zip +0 -0
  16. package/.yarn/cache/hast-util-to-text-npm-3.1.2-922eb1f623-d17cf3344c.zip +0 -0
  17. package/.yarn/cache/hast-util-whitespace-npm-1.0.4-43bb1ff3d0-b7f4a1942b.zip +0 -0
  18. package/.yarn/cache/{husky-npm-8.0.2-46c70b41ed-e101656fcb.zip → husky-npm-8.0.3-b0b59c5127-837bc7e441.zip} +0 -0
  19. package/.yarn/cache/lowlight-npm-2.8.0-c65abb6cac-c45a91e715.zip +0 -0
  20. package/.yarn/cache/not-npm-0.1.0-a1712708cd-8043bb53bc.zip +0 -0
  21. package/.yarn/cache/nth-check-npm-1.0.2-3f6d0d22eb-59e115fdd7.zip +0 -0
  22. package/.yarn/cache/property-information-npm-3.2.0-ae434c241d-ed2614520d.zip +0 -0
  23. package/.yarn/cache/rehype-add-classes-npm-1.0.0-ddf6b4e74d-25c0e2dbf5.zip +0 -0
  24. package/.yarn/cache/rehype-autolink-headings-npm-6.1.1-fe8058cc11-60782fb2e5.zip +0 -0
  25. package/.yarn/cache/rehype-highlight-npm-6.0.0-5179257139-5a70e7ad45.zip +0 -0
  26. package/.yarn/cache/rehype-slug-npm-5.1.0-ae08840ba8-2a7c17fd74.zip +0 -0
  27. package/.yarn/cache/space-separated-tokens-npm-1.1.5-2352c83473-8ef68f1cfa.zip +0 -0
  28. package/.yarn/cache/unist-util-find-after-npm-4.0.0-11b3b7fb4f-8381ef0bad.zip +0 -0
  29. package/.yarn/cache/zwitch-npm-1.0.5-5911cef6ce-28a1bebaca.zip +0 -0
  30. package/.yarn/install-state.gz +0 -0
  31. package/package.json +8 -5
  32. package/playground/{App.res → PlaygroundApp.res} +14 -7
  33. package/playground/PlaygroundComponents.res +109 -0
  34. package/playground/PlaygroundLocales.res +1 -0
  35. package/playground/PlaygroundRouter.res +23 -0
  36. package/playground/{CodeBlock.res → Playground_CodeBlock.res} +12 -16
  37. package/playground/{stories/IntroductionColors.stories.mdx → design/DesignSystem_Colors.mdx} +0 -0
  38. package/playground/{stories/IntroductionFonts.stories.mdx → design/DesignSystem_Fonts.mdx} +0 -0
  39. package/playground/{stories/IntroductionMediaQueries.stories.mdx → design/DesignSystem_MediaQueries.mdx} +0 -0
  40. package/playground/design/Playground_DesignSystem.res +12 -0
  41. package/playground/{stories/TailwindConfigBreakpoints.js → design/TailwindConfigBreakpoints.jsx} +1 -1
  42. package/playground/{stories/TailwindConfigColorsPreview.js → design/TailwindConfigColorsPreview.jsx} +1 -1
  43. package/playground/{stories/TailwindConfigFontsPreview.js → design/TailwindConfigFontsPreview.jsx} +1 -1
  44. package/playground/docs/ApiDecoding.mdx +70 -0
  45. package/playground/docs/Form.mdx +109 -0
  46. package/playground/docs/Identifiers.mdx +38 -0
  47. package/playground/{Doc.res → docs/Playground_Docs.res} +8 -8
  48. package/playground/docs/Primitives.mdx +53 -0
  49. package/playground/docs/Request.mdx +281 -0
  50. package/playground/docs/Router.mdx +43 -0
  51. package/playground/docs/Setup.mdx +58 -0
  52. package/playground/docs/Unleash.mdx +53 -0
  53. package/playground/main.jsx +1 -1
  54. package/src/intl/Toolkit__Intl.res +5 -9
  55. package/src/intl/Toolkit__Intl.resi +1 -0
  56. package/src/logger/Toolkit__BrowserLogger.res +15 -15
  57. package/src/tailwind/tailwind.config.cjs +3 -5
  58. package/vite.config.js +43 -1
  59. package/.yarn/cache/cosmiconfig-npm-7.0.0-b9d0d7d156-6801feaa02.zip +0 -0
  60. package/.yarn/cache/import-fresh-npm-3.3.0-3e34265ca9-2cacfad06e.zip +0 -0
  61. package/.yarn/cache/klona-npm-2.0.4-6bc4e7cd86-abc6690882.zip +0 -0
  62. package/.yarn/cache/postcss-loader-npm-4.2.0-f01fec2503-c45ec1ca1b.zip +0 -0
  63. package/.yarn/cache/semver-npm-7.3.4-4c3baf0ead-96451bfd7c.zip +0 -0
  64. package/playground/Playground_Component.res +0 -33
  65. package/playground/Playground_ComponentDetails.res +0 -25
  66. package/playground/Playground_ComponentsList.res +0 -43
package/.gitlab-ci.yml CHANGED
@@ -47,7 +47,7 @@ publish rescript-toolkit:
47
47
  # -----------------------------------------------
48
48
  pages:
49
49
  image: node:16-bullseye
50
- extends: .rules-only-for-tags
50
+ extends: .rules-only-for-master
51
51
  tags:
52
52
  - aws
53
53
  stage: deploy
@@ -55,9 +55,10 @@ pages:
55
55
  - export NPM_TOKEN=${NPM_TOKEN:-undefined}
56
56
  - yarn
57
57
  - yarn build
58
+ - cp -a dist/. public/
58
59
  artifacts:
59
60
  paths:
60
- - dist
61
+ - public
61
62
  cache:
62
63
  key: "yarn-$CI_COMMIT_REF_SLUG"
63
64
  paths:
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@colisweb/rescript-toolkit",
3
- "version": "2.67.0",
3
+ "version": "2.67.1",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "clean": "rescript clean",
@@ -59,8 +59,7 @@
59
59
  "lenses-ppx": "6.1.10",
60
60
  "list-selectors": "2.0.1",
61
61
  "lodash": "4.17.21",
62
- "postcss": "8.4.19",
63
- "postcss-loader": "4.2.0",
62
+ "postcss": "8.4.21",
64
63
  "postcss-preset-env": "7.8.3",
65
64
  "prismjs": "1.29.0",
66
65
  "react": "18.2.0",
@@ -95,12 +94,16 @@
95
94
  "@vitejs/plugin-react": "^3.0.0",
96
95
  "babel-loader": "8.2.5",
97
96
  "highlight.js": "11.7.0",
98
- "husky": "8.0.2",
97
+ "husky": "8.0.3",
99
98
  "is-ci": "3.0.1",
100
99
  "raw-loader": "4.0.2",
101
100
  "react-is": "18.2.0",
101
+ "rehype-add-classes": "^1.0.0",
102
+ "rehype-autolink-headings": "^6.1.1",
103
+ "rehype-highlight": "^6.0.0",
104
+ "rehype-slug": "^5.1.0",
102
105
  "sass": "1.56.1",
103
- "vite": "^4.0.0"
106
+ "vite": "4.0.4"
104
107
  },
105
108
  "packageManager": "yarn@3.3.1"
106
109
  }
@@ -72,18 +72,25 @@ let make = () => {
72
72
  <PlaygroundRouter.Breadcrumb />
73
73
  <div className="p-4">
74
74
  {switch currentRoute {
75
- | Home => <Doc.Setup />
75
+ | Home => <Playground_Docs.Setup />
76
76
  | Docs(doc) =>
77
77
  switch doc {
78
- | Identifiers => <Doc.Identifiers />
79
- | ApiDecoding => <Doc.ApiDecoding />
80
- | Form => <Doc.Form />
81
- | Requests => <Doc.Requests />
78
+ | Identifiers => <Playground_Docs.Identifiers />
79
+ | ApiDecoding => <Playground_Docs.ApiDecoding />
80
+ | Form => <Playground_Docs.Form />
81
+ | Requests => <Playground_Docs.Requests />
82
82
  }
83
+ | DesignSystem(_route) => React.null
84
+ // switch route {
85
+ // | Fonts => <Playground_DesignSystem.Fonts />
86
+ // | Colors => <Playground_DesignSystem.Colors />
87
+ // | MediaQueries => <Playground_DesignSystem.MediaQueries />
88
+ // }
89
+
83
90
  | Components(component) =>
84
91
  switch component {
85
- | List => <Playground_ComponentsList />
86
- | Details(component) => <Playground_ComponentDetails component />
92
+ | List => <PlaygroundComponents.List />
93
+ | Details(component) => <PlaygroundComponents.Details component />
87
94
  }
88
95
 
89
96
  | NotFound => "NotFound"->React.string
@@ -0,0 +1,109 @@
1
+ module type Config = {
2
+ let resi: string
3
+ let codeExample: string
4
+ @react.component
5
+ let make: unit => React.element
6
+ }
7
+
8
+ let components: array<(string, module(Config))> = [
9
+ ("card", module(Playground_Card)),
10
+ ("switch", module(Playground_Switch)),
11
+ ]
12
+
13
+ module List = {
14
+ module ComponentLink = {
15
+ @react.component
16
+ let make = (~name) => {
17
+ <PlaygroundRouter.Link
18
+ route={Components(Details(name))}
19
+ className="p-4 rounded-lg border bg-white hover:border-primary-700 w-64">
20
+ <strong className="capitalize"> {name->React.string} </strong>
21
+ </PlaygroundRouter.Link>
22
+ }
23
+ }
24
+
25
+ @react.component
26
+ let make = () => {
27
+ let (search, setSearch) = React.useState(() => "")
28
+
29
+ <div>
30
+ <h1 className="text-4xl font-bold font-display mb-4 flex flex-row gap-4 items-center">
31
+ {"Components"->React.string}
32
+ <input
33
+ type_="search"
34
+ placeholder="Search"
35
+ value={search}
36
+ onChange={event => {
37
+ let target = event->ReactEvent.Form.target
38
+
39
+ setSearch(_ => target["value"])
40
+ }}
41
+ className="bg-white text-sm font-sans px-4 font-normal rounded-md border border-neutral-300 focus:border-primary-700 h-10 w-60"
42
+ />
43
+ </h1>
44
+ <div className="flex flex-row flex-wrap gap-4">
45
+ {components
46
+ ->Array.keep(((name, _)) => name->Js.String2.toLowerCase->Js.String2.includes(search))
47
+ ->Array.map(((name, _)) => <ComponentLink name key={name} />)
48
+ ->React.array}
49
+ </div>
50
+ </div>
51
+ }
52
+ }
53
+
54
+ module Details = {
55
+ module Component = {
56
+ @react.component
57
+ let make = (~component: module(Config)) => {
58
+ let module(Config) = component
59
+ <div>
60
+ <ReachUi.Tabs>
61
+ <ReachUi.TabList className="mb-4">
62
+ <ReachUi.Tab> {"Example"->React.string} </ReachUi.Tab>
63
+ <ReachUi.Tab> {"Code example"->React.string} </ReachUi.Tab>
64
+ <ReachUi.Tab> {"API"->React.string} </ReachUi.Tab>
65
+ </ReachUi.TabList>
66
+ <ReachUi.TabPanels>
67
+ <ReachUi.TabPanel>
68
+ <Config />
69
+ </ReachUi.TabPanel>
70
+ <ReachUi.TabPanel>
71
+ <Playground_CodeBlock code={Config.codeExample} />
72
+ </ReachUi.TabPanel>
73
+ <ReachUi.TabPanel>
74
+ <Playground_CodeBlock code={Config.resi} />
75
+ </ReachUi.TabPanel>
76
+ </ReachUi.TabPanels>
77
+ </ReachUi.Tabs>
78
+ </div>
79
+ }
80
+ }
81
+
82
+ @react.component
83
+ let make = (~component: string) => {
84
+ PlaygroundRouter.Breadcrumb.use([
85
+ {
86
+ route: Components(List),
87
+ text: "Components"->React.string,
88
+ },
89
+ {
90
+ route: Components(Details(component)),
91
+ text: <span className="capitalize"> {`${component}`->React.string} </span>,
92
+ },
93
+ ])
94
+ <div>
95
+ <h1 className="text-4xl font-bold font-display mb-4 capitalize">
96
+ {component->React.string}
97
+ </h1>
98
+ <div>
99
+ {components
100
+ ->Array.getBy(((name, _)) => {
101
+ component === name
102
+ })
103
+ ->Option.mapWithDefault("unknown"->React.string, ((_, playgroundModule)) => {
104
+ <Component component={playgroundModule} />
105
+ })}
106
+ </div>
107
+ </div>
108
+ }
109
+ }
@@ -6,4 +6,5 @@ include Toolkit.Intl.Make({
6
6
  fr: Array.concatMany([toolkitLocalesFr]),
7
7
  }
8
8
  let defaultLocale = None
9
+ let onError = msg => Js.log(msg)
9
10
  })
@@ -8,10 +8,16 @@ module RouterConfig = {
8
8
  | Requests
9
9
  | Form
10
10
 
11
+ type designRoutes =
12
+ | Fonts
13
+ | Colors
14
+ | MediaQueries
15
+
11
16
  type t =
12
17
  | Home
13
18
  | Docs(docRoutes)
14
19
  | Components(componentRoutes)
20
+ | DesignSystem(designRoutes)
15
21
  | NotFound
16
22
 
17
23
  let make = (url: RescriptReactRouter.url) => {
@@ -25,6 +31,13 @@ module RouterConfig = {
25
31
  | list{"requests"} => Docs(Requests)
26
32
  | _ => NotFound
27
33
  }
34
+ | list{"design", ...rest} =>
35
+ switch rest {
36
+ | list{"fonts"} => DesignSystem(Fonts)
37
+ | list{"colors"} => DesignSystem(Colors)
38
+ | list{"mediaQueries"} => DesignSystem(MediaQueries)
39
+ | _ => NotFound
40
+ }
28
41
  | list{"components", ...rest} =>
29
42
  switch rest {
30
43
  | list{} => Components(List)
@@ -50,6 +63,16 @@ module RouterConfig = {
50
63
  }
51
64
  }
52
65
 
66
+ | DesignSystem(designRoute) => {
67
+ let base = "/design"
68
+
69
+ switch designRoute {
70
+ | Fonts => `${base}/fonts`
71
+ | Colors => `${base}/colors`
72
+ | MediaQueries => `${base}/mediaQueries`
73
+ }
74
+ }
75
+
53
76
  | Components(route) => {
54
77
  let base = "/components"
55
78
 
@@ -3,34 +3,30 @@ module HighlightJs = {
3
3
  external registerLanguage: (string, 'a) => unit = "registerLanguage"
4
4
  @module("highlight.js") @scope("default")
5
5
  external highlightAll: unit => unit = "highlightAll"
6
+
7
+ type result = {value: string}
8
+ @module("highlight.js") @scope("default")
9
+ external highlight: (string, 'a) => result = "highlight"
6
10
  }
7
11
 
8
12
  @module("../../../playground/utils/rescript-highlight")
9
13
  external rescriptModule: 'a = "default"
10
- @module("highlight.js/lib/languages/bash")
11
- external bashModule: 'a = "default"
12
- @module("highlight.js/lib/languages/javascript")
13
- external javascriptModule: 'a = "default"
14
14
 
15
15
  HighlightJs.registerLanguage("rescript", rescriptModule)
16
- HighlightJs.registerLanguage("bash", bashModule)
17
- HighlightJs.registerLanguage("js", javascriptModule)
18
16
 
19
17
  @react.component
20
- let make = (~children, ~className="") => {
21
- React.useEffect0(() => {
22
- HighlightJs.highlightAll()
23
-
24
- None
25
- })
26
-
18
+ let make = (~code) => {
27
19
  <div className="Code border rounded-lg mb-6 relative">
28
20
  <pre className="p-4">
29
- <code className={className}> {children} </code>
21
+ <code
22
+ dangerouslySetInnerHTML={
23
+ "__html": HighlightJs.highlight(code, {"language": "rescript"}).value,
24
+ }
25
+ />
30
26
  </pre>
31
27
  <button
32
- className="absolute right-0 bottom-0 bg-white rounded-tl rounded-br text-sm px-2 border-t border-l hover:bg-neutral-200"
33
- onClick={_ => Browser.Navigator.Clipboard.writeText(Obj.magic(children))}>
28
+ className="absolute right-0 top-0 bg-white rounded-tl rounded-br text-sm px-2 border-b border-l hover:bg-neutral-200"
29
+ onClick={_ => Browser.Navigator.Clipboard.writeText(Obj.magic(code))}>
34
30
  {"Copy"->React.string}
35
31
  </button>
36
32
  </div>
@@ -0,0 +1,12 @@
1
+ module Fonts = {
2
+ @module("../../../../playground/design/DesignSystem_Fonts.mdx") @react.component
3
+ external make: unit => React.element = "default"
4
+ }
5
+ module Colors = {
6
+ @module("../../../../playground/design/DesignSystem_Colors.mdx") @react.component
7
+ external make: unit => React.element = "default"
8
+ }
9
+ module MediaQueries = {
10
+ @module("../../../../playground/design/DesignSystem_MediaQueries.mdx") @react.component
11
+ external make: unit => React.element = "default"
12
+ }
@@ -1,4 +1,4 @@
1
- import tailwindConfig from "../src/tailwind/tailwind.config";
1
+ import * as tailwindConfig from "../../src/tailwind/tailwind.config.js";
2
2
 
3
3
  const screens = tailwindConfig.theme.screens;
4
4
 
@@ -1,4 +1,4 @@
1
- import tailwindConfig from "../../src/tailwind/tailwind.config";
1
+ import * as tailwindConfig from "../../src/tailwind/tailwind.config.js";
2
2
 
3
3
  const colors = tailwindConfig.theme.colors;
4
4
 
@@ -1,4 +1,4 @@
1
- import tailwindConfig from "../src/tailwind/tailwind.config";
1
+ import * as tailwindConfig from "../../src/tailwind/tailwind.config.js";
2
2
 
3
3
  const fontFamily = tailwindConfig.theme.fontFamily;
4
4
  const fontSize = tailwindConfig.theme.fontSize;
@@ -0,0 +1,70 @@
1
+ # Decode content from API result
2
+
3
+ ## API
4
+
5
+ ### Decode an enumeration
6
+
7
+ ```rescript
8
+ module LiftEnum = {
9
+ @deriving(jsConverter)
10
+ type enum = [
11
+ | #withLift
12
+ | #withoutLift
13
+ | #unknown
14
+ ]
15
+ }
16
+
17
+ module Lift = Toolkit.Decoder.Enum(LiftEnum)
18
+
19
+ @decco
20
+ type response = {lift: Lift.t}
21
+ ```
22
+
23
+ ### Decode a date
24
+
25
+ ```rescript
26
+ @decco
27
+ type response = {
28
+ createdAt: Toolkit.Decoder.Date.t
29
+ }
30
+ ```
31
+
32
+ ### Decode unit measure
33
+
34
+ There are 2 options :
35
+
36
+ - the field has the unit like : `19 mm`
37
+ - the field has only the value
38
+
39
+ #### Automatic unit handling
40
+
41
+ ```rescript
42
+ [@decco]
43
+ type response = {
44
+ length: Toolkit.Decoder.UnitMeasure.Dimension.WithUnit.t
45
+ }
46
+ ```
47
+
48
+ #### Known unit
49
+
50
+ ```rescript
51
+ [@decco]
52
+ type response = {
53
+ weight: Toolkit.Decoder.UnitMeasure.Weight.Kg.t
54
+ }
55
+ ```
56
+
57
+ ### Decode an Array written as a String
58
+
59
+ This codec is intended for encoding the array params of API requests of scala services.
60
+
61
+ ```rescript
62
+ @decco
63
+ type params = {
64
+ lengths: Toolkit.Decoder.StringArray<Toolkit.Decoder.UnitMeasure.Dimension.WithUnit.t>
65
+ };
66
+
67
+ let params = {lengths:[#cm(1),#m(40), #km(3)]};
68
+ let encodedParams = params->params_encode; // "1.00 cm,40.00 m,3.00 km"
69
+ let decodedParams = encodedParams->params_decode; // Ok([#cm(1),#m(40),#km(3)])
70
+ ```
@@ -0,0 +1,109 @@
1
+ # Handling forms
2
+
3
+ We have created a fork of [reform@9.8.0](https://github.com/Astrocoders/reform) we had some features :
4
+
5
+ - `onSubmit` must return a `Promise.promise(result('a, 'e))`
6
+ - `SubmitFailed(option('error'))` to the `formState('error)` variant
7
+
8
+ ## Usage
9
+
10
+ ### Define a FormState
11
+
12
+ The module must contains an `error` type and an include of `state` type with `%lenses`
13
+
14
+ ```rescript
15
+ module FormState = {
16
+ type error = ColiswebApi.V5.Store.Contact.CreateContact.Request.error;
17
+ include [%lenses
18
+ type state = {
19
+ firstName: string,
20
+ lastName: string,
21
+ email: string,
22
+ phone1: string,
23
+ phone2: string,
24
+ }
25
+ ];
26
+ };
27
+
28
+ module FormApi = Toolkit.Form.Make(FormState);
29
+ ```
30
+
31
+ ### Use the form in React
32
+
33
+ ```rescript
34
+ // ...
35
+ @react.component
36
+ let make = () => {
37
+
38
+ let initialState =
39
+ FormState.{
40
+ firstName: "",
41
+ lastName: "",
42
+ phone1: "",
43
+ phone2: "",
44
+ email: "",
45
+ };
46
+
47
+ let schema =
48
+ FormApi.Form.Validation.Schema([
49
+ StringNonEmpty(FirstName),
50
+ StringNonEmpty(LastName),
51
+ Email(Email),
52
+ ]);
53
+
54
+ let onSubmit = (form: FormApi.Form.onSubmitAPI) => {
55
+ let {values}: FormApi.Form.state = form.state;
56
+
57
+ ColiswebApi.V5.Store.Contact.CreateContact.Config.exec((
58
+ clientId,
59
+ storeId,
60
+ {
61
+ firstName: values.firstName->OptionUtils.fromString,
62
+ lastName: values.lastName->OptionUtils.fromString,
63
+ email: values.email,
64
+ phone1: values.phone1->OptionUtils.fromString,
65
+ phone2: values.phone2->OptionUtils.fromString,
66
+ },
67
+ ))
68
+ ->Promise.flatMapOk(result =>
69
+ reloadContact()->Promise.map(_ => Ok(result))
70
+ )
71
+ ->Promise.tapOk(_ => hide())
72
+ };
73
+
74
+ let form = FormApi.Form.use(~initialState, ~schema, ~onSubmit, ());
75
+
76
+ <FormApi.Form.Provider value=form>
77
+ <form onSubmit={event => {
78
+ ReactEvent.Synthetic.preventDefault(event);
79
+ form.submit();
80
+ }}>
81
+
82
+ <Form.Field
83
+ field
84
+ render={({handleChange, error, value, validate}) => {
85
+ let isInvalid = error->Option.isSome;
86
+ <>
87
+ <input value onChange={BsReform.Helpers.handleChange(handleChange)} />
88
+
89
+ {
90
+ error->Option.mapWithDefault(React.null, e => <p>e->React.string</p>)
91
+ }
92
+ </>;
93
+ }}
94
+ />;
95
+
96
+ <Button
97
+ type_="submit"
98
+ color=#primary
99
+ isLoading={form.state.formState === Submitting}
100
+ onClick={_ => form.submit()}>
101
+ <FormattedMessage
102
+ id="forms.controls.confirm"
103
+ defaultMessage="Confirm"
104
+ />
105
+ </Button>
106
+ </form>
107
+ </FormApi.Form.Provider>;
108
+ }
109
+ ```
@@ -0,0 +1,38 @@
1
+ # Avoid string type with unique identifiers
2
+
3
+ Convert a string or an int in an opaque type with a decco decoder.
4
+
5
+ ### `string` identifier
6
+
7
+ ```rescript
8
+ module DeliveryId = Toolkit.Identifier.MakeString({});
9
+
10
+ /**
11
+ somewhere
12
+ **/
13
+ @decco
14
+ type response = {
15
+ deliveryId: DeliveryId.t
16
+ };
17
+
18
+ let deliveryId = DeliveryId.make("some-id");
19
+ deliveryId->DeliveryId.toString // "some-id"
20
+ ```
21
+
22
+ ### `int` identifier
23
+
24
+ ```rescript
25
+ module DeliveryId = Toolkit.Identifier.MakeInt({});
26
+
27
+ /**
28
+ somewhere
29
+ **/
30
+ @decco
31
+ type response = {
32
+ deliveryId: DeliveryId.t
33
+ };
34
+
35
+ let deliveryId = DeliveryId.make(12);
36
+ deliveryId->DeliveryId.toString; // "12"
37
+ deliveryId->DeliveryId.toInt; // 12
38
+ ```