Playground to TypeScript
This commit is contained in:
parent
73114c6a47
commit
c8bb0c2060
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
||||||
node_modules
|
node_modules
|
||||||
|
yarn-error.log
|
||||||
.cache
|
.cache
|
||||||
.merlin
|
.merlin
|
||||||
.parcel-cache
|
.parcel-cache
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 347 KiB |
|
@ -1,8 +0,0 @@
|
||||||
{
|
|
||||||
"packages": [
|
|
||||||
"packages/*"
|
|
||||||
],
|
|
||||||
"npmClient": "yarn",
|
|
||||||
"useWorkspaces": true,
|
|
||||||
"version": "0.0.0"
|
|
||||||
}
|
|
17
package.json
17
package.json
|
@ -1,14 +1,21 @@
|
||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
"devDependencies": {
|
|
||||||
"lerna": "^4.0.0"
|
|
||||||
},
|
|
||||||
"name": "squiggle",
|
"name": "squiggle",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build:lang": "cd packages/squiggle-lang && yarn && yarn build && yarn package",
|
"build:lang": "cd packages/squiggle-lang && yarn && yarn build && yarn package",
|
||||||
"storybook:components": "cd packages/components && yarn && yarn storybook",
|
"storybook:components": "cd packages/components && yarn && yarn storybook",
|
||||||
"build-storybook:components": "cd packages/components && yarn && yarn build-storybook",
|
"build-storybook:components": "cd packages/components && yarn && yarn build-storybook",
|
||||||
"build:components": "cd packages/components && yarn && yarn package"
|
"build:components": "cd packages/components && yarn && yarn package",
|
||||||
|
"build:playground": "cd packages/playground && yarn && yarn parcel-build",
|
||||||
|
"ci:lang": "yarn workspace @squiggle/lang ci",
|
||||||
|
"ci:components": "yarn ci:lang && yarn workspace @squiggle/components ci",
|
||||||
|
"ci:playground": "yarn ci:components && yarn workspace @squiggle/playground ci"
|
||||||
},
|
},
|
||||||
"workspaces": ["packages/*"]
|
"workspaces": [
|
||||||
|
"packages/*"
|
||||||
|
],
|
||||||
|
"resolutions": {
|
||||||
|
"@types/react": "17.0.39"
|
||||||
|
},
|
||||||
|
"packageManager": "yarn@1.22.17"
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@squiggle/lang": "^0.1.9",
|
"@squiggle/lang": "0.1.9",
|
||||||
"@testing-library/jest-dom": "^5.16.2",
|
"@testing-library/jest-dom": "^5.16.2",
|
||||||
"@testing-library/react": "^12.1.2",
|
"@testing-library/react": "^12.1.2",
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
|
@ -20,14 +20,17 @@
|
||||||
"react-vega": "^7.4.4",
|
"react-vega": "^7.4.4",
|
||||||
"tsconfig-paths-webpack-plugin": "^3.5.2",
|
"tsconfig-paths-webpack-plugin": "^3.5.2",
|
||||||
"typescript": "^4.5.5",
|
"typescript": "^4.5.5",
|
||||||
|
"vega": "^5.21.0",
|
||||||
"vega-embed": "^6.20.6",
|
"vega-embed": "^6.20.6",
|
||||||
|
"vega-lite": "^5.2.0",
|
||||||
"web-vitals": "^2.1.4",
|
"web-vitals": "^2.1.4",
|
||||||
"webpack-cli": "^4.9.2"
|
"webpack-cli": "^4.9.2"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"storybook": "cross-env REACT_APP_FAST_REFRESH=false && start-storybook -p 6006 -s public",
|
"storybook": "cross-env REACT_APP_FAST_REFRESH=false && start-storybook -p 6006 -s public",
|
||||||
"build-storybook": "build-storybook -s public",
|
"build-storybook": "build-storybook -s public",
|
||||||
"package": "tsc"
|
"package": "tsc",
|
||||||
|
"ci": "yarn package"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"extends": [
|
"extends": [
|
||||||
|
@ -68,6 +71,9 @@
|
||||||
"@storybook/react": "^6.4.18",
|
"@storybook/react": "^6.4.18",
|
||||||
"webpack": "^5.68.0"
|
"webpack": "^5.68.0"
|
||||||
},
|
},
|
||||||
"main": "dist/lib.js",
|
"resolutions": {
|
||||||
"types": "dist/lib.d.ts"
|
"@types/react": "17.0.39"
|
||||||
|
},
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"types": "dist/index.d.ts"
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"jsx": "react",
|
"jsx": "react",
|
||||||
"noImplicitAny": false,
|
"noImplicitAny": false,
|
||||||
|
"esModuleInterop": true,
|
||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"preserveConstEnums": true,
|
"preserveConstEnums": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,22 +0,0 @@
|
||||||
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2020 Foretold
|
|
||||||
|
|
||||||
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.
|
|
|
@ -1,19 +1,19 @@
|
||||||
# Squiggle
|
# Squiggle Playground
|
||||||
|
|
||||||
This is an experiment DSL/language for making probabilistic estimates.
|
This repository contains the squiggle playground, a small web interface
|
||||||
|
for playing around with squiggle concepts.
|
||||||
|
|
||||||
## DistPlus
|
It depends on `@squiggle/components` and `@squiggle/lang` so both of them will
|
||||||
We have a custom library called DistPlus to handle distributions with additional metadata. This helps handle mixed distributions (continuous + discrete), a cache for a cdf, possible unit types (specific times are supported), and limited domains.
|
need to be packaged for this to work. This can be done from the root directory
|
||||||
|
with
|
||||||
## Running
|
|
||||||
|
|
||||||
Currently it only has a few very simple models.
|
|
||||||
|
|
||||||
```
|
```
|
||||||
yarn
|
yarn build:lang
|
||||||
yarn run start
|
yarn build:components
|
||||||
yarn run parcel
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Expected future setup
|
Then, starting the playground can be done with:
|
||||||
![setup](https://raw.githubusercontent.com/foretold-app/widedomain/master/Screen%20Shot%202020-06-30%20at%208.27.32%20AM.png)
|
|
||||||
|
```
|
||||||
|
yarn parcel
|
||||||
|
```
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 347 KiB |
|
@ -1,54 +0,0 @@
|
||||||
{
|
|
||||||
"name": "probExample",
|
|
||||||
"reason": {
|
|
||||||
"react-jsx": 3
|
|
||||||
},
|
|
||||||
"sources": [
|
|
||||||
{
|
|
||||||
"dir": "src",
|
|
||||||
"subdirs": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"dir": "showcase",
|
|
||||||
"type": "dev",
|
|
||||||
"subdirs": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"dir": "__tests__",
|
|
||||||
"type": "dev",
|
|
||||||
"subdirs": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"bsc-flags": [
|
|
||||||
"-bs-super-errors",
|
|
||||||
"-bs-no-version-header",
|
|
||||||
"-bs-g"
|
|
||||||
],
|
|
||||||
"package-specs": [
|
|
||||||
{
|
|
||||||
"module": "commonjs",
|
|
||||||
"in-source": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"suffix": ".bs.js",
|
|
||||||
"namespace": true,
|
|
||||||
"bs-dependencies": [
|
|
||||||
"@glennsl/bs-jest",
|
|
||||||
"@glennsl/bs-json",
|
|
||||||
"@rescriptbr/reform",
|
|
||||||
"@rescript/react",
|
|
||||||
"bs-css",
|
|
||||||
"bs-css-emotion",
|
|
||||||
"@squiggle/lang",
|
|
||||||
"rationale",
|
|
||||||
"bs-moment",
|
|
||||||
"reschema"
|
|
||||||
],
|
|
||||||
"refmt": 3,
|
|
||||||
"warnings": {
|
|
||||||
"number": "+A-42-48-9-30-4-102"
|
|
||||||
},
|
|
||||||
"ppx-flags": [
|
|
||||||
"lenses-ppx/ppx"
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
# Squiggle
|
|
||||||
|
|
||||||
Squiggle is a DSL for making probabilistic estimations. It is meant
|
|
||||||
to be a programming analogue of the [Guesstimate](https://www.getguesstimate.com/)
|
|
||||||
application.
|
|
||||||
|
|
||||||
There are several use cases for a language that represent uncertainty. Some include
|
|
||||||
writing cost effectiveness analysis, as well as doing accurate forecasting.
|
|
||||||
|
|
||||||
Squiggle is written in [Rescript](https://rescript-lang.org/) and is presented
|
|
||||||
as a website.
|
|
||||||
|
|
||||||
If you wish to try squiggle out, you can visit our [main page](https://squiggle-language.com/).
|
|
||||||
|
|
||||||
## Syntax
|
|
||||||
We use the [Math.js expression language](https://mathjs.org/index.html) for Squiggle.
|
|
||||||
So any expression that's available on Math.js is supported on Squiggle.
|
|
||||||
|
|
||||||
To represent uncertainty, we use a custom DSL called [DistML](https://docs.google.com/document/d/1xlEC8KjchP4PL-KdSxfBJr0UZ9nVMSAlz-rjAQEinyA/edit#).
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
To contribute to this project, we recommend visiting our [Contributing Guide](contributing.md).
|
|
|
@ -1,27 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Squiggle Documentation</title>
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
|
||||||
<meta name="description" content="Description">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
|
|
||||||
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@4/lib/themes/vue.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="app"></div>
|
|
||||||
<script>
|
|
||||||
window.$docsify = {
|
|
||||||
name: 'Squiggle',
|
|
||||||
repo: 'squiggle/lang',
|
|
||||||
loadSidebar: true
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<!-- Docsify v4 -->
|
|
||||||
<script src="//cdn.jsdelivr.net/npm/docsify@4"></script>
|
|
||||||
<!-- CDN files for docsify-katex -->
|
|
||||||
<script src="//cdn.jsdelivr.net/npm/docsify-katex@latest/dist/docsify-katex.js"></script>
|
|
||||||
<!-- or <script src="//cdn.jsdelivr.net/gh/upupming/docsify-katex@latest/dist/docsify-katex.js"></script> -->
|
|
||||||
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/katex@latest/dist/katex.min.css"/>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,5 +0,0 @@
|
||||||
{
|
|
||||||
"devDependencies": {
|
|
||||||
"docsify-cli": "^4.4.3"
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,4 @@
|
||||||
[[redirects]]
|
[[redirects]]
|
||||||
from = "/*"
|
from = "/*"
|
||||||
to = "/index.html"
|
to = "/index.html"
|
||||||
status = 200
|
status = 200
|
||||||
|
|
|
@ -3,48 +3,23 @@
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"homepage": "https://foretold-app.github.io/estiband/",
|
"homepage": "https://foretold-app.github.io/estiband/",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "rescript build",
|
|
||||||
"build:deps": "rescript build -with-deps",
|
|
||||||
"build:style": "tailwind build src/styles/index.css -o src/styles/tailwind.css",
|
|
||||||
"start": "rescript build -w",
|
|
||||||
"clean": "rescript clean",
|
|
||||||
"parcel": "parcel ./src/index.html",
|
"parcel": "parcel ./src/index.html",
|
||||||
"parcel-build": "parcel build ./src/index.html --no-source-maps --no-autoinstall",
|
"parcel-build": "parcel build ./src/index.html --no-source-maps --no-autoinstall --no-scope-hoist",
|
||||||
"showcase": "PORT=12345 parcel showcase/index.html",
|
|
||||||
"server": "moduleserve ./ --port 8000",
|
|
||||||
"predeploy": "parcel build ./src/index.html --no-source-maps --no-autoinstall",
|
|
||||||
"deploy": "gh-pages -d dist",
|
"deploy": "gh-pages -d dist",
|
||||||
"test": "jest",
|
"ci": "yarn parcel-build"
|
||||||
"test:ci": "yarn jest",
|
|
||||||
"watch:test": "jest --watchAll",
|
|
||||||
"watch:s": "yarn jest -- Converter_test --watch"
|
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [],
|
||||||
"BuckleScript",
|
|
||||||
"ReasonReact",
|
|
||||||
"reason-react"
|
|
||||||
],
|
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@glennsl/bs-json": "^5.0.2",
|
"@emotion/react": "^11.8.1",
|
||||||
"@rescript/react": "^0.10.3",
|
|
||||||
"@rescriptbr/reform": "^11.0.1",
|
|
||||||
"@squiggle/lang": "^0.1.9",
|
"@squiggle/lang": "^0.1.9",
|
||||||
"ace-builds": "^1.4.12",
|
"ace-builds": "^1.4.12",
|
||||||
"antd": "^4.18.5",
|
"antd": "^4.18.5",
|
||||||
"autoprefixer": "9.8.8",
|
|
||||||
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
|
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
|
||||||
"binary-search-tree": "0.2.6",
|
"binary-search-tree": "0.2.6",
|
||||||
"bs-ant-design-alt": "2.0.0-alpha.33",
|
|
||||||
"bs-css": "^15.1.0",
|
|
||||||
"bs-css-emotion": "^4.1.0",
|
|
||||||
"bs-moment": "0.6.0",
|
|
||||||
"bsb-js": "1.1.7",
|
|
||||||
"css-loader": "^6.6.0",
|
"css-loader": "^6.6.0",
|
||||||
"d3": "7.3.0",
|
|
||||||
"gh-pages": "2.2.0",
|
"gh-pages": "2.2.0",
|
||||||
"jest": "^25.5.1",
|
|
||||||
"jstat": "1.9.2",
|
"jstat": "1.9.2",
|
||||||
"lenses-ppx": "5.1.0",
|
"lenses-ppx": "5.1.0",
|
||||||
"less": "3.10.3",
|
"less": "3.10.3",
|
||||||
|
@ -53,27 +28,27 @@
|
||||||
"moduleserve": "0.9.1",
|
"moduleserve": "0.9.1",
|
||||||
"moment": "2.24.0",
|
"moment": "2.24.0",
|
||||||
"pdfast": "^0.2.0",
|
"pdfast": "^0.2.0",
|
||||||
"postcss": "^8.4.7",
|
|
||||||
"postcss-cli": "^9.1.0",
|
|
||||||
"rationale": "0.2.0",
|
"rationale": "0.2.0",
|
||||||
"react": "17.0.2",
|
"react": "17.0.2",
|
||||||
"react-ace": "^9.2.0",
|
"react-ace": "^9.2.0",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-use": "^17.3.2",
|
"react-use": "^17.3.2",
|
||||||
"react-vega": "^7.4.4",
|
"react-vega": "^7.4.4",
|
||||||
"reschema": "^2.2.0",
|
|
||||||
"rescript": "^9.1.4",
|
|
||||||
"tailwindcss": "1.2.0",
|
|
||||||
"vega": "*",
|
"vega": "*",
|
||||||
"vega-embed": "6.6.0",
|
"vega-embed": "6.6.0",
|
||||||
"vega-lite": "*"
|
"vega-lite": "*"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@glennsl/bs-jest": "^0.5.1",
|
"@emotion/babel-plugin": "^11.7.2",
|
||||||
"bs-platform": "8.4.2",
|
"@parcel/core": "^2.3.2",
|
||||||
|
"@types/react": "^17.0.39",
|
||||||
|
"autoprefixer": "^10.4.2",
|
||||||
"docsify": "^4.12.2",
|
"docsify": "^4.12.2",
|
||||||
|
"jest": "^27.5.1",
|
||||||
"parcel": "^2.3.2",
|
"parcel": "^2.3.2",
|
||||||
"parcel-plugin-bundle-visualiser": "^1.2.0",
|
"postcss": "^8.4.7",
|
||||||
"parcel-plugin-less-js-enabled": "1.0.2"
|
"postcss-cli": "^9.1.0",
|
||||||
|
"tailwindcss": "^3.0.23",
|
||||||
|
"typescript": "^4.6.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
//postcss.config.js
|
module.exports = {
|
||||||
const tailwindcss = require('tailwindcss');
|
plugins: {
|
||||||
module.exports = {
|
tailwindcss: {},
|
||||||
plugins: [
|
autoprefixer: {},
|
||||||
tailwindcss('./tailwind.js'),
|
},
|
||||||
require('autoprefixer'),
|
}
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
let entries = [];
|
|
|
@ -1,30 +0,0 @@
|
||||||
type compEntry = {
|
|
||||||
mutable id: string,
|
|
||||||
title: string,
|
|
||||||
render: unit => React.element,
|
|
||||||
container: containerType,
|
|
||||||
}
|
|
||||||
and folderEntry = {
|
|
||||||
mutable id: string,
|
|
||||||
title: string,
|
|
||||||
children: list(navEntry),
|
|
||||||
}
|
|
||||||
and navEntry =
|
|
||||||
| CompEntry(compEntry)
|
|
||||||
| FolderEntry(folderEntry)
|
|
||||||
and containerType =
|
|
||||||
| FullWidth
|
|
||||||
| Sidebar;
|
|
||||||
|
|
||||||
let entry = (~title, ~render): navEntry => {
|
|
||||||
CompEntry({id: "", title, render, container: FullWidth});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Maybe different api, this avoids breaking changes
|
|
||||||
let sidebar = (~title, ~render): navEntry => {
|
|
||||||
CompEntry({id: "", title, render, container: Sidebar});
|
|
||||||
};
|
|
||||||
|
|
||||||
let folder = (~title, ~children): navEntry => {
|
|
||||||
FolderEntry({id: "", title, children});
|
|
||||||
};
|
|
|
@ -1,163 +0,0 @@
|
||||||
open EntryTypes
|
|
||||||
|
|
||||||
module HS = Belt.HashMap.String
|
|
||||||
|
|
||||||
let entriesByPath: HS.t<navEntry> = HS.make(~hintSize=100)
|
|
||||||
|
|
||||||
/* Creates unique id's per scope based on title */
|
|
||||||
let buildIds = entries => {
|
|
||||||
let genId = (title, path) => {
|
|
||||||
let noSpaces = Js.String.replaceByRe(%re("/\\s+/g"), "-", title)
|
|
||||||
if !HS.has(entriesByPath, path ++ ("/" ++ noSpaces)) {
|
|
||||||
noSpaces
|
|
||||||
} else {
|
|
||||||
let rec loop = num => {
|
|
||||||
let testId = noSpaces ++ ("-" ++ string_of_int(num))
|
|
||||||
if !HS.has(entriesByPath, path ++ ("/" ++ testId)) {
|
|
||||||
testId
|
|
||||||
} else {
|
|
||||||
loop(num + 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
loop(2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let rec processFolder = (f: folderEntry, curPath) => {
|
|
||||||
f.id = curPath ++ ("/" ++ genId(f.title, curPath))
|
|
||||||
HS.set(entriesByPath, f.id, FolderEntry(f))
|
|
||||||
f.children |> E.L.iter(x =>
|
|
||||||
switch x {
|
|
||||||
| CompEntry(c) => processEntry(c, f.id)
|
|
||||||
| FolderEntry(f) => processFolder(f, f.id)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
and processEntry = (c: compEntry, curPath) => {
|
|
||||||
c.id = curPath ++ ("/" ++ genId(c.title, curPath))
|
|
||||||
HS.set(entriesByPath, c.id, CompEntry(c))
|
|
||||||
}
|
|
||||||
entries |> E.L.iter(x =>
|
|
||||||
switch x {
|
|
||||||
| CompEntry(c) => processEntry(c, "")
|
|
||||||
| FolderEntry(f) => processFolder(f, "")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
let entries = Entries.entries
|
|
||||||
buildIds(entries)
|
|
||||||
|
|
||||||
module Styles = {
|
|
||||||
open CssJs
|
|
||||||
let pageContainer = style(. [ display(#flex), height(#vh(100.)) ])
|
|
||||||
let leftNav = style(. [ padding(#em(2.)),
|
|
||||||
flexBasis(#px(200)),
|
|
||||||
flexShrink(0.),
|
|
||||||
backgroundColor(#hex("eaeff3")),
|
|
||||||
boxShadows([ Shadow.box(~x=px(-1), ~blur=px(1), ~inset=true, rgba(0, 0, 0, #percent(0.1))) ]),
|
|
||||||
])
|
|
||||||
|
|
||||||
let folderNav = style(. [ selector(.
|
|
||||||
">h4",
|
|
||||||
[ cursor(#pointer), margin2(~v=#em(0.3), ~h=#zero), hover([ color(#hex("7089ad")) ]) ],
|
|
||||||
),
|
|
||||||
])
|
|
||||||
let folderChildren = style(. [ paddingLeft(#px(7)) ])
|
|
||||||
let compNav = style(. [ cursor(#pointer),
|
|
||||||
paddingBottom(#px(3)),
|
|
||||||
hover([ color(#hex("7089ad")) ]),
|
|
||||||
])
|
|
||||||
let compContainer = style(. [ padding(#em(2.)), flexGrow(1.) ])
|
|
||||||
// Approximate sidebar container for entry
|
|
||||||
let sidebarContainer = style(. [ maxWidth(#px(430)) ])
|
|
||||||
let folderChildContainer = style(. [ marginBottom(#em(2.)) ])
|
|
||||||
}
|
|
||||||
|
|
||||||
let baseUrl = "/showcase/index.html"
|
|
||||||
|
|
||||||
module Index = {
|
|
||||||
type state = {route: RescriptReactRouter.url}
|
|
||||||
|
|
||||||
type action =
|
|
||||||
| ItemClick(string)
|
|
||||||
| ChangeRoute(RescriptReactRouter.url)
|
|
||||||
|
|
||||||
let changeId = (id: string) => {
|
|
||||||
let _ = RescriptReactRouter.push(baseUrl ++ ("#" ++ id))
|
|
||||||
}
|
|
||||||
|
|
||||||
let buildNav = _ => {
|
|
||||||
let rec buildFolder = (f: folderEntry) =>
|
|
||||||
<div key=f.id className=Styles.folderNav>
|
|
||||||
<h4 onClick={_e => changeId(f.id)}> {f.title->React.string} </h4>
|
|
||||||
<div className=Styles.folderChildren>
|
|
||||||
{(f.children
|
|
||||||
|> E.L.fmap(e =>
|
|
||||||
switch e {
|
|
||||||
| FolderEntry(folder) => buildFolder(folder)
|
|
||||||
| CompEntry(entry) => buildEntry(entry)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|> E.L.toArray)->React.array}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
and buildEntry = (e: compEntry) =>
|
|
||||||
<div key=e.id className=Styles.compNav onClick={_e => changeId(e.id)}>
|
|
||||||
{e.title->React.string}
|
|
||||||
</div>
|
|
||||||
(entries
|
|
||||||
|> E.L.fmap(e =>
|
|
||||||
switch e {
|
|
||||||
| FolderEntry(folder) => buildFolder(folder)
|
|
||||||
| CompEntry(entry) => buildEntry(entry)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|> E.L.toArray)->React.array
|
|
||||||
}
|
|
||||||
|
|
||||||
let renderEntry = e =>
|
|
||||||
switch e.container {
|
|
||||||
| FullWidth => e.render()
|
|
||||||
| Sidebar => <div className=Styles.sidebarContainer> {e.render()} </div>
|
|
||||||
}
|
|
||||||
|
|
||||||
@react.component
|
|
||||||
let make = () => {
|
|
||||||
let (route, setRoute) = React.useState(() => {
|
|
||||||
let url: RescriptReactRouter.url = {path: list{}, hash: "", search: ""}
|
|
||||||
url
|
|
||||||
})
|
|
||||||
|
|
||||||
React.useState(() => {
|
|
||||||
let _ = RescriptReactRouter.watchUrl(url => setRoute(_ => url))
|
|
||||||
}) |> ignore
|
|
||||||
|
|
||||||
<div className=Styles.pageContainer>
|
|
||||||
<div className=Styles.leftNav> {buildNav(setRoute)} </div>
|
|
||||||
<div className=Styles.compContainer>
|
|
||||||
{if route.hash == "" {
|
|
||||||
React.null
|
|
||||||
} else {
|
|
||||||
switch HS.get(entriesByPath, route.hash) {
|
|
||||||
| Some(navEntry) =>
|
|
||||||
switch navEntry {
|
|
||||||
| CompEntry(c) => renderEntry(c)
|
|
||||||
| FolderEntry(f) =>
|
|
||||||
/* Rendering immediate children */
|
|
||||||
(f.children
|
|
||||||
|> E.L.fmap(child =>
|
|
||||||
switch child {
|
|
||||||
| CompEntry(c) =>
|
|
||||||
<div className=Styles.folderChildContainer key=c.id> {renderEntry(c)} </div>
|
|
||||||
| _ => React.null
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|> E.L.toArray)->React.array
|
|
||||||
}
|
|
||||||
| None => <div> {"Component not found"->React.string} </div>
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
switch(ReactDOM.querySelector("main")){
|
|
||||||
| Some(root) => ReactDOM.render(<div> <Lib.Index /> </div>, root)
|
|
||||||
| None => () // do nothing
|
|
||||||
}
|
|
||||||
RescriptReactRouter.push("")
|
|
|
@ -1,24 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
||||||
<link href="https://fonts.googleapis.com/css?family=Lato:300,400,700,900" rel="stylesheet">
|
|
||||||
<link href="https://fonts.googleapis.com/css?family=Lato:300,400,700,900" rel="stylesheet">
|
|
||||||
<link href="../src/styles/index.css" rel="stylesheet">
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<title>Showcase</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div id="main"></div>
|
|
||||||
<script src=" ./ShowcaseIndex.bs.js "></script>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
|
@ -1,6 +0,0 @@
|
||||||
module Input = Antd_Input
|
|
||||||
module Grid = Antd_Grid
|
|
||||||
module Form = Antd_Form
|
|
||||||
module Card = Antd_Card
|
|
||||||
module Button = Antd_Button
|
|
||||||
module IconName = Antd_IconName
|
|
|
@ -1,38 +0,0 @@
|
||||||
|
|
||||||
@deriving(abstract)
|
|
||||||
type props
|
|
||||||
type makeType = props => React.element
|
|
||||||
|
|
||||||
@obj external makeProps:
|
|
||||||
(
|
|
||||||
~disabled: bool=?,
|
|
||||||
~ghost: bool=?,
|
|
||||||
~href: string=?,
|
|
||||||
~htmlType: @string [#button | #submit | #submit]=?,
|
|
||||||
~icon: Antd_IconName.t=?,
|
|
||||||
~shape: @string [#circle | #round]=?,
|
|
||||||
~size: @string [#small | #large]=?,
|
|
||||||
~target: string=?,
|
|
||||||
~loading: bool=?,
|
|
||||||
~_type: @string
|
|
||||||
[
|
|
||||||
| #primary
|
|
||||||
| #default
|
|
||||||
| #dashed
|
|
||||||
| #danger
|
|
||||||
| #link
|
|
||||||
| #ghost
|
|
||||||
]=?,
|
|
||||||
~onClick: ReactEvent.Mouse.t => unit=?,
|
|
||||||
~block: bool=?,
|
|
||||||
~children: React.element=?,
|
|
||||||
~className: string=?,
|
|
||||||
~id: string=?,
|
|
||||||
~testId: string=?,
|
|
||||||
unit
|
|
||||||
) =>
|
|
||||||
props =
|
|
||||||
""
|
|
||||||
|
|
||||||
@module("antd")
|
|
||||||
external make : makeType = "Button"
|
|
|
@ -1,31 +0,0 @@
|
||||||
@deriving(abstract)
|
|
||||||
type props
|
|
||||||
type makeType = props => React.element
|
|
||||||
|
|
||||||
@obj external makeProps: (
|
|
||||||
~actions: array<React.element>=?,
|
|
||||||
~activeTabKey: string=?,
|
|
||||||
~headStyle: ReactDOMStyle.t=?,
|
|
||||||
~bodyStyle: ReactDOMStyle.t=?,
|
|
||||||
~style: ReactDOMStyle.t=?,
|
|
||||||
~bordered: bool=?,
|
|
||||||
~cover: React.element=?,
|
|
||||||
~defaultActiveTabKey: string=?,
|
|
||||||
~extra: React.element=?,
|
|
||||||
~hoverable: bool=?,
|
|
||||||
~loading: bool=?,
|
|
||||||
~tabList: array<{
|
|
||||||
"key": string,
|
|
||||||
"tab": React.element,
|
|
||||||
}>
|
|
||||||
=?,
|
|
||||||
~size: @string [ #default | #small]=?,
|
|
||||||
~title: 'a=?,
|
|
||||||
~_type: string=?,
|
|
||||||
~onTabChange: string => unit=?,
|
|
||||||
~children: React.element=?,
|
|
||||||
unit // This unit is a quirk of the type system. Apparently it must exist to have optional arguments in a type
|
|
||||||
) => props = ""
|
|
||||||
|
|
||||||
@module("antd")
|
|
||||||
external make : makeType = "Card"
|
|
|
@ -1,52 +0,0 @@
|
||||||
|
|
||||||
@deriving(abstract)
|
|
||||||
type props
|
|
||||||
type makeType = props => React.element
|
|
||||||
|
|
||||||
@obj
|
|
||||||
external makeProps:
|
|
||||||
(
|
|
||||||
~onSubmit: ReactEvent.Form.t => unit=?,
|
|
||||||
~hideRequiredMark: bool=?,
|
|
||||||
~id: string=?,
|
|
||||||
~className: string=?,
|
|
||||||
~style: ReactDOMStyle.t=?,
|
|
||||||
~colon: bool=?,
|
|
||||||
~validateStatus: string=?,
|
|
||||||
~extra: string=?,
|
|
||||||
~required: bool=?,
|
|
||||||
~label: string=?,
|
|
||||||
~help: string=?,
|
|
||||||
~hasFeedback: bool=?,
|
|
||||||
~children:React.element=?,
|
|
||||||
unit
|
|
||||||
) =>
|
|
||||||
props =
|
|
||||||
""
|
|
||||||
|
|
||||||
|
|
||||||
@module("antd")
|
|
||||||
external make : makeType = "Form"
|
|
||||||
|
|
||||||
module Item = {
|
|
||||||
type props
|
|
||||||
type makeType = props => React.element
|
|
||||||
@obj
|
|
||||||
external makeProps:
|
|
||||||
(
|
|
||||||
~colon:string=?,
|
|
||||||
~validateStatus:string=?,
|
|
||||||
~extra:string=?,
|
|
||||||
~className:string=?,
|
|
||||||
~required:bool=?,
|
|
||||||
~style:ReactDOMStyle.t=?,
|
|
||||||
~label:string=?,
|
|
||||||
~id:string=?,
|
|
||||||
~help:string=?,
|
|
||||||
~hasFeedback:bool=?,
|
|
||||||
~children:React.element=?,
|
|
||||||
unit
|
|
||||||
) => props = ""
|
|
||||||
@module("antd/lib/form/FormItem")
|
|
||||||
external make : makeType = "default"
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
%%raw(`require("antd/lib/grid/style")`)
|
|
||||||
|
|
||||||
|
|
||||||
module Row = {
|
|
||||||
type props
|
|
||||||
|
|
||||||
@obj
|
|
||||||
external makeProps:
|
|
||||||
(
|
|
||||||
~className: string=?,
|
|
||||||
~_type: string=?,
|
|
||||||
~align: string=?,
|
|
||||||
~justify: string=?,
|
|
||||||
~gutter: 'a=?,
|
|
||||||
~style: ReactDOMStyle.t=?,
|
|
||||||
~prefixCls: string=?,
|
|
||||||
~children: React.element=?,
|
|
||||||
unit
|
|
||||||
) =>
|
|
||||||
props =
|
|
||||||
"";
|
|
||||||
|
|
||||||
type makeType = props => React.element
|
|
||||||
|
|
||||||
@module("antd")
|
|
||||||
external make : makeType = "Row"
|
|
||||||
}
|
|
||||||
|
|
||||||
module Col = {
|
|
||||||
type props
|
|
||||||
|
|
||||||
@obj
|
|
||||||
external makeProps:
|
|
||||||
(
|
|
||||||
~className: string=?,
|
|
||||||
~span: int=?,
|
|
||||||
~order: int=?,
|
|
||||||
~offset: int=?,
|
|
||||||
~push: int=?,
|
|
||||||
~pull: int=?,
|
|
||||||
~xs: 'a=?,
|
|
||||||
~sm: 'b=?,
|
|
||||||
~md: 'c=?,
|
|
||||||
~lg: 'd=?,
|
|
||||||
~xl: 'e=?,
|
|
||||||
~xxl: 'f=?,
|
|
||||||
~prefixCls: string=?,
|
|
||||||
~style: ReactDOMStyle.t=?,
|
|
||||||
~children: React.element=?,
|
|
||||||
unit
|
|
||||||
) =>
|
|
||||||
props =
|
|
||||||
"";
|
|
||||||
|
|
||||||
type makeType = props => React.element
|
|
||||||
|
|
||||||
@module("antd")
|
|
||||||
external make : makeType = "Col"
|
|
||||||
}
|
|
|
@ -1,581 +0,0 @@
|
||||||
type t = string
|
|
||||||
|
|
||||||
let toString = t => t
|
|
||||||
|
|
||||||
let fromString = t => t
|
|
||||||
|
|
||||||
let compare = (t1, t2) => t1 == t2
|
|
||||||
|
|
||||||
let stepBackward = "step-backward"
|
|
||||||
|
|
||||||
let stepForward = "step-forward"
|
|
||||||
|
|
||||||
let fastBackward = "fast-backward"
|
|
||||||
|
|
||||||
let fastForward = "fast-forward"
|
|
||||||
|
|
||||||
let shrink = "shrink"
|
|
||||||
|
|
||||||
let arrowsAlt = "arrows-alt"
|
|
||||||
|
|
||||||
let down = "down"
|
|
||||||
|
|
||||||
let up = "up"
|
|
||||||
|
|
||||||
let left = "left"
|
|
||||||
|
|
||||||
let right = "right"
|
|
||||||
|
|
||||||
let caretUp = "caret-up"
|
|
||||||
|
|
||||||
let caretDown = "caret-down"
|
|
||||||
|
|
||||||
let caretLeft = "caret-left"
|
|
||||||
|
|
||||||
let caretRight = "caret-right"
|
|
||||||
|
|
||||||
let upCircle = "up-circle"
|
|
||||||
|
|
||||||
let downCircle = "down-circle"
|
|
||||||
|
|
||||||
let leftCircle = "left-circle"
|
|
||||||
|
|
||||||
let rightCircle = "right-circle"
|
|
||||||
|
|
||||||
let upCircleO = "up-circle-o"
|
|
||||||
|
|
||||||
let downCircleO = "down-circle-o"
|
|
||||||
|
|
||||||
let rightCircleO = "right-circle-o"
|
|
||||||
|
|
||||||
let leftCircleO = "left-circle-o"
|
|
||||||
|
|
||||||
let doubleRight = "double-right"
|
|
||||||
|
|
||||||
let doubleLeft = "double-left"
|
|
||||||
|
|
||||||
let verticleLeft = "verticle-left"
|
|
||||||
|
|
||||||
let verticleRight = "verticle-right"
|
|
||||||
|
|
||||||
let forward = "forward"
|
|
||||||
|
|
||||||
let backward = "backward"
|
|
||||||
|
|
||||||
let rollback = "rollback"
|
|
||||||
|
|
||||||
let enter = "enter"
|
|
||||||
|
|
||||||
let retweet = "retweet"
|
|
||||||
|
|
||||||
let swap = "swap"
|
|
||||||
|
|
||||||
let swapLeft = "swap-left"
|
|
||||||
|
|
||||||
let swapRight = "swap-right"
|
|
||||||
|
|
||||||
let arrowUp = "arrow-up"
|
|
||||||
|
|
||||||
let arrowDown = "arrow-down"
|
|
||||||
|
|
||||||
let arrowLeft = "arrow-left"
|
|
||||||
|
|
||||||
let arrowRight = "arrow-right"
|
|
||||||
|
|
||||||
let playCircle = "play-circle"
|
|
||||||
|
|
||||||
let playCircleO = "play-circle-o"
|
|
||||||
|
|
||||||
let upSquare = "up-square"
|
|
||||||
|
|
||||||
let downSquare = "down-square"
|
|
||||||
|
|
||||||
let leftSquare = "left-square"
|
|
||||||
|
|
||||||
let rightSquare = "right-square"
|
|
||||||
|
|
||||||
let upSquareO = "up-square-o"
|
|
||||||
|
|
||||||
let downSquareO = "down-square-o"
|
|
||||||
|
|
||||||
let leftSquareO = "left-square-o"
|
|
||||||
|
|
||||||
let rightSquareO = "right-square-o"
|
|
||||||
|
|
||||||
let login = "login"
|
|
||||||
|
|
||||||
let logout = "logout"
|
|
||||||
|
|
||||||
let menuFold = "menu-fold"
|
|
||||||
|
|
||||||
let menuUnfold = "menu-unfold"
|
|
||||||
|
|
||||||
let question = "question"
|
|
||||||
|
|
||||||
let questionCircleO = "question-circle-o"
|
|
||||||
|
|
||||||
let questionCircle = "question-circle"
|
|
||||||
|
|
||||||
let plus = "plus"
|
|
||||||
|
|
||||||
let plusCircleO = "plus-circle-o"
|
|
||||||
|
|
||||||
let plusCircle = "plus-circle"
|
|
||||||
|
|
||||||
let pause = "pause"
|
|
||||||
|
|
||||||
let pauseCircleO = "pause-circle-o"
|
|
||||||
|
|
||||||
let pauseCircle = "pause-circle"
|
|
||||||
|
|
||||||
let minus = "minus"
|
|
||||||
|
|
||||||
let minusCircleO = "minus-circle-o"
|
|
||||||
|
|
||||||
let minusCircle = "minus-circle"
|
|
||||||
|
|
||||||
let plusSquare = "plus-square"
|
|
||||||
|
|
||||||
let plusSquareO = "plus-square-o"
|
|
||||||
|
|
||||||
let minusSquare = "minus-square"
|
|
||||||
|
|
||||||
let minusSquareO = "minus-square-o"
|
|
||||||
|
|
||||||
let info = "info"
|
|
||||||
|
|
||||||
let infoCircleO = "info-circle-o"
|
|
||||||
|
|
||||||
let infoCircle = "info-circle"
|
|
||||||
|
|
||||||
let exclamation = "exclamation"
|
|
||||||
|
|
||||||
let exclamationCircleO = "exclamation-circle-o"
|
|
||||||
|
|
||||||
let exclamationCircle = "exclamation-circle"
|
|
||||||
|
|
||||||
let close = "close"
|
|
||||||
|
|
||||||
let closeCircle = "close-circle"
|
|
||||||
|
|
||||||
let closeCircleO = "close-circle-o"
|
|
||||||
|
|
||||||
let closeSquare = "close-square"
|
|
||||||
|
|
||||||
let closeSquareO = "close-square-o"
|
|
||||||
|
|
||||||
let check = "check"
|
|
||||||
|
|
||||||
let checkCircle = "check-circle"
|
|
||||||
|
|
||||||
let checkCircleO = "check-circle-o"
|
|
||||||
|
|
||||||
let checkSquare = "check-square"
|
|
||||||
|
|
||||||
let checkSquareO = "check-square-o"
|
|
||||||
|
|
||||||
let clockCircleO = "clock-circle-o"
|
|
||||||
|
|
||||||
let clockCircle = "clock-circle"
|
|
||||||
|
|
||||||
let warning = "warning"
|
|
||||||
|
|
||||||
let lock = "lock"
|
|
||||||
|
|
||||||
let unlock = "unlock"
|
|
||||||
|
|
||||||
let areaChart = "area-chart"
|
|
||||||
|
|
||||||
let pieChart = "pie-chart"
|
|
||||||
|
|
||||||
let barChart = "bar-chart"
|
|
||||||
|
|
||||||
let dotChart = "dot-chart"
|
|
||||||
|
|
||||||
let bars = "bars"
|
|
||||||
|
|
||||||
let book = "book"
|
|
||||||
|
|
||||||
let calendar = "calendar"
|
|
||||||
|
|
||||||
let cloud = "cloud"
|
|
||||||
|
|
||||||
let cloudDownload = "cloud-download"
|
|
||||||
|
|
||||||
let code = "code"
|
|
||||||
|
|
||||||
let codeO = "code-o"
|
|
||||||
|
|
||||||
let copy = "copy"
|
|
||||||
|
|
||||||
let creditCard = "credit-card"
|
|
||||||
|
|
||||||
let delete = "delete"
|
|
||||||
|
|
||||||
let desktop = "desktop"
|
|
||||||
|
|
||||||
let download = "download"
|
|
||||||
|
|
||||||
let edit = "edit"
|
|
||||||
|
|
||||||
let ellipsis = "ellipsis"
|
|
||||||
|
|
||||||
let file = "file"
|
|
||||||
|
|
||||||
let fileText = "file-text"
|
|
||||||
|
|
||||||
let fileUnknown = "file-unknown"
|
|
||||||
|
|
||||||
let filePdf = "file-pdf"
|
|
||||||
|
|
||||||
let fileWord = "file-word"
|
|
||||||
|
|
||||||
let fileExcel = "file-excel"
|
|
||||||
|
|
||||||
let fileJpg = "file-jpg"
|
|
||||||
|
|
||||||
let filePpt = "file-ppt"
|
|
||||||
|
|
||||||
let fileMarkdown = "file-markdown"
|
|
||||||
|
|
||||||
let fileAdd = "file-add"
|
|
||||||
|
|
||||||
let folder = "folder"
|
|
||||||
|
|
||||||
let folderOpen = "folder-open"
|
|
||||||
|
|
||||||
let folderAdd = "folder-add"
|
|
||||||
|
|
||||||
let hdd = "hdd"
|
|
||||||
|
|
||||||
let frown = "frown"
|
|
||||||
|
|
||||||
let frownO = "frown-o"
|
|
||||||
|
|
||||||
let meh = "meh"
|
|
||||||
|
|
||||||
let mehO = "meh-o"
|
|
||||||
|
|
||||||
let smile = "smile"
|
|
||||||
|
|
||||||
let smileO = "smile-o"
|
|
||||||
|
|
||||||
let inbox = "inbox"
|
|
||||||
|
|
||||||
let laptop = "laptop"
|
|
||||||
|
|
||||||
let appstoreO = "appstore-o"
|
|
||||||
|
|
||||||
let appstore = "appstore"
|
|
||||||
|
|
||||||
let lineChart = "line-chart"
|
|
||||||
|
|
||||||
let link = "link"
|
|
||||||
|
|
||||||
let mail = "mail"
|
|
||||||
|
|
||||||
let mobile = "mobile"
|
|
||||||
|
|
||||||
let notification = "notification"
|
|
||||||
|
|
||||||
let paperClip = "paper-clip"
|
|
||||||
|
|
||||||
let picture = "picture"
|
|
||||||
|
|
||||||
let poweroff = "poweroff"
|
|
||||||
|
|
||||||
let reload = "reload"
|
|
||||||
|
|
||||||
let search = "search"
|
|
||||||
|
|
||||||
let setting = "setting"
|
|
||||||
|
|
||||||
let shareAlt = "share-alt"
|
|
||||||
|
|
||||||
let shoppingCart = "shopping-cart"
|
|
||||||
|
|
||||||
let tablet = "tablet"
|
|
||||||
|
|
||||||
let tag = "tag"
|
|
||||||
|
|
||||||
let tagO = "tag-o"
|
|
||||||
|
|
||||||
let tags = "tags"
|
|
||||||
|
|
||||||
let tagsO = "tags-o"
|
|
||||||
|
|
||||||
let toTop = "to-top"
|
|
||||||
|
|
||||||
let upload = "upload"
|
|
||||||
|
|
||||||
let user = "user"
|
|
||||||
|
|
||||||
let videoCamera = "video-camera"
|
|
||||||
|
|
||||||
let home = "home"
|
|
||||||
|
|
||||||
let loading = "loading"
|
|
||||||
|
|
||||||
let loading3Quarters = "loading-3-quarters"
|
|
||||||
|
|
||||||
let cloudUploadO = "cloud-upload-o"
|
|
||||||
|
|
||||||
let cloudDownloadO = "cloud-download-o"
|
|
||||||
|
|
||||||
let cloudUpload = "cloud-upload"
|
|
||||||
|
|
||||||
let cloudO = "cloud-o"
|
|
||||||
|
|
||||||
let starO = "star-o"
|
|
||||||
|
|
||||||
let star = "star"
|
|
||||||
|
|
||||||
let heartO = "heart-o"
|
|
||||||
|
|
||||||
let heart = "heart"
|
|
||||||
|
|
||||||
let environment = "environment"
|
|
||||||
|
|
||||||
let environmentO = "environment-o"
|
|
||||||
|
|
||||||
let eye = "eye"
|
|
||||||
|
|
||||||
let eyeO = "eye-o"
|
|
||||||
|
|
||||||
let camera = "camera"
|
|
||||||
|
|
||||||
let cameraO = "camera-o"
|
|
||||||
|
|
||||||
let save = "save"
|
|
||||||
|
|
||||||
let team = "team"
|
|
||||||
|
|
||||||
let solution = "solution"
|
|
||||||
|
|
||||||
let phone = "phone"
|
|
||||||
|
|
||||||
let filter = "filter"
|
|
||||||
|
|
||||||
let exception_ = "exception"
|
|
||||||
|
|
||||||
let \"export" = "export"
|
|
||||||
|
|
||||||
let customerService = "customer-service"
|
|
||||||
|
|
||||||
let qrcode = "qrcode"
|
|
||||||
|
|
||||||
let scan = "scan"
|
|
||||||
|
|
||||||
let like = "like"
|
|
||||||
|
|
||||||
let likeO = "like-o"
|
|
||||||
|
|
||||||
let dislike = "dislike"
|
|
||||||
|
|
||||||
let dislikeO = "dislike-o"
|
|
||||||
|
|
||||||
let message = "message"
|
|
||||||
|
|
||||||
let payCircle = "pay-circle"
|
|
||||||
|
|
||||||
let payCircleO = "pay-circle-o"
|
|
||||||
|
|
||||||
let calculator = "calculator"
|
|
||||||
|
|
||||||
let pushpin = "pushpin"
|
|
||||||
|
|
||||||
let pushpinO = "pushpin-o"
|
|
||||||
|
|
||||||
let bulb = "bulb"
|
|
||||||
|
|
||||||
let select = "select"
|
|
||||||
|
|
||||||
let switcher = "switcher"
|
|
||||||
|
|
||||||
let rocket = "rocket"
|
|
||||||
|
|
||||||
let bell = "bell"
|
|
||||||
|
|
||||||
let disconnect = "disconnect"
|
|
||||||
|
|
||||||
let database = "database"
|
|
||||||
|
|
||||||
let compass = "compass"
|
|
||||||
|
|
||||||
let barcode = "barcode"
|
|
||||||
|
|
||||||
let hourglass = "hourglass"
|
|
||||||
|
|
||||||
let key = "key"
|
|
||||||
|
|
||||||
let flag = "flag"
|
|
||||||
|
|
||||||
let layout = "layout"
|
|
||||||
|
|
||||||
let printer = "printer"
|
|
||||||
|
|
||||||
let sound = "sound"
|
|
||||||
|
|
||||||
let usb = "usb"
|
|
||||||
|
|
||||||
let skin = "skin"
|
|
||||||
|
|
||||||
let tool = "tool"
|
|
||||||
|
|
||||||
let sync = "sync"
|
|
||||||
|
|
||||||
let wifi = "wifi"
|
|
||||||
|
|
||||||
let car = "car"
|
|
||||||
|
|
||||||
let schedule = "schedule"
|
|
||||||
|
|
||||||
let userAdd = "user-add"
|
|
||||||
|
|
||||||
let userDelete = "user-delete"
|
|
||||||
|
|
||||||
let usergroupAdd = "usergroup-add"
|
|
||||||
|
|
||||||
let usergroupDelete = "usergroup-delete"
|
|
||||||
|
|
||||||
let man = "man"
|
|
||||||
|
|
||||||
let woman = "woman"
|
|
||||||
|
|
||||||
let shop = "shop"
|
|
||||||
|
|
||||||
let gift = "gift"
|
|
||||||
|
|
||||||
let idcard = "idcard"
|
|
||||||
|
|
||||||
let medicineBox = "medicine-box"
|
|
||||||
|
|
||||||
let redEnvelope = "red-envelope"
|
|
||||||
|
|
||||||
let coffee = "coffee"
|
|
||||||
|
|
||||||
let copyright = "copyright"
|
|
||||||
|
|
||||||
let trademark = "trademark"
|
|
||||||
|
|
||||||
let safety = "safety"
|
|
||||||
|
|
||||||
let wallet = "wallet"
|
|
||||||
|
|
||||||
let bank = "bank"
|
|
||||||
|
|
||||||
let trophy = "trophy"
|
|
||||||
|
|
||||||
let contacts = "contacts"
|
|
||||||
|
|
||||||
let global = "global"
|
|
||||||
|
|
||||||
let shake = "shake"
|
|
||||||
|
|
||||||
let api = "api"
|
|
||||||
|
|
||||||
let fork = "fork"
|
|
||||||
|
|
||||||
let dashboard = "dashboard"
|
|
||||||
|
|
||||||
let form = "form"
|
|
||||||
|
|
||||||
let table = "table"
|
|
||||||
|
|
||||||
let profile = "profile"
|
|
||||||
|
|
||||||
let android = "android"
|
|
||||||
|
|
||||||
let androidO = "android-o"
|
|
||||||
|
|
||||||
let apple = "apple"
|
|
||||||
|
|
||||||
let appleO = "apple-o"
|
|
||||||
|
|
||||||
let windows = "windows"
|
|
||||||
|
|
||||||
let windowsO = "windows-o"
|
|
||||||
|
|
||||||
let ie = "ie"
|
|
||||||
|
|
||||||
let chrome = "chrome"
|
|
||||||
|
|
||||||
let github = "github"
|
|
||||||
|
|
||||||
let aliwangwang = "aliwangwang"
|
|
||||||
|
|
||||||
let aliwangwangO = "aliwangwang-o"
|
|
||||||
|
|
||||||
let dingding = "dingding"
|
|
||||||
|
|
||||||
let dingdingO = "dingding-o"
|
|
||||||
|
|
||||||
let weiboSquare = "weibo-square"
|
|
||||||
|
|
||||||
let weiboCircle = "weibo-circle"
|
|
||||||
|
|
||||||
let taobaoCircle = "taobao-circle"
|
|
||||||
|
|
||||||
let html5 = "html5"
|
|
||||||
|
|
||||||
let weibo = "weibo"
|
|
||||||
|
|
||||||
let twitter = "twitter"
|
|
||||||
|
|
||||||
let wechat = "wechat"
|
|
||||||
|
|
||||||
let youtube = "youtube"
|
|
||||||
|
|
||||||
let alipayCircle = "alipay-circle"
|
|
||||||
|
|
||||||
let taobao = "taobao"
|
|
||||||
|
|
||||||
let skype = "skype"
|
|
||||||
|
|
||||||
let qq = "qq"
|
|
||||||
|
|
||||||
let mediumWorkmark = "medium-workmark"
|
|
||||||
|
|
||||||
let gitlab = "gitlab"
|
|
||||||
|
|
||||||
let medium = "medium"
|
|
||||||
|
|
||||||
let linkedin = "linkedin"
|
|
||||||
|
|
||||||
let googlePlus = "google-plus"
|
|
||||||
|
|
||||||
let dropbox = "dropbox"
|
|
||||||
|
|
||||||
let facebook = "facebook"
|
|
||||||
|
|
||||||
let codepen = "codepen"
|
|
||||||
|
|
||||||
let amazon = "amazon"
|
|
||||||
|
|
||||||
let google = "google"
|
|
||||||
|
|
||||||
let codepenCircle = "codepen-circle"
|
|
||||||
|
|
||||||
let alipay = "alipay"
|
|
||||||
|
|
||||||
let antDesign = "ant-design"
|
|
||||||
|
|
||||||
let aliyun = "aliyun"
|
|
||||||
|
|
||||||
let zhihu = "zhihu"
|
|
||||||
|
|
||||||
let slack = "slack"
|
|
||||||
|
|
||||||
let slackSquare = "slack-square"
|
|
||||||
|
|
||||||
let behance = "behance"
|
|
||||||
|
|
||||||
let behanceSquare = "behance-square"
|
|
||||||
|
|
||||||
let dribbble = "dribbble"
|
|
||||||
|
|
||||||
let dribbbleSquare = "dribbble-square"
|
|
||||||
|
|
||||||
let instagram = "instagram"
|
|
||||||
|
|
||||||
let yuque = "yuque"
|
|
|
@ -1,21 +0,0 @@
|
||||||
@deriving(abstract)
|
|
||||||
type props
|
|
||||||
type makeType = props => React.element
|
|
||||||
|
|
||||||
@obj external makeProps: (
|
|
||||||
@as("type")
|
|
||||||
~htmlType: string=?,
|
|
||||||
~name: string=?,
|
|
||||||
~value: string=?,
|
|
||||||
~defaultValue: string=?,
|
|
||||||
~onChange: ReactEvent.Form.t => unit=?,
|
|
||||||
~onPressEnter: ReactEvent.Keyboard.t => unit=?,
|
|
||||||
~onBlur: ReactEvent.Focus.t => unit=?,
|
|
||||||
~className: string=?,
|
|
||||||
~style: ReactDOMStyle.t=?,
|
|
||||||
~placeholder: string=?,
|
|
||||||
unit // This unit is a quirk of the type system. Apparently it must exist to have optional arguments in a type
|
|
||||||
) => props = ""
|
|
||||||
|
|
||||||
@module("antd")
|
|
||||||
external make : makeType = "Input"
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,28 +0,0 @@
|
||||||
type route =
|
|
||||||
| DistBuilder
|
|
||||||
| NotFound
|
|
||||||
|
|
||||||
let routeToPath = route =>
|
|
||||||
switch route {
|
|
||||||
| DistBuilder => "/"
|
|
||||||
| _ => "/"
|
|
||||||
}
|
|
||||||
|
|
||||||
let fixedLength = r => <div className="w-full max-w-screen-xl mx-auto px-6"> r </div>
|
|
||||||
|
|
||||||
@react.component
|
|
||||||
let make = () => {
|
|
||||||
let url = RescriptReactRouter.useUrl()
|
|
||||||
|
|
||||||
let routing = switch url.path {
|
|
||||||
| list{} => DistBuilder
|
|
||||||
| _ => NotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
<>
|
|
||||||
{switch routing {
|
|
||||||
| DistBuilder => <DistBuilder />
|
|
||||||
| _ => fixedLength("Page is not found" |> R.ste)
|
|
||||||
}}
|
|
||||||
</>
|
|
||||||
}
|
|
|
@ -1,443 +0,0 @@
|
||||||
open Rationale.Function.Infix
|
|
||||||
|
|
||||||
module FloatFloatMap = {
|
|
||||||
module Id = Belt.Id.MakeComparable({
|
|
||||||
type t = float
|
|
||||||
let cmp: (float, float) => int = Pervasives.compare
|
|
||||||
})
|
|
||||||
|
|
||||||
type t = Belt.MutableMap.t<Id.t, float, Id.identity>
|
|
||||||
|
|
||||||
let fromArray = (ar: array<(float, float)>) => Belt.MutableMap.fromArray(ar, ~id=module(Id))
|
|
||||||
let toArray = (t: t) => Belt.MutableMap.toArray(t)
|
|
||||||
let empty = () => Belt.MutableMap.make(~id=module(Id))
|
|
||||||
let increment = (el, t: t) =>
|
|
||||||
Belt.MutableMap.update(t, el, x =>
|
|
||||||
switch x {
|
|
||||||
| Some(n) => Some(n +. 1.0)
|
|
||||||
| None => Some(1.0)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
let get = (el, t: t) => Belt.MutableMap.get(t, el)
|
|
||||||
let fmap = (fn, t: t) => Belt.MutableMap.map(t, fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
module Int = {
|
|
||||||
let max = (i1: int, i2: int) => i1 > i2 ? i1 : i2
|
|
||||||
}
|
|
||||||
/* Utils */
|
|
||||||
module U = {
|
|
||||||
let isEqual = (a, b) => a == b
|
|
||||||
let toA = a => [a]
|
|
||||||
let id = e => e
|
|
||||||
}
|
|
||||||
|
|
||||||
module O = {
|
|
||||||
let dimap = (sFn, rFn, e) =>
|
|
||||||
switch e {
|
|
||||||
| Some(r) => sFn(r)
|
|
||||||
| None => rFn()
|
|
||||||
}
|
|
||||||
()
|
|
||||||
let fmap = Rationale.Option.fmap
|
|
||||||
let bind = Rationale.Option.bind
|
|
||||||
let default = Rationale.Option.default
|
|
||||||
let isSome = Rationale.Option.isSome
|
|
||||||
let isNone = Rationale.Option.isNone
|
|
||||||
let toExn = Rationale.Option.toExn
|
|
||||||
let some = Rationale.Option.some
|
|
||||||
let firstSome = Rationale.Option.firstSome
|
|
||||||
let toExt = Rationale.Option.toExn
|
|
||||||
let flatApply = (fn, b) => Rationale.Option.apply(fn, Some(b)) |> Rationale.Option.flatten
|
|
||||||
|
|
||||||
let toBool = opt =>
|
|
||||||
switch opt {
|
|
||||||
| Some(_) => true
|
|
||||||
| _ => false
|
|
||||||
}
|
|
||||||
|
|
||||||
let ffmap = (fn, r) =>
|
|
||||||
switch r {
|
|
||||||
| Some(sm) => fn(sm)
|
|
||||||
| _ => None
|
|
||||||
}
|
|
||||||
|
|
||||||
let toString = opt =>
|
|
||||||
switch opt {
|
|
||||||
| Some(s) => s
|
|
||||||
| _ => ""
|
|
||||||
}
|
|
||||||
|
|
||||||
let toResult = (error, e) =>
|
|
||||||
switch e {
|
|
||||||
| Some(r) => Belt.Result.Ok(r)
|
|
||||||
| None => Error(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
let compare = (compare, f1: option<float>, f2: option<float>) =>
|
|
||||||
switch (f1, f2) {
|
|
||||||
| (Some(f1), Some(f2)) => Some(compare(f1, f2) ? f1 : f2)
|
|
||||||
| (Some(f1), None) => Some(f1)
|
|
||||||
| (None, Some(f2)) => Some(f2)
|
|
||||||
| (None, None) => None
|
|
||||||
}
|
|
||||||
|
|
||||||
let min = compare(\"<")
|
|
||||||
let max = compare(\">")
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Functions */
|
|
||||||
module F = {
|
|
||||||
let apply = (a, e) => a |> e
|
|
||||||
|
|
||||||
let flatten2Callbacks = (fn1, fn2, fnlast) =>
|
|
||||||
fn1(response1 => fn2(response2 => fnlast(response1, response2)))
|
|
||||||
|
|
||||||
let flatten3Callbacks = (fn1, fn2, fn3, fnlast) =>
|
|
||||||
fn1(response1 => fn2(response2 => fn3(response3 => fnlast(response1, response2, response3))))
|
|
||||||
|
|
||||||
let flatten4Callbacks = (fn1, fn2, fn3, fn4, fnlast) =>
|
|
||||||
fn1(response1 =>
|
|
||||||
fn2(response2 =>
|
|
||||||
fn3(response3 => fn4(response4 => fnlast(response1, response2, response3, response4)))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
module Bool = {
|
|
||||||
type t = bool
|
|
||||||
let toString = (t: t) => t ? "TRUE" : "FALSE"
|
|
||||||
let fromString = str => str == "TRUE" ? true : false
|
|
||||||
|
|
||||||
module O = {
|
|
||||||
let toBool = opt =>
|
|
||||||
switch opt {
|
|
||||||
| Some(true) => true
|
|
||||||
| _ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module Float = {
|
|
||||||
let with2DigitsPrecision = Js.Float.toPrecisionWithPrecision(_, ~digits=2)
|
|
||||||
let with3DigitsPrecision = Js.Float.toPrecisionWithPrecision(_, ~digits=3)
|
|
||||||
let toFixed = Js.Float.toFixed
|
|
||||||
let toString = Js.Float.toString
|
|
||||||
}
|
|
||||||
|
|
||||||
module I = {
|
|
||||||
let increment = n => n + 1
|
|
||||||
let decrement = n => n - 1
|
|
||||||
let toString = Js.Int.toString
|
|
||||||
}
|
|
||||||
|
|
||||||
/* R for Result */
|
|
||||||
module R = {
|
|
||||||
let result = Rationale.Result.result
|
|
||||||
let id = e => e |> result(U.id, U.id)
|
|
||||||
let fmap = Rationale.Result.fmap
|
|
||||||
let bind = Rationale.Result.bind
|
|
||||||
let toExn = Belt.Result.getExn
|
|
||||||
let default = (default, res: Belt.Result.t<'a, 'b>) =>
|
|
||||||
switch res {
|
|
||||||
| Ok(r) => r
|
|
||||||
| Error(_) => default
|
|
||||||
}
|
|
||||||
let merge = (a, b) =>
|
|
||||||
switch (a, b) {
|
|
||||||
| (Error(e), _) => Error(e)
|
|
||||||
| (_, Error(e)) => Error(e)
|
|
||||||
| (Ok(a), Ok(b)) => Ok((a, b))
|
|
||||||
}
|
|
||||||
let toOption = (e: Belt.Result.t<'a, 'b>) =>
|
|
||||||
switch e {
|
|
||||||
| Ok(r) => Some(r)
|
|
||||||
| Error(_) => None
|
|
||||||
}
|
|
||||||
|
|
||||||
let errorIfCondition = (errorCondition, errorMessage, r) =>
|
|
||||||
errorCondition(r) ? Error(errorMessage) : Ok(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
let safe_fn_of_string = (fn, s: string): option<'a> =>
|
|
||||||
try Some(fn(s)) catch {
|
|
||||||
| _ => None
|
|
||||||
}
|
|
||||||
|
|
||||||
module S = {
|
|
||||||
let safe_float = float_of_string->safe_fn_of_string
|
|
||||||
let safe_int = int_of_string->safe_fn_of_string
|
|
||||||
let default = (defaultStr, str) => str == "" ? defaultStr : str
|
|
||||||
}
|
|
||||||
|
|
||||||
module J = {
|
|
||||||
let toString = \"||>"(Js.Json.decodeString, O.default(""))
|
|
||||||
let fromString = Js.Json.string
|
|
||||||
let fromNumber = Js.Json.number
|
|
||||||
|
|
||||||
module O = {
|
|
||||||
let fromString = (str: string) =>
|
|
||||||
switch str {
|
|
||||||
| "" => None
|
|
||||||
| _ => Some(Js.Json.string(str))
|
|
||||||
}
|
|
||||||
|
|
||||||
let toString = (str: option<'a>) =>
|
|
||||||
switch str {
|
|
||||||
| Some(str) => Some(str |> \"||>"(Js.Json.decodeString, O.default("")))
|
|
||||||
| _ => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module JsDate = {
|
|
||||||
let fromString = Js.Date.fromString
|
|
||||||
let now = Js.Date.now
|
|
||||||
let make = Js.Date.make
|
|
||||||
let valueOf = Js.Date.valueOf
|
|
||||||
}
|
|
||||||
|
|
||||||
/* List */
|
|
||||||
module L = {
|
|
||||||
let fmap = List.map
|
|
||||||
let get = Belt.List.get
|
|
||||||
let toArray = Array.of_list
|
|
||||||
let fmapi = List.mapi
|
|
||||||
let concat = List.concat
|
|
||||||
let drop = Rationale.RList.drop
|
|
||||||
let remove = Rationale.RList.remove
|
|
||||||
let find = List.find
|
|
||||||
let filter = List.filter
|
|
||||||
let for_all = List.for_all
|
|
||||||
let exists = List.exists
|
|
||||||
let sort = List.sort
|
|
||||||
let length = List.length
|
|
||||||
let filter_opt = Rationale.RList.filter_opt
|
|
||||||
let uniqBy = Rationale.RList.uniqBy
|
|
||||||
let join = Rationale.RList.join
|
|
||||||
let head = Rationale.RList.head
|
|
||||||
let uniq = Rationale.RList.uniq
|
|
||||||
let flatten = List.flatten
|
|
||||||
let last = Rationale.RList.last
|
|
||||||
let append = List.append
|
|
||||||
let getBy = Belt.List.getBy
|
|
||||||
let dropLast = Rationale.RList.dropLast
|
|
||||||
let contains = Rationale.RList.contains
|
|
||||||
let without = Rationale.RList.without
|
|
||||||
let update = Rationale.RList.update
|
|
||||||
let iter = List.iter
|
|
||||||
let findIndex = Rationale.RList.findIndex
|
|
||||||
}
|
|
||||||
|
|
||||||
/* A for Array */
|
|
||||||
module A = {
|
|
||||||
let fmap = Array.map
|
|
||||||
let fmapi = Array.mapi
|
|
||||||
let to_list = Array.to_list
|
|
||||||
let of_list = Array.of_list
|
|
||||||
let length = Array.length
|
|
||||||
let append = Array.append
|
|
||||||
// let empty = [||];
|
|
||||||
let unsafe_get = Array.unsafe_get
|
|
||||||
let get = Belt.Array.get
|
|
||||||
let getBy = Belt.Array.getBy
|
|
||||||
let last = a => get(a, length(a) - 1)
|
|
||||||
let first = get(_, 0)
|
|
||||||
let hasBy = (r, fn) => Belt.Array.getBy(r, fn) |> O.isSome
|
|
||||||
let fold_left = Array.fold_left
|
|
||||||
let fold_right = Array.fold_right
|
|
||||||
let concatMany = Belt.Array.concatMany
|
|
||||||
let keepMap = Belt.Array.keepMap
|
|
||||||
let init = Array.init
|
|
||||||
let reduce = Belt.Array.reduce
|
|
||||||
let reducei = Belt.Array.reduceWithIndex
|
|
||||||
let isEmpty = r => length(r) < 1
|
|
||||||
let min = a => get(a, 0) |> O.fmap(first => Belt.Array.reduce(a, first, (i, j) => i < j ? i : j))
|
|
||||||
let max = a => get(a, 0) |> O.fmap(first => Belt.Array.reduce(a, first, (i, j) => i > j ? i : j))
|
|
||||||
let stableSortBy = Belt.SortArray.stableSortBy
|
|
||||||
let toRanges = (a: array<'a>) =>
|
|
||||||
switch a |> Belt.Array.length {
|
|
||||||
| 0
|
|
||||||
| 1 =>
|
|
||||||
Belt.Result.Error("Must be at least 2 elements")
|
|
||||||
| n =>
|
|
||||||
Belt.Array.makeBy(n - 1, r => r)
|
|
||||||
|> Belt.Array.map(_, index => (
|
|
||||||
Belt.Array.getUnsafe(a, index),
|
|
||||||
Belt.Array.getUnsafe(a, index + 1),
|
|
||||||
))
|
|
||||||
|> Rationale.Result.return
|
|
||||||
}
|
|
||||||
|
|
||||||
// This zips while taking the longest elements of each array.
|
|
||||||
let zipMaxLength = (array1, array2) => {
|
|
||||||
let maxLength = Int.max(length(array1), length(array2))
|
|
||||||
let result = maxLength |> Belt.Array.makeUninitializedUnsafe
|
|
||||||
for i in 0 to maxLength - 1 {
|
|
||||||
Belt.Array.set(result, i, (get(array1, i), get(array2, i))) |> ignore
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
let asList = (f: list<'a> => list<'a>, r: array<'a>) => r |> to_list |> f |> of_list
|
|
||||||
/* TODO: Is there a better way of doing this? */
|
|
||||||
let uniq = r => asList(L.uniq, r)
|
|
||||||
|
|
||||||
//intersperse([1,2,3], [10,11,12]) => [1,10,2,11,3,12]
|
|
||||||
let intersperse = (a: array<'a>, b: array<'a>) => {
|
|
||||||
let items: ref<array<'a>> = ref([])
|
|
||||||
|
|
||||||
Belt.Array.forEachWithIndex(a, (i, item) =>
|
|
||||||
switch Belt.Array.get(b, i) {
|
|
||||||
| Some(r) => items := append(items.contents, [item, r])
|
|
||||||
| None => items := append(items.contents, [item])
|
|
||||||
}
|
|
||||||
)
|
|
||||||
items.contents
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is like map, but
|
|
||||||
//accumulate((a,b) => a + b, [1,2,3]) => [1, 3, 5]
|
|
||||||
let accumulate = (fn: ('a, 'a) => 'a, items: array<'a>) => {
|
|
||||||
let length = items |> length
|
|
||||||
let empty = Belt.Array.make(length, items |> unsafe_get(_, 0))
|
|
||||||
Belt.Array.forEachWithIndex(items, (index, element) => {
|
|
||||||
let item = switch index {
|
|
||||||
| 0 => element
|
|
||||||
| index => fn(element, unsafe_get(empty, index - 1))
|
|
||||||
}
|
|
||||||
let _ = Belt.Array.set(empty, index, item)
|
|
||||||
})
|
|
||||||
empty
|
|
||||||
}
|
|
||||||
|
|
||||||
// @todo: Is -1 still the indicator that this is false (as is true with
|
|
||||||
// @todo: js findIndex)? Wasn't sure.
|
|
||||||
let findIndex = (e, i) =>
|
|
||||||
Js.Array.findIndex(e, i) |> (
|
|
||||||
r =>
|
|
||||||
switch r {
|
|
||||||
| -1 => None
|
|
||||||
| r => Some(r)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
let filter = (o, e) => Js.Array.filter(o, e)
|
|
||||||
|
|
||||||
module O = {
|
|
||||||
let concatSomes = (optionals: array<option<'a>>): array<'a> =>
|
|
||||||
optionals
|
|
||||||
|> Js.Array.filter(Rationale.Option.isSome)
|
|
||||||
|> Js.Array.map(Rationale.Option.toExn("Warning: This should not have happened"))
|
|
||||||
let defaultEmpty = (o: option<array<'a>>): array<'a> =>
|
|
||||||
switch o {
|
|
||||||
| Some(o) => o
|
|
||||||
| None => []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module R = {
|
|
||||||
let firstErrorOrOpen = (results: array<Belt.Result.t<'a, 'b>>): Belt.Result.t<
|
|
||||||
array<'a>,
|
|
||||||
'b,
|
|
||||||
> => {
|
|
||||||
let bringErrorUp = switch results |> Belt.Array.getBy(_, Belt.Result.isError) {
|
|
||||||
| Some(Belt.Result.Error(err)) => Belt.Result.Error(err)
|
|
||||||
| Some(Belt.Result.Ok(_)) => Belt.Result.Ok(results)
|
|
||||||
| None => Belt.Result.Ok(results)
|
|
||||||
}
|
|
||||||
let forceOpen = (r: array<Belt.Result.t<'a, 'b>>): array<'a> =>
|
|
||||||
r |> Belt.Array.map(_, r => Belt.Result.getExn(r))
|
|
||||||
bringErrorUp |> Belt.Result.map(_, forceOpen)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module Sorted = {
|
|
||||||
let min = first
|
|
||||||
let max = last
|
|
||||||
let range = (~min=min, ~max=max, a) =>
|
|
||||||
switch (min(a), max(a)) {
|
|
||||||
| (Some(min), Some(max)) => Some(max -. min)
|
|
||||||
| _ => None
|
|
||||||
}
|
|
||||||
let binarySearchFirstElementGreaterIndex = (ar: array<'a>, el: 'a) => {
|
|
||||||
let el = Belt.SortArray.binarySearchBy(ar, el, compare)
|
|
||||||
let el = el < 0 ? el * -1 - 1 : el
|
|
||||||
switch el {
|
|
||||||
| e if e >= length(ar) => #overMax
|
|
||||||
| e if e == 0 => #underMin
|
|
||||||
| e => #firstHigher(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let concat = (t1: array<'a>, t2: array<'a>) => {
|
|
||||||
let ts = Belt.Array.concat(t1, t2)
|
|
||||||
ts |> Array.fast_sort(compare)
|
|
||||||
ts
|
|
||||||
}
|
|
||||||
|
|
||||||
let concatMany = (t1: array<array<'a>>) => {
|
|
||||||
let ts = Belt.Array.concatMany(t1)
|
|
||||||
ts |> Array.fast_sort(compare)
|
|
||||||
ts
|
|
||||||
}
|
|
||||||
|
|
||||||
module Floats = {
|
|
||||||
let makeIncrementalUp = (a, b) =>
|
|
||||||
Array.make(b - a + 1, a) |> Array.mapi((i, c) => c + i) |> Belt.Array.map(_, float_of_int)
|
|
||||||
|
|
||||||
let makeIncrementalDown = (a, b) =>
|
|
||||||
Array.make(a - b + 1, a) |> Array.mapi((i, c) => c - i) |> Belt.Array.map(_, float_of_int)
|
|
||||||
|
|
||||||
let split = (sortedArray: array<float>) => {
|
|
||||||
let continuous = []
|
|
||||||
let discrete = FloatFloatMap.empty()
|
|
||||||
Belt.Array.forEachWithIndex(sortedArray, (index, element) => {
|
|
||||||
let maxIndex = (sortedArray |> Array.length) - 1
|
|
||||||
let possiblySimilarElements = switch index {
|
|
||||||
| 0 => [index + 1]
|
|
||||||
| n if n == maxIndex => [index - 1]
|
|
||||||
| _ => [index - 1, index + 1]
|
|
||||||
} |> Belt.Array.map(_, r => sortedArray[r])
|
|
||||||
let hasSimilarElement = Belt.Array.some(possiblySimilarElements, r => r == element)
|
|
||||||
hasSimilarElement
|
|
||||||
? FloatFloatMap.increment(element, discrete)
|
|
||||||
: {
|
|
||||||
let _ = Js.Array.push(element, continuous)
|
|
||||||
}
|
|
||||||
()
|
|
||||||
})
|
|
||||||
|
|
||||||
(continuous, discrete)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module Floats = {
|
|
||||||
let sum = Belt.Array.reduce(_, 0., (i, j) => i +. j)
|
|
||||||
let mean = a => sum(a) /. (Array.length(a) |> float_of_int)
|
|
||||||
let random = Js.Math.random_int
|
|
||||||
|
|
||||||
exception RangeError(string)
|
|
||||||
let range = (min: float, max: float, n: int): array<float> =>
|
|
||||||
switch n {
|
|
||||||
| 0 => []
|
|
||||||
| 1 => [min]
|
|
||||||
| 2 => [min, max]
|
|
||||||
| _ if min == max => Belt.Array.make(n, min)
|
|
||||||
| _ if n < 0 => raise(RangeError("n must be greater than 0"))
|
|
||||||
| _ if min > max => raise(RangeError("Min value is less then max value"))
|
|
||||||
| _ =>
|
|
||||||
let diff = (max -. min) /. Belt.Float.fromInt(n - 1)
|
|
||||||
Belt.Array.makeBy(n, i => min +. Belt.Float.fromInt(i) *. diff)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module JsArray = {
|
|
||||||
let concatSomes = (optionals: Js.Array.t<option<'a>>): Js.Array.t<'a> =>
|
|
||||||
optionals
|
|
||||||
|> Js.Array.filter(Rationale.Option.isSome)
|
|
||||||
|> Js.Array.map(Rationale.Option.toExn("Warning: This should not have happened"))
|
|
||||||
let filter = Js.Array.filter
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
let reasonReactBlue = "#48a9dc";
|
|
||||||
|
|
||||||
// The {j|...|j} feature is just string interpolation, from
|
|
||||||
// bucklescript.github.io/docs/en/interop-cheatsheet#string-unicode-interpolation
|
|
||||||
// This allows us to conveniently write CSS, together with variables, by
|
|
||||||
// constructing a string
|
|
||||||
let style = {j|
|
|
||||||
body {
|
|
||||||
background-color: rgb(224, 226, 229);
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
button {
|
|
||||||
background-color: white;
|
|
||||||
color: $reasonReactBlue;
|
|
||||||
box-shadow: 0 0 0 1px $reasonReactBlue;
|
|
||||||
border: none;
|
|
||||||
padding: 8px;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
button:active {
|
|
||||||
background-color: $reasonReactBlue;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
.container {
|
|
||||||
margin: 12px 0px;
|
|
||||||
box-shadow: 0px 4px 16px rgb(200, 200, 200);
|
|
||||||
width: 720px;
|
|
||||||
border-radius: 12px;
|
|
||||||
font-family: sans-serif;
|
|
||||||
}
|
|
||||||
.containerTitle {
|
|
||||||
background-color: rgb(242, 243, 245);
|
|
||||||
border-radius: 12px 12px 0px 0px;
|
|
||||||
padding: 12px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
.containerContent {
|
|
||||||
background-color: white;
|
|
||||||
padding: 16px;
|
|
||||||
border-radius: 0px 0px 12px 12px;
|
|
||||||
}
|
|
||||||
|j};
|
|
|
@ -1,21 +0,0 @@
|
||||||
let normal = (mean: float, std: float) =>
|
|
||||||
Js.Float.(
|
|
||||||
{
|
|
||||||
let nMean = toPrecisionWithPrecision(mean, ~digits=4);
|
|
||||||
let nStd = toPrecisionWithPrecision(std, ~digits=2);
|
|
||||||
{j|normal($(nMean), $(nStd))|j};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
let logNormal = (mean: float, std: float) => {
|
|
||||||
Js.Float.(
|
|
||||||
{
|
|
||||||
let nMean = toPrecisionWithPrecision(mean, ~digits=4);
|
|
||||||
let nStd = toPrecisionWithPrecision(std, ~digits=2);
|
|
||||||
{j|lognormal({mean: $(nMean), stdev: $(nStd)})|j};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
let divide = (str1: string, str2: string) => {j|$(str1)/$(str2)|j};
|
|
||||||
let min = (str1: string, str2: string) => {j|min($(str1),$(str2))|j};
|
|
|
@ -1,5 +0,0 @@
|
||||||
%raw(`import('./styles/index.css')`)
|
|
||||||
switch ReactDOM.querySelector("#app") {
|
|
||||||
| Some(root) => ReactDOM.render(<App />, root)
|
|
||||||
| None => ()
|
|
||||||
}
|
|
9
packages/playground/src/Index.tsx
Normal file
9
packages/playground/src/Index.tsx
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { render } from "react-dom"
|
||||||
|
import DistBuilder from "./components/DistBuilder"
|
||||||
|
|
||||||
|
var root = document.querySelector("#app")
|
||||||
|
|
||||||
|
if (!(root == null)) {
|
||||||
|
render(<DistBuilder />, root)
|
||||||
|
}
|
|
@ -1,8 +0,0 @@
|
||||||
let ste = React.string
|
|
||||||
let showIf = (cond, comp) => cond ? comp : React.null
|
|
||||||
|
|
||||||
module O = {
|
|
||||||
let defaultNull = E.O.default(React.null)
|
|
||||||
let fmapOrNull = (fn, el) => el |> E.O.fmap(fn) |> E.O.default(React.null)
|
|
||||||
let flatten = E.O.default(React.null)
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
type props
|
|
||||||
@obj external makeProps : (~value:string=?, ~onChange: string => unit, ~children: React.element=?, unit) => props = ""
|
|
||||||
|
|
||||||
@module("./CodeEditor.js")
|
|
||||||
external make: props => React.element = "CodeEditor"
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React from "react";
|
import React, {FC} from "react";
|
||||||
import AceEditor from "react-ace";
|
import AceEditor from "react-ace";
|
||||||
|
|
||||||
import "ace-builds/src-noconflict/mode-golang";
|
import "ace-builds/src-noconflict/mode-golang";
|
||||||
|
@ -6,12 +6,12 @@ import "ace-builds/src-noconflict/theme-github";
|
||||||
import "ace-builds/src-noconflict/ext-language_tools";
|
import "ace-builds/src-noconflict/ext-language_tools";
|
||||||
import "ace-builds/src-noconflict/keybinding-vim";
|
import "ace-builds/src-noconflict/keybinding-vim";
|
||||||
|
|
||||||
function onChange(newValue) {
|
interface CodeEditorProps {
|
||||||
console.log("change", newValue);
|
value : string,
|
||||||
|
onChange : (value: string) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export function CodeEditor(props) {
|
export let CodeEditor : FC<CodeEditorProps> = (props) =>
|
||||||
return (
|
|
||||||
<AceEditor
|
<AceEditor
|
||||||
value={props.value}
|
value={props.value}
|
||||||
mode="golang"
|
mode="golang"
|
||||||
|
@ -32,5 +32,3 @@ export function CodeEditor(props) {
|
||||||
enableSnippets: true,
|
enableSnippets: true,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,273 +0,0 @@
|
||||||
open ReForm
|
|
||||||
open Antd.Grid
|
|
||||||
|
|
||||||
module FormConfig = %lenses(
|
|
||||||
type state = {
|
|
||||||
squiggleString: string,
|
|
||||||
sampleCount: string,
|
|
||||||
outputXYPoints: string,
|
|
||||||
downsampleTo: string,
|
|
||||||
kernelWidth: string,
|
|
||||||
diagramStart: string,
|
|
||||||
diagramStop: string,
|
|
||||||
diagramCount: string,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
type options = {
|
|
||||||
sampleCount: int,
|
|
||||||
outputXYPoints: int,
|
|
||||||
downsampleTo: option<int>,
|
|
||||||
kernelWidth: option<float>,
|
|
||||||
diagramStart: float,
|
|
||||||
diagramStop: float,
|
|
||||||
diagramCount: int,
|
|
||||||
}
|
|
||||||
|
|
||||||
module Form = ReForm.Make(FormConfig)
|
|
||||||
|
|
||||||
module FieldText = {
|
|
||||||
@react.component
|
|
||||||
let make = (~field, ~label) => <>
|
|
||||||
<Form.Field
|
|
||||||
field
|
|
||||||
render={({handleChange, error, value, validate}) =>{
|
|
||||||
Js.Console.log(CodeEditor.make);
|
|
||||||
(<CodeEditor value onChange={r => handleChange(r)} />)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
module FieldString = {
|
|
||||||
@react.component
|
|
||||||
let make = (~field, ~label) =>
|
|
||||||
<Form.Field
|
|
||||||
field
|
|
||||||
render={({handleChange, error, value, validate}) =>
|
|
||||||
<Antd.Form.Item label={label}>
|
|
||||||
<Antd.Input
|
|
||||||
value onChange={ReForm.Helpers.handleChange(handleChange)} onBlur={_ => validate()}
|
|
||||||
/>
|
|
||||||
</Antd.Form.Item>}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
|
|
||||||
module FieldFloat = {
|
|
||||||
@react.component
|
|
||||||
let make = (~field, ~label, ~className=CssJs.style(. [])) =>
|
|
||||||
<Form.Field
|
|
||||||
field
|
|
||||||
render={({handleChange, error, value, validate}) =>
|
|
||||||
<Antd.Form.Item label={label}>
|
|
||||||
<Antd.Input
|
|
||||||
value
|
|
||||||
onChange={ReForm.Helpers.handleChange(handleChange)}
|
|
||||||
onBlur={_ => validate()}
|
|
||||||
className={className}
|
|
||||||
/>
|
|
||||||
</Antd.Form.Item>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
|
|
||||||
module Styles = {
|
|
||||||
open CssJs
|
|
||||||
let rows = style(. [
|
|
||||||
selector(. ">.antCol:firstChild", [ paddingLeft(em(0.25)), paddingRight(em(0.125)) ]),
|
|
||||||
selector(. ">.antCol:lastChild", [ paddingLeft(em(0.125)), paddingRight(em(0.25)) ]),
|
|
||||||
selector(.
|
|
||||||
">.antCol:not(:firstChild):not(:lastChild)",
|
|
||||||
[ paddingLeft(em(0.125)), paddingRight(em(0.125)) ],
|
|
||||||
),
|
|
||||||
])
|
|
||||||
let parent = style(. [ selector(. ".antInputNumber", [ width(#percent(100.)) ]),
|
|
||||||
selector(. ".anticon", [ verticalAlign(#zero) ]),
|
|
||||||
])
|
|
||||||
let form = style(. [ backgroundColor(hex("eee")), padding(em(1.)) ])
|
|
||||||
let dist = style(. [ padding(em(1.)) ])
|
|
||||||
let spacer = style(. [ marginTop(em(1.)) ])
|
|
||||||
let groupA = style(. [ selector(. ".antInputNumberInput", [ backgroundColor(hex("fff7db")) ]),
|
|
||||||
])
|
|
||||||
let groupB = style(. [ selector(. ".antInputNumberInput", [ backgroundColor(hex("eaf4ff")) ]),
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
module DemoDist = {
|
|
||||||
@react.component
|
|
||||||
let make = (~squiggleString: string, ~options) =>
|
|
||||||
<Antd.Card title={"Distribution"}>
|
|
||||||
<div>
|
|
||||||
{switch options {
|
|
||||||
| Some(options) =>
|
|
||||||
let inputs1 = SquiggleLang.ProgramEvaluator.Inputs.make(
|
|
||||||
~samplingInputs={
|
|
||||||
sampleCount: Some(options.sampleCount),
|
|
||||||
outputXYPoints: Some(options.outputXYPoints),
|
|
||||||
kernelWidth: options.kernelWidth,
|
|
||||||
pointSetDistLength: Some(options.downsampleTo |> E.O.default(1000)),
|
|
||||||
},
|
|
||||||
~squiggleString,
|
|
||||||
~environment=[
|
|
||||||
("K", #SymbolicDist(#Float(1000.0))),
|
|
||||||
("M", #SymbolicDist(#Float(1000000.0))),
|
|
||||||
("B", #SymbolicDist(#Float(1000000000.0))),
|
|
||||||
("T", #SymbolicDist(#Float(1000000000000.0))),
|
|
||||||
]->Belt.Map.String.fromArray,
|
|
||||||
(),
|
|
||||||
)
|
|
||||||
|
|
||||||
let distributionList = SquiggleLang.ProgramEvaluator.evaluateProgram(inputs1)
|
|
||||||
|
|
||||||
let renderExpression = response1 =>
|
|
||||||
switch response1 {
|
|
||||||
| #DistPlus(distPlus1) => <DistPlusPlot distPlus={SquiggleLang.DistPlus.T.normalize(distPlus1)} />
|
|
||||||
| #Float(f) => <NumberShower number=f precision=3 />
|
|
||||||
| #Function((f, a), env) =>
|
|
||||||
// Problem: When it gets the function, it doesn't save state about previous commands
|
|
||||||
let foo: SquiggleLang.ProgramEvaluator.Inputs.inputs = {
|
|
||||||
squiggleString: squiggleString,
|
|
||||||
samplingInputs: inputs1.samplingInputs,
|
|
||||||
environment: env,
|
|
||||||
}
|
|
||||||
let results =
|
|
||||||
E.A.Floats.range(options.diagramStart, options.diagramStop, options.diagramCount)
|
|
||||||
|> E.A.fmap(r =>
|
|
||||||
SquiggleLang.ProgramEvaluator.evaluateFunction(
|
|
||||||
foo,
|
|
||||||
(f, a),
|
|
||||||
[#SymbolicDist(#Float(r))],
|
|
||||||
) |> E.R.bind(_, a =>
|
|
||||||
switch a {
|
|
||||||
| #DistPlus(d) => Ok((r, SquiggleLang.DistPlus.T.normalize(d)))
|
|
||||||
| n =>
|
|
||||||
Js.log2("Error here", n)
|
|
||||||
Error("wrong type")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|> E.A.R.firstErrorOrOpen
|
|
||||||
switch results {
|
|
||||||
| Ok(dists) => <PercentilesChart dists />
|
|
||||||
| Error(r) => r |> R.ste
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render the list of distributions given by the
|
|
||||||
switch distributionList {
|
|
||||||
| Ok(xs) =>
|
|
||||||
let childrenElements = List.map(renderExpression, xs)
|
|
||||||
Js.Console.log(childrenElements)
|
|
||||||
<ul>
|
|
||||||
{Belt.List.toArray(Belt.List.mapWithIndex(childrenElements, (i, child) => <li key={Belt.Int.toString(i)}>child</li>))->React.array}
|
|
||||||
</ul>
|
|
||||||
| Error(r) => r |> R.ste
|
|
||||||
}
|
|
||||||
| _ => "Nothing to show. Try to change the distribution description." |> R.ste
|
|
||||||
}}
|
|
||||||
</div>
|
|
||||||
</Antd.Card>
|
|
||||||
}
|
|
||||||
|
|
||||||
@react.component
|
|
||||||
let make = () => {
|
|
||||||
let (reloader, setReloader) = React.useState(() => 1)
|
|
||||||
let reform = Form.use(
|
|
||||||
~validationStrategy=OnDemand,
|
|
||||||
~schema=Form.Validation.Schema([]),
|
|
||||||
~onSubmit=({state}) => None,
|
|
||||||
~initialState={
|
|
||||||
//squiggleString: "mm(normal(-10, 2), uniform(18, 25), lognormal({mean: 10, stdev: 8}), triangular(31,40,50))",
|
|
||||||
squiggleString: "mm(normal(5,2), normal(10,2))",
|
|
||||||
sampleCount: "1000",
|
|
||||||
outputXYPoints: "1000",
|
|
||||||
downsampleTo: "",
|
|
||||||
kernelWidth: "",
|
|
||||||
diagramStart: "0",
|
|
||||||
diagramStop: "10",
|
|
||||||
diagramCount: "20",
|
|
||||||
},
|
|
||||||
(),
|
|
||||||
)
|
|
||||||
|
|
||||||
let onSubmit = e => {
|
|
||||||
e->ReactEvent.Synthetic.preventDefault
|
|
||||||
reform.submit()
|
|
||||||
}
|
|
||||||
|
|
||||||
let squiggleString = reform.state.values.squiggleString
|
|
||||||
let sampleCount = reform.state.values.sampleCount |> Js.Float.fromString
|
|
||||||
let outputXYPoints = reform.state.values.outputXYPoints |> Js.Float.fromString
|
|
||||||
let downsampleTo = reform.state.values.downsampleTo |> Js.Float.fromString
|
|
||||||
let kernelWidth = reform.state.values.kernelWidth |> Js.Float.fromString
|
|
||||||
let diagramStart = reform.state.values.diagramStart |> Js.Float.fromString
|
|
||||||
let diagramStop = reform.state.values.diagramStop |> Js.Float.fromString
|
|
||||||
let diagramCount = reform.state.values.diagramCount |> Js.Float.fromString
|
|
||||||
|
|
||||||
let options = switch (sampleCount, outputXYPoints, downsampleTo) {
|
|
||||||
| (_, _, _)
|
|
||||||
if !Js.Float.isNaN(sampleCount) &&
|
|
||||||
(!Js.Float.isNaN(outputXYPoints) &&
|
|
||||||
(!Js.Float.isNaN(downsampleTo) && (sampleCount > 10. && outputXYPoints > 10.))) =>
|
|
||||||
Some({
|
|
||||||
sampleCount: sampleCount |> int_of_float,
|
|
||||||
outputXYPoints: outputXYPoints |> int_of_float,
|
|
||||||
downsampleTo: int_of_float(downsampleTo) > 0 ? Some(int_of_float(downsampleTo)) : None,
|
|
||||||
kernelWidth: kernelWidth == 0.0 ? None : Some(kernelWidth),
|
|
||||||
diagramStart: diagramStart,
|
|
||||||
diagramStop: diagramStop,
|
|
||||||
diagramCount: diagramCount |> int_of_float,
|
|
||||||
})
|
|
||||||
| _ => None
|
|
||||||
}
|
|
||||||
|
|
||||||
let demoDist = React.useMemo1(
|
|
||||||
() => <DemoDist squiggleString options />,
|
|
||||||
[
|
|
||||||
reform.state.values.squiggleString,
|
|
||||||
reform.state.values.sampleCount,
|
|
||||||
reform.state.values.outputXYPoints,
|
|
||||||
reform.state.values.downsampleTo,
|
|
||||||
reform.state.values.kernelWidth,
|
|
||||||
reform.state.values.diagramStart,
|
|
||||||
reform.state.values.diagramStop,
|
|
||||||
reform.state.values.diagramCount,
|
|
||||||
reloader |> string_of_int,
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
let onReload = _ => setReloader(_ => reloader + 1)
|
|
||||||
|
|
||||||
<div className="grid grid-cols-2 gap-4">
|
|
||||||
<div>
|
|
||||||
<Antd.Card
|
|
||||||
title={"Distribution Form" |> R.ste}>
|
|
||||||
<Form.Provider value=reform>
|
|
||||||
<Antd.Form onSubmit>
|
|
||||||
<Row _type="flex" className=Styles.rows>
|
|
||||||
<Col span=24> <FieldText field=FormConfig.SquiggleString label="Program" /> </Col>
|
|
||||||
</Row>
|
|
||||||
<Row _type="flex" className=Styles.rows>
|
|
||||||
<Col span=12> <FieldFloat field=FormConfig.SampleCount label="Sample Count" /> </Col>
|
|
||||||
<Col span=12>
|
|
||||||
<FieldFloat field=FormConfig.OutputXYPoints label="Output XY-points" />
|
|
||||||
</Col>
|
|
||||||
<Col span=12>
|
|
||||||
<FieldFloat field=FormConfig.DownsampleTo label="Downsample To" />
|
|
||||||
</Col>
|
|
||||||
<Col span=12> <FieldFloat field=FormConfig.KernelWidth label="Kernel Width" /> </Col>
|
|
||||||
<Col span=12>
|
|
||||||
<FieldFloat field=FormConfig.DiagramStart label="Diagram Start" />
|
|
||||||
</Col>
|
|
||||||
<Col span=12> <FieldFloat field=FormConfig.DiagramStop label="Diagram Stop" /> </Col>
|
|
||||||
<Col span=12>
|
|
||||||
<FieldFloat field=FormConfig.DiagramCount label="Diagram Count" />
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
</Antd.Form>
|
|
||||||
</Form.Provider>
|
|
||||||
</Antd.Card>
|
|
||||||
</div>
|
|
||||||
<div> demoDist </div>
|
|
||||||
</div>
|
|
||||||
}
|
|
171
packages/playground/src/components/DistBuilder.tsx
Normal file
171
packages/playground/src/components/DistBuilder.tsx
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
import { FC, useState } from "react"
|
||||||
|
import { SquiggleChart } from "@squiggle/components"
|
||||||
|
import { CodeEditor } from "./CodeEditor"
|
||||||
|
import { Form, Input, Card, Row, Col } from "antd"
|
||||||
|
import { css } from '@emotion/react'
|
||||||
|
|
||||||
|
interface FieldFloatProps {
|
||||||
|
label : string,
|
||||||
|
className? : string,
|
||||||
|
value : number,
|
||||||
|
onChange : (value: number) => void,
|
||||||
|
}
|
||||||
|
|
||||||
|
function FieldFloat(Props: FieldFloatProps) {
|
||||||
|
let [contents, setContents] = useState(Props.value + "");
|
||||||
|
return <Form.Item label={Props.label}>
|
||||||
|
<Input
|
||||||
|
value={contents}
|
||||||
|
className={Props.className ? Props.className : ""}
|
||||||
|
onChange={(e) => setContents(e.target.value)}
|
||||||
|
onBlur={(_) => {
|
||||||
|
let result = parseFloat(contents);
|
||||||
|
if(result != NaN) {
|
||||||
|
Props.onChange(result)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
}
|
||||||
|
let rows = css`
|
||||||
|
>.antCol:firstChild {
|
||||||
|
paddingLeft: 0.25em;
|
||||||
|
paddingRight: 0.125em;
|
||||||
|
}
|
||||||
|
>.antCol:lastChild {
|
||||||
|
paddingLeft: 0.125em;
|
||||||
|
paddingRight: 0.25em;
|
||||||
|
}
|
||||||
|
>.antCol:not(:lastChild):not(:lastChild) {
|
||||||
|
paddingLeft: 0.125em;
|
||||||
|
paddingRight: 0.125em;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
let parent = css`
|
||||||
|
.antImportNumber {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.anticon {
|
||||||
|
verticalAlign: "zero";
|
||||||
|
}
|
||||||
|
`
|
||||||
|
var form = css`
|
||||||
|
backgroundColor: #eee;
|
||||||
|
padding: 1em;
|
||||||
|
`
|
||||||
|
var dist = css`
|
||||||
|
padding: 1em;
|
||||||
|
`
|
||||||
|
|
||||||
|
var spacer = css`
|
||||||
|
marginTop: 1em;
|
||||||
|
`
|
||||||
|
|
||||||
|
var groupA = css`
|
||||||
|
.antInputNumberInputs {
|
||||||
|
backgroundColor: #fff7db;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
var groupB = css`
|
||||||
|
.antInputNumberInput {
|
||||||
|
backgroundColor: #eaf4ff;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
var Styles = {
|
||||||
|
rows: rows,
|
||||||
|
parent: parent,
|
||||||
|
form: form,
|
||||||
|
dist: dist,
|
||||||
|
spacer: spacer,
|
||||||
|
groupA: groupA,
|
||||||
|
groupB: groupB
|
||||||
|
};
|
||||||
|
|
||||||
|
let DistBuilder : FC<{}> = (_: {}) => {
|
||||||
|
let [squiggleString, setSquiggleString] = useState("mm(normal(5,2), normal(10,2))")
|
||||||
|
let [sampleCount, setSampleCount] = useState(1000)
|
||||||
|
let [outputXYPoints, setOutputXYPoints] = useState(1000)
|
||||||
|
let [pointDistLength, setPointDistLength] = useState(undefined)
|
||||||
|
let [kernelWidth, setKernelWidth] = useState(undefined)
|
||||||
|
let [diagramStart, setDiagramStart] = useState(0)
|
||||||
|
let [diagramStop, setDiagramStop] = useState(10)
|
||||||
|
let [diagramCount, setDiagramCount] = useState(20)
|
||||||
|
var demoDist =
|
||||||
|
<SquiggleChart
|
||||||
|
squiggleString={squiggleString}
|
||||||
|
sampleCount={sampleCount}
|
||||||
|
outputXYPoints={outputXYPoints}
|
||||||
|
diagramStart={diagramStart}
|
||||||
|
diagramStop={diagramStop}
|
||||||
|
diagramCount={diagramCount}
|
||||||
|
pointDistLength={pointDistLength}
|
||||||
|
/>
|
||||||
|
return (
|
||||||
|
<div className="grid grid-cols-2 gap-4">
|
||||||
|
<div>
|
||||||
|
<Card
|
||||||
|
title="Distribution Form">
|
||||||
|
<Form>
|
||||||
|
<Row css={Styles.rows}>
|
||||||
|
<Col span={24}>
|
||||||
|
<CodeEditor value={squiggleString} onChange={setSquiggleString} /> </Col>
|
||||||
|
</Row>
|
||||||
|
<Row css={Styles.rows}>
|
||||||
|
<Col span={12}>
|
||||||
|
<FieldFloat
|
||||||
|
value={sampleCount}
|
||||||
|
label="Sample Count"
|
||||||
|
onChange={setSampleCount}
|
||||||
|
/> </Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<FieldFloat
|
||||||
|
value={outputXYPoints}
|
||||||
|
onChange={setOutputXYPoints}
|
||||||
|
label="Output XY-points" />
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<FieldFloat
|
||||||
|
value={pointDistLength}
|
||||||
|
onChange={setPointDistLength}
|
||||||
|
label="Downsample To"
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<FieldFloat
|
||||||
|
value={kernelWidth}
|
||||||
|
onChange={setKernelWidth}
|
||||||
|
label="Kernel Width"
|
||||||
|
/> </Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<FieldFloat
|
||||||
|
value={diagramStart}
|
||||||
|
onChange={setDiagramStart}
|
||||||
|
label="Diagram Start"
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<FieldFloat
|
||||||
|
value={diagramStop}
|
||||||
|
onChange={setDiagramStop}
|
||||||
|
label="Diagram Stop"
|
||||||
|
/> </Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<FieldFloat
|
||||||
|
value={diagramCount}
|
||||||
|
onChange={setDiagramCount}
|
||||||
|
label="Diagram Count"
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Form>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
{demoDist}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default DistBuilder
|
|
@ -1,306 +0,0 @@
|
||||||
open DistPlusPlotReducer
|
|
||||||
let plotBlue = #hex("1860ad")
|
|
||||||
|
|
||||||
let showAsForm = (distPlus: SquiggleLang.PointSetTypes.distPlus) =>
|
|
||||||
<div> <Antd.Input value={distPlus.squiggleString |> E.O.default("")} /> </div>
|
|
||||||
|
|
||||||
let showFloat = (~precision=3, number) => <NumberShower number precision />
|
|
||||||
|
|
||||||
let table = (distPlus, x) =>
|
|
||||||
<div>
|
|
||||||
<table className="table-auto text-sm">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<td className="px-4 py-2 "> {"X Point" |> React.string} </td>
|
|
||||||
<td className="px-4 py-2"> {"Discrete Value" |> React.string} </td>
|
|
||||||
<td className="px-4 py-2"> {"Continuous Value" |> React.string} </td>
|
|
||||||
<td className="px-4 py-2"> {"Y Integral to Point" |> React.string} </td>
|
|
||||||
<td className="px-4 py-2"> {"Y Integral Total" |> React.string} </td>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td className="px-4 py-2 border"> {x |> E.Float.toString |> React.string} </td>
|
|
||||||
<td className="px-4 py-2 border ">
|
|
||||||
{distPlus
|
|
||||||
|> SquiggleLang.DistPlus.T.xToY(x)
|
|
||||||
|> SquiggleLang.PointSetTypes.MixedPoint.toDiscreteValue
|
|
||||||
|> Js.Float.toPrecisionWithPrecision(_, ~digits=7)
|
|
||||||
|> React.string}
|
|
||||||
</td>
|
|
||||||
<td className="px-4 py-2 border ">
|
|
||||||
{distPlus
|
|
||||||
|> SquiggleLang.DistPlus.T.xToY(x)
|
|
||||||
|> SquiggleLang.PointSetTypes.MixedPoint.toContinuousValue
|
|
||||||
|> Js.Float.toPrecisionWithPrecision(_, ~digits=7)
|
|
||||||
|> React.string}
|
|
||||||
</td>
|
|
||||||
<td className="px-4 py-2 border ">
|
|
||||||
{distPlus
|
|
||||||
|> SquiggleLang.DistPlus.T.Integral.xToY(x)
|
|
||||||
|> E.Float.with2DigitsPrecision
|
|
||||||
|> React.string}
|
|
||||||
</td>
|
|
||||||
<td className="px-4 py-2 border ">
|
|
||||||
{distPlus
|
|
||||||
|> SquiggleLang.DistPlus.T.Integral.sum
|
|
||||||
|> E.Float.with2DigitsPrecision
|
|
||||||
|> React.string}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<table className="table-auto text-sm">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<td className="px-4 py-2"> {"Continuous Total" |> React.string} </td>
|
|
||||||
<td className="px-4 py-2"> {"Discrete Total" |> React.string} </td>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td className="px-4 py-2 border">
|
|
||||||
{distPlus
|
|
||||||
|> SquiggleLang.DistPlus.T.toContinuous
|
|
||||||
|> E.O.fmap(SquiggleLang.Continuous.T.Integral.sum)
|
|
||||||
|> E.O.fmap(E.Float.with2DigitsPrecision)
|
|
||||||
|> E.O.default("")
|
|
||||||
|> React.string}
|
|
||||||
</td>
|
|
||||||
<td className="px-4 py-2 border ">
|
|
||||||
{distPlus
|
|
||||||
|> SquiggleLang.DistPlus.T.toDiscrete
|
|
||||||
|> E.O.fmap(SquiggleLang.Discrete.T.Integral.sum)
|
|
||||||
|> E.O.fmap(E.Float.with2DigitsPrecision)
|
|
||||||
|> E.O.default("")
|
|
||||||
|> React.string}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
let percentiles = distPlus =>
|
|
||||||
<div>
|
|
||||||
<table className="table-auto text-sm">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<td className="px-4 py-2"> {"1" |> React.string} </td>
|
|
||||||
<td className="px-4 py-2"> {"5" |> React.string} </td>
|
|
||||||
<td className="px-4 py-2"> {"25" |> React.string} </td>
|
|
||||||
<td className="px-4 py-2"> {"50" |> React.string} </td>
|
|
||||||
<td className="px-4 py-2"> {"75" |> React.string} </td>
|
|
||||||
<td className="px-4 py-2"> {"95" |> React.string} </td>
|
|
||||||
<td className="px-4 py-2"> {"99" |> React.string} </td>
|
|
||||||
<td className="px-4 py-2"> {"99.999" |> React.string} </td>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td className="px-4 py-2 border">
|
|
||||||
{distPlus |> SquiggleLang.DistPlus.T.Integral.yToX(0.01) |> showFloat}
|
|
||||||
</td>
|
|
||||||
<td className="px-4 py-2 border">
|
|
||||||
{distPlus |> SquiggleLang.DistPlus.T.Integral.yToX(0.05) |> showFloat}
|
|
||||||
</td>
|
|
||||||
<td className="px-4 py-2 border">
|
|
||||||
{distPlus |> SquiggleLang.DistPlus.T.Integral.yToX(0.25) |> showFloat}
|
|
||||||
</td>
|
|
||||||
<td className="px-4 py-2 border">
|
|
||||||
{distPlus |> SquiggleLang.DistPlus.T.Integral.yToX(0.5) |> showFloat}
|
|
||||||
</td>
|
|
||||||
<td className="px-4 py-2 border">
|
|
||||||
{distPlus |> SquiggleLang.DistPlus.T.Integral.yToX(0.75) |> showFloat}
|
|
||||||
</td>
|
|
||||||
<td className="px-4 py-2 border">
|
|
||||||
{distPlus |> SquiggleLang.DistPlus.T.Integral.yToX(0.95) |> showFloat}
|
|
||||||
</td>
|
|
||||||
<td className="px-4 py-2 border">
|
|
||||||
{distPlus |> SquiggleLang.DistPlus.T.Integral.yToX(0.99) |> showFloat}
|
|
||||||
</td>
|
|
||||||
<td className="px-4 py-2 border">
|
|
||||||
{distPlus |> SquiggleLang.DistPlus.T.Integral.yToX(0.99999) |> showFloat}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<table className="table-auto text-sm">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<td className="px-4 py-2"> {"mean" |> React.string} </td>
|
|
||||||
<td className="px-4 py-2"> {"standard deviation" |> React.string} </td>
|
|
||||||
<td className="px-4 py-2"> {"variance" |> React.string} </td>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td className="px-4 py-2 border"> {distPlus |> SquiggleLang.DistPlus.T.mean |> showFloat} </td>
|
|
||||||
<td className="px-4 py-2 border">
|
|
||||||
{distPlus |> SquiggleLang.DistPlus.T.variance |> (r => r ** 0.5) |> showFloat}
|
|
||||||
</td>
|
|
||||||
<td className="px-4 py-2 border"> {distPlus |> SquiggleLang.DistPlus.T.variance |> showFloat} </td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
let adjustBoth = discreteProbabilityMassFraction => {
|
|
||||||
let yMaxDiscreteDomainFactor = discreteProbabilityMassFraction
|
|
||||||
let yMaxContinuousDomainFactor = 1.0 -. discreteProbabilityMassFraction
|
|
||||||
|
|
||||||
// use the bigger proportion, such that whichever is the bigger proportion, the yMax is 1.
|
|
||||||
|
|
||||||
let yMax = yMaxDiscreteDomainFactor > 0.5 ? yMaxDiscreteDomainFactor : yMaxContinuousDomainFactor
|
|
||||||
(yMax /. yMaxDiscreteDomainFactor, yMax /. yMaxContinuousDomainFactor)
|
|
||||||
}
|
|
||||||
|
|
||||||
module DistPlusChart = {
|
|
||||||
@react.component
|
|
||||||
let make = (~distPlus: SquiggleLang.PointSetTypes.distPlus, ~config: chartConfig, ~onHover) => {
|
|
||||||
open SquiggleLang.DistPlus
|
|
||||||
|
|
||||||
let discrete = distPlus |> T.toDiscrete |> E.O.fmap(SquiggleLang.Discrete.getShape)
|
|
||||||
let continuous = distPlus |> T.toContinuous |> E.O.fmap(SquiggleLang.Continuous.getShape)
|
|
||||||
|
|
||||||
// // We subtract a bit from the range to make sure that it fits. Maybe this should be done in d3 instead.
|
|
||||||
// let minX =
|
|
||||||
// switch (
|
|
||||||
// distPlus
|
|
||||||
// |> DistPlus.T.Integral.yToX(0.0001),
|
|
||||||
// range,
|
|
||||||
// ) {
|
|
||||||
// | (min, Some(range)) => Some(min -. range *. 0.001)
|
|
||||||
// | _ => None
|
|
||||||
// };
|
|
||||||
|
|
||||||
let minX = distPlus |> T.Integral.yToX(0.00001)
|
|
||||||
|
|
||||||
let maxX = distPlus |> T.Integral.yToX(0.99999)
|
|
||||||
|
|
||||||
let timeScale = distPlus.unit |> SquiggleLang.PointSetTypes.DistributionUnit.toJson
|
|
||||||
let discreteProbabilityMassFraction = distPlus |> T.toDiscreteProbabilityMassFraction
|
|
||||||
|
|
||||||
let (yMaxDiscreteDomainFactor, yMaxContinuousDomainFactor) = adjustBoth(
|
|
||||||
discreteProbabilityMassFraction,
|
|
||||||
)
|
|
||||||
|
|
||||||
<DistributionPlot
|
|
||||||
xScale={config.xLog ? "log" : "linear"}
|
|
||||||
yScale={config.yLog ? "log" : "linear"}
|
|
||||||
height={DistPlusPlotReducer.heightToPix(config.height)}
|
|
||||||
minX
|
|
||||||
maxX
|
|
||||||
yMaxDiscreteDomainFactor
|
|
||||||
yMaxContinuousDomainFactor
|
|
||||||
?discrete
|
|
||||||
?continuous
|
|
||||||
color=plotBlue
|
|
||||||
onHover
|
|
||||||
timeScale
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module IntegralChart = {
|
|
||||||
@react.component
|
|
||||||
let make = (~distPlus: SquiggleLang.PointSetTypes.distPlus, ~config: chartConfig, ~onHover) => {
|
|
||||||
let integral = distPlus.integralCache
|
|
||||||
let continuous = integral |> SquiggleLang.Continuous.toLinear |> E.O.fmap(SquiggleLang.Continuous.getShape)
|
|
||||||
let minX = distPlus |> SquiggleLang.DistPlus.T.Integral.yToX(0.00001)
|
|
||||||
|
|
||||||
let maxX = distPlus |> SquiggleLang.DistPlus.T.Integral.yToX(0.99999)
|
|
||||||
let timeScale = distPlus.unit |> SquiggleLang.PointSetTypes.DistributionUnit.toJson
|
|
||||||
<DistributionPlot
|
|
||||||
xScale={config.xLog ? "log" : "linear"}
|
|
||||||
yScale={config.yLog ? "log" : "linear"}
|
|
||||||
height={DistPlusPlotReducer.heightToPix(config.height)}
|
|
||||||
minX
|
|
||||||
maxX
|
|
||||||
?continuous
|
|
||||||
color=plotBlue
|
|
||||||
timeScale
|
|
||||||
onHover
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module Chart = {
|
|
||||||
@react.component
|
|
||||||
let make = (~distPlus: SquiggleLang.PointSetTypes.distPlus, ~config: chartConfig, ~onHover) => {
|
|
||||||
let chart = React.useMemo2(
|
|
||||||
() =>
|
|
||||||
config.isCumulative
|
|
||||||
? <IntegralChart distPlus config onHover />
|
|
||||||
: <DistPlusChart distPlus config onHover />,
|
|
||||||
(distPlus, config),
|
|
||||||
)
|
|
||||||
<div
|
|
||||||
className={
|
|
||||||
open CssJs
|
|
||||||
style(. [ minHeight(#px(DistPlusPlotReducer.heightToPix(config.height))) ])
|
|
||||||
}>
|
|
||||||
chart
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let button = "bg-gray-300 hover:bg-gray-500 text-grey-darkest text-xs px-4 py-1"
|
|
||||||
|
|
||||||
@react.component
|
|
||||||
let make = (~distPlus: SquiggleLang.PointSetTypes.distPlus) => {
|
|
||||||
let (x, setX) = React.useState(() => 0.)
|
|
||||||
let (state, dispatch) = React.useReducer(DistPlusPlotReducer.reducer, DistPlusPlotReducer.init)
|
|
||||||
|
|
||||||
<div>
|
|
||||||
{state.distributions
|
|
||||||
|> E.L.fmapi((index, config) =>
|
|
||||||
<div className="flex" key={string_of_int(index)}>
|
|
||||||
<div className="w-4/5"> <Chart distPlus config onHover={r => setX(_ => r)} /> </div>
|
|
||||||
<div className="w-1/5">
|
|
||||||
<div className="opacity-50 hover:opacity-100">
|
|
||||||
<button className=button onClick={_ => dispatch(CHANGE_X_LOG(index))}>
|
|
||||||
{(config.xLog ? "x-log" : "x-linear") |> React.string}
|
|
||||||
</button>
|
|
||||||
<button className=button onClick={_ => dispatch(CHANGE_Y_LOG(index))}>
|
|
||||||
{(config.yLog ? "y-log" : "y-linear") |> React.string}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className=button
|
|
||||||
onClick={_ => dispatch(CHANGE_IS_CUMULATIVE(index, !config.isCumulative))}>
|
|
||||||
{(config.isCumulative ? "cdf" : "pdf") |> React.string}
|
|
||||||
</button>
|
|
||||||
<button className=button onClick={_ => dispatch(HEIGHT_INCREMENT(index))}>
|
|
||||||
{"expand" |> React.string}
|
|
||||||
</button>
|
|
||||||
<button className=button onClick={_ => dispatch(HEIGHT_DECREMENT(index))}>
|
|
||||||
{"shrink" |> React.string}
|
|
||||||
</button>
|
|
||||||
{index != 0
|
|
||||||
? <button className=button onClick={_ => dispatch(REMOVE_DIST(index))}>
|
|
||||||
{"remove" |> React.string}
|
|
||||||
</button>
|
|
||||||
: React.null}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|> E.L.toArray
|
|
||||||
|> React.array}
|
|
||||||
<div className="inline-flex opacity-50 hover:opacity-100">
|
|
||||||
<button className=button onClick={_ => dispatch(CHANGE_SHOW_PERCENTILES)}>
|
|
||||||
{"Percentiles" |> React.string}
|
|
||||||
</button>
|
|
||||||
<button className=button onClick={_ => dispatch(CHANGE_SHOW_STATS)}>
|
|
||||||
{"Debug Stats" |> React.string}
|
|
||||||
</button>
|
|
||||||
<button className=button onClick={_ => dispatch(CHANGE_SHOW_PARAMS)}>
|
|
||||||
{"Params" |> React.string}
|
|
||||||
</button>
|
|
||||||
<button className=button onClick={_ => dispatch(ADD_DIST)}>
|
|
||||||
{"Add" |> React.string}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{state.showParams ? showAsForm(distPlus) : React.null}
|
|
||||||
{state.showStats ? table(distPlus, x) : React.null}
|
|
||||||
{state.showPercentiles ? percentiles(distPlus) : React.null}
|
|
||||||
</div>
|
|
||||||
}
|
|
|
@ -1,112 +0,0 @@
|
||||||
type chartConfig = {
|
|
||||||
xLog: bool,
|
|
||||||
yLog: bool,
|
|
||||||
isCumulative: bool,
|
|
||||||
height: int,
|
|
||||||
};
|
|
||||||
|
|
||||||
type state = {
|
|
||||||
showStats: bool,
|
|
||||||
showPercentiles: bool,
|
|
||||||
showParams: bool,
|
|
||||||
distributions: list(chartConfig),
|
|
||||||
};
|
|
||||||
|
|
||||||
type action =
|
|
||||||
| CHANGE_SHOW_STATS
|
|
||||||
| CHANGE_SHOW_PARAMS
|
|
||||||
| CHANGE_SHOW_PERCENTILES
|
|
||||||
| REMOVE_DIST(int)
|
|
||||||
| ADD_DIST
|
|
||||||
| CHANGE_X_LOG(int)
|
|
||||||
| CHANGE_Y_LOG(int)
|
|
||||||
| CHANGE_IS_CUMULATIVE(int, bool)
|
|
||||||
| HEIGHT_INCREMENT(int)
|
|
||||||
| HEIGHT_DECREMENT(int);
|
|
||||||
|
|
||||||
let changeHeight = (currentHeight, foo: [ | `increment | `decrement]) =>
|
|
||||||
switch (currentHeight, foo) {
|
|
||||||
| (1, `decrement) => 1
|
|
||||||
| (2, `decrement) => 1
|
|
||||||
| (3, `decrement) => 2
|
|
||||||
| (4, `decrement) => 3
|
|
||||||
| (5, `decrement) => 4
|
|
||||||
| (1, `increment) => 2
|
|
||||||
| (2, `increment) => 3
|
|
||||||
| (3, `increment) => 4
|
|
||||||
| (4, `increment) => 5
|
|
||||||
| (5, `increment) => 5
|
|
||||||
| _ => 1
|
|
||||||
};
|
|
||||||
|
|
||||||
let heightToPix =
|
|
||||||
fun
|
|
||||||
| 1 => 80
|
|
||||||
| 2 => 140
|
|
||||||
| 3 => 240
|
|
||||||
| 4 => 340
|
|
||||||
| 5 => 440
|
|
||||||
| _ => 140;
|
|
||||||
|
|
||||||
let distributionReducer = (index, state: list(chartConfig), action) => {
|
|
||||||
switch (action, E.L.get(state, index)) {
|
|
||||||
| (HEIGHT_INCREMENT(_), Some(dist)) =>
|
|
||||||
E.L.update(
|
|
||||||
{...dist, height: changeHeight(dist.height, `increment)},
|
|
||||||
index,
|
|
||||||
state,
|
|
||||||
)
|
|
||||||
| (HEIGHT_DECREMENT(_), Some(dist)) =>
|
|
||||||
E.L.update(
|
|
||||||
{...dist, height: changeHeight(dist.height, `decrement)},
|
|
||||||
index,
|
|
||||||
state,
|
|
||||||
)
|
|
||||||
| (CHANGE_IS_CUMULATIVE(_, isCumulative), Some(dist)) =>
|
|
||||||
E.L.update({...dist, isCumulative}, index, state)
|
|
||||||
| (CHANGE_X_LOG(_), Some(dist)) =>
|
|
||||||
E.L.update({...dist, xLog: !dist.xLog}, index, state)
|
|
||||||
| (CHANGE_Y_LOG(_), Some(dist)) =>
|
|
||||||
E.L.update({...dist, yLog: !dist.yLog}, index, state)
|
|
||||||
| (REMOVE_DIST(_), Some(_)) => E.L.remove(index, 1, state)
|
|
||||||
| (ADD_DIST, Some(_)) =>
|
|
||||||
E.L.append(
|
|
||||||
state,
|
|
||||||
[{yLog: false, xLog: false, isCumulative: false, height: 4}],
|
|
||||||
)
|
|
||||||
| _ => state
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
let reducer = (state: state, action: action) =>
|
|
||||||
switch (action) {
|
|
||||||
| CHANGE_X_LOG(i)
|
|
||||||
| CHANGE_Y_LOG(i)
|
|
||||||
| CHANGE_IS_CUMULATIVE(i, _)
|
|
||||||
| HEIGHT_DECREMENT(i)
|
|
||||||
| REMOVE_DIST(i)
|
|
||||||
| HEIGHT_INCREMENT(i) => {
|
|
||||||
...state,
|
|
||||||
distributions: distributionReducer(i, state.distributions, action),
|
|
||||||
}
|
|
||||||
| ADD_DIST => {
|
|
||||||
...state,
|
|
||||||
distributions: distributionReducer(0, state.distributions, action),
|
|
||||||
}
|
|
||||||
| CHANGE_SHOW_STATS => {...state, showStats: !state.showStats}
|
|
||||||
| CHANGE_SHOW_PARAMS => {...state, showParams: !state.showParams}
|
|
||||||
| CHANGE_SHOW_PERCENTILES => {
|
|
||||||
...state,
|
|
||||||
showPercentiles: !state.showPercentiles,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let init = {
|
|
||||||
showStats: false,
|
|
||||||
showParams: false,
|
|
||||||
showPercentiles: false,
|
|
||||||
distributions: [
|
|
||||||
{yLog: false, xLog: false, isCumulative: false, height: 4},
|
|
||||||
{yLog: false, xLog: false, isCumulative: true, height: 1},
|
|
||||||
],
|
|
||||||
};
|
|
|
@ -1,108 +0,0 @@
|
||||||
module RawPlot = {
|
|
||||||
type primaryDistribution = option<{"xs": array<float>, "ys": array<float>}>
|
|
||||||
|
|
||||||
type discrete = option<{"xs": array<float>, "ys": array<float>}>
|
|
||||||
|
|
||||||
type props
|
|
||||||
type makeType = props => React.element
|
|
||||||
@obj external makeProps: (
|
|
||||||
~height: int=?,
|
|
||||||
~marginBottom: int=?,
|
|
||||||
~marginTop: int=?,
|
|
||||||
~maxX: float=?,
|
|
||||||
~minX: float=?,
|
|
||||||
~yMaxContinuousDomainFactor: float=?,
|
|
||||||
~yMaxDiscreteDomainFactor: float=?,
|
|
||||||
~onHover: float => (),
|
|
||||||
~continuous: option<{"xs": array<float>, "ys": array<float>}>=?,
|
|
||||||
~discrete: option<{"xs": array<float>, "ys": array<float>}>=?,
|
|
||||||
~xScale: string=?,
|
|
||||||
~yScale: string=?,
|
|
||||||
~showDistributionLines: bool=?,
|
|
||||||
~showDistributionYAxis: bool=?,
|
|
||||||
~showVerticalLine: bool=?,
|
|
||||||
~timeScale:Js.Null.t<{"unit": string, "zero": MomentRe.Moment.t}>=?,
|
|
||||||
~verticalLine: int=?,
|
|
||||||
~children: array<React.element>=?,
|
|
||||||
unit // This unit is a quirk of the type system. Apparently it must exist to have optional arguments in a type
|
|
||||||
) => props = ""
|
|
||||||
|
|
||||||
|
|
||||||
@module("./distPlotReact.js")
|
|
||||||
external make : makeType = "default"
|
|
||||||
}
|
|
||||||
|
|
||||||
module Styles = {
|
|
||||||
open CssJs
|
|
||||||
let textOverlay = style(. [position(#absolute)])
|
|
||||||
let mainText = style(. [ fontSize(#em(1.1))])
|
|
||||||
let secondaryText = style(. [fontSize(#em(0.9))])
|
|
||||||
|
|
||||||
let graph = chartColor =>
|
|
||||||
style(. [
|
|
||||||
position(#relative),
|
|
||||||
selector(. ".xAxis", [fontSize(#px(9))]),
|
|
||||||
selector(. ".xAxis .domain", [ display(#none) ]),
|
|
||||||
selector(. ".xAxis .tick line", [ display(#none) ]),
|
|
||||||
selector(. ".xAxis .tick text", [ color(#hex("7a8998")) ]),
|
|
||||||
selector(. ".chart .areaPath", [ SVG.fill(chartColor) ]),
|
|
||||||
selector(. ".lollipopsLine", [ SVG.stroke(#hex("bfcad4")) ]),
|
|
||||||
selector(. ".lollipopsCircle", [ SVG.stroke(#hex("bfcad4")), SVG.fill(#hex("bfcad4")) ]),
|
|
||||||
selector(. ".lollipopsXAxis .domain", [ display(#none) ]),
|
|
||||||
selector(. ".lollipopsXAxis .tick line", [ display(#none) ]),
|
|
||||||
selector(. ".lollipopsXAxis .tick text", [ display(#none) ]),
|
|
||||||
selector(.
|
|
||||||
".lollipopsTooltip",
|
|
||||||
[ position(#absolute),
|
|
||||||
textAlign(#center),
|
|
||||||
padding(px(2)),
|
|
||||||
backgroundColor(hex("bfcad4")),
|
|
||||||
borderRadius(px(3)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
selector(.
|
|
||||||
".lollipopsCircleMouseover",
|
|
||||||
[ SVG.fill(hex("ffa500")), SVG.stroke(#hex("fff")) ],
|
|
||||||
),
|
|
||||||
selector(. ".lollipopsLineMouseover", [ SVG.stroke(#hex("ffa500")) ]),
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
@react.component
|
|
||||||
let make = (
|
|
||||||
~color=#hex("111"),
|
|
||||||
~discrete=?,
|
|
||||||
~height=200,
|
|
||||||
~maxX=?,
|
|
||||||
~minX=?,
|
|
||||||
~yMaxDiscreteDomainFactor=?,
|
|
||||||
~yMaxContinuousDomainFactor=?,
|
|
||||||
~onHover: float => unit=_ => (),
|
|
||||||
~continuous=?,
|
|
||||||
~xScale=?,
|
|
||||||
~yScale=?,
|
|
||||||
~showDistributionLines=false,
|
|
||||||
~showDistributionYAxis=false,
|
|
||||||
~showVerticalLine=false,
|
|
||||||
~timeScale=?,
|
|
||||||
) =>
|
|
||||||
<div className={Styles.graph(color)}>
|
|
||||||
<RawPlot
|
|
||||||
?maxX
|
|
||||||
?minX
|
|
||||||
?yMaxDiscreteDomainFactor
|
|
||||||
?yMaxContinuousDomainFactor
|
|
||||||
?xScale
|
|
||||||
?yScale
|
|
||||||
?timeScale
|
|
||||||
discrete={discrete |> E.O.fmap(SquiggleLang.XYShape.T.toJs)}
|
|
||||||
height
|
|
||||||
marginBottom=50
|
|
||||||
marginTop=0
|
|
||||||
onHover
|
|
||||||
continuous={continuous |> E.O.fmap(SquiggleLang.XYShape.T.toJs)}
|
|
||||||
showDistributionLines
|
|
||||||
showDistributionYAxis
|
|
||||||
showVerticalLine
|
|
||||||
/>
|
|
||||||
</div>
|
|
|
@ -1,10 +0,0 @@
|
||||||
import * as _ from "lodash";
|
|
||||||
import { createClassFromSpec } from "react-vega";
|
|
||||||
import spec from "./spec-percentiles";
|
|
||||||
|
|
||||||
const PercentilesChart = createClassFromSpec({
|
|
||||||
spec,
|
|
||||||
style: "width: 100%",
|
|
||||||
});
|
|
||||||
|
|
||||||
export { PercentilesChart };
|
|
|
@ -1,55 +0,0 @@
|
||||||
open SquiggleLang
|
|
||||||
@module("./PercentilesChart.js")
|
|
||||||
external percentilesChart: React.element = "PercentilesChart"
|
|
||||||
|
|
||||||
module Internal = {
|
|
||||||
type props
|
|
||||||
type makeType = props => React.element
|
|
||||||
type dataType = { "facet": array<
|
|
||||||
{
|
|
||||||
"p1": float,
|
|
||||||
"p10": float,
|
|
||||||
"p20": float,
|
|
||||||
"p30": float,
|
|
||||||
"p40": float,
|
|
||||||
"p5": float,
|
|
||||||
"p50": float,
|
|
||||||
"p60": float,
|
|
||||||
"p70": float,
|
|
||||||
"p80": float,
|
|
||||||
"p90": float,
|
|
||||||
"p95": float,
|
|
||||||
"p99": float,
|
|
||||||
"x": float,
|
|
||||||
}>}
|
|
||||||
@obj external makeProps: (~data: dataType, ~signalListeners: list<string>,~children:React.element, unit) => props = ""
|
|
||||||
|
|
||||||
@module("./PercentilesChart.js")
|
|
||||||
external make : makeType = "PercentilesChart"
|
|
||||||
}
|
|
||||||
|
|
||||||
@react.component
|
|
||||||
@module("./PercentilesChart.js")
|
|
||||||
let make = (~dists: array<(float, PointSetTypes.distPlus)>, ~children=React.null) => {
|
|
||||||
let data = dists -> Belt.Array.map(((x, r)) =>
|
|
||||||
{
|
|
||||||
"x": x,
|
|
||||||
"p1": r |> DistPlus.T.Integral.yToX(0.01),
|
|
||||||
"p5": r |> DistPlus.T.Integral.yToX(0.05),
|
|
||||||
"p10": r |> DistPlus.T.Integral.yToX(0.1),
|
|
||||||
"p20": r |> DistPlus.T.Integral.yToX(0.2),
|
|
||||||
"p30": r |> DistPlus.T.Integral.yToX(0.3),
|
|
||||||
"p40": r |> DistPlus.T.Integral.yToX(0.4),
|
|
||||||
"p50": r |> DistPlus.T.Integral.yToX(0.5),
|
|
||||||
"p60": r |> DistPlus.T.Integral.yToX(0.6),
|
|
||||||
"p70": r |> DistPlus.T.Integral.yToX(0.7),
|
|
||||||
"p80": r |> DistPlus.T.Integral.yToX(0.8),
|
|
||||||
"p90": r |> DistPlus.T.Integral.yToX(0.9),
|
|
||||||
"p95": r |> DistPlus.T.Integral.yToX(0.95),
|
|
||||||
"p99": r |> DistPlus.T.Integral.yToX(0.99),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
Js.log3("Data", dists, data)
|
|
||||||
let da = {"facet": data}
|
|
||||||
<Internal data=da signalListeners=list{}>children</Internal>
|
|
||||||
}
|
|
|
@ -1,658 +0,0 @@
|
||||||
const _ = require('lodash');
|
|
||||||
const d3 = require('d3');
|
|
||||||
const moment = require('moment');
|
|
||||||
require('./styles.css');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param arr
|
|
||||||
* @returns {*}
|
|
||||||
*/
|
|
||||||
function exists(arr) {
|
|
||||||
return arr.find(num => _.isFinite(num));
|
|
||||||
}
|
|
||||||
|
|
||||||
export class DistPlotD3 {
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.attrs = {
|
|
||||||
svgWidth: 400,
|
|
||||||
svgHeight: 400,
|
|
||||||
marginTop: 5,
|
|
||||||
marginBottom: 5,
|
|
||||||
marginRight: 50,
|
|
||||||
marginLeft: 5,
|
|
||||||
|
|
||||||
container: null,
|
|
||||||
|
|
||||||
// X
|
|
||||||
minX: null,
|
|
||||||
maxX: null,
|
|
||||||
xScaleType: 'linear',
|
|
||||||
xScaleTimeOptions: null,
|
|
||||||
xScaleLogBase: 10,
|
|
||||||
|
|
||||||
// Y
|
|
||||||
minY: null,
|
|
||||||
maxY: null,
|
|
||||||
yScaleType: 'linear',
|
|
||||||
yScaleTimeOptions: null,
|
|
||||||
yScaleLogBase: 10,
|
|
||||||
|
|
||||||
xMinContinuousDomainFactor: 1,
|
|
||||||
xMaxContinuousDomainFactor: 1,
|
|
||||||
yMaxContinuousDomainFactor: 1,
|
|
||||||
yMaxDiscreteDomainFactor: 1,
|
|
||||||
|
|
||||||
showDistributionYAxis: false,
|
|
||||||
showDistributionLines: true,
|
|
||||||
|
|
||||||
areaColors: ['#E1E5EC', '#E1E5EC'],
|
|
||||||
verticalLine: 110,
|
|
||||||
showVerticalLine: true,
|
|
||||||
data: {
|
|
||||||
continuous: null,
|
|
||||||
discrete: null,
|
|
||||||
},
|
|
||||||
onHover: (e) => {
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
this.calc = {
|
|
||||||
chartLeftMargin: null,
|
|
||||||
chartTopMargin: null,
|
|
||||||
chartWidth: null,
|
|
||||||
chartHeight: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.chart = null;
|
|
||||||
this.svg = null;
|
|
||||||
this._container = null;
|
|
||||||
|
|
||||||
this.formatDates = this.formatDates.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} name
|
|
||||||
* @param value
|
|
||||||
* @returns {DistPlotD3}
|
|
||||||
*/
|
|
||||||
set(name, value) {
|
|
||||||
_.set(this.attrs, [name], value);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param data
|
|
||||||
* @returns {DistPlotD3}
|
|
||||||
*/
|
|
||||||
data(data) {
|
|
||||||
const continuousXs = _.get(data, 'continuous.xs', []);
|
|
||||||
const continuousYs = _.get(data, 'continuous.ys', []);
|
|
||||||
const discreteXs = _.get(data, 'discrete.xs', []);
|
|
||||||
const discreteYs = _.get(data, 'discrete.ys', []);
|
|
||||||
this.attrs.data = data;
|
|
||||||
this.attrs.data.continuous = {
|
|
||||||
xs: continuousXs,
|
|
||||||
ys: continuousYs,
|
|
||||||
};
|
|
||||||
this.attrs.data.discrete = {
|
|
||||||
xs: discreteXs,
|
|
||||||
ys: discreteYs,
|
|
||||||
};
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
this._container = d3.select(this.attrs.container);
|
|
||||||
if (this._container.node() === null) {
|
|
||||||
throw new Error('Container for D3 is not defined.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!['log', 'linear'].includes(this.attrs.xScaleType)) {
|
|
||||||
throw new Error('X-scale type should be either "log" or "linear".');
|
|
||||||
}
|
|
||||||
if (!['log', 'linear'].includes(this.attrs.yScaleType)) {
|
|
||||||
throw new Error('Y-scale type should be either "log" or "linear".');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log Scale.
|
|
||||||
if (this.attrs.xScaleType === 'log') {
|
|
||||||
this.logFilter('continuous', (x, y) => x > 0);
|
|
||||||
this.logFilter('discrete', (x, y) => x > 0);
|
|
||||||
}
|
|
||||||
if (this.attrs.yScaleType === 'log') {
|
|
||||||
this.logFilter('continuous', (x, y) => y > 0);
|
|
||||||
this.logFilter('discrete', (x, y) => y > 0);
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
this.attrs.xScaleType === 'log'
|
|
||||||
&& this.attrs.minX !== null
|
|
||||||
&& this.attrs.minX < 0
|
|
||||||
) {
|
|
||||||
console.warn('minX should be positive.');
|
|
||||||
this.attrs.minX = undefined;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
this.attrs.yScaleType === 'log'
|
|
||||||
&& this.attrs.minY !== null
|
|
||||||
&& this.attrs.minY < 0
|
|
||||||
) {
|
|
||||||
console.warn('minY should be positive.');
|
|
||||||
this.attrs.minY = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fields.
|
|
||||||
const fields = [
|
|
||||||
'marginLeft', 'marginRight',
|
|
||||||
'marginTop', 'marginBottom',
|
|
||||||
'svgWidth', 'svgHeight',
|
|
||||||
'yMaxContinuousDomainFactor',
|
|
||||||
'yMaxDiscreteDomainFactor',
|
|
||||||
'xScaleLogBase', 'yScaleLogBase',
|
|
||||||
];
|
|
||||||
for (const field of fields) {
|
|
||||||
if (!_.isNumber(this.attrs[field])) {
|
|
||||||
throw new Error(`${field} should be a number.`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sets the width from the DOM element.
|
|
||||||
const containerRect = this._container.node().getBoundingClientRect();
|
|
||||||
if (containerRect.width > 0) {
|
|
||||||
this.attrs.svgWidth = containerRect.width;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculated properties.
|
|
||||||
this.calc.chartLeftMargin = this.attrs.marginLeft;
|
|
||||||
this.calc.chartTopMargin = this.attrs.marginTop;
|
|
||||||
this.calc.chartWidth = this.attrs.svgWidth
|
|
||||||
- this.attrs.marginRight
|
|
||||||
- this.attrs.marginLeft;
|
|
||||||
this.calc.chartHeight = this.attrs.svgHeight
|
|
||||||
- this.attrs.marginBottom
|
|
||||||
- this.attrs.marginTop;
|
|
||||||
|
|
||||||
// Add svg.
|
|
||||||
this.svg = this._container
|
|
||||||
.createObject({ tag: 'svg', selector: 'svg-chart-container' })
|
|
||||||
.attr('width', '100%')
|
|
||||||
.attr('height', this.attrs.svgHeight)
|
|
||||||
.attr('pointer-events', 'none');
|
|
||||||
|
|
||||||
// Add container 'g' (empty) element.
|
|
||||||
this.chart = this.svg
|
|
||||||
.createObject({ tag: 'g', selector: 'chart' })
|
|
||||||
.attr(
|
|
||||||
'transform',
|
|
||||||
`translate(${this.calc.chartLeftMargin}, ${this.calc.chartTopMargin})`,
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const common = this.getCommonThings();
|
|
||||||
if (this.hasDate('continuous')) {
|
|
||||||
this.addDistributionChart(common);
|
|
||||||
}
|
|
||||||
if (this.hasDate('discrete')) {
|
|
||||||
this.addLollipopsChart(common);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
this._container.selectAll("*").remove();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {*}
|
|
||||||
*/
|
|
||||||
getCommonThings() {
|
|
||||||
// Boundaries.
|
|
||||||
const xMin = exists([
|
|
||||||
this.attrs.minX,
|
|
||||||
d3.min(this.attrs.data.continuous.xs),
|
|
||||||
d3.min(this.attrs.data.discrete.xs),
|
|
||||||
]);
|
|
||||||
const xMax = exists([
|
|
||||||
this.attrs.maxX,
|
|
||||||
d3.max(this.attrs.data.continuous.xs),
|
|
||||||
d3.max(this.attrs.data.discrete.xs),
|
|
||||||
]);
|
|
||||||
|
|
||||||
const yMin = exists([
|
|
||||||
this.attrs.minY,
|
|
||||||
d3.min(this.attrs.data.continuous.ys),
|
|
||||||
d3.min(this.attrs.data.discrete.ys),
|
|
||||||
]);
|
|
||||||
const yMax = exists([
|
|
||||||
this.attrs.maxY,
|
|
||||||
d3.max(this.attrs.data.continuous.ys),
|
|
||||||
d3.max(this.attrs.data.discrete.ys),
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Errors.
|
|
||||||
if (!_.isFinite(xMin)) throw new Error('xMin is undefined');
|
|
||||||
if (!_.isFinite(xMax)) throw new Error('xMax is undefined');
|
|
||||||
if (!_.isFinite(yMin)) throw new Error('yMin is undefined');
|
|
||||||
if (!_.isFinite(yMax)) throw new Error('yMax is undefined');
|
|
||||||
|
|
||||||
// X-domains.
|
|
||||||
const xMinDomainFactor = _.get(this.attrs, 'xMinContinuousDomainFactor', 1);
|
|
||||||
const xMaxDomainFactor = _.get(this.attrs, 'xMaxContinuousDomainFactor', 1);
|
|
||||||
const yMinDomainFactor = _.get(this.attrs, 'yMinContinuousDomainFactor', 1);
|
|
||||||
const yMaxDomainFactor = _.get(this.attrs, 'yMaxContinuousDomainFactor', 1);
|
|
||||||
|
|
||||||
const xMinDomain = xMin * xMinDomainFactor;
|
|
||||||
const xMaxDomain = xMax * xMaxDomainFactor;
|
|
||||||
const yMinDomain = yMin * yMinDomainFactor;
|
|
||||||
const yMaxDomain = yMax * yMaxDomainFactor;
|
|
||||||
|
|
||||||
// X-scale.
|
|
||||||
const xScale = this.attrs.xScaleType === 'linear'
|
|
||||||
? d3.scaleLinear()
|
|
||||||
.domain([xMinDomain, xMaxDomain])
|
|
||||||
.range([0, this.calc.chartWidth])
|
|
||||||
: d3.scaleLog()
|
|
||||||
.base(this.attrs.xScaleLogBase)
|
|
||||||
.domain([xMinDomain, xMaxDomain])
|
|
||||||
.range([0, this.calc.chartWidth]);
|
|
||||||
|
|
||||||
// Y-scale.
|
|
||||||
const yScale = this.attrs.yScaleType === 'linear'
|
|
||||||
? d3.scaleLinear()
|
|
||||||
.domain([yMinDomain, yMaxDomain])
|
|
||||||
.range([this.calc.chartHeight, 0])
|
|
||||||
: d3.scaleLog()
|
|
||||||
.base(this.attrs.yScaleLogBase)
|
|
||||||
.domain([yMinDomain, yMaxDomain])
|
|
||||||
.range([this.calc.chartHeight, 0]);
|
|
||||||
|
|
||||||
return {
|
|
||||||
xMin, xMax,
|
|
||||||
xScale, yScale,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param common
|
|
||||||
*/
|
|
||||||
addDistributionChart(common) {
|
|
||||||
const areaColorRange = d3.scaleOrdinal().range(this.attrs.areaColors);
|
|
||||||
const dataPoints = [this.getDataPoints('continuous')];
|
|
||||||
|
|
||||||
const { xMin, xMax, xScale, yScale } = common;
|
|
||||||
|
|
||||||
// X-axis.
|
|
||||||
let xAxis = null;
|
|
||||||
if (!!this.attrs.xScaleTimeOptions) {
|
|
||||||
// Calculates the projection on X-axis.
|
|
||||||
const zero = _.get(this.attrs, 'xScaleTimeOptions.zero', moment());
|
|
||||||
const unit = _.get(this.attrs, 'xScaleTimeOptions.unit', 'years');
|
|
||||||
const diff = Math.abs(xMax - xMin);
|
|
||||||
const left = zero.clone().add(xMin, unit);
|
|
||||||
const right = left.clone().add(diff, unit);
|
|
||||||
|
|
||||||
// X-time-scale.
|
|
||||||
const xScaleTime = d3.scaleTime()
|
|
||||||
.domain([left.toDate(), right.toDate()])
|
|
||||||
.nice()
|
|
||||||
.range([0, this.calc.chartWidth]);
|
|
||||||
|
|
||||||
xAxis = d3.axisBottom()
|
|
||||||
.scale(xScaleTime)
|
|
||||||
.ticks(this.getTimeTicksByStr(unit))
|
|
||||||
.tickFormat(this.formatDates);
|
|
||||||
} else {
|
|
||||||
xAxis = d3.axisBottom(xScale)
|
|
||||||
.ticks(3)
|
|
||||||
.tickFormat(d => {
|
|
||||||
if (Math.abs(d) < 1) {
|
|
||||||
return d3.format('.2')(d);
|
|
||||||
} else if (xMin > 1000 && xMax < 3000) {
|
|
||||||
// Condition which identifies years; 2019, 2020, 2021.
|
|
||||||
return d3.format('.0')(d);
|
|
||||||
} else {
|
|
||||||
const prefix = d3.formatPrefix('.0', d);
|
|
||||||
return prefix(d).replace('G', 'B');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Y-axis.
|
|
||||||
const yAxis = d3.axisRight(yScale);
|
|
||||||
|
|
||||||
// Add axis.
|
|
||||||
this.chart
|
|
||||||
.createObject({ tag: 'g', selector: 'x-axis' })
|
|
||||||
.attr('transform', `translate(0, ${this.calc.chartHeight})`)
|
|
||||||
.call(xAxis);
|
|
||||||
|
|
||||||
if (this.attrs.showDistributionYAxis) {
|
|
||||||
this.chart
|
|
||||||
.createObject({ tag: 'g', selector: 'y-axis' })
|
|
||||||
.call(yAxis);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw area.
|
|
||||||
const area = d3.area()
|
|
||||||
.x(d => xScale(d.x))
|
|
||||||
.y1(d => yScale(d.y))
|
|
||||||
.y0(this.calc.chartHeight);
|
|
||||||
|
|
||||||
this.chart
|
|
||||||
.createObjectsWithData({
|
|
||||||
tag: 'path',
|
|
||||||
selector: 'area-path',
|
|
||||||
data: dataPoints,
|
|
||||||
})
|
|
||||||
.attr('d', area)
|
|
||||||
.attr('fill', (d, i) => areaColorRange(i))
|
|
||||||
.attr('opacity', (d, i) => i === 0 ? 0.7 : 0.5);
|
|
||||||
|
|
||||||
// Draw line.
|
|
||||||
if (this.attrs.showDistributionLines) {
|
|
||||||
const line = d3.line()
|
|
||||||
.x(d => xScale(d.x))
|
|
||||||
.y(d => yScale(d.y));
|
|
||||||
|
|
||||||
this.chart
|
|
||||||
.createObjectsWithData({
|
|
||||||
tag: 'path',
|
|
||||||
selector: 'line-path',
|
|
||||||
data: dataPoints,
|
|
||||||
})
|
|
||||||
.attr('d', line)
|
|
||||||
.attr('id', (d, i) => 'line-' + (i + 1))
|
|
||||||
.attr('opacity', (d, i) => i === 0 ? 0.7 : 1)
|
|
||||||
.attr('fill', 'none');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.attrs.showVerticalLine) {
|
|
||||||
this.chart
|
|
||||||
.createObject({ tag: 'line', selector: 'v-line' })
|
|
||||||
.attr('x1', xScale(this.attrs.verticalLine))
|
|
||||||
.attr('x2', xScale(this.attrs.verticalLine))
|
|
||||||
.attr('y1', 0)
|
|
||||||
.attr('y2', this.calc.chartHeight)
|
|
||||||
.attr('stroke-width', 1.5)
|
|
||||||
.attr('stroke-dasharray', '6 6')
|
|
||||||
.attr('stroke', 'steelblue');
|
|
||||||
}
|
|
||||||
|
|
||||||
const hoverLine = this.chart
|
|
||||||
.createObject({ tag: 'line', selector: 'hover-line' })
|
|
||||||
.attr('x1', 0)
|
|
||||||
.attr('x2', 0)
|
|
||||||
.attr('y1', 0)
|
|
||||||
.attr('y2', this.calc.chartHeight)
|
|
||||||
.attr('opacity', 0)
|
|
||||||
.attr('stroke-width', 1.5)
|
|
||||||
.attr('stroke-dasharray', '6 6')
|
|
||||||
.attr('stroke', '#22313F');
|
|
||||||
|
|
||||||
// Add drawing rectangle.
|
|
||||||
{
|
|
||||||
const context = this;
|
|
||||||
|
|
||||||
function mouseover() {
|
|
||||||
const mouse = d3.mouse(this);
|
|
||||||
hoverLine
|
|
||||||
.attr('opacity', 1)
|
|
||||||
.attr('x1', mouse[0])
|
|
||||||
.attr('x2', mouse[0]);
|
|
||||||
const xValue = xScale.invert(mouse[0]);
|
|
||||||
context.attrs.onHover(xValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
function mouseout() {
|
|
||||||
hoverLine.attr('opacity', 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.chart
|
|
||||||
.createObject({ tag: 'rect', selector: 'mouse-rect' })
|
|
||||||
.attr('width', this.calc.chartWidth)
|
|
||||||
.attr('height', this.calc.chartHeight)
|
|
||||||
.attr('fill', 'transparent')
|
|
||||||
.attr('pointer-events', 'all')
|
|
||||||
.on('mouseover', mouseover)
|
|
||||||
.on('mousemove', mouseover)
|
|
||||||
.on('mouseout', mouseout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {object} common
|
|
||||||
* @param {object} common.xScale
|
|
||||||
* @param {object} common.yScale
|
|
||||||
*/
|
|
||||||
addLollipopsChart(common) {
|
|
||||||
const data = this.getDataPoints('discrete');
|
|
||||||
|
|
||||||
const yMin = 0.;
|
|
||||||
const yMax = d3.max(this.attrs.data.discrete.ys);
|
|
||||||
|
|
||||||
// X axis.
|
|
||||||
this.chart.append('g')
|
|
||||||
.attr('class', 'lollipops-x-axis')
|
|
||||||
.attr('transform', `translate(0, ${this.calc.chartHeight})`)
|
|
||||||
.call(d3.axisBottom(common.xScale));
|
|
||||||
|
|
||||||
// Y-domain.
|
|
||||||
const yMinDomainFactor = _.get(this.attrs, 'yMinDiscreteDomainFactor', 1);
|
|
||||||
const yMaxDomainFactor = _.get(this.attrs, 'yMaxDiscreteDomainFactor', 1);
|
|
||||||
const yMinDomain = yMin * yMinDomainFactor;
|
|
||||||
const yMaxDomain = yMax * yMaxDomainFactor;
|
|
||||||
|
|
||||||
// Y-scale.
|
|
||||||
const yScale = this.attrs.yScaleType === 'linear'
|
|
||||||
? d3.scaleLinear()
|
|
||||||
.domain([yMinDomain, yMaxDomain])
|
|
||||||
.range([this.calc.chartHeight, 0])
|
|
||||||
: d3.scaleLog()
|
|
||||||
.base(this.attrs.yScaleLogBase)
|
|
||||||
.domain([yMinDomain, yMaxDomain])
|
|
||||||
.range([this.calc.chartHeight, 0]);
|
|
||||||
|
|
||||||
//
|
|
||||||
const yTicks = Math.floor(this.calc.chartHeight / 20);
|
|
||||||
const yAxis = d3.axisLeft(yScale).ticks(yTicks);
|
|
||||||
|
|
||||||
// Adds 'g' for an y-axis.
|
|
||||||
this.chart.append('g')
|
|
||||||
.attr('class', 'lollipops-y-axis')
|
|
||||||
.attr('transform', `translate(${this.calc.chartWidth}, 0)`)
|
|
||||||
.call(yAxis);
|
|
||||||
|
|
||||||
const thi$ = this;
|
|
||||||
|
|
||||||
function showTooltip(d) {
|
|
||||||
thi$.chart.select('.lollipops-line-' + d.id)
|
|
||||||
.classed('lollipops-line-mouseover', true);
|
|
||||||
thi$.chart.select('.lollipops-circle-' + d.id)
|
|
||||||
.classed('lollipops-circle-mouseover', true)
|
|
||||||
.attr('r', 6);
|
|
||||||
tooltip.transition()
|
|
||||||
.style('opacity', .9);
|
|
||||||
tooltip.html(`x: ${d.x}, y: ${(d.y * 100).toFixed(1)}%`)
|
|
||||||
.style('left', (common.xScale(d.x) + 60) + 'px')
|
|
||||||
.style('top', yScale(d.y) + 'px');
|
|
||||||
}
|
|
||||||
|
|
||||||
function hideTooltip(d) {
|
|
||||||
thi$.chart.select('.lollipops-line-' + d.id)
|
|
||||||
.classed('lollipops-line-mouseover', false);
|
|
||||||
thi$.chart.select('.lollipops-circle-' + d.id)
|
|
||||||
.classed('lollipops-circle-mouseover', false)
|
|
||||||
.attr('r', 4);
|
|
||||||
tooltip.transition()
|
|
||||||
.style('opacity', 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lines.
|
|
||||||
this.chart.selectAll('lollipops-line')
|
|
||||||
.data(data)
|
|
||||||
.enter()
|
|
||||||
.append('line')
|
|
||||||
.attr('class', 'lollipops-line')
|
|
||||||
.attr('class', d => 'lollipops-line lollipops-line-' + d.id)
|
|
||||||
.attr('x1', d => common.xScale(d.x))
|
|
||||||
.attr('x2', d => common.xScale(d.x))
|
|
||||||
.attr('y1', d => yScale(d.y))
|
|
||||||
.attr('y2', yScale(yMin));
|
|
||||||
|
|
||||||
// Define the div for the tooltip
|
|
||||||
const tooltip = this._container.append('div')
|
|
||||||
.attr('class', 'lollipop-tooltip')
|
|
||||||
.style('opacity', 0);
|
|
||||||
|
|
||||||
// Circles.
|
|
||||||
this.chart.selectAll('lollipops-circle')
|
|
||||||
.data(data)
|
|
||||||
.enter()
|
|
||||||
.append('circle')
|
|
||||||
.attr('class', d => 'lollipops-circle lollipops-circle-' + d.id)
|
|
||||||
.attr('cx', d => common.xScale(d.x))
|
|
||||||
.attr('cy', d => yScale(d.y))
|
|
||||||
.attr('r', '4');
|
|
||||||
|
|
||||||
// Rectangles.
|
|
||||||
this.chart.selectAll('lollipops-rectangle')
|
|
||||||
.data(data)
|
|
||||||
.enter()
|
|
||||||
.append('rect')
|
|
||||||
.attr('width', 30)
|
|
||||||
.attr('height', d => this.calc.chartHeight - yScale(d.y) + 10)
|
|
||||||
.attr('x', d => common.xScale(d.x) - 15)
|
|
||||||
.attr('y', d => yScale(d.y) - 10)
|
|
||||||
.attr('opacity', 0)
|
|
||||||
.attr('pointer-events', 'all')
|
|
||||||
.on('mouseover', showTooltip)
|
|
||||||
.on('mouseout', hideTooltip)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param ts
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
formatDates(ts) {
|
|
||||||
return moment(ts).format('MMMM Do YYYY');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} unit
|
|
||||||
* @returns {*}
|
|
||||||
*/
|
|
||||||
getTimeTicksByStr(unit) {
|
|
||||||
switch (unit) {
|
|
||||||
case 'months':
|
|
||||||
return d3.timeMonth.every(4);
|
|
||||||
case 'quarters':
|
|
||||||
// It is temporary solution, but it works
|
|
||||||
// if the difference between edge dates is not
|
|
||||||
// much more than 10 units.
|
|
||||||
return d3.timeMonth.every(12);
|
|
||||||
case 'hours':
|
|
||||||
return d3.timeHour.every(10);
|
|
||||||
case 'days':
|
|
||||||
return d3.timeDay.every(7);
|
|
||||||
case 'seconds':
|
|
||||||
return d3.timeSecond.every(10);
|
|
||||||
case 'years':
|
|
||||||
return d3.timeYear.every(10);
|
|
||||||
case 'minutes':
|
|
||||||
return d3.timeMinute.every(10);
|
|
||||||
case 'weeks':
|
|
||||||
return d3.timeWeek.every(10);
|
|
||||||
case 'milliseconds':
|
|
||||||
return d3.timeMillisecond.every(10);
|
|
||||||
default:
|
|
||||||
return d3.timeYear.every(10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} key
|
|
||||||
* @returns {{x: number[], y: number[]}}
|
|
||||||
*/
|
|
||||||
getDataPoints(key) {
|
|
||||||
const dt = [];
|
|
||||||
const emptyShape = { xs: [], ys: [] };
|
|
||||||
const data = _.get(this.attrs.data, key, emptyShape);
|
|
||||||
const len = data.xs.length;
|
|
||||||
|
|
||||||
for (let i = 0; i < len; i++) {
|
|
||||||
const x = data.xs[i];
|
|
||||||
const y = data.ys[i];
|
|
||||||
const id = i;
|
|
||||||
dt.push({ x, y, id });
|
|
||||||
}
|
|
||||||
|
|
||||||
return dt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} key
|
|
||||||
* @param {function} pred
|
|
||||||
* @returns {{x: number[], y: number[]}}
|
|
||||||
*/
|
|
||||||
logFilter(key, pred) {
|
|
||||||
const xs = [];
|
|
||||||
const ys = [];
|
|
||||||
const emptyShape = { xs: [], ys: [] };
|
|
||||||
const data = _.get(this.attrs.data, key, emptyShape);
|
|
||||||
|
|
||||||
for (let i = 0, len = data.xs.length; i < len; i++) {
|
|
||||||
const x = data.xs[i];
|
|
||||||
const y = data.ys[i];
|
|
||||||
if (pred(x, y)) {
|
|
||||||
xs.push(x);
|
|
||||||
ys.push(y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_.set(this.attrs.data, [key, 'xs'], xs);
|
|
||||||
_.set(this.attrs.data, [key, 'ys'], ys);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} key
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
hasDate(key) {
|
|
||||||
const xs = _.get(this.attrs, ['data', key, 'xs']);
|
|
||||||
return !!_.size(xs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @docs: https://github.com/d3/d3-selection
|
|
||||||
* @param {object} params
|
|
||||||
* @param {string} params.selector
|
|
||||||
* @param {string} params.tag
|
|
||||||
* @returns {*}
|
|
||||||
*/
|
|
||||||
d3.selection.prototype.createObject = function createObject(params) {
|
|
||||||
const selector = params.selector;
|
|
||||||
const tag = params.tag;
|
|
||||||
return this.insert(tag).attr('class', selector);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @docs: https://github.com/d3/d3-selection
|
|
||||||
* @param {object} params
|
|
||||||
* @param {string} params.selector
|
|
||||||
* @param {string} params.tag
|
|
||||||
* @param {*[]} params.data
|
|
||||||
* @returns {*}
|
|
||||||
*/
|
|
||||||
d3.selection.prototype.createObjectsWithData = function createObjectsWithData(params) {
|
|
||||||
const selector = params.selector;
|
|
||||||
const tag = params.tag;
|
|
||||||
const data = params.data;
|
|
||||||
|
|
||||||
return this.selectAll('.' + selector)
|
|
||||||
.data(data)
|
|
||||||
.enter()
|
|
||||||
.insert(tag)
|
|
||||||
.attr('class', selector);
|
|
||||||
};
|
|
|
@ -1,81 +0,0 @@
|
||||||
import React, { useEffect } from 'react';
|
|
||||||
import { useSize } from 'react-use';
|
|
||||||
import { DistPlotD3 } from './distPlotD3';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param min
|
|
||||||
* @param max
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
function getRandomInt(min, max) {
|
|
||||||
min = Math.ceil(min);
|
|
||||||
max = Math.floor(max);
|
|
||||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param props
|
|
||||||
* @returns {*}
|
|
||||||
* @constructor
|
|
||||||
*/
|
|
||||||
function DistPlotReact(props) {
|
|
||||||
const containerRef = React.createRef();
|
|
||||||
const key = "cdf-chart-react-" + getRandomInt(0, 1000);
|
|
||||||
const style = !!props.width ? { width: props.width + "px" } : {};
|
|
||||||
|
|
||||||
const [sized, { width }] = useSize(() => {
|
|
||||||
return React.createElement("div", {
|
|
||||||
key: "resizable-div",
|
|
||||||
});
|
|
||||||
}, {
|
|
||||||
width: props.width,
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
try {
|
|
||||||
new DistPlotD3()
|
|
||||||
.set('svgWidth', width)
|
|
||||||
.set('svgHeight', props.height)
|
|
||||||
.set('maxX', props.maxX)
|
|
||||||
.set('minX', props.minX)
|
|
||||||
.set('onHover', props.onHover)
|
|
||||||
.set('marginBottom', props.marginBottom || 15)
|
|
||||||
.set('marginLeft', 30)
|
|
||||||
.set('marginRight', 30)
|
|
||||||
.set('marginTop', 5)
|
|
||||||
.set('showDistributionLines', props.showDistributionLines)
|
|
||||||
.set('showDistributionYAxis', props.showDistributionYAxis)
|
|
||||||
.set('verticalLine', props.verticalLine || 110)
|
|
||||||
.set('showVerticalLine', props.showVerticalLine)
|
|
||||||
.set('container', containerRef.current)
|
|
||||||
.set('xScaleType', props.xScale || 'linear')
|
|
||||||
.set('yScaleType', props.yScale || 'linear')
|
|
||||||
.set('xScaleTimeOptions', props.timeScale)
|
|
||||||
.set('yMaxContinuousDomainFactor', props.yMaxContinuousDomainFactor || 1)
|
|
||||||
.set('yMaxDiscreteDomainFactor', props.yMaxDiscreteDomainFactor || 1)
|
|
||||||
.data({
|
|
||||||
continuous: props.continuous,
|
|
||||||
discrete: props.discrete,
|
|
||||||
})
|
|
||||||
.render();
|
|
||||||
} catch (e) {
|
|
||||||
console.error("distPlotD3 Error: ", e)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return React.createElement("div", {
|
|
||||||
style: {
|
|
||||||
paddingLeft: "10px",
|
|
||||||
paddingRight: "10px",
|
|
||||||
},
|
|
||||||
}, [
|
|
||||||
sized,
|
|
||||||
React.createElement("div", {
|
|
||||||
key,
|
|
||||||
style,
|
|
||||||
ref: containerRef,
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DistPlotReact;
|
|
|
@ -1,208 +0,0 @@
|
||||||
{
|
|
||||||
"$schema": "https://vega.github.io/schema/vega/v5.json",
|
|
||||||
"width": 500,
|
|
||||||
"height": 400,
|
|
||||||
"padding": 5,
|
|
||||||
"data": [
|
|
||||||
{
|
|
||||||
"name": "facet",
|
|
||||||
"values": [],
|
|
||||||
"format": { "type": "json", "parse": { "timestamp": "date" } }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "table",
|
|
||||||
"source": "facet",
|
|
||||||
"transform": [
|
|
||||||
{
|
|
||||||
"type": "aggregate",
|
|
||||||
"groupby": ["x"],
|
|
||||||
"ops": [
|
|
||||||
"mean",
|
|
||||||
"mean",
|
|
||||||
"mean",
|
|
||||||
"mean",
|
|
||||||
"mean",
|
|
||||||
"mean",
|
|
||||||
"mean",
|
|
||||||
"mean",
|
|
||||||
"mean",
|
|
||||||
"mean",
|
|
||||||
"mean",
|
|
||||||
"mean",
|
|
||||||
"mean"
|
|
||||||
],
|
|
||||||
"fields": [
|
|
||||||
"p1",
|
|
||||||
"p5",
|
|
||||||
"p10",
|
|
||||||
"p20",
|
|
||||||
"p30",
|
|
||||||
"p40",
|
|
||||||
"p50",
|
|
||||||
"p60",
|
|
||||||
"p70",
|
|
||||||
"p80",
|
|
||||||
"p90",
|
|
||||||
"p95",
|
|
||||||
"p99"
|
|
||||||
],
|
|
||||||
"as": [
|
|
||||||
"p1",
|
|
||||||
"p5",
|
|
||||||
"p10",
|
|
||||||
"p20",
|
|
||||||
"p30",
|
|
||||||
"p40",
|
|
||||||
"p50",
|
|
||||||
"p60",
|
|
||||||
"p70",
|
|
||||||
"p80",
|
|
||||||
"p90",
|
|
||||||
"p95",
|
|
||||||
"p99"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"scales": [
|
|
||||||
{
|
|
||||||
"name": "xscale",
|
|
||||||
"type": "linear",
|
|
||||||
"nice": true,
|
|
||||||
"domain": { "data": "facet", "field": "x" },
|
|
||||||
"range": "width"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "yscale",
|
|
||||||
"type": "linear",
|
|
||||||
"range": "height",
|
|
||||||
"nice": true,
|
|
||||||
"zero": true,
|
|
||||||
"domain": { "data": "facet", "field": "p99" }
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"axes": [
|
|
||||||
{
|
|
||||||
"orient": "bottom",
|
|
||||||
"scale": "xscale",
|
|
||||||
"grid": false,
|
|
||||||
"tickSize": 2,
|
|
||||||
"encode": {
|
|
||||||
"grid": { "enter": { "stroke": { "value": "#ccc" } } },
|
|
||||||
"ticks": { "enter": { "stroke": { "value": "#ccc" } } }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"orient": "left",
|
|
||||||
"scale": "yscale",
|
|
||||||
"grid": false,
|
|
||||||
"domain": false,
|
|
||||||
"tickSize": 2,
|
|
||||||
"encode": {
|
|
||||||
"grid": { "enter": { "stroke": { "value": "#ccc" } } },
|
|
||||||
"ticks": { "enter": { "stroke": { "value": "#ccc" } } }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"marks": [
|
|
||||||
{
|
|
||||||
"type": "area",
|
|
||||||
"from": { "data": "table" },
|
|
||||||
"encode": {
|
|
||||||
"enter": { "fill": { "value": "#4C78A8" } },
|
|
||||||
"update": {
|
|
||||||
"interpolate": { "value": "monotone" },
|
|
||||||
"x": { "scale": "xscale", "field": "x" },
|
|
||||||
"y": { "scale": "yscale", "field": "p1" },
|
|
||||||
"y2": { "scale": "yscale", "field": "p99" },
|
|
||||||
"opacity": { "value": 0.05 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "area",
|
|
||||||
"from": { "data": "table" },
|
|
||||||
"encode": {
|
|
||||||
"enter": { "fill": { "value": "#4C78A8" } },
|
|
||||||
"update": {
|
|
||||||
"interpolate": { "value": "monotone" },
|
|
||||||
"x": { "scale": "xscale", "field": "x" },
|
|
||||||
"y": { "scale": "yscale", "field": "p5" },
|
|
||||||
"y2": { "scale": "yscale", "field": "p95" },
|
|
||||||
"opacity": { "value": 0.1 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "area",
|
|
||||||
"from": { "data": "table" },
|
|
||||||
"encode": {
|
|
||||||
"enter": { "fill": { "value": "#4C78A8" } },
|
|
||||||
"update": {
|
|
||||||
"interpolate": { "value": "monotone" },
|
|
||||||
"x": { "scale": "xscale", "field": "x" },
|
|
||||||
"y": { "scale": "yscale", "field": "p10" },
|
|
||||||
"y2": { "scale": "yscale", "field": "p90" },
|
|
||||||
"opacity": { "value": 0.15 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "area",
|
|
||||||
"from": { "data": "table" },
|
|
||||||
"encode": {
|
|
||||||
"enter": { "fill": { "value": "#4C78A8" } },
|
|
||||||
"update": {
|
|
||||||
"interpolate": { "value": "monotone" },
|
|
||||||
"x": { "scale": "xscale", "field": "x" },
|
|
||||||
"y": { "scale": "yscale", "field": "p20" },
|
|
||||||
"y2": { "scale": "yscale", "field": "p80" },
|
|
||||||
"opacity": { "value": 0.2 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "area",
|
|
||||||
"from": { "data": "table" },
|
|
||||||
"encode": {
|
|
||||||
"enter": { "fill": { "value": "#4C78A8" } },
|
|
||||||
"update": {
|
|
||||||
"interpolate": { "value": "monotone" },
|
|
||||||
"x": { "scale": "xscale", "field": "x" },
|
|
||||||
"y": { "scale": "yscale", "field": "p30" },
|
|
||||||
"y2": { "scale": "yscale", "field": "p70" },
|
|
||||||
"opacity": { "value": 0.2 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "area",
|
|
||||||
"from": { "data": "table" },
|
|
||||||
"encode": {
|
|
||||||
"enter": { "fill": { "value": "#4C78A8" } },
|
|
||||||
"update": {
|
|
||||||
"interpolate": { "value": "monotone" },
|
|
||||||
"x": { "scale": "xscale", "field": "x" },
|
|
||||||
"y": { "scale": "yscale", "field": "p40" },
|
|
||||||
"y2": { "scale": "yscale", "field": "p60" },
|
|
||||||
"opacity": { "value": 0.2 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "line",
|
|
||||||
"from": { "data": "table" },
|
|
||||||
"encode": {
|
|
||||||
"update": {
|
|
||||||
"interpolate": { "value": "monotone" },
|
|
||||||
"stroke": { "value": "#4C78A8" },
|
|
||||||
"strokeWidth": { "value": 2 },
|
|
||||||
"opacity": { "value": 0.8 },
|
|
||||||
"x": { "scale": "xscale", "field": "x" },
|
|
||||||
"y": { "scale": "yscale", "field": "p50" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
.lollipops-line-mouseover {
|
|
||||||
stroke-dasharray: 4;
|
|
||||||
animation: dash 2s linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes dash {
|
|
||||||
to {
|
|
||||||
stroke-dashoffset: 1000;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
module JS = {
|
|
||||||
@deriving(abstract)
|
|
||||||
type numberPresentation = {
|
|
||||||
value: string,
|
|
||||||
power: option<float>,
|
|
||||||
symbol: option<string>,
|
|
||||||
}
|
|
||||||
|
|
||||||
@module("./numberShower.js")
|
|
||||||
external numberShow: (float, int) => numberPresentation = "numberShow"
|
|
||||||
}
|
|
||||||
|
|
||||||
let sup = {
|
|
||||||
open CssJs
|
|
||||||
style(. [ fontSize(#em(0.6)), verticalAlign(#super) ])
|
|
||||||
}
|
|
||||||
|
|
||||||
@react.component
|
|
||||||
let make = (~number, ~precision) => {
|
|
||||||
let numberWithPresentation = JS.numberShow(number, precision)
|
|
||||||
<span>
|
|
||||||
{JS.valueGet(numberWithPresentation) |> React.string}
|
|
||||||
{JS.symbolGet(numberWithPresentation) |> R.O.fmapOrNull(React.string)}
|
|
||||||
{JS.powerGet(numberWithPresentation) |> R.O.fmapOrNull(e =>
|
|
||||||
<span>
|
|
||||||
{j`\\u00b710` |> React.string}
|
|
||||||
<span className=sup> {e |> E.Float.toString |> React.string} </span>
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
// 105 -> 3
|
|
||||||
const orderOfMagnitudeNum = (n) => {
|
|
||||||
return Math.pow(10, n);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 105 -> 3
|
|
||||||
const orderOfMagnitude = (n) => {
|
|
||||||
return Math.floor(Math.log(n) / Math.LN10 + 0.000000001);
|
|
||||||
};
|
|
||||||
|
|
||||||
function withXSigFigs(number, sigFigs) {
|
|
||||||
const withPrecision = number.toPrecision(sigFigs);
|
|
||||||
const formatted = Number(withPrecision);
|
|
||||||
return `${formatted}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
class NumberShower {
|
|
||||||
constructor(number, precision = 2) {
|
|
||||||
this.number = number;
|
|
||||||
this.precision = precision;
|
|
||||||
}
|
|
||||||
|
|
||||||
convert() {
|
|
||||||
const number = Math.abs(this.number);
|
|
||||||
const response = this.evaluate(number);
|
|
||||||
if (this.number < 0) {
|
|
||||||
response.value = '-' + response.value;
|
|
||||||
}
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
|
|
||||||
metricSystem(number, order) {
|
|
||||||
const newNumber = number / orderOfMagnitudeNum(order);
|
|
||||||
const precision = this.precision;
|
|
||||||
return `${withXSigFigs(newNumber, precision)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
evaluate(number) {
|
|
||||||
if (number === 0) {
|
|
||||||
return { value: this.metricSystem(0, 0) }
|
|
||||||
}
|
|
||||||
|
|
||||||
const order = orderOfMagnitude(number);
|
|
||||||
if (order < -2) {
|
|
||||||
return { value: this.metricSystem(number, order), power: order };
|
|
||||||
} else if (order < 4) {
|
|
||||||
return { value: this.metricSystem(number, 0) };
|
|
||||||
} else if (order < 6) {
|
|
||||||
return { value: this.metricSystem(number, 3), symbol: 'K' };
|
|
||||||
} else if (order < 9) {
|
|
||||||
return { value: this.metricSystem(number, 6), symbol: 'M' };
|
|
||||||
} else if (order < 12) {
|
|
||||||
return { value: this.metricSystem(number, 9), symbol: 'B' };
|
|
||||||
} else if (order < 15) {
|
|
||||||
return { value: this.metricSystem(number, 12), symbol: 'T' };
|
|
||||||
} else {
|
|
||||||
return { value: this.metricSystem(number, order), power: order };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function numberShow(number, precision = 2) {
|
|
||||||
const ns = new NumberShower(number, precision);
|
|
||||||
return ns.convert();
|
|
||||||
}
|
|
|
@ -5,9 +5,9 @@
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Squiggle Language</title>
|
<title>Squiggle Language</title>
|
||||||
<link href="https://fonts.googleapis.com/css?family=Lato:300,400,700,900" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css?family=Lato:300,400,700,900" rel="stylesheet">
|
||||||
<link href="./styles/index.css" rel="stylesheet">
|
|
||||||
<link href="./styles/antd.css" rel="stylesheet">
|
<link href="./styles/antd.css" rel="stylesheet">
|
||||||
<script type="module" src="./Index.bs.js" defer></script>
|
<link href="./styles/index.css" rel="stylesheet">
|
||||||
|
<script type="module" src="./Index.tsx" defer></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
@tailwind base;
|
@tailwind base;
|
||||||
|
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
|
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
9
packages/playground/tailwind.config.js
Normal file
9
packages/playground/tailwind.config.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
module.exports = {
|
||||||
|
content: [
|
||||||
|
"./src/components/*.tsx"
|
||||||
|
],
|
||||||
|
theme: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
plugins: [],
|
||||||
|
}
|
|
@ -1,694 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
prefix: '',
|
|
||||||
important: false,
|
|
||||||
separator: ':',
|
|
||||||
theme: {
|
|
||||||
screens: {
|
|
||||||
sm: '640px',
|
|
||||||
md: '768px',
|
|
||||||
lg: '1024px',
|
|
||||||
xl: '1280px',
|
|
||||||
},
|
|
||||||
colors: {
|
|
||||||
transparent: 'transparent',
|
|
||||||
|
|
||||||
black: '#000',
|
|
||||||
white: '#fff',
|
|
||||||
|
|
||||||
gray: {
|
|
||||||
100: '#f7fafc',
|
|
||||||
200: '#edf2f7',
|
|
||||||
300: '#e2e8f0',
|
|
||||||
400: '#cbd5e0',
|
|
||||||
500: '#a0aec0',
|
|
||||||
600: '#718096',
|
|
||||||
700: '#4a5568',
|
|
||||||
800: '#2d3748',
|
|
||||||
900: '#1a202c',
|
|
||||||
},
|
|
||||||
red: {
|
|
||||||
100: '#fff5f5',
|
|
||||||
200: '#fed7d7',
|
|
||||||
300: '#feb2b2',
|
|
||||||
400: '#fc8181',
|
|
||||||
500: '#f56565',
|
|
||||||
600: '#e53e3e',
|
|
||||||
700: '#c53030',
|
|
||||||
800: '#9b2c2c',
|
|
||||||
900: '#742a2a',
|
|
||||||
},
|
|
||||||
orange: {
|
|
||||||
100: '#fffaf0',
|
|
||||||
200: '#feebc8',
|
|
||||||
300: '#fbd38d',
|
|
||||||
400: '#f6ad55',
|
|
||||||
500: '#ed8936',
|
|
||||||
600: '#dd6b20',
|
|
||||||
700: '#c05621',
|
|
||||||
800: '#9c4221',
|
|
||||||
900: '#7b341e',
|
|
||||||
},
|
|
||||||
yellow: {
|
|
||||||
100: '#fffff0',
|
|
||||||
200: '#fefcbf',
|
|
||||||
300: '#faf089',
|
|
||||||
400: '#f6e05e',
|
|
||||||
500: '#ecc94b',
|
|
||||||
600: '#d69e2e',
|
|
||||||
700: '#b7791f',
|
|
||||||
800: '#975a16',
|
|
||||||
900: '#744210',
|
|
||||||
},
|
|
||||||
green: {
|
|
||||||
100: '#f0fff4',
|
|
||||||
200: '#c6f6d5',
|
|
||||||
300: '#9ae6b4',
|
|
||||||
400: '#68d391',
|
|
||||||
500: '#48bb78',
|
|
||||||
600: '#38a169',
|
|
||||||
700: '#2f855a',
|
|
||||||
800: '#276749',
|
|
||||||
900: '#22543d',
|
|
||||||
},
|
|
||||||
teal: {
|
|
||||||
100: '#e6fffa',
|
|
||||||
200: '#b2f5ea',
|
|
||||||
300: '#81e6d9',
|
|
||||||
400: '#4fd1c5',
|
|
||||||
500: '#38b2ac',
|
|
||||||
600: '#319795',
|
|
||||||
700: '#2c7a7b',
|
|
||||||
800: '#285e61',
|
|
||||||
900: '#234e52',
|
|
||||||
},
|
|
||||||
blue: {
|
|
||||||
100: '#ebf8ff',
|
|
||||||
200: '#bee3f8',
|
|
||||||
300: '#90cdf4',
|
|
||||||
400: '#63b3ed',
|
|
||||||
500: '#4299e1',
|
|
||||||
600: '#3182ce',
|
|
||||||
700: '#2b6cb0',
|
|
||||||
800: '#2c5282',
|
|
||||||
900: '#2a4365',
|
|
||||||
},
|
|
||||||
indigo: {
|
|
||||||
100: '#ebf4ff',
|
|
||||||
200: '#c3dafe',
|
|
||||||
300: '#a3bffa',
|
|
||||||
400: '#7f9cf5',
|
|
||||||
500: '#667eea',
|
|
||||||
600: '#5a67d8',
|
|
||||||
700: '#4c51bf',
|
|
||||||
800: '#434190',
|
|
||||||
900: '#3c366b',
|
|
||||||
},
|
|
||||||
purple: {
|
|
||||||
100: '#faf5ff',
|
|
||||||
200: '#e9d8fd',
|
|
||||||
300: '#d6bcfa',
|
|
||||||
400: '#b794f4',
|
|
||||||
500: '#9f7aea',
|
|
||||||
600: '#805ad5',
|
|
||||||
700: '#6b46c1',
|
|
||||||
800: '#553c9a',
|
|
||||||
900: '#44337a',
|
|
||||||
},
|
|
||||||
pink: {
|
|
||||||
100: '#fff5f7',
|
|
||||||
200: '#fed7e2',
|
|
||||||
300: '#fbb6ce',
|
|
||||||
400: '#f687b3',
|
|
||||||
500: '#ed64a6',
|
|
||||||
600: '#d53f8c',
|
|
||||||
700: '#b83280',
|
|
||||||
800: '#97266d',
|
|
||||||
900: '#702459',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
spacing: {
|
|
||||||
px: '1px',
|
|
||||||
'0': '0',
|
|
||||||
'1': '0.25rem',
|
|
||||||
'2': '0.5rem',
|
|
||||||
'3': '0.75rem',
|
|
||||||
'4': '1rem',
|
|
||||||
'5': '1.25rem',
|
|
||||||
'6': '1.5rem',
|
|
||||||
'8': '2rem',
|
|
||||||
'10': '2.5rem',
|
|
||||||
'12': '3rem',
|
|
||||||
'16': '4rem',
|
|
||||||
'20': '5rem',
|
|
||||||
'24': '6rem',
|
|
||||||
'32': '8rem',
|
|
||||||
'40': '10rem',
|
|
||||||
'48': '12rem',
|
|
||||||
'56': '14rem',
|
|
||||||
'64': '16rem',
|
|
||||||
},
|
|
||||||
backgroundColor: theme => theme('colors'),
|
|
||||||
backgroundPosition: {
|
|
||||||
bottom: 'bottom',
|
|
||||||
center: 'center',
|
|
||||||
left: 'left',
|
|
||||||
'left-bottom': 'left bottom',
|
|
||||||
'left-top': 'left top',
|
|
||||||
right: 'right',
|
|
||||||
'right-bottom': 'right bottom',
|
|
||||||
'right-top': 'right top',
|
|
||||||
top: 'top',
|
|
||||||
},
|
|
||||||
backgroundSize: {
|
|
||||||
auto: 'auto',
|
|
||||||
cover: 'cover',
|
|
||||||
contain: 'contain',
|
|
||||||
},
|
|
||||||
borderColor: theme => ({
|
|
||||||
...theme('colors'),
|
|
||||||
default: theme('colors.gray.300', 'currentColor'),
|
|
||||||
}),
|
|
||||||
borderRadius: {
|
|
||||||
none: '0',
|
|
||||||
sm: '0.125rem',
|
|
||||||
default: '0.25rem',
|
|
||||||
md: '0.375rem',
|
|
||||||
lg: '0.5rem',
|
|
||||||
full: '9999px',
|
|
||||||
},
|
|
||||||
borderWidth: {
|
|
||||||
default: '1px',
|
|
||||||
'0': '0',
|
|
||||||
'2': '2px',
|
|
||||||
'4': '4px',
|
|
||||||
'8': '8px',
|
|
||||||
},
|
|
||||||
boxShadow: {
|
|
||||||
xs: '0 0 0 1px rgba(0, 0, 0, 0.05)',
|
|
||||||
sm: '0 1px 2px 0 rgba(0, 0, 0, 0.05)',
|
|
||||||
default: '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)',
|
|
||||||
md: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
|
|
||||||
lg: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
|
|
||||||
xl: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
|
|
||||||
'2xl': '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
|
|
||||||
inner: 'inset 0 2px 4px 0 rgba(0, 0, 0, 0.06)',
|
|
||||||
outline: '0 0 0 3px rgba(66, 153, 225, 0.5)',
|
|
||||||
none: 'none',
|
|
||||||
},
|
|
||||||
container: {},
|
|
||||||
cursor: {
|
|
||||||
auto: 'auto',
|
|
||||||
default: 'default',
|
|
||||||
pointer: 'pointer',
|
|
||||||
wait: 'wait',
|
|
||||||
text: 'text',
|
|
||||||
move: 'move',
|
|
||||||
'not-allowed': 'not-allowed',
|
|
||||||
},
|
|
||||||
fill: {
|
|
||||||
current: 'currentColor',
|
|
||||||
},
|
|
||||||
flex: {
|
|
||||||
'1': '1 1 0%',
|
|
||||||
auto: '1 1 auto',
|
|
||||||
initial: '0 1 auto',
|
|
||||||
none: 'none',
|
|
||||||
},
|
|
||||||
flexGrow: {
|
|
||||||
'0': '0',
|
|
||||||
default: '1',
|
|
||||||
},
|
|
||||||
flexShrink: {
|
|
||||||
'0': '0',
|
|
||||||
default: '1',
|
|
||||||
},
|
|
||||||
fontFamily: {
|
|
||||||
sans: [
|
|
||||||
'system-ui',
|
|
||||||
'-apple-system',
|
|
||||||
'BlinkMacSystemFont',
|
|
||||||
'"Segoe UI"',
|
|
||||||
'Roboto',
|
|
||||||
'"Helvetica Neue"',
|
|
||||||
'Arial',
|
|
||||||
'"Noto Sans"',
|
|
||||||
'sans-serif',
|
|
||||||
'"Apple Color Emoji"',
|
|
||||||
'"Segoe UI Emoji"',
|
|
||||||
'"Segoe UI Symbol"',
|
|
||||||
'"Noto Color Emoji"',
|
|
||||||
],
|
|
||||||
serif: ['Georgia', 'Cambria', '"Times New Roman"', 'Times', 'serif'],
|
|
||||||
mono: ['Menlo', 'Monaco', 'Consolas', '"Liberation Mono"', '"Courier New"', 'monospace'],
|
|
||||||
},
|
|
||||||
fontSize: {
|
|
||||||
xs: '0.75rem',
|
|
||||||
sm: '0.875rem',
|
|
||||||
base: '1rem',
|
|
||||||
lg: '1.125rem',
|
|
||||||
xl: '1.25rem',
|
|
||||||
'2xl': '1.5rem',
|
|
||||||
'3xl': '1.875rem',
|
|
||||||
'4xl': '2.25rem',
|
|
||||||
'5xl': '3rem',
|
|
||||||
'6xl': '4rem',
|
|
||||||
},
|
|
||||||
fontWeight: {
|
|
||||||
hairline: '100',
|
|
||||||
thin: '200',
|
|
||||||
light: '300',
|
|
||||||
normal: '400',
|
|
||||||
medium: '500',
|
|
||||||
semibold: '600',
|
|
||||||
bold: '700',
|
|
||||||
extrabold: '800',
|
|
||||||
black: '900',
|
|
||||||
},
|
|
||||||
height: theme => ({
|
|
||||||
auto: 'auto',
|
|
||||||
...theme('spacing'),
|
|
||||||
full: '100%',
|
|
||||||
screen: '100vh',
|
|
||||||
}),
|
|
||||||
inset: {
|
|
||||||
'0': '0',
|
|
||||||
auto: 'auto',
|
|
||||||
},
|
|
||||||
letterSpacing: {
|
|
||||||
tighter: '-0.05em',
|
|
||||||
tight: '-0.025em',
|
|
||||||
normal: '0',
|
|
||||||
wide: '0.025em',
|
|
||||||
wider: '0.05em',
|
|
||||||
widest: '0.1em',
|
|
||||||
},
|
|
||||||
lineHeight: {
|
|
||||||
none: '1',
|
|
||||||
tight: '1.25',
|
|
||||||
snug: '1.375',
|
|
||||||
normal: '1.5',
|
|
||||||
relaxed: '1.625',
|
|
||||||
loose: '2',
|
|
||||||
'3': '.75rem',
|
|
||||||
'4': '1rem',
|
|
||||||
'5': '1.25rem',
|
|
||||||
'6': '1.5rem',
|
|
||||||
'7': '1.75rem',
|
|
||||||
'8': '2rem',
|
|
||||||
'9': '2.25rem',
|
|
||||||
'10': '2.5rem',
|
|
||||||
},
|
|
||||||
listStyleType: {
|
|
||||||
none: 'none',
|
|
||||||
disc: 'disc',
|
|
||||||
decimal: 'decimal',
|
|
||||||
},
|
|
||||||
margin: (theme, { negative }) => ({
|
|
||||||
auto: 'auto',
|
|
||||||
...theme('spacing'),
|
|
||||||
...negative(theme('spacing')),
|
|
||||||
}),
|
|
||||||
maxHeight: {
|
|
||||||
full: '100%',
|
|
||||||
screen: '100vh',
|
|
||||||
},
|
|
||||||
maxWidth: (theme, { breakpoints }) => ({
|
|
||||||
none: 'none',
|
|
||||||
xs: '20rem',
|
|
||||||
sm: '24rem',
|
|
||||||
md: '28rem',
|
|
||||||
lg: '32rem',
|
|
||||||
xl: '36rem',
|
|
||||||
'2xl': '42rem',
|
|
||||||
'3xl': '48rem',
|
|
||||||
'4xl': '56rem',
|
|
||||||
'5xl': '64rem',
|
|
||||||
'6xl': '72rem',
|
|
||||||
full: '100%',
|
|
||||||
...breakpoints(theme('screens')),
|
|
||||||
}),
|
|
||||||
minHeight: {
|
|
||||||
'0': '0',
|
|
||||||
full: '100%',
|
|
||||||
screen: '100vh',
|
|
||||||
},
|
|
||||||
minWidth: {
|
|
||||||
'0': '0',
|
|
||||||
full: '100%',
|
|
||||||
},
|
|
||||||
objectPosition: {
|
|
||||||
bottom: 'bottom',
|
|
||||||
center: 'center',
|
|
||||||
left: 'left',
|
|
||||||
'left-bottom': 'left bottom',
|
|
||||||
'left-top': 'left top',
|
|
||||||
right: 'right',
|
|
||||||
'right-bottom': 'right bottom',
|
|
||||||
'right-top': 'right top',
|
|
||||||
top: 'top',
|
|
||||||
},
|
|
||||||
opacity: {
|
|
||||||
'0': '0',
|
|
||||||
'25': '0.25',
|
|
||||||
'50': '0.5',
|
|
||||||
'75': '0.75',
|
|
||||||
'100': '1',
|
|
||||||
},
|
|
||||||
order: {
|
|
||||||
first: '-9999',
|
|
||||||
last: '9999',
|
|
||||||
none: '0',
|
|
||||||
'1': '1',
|
|
||||||
'2': '2',
|
|
||||||
'3': '3',
|
|
||||||
'4': '4',
|
|
||||||
'5': '5',
|
|
||||||
'6': '6',
|
|
||||||
'7': '7',
|
|
||||||
'8': '8',
|
|
||||||
'9': '9',
|
|
||||||
'10': '10',
|
|
||||||
'11': '11',
|
|
||||||
'12': '12',
|
|
||||||
},
|
|
||||||
padding: theme => theme('spacing'),
|
|
||||||
placeholderColor: theme => theme('colors'),
|
|
||||||
stroke: {
|
|
||||||
current: 'currentColor',
|
|
||||||
},
|
|
||||||
strokeWidth: {
|
|
||||||
'0': '0',
|
|
||||||
'1': '1',
|
|
||||||
'2': '2',
|
|
||||||
},
|
|
||||||
textColor: theme => theme('colors'),
|
|
||||||
width: theme => ({
|
|
||||||
auto: 'auto',
|
|
||||||
...theme('spacing'),
|
|
||||||
'1/2': '50%',
|
|
||||||
'1/3': '33.333333%',
|
|
||||||
'2/3': '66.666667%',
|
|
||||||
'1/4': '25%',
|
|
||||||
'2/4': '50%',
|
|
||||||
'3/4': '75%',
|
|
||||||
'1/5': '20%',
|
|
||||||
'2/5': '40%',
|
|
||||||
'3/5': '60%',
|
|
||||||
'4/5': '80%',
|
|
||||||
'1/6': '16.666667%',
|
|
||||||
'2/6': '33.333333%',
|
|
||||||
'3/6': '50%',
|
|
||||||
'4/6': '66.666667%',
|
|
||||||
'5/6': '83.333333%',
|
|
||||||
'1/12': '8.333333%',
|
|
||||||
'2/12': '16.666667%',
|
|
||||||
'3/12': '25%',
|
|
||||||
'4/12': '33.333333%',
|
|
||||||
'5/12': '41.666667%',
|
|
||||||
'6/12': '50%',
|
|
||||||
'7/12': '58.333333%',
|
|
||||||
'8/12': '66.666667%',
|
|
||||||
'9/12': '75%',
|
|
||||||
'10/12': '83.333333%',
|
|
||||||
'11/12': '91.666667%',
|
|
||||||
full: '100%',
|
|
||||||
screen: '100vw',
|
|
||||||
}),
|
|
||||||
zIndex: {
|
|
||||||
auto: 'auto',
|
|
||||||
'0': '0',
|
|
||||||
'10': '10',
|
|
||||||
'20': '20',
|
|
||||||
'30': '30',
|
|
||||||
'40': '40',
|
|
||||||
'50': '50',
|
|
||||||
},
|
|
||||||
gap: theme => theme('spacing'),
|
|
||||||
gridTemplateColumns: {
|
|
||||||
none: 'none',
|
|
||||||
'1': 'repeat(1, minmax(0, 1fr))',
|
|
||||||
'2': 'repeat(2, minmax(0, 1fr))',
|
|
||||||
'3': 'repeat(3, minmax(0, 1fr))',
|
|
||||||
'4': 'repeat(4, minmax(0, 1fr))',
|
|
||||||
'5': 'repeat(5, minmax(0, 1fr))',
|
|
||||||
'6': 'repeat(6, minmax(0, 1fr))',
|
|
||||||
'7': 'repeat(7, minmax(0, 1fr))',
|
|
||||||
'8': 'repeat(8, minmax(0, 1fr))',
|
|
||||||
'9': 'repeat(9, minmax(0, 1fr))',
|
|
||||||
'10': 'repeat(10, minmax(0, 1fr))',
|
|
||||||
'11': 'repeat(11, minmax(0, 1fr))',
|
|
||||||
'12': 'repeat(12, minmax(0, 1fr))',
|
|
||||||
},
|
|
||||||
gridColumn: {
|
|
||||||
auto: 'auto',
|
|
||||||
'span-1': 'span 1 / span 1',
|
|
||||||
'span-2': 'span 2 / span 2',
|
|
||||||
'span-3': 'span 3 / span 3',
|
|
||||||
'span-4': 'span 4 / span 4',
|
|
||||||
'span-5': 'span 5 / span 5',
|
|
||||||
'span-6': 'span 6 / span 6',
|
|
||||||
'span-7': 'span 7 / span 7',
|
|
||||||
'span-8': 'span 8 / span 8',
|
|
||||||
'span-9': 'span 9 / span 9',
|
|
||||||
'span-10': 'span 10 / span 10',
|
|
||||||
'span-11': 'span 11 / span 11',
|
|
||||||
'span-12': 'span 12 / span 12',
|
|
||||||
},
|
|
||||||
gridColumnStart: {
|
|
||||||
auto: 'auto',
|
|
||||||
'1': '1',
|
|
||||||
'2': '2',
|
|
||||||
'3': '3',
|
|
||||||
'4': '4',
|
|
||||||
'5': '5',
|
|
||||||
'6': '6',
|
|
||||||
'7': '7',
|
|
||||||
'8': '8',
|
|
||||||
'9': '9',
|
|
||||||
'10': '10',
|
|
||||||
'11': '11',
|
|
||||||
'12': '12',
|
|
||||||
'13': '13',
|
|
||||||
},
|
|
||||||
gridColumnEnd: {
|
|
||||||
auto: 'auto',
|
|
||||||
'1': '1',
|
|
||||||
'2': '2',
|
|
||||||
'3': '3',
|
|
||||||
'4': '4',
|
|
||||||
'5': '5',
|
|
||||||
'6': '6',
|
|
||||||
'7': '7',
|
|
||||||
'8': '8',
|
|
||||||
'9': '9',
|
|
||||||
'10': '10',
|
|
||||||
'11': '11',
|
|
||||||
'12': '12',
|
|
||||||
'13': '13',
|
|
||||||
},
|
|
||||||
gridTemplateRows: {
|
|
||||||
none: 'none',
|
|
||||||
'1': 'repeat(1, minmax(0, 1fr))',
|
|
||||||
'2': 'repeat(2, minmax(0, 1fr))',
|
|
||||||
'3': 'repeat(3, minmax(0, 1fr))',
|
|
||||||
'4': 'repeat(4, minmax(0, 1fr))',
|
|
||||||
'5': 'repeat(5, minmax(0, 1fr))',
|
|
||||||
'6': 'repeat(6, minmax(0, 1fr))',
|
|
||||||
},
|
|
||||||
gridRow: {
|
|
||||||
auto: 'auto',
|
|
||||||
'span-1': 'span 1 / span 1',
|
|
||||||
'span-2': 'span 2 / span 2',
|
|
||||||
'span-3': 'span 3 / span 3',
|
|
||||||
'span-4': 'span 4 / span 4',
|
|
||||||
'span-5': 'span 5 / span 5',
|
|
||||||
'span-6': 'span 6 / span 6',
|
|
||||||
},
|
|
||||||
gridRowStart: {
|
|
||||||
auto: 'auto',
|
|
||||||
'1': '1',
|
|
||||||
'2': '2',
|
|
||||||
'3': '3',
|
|
||||||
'4': '4',
|
|
||||||
'5': '5',
|
|
||||||
'6': '6',
|
|
||||||
'7': '7',
|
|
||||||
},
|
|
||||||
gridRowEnd: {
|
|
||||||
auto: 'auto',
|
|
||||||
'1': '1',
|
|
||||||
'2': '2',
|
|
||||||
'3': '3',
|
|
||||||
'4': '4',
|
|
||||||
'5': '5',
|
|
||||||
'6': '6',
|
|
||||||
'7': '7',
|
|
||||||
},
|
|
||||||
transformOrigin: {
|
|
||||||
center: 'center',
|
|
||||||
top: 'top',
|
|
||||||
'top-right': 'top right',
|
|
||||||
right: 'right',
|
|
||||||
'bottom-right': 'bottom right',
|
|
||||||
bottom: 'bottom',
|
|
||||||
'bottom-left': 'bottom left',
|
|
||||||
left: 'left',
|
|
||||||
'top-left': 'top left',
|
|
||||||
},
|
|
||||||
scale: {
|
|
||||||
'0': '0',
|
|
||||||
'50': '.5',
|
|
||||||
'75': '.75',
|
|
||||||
'90': '.9',
|
|
||||||
'95': '.95',
|
|
||||||
'100': '1',
|
|
||||||
'105': '1.05',
|
|
||||||
'110': '1.1',
|
|
||||||
'125': '1.25',
|
|
||||||
'150': '1.5',
|
|
||||||
},
|
|
||||||
rotate: {
|
|
||||||
'-180': '-180deg',
|
|
||||||
'-90': '-90deg',
|
|
||||||
'-45': '-45deg',
|
|
||||||
'0': '0',
|
|
||||||
'45': '45deg',
|
|
||||||
'90': '90deg',
|
|
||||||
'180': '180deg',
|
|
||||||
},
|
|
||||||
translate: (theme, { negative }) => ({
|
|
||||||
...theme('spacing'),
|
|
||||||
...negative(theme('spacing')),
|
|
||||||
'-full': '-100%',
|
|
||||||
'-1/2': '-50%',
|
|
||||||
'1/2': '50%',
|
|
||||||
full: '100%',
|
|
||||||
}),
|
|
||||||
skew: {
|
|
||||||
'-12': '-12deg',
|
|
||||||
'-6': '-6deg',
|
|
||||||
'-3': '-3deg',
|
|
||||||
'0': '0',
|
|
||||||
'3': '3deg',
|
|
||||||
'6': '6deg',
|
|
||||||
'12': '12deg',
|
|
||||||
},
|
|
||||||
transitionProperty: {
|
|
||||||
none: 'none',
|
|
||||||
all: 'all',
|
|
||||||
default: 'background-color, border-color, color, fill, stroke, opacity, box-shadow, transform',
|
|
||||||
colors: 'background-color, border-color, color, fill, stroke',
|
|
||||||
opacity: 'opacity',
|
|
||||||
shadow: 'box-shadow',
|
|
||||||
transform: 'transform',
|
|
||||||
},
|
|
||||||
transitionTimingFunction: {
|
|
||||||
linear: 'linear',
|
|
||||||
in: 'cubic-bezier(0.4, 0, 1, 1)',
|
|
||||||
out: 'cubic-bezier(0, 0, 0.2, 1)',
|
|
||||||
'in-out': 'cubic-bezier(0.4, 0, 0.2, 1)',
|
|
||||||
},
|
|
||||||
transitionDuration: {
|
|
||||||
'75': '75ms',
|
|
||||||
'100': '100ms',
|
|
||||||
'150': '150ms',
|
|
||||||
'200': '200ms',
|
|
||||||
'300': '300ms',
|
|
||||||
'500': '500ms',
|
|
||||||
'700': '700ms',
|
|
||||||
'1000': '1000ms',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
variants: {
|
|
||||||
accessibility: ['responsive', 'focus'],
|
|
||||||
alignContent: ['responsive'],
|
|
||||||
alignItems: ['responsive'],
|
|
||||||
alignSelf: ['responsive'],
|
|
||||||
appearance: ['responsive'],
|
|
||||||
backgroundAttachment: ['responsive'],
|
|
||||||
backgroundColor: ['responsive', 'hover', 'focus'],
|
|
||||||
backgroundPosition: ['responsive'],
|
|
||||||
backgroundRepeat: ['responsive'],
|
|
||||||
backgroundSize: ['responsive'],
|
|
||||||
borderCollapse: ['responsive'],
|
|
||||||
borderColor: ['responsive', 'hover', 'focus'],
|
|
||||||
borderRadius: ['responsive'],
|
|
||||||
borderStyle: ['responsive'],
|
|
||||||
borderWidth: ['responsive'],
|
|
||||||
boxShadow: ['responsive', 'hover', 'focus'],
|
|
||||||
boxSizing: ['responsive'],
|
|
||||||
cursor: ['responsive'],
|
|
||||||
display: ['responsive'],
|
|
||||||
fill: ['responsive'],
|
|
||||||
flex: ['responsive'],
|
|
||||||
flexDirection: ['responsive'],
|
|
||||||
flexGrow: ['responsive'],
|
|
||||||
flexShrink: ['responsive'],
|
|
||||||
flexWrap: ['responsive'],
|
|
||||||
float: ['responsive'],
|
|
||||||
clear: ['responsive'],
|
|
||||||
fontFamily: ['responsive'],
|
|
||||||
fontSize: ['responsive'],
|
|
||||||
fontSmoothing: ['responsive'],
|
|
||||||
fontStyle: ['responsive'],
|
|
||||||
fontWeight: ['responsive', 'hover', 'focus'],
|
|
||||||
height: ['responsive'],
|
|
||||||
inset: ['responsive'],
|
|
||||||
justifyContent: ['responsive'],
|
|
||||||
letterSpacing: ['responsive'],
|
|
||||||
lineHeight: ['responsive'],
|
|
||||||
listStylePosition: ['responsive'],
|
|
||||||
listStyleType: ['responsive'],
|
|
||||||
margin: ['responsive'],
|
|
||||||
maxHeight: ['responsive'],
|
|
||||||
maxWidth: ['responsive'],
|
|
||||||
minHeight: ['responsive'],
|
|
||||||
minWidth: ['responsive'],
|
|
||||||
objectFit: ['responsive'],
|
|
||||||
objectPosition: ['responsive'],
|
|
||||||
opacity: ['responsive', 'hover', 'focus'],
|
|
||||||
order: ['responsive'],
|
|
||||||
outline: ['responsive', 'focus'],
|
|
||||||
overflow: ['responsive'],
|
|
||||||
padding: ['responsive'],
|
|
||||||
placeholderColor: ['responsive', 'focus'],
|
|
||||||
pointerEvents: ['responsive'],
|
|
||||||
position: ['responsive'],
|
|
||||||
resize: ['responsive'],
|
|
||||||
stroke: ['responsive'],
|
|
||||||
strokeWidth: ['responsive'],
|
|
||||||
tableLayout: ['responsive'],
|
|
||||||
textAlign: ['responsive'],
|
|
||||||
textColor: ['responsive', 'hover', 'focus'],
|
|
||||||
textDecoration: ['responsive', 'hover', 'focus'],
|
|
||||||
textTransform: ['responsive'],
|
|
||||||
userSelect: ['responsive'],
|
|
||||||
verticalAlign: ['responsive'],
|
|
||||||
visibility: ['responsive'],
|
|
||||||
whitespace: ['responsive'],
|
|
||||||
width: ['responsive'],
|
|
||||||
wordBreak: ['responsive'],
|
|
||||||
zIndex: ['responsive'],
|
|
||||||
gap: ['responsive'],
|
|
||||||
gridAutoFlow: ['responsive'],
|
|
||||||
gridTemplateColumns: ['responsive'],
|
|
||||||
gridColumn: ['responsive'],
|
|
||||||
gridColumnStart: ['responsive'],
|
|
||||||
gridColumnEnd: ['responsive'],
|
|
||||||
gridTemplateRows: ['responsive'],
|
|
||||||
gridRow: ['responsive'],
|
|
||||||
gridRowStart: ['responsive'],
|
|
||||||
gridRowEnd: ['responsive'],
|
|
||||||
transform: ['responsive'],
|
|
||||||
transformOrigin: ['responsive'],
|
|
||||||
scale: ['responsive', 'hover', 'focus'],
|
|
||||||
rotate: ['responsive', 'hover', 'focus'],
|
|
||||||
translate: ['responsive', 'hover', 'focus'],
|
|
||||||
skew: ['responsive', 'hover', 'focus'],
|
|
||||||
transitionProperty: ['responsive'],
|
|
||||||
transitionTimingFunction: ['responsive'],
|
|
||||||
transitionDuration: ['responsive'],
|
|
||||||
},
|
|
||||||
corePlugins: {},
|
|
||||||
plugins: [],
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
@react.component
|
|
||||||
let make = (
|
|
||||||
~disabled: bool=?,
|
|
||||||
~ghost: bool=?,
|
|
||||||
~href: string=?,
|
|
||||||
~htmlType: @string [#button | #submit | #submit]=?,
|
|
||||||
~icon: 'a=?,
|
|
||||||
~shape: @string [#circle | #round]=?,
|
|
||||||
~size: @string [#small | #large]=?,
|
|
||||||
~target: string=?,
|
|
||||||
~loading: bool=?,
|
|
||||||
~_type: @string
|
|
||||||
[
|
|
||||||
| #primary
|
|
||||||
| #default
|
|
||||||
| #dashed
|
|
||||||
| #danger
|
|
||||||
| #link
|
|
||||||
| #ghost
|
|
||||||
]=?,
|
|
||||||
~onClick: ReactEvent.Mouse.t => unit=?,
|
|
||||||
~block: bool=?,
|
|
||||||
~children: React.element=?,
|
|
||||||
~className: string=?,
|
|
||||||
~id: string=?,
|
|
||||||
~testId: string=?,
|
|
||||||
) =>
|
|
||||||
ReasonReact.cloneElement(
|
|
||||||
<AntButton
|
|
||||||
_type
|
|
||||||
disabled
|
|
||||||
ghost
|
|
||||||
href
|
|
||||||
htmlType
|
|
||||||
icon={Antd_Utils.tts(Antd_Icon.iconToJsSafe(~icon, ()))}
|
|
||||||
shape
|
|
||||||
size
|
|
||||||
target
|
|
||||||
onClick
|
|
||||||
block
|
|
||||||
loading
|
|
||||||
className
|
|
||||||
id>
|
|
||||||
children
|
|
||||||
</AntButton>,
|
|
||||||
~props={"data-testid": testId},
|
|
||||||
[],
|
|
||||||
)
|
|
19
packages/playground/tsconfig.json
Normal file
19
packages/playground/tsconfig.json
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "commonjs",
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"jsxImportSource": "@emotion/react",
|
||||||
|
"noImplicitAny": false,
|
||||||
|
"removeComments": true,
|
||||||
|
"preserveConstEnums": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"outDir": "./dist",
|
||||||
|
"declarationDir": "./dist",
|
||||||
|
"declaration": true,
|
||||||
|
"sourceMap": true
|
||||||
|
},
|
||||||
|
"target": "ES6",
|
||||||
|
"include": ["src/**/*"],
|
||||||
|
"exclude": ["node_modules", "**/*.spec.ts"]
|
||||||
|
}
|
1
packages/squiggle-lang/.gitignore
vendored
1
packages/squiggle-lang/.gitignore
vendored
|
@ -15,3 +15,4 @@ yarn-error.log
|
||||||
.idea
|
.idea
|
||||||
*.gen.ts
|
*.gen.ts
|
||||||
*.gen.js
|
*.gen.js
|
||||||
|
dist
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
"name": "@squiggle/lang",
|
"name": "@squiggle/lang",
|
||||||
"version": "0.1.9",
|
"version": "0.1.9",
|
||||||
"homepage": "https://foretold-app.github.io/estiband/",
|
"homepage": "https://foretold-app.github.io/estiband/",
|
||||||
"private": false,
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "rescript build -with-deps",
|
"build": "rescript build -with-deps",
|
||||||
"parcel": "parcel build ./src/js/index.js --no-source-maps --no-autoinstall",
|
"parcel": "parcel build ./src/js/index.js --no-source-maps --no-autoinstall",
|
||||||
|
@ -12,7 +11,8 @@
|
||||||
"test:ci": "yarn jest ./__tests__/Lodash__test.re",
|
"test:ci": "yarn jest ./__tests__/Lodash__test.re",
|
||||||
"watch:test": "jest --watchAll",
|
"watch:test": "jest --watchAll",
|
||||||
"watch:s": "yarn jest -- Converter_test --watch",
|
"watch:s": "yarn jest -- Converter_test --watch",
|
||||||
"package": "tsc"
|
"package": "tsc",
|
||||||
|
"ci": "yarn build && yarn package"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"Rescript"
|
"Rescript"
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user