reactpy 2.0.0b5__py3-none-any.whl → 2.0.0b6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- reactpy/__init__.py +3 -2
- reactpy/_html.py +11 -9
- reactpy/core/_life_cycle_hook.py +4 -1
- reactpy/core/layout.py +43 -38
- reactpy/core/serve.py +11 -16
- reactpy/core/vdom.py +3 -5
- reactpy/pyscript/utils.py +1 -1
- reactpy/reactjs/__init__.py +353 -0
- reactpy/reactjs/module.py +203 -0
- reactpy/reactjs/types.py +7 -0
- reactpy/reactjs/utils.py +183 -0
- reactpy/static/index-h31022cd.js +5 -0
- reactpy/static/index-h31022cd.js.map +11 -0
- reactpy/static/index-sbddj6ms.js +5 -0
- reactpy/static/index-sbddj6ms.js.map +10 -0
- reactpy/static/index-y71bxs88.js +5 -0
- reactpy/static/index-y71bxs88.js.map +10 -0
- reactpy/static/index.js +2 -2
- reactpy/static/index.js.map +6 -10
- reactpy/static/react-dom.js +4 -0
- reactpy/static/react-dom.js.map +11 -0
- reactpy/static/react-jsx-runtime.js +4 -0
- reactpy/static/react-jsx-runtime.js.map +9 -0
- reactpy/static/react.js +4 -0
- reactpy/static/react.js.map +10 -0
- reactpy/testing/backend.py +4 -4
- reactpy/testing/display.py +2 -1
- reactpy/testing/logs.py +1 -1
- reactpy/transforms.py +2 -2
- reactpy/types.py +17 -11
- reactpy/utils.py +1 -1
- reactpy/web/__init__.py +0 -6
- reactpy/web/module.py +37 -473
- reactpy/web/utils.py +2 -158
- {reactpy-2.0.0b5.dist-info → reactpy-2.0.0b6.dist-info}/METADATA +1 -1
- {reactpy-2.0.0b5.dist-info → reactpy-2.0.0b6.dist-info}/RECORD +39 -24
- reactpy/web/templates/react.js +0 -61
- {reactpy-2.0.0b5.dist-info → reactpy-2.0.0b6.dist-info}/WHEEL +0 -0
- {reactpy-2.0.0b5.dist-info → reactpy-2.0.0b6.dist-info}/entry_points.txt +0 -0
- {reactpy-2.0.0b5.dist-info → reactpy-2.0.0b6.dist-info}/licenses/LICENSE +0 -0
reactpy/__init__.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from reactpy import config, logging, types, web, widgets
|
|
1
|
+
from reactpy import config, logging, reactjs, types, web, widgets
|
|
2
2
|
from reactpy._html import html
|
|
3
3
|
from reactpy.core import hooks
|
|
4
4
|
from reactpy.core.component import component
|
|
@@ -23,7 +23,7 @@ from reactpy.pyscript.components import pyscript_component
|
|
|
23
23
|
from reactpy.utils import Ref, reactpy_to_string, string_to_reactpy
|
|
24
24
|
|
|
25
25
|
__author__ = "The Reactive Python Team"
|
|
26
|
-
__version__ = "2.0.
|
|
26
|
+
__version__ = "2.0.0b6"
|
|
27
27
|
|
|
28
28
|
__all__ = [
|
|
29
29
|
"Ref",
|
|
@@ -36,6 +36,7 @@ __all__ = [
|
|
|
36
36
|
"html",
|
|
37
37
|
"logging",
|
|
38
38
|
"pyscript_component",
|
|
39
|
+
"reactjs",
|
|
39
40
|
"reactpy_to_string",
|
|
40
41
|
"string_to_reactpy",
|
|
41
42
|
"types",
|
reactpy/_html.py
CHANGED
|
@@ -6,7 +6,6 @@ from typing import ClassVar, overload
|
|
|
6
6
|
from reactpy.core.vdom import Vdom
|
|
7
7
|
from reactpy.types import (
|
|
8
8
|
EventHandlerDict,
|
|
9
|
-
Key,
|
|
10
9
|
VdomAttributes,
|
|
11
10
|
VdomChild,
|
|
12
11
|
VdomChildren,
|
|
@@ -14,7 +13,7 @@ from reactpy.types import (
|
|
|
14
13
|
VdomDict,
|
|
15
14
|
)
|
|
16
15
|
|
|
17
|
-
__all__ = ["html"]
|
|
16
|
+
__all__ = ["h", "html"]
|
|
18
17
|
|
|
19
18
|
NO_CHILDREN_ALLOWED_HTML_BODY = {
|
|
20
19
|
"area",
|
|
@@ -100,12 +99,10 @@ NO_CHILDREN_ALLOWED_SVG = {
|
|
|
100
99
|
def _fragment(
|
|
101
100
|
attributes: VdomAttributes,
|
|
102
101
|
children: Sequence[VdomChild],
|
|
103
|
-
key: Key | None,
|
|
104
102
|
event_handlers: EventHandlerDict,
|
|
105
103
|
) -> VdomDict:
|
|
106
104
|
"""An HTML fragment - this element will not appear in the DOM"""
|
|
107
|
-
|
|
108
|
-
if attributes or event_handlers:
|
|
105
|
+
if any(k != "key" for k in attributes) or event_handlers:
|
|
109
106
|
msg = "Fragments cannot have attributes besides 'key'"
|
|
110
107
|
raise TypeError(msg)
|
|
111
108
|
model = VdomDict(tagName="")
|
|
@@ -113,8 +110,8 @@ def _fragment(
|
|
|
113
110
|
if children:
|
|
114
111
|
model["children"] = children
|
|
115
112
|
|
|
116
|
-
if
|
|
117
|
-
model["
|
|
113
|
+
if attributes:
|
|
114
|
+
model["attributes"] = attributes
|
|
118
115
|
|
|
119
116
|
return model
|
|
120
117
|
|
|
@@ -122,7 +119,6 @@ def _fragment(
|
|
|
122
119
|
def _script(
|
|
123
120
|
attributes: VdomAttributes,
|
|
124
121
|
children: Sequence[VdomChild],
|
|
125
|
-
key: Key | None,
|
|
126
122
|
event_handlers: EventHandlerDict,
|
|
127
123
|
) -> VdomDict:
|
|
128
124
|
"""Create a new `<script> <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script>`__ element.
|
|
@@ -148,6 +144,8 @@ def _script(
|
|
|
148
144
|
msg = "'script' elements do not support event handlers"
|
|
149
145
|
raise ValueError(msg)
|
|
150
146
|
|
|
147
|
+
key = attributes.get("key")
|
|
148
|
+
|
|
151
149
|
if children:
|
|
152
150
|
if len(children) > 1:
|
|
153
151
|
msg = "'script' nodes may have, at most, one child."
|
|
@@ -165,7 +163,9 @@ def _script(
|
|
|
165
163
|
key = attributes["src"]
|
|
166
164
|
|
|
167
165
|
if key is not None:
|
|
168
|
-
|
|
166
|
+
if "attributes" not in model:
|
|
167
|
+
model["attributes"] = {}
|
|
168
|
+
model["attributes"]["key"] = key
|
|
169
169
|
|
|
170
170
|
return model
|
|
171
171
|
|
|
@@ -287,6 +287,7 @@ class HtmlConstructor:
|
|
|
287
287
|
"fragment": Vdom("", custom_constructor=_fragment),
|
|
288
288
|
"svg": SvgConstructor(),
|
|
289
289
|
}
|
|
290
|
+
__call__ = __cache__["fragment"].__call__
|
|
290
291
|
|
|
291
292
|
def __getattr__(self, value: str) -> VdomConstructor:
|
|
292
293
|
value = value.rstrip("_").replace("_", "-")
|
|
@@ -423,3 +424,4 @@ class HtmlConstructor:
|
|
|
423
424
|
|
|
424
425
|
|
|
425
426
|
html = HtmlConstructor()
|
|
427
|
+
h = html # shorthand alias for html
|
reactpy/core/_life_cycle_hook.py
CHANGED
|
@@ -33,7 +33,10 @@ class _HookStack(Singleton): # nocov
|
|
|
33
33
|
)
|
|
34
34
|
|
|
35
35
|
def get(self) -> list[LifeCycleHook]:
|
|
36
|
-
|
|
36
|
+
try:
|
|
37
|
+
return self._state.get()
|
|
38
|
+
except LookupError:
|
|
39
|
+
return []
|
|
37
40
|
|
|
38
41
|
def initialize(self) -> Token[list[LifeCycleHook]] | None:
|
|
39
42
|
return None if isinstance(self._state, ThreadLocal) else self._state.set([])
|
reactpy/core/layout.py
CHANGED
|
@@ -34,7 +34,7 @@ from reactpy.config import (
|
|
|
34
34
|
REACTPY_CHECK_VDOM_SPEC,
|
|
35
35
|
REACTPY_DEBUG,
|
|
36
36
|
)
|
|
37
|
-
from reactpy.core._life_cycle_hook import LifeCycleHook
|
|
37
|
+
from reactpy.core._life_cycle_hook import HOOK_STACK, LifeCycleHook
|
|
38
38
|
from reactpy.core.vdom import validate_vdom_json
|
|
39
39
|
from reactpy.types import (
|
|
40
40
|
BaseLayout,
|
|
@@ -162,43 +162,47 @@ class Layout(BaseLayout):
|
|
|
162
162
|
async def _create_layout_update(
|
|
163
163
|
self, old_state: _ModelState
|
|
164
164
|
) -> LayoutUpdateMessage:
|
|
165
|
-
|
|
165
|
+
token = HOOK_STACK.initialize()
|
|
166
166
|
try:
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
167
|
+
component = old_state.life_cycle_state.component
|
|
168
|
+
try:
|
|
169
|
+
parent: _ModelState | None = old_state.parent
|
|
170
|
+
except AttributeError:
|
|
171
|
+
parent = None
|
|
172
|
+
|
|
173
|
+
async with AsyncExitStack() as exit_stack:
|
|
174
|
+
new_state = await self._render_component(
|
|
175
|
+
exit_stack,
|
|
176
|
+
old_state,
|
|
177
|
+
parent,
|
|
178
|
+
old_state.index,
|
|
179
|
+
old_state.key,
|
|
180
|
+
component,
|
|
181
|
+
)
|
|
180
182
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
183
|
+
if parent is not None:
|
|
184
|
+
parent.children_by_key[new_state.key] = new_state
|
|
185
|
+
old_parent_model = parent.model.current
|
|
186
|
+
old_parent_children = old_parent_model.setdefault("children", [])
|
|
187
|
+
parent.model.current = {
|
|
188
|
+
**old_parent_model,
|
|
189
|
+
"children": [
|
|
190
|
+
*old_parent_children[: new_state.index],
|
|
191
|
+
new_state.model.current,
|
|
192
|
+
*old_parent_children[new_state.index + 1 :],
|
|
193
|
+
],
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if REACTPY_CHECK_VDOM_SPEC.current:
|
|
197
|
+
validate_vdom_json(new_state.model.current)
|
|
198
|
+
|
|
199
|
+
return {
|
|
200
|
+
"type": "layout-update",
|
|
201
|
+
"path": new_state.patch_path,
|
|
202
|
+
"model": new_state.model.current,
|
|
192
203
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
validate_vdom_json(new_state.model.current)
|
|
196
|
-
|
|
197
|
-
return {
|
|
198
|
-
"type": "layout-update",
|
|
199
|
-
"path": new_state.patch_path,
|
|
200
|
-
"model": new_state.model.current,
|
|
201
|
-
}
|
|
204
|
+
finally:
|
|
205
|
+
HOOK_STACK.reset(token)
|
|
202
206
|
|
|
203
207
|
async def _render_component(
|
|
204
208
|
self,
|
|
@@ -299,8 +303,9 @@ class Layout(BaseLayout):
|
|
|
299
303
|
except Exception as e: # nocov
|
|
300
304
|
msg = f"Expected a VDOM element dict, not {raw_model}"
|
|
301
305
|
raise ValueError(msg) from e
|
|
302
|
-
|
|
303
|
-
|
|
306
|
+
key = raw_model.get("attributes", {}).get("key")
|
|
307
|
+
if key is not None:
|
|
308
|
+
new_state.key = key
|
|
304
309
|
if "importSource" in raw_model:
|
|
305
310
|
new_state.model.current["importSource"] = raw_model["importSource"]
|
|
306
311
|
self._render_model_attributes(old_state, new_state, raw_model)
|
|
@@ -722,7 +727,7 @@ def _get_children_info(
|
|
|
722
727
|
continue
|
|
723
728
|
elif isinstance(child, dict):
|
|
724
729
|
child_type = _DICT_TYPE
|
|
725
|
-
key = child.get("key")
|
|
730
|
+
key = child.get("attributes", {}).get("key")
|
|
726
731
|
elif isinstance(child, Component):
|
|
727
732
|
child_type = _COMPONENT_TYPE
|
|
728
733
|
key = child.key
|
reactpy/core/serve.py
CHANGED
|
@@ -8,7 +8,6 @@ from anyio import create_task_group
|
|
|
8
8
|
from anyio.abc import TaskGroup
|
|
9
9
|
|
|
10
10
|
from reactpy.config import REACTPY_DEBUG
|
|
11
|
-
from reactpy.core._life_cycle_hook import HOOK_STACK
|
|
12
11
|
from reactpy.types import BaseLayout, LayoutEventMessage, LayoutUpdateMessage
|
|
13
12
|
|
|
14
13
|
logger = getLogger(__name__)
|
|
@@ -45,22 +44,18 @@ async def _single_outgoing_loop(
|
|
|
45
44
|
send: SendCoroutine,
|
|
46
45
|
) -> None:
|
|
47
46
|
while True:
|
|
48
|
-
|
|
47
|
+
update = await layout.render()
|
|
49
48
|
try:
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
logger.error(msg)
|
|
61
|
-
raise
|
|
62
|
-
finally:
|
|
63
|
-
HOOK_STACK.reset(token)
|
|
49
|
+
await send(update)
|
|
50
|
+
except Exception: # nocov
|
|
51
|
+
if not REACTPY_DEBUG.current:
|
|
52
|
+
msg = (
|
|
53
|
+
"Failed to send update. More info may be available "
|
|
54
|
+
"if you enabling debug mode by setting "
|
|
55
|
+
"`reactpy.config.REACTPY_DEBUG.current = True`."
|
|
56
|
+
)
|
|
57
|
+
logger.error(msg)
|
|
58
|
+
raise
|
|
64
59
|
|
|
65
60
|
|
|
66
61
|
async def _single_incoming_loop(
|
reactpy/core/vdom.py
CHANGED
|
@@ -41,7 +41,6 @@ VDOM_JSON_SCHEMA = {
|
|
|
41
41
|
"type": "object",
|
|
42
42
|
"properties": {
|
|
43
43
|
"tagName": {"type": "string"},
|
|
44
|
-
"key": {"type": ["string", "number", "null"]},
|
|
45
44
|
"error": {"type": "string"},
|
|
46
45
|
"children": {"$ref": "#/definitions/elementChildren"},
|
|
47
46
|
"attributes": {"type": "object"},
|
|
@@ -170,7 +169,6 @@ class Vdom:
|
|
|
170
169
|
) -> VdomDict:
|
|
171
170
|
"""The entry point for the VDOM API, for example reactpy.html(<WE_ARE_HERE>)."""
|
|
172
171
|
attributes, children = separate_attributes_and_children(attributes_and_children)
|
|
173
|
-
key = attributes.get("key", None)
|
|
174
172
|
attributes, event_handlers, inline_javascript = (
|
|
175
173
|
separate_attributes_handlers_and_inline_javascript(attributes)
|
|
176
174
|
)
|
|
@@ -180,7 +178,6 @@ class Vdom:
|
|
|
180
178
|
# Run custom constructor, if defined
|
|
181
179
|
if self.custom_constructor:
|
|
182
180
|
result = self.custom_constructor(
|
|
183
|
-
key=key,
|
|
184
181
|
children=children,
|
|
185
182
|
attributes=attributes,
|
|
186
183
|
event_handlers=event_handlers,
|
|
@@ -189,7 +186,6 @@ class Vdom:
|
|
|
189
186
|
# Otherwise, use the default constructor
|
|
190
187
|
else:
|
|
191
188
|
result = {
|
|
192
|
-
**({"key": key} if key is not None else {}),
|
|
193
189
|
**({"children": children} if children else {}),
|
|
194
190
|
**({"attributes": attributes} if attributes else {}),
|
|
195
191
|
**({"eventHandlers": event_handlers} if event_handlers else {}),
|
|
@@ -277,7 +273,9 @@ def _validate_child_key_integrity(value: Any) -> None:
|
|
|
277
273
|
for child in value:
|
|
278
274
|
if isinstance(child, Component) and child.key is None:
|
|
279
275
|
warn(f"Key not specified for child in list {child}", UserWarning)
|
|
280
|
-
elif isinstance(child, Mapping) and "key" not in child
|
|
276
|
+
elif isinstance(child, Mapping) and "key" not in child.get(
|
|
277
|
+
"attributes", {}
|
|
278
|
+
):
|
|
281
279
|
# remove 'children' to reduce log spam
|
|
282
280
|
child_copy = {**child, "children": EllipsisRepr()}
|
|
283
281
|
warn(f"Key not specified for child in list {child_copy}", UserWarning)
|
reactpy/pyscript/utils.py
CHANGED
|
@@ -123,7 +123,7 @@ def extend_pyscript_config(
|
|
|
123
123
|
pyscript_config["packages"].extend(extra_py)
|
|
124
124
|
|
|
125
125
|
# FIXME: https://github.com/pyscript/pyscript/issues/2282
|
|
126
|
-
if any(pkg.endswith(".whl") for pkg in pyscript_config["packages"]):
|
|
126
|
+
if any(pkg.endswith(".whl") for pkg in pyscript_config["packages"]): # nocov
|
|
127
127
|
pyscript_config["packages_cache"] = "never"
|
|
128
128
|
|
|
129
129
|
# Extend the JavaScript dependency list
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import hashlib
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any, overload
|
|
6
|
+
|
|
7
|
+
from reactpy.reactjs.module import (
|
|
8
|
+
file_to_module,
|
|
9
|
+
import_reactjs,
|
|
10
|
+
module_to_vdom,
|
|
11
|
+
string_to_module,
|
|
12
|
+
url_to_module,
|
|
13
|
+
)
|
|
14
|
+
from reactpy.reactjs.types import (
|
|
15
|
+
NAME_SOURCE,
|
|
16
|
+
URL_SOURCE,
|
|
17
|
+
)
|
|
18
|
+
from reactpy.types import JavaScriptModule, VdomConstructor
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"NAME_SOURCE",
|
|
22
|
+
"URL_SOURCE",
|
|
23
|
+
"component_from_file",
|
|
24
|
+
"component_from_npm",
|
|
25
|
+
"component_from_string",
|
|
26
|
+
"component_from_url",
|
|
27
|
+
"import_reactjs",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
_URL_JS_MODULE_CACHE: dict[str, JavaScriptModule] = {}
|
|
31
|
+
_FILE_JS_MODULE_CACHE: dict[str, JavaScriptModule] = {}
|
|
32
|
+
_STRING_JS_MODULE_CACHE: dict[str, JavaScriptModule] = {}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@overload
|
|
36
|
+
def component_from_url(
|
|
37
|
+
url: str,
|
|
38
|
+
import_names: str,
|
|
39
|
+
resolve_imports: bool = ...,
|
|
40
|
+
resolve_imports_depth: int = ...,
|
|
41
|
+
fallback: Any | None = ...,
|
|
42
|
+
unmount_before_update: bool = ...,
|
|
43
|
+
allow_children: bool = ...,
|
|
44
|
+
) -> VdomConstructor: ...
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@overload
|
|
48
|
+
def component_from_url(
|
|
49
|
+
url: str,
|
|
50
|
+
import_names: list[str] | tuple[str, ...],
|
|
51
|
+
resolve_imports: bool = ...,
|
|
52
|
+
resolve_imports_depth: int = ...,
|
|
53
|
+
fallback: Any | None = ...,
|
|
54
|
+
unmount_before_update: bool = ...,
|
|
55
|
+
allow_children: bool = ...,
|
|
56
|
+
) -> list[VdomConstructor]: ...
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def component_from_url(
|
|
60
|
+
url: str,
|
|
61
|
+
import_names: str | list[str] | tuple[str, ...],
|
|
62
|
+
resolve_imports: bool = False,
|
|
63
|
+
resolve_imports_depth: int = 5,
|
|
64
|
+
fallback: Any | None = None,
|
|
65
|
+
unmount_before_update: bool = False,
|
|
66
|
+
allow_children: bool = True,
|
|
67
|
+
) -> VdomConstructor | list[VdomConstructor]:
|
|
68
|
+
"""Import a component from a URL.
|
|
69
|
+
|
|
70
|
+
Parameters:
|
|
71
|
+
url:
|
|
72
|
+
The URL to import the component from.
|
|
73
|
+
import_names:
|
|
74
|
+
One or more component names to import. If given as a string, a single component
|
|
75
|
+
will be returned. If a list is given, then a list of components will be
|
|
76
|
+
returned.
|
|
77
|
+
resolve_imports:
|
|
78
|
+
Whether to try and find all the named imports of this module.
|
|
79
|
+
resolve_imports_depth:
|
|
80
|
+
How deeply to search for those imports.
|
|
81
|
+
fallback:
|
|
82
|
+
What to temporarily display while the module is being loaded.
|
|
83
|
+
unmount_before_update:
|
|
84
|
+
Cause the component to be unmounted before each update. This option should
|
|
85
|
+
only be used if the imported package fails to re-render when props change.
|
|
86
|
+
Using this option has negative performance consequences since all DOM
|
|
87
|
+
elements must be changed on each render. See :issue:`461` for more info.
|
|
88
|
+
allow_children:
|
|
89
|
+
Whether or not these components can have children.
|
|
90
|
+
"""
|
|
91
|
+
key = f"{url}{resolve_imports}{resolve_imports_depth}{unmount_before_update}"
|
|
92
|
+
if key in _URL_JS_MODULE_CACHE:
|
|
93
|
+
module = _URL_JS_MODULE_CACHE[key]
|
|
94
|
+
else:
|
|
95
|
+
module = url_to_module(
|
|
96
|
+
url,
|
|
97
|
+
fallback=fallback,
|
|
98
|
+
resolve_imports=resolve_imports,
|
|
99
|
+
resolve_imports_depth=resolve_imports_depth,
|
|
100
|
+
unmount_before_update=unmount_before_update,
|
|
101
|
+
)
|
|
102
|
+
_URL_JS_MODULE_CACHE[key] = module
|
|
103
|
+
return module_to_vdom(module, import_names, fallback, allow_children)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@overload
|
|
107
|
+
def component_from_npm(
|
|
108
|
+
package: str,
|
|
109
|
+
import_names: str,
|
|
110
|
+
resolve_imports: bool = ...,
|
|
111
|
+
resolve_imports_depth: int = ...,
|
|
112
|
+
version: str = "latest",
|
|
113
|
+
cdn: str = "https://esm.sh",
|
|
114
|
+
fallback: Any | None = ...,
|
|
115
|
+
unmount_before_update: bool = ...,
|
|
116
|
+
allow_children: bool = ...,
|
|
117
|
+
) -> VdomConstructor: ...
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@overload
|
|
121
|
+
def component_from_npm(
|
|
122
|
+
package: str,
|
|
123
|
+
import_names: list[str] | tuple[str, ...],
|
|
124
|
+
resolve_imports: bool = ...,
|
|
125
|
+
resolve_imports_depth: int = ...,
|
|
126
|
+
version: str = "latest",
|
|
127
|
+
cdn: str = "https://esm.sh",
|
|
128
|
+
fallback: Any | None = ...,
|
|
129
|
+
unmount_before_update: bool = ...,
|
|
130
|
+
allow_children: bool = ...,
|
|
131
|
+
) -> list[VdomConstructor]: ...
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def component_from_npm(
|
|
135
|
+
package: str,
|
|
136
|
+
import_names: str | list[str] | tuple[str, ...],
|
|
137
|
+
resolve_imports: bool = False,
|
|
138
|
+
resolve_imports_depth: int = 5,
|
|
139
|
+
version: str = "latest",
|
|
140
|
+
cdn: str = "https://esm.sh",
|
|
141
|
+
fallback: Any | None = None,
|
|
142
|
+
unmount_before_update: bool = False,
|
|
143
|
+
allow_children: bool = True,
|
|
144
|
+
) -> VdomConstructor | list[VdomConstructor]:
|
|
145
|
+
"""Import a component from an NPM package.
|
|
146
|
+
|
|
147
|
+
Is is mandatory to load `reactpy.reactjs.import_reactjs()` on your page before using this
|
|
148
|
+
function. It is recommended to put this within your HTML <head> content.
|
|
149
|
+
|
|
150
|
+
Parameters:
|
|
151
|
+
package:
|
|
152
|
+
The name of the NPM package.
|
|
153
|
+
import_names:
|
|
154
|
+
One or more component names to import. If given as a string, a single component
|
|
155
|
+
will be returned. If a list is given, then a list of components will be
|
|
156
|
+
returned.
|
|
157
|
+
resolve_imports:
|
|
158
|
+
Whether to try and find all the named imports of this module.
|
|
159
|
+
resolve_imports_depth:
|
|
160
|
+
How deeply to search for those imports.
|
|
161
|
+
version:
|
|
162
|
+
The version of the package to use. Defaults to "latest".
|
|
163
|
+
cdn:
|
|
164
|
+
The CDN to use. Defaults to "https://esm.sh".
|
|
165
|
+
fallback:
|
|
166
|
+
What to temporarily display while the module is being loaded.
|
|
167
|
+
unmount_before_update:
|
|
168
|
+
Cause the component to be unmounted before each update. This option should
|
|
169
|
+
only be used if the imported package fails to re-render when props change.
|
|
170
|
+
Using this option has negative performance consequences since all DOM
|
|
171
|
+
elements must be changed on each render. See :issue:`461` for more info.
|
|
172
|
+
allow_children:
|
|
173
|
+
Whether or not these components can have children.
|
|
174
|
+
"""
|
|
175
|
+
url = f"{cdn}/{package}@{version}"
|
|
176
|
+
|
|
177
|
+
if "esm.sh" in cdn:
|
|
178
|
+
if "?" in url:
|
|
179
|
+
url += "&external=react,react-dom"
|
|
180
|
+
else:
|
|
181
|
+
url += "?external=react,react-dom"
|
|
182
|
+
|
|
183
|
+
return component_from_url(
|
|
184
|
+
url,
|
|
185
|
+
import_names,
|
|
186
|
+
fallback=fallback,
|
|
187
|
+
resolve_imports=resolve_imports,
|
|
188
|
+
resolve_imports_depth=resolve_imports_depth,
|
|
189
|
+
unmount_before_update=unmount_before_update,
|
|
190
|
+
allow_children=allow_children,
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
@overload
|
|
195
|
+
def component_from_file(
|
|
196
|
+
file: str | Path,
|
|
197
|
+
import_names: str,
|
|
198
|
+
resolve_imports: bool = ...,
|
|
199
|
+
resolve_imports_depth: int = ...,
|
|
200
|
+
name: str = "",
|
|
201
|
+
fallback: Any | None = ...,
|
|
202
|
+
unmount_before_update: bool = ...,
|
|
203
|
+
symlink: bool = ...,
|
|
204
|
+
allow_children: bool = ...,
|
|
205
|
+
) -> VdomConstructor: ...
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
@overload
|
|
209
|
+
def component_from_file(
|
|
210
|
+
file: str | Path,
|
|
211
|
+
import_names: list[str] | tuple[str, ...],
|
|
212
|
+
resolve_imports: bool = ...,
|
|
213
|
+
resolve_imports_depth: int = ...,
|
|
214
|
+
name: str = "",
|
|
215
|
+
fallback: Any | None = ...,
|
|
216
|
+
unmount_before_update: bool = ...,
|
|
217
|
+
symlink: bool = ...,
|
|
218
|
+
allow_children: bool = ...,
|
|
219
|
+
) -> list[VdomConstructor]: ...
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def component_from_file(
|
|
223
|
+
file: str | Path,
|
|
224
|
+
import_names: str | list[str] | tuple[str, ...],
|
|
225
|
+
resolve_imports: bool = False,
|
|
226
|
+
resolve_imports_depth: int = 5,
|
|
227
|
+
name: str = "",
|
|
228
|
+
fallback: Any | None = None,
|
|
229
|
+
unmount_before_update: bool = False,
|
|
230
|
+
symlink: bool = False,
|
|
231
|
+
allow_children: bool = True,
|
|
232
|
+
) -> VdomConstructor | list[VdomConstructor]:
|
|
233
|
+
"""Import a component from a file.
|
|
234
|
+
|
|
235
|
+
Parameters:
|
|
236
|
+
file:
|
|
237
|
+
The file from which the content of the web module will be created.
|
|
238
|
+
import_names:
|
|
239
|
+
One or more component names to import. If given as a string, a single component
|
|
240
|
+
will be returned. If a list is given, then a list of components will be
|
|
241
|
+
returned.
|
|
242
|
+
resolve_imports:
|
|
243
|
+
Whether to try and find all the named imports of this module.
|
|
244
|
+
resolve_imports_depth:
|
|
245
|
+
How deeply to search for those imports.
|
|
246
|
+
name:
|
|
247
|
+
The human-readable name of the ReactJS package
|
|
248
|
+
fallback:
|
|
249
|
+
What to temporarily display while the module is being loaded.
|
|
250
|
+
unmount_before_update:
|
|
251
|
+
Cause the component to be unmounted before each update. This option should
|
|
252
|
+
only be used if the imported package fails to re-render when props change.
|
|
253
|
+
Using this option has negative performance consequences since all DOM
|
|
254
|
+
elements must be changed on each render. See :issue:`461` for more info.
|
|
255
|
+
symlink:
|
|
256
|
+
Whether the web module should be saved as a symlink to the given ``file``.
|
|
257
|
+
allow_children:
|
|
258
|
+
Whether or not these components can have children.
|
|
259
|
+
"""
|
|
260
|
+
name = name or hashlib.sha256(str(file).encode()).hexdigest()[:10]
|
|
261
|
+
key = f"{name}{resolve_imports}{resolve_imports_depth}{unmount_before_update}"
|
|
262
|
+
if key in _FILE_JS_MODULE_CACHE:
|
|
263
|
+
module = _FILE_JS_MODULE_CACHE[key]
|
|
264
|
+
else:
|
|
265
|
+
module = file_to_module(
|
|
266
|
+
name,
|
|
267
|
+
file,
|
|
268
|
+
fallback=fallback,
|
|
269
|
+
resolve_imports=resolve_imports,
|
|
270
|
+
resolve_imports_depth=resolve_imports_depth,
|
|
271
|
+
unmount_before_update=unmount_before_update,
|
|
272
|
+
symlink=symlink,
|
|
273
|
+
)
|
|
274
|
+
_FILE_JS_MODULE_CACHE[key] = module
|
|
275
|
+
return module_to_vdom(module, import_names, fallback, allow_children)
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
@overload
|
|
279
|
+
def component_from_string(
|
|
280
|
+
content: str,
|
|
281
|
+
import_names: str,
|
|
282
|
+
resolve_imports: bool = ...,
|
|
283
|
+
resolve_imports_depth: int = ...,
|
|
284
|
+
name: str = "",
|
|
285
|
+
fallback: Any | None = ...,
|
|
286
|
+
unmount_before_update: bool = ...,
|
|
287
|
+
allow_children: bool = ...,
|
|
288
|
+
) -> VdomConstructor: ...
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
@overload
|
|
292
|
+
def component_from_string(
|
|
293
|
+
content: str,
|
|
294
|
+
import_names: list[str] | tuple[str, ...],
|
|
295
|
+
resolve_imports: bool = ...,
|
|
296
|
+
resolve_imports_depth: int = ...,
|
|
297
|
+
name: str = "",
|
|
298
|
+
fallback: Any | None = ...,
|
|
299
|
+
unmount_before_update: bool = ...,
|
|
300
|
+
allow_children: bool = ...,
|
|
301
|
+
) -> list[VdomConstructor]: ...
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def component_from_string(
|
|
305
|
+
content: str,
|
|
306
|
+
import_names: str | list[str] | tuple[str, ...],
|
|
307
|
+
resolve_imports: bool = False,
|
|
308
|
+
resolve_imports_depth: int = 5,
|
|
309
|
+
name: str = "",
|
|
310
|
+
fallback: Any | None = None,
|
|
311
|
+
unmount_before_update: bool = False,
|
|
312
|
+
allow_children: bool = True,
|
|
313
|
+
) -> VdomConstructor | list[VdomConstructor]:
|
|
314
|
+
"""Import a component from a string.
|
|
315
|
+
|
|
316
|
+
Parameters:
|
|
317
|
+
content:
|
|
318
|
+
The contents of the web module
|
|
319
|
+
import_names:
|
|
320
|
+
One or more component names to import. If given as a string, a single component
|
|
321
|
+
will be returned. If a list is given, then a list of components will be
|
|
322
|
+
returned.
|
|
323
|
+
resolve_imports:
|
|
324
|
+
Whether to try and find all the named imports of this module.
|
|
325
|
+
resolve_imports_depth:
|
|
326
|
+
How deeply to search for those imports.
|
|
327
|
+
name:
|
|
328
|
+
The human-readable name of the ReactJS package
|
|
329
|
+
fallback:
|
|
330
|
+
What to temporarily display while the module is being loaded.
|
|
331
|
+
unmount_before_update:
|
|
332
|
+
Cause the component to be unmounted before each update. This option should
|
|
333
|
+
only be used if the imported package fails to re-render when props change.
|
|
334
|
+
Using this option has negative performance consequences since all DOM
|
|
335
|
+
elements must be changed on each render. See :issue:`461` for more info.
|
|
336
|
+
allow_children:
|
|
337
|
+
Whether or not these components can have children.
|
|
338
|
+
"""
|
|
339
|
+
name = name or hashlib.sha256(content.encode()).hexdigest()[:10]
|
|
340
|
+
key = f"{name}{resolve_imports}{resolve_imports_depth}{unmount_before_update}"
|
|
341
|
+
if key in _STRING_JS_MODULE_CACHE:
|
|
342
|
+
module = _STRING_JS_MODULE_CACHE[key]
|
|
343
|
+
else:
|
|
344
|
+
module = string_to_module(
|
|
345
|
+
name,
|
|
346
|
+
content,
|
|
347
|
+
fallback=fallback,
|
|
348
|
+
resolve_imports=resolve_imports,
|
|
349
|
+
resolve_imports_depth=resolve_imports_depth,
|
|
350
|
+
unmount_before_update=unmount_before_update,
|
|
351
|
+
)
|
|
352
|
+
_STRING_JS_MODULE_CACHE[key] = module
|
|
353
|
+
return module_to_vdom(module, import_names, fallback, allow_children)
|