diff --git a/.github/ISSUE_TEMPLATE/documentation_issue.md b/.github/ISSUE_TEMPLATE/documentation_issue.md index f371b6270..95cb9bae2 100644 --- a/.github/ISSUE_TEMPLATE/documentation_issue.md +++ b/.github/ISSUE_TEMPLATE/documentation_issue.md @@ -1,9 +1,7 @@ --- name: 🚨 Documentation issue about: Create an issue to help us improve the rescript-lang.org documentation website -title: '' -labels: '' -assignees: '' - +title: "" +labels: "" +assignees: "" --- - diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 58df60cb2..ecd03a074 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -12,6 +12,7 @@ jobs: - run: npm ci - run: npx rescript - run: npm test + - run: npm run ci:format - name: Format check run: npx rescript format -check -all diff --git a/.gitignore b/.gitignore index 79ff8c108..31b182d6e 100644 --- a/.gitignore +++ b/.gitignore @@ -22,7 +22,6 @@ _tempFile.cmt .bsb.lock .merlin lib/ -.vscode/ .vercel diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..564d6bf5a --- /dev/null +++ b/.prettierrc @@ -0,0 +1,2 @@ +plugins: + - "@prettier/plugin-oxc" diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 000000000..241f2c935 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["esbenp.prettier-vscode", "chenglou92.rescript-vscode"] +} diff --git a/CHANGELOG.md b/CHANGELOG.md index b84fef4c6..a46ed2ce6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,5 @@ # Changelog - This changelog documents significant changes that caused a new version in the manual, or other related resources. We don't create a version fork for every minor release, and try to make docs "append only" as much as possible. Usually when we introduce a new feature we add a `since 9.0` annotation to a specific section, and be done with it. @@ -13,8 +12,7 @@ Here are the notes on major changes we did, and how the version corresponds to s ### latest -- 9.1 related - - +- ## 9.1 related ### v9.0 (v8.3 - v9.0) @@ -34,5 +32,3 @@ Here are the notes on major changes we did, and how the version corresponds to s ### v8.0.0 (v6 - v8.3) - Docs with Reason / OCaml syntax before the new syntax - - diff --git a/README.md b/README.md index 90d521539..7837c53ad 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # rescript-lang.org + [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-v1.4%20adopted-ff69b4.svg)](CODE_OF_CONDUCT.md) This is the official documentation platform for the [ReScript](https://rescript-lang.org) programming language. diff --git a/_blogposts/2020-08-10-bucklescript-is-rebranding.mdx b/_blogposts/2020-08-10-bucklescript-is-rebranding.mdx index 168c3abf5..fb0d54ca7 100644 --- a/_blogposts/2020-08-10-bucklescript-is-rebranding.mdx +++ b/_blogposts/2020-08-10-bucklescript-is-rebranding.mdx @@ -21,6 +21,7 @@ We're pleased to announce that BuckleScript is getting a brand new name: **ReScr ## Community Situation BuckleScript started with the idea that **JavaScript programmers deserved a great typed language with a fast and lean toolchain**. This idea took root and, over the years, we've gradually accomplished feats such as: + - a state of the art compiled JavaScript output that rivals hand-written JS, - a fast & reliable toolchain much needed in front-end and Node development, - various JS interop features that spawned an ecosystem of well typed libraries, @@ -28,6 +29,7 @@ BuckleScript started with the idea that **JavaScript programmers deserved a grea - [and recently](/blog/bucklescript-8-1-new-syntax), a fresh syntax made by a major contributor of Reason's old syntax. These developments have attracted many people into our community. But one bigger challenge persisted: newcomers dropped out at the sheer amount of extra incongruent tools and learning overhead from having to understand OCaml concepts, Reason concepts, and BuckleScript's concepts. Take, for example, what's required to make a React app using BuckleScript: + - Knowledge of React. - Knowledge of JS. - Knowledge of BuckleScript's specific bindings to React (that we've tried hard to keep to a minimum). @@ -43,6 +45,7 @@ The adoption barrier is real, and it's about time we finally solve it. ## The Rebranding Today, we'll start to truly unify the various BuckleScript-related projects under the ReScript umbrella. This includes: + - The compiler, build system and the new syntax unified under a single installation. - Doubling down on editor tooling for ReScript usage. - A single documentation site (this one), which unifies all the docs and greatly trims down on redundant and stale info. diff --git a/_blogposts/2020-08-28-new-rescript-logo.mdx b/_blogposts/2020-08-28-new-rescript-logo.mdx index 0d40e3903..1e4c275fb 100644 --- a/_blogposts/2020-08-28-new-rescript-logo.mdx +++ b/_blogposts/2020-08-28-new-rescript-logo.mdx @@ -15,11 +15,14 @@ ReScript is the evolution and fusion of Reason and BuckleScript. As we're a desi Here it is! - - - + The old Reason and BuckleScript logo had many limitations: + - The icons didn't really work well on round Social Media profile images (or round shapes at all). - There's no guideline on how the logo works inverted, or on colored background. - The large red rectangle makes it difficult to balance the logo with other elements. @@ -27,15 +30,21 @@ The old Reason and BuckleScript logo had many limitations: The new logo addresses all these and more: - + ## Creating Meaning Through Simple Shapes A minimal logo design is achieved by putting aside all distractions while focusing on legibility, meaning and small details like clear lines, interesting perspective and depth. - - - + **The letter "r"**, composed of two shapes, is inspired by Albers, a german-born American Bauhaus artist and typographer. An object should be simple, beautiful, functional and accessible for everyone - a statement which applies to ReScript's principles perfectly. @@ -43,7 +52,7 @@ A minimal logo design is achieved by putting aside all distractions while focusi **The red app-shaped background** references the vibrant, playful applications our developers are empowered to create with ReScript. -**The Logotype** ("rescript") complements the brand mark with its clean look and its embrace of technology while retaining a functional look. +**The Logotype** ("rescript") complements the brand mark with its clean look and its embrace of technology while retaining a functional look. We'd like to position ReScript to be a community of product-first developers who care about the fit & finish of their work, while keeping an eye on the quality of their engineering. This interplay of design and engineering is a hard-to-achieve but beautifully worthwhile sweet spot that's frequently been missing in the programmer community; our vibrant logo is our renewed symbolic step toward this mission. Come along with us on our journey! diff --git a/_blogposts/2020-09-25-release-8-3-2.mdx b/_blogposts/2020-09-25-release-8-3-2.mdx index a0ba49a92..2ad89accb 100644 --- a/_blogposts/2020-09-25-release-8-3-2.mdx +++ b/_blogposts/2020-09-25-release-8-3-2.mdx @@ -74,7 +74,7 @@ To get the build output, instead of communicating through IPC, we adopted a simp This makes the editor integration build-system agnostic, it does not need talk to the build system directly. It also makes our build tool work with other watchers including Facebook's [watchman](https://facebook.github.io/watchman/). -Watchman is a more scalable watcher tool for some specific platforms and less memory hungry, however, we still need a watchman-client to get the output of triggered job. +Watchman is a more scalable watcher tool for some specific platforms and less memory hungry, however, we still need a watchman-client to get the output of triggered job. We write the output to `.compiler.log` per each build, allowing clients to read compiler diagnostics when they want. ## A better algorithm for removing stale outputs @@ -90,8 +90,8 @@ We scan `lib/bs` directory and check some dangling `cm{i,t,j,ti}` files, if it d the current build set, it is considered stale artifacts. If it is `cmt` file, it would trigger some hooks of `genType`, notably -cmt-rm. - Based on previous build logs -We store previous compilation stats. If a file is in the previous compiler output, but no longer in the output of the new build, it is considered stale and can be removed. -it is considered stale output which can be removed. + We store previous compilation stats. If a file is in the previous compiler output, but no longer in the output of the new build, it is considered stale and can be removed. + it is considered stale output which can be removed. In general, strategy two is more reliable and efficient. @@ -100,11 +100,9 @@ In general, strategy two is more reliable and efficient. However, strategy one is easier for tooling like `genType`. Not every tool has knowledge of the build system. - Sometimes a combination of both strategies is needed. -- When removing .cm* files, we use the first strategy. -- When removing generated javascript, we use strategy two, - +- When removing .cm\* files, we use the first strategy. +- When removing generated javascript, we use strategy two, Happy Hacking! diff --git a/_blogposts/2020-09-25-release-8-3.mdx b/_blogposts/2020-09-25-release-8-3.mdx index 5975e6678..71874227f 100644 --- a/_blogposts/2020-09-25-release-8-3.mdx +++ b/_blogposts/2020-09-25-release-8-3.mdx @@ -17,9 +17,7 @@ It's focused on type safety, performance and JS interop. It used to be called Bu npm i bs-platform@8.3.0 ``` -The changes are listed [here](https://github.com/rescript-lang/rescript/blob/master/Changes.md#83), this is a large release, and we will go through some highlighted changes. - - +The changes are listed [here](https://github.com/rescript-lang/rescript/blob/master/Changes.md#83), this is a large release, and we will go through some highlighted changes. ## Lightweight FFI attributes without `bs.` prefix @@ -27,18 +25,19 @@ In this release, we make the `bs.` prefix optional, this will make the FFI less For example, the old externals for `readFileAsUtf8Sync` used to be written like this - ```res @bs.val @bs.module("fs") external readFileAsUtf8Sync: (string, @bs.as("utf8") _) => string = "readFileSync" ``` + ```reason [@bs.val] [@bs.module "fs"] external readFileAsUtf8Sync: (string, [@bs.as "utf8"] _) => string = "readFileSync"; ``` + ```ocaml external readFileAsUtf8Sync : string -> (_[@bs.as "utf8"]) -> string = "readFileSync" [@@bs.val] [@@bs.module "fs"] ``` @@ -52,11 +51,13 @@ It can now be simplified as ```res @val @module("fs") external readFileAsUtf8Sync: (string, @as("utf8") _) => string = "readFileSync" ``` + ```reason [@val] [@module "fs"] external readFileAsUtf8Sync: (string, [@as "utf8"] _) => string = "readFileSync"; ``` + ```ocaml external readFileAsUtf8Sync : string -> (_[@as "utf8"]) -> string = "readFileSync" [@@val] [@@module "fs"] @@ -70,8 +71,7 @@ with the exception of the following two that don't have abbreviations: - `bs.send.pipe` : this attribute was deprecated in favor of `bs.send`; you can still use the existing one for backward compatibility. - `bs.splice` : this attribute was deprecated in favor of `bs.variadic`; you can still use the existing one for -backward compatibility. - + backward compatibility. ## default import in Es6 support @@ -84,11 +84,13 @@ If you use es6 module output, the default bindings will be compiled properly now let a = input("hello") ``` + ```reason [@module "hello"] external input: string => string = "default"; let a = input("hello"); ``` + ```ocaml external input : string -> string = "default" [@@module "hello"] @@ -104,7 +106,6 @@ import Hello from "hello"; var a = Hello("hello"); ``` - ## Customized js file extension support Now user can pick up their js file extension support per module format: @@ -126,8 +127,6 @@ To have better integration with other [JS infrastructures](https://github.com/re for example, Next.js/React Native, we allow file names like `404.res`, `Button.Android.res` so that it can just be picked up by those tools - - ## Better type based inference for pattern `let {a,b,c} = value` Previously, for code like this: @@ -144,6 +143,7 @@ let f = (u: N.t) => { x + 1 } /* type error */ ``` + ```reason module N = { type t = {x: int}; @@ -154,6 +154,7 @@ let f = (u: N.t) => { x + 1; }; /* type error */ ``` + ```ocaml module N = struct type t = { diff --git a/_blogposts/2020-11-26-editor-support-release-1-0.mdx b/_blogposts/2020-11-26-editor-support-release-1-0.mdx index 090f101b6..08ae79ed0 100644 --- a/_blogposts/2020-11-26-editor-support-release-1-0.mdx +++ b/_blogposts/2020-11-26-editor-support-release-1-0.mdx @@ -9,12 +9,12 @@ description: | Type hints, jump to definition, error diagnostics, and more. --- - ## Editor Integration Has Finally Landed Thank you so much for the wait! **Here are all the features:** + - Highlighting - Formatting - Diagnostics @@ -32,4 +32,8 @@ We'll keep on iterating on the polish of the plugins, and release better [Sublim Happy thanksgiving! - + diff --git a/_blogposts/2021-02-09-release-9-0.mdx b/_blogposts/2021-02-09-release-9-0.mdx index 0ae1f049c..1238d0788 100644 --- a/_blogposts/2021-02-09-release-9-0.mdx +++ b/_blogposts/2021-02-09-release-9-0.mdx @@ -34,7 +34,6 @@ Our compiler comes with a set of stdlib modules (such as `Belt`, `Pervasives`, e In previous versions, users couldn't ship their compiled JS code without defining a `package.json` dependency on `bs-platform`. Whenever a ReScript developer wanted to publish a package just for pure JS consumption / lean container deployment, they were required to use a bundler to bundle up their library / stdlib code, which made things way more complex and harder to understand. - To fix this problem, we introduced an `external-stdlib` configuration that allows specifying a pre-compiled stdlib npm package (`@rescript/std`). More details on how to use that feature can be found in our [External Stdlib](/docs/manual/latest/build-external-stdlib) documentation. ### Less Bundle Bloat when Adding ReScript @@ -67,8 +66,8 @@ The snippet above will compile to the following JS output: ```js -function test(x){ - return x === 0 +function test(x) { + return x === 0; } ``` @@ -82,7 +81,6 @@ function test(x) { } ``` - As you can see, the 9.0 compiler removes all the unnecessary `typeof` checks! @@ -153,7 +151,6 @@ type animation = [ #\"ease-in" | #\"ease-out" ] We introduced this change to allow easier interop with existing JS string enums. In pure ReScript code, we'd still recommend our users to stick with valid identifier names instead (e.g. `easeIn` instead of `ease-in`). - ## Breaking Changes This release comes with a minor breaking change that shouldn't have much impact on the upgrade of existing codebases. @@ -209,5 +206,4 @@ For example, we are tinkering with the idea on using WASM to replace Camlp4, and We will discuss these topics in a separate development post, but we are already excited about the new possibilities this will bring within the compiler toolchain. - Happy Hacking! diff --git a/_blogposts/2021-05-07-release-9-1.mdx b/_blogposts/2021-05-07-release-9-1.mdx index 75f021180..56b4e8b15 100644 --- a/_blogposts/2021-05-07-release-9-1.mdx +++ b/_blogposts/2021-05-07-release-9-1.mdx @@ -41,6 +41,7 @@ The default `rescript` is equivalent to `rescript build` subcommand ``` Here's a table of translation, if you're upgrading your script that is currently using `bsc` and `bsb`: + - `bsc -format myFile.res`: `rescript format myFile.res` - `bsb`: `rescript build` \* - `bsb -make-world`: `rescript build -with-deps` \* @@ -53,7 +54,8 @@ This means that you can ditch your old `-make-world` (now the explicit `-with-de ### Polymorphic Variants for Numbers and Strings -*Drumrolls* +_Drumrolls_ + - Poly variants like `#1`, `#42` compile to JavaScript numbers. - Poly variants like `#hello`, `#world` compile to JavaScript Strings. diff --git a/_blogposts/2021-06-25-roadmap-2021-and-new-landing-page.mdx b/_blogposts/2021-06-25-roadmap-2021-and-new-landing-page.mdx index a1da83db4..013f411a5 100644 --- a/_blogposts/2021-06-25-roadmap-2021-and-new-landing-page.mdx +++ b/_blogposts/2021-06-25-roadmap-2021-and-new-landing-page.mdx @@ -7,7 +7,7 @@ description: | Announcing our roadmap for 2021 / 2022, release cycle plans and new landing page. --- -import Image from "src/components/Image.mjs" +import Image from "src/components/Image.mjs"; ## Team Update diff --git a/_blogposts/2022-08-25-release-10-0-0.mdx b/_blogposts/2022-08-25-release-10-0-0.mdx index b66493af2..9413fa21d 100644 --- a/_blogposts/2022-08-25-release-10-0-0.mdx +++ b/_blogposts/2022-08-25-release-10-0-0.mdx @@ -17,15 +17,19 @@ npm install rescript@10 All changes are listed [here](https://github.com/rescript-lang/rescript/blob/10.0_release/CHANGELOG.md). Let's take a tour of a few of the features we're extra excited about. ## Faster builds with native M1 support + Users with M1 chips should see a notable speedup, as the new ReScript version has full native support for M1. ## Better ergonomics with Unicode support in regular strings + You can now use Unicode characters directly in regular strings. This will now produce what you'd expect: + ```res let str = "Σ" ``` You can also pattern match on Unicode characters: + ```res switch someCharacter { | 'Σ' => "what a fine Unicode char" @@ -34,7 +38,9 @@ switch someCharacter { ``` ## Experimental optional record fields + Previously, a record would always have to define all its optional fields: + ```res type user = { name: string, @@ -51,6 +57,7 @@ let userWithAge = { age: Some(34), } ``` + For small records like the one above, this is typically fine. But for records with many fields, the friction of having to always set all optional fields explicitly adds up. This release has a new experimental feature called optional record fields, allowing you to rewrite the above to this instead: ```res diff --git a/_blogposts/2023-02-02-release-10-1.mdx b/_blogposts/2023-02-02-release-10-1.mdx index cce653a2e..18628c6b4 100644 --- a/_blogposts/2023-02-02-release-10-1.mdx +++ b/_blogposts/2023-02-02-release-10-1.mdx @@ -70,11 +70,10 @@ Way easier on the eyes, don't you think? Note that the new `promise` type is ful Additionally, we also introduced the `Js.Promise2` module as a stepping stone to migrate `Js.Promise` based code to a first-pipe (->) friendly solution. For the daily practise you'll almost always want to use `async` / `await` to handle promises. -(*Sidenote*: We are also well aware that our users want a solution to unify `Belt`, `Js` and `Js.xxx2` and have a fully featured "standard library" instead of adding more `Js.xxx2` modules. Good news is that we have a solution in the pipeline to fix this. `Js.Promise2` was introduced to ease the process later on and is not supposed to be the panacea of promise handling.) +(_Sidenote_: We are also well aware that our users want a solution to unify `Belt`, `Js` and `Js.xxx2` and have a fully featured "standard library" instead of adding more `Js.xxx2` modules. Good news is that we have a solution in the pipeline to fix this. `Js.Promise2` was introduced to ease the process later on and is not supposed to be the panacea of promise handling.) If you are already using a third-party promise library like [ryyppy/rescript-promise](https://github.com/ryyppy/rescript-promise) or similar, there's no need to migrate any existing code. Introduce `async` / `await` gradually in your codebase as you go. - ## New JSX v4 syntax ReScript 10.1 now ships with JSX v4. Here's what's new: @@ -83,7 +82,7 @@ ReScript 10.1 now ships with JSX v4. Here's what's new: - **Two new transformation modes**. JSX v4 comes with a `classic` mode (= `React.createElement`) and `automatic` mode (= `jsx-runtime` calls). The latter is the new default, moving forward with `rescript/react@0.11` and `React@18`. - **Allow mixing JSX configurations on the project and module level.** Gradually mix and match JSX transformations and modes without migrating any old code! - **Pass `prop` types** to `@react.component`. You can now fine tune `@react.component` with your specific prop type needs. Very useful for libraries and frameworks to define component interfaces. -- **Less boilerplate when using `React.Context`**. Check out our [example](/docs/react/latest/migrate-react#reactcontext) for comparison. +- **Less boilerplate when using `React.Context`**. Check out our [example](/docs/react/latest/migrate-react#reactcontext) for comparison. - **Revisited props spread operator.** This will allow users to spread records in JSX without sacrificing their sanity. Note that this implementation has harder constraints than its JS counterpart. (requires `rescript/react@0.11` or higher) - **Better type inference of props.** Type inference when passing e.g. variants that are defined in the same module as the component is much improved. With the earlier JSX version, you'd often need to write code like this in order for the compiler to understand which variant you're passing: ` ``` + ```js use client' // Generated by ReScript, PLEASE EDIT WITH CARE diff --git a/pages/docs/react/v0.10.0/arrays-and-keys.mdx b/pages/docs/react/v0.10.0/arrays-and-keys.mdx index 56be3f290..7543924ac 100644 --- a/pages/docs/react/v0.10.0/arrays-and-keys.mdx +++ b/pages/docs/react/v0.10.0/arrays-and-keys.mdx @@ -77,7 +77,7 @@ module Blog = {

