cronixui 1.0.5 → 1.1.0

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 (130) hide show
  1. package/README.md +35 -5
  2. package/package.json +21 -3
  3. package/packages/go/cronixui/cronixui.go +784 -237
  4. package/packages/go/cronixui/go.mod +34 -9
  5. package/packages/go/cronixui/go.sum +666 -0
  6. package/packages/python/cronixui/__init__.py +131 -1
  7. package/packages/python/cronixui/alert.py +61 -0
  8. package/packages/python/cronixui/avatar.py +50 -0
  9. package/packages/python/cronixui/badge.py +46 -0
  10. package/packages/python/cronixui/button.py +64 -0
  11. package/packages/python/cronixui/card.py +62 -0
  12. package/packages/python/cronixui/form.py +255 -0
  13. package/packages/python/cronixui/layout.py +143 -0
  14. package/packages/python/cronixui/list.py +51 -0
  15. package/packages/python/cronixui/loading.py +36 -0
  16. package/packages/python/cronixui/progress.py +90 -0
  17. package/packages/python/cronixui/table.py +48 -0
  18. package/packages/python/cronixui/tokens.py +200 -0
  19. package/packages/python/cronixui/tooltip.py +28 -0
  20. package/packages/react/src/components/Accordion.tsx +82 -0
  21. package/packages/react/src/components/Alert.tsx +80 -0
  22. package/packages/react/src/components/Avatar.tsx +54 -0
  23. package/packages/react/src/components/Badge.tsx +32 -0
  24. package/packages/react/src/components/Breadcrumb.tsx +50 -0
  25. package/packages/react/src/components/Button.tsx +47 -0
  26. package/packages/react/src/components/Card.tsx +69 -0
  27. package/packages/react/src/components/Checkbox.tsx +30 -0
  28. package/packages/react/src/components/CommandPalette.tsx +131 -0
  29. package/packages/react/src/components/Container.tsx +26 -0
  30. package/packages/react/src/components/Dropdown.tsx +88 -0
  31. package/packages/react/src/components/FileInput.tsx +86 -0
  32. package/packages/react/src/components/Footer.tsx +36 -0
  33. package/packages/react/src/components/FormGroup.tsx +36 -0
  34. package/packages/react/src/components/Header.tsx +29 -0
  35. package/packages/react/src/components/Input.tsx +54 -0
  36. package/packages/react/src/components/List.tsx +55 -0
  37. package/packages/react/src/components/Modal.tsx +89 -0
  38. package/packages/react/src/components/Nav.tsx +63 -0
  39. package/packages/react/src/components/Pagination.tsx +107 -0
  40. package/packages/react/src/components/Progress.tsx +49 -0
  41. package/packages/react/src/components/Radio.tsx +64 -0
  42. package/packages/react/src/components/Search.tsx +95 -0
  43. package/packages/react/src/components/Select.tsx +41 -0
  44. package/packages/react/src/components/Sidebar.tsx +64 -0
  45. package/packages/react/src/components/Skeleton.tsx +39 -0
  46. package/packages/react/src/components/Slider.tsx +32 -0
  47. package/packages/react/src/components/Spinner.tsx +24 -0
  48. package/packages/react/src/components/Stack.tsx +69 -0
  49. package/packages/react/src/components/Stat.tsx +35 -0
  50. package/packages/react/src/components/Table.tsx +90 -0
  51. package/packages/react/src/components/Tabs.tsx +85 -0
  52. package/packages/react/src/components/Tag.tsx +30 -0
  53. package/packages/react/src/components/Textarea.tsx +21 -0
  54. package/packages/react/src/components/Toast.tsx +134 -0
  55. package/packages/react/src/components/Toggle.tsx +58 -0
  56. package/packages/react/src/components/Tooltip.tsx +31 -0
  57. package/packages/react/src/components/Typography.tsx +66 -0
  58. package/packages/react/src/index.ts +40 -0
  59. package/packages/react/src/styles.css +2039 -0
  60. package/packages/react/src/tokens/index.ts +94 -0
  61. package/packages/rust/cronixui/src/colors.rs +135 -0
  62. package/packages/rust/cronixui/src/components/accordion.rs +47 -0
  63. package/packages/rust/cronixui/src/components/alert.rs +95 -0
  64. package/packages/rust/cronixui/src/components/avatar.rs +85 -0
  65. package/packages/rust/cronixui/src/components/badge.rs +35 -0
  66. package/packages/rust/cronixui/src/components/breadcrumb.rs +58 -0
  67. package/packages/rust/cronixui/src/components/button.rs +70 -0
  68. package/packages/rust/cronixui/src/components/card.rs +259 -0
  69. package/packages/rust/cronixui/src/components/command_palette.rs +254 -0
  70. package/packages/rust/cronixui/src/components/dropdown.rs +179 -0
  71. package/packages/rust/cronixui/src/components/file_input.rs +74 -0
  72. package/packages/rust/cronixui/src/components/input.rs +21 -0
  73. package/packages/rust/cronixui/src/components/list.rs +38 -0
  74. package/packages/rust/cronixui/src/components/mod.rs +51 -0
  75. package/packages/rust/cronixui/src/{modal.rs → components/modal.rs} +15 -1
  76. package/packages/rust/cronixui/src/components/nav.rs +19 -0
  77. package/packages/rust/cronixui/src/{pagination.rs → components/pagination.rs} +14 -13
  78. package/packages/rust/cronixui/src/components/progress.rs +50 -0
  79. package/packages/rust/cronixui/src/components/search.rs +185 -0
  80. package/packages/rust/cronixui/src/components/skeleton.rs +63 -0
  81. package/packages/rust/cronixui/src/components/spinner.rs +21 -0
  82. package/packages/rust/cronixui/src/components/table.rs +56 -0
  83. package/packages/rust/cronixui/src/components/tabs.rs +43 -0
  84. package/packages/rust/cronixui/src/components/toast.rs +69 -0
  85. package/packages/rust/cronixui/src/{toggle.rs → components/toggle.rs} +7 -5
  86. package/packages/rust/cronixui/src/components/tooltip.rs +11 -0
  87. package/packages/rust/cronixui/src/lib.rs +111 -62
  88. package/packages/rust/cronixui/src/tokens.rs +107 -0
  89. package/packages/web/src/tokens.ts +120 -0
  90. package/packages/web/src/variables.css +81 -81
  91. package/packages/python/cronixui/pyproject.toml +0 -11
  92. package/packages/react/src/components/Accordion.jsx +0 -50
  93. package/packages/react/src/components/Alert.jsx +0 -62
  94. package/packages/react/src/components/Avatar.jsx +0 -34
  95. package/packages/react/src/components/Badge.jsx +0 -15
  96. package/packages/react/src/components/Breadcrumb.jsx +0 -27
  97. package/packages/react/src/components/Button.jsx +0 -21
  98. package/packages/react/src/components/Card.jsx +0 -23
  99. package/packages/react/src/components/Checkbox.jsx +0 -27
  100. package/packages/react/src/components/CommandPalette.jsx +0 -93
  101. package/packages/react/src/components/Dropdown.jsx +0 -48
  102. package/packages/react/src/components/FileInput.jsx +0 -44
  103. package/packages/react/src/components/Input.jsx +0 -22
  104. package/packages/react/src/components/List.jsx +0 -29
  105. package/packages/react/src/components/Modal.jsx +0 -65
  106. package/packages/react/src/components/Nav.jsx +0 -50
  107. package/packages/react/src/components/Pagination.jsx +0 -81
  108. package/packages/react/src/components/Progress.jsx +0 -23
  109. package/packages/react/src/components/Radio.jsx +0 -50
  110. package/packages/react/src/components/Search.jsx +0 -70
  111. package/packages/react/src/components/Select.jsx +0 -33
  112. package/packages/react/src/components/Skeleton.jsx +0 -15
  113. package/packages/react/src/components/Slider.jsx +0 -29
  114. package/packages/react/src/components/Spinner.jsx +0 -5
  115. package/packages/react/src/components/Stat.jsx +0 -19
  116. package/packages/react/src/components/Table.jsx +0 -48
  117. package/packages/react/src/components/Tabs.jsx +0 -65
  118. package/packages/react/src/components/Tag.jsx +0 -19
  119. package/packages/react/src/components/Textarea.jsx +0 -17
  120. package/packages/react/src/components/Toast.jsx +0 -78
  121. package/packages/react/src/components/Toggle.jsx +0 -34
  122. package/packages/react/src/components/Tooltip.jsx +0 -12
  123. package/packages/react/src/index.d.ts +0 -103
  124. package/packages/react/src/index.js +0 -33
  125. package/packages/rust/cronixui/src/accordion.rs +0 -49
  126. package/packages/rust/cronixui/src/command_palette.rs +0 -62
  127. package/packages/rust/cronixui/src/dropdown.rs +0 -31
  128. package/packages/rust/cronixui/src/search.rs +0 -49
  129. package/packages/rust/cronixui/src/tabs.rs +0 -23
  130. package/packages/rust/cronixui/src/toast.rs +0 -70
