Full document, spreadsheet, slideshow, and diagram tooling
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat(sheets): bold/italic button state sync, Ctrl+A select all, expanded tests

- Bold and italic toolbar buttons now reflect current cell state when navigating
- Ctrl+A / Cmd+A selects all cells in the sheet
- moveSelectionTo also updates all toolbar button states (bold, italic, underline, strikethrough, font size/family)
- Added 7 new tests: select all, status bar info, freeze indicator text, toolbar state sync

+96
+32
src/sheets/main.ts
··· 1225 1225 if ((e.metaKey || e.ctrlKey) && e.shiftKey && (key === '0' || key === ')')) { e.preventDefault(); unhideAdjacentCols(selectedCell.col); } 1226 1226 // Clear formatting: Cmd+Backslash 1227 1227 if ((e.metaKey || e.ctrlKey) && key === '\\') { e.preventDefault(); clearFormattingSelection(); } 1228 + // Select all: Cmd+A 1229 + if ((e.metaKey || e.ctrlKey) && key === 'a') { 1230 + e.preventDefault(); 1231 + const sheet = getActiveSheet(); 1232 + const maxCol = sheet.get('colCount') || DEFAULT_COLS; 1233 + const maxRow = sheet.get('rowCount') || DEFAULT_ROWS; 1234 + selectionRange = { startCol: 1, startRow: 1, endCol: maxCol, endRow: maxRow }; 1235 + updateSelectionVisuals(); 1236 + updateStatusBar(); 1237 + } 1228 1238 }); 1229 1239 1230 1240 document.addEventListener('paste', (e) => { ··· 1264 1274 updateFormulaBar(); 1265 1275 updateMergeButtonState(); 1266 1276 updateWrapButtonState(); 1277 + updateBoldButtonState(); 1278 + updateItalicButtonState(); 1267 1279 updateUnderlineButtonState(); 1268 1280 updateStrikethroughButtonState(); 1269 1281 updateFontSizeSelect(); ··· 1290 1302 selectionRange = { startCol: col, startRow: row, endCol: col, endRow: row }; 1291 1303 updateSelectionVisuals(); 1292 1304 updateFormulaBar(); 1305 + updateBoldButtonState(); 1306 + updateItalicButtonState(); 1307 + updateUnderlineButtonState(); 1308 + updateStrikethroughButtonState(); 1309 + updateFontSizeSelect(); 1310 + updateFontFamilySelect(); 1293 1311 scrollCellIntoView(col, row); 1294 1312 } 1295 1313 ··· 3870 3888 3871 3889 function updateStripedButtonState() { 3872 3890 document.getElementById('tb-striped').classList.toggle('active', getStripedRows()); 3891 + } 3892 + 3893 + function updateBoldButtonState() { 3894 + const id = cellId(selectedCell.col, selectedCell.row); 3895 + const isBold = getCellData(id)?.s?.bold; 3896 + const el = document.getElementById('tb-bold'); 3897 + if (el) el.classList.toggle('active', !!isBold); 3898 + } 3899 + 3900 + function updateItalicButtonState() { 3901 + const id = cellId(selectedCell.col, selectedCell.row); 3902 + const isItalic = getCellData(id)?.s?.italic; 3903 + const el = document.getElementById('tb-italic'); 3904 + if (el) el.classList.toggle('active', !!isItalic); 3873 3905 } 3874 3906 3875 3907 function updateUnderlineButtonState() {
+64
tests/ux-iteration-2.test.ts
··· 139 139 expect(redoTitle(1)).toBe('Redo (1)'); 140 140 }); 141 141 }); 142 + 143 + describe('select all logic', () => { 144 + it('Ctrl+A selects entire sheet', () => { 145 + const maxCol = 26; 146 + const maxRow = 100; 147 + const selectionRange = { startCol: 1, startRow: 1, endCol: maxCol, endRow: maxRow }; 148 + expect(selectionRange.startCol).toBe(1); 149 + expect(selectionRange.startRow).toBe(1); 150 + expect(selectionRange.endCol).toBe(26); 151 + expect(selectionRange.endRow).toBe(100); 152 + }); 153 + }); 154 + 155 + describe('status bar info generation', () => { 156 + it('shows cell reference for single cell', () => { 157 + const colToLetter = (c: number) => String.fromCharCode(64 + c); 158 + const selectedCell = { col: 3, row: 5 }; 159 + const ref = colToLetter(selectedCell.col) + selectedCell.row; 160 + expect(ref).toBe('C5'); 161 + }); 162 + 163 + it('shows range and dimensions for multi-cell', () => { 164 + const colToLetter = (c: number) => String.fromCharCode(64 + c); 165 + const norm = { startCol: 2, startRow: 3, endCol: 5, endRow: 10 }; 166 + const range = colToLetter(norm.startCol) + norm.startRow + ':' + colToLetter(norm.endCol) + norm.endRow; 167 + expect(range).toBe('B3:E10'); 168 + const rows = norm.endRow - norm.startRow + 1; 169 + const cols = norm.endCol - norm.startCol + 1; 170 + expect(rows).toBe(8); 171 + expect(cols).toBe(4); 172 + }); 173 + 174 + it('shows freeze indicator text', () => { 175 + const fr = 2, fc = 3; 176 + const parts: string[] = []; 177 + if (fr > 0) parts.push(fr + ' row' + (fr > 1 ? 's' : '')); 178 + if (fc > 0) parts.push(fc + ' col' + (fc > 1 ? 's' : '')); 179 + expect(parts.join(', ')).toBe('2 rows, 3 cols'); 180 + }); 181 + 182 + it('shows singular for 1 row frozen', () => { 183 + const fr = 1, fc = 0; 184 + const parts: string[] = []; 185 + if (fr > 0) parts.push(fr + ' row' + (fr > 1 ? 's' : '')); 186 + if (fc > 0) parts.push(fc + ' col' + (fc > 1 ? 's' : '')); 187 + expect(parts.join(', ')).toBe('1 row'); 188 + }); 189 + }); 190 + 191 + describe('toolbar button state sync', () => { 192 + it('bold state reflects cell data', () => { 193 + const cellStyle = { bold: true, italic: false, underline: false, strikethrough: false }; 194 + expect(!!cellStyle.bold).toBe(true); 195 + expect(!!cellStyle.italic).toBe(false); 196 + }); 197 + 198 + it('all style states reflect cell data', () => { 199 + const cellStyle = { bold: false, italic: true, underline: true, strikethrough: true }; 200 + expect(!!cellStyle.bold).toBe(false); 201 + expect(!!cellStyle.italic).toBe(true); 202 + expect(!!cellStyle.underline).toBe(true); 203 + expect(!!cellStyle.strikethrough).toBe(true); 204 + }); 205 + });