nitro-web 0.0.143 → 0.0.145

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,6 +1,7 @@
1
- import { JSX, useState, useCallback, Fragment } from 'react'
1
+ import { JSX, useState, useCallback, Fragment, useMemo, useEffect } from 'react'
2
2
  import { ChevronDownIcon, ChevronUpIcon } from 'lucide-react'
3
3
  import { Checkbox, queryObject, queryString, twMerge } from 'nitro-web'
4
+ import { useLocation, useNavigate } from 'react-router-dom'
4
5
 
5
6
  export type TableRowType = 'row' | 'loading' | 'empty' | 'thead'
6
7
 
@@ -78,6 +79,11 @@ export function Table<T extends TableRow>({
78
79
  'first:border-l last:border-r border-t-0 box-border'
79
80
  const [rand] = useState(() => new Date().getTime() + Math.random())
80
81
 
82
+ const rowsToRender = useMemo(() => {
83
+ // 1) Only show the first row when loading (content hidden), 2) an empty row when there are no records, or all rows
84
+ return rows.length > 0 ? (isLoading ? rows.slice(0, 1) : rows) : [{ _id: '' }] as unknown as T[]
85
+ }, [rows, isLoading])
86
+
81
87
  const columns = useMemo(() => {
82
88
  const checkboxCol: TableColumn = { value: 'checkbox', label: '', disableSort: true }
83
89
  const cols = (generateCheckboxActions ? [checkboxCol, ...columnsProp] : columnsProp).map((col, _i) => ({
@@ -92,7 +98,7 @@ export function Table<T extends TableRow>({
92
98
 
93
99
  const onSelect = useCallback((idOrAll: string, checked: boolean) => {
94
100
  setSelectedRowIds((o) => {
95
- if (idOrAll == 'all' && checked) return (rows ?? []).map(row => row?._id||'')
101
+ if (idOrAll == 'all' && checked) return (rows ?? []).map(row => row._id || '')
96
102
  else if (idOrAll == 'all' && !checked) return []
97
103
  else if (o.includes(idOrAll) && !checked) return o.filter(id => id != idOrAll)
98
104
  else if (!o.includes(idOrAll) && checked) return [...o, idOrAll]
@@ -106,7 +112,7 @@ export function Table<T extends TableRow>({
106
112
  }, [])
107
113
 
108
114
  // Reset selected rows when the location changes, or the number of rows changed (e.g. when a row is removed)
109
- useEffect(() => setSelectedRowIds([]), [location.key, (rows ?? []).map(row => row?._id||'').join(',')])
115
+ useEffect(() => setSelectedRowIds([]), [location.key, (rows ?? []).map(row => row._id || '').join(',')])
110
116
 
111
117
  // --- Sorting ---
112
118
 
@@ -124,8 +130,8 @@ export function Table<T extends TableRow>({
124
130
  navigate(location.pathname + queryStr, { replace: true })
125
131
  }, [location.pathname, query, sort, sortBy])
126
132
 
127
- const getColumnPadding = useCallback((j: number, row: T|undefined, type: TableRowType) => {
128
- const sideColor = j == 0 && rowSideColor ? rowSideColor(row, type) : undefined
133
+ const getColumnPadding = useCallback((j: number, row: T|undefined, rowType: TableRowType) => {
134
+ const sideColor = j == 0 && rowSideColor ? rowSideColor(row, rowType) : undefined
129
135
  const sideColorPadding = sideColor /*&& rows.length > 0*/ ? sideColor.width + 5 : 0
130
136
  const pl = sideColorPadding + (j == 0 ? columnPaddingX : columnGap)
131
137
  const pr = j == columns.length - 1 ? columnPaddingX : columnGap
@@ -214,8 +220,8 @@ export function Table<T extends TableRow>({
214
220
  </div>
215
221
  {/* Tbody rows */}
216
222
  {
217
- !isLoading && rows.map((row: T, i: number) => {
218
- const isSelected = selectedRowIds.includes(row?._id||'')
223
+ rowsToRender.map((row: T, i: number) => {
224
+ const isSelected = selectedRowIds.includes(row._id || '')
219
225
  return (
220
226
  <div
221
227
  key={`${row._id}-${i}`}
@@ -227,7 +233,8 @@ export function Table<T extends TableRow>({
227
233
  >
228
234
  {
229
235
  columns.map((col, j) => {
230
- const { pl, pr, sideColor } = getColumnPadding(j, row, 'row')
236
+ const rowType = row._id ? 'row' : isLoading ? 'loading' : 'empty'
237
+ const { pl, pr, sideColor } = getColumnPadding(j, isLoading ? undefined : row, rowType)
231
238
  if (col.isHidden) return <Fragment key={j} />
232
239
  return (
233
240
  <div
@@ -260,18 +267,31 @@ export function Table<T extends TableRow>({
260
267
  />
261
268
  }
262
269
  {
263
- col.value == 'checkbox'
264
- ? <Checkbox
265
- size={checkboxSize}
266
- name={`checkbox-${row._id}`}
267
- onChange={(e) => onSelect(row?._id || '', e.target.checked)}
268
- checked={selectedRowIds.includes(row?._id || '')}
269
- onClick={(e) => e.stopPropagation()}
270
- hitboxPadding={5}
271
- className='!m-0 py-[5px]' // py-5 is required for hitbox (restricted to tabel cell height)
272
- checkboxClassName={twMerge('border-foreground shadow-[0_1px_2px_0px_#0000001c]', checkboxClassName)}
273
- />
274
- : generateTd(col, row, i, i == rows.length - 1)
270
+ // Rows (content hidden when loading)
271
+ row._id &&
272
+ <div className={isLoading ? 'opacity-0 pointer-events-none' : ''}>
273
+ {
274
+ col.value == 'checkbox'
275
+ ? <Checkbox
276
+ size={checkboxSize}
277
+ name={`checkbox-${row._id}`}
278
+ onChange={(e) => onSelect(row?._id || '', e.target.checked)}
279
+ checked={selectedRowIds.includes(row?._id || '')}
280
+ onClick={(e) => e.stopPropagation()}
281
+ hitboxPadding={5}
282
+ className='!m-0 py-[5px]' // py-5 is required for hitbox (restricted to tabel cell height)
283
+ checkboxClassName={twMerge('border-foreground shadow-[0_1px_2px_0px_#0000001c]', checkboxClassName)}
284
+ />
285
+ : generateTd(col, row, i, i == rows.length - 1)
286
+ }
287
+ </div>
288
+ }
289
+ {
290
+ // Show "loading" or "no records" text in the first column
291
+ j == 0 && (isLoading || !row._id) &&
292
+ <div className={'absolute top-0 h-full flex items-center justify-center text-sm text-gray-500'}>
293
+ { isLoading ? <>Loading<span className="relative ml-[2px] loading-dots" /></> : 'No records found.' }
294
+ </div>
275
295
  }
276
296
  </div>
277
297
  </div>
@@ -282,39 +302,6 @@ export function Table<T extends TableRow>({
282
302
  )
283
303
  })
284
304
  }
285
- {
286
- (isLoading || rows.length == 0) &&
287
- <div className='table-row relative'>
288
- {
289
- columns.map((col, j) => {
290
- const { pl, pr, sideColor } = getColumnPadding(j, undefined, isLoading ? 'loading' : 'empty')
291
- return (
292
- <div
293
- key={j}
294
- style={{ height: rowHeightMin, paddingLeft: pl, paddingRight: pr }}
295
- className={twMerge(_columnClassName, columnClassName, col.className)}
296
- >
297
- {
298
- sideColor &&
299
- <div
300
- className={`absolute top-0 left-0 h-full ${sideColor?.className||''}`}
301
- style={{ width: sideColor.width }}
302
- />
303
- }
304
- <div
305
- className={twMerge(
306
- 'absolute top-0 h-full flex items-center justify-center text-sm text-gray-500',
307
- col.innerClassName
308
- )}
309
- >
310
- { j == 0 && (isLoading ? <>Loading<span className="relative ml-[2px] loading-dots" /></> : 'No records found.') }
311
- </div>
312
- </div>
313
- )
314
- })
315
- }
316
- </div>
317
- }
318
305
  </div>
319
306
  </div>
320
307
  )
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nitro-web",
3
- "version": "0.0.143",
3
+ "version": "0.0.145",
4
4
  "repository": "github:boycce/nitro-web",
5
5
  "homepage": "https://boycce.github.io/nitro-web/",
6
6
  "description": "Nitro is a battle-tested, modular base project to turbocharge your projects, styled using Tailwind 🚀",