From 0e5af9b3ad0a34035f2c1aee361f5d048c5624fc Mon Sep 17 00:00:00 2001 From: sam bacha Date: Thu, 10 Mar 2022 09:49:34 -0800 Subject: [PATCH 01/38] feat(coinbase-wallet): coinbase wallet connector --- .gitignore | 2 - .size-limit.json | 15 + .vscode/settings.json | 5 + DISCO3.md | 753 +- README.md | 6 +- packages/coinbase-wallet/package.json | 32 + packages/coinbase-wallet/src/index.spec.ts | 55 + packages/coinbase-wallet/src/index.ts | 226 + packages/coinbase-wallet/tsconfig.json | 7 + packages/components/package.json | 15 +- packages/core/package.json | 9 +- packages/eip1193/package.json | 12 +- packages/generateComponent.js | 2 +- packages/network/package.json | 19 +- packages/network/src/index.spec.ts | 25 +- packages/network/src/index.ts | 123 +- packages/store/package.json | 11 +- packages/store/src/index.spec.ts | 43 +- packages/store/src/index.ts | 14 +- packages/types/src/index.ts | 8 +- ui-docs/next-env.d.ts | 5 + ui-docs/next.config.js | 73 + ui-docs/package.json | 50 + ui-docs/public/favicons/apple-touch-icon.png | Bin 0 -> 2213 bytes ui-docs/public/favicons/favicon-16x16.png | Bin 0 -> 477 bytes ui-docs/public/favicons/favicon-32x32.png | Bin 0 -> 610 bytes .../fonts/mono/iAWriterMonoS-Bold.woff2 | Bin 0 -> 37540 bytes .../fonts/mono/iAWriterMonoS-BoldItalic.woff2 | Bin 0 -> 41392 bytes .../fonts/mono/iAWriterMonoS-Italic.woff2 | Bin 0 -> 40708 bytes .../fonts/mono/iAWriterMonoS-Regular.woff2 | Bin 0 -> 36952 bytes ui-docs/public/logo.svg | 74 + ui-docs/public/robots.txt | 2 + ui-docs/src/components/CodeBlock.tsx | 121 + .../components/CodePreview/CodePreview.tsx | 127 + ui-docs/src/components/CodePreview/index.ts | 2 + .../src/components/CodePreview/styles.css.ts | 22 + ui-docs/src/components/CopyButton.tsx | 49 + ui-docs/src/components/Header.tsx | 26 + ui-docs/src/components/Link.tsx | 52 + ui-docs/src/components/MDX.tsx | 57 + ui-docs/src/components/Nav.tsx | 145 + ui-docs/src/components/PropsTable.tsx | 143 + ui-docs/src/components/SearchIcons.tsx | 77 + ui-docs/src/components/SkipNav.tsx | 28 + ui-docs/src/components/ThemeSwitcher.tsx | 78 + ui-docs/src/components/index.ts | 10 + ui-docs/src/guides/development.mdx | 46 + ui-docs/src/guides/playroom.mdx | 95 + ui-docs/src/layouts/docs.tsx | 77 + ui-docs/src/layouts/site.tsx | 7 + ui-docs/src/pages/_app.tsx | 38 + ui-docs/src/pages/_document.tsx | 61 + ui-docs/src/pages/components/[slug].tsx | 109 + ui-docs/src/pages/guides/[slug].tsx | 85 + ui-docs/src/pages/index.mdx | 61 + ui-docs/src/styles/globals.css.ts | 36 + ui-docs/src/styles/utils.css.ts | 30 + ui-docs/src/types/next.d.ts | 23 + ui-docs/src/utils/cookies.ts | 21 + ui-docs/src/utils/fs.ts | 27 + ui-docs/src/utils/getStaticTypes.ts | 39 + ui-docs/src/utils/github.ts | 10 + ui-docs/src/utils/isMounted.ts | 9 + ui-docs/src/utils/playroom.ts | 12 + ui-docs/tsconfig.json | 34 + ui-docs/yarn.lock | 6367 +++++++++++++++++ yarn.lock | 965 ++- 67 files changed, 10104 insertions(+), 571 deletions(-) create mode 100644 .size-limit.json create mode 100644 .vscode/settings.json create mode 100644 packages/coinbase-wallet/package.json create mode 100644 packages/coinbase-wallet/src/index.spec.ts create mode 100644 packages/coinbase-wallet/src/index.ts create mode 100644 packages/coinbase-wallet/tsconfig.json create mode 100644 ui-docs/next-env.d.ts create mode 100644 ui-docs/next.config.js create mode 100644 ui-docs/package.json create mode 100644 ui-docs/public/favicons/apple-touch-icon.png create mode 100644 ui-docs/public/favicons/favicon-16x16.png create mode 100644 ui-docs/public/favicons/favicon-32x32.png create mode 100644 ui-docs/public/fonts/mono/iAWriterMonoS-Bold.woff2 create mode 100644 ui-docs/public/fonts/mono/iAWriterMonoS-BoldItalic.woff2 create mode 100644 ui-docs/public/fonts/mono/iAWriterMonoS-Italic.woff2 create mode 100644 ui-docs/public/fonts/mono/iAWriterMonoS-Regular.woff2 create mode 100644 ui-docs/public/logo.svg create mode 100644 ui-docs/public/robots.txt create mode 100644 ui-docs/src/components/CodeBlock.tsx create mode 100644 ui-docs/src/components/CodePreview/CodePreview.tsx create mode 100644 ui-docs/src/components/CodePreview/index.ts create mode 100644 ui-docs/src/components/CodePreview/styles.css.ts create mode 100644 ui-docs/src/components/CopyButton.tsx create mode 100644 ui-docs/src/components/Header.tsx create mode 100644 ui-docs/src/components/Link.tsx create mode 100644 ui-docs/src/components/MDX.tsx create mode 100644 ui-docs/src/components/Nav.tsx create mode 100644 ui-docs/src/components/PropsTable.tsx create mode 100644 ui-docs/src/components/SearchIcons.tsx create mode 100644 ui-docs/src/components/SkipNav.tsx create mode 100644 ui-docs/src/components/ThemeSwitcher.tsx create mode 100644 ui-docs/src/components/index.ts create mode 100644 ui-docs/src/guides/development.mdx create mode 100644 ui-docs/src/guides/playroom.mdx create mode 100644 ui-docs/src/layouts/docs.tsx create mode 100644 ui-docs/src/layouts/site.tsx create mode 100644 ui-docs/src/pages/_app.tsx create mode 100644 ui-docs/src/pages/_document.tsx create mode 100644 ui-docs/src/pages/components/[slug].tsx create mode 100644 ui-docs/src/pages/guides/[slug].tsx create mode 100644 ui-docs/src/pages/index.mdx create mode 100644 ui-docs/src/styles/globals.css.ts create mode 100644 ui-docs/src/styles/utils.css.ts create mode 100644 ui-docs/src/types/next.d.ts create mode 100644 ui-docs/src/utils/cookies.ts create mode 100644 ui-docs/src/utils/fs.ts create mode 100644 ui-docs/src/utils/getStaticTypes.ts create mode 100644 ui-docs/src/utils/github.ts create mode 100644 ui-docs/src/utils/isMounted.ts create mode 100644 ui-docs/src/utils/playroom.ts create mode 100644 ui-docs/tsconfig.json create mode 100644 ui-docs/yarn.lock diff --git a/.gitignore b/.gitignore index b991ff9..5ecfa57 100644 --- a/.gitignore +++ b/.gitignore @@ -69,5 +69,3 @@ cache/ *.debug # Generated Components -components/ -!packages/components/**/* diff --git a/.size-limit.json b/.size-limit.json new file mode 100644 index 0000000..3575794 --- /dev/null +++ b/.size-limit.json @@ -0,0 +1,15 @@ +[ + { + "path": "./packages/components/dist/index.cjs.js", + "limit": "60 kB" + }, + { + "path": "./packages/components/dist/index.es.js", + "limit": "60 kB" + }, + { + "path": "./packages/components/dist/style.css", + "limit": "50 kB", + "webpack": false + } +] diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..1841723 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "cSpell.words": [ + "zustand" + ] +} diff --git a/DISCO3.md b/DISCO3.md index 150c97e..9d667c5 100644 --- a/DISCO3.md +++ b/DISCO3.md @@ -1,77 +1,88 @@ -| title: | disco: distributed computing aesthetic and critique | -|---------- |----------------------------------------------------- | -| version: | 2022.02 | -| summary: | distributed computing: a design framework | -| license: | Apache-2.0 / CC-2.5 SA | - +| title: | disco: distributed computing aesthetic and critique | +| -------- | --------------------------------------------------- | +| version: | 2022.02 | +| summary: | distributed computing: a design framework | +| license: | Apache-2.0 / CC-2.5 SA | --- - -# disco - a web3 engineering and design system - +# disco - a web3 engineering and design system > State is the root of all revenue. - - -
- ## abstract - -> [abstract]: -> we present an engineering focused aesthetic for a novel design framework: disco. disco's is a web3 focused UI/UX framework that is built to enable, provide and reinforce *trust* in the underlying process (both the activity and the application they are using itself). By communicating to the end user directly and indirectly we hope to significatly reduce user error prone mistakes - +> [abstract]: we present an engineering focused aesthetic for a novel design +> framework: disco. disco's is a web3 focused UI/UX framework that is built to +> enable, provide and reinforce _trust_ in the underlying process (both the +> activity and the application they are using itself). By communicating to the +> end user directly and indirectly we hope to significatly reduce user error +> prone mistakes ## motivation -User interface development tools are very powerful. They can be used to construct large and complex user interfaces, with only a relatively small amount of code written by an application developer. And yet, despite the power of such tools and the relatively small amount of code that is written, user interface software often has the following characteristics: - -- the code can be difficult to understand and review thoroughly: -- the code can be difficult to test in a systematic and thorough way; -- the code can contain bugs even after extensive testing and bug fixing; -- the code can be difficult to enhance without introducing unwanted side-effects; -- the quality of the code tends to deteriorate as enhancements are made to it. - -Despite the obvious problems associated with user interface development, **little effort has been made to improve the situation**. Any practitioner who has worked on large user interface projects will be familiar with many of the above characteristics, which are **symptomatic of the way in which the software is constructed**. - +User interface development tools are very powerful. They can be used to +construct large and complex user interfaces, with only a relatively small amount +of code written by an application developer. And yet, despite the power of such +tools and the relatively small amount of code that is written, user interface +software often has the following characteristics: + +- the code can be difficult to understand and review thoroughly: +- the code can be difficult to test in a systematic and thorough way; +- the code can contain bugs even after extensive testing and bug fixing; +- the code can be difficult to enhance without introducing unwanted + side-effects; +- the quality of the code tends to deteriorate as enhancements are made to it. + +Despite the obvious problems associated with user interface development, +**little effort has been made to improve the situation**. Any practitioner who +has worked on large user interface projects will be familiar with many of the +above characteristics, which are **symptomatic of the way in which the software +is constructed**. ### Principles for Transactions -[UX/UI] Manage transaction wait time. Clarify blockchain specific times and manage user’s wait in various phases and feedback.
-[UX/UI] Within the context of an individual, adapt to progressively increase/decrease the amount of new lingo and specific concepts that they need to learn and are exposed to. never combine expert-level blockchain-specific lingo with the need-to-know basics when acting within the same context of an individual; create tiers of knowledge levels. You can show an expert the basics, but never the other way around.
-[UX/UI] Use a consistent visual language to dictate addresses. use human-readable deterministic visual representation of the hash (i.e. Identicons, Blockies et al.) when possible. allow users to expand the full address/hash and copy.
-[UX/UI] Apply relevance to interrupting messages only for information relevant to the current user.
-[UX/UI] Clarify which data comes from the blockchain and which doesn’t.
-[UX/UI] Types of transactions i.e. value transfers, function calls, contract generating.
-[UX/UI] When a blockchain event aborts or otherwise fails to complete as expected, the fallback must remain functional with resulting blockchain state clear.
-[UX/UI] Allow users to subscribe-to, unsubscribe-from or temporarily mute certain events.
-[UX/UI] Errors MUST populate back to the user. -[UX/UI] Budget performance and response time so that stallouts or failovers can be approximated in worse-case - +[UX/UI] Manage transaction wait time. Clarify blockchain specific times and +manage user’s wait in various phases and feedback.
[UX/UI] Within the +context of an individual, adapt to progressively increase/decrease the amount of +new lingo and specific concepts that they need to learn and are exposed to. +never combine expert-level blockchain-specific lingo with the need-to-know +basics when acting within the same context of an individual; create tiers of +knowledge levels. You can show an expert the basics, but never the other way +around.
[UX/UI] Use a consistent visual language to dictate addresses. use +human-readable deterministic visual representation of the hash (i.e. Identicons, +Blockies et al.) when possible. allow users to expand the full address/hash and +copy.
[UX/UI] Apply relevance to interrupting messages only for information +relevant to the current user.
[UX/UI] Clarify which data comes from the +blockchain and which doesn’t.
[UX/UI] Types of transactions i.e. value +transfers, function calls, contract generating.
[UX/UI] When a blockchain +event aborts or otherwise fails to complete as expected, the fallback must +remain functional with resulting blockchain state clear.
[UX/UI] Allow +users to subscribe-to, unsubscribe-from or temporarily mute certain events.
+[UX/UI] Errors MUST populate back to the user. [UX/UI] Budget performance and +response time so that stallouts or failovers can be approximated in worse-case #### Example: Bad UI/UX can cost big -UI issue causes Citibank to accidentally pay off its insolvent client's $900M loan. - (accessed, 2021.12.20) +UI issue causes Citibank to accidentally pay off its insolvent client's $900M +loan. + +(accessed, 2021.12.20) --- - ## UI/X - Design Decision Records - ## Colors - Semantic Aliases A guide to providing semantic aliases for colors. -Referencing color scales by their actual scale name can work well, like `blue` and `red`. -But often, creating semantic aliases like `accent`, `primary`, `neutral`, or `brand` can be helpful, especially when it comes to theming. - +Referencing color scales by their actual scale name can work well, like `blue` +and `red`. But often, creating semantic aliases like `accent`, `primary`, +`neutral`, or `brand` can be helpful, especially when it comes to theming. #### Bad Color Aliasing @@ -111,20 +122,22 @@ But often, creating semantic aliases like `accent`, `primary`, `neutral`, or `br ## Why Color Alias Matters -With this approach, you will likely run into issues where you need to use the same scale for multiple semantics. Common examples include: +With this approach, you will likely run into issues where you need to use the +same scale for multiple semantics. Common examples include: -- If you map `yellow` to "**warning**", you might also need `yellow` to communicate "**pending**". - -- If you map `red` to "danger", you might also need `red` to communicate "error" or "rejected". - -- If you map `green` to "success", you might also need `green` to communicate "valid". - -- If you map `blue` to "accent", you might also need `blue` to communicate "info". - +- If you map `yellow` to "**warning**", you might also need `yellow` to + communicate "**pending**". +- If you map `red` to "danger", you might also need `red` to communicate "error" + or "rejected". +- If you map `green` to "success", you might also need `green` to communicate + "valid". +- If you map `blue` to "accent", you might also need `blue` to communicate + "info". -> 💡 In this scenario, you can choose to define multiple semantic aliases which map to the same scale. +> 💡 In this scenario, you can choose to define multiple semantic aliases which +> map to the same scale. -#### Good Color Alias +#### Good Color Alias ```css @import 'https://cdn.jsdelivr.net/npm/@radix-ui/colors@latest/blue.css'; @@ -147,11 +160,9 @@ With this approach, you will likely run into issues where you need to use the sa --pending1: var(--yellow1); --pending2: var(--yellow2); } - ``` - - + ## Table of Contents - - [Table of Contents](#table-of-contents) +- [Table of Contents](#table-of-contents) - [Antipatterns](#antipatterns) - [Strict email validation](#strict-email-validation) - [Late returns](#late-returns) @@ -277,29 +292,28 @@ You might also say: "Things that change together should be located as close as r # Antipatterns -Most of those are antipatterns in the Python programming language, but -some of them might be more generic. +Most of those are antipatterns in the Python programming language, but some of +them might be more generic. ## Strict email validation -It is almost impossible to strictly validate an email. Even if you were -writing or using a regex that follows -[RFC5322](http://tools.ietf.org/html/rfc5322#section-3.4), you would -have false positives when trying to validate actual emails that don't -follow the RFC. +It is almost impossible to strictly validate an email. Even if you were writing +or using a regex that follows +[RFC5322](http://tools.ietf.org/html/rfc5322#section-3.4), you would have false +positives when trying to validate actual emails that don't follow the RFC. -What's more, validating an email provides very weak guarantees. A -stronger, more meaningful validation would be to send an email and -validate that the user received it. +What's more, validating an email provides very weak guarantees. A stronger, more +meaningful validation would be to send an email and validate that the user +received it. -To sum up, don't waste your time trying to validate an email if you -don't need to (or just check that there's a `@` in it). If you need to, -send an email with a token and validate that the user received it. +To sum up, don't waste your time trying to validate an email if you don't need +to (or just check that there's a `@` in it). If you need to, send an email with +a token and validate that the user received it. ## Late returns -Returning early reduces cognitive overhead, and improve readability by -killing indentation levels. +Returning early reduces cognitive overhead, and improve readability by killing +indentation levels. Bad: @@ -331,15 +345,14 @@ toaster.restart() There's multiple things wrong with this comment: -- Even if it is actually a hack, no need to say it in a comment. It - lowers the perceived quality of a codebase and impacts developer - motivation. -- Putting the author and the date is totally useless when using source - control (`git blame`). +- Even if it is actually a hack, no need to say it in a comment. It lowers the + perceived quality of a codebase and impacts developer motivation. +- Putting the author and the date is totally useless when using source control + (`git blame`). - This does not explain why it's temporary. - It's impossible to easily grep for temporary fixes. -- [Louis de Funès](https://en.wikipedia.org/wiki/Louis_de_Fun%C3%A8s) - would never write a hack. +- [Louis de Funès](https://en.wikipedia.org/wiki/Louis_de_Fun%C3%A8s) would + never write a hack. Good: @@ -350,8 +363,8 @@ toaster.restart() ``` - This clearly explains the nature of the temporary fix. -- Using `TODO` is an ubiquitous pattern that allows easy grepping and - plays nice with most text editors. +- Using `TODO` is an ubiquitous pattern that allows easy grepping and plays nice + with most text editors. - The perceived quality of this temporary fix is much higher. ## Repeating arguments in function name @@ -363,8 +376,8 @@ def get_by_color(color): return Toasters.filter_by(color=color) ``` -Putting the argument name in both the function name and in arguments is, -in most cases and for most interpreted languages, redundant. +Putting the argument name in both the function name and in arguments is, in most +cases and for most interpreted languages, redundant. Good: @@ -384,10 +397,10 @@ class Toasters(object): pass ``` -This is bad because it's unnecessarily redundant -(`Toasters.get_toaster(1)`). According to the single responsibility -principle, a class should focus on one area of responsibility. So the -`Toasters` class should only focus on toasters object. +This is bad because it's unnecessarily redundant (`Toasters.get_toaster(1)`). +According to the single responsibility principle, a class should focus on one +area of responsibility. So the `Toasters` class should only focus on toasters +object. Good: @@ -464,8 +477,8 @@ def get_data(): ## Undeterministic tests -When testing function that don't behave deterministically, it can be -tempting to run them multiple time and average their results. +When testing function that don't behave deterministically, it can be tempting to +run them multiple time and average their results. Bad: @@ -508,21 +521,19 @@ This is a deterministic test that clearly tells what's going on. ## Unbalanced boilerplate -One thing to strive for in libraries is have as little boilerplate as -possible, but not less. +One thing to strive for in libraries is have as little boilerplate as possible, +but not less. Not enough boilerplate: you'll spend hours trying to understand specific -behaviors that are too magical/implicit. You will need flexibility and -you won't be able to get it. Boilerplate is useful insofar as it -increases +behaviors that are too magical/implicit. You will need flexibility and you won't +be able to get it. Boilerplate is useful insofar as it increases [transparency](http://www.catb.org/esr/writings/taoup/html/ch01s06.html). Too much boilerplate: users of your library will be stuck using outdated -patterns. Users will write library to generate the boilerplate required -by your library. +patterns. Users will write library to generate the boilerplate required by your +library. -I think Flask and SQLAlchemy do a very good job at keeping this under -control. +I think Flask and SQLAlchemy do a very good job at keeping this under control. ## Inconsistent use of verbs in functions @@ -546,17 +557,17 @@ def find_toasts(color): return filter(lambda toast: toast.color == color, TOASTS) ``` -The use of verb is inconsistent in this example. `get` is used to return -a possibly empty list of toasters, and `find` is used to return a single -toaster (or raise an exception) in the second function or a possibly -empty list of toasts in the third function. +The use of verb is inconsistent in this example. `get` is used to return a +possibly empty list of toasters, and `find` is used to return a single toaster +(or raise an exception) in the second function or a possibly empty list of +toasts in the third function. This is based on personal taste but I have the following rule: -- `get` prefixes function that return at most one object (they either - return none or raise an exception depending on the cases) -- `find` prefixes function that return a possibly empty list (or - iterable) of objects. +- `get` prefixes function that return at most one object (they either return + none or raise an exception depending on the cases) +- `find` prefixes function that return a possibly empty list (or iterable) of + objects. Good: @@ -601,16 +612,16 @@ def create2(*args, **kwargs): Why is this bad? -- It's really easy to make a mistake, especially in interpreted - languages such as Python. For instance, if I call - `create({'name': 'hello', 'ccolor': 'blue'})`, I won't get any error, - but the color won't be the one I expect. -- It increases cognitive load, as I have to understand where the object - is coming from to introspect its content. +- It's really easy to make a mistake, especially in interpreted languages such + as Python. For instance, if I call + `create({'name': 'hello', 'ccolor': 'blue'})`, I won't get any error, but the + color won't be the one I expect. +- It increases cognitive load, as I have to understand where the object is + coming from to introspect its content. - It makes the job of static analyzer harder or impossible. -Granted, this pattern is sometimes required (for instance when the -number of params is too large, or when dealing with pure data). +Granted, this pattern is sometimes required (for instance when the number of +params is too large, or when dealing with pure data). A better way is to be explicit: @@ -641,10 +652,10 @@ def get_url(user_id): return 'http://127.0.0.1/users/%s' % user_id ``` -I consider this an antipattern because it hides the request formatting -from the developer, making it more complex to see what `url` look like. -In this extreme example, the formatting function is a one-liner which -sounds a bit overkill for a function. +I consider this an antipattern because it hides the request formatting from the +developer, making it more complex to see what `url` look like. In this extreme +example, the formatting function is a one-liner which sounds a bit overkill for +a function. Good: @@ -654,12 +665,12 @@ def get_user(user_id): return requests.get(url) ``` -Even if you were duplicating the logic once or twice it might still be -fine, because: +Even if you were duplicating the logic once or twice it might still be fine, +because: - You're unlikely to re-use anywhere else outside this file. -- Putting this inline makes it easier for follow the flow. Code is - written to be read primarily by computers. +- Putting this inline makes it easier for follow the flow. Code is written to be + read primarily by computers. ## Returning nothing instead of raising NotFound exception @@ -680,16 +691,15 @@ def toast(toaster_id): ``` It all depends on the caller, but in this cases I'd argue that it is bad -practice to return nothing when the toaster identified by `toaster_id` -can't be found, for two main reasons. +practice to return nothing when the toaster identified by `toaster_id` can't be +found, for two main reasons. **First reason**: when we provide an identifier, we expect it to return -something. Once again, this depends on the caller (for instance, we -could try to see if a user exists by checking an email for instance). In -this simple example it's ok because the `toaster.toast()` will fail -immediately, but what if we were never calling it and creating some -other unrelated objects? We would be doing things that we should never -be doing if the object did not exist: +something. Once again, this depends on the caller (for instance, we could try to +see if a user exists by checking an email for instance). In this simple example +it's ok because the `toaster.toast()` will fail immediately, but what if we were +never calling it and creating some other unrelated objects? We would be doing +things that we should never be doing if the object did not exist: ```python def toast(toaster_id, user): @@ -699,12 +709,11 @@ def toast(toaster_id, user): bill_new_toaster(user) ``` -**Second reason**: `toaster.toast` will fail anyway if `toaster` is none -(in Python with `AttributeError: NoneType has no attribute toast`). In -this abstract example it's ok because the two lines are next to each -other, but the actual `toaster.toast()` call might happen further down -the stack - and it will be very difficult for the developer to -understand where the error is coming from. +**Second reason**: `toaster.toast` will fail anyway if `toaster` is none (in +Python with `AttributeError: NoneType has no attribute toast`). In this abstract +example it's ok because the two lines are next to each other, but the actual +`toaster.toast()` call might happen further down the stack - and it will be very +difficult for the developer to understand where the error is coming from. ```python def toast(toaster_id, user): @@ -726,10 +735,9 @@ def do_stuff_b(toaster): What's the correct things to do? -- If you expect the object to be there, make sure to raise if you don't - find it. -- If you're using SQLAlchemy, use `one()` to force raising an exception - if the object can't be found. Don't use `first` or `one_or_none()`. +- If you expect the object to be there, make sure to raise if you don't find it. +- If you're using SQLAlchemy, use `one()` to force raising an exception if the + object can't be found. Don't use `first` or `one_or_none()`. ## Having a library that contains all utils @@ -748,26 +756,24 @@ def upload_to_sftp(...): ... ``` -`util` or `tools` or `lib` modules that contain all sorts of utilities -have a tendency to become bloated and unmaintainable. Prefer to have -small, dedicated files. +`util` or `tools` or `lib` modules that contain all sorts of utilities have a +tendency to become bloated and unmaintainable. Prefer to have small, dedicated +files. This will keep your imports logical (`lib.date_utils`, `lib.csv_utils`, -`lib.sftp`), make it easier for the reader to identify all the utilities -around a specific topic, and test files easy to keep organized. - +`lib.sftp`), make it easier for the reader to identify all the utilities around +a specific topic, and test files easy to keep organized. - -### Conformance: Configurations for linting, etc +### Conformance: Configurations for linting, etc > Engineering and Design Practices - [Conformance](#conformance) - * [Prettier](#prettier) - + [whitespace](#whitespace) - + [arrow-parens](#arrow-parens) - + [comma-dangle](#202-additional-trailing-comma--yup-eslint--comma-dangle) - + [implicit-arrow-linebreak](#86-enforce-the-location-of-arrow-function-bodies-with-implicit-returns-eslint--implicit-arrow-linebreak) + - [Prettier](#prettier) + - [whitespace](#whitespace) + - [arrow-parens](#arrow-parens) + - [comma-dangle](#202-additional-trailing-comma--yup-eslint--comma-dangle) + - [implicit-arrow-linebreak](#86-enforce-the-location-of-arrow-function-bodies-with-implicit-returns-eslint--implicit-arrow-linebreak) - [Naming Convention](#naming-convention) - [Naming Components](#naming-components) - [Class vs `React.createClass` vs stateless](#class-vs--reactcreateclass--vs-stateless) @@ -786,23 +792,23 @@ around a specific topic, and test files easy to keep organized. - [General Constructs](#general-constructs) - [Style](#style) - [Reference Specification](#reference-specification) - * [System UI](#system-ui) - + [Scale Objects](#scale-objects) - + [Scale Aliases](#scale-aliases) - + [Excluded Values](#excluded-values) - * [Keys](#keys) - + [Space](#space) - * [Breakpoints](#breakpoints) - + [Media Queries](#media-queries) - * [Key Reference](#key-reference) - * [Prior Art](#prior-art) - + - [System UI](#system-ui) + - [Scale Objects](#scale-objects) + - [Scale Aliases](#scale-aliases) + - [Excluded Values](#excluded-values) + - [Keys](#keys) + - [Space](#space) + - [Breakpoints](#breakpoints) + - [Media Queries](#media-queries) + - [Key Reference](#key-reference) + - [Prior Art](#prior-art) ## Conformance -Conformance objectives are to reduce AST diff churn and improve developer experience +Conformance objectives are to reduce AST diff churn and improve developer +experience -### Prettier +### Prettier ### whitespace @@ -891,7 +897,7 @@ const dragonball = 'z'; #### comma-dangle -> 20.2 Additional trailing comma: Yup. eslint: +> 20.2 Additional trailing comma: Yup. eslint: Why? This leads to cleaner git diffs. Also, transpilers like Babel will remove the additional trailing comma in the transpiled code which means you don’t have to worry about the trailing comma problem in legacy browsers. @@ -914,7 +920,7 @@ const hero = { #### implicit-arrow-linebreak -Enforce the location of arrow function bodies with implicit returns. eslint: +Enforce the location of arrow function bodies with implicit returns. eslint: ```js // bad @@ -928,118 +934,125 @@ Enforce the location of arrow function bodies with implicit returns. eslint: (foo) => bar; ``` - ## Naming Convention -We recommend using camel case, pascal case or snake case for your theme tokens. Other word separators may not work as expected. +We recommend using camel case, pascal case or snake case for your theme tokens. +Other word separators may not work as expected. ```js // recommended -tokenName -token_name -token-name +tokenName; +token_name; +token - name; // avoid -token.name -token$name -token*name +token.name; +token$name; +token * name; ``` ## Naming Components - - **Extensions**: Use `.jsx` extension for React components. eslint: [`react/jsx-filename-extension`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-filename-extension.md) - - **Filename**: Use PascalCase for filenames. E.g., `ReservationCard.jsx`. - - **Reference Naming**: Use PascalCase for React components and camelCase for their instances. eslint: [`react/jsx-pascal-case`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-pascal-case.md) +- **Extensions**: Use `.jsx` extension for React components. eslint: + [`react/jsx-filename-extension`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-filename-extension.md) +- **Filename**: Use PascalCase for filenames. E.g., `ReservationCard.jsx`. +- **Reference Naming**: Use PascalCase for React components and camelCase for + their instances. eslint: + [`react/jsx-pascal-case`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-pascal-case.md) ```jsx - // bad - import reservationCard from './ReservationCard'; +// bad +import reservationCard from './ReservationCard'; - // good - import ReservationCard from './ReservationCard'; +// good +import ReservationCard from './ReservationCard'; - // bad - const ReservationItem = ; +// bad +const ReservationItem = ; - // good - const reservationItem = ; - ``` +// good +const reservationItem = ; +``` -- **Component Naming**: Use the filename as the component name. For example, `ReservationCard.jsx` should have a reference name of `ReservationCard`. However, for root components of a directory, use `index.jsx` as the filename and use the directory name as the component name: +- **Component Naming**: Use the filename as the component name. For example, + `ReservationCard.jsx` should have a reference name of `ReservationCard`. + However, for root components of a directory, use `index.jsx` as the filename + and use the directory name as the component name: ```jsx - // bad - import Footer from './Footer/Footer'; +// bad +import Footer from './Footer/Footer'; - // bad - import Footer from './Footer/index'; +// bad +import Footer from './Footer/index'; - // good - import Footer from './Footer'; +// good +import Footer from './Footer'; ``` - ## Class vs `React.createClass` vs stateless - - If you have internal state and/or refs, prefer `class extends React.Component` over `React.createClass`. eslint: [`react/prefer-es6-class`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-es6-class.md) [`react/prefer-stateless-function`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-stateless-function.md) +- If you have internal state and/or refs, prefer `class extends React.Component` + over `React.createClass`. eslint: + [`react/prefer-es6-class`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-es6-class.md) + [`react/prefer-stateless-function`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-stateless-function.md) ```jsx - // bad - const Listing = React.createClass({ - // ... - render() { - return
{this.state.hello}
; - } - }); - - // good - class Listing extends React.Component { - // ... - render() { - return
{this.state.hello}
; - } - } +// bad +const Listing = React.createClass({ + // ... + render() { + return
{this.state.hello}
; + }, +}); + +// good +class Listing extends React.Component { + // ... + render() { + return
{this.state.hello}
; + } +} ``` -> And if you don’t have state or refs, prefer normal functions (not arrow functions) over classes: +> And if you don’t have state or refs, prefer normal functions (not arrow +> functions) over classes: ```jsx - // bad - class Listing extends React.Component { - render() { - return
{this.props.hello}
; - } - } +// bad +class Listing extends React.Component { + render() { + return
{this.props.hello}
; + } +} - // bad (relying on function name inference is discouraged) - const Listing = ({ hello }) => ( -
{hello}
- ); +// bad (relying on function name inference is discouraged) +const Listing = ({ hello }) =>
{hello}
; - // good - function Listing({ hello }) { - return
{hello}
; - } +// good +function Listing({ hello }) { + return
{hello}
; +} ``` ## TypeScript -These guidelines are adapted from the TypeScript core's contributor coding guidelines. - -* [Names](#names) -* [Exports](#exports) -* [Components](#components) -* [Types](#types) -* [`null` and `undefined`](#null-and-undefined) -* [General Assumptions](#general-assumptions) -* [Flags](#flags) -* [Comments](#comments) -* [Strings](#strings) -* [When to use `any`](#when-to-use-any) -* [Diagnostic Messages](#diagnostic-messages) -* [General Constructs](#general-constructs) -* [Style](#style) +These guidelines are adapted from the TypeScript core's contributor coding +guidelines. +- [Names](#names) +- [Exports](#exports) +- [Components](#components) +- [Types](#types) +- [`null` and `undefined`](#null-and-undefined) +- [General Assumptions](#general-assumptions) +- [Flags](#flags) +- [Comments](#comments) +- [Strings](#strings) +- [When to use `any`](#when-to-use-any) +- [Diagnostic Messages](#diagnostic-messages) +- [General Constructs](#general-constructs) +- [Style](#style) ## Names @@ -1050,115 +1063,144 @@ These guidelines are adapted from the TypeScript core's contributor coding guide 5. Use camelCase for property names and local variables. 6. Do not use "\_" as a prefix for private properties. 7. Use whole words in names when possible. -8. Use `isXXXing` or `hasXXXXed` for variables representing states of things (e.g. `isLoading`, `hasCompletedOnboarding`). +8. Use `isXXXing` or `hasXXXXed` for variables representing states of things + (e.g. `isLoading`, `hasCompletedOnboarding`). 9. Give folders/files/components/functions unique names. ## Exports -1. Only use named exports. The only exceptions are a tool requires default exports (e.g `React.lazy()`, Gatsby and Next.js `pages`, `typography.js`) +1. Only use named exports. The only exceptions are a tool requires default + exports (e.g `React.lazy()`, Gatsby and Next.js `pages`, `typography.js`) ## Components 1. 1 file per logical component (e.g. parser, scanner, emitter, checker). -2. If not kept in a separate folder, files with ".generated.\*" suffix are auto-generated, do not hand-edit them. +2. If not kept in a separate folder, files with ".generated.\*" suffix are + auto-generated, do not hand-edit them. 3. Tests should be kept in the same directory with ".test.\*" suffix -4. Filename should match the component name. Interfaces for React components should be called `Props` and `State`. The only exception is when writing a render prop. In this situation, you, the author, should call the interface for your component's props `Config` and then the render prop interface `Props` so it is easy for everyone else to use. +4. Filename should match the component name. Interfaces for React components + should be called `Props` and `State`. The only + exception is when writing a render prop. In this situation, you, the author, + should call the interface for your component's props `Config` + and then the render prop interface `Props` so it is easy for + everyone else to use. ## Types -1. Do not export types/functions unless you need to share it across multiple components. +1. Do not export types/functions unless you need to share it across multiple + components. 2. Do not introduce new types/values to the global namespace. 3. Shared types should be defined in 'types.ts'. 4. Within a file, type definitions should come first (after the imports). ## `null` and `undefined` -1. Use **undefined**. Do not use `null`. EVER. If null is used (like in legacy Redux code), it should be kept isolated from other code with selectors. +1. Use **undefined**. Do not use `null`. EVER. If null is used (like in legacy + Redux code), it should be kept isolated from other code with selectors. ## General Assumptions -1. Consider objects like Nodes, Symbols, etc. as immutable outside the component that created them. Do not change them. +1. Consider objects like Nodes, Symbols, etc. as immutable outside the + component that created them. Do not change them. 2. Consider arrays as immutable by default after creation. ## Flags -1. More than 2 related Boolean properties on a type should be turned into a flag. +1. More than 2 related Boolean properties on a type should be turned into a + flag. ## Comments 1. Use JSDoc style comments for functions, interfaces, enums, and classes. -2. **Document crazy stuff.** Always add `@see ` and the current date when referencing external resources, blog posts, tweets, snippets, gists, issues etc. +2. **Document crazy stuff.** Always add `@see ` and the current date when + referencing external resources, blog posts, tweets, snippets, gists, issues + etc. 3. Make note conditions upon which hacks and smelly code can be removed. ## Strings 1. Use single quotes for strings. Double quotes around JSX string props. -2. All strings visible to the user need to be localized (make an entry in diagnosticMessages.json). +2. All strings visible to the user need to be localized (make an entry in + diagnosticMessages.json). ## When to use `any` -1. If something takes you longer than 10 minutes to type or you feel the need to read through TS Advanced Types docs, you should take a step back and ask for help, or use `any`. -2. Custom typings of 3rd-party modules should be added to a `.d.ts` file in a `typings` directory. Document the date and version of the module you are typing at the top of the file. -3. Consider rewriting tiny modules in typescript if types are too hard to think through. +1. If something takes you longer than 10 minutes to type or you feel the need + to read through TS Advanced Types docs, you should take a step back and ask + for help, or use `any`. +2. Custom typings of 3rd-party modules should be added to a `.d.ts` file in a + `typings` directory. Document the date and version of the module you are + typing at the top of the file. +3. Consider rewriting tiny modules in typescript if types are too hard to think + through. ## Diagnostic Messages 1. Use a period at the end of a sentence. 2. Use indefinite articles for indefinite entities. -3. Definite entities should be named (this is for a variable name, type name, etc..). -4. When stating a rule, the subject should be in the singular (e.g. "An external module cannot..." instead of "External modules cannot..."). +3. Definite entities should be named (this is for a variable name, type name, + etc..). +4. When stating a rule, the subject should be in the singular (e.g. "An + external module cannot..." instead of "External modules cannot..."). 5. Use present tense. 6. Use active voice. ## General Constructs -For a variety of reasons, we avoid certain constructs, and use some of our own. Among them: +For a variety of reasons, we avoid certain constructs, and use some of our own. +Among them: -1. Do not use `for..in` statements; instead, use `ts.forEach`, `ts.forEachKey` and `ts.forEachValue`. Be aware of their slightly different semantics. -2. Try to use `ts.forEach`, `ts.map`, and `ts.filter` instead of loops when it is not strongly inconvenient. +1. Do not use `for..in` statements; instead, use `ts.forEach`, `ts.forEachKey` + and `ts.forEachValue`. Be aware of their slightly different semantics. +2. Try to use `ts.forEach`, `ts.map`, and `ts.filter` instead of loops when it + is not strongly inconvenient. ## Style 0. Use prettier and tslint/eslint. 1. Use arrow functions over anonymous function expressions. -1. Only surround arrow function parameters when necessary.
For example, `(x) => x + x` is wrong but the following are correct: +1. Only surround arrow function parameters when necessary.
For example, + `(x) => x + x` is wrong but the following are correct: 1. `x => x + x` 2. `(x,y) => x + y` 3. `(x: T, y: T) => x === y` -1. Always surround loop and conditional bodies with curly braces. Statements on the same line are allowed to omit braces. +1. Always surround loop and conditional bodies with curly braces. Statements on + the same line are allowed to omit braces. 1. Open curly braces always go on the same line as whatever necessitates them. -1. Parenthesized constructs should have no surrounding whitespace.
A single space follows commas, colons, and semicolons in those constructs. For example: +1. Parenthesized constructs should have no surrounding whitespace.
A + single space follows commas, colons, and semicolons in those constructs. For + example: 1. `for (var i = 0, n = str.length; i < 10; i++) { }` 2. `if (x < 10) { }` 3. `function f(x: number, y: string): void { }` -1. Use a single declaration per variable statement
(i.e. use `var x = 1; var y = 2;` over `var x = 1, y = 2;`). +1. Use a single declaration per variable statement
(i.e. use + `var x = 1; var y = 2;` over `var x = 1, y = 2;`). 1. Use 2 spaces per indentation. - ## Reference Specification ### System UI > [System UI Theme Specification](https://system-ui.com] - -The theme object is intended to be a general purpose format for storing design system style values, scales, and/or design tokens. -The object itself is not coupled to any particular library's implementation and can be used -in places where sharing common style values in multiple parts of a code base is desirable. +The theme object is intended to be a general purpose format for storing design +system style values, scales, and/or design tokens. The object itself is not +coupled to any particular library's implementation and can be used in places +where sharing common style values in multiple parts of a code base is desirable. #### Scale Objects -Many CSS style properties accept open-ended values like lengths, colors, and font names. -In order to create a consistent styling system, the theme object is centered around the idea of scales, -such as a typographic (font-size) scale, a spacing scale for margin and padding, and a color object. -These scales can be defined in multiple ways depending on needs, but tend to use arrays for ordinal values like font sizes, -or plain objects for named values like colors, with the option of nesting objects for more complex systems. +Many CSS style properties accept open-ended values like lengths, colors, and +font names. In order to create a consistent styling system, the theme object is +centered around the idea of scales, such as a typographic (font-size) scale, a +spacing scale for margin and padding, and a color object. These scales can be +defined in multiple ways depending on needs, but tend to use arrays for ordinal +values like font sizes, or plain objects for named values like colors, with the +option of nesting objects for more complex systems. ```js // example fontSizes scale as an array -fontSizes: [ - 12, 14, 16, 20, 24, 32 -] +fontSizes: [12, 14, 16, 20, 24, 32]; ``` ```js @@ -1184,49 +1226,55 @@ colors: { #### Scale Aliases -For typically ordinal values like font sizes that are stored in arrays, it can be helpful to create aliases by adding named properties to the object. +For typically ordinal values like font sizes that are stored in arrays, it can +be helpful to create aliases by adding named properties to the object. ```js // example fontSizes aliases -fontSizes: [ - 12, 14, 16, 20, 24, 32 -] +fontSizes: [12, 14, 16, 20, 24, 32]; // aliases -fontSizes.body = fontSizes[2] -fontSizes.display = fontSizes[5] +fontSizes.body = fontSizes[2]; +fontSizes.display = fontSizes[5]; ``` #### Excluded Values -Some CSS properties accept only a small, finite number of valid CSS values and should *not* be included as a scale object. -For example, the `text-align` property accepts the following values: -`left`, `right`, `center`, `justify`, `justify-all`, `start`, `end`, or `match-parent`. -Other properties that are intentionally excluded from this specification include: `float`, `clear`, `display`, `overflow`, `position`, `vertical-align`, `align-items`, `justify-content`, and `flex-direction`. +Some CSS properties accept only a small, finite number of valid CSS values and +should _not_ be included as a scale object. For example, the `text-align` +property accepts the following values: `left`, `right`, `center`, `justify`, +`justify-all`, `start`, `end`, or `match-parent`. Other properties that are +intentionally excluded from this specification include: `float`, `clear`, +`display`, `overflow`, `position`, `vertical-align`, `align-items`, +`justify-content`, and `flex-direction`. ### Keys -The keys in the theme object should typically correspond with the CSS properties they are used for, and follow a plural naming convention. -For example, the CSS property `font-size` is expected to use values from the `fontSizes` scale, and the `color` property uses values from the `colors` scale. - -Some keys can be used for multiple CSS properties, where the data type is the same. -The `color` object is intended to be used with any property that accepts a CSS color value, such as `background-color` or `border-color`. +The keys in the theme object should typically correspond with the CSS properties +they are used for, and follow a plural naming convention. For example, the CSS +property `font-size` is expected to use values from the `fontSizes` scale, and +the `color` property uses values from the `colors` scale. +Some keys can be used for multiple CSS properties, where the data type is the +same. The `color` object is intended to be used with any property that accepts a +CSS color value, such as `background-color` or `border-color`. #### Space -The `space` key is a specially-named scale intended for use with margin, padding, and other layout-related CSS properties. -A space scale can be defined as either a plain object or an array, but by convention an array is preferred. -This is an intentional constraint that makes it difficult to add *"one-off"* or *"in-between"* sizes that could lead to unwanted and rippling affects to layout. +The `space` key is a specially-named scale intended for use with margin, +padding, and other layout-related CSS properties. A space scale can be defined +as either a plain object or an array, but by convention an array is preferred. +This is an intentional constraint that makes it difficult to add _"one-off"_ or +_"in-between"_ sizes that could lead to unwanted and rippling affects to layout. -> Note: other names under consideration include *spacing*, *spaces*, and *lengths*. +> Note: other names under consideration include _spacing_, _spaces_, and +> _lengths_. -When defining space scales as an array, it is conventional to use the value `0` as the first value so that `space[0] === 0`. +When defining space scales as an array, it is conventional to use the value `0` +as the first value so that `space[0] === 0`. ```js // example space scale -space: [ - 0, 4, 8, 16, 32, 64 -] +space: [0, 4, 8, 16, 32, 64]; ``` ```js @@ -1240,22 +1288,22 @@ space: { ```js // example space scale with aliases -space: [ - 0, 4, 8, 16, 32 -] -space.small = space[1] -space.medium = space[2] -space.large = space[3] +space: [0, 4, 8, 16, 32]; +space.small = space[1]; +space.medium = space[2]; +space.large = space[3]; ``` ### Breakpoints -Breakpoints are CSS lengths intended for use in media queries. -Commonly, the breakpoints scale is used to create mobile-first responsive media queries based on array values. +Breakpoints are CSS lengths intended for use in media queries. Commonly, the +breakpoints scale is used to create mobile-first responsive media queries based +on array values. #### Media Queries -For convenience and for use with other styling approaches, a `mediaQueries` scale derived from the `breakpoints` scale can be added to the theme object. +For convenience and for use with other styling approaches, a `mediaQueries` +scale derived from the `breakpoints` scale can be added to the theme object. ```js breakpoints: [ '40em', '52em', '64em' ] @@ -1269,30 +1317,31 @@ mediaQueries: { ### Key Reference -The following is a list of theme object keys and their corresponding CSS properties. -This list may be non-exhaustive. - -Theme Key | CSS Properties -------------------|-------------- -`space` | `margin`, `margin-top`, `margin-right`, `margin-bottom`, `margin-left`, `padding`, `padding-top`, `padding-right`, `padding-bottom`, `padding-left`, `grid-gap`, `grid-column-gap`, `grid-row-gap` -`fontSizes` | `font-size` -`colors` | `color`, `background-color`, `border-color` -`fonts` | `font-family` -`fontWeights` | `font-weight` -`lineHeights` | `line-height` -`letterSpacings` | `letter-spacing` -`sizes` | `width`, `height`, `min-width`, `max-width`, `min-height`, `max-height` -`borders` | `border`, `border-top`, `border-right`, `border-bottom`, `border-left` -`borderWidths` | `border-width` -`borderStyles` | `border-style` -`radii` | `border-radius` -`shadows` | `box-shadow`, `text-shadow` -`zIndices` | `z-index` -`transitions` | `transition` +The following is a list of theme object keys and their corresponding CSS +properties. This list may be non-exhaustive. + +| Theme Key | CSS Properties | +| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `space` | `margin`, `margin-top`, `margin-right`, `margin-bottom`, `margin-left`, `padding`, `padding-top`, `padding-right`, `padding-bottom`, `padding-left`, `grid-gap`, `grid-column-gap`, `grid-row-gap` | +| `fontSizes` | `font-size` | +| `colors` | `color`, `background-color`, `border-color` | +| `fonts` | `font-family` | +| `fontWeights` | `font-weight` | +| `lineHeights` | `line-height` | +| `letterSpacings` | `letter-spacing` | +| `sizes` | `width`, `height`, `min-width`, `max-width`, `min-height`, `max-height` | +| `borders` | `border`, `border-top`, `border-right`, `border-bottom`, `border-left` | +| `borderWidths` | `border-width` | +| `borderStyles` | `border-style` | +| `radii` | `border-radius` | +| `shadows` | `box-shadow`, `text-shadow` | +| `zIndices` | `z-index` | +| `transitions` | `transition` | ### Prior Art -Prior art includes, but is not limited to the following. Please open an issue or pull request to help ensure this list is inclusive. +Prior art includes, but is not limited to the following. Please open an issue or +pull request to help ensure this list is inclusive. - [Theo](https://github.com/salesforce-ux/theo) - [Style Dictionary](https://amzn.github.io/style-dictionary/) diff --git a/README.md b/README.md index c8f7fcc..088b043 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,13 @@ > a performant web3 react library - > [Read the Disco3 Design and Arch. Document](https://github.com/manifoldfinance/disco3-react/blob/master/DISCO3.md) + --- -[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/5693/badge)](https://bestpractices.coreinfrastructure.org/projects/5693) [![manifoldfinance.eth](https://img.shields.io/static/v1?label=&message=manifoldfinance.eth&color=black&logo=ethereum&logoColor=white)](https://etherscan.io/enslookup-search?search=manifoldfinance.eth) [![manifoldfinance - disco3-react](https://img.shields.io/static/v1?label=manifoldfinance&message=disco3-react&color=black&logo=github)](https://github.com/manifoldfinance/disco3-react 'Go to GitHub repo') +[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/5693/badge)](https://bestpractices.coreinfrastructure.org/projects/5693) +[![manifoldfinance.eth](https://img.shields.io/static/v1?label=&message=manifoldfinance.eth&color=black&logo=ethereum&logoColor=white)](https://etherscan.io/enslookup-search?search=manifoldfinance.eth) +[![manifoldfinance - disco3-react](https://img.shields.io/static/v1?label=manifoldfinance&message=disco3-react&color=black&logo=github)](https://github.com/manifoldfinance/disco3-react 'Go to GitHub repo') | package | description | | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | diff --git a/packages/coinbase-wallet/package.json b/packages/coinbase-wallet/package.json new file mode 100644 index 0000000..b852521 --- /dev/null +++ b/packages/coinbase-wallet/package.json @@ -0,0 +1,32 @@ +{ + "name": "@disco3/coinbase-wallet", + "keywords": [ + "web3-react", + "coinbase wallet" + ], + "publishConfig": { + "access": "public" + }, + "version": "8.1.0", + "files": [ + "dist/*" + ], + "type": "commonjs", + "types": "./dist/index.d.ts", + "main": "./dist/index.js", + "exports": "./dist/index.js", + "scripts": { + "prebuild": "rm -rf dist", + "build": "tsc", + "start": "tsc --watch" + }, + "dependencies": { + "@disco3/types": "^8.0.10-beta.0" + }, + "peerDependencies": { + "@coinbase/wallet-sdk": "^3.0.1" + }, + "devDependencies": { + "@disco3/store": "^8.0.13-beta.0" + } + } diff --git a/packages/coinbase-wallet/src/index.spec.ts b/packages/coinbase-wallet/src/index.spec.ts new file mode 100644 index 0000000..ba09426 --- /dev/null +++ b/packages/coinbase-wallet/src/index.spec.ts @@ -0,0 +1,55 @@ +import { createWeb3ReactStoreAndActions } from '@disco3/store'; +import type { Actions, Web3ReactStore } from '@disco3/types'; +import { WalletLink } from '.'; +import { MockEIP1193Provider } from '../../eip1193/src/index.spec'; + +jest.mock( + '@coinbase/wallet-sdk', + () => + class MockWalletLink { + makeWeb3Provider() { + return new MockEIP1193Provider(); + } + }, +); + +const chainId = '0x1'; +const accounts: string[] = []; + +describe('WalletLink', () => { + let store: Web3ReactStore; + let connector: WalletLink; + let mockConnector: MockEIP1193Provider; + + describe('connectEagerly = true', () => { + beforeEach(() => { + let actions: Actions; + [store, actions] = createWeb3ReactStoreAndActions(); + connector = new WalletLink( + actions, + { + appName: 'test', + url: 'https://mock.url', + }, + true, + ); + }); + + beforeEach(async () => { + mockConnector = connector.provider as unknown as MockEIP1193Provider; + mockConnector.chainId = chainId; + mockConnector.accounts = accounts; + }); + + test('#activate', async () => { + await connector.activate(); + + expect(store.getState()).toEqual({ + chainId: Number.parseInt(chainId, 16), + accounts, + activating: false, + error: undefined, + }); + }); + }); +}); diff --git a/packages/coinbase-wallet/src/index.ts b/packages/coinbase-wallet/src/index.ts new file mode 100644 index 0000000..5e0e4a4 --- /dev/null +++ b/packages/coinbase-wallet/src/index.ts @@ -0,0 +1,226 @@ +import type { + CoinbaseWalletProvider, + CoinbaseWalletSDK, +} from '@coinbase/wallet-sdk'; +import type { + Actions, + AddEthereumChainParameter, + ProviderConnectInfo, + ProviderRpcError, +} from '@disco3/types'; +import { Connector } from '@disco3/types'; + +function parseChainId(chainId: string | number) { + return typeof chainId === 'number' + ? chainId + : Number.parseInt(chainId, chainId.startsWith('0x') ? 16 : 10); +} + +type CoinbaseWalletSDKOptions = ConstructorParameters< + typeof CoinbaseWalletSDK +>[0] & { url: string }; + +export class WalletLink extends Connector { + /** {@inheritdoc Connector.provider} */ + public provider: CoinbaseWalletProvider | undefined; + + private readonly options: CoinbaseWalletSDKOptions; + private eagerConnection?: Promise; + + /** + * A `walletlink` instance. + */ + public walletLink: CoinbaseWalletSDK | undefined; + + /** + * @param options - Options to pass to `walletlink` + * @param connectEagerly - A flag indicating whether connection should be initiated when the class is constructed. + */ + constructor( + actions: Actions, + options: CoinbaseWalletSDKOptions, + connectEagerly = false, + ) { + super(actions); + + if (connectEagerly && typeof window === 'undefined') { + throw new Error( + 'connectEagerly = true is invalid for SSR, instead use the connectEagerly method in a useEffect', + ); + } + + this.options = options; + + if (connectEagerly) void this.connectEagerly(); + } + + // the `connected` property, is bugged, but this works as a hack to check connection status + private get connected() { + return !!this.provider?.selectedAddress; + } + + private async isomorphicInitialize(): Promise { + if (this.eagerConnection) return this.eagerConnection; + + await (this.eagerConnection = import('@coinbase/wallet-sdk').then((m) => { + const { url, ...options } = this.options; + this.walletLink = new m.default(options); + this.provider = this.walletLink.makeWeb3Provider(url); + + this.provider.on('connect', ({ chainId }: ProviderConnectInfo): void => { + this.actions.update({ chainId: parseChainId(chainId) }); + }); + + this.provider.on('disconnect', (error: ProviderRpcError): void => { + this.actions.reportError(error); + }); + + this.provider.on('chainChanged', (chainId: string): void => { + this.actions.update({ chainId: parseChainId(chainId) }); + }); + + this.provider.on('accountsChanged', (accounts: string[]): void => { + this.actions.update({ accounts }); + }); + })); + } + + /** {@inheritdoc Connector.connectEagerly} */ + public async connectEagerly(): Promise { + const cancelActivation = this.actions.startActivation(); + + await this.isomorphicInitialize(); + + if (this.connected) { + return Promise.all([ + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + this.provider!.request({ method: 'eth_chainId' }), + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + this.provider!.request({ method: 'eth_accounts' }), + ]) + .then(([chainId, accounts]) => { + if (accounts.length) { + this.actions.update({ chainId: parseChainId(chainId), accounts }); + } else { + throw new Error('No accounts returned'); + } + }) + .catch((error) => { + console.debug('Could not connect eagerly', error); + cancelActivation(); + }); + } else { + cancelActivation(); + } + } + + /** + * Initiates a connection. + * + * @param desiredChainIdOrChainParameters - If defined, indicates the desired chain to connect to. If the user is + * already connected to this chain, no additional steps will be taken. Otherwise, the user will be prompted to switch + * to the chain, if one of two conditions is met: either they already have it added, or the argument is of type + * AddEthereumChainParameter, in which case the user will be prompted to add the chain with the specified parameters + * first, before being prompted to switch. + */ + public async activate( + desiredChainIdOrChainParameters?: number | AddEthereumChainParameter, + ): Promise { + const desiredChainId = + typeof desiredChainIdOrChainParameters === 'number' + ? desiredChainIdOrChainParameters + : desiredChainIdOrChainParameters?.chainId; + + if (this.connected) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + if ( + !desiredChainId || + desiredChainId === parseChainId(this.provider!.chainId) + ) + return; + + const desiredChainIdHex = `0x${desiredChainId.toString(16)}`; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return this.provider!.request({ + method: 'wallet_switchEthereumChain', + params: [{ chainId: desiredChainIdHex }], + }) + .catch(async (error: ProviderRpcError) => { + if ( + error.code === 4902 && + typeof desiredChainIdOrChainParameters !== 'number' + ) { + // if we're here, we can try to add a new network + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return this.provider!.request({ + method: 'wallet_addEthereumChain', + params: [ + { + ...desiredChainIdOrChainParameters, + chainId: desiredChainIdHex, + }, + ], + }); + } else { + throw error; + } + }) + .catch((error: ProviderRpcError) => { + this.actions.reportError(error); + }); + } + + this.actions.startActivation(); + await this.isomorphicInitialize(); + + return Promise.all([ + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + this.provider!.request({ method: 'eth_chainId' }), + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + this.provider!.request({ method: 'eth_requestAccounts' }), + ]) + .then(([chainId, accounts]) => { + const receivedChainId = parseChainId(chainId); + + if (!desiredChainId || desiredChainId === receivedChainId) { + return this.actions.update({ chainId: receivedChainId, accounts }); + } + + // if we're here, we can try to switch networks + const desiredChainIdHex = `0x${desiredChainId.toString(16)}`; + return this.provider + ?.request({ + method: 'wallet_switchEthereumChain', + params: [{ chainId: desiredChainIdHex }], + }) + .catch(async (error: ProviderRpcError) => { + if ( + error.code === 4902 && + typeof desiredChainIdOrChainParameters !== 'number' + ) { + // if we're here, we can try to add a new network + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return this.provider!.request({ + method: 'wallet_addEthereumChain', + params: [ + { + ...desiredChainIdOrChainParameters, + chainId: desiredChainIdHex, + }, + ], + }); + } else { + throw error; + } + }); + }) + .catch((error: Error) => { + this.actions.reportError(error); + }); + } + + /** {@inheritdoc Connector.deactivate} */ + public deactivate(): void { + this.walletLink?.disconnect(); + } +} diff --git a/packages/coinbase-wallet/tsconfig.json b/packages/coinbase-wallet/tsconfig.json new file mode 100644 index 0000000..b4485ae --- /dev/null +++ b/packages/coinbase-wallet/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.json", + "include": ["./src"], + "compilerOptions": { + "outDir": "./dist" + } + } diff --git a/packages/components/package.json b/packages/components/package.json index bb519a8..7d0a7db 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,7 +1,10 @@ { - "name": "@disco3/components", - "version": "0.0.1", + "name": "disco-web3", + "version": "0.0.3", "description": "web3 design system for disco3", + "publishConfig": { + "access": "public" + }, "main": "./dist/index.cjs.js", "module": "./dist/index.es.js", "types": "./dist/types/index.d.ts", @@ -46,8 +49,6 @@ "build": "NODE_ENV=production npx vite build", "clean": "rimraf dist src/components/icons/generated/", "lint:types": "npx tsc --noEmit", - "prepack": "yarn build", - "publish": "yarn npm publish", "test": "npx jest -u" }, "dependencies": { @@ -96,9 +97,9 @@ "rimraf": "^3.0.2", "ts-jest": "^27.0.7", "ts-node": "^10.4.0", - "vite": "^2.6.13", - "vite-plugin-dts": "^0.9.2", - "vite-tsconfig-paths": "^3.3.17" + "vite": "^2.8.6", + "vite-plugin-dts": "^0.9.9", + "vite-tsconfig-paths": "^3.4.1" }, "peerDependencies": { "react": "^17", diff --git a/packages/core/package.json b/packages/core/package.json index 8cf6c2a..21d82f4 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -13,7 +13,8 @@ "homepage": "https://manifoldfinace.github.io/disco3-react/", "repository": { "type": "git", - "url": "https://github.com/manifoldfinance/disco3-react.git" + "url": "https://github.com/manifoldfinance/disco3-react.git", + "directory": "packages/core" }, "bugs": { "url": "https://github.com/manifoldfinance/disco3-react/issues" @@ -40,10 +41,10 @@ "start": "tsc --watch" }, "dependencies": { - "@disco3/store": "^8.0.2-beta.0", - "@disco3/types": "^8.0.2-beta.0", "@ethersproject/providers": "^5.5.1", - "zustand": "^4.0.0-beta.0" + "@disco3/store": "^8.0.13-beta.0", + "@disco3/types": "^8.0.10-beta.0", + "zustand": "^4.0.0-beta.2" }, "peerDependencies": { "react": ">=17" diff --git a/packages/eip1193/package.json b/packages/eip1193/package.json index 24a4886..aa96cfb 100644 --- a/packages/eip1193/package.json +++ b/packages/eip1193/package.json @@ -29,10 +29,10 @@ "start": "tsc --watch" }, "dependencies": { - "@disco3/store": "^8.0.2-beta.0", - "@disco3/types": "^8.0.2-beta.0", - "@ethersproject/experimental": "^5.5.0", - "@ethersproject/providers": "^5.5.1" + "@disco3/types": "^8.0.10-beta.0" }, - "devDependencies": {} -} + "devDependencies": { + "@ethersproject/experimental": "^5.6.0", + "@ethersproject/providers": "^5.6.0", + "@disco3/store": "^8.0.13-beta.0" + } diff --git a/packages/generateComponent.js b/packages/generateComponent.js index 2072e3f..5035e0a 100644 --- a/packages/generateComponent.js +++ b/packages/generateComponent.js @@ -82,7 +82,7 @@ const componentsDir = path.join(baseDir, 'components/src/components') --- \`\`\`tsx - import { ${componentName} } from 'degen' + import { ${componentName} } from '@disco3/components' \`\`\` \`\`\`tsx live=true expand=true diff --git a/packages/network/package.json b/packages/network/package.json index ef8b4c9..90f634b 100644 --- a/packages/network/package.json +++ b/packages/network/package.json @@ -7,11 +7,15 @@ ], "author": "SEE CONTRIBUTORS", "license": "GPL-3.0-or-later", - "repository": "git+https://github.com/manifoldfinance/disco3-react", + "repository": { + "type": "git", + "url": "https://github.com/manifoldfinance/disco3-react.git", + "directory": "packages/network" + }, "publishConfig": { "access": "public" }, - "version": "8.0.2-beta.0", + "version": "8.1.0", "type": "module", "files": [ "dist/*" @@ -30,10 +34,11 @@ "start": "tsc --watch" }, "dependencies": { - "@disco3/store": "^8.0.2-beta.0", - "@disco3/types": "^8.0.2-beta.0", - "@ethersproject/experimental": "^5.5.0", - "@ethersproject/providers": "^5.5.1" + "@ethersproject/experimental": "^5.6.0", + "@ethersproject/providers": "^5.6.0", + "@disco3/types": "^8.0.10-beta.0" }, - "devDependencies": {} + "devDependencies": { + "@disco3/store": "^8.0.13-beta.0" + } } diff --git a/packages/network/src/index.spec.ts b/packages/network/src/index.spec.ts index 7e44b2a..ad01322 100644 --- a/packages/network/src/index.spec.ts +++ b/packages/network/src/index.spec.ts @@ -1,8 +1,8 @@ +import { createWeb3ReactStoreAndActions } from '@disco3/store'; import type { Actions, Web3ReactStore } from '@disco3/types'; - import { MockEip1193Bridge } from '../../url/src/index.spec'; import { Network } from './'; -import { createWeb3ReactStoreAndActions } from '@disco3/store'; + jest.mock('@ethersproject/providers', () => ({ JsonRpcProvider: class MockJsonRpcProvider { getSigner() {} @@ -17,7 +17,7 @@ jest.mock('@ethersproject/experimental', () => ({ const chainId = '0x1'; const accounts: string[] = []; -describe('Url', () => { +describe('Network', () => { let store: Web3ReactStore; let connector: Network; let mockConnector: MockEip1193Bridge; @@ -26,7 +26,7 @@ describe('Url', () => { beforeEach(() => { let actions: Actions; [store, actions] = createWeb3ReactStoreAndActions(); - connector = new Network(actions, { 1: 'https://mock.url' }); + connector = new Network(actions, { 1: 'https://mock.url' }, true); }); beforeEach(async () => { @@ -89,9 +89,11 @@ describe('Url', () => { beforeEach(() => { let actions: Actions; [store, actions] = createWeb3ReactStoreAndActions(); - connector = new Network(actions, { - 1: ['https://1.mock.url', 'https://2.mock.url'], - }); + connector = new Network( + actions, + { 1: ['https://1.mock.url', 'https://2.mock.url'] }, + true, + ); }); beforeEach(async () => { @@ -116,10 +118,11 @@ describe('Url', () => { beforeEach(() => { let actions: Actions; [store, actions] = createWeb3ReactStoreAndActions(); - connector = new Network(actions, { - 1: 'https://mainnet.mock.url', - 2: 'https://testnet.mock.url', - }); + connector = new Network( + actions, + { 1: 'https://mainnet.mock.url', 2: 'https://testnet.mock.url' }, + true, + ); }); beforeEach(async () => { diff --git a/packages/network/src/index.ts b/packages/network/src/index.ts index d677668..40f4585 100644 --- a/packages/network/src/index.ts +++ b/packages/network/src/index.ts @@ -7,22 +7,32 @@ type url = string | ConnectionInfo; export class Network extends Connector { /** {@inheritdoc Connector.provider} */ - provider: Eip1193Bridge | undefined; + public provider: Eip1193Bridge | undefined; - private urlMap: { [chainId: number]: url[] }; - private chainId: number; - private providerCache: { [chainId: number]: Eip1193Bridge } = {}; + private urlMap: Record; + private defaultChainId: number; + private providerCache: Record | undefined> = + {}; /** * @param urlMap - A mapping from chainIds to RPC urls. * @param connectEagerly - A flag indicating whether connection should be initiated when the class is constructed. + * @param defaultChainId - The chainId to connect to if connectEagerly is true. */ constructor( actions: Actions, urlMap: { [chainId: number]: url | url[] }, - connectEagerly = true, + connectEagerly = false, + defaultChainId = Number(Object.keys(urlMap)[0]), ) { super(actions); + + if (connectEagerly && typeof window === 'undefined') { + throw new Error( + 'connectEagerly = true is invalid for SSR, instead use the activate method in a useEffect', + ); + } + this.urlMap = Object.keys(urlMap).reduce<{ [chainId: number]: url[] }>( (accumulator, chainId) => { const urls = urlMap[Number(chainId)]; @@ -31,72 +41,35 @@ export class Network extends Connector { }, {}, ); - // use the first chainId in urlMap as the default - this.chainId = Number(Object.keys(this.urlMap)[0]); + this.defaultChainId = defaultChainId; - if (connectEagerly) { - void this.initialize(); - } + if (connectEagerly) void this.activate(); } - private async initialize(): Promise { - this.provider = undefined; - this.actions.startActivation(); - - // cache the desired chainId before async logic - const chainId = this.chainId; - - // populate the provider cache if necessary - if (!this.providerCache[chainId]) { - // instantiate new provider - const [{ JsonRpcProvider, FallbackProvider }, Eip1193Bridge] = - await Promise.all([ - import('@ethersproject/providers').then( - ({ JsonRpcProvider, FallbackProvider }) => ({ - JsonRpcProvider, - FallbackProvider, - }), - ), - import('@ethersproject/experimental').then( - ({ Eip1193Bridge }) => Eip1193Bridge, - ), - ]); - + private async isomorphicInitialize(chainId: number): Promise { + if (this.providerCache[chainId]) + return this.providerCache[chainId] as Promise; + + return (this.providerCache[chainId] = Promise.all([ + import('@ethersproject/providers').then( + ({ JsonRpcProvider, FallbackProvider }) => ({ + JsonRpcProvider, + FallbackProvider, + }), + ), + import('@ethersproject/experimental').then( + ({ Eip1193Bridge }) => Eip1193Bridge, + ), + ]).then(([{ JsonRpcProvider, FallbackProvider }, Eip1193Bridge]) => { const urls = this.urlMap[chainId]; const providers = urls.map((url) => new JsonRpcProvider(url, chainId)); - const provider = new Eip1193Bridge( + + return new Eip1193Bridge( providers[0].getSigner(), providers.length === 1 ? providers[0] : new FallbackProvider(providers), ); - - this.providerCache[chainId] = provider; - } - - // once we're here, the cache is guaranteed to be initialized - // so, if the current chainId still matches the one at the beginning of the call, update - if (chainId === this.chainId) { - this.provider = this.providerCache[chainId]; - - return this.provider - .request({ method: 'eth_chainId' }) - .then((returnedChainId: number) => { - if (returnedChainId !== chainId) { - // this means the returned chainId was unexpected, i.e. the provided url(s) were wrong - throw new Error( - `expected chainId ${chainId}, received ${returnedChainId}`, - ); - } - - // again we have to make sure the chainIds match, to prevent race conditions - if (chainId === this.chainId) { - this.actions.update({ chainId, accounts: [] }); - } - }) - .catch((error: Error) => { - this.actions.reportError(error); - }); - } + })); } /** @@ -104,18 +77,18 @@ export class Network extends Connector { * * @param desiredChainId - The desired chain to connect to. */ - public async activate( - desiredChainId = Number(Object.keys(this.urlMap)[0]), - ): Promise { - if (this.urlMap[desiredChainId] === undefined) { - throw new Error( - `no url(s) provided for desiredChainId ${desiredChainId}`, - ); - } - - // set the connector's chainId to the target, to prevent race conditions - this.chainId = desiredChainId; - - return this.initialize(); + public async activate(desiredChainId = this.defaultChainId): Promise { + if (!this.provider) this.actions.startActivation(); + + this.provider = await this.isomorphicInitialize(desiredChainId); + + return this.provider + .request({ method: 'eth_chainId' }) + .then((chainId: number) => { + this.actions.update({ chainId, accounts: [] }); + }) + .catch((error: Error) => { + this.actions.reportError(error); + }); } } diff --git a/packages/store/package.json b/packages/store/package.json index 9ca16ff..42643a2 100644 --- a/packages/store/package.json +++ b/packages/store/package.json @@ -1,6 +1,6 @@ { "name": "@disco3/store", - "version": "8.0.2-beta.0", + "version": "8.1.0", "type": "module", "files": [ "dist/*" @@ -19,7 +19,8 @@ "homepage": "https://manifoldfinace.github.io/disco3-react/", "repository": { "type": "git", - "url": "https://github.com/manifoldfinance/disco3-react.git" + "url": "https://github.com/manifoldfinance/disco3-react.git", + "directory": "packages/store" }, "bugs": { "url": "https://github.com/manifoldfinance/disco3-react/issues" @@ -41,8 +42,8 @@ "start": "tsc --watch" }, "dependencies": { - "@disco3/types": "8.0.2-beta.0", - "@ethersproject/address": "^5.4.0", - "zustand": "^4.0.0-beta.0" + "@ethersproject/address": "^5.6.0", + "@disco3/types": "^8.0.20-beta.0", + "zustand": "^4.0.0-beta.2" } } diff --git a/packages/store/src/index.spec.ts b/packages/store/src/index.spec.ts index 22c257a..821b78d 100644 --- a/packages/store/src/index.spec.ts +++ b/packages/store/src/index.spec.ts @@ -1,4 +1,8 @@ -import { ChainIdNotAllowedError, createWeb3ReactStoreAndActions } from '.'; +import { + ChainIdNotAllowedError, + createWeb3ReactStoreAndActions, + MAX_SAFE_CHAIN_ID, +} from '.'; test('ChainIdNotAllowedError', () => { const error = new ChainIdNotAllowedError(1, [2]); @@ -25,7 +29,7 @@ describe('#createWeb3ReactStoreAndActions', () => { }); describe('#startActivation', () => { - test('#works', () => { + test('works', () => { const [store, actions] = createWeb3ReactStoreAndActions(); actions.startActivation(); expect(store.getState()).toEqual({ @@ -35,6 +39,7 @@ describe('#createWeb3ReactStoreAndActions', () => { error: undefined, }); }); + test('cancellation works', () => { const [store, actions] = createWeb3ReactStoreAndActions(); const cancelActivation = actions.startActivation(); @@ -53,7 +58,7 @@ describe('#createWeb3ReactStoreAndActions', () => { describe('#update', () => { test('throws on bad chainIds', () => { const [, actions] = createWeb3ReactStoreAndActions(); - for (const chainId of [1.1, 0, Number.MAX_SAFE_INTEGER + 1]) { + for (const chainId of [1.1, 0, MAX_SAFE_CHAIN_ID + 1]) { expect(() => actions.update({ chainId })).toThrow( `Invalid chainId ${chainId}`, ); @@ -196,15 +201,29 @@ describe('#createWeb3ReactStoreAndActions', () => { }); }); - test('#reportError', () => { - const [store, actions] = createWeb3ReactStoreAndActions(); - const error = new Error(); - actions.reportError(error); - expect(store.getState()).toEqual({ - chainId: undefined, - accounts: undefined, - activating: false, - error, + describe('#reportError', () => { + test('sets error', () => { + const [store, actions] = createWeb3ReactStoreAndActions(); + const error = new Error(); + actions.reportError(error); + expect(store.getState()).toEqual({ + chainId: undefined, + accounts: undefined, + activating: false, + error, + }); + }); + + test('resets state', () => { + const [store, actions] = createWeb3ReactStoreAndActions(); + actions.reportError(new Error()); + actions.reportError(undefined); + expect(store.getState()).toEqual({ + chainId: undefined, + accounts: undefined, + activating: false, + error: undefined, + }); }); }); }); diff --git a/packages/store/src/index.ts b/packages/store/src/index.ts index 40059a7..5f8241a 100644 --- a/packages/store/src/index.ts +++ b/packages/store/src/index.ts @@ -7,11 +7,19 @@ import type { } from '@disco3/types'; import create from 'zustand/vanilla'; +/** + * MAX_SAFE_CHAIN_ID is the upper bound limit on what will be accepted for `chainId` + * `MAX_SAFE_CHAIN_ID = floor( ( 2**53 - 39 ) / 2 ) = 4503599627370476` + * + * @see {@link https://github.com/MetaMask/metamask-extension/blob/b6673731e2367e119a5fee9a454dd40bd4968948/shared/constants/network.js#L31} + */ +export const MAX_SAFE_CHAIN_ID = 4503599627370476; + function validateChainId(chainId: number): void { if ( !Number.isInteger(chainId) || chainId <= 0 || - chainId > Number.MAX_SAFE_INTEGER + chainId > MAX_SAFE_CHAIN_ID ) { throw new Error(`Invalid chainId ${chainId}`); } @@ -73,9 +81,7 @@ export function createWeb3ReactStoreAndActions( // return a function that cancels the activation iff nothing else has happened return () => { - if (nullifier === nullifierCached) { - store.setState({ ...DEFAULT_STATE, activating: false }); - } + if (nullifier === nullifierCached) store.setState({ activating: false }); }; } diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 13ea5ab..74f0ee5 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -1,6 +1,5 @@ -import type { State, StoreApi } from 'zustand/vanilla'; - import type { EventEmitter } from 'node:events'; +import type { State, StoreApi } from 'zustand/vanilla'; export interface Web3ReactState extends State { chainId: number | undefined; @@ -88,6 +87,11 @@ export abstract class Connector { this.actions = actions; } + /** + * Attempt to initiate a connection, failing silently + */ + public connectEagerly?(...args: unknown[]): Promise | void; + /** * Initiate a connection. */ diff --git a/ui-docs/next-env.d.ts b/ui-docs/next-env.d.ts new file mode 100644 index 0000000..4f11a03 --- /dev/null +++ b/ui-docs/next-env.d.ts @@ -0,0 +1,5 @@ +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/ui-docs/next.config.js b/ui-docs/next.config.js new file mode 100644 index 0000000..4e7aa89 --- /dev/null +++ b/ui-docs/next.config.js @@ -0,0 +1,73 @@ +const { glob } = require('glob') +const { createVanillaExtractPlugin } = require('@vanilla-extract/next-plugin') +const withVanillaExtract = createVanillaExtractPlugin({ + identifiers: 'short', +}) +const withMDX = require('@next/mdx')({ + extension: /\.mdx?$/, +}) + +const path = require('path') + +const componentPaths = glob + .sync('../components/src/components/!(Icons)**/*.docs.mdx', { + cwd: process.cwd(), + absolute: true, + }) + .map((x) => { + const name = path.basename(x, '.docs.mdx') + const route = `/components/${name}` + return { name, route } + }) + +const config = { + images: { + domains: ['images.mirror-media.xyz'], + }, + env: { + navLinks: [ + { + name: 'components', + links: componentPaths, + }, + ], + }, + experimental: { + externalDir: true, + }, + async rewrites() { + // Rewrite playroom urls for production + if (process.env.NODE_ENV === 'production') + return [ + { + source: '/playroom/preview', + destination: '/playroom/preview/index.html', + }, + { + source: '/playroom/frame.html', + destination: '/playroom/frame.html', + }, + { + source: '/playroom', + destination: '/playroom/index.html', + }, + ] + return [] + }, + async redirects() { + if (process.env.NODE_ENV === 'production') return [] + // Redirect playroom to local dev server in development + return [ + { + source: '/playroom', + destination: 'http://localhost:8082', + permanent: false, + }, + ] + }, + pageExtensions: ['mdx', 'tsx'], + reactStrictMode: true, +} + +/** @type {import('next').NextConfig} */ +module.exports = withVanillaExtract(withMDX(config)) diff --git a/ui-docs/package.json b/ui-docs/package.json new file mode 100644 index 0000000..e958bcf --- /dev/null +++ b/ui-docs/package.json @@ -0,0 +1,50 @@ +{ + "name": "docs", + "version": "0.1.0", + "private": true, + "scripts": { + "build": "next build", + "clean": "rimraf .next", + "dev": "next dev", + "lint": "next lint", + "lint:types": "tsc --noEmit", + "start": "next start" + }, + "dependencies": { + "@disco3/ui-components": "^0.0.3", + "@reach/skip-nav": "^0.16.0", + "@sindresorhus/slugify": "^2.1.0", + "@vanilla-extract/css-utils": "^0.1.1", + "copy-to-clipboard": "^3.3.1", + "disco-web3": "^0.0.3", + "gray-matter": "^4.0.3", + "lodash": "^4.17.21", + "next": "12.1.0", + "next-mdx-remote": "^3.0.6", + "nookies": "^2.5.2", + "playroom": "0.27.7", + "prism-react-renderer": "^1.2.1", + "react": "^17.0.2", + "react-docgen-typescript": "^2.1.1", + "react-dom": "^17.0.2", + "react-live": "^2.3.0" + }, + "devDependencies": { + "@mdx-js/loader": "^1.6.22", + "@mdx-js/react": "^1.6.22", + "@next/mdx": "^12.0.1", + "@types/fs-extra": "^9.0.13", + "@types/glob": "^7.2.0", + "@types/lodash": "^4.14.176", + "@types/mdx-js__react": "^1.5.5", + "@types/react": "^17.0.33", + "@types/react-dom": "^17.0.10", + "@types/rimraf": "^3.0.2", + "@vanilla-extract/babel-plugin": "^1.1.2", + "@vanilla-extract/css": "^1.6.3", + "@vanilla-extract/next-plugin": "^1.0.1", + "fs-extra": "^10.0.0", + "glob": "^7.2.0", + "rimraf": "^3.0.2" + } +} diff --git a/ui-docs/public/favicons/apple-touch-icon.png b/ui-docs/public/favicons/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..e1a84ae9817accdd863c235742ff97dee751f847 GIT binary patch literal 2213 zcmeHI`#aN(8~#WX!i$KZRtq_7?+|JZWj1r%9M;rIXk-c#BSw-_Q6YPkY-y8n=#^y3 zmQXq5G?OAOl^hzwDlJ3GyYG+h58wab{o%Rq=f0oozMkuPetB|yuozWkkTL)Os_t$m zKN)lWSDQD=@J1V-E2E9!&fd-dP?xW=7NQ{2V3M1kHvrI#0U#|C09IvI+6(~1!vR1P z3;>8?0N578P#r)nDnc75k_eO7;Qc+Sj0xA76t|@9nmaJ6U>G^Y*&XI&O8X zxLN3UQ*HVYJd8f^;hmW@e;xRHXE7Px$VXJa$~F;Qr#V zK;Db4@=JX=M0M9aVwh=XeXiCl`!beTnP`CM8cyM3ntJq`I_$+-din1_G}aEh=1f#$ zu0gxmP>kX;i}Iniu8!qQyQDnf`?&$RYq2q#F6Qk#k+bDtj@F4c)b zVN_nYtXp^>uBzJ@cJ9{S75xje^Ix*oo(N3LzUD?3jE_#!qJ^)J;pArNyU)M*sB4~X zAp(e(=8sniFtfM3wYYQbLCcVz!Z?gG&PVWifOXa7^fV=M5A95M6)61C>u0Ndzket| zcV@xcd<=Jd#z}N?>6E-lUFy@v;yhjGxJ2P#r_T+>i0^9AN(J=9`*o+h4^9}@xC8NG zfn_iKXXC{rkQI0MIb#1G3l1iFeJgGIT{;CY$QUxv(^yJ8VonlIH&w-D<*@^|Pp#_J z^)Ii8n0<#Oe$8+8BRd7gs?n@!C_UMRe?3Edmu*lLmyyRti>HV5QfCwq9O7m?4gWg2HYs8n?YPpy-C1!i9wxA~F|M7uP?%bJt${!Y2%^8Ai)HiW5XK>= zAo+hS4st(>#zUo7=JmTjLA}&IjwnSNsSjuq?-mfc)Smdn?(-cCpk6uJ3R$z|xP{cP zM6MU_xiTEQ=>kjq^!5j^_F@0_sTrZm2=_tP^c~X~MI~lu!sqOvJsi+4vEGvH6F<8K zR}+-u7%rTg^WrFt6%i(Fp6(#RoK|^|KHmb{V6ZL}5fmxA^U zYA+BQ#Q_hKOCM;3F8kbjhEXItD~@cXO#}xXpW{E0x~Up!y=^R95`0&@9{|IW%bhH2 zI0ek^4#A*e)IQ>0skg97?^*J&PnQJsiZwyD?xNEOBhJ_Mx=1z0i1F&kGc^&lvv`4J zdStnYr2M(PC)Ru`=$O8+e?oob+}zZdi|NP4@^qc@+k-B+Be}MG_m%YG4ZI7jifSs3 zBvVA`+gUX?IVfsj%}J7JRK?GxRkuU5Ig&anN#@;%K2$Ysv59>a3@58}N`JVWFF7=- zzp7sb%3xQR`_^o^w{ogSpI89HDmw;NfiC%_G!&goKD*(vOFyBSHkg=*v;(kRKU^KG zThOnCEgs2872hI%B#!Xt6mz%3_)74)4UewPHZc$URh0WBA84v2ABi-V;D|dv1f?yv z=x%qRw>UAf;&Y^wif1egz+>=cKhDp?*BLrV&L*1;^l8JQh z1=9A1S-l6cOWs0D7gJbYE{EJd$J`sGGN;{g!{tx1Gx6pQ+C9I7M86&l5ScN3zM`;U zr8(I$XomZk%XrM4Siy`m3!wGmr3&abNWLc~K6@b_sN_TZpAzMEBKMZUX*XqrLzul?5@5JwA_fDHc7M*mqg_)KJ9Nc!$RImKHwmk^T? zI)7yFiKtsjn#?aRYyL*R(Uk@sY*rY6#Zx?8U1cvAFruOlQ$s_jVF*%en2Z1`xD^~~ zX$ghz$6MMUtnCnRxH;TXhTv9)$G-wml+cKiN&i3KdkeB83k1;chpB!cXTdSCl#>yW zVPI-fOc*#KhDri}MCRn;md$4fd-inWdV1Zb{Q!B03XG(p1<~@PZlaxq8=cF)Bgcp0tPSu literal 0 HcmV?d00001 diff --git a/ui-docs/public/favicons/favicon-16x16.png b/ui-docs/public/favicons/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..1577c611d19f476d162e250f69715809990f8e66 GIT binary patch literal 477 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YDR+ueoXe|!I#{Xiaj ziKnkC`x9?yz4$pUBaQWu`ihc87b6(g9ugB# z+SuZ$wlArU1(iRB6fMfqu&IjIUIl?AB^nFS@u3=9=>9)IHD zC=AokIOTu(jOWuJ24-b$y<~1-Wnu5hBFw@HE)6D!Q<#-EhbWxBaplC3Ge=~Ou%B-5 cSm33{@Jd{;RG<|Mp00i_>zopr0FGInu>b%7 literal 0 HcmV?d00001 diff --git a/ui-docs/public/favicons/favicon-32x32.png b/ui-docs/public/favicons/favicon-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..3ddf7a17a18e04124ee7077a2e902c0be58c655e GIT binary patch literal 610 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UEa{HEjtmSN`?>!lvVtU&J%W50 z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-G$+Qd;gjJKpuOE zr>`sf6K+m^RmS^;T8|kR7}-5t978;gzrA4X-4w{c_Tc&DmQxe9ct&Y$Sje$trK8I) z#@Gd0cdq2Vq9e4GmG`UnENPvN1zT^%3+M{EOt`vW*?i5cwfjz6vY-1s$9sY9aXZQF zNxtXiu*8Mj+4bpx?xGvp>^bzkU7o&)nwoR_=bKwgtFH!`KRCk9$^OmfArX)lM`mA?J3AGWM^7^z} znvB%j$n~~QPLy2Ep0hu7<9e%<+-uSH<{lC6cl#wc$8em8kYGqSnIkd7+)`k|Bu?g+ z)84;PSH6^(kh7r5dod#mGqa<_kK(oi0uoHl5B?tr&;7v`^HP1ulZ~FsfuW>Y;u=ws zl30>zm0Xkxq!^40j0|)Q4RsAHLkvx=jLoeK47Cjmtqcs>womwnq9HdwB{QuOw}$Vp zG@O7M!mC0eN`ey06$*;-(=u~X6-p`#QWY`_N|G5ED&{=?#KTb-rlE1l|MVHpr$G$N z%G`R%+``Jj-jhX`g%w;HOb(|oD{l@_IDO;Fi6du@$Q)rm-QcmnOON4|xM0aAC)24w PD;PXo{an^LB{Ts5pBmsD literal 0 HcmV?d00001 diff --git a/ui-docs/public/fonts/mono/iAWriterMonoS-Bold.woff2 b/ui-docs/public/fonts/mono/iAWriterMonoS-Bold.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..1271a12acebf5430ebcb496895b692a020c3f31d GIT binary patch literal 37540 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
    xdtBx59o-c02@6Z=} zSFiPiAHKYak8_ZoBUo45W>~MEi%ptK9-VlWGWqV8K=+G!*FJoPTBVzdg=|S41r|Vs zWk6^tqI-HSW#Z19^C&!glth19PzFpYLG(;-Ne*d*dfStve|`qHSMT=m4jO9GZo_^? zgCCC?*75dFg!kvAiCny{j9(OTW#ATw{}LC6ax!#b8S#oA(f&Xzrr!Ubg`iu~Ch>oh zb7PZq_kh--t1Ritm1;6lOffHPdcNxBw93j~AxolosNY<2Fscp# zKbq7Um;7AvlP`T?%`B!=Qts}w9$r;c)z;Y`9e2+{yVzgo()Gj>uGr=0fH>MS5`O)8rwvBl@TS zIrJ%Fk#0K`wvpNK6$;mO`6=8=oOlRxB- zt&^RpTcgz}J)vrM7C#l)`I#M19*fLRMw5-2mp)q+r|a)nPt+PSU7<>c_CZ`)EiqFV zfvPgXXSuxb*!Nwo3qe7&YisY;XqO;(!R31S63NAd{Tbv!63Oqc+&%EM{;-!-+Jvfg zI@%ST*qi8zjy`QHW_;ql{#y8+C57aS!}3*M*KSAGm~++29f z-g>q7`_qf{kIvh%r(M98=;uoadb#Ps;%KI11h@RNLg`_vUVk?Hzd$?XH3z*}amAdNI-) z+g1iZd2KvfnMc|f#Ef;7)pVC;hNPlWHNF?m-9x8M$eS_g7#+0D@(CJ!4>x&7)S}Xm zG_$m(yQ~YgLrtXBy$SK+y{x|S3d72Nn>TmBW>^-=RgT@wHF}%_nXG&hmt)GUEmzY@ zW?u?JzE-oksIAo(626?Jm8i>eYfT&zmzAG6;Bn>}?<&V~LxyDowp?$&&9JhfJge`$ z7l=*nRJd@N3ReDl&_PU4Z>@GWl(-sUtL zPeq@IZZ^2f2)MSjd#rQ$>L9!}EB}9Ob8|6Pu4)K_JuwaEVSkH2OP_UAhBxES2zw}@+s z{mN}rK92Y<#v1k8&Ce6$DQ(v7MLGjN?xCxr=aD(L&mC!RnmcP6)GcXg&U~vmmChW) zqyBqhMr%{FI+n^{x4=_bWIZh}1ygB!e9)3IJ)g1;gRyySz7FfuYlrfh3l7hfRyc0P zXOV`Lwg!;#aB5lAXpMoTI)q;XGIyZRo++&<%2H+Z-cpmw`}$MJ@@2WJ)t(cE_!ob;ipxG%A(B284oeE=2qejR{*)HEL7JSJ<=!XbO7p zRpUn5Q`6jMbH+<4$R8st+knnC|BY@*DoY8)R8NVgVq!yYUUi5Z2Z!wxDCI?^5~axS zDhbIoJn|fcOO+Le&jG3Z9{>-yI$`(&+8=oGqesmO?ZK`1ksZ`?X9T%o1aSbF zx$_S7NiG`PwD9HXO zH-?JaiDk_9w~$g0*aFG>bEKHH=(WsYZ0g`Dsn$dmhI(l+r>+OykNCc%#Sr;MNM1jp zt&1yP~dbyv?YX z-9rBP;k~ES1{U%tgrEnMF>3S#Uz!PtFD7zxB3k=@A&#CY^oS1zwJ{xZsgH{ zpD3NQhN}&7)lojGxcS$G&?+Hm<3s(AJ?BTTM`U7Mg%jx%Y-pWZ^e@e3mhjRo4kk}- zdnH*vk>$oSIhaMl6|Jt1>No!dgP!Lybd6uokpi#Tx$X$2VKND`dxc1o1)q~6_q5)% z6Zkv6QS!*s7O9B#_lp)W7{mq94jKnStgCIQK6<7N5-(y+h<^2Et*TVe{MRK#ek+60 z^?4gRx_&wu0{LYHxxShG;oYE2Nx$(lly>1`3uR@haS{(nZ&YLIN(+TGa?LFl3Z;g} zbNeqT|EHzB^F1*@p`PIHQovve1Y(9Yxtf8r;S*CD^5Xp@6n^I-4{fFXHd1k0Pg@D2 zop@9dDj1xh&9r=|7B!!&11nN?YSqb!NLjx_1C;hyoQ1c(=FsiRLX8htV^g^{(9&X8I zG69sb+{$BFitG+1uzkEsX1MC2>375)d_dZLuHlg64MkZeB_++V5XU@(e5hFV zH5`7BOVg-q$#*TDT5tatuj^vJqnFB|qnnvbuQ_fJ=)3N$B z(*hQcb;&gi`x$vIh~9ZGhf#59vXf*AB3F2ak3_<3@d2|4_Q!yhef%!>no+Mjxs?G=^X1GlA0m z$|*+7G*2IJ2 zAuR9WM@PYa?kd-SQZ>+VGJ*;_a<_O+N2xeE5ldJaWLB#i z*5xpJVnka zhf7g$8S3v4fNUq4k3-P3NajJ1Hm5T!lO@5@ATu#sRNrf#>rdk?UfuYTWuGizS&&;j z)G1OG>~2@g)Z&r*d9hrJ$5vdN;KU0hRsY-?;5ZOLx~CBnSjO_yJ9?;^dZ>cQ1bNeW z)1j8#L{ovFatcngm}4pYaP9==_xu7NaIKav2)?oAUWpt4%|Ob0TK^dF~v^bE+!oF-XK97$eZXy(e`_B;qi^o`X;-; zHo3C_7DDlChHRJ>xThOnX&N{R1Uca}vd8L-%y#kl)H7xHkorC+DJq3C;qIX#(NJ&F07@Cf*(r0Shp1&&DwG2#T~RLo@__!xHrb9Ux3FYryJn}CI| zOoL+%H_V3DdF^y?!@c4}rv2hDr=!5KdDI9Nz;s@i;`6A4u}ZnGIPP%VI3ZRuuZtKR zzG@XXCOHB^Sv6EMn9GFWpT>Y02WYavwYvJw^7dOrzK85gu?tzoL4hrQ6RiSZ)(7~` zkgkST*`F}}>FjTsiDmvAFv~^))|TNm5{E3QLGCA+)sj%h8M}z(k`t zA}*Cti=5044JawyQ=2RIXc<+zfF&Hu;a?AO^93)S$X0z-xtZEgQ9YsGK10*E9j(OS zurhd>K~cXypG^cj4AY!=MF9Z5L@Y1Q#eH_F+h)Oct+Cv1gaepgn3;DiK>6t?KgLa8 zWX7w_ir~rDr{ZhQDeWd2%~x@0f~aMTyki`#;7v1eMw_PkTLgmz-WS_dj7_nAs_iNc zp7HXL){GByP;FKc|j+UtPF*Z~`WaP1o4UIe$ zBM-|z^01T=wLabk?&0Z87Xo!010yp6*+rh%zfahO7ZSd4fvArH*eek%n^m_n1?R|i0TKz9y zytY($x)CIO0eCrM<{MB0l347!BfQv~65jt$0YF~FCnk9lm)OK2l7u86qJh@jtKv!j zAMX4PDB*DILu;quou|lxjN-Mk6{a1pIy)k(p{4iM;}}vBpc&DN@Rwp=)&@+v_~Dhc z>(TCi%xh^!)W(PVdmMKEvUdGA+1mY`q$%vr-23om^vJdDT+Oc!)^{Hc|1{w#>_DAV z_e&rDU;A8(sMg;<(m7+%dpb)D>Q?{;&<2zKA1egi0D$@i$WWdxCZpDyvYz#K_MJ7t zmzkh3P^%@UeDv{`0A6QI#%(0Eer&`5uc+m?yGAo_ zov9$*@%g;Yn#W{KNsgQId7En#3fx68QO}&N*Br&WX<@a930|cRC6(OX`Fzj1VGWg` z+?}ski3A_+L3?1wIDZYTv|^Clt5vBg6%_dnd!;`N;t+2_UN!e)4%eNzUXh<7%O`9# zF&VE?m*9JyvoV}8&IjvzwCMu(H-{5g>2`cy)Ip|7% z7{npoguHF;$A}K}eeZmZ;L~71<%xmYtpPq4RPGsCF5+G_hNvRXXMfg~sM56dPOBd= zh{ji2{tRC(6P=>1VDQdR0>#qisbGJt7RkLz&l#}ltszN*JmE6)wYK)87$t;gl`@Y&l7`;d4ast2@v~zPxS!Tad+QRgd4!WA2xK&Mcx{VG4w@3S`b&lBDZ@ofPR1GZP{Pom z0i5Z?Pjrqm+TS3y5ggPiA_ma{MyoA8*P=?m;#K}|Y-+Bdawu&*^4uX)RccUAl5bka z_JlP7W4snFv#pApmcW=Tp%$vJu*qg_#u>>{z**D=BBjnLnswM13y5=7XcGVGmH2X* zu+_Az0UzWNe4$E|arS3&TS7BArsv49t}#ebq&#^U%jRo21?|u*F#=Al4OfWN#?kK< zBTkz6f$7{cyVt-a-*L*Q*M#dG+Irp9181K`gcr1m2zad;uN?8r(D0K7PMorPQayUs z=ukA1M`kt~P&JR_m^-P)`xx*ES1wu2nk!Ru^%>F3Wi6ZgTO}348O9}$?n=X~g;tyB zEE#(5>+Lqr;s5LoCp%i1enqLKjI?u&IMc(nHLpeOiA)Ut$`+MS#;XVxH@ zE?ra$ULr0fsp;u6MisOgudeB>Y~qkLbaVO6!*FFQH!G6fFfCp_10Eoa_k8?|YrOYs zyLDXWFh;l@Dnu*Bl2Vo+dE@N`y0Lb!&CR*W+F73hUcp(ny=r&XTl4+ahveShn}f#* zvDw|(tvA|;EABCbUzKXY7e%au;{j)J>Pa133Ut;T1`nUKS`xEQG{4LG%W1={5zXKc z*UKsnQf?D1q>#1xm7g3&9n`)YPVGy`a%j@|i8*tUZlb}S&3rnu8CR1kq_$Bq|JyEb z$?C6QvijZAx^RjX<6pM#6&`mB+pn&KMP3`5NHH+4Ioqblm}~64G5J-k`m3l4&|om> zxmNcUH5dHg=l?9EcXqvzqQ2i})nEZh3{+@A=(!A3Q~EPyxXKK7x2)RNGNT5<9|5lo^{oAOsL^!ayHVUSJazzVnqLs(@Gn+;RA z@EAH-*2|FcG24%DM&9z<)s3=xdhG%hPUeNCZN}>2NU?Va8R{UIrZjs<1Q#?sx5*eI z$>TC9Lmx#rYV%RMH}A%F;7w|X?2%Xk@6QnO(qJF!1(b|7LiA-5@~&5eA>@<%?hZ;* z%?Id>{`(h`>v?mqOmK}hKR7aDNkwmov@V5pU|9>uGm-SC?T@8VW&(HIo&>MtusvkO zxVl9TsZ!K#Ws@WSXqET534QgloW^N#2P+Z8K&Rl-MnrhA*A6N9x|KLolsX_l?~_K^ z-T9~w1K%~T;;R+KXxtvK>QHdV19C!1sK^B;8y}hrh?1{AV7kB7_laipCOp+Qnnzu* z)I)*JvSiAMTLy*I3r4jUB^#WqPsE{KKoAhI!IaWpcTQDIG(>Vo5)30X$S8V&wO0OO zxJ)iR$YU*hB^xj`P(gS~K*-6oMsdV!ZBPoTs-5VpEeZl>3(({$9L(?u@`n z{ACt(6U%dCj1g}&;=4A4&{_e#uyiSdUV-*GEDI0Y9;+Ns3)OmovH2EZP3PW_)o)|*5OD-AH;zDzHj0!GV_ zrZEf|thqCi;M&xv0u!ZqO%)*ycV;XIsvcOPi{0xF^4RT3U$_p>%EB>m z;6Oz%+ag6#n-U;sOj$<0w>a;6*)trLfiCd?D)r7f5)4+t=#Xc~J96Bzh6wMhqyc0Q zNWV4uoJD~4M#hEt)k`dT#Sj=%_{}*I12W%ohXejZWgVkXs4{?Tsv?a--nU)Zdcy3^ zE#g@*%^nRCYmZIMd_|tf5mRw4I7}CtqBjbWKze|RQ3YMQfJeV>Y$2jSH7AonGDCg& zqfXSkcrf?&Daa!a5??x1?1+}%ztokSvMtTf%8~t3m_m-~Jykdk6-h6!`9qP^2GYuA zNdyT=#`#FhK*4;hh30V!Q5r%miRgz`{nD1Q@JyZ6hL@8RxDrcC#3V-48pP8N1wbyd zt`k|kW=U)w33NBeKm_HQLU4>R$ujUL6JmPlAIkxq{b z4PA=`{KdXDEbOJka!%=kj**D5T}9G6(~+26nPu4um2zC{$_C_s{HU|ZWJ3NXH7b98 zJRE@MZyvw?P#vBQ_vaJbbGH^`avGo0L=Ea*gc-Y3k{_MUru z=nARlWXVRE2f3NBQWzY$>!I3Fa3Rs+^Nl8qe>|yWNDx00;ZK*Ik+lzvtJ@O@RF#O( z2f!|e#wLz^jB%nj76{ty!l#^U?&*R1HE*O?f87i&lAmsjk{Co#yD67fc~XzlNXcz# zOgIZ&${^Ox2M^Hhj!g9^L?K8f3!0@BCe{p) zmWExhHUbztp>47Bb#C^- z02s{uEDE7du_9vDtNvXw)>Y3;3H(5ua0mmrXk^=h8W|p6rZp~o;bgkw5jftp+vNfd z><^t8L!v#WwpcG8_{STN20ED0qx>Ok+8JI-jWj`S* zT%G)GC8OA)4Eu9h1I^U2qzQ`QbJ3X=>?tJIhJ>z!aj}(IdPJO<5V}F4eY9>ak?;j#8s`;bzxRQmS- zWT6)v@ulX{>%*|wht|s14!aBI=ZSzKhLdWInkLYr zd%gViHu&w~MjDZ=C(Z+HOk$}3hQ{guCyLd2;vuyQ3z7%V1ztwsn`aQKiwq z^W||2tnkpno-C^_z~e+EQhNZRSN8Loy&JS%w0V{$zDKF(KI?C7Ymjd9NwX94rry6u zvm}qBceH%caDu4QuQv&?M{Ro2y`@07++vkPPh&QJfBCAcF|GZX-&lgwSg#_bsfC`wQV(UQD)@`QgRH| zUR62ChS+FhDU{g`m8GO!#gjcAEPK+>O$*`IfLZ`lmv|E@Da97{$gRJ+k&!QU-;I7c zb7N)T$)hzo^K7aKVs+GlQkd?^SO=k40MrI!a?A%g^5EpoP5?6ON7|0H9-wT7<)J!a zkpW87?6sgU9c5S&B}c4uqW!<)70U`coyE=b0C*m9?HOcW{u(9ft4C^jV+s{$U>?lj zY+Gx{iW00@`jx<-V*QA^zrsA%Y{SMw#2baK(#O-*SU6b45xBsnu-eWc2Vdef@&n96noPp!uC?5T;T2B+qsv@uqO^+S*5@u9Hg!QcA z(C6Q%^l~XBaQSZecsj_1?CKKMRF;CyZw6$w5hMabVZsU)ZGW6Iq+jYYWY}5`1t=)J z_}KvAYrNF>wKX3c=av+;O`Ml+cKHa+)ZetQ6`d`%y(tNl1f&cqPYO>SBjBj38CC&1 zVZ5%L_VpQhxC@$?D{KUHNF)o%n-*Ab7ypT2k*8~k0S<&$^y}66=$Vwc z6MvgW{B~4WhOPI0-}g_HP(ly-v7Nvg8U~TX3W6pQV%*b^L5ywcY@^0kLlpLEiTQ;G z8=~b_rSrKdMQknoIGBN7C5sD1YXwWwt2N337R+N@Px~EordqIgL+u9A-D5!rmj>Rc zx;LpZA#H|`K5;5{g^AJTk2kDt>#R@d8(fPk%OzI1sdl<>DN2WQvZjUMEi?EoUHFy^ z;w>uxXj($!{gqr($mWvhuQv~2;d&A+eX6t4!1!YodXz3bNXswPJR4^OI=z{NC^-Fb z%-DeB6_2hbn8-1Ml!&`EJ~~qw*9*1KgU1*a=7R-79IRwGd;9765}Zz%*8o3~O!YHK zr5Hr>PoAl&`2-af8Z3m#gyUt#t=QN9vP>jBI%Z!O?8 zulAK}tA{?b(K0i;6IQl8BaX)lW0*K(F!zA8$HCf=u7x(Nac7hq7-p^h!AgAt7#ghR z`+$mqS_V4u81>y{&FZm3D?q5wD0eM@^-dUHR{<5POgNHHgjKGcYq(N0Fj8@(I|2c4 zqoqI;CL$wbk`o`1e0cql3{3OhO>pKuU>%d8NdQwK-9V#k;^8wdUt&xL*QMD*jcWeD z>CKqM$(Fl7y96KFaw?JOYi&UW9Qc7r-A;y=Wlzr|@N@>r7=`d=VP7)!m!0xfu*JC$ z!Fa%`GrJQ_;}OISoBA^t>`9h5wN0!eW!;($3bj!kNDJwH2Qr~)^b}=k9EySQ)KZe{ zA!R@SWV}Ro-hY}$qrBTKaQnP{I33`I>qBQRh>K}FVl_X6;GiY0$yQkt!`EYjK!qA2 zDje0L!%e8pr=nf3wNrt$$z@39)6p7Xg+6|vZK55DSzkV$jmmB|z}KHYe7bquJe-ek z&DF7DGztUH#Vqj+*wdw!tZP674&e|!b7#xb_F%dQKc*!c=2|3@mKd{f?6I2O z7+6;m(ggf%=MoMHzj#PO)3`PdvbBVA${esjk+(M|5OTyF0jW{3OS61?)Eg2$@1~7r zc(ySwT2=TEvr!>3>uo%!t-sbt0e=5uluGCH2VssXlvo&E~E}FEI{eWxq_o<;YQ7Z z_W{aWV3R5H2;y5nWOR43l{C!497Ax*uYJbobW`A-BIz53MEu6Nj9}3DCo)Tc?K*9; z1}01@!P&T4e9iBK-%Q;aKx;3!ENzI;9awd`)q>qi)T-qZOBd_aom1LihQl|F!*IAL z6G3RIRvaTEf^AE{jg*0lviMo<6{)eb82)>v%#6G}8HEgJHLIt3b@kp3?nP5*8#9UJ!0-pB^J?>51Fa;Rly)I6=A4|AX)ZF#j!r$cpVMLa?cbWV&sai z9ab|zt`I1K2Ct$OpD~TU#hijnX=gx=MPBv&%M9VI0hrQ-Q>hX`n6ZK)FrP=&RcMbp z#q1jz>u~^CZNWQ#6W) zb7_(sg$mV?y@t4tJ%C=$)IU{Ox9PYIF7!MkOOwb>N!qm-#%MB{>`eOO5%&f?d*7Y7bS(=O-<{8yRoE7}XFrs< zlj~2X=pBi0#-QP&V$|r>_tldyLwAN?;5%;|Y4#*CoTCEsp{ZVT+0PhKBm&I>JY!|V z!VBqHic8wSd2_pyDJz3}rmbnF9n6K_3n;w~$$LE!-yD#=Ih2}2U>Ra56&OOat`x5Oex zzwmOP?fO*)WIi?xs~x4Zr`e6L#B=ThJFHiW$*xemXHU;?G|2^*-+Iqq+l}B+$mtiM zS>x?YoQluHXu%p>``?Lslh#DMbIHPqHr5i2ObBbNXp}7PMqUA-$`1DiCVf;tM0_hs zR(Q>himt9(w?t>GTrNy8oM^yuk!Q3a6Xq;)tV4>}6DXk)?(hiNL|%Fj)=X&~FCN8o z&JqKb;EF*l^&KB|>KsWz^7Gwjf%G0g549IeRbMgmr)`hGCIQRumSUEyVk4xK@YUwb zBqb`dAXi;nGi7S+P9#k_m-}^u4CI=Kd;ZmQk|)P@aN~Nbo?nrk1k-$vbvmTDB^-{p z$=gxX9a|`hdy<5hI@2w>%bIXx&-#m!vYR(2C9Wei6NSQZI>Vyh6Vasxq5!X~k?TH! zRwDCfdc0A=XPmQbXL-Llf09WS*Usb1`8A5nGGKOMOu2};626SGm+u@ZEy*V${Lld@D?aBej(yFHAT+B_iHp^C1 z(@dQOJXY;tw^}Z`wxKT8XxfiFUlg-^9E!&MLKp7?ZGM%Yv$c3|=Lhy{PDL?Y>;W-r z)2y}G0?CqXXI&9!&99=cM2Es_N8?ScE8JEh#@_3>0UZZ+m>hy-&j-q{Qo#XRqjWu4q+@PJa+sg!-I z+KdZM6((Us0N;tS-)o-7byAq7vNZ%w*9=tkR+OSkqv{8{Bpd~1id-Fz_;*Mch)B}D z=I;54*XNb$j9_;C^%$TxYC>TN=}R9Cv^iWBti-Fzno=OH`&e=55wV}0Y!n737S@Gh zj&Md))4B6SRb41E?K!-(s64MnmI2v<g|3M3X=%sV~ME(J>m@;!BdrG0W5EdbyE%Xu{9||aKP1V0znFl&^ZB4 z3qHOyp=~3YWwy~hP%%X^JYe-kdAS4RONYiGKc5agx(CI$Bv2hK^5CGERS) zGZ`<(O5c&*V1y3I0Vl<1!V*x60Tkk5S$0({>oQppEFG}^x?}Yv<0q3;WPMKpzGa6x z6PtAezSLc)Q1AuBBZ4*eKJK%Z?V_^Cv33r30z#cX^oL!GRdmW^byy}Kz72{Rn3Bf| z$FL!iq|z>7AH_BV>*-1&wc9>hFl)m>yH^bqYnP`ne@w{=BaZblz&FY zCKhi085}uO_|9~?30dX4knKT_5cWzdxPYQCCs54XH1y4*=rEbn?ryh;N}F>=yLp1P z7R_evr}~mHP{juCyHAcnun(vrqGH8KZ2x^kW?62^KY1`$H5l3P@j5|tAJ6OS@-wCEKpZXY zzn$pNi&$bl)3xI|1SOeb+(H|o7H4g59uTwEXAeUe3RT140N+3WZp_IE!Pby0CRHCm^LQz8RaF%3KFKjm#Hnlt~H)1q5`zacyde@oBMH=ou<= zkbj&__D=-TKOv&>*cL{59f=o!9g0?#+3AABJ;o2?7yxErwRlN{$@P4IVx3KnNsVvzeYV zdPlFn;0xh+W=TIe@FI!kTU+r{d1f0}RchOa>@9M@Rp7qoid8w#nxI2hK{_5T@iaR{ za5l!Mr=gyb)?2tF z5il~OYHms}du*@6ts6BKwv9VxR@@gz2=0Ll^>wSIv354(qTwiVqna>;I@mf#|fe zEdi*gV|mK&!p4GL4N{O>*B-HrbRMY6Ju?crT5Qxogau0_6i!NvcFnc418wuB zjo-91n$MT}y0x+3qW(`0sIlOpwQpJ;?s-dJ!^%!}QUvz~WN5IYi|uH-1#{OoGM63f z>v(jCZT`pBzG>5N&s+c6GrthDc{Fd@_|5$}To=p#3Chhu?Jb!f0AK=GJ!C}0rnrVB z9-H!{hOZMfS=O2I?}~f6>x!WFrX=_+ORWTgVRO>;4la?+57lxGxVEKDManmf27=e3 zdg_iX3Nt>CdstMx1=5l1O9_f>3{{;5?rM##d8&|n-ikK1Oa@GwQOnl2EQ^WYaXC6+ zV|}76t7xwZ-f>zKg4kd!v5DXjuV;;}8m?xCUNTMZb2_+sF7pVyv_>wTb)#t3sBoj) zwM#zI7Zvd;f!9!UlJAn=zn5oYta>1G6&@rwuNcV}MP7!*Eu0FPVpo8I8T#J@KQ-@N z#F9TAPkB3bu7z6B)K%Aov?y?hXxrzudphVwno#0Bhv-&$?t+sWnt;`2LV{PoQ~BTC zBtfu=k^kL%@vPepkGaP*LHAe&#{U=OItJdKcJh|vq!Ie;%vbIu!OOZxqzkY#9Mq4|bC$VY}0RKF0SoGR!lC8r z&3lud?mDQ!uGKvwH6JTSzFuGN(}z?G|9CIsDDYip>@|tv-XPSXIxFdTIstJ%`{?gtzlYdm#o}Pc}B3p*BMNujfsRwh~>7(RzNOy_+oBOeTl^ z`X_Q%P-narZN)nAWe3<%ACtXG5lzcxytQ7TgI`W~Y@?`Mwqxh(qb90L(|wmY{?=x@ zK*Z{i`1_t4vP;%4G0d=cgQP_a)t!*$L(%;N*WcoD;K3x2t9ry@ytn$W$IQdtpgm;u zBaxgpq45(m{8V}uy;ISjz#4qm5}i#9)+ys(>_p?TB^(=|LJbr4dD!6`Q%pRE^($SL zTF*GjYU`=1CaaGz*Ca)TS}qy{n(jfYABgXh*yGw<9?{SW4*}{pb`YGh30<=;?B9(B ziNT3_URyM%rvr~X>{_9Qi}j5YY}?^kmfbn&GKxS_suP`ST+(o0Vwu#ww;8~kcf~pg z<#kWO8LOn*?JWt{bQ(C_DGQ%cPS>6HwEu0_Y{ZFMjY~k*$T>^G;WY+O#yt7+M_nU< z73zCDTsLw3?>x|Px!)kN1E^gL5lIo|nZ-D^OAp0aOi*};2}`YT`x1QrZX7 zmSsUuO7@LbS&?mKC`bc{PBem{Oix4tWf+K3?}8VZGzvTRPMl0>=J;w6`VP}%k*-~N z*2!c~FA#dKvt?zi`F%{`-HY*E>tD7)BB$0*v}i1{Mi+UP(` z)I3lRksT8zu&@utqjruD!OFZAUk5b~)iN0{lknx%S(5J7l^AgPjUwDYgWSe9S0auB zyjQ~BC9DGMu#EUS%txKkgyhB2UgnY5v1RP+_T(d+VuxjG3y0JrD}}vzq^i&;InU!b zXZapg8pN2ITKdQmeNtY^${m(C#1TaX&fnim$i!8L_`6Z zzi=u!M~K(rokCBIB@%Lio9|6J%=yR{Rj72zgHN6Z=ROOT%sBVUZOETAHPjt7PRTUK z(*;B7*KKjNT2P6Fx?)b0_Rl$ZD z+U^!#=&2BK0{o=4H@*SMJ@iy)!j?u$JUwSVJ|$pXAfP4Xe92QNZwLW%&BYBS z$HP=3;wsWjSbSW<3XV7OvW?R?;WXAG1y1$ZcI=FD27A#Tt}%wuI;FgLQ_^kHG^sbc zT^Itphibq6Tgu3xvz~(bK#2UtIN4}Ty$gqNLY(v+)^OQoMwr}Aaet+OTR$#kfDIj!Pa8st3*mh@^hVuj z^Nl0Y7&6jN$IunOrZM*b?uhap%nl2Fbc8R%zQTXNAn8kkKdp|JRy?D|QPkZsbr&c_ zlSRZuZxKL^9bd+f;R-t(+nz`7(0TRNlr<|mHr@Kf+#;Lg$e^2)PU&MbK)zgzcN{DYbb2GqVRuKhW zXU(lANsshb@t>KfemK)h{1)E2Z{sa8%+V4Zn>LzJ-7QhH$-N(!a* z{+JyT93g+M(yp}WwUi8sLLwq(FS|<0bmeqKGvdy+)tUuoz)yvA5R*y`$li0|ly9_Y zuGfoSB7=93PNY4=GhyE}7I)oJM;GK3qM9O)e*otQDS69_sl;q%9seAHq$-;|p00aWxPyD!V;?8MBr`q13f`Z0COgw>}j3Z}ouyz6ythrg0-R zBm&l-4Whv{Zg()8I5JaZSQ#*MsA@dCi5 zG3=<@xUVt_wTU|3;y!)_zBc`XbzN^Op^vTS6Q&^f>GnoOf@Wi6+nQxEkZWJ~WNG>c zb@8xM35Y6OUFA7&^?G&tkI^5xfEm-1AY=I?nsq8IL+eude_ee3e3V0xPU+^f=bGv- zZ*HkKa5|~`El#$v5J2#)!i-N_N$>2qBo<&o&5{(0jdo5O-!n|^6qNFLIX~UK?%JNG zk^`114jGw_)up(4P5R=6Tea^EH{UFm2m#Bd;{JSGE$R|cln0)BxA;5fFF9{Ld4bYC zLo`<4+HLE{`PR0nYnEv12S>QZ2SDX&hc((J+c8?6J939g*;LA0551*W^S zgbCwaH*kG78^1R#zvy@w>^bFml!tE`jkobGi#o^Byy^H}ECzo8_S_gS#r^K5zHTuQ zh{bN${z`C@!blGw#D%uTYVb{8Zx-Vt$)RHC<@KKX3xHqHj0T~!Dno~Mi|ksC?7N(} zn+#;;Kz}Z|Xou2yetn&$2m#l3*GaaUbd@ekfsz5CHL&i6g&S8e8H|IJcMh7q9*;z$ zN*Iroz~RE6kWC$fIYNmGT@g5Zs@?Hi6sZqu;(GgvzAkGAMQ!E{Xs$Rd46bm{zrnx# z`HsOXb#43ptHWQ#NEA`iQ0A!tT@k(^_0Od?z0}yeb$oLj_F)n zAdQBv_N$kmUvYhZJ(N8Su1w4Ct?ncE-|%otPc)0DbAOTz7JOhS~bZcGHfZ zw4M9k;d(d*F6gBgJ;N1A=OBBA>#wz=ia3Aw<@h%E#yII*?>Uz9`{X<0VjM=#xm*kV z!MHI`v*&8VjoUBvugV|Am*Jg#!Jd~V{qfuC;>X^Tlcs&%-|8(rKzxF;{A5YIu&-&M!hx^}N+g}^~`G@-5_{L#h_;=m8bM@-Qi}UlxkMG~Vd-vSj z#*H(Y_h#0tS+QbbVr*=9xW9kVqK=NHreM(HvDvb+M4~9TbH8!#?yZ|wZ@7N#;+0&! zbm4sD-27Q*P9Hy&lP8WHJ#u*eAqNla-j}_5cJ17;eQukrTQ+XCX?A9V_3PHGH9fUr zwN)!8mRmMCw$zgG;l)Nr`iBe-Eb7zS)6sp^)!EeE)YjV4*ic_rTT@*XtPECo3Oxav z+vajQvaDGagHEIt5s#abF`7i4gKd3i(D*xG3xde7`TF5$vEWR>nQv}xO8dWCX5I;o zYV7wx&ZTeZD)x`Khbfh8s@}`jTI4%+ZzpzsaAYdcV^$6)R!s96<2UvG9_)}fTdoJ* ze6~%||0kA*gmPZ&5opu19tP(dKL>-pCL+Auj$YQmDhhkq(TBl81)VjSaiOMjh{!j3 zVctq?z+7#mh31*nFy!+$E73VBLTJrz@5#Q$j%J7j!e*(h3{&$rE=q2wcpmjy0rkw) z+gr73Y1^R4O^39DmzNc55zfXpf-D`G*XZqnV5mB_x)nH^J~#^X<g4eso*yNc=J8&t2O=qi|*}Wlr?NXE=Ao>0lZ#7xEe)_ zKIEO3WjdOmqk|Xgo4u~9k+3ZxBHQU zCtOex-P^tX;I-zPvcp)c?%fD%`kEnRoWxdy?0b5jar(Qv^vGXO>^IN2qcbT`+s#;x zlGNoqUkYgHyr&w6?uPdE4S8Hk7%h3PdT$ncMp$__GtJBHB#Wc?rqAe|9wO%PF#Dmw&MA8{wiB*xH%UJJkM<-Y&8+WPn|C_~SuI|ZjR)AF zlGfizTxYK(yc8D3JEysWazO)1bq&PrNA`l!%DWz~{ZaQ~*>Mcq^h%lBLUD(zc_r{H zi+yF>q~Fn2#+=X3)~Di>9hDW88?}T^x25H2so%_JRoLwFo6`QYCT&dB>0Y{$t|#O2 zH+NHQx|!~zigZ66Psh^9biw=&9;LE$F?+s$(B3qY{LIW*IcRHrxSjNE_`_M(3rTy@ z(ZpHMwAzt##;iw*Ybif(bS>VFUC`*`ne?)+#Ajc+c1bQJD8t8#8I%?`9h_@NSQ_9N znCE?PBtWjCkMgyJ)JHv&Q=hvQV)K|qzIWwSL)t4|K~WH7EAwES(B9_yg`{n185K<_ zjQk}d5B3)L26nN^2nzk3*%3B92NO+u(*}$HgqEIXV&!5ODcZq_ozWv8)G(i=9iF#< zIw+`@gSsZDH-I`ds6&D}BdF6kO_WXt*eBIHWvW2gTKIVxJq!Ag3etb+P+Ab z^uMH+sb+B_Lj4{Q>u)s?FwHbHQJ`7Z_W%{<+K(NiRITTtj4&}aJ_|dY1L%scMj$l? zX1?xj{?6VY%!F*2sS_&;(MS>zM};G(l(0&P<|AG~~({tA)|g zMr|a^gj;yzNG^7!$(jB2Qykb>bQFfleh3p2ag8;ey9@<=qun`K9c7ft{dahi12= zCZb-AtxIu_D#)@e#LgFoQpZ@=G~CC$s@BZ*4Xi}4im4b$lzl3}=4AvpkMvkAjBf6x zYa~Td(la0?lubUzQ|Dl}i^PH(kC!d7CAivV_ZfJ{)HFqdCB6=7}ih28{zURuQt-P%sN-N*;=FAbW4@$ zZcnPZ+cL}FYpMH!%|1*XsPT}=Bac1t)U(Dk*85&~=~d$z-}kRG{={4Fyl;XheGxfn zsMCb@o-zCE3yTI{ee>N9KmGFipMU?`xM}kim1wLzisKuK!O^vG813QK_rM zEe+nio~zuf>${ciGy|tsQt!H3lVrF3#4VUiVLaKN z!6P_?+AgG>Zd%Gk1mXO$fl92{WN|d;zi`sI?1faiW!?oBU2?=xS6%y28eg;{FJ8WS zZS0L$Q}(`l|Ka1O&tLrU*FTMo|J1Cd^=SRzN9PEv=7VURB83i_V!uQNJN{^EldTTe z@~^mV|JSKYH*34CA{CWq@op@#tirp1H$LV3{d*C&+KK;Y3PZwEUluIpvhK&;C{w@8f53TZu{>R5Y^Vmm&Zf@`HA0D5c-@d$i|Ka1O zsC%m_znQxEx$U0!!>#;`UA?S%w<~oe>v`_0QN5xqc_kau zS|`ScMFh2`AiUfBYpmjL#l^ zmW%&4+>spN0W2B{*JXvjHg1o~rPU5H_02c{-eS_uFdvoAdd%&4zvbuJ9nE5II=X>K z-q~sO;i=pZlANvU?apS{DVoy6?pAf$oG;=h$a%k~Dca5=@_d$EP~$i>Pk$yG6P^*;<(`dnIhoFC+>X!)y5H}lgN?U&ijgoA zuA@A~x%p(E!c4_}IE9VHt};_TML37M#{9>x9RpW5jiqF2e>@;<_17KMORs39)LX9m z^NyGeJ8RaM-$ z^VLTfS0q#qC(S1An7N3nVWdV(RofZ^s{a<36U8zGInrySD2~G93MvxXYZpdKI zz~(*gsz3R*0y>kek>s*N+k3&mwIwc#M|<6poXJk*F^DHV^3*>%lC8qzLtX`U^bMEG zqaB(!rE!4>a;Q)zE%?Ozbl6CxzV}0jjv%g;gm*1$1vmRX;Zgrj$lDe3e13}=>;Byff)ca3Cc8PAeeRW=1>%igya+~2vuJ#8si3m zLZa0t9W@>+G@%#uS?66RVIdF$01giIO(v!5z?9u>;7Bx9d~^#y;le>1-2qU+okn_f z4+IOwcr);0Oa0q$zX~!3>CC*2SAMiuPg= zS(nbifdn=C6V&O^3$?dx*y#TBcJP2lVp%T{jA4KMO+w(}QeJn+xiKwqUk%+c39Db={+ zn({wXpZ6B60tyf)oCL`(AYuxLkRUnNCg^DjMR)F{Slfbw!c z4>S8%y$@#TRu0KQp8H(Z(~z0%ky@;jYY`oA5L#gq4q`|H2#Q6T0?jix_Z$+YR7hO$ zKKv%Kfx>#e=e6tusUa4r^St7W?ak}-)Nr_WX1ClwhvT=xmT1L6&2wbW4hMM;qc7uq zDa+N@oUOBecKK1_94SZqgL~1kewN$vt?pC;%IKGRI+Wau$C#2|`ThvsW<0utgYyzV z`F5Bo;(k8(mB-@sAQLKj>?=@xoPOYGI~@xPT@6&zYZ;=#|NXYxo3mR7C6&Kz)EVWm zb@eCPW2$HSa+~ z0a^4z%0xXMk~H@aKDde`SHn4SjtR>e&KuG$B!liP=|mTjRiqsVezkCzb{o=!)1*h) z%c5?33m&v2OsonVU+`Z!I8)k*D7z15qrec(r2?Z4-%hK6lFYw;*zAA;S6=bgs0%R zW}@J`@OKw8axN|^%)l@PcY<+xit};9QD`(16~38p7t%oTM?ONCK=ByLGn+a literal 0 HcmV?d00001 diff --git a/ui-docs/public/fonts/mono/iAWriterMonoS-Italic.woff2 b/ui-docs/public/fonts/mono/iAWriterMonoS-Italic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..c76d4ce4d66425b7f6bb4cf8448d54d450d65d6f GIT binary patch literal 40708 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 z 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 A2mk;8 literal 0 HcmV?d00001 diff --git a/ui-docs/public/logo.svg b/ui-docs/public/logo.svg new file mode 100644 index 0000000..176a318 --- /dev/null +++ b/ui-docs/public/logo.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-docs/public/robots.txt b/ui-docs/public/robots.txt new file mode 100644 index 0000000..eb05362 --- /dev/null +++ b/ui-docs/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: diff --git a/ui-docs/src/components/CodeBlock.tsx b/ui-docs/src/components/CodeBlock.tsx new file mode 100644 index 0000000..7817fcc --- /dev/null +++ b/ui-docs/src/components/CodeBlock.tsx @@ -0,0 +1,121 @@ +import * as React from 'react'; + +import { Box, BoxProps, useTheme } from 'disco-web3'; +import Highlight, { + Language, + PrismTheme, + defaultProps, +} from 'prism-react-renderer'; + +import type { Props as CodePreviewProps } from './CodePreview'; +import { CopyButton } from './CopyButton'; +import { PlayroomStateProvider } from '../../../playroom/src/PlayroomState'; +import dynamic from 'next/dynamic'; +import { useIsMounted } from '~/utils/isMounted'; +import { vars } from 'disco-web3/css'; +import vsDark from 'prism-react-renderer/themes/vsDark'; +import vsLight from 'prism-react-renderer/themes/vsLight'; + +const CodePreview = dynamic( + () => import('./CodePreview').then((mod) => mod.CodePreview), + { + loading: () => ( + + ), + }, +); + +type Props = { + backgroundColor?: BoxProps['backgroundColor']; + children: string; + className: string; + live?: boolean; + expand?: boolean; +}; + +export const CodeBlock = ({ + backgroundColor, + children, + className, + live, + expand, +}: Props) => { + const isMounted = useIsMounted(); + const { mode } = useTheme(); + const theme = mode === 'light' ? vsLight : vsDark; + const modifiedTheme: PrismTheme | undefined = isMounted + ? { + ...theme, + plain: { + ...theme.plain, + color: vars.colors.foreground, + backgroundColor: vars.colors.foregroundTertiary, + }, + } + : undefined; + + const code = children.trim(); + if (live) + return ( + + + + ); + + const language = className?.replace(/language-/, '') as Language; + return ( + + {/* eslint-disable react/no-array-index-key */} + {({ className, style, tokens, getLineProps, getTokenProps }) => ( + + + + + + {tokens.map((line, i) => ( + + {line.map((token, key) => ( + + ))} + + ))} + + )} + {/* eslint-enable react/no-array-index-key */} + + ); +}; diff --git a/ui-docs/src/components/CodePreview/CodePreview.tsx b/ui-docs/src/components/CodePreview/CodePreview.tsx new file mode 100644 index 0000000..18685c0 --- /dev/null +++ b/ui-docs/src/components/CodePreview/CodePreview.tsx @@ -0,0 +1,127 @@ +import './styles.css'; + +import * as Components from 'disco-web3'; +import * as React from 'react'; + +import { Box, Button, Stack, Text, useTheme } from 'disco-web3'; +import { LiveEditor, LiveError, LivePreview, LiveProvider } from 'react-live'; + +import { CopyButton } from '../CopyButton'; +import { default as NextImage } from 'next/image'; +import { default as NextLink } from 'next/link'; +import { PrismTheme } from 'prism-react-renderer'; +import { avatars } from '../../../../playroom/src/useScope'; +import { createPlayroomLink } from '~/utils/playroom'; +import { mdx } from '@mdx-js/react'; +import { usePlayroomStore } from '../../../../playroom/src/PlayroomState'; +import { vars } from 'disco-web3/css'; + +export type Props = { + backgroundColor?: Components.BoxProps['backgroundColor']; + code: string; + expand?: boolean; + theme?: PrismTheme; +}; + +type State = { + expand: boolean; +}; + +const initialState = { + expand: false, +}; + +export const CodePreview = ({ + backgroundColor = 'background', + code, + expand = false, + theme, +}: Props) => { + const previewRef = React.useRef(null); + const [state, setState] = React.useState({ + ...initialState, + expand, + }); + const store = usePlayroomStore(); + const themeValue = useTheme(); + + return ( + '/** @jsx mdx */' + code} + > + + + + + + + + + + {state.expand && ( + + + + + + + + )} + + + + + + + + + + + ); +}; diff --git a/ui-docs/src/components/CodePreview/index.ts b/ui-docs/src/components/CodePreview/index.ts new file mode 100644 index 0000000..c8011f3 --- /dev/null +++ b/ui-docs/src/components/CodePreview/index.ts @@ -0,0 +1,2 @@ +export { CodePreview } from './CodePreview'; +export type { Props } from './CodePreview'; diff --git a/ui-docs/src/components/CodePreview/styles.css.ts b/ui-docs/src/components/CodePreview/styles.css.ts new file mode 100644 index 0000000..6d3596e --- /dev/null +++ b/ui-docs/src/components/CodePreview/styles.css.ts @@ -0,0 +1,22 @@ +import { globalStyle } from '@vanilla-extract/css'; +import { vars } from 'disco-web3/css'; +import type { vars } from '/disco-web3/dist/types/css/vars.css.d.ts'; +import { tokens } from 'disco-web3/css'; + +globalStyle('.npm__react-simple-code-editor__textarea', { + fontFamily: vars.fonts.mono + ' !important', + fontSize: vars.fontSizes.base + ' !important', + padding: vars.space['6'] + ' !important', + paddingRight: vars.space['14'] + ' !important', +}); + +globalStyle('.npm__react-simple-code-editor__textarea:focus-visible', { + outline: 'none', +}); + +globalStyle('.npm__react-simple-code-editor__textarea + pre', { + fontFamily: vars.fonts.mono + ' !important', + fontSize: vars.fontSizes.base + ' !important', + padding: vars.space['6'] + ' !important', + paddingRight: vars.space['14'] + ' !important', +}); diff --git a/ui-docs/src/components/CopyButton.tsx b/ui-docs/src/components/CopyButton.tsx new file mode 100644 index 0000000..f098072 --- /dev/null +++ b/ui-docs/src/components/CopyButton.tsx @@ -0,0 +1,49 @@ +import * as React from 'react'; + +import { Button, IconCheck, IconDuplicate } from 'disco-web3'; + +import { default as copy } from 'copy-to-clipboard'; + +type Props = { + content: string; +}; + +type State = { + copied: boolean; +}; + +const initialState = { + copied: false, +}; + +export const CopyButton = ({ content }: Props) => { + const timeoutRef = React.useRef(); + const [state, setState] = React.useState(initialState); + + const onClick = React.useCallback(() => { + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + setState((x) => ({ ...x, copied: false })); + } + + copy(content, { + format: 'text/plain', + }); + + setState((x) => ({ ...x, copied: true })); + timeoutRef.current = setTimeout( + () => setState((x) => ({ ...x, copied: false })), + 500, + ); + }, [content]); + + return ( + + ); +}; diff --git a/ui-docs/src/components/Header.tsx b/ui-docs/src/components/Header.tsx new file mode 100644 index 0000000..2fbb88f --- /dev/null +++ b/ui-docs/src/components/Header.tsx @@ -0,0 +1,26 @@ +import * as React from 'react'; + +import { Box, Heading, Stack, Text } from 'disco-web3'; + +type Props = { + description?: React.ReactNode; + title: React.ReactNode; +}; + +export const Header = ({ description, title }: Props) => { + return ( + + + + {title} + + + {description && ( + + {description} + + )} + + + ); +}; diff --git a/ui-docs/src/components/Link.tsx b/ui-docs/src/components/Link.tsx new file mode 100644 index 0000000..834b93c --- /dev/null +++ b/ui-docs/src/components/Link.tsx @@ -0,0 +1,52 @@ +import * as React from 'react'; + +import { Box } from 'disco-web3'; +import NextLink from 'next/link'; + +type NextLinkProps = Parameters[0]; + +type Props = { + as?: NextLinkProps['as']; + className?: string; + href: string; +}; + +export const Link = ({ + as, + children, + className, + href, +}: React.PropsWithChildren) => { + const external = !href.startsWith('/'); + if (external) { + return ( + + {children} + + ); + } + + return ( + <> + + + {children} + + + + ); +}; +const canPrefetch = (href: string) => { + if (!href || !href.startsWith('/')) return false; + return true; +}; diff --git a/ui-docs/src/components/MDX.tsx b/ui-docs/src/components/MDX.tsx new file mode 100644 index 0000000..19b0812 --- /dev/null +++ b/ui-docs/src/components/MDX.tsx @@ -0,0 +1,57 @@ +import * as styles from '~/styles/utils.css'; + +import { Box, Heading, Text } from 'disco-web3'; + +import { CodeBlock } from './CodeBlock'; +import { Link } from './Link'; +import { MDXProviderProps } from '@mdx-js/react'; +import { PropsTable } from './PropsTable'; +import { SearchIcons } from './SearchIcons'; +import slugify from '@sindresorhus/slugify'; + +export const MDX: MDXProviderProps['components'] = { + PropsTable, + SearchIcons, + // Default components + // https://mdxjs.com/table-of-components/ + a: (props) => , + code: (props) => , + h2: ({ children }) => { + const id = slugify(children); + return ( + + + + {children} + + # + + + + + ); + }, + inlineCode: ({ children }) => ( + + {children} + + ), + p: ({ children }) => ( + + + {children} + + + ), + pre: (props) => , +}; diff --git a/ui-docs/src/components/Nav.tsx b/ui-docs/src/components/Nav.tsx new file mode 100644 index 0000000..4ee26c2 --- /dev/null +++ b/ui-docs/src/components/Nav.tsx @@ -0,0 +1,145 @@ +import * as React from 'react'; +import * as styles from '~/styles/utils.css'; + +import { Box, Button, Stack, Text } from 'disco-web3'; + +import { Link } from './Link'; +import NextImage from 'next/image'; +import { ThemeSwitcher } from './ThemeSwitcher'; +import { createGitHubLink } from '~/utils/github'; +import { createPlayroomLink } from '~/utils/playroom'; +import { useIsMounted } from '~/utils/isMounted'; +import { useRouter } from 'next/dist/client/router'; + +type Link = { name: string; route: string }; + +export type Props = { + links: { name: string; links: Link[] }[]; +}; + +type State = { + open: boolean; +}; + +const initialState = { + open: false, +}; + +export const Nav = ({ links }: Props) => { + const isMounted = useIsMounted(); + const router = useRouter(); + const [state, setState] = React.useState(initialState); + + // Close menu on route change + /* eslint-disable react-hooks/exhaustive-deps */ + React.useEffect(() => { + const handleRouteChange = () => setState((x) => ({ ...x, open: false })); + router.events.on('routeChangeComplete', handleRouteChange); + return () => { + router.events.off('routeChangeComplete', handleRouteChange); + }; + }, []); + /* eslint-enable react-hooks/exhaustive-deps */ + + return ( + + + + + + + + + + + + + + + + + + + + + GitHub + Playroom + + + + Guides + + Development + Playroom + + + + {links.map((x) => ( + + {x.name} + + + {x.links.map((y) => ( + + {y.name} + + ))} + + + ))} + + + + ); +}; + +const NavLink = ({ + active, + href, + children, +}: React.PropsWithChildren<{ + active?: boolean; + href: string; +}>) => { + return ( + + + + {children} + + + + ); +}; diff --git a/ui-docs/src/components/PropsTable.tsx b/ui-docs/src/components/PropsTable.tsx new file mode 100644 index 0000000..d15e9b8 --- /dev/null +++ b/ui-docs/src/components/PropsTable.tsx @@ -0,0 +1,143 @@ +import * as React from 'react'; + +import { Box, Button, Stack, Text, VisuallyHidden } from 'disco-web3'; + +import { Link } from './Link'; +import { PropItem } from 'react-docgen-typescript'; + +type Props = { + sourceLink?: string; + types: Record; +}; + +const dataProps: Parameters[0] = { + as: 'td', + paddingX: '4', + paddingY: '3', +}; + +export const PropsTable = ({ sourceLink, types }: Props) => { + const [state, setState] = React.useState<{ + showDescriptions: boolean; + }>({ + showDescriptions: Object.values(types).some((x) => x.description !== ''), + }); + + const headers = [ + 'name', + 'type', + 'default', + ...(state.showDescriptions ? ['description'] : []), + ]; + const props = Object.values(types).sort((a, b) => { + if (a.name.startsWith('on') || b.name.startsWith('on')) return 1; + if (a.name < b.name) return -1; + if (a.name > b.name) return 1; + return 0; + }); + + return ( + <> + {props.length ? ( + + + + + {headers.map((x, i) => ( + + + {x} + + + ))} + + + + + {props.map((x) => ( + + + + {x.name} + {x.required && ( + + *Required + + )} + + + + + + {x.type.raw ?? x.type.name} + + + + + + {x.defaultValue?.value.toString() ?? '-'} + + + + {state.showDescriptions && ( + + + {x.description || '-'} + + + )} + + ))} + + + + ) : ( + + No props + + )} + + + + {!!props.length && ( + + )} + + {sourceLink && ( + + + + )} + + + + ); +}; diff --git a/ui-docs/src/components/SearchIcons.tsx b/ui-docs/src/components/SearchIcons.tsx new file mode 100644 index 0000000..215e205 --- /dev/null +++ b/ui-docs/src/components/SearchIcons.tsx @@ -0,0 +1,77 @@ +import * as Components from 'disco-web3'; +import * as React from 'react'; + +import { Box, IconSearch, Input, Stack, Text } from 'disco-web3'; + +import { Link } from '~/components'; + +const icons = Object.entries(Components) + .filter(([k]) => k.includes('Icon')) + .map(([name, Component]) => ({ name, Component })) + .sort((a, b) => (a.name > b.name ? 1 : -1)); + +type State = { + query: string; +}; + +const initialState: State = { + query: '', +}; + +export const SearchIcons = () => { + const [state, setState] = React.useState(initialState); + + const filteredIcons = React.useMemo(() => { + if (!state.query?.length) return icons; + return icons.filter((x) => + x.name.toLowerCase().includes(state.query.toLowerCase()), + ); + }, [state.query]); + + return ( + + } + value={state.query} + onChange={(event) => + setState((x) => ({ ...x, query: event.target.value })) + } + /> + + + {filteredIcons.map((x) => ( + + + + + {React.createElement(x.Component as any, { + size: { xs: '10', md: '12' }, + })} + + + {x.name.replace('Icon', '')} + + + + + ))} + + + ); +}; diff --git a/ui-docs/src/components/SkipNav.tsx b/ui-docs/src/components/SkipNav.tsx new file mode 100644 index 0000000..556bc91 --- /dev/null +++ b/ui-docs/src/components/SkipNav.tsx @@ -0,0 +1,28 @@ +import '@reach/skip-nav/styles.css'; + +import { + SkipNavContent as ReachSkipNavContent, + SkipNavLink as ReachSkipNavLink, + SkipNavLinkProps, +} from '@reach/skip-nav'; + +import { Box } from 'disco-web3'; +import { vars } from 'disco-web3/css'; + +export const SkipNavLink = ({ children, ...rest }: SkipNavLinkProps) => { + return ( + + {children} + + ); +}; + +export const SkipNavContent = ReachSkipNavContent; diff --git a/ui-docs/src/components/ThemeSwitcher.tsx b/ui-docs/src/components/ThemeSwitcher.tsx new file mode 100644 index 0000000..8b1a6c3 --- /dev/null +++ b/ui-docs/src/components/ThemeSwitcher.tsx @@ -0,0 +1,78 @@ +import * as React from 'react'; + +import { + Box, + Button, + Skeleton, + SkeletonGroup, + Stack, + useTheme, +} from 'disco-web3'; +import { setThemeAccent, setThemeMode } from '~/utils/cookies'; + +import { Accent } from 'degen/tokens'; +import { useIsMounted } from '~/utils/isMounted'; + +export const ThemeSwitcher = () => { + // Theme doesn't resolve from localStorage until mounted + // Show skeletons to avoid hydration mismatch error + const isMounted = useIsMounted(); + const { accent, mode, setMode, setAccent } = useTheme(); + + const toggleMode = React.useCallback(() => { + const nextMode = mode === 'dark' ? 'light' : 'dark'; + setMode(nextMode); + setThemeMode(nextMode); + }, [mode, setMode]); + + const toggleAccent = React.useCallback(() => { + const nextAccent = getNextAccent(accent); + setAccent(nextAccent); + setThemeAccent(nextAccent); + }, [accent, setAccent]); + + return ( + + + + + + + + + + + + ); +}; + +const getNextAccent = ( + accent: Accent | 'foreground', +): Accent | 'foreground' => { + switch (accent) { + case 'blue': + return 'green'; + case 'green': + return 'indigo'; + case 'indigo': + return 'orange'; + case 'orange': + return 'pink'; + case 'pink': + return 'purple'; + case 'purple': + return 'red'; + case 'red': + return 'teal'; + case 'teal': + return 'yellow'; + case 'yellow': + return 'foreground'; + case 'foreground': + return 'blue'; + } +}; diff --git a/ui-docs/src/components/index.ts b/ui-docs/src/components/index.ts new file mode 100644 index 0000000..bc30444 --- /dev/null +++ b/ui-docs/src/components/index.ts @@ -0,0 +1,10 @@ +export { CodeBlock } from './CodeBlock'; +export { Header } from './Header'; +export { Link } from './Link'; +export { MDX } from './MDX'; +export { Nav } from './Nav'; +export type { Props as NavProps } from './Nav'; +export { PropsTable } from './PropsTable'; +export { SearchIcons } from './SearchIcons'; +export { SkipNavLink, SkipNavContent } from './SkipNav'; +export { ThemeSwitcher } from './ThemeSwitcher'; diff --git a/ui-docs/src/guides/development.mdx b/ui-docs/src/guides/development.mdx new file mode 100644 index 0000000..97fa08f --- /dev/null +++ b/ui-docs/src/guides/development.mdx @@ -0,0 +1,46 @@ +--- +title: Development +description: Guidelines for working on degen +--- + +## Set Up + +Clone repository, install dependencies, and run docs site and Playroom. + +```bash +gh repo clone mirror-xyz/degen +yarn +yarn dev +``` + +## Adding Components + +Scaffold a new component: + +```bash +yarn gen:component +``` + +Export from `src/index.ts` to make available: + +```ts +export { ComponentName } from './components' +``` + +## Adding Icons + +Add a `.svg` file to `icons` and run: + +```bash +yarn gen:icons +``` + +All files in the `icons` directory are automatically converted to React components and exported for use. Generated icons should follow a 24x24 bounding box. + +## Publishing New Versions + +[Create a new release](https://github.com/mirror-xyz/@disco3/componentsreleases/new) on GitHub with a tag that follows [semantic versioning](https://semver.org/). Publishing a release triggers a workflow for building, testing, and pushing to [npm](https://www.npmjs.com/package/degen). + +## Don’t work at Mirror? + +**Please consider this project read-only.** We’re happy for you to follow along with our work, copy it, fork it, ask us questions on Twitter, etc. but we’re also wanting to minimise the overhead of managing contributions. diff --git a/ui-docs/src/guides/playroom.mdx b/ui-docs/src/guides/playroom.mdx new file mode 100644 index 0000000..0640c1c --- /dev/null +++ b/ui-docs/src/guides/playroom.mdx @@ -0,0 +1,95 @@ +--- +title: Playroom +description: Guidelines for prototyping using Playroom +--- + +## Usage + +Select "Open in Playroom" to get started with the example below. + +```tsx live=true + + + +``` + +With Playroom, you can test different screen sizes and themes, share links to prototypes, and use all system components without needing to import anything. + +## State and Interactivity + +You can control Playroom state and interactivity using the variables and functions that are injected into the global context: + +```ts +// State +setDefaultState(key, value) +getState(key) +setState(key, value) +toggleState(key) +resetState() +// Theme +accent +mode +setAccent(accent) +setMode(mode) +// CSS +vars +``` + +```tsx live=true + + + {getState('counter') != null ? getState('counter') : 2} + + + + + + {getState('counter') != null && getState('counter') !== 2 && ( + + )} + + + + {setDefaultState('counter', 2)} + + +``` diff --git a/ui-docs/src/layouts/docs.tsx b/ui-docs/src/layouts/docs.tsx new file mode 100644 index 0000000..720d0ff --- /dev/null +++ b/ui-docs/src/layouts/docs.tsx @@ -0,0 +1,77 @@ +import * as React from 'react'; + +import { GetLayout, NextLayout } from 'next'; +import { + Header, + Nav, + NavProps, + SkipNavContent, + SkipNavLink, +} from '~/components'; + +import { Box } from 'disco-web3'; +import Head from 'next/head'; +import { getLayout as getBaseLayout } from './site'; + +export type Props = { + meta: { + title: string; + description?: string; + }; +}; + +const Layout: NextLayout = ({ children, meta }) => { + const links = (process.env.navLinks as unknown as NavProps['links']) ?? []; + return ( + <> + + + {meta?.title ? `${meta.title} — Mirror Design` : 'Mirror Design'} + + + + + Skip to content + + + +