Nikhil Rao před 2 roky
revize
e8e8eaa010
100 změnil soubory, kde provedl 5783 přidání a 0 odebrání
  1. 10 0
      .gitignore
  2. 128 0
      CODE_OF_CONDUCT.md
  3. 18 0
      CONTRIBUTING.md
  4. 201 0
      LICENSE
  5. 18 0
      README.md
  6. binární
      docs/images/Counter.gif
  7. binární
      docs/images/logo.png
  8. 0 0
      pynecone/.templates/app/__init__.py
  9. 83 0
      pynecone/.templates/app/tutorial.py
  10. binární
      pynecone/.templates/assets/favicon.ico
  11. 39 0
      pynecone/.templates/web/.gitignore
  12. 3 0
      pynecone/.templates/web/next.config.js
  13. 32 0
      pynecone/.templates/web/package.json
  14. 19 0
      pynecone/.templates/web/pages/404.js
  15. 12 0
      pynecone/.templates/web/pages/_app.js
  16. 93 0
      pynecone/.templates/web/utils/state.js
  17. 12 0
      pynecone/__init__.py
  18. 344 0
      pynecone/app.py
  19. 75 0
      pynecone/base.py
  20. 1 0
      pynecone/compiler/__init__.py
  21. 68 0
      pynecone/compiler/compiler.py
  22. 181 0
      pynecone/compiler/templates.py
  23. 219 0
      pynecone/compiler/utils.py
  24. 91 0
      pynecone/components/__init__.py
  25. 7 0
      pynecone/components/base/__init__.py
  26. 30 0
      pynecone/components/base/bare.py
  27. 12 0
      pynecone/components/base/body.py
  28. 33 0
      pynecone/components/base/document.py
  29. 15 0
      pynecone/components/base/head.py
  30. 21 0
      pynecone/components/base/link.py
  31. 25 0
      pynecone/components/base/title.py
  32. 345 0
      pynecone/components/component.py
  33. 9 0
      pynecone/components/datadisplay/__init__.py
  34. 16 0
      pynecone/components/datadisplay/badge.py
  35. 71 0
      pynecone/components/datadisplay/code.py
  36. 55 0
      pynecone/components/datadisplay/datatable.py
  37. 16 0
      pynecone/components/datadisplay/divider.py
  38. 38 0
      pynecone/components/datadisplay/list.py
  39. 43 0
      pynecone/components/datadisplay/stat.py
  40. 81 0
      pynecone/components/datadisplay/table.py
  41. 12 0
      pynecone/components/disclosure/__init__.py
  42. 60 0
      pynecone/components/disclosure/accordion.py
  43. 70 0
      pynecone/components/disclosure/tabs.py
  44. 7 0
      pynecone/components/feedback/__init__.py
  45. 34 0
      pynecone/components/feedback/alert.py
  46. 40 0
      pynecone/components/feedback/circularprogress.py
  47. 31 0
      pynecone/components/feedback/progress.py
  48. 70 0
      pynecone/components/feedback/skeleton.py
  49. 25 0
      pynecone/components/feedback/spinner.py
  50. 29 0
      pynecone/components/forms/__init__.py
  51. 55 0
      pynecone/components/forms/button.py
  52. 82 0
      pynecone/components/forms/checkbox.py
  53. 69 0
      pynecone/components/forms/editable.py
  54. 46 0
      pynecone/components/forms/formcontrol.py
  55. 34 0
      pynecone/components/forms/iconbutton.py
  56. 82 0
      pynecone/components/forms/input.py
  57. 120 0
      pynecone/components/forms/numberinput.py
  58. 88 0
      pynecone/components/forms/pininput.py
  59. 93 0
      pynecone/components/forms/radio.py
  60. 99 0
      pynecone/components/forms/rangeslider.py
  61. 108 0
      pynecone/components/forms/select.py
  62. 102 0
      pynecone/components/forms/slider.py
  63. 57 0
      pynecone/components/forms/switch.py
  64. 61 0
      pynecone/components/forms/textarea.py
  65. 5 0
      pynecone/components/graphing/__init__.py
  66. 53 0
      pynecone/components/graphing/plotly.py
  67. 14 0
      pynecone/components/layout/__init__.py
  68. 25 0
      pynecone/components/layout/box.py
  69. 21 0
      pynecone/components/layout/center.py
  70. 75 0
      pynecone/components/layout/cond.py
  71. 13 0
      pynecone/components/layout/container.py
  72. 31 0
      pynecone/components/layout/flex.py
  73. 62 0
      pynecone/components/layout/foreach.py
  74. 105 0
      pynecone/components/layout/grid.py
  75. 9 0
      pynecone/components/layout/spacer.py
  76. 46 0
      pynecone/components/layout/stack.py
  77. 15 0
      pynecone/components/layout/wrap.py
  78. 1 0
      pynecone/components/libs/__init__.py
  79. 9 0
      pynecone/components/libs/chakra.py
  80. 7 0
      pynecone/components/media/__init__.py
  81. 69 0
      pynecone/components/media/avatar.py
  82. 15 0
      pynecone/components/media/icon.py
  83. 53 0
      pynecone/components/media/image.py
  84. 8 0
      pynecone/components/navigation/__init__.py
  85. 52 0
      pynecone/components/navigation/breadcrumb.py
  86. 42 0
      pynecone/components/navigation/link.py
  87. 22 0
      pynecone/components/navigation/linkoverlay.py
  88. 22 0
      pynecone/components/navigation/nextlink.py
  89. 50 0
      pynecone/components/overlay/__init__.py
  90. 101 0
      pynecone/components/overlay/alertdialog.py
  91. 107 0
      pynecone/components/overlay/drawer.py
  92. 160 0
      pynecone/components/overlay/menu.py
  93. 101 0
      pynecone/components/overlay/modal.py
  94. 132 0
      pynecone/components/overlay/popover.py
  95. 72 0
      pynecone/components/overlay/tooltip.py
  96. 5 0
      pynecone/components/tags/__init__.py
  97. 35 0
      pynecone/components/tags/cond_tag.py
  98. 90 0
      pynecone/components/tags/iter_tag.py
  99. 196 0
      pynecone/components/tags/tag.py
  100. 22 0
      pynecone/components/tags/tagless.py

+ 10 - 0
.gitignore