{React.string(post.content)}

}); - +
{sidebar}
@@ -94,7 +94,6 @@ let posts = [ let blog = ``` - ## Rendering `list` Values In case you ever want to render a `list` of items, you can do something like this: @@ -124,4 +123,3 @@ let make = () => { We use `Belt.List.toArray` to convert our list to an array before creating our `array`. Please note that using `list` has performance impact due to extra conversion costs. 99% of the time you'll want to use arrays (seamless interop, faster JS code), but in some cases it might make sense to use a `list` to leverage advanced pattern matching features etc. - diff --git a/pages/docs/react/v0.10.0/beyond-jsx.mdx b/pages/docs/react/v0.10.0/beyond-jsx.mdx index b12aeba0b..0a3070669 100644 --- a/pages/docs/react/v0.10.0/beyond-jsx.mdx +++ b/pages/docs/react/v0.10.0/beyond-jsx.mdx @@ -14,11 +14,11 @@ JSX is a syntax sugar that allows us to use React components in an HTML like man **Note:** This section requires knowledge about the low level apis for [creating elements](./elements-and-jsx#creating-elements-from-component-functions), such as `React.createElement` or `ReactDOMRe.createDOMElementVariadic`. -> **Note:** This page assumes your `bsconfig.json` to be set to `"reason": { "react-jsx": 3 }` to apply the right JSX transformations. +> **Note:** This page assumes your `bsconfig.json` to be set to `"reason": { "react-jsx": 3 }` to apply the right JSX transformations. ## Component Types -A plain React component is defined as a `('props) => React.element` function. You can also express a component more efficiently with our shorthand type `React.component<'props>`. +A plain React component is defined as a `('props) => React.element` function. You can also express a component more efficiently with our shorthand type `React.component<'props>`. Here are some examples on how to define your own component types (often useful when interoping with existing JS code, or passing around components): @@ -35,6 +35,7 @@ type containerComp = "children": React.element }>; ``` + The types above are pretty low level (basically the JS representation of a React component), but since ReScript React has its own ways of defining React components in a more language specific way, let's have a closer look on the anatomy of such a construct. ## JSX Component Interface @@ -54,6 +55,7 @@ module Friend = { } } ``` + ```res module Friend = { @obj @@ -82,7 +84,6 @@ In the expanded output: The `@react.component` decorator also works for `React.forwardRef` calls: - ```res @@ -129,16 +130,18 @@ So now that we know how the ReScript React component transformation works, let's ## JSX Under the Hood -Whenever we are using JSX with a custom component ("capitalized JSX"), we are actually using `React.createElement` to create a new element. Here is an example of a React component without children: +Whenever we are using JSX with a custom component ("capitalized JSX"), we are actually using `React.createElement` to create a new element. Here is an example of a React component without children: ```res ``` + ```res React.createElement(Friend.make, Friend.makeProps(~name="Fred", ~age=1, ())) ``` + ```js React.createElement(Playground$Friend, { name: "Fred", age: 20 }); ``` @@ -165,17 +168,21 @@ React.createElementVariadic( ``` ```js -React.createElement(Container, { width: 200, children: null }, "Hello", "World"); +React.createElement( + Container, + { width: 200, children: null }, + "Hello", + "World", +); ``` Note that the `~children=React.null` prop has no relevance since React will only care about the children array passed as a third argument. - ### Dom Elements -"Uncapitalized JSX" expressions are treated as DOM elements and will be converted to `ReactDOMRe.createDOMElementVariadic` calls: +"Uncapitalized JSX" expressions are treated as DOM elements and will be converted to `ReactDOMRe.createDOMElementVariadic` calls: @@ -188,7 +195,7 @@ ReactDOMRe.createDOMElementVariadic("div", ~props=ReactDOMRe.domProps(~title="te ``` ```js - React.createElement("div", { title: "test" }); +React.createElement("div", { title: "test" }); ``` @@ -212,7 +219,11 @@ ReactDOMRe.createDOMElementVariadic( ``` ```js -React.createElement("div", { title: "test" }, React.createElement("span", undefined)); +React.createElement( + "div", + { title: "test" }, + React.createElement("span", undefined), +); ``` diff --git a/pages/docs/react/v0.10.0/components-and-props.mdx b/pages/docs/react/v0.10.0/components-and-props.mdx index 160eb515b..29ab91dfb 100644 --- a/pages/docs/react/v0.10.0/components-and-props.mdx +++ b/pages/docs/react/v0.10.0/components-and-props.mdx @@ -8,13 +8,13 @@ canonical: "/docs/react/latest/components-and-props" -Components let you split the UI into independent, reusable pieces, and think about each piece in isolation. This page provides an introduction to the idea of components. +Components let you split the UI into independent, reusable pieces, and think about each piece in isolation. This page provides an introduction to the idea of components. ## What is a Component? -A React component is a function describing a UI element that receives a `props` object as a parameter (data describing the dynamic parts of the UI) and returns a `React.element`. +A React component is a function describing a UI element that receives a `props` object as a parameter (data describing the dynamic parts of the UI) and returns a `React.element`. The nice thing about this concept is that you can solely focus on the input and output. The component function receives some data and returns some opaque `React.element` that is managed by the React framework to render your UI. @@ -35,6 +35,7 @@ let make = () => {
} ``` + ```js var React = require("react"); @@ -51,7 +52,7 @@ var make = Greeting; We've created a `Greeting.res` file that contains a `make` function that doesn't receive any props (the function doesn't receive any parameters), and returns a `React.element` that represents `
Hello ReScripters!
` in the rendered DOM. -You can also see in the the JS output that the function we created was directly translated into the pure JS version of a ReactJS component. Note how a `
` transforms into a `React.createElement("div",...)` call in JavaScript. +You can also see in the the JS output that the function we created was directly translated into the pure JS version of a ReactJS component. Note how a `
` transforms into a `React.createElement("div",...)` call in JavaScript. ## Defining Props @@ -71,6 +72,7 @@ let make = (~title: string, ~visitorCount: int, ~children: React.element) => {
} ``` + ```js var React = require("react"); @@ -79,7 +81,13 @@ function Article(Props) { var visitorCount = Props.visitorCount; var children = Props.children; var visitorCountMsg = "You are visitor number: " + String(visitorCount); - return React.createElement("div", undefined, React.createElement("div", undefined, title), React.createElement("div", undefined, visitorCountMsg), children); + return React.createElement( + "div", + undefined, + React.createElement("div", undefined, title), + React.createElement("div", undefined, visitorCountMsg), + children, + ); } var make = Article; @@ -115,7 +123,7 @@ function Greeting(Props) { -**Note:** The `@react.component` attribute implicitly adds the last `()` parameter to our `make` function for us (no need to do it ourselves). +**Note:** The `@react.component` attribute implicitly adds the last `()` parameter to our `make` function for us (no need to do it ourselves). In JSX, you can apply optional props with some special syntax: @@ -150,13 +158,12 @@ Check out the corresponding [Arrays and Keys](./arrays-and-keys) and [Forwarding ### Handling Invalid Prop Names (e.g. keywords) -Prop names like `type` (as in ``) aren't syntactically valid; `type` is a reserved keyword in ReScript. Use `` instead. +Prop names like `type` (as in ``) aren't syntactically valid; `type` is a reserved keyword in ReScript. Use `` instead. For `aria-*` use camelCasing, e.g., `ariaLabel`. For DOM components, we'll translate it to `aria-label` under the hood. For `data-*` this is a bit trickier; words with `-` in them aren't valid in ReScript. When you do want to write them, e.g., `
`, check out the [React.cloneElement](./elements-and-jsx#cloning-elements) or [React.createDOMElementVariadic](./elements-and-jsx#creating-dom-elements) section. - ## Children Props In React `props.children` is a special attribute to represent the nested elements within a parent element: @@ -187,20 +194,23 @@ module MyList = { ``` ```js - function MyList(Props) { var children = Props.children; return React.createElement("ul", undefined, children); } var MyList = { - make: MyList + make: MyList, }; -React.createElement(MyList, { - children: null - }, React.createElement("li", undefined, "Item 1"), - React.createElement("li", undefined, "Item 2")); +React.createElement( + MyList, + { + children: null, + }, + React.createElement("li", undefined, "Item 1"), + React.createElement("li", undefined, "Item 2"), +); ``` @@ -270,14 +280,12 @@ The best way to approach this kind of issue is by using props instead of childre **The best use-case for `children` is to pass down `React.element`s without any semantic order or implementation details!** - ## Props & Type Inference -The ReScript type system is really good at inferring the prop types just by looking at its prop usage. +The ReScript type system is really good at inferring the prop types just by looking at its prop usage. For simple cases, well-scoped usage, or experimentation, it's still fine to omit type annotations: - ```res // Button.res @@ -310,12 +318,17 @@ let make = () => {
} ``` + ```js var React = require("react"); -var Greeting = require("./Greeting.js") +var Greeting = require("./Greeting.js"); function App(Props) { - return React.createElement("div", undefined, React.createElement(Greeting.make, {})); + return React.createElement( + "div", + undefined, + React.createElement(Greeting.make, {}), + ); } var make = App; @@ -325,7 +338,6 @@ var make = App; **Note:** React components are capitalized; primitive DOM elements like `div` or `button` are uncapitalized. More infos on the JSX specifics and code transformations can be found in our [JSX language manual section](/docs/manual/latest/jsx#capitalized-tag). - ### Handwritten Components You don't need to use the `@react.component` decorator to write components that can be used in JSX. Instead you can write a pair of `make` and `makeProps` functions such that type `makeProps: 'a => props` and `make: props => React.element` and these will always work as React components. @@ -342,7 +354,7 @@ module Link = { ~children: React.element, unit) => props = "" - let make = (props: props) => { + let make = (props: props) => { {props["children"]} @@ -351,27 +363,31 @@ module Link = { {React.string("Docs")} ``` + ```js function Link(props) { - return React.createElement("a", { - href: props.href - }, props.children); + return React.createElement( + "a", + { + href: props.href, + }, + props.children, + ); } React.createElement(Link, { - href: "/docs", - children: "Docs" - }); + href: "/docs", + children: "Docs", +}); ``` More details on the `@react.component` decorator and its generated interface can be found in our [Beyond JSX](./beyond-jsx) page. - ## Submodule Components -We can also represent React components as submodules, which makes it very convenient to build more complex UI without the need to create multiple files for each composite component (that's probably only used by the parent component anyways): +We can also represent React components as submodules, which makes it very convenient to build more complex UI without the need to create multiple files for each composite component (that's probably only used by the parent component anyways): ```res // src/Button.res @@ -393,7 +409,6 @@ let make = (~children) => { The `Button.res` file defined above is now containing a `Label` component, that can also be used by other components, either by writing the fully qualified module name (``) or by using a module alias to shortcut the full qualifier: - ```res module Label = Button.Label @@ -404,7 +419,6 @@ let content =
} ``` + ```js function Counter(Props) { var match = React.useState(function () { - return 0; - }); + return 0; + }); var setCount = match[1]; var onClick = function (_evt) { - return Curry._1(setCount, (function (prev) { - return prev + 1 | 0; - })); + return Curry._1(setCount, function (prev) { + return (prev + 1) | 0; + }); }; var msg = "You clicked" + String(match[0]) + "times"; - return React.createElement("div", undefined, React.createElement("p", undefined, msg), React.createElement("button", { - onClick: onClick - }, "Click me")); + return React.createElement( + "div", + undefined, + React.createElement("p", undefined, msg), + React.createElement( + "button", + { + onClick: onClick, + }, + "Click me", + ), + ); } ```
- -Here we are using the `React.useState` Hook. We call it inside a component function to add some local state to it. React will preserve this state between re-renders. `React.useState` returns a tuple: the current state value (`count`) and a function that lets you update it (`setCount`). You can call this function from an event handler or pass it down to other components to call the function. +Here we are using the `React.useState` Hook. We call it inside a component function to add some local state to it. React will preserve this state between re-renders. `React.useState` returns a tuple: the current state value (`count`) and a function that lets you update it (`setCount`). You can call this function from an event handler or pass it down to other components to call the function. The only argument to `React.useState` is a function that returns the initial state (`_ => 0`). In the example above, it is 0 because our counter starts from zero. Note that your state can be any type you want and `ReScript` will make sure to infer the types for you (only make sure to return an initial state that matches your type). The initial state argument is only used during the first render. @@ -84,12 +93,11 @@ This was just a quick example on our first hook usage. We will go into more deta ### Additional Hooks: - [useReducer](./hooks-reducer): An alternative to `useState`. Uses the state / action / reduce pattern. - - + + - [useRef](./hooks-ref): Returns a mutable React-Ref value - - - + + ## Rules of Hooks @@ -97,10 +105,8 @@ Hooks are just simple functions, but you need to follow _two rules_ when using t ### Rule 1) Only Call Hooks at the Top Level - **Don’t call Hooks inside loops, conditions, or nested functions.** Instead, always use Hooks at the top level of your React function. By following this rule, you ensure that Hooks are called in the same order each time a component renders. That’s what allows React to correctly preserve the state of Hooks between multiple `useState` and `useEffect` calls. (If you’re curious, you can check out the in depth explanation in the [ReactJS Hooks docs](https://reactjs.org/docs/hooks-rules.html#explanation)) - ### Rule 2) Only Call Hooks from React Functions **Don't call Hooks from regular functions.** Instead, you can: diff --git a/pages/docs/react/v0.10.0/hooks-reducer.mdx b/pages/docs/react/v0.10.0/hooks-reducer.mdx index 885ac59ce..da29239df 100644 --- a/pages/docs/react/v0.10.0/hooks-reducer.mdx +++ b/pages/docs/react/v0.10.0/hooks-reducer.mdx @@ -26,7 +26,7 @@ var match = React.useReducer(reducer, initialState); -An alternative to [useState](./hooks-state). Accepts a reducer of type `(state, action) => newState`, and returns the current `state` paired with a `dispatch` function `(action) => unit`. +An alternative to [useState](./hooks-state). Accepts a reducer of type `(state, action) => newState`, and returns the current `state` paired with a `dispatch` function `(action) => unit`. `React.useReducer` is usually preferable to `useState` when you have complex state logic that involves multiple sub-values or when the next state depends on the previous one. `useReducer` also lets you optimize performance for components that trigger deep updates because you can pass dispatch down instead of callbacks. @@ -67,29 +67,43 @@ let make = () => { function reducer(state, action) { if (action) { return { - count: state.count - 1 | 0 - }; + count: (state.count - 1) | 0, + }; } else { return { - count: state.count + 1 | 0 - }; + count: (state.count + 1) | 0, + }; } } function Counter(Props) { var match = React.useReducer(reducer, { - count: 0 - }); + count: 0, + }); var dispatch = match[1]; - return React.createElement(React.Fragment, undefined, "Count:" + String(match[0].count), React.createElement("button", { - onClick: (function (param) { - return Curry._1(dispatch, /* Dec */1); - }) - }, "-"), React.createElement("button", { - onClick: (function (param) { - return Curry._1(dispatch, /* Inc */0); - }) - }, "+")); + return React.createElement( + React.Fragment, + undefined, + "Count:" + String(match[0].count), + React.createElement( + "button", + { + onClick: function (param) { + return Curry._1(dispatch, /* Dec */ 1); + }, + }, + "-", + ), + React.createElement( + "button", + { + onClick: function (param) { + return Curry._1(dispatch, /* Inc */ 0); + }, + }, + "+", + ), + ); } ``` @@ -177,88 +191,103 @@ let make = () => { ```js function reducer(state, action) { switch (action.TAG | 0) { - case /* AddTodo */0 : - var todos = state.todos.concat([{ - id: state.nextId, - content: action._0, - completed: false - }]); - return { - todos: todos, - nextId: state.nextId + 1 | 0 - }; - case /* RemoveTodo */1 : - var id = action._0; - var todos$1 = state.todos.filter(function (todo) { - return todo.id !== id; - }); - return { - todos: todos$1, - nextId: state.nextId - }; - case /* ToggleTodo */2 : - var id$1 = action._0; - var todos$2 = Belt_Array.map(state.todos, (function (todo) { - if (todo.id === id$1) { - return { - id: todo.id, - content: todo.content, - completed: !todo.completed - }; - } else { - return todo; - } - })); - return { - todos: todos$2, - nextId: state.nextId - }; - + case /* AddTodo */ 0: + var todos = state.todos.concat([ + { + id: state.nextId, + content: action._0, + completed: false, + }, + ]); + return { + todos: todos, + nextId: (state.nextId + 1) | 0, + }; + case /* RemoveTodo */ 1: + var id = action._0; + var todos$1 = state.todos.filter(function (todo) { + return todo.id !== id; + }); + return { + todos: todos$1, + nextId: state.nextId, + }; + case /* ToggleTodo */ 2: + var id$1 = action._0; + var todos$2 = Belt_Array.map(state.todos, function (todo) { + if (todo.id === id$1) { + return { + id: todo.id, + content: todo.content, + completed: !todo.completed, + }; + } else { + return todo; + } + }); + return { + todos: todos$2, + nextId: state.nextId, + }; } } -var initialTodos = [{ +var initialTodos = [ + { id: 1, content: "Try ReScript & React", - completed: false - }]; + completed: false, + }, +]; function TodoApp(Props) { var match = React.useReducer(reducer, { - todos: initialTodos, - nextId: 2 - }); + todos: initialTodos, + nextId: 2, + }); var dispatch = match[1]; - var todos = Belt_Array.map(match[0].todos, (function (todo) { - return React.createElement("li", undefined, todo.content, React.createElement("button", { - onClick: (function (param) { - return Curry._1(dispatch, { - TAG: /* RemoveTodo */1, - _0: todo.id - }); - }) - }, "Remove"), React.createElement("input", { - checked: todo.completed, - type: "checkbox", - onChange: (function (param) { - return Curry._1(dispatch, { - TAG: /* ToggleTodo */2, - _0: todo.id - }); - }) - })); - })); - return React.createElement(React.Fragment, undefined, React.createElement("h1", undefined, "Todo List:"), React.createElement("ul", undefined, todos)); + var todos = Belt_Array.map(match[0].todos, function (todo) { + return React.createElement( + "li", + undefined, + todo.content, + React.createElement( + "button", + { + onClick: function (param) { + return Curry._1(dispatch, { + TAG: /* RemoveTodo */ 1, + _0: todo.id, + }); + }, + }, + "Remove", + ), + React.createElement("input", { + checked: todo.completed, + type: "checkbox", + onChange: function (param) { + return Curry._1(dispatch, { + TAG: /* ToggleTodo */ 2, + _0: todo.id, + }); + }, + }), + ); + }); + return React.createElement( + React.Fragment, + undefined, + React.createElement("h1", undefined, "Todo List:"), + React.createElement("ul", undefined, todos), + ); } ``` - ## Lazy Initialization - - ```res @@ -315,25 +344,25 @@ let make = (~initialCount: int) => { ```js function init(initialCount) { return { - count: initialCount - }; + count: initialCount, + }; } function reducer(state, action) { if (typeof action === "number") { if (action !== 0) { return { - count: state.count - 1 | 0 - }; + count: (state.count - 1) | 0, + }; } else { return { - count: state.count + 1 | 0 - }; + count: (state.count + 1) | 0, + }; } } else { return { - count: action._0 - }; + count: action._0, + }; } } @@ -341,15 +370,29 @@ function Counter(Props) { var initialCount = Props.initialCount; var match = React.useReducer(reducer, initialCount, init); var dispatch = match[1]; - return React.createElement(React.Fragment, undefined, "Count:" + String(match[0].count), React.createElement("button", { - onClick: (function (param) { - return Curry._1(dispatch, /* Dec */1); - }) - }, "-"), React.createElement("button", { - onClick: (function (param) { - return Curry._1(dispatch, /* Inc */0); - }) - }, "+")); + return React.createElement( + React.Fragment, + undefined, + "Count:" + String(match[0].count), + React.createElement( + "button", + { + onClick: function (param) { + return Curry._1(dispatch, /* Dec */ 1); + }, + }, + "-", + ), + React.createElement( + "button", + { + onClick: function (param) { + return Curry._1(dispatch, /* Inc */ 0); + }, + }, + "+", + ), + ); } ``` diff --git a/pages/docs/react/v0.10.0/hooks-ref.mdx b/pages/docs/react/v0.10.0/hooks-ref.mdx index a3d596f7c..25569e87c 100644 --- a/pages/docs/react/v0.10.0/hooks-ref.mdx +++ b/pages/docs/react/v0.10.0/hooks-ref.mdx @@ -21,8 +21,8 @@ let refContainer = React.useRef(initialValue); ``` ```js - var button = React.useRef(null); - React.useRef(0); +var button = React.useRef(null); +React.useRef(0); ``` @@ -37,7 +37,6 @@ However, `useRef()` is useful for more than the ref attribute. It's handy for ke This works because `useRef()` creates a plain JavaScript object. The only difference between `useRef()` and creating a `{current: ...}` object yourself is that useRef will give you the same ref object on every render. - Keep in mind that `useRef` doesn’t notify you when its content changes. Mutating the `.current` record field doesn’t cause a re-render. If you want to run some code when React attaches or detaches a ref to a DOM node, you may want to use a [callback ref](./refs-and-the-dom#callback-refs) instead. More infos on direct DOM manipulation can be found in the [Refs and the DOM](./refs-and-the-dom) section. @@ -46,7 +45,6 @@ More infos on direct DOM manipulation can be found in the [Refs and the DOM](./r ### Managing Focus for a Text Input - ```res @@ -75,17 +73,28 @@ let make = () => { function TextInputWithFocusButton(Props) { var inputEl = React.useRef(null); var onClick = function (param) { - return Belt_Option.forEach(Caml_option.nullable_to_opt(inputEl.current), (function (input) { - input.focus(); - - })); + return Belt_Option.forEach( + Caml_option.nullable_to_opt(inputEl.current), + function (input) { + input.focus(); + }, + ); }; - return React.createElement(React.Fragment, undefined, React.createElement("input", { - ref: inputEl, - type: "text" - }), React.createElement("button", { - onClick: onClick - }, "Focus the input")); + return React.createElement( + React.Fragment, + undefined, + React.createElement("input", { + ref: inputEl, + type: "text", + }), + React.createElement( + "button", + { + onClick: onClick, + }, + "Focus the input", + ), + ); } ``` @@ -129,22 +138,28 @@ function CustomTextInput(Props) { var textInput = React.useRef(null); var setTextInputRef = function (element) { textInput.current = element; - }; var focusTextInput = function (param) { - return Belt_Option.forEach(Caml_option.nullable_to_opt(textInput.current), (function (input) { - input.focus(); - - })); + return Belt_Option.forEach( + Caml_option.nullable_to_opt(textInput.current), + function (input) { + input.focus(); + }, + ); }; - return React.createElement("div", undefined, React.createElement("input", { - ref: setTextInputRef, - type: "text" - }), React.createElement("input", { - type: "button", - value: "Focus the text input", - onClick: focusTextInput - })); + return React.createElement( + "div", + undefined, + React.createElement("input", { + ref: setTextInputRef, + type: "text", + }), + React.createElement("input", { + type: "button", + value: "Focus the text input", + onClick: focusTextInput, + }), + ); } ``` diff --git a/pages/docs/react/v0.10.0/hooks-state.mdx b/pages/docs/react/v0.10.0/hooks-state.mdx index a3a9793c9..0dd47d0ef 100644 --- a/pages/docs/react/v0.10.0/hooks-state.mdx +++ b/pages/docs/react/v0.10.0/hooks-state.mdx @@ -22,8 +22,8 @@ let (state, setState) = React.useState(_ => initialState) ```js var match = React.useState(function () { - return initialState; - }); + return initialState; +}); var state = match[0]; @@ -32,7 +32,6 @@ var setState = match[1]; - During the initial render, the returned state `state` is the same as the value passed as the first argument (initialState). The `setState` function can be passed down to other components as well, which is useful for e.g. setting the state of a parent component by its children. @@ -62,7 +61,6 @@ let make = () => { In this example, we are creating a `ThemeContainer` component that manages a `darkmode` boolean state and passes the `setDarkmode` function to a `ControlPanel` component to trigger the state changes. - ```res @@ -95,37 +93,54 @@ let make = (~content) => { } ``` + ```js function ControlPanel(Props) { var setDarkmode = Props.setDarkmode; var darkmode = Props.darkmode; var onClick = function (evt) { evt.preventDefault(); - return Curry._1(setDarkmode, (function (prev) { - return !prev; - })); + return Curry._1(setDarkmode, function (prev) { + return !prev; + }); }; - var toggleText = "Switch to " + (( - darkmode ? "light" : "dark" - ) + " theme"); - return React.createElement("div", undefined, React.createElement("button", { - onClick: onClick - }, toggleText)); + var toggleText = "Switch to " + ((darkmode ? "light" : "dark") + " theme"); + return React.createElement( + "div", + undefined, + React.createElement( + "button", + { + onClick: onClick, + }, + toggleText, + ), + ); } function ThemeContainer(Props) { var content = Props.content; var match = React.useState(function () { - return false; - }); + return false; + }); var darkmode = match[0]; var className = darkmode ? "theme-dark" : "theme-light"; - return React.createElement("div", { - className: className - }, React.createElement("section", undefined, React.createElement("h1", undefined, "More Infos about ReScript"), content), React.createElement(Playground$ControlPanel, { - setDarkmode: match[1], - darkmode: darkmode - })); + return React.createElement( + "div", + { + className: className, + }, + React.createElement( + "section", + undefined, + React.createElement("h1", undefined, "More Infos about ReScript"), + content, + ), + React.createElement(Playground$ControlPanel, { + setDarkmode: match[1], + darkmode: darkmode, + }), + ); } ``` @@ -133,7 +148,6 @@ function ThemeContainer(Props) { Note that whenever `setDarkmode` is returning a new value (e.g. switching from `true` -> `false`), it will cause a re-render for `ThemeContainer`'s `className` and the toggle text of its nested `ControlPanel`. - ## Uncurried Version For cleaner JS output, you can use `React.Uncurried.useState` instead: @@ -148,15 +162,14 @@ setState(. prev => prev + 1) ```js var match = React.useState(function () { - return 0; - }); + return 0; +}); var setState = match[1]; setState(function (prev) { - return prev + 1 | 0; - }); + return (prev + 1) | 0; +}); ``` - diff --git a/pages/docs/react/v0.10.0/refs-and-the-dom.mdx b/pages/docs/react/v0.10.0/refs-and-the-dom.mdx index db14f0e53..aa4636a04 100644 --- a/pages/docs/react/v0.10.0/refs-and-the-dom.mdx +++ b/pages/docs/react/v0.10.0/refs-and-the-dom.mdx @@ -12,7 +12,6 @@ Refs provide a way to access DOM nodes or React elements created within your `ma - In the typical React dataflow, [props](./components-and-props) are the only way that parent components interact with their children. To modify a child, you re-render it with new props. However, there are a few cases where you need to imperatively modify a child outside of the typical dataflow. The child to be modified could be an `React.element`, or it could be a `Dom.element`. For both of these cases, React provides an escape hatch. A `React.ref` is defined like this: @@ -21,13 +20,13 @@ A `React.ref` is defined like this: type t<'value> = { mutable current: 'value } ``` -> *Note that the `Ref.ref` should not to be confused with the builtin [ref type](/docs/manual/latest/mutation), the language feature that enables mutation.* +> _Note that the `Ref.ref` should not to be confused with the builtin [ref type](/docs/manual/latest/mutation), the language feature that enables mutation._ ## When to use Refs There are a few good use cases for refs: -- Managing state that *should not trigger* any re-render. +- Managing state that _should not trigger_ any re-render. - Managing focus, text selection, or media playback. - Triggering imperative animations. - Integrating with third-party DOM libraries. @@ -64,6 +63,7 @@ let value = myRef.current ``` The value of the ref differs depending on the type of the node: + - When the ref attribute is used on an HTML element, the ref passed via `ReactDOM.Ref.domRef` receives the underlying DOM element as its current property (type of `React.ref>`) - In case of interop, when the ref attribute is used on a custom class component (based on JS classes), the ref object receives the mounted instance of the component as its current (not discussed in this document). - **You may not use the ref attribute on component functions** because they don’t have instances (we don't expose JS classes in ReScript). @@ -107,18 +107,22 @@ function CustomTextInput(Props) { var dom = textInput.current; if (!(dom == null)) { dom.focus(); - return ; + return; } - }; - return React.createElement("div", undefined, React.createElement("input", { - ref: textInput, - type: "text" - }), React.createElement("input", { - type: "button", - value: "Focus the text input", - onClick: onClick - })); + return React.createElement( + "div", + undefined, + React.createElement("input", { + ref: textInput, + type: "text", + }), + React.createElement("input", { + type: "button", + value: "Focus the text input", + onClick: onClick, + }), + ); } ``` @@ -132,12 +136,10 @@ A few things happened here, so let's break them down: React will assign the `current` field with the DOM element when the component mounts, and assign it back to null when it unmounts. - ### Refs and Component Functions In React, you **can't** pass a `ref` attribute to a component function: - ```res @@ -167,7 +169,6 @@ The snippet above will not compile and output an error that looks like this: `"R As the error message implies, If you want to allow people to take a ref to your component function, you can use [ref forwarding](./forwarding-refs) (possibly in conjunction with useImperativeHandle) instead. - ## Exposing DOM Refs to Parent Components In rare cases, you might want to have access to a child’s DOM node from a parent component. This is generally not recommended because it breaks component encapsulation, but it can occasionally be useful for triggering focus or measuring the size or position of a child DOM node. @@ -218,22 +219,28 @@ function CustomTextInput(Props) { var textInput = React.useRef(null); var setTextInputRef = function (element) { textInput.current = element; - }; var focusTextInput = function (param) { - return Belt_Option.forEach(Caml_option.nullable_to_opt(textInput.current), (function (input) { - input.focus(); - - })); + return Belt_Option.forEach( + Caml_option.nullable_to_opt(textInput.current), + function (input) { + input.focus(); + }, + ); }; - return React.createElement("div", undefined, React.createElement("input", { - ref: setTextInputRef, - type: "text" - }), React.createElement("input", { - type: "button", - value: "Focus the text input", - onClick: focusTextInput - })); + return React.createElement( + "div", + undefined, + React.createElement("input", { + ref: setTextInputRef, + type: "text", + }), + React.createElement("input", { + type: "button", + value: "Focus the text input", + onClick: focusTextInput, + }), + ); } ``` @@ -271,30 +278,31 @@ let make = () => { ```js function CustomTextInput(Props) { var setInputRef = Props.setInputRef; - return React.createElement("div", undefined, React.createElement("input", { - ref: setInputRef, - type: "text" - })); + return React.createElement( + "div", + undefined, + React.createElement("input", { + ref: setInputRef, + type: "text", + }), + ); } var CustomTextInput = { - make: CustomTextInput + make: CustomTextInput, }; function Parent(Props) { var textInput = React.useRef(null); var setInputRef = function (element) { textInput.current = element; - }; return React.createElement(CustomTextInput, { - setInputRef: setInputRef - }); + setInputRef: setInputRef, + }); } ``` - In the example above, `Parent` passes its ref callback as an `setInputRef` prop to the `CustomTextInput`, and the `CustomTextInput` passes the same function as a special ref attribute to the ``. As a result, the `textInput` ref in Parent will be set to the DOM node corresponding to the `` element in the `CustomTextInput`. - diff --git a/pages/docs/react/v0.10.0/rendering-elements.mdx b/pages/docs/react/v0.10.0/rendering-elements.mdx index 55c3af853..a7e1a1908 100644 --- a/pages/docs/react/v0.10.0/rendering-elements.mdx +++ b/pages/docs/react/v0.10.0/rendering-elements.mdx @@ -25,7 +25,7 @@ Unlike browser DOM elements, React elements are plain objects, and are cheap to Let's assume we've got an HTML file that contains a `div` like this: ```html -
+
``` We call this a “root” DOM node because everything inside it will be managed by React DOM. @@ -33,6 +33,7 @@ We call this a “root” DOM node because everything inside it will be managed Plain React applications usually have a single root DOM node. If you are integrating React into an existing app, you may have as many isolated root DOM nodes as you like. To render our React application into the `root` div, we need to do two things: + - Find our DOM node with `ReactDOM.querySelector` - Render our React element to our queried `Dom.element` with `ReactDOM.render` @@ -48,6 +49,7 @@ switch(ReactDOM.querySelector("#root")){ | None => () // do nothing } ``` + ```js var root = document.querySelector("#root"); diff --git a/pages/docs/react/v0.10.0/router.mdx b/pages/docs/react/v0.10.0/router.mdx index 0ceaaf0c0..104172a1c 100644 --- a/pages/docs/react/v0.10.0/router.mdx +++ b/pages/docs/react/v0.10.0/router.mdx @@ -15,18 +15,19 @@ RescriptReact comes with a router! We've leveraged the language and library feat ## How does it work? The available methods are listed here: - - `RescriptReactRouter.push(string)`: takes a new path and update the URL. - - `RescriptReactRouter.replace(string)`: like `push`, but replaces the current URL. - - `RescriptReactRouter.watchUrl(f)`: start watching for URL changes. Returns a subscription token. Upon url change, calls the callback and passes it the `RescriptReactRouter.url` record. - - `RescriptReactRouter.unwatchUrl(watcherID)`: stop watching for URL changes. - - `RescriptReactRouter.dangerouslyGetInitialUrl()`: get `url` record outside of `watchUrl`. Described later. - - `RescriptReactRouter.useUrl(~serverUrl)`: returns the `url` record inside a component. + +- `RescriptReactRouter.push(string)`: takes a new path and update the URL. +- `RescriptReactRouter.replace(string)`: like `push`, but replaces the current URL. +- `RescriptReactRouter.watchUrl(f)`: start watching for URL changes. Returns a subscription token. Upon url change, calls the callback and passes it the `RescriptReactRouter.url` record. +- `RescriptReactRouter.unwatchUrl(watcherID)`: stop watching for URL changes. +- `RescriptReactRouter.dangerouslyGetInitialUrl()`: get `url` record outside of `watchUrl`. Described later. +- `RescriptReactRouter.useUrl(~serverUrl)`: returns the `url` record inside a component. > If you want to know more about the low level details on how the router interface is implemented, refer to the [RescriptReactRouter implementation](https://github.com/rescript-lang/rescript-react/blob/master/src/RescriptReactRouter.res). ## Match a Route -*There's no API*! `watchUrl` gives you back a `url` record of the following shape: +_There's no API_! `watchUrl` gives you back a `url` record of the following shape: @@ -40,6 +41,7 @@ type url = { search: string } ``` + ```js // Empty output ``` @@ -57,6 +59,7 @@ So the url `www.hello.com/book/10/edit?name=Jane#author` is given back as: search: "name=Jane" } ``` + ```js // Empty output ``` @@ -74,7 +77,7 @@ Let's start with a first example to see how a ReScript React Router looks like: @react.component let make = () => { let url = RescriptReactRouter.useUrl() - + switch url.path { | list{"user", id} => | list{} => @@ -82,6 +85,7 @@ let make = () => { } } ``` + ```js import * as React from "react"; import * as User from "./User.bs.js"; @@ -99,20 +103,16 @@ function App(Props) { var match$1 = match.tl; if (match$1 && !match$1.tl) { return React.createElement(User.make, { - id: match$1.hd - }); + id: match$1.hd, + }); } - } return React.createElement(NotFound.make, {}); } var make = App; -export { - make , - -} +export { make }; ``` @@ -126,6 +126,7 @@ In other words, you'd like to read from the `url` record once at the beginning o Note: the reason why we label it as "dangerous" is to remind you not to read this `url` in any arbitrary component's e.g. `render`, since that information might be out of date if said component doesn't also contain a `watchUrl` subscription that re-renders the component when the URL changes. Aka, please only use `dangerouslyGetInitialUrl` alongside `watchUrl`. ## Push a New Route + From anywhere in your app, just call e.g. `RescriptReactRouter.push("/books/10/edit#validated")`. This will trigger a URL change (without a page refresh) and `watchUrl`'s callback will be called again. We might provide better facilities for typed routing + payload carrying in the future! diff --git a/pages/docs/react/v0.11.0/arrays-and-keys.mdx b/pages/docs/react/v0.11.0/arrays-and-keys.mdx index 56be3f290..7543924ac 100644 --- a/pages/docs/react/v0.11.0/arrays-and-keys.mdx +++ b/pages/docs/react/v0.11.0/arrays-and-keys.mdx @@ -77,7 +77,7 @@ module Blog = {

