diff --git a/packages/sheets-conditional-formatting-ui/src/components/panel/rule-edit/index.tsx b/packages/sheets-conditional-formatting-ui/src/components/panel/rule-edit/index.tsx index d588f3fc615..32943f71a47 100644 --- a/packages/sheets-conditional-formatting-ui/src/components/panel/rule-edit/index.tsx +++ b/packages/sheets-conditional-formatting-ui/src/components/panel/rule-edit/index.tsx @@ -181,6 +181,9 @@ export const RuleEdit = (props: IRuleEditProps) => { }; const handleSubmit = () => { + if (errorText) { + return; + } const getRanges = () => { const worksheet = univerInstanceService.getCurrentUnitForType(UniverInstanceType.UNIVER_SHEET)!.getActiveSheet(); if (!worksheet) { @@ -222,7 +225,7 @@ export const RuleEdit = (props: IRuleEditProps) => { const handleVerify = (v: boolean, rangeText: string) => { if (v) { if (rangeText.length < 1) { - errorTextSet(localeService.t('sheet.cf.errorMessage.notBlank')); + errorTextSet(localeService.t('sheet.cf.errorMessage.rangeError')); } else { errorTextSet(undefined); } diff --git a/packages/sheets-formula/src/views/range-selector/hooks/useSheetSelectionChange.ts b/packages/sheets-formula/src/views/range-selector/hooks/useSheetSelectionChange.ts index e9ac17b22b6..1e6d772111b 100644 --- a/packages/sheets-formula/src/views/range-selector/hooks/useSheetSelectionChange.ts +++ b/packages/sheets-formula/src/views/range-selector/hooks/useSheetSelectionChange.ts @@ -25,6 +25,7 @@ import { IEditorBridgeService } from '@univerjs/sheets-ui'; import { useEffect, useMemo, useRef } from 'react'; import { RefSelectionsRenderService } from '../../../services/render-services/ref-selections.render-service'; import { RANGE_SPLIT_STRING } from '../index'; +import { rangePreProcess } from '../utils/rangePreProcess'; import { sequenceNodeToText } from '../utils/sequenceNodeToText'; import { getSheetNameById, unitRangesToText } from '../utils/unitRangesToText'; @@ -89,6 +90,7 @@ export const useSheetSelectionChange = (isNeed: boolean, const currentSelection = cloneSelectionList.shift(); if (currentSelection) { const cloneNode = { ...node }; + rangePreProcess(currentSelection.rangeWithCoord); cloneNode.token = serializeRange(currentSelection.rangeWithCoord); return cloneNode; } @@ -98,7 +100,8 @@ export const useSheetSelectionChange = (isNeed: boolean, return node; }); const theLast = unitRangesToText(cloneSelectionList.map((e) => ({ range: e.rangeWithCoord, unitId: e.rangeWithCoord.unitId ?? '', sheetName: getSheetNameById(univerInstanceService, e.rangeWithCoord.unitId ?? '', e.rangeWithCoord.sheetId ?? '') })), unitId, subUnitId, univerInstanceService).join(RANGE_SPLIT_STRING); - const result = `${sequenceNodeToText(newSequenceNodes)}${theLast ? `,${theLast}` : ''}`; + const thePre = sequenceNodeToText(newSequenceNodes); + const result = `${thePre}${(thePre && theLast) ? RANGE_SPLIT_STRING : ''}${theLast}`; const isScaling = isScalingRef.current; handleRangeChange(result, isScaling ? -1 : result.length); }); diff --git a/packages/sheets-formula/src/views/range-selector/index.module.less b/packages/sheets-formula/src/views/range-selector/index.module.less index 15d96f8b82c..652c6e5b13b 100644 --- a/packages/sheets-formula/src/views/range-selector/index.module.less +++ b/packages/sheets-formula/src/views/range-selector/index.module.less @@ -1,7 +1,7 @@ .sheet-range-selector { &-text-wrap { height: 32px; - padding: 6px 8px 2px 0px; + padding: 6px 8px 2px 2px; width: 100%; display: flex; justify-content: space-around; diff --git a/packages/sheets-formula/src/views/range-selector/index.tsx b/packages/sheets-formula/src/views/range-selector/index.tsx index ae67241fda4..8581fb13766 100644 --- a/packages/sheets-formula/src/views/range-selector/index.tsx +++ b/packages/sheets-formula/src/views/range-selector/index.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { createInternalEditorID, generateRandomId, ICommandService, IUniverInstanceService, LocaleService, useDependency } from '@univerjs/core'; +import { createInternalEditorID, debounce, generateRandomId, ICommandService, IUniverInstanceService, LocaleService, useDependency } from '@univerjs/core'; import { Button, Dialog, Input, Tooltip } from '@univerjs/design'; import { DocBackScrollRenderController, IEditorService } from '@univerjs/docs-ui'; import { deserializeRangeWithSheet, LexerTreeBuilder, sequenceNodeType } from '@univerjs/engine-formula'; @@ -36,8 +36,10 @@ import { useSheetSelectionChange } from './hooks/useSheetSelectionChange'; import styles from './index.module.less'; import { RANGE_SELECTOR_SYMBOLS } from './utils/isRangeSelector'; +import { rangePreProcess } from './utils/rangePreProcess'; import { sequenceNodeToText } from './utils/sequenceNodeToText'; import { unitRangesToText } from './utils/unitRangesToText'; +import { verifyRange } from './utils/verifyRange'; export const RANGE_SPLIT_STRING = ','; @@ -58,6 +60,7 @@ export function RangeSelector(props: IRangeSelectorProps) { const localeService = useDependency(LocaleService); const univerInstanceService = useDependency(IUniverInstanceService); const commandService = useDependency(ICommandService); + const lexerTreeBuilder = useDependency(LexerTreeBuilder); const [rangeDialogVisible, rangeDialogVisibleSet] = useState(false); const [isFocus, isFocusSet] = useState(false); @@ -80,7 +83,28 @@ export function RangeSelector(props: IRangeSelectorProps) { const isError = useMemo(() => errorText !== undefined, [errorText]); - const handleConform = (ranges: IUnitRangeName[]) => { + const handleInputDebounce = useMemo(() => debounce((text: string) => { + const nodes = lexerTreeBuilder.sequenceNodesBuilder(text); + if (nodes) { + const verify = verifyRange(nodes); + if (verify) { + const preNodes = nodes.map((node) => { + if (typeof node === 'string') { + return node; + } else if (node.nodeType === sequenceNodeType.REFERENCE) { + const unitRange = deserializeRangeWithSheet(node.token); + unitRange.range = rangePreProcess(unitRange.range); + node.token = unitRangesToText([unitRange], unitId, subUnitId, univerInstanceService)[0]; + } + return node; + }); + const result = sequenceNodeToText(preNodes); + onChange(result); + } + } + }, 30), []); + + const handleConfirm = (ranges: IUnitRangeName[]) => { const text = unitRangesToText(ranges, unitId, subUnitId, univerInstanceService).join(RANGE_SPLIT_STRING); rangeStringSet(text); onChange(text); @@ -132,24 +156,8 @@ export function RangeSelector(props: IRangeSelectorProps) { useEffect(() => { if (onVerify) { - const result = sequenceNodes.some((item) => { - if (typeof item === 'string') { - if (item !== RANGE_SPLIT_STRING) { - // eslint-disable-next-line ts/no-unused-expressions - onVerify && onVerify(false, sequenceNodeToText(sequenceNodes)); - return true; - } - } else { - if (item.nodeType !== sequenceNodeType.REFERENCE) { - onVerify && onVerify(false, sequenceNodeToText(sequenceNodes)); - return true; - } - } - return false; - }); - if (!result) { - onVerify && onVerify(true, sequenceNodeToText(sequenceNodes)); - } + const result = verifyRange(sequenceNodes); + onVerify(result, sequenceNodeToText(sequenceNodes)); } }, [sequenceNodes, onVerify]); @@ -158,7 +166,7 @@ export function RangeSelector(props: IRangeSelectorProps) { const dispose = editor.input$.subscribe((e) => { const text = (e.data.body?.dataStream ?? '').replaceAll(/\n|\r/g, ''); rangeStringSet(text); - onChange(text); + handleInputDebounce(text); }); return () => { dispose.unsubscribe(); @@ -203,6 +211,18 @@ export function RangeSelector(props: IRangeSelectorProps) { }; }, []); + useEffect(() => { + if (editor && rangeDialogVisible) { + editor.blur(); + const d = editor.focus$.subscribe(() => { + editor.blur(); + }); + return () => { + d.unsubscribe(); + }; + } + }, [editor, rangeDialogVisible]); + useLayoutEffect(() => { let dispose: IDisposable; if (containerRef.current) { @@ -233,7 +253,7 @@ export function RangeSelector(props: IRangeSelectorProps) { {rangeDialogVisible && ( void; + handleConfirm: (ranges: IUnitRangeName[]) => void; handleClose: () => void; visible: boolean; initValue: IUnitRangeName[]; unitId: string; subUnitId: string; }) { - const { handleConform, handleClose, visible, initValue, unitId, subUnitId } = props; + const { handleConfirm, handleClose, visible, initValue, unitId, subUnitId } = props; const localeService = useDependency(LocaleService); const univerInstanceService = useDependency(IUniverInstanceService); @@ -283,6 +303,9 @@ function RangeSelectorDialog(props: { const handleRangeRemove = (index: number) => { rangesSet((v) => { + if (v.length === 1) { + return v; + } const result: string[] = []; v.forEach((r, i) => { if (index !== i) { @@ -295,7 +318,7 @@ function RangeSelectorDialog(props: { const handleRangeAdd = () => { rangesSet((v) => { - v.push(''); + v.push('A1'); focusIndexSet(v.length - 1); return [...v]; }); @@ -319,10 +342,10 @@ function RangeSelectorDialog(props: {