Explorar el Código

Merge pull request #14763 from overleaf/mj-extend-col-row-selectors

[visual] Allow shift clicking column and row selectors

GitOrigin-RevId: 2e6191741681196e4af462f92dc60268f22d137e
Mathias Jakobsen hace 3 años
padre
commit
1e3f305ba3

+ 9 - 2
services/web/frontend/js/features/source-editor/components/table-generator/contexts/selection-context.tsx

@@ -30,13 +30,20 @@ export class TableSelection {
     )
   }
 
-  static selectRow(row: number, table: TableData) {
+  selectRow(row: number, extend: boolean, table: TableData) {
     return new TableSelection(
-      { row, cell: 0 },
+      { row: extend ? this.from.row : row, cell: 0 },
       { row, cell: table.columns.length - 1 }
     )
   }
 
+  selectColumn(column: number, extend: boolean, table: TableData) {
+    return new TableSelection(
+      { row: 0, cell: extend ? this.from.cell : column },
+      { row: table.rows.length - 1, cell: column }
+    )
+  }
+
   normalized() {
     const minX = Math.min(this.from.cell, this.to.cell)
     const maxX = Math.max(this.from.cell, this.to.cell)

+ 33 - 12
services/web/frontend/js/features/source-editor/components/table-generator/selectors.tsx

@@ -1,4 +1,4 @@
-import { useCallback } from 'react'
+import { MouseEventHandler, useCallback } from 'react'
 import {
   TableSelection,
   useSelectionContext,
@@ -9,14 +9,22 @@ import { useTableContext } from './contexts/table-context'
 export const ColumnSelector = ({ index }: { index: number }) => {
   const { selection, setSelection } = useSelectionContext()
   const { table } = useTableContext()
-  const onColumnSelect = useCallback(() => {
-    setSelection(
-      new TableSelection(
-        { row: 0, cell: index },
-        { row: table.rows.length - 1, cell: index }
-      )
-    )
-  }, [table.rows.length, index, setSelection])
+  const onColumnSelect: MouseEventHandler = useCallback(
+    event => {
+      event.preventDefault()
+      if (!selection) {
+        setSelection(
+          new TableSelection(
+            { row: 0, cell: index },
+            { row: table.rows.length - 1, cell: index }
+          )
+        )
+        return
+      }
+      setSelection(selection.selectColumn(index, event.shiftKey, table))
+    },
+    [index, setSelection, selection, table]
+  )
   const fullySelected = selection?.isColumnSelected(index, table)
   return (
     // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions
@@ -32,9 +40,22 @@ export const ColumnSelector = ({ index }: { index: number }) => {
 export const RowSelector = ({ index }: { index: number }) => {
   const { table } = useTableContext()
   const { selection, setSelection } = useSelectionContext()
-  const onSelect = useCallback(() => {
-    setSelection(TableSelection.selectRow(index, table))
-  }, [index, setSelection, table])
+  const onSelect: MouseEventHandler = useCallback(
+    event => {
+      event.preventDefault()
+      if (!selection) {
+        setSelection(
+          new TableSelection(
+            { row: index, cell: 0 },
+            { row: index, cell: table.columns.length - 1 }
+          )
+        )
+        return
+      }
+      setSelection(selection.selectRow(index, event.shiftKey, table))
+    },
+    [index, setSelection, table, selection]
+  )
   const fullySelected = selection?.isRowSelected(index, table)
   return (
     // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions

+ 44 - 0
services/web/test/frontend/features/source-editor/components/codemirror-editor-table-generator.spec.tsx

@@ -588,5 +588,49 @@ cell 3 & cell 4 \\\\
       cy.get('@cell-2').tab({ shift: true })
       cy.get('@cell-1').should('have.focus').should('have.class', 'selected')
     })
+
+    it('Can select rows and columns with selectors', function () {
+      mountEditor(`
+\\begin{tabular}{cc }
+  cell 1 & cell 2\\\\
+  cell 3 & cell 4 \\\\
+\\end{tabular}`)
+      cy.get('.table-generator-cell').eq(0).as('cell-1')
+      cy.get('.table-generator-cell').eq(1).as('cell-2')
+      cy.get('.table-generator-cell').eq(2).as('cell-3')
+      cy.get('.table-generator-cell').eq(3).as('cell-4')
+
+      cy.get('.column-selector').eq(0).click()
+      cy.get('@cell-1').should('have.class', 'selected')
+      cy.get('@cell-2').should('not.have.class', 'selected')
+      cy.get('@cell-3').should('have.class', 'selected')
+      cy.get('@cell-4').should('not.have.class', 'selected')
+      cy.get('.column-selector').eq(1).click()
+      cy.get('@cell-1').should('not.have.class', 'selected')
+      cy.get('@cell-2').should('have.class', 'selected')
+      cy.get('@cell-3').should('not.have.class', 'selected')
+      cy.get('@cell-4').should('have.class', 'selected')
+      cy.get('.column-selector').eq(0).click({ shiftKey: true })
+      cy.get('@cell-1').should('have.class', 'selected')
+      cy.get('@cell-2').should('have.class', 'selected')
+      cy.get('@cell-3').should('have.class', 'selected')
+      cy.get('@cell-4').should('have.class', 'selected')
+
+      cy.get('.row-selector').eq(0).click()
+      cy.get('@cell-1').should('have.class', 'selected')
+      cy.get('@cell-2').should('have.class', 'selected')
+      cy.get('@cell-3').should('not.have.class', 'selected')
+      cy.get('@cell-4').should('not.have.class', 'selected')
+      cy.get('.row-selector').eq(1).click()
+      cy.get('@cell-1').should('not.have.class', 'selected')
+      cy.get('@cell-2').should('not.have.class', 'selected')
+      cy.get('@cell-3').should('have.class', 'selected')
+      cy.get('@cell-4').should('have.class', 'selected')
+      cy.get('.row-selector').eq(0).click({ shiftKey: true })
+      cy.get('@cell-1').should('have.class', 'selected')
+      cy.get('@cell-2').should('have.class', 'selected')
+      cy.get('@cell-3').should('have.class', 'selected')
+      cy.get('@cell-4').should('have.class', 'selected')
+    })
   })
 })