Removed react dependencies

This commit is contained in:
Ozzie Gooen 2022-01-29 15:35:12 -05:00
parent aa67cb955b
commit 1d268d474c
45 changed files with 42 additions and 75859 deletions

View File

@ -1,18 +1,12 @@
{
"name": "probExample",
"reason": {
"react-jsx": 3
},
"sources": [
{
"dir": "src",
"subdirs": true
},
{
"dir": "showcase",
"type": "dev",
"subdirs": true
},
{
"dir": "__tests__",
"type": "dev",
@ -35,19 +29,13 @@
"bs-dependencies": [
"@glennsl/bs-jest",
"@glennsl/bs-json",
"@rescriptbr/reform",
"@rescript/react",
"bs-css",
"bs-css-dom",
"rationale",
"bs-moment",
"reschema"
"bs-moment"
],
"refmt": 3,
"warnings": {
"number": "+A-42-48-9-30-4-102"
},
"ppx-flags": [
"lenses-ppx/ppx"
]
}

View File

@ -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).

View File

@ -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: 'foretold-app/squiggle',
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>

View File

@ -1,5 +0,0 @@
{
"devDependencies": {
"docsify-cli": "^4.4.3"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +0,0 @@
[[redirects]]
from = "/*"
to = "/index.html"
status = 200

View File

@ -27,44 +27,21 @@
"license": "MIT",
"dependencies": {
"@glennsl/bs-json": "^5.0.2",
"@rescript/react": "^0.10.3",
"@rescriptbr/reform": "^11.0.1",
"ace-builds": "^1.4.12",
"antd": "^4.18.5",
"autoprefixer": "9.8.8",
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
"binary-search-tree": "0.2.6",
"bs-ant-design-alt": "2.0.0-alpha.33",
"bs-css": "^15.1.0",
"bs-css-dom": "^3.1.0",
"bs-moment": "0.6.0",
"bs-reform": "^10.0.3",
"bsb-js": "1.1.7",
"d3": "7.3.0",
"gh-pages": "2.2.0",
"jest": "^25.5.1",
"jstat": "1.9.2",
"lenses-ppx": "5.1.0",
"less": "3.10.3",
"lodash": "4.17.15",
"mathjs": "5.10.3",
"moduleserve": "0.9.1",
"moment": "2.24.0",
"pdfast": "^0.2.0",
"postcss-cli": "7.1.0",
"rationale": "0.2.0",
"react": "^16.10.0",
"react-ace": "^9.2.0",
"react-dom": "^0.13.0 || ^0.14.0 || ^15.0.1 || ^16.0.0",
"react-use": "^17.3.2",
"react-vega": "^7.4.4",
"reason-react": ">=0.7.0",
"reschema": "^2.2.0",
"rescript": "^9.1.4",
"tailwindcss": "1.2.0",
"vega": "*",
"vega-embed": "6.6.0",
"vega-lite": "*"
"rescript": "^9.1.4"
},
"devDependencies": {
"@glennsl/bs-jest": "^0.5.1",

View File

@ -1 +0,0 @@
let entries = [];

View File

@ -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});
};

View File

@ -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 style=Styles.folderNav>
<h4 onClick={_e => changeId(f.id)}> {f.title->React.string} </h4>
<div style=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 style=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 style=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 style=Styles.pageContainer>
<div style=Styles.leftNav> {buildNav(setRoute)} </div>
<div style=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 style=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>
}
}

View File

@ -1,5 +0,0 @@
switch(ReactDOM.querySelector("main")){
| Some(root) => ReactDOM.render(<div> <Lib.Index /> </div>, root)
| None => () // do nothing
}
RescriptReactRouter.push("")

View File

@ -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>

View File

@ -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

View File

@ -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: '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=?,
unit
) =>
props =
""
@module("antd")
external make : makeType = "Button"

View File

@ -1,32 +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"

View File

@ -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")
external make : makeType = "Form.Item"
}

View File

@ -1,58 +0,0 @@
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"
}

View File

@ -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"

View File

@ -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"

View File

