add next/image and next-video in next namespace (#2223)
This commit is contained in:
parent
d6374ca3f0
commit
caf32605ca
@ -4,10 +4,13 @@ Anything imported here will be available in the default Reflex import as `rx.*`.
|
||||
To signal to typecheckers that something should be reexported,
|
||||
we use the Flask "import name as name" syntax.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib
|
||||
from typing import Type
|
||||
|
||||
from reflex.page import page as page
|
||||
from reflex.utils import console
|
||||
from reflex.utils.format import to_snake_case
|
||||
|
||||
_ALL_COMPONENTS = [
|
||||
@ -181,10 +184,6 @@ _ALL_COMPONENTS = [
|
||||
"StatGroup",
|
||||
"StatHelpText",
|
||||
"StatLabel",
|
||||
"StatArrow",
|
||||
"StatGroup",
|
||||
"StatHelpText",
|
||||
"StatLabel",
|
||||
"StatNumber",
|
||||
"Step",
|
||||
"StepDescription",
|
||||
@ -250,7 +249,7 @@ _MAPPING = {
|
||||
"reflex.base": ["base", "Base"],
|
||||
"reflex.compiler": ["compiler"],
|
||||
"reflex.compiler.utils": ["get_asset_path"],
|
||||
"reflex.components": _ALL_COMPONENTS,
|
||||
"reflex.components": _ALL_COMPONENTS + ["chakra", "next"],
|
||||
"reflex.components.component": ["memo"],
|
||||
"reflex.components.graphing": ["recharts"],
|
||||
"reflex.components.datadisplay.moment": ["MomentDelta"],
|
||||
@ -286,7 +285,31 @@ _MAPPING = {
|
||||
"reflex.utils": ["utils"],
|
||||
"reflex.vars": ["vars", "cached_var", "Var"],
|
||||
}
|
||||
_MAPPING = {value: key for key, values in _MAPPING.items() for value in values}
|
||||
|
||||
|
||||
def _reverse_mapping(mapping: dict[str, list]) -> dict[str, str]:
|
||||
"""Reverse the mapping used to lazy loading, and check for conflicting name.
|
||||
|
||||
Args:
|
||||
mapping: The mapping to reverse.
|
||||
|
||||
Returns:
|
||||
The reversed mapping.
|
||||
"""
|
||||
reversed_mapping = {}
|
||||
for key, values in mapping.items():
|
||||
for value in values:
|
||||
if value not in reversed_mapping:
|
||||
reversed_mapping[value] = key
|
||||
else:
|
||||
console.warn(
|
||||
f"Key {value} is present multiple times in the imports _MAPPING: {key} / {reversed_mapping[value]}"
|
||||
)
|
||||
return reversed_mapping
|
||||
|
||||
|
||||
# _MAPPING = {value: key for key, values in _MAPPING.items() for value in values}
|
||||
_MAPPING = _reverse_mapping(_MAPPING)
|
||||
|
||||
|
||||
def _removeprefix(text, prefix):
|
||||
|
@ -440,6 +440,8 @@ from reflex.components import clear_selected_files as clear_selected_files
|
||||
from reflex.components import EditorButtonList as EditorButtonList
|
||||
from reflex.components import EditorOptions as EditorOptions
|
||||
from reflex.components import NoSSRComponent as NoSSRComponent
|
||||
from reflex.components import chakra as chakra
|
||||
from reflex.components import next as next
|
||||
from reflex.components.component import memo as memo
|
||||
from reflex.components.graphing import recharts as recharts
|
||||
from reflex.components.datadisplay.moment import MomentDelta as MomentDelta
|
||||
|
@ -1,7 +1,9 @@
|
||||
"""Import all the components."""
|
||||
from __future__ import annotations
|
||||
|
||||
from . import next as next
|
||||
from .base import Script
|
||||
from .chakra import *
|
||||
from .component import Component
|
||||
from .component import NoSSRComponent as NoSSRComponent
|
||||
from .datadisplay import *
|
||||
|
23
reflex/components/chakra/__init__.py
Normal file
23
reflex/components/chakra/__init__.py
Normal file
@ -0,0 +1,23 @@
|
||||
"""Chakra components."""
|
||||
|
||||
|
||||
import importlib
|
||||
from typing import Type
|
||||
|
||||
from .media.image import Image
|
||||
|
||||
image = Image.create
|
||||
|
||||
# _MAPPING = {
|
||||
# "image": "media",
|
||||
# }
|
||||
|
||||
|
||||
# def __getattr__(name: str) -> Type:
|
||||
# print(f"importing {name}")
|
||||
# if name not in _MAPPING:
|
||||
# return importlib.import_module(name)
|
||||
|
||||
# module = importlib.import_module(_MAPPING[name], package=".")
|
||||
|
||||
# return getattr(module, name) if name != _MAPPING[name].rsplit(".")[-1] else module
|
@ -1,13 +1,10 @@
|
||||
"""An image component."""
|
||||
from __future__ import annotations
|
||||
|
||||
import base64
|
||||
import io
|
||||
from typing import Any, Optional, Union
|
||||
|
||||
from reflex.components.component import Component
|
||||
from reflex.components.libs.chakra import ChakraComponent, LiteralImageLoading
|
||||
from reflex.utils.serializers import serializer
|
||||
from reflex.vars import Var
|
||||
|
||||
|
||||
@ -15,7 +12,7 @@ class Image(ChakraComponent):
|
||||
"""Display an image."""
|
||||
|
||||
tag = "Image"
|
||||
|
||||
alias = "ChakraImage"
|
||||
# How to align the image within its bounds. It maps to css `object-position` property.
|
||||
align: Var[str]
|
||||
|
||||
@ -79,27 +76,3 @@ class Image(ChakraComponent):
|
||||
if src is not None and not isinstance(src, (Var)):
|
||||
props["src"] = Var.create(value=src, _var_is_string=True)
|
||||
return super().create(*children, **props)
|
||||
|
||||
|
||||
try:
|
||||
from PIL.Image import Image as Img
|
||||
|
||||
@serializer
|
||||
def serialize_image(image: Img) -> str:
|
||||
"""Serialize a plotly figure.
|
||||
|
||||
Args:
|
||||
image: The image to serialize.
|
||||
|
||||
Returns:
|
||||
The serialized image.
|
||||
"""
|
||||
buff = io.BytesIO()
|
||||
image.save(buff, format=getattr(image, "format", None) or "PNG")
|
||||
image_bytes = buff.getvalue()
|
||||
base64_image = base64.b64encode(image_bytes).decode("utf-8")
|
||||
mime_type = getattr(image, "get_format_mimetype", lambda: "image/png")()
|
||||
return f"data:{mime_type};base64,{base64_image}"
|
||||
|
||||
except ImportError:
|
||||
pass
|
120
reflex/components/chakra/media/image.pyi
Normal file
120
reflex/components/chakra/media/image.pyi
Normal file
@ -0,0 +1,120 @@
|
||||
"""Stub file for reflex/components/chakra/media/image.py"""
|
||||
# ------------------- DO NOT EDIT ----------------------
|
||||
# This file was generated by `scripts/pyi_generator.py`!
|
||||
# ------------------------------------------------------
|
||||
|
||||
from typing import Any, Dict, Literal, Optional, Union, overload
|
||||
from reflex.vars import Var, BaseVar, ComputedVar
|
||||
from reflex.event import EventChain, EventHandler, EventSpec
|
||||
from reflex.style import Style
|
||||
from typing import Any, Optional, Union
|
||||
from reflex.components.component import Component
|
||||
from reflex.components.libs.chakra import ChakraComponent, LiteralImageLoading
|
||||
from reflex.vars import Var
|
||||
|
||||
class Image(ChakraComponent):
|
||||
def get_event_triggers(self) -> dict[str, Union[Var, Any]]: ...
|
||||
@overload
|
||||
@classmethod
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*children,
|
||||
align: Optional[Union[Var[str], str]] = None,
|
||||
fallback: Optional[Component] = None,
|
||||
fallback_src: Optional[Union[Var[str], str]] = None,
|
||||
fit: Optional[Union[Var[str], str]] = None,
|
||||
html_height: Optional[Union[Var[str], str]] = None,
|
||||
html_width: Optional[Union[Var[str], str]] = None,
|
||||
ignore_fallback: Optional[Union[Var[bool], bool]] = None,
|
||||
loading: Optional[
|
||||
Union[Var[Literal["eager", "lazy"]], Literal["eager", "lazy"]]
|
||||
] = None,
|
||||
src: Optional[Union[Var[Any], Any]] = None,
|
||||
alt: Optional[Union[Var[str], str]] = None,
|
||||
src_set: Optional[Union[Var[str], str]] = None,
|
||||
style: Optional[Style] = None,
|
||||
key: Optional[Any] = None,
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_error: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_load: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
**props
|
||||
) -> "Image":
|
||||
"""Create an Image component.
|
||||
|
||||
Args:
|
||||
*children: The children of the image.
|
||||
align: How to align the image within its bounds. It maps to css `object-position` property.
|
||||
fallback: Fallback Reflex component to show if image is loading or image fails.
|
||||
fallback_src: Fallback image src to show if image is loading or image fails.
|
||||
fit: How the image to fit within its bounds. It maps to css `object-fit` property.
|
||||
html_height: The native HTML height attribute to the passed to the img.
|
||||
html_width: The native HTML width attribute to the passed to the img.
|
||||
ignore_fallback: If true, opt out of the fallbackSrc logic and use as img.
|
||||
loading: "eager" | "lazy"
|
||||
src: The path/url to the image or PIL image object.
|
||||
alt: The alt text of the image.
|
||||
src_set: Provide multiple sources for an image, allowing the browser to select the most appropriate source based on factors like screen resolution and device capabilities. Learn more _[here](https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images)_
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
class_name: The class name for the component.
|
||||
autofocus: Whether the component should take the focus once the page is loaded
|
||||
custom_attrs: custom attribute
|
||||
**props: The props of the image.
|
||||
|
||||
Returns:
|
||||
The Image component.
|
||||
"""
|
||||
...
|
@ -785,6 +785,10 @@ class Component(BaseComponent, ABC):
|
||||
for child in self.children:
|
||||
dynamic_imports |= child.get_dynamic_imports()
|
||||
|
||||
for prop in self.get_component_props():
|
||||
if getattr(self, prop) is not None:
|
||||
dynamic_imports |= getattr(self, prop).get_dynamic_imports()
|
||||
|
||||
# Return the dynamic imports
|
||||
return dynamic_imports
|
||||
|
||||
|
@ -3,7 +3,6 @@
|
||||
from .audio import Audio
|
||||
from .avatar import Avatar, AvatarBadge, AvatarGroup
|
||||
from .icon import Icon
|
||||
from .image import Image
|
||||
from .video import Video
|
||||
|
||||
__all__ = [f for f in dir() if f[0].isupper()] # type: ignore
|
||||
|
8
reflex/components/next/__init__.py
Normal file
8
reflex/components/next/__init__.py
Normal file
@ -0,0 +1,8 @@
|
||||
"""Namespace for components provided by next packages."""
|
||||
|
||||
from .base import NextComponent
|
||||
from .image import Image
|
||||
from .video import Video
|
||||
|
||||
image = Image.create
|
||||
video = Video.create
|
8
reflex/components/next/base.py
Normal file
8
reflex/components/next/base.py
Normal file
@ -0,0 +1,8 @@
|
||||
"""Base for NextJS components."""
|
||||
from reflex.components.component import Component
|
||||
|
||||
|
||||
class NextComponent(Component):
|
||||
"""A Component used as based for any NextJS component."""
|
||||
|
||||
...
|
91
reflex/components/next/base.pyi
Normal file
91
reflex/components/next/base.pyi
Normal file
@ -0,0 +1,91 @@
|
||||
"""Stub file for reflex/components/next/base.py"""
|
||||
# ------------------- DO NOT EDIT ----------------------
|
||||
# This file was generated by `scripts/pyi_generator.py`!
|
||||
# ------------------------------------------------------
|
||||
|
||||
from typing import Any, Dict, Literal, Optional, Union, overload
|
||||
from reflex.vars import Var, BaseVar, ComputedVar
|
||||
from reflex.event import EventChain, EventHandler, EventSpec
|
||||
from reflex.style import Style
|
||||
from reflex.components.component import Component
|
||||
|
||||
class NextComponent(Component):
|
||||
...
|
||||
|
||||
@overload
|
||||
@classmethod
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*children,
|
||||
style: Optional[Style] = None,
|
||||
key: Optional[Any] = None,
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
**props
|
||||
) -> "NextComponent":
|
||||
"""Create the component.
|
||||
|
||||
Args:
|
||||
*children: The children of the component.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
class_name: The class name for the component.
|
||||
autofocus: Whether the component should take the focus once the page is loaded
|
||||
custom_attrs: custom attribute
|
||||
**props: The props of the component.
|
||||
|
||||
Returns:
|
||||
The component.
|
||||
|
||||
Raises:
|
||||
TypeError: If an invalid child is passed.
|
||||
"""
|
||||
...
|
140
reflex/components/next/image.py
Normal file
140
reflex/components/next/image.py
Normal file
@ -0,0 +1,140 @@
|
||||
"""Image component from next/image."""
|
||||
import base64
|
||||
import io
|
||||
from typing import Any, Dict, Literal, Optional, Union
|
||||
|
||||
from reflex.utils import types
|
||||
from reflex.utils.serializers import serializer
|
||||
from reflex.vars import Var
|
||||
|
||||
from .base import NextComponent
|
||||
|
||||
|
||||
class Image(NextComponent):
|
||||
"""Display an image."""
|
||||
|
||||
tag = "Image"
|
||||
library = "next/image"
|
||||
is_default = True
|
||||
|
||||
# This can be either an absolute external URL, or an internal path
|
||||
src: Var[Any]
|
||||
|
||||
# Represents the rendered width in pixels, so it will affect how large the image appears.
|
||||
width: Var[Any]
|
||||
|
||||
# Represents the rendered height in pixels, so it will affect how large the image appears.
|
||||
height: Var[Any]
|
||||
|
||||
# Used to describe the image for screen readers and search engines.
|
||||
alt: Var[str]
|
||||
|
||||
# A custom function used to resolve image URLs.
|
||||
loader: Var[Any]
|
||||
|
||||
# A boolean that causes the image to fill the parent element, which is useful when the width and height are unknown. Default to True
|
||||
fill: Var[bool]
|
||||
|
||||
# A string, similar to a media query, that provides information about how wide the image will be at different breakpoints.
|
||||
sizes: Var[str]
|
||||
|
||||
# The quality of the optimized image, an integer between 1 and 100, where 100 is the best quality and therefore largest file size. Defaults to 75.
|
||||
quality: Var[int]
|
||||
|
||||
# When true, the image will be considered high priority and preload. Lazy loading is automatically disabled for images using priority.
|
||||
priority: Var[bool]
|
||||
|
||||
# A placeholder to use while the image is loading. Possible values are blur, empty, or data:image/.... Defaults to empty.
|
||||
placeholder: Var[str]
|
||||
|
||||
# Allows passing CSS styles to the underlying image element.
|
||||
# style: Var[Any]
|
||||
|
||||
# The loading behavior of the image. Defaults to lazy. Can hurt performance, recommended to use `priority` instead.
|
||||
loading: Var[Literal["lazy", "eager"]]
|
||||
|
||||
# A Data URL to be used as a placeholder image before the src image successfully loads. Only takes effect when combined with placeholder="blur".
|
||||
blurDataURL: Var[str]
|
||||
|
||||
def get_event_triggers(self) -> Dict[str, Any]:
|
||||
"""The event triggers of the component.
|
||||
|
||||
Returns:
|
||||
The dict describing the event triggers.
|
||||
"""
|
||||
return {
|
||||
**super().get_event_triggers(),
|
||||
"on_load": lambda: [],
|
||||
"on_error": lambda: [],
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def create(
|
||||
cls,
|
||||
*children,
|
||||
width: Optional[Union[int, str]] = None,
|
||||
height: Optional[Union[int, str]] = None,
|
||||
**props,
|
||||
):
|
||||
"""Create an Image component from next/image.
|
||||
|
||||
Args:
|
||||
*children: The children of the component.
|
||||
width: The width of the image.
|
||||
height: The height of the image.
|
||||
**props:The props of the component.
|
||||
|
||||
Returns:
|
||||
_type_: _description_
|
||||
"""
|
||||
style = props.get("style", {})
|
||||
DEFAULT_W_H = "100%"
|
||||
|
||||
def check_prop_type(prop_name, prop_value):
|
||||
if types.check_prop_in_allowed_types(prop_value, allowed_types=[int]):
|
||||
props[prop_name] = prop_value
|
||||
|
||||
elif types.check_prop_in_allowed_types(prop_value, allowed_types=[str]):
|
||||
props[prop_name] = 0
|
||||
style[prop_name] = prop_value
|
||||
else:
|
||||
props[prop_name] = 0
|
||||
style[prop_name] = DEFAULT_W_H
|
||||
|
||||
check_prop_type("width", width)
|
||||
check_prop_type("height", height)
|
||||
|
||||
props["style"] = style
|
||||
|
||||
# mysteriously, following `sizes` prop is needed to avoid blury images.
|
||||
props["sizes"] = "100vw"
|
||||
|
||||
src = props.get("src", None)
|
||||
if src is not None and not isinstance(src, (Var)):
|
||||
props["src"] = Var.create(value=src, _var_is_string=True)
|
||||
|
||||
return super().create(*children, **props)
|
||||
|
||||
|
||||
try:
|
||||
from PIL.Image import Image as Img
|
||||
|
||||
@serializer
|
||||
def serialize_image(image: Img) -> str:
|
||||
"""Serialize a plotly figure.
|
||||
|
||||
Args:
|
||||
image: The image to serialize.
|
||||
|
||||
Returns:
|
||||
The serialized image.
|
||||
"""
|
||||
buff = io.BytesIO()
|
||||
image.save(buff, format=getattr(image, "format", None) or "PNG")
|
||||
image_bytes = buff.getvalue()
|
||||
base64_image = base64.b64encode(image_bytes).decode("utf-8")
|
||||
mime_type = getattr(image, "get_format_mimetype", lambda: "image/png")()
|
||||
return f"data:{mime_type};base64,{base64_image}"
|
||||
|
||||
except ImportError:
|
||||
pass
|
134
reflex/components/next/image.pyi
Normal file
134
reflex/components/next/image.pyi
Normal file
@ -0,0 +1,134 @@
|
||||
"""Stub file for reflex/components/next/image.py"""
|
||||
# ------------------- DO NOT EDIT ----------------------
|
||||
# This file was generated by `scripts/pyi_generator.py`!
|
||||
# ------------------------------------------------------
|
||||
|
||||
from typing import Any, Dict, Literal, Optional, Union, overload
|
||||
from reflex.vars import Var, BaseVar, ComputedVar
|
||||
from reflex.event import EventChain, EventHandler, EventSpec
|
||||
from reflex.style import Style
|
||||
import base64
|
||||
import io
|
||||
from typing import Any, Dict, Literal, Optional, Union
|
||||
from reflex.utils import types
|
||||
from reflex.utils.serializers import serializer
|
||||
from reflex.vars import Var
|
||||
from .base import NextComponent
|
||||
|
||||
class Image(NextComponent):
|
||||
def get_event_triggers(self) -> Dict[str, Any]: ...
|
||||
@overload
|
||||
@classmethod
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*children,
|
||||
width: Optional[Union[str, int]] = None,
|
||||
height: Optional[Union[str, int]] = None,
|
||||
src: Optional[Union[Var[Any], Any]] = None,
|
||||
alt: Optional[Union[Var[str], str]] = None,
|
||||
loader: Optional[Union[Var[Any], Any]] = None,
|
||||
fill: Optional[Union[Var[bool], bool]] = None,
|
||||
sizes: Optional[Union[Var[str], str]] = None,
|
||||
quality: Optional[Union[Var[int], int]] = None,
|
||||
priority: Optional[Union[Var[bool], bool]] = None,
|
||||
placeholder: Optional[Union[Var[str], str]] = None,
|
||||
loading: Optional[
|
||||
Union[Var[Literal["lazy", "eager"]], Literal["lazy", "eager"]]
|
||||
] = None,
|
||||
blurDataURL: Optional[Union[Var[str], str]] = None,
|
||||
style: Optional[Style] = None,
|
||||
key: Optional[Any] = None,
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_error: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_load: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
**props
|
||||
) -> "Image":
|
||||
"""Create an Image component from next/image.
|
||||
|
||||
Args:
|
||||
*children: The children of the component.
|
||||
width: The width of the image.
|
||||
height: The height of the image.
|
||||
src: This can be either an absolute external URL, or an internal path
|
||||
alt: Used to describe the image for screen readers and search engines.
|
||||
loader: A custom function used to resolve image URLs.
|
||||
fill: A boolean that causes the image to fill the parent element, which is useful when the width and height are unknown. Default to True
|
||||
sizes: A string, similar to a media query, that provides information about how wide the image will be at different breakpoints.
|
||||
quality: The quality of the optimized image, an integer between 1 and 100, where 100 is the best quality and therefore largest file size. Defaults to 75.
|
||||
priority: When true, the image will be considered high priority and preload. Lazy loading is automatically disabled for images using priority.
|
||||
placeholder: A placeholder to use while the image is loading. Possible values are blur, empty, or data:image/.... Defaults to empty.
|
||||
loading: Allows passing CSS styles to the underlying image element. style: Var[Any] The loading behavior of the image. Defaults to lazy. Can hurt performance, recommended to use `priority` instead.
|
||||
blurDataURL: A Data URL to be used as a placeholder image before the src image successfully loads. Only takes effect when combined with placeholder="blur".
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
class_name: The class name for the component.
|
||||
autofocus: Whether the component should take the focus once the page is loaded
|
||||
custom_attrs: custom attribute
|
||||
**props:The props of the component.
|
||||
|
||||
Returns:
|
||||
_type_: _description_
|
||||
"""
|
||||
...
|
||||
|
||||
try:
|
||||
from PIL.Image import Image as Img
|
||||
|
||||
@serializer
|
||||
def serialize_image(image: Img) -> str: ...
|
||||
|
||||
except ImportError:
|
||||
pass
|
33
reflex/components/next/video.py
Normal file
33
reflex/components/next/video.py
Normal file
@ -0,0 +1,33 @@
|
||||
"""Wrapping of the next-video component."""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from reflex.components.component import Component
|
||||
from reflex.vars import Var
|
||||
|
||||
from .base import NextComponent
|
||||
|
||||
|
||||
class Video(NextComponent):
|
||||
"""A video component from NextJS."""
|
||||
|
||||
tag = "Video"
|
||||
library = "next-video"
|
||||
is_default = True
|
||||
# the URL
|
||||
src: Var[str]
|
||||
|
||||
as_: Optional[Component]
|
||||
|
||||
@classmethod
|
||||
def create(cls, *children, **props) -> NextComponent:
|
||||
"""Create a Video component.
|
||||
|
||||
Args:
|
||||
*children: The children of the component.
|
||||
**props: The props of the component.
|
||||
|
||||
Returns:
|
||||
The Video component.
|
||||
"""
|
||||
return super().create(*children, **props)
|
92
reflex/components/next/video.pyi
Normal file
92
reflex/components/next/video.pyi
Normal file
@ -0,0 +1,92 @@
|
||||
"""Stub file for reflex/components/next/video.py"""
|
||||
# ------------------- DO NOT EDIT ----------------------
|
||||
# This file was generated by `scripts/pyi_generator.py`!
|
||||
# ------------------------------------------------------
|
||||
|
||||
from typing import Any, Dict, Literal, Optional, Union, overload
|
||||
from reflex.vars import Var, BaseVar, ComputedVar
|
||||
from reflex.event import EventChain, EventHandler, EventSpec
|
||||
from reflex.style import Style
|
||||
from typing import Optional
|
||||
from reflex.components.component import Component
|
||||
from reflex.vars import Var
|
||||
from .base import NextComponent
|
||||
|
||||
class Video(NextComponent):
|
||||
@overload
|
||||
@classmethod
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*children,
|
||||
src: Optional[Union[Var[str], str]] = None,
|
||||
as_: Optional[Component] = None,
|
||||
style: Optional[Style] = None,
|
||||
key: Optional[Any] = None,
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, function, BaseVar]
|
||||
] = None,
|
||||
**props
|
||||
) -> "Video":
|
||||
"""Create a Video component.
|
||||
|
||||
Args:
|
||||
*children: The children of the component.
|
||||
src: the URL
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
class_name: The class name for the component.
|
||||
autofocus: Whether the component should take the focus once the page is loaded
|
||||
custom_attrs: custom attribute
|
||||
**props: The props of the component.
|
||||
|
||||
Returns:
|
||||
The Video component.
|
||||
"""
|
||||
...
|
@ -272,6 +272,23 @@ def check_type_in_allowed_types(value_type: Type, allowed_types: Iterable) -> bo
|
||||
return get_base_class(value_type) in allowed_types
|
||||
|
||||
|
||||
def check_prop_in_allowed_types(prop: Any, allowed_types: Iterable) -> bool:
|
||||
"""Check that a prop value is in a list of allowed types.
|
||||
Does the check in a way that works regardless if it's a raw value or a state Var.
|
||||
|
||||
Args:
|
||||
prop: The prop to check.
|
||||
allowed_types: The list of allowed types.
|
||||
|
||||
Returns:
|
||||
If the prop type match one of the allowed_types.
|
||||
"""
|
||||
from reflex.vars import Var
|
||||
|
||||
type_ = prop._var_type if _isinstance(prop, Var) else type(prop)
|
||||
return type_ in allowed_types
|
||||
|
||||
|
||||
# Store this here for performance.
|
||||
StateBases = get_base_class(StateVar)
|
||||
StateIterBases = get_base_class(StateIterVar)
|
||||
|
@ -1,63 +1,58 @@
|
||||
# PIL is only available in python 3.8+
|
||||
import numpy as np
|
||||
import PIL
|
||||
import pytest
|
||||
from PIL.Image import Image as Img
|
||||
|
||||
try:
|
||||
# PIL is only available in python 3.8+
|
||||
import numpy as np
|
||||
import PIL
|
||||
from PIL.Image import Image as Img
|
||||
import reflex as rx
|
||||
from reflex.components.next.image import Image, serialize_image # type: ignore
|
||||
from reflex.utils.serializers import serialize
|
||||
|
||||
import reflex as rx
|
||||
from reflex.components.media.image import Image, serialize_image # type: ignore
|
||||
from reflex.utils.serializers import serialize
|
||||
|
||||
@pytest.fixture
|
||||
def pil_image() -> Img:
|
||||
"""Get an image.
|
||||
@pytest.fixture
|
||||
def pil_image() -> Img:
|
||||
"""Get an image.
|
||||
|
||||
Returns:
|
||||
A random PIL image.
|
||||
"""
|
||||
imarray = np.random.rand(100, 100, 3) * 255
|
||||
return PIL.Image.fromarray(imarray.astype("uint8")).convert("RGBA") # type: ignore
|
||||
Returns:
|
||||
A random PIL image.
|
||||
"""
|
||||
imarray = np.random.rand(100, 100, 3) * 255
|
||||
return PIL.Image.fromarray(imarray.astype("uint8")).convert("RGBA") # type: ignore
|
||||
|
||||
def test_serialize_image(pil_image: Img):
|
||||
"""Test that serializing an image works.
|
||||
|
||||
Args:
|
||||
pil_image: The image to serialize.
|
||||
"""
|
||||
data = serialize(pil_image)
|
||||
assert isinstance(data, str)
|
||||
assert data == serialize_image(pil_image)
|
||||
assert data.startswith("data:image/png;base64,")
|
||||
def test_serialize_image(pil_image: Img):
|
||||
"""Test that serializing an image works.
|
||||
|
||||
def test_set_src_str():
|
||||
"""Test that setting the src works."""
|
||||
image = rx.image(src="pic2.jpeg")
|
||||
assert str(image.src) == "{`pic2.jpeg`}" # type: ignore
|
||||
Args:
|
||||
pil_image: The image to serialize.
|
||||
"""
|
||||
data = serialize(pil_image)
|
||||
assert isinstance(data, str)
|
||||
assert data == serialize_image(pil_image)
|
||||
assert data.startswith("data:image/png;base64,")
|
||||
|
||||
def test_set_src_img(pil_image: Img):
|
||||
"""Test that setting the src works.
|
||||
|
||||
Args:
|
||||
pil_image: The image to serialize.
|
||||
"""
|
||||
image = Image.create(src=pil_image)
|
||||
assert str(image.src._var_name) == serialize_image(pil_image) # type: ignore
|
||||
def test_set_src_str():
|
||||
"""Test that setting the src works."""
|
||||
image = rx.image(src="pic2.jpeg")
|
||||
assert str(image.src) == "{`pic2.jpeg`}" # type: ignore
|
||||
|
||||
def test_render(pil_image: Img):
|
||||
"""Test that rendering an image works.
|
||||
|
||||
Args:
|
||||
pil_image: The image to serialize.
|
||||
"""
|
||||
image = Image.create(src=pil_image)
|
||||
assert image.src._var_is_string # type: ignore
|
||||
def test_set_src_img(pil_image: Img):
|
||||
"""Test that setting the src works.
|
||||
|
||||
except ImportError:
|
||||
Args:
|
||||
pil_image: The image to serialize.
|
||||
"""
|
||||
image = Image.create(src=pil_image)
|
||||
assert str(image.src._var_name) == serialize_image(pil_image) # type: ignore
|
||||
|
||||
def test_pillow_import():
|
||||
"""Make sure the Python version is less than 3.8."""
|
||||
import sys
|
||||
|
||||
assert sys.version_info < (3, 8)
|
||||
def test_render(pil_image: Img):
|
||||
"""Test that rendering an image works.
|
||||
|
||||
Args:
|
||||
pil_image: The image to serialize.
|
||||
"""
|
||||
image = Image.create(src=pil_image)
|
||||
assert image.src._var_is_string # type: ignore
|
||||
|
Loading…
Reference in New Issue
Block a user