@@ -0,0 +1,10 @@
+**/*.pyc
+**/.DS_Store
+**/*.swp
+**/.web
+**/*.db
+**/node_modules/**
+bun.lockb
+poetry.lock
+dist/*
+pynetree/

+ 128 - 0
CODE_OF_CONDUCT.md

@@ -0,0 +1,128 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+We as members, contributors, and leaders pledge to make participation in our
+community a harassment-free experience for everyone, regardless of age, body
+size, visible or invisible disability, ethnicity, sex characteristics, gender
+identity and expression, level of experience, education, socio-economic status,
+nationality, personal appearance, race, religion, or sexual identity
+and orientation.
+
+We pledge to act and interact in ways that contribute to an open, welcoming,
+diverse, inclusive, and healthy community.
+
+## Our Standards
+
+Examples of behavior that contributes to a positive environment for our
+community include:
+
+* Demonstrating empathy and kindness toward other people
+* Being respectful of differing opinions, viewpoints, and experiences
+* Giving and gracefully accepting constructive feedback
+* Accepting responsibility and apologizing to those affected by our mistakes,
+  and learning from the experience
+* Focusing on what is best not just for us as individuals, but for the
+  overall community
+
+Examples of unacceptable behavior include:
+
+* The use of sexualized language or imagery, and sexual attention or
+  advances of any kind
+* Trolling, insulting or derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or email
+  address, without their explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+  professional setting
+
+## Enforcement Responsibilities
+
+Community leaders are responsible for clarifying and enforcing our standards of
+acceptable behavior and will take appropriate and fair corrective action in
+response to any behavior that they deem inappropriate, threatening, offensive,
+or harmful.
+
+Community leaders have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, and will communicate reasons for moderation
+decisions when appropriate.
+
+## Scope
+
+This Code of Conduct applies within all community spaces, and also applies when
+an individual is officially representing the community in public spaces.
+Examples of representing our community include using an official e-mail address,
+posting via an official social media account, or acting as an appointed
+representative at an online or offline event.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported to the community leaders responsible for enforcement at
+opensource@pynecone.io.
+All complaints will be reviewed and investigated promptly and fairly.
+
+All community leaders are obligated to respect the privacy and security of the
+reporter of any incident.
+
+## Enforcement Guidelines
+
+Community leaders will follow these Community Impact Guidelines in determining
+the consequences for any action they deem in violation of this Code of Conduct:
+
+### 1. Correction
+
+**Community Impact**: Use of inappropriate language or other behavior deemed
+unprofessional or unwelcome in the community.
+
+**Consequence**: A private, written warning from community leaders, providing
+clarity around the nature of the violation and an explanation of why the
+behavior was inappropriate. A public apology may be requested.
+
+### 2. Warning
+
+**Community Impact**: A violation through a single incident or series
+of actions.
+
+**Consequence**: A warning with consequences for continued behavior. No
+interaction with the people involved, including unsolicited interaction with
+those enforcing the Code of Conduct, for a specified period of time. This
+includes avoiding interactions in community spaces as well as external channels
+like social media. Violating these terms may lead to a temporary or
+permanent ban.
+
+### 3. Temporary Ban
+
+**Community Impact**: A serious violation of community standards, including
+sustained inappropriate behavior.
+
+**Consequence**: A temporary ban from any sort of interaction or public
+communication with the community for a specified period of time. No public or
+private interaction with the people involved, including unsolicited interaction
+with those enforcing the Code of Conduct, is allowed during this period.
+Violating these terms may lead to a permanent ban.
+
+### 4. Permanent Ban
+
+**Community Impact**: Demonstrating a pattern of violation of community
+standards, including sustained inappropriate behavior,  harassment of an
+individual, or aggression toward or disparagement of classes of individuals.
+
+**Consequence**: A permanent ban from any sort of public interaction within
+the community.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 2.0, available at
+https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
+
+Community Impact Guidelines were inspired by [Mozilla's code of conduct
+enforcement ladder](https://github.com/mozilla/diversity).
+
+[homepage]: https://www.contributor-covenant.org
+
+For answers to common questions about this code of conduct, see the FAQ at
+https://www.contributor-covenant.org/faq. Translations are available at
+https://www.contributor-covenant.org/translations.

+ 18 - 0
CONTRIBUTING.md

@@ -0,0 +1,18 @@
+# Welcome to Pynecone contributing guide! 🥳
+
+## Getting started
+
+To navigate our codebase with confidence, see [Pynecone Docs](https://pynecone.io/docs/getting-started/introduction) :confetti_ball:. 
+
+### Issues
+
+#### Create a new issue
+
+If you spot a problem with anything in Pynecone feel free to create an issue. Even if you are not sure if its a problem with the framework or your own code, create an issue and we will do our best to answer or resolve it.
+
+#### Solve an issue
+
+Scan through our [existing issues](https://github.com/pynecone-io/pynecone/issues) to find one that interests you. You can narrow down the search using `labels` as filters. As a general rule, we don’t assign issues to anyone. If you find an issue to work on, you are welcome to open a PR with a fix. Any large issue changing the compiler of Pynecone should brought to the Pynecone maintainers for approval
+
+Thank you for supporting Pynecone!🎊
+

+ 201 - 0
LICENSE

@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

+ 18 - 0
README.md

@@ -0,0 +1,18 @@
+<div align="center">
+
+<img src="docs/images/logo.png" alt="drawing" width = 450/>
+
+**The easiest way to build and deploy web apps.**
+
+[![PyPI version](https://badge.fury.io/py/pynecone-io.svg)](https://badge.fury.io/py/pynecone-io)
+![versions](https://img.shields.io/pypi/pyversions/pynecone-io.svg)
+[![License](https://img.shields.io/badge/License-Apache_2.0-yellowgreen.svg)](https://opensource.org/licenses/Apache-2.0)  
+
+
+<div align="left">
+
+## Coming Soon
+
+Pynecone is a full-stack python framework that makes it easy to build and deploy web apps in minutes.
+
+

binární
docs/images/Counter.gif


binární
docs/images/logo.png


+ 0 - 0
pynecone/.templates/app/__init__.py


+ 83 - 0
pynecone/.templates/app/tutorial.py

@@ -0,0 +1,83 @@
+"""Welcome to Pynecone! This file outlines the steps to create a basic app."""
+
+# Import pynecone.
+import pcconfig
+
+import pynecone as pc
+
+docs_url = "https://pynecone.io/docs/getting-started/introduction"
+title = "Welcome to Pynecone!"
+filename = f"{pcconfig.APP_NAME}/{pcconfig.APP_NAME}.py"
+
+
+class State(pc.State):
+    """The app state."""
+
+    # The colors to cycle through.
+    colors = ["black", "red", "orange", "yellow", "green", "blue", "purple"]
+
+    # The index of the current color.
+    index = 0
+
+    def next_color(self):
+        """Cycle to the next color."""
+        self.index = (self.index + 1) % len(self.colors)
+
+    @pc.var
+    def color(self):
+        return self.colors[self.index]
+
+
+# Define views.
+def welcome_text():
+    return pc.heading(
+        title,
+        font_size="2.5em",
+        on_click=State.next_color,
+        color=State.color,
+        _hover={"cursor": "pointer"},
+    )
+
+
+def instructions():
+    return pc.box(
+        "Get started by editing ",
+        pc.code(
+            filename,
+            font_size="0.8em",
+        ),
+    )
+
+
+def doclink():
+    return pc.link(
+        "Check out our docs!",
+        href=docs_url,
+        border="0.1em solid",
+        padding="0.5em",
+        _hover={
+            "border_color": State.color,
+            "color": State.color,
+        },
+    )
+
+
+def index():
+    return pc.container(
+        pc.vstack(
+            welcome_text(),
+            instructions(),
+            doclink(),
+            spacing="2em",
+        ),
+        padding_y="5em",
+        font_size="2em",
+        text_align="center",
+        height="100vh",
+    )
+
+
+# Add state and page to the app.
+app = pc.App(state=State)
+app.add_page(index, title=title)
+app.compile()

binární
pynecone/.templates/assets/favicon.ico


+ 39 - 0
pynecone/.templates/web/.gitignore

@@ -0,0 +1,39 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+/_static
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+
+# testing
+/coverage
+
+# next.js
+/.next/
+/out/
+
+# production
+/build
+
+# misc
+.DS_Store
+*.pem
+
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# local env files
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+
+# vercel
+.vercel
+
+# DS_Store
+.DS_Store

+ 3 - 0
pynecone/.templates/web/next.config.js

@@ -0,0 +1,3 @@
+module.exports = {
+  reactStrictMode: true
+};

+ 32 - 0
pynecone/.templates/web/package.json

@@ -0,0 +1,32 @@
+{
+  "name": "pynecone",
+  "scripts": {
+    "dev": "next dev",
+    "export": "next build && next export -o _static",
+    "prod": "next start"
+  },
+  "dependencies": {
+    "@chakra-ui/icons": "^2.0.10",
+    "@chakra-ui/react": "1.8.8",
+    "@emotion/react": "^11.9.0",
+    "@emotion/styled": "^11.8.1",
+    "axios": "^0.27.2",
+    "focus-visible": "^5.2.0",
+    "framer-motion": "^6.3.3",
+    "gridjs": "^4.0.0",
+    "gridjs-react": "^4.0.0",
+    "next": "^12.1.0",
+    "plotly.js": "2.6.4",
+    "prettier": "^2.7.1",
+    "react": "^17.0.2",
+    "react-confetti": "^6.1.0",
+    "react-copy-to-clipboard": "^5.1.0",
+    "react-dom": "^17.0.2",
+    "react-markdown": "^8.0.3",
+    "react-plotly.js": "^2.6.0",
+    "react-syntax-highlighter": "^15.5.0",
+    "rehype-katex": "^6.0.2",
+    "remark-gfm": "^3.0.1",
+    "remark-math": "^5.1.1"
+  }
+}

+ 19 - 0
pynecone/.templates/web/pages/404.js

@@ -0,0 +1,19 @@
+import Router from "next/router";
+import { useEffect, useState } from "react";
+
+export default function Custom404() {
+  const [isNotFound, setIsNotFound] = useState(false);
+
+  useEffect(() => {
+    const pathNameArray = window.location.pathname.split("/");
+    if (pathNameArray.length == 2 && pathNameArray[1] == "404") {
+      setIsNotFound(true);
+    } else {
+      Router.replace(window.location.pathname);
+    }
+  }, []);
+
+  if (isNotFound) return <h1>404 - Page Not Found</h1>;
+
+  return null;
+}

+ 12 - 0
pynecone/.templates/web/pages/_app.js

@@ -0,0 +1,12 @@
+import { ChakraProvider, extendTheme } from "@chakra-ui/react";
+import theme from "/utils/theme";
+
+function MyApp({ Component, pageProps }) {
+  return (
+    <ChakraProvider theme={extendTheme(theme)}>
+      <Component {...pageProps} />
+    </ChakraProvider>
+  );
+}
+
+export default MyApp;

+ 93 - 0
pynecone/.templates/web/utils/state.js

@@ -0,0 +1,93 @@
+import axios from "axios";
+
+let token;
+const TOKEN_KEY = "token";
+
+const generateUUID = () => {
+  let d = new Date().getTime(),
+    d2 = (performance && performance.now && performance.now() * 1000) || 0;
+  return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
+    let r = Math.random() * 16;
+    if (d > 0) {
+      r = (d + r) % 16 | 0;
+      d = Math.floor(d / 16);
+    } else {
+      r = (d2 + r) % 16 | 0;
+      d2 = Math.floor(d2 / 16);
+    }
+    return (c == "x" ? r : (r & 0x7) | 0x8).toString(16);
+  });
+};
+
+export const getToken = () => {
+  if (token) {
+    return token;
+  }
+  if (window) {
+    if (!window.sessionStorage.getItem(TOKEN_KEY)) {
+      window.sessionStorage.setItem(TOKEN_KEY, generateUUID());
+    }
+    token = window.sessionStorage.getItem(TOKEN_KEY);
+  }
+  return token;
+};
+
+export const applyDelta = (state, delta) => {
+  for (const substate in delta) {
+    let s = state;
+    const path = substate.split(".").slice(1);
+    while (path.length > 0) {
+      s = s[path.shift()];
+    }
+    for (const key in delta[substate]) {
+      s[key] = delta[substate][key];
+    }
+  }
+};
+
+export const applyEvent = async (state, event, endpoint, router) => {
+  // Handle special events
+  if (event.name == "_redirect") {
+    router.push(event.payload.path);
+    return [];
+  }
+
+  if (event.name == "_console") {
+    console.log(event.payload.message);
+    return [];
+  }
+
+  if (event.name == "_alert") {
+    alert(event.payload.message);
+    return [];
+  }
+
+  event.token = getToken();
+  const update = (await axios.post(endpoint, event)).data;
+  applyDelta(state, update.delta);
+  return update.events;
+};
+
+export const updateState = async (
+  state,
+  result,
+  setResult,
+  endpoint,
+  router
+) => {
+  if (result.processing || state.events.length == 0) {
+    return;
+  }
+  setResult({ ...result, processing: true });
+  const events = await applyEvent(
+    state,
+    state.events.shift(),
+    endpoint,
+    router
+  );
+  setResult({
+    state: state,
+    events: events,
+    processing: true,
+  });
+};

+ 12 - 0
pynecone/__init__.py

@@ -0,0 +1,12 @@
+"""Import all classes and functions the end user will need to make an app.
+
+Anything imported here will be available in the default Pynecone import as `pc.*`.
+"""
+
+from .app import App
+from .base import Base
+from .components import *
+from .event import console_log, redirect, window_alert
+from .model import Model, session
+from .state import ComputedVar as var
+from .state import State

+ 344 - 0
pynecone/app.py

@@ -0,0 +1,344 @@
+"""The main Pynecone app."""
+
+import re
+from typing import Any, Callable, Coroutine, Dict, List, Optional, Tuple, Type, Union
+
+import fastapi
+from fastapi.middleware import cors
+
+from pynecone import constants, utils
+from pynecone.base import Base
+from pynecone.compiler import compiler
+from pynecone.compiler import utils as compiler_utils
+from pynecone.components.component import Component, ComponentStyle
+from pynecone.event import Event
+from pynecone.middleware import HydrateMiddleware, LoggingMiddleware, Middleware
+from pynecone.model import Model
+from pynecone.state import DefaultState, Delta, State, StateManager, StateUpdate
+
+# Define custom types.
+ComponentCallable = Callable[[], Component]
+Reducer = Callable[[Event], Coroutine[Any, Any, StateUpdate]]
+
+
+class App(Base):
+    """A Pynecone application."""
+
+    # A map from a page route to the component to render.
+    pages: Dict[str, Component] = {}
+
+    # A list of URLs to stylesheets to include in the app.
+    stylesheets: List[str] = []
+
+    # The backend API object.
+    api: fastapi.FastAPI = None  # type: ignore
+
+    # The state class to use for the app.
+    state: Type[State] = DefaultState
+
+    # Class to manage many client states.
+    state_manager: StateManager = StateManager()
+
+    # The styling to apply to each component.
+    style: ComponentStyle = {}
+
+    # Middleware to add to the app.
+    middleware: List[Middleware] = []
+
+    def __init__(self, *args, **kwargs):
+        """Initialize the app.
+
+        Args:
+            *args: Args to initialize the app with.
+            **kwargs: Kwargs to initialize the app with.
+        """
+        super().__init__(*args, **kwargs)
+
+        # Add middleware.
+        self.middleware.append(HydrateMiddleware())
+        self.middleware.append(LoggingMiddleware())
+
+        # Set up the state manager.
+        self.state_manager.set(state=self.state)
+
+        # Set up the API.
+        self.api = fastapi.FastAPI()
+        self.add_cors()
+        self.add_default_endpoints()
+
+    def __repr__(self) -> str:
+        """Get the string representation of the app.
+
+        Returns:
+            The string representation of the app.
+        """
+        return f"<App state={self.state.__name__}>"
+
+    def add_default_endpoints(self):
+        """Add the default endpoints."""
+        # To test the server.
+        self.get(str(constants.Endpoint.PING))(_ping)
+
+        # To make state changes.
+        self.post(str(constants.Endpoint.EVENT))(_event(app=self))
+
+    def add_cors(self):
+        """Add CORS middleware to the app."""
+        self.api.add_middleware(
+            cors.CORSMiddleware,
+            allow_origins=["*"],
+            allow_methods=["*"],
+            allow_headers=["*"],
+        )
+
+    def get(self, path: str, *args, **kwargs) -> Callable:
+        """Register a get request.
+
+        Args:
+            path: The endpoint path to link to the request.
+            *args: Args to pass to the request.
+            **kwargs: Kwargs to pass to the request.
+
+        Returns:
+            A decorator to handle the request.
+        """
+        return self.api.get(path, *args, **kwargs)
+
+    def post(self, path: str, *args, **kwargs) -> Callable:
+        """Register a post request.
+
+        Args:
+            path: The endpoint path to link to the request.
+            *args: Args to pass to the request.
+            **kwargs: Kwargs to pass to the request.
+
+        Returns:
+            A decorator to handle the request.
+        """
+        return self.api.post(path, *args, **kwargs)
+
+    def preprocess(self, state: State, event: Event) -> Optional[Delta]:
+        """Preprocess the event.
+
+        This is where middleware can modify the event before it is processed.
+        Each middleware is called in the order it was added to the app.
+
+        If a middleware returns a delta, the event is not processed and the
+        delta is returned.
+
+        Args:
+            state: The state to preprocess.
+            event: The event to preprocess.
+
+        Returns:
+            An optional state to return.
+        """
+        for middleware in self.middleware:
+            out = middleware.preprocess(app=self, state=state, event=event)
+            if out is not None:
+                return out
+
+    def postprocess(self, state: State, event: Event, delta: Delta) -> Optional[Delta]:
+        """Postprocess the event.
+
+        This is where middleware can modify the delta after it is processed.
+        Each middleware is called in the order it was added to the app.
+
+        If a middleware returns a delta, the delta is not processed and the
+        delta is returned.
+
+        Args:
+            state: The state to postprocess.
+            event: The event to postprocess.
+            delta: The delta to postprocess.
+
+        Returns:
+            An optional state to return.
+        """
+        for middleware in self.middleware:
+            out = middleware.postprocess(
+                app=self, state=state, event=event, delta=delta
+            )
+            if out is not None:
+                return out
+
+    def add_page(
+        self,
+        component: Union[Component, ComponentCallable],
+        path: Optional[str] = None,
+        title: str = constants.DEFAULT_TITLE,
+    ):
+        """Add a page to the app.
+
+        If the component is a callable, by default the route is the name of the
+        function. Otherwise, a route must be provided.
+
+        Args:
+            component: The component to display at the page.
+            path: The path to display the component at.
+            title: The title of the page.
+        """
+        # If the path is not set, get it from the callable.
+        if path is None:
+            assert isinstance(
+                component, Callable
+            ), "Path must be set if component is not a callable."
+            path = component.__name__
+
+        from pynecone.var import BaseVar
+
+        parts = path.split("/")
+        check = re.compile(r"^\[(.+)\]$")
+        args = []
+        for part in parts:
+            match = check.match(part)
+            if match:
+                v = BaseVar(
+                    name=match.groups()[0],
+                    type_=str,
+                    state="router.query",
+                )
+                args.append(v)
+
+        # Generate the component if it is a callable.
+        component = component if isinstance(component, Component) else component(*args)
+
+        # Add the title to the component.
+        compiler_utils.add_title(component, title)
+
+        # Format the route.
+        route = utils.format_route(path)
+
+        # Add the page.
+        self.pages[route] = component
+
+    def compile(self, ignore_env: bool = False):
+        """Compile the app and output it to the pages folder.
+
+        If the pcconfig environment is set to production, the app will
+        not be compiled.
+
+        Args:
+            ignore_env: Whether to ignore the pcconfig environment.
+        """
+        # Get the env mode.
+        config = utils.get_config()
+        if not ignore_env and config.ENV != constants.Env.DEV.value:
+            print("Skipping compilation in non-dev mode.")
+            return
+
+        # Create the database models.
+        Model.create_all()
+
+        # Create the root document with base styles and fonts.
+        self.pages[constants.DOCUMENT_ROOT] = compiler_utils.create_document_root(
+            self.stylesheets
+        )
+        self.pages[constants.THEME] = compiler_utils.create_theme(self.style)  # type: ignore
+
+        # Compile the pages.
+        for path, component in self.pages.items():
+            path, code = self.compile_page(path, component)
+
+    def compile_page(
+        self, path: str, component: Component, write: bool = True
+    ) -> Tuple[str, str]:
+        """Compile a single page.
+
+        Args:
+            path: The path to compile the page to.
+            component: The component to compile.
+            write: Whether to write the page to the pages folder.
+
+        Returns:
+            The path and code of the compiled page.
+        """
+        # Get the path for the output file.
+        output_path = utils.get_page_path(path)
+
+        # Compile the document root.
+        if path == constants.DOCUMENT_ROOT:
+            code = compiler.compile_document_root(component)
+
+        # Compile the theme.
+        elif path == constants.THEME:
+            output_path = utils.get_theme_path()
+            code = compiler.compile_theme(component)  # type: ignore
+
+        # Compile all other pages.
+        else:
+            # Add the style to the component.
+            component.add_style(self.style)
+            code = compiler.compile_component(
+                component=component,
+                state=self.state,
+            )
+
+        # Write the page to the pages folder.
+        if write:
+            utils.write_page(output_path, code)
+
+        return output_path, code
+
+    def get_state(self, token: str) -> State:
+        """Get the state for a token.
+
+        Args:
+            token: The token to get the state for.
+
+        Returns:
+            The state for the token.
+        """
+        return self.state_manager.get_state(token)
+
+    def set_state(self, token: str, state: State):
+        """Set the state for a token.
+
+        Args:
+            token: The token to set the state for.
+            state: The state to set.
+        """
+        self.state_manager.set_state(token, state)
+
+
+async def _ping() -> str:
+    """Test API endpoint.
+
+    Returns:
+        The response.
+    """
+    return "pong"
+
+
+def _event(app: App) -> Reducer:
+    """Create an event reducer to modify the state.
+
+    Args:
+        app: The app to modify the state of.
+
+    Returns:
+        A handler that takes in an event and modifies the state.
+    """
+
+    async def process(event: Event) -> StateUpdate:
+        # Get the state for the session.
+        state = app.get_state(event.token)
+
+        # Preprocess the event.
+        pre = app.preprocess(state, event)
+        if pre is not None:
+            return StateUpdate(delta=pre)
+
+        # Apply the event to the state.
+        update = await state.process(event)
+        app.set_state(event.token, state)
+
+        # Postprocess the event.
+        post = app.postprocess(state, event, update.delta)
+        if post is not None:
+            return StateUpdate(delta=post)
+
+        # Return the delta.
+        return update
+
+    return process

+ 75 - 0
pynecone/base.py

@@ -0,0 +1,75 @@
+"""Define the base Pynecone class."""
+from __future__ import annotations
+
+from typing import Any, Dict, TypeVar
+
+import pydantic
+
+# Typevar to represent any class subclassing Base.
+PcType = TypeVar("PcType")
+
+
+class Base(pydantic.BaseModel):
+    """The base class subclassed by all Pynecone classes.
+
+    This class wraps Pydantic and provides common methods such as
+    serialization and setting fields.
+
+    Any data structure that needs to be transferred between the
+    frontend and backend should subclass this class.
+    """
+
+    class Config:
+        """Pydantic config."""
+
+        arbitrary_types_allowed = True
+
+    def json(self) -> str:
+        """Convert the object to a json string.
+
+        Returns:
+            The object as a json string.
+        """
+        return self.__config__.json_dumps(self.dict())
+
+    def set(self: PcType, **kwargs) -> PcType:
+        """Set multiple fields and return the object.
+
+        Args:
+            **kwargs: The fields and values to set.
+
+        Returns:
+            The object with the fields set.
+        """
+        for key, value in kwargs.items():
+            setattr(self, key, value)
+        return self
+
+    @classmethod
+    def get_fields(cls) -> Dict[str, Any]:
+        """Get the fields of the object.
+
+        Returns:
+            The fields of the object.
+        """
+        return cls.__fields__
+
+    def get_value(self, key: str) -> Any:
+        """Get the value of a field.
+
+        Args:
+            key: The key of the field.
+
+        Returns:
+            The value of the field.
+        """
+        return self._get_value(
+            key,
+            to_dict=True,
+            by_alias=False,
+            include=None,
+            exclude=None,
+            exclude_unset=False,
+            exclude_defaults=False,
+            exclude_none=False,
+        )

+ 1 - 0
pynecone/compiler/__init__.py

@@ -0,0 +1 @@
+"""The Pynecone compiler."""

+ 68 - 0
pynecone/compiler/compiler.py

@@ -0,0 +1,68 @@
+"""Compiler for the pynecone apps."""
+
+import json
+from typing import Type
+
+from pynecone import constants
+from pynecone.compiler import templates, utils
+from pynecone.components.component import Component, ImportDict
+from pynecone.state import State
+
+# Imports to be included in every Pynecone app.
+DEFAULT_IMPORTS: ImportDict = {
+    "react": {"useEffect", "useState"},
+    "next/router": {"useRouter"},
+    f"/{constants.STATE_PATH}": {"updateState"},
+}
+
+
+def compile_document_root(root: Component) -> str:
+    """Compile the document root.
+
+    Args:
+        root: The document root to compile.
+
+    Returns:
+        The compiled document root.
+    """
+    return templates.DOCUMENT_ROOT(
+        imports=utils.compile_imports(root.get_imports()),
+        document=root.render(),
+    )
+
+
+def compile_theme(theme: dict) -> str:
+    """Compile the theme.
+
+    Args:
+        theme: The theme to compile.
+
+    Returns:
+        The compiled theme.
+    """
+    return templates.THEME(theme=json.dumps(theme))
+
+
+def compile_component(component: Component, state: Type[State]) -> str:
+    """Compile the component given the app state.
+
+    Args:
+        component: The component to compile.
+        state: The app state.
+
+    Returns:
+        The compiled component.
+    """
+    # Merge the default imports with the app-specific imports.
+    imports = utils.merge_imports(DEFAULT_IMPORTS, component.get_imports())
+
+    # Compile the code to render the component.
+    return templates.COMPONENT(
+        imports=utils.compile_imports(imports),
+        custom_code=component.get_custom_code(),
+        constants=utils.compile_constants(),
+        state=utils.compile_state(state),
+        events=utils.compile_events(state),
+        effects=utils.compile_effects(state),
+        render=component.render(),
+    )

+ 181 - 0
pynecone/compiler/templates.py

@@ -0,0 +1,181 @@
+"""Templates to use in the pynecone compiler."""
+
+from typing import Callable, Optional, Set
+
+from pynecone import constants, utils
+from pynecone.utils import join
+
+# Template for the Pynecone config file.
+PCCONFIG = f"""# The Pynecone configuration file.
+
+APP_NAME = "{{app_name}}"
+API_HOST = "http://localhost:8000"
+BUN_PATH = "$HOME/.bun/bin/bun"
+ENV = "{constants.Env.DEV.value}"
+DB_URI = "sqlite:///{constants.DB_NAME}"
+"""
+
+# Javascript formatting.
+CONST = "const {name} = {value}".format
+PROP = "{object}.{property}".format
+IMPORT_LIB = 'import "{lib}"'.format
+IMPORT_FIELDS = 'import {default}{others} from "{lib}"'.format
+
+
+def format_import(lib: str, default: str = "", rest: Optional[Set[str]] = None) -> str:
+    """Format an import statement.
+
+    Args:
+        lib: The library to import from.
+        default: The default field to import.
+        rest: The set of fields to import from the library.
+
+    Returns:
+        The compiled import statement.
+    """
+    # Handle the case of direct imports with no libraries.
+    if lib == "":
+        assert default == "", "No default field allowed for empty library."
+        assert rest is not None and len(rest) > 0, "No fields to import."
+        return join([IMPORT_LIB(lib=lib) for lib in sorted(rest)])
+
+    # Handle importing from a library.
+    rest = rest or set()
+    if len(default) == 0 and len(rest) == 0:
+        # Handle the case of importing a library with no fields.
+        return IMPORT_LIB(lib=lib)
+    else:
+        # Handle importing specific fields from a library.
+        others = f'{{{", ".join(sorted(rest))}}}' if len(rest) > 0 else ""
+        if len(default) > 0 and len(rest) > 0:
+            default += ", "
+        return IMPORT_FIELDS(default=default, others=others, lib=lib)
+
+
+# Code to render a NextJS Document root.
+DOCUMENT_ROOT = join(
+    [
+        "{imports}",
+        "",
+        "export default function Document() {{",
+        "",
+        "return (",
+        "{document}",
+        ")",
+        "}}",
+    ]
+).format
+
+# Template for the theme file.
+THEME = "export default {theme}".format
+
+# Code to render a single NextJS component.
+COMPONENT = join(
+    [
+        "{imports}",
+        "{custom_code}",
+        "",
+        "{constants}",
+        "",
+        "export default function Component() {{",
+        "",
+        "{state}",
+        "",
+        "{events}",
+        "",
+        "{effects}",
+        "",
+        "return (",
+        "{render}",
+        ")",
+        "}}",
+    ]
+).format
+
+# React state declarations.
+USE_STATE = CONST(
+    name="[{state}, {set_state}]", value="useState({initial_state})"
+).format
+
+
+def format_state_setter(state: str) -> str:
+    """Format a state setter.
+
+    Args:
+        state: The name of the state variable.
+
+    Returns:
+        The compiled state setter.
+    """
+    return f"set{state[0].upper() + state[1:]}"
+
+
+def format_state(
+    state: str,
+    initial_state: str,
+) -> str:
+    """Format a state declaration.
+
+    Args:
+        state: The name of the state variable.
+        initial_state: The initial state of the state variable.
+
+    Returns:
+        The compiled state declaration.
+    """
+    set_state = format_state_setter(state)
+    return USE_STATE(state=state, set_state=set_state, initial_state=initial_state)
+
+
+# Events.
+EVENT_ENDPOINT = constants.Endpoint.EVENT.name
+EVENT_FN = join(
+    [
+        "const E = (name, payload) => {{ return {{name, payload}} }}",
+        "const Event = events => {set_state}({{",
+        "  ...{state},",
+        "  events: [...{state}.events, ...events],",
+        "}})",
+    ]
+).format
+
+
+def format_event_declaration(fn: Callable) -> str:
+    """Format an event declaration.
+
+    Args:
+        fn: The function to declare.
+
+    Returns:
+        The compiled event declaration.
+    """
+    name = utils.format_event_fn(fn=fn)
+    event = utils.to_snake_case(fn.__qualname__)
+    return f"const {name} = Event('{event}')"
+
+
+# Effects.
+USE_EFFECT = join(
+    [
+        "useEffect(() => {{",
+        "  const update = async () => {{",
+        "    if (result.state != null) {{",
+        "      setState({{",
+        "        ...result.state,",
+        "        events: [...state.events, ...result.events],",
+        "      }})",
+        "      setResult({{",
+        "        ...result,",
+        "        state: null,",
+        "       processing: false,",
+        "      }})",
+        "    }}",
+        f"    await updateState({{state}}, {{result}}, {{set_result}}, {EVENT_ENDPOINT}, {constants.ROUTER})",
+        "  }}",
+        "  update()",
+        "}})",
+    ]
+).format
+
+# Routing
+ROUTER = f"const {constants.ROUTER} = useRouter()"

+ 219 - 0
pynecone/compiler/utils.py

@@ -0,0 +1,219 @@
+"""Common utility functions used in the compiler."""
+
+from __future__ import annotations
+
+import json
+from typing import TYPE_CHECKING, Dict, Set, Type
+
+from pynecone import constants, utils
+from pynecone.compiler import templates
+from pynecone.components.base import (
+    Body,
+    DocumentHead,
+    Head,
+    Html,
+    Link,
+    Main,
+    Script,
+    Title,
+)
+from pynecone.components.component import ImportDict
+from pynecone.state import State
+from pynecone.style import Style
+
+if TYPE_CHECKING:
+    from pynecone.components.component import Component
+
+
+# To re-export this function.
+merge_imports = utils.merge_imports
+
+
+def compile_import_statement(lib: str, fields: Set[str]) -> str:
+    """Compile an import statement.
+
+    Args:
+        lib: The library to import from.
+        fields: The set of fields to import from the library.
+
+    Returns:
+        The compiled import statement.
+    """
+    # Check for default imports.
+    defaults = {
+        field
+        for field in fields
+        if field.lower() == lib.lower().replace("-", "").replace("/", "")
+    }
+    assert len(defaults) < 2
+
+    # Get the default import, and the specific imports.
+    default = next(iter(defaults), "")
+    rest = fields - defaults
+    return templates.format_import(lib=lib, default=default, rest=rest)
+
+
+def compile_imports(imports: ImportDict) -> str:
+    """Compile an import dict.
+
+    Args:
+        imports: The import dict to compile.
+
+    Returns:
+        The compiled import dict.
+    """
+    return templates.join(
+        [compile_import_statement(lib, fields) for lib, fields in imports.items()]
+    )
+
+
+def compile_constant_declaration(name: str, value: str) -> str:
+    """Compile a constant declaration.
+
+    Args:
+        name: The name of the constant.
+        value: The value of the constant.
+
+    Returns:
+        The compiled constant declaration.
+    """
+    return templates.CONST(name=name, value=json.dumps(value))
+
+
+def compile_constants() -> str:
+    """Compile all the necessary constants.
+
+    Returns:
+        A string of all the compiled constants.
+    """
+    endpoint = constants.Endpoint.EVENT
+    return templates.join(
+        [compile_constant_declaration(name=endpoint.name, value=endpoint.get_url())]
+    )
+
+
+import plotly.graph_objects as go
+
+
+def compile_state(state: Type[State]) -> str:
+    """Compile the state of the app.
+
+    Args:
+        state: The app state object.
+
+    Returns:
+        A string of the compiled state.
+    """
+    initial_state = state().dict()
+    initial_state.update(
+        {
+            "events": [{"name": utils.get_hydrate_event(state)}],
+        }
+    )
+    initial_state = utils.format_state(initial_state)
+    synced_state = templates.format_state(
+        state=state.get_name(), initial_state=json.dumps(initial_state)
+    )
+    initial_result = {
+        "state": None,
+        "events": [],
+        "processing": False,
+    }
+    result = templates.format_state(
+        state="result",
+        initial_state=json.dumps(initial_result),
+    )
+    router = templates.ROUTER
+    return templates.join([synced_state, result, router])
+
+
+def compile_events(state: Type[State]) -> str:
+    """Compile all the events for a given component.
+
+    Args:
+        state: The state class for the component.
+
+    Returns:
+        A string of the compiled events for the component.
+    """
+    state_name = state.get_name()
+    state_setter = templates.format_state_setter(state_name)
+    return templates.EVENT_FN(state=state_name, set_state=state_setter)
+
+
+def compile_effects(state: Type[State]) -> str:
+    """Compile all the effects for a given component.
+
+    Args:
+        state: The state class for the component.
+
+    Returns:
+        A string of the compiled effects for the component.
+    """
+    state_name = state.get_name()
+    result_name = "result"
+    set_result = templates.format_state_setter(result_name)
+    return templates.USE_EFFECT(
+        state=state_name, result=result_name, set_result=set_result
+    )
+
+
+def compile_render(component: Component) -> str:
+    """Compile the component's render method.
+
+    Args:
+        component: The component to compile the render method for.
+
+    Returns:
+        A string of the compiled render method.
+    """
+    return component.render()
+
+
+def create_document_root(stylesheets) -> Component:
+    """Create the document root.
+
+    Args:
+        stylesheets: The stylesheets to include in the document root.
+
+    Returns:
+        The document root.
+    """
+    sheets = [Link.create(rel="stylesheet", href=href) for href in stylesheets]
+    return Html.create(
+        DocumentHead.create(*sheets),
+        Body.create(
+            Main.create(),
+            Script.create(),
+        ),
+    )
+
+
+def create_theme(style: Style) -> Dict:
+    """Create the base style for the app.
+
+    Args:
+        style: The style dict for the app.
+
+    Returns:
+        The base style for the app.
+    """
+    return {
+        "styles": {
+            "global": Style({k: v for k, v in style.items() if not isinstance(k, type)})
+        },
+    }
+
+
+def add_title(page: Component, title: str) -> Component:
+    """Add a title to a page.
+
+    Args:
+        page: The component for the page.
+        title: The title to add.
+
+    Returns:
+        The component with the title added.
+    """
+    page.children.append(Head.create(Title.create(title)))
+    return page

+ 91 - 0
pynecone/components/__init__.py

@@ -0,0 +1,91 @@
+"""Import all the components."""
+
+from pynecone import utils
+from pynecone.event import EventSpec
+from pynecone.var import Var
+
+from .component import Component
+from .datadisplay import *
+from .disclosure import *
+from .feedback import *
+from .forms import *
+from .graphing import *
+from .layout import *
+from .media import *
+from .navigation import *
+from .overlay import *
+from .typography import *
+
+# Add the convenience methods for all the components.
+locals().update(
+    {
+        utils.to_snake_case(name): value.create
+        for name, value in locals().items()
+        if isinstance(value, type) and issubclass(value, Component)
+    }
+)
+
+# Add responsive styles shortcuts.
+def mobile_only(*children, **props):
+    """Create a component that is only visible on mobile.
+
+    Args:
+        *children: The children to pass to the component.
+        **props: The props to pass to the component.
+
+    Returns:
+        The component.
+    """
+    return Box.create(*children, **props, display=["block", "none", "none", "none"])
+
+
+def tablet_only(*children, **props):
+    """Create a component that is only visible on tablet.
+
+    Args:
+        *children: The children to pass to the component.
+        **props: The props to pass to the component.
+
+    Returns:
+        The component.
+    """
+    return Box.create(*children, **props, display=["none", "block", "block", "none"])
+
+
+def desktop_only(*children, **props):
+    """Create a component that is only visible on desktop.
+
+    Args:
+        *children: The children to pass to the component.
+        **props: The props to pass to the component.
+
+    Returns:
+        The component.
+    """
+    return Box.create(*children, **props, display=["none", "none", "none", "block"])
+
+
+def tablet_and_desktop(*children, **props):
+    """Create a component that is only visible on tablet and desktop.
+
+    Args:
+        *children: The children to pass to the component.
+        **props: The props to pass to the component.
+
+    Returns:
+        The component.
+    """
+    return Box.create(*children, **props, display=["none", "block", "block", "block"])
+
+
+def mobile_and_tablet(*children, **props):
+    """Create a component that is only visible on mobile and tablet.
+
+    Args:
+        *children: The children to pass to the component.
+        **props: The props to pass to the component.
+
+    Returns:
+        The component.
+    """
+    return Box.create(*children, **props, display=["block", "block", "block", "none"])

+ 7 - 0
pynecone/components/base/__init__.py

@@ -0,0 +1,7 @@
+"""Base components."""
+
+from .body import Body
+from .document import DocumentHead, Html, Main, Script
+from .head import Head
+from .link import Link
+from .title import Title

+ 30 - 0
pynecone/components/base/bare.py

@@ -0,0 +1,30 @@
+"""A bare component."""
+from __future__ import annotations
+
+from typing import Any
+
+from pynecone.components.component import Component
+from pynecone.components.tags import Tag
+from pynecone.components.tags.tagless import Tagless
+from pynecone.var import Var
+
+
+class Bare(Component):
+    """A component with no tag."""
+
+    contents: Var[str]
+
+    @classmethod
+    def create(cls, contents: Any) -> Component:
+        """Create a Bare component, with no tag.
+
+        Args:
+            contents: The contents of the component.
+
+        Returns:
+            The component.
+        """
+        return cls(contents=str(contents))  # type: ignore
+
+    def _render(self) -> Tag:
+        return Tagless(contents=str(self.contents))

+ 12 - 0
pynecone/components/base/body.py

@@ -0,0 +1,12 @@
+"""Display the page body."""
+
+from pynecone.components.component import Component
+from pynecone.components.tags import Tag
+from pynecone.var import Var
+
+
+class Body(Component):
+    """A body component."""
+
+    def _render(self) -> Tag:
+        return Tag(name="body")

+ 33 - 0
pynecone/components/base/document.py

@@ -0,0 +1,33 @@
+"""Document components."""
+
+from pynecone.components.component import Component
+
+
+class NextDocumentLib(Component):
+    """Root document components."""
+
+    library = "next/document"
+
+
+class Html(NextDocumentLib):
+    """The document html."""
+
+    tag = "Html"
+
+
+class DocumentHead(NextDocumentLib):
+    """The document head."""
+
+    tag = "Head"
+
+
+class Main(NextDocumentLib):
+    """The document main section."""
+
+    tag = "Main"
+
+
+class Script(NextDocumentLib):
+    """The document main scripts."""
+
+    tag = "NextScript"

+ 15 - 0
pynecone/components/base/head.py

@@ -0,0 +1,15 @@
+"""The head component."""
+
+from pynecone.components.component import Component
+
+
+class NextHeadLib(Component):
+    """Header components."""
+
+    library = "next/head"
+
+
+class Head(NextHeadLib):
+    """Head Component."""
+
+    tag = "NextHead"

+ 21 - 0
pynecone/components/base/link.py

@@ -0,0 +1,21 @@
+"""Display the title of the current page."""
+
+from pynecone.components.component import Component
+from pynecone.components.tags import Tag
+from pynecone.var import Var
+
+
+class Link(Component):
+    """A component that displays the title of the current page."""
+
+    # The href.
+    href: Var[str]
+
+    # The type of link.
+    rel: Var[str]
+
+    def _render(self) -> Tag:
+        return Tag(name="link").add_attrs(
+            href=self.href,
+            rel=self.rel,
+        )

+ 25 - 0
pynecone/components/base/title.py

@@ -0,0 +1,25 @@
+"""Display the title of the current page."""
+
+from pynecone.components.base.bare import Bare
+from pynecone.components.component import Component
+from pynecone.components.tags import Tag
+
+
+class Title(Component):
+    """A component that displays the title of the current page."""
+
+    def _render(self) -> Tag:
+        return Tag(name="title")
+
+    def render(self) -> str:
+        """Render the title component.
+
+        Returns:
+            The rendered title component.
+        """
+        tag = self._render()
+        # Make sure the title is a single string.
+        assert len(self.children) == 1 and isinstance(
+            self.children[0], Bare
+        ), "Title must be a single string."
+        return str(tag.set(contents=str(self.children[0].contents)))

+ 345 - 0
pynecone/components/component.py

@@ -0,0 +1,345 @@
+"""Base component definitions."""
+
+from __future__ import annotations
+
+from abc import ABC
+from typing import Any, Callable, Dict, List, Optional, Set, Type, Union
+
+from pynecone import utils
+from pynecone.base import Base
+from pynecone.components.tags import Tag
+from pynecone.event import (
+    EVENT_ARG,
+    EVENT_TRIGGERS,
+    EventChain,
+    EventHandler,
+    EventSpec,
+)
+from pynecone.style import Style
+from pynecone.var import Var
+
+ImportDict = Dict[str, Set[str]]
+
+
+class Component(Base, ABC):
+    """The base class for all Pynecone components."""
+
+    # The children nested within the component.
+    children: List[Component] = []
+
+    # The style of the component.
+    style: Style = Style()
+
+    # A mapping of event chains to event triggers.
+    event_triggers: Dict[str, EventChain] = {}
+
+    # The library that the component is based on.
+    library: Optional[str] = None
+
+    # The tag to use when rendering the component.
+    tag: Optional[str] = None
+
+    # A unique key for the component.
+    key: Any = None
+
+    @classmethod
+    def __init_subclass__(cls, **kwargs):
+        """Set default properties.
+
+        Args:
+            **kwargs: The kwargs to pass to the superclass.
+        """
+        super().__init_subclass__(**kwargs)
+
+        # Get all the props for the component.
+        props = cls.get_props()
+
+        # Convert fields to props, setting default values.
+        for field in cls.get_fields().values():
+            # If the field is not a component prop, skip it.
+            if field.name not in props:
+                continue
+
+            # Set default values for any props.
+            if utils._issubclass(field.type_, Var):
+                field.required = False
+                field.default = Var.create(field.default)
+
+    def __init__(self, *args, **kwargs):
+        """Initialize the component.
+
+        Args:
+            *args: Args to initialize the component.
+            **kwargs: Kwargs to initialize the component.
+        """
+        # Get the component fields, triggers, and props.
+        fields = self.get_fields()
+        triggers = self.get_triggers()
+        props = self.get_props()
+
+        # Add any events triggers.
+        if "event_triggers" not in kwargs:
+            kwargs["event_triggers"] = {}
+        kwargs["event_triggers"] = kwargs["event_triggers"].copy()
+
+        # Iterate through the kwargs and set the props.
+        for key, value in kwargs.items():
+            if key in triggers:
+                # Event triggers are bound to event chains.
+                field_type = EventChain
+            else:
+                # If the key is not in the fields, skip it.
+                if key not in props:
+                    continue
+
+                # Set the field type.
+                field_type = fields[key].type_
+
+            # Check whether the key is a component prop.
+            if utils._issubclass(field_type, Var):
+                # Convert any constants into vars and make sure the types match.
+                kwargs[key] = Var.create(value)
+                passed_type = kwargs[key].type_
+                expected_type = fields[key].outer_type_.__args__[0]
+                assert utils._issubclass(
+                    passed_type, expected_type
+                ), f"Invalid var passed for {key}, expected {expected_type}, got {passed_type}."
+
+            # Check if the key is an event trigger.
+            if key in triggers:
+                kwargs["event_triggers"][key] = self._create_event_chain(key, value)
+
+        # Remove any keys that were added as events.
+        for key in kwargs["event_triggers"]:
+            del kwargs[key]
+
+        # Add style props to the component.
+        style = kwargs["style"] if "style" in kwargs else {}
+        kwargs["style"] = Style(
+            {
+                **style,
+                **{attr: value for attr, value in kwargs.items() if attr not in fields},
+            }
+        )
+
+        # Construct the component.
+        super().__init__(*args, **kwargs)
+
+    def _create_event_chain(
+        self,
+        event_trigger: str,
+        value: Union[EventHandler, List[EventHandler], Callable],
+    ) -> EventChain:
+        """Create an event chain from a variety of input types.
+
+        Args:
+            event_trigger: The event trigger to bind the chain to.
+            value: The value to create the event chain from.
+
+        Returns:
+            The event chain.
+        """
+        arg = self.get_controlled_value()
+
+        # If the input is a single event handler, wrap it in a list.
+        if isinstance(value, EventHandler):
+            value = [value]
+
+        # If the input is a list of event handlers, create an event chain.
+        if isinstance(value, List):
+            events = [utils.call_event_handler(v, arg) for v in value]
+
+        # If the input is a callable, create an event chain.
+        elif isinstance(value, Callable):
+            events = utils.call_event_fn(value, arg)
+
+        # Otherwise, raise an error.
+        else:
+            raise ValueError(f"Invalid event chain: {value}")
+
+        # Add args to the event specs if necessary.
+        if event_trigger in self.get_controlled_triggers():
+            events = [
+                EventSpec(
+                    handler=e.handler,
+                    local_args=(EVENT_ARG.name,),
+                    args=utils.get_handler_args(e, arg),
+                )
+                for e in events
+            ]
+
+        # Return the event chain.
+        return EventChain(events=events)
+
+    @classmethod
+    def get_triggers(cls) -> Set[str]:
+        """Get the event triggers for the component.
+
+        Returns:
+            The event triggers.
+        """
+        return EVENT_TRIGGERS | cls.get_controlled_triggers()
+
+    @classmethod
+    def get_controlled_triggers(cls) -> Set[str]:
+        """Get the event triggers that pass the component's value to the handler.
+
+        Returns:
+            The controlled event triggers.
+        """
+        return set()
+
+    @classmethod
+    def get_controlled_value(cls) -> Var:
+        """Get the var that is passed to the event handler for controlled triggers.
+
+        Returns:
+            The controlled value.
+        """
+        return EVENT_ARG
+
+    def __repr__(self) -> str:
+        """Represent the component in React.
+
+        Returns:
+            The code to render the component.
+        """
+        return self.render()
+
+    def __str__(self) -> str:
+        """Represent the component in React.
+
+        Returns:
+            The code to render the component.
+        """
+        return self.render()
+
+    def _render(self) -> Tag:
+        """Define how to render the component in React.
+
+        Returns:
+            The tag to render.
+        """
+        tag = Tag(name=self.tag).add_attrs(
+            **{attr: getattr(self, attr) for attr in self.get_props()}
+        )
+
+        # Special case for props named `type_`.
+        if hasattr(self, "type_"):
+            tag.add_attrs(type=getattr(self, "type_"))
+        return tag
+
+    @classmethod
+    def get_props(cls) -> Set[str]:
+        """Get the unique fields for the component.
+
+        Returns:
+            The unique fields.
+        """
+        return set(cls.get_fields()) - set(Component.get_fields())
+
+    @classmethod
+    def create(cls, *children, **props) -> Component:
+        """Create the component.
+
+        Args:
+            *children: The children of the component.
+            **props: The props of the component.
+
+        Returns:
+            The component.
+        """
+        # Import here to avoid circular imports.
+        from pynecone.components.base.bare import Bare
+
+        children = [
+            Bare.create(contents=Var.create(child, is_string=True))
+            if not isinstance(child, Component)
+            else child
+            for child in children
+        ]
+        return cls(children=children, **props)
+
+    def _add_style(self, style):
+        self.style.update(style)
+
+    def add_style(self, style: ComponentStyle) -> Component:
+        """Add additional style to the component and its children.
+
+        Args:
+            style: A dict from component to styling.
+
+        Returns:
+            The component with the additional style.
+        """
+        if type(self) in style:
+            # Extract the style for this component.
+            component_style = Style(style[type(self)])
+
+            # Only add stylee props that are not overriden.
+            component_style = {
+                k: v for k, v in component_style.items() if k not in self.style
+            }
+
+            # Add the style to the component.
+            self._add_style(component_style)
+
+        # Recursively add style to the children.
+        for child in self.children:
+            child.add_style(style)
+        return self
+
+    def render(self) -> str:
+        """Render the component.
+
+        Returns:
+            The code to render the component.
+        """
+        tag = self._render()
+        return str(
+            tag.add_attrs(**self.event_triggers, key=self.key, sx=self.style).set(
+                contents=utils.join(
+                    [str(tag.contents)] + [child.render() for child in self.children]
+                ),
+            )
+        )
+
+    def _get_custom_code(self) -> str:
+        """Get custom code for the component.
+
+        Returns:
+            The custom code.
+        """
+        return ""
+
+    def get_custom_code(self) -> str:
+        """Get custom code for the component and its children.
+
+        Returns:
+            The custom code.
+        """
+        code = self._get_custom_code()
+        for child in self.children:
+            child_code = child.get_custom_code()
+            if child_code != "" and child_code not in code:
+                code += child_code
+        return code
+
+    def _get_imports(self) -> ImportDict:
+        if self.library is not None and self.tag is not None:
+            return {self.library: {self.tag}}
+        return {}
+
+    def get_imports(self) -> ImportDict:
+        """Get all the libraries and fields that are used by the component.
+
+        Returns:
+            The import dict with the required imports.
+        """
+        return utils.merge_imports(
+            self._get_imports(), *[child.get_imports() for child in self.children]
+        )
+
+
+# Map from component to styling.
+ComponentStyle = Dict[Union[str, Type[Component]], Any]

+ 9 - 0
pynecone/components/datadisplay/__init__.py

@@ -0,0 +1,9 @@
+"""Data display components."""
+
+from .badge import Badge
+from .code import Code, CodeBlock
+from .datatable import DataTable
+from .divider import Divider
+from .list import List, ListItem, OrderedList, UnorderedList
+from .stat import Stat, StatArrow, StatGroup, StatHelpText, StatLabel, StatNumber
+from .table import Table, TableCaption, TableContainer, Tbody, Td, Tfoot, Th, Thead, Tr

+ 16 - 0
pynecone/components/datadisplay/badge.py

@@ -0,0 +1,16 @@
+"""Badge component."""
+
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class Badge(ChakraComponent):
+    """A badge component."""
+
+    tag = "Badge"
+
+    # Variant of the badge ("solid" | "subtle" | "outline")
+    variant: Var[str]
+
+    # The color of the badge
+    color_scheme: Var[str]

+ 71 - 0
pynecone/components/datadisplay/code.py

@@ -0,0 +1,71 @@
+"""A code component."""
+
+import json
+from typing import Dict
+
+from pynecone import utils
+from pynecone.components.component import Component
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.components.tags import Tag
+from pynecone.var import Var
+
+
+class CodeBlock(Component):
+    """A code block."""
+
+    library = "react-syntax-highlighter"
+
+    tag = "Prism"
+
+    # The language to use.
+    language: Var[str]
+
+    # If this is enabled line numbers will be shown next to the code block.
+    show_line_numbers: Var[bool]
+
+    # The starting line number to use.
+    starting_line_number: Var[int]
+
+    # Whether to wrap long lines.
+    wrap_long_lines: Var[bool]
+
+    # A custom style for the code block.
+    custom_style: Var[Dict[str, str]]
+
+    # Props passed down to the code tag.
+    code_tag_props: Var[Dict[str, str]]
+
+    @classmethod
+    def create(cls, *children, **props):
+        """Create a text component.
+
+        Args:
+            *children: The children of the component.
+            **props: The props to pass to the component.
+
+        Returns:
+            The text component.
+        """
+        # This component handles style in a special prop.
+        custom_style = props.get("custom_style", {})
+
+        # Transfer style props to the custom style prop.
+        for key, value in props.items():
+            if key not in cls.get_fields():
+                custom_style[key] = value
+
+        # Create the component.
+        return super().create(
+            *children,
+            **props,
+        )
+
+    def _add_style(self, style):
+        self.custom_style = self.custom_style or {}
+        self.custom_style.update(style)  # type: ignore
+
+
+class Code(ChakraComponent):
+    """Used to display inline code."""
+
+    tag = "Code"

+ 55 - 0
pynecone/components/datadisplay/datatable.py

@@ -0,0 +1,55 @@
+"""Table components."""
+
+from typing import Any, Dict, List, Union
+
+from pynecone.components.component import Component
+from pynecone.components.tags import Tag
+from pynecone.var import Var
+
+
+class Gridjs(Component):
+    """A component that wraps a nivo bar component."""
+
+    library = "gridjs-react"
+
+
+class DataTable(Gridjs):
+    """A data table component."""
+
+    tag = "Grid"
+
+    df: Var[Any]
+
+    # The data to display. EIther a list of lists or a pandas dataframe.
+    data: Any
+
+    # The columns to display.
+    columns: Var[List]
+
+    # Enable a search bar.
+    search: Var[bool]
+
+    # Enable sorting on columns.
+    sort: Var[bool]
+
+    # Enable resizable columns.
+    resizable: Var[bool]
+
+    # Enable pagination.
+    pagination: Var[bool]
+
+    def _get_custom_code(self) -> str:
+        return """
+import "gridjs/dist/theme/mermaid.css";
+"""
+
+    def _render(self) -> Tag:
+        if type(self.data).__name__ == "DataFrame":
+            self.columns = Var.create(list(self.data.columns.values.tolist()))  # type: ignore
+            self.data = Var.create(list(self.data.values.tolist()))  # type: ignore
+
+        if isinstance(self.df, Var):
+            self.columns = self.df["columns"]
+            self.data = self.df["data"]
+
+        return super()._render()

+ 16 - 0
pynecone/components/datadisplay/divider.py

@@ -0,0 +1,16 @@
+"""A line to divide parts of the layout."""
+
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class Divider(ChakraComponent):
+    """Dividers are used to visually separate content in a list or group."""
+
+    tag = "Divider"
+
+    # Pass the orientation prop and set it to either horizontal or vertical. If the vertical orientation is used, make sure that the parent element is assigned a height.
+    orientation: Var[str]
+
+    # Variant of the divider ("solid" | "dashed")
+    variant: Var[str]

+ 38 - 0
pynecone/components/datadisplay/list.py

@@ -0,0 +1,38 @@
+"""List components."""
+
+from pynecone.components.component import Component
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class List(ChakraComponent):
+    """List component is used to display list items. It renders a ul element by default."""
+
+    tag = "List"
+
+    # The space between each list item
+    spacing: Var[str]
+
+    # Shorthand prop for listStylePosition
+    style_position: Var[str]
+
+    # Shorthand prop for listStyleType
+    style_type: Var[str]
+
+
+class ListItem(ChakraComponent):
+    """ListItem composes Box so you can pass all style and pseudo style props."""
+
+    tag = "ListItem"
+
+
+class OrderedList(ChakraComponent):
+    """An ordered list component."""
+
+    tag = "OrderedList"
+
+
+class UnorderedList(ChakraComponent):
+    """An unordered list component."""
+
+    tag = "UnorderedList"

+ 43 - 0
pynecone/components/datadisplay/stat.py

@@ -0,0 +1,43 @@
+"""Statistics components."""
+
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class Stat(ChakraComponent):
+    """The Stat component is used to display some statistics. It can take in a label, a number and a help text."""
+
+    tag = "Stat"
+
+
+class StatLabel(ChakraComponent):
+    """A stat label component."""
+
+    tag = "StatLabel"
+
+
+class StatNumber(ChakraComponent):
+    """The stat to display."""
+
+    tag = "StatNumber"
+
+
+class StatHelpText(ChakraComponent):
+    """A helper text to display under the stat."""
+
+    tag = "StatHelpText"
+
+
+class StatArrow(ChakraComponent):
+    """A stat arrow component indicating the direction of change."""
+
+    tag = "StatArrow"
+
+    # The type of arrow, either increase or decrease.
+    type_: Var[str]
+
+
+class StatGroup(ChakraComponent):
+    """A stat group component to evenly space out the stats."""
+
+    tag = "StatGroup"

+ 81 - 0
pynecone/components/datadisplay/table.py

@@ -0,0 +1,81 @@
+"""Table components."""
+
+from typing import List
+
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class Table(ChakraComponent):
+    """A table component."""
+
+    tag = "Table"
+
+    # The color scheme of the table
+    color_scheme: Var[str]
+
+    # The variant of the table style to use
+    variant: Var[str]
+
+    # The size of the table
+    size: Var[str]
+
+    # The placement of the table caption.
+    placement: Var[str]
+
+
+class Thead(Table):
+    """A table header component."""
+
+    tag = "Thead"
+
+
+class Tbody(Table):
+    """A table body component."""
+
+    tag = "Tbody"
+
+
+class Tfoot(Table):
+    """A table footer component."""
+
+    tag = "Tfoot"
+
+
+class Tr(Table):
+    """A table row component."""
+
+    tag = "Tr"
+
+
+class Th(ChakraComponent):
+    """A table header cell component."""
+
+    tag = "Th"
+
+    # Aligns the cell content to the right.
+    is_numeric: Var[bool]
+
+
+class Td(ChakraComponent):
+    """A table data cell component."""
+
+    tag = "Td"
+
+    # Aligns the cell content to the right.
+    is_numeric: Var[bool]
+
+
+class TableCaption(ChakraComponent):
+    """A table caption component."""
+
+    tag = "TableCaption"
+
+    # The placement of the table caption. This sets the `caption-side` CSS attribute.
+    placement: Var[str]
+
+
+class TableContainer(ChakraComponent):
+    """The table container component renders a div that wraps the table component."""
+
+    tag = "TableContainer"

+ 12 - 0
pynecone/components/disclosure/__init__.py

@@ -0,0 +1,12 @@
+"""Disclosure components."""
+
+from .accordion import (
+    Accordion,
+    AccordionButton,
+    AccordionIcon,
+    AccordionItem,
+    AccordionPanel,
+)
+from .tabs import Tab, TabList, TabPanel, TabPanels, Tabs
+
+__all__ = [f for f in dir() if f[0].isupper()]  # type: ignore

+ 60 - 0
pynecone/components/disclosure/accordion.py

@@ -0,0 +1,60 @@
+"""Container to stack elements with spacing."""
+
+from typing import List, Optional, Union
+
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class Accordion(ChakraComponent):
+    """The wrapper that uses cloneElement to pass props to AccordionItem children."""
+
+    tag = "Accordion"
+
+    # If true, multiple accordion items can be expanded at once.
+    allow_multiple: Var[bool]
+
+    # If true, any expanded accordion item can be collapsed again.
+    allow_toggle: Var[bool]
+
+    # The initial index(es) of the expanded accordion item(s).
+    default_index: Var[Optional[List[int]]]
+
+    # The index(es) of the expanded accordion item
+    index: Var[Union[int, List[int]]]
+
+    # If true, height animation and transitions will be disabled.
+    reduce_motion: Var[bool]
+
+
+class AccordionItem(ChakraComponent):
+    """A single accordion item."""
+
+    tag = "AccordionItem"
+
+    # A unique id for the accordion item.
+    id_: Var[str]
+
+    # If true, the accordion item will be disabled.
+    is_disabled: Var[bool]
+
+    # If true, the accordion item will be focusable.
+    is_focusable: Var[bool]
+
+
+class AccordionButton(ChakraComponent):
+    """The button that toggles the expand/collapse state of the accordion item. This button must be wrapped in an element with role heading."""
+
+    tag = "AccordionButton"
+
+
+class AccordionPanel(ChakraComponent):
+    """The container for the details to be revealed."""
+
+    tag = "AccordionPanel"
+
+
+class AccordionIcon(ChakraComponent):
+    """A chevron-down icon that rotates based on the expanded/collapsed state."""
+
+    tag = "AccordionIcon"

+ 70 - 0
pynecone/components/disclosure/tabs.py

@@ -0,0 +1,70 @@
+"""Tab components."""
+
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class Tabs(ChakraComponent):
+    """An accessible tabs component that provides keyboard interactions and ARIA attributes described in the WAI-ARIA Tabs Design Pattern. Tabs, provides context and state for all components."""
+
+    tag = "Tabs"
+
+    # The alignment of the tabs ("center" | "end" | "start").
+    align: Var[str]
+
+    # The initial index of the selected tab (in uncontrolled mode).
+    default_index: Var[int]
+
+    # The id of the tab.
+    id_: Var[str]
+
+    # If true, tabs will stretch to width of the tablist.
+    is_fitted: Var[bool]
+
+    # Performance booster. If true, rendering of the tab panel's will be deferred until it is selected.
+    is_lazy: Var[bool]
+
+    # If true, the tabs will be manually activated and display its panel by pressing Space or Enter. If false, the tabs will be automatically activated and their panel is displayed when they receive focus.
+    is_manual: Var[bool]
+
+    # The orientation of the tab list.
+    orientation: Var[str]
+
+    # "line" | "enclosed" | "enclosed-colored" | "soft-rounded" | "solid-rounded" | "unstyled"
+    variant: Var[str]
+
+
+class Tab(ChakraComponent):
+    """An element that serves as a label for one of the tab panels and can be activated to display that panel.."""
+
+    tag = "Tab"
+
+    # If true, the Tab won't be toggleable.
+    is_disabled: Var[bool]
+
+    # If true, the Tab will be selected.
+    is_selected: Var[bool]
+
+    # The id of the tab.
+    id_: Var[str]
+
+    # The id of the panel.
+    panel_id: Var[str]
+
+
+class TabList(ChakraComponent):
+    """Wrapper for the Tab components."""
+
+    tag = "TabList"
+
+
+class TabPanels(ChakraComponent):
+    """Wrapper for the Tab components."""
+
+    tag = "TabPanels"
+
+
+class TabPanel(ChakraComponent):
+    """An element that contains the content associated with a tab."""
+
+    tag = "TabPanel"

+ 7 - 0
pynecone/components/feedback/__init__.py

@@ -0,0 +1,7 @@
+"""Convenience functions to define core components."""
+
+from .alert import Alert, AlertDescription, AlertIcon, AlertTitle
+from .circularprogress import CircularProgress, CircularProgressLabel
+from .progress import Progress
+from .skeleton import Skeleton, SkeletonCircle, SkeletonText
+from .spinner import Spinner

+ 34 - 0
pynecone/components/feedback/alert.py

@@ -0,0 +1,34 @@
+"""Alert components."""
+
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class Alert(ChakraComponent):
+    """Container to stack elements with spacing."""
+
+    tag = "Alert"
+
+    # The status of the alert ("success" | "info" | "warning" | "error")
+    status: Var[str]
+
+    # "subtle" | "left-accent" | "top-accent" | "solid"
+    variant: Var[str]
+
+
+class AlertIcon(ChakraComponent):
+    """AlertIcon composes Icon and changes the icon based on the status prop."""
+
+    tag = "AlertIcon"
+
+
+class AlertTitle(ChakraComponent):
+    """AlertTitle composes the Box component."""
+
+    tag = "AlertTitle"
+
+
+class AlertDescription(ChakraComponent):
+    """AlertDescription composes the Box component."""
+
+    tag = "AlertDescription"

+ 40 - 0
pynecone/components/feedback/circularprogress.py

@@ -0,0 +1,40 @@
+"""Container to stack elements with spacing."""
+
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class CircularProgress(ChakraComponent):
+    """The CircularProgress component is used to indicate the progress for determinate and indeterminate processes."""
+
+    tag = "CircularProgress"
+
+    # If true, the cap of the progress indicator will be rounded.
+    cap_is_round: Var[bool]
+
+    # If true, the progress will be indeterminate and the value prop will be ignored
+    is_indeterminate: Var[bool]
+
+    # Maximum value defining 100% progress made (must be higher than 'min')
+    max_: Var[int]
+
+    # Minimum value defining 'no progress' (must be lower than 'max')
+    min_: Var[int]
+
+    # This defines the stroke width of the svg circle.
+    thickness: Var[int]
+
+    # The color name of the progress track. Use a color key in the theme object
+    track_color: Var[str]
+
+    # Current progress (must be between min/max).
+    value: Var[int]
+
+    # The desired valueText to use in place of the value.
+    value_text: Var[str]
+
+
+class CircularProgressLabel(ChakraComponent):
+    """Label of CircularProcess."""
+
+    tag = "CircularProgressLabel"

+ 31 - 0
pynecone/components/feedback/progress.py

@@ -0,0 +1,31 @@
+"""Container to stack elements with spacing."""
+
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class Progress(ChakraComponent):
+    """A bar to display progress."""
+
+    tag = "Progress"
+
+    # If true, the progress bar will show stripe
+    has_striped: Var[bool]
+
+    # If true, and hasStripe is true, the stripes will be animated
+    is_animated: Var[bool]
+
+    # If true, the progress will be indeterminate and the value prop will be ignored
+    is_indeterminate: Var[bool]
+
+    # The maximum value of the progress
+    max_: Var[int]
+
+    # The minimum value of the progress
+    min_: Var[int]
+
+    # The value of the progress indicator. If undefined the progress bar will be in indeterminate state
+    value: Var[int]
+
+    # The color scheme of the progress bar.
+    color_scheme: Var[str]

+ 70 - 0
pynecone/components/feedback/skeleton.py

@@ -0,0 +1,70 @@
+"""Container to stack elements with spacing."""
+
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class Skeleton(ChakraComponent):
+    """Skeleton is used to display the loading state of some components. You can use it as a standalone component. Or to wrap another component to take the same height and width."""
+
+    tag = "Skeleton"
+
+    # The color at the animation end
+    end_color: Var[str]
+
+    # The fadeIn duration in seconds
+    fade_duration: Var[float]
+
+    # If true, it'll render its children with a nice fade transition
+    is_loaded: Var[bool]
+
+    # The animation speed in seconds
+    speed: Var[float]
+
+    # The color at the animation start
+    start_color: Var[str]
+
+
+class SkeletonCircle(ChakraComponent):
+    """SkeletonCircle is used to display the loading state of some components."""
+
+    tag = "SkeletonCircle"
+
+    # The color at the animation end
+    end_color: Var[str]
+
+    # The fadeIn duration in seconds
+    fade_duration: Var[float]
+
+    # If true, it'll render its children with a nice fade transition
+    is_loaded: Var[bool]
+
+    # The animation speed in seconds
+    speed: Var[float]
+
+    # The color at the animation start
+    start_color: Var[str]
+
+
+class SkeletonText(ChakraComponent):
+    """SkeletonText is used to display the loading state of some components."""
+
+    tag = "SkeletonText"
+
+    # The color at the animation end
+    end_color: Var[str]
+
+    # The fadeIn duration in seconds
+    fade_duration: Var[float]
+
+    # If true, it'll render its children with a nice fade transition
+    is_loaded: Var[bool]
+
+    # The animation speed in seconds
+    speed: Var[float]
+
+    # The color at the animation start
+    start_color: Var[str]
+
+    # Number is lines of text.
+    no_of_lines: Var[int]

+ 25 - 0
pynecone/components/feedback/spinner.py

@@ -0,0 +1,25 @@
+"""Container to stack elements with spacing."""
+
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class Spinner(ChakraComponent):
+    """The component that spins."""
+
+    tag = "Spinner"
+
+    # The color of the empty area in the spinner
+    empty_color: Var[str]
+
+    # For accessibility, it is important to add a fallback loading text. This text will be visible to screen readers.
+    label: Var[str]
+
+    # The speed of the spinner must be as a string and in seconds '1s'. Default is '0.45s'.
+    speed: Var[str]
+
+    # The thickness of the spinner.
+    thickness: Var[int]
+
+    # "xs" | "sm" | "md" | "lg" | "xl"
+    size: Var[str]

+ 29 - 0
pynecone/components/forms/__init__.py

@@ -0,0 +1,29 @@
+"""Convenience functions to define core components."""
+
+from .button import Button, ButtonGroup
+from .checkbox import Checkbox, CheckboxGroup
+from .editable import Editable, EditableInput, EditablePreview, EditableTextarea
+from .formcontrol import FormControl, FormErrorMessage, FormHelperText, FormLabel
+from .iconbutton import IconButton
+from .input import Input, InputGroup, InputLeftAddon, InputRightAddon
+from .numberinput import (
+    NumberDecrementStepper,
+    NumberIncrementStepper,
+    NumberInput,
+    NumberInputField,
+    NumberInputStepper,
+)
+from .pininput import PinInput, PinInputField
+from .radio import Radio, RadioGroup
+from .rangeslider import (
+    RangeSlider,
+    RangeSliderFilledTrack,
+    RangeSliderThumb,
+    RangeSliderTrack,
+)
+from .select import Option, Select
+from .slider import Slider, SliderFilledTrack, SliderMark, SliderThumb, SliderTrack
+from .switch import Switch
+from .textarea import TextArea
+
+__all__ = [f for f in dir() if f[0].isupper()]  # type: ignore

+ 55 - 0
pynecone/components/forms/button.py

@@ -0,0 +1,55 @@
+"""A button component."""
+
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class Button(ChakraComponent):
+    """The Button component is used to trigger an event or event, such as submitting a form, opening a dialog, canceling an event, or performing a delete operation."""
+
+    tag = "Button"
+
+    # The type of button.
+    type: Var[str]
+
+    # The space between the button icon and label.
+    icon_spacing: Var[int]
+
+    # If true, the button will be styled in its active state.
+    is_active: Var[bool]
+
+    # If true, the button will be styled in its disabled state.
+    is_disabled: Var[bool]
+
+    # If true, the button will take up the full width of its container.
+    is_full_width: Var[bool]
+
+    # If true, the button will show a spinner.
+    is_loading: Var[bool]
+
+    # The label to show in the button when isLoading is true If no text is passed, it only shows the spinner.
+    loading_text: Var[str]
+
+    # "lg" | "md" | "sm" | "xs"
+    size: Var[str]
+
+    # "ghost" | "outline" | "solid" | "link" | "unstyled"
+    variant: Var[str]
+
+    # Built in color scheme for ease of use.
+    color_scheme: Var[str]
+
+
+class ButtonGroup(ChakraComponent):
+    """A group of buttons."""
+
+    tag = "ButtonGroup"
+
+    # If true, the borderRadius of button that are direct children will be altered to look flushed together.
+    is_attached: Var[bool]
+
+    # If true, all wrapped button will be disabled.
+    is_disabled: Var[bool]
+
+    # The spacing between the buttons.
+    spacing: Var[int]

+ 82 - 0
pynecone/components/forms/checkbox.py

@@ -0,0 +1,82 @@
+"""A checkbox component."""
+
+from typing import Set
+
+from pynecone.components.component import EVENT_ARG
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class Checkbox(ChakraComponent):
+    """The Checkbox component is used in forms when a user needs to select multiple values from several options."""
+
+    tag = "Checkbox"
+
+    # Color scheme for checkbox.
+    color_scheme: Var[str]
+
+    # "sm" | "md" | "lg"
+    size: Var[str]
+
+    # If true, the checkbox will be checked.
+    is_checked: Var[bool]
+
+    # If true, the checkbox will be disabled
+    is_disabled: Var[bool]
+
+    # If true and is_disabled is passed, the checkbox will remain tabbable but not interactive
+    is_focusable: Var[bool]
+
+    # If true, the checkbox will be indeterminate. This only affects the icon shown inside checkbox and does not modify the is_checked var.
+    is_indeterminate: Var[bool]
+
+    # If true, the checkbox is marked as invalid. Changes style of unchecked state.
+    is_invalid: Var[bool]
+
+    # If true, the checkbox will be readonly
+    is_read_only: Var[bool]
+
+    # If true, the checkbox input is marked as required, and required attribute will be added
+    is_required: Var[bool]
+
+    # The name of the input field in a checkbox (Useful for form submission).
+    name: Var[str]
+
+    # The spacing between the checkbox and its label text (0.5rem)
+    spacing: Var[str]
+
+    @classmethod
+    def get_controlled_triggers(cls) -> Set[str]:
+        """Get the event triggers that pass the component's value to the handler.
+
+        Returns:
+            The controlled event triggers.
+        """
+        return {"on_change"}
+
+    @classmethod
+    def get_controlled_value(cls) -> Var:
+        """Get the var that is passed to the event handler for controlled triggers.
+
+        Returns:
+            The controlled value.
+        """
+        return EVENT_ARG.target.checked
+
+
+class CheckboxGroup(ChakraComponent):
+    """A group of checkboxes."""
+
+    tag = "CheckboxGroup"
+
+    # The value of the checkbox group
+    value: Var[str]
+
+    # The initial value of the checkbox group
+    default_value: Var[str]
+
+    # If true, all wrapped checkbox inputs will be disabled
+    is_disabled: Var[bool]
+
+    # If true, input elements will receive checked attribute instead of isChecked. This assumes, you're using native radio inputs
+    is_native: Var[bool]

+ 69 - 0
pynecone/components/forms/editable.py

@@ -0,0 +1,69 @@
+"""An editable component."""
+
+from typing import Set
+
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.components.tags import Tag
+from pynecone.var import Var
+
+
+class Editable(ChakraComponent):
+    """The wrapper component that provides context value."""
+
+    tag = "Editable"
+
+    # If true, the Editable will be disabled.
+    is_disabled: Var[bool]
+
+    # If true, the read only view, has a tabIndex set to 0 so it can receive focus via the keyboard or click.
+    is_preview_focusable: Var[bool]
+
+    # The placeholder text when the value is empty.
+    placeholder: Var[str]
+
+    # If true, the input's text will be highlighted on focus.
+    select_all_on_focus: Var[bool]
+
+    # If true, the Editable will start with edit mode by default.
+    start_with_edit_view: Var[bool]
+
+    # If true, it'll update the value onBlur and turn off the edit mode.
+    submit_on_blur: Var[bool]
+
+    # The value of the Editable in both edit & preview mode
+    value: Var[str]
+
+    # The initial value of the Editable in both edit and preview mode.
+    default_value: Var[str]
+
+    @classmethod
+    def get_controlled_triggers(cls) -> Set[str]:
+        """Get the event triggers that pass the component's value to the handler.
+
+        Returns:
+            The controlled event triggers.
+        """
+        return {
+            "on_change",
+            "on_edit",
+            "on_submit",
+            "on_cancel",
+        }
+
+
+class EditableInput(ChakraComponent):
+    """The edit view of the component. It shows when you click or focus on the text."""
+
+    tag = "EditableInput"
+
+
+class EditableTextarea(ChakraComponent):
+    """Use the textarea element to handle multi line text input in an editable context."""
+
+    tag = "EditableTextarea"
+
+
+class EditablePreview(ChakraComponent):
+    """The read-only view of the component."""
+
+    tag = "EditablePreview"

+ 46 - 0
pynecone/components/forms/formcontrol.py

@@ -0,0 +1,46 @@
+"""Form components."""
+
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class FormControl(ChakraComponent):
+    """FormControl provides context such as isInvalid, isDisabled, and isRequired to form elements."""
+
+    tag = "FormControl"
+
+    # If true, the form control will be disabled.
+    is_disabled: Var[bool]
+
+    # If true, the form control will be invalid.
+    is_invalid: Var[bool]
+
+    # If true, the form control will be readonly
+    is_read_only: Var[bool]
+
+    # If true, the form control will be required.
+    is_required: Var[bool]
+
+    # The label text used to inform users as to what information is requested for a text field.
+    label: Var[str]
+
+
+class FormHelperText(ChakraComponent):
+    """A form helper text component."""
+
+    tag = "FormHelperText"
+
+
+class FormLabel(ChakraComponent):
+    """A form label component."""
+
+    tag = "FormLabel"
+
+    # Link
+    html_for: Var[str]
+
+
+class FormErrorMessage(ChakraComponent):
+    """A form error message component."""
+
+    tag = "FormErrorMessage"

+ 34 - 0
pynecone/components/forms/iconbutton.py

@@ -0,0 +1,34 @@
+"""A button component."""
+
+from pynecone.components.typography.text import Text
+from pynecone.var import Var
+
+
+class IconButton(Text):
+    """A button that can be clicked."""
+
+    tag = "IconButton"
+
+    # The type of button.
+    type: Var[str]
+
+    #  A label that describes the button
+    aria_label: Var[str]
+
+    # The icon to be used in the button.
+    icon: Var[str]
+
+    # If true, the button will be styled in its active state.
+    is_active: Var[bool]
+
+    # If true, the button will be disabled.
+    is_disabled: Var[bool]
+
+    # If true, the button will show a spinner.
+    is_loading: Var[bool]
+
+    # If true, the button will be perfectly round. Else, it'll be slightly round
+    is_round: Var[bool]
+
+    # Replace the spinner component when isLoading is set to true
+    spinner: Var[str]

+ 82 - 0
pynecone/components/forms/input.py

@@ -0,0 +1,82 @@
+"""An input component."""
+
+from typing import Set
+
+from pynecone.components.component import EVENT_ARG
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class Input(ChakraComponent):
+    """The Input component is a component that is used to get user input in a text field."""
+
+    tag = "Input"
+
+    # State var to bind the the input.
+    value: Var[str]
+
+    # The default value of the input.
+    default_value: Var[str]
+
+    # The placeholder text.
+    placeholder: Var[str]
+
+    # The type of input.
+    type_: Var[str] = "text"  # type: ignore
+
+    # The border color when the input is invalid.
+    error_border_color: Var[str]
+
+    # The border color when the input is focused.
+    focus_border_color: Var[str]
+
+    # If true, the form control will be disabled. This has 2 side effects - The FormLabel will have `data-disabled` attribute - The form element (e.g, Input) will be disabled
+    is_disabled: Var[bool]
+
+    # If true, the form control will be invalid. This has 2 side effects - The FormLabel and FormErrorIcon will have `data-invalid` set to true - The form element (e.g, Input) will have `aria-invalid` set to true
+    is_invalid: Var[bool]
+
+    # If true, the form control will be readonly.
+    is_read_only: Var[bool]
+
+    # If true, the form control will be required. This has 2 side effects - The FormLabel will show a required indicator - The form element (e.g, Input) will have `aria-required` set to true
+    is_required: Var[bool]
+
+    # "outline" | "filled" | "flushed" | "unstyled"
+    variant: Var[str]
+
+    @classmethod
+    def get_controlled_triggers(cls) -> Set[str]:
+        """Get the event triggers that pass the component's value to the handler.
+
+        Returns:
+            The controlled event triggers.
+        """
+        return {"on_change", "on_focus", "on_blur"}
+
+    @classmethod
+    def get_controlled_value(cls) -> Var:
+        """Get the var that is passed to the event handler for controlled triggers.
+
+        Returns:
+            The controlled value.
+        """
+        return EVENT_ARG.target.value
+
+
+class InputGroup(ChakraComponent):
+    """The InputGroup component is a component that is used to group a set of inputs."""
+
+    tag = "InputGroup"
+
+
+class InputLeftAddon(ChakraComponent):
+    """The InputLeftAddon component is a component that is used to add an addon to the left of an input."""
+
+    tag = "InputLeftAddon"
+
+
+class InputRightAddon(ChakraComponent):
+    """The InputRightAddon component is a component that is used to add an addon to the right of an input."""
+
+    tag = "InputRightAddon"

+ 120 - 0
pynecone/components/forms/numberinput.py

@@ -0,0 +1,120 @@
+"""A number input component."""
+
+from typing import Set
+
+from pynecone.components.component import Component
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class NumberInput(ChakraComponent):
+    """The wrapper that provides context and logic to the components."""
+
+    tag = "NumberInput"
+
+    # State var to bind the the input.
+    value: Var[int]
+
+    # If true, the input's value will change based on mouse wheel.
+    allow_mouse_wheel: Var[bool]
+
+    # This controls the value update when you blur out of the input. - If true and the value is greater than max, the value will be reset to max - Else, the value remains the same.
+    clamped_value_on_blur: Var[bool]
+
+    # The initial value of the counter. Should be less than max and greater than min
+    default_value: Var[int]
+
+    # The border color when the input is invalid.
+    error_border_color: Var[str]
+
+    # The border color when the input is focused.
+    focus_border_color: Var[str]
+
+    # If true, the input will be focused as you increment or decrement the value with the stepper
+    focus_input_on_change: Var[bool]
+
+    # Hints at the type of data that might be entered by the user. It also determines the type of keyboard shown to the user on mobile devices ("text" | "search" | "none" | "tel" | "url" | "email" | "numeric" | "decimal")
+    input_mode: Var[str]
+
+    # Whether the input should be disabled.
+    is_disabled: Var[bool]
+
+    # If true, the input will have `aria-invalid` set to true
+    is_invalid: Var[bool]
+
+    # If true, the input will be in readonly mode
+    is_read_only: Var[bool]
+
+    # Whether the input is required
+    is_required: Var[bool]
+
+    # Whether the pressed key should be allowed in the input. The default behavior is to allow DOM floating point characters defined by /^[Ee0-9+\-.]$/
+    is_valid_character: Var[str]
+
+    # This controls the value update behavior in general. - If true and you use the stepper or up/down arrow keys, the value will not exceed the max or go lower than min - If false, the value will be allowed to go out of range.
+    keep_within_range: Var[bool]
+
+    # The maximum value of the counter
+    max_: Var[int]
+
+    # The minimum value of the counter
+    min_: Var[int]
+
+    # "outline" | "filled" | "flushed" | "unstyled"
+    variant: Var[str]
+
+    @classmethod
+    def get_controlled_triggers(cls) -> Set[str]:
+        """Get the event triggers that pass the component's value to the handler.
+
+        Returns:
+            The controlled event triggers.
+        """
+        return {"on_change"}
+
+    @classmethod
+    def create(cls, *children, **props) -> Component:
+        """Create a number input component.
+
+        If no children are provided, a default stepper will be used.
+
+        Args:
+            *children: The children of the component.
+            **props: The props of the component.
+
+        Returns:
+            The component.
+        """
+        if len(children) == 0:
+            children = [
+                NumberInputField.create(),
+                NumberInputStepper.create(
+                    NumberIncrementStepper.create(),
+                    NumberDecrementStepper.create(),
+                ),
+            ]
+        return super().create(*children, **props)
+
+
+class NumberInputField(ChakraComponent):
+    """The input field itself."""
+
+    tag = "NumberInputField"
+
+
+class NumberInputStepper(ChakraComponent):
+    """The wrapper for the input's stepper buttons."""
+
+    tag = "NumberInputStepper"
+
+
+class NumberIncrementStepper(ChakraComponent):
+    """The button to increment the value of the input."""
+
+    tag = "NumberIncrementStepper"
+
+
+class NumberDecrementStepper(ChakraComponent):
+    """The button to decrement the value of the input."""
+
+    tag = "NumberDecrementStepper"

+ 88 - 0
pynecone/components/forms/pininput.py

@@ -0,0 +1,88 @@
+"""A pin input component."""
+
+from typing import Set
+
+from pynecone.components.component import Component
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class PinInput(ChakraComponent):
+    """The component that provides context to all the pin-input fields."""
+
+    tag = "PinInput"
+
+    # State var to bind the the input.
+    value: Var[str]
+
+    # If true, the pin input receives focus on mount
+    auto_focus: Var[bool]
+
+    # The default value of the pin input
+    default_value: Var[str]
+
+    # The border color when the input is invalid.
+    error_border_color: Var[str]
+
+    # The border color when the input is focused.
+    focus_border_color: Var[str]
+
+    # The top-level id string that will be applied to the input fields. The index of the input will be appended to this top-level id.
+    id_: Var[str]
+
+    # The length of the number input.
+    length: Var[int]
+
+    # If true, the pin input component is put in the disabled state
+    is_disabled: Var[bool]
+
+    # If true, the pin input component is put in the invalid state
+    is_invalid: Var[bool]
+
+    # If true, focus will move automatically to the next input once filled
+    manage_focus: Var[bool]
+
+    # If true, the input's value will be masked just like `type=password`
+    mask: Var[bool]
+
+    # The placeholder for the pin input
+    placeholder: Var[str]
+
+    # The type of values the pin-input should allow ("number" | "alphanumeric").
+    type_: Var[str]
+
+    # "outline" | "flushed" | "filled" | "unstyled"
+    variant: Var[str]
+
+    @classmethod
+    def get_controlled_triggers(cls) -> Set[str]:
+        """Get the event triggers that pass the component's value to the handler.
+
+        Returns:
+            The controlled event triggers.
+        """
+        return {"on_change", "on_complete"}
+
+    @classmethod
+    def create(cls, *children, **props) -> Component:
+        """Create a pin input component.
+
+        If no children are passed in, the component will create a default pin input
+        based on the length prop.
+
+        Args:
+            *children: The children of the component.
+            **props: The props of the component.
+
+        Returns:
+            The pin input component.
+        """
+        if len(children) == 0 and "length" in props:
+            children = [PinInputField()] * props["length"]
+        return super().create(*children, **props)
+
+
+class PinInputField(ChakraComponent):
+    """The text field that user types in - must be a direct child of PinInput."""
+
+    tag = "PinInputField"

+ 93 - 0
pynecone/components/forms/radio.py

@@ -0,0 +1,93 @@
+"""A radio component."""
+
+
+from typing import Any, Set
+
+from pynecone.components.component import Component
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.components.typography.text import Text
+from pynecone.var import Var
+
+
+class RadioGroup(ChakraComponent):
+    """A grouping of individual radio options."""
+
+    tag = "RadioGroup"
+
+    # State var to bind the the input.
+    value: Var[Any]
+
+    @classmethod
+    def get_controlled_triggers(cls) -> Set[str]:
+        """Get the event triggers that pass the component's value to the handler.
+
+        Returns:
+            The controlled event triggers.
+        """
+        return {"on_change"}
+
+    @classmethod
+    def create(cls, *children, **props) -> Component:
+        """Create a radio group component.
+
+        Args:
+            *children: The children of the component.
+            **props: The props of the component.
+
+        Returns:
+            The component.
+        """
+        if len(children) == 1 and isinstance(children[0], list):
+            children = [Radio.create(child) for child in children[0]]
+        return super().create(*children, **props)
+
+
+class Radio(Text):
+    """Radios are used when only one choice may be selected in a series of options."""
+
+    tag = "Radio"
+
+    # Value of radio.
+    value: Var[Any]
+
+    # The default value.
+    default_value: Var[Any]
+
+    # The color scheme.
+    color_scheme: Var[str]
+
+    # If true, the radio will be initially checked.
+    default_checked: Var[bool]
+
+    # If true, the radio will be checked. You'll need to pass onChange to update its value (since it is now controlled)
+    is_checked: Var[bool]
+
+    # If true, the radio will be disabled.
+    is_disabled: Var[bool]
+
+    # If true, the radio button will be invalid. This also sets `aria-invalid` to true.
+    is_invalid: Var[bool]
+
+    # If true, the radio will be read-only
+    is_read_only: Var[bool]
+
+    # If true, the radio button will be required. This also sets `aria-required` to true.
+    is_required: Var[bool]
+
+    @classmethod
+    def create(cls, *children, **props) -> Component:
+        """Create a radio component.
+
+        By default, the value is bound to the first child.
+
+        Args:
+            *children: The children of the component.
+            **props: The props of the component.
+
+        Returns:
+            The radio component.
+        """
+        if "value" not in props:
+            assert len(children) == 1
+            props["value"] = children[0]
+        return super().create(*children, **props)

+ 99 - 0
pynecone/components/forms/rangeslider.py

@@ -0,0 +1,99 @@
+"""A button component."""
+
+from typing import List, Set
+
+from pynecone.components.component import Component
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class RangeSlider(ChakraComponent):
+    """The RangeSlider is a multi thumb slider used to select a range of related values. A common use-case of this component is a price range picker that allows a user to set the minimum and maximum price."""
+
+    tag = "RangeSlider"
+
+    # State var to bind the the input.
+    value: Var[List[int]]
+
+    # The default values.
+    default_value: Var[List[int]]
+
+    # The writing mode ("ltr" | "rtl")
+    direction: Var[str]
+
+    # If false, the slider handle will not capture focus when value changes.
+    focus_thumb_on_change: Var[bool]
+
+    # If true, the slider will be disabled
+    is_disabled: Var[bool]
+
+    # If true, the slider will be in `read-only` state.
+    is_read_only: Var[bool]
+
+    # If true, the value will be incremented or decremented in reverse.
+    is_reversed: Var[bool]
+
+    # The minimum value of the slider.
+    min_: Var[int]
+
+    # The maximum value of the slider.
+    max_: Var[int]
+
+    # The minimum distance between slider thumbs. Useful for preventing the thumbs from being too close together.
+    min_steps_between_thumbs: Var[int]
+
+    @classmethod
+    def get_controlled_triggers(cls) -> Set[str]:
+        """Get the event triggers that pass the component's value to the handler.
+
+        Returns:
+            The controlled event triggers.
+        """
+        return {
+            "on_change",
+            "on_change_end",
+            "on_change_start",
+        }
+
+    @classmethod
+    def create(cls, *children, **props) -> Component:
+        """Create a RangeSlider component.
+
+        If no children are provided, a default RangeSlider will be created.
+
+        Args:
+            children: The children of the component.
+            props: The properties of the component.
+
+        Returns:
+            The RangeSlider component.
+        """
+        if len(children) == 0:
+            children = [
+                RangeSliderTrack.create(
+                    RangeSliderFilledTrack.create(),
+                ),
+                RangeSliderThumb.create(index=0),
+                RangeSliderThumb.create(index=1),
+            ]
+        return super().create(*children, **props)
+
+
+class RangeSliderTrack(ChakraComponent):
+    """A button component."""
+
+    tag = "RangeSliderTrack"
+
+
+class RangeSliderFilledTrack(ChakraComponent):
+    """A button component."""
+
+    tag = "RangeSliderFilledTrack"
+
+
+class RangeSliderThumb(ChakraComponent):
+    """A button component."""
+
+    tag = "RangeSliderThumb"
+
+    index: Var[int]

+ 108 - 0
pynecone/components/forms/select.py

@@ -0,0 +1,108 @@
+"""A select component."""
+
+from typing import Any, Set
+
+from pynecone import utils
+from pynecone.components.component import EVENT_ARG, Component
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.components.tags import Tag
+from pynecone.components.typography.text import Text
+from pynecone.var import Var
+
+
+class Select(ChakraComponent):
+    """Select component is a component that allows users pick a value from predefined options. Ideally, it should be used when there are more than 5 options, otherwise you might consider using a radio group instead."""
+
+    tag = "Select"
+
+    # State var to bind the the select.
+    value: Var[str]
+
+    # The default value of the select.
+    default_value: Var[str]
+
+    # The placeholder text.
+    placeholder: Var[str]
+
+    # The border color when the select is invalid.
+    error_border_color: Var[str]
+
+    # The border color when the select is focused.
+    focus_border_color: Var[str]
+
+    # If true, the select will be disabled.
+    is_disabled: Var[bool]
+
+    # If true, the form control will be invalid. This has 2 side effects: - The FormLabel and FormErrorIcon will have `data-invalid` set to true - The form element (e.g, Input) will have `aria-invalid` set to true
+    is_invalid: Var[bool]
+
+    # If true, the form control will be readonly
+    is_read_only: Var[bool]
+
+    # If true, the form control will be required. This has 2 side effects: - The FormLabel will show a required indicator - The form element (e.g, Input) will have `aria-required` set to true
+    is_required: Var[bool]
+
+    # "outline" | "filled" | "flushed" | "unstyled"
+    variant: Var[str]
+
+    @classmethod
+    def get_controlled_triggers(cls) -> Set[str]:
+        """Get the event triggers that pass the component's value to the handler.
+
+        Returns:
+            The controlled event triggers.
+        """
+        return {"on_change"}
+
+    @classmethod
+    def get_controlled_value(cls) -> Var:
+        """Get the var that is passed to the event handler for controlled triggers.
+
+        Returns:
+            The controlled value.
+        """
+        return EVENT_ARG.target.value
+
+    @classmethod
+    def create(cls, *children, **props) -> Component:
+        """Create a select component.
+
+        If a list is provided as the first children, a default component
+        will be created for each item in the list.
+
+        Args:
+            *children: The children of the component.
+            **props: The props of the component.
+
+        Returns:
+            The component.
+        """
+        if len(children) == 1 and isinstance(children[0], list):
+            children = [Option.create(child) for child in children[0]]
+        return super().create(*children, **props)
+
+
+class Option(Text):
+    """A button component."""
+
+    tag = "option"
+
+    value: Var[Any]
+
+    @classmethod
+    def create(cls, *children, **props) -> Component:
+        """Create a select option component.
+
+        By default, the value of the option is the text of the option.
+
+        Args:
+            *children: The children of the component.
+            **props: The props of the component.
+
+        Returns:
+            The component.
+        """
+        if "value" not in props:
+            assert len(children) == 1
+            props["value"] = children[0]
+        return super().create(*children, **props)

+ 102 - 0
pynecone/components/forms/slider.py

@@ -0,0 +1,102 @@
+"""A slider component."""
+
+from typing import Set
+
+from pynecone.components.component import Component
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class Slider(ChakraComponent):
+    """The wrapper that provides context and functionality for all children."""
+
+    tag = "Slider"
+
+    # State var to bind the the input.
+    value: Var[int]
+
+    # The placeholder text.
+    default_value: Var[int]
+
+    # The writing mode ("ltr" | "rtl")
+    direction: Var[str]
+
+    # If false, the slider handle will not capture focus when value changes.
+    focus_thumb_on_change: Var[bool]
+
+    # If true, the slider will be disabled
+    is_disabled: Var[bool]
+
+    # If true, the slider will be in `read-only` state.
+    is_read_only: Var[bool]
+
+    # If true, the value will be incremented or decremented in reverse.
+    is_reversed: Var[bool]
+
+    # The minimum value of the slider.
+    min_: Var[int]
+
+    # The maximum value of the slider.
+    max_: Var[int]
+
+    # The minimum distance between slider thumbs. Useful for preventing the thumbs from being too close together.
+    min_steps_between_thumbs: Var[int]
+
+    @classmethod
+    def get_controlled_triggers(cls) -> Set[str]:
+        """Get the event triggers that pass the component's value to the handler.
+
+        Returns:
+            The controlled event triggers.
+        """
+        return {
+            "on_change",
+            "on_change_end",
+            "on_change_start",
+        }
+
+    @classmethod
+    def create(cls, *children, **props) -> Component:
+        """Create a slider component.
+
+        If no children are provided, a default slider will be created.
+
+        Args:
+            children: The children of the component.
+            props: The properties of the component.
+
+        Returns:
+            The slider component.
+        """
+        if len(children) == 0:
+            children = [
+                SliderTrack.create(
+                    SliderFilledTrack.create(),
+                ),
+                SliderThumb.create(),
+            ]
+        return super().create(*children, **props)
+
+
+class SliderTrack(ChakraComponent):
+    """The empty part of the slider that shows the track."""
+
+    tag = "SliderTrack"
+
+
+class SliderFilledTrack(ChakraComponent):
+    """The filled part of the slider."""
+
+    tag = "SliderFilledTrack"
+
+
+class SliderThumb(ChakraComponent):
+    """The handle that's used to change the slider value."""
+
+    tag = "SliderThumb"
+
+
+class SliderMark(ChakraComponent):
+    """The label or mark that shows names for specific slider values."""
+
+    tag = "SliderMark"

+ 57 - 0
pynecone/components/forms/switch.py

@@ -0,0 +1,57 @@
+"""A switch component."""
+from typing import Set
+
+from pynecone.components.component import EVENT_ARG
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class Switch(ChakraComponent):
+    """Togglable switch component."""
+
+    tag = "Switch"
+
+    # If true, the switch will be checked. You'll need to pass onChange to update its value (since it is now controlled)
+    is_checked: Var[bool]
+
+    # If true, the switch will be disabled
+    is_disabled: Var[bool]
+
+    # If true and isDisabled is passed, the switch will remain tabbable but not interactive
+    is_focusable: Var[bool]
+
+    # If true, the switch is marked as invalid. Changes style of unchecked state.
+    is_invalid: Var[bool]
+
+    # If true, the switch will be readonly
+    is_read_only: Var[bool]
+
+    # If true, the switch will be required
+    is_required: Var[bool]
+
+    # The name of the input field in a switch (Useful for form submission).
+    name: Var[str]
+
+    # The spacing between the switch and its label text (0.5rem)
+    spacing: Var[str]
+
+    # The placeholder text.
+    placeholder: Var[str]
+
+    @classmethod
+    def get_controlled_triggers(cls) -> Set[str]:
+        """Get the event triggers that pass the component's value to the handler.
+
+        Returns:
+            The controlled event triggers.
+        """
+        return {"on_change"}
+
+    @classmethod
+    def get_controlled_value(cls) -> Var:
+        """Get the var that is passed to the event handler for controlled triggers.
+
+        Returns:
+            The controlled value.
+        """
+        return EVENT_ARG.target.checked

+ 61 - 0
pynecone/components/forms/textarea.py

@@ -0,0 +1,61 @@
+"""A textarea component."""
+
+from typing import Set
+
+from pynecone.components.component import EVENT_ARG
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class TextArea(ChakraComponent):
+    """A text area component."""
+
+    tag = "Textarea"
+
+    # State var to bind the the input.
+    value: Var[str]
+
+    # The default value of the textarea.
+    default_value: Var[str]
+
+    # The placeholder text.
+    placeholder: Var[str]
+
+    # The border color when the input is invalid.
+    error_border_color: Var[str]
+
+    # The border color when the input is focused.
+    focus_border_color: Var[str]
+
+    # If true, the form control will be disabled.
+    is_disabled: Var[bool]
+
+    # If true, the form control will be invalid.
+    is_invalid: Var[bool]
+
+    # If true, the form control will be readonly.
+    is_read_only: Var[bool]
+
+    # If true, the form control will be required.
+    is_required: Var[bool]
+
+    # "outline" | "filled" | "flushed" | "unstyled"
+    variant: Var[str]
+
+    @classmethod
+    def get_controlled_triggers(cls) -> Set[str]:
+        """Get the event triggers that pass the component's value to the handler.
+
+        Returns:
+            The controlled event triggers.
+        """
+        return {"on_change", "on_focus", "on_blur"}
+
+    @classmethod
+    def get_controlled_value(cls) -> Var:
+        """Get the var that is passed to the event handler for controlled triggers.
+
+        Returns:
+            The controlled value.
+        """
+        return EVENT_ARG.target.value

+ 5 - 0
pynecone/components/graphing/__init__.py

@@ -0,0 +1,5 @@
+"""Convenience functions to define layout components."""
+
+from .plotly import Plotly
+
+__all__ = [f for f in dir() if f[0].isupper()]  # type: ignore

+ 53 - 0
pynecone/components/graphing/plotly.py

@@ -0,0 +1,53 @@
+"""Component for displaying a plotly graph."""
+
+from typing import Dict, Union
+
+from plotly.graph_objects import Figure
+from plotly.io import to_json
+
+from pynecone.components.component import Component
+from pynecone.components.tags import Tag
+from pynecone.var import Var
+
+
+class PlotlyLib(Component):
+    """A component that wraps a plotly lib."""
+
+    library = "react-plotly.js"
+
+
+class Plotly(PlotlyLib):
+    """Display a plotly graph."""
+
+    tag = "Plot"
+
+    # The figure to display. This can be a plotly figure or a plotly data json.
+    data: Var[Figure]
+
+    # The layout of the graph.
+    layout: Var[Dict]
+
+    # The width of the graph.
+    width: Var[str]
+
+    # The height of the graph.
+    height: Var[str]
+
+    def _get_imports(self):
+        return {}
+
+    def _get_custom_code(self) -> str:
+        return """
+import dynamic from 'next/dynamic'
+const Plot = dynamic(() => import('react-plotly.js'), { ssr: false }); 
+"""
+
+    def _render(self) -> Tag:
+        if isinstance(self.data, Figure):
+            if self.layout is None:
+                if self.width is not None:
+                    layout = Var.create({"width": self.width, "height": self.height})
+                    assert layout is not None
+                    self.layout = layout
+
+        return super()._render()

+ 14 - 0
pynecone/components/layout/__init__.py

@@ -0,0 +1,14 @@
+"""Convenience functions to define layout components."""
+
+from .box import Box
+from .center import Center, Circle, Square
+from .cond import Cond
+from .container import Container
+from .flex import Flex
+from .foreach import Foreach
+from .grid import Grid, GridItem, ResponsiveGrid
+from .spacer import Spacer
+from .stack import Hstack, Stack, Vstack
+from .wrap import Wrap, WrapItem
+
+__all__ = [f for f in dir() if f[0].isupper()]  # type: ignore

+ 25 - 0
pynecone/components/layout/box.py

@@ -0,0 +1,25 @@
+"""A box component that can contain other components."""
+
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.components.tags import Tag
+from pynecone.var import Var
+
+
+class Box(ChakraComponent):
+    """Renders a box component that can contain other components."""
+
+    tag = "Box"
+
+    # The element to render.
+    element: Var[str]
+
+    def _render(self) -> Tag:
+        return (
+            super()
+            ._render()
+            .add_attrs(
+                **{
+                    "as": self.element,
+                }
+            )
+        )

+ 21 - 0
pynecone/components/layout/center.py

@@ -0,0 +1,21 @@
+"""A box that centers its contents."""
+
+from pynecone.components.libs.chakra import ChakraComponent
+
+
+class Center(ChakraComponent):
+    """Center is a layout component that centers its child within itself. It's useful for centering text, images, and other elements. All box can be used on center to style."""
+
+    tag = "Center"
+
+
+class Square(ChakraComponent):
+    """Square centers its child given size (width and height). All box props can be used on Square."""
+
+    tag = "Square"
+
+
+class Circle(ChakraComponent):
+    """Circle a Square with round border-radius. All box props can be used on Circle."""
+
+    tag = "Circle"

+ 75 - 0
pynecone/components/layout/cond.py

@@ -0,0 +1,75 @@
+"""Create a list of components from an iterable."""
+from __future__ import annotations
+
+from typing import Optional
+
+import pydantic
+
+from pynecone.components.component import Component
+from pynecone.components.layout.box import Box
+from pynecone.components.tags import CondTag, Tag
+from pynecone.var import Var
+
+
+class Cond(Component):
+    """Display a conditional render."""
+
+    # The cond to determine which component to render.
+    cond: Var[bool]
+
+    # The component to render if the cond is true.
+    comp1: Component
+
+    # The component to render if the cond is false.
+    comp2: Component
+
+    # Whether the cond is within another cond.
+    is_nested: bool = False
+
+    @pydantic.validator("cond")
+    def validate_cond(cls, cond: Var) -> Var:
+        """Validate that the cond is a boolean.
+
+        Args:
+            cond: The cond to validate.
+
+        Returns:
+            The validated cond.
+        """
+        assert issubclass(cond.type_, bool), "The var must be a boolean."
+        return cond
+
+    @classmethod
+    def create(
+        cls, cond: Var, comp1: Component, comp2: Optional[Component] = None
+    ) -> Cond:
+        """Create a conditional component.
+
+        Args:
+            cond: The cond to determine which component to render.
+            comp1: The component to render if the cond is true.
+            comp2: The component to render if the cond is false.
+
+        Returns:
+            The conditional component.
+        """
+        if comp2 is None:
+            comp2 = Box.create()
+        if isinstance(comp1, Cond):
+            comp1.is_nested = True
+        if isinstance(comp2, Cond):
+            comp2.is_nested = True
+        return cls(
+            cond=cond,
+            comp1=comp1,
+            comp2=comp2,
+            children=[comp1, comp2],
+        )  # type: ignore
+
+    def _render(self) -> Tag:
+        return CondTag(
+            cond=self.cond,
+            true_value=self.comp1.render(),
+            false_value=self.comp2.render(),
+            is_nested=self.is_nested,
+        )

+ 13 - 0
pynecone/components/layout/container.py

@@ -0,0 +1,13 @@
+"""A flexbox container."""
+
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class Container(ChakraComponent):
+    """Container composes Box so you can pass all Box related props in addition to this."""
+
+    tag = "Container"
+
+    # If true, container will center its children regardless of their width.
+    center_content: Var[bool]

+ 31 - 0
pynecone/components/layout/flex.py

@@ -0,0 +1,31 @@
+"""A reflexive container component."""
+
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class Flex(ChakraComponent):
+    """Flex is Box with display, flex and comes with helpful style shorthand. It renders a div element."""
+
+    tag = "Flex"
+
+    # How to align items in the flex.
+    align: Var[str]
+
+    # Shorthand for flexBasis style prop
+    basis: Var[str]
+
+    # Shorthand for flexDirection style prop
+    direction: Var[str]
+
+    # Shorthand for flexGrow style prop
+    grow: Var[str]
+
+    # The way to justify the items.
+    justify: Var[str]
+
+    # Shorthand for flexWrap style prop
+    wrap: Var[str]
+
+    # Shorthand for flexShrink style prop
+    shrink: Var[str]

+ 62 - 0
pynecone/components/layout/foreach.py

@@ -0,0 +1,62 @@
+"""Create a list of components from an iterable."""
+from __future__ import annotations
+
+from typing import Any, List, Protocol, runtime_checkable
+
+from pynecone.components.component import Component
+from pynecone.components.tags import IterTag, Tag
+from pynecone.var import BaseVar, Var
+
+
+@runtime_checkable
+class RenderFn(Protocol):
+    """A function that renders a component."""
+
+    def __call__(self, *args, **kwargs) -> Component:
+        """Render a component.
+
+        Args:
+            *args: The positional arguments.
+            **kwargs: The keyword arguments.
+
+        Returns: # noqa: DAR202
+            The rendered component.
+        """
+        ...
+
+
+class Foreach(Component):
+    """Display a foreach."""
+
+    # The iterable to create components from.
+    iterable: Var[List]
+
+    # A function from the render args to the component.
+    render_fn: RenderFn
+
+    @classmethod
+    def create(cls, iterable: Var[List], render_fn: RenderFn, **props) -> Foreach:
+        """Create a foreach component.
+
+        Args:
+            iterable: The iterable to create components from.
+            render_fn: A function from the render args to the component.
+            **props: The attributes to pass to each child component.
+
+        Returns:
+            The foreach component.
+        """
+        try:
+            type_ = iterable.type_.__args__[0]
+        except:
+            type_ = Any
+        arg = BaseVar(name="_", type_=type_, is_local=True)
+        return cls(
+            iterable=iterable,
+            render_fn=render_fn,
+            children=[IterTag.render_component(render_fn, arg=arg)],
+            **props,
+        )
+
+    def _render(self) -> Tag:
+        return IterTag(iterable=self.iterable, render_fn=self.render_fn)

+ 105 - 0
pynecone/components/layout/grid.py

@@ -0,0 +1,105 @@
+"""Container to stack elements with spacing."""
+
+from typing import List
+
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class Grid(ChakraComponent):
+    """The main wrapper of th egrid component."""
+
+    tag = "Grid"
+
+    # Shorthand prop for gridAutoColumns
+    auto_columns: Var[str]
+
+    # Shorthand prop for gridAutoFlow
+    auto_flow: Var[str]
+
+    # Shorthand prop for gridAutoRows
+    auto_rows: Var[str]
+
+    # Shorthand prop for gridColumn
+    column: Var[str]
+
+    # Shorthand prop for gridRow
+    row: Var[str]
+
+    # Shorthand prop for gridTemplateColumns
+    template_columns: Var[str]
+
+    # Shorthand prop for gridTemplateRows
+    template_rows: Var[str]
+
+
+class GridItem(ChakraComponent):
+    """Used as a child of Grid to control the span, and start positions within the grid."""
+
+    tag = "GridItem"
+
+    # Shorthand prop for gridArea
+    area: Var[str]
+
+    # Shorthand prop for gridColumnEnd
+    col_end: Var[str]
+
+    # The column number the grid item should start.
+    col_start: Var[int]
+
+    # The number of columns the grid item should span.
+    col_span: Var[int]
+
+    # Shorthand prop for gridRowEnd
+    row_end: Var[str]
+
+    # The row number the grid item should start.
+    row_start: Var[int]
+
+    # The number of rows the grid item should span.
+    row_span: Var[int]
+
+
+class ResponsiveGrid(ChakraComponent):
+    """A responsive grid component."""
+
+    tag = "SimpleGrid"
+
+    # Shorthand prop for gridAutoColumns
+    auto_columns: Var[str]
+
+    # Shorthand prop for gridAutoFlow
+    auto_flow: Var[str]
+
+    # Shorthand prop for gridAutoRows
+    auto_rows: Var[str]
+
+    # Shorthand prop for gridColumn
+    column: Var[str]
+
+    # Shorthand prop for gridRow
+    row: Var[str]
+
+    # Alist that defines the number of columns for each breakpoint.
+    columns: Var[List[int]]
+
+    # The width at which child elements will break into columns. Pass a number for pixel values or a string for any other valid CSS length.
+    min_child_width: Var[str]
+
+    # The gap between the grid items
+    spacing: Var[str]
+
+    # The column gap between the grid items
+    spacing_x: Var[str]
+
+    # The row gap between the grid items
+    spacing_y: Var[str]
+
+    # Shorthand prop for gridTemplateAreas
+    template_areas: Var[str]
+
+    # Shorthand prop for gridTemplateColumns
+    template_columns: Var[str]
+
+    # Shorthand prop for gridTemplateRows
+    template_rows: Var[str]

+ 9 - 0
pynecone/components/layout/spacer.py

@@ -0,0 +1,9 @@
+"""A flexible space component."""
+
+from pynecone.components.libs.chakra import ChakraComponent
+
+
+class Spacer(ChakraComponent):
+    """Display a flexible space."""
+
+    tag = "Spacer"

+ 46 - 0
pynecone/components/layout/stack.py

@@ -0,0 +1,46 @@
+"""Container to stack elements with spacing."""
+
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class Stack(ChakraComponent):
+    """Display a square box."""
+
+    tag = "Stack"
+
+    # Shorthand for alignItems style prop
+    align_items: Var[str]
+
+    # The direction to stack the items.
+    direction: Var[str]
+
+    # If true the items will be stacked horizontally.
+    is_inline: Var[bool]
+
+    # Shorthand for justifyContent style prop
+    justify_content: Var[str]
+
+    # If true, the children will be wrapped in a Box, and the Box will take the spacing props
+    should_wrap_children: Var[bool]
+
+    # The space between each stack item
+    spacing: Var[str]
+
+    # Shorthand for flexWrap style prop
+    wrap: Var[str]
+
+    # Alignment of contents.
+    justify: Var[str]
+
+
+class Hstack(Stack):
+    """The HStack component is a component which is only facing the horizontal direction. Additionally you can add a divider and horizontal spacing between the items."""
+
+    tag = "HStack"
+
+
+class Vstack(Stack):
+    """The VStack component is a component which is only facing the vertical direction. Additionally you can add a divider and vertical spacing between the items."""
+
+    tag = "VStack"

+ 15 - 0
pynecone/components/layout/wrap.py

@@ -0,0 +1,15 @@
+"""Container to stack elements with spacing."""
+
+from pynecone.components.libs.chakra import ChakraComponent
+
+
+class Wrap(ChakraComponent):
+    """Layout component used to add space between elements and wraps automatically if there isn't enough space."""
+
+    tag = "Wrap"
+
+
+class WrapItem(ChakraComponent):
+    """Item of the Wrap component."""
+
+    tag = "WrapItem"

+ 1 - 0
pynecone/components/libs/__init__.py

@@ -0,0 +1 @@
+"""React component libraries."""

+ 9 - 0
pynecone/components/libs/chakra.py

@@ -0,0 +1,9 @@
+"""Components that are based on Chakra-UI."""
+
+from pynecone.components.component import Component
+
+
+class ChakraComponent(Component):
+    """A component that wraps a Chakra component."""
+
+    library = "@chakra-ui/react"

+ 7 - 0
pynecone/components/media/__init__.py

@@ -0,0 +1,7 @@
+"""Media components."""
+
+from .avatar import Avatar, AvatarBadge, AvatarGroup
+from .icon import Icon
+from .image import Image
+
+__all__ = [f for f in dir() if f[0].isupper()]  # type: ignore

+ 69 - 0
pynecone/components/media/avatar.py

@@ -0,0 +1,69 @@
+"""Avatar components."""
+
+from typing import Set
+
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class Avatar(ChakraComponent):
+    """The image that represents the user."""
+
+    tag = "Avatar"
+
+    # Function to get the initials to display.
+    get_initials: Var[str]
+
+    # The default avatar used as fallback when name, and src is not specified.
+    icon: Var[str]
+
+    # The label of the icon.
+    icon_label: Var[str]
+
+    # If true, opt out of the avatar's fallback logic and renders the img at all times.
+    ignore_fallback: Var[bool]
+
+    # Defines loading strategy ("eager" | "lazy").
+    loading: Var[str]
+
+    # The name of the person in the avatar.
+    name: Var[str]
+
+    # If true, the Avatar will show a border around it. Best for a group of avatars.
+    show_border: Var[bool]
+
+    # The image url of the Avatar.
+    src: Var[str]
+
+    # List of sources to use for different screen resolutions.
+    src_set: Var[str]
+
+    # "2xs" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "full"
+    size: Var[str]
+
+    @classmethod
+    def get_triggers(cls) -> Set[str]:
+        """Get the event triggers for the component.
+
+        Returns:
+            The event triggers.
+        """
+        return super().get_triggers() | {"on_error"}
+
+
+class AvatarBadge(ChakraComponent):
+    """A wrapper that displays its content on the right corner of the avatar."""
+
+    tag = "AvatarBadge"
+
+
+class AvatarGroup(ChakraComponent):
+    """A wrapper to stack multiple Avatars together."""
+
+    tag = "AvatarGroup"
+
+    # The maximum number of visible avatars.
+    max_: Var[int]
+
+    # The space between the avatars in the group.
+    spacing: Var[int]

+ 15 - 0
pynecone/components/media/icon.py

@@ -0,0 +1,15 @@
+"""An image component."""
+
+from pynecone.components.component import Component
+
+
+class ChakraIconComponent(Component):
+    """A component that wraps a chakra icon component."""
+
+    library = "@chakra-ui/icons"
+
+
+class Icon(ChakraIconComponent):
+    """The Avatar component is used to represent a user, and displays the profile picture, initials or fallback icon."""
+
+    tag = "None"

+ 53 - 0
pynecone/components/media/image.py

@@ -0,0 +1,53 @@
+"""An image component."""
+from __future__ import annotations
+
+from typing import Optional, Set
+
+from pynecone.components.component import Component
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class Image(ChakraComponent):
+    """The Image component is used to display images. Image composes Box so you can use all the style props and add responsive styles as well."""
+
+    tag = "Image"
+
+    # How to align the image within its bounds. It maps to css `object-position` property.
+    align: Var[str]
+
+    # Fallback Pynecone component to show if image is loading or image fails.
+    fallback: Optional[Component] = None
+
+    # Fallback image src to show if image is loading or image fails.
+    fallback_src: Var[str]
+
+    # How the image to fit within its bounds. It maps to css `object-fit` property.
+    fit: Var[str]
+
+    # The native HTML height attribute to the passed to the img.
+    html_height: Var[str]
+
+    # The native HTML width attribute to the passed to the img.
+    html_width: Var[str]
+
+    # If true, opt out of the fallbackSrc logic and use as img.
+    ignore_fallback: Var[bool]
+
+    # "eager" | "lazy"
+    loading: Var[str]
+
+    # The image src attribute.
+    src: Var[str]
+
+    # The image srcset attribute.
+    src_set: Var[str]
+
+    @classmethod
+    def get_triggers(cls) -> Set[str]:
+        """Get the event triggers for the component.
+
+        Returns:
+            The event triggers.
+        """
+        return super().get_triggers() | {"on_error", "on_load"}

+ 8 - 0
pynecone/components/navigation/__init__.py

@@ -0,0 +1,8 @@
+"""Navigation components."""
+
+from .breadcrumb import Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbSeparator
+from .link import Link
+from .linkoverlay import LinkBox, LinkOverlay
+from .nextlink import NextLink
+
+__all__ = [f for f in dir() if f[0].isupper()]  # type: ignore

+ 52 - 0
pynecone/components/navigation/breadcrumb.py

@@ -0,0 +1,52 @@
+"""Breadcrumb components."""
+
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class Breadcrumb(ChakraComponent):
+    """The parent container for breadcrumbs."""
+
+    tag = "Breadcrumb"
+
+    # The visual separator between each breadcrumb item
+    separator: Var[str]
+
+    # The left and right margin applied to the separator
+    separator_margin: Var[str]
+
+
+class BreadcrumbItem(ChakraComponent):
+    """Individual breadcrumb element containing a link and a divider."""
+
+    tag = "BreadcrumbItem"
+
+    # Is the current page of the breadcrumb.
+    is_current_page: Var[bool]
+
+    # Is the last child of the breadcrumb.
+    is_last_child: Var[bool]
+
+    # The visual separator between each breadcrumb item
+    separator: Var[str]
+
+    # The left and right margin applied to the separator
+    spacing: Var[str]
+
+    # The href of the item.
+    href: Var[str]
+
+
+class BreadcrumbSeparator(ChakraComponent):
+    """The visual separator between each breadcrumb."""
+
+    tag = "BreadcrumbSeparator"
+
+
+class BreadcrumbLink(ChakraComponent):
+    """The breadcrumb link."""
+
+    tag = "BreadcrumbLink"
+
+    # Is the current page of the breadcrumb.
+    is_current_page: Var[bool]

+ 42 - 0
pynecone/components/navigation/link.py

@@ -0,0 +1,42 @@
+"""A link component."""
+
+from pynecone.components.component import Component
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.components.navigation.nextlink import NextLink
+from pynecone.var import Var
+
+
+class Link(ChakraComponent):
+    """Component the provides a link."""
+
+    tag = "Link"
+
+    # The rel.
+    rel: Var[str]
+
+    # The page to link to.
+    href: Var[str]
+
+    # The text to display.
+    text: Var[str]
+
+    # If true, the link will open in new tab.
+    is_external: Var[bool]
+
+    @classmethod
+    def create(cls, *children, **props) -> Component:
+        """Create a NextJS link component, wrapping a Chakra link component.
+
+        Args:
+            *children: The children to pass to the component.
+            **props: The attributes to pass to the component.
+
+        Returns:
+            The component.
+        """
+        kwargs = {}
+        if "href" in props:
+            kwargs["href"] = props.pop("href")
+        else:
+            kwargs["href"] = "#"
+        return NextLink.create(super().create(*children, **props), **kwargs)

+ 22 - 0
pynecone/components/navigation/linkoverlay.py

@@ -0,0 +1,22 @@
+"""Link overlay components."""
+
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class LinkOverlay(ChakraComponent):
+    """Wraps cild componet in a link."""
+
+    tag = "LinkOverlay"
+
+    # If true, the link will open in new tab
+    is_external: Var[bool]
+
+    # Href of the link overlay.
+    href: Var[str]
+
+
+class LinkBox(ChakraComponent):
+    """The LinkBox lifts any nested links to the top using z-index to ensure proper keyboard navigation between links."""
+
+    tag = "LinkBox"

+ 22 - 0
pynecone/components/navigation/nextlink.py

@@ -0,0 +1,22 @@
+"""A link component."""
+
+from pynecone.components.component import Component
+from pynecone.var import Var
+
+
+class NextLinkLib(Component):
+    """A component that inherits from next/link."""
+
+    library = "next/link"
+
+
+class NextLink(NextLinkLib):
+    """Links are accessible elements used primarily for navigation. This component is styled to resemble a hyperlink and semantically renders an <a>."""
+
+    tag = "NextLink"
+
+    # The page to link to.
+    href: Var[str]
+
+    # Whether to pass the href prop to the child.
+    pass_href: Var[bool] = True  # type: ignore

+ 50 - 0
pynecone/components/overlay/__init__.py

@@ -0,0 +1,50 @@
+"""Overlay components."""
+
+from .alertdialog import (
+    AlertDialog,
+    AlertDialogBody,
+    AlertDialogContent,
+    AlertDialogFooter,
+    AlertDialogHeader,
+    AlertDialogOverlay,
+)
+from .drawer import (
+    Drawer,
+    DrawerBody,
+    DrawerCloseButton,
+    DrawerContent,
+    DrawerFooter,
+    DrawerHeader,
+    DrawerOverlay,
+)
+from .menu import (
+    Menu,
+    MenuButton,
+    MenuDivider,
+    MenuGroup,
+    MenuItem,
+    MenuItemOption,
+    MenuList,
+    MenuOptionGroup,
+)
+from .modal import (
+    Modal,
+    ModalBody,
+    ModalCloseButton,
+    ModalContent,
+    ModalFooter,
+    ModalHeader,
+    ModalOverlay,
+)
+from .popover import (
+    Popover,
+    PopoverAnchor,
+    PopoverArrow,
+    PopoverBody,
+    PopoverCloseButton,
+    PopoverContent,
+    PopoverFooter,
+    PopoverHeader,
+    PopoverTrigger,
+)
+from .tooltip import Tooltip

+ 101 - 0
pynecone/components/overlay/alertdialog.py

@@ -0,0 +1,101 @@
+"""Alert dialog components."""
+
+from typing import Set
+
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class AlertDialog(ChakraComponent):
+    """Provides context and state for the dialog."""
+
+    tag = "AlertDialog"
+
+    # If true, the modal will be open.
+    is_open: Var[bool]
+
+    # The least destructive element to focus when the dialog opens.
+    least_destructive_ref: Var[str]
+
+    # Handle zoom/pinch gestures on iOS devices when scroll locking is enabled. Defaults to false.
+    allow_pinch_zoom: Var[bool]
+
+    # If true, the modal will autofocus the first enabled and interactive element within the ModalContent
+    auto_focus: Var[bool]
+
+    # If true, scrolling will be disabled on the body when the modal opens.
+    block_scroll_on_mount: Var[bool]
+
+    # If true, the modal will close when the Esc key is pressed
+    close_on_esc: Var[bool]
+
+    # If true, the modal will close when the overlay is clicked
+    close_on_overlay_click: Var[bool]
+
+    # If true, the modal will be centered on screen.
+    is_centered: Var[bool]
+
+    # Enables aggressive focus capturing within iframes. If true, keep focus in the lock, no matter where lock is active. If false, allows focus to move outside of iframe.
+    lock_focus_across_frames: Var[bool]
+
+    # If true, a `padding-right` will be applied to the body element that's equal to the width of the scrollbar. This can help prevent some unpleasant flickering effect and content adjustment when the modal opens
+    preserve_scroll_bar_gap: Var[bool]
+
+    # If true, the modal will return focus to the element that triggered it when it closes.
+    return_focus_on_close: Var[bool]
+
+    # "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | "6xl" | "full"
+    size: Var[str]
+
+    # If true, the siblings of the modal will have `aria-hidden` set to true so that screen readers can only see the modal. This is commonly known as making the other elements **inert**
+    use_intert: Var[bool]
+
+    @classmethod
+    def get_triggers(cls) -> Set[str]:
+        """Get the event triggers for the component.
+
+        Returns:
+            The event triggers.
+        """
+        return super().get_triggers() | {
+            "on_close",
+            "on_close_complete",
+            "on_esc",
+            "on_overlay_click",
+        }
+
+
+class AlertDialogBody(ChakraComponent):
+    """Should contain the description announced by screen readers."""
+
+    tag = "AlertDialogBody"
+
+
+class AlertDialogHeader(ChakraComponent):
+    """Should contain the title announced by screen readers."""
+
+    tag = "AlertDialogHeader"
+
+
+class AlertDialogFooter(ChakraComponent):
+    """Should contain the events of the dialog."""
+
+    tag = "AlertDialogFooter"
+
+
+class AlertDialogContent(ChakraComponent):
+    """The wrapper for the alert dialog's content."""
+
+    tag = "AlertDialogContent"
+
+
+class AlertDialogOverlay(ChakraComponent):
+    """The dimmed overlay behind the dialog."""
+
+    tag = "AlertDialogOverlay"
+
+
+class AlertDialogCloseButton(ChakraComponent):
+    """The button that closes the dialog."""
+
+    tag = "AlertDialogCloseButton"

+ 107 - 0
pynecone/components/overlay/drawer.py

@@ -0,0 +1,107 @@
+"""Container to stack elements with spacing."""
+
+from typing import Set
+
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class Drawer(ChakraComponent):
+    """A drawer component."""
+
+    tag = "Drawer"
+
+    # If true, the modal will be open.
+    is_open: Var[bool]
+
+    # Handle zoom/pinch gestures on iOS devices when scroll locking is enabled. Defaults to false.
+    allow_pinch_zoom: Var[bool]
+
+    # If true, the modal will autofocus the first enabled and interactive element within the ModalContent
+    auto_focus: Var[bool]
+
+    # If true, scrolling will be disabled on the body when the modal opens.
+    block_scroll_on_mount: Var[bool]
+
+    # If true, the modal will close when the Esc key is pressed
+    close_on_esc: Var[bool]
+
+    # If true, the modal will close when the overlay is clicked
+    close_on_overlay_click: Var[bool]
+
+    # If true, the modal will be centered on screen.
+    is_centered: Var[bool]
+
+    # If true and drawer's placement is top or bottom, the drawer will occupy the viewport height (100vh)
+    is_full_height: Var[bool]
+
+    # Enables aggressive focus capturing within iframes. - If true: keep focus in the lock, no matter where lock is active - If false: allows focus to move outside of iframe
+    lock_focus_across_frames: Var[bool]
+
+    # The placement of the drawer
+    placement: Var[str]
+
+    # If true, a `padding-right` will be applied to the body element that's equal to the width of the scrollbar. This can help prevent some unpleasant flickering effect and content adjustment when the modal opens
+    preserve_scroll_bar_gap: Var[bool]
+
+    # If true, the modal will return focus to the element that triggered it when it closes.
+    return_focus_on_close: Var[bool]
+
+    # "xs" | "sm" | "md" | "lg" | "xl" | "full"
+    size: Var[str]
+
+    # A11y: If true, the siblings of the modal will have `aria-hidden` set to true so that screen readers can only see the modal. This is commonly known as making the other elements **inert**
+    use_intert: Var[bool]
+
+    # Variant of drawer
+    variant: Var[str]
+
+    @classmethod
+    def get_triggers(cls) -> Set[str]:
+        """Get the event triggers for the component.
+
+        Returns:
+            The event triggers.
+        """
+        return super().get_triggers() | {
+            "on_close",
+            "on_close_complete",
+            "on_esc",
+            "on_overlay_click",
+        }
+
+
+class DrawerBody(ChakraComponent):
+    """Drawer body."""
+
+    tag = "DrawerBody"
+
+
+class DrawerHeader(ChakraComponent):
+    """Drawer header."""
+
+    tag = "DrawerHeader"
+
+
+class DrawerFooter(ChakraComponent):
+    """Drawer footer."""
+
+    tag = "DrawerFooter"
+
+
+class DrawerOverlay(Drawer):
+    """Drawer overlay."""
+
+    tag = "DrawerOverlay"
+
+
+class DrawerContent(Drawer):
+    """Drawer content."""
+
+    tag = "DrawerContent"
+
+
+class DrawerCloseButton(Drawer):
+    """Drawer close button."""
+
+    tag = "DrawerCloseButton"

+ 160 - 0
pynecone/components/overlay/menu.py

@@ -0,0 +1,160 @@
+"""Menu components."""
+
+from typing import Set
+
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class Menu(ChakraComponent):
+    """The wrapper component provides context, state, and focus management."""
+
+    tag = "Menu"
+
+    # The padding required to prevent the arrow from reaching the very edge of the popper.
+    arrow_padding: Var[int]
+
+    # If true, the first enabled menu item will receive focus and be selected when the menu opens.
+    auto_select: Var[bool]
+
+    # The boundary area for the popper. Used within the preventOverflow modifier
+    boundary: Var[str]
+
+    # If true, the menu will close when you click outside the menu list
+    close_on_blur: Var[bool]
+
+    # If true, the menu will close when a menu item is clicked
+    close_on_select: Var[bool]
+
+    # If by default the menu is open.
+    default_is_open: Var[bool]
+
+    # If rtl, poper placement positions will be flipped i.e. 'top-right' will become 'top-left' and vice-verse ("ltr" | "rtl")
+    direction: Var[str]
+
+    # If true, the popper will change its placement and flip when it's about to overflow its boundary area.
+    flip: Var[bool]
+
+    # The distance or margin between the reference and popper. It is used internally to create an offset modifier. NB: If you define offset prop, it'll override the gutter.
+    gutter: Var[int]
+
+    # Performance 🚀: If true, the MenuItem rendering will be deferred until the menu is open.
+    is_lazy: Var[bool]
+
+    # Performance 🚀: The lazy behavior of menu's content when not visible. Only works when `isLazy={true}` - "unmount": The menu's content is always unmounted when not open. - "keepMounted": The menu's content initially unmounted, but stays mounted when menu is open.
+    lazy_behavior: Var[str]
+
+    # Determines if the menu is open or not.
+    is_open: Var[bool]
+
+    # If true, the popper will match the width of the reference at all times. It's useful for autocomplete, `date-picker` and select patterns.
+    match_width: Var[bool]
+
+    # The placement of the popper relative to its reference.
+    placement: Var[str]
+
+    # If true, will prevent the popper from being cut off and ensure it's visible within the boundary area.
+    prevent_overflow: Var[bool]
+
+    # The CSS positioning strategy to use. ("fixed" | "absolute")
+    strategy: Var[str]
+
+    @classmethod
+    def get_triggers(cls) -> Set[str]:
+        """Get the event triggers for the component.
+
+        Returns:
+            The event triggers.
+        """
+        return super().get_triggers() | {"on_close", "on_open"}
+
+
+class MenuButton(ChakraComponent):
+    """The trigger for the menu list. Must be a direct child of Menu."""
+
+    tag = "MenuButton"
+
+    variant: Var[str]
+
+    as_: Var[str]
+
+
+class MenuList(ChakraComponent):
+    """The wrapper for the menu items. Must be a direct child of Menu."""
+
+    tag = "MenuList"
+
+
+class MenuItem(Menu):
+    """The trigger that handles menu selection. Must be a direct child of a MenuList."""
+
+    tag = "MenuItem"
+
+    # Overrides the parent menu's closeOnSelect prop.
+    close_on_select: Var[bool]
+
+    # Right-aligned label text content, useful for displaying hotkeys.
+    command: Var[str]
+
+    # The spacing between the command and menu item's label.
+    command_spacing: Var[int]
+
+    # If true, the menuitem will be disabled.
+    is_disabled: Var[bool]
+
+    # If true and the menuitem is disabled, it'll remain keyboard-focusable
+    is_focusable: Var[bool]
+
+
+class MenuItemOption(Menu):
+    """The checkable menu item, to be used with MenuOptionGroup."""
+
+    tag = "MenuItemOption"
+
+    # Overrides the parent menu's closeOnSelect prop.
+    close_on_select: Var[bool]
+
+    # Right-aligned label text content, useful for displaying hotkeys.
+    command: Var[str]
+
+    # The spacing between the command and menu item's label.
+    command_spacing: Var[int]
+
+    # Determines if menu item is checked.
+    is_checked: Var[bool]
+
+    # If true, the menuitem will be disabled.
+    is_disabled: Var[bool]
+
+    # If true and the menuitem is disabled, it'll remain keyboard-focusable
+    is_focusable: Var[bool]
+
+    # "checkbox" | "radio"
+    type_: Var[str]
+
+    # Value of the menu item.
+    value: Var[str]
+
+
+class MenuGroup(Menu):
+    """A wrapper to group related menu items."""
+
+    tag = "MenuGroup"
+
+
+class MenuOptionGroup(Menu):
+    """A wrapper for checkable menu items (radio and checkbox)."""
+
+    tag = "MenuOptionGroup"
+
+    # "checkbox" | "radio"
+    type_: Var[str]
+
+    # Value of the option group.
+    value: Var[str]
+
+
+class MenuDivider(Menu):
+    """A visual separator for menu items and groups."""
+
+    tag = "MenuDivider"

+ 101 - 0
pynecone/components/overlay/modal.py

@@ -0,0 +1,101 @@
+"""Modal components."""
+
+from typing import Set
+
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class Modal(ChakraComponent):
+    """The wrapper that provides context for its children."""
+
+    tag = "Modal"
+
+    # If true, the modal will be open.
+    is_open: Var[bool]
+
+    # Handle zoom/pinch gestures on iOS devices when scroll locking is enabled. Defaults to false.
+    allow_pinch_zoom: Var[bool]
+
+    # If true, the modal will autofocus the first enabled and interactive element within the ModalContent
+    auto_focus: Var[bool]
+
+    # If true, scrolling will be disabled on the body when the modal opens.
+    block_scroll_on_mount: Var[bool]
+
+    # If true, the modal will close when the Esc key is pressed
+    close_on_esc: Var[bool]
+
+    # If true, the modal will close when the overlay is clicked
+    close_on_overlay_click: Var[bool]
+
+    # If true, the modal will be centered on screen.
+    is_centered: Var[bool]
+
+    # Enables aggressive focus capturing within iframes. - If true: keep focus in the lock, no matter where lock is active - If false: allows focus to move outside of iframe
+    lock_focus_across_frames: Var[bool]
+
+    # The transition that should be used for the modal
+    motion_preset: Var[str]
+
+    # If true, a `padding-right` will be applied to the body element that's equal to the width of the scrollbar. This can help prevent some unpleasant flickering effect and content adjustment when the modal opens
+    preserve_scroll_bar_gap: Var[bool]
+
+    # If true, the modal will return focus to the element that triggered it when it closes.
+    return_focus_on_close: Var[bool]
+
+    # "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | "6xl" | "full"
+    size: Var[str]
+
+    # A11y: If true, the siblings of the modal will have `aria-hidden` set to true so that screen readers can only see the modal. This is commonly known as making the other elements **inert**
+    use_intert: Var[bool]
+
+    @classmethod
+    def get_triggers(cls) -> Set[str]:
+        """Get the event triggers for the component.
+
+        Returns:
+            The event triggers.
+        """
+        return super().get_triggers() | {
+            "on_close",
+            "on_close_complete",
+            "on_esc",
+            "on_overlay_click",
+        }
+
+
+class ModalOverlay(Modal):
+    """The dimmed overlay behind the modal dialog."""
+
+    tag = "ModalOverlay"
+
+
+class ModalHeader(ChakraComponent):
+    """The header that labels the modal dialog."""
+
+    tag = "ModalHeader"
+
+
+class ModalFooter(ChakraComponent):
+    """The footer that houses the modal events."""
+
+    tag = "ModalFooter"
+
+
+class ModalContent(Modal):
+    """The container for the modal dialog's content."""
+
+    tag = "ModalContent"
+
+
+class ModalBody(ChakraComponent):
+    """The wrapper that houses the modal's main content."""
+
+    tag = "ModalBody"
+
+
+class ModalCloseButton(Modal):
+    """The button that closes the modal."""
+
+    tag = "ModalCloseButton"

+ 132 - 0
pynecone/components/overlay/popover.py

@@ -0,0 +1,132 @@
+"""Popover components."""
+
+from typing import Set
+
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class Popover(ChakraComponent):
+    """The wrapper that provides props, state, and context to its children."""
+
+    tag = "Popover"
+
+    # The padding required to prevent the arrow from reaching the very edge of the popper.
+    arrow_padding: Var[int]
+
+    # The `box-shadow` of the popover arrow
+    arrow_shadow_color: Var[str]
+
+    # The size of the popover arrow
+    arrow_size: Var[int]
+
+    # If true, focus will be transferred to the first interactive element when the popover opens
+    auto_focus: Var[bool]
+
+    # The boundary area for the popper. Used within the preventOverflow modifier
+    boundary: Var[str]
+
+    # If true, the popover will close when you blur out it by clicking outside or tabbing out
+    close_on_blur: Var[bool]
+
+    # If true, the popover will close when you hit the Esc key
+    close_on_esc: Var[bool]
+
+    # If true, the popover will be initially opened.
+    default_is_open: Var[bool]
+
+    # Theme direction ltr or rtl. Popper's placement will be set accordingly
+    direction: Var[str]
+
+    # If true, the popper will change its placement and flip when it's about to overflow its boundary area.
+    flip: Var[bool]
+
+    # The distance or margin between the reference and popper. It is used internally to create an offset modifier. NB: If you define offset prop, it'll override the gutter.
+    gutter: Var[int]
+
+    # The html id attribute of the popover. If not provided, we generate a unique id. This id is also used to auto-generate the `aria-labelledby` and `aria-describedby` attributes that points to the PopoverHeader and PopoverBody
+    id_: Var[str]
+
+    # Performance 🚀: If true, the PopoverContent rendering will be deferred until the popover is open.
+    is_lazy: Var[bool]
+
+    # Performance 🚀: The lazy behavior of popover's content when not visible. Only works when `isLazy={true}` - "unmount": The popover's content is always unmounted when not open. - "keepMounted": The popover's content initially unmounted, but stays mounted when popover is open.
+    lazy_behavior: Var[str]
+
+    # If true, the popover will be opened in controlled mode.
+    is_open: Var[bool]
+
+    # If true, the popper will match the width of the reference at all times. It's useful for autocomplete, `date-picker` and select patterns.
+    match_width: Var[bool]
+
+    # The placement of the popover. It's used internally by Popper.js.
+    placement: Var[str]
+
+    # If true, will prevent the popper from being cut off and ensure it's visible within the boundary area.
+    prevent_overflow: Var[bool]
+
+    # If true, focus will be returned to the element that triggers the popover when it closes
+    return_focus_on_close: Var[bool]
+
+    # The CSS positioning strategy to use. ("fixed" | "absolute")
+    strategy: Var[str]
+
+    # The interaction that triggers the popover. hover - means the popover will open when you hover with mouse or focus with keyboard on the popover trigger click - means the popover will open on click or press Enter to Space on keyboard ("click" | "hover")
+    trigger: Var[str]
+
+    @classmethod
+    def get_triggers(cls) -> Set[str]:
+        """Get the event triggers for the component.
+
+        Returns:
+            The event triggers.
+        """
+        return super().get_triggers() | {"on_close", "on_open"}
+
+
+class PopoverContent(Popover):
+    """The popover itself."""
+
+    tag = "PopoverContent"
+
+
+class PopoverHeader(ChakraComponent):
+    """The header of the popover."""
+
+    tag = "PopoverHeader"
+
+
+class PopoverFooter(ChakraComponent):
+    """Display a popover footer."""
+
+    tag = "PopoverFooter"
+
+
+class PopoverBody(ChakraComponent):
+    """The body of the popover."""
+
+    tag = "PopoverBody"
+
+
+class PopoverArrow(Popover):
+    """A visual arrow that points to the reference (or trigger)."""
+
+    tag = "PopoverArrow"
+
+
+class PopoverCloseButton(Popover):
+    """A button to close the popover."""
+
+    tag = "PopoverCloseButton"
+
+
+class PopoverAnchor(Popover):
+    """Used to wrap the position-reference element."""
+
+    tag = "PopoverAnchor"
+
+
+class PopoverTrigger(Popover):
+    """Used to wrap the reference (or trigger) element."""
+
+    tag = "PopoverTrigger"

+ 72 - 0
pynecone/components/overlay/tooltip.py

@@ -0,0 +1,72 @@
+"""Tooltip components."""
+
+from typing import Set
+
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.var import Var
+
+
+class Tooltip(ChakraComponent):
+    """A tooltip message to appear."""
+
+    tag = "Tooltip"
+
+    # The padding required to prevent the arrow from reaching the very edge of the popper.
+    arrow_padding: Var[int]
+
+    # The color of the arrow shadow.
+    arrow_shadow_color: Var[str]
+
+    # Size of the arrow.
+    arrow_size: Var[int]
+
+    # Delay (in ms) before hiding the tooltip
+    delay: Var[int]
+
+    # If true, the tooltip will hide on click
+    close_on_click: Var[bool]
+
+    # If true, the tooltip will hide on pressing Esc key
+    close_on_esc: Var[bool]
+
+    # If true, the tooltip will hide while the mouse is down
+    close_on_mouse_down: Var[bool]
+
+    # If true, the tooltip will be initially shown
+    default_is_open: Var[bool]
+
+    # Theme direction ltr or rtl. Popper's placement will be set accordingly
+    direction: Var[str]
+
+    # The distance or margin between the reference and popper. It is used internally to create an offset modifier. NB: If you define offset prop, it'll override the gutter.
+    gutter: Var[int]
+
+    # If true, the tooltip will show an arrow tip
+    has_arrow: Var[bool]
+
+    # If true, th etooltip with be disabled.
+    is_disabled: Var[bool]
+
+    # If true, the tooltip will be open.
+    is_open: Var[bool]
+
+    # The label of the tooltip
+    label: Var[str]
+
+    # Delay (in ms) before showing the tooltip
+    open_delay: Var[int]
+
+    # The placement of the popper relative to its reference.
+    placement: Var[str]
+
+    # If true, the tooltip will wrap its children in a `<span/>` with `tabIndex=0`
+    should_wrap_children: Var[bool]
+
+    @classmethod
+    def get_triggers(cls) -> Set[str]:
+        """Get the event triggers for the component.
+
+        Returns:
+            The event triggers.
+        """
+        return super().get_triggers() | {"on_close", "on_open"}

+ 5 - 0
pynecone/components/tags/__init__.py

@@ -0,0 +1,5 @@
+"""Representations for React tags."""
+
+from .cond_tag import CondTag
+from .iter_tag import IterTag
+from .tag import Tag

+ 35 - 0
pynecone/components/tags/cond_tag.py

@@ -0,0 +1,35 @@
+"""Tag to conditionally render components."""
+
+from pynecone import utils
+from pynecone.components.tags.tag import Tag
+from pynecone.var import Var
+
+
+class CondTag(Tag):
+    """A conditional tag."""
+
+    # The condition to determine which component to render.
+    cond: Var[bool]
+
+    # The code to render if the condition is true.
+    true_value: str
+
+    # The code to render if the condition is false.
+    false_value: str
+
+    # Whether the cond tag is nested.
+    is_nested: bool = False
+
+    def __str__(self) -> str:
+        """Render the tag as a React string.
+
+        Returns:
+            The React code to render the tag.
+        """
+        assert self.cond is not None, "The condition must be set."
+        return utils.format_cond(
+            cond=self.cond.full_name,
+            true_value=self.true_value,
+            false_value=self.false_value,
+            is_nested=self.is_nested,
+        )

+ 90 - 0
pynecone/components/tags/iter_tag.py

@@ -0,0 +1,90 @@
+"""Tag to loop through a list of components."""
+from __future__ import annotations
+
+import inspect
+from typing import TYPE_CHECKING, Any, Callable, List
+
+from pynecone import utils
+from pynecone.components.tags.tag import Tag
+from pynecone.var import BaseVar, Var
+
+if TYPE_CHECKING:
+    from pynecone.components.component import Component
+
+
+INDEX_VAR = "i"
+
+
+class IterTag(Tag):
+    """An iterator tag."""
+
+    # The var to iterate over.
+    iterable: Var[List]
+
+    # The component render function for each item in the iterable.
+    render_fn: Callable
+
+    @staticmethod
+    def get_index_var() -> Var:
+        """Get the index var for the tag.
+
+        Returns:
+            The index var.
+        """
+        index = Var.create(INDEX_VAR, is_local=False)
+        assert index is not None
+        return index
+
+    @staticmethod
+    def get_index_var_arg() -> Var:
+        """Get the index var for the tag.
+
+        Returns:
+            The index var.
+        """
+        arg = Var.create(INDEX_VAR)
+        assert arg is not None
+        return arg
+
+    @staticmethod
+    def render_component(render_fn: Callable, arg: Var) -> Component:
+        """Render the component.
+
+        Args:
+            render_fn: The render function.
+            arg: The argument to pass to the render function.
+
+        Returns:
+            The rendered component.
+        """
+        args = inspect.getfullargspec(render_fn).args
+        index = IterTag.get_index_var()
+        if len(args) == 1:
+            component = render_fn(arg)
+        else:
+            assert len(args) == 2
+            component = render_fn(arg, index)
+        if component.key is None:
+            component.key = utils.wrap(str(index), "{", check_first=False)
+        return component
+
+    def __str__(self) -> str:
+        """Render the tag as a React string.
+
+        Returns:
+            The React code to render the tag.
+        """
+        try:
+            type_ = self.iterable.type_.__args__[0]
+        except:
+            type_ = Any
+        arg = BaseVar(
+            name=utils.get_unique_variable_name(),
+            type_=type_,
+        )
+        index_arg = self.get_index_var_arg()
+        component = self.render_component(self.render_fn, arg)
+        return utils.wrap(
+            f"{self.iterable.full_name}.map(({arg.name}, {index_arg}) => {component})",
+            "{",
+        )

+ 196 - 0
pynecone/components/tags/tag.py

@@ -0,0 +1,196 @@
+"""A React tag."""
+
+from __future__ import annotations
+
+import json
+import os
+import re
+from typing import Any, Dict, Optional, Union
+
+import pydantic
+from plotly.graph_objects import Figure
+from plotly.io import to_json
+
+from pynecone import utils
+from pynecone.base import Base
+from pynecone.event import EventChain
+from pynecone.var import Var
+
+
+class Tag(Base):
+    """A React tag."""
+
+    # The name of the tag.
+    name: str = ""
+
+    # The attributes of the tag.
+    attrs: Dict[str, Any] = {}
+
+    # The inner contents of the tag.
+    contents: str = ""
+
+    def __init__(self, *args, **kwargs):
+        """Initialize the tag.
+
+        Args:
+            *args: Args to initialize the tag.
+            **kwargs: Kwargs to initialize the tag.
+        """
+        # Convert any attrs to properties.
+        if "attrs" in kwargs:
+            kwargs["attrs"] = {
+                name: Var.create(value) for name, value in kwargs["attrs"].items()
+            }
+        super().__init__(*args, **kwargs)
+
+    @staticmethod
+    def format_attr_value(
+        value: Union[Var, EventChain, Dict[str, Var], str],
+    ) -> Union[int, float, str]:
+        """Format an attribute value.
+
+        Args:
+            value: The value of the attribute
+
+        Returns:
+            The formatted value to display within the tag.
+        """
+
+        def format_fn(value):
+            args = ",".join([":".join((name, val)) for name, val in value.args])
+            return f"E(\"{utils.to_snake_case(value.handler.fn.__qualname__)}\", {utils.wrap(args, '{')})"
+
+        # Handle var attributes.
+        if isinstance(value, Var):
+            if not value.is_local or value.is_string:
+                return str(value)
+            if issubclass(value.type_, str):
+                value = json.dumps(value.full_name)
+                value = re.sub('"{', "", value)
+                value = re.sub('}"', "", value)
+                value = re.sub('"`', '{"', value)
+                value = re.sub('`"', '"}', value)
+                return value
+            value = value.full_name
+
+        # Handle events.
+        elif isinstance(value, EventChain):
+            local_args = ",".join(value.events[0].local_args)
+            fns = ",".join([format_fn(event) for event in value.events])
+            value = f"({local_args}) => Event([{fns}])"
+
+        # Handle other types.
+        elif isinstance(value, str):
+            if utils.is_wrapped(value, "{"):
+                return value
+            return json.dumps(value)
+
+        elif isinstance(value, Figure):
+            value = json.loads(to_json(value))["data"]
+
+        # For dictionaries, convert any properties to strings.
+        else:
+            if isinstance(value, dict):
+                value = json.dumps(
+                    {
+                        key: str(val) if isinstance(val, Var) else val
+                        for key, val in value.items()
+                    }
+                )
+            else:
+                value = json.dumps(value)
+
+            value = re.sub('"{', "", value)
+            value = re.sub('}"', "", value)
+            value = re.sub('"`', '{"', value)
+            value = re.sub('`"', '"}', value)
+
+        # Wrap the variable in braces.
+        assert isinstance(value, str), "The value must be a string."
+        return utils.wrap(value, "{", check_first=False)
+
+    def format_attrs(self) -> str:
+        """Format a dictionary of attributes.
+
+        Returns:
+            The formatted attributes.
+        """
+        # If there are no attributes, return an empty string.
+        if len(self.attrs) == 0:
+            return ""
+
+        # Get the string representation of all the attributes joined.
+        # We need a space at the beginning for formatting.
+        return os.linesep.join(
+            f"{name}={self.format_attr_value(value)}"
+            for name, value in self.attrs.items()
+            if value is not None
+        )
+
+    def __str__(self) -> str:
+        """Render the tag as a React string.
+
+        Returns:
+            The React code to render the tag.
+        """
+        # Get the tag attributes.
+        attrs_str = self.format_attrs()
+        if len(attrs_str) > 0:
+            attrs_str = " " + attrs_str
+
+        if len(self.contents) == 0:
+            # If there is no inner content, we don't need a closing tag.
+            tag_str = utils.wrap(f"{self.name}{attrs_str}/", "<")
+        else:
+            # Otherwise wrap it in opening and closing tags.
+            open = utils.wrap(f"{self.name}{attrs_str}", "<")
+            close = utils.wrap(f"/{self.name}", "<")
+            tag_str = utils.wrap(self.contents, open, close)
+
+        return tag_str
+
+    def add_attrs(self, **kwargs: Optional[Any]) -> Tag:
+        """Add attributes to the tag.
+
+        Args:
+            **kwargs: The attributes to add.
+
+        Returns:
+            The tag with the attributes added.
+        """
+        self.attrs.update(
+            {
+                utils.to_camel_case(name): attr
+                if utils._isinstance(attr, Union[EventChain, dict])
+                else Var.create(attr)
+                for name, attr in kwargs.items()
+                if self.is_valid_attr(attr)
+            }
+        )
+        return self
+
+    def remove_attrs(self, *args: str) -> Tag:
+        """Remove attributes from the tag.
+
+        Args:
+            *args: The attributes to remove.
+
+        Returns:
+            The tag with the attributes removed.
+        """
+        for name in args:
+            if name in self.attrs:
+                del self.attrs[name]
+        return self
+
+    @staticmethod
+    def is_valid_attr(attr: Optional[Var]) -> bool:
+        """Check if the attr is valid.
+
+        Args:
+            attr: The value to check.
+
+        Returns:
+            Whether the value is valid.
+        """
+        return attr is not None and not (isinstance(attr, dict) and len(attr) == 0)

+ 22 - 0
pynecone/components/tags/tagless.py

@@ -0,0 +1,22 @@
+"""A tag with no tag."""
+
+from pynecone import utils
+from pynecone.components.tags import Tag
+
+
+class Tagless(Tag):
+    """A tag with no tag."""
+
+    def __str__(self) -> str:
+        """Return the string representation of the tag.
+
+        Returns:
+            The string representation of the tag.
+        """
+        out = self.contents
+        space = utils.wrap(" ", "{")
+        if len(self.contents) > 0 and self.contents[0] == " ":
+            out = space + out
+        if len(self.contents) > 0 and self.contents[-1] == " ":
+            out = out + space
+        return out

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů