reflex-reactbits 0.1.1__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.
@@ -0,0 +1,97 @@
1
+ """Base class shared by every React Bits wrapper."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, ClassVar
6
+
7
+ import reflex as rx
8
+ from reflex.components.component import NoSSRComponent
9
+ from reflex.vars.function import FunctionStringVar
10
+
11
+ from .source import ASSETS_SUBDIR, backend_only, ensure_component_source
12
+
13
+ SAFE_FN_NAME = "reactbitsSafe"
14
+
15
+ # Event payloads are sent to the backend as JSON. React Bits callbacks sometimes
16
+ # pass rich objects (items holding React elements, Errors, Files, DOM events),
17
+ # so every event argument goes through this sanitizer first.
18
+ SAFE_FN_CODE = """
19
+ const reactbitsSafe = (value, depth = 0, seen = new WeakSet()) => {
20
+ if (value === undefined || value === null) return null;
21
+ const kind = typeof value;
22
+ if (kind === "function" || kind === "symbol") return undefined;
23
+ if (kind === "bigint") return Number(value);
24
+ if (kind === "number") return Number.isFinite(value) ? value : null;
25
+ if (kind !== "object") return value;
26
+ if (value.$$typeof) return undefined;
27
+ if (value.nativeEvent) return { type: value.type };
28
+ if (typeof Event !== "undefined" && value instanceof Event) return { type: value.type };
29
+ if (typeof Node !== "undefined" && value instanceof Node) return undefined;
30
+ if (typeof File !== "undefined" && value instanceof File)
31
+ return { name: value.name, size: value.size, type: value.type, lastModified: value.lastModified };
32
+ if (value instanceof Error) return { name: value.name, message: value.message };
33
+ if (value instanceof Date) return value.toISOString();
34
+ if (depth > 8 || seen.has(value)) return undefined;
35
+ // seen tracks the current path, not every value already visited: an object
36
+ // reachable twice (the same option listed twice, two keys sharing a config)
37
+ // is not a cycle and must survive both times, so it is removed again below.
38
+ seen.add(value);
39
+ let out;
40
+ if (Array.isArray(value) || (typeof FileList !== "undefined" && value instanceof FileList)) {
41
+ out = Array.from(value, (item) => reactbitsSafe(item, depth + 1, seen) ?? null);
42
+ } else {
43
+ out = {};
44
+ for (const [key, item] of Object.entries(value)) {
45
+ const safe = reactbitsSafe(item, depth + 1, seen);
46
+ if (safe !== undefined) out[key] = safe;
47
+ }
48
+ }
49
+ seen.delete(value);
50
+ return out;
51
+ };
52
+ """
53
+
54
+
55
+ def safe(value: rx.Var) -> rx.Var:
56
+ """Wrap a JS event argument so it is always JSON serializable."""
57
+ return FunctionStringVar.create(SAFE_FN_NAME).call(value)
58
+
59
+
60
+ class ReactBitsComponent(NoSSRComponent):
61
+ """A React Bits component whose source lives in the app's ``assets/reactbits``.
62
+
63
+ Subclasses declare the React Bits category/name and the files making up the
64
+ component. The source is copied into the app on first use (see
65
+ :mod:`reflex_reactbits.source`), and the component is imported client-side
66
+ only, since most React Bits components rely on ``window``, WebGL or canvas.
67
+ """
68
+
69
+ # React Bits category folder, e.g. "TextAnimations".
70
+ _rb_category: ClassVar[str] = ""
71
+ # React Bits component folder, e.g. "BlurText".
72
+ _rb_name: ClassVar[str] = ""
73
+ # Source files of the component (relative to its folder).
74
+ _rb_files: ClassVar[tuple[str, ...]] = ()
75
+ # Entry module (defaults to "<name>.jsx").
76
+ _rb_entry: ClassVar[str] = ""
77
+
78
+ def __init_subclass__(cls, **kwargs: Any):
79
+ """Derive the local import path for the component module."""
80
+ if cls.__dict__.get("_rb_name"):
81
+ entry = cls.__dict__.get("_rb_entry") or f"{cls._rb_name}.jsx"
82
+ cls.library = f"$/public/{ASSETS_SUBDIR}/{cls._rb_category}/{cls._rb_name}/{entry}"
83
+ super().__init_subclass__(**kwargs)
84
+
85
+ @classmethod
86
+ def create(cls, *children: Any, **props: Any) -> rx.Component:
87
+ """Copy the component source into the app (once) and create the component."""
88
+ # A backend-only process has no frontend to compile, so there is nothing
89
+ # to vendor. The guard lives here and not in ensure_component_source so
90
+ # that the ``reactbits add`` CLI still works in such an environment.
91
+ if cls._rb_name and not backend_only():
92
+ ensure_component_source(cls._rb_category, cls._rb_name, cls._rb_files)
93
+ return super().create(*children, **props)
94
+
95
+ def add_custom_code(self) -> list[str]:
96
+ """Add the event payload sanitizer used by the event specs."""
97
+ return [SAFE_FN_CODE]
@@ -0,0 +1,58 @@
1
+ """Stub file for reflex_reactbits/base.py"""
2
+
3
+ # ------------------- DO NOT EDIT ----------------------
4
+ # This file was generated by `reflex/utils/pyi_generator.py`!
5
+ # ------------------------------------------------------
6
+ from collections.abc import Mapping, Sequence
7
+ from typing import Any, Optional
8
+ from reflex_components_core.core.breakpoints import Breakpoints
9
+ from reflex_base.event import (
10
+ EventType,
11
+ PointerEventInfo,
12
+ )
13
+ from reflex_base.vars.base import Var
14
+ import reflex as rx
15
+ from reflex.components.component import NoSSRComponent
16
+
17
+ SAFE_FN_NAME = "reactbitsSafe"
18
+ SAFE_FN_CODE = '\nconst reactbitsSafe = (value, depth = 0, seen = new WeakSet()) => {\n if (value === undefined || value === null) return null;\n const kind = typeof value;\n if (kind === "function" || kind === "symbol") return undefined;\n if (kind === "bigint") return Number(value);\n if (kind === "number") return Number.isFinite(value) ? value : null;\n if (kind !== "object") return value;\n if (value.$$typeof) return undefined;\n if (value.nativeEvent) return { type: value.type };\n if (typeof Event !== "undefined" && value instanceof Event) return { type: value.type };\n if (typeof Node !== "undefined" && value instanceof Node) return undefined;\n if (typeof File !== "undefined" && value instanceof File)\n return { name: value.name, size: value.size, type: value.type, lastModified: value.lastModified };\n if (value instanceof Error) return { name: value.name, message: value.message };\n if (value instanceof Date) return value.toISOString();\n if (depth > 8 || seen.has(value)) return undefined;\n seen.add(value);\n if (Array.isArray(value) || (typeof FileList !== "undefined" && value instanceof FileList))\n return Array.from(value, (item) => reactbitsSafe(item, depth + 1, seen) ?? null);\n const out = {};\n for (const [key, item] of Object.entries(value)) {\n const safe = reactbitsSafe(item, depth + 1, seen);\n if (safe !== undefined) out[key] = safe;\n }\n return out;\n};\n'
19
+
20
+ def safe(value: rx.Var) -> rx.Var: ...
21
+
22
+ class ReactBitsComponent(NoSSRComponent):
23
+ @classmethod
24
+ def create(
25
+ cls,
26
+ *children,
27
+ style: Sequence[Mapping[str, Any]]
28
+ | Mapping[str, Any]
29
+ | Var[Mapping[str, Any]]
30
+ | Breakpoints
31
+ | None = None,
32
+ key: Any | None = None,
33
+ id: Any | None = None,
34
+ ref: Var | None = None,
35
+ class_name: Any | None = None,
36
+ custom_attrs: dict[str, Any | Var] | None = None,
37
+ on_blur: Optional[EventType[()]] = None,
38
+ on_click: Optional[EventType[()] | EventType[PointerEventInfo]] = None,
39
+ on_context_menu: Optional[EventType[()] | EventType[PointerEventInfo]] = None,
40
+ on_double_click: Optional[EventType[()] | EventType[PointerEventInfo]] = None,
41
+ on_focus: Optional[EventType[()]] = None,
42
+ on_mount: Optional[EventType[()]] = None,
43
+ on_mouse_down: Optional[EventType[()]] = None,
44
+ on_mouse_enter: Optional[EventType[()]] = None,
45
+ on_mouse_leave: Optional[EventType[()]] = None,
46
+ on_mouse_move: Optional[EventType[()]] = None,
47
+ on_mouse_out: Optional[EventType[()]] = None,
48
+ on_mouse_over: Optional[EventType[()]] = None,
49
+ on_mouse_up: Optional[EventType[()]] = None,
50
+ on_scroll: Optional[EventType[()]] = None,
51
+ on_scroll_end: Optional[EventType[()]] = None,
52
+ on_unmount: Optional[EventType[()]] = None,
53
+ **props,
54
+ ) -> "ReactBitsComponent":
55
+ """Copy the component source into the app (once) and create the component."""
56
+ ...
57
+
58
+ def add_custom_code(self) -> list[str]: ...