cronixui 1.1.2 → 1.1.3

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 (76) hide show
  1. package/README.md +1 -1
  2. package/package.json +71 -71
  3. package/packages/flutter/.qwen/settings.json +7 -0
  4. package/packages/flutter/pubspec.yaml +20 -20
  5. package/packages/go/cronixui/cronixui.go +926 -926
  6. package/packages/python/README.md +142 -0
  7. package/packages/python/cronixui/__init__.py +15 -6
  8. package/packages/python/cronixui/__pycache__/__init__.cpython-314.pyc +0 -0
  9. package/packages/python/cronixui/__pycache__/accordion.cpython-314.pyc +0 -0
  10. package/packages/python/cronixui/__pycache__/alert.cpython-314.pyc +0 -0
  11. package/packages/python/cronixui/__pycache__/avatar.cpython-314.pyc +0 -0
  12. package/packages/python/cronixui/__pycache__/badge.cpython-314.pyc +0 -0
  13. package/packages/python/cronixui/__pycache__/button.cpython-314.pyc +0 -0
  14. package/packages/python/cronixui/__pycache__/card.cpython-314.pyc +0 -0
  15. package/packages/python/cronixui/__pycache__/command_palette.cpython-314.pyc +0 -0
  16. package/packages/python/cronixui/__pycache__/core.cpython-314.pyc +0 -0
  17. package/packages/python/cronixui/__pycache__/dropdown.cpython-314.pyc +0 -0
  18. package/packages/python/cronixui/__pycache__/form.cpython-314.pyc +0 -0
  19. package/packages/python/cronixui/__pycache__/layout.cpython-314.pyc +0 -0
  20. package/packages/python/cronixui/__pycache__/list.cpython-314.pyc +0 -0
  21. package/packages/python/cronixui/__pycache__/loading.cpython-314.pyc +0 -0
  22. package/packages/python/cronixui/__pycache__/modal.cpython-314.pyc +0 -0
  23. package/packages/python/cronixui/__pycache__/nav.cpython-314.pyc +0 -0
  24. package/packages/python/cronixui/__pycache__/pagination.cpython-314.pyc +0 -0
  25. package/packages/python/cronixui/__pycache__/progress.cpython-314.pyc +0 -0
  26. package/packages/python/cronixui/__pycache__/search.cpython-314.pyc +0 -0
  27. package/packages/python/cronixui/__pycache__/table.cpython-314.pyc +0 -0
  28. package/packages/python/cronixui/__pycache__/tabs.cpython-314.pyc +0 -0
  29. package/packages/python/cronixui/__pycache__/toast.cpython-314.pyc +0 -0
  30. package/packages/python/cronixui/__pycache__/toggle.cpython-314.pyc +0 -0
  31. package/packages/python/cronixui/__pycache__/tokens.cpython-314.pyc +0 -0
  32. package/packages/python/cronixui/__pycache__/tooltip.cpython-314.pyc +0 -0
  33. package/packages/python/cronixui/alert.py +119 -36
  34. package/packages/python/cronixui/avatar.py +129 -22
  35. package/packages/python/cronixui/badge.py +161 -24
  36. package/packages/python/cronixui/button.py +96 -27
  37. package/packages/python/cronixui/card.py +206 -33
  38. package/packages/python/cronixui/core.py +212 -23
  39. package/packages/python/cronixui/form.py +552 -141
  40. package/packages/python/cronixui/layout.py +358 -96
  41. package/packages/python/cronixui/list.py +140 -37
  42. package/packages/python/cronixui/loading.py +107 -17
  43. package/packages/python/cronixui/progress.py +189 -47
  44. package/packages/python/cronixui/table.py +118 -31
  45. package/packages/python/cronixui/tooltip.py +117 -15
  46. package/packages/react/src/components/Accordion.tsx +82 -82
  47. package/packages/react/src/components/Button.tsx +47 -47
  48. package/packages/react/src/components/Card.tsx +69 -69
  49. package/packages/react/src/components/CommandPalette.tsx +131 -131
  50. package/packages/react/src/components/Dropdown.tsx +88 -88
  51. package/packages/react/src/components/FileInput.tsx +86 -86
  52. package/packages/react/src/components/FormGroup.tsx +36 -36
  53. package/packages/react/src/components/List.tsx +55 -55
  54. package/packages/react/src/components/Pagination.tsx +107 -107
  55. package/packages/react/src/components/Progress.tsx +49 -49
  56. package/packages/react/src/components/Search.tsx +95 -95
  57. package/packages/react/src/components/Sidebar.tsx +64 -64
  58. package/packages/react/src/components/Stack.tsx +69 -69
  59. package/packages/react/src/components/Table.tsx +90 -90
  60. package/packages/react/src/components/Toast.tsx +134 -134
  61. package/packages/react/src/components/Typography.tsx +66 -66
  62. package/packages/react/src/index.ts +40 -40
  63. package/packages/react/src/styles.css +2039 -2039
  64. package/packages/rust/cronixui/src/components/avatar.rs +85 -85
  65. package/packages/rust/cronixui/src/components/breadcrumb.rs +58 -58
  66. package/packages/rust/cronixui/src/components/card.rs +259 -259
  67. package/packages/rust/cronixui/src/components/command_palette.rs +254 -254
  68. package/packages/rust/cronixui/src/components/dropdown.rs +179 -179
  69. package/packages/rust/cronixui/src/components/file_input.rs +74 -74
  70. package/packages/rust/cronixui/src/components/mod.rs +51 -51
  71. package/packages/rust/cronixui/src/components/search.rs +185 -185
  72. package/packages/rust/cronixui/src/components/skeleton.rs +63 -63
  73. package/packages/rust/cronixui/src/components/table.rs +56 -56
  74. package/packages/rust/cronixui/src/lib.rs +128 -128
  75. package/packages/web/dist/cronixui.css +97 -93
  76. package/packages/web/dist/cronixui.min.css +1 -1
