uibee 3.1.5 → 3.2.0
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/dist/src/components/index.d.ts +165 -2
- package/dist/src/components/index.js +455 -10
- package/dist/style.css +252 -72
- package/package.json +1 -1
- package/src/components/badge/badge.tsx +44 -0
- package/src/components/buttons/button.tsx +2 -1
- package/src/components/code/code.tsx +55 -0
- package/src/components/container/accordion.tsx +5 -1
- package/src/components/container/expandableCard.tsx +80 -0
- package/src/components/container/glassCard.tsx +14 -0
- package/src/components/container/tabs.tsx +3 -3
- package/src/components/empty/emptyState.tsx +26 -0
- package/src/components/index.ts +17 -0
- package/src/components/inputs/fileInput.tsx +100 -0
- package/src/components/inputs/input.tsx +2 -2
- package/src/components/inputs/multiSelect.tsx +8 -2
- package/src/components/inputs/shared/colorPickerPopup.tsx +1 -1
- package/src/components/inputs/shared/dateTimePickerPopup.tsx +1 -1
- package/src/components/inputs/switch.tsx +5 -1
- package/src/components/modal/modal.tsx +74 -0
- package/src/components/sidebar/sidebar.tsx +177 -0
- package/src/components/spinner/spinner.tsx +20 -0
- package/src/components/table/body.tsx +37 -31
- package/src/components/table/constants.ts +1 -3
- package/src/components/table/header.tsx +32 -22
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
type SpinnerProps = {
|
|
2
|
+
size?: 'sm' | 'md' | 'lg'
|
|
3
|
+
className?: string
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
const sizes = {
|
|
7
|
+
sm: 'w-4 h-4 border-2',
|
|
8
|
+
md: 'w-6 h-6 border-2',
|
|
9
|
+
lg: 'w-9 h-9 border-[3px]',
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default function Spinner({ size = 'md', className = '' }: SpinnerProps) {
|
|
13
|
+
return (
|
|
14
|
+
<div
|
|
15
|
+
role='status'
|
|
16
|
+
aria-label='Loading'
|
|
17
|
+
className={`rounded-full border-login-500 border-t-login animate-spin ${sizes[size]} ${className}`}
|
|
18
|
+
/>
|
|
19
|
+
)
|
|
20
|
+
}
|
|
@@ -46,18 +46,16 @@ function Cell<T extends Record<string, unknown>>({
|
|
|
46
46
|
variant: TableVariant
|
|
47
47
|
}) {
|
|
48
48
|
const value = row[col.key]
|
|
49
|
-
// Truncate: opt-in, only applied when col.truncate === true (needs an explicit col.width to bite).
|
|
50
49
|
const shouldTruncate = col.truncate === true
|
|
51
50
|
const align = col.align ?? 'left'
|
|
52
51
|
|
|
53
52
|
const wrapperAlign =
|
|
54
53
|
align === 'right' ? 'text-right' :
|
|
55
|
-
|
|
54
|
+
align === 'center' ? 'text-center' : ''
|
|
56
55
|
|
|
57
56
|
let content: React.ReactNode
|
|
58
57
|
|
|
59
58
|
if (col.render) {
|
|
60
|
-
// Custom renderer: caller is responsible for alignment
|
|
61
59
|
content = col.render(value, row)
|
|
62
60
|
} else if (col.highlight) {
|
|
63
61
|
const colorName = col.highlight[String(value)] ?? col.highlight['default']
|
|
@@ -124,8 +122,6 @@ export default function Body<T extends Record<string, unknown>>({
|
|
|
124
122
|
|
|
125
123
|
useEffect(() => {
|
|
126
124
|
if (openMenuId === null) return
|
|
127
|
-
// The menu is anchored to viewport coords, so close it on any scroll (the scroll
|
|
128
|
-
// container is now an ancestor of the table). Capture phase since scroll doesn't bubble.
|
|
129
125
|
document.addEventListener('scroll', closeMenu, true)
|
|
130
126
|
return () => document.removeEventListener('scroll', closeMenu, true)
|
|
131
127
|
}, [closeMenu, openMenuId])
|
|
@@ -150,7 +146,11 @@ export default function Body<T extends Record<string, unknown>>({
|
|
|
150
146
|
return (
|
|
151
147
|
<tbody className={VARIANT_TBODY[variant]}>
|
|
152
148
|
{data.map((row, rowIdx) => {
|
|
153
|
-
const id = resolveId(
|
|
149
|
+
const id = resolveId(
|
|
150
|
+
row as Record<string, unknown>,
|
|
151
|
+
idKey as string | undefined,
|
|
152
|
+
columns as Column<Record<string, unknown>>[],
|
|
153
|
+
)
|
|
154
154
|
const url = resolveRedirectUrl(redirectPath, row as Record<string, unknown>, id)
|
|
155
155
|
const isClickable = Boolean(url || onRowClick || hasExpand)
|
|
156
156
|
const isMenuOpen = openMenuId === id
|
|
@@ -195,28 +195,34 @@ export default function Body<T extends Record<string, unknown>>({
|
|
|
195
195
|
{selectable && (
|
|
196
196
|
<td className={`align-middle ${VARIANT_ROW_BORDER[variant]}`}
|
|
197
197
|
style={{ width: '3rem', minWidth: '3rem' }}>
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
198
|
+
<div className='flex items-center justify-center'>
|
|
199
|
+
<button
|
|
200
|
+
type='button'
|
|
201
|
+
aria-label={isSelected ? 'Deselect row' : 'Select row'}
|
|
202
|
+
aria-checked={isSelected}
|
|
203
|
+
role='checkbox'
|
|
204
|
+
onClick={(e) => { e.stopPropagation(); toggleSelect(id) }}
|
|
205
|
+
className={`
|
|
206
206
|
h-4 w-4 rounded border flex items-center justify-center transition-colors cursor-pointer
|
|
207
207
|
${isSelected
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
208
|
+
? 'bg-login border-login text-white'
|
|
209
|
+
: 'border-login-400 bg-transparent hover:border-login-100'
|
|
210
|
+
}
|
|
211
211
|
`}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
212
|
+
>
|
|
213
|
+
{isSelected && (
|
|
214
|
+
<svg className='h-3 w-3' viewBox='0 0 12 12' fill='none'>
|
|
215
|
+
<path
|
|
216
|
+
d='M2 6l3 3 5-5'
|
|
217
|
+
stroke='currentColor'
|
|
218
|
+
strokeWidth='1.5'
|
|
219
|
+
strokeLinecap='round'
|
|
220
|
+
strokeLinejoin='round'
|
|
221
|
+
/>
|
|
222
|
+
</svg>
|
|
223
|
+
)}
|
|
224
|
+
</button>
|
|
225
|
+
</div>
|
|
220
226
|
</td>
|
|
221
227
|
)}
|
|
222
228
|
|
|
@@ -227,12 +233,12 @@ export default function Body<T extends Record<string, unknown>>({
|
|
|
227
233
|
{hasExpand && (
|
|
228
234
|
<td className={`align-middle ${VARIANT_ROW_BORDER[variant]}`}
|
|
229
235
|
style={{ width: '2.5rem', minWidth: '2.5rem' }}>
|
|
230
|
-
|
|
231
|
-
|
|
236
|
+
<div className='flex items-center justify-center'>
|
|
237
|
+
<ChevronDown className={`
|
|
232
238
|
h-4 w-4 transition-transform duration-200
|
|
233
239
|
${isExpanded ? 'rotate-180 text-login' : 'text-login-400'}
|
|
234
240
|
`} />
|
|
235
|
-
|
|
241
|
+
</div>
|
|
236
242
|
</td>
|
|
237
243
|
)}
|
|
238
244
|
|
|
@@ -258,9 +264,9 @@ export default function Body<T extends Record<string, unknown>>({
|
|
|
258
264
|
className={`
|
|
259
265
|
p-1.5 rounded flex items-center justify-center transition-colors
|
|
260
266
|
${isMenuOpen
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
267
|
+
? 'bg-login-500 text-login-75'
|
|
268
|
+
: 'text-login-300 hover:bg-login-500/60 hover:text-login-75'
|
|
269
|
+
}
|
|
264
270
|
`}
|
|
265
271
|
>
|
|
266
272
|
<EllipsisVertical className='h-4 w-4' />
|
|
@@ -34,11 +34,9 @@ export const VARIANT_THEAD: Record<TableVariant, string> = {
|
|
|
34
34
|
|
|
35
35
|
export const VARIANT_HEAD_BG: Record<TableVariant, string> = {
|
|
36
36
|
original: 'bg-login-700',
|
|
37
|
-
modern: '
|
|
37
|
+
modern: '',
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
// Bottom border under the header cells (row dividers live on the cells, not the <tr>,
|
|
41
|
-
// because native table rows don't render borders in border-separate mode).
|
|
42
40
|
export const VARIANT_HEAD_BORDER: Record<TableVariant, string> = {
|
|
43
41
|
original: 'border-b border-login-600',
|
|
44
42
|
modern: 'border-b border-login-500/40',
|
|
@@ -49,29 +49,35 @@ export default function Header<T extends Record<string, unknown>>({
|
|
|
49
49
|
{hasSelect && (
|
|
50
50
|
<th className={`sticky top-0 z-10 ${VARIANT_HEAD_BG[variant]} ${VARIANT_HEAD_BORDER[variant]}`}
|
|
51
51
|
style={{ width: '3rem', minWidth: '3rem' }}>
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
<div className='flex items-center justify-center'>
|
|
53
|
+
<button
|
|
54
|
+
type='button'
|
|
55
|
+
aria-label={allSelected ? 'Deselect all' : 'Select all'}
|
|
56
|
+
onClick={onSelectAll}
|
|
57
|
+
className={`
|
|
58
58
|
h-4 w-4 rounded border flex items-center justify-center transition-colors cursor-pointer
|
|
59
59
|
${allSelected || someSelected
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
? 'bg-login border-login text-white'
|
|
61
|
+
: 'border-login-400 bg-transparent hover:border-login-200'
|
|
62
|
+
}
|
|
63
63
|
`}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
64
|
+
>
|
|
65
|
+
{someSelected && !allSelected && (
|
|
66
|
+
<span className='block h-0.5 w-2 bg-white rounded-full' />
|
|
67
|
+
)}
|
|
68
|
+
{allSelected && (
|
|
69
|
+
<svg className='h-3 w-3' viewBox='0 0 12 12' fill='none'>
|
|
70
|
+
<path
|
|
71
|
+
d='M2 6l3 3 5-5'
|
|
72
|
+
stroke='currentColor'
|
|
73
|
+
strokeWidth='1.5'
|
|
74
|
+
strokeLinecap='round'
|
|
75
|
+
strokeLinejoin='round'
|
|
76
|
+
/>
|
|
77
|
+
</svg>
|
|
78
|
+
)}
|
|
79
|
+
</button>
|
|
80
|
+
</div>
|
|
75
81
|
</th>
|
|
76
82
|
)}
|
|
77
83
|
|
|
@@ -84,7 +90,7 @@ export default function Header<T extends Record<string, unknown>>({
|
|
|
84
90
|
|
|
85
91
|
const alignClass =
|
|
86
92
|
col.align === 'right' ? 'justify-end' :
|
|
87
|
-
|
|
93
|
+
col.align === 'center' ? 'justify-center' : ''
|
|
88
94
|
|
|
89
95
|
return (
|
|
90
96
|
<th
|
|
@@ -126,7 +132,11 @@ export default function Header<T extends Record<string, unknown>>({
|
|
|
126
132
|
{hasExpand && (
|
|
127
133
|
<th className={`sticky top-0 z-10 ${VARIANT_HEAD_BG[variant]} ${VARIANT_HEAD_BORDER[variant]}`}
|
|
128
134
|
style={{ width: '2.5rem', minWidth: '2.5rem' }}>
|
|
129
|
-
<span className={`
|
|
135
|
+
<span className={`
|
|
136
|
+
flex items-center justify-center
|
|
137
|
+
text-xs font-medium tracking-wider uppercase opacity-50
|
|
138
|
+
${VARIANT_THEAD_TH[variant]}
|
|
139
|
+
`}>
|
|
130
140
|
+
|
|
131
141
|
</span>
|
|
132
142
|
</th>
|