cynx-ui 1.3.17 → 1.3.19

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.
@@ -0,0 +1,204 @@
1
+ import React from 'react';
2
+
3
+ const SIZES = {
4
+ xs: {
5
+ height: 26,
6
+ padding: '0 8px',
7
+ fontSize: '.74rem',
8
+ iconSize: 13,
9
+ dotSize: '.7rem',
10
+ sepHeight: 12,
11
+ gap: 6,
12
+ borderRadius: 'var(--radxs, 6px)',
13
+ },
14
+ sm: {
15
+ height: 32,
16
+ padding: '0 12px',
17
+ fontSize: '.82rem',
18
+ iconSize: 15,
19
+ dotSize: '.75rem',
20
+ sepHeight: 14,
21
+ gap: 8,
22
+ borderRadius: 'var(--rads, 8px)',
23
+ },
24
+ md: {
25
+ height: 36,
26
+ padding: '0 14px',
27
+ fontSize: '.88rem',
28
+ iconSize: 16,
29
+ dotSize: '.8rem',
30
+ sepHeight: 16,
31
+ gap: 10,
32
+ borderRadius: 'var(--rad, 10px)',
33
+ },
34
+ lg: {
35
+ height: 40,
36
+ padding: '0 16px',
37
+ fontSize: '.95rem',
38
+ iconSize: 18,
39
+ dotSize: '.85rem',
40
+ sepHeight: 18,
41
+ gap: 12,
42
+ borderRadius: 'var(--rad, 10px)',
43
+ },
44
+ };
45
+
46
+ const VARIANTS = {
47
+ default: {
48
+ background: 'var(--surface, #ffffff)',
49
+ border: '1px solid var(--border, #d7d8e0)',
50
+ boxShadow: 'var(--shadow, 0 1px 2px rgba(0, 0, 0, 0.05))',
51
+ },
52
+ surface: {
53
+ background: 'var(--surface, #ffffff)',
54
+ border: '1px solid var(--border, #d7d8e0)',
55
+ boxShadow: 'var(--shadow, 0 1px 2px rgba(0, 0, 0, 0.05))',
56
+ },
57
+ flat: {
58
+ background: 'var(--grey-1, #f5f5f8)',
59
+ border: '1px solid var(--border, #d7d8e0)',
60
+ boxShadow: 'none',
61
+ },
62
+ ghost: {
63
+ background: 'transparent',
64
+ border: '1px solid var(--border, #d7d8e0)',
65
+ boxShadow: 'none',
66
+ },
67
+ };
68
+
69
+ export default function InfoBadge({
70
+ items,
71
+ icon,
72
+ label,
73
+ value,
74
+ color,
75
+ title,
76
+ dot = true,
77
+ size = 'sm',
78
+ variant = 'default',
79
+ style,
80
+ className = '',
81
+ children,
82
+ onClick,
83
+ ...props
84
+ }) {
85
+ const sz = SIZES[size] || SIZES.sm;
86
+ const vr = VARIANTS[variant] || VARIANTS.default;
87
+
88
+ const containerStyle = {
89
+ display: 'inline-flex',
90
+ alignItems: 'center',
91
+ boxSizing: 'border-box',
92
+ height: sz.height,
93
+ padding: sz.padding,
94
+ borderRadius: sz.borderRadius,
95
+ background: vr.background,
96
+ border: vr.border,
97
+ boxShadow: vr.boxShadow,
98
+ gap: sz.gap,
99
+ cursor: onClick ? 'pointer' : 'default',
100
+ userSelect: 'none',
101
+ ...style,
102
+ };
103
+
104
+ if (children) {
105
+ return (
106
+ <div style={containerStyle} className={className} onClick={onClick} title={title} {...props}>
107
+ {children}
108
+ </div>
109
+ );
110
+ }
111
+
112
+ const resolvedItems = Array.isArray(items) && items.length > 0
113
+ ? items
114
+ : (icon != null || value != null || label != null)
115
+ ? [{ icon, label, value, color, title, onClick }]
116
+ : [];
117
+
118
+ return (
119
+ <div style={containerStyle} className={className} onClick={onClick} title={title} {...props}>
120
+ {resolvedItems.map((it, idx) => {
121
+ const itemColor = it.color || 'inherit';
122
+ const showDot = it.dot !== undefined ? it.dot : dot;
123
+
124
+ return (
125
+ <React.Fragment key={it.id || it.key || idx}>
126
+ {idx > 0 && (
127
+ <div
128
+ style={{
129
+ width: 1,
130
+ height: sz.sepHeight,
131
+ background: 'var(--border, #d7d8e0)',
132
+ flexShrink: 0,
133
+ }}
134
+ />
135
+ )}
136
+ <div
137
+ style={{
138
+ display: 'inline-flex',
139
+ alignItems: 'center',
140
+ gap: 5,
141
+ cursor: it.onClick ? 'pointer' : 'inherit',
142
+ }}
143
+ title={it.title}
144
+ onClick={it.onClick}
145
+ >
146
+ {it.icon && (
147
+ <span
148
+ style={{
149
+ display: 'inline-flex',
150
+ alignItems: 'center',
151
+ justifyContent: 'center',
152
+ color: itemColor,
153
+ flexShrink: 0,
154
+ }}
155
+ >
156
+ {typeof it.icon === 'function'
157
+ ? React.createElement(it.icon, { size: sz.iconSize })
158
+ : React.isValidElement(it.icon)
159
+ ? React.cloneElement(it.icon, { size: it.icon.props?.size || sz.iconSize })
160
+ : it.icon}
161
+ </span>
162
+ )}
163
+ {it.label && (
164
+ <span
165
+ style={{
166
+ fontSize: sz.fontSize,
167
+ fontWeight: 500,
168
+ color: itemColor !== 'inherit' ? itemColor : 'var(--primary-text, #0f111c)',
169
+ }}
170
+ >
171
+ {it.label}
172
+ </span>
173
+ )}
174
+ {showDot && (it.icon || it.label) && it.value !== undefined && (
175
+ <span
176
+ style={{
177
+ fontSize: sz.dotSize,
178
+ color: 'var(--muted, #9b9daa)',
179
+ lineHeight: 1,
180
+ }}
181
+ >
182
+
183
+ </span>
184
+ )}
185
+ {it.value !== undefined && (
186
+ <span
187
+ style={{
188
+ fontSize: sz.fontSize,
189
+ fontWeight: 500,
190
+ color: 'var(--primary-text, #0f111c)',
191
+ fontVariantNumeric: 'tabular-nums',
192
+ lineHeight: 1,
193
+ }}
194
+ >
195
+ {it.value}
196
+ </span>
197
+ )}
198
+ </div>
199
+ </React.Fragment>
200
+ );
201
+ })}
202
+ </div>
203
+ );
204
+ }
@@ -20,13 +20,15 @@ const STYLES = `
20
20
  display: flex; align-items: center; justify-content: space-between;
21
21
  padding: 15px 20px; border-bottom: 1px solid var(--border-light);
22
22
  border-radius: 14px 14px 0 0;
23
+ flex-shrink: 0;
23
24
  }
24
25
  .modal-title { font-size: .88rem; font-weight: 700; letter-spacing: -.01em; }
25
- .modal-body { padding: 20px; overflow: visible; }
26
+ .modal-body { padding: 20px; overflow-x: hidden; overflow-y: auto; flex: 1 1 auto; min-height: 0; }
26
27
  .modal-footer {
27
28
  display: flex; justify-content: flex-end; gap: 8px;
28
29
  padding: 13px 20px; border-top: 1px solid var(--border-light);
29
30
  background: var(--grey-1); border-radius: 0 0 14px 14px;
31
+ flex-shrink: 0;
30
32
  }
31
33
  .modal-card {
32
34
  background: var(--surface); border: 1px solid var(--border);
@@ -94,7 +96,7 @@ function ensureStyles() {
94
96
  // Auto-inject on module load
95
97
  if (typeof document !== 'undefined') ensureStyles();
96
98
 
97
- export function Modal({ open, onClose, onBeforeClose, title, children, footer, maxWidth = 520, bodyStyle }) {
99
+ export function Modal({ open, onClose, onBeforeClose, title, children, footer, maxWidth = 520, maxHeight, bodyStyle, style }) {
98
100
  const [closing, setClosing] = useState(false);
99
101
  const mounted = useRef(open);
100
102
 
@@ -131,6 +133,7 @@ export function Modal({ open, onClose, onBeforeClose, title, children, footer, m
131
133
 
132
134
  const resolvedFooter = typeof footer === 'function' ? footer(close) : footer;
133
135
  const resolvedChildren = typeof children === 'function' ? children(close) : children;
136
+ const resolvedMaxHeight = style?.maxHeight || maxHeight || '60vh';
134
137
 
135
138
  return createPortal(
136
139
  <div
@@ -138,7 +141,7 @@ export function Modal({ open, onClose, onBeforeClose, title, children, footer, m
138
141
  style={{
139
142
  position: 'fixed', inset: 0,
140
143
  background: 'rgba(20,22,41,.45)',
141
- display: 'flex', alignItems: 'center', justifyContent: 'center',
144
+ display: 'flex', alignItems: 'center', justifyItems: 'center', justifyContent: 'center',
142
145
  zIndex: 8000, padding: 20,
143
146
  animation: `${closing ? 'modalFadeOut' : 'modalFadeIn'} .26s ease forwards`,
144
147
  }}
@@ -148,25 +151,28 @@ export function Modal({ open, onClose, onBeforeClose, title, children, footer, m
148
151
  className="modal-card"
149
152
  style={{
150
153
  background: 'var(--surface)', border: '1px solid var(--border)',
151
- borderRadius: 14, width: '100%', maxWidth, maxHeight: '60vh',
154
+ borderRadius: 14, width: '100%',
155
+ maxWidth: style?.maxWidth || maxWidth,
156
+ maxHeight: resolvedMaxHeight,
152
157
  boxShadow: 'var(--slg, 0 20px 60px rgba(0,0,0,.25))',
153
158
  overflow: 'hidden', display: 'flex', flexDirection: 'column',
154
159
  animation: `${closing ? 'modalCardOut' : 'modalCardIn'} .26s cubic-bezier(.4,0,.2,1) forwards`,
160
+ ...style,
155
161
  }}
156
162
  onMouseDown={e => e.stopPropagation()}
157
163
  >
158
164
  <div className="modal-hdr" style={{
159
165
  display: 'flex', alignItems: 'center', justifyContent: 'space-between',
160
166
  padding: '15px 20px', borderBottom: '1px solid var(--border-light)',
161
- borderRadius: '14px 14px 0 0',
167
+ borderRadius: '14px 14px 0 0', flexShrink: 0,
162
168
  }}>
163
169
  <span className="modal-title" style={{ fontSize: '.88rem', fontWeight: 700, letterSpacing: '-.01em' }}>{title}</span>
164
170
  </div>
165
- <div className="modal-body" style={{ padding: 20, overflowX: 'hidden', overflowY: 'auto', flex: 1, minHeight: 0, ...bodyStyle }}>{resolvedChildren}</div>
171
+ <div className="modal-body" style={{ padding: 20, overflowX: 'hidden', overflowY: 'auto', flex: '1 1 auto', minHeight: 0, ...bodyStyle }}>{resolvedChildren}</div>
166
172
  {resolvedFooter && <div className="modal-footer" style={{
167
173
  display: 'flex', justifyContent: 'flex-end', gap: 8,
168
174
  padding: '13px 20px', borderTop: '1px solid var(--border-light)',
169
- background: 'var(--grey-1)', borderRadius: '0 0 14px 14px',
175
+ background: 'var(--grey-1)', borderRadius: '0 0 14px 14px', flexShrink: 0,
170
176
  }}>{resolvedFooter}</div>}
171
177
  </div>
172
178
  </div>,
package/index.js CHANGED
@@ -38,11 +38,13 @@ import { XTable as _XTable, XThead as _XThead, XTbody as _XTbody, XTr as _XTr, X
38
38
  import { PageShell as _PageShell, TableCard as _TableCard, TableCardFilters as _TableCardFilters, TableCardBody as _TableCardBody, TableCardFooter as _TableCardFooter, CardHdr as _CardHdr, StatCard as _StatCard, StatCardSkeleton as _StatCardSkeleton } from './components/Card.jsx';
39
39
 
40
40
  import { default as _FilePicker } from './components/FilePicker.jsx';
41
- import { default as _Divider } from './components/Divider.jsx';
41
+ import { default as _Divider } from './components/Divider.jsx';
42
+ import { default as _InfoBadge } from './components/InfoBadge.jsx';
42
43
 
43
44
  export const Button = _Button;
44
45
  export const FilePicker = _FilePicker;
45
- export const Divider = _Divider;
46
+ export const Divider = _Divider;
47
+ export const InfoBadge = _InfoBadge;
46
48
  export const Input = _Input;
47
49
  export const Toggle = _Toggle;
48
50
  export const Spinner = _Spinner || _SpinnerNamed;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cynx-ui",
3
- "version": "1.3.17",
3
+ "version": "1.3.19",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./index.js"