diff --git a/.github/workflows/test-docs.yml b/.github/workflows/test-docs.yml index 5b5bcf6b..4db0842e 100644 --- a/.github/workflows/test-docs.yml +++ b/.github/workflows/test-docs.yml @@ -20,6 +20,16 @@ jobs: - uses: actions/setup-python@v4 with: python-version: 3.x - - run: pip install -r requirements/build-docs.txt - - run: linkcheckMarkdown docs/ -v -r - - run: mkdocs build --strict + - name: Check docs build + run: | + pip install -r requirements/build-docs.txt + linkcheckMarkdown docs/ -v -r + mkdocs build --strict + - name: Check docs examples + run: | + pip install -r requirements/check-types.txt + pip install -r requirements/check-style.txt + mypy --show-error-codes docs/python/ + black docs/python/ --check + isort docs/python/ --check-only + flake8 docs/python/ diff --git a/.gitignore b/.gitignore index 2477a484..90028709 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,7 @@ settings.json *$py.class # Distribution / packaging +build/ .Python build/ develop-eggs/ dist/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ac34c86..aca2dceb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,18 +10,44 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] +- Nothing (yet) + +## [3.0.0a1] - 2023-02-02 + +???+ note + + This is Django-IDOM's biggest update yet! + + To upgrade from previous version you will need to... + + 1. Install `django-idom >= 3.0.0` + 2. Run `idom update-html-usages
{% component "example_project.my_app_2.components.goodbye_world" class="bold small-font" %}
+ {% component "example_project.my_app_3.components.simple_button" %} ``` @@ -99,3 +100,23 @@ The `component` template tag can be used to insert any number of IDOM components Additionally, in scenarios where you are trying to create a Single Page Application (SPA) within Django, you will only have one component within your `#!html ` tag. + + + +??? question "Can I use positional arguments instead of keyword arguments?" + + You can use any combination of `*args`/`**kwargs` in your template tag. + + === "my-template.html" + + ```jinja + {% component "example_project.my_app.components.frog_greeter" 123 "Mr. Froggles" species="Grey Treefrog" %} + ``` + + === "components.py" + + ```python + {% include "../../python/template-tag-args-kwargs.py" %} + ``` + + diff --git a/docs/src/features/utils.md b/docs/src/features/utils.md index 9a0aca8b..3cf63c29 100644 --- a/docs/src/features/utils.md +++ b/docs/src/features/utils.md @@ -1,7 +1,11 @@ -???+ summary +## Overview + +!!! summary Utility functions that you can use when needed. +--- + ## Django Query Postprocessor This is the default postprocessor for the `use_query` hook. @@ -11,36 +15,13 @@ This postprocessor is designed to prevent Django's `SynchronousOnlyException` by === "components.py" ```python - from example_project.my_app.models import TodoItem - from idom import component - from django_idom.hooks import use_query - from django_idom.types import QueryOptions - from django_idom.utils import django_query_postprocessor - - def get_items(): - return TodoItem.objects.all() - - @component - def todo_list(): - # These `QueryOptions` are functionally equivalent to Django-IDOM's default values - item_query = use_query( - QueryOptions( - postprocessor=django_query_postprocessor, - postprocessor_kwargs={"many_to_many": True, "many_to_one": True}, - ), - get_items, - ) - - ... + {% include "../../python/django-query-postprocessor.py" %} ``` === "models.py" ```python - from django.db import models - - class TodoItem(models.Model): - text = models.CharField(max_length=255) + {% include "../../python/example/models.py" %} ``` ??? example "See Interface" diff --git a/docs/src/getting-started/choose-django-app.md b/docs/src/get-started/choose-django-app.md similarity index 84% rename from docs/src/getting-started/choose-django-app.md rename to docs/src/get-started/choose-django-app.md index b414cc2a..fffb8c76 100644 --- a/docs/src/getting-started/choose-django-app.md +++ b/docs/src/get-started/choose-django-app.md @@ -1,10 +1,14 @@ -???+ summary +## Overview + +!!! summary Set up a **Django Project** with at least one app. --- -If you have reached this point, you should have already [installed Django-IDOM](../getting-started/installation.md) through the previous steps. +## Choose a Django App + +If you have reached this point, you should have already [installed Django-IDOM](../get-started/installation.md) through the previous steps. You will now need to pick at least one **Django app** to start using Django-IDOM on. diff --git a/docs/src/getting-started/create-component.md b/docs/src/get-started/create-component.md similarity index 94% rename from docs/src/getting-started/create-component.md rename to docs/src/get-started/create-component.md index e024a3e9..8a74350d 100644 --- a/docs/src/getting-started/create-component.md +++ b/docs/src/get-started/create-component.md @@ -1,9 +1,13 @@ -???+ summary +## Overview + +!!! summary Create a component function using our decorator. --- +## Create a Component + {% include-markdown "../../../README.md" start="" end="" %} === "components.py" diff --git a/docs/src/getting-started/installation.md b/docs/src/get-started/installation.md similarity index 60% rename from docs/src/getting-started/installation.md rename to docs/src/get-started/installation.md index f311abef..f822c8b2 100644 --- a/docs/src/getting-started/installation.md +++ b/docs/src/get-started/installation.md @@ -1,7 +1,11 @@ -???+ summary +## Overview + +!!! summary Django-IDOM can be installed from PyPI to an existing **Django project** with minimal configuration. +--- + ## Step 0: Create a Django Project These docs assumes you have already created [a **Django project**](https://docs.djangoproject.com/en/dev/intro/tutorial01/), which involves creating and installing at least one **Django app**. If not, check out this [9 minute YouTube tutorial](https://www.youtube.com/watch?v=ZsJRXS_vrw0) created by _IDG TECHtalk_. @@ -19,15 +23,12 @@ In your settings you will need to add `django_idom` to [`INSTALLED_APPS`](https: === "settings.py" ```python - INSTALLED_APPS = [ - "django_idom", - ... - ] + {% include "../../python/configure-installed-apps.py" %} ``` -??? warning "Enable Django ASGI (Required)" +??? warning "Enable Django Channels ASGI (Required)" - Django-IDOM requires ASGI in order to use Websockets. + Django-IDOM requires ASGI Websockets from [Django Channels](https://github.com/django/channels). If you have not enabled ASGI on your **Django project** yet, you will need to install `channels[daphne]`, add `daphne` to `INSTALLED_APPS`, then set your `ASGI_APPLICATION` variable. @@ -36,18 +37,16 @@ In your settings you will need to add `django_idom` to [`INSTALLED_APPS`](https: === "settings.py" ```python - INSTALLED_APPS = [ - "daphne", - ... - ] - ASGI_APPLICATION = "example_project.asgi.application" + {% include "../../python/configure-channels.py" %} ``` ??? note "Configure IDOM settings (Optional)" Below are a handful of values you can change within `settings.py` to modify the behavior of IDOM. - {% include-markdown "../features/settings.md" start="" end="" preserve-includer-indent=false %} + ```python + {% include "../../python/settings.py" %} + ``` ## Step 3: Configure [`urls.py`](https://docs.djangoproject.com/en/dev/topics/http/urls/) @@ -56,12 +55,7 @@ Add IDOM HTTP paths to your `urlpatterns`. === "urls.py" ```python - from django.urls import include, path - - urlpatterns = [ - path("idom/", include("django_idom.http.urls")), - ... - ] + {% include "../../python/configure-urls.py" %} ``` ## Step 4: Configure [`asgi.py`](https://docs.djangoproject.com/en/dev/howto/deployment/asgi/) @@ -71,26 +65,7 @@ Register IDOM's Websocket using `IDOM_WEBSOCKET_PATH`. === "asgi.py" ```python - import os - from django.core.asgi import get_asgi_application - - # Ensure DJANGO_SETTINGS_MODULE is set properly based on your project name! - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example_project.settings") - django_asgi_app = get_asgi_application() - - from channels.auth import AuthMiddlewareStack - from channels.routing import ProtocolTypeRouter, URLRouter - from channels.sessions import SessionMiddlewareStack - from django_idom import IDOM_WEBSOCKET_PATH - - application = ProtocolTypeRouter( - { - "http": django_asgi_app, - "websocket": SessionMiddlewareStack( - AuthMiddlewareStack(URLRouter([IDOM_WEBSOCKET_PATH])) - ), - } - ) + {% include "../../python/configure-asgi.py" %} ``` ??? question "Where is my `asgi.py`?" diff --git a/docs/src/getting-started/learn-more.md b/docs/src/get-started/learn-more.md similarity index 54% rename from docs/src/getting-started/learn-more.md rename to docs/src/get-started/learn-more.md index b41b6484..e50af0ab 100644 --- a/docs/src/getting-started/learn-more.md +++ b/docs/src/get-started/learn-more.md @@ -4,8 +4,8 @@ If you followed the previous steps, you have now created a "Hello World" compone The docs you are reading only covers our Django integration. To learn more about features, such as interactive events and hooks, check out the [IDOM Core Documentation](https://idom-docs.herokuapp.com/docs/guides/creating-interfaces/index.html)! -Additionally, the vast majority of tutorials/guides you find for React can be applied to IDOM. +Additionally, the vast majority of tutorials/guides you find for ReactJS can be applied to IDOM. -| Learn More | -| --- | -| [Django-IDOM Advanced Usage](../features/components.md){ .md-button } [IDOM Core Documentation](https://idom-docs.herokuapp.com/docs/guides/creating-interfaces/index.html){ .md-button } [Ask Questions on GitHub Discussions](https://github.com/idom-team/idom/discussions){ .md-button .md-button--primary } | +=== "Learn More" + + [Django-IDOM Advanced Usage](../features/components.md){ .md-button .md-button--primary} [IDOM Core Documentation](https://idom-docs.herokuapp.com/docs/guides/creating-interfaces/index.html){ .md-button .md-button--primary } [Ask Questions](https://github.com/idom-team/idom/discussions){ .md-button .md-button--primary } diff --git a/docs/src/getting-started/render-view.md b/docs/src/get-started/render-view.md similarity index 84% rename from docs/src/getting-started/render-view.md rename to docs/src/get-started/render-view.md index 6098680b..30e0ead6 100644 --- a/docs/src/getting-started/render-view.md +++ b/docs/src/get-started/render-view.md @@ -1,9 +1,13 @@ -???+ summary +## Overview + +!!! summary Select your template containing an IDOM component, and render it using a Django view. --- +## Render Your View + We will assume you have [created a Django View](https://docs.djangoproject.com/en/dev/intro/tutorial01/#write-your-first-view) before, but here's a simple example below. Within your **Django app**'s `views.py` file, you will need to create a function to render the HTML template containing your IDOM components. @@ -13,10 +17,7 @@ In this example, we will create a view that renders `my-template.html` (_from th === "views.py" ```python - from django.shortcuts import render - - def index(request): - return render(request, "my-template.html") + {% include "../../python/example/views.py" %} ``` We will add this new view into your [`urls.py`](https://docs.djangoproject.com/en/dev/intro/tutorial01/#write-your-first-view). @@ -24,12 +25,7 @@ We will add this new view into your [`urls.py`](https://docs.djangoproject.com/e === "urls.py" ```python - from django.urls import path - from example_project.my_app import views - - urlpatterns = [ - path("example/", views.index), - ] + {% include "../../python/example/urls.py" %} ``` Now, navigate to `http://127.0.0.1:8000/example/`. If you copy-pasted the component from the previous example, you will now see your component display "Hello World". diff --git a/docs/src/getting-started/reference-component.md b/docs/src/get-started/use-template-tag.md similarity index 63% rename from docs/src/getting-started/reference-component.md rename to docs/src/get-started/use-template-tag.md index 1576f3ee..6fd9017c 100644 --- a/docs/src/getting-started/reference-component.md +++ b/docs/src/get-started/use-template-tag.md @@ -1,20 +1,24 @@ -???+ summary +## Overview + +!!! summary Decide where the component will be displayed by using our template tag. --- +## Use the Template Tag + {% include-markdown "../../../README.md" start="" end="" %} === "my-template.html" {% include-markdown "../../../README.md" start="" end="" %} -{% include-markdown "../features/templatetag.md" start="" end="" %} +{% include-markdown "../features/template-tag.md" start="" end="" %} -{% include-markdown "../features/templatetag.md" start="" end="" %} +{% include-markdown "../features/template-tag.md" start="" end="" %} -{% include-markdown "../features/templatetag.md" start="" end="" %} +{% include-markdown "../features/template-tag.md" start="" end="" %} ??? question "Where is my templates folder?" diff --git a/docs/src/stylesheets/extra.css b/docs/src/stylesheets/extra.css index 259625f9..72e8bd26 100644 --- a/docs/src/stylesheets/extra.css +++ b/docs/src/stylesheets/extra.css @@ -1,12 +1,4 @@ -.md-footer__inner { - display: none; -} - -.md-tabs, -.md-header { - background-color: var(--md-footer-bg-color--dark); -} - +/* Reduce the insane amounts of white space the default theme has */ .md-typeset :is(.admonition, details) { margin: 0.55em 0; } @@ -16,14 +8,230 @@ padding-bottom: 0.35em; } -body[data-md-color-scheme="slate"] - .md-typeset - :is(.admonition, details):is(.question, .help, .faq) { - border-color: #366517; +/* Font size for admonitions */ +.md-typeset .admonition.summary, +.md-typeset details.summary { + font-size: 0.7rem; } -body[data-md-color-scheme="slate"] +/* Colors for admonitions */ +[data-md-color-scheme="slate"] .md-typeset - :-webkit-any(.admonition, details):-webkit-any(.question, .help, .faq) { - border-color: #366517; + details:not(.warning, .failure, .danger, .bug) + > .admonition-title, +[data-md-color-scheme="slate"] + .md-typeset + details:not(.warning, .failure, .danger, .bug) + > summary { + background: var(--md-primary-fg-color) !important; +} + +[data-md-color-scheme="slate"] .md-typeset .admonition, +[data-md-color-scheme="slate"] .md-typeset details { + border-color: transparent !important; +} + +[data-md-color-scheme="slate"] .md-typeset .admonition.summary, +[data-md-color-scheme="slate"] .md-typeset details.summary { + background: #353a45; +} + +[data-md-color-scheme="slate"] .md-typeset details > .admonition-title:after, +[data-md-color-scheme="slate"] .md-typeset details > summary:after { + color: var(--md-admonition-fg-color) !important; +} + +/* Colors for summary admonition */ +[data-md-color-scheme="slate"] .md-typeset .admonition.summary, +[data-md-color-scheme="slate"] .md-typeset details.summary { + background: #353a45; +} + +[data-md-color-scheme="slate"] .md-typeset details.summary > .admonition-title, +[data-md-color-scheme="slate"] .md-typeset details.summary > summary { + background: #353a45 !important; +} + +[data-md-color-scheme="slate"] .md-typeset .summary .admonition-title, +[data-md-color-scheme="slate"] .md-typeset .summary summary { + background: transparent; +} + +/* Move the sidebars to the edges of the page */ +.md-main__inner.md-grid { + margin-left: 0; + margin-right: 0; + max-width: unset; + display: flex; + justify-content: center; +} + +.md-sidebar--primary { + margin-right: auto; +} + +.md-sidebar.md-sidebar--secondary { + margin-left: auto; +} + +.md-content { + max-width: 56rem; +} + +/* Maintain content positioning even if sidebars are disabled */ +@media screen and (min-width: 76.1875em) { + .md-sidebar { + display: block; + } + + .md-sidebar[hidden] { + visibility: hidden; + } +} + +/* Sidebar styling */ +@media screen and (min-width: 76.1875em) { + .md-nav__title[for="__toc"] { + text-transform: uppercase; + margin: 0.5rem; + } + + .md-nav--lifted > .md-nav__list > .md-nav__item--active > .md-nav__link { + color: rgb(133 142 159); + margin: 0.5rem; + } + + .md-nav__item .md-nav__link { + position: relative; + } + + .md-nav__link:is(:focus, :hover):not(.md-nav__link--active) { + color: unset; + } + + .md-nav__item + .md-nav__link:is(:focus, :hover):not(.md-nav__link--active):before { + content: ""; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + opacity: 0.2; + z-index: -1; + background-color: grey; + } + + .md-nav__item .md-nav__link--active:before { + content: ""; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + opacity: 0.15; + z-index: -1; + background-color: var(--md-typeset-a-color); + } + + .md-nav__link { + padding: 0.5rem 0.5rem 0.5rem 1rem; + margin: 0; + border-radius: 0 10px 10px 0; + font-weight: 500; + } + + .md-sidebar__scrollwrap { + margin: 0; + } + + [dir="ltr"] + .md-nav--lifted + .md-nav[data-md-level="1"] + > .md-nav__list + > .md-nav__item { + padding: 0; + } + + .md-nav__item--nested .md-nav__item .md-nav__item { + padding: 0; + } + + .md-nav__item--nested .md-nav__item .md-nav__item .md-nav__link { + font-weight: 400; + padding-left: 1.5rem; + } +} + +/* Table of Contents styling */ +@media screen and (min-width: 60em) { + [data-md-component="sidebar"] .md-nav__title[for="__toc"] { + text-transform: uppercase; + margin: 0.5rem; + margin-left: 0; + } + + [data-md-component="toc"] .md-nav__item .md-nav__link--active { + position: relative; + } + + [data-md-component="toc"] .md-nav__item .md-nav__link--active:before { + content: ""; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + opacity: 0.15; + z-index: -1; + background-color: var(--md-typeset-a-color); + } + + [data-md-component="toc"] .md-nav__link { + padding: 0.5rem 0.5rem; + margin: 0; + border-radius: 10px 0 0 10px; + } + [dir="ltr"] .md-sidebar__inner { + padding: 0; + } + + .md-nav__item { + padding: 0; + } +} + +/* Page background color */ +[data-md-color-scheme="slate"] { + --md-hue: 225; + --md-default-bg-color: hsla(var(--md-hue), 15%, 16%, 1); + --md-default-bg-color--light: hsla(var(--md-hue), 15%, 16%, 0.54); + --md-default-bg-color--lighter: hsla(var(--md-hue), 15%, 16%, 0.26); + --md-default-bg-color--lightest: hsla(var(--md-hue), 15%, 16%, 0.07); + --md-code-bg-color: #16181d; + --md-primary-fg-color: #2b3540; + --md-default-fg-color--light: #fff; + --md-typeset-a-color: #00b0f0; + --md-code-hl-comment-color: hsla(var(--md-hue), 75%, 90%, 0.43); +} + +/* Font changes */ +.md-typeset h1 { + font-weight: 500; +} + +.md-typeset h1:not([id]) { + display: none; +} + +.md-typeset h2 { + font-weight: 400; +} + +/* Hide invisible jump selectors */ +h2#overview { + visibility: hidden; + height: 0; + margin: 0; + padding: 0; } diff --git a/mkdocs.yml b/mkdocs.yml index 2a60cb5c..78fb08af 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,36 +1,39 @@ --- nav: - Home: index.md - - Getting Started: - - 1. Install Django-IDOM: getting-started/installation.md - - 2. Choose a Django App: getting-started/choose-django-app.md - - 3. Create a Component: getting-started/create-component.md - - 4. Use the Template Tag: getting-started/reference-component.md - - 5. Render Your View: getting-started/render-view.md - - 6. Learn More: getting-started/learn-more.md - - Usage: + - Get Started: + - Install Django-IDOM: get-started/installation.md + - Choose a Django App: get-started/choose-django-app.md + - Create a Component: get-started/create-component.md + - Use the Template Tag: get-started/use-template-tag.md + - Render Your View: get-started/render-view.md + - Learn More: get-started/learn-more.md + - Reference: - Components: features/components.md - Hooks: features/hooks.md - Decorators: features/decorators.md - Utilities: features/utils.md - - Template Tag: features/templatetag.md + - Template Tag: features/template-tag.md - Settings: features/settings.md - - Contribute: - - Code: contribute/code.md - - Docs: contribute/docs.md - - Running Tests: contribute/running-tests.md - - Changelog: changelog/index.md + - About: + - Contribute: + - Code: contribute/code.md + - Docs: contribute/docs.md + - Running Tests: contribute/running-tests.md + - Community: https://github.com/idom-team/idom/discussions + - Changelog: changelog/index.md theme: name: material + custom_dir: docs/overrides palette: - media: "(prefers-color-scheme: dark)" scheme: slate toggle: icon: material/white-balance-sunny name: Switch to light mode - primary: deep-orange - accent: orange + primary: light blue + accent: light blue - media: "(prefers-color-scheme: light)" scheme: default toggle: @@ -39,10 +42,9 @@ theme: primary: black features: - navigation.instant - - navigation.tracking - navigation.tabs - - toc.integrate - navigation.top + - content.code.copy icon: repo: fontawesome/brands/github @@ -64,7 +66,13 @@ markdown_extensions: plugins: - search + - git-authors - include-markdown + - minify: + minify_html: true + minify_js: true + minify_css: true + cache_safe: true - git-revision-date-localized: fallback_to_build_date: true - spellcheck: @@ -84,7 +92,7 @@ watch: - README.md - CHANGELOG.md -site_name: Django IDOM Docs +site_name: Django-IDOM Docs site_author: Archmonger site_description: React for Django developers. copyright: Copyright © 2022 IDOM Team diff --git a/requirements.txt b/requirements.txt index 7328d474..63e3d68e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,8 @@ --r requirements/pkg-deps.txt +-r requirements/build-docs.txt +-r requirements/build-pkg.txt -r requirements/check-style.txt +-r requirements/check-types.txt +-r requirements/dev-env.txt +-r requirements/pkg-deps.txt -r requirements/test-env.txt -r requirements/test-run.txt --r requirements/dev-env.txt diff --git a/requirements/build-docs.txt b/requirements/build-docs.txt index 304cc367..9ae8fcf1 100644 --- a/requirements/build-docs.txt +++ b/requirements/build-docs.txt @@ -4,3 +4,5 @@ mkdocs-material mkdocs-include-markdown-plugin linkcheckmd mkdocs-spellcheck[all] +mkdocs-git-authors-plugin +mkdocs-minify-plugin diff --git a/requirements/pkg-deps.txt b/requirements/pkg-deps.txt index 441e7a04..ef43fa41 100644 --- a/requirements/pkg-deps.txt +++ b/requirements/pkg-deps.txt @@ -1,5 +1,5 @@ channels >=4.0.0 -idom >=0.43.0, <0.44.0 +idom >=1.0.0a2, <1.1.0 aiofile >=3.0 dill >=0.3.5 typing_extensions diff --git a/setup.py b/setup.py index 4d796537..9fd8e902 100644 --- a/setup.py +++ b/setup.py @@ -84,7 +84,7 @@ def list2cmdline(cmd_list): package["version"] = eval(line.split("=", 1)[1]) break else: - print("No version found in %s/__init__.py" % package_dir) + print(f"No version found in {package_dir}/__init__.py") sys.exit(1) @@ -95,9 +95,7 @@ def list2cmdline(cmd_list): requirements = [] with (root_dir / "requirements" / "pkg-deps.txt").open() as f: - for line in map(str.strip, f): - if not line.startswith("#"): - requirements.append(line) + requirements.extend(line for line in map(str.strip, f) if not line.startswith("#")) package["install_requires"] = requirements @@ -121,22 +119,42 @@ def list2cmdline(cmd_list): def build_javascript_first(cls): class Command(cls): def run(self): + js_dir = str(src_dir / "js") + npm = shutil.which("npm") # this is required on windows + if npm is None: + raise RuntimeError("NPM is not installed.") + + log.info("Updating NPM...") + try: + args_list = [npm, "install", "-g", "npm@latest"] + log.info(f"> {list2cmdline(args_list)}") + subprocess.run(args_list, cwd=js_dir, check=True) + except Exception: + log.error("Failed to update NPM") + log.error(traceback.format_exc()) + raise + log.info("Installing Javascript...") try: - js_dir = str(src_dir / "js") - npm = shutil.which("npm") # this is required on windows - if npm is None: - raise RuntimeError("NPM is not installed.") - for args in (f"{npm} install", f"{npm} run build"): - args_list = args.split() - log.info(f"> {list2cmdline(args_list)}") - subprocess.run(args_list, cwd=js_dir, check=True) + args_list = [npm, "install"] + log.info(f"> {list2cmdline(args_list)}") + subprocess.run(args_list, cwd=js_dir, check=True) except Exception: log.error("Failed to install Javascript") log.error(traceback.format_exc()) raise - else: - log.info("Successfully installed Javascript") + + log.info("Building Javascript...") + try: + args_list = [npm, "run", "build"] + log.info(f"> {list2cmdline(args_list)}") + subprocess.run(args_list, cwd=js_dir, check=True) + except Exception: + log.error("Failed to build Javascript") + log.error(traceback.format_exc()) + raise + + log.info("Successfully built Javascript") super().run() return Command diff --git a/src/django_idom/__init__.py b/src/django_idom/__init__.py index ca378289..ed57b138 100644 --- a/src/django_idom/__init__.py +++ b/src/django_idom/__init__.py @@ -2,7 +2,7 @@ from django_idom.websocket.paths import IDOM_WEBSOCKET_PATH -__version__ = "2.2.1" +__version__ = "3.0.0a1" __all__ = [ "IDOM_WEBSOCKET_PATH", "hooks", diff --git a/src/django_idom/components.py b/src/django_idom/components.py index fd9d5292..4448371f 100644 --- a/src/django_idom/components.py +++ b/src/django_idom/components.py @@ -76,10 +76,7 @@ async def async_render(): view, _args, _kwargs ) return html.iframe( - { - "src": reverse("idom:view_to_component", args=[dotted_path]), - "loading": "lazy", - } + src=reverse("idom:view_to_component", args=[dotted_path]), loading="lazy" ) # Return the view if it's been rendered via the `async_render` hook diff --git a/src/django_idom/http/views.py b/src/django_idom/http/views.py index d8858f4c..5fffde7e 100644 --- a/src/django_idom/http/views.py +++ b/src/django_idom/http/views.py @@ -3,7 +3,7 @@ from aiofile import async_open from django.core.exceptions import SuspiciousOperation from django.http import HttpRequest, HttpResponse, HttpResponseNotFound -from idom.config import IDOM_WED_MODULES_DIR +from idom.config import IDOM_WEB_MODULES_DIR from django_idom.utils import create_cache_key, render_view @@ -13,13 +13,13 @@ async def web_modules_file(request: HttpRequest, file: str) -> HttpResponse: returned from cache if available.""" from django_idom.config import IDOM_CACHE - web_modules_dir = IDOM_WED_MODULES_DIR.current + web_modules_dir = IDOM_WEB_MODULES_DIR.current path = os.path.abspath(web_modules_dir.joinpath(*file.split("/"))) # Prevent attempts to walk outside of the web modules dir if str(web_modules_dir) != os.path.commonpath((path, web_modules_dir)): raise SuspiciousOperation( - "Attempt to access a directory outside of IDOM_WED_MODULES_DIR." + "Attempt to access a directory outside of IDOM_WEB_MODULES_DIR." ) # Fetch the file from cache, if available diff --git a/src/django_idom/websocket/consumer.py b/src/django_idom/websocket/consumer.py index fa90ca48..99f860ba 100644 --- a/src/django_idom/websocket/consumer.py +++ b/src/django_idom/websocket/consumer.py @@ -13,8 +13,8 @@ from django.utils import timezone from idom.backend.hooks import ConnectionContext from idom.backend.types import Connection, Location -from idom.core.layout import Layout, LayoutEvent -from idom.core.serve import serve_json_patch +from idom.core.layout import Layout +from idom.core.serve import serve_layout from django_idom.types import ComponentParamData, ComponentWebsocket from django_idom.utils import db_cleanup, func_has_params @@ -50,8 +50,8 @@ async def disconnect(self, code: int) -> None: self._idom_dispatcher_future.cancel() await super().disconnect(code) - async def receive_json(self, content: Any, **kwargs: Any) -> None: - await self._idom_recv_queue.put(LayoutEvent(**content)) + async def receive_json(self, content: Any, **_) -> None: + await self._idom_recv_queue.put(content) async def _run_dispatch_loop(self): from django_idom import models @@ -121,7 +121,7 @@ async def _run_dispatch_loop(self): # Begin serving the IDOM component try: - await serve_json_patch( + await serve_layout( Layout(ConnectionContext(component_instance, value=connection)), self.send_json, self._idom_recv_queue.get, diff --git a/src/js/package-lock.json b/src/js/package-lock.json index fc51d27a..83e0ec39 100644 --- a/src/js/package-lock.json +++ b/src/js/package-lock.json @@ -5,43 +5,146 @@ "packages": { "": { "dependencies": { - "idom-client-react": "^0.43.0", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "idom-client-react": "^1.0.0-a2" }, "devDependencies": { - "prettier": "^2.2.1", - "rollup": "^2.56.3", - "rollup-plugin-commonjs": "^10.1.0", - "rollup-plugin-node-resolve": "^5.2.0", - "rollup-plugin-replace": "^2.2.0" + "@rollup/plugin-commonjs": "^24.0.1", + "@rollup/plugin-node-resolve": "^15.0.1", + "@rollup/plugin-replace": "^5.0.2", + "prettier": "^2.8.3", + "rollup": "^3.12.0" } }, - "node_modules/@types/estree": { - "version": "0.0.48", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.48.tgz", - "integrity": "sha512-LfZwXoGUDo0C3me81HXgkBg5CTQYb6xzEl+fNmbO4JdRiSKQ8A0GD1OBBvKAIsbCUgoyAty7m99GqqMQe784ew==", + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", "dev": true }, - "node_modules/@types/node": { - "version": "15.12.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.2.tgz", - "integrity": "sha512-zjQ69G564OCIWIOHSXyQEEDpdpGl+G348RAKY0XXy9Z5kU9Vzv1GMNnkar/ZJ8dzXB3COzD9Mo9NtRZ4xfgUww==", + "node_modules/@rollup/plugin-commonjs": { + "version": "24.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-24.0.1.tgz", + "integrity": "sha512-15LsiWRZk4eOGqvrJyu3z3DaBu5BhXIMeWnijSRvd8irrrg9SHpQ1pH+BUK4H6Z9wL9yOxZJMTLU+Au86XHxow==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "glob": "^8.0.3", + "is-reference": "1.2.1", + "magic-string": "^0.27.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.68.0||^3.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.0.1.tgz", + "integrity": "sha512-ReY88T7JhJjeRVbfCyNj+NXAG3IIsVMsX9b5/9jC98dRP8/yxlZdz7mHZbHk5zHr24wZZICS5AcXsFZAXYUQEg==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-builtin-module": "^3.2.0", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-replace": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.2.tgz", + "integrity": "sha512-M9YXNekv/C/iHHK+cvORzfRYfPbq0RDD8r0G+bMiTXjNGKulPnCT9O3Ss46WfhI6ZOCgApOP7xAdmCQJ+U2LAA==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "magic-string": "^0.27.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.2.tgz", + "integrity": "sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@types/estree": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", + "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==", "dev": true }, "node_modules/@types/resolve": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz", - "integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "dependencies": { - "@types/node": "*" + "balanced-match": "^1.0.0" } }, "node_modules/builtin-modules": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", - "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", "dev": true, "engines": { "node": ">=6" @@ -50,16 +153,37 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/estree-walker": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", - "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "dev": true }, - "node_modules/fast-json-patch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz", - "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==" + "node_modules/foreach": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.6.tgz", + "integrity": "sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg==" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true }, "node_modules/fsevents": { "version": "2.3.2", @@ -81,6 +205,25 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, + "node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -99,22 +242,53 @@ "integrity": "sha512-L0s3Sid5r6YwrEvkig14SK3Emmc+kIjlfLhEGn2Vy3bk21JyDEes4MoDsbJk6luaPp8bugErnxPz86ZuAw6e5Q==" }, "node_modules/idom-client-react": { - "version": "0.43.0", - "resolved": "https://registry.npmjs.org/idom-client-react/-/idom-client-react-0.43.0.tgz", - "integrity": "sha512-SjVR7wmqsNO5ymKKOsLsQUA+cN12+KuG56xLkCDVyEnlDxUytIOzpzQ3qBsAeMbRJkT/BFURim7UeKnAgWgoLw==", + "version": "1.0.0-a2", + "resolved": "https://registry.npmjs.org/idom-client-react/-/idom-client-react-1.0.0-a2.tgz", + "integrity": "sha512-mfpyPXfM8R4lvgd45DJg+tn/tc5gKNxM32sQPaUr5oWFmt81f1nhWHLmM6RlNv/hB1n51023QCcU4Fj0NCmleg==", "dependencies": { - "fast-json-patch": "^3.1.1", - "htm": "^3.0.3" + "htm": "^3.0.3", + "json-pointer": "^0.6.2" }, "peerDependencies": { "react": ">=16", "react-dom": ">=16" } }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-builtin-module": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.0.tgz", + "integrity": "sha512-phDA4oSGt7vl1n5tJvTWooWWAsXLY+2xCnxNqvKhGEzujg+A43wPlPOyDg3C8XQHN+6k/JTQWJ/j0dQh/qr+Hw==", + "dev": true, + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-core-module": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", - "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -126,7 +300,7 @@ "node_modules/is-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", "dev": true }, "node_modules/is-reference": { @@ -141,12 +315,22 @@ "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "peer": true + }, + "node_modules/json-pointer": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/json-pointer/-/json-pointer-0.6.2.tgz", + "integrity": "sha512-vLWcKbOaXlO+jvRy4qNd+TI1QUPZzfJj1tpJ3vAXDych5XJf93ftpUKe5pKCrzyIIwgBJcOcCVRUfqQP25afBw==", + "dependencies": { + "foreach": "^2.0.4" + } }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "peer": true, "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -155,44 +339,85 @@ } }, "node_modules/magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", + "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.13" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, "dependencies": { - "sourcemap-codec": "^1.4.4" + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" } }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "peer": true, "engines": { "node": ">=0.10.0" } }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, - "node_modules/prettier": { + "node_modules/picomatch": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.1.tgz", - "integrity": "sha512-p+vNbgpLjif/+D+DwAZAbndtRrR0md0MwfmOVN9N+2RgyACMT+7tfaRnT+WDPkqnuVwleyuBIG2XBxKDme3hPA==", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prettier": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.3.tgz", + "integrity": "sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw==", "dev": true, "bin": { "prettier": "bin-prettier.js" }, "engines": { "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, "node_modules/react": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" @@ -205,6 +430,7 @@ "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", @@ -215,141 +441,184 @@ } }, "node_modules/resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", "dev": true, "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/rollup": { - "version": "2.56.3", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.56.3.tgz", - "integrity": "sha512-Au92NuznFklgQCUcV96iXlxUbHuB1vQMaH76DHl5M11TotjOHwqk9CwcrT78+Tnv4FN9uTBxq6p4EJoYkpyekg==", + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.12.0.tgz", + "integrity": "sha512-4MZ8kA2HNYahIjz63rzrMMRvDqQDeS9LoriJvMuV0V6zIGysP36e9t4yObUfwdT9h/szXoHQideICftcdZklWg==", "dev": true, "bin": { "rollup": "dist/bin/rollup" }, "engines": { - "node": ">=10.0.0" + "node": ">=14.18.0", + "npm": ">=8.0.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, - "node_modules/rollup-plugin-commonjs": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-commonjs/-/rollup-plugin-commonjs-10.1.0.tgz", - "integrity": "sha512-jlXbjZSQg8EIeAAvepNwhJj++qJWNJw1Cl0YnOqKtP5Djx+fFGkp3WRh+W0ASCaFG5w1jhmzDxgu3SJuVxPF4Q==", - "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-commonjs.", - "dev": true, + "node_modules/scheduler": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "peer": true, "dependencies": { - "estree-walker": "^0.6.1", - "is-reference": "^1.1.2", - "magic-string": "^0.25.2", - "resolve": "^1.11.0", - "rollup-pluginutils": "^2.8.1" - }, - "peerDependencies": { - "rollup": ">=1.12.0" + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" } }, - "node_modules/rollup-plugin-node-resolve": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz", - "integrity": "sha512-jUlyaDXts7TW2CqQ4GaO5VJ4PwwaV8VUGA7+km3n6k6xtOEacf61u0VXwN80phY/evMcaS+9eIeJ9MOyDxt5Zw==", - "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-node-resolve.", + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, - "dependencies": { - "@types/resolve": "0.0.8", - "builtin-modules": "^3.1.0", - "is-module": "^1.0.0", - "resolve": "^1.11.1", - "rollup-pluginutils": "^2.8.1" + "engines": { + "node": ">= 0.4" }, - "peerDependencies": { - "rollup": ">=1.11.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/rollup-plugin-replace": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-replace/-/rollup-plugin-replace-2.2.0.tgz", - "integrity": "sha512-/5bxtUPkDHyBJAKketb4NfaeZjL5yLZdeUihSfbF2PQMz+rSTEb8ARKoOl3UBT4m7/X+QOXJo3sLTcq+yMMYTA==", - "deprecated": "This module has moved and is now available at @rollup/plugin-replace. Please update your dependencies. This version is no longer maintained.", + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + } + }, + "dependencies": { + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "@rollup/plugin-commonjs": { + "version": "24.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-24.0.1.tgz", + "integrity": "sha512-15LsiWRZk4eOGqvrJyu3z3DaBu5BhXIMeWnijSRvd8irrrg9SHpQ1pH+BUK4H6Z9wL9yOxZJMTLU+Au86XHxow==", "dev": true, - "dependencies": { - "magic-string": "^0.25.2", - "rollup-pluginutils": "^2.6.0" + "requires": { + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "glob": "^8.0.3", + "is-reference": "1.2.1", + "magic-string": "^0.27.0" + } + }, + "@rollup/plugin-node-resolve": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.0.1.tgz", + "integrity": "sha512-ReY88T7JhJjeRVbfCyNj+NXAG3IIsVMsX9b5/9jC98dRP8/yxlZdz7mHZbHk5zHr24wZZICS5AcXsFZAXYUQEg==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-builtin-module": "^3.2.0", + "is-module": "^1.0.0", + "resolve": "^1.22.1" } }, - "node_modules/rollup-pluginutils": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", - "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "@rollup/plugin-replace": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.2.tgz", + "integrity": "sha512-M9YXNekv/C/iHHK+cvORzfRYfPbq0RDD8r0G+bMiTXjNGKulPnCT9O3Ss46WfhI6ZOCgApOP7xAdmCQJ+U2LAA==", "dev": true, - "dependencies": { - "estree-walker": "^0.6.1" + "requires": { + "@rollup/pluginutils": "^5.0.1", + "magic-string": "^0.27.0" } }, - "node_modules/scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "@rollup/pluginutils": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.2.tgz", + "integrity": "sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==", + "dev": true, + "requires": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" } }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "dev": true - } - }, - "dependencies": { "@types/estree": { - "version": "0.0.48", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.48.tgz", - "integrity": "sha512-LfZwXoGUDo0C3me81HXgkBg5CTQYb6xzEl+fNmbO4JdRiSKQ8A0GD1OBBvKAIsbCUgoyAty7m99GqqMQe784ew==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", + "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==", "dev": true }, - "@types/node": { - "version": "15.12.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.2.tgz", - "integrity": "sha512-zjQ69G564OCIWIOHSXyQEEDpdpGl+G348RAKY0XXy9Z5kU9Vzv1GMNnkar/ZJ8dzXB3COzD9Mo9NtRZ4xfgUww==", + "@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", "dev": true }, - "@types/resolve": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz", - "integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==", + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "requires": { - "@types/node": "*" + "balanced-match": "^1.0.0" } }, "builtin-modules": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", - "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", "dev": true }, "estree-walker": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", - "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "dev": true }, - "fast-json-patch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz", - "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==" + "foreach": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.6.tgz", + "integrity": "sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg==" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true }, "fsevents": { "version": "2.3.2", @@ -364,6 +633,19 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, + "glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -379,18 +661,43 @@ "integrity": "sha512-L0s3Sid5r6YwrEvkig14SK3Emmc+kIjlfLhEGn2Vy3bk21JyDEes4MoDsbJk6luaPp8bugErnxPz86ZuAw6e5Q==" }, "idom-client-react": { - "version": "0.43.0", - "resolved": "https://registry.npmjs.org/idom-client-react/-/idom-client-react-0.43.0.tgz", - "integrity": "sha512-SjVR7wmqsNO5ymKKOsLsQUA+cN12+KuG56xLkCDVyEnlDxUytIOzpzQ3qBsAeMbRJkT/BFURim7UeKnAgWgoLw==", + "version": "1.0.0-a2", + "resolved": "https://registry.npmjs.org/idom-client-react/-/idom-client-react-1.0.0-a2.tgz", + "integrity": "sha512-mfpyPXfM8R4lvgd45DJg+tn/tc5gKNxM32sQPaUr5oWFmt81f1nhWHLmM6RlNv/hB1n51023QCcU4Fj0NCmleg==", + "requires": { + "htm": "^3.0.3", + "json-pointer": "^0.6.2" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, "requires": { - "fast-json-patch": "^3.1.1", - "htm": "^3.0.3" + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-builtin-module": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.0.tgz", + "integrity": "sha512-phDA4oSGt7vl1n5tJvTWooWWAsXLY+2xCnxNqvKhGEzujg+A43wPlPOyDg3C8XQHN+6k/JTQWJ/j0dQh/qr+Hw==", + "dev": true, + "requires": { + "builtin-modules": "^3.3.0" } }, "is-core-module": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", - "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "dev": true, "requires": { "has": "^1.0.3" @@ -399,7 +706,7 @@ "is-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", "dev": true }, "is-reference": { @@ -414,29 +721,58 @@ "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "peer": true + }, + "json-pointer": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/json-pointer/-/json-pointer-0.6.2.tgz", + "integrity": "sha512-vLWcKbOaXlO+jvRy4qNd+TI1QUPZzfJj1tpJ3vAXDych5XJf93ftpUKe5pKCrzyIIwgBJcOcCVRUfqQP25afBw==", + "requires": { + "foreach": "^2.0.4" + } }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "peer": true, "requires": { "js-tokens": "^3.0.0 || ^4.0.0" } }, "magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", + "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", "dev": true, "requires": { - "sourcemap-codec": "^1.4.4" + "@jridgewell/sourcemap-codec": "^1.4.13" + } + }, + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" } }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "peer": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } }, "path-parse": { "version": "1.0.7", @@ -444,16 +780,23 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, - "prettier": { + "picomatch": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.1.tgz", - "integrity": "sha512-p+vNbgpLjif/+D+DwAZAbndtRrR0md0MwfmOVN9N+2RgyACMT+7tfaRnT+WDPkqnuVwleyuBIG2XBxKDme3hPA==", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "prettier": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.3.tgz", + "integrity": "sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw==", "dev": true }, "react": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", + "peer": true, "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" @@ -463,6 +806,7 @@ "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "peer": true, "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", @@ -470,82 +814,45 @@ } }, "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", "dev": true, "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" } }, "rollup": { - "version": "2.56.3", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.56.3.tgz", - "integrity": "sha512-Au92NuznFklgQCUcV96iXlxUbHuB1vQMaH76DHl5M11TotjOHwqk9CwcrT78+Tnv4FN9uTBxq6p4EJoYkpyekg==", + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.12.0.tgz", + "integrity": "sha512-4MZ8kA2HNYahIjz63rzrMMRvDqQDeS9LoriJvMuV0V6zIGysP36e9t4yObUfwdT9h/szXoHQideICftcdZklWg==", "dev": true, "requires": { "fsevents": "~2.3.2" } }, - "rollup-plugin-commonjs": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-commonjs/-/rollup-plugin-commonjs-10.1.0.tgz", - "integrity": "sha512-jlXbjZSQg8EIeAAvepNwhJj++qJWNJw1Cl0YnOqKtP5Djx+fFGkp3WRh+W0ASCaFG5w1jhmzDxgu3SJuVxPF4Q==", - "dev": true, - "requires": { - "estree-walker": "^0.6.1", - "is-reference": "^1.1.2", - "magic-string": "^0.25.2", - "resolve": "^1.11.0", - "rollup-pluginutils": "^2.8.1" - } - }, - "rollup-plugin-node-resolve": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz", - "integrity": "sha512-jUlyaDXts7TW2CqQ4GaO5VJ4PwwaV8VUGA7+km3n6k6xtOEacf61u0VXwN80phY/evMcaS+9eIeJ9MOyDxt5Zw==", - "dev": true, - "requires": { - "@types/resolve": "0.0.8", - "builtin-modules": "^3.1.0", - "is-module": "^1.0.0", - "resolve": "^1.11.1", - "rollup-pluginutils": "^2.8.1" - } - }, - "rollup-plugin-replace": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-replace/-/rollup-plugin-replace-2.2.0.tgz", - "integrity": "sha512-/5bxtUPkDHyBJAKketb4NfaeZjL5yLZdeUihSfbF2PQMz+rSTEb8ARKoOl3UBT4m7/X+QOXJo3sLTcq+yMMYTA==", - "dev": true, - "requires": { - "magic-string": "^0.25.2", - "rollup-pluginutils": "^2.6.0" - } - }, - "rollup-pluginutils": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", - "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", - "dev": true, - "requires": { - "estree-walker": "^0.6.1" - } - }, "scheduler": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "peer": true, "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" } }, - "sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true } } diff --git a/src/js/package.json b/src/js/package.json index 10b43551..b43be2dc 100644 --- a/src/js/package.json +++ b/src/js/package.json @@ -1,6 +1,7 @@ { - "description": "test app for idom_django websocket server", + "description": "django-idom client", "main": "src/index.js", + "type": "module", "files": [ "src/**/*.js" ], @@ -9,15 +10,13 @@ "format": "prettier --ignore-path .gitignore --write ." }, "devDependencies": { - "prettier": "^2.2.1", - "rollup": "^2.56.3", - "rollup-plugin-commonjs": "^10.1.0", - "rollup-plugin-node-resolve": "^5.2.0", - "rollup-plugin-replace": "^2.2.0" + "prettier": "^2.8.3", + "rollup": "^3.12.0", + "@rollup/plugin-commonjs": "^24.0.1", + "@rollup/plugin-node-resolve": "^15.0.1", + "@rollup/plugin-replace": "^5.0.2" }, "dependencies": { - "idom-client-react": "^0.43.0", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "idom-client-react": "^1.0.0-a2" } } diff --git a/src/js/rollup.config.js b/src/js/rollup.config.js deleted file mode 100644 index 2443f388..00000000 --- a/src/js/rollup.config.js +++ /dev/null @@ -1,29 +0,0 @@ -import resolve from "rollup-plugin-node-resolve"; -import commonjs from "rollup-plugin-commonjs"; -import replace from "rollup-plugin-replace"; - -export default { - input: "src/index.js", - output: { - file: "../django_idom/static/django_idom/client.js", - format: "esm", - }, - plugins: [ - resolve(), - commonjs(), - replace({ - "process.env.NODE_ENV": JSON.stringify("production"), - }), - ], - onwarn: function (warning) { - // Skip certain warnings - - // should intercept ... but doesn't in some rollup versions - if (warning.code === "THIS_IS_UNDEFINED") { - return; - } - - // console.warn everything else - console.warn(warning.message); - }, -}; diff --git a/src/js/rollup.config.mjs b/src/js/rollup.config.mjs new file mode 100644 index 00000000..57c36438 --- /dev/null +++ b/src/js/rollup.config.mjs @@ -0,0 +1,21 @@ +import resolve from "@rollup/plugin-node-resolve"; +import commonjs from "@rollup/plugin-commonjs"; +import replace from "@rollup/plugin-replace"; + +export default { + input: "src/index.js", + output: { + file: "../django_idom/static/django_idom/client.js", + format: "esm", + }, + plugins: [ + resolve(), + commonjs(), + replace({ + "process.env.NODE_ENV": JSON.stringify("production"), + }), + ], + onwarn: function (warning) { + console.warn(warning.message); + }, +}; diff --git a/tests/test_app/components.py b/tests/test_app/components.py index 38ba30a5..042b9aa7 100644 --- a/tests/test_app/components.py +++ b/tests/test_app/components.py @@ -15,7 +15,7 @@ @component def hello_world(): - return html._(html.div({"id": "hello-world"}, "Hello World!"), html.hr()) + return html._(html.div("Hello World!", id="hello-world"), html.hr()) @component @@ -25,13 +25,11 @@ def button(): html.div( "button:", html.button( - {"id": "counter-inc", "onClick": lambda event: set_count(count + 1)}, "Click me!", + id="counter-inc", + on_click=lambda event: set_count(count + 1), ), - html.p( - {"id": "counter-num", "data-count": count}, - f"Current count is: {count}", - ), + html.p(f"Current count is: {count}", id="counter-num", data_count=count), ), html.hr(), ) @@ -42,8 +40,9 @@ def parameterized_component(x, y): total = x + y return html._( html.div( - {"id": "parametrized-component", "data-value": total}, f"parameterized_component: {total}", + id="parametrized-component", + data_value=total, ), html.hr(), ) @@ -54,14 +53,7 @@ def object_in_templatetag(my_object: TestObject): success = bool(my_object and my_object.value) co_name = inspect.currentframe().f_code.co_name # type: ignore return html._( - html.div( - { - "id": co_name, - "data-success": success, - }, - f"{co_name}: ", - str(my_object), - ), + html.div(f"{co_name}: ", str(my_object), id=co_name, data_success=success), html.hr(), ) @@ -79,7 +71,7 @@ def object_in_templatetag(my_object: TestObject): def simple_button(): return html._( "simple_button:", - SimpleButton({"id": "simple-button"}), + SimpleButton(id="simple-button"), html.hr(), ) @@ -95,9 +87,7 @@ def use_connection(): and getattr(ws.carrier, "dotted_path", None) ) return html.div( - {"id": "use-connection", "data-success": success}, - f"use_connection: {ws}", - html.hr(), + f"use_connection: {ws}", html.hr(), id="use-connection", data_success=success ) @@ -106,9 +96,7 @@ def use_scope(): scope = django_idom.hooks.use_scope() success = len(scope) >= 10 and scope["type"] == "websocket" return html.div( - {"id": "use-scope", "data-success": success}, - f"use_scope: {scope}", - html.hr(), + f"use_scope: {scope}", html.hr(), id="use-scope", data_success=success ) @@ -117,9 +105,7 @@ def use_location(): location = django_idom.hooks.use_location() success = bool(location) return html.div( - {"id": "use-location", "data-success": success}, - f"use_location: {location}", - html.hr(), + f"use_location: {location}", html.hr(), id="use-location", data_success=success ) @@ -128,20 +114,18 @@ def use_origin(): origin = django_idom.hooks.use_origin() success = bool(origin) return html.div( - {"id": "use-origin", "data-success": success}, - f"use_origin: {origin}", - html.hr(), + f"use_origin: {origin}", html.hr(), id="use-origin", data_success=success ) @component def django_css(): return html.div( - {"id": "django-css"}, django_idom.components.django_css("django-css-test.css", key="test"), - html.div({"style": {"display": "inline"}}, "django_css: "), + html.div("django_css: ", style={"display": "inline"}), html.button("This text should be blue."), html.hr(), + id="django-css", ) @@ -150,9 +134,10 @@ def django_js(): success = False return html._( html.div( - {"id": "django-js", "data-success": success}, f"django_js: {success}", django_idom.components.django_js("django-js-test.js", key="test"), + id="django-js", + data_success=success, ), html.hr(), ) @@ -161,34 +146,22 @@ def django_js(): @component @django_idom.decorators.auth_required( fallback=html.div( - {"id": "unauthorized-user-fallback"}, - "unauthorized_user: Success", - html.hr(), + "unauthorized_user: Success", html.hr(), id="unauthorized-user-fallback" ) ) def unauthorized_user(): - return html.div( - {"id": "unauthorized-user"}, - "unauthorized_user: Fail", - html.hr(), - ) + return html.div("unauthorized_user: Fail", html.hr(), id="unauthorized-user") @component @django_idom.decorators.auth_required( auth_attribute="is_anonymous", fallback=html.div( - {"id": "authorized-user-fallback"}, - "authorized_user: Fail", - html.hr(), + "authorized_user: Fail", html.hr(), id="authorized-user-fallback" ), ) def authorized_user(): - return html.div( - {"id": "authorized-user"}, - "authorized_user: Success", - html.hr(), - ) + return html.div("authorized_user: Success", html.hr(), id="authorized-user") def create_relational_parent() -> RelationalParent: @@ -231,15 +204,13 @@ def relational_query(): fk = foriegn_child.data.parent return html.div( - { - "id": "relational-query", - "data-success": bool(mtm) and bool(oto) and bool(mto) and bool(fk), - }, html.div(f"Relational Parent Many To Many: {mtm}"), html.div(f"Relational Parent One To One: {oto}"), html.div(f"Relational Parent Many to One: {mto}"), html.div(f"Relational Child Foreign Key: {fk}"), html.hr(), + id="relational-query", + data_success=bool(mtm) and bool(oto) and bool(mto) and bool(fk), ) @@ -302,13 +273,11 @@ def on_change(event): return html.div( html.label("Add an item:"), html.input( - { - "type": "text", - "id": "todo-input", - "value": input_value, - "onKeyPress": on_submit, - "onChange": on_change, - } + type="text", + id="todo-input", + value=input_value, + on_key_press=on_submit, + on_change=on_change, ), mutation_status, rendered_items, @@ -320,17 +289,15 @@ def _render_todo_items(items, toggle_item): return html.ul( [ html.li( - {"id": f"todo-item-{item.text}"}, item.text, html.input( - { - "id": f"todo-item-{item.text}-checkbox", - "type": "checkbox", - "checked": item.done, - "onChange": lambda event, i=item: toggle_item.execute(i), - } + id=f"todo-item-{item.text}-checkbox", + type="checkbox", + checked=item.done, + on_change=lambda event, i=item: toggle_item.execute(i), ), key=item.text, + id=f"todo-item-{item.text}", ) for item in items ] @@ -368,45 +335,45 @@ def _render_todo_items(items, toggle_item): @component def view_to_component_sync_func_compatibility(): return html.div( - {"id": inspect.currentframe().f_code.co_name}, # type: ignore _view_to_component_sync_func_compatibility(key="test"), html.hr(), + id=inspect.currentframe().f_code.co_name, # type: ignore ) @component def view_to_component_async_func_compatibility(): return html.div( - {"id": inspect.currentframe().f_code.co_name}, # type: ignore _view_to_component_async_func_compatibility(), html.hr(), + id=inspect.currentframe().f_code.co_name, # type: ignore ) @component def view_to_component_sync_class_compatibility(): return html.div( - {"id": inspect.currentframe().f_code.co_name}, # type: ignore _view_to_component_sync_class_compatibility(), html.hr(), + id=inspect.currentframe().f_code.co_name, # type: ignore ) @component def view_to_component_async_class_compatibility(): return html.div( - {"id": inspect.currentframe().f_code.co_name}, # type: ignore _view_to_component_async_class_compatibility(), html.hr(), + id=inspect.currentframe().f_code.co_name, # type: ignore ) @component def view_to_component_template_view_class_compatibility(): return html.div( - {"id": inspect.currentframe().f_code.co_name}, # type: ignore _view_to_component_template_view_class_compatibility(), html.hr(), + id=inspect.currentframe().f_code.co_name, # type: ignore ) @@ -421,8 +388,9 @@ def on_click(_): return html._( html.button( - {"id": f"{inspect.currentframe().f_code.co_name}_btn", "onClick": on_click}, # type: ignore "Click me", + id=f"{inspect.currentframe().f_code.co_name}_btn", # type: ignore + on_click=on_click, ), _view_to_component_request(request=request), ) @@ -437,8 +405,9 @@ def on_click(_): return html._( html.button( - {"id": f"{inspect.currentframe().f_code.co_name}_btn", "onClick": on_click}, # type: ignore "Click me", + id=f"{inspect.currentframe().f_code.co_name}_btn", # type: ignore + on_click=on_click, ), _view_to_component_args(None, success), ) @@ -453,8 +422,9 @@ def on_click(_): return html._( html.button( - {"id": f"{inspect.currentframe().f_code.co_name}_btn", "onClick": on_click}, # type: ignore "Click me", + id=f"{inspect.currentframe().f_code.co_name}_btn", # type: ignore + on_click=on_click, ), _view_to_component_kwargs(success=success), )