cronixui 1.0.0 → 1.0.2
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.
- package/LICENSE +674 -0
- package/README.md +582 -0
- package/package.json +10 -7
- package/packages/react/src/components/Accordion.jsx +50 -0
- package/packages/react/src/components/Alert.jsx +62 -0
- package/packages/react/src/components/Avatar.jsx +34 -0
- package/packages/react/src/components/Badge.jsx +15 -0
- package/packages/react/src/components/Breadcrumb.jsx +27 -0
- package/packages/react/src/components/Button.jsx +21 -0
- package/packages/react/src/components/Card.jsx +23 -0
- package/packages/react/src/components/Checkbox.jsx +27 -0
- package/packages/react/src/components/CommandPalette.jsx +93 -0
- package/packages/react/src/components/Dropdown.jsx +48 -0
- package/packages/react/src/components/FileInput.jsx +44 -0
- package/packages/react/src/components/Input.jsx +22 -0
- package/packages/react/src/components/List.jsx +29 -0
- package/packages/react/src/components/Modal.jsx +65 -0
- package/packages/react/src/components/Nav.jsx +50 -0
- package/packages/react/src/components/Pagination.jsx +81 -0
- package/packages/react/src/components/Progress.jsx +23 -0
- package/packages/react/src/components/Radio.jsx +50 -0
- package/packages/react/src/components/Search.jsx +70 -0
- package/packages/react/src/components/Select.jsx +33 -0
- package/packages/react/src/components/Skeleton.jsx +15 -0
- package/packages/react/src/components/Slider.jsx +29 -0
- package/packages/react/src/components/Spinner.jsx +5 -0
- package/packages/react/src/components/Stat.jsx +19 -0
- package/packages/react/src/components/Table.jsx +48 -0
- package/packages/react/src/components/Tabs.jsx +65 -0
- package/packages/react/src/components/Tag.jsx +19 -0
- package/packages/react/src/components/Textarea.jsx +17 -0
- package/packages/react/src/components/Toast.jsx +78 -0
- package/packages/react/src/components/Toggle.jsx +34 -0
- package/packages/react/src/components/Tooltip.jsx +12 -0
- package/packages/react/src/index.js +33 -0
- package/packages/win/CronixUI.WinUI/Controls/FlAvatar.cs +39 -0
- package/packages/win/CronixUI.WinUI/Controls/FlBadge.cs +21 -0
- package/packages/win/CronixUI.WinUI/Controls/FlButton.cs +30 -0
- package/packages/win/CronixUI.WinUI/Controls/FlCard.cs +21 -0
- package/packages/win/CronixUI.WinUI/Controls/FlCheckBox.cs +12 -0
- package/packages/win/CronixUI.WinUI/Controls/FlComboBox.cs +12 -0
- package/packages/win/CronixUI.WinUI/Controls/FlModal.cs +34 -0
- package/packages/win/CronixUI.WinUI/Controls/FlNavigation.cs +12 -0
- package/packages/win/CronixUI.WinUI/Controls/FlProgressBar.cs +21 -0
- package/packages/win/CronixUI.WinUI/Controls/FlRadioButton.cs +12 -0
- package/packages/win/CronixUI.WinUI/Controls/FlSlider.cs +12 -0
- package/packages/win/CronixUI.WinUI/Controls/FlSpinner.cs +21 -0
- package/packages/win/CronixUI.WinUI/Controls/FlTabs.cs +12 -0
- package/packages/win/CronixUI.WinUI/Controls/FlTextBox.cs +21 -0
- package/packages/win/CronixUI.WinUI/Controls/FlToggle.cs +12 -0
- package/packages/win/CronixUI.WinUI/Controls/FlTooltip.cs +21 -0
- package/packages/win/CronixUI.WinUI/CronixUI.WinUI.csproj +21 -0
- package/packages/win/CronixUI.WinUI/CronixUI.WinUI.sln +33 -0
- package/packages/win/CronixUI.WinUI/Themes/FlAvatar.xaml +39 -0
- package/packages/win/CronixUI.WinUI/Themes/FlBadge.xaml +30 -0
- package/packages/win/CronixUI.WinUI/Themes/FlButton.xaml +36 -0
- package/packages/win/CronixUI.WinUI/Themes/FlCard.xaml +28 -0
- package/packages/win/CronixUI.WinUI/Themes/FlCheckBox.xaml +45 -0
- package/packages/win/CronixUI.WinUI/Themes/FlComboBox.xaml +70 -0
- package/packages/win/CronixUI.WinUI/Themes/FlModal.xaml +47 -0
- package/packages/win/CronixUI.WinUI/Themes/FlProgressBar.xaml +27 -0
- package/packages/win/CronixUI.WinUI/Themes/FlRadioButton.xaml +42 -0
- package/packages/win/CronixUI.WinUI/Themes/FlSlider.xaml +38 -0
- package/packages/win/CronixUI.WinUI/Themes/FlSpinner.xaml +13 -0
- package/packages/win/CronixUI.WinUI/Themes/FlTextBox.xaml +39 -0
- package/packages/win/CronixUI.WinUI/Themes/FlToggle.xaml +45 -0
- package/packages/win/CronixUI.WinUI/Themes/FlTooltip.xaml +31 -0
- package/packages/win/CronixUI.WinUI/Themes/Generic.xaml +163 -0
- /package/{dist → packages/web/dist}/cronixui.css +0 -0
- /package/{dist → packages/web/dist}/cronixui.js +0 -0
- /package/{dist → packages/web/dist}/cronixui.min.css +0 -0
- /package/{dist → packages/web/dist}/cronixui.min.js +0 -0
- /package/{src → packages/web/src}/cronixui.css +0 -0
- /package/{src → packages/web/src}/cronixui.js +0 -0
- /package/{src → packages/web/src}/variables.css +0 -0
|
@@ -0,0 +1,50 @@
|
|
|
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;
|
|
@@ -0,0 +1,70 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
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;
|
|
@@ -0,0 +1,15 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
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;
|
|
@@ -0,0 +1,19 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
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;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
|
|
3
|
+
export default function Tabs({
|
|
4
|
+
defaultIndex = 0,
|
|
5
|
+
index: controlledIndex,
|
|
6
|
+
onChange,
|
|
7
|
+
children,
|
|
8
|
+
className = ''
|
|
9
|
+
}) {
|
|
10
|
+
const [internalIndex, setInternalIndex] = useState(defaultIndex);
|
|
11
|
+
const activeIndex = controlledIndex !== undefined ? controlledIndex : internalIndex;
|
|
12
|
+
|
|
13
|
+
const handleTabClick = (idx) => {
|
|
14
|
+
if (onChange) {
|
|
15
|
+
onChange(idx);
|
|
16
|
+
} else {
|
|
17
|
+
setInternalIndex(idx);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const tabs = [];
|
|
22
|
+
const panels = [];
|
|
23
|
+
|
|
24
|
+
children.forEach((child) => {
|
|
25
|
+
if (child.type?.displayName === 'Tab') {
|
|
26
|
+
tabs.push(child);
|
|
27
|
+
} else if (child.type?.displayName === 'TabPanel') {
|
|
28
|
+
panels.push(child);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<div className={className}>
|
|
34
|
+
<div className="cn-tabs">
|
|
35
|
+
{tabs.map((tab, idx) => (
|
|
36
|
+
<div
|
|
37
|
+
key={idx}
|
|
38
|
+
className={`cn-tab ${activeIndex === idx ? 'cn-tab-active' : ''}`}
|
|
39
|
+
onClick={() => handleTabClick(idx)}
|
|
40
|
+
>
|
|
41
|
+
{tab.props.children}
|
|
42
|
+
</div>
|
|
43
|
+
))}
|
|
44
|
+
</div>
|
|
45
|
+
{panels.map((panel, idx) => (
|
|
46
|
+
<div
|
|
47
|
+
key={idx}
|
|
48
|
+
className={`cn-tab-panel ${activeIndex === idx ? 'cn-tab-panel-active' : ''}`}
|
|
49
|
+
>
|
|
50
|
+
{panel.props.children}
|
|
51
|
+
</div>
|
|
52
|
+
))}
|
|
53
|
+
</div>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function Tab({ children }) {
|
|
58
|
+
return children;
|
|
59
|
+
}
|
|
60
|
+
Tab.displayName = 'Tab';
|
|
61
|
+
|
|
62
|
+
export function TabPanel({ children }) {
|
|
63
|
+
return children;
|
|
64
|
+
}
|
|
65
|
+
TabPanel.displayName = 'TabPanel';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export default function Tag({
|
|
2
|
+
children,
|
|
3
|
+
onRemove,
|
|
4
|
+
className = ''
|
|
5
|
+
}) {
|
|
6
|
+
return (
|
|
7
|
+
<div className={`cn-tag ${className}`}>
|
|
8
|
+
<span>{children}</span>
|
|
9
|
+
{onRemove && (
|
|
10
|
+
<button className="cn-tag-remove" onClick={onRemove}>
|
|
11
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
|
12
|
+
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
13
|
+
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
14
|
+
</svg>
|
|
15
|
+
</button>
|
|
16
|
+
)}
|
|
17
|
+
</div>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { forwardRef } from 'react';
|
|
2
|
+
|
|
3
|
+
const Textarea = forwardRef(function Textarea({
|
|
4
|
+
error = false,
|
|
5
|
+
className = '',
|
|
6
|
+
...props
|
|
7
|
+
}, ref) {
|
|
8
|
+
return (
|
|
9
|
+
<textarea
|
|
10
|
+
ref={ref}
|
|
11
|
+
className={`cn-input cn-textarea ${error ? 'cn-input-error' : ''} ${className}`}
|
|
12
|
+
{...props}
|
|
13
|
+
/>
|
|
14
|
+
);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
export default Textarea;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { useState, useEffect, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
function ToastContainer() {
|
|
4
|
+
return <div className="cn-toast-container" />;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function ToastItem({ toast, onRemove }) {
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
if (toast.duration > 0) {
|
|
10
|
+
const timer = setTimeout(() => onRemove(toast.id), toast.duration);
|
|
11
|
+
return () => clearTimeout(timer);
|
|
12
|
+
}
|
|
13
|
+
}, [toast.id, toast.duration, onRemove]);
|
|
14
|
+
|
|
15
|
+
const icons = {
|
|
16
|
+
success: '<polyline points="20 6 9 17 4 12"></polyline>',
|
|
17
|
+
error: '<circle cx="12" cy="12" r="10"></circle><line x1="15" y1="9" x2="9" y2="15"></line><line x1="9" y1="9" x2="15" y2="15"></line>',
|
|
18
|
+
warning: '<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path><line x1="12" y1="9" x2="12" y2="13"></line><line x1="12" y1="17" x2="12.01" y2="17"></line>',
|
|
19
|
+
info: '<circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line>'
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div className={`cn-toast cn-toast-${toast.type}`}>
|
|
24
|
+
<div className="cn-alert-icon">
|
|
25
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" dangerouslySetInnerHTML={{ __html: icons[toast.type] }} />
|
|
26
|
+
</div>
|
|
27
|
+
<div className="cn-alert-content">
|
|
28
|
+
{toast.title && <div className="cn-alert-title">{toast.title}</div>}
|
|
29
|
+
{toast.message && <div className="cn-alert-message">{toast.message}</div>}
|
|
30
|
+
</div>
|
|
31
|
+
{toast.closable && (
|
|
32
|
+
<button className="cn-alert-close" onClick={() => onRemove(toast.id)}>
|
|
33
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" width="16" height="16">
|
|
34
|
+
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
35
|
+
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
36
|
+
</svg>
|
|
37
|
+
</button>
|
|
38
|
+
)}
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export default function Toast({ toasts = [], onRemove }) {
|
|
44
|
+
return (
|
|
45
|
+
<div className="cn-toast-container">
|
|
46
|
+
{toasts.map((toast) => (
|
|
47
|
+
<ToastItem key={toast.id} toast={toast} onRemove={onRemove} />
|
|
48
|
+
))}
|
|
49
|
+
</div>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function useToast() {
|
|
54
|
+
const [toasts, setToasts] = useState([]);
|
|
55
|
+
const idRef = useRef(0);
|
|
56
|
+
|
|
57
|
+
const addToast = (options) => {
|
|
58
|
+
const id = ++idRef.current;
|
|
59
|
+
const toast = { id, duration: 4000, closable: true, type: 'info', ...options };
|
|
60
|
+
setToasts((prev) => [...prev, toast]);
|
|
61
|
+
return id;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const removeToast = (id) => {
|
|
65
|
+
setToasts((prev) => prev.filter((t) => t.id !== id));
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const toast = {
|
|
69
|
+
success: (message, title) => addToast({ message, title, type: 'success' }),
|
|
70
|
+
error: (message, title) => addToast({ message, title, type: 'error' }),
|
|
71
|
+
warning: (message, title) => addToast({ message, title, type: 'warning' }),
|
|
72
|
+
info: (message, title) => addToast({ message, title, type: 'info' }),
|
|
73
|
+
show: addToast,
|
|
74
|
+
remove: removeToast
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
return { toasts, toast, removeToast };
|
|
78
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
|
|
3
|
+
export default function Toggle({
|
|
4
|
+
on = false,
|
|
5
|
+
onChange,
|
|
6
|
+
disabled = false,
|
|
7
|
+
size = 'md',
|
|
8
|
+
className = '',
|
|
9
|
+
...props
|
|
10
|
+
}) {
|
|
11
|
+
const [internalOn, setInternalOn] = useState(on);
|
|
12
|
+
const isOn = onChange !== undefined ? on : internalOn;
|
|
13
|
+
|
|
14
|
+
const handleToggle = () => {
|
|
15
|
+
if (disabled) return;
|
|
16
|
+
if (onChange) {
|
|
17
|
+
onChange(!on);
|
|
18
|
+
} else {
|
|
19
|
+
setInternalOn(!internalOn);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const sizeClass = size === 'sm' ? 'cn-toggle-sm' : size === 'lg' ? 'cn-toggle-lg' : '';
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<div
|
|
27
|
+
className={`cn-toggle ${isOn ? 'on' : ''} ${sizeClass} ${disabled ? 'disabled' : ''} ${className}`}
|
|
28
|
+
onClick={handleToggle}
|
|
29
|
+
{...props}
|
|
30
|
+
>
|
|
31
|
+
<div className="cn-toggle-box"></div>
|
|
32
|
+
</div>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import 'CronixUI-web/dist/CronixUI.css';
|
|
2
|
+
|
|
3
|
+
export { default as Toggle } from './components/Toggle';
|
|
4
|
+
export { default as Button } from './components/Button';
|
|
5
|
+
export { default as Input } from './components/Input';
|
|
6
|
+
export { default as Textarea } from './components/Textarea';
|
|
7
|
+
export { default as Checkbox } from './components/Checkbox';
|
|
8
|
+
export { default as Radio, RadioGroup } from './components/Radio';
|
|
9
|
+
export { default as Select } from './components/Select';
|
|
10
|
+
export { default as Slider } from './components/Slider';
|
|
11
|
+
export { default as FileInput } from './components/FileInput';
|
|
12
|
+
export { default as Modal } from './components/Modal';
|
|
13
|
+
export { default as Alert } from './components/Alert';
|
|
14
|
+
export { default as Toast, useToast } from './components/Toast';
|
|
15
|
+
export { default as Tabs, Tab, TabPanel } from './components/Tabs';
|
|
16
|
+
export { default as Accordion, AccordionItem } from './components/Accordion';
|
|
17
|
+
export { default as Dropdown, DropdownItem } from './components/Dropdown';
|
|
18
|
+
export { default as Nav, NavItem } from './components/Nav';
|
|
19
|
+
export { default as Badge } from './components/Badge';
|
|
20
|
+
export { default as Tag } from './components/Tag';
|
|
21
|
+
export { default as Card } from './components/Card';
|
|
22
|
+
export { default as Avatar, AvatarGroup } from './components/Avatar';
|
|
23
|
+
export { default as Progress } from './components/Progress';
|
|
24
|
+
export { default as Spinner } from './components/Spinner';
|
|
25
|
+
export { default as Skeleton } from './components/Skeleton';
|
|
26
|
+
export { default as Tooltip } from './components/Tooltip';
|
|
27
|
+
export { default as Stat } from './components/Stat';
|
|
28
|
+
export { default as Pagination } from './components/Pagination';
|
|
29
|
+
export { default as Table } from './components/Table';
|
|
30
|
+
export { default as List, ListItem } from './components/List';
|
|
31
|
+
export { default as Breadcrumb, BreadcrumbItem } from './components/Breadcrumb';
|
|
32
|
+
export { default as Search } from './components/Search';
|
|
33
|
+
export { default as CommandPalette } from './components/CommandPalette';
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
using Microsoft.UI.Xaml;
|
|
2
|
+
using Microsoft.UI.Xaml.Controls;
|
|
3
|
+
|
|
4
|
+
namespace CronixUI.Controls;
|
|
5
|
+
|
|
6
|
+
public sealed class FlAvatar : Control
|
|
7
|
+
{
|
|
8
|
+
public FlAvatar()
|
|
9
|
+
{
|
|
10
|
+
DefaultStyleKey = typeof(FlAvatar);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
public static readonly DependencyProperty SourceProperty =
|
|
14
|
+
DependencyProperty.Register(nameof(Source), typeof(string), typeof(FlAvatar), new PropertyMetadata(string.Empty));
|
|
15
|
+
|
|
16
|
+
public string Source
|
|
17
|
+
{
|
|
18
|
+
get => (string)GetValue(SourceProperty);
|
|
19
|
+
set => SetValue(SourceProperty, value);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
public static readonly DependencyProperty InitialsProperty =
|
|
23
|
+
DependencyProperty.Register(nameof(Initials), typeof(string), typeof(FlAvatar), new PropertyMetadata(string.Empty));
|
|
24
|
+
|
|
25
|
+
public string Initials
|
|
26
|
+
{
|
|
27
|
+
get => (string)GetValue(InitialsProperty);
|
|
28
|
+
set => SetValue(InitialsProperty, value);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public static readonly DependencyProperty SizeProperty =
|
|
32
|
+
DependencyProperty.Register(nameof(Size), typeof(string), typeof(FlAvatar), new PropertyMetadata("md"));
|
|
33
|
+
|
|
34
|
+
public string Size
|
|
35
|
+
{
|
|
36
|
+
get => (string)GetValue(SizeProperty);
|
|
37
|
+
set => SetValue(SizeProperty, value);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
using Microsoft.UI.Xaml;
|
|
2
|
+
using Microsoft.UI.Xaml.Controls;
|
|
3
|
+
|
|
4
|
+
namespace CronixUI.Controls;
|
|
5
|
+
|
|
6
|
+
public sealed class FlBadge : ContentControl
|
|
7
|
+
{
|
|
8
|
+
public FlBadge()
|
|
9
|
+
{
|
|
10
|
+
DefaultStyleKey = typeof(FlBadge);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
public static readonly DependencyProperty VariantProperty =
|
|
14
|
+
DependencyProperty.Register(nameof(Variant), typeof(string), typeof(FlBadge), new PropertyMetadata("default"));
|
|
15
|
+
|
|
16
|
+
public string Variant
|
|
17
|
+
{
|
|
18
|
+
get => (string)GetValue(VariantProperty);
|
|
19
|
+
set => SetValue(VariantProperty, value);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
using Microsoft.UI.Xaml;
|
|
2
|
+
using Microsoft.UI.Xaml.Controls;
|
|
3
|
+
|
|
4
|
+
namespace CronixUI.Controls;
|
|
5
|
+
|
|
6
|
+
public sealed class FlButton : Button
|
|
7
|
+
{
|
|
8
|
+
public FlButton()
|
|
9
|
+
{
|
|
10
|
+
DefaultStyleKey = typeof(FlButton);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
public static readonly DependencyProperty VariantProperty =
|
|
14
|
+
DependencyProperty.Register(nameof(Variant), typeof(string), typeof(FlButton), new PropertyMetadata("default"));
|
|
15
|
+
|
|
16
|
+
public string Variant
|
|
17
|
+
{
|
|
18
|
+
get => (string)GetValue(VariantProperty);
|
|
19
|
+
set => SetValue(VariantProperty, value);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
public static readonly DependencyProperty SizeProperty =
|
|
23
|
+
DependencyProperty.Register(nameof(Size), typeof(string), typeof(FlButton), new PropertyMetadata("md"));
|
|
24
|
+
|
|
25
|
+
public string Size
|
|
26
|
+
{
|
|
27
|
+
get => (string)GetValue(SizeProperty);
|
|
28
|
+
set => SetValue(SizeProperty, value);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
using Microsoft.UI.Xaml;
|
|
2
|
+
using Microsoft.UI.Xaml.Controls;
|
|
3
|
+
|
|
4
|
+
namespace CronixUI.Controls;
|
|
5
|
+
|
|
6
|
+
public sealed class FlCard : ContentControl
|
|
7
|
+
{
|
|
8
|
+
public FlCard()
|
|
9
|
+
{
|
|
10
|
+
DefaultStyleKey = typeof(FlCard);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
public static readonly DependencyProperty HoverableProperty =
|
|
14
|
+
DependencyProperty.Register(nameof(Hoverable), typeof(bool), typeof(FlCard), new PropertyMetadata(false));
|
|
15
|
+
|
|
16
|
+
public bool Hoverable
|
|
17
|
+
{
|
|
18
|
+
get => (bool)GetValue(HoverableProperty);
|
|
19
|
+
set => SetValue(HoverableProperty, value);
|
|
20
|
+
}
|
|
21
|
+
}
|