@ -1,78 +0,0 @@
type route =
| DistBuilder
| Home
| NotFound
let routeToPath = route =>
switch route {
| DistBuilder => "/dist-builder"
| Home => "/"
| _ => "/"
}
module Menu = {
module Styles = {
open CssJs
let menu = style(. [ position(#relative),
marginTop(em(0.25)),
marginBottom(em(0.25)),
selector(.
"a",
[ borderRadius(em(0.25)),
display(#inlineBlock),
backgroundColor(#hex("eee")),
padding(em(1.)),
cursor(#pointer),
],
),
selector(. "a:hover", [ backgroundColor(#hex("bfcad4")) ]),
selector(. "a:hover", [ backgroundColor(#hex("bfcad4")) ]),
selector(.
"a:not(:firstChild):not(:lastChild)",
[ marginRight(em(0.25)), marginLeft(em(0.25)) ],
),
])
}
module Item = {
@react.component
let make = (~href, ~children) =>
<a
href
onClick={e => {
e->ReactEvent.Synthetic.preventDefault
RescriptReactRouter.push(href)
}}>
children
</a>
}
@react.component
let make = () =>
<div style=Styles.menu>
<Item href={routeToPath(Home)} key="home"> {"Home" |> R.ste} </Item>
<Item href={routeToPath(DistBuilder)} key="dist-builder"> {"Dist Builder" |> R.ste} </Item>
</div>
}
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{"dist-builder"} => DistBuilder
| list{} => Home
| _ => NotFound
}
<>
<Menu />
{switch routing {
| DistBuilder => <DistBuilder />
| Home => <Home />
| _ => fixedLength("Page is not found" |> R.ste)
}}
</>
}

View File

@ -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};

View File

@ -1,5 +0,0 @@
%raw(`import('./styles/index.css')`)
switch ReactDOM.querySelector("#app") {
| Some(root) => ReactDOM.render(<App />, root)
| None => ()
}

View File

@ -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)
}

View File

@ -1,36 +0,0 @@
import React from "react";
import AceEditor from "react-ace";
import "ace-builds/src-noconflict/mode-golang";
import "ace-builds/src-noconflict/theme-github";
import "ace-builds/src-noconflict/ext-language_tools";
import "ace-builds/src-noconflict/keybinding-vim";
function onChange(newValue) {
console.log("change", newValue);
}
export function CodeEditor(props) {
return (
<AceEditor
value={props.value}
mode="golang"
height="400px"
width="100%"
theme="github"
showGutter={false}
highlightActiveLine={false}
showPrintMargin={false}
onChange={props.onChange}
name="UNIQUE_ID_OF_DIV"
editorProps={{
$blockScrolling: true,
}}
setOptions={{
enableBasicAutocompletion: false,
enableLiveAutocompletion: true,
enableSnippets: true,
}}
/>
);
}

View File

@ -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"

View File

@ -1,271 +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.Input
value
onChange={ReForm.Helpers.handleChange(handleChange)}
onBlur={_ => validate()}
style={className}
/>
}
/>
}
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 = ProgramEvaluator.Inputs.make(
~samplingInputs={
sampleCount: Some(options.sampleCount),
outputXYPoints: Some(options.outputXYPoints),
kernelWidth: options.kernelWidth,
shapeLength: 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 = ProgramEvaluator.evaluateProgram(inputs1)
let renderExpression = response1 =>
switch response1 {
| #DistPlus(distPlus1) => <DistPlusPlot distPlus={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: 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 =>
ProgramEvaluator.evaluateFunction(
foo,
(f, a),
[#SymbolicDist(#Float(r))],
) |> E.R.bind(_, a =>
switch a {
| #DistPlus(d) => Ok((r, 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}
extra={<Antd.Button icon=Antd.IconName.reload shape=#circle onClick=onReload />}>
<Form.Provider value=reform>
<Antd.Form onSubmit>
<Row _type="flex" style=Styles.rows>
<Col span=24> <FieldText field=FormConfig.SquiggleString label="Program" /> </Col>
</Row>
<Row _type="flex" style=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>
}

View File

@ -1,306 +0,0 @@
open DistPlusPlotReducer
let plotBlue = #hex("1860ad")
let showAsForm = (distPlus: DistTypes.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
|> DistPlus.T.xToY(x)
|> DistTypes.MixedPoint.toDiscreteValue
|> Js.Float.toPrecisionWithPrecision(_, ~digits=7)
|> React.string}
</td>
<td className="px-4 py-2 border ">
{distPlus
|> DistPlus.T.xToY(x)
|> DistTypes.MixedPoint.toContinuousValue
|> Js.Float.toPrecisionWithPrecision(_, ~digits=7)
|> React.string}
</td>
<td className="px-4 py-2 border ">
{distPlus
|> DistPlus.T.Integral.xToY(x)
|> E.Float.with2DigitsPrecision
|> React.string}
</td>
<td className="px-4 py-2 border ">
{distPlus
|> 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
|> DistPlus.T.toContinuous
|> E.O.fmap(Continuous.T.Integral.sum)
|> E.O.fmap(E.Float.with2DigitsPrecision)
|> E.O.default("")
|> React.string}
</td>
<td className="px-4 py-2 border ">
{distPlus
|> DistPlus.T.toDiscrete
|> E.O.fmap(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 |> DistPlus.T.Integral.yToX(0.01) |> showFloat}
</td>
<td className="px-4 py-2 border">
{distPlus |> DistPlus.T.Integral.yToX(0.05) |> showFloat}
</td>
<td className="px-4 py-2 border">
{distPlus |> DistPlus.T.Integral.yToX(0.25) |> showFloat}
</td>
<td className="px-4 py-2 border">
{distPlus |> DistPlus.T.Integral.yToX(0.5) |> showFloat}
</td>
<td className="px-4 py-2 border">
{distPlus |> DistPlus.T.Integral.yToX(0.75) |> showFloat}
</td>
<td className="px-4 py-2 border">
{distPlus |> DistPlus.T.Integral.yToX(0.95) |> showFloat}
</td>
<td className="px-4 py-2 border">
{distPlus |> DistPlus.T.Integral.yToX(0.99) |> showFloat}
</td>
<td className="px-4 py-2 border">
{distPlus |> 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 |> DistPlus.T.mean |> showFloat} </td>
<td className="px-4 py-2 border">
{distPlus |> DistPlus.T.variance |> (r => r ** 0.5) |> showFloat}
</td>
<td className="px-4 py-2 border"> {distPlus |> 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: DistTypes.distPlus, ~config: chartConfig, ~onHover) => {
open DistPlus
let discrete = distPlus |> T.toDiscrete |> E.O.fmap(Discrete.getShape)
let continuous = distPlus |> T.toContinuous |> E.O.fmap(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 |> DistPlus.T.Integral.yToX(0.00001)
let maxX = distPlus |> DistPlus.T.Integral.yToX(0.99999)
let timeScale = distPlus.unit |> DistTypes.DistributionUnit.toJson
let discreteProbabilityMassFraction = distPlus |> 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: DistTypes.distPlus, ~config: chartConfig, ~onHover) => {
let integral = distPlus.integralCache
let continuous = integral |> Continuous.toLinear |> E.O.fmap(Continuous.getShape)
let minX = distPlus |> DistPlus.T.Integral.yToX(0.00001)
let maxX = distPlus |> DistPlus.T.Integral.yToX(0.99999)
let timeScale = distPlus.unit |> DistTypes.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: DistTypes.distPlus, ~config: chartConfig, ~onHover) => {
let chart = React.useMemo2(
() =>
config.isCumulative
? <IntegralChart distPlus config onHover />
: <DistPlusChart distPlus config onHover />,
(distPlus, config),
)
<div
style={
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: DistTypes.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>
}

View File

@ -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},
],
};

View File

@ -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 style={Styles.graph(color)}>
<RawPlot
?maxX
?minX
?yMaxDiscreteDomainFactor
?yMaxContinuousDomainFactor
?xScale
?yScale
?timeScale
discrete={discrete |> E.O.fmap(XYShape.T.toJs)}
height
marginBottom=50
marginTop=0
onHover
continuous={continuous |> E.O.fmap(XYShape.T.toJs)}
showDistributionLines
showDistributionYAxis
showVerticalLine
/>
</div>

View File

@ -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 };

View File

@ -1,54 +0,0 @@
@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, DistTypes.distPlus)>, ~children=React.null) => {
let data = dists |> E.A.fmap(((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>
}

View File

@ -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);
};

View File

@ -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;

View File

@ -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" }
}
}
}
]
}

View File

@ -1,10 +0,0 @@
.lollipops-line-mouseover {
stroke-dasharray: 4;
animation: dash 2s linear infinite;
}
@keyframes dash {
to {
stroke-dashoffset: 1000;
}
}

View File

@ -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) |> E.O.React.fmapOrNull(React.string)}
{JS.powerGet(numberWithPresentation) |> E.O.React.fmapOrNull(e =>
<span>
{j`\\u00b710` |> React.string}
<span style=sup> {e |> E.Float.toString |> React.string} </span>
</span>
)}
</span>
}

