buridan-create 0.1.0__tar.gz

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.
Files changed (81) hide show
  1. buridan_create-0.1.0/.gitignore +15 -0
  2. buridan_create-0.1.0/.python-version +1 -0
  3. buridan_create-0.1.0/PKG-INFO +6 -0
  4. buridan_create-0.1.0/app/__init__.py +0 -0
  5. buridan_create-0.1.0/app/app.py +6 -0
  6. buridan_create-0.1.0/app/base_ui/__init__.py +0 -0
  7. buridan_create-0.1.0/app/base_ui/components/__init__.py +0 -0
  8. buridan_create-0.1.0/app/base_ui/components/base/__init__.py +0 -0
  9. buridan_create-0.1.0/app/base_ui/components/base/accordion.py +331 -0
  10. buridan_create-0.1.0/app/base_ui/components/base/avatar.py +126 -0
  11. buridan_create-0.1.0/app/base_ui/components/base/badge.py +88 -0
  12. buridan_create-0.1.0/app/base_ui/components/base/breadcrumb.py +95 -0
  13. buridan_create-0.1.0/app/base_ui/components/base/button.py +124 -0
  14. buridan_create-0.1.0/app/base_ui/components/base/checkbox.py +138 -0
  15. buridan_create-0.1.0/app/base_ui/components/base/collapsible.py +141 -0
  16. buridan_create-0.1.0/app/base_ui/components/base/context_menu.py +678 -0
  17. buridan_create-0.1.0/app/base_ui/components/base/dialog.py +277 -0
  18. buridan_create-0.1.0/app/base_ui/components/base/input.py +47 -0
  19. buridan_create-0.1.0/app/base_ui/components/base/input_group.py +93 -0
  20. buridan_create-0.1.0/app/base_ui/components/base/kbd.py +48 -0
  21. buridan_create-0.1.0/app/base_ui/components/base/link.py +105 -0
  22. buridan_create-0.1.0/app/base_ui/components/base/menu.py +690 -0
  23. buridan_create-0.1.0/app/base_ui/components/base/popover.py +375 -0
  24. buridan_create-0.1.0/app/base_ui/components/base/scroll_area.py +206 -0
  25. buridan_create-0.1.0/app/base_ui/components/base/select.py +593 -0
  26. buridan_create-0.1.0/app/base_ui/components/base/skeleton.py +23 -0
  27. buridan_create-0.1.0/app/base_ui/components/base/slider.py +232 -0
  28. buridan_create-0.1.0/app/base_ui/components/base/switch.py +118 -0
  29. buridan_create-0.1.0/app/base_ui/components/base/tabs.py +167 -0
  30. buridan_create-0.1.0/app/base_ui/components/base/textarea.py +46 -0
  31. buridan_create-0.1.0/app/base_ui/components/base/theme_switcher.py +37 -0
  32. buridan_create-0.1.0/app/base_ui/components/base/toggle.py +62 -0
  33. buridan_create-0.1.0/app/base_ui/components/base/toggle_group.py +69 -0
  34. buridan_create-0.1.0/app/base_ui/components/base/tooltip.py +316 -0
  35. buridan_create-0.1.0/app/base_ui/components/base/typography.py +146 -0
  36. buridan_create-0.1.0/app/base_ui/components/base_ui.py +12 -0
  37. buridan_create-0.1.0/app/base_ui/components/component.py +43 -0
  38. buridan_create-0.1.0/app/base_ui/icons/hugeicon.py +64 -0
  39. buridan_create-0.1.0/app/base_ui/icons/others.py +89 -0
  40. buridan_create-0.1.0/app/base_ui/utils/__init__.py +0 -0
  41. buridan_create-0.1.0/app/base_ui/utils/twmerge.py +28 -0
  42. buridan_create-0.1.0/app/constants.py +0 -0
  43. buridan_create-0.1.0/app/engine/actions.py +831 -0
  44. buridan_create-0.1.0/app/engine/seed.py +235 -0
  45. buridan_create-0.1.0/app/engine/url_sync.py +80 -0
  46. buridan_create-0.1.0/app/examples/components.py +1162 -0
  47. buridan_create-0.1.0/app/examples/utils.py +54 -0
  48. buridan_create-0.1.0/app/export.py +0 -0
  49. buridan_create-0.1.0/app/hooks.py +35 -0
  50. buridan_create-0.1.0/app/registry/colors.py +264 -0
  51. buridan_create-0.1.0/app/registry/fonts.py +28 -0
  52. buridan_create-0.1.0/app/registry/radii.py +6 -0
  53. buridan_create-0.1.0/app/registry/styles.py +56 -0
  54. buridan_create-0.1.0/app/registry/themes.py +433 -0
  55. buridan_create-0.1.0/app/templates/compiler.py +420 -0
  56. buridan_create-0.1.0/app/templates/config.py +60 -0
  57. buridan_create-0.1.0/app/templates/mainpage.py +25 -0
  58. buridan_create-0.1.0/app/templates/navbar.py +68 -0
  59. buridan_create-0.1.0/app/templates/options.py +596 -0
  60. buridan_create-0.1.0/app/templates/preview.py +64 -0
  61. buridan_create-0.1.0/app/templates/reset.py +51 -0
  62. buridan_create-0.1.0/app/templates/sidebar.py +99 -0
  63. buridan_create-0.1.0/assets/favicon.ico +0 -0
  64. buridan_create-0.1.0/assets/globals.css +72 -0
  65. buridan_create-0.1.0/assets/svg/claude/claude_dark.svg +1 -0
  66. buridan_create-0.1.0/assets/svg/claude/claude_light.svg +1 -0
  67. buridan_create-0.1.0/assets/svg/markdown/md_dark.svg +1 -0
  68. buridan_create-0.1.0/assets/svg/markdown/md_light.svg +1 -0
  69. buridan_create-0.1.0/assets/svg/openai/ai_dark.svg +1 -0
  70. buridan_create-0.1.0/assets/svg/openai/ai_light.svg +1 -0
  71. buridan_create-0.1.0/assets/svg/reflex/reflex_dark.svg +5 -0
  72. buridan_create-0.1.0/assets/svg/reflex/reflex_light.svg +5 -0
  73. buridan_create-0.1.0/assets/svg/theme/theme_dark.svg +31 -0
  74. buridan_create-0.1.0/assets/svg/theme/theme_light.svg +24 -0
  75. buridan_create-0.1.0/cli/main.py +273 -0
  76. buridan_create-0.1.0/pyproject.toml +19 -0
  77. buridan_create-0.1.0/reflex.lock/bun.lock +649 -0
  78. buridan_create-0.1.0/reflex.lock/package.json +42 -0
  79. buridan_create-0.1.0/rxconfig.py +63 -0
  80. buridan_create-0.1.0/scratch.py +609 -0
  81. buridan_create-0.1.0/uv.lock +922 -0
