cynx-ui 1.3.13 → 1.3.15

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.
@@ -1,171 +1,171 @@
1
- import CircularProgress from './CircularProgress';
2
-
3
- const BASE = {
4
- display: 'flex',
5
- alignItems: 'center',
6
- justifyContent: 'space-between',
7
- padding: '10px 14px',
8
- minHeight: 68,
9
- borderRadius: 'var(--rad,10px)',
10
- background: 'var(--surface,#fff)',
11
- border: '1px solid var(--border)',
12
- boxShadow: 'var(--shadow, 0 1px 3px rgba(0,0,0,.06), 0 1px 2px rgba(0,0,0,.04))',
13
- minWidth: 0,
14
- transition: 'border-color .15s',
15
- };
16
-
17
- const SIMPLE_BASE = {
18
- ...BASE,
19
- padding: '12px 14px',
20
- flexDirection: 'column',
21
- alignItems: 'flex-start',
22
- justifyContent: 'flex-start',
23
- };
24
-
25
- export default function StatsCard({
26
- variant = 'default',
27
- icon,
28
- iconColor = 'var(--blue)',
29
- iconBg = 'var(--infd, rgba(39,130,228,.1))',
30
- title,
31
- value,
32
- subtitle,
33
- percent,
34
- percentColor,
35
- progressSize = 'sm',
36
- progressTrackColor = 'var(--bd2, #e8e8ec)',
37
- headRight,
38
- className = '',
39
- style = {},
40
- children,
41
- }) {
42
- if (variant === 'simple') {
43
- return (
44
- <div className={className} style={{ ...SIMPLE_BASE, ...style }}>
45
- <div style={{
46
- width: '100%',
47
- marginBottom: 8,
48
- display: 'flex',
49
- alignItems: 'center',
50
- justifyContent: 'space-between',
51
- }}>
52
- {title && (
53
- <div style={{
54
- fontSize: '.58rem',
55
- fontWeight: 600,
56
- textTransform: 'uppercase',
57
- letterSpacing: '.08em',
58
- color: 'var(--muted,#9b9daa)',
59
- }}>{title}</div>
60
- )}
61
- {icon && (
62
- <div style={{
63
- display: 'inline-flex',
64
- alignItems: 'center',
65
- justifyContent: 'center',
66
- flexShrink: 0,
67
- color: iconColor,
68
- }}>
69
- {icon}
70
- </div>
71
- )}
72
- </div>
73
- {value !== undefined && (
74
- <div style={{
75
- fontSize: '1.25rem',
76
- fontWeight: 800,
77
- letterSpacing: '-.03em',
78
- lineHeight: 1.1,
79
- minHeight: '1.375em',
80
- }}>{value}</div>
81
- )}
82
- {children}
83
- </div>
84
- );
85
- }
86
-
87
- return (
88
- <div className={className} style={{ ...BASE, ...style }}>
89
- <div style={{
90
- display: 'flex',
91
- flexDirection: 'column',
92
- minWidth: 0,
93
- flex: 1,
94
- }}>
95
- <div style={{
96
- display: 'flex',
97
- alignItems: 'center',
98
- justifyContent: 'space-between',
99
- marginBottom: 8,
100
- }}>
101
- <div style={{
102
- display: 'flex',
103
- alignItems: 'center',
104
- gap: 6,
105
- }}>
106
- {icon && (
107
- <div style={{
108
- width: 24,
109
- height: 24,
110
- borderRadius: 6,
111
- display: 'inline-flex',
112
- alignItems: 'center',
113
- justifyContent: 'center',
114
- flexShrink: 0,
115
- background: iconBg,
116
- color: iconColor,
117
- }}>
118
- {icon}
119
- </div>
120
- )}
121
- {title && (
122
- <div style={{
123
- fontSize: '.58rem',
124
- fontWeight: 600,
125
- textTransform: 'uppercase',
126
- letterSpacing: '.08em',
127
- color: 'var(--muted,#9b9daa)',
128
- }}>{title}</div>
129
- )}
130
- </div>
131
- {headRight}
132
- </div>
133
- {value !== undefined && (
134
- <div style={{
135
- fontSize: '1.1rem',
136
- fontWeight: 800,
137
- letterSpacing: '-.02em',
138
- color: 'var(--primary-text,#0f111c)',
139
- lineHeight: 1.2,
140
- minHeight: '1.32em',
141
- }}>{value}</div>
142
- )}
143
- <div style={{
144
- fontSize: '.62rem',
145
- color: 'var(--muted,#9b9daa)',
146
- fontWeight: 500,
147
- marginTop: 1,
148
- minHeight: 14,
149
- }}>{subtitle || '\u00A0'}</div>
150
- {children}
151
- </div>
152
- <div style={{
153
- display: 'flex',
154
- alignItems: 'center',
155
- gap: 8,
156
- flexShrink: 0,
157
- }}>
158
- {percent !== undefined && (
159
- <CircularProgress
160
- value={percent}
161
- size={progressSize}
162
- color={percentColor}
163
- trackColor={progressTrackColor}
164
- showPercent
165
- rounded
166
- />
167
- )}
168
- </div>
169
- </div>
170
- );
171
- }
1
+ import CircularProgress from './CircularProgress';
2
+
3
+ const BASE = {
4
+ display: 'flex',
5
+ alignItems: 'center',
6
+ justifyContent: 'space-between',
7
+ padding: '10px 14px',
8
+ minHeight: 68,
9
+ borderRadius: 'var(--rad,10px)',
10
+ background: 'var(--surface,#fff)',
11
+ border: '1px solid var(--border)',
12
+ boxShadow: 'var(--shadow, 0 1px 3px rgba(0,0,0,.06), 0 1px 2px rgba(0,0,0,.04))',
13
+ minWidth: 0,
14
+ transition: 'border-color .15s',
15
+ };
16
+
17
+ const SIMPLE_BASE = {
18
+ ...BASE,
19
+ padding: '12px 14px',
20
+ flexDirection: 'column',
21
+ alignItems: 'flex-start',
22
+ justifyContent: 'flex-start',
23
+ };
24
+
25
+ export default function StatsCard({
26
+ variant = 'default',
27
+ icon,
28
+ iconColor = 'var(--blue)',
29
+ iconBg = 'var(--infd, rgba(39,130,228,.1))',
30
+ title,
31
+ value,
32
+ subtitle,
33
+ percent,
34
+ percentColor,
35
+ progressSize = 'sm',
36
+ progressTrackColor = 'var(--bd2, #e8e8ec)',
37
+ headRight,
38
+ className = '',
39
+ style = {},
40
+ children,
41
+ }) {
42
+ if (variant === 'simple') {
43
+ return (
44
+ <div className={className} style={{ ...SIMPLE_BASE, ...style }}>
45
+ <div style={{
46
+ width: '100%',
47
+ marginBottom: 8,
48
+ display: 'flex',
49
+ alignItems: 'center',
50
+ justifyContent: 'space-between',
51
+ }}>
52
+ {title && (
53
+ <div style={{
54
+ fontSize: '.58rem',
55
+ fontWeight: 600,
56
+ textTransform: 'uppercase',
57
+ letterSpacing: '.08em',
58
+ color: 'var(--muted,#9b9daa)',
59
+ }}>{title}</div>
60
+ )}
61
+ {icon && (
62
+ <div style={{
63
+ display: 'inline-flex',
64
+ alignItems: 'center',
65
+ justifyContent: 'center',
66
+ flexShrink: 0,
67
+ color: iconColor,
68
+ }}>
69
+ {icon}
70
+ </div>
71
+ )}
72
+ </div>
73
+ {value !== undefined && (
74
+ <div style={{
75
+ fontSize: '1.25rem',
76
+ fontWeight: 800,
77
+ letterSpacing: '-.03em',
78
+ lineHeight: 1.1,
79
+ minHeight: '1.375em',
80
+ }}>{value}</div>
81
+ )}
82
+ {children}
83
+ </div>
84
+ );
85
+ }
86
+
87
+ return (
88
+ <div className={className} style={{ ...BASE, ...style }}>
89
+ <div style={{
90
+ display: 'flex',
91
+ flexDirection: 'column',
92
+ minWidth: 0,
93
+ flex: 1,
94
+ }}>
95
+ <div style={{
96
+ display: 'flex',
97
+ alignItems: 'center',
98
+ justifyContent: 'space-between',
99
+ marginBottom: 8,
100
+ }}>
101
+ <div style={{
102
+ display: 'flex',
103
+ alignItems: 'center',
104
+ gap: 6,
105
+ }}>
106
+ {icon && (
107
+ <div style={{
108
+ width: 24,
109
+ height: 24,
110
+ borderRadius: 6,
111
+ display: 'inline-flex',
112
+ alignItems: 'center',
113
+ justifyContent: 'center',
114
+ flexShrink: 0,
115
+ background: iconBg,
116
+ color: iconColor,
117
+ }}>
118
+ {icon}
119
+ </div>
120
+ )}
121
+ {title && (
122
+ <div style={{
123
+ fontSize: '.58rem',
124
+ fontWeight: 600,
125
+ textTransform: 'uppercase',
126
+ letterSpacing: '.08em',
127
+ color: 'var(--muted,#9b9daa)',
128
+ }}>{title}</div>
129
+ )}
130
+ </div>
131
+ {headRight}
132
+ </div>
133
+ {value !== undefined && (
134
+ <div style={{
135
+ fontSize: '1.1rem',
136
+ fontWeight: 800,
137
+ letterSpacing: '-.02em',
138
+ color: 'var(--primary-text,#0f111c)',
139
+ lineHeight: 1.2,
140
+ minHeight: '1.32em',
141
+ }}>{value}</div>
142
+ )}
143
+ <div style={{
144
+ fontSize: '.62rem',
145
+ color: 'var(--muted,#9b9daa)',
146
+ fontWeight: 500,
147
+ marginTop: 1,
148
+ minHeight: 14,
149
+ }}>{subtitle || '\u00A0'}</div>
150
+ {children}
151
+ </div>
152
+ <div style={{
153
+ display: 'flex',
154
+ alignItems: 'center',
155
+ gap: 8,
156
+ flexShrink: 0,
157
+ }}>
158
+ {percent !== undefined && (
159
+ <CircularProgress
160
+ value={percent}
161
+ size={progressSize}
162
+ color={percentColor}
163
+ trackColor={progressTrackColor}
164
+ showPercent
165
+ rounded
166
+ />
167
+ )}
168
+ </div>
169
+ </div>
170
+ );
171
+ }
@@ -123,11 +123,12 @@ export default function TabBar({ tabs, active, onChange, capitalize = false, pad
123
123
  >
124
124
  {tabs.map(t => {
125
125
  const hasItems = Array.isArray(t.items) && t.items.length > 0;
126
- const activeSubItem = hasItems ? t.items.find(item => item.id === active) : null;
127
- const isActive = active === t.id || !!activeSubItem;
126
+ const activeSubItem = hasItems ? t.items.find(item => String(item.id) === String(active)) : null;
127
+ const isActive = (active != null && t.id != null && String(active) === String(t.id)) || !!activeSubItem;
128
128
  const isOpen = openDropdownId === t.id;
129
129
 
130
130
  const handleTabClick = () => {
131
+ if (t.disabled) return;
131
132
  if (hasItems) {
132
133
  setOpenDropdownId(isOpen ? null : t.id);
133
134
  } else {
@@ -142,6 +143,7 @@ export default function TabBar({ tabs, active, onChange, capitalize = false, pad
142
143
  type="button"
143
144
  data-tabid={t.id}
144
145
  data-active={isActive}
146
+ disabled={t.disabled}
145
147
  onClick={handleTabClick}
146
148
  style={{
147
149
  display: 'flex', alignItems: 'center', gap: 5,
@@ -150,10 +152,11 @@ export default function TabBar({ tabs, active, onChange, capitalize = false, pad
150
152
  border: 'none',
151
153
  borderRadius: 'var(--radxs, 6px)',
152
154
  background: isActive ? 'var(--surface,#fff)' : isOpen ? 'var(--grey-2, #e5e7eb)' : 'transparent',
153
- boxShadow: isActive ? 'var(--shadow, 0 1px 3px rgba(0,0,0,.08))' : 'none',
155
+ boxShadow: isActive ? '0 1px 3px rgba(0,0,0,.1), 0 1px 2px rgba(0,0,0,.06)' : 'none',
154
156
  fontSize: '.75rem', fontWeight: isActive ? 600 : 500,
155
157
  color: isActive ? 'var(--primary-text, #0f111c)' : 'var(--muted, #9b9daa)',
156
- cursor: 'pointer',
158
+ cursor: t.disabled ? 'not-allowed' : 'pointer',
159
+ opacity: t.disabled ? 0.38 : 1,
157
160
  transition: 'all .18s ease',
158
161
  fontFamily: 'inherit',
159
162
  whiteSpace: 'nowrap',
@@ -266,11 +269,12 @@ export default function TabBar({ tabs, active, onChange, capitalize = false, pad
266
269
 
267
270
  {tabs.map(t => {
268
271
  const hasItems = Array.isArray(t.items) && t.items.length > 0;
269
- const activeSubItem = hasItems ? t.items.find(item => item.id === active) : null;
270
- const isActive = active === t.id || !!activeSubItem;
272
+ const activeSubItem = hasItems ? t.items.find(item => String(item.id) === String(active)) : null;
273
+ const isActive = (active != null && t.id != null && String(active) === String(t.id)) || !!activeSubItem;
271
274
  const isOpen = openDropdownId === t.id;
272
275
 
273
276
  const handleTabClick = () => {
277
+ if (t.disabled) return;
274
278
  if (hasItems) {
275
279
  setOpenDropdownId(isOpen ? null : t.id);
276
280
  } else {
@@ -285,6 +289,7 @@ export default function TabBar({ tabs, active, onChange, capitalize = false, pad
285
289
  type="button"
286
290
  data-tabid={t.id}
287
291
  data-active={isActive}
292
+ disabled={t.disabled}
288
293
  onClick={handleTabClick}
289
294
  style={{
290
295
  display:'flex', alignItems:'center', gap:6,
@@ -292,7 +297,8 @@ export default function TabBar({ tabs, active, onChange, capitalize = false, pad
292
297
  border:'none', background:'none',
293
298
  fontSize:'.82rem', fontWeight:500,
294
299
  color: isActive ? 'var(--accent)' : 'var(--muted)',
295
- cursor:'pointer',
300
+ cursor: t.disabled ? 'not-allowed' : 'pointer',
301
+ opacity: t.disabled ? 0.38 : 1,
296
302
  transition:'color .18s',
297
303
  marginBottom:'-1px',
298
304
  position:'relative', zIndex:1,
@@ -1,29 +1,29 @@
1
- export function Tabs({ tabs, value, onChange, style }) {
2
- return (
3
- <div style={{ display: 'inline-flex', gap: 3, background: 'var(--grey-1, #f5f5f8)', borderRadius: 'var(--radxs, 6px)', padding: '3px', border: '1px solid var(--border-light, #ebebf0)', ...style }}>
4
- {tabs.map(t => {
5
- const label = typeof t === 'string' ? t : t.label;
6
- const key = typeof t === 'string' ? t : t.value;
7
- const active = key === value;
8
- return (
9
- <button key={key} onClick={() => onChange(key)} style={{
10
- display: 'flex', alignItems: 'center', gap: 5,
11
- padding: '5px 12px',
12
- border: 'none',
13
- borderRadius: 'var(--radxs, 6px)',
14
- background: active ? 'var(--surface,#fff)' : 'transparent',
15
- boxShadow: active ? 'var(--shadow, 0 1px 2px rgba(0,0,0,.06))' : 'none',
16
- fontSize: '.75rem', fontWeight: active ? 600 : 500,
17
- color: active ? 'var(--primary-text, #0f111c)' : 'var(--muted, #9b9daa)',
18
- cursor: 'pointer',
19
- transition: 'all .18s ease',
20
- fontFamily: 'inherit',
21
- whiteSpace: 'nowrap',
22
- }}>
23
- {label}
24
- </button>
25
- );
26
- })}
27
- </div>
28
- );
29
- }
1
+ export function Tabs({ tabs, value, onChange, style }) {
2
+ return (
3
+ <div style={{ display: 'inline-flex', gap: 3, background: 'var(--grey-1, #f5f5f8)', borderRadius: 'var(--radxs, 6px)', padding: '3px', border: '1px solid var(--border-light, #ebebf0)', ...style }}>
4
+ {tabs.map(t => {
5
+ const label = typeof t === 'string' ? t : t.label;
6
+ const key = typeof t === 'string' ? t : t.value;
7
+ const active = key === value;
8
+ return (
9
+ <button key={key} onClick={() => onChange(key)} style={{
10
+ display: 'flex', alignItems: 'center', gap: 5,
11
+ padding: '5px 12px',
12
+ border: 'none',
13
+ borderRadius: 'var(--radxs, 6px)',
14
+ background: active ? 'var(--surface,#fff)' : 'transparent',
15
+ boxShadow: active ? 'var(--shadow, 0 1px 2px rgba(0,0,0,.06))' : 'none',
16
+ fontSize: '.75rem', fontWeight: active ? 600 : 500,
17
+ color: active ? 'var(--primary-text, #0f111c)' : 'var(--muted, #9b9daa)',
18
+ cursor: 'pointer',
19
+ transition: 'all .18s ease',
20
+ fontFamily: 'inherit',
21
+ whiteSpace: 'nowrap',
22
+ }}>
23
+ {label}
24
+ </button>
25
+ );
26
+ })}
27
+ </div>
28
+ );
29
+ }