@colisweb/rescript-toolkit 2.43.0 → 2.46.0

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.
package/bsconfig.json CHANGED
@@ -23,8 +23,6 @@
23
23
  "suffix": ".bs.js",
24
24
  "namespace": false,
25
25
  "bs-dependencies": [
26
- "bs-css",
27
- "bs-css-emotion",
28
26
  "@rescript/react",
29
27
  "reason-promise",
30
28
  "decco",
package/locale/fr.json ADDED
@@ -0,0 +1,102 @@
1
+ [
2
+ {
3
+ "id": "_05a04636",
4
+ "defaultMessage": "Bin packing",
5
+ "message": "Bin packing"
6
+ },
7
+ {
8
+ "id": "_09d99cb1",
9
+ "defaultMessage": "Mardi",
10
+ "message": "Mardi"
11
+ },
12
+ {
13
+ "id": "_1484eaf0",
14
+ "defaultMessage": "Format requis : 14 chiffres",
15
+ "message": "Format requis : 14 chiffres"
16
+ },
17
+ {
18
+ "id": "_24a9ec30",
19
+ "defaultMessage": "Format requis : 4 caractères ou nombres (exemples : 'A1b2' 'abcd')",
20
+ "message": "Format requis : 4 caractères ou nombres (exemples : 'A1b2' 'abcd')"
21
+ },
22
+ {
23
+ "id": "_29102a96",
24
+ "defaultMessage": "Volume total",
25
+ "message": "Volume total"
26
+ },
27
+ {
28
+ "id": "_337be526",
29
+ "defaultMessage": "Jeudi",
30
+ "message": "Jeudi"
31
+ },
32
+ {
33
+ "id": "_49a79a00",
34
+ "defaultMessage": "Samedi",
35
+ "message": "Samedi"
36
+ },
37
+ {
38
+ "id": "_5689ac4d",
39
+ "defaultMessage": "Masquer le mot de passe",
40
+ "message": "Masquer le mot de passe"
41
+ },
42
+ {
43
+ "id": "_8f8eb0df",
44
+ "defaultMessage": "Vendredi",
45
+ "message": "Vendredi"
46
+ },
47
+ {
48
+ "id": "_90cfad83",
49
+ "defaultMessage": "Mercredi",
50
+ "message": "Mercredi"
51
+ },
52
+ {
53
+ "id": "_9fc912ee",
54
+ "defaultMessage": "Lundi",
55
+ "message": "Lundi"
56
+ },
57
+ {
58
+ "id": "_aaa4996e",
59
+ "defaultMessage": "Dimanche",
60
+ "message": "Dimanche"
61
+ },
62
+ {
63
+ "id": "_c05fffa7",
64
+ "defaultMessage": "Afficher le mot de passe",
65
+ "message": "Afficher le mot de passe"
66
+ },
67
+ {
68
+ "id": "_c98895d1",
69
+ "defaultMessage": "Doit etre un entier positif",
70
+ "message": "Doit etre un entier positif"
71
+ },
72
+ {
73
+ "id": "_d2c9771a",
74
+ "defaultMessage": "Mauvais format (req: {exemple})",
75
+ "message": "Mauvais format (req: {exemple})"
76
+ },
77
+ {
78
+ "id": "_d56f025d",
79
+ "defaultMessage": "Champs requis",
80
+ "message": "Champs requis"
81
+ },
82
+ {
83
+ "id": "_d7f4a16b",
84
+ "defaultMessage": "Ce nom est deja utilisé dans un autre forfait",
85
+ "message": "Ce nom est deja utilisé dans un autre forfait"
86
+ },
87
+ {
88
+ "id": "_dd093040",
89
+ "defaultMessage": "Doit être un entier positif ou un nombre a virgule",
90
+ "message": "Doit être un entier positif ou un nombre a virgule"
91
+ },
92
+ {
93
+ "id": "_e6b5a42a",
94
+ "defaultMessage": "Nbr colis",
95
+ "message": "Nbr colis"
96
+ },
97
+ {
98
+ "id": "clipboard.copied",
99
+ "defaultMessage": "Copied to clipboard",
100
+ "message": "Copied to clipboard"
101
+ }
102
+ ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@colisweb/rescript-toolkit",
3
- "version": "2.43.0",
3
+ "version": "2.46.0",
4
4
  "scripts": {
5
5
  "clean": "rescript clean",
6
6
  "build": "rescript build -with-deps",
@@ -9,7 +9,9 @@
9
9
  "build:reacticons": "node tools/extract-react-icons.js",
10
10
  "build:scss": "node tools/build-scss.js",
11
11
  "storybook": "STORYBOOK=true start-storybook -p 6006 --no-manager-cache",
12
- "build-storybook": "TAILWIND_MODE=build STORYBOOK=true build-storybook"
12
+ "build-storybook": "TAILWIND_MODE=build STORYBOOK=true build-storybook",
13
+ "intl:check": "node src/intl/check.js",
14
+ "intl:extract": "node src/intl/extract.js"
13
15
  },
14
16
  "keywords": [
15
17
  "ReScript",
@@ -21,8 +23,10 @@
21
23
  "author": "Colisweb",
22
24
  "license": "MIT",
23
25
  "dependencies": {
26
+ "@colisweb/bs-react-intl-extractor-bin": "0.12.2",
24
27
  "@colisweb/react-day-picker": "7.4.16",
25
28
  "@colisweb/restorative": "0.5.1",
29
+ "@datadog/browser-rum": "4.14.0",
26
30
  "@reach/accordion": "0.17.0",
27
31
  "@reach/alert-dialog": "0.17.0",
28
32
  "@reach/auto-id": "0.17.0",
@@ -40,8 +44,6 @@
40
44
  "autoprefixer": "10.4.7",
41
45
  "axios": "0.24.0",
42
46
  "bs-axios": "0.0.43",
43
- "bs-css": "13.4.0",
44
- "bs-css-emotion": "2.4.0",
45
47
  "case": "1.6.3",
46
48
  "click-outside-hook": "1.1.0",
47
49
  "copy-to-clipboard": "3.3.1",
@@ -51,12 +53,19 @@
51
53
  "downshift": "5.2.5",
52
54
  "lenses-ppx": "6.1.10",
53
55
  "list-selectors": "2.0.1",
56
+ "lodash": "4.17.21",
54
57
  "postcss": "8.4.14",
55
58
  "postcss-loader": "4.2.0",
56
59
  "postcss-preset-env": "6.7.0",
57
60
  "prismjs": "1.28.0",
61
+ "react": "18.2.0",
62
+ "react-big-calendar": "1.0.1",
58
63
  "react-datepicker": "3.8.0",
64
+ "react-dom": "18.2.0",
65
+ "react-error-boundary": "3.1.4",
66
+ "react-helmet": "6.1.0",
59
67
  "react-icons": "4.4.0",
68
+ "react-intl": "6.0.5",
60
69
  "react-select": "5.4.0",
61
70
  "react-table": "7.8.0",
62
71
  "react-use": "17.4.0",
@@ -68,14 +77,7 @@
68
77
  "rescript-react-update": "5.0.0",
69
78
  "sanitize-html": "2.7.0",
70
79
  "swr": "1.3.0",
71
- "tailwindcss": "3.1.4",
72
- "react-error-boundary": "3.1.4",
73
- "@datadog/browser-rum": "4.14.0",
74
- "react-intl": "6.0.5",
75
- "lodash": "4.17.21",
76
- "react-helmet": "6.1.0",
77
- "react": "18.2.0",
78
- "react-dom": "18.2.0"
80
+ "tailwindcss": "3.1.4"
79
81
  },
80
82
  "devDependencies": {
81
83
  "@babel/core": "7.18.6",
package/src/Toolkit.res CHANGED
@@ -12,3 +12,5 @@ module Form = Toolkit__Form
12
12
  module FormValidationFunctions = Toolkit__FormValidationFunctions
13
13
  module BrowserLogger = Toolkit__BrowserLogger
14
14
  module NativeLogger = Toolkit__NativeLogger
15
+ module Intl = Toolkit__Intl
16
+ module LocalesHelpers = Toolkit__LocalesHelpers
@@ -166,12 +166,8 @@ module Make = (StateLenses: Config) => {
166
166
  | "password" =>
167
167
  <Toolkit__Ui_Tooltip
168
168
  label={showPassword
169
- ? <ReactIntl.FormattedMessage
170
- id="toolkit.hidePassword" defaultMessage="Hide password"
171
- />
172
- : <ReactIntl.FormattedMessage
173
- id="toolkit.showPassword" defaultMessage="Show password"
174
- />}>
169
+ ? <ReactIntl.FormattedMessage defaultMessage="Masquer le mot de passe" />
170
+ : <ReactIntl.FormattedMessage defaultMessage="Afficher le mot de passe" />}>
175
171
  <button
176
172
  type_="button"
177
173
  className="p-1 bg-neutral-300 rounded-r border border-gray-300 text-neutral-800"
@@ -2,20 +2,22 @@ open ReactIntl
2
2
 
3
3
  module Msg = {
4
4
  @@intl.messages
5
- let requiredValue = {defaultMessage: "required value"}
6
- let requiredPosInt = {defaultMessage: "must be a positive integer"}
7
- let requiredPosIntOrFloat = {defaultMessage: "must be a positive integer or float"}
8
- let wrongFormat = {defaultMessage: "Wrong format (req: {exemple})"}
9
- let maxNumberOfPackets = {defaultMessage: "Nb packets"}
10
- let totalVolume = {defaultMessage: "Total volume"}
5
+ let requiredValue = {defaultMessage: "Champs requis"}
6
+ let requiredPosInt = {defaultMessage: "Doit etre un entier positif"}
7
+ let requiredPosIntOrFloat = {
8
+ defaultMessage: "Doit être un entier positif ou un nombre a virgule",
9
+ }
10
+ let wrongFormat = {defaultMessage: "Mauvais format (req: {exemple})"}
11
+ let maxNumberOfPackets = {defaultMessage: "Nbr colis"}
12
+ let totalVolume = {defaultMessage: "Volume total"}
11
13
  let binPacking = {defaultMessage: "Bin packing"}
12
- let vehicleNameAlreadyUsed = {defaultMessage: "This name is already used in another flat rate"}
14
+ let vehicleNameAlreadyUsed = {defaultMessage: "Ce nom est deja utilisé dans un autre forfait"}
13
15
 
14
16
  let requiredAlphanumericMax4 = {
15
- defaultMessage: "required format : 4 characters or numbers (exemples: 'A1b2' 'abcd')",
17
+ defaultMessage: "Format requis : 4 caractères ou nombres (exemples : 'A1b2' 'abcd')",
16
18
  }
17
19
  let required14Digits = {
18
- defaultMessage: "required format : 14 digits",
20
+ defaultMessage: "Format requis : 14 chiffres",
19
21
  }
20
22
  }
21
23
 
@@ -0,0 +1,101 @@
1
+ open ReactIntl
2
+
3
+ type rec messages = {fr: array<translation>}
4
+ and translation = {
5
+ id: string,
6
+ defaultMessage: string,
7
+ message: Js.nullable<string>,
8
+ }
9
+
10
+ let toDict = (translations: array<translation>) =>
11
+ translations->Array.reduce(Js.Dict.empty(), (dict, entry) => {
12
+ dict->Js.Dict.set(
13
+ entry.id,
14
+ entry.message->Js.Nullable.toOption->Option.getWithDefault(entry.defaultMessage),
15
+ )
16
+ dict
17
+ })
18
+
19
+ type availableLanguages = [
20
+ | #fr
21
+ ]
22
+
23
+ let availableLanguagesToString = (availableLanguages: availableLanguages) =>
24
+ switch availableLanguages {
25
+ | #fr => "fr"
26
+ }
27
+
28
+ let availableLanguagesFromString = v =>
29
+ switch v {
30
+ | v if v->Js.String2.includes("fr") => #fr
31
+ | _ => #fr
32
+ }
33
+
34
+ let createIntl = (locale: availableLanguages, messages) => {
35
+ let cache = createIntlCache()
36
+
37
+ createIntl(
38
+ intlConfig(
39
+ ~locale=locale->availableLanguagesToString,
40
+ ~messages,
41
+ ~onError=message => Toolkit__BrowserLogger.error2("create intl error", message),
42
+ (),
43
+ ),
44
+ cache,
45
+ )
46
+ }
47
+
48
+ module type IntlConfig = {
49
+ let messages: messages
50
+ let defaultLocale: option<availableLanguages>
51
+ }
52
+
53
+ module Make = (Config: IntlConfig) => {
54
+ let browserLocale = Browser.Navigator.getBrowserLanguage()
55
+ let locale =
56
+ Config.defaultLocale->Option.getWithDefault(browserLocale->availableLanguagesFromString)
57
+
58
+ let messages = switch locale {
59
+ | #fr => Config.messages.fr->toDict
60
+ }
61
+ let intl = createIntl(locale, messages)
62
+
63
+ type state = {
64
+ locale: availableLanguages,
65
+ intl: Intl.t,
66
+ }
67
+
68
+ type action = SetLocale(availableLanguages)
69
+
70
+ let store = Restorative.createStore({locale: locale, intl: intl}, (_state, action) =>
71
+ switch action {
72
+ | SetLocale(locale) => {
73
+ locale: locale,
74
+ intl: {
75
+ let messages = switch locale {
76
+ | #fr => Config.messages.fr->toDict
77
+ }
78
+ createIntl(locale, messages)
79
+ },
80
+ }
81
+ }
82
+ )
83
+
84
+ let setCurrentLocale = (locale: availableLanguages) => store.dispatch(SetLocale(locale))
85
+
86
+ let useCurrentLocale = () => store.useStore().locale
87
+ let useIntl = () => store.useStore().intl
88
+
89
+ let getDateFnsLocale = locale =>
90
+ switch locale {
91
+ | #fr => BsDateFns.frLocale
92
+ }
93
+
94
+ module Provider = {
95
+ @react.component
96
+ let make = (~children) => {
97
+ let intl = useIntl()
98
+ <RawIntlProvider value=intl> children </RawIntlProvider>
99
+ }
100
+ }
101
+ }
@@ -0,0 +1,33 @@
1
+ type availableLanguages = [
2
+ | #fr
3
+ ]
4
+ type rec messages = {fr: array<translation>}
5
+ and translation = {
6
+ id: string,
7
+ defaultMessage: string,
8
+ message: Js.nullable<string>,
9
+ }
10
+
11
+ let availableLanguagesToString: availableLanguages => string
12
+ let availableLanguagesFromString: string => availableLanguages
13
+
14
+ module type IntlConfig = {
15
+ let messages: messages
16
+ let defaultLocale: option<availableLanguages>
17
+ }
18
+
19
+ module Make: (Config: IntlConfig) =>
20
+ {
21
+ let browserLocale: string
22
+ let locale: availableLanguages
23
+ let intl: ReactIntl.Intl.t
24
+ let useIntl: unit => ReactIntl.Intl.t
25
+ let useCurrentLocale: unit => availableLanguages
26
+ let setCurrentLocale: availableLanguages => unit
27
+ let getDateFnsLocale: availableLanguages => BsDateFns.dateFnsLocale
28
+
29
+ module Provider: {
30
+ @react.component
31
+ let make: (~children: React.element) => React.element
32
+ }
33
+ }
@@ -0,0 +1,35 @@
1
+ open ReactIntl
2
+
3
+ module DatePicker = {
4
+ module Fr = {
5
+ let weekdaysShort = ["Di", "Lun", "Ma", "Me", "Je", "Ve", "Sa"]
6
+
7
+ let months = [
8
+ j`Janvier`,
9
+ j`Février`,
10
+ j`Mars`,
11
+ j`Avril`,
12
+ j`Mai`,
13
+ j`Juin`,
14
+ j`Juillet`,
15
+ j`Août`,
16
+ j`Septembre`,
17
+ j`Octobre`,
18
+ j`Novembre`,
19
+ j`Décembre`,
20
+ ]
21
+
22
+ let firstDayOfWeek = 1
23
+ }
24
+ }
25
+
26
+ module Days = {
27
+ @@intl.messages
28
+ let monday = {defaultMessage: "Lundi"}
29
+ let tuesday = {defaultMessage: "Mardi"}
30
+ let wednesday = {defaultMessage: "Mercredi"}
31
+ let thursday = {defaultMessage: "Jeudi"}
32
+ let friday = {defaultMessage: "Vendredi"}
33
+ let saturday = {defaultMessage: "Samedi"}
34
+ let sunday = {defaultMessage: "Dimanche"}
35
+ }
package/src/intl/check.js CHANGED
@@ -1,25 +1,26 @@
1
- const fs = require('fs')
2
- const cp = require('child_process')
3
- const path = require('path')
1
+ const fs = require("fs");
2
+ const cp = require("child_process");
3
+ const path = require("path");
4
+ const cwd = process.cwd();
5
+ const translations = path.join(cwd, "locale");
4
6
 
5
- const cwd = process.cwd()
6
- const translations = path.join(cwd, 'locale', 'translations')
7
+ const AVAILABLE_LANGUAGES = ["fr"];
7
8
 
8
- const [enMissing, frMissing] = ['en', 'fr'].map((locale) => {
9
- const file = path.join(translations, `${locale}.json`)
10
- const content = JSON.parse(fs.readFileSync(file))
9
+ const missingMessagesLanguages = AVAILABLE_LANGUAGES.map((locale) => {
10
+ const file = path.join(translations, `${locale}.json`);
11
+ const content = JSON.parse(fs.readFileSync(file));
11
12
 
12
- return content.filter((item) => item.message === '').length
13
- })
13
+ return [content.filter((item) => item.message === "").length, locale];
14
+ });
14
15
 
15
- if (enMissing > 0) {
16
- console.log(`=== ⚠️ [EN] There are ${enMissing} messages missing.`)
17
- }
18
-
19
- if (frMissing > 0) {
20
- console.log(`=== ⚠️ [FR] There are ${frMissing} messages missing.`)
21
- }
16
+ missingMessagesLanguages.forEach(([missingMessagesLanguage, language]) => {
17
+ if (missingMessagesLanguage > 0) {
18
+ console.log(
19
+ `=== ⚠️ [${language}] There are ${missingMessagesLanguage} messages missing.`
20
+ );
21
+ }
22
+ });
22
23
 
23
- if (enMissing || frMissing) {
24
- process.exit(1)
24
+ if (missingMessagesLanguages.some(([missingMessages]) => missingMessages > 0)) {
25
+ process.exit(1);
25
26
  }
@@ -0,0 +1,37 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+ const glob = require("glob");
4
+
5
+ const cwd = process.cwd();
6
+ const originFile = path.join(cwd, "locale/translations/fr.json");
7
+ const base = JSON.parse(fs.readFileSync(originFile, "utf8"));
8
+ const dict = base.reduce((acc, value) => {
9
+ acc[value.defaultMessage] = value.message;
10
+ return acc;
11
+ }, {});
12
+ /**
13
+ * Match :
14
+ * - defaultMessage=""
15
+ * - defaultMessage={""}
16
+ * - defaultMessage:
17
+ */
18
+ const pattern = /(defaultMessage(=|:|={|:\s))"(.*?|$)"/g;
19
+
20
+ glob("**/*.res", (err, files) => {
21
+ files.forEach((file) => {
22
+ const filePath = path.join(cwd, file);
23
+ let fileContent = fs.readFileSync(filePath, "utf-8");
24
+ const matches = fileContent.matchAll(pattern);
25
+
26
+ for (const match of matches) {
27
+ let [, , , key] = match;
28
+ let message = dict[key];
29
+
30
+ if (message) {
31
+ fileContent = fileContent.replace(`"${key}"`, `"${message}"`);
32
+ }
33
+ }
34
+
35
+ fs.writeFileSync(filePath, fileContent);
36
+ });
37
+ });
@@ -1,33 +1,44 @@
1
1
  const fs = require("fs");
2
2
  const cp = require("child_process");
3
3
  const path = require("path");
4
-
5
- const locales = ["en", "fr"];
6
-
7
4
  const cwd = process.cwd();
8
5
  const src = path.join(cwd, "src");
9
- const locale = path.join(cwd, "locale");
10
- const toolkit = path.join(cwd, "node_modules/@colisweb/rescript-toolkit/src");
6
+ const localeFolderPath = path.join(cwd, "locale");
7
+
8
+ const AVAILABLE_LANGUAGES = ["fr"];
9
+ const DEFAULT_LANGUAGE = "fr";
10
+
11
+ if (!fs.existsSync(localeFolderPath)) {
12
+ fs.mkdirSync(localeFolderPath);
13
+ }
14
+
11
15
  const bin = path.join(cwd, "node_modules", ".bin", "bs-react-intl-extractor");
12
16
 
13
17
  console.log("=== ⏳ Extracting messages...");
14
18
  const extracted = JSON.parse(
15
- cp.execSync(`${bin} --allow-duplicates ${src} ${locale} ${toolkit}`)
19
+ cp.execSync(`${bin} --allow-duplicates ${src} ${localeFolderPath}`)
16
20
  );
17
21
  console.log("=== ✅ Extracting messages... done.");
18
22
 
19
- for (const locale of locales) {
20
- console.log(`\n=== ⏳ Updating ${locale} translation...`);
21
- const file = path.join(src, "../locale/translations", `${locale}.json`);
23
+ for (const LANGUAGE of AVAILABLE_LANGUAGES) {
24
+ console.log(`\n=== ⏳ Updating ${LANGUAGE} translation...`);
25
+ const file = path.join(src, "../locale", `${LANGUAGE}.json`);
22
26
 
23
27
  let content;
24
28
  try {
25
- content = JSON.parse(fs.readFileSync(file));
29
+ if (fs.existsSync(file)) {
30
+ content = JSON.parse(fs.readFileSync(file));
31
+ } else {
32
+ console.log(
33
+ `=== ⚠️ Translation for ${LANGUAGE} wasn't found. Creating new one.`
34
+ );
35
+ content = [];
36
+ }
26
37
  } catch (error) {
27
38
  console.log(error.code);
28
39
  if (error.code === "ENOENT") {
29
40
  console.log(
30
- `=== ⚠️ Translation for ${locale} wasn't found. Creating new one.`
41
+ `=== ⚠️ Translation for ${LANGUAGE} wasn't found. Creating new one.`
31
42
  );
32
43
  content = [];
33
44
  } else {
@@ -42,11 +53,11 @@ for (const locale of locales) {
42
53
  message:
43
54
  cache[msg.id] && cache[msg.id].message
44
55
  ? cache[msg.id].message
45
- : locale === "en"
56
+ : LANGUAGE === DEFAULT_LANGUAGE
46
57
  ? msg.defaultMessage
47
58
  : "",
48
59
  }));
49
60
 
50
61
  fs.writeFileSync(file, JSON.stringify(messages, null, 2) + "\n");
51
- console.log(`=== ✅ Updating ${locale} translation... done.`);
62
+ console.log(`=== ✅ Updating ${LANGUAGE} translation... done.`);
52
63
  }
@@ -4,39 +4,9 @@ let make = (~children, ~className="", ~size: [#md | #xl]=#md) => {
4
4
  <div
5
5
  className={cx([
6
6
  className,
7
- "flex justify-center items-center rounded-full font-display bg-gray-200",
7
+ "flex justify-center items-center rounded-full font-display bg-gray-200 cw-ButtonGroup",
8
8
  isMd ? "h-6" : "h-10",
9
9
  isMd ? "text-sm" : "text-xl",
10
- {
11
- open Css
12
- style(list{
13
- selector(
14
- "& > button",
15
- list{
16
- whiteSpace(#nowrap),
17
- height(100.->pct),
18
- padding2(~v=0.75->rem, ~h=isMd ? 0.75->rem : 1.->rem),
19
- display(#flex),
20
- alignItems(#center),
21
- justifyContent(#center),
22
- borderRadius(2.->rem),
23
- selector("&:hover", list{backgroundColor("3DDEF3"->hex)}),
24
- },
25
- ),
26
- selector(
27
- "& > button.selected",
28
- list{
29
- background(
30
- linearGradient(
31
- 270.->deg,
32
- list{(0.->pct, "11a3b6"->hex), (100.->pct, "27d0dc"->hex)},
33
- ),
34
- ),
35
- color(white),
36
- },
37
- ),
38
- })
39
- },
40
10
  ])}>
41
11
  children
42
12
  </div>
@@ -79,13 +79,7 @@ module Footer = {
79
79
  @react.component
80
80
  let make = (~className="", ~children=React.null, ~customMinHeight=200) =>
81
81
  <div
82
- className={cx([
83
- className,
84
- "rounded-lg shadow-sm bg-white p-6",
85
- {
86
- open Css
87
- style(list{minHeight(customMinHeight->px)})
88
- },
89
- ])}>
82
+ style={ReactDOMStyle.make(~minHeight=`${customMinHeight->Int.toString}px`, ())}
83
+ className={cx([className, "rounded-lg shadow-sm bg-white p-6"])}>
90
84
  children
91
85
  </div>
@@ -1,19 +1,5 @@
1
1
  type size = [#xs | #sm | #md | #lg]
2
2
 
3
- module Styles = {
4
- open Css
5
-
6
- let label = style(list{
7
- selector("& > input + .checkmark", list{backgroundColor(hex("fff"))}),
8
- selector(
9
- "& > input:checked + .checkmark",
10
- list{backgroundColor(hex("15cbe3")), borderColor(hex("15cbe3"))},
11
- ),
12
- selector("& > input + .checkmark > *", list{opacity(0.)}),
13
- selector("& > input:checked + .checkmark > *", list{opacity(1.)}),
14
- })
15
- }
16
-
17
3
  @react.component
18
4
  let make = (
19
5
  ~value,
@@ -45,8 +31,7 @@ let make = (
45
31
 
46
32
  <label
47
33
  className={cx([
48
- Styles.label,
49
- "items-center",
34
+ "items-center cw-Checkbox",
50
35
  inverseLabel ? "inline-flex flex-row-reverse justify-end" : "flex flex-row",
51
36
  disabled->Option.getWithDefault(false)
52
37
  ? "cursor-not-allowed opacity-75 text-gray-600"
@@ -58,7 +43,7 @@ let make = (
58
43
  type_="checkbox"
59
44
  value
60
45
  ?defaultChecked
61
- className="hidden"
46
+ className="hidden peer"
62
47
  onChange={event => {
63
48
  let target = ReactEvent.Form.target(event)
64
49
  let checked = target["checked"]
@@ -73,7 +58,8 @@ let make = (
73
58
  />
74
59
  <span
75
60
  className={cx([
76
- "checkmark rounded border text-white border-neutral-300 transform transition-all ease-in-out flex items-center justify-center flex-shrink-0",
61
+ "peer-checked:bg-primary-500 peer-checked:border-primary-500",
62
+ "bg-white rounded border text-white border-neutral-300 transform transition-all ease-in-out flex items-center justify-center flex-shrink-0",
77
63
  switch size {
78
64
  | #xs => "w-4 h-4"
79
65
  | #sm => "w-6 h-6"
@@ -2,19 +2,6 @@ type size = [#xs | #sm | #md | #lg | #custom(int)]
2
2
  type color = [#primary | #success | #danger | #neutral]
3
3
  type style = [#default | #colored(color)]
4
4
 
5
- let sizeRule = size => {
6
- let value = switch size {
7
- | #xs => 480
8
- | #sm => 600
9
- | #md => 768
10
- | #lg => 900
11
- | #custom(value) => value
12
- }
13
-
14
- open Css
15
- style(list{width(pct(100.)), important(maxWidth(px(value)))})
16
- }
17
-
18
5
  let modalStyle = (~type_) =>
19
6
  switch type_ {
20
7
  | #default => "rounded"
@@ -51,23 +38,6 @@ let closeIconStyle = (~type_) =>
51
38
  | #colored(_) => "hover:bg-white hover:text-black text-white"
52
39
  }
53
40
 
54
- let blockBody = () => {
55
- open Css
56
- global("body", list{overflow(#hidden)})
57
- }
58
- let resetBody = () => {
59
- open Css
60
- global("body", list{overflow(#auto)})
61
- }
62
- {
63
- open Css
64
- global("[data-reach-dialog-overlay]", list{important(background(rgba(74, 115, 120, #num(0.5))))})
65
- }
66
- {
67
- open Css
68
- global("[data-reach-dialog-content]", list{important(background(transparent))})
69
- }
70
-
71
41
  @react.component
72
42
  let make = (
73
43
  ~isVisible,
@@ -79,7 +49,28 @@ let make = (
79
49
  ~footer=?,
80
50
  ~ariaLabel="",
81
51
  ) =>
82
- <ReachUi.Dialog ariaLabel isOpen=isVisible onDismiss=hide className={sizeRule(size)}>
52
+ <ReachUi.Dialog
53
+ ariaLabel
54
+ isOpen=isVisible
55
+ onDismiss=hide
56
+ style={ReactDOMStyle.make(
57
+ ~maxWidth={
58
+ let value = switch size {
59
+ | #xs => 480
60
+ | #sm => 600
61
+ | #md => 768
62
+ | #lg => 900
63
+ | #custom(value) => value
64
+ }
65
+ `${value->Int.toString}px`
66
+ },
67
+ (),
68
+ )}
69
+ className={cx([
70
+ {
71
+ "w-full "
72
+ },
73
+ ])}>
83
74
  <div className={cx(["bg-white pb-5 z-40 shadow-lg w-full", modalStyle(~type_)])}>
84
75
  <header
85
76
  className={cx([
@@ -4,6 +4,7 @@ type color = [#success | #danger | #warning | #info]
4
4
  let make = (~progression: float, ~color: color=#success) =>
5
5
  <div className="flex flex-row w-full h-2 bg-neutral-300 rounded-lg">
6
6
  <div
7
+ style={ReactDOMStyle.make(~width=`${progression->Float.toString}%`, ())}
7
8
  className={cx([
8
9
  "h-full rounded-lg",
9
10
  switch color {
@@ -12,7 +13,6 @@ let make = (~progression: float, ~color: color=#success) =>
12
13
  | #warning => "bg-warning-500"
13
14
  | #info => "bg-info-500"
14
15
  },
15
- Css.style(list{Css.width(progression->#percent)}),
16
16
  ])}
17
17
  />
18
18
  </div>
@@ -1,20 +1,5 @@
1
1
  type size = [#xs | #sm | #md | #lg]
2
2
 
3
- module Styles = {
4
- open Css
5
-
6
- let label = style(list{
7
- selector("& > input + .checkmark", list{backgroundColor(hex("fff"))}),
8
- selector("& > input:focus + .checkmark", list{unsafe("boxShadow", "0px 0px 4px #15CBE3")}),
9
- selector(
10
- "& > input:checked + .checkmark",
11
- list{backgroundColor(hex("15cbe3")), borderColor(hex("15cbe3"))},
12
- ),
13
- selector("& > input + .checkmark > *", list{opacity(0.)}),
14
- selector("& > input:checked + .checkmark > *", list{opacity(1.)}),
15
- })
16
- }
17
-
18
3
  @react.component
19
4
  let make = (
20
5
  ~value,
@@ -28,7 +13,6 @@ let make = (
28
13
  ) =>
29
14
  <label
30
15
  className={cx([
31
- Styles.label,
32
16
  "flex items-center",
33
17
  disabled->Option.getWithDefault(false)
34
18
  ? "cursor-not-allowed opacity-75 text-gray-600"
@@ -38,7 +22,7 @@ let make = (
38
22
  <input
39
23
  type_="radio"
40
24
  value
41
- className="opacity-0 w-0 h-0"
25
+ className="opacity-0 w-0 h-0 peer"
42
26
  onChange={event => {
43
27
  let target = ReactEvent.Form.target(event)
44
28
  let value = target["value"]
@@ -51,6 +35,8 @@ let make = (
51
35
  />
52
36
  <span
53
37
  className={cx([
38
+ "bg-white peer-focus:shadow-sm peer-focus:shadow-primary-500",
39
+ "peer-checked:border-primary-500 peer-checked:bg-primary-500",
54
40
  "checkmark rounded-full border text-white mr-3 border-neutral-300 transform transition-all ease-in-out flex items-center justify-center",
55
41
  switch size {
56
42
  | #xs => "w-4 h-4"
@@ -38,32 +38,23 @@ let make = (
38
38
  {isVisible && canBeShowed
39
39
  ? <ReachUi.Portal>
40
40
  <div
41
- className={cx([
42
- "absolute w-0 h-0 border-gray-800",
43
- triangleClassName,
44
- {
45
- open Css
46
- style(list{
47
- unsafe("borderLeft", "10px solid transparent !important"),
48
- unsafe("borderRight", "10px solid transparent !important"),
49
- unsafe("borderBottom", "10px solid"),
50
- left(
51
- triggerRect
52
- ->Js.Nullable.toOption
53
- ->Option.mapWithDefault(0, triggerRect =>
54
- triggerRect.left - 10 + triggerRect.width / 2
55
- )
56
- ->px,
57
- ),
58
- top(
59
- triggerRect
60
- ->Js.Nullable.toOption
61
- ->Option.mapWithDefault(0, triggerRect => triggerRect.bottom + scrollY)
62
- ->px,
63
- ),
64
- })
65
- },
66
- ])}
41
+ style={ReactDOMStyle.make(
42
+ ~borderLeft="10px solid transparent",
43
+ ~borderRight="10px solid transparent",
44
+ ~borderBottom="10px solid",
45
+ ~left=`${triggerRect
46
+ ->Js.Nullable.toOption
47
+ ->Option.mapWithDefault(0, triggerRect =>
48
+ triggerRect.left - 10 + triggerRect.width / 2
49
+ )
50
+ ->Int.toString}px`,
51
+ ~top=`${triggerRect
52
+ ->Js.Nullable.toOption
53
+ ->Option.mapWithDefault(0, triggerRect => triggerRect.bottom + scrollY)
54
+ ->Int.toString}px`,
55
+ (),
56
+ )}
57
+ className={cx(["absolute w-0 h-0 border-gray-800", triangleClassName])}
67
58
  />
68
59
  </ReachUi.Portal>
69
60
  : React.null}
@@ -71,10 +62,10 @@ let make = (
71
62
  ? <Toolkit__Ui_Spread props=tooltip>
72
63
  <TooltipPopup
73
64
  label
65
+ style={ReactDOMStyle.make(~maxWidth=`${maxWidth->Int.toString}px`, ())}
74
66
  className={cx([
75
67
  "px-3 py-2 bg-gray-800 rounded text-white text-sm z-40 whitespace-pre-wrap",
76
68
  tooltipClassName,
77
- Css.style(list{Css.maxWidth(maxWidth->Css.px)}),
78
69
  ])}
79
70
  position=centered
80
71
  />
package/src/ui/styles.css CHANGED
@@ -39,12 +39,13 @@ body,
39
39
 
40
40
  [data-reach-dialog-content] {
41
41
  padding: 0 !important;
42
+ background: transparent;
42
43
  margin: 10vh auto;
43
44
  outline: 0;
44
45
  }
45
46
 
46
47
  [data-reach-dialog-overlay] {
47
- background: rgba(0, 0, 0, 0.6);
48
+ background: rgba(74, 115, 120, 0.5);
48
49
  z-index: 40;
49
50
  position: fixed;
50
51
  top: 0;
@@ -376,4 +377,20 @@ input[type=number] {
376
377
  color: #15373a;
377
378
  }
378
379
 
380
+ .cw-ButtonGroup > button {
381
+ @apply whitespace-nowrap h-full px-3 md:px-4 flex items-center justify-center rounded-3xl py-3
382
+ }
383
+ .cw-ButtonGroup > button:hover {
384
+ @apply bg-primary-300
385
+ }
386
+
387
+ .cw-ButtonGroup > button.selected {
388
+ background: linear-gradient(270deg, #11a3b6 0%, #27d0dc 100%);
389
+ color: white;
390
+ }
391
+
392
+ .cw-Checkbox > input:checked + .checkmark > * {
393
+ @apply opacity-100
394
+ }
395
+
379
396
  /* purgecss end ignore */
@@ -56,3 +56,19 @@ external screenWidth: int = "window.screen.width"
56
56
 
57
57
  @val
58
58
  external screenHeight: int = "window.screen.height"
59
+
60
+ module Navigator = {
61
+ type t
62
+
63
+ @val
64
+ external userLanguage: option<string> = "window.navigator.userLanguage"
65
+
66
+ @val external language: option<string> = "window.navigator.language"
67
+
68
+ let getBrowserLanguage = () =>
69
+ switch (userLanguage, language) {
70
+ | (Some(l), _) => l
71
+ | (_, Some(l)) => l
72
+ | (None, None) => "fr"
73
+ }
74
+ }
@@ -36,3 +36,14 @@ module DomElement: {
36
36
  }
37
37
 
38
38
  let innerWidth: int
39
+
40
+ module Navigator: {
41
+ type t
42
+
43
+ @val
44
+ external userLanguage: option<string> = "window.navigator.userLanguage"
45
+
46
+ @val external language: option<string> = "window.navigator.language"
47
+
48
+ let getBrowserLanguage: unit => string
49
+ }
@@ -0,0 +1,5 @@
1
+ @module("shallow-equal")
2
+ external shallowEqualObjects: ('a, 'b) => bool = "shallowEqualObjects"
3
+
4
+ @module("shallow-equal")
5
+ external shallowEqualArrays: (array<'a>, array<'b>) => bool = "shallowEqualArrays"
@@ -28,6 +28,7 @@ module TooltipPopup = {
28
28
  external make: (
29
29
  ~className: string=?,
30
30
  ~position: (triggerRect, triggerRect) => position,
31
+ ~style: ReactDOMStyle.t=?,
31
32
  ~label: React.element,
32
33
  ) => React.element = "TooltipPopup"
33
34
  }