Repository: streamlit/streamlit
File: frontend/lib/src/components/widgets/DataFrame/hooks/useDataEditor.ts (TypeScript)

Code before:
          lastUpdated: performance.now(),
        })

        syncEditState()
      } else {
        LOG.warn(
          `Not applying the cell edit since it causes this error:\n ${newCell.data}`
        )
      }
    },
    [columns, editingState, getOriginalIndex, getCellContent, syncEditState]
  )

  /**
   * Appends a new empty row to the end of the table.
   */
  const appendEmptyRow = useCallback(() => {
    if (!canAddRows) {
      // Appending rows is not supported
      return
    }

    const newRow: Map<number, GridCell> = new Map()
    // We use allColumns (including hidden columns) to ensure that
    // cells are created for all columns. This prevents issues when
    // a hidden column is later made visible.
    allColumns.forEach(column => {
      // For the default value, we trust the developer to make a valid choice,
      // so we do not validate the value here.
      newRow.set(column.indexNumber, column.getCell(column.defaultValue))
    })
    editingState.current.addRow(newRow)
    updateNumRows()
  }, [allColumns, editingState, canAddRows, updateNumRows])

  /**
   * Callback used by glide-data-grid when the user adds a new row in the table UI.
   */
  const onRowAppended = useCallback(() => {
    if (!canAddRows) {
      // Appending rows is not supported
      return
    }

    appendEmptyRow()
    syncEditState()
  }, [appendEmptyRow, syncEditState, canAddRows])

  /**
   * Callback used by glide-data-grid when the user deletes a row or cell value in the table UI.
   */

Review comment (bug):
**nit:** Could consider linking back to the original bug report in the comments for more context: https://github.com/streamlit/streamlit/pull/13916/

Code after:
          lastUpdated: performance.now(),
        })

        syncEditState()
      } else {
        LOG.warn(
          `Not applying the cell edit since it causes this error:\n ${newCell.data}`
        )
      }
    },
    [columns, editingState, getOriginalIndex, getCellContent, syncEditState]
  )

  /**
   * Appends a new empty row to the end of the table.
   */
  const appendEmptyRow = useCallback(() => {
    if (!canAddRows) {
      // Appending rows is not supported
      return
    }

    const newRow: Map<number, GridCell> = new Map()
    // We use allColumns (including hidden columns) to ensure that
    // cells are created for all columns. This prevents issues when
    // a hidden column is later made visible (see issue #13915).
    allColumns.forEach(column => {
      // For the default value, we trust the developer to make a valid choice,
      // so we do not validate the value here.
      newRow.set(column.indexNumber, column.getCell(column.defaultValue))
    })
    editingState.current.addRow(newRow)
    updateNumRows()
  }, [allColumns, editingState, canAddRows, updateNumRows])

  /**
   * Callback used by glide-data-grid when the user adds a new row in the table UI.
   */
  const onRowAppended = useCallback(() => {
    if (!canAddRows) {
      // Appending rows is not supported
      return
    }

    appendEmptyRow()
    syncEditState()
  }, [appendEmptyRow, syncEditState, canAddRows])

  /**
   * Callback used by glide-data-grid when the user deletes a row or cell value in the table UI.
   */