@@ -1,86 +1,86 @@
1
- import * as React from 'react';
2
-
3
- export interface FileInputProps {
4
- onFileSelect?: (file: File | File[]) => void;
5
- accept?: string;
6
- multiple?: boolean;
7
- label?: string;
8
- className?: string;
9
- }
10
-
11
- export const FileInput: React.FC<FileInputProps> = ({
12
- onFileSelect,
13
- accept,
14
- multiple = false,
15
- label = 'Drag and drop files here, or click to browse',
16
- className = '',
17
- }) => {
18
- const [fileName, setFileName] = React.useState('');
19
- const [isDragging, setIsDragging] = React.useState(false);
20
- const inputRef = React.useRef<HTMLInputElement>(null);
21
-
22
- const processFiles = React.useCallback((files: File[]) => {
23
- if (files.length > 0) {
24
- setFileName(files.map(f => f.name).join(', '));
25
- onFileSelect?.(multiple ? files : files[0]);
26
- }
27
- }, [multiple, onFileSelect]);
28
-
29
- const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
30
- const files = Array.from(e.target.files || []);
31
- processFiles(files);
32
- };
33
-
34
- const handleDragOver = (e: React.DragEvent<HTMLLabelElement>) => {
35
- e.preventDefault();
36
- e.stopPropagation();
37
- setIsDragging(true);
38
- };
39
-
40
- const handleDragLeave = (e: React.DragEvent<HTMLLabelElement>) => {
41
- e.preventDefault();
42
- e.stopPropagation();
43
- setIsDragging(false);
44
- };
45
-
46
- const handleDrop = (e: React.DragEvent<HTMLLabelElement>) => {
47
- e.preventDefault();
48
- e.stopPropagation();
49
- setIsDragging(false);
50
- const files = Array.from(e.dataTransfer.files);
51
- processFiles(files);
52
- };
53
-
54
- return (
55
- <div className={`cn-file-input ${fileName ? 'cn-file-input-has-file' : ''} ${isDragging ? 'cn-file-input-dragging' : ''} ${className}`.trim()}>
56
- <label
57
- className="cn-file-input-label"
58
- onDragOver={handleDragOver}
59
- onDragLeave={handleDragLeave}
60
- onDrop={handleDrop}
61
- >
62
- <input
63
- ref={inputRef}
64
- type="file"
65
- accept={accept}
66
- multiple={multiple}
67
- onChange={handleChange}
68
- />
69
- <div className="cn-file-input-icon">
70
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
71
- <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
72
- <polyline points="17 8 12 3 7 8" />
73
- <line x1="12" y1="3" x2="12" y2="15" />
74
- </svg>
75
- </div>
76
- <div className="cn-file-input-text">
77
- {fileName ? <span>{fileName}</span> : label}
78
- </div>
79
- </label>
80
- </div>
81
- );
82
- };
83
-
84
- FileInput.displayName = 'FileInput';
85
-
86
- export default FileInput;
1
+ import * as React from 'react';
2
+
3
+ export interface FileInputProps {
4
+ onFileSelect?: (file: File | File[]) => void;
5
+ accept?: string;
6
+ multiple?: boolean;
7
+ label?: string;
8
+ className?: string;
9
+ }
10
+
11
+ export const FileInput: React.FC<FileInputProps> = ({
12
+ onFileSelect,
13
+ accept,
14
+ multiple = false,
15
+ label = 'Drag and drop files here, or click to browse',
16
+ className = '',
17
+ }) => {
18
+ const [fileName, setFileName] = React.useState('');
19
+ const [isDragging, setIsDragging] = React.useState(false);
20
+ const inputRef = React.useRef<HTMLInputElement>(null);
21
+
22
+ const processFiles = React.useCallback((files: File[]) => {
23
+ if (files.length > 0) {
24
+ setFileName(files.map(f => f.name).join(', '));
25
+ onFileSelect?.(multiple ? files : files[0]);
26
+ }
27
+ }, [multiple, onFileSelect]);
28
+
29
+ const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
30
+ const files = Array.from(e.target.files || []);
31
+ processFiles(files);
32
+ };
33
+
34
+ const handleDragOver = (e: React.DragEvent<HTMLLabelElement>) => {
35
+ e.preventDefault();
36
+ e.stopPropagation();
37
+ setIsDragging(true);
38
+ };
39
+
40
+ const handleDragLeave = (e: React.DragEvent<HTMLLabelElement>) => {
41
+ e.preventDefault();
42
+ e.stopPropagation();
43
+ setIsDragging(false);
44
+ };
45
+
46
+ const handleDrop = (e: React.DragEvent<HTMLLabelElement>) => {
47
+ e.preventDefault();
48
+ e.stopPropagation();
49
+ setIsDragging(false);
50
+ const files = Array.from(e.dataTransfer.files);
51
+ processFiles(files);
52
+ };
53
+
54
+ return (
55
+ <div className={`cn-file-input ${fileName ? 'cn-file-input-has-file' : ''} ${isDragging ? 'cn-file-input-dragging' : ''} ${className}`.trim()}>
56
+ <label
57
+ className="cn-file-input-label"
58
+ onDragOver={handleDragOver}
59
+ onDragLeave={handleDragLeave}
60
+ onDrop={handleDrop}
61
+ >
62
+ <input
63
+ ref={inputRef}
64
+ type="file"
65
+ accept={accept}
66
+ multiple={multiple}
67
+ onChange={handleChange}
68
+ />
69
+ <div className="cn-file-input-icon">
70
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
71
+ <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
72
+ <polyline points="17 8 12 3 7 8" />
73
+ <line x1="12" y1="3" x2="12" y2="15" />
74
+ </svg>
75
+ </div>
76
+ <div className="cn-file-input-text">
77
+ {fileName ? <span>{fileName}</span> : label}
78
+ </div>
79
+ </label>
80
+ </div>
81
+ );
82
+ };
83
+
84
+ FileInput.displayName = 'FileInput';
85
+
86
+ export default FileInput;
@@ -1,36 +1,36 @@
1
- import * as React from 'react';
2
-
3
- export interface FormGroupProps extends React.HTMLAttributes<HTMLDivElement> {
4
- label?: React.ReactNode;
5
- error?: React.ReactNode;
6
- help?: React.ReactNode;
7
- required?: boolean;
8
- }
9
-
10
- export const FormGroup: React.FC<FormGroupProps> = ({
11
- children,
12
- label,
13
- error,
14
- help,
15
- required = false,
16
- className = '',
17
- ...props
18
- }) => {
19
- return (
20
- <div className={`cn-form-group ${className}`.trim()} {...props}>
21
- {label && (
22
- <label className="cn-form-label">
23
- {label}
24
- {required && <span style={{ color: 'var(--cn-error-text)', marginLeft: 'var(--cn-space-1)' }}>*</span>}
25
- </label>
26
- )}
27
- {children}
28
- {error && <div className="cn-form-error">{error}</div>}
29
- {!error && help && <div className="cn-form-help">{help}</div>}
30
- </div>
31
- );
32
- };
33
-
34
- FormGroup.displayName = 'FormGroup';
35
-
36
- export default FormGroup;
1
+ import * as React from 'react';
2
+
3
+ export interface FormGroupProps extends React.HTMLAttributes<HTMLDivElement> {
4
+ label?: React.ReactNode;
5
+ error?: React.ReactNode;
6
+ help?: React.ReactNode;
7
+ required?: boolean;
8
+ }
9
+
10
+ export const FormGroup: React.FC<FormGroupProps> = ({
11
+ children,
12
+ label,
13
+ error,
14
+ help,
15
+ required = false,
16
+ className = '',
17
+ ...props
18
+ }) => {
19
+ return (
20
+ <div className={`cn-form-group ${className}`.trim()} {...props}>
21
+ {label && (
22
+ <label className="cn-form-label">
23
+ {label}
24
+ {required && <span style={{ color: 'var(--cn-error-text)', marginLeft: 'var(--cn-space-1)' }}>*</span>}
25
+ </label>
26
+ )}
27
+ {children}
28
+ {error && <div className="cn-form-error">{error}</div>}
29
+ {!error && help && <div className="cn-form-help">{help}</div>}
30
+ </div>
31
+ );
32
+ };
33
+
34
+ FormGroup.displayName = 'FormGroup';
35
+
36
+ export default FormGroup;
@@ -1,55 +1,55 @@
1
- import * as React from 'react';
2
-
3
- export interface ListProps extends React.HTMLAttributes<HTMLDivElement> {}
4
-
5
- export interface ListItemProps extends React.HTMLAttributes<HTMLDivElement> {
6
- icon?: React.ReactNode;
7
- title?: string;
8
- subtitle?: string;
9
- actions?: React.ReactNode;
10
- clickable?: boolean;
11
- }
12
-
13
- export const List: React.FC<ListProps> = ({ children, className = '', ...props }) => {
14
- return (
15
- <div className={`cn-list ${className}`.trim()} role="list" {...props}>
16
- {children}
17
- </div>
18
- );
19
- };
20
-
21
- List.displayName = 'List';
22
-
23
- export const ListItem: React.FC<ListItemProps> = ({
24
- children,
25
- icon,
26
- title,
27
- subtitle,
28
- actions,
29
- clickable = false,
30
- onClick,
31
- className = '',
32
- ...props
33
- }) => {
34
- return (
35
- <div
36
- className={`cn-list-item ${clickable ? 'cn-list-item-clickable' : ''} ${className}`.trim()}
37
- onClick={onClick}
38
- role={clickable ? 'button' : 'listitem'}
39
- tabIndex={clickable ? 0 : undefined}
40
- {...props}
41
- >
42
- {icon && <div className="cn-list-item-icon">{icon}</div>}
43
- <div className="cn-list-item-content">
44
- {title && <div className="cn-list-item-title">{title}</div>}
45
- {subtitle && <div className="cn-list-item-subtitle">{subtitle}</div>}
46
- {children}
47
- </div>
48
- {actions && <div className="cn-list-item-actions">{actions}</div>}
49
- </div>
50
- );
51
- };
52
-
53
- ListItem.displayName = 'ListItem';
54
-
55
- export default List;
1
+ import * as React from 'react';
2
+
3
+ export interface ListProps extends React.HTMLAttributes<HTMLDivElement> {}
4
+
5
+ export interface ListItemProps extends React.HTMLAttributes<HTMLDivElement> {
6
+ icon?: React.ReactNode;
7
+ title?: string;
8
+ subtitle?: string;
9
+ actions?: React.ReactNode;
10
+ clickable?: boolean;
11
+ }
12
+
13
+ export const List: React.FC<ListProps> = ({ children, className = '', ...props }) => {
14
+ return (
15
+ <div className={`cn-list ${className}`.trim()} role="list" {...props}>
16
+ {children}
17
+ </div>
18
+ );
19
+ };
20
+
21
+ List.displayName = 'List';
22
+
23
+ export const ListItem: React.FC<ListItemProps> = ({
24
+ children,
25
+ icon,
26
+ title,
27
+ subtitle,
28
+ actions,
29
+ clickable = false,
30
+ onClick,
31
+ className = '',
32
+ ...props
33
+ }) => {
34
+ return (
35
+ <div
36
+ className={`cn-list-item ${clickable ? 'cn-list-item-clickable' : ''} ${className}`.trim()}
37
+ onClick={onClick}
38
+ role={clickable ? 'button' : 'listitem'}
39
+ tabIndex={clickable ? 0 : undefined}
40
+ {...props}
41
+ >
42
+ {icon && <div className="cn-list-item-icon">{icon}</div>}
43
+ <div className="cn-list-item-content">
44
+ {title && <div className="cn-list-item-title">{title}</div>}
45
+ {subtitle && <div className="cn-list-item-subtitle">{subtitle}</div>}
46
+ {children}
47
+ </div>
48
+ {actions && <div className="cn-list-item-actions">{actions}</div>}
49
+ </div>
50
+ );
51
+ };
52
+
53
+ ListItem.displayName = 'ListItem';
54
+
55
+ export default List;
@@ -1,107 +1,107 @@
1
- import * as React from 'react';
2
-
3
- export interface PaginationProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {
4
- total: number;
5
- current?: number;
6
- onChange?: (page: number) => void;
7
- }
8
-
9
- export const Pagination: React.FC<PaginationProps> = ({
10
- total,
11
- current = 1,
12
- onChange,
13
- className = '',
14
- ...props
15
- }) => {
16
- const [page, setPage] = React.useState(current);
17
-
18
- const activePage = onChange !== undefined ? current : page;
19
-
20
- const getPages = (): (number | string)[] => {
21
- const pages: (number | string)[] = [];
22
- const maxVisible = 5;
23
-
24
- if (total <= maxVisible) {
25
- for (let i = 1; i <= total; i++) pages.push(i);
26
- } else {
27
- if (activePage <= 3) {
28
- for (let i = 1; i <= 4; i++) pages.push(i);
29
- pages.push('...');
30
- pages.push(total);
31
- } else if (activePage >= total - 2) {
32
- pages.push(1);
33
- pages.push('...');
34
- for (let i = total - 3; i <= total; i++) pages.push(i);
35
- } else {
36
- pages.push(1);
37
- pages.push('...');
38
- for (let i = activePage - 1; i <= activePage + 1; i++) pages.push(i);
39
- pages.push('...');
40
- pages.push(total);
41
- }
42
- }
43
-
44
- return pages;
45
- };
46
-
47
- const goTo = (p: number) => {
48
- if (p < 1 || p > total || p === activePage) return;
49
- if (onChange) {
50
- onChange(p);
51
- } else {
52
- setPage(p);
53
- }
54
- };
55
-
56
- return (
57
- <nav className={`cn-pagination ${className}`.trim()} aria-label="Pagination" {...props}>
58
- <button
59
- className="cn-pagination-item"
60
- onClick={() => goTo(activePage - 1)}
61
- disabled={activePage === 1}
62
- aria-label="Previous page"
63
- >
64
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" width="16" height="16">
65
- <polyline points="15 18 9 12 15 6" />
66
- </svg>
67
- </button>
68
- {getPages().map((p, idx) =>
69
- p === '...' ? (
70
- <button
71
- key={idx}
72
- className="cn-pagination-item cn-pagination-ellipsis"
73
- disabled
74
- aria-label="More pages"
75
- aria-hidden="true"
76
- tabIndex={-1}
77
- >
78
- {p}
79
- </button>
80
- ) : (
81
- <button
82
- key={idx}
83
- className={`cn-pagination-item ${p === activePage ? 'cn-pagination-active' : ''}`.trim()}
84
- onClick={() => goTo(p)}
85
- aria-current={p === activePage ? 'page' : undefined}
86
- >
87
- {p}
88
- </button>
89
- )
90
- )}
91
- <button
92
- className="cn-pagination-item"
93
- onClick={() => goTo(activePage + 1)}
94
- disabled={activePage === total}
95
- aria-label="Next page"
96
- >
97
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" width="16" height="16">
98
- <polyline points="9 18 15 12 9 6" />
99
- </svg>
100
- </button>
101
- </nav>
102
- );
103
- };
104
-
105
- Pagination.displayName = 'Pagination';
106
-
107
- export default Pagination;
1
+ import * as React from 'react';
2
+
3
+ export interface PaginationProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {
4
+ total: number;
5
+ current?: number;
6
+ onChange?: (page: number) => void;
7
+ }
8
+
9
+ export const Pagination: React.FC<PaginationProps> = ({
10
+ total,
11
+ current = 1,
12
+ onChange,
13
+ className = '',
14
+ ...props
15
+ }) => {
16
+ const [page, setPage] = React.useState(current);
17
+
18
+ const activePage = onChange !== undefined ? current : page;
19
+
20
+ const getPages = (): (number | string)[] => {
21
+ const pages: (number | string)[] = [];
22
+ const maxVisible = 5;
23
+
24
+ if (total <= maxVisible) {
25
+ for (let i = 1; i <= total; i++) pages.push(i);
26
+ } else {
27
+ if (activePage <= 3) {
28
+ for (let i = 1; i <= 4; i++) pages.push(i);
29
+ pages.push('...');
30
+ pages.push(total);
31
+ } else if (activePage >= total - 2) {
32
+ pages.push(1);
33
+ pages.push('...');
34
+ for (let i = total - 3; i <= total; i++) pages.push(i);
35
+ } else {
36
+ pages.push(1);
37
+ pages.push('...');
38
+ for (let i = activePage - 1; i <= activePage + 1; i++) pages.push(i);
39
+ pages.push('...');
40
+ pages.push(total);
41
+ }
42
+ }
43
+
44
+ return pages;
45
+ };
46
+
47
+ const goTo = (p: number) => {
48
+ if (p < 1 || p > total || p === activePage) return;
49
+ if (onChange) {
50
+ onChange(p);
51
+ } else {
52
+ setPage(p);
53
+ }
54
+ };
55
+
56
+ return (
57
+ <nav className={`cn-pagination ${className}`.trim()} aria-label="Pagination" {...props}>
58
+ <button
59
+ className="cn-pagination-item"
60
+ onClick={() => goTo(activePage - 1)}
61
+ disabled={activePage === 1}
62
+ aria-label="Previous page"
63
+ >
64
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" width="16" height="16">
65
+ <polyline points="15 18 9 12 15 6" />
66
+ </svg>
67
+ </button>
68
+ {getPages().map((p, idx) =>
69
+ p === '...' ? (
70
+ <button
71
+ key={idx}
72
+ className="cn-pagination-item cn-pagination-ellipsis"
73
+ disabled
74
+ aria-label="More pages"
75
+ aria-hidden="true"
76
+ tabIndex={-1}
77
+ >
78
+ {p}
79
+ </button>
80
+ ) : (
81
+ <button
82
+ key={idx}
83
+ className={`cn-pagination-item ${p === activePage ? 'cn-pagination-active' : ''}`.trim()}
84
+ onClick={() => goTo(p)}
85
+ aria-current={p === activePage ? 'page' : undefined}
86
+ >
87
+ {p}
88
+ </button>
89
+ )
90
+ )}
91
+ <button
92
+ className="cn-pagination-item"
93
+ onClick={() => goTo(activePage + 1)}
94
+ disabled={activePage === total}
95
+ aria-label="Next page"
96
+ >
97
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" width="16" height="16">
98
+ <polyline points="9 18 15 12 9 6" />
99
+ </svg>
100
+ </button>
101
+ </nav>
102
+ );
103
+ };
104
+
105
+ Pagination.displayName = 'Pagination';
106
+
107
+ export default Pagination;
@@ -1,49 +1,49 @@
1
- import * as React from 'react';
2
-
3
- export type ProgressVariant = 'default' | 'success' | 'warning' | 'error';
4
- export type ProgressSize = 'sm' | 'md' | 'lg';
5
-
6
- export interface ProgressProps extends React.HTMLAttributes<HTMLDivElement> {
7
- value?: number;
8
- max?: number;
9
- showLabel?: boolean;
10
- label?: string;
11
- variant?: ProgressVariant;
12
- size?: ProgressSize;
13
- }
14
-
15
- export const Progress: React.FC<ProgressProps> = ({
16
- value = 0,
17
- max = 100,
18
- showLabel = false,
19
- label,
20
- variant = 'default',
21
- size = 'md',
22
- className = '',
23
- ...props
24
- }) => {
25
- const percentage = Math.min(Math.max((value / max) * 100, 0), 100);
26
-
27
- return (
28
- <div className={className} {...props}>
29
- {showLabel && (
30
- <div className="cn-progress-label">
31
- <span>{label ?? `${percentage.toFixed(0)}%`}</span>
32
- </div>
33
- )}
34
- <div
35
- className={`cn-progress ${size !== 'md' ? `cn-progress-${size}` : ''} ${variant !== 'default' ? `cn-progress-${variant}` : ''}`.trim()}
36
- role="progressbar"
37
- aria-valuenow={percentage}
38
- aria-valuemin={0}
39
- aria-valuemax={100}
40
- >
41
- <div className="cn-progress-bar" style={{ width: `${percentage}%` }} />
42
- </div>
43
- </div>
44
- );
45
- };
46
-
47
- Progress.displayName = 'Progress';
48
-
49
- export default Progress;
1
+ import * as React from 'react';
2
+
3
+ export type ProgressVariant = 'default' | 'success' | 'warning' | 'error';
4
+ export type ProgressSize = 'sm' | 'md' | 'lg';
5
+
6
+ export interface ProgressProps extends React.HTMLAttributes<HTMLDivElement> {
7
+ value?: number;
8
+ max?: number;
9
+ showLabel?: boolean;
10
+ label?: string;
11
+ variant?: ProgressVariant;
12
+ size?: ProgressSize;
13
+ }
14
+
15
+ export const Progress: React.FC<ProgressProps> = ({
16
+ value = 0,
17
+ max = 100,
18
+ showLabel = false,
19
+ label,
20
+ variant = 'default',
21
+ size = 'md',
22
+ className = '',
23
+ ...props
24
+ }) => {
25
+ const percentage = Math.min(Math.max((value / max) * 100, 0), 100);
26
+
27
+ return (
28
+ <div className={className} {...props}>
29
+ {showLabel && (
30
+ <div className="cn-progress-label">
31
+ <span>{label ?? `${percentage.toFixed(0)}%`}</span>
32
+ </div>
33
+ )}
34
+ <div
35
+ className={`cn-progress ${size !== 'md' ? `cn-progress-${size}` : ''} ${variant !== 'default' ? `cn-progress-${variant}` : ''}`.trim()}
36
+ role="progressbar"
37
+ aria-valuenow={percentage}
38
+ aria-valuemin={0}
39
+ aria-valuemax={100}
40
+ >
41
+ <div className="cn-progress-bar" style={{ width: `${percentage}%` }} />
42
+ </div>
43
+ </div>
44
+ );
45
+ };
46
+
47
+ Progress.displayName = 'Progress';
48
+
49
+ export default Progress;