reflex-components-internal 0.0.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.
Files changed (57) hide show
  1. reflex_components_internal/__init__.py +50 -0
  2. reflex_components_internal/blocks/__init__.py +1 -0
  3. reflex_components_internal/blocks/calcom.py +110 -0
  4. reflex_components_internal/blocks/demo_form.py +423 -0
  5. reflex_components_internal/blocks/intro_form.py +444 -0
  6. reflex_components_internal/blocks/lemcal.py +68 -0
  7. reflex_components_internal/blocks/plain.py +166 -0
  8. reflex_components_internal/blocks/telemetry/__init__.py +23 -0
  9. reflex_components_internal/blocks/telemetry/clearbit.py +22 -0
  10. reflex_components_internal/blocks/telemetry/common_room.py +77 -0
  11. reflex_components_internal/blocks/telemetry/default.py +16 -0
  12. reflex_components_internal/blocks/telemetry/google.py +59 -0
  13. reflex_components_internal/blocks/telemetry/koala.py +46 -0
  14. reflex_components_internal/blocks/telemetry/posthog.py +138 -0
  15. reflex_components_internal/blocks/telemetry/rb2b.py +30 -0
  16. reflex_components_internal/blocks/telemetry/unify.py +15 -0
  17. reflex_components_internal/components/__init__.py +18 -0
  18. reflex_components_internal/components/base/__init__.py +15 -0
  19. reflex_components_internal/components/base/accordion.py +329 -0
  20. reflex_components_internal/components/base/avatar.py +139 -0
  21. reflex_components_internal/components/base/badge.py +124 -0
  22. reflex_components_internal/components/base/button.py +149 -0
  23. reflex_components_internal/components/base/card.py +178 -0
  24. reflex_components_internal/components/base/checkbox.py +153 -0
  25. reflex_components_internal/components/base/collapsible.py +156 -0
  26. reflex_components_internal/components/base/context_menu.py +745 -0
  27. reflex_components_internal/components/base/dialog.py +309 -0
  28. reflex_components_internal/components/base/drawer.py +320 -0
  29. reflex_components_internal/components/base/gradient_profile.py +34 -0
  30. reflex_components_internal/components/base/input.py +208 -0
  31. reflex_components_internal/components/base/link.py +109 -0
  32. reflex_components_internal/components/base/menu.py +782 -0
  33. reflex_components_internal/components/base/navigation_menu.py +393 -0
  34. reflex_components_internal/components/base/popover.py +406 -0
  35. reflex_components_internal/components/base/preview_card.py +304 -0
  36. reflex_components_internal/components/base/scroll_area.py +230 -0
  37. reflex_components_internal/components/base/select.py +715 -0
  38. reflex_components_internal/components/base/skeleton.py +28 -0
  39. reflex_components_internal/components/base/slider.py +288 -0
  40. reflex_components_internal/components/base/switch.py +131 -0
  41. reflex_components_internal/components/base/tabs.py +220 -0
  42. reflex_components_internal/components/base/textarea.py +39 -0
  43. reflex_components_internal/components/base/theme_switcher.py +56 -0
  44. reflex_components_internal/components/base/toggle.py +65 -0
  45. reflex_components_internal/components/base/toggle_group.py +72 -0
  46. reflex_components_internal/components/base/tooltip.py +352 -0
  47. reflex_components_internal/components/base_ui.py +14 -0
  48. reflex_components_internal/components/component.py +42 -0
  49. reflex_components_internal/components/icons/__init__.py +19 -0
  50. reflex_components_internal/components/icons/hugeicon.py +85 -0
  51. reflex_components_internal/components/icons/others.py +86 -0
  52. reflex_components_internal/components/icons/simple_icon.py +49 -0
  53. reflex_components_internal/utils/__init__.py +17 -0
  54. reflex_components_internal/utils/twmerge.py +25 -0
  55. reflex_components_internal-0.0.1.dist-info/METADATA +14 -0
  56. reflex_components_internal-0.0.1.dist-info/RECORD +57 -0
  57. reflex_components_internal-0.0.1.dist-info/WHEEL +4 -0