View File

@ -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();
}

View File

@ -85,11 +85,6 @@ module O = {
let min = compare(\"<")
let max = compare(\">")
module React = {
let defaultNull = default(React.null)
let fmapOrNull = fn => \"||>"(fmap(fn), default(React.null))
let flatten = default(React.null)
}
}
/* Functions */

View File

@ -1,16 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Squiggle Language</title>
<link href="https://fonts.googleapis.com/css?family=Lato:300,400,700,900" rel="stylesheet">
<link href="./styles/index.css" rel="stylesheet">
<script src="./Index.bs.js" defer></script>
</head>
<body>
<div id="app" style="height: 100%"></div>
</body>
</html>

View File

@ -1,19 +0,0 @@
module Styles = {
open CssJs
let h3 = style(. [ fontSize(#em(1.5)), marginBottom(#em(1.5)) ])
let card = style(. [ marginTop(#em(2.)), marginBottom(#em(2.)) ])
}
module Table = {
module TableStyles = {
open CssJs
let row = style(. [ display(#flex), height(#em(4.)) ])
let col = (~f=1.0, ()) => style(. [ flex(#num(f)) ])
}
@react.component
let make = () => <> </>
}
@react.component
let make = () => <div> <div style=Styles.card> <Table /> </div> </div>

View File

@ -1,5 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

File diff suppressed because it is too large Load Diff

View File

@ -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: [],
}

View File

@ -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},
[],
)

3251
yarn.lock

File diff suppressed because it is too large Load Diff