Новые стили, починил фокус formulabar
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { Redo2, Save, Undo2 } from 'lucide-react'
|
||||
import { Save } from 'lucide-react'
|
||||
import { memo } from 'react'
|
||||
import { ExcelUploadPanel } from '../../TemplateManager/ExcelUploadPanel'
|
||||
import { FormulaBarProps } from '../types'
|
||||
import { getColumnLabel } from '../utils'
|
||||
|
||||
@@ -20,17 +21,23 @@ export const FormulaBar = memo(
|
||||
lastSaveError = null,
|
||||
onManualSave,
|
||||
onClearError,
|
||||
excelFileName,
|
||||
isExcelLoading = false,
|
||||
onExcelFileChange,
|
||||
}: Omit<FormulaBarProps, 'sheetType' | 'activeSheet'>) => {
|
||||
return (
|
||||
<div className="formula-bar flex-shrink-0 border-b bg-background px-3 py-1">
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="flex min-w-[50px] items-center justify-center rounded-md border bg-muted px-2 py-1">
|
||||
<div className="formula-bar flex-shrink-0 border-b bg-background px-3 py-1.5">
|
||||
<div className="flex items-center space-x-3">
|
||||
{/* Адрес ячейки */}
|
||||
<div className="flex min-w-[45px] items-center justify-center rounded border bg-muted px-1.5 py-0.5">
|
||||
<span className="text-xs font-medium text-muted-foreground">
|
||||
{selectedCell
|
||||
? `${getColumnLabel(selectedCell.col)}${selectedCell.row + 1}`
|
||||
: 'A1'}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Строка формул */}
|
||||
<div className="flex flex-1 items-center space-x-2">
|
||||
<div className="flex items-center text-muted-foreground">
|
||||
<svg
|
||||
@@ -43,37 +50,81 @@ export const FormulaBar = memo(
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M9 7h6m0 10v-3m-3 3h.01M9 17h.01M9 14h.01M12 14h.01M15 11h.01M12 11h.01M9 11h.01M7 21h10a2 2 0 002-2V5a2 2 0 00-2-2H7a2 2 0 00-2 2v14a2 2 0 002 2z"
|
||||
d="M9 7h6m0 10v-3m-3 3h.01M9 17h.01M9 14h.01M12 14h.01M15 11h.01M12 11h.01M9 11h.01M7 21h10a2 2 0 002-2V5a2 2 0 00-2-2H7a2 2 0 002 2z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<input
|
||||
ref={formulaBarRef}
|
||||
type="text"
|
||||
className={`flex-1 rounded-md border border-input bg-background px-2 py-1 text-sm ring-offset-background transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 ${
|
||||
isEditing ? 'ring-2 ring-ring ring-offset-2' : ''
|
||||
} ${isCalculating ? 'animate-pulse' : ''}`}
|
||||
className={`text-m flex-1 rounded border border-input bg-background px-2 py-0.5 outline-none ring-offset-background transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus:outline-none disabled:cursor-not-allowed disabled:opacity-50 ${isCalculating ? 'animate-pulse' : ''}`}
|
||||
placeholder="Введите формулу или значение..."
|
||||
value={formulaBarValue}
|
||||
onChange={e => onValueChange(e.target.value)}
|
||||
onFocus={onFocus}
|
||||
onBlur={e => {
|
||||
// Проверяем, не переходит ли фокус в ячейку редактирования
|
||||
const relatedTarget = e.relatedTarget as HTMLElement
|
||||
if (
|
||||
relatedTarget &&
|
||||
relatedTarget.closest('input[type="text"]')
|
||||
) {
|
||||
return // Не завершаем редактирование
|
||||
return
|
||||
}
|
||||
onBlur(e)
|
||||
}}
|
||||
onKeyDown={onKeyDown}
|
||||
onMouseDown={e => {
|
||||
// Если поле не в режиме редактирования, нужно запустить редактирование
|
||||
// но сохранить позицию курсора
|
||||
if (!isEditing) {
|
||||
// Вычисляем позицию клика вручную
|
||||
const input = e.currentTarget
|
||||
const rect = input.getBoundingClientRect()
|
||||
const clickX =
|
||||
e.clientX -
|
||||
rect.left -
|
||||
parseInt(getComputedStyle(input).paddingLeft)
|
||||
|
||||
// Создаем временный range для определения позиции
|
||||
const tempSpan = document.createElement('span')
|
||||
tempSpan.textContent = input.value
|
||||
tempSpan.style.cssText = getComputedStyle(input).cssText
|
||||
tempSpan.style.position = 'absolute'
|
||||
tempSpan.style.visibility = 'hidden'
|
||||
tempSpan.style.whiteSpace = 'pre'
|
||||
document.body.appendChild(tempSpan)
|
||||
|
||||
let position = 0
|
||||
let bestDistance = Infinity
|
||||
|
||||
for (let i = 0; i <= input.value.length; i++) {
|
||||
tempSpan.textContent = input.value.substring(0, i)
|
||||
const distance = Math.abs(tempSpan.offsetWidth - clickX)
|
||||
if (distance < bestDistance) {
|
||||
bestDistance = distance
|
||||
position = i
|
||||
}
|
||||
}
|
||||
|
||||
document.body.removeChild(tempSpan)
|
||||
|
||||
// Сохраняем вычисленную позицию в data-атрибуте
|
||||
input.dataset.clickPosition = position.toString()
|
||||
|
||||
// Запускаем редактирование
|
||||
onFocus()
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Правая группа: индикаторы и действия */}
|
||||
<div className="flex items-center gap-2">
|
||||
{/* Индикатор процесса */}
|
||||
{(isCalculating || isSaving || isLoading) && (
|
||||
<div className="flex items-center text-muted-foreground">
|
||||
<svg
|
||||
className="h-3.5 w-3.5 animate-spin"
|
||||
className="h-2.5 w-2.5 animate-spin"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
@@ -100,6 +151,7 @@ export const FormulaBar = memo(
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Ошибка сохранения */}
|
||||
{lastSaveError && (
|
||||
<div className="flex items-center gap-1 rounded-md bg-destructive/10 px-2 py-1">
|
||||
@@ -120,15 +172,15 @@ export const FormulaBar = memo(
|
||||
className="text-xs text-destructive"
|
||||
title={lastSaveError}
|
||||
>
|
||||
Ошибка сохранения
|
||||
Ошибка
|
||||
</span>
|
||||
{onClearError && (
|
||||
<button
|
||||
onClick={onClearError}
|
||||
className="ml-1 text-destructive/60 hover:text-destructive"
|
||||
className="ml-0.5 text-destructive/60 hover:text-destructive"
|
||||
>
|
||||
<svg
|
||||
className="h-3 w-3"
|
||||
className="h-2 w-2"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
@@ -144,31 +196,13 @@ export const FormulaBar = memo(
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{/* Кнопки отмены и повтора */}
|
||||
{
|
||||
<div className="flex items-center gap-1">
|
||||
<button
|
||||
disabled={true}
|
||||
className="flex items-center gap-1 rounded-md bg-muted px-2 py-1 text-xs text-muted-foreground transition-colors hover:bg-muted/80 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
title="Отменить (Ctrl+Z)"
|
||||
>
|
||||
<Undo2 className="h-3 w-3" />
|
||||
</button>
|
||||
<button
|
||||
disabled={true}
|
||||
className="flex items-center gap-1 rounded-md bg-muted px-2 py-1 text-xs text-muted-foreground transition-colors hover:bg-muted/80 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
title="Повторить (Ctrl+Y)"
|
||||
>
|
||||
<Redo2 className="h-3 w-3" />
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
{/* Кнопка ручного сохранения */}
|
||||
|
||||
{/* Кнопка сохранения */}
|
||||
{onManualSave && (
|
||||
<button
|
||||
onClick={onManualSave}
|
||||
disabled={isSaving}
|
||||
className={`flex items-center gap-1 rounded-md px-2 py-1 text-xs transition-colors ${
|
||||
className={`flex items-center gap-1 rounded px-1.5 py-0.5 text-xs transition-colors ${
|
||||
hasUnsavedChanges
|
||||
? 'bg-primary text-primary-foreground hover:bg-primary/90'
|
||||
: lastSaveError
|
||||
@@ -184,13 +218,25 @@ export const FormulaBar = memo(
|
||||
}
|
||||
>
|
||||
<Save className="h-3 w-3" />
|
||||
{lastSaveError
|
||||
? 'Повторить'
|
||||
: hasUnsavedChanges
|
||||
? 'Сохранить'
|
||||
: 'Сохранено'}
|
||||
<span className="hidden sm:inline">
|
||||
{lastSaveError
|
||||
? 'Повторить'
|
||||
: hasUnsavedChanges
|
||||
? 'Сохранить'
|
||||
: 'Сохранено'}
|
||||
</span>
|
||||
</button>
|
||||
)}
|
||||
|
||||
{/* ExcelUploadPanel */}
|
||||
{onExcelFileChange && (
|
||||
<ExcelUploadPanel
|
||||
fileName={excelFileName}
|
||||
isLoading={isExcelLoading}
|
||||
onUploadClick={() => {}}
|
||||
onFileChange={onExcelFileChange}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user