# 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([]); ``` **After:** ```typescript const selectedAssets = ref>({}); ``` ### 2. Select All Checkbox **Before:** ```vue ``` **After:** ```vue ``` 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 ``` **After:** ```vue ``` ### 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.