cronixui 1.0.6 → 1.1.1

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 (169) hide show
  1. package/README.md +20 -5
  2. package/package.json +20 -5
  3. package/packages/flutter/lib/cronixui.dart +41 -0
  4. package/packages/flutter/lib/src/tokens/colors.dart +34 -0
  5. package/packages/flutter/lib/src/tokens/spacing.dart +54 -0
  6. package/packages/flutter/lib/src/tokens/theme.dart +174 -0
  7. package/packages/flutter/lib/src/widgets/cn_accordion.dart +254 -0
  8. package/packages/flutter/lib/src/widgets/cn_alert.dart +137 -0
  9. package/packages/flutter/lib/src/widgets/cn_avatar.dart +98 -0
  10. package/packages/flutter/lib/src/widgets/cn_badge.dart +80 -0
  11. package/packages/flutter/lib/src/widgets/cn_breadcrumb.dart +88 -0
  12. package/packages/flutter/lib/src/widgets/cn_button.dart +137 -0
  13. package/packages/flutter/lib/src/widgets/cn_card.dart +99 -0
  14. package/packages/flutter/lib/src/widgets/cn_checkbox.dart +77 -0
  15. package/packages/flutter/lib/src/widgets/cn_command_palette.dart +299 -0
  16. package/packages/flutter/lib/src/widgets/cn_container.dart +131 -0
  17. package/packages/flutter/lib/src/widgets/cn_dropdown.dart +149 -0
  18. package/packages/flutter/lib/src/widgets/cn_file_input.dart +113 -0
  19. package/packages/flutter/lib/src/widgets/cn_footer.dart +108 -0
  20. package/packages/flutter/lib/src/widgets/cn_header.dart +173 -0
  21. package/packages/flutter/lib/src/widgets/cn_input.dart +142 -0
  22. package/packages/flutter/lib/src/widgets/cn_list.dart +150 -0
  23. package/packages/flutter/lib/src/widgets/cn_modal.dart +213 -0
  24. package/packages/flutter/lib/src/widgets/cn_nav.dart +157 -0
  25. package/packages/flutter/lib/src/widgets/cn_pagination.dart +193 -0
  26. package/packages/flutter/lib/src/widgets/cn_progress.dart +146 -0
  27. package/packages/flutter/lib/src/widgets/cn_radio.dart +133 -0
  28. package/packages/flutter/lib/src/widgets/cn_search.dart +183 -0
  29. package/packages/flutter/lib/src/widgets/cn_select.dart +244 -0
  30. package/packages/flutter/lib/src/widgets/cn_sidebar.dart +207 -0
  31. package/packages/flutter/lib/src/widgets/cn_skeleton.dart +136 -0
  32. package/packages/flutter/lib/src/widgets/cn_slider.dart +141 -0
  33. package/packages/flutter/lib/src/widgets/cn_spinner.dart +85 -0
  34. package/packages/flutter/lib/src/widgets/cn_stat.dart +135 -0
  35. package/packages/flutter/lib/src/widgets/cn_table.dart +136 -0
  36. package/packages/flutter/lib/src/widgets/cn_tabs.dart +229 -0
  37. package/packages/flutter/lib/src/widgets/cn_tag.dart +185 -0
  38. package/packages/flutter/lib/src/widgets/cn_textarea.dart +143 -0
  39. package/packages/flutter/lib/src/widgets/cn_toast.dart +121 -0
  40. package/packages/flutter/lib/src/widgets/cn_toggle.dart +78 -0
  41. package/packages/flutter/lib/src/widgets/cn_tooltip.dart +118 -0
  42. package/packages/flutter/pubspec.yaml +20 -0
  43. package/packages/go/cronixui/cronixui.go +784 -237
  44. package/packages/go/cronixui/go.mod +32 -0
  45. package/packages/go/cronixui/go.sum +666 -0
  46. package/packages/python/cronixui/__init__.py +59 -3
  47. package/packages/python/cronixui/alert.py +61 -0
  48. package/packages/python/cronixui/avatar.py +50 -0
  49. package/packages/python/cronixui/badge.py +46 -0
  50. package/packages/python/cronixui/button.py +64 -0
  51. package/packages/python/cronixui/card.py +62 -0
  52. package/packages/python/cronixui/form.py +255 -0
  53. package/packages/python/cronixui/layout.py +143 -0
  54. package/packages/python/cronixui/list.py +51 -0
  55. package/packages/python/cronixui/loading.py +36 -0
  56. package/packages/python/cronixui/progress.py +90 -0
  57. package/packages/python/cronixui/table.py +48 -0
  58. package/packages/python/cronixui/tooltip.py +28 -0
  59. package/packages/react/src/components/Accordion.tsx +82 -0
  60. package/packages/react/src/components/Alert.tsx +80 -0
  61. package/packages/react/src/components/Avatar.tsx +54 -0
  62. package/packages/react/src/components/Badge.tsx +32 -0
  63. package/packages/react/src/components/Breadcrumb.tsx +50 -0
  64. package/packages/react/src/components/Button.tsx +47 -0
  65. package/packages/react/src/components/Card.tsx +69 -0
  66. package/packages/react/src/components/Checkbox.tsx +30 -0
  67. package/packages/react/src/components/CommandPalette.tsx +131 -0
  68. package/packages/react/src/components/Container.tsx +26 -0
  69. package/packages/react/src/components/Dropdown.tsx +88 -0
  70. package/packages/react/src/components/FileInput.tsx +86 -0
  71. package/packages/react/src/components/Footer.tsx +36 -0
  72. package/packages/react/src/components/FormGroup.tsx +36 -0
  73. package/packages/react/src/components/Header.tsx +29 -0
  74. package/packages/react/src/components/Input.tsx +54 -0
  75. package/packages/react/src/components/List.tsx +55 -0
  76. package/packages/react/src/components/Modal.tsx +89 -0
  77. package/packages/react/src/components/Nav.tsx +63 -0
  78. package/packages/react/src/components/Pagination.tsx +107 -0
  79. package/packages/react/src/components/Progress.tsx +49 -0
  80. package/packages/react/src/components/Radio.tsx +64 -0
  81. package/packages/react/src/components/Search.tsx +95 -0
  82. package/packages/react/src/components/Select.tsx +41 -0
  83. package/packages/react/src/components/Sidebar.tsx +64 -0
  84. package/packages/react/src/components/Skeleton.tsx +39 -0
  85. package/packages/react/src/components/Slider.tsx +32 -0
  86. package/packages/react/src/components/Spinner.tsx +24 -0
  87. package/packages/react/src/components/Stack.tsx +69 -0
  88. package/packages/react/src/components/Stat.tsx +35 -0
  89. package/packages/react/src/components/Table.tsx +90 -0
  90. package/packages/react/src/components/Tabs.tsx +85 -0
  91. package/packages/react/src/components/Tag.tsx +30 -0
  92. package/packages/react/src/components/Textarea.tsx +21 -0
  93. package/packages/react/src/components/Toast.tsx +134 -0
  94. package/packages/react/src/components/Toggle.tsx +58 -0
  95. package/packages/react/src/components/Tooltip.tsx +31 -0
  96. package/packages/react/src/components/Typography.tsx +66 -0
  97. package/packages/react/src/index.ts +40 -0
  98. package/packages/react/src/styles.css +2039 -0
  99. package/packages/react/src/tokens/index.ts +94 -0
  100. package/packages/rust/cronixui/src/colors.rs +135 -0
  101. package/packages/rust/cronixui/src/components/accordion.rs +47 -0
  102. package/packages/rust/cronixui/src/components/alert.rs +95 -0
  103. package/packages/rust/cronixui/src/components/avatar.rs +85 -0
  104. package/packages/rust/cronixui/src/components/badge.rs +35 -0
  105. package/packages/rust/cronixui/src/components/breadcrumb.rs +58 -0
  106. package/packages/rust/cronixui/src/components/button.rs +70 -0
  107. package/packages/rust/cronixui/src/components/card.rs +259 -0
  108. package/packages/rust/cronixui/src/components/command_palette.rs +254 -0
  109. package/packages/rust/cronixui/src/components/dropdown.rs +179 -0
  110. package/packages/rust/cronixui/src/components/file_input.rs +74 -0
  111. package/packages/rust/cronixui/src/components/input.rs +21 -0
  112. package/packages/rust/cronixui/src/components/list.rs +38 -0
  113. package/packages/rust/cronixui/src/components/mod.rs +51 -0
  114. package/packages/rust/cronixui/src/{modal.rs → components/modal.rs} +15 -1
  115. package/packages/rust/cronixui/src/components/nav.rs +19 -0
  116. package/packages/rust/cronixui/src/{pagination.rs → components/pagination.rs} +14 -13
  117. package/packages/rust/cronixui/src/components/progress.rs +50 -0
  118. package/packages/rust/cronixui/src/components/search.rs +185 -0
  119. package/packages/rust/cronixui/src/components/skeleton.rs +63 -0
  120. package/packages/rust/cronixui/src/components/spinner.rs +21 -0
  121. package/packages/rust/cronixui/src/components/table.rs +56 -0
  122. package/packages/rust/cronixui/src/components/tabs.rs +43 -0
  123. package/packages/rust/cronixui/src/components/toast.rs +69 -0
  124. package/packages/rust/cronixui/src/{toggle.rs → components/toggle.rs} +7 -5
  125. package/packages/rust/cronixui/src/components/tooltip.rs +11 -0
  126. package/packages/rust/cronixui/src/lib.rs +111 -64
  127. package/packages/rust/cronixui/src/tokens.rs +97 -127
  128. package/packages/web/src/variables.css +81 -81
  129. package/packages/go/cronixui/tokens.go +0 -129
  130. package/packages/python/cronixui/pyproject.toml +0 -11
  131. package/packages/react/src/components/Accordion.jsx +0 -50
  132. package/packages/react/src/components/Alert.jsx +0 -62
  133. package/packages/react/src/components/Avatar.jsx +0 -34
  134. package/packages/react/src/components/Badge.jsx +0 -15
  135. package/packages/react/src/components/Breadcrumb.jsx +0 -27
  136. package/packages/react/src/components/Button.jsx +0 -21
  137. package/packages/react/src/components/Card.jsx +0 -23
  138. package/packages/react/src/components/Checkbox.jsx +0 -27
  139. package/packages/react/src/components/CommandPalette.jsx +0 -93
  140. package/packages/react/src/components/Dropdown.jsx +0 -48
  141. package/packages/react/src/components/FileInput.jsx +0 -44
  142. package/packages/react/src/components/Input.jsx +0 -22
  143. package/packages/react/src/components/List.jsx +0 -29
  144. package/packages/react/src/components/Modal.jsx +0 -65
  145. package/packages/react/src/components/Nav.jsx +0 -50
  146. package/packages/react/src/components/Pagination.jsx +0 -81
  147. package/packages/react/src/components/Progress.jsx +0 -23
  148. package/packages/react/src/components/Radio.jsx +0 -50
  149. package/packages/react/src/components/Search.jsx +0 -70
  150. package/packages/react/src/components/Select.jsx +0 -33
  151. package/packages/react/src/components/Skeleton.jsx +0 -15
  152. package/packages/react/src/components/Slider.jsx +0 -29
  153. package/packages/react/src/components/Spinner.jsx +0 -5
  154. package/packages/react/src/components/Stat.jsx +0 -19
  155. package/packages/react/src/components/Table.jsx +0 -48
  156. package/packages/react/src/components/Tabs.jsx +0 -65
  157. package/packages/react/src/components/Tag.jsx +0 -19
  158. package/packages/react/src/components/Textarea.jsx +0 -17
  159. package/packages/react/src/components/Toast.jsx +0 -78
  160. package/packages/react/src/components/Toggle.jsx +0 -34
  161. package/packages/react/src/components/Tooltip.jsx +0 -12
  162. package/packages/react/src/index.d.ts +0 -103
  163. package/packages/react/src/index.js +0 -33
  164. package/packages/rust/cronixui/src/accordion.rs +0 -49
  165. package/packages/rust/cronixui/src/command_palette.rs +0 -62
  166. package/packages/rust/cronixui/src/dropdown.rs +0 -31
  167. package/packages/rust/cronixui/src/search.rs +0 -49
  168. package/packages/rust/cronixui/src/tabs.rs +0 -23
  169. package/packages/rust/cronixui/src/toast.rs +0 -70