{React.string(post.content)}

}); - +
{sidebar}
@@ -94,7 +94,6 @@ let posts = [ let blog = ``` - ## Rendering `list` Values In case you ever want to render a `list` of items, you can do something like this: @@ -124,4 +123,3 @@ let make = () => { We use `Belt.List.toArray` to convert our list to an array before creating our `array`. Please note that using `list` has performance impact due to extra conversion costs. 99% of the time you'll want to use arrays (seamless interop, faster JS code), but in some cases it might make sense to use a `list` to leverage advanced pattern matching features etc. - diff --git a/pages/docs/react/v0.11.0/beyond-jsx.mdx b/pages/docs/react/v0.11.0/beyond-jsx.mdx index bb4a12411..19a23f605 100644 --- a/pages/docs/react/v0.11.0/beyond-jsx.mdx +++ b/pages/docs/react/v0.11.0/beyond-jsx.mdx @@ -14,11 +14,11 @@ JSX is a syntax sugar that allows us to use React components in an HTML like man **Note:** This section requires knowledge about the low level apis for [creating elements](./elements-and-jsx#creating-elements-from-component-functions), such as `React.createElement` or `ReactDOM.createDOMElementVariadic`. -> **Note:** This page assumes your `bsconfig.json` to be set to `"jsx": { "version": 4 }` to apply the right JSX transformations. +> **Note:** This page assumes your `bsconfig.json` to be set to `"jsx": { "version": 4 }` to apply the right JSX transformations. ## Component Types -A plain React component is defined as a `('props) => React.element` function. You can also express a component more efficiently with our shorthand type `React.component<'props>`. +A plain React component is defined as a `('props) => React.element` function. You can also express a component more efficiently with our shorthand type `React.component<'props>`. Here are some examples on how to define your own component types (often useful when interoping with existing JS code, or passing around components): @@ -32,6 +32,7 @@ type friendComp = friend => React.element type props = {padding: string, children: React.element} type containerComp = React.component ``` + The types above are pretty low level (basically the JS representation of a React component), but since ReScript React has its own ways of defining React components in a more language specific way, let's have a closer look on the anatomy of such a construct. ## JSX Component Interface @@ -51,6 +52,7 @@ module Friend = { } } ``` + ```res module Friend = { type props<'name, 'children> = { @@ -75,7 +77,6 @@ In the expanded output: The `@react.component` decorator also works for `React.forwardRef` calls: - ```res @@ -112,13 +113,14 @@ So now that we know how the ReScript React component transformation works, let's ## JSX Under the Hood -Whenever we are using JSX with a custom component ("capitalized JSX"), we are actually using `React.createElement` to create a new element. Here is an example of a React component without children: +Whenever we are using JSX with a custom component ("capitalized JSX"), we are actually using `React.createElement` to create a new element. Here is an example of a React component without children: ```res ``` + ```res // classic React.createElement(Friend.make, {name: "Fred", age:20}) @@ -126,6 +128,7 @@ React.createElement(Friend.make, {name: "Fred", age:20}) // automatic React.jsx(Friend.make, {name: "Fred", age: 20}) ``` + ```js React.createElement(Playground$Friend, { name: "Fred", age: 20 }); ``` @@ -159,17 +162,21 @@ React.jsxs( ``` ```js -React.createElement(Container, { width: 200, children: null }, "Hello", "World"); +React.createElement( + Container, + { width: 200, children: null }, + "Hello", + "World", +); ``` Note that the `children: React.null` field has no relevance since React will only care about the children array passed as a third argument. - ### Dom Elements -"Uncapitalized JSX" expressions are treated as DOM elements and will be converted to `ReactDOM.createDOMElementVariadic` calls: +"Uncapitalized JSX" expressions are treated as DOM elements and will be converted to `ReactDOM.createDOMElementVariadic` calls: @@ -214,7 +221,11 @@ ReactDOM.jsx("div", {title: "test", children: ?ReactDOM.someElement(ReactDOM.jsx ``` ```js -React.createElement("div", { title: "test" }, React.createElement("span", undefined)); +React.createElement( + "div", + { title: "test" }, + React.createElement("span", undefined), +); ``` diff --git a/pages/docs/react/v0.11.0/components-and-props.mdx b/pages/docs/react/v0.11.0/components-and-props.mdx index 7d21b1d68..20165fe1e 100644 --- a/pages/docs/react/v0.11.0/components-and-props.mdx +++ b/pages/docs/react/v0.11.0/components-and-props.mdx @@ -8,13 +8,13 @@ canonical: "/docs/react/latest/components-and-props" -Components let you split the UI into independent, reusable pieces, and think about each piece in isolation. This page provides an introduction to the idea of components. +Components let you split the UI into independent, reusable pieces, and think about each piece in isolation. This page provides an introduction to the idea of components. ## What is a Component? -A React component is a function describing a UI element that receives a `props` object as a parameter (data describing the dynamic parts of the UI) and returns a `React.element`. +A React component is a function describing a UI element that receives a `props` object as a parameter (data describing the dynamic parts of the UI) and returns a `React.element`. The nice thing about this concept is that you can solely focus on the input and output. The component function receives some data and returns some opaque `React.element` that is managed by the React framework to render your UI. @@ -35,6 +35,7 @@ let make = () => {
} ``` + ```js import * as React from "react"; @@ -51,7 +52,7 @@ var make = Greeting; We've created a `Greeting.res` file that contains a `make` function that doesn't receive any props (the function doesn't receive any parameters), and returns a `React.element` that represents `
Hello ReScripters!
` in the rendered DOM. -You can also see in the the JS output that the function we created was directly translated into the pure JS version of a ReactJS component. Note how a `
` transforms into a `React.createElement("div",...)` call in JavaScript. +You can also see in the the JS output that the function we created was directly translated into the pure JS version of a ReactJS component. Note how a `
` transforms into a `React.createElement("div",...)` call in JavaScript. ## Defining Props @@ -71,12 +72,19 @@ let make = (~title: string, ~visitorCount: int, ~children: React.element) => {
} ``` + ```js import * as React from "react"; function Article(props) { var visitorCountMsg = "You are visitor number: " + String(props.visitorCount); - return React.createElement("div", undefined, React.createElement("div", undefined, props.title), React.createElement("div", undefined, visitorCountMsg), props.children); + return React.createElement( + "div", + undefined, + React.createElement("div", undefined, props.title), + React.createElement("div", undefined, visitorCountMsg), + props.children, + ); } var make = Article; @@ -112,7 +120,7 @@ function Greeting(props) { -**Note:** The `@react.component` attribute implicitly adds the last `()` parameter to our `make` function for us (no need to do it ourselves). +**Note:** The `@react.component` attribute implicitly adds the last `()` parameter to our `make` function for us (no need to do it ourselves). In JSX, you can apply optional props with some special syntax: @@ -128,7 +136,7 @@ let name = Some("Andrea") var name = "Andrea"; React.createElement(Greeting, { - name: name + name: name, }); ``` @@ -142,13 +150,12 @@ Check out the corresponding [Arrays and Keys](./arrays-and-keys) and [Forwarding ### Handling Invalid Prop Names (e.g. keywords) -Prop names like `type` (as in ``) aren't syntactically valid; `type` is a reserved keyword in ReScript. Use `` instead. +Prop names like `type` (as in ``) aren't syntactically valid; `type` is a reserved keyword in ReScript. Use `` instead. For `aria-*` use camelCasing, e.g., `ariaLabel`. For DOM components, we'll translate it to `aria-label` under the hood. For `data-*` this is a bit trickier; words with `-` in them aren't valid in ReScript. When you do want to write them, e.g., `
`, check out the [React.cloneElement](./elements-and-jsx#cloning-elements) or [React.createDOMElementVariadic](./elements-and-jsx#creating-dom-elements) section. - ## Children Props In React `props.children` is a special attribute to represent the nested elements within a parent element: @@ -184,13 +191,17 @@ function MyList(props) { } var MyList = { - make: MyList + make: MyList, }; -React.createElement(MyList, { - children: null - }, React.createElement("li", undefined, "Item 1"), - React.createElement("li", undefined, "Item 2")); +React.createElement( + MyList, + { + children: null, + }, + React.createElement("li", undefined, "Item 1"), + React.createElement("li", undefined, "Item 2"), +); ``` @@ -260,14 +271,12 @@ The best way to approach this kind of issue is by using props instead of childre **The best use-case for `children` is to pass down `React.element`s without any semantic order or implementation details!** - ## Props & Type Inference -The ReScript type system is really good at inferring the prop types just by looking at its prop usage. +The ReScript type system is really good at inferring the prop types just by looking at its prop usage. For simple cases, well-scoped usage, or experimentation, it's still fine to omit type annotations: - ```res // Button.res @@ -300,12 +309,17 @@ let make = () => {
} ``` + ```js var React = require("react"); -var Greeting = require("./Greeting.js") +var Greeting = require("./Greeting.js"); function App(Props) { - return React.createElement("div", undefined, React.createElement(Greeting.make, {})); + return React.createElement( + "div", + undefined, + React.createElement(Greeting.make, {}), + ); } var make = App; @@ -315,7 +329,6 @@ var make = App; **Note:** React components are capitalized; primitive DOM elements like `div` or `button` are uncapitalized. More infos on the JSX specifics and code transformations can be found in our [JSX language manual section](/docs/manual/latest/jsx#capitalized-tag). - ### Handwritten Components You don't need to use the `@react.component` decorator to write components that can be used in JSX. Instead you can write the `make` function with type `props` and these will always work as React components. But then you will have the issue with the component name being "make" in the React dev tools. @@ -327,8 +340,8 @@ For example: ```res module Link = { type props = {href: string, children: React.element}; - - let make = (props: props) => { + + let make = (props: props) => { {props.children} @@ -337,13 +350,10 @@ module Link = { {React.string("Docs")} ``` + ```js function make(props) { - return React.createElement( - "a", - { href: props.href }, - props.children - ); + return React.createElement("a", { href: props.href }, props.children); } var Link = { @@ -360,10 +370,9 @@ React.createElement(make, { More details on the `@react.component` decorator and its generated interface can be found in our [Beyond JSX](./beyond-jsx) page. - ## Submodule Components -We can also represent React components as submodules, which makes it very convenient to build more complex UI without the need to create multiple files for each composite component (that's probably only used by the parent component anyways): +We can also represent React components as submodules, which makes it very convenient to build more complex UI without the need to create multiple files for each composite component (that's probably only used by the parent component anyways): ```res // src/Button.res @@ -385,7 +394,6 @@ let make = (~children) => { The `Button.res` file defined above is now containing a `Label` component, that can also be used by other components, either by writing the fully qualified module name (``) or by using a module alias to shortcut the full qualifier: - ```res module Label = Button.Label @@ -396,7 +404,6 @@ let content =
} ``` + ```js function Counter(Props) { var match = React.useState(function () { - return 0; - }); + return 0; + }); var setCount = match[1]; var onClick = function (_evt) { - return Curry._1(setCount, (function (prev) { - return prev + 1 | 0; - })); + return Curry._1(setCount, function (prev) { + return (prev + 1) | 0; + }); }; var msg = "You clicked" + String(match[0]) + "times"; - return React.createElement("div", undefined, React.createElement("p", undefined, msg), React.createElement("button", { - onClick: onClick - }, "Click me")); + return React.createElement( + "div", + undefined, + React.createElement("p", undefined, msg), + React.createElement( + "button", + { + onClick: onClick, + }, + "Click me", + ), + ); } ``` - -Here we are using the `React.useState` Hook. We call it inside a component function to add some local state to it. React will preserve this state between re-renders. `React.useState` returns a tuple: the current state value (`count`) and a function that lets you update it (`setCount`). You can call this function from an event handler or pass it down to other components to call the function. +Here we are using the `React.useState` Hook. We call it inside a component function to add some local state to it. React will preserve this state between re-renders. `React.useState` returns a tuple: the current state value (`count`) and a function that lets you update it (`setCount`). You can call this function from an event handler or pass it down to other components to call the function. The only argument to `React.useState` is a function that returns the initial state (`_ => 0`). In the example above, it is 0 because our counter starts from zero. Note that your state can be any type you want and `ReScript` will make sure to infer the types for you (only make sure to return an initial state that matches your type). The initial state argument is only used during the first render. @@ -84,12 +93,11 @@ This was just a quick example on our first hook usage. We will go into more deta ### Additional Hooks: - [useReducer](./hooks-reducer): An alternative to `useState`. Uses the state / action / reduce pattern. - - + + - [useRef](./hooks-ref): Returns a mutable React-Ref value - - - + + ## Rules of Hooks @@ -97,10 +105,8 @@ Hooks are just simple functions, but you need to follow _two rules_ when using t ### Rule 1) Only Call Hooks at the Top Level - **Don’t call Hooks inside loops, conditions, or nested functions.** Instead, always use Hooks at the top level of your React function. By following this rule, you ensure that Hooks are called in the same order each time a component renders. That’s what allows React to correctly preserve the state of Hooks between multiple `useState` and `useEffect` calls. (If you’re curious, you can check out the in depth explanation in the [ReactJS Hooks docs](https://reactjs.org/docs/hooks-rules.html#explanation)) - ### Rule 2) Only Call Hooks from React Functions **Don't call Hooks from regular functions.** Instead, you can: diff --git a/pages/docs/react/v0.11.0/hooks-reducer.mdx b/pages/docs/react/v0.11.0/hooks-reducer.mdx index 885ac59ce..da29239df 100644 --- a/pages/docs/react/v0.11.0/hooks-reducer.mdx +++ b/pages/docs/react/v0.11.0/hooks-reducer.mdx @@ -26,7 +26,7 @@ var match = React.useReducer(reducer, initialState); -An alternative to [useState](./hooks-state). Accepts a reducer of type `(state, action) => newState`, and returns the current `state` paired with a `dispatch` function `(action) => unit`. +An alternative to [useState](./hooks-state). Accepts a reducer of type `(state, action) => newState`, and returns the current `state` paired with a `dispatch` function `(action) => unit`. `React.useReducer` is usually preferable to `useState` when you have complex state logic that involves multiple sub-values or when the next state depends on the previous one. `useReducer` also lets you optimize performance for components that trigger deep updates because you can pass dispatch down instead of callbacks. @@ -67,29 +67,43 @@ let make = () => { function reducer(state, action) { if (action) { return { - count: state.count - 1 | 0 - }; + count: (state.count - 1) | 0, + }; } else { return { - count: state.count + 1 | 0 - }; + count: (state.count + 1) | 0, + }; } } function Counter(Props) { var match = React.useReducer(reducer, { - count: 0 - }); + count: 0, + }); var dispatch = match[1]; - return React.createElement(React.Fragment, undefined, "Count:" + String(match[0].count), React.createElement("button", { - onClick: (function (param) { - return Curry._1(dispatch, /* Dec */1); - }) - }, "-"), React.createElement("button", { - onClick: (function (param) { - return Curry._1(dispatch, /* Inc */0); - }) - }, "+")); + return React.createElement( + React.Fragment, + undefined, + "Count:" + String(match[0].count), + React.createElement( + "button", + { + onClick: function (param) { + return Curry._1(dispatch, /* Dec */ 1); + }, + }, + "-", + ), + React.createElement( + "button", + { + onClick: function (param) { + return Curry._1(dispatch, /* Inc */ 0); + }, + }, + "+", + ), + ); } ``` @@ -177,88 +191,103 @@ let make = () => { ```js function reducer(state, action) { switch (action.TAG | 0) { - case /* AddTodo */0 : - var todos = state.todos.concat([{ - id: state.nextId, - content: action._0, - completed: false - }]); - return { - todos: todos, - nextId: state.nextId + 1 | 0 - }; - case /* RemoveTodo */1 : - var id = action._0; - var todos$1 = state.todos.filter(function (todo) { - return todo.id !== id; - }); - return { - todos: todos$1, - nextId: state.nextId - }; - case /* ToggleTodo */2 : - var id$1 = action._0; - var todos$2 = Belt_Array.map(state.todos, (function (todo) { - if (todo.id === id$1) { - return { - id: todo.id, - content: todo.content, - completed: !todo.completed - }; - } else { - return todo; - } - })); - return { - todos: todos$2, - nextId: state.nextId - }; - + case /* AddTodo */ 0: + var todos = state.todos.concat([ + { + id: state.nextId, + content: action._0, + completed: false, + }, + ]); + return { + todos: todos, + nextId: (state.nextId + 1) | 0, + }; + case /* RemoveTodo */ 1: + var id = action._0; + var todos$1 = state.todos.filter(function (todo) { + return todo.id !== id; + }); + return { + todos: todos$1, + nextId: state.nextId, + }; + case /* ToggleTodo */ 2: + var id$1 = action._0; + var todos$2 = Belt_Array.map(state.todos, function (todo) { + if (todo.id === id$1) { + return { + id: todo.id, + content: todo.content, + completed: !todo.completed, + }; + } else { + return todo; + } + }); + return { + todos: todos$2, + nextId: state.nextId, + }; } } -var initialTodos = [{ +var initialTodos = [ + { id: 1, content: "Try ReScript & React", - completed: false - }]; + completed: false, + }, +]; function TodoApp(Props) { var match = React.useReducer(reducer, { - todos: initialTodos, - nextId: 2 - }); + todos: initialTodos, + nextId: 2, + }); var dispatch = match[1]; - var todos = Belt_Array.map(match[0].todos, (function (todo) { - return React.createElement("li", undefined, todo.content, React.createElement("button", { - onClick: (function (param) { - return Curry._1(dispatch, { - TAG: /* RemoveTodo */1, - _0: todo.id - }); - }) - }, "Remove"), React.createElement("input", { - checked: todo.completed, - type: "checkbox", - onChange: (function (param) { - return Curry._1(dispatch, { - TAG: /* ToggleTodo */2, - _0: todo.id - }); - }) - })); - })); - return React.createElement(React.Fragment, undefined, React.createElement("h1", undefined, "Todo List:"), React.createElement("ul", undefined, todos)); + var todos = Belt_Array.map(match[0].todos, function (todo) { + return React.createElement( + "li", + undefined, + todo.content, + React.createElement( + "button", + { + onClick: function (param) { + return Curry._1(dispatch, { + TAG: /* RemoveTodo */ 1, + _0: todo.id, + }); + }, + }, + "Remove", + ), + React.createElement("input", { + checked: todo.completed, + type: "checkbox", + onChange: function (param) { + return Curry._1(dispatch, { + TAG: /* ToggleTodo */ 2, + _0: todo.id, + }); + }, + }), + ); + }); + return React.createElement( + React.Fragment, + undefined, + React.createElement("h1", undefined, "Todo List:"), + React.createElement("ul", undefined, todos), + ); } ``` - ## Lazy Initialization - - ```res @@ -315,25 +344,25 @@ let make = (~initialCount: int) => { ```js function init(initialCount) { return { - count: initialCount - }; + count: initialCount, + }; } function reducer(state, action) { if (typeof action === "number") { if (action !== 0) { return { - count: state.count - 1 | 0 - }; + count: (state.count - 1) | 0, + }; } else { return { - count: state.count + 1 | 0 - }; + count: (state.count + 1) | 0, + }; } } else { return { - count: action._0 - }; + count: action._0, + }; } } @@ -341,15 +370,29 @@ function Counter(Props) { var initialCount = Props.initialCount; var match = React.useReducer(reducer, initialCount, init); var dispatch = match[1]; - return React.createElement(React.Fragment, undefined, "Count:" + String(match[0].count), React.createElement("button", { - onClick: (function (param) { - return Curry._1(dispatch, /* Dec */1); - }) - }, "-"), React.createElement("button", { - onClick: (function (param) { - return Curry._1(dispatch, /* Inc */0); - }) - }, "+")); + return React.createElement( + React.Fragment, + undefined, + "Count:" + String(match[0].count), + React.createElement( + "button", + { + onClick: function (param) { + return Curry._1(dispatch, /* Dec */ 1); + }, + }, + "-", + ), + React.createElement( + "button", + { + onClick: function (param) { + return Curry._1(dispatch, /* Inc */ 0); + }, + }, + "+", + ), + ); } ``` diff --git a/pages/docs/react/v0.11.0/hooks-ref.mdx b/pages/docs/react/v0.11.0/hooks-ref.mdx index a3d596f7c..25569e87c 100644 --- a/pages/docs/react/v0.11.0/hooks-ref.mdx +++ b/pages/docs/react/v0.11.0/hooks-ref.mdx @@ -21,8 +21,8 @@ let refContainer = React.useRef(initialValue); ``` ```js - var button = React.useRef(null); - React.useRef(0); +var button = React.useRef(null); +React.useRef(0); ``` @@ -37,7 +37,6 @@ However, `useRef()` is useful for more than the ref attribute. It's handy for ke This works because `useRef()` creates a plain JavaScript object. The only difference between `useRef()` and creating a `{current: ...}` object yourself is that useRef will give you the same ref object on every render. - Keep in mind that `useRef` doesn’t notify you when its content changes. Mutating the `.current` record field doesn’t cause a re-render. If you want to run some code when React attaches or detaches a ref to a DOM node, you may want to use a [callback ref](./refs-and-the-dom#callback-refs) instead. More infos on direct DOM manipulation can be found in the [Refs and the DOM](./refs-and-the-dom) section. @@ -46,7 +45,6 @@ More infos on direct DOM manipulation can be found in the [Refs and the DOM](./r ### Managing Focus for a Text Input - ```res @@ -75,17 +73,28 @@ let make = () => { function TextInputWithFocusButton(Props) { var inputEl = React.useRef(null); var onClick = function (param) { - return Belt_Option.forEach(Caml_option.nullable_to_opt(inputEl.current), (function (input) { - input.focus(); - - })); + return Belt_Option.forEach( + Caml_option.nullable_to_opt(inputEl.current), + function (input) { + input.focus(); + }, + ); }; - return React.createElement(React.Fragment, undefined, React.createElement("input", { - ref: inputEl, - type: "text" - }), React.createElement("button", { - onClick: onClick - }, "Focus the input")); + return React.createElement( + React.Fragment, + undefined, + React.createElement("input", { + ref: inputEl, + type: "text", + }), + React.createElement( + "button", + { + onClick: onClick, + }, + "Focus the input", + ), + ); } ``` @@ -129,22 +138,28 @@ function CustomTextInput(Props) { var textInput = React.useRef(null); var setTextInputRef = function (element) { textInput.current = element; - }; var focusTextInput = function (param) { - return Belt_Option.forEach(Caml_option.nullable_to_opt(textInput.current), (function (input) { - input.focus(); - - })); + return Belt_Option.forEach( + Caml_option.nullable_to_opt(textInput.current), + function (input) { + input.focus(); + }, + ); }; - return React.createElement("div", undefined, React.createElement("input", { - ref: setTextInputRef, - type: "text" - }), React.createElement("input", { - type: "button", - value: "Focus the text input", - onClick: focusTextInput - })); + return React.createElement( + "div", + undefined, + React.createElement("input", { + ref: setTextInputRef, + type: "text", + }), + React.createElement("input", { + type: "button", + value: "Focus the text input", + onClick: focusTextInput, + }), + ); } ``` diff --git a/pages/docs/react/v0.11.0/hooks-state.mdx b/pages/docs/react/v0.11.0/hooks-state.mdx index a3a9793c9..0dd47d0ef 100644 --- a/pages/docs/react/v0.11.0/hooks-state.mdx +++ b/pages/docs/react/v0.11.0/hooks-state.mdx @@ -22,8 +22,8 @@ let (state, setState) = React.useState(_ => initialState) ```js var match = React.useState(function () { - return initialState; - }); + return initialState; +}); var state = match[0]; @@ -32,7 +32,6 @@ var setState = match[1]; - During the initial render, the returned state `state` is the same as the value passed as the first argument (initialState). The `setState` function can be passed down to other components as well, which is useful for e.g. setting the state of a parent component by its children. @@ -62,7 +61,6 @@ let make = () => { In this example, we are creating a `ThemeContainer` component that manages a `darkmode` boolean state and passes the `setDarkmode` function to a `ControlPanel` component to trigger the state changes. - ```res @@ -95,37 +93,54 @@ let make = (~content) => {
} ``` + ```js function ControlPanel(Props) { var setDarkmode = Props.setDarkmode; var darkmode = Props.darkmode; var onClick = function (evt) { evt.preventDefault(); - return Curry._1(setDarkmode, (function (prev) { - return !prev; - })); + return Curry._1(setDarkmode, function (prev) { + return !prev; + }); }; - var toggleText = "Switch to " + (( - darkmode ? "light" : "dark" - ) + " theme"); - return React.createElement("div", undefined, React.createElement("button", { - onClick: onClick - }, toggleText)); + var toggleText = "Switch to " + ((darkmode ? "light" : "dark") + " theme"); + return React.createElement( + "div", + undefined, + React.createElement( + "button", + { + onClick: onClick, + }, + toggleText, + ), + ); } function ThemeContainer(Props) { var content = Props.content; var match = React.useState(function () { - return false; - }); + return false; + }); var darkmode = match[0]; var className = darkmode ? "theme-dark" : "theme-light"; - return React.createElement("div", { - className: className - }, React.createElement("section", undefined, React.createElement("h1", undefined, "More Infos about ReScript"), content), React.createElement(Playground$ControlPanel, { - setDarkmode: match[1], - darkmode: darkmode - })); + return React.createElement( + "div", + { + className: className, + }, + React.createElement( + "section", + undefined, + React.createElement("h1", undefined, "More Infos about ReScript"), + content, + ), + React.createElement(Playground$ControlPanel, { + setDarkmode: match[1], + darkmode: darkmode, + }), + ); } ``` @@ -133,7 +148,6 @@ function ThemeContainer(Props) { Note that whenever `setDarkmode` is returning a new value (e.g. switching from `true` -> `false`), it will cause a re-render for `ThemeContainer`'s `className` and the toggle text of its nested `ControlPanel`. - ## Uncurried Version For cleaner JS output, you can use `React.Uncurried.useState` instead: @@ -148,15 +162,14 @@ setState(. prev => prev + 1) ```js var match = React.useState(function () { - return 0; - }); + return 0; +}); var setState = match[1]; setState(function (prev) { - return prev + 1 | 0; - }); + return (prev + 1) | 0; +}); ``` - diff --git a/pages/docs/react/v0.11.0/refs-and-the-dom.mdx b/pages/docs/react/v0.11.0/refs-and-the-dom.mdx index db14f0e53..aa4636a04 100644 --- a/pages/docs/react/v0.11.0/refs-and-the-dom.mdx +++ b/pages/docs/react/v0.11.0/refs-and-the-dom.mdx @@ -12,7 +12,6 @@ Refs provide a way to access DOM nodes or React elements created within your `ma - In the typical React dataflow, [props](./components-and-props) are the only way that parent components interact with their children. To modify a child, you re-render it with new props. However, there are a few cases where you need to imperatively modify a child outside of the typical dataflow. The child to be modified could be an `React.element`, or it could be a `Dom.element`. For both of these cases, React provides an escape hatch. A `React.ref` is defined like this: @@ -21,13 +20,13 @@ A `React.ref` is defined like this: type t<'value> = { mutable current: 'value } ``` -> *Note that the `Ref.ref` should not to be confused with the builtin [ref type](/docs/manual/latest/mutation), the language feature that enables mutation.* +> _Note that the `Ref.ref` should not to be confused with the builtin [ref type](/docs/manual/latest/mutation), the language feature that enables mutation._ ## When to use Refs There are a few good use cases for refs: -- Managing state that *should not trigger* any re-render. +- Managing state that _should not trigger_ any re-render. - Managing focus, text selection, or media playback. - Triggering imperative animations. - Integrating with third-party DOM libraries. @@ -64,6 +63,7 @@ let value = myRef.current ``` The value of the ref differs depending on the type of the node: + - When the ref attribute is used on an HTML element, the ref passed via `ReactDOM.Ref.domRef` receives the underlying DOM element as its current property (type of `React.ref>`) - In case of interop, when the ref attribute is used on a custom class component (based on JS classes), the ref object receives the mounted instance of the component as its current (not discussed in this document). - **You may not use the ref attribute on component functions** because they don’t have instances (we don't expose JS classes in ReScript). @@ -107,18 +107,22 @@ function CustomTextInput(Props) { var dom = textInput.current; if (!(dom == null)) { dom.focus(); - return ; + return; } - }; - return React.createElement("div", undefined, React.createElement("input", { - ref: textInput, - type: "text" - }), React.createElement("input", { - type: "button", - value: "Focus the text input", - onClick: onClick - })); + return React.createElement( + "div", + undefined, + React.createElement("input", { + ref: textInput, + type: "text", + }), + React.createElement("input", { + type: "button", + value: "Focus the text input", + onClick: onClick, + }), + ); } ``` @@ -132,12 +136,10 @@ A few things happened here, so let's break them down: React will assign the `current` field with the DOM element when the component mounts, and assign it back to null when it unmounts. - ### Refs and Component Functions In React, you **can't** pass a `ref` attribute to a component function: - ```res @@ -167,7 +169,6 @@ The snippet above will not compile and output an error that looks like this: `"R As the error message implies, If you want to allow people to take a ref to your component function, you can use [ref forwarding](./forwarding-refs) (possibly in conjunction with useImperativeHandle) instead. - ## Exposing DOM Refs to Parent Components In rare cases, you might want to have access to a child’s DOM node from a parent component. This is generally not recommended because it breaks component encapsulation, but it can occasionally be useful for triggering focus or measuring the size or position of a child DOM node. @@ -218,22 +219,28 @@ function CustomTextInput(Props) { var textInput = React.useRef(null); var setTextInputRef = function (element) { textInput.current = element; - }; var focusTextInput = function (param) { - return Belt_Option.forEach(Caml_option.nullable_to_opt(textInput.current), (function (input) { - input.focus(); - - })); + return Belt_Option.forEach( + Caml_option.nullable_to_opt(textInput.current), + function (input) { + input.focus(); + }, + ); }; - return React.createElement("div", undefined, React.createElement("input", { - ref: setTextInputRef, - type: "text" - }), React.createElement("input", { - type: "button", - value: "Focus the text input", - onClick: focusTextInput - })); + return React.createElement( + "div", + undefined, + React.createElement("input", { + ref: setTextInputRef, + type: "text", + }), + React.createElement("input", { + type: "button", + value: "Focus the text input", + onClick: focusTextInput, + }), + ); } ``` @@ -271,30 +278,31 @@ let make = () => { ```js function CustomTextInput(Props) { var setInputRef = Props.setInputRef; - return React.createElement("div", undefined, React.createElement("input", { - ref: setInputRef, - type: "text" - })); + return React.createElement( + "div", + undefined, + React.createElement("input", { + ref: setInputRef, + type: "text", + }), + ); } var CustomTextInput = { - make: CustomTextInput + make: CustomTextInput, }; function Parent(Props) { var textInput = React.useRef(null); var setInputRef = function (element) { textInput.current = element; - }; return React.createElement(CustomTextInput, { - setInputRef: setInputRef - }); + setInputRef: setInputRef, + }); } ``` - In the example above, `Parent` passes its ref callback as an `setInputRef` prop to the `CustomTextInput`, and the `CustomTextInput` passes the same function as a special ref attribute to the ``. As a result, the `textInput` ref in Parent will be set to the DOM node corresponding to the `` element in the `CustomTextInput`. - diff --git a/pages/docs/react/v0.11.0/rendering-elements.mdx b/pages/docs/react/v0.11.0/rendering-elements.mdx index 06413ad0a..d5813c2a7 100644 --- a/pages/docs/react/v0.11.0/rendering-elements.mdx +++ b/pages/docs/react/v0.11.0/rendering-elements.mdx @@ -25,7 +25,7 @@ Unlike browser DOM elements, React elements are plain objects, and are cheap to Let's assume we've got an HTML file that contains a `div` like this: ```html -
+
``` We call this a “root” DOM node because everything inside it will be managed by React DOM. @@ -33,6 +33,7 @@ We call this a “root” DOM node because everything inside it will be managed Plain React applications usually have a single root DOM node. If you are integrating React into an existing app, you may have as many isolated root DOM nodes as you like. To render our React application into the `root` div, we need to do two things: + - Find our DOM node with `ReactDOM.querySelector` - Render our React element to our queried `Dom.element` with `ReactDOM.render` @@ -51,6 +52,7 @@ switch ReactDOM.querySelector("#root") { | None => () } ``` + ```js var root = document.querySelector("#root"); diff --git a/pages/docs/react/v0.11.0/router.mdx b/pages/docs/react/v0.11.0/router.mdx index 0ceaaf0c0..104172a1c 100644 --- a/pages/docs/react/v0.11.0/router.mdx +++ b/pages/docs/react/v0.11.0/router.mdx @@ -15,18 +15,19 @@ RescriptReact comes with a router! We've leveraged the language and library feat ## How does it work? The available methods are listed here: - - `RescriptReactRouter.push(string)`: takes a new path and update the URL. - - `RescriptReactRouter.replace(string)`: like `push`, but replaces the current URL. - - `RescriptReactRouter.watchUrl(f)`: start watching for URL changes. Returns a subscription token. Upon url change, calls the callback and passes it the `RescriptReactRouter.url` record. - - `RescriptReactRouter.unwatchUrl(watcherID)`: stop watching for URL changes. - - `RescriptReactRouter.dangerouslyGetInitialUrl()`: get `url` record outside of `watchUrl`. Described later. - - `RescriptReactRouter.useUrl(~serverUrl)`: returns the `url` record inside a component. + +- `RescriptReactRouter.push(string)`: takes a new path and update the URL. +- `RescriptReactRouter.replace(string)`: like `push`, but replaces the current URL. +- `RescriptReactRouter.watchUrl(f)`: start watching for URL changes. Returns a subscription token. Upon url change, calls the callback and passes it the `RescriptReactRouter.url` record. +- `RescriptReactRouter.unwatchUrl(watcherID)`: stop watching for URL changes. +- `RescriptReactRouter.dangerouslyGetInitialUrl()`: get `url` record outside of `watchUrl`. Described later. +- `RescriptReactRouter.useUrl(~serverUrl)`: returns the `url` record inside a component. > If you want to know more about the low level details on how the router interface is implemented, refer to the [RescriptReactRouter implementation](https://github.com/rescript-lang/rescript-react/blob/master/src/RescriptReactRouter.res). ## Match a Route -*There's no API*! `watchUrl` gives you back a `url` record of the following shape: +_There's no API_! `watchUrl` gives you back a `url` record of the following shape: @@ -40,6 +41,7 @@ type url = { search: string } ``` + ```js // Empty output ``` @@ -57,6 +59,7 @@ So the url `www.hello.com/book/10/edit?name=Jane#author` is given back as: search: "name=Jane" } ``` + ```js // Empty output ``` @@ -74,7 +77,7 @@ Let's start with a first example to see how a ReScript React Router looks like: @react.component let make = () => { let url = RescriptReactRouter.useUrl() - + switch url.path { | list{"user", id} => | list{} => @@ -82,6 +85,7 @@ let make = () => { } } ``` + ```js import * as React from "react"; import * as User from "./User.bs.js"; @@ -99,20 +103,16 @@ function App(Props) { var match$1 = match.tl; if (match$1 && !match$1.tl) { return React.createElement(User.make, { - id: match$1.hd - }); + id: match$1.hd, + }); } - } return React.createElement(NotFound.make, {}); } var make = App; -export { - make , - -} +export { make }; ``` @@ -126,6 +126,7 @@ In other words, you'd like to read from the `url` record once at the beginning o Note: the reason why we label it as "dangerous" is to remind you not to read this `url` in any arbitrary component's e.g. `render`, since that information might be out of date if said component doesn't also contain a `watchUrl` subscription that re-renders the component when the URL changes. Aka, please only use `dangerouslyGetInitialUrl` alongside `watchUrl`. ## Push a New Route + From anywhere in your app, just call e.g. `RescriptReactRouter.push("/books/10/edit#validated")`. This will trigger a URL change (without a page refresh) and `watchUrl`'s callback will be called again. We might provide better facilities for typed routing + payload carrying in the future! diff --git a/pages/markdown-guide.mdx b/pages/markdown-guide.mdx index a8a727cbb..00906ed76 100644 --- a/pages/markdown-guide.mdx +++ b/pages/markdown-guide.mdx @@ -8,16 +8,14 @@ all available components and demonstrates some use-cases. - ## How does it work? We use a toolset called [mdxjs](https://mdxjs.com) to parse and interpret -`.mdx` files within the `pages/` directory. The default set for our markdown +`.mdx` files within the `pages/` directory. The default set for our markdown components is defined in the `Markdown.default` binding. Each layout in our codebase injects the components via the `Mdx.Provider` component, kinda like this: - ```re let components = Markdown.default; @@ -59,10 +57,8 @@ If you leave them out, the content will be a **plain string** without further fo Keep this in mind when editing content. - ## Text Components - ### Info / Blockquote The `` component is useful for putting notes into a highlighted @@ -84,7 +80,6 @@ section. You can use it via JSX syntax... The `Info` component is also really useful if you want its children to be parsed as markdown. You can even pass in html elements. - ``` @@ -115,7 +110,6 @@ similar information. - ### UrlBox ``` @@ -128,7 +122,9 @@ This is how you define a UrlBox **Examples:** -Check out the officially deployed version of this website (via absolute URL) + + Check out the officially deployed version of this website (via absolute URL) + @@ -139,7 +135,6 @@ Try **multiple paragraphs** for instance! - ### Cite @@ -148,7 +143,6 @@ Try **multiple paragraphs** for instance! - ``` @@ -159,8 +153,8 @@ Try **multiple paragraphs** for instance! ### Intro / Chapter Hero -This component is useful to ease the user into the topic. Use it for the first -paragraph and give a quick overview on what the document is about. +This component is useful to ease the user into the topic. Use it for the first +paragraph and give a quick overview on what the document is about. @@ -178,13 +172,11 @@ Your hero text ``` - ## Codeblocks Codeblocks are represented via \`\`\` codefences. Following languages are available: `res`, `re`, `js`, `ml`, `text`, `json`, `sh` - ```res let a = "This is a Reason codeblock" ``` @@ -198,7 +190,7 @@ highlighting To highlight codelines in your code snippet, use the `{range}` meta parameter: -~~~ +```` ```res {1,4-5} let a = 1 @@ -210,7 +202,7 @@ switch a => { | _ => b } ``` -~~~ +```` which will render: @@ -231,7 +223,8 @@ For cases where you want to show a single codeblock with multiple syntaxes, use Make sure to leave a newline between the `` JSX tags, otherwise codeblock children won't be recognized! **Example:** -~~~ + +```` ```res @@ -245,23 +238,23 @@ var highlighted = "yep" ``` -~~~ +```` Renders to following output: - ```res - let a = "Some ReScript code" - switch myValue { +```res +let a = "Some ReScript code" +switch myValue { - } - ``` +} +``` - ```js {3} - var a = "Some JavaScript code"; +```js {3} +var a = "Some JavaScript code"; - var highlighted = "Also supports highlighting ranges"; - ``` +var highlighted = "Also supports highlighting ranges"; +``` diff --git a/pages/packages.js b/pages/packages.js index 42d9cc1ab..57719db18 100644 --- a/pages/packages.js +++ b/pages/packages.js @@ -1,7 +1,7 @@ -import Comp from "src/Packages" +import Comp from "src/Packages"; -export { getStaticProps } from "src/Packages" +export { getStaticProps } from "src/Packages"; export default function PackagesPage(props) { - return ; + return ; } diff --git a/pages/syntax-lookup.js b/pages/syntax-lookup.js index 22cd2e6f4..689486f60 100644 --- a/pages/syntax-lookup.js +++ b/pages/syntax-lookup.js @@ -3,5 +3,5 @@ import SyntaxLookupRes from "src/SyntaxLookup.mjs"; export { getStaticProps } from "src/SyntaxLookup.mjs"; export default function SyntaxLookup(props) { - return + return ; } diff --git a/plugins/cm-reason-mode.js b/plugins/cm-reason-mode.js index 368d736eb..06265840c 100644 --- a/plugins/cm-reason-mode.js +++ b/plugins/cm-reason-mode.js @@ -14,45 +14,48 @@ CodeMirror.defineSimpleMode("reason", { // raw string and raw byte string { regex: /b?r"/, token: "string", next: "string_raw" }, { regex: /b?r#+"/, token: "string", next: "string_raw_hash" }, - { regex: /(\:\s*)(.*)(\s*=)\s/, token: [null, "type-annotation", null]}, + { regex: /(\:\s*)(.*)(\s*=)\s/, token: [null, "type-annotation", null] }, // character { regex: /'(?:[^'\\]|\\(?:[nrt0'"]|x[\da-fA-F]{2}|u\{[\da-fA-F]{6}\}))'/, - token: "string-2" + token: "string-2", }, // byte { regex: /b'(?:[^']|\\(?:['\\nrt0]|x[\da-fA-F]{2}))'/, token: "string-2" }, { - regex: /(?:(?:[0-9][0-9_]*)(?:(?:[Ee][+-]?[0-9_]+)|\.[0-9_]+(?:[Ee][+-]?[0-9_]+)?)(?:f32|f64)?)|(?:0(?:b[01_]+|(?:o[0-7_]+)|(?:x[0-9a-fA-F_]+))|(?:[0-9][0-9_]*))(?:u8|u16|u32|u64|i8|i16|i32|i64|isize|usize)?/, - token: "number" + regex: + /(?:(?:[0-9][0-9_]*)(?:(?:[Ee][+-]?[0-9_]+)|\.[0-9_]+(?:[Ee][+-]?[0-9_]+)?)(?:f32|f64)?)|(?:0(?:b[01_]+|(?:o[0-7_]+)|(?:x[0-9a-fA-F_]+))|(?:[0-9][0-9_]*))(?:u8|u16|u32|u64|i8|i16|i32|i64|isize|usize)?/, + token: "number", }, { regex: /(let|type)(\s+rec)?(\s+)([a-zA-Z_][a-zA-Z0-9_]*)/, - token: ["keyword", "keyword2", null, "def"] + token: ["keyword", "keyword2", null, "def"], }, { - regex: /(?:switch|module|as|do|else|external|for|if|in|loop|mod|pub|ref|type|while|open|open\!)\b/, - token: "keyword" + regex: + /(?:switch|module|as|do|else|external|for|if|in|loop|mod|pub|ref|type|while|open|open\!)\b/, + token: "keyword", }, { regex: /(?:rec)\b/, - token: "keyword2" + token: "keyword2", }, { regex: /\b(?:char|bool|option|int|string)\b/, - token: "atom" + token: "atom", }, { regex: /\b(?:true|false)\b/, token: "builtin" }, { regex: /\b(fun)(\s+)([a-zA-Z_\|][a-zA-Z0-9_]*)/, - token: ["keyword", null, "def"] + token: ["keyword", null, "def"], }, { regex: /\b([A-Z][a-zA-Z0-9_]*)(\.)/, - token: ["module", null] - }, { + token: ["module", null], + }, + { regex: /\b([A-Z][a-zA-Z0-9_]*)/, - token: ["variant-constructor", null, null, null] + token: ["variant-constructor", null, null, null], }, { regex: /\[.*\]/, token: "decorator" }, { regex: /#!?\[.*\]/, token: "meta" }, @@ -62,26 +65,24 @@ CodeMirror.defineSimpleMode("reason", { { regex: /[a-zA-Z_]\w*!/, token: "variable-3" }, { regex: /[a-zA-Z_]\w*/, token: "variable" }, { regex: /[\{\[\(]/, indent: true }, - { regex: /[\}\]\)]/, dedent: true } - ], - variantConstructor: [ - + { regex: /[\}\]\)]/, dedent: true }, ], + variantConstructor: [], string: [ { regex: /"/, token: "string", next: "start" }, - { regex: /(?:[^\\"]|\\(?:.|$))*/, token: "string" } + { regex: /(?:[^\\"]|\\(?:.|$))*/, token: "string" }, ], string_raw: [ { regex: /"/, token: "string", next: "start" }, - { regex: /[^"]*/, token: "string" } + { regex: /[^"]*/, token: "string" }, ], string_raw_hash: [ { regex: /"#+/, token: "string", next: "start" }, - { regex: /(?:[^"]|"(?!#))*/, token: "string" } + { regex: /(?:[^"]|"(?!#))*/, token: "string" }, ], comment: [ { regex: /.*?\*\//, token: "comment", next: "start" }, - { regex: /.*/, token: "comment" } + { regex: /.*/, token: "comment" }, ], meta: { dontIndentStates: ["comment"], @@ -89,8 +90,8 @@ CodeMirror.defineSimpleMode("reason", { blockCommentStart: "/*", blockCommentEnd: "*/", lineComment: "//", - fold: "brace" - } + fold: "brace", + }, }); CodeMirror.defineMIME("text/x-reasonsrc", "reason"); diff --git a/plugins/cm-rescript-mode.js b/plugins/cm-rescript-mode.js index 008a0f57e..202fd38a1 100644 --- a/plugins/cm-rescript-mode.js +++ b/plugins/cm-rescript-mode.js @@ -7,7 +7,6 @@ import "codemirror/addon/mode/simple"; import CodeMirror from "codemirror/lib/codemirror"; - CodeMirror.defineSimpleMode("rescript", { start: [ // string and byte string @@ -17,47 +16,49 @@ CodeMirror.defineSimpleMode("rescript", { //{ regex: /b?r#+"/, token: "string", next: "string_raw_hash" }, // string and byte string { regex: /b?"/, token: "string", next: "string" }, - { regex: /(\:\s*)(.*)(\s*=)\s/, token: [null, "type-annotation", null]}, - // interpolation string + { regex: /(\:\s*)(.*)(\s*=)\s/, token: [null, "type-annotation", null] }, + // interpolation string { regex: /b?`/, token: "string", next: "string_interpolation" }, // character { regex: /'(?:[^'\\]|\\(?:[nrt0'"]|x[\da-fA-F]{2}|u\{[\da-fA-F]{6}\}))'/, - token: "string-2" + token: "string-2", }, // byte { regex: /b'(?:[^']|\\(?:['\\nrt0]|x[\da-fA-F]{2}))'/, token: "string-2" }, { - regex: /(?:(?:[0-9][0-9_]*)(?:(?:[Ee][+-]?[0-9_]+)|\.[0-9_]+(?:[Ee][+-]?[0-9_]+)?)(?:f32|f64)?)|(?:0(?:b[01_]+|(?:o[0-7_]+)|(?:x[0-9a-fA-F_]+))|(?:[0-9][0-9_]*))(?:u8|u16|u32|u64|i8|i16|i32|i64|isize|usize)?/, - token: "number" + regex: + /(?:(?:[0-9][0-9_]*)(?:(?:[Ee][+-]?[0-9_]+)|\.[0-9_]+(?:[Ee][+-]?[0-9_]+)?)(?:f32|f64)?)|(?:0(?:b[01_]+|(?:o[0-7_]+)|(?:x[0-9a-fA-F_]+))|(?:[0-9][0-9_]*))(?:u8|u16|u32|u64|i8|i16|i32|i64|isize|usize)?/, + token: "number", }, { regex: /(let|type)(\s+rec)?(\s+)([a-zA-Z_][a-zA-Z0-9_]*)/, - token: ["keyword", "keyword2", null, "def"] + token: ["keyword", "keyword2", null, "def"], }, { - regex: /(?:and|as|assert|catch|async|await|constraint|downto|else|exception|export|external|false|for|if|import|in|include|lazy|let|module|mutable|of|open|private|switch|to|true|try|type|when|while|with\!)\b/, - token: "keyword" + regex: + /(?:and|as|assert|catch|async|await|constraint|downto|else|exception|export|external|false|for|if|import|in|include|lazy|let|module|mutable|of|open|private|switch|to|true|try|type|when|while|with\!)\b/, + token: "keyword", }, { regex: /(?:rec|list)\b/, - token: "keyword2" + token: "keyword2", }, { regex: /\b(?:char|bool|option|int|string)\b/, - token: "atom" + token: "atom", }, { regex: /\b(?:true|false)\b/, token: "builtin" }, { regex: /\b([A-Z][a-zA-Z0-9_]*)(\.)/, - token: ["module", null] + token: ["module", null], }, { regex: /\b([A-Z][a-zA-Z0-9_]*)/, - token: ["variant-constructor", null, null, null] + token: ["variant-constructor", null, null, null], }, //polyvar - { regex: /#[a-zA-Z0-9_"]*/, token: "variant-constructor"}, + { regex: /#[a-zA-Z0-9_"]*/, token: "variant-constructor" }, { regex: /@.[\w\.\(\)]*/, token: "decorator" }, { regex: /#!?\[.*\]/, token: "meta" }, { regex: /\/\/.*/, token: "comment" }, @@ -66,34 +67,32 @@ CodeMirror.defineSimpleMode("rescript", { { regex: /[a-zA-Z_]\w*!/, token: "variable-3" }, { regex: /[a-zA-Z_]\w*/, token: "variable" }, { regex: /[\{\[\(]/, indent: true }, - { regex: /[\}\]\)]/, dedent: true } - ], - variantConstructor: [ - + { regex: /[\}\]\)]/, dedent: true }, ], + variantConstructor: [], string: [ { regex: /"/, token: "string", next: "start" }, - { regex: /(?:[^\\"]|\\(?:.|$))*/, token: "string" } + { regex: /(?:[^\\"]|\\(?:.|$))*/, token: "string" }, ], //string_raw: [ - //{ regex: /"/, token: "string", next: "start" }, - //{ regex: /[^"]*/, token: "string" } + //{ regex: /"/, token: "string", next: "start" }, + //{ regex: /[^"]*/, token: "string" } //], //string_raw_hash: [ - //{ regex: /"#+/, token: "string", next: "start" }, - //{ regex: /(?:[^"]|"(?!#))*/, token: "string" } + //{ regex: /"#+/, token: "string", next: "start" }, + //{ regex: /(?:[^"]|"(?!#))*/, token: "string" } //], list: [ { regex: /list{/, token: "keyword2", next: "start" }, - { regex: /[^`]*/, token: "string" } + { regex: /[^`]*/, token: "string" }, ], string_interpolation: [ { regex: /`/, token: "string", next: "start" }, - { regex: /[^`]*/, token: "string" } + { regex: /[^`]*/, token: "string" }, ], comment: [ { regex: /.*?\*\//, token: "comment", next: "start" }, - { regex: /.*/, token: "comment" } + { regex: /.*/, token: "comment" }, ], meta: { dontIndentStates: ["comment"], @@ -101,8 +100,8 @@ CodeMirror.defineSimpleMode("rescript", { blockCommentStart: "/*", blockCommentEnd: "*/", lineComment: "//", - fold: "brace" - } + fold: "brace", + }, }); CodeMirror.defineMIME("text/x-reasonsrc", "reason"); diff --git a/plugins/reason-highlightjs.js b/plugins/reason-highlightjs.js index ec77aee43..f5cb1fba9 100644 --- a/plugins/reason-highlightjs.js +++ b/plugins/reason-highlightjs.js @@ -6,53 +6,82 @@ Category: functional // Note: Extracted and adapted from the reason-highlightjs package: // https://github.com/reasonml-editor/reason-highlightjs -export default function(hljs) { - function orReValues(ops){ +export default function (hljs) { + function orReValues(ops) { return ops - .map(function(op) { - return op - .split('') - .map(function(char) { - return '\\' + char; - }) - .join(''); - }) - .join('|'); + .map(function (op) { + return op + .split("") + .map(function (char) { + return "\\" + char; + }) + .join(""); + }) + .join("|"); } // eh why is the $ here - var RE_IDENT = '~?[a-z$_][0-9a-zA-Z$_]*'; - var RE_ATTRIBUTE = '[A-Za-z_][A-Za-z0-9_\\.]*'; - var RE_MODULE_IDENT = '[A-Z$_][0-9a-zA-Z$_]*'; - var RE_CONSTRUCTOR = '([A-Z][0-9a-zA-Z$_]*)|(`[a-zA-Z][0-9a-zA-Z$_]*)'; + var RE_IDENT = "~?[a-z$_][0-9a-zA-Z$_]*"; + var RE_ATTRIBUTE = "[A-Za-z_][A-Za-z0-9_\\.]*"; + var RE_MODULE_IDENT = "[A-Z$_][0-9a-zA-Z$_]*"; + var RE_CONSTRUCTOR = "([A-Z][0-9a-zA-Z$_]*)|(`[a-zA-Z][0-9a-zA-Z$_]*)"; - var RE_PARAM_TYPEPARAM = '\'?[a-z$_][0-9a-z$_]*'; - var RE_PARAM_TYPE = '\s*:\s*[a-z$_][0-9a-z$_]*(\(\s*(' + RE_PARAM_TYPEPARAM + '\s*(,' + RE_PARAM_TYPEPARAM + ')*)?\s*\))?'; - var RE_PARAM = RE_IDENT + '(' + RE_PARAM_TYPE + ')?(' + RE_PARAM_TYPE + ')?'; - var RE_OPERATOR = "(" + orReValues(['->', '||', '&&', '++', '**', '+.', '+', '-.', '-', '*.', '*', '/.', '/', '...', '|>', '===', '==', '^', ':=', '!']) + ")"; + var RE_PARAM_TYPEPARAM = "'?[a-z$_][0-9a-z$_]*"; + var RE_PARAM_TYPE = + "\s*:\s*[a-z$_][0-9a-z$_]*(\(\s*(" + + RE_PARAM_TYPEPARAM + + "\s*(," + + RE_PARAM_TYPEPARAM + + ")*)?\s*\))?"; + var RE_PARAM = RE_IDENT + "(" + RE_PARAM_TYPE + ")?(" + RE_PARAM_TYPE + ")?"; + var RE_OPERATOR = + "(" + + orReValues([ + "->", + "||", + "&&", + "++", + "**", + "+.", + "+", + "-.", + "-", + "*.", + "*", + "/.", + "/", + "...", + "|>", + "===", + "==", + "^", + ":=", + "!", + ]) + + ")"; var KEYWORDS = { /* https://github.com/facebook/reason/blob/79e67d5334ef181fdb54bd57bd9e7729f9fe46e7/src/reason-parser/reason_lexer.mll#L94-L154 */ keyword: - 'and as assert begin class constraint done downto exception external fun ' + - 'esfun function functor include inherit initializer lazy let pub mutable new nonrec ' + - 'object of open or pri rec then to type val virtual ' + - 'try catch finally do else for if switch while import library export ' + - 'module in raise', + "and as assert begin class constraint done downto exception external fun " + + "esfun function functor include inherit initializer lazy let pub mutable new nonrec " + + "object of open or pri rec then to type val virtual " + + "try catch finally do else for if switch while import library export " + + "module in raise", // not reliable // built_in: // 'array bool bytes char exn|5 float int int32 int64 list lazy_t|5 nativeint|5 ref string unit', - literal: - 'true false' + literal: "true false", }; - const RE_NUMBER = '\\b(0[xX][a-fA-F0-9_]+[Lln]?|' + - '0[oO][0-7_]+[Lln]?|' + - '0[bB][01_]+[Lln]?|' + - '[0-9][0-9_]*([Lln]|(\\.[0-9_]*)?([eE][-+]?[0-9_]+)?)?)'; + const RE_NUMBER = + "\\b(0[xX][a-fA-F0-9_]+[Lln]?|" + + "0[oO][0-7_]+[Lln]?|" + + "0[bB][01_]+[Lln]?|" + + "[0-9][0-9_]*([Lln]|(\\.[0-9_]*)?([eE][-+]?[0-9_]+)?)?)"; const STRING_MODE = { - className: 'string', + className: "string", variants: [ { begin: '"', @@ -61,68 +90,68 @@ export default function(hljs) { }, // {foo|bla|foo} { - begin: '\\{(' + RE_IDENT + ')?\\|', - end: '\\|(' + RE_IDENT + ')?\\}', + begin: "\\{(" + RE_IDENT + ")?\\|", + end: "\\|(" + RE_IDENT + ")?\\}", }, - ] + ], }; const CHARACTER_MODE = { - className: 'character', - begin: '\'(\\\\[^\']+|[^\'])\'', - illegal: '\\n', - relevance: 0 + className: "character", + begin: "'(\\\\[^']+|[^'])'", + illegal: "\\n", + relevance: 0, }; const NUMBER_MODE = { - className: 'number', + className: "number", relevance: 0, variants: [ { - begin: RE_NUMBER + begin: RE_NUMBER, }, { - begin: '\\(\\-' + RE_NUMBER + '\\)' - } - ] + begin: "\\(\\-" + RE_NUMBER + "\\)", + }, + ], }; const OPERATOR_MODE = { - className: 'operator', + className: "operator", relevance: 0, - begin: RE_OPERATOR + begin: RE_OPERATOR, }; // as in variant constructor const CONSTRUCTOR_MODE = { - className: 'constructor', - begin: '\\b' + RE_CONSTRUCTOR, - illegal: '\\n', + className: "constructor", + begin: "\\b" + RE_CONSTRUCTOR, + illegal: "\\n", keywords: KEYWORDS, }; const ARRAY_MODES = { - className: 'literal', + className: "literal", variants: [ { - begin: '\\[\\|', + begin: "\\[\\|", }, { - begin: '\\|\\]', + begin: "\\|\\]", }, - ] + ], }; const LIST_MODES = { - className: 'literal', + className: "literal", variants: [ { - begin: '\\[', + begin: "\\[", }, { - begin: '\\]', + begin: "\\]", }, - ] + ], }; const MODULE_ACCESS_MODE = { @@ -131,9 +160,9 @@ export default function(hljs) { contains: [ { begin: RE_MODULE_IDENT, - className: 'module-identifier', + className: "module-identifier", }, - ] + ], }; const JSX_MODE = { @@ -152,20 +181,20 @@ export default function(hljs) { contains: [ { begin: RE_MODULE_IDENT, - className: 'module-identifier', + className: "module-identifier", }, - ] + ], }, { begin: "<", contains: [ { begin: RE_MODULE_IDENT, - className: 'module-identifier', + className: "module-identifier", }, - ] + ], }, - ] + ], }; // Foo.Bar.Baz where Baz is actually a module, not a constructor @@ -183,13 +212,13 @@ export default function(hljs) { { begin: RE_MODULE_IDENT, className: "module-identifier", - } - ] + }, + ], }, - ] + ], }; const ATTRIBUTE_MODE = { - className: 'attribute', + className: "attribute", variants: [ { begin: "\\[@", @@ -227,16 +256,14 @@ export default function(hljs) { }, ], }, - ] + ], }; // all the modes below are mutually recursive let OPEN_OR_INCLUDE_MODULE_MODE = { begin: "\\b(open|include)\\s*", keywords: KEYWORDS, - contains: [ - MODULE_ACCESS_ENDS_WITH_MODULE, - ] + contains: [MODULE_ACCESS_ENDS_WITH_MODULE], }; let MODULE_MODE = { begin: "\\s*\\{\\s*", @@ -244,7 +271,7 @@ export default function(hljs) { keywords: KEYWORDS, // most of the order here is important contains: [ - hljs.COMMENT('/\\*', '\\*/', { illegal: '^(\\#,\\/\\/)' }), + hljs.COMMENT("/\\*", "\\*/", { illegal: "^(\\#,\\/\\/)" }), hljs.C_LINE_COMMENT_MODE, // there's also a block mode technically, but for our purpose, a module {} // and a block {} can be considered the same for highlighting @@ -259,7 +286,7 @@ export default function(hljs) { OPEN_OR_INCLUDE_MODULE_MODE, MODULE_ACCESS_MODE, CONSTRUCTOR_MODE, - ] + ], }; const MODULE_DECLARATION_MODE = { begin: "\\bmodule\\s+(type\\s+)?(of\\s+)?", @@ -279,7 +306,7 @@ export default function(hljs) { begin: RE_MODULE_IDENT, className: "module-identifier", }, - MODULE_MODE + MODULE_MODE, ], }, // then the = part and the right hand side @@ -308,29 +335,28 @@ export default function(hljs) { MODULE_MODE, { begin: "\\s*,\\s*", - } - ] + }, + ], }, MODULE_MODE, - ] + ], }, MODULE_MODE, { - begin: "\\s*=>\\s*" - } - ] + begin: "\\s*=>\\s*", + }, + ], }, - ] + ], }; MODULE_MODE.contains.unshift(MODULE_DECLARATION_MODE); - OPEN_OR_INCLUDE_MODULE_MODE.contains.push(MODULE_MODE) + OPEN_OR_INCLUDE_MODULE_MODE.contains.push(MODULE_MODE); return { - aliases: ['re', 'reasonml', 'rei'], + aliases: ["re", "reasonml", "rei"], keywords: KEYWORDS, - illegal: '(:\\-|:=|\\${|\\+=)', + illegal: "(:\\-|:=|\\${|\\+=)", // lol beautiful contains: MODULE_MODE.contains, }; } - diff --git a/postcss.config.mjs b/postcss.config.mjs index 9bcdedb99..c2ddf7482 100644 --- a/postcss.config.mjs +++ b/postcss.config.mjs @@ -1,5 +1,5 @@ export default { - plugins: { - '@tailwindcss/postcss': {}, - }, -} \ No newline at end of file + plugins: { + "@tailwindcss/postcss": {}, + }, +}; diff --git a/public/static/docson/box.html b/public/static/docson/box.html index c39369d69..a6ed00877 100644 --- a/public/static/docson/box.html +++ b/public/static/docson/box.html @@ -1,157 +1,98 @@ -{{! - Copyright 2013 Laurent Bovet (laurent.bovet@windmaster.ch) - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -}} -{{#scope this}} -
-
-
- {{#name this}}
{{__name}}
{{/name}} -
{{desc this}}
-
+{{! Copyright 2013 Laurent Bovet (laurent.bovet@windmaster.ch) Licensed under +the Apache License, Version 2.0 (the "License"); you may not use this file +except in compliance with the License. You may obtain a copy of the License at +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or +agreed to in writing, software distributed under the License is distributed on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +or implied. See the License for the specific language governing permissions and +limitations under the License. }} {{#scope this}} +
+
+
+ {{#name this}} +
{{__name}}
+ {{/name}} +
{{desc this}}
+
+
+
+
{}
+
+
+
+ {{#sub this}} +
+
+
+ {{#primitive this}} {{signature this null this}} {{/primitive}} + {{#equals type "array"}} {{signature this "array" items}} {{/equals}} + {{#if allOf}} {{signature this "all of" allOf}} {{/if}} {{#if anyOf}} + {{signature this "any of" anyOf}} {{/if}} {{#if oneOf}} {{signature + this "one of" oneOf}} {{/if}} {{#if not}} {{signature this "not" not}} + {{/if}}
+
+
+ {{#boxes}} +
{{schema this}}
+ {{/boxes}} +
-
{}
-
-
+
- {{#sub this}} -
-
-
- {{#primitive this}} - {{signature this null this}} - {{/primitive}} - {{#equals type "array"}} - {{signature this "array" items}} - {{/equals}} - {{#if allOf}} - {{signature this "all of" allOf}} - {{/if}} - {{#if anyOf}} - {{signature this "any of" anyOf}} - {{/if}} - {{#if oneOf}} - {{signature this "one of" oneOf}} - {{/if}} - {{#if not}} - {{signature this "not" not}} - {{/if}} -
-
-
- {{#boxes}} -
- {{schema this}} -
- {{/boxes}} -
+ {{/sub}} {{#if properties}} {{#each properties}} +
+
+
+ {{@key}} +
+
+ {{#main this}} {{signature this null this}} {{/main}} {{#equals type + "array"}} {{signature this "array" items}} {{/equals}} {{#if allOf}} + {{signature this "all of" allOf}} {{/if}} {{#if anyOf}} {{signature + this "any of" anyOf}} {{/if}} {{#if oneOf}} {{signature this "one of" + oneOf}} {{/if}} {{#if additionalProperties}} {{signature this "map" + additionalProperties}} {{/if}} {{#if not}} {{signature this "not" + not}} {{/if}}
- {{/sub}} - {{#if properties}} - {{#each properties}} -
-
-
{{@key}}
-
- {{#main this}} - {{signature this null this}} - {{/main}} - {{#equals type "array"}} - {{signature this "array" items}} - {{/equals}} - {{#if allOf}} - {{signature this "all of" allOf}} - {{/if}} - {{#if anyOf}} - {{signature this "any of" anyOf}} - {{/if}} - {{#if oneOf}} - {{signature this "one of" oneOf}} - {{/if}} - {{#if additionalProperties}} - {{signature this "map" additionalProperties}} - {{/if}} - {{#if not}} - {{signature this "not" not}} - {{/if}} -
-
{{desc this}}
-
-
- {{#boxes}} -
- {{schema this}} -
- {{/boxes}} -
-
- {{/each}} - {{/if}} - - {{#if patternProperties}} - {{#each patternProperties}} -
-
-
{{@key}}
-
- {{#main this}} - {{signature this null this}} - {{/main}} - {{#equals type "array"}} - {{signature this "array" items}} - {{/equals}} - {{#if allOf}} - {{signature this "all of" allOf}} - {{/if}} - {{#if anyOf}} - {{signature this "any of" anyOf}} - {{/if}} - {{#if oneOf}} - {{signature this "one of" oneOf}} - {{/if}} - {{#if not}} - {{signature this "not" not}} - {{/if}} -
-
{{desc this}}
-
-
- {{#boxes}} -
- {{schema this}} -
- {{/boxes}} -
-
- {{/each}} - {{/if}} - - {{#if additionalProperties}} -
-
-
additional
-
- {{schema ../additionalProperties}} -
-
+
{{desc this}}
+
+
+ {{#boxes}} +
{{schema this}}
+ {{/boxes}} +
+
+ {{/each}} {{/if}} {{#if patternProperties}} {{#each patternProperties}} +
+
+
{{@key}}
+
+ {{#main this}} {{signature this null this}} {{/main}} {{#equals type + "array"}} {{signature this "array" items}} {{/equals}} {{#if allOf}} + {{signature this "all of" allOf}} {{/if}} {{#if anyOf}} {{signature + this "any of" anyOf}} {{/if}} {{#if oneOf}} {{signature this "one of" + oneOf}} {{/if}} {{#if not}} {{signature this "not" not}} {{/if}}
- {{/if}} +
{{desc this}}
+
+
+ {{#boxes}} +
{{schema this}}
+ {{/boxes}} +
-
-
-{{source this}}
+ {{/each}} {{/if}} {{#if additionalProperties}} +
+
+
additional
+
{{schema ../additionalProperties}}
+
+ {{/if}} +
+
+
{{source this}}
+
-
+
{{/scope}} diff --git a/public/static/docson/signature.html b/public/static/docson/signature.html index 8412dbc23..75672360a 100644 --- a/public/static/docson/signature.html +++ b/public/static/docson/signature.html @@ -1,86 +1,67 @@ -{{! - Copyright 2013 Laurent Bovet (laurent.bovet@windmaster.ch) - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -}} -{{#if keyword}} - {{keyword}}{{range schema.minItems schema.maxItems 0 "" false false ".."}} - {{#each schemas}} - {{enum this}} - {{#simple this}} - - {{__type}} - - - {{range minLength maxLength "" "" false false ".."}}{{range minimum maximum "-∞" "∞" exclusiveMinimum exclusiveMaximum ";"}} - - {{/simple}} - {{#complex this}} - {{#box this}} - {{__type}} - {{/box}} - {{/complex}} - {{#ref this}} - {{#box this}} - {{__name}} - {{/box}} - {{/ref}} - {{#if pattern}} - /{{pattern}}/ - {{/if}} - {{#if enum}} - {{#each enum}} - {{this}} - {{/each}} - {{/if}} - {{#exists default}} - default - {{__default}} - {{/exists}} - {{/each}} -{{/if}} -{{#unless keyword}} - {{#each schemas}} - {{enum this}} - {{#primitive this}} - - {{__type}} - - - {{range minLength maxLength "" "" false false ".."}}{{range minimum maximum "-∞" "∞" exclusiveMinimum exclusiveMaximum ";"}} - - {{/primitive}} - {{#ref this}} - {{#box this}} - {{__name}} - {{/box}} - {{/ref}} - {{#obj this}} - {{#box this}} - {{__type}} - {{/box}} - {{/obj}} - {{#if pattern}} - /{{pattern}}/ - {{/if}} - {{#if enum}} - {{#each enum}} - {{this}} - {{/each}} - {{/if}} - {{#exists default}} - default - {{__default}} - {{/exists}} - {{/each}} -{{/unless}} +{{! Copyright 2013 Laurent Bovet (laurent.bovet@windmaster.ch) Licensed under +the Apache License, Version 2.0 (the "License"); you may not use this file +except in compliance with the License. You may obtain a copy of the License at +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or +agreed to in writing, software distributed under the License is distributed on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +or implied. See the License for the specific language governing permissions and +limitations under the License. }} {{#if keyword}} +{{keyword}}{{range schema.minItems schema.maxItems 0 "" false false + ".."}} +{{#each schemas}} +{{enum this}} +{{#simple this}} + {{__type}} + + {{range minLength maxLength "" "" false false ".."}}{{range minimum maximum + "-∞" "∞" exclusiveMinimum exclusiveMaximum ";"}} + +{{/simple}} {{#complex this}} {{#box this}} +{{__type}} +{{/box}} {{/complex}} {{#ref this}} {{#box this}} +{{__name}} +{{/box}} {{/ref}} {{#if pattern}} +/{{pattern}}/ +{{/if}} {{#if enum}} {{#each enum}} +{{this}} +{{/each}} {{/if}} {{#exists default}} +default +{{__default}} +{{/exists}} {{/each}} {{/if}} {{#unless keyword}} {{#each schemas}} +{{enum this}} +{{#primitive this}} + {{__type}} + + {{range minLength maxLength "" "" false false ".."}}{{range minimum maximum + "-∞" "∞" exclusiveMinimum exclusiveMaximum ";"}} + +{{/primitive}} {{#ref this}} {{#box this}} +{{__name}} +{{/box}} {{/ref}} {{#obj this}} {{#box this}} +{{__type}} +{{/box}} {{/obj}} {{#if pattern}} +/{{pattern}}/ +{{/if}} {{#if enum}} {{#each enum}} +{{this}} +{{/each}} {{/if}} {{#exists default}} +default +{{__default}} +{{/exists}} {{/each}} {{/unless}} diff --git a/public/static/favicon/site.webmanifest b/public/static/favicon/site.webmanifest index 45dc8a206..fa99de77d 100644 --- a/public/static/favicon/site.webmanifest +++ b/public/static/favicon/site.webmanifest @@ -1 +1,19 @@ -{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} \ No newline at end of file +{ + "name": "", + "short_name": "", + "icons": [ + { + "src": "/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} diff --git a/rescript.json b/rescript.json index 87790843e..84bf239bd 100644 --- a/rescript.json +++ b/rescript.json @@ -4,13 +4,8 @@ "jsx": { "version": 4 }, - "bs-dependencies": [ - "@rescript/react", - "@rescript/webapi" - ], - "bsc-flags": [ - "-open WebAPI.Global" - ], + "bs-dependencies": ["@rescript/react", "@rescript/webapi"], + "bsc-flags": ["-open WebAPI.Global"], "sources": [ { "dir": "src", diff --git a/scripts/bsb-benchmark-test.js b/scripts/bsb-benchmark-test.js index f73e6242e..9188db0b7 100644 --- a/scripts/bsb-benchmark-test.js +++ b/scripts/bsb-benchmark-test.js @@ -45,7 +45,7 @@ fix the build issue before benchmarking time = { real: parseFloat(match[1]), user: parseFloat(match[2]), - sys: parseFloat(match[3]) + sys: parseFloat(match[3]), }; } @@ -53,7 +53,7 @@ fix the build issue before benchmarking }; const getFileMetrics = () => { - const paths = bsconfig.sources.map(source => { + const paths = bsconfig.sources.map((source) => { if (typeof source === "string") { return source; } @@ -75,7 +75,7 @@ const getFileMetrics = () => { blankLines: out.ReasonML.blank, commentLines: out.ReasonML.comment, codeLines: out.ReasonML.code, - totalLines: out.header.n_lines + totalLines: out.header.n_lines, }; }; @@ -103,15 +103,14 @@ function main() { fileMetrics, buildTime, results: { - locPerSec - } + locPerSec, + }, }; if (asJson) { console.log(JSON.stringify(result, null, 2)); } - // TODO: maybe add human readable format as an option? } diff --git a/scripts/extract-indices.mjs b/scripts/extract-indices.mjs index d6d05777f..0a86d698e 100644 --- a/scripts/extract-indices.mjs +++ b/scripts/extract-indices.mjs @@ -8,14 +8,15 @@ import glob from "glob"; import path from "path"; import fs from "fs"; -import { URL } from 'url'; +import { URL } from "url"; import { defaultProcessor } from "./markdown.js"; -const pathname = new URL('.', import.meta.url).pathname; -const __dirname = process.platform !== 'win32' ? pathname : pathname.substring(1) +const pathname = new URL(".", import.meta.url).pathname; +const __dirname = + process.platform !== "win32" ? pathname : pathname.substring(1); -const processFile = filepath => { +const processFile = (filepath) => { const content = fs.readFileSync(filepath, "utf8"); const result = defaultProcessor.processSync(content); @@ -27,12 +28,12 @@ const processFile = filepath => { headers: result.data.headers, signatures: result.data.codeblocks.re, href: path.join(parsedPath.dir, parsedPath.name), - moduleName: result.data.mainHeader + moduleName: result.data.mainHeader, }; return dataset; }; -const createIndex = result => { +const createIndex = (result) => { // Currently we reorder the data to a map, the key is // reflected as the router pathname, as defined by the // NextJS router @@ -40,34 +41,37 @@ const createIndex = result => { const { signatures = [], moduleName, headers } = data; // Sort the headers, but keep type `t` as the first header. - const headersSorted = [...headers].sort( - (headerA, headerB) => { - if (headerA.name === 't') { - return -1 - } else if (headerB.name === 't') { - return 1 - } else { - return headerA.name.localeCompare(headerB.name) - } + const headersSorted = [...headers].sort((headerA, headerB) => { + if (headerA.name === "t") { + return -1; + } else if (headerB.name === "t") { + return 1; + } else { + return headerA.name.localeCompare(headerB.name); } - ); + }); acc["/" + data.href] = { moduleName, - headers: headersSorted + headers: headersSorted, }; return acc; }, {}); }; -const extractApiIndex = version => { +const extractApiIndex = (version) => { const versionLabel = version.replace(/\./g, ""); - const VERSION_DIR = path.join(__dirname, "../pages/docs/manual", version, "api"); + const VERSION_DIR = path.join( + __dirname, + "../pages/docs/manual", + version, + "api", + ); const BELT_MD_DIR = path.join(VERSION_DIR, "belt"); const BELT_INDEX_FILE = path.join( __dirname, - `../index_data/${versionLabel}_belt_api_index.json` + `../index_data/${versionLabel}_belt_api_index.json`, ); const beltFiles = glob.sync(`${BELT_MD_DIR}/*.md?(x)`); const beltResult = beltFiles.map(processFile); @@ -76,7 +80,10 @@ const extractApiIndex = version => { fs.writeFileSync(BELT_INDEX_FILE, JSON.stringify(beltIndex), "utf8"); const JS_MD_DIR = path.join(VERSION_DIR, "js"); - const JS_INDEX_FILE = path.join(__dirname, `../index_data/${versionLabel}_js_api_index.json`); + const JS_INDEX_FILE = path.join( + __dirname, + `../index_data/${versionLabel}_js_api_index.json`, + ); const jsFiles = glob.sync(`${JS_MD_DIR}/*.md?(x)`); const jsResult = jsFiles.map(processFile); const jsIndex = createIndex(jsResult); @@ -85,7 +92,7 @@ const extractApiIndex = version => { const DOM_MD_DIR = path.join(VERSION_DIR, "dom"); const DOM_INDEX_FILE = path.join( __dirname, - `../index_data/${versionLabel}_dom_api_index.json` + `../index_data/${versionLabel}_dom_api_index.json`, ); const domFiles = glob .sync(`${DOM_MD_DIR}/*.md?(x)`) @@ -100,4 +107,3 @@ const extractApiIndex = version => { extractApiIndex("v10.0.0"); extractApiIndex("v9.0.0"); extractApiIndex("v8.0.0"); - diff --git a/scripts/extract-syntax.mjs b/scripts/extract-syntax.mjs index 86aa85cfe..22a3ab362 100644 --- a/scripts/extract-syntax.mjs +++ b/scripts/extract-syntax.mjs @@ -1,42 +1,57 @@ import glob from "glob"; import path from "path"; import fs from "fs"; -import { URL } from 'url'; +import { URL } from "url"; import { defaultProcessor } from "./markdown.js"; -const pathname = new URL('.', import.meta.url).pathname; -const __dirname = process.platform !== 'win32' ? pathname : pathname.substring(1) +const pathname = new URL(".", import.meta.url).pathname; +const __dirname = + process.platform !== "win32" ? pathname : pathname.substring(1); -const processFile = filepath => { +const processFile = (filepath) => { const content = fs.readFileSync(filepath, "utf8"); - const { data: { matter } } = defaultProcessor.processSync(content); + const { + data: { matter }, + } = defaultProcessor.processSync(content); const syntaxPath = path.resolve("./misc_docs/syntax"); const relFilePath = path.relative(syntaxPath, filepath); const parsedPath = path.parse(relFilePath); - if (matter.id && matter.keywords && matter.name && matter.summary && matter.category) { + if ( + matter.id && + matter.keywords && + matter.name && + matter.summary && + matter.category + ) { return { file: parsedPath.name, id: matter.id, keywords: matter.keywords, name: matter.name, summary: matter.summary, - category: matter.category - } + category: matter.category, + }; } - console.error("Metadata missing in " + parsedPath.name + ".mdx") + console.error("Metadata missing in " + parsedPath.name + ".mdx"); return null; }; -const extractSyntax = async version => { +const extractSyntax = async (version) => { const SYNTAX_MD_DIR = path.join(__dirname, "../misc_docs/syntax"); - const SYNTAX_INDEX_FILE = path.join(__dirname, "../index_data/syntax_index.json"); + const SYNTAX_INDEX_FILE = path.join( + __dirname, + "../index_data/syntax_index.json", + ); const syntaxFiles = glob.sync(`${SYNTAX_MD_DIR}/*.md?(x)`); - const syntaxIndex = syntaxFiles.map(processFile).filter(Boolean).sort((a, b) => a.name.localeCompare(b.name)) + const syntaxIndex = syntaxFiles + .map(processFile) + .filter(Boolean) + .sort((a, b) => a.name.localeCompare(b.name)); fs.writeFileSync(SYNTAX_INDEX_FILE, JSON.stringify(syntaxIndex), "utf8"); }; -extractSyntax() +extractSyntax(); diff --git a/scripts/extract-tocs.mjs b/scripts/extract-tocs.mjs index 00055a9f7..ccb770559 100644 --- a/scripts/extract-tocs.mjs +++ b/scripts/extract-tocs.mjs @@ -32,7 +32,7 @@ const orderFiles = (filepaths, orderArr) => { // sidebar json if (filepath == null) { throw new Error( - `Cannot find file for "${name}". Does it exist in the pages folder?` + `Cannot find file for "${name}". Does it exist in the pages folder?`, ); } }); @@ -111,12 +111,12 @@ const createManualToc = (version) => { const SIDEBAR_JSON = path.join( __dirname, - `../data/sidebar_manual_${versionNoDot}.json` + `../data/sidebar_manual_${versionNoDot}.json`, ); const TARGET_FILE = path.join( __dirname, - `../index_data/manual_${versionNoDot}_toc.json` + `../index_data/manual_${versionNoDot}_toc.json`, ); const sidebarJson = JSON.parse(fs.readFileSync(SIDEBAR_JSON)); @@ -139,11 +139,11 @@ const createReactToc = (version) => { const MD_DIR = path.join(__dirname, "../pages/docs/react"); const SIDEBAR_JSON = path.join( __dirname, - `../data/sidebar_react_${versionLabel}.json` + `../data/sidebar_react_${versionLabel}.json`, ); const TARGET_FILE = path.join( __dirname, - `../index_data/react_${versionLabel}_toc.json` + `../index_data/react_${versionLabel}_toc.json`, ); const sidebarJson = JSON.parse(fs.readFileSync(SIDEBAR_JSON)); diff --git a/scripts/figma-fetch.js b/scripts/figma-fetch.js index cbfbcefa7..829354ef6 100644 --- a/scripts/figma-fetch.js +++ b/scripts/figma-fetch.js @@ -16,32 +16,33 @@ */ // Inspect the /files JSON response, or the URL of the Figma page: // https://www.figma.com/file//Some-Name?node-id= -const PAGE_ID = '312:2'; +const PAGE_ID = "312:2"; // Go to a team URL and get the ID: // https://www.figma.com/files/team//Team-Name -const TEAM_ID = '977136127691894995'; +const TEAM_ID = "977136127691894995"; // Get this from the URL of a single file: // https://www.figma.com/file//Some-Name?node-id=182%3A0 -const FILE_KEY = 'FsQT67sVviqPXhYoTbpfIb'; +const FILE_KEY = "FsQT67sVviqPXhYoTbpfIb"; -const fetch = require('node-fetch'); -const fs = require('fs'); -const { promisify } = require('util'); -const path = require('path'); +const fetch = require("node-fetch"); +const fs = require("fs"); +const { promisify } = require("util"); +const path = require("path"); const writeFile = promisify(fs.writeFile); const personalToken = process.env.FIGMA_PERSONAL_TOKEN; if (!personalToken) { - console.error('Please pass FIGMA_PERSONAL_TOKEN to this script and re-run'); - process.exit(1); + console.error("Please pass FIGMA_PERSONAL_TOKEN to this script and re-run"); + process.exit(1); } -const figmaBase = 'https://api.figma.com/'; +const figmaBase = "https://api.figma.com/"; const rgbToHex = (r, g, b) => { - const color = '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); + const color = + "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); if (color.length > 7) { return color.slice(0, 7); @@ -49,35 +50,33 @@ const rgbToHex = (r, g, b) => { return color; }; -const slugify = (str) => str.toLowerCase().replace(/\s+/, '-'); +const slugify = (str) => str.toLowerCase().replace(/\s+/, "-"); const doFetch = (url) => - fetch(`${figmaBase}v1${url}`, { - headers: { - 'X-Figma-Token': personalToken, - }, + fetch(`${figmaBase}v1${url}`, { + headers: { + "X-Figma-Token": personalToken, + }, + }) + .then((res) => { + if (!res.ok) { + throw new Error(`Status: ${res.status}`); + } + + return res.json(); }) - .then((res) => { - if (!res.ok) { - throw new Error(`Status: ${res.status}`); - } - - return res.json(); - }) - .then((json) => { - if (json.error || (json.status && json.status !== 200)) { - throw new Error( - json.error || `Status ${json.status}: ${json.err}` - ); - } - - return json; - }); + .then((json) => { + if (json.error || (json.status && json.status !== 200)) { + throw new Error(json.error || `Status ${json.status}: ${json.err}`); + } + + return json; + }); const fetchStyles = async (teamId) => { - const json = await doFetch(`/teams/${teamId}/styles?page_size=99`); + const json = await doFetch(`/teams/${teamId}/styles?page_size=99`); - return json.meta.styles; + return json.meta.styles; }; const fetchFile = async (key) => await doFetch(`/files/${key}`); @@ -91,21 +90,20 @@ const flattenTree = (root) => { let { children = [] } = root; - for(let i = 0; i < children.length; i++) { + for (let i = 0; i < children.length; i++) { const el = children[i]; const type = el.type; - if(type === "GROUP") { + if (type === "GROUP") { let sub = flattenTree(el); ret = ret.concat(sub); - } - else { - ret.push(el) + } else { + ret.push(el); } } return ret; -} +}; /** * Fetches all color styles from the Figma doc and returns an object @@ -138,35 +136,34 @@ const fetchAllColorStyles = async () => { const root = file.document.children[0]; - if(!root) { - return [] + if (!root) { + return []; } - const canvas = root.children.find((page) =>{ - return page.id === PAGE_ID + const canvas = root.children.find((page) => { + return page.id === PAGE_ID; }); const isRectOrVector = (c) => c.type === "RECTANGLE" || c.type === "VECTOR"; - console.log(JSON.stringify(canvas, null, 2)) + console.log(JSON.stringify(canvas, null, 2)); const allElements = flattenTree(canvas); - return ( - allElements - .filter((c) => isRectOrVector(c) && c.styles != null && c.styles.fill != null) + return allElements + .filter( + (c) => isRectOrVector(c) && c.styles != null && c.styles.fill != null, + ) .map((c) => { - const { r, g, b, a} = c.fills[0].color; + const { r, g, b, a } = c.fills[0].color; const { opacity = a } = c.fills[0]; const nodeId = c.styles.fill; - let color; - if(opacity < 1) { - color = `rgba(${(r*255).toFixed(0)}, ${(g*255).toFixed(0)}, ${(b*255).toFixed(0)}, ${opacity.toFixed(2)})` - } - else { - color = rgbToHex(r * 256, g * 256, b * 256); + if (opacity < 1) { + color = `rgba(${(r * 255).toFixed(0)}, ${(g * 255).toFixed(0)}, ${(b * 255).toFixed(0)}, ${opacity.toFixed(2)})`; + } else { + color = rgbToHex(r * 256, g * 256, b * 256); } return { @@ -176,39 +173,38 @@ const fetchAllColorStyles = async () => { color, }; }) - .filter((c) => c.name != null) - ); + .filter((c) => c.name != null); }; /** * Calls Figma's API and saves to a `colors.js` file in the project root. */ const writeColorsFromFigma = async () => { - const styles = await fetchAllColorStyles(); + const styles = await fetchAllColorStyles(); - if (!styles) { - throw new Error('No styles found'); - } + if (!styles) { + throw new Error("No styles found"); + } + + const colors = styles + .sort((a, b) => (a.sort_position < b.sort_position ? -1 : 1)) + .map((s) => { + return ( + (s.description ? ` /** ${s.description} */\n` : "") + + ` '${slugify(s.name)}': '${s.color}',` + ); + }) + .join("\n"); - const colors = styles - .sort((a, b) => (a.sort_position < b.sort_position ? -1 : 1)) - .map( - (s) => { - return (s.description ? ` /** ${s.description} */\n` : '') + - ` '${slugify(s.name)}': '${s.color}',` - } - ) - .join('\n'); - - const fileContents = `/* eslint-disable */ + const fileContents = `/* eslint-disable */ /* Updated at ${new Date().toUTCString()}*/ module.exports = { ${colors} }`; - await writeFile(path.resolve(__dirname + '/../colors.js'), fileContents); + await writeFile(path.resolve(__dirname + "/../colors.js"), fileContents); - console.log(`Wrote ${styles.length} colors to colors.js`); + console.log(`Wrote ${styles.length} colors to colors.js`); }; writeColorsFromFigma().catch(console.error); diff --git a/scripts/markdown.js b/scripts/markdown.js index 0d5584733..5e13cd52f 100644 --- a/scripts/markdown.js +++ b/scripts/markdown.js @@ -7,15 +7,15 @@ import rehypeSlug from "rehype-slug"; import rehypeStringify from "rehype-stringify"; import { matter } from "vfile-matter"; -const remarkVfileMatter = options => (tree, file) => { +const remarkVfileMatter = (options) => (tree, file) => { matter(file); }; -const remarkCodeblocks = options => (tree, file) => { +const remarkCodeblocks = (options) => (tree, file) => { const { children } = tree; const codeblocks = {}; - const formatter = value => { + const formatter = (value) => { // Strip newlines and weird spacing return value .replace(/\n/g, " ") @@ -24,7 +24,7 @@ const remarkCodeblocks = options => (tree, file) => { .replace(/\s+\)/g, ")"); }; - children.forEach(child => { + children.forEach((child) => { if (child.type === "code" && child.value) { const { meta, lang } = child; if (meta === "sig" && lang === "re") { @@ -39,19 +39,19 @@ const remarkCodeblocks = options => (tree, file) => { Object.assign(file.data, { codeblocks }); }; -const rehypeHeaders = options => (tree, file) => { +const rehypeHeaders = (options) => (tree, file) => { const headers = []; let mainHeader; - tree.children.forEach(child => { + tree.children.forEach((child) => { if (child.tagName === "h1") { if (child.children.length > 0) { - mainHeader = child.children.map(element => element.value).join(""); + mainHeader = child.children.map((element) => element.value).join(""); } } if (child.tagName === "h2") { if (child.children.length > 0) { const id = child.properties.id || ""; - const name = child.children.map(element => element.value).join(""); + const name = child.children.map((element) => element.value).join(""); headers.push({ name, href: id }); } } @@ -63,7 +63,7 @@ const rehypeHeaders = options => (tree, file) => { export const defaultProcessor = unified() .use(remarkParse) .use(remarkGfm) - .use(remarkFrontmatter, [{ type: 'yaml', marker: '-' }]) + .use(remarkFrontmatter, [{ type: "yaml", marker: "-" }]) .use(remarkVfileMatter) .use(remarkCodeblocks) .use(remarkRehype) diff --git a/scripts/sync-playground-bundles.mjs b/scripts/sync-playground-bundles.mjs index da9850862..c9106ae2a 100644 --- a/scripts/sync-playground-bundles.mjs +++ b/scripts/sync-playground-bundles.mjs @@ -6,11 +6,15 @@ import * as stream from "node:stream/promises"; const bucketUrl = new URL("https://cdn.rescript-lang.org"); -const bundlesDir = path.join(import.meta.dirname, "../public/playground-bundles"); +const bundlesDir = path.join( + import.meta.dirname, + "../public/playground-bundles", +); fs.mkdirSync(bundlesDir, { recursive: true }); -const versions = await fetch(new URL("/playground-bundles/versions.json", bucketUrl)) - .then(res => res.json()); +const versions = await fetch( + new URL("/playground-bundles/versions.json", bucketUrl), +).then((res) => res.json()); for (const version of versions) { const versionDir = path.join(bundlesDir, version); @@ -23,7 +27,9 @@ for (const version of versions) { console.group(`Syncing %s...`, version); { console.log(`Downloading archive file...`); - const res = await fetch(new URL(`/playground-bundles/${version}.tar.zst`, bucketUrl)); + const res = await fetch( + new URL(`/playground-bundles/${version}.tar.zst`, bucketUrl), + ); if (!res.ok) { console.error(await res.text()); continue; diff --git a/scripts/sync-redirects.mjs b/scripts/sync-redirects.mjs index 566d842bc..356897b1c 100644 --- a/scripts/sync-redirects.mjs +++ b/scripts/sync-redirects.mjs @@ -10,14 +10,10 @@ const redirectsConfig = await nextConfig.redirects(); * source: string, * destination: string, * permanent: boolean, - * }} config + * }} config * @return {string} */ -function lineFormat({ - source, - destination, - permanent, -}) { +function lineFormat({ source, destination, permanent }) { return `${source} ${destination} ${permanent ? 308 : 307}`; } diff --git a/scripts/test-examples.mjs b/scripts/test-examples.mjs index f7acca969..23827c08b 100644 --- a/scripts/test-examples.mjs +++ b/scripts/test-examples.mjs @@ -2,123 +2,167 @@ import glob from "glob"; import fs from "fs"; import child_process from "child_process"; import path from "path"; -import { URL } from 'url'; +import { URL } from "url"; -const pathname = new URL('.', import.meta.url).pathname; -const __dirname = process.platform !== 'win32' ? pathname : pathname.substring(1) +const pathname = new URL(".", import.meta.url).pathname; +const __dirname = + process.platform !== "win32" ? pathname : pathname.substring(1); -let tempFileName = path.join(__dirname, '..', '_tempFile.res') -let tempFileNameRegex = /_tempFile\.res/g +let tempFileName = path.join(__dirname, "..", "_tempFile.res"); +let tempFileNameRegex = /_tempFile\.res/g; // TODO: In the future we need to use the appropriate rescript version for each doc version variant // see the package.json on how to define another rescript version -let compilersDir = path.join(__dirname, "..", "compilers") - -let bsc = path.join(compilersDir, 'node_modules', 'rescript-1110', process.platform, 'bsc.exe'); -let rescriptBin = path.join(compilersDir, 'node_modules', 'rescript-1110', 'rescript'); -let rescriptCoreCompiled = path.join(compilersDir, 'node_modules', '@rescript', 'core', 'lib', 'ocaml'); -let rescriptReactCompiled = path.join(compilersDir, 'node_modules', '@rescript', 'react', 'lib', 'ocaml'); +let compilersDir = path.join(__dirname, "..", "compilers"); + +let bsc = path.join( + compilersDir, + "node_modules", + "rescript-1110", + process.platform, + "bsc.exe", +); +let rescriptBin = path.join( + compilersDir, + "node_modules", + "rescript-1110", + "rescript", +); +let rescriptCoreCompiled = path.join( + compilersDir, + "node_modules", + "@rescript", + "core", + "lib", + "ocaml", +); +let rescriptReactCompiled = path.join( + compilersDir, + "node_modules", + "@rescript", + "react", + "lib", + "ocaml", +); const prepareCompilers = () => { if (fs.existsSync(bsc)) { return; } console.log("compilers not installed. Installing compilers..."); - child_process.execFileSync("npm", ['install'], {cwd: compilersDir}) -} + child_process.execFileSync("npm", ["install"], { cwd: compilersDir }); +}; const prepareDependencies = () => { - if (fs.existsSync(rescriptCoreCompiled) && fs.existsSync(rescriptReactCompiled)) { + if ( + fs.existsSync(rescriptCoreCompiled) && + fs.existsSync(rescriptReactCompiled) + ) { return; } console.log("Dependencies not installed. Installing..."); - child_process.execFileSync(rescriptBin, [], {cwd: compilersDir}) -} + child_process.execFileSync(rescriptBin, [], { cwd: compilersDir }); +}; -let parseFile = content => { +let parseFile = (content) => { if (!/```res (example|prelude|sig)/.test(content)) { - return + return; } - let inCodeBlock = false - let moduleId = 0 - return content.split('\n').map(line => { - let modifiedLine = '' - if (line.startsWith('```res example')) { - inCodeBlock = true - modifiedLine = `/* _MODULE_EXAMPLE_START */ module M_${moduleId++} = {` - } else if (line.startsWith('```res prelude')) { - inCodeBlock = true - modifiedLine = `/* _MODULE_PRELUDE_START */ include {` - } else if (line.startsWith('```res sig')) { - inCodeBlock = true - modifiedLine = `/* _MODULE_SIG_START */ module type M_${moduleId++} = {` - } else if (inCodeBlock) { - if (line.startsWith('```')) { - inCodeBlock = false - modifiedLine = '} // _MODULE_END' - } else { - modifiedLine = line + let inCodeBlock = false; + let moduleId = 0; + return content + .split("\n") + .map((line) => { + let modifiedLine = ""; + if (line.startsWith("```res example")) { + inCodeBlock = true; + modifiedLine = `/* _MODULE_EXAMPLE_START */ module M_${moduleId++} = {`; + } else if (line.startsWith("```res prelude")) { + inCodeBlock = true; + modifiedLine = `/* _MODULE_PRELUDE_START */ include {`; + } else if (line.startsWith("```res sig")) { + inCodeBlock = true; + modifiedLine = `/* _MODULE_SIG_START */ module type M_${moduleId++} = {`; + } else if (inCodeBlock) { + if (line.startsWith("```")) { + inCodeBlock = false; + modifiedLine = "} // _MODULE_END"; + } else { + modifiedLine = line; + } } - } - return modifiedLine - }).join('\n') -} + return modifiedLine; + }) + .join("\n"); +}; let postprocessOutput = (file, error) => { - return error.stderr.toString() - .replace(tempFileNameRegex, path.relative('.', file)) - .replace(/\/\* _MODULE_(EXAMPLE|PRELUDE|SIG)_START \*\/.+/g, (_, capture) => { - return '```res ' + (capture === 'EXAMPLE' ? 'example' : capture === 'PRELUDE' ? 'prelude' : 'sig') - }) + return error.stderr + .toString() + .replace(tempFileNameRegex, path.relative(".", file)) + .replace( + /\/\* _MODULE_(EXAMPLE|PRELUDE|SIG)_START \*\/.+/g, + (_, capture) => { + return ( + "```res " + + (capture === "EXAMPLE" + ? "example" + : capture === "PRELUDE" + ? "prelude" + : "sig") + ); + }, + ) .replace(/(.*)\}(.*)\/\/ _MODULE_END/g, (_, cap1, cap2) => { // cap1 cap2 might be empty or ansi coloring code - return cap1 + '```' + cap2 - }) -} - + return cap1 + "```" + cap2; + }); +}; prepareCompilers(); prepareDependencies(); -console.log("Running tests...") -fs.writeFileSync(tempFileName, '') - -let success = true - -glob.sync(__dirname + '/../pages/docs/{manual/latest,react/latest}/**/*.mdx').forEach((file) => { - let content = fs.readFileSync(file, {encoding: 'utf-8'}) - let parsedResult = parseFile(content) - if (parsedResult != null) { - fs.writeFileSync(tempFileName, parsedResult) - try { - // -109 for suppressing `Toplevel expression is expected to have unit type.` - // Most doc snippets do e.g. `Belt.Array.length(["test"])`, which triggers this - child_process.execFileSync( - bsc, - [ - tempFileName, - '-I', - rescriptCoreCompiled, - '-I', - rescriptReactCompiled, - '-bs-jsx', - '4', - '-w', - '-109', - '-uncurried', - '-open', - 'RescriptCore', - ], - { stdio: "pipe" } - ); - } catch (e) { - process.stdout.write(postprocessOutput(file, e)) - success = false +console.log("Running tests..."); +fs.writeFileSync(tempFileName, ""); + +let success = true; + +glob + .sync(__dirname + "/../pages/docs/{manual/latest,react/latest}/**/*.mdx") + .forEach((file) => { + let content = fs.readFileSync(file, { encoding: "utf-8" }); + let parsedResult = parseFile(content); + if (parsedResult != null) { + fs.writeFileSync(tempFileName, parsedResult); + try { + // -109 for suppressing `Toplevel expression is expected to have unit type.` + // Most doc snippets do e.g. `Belt.Array.length(["test"])`, which triggers this + child_process.execFileSync( + bsc, + [ + tempFileName, + "-I", + rescriptCoreCompiled, + "-I", + rescriptReactCompiled, + "-bs-jsx", + "4", + "-w", + "-109", + "-uncurried", + "-open", + "RescriptCore", + ], + { stdio: "pipe" }, + ); + } catch (e) { + process.stdout.write(postprocessOutput(file, e)); + success = false; + } } - } -}) + }); -fs.unlinkSync(tempFileName) -process.exit(success ? 0 : 1) +fs.unlinkSync(tempFileName); +process.exit(success ? 0 : 1); diff --git a/scripts/test-hrefs.mjs b/scripts/test-hrefs.mjs index 11c744cc8..075b8dd6e 100644 --- a/scripts/test-hrefs.mjs +++ b/scripts/test-hrefs.mjs @@ -6,25 +6,26 @@ * the website. */ -import { config } from "dotenv" +import { config } from "dotenv"; import glob from "glob"; import path from "path"; import fs from "fs"; import urlModule from "url"; -import { URL } from 'url'; -import { getAllPosts, blogPathToSlug } from '../src/common/BlogApi.mjs' +import { URL } from "url"; +import { getAllPosts, blogPathToSlug } from "../src/common/BlogApi.mjs"; import { defaultProcessor } from "./markdown.js"; -config() +config(); -let latestVersion = process.env.VERSION_LATEST -let nextVersion = process.env.VERSION_NEXT +let latestVersion = process.env.VERSION_LATEST; +let nextVersion = process.env.VERSION_NEXT; -const pathname = new URL('.', import.meta.url).pathname; -const __dirname = process.platform !== 'win32' ? pathname : pathname.substring(1) +const pathname = new URL(".", import.meta.url).pathname; +const __dirname = + process.platform !== "win32" ? pathname : pathname.substring(1); -const mapBlogFilePath = path => { +const mapBlogFilePath = (path) => { const match = path.match(/\.\/_blogposts\/(.*\.mdx)/); if (match) { @@ -40,26 +41,24 @@ const mapBlogFilePath = path => { // Static files are located in /public/static/img/somefile.png // within markdown files they are referenced as /static/img/somefile.png -const mapStaticFilePath = path => { +const mapStaticFilePath = (path) => { return path.replace("./public", ""); -} +}; // Creates a lookup table of all available pages within the website // It will also automatically map urls for dedicated directorys (such as _blogposts) // to the correct url // { key=url: value=original_filepath} -const createPageIndex = files => { +const createPageIndex = (files) => { return files.reduce((acc, path) => { // We need to consider all the different file formats used in pages // Calculate the website url by stripping .re, .bs.js, .md(x), etc. let url; if (path.startsWith("./_blogposts")) { - url = mapBlogFilePath(path) - } - else if (path.startsWith("./public/static")) { + url = mapBlogFilePath(path); + } else if (path.startsWith("./public/static")) { url = mapStaticFilePath(path); - } - else { + } else { url = path; } @@ -75,7 +74,7 @@ const createPageIndex = files => { }, {}); }; -const flattenChildren = children => { +const flattenChildren = (children) => { return children.reduce((acc, node) => { if (node.type === "link") { return acc.concat([node]); @@ -88,7 +87,7 @@ const flattenChildren = children => { }; // Finds all relative links within a file -const hrefs = options => (tree, file) => { +const hrefs = (options) => (tree, file) => { const links = flattenChildren(tree.children); file.data = Object.assign({}, file.data, { links }); @@ -96,7 +95,7 @@ const hrefs = options => (tree, file) => { const processor = defaultProcessor.use(hrefs); -const processFile = filepath => { +const processFile = (filepath) => { const content = fs.readFileSync(filepath, "utf8"); const result = processor.processSync(content); @@ -105,27 +104,34 @@ const processFile = filepath => { return result.data; }; -const showErrorMsg = failedTest => { +const showErrorMsg = (failedTest) => { const { stderr } = failedTest; console.log(`\n-----------\nError Preview:`); console.log(stderr); }; -const createApiIndexModules = version => { +const createApiIndexModules = (version) => { const dir = path.join(__dirname, "..", "data", "api", version); - const modules = fs.readdirSync(dir).filter(file => file !== "toc_tree.json"); + const modules = fs + .readdirSync(dir) + .filter((file) => file !== "toc_tree.json"); const paths = modules.reduce((acc, file) => { const json = JSON.parse(fs.readFileSync(path.join(dir, file))); const keys = Object.keys(json); - const paths = keys.map(modulePath => path.join(version, "api", modulePath)); + const paths = keys.map((modulePath) => + path.join(version, "api", modulePath), + ); return acc.concat(paths); }, []); return [`${version}/api`, ...paths]; }; -const apiIndexModules = [...createApiIndexModules(latestVersion), ...createApiIndexModules(nextVersion)] +const apiIndexModules = [ + ...createApiIndexModules(latestVersion), + ...createApiIndexModules(nextVersion), +]; const testFile = (pageMap, test) => { const filepath = test.filepath; @@ -133,7 +139,7 @@ const testFile = (pageMap, test) => { // Used for storing failed / ok hrefs const results = []; - test.links.forEach(link => { + test.links.forEach((link) => { // Simulate the redirect of "latest" and "next" version aliases. if (link.url.includes("/manual/latest/")) { link.url = link.url.replace("/latest/", `/${latestVersion}/`); @@ -176,20 +182,16 @@ const testFile = (pageMap, test) => { let resolved; if (!path.isAbsolute(url)) { resolved = path.join("/", path.dirname(filepath), parsed.pathname); - } - else { + } else { if (parsed.pathname.startsWith("/static")) { console.log("Static"); resolved = path.join(parsed.pathname); - } - else { + } else { // e.g. /api/javascript/latest/js needs to be prefixed to actual pages dir resolved = path.join("/pages", parsed.pathname); } } - - if ( resolved.startsWith(`/pages/docs/manual/${latestVersion}/api`) || resolved.startsWith(`/pages/docs/manual/${nextVersion}/api`) @@ -200,7 +202,7 @@ const testFile = (pageMap, test) => { if (pathExists) { results.push({ status: "ok", - link + link, }); } else { const { line, column } = link.position.start; @@ -209,7 +211,7 @@ const testFile = (pageMap, test) => { status: "failed", filepath, stderr, - link + link, }); } return; @@ -223,7 +225,7 @@ const testFile = (pageMap, test) => { status: "failed", filepath, stderr, - link + link, }); return; } @@ -231,20 +233,20 @@ const testFile = (pageMap, test) => { results.push({ status: "ok", - link + link, }); }); if (results.length > 0) { console.log(`\n-------Results for '${filepath}'----------`); - results.forEach(r => { + results.forEach((r) => { const { status } = r; const { line, column } = r.link.position.start; if (status === "failed") { console.log( - `${filepath}:${line} => ${status} / Unknown href '${r.link.url}' in line ${line}:${column}` + `${filepath}:${line} => ${status} / Unknown href '${r.link.url}' in line ${line}:${column}`, ); } else { console.log(`${filepath}:${line} => ${status}`); @@ -254,7 +256,7 @@ const testFile = (pageMap, test) => { return { data: test, - results + results, }; }; @@ -265,12 +267,14 @@ const main = () => { // All files that are going to be tested for broken links const files = glob.sync( pattern ? pattern : `./{pages,_blogposts,misc_docs}/**/*.md?(x)`, - { cwd } + { cwd }, ); // We need to capture all files independently from the test file glob const pageMapFiles = glob.sync("./{pages,_blogposts}/**/*.{js,mdx}", { cwd }); - const staticFiles = glob.sync("./public/static/**/*.{svg,png,woff2}", { cwd }); + const staticFiles = glob.sync("./public/static/**/*.{svg,png,woff2}", { + cwd, + }); const allFiles = pageMapFiles.concat(staticFiles); @@ -278,14 +282,14 @@ const main = () => { const processedFiles = files.map(processFile); - const allTested = processedFiles.map(file => testFile(pageMap, file)); + const allTested = processedFiles.map((file) => testFile(pageMap, file)); const failed = allTested.reduce((acc, test) => { - return acc.concat(test.results.filter(r => r.status === "failed")); + return acc.concat(test.results.filter((r) => r.status === "failed")); }, []); const success = allTested.reduce((acc, test) => { - return acc.concat(test.results.filter(r => r.status === "ok")); + return acc.concat(test.results.filter((r) => r.status === "ok")); }, []); console.log("-----------\nSummary:"); @@ -295,7 +299,7 @@ const main = () => { if (failed.length > 0) { console.log( - `\nTip: You can also run tests just for specific files / globs:` + `\nTip: You can also run tests just for specific files / globs:`, ); console.log('`node scripts/test-hrefs.js "pages/**/*.mdx"`'); showErrorMsg(failed[0]); diff --git a/src/ffi/loadScript.js b/src/ffi/loadScript.js index fe79fa3ea..dca71e6ff 100644 --- a/src/ffi/loadScript.js +++ b/src/ffi/loadScript.js @@ -1,5 +1,5 @@ const isBrowser = - typeof window !== 'undefined' && typeof window.document !== 'undefined'; + typeof window !== "undefined" && typeof window.document !== "undefined"; export default function loadScript(src, onSuccess, onError) { if (!isBrowser) return; @@ -22,5 +22,5 @@ export function removeScript(src) { const existing = document.body.querySelectorAll(`script[src="${src}"]`); existing.forEach((el) => { document.body.removeChild(el); - }) + }); } diff --git a/src/ffi/react-codemirror-hooks.js b/src/ffi/react-codemirror-hooks.js index d7b824cf2..9b5f14093 100644 --- a/src/ffi/react-codemirror-hooks.js +++ b/src/ffi/react-codemirror-hooks.js @@ -2,7 +2,7 @@ // OBSOLETE! // // This file is reimplemented in common/CodeMirrorBase.re -// We keep this around for reference in case we find some +// We keep this around for reference in case we find some // bugs in the new implementation // import CodeMirror from "codemirror"; @@ -103,7 +103,7 @@ export default function CodeMirrorReact(props) { const cm = CodeMirror.fromTextArea(inputElement.current, { theme: "material", gutters: [ERROR_GUTTER_ID, "CodeMirror-linenumbers"], - ...options + ...options, }); cm.getScrollerElement().style.minHeight = props.minHeight; diff --git a/styles/_docsearch.css b/styles/_docsearch.css index 933a2614a..eb2debc9b 100644 --- a/styles/_docsearch.css +++ b/styles/_docsearch.css @@ -48,7 +48,7 @@ background-color: rgba(0, 0, 0, 0.2); backdrop-filter: blur(0px); cursor: inherit !important; - transition: all .05s ease; + transition: all 0.05s ease; @apply fixed top-0 left-0 flex flex-col; } @@ -71,7 +71,7 @@ @apply relative min-h-0 mx-auto bg-white w-full flex flex-col shadow-lg max-w-(--breakpoint-md) rounded-lg; transform: scale(0.95); opacity: 0; - transition: all .2s ease; + transition: all 0.2s ease; } .DocSearch--active { @@ -213,11 +213,11 @@ @apply text-gray-40 opacity-50 stroke-2 w-5 h-7; } -.DocSearch-Hit[aria-selected='true'] a { +.DocSearch-Hit[aria-selected="true"] a { @apply bg-gray-20; } -.DocSearch-Hit[aria-selected='true'] mark { +.DocSearch-Hit[aria-selected="true"] mark { text-decoration: none; } @@ -250,7 +250,7 @@ svg.DocSearch-Hit-Select-Icon { display: none; } -.DocSearch-Hit[aria-selected='true'] .DocSearch-Hit-Select-Icon { +.DocSearch-Hit[aria-selected="true"] .DocSearch-Hit-Select-Icon { display: block; } @@ -271,13 +271,13 @@ svg.DocSearch-Hit-Select-Icon { @apply text-12; } -.DocSearch-Hit[aria-selected='true'] .DocSearch-Hit-title, -.DocSearch-Hit[aria-selected='true'] mark, -.DocSearch-Hit[aria-selected='true'] .DocSearch-Hit-text, -.DocSearch-Hit[aria-selected='true'] .DocSearch-Hit-path, -.DocSearch-Hit[aria-selected='true'] .DocSearch-Hit-icon, -.DocSearch-Hit[aria-selected='true'] .DocSearch-Hit-action, -.DocSearch-Hit[aria-selected='true'] .DocSearch-Hit-Tree { +.DocSearch-Hit[aria-selected="true"] .DocSearch-Hit-title, +.DocSearch-Hit[aria-selected="true"] mark, +.DocSearch-Hit[aria-selected="true"] .DocSearch-Hit-text, +.DocSearch-Hit[aria-selected="true"] .DocSearch-Hit-path, +.DocSearch-Hit[aria-selected="true"] .DocSearch-Hit-icon, +.DocSearch-Hit[aria-selected="true"] .DocSearch-Hit-action, +.DocSearch-Hit[aria-selected="true"] .DocSearch-Hit-Tree { color: none; } diff --git a/styles/_fonts.css b/styles/_fonts.css index 663335621..0013e4b3e 100644 --- a/styles/_fonts.css +++ b/styles/_fonts.css @@ -26,79 +26,114 @@ $ pyftsubset --unicodes="U+0000-00FF, U+0131, U+0152-0153, U+02BB /* latin */ @font-face { - font-family: 'Inter'; - src: local('Inter Bold'), local('Inter-Bold'), - url('/static/fonts/subset-Inter-Bold.woff2') format('woff2'); - font-weight: 700; - font-style: normal; - font-display: swap; - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; + font-family: "Inter"; + src: + local("Inter Bold"), + local("Inter-Bold"), + url("/static/fonts/subset-Inter-Bold.woff2") format("woff2"); + font-weight: 700; + font-style: normal; + font-display: swap; + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, + U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, + U+FFFD; } /* latin */ @font-face { - font-family: 'Inter'; - src: local('Inter Italic'), local('Inter-Italic'), - url('/static/fonts/subset-Inter-Italic.woff2') format('woff2'); - font-weight: 400; - font-style: italic; - font-display: swap; - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; + font-family: "Inter"; + src: + local("Inter Italic"), + local("Inter-Italic"), + url("/static/fonts/subset-Inter-Italic.woff2") format("woff2"); + font-weight: 400; + font-style: italic; + font-display: swap; + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, + U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, + U+FFFD; } /* latin */ @font-face { - font-family: 'Inter'; - src: local('Inter Medium'), local('Inter-Medium'), - url('/static/fonts/subset-Inter-Medium.woff2') format('woff2'); - font-weight: 500; - font-style: normal; - font-display: swap; - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; + font-family: "Inter"; + src: + local("Inter Medium"), + local("Inter-Medium"), + url("/static/fonts/subset-Inter-Medium.woff2") format("woff2"); + font-weight: 500; + font-style: normal; + font-display: swap; + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, + U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, + U+FFFD; } /* latin */ @font-face { - font-family: 'Inter'; - src: local('Inter Semi Bold'), local('Inter-SemiBold'), - url('/static/fonts/subset-Inter-SemiBold.woff2') format('woff2'); - font-weight: 600; - font-style: normal; - font-display: swap; - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; + font-family: "Inter"; + src: + local("Inter Semi Bold"), + local("Inter-SemiBold"), + url("/static/fonts/subset-Inter-SemiBold.woff2") format("woff2"); + font-weight: 600; + font-style: normal; + font-display: swap; + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, + U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, + U+FFFD; } /* latin */ @font-face { - font-family: 'Inter'; - src: local('Inter Regular'), local('Inter-Regular'), - url('/static/fonts/subset-Inter-Regular.woff2') format('woff2'); - font-weight: 400; - font-style: normal; - font-display: swap; - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; + font-family: "Inter"; + src: + local("Inter Regular"), + local("Inter-Regular"), + url("/static/fonts/subset-Inter-Regular.woff2") format("woff2"); + font-weight: 400; + font-style: normal; + font-display: swap; + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, + U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, + U+FFFD; } - - /* ROBOTO MONO */ /* latin */ @font-face { - font-family: 'Roboto Mono'; + font-family: "Roboto Mono"; font-style: normal; font-weight: 400; font-display: swap; - src: local('Roboto Mono'), local('RobotoMono-Regular'), url(/static/fonts/roboto-mono-400.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; + src: + local("Roboto Mono"), + local("RobotoMono-Regular"), + url(/static/fonts/roboto-mono-400.woff2) format("woff2"); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, + U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, + U+FFFD; } /* latin */ @font-face { - font-family: 'Roboto Mono'; + font-family: "Roboto Mono"; font-style: bold; font-weight: 700; font-display: swap; - src: local('Roboto Mono Bold'), local('RobotoMono-Bold'), url(/static/fonts/roboto-mono-700.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; + src: + local("Roboto Mono Bold"), + local("RobotoMono-Bold"), + url(/static/fonts/roboto-mono-700.woff2) format("woff2"); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, + U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, + U+FFFD; } diff --git a/styles/_hljs.css b/styles/_hljs.css index 89dcb5b73..21ea1a9f2 100644 --- a/styles/_hljs.css +++ b/styles/_hljs.css @@ -5,7 +5,7 @@ Docco style used in http://jashkenas.github.com/docco/ converted by Simon Madine /* purgecss start ignore */ .hljs { display: block; - + /*overflow-x: auto;*/ /*background: #f8f8ff;*/ } @@ -15,7 +15,8 @@ Docco style used in http://jashkenas.github.com/docco/ converted by Simon Madine font-style: italic; } -.hljs-operator, .hljs-literal { +.hljs-operator, +.hljs-literal { @apply text-water; } @@ -101,11 +102,11 @@ Docco style used in http://jashkenas.github.com/docco/ converted by Simon Madine } .hljs-function { - color: #8AAEC8; + color: #8aaec8; } .hljs-module-identifier { - @apply text-water + @apply text-water; } /* tweaks to syntax highlighting, assuming atom-one-light theme */ @@ -115,28 +116,31 @@ Docco style used in http://jashkenas.github.com/docco/ converted by Simon Madine } .hljs-constructor { -@apply text-orange + @apply text-orange; } /* DARK MODE COLORS */ .hljs.dark { - @apply text-gray-30 + @apply text-gray-30; } .hljs.dark .hljs-module-identifier { - @apply text-fire-dark + @apply text-fire-dark; } .hljs.dark .hljs-comment { - color: #546E7A; + color: #546e7a; } -.hljs.dark .hljs-operator, .hljs.dark .hljs-literal { +.hljs.dark .hljs-operator, +.hljs.dark .hljs-literal { @apply text-ocean-dark; } -.hljs.dark .hljs-tag, .hljs.dark .hljs-name, .hljs.dark .hljs-attribute { +.hljs.dark .hljs-tag, +.hljs.dark .hljs-name, +.hljs.dark .hljs-attribute { @apply text-water-dark; font-weight: normal; } diff --git a/styles/_markdown.css b/styles/_markdown.css index 18bf4100b..72f6b9e2e 100644 --- a/styles/_markdown.css +++ b/styles/_markdown.css @@ -1,12 +1,13 @@ /* Markdown related stuff */ /* Sometimes we cannot circumvent the cascade, especially for nested lists */ -.md-ul, .md-ol { +.md-ul, +.md-ol { @apply mb-8; } .md-ul ul { - @apply mb-0 ; + @apply mb-0; } .md-ol > li { @@ -22,12 +23,12 @@ @apply absolute font-semibold; } -.md-ul > .md-li::before{ +.md-ul > .md-li::before { content: "•"; @apply absolute; } -.md-ul > .md-li > ul > li::before{ +.md-ul > .md-li > ul > li::before { content: "—"; @apply absolute; } @@ -51,15 +52,15 @@ /* INFOBOX (Markdown.res) Find a better solution for

text inside of Info-Box (Markdown)? */ .infobox > p { @apply text-14 mt-0; -} +} .infobox > .md-p { @apply mt-0; } -.infobox >p >a { +.infobox > p > a { @apply underline text-current; } -.infobox >p >a:hover { +.infobox > p > a:hover { @apply no-underline text-current text-gray-70; } diff --git a/styles/_theme.css b/styles/_theme.css index f86870a6b..91973263d 100644 --- a/styles/_theme.css +++ b/styles/_theme.css @@ -1,11 +1,11 @@ /* purgecss start ignore */ .theme-reason { - --color-text-primary-dark: theme('colors.fire.DEFAULT'); - --color-text-primary: theme('colors.fire.DEFAULT'); - --color-text-primary-light: theme('colors.fire.DEFAULT'); - --color-text-primary-80: theme('colors.fire.90'); - --color-text-primary-40: theme('colors.fire.50'); - --color-text-primary-15: theme('colors.fire.10'); + --color-text-primary-dark: theme("colors.fire.DEFAULT"); + --color-text-primary: theme("colors.fire.DEFAULT"); + --color-text-primary-light: theme("colors.fire.DEFAULT"); + --color-text-primary-80: theme("colors.fire.90"); + --color-text-primary-40: theme("colors.fire.50"); + --color-text-primary-15: theme("colors.fire.10"); } .list-fire li::before { diff --git a/styles/docson.css b/styles/docson.css index 1627e741c..2ed6c7ee2 100644 --- a/styles/docson.css +++ b/styles/docson.css @@ -15,462 +15,474 @@ */ .docson { - font-family: 'Droid Sans',verdana,helvetica; - font-size: 13px; - padding: 6px 6px 6px 6px; + font-family: "Droid Sans", verdana, helvetica; + font-size: 13px; + padding: 6px 6px 6px 6px; } .docson .box { - position: relative; - float: left; - background-color:rgba(255, 255, 255, 0.2); - border: 1px solid lightgrey; - border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - padding-bottom: 10px; - -moz-box-shadow: 1px 1px 1px darkgray; - -webkit-box-shadow: 1px 1px 1px darkgray; - box-shadow: 1px 1px 1px darkgray; + position: relative; + float: left; + background-color: rgba(255, 255, 255, 0.2); + border: 1px solid lightgrey; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + padding-bottom: 10px; + -moz-box-shadow: 1px 1px 1px darkgray; + -webkit-box-shadow: 1px 1px 1px darkgray; + box-shadow: 1px 1px 1px darkgray; } .docson .expand-button { - position: absolute; - margin-top: 15px; - padding: 2px; - right: 2px; - float: right; - width: 18px; - text-align: center; - cursor: pointer; - font-weight: bold; - font-family: "Lucida Console", Monaco, monospace; - font-size: 15px; - color: darkgray; - display: none; + position: absolute; + margin-top: 15px; + padding: 2px; + right: 2px; + float: right; + width: 18px; + text-align: center; + cursor: pointer; + font-weight: bold; + font-family: "Lucida Console", Monaco, monospace; + font-size: 15px; + color: darkgray; + display: none; } .docson .source-button { - position: absolute; - padding: 2px; - margin-top: 3px; - right: 2px; - width: 18px; - text-align: center; - cursor: pointer; - font-weight: bold; - font-family: "Lucida Console", Monaco, monospace; - font-size: 10px; - color: darkgray; - display: none; + position: absolute; + padding: 2px; + margin-top: 3px; + right: 2px; + width: 18px; + text-align: center; + cursor: pointer; + font-weight: bold; + font-family: "Lucida Console", Monaco, monospace; + font-size: 10px; + color: darkgray; + display: none; } .docson .box-header { - padding: 6px; - border-top-left-radius: 4px; - border-top-right-radius: 4px; - border-bottom: 1px solid lightgrey; - background: whitesmoke; - /* background: -webkit-linear-gradient(ghostwhite, whitesmoke, whitesmoke, gainsboro); + padding: 6px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom: 1px solid lightgrey; + background: whitesmoke; + /* background: -webkit-linear-gradient(ghostwhite, whitesmoke, whitesmoke, gainsboro); background: -moz-linear-gradient(ghostwhite, whitesmoke, whitesmoke, gainsboro);*/ } .docson .box-name { - color: darkblue; - padding: 5px 40px 2px 3px; - float: left; + color: darkblue; + padding: 5px 40px 2px 3px; + float: left; } .docson .title { - margin-top: -3px; - font-size: 120%; + margin-top: -3px; + font-size: 120%; } .docson .link { - text-decoration: underline; + text-decoration: underline; } .docson .box-description { - color: dimgray; - float: left; - max-width: 600px; + color: dimgray; + float: left; + max-width: 600px; } .docson .end { - clear: both; + clear: both; } .docson .error { - color: red; + color: red; } .docson .box-body { - padding-left: 10px; - padding-right: 28px; - clear: both; + padding-left: 10px; + padding-right: 28px; + clear: both; } .docson .box-1 { - background: whitesmoke;/* + background: whitesmoke; /* background: -webkit-linear-gradient(ghostwhite, whitesmoke, whitesmoke, gainsboro); background: -moz-linear-gradient(ghostwhite, whitesmoke, whitesmoke, gainsboro);*/ } .docson .box-2 { - background: beige; - background: -webkit-linear-gradient(white, beige, beige, gainsboro); - background: -moz-linear-gradient(white, beige, beige, gainsboro); + background: beige; + background: -webkit-linear-gradient(white, beige, beige, gainsboro); + background: -moz-linear-gradient(white, beige, beige, gainsboro); } .docson .box-3 { - background: azure; - background: -webkit-linear-gradient(white, azure, azure, gainsboro); - background: -moz-linear-gradient(white, azure, azure, gainsboro); + background: azure; + background: -webkit-linear-gradient(white, azure, azure, gainsboro); + background: -moz-linear-gradient(white, azure, azure, gainsboro); } .docson .box-4 { - background: mistyrose; - background: -webkit-linear-gradient(white, mistyrose, mistyrose, gainsboro); - background: -moz-linear-gradient(white, mistyrose, mistyrose, gainsboro); + background: mistyrose; + background: -webkit-linear-gradient(white, mistyrose, mistyrose, gainsboro); + background: -moz-linear-gradient(white, mistyrose, mistyrose, gainsboro); } .docson .box-5 { - background: #ddffee; - background: -webkit-linear-gradient(white, #ddffee, #ddffee, gainsboro); - background: -moz-linear-gradient(white, #ddffee, #ddffee, gainsboro); + background: #ddffee; + background: -webkit-linear-gradient(white, #ddffee, #ddffee, gainsboro); + background: -moz-linear-gradient(white, #ddffee, #ddffee, gainsboro); } .docson .box-6 { - background: ghostwhite; - background: -webkit-linear-gradient(white, ghostwhite, ghostwhite, gainsboro); - background: -moz-linear-gradient(white, ghostwhite, ghostwhite, gainsboro); + background: ghostwhite; + background: -webkit-linear-gradient(white, ghostwhite, ghostwhite, gainsboro); + background: -moz-linear-gradient(white, ghostwhite, ghostwhite, gainsboro); } .docson .box-7 { - background: lavenderblush; - background: -webkit-linear-gradient(white, lavenderblush, lavenderblush, gainsboro); - background: -moz-linear-gradient(white, lavenderblush, lavenderblush, gainsboro); + background: lavenderblush; + background: -webkit-linear-gradient( + white, + lavenderblush, + lavenderblush, + gainsboro + ); + background: -moz-linear-gradient( + white, + lavenderblush, + lavenderblush, + gainsboro + ); } .docson .box-8 { - background: aliceblue; - background: -webkit-linear-gradient(white, aliceblue, aliceblue, gainsboro); - background: -moz-linear-gradient(white, aliceblue, aliceblue, gainsboro); + background: aliceblue; + background: -webkit-linear-gradient(white, aliceblue, aliceblue, gainsboro); + background: -moz-linear-gradient(white, aliceblue, aliceblue, gainsboro); } .docson .signature { - padding-top: 5px; - clear: left; + padding-top: 5px; + clear: left; } .docson .signature-header { - padding-top: 3px; - height: 20px; - line-height: 24px; + padding-top: 3px; + height: 20px; + line-height: 24px; } .docson .property-name { - float: left; - font-family: "Lucida Console", Monaco, monospace; - min-width: 130px; + float: left; + font-family: "Lucida Console", Monaco, monospace; + min-width: 130px; } .docson .required { - font-weight: bold; + font-weight: bold; } .docson .type-keyword { - font-size: 80%; - color: dimgray; + font-size: 80%; + color: dimgray; } .docson .type-pattern { - font-size: 80%; - color: darkolivegreen; + font-size: 80%; + color: darkolivegreen; } .docson .type-enum { - color: purple; - font-family: "Lucida Console", Monaco, monospace; - font-size: 90%; - padding-left: 2px; + color: purple; + font-family: "Lucida Console", Monaco, monospace; + font-size: 90%; + padding-left: 2px; } .docson .type-default { - color: darkslategrey; - font-family: "Lucida Console", Monaco, monospace; + color: darkslategrey; + font-family: "Lucida Console", Monaco, monospace; } .docson .signature-type { - padding-left: 6px; - float: left; - min-width: 160px; - max-width: 320px; + padding-left: 6px; + float: left; + min-width: 160px; + max-width: 320px; } .docson .signature-type-any { - font-style: italic; + font-style: italic; } .docson .signature-type-string { - color: green; + color: green; } .docson .signature-type-number { - color: blue; + color: blue; } .docson .signature-type-integer { - color: blueviolet; + color: blueviolet; } .docson .signature-type-boolean { - color: orangered; + color: orangered; } .docson .signature-type-null { - font-family: "Lucida Console", Monaco, monospace; - color: red; + font-family: "Lucida Console", Monaco, monospace; + color: red; } .docson .signature-type-date-time { - color: #224466; + color: #224466; } .docson .signature-type-email { - color: cornflowerblue; + color: cornflowerblue; } .docson .signature-type-hostname { - color: darkolivegreen; + color: darkolivegreen; } .docson .signature-type-ipv6 { - color: darkslateblue; + color: darkslateblue; } .docson .signature-type-ipv4 { - color: indigo; + color: indigo; } .docson .signature-type-uri { - color: saddlebrown; + color: saddlebrown; } .docson .signature-button { - cursor: pointer; - padding: 4px; - border-radius: 4px; - border: 1px solid lightgrey; - -moz-border-radius: 4px; + cursor: pointer; + padding: 4px; + border-radius: 4px; + border: 1px solid lightgrey; + -moz-border-radius: 4px; } .docson .signature-type-ref { - color: darkblue; + color: darkblue; } .docson .signature-type-expanded { - padding: 5px 3px 3px 5px; - vertical-align: -1px; - opacity: 0.6; - -moz-box-shadow: inset 1px 1px 1px darkgray; - -webkit-box-shadow: inset 1px 1px 1px darkgray; - box-shadow: inset 1px 1px 1px darkgray; + padding: 5px 3px 3px 5px; + vertical-align: -1px; + opacity: 0.6; + -moz-box-shadow: inset 1px 1px 1px darkgray; + -webkit-box-shadow: inset 1px 1px 1px darkgray; + box-shadow: inset 1px 1px 1px darkgray; } .docson .signature-description { - padding-left: 6px; - padding-bottom: 3px; - color: dimgray; - float: left; - max-width: 600px; + padding-left: 6px; + padding-bottom: 3px; + color: dimgray; + float: left; + max-width: 600px; } .docson .signature-box-container { - clear: both; + clear: both; } .docson .box-container { - float: left; - padding-top: 4px; - padding-left: 8px; - display: none; + float: left; + padding-top: 4px; + padding-left: 8px; + display: none; } .docson .button { - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } .docson .button:hover { - color: darkred; + color: darkred; } @media all and (min-width: 20px) and (max-width: 500px) { - .docson .property-name { - min-width: 0px; - } - .docson .signature-type { - min-width: 0px; - } - .docson .source { - width: 100%; - } - .docson .box-container, .box { - width: 100%; - } + .docson .property-name { + min-width: 0px; + } + .docson .signature-type { + min-width: 0px; + } + .docson .source { + width: 100%; + } + .docson .box-container, + .box { + width: 100%; + } } .docson .desc { - padding-left: 6px; - line-height: 17px; + padding-left: 6px; + line-height: 17px; } .docson .desc p { - margin: 0; - margin-top: 3px; + margin: 0; + margin-top: 3px; } .docson .desc code { - color: purple; - font-size: 90%; + color: purple; + font-size: 90%; } - .docson .desc table { - margin-top: 4px; - margin-bottom: 4px; - border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; + border-collapse: collapse; } .docson .desc th { - padding: 0px; - font-size: 80%; - font-weight: normal; - background: rgba(231, 231, 231, 0.5); + padding: 0px; + font-size: 80%; + font-weight: normal; + background: rgba(231, 231, 231, 0.5); } .docson .desc table, .docson .desc th, .docson .desc td { - border: 1px solid lightgrey; + border: 1px solid lightgrey; } .docson .desc tr > td { - padding: 2px 6px 2px 6px; + padding: 2px 6px 2px 6px; } .docson .desc h1 { - font-size: 120%; - margin-top: 0px; - margin-bottom: 3px; + font-size: 120%; + margin-top: 0px; + margin-bottom: 3px; } .docson .desc h2 { - font-size: 115%; - margin-top: 0px; - margin-bottom: 3px; + font-size: 115%; + margin-top: 0px; + margin-bottom: 3px; } .docson .desc h3 { - font-size: 110%; - margin-top: 0px; - margin-bottom: 3px; + font-size: 110%; + margin-top: 0px; + margin-bottom: 3px; } .docson .desc h4 { - font-size: 100%; - margin-top: 0px; - margin-bottom: 3px; + font-size: 100%; + margin-top: 0px; + margin-bottom: 3px; } .docson .desc pre { - border: 1px solid lightgray; - border-radius: 4px; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - padding: 4px; - margin: 3px 0px; + border: 1px solid lightgray; + border-radius: 4px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + padding: 4px; + margin: 3px 0px; } .docson .desc ul { - padding-left: 16px; - margin: 3px 0px; + padding-left: 16px; + margin: 3px 0px; } .docson .desc ol { - padding-left: 16px; - margin: 3px 0px; + padding-left: 16px; + margin: 3px 0px; } .docson .desc blockquote { - margin: 3px 0px 3px 10px; - padding-left: 6px; - border-left: 1px solid lightgray; + margin: 3px 0px 3px 10px; + padding-left: 6px; + border-left: 1px solid lightgray; } .docson .desc img { - vertical-align: middle; + vertical-align: middle; } .docson .desc hr { - border: 0; - height: 1px; - background: lightgrey; - color: lightgrey; - width: 50%; + border: 0; + height: 1px; + background: lightgrey; + color: lightgrey; + width: 50%; } .docson .source { - display: none; - padding-left: 16px; - padding-right: 30px; + display: none; + padding-left: 16px; + padding-right: 30px; } -.docson .json, .json-schema { - font-family: "Lucida Console", Monaco, monospace; +.docson .json, +.json-schema { + font-family: "Lucida Console", Monaco, monospace; } .docson .json-punctuation { - font-weight: bold; + font-weight: bold; } -.docson .json-null, .json-true, .json-false { - font-weight: bold; +.docson .json-null, +.json-true, +.json-false { + font-weight: bold; } .docson .json-true { - color: #080; + color: #080; } .docson .json-false { - color: #800; + color: #800; } .docson .json-object-key { - color: #246; + color: #246; } .docson .json-keyword { - font-weight: bold; - color: #036; + font-weight: bold; + color: #036; } .docson .json-number { - font-weight: bold; - color: #660; + font-weight: bold; + color: #660; } .docson .json-string { - color: #800; + color: #800; } .docson .json-schema-map > .json-object-key { - color: #080; - font-style: italic; + color: #080; + font-style: italic; } - diff --git a/styles/main.css b/styles/main.css index b3765e10e..81ec7d6a2 100644 --- a/styles/main.css +++ b/styles/main.css @@ -1,9 +1,9 @@ -@import './_hljs.css' layer(base); -@import './_markdown.css' layer(base); -@import './_fonts.css' layer(base); -@import './_docsearch.css' layer(base); +@import "./_hljs.css" layer(base); +@import "./_markdown.css" layer(base); +@import "./_fonts.css" layer(base); +@import "./_docsearch.css" layer(base); -@import 'tailwindcss'; +@import "tailwindcss"; @source '../src/**/*.{mjs,js,res}'; @source '../pages/**/*.{mjs,js,mdx}'; @@ -164,7 +164,6 @@ --shadow-sm: 0 0.5px 0.5px 0 rgba(0, 0, 0, 0.05); @keyframes pulse { - 0%, 100% { opacity: 1; @@ -185,7 +184,6 @@ color utility to any element that depends on these defaults. */ @layer base { - *, ::after, ::before, @@ -297,12 +295,11 @@ /* Chrome/Safari/Webkit */ } - a>code { + a > code { @apply text-fire; } } - .CodeMirror { @apply h-full; background-color: inherit; @@ -343,7 +340,7 @@ } .cm-s-material .CodeMirror-cursor { - border-left: 1px solid #FFCC00; + border-left: 1px solid #ffcc00; } .cm-s-material div.CodeMirror-selected { @@ -355,14 +352,14 @@ } .cm-s-material .CodeMirror-line::selection, -.cm-s-material .CodeMirror-line>span::selection, -.cm-s-material .CodeMirror-line>span>span::selection { +.cm-s-material .CodeMirror-line > span::selection, +.cm-s-material .CodeMirror-line > span > span::selection { background: rgba(128, 203, 196, 0.2); } .cm-s-material .CodeMirror-line::-moz-selection, -.cm-s-material .CodeMirror-line>span::-moz-selection, -.cm-s-material .CodeMirror-line>span>span::-moz-selection { +.cm-s-material .CodeMirror-line > span::-moz-selection, +.cm-s-material .CodeMirror-line > span > span::-moz-selection { background: rgba(128, 203, 196, 0.2); } @@ -391,7 +388,7 @@ } .cm-s-material .cm-variable-2 { - color: #EEFFFF; + color: #eeffff; } .cm-s-material .cm-variable-3, @@ -440,34 +437,33 @@ } .cm-s-material .cm-tag { - color: #FF5370; + color: #ff5370; } .cm-s-material .cm-meta { - color: #FFCB6B; + color: #ffcb6b; } .cm-s-material .cm-attribute { - color: #C792EA; + color: #c792ea; } .cm-s-material .cm-property { - color: #C792EA; + color: #c792ea; } .cm-s-material .cm-qualifier { - color: #DECB6B; + color: #decb6b; } .cm-s-material .cm-variable-3, .cm-s-material .cm-type { - color: #DECB6B; + color: #decb6b; } - .cm-s-material .cm-error { - color: rgba(255, 255, 255, 1.0); - background-color: #FF5370; + color: rgba(255, 255, 255, 1); + background-color: #ff5370; } .cm-s-material .CodeMirror-matchingbracket { @@ -475,7 +471,6 @@ color: white !important; } - /* simplescrollbars style */ .CodeMirror-simplescroll-horizontal div, .CodeMirror-simplescroll-vertical div { @@ -516,7 +511,6 @@ width: 100%; } - .CodeMirror-overlayscroll .CodeMirror-scrollbar-filler, .CodeMirror-overlayscroll .CodeMirror-gutter-filler { display: none; @@ -555,4 +549,4 @@ .CodeMirror-overlayscroll-vertical div { right: 0; width: 100%; -} \ No newline at end of file +} diff --git a/styles/utils.css b/styles/utils.css index ca814f7d3..314e8b44e 100644 --- a/styles/utils.css +++ b/styles/utils.css @@ -1,10 +1,12 @@ - - .gradientShadow { /*box-shadow: inset 30 -30 50px 50px #edf0f2, inset 15 0 -20px 50px #edf0f2;*/ /*background: red;*/ - background: linear-gradient(to right, rgba(244, 100, 106, 0.4), rgba(234, 151, 67, 0.4)); + background: linear-gradient( + to right, + rgba(244, 100, 106, 0.4), + rgba(234, 151, 67, 0.4) + ); transform: translateY(20px) scale(0.95); filter: blur(15px); opacity: 0.7;