@@ -0,0 +1,15 @@
1
+ .states
2
+ .web
3
+ assets/external/
4
+ *.py[cod]
5
+ *.db
6
+ # Python-generated files
7
+ __pycache__/
8
+ *.py[oc]
9
+ build/
10
+ dist/
11
+ wheels/
12
+ *.egg-info
13
+
14
+ # Virtual environments
15
+ .venv
@@ -0,0 +1 @@
1
+ 3.11
@@ -0,0 +1,6 @@
1
+ Metadata-Version: 2.4
2
+ Name: buridan-create
3
+ Version: 0.1.0
4
+ Summary: CLI to initialize Buridan UI design system in Reflex apps
5
+ Requires-Python: >=3.11
6
+ Requires-Dist: reflex>=0.9.3
File without changes
@@ -0,0 +1,6 @@
1
+ import reflex as rx
2
+
3
+ from app.templates.mainpage import mainpage
4
+
5
+ app = rx.App(stylesheets=["globals.css"])
6
+ app.add_page(component=mainpage(), route="/")
File without changes
@@ -0,0 +1,331 @@
1
+ """Custom Accordion component."""
2
+
3
+ from typing import Any, Literal
4
+
5
+ from reflex.components.component import Component, ComponentNamespace
6
+ from reflex.event import EventHandler, passthrough_event_spec
7
+ from reflex.utils.imports import ImportVar
8
+ from reflex.vars.base import Var
9
+ from reflex.vars.object import ObjectVar
10
+ from reflex_components_core.core.foreach import foreach
11
+ from reflex_components_core.el import Div
12
+
13
+ from ...icons.hugeicon import hi, icon
14
+ from ..base.button import button
15
+ from ..base_ui import PACKAGE_NAME, BaseUIComponent
16
+
17
+ LiteralOrientation = Literal["horizontal", "vertical"]
18
+
19
+ ITEMS_TYPE = list[dict[str, str | Component]]
20
+
21
+
22
+ class ClassNames:
23
+ """Class names for accordion components."""
24
+
25
+ ROOT = (
26
+ "flex flex-col justify-center divide-y divide-input overflow-hidden rounded-xl"
27
+ )
28
+ ITEM = "not-last:border-b"
29
+ HEADER = ""
30
+ TRIGGER = "group relative flex w-full items-center justify-between gap-4 bg-secondary py-2 text-md font-semibold text-secondary-12 transition-colors disabled:cursor-not-allowed disabled:bg-secondary-3 disabled:text-secondary-8 disabled:[&_svg]:text-secondary-8 [&_svg]:text-secondary-11"
31
+ PANEL = "h-[var(--accordion-panel-height)] overflow-hidden transition-[height] ease-out data-[ending-style]:h-0 data-[starting-style]:h-0"
32
+ PANEL_DIV = ""
33
+ TRIGGER_ICON = "size-4 shrink-0 transition-all ease-out group-data-[panel-open]:scale-110 group-data-[panel-open]:rotate-45"
34
+
35
+
36
+ class AccordionBaseComponent(BaseUIComponent):
37
+ """Base component for accordion components."""
38
+
39
+ library = f"{PACKAGE_NAME}/accordion"
40
+
41
+ @property
42
+ def import_var(self):
43
+ """Return the import variable for the accordion component."""
44
+ return ImportVar(tag="Accordion", package_path="", install=False)
45
+
46
+
47
+ class AccordionRoot(AccordionBaseComponent):
48
+ """Groups all parts of the accordion."""
49
+
50
+ tag = "Accordion.Root"
51
+
52
+ # The uncontrolled value of the item(s) that should be initially expanded. To render a controlled accordion, use the `value` prop instead.
53
+ default_value: Var[list[Any]]
54
+
55
+ # The controlled value of the item(s) that should be expanded. To render an uncontrolled accordion, use the `default_value` prop instead.
56
+ value: Var[list[Any]]
57
+
58
+ # Event handler called when an accordion item is expanded or collapsed. Provides the new value as an argument.
59
+ on_value_change: EventHandler[passthrough_event_spec(list[str])]
60
+
61
+ # Allows the browser's built-in page search to find and expand the panel contents. Overrides the `keep_mounted` prop and uses `hidden="until-found"` to hide the element without removing it from the DOM. Defaults to False.
62
+ hidden_until_found: Var[bool]
63
+
64
+ # Whether multiple items can be open at the same time. Defaults to True.
65
+ multiple: Var[bool]
66
+
67
+ # Whether the component should ignore user interaction. Defaults to False.
68
+ disabled: Var[bool]
69
+
70
+ # Whether to loop keyboard focus back to the first item when the end of the list is reached while using the arrow keys. Defaults to True.
71
+ loop_focus: Var[bool]
72
+
73
+ # The visual orientation of the accordion. Controls whether roving focus uses left/right or up/down arrow keys. Defaults to 'vertical'.
74
+ orientation: Var[LiteralOrientation]
75
+
76
+ # Whether to keep the element in the DOM while the panel is closed. This prop is ignored when hidden_until_found is used. Defaults to False.
77
+ keep_mounted: Var[bool]
78
+
79
+ # The render prop.
80
+ render_: Var[Component]
81
+
82
+ @classmethod
83
+ def create(cls, *children, **props) -> BaseUIComponent:
84
+ """Create the accordion root component."""
85
+ props["data-slot"] = "accordion"
86
+ cls.set_class_name(ClassNames.ROOT, props)
87
+ return super().create(*children, **props)
88
+
89
+
90
+ class AccordionItem(AccordionBaseComponent):
91
+ """Groups an accordion header with the corresponding panel."""
92
+
93
+ tag = "Accordion.Item"
94
+
95
+ # The value that identifies this item.
96
+ value: Var[str]
97
+
98
+ # Event handler called when the panel is opened or closed.
99
+ on_open_change: EventHandler[passthrough_event_spec(bool)]
100
+
101
+ # Whether the component should ignore user interaction. Defaults to False.
102
+ disabled: Var[bool]
103
+
104
+ # The render prop.
105
+ render_: Var[Component]
106
+
107
+ @classmethod
108
+ def create(cls, *children, **props) -> BaseUIComponent:
109
+ """Create the accordion item component."""
110
+ props["data-slot"] = "accordion-item"
111
+ cls.set_class_name(ClassNames.ITEM, props)
112
+ return super().create(*children, **props)
113
+
114
+
115
+ class AccordionHeader(AccordionBaseComponent):
116
+ """A heading that labels the corresponding panel."""
117
+
118
+ tag = "Accordion.Header"
119
+
120
+ # The render prop.
121
+ render_: Var[Component]
122
+
123
+ @classmethod
124
+ def create(cls, *children, **props) -> BaseUIComponent:
125
+ """Create the accordion header component."""
126
+ props["data-slot"] = "accordion-header"
127
+ cls.set_class_name(ClassNames.HEADER, props)
128
+ return super().create(*children, **props)
129
+
130
+
131
+ class AccordionTrigger(AccordionBaseComponent):
132
+ """A button that opens and closes the corresponding panel."""
133
+
134
+ tag = "Accordion.Trigger"
135
+
136
+ title: Var[str]
137
+ native_button: Var[bool]
138
+
139
+ # Default is None so we can detect overrides
140
+ render_: Var[Component] = None
141
+
142
+ @classmethod
143
+ def create(cls, *children, **props) -> BaseUIComponent:
144
+ props["data-slot"] = "accordion-trigger"
145
+ cls.set_class_name(ClassNames.TRIGGER, props)
146
+
147
+ # 1️⃣ If render_ is NOT provided, we must resolve title
148
+ if "render_" not in props or props["render_"] is None:
149
+ if "title" not in props:
150
+ if len(children) == 1 and isinstance(children[0], str):
151
+ props["title"] = children[0]
152
+ elif children:
153
+ raise TypeError(
154
+ "AccordionTrigger expects a single string child "
155
+ "when used without a `title` prop."
156
+ )
157
+ else:
158
+ raise ValueError("AccordionTrigger requires a `title`.")
159
+
160
+ # 2️⃣ Generate default render_
161
+ props["render_"] = button(
162
+ props["title"],
163
+ hi(
164
+ "Add01Icon",
165
+ class_name=(
166
+ "size-3 transition-transform duration-50 ease-in-out "
167
+ "group-aria-[expanded=true]:rotate-45"
168
+ ),
169
+ ),
170
+ variant="ghost",
171
+ class_name=(
172
+ "w-full flex items-center justify-between group py-2 "
173
+ "font-medium !text-sm hover:bg-transparent !px-0"
174
+ ),
175
+ )
176
+
177
+ # 3️⃣ render_ was supplied → leave it untouched
178
+ return super().create(*children, **props)
179
+
180
+
181
+ class AccordionPanel(AccordionBaseComponent):
182
+ """A collapsible panel with the accordion item contents."""
183
+
184
+ tag = "Accordion.Panel"
185
+
186
+ # Allows the browser's built-in page search to find and expand the panel contents. Overrides the `keep_mounted` prop and uses `hidden="until-found"` to hide the element without removing it from the DOM. Defaults to False.
187
+ hidden_until_found: Var[bool]
188
+
189
+ # Whether to keep the element in the DOM while the panel is closed. This prop is ignored when `hidden_until_found` is used. Defaults to False.
190
+ keep_mounted: Var[bool]
191
+
192
+ # The render prop.
193
+ render_: Var[Component]
194
+
195
+ @classmethod
196
+ def create(cls, *children, **props) -> BaseUIComponent:
197
+ """Create the accordion panel component."""
198
+ props["data-slot"] = "accordion-panel"
199
+ cls.set_class_name(ClassNames.PANEL, props)
200
+ return super().create(*children, **props)
201
+
202
+
203
+ class HighLevelAccordion(AccordionRoot):
204
+ """High level wrapper for the Accordion component."""
205
+
206
+ items: Var[ITEMS_TYPE] | ITEMS_TYPE
207
+
208
+ _item_props = {"on_open_change", "disabled"}
209
+ _trigger_props = {"native_button"}
210
+ _panel_props = {"hidden_until_found", "keep_mounted"}
211
+
212
+ @classmethod
213
+ def create(
214
+ cls,
215
+ items: Var[ITEMS_TYPE] | ITEMS_TYPE,
216
+ **props,
217
+ ) -> BaseUIComponent:
218
+ """Create a high level accordion component.
219
+
220
+ Args:
221
+ items: List of dictionaries with 'trigger', 'content', and optional 'value' and 'disabled' keys.
222
+ **props: Additional properties to apply to the accordion component.
223
+
224
+ Returns:
225
+ The accordion component with all necessary subcomponents.
226
+ """
227
+ # Extract props for different parts
228
+ item_props = {k: props.pop(k) for k in cls._item_props & props.keys()}
229
+ trigger_props = {k: props.pop(k) for k in cls._trigger_props & props.keys()}
230
+ panel_props = {k: props.pop(k) for k in cls._panel_props & props.keys()}
231
+
232
+ if isinstance(items, Var):
233
+ accordion_items = foreach(
234
+ items,
235
+ lambda item: cls._create_accordion_item_dynamic(
236
+ item, item_props, trigger_props, panel_props
237
+ ),
238
+ )
239
+ return AccordionRoot.create(accordion_items, **props)
240
+ accordion_items = [
241
+ cls._create_accordion_item(
242
+ item, index, item_props, trigger_props, panel_props
243
+ )
244
+ for index, item in enumerate(items)
245
+ ]
246
+ return AccordionRoot.create(*accordion_items, **props)
247
+
248
+ @classmethod
249
+ def _create_trigger_icon(cls) -> Component:
250
+ """Create the accordion trigger icon."""
251
+ return icon(
252
+ "PlusSignIcon",
253
+ class_name=ClassNames.TRIGGER_ICON,
254
+ data_slot="accordion-trigger-icon",
255
+ )
256
+
257
+ @classmethod
258
+ def _create_accordion_item(
259
+ cls,
260
+ item: dict[str, str | Component],
261
+ index: int,
262
+ item_props: dict,
263
+ trigger_props: dict,
264
+ panel_props: dict,
265
+ ) -> BaseUIComponent:
266
+ """Create a single accordion item from a dictionary (for normal lists)."""
267
+ return AccordionItem.create(
268
+ AccordionHeader.create(
269
+ AccordionTrigger.create(
270
+ item.get("trigger"),
271
+ cls._create_trigger_icon(),
272
+ **trigger_props,
273
+ ),
274
+ ),
275
+ AccordionPanel.create(
276
+ Div.create(
277
+ item.get("content"),
278
+ class_name=ClassNames.PANEL_DIV,
279
+ data_slot="accordion-panel-div",
280
+ ),
281
+ **panel_props,
282
+ ),
283
+ value=item.get("value", f"item-{index + 1}"),
284
+ disabled=item.get("disabled", False),
285
+ **item_props,
286
+ )
287
+
288
+ @classmethod
289
+ def _create_accordion_item_dynamic(
290
+ cls,
291
+ item: ObjectVar[dict[str, str | Component]],
292
+ item_props: dict,
293
+ trigger_props: dict,
294
+ panel_props: dict,
295
+ ) -> BaseUIComponent:
296
+ """Create a single accordion item from a dictionary (for Var items)."""
297
+ return AccordionItem.create(
298
+ AccordionHeader.create(
299
+ AccordionTrigger.create(
300
+ item["trigger"],
301
+ cls._create_trigger_icon(),
302
+ **trigger_props,
303
+ ),
304
+ ),
305
+ AccordionPanel.create(
306
+ Div.create(
307
+ item["content"],
308
+ class_name=ClassNames.PANEL_DIV,
309
+ data_slot="accordion-panel-div",
310
+ ),
311
+ **panel_props,
312
+ ),
313
+ value=item.get("value", ""),
314
+ disabled=item.get("disabled", False).bool(),
315
+ **item_props,
316
+ )
317
+
318
+
319
+ class Accordion(ComponentNamespace):
320
+ """Namespace for Accordion components."""
321
+
322
+ root = staticmethod(AccordionRoot.create)
323
+ item = staticmethod(AccordionItem.create)
324
+ header = staticmethod(AccordionHeader.create)
325
+ trigger = staticmethod(AccordionTrigger.create)
326
+ panel = staticmethod(AccordionPanel.create)
327
+ class_names = ClassNames
328
+ __call__ = staticmethod(HighLevelAccordion.create)
329
+
330
+
331
+ accordion = Accordion()
@@ -0,0 +1,126 @@
1
+ """Custom avatar component."""
2
+
3
+ from reflex.components.component import Component, ComponentNamespace
4
+ from reflex.event import EventHandler, passthrough_event_spec
5
+ from reflex.utils.imports import ImportVar
6
+ from reflex.vars.base import Var
7
+
8
+ from ..base_ui import PACKAGE_NAME, BaseUIComponent
9
+
10
+
11
+ class ClassNames:
12
+ """Class names for avatar components."""
13
+
14
+ ROOT = "shrink-0 inline-flex size-8 items-center justify-center overflow-hidden rounded-full align-middle text-base font-medium select-none"
15
+ IMAGE = "size-full object-cover shrink-0"
16
+ FALLBACK = "flex size-full items-center justify-center text-sm bg-muted"
17
+
18
+
19
+ class AvatarBaseComponent(BaseUIComponent):
20
+ """Base component for avatar components."""
21
+
22
+ library = f"{PACKAGE_NAME}/avatar"
23
+
24
+ @property
25
+ def import_var(self):
26
+ """Return the import variable for the avatar component."""
27
+ return ImportVar(tag="Avatar", package_path="", install=False)
28
+
29
+
30
+ class AvatarRoot(AvatarBaseComponent):
31
+ """Displays a user's profile picture, initials, or fallback icon."""
32
+
33
+ tag = "Avatar.Root"
34
+
35
+ # The component to render
36
+ render_: Var[Component]
37
+
38
+ @classmethod
39
+ def create(cls, *children, **props) -> BaseUIComponent:
40
+ """Create the avatar root component."""
41
+ props["data-slot"] = "avatar"
42
+ cls.set_class_name(ClassNames.ROOT, props)
43
+ return super().create(*children, **props)
44
+
45
+
46
+ class AvatarImage(AvatarBaseComponent):
47
+ """The image to be displayed in the avatar."""
48
+
49
+ tag = "Avatar.Image"
50
+
51
+ # The image source URL
52
+ src: Var[str]
53
+
54
+ # Callback when loading status changes
55
+ on_loading_status_change: EventHandler[passthrough_event_spec(str)]
56
+
57
+ # The component to render
58
+ render_: Var[Component]
59
+
60
+ @classmethod
61
+ def create(cls, *children, **props) -> BaseUIComponent:
62
+ """Create the avatar image component."""
63
+ props["data-slot"] = "avatar-image"
64
+ cls.set_class_name(ClassNames.IMAGE, props)
65
+ return super().create(*children, **props)
66
+
67
+
68
+ class AvatarFallback(AvatarBaseComponent):
69
+ """Rendered when the image fails to load or when no image is provided."""
70
+
71
+ tag = "Avatar.Fallback"
72
+
73
+ # How long to wait before showing the fallback. Specified in milliseconds
74
+ delay: Var[int]
75
+
76
+ # The component to render
77
+ render_: Var[Component]
78
+
79
+ @classmethod
80
+ def create(cls, *children, **props) -> BaseUIComponent:
81
+ """Create the avatar fallback component."""
82
+ props["data-slot"] = "avatar-fallback"
83
+ cls.set_class_name(ClassNames.FALLBACK, props)
84
+ return super().create(*children, **props)
85
+
86
+
87
+ class HighLevelAvatar(AvatarRoot):
88
+ """High level wrapper for the Avatar component."""
89
+
90
+ # The image source URL
91
+ src: Var[str]
92
+
93
+ # Image props
94
+ _image_props = {"src", "on_loading_status_change", "render_"}
95
+
96
+ # Fallback props
97
+ _fallback_props = {"delay"}
98
+
99
+ @classmethod
100
+ def create(cls, *children, **props) -> BaseUIComponent:
101
+ """Create the avatar component."""
102
+ # Extract props for each subcomponent
103
+ image_props = {k: props.pop(k) for k in cls._image_props & props.keys()}
104
+ fallback_props = {k: props.pop(k) for k in cls._fallback_props & props.keys()}
105
+
106
+ fallback_content = props.pop("fallback", "")
107
+
108
+ return AvatarRoot.create(
109
+ AvatarImage.create(**image_props),
110
+ AvatarFallback.create(fallback_content, **fallback_props),
111
+ *children,
112
+ **props,
113
+ )
114
+
115
+
116
+ class Avatar(ComponentNamespace):
117
+ """Namespace for Avatar components."""
118
+
119
+ root = staticmethod(AvatarRoot.create)
120
+ image = staticmethod(AvatarImage.create)
121
+ fallback = staticmethod(AvatarFallback.create)
122
+ class_names = ClassNames
123
+ __call__ = staticmethod(HighLevelAvatar.create)
124
+
125
+
126
+ avatar = Avatar()
@@ -0,0 +1,88 @@
1
+ from typing import Literal
2
+
3
+ from reflex.vars.base import Var
4
+ from reflex_components_core.el import Span
5
+
6
+ from ..component import CoreComponent
7
+
8
+ LiteralBadgeVariant = Literal["default", "secondary", "destructive", "outline"]
9
+
10
+ DEFAULT_BASE_CLASSES = (
11
+ "inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium "
12
+ "w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none "
13
+ "focus-visible:border-[var(--ring)] focus-visible:ring-[var(--ring)]/50 focus-visible:ring-[3px] "
14
+ "aria-invalid:ring-[var(--destructive)]/20 dark:aria-invalid:ring-[var(--destructive)]/40 "
15
+ "aria-invalid:border-[var(--destructive)] transition-[color,box-shadow] overflow-hidden"
16
+ )
17
+
18
+ BADGE_VARIANTS = {
19
+ "default": (
20
+ "border-transparent bg-[var(--primary)] text-[var(--primary-foreground)] "
21
+ "[a&]:hover:bg-[var(--primary)]/90"
22
+ ),
23
+ "secondary": (
24
+ "border-transparent bg-[var(--secondary)] text-[var(--secondary-foreground)] "
25
+ "[a&]:hover:bg-[var(--secondary)]/90"
26
+ ),
27
+ "destructive": (
28
+ "border-transparent bg-[var(--destructive)] text-white "
29
+ "[a&]:hover:bg-[var(--destructive)]/90 "
30
+ "focus-visible:ring-[var(--destructive)]/20 dark:focus-visible:ring-[var(--destructive)]/40 "
31
+ "dark:bg-[var(--destructive)]/60"
32
+ ),
33
+ "outline": (
34
+ "text-[var(--foreground)] border-[var(--input)] "
35
+ "[a&]:hover:bg-[var(--accent)] [a&]:hover:text-[var(--accent-foreground)]"
36
+ ),
37
+ }
38
+
39
+
40
+ def get_badge_classes(variant: LiteralBadgeVariant) -> str:
41
+ """Get the complete badge class string.
42
+
43
+ Args:
44
+ variant: The badge variant to apply
45
+
46
+ Returns:
47
+ The complete class string for the badge
48
+ """
49
+ variant_classes = BADGE_VARIANTS[variant]
50
+ return f"{DEFAULT_BASE_CLASSES} {variant_classes}"
51
+
52
+
53
+ class Badge(Span, CoreComponent):
54
+ """A badge component that displays a label."""
55
+
56
+ # Badge variant
57
+ variant: Var[LiteralBadgeVariant]
58
+
59
+ @classmethod
60
+ def create(cls, *children, **props) -> Span:
61
+ """Create the badge component.
62
+
63
+ Args:
64
+ *children: The badge content
65
+ **props: Component properties including variant
66
+
67
+ Returns:
68
+ A configured Span component
69
+ """
70
+ variant = props.pop("variant", "default")
71
+
72
+ cls.set_class_name(get_badge_classes(variant), props)
73
+
74
+ # Add data-slot attribute
75
+ props.setdefault("data_slot", "badge")
76
+
77
+ return super().create(*children, **props)
78
+
79
+ def _exclude_props(self) -> list[str]:
80
+ """Exclude component-specific props from being passed to the DOM.
81
+
82
+ Returns:
83
+ List of prop names to exclude
84
+ """
85
+ return [*super()._exclude_props(), "variant"]
86
+
87
+
88
+ badge = Badge.create
@@ -0,0 +1,95 @@
1
+ import reflex as rx
2
+
3
+
4
+ def breadcrumb(*children, **props):
5
+ """Breadcrumb navigation container"""
6
+ return rx.el.nav(
7
+ *children, aria_label="breadcrumb", data_slot="breadcrumb", **props
8
+ )
9
+
10
+
11
+ def breadcrumb_list(*children, class_name: str = "", **props):
12
+ """Ordered list container for breadcrumb items"""
13
+ base_classes = (
14
+ "text-[var(--muted-foreground)] flex flex-wrap items-center gap-1 text-sm "
15
+ "break-words sm:gap-2.5"
16
+ )
17
+
18
+ return rx.el.ol(
19
+ *children,
20
+ data_slot="breadcrumb-list",
21
+ class_name=f"{base_classes} {class_name}".strip(),
22
+ **props,
23
+ )
24
+
25
+
26
+ def breadcrumb_item(*children, class_name: str = "", **props):
27
+ """Individual breadcrumb item"""
28
+ base_classes = "inline-flex items-center gap-1.5"
29
+
30
+ return rx.el.li(
31
+ *children,
32
+ data_slot="breadcrumb-item",
33
+ class_name=f"{base_classes} {class_name}".strip(),
34
+ **props,
35
+ )
36
+
37
+
38
+ def breadcrumb_link(*children, href: str = "#", class_name: str = "", **props):
39
+ """Breadcrumb link (clickable)"""
40
+ base_classes = "hover:text-[var(--foreground)] transition-colors no-underline"
41
+
42
+ return rx.el.a(
43
+ *children,
44
+ href=href,
45
+ data_slot="breadcrumb-link",
46
+ class_name=f"{base_classes} {class_name}".strip(),
47
+ **props,
48
+ )
49
+
50
+
51
+ def breadcrumb_page(*children, class_name: str = "", **props):
52
+ """Current page breadcrumb (non-clickable)"""
53
+ base_classes = "text-[var(--foreground)] font-normal"
54
+
55
+ return rx.el.span(
56
+ *children,
57
+ role="link",
58
+ aria_disabled="true",
59
+ aria_current="page",
60
+ data_slot="breadcrumb-page",
61
+ class_name=f"{base_classes} {class_name}".strip(),
62
+ **props,
63
+ )
64
+
65
+
66
+ def breadcrumb_separator(*children, class_name: str = "", **props):
67
+ """Separator between breadcrumb items"""
68
+ base_classes = "[&>svg]:size-3.5"
69
+
70
+ if not children:
71
+ children = (rx.icon(tag="chevron-right", size=14),)
72
+
73
+ return rx.el.li(
74
+ *children,
75
+ role="presentation",
76
+ aria_hidden="true",
77
+ data_slot="breadcrumb-separator",
78
+ class_name=f"{base_classes} {class_name}".strip(),
79
+ **props,
80
+ )
81
+
82
+
83
+ def breadcrumb_ellipsis(class_name: str = "", **props):
84
+ """Ellipsis for collapsed breadcrumb items"""
85
+ base_classes = "flex size-9 items-center justify-center"
86
+
87
+ return rx.el.span(
88
+ rx.icon(tag="ellipsis", size=16),
89
+ rx.el.span("More", class_name="sr-only"),
90
+ role="presentation",
91
+ aria_hidden="true",
92
+ data_slot="breadcrumb-ellipsis",
93
+ class_name=f"{base_classes} {class_name}".strip(),
94
+ **props,
95
+ )