@kikiloaw/simple-table 1.0.2 → 1.0.4
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/README.md +357 -11
- package/package.json +1 -1
- package/src/SimpleTable.vue +41 -3
- package/src/components/table/TableCell.vue +13 -2
- package/src/components/table/TableHead.vue +6 -2
package/README.md
CHANGED
|
@@ -87,6 +87,307 @@ public function getData(Request $request)
|
|
|
87
87
|
|
|
88
88
|
---
|
|
89
89
|
|
|
90
|
+
## 📦 Using Predefined/Static Data
|
|
91
|
+
|
|
92
|
+
**Want to use static data instead of an API?** SimpleTable handles this perfectly in client-side mode!
|
|
93
|
+
|
|
94
|
+
### Basic Setup
|
|
95
|
+
|
|
96
|
+
```vue
|
|
97
|
+
<script setup lang="ts">
|
|
98
|
+
import SimpleTable from '@kikiloaw/simple-table'
|
|
99
|
+
|
|
100
|
+
// Define your static data
|
|
101
|
+
const data = [
|
|
102
|
+
{ id: 1, name: 'John Doe', email: 'john@example.com', status: 'active' },
|
|
103
|
+
{ id: 2, name: 'Jane Smith', email: 'jane@example.com', status: 'active' },
|
|
104
|
+
{ id: 3, name: 'Bob Johnson', email: 'bob@example.com', status: 'inactive' },
|
|
105
|
+
// ... more rows
|
|
106
|
+
]
|
|
107
|
+
|
|
108
|
+
const columns = [
|
|
109
|
+
{ key: 'id', label: '#', sortable: true, width: '80px' },
|
|
110
|
+
{ key: 'name', label: 'Name', sortable: true },
|
|
111
|
+
{ key: 'email', label: 'Email', sortable: true },
|
|
112
|
+
{ key: 'status', label: 'Status', width: '120px' }
|
|
113
|
+
]
|
|
114
|
+
|
|
115
|
+
const pageSizes = [
|
|
116
|
+
{ label: '50 Rows', value: 50 },
|
|
117
|
+
{ label: '100 Rows', value: 100 },
|
|
118
|
+
]
|
|
119
|
+
</script>
|
|
120
|
+
|
|
121
|
+
<template>
|
|
122
|
+
<SimpleTable
|
|
123
|
+
:data="data"
|
|
124
|
+
:columns="columns"
|
|
125
|
+
:page-sizes="pageSizes"
|
|
126
|
+
:per-page="50"
|
|
127
|
+
mode="client"
|
|
128
|
+
searchable
|
|
129
|
+
/>
|
|
130
|
+
</template>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Key Props for Static Data
|
|
134
|
+
|
|
135
|
+
| Prop | Required | Default | Description |
|
|
136
|
+
|------|----------|---------|-------------|
|
|
137
|
+
| `:data` | **Yes** | `[]` | Your static array of objects |
|
|
138
|
+
| `mode` | **Yes** | `'auto'` | Set to `"client"` for static data |
|
|
139
|
+
| `:per-page` | Recommended | `10` | Initial page size (should match first option in pageSizes) |
|
|
140
|
+
| `:page-sizes` | Optional | `[10,20,30,50,100]` | Available page size options |
|
|
141
|
+
|
|
142
|
+
### ⚠️ Common Pitfalls
|
|
143
|
+
|
|
144
|
+
#### 1. **Don't Mix Static Data with `fetch-url`**
|
|
145
|
+
|
|
146
|
+
❌ **Wrong:**
|
|
147
|
+
```vue
|
|
148
|
+
<!-- This will ignore your static data! -->
|
|
149
|
+
<SimpleTable
|
|
150
|
+
:data="myData"
|
|
151
|
+
fetch-url="/api/users" <!-- ❌ Conflicts with :data -->
|
|
152
|
+
/>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
✅ **Correct:**
|
|
156
|
+
```vue
|
|
157
|
+
<!-- Remove fetch-url when using static data -->
|
|
158
|
+
<SimpleTable
|
|
159
|
+
:data="myData"
|
|
160
|
+
mode="client"
|
|
161
|
+
/>
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
#### 2. **Set Initial Page Size to Match Your Options**
|
|
165
|
+
|
|
166
|
+
❌ **Wrong:**
|
|
167
|
+
```vue
|
|
168
|
+
<!-- Component defaults to 10, but you only have 50/100 options -->
|
|
169
|
+
<SimpleTable
|
|
170
|
+
:data="data"
|
|
171
|
+
:page-sizes="[{ label: '50 Rows', value: 50 }, { label: '100 Rows', value: 100 }]"
|
|
172
|
+
<!-- ❌ Will show "10 Rows" which doesn't exist in dropdown -->
|
|
173
|
+
/>
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
✅ **Correct:**
|
|
177
|
+
```vue
|
|
178
|
+
<SimpleTable
|
|
179
|
+
:data="data"
|
|
180
|
+
:page-sizes="[50, 100]"
|
|
181
|
+
:per-page="50" <!-- ✅ Matches first option -->
|
|
182
|
+
/>
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
#### 3. **Columns Must Match Your Data Structure**
|
|
186
|
+
|
|
187
|
+
❌ **Wrong:**
|
|
188
|
+
```vue
|
|
189
|
+
<script setup>
|
|
190
|
+
const data = [
|
|
191
|
+
{ CourseCode: 'CS101', Description: 'Intro to CS', Units: 3 }
|
|
192
|
+
]
|
|
193
|
+
|
|
194
|
+
const columns = [
|
|
195
|
+
{ key: 'course_code', label: 'Code' }, // ❌ Wrong key!
|
|
196
|
+
{ key: 'description', label: 'Name' }, // ❌ Wrong key!
|
|
197
|
+
]
|
|
198
|
+
</script>
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
✅ **Correct:**
|
|
202
|
+
```vue
|
|
203
|
+
<script setup>
|
|
204
|
+
const data = [
|
|
205
|
+
{ CourseCode: 'CS101', Description: 'Intro to CS', Units: 3 }
|
|
206
|
+
]
|
|
207
|
+
|
|
208
|
+
const columns = [
|
|
209
|
+
{ key: 'CourseCode', label: 'Code' }, // ✅ Matches data
|
|
210
|
+
{ key: 'Description', label: 'Name' }, // ✅ Matches data
|
|
211
|
+
{ key: 'Units', label: 'Units' },
|
|
212
|
+
]
|
|
213
|
+
</script>
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Features Available in Client-Side Mode
|
|
217
|
+
|
|
218
|
+
✅ **Works:**
|
|
219
|
+
- Client-side searching (filters through your data array)
|
|
220
|
+
- Client-side sorting (by sortable columns)
|
|
221
|
+
- Client-side pagination (chunks your data into pages)
|
|
222
|
+
- Data transformation via `beforeRender`
|
|
223
|
+
- Custom cell rendering
|
|
224
|
+
- Group headers
|
|
225
|
+
- Auto-numbering
|
|
226
|
+
|
|
227
|
+
❌ **Not Available:**
|
|
228
|
+
- Server-side sorting (data is sorted locally)
|
|
229
|
+
- API caching (no API calls)
|
|
230
|
+
- Query parameters (no server to send them to)
|
|
231
|
+
|
|
232
|
+
### Complete Example with Group Headers
|
|
233
|
+
|
|
234
|
+
```vue
|
|
235
|
+
<script setup lang="ts">
|
|
236
|
+
import SimpleTable from '@kikiloaw/simple-table'
|
|
237
|
+
|
|
238
|
+
// Static course data
|
|
239
|
+
const data = [
|
|
240
|
+
{
|
|
241
|
+
CourseCode: 'CS101',
|
|
242
|
+
Description: 'Intro to Computer Science',
|
|
243
|
+
Units: 3,
|
|
244
|
+
Grade: 'A',
|
|
245
|
+
semester: '1st Semester, 2023-2024'
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
CourseCode: 'MATH101',
|
|
249
|
+
Description: 'Calculus I',
|
|
250
|
+
Units: 4,
|
|
251
|
+
Grade: 'B+',
|
|
252
|
+
semester: '1st Semester, 2023-2024'
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
CourseCode: 'CS102',
|
|
256
|
+
Description: 'Data Structures',
|
|
257
|
+
Units: 3,
|
|
258
|
+
Grade: 'A-',
|
|
259
|
+
semester: '2nd Semester, 2023-2024'
|
|
260
|
+
},
|
|
261
|
+
]
|
|
262
|
+
|
|
263
|
+
const columns = [
|
|
264
|
+
{ key: 'CourseCode', label: 'Course Code', sortable: true, width: '150px' },
|
|
265
|
+
{ key: 'Description', label: 'Description', sortable: true, width: '300px' },
|
|
266
|
+
{ key: 'Units', label: 'Units', width: '80px' },
|
|
267
|
+
{ key: 'Grade', label: 'Grade', sortable: true, width: '80px' },
|
|
268
|
+
]
|
|
269
|
+
|
|
270
|
+
// Add group headers by semester
|
|
271
|
+
const addGroupHeaders = (rows) => {
|
|
272
|
+
// DON'T sort here if your data is already in the correct order!
|
|
273
|
+
// Sorting will override your predefined order
|
|
274
|
+
|
|
275
|
+
const result = []
|
|
276
|
+
let currentSemester = null
|
|
277
|
+
|
|
278
|
+
rows.forEach(row => {
|
|
279
|
+
const semester = row.semester || 'No Semester'
|
|
280
|
+
|
|
281
|
+
// When semester changes, add a header row
|
|
282
|
+
if (semester !== currentSemester) {
|
|
283
|
+
result.push({
|
|
284
|
+
_isGroupHeader: true,
|
|
285
|
+
_groupTitle: semester,
|
|
286
|
+
// Empty values for all columns
|
|
287
|
+
CourseCode: '',
|
|
288
|
+
Description: semester,
|
|
289
|
+
Units: '',
|
|
290
|
+
Grade: '',
|
|
291
|
+
})
|
|
292
|
+
currentSemester = semester
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
result.push(row)
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
return result
|
|
299
|
+
}
|
|
300
|
+
</script>
|
|
301
|
+
|
|
302
|
+
<template>
|
|
303
|
+
<SimpleTable
|
|
304
|
+
:data="data"
|
|
305
|
+
:columns="columns"
|
|
306
|
+
:page-sizes="[50, 100]"
|
|
307
|
+
:per-page="50"
|
|
308
|
+
:before-render="addGroupHeaders"
|
|
309
|
+
mode="client"
|
|
310
|
+
searchable
|
|
311
|
+
odd-row-color="bg-gray-50"
|
|
312
|
+
even-row-color="bg-white"
|
|
313
|
+
hover-color="hover:bg-green-100"
|
|
314
|
+
/>
|
|
315
|
+
</template>
|
|
316
|
+
|
|
317
|
+
### 📏 Row Height Control
|
|
318
|
+
|
|
319
|
+
Control the exact height of your table rows with the `rowHeight` prop:
|
|
320
|
+
|
|
321
|
+
```vue
|
|
322
|
+
<template>
|
|
323
|
+
<SimpleTable
|
|
324
|
+
:data="data"
|
|
325
|
+
:columns="columns"
|
|
326
|
+
:row-height="38" <!-- Rows will be exactly 38px tall -->
|
|
327
|
+
/>
|
|
328
|
+
</template>
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
**How it works:**
|
|
332
|
+
- Sets the `height` style on both header and data rows
|
|
333
|
+
- Automatically adjusts cell padding based on the height
|
|
334
|
+
- Default: `38px` (compact and readable)
|
|
335
|
+
|
|
336
|
+
**Recommended Values:**
|
|
337
|
+
|
|
338
|
+
| Height | Padding | Use Case |
|
|
339
|
+
|--------|---------|----------|
|
|
340
|
+
| `30-36px` | `p-2` (8px) | **Extra compact** - Maximum rows visible, dense data |
|
|
341
|
+
| `38-42px` | `p-2` (8px) | **Standard** - Good balance (default: 38px) |
|
|
342
|
+
| `44-55px` | `p-3` (12px) | **Comfortable** - Easy to read, spacious |
|
|
343
|
+
| `56px+` | `p-4` (16px) | **Very spacious** - Accessibility-friendly, large text |
|
|
344
|
+
|
|
345
|
+
**Examples:**
|
|
346
|
+
|
|
347
|
+
```vue
|
|
348
|
+
<!-- Ultra compact for dashboards -->
|
|
349
|
+
<SimpleTable :row-height="32" />
|
|
350
|
+
|
|
351
|
+
<!-- Default - balanced -->
|
|
352
|
+
<SimpleTable :row-height="38" /> <!-- or omit for default -->
|
|
353
|
+
|
|
354
|
+
<!-- Comfortable reading -->
|
|
355
|
+
<SimpleTable :row-height="48" />
|
|
356
|
+
|
|
357
|
+
<!-- Accessibility-friendly -->
|
|
358
|
+
<SimpleTable :row-height="60" />
|
|
359
|
+
|
|
360
|
+
<!-- No prop = uses default 38px -->
|
|
361
|
+
<SimpleTable :data="data" :columns="columns" />
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
**Padding Auto-Adjustment:**
|
|
365
|
+
|
|
366
|
+
The component automatically adjusts internal padding:
|
|
367
|
+
- **< 44px**: Uses `p-2` (8px) - Compact
|
|
368
|
+
- **44-55px**: Uses `p-3` (12px) - Normal
|
|
369
|
+
- **56px+**: Uses `p-4` (16px) - Comfortable
|
|
370
|
+
|
|
371
|
+
### 💡 Best Practices
|
|
372
|
+
|
|
373
|
+
1. **Data Order Preservation**
|
|
374
|
+
- If your data is already sorted correctly, **don't sort it again** in `beforeRender`
|
|
375
|
+
- Let users sort by clicking column headers if needed
|
|
376
|
+
|
|
377
|
+
2. **Performance**
|
|
378
|
+
- Client-side mode works great for **< 1,000 rows**
|
|
379
|
+
- For larger datasets, consider server-side mode with `fetch-url`
|
|
380
|
+
|
|
381
|
+
3. **Reactivity**
|
|
382
|
+
- Use `ref()` or `reactive()` if your data changes
|
|
383
|
+
- The table will automatically update when data changes
|
|
384
|
+
|
|
385
|
+
4. **Page Size Options**
|
|
386
|
+
- Keep options reasonable: `[10, 25, 50, 100]`
|
|
387
|
+
- Set `:per-page` to match your first option
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
90
391
|
## 📖 Table of Contents
|
|
91
392
|
|
|
92
393
|
- [Core Concepts](#-core-concepts)
|
|
@@ -754,28 +1055,73 @@ const beforeRender = (rows) => {
|
|
|
754
1055
|
|
|
755
1056
|
### Custom Cell Rendering
|
|
756
1057
|
|
|
757
|
-
**Customize how data is displayed in
|
|
1058
|
+
**Customize how data is displayed in any column using named slots.**
|
|
1059
|
+
|
|
1060
|
+
**Slot Syntax:** `#cell-{columnKey}="{ row }"`
|
|
1061
|
+
|
|
1062
|
+
#### 1. Conditional Styling & Badges
|
|
758
1063
|
|
|
759
1064
|
```vue
|
|
760
|
-
<SimpleTable :columns="columns"
|
|
761
|
-
<!--
|
|
762
|
-
<template #cell-
|
|
1065
|
+
<SimpleTable :columns="columns" :data="data">
|
|
1066
|
+
<!-- Status Badge with Conditional Color -->
|
|
1067
|
+
<template #cell-is_active="{ row }">
|
|
763
1068
|
<span
|
|
764
|
-
|
|
1069
|
+
v-if="!row._isGroupHeader"
|
|
1070
|
+
:class="row.is_active ? 'text-green-600 font-bold' : 'text-red-600'"
|
|
765
1071
|
>
|
|
766
|
-
{{ row.
|
|
1072
|
+
{{ row.is_active ? 'Active' : 'Inactive' }}
|
|
767
1073
|
</span>
|
|
768
1074
|
</template>
|
|
769
|
-
|
|
770
|
-
|
|
1075
|
+
</SimpleTable>
|
|
1076
|
+
```
|
|
1077
|
+
|
|
1078
|
+
#### 2. Rendering Lists/Tags
|
|
1079
|
+
|
|
1080
|
+
```vue
|
|
1081
|
+
<SimpleTable :columns="columns" :data="data">
|
|
1082
|
+
<!-- Loop through array data in a cell -->
|
|
1083
|
+
<template #cell-tags="{ row }">
|
|
1084
|
+
<div v-if="!row._isGroupHeader" class="flex gap-1 flex-wrap">
|
|
1085
|
+
<span
|
|
1086
|
+
v-for="tag in row.tags"
|
|
1087
|
+
:key="tag.id"
|
|
1088
|
+
class="bg-blue-100 text-blue-800 text-xs px-2 py-0.5 rounded"
|
|
1089
|
+
>
|
|
1090
|
+
{{ tag.name }}
|
|
1091
|
+
</span>
|
|
1092
|
+
</div>
|
|
1093
|
+
</template>
|
|
1094
|
+
</SimpleTable>
|
|
1095
|
+
```
|
|
1096
|
+
|
|
1097
|
+
#### 3. Action Buttons
|
|
1098
|
+
|
|
1099
|
+
```vue
|
|
1100
|
+
<SimpleTable :columns="columns" :data="data">
|
|
771
1101
|
<template #cell-actions="{ row }">
|
|
772
|
-
<
|
|
773
|
-
|
|
1102
|
+
<div v-if="!row._isGroupHeader" class="flex gap-2">
|
|
1103
|
+
<Button variant="outline" size="sm" @click="edit(row)">Edit</Button>
|
|
1104
|
+
<Button variant="destructive" size="sm" @click="remove(row)">Delete</Button>
|
|
1105
|
+
</div>
|
|
774
1106
|
</template>
|
|
775
1107
|
</SimpleTable>
|
|
776
1108
|
```
|
|
777
1109
|
|
|
778
|
-
|
|
1110
|
+
#### ⚠️ Important: Handling Group Headers
|
|
1111
|
+
|
|
1112
|
+
If you use **Group Headers**, your custom slots will technically be available for the header row too (though hidden by the colspan). To avoid errors accessing properties that don't exist on the header row, **always check `!row._isGroupHeader`**.
|
|
1113
|
+
|
|
1114
|
+
```vue
|
|
1115
|
+
<template #cell-price="{ row }">
|
|
1116
|
+
<!-- ❌ Bad: Might crash on header row where row.price is undefined -->
|
|
1117
|
+
${{ row.price.toFixed(2) }}
|
|
1118
|
+
|
|
1119
|
+
<!-- ✅ Good: Safe check -->
|
|
1120
|
+
<span v-if="!row._isGroupHeader">
|
|
1121
|
+
${{ row.price?.toFixed(2) }}
|
|
1122
|
+
</span>
|
|
1123
|
+
</template>
|
|
1124
|
+
```
|
|
779
1125
|
|
|
780
1126
|
---
|
|
781
1127
|
|
package/package.json
CHANGED
package/src/SimpleTable.vue
CHANGED
|
@@ -45,6 +45,7 @@ interface Props {
|
|
|
45
45
|
queryParams?: Record<string, any> // Additional parameters to send with every request (e.g., filters, user context)
|
|
46
46
|
|
|
47
47
|
// Style Props
|
|
48
|
+
rowHeight?: number // Table row height in pixels (default: 38)
|
|
48
49
|
oddRowColor?: string // Tailwind color class, e.g. 'bg-white'
|
|
49
50
|
evenRowColor?: string // Tailwind color class, e.g. 'bg-gray-50'
|
|
50
51
|
hoverColor?: string // Tailwind color class for hover, e.g. 'hover:bg-gray-100'. If passed, we'll try to apply group-hover for fixed cols.
|
|
@@ -60,6 +61,7 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
60
61
|
queryParams: () => ({}),
|
|
61
62
|
perPage: 10,
|
|
62
63
|
pageSizes: () => [10, 20, 30, 50, 100],
|
|
64
|
+
rowHeight: 38,
|
|
63
65
|
oddRowColor: 'bg-background',
|
|
64
66
|
evenRowColor: 'bg-background',
|
|
65
67
|
hoverColor: 'hover:bg-muted/50'
|
|
@@ -88,6 +90,37 @@ const normalizedPageSizes = computed(() => {
|
|
|
88
90
|
return []
|
|
89
91
|
})
|
|
90
92
|
|
|
93
|
+
// -- Computed: Row height-based sizing --
|
|
94
|
+
const densityConfig = computed(() => {
|
|
95
|
+
const height = props.rowHeight || 38
|
|
96
|
+
|
|
97
|
+
// Calculate padding based on height
|
|
98
|
+
// For 38px height: use p-2 (8px)
|
|
99
|
+
// For 48px height: use p-3 (12px)
|
|
100
|
+
// For 56px+ height: use p-4 (16px)
|
|
101
|
+
let cellPadding = 'p-2'
|
|
102
|
+
let headerPadding = 'px-2'
|
|
103
|
+
let groupHeaderPadding = 'py-1'
|
|
104
|
+
|
|
105
|
+
if (height >= 56) {
|
|
106
|
+
cellPadding = 'p-4'
|
|
107
|
+
headerPadding = 'px-4'
|
|
108
|
+
groupHeaderPadding = 'py-2'
|
|
109
|
+
} else if (height >= 44) {
|
|
110
|
+
cellPadding = 'p-3'
|
|
111
|
+
headerPadding = 'px-3'
|
|
112
|
+
groupHeaderPadding = 'py-1.5'
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
cellPadding,
|
|
117
|
+
cellHeight: `${height}px`,
|
|
118
|
+
headerHeight: `h-[${height}px]`,
|
|
119
|
+
headerPadding,
|
|
120
|
+
groupHeaderPadding
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
|
|
91
124
|
|
|
92
125
|
|
|
93
126
|
// <template>
|
|
@@ -722,12 +755,14 @@ function getCellStyle(col: any) {
|
|
|
722
755
|
<!-- We add min-w-full to Table to ensure it stretches -->
|
|
723
756
|
<Table class="min-w-full table-fixed">
|
|
724
757
|
<TableHeader>
|
|
725
|
-
<TableRow>
|
|
758
|
+
<TableRow :style="{ height: densityConfig.cellHeight }">
|
|
726
759
|
<TableHead
|
|
727
760
|
v-for="(col, idx) in columns"
|
|
728
761
|
:key="col.key"
|
|
729
762
|
:class="getCellClass(col, idx, columns.length)"
|
|
730
763
|
:style="getCellStyle(col)"
|
|
764
|
+
:height="densityConfig.headerHeight"
|
|
765
|
+
:padding="densityConfig.headerPadding"
|
|
731
766
|
>
|
|
732
767
|
<div
|
|
733
768
|
v-if="col.sortable"
|
|
@@ -757,11 +792,12 @@ function getCellStyle(col: any) {
|
|
|
757
792
|
:key="idx"
|
|
758
793
|
class="group"
|
|
759
794
|
:class="getRowClass(row, idx)"
|
|
795
|
+
:style="{ height: densityConfig.cellHeight }"
|
|
760
796
|
>
|
|
761
797
|
<!-- Group Header Row: Single cell spanning all columns -->
|
|
762
798
|
<template v-if="row._isGroupHeader">
|
|
763
799
|
<TableCell :colspan="columns.length" class="border-b border-gray-200">
|
|
764
|
-
<div class="px-2
|
|
800
|
+
<div :class="['px-2', densityConfig.groupHeaderPadding, 'font-semibold text-gray-700 text-sm uppercase tracking-wide']">
|
|
765
801
|
{{ row._groupTitle }}
|
|
766
802
|
</div>
|
|
767
803
|
</TableCell>
|
|
@@ -774,6 +810,8 @@ function getCellStyle(col: any) {
|
|
|
774
810
|
:key="col.key"
|
|
775
811
|
:class="getCellClass(col, cIdx, columns.length, idx)"
|
|
776
812
|
:style="getCellStyle(col)"
|
|
813
|
+
:padding="densityConfig.cellPadding"
|
|
814
|
+
:height="densityConfig.cellHeight"
|
|
777
815
|
>
|
|
778
816
|
<!-- Auto-numbering or custom cell rendering -->
|
|
779
817
|
<div>
|
|
@@ -790,7 +828,7 @@ function getCellStyle(col: any) {
|
|
|
790
828
|
</template>
|
|
791
829
|
</TableRow>
|
|
792
830
|
</template>
|
|
793
|
-
<TableRow v-else>
|
|
831
|
+
<TableRow v-else :style="{ height: densityConfig.cellHeight }">
|
|
794
832
|
<TableCell :colspan="columns.length" class="h-24 text-center">
|
|
795
833
|
No results.
|
|
796
834
|
</TableCell>
|
|
@@ -4,18 +4,29 @@ import { cn } from '@/lib/utils'
|
|
|
4
4
|
|
|
5
5
|
const props = defineProps<{
|
|
6
6
|
class?: HTMLAttributes['class']
|
|
7
|
+
style?: any
|
|
8
|
+
padding?: string
|
|
9
|
+
height?: string
|
|
7
10
|
}>()
|
|
8
11
|
|
|
9
12
|
const delegatedProps = computed(() => {
|
|
10
|
-
const { class: _, ...delegated } = props
|
|
13
|
+
const { class: _, padding: __, height: ___, style: ____, ...delegated } = props
|
|
11
14
|
|
|
12
15
|
return delegated
|
|
13
16
|
})
|
|
17
|
+
|
|
18
|
+
const cellStyle = computed(() => {
|
|
19
|
+
const baseStyle = (props as any).style || {}
|
|
20
|
+
const heightStyle = props.height ? { minHeight: props.height } : {}
|
|
21
|
+
|
|
22
|
+
return { ...baseStyle, ...heightStyle }
|
|
23
|
+
})
|
|
14
24
|
</script>
|
|
15
25
|
|
|
16
26
|
<template>
|
|
17
27
|
<td
|
|
18
|
-
:class="cn('p-
|
|
28
|
+
:class="cn(props.padding || 'p-2', 'align-middle [&:has([role=checkbox])]:pr-0', props.class)"
|
|
29
|
+
:style="cellStyle"
|
|
19
30
|
v-bind="delegatedProps"
|
|
20
31
|
>
|
|
21
32
|
<slot />
|
|
@@ -4,10 +4,12 @@ import { cn } from '@/lib/utils'
|
|
|
4
4
|
|
|
5
5
|
const props = defineProps<{
|
|
6
6
|
class?: HTMLAttributes['class']
|
|
7
|
+
height?: string
|
|
8
|
+
padding?: string
|
|
7
9
|
}>()
|
|
8
10
|
|
|
9
11
|
const delegatedProps = computed(() => {
|
|
10
|
-
const { class: _, ...delegated } = props
|
|
12
|
+
const { class: _, height: __, padding: ___, ...delegated } = props
|
|
11
13
|
|
|
12
14
|
return delegated
|
|
13
15
|
})
|
|
@@ -17,7 +19,9 @@ const delegatedProps = computed(() => {
|
|
|
17
19
|
<th
|
|
18
20
|
:class="
|
|
19
21
|
cn(
|
|
20
|
-
'h-
|
|
22
|
+
props.height || 'h-[38px]',
|
|
23
|
+
props.padding || 'px-2',
|
|
24
|
+
'text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0',
|
|
21
25
|
props.class,
|
|
22
26
|
)
|
|
23
27
|
"
|