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,23 @@
1
+ """Machine-readable catalog of every wrapped React Bits component."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ #: One entry per wrapper class: class/factory names, category, docs URL, npm deps and props.
10
+ CATALOG: list[dict[str, Any]] = json.loads(
11
+ (Path(__file__).parent / "catalog.json").read_text(encoding="utf-8")
12
+ )
13
+
14
+
15
+ def find_component(name: str) -> dict[str, Any]:
16
+ """Look up a catalog entry by React name, class name or factory name (case-insensitive)."""
17
+ key = name.lower().replace("-", "").replace("_", "")
18
+ for entry in CATALOG:
19
+ candidates = {entry["class"], entry["factory"], entry["name"]}
20
+ if key in {c.lower().replace("_", "") for c in candidates}:
21
+ return entry
22
+ msg = f"Unknown React Bits component: {name!r}"
23
+ raise KeyError(msg)
@@ -0,0 +1,125 @@
1
+ """``reactbits`` command line: list, inspect and pre-fetch React Bits sources.
2
+
3
+ Examples::
4
+
5
+ reactbits list --category Backgrounds
6
+ reactbits info BlurText
7
+ reactbits add BlurText Aurora # copy sources into ./assets/reactbits
8
+ reactbits add --all # vendor every component (offline builds)
9
+ reactbits remove Aurora
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import argparse
15
+ import sys
16
+ from pathlib import Path
17
+
18
+ from .catalog import CATALOG, find_component
19
+ from .source import PINNED_REF, component_dir, ensure_component_source, remove_component_source
20
+
21
+ _CATEGORIES = sorted({e["category"] for e in CATALOG})
22
+
23
+
24
+ def _source_entries(names: list[str], all_: bool) -> list[dict]:
25
+ if all_:
26
+ entries = [e for e in CATALOG if not e.get("sub")]
27
+ else:
28
+ entries = [find_component(n) for n in names]
29
+ # Sub-components share their parent's files.
30
+ seen, out = set(), []
31
+ for e in entries:
32
+ key = (e["category"], e["name"])
33
+ if key not in seen:
34
+ seen.add(key)
35
+ out.append(e)
36
+ return out
37
+
38
+
39
+ def _files_for(entry: dict) -> tuple[str, ...]:
40
+ import reflex_reactbits
41
+
42
+ return getattr(reflex_reactbits, entry["class"])._rb_files
43
+
44
+
45
+ def cmd_list(args: argparse.Namespace) -> int:
46
+ for cat in _CATEGORIES:
47
+ if args.category and cat.lower() != args.category.lower():
48
+ continue
49
+ entries = [e for e in CATALOG if e["category"] == cat]
50
+ print(f"\n{cat} ({len(entries)})")
51
+ for e in entries:
52
+ print(f" {e['factory']:<28} {e['description'][:70]}")
53
+ return 0
54
+
55
+
56
+ def cmd_info(args: argparse.Namespace) -> int:
57
+ e = find_component(args.name)
58
+ print(f"{e['class']} ({e['category']}) -> reflex_reactbits.{e['factory']}()")
59
+ print(e["description"])
60
+ print(f"Docs: {e['docs_url']}")
61
+ if e["npm"]:
62
+ print("npm: " + ", ".join(e["npm"]))
63
+ print("\nProps:")
64
+ for p in e["props"]:
65
+ if p["type"] == "event":
66
+ args_ = ", ".join(p.get("args") or [])
67
+ print(f" {p['name']:<28} event({args_})")
68
+ else:
69
+ print(f" {p['name']:<28} {p['type']:<22} {(p.get('default') or '')[:30]}")
70
+ return 0
71
+
72
+
73
+ def cmd_add(args: argparse.Namespace) -> int:
74
+ assets = Path(args.assets_dir) if args.assets_dir else None
75
+ for e in _source_entries(args.names, args.all):
76
+ written = ensure_component_source(
77
+ e["category"], e["name"], _files_for(e), assets_dir=assets, ref=args.ref, force=args.force
78
+ )
79
+ where = component_dir(e["category"], e["name"], assets)
80
+ state = "added" if written else "up to date"
81
+ print(f"{e['name']:<24} {state:<11} {where}")
82
+ return 0
83
+
84
+
85
+ def cmd_remove(args: argparse.Namespace) -> int:
86
+ assets = Path(args.assets_dir) if args.assets_dir else None
87
+ for e in _source_entries(args.names, False):
88
+ removed = remove_component_source(e["category"], e["name"], assets)
89
+ print(f"{e['name']:<24} {'removed' if removed else 'not present'}")
90
+ return 0
91
+
92
+
93
+ def main(argv: list[str] | None = None) -> int:
94
+ parser = argparse.ArgumentParser(prog="reactbits", description=__doc__.splitlines()[0])
95
+ sub = parser.add_subparsers(dest="command", required=True)
96
+
97
+ p = sub.add_parser("list", help="List the available components.")
98
+ p.add_argument("--category", choices=_CATEGORIES, type=str)
99
+ p.set_defaults(func=cmd_list)
100
+
101
+ p = sub.add_parser("info", help="Show props, events and npm deps of a component.")
102
+ p.add_argument("name")
103
+ p.set_defaults(func=cmd_info)
104
+
105
+ for name, func, help_ in (
106
+ ("add", cmd_add, "Copy component sources into the app's assets/reactbits."),
107
+ ("remove", cmd_remove, "Delete copied component sources."),
108
+ ):
109
+ p = sub.add_parser(name, help=help_)
110
+ p.add_argument("names", nargs="*")
111
+ p.add_argument("--assets-dir", help="App assets directory (default: ./assets).")
112
+ if name == "add":
113
+ p.add_argument("--all", action="store_true", help="Add every component.")
114
+ p.add_argument("--ref", default=None, help=f"react-bits git ref (default {PINNED_REF[:10]}).")
115
+ p.add_argument("--force", action="store_true", help="Overwrite existing (possibly edited) files.")
116
+ p.set_defaults(func=func)
117
+
118
+ args = parser.parse_args(argv)
119
+ if getattr(args, "names", None) == [] and not getattr(args, "all", False):
120
+ parser.error("give at least one component name" + (" or --all" if args.command == "add" else ""))
121
+ return args.func(args)
122
+
123
+
124
+ if __name__ == "__main__":
125
+ sys.exit(main())