Skip to content

Commit

Permalink
v0.36.0 fix, import from bitbucket
Browse files Browse the repository at this point in the history
  • Loading branch information
icecream17 authored Apr 23, 2024
1 parent 2c5e285 commit ae552ba
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 38 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ Note: Many earlier versions are not specified, that's too much work.

When a `@types` dependency updates, they almost always don't affect anything.

## v0.36.0

- (use) Fix ANOTHER massive bug: editing multiple cells now works and is consistent with the visuals
- (use) Ctrl+A to select all cells

## v0.35.1

- (use) Fix massive bug in cell keyboard nagivation, where pressing an arrow key would focus the next cell and select the next next cell
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "solver",
"version": "0.35.1",
"version": "0.36.0",
"private": true,
"homepage": "https://icecream17.github.io/solver",
"dependencies": {
Expand Down
6 changes: 5 additions & 1 deletion src/Elems/MainElems/Cell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,11 @@ export default class Cell extends React.Component<CellProps, CellState> {
}))
}

// cell blur --> this is called for all selected cells
syncNewCandidates() {
this.props.whenNewCandidates(this, this.state.candidates)
}

// setState for both of these is called in the when handlers through updateSelectionStatus,
// but should be consistent with the commented out code
whenFocus(event: React.FocusEvent) {
Expand All @@ -339,7 +344,6 @@ export default class Cell extends React.Component<CellProps, CellState> {
}

whenBlur(event: React.FocusEvent) {
this.props.whenNewCandidates(this, this.state.candidates)
this.props.whenCellBlur(this, event)
// this.setState({
// active: false,
Expand Down
14 changes: 12 additions & 2 deletions src/Elems/MainElems/Sudoku.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@
import { fireEvent, render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import App from '../../App';
import { IndexToNine } from '../../Types';
import { INDICES_TO_NINE, IndexToNine } from '../../Types';
import { getButtonCellElement, getTableCellElement } from './Sudoku.testUtils';
import { keysPressed } from '../../keyboardListener';

function tryKey (keyboard: string, row: IndexToNine, column: IndexToNine) {
userEvent.keyboard(keyboard)
expect(getButtonCellElement(row, column)).toHaveFocus()
}

beforeEach(() => {
render(<App />);
render(<App />)
keysPressed.clear() // TODO: This should not be needed, test this!
})

// The name === 'Sudoku' because aria-label === 'Sudoku'
Expand Down Expand Up @@ -67,6 +69,14 @@ test("Focused buttonCells are highlighted", () => {
userEvent.keyboard('{/Control}{Escape}')
expect(buttonCell).not.toHaveAttribute('data-active') // not selected
expect(buttonCell2).not.toHaveAttribute('data-active') // not selected

userEvent.click(buttonCell)
userEvent.keyboard('{Control>}a{/Control}')
for (const row of INDICES_TO_NINE) {
for (const col of INDICES_TO_NINE) {
expect(getButtonCellElement(row, col)).toHaveAttribute('data-active')
}
}
})

test("Setting a cell to a digit", () => {
Expand Down
75 changes: 42 additions & 33 deletions src/Elems/MainElems/Sudoku.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React from 'react'

import Row from './Row'
import Cell from './Cell'
import { CouldAIsB, IndexToNine, SudokuDigits, _Callback } from '../../Types'
import { CouldAIsB, INDICES_TO_NINE, IndexToNine, SudokuDigits, _Callback } from '../../Types'
import { CellID, id } from '../../Api/Utils'
import SudokuData from '../../Api/Spaces/Sudoku'
import { keysPressed } from '../../keyboardListener'
Expand Down Expand Up @@ -62,7 +62,7 @@ export default class Sudoku extends React.Component<SudokuProps> {

this.cellsSelected = new Set<CellID>()
this.selectionStatus = null
this.listener = this.listener.bind(this)
// this.listener = this.listener.bind(this)

this.whenCellBlur = this.whenCellBlur.bind(this)
this.whenCellFocus = this.whenCellFocus.bind(this)
Expand Down Expand Up @@ -106,9 +106,9 @@ export default class Sudoku extends React.Component<SudokuProps> {
)
}

listener() {
// TODO
}
// listener() {
// // TODO
// }

syncSelectionStatus() {
for (const row of this.props.sudoku.cells) {
Expand All @@ -121,6 +121,16 @@ export default class Sudoku extends React.Component<SudokuProps> {
}
}

syncSelectionCandidates() {
for (const row of this.props.sudoku.cells) {
for (const cell of row) {
if (cell != null && this.cellsSelected.has(cell.id)) {
cell.syncNewCandidates()
}
}
}
}

/**
* Implicitly blurs the previously focused cell
* INCOMPLETELY DOCUMENTED BUG: This focuses the element, but often the
Expand All @@ -129,13 +139,6 @@ export default class Sudoku extends React.Component<SudokuProps> {
this.getCellElement(row, column).focus()
}

focusIfTargetMovedAndAddToSelection(row: IndexToNine, column: IndexToNine, targetMoved: boolean, newSelected: Set<CellID>) {
if (targetMoved) {
this.focusCell(row, column)
}
newSelected.add(id(row, column))
}

isCellElement(element: null | Element): CouldAIsB<typeof element, HTMLButtonElement> {
// button, td, row, tbody
return element?.parentElement?.parentElement?.parentElement === this.tbodyElement
Expand Down Expand Up @@ -181,27 +184,19 @@ export default class Sudoku extends React.Component<SudokuProps> {
this.syncSelectionStatus()
}

whenCellBlur(cell: Cell, event: React.FocusEvent) {
whenCellBlur(_cell: Cell, _event: React.FocusEvent) {
// console.debug("blur", cell.id)
// When <kbd>Escape</kbd> blurs a cell, the selection could be empty
// in which case, do nothing
if (this.selectionStatus === null) {
return
}

const toAnotherElement = this.isCellElement(event.relatedTarget)
const ctrlMultiselect = keysPressed.has('Control') && !keysPressed.has('Tab')

if (toAnotherElement) {
if (!ctrlMultiselect) {
this.cellsSelected.delete(cell.id)
}
// this.selectionStatus = true
} else {
this.selectionStatus = false
}

// if another cell is selected, it will clear selectedness for the rest of the cells
// until then, the cell stays inactively selected
this.selectionStatus = false
this.syncSelectionStatus()
this.syncSelectionCandidates()
}

/**
Expand Down Expand Up @@ -230,17 +225,26 @@ export default class Sudoku extends React.Component<SudokuProps> {

const newSelected = new Set<CellID>()

const target = event.target as HTMLDivElement
const target = event.target as HTMLDivElement // only used in Escape
const shiftHeld = keysPressed.has('Shift')
const ctrlHeld = keysPressed.has('Control')

// Ctrl+A = Select all
if (ctrlHeld && keysPressed.has('a')) {
for (const row of INDICES_TO_NINE) {
for (const col of INDICES_TO_NINE) {
this.cellsSelected.add(id(row, col))
}
}
}

// eslint-disable-next-line unicorn/no-useless-spread -- Copy/save previous cells selected, since it changes during the loop
for (let {row, column} of [...this.cellsSelected]) {
let cell = this.props.sudoku.cells[row][column]
const wasTarget = cell === targetCell

for (const key of keysToProcess) {
if (cell == null) {
if (cell == null) { // `cell` may change within the loop, so the check is also within the loop
break
}

Expand Down Expand Up @@ -270,19 +274,19 @@ export default class Sudoku extends React.Component<SudokuProps> {
} else {
// Keyboard movements
if (key in keyboardMappings) {
const step = keyboardMappings[(key as keyof typeof keyboardMappings)];
const step = keyboardMappings[key as keyof typeof keyboardMappings];

row = (row + 9 + step.vRow) % 9 as IndexToNine
column = (column + 9 + step.vColumn) % 9 as IndexToNine
} else if (key === 'Home') {
if (event.ctrlKey) {
if (ctrlHeld) {
row = 0
column = 0
} else {
column = 0
}
} else if (key === 'End') {
if (event.ctrlKey) {
if (ctrlHeld) {
row = 8
column = 8
} else {
Expand All @@ -300,9 +304,14 @@ export default class Sudoku extends React.Component<SudokuProps> {
}
}

// Due to keyboard movements, the original location may have moved to a new location.
// This new location is reflected by row and column
this.focusIfTargetMovedAndAddToSelection(row, column, wasTarget && cell !== targetCell, newSelected)
// Due to keyboard movements, the original focus may have moved to a new focus.
const targetMoved = wasTarget && cell !== targetCell
if (targetMoved) {
this.focusCell(row, column)
}

// Even if not focused we select the new cell after the movement
newSelected.add(id(row, column))
}

this.cellsSelected = newSelected
Expand Down
2 changes: 1 addition & 1 deletion src/Elems/Version.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import StaticComponent from './StaticComponent';
* <Version />
*/
function Version () {
return <span className="Version">v0.35.1</span>
return <span className="Version">v0.36.0</span>
}

export default StaticComponent(Version)

0 comments on commit ae552ba

Please sign in to comment.