mirror of
https://github.com/dream-num/univer.git
synced 2026-10-02 04:24:34 +08:00
fix(sheets-ui): align cell editor selection border (#7789)
This commit is contained in:
@@ -14,9 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { Nullable, Workbook } from '@univerjs/core';
|
||||
import type { Workbook } from '@univerjs/core';
|
||||
import type { KeyCode } from '@univerjs/ui';
|
||||
import type { ICellEditorState } from '../../services/editor-bridge.service';
|
||||
import {
|
||||
DisposableCollection,
|
||||
DOCS_NORMAL_EDITOR_UNIT_ID_KEY,
|
||||
@@ -80,33 +79,6 @@ const EDITOR_DEFAULT_POSITION = {
|
||||
const CELL_EDITOR_DARK_SURFACE_THEME_COLOR = 'gray.800';
|
||||
const CELL_EDITOR_LIGHT_SURFACE_THEME_COLOR = 'gray.0';
|
||||
|
||||
interface ICellEditorHostBackgroundOptions {
|
||||
darkMode?: boolean;
|
||||
getColorFromTheme?: (color: string) => string | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the host background color for the cell editor.
|
||||
*/
|
||||
function getCellEditorHostBackgroundColor(
|
||||
editState: Nullable<Pick<ICellEditorState, 'documentLayoutObject'>>,
|
||||
options: ICellEditorHostBackgroundOptions = {}
|
||||
): string | undefined {
|
||||
const cellFill = editState?.documentLayoutObject.fill;
|
||||
if (cellFill && !isTransparentColor(cellFill)) {
|
||||
return cellFill;
|
||||
}
|
||||
|
||||
return options.getColorFromTheme?.(
|
||||
options.darkMode ? CELL_EDITOR_DARK_SURFACE_THEME_COLOR : CELL_EDITOR_LIGHT_SURFACE_THEME_COLOR
|
||||
);
|
||||
}
|
||||
|
||||
function isTransparentColor(color: string) {
|
||||
const normalizedColor = color.trim().toLowerCase().replace(/\s+/g, '');
|
||||
return normalizedColor === 'transparent' || normalizedColor === 'rgba(0,0,0,0)';
|
||||
}
|
||||
|
||||
export function shouldRefocusCellEditorAfterPointerDown(options: {
|
||||
root: HTMLElement | null | undefined;
|
||||
target: EventTarget | null | undefined;
|
||||
@@ -243,6 +215,11 @@ export function EditorContainer({ hidden = false }: IEditorContainerProps) {
|
||||
: null;
|
||||
const activeSheet = useActiveWorksheet(workbook);
|
||||
const darkMode = useObservable(themeService.darkMode$, themeService.darkMode);
|
||||
const cellFill = editState?.documentLayoutObject.fill;
|
||||
const normalizedFill = cellFill?.trim().toLowerCase().replace(/\s+/g, '');
|
||||
const editorBackgroundColor = cellFill && normalizedFill !== 'transparent' && normalizedFill !== 'rgba(0,0,0,0)'
|
||||
? cellFill
|
||||
: themeService.getColorFromTheme(darkMode ? CELL_EDITOR_DARK_SURFACE_THEME_COLOR : CELL_EDITOR_LIGHT_SURFACE_THEME_COLOR);
|
||||
const [showEditCellAddress, setShowEditCellAddress] = useState(false);
|
||||
const editSheetName = editState ? workbook?.getSheetBySheetId(editState.sheetId)?.getName() : null;
|
||||
const editCellAddress = editState
|
||||
@@ -250,8 +227,7 @@ export function EditorContainer({ hidden = false }: IEditorContainerProps) {
|
||||
? `'${quoteSheetName(editSheetName)}'!`
|
||||
: ''}${numberToABC(editState.column)}${editState.row + 1}`
|
||||
: null;
|
||||
// The editor border uses the normal selection stroke, so the address label stays visually in sync with it.
|
||||
const editorBorderColor = genNormalSelectionStyle(themeService).stroke;
|
||||
const { stroke: editorBorderColor, strokeWidth: editorBorderWidth } = genNormalSelectionStyle(themeService);
|
||||
const focusCoordinator = injector.has(ISheetEmbedRuntimeFocusCoordinator)
|
||||
? injector.get(ISheetEmbedRuntimeFocusCoordinator)
|
||||
: undefined;
|
||||
@@ -630,8 +606,8 @@ export function EditorContainer({ hidden = false }: IEditorContainerProps) {
|
||||
}, [contextService, disableAutoFocus, editorService, focusCoordinator, injector, instanceService, runtimeFocusState, visible?.visible]);
|
||||
|
||||
useEffect(() => {
|
||||
const ownerWindow = rootRef.current?.ownerDocument.defaultView;
|
||||
return () => {
|
||||
const ownerWindow = rootRef.current?.ownerDocument.defaultView;
|
||||
if (ownerWindow && pointerRefocusTimerRef.current != null) {
|
||||
ownerWindow.clearTimeout(pointerRefocusTimerRef.current);
|
||||
}
|
||||
@@ -674,7 +650,7 @@ export function EditorContainer({ hidden = false }: IEditorContainerProps) {
|
||||
|
||||
const handleClickSideBar = useEvent(() => {
|
||||
if (editorBridgeService.isVisible().visible) {
|
||||
commandService.executeCommand(SetCellEditVisibleOperation.id, {
|
||||
return commandService.executeCommand(SetCellEditVisibleOperation.id, {
|
||||
visible: false,
|
||||
eventType: DeviceInputEventType.PointerUp,
|
||||
unitId: editState?.unitId,
|
||||
@@ -687,7 +663,7 @@ export function EditorContainer({ hidden = false }: IEditorContainerProps) {
|
||||
const keyCodeConfig = useKeyEventConfig(editState?.unitId);
|
||||
|
||||
const onMoveInEditor = useEvent((keycode: KeyCode, metaKey: MetaKeys) => {
|
||||
commandService.executeCommand(SetCellEditVisibleArrowOperation.id, {
|
||||
return commandService.executeCommand(SetCellEditVisibleArrowOperation.id, {
|
||||
keycode,
|
||||
visible: false,
|
||||
eventType: DeviceInputEventType.Keyboard,
|
||||
@@ -709,10 +685,7 @@ export function EditorContainer({ hidden = false }: IEditorContainerProps) {
|
||||
height: state.height,
|
||||
opacity: hidden ? 0 : undefined,
|
||||
pointerEvents: hidden ? 'none' : undefined,
|
||||
backgroundColor: getCellEditorHostBackgroundColor(editState, {
|
||||
darkMode,
|
||||
getColorFromTheme: themeService.getColorFromTheme.bind(themeService),
|
||||
}),
|
||||
backgroundColor: editorBackgroundColor,
|
||||
}}
|
||||
>
|
||||
{visible?.visible && showEditCellAddress && editCellAddress && (
|
||||
@@ -749,6 +722,7 @@ export function EditorContainer({ hidden = false }: IEditorContainerProps) {
|
||||
resetSelectionOnBlur={false}
|
||||
isSingle={false}
|
||||
autoScrollbar={false}
|
||||
borderless
|
||||
onFormulaSelectingChange={(isSelecting: 0 | 1 | 2) => {
|
||||
if (isSelecting) {
|
||||
editorBridgeService.enableForceKeepVisible();
|
||||
@@ -760,6 +734,21 @@ export function EditorContainer({ hidden = false }: IEditorContainerProps) {
|
||||
canvasStyle={{ backgroundColor: 'transparent' }}
|
||||
/>
|
||||
)}
|
||||
{visible?.visible && (
|
||||
<div
|
||||
aria-hidden
|
||||
className="
|
||||
univer-pointer-events-none univer-absolute univer-left-0 univer-top-0 univer-z-10
|
||||
univer-box-border
|
||||
"
|
||||
style={{
|
||||
// Selection strokes start at the cell edge and include its last pixel.
|
||||
width: state.width + editorBorderWidth,
|
||||
height: state.height + editorBorderWidth,
|
||||
border: `${editorBorderWidth}px solid ${editorBorderColor}`,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -858,27 +858,6 @@ describe('EditorContainer embed focus lease', () => {
|
||||
expect(cellEditorManagerService.setFocus).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not keep refocusing the embedded sheet cell editor on delayed timers after it becomes visible', async () => {
|
||||
const { injector } = createTestBed({ docSelectionIsFocusing: false });
|
||||
const setTimeoutSpy = vi.spyOn(window, 'setTimeout');
|
||||
container = document.createElement('div');
|
||||
container.setAttribute(EMBED_INTERACTION_BOUNDARY_OWNER_ATTRIBUTE, 'embed-1');
|
||||
document.body.appendChild(container);
|
||||
root = createRoot(container);
|
||||
|
||||
await act(async () => {
|
||||
renderEditorContainer(root!, injector);
|
||||
await Promise.resolve();
|
||||
});
|
||||
|
||||
expect(setTimeoutSpy).not.toHaveBeenCalledWith(expect.any(Function), 80);
|
||||
expect(setTimeoutSpy).not.toHaveBeenCalledWith(expect.any(Function), 200);
|
||||
expect(setTimeoutSpy).not.toHaveBeenCalledWith(expect.any(Function), 500);
|
||||
expect(setTimeoutSpy).not.toHaveBeenCalledWith(expect.any(Function), 1000);
|
||||
|
||||
setTimeoutSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('restores focus to the internal cell editor after pointer down inside the editor canvas', async () => {
|
||||
const { injector, docSelectionRenderService } = createTestBed({ docSelectionIsFocusing: false });
|
||||
const hiddenEditor = document.createElement('div');
|
||||
|
||||
Reference in New Issue
Block a user