@@ -0,0 +1,143 @@
1
+ """CronixUI Layout Components"""
2
+
3
+ from .core import create_el
4
+
5
+
6
+ class Header:
7
+ """Header component."""
8
+
9
+ def __init__(self, brand: str = ""):
10
+ self.brand = brand
11
+ self.element = self._render()
12
+
13
+ def _render(self):
14
+ el = create_el("header", "cn-header")
15
+
16
+ brand_el = create_el("a", "cn-header-brand")
17
+ brand_el.textContent = self.brand
18
+ el.appendChild(brand_el)
19
+
20
+ self.nav = create_el("nav", "cn-header-nav")
21
+ el.appendChild(self.nav)
22
+
23
+ self.actions = create_el("div", "cn-header-actions")
24
+ el.appendChild(self.actions)
25
+
26
+ return el
27
+
28
+ def add_nav_item(self, text: str, href: str = "#"):
29
+ link = create_el("a", "cn-btn cn-btn-ghost")
30
+ link.textContent = text
31
+ link.setAttribute("href", href)
32
+ self.nav.appendChild(link)
33
+
34
+ def add_action(self, element):
35
+ self.actions.appendChild(element)
36
+
37
+
38
+ class Sidebar:
39
+ """Sidebar navigation component."""
40
+
41
+ def __init__(self):
42
+ self.element = self._render()
43
+
44
+ def _render(self):
45
+ el = create_el("aside", "cn-sidebar")
46
+
47
+ self.header = create_el("div", "cn-sidebar-header")
48
+ el.appendChild(self.header)
49
+
50
+ self.nav = create_el("nav", "cn-sidebar-nav")
51
+ el.appendChild(self.nav)
52
+
53
+ self.footer = create_el("div", "cn-sidebar-footer")
54
+ el.appendChild(self.footer)
55
+
56
+ return el
57
+
58
+ def add_item(
59
+ self, text: str, icon: str = None, href: str = "#", active: bool = False
60
+ ):
61
+ item = create_el("a", "cn-sidebar-item")
62
+ item.setAttribute("href", href)
63
+ if active:
64
+ item.classList.add("cn-sidebar-active")
65
+
66
+ if icon:
67
+ icon_el = create_el("span")
68
+ icon_el.innerHTML = icon
69
+ item.appendChild(icon_el)
70
+
71
+ text_el = create_el("span")
72
+ text_el.textContent = text
73
+ item.appendChild(text_el)
74
+
75
+ self.nav.appendChild(item)
76
+
77
+
78
+ class Footer:
79
+ """Footer component."""
80
+
81
+ def __init__(self, copyright: str = ""):
82
+ self.copyright = copyright
83
+ self.element = self._render()
84
+
85
+ def _render(self):
86
+ el = create_el("footer", "cn-footer")
87
+
88
+ content = create_el("div", "cn-footer-content")
89
+
90
+ self.links = create_el("div", "cn-footer-links")
91
+ content.appendChild(self.links)
92
+
93
+ copyright_el = create_el("div", "cn-footer-copyright")
94
+ copyright_el.textContent = self.copyright
95
+ content.appendChild(copyright_el)
96
+
97
+ el.appendChild(content)
98
+ return el
99
+
100
+ def add_link(self, text: str, href: str = "#"):
101
+ link = create_el("a", "cn-footer-link")
102
+ link.textContent = text
103
+ link.setAttribute("href", href)
104
+ self.links.appendChild(link)
105
+
106
+
107
+ class Container:
108
+ """Container component."""
109
+
110
+ SIZES = ("sm", "md", "lg", "xl", "fluid")
111
+
112
+ def __init__(self, size: str = "lg"):
113
+ self.size = size if size in self.SIZES else "lg"
114
+ self.element = self._render()
115
+
116
+ def _render(self):
117
+ classes = "cn-container"
118
+ if self.size != "lg":
119
+ classes += f" cn-container-{self.size}"
120
+ return create_el("div", classes)
121
+
122
+
123
+ class Divider:
124
+ """Divider component."""
125
+
126
+ def __init__(self):
127
+ self.element = create_el("div", "cn-divider")
128
+
129
+
130
+ class Section:
131
+ """Section spacing component."""
132
+
133
+ SIZES = ("sm", "md", "lg")
134
+
135
+ def __init__(self, size: str = "md"):
136
+ self.size = size if size in self.SIZES else "md"
137
+ self.element = self._render()
138
+
139
+ def _render(self):
140
+ classes = "cn-section"
141
+ if self.size != "md":
142
+ classes += f" cn-section-{self.size}"
143
+ return create_el("section", classes)
@@ -0,0 +1,51 @@
1
+ """CronixUI List Component"""
2
+
3
+ from typing import Optional, Callable
4
+ from .core import create_el
5
+
6
+
7
+ class List:
8
+ """List component."""
9
+
10
+ def __init__(self, items: list, clickable: bool = False):
11
+ self.items = items
12
+ self.clickable = clickable
13
+ self.element = self._render()
14
+
15
+ def _render(self):
16
+ el = create_el("div", "cn-list")
17
+ for item in self.items:
18
+ item_el = create_el("div", "cn-list-item")
19
+ if self.clickable:
20
+ item_el.classList.add("cn-list-item-clickable")
21
+
22
+ if isinstance(item, dict):
23
+ if icon := item.get("icon"):
24
+ icon_el = create_el("span", "cn-list-item-icon")
25
+ icon_el.innerHTML = icon
26
+ item_el.appendChild(icon_el)
27
+
28
+ content = create_el("div", "cn-list-item-content")
29
+ if title := item.get("title"):
30
+ title_el = create_el("div", "cn-list-item-title")
31
+ title_el.textContent = title
32
+ content.appendChild(title_el)
33
+
34
+ if subtitle := item.get("subtitle"):
35
+ subtitle_el = create_el("div", "cn-list-item-subtitle")
36
+ subtitle_el.textContent = subtitle
37
+ content.appendChild(subtitle_el)
38
+
39
+ item_el.appendChild(content)
40
+
41
+ if actions := item.get("actions"):
42
+ actions_el = create_el("div", "cn-list-item-actions")
43
+ actions_el.innerHTML = actions
44
+ item_el.appendChild(actions_el)
45
+ else:
46
+ content = create_el("div", "cn-list-item-content")
47
+ content.textContent = str(item)
48
+ item_el.appendChild(content)
49
+
50
+ el.appendChild(item_el)
51
+ return el
@@ -0,0 +1,36 @@
1
+ """CronixUI Loading Components"""
2
+
3
+ from .core import create_el
4
+
5
+
6
+ class Spinner:
7
+ """Loading spinner component."""
8
+
9
+ SIZES = ("sm", "md", "lg")
10
+
11
+ def __init__(self, size: str = "md"):
12
+ self.size = size if size in self.SIZES else "md"
13
+ self.element = self._render()
14
+
15
+ def _render(self):
16
+ el = create_el("div", "cn-spinner")
17
+ if self.size != "md":
18
+ el.classList.add(f"cn-spinner-{self.size}")
19
+ return el
20
+
21
+
22
+ class Skeleton:
23
+ """Skeleton loading placeholder."""
24
+
25
+ VARIANTS = ("text", "title", "avatar")
26
+
27
+ def __init__(self, variant: str = "text", width: str = None):
28
+ self.variant = variant if variant in self.VARIANTS else "text"
29
+ self.width = width
30
+ self.element = self._render()
31
+
32
+ def _render(self):
33
+ el = create_el("div", f"cn-skeleton cn-skeleton-{self.variant}")
34
+ if self.width:
35
+ el.style.width = self.width
36
+ return el
@@ -0,0 +1,90 @@
1
+ """CronixUI Progress Components"""
2
+
3
+ from .core import create_el
4
+
5
+
6
+ class Progress:
7
+ """Progress bar component."""
8
+
9
+ VARIANTS = ("default", "success", "warning", "error")
10
+ SIZES = ("sm", "md", "lg")
11
+
12
+ def __init__(
13
+ self,
14
+ value: float = 0,
15
+ max: float = 100,
16
+ variant: str = "default",
17
+ size: str = "md",
18
+ show_label: bool = False,
19
+ ):
20
+ self.value = value
21
+ self.max = max
22
+ self.variant = variant if variant in self.VARIANTS else "default"
23
+ self.size = size if size in self.SIZES else "md"
24
+ self.show_label = show_label
25
+ self.element = self._render()
26
+
27
+ def _render(self):
28
+ container = create_el("div")
29
+
30
+ if self.show_label:
31
+ label = create_el("div", "cn-progress-label")
32
+ current = create_el("span")
33
+ current.textContent = str(int(self.value))
34
+ total = create_el("span")
35
+ total.textContent = str(int(self.max))
36
+ label.appendChild(current)
37
+ label.appendChild(total)
38
+ container.appendChild(label)
39
+
40
+ progress = create_el("div", "cn-progress")
41
+ if self.size != "md":
42
+ progress.classList.add(f"cn-progress-{self.size}")
43
+ if self.variant != "default":
44
+ progress.classList.add(f"cn-progress-{self.variant}")
45
+
46
+ bar = create_el("div", "cn-progress-bar")
47
+ bar.style.width = f"{(self.value / self.max) * 100}%"
48
+ progress.appendChild(bar)
49
+
50
+ container.appendChild(progress)
51
+ return container
52
+
53
+ def set_value(self, value: float):
54
+ self.value = value
55
+ bar = self.element.querySelector(".cn-progress-bar")
56
+ if bar:
57
+ bar.style.width = f"{(self.value / self.max) * 100}%"
58
+
59
+
60
+ class Stat:
61
+ """Stat component for displaying metrics."""
62
+
63
+ def __init__(
64
+ self, value: str, label: str, delta: str = None, delta_type: str = None
65
+ ):
66
+ self.value = value
67
+ self.label = label
68
+ self.delta = delta
69
+ self.delta_type = delta_type
70
+ self.element = self._render()
71
+
72
+ def _render(self):
73
+ el = create_el("div", "cn-stat")
74
+
75
+ value_el = create_el("div", "cn-stat-value")
76
+ value_el.textContent = self.value
77
+ el.appendChild(value_el)
78
+
79
+ label_el = create_el("div", "cn-stat-label")
80
+ label_el.textContent = self.label
81
+ el.appendChild(label_el)
82
+
83
+ if self.delta:
84
+ delta_el = create_el(
85
+ "div", f"cn-stat-delta cn-stat-delta-{self.delta_type}"
86
+ )
87
+ delta_el.textContent = self.delta
88
+ el.appendChild(delta_el)
89
+
90
+ return el
@@ -0,0 +1,48 @@
1
+ """CronixUI Table Component"""
2
+
3
+ from typing import List, Optional
4
+ from .core import create_el
5
+
6
+
7
+ class Table:
8
+ """Table component."""
9
+
10
+ def __init__(
11
+ self,
12
+ headers: List[str],
13
+ rows: List[List[str]],
14
+ sortable: bool = False,
15
+ ):
16
+ self.headers = headers
17
+ self.rows = rows
18
+ self.sortable = sortable
19
+ self.element = self._render()
20
+
21
+ def _render(self):
22
+ wrapper = create_el("div", "cn-table-wrapper")
23
+ table = create_el("table", "cn-table")
24
+
25
+ if self.sortable:
26
+ table.classList.add("cn-table-sortable")
27
+
28
+ thead = create_el("thead")
29
+ header_row = create_el("tr")
30
+ for header in self.headers:
31
+ th = create_el("th")
32
+ th.textContent = header
33
+ header_row.appendChild(th)
34
+ thead.appendChild(header_row)
35
+ table.appendChild(thead)
36
+
37
+ tbody = create_el("tbody")
38
+ for row_data in self.rows:
39
+ row = create_el("tr")
40
+ for cell in row_data:
41
+ td = create_el("td")
42
+ td.textContent = cell
43
+ row.appendChild(td)
44
+ tbody.appendChild(row)
45
+ table.appendChild(tbody)
46
+
47
+ wrapper.appendChild(table)
48
+ return wrapper
@@ -0,0 +1,200 @@
1
+ """
2
+ CronixUI Design Tokens
3
+ """
4
+
5
+ from dataclasses import dataclass
6
+ from typing import Tuple
7
+
8
+
9
+ @dataclass(frozen=True)
10
+ class Color:
11
+ """Color token."""
12
+
13
+ hex: str
14
+ rgb: Tuple[int, int, int]
15
+
16
+
17
+ # Background colors
18
+ BG = Color("#0a0a0a", (10, 10, 10))
19
+ SURFACE = Color("#111111", (17, 17, 17))
20
+ SURFACE_2 = Color("#1a1a1a", (26, 26, 26))
21
+ SURFACE_3 = Color("#222222", (34, 34, 34))
22
+ SURFACE_4 = Color("#2a2a2a", (42, 42, 42))
23
+
24
+ # Text colors
25
+ TEXT = Color("#f0ede8", (240, 237, 232))
26
+ TEXT_MUTED = "rgba(240, 237, 232, 0.5)"
27
+ TEXT_DIM = "rgba(240, 237, 232, 0.25)"
28
+
29
+ # Accent (Crimson)
30
+ ACCENT = Color("#6b2323", (107, 35, 35))
31
+ ACCENT_HOVER = Color("#7d2a2a", (125, 42, 42))
32
+ ACCENT_LIGHT = Color("#8a3535", (138, 53, 53))
33
+ ACCENT_GLOW = "rgba(107, 35, 35, 0.3)"
34
+ ACCENT_TEXT = Color("#c97a7a", (201, 122, 122))
35
+
36
+ # Semantic colors
37
+ SUCCESS = Color("#1e5028", (30, 80, 40))
38
+ SUCCESS_BORDER = "rgba(60, 140, 70, 0.4)"
39
+ SUCCESS_TEXT = Color("#6bc47a", (107, 196, 122))
40
+
41
+ WARNING = Color("#503c14", (80, 60, 20))
42
+ WARNING_BORDER = "rgba(150, 110, 30, 0.4)"
43
+ WARNING_TEXT = Color("#c4a43a", (196, 164, 58))
44
+
45
+ ERROR = Color("#501414", (80, 20, 20))
46
+ ERROR_BORDER = "rgba(180, 60, 60, 0.4)"
47
+ ERROR_TEXT = Color("#c46b6b", (196, 107, 107))
48
+
49
+ INFO = Color("#143550", (20, 53, 80))
50
+ INFO_BORDER = "rgba(60, 140, 200, 0.4)"
51
+ INFO_TEXT = Color("#6ba8c4", (107, 168, 196))
52
+
53
+ # Border
54
+ BORDER = "rgba(255, 255, 255, 0.08)"
55
+ BORDER_HOVER = "rgba(255, 255, 255, 0.15)"
56
+ BORDER_FOCUS = "rgba(255, 255, 255, 0.25)"
57
+
58
+
59
+ @dataclass(frozen=True)
60
+ class Typography:
61
+ """Typography tokens."""
62
+
63
+ font_family: str = (
64
+ "'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif"
65
+ )
66
+ font_mono: str = "'JetBrains Mono', 'Fira Code', 'Consolas', monospace"
67
+
68
+ # Font sizes
69
+ xs: int = 11
70
+ sm: int = 12
71
+ base: int = 13
72
+ md: int = 14
73
+ lg: int = 16
74
+ xl: int = 20
75
+ xxl: int = 28
76
+ xxxl: int = 36
77
+
78
+
79
+ @dataclass(frozen=True)
80
+ class Spacing:
81
+ """Spacing tokens."""
82
+
83
+ space_1: int = 4
84
+ space_2: int = 8
85
+ space_3: int = 12
86
+ space_4: int = 16
87
+ space_5: int = 20
88
+ space_6: int = 24
89
+ space_8: int = 32
90
+ space_10: int = 40
91
+ space_12: int = 48
92
+
93
+
94
+ @dataclass(frozen=True)
95
+ class Radius:
96
+ """Border radius tokens."""
97
+
98
+ sm: int = 6
99
+ default: int = 10
100
+ lg: int = 14
101
+ xl: int = 20
102
+ full: int = 9999
103
+
104
+
105
+ @dataclass(frozen=True)
106
+ class Shadow:
107
+ """Shadow tokens."""
108
+
109
+ sm: str = "0 1px 2px rgba(0, 0, 0, 0.3)"
110
+ default: str = "0 4px 12px rgba(0, 0, 0, 0.4)"
111
+ lg: str = "0 8px 24px rgba(0, 0, 0, 0.5)"
112
+ glow: str = "0 0 20px rgba(107, 35, 35, 0.3)"
113
+
114
+
115
+ @dataclass(frozen=True)
116
+ class Transition:
117
+ """Transition tokens."""
118
+
119
+ fast: str = "0.1s ease"
120
+ default: str = "0.15s ease"
121
+ slow: str = "0.25s ease"
122
+
123
+
124
+ @dataclass(frozen=True)
125
+ class ZIndex:
126
+ """Z-index tokens."""
127
+
128
+ dropdown: int = 100
129
+ sticky: int = 200
130
+ fixed: int = 300
131
+ modal_backdrop: int = 400
132
+ modal: int = 500
133
+ popover: int = 600
134
+ tooltip: int = 700
135
+ toast: int = 800
136
+
137
+
138
+ @dataclass(frozen=True)
139
+ class Layout:
140
+ """Layout tokens."""
141
+
142
+ container_max: int = 1200
143
+ sidebar_width: int = 260
144
+
145
+
146
+ # Token instances
147
+ typography = Typography()
148
+ spacing = Spacing()
149
+ radius = Radius()
150
+ shadow = Shadow()
151
+ transition = Transition()
152
+ z_index = ZIndex()
153
+ layout = Layout()
154
+
155
+
156
+ __all__ = [
157
+ "Color",
158
+ "BG",
159
+ "SURFACE",
160
+ "SURFACE_2",
161
+ "SURFACE_3",
162
+ "SURFACE_4",
163
+ "TEXT",
164
+ "TEXT_MUTED",
165
+ "TEXT_DIM",
166
+ "ACCENT",
167
+ "ACCENT_HOVER",
168
+ "ACCENT_LIGHT",
169
+ "ACCENT_GLOW",
170
+ "ACCENT_TEXT",
171
+ "SUCCESS",
172
+ "SUCCESS_BORDER",
173
+ "SUCCESS_TEXT",
174
+ "WARNING",
175
+ "WARNING_BORDER",
176
+ "WARNING_TEXT",
177
+ "ERROR",
178
+ "ERROR_BORDER",
179
+ "ERROR_TEXT",
180
+ "INFO",
181
+ "INFO_BORDER",
182
+ "INFO_TEXT",
183
+ "BORDER",
184
+ "BORDER_HOVER",
185
+ "BORDER_FOCUS",
186
+ "Typography",
187
+ "typography",
188
+ "Spacing",
189
+ "spacing",
190
+ "Radius",
191
+ "radius",
192
+ "Shadow",
193
+ "shadow",
194
+ "Transition",
195
+ "transition",
196
+ "ZIndex",
197
+ "z_index",
198
+ "Layout",
199
+ "layout",
200
+ ]
@@ -0,0 +1,28 @@
1
+ """CronixUI Tooltip Component"""
2
+
3
+ from .core import create_el
4
+
5
+
6
+ class Tooltip:
7
+ """Tooltip component."""
8
+
9
+ POSITIONS = ("top", "bottom", "left", "right")
10
+
11
+ def __init__(self, content: str, position: str = "top"):
12
+ self.content = content
13
+ self.position = position if position in self.POSITIONS else "top"
14
+ self.element = self._render()
15
+
16
+ def _render(self):
17
+ el = create_el("div", "cn-tooltip")
18
+
19
+ tooltip_content = create_el("div", "cn-tooltip-content")
20
+ tooltip_content.textContent = self.content
21
+
22
+ el.appendChild(tooltip_content)
23
+ return el
24
+
25
+ def wrap(self, element):
26
+ """Wrap an element with tooltip."""
27
+ self.element.insertBefore(element, self.element.firstChild)
28
+ return self.element
@@ -0,0 +1,82 @@
1
+ import * as React from 'react';
2
+
3
+ export interface AccordionProps extends React.HTMLAttributes<HTMLDivElement> {
4
+ allowMultiple?: boolean;
5
+ defaultOpen?: number[];
6
+ }
7
+
8
+ export interface AccordionItemProps {
9
+ title: string;
10
+ children: React.ReactNode;
11
+ }
12
+
13
+ export const Accordion: React.FC<AccordionProps> & {
14
+ Item: React.FC<AccordionItemProps>;
15
+ } = Object.assign(
16
+ ({ allowMultiple = false, defaultOpen = [], children, className = '', ...props }: AccordionProps) => {
17
+ const [openItems, setOpenItems] = React.useState(new Set(defaultOpen));
18
+
19
+ const toggleItem = (index: number) => {
20
+ setOpenItems((prev) => {
21
+ const next = new Set(prev);
22
+ if (next.has(index)) {
23
+ next.delete(index);
24
+ } else {
25
+ if (!allowMultiple) {
26
+ next.clear();
27
+ }
28
+ next.add(index);
29
+ }
30
+ return next;
31
+ });
32
+ };
33
+
34
+ const items = React.Children.toArray(children);
35
+
36
+ return (
37
+ <div className={`cn-accordion ${className}`.trim()} {...props}>
38
+ {items.map((child, idx) => {
39
+ if (React.isValidElement<AccordionItemProps>(child)) {
40
+ return (
41
+ <div
42
+ key={idx}
43
+ className={`cn-accordion-item ${openItems.has(idx) ? 'cn-accordion-open' : ''}`.trim()}
44
+ >
45
+ <div
46
+ className="cn-accordion-header"
47
+ onClick={() => toggleItem(idx)}
48
+ role="button"
49
+ tabIndex={0}
50
+ aria-expanded={openItems.has(idx)}
51
+ onKeyDown={(e) => {
52
+ if (e.key === 'Enter' || e.key === ' ') {
53
+ e.preventDefault();
54
+ toggleItem(idx);
55
+ }
56
+ }}
57
+ >
58
+ <span className="cn-accordion-title">{child.props.title}</span>
59
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" width="20" height="20" className="cn-accordion-icon">
60
+ <polyline points="6 9 12 15 18 9" />
61
+ </svg>
62
+ </div>
63
+ <div className="cn-accordion-content">
64
+ {child.props.children}
65
+ </div>
66
+ </div>
67
+ );
68
+ }
69
+ return child;
70
+ })}
71
+ </div>
72
+ );
73
+ },
74
+ {
75
+ Item: ({ children }: AccordionItemProps) => <>{children}</>,
76
+ }
77
+ );
78
+
79
+ Accordion.displayName = 'Accordion';
80
+ (Accordion.Item as React.FC<AccordionItemProps> & { displayName?: string }).displayName = 'AccordionItem';
81
+
82
+ export default Accordion;