@@ -0,0 +1,50 @@
1
+ """Reflex internal components package."""
2
+
3
+ from reflex.utils import lazy_loader
4
+
5
+ _COMPONENTS_MAPPING = {
6
+ "components.base.accordion": ["accordion"],
7
+ "components.base.avatar": ["avatar"],
8
+ "components.base.badge": ["badge"],
9
+ "components.base.button": ["button"],
10
+ "components.base.card": ["card"],
11
+ "components.base.checkbox": ["checkbox"],
12
+ "components.base.collapsible": ["collapsible"],
13
+ "components.base.context_menu": ["context_menu"],
14
+ "components.base.dialog": ["dialog"],
15
+ "components.base.drawer": ["drawer"],
16
+ "components.base.gradient_profile": ["gradient_profile"],
17
+ "components.base.input": ["input"],
18
+ "components.base.link": ["link"],
19
+ "components.base.menu": ["menu"],
20
+ "components.base.navigation_menu": ["navigation_menu"],
21
+ "components.base.popover": ["popover"],
22
+ "components.base.preview_card": ["preview_card"],
23
+ "components.base.scroll_area": ["scroll_area"],
24
+ "components.base.select": ["select"],
25
+ "components.base.skeleton": ["skeleton"],
26
+ "components.base.slider": ["slider"],
27
+ "components.base.switch": ["switch"],
28
+ "components.base.tabs": ["tabs"],
29
+ "components.base.textarea": ["textarea"],
30
+ "components.base.theme_switcher": ["theme_switcher"],
31
+ "components.base.toggle_group": ["toggle_group"],
32
+ "components.base.toggle": ["toggle"],
33
+ "components.base.tooltip": ["tooltip"],
34
+ }
35
+
36
+ _SUBMODULES = {"components", "utils"}
37
+ _SUBMOD_ATTRS = {
38
+ **_COMPONENTS_MAPPING,
39
+ "components": ["base"],
40
+ "components.icons.hugeicon": ["hi", "icon"],
41
+ "components.icons.simple_icon": ["simple_icon"],
42
+ "components.icons.others": ["spinner", "select_arrow", "arrow_svg"],
43
+ "utils.twmerge": ["cn"],
44
+ }
45
+
46
+ __getattr__, __dir__, __all__ = lazy_loader.attach(
47
+ __name__,
48
+ submodules=_SUBMODULES,
49
+ submod_attrs=_SUBMOD_ATTRS,
50
+ )
@@ -0,0 +1 @@
1
+ """Blocks for reflex-components-internal."""
@@ -0,0 +1,110 @@
1
+ """Cal.com integration components."""
2
+
3
+ import os
4
+
5
+ import reflex as rx
6
+
7
+ DEFAULT_CAL_FORM = os.getenv(
8
+ "DEFAULT_CAL_FORM", "forms/f87bd9b2-b339-4915-b4d4-0098e2db4394"
9
+ )
10
+
11
+
12
+ def get_cal_attrs(cal_form: str = DEFAULT_CAL_FORM, **kwargs):
13
+ """Get Cal.com attributes for embedding.
14
+
15
+ Args:
16
+ cal_form: The Cal.com form link
17
+ **kwargs: Additional attributes to include
18
+
19
+ Returns:
20
+ Dictionary of Cal.com attributes
21
+ """
22
+ attrs = {
23
+ "data-cal-link": cal_form,
24
+ "data-cal-namespace": "talk",
25
+ "data-cal-config": rx.color_mode_cond(
26
+ '{"theme":"light","layout":"month_view"}',
27
+ '{"theme":"dark","layout":"month_view"}',
28
+ ),
29
+ }
30
+ attrs.update(kwargs)
31
+ return attrs
32
+
33
+
34
+ class CalcomPopupEmbed(rx.Fragment):
35
+ """Cal.com popup embed component using React hooks."""
36
+
37
+ def add_imports(self) -> rx.ImportDict:
38
+ """Add required imports for Cal.com embed.
39
+
40
+ Returns:
41
+ Dictionary of imports needed for the component
42
+ """
43
+ return {
44
+ "react": rx.ImportVar("useEffect"),
45
+ "@calcom/embed-react@1.5.3": rx.ImportVar("getCalApi"),
46
+ }
47
+
48
+ def add_hooks(self) -> list[str | rx.Var[object]]:
49
+ """Add React hooks for Cal.com API initialization.
50
+
51
+ Returns:
52
+ List of hook code strings to initialize Cal.com
53
+ """
54
+ return [
55
+ """
56
+ useEffect(() => {
57
+ (async function () {
58
+ const cal = await getCalApi({ namespace: "talk" });
59
+ cal("ui", {
60
+ hideEventTypeDetails: false,
61
+ layout: "month_view",
62
+ styles: {
63
+ branding: { brandColor: "#6F56CF" },
64
+ },
65
+ });
66
+ })();
67
+ }, []);
68
+ """,
69
+ ]
70
+
71
+
72
+ calcom_popup_embed = CalcomPopupEmbed.create
73
+
74
+
75
+ class CalEmbed(rx.Component):
76
+ """Cal.com embed component using the Cal React component."""
77
+
78
+ library = "@calcom/embed-react@1.5.3"
79
+ tag = "Cal"
80
+ is_default = True
81
+
82
+ cal_link: rx.Var[str]
83
+
84
+ config: rx.Var[dict]
85
+
86
+ @classmethod
87
+ def create(
88
+ cls,
89
+ cal_link: str = DEFAULT_CAL_FORM,
90
+ config: dict | None = None,
91
+ **props,
92
+ ):
93
+ """Create a Cal.com embed component.
94
+
95
+ Args:
96
+ cal_link: The Cal.com link (e.g., "forms/...")
97
+ config: Configuration object for Cal.com (e.g., {"theme": "light"})
98
+ **props: Additional props to pass to the component
99
+
100
+ Returns:
101
+ The component.
102
+ """
103
+ return super().create(
104
+ cal_link=cal_link,
105
+ config=config,
106
+ **props,
107
+ )
108
+
109
+
110
+ cal_embed = CalEmbed.create
@@ -0,0 +1,423 @@
1
+ """Demo form component for collecting user information and scheduling enterprise calls.
2
+
3
+ This module provides a comprehensive demo form that validates company emails,
4
+ sends data to PostHog and Slack, and redirects users to appropriate Cal.com links
5
+ based on company size.
6
+ """
7
+
8
+ from typing import Any
9
+
10
+ import reflex as rx
11
+ from reflex.event import EventType
12
+ from reflex.experimental.client_state import ClientStateVar
13
+ from reflex.vars.base import get_unique_variable_name
14
+ from reflex_components_internal.blocks.telemetry.posthog import (
15
+ track_demo_form_posthog_submission,
16
+ )
17
+ from reflex_components_internal.components.base.button import button
18
+ from reflex_components_internal.components.base.dialog import dialog
19
+ from reflex_components_internal.components.base.input import input
20
+ from reflex_components_internal.components.base.textarea import textarea
21
+ from reflex_components_internal.components.icons.hugeicon import hi
22
+ from reflex_components_internal.components.icons.others import select_arrow
23
+ from reflex_components_internal.utils.twmerge import cn
24
+
25
+ demo_form_error_message = ClientStateVar.create("demo_form_error_message", "")
26
+ demo_form_open_cs = ClientStateVar.create("demo_form_open", False)
27
+
28
+ PERSONAL_EMAIL_PROVIDERS = r"^(?!.*@(gmail|outlook|hotmail|yahoo|icloud|aol|protonmail|mail|yandex|zoho|live|msn|me|mac|googlemail)\.com$|.*@(yahoo|outlook|hotmail)\.co\.uk$|.*@yahoo\.ca$|.*@yahoo\.co\.in$|.*@proton\.me$).*$"
29
+
30
+
31
+ def get_element_value(element_id: str) -> str:
32
+ """Get the value of an element by ID.
33
+
34
+ Returns:
35
+ The component.
36
+ """
37
+ return f"document.getElementById('{element_id}')?.value"
38
+
39
+
40
+ def check_if_company_email(email: str) -> bool:
41
+ """Check if an email address is from a company domain (not a personal email provider).
42
+
43
+ Args:
44
+ email: The email address to check
45
+
46
+ Returns:
47
+ True if it's likely a company email, False if it's from a personal provider
48
+ """
49
+ if not email or "@" not in email:
50
+ return False
51
+
52
+ domain = email.split("@")[-1].lower()
53
+
54
+ # List of common personal email providers
55
+ personal_domains = {
56
+ "gmail.com",
57
+ "outlook.com",
58
+ "hotmail.com",
59
+ "yahoo.com",
60
+ "icloud.com",
61
+ "aol.com",
62
+ "protonmail.com",
63
+ "proton.me",
64
+ "mail.com",
65
+ "yandex.com",
66
+ "zoho.com",
67
+ "live.com",
68
+ "msn.com",
69
+ "me.com",
70
+ "mac.com",
71
+ "googlemail.com",
72
+ "yahoo.co.uk",
73
+ "yahoo.ca",
74
+ "yahoo.co.in",
75
+ "outlook.co.uk",
76
+ "hotmail.co.uk",
77
+ }
78
+
79
+ return domain not in personal_domains and ".edu" not in domain
80
+
81
+
82
+ def check_if_default_value_is_selected(value: str) -> bool:
83
+ """Check if the default value is selected.
84
+
85
+ Returns:
86
+ The component.
87
+ """
88
+ return bool(value.strip())
89
+
90
+
91
+ class DemoFormStateUI(rx.State):
92
+ """State for handling demo form submissions and validation."""
93
+
94
+ @rx.event
95
+ def validate_email(self, email: str):
96
+ """Validate the email address.
97
+
98
+ Yields:
99
+ The event actions.
100
+ """
101
+ if not check_if_company_email(email):
102
+ yield [
103
+ demo_form_error_message.push(
104
+ "Please enter a valid company email - gmails, aol, me, etc are not allowed"
105
+ ),
106
+ ]
107
+ else:
108
+ yield demo_form_error_message.push("")
109
+
110
+ @rx.event
111
+ def track_demo_form_posthog(self, form_data: dict[str, Any]):
112
+ """Send demo form fields to PostHog (identify + capture) in the browser.
113
+
114
+ Returns:
115
+ Event that runs PostHog identify and capture in the browser.
116
+ """
117
+ return track_demo_form_posthog_submission(form_data)
118
+
119
+
120
+ def input_field(
121
+ label: str,
122
+ placeholder: str,
123
+ name: str,
124
+ type: str = "text",
125
+ required: bool = False,
126
+ ) -> rx.Component:
127
+ """Create a labeled input field component.
128
+
129
+ Args:
130
+ label: The label text to display above the input
131
+ placeholder: Placeholder text for the input
132
+ name: The name attribute for the input field
133
+ type: The input type (text, email, tel, etc.)
134
+ required: Whether the field is required
135
+
136
+ Returns:
137
+ A Reflex component containing the labeled input field
138
+ """
139
+ return rx.el.div(
140
+ rx.el.label(
141
+ label + (" *" if required else ""),
142
+ class_name="block text-sm font-medium text-secondary-12",
143
+ ),
144
+ input(
145
+ placeholder=placeholder,
146
+ name=name,
147
+ type=type,
148
+ required=required,
149
+ max_length=255,
150
+ class_name="w-full",
151
+ ),
152
+ class_name="flex flex-col gap-1.5",
153
+ )
154
+
155
+
156
+ def validation_input_field(
157
+ label: str,
158
+ placeholder: str,
159
+ name: str,
160
+ type: str = "text",
161
+ required: bool = False,
162
+ pattern: str | None = None,
163
+ on_blur: EventType[()] | None = None,
164
+ id: str = "",
165
+ ) -> rx.Component:
166
+ """Create a labeled input field component.
167
+
168
+ Args:
169
+ label: The label text to display above the input
170
+ placeholder: Placeholder text for the input
171
+ name: The name attribute for the input field
172
+ type: The input type (text, email, tel, etc.)
173
+ pattern: Regex pattern for input validation
174
+ required: Whether the field is required
175
+ on_blur: Event handler for when the input is blurred
176
+ id: The ID attribute for the input field
177
+
178
+ Returns:
179
+ A Reflex component containing the labeled input field
180
+ """
181
+ return rx.el.div(
182
+ rx.el.label(
183
+ label + (" *" if required else ""),
184
+ class_name="block text-sm font-medium text-secondary-12",
185
+ ),
186
+ input(
187
+ placeholder=placeholder,
188
+ id=id,
189
+ name=name,
190
+ type=type,
191
+ required=required,
192
+ max_length=255,
193
+ pattern=pattern,
194
+ class_name="w-full",
195
+ on_blur=on_blur,
196
+ ),
197
+ class_name="flex flex-col gap-1.5",
198
+ )
199
+
200
+
201
+ def text_area_field(
202
+ label: str, placeholder: str, name: str, required: bool = False
203
+ ) -> rx.Component:
204
+ """Create a labeled textarea field component.
205
+
206
+ Args:
207
+ label: The label text to display above the textarea
208
+ placeholder: Placeholder text for the textarea
209
+ name: The name attribute for the textarea field
210
+ required: Whether the field is required
211
+
212
+ Returns:
213
+ A Reflex component containing the labeled textarea field
214
+ """
215
+ return rx.el.div(
216
+ rx.el.label(label, class_name="block text-sm font-medium text-secondary-12"),
217
+ textarea(
218
+ placeholder=placeholder,
219
+ name=name,
220
+ required=required,
221
+ class_name="w-full min-h-14",
222
+ max_length=800,
223
+ ),
224
+ class_name="flex flex-col gap-1.5",
225
+ )
226
+
227
+
228
+ def select_field(
229
+ label: str,
230
+ name: str,
231
+ items: list[str],
232
+ required: bool = False,
233
+ ) -> rx.Component:
234
+ """Create a labeled select field component.
235
+
236
+ Args:
237
+ label: The label text to display above the select
238
+ name: The name attribute for the select field
239
+ items: List of options to display in the select
240
+ required: Whether the field is required
241
+
242
+ Returns:
243
+ A Reflex component containing the labeled select field
244
+ """
245
+ return rx.el.div(
246
+ rx.el.label(
247
+ label + (" *" if required else ""),
248
+ class_name="block text-xs lg:text-sm font-medium text-secondary-12 truncate min-w-0",
249
+ ),
250
+ rx.el.div(
251
+ rx.el.select(
252
+ rx.el.option("Select", value=""),
253
+ *[rx.el.option(item, value=item) for item in items],
254
+ default_value="",
255
+ name=name,
256
+ required=required,
257
+ class_name=cn(
258
+ "w-full appearance-none pr-9",
259
+ button.class_names.for_button("outline", "md"),
260
+ "outline-primary-6 focus:border-primary-6",
261
+ ),
262
+ ),
263
+ select_arrow(
264
+ class_name="size-4 text-secondary-9 absolute right-2.5 top-1/2 -translate-y-1/2 pointer-events-none"
265
+ ),
266
+ class_name="relative",
267
+ ),
268
+ class_name="flex flex-col gap-1.5 min-w-0",
269
+ )
270
+
271
+
272
+ def demo_form(id_prefix: str = "", **props) -> rx.Component:
273
+ """Create and return the demo form component.
274
+
275
+ Builds a complete form with all required fields, validation,
276
+ and styling. The form includes personal info, company details,
277
+ and preferences.
278
+
279
+ Args:
280
+ id_prefix: Optional prefix for all element IDs to ensure uniqueness when multiple forms exist.
281
+ If empty, a unique prefix will be auto-generated.
282
+ **props: Additional properties to pass to the form component
283
+
284
+ Returns:
285
+ A Reflex form component with all demo form fields
286
+ """
287
+ prefix = id_prefix or get_unique_variable_name()
288
+ email_id = f"{prefix}_user_email"
289
+ form = rx.el.form(
290
+ rx.el.div(
291
+ input_field("First name", "John", "first_name", "text", True),
292
+ input_field("Last name", "Smith", "last_name", "text", True),
293
+ class_name="grid grid-cols-2 gap-4",
294
+ ),
295
+ validation_input_field(
296
+ "Business Email",
297
+ "john@company.com",
298
+ "email",
299
+ "email",
300
+ True,
301
+ PERSONAL_EMAIL_PROVIDERS,
302
+ id=email_id,
303
+ on_blur=DemoFormStateUI.validate_email(rx.Var(get_element_value(email_id))),
304
+ ),
305
+ rx.el.div(
306
+ input_field("Job title", "CTO", "job_title", "text", True),
307
+ input_field("Company name", "Pynecone, Inc.", "company_name", "text", True),
308
+ class_name="grid grid-cols-2 gap-4",
309
+ ),
310
+ text_area_field(
311
+ "What are you looking to build? *",
312
+ "Please list any apps, requirements, or data sources you plan on using",
313
+ "internal_tools",
314
+ True,
315
+ ),
316
+ rx.el.div(
317
+ select_field(
318
+ "Number of employees?",
319
+ "number_of_employees",
320
+ ["1", "2-5", "6-10", "11-50", "51-100", "101-500", "500+"],
321
+ required=True,
322
+ ),
323
+ select_field(
324
+ "How did you hear about us?",
325
+ "how_did_you_hear_about_us",
326
+ [
327
+ "Google Search",
328
+ "Social Media",
329
+ "Word of Mouth",
330
+ "Blog",
331
+ "Conference",
332
+ "LLM (Claude, ChatGPT, etc)",
333
+ "Other",
334
+ ],
335
+ required=True,
336
+ ),
337
+ class_name="grid grid-cols-1 md:grid-cols-2 gap-4",
338
+ ),
339
+ select_field(
340
+ "How technical are you?",
341
+ "technical_level",
342
+ ["Non-technical", "Neutral", "Technical"],
343
+ True,
344
+ ),
345
+ rx.cond(
346
+ demo_form_error_message.value,
347
+ rx.el.span(
348
+ demo_form_error_message.value,
349
+ class_name="text-destructive-10 text-sm font-medium px-2 py-1 rounded-md bg-destructive-3 border border-destructive-4",
350
+ ),
351
+ ),
352
+ button(
353
+ "Submit",
354
+ type="submit",
355
+ class_name="w-full",
356
+ ),
357
+ class_name=cn(
358
+ "@container flex flex-col lg:gap-6 gap-2 p-6",
359
+ props.pop("class_name", ""),
360
+ ),
361
+ on_submit=[
362
+ DemoFormStateUI.track_demo_form_posthog,
363
+ rx.call_function(demo_form_open_cs.set_value(False)),
364
+ ],
365
+ data_default_form_id="965991",
366
+ **props,
367
+ )
368
+ return rx.fragment(
369
+ form,
370
+ )
371
+
372
+
373
+ def demo_form_dialog(
374
+ trigger: rx.Component | None = None, id_prefix: str = "", **props
375
+ ) -> rx.Component:
376
+ """Return a demo form dialog container element.
377
+
378
+ Args:
379
+ trigger: The component that triggers the dialog
380
+ id_prefix: Optional prefix for all element IDs to ensure uniqueness when multiple dialogs exist
381
+ **props: Additional properties to pass to the dialog root
382
+
383
+ Returns:
384
+ A Reflex dialog component containing the demo form
385
+ """
386
+ if trigger is None:
387
+ trigger = rx.fragment()
388
+ class_name = cn("w-auto", props.pop("class_name", ""))
389
+ return dialog.root(
390
+ dialog.trigger(render_=trigger),
391
+ dialog.portal(
392
+ dialog.backdrop(),
393
+ dialog.popup(
394
+ rx.el.div(
395
+ rx.el.div(
396
+ rx.el.h1(
397
+ "Book a Demo",
398
+ class_name="text-xl font-bold text-secondary-12",
399
+ ),
400
+ dialog.close(
401
+ render_=button(
402
+ hi("Cancel01Icon"),
403
+ variant="ghost",
404
+ size="icon-sm",
405
+ class_name="text-secondary-11",
406
+ ),
407
+ ),
408
+ class_name="flex flex-row justify-between items-center gap-1 px-6 pt-4 -mb-4",
409
+ ),
410
+ demo_form(id_prefix=id_prefix, class_name="w-full max-w-md"),
411
+ class_name="relative isolate overflow-hidden -m-px w-full max-w-md",
412
+ ),
413
+ class_name="h-fit mt-1 overflow-hidden w-full max-w-md",
414
+ ),
415
+ ),
416
+ open=demo_form_open_cs.value,
417
+ on_open_change=demo_form_open_cs.set_value,
418
+ on_open_change_complete=[
419
+ rx.call_function(demo_form_error_message.set_value(""))
420
+ ],
421
+ class_name=class_name,
422
+ **props,
423
+ )