root
Working CHanges to revesion ; add preact support
e8a57cb
/**
* Data Table Component with Selection & Inline Editing
* For dashboard-like interfaces
*/
const { useState, useEffect, useMemo } = window.PreactLib || {};
export function DashboardTable({
data = [],
columns = [],
onSelectionChange,
onRowUpdate,
onRowDelete,
actions = [],
className = ''
}) {
const html = window.html;
const [selectedIds, setSelectedIds] = useState(new Set());
const [editingId, setEditingId] = useState(null);
const [editValue, setEditValue] = useState('');
const allSelected = data.length > 0 && selectedIds.size === data.length;
const someSelected = selectedIds.size > 0 && selectedIds.size < data.length;
const toggleSelectAll = () => {
if (allSelected) {
setSelectedIds(new Set());
} else {
setSelectedIds(new Set(data.map(row => row.id)));
}
};
const toggleSelect = (id) => {
const newSelected = new Set(selectedIds);
if (newSelected.has(id)) {
newSelected.delete(id);
} else {
newSelected.add(id);
}
setSelectedIds(newSelected);
};
const startEditing = (row, columnKey) => {
setEditingId(row.id);
setEditValue(row[columnKey]);
};
const saveEdit = (columnKey) => {
if (onRowUpdate) {
onRowUpdate(editingId, { [columnKey]: editValue });
}
setEditingId(null);
};
const cancelEdit = () => {
setEditingId(null);
setEditValue('');
};
useEffect(() => {
if (onSelectionChange) {
onSelectionChange(Array.from(selectedIds));
}
}, [selectedIds]);
return html`
<div class="table-responsive ${className}">
<table class="table table-hover table-striped">
<thead>
<tr>
<th style="width: 3%;">
<input
type="checkbox"
class="form-check-input"
checked=${allSelected}
indeterminate=${someSelected}
onChange=${toggleSelectAll}
/>
</th>
${columns.map(col => html`
<th scope="col" style="${col.style || ''}">${col.header}</th>
`)}
${actions.length > 0 ? html`<th scope="col">Actions</th>` : ''}
</tr>
</thead>
<tbody>
${data.length === 0 ? html`
<tr>
<td colSpan=${columns.length + 2} class="text-center py-4 text-muted">
No data available
</td>
</tr>
` : data.map(row => html`
<tr key=${row.id} class="${selectedIds.has(row.id) ? 'table-active' : ''}">
<td>
<input
type="checkbox"
class="form-check-input"
checked=${selectedIds.has(row.id)}
onChange=${() => toggleSelect(row.id)}
/>
</td>
${columns.map(col => html`
<td>
${editingId === row.id && col.editable ? html`
<div class="input-group input-group-sm">
<input
type="text"
class="form-control"
value=${editValue}
onInput=${(e) => setEditValue(e.target.value)}
onBlur=${() => saveEdit(col.key)}
onKeyDown=${(e) => {
if (e.key === 'Enter') saveEdit(col.key);
if (e.key === 'Escape') cancelEdit();
}}
autofocus
/>
</div>
` : html`
<div
style="${col.editable ? 'cursor: pointer;' : ''}"
onClick=${() => col.editable && startEditing(row, col.key)}
>
${col.render ? col.render(row[col.key], row) : row[col.key]}
${col.editable ? html`<i class="fas fa-pencil-alt ms-2 text-muted" style="font-size: 0.8rem;"></i>` : ''}
</div>
`}
</td>
`)}
${actions.length > 0 ? html`
<td>
<div class="btn-group btn-group-sm">
${actions.map(action => {
// Skip hidden actions
if (action.hidden && action.hidden(row)) {
return null;
}
return html`
<button
class="btn ${action.variant || 'btn-outline-primary'}"
title=${action.title || action.label}
onClick=${(e) => {
e.stopPropagation();
action.onClick(row);
}}
>
${action.icon ? html`<i class="${action.icon}"></i>` : action.label}
</button>
`;
})}
</div>
</td>
` : ''}
</tr>
`)}
</tbody>
</table>
</div>
`;
}
// === Filter Tabs Component ===
export function FilterTabs({
filters = [],
activeFilter = 'all',
onChange,
className = ''
}) {
const html = window.html;
return html`
<ul class="nav nav-pills mb-3 ${className}">
${filters.map(filter => html`
<li class="nav-item">
<button
class="nav-link ${activeFilter === filter.value ? 'active' : ''}"
onClick=${() => onChange(filter.value)}
>
${filter.icon ? html`<i class="${filter.icon} me-1"></i>` : ''}
${filter.label}
</button>
</li>
`)}
</ul>
`;
}
// === Bulk Actions Bar ===
export function BulkActionsBar({
selectedCount = 0,
actions = [],
onClearSelection,
className = ''
}) {
const html = window.html;
if (selectedCount === 0) return null;
return html`
<div class="alert alert-info d-flex align-items-center justify-content-between ${className}">
<span>
<i class="bi bi-check-circle-fill me-2"></i>
<strong>${selectedCount}</strong> item${selectedCount > 1 ? 's' : ''} selected
</span>
<div class="btn-group">
${actions.map(action => html`
<button
class="btn ${action.variant || 'btn-outline-primary'}"
onClick=${action.onClick}
>
${action.icon ? html`<i class="${action.icon} me-1"></i>` : ''}
${action.label}
</button>
`)}
<button
class="btn btn-outline-secondary"
onClick=${onClearSelection}
>
<i class="bi bi-x-lg me-1"></i>Clear
</button>
</div>
</div>
`;
}
export default DashboardTable;