Init Repo
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
# Checkbox Selection Refactor
|
||||
|
||||
## Overview
|
||||
Refactored the AssetBrowser component to use a cleaner, more Vue-friendly approach for checkbox selection using object-based state instead of array-based state. This leverages the native v-model support in shadcn-vue Checkbox components (based on reka-ui).
|
||||
|
||||
## Changes Made
|
||||
|
||||
### 1. Selection State Structure
|
||||
**Before:**
|
||||
```typescript
|
||||
const selectedAssets = ref<number[]>([]);
|
||||
```
|
||||
|
||||
**After:**
|
||||
```typescript
|
||||
const selectedAssets = ref<Record<number, boolean>>({});
|
||||
```
|
||||
|
||||
### 2. Select All Checkbox
|
||||
**Before:**
|
||||
```vue
|
||||
<Checkbox
|
||||
:checked="isAllSelected"
|
||||
@update:checked="toggleSelectAll"
|
||||
/>
|
||||
```
|
||||
|
||||
**After:**
|
||||
```vue
|
||||
<Checkbox v-model="selectAllChecked" />
|
||||
```
|
||||
|
||||
With computed property (getter/setter pattern):
|
||||
```typescript
|
||||
const selectAllChecked = computed({
|
||||
get: () => {
|
||||
return filteredAssets.value.length > 0 &&
|
||||
filteredAssets.value.every(asset => selectedAssets.value[asset.id]);
|
||||
},
|
||||
set: (checked: boolean) => {
|
||||
toggleSelectAll(checked);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
The computed property's setter is automatically called by v-model, eliminating the need for a separate event handler.
|
||||
|
||||
### 3. Row Checkboxes
|
||||
**Before:**
|
||||
```vue
|
||||
<Checkbox
|
||||
:checked="selectedAssets.includes(asset.id)"
|
||||
@update:checked="(checked) => toggleAssetSelection(asset.id, checked)"
|
||||
@click.stop
|
||||
/>
|
||||
```
|
||||
|
||||
**After:**
|
||||
```vue
|
||||
<Checkbox
|
||||
v-model="selectedAssets[asset.id]"
|
||||
@click.stop
|
||||
/>
|
||||
```
|
||||
|
||||
### 4. Helper Methods
|
||||
|
||||
**New method to get selected IDs:**
|
||||
```typescript
|
||||
const getSelectedAssetIds = () => {
|
||||
return Object.keys(selectedAssets.value)
|
||||
.filter(id => selectedAssets.value[Number(id)])
|
||||
.map(id => Number(id));
|
||||
};
|
||||
```
|
||||
|
||||
**Simplified toggleSelectAll:**
|
||||
```typescript
|
||||
const toggleSelectAll = (checked: boolean) => {
|
||||
filteredAssets.value.forEach(asset => {
|
||||
selectedAssets.value[asset.id] = checked;
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
### 5. Row Selection Logic
|
||||
Updated to work with object-based state:
|
||||
```typescript
|
||||
const handleRowClick = (asset: Asset, event: MouseEvent) => {
|
||||
if (event.ctrlKey || event.metaKey) {
|
||||
// Multi-select with Ctrl/Cmd - toggle selection
|
||||
selectedAssets.value[asset.id] = !selectedAssets.value[asset.id];
|
||||
} else if (event.shiftKey && getSelectedAssetIds().length > 0) {
|
||||
// Range select with Shift
|
||||
const selectedIds = getSelectedAssetIds();
|
||||
const lastSelectedId = selectedIds[selectedIds.length - 1];
|
||||
// ... range selection logic
|
||||
} else {
|
||||
// Single select
|
||||
selectAsset(asset);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Benefits
|
||||
|
||||
1. **Direct v-model Binding**: The shadcn-vue Checkbox (based on reka-ui) supports `v-model` natively when bound to a boolean value ([reka-ui issue #1017](https://github.com/unovue/reka-ui/issues/1017))
|
||||
2. **Simpler Code**: No need for manual event handlers - v-model handles everything
|
||||
3. **Better Performance**: Direct property access (`selectedAssets[id]`) is faster than array operations (`.includes()`, `.push()`, `.splice()`)
|
||||
4. **More Reactive**: Vue's reactivity system handles object property changes efficiently
|
||||
5. **Cleaner API**: The checkbox state is directly tied to the data structure
|
||||
6. **No Redundant Handlers**: Using v-model eliminates the need for separate event handlers
|
||||
|
||||
## Testing
|
||||
|
||||
A test file (`frontend/test-asset-selection.html`) has been created to demonstrate the pattern working with plain Vue and native HTML checkboxes.
|
||||
|
||||
To test:
|
||||
1. Open `frontend/test-asset-selection.html` in a browser
|
||||
2. Try selecting individual checkboxes
|
||||
3. Try the "Select All" checkbox
|
||||
4. Try the action buttons (Select All, Deselect All, Select First 3)
|
||||
5. Verify the selection info updates correctly
|
||||
|
||||
## Migration Notes
|
||||
|
||||
Any code that previously used `selectedAssets.value` as an array needs to be updated:
|
||||
- Use `getSelectedAssetIds()` to get an array of selected IDs
|
||||
- Use `selectedAssets.value[id]` to check if an asset is selected
|
||||
- Use `selectedAssets.value = {}` to clear all selections
|
||||
|
||||
## Important Notes
|
||||
|
||||
### v-model vs v-model:checked
|
||||
|
||||
According to [reka-ui issue #1017](https://github.com/unovue/reka-ui/issues/1017), the correct syntax is:
|
||||
- ✅ Use `v-model` (not `v-model:checked`)
|
||||
- ✅ Works with boolean values directly
|
||||
- ✅ No need for `:checked` + `@update:checked` patterns
|
||||
|
||||
### When to Use Event Handlers
|
||||
|
||||
When using Checkbox with props that need to emit to parent (like in ColumnVisibilityControl), you may still need `@update:checked` handlers to emit changes to the parent component, since props are not directly mutable. However, for local state management (like in AssetBrowser), pure v-model is sufficient.
|
||||
Reference in New Issue
Block a user