@@ -1,48 +0,0 @@
1
- import { useState, useEffect, useRef } from 'react';
2
-
3
- export default function Dropdown({
4
- trigger,
5
- children,
6
- className = ''
7
- }) {
8
- const [isOpen, setIsOpen] = useState(false);
9
- const dropdownRef = useRef(null);
10
-
11
- const toggle = () => setIsOpen((prev) => !prev);
12
- const close = () => setIsOpen(false);
13
-
14
- useEffect(() => {
15
- const handleClickOutside = (e) => {
16
- if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
17
- close();
18
- }
19
- };
20
-
21
- if (isOpen) {
22
- document.addEventListener('click', handleClickOutside);
23
- }
24
-
25
- return () => {
26
- document.removeEventListener('click', handleClickOutside);
27
- };
28
- }, [isOpen]);
29
-
30
- return (
31
- <div ref={dropdownRef} className={`cn-dropdown ${isOpen ? 'cn-dropdown-open' : ''} ${className}`}>
32
- <div className="cn-dropdown-trigger" onClick={toggle}>
33
- {trigger}
34
- </div>
35
- <div className="cn-dropdown-menu" onClick={close}>
36
- {children}
37
- </div>
38
- </div>
39
- );
40
- }
41
-
42
- export function DropdownItem({ children, onClick, className = '', ...props }) {
43
- return (
44
- <div className={`cn-dropdown-item ${className}`} onClick={onClick} {...props}>
45
- {children}
46
- </div>
47
- );
48
- }
@@ -1,44 +0,0 @@
1
- import { useState, useRef } from 'react';
2
-
3
- export default function FileInput({
4
- onFileSelect,
5
- accept,
6
- multiple = false,
7
- label = 'Drag and drop files here, or click to browse',
8
- className = ''
9
- }) {
10
- const [fileName, setFileName] = useState('');
11
- const inputRef = useRef(null);
12
-
13
- const handleChange = (e) => {
14
- const files = Array.from(e.target.files);
15
- if (files.length > 0) {
16
- setFileName(files.map(f => f.name).join(', '));
17
- onFileSelect?.(multiple ? files : files[0]);
18
- }
19
- };
20
-
21
- return (
22
- <div className={`cn-file-input ${fileName ? 'cn-file-input-has-file' : ''} ${className}`}>
23
- <input
24
- ref={inputRef}
25
- type="file"
26
- accept={accept}
27
- multiple={multiple}
28
- onChange={handleChange}
29
- />
30
- <div className="cn-file-input-label">
31
- <div className="cn-file-input-icon">
32
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
33
- <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
34
- <polyline points="17 8 12 3 7 8"></polyline>
35
- <line x1="12" y1="3" x2="12" y2="15"></line>
36
- </svg>
37
- </div>
38
- <div className="cn-file-input-text">
39
- {fileName ? <span>{fileName}</span> : label}
40
- </div>
41
- </div>
42
- </div>
43
- );
44
- }
@@ -1,22 +0,0 @@
1
- import { forwardRef } from 'react';
2
-
3
- const Input = forwardRef(function Input({
4
- type = 'text',
5
- size = 'md',
6
- error = false,
7
- className = '',
8
- ...props
9
- }, ref) {
10
- const sizeClass = size !== 'md' ? `cn-input-${size}` : '';
11
-
12
- return (
13
- <input
14
- ref={ref}
15
- type={type}
16
- className={`cn-input ${sizeClass} ${error ? 'cn-input-error' : ''} ${className}`}
17
- {...props}
18
- />
19
- );
20
- });
21
-
22
- export default Input;
@@ -1,29 +0,0 @@
1
- export function List({ children, className = '' }) {
2
- return <div className={`cn-list ${className}`}>{children}</div>;
3
- }
4
-
5
- export function ListItem({
6
- children,
7
- icon,
8
- title,
9
- subtitle,
10
- actions,
11
- clickable = false,
12
- onClick,
13
- className = ''
14
- }) {
15
- return (
16
- <div
17
- className={`cn-list-item ${clickable ? 'cn-list-item-clickable' : ''} ${className}`}
18
- onClick={onClick}
19
- >
20
- {icon && <div className="cn-list-item-icon">{icon}</div>}
21
- <div className="cn-list-item-content">
22
- {title && <div className="cn-list-item-title">{title}</div>}
23
- {subtitle && <div className="cn-list-item-subtitle">{subtitle}</div>}
24
- {children}
25
- </div>
26
- {actions && <div className="cn-list-item-actions">{actions}</div>}
27
- </div>
28
- );
29
- }
@@ -1,65 +0,0 @@
1
- import { useEffect, useRef } from 'react';
2
-
3
- export default function Modal({
4
- isOpen = false,
5
- onClose,
6
- children,
7
- className = ''
8
- }) {
9
- const modalRef = useRef(null);
10
-
11
- useEffect(() => {
12
- const handleEscape = (e) => {
13
- if (e.key === 'Escape' && onClose) {
14
- onClose();
15
- }
16
- };
17
-
18
- if (isOpen) {
19
- document.addEventListener('keydown', handleEscape);
20
- document.body.style.overflow = 'hidden';
21
- }
22
-
23
- return () => {
24
- document.removeEventListener('keydown', handleEscape);
25
- document.body.style.overflow = '';
26
- };
27
- }, [isOpen, onClose]);
28
-
29
- if (!isOpen) return null;
30
-
31
- return (
32
- <div
33
- className={`cn-modal-backdrop cn-modal-open ${className}`}
34
- onClick={(e) => e.target === e.currentTarget && onClose?.()}
35
- >
36
- <div className="cn-modal" ref={modalRef}>
37
- {children}
38
- </div>
39
- </div>
40
- );
41
- }
42
-
43
- Modal.Header = function ModalHeader({ children, onClose, className = '' }) {
44
- return (
45
- <div className={`cn-modal-header ${className}`}>
46
- <div className="cn-modal-title">{children}</div>
47
- {onClose && (
48
- <button className="cn-modal-close" onClick={onClose}>
49
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
50
- <line x1="18" y1="6" x2="6" y2="18"></line>
51
- <line x1="6" y1="6" x2="18" y2="18"></line>
52
- </svg>
53
- </button>
54
- )}
55
- </div>
56
- );
57
- };
58
-
59
- Modal.Body = function ModalBody({ children, className = '' }) {
60
- return <div className={`cn-modal-body ${className}`}>{children}</div>;
61
- };
62
-
63
- Modal.Footer = function ModalFooter({ children, className = '' }) {
64
- return <div className={`cn-modal-footer ${className}`}>{children}</div>;
65
- };
@@ -1,50 +0,0 @@
1
- import { useState } from 'react';
2
-
3
- export default function Nav({
4
- defaultActive,
5
- active: controlledActive,
6
- onChange,
7
- children,
8
- className = ''
9
- }) {
10
- const [internalActive, setInternalActive] = useState(defaultActive);
11
- const activeItem = controlledActive !== undefined ? controlledActive : internalActive;
12
-
13
- const handleClick = (item) => {
14
- if (onChange) {
15
- onChange(item);
16
- } else {
17
- setInternalActive(item);
18
- }
19
- };
20
-
21
- return (
22
- <nav className={`cn-nav ${className}`}>
23
- {children.map((child, idx) => {
24
- const isActive = child.props.active !== undefined
25
- ? child.props.active
26
- : child.props.id === activeItem;
27
-
28
- return {
29
- ...child,
30
- props: {
31
- ...child.props,
32
- active: isActive,
33
- onClick: () => handleClick(child.props.id),
34
- }
35
- };
36
- })}
37
- </nav>
38
- );
39
- }
40
-
41
- export function NavItem({ children, active = false, onClick, className = '' }) {
42
- return (
43
- <div
44
- className={`cn-nav-item ${active ? 'cn-nav-active' : ''} ${className}`}
45
- onClick={onClick}
46
- >
47
- {children}
48
- </div>
49
- );
50
- }
@@ -1,81 +0,0 @@
1
- import { useState } from 'react';
2
-
3
- export default function Pagination({
4
- total,
5
- current = 1,
6
- onChange,
7
- className = ''
8
- }) {
9
- const [page, setPage] = useState(current);
10
-
11
- const activePage = onChange !== undefined ? current : page;
12
-
13
- const getPages = () => {
14
- const pages = [];
15
- const maxVisible = 5;
16
-
17
- if (total <= maxVisible) {
18
- for (let i = 1; i <= total; i++) pages.push(i);
19
- } else {
20
- if (activePage <= 3) {
21
- for (let i = 1; i <= 4; i++) pages.push(i);
22
- pages.push('...');
23
- pages.push(total);
24
- } else if (activePage >= total - 2) {
25
- pages.push(1);
26
- pages.push('...');
27
- for (let i = total - 3; i <= total; i++) pages.push(i);
28
- } else {
29
- pages.push(1);
30
- pages.push('...');
31
- for (let i = activePage - 1; i <= activePage + 1; i++) pages.push(i);
32
- pages.push('...');
33
- pages.push(total);
34
- }
35
- }
36
-
37
- return pages;
38
- };
39
-
40
- const goTo = (p) => {
41
- if (p < 1 || p > total || p === activePage) return;
42
- if (onChange) {
43
- onChange(p);
44
- } else {
45
- setPage(p);
46
- }
47
- };
48
-
49
- return (
50
- <div className={`cn-pagination ${className}`}>
51
- <button
52
- className="cn-pagination-item"
53
- onClick={() => goTo(activePage - 1)}
54
- disabled={activePage === 1}
55
- >
56
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" width="16" height="16">
57
- <polyline points="15 18 9 12 15 6"></polyline>
58
- </svg>
59
- </button>
60
- {getPages().map((p, idx) => (
61
- <button
62
- key={idx}
63
- className={`cn-pagination-item ${p === activePage ? 'cn-pagination-active' : ''}`}
64
- onClick={() => typeof p === 'number' && goTo(p)}
65
- disabled={p === '...'}
66
- >
67
- {p}
68
- </button>
69
- ))}
70
- <button
71
- className="cn-pagination-item"
72
- onClick={() => goTo(activePage + 1)}
73
- disabled={activePage === total}
74
- >
75
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" width="16" height="16">
76
- <polyline points="9 18 15 12 9 6"></polyline>
77
- </svg>
78
- </button>
79
- </div>
80
- );
81
- }
@@ -1,23 +0,0 @@
1
- export default function Progress({
2
- value = 0,
3
- max = 100,
4
- showLabel = false,
5
- variant = 'default',
6
- size = 'md',
7
- className = ''
8
- }) {
9
- const percentage = Math.min(Math.max((value / max) * 100, 0), 100);
10
-
11
- return (
12
- <div className={className}>
13
- {showLabel && (
14
- <div className="cn-progress-label">
15
- <span>{percentage.toFixed(0)}%</span>
16
- </div>
17
- )}
18
- <div className={`cn-progress ${size !== 'md' ? `cn-progress-${size}` : ''} ${variant !== 'default' ? `cn-progress-${variant}` : ''}`}>
19
- <div className="cn-progress-bar" style={{ width: `${percentage}%` }}></div>
20
- </div>
21
- </div>
22
- );
23
- }
@@ -1,50 +0,0 @@
1
- import { forwardRef } from 'react';
2
-
3
- const Radio = forwardRef(function Radio({
4
- checked = false,
5
- onChange,
6
- disabled = false,
7
- children,
8
- name,
9
- className = '',
10
- ...props
11
- }, ref) {
12
- return (
13
- <label className={`cn-radio ${disabled ? 'disabled' : ''} ${className}`}>
14
- <input
15
- ref={ref}
16
- type="radio"
17
- checked={checked}
18
- onChange={(e) => onChange?.(e.target.checked)}
19
- disabled={disabled}
20
- name={name}
21
- {...props}
22
- />
23
- <span className="cn-radio-box"></span>
24
- {children && <span className="cn-radio-label">{children}</span>}
25
- </label>
26
- );
27
- });
28
-
29
- export function RadioGroup({ children, name, value, onChange, className = '' }) {
30
- return (
31
- <div className={className} role="radiogroup">
32
- {children.map((child, idx) => {
33
- if (child.type?.displayName === 'Radio') {
34
- return {
35
- ...child,
36
- props: {
37
- ...child.props,
38
- name,
39
- checked: child.props.value === value,
40
- onChange: () => onChange?.(child.props.value),
41
- }
42
- };
43
- }
44
- return child;
45
- })}
46
- </div>
47
- );
48
- }
49
-
50
- export default Radio;
@@ -1,70 +0,0 @@
1
- import { useState, useEffect, useRef } from 'react';
2
-
3
- export default function Search({
4
- items = [],
5
- placeholder = 'Search...',
6
- onSelect,
7
- className = ''
8
- }) {
9
- const [query, setQuery] = useState('');
10
- const [isOpen, setIsOpen] = useState(false);
11
- const ref = useRef(null);
12
-
13
- const filtered = items.filter(item =>
14
- item.title.toLowerCase().includes(query.toLowerCase()) ||
15
- (item.subtitle && item.subtitle.toLowerCase().includes(query.toLowerCase()))
16
- );
17
-
18
- useEffect(() => {
19
- const handleClickOutside = (e) => {
20
- if (ref.current && !ref.current.contains(e.target)) {
21
- setIsOpen(false);
22
- }
23
- };
24
-
25
- document.addEventListener('click', handleClickOutside);
26
- return () => document.removeEventListener('click', handleClickOutside);
27
- }, []);
28
-
29
- const handleSelect = (item) => {
30
- setQuery(item.title);
31
- setIsOpen(false);
32
- onSelect?.(item);
33
- };
34
-
35
- return (
36
- <div ref={ref} className={`cn-search ${isOpen ? 'cn-search-open' : ''} ${className}`}>
37
- <svg className="cn-search-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
38
- <circle cx="11" cy="11" r="8"></circle>
39
- <line x1="21" y1="21" x2="16.65" y2="16.65"></line>
40
- </svg>
41
- <input
42
- type="text"
43
- className="cn-input cn-search-input"
44
- placeholder={placeholder}
45
- value={query}
46
- onChange={(e) => {
47
- setQuery(e.target.value);
48
- setIsOpen(true);
49
- }}
50
- onFocus={() => setIsOpen(true)}
51
- />
52
- {isOpen && filtered.length > 0 && (
53
- <div className="cn-search-results">
54
- {filtered.map((item, idx) => (
55
- <div
56
- key={idx}
57
- className="cn-search-result"
58
- onClick={() => handleSelect(item)}
59
- >
60
- <div className="cn-search-result-title">{item.title}</div>
61
- {item.subtitle && (
62
- <div className="cn-search-result-subtitle">{item.subtitle}</div>
63
- )}
64
- </div>
65
- ))}
66
- </div>
67
- )}
68
- </div>
69
- );
70
- }
@@ -1,33 +0,0 @@
1
- import { forwardRef } from 'react';
2
-
3
- const Select = forwardRef(function Select({
4
- options = [],
5
- value,
6
- onChange,
7
- placeholder = 'Select...',
8
- disabled = false,
9
- className = '',
10
- ...props
11
- }, ref) {
12
- return (
13
- <div className={`cn-select-wrapper ${className}`}>
14
- <select
15
- ref={ref}
16
- className="cn-select"
17
- value={value}
18
- onChange={(e) => onChange?.(e.target.value)}
19
- disabled={disabled}
20
- {...props}
21
- >
22
- {placeholder && <option value="" disabled>{placeholder}</option>}
23
- {options.map((opt, idx) => (
24
- <option key={idx} value={opt.value}>
25
- {opt.label}
26
- </option>
27
- ))}
28
- </select>
29
- </div>
30
- );
31
- });
32
-
33
- export default Select;
@@ -1,15 +0,0 @@
1
- export default function Skeleton({
2
- variant = 'text',
3
- width,
4
- height,
5
- className = ''
6
- }) {
7
- const variantClass = variant !== 'text' ? `cn-skeleton-${variant}` : 'cn-skeleton';
8
-
9
- const style = {
10
- width: width,
11
- height: height,
12
- };
13
-
14
- return <div className={`${variantClass} ${className}`} style={style}></div>;
15
- }
@@ -1,29 +0,0 @@
1
- import { forwardRef } from 'react';
2
-
3
- const Slider = forwardRef(function Slider({
4
- value = 0,
5
- min = 0,
6
- max = 100,
7
- step = 1,
8
- onChange,
9
- disabled = false,
10
- className = '',
11
- ...props
12
- }, ref) {
13
- return (
14
- <input
15
- ref={ref}
16
- type="range"
17
- className={`cn-slider ${className}`}
18
- value={value}
19
- min={min}
20
- max={max}
21
- step={step}
22
- onChange={(e) => onChange?.(Number(e.target.value))}
23
- disabled={disabled}
24
- {...props}
25
- />
26
- );
27
- });
28
-
29
- export default Slider;
@@ -1,5 +0,0 @@
1
- export default function Spinner({ size = 'md', className = '' }) {
2
- const sizeClass = size !== 'md' ? `cn-spinner-${size}` : '';
3
-
4
- return <div className={`cn-spinner ${sizeClass} ${className}`}></div>;
5
- }
@@ -1,19 +0,0 @@
1
- export default function Stat({
2
- value,
3
- label,
4
- delta,
5
- deltaType = 'up',
6
- className = ''
7
- }) {
8
- return (
9
- <div className={`cn-stat ${className}`}>
10
- <div className="cn-stat-value">{value}</div>
11
- {label && <div className="cn-stat-label">{label}</div>}
12
- {delta && (
13
- <div className={`cn-stat-delta cn-stat-delta-${deltaType}`}>
14
- {deltaType === 'up' ? '↑' : '↓'} {delta}
15
- </div>
16
- )}
17
- </div>
18
- );
19
- }
@@ -1,48 +0,0 @@
1
- import { forwardRef } from 'react';
2
-
3
- const Table = forwardRef(function Table({
4
- columns = [],
5
- data = [],
6
- sortable = false,
7
- onSort,
8
- className = ''
9
- }, ref) {
10
- const handleSort = (column) => {
11
- if (!sortable || !column.sortable) return;
12
- onSort?.(column.key);
13
- };
14
-
15
- return (
16
- <div className={`cn-table-wrapper ${sortable ? 'cn-table-sortable' : ''} ${className}`}>
17
- <table className="cn-table" ref={ref}>
18
- <thead>
19
- <tr>
20
- {columns.map((col, idx) => (
21
- <th
22
- key={idx}
23
- onClick={() => handleSort(col)}
24
- data-sort={col.key}
25
- >
26
- {col.header}
27
- {col.sortable && ' ↕'}
28
- </th>
29
- ))}
30
- </tr>
31
- </thead>
32
- <tbody>
33
- {data.map((row, idx) => (
34
- <tr key={idx}>
35
- {columns.map((col, colIdx) => (
36
- <td key={colIdx}>
37
- {col.render ? col.render(row) : row[col.key]}
38
- </td>
39
- ))}
40
- </tr>
41
- ))}
42
- </tbody>
43
- </table>
44
- </div>
45
- );
46
- });
47
-
48